@tanstack/router-utils
Advanced tools
+19
-10
@@ -9,17 +9,26 @@ const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| //#region src/ast.ts | ||
| function parseAst({ code, ...opts }) { | ||
| function parseAst({ code, filename, sourceFilename, plugins, ...opts }) { | ||
| return (0, _babel_parser.parse)(code, { | ||
| plugins: [ | ||
| "jsx", | ||
| "typescript", | ||
| "explicitResourceManagement", | ||
| "importAttributes", | ||
| "deprecatedImportAssert", | ||
| ["decorators", { decoratorsBeforeExport: true }], | ||
| "decoratorAutoAccessors" | ||
| ], | ||
| plugins: plugins ?? getDefaultParserPluginsForFilename(filename ?? sourceFilename), | ||
| sourceType: "module", | ||
| sourceFilename, | ||
| ...opts | ||
| }); | ||
| } | ||
| function getDefaultParserPluginsForFilename(filename) { | ||
| const plugins = [ | ||
| "typescript", | ||
| "explicitResourceManagement", | ||
| "importAttributes", | ||
| "deprecatedImportAssert", | ||
| ["decorators", { decoratorsBeforeExport: true }], | ||
| "decoratorAutoAccessors" | ||
| ]; | ||
| if (!isPlainTypeScriptFile(filename)) plugins.unshift("jsx"); | ||
| return plugins; | ||
| } | ||
| function isPlainTypeScriptFile(filename) { | ||
| if (!filename) return false; | ||
| return /\.[cm]?ts(?:$|[?#])/.test(filename); | ||
| } | ||
| var generate = _babel_generator.default; | ||
@@ -26,0 +35,0 @@ if ("default" in generate) generate = generate.default; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ast.cjs","names":[],"sources":["../../src/ast.ts"],"sourcesContent":["import { parse } from '@babel/parser'\nimport _generate from '@babel/generator'\nimport * as t from '@babel/types'\nimport {\n deadCodeElimination as _deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport type { GeneratorOptions, GeneratorResult } from '@babel/generator'\nimport type { ParseResult, ParserOptions } from '@babel/parser'\nimport type * as _babel_types from '@babel/types'\n\nexport type ParseAstOptions = ParserOptions & {\n code: string\n}\n\nexport type ParseAstResult = ParseResult<_babel_types.File>\nexport function parseAst({ code, ...opts }: ParseAstOptions): ParseAstResult {\n return parse(code, {\n plugins: [\n 'jsx',\n 'typescript',\n 'explicitResourceManagement',\n 'importAttributes',\n 'deprecatedImportAssert',\n ['decorators', { decoratorsBeforeExport: true }],\n 'decoratorAutoAccessors',\n ],\n sourceType: 'module',\n ...opts,\n })\n}\n\nlet generate = _generate\n\nif ('default' in generate) {\n generate = generate.default as typeof generate\n}\ntype GenerateFromAstOptions = GeneratorOptions &\n Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>\nexport function generateFromAst(\n ast: _babel_types.Node,\n opts?: GenerateFromAstOptions,\n): GeneratorResult {\n return generate(\n ast,\n opts\n ? { importAttributesKeyword: 'with', sourceMaps: true, ...opts }\n : undefined,\n )\n}\nexport type { GeneratorResult } from '@babel/generator'\n\n/**\n * Strips TypeScript type-only exports and imports from an AST.\n *\n * This is necessary because babel-dead-code-elimination doesn't handle\n * TypeScript type exports/imports. When a type export references an import\n * that pulls in server-only code, the dead code elimination won't remove\n * that import because it sees the type as still referencing it.\n *\n * This function removes:\n * - `export type Foo = ...`\n * - `export interface Foo { ... }`\n * - `export type { Foo } from './module'`\n * - `export type * from './module'`\n * - Type specifiers in mixed exports: `export { value, type Foo }` -> `export { value }`\n * - `import type { Foo } from './module'`\n * - Type specifiers in mixed imports: `import { value, type Foo } from './module'` -> `import { value }`\n *\n * Note: Non-exported type/interface declarations are preserved as they may be\n * used as type annotations within the code.\n *\n * @param ast - The Babel AST (or ParseResult) to mutate\n */\nexport function stripTypeExports(ast: ParseResult<_babel_types.File>): void {\n // Filter the program body to remove type-only nodes\n ast.program.body = ast.program.body.filter((node) => {\n // Handle export declarations\n if (t.isExportNamedDeclaration(node)) {\n // Remove entire export if it's a type-only export\n // e.g., `export type Foo = string`, `export interface Bar {}`, `export type { X } from './y'`\n if (node.exportKind === 'type') {\n return false\n }\n\n // For value exports with mixed specifiers, filter out type-only specifiers\n // e.g., `export { value, type TypeOnly }` -> `export { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isExportSpecifier(specifier)) {\n return specifier.exportKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire export declaration\n // (unless it has a declaration like `export const x = 1`)\n if (node.specifiers.length === 0 && !node.declaration) {\n return false\n }\n }\n }\n\n // Handle type-only export-all declarations\n // e.g., `export type * from './module'`\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') {\n return false\n }\n }\n\n // Handle import declarations\n if (t.isImportDeclaration(node)) {\n // Remove entire import if it's a type-only import\n // e.g., `import type { Foo } from './module'`\n if (node.importKind === 'type') {\n return false\n }\n\n // For value imports with mixed specifiers, filter out type-only specifiers\n // e.g., `import { value, type TypeOnly } from './module'` -> `import { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isImportSpecifier(specifier)) {\n return specifier.importKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire import declaration\n if (node.specifiers.length === 0) {\n return false\n }\n }\n }\n\n return true\n })\n}\n\n// Re-export findReferencedIdentifiers from babel-dead-code-elimination\nexport { findReferencedIdentifiers }\n\n/**\n * Performs dead code elimination on the AST, with TypeScript type stripping.\n *\n * This is a wrapper around babel-dead-code-elimination that first strips\n * TypeScript type-only exports and imports. This is necessary because\n * babel-dead-code-elimination doesn't handle type exports, which can cause\n * imports to be retained when they're only referenced by type exports.\n *\n * @param ast - The Babel AST to mutate\n * @param candidates - Optional set of identifier paths to consider for removal.\n * If provided, only these identifiers will be candidates for removal.\n * This should be the result of `findReferencedIdentifiers(ast)` called\n * before any AST transformations.\n */\nexport function deadCodeElimination(\n ast: ParseResult<_babel_types.File>,\n candidates?: ReturnType<typeof findReferencedIdentifiers>,\n): void {\n // First strip TypeScript type-only exports and imports\n stripTypeExports(ast)\n\n // Then run the original dead code elimination\n _deadCodeElimination(ast, candidates)\n}\n"],"mappings":";;;;;;;;AAgBA,SAAgB,SAAS,EAAE,MAAM,GAAG,QAAyC;AAC3E,SAAA,GAAA,cAAA,OAAa,MAAM;EACjB,SAAS;GACP;GACA;GACA;GACA;GACA;GACA,CAAC,cAAc,EAAE,wBAAwB,MAAM,CAAC;GAChD;GACD;EACD,YAAY;EACZ,GAAG;EACJ,CAAC;;AAGJ,IAAI,WAAW,iBAAA;AAEf,IAAI,aAAa,SACf,YAAW,SAAS;AAItB,SAAgB,gBACd,KACA,MACiB;AACjB,QAAO,SACL,KACA,OACI;EAAE,yBAAyB;EAAQ,YAAY;EAAM,GAAG;EAAM,GAC9D,KAAA,EACL;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,SAAgB,iBAAiB,KAA2C;AAE1E,KAAI,QAAQ,OAAO,IAAI,QAAQ,KAAK,QAAQ,SAAS;AAEnD,MAAI,aAAE,yBAAyB,KAAK,EAAE;AAGpC,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,aAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAIF,QAAI,KAAK,WAAW,WAAW,KAAK,CAAC,KAAK,YACxC,QAAO;;;AAOb,MAAI,aAAE,uBAAuB,KAAK;OAC5B,KAAK,eAAe,OACtB,QAAO;;AAKX,MAAI,aAAE,oBAAoB,KAAK,EAAE;AAG/B,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,aAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAGF,QAAI,KAAK,WAAW,WAAW,EAC7B,QAAO;;;AAKb,SAAO;GACP;;;;;;;;;;;;;;;;AAoBJ,SAAgB,oBACd,KACA,YACM;AAEN,kBAAiB,IAAI;AAGrB,EAAA,GAAA,4BAAA,qBAAqB,KAAK,WAAW"} | ||
| {"version":3,"file":"ast.cjs","names":[],"sources":["../../src/ast.ts"],"sourcesContent":["import { parse } from '@babel/parser'\nimport _generate from '@babel/generator'\nimport * as t from '@babel/types'\nimport {\n deadCodeElimination as _deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport type { GeneratorOptions, GeneratorResult } from '@babel/generator'\nimport type { ParseResult, ParserOptions } from '@babel/parser'\nimport type * as _babel_types from '@babel/types'\n\nexport type ParseAstOptions = ParserOptions & {\n code: string\n filename?: string\n}\n\nexport type ParseAstResult = ParseResult<_babel_types.File>\nexport function parseAst({\n code,\n filename,\n sourceFilename,\n plugins,\n ...opts\n}: ParseAstOptions): ParseAstResult {\n const inferredFilename = filename ?? sourceFilename\n return parse(code, {\n plugins: plugins ?? getDefaultParserPluginsForFilename(inferredFilename),\n sourceType: 'module',\n sourceFilename,\n ...opts,\n })\n}\n\nfunction getDefaultParserPluginsForFilename(\n filename: string | undefined,\n): NonNullable<ParserOptions['plugins']> {\n const plugins: NonNullable<ParserOptions['plugins']> = [\n 'typescript',\n 'explicitResourceManagement',\n 'importAttributes',\n 'deprecatedImportAssert',\n ['decorators', { decoratorsBeforeExport: true }],\n 'decoratorAutoAccessors',\n ]\n\n if (!isPlainTypeScriptFile(filename)) {\n plugins.unshift('jsx')\n }\n\n return plugins\n}\n\nfunction isPlainTypeScriptFile(filename: string | undefined): boolean {\n if (!filename) {\n return false\n }\n\n return /\\.[cm]?ts(?:$|[?#])/.test(filename)\n}\n\nlet generate = _generate\n\nif ('default' in generate) {\n generate = generate.default as typeof generate\n}\ntype GenerateFromAstOptions = GeneratorOptions &\n Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>\nexport function generateFromAst(\n ast: _babel_types.Node,\n opts?: GenerateFromAstOptions,\n): GeneratorResult {\n return generate(\n ast,\n opts\n ? { importAttributesKeyword: 'with', sourceMaps: true, ...opts }\n : undefined,\n )\n}\nexport type { GeneratorResult } from '@babel/generator'\n\n/**\n * Strips TypeScript type-only exports and imports from an AST.\n *\n * This is necessary because babel-dead-code-elimination doesn't handle\n * TypeScript type exports/imports. When a type export references an import\n * that pulls in server-only code, the dead code elimination won't remove\n * that import because it sees the type as still referencing it.\n *\n * This function removes:\n * - `export type Foo = ...`\n * - `export interface Foo { ... }`\n * - `export type { Foo } from './module'`\n * - `export type * from './module'`\n * - Type specifiers in mixed exports: `export { value, type Foo }` -> `export { value }`\n * - `import type { Foo } from './module'`\n * - Type specifiers in mixed imports: `import { value, type Foo } from './module'` -> `import { value }`\n *\n * Note: Non-exported type/interface declarations are preserved as they may be\n * used as type annotations within the code.\n *\n * @param ast - The Babel AST (or ParseResult) to mutate\n */\nexport function stripTypeExports(ast: ParseResult<_babel_types.File>): void {\n // Filter the program body to remove type-only nodes\n ast.program.body = ast.program.body.filter((node) => {\n // Handle export declarations\n if (t.isExportNamedDeclaration(node)) {\n // Remove entire export if it's a type-only export\n // e.g., `export type Foo = string`, `export interface Bar {}`, `export type { X } from './y'`\n if (node.exportKind === 'type') {\n return false\n }\n\n // For value exports with mixed specifiers, filter out type-only specifiers\n // e.g., `export { value, type TypeOnly }` -> `export { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isExportSpecifier(specifier)) {\n return specifier.exportKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire export declaration\n // (unless it has a declaration like `export const x = 1`)\n if (node.specifiers.length === 0 && !node.declaration) {\n return false\n }\n }\n }\n\n // Handle type-only export-all declarations\n // e.g., `export type * from './module'`\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') {\n return false\n }\n }\n\n // Handle import declarations\n if (t.isImportDeclaration(node)) {\n // Remove entire import if it's a type-only import\n // e.g., `import type { Foo } from './module'`\n if (node.importKind === 'type') {\n return false\n }\n\n // For value imports with mixed specifiers, filter out type-only specifiers\n // e.g., `import { value, type TypeOnly } from './module'` -> `import { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isImportSpecifier(specifier)) {\n return specifier.importKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire import declaration\n if (node.specifiers.length === 0) {\n return false\n }\n }\n }\n\n return true\n })\n}\n\n// Re-export findReferencedIdentifiers from babel-dead-code-elimination\nexport { findReferencedIdentifiers }\n\n/**\n * Performs dead code elimination on the AST, with TypeScript type stripping.\n *\n * This is a wrapper around babel-dead-code-elimination that first strips\n * TypeScript type-only exports and imports. This is necessary because\n * babel-dead-code-elimination doesn't handle type exports, which can cause\n * imports to be retained when they're only referenced by type exports.\n *\n * @param ast - The Babel AST to mutate\n * @param candidates - Optional set of identifier paths to consider for removal.\n * If provided, only these identifiers will be candidates for removal.\n * This should be the result of `findReferencedIdentifiers(ast)` called\n * before any AST transformations.\n */\nexport function deadCodeElimination(\n ast: ParseResult<_babel_types.File>,\n candidates?: ReturnType<typeof findReferencedIdentifiers>,\n): void {\n // First strip TypeScript type-only exports and imports\n stripTypeExports(ast)\n\n // Then run the original dead code elimination\n _deadCodeElimination(ast, candidates)\n}\n"],"mappings":";;;;;;;;AAiBA,SAAgB,SAAS,EACvB,MACA,UACA,gBACA,SACA,GAAG,QAC+B;AAElC,SAAA,GAAA,cAAA,OAAa,MAAM;EACjB,SAAS,WAAW,mCAFG,YAAY,eAEqC;EACxE,YAAY;EACZ;EACA,GAAG;EACJ,CAAC;;AAGJ,SAAS,mCACP,UACuC;CACvC,MAAM,UAAiD;EACrD;EACA;EACA;EACA;EACA,CAAC,cAAc,EAAE,wBAAwB,MAAM,CAAC;EAChD;EACD;AAED,KAAI,CAAC,sBAAsB,SAAS,CAClC,SAAQ,QAAQ,MAAM;AAGxB,QAAO;;AAGT,SAAS,sBAAsB,UAAuC;AACpE,KAAI,CAAC,SACH,QAAO;AAGT,QAAO,sBAAsB,KAAK,SAAS;;AAG7C,IAAI,WAAW,iBAAA;AAEf,IAAI,aAAa,SACf,YAAW,SAAS;AAItB,SAAgB,gBACd,KACA,MACiB;AACjB,QAAO,SACL,KACA,OACI;EAAE,yBAAyB;EAAQ,YAAY;EAAM,GAAG;EAAM,GAC9D,KAAA,EACL;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,SAAgB,iBAAiB,KAA2C;AAE1E,KAAI,QAAQ,OAAO,IAAI,QAAQ,KAAK,QAAQ,SAAS;AAEnD,MAAI,aAAE,yBAAyB,KAAK,EAAE;AAGpC,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,aAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAIF,QAAI,KAAK,WAAW,WAAW,KAAK,CAAC,KAAK,YACxC,QAAO;;;AAOb,MAAI,aAAE,uBAAuB,KAAK;OAC5B,KAAK,eAAe,OACtB,QAAO;;AAKX,MAAI,aAAE,oBAAoB,KAAK,EAAE;AAG/B,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,aAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAGF,QAAI,KAAK,WAAW,WAAW,EAC7B,QAAO;;;AAKb,SAAO;GACP;;;;;;;;;;;;;;;;AAoBJ,SAAgB,oBACd,KACA,YACM;AAEN,kBAAiB,IAAI;AAGrB,EAAA,GAAA,4BAAA,qBAAqB,KAAK,WAAW"} |
@@ -7,5 +7,6 @@ import { findReferencedIdentifiers } from 'babel-dead-code-elimination'; | ||
| code: string; | ||
| filename?: string; | ||
| }; | ||
| export type ParseAstResult = ParseResult<_babel_types.File>; | ||
| export declare function parseAst({ code, ...opts }: ParseAstOptions): ParseAstResult; | ||
| export declare function parseAst({ code, filename, sourceFilename, plugins, ...opts }: ParseAstOptions): ParseAstResult; | ||
| type GenerateFromAstOptions = GeneratorOptions & Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>; | ||
@@ -12,0 +13,0 @@ export declare function generateFromAst(ast: _babel_types.Node, opts?: GenerateFromAstOptions): GeneratorResult; |
@@ -7,5 +7,6 @@ import { findReferencedIdentifiers } from 'babel-dead-code-elimination'; | ||
| code: string; | ||
| filename?: string; | ||
| }; | ||
| export type ParseAstResult = ParseResult<_babel_types.File>; | ||
| export declare function parseAst({ code, ...opts }: ParseAstOptions): ParseAstResult; | ||
| export declare function parseAst({ code, filename, sourceFilename, plugins, ...opts }: ParseAstOptions): ParseAstResult; | ||
| type GenerateFromAstOptions = GeneratorOptions & Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>; | ||
@@ -12,0 +13,0 @@ export declare function generateFromAst(ast: _babel_types.Node, opts?: GenerateFromAstOptions): GeneratorResult; |
+19
-10
@@ -6,17 +6,26 @@ import { parse } from "@babel/parser"; | ||
| //#region src/ast.ts | ||
| function parseAst({ code, ...opts }) { | ||
| function parseAst({ code, filename, sourceFilename, plugins, ...opts }) { | ||
| return parse(code, { | ||
| plugins: [ | ||
| "jsx", | ||
| "typescript", | ||
| "explicitResourceManagement", | ||
| "importAttributes", | ||
| "deprecatedImportAssert", | ||
| ["decorators", { decoratorsBeforeExport: true }], | ||
| "decoratorAutoAccessors" | ||
| ], | ||
| plugins: plugins ?? getDefaultParserPluginsForFilename(filename ?? sourceFilename), | ||
| sourceType: "module", | ||
| sourceFilename, | ||
| ...opts | ||
| }); | ||
| } | ||
| function getDefaultParserPluginsForFilename(filename) { | ||
| const plugins = [ | ||
| "typescript", | ||
| "explicitResourceManagement", | ||
| "importAttributes", | ||
| "deprecatedImportAssert", | ||
| ["decorators", { decoratorsBeforeExport: true }], | ||
| "decoratorAutoAccessors" | ||
| ]; | ||
| if (!isPlainTypeScriptFile(filename)) plugins.unshift("jsx"); | ||
| return plugins; | ||
| } | ||
| function isPlainTypeScriptFile(filename) { | ||
| if (!filename) return false; | ||
| return /\.[cm]?ts(?:$|[?#])/.test(filename); | ||
| } | ||
| var generate = _generate; | ||
@@ -23,0 +32,0 @@ if ("default" in generate) generate = generate.default; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ast.js","names":[],"sources":["../../src/ast.ts"],"sourcesContent":["import { parse } from '@babel/parser'\nimport _generate from '@babel/generator'\nimport * as t from '@babel/types'\nimport {\n deadCodeElimination as _deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport type { GeneratorOptions, GeneratorResult } from '@babel/generator'\nimport type { ParseResult, ParserOptions } from '@babel/parser'\nimport type * as _babel_types from '@babel/types'\n\nexport type ParseAstOptions = ParserOptions & {\n code: string\n}\n\nexport type ParseAstResult = ParseResult<_babel_types.File>\nexport function parseAst({ code, ...opts }: ParseAstOptions): ParseAstResult {\n return parse(code, {\n plugins: [\n 'jsx',\n 'typescript',\n 'explicitResourceManagement',\n 'importAttributes',\n 'deprecatedImportAssert',\n ['decorators', { decoratorsBeforeExport: true }],\n 'decoratorAutoAccessors',\n ],\n sourceType: 'module',\n ...opts,\n })\n}\n\nlet generate = _generate\n\nif ('default' in generate) {\n generate = generate.default as typeof generate\n}\ntype GenerateFromAstOptions = GeneratorOptions &\n Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>\nexport function generateFromAst(\n ast: _babel_types.Node,\n opts?: GenerateFromAstOptions,\n): GeneratorResult {\n return generate(\n ast,\n opts\n ? { importAttributesKeyword: 'with', sourceMaps: true, ...opts }\n : undefined,\n )\n}\nexport type { GeneratorResult } from '@babel/generator'\n\n/**\n * Strips TypeScript type-only exports and imports from an AST.\n *\n * This is necessary because babel-dead-code-elimination doesn't handle\n * TypeScript type exports/imports. When a type export references an import\n * that pulls in server-only code, the dead code elimination won't remove\n * that import because it sees the type as still referencing it.\n *\n * This function removes:\n * - `export type Foo = ...`\n * - `export interface Foo { ... }`\n * - `export type { Foo } from './module'`\n * - `export type * from './module'`\n * - Type specifiers in mixed exports: `export { value, type Foo }` -> `export { value }`\n * - `import type { Foo } from './module'`\n * - Type specifiers in mixed imports: `import { value, type Foo } from './module'` -> `import { value }`\n *\n * Note: Non-exported type/interface declarations are preserved as they may be\n * used as type annotations within the code.\n *\n * @param ast - The Babel AST (or ParseResult) to mutate\n */\nexport function stripTypeExports(ast: ParseResult<_babel_types.File>): void {\n // Filter the program body to remove type-only nodes\n ast.program.body = ast.program.body.filter((node) => {\n // Handle export declarations\n if (t.isExportNamedDeclaration(node)) {\n // Remove entire export if it's a type-only export\n // e.g., `export type Foo = string`, `export interface Bar {}`, `export type { X } from './y'`\n if (node.exportKind === 'type') {\n return false\n }\n\n // For value exports with mixed specifiers, filter out type-only specifiers\n // e.g., `export { value, type TypeOnly }` -> `export { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isExportSpecifier(specifier)) {\n return specifier.exportKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire export declaration\n // (unless it has a declaration like `export const x = 1`)\n if (node.specifiers.length === 0 && !node.declaration) {\n return false\n }\n }\n }\n\n // Handle type-only export-all declarations\n // e.g., `export type * from './module'`\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') {\n return false\n }\n }\n\n // Handle import declarations\n if (t.isImportDeclaration(node)) {\n // Remove entire import if it's a type-only import\n // e.g., `import type { Foo } from './module'`\n if (node.importKind === 'type') {\n return false\n }\n\n // For value imports with mixed specifiers, filter out type-only specifiers\n // e.g., `import { value, type TypeOnly } from './module'` -> `import { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isImportSpecifier(specifier)) {\n return specifier.importKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire import declaration\n if (node.specifiers.length === 0) {\n return false\n }\n }\n }\n\n return true\n })\n}\n\n// Re-export findReferencedIdentifiers from babel-dead-code-elimination\nexport { findReferencedIdentifiers }\n\n/**\n * Performs dead code elimination on the AST, with TypeScript type stripping.\n *\n * This is a wrapper around babel-dead-code-elimination that first strips\n * TypeScript type-only exports and imports. This is necessary because\n * babel-dead-code-elimination doesn't handle type exports, which can cause\n * imports to be retained when they're only referenced by type exports.\n *\n * @param ast - The Babel AST to mutate\n * @param candidates - Optional set of identifier paths to consider for removal.\n * If provided, only these identifiers will be candidates for removal.\n * This should be the result of `findReferencedIdentifiers(ast)` called\n * before any AST transformations.\n */\nexport function deadCodeElimination(\n ast: ParseResult<_babel_types.File>,\n candidates?: ReturnType<typeof findReferencedIdentifiers>,\n): void {\n // First strip TypeScript type-only exports and imports\n stripTypeExports(ast)\n\n // Then run the original dead code elimination\n _deadCodeElimination(ast, candidates)\n}\n"],"mappings":";;;;;AAgBA,SAAgB,SAAS,EAAE,MAAM,GAAG,QAAyC;AAC3E,QAAO,MAAM,MAAM;EACjB,SAAS;GACP;GACA;GACA;GACA;GACA;GACA,CAAC,cAAc,EAAE,wBAAwB,MAAM,CAAC;GAChD;GACD;EACD,YAAY;EACZ,GAAG;EACJ,CAAC;;AAGJ,IAAI,WAAW;AAEf,IAAI,aAAa,SACf,YAAW,SAAS;AAItB,SAAgB,gBACd,KACA,MACiB;AACjB,QAAO,SACL,KACA,OACI;EAAE,yBAAyB;EAAQ,YAAY;EAAM,GAAG;EAAM,GAC9D,KAAA,EACL;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,SAAgB,iBAAiB,KAA2C;AAE1E,KAAI,QAAQ,OAAO,IAAI,QAAQ,KAAK,QAAQ,SAAS;AAEnD,MAAI,EAAE,yBAAyB,KAAK,EAAE;AAGpC,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,EAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAIF,QAAI,KAAK,WAAW,WAAW,KAAK,CAAC,KAAK,YACxC,QAAO;;;AAOb,MAAI,EAAE,uBAAuB,KAAK;OAC5B,KAAK,eAAe,OACtB,QAAO;;AAKX,MAAI,EAAE,oBAAoB,KAAK,EAAE;AAG/B,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,EAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAGF,QAAI,KAAK,WAAW,WAAW,EAC7B,QAAO;;;AAKb,SAAO;GACP;;;;;;;;;;;;;;;;AAoBJ,SAAgB,sBACd,KACA,YACM;AAEN,kBAAiB,IAAI;AAGrB,qBAAqB,KAAK,WAAW"} | ||
| {"version":3,"file":"ast.js","names":[],"sources":["../../src/ast.ts"],"sourcesContent":["import { parse } from '@babel/parser'\nimport _generate from '@babel/generator'\nimport * as t from '@babel/types'\nimport {\n deadCodeElimination as _deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport type { GeneratorOptions, GeneratorResult } from '@babel/generator'\nimport type { ParseResult, ParserOptions } from '@babel/parser'\nimport type * as _babel_types from '@babel/types'\n\nexport type ParseAstOptions = ParserOptions & {\n code: string\n filename?: string\n}\n\nexport type ParseAstResult = ParseResult<_babel_types.File>\nexport function parseAst({\n code,\n filename,\n sourceFilename,\n plugins,\n ...opts\n}: ParseAstOptions): ParseAstResult {\n const inferredFilename = filename ?? sourceFilename\n return parse(code, {\n plugins: plugins ?? getDefaultParserPluginsForFilename(inferredFilename),\n sourceType: 'module',\n sourceFilename,\n ...opts,\n })\n}\n\nfunction getDefaultParserPluginsForFilename(\n filename: string | undefined,\n): NonNullable<ParserOptions['plugins']> {\n const plugins: NonNullable<ParserOptions['plugins']> = [\n 'typescript',\n 'explicitResourceManagement',\n 'importAttributes',\n 'deprecatedImportAssert',\n ['decorators', { decoratorsBeforeExport: true }],\n 'decoratorAutoAccessors',\n ]\n\n if (!isPlainTypeScriptFile(filename)) {\n plugins.unshift('jsx')\n }\n\n return plugins\n}\n\nfunction isPlainTypeScriptFile(filename: string | undefined): boolean {\n if (!filename) {\n return false\n }\n\n return /\\.[cm]?ts(?:$|[?#])/.test(filename)\n}\n\nlet generate = _generate\n\nif ('default' in generate) {\n generate = generate.default as typeof generate\n}\ntype GenerateFromAstOptions = GeneratorOptions &\n Required<Pick<GeneratorOptions, 'sourceFileName' | 'filename'>>\nexport function generateFromAst(\n ast: _babel_types.Node,\n opts?: GenerateFromAstOptions,\n): GeneratorResult {\n return generate(\n ast,\n opts\n ? { importAttributesKeyword: 'with', sourceMaps: true, ...opts }\n : undefined,\n )\n}\nexport type { GeneratorResult } from '@babel/generator'\n\n/**\n * Strips TypeScript type-only exports and imports from an AST.\n *\n * This is necessary because babel-dead-code-elimination doesn't handle\n * TypeScript type exports/imports. When a type export references an import\n * that pulls in server-only code, the dead code elimination won't remove\n * that import because it sees the type as still referencing it.\n *\n * This function removes:\n * - `export type Foo = ...`\n * - `export interface Foo { ... }`\n * - `export type { Foo } from './module'`\n * - `export type * from './module'`\n * - Type specifiers in mixed exports: `export { value, type Foo }` -> `export { value }`\n * - `import type { Foo } from './module'`\n * - Type specifiers in mixed imports: `import { value, type Foo } from './module'` -> `import { value }`\n *\n * Note: Non-exported type/interface declarations are preserved as they may be\n * used as type annotations within the code.\n *\n * @param ast - The Babel AST (or ParseResult) to mutate\n */\nexport function stripTypeExports(ast: ParseResult<_babel_types.File>): void {\n // Filter the program body to remove type-only nodes\n ast.program.body = ast.program.body.filter((node) => {\n // Handle export declarations\n if (t.isExportNamedDeclaration(node)) {\n // Remove entire export if it's a type-only export\n // e.g., `export type Foo = string`, `export interface Bar {}`, `export type { X } from './y'`\n if (node.exportKind === 'type') {\n return false\n }\n\n // For value exports with mixed specifiers, filter out type-only specifiers\n // e.g., `export { value, type TypeOnly }` -> `export { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isExportSpecifier(specifier)) {\n return specifier.exportKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire export declaration\n // (unless it has a declaration like `export const x = 1`)\n if (node.specifiers.length === 0 && !node.declaration) {\n return false\n }\n }\n }\n\n // Handle type-only export-all declarations\n // e.g., `export type * from './module'`\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') {\n return false\n }\n }\n\n // Handle import declarations\n if (t.isImportDeclaration(node)) {\n // Remove entire import if it's a type-only import\n // e.g., `import type { Foo } from './module'`\n if (node.importKind === 'type') {\n return false\n }\n\n // For value imports with mixed specifiers, filter out type-only specifiers\n // e.g., `import { value, type TypeOnly } from './module'` -> `import { value }`\n if (node.specifiers.length > 0) {\n node.specifiers = node.specifiers.filter((specifier) => {\n if (t.isImportSpecifier(specifier)) {\n return specifier.importKind !== 'type'\n }\n return true\n })\n\n // If all specifiers were removed, remove the entire import declaration\n if (node.specifiers.length === 0) {\n return false\n }\n }\n }\n\n return true\n })\n}\n\n// Re-export findReferencedIdentifiers from babel-dead-code-elimination\nexport { findReferencedIdentifiers }\n\n/**\n * Performs dead code elimination on the AST, with TypeScript type stripping.\n *\n * This is a wrapper around babel-dead-code-elimination that first strips\n * TypeScript type-only exports and imports. This is necessary because\n * babel-dead-code-elimination doesn't handle type exports, which can cause\n * imports to be retained when they're only referenced by type exports.\n *\n * @param ast - The Babel AST to mutate\n * @param candidates - Optional set of identifier paths to consider for removal.\n * If provided, only these identifiers will be candidates for removal.\n * This should be the result of `findReferencedIdentifiers(ast)` called\n * before any AST transformations.\n */\nexport function deadCodeElimination(\n ast: ParseResult<_babel_types.File>,\n candidates?: ReturnType<typeof findReferencedIdentifiers>,\n): void {\n // First strip TypeScript type-only exports and imports\n stripTypeExports(ast)\n\n // Then run the original dead code elimination\n _deadCodeElimination(ast, candidates)\n}\n"],"mappings":";;;;;AAiBA,SAAgB,SAAS,EACvB,MACA,UACA,gBACA,SACA,GAAG,QAC+B;AAElC,QAAO,MAAM,MAAM;EACjB,SAAS,WAAW,mCAFG,YAAY,eAEqC;EACxE,YAAY;EACZ;EACA,GAAG;EACJ,CAAC;;AAGJ,SAAS,mCACP,UACuC;CACvC,MAAM,UAAiD;EACrD;EACA;EACA;EACA;EACA,CAAC,cAAc,EAAE,wBAAwB,MAAM,CAAC;EAChD;EACD;AAED,KAAI,CAAC,sBAAsB,SAAS,CAClC,SAAQ,QAAQ,MAAM;AAGxB,QAAO;;AAGT,SAAS,sBAAsB,UAAuC;AACpE,KAAI,CAAC,SACH,QAAO;AAGT,QAAO,sBAAsB,KAAK,SAAS;;AAG7C,IAAI,WAAW;AAEf,IAAI,aAAa,SACf,YAAW,SAAS;AAItB,SAAgB,gBACd,KACA,MACiB;AACjB,QAAO,SACL,KACA,OACI;EAAE,yBAAyB;EAAQ,YAAY;EAAM,GAAG;EAAM,GAC9D,KAAA,EACL;;;;;;;;;;;;;;;;;;;;;;;;AA0BH,SAAgB,iBAAiB,KAA2C;AAE1E,KAAI,QAAQ,OAAO,IAAI,QAAQ,KAAK,QAAQ,SAAS;AAEnD,MAAI,EAAE,yBAAyB,KAAK,EAAE;AAGpC,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,EAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAIF,QAAI,KAAK,WAAW,WAAW,KAAK,CAAC,KAAK,YACxC,QAAO;;;AAOb,MAAI,EAAE,uBAAuB,KAAK;OAC5B,KAAK,eAAe,OACtB,QAAO;;AAKX,MAAI,EAAE,oBAAoB,KAAK,EAAE;AAG/B,OAAI,KAAK,eAAe,OACtB,QAAO;AAKT,OAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,SAAK,aAAa,KAAK,WAAW,QAAQ,cAAc;AACtD,SAAI,EAAE,kBAAkB,UAAU,CAChC,QAAO,UAAU,eAAe;AAElC,YAAO;MACP;AAGF,QAAI,KAAK,WAAW,WAAW,EAC7B,QAAO;;;AAKb,SAAO;GACP;;;;;;;;;;;;;;;;AAoBJ,SAAgB,sBACd,KACA,YACM;AAEN,kBAAiB,IAAI;AAGrB,qBAAqB,KAAK,WAAW"} |
+1
-1
| { | ||
| "name": "@tanstack/router-utils", | ||
| "version": "1.161.7", | ||
| "version": "1.161.8", | ||
| "description": "Modern and scalable routing for React applications", | ||
@@ -5,0 +5,0 @@ "author": "Tanner Linsley", |
+38
-10
@@ -14,17 +14,18 @@ import { parse } from '@babel/parser' | ||
| code: string | ||
| filename?: string | ||
| } | ||
| export type ParseAstResult = ParseResult<_babel_types.File> | ||
| export function parseAst({ code, ...opts }: ParseAstOptions): ParseAstResult { | ||
| export function parseAst({ | ||
| code, | ||
| filename, | ||
| sourceFilename, | ||
| plugins, | ||
| ...opts | ||
| }: ParseAstOptions): ParseAstResult { | ||
| const inferredFilename = filename ?? sourceFilename | ||
| return parse(code, { | ||
| plugins: [ | ||
| 'jsx', | ||
| 'typescript', | ||
| 'explicitResourceManagement', | ||
| 'importAttributes', | ||
| 'deprecatedImportAssert', | ||
| ['decorators', { decoratorsBeforeExport: true }], | ||
| 'decoratorAutoAccessors', | ||
| ], | ||
| plugins: plugins ?? getDefaultParserPluginsForFilename(inferredFilename), | ||
| sourceType: 'module', | ||
| sourceFilename, | ||
| ...opts, | ||
@@ -34,2 +35,29 @@ }) | ||
| function getDefaultParserPluginsForFilename( | ||
| filename: string | undefined, | ||
| ): NonNullable<ParserOptions['plugins']> { | ||
| const plugins: NonNullable<ParserOptions['plugins']> = [ | ||
| 'typescript', | ||
| 'explicitResourceManagement', | ||
| 'importAttributes', | ||
| 'deprecatedImportAssert', | ||
| ['decorators', { decoratorsBeforeExport: true }], | ||
| 'decoratorAutoAccessors', | ||
| ] | ||
| if (!isPlainTypeScriptFile(filename)) { | ||
| plugins.unshift('jsx') | ||
| } | ||
| return plugins | ||
| } | ||
| function isPlainTypeScriptFile(filename: string | undefined): boolean { | ||
| if (!filename) { | ||
| return false | ||
| } | ||
| return /\.[cm]?ts(?:$|[?#])/.test(filename) | ||
| } | ||
| let generate = _generate | ||
@@ -36,0 +64,0 @@ |
58900
5.77%731
6.1%