@tanstack/router-generator 1.121.1 → 1.121.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,7 +10,7 @@ async function transform({
|
|
|
10
10
|
source,
|
|
11
11
|
plugins
|
|
12
12
|
}) {
|
|
13
|
-
var _a, _b, _c;
|
|
13
|
+
var _a, _b, _c, _d;
|
|
14
14
|
let appliedChanges = false;
|
|
15
15
|
let ast;
|
|
16
16
|
const foundExports = [];
|
|
@@ -46,22 +46,45 @@ async function transform({
|
|
|
46
46
|
}
|
|
47
47
|
registeredExports.set(exportName, plugin);
|
|
48
48
|
}
|
|
49
|
+
function onExportFound(decl, exportName, plugin) {
|
|
50
|
+
const pluginAppliedChanges = plugin.onExportFound({
|
|
51
|
+
decl,
|
|
52
|
+
ctx: { ...ctx, preferredQuote }
|
|
53
|
+
});
|
|
54
|
+
if (pluginAppliedChanges) {
|
|
55
|
+
appliedChanges = true;
|
|
56
|
+
}
|
|
57
|
+
registeredExports.delete(exportName);
|
|
58
|
+
foundExports.push(exportName);
|
|
59
|
+
}
|
|
49
60
|
const program = ast.program;
|
|
50
61
|
for (const n of program.body) {
|
|
51
|
-
if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
decl,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration") {
|
|
63
|
+
if (((_b = n.declaration) == null ? void 0 : _b.type) === "VariableDeclaration") {
|
|
64
|
+
const decl = n.declaration.declarations[0];
|
|
65
|
+
if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
|
|
66
|
+
const plugin = registeredExports.get(decl.id.name);
|
|
67
|
+
if (plugin) {
|
|
68
|
+
onExportFound(decl, decl.id.name, plugin);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else if (n.declaration === null && n.specifiers) {
|
|
72
|
+
for (const spec of n.specifiers) {
|
|
73
|
+
if (typeof spec.exported.name === "string") {
|
|
74
|
+
const plugin = registeredExports.get(spec.exported.name);
|
|
75
|
+
if (plugin) {
|
|
76
|
+
const variableName = ((_c = spec.local) == null ? void 0 : _c.name) || spec.exported.name;
|
|
77
|
+
for (const decl of program.body) {
|
|
78
|
+
if (decl.type === "VariableDeclaration" && decl.declarations[0]) {
|
|
79
|
+
const variable = decl.declarations[0];
|
|
80
|
+
if (variable.type === "VariableDeclarator" && variable.id.type === "Identifier" && variable.id.name === variableName) {
|
|
81
|
+
onExportFound(variable, spec.exported.name, plugin);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
62
87
|
}
|
|
63
|
-
registeredExports.delete(decl.id.name);
|
|
64
|
-
foundExports.push(decl.id.name);
|
|
65
88
|
}
|
|
66
89
|
}
|
|
67
90
|
}
|
|
@@ -197,7 +220,7 @@ async function transform({
|
|
|
197
220
|
if (importDeclarationsToRemove.length > 0) {
|
|
198
221
|
appliedChanges = true;
|
|
199
222
|
for (const importDeclaration of importDeclarationsToRemove) {
|
|
200
|
-
if (((
|
|
223
|
+
if (((_d = importDeclaration.specifiers) == null ? void 0 : _d.length) === 0) {
|
|
201
224
|
const index = program.body.indexOf(importDeclaration);
|
|
202
225
|
if (index !== -1) {
|
|
203
226
|
program.body.splice(index, 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.cjs","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (\n registeredExports.size > 0 &&\n n.type === 'ExportNamedDeclaration' &&\n n.declaration?.type === 'VariableDeclaration'\n ) {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(decl.id.name)\n // store the export so we can later return it once the file is transformed\n foundExports.push(decl.id.name)\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["types","parse","parseAst","mergeImportDeclarations","importStatement","print","sourceMap","SourceMapConsumer","visit"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.cjs","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n function onExportFound(\n decl: types.namedTypes.VariableDeclarator,\n exportName: string,\n plugin: TransformPlugin,\n ) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(exportName)\n // store the export so we can later return it once the file is transformed\n foundExports.push(exportName)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (registeredExports.size > 0 && n.type === 'ExportNamedDeclaration') {\n // direct export of a variable declaration, e.g. `export const Route = createFileRoute('/path')`\n if (n.declaration?.type === 'VariableDeclaration') {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n onExportFound(decl, decl.id.name, plugin)\n }\n }\n }\n // this is an export without a declaration, e.g. `export { Route }`\n else if (n.declaration === null && n.specifiers) {\n for (const spec of n.specifiers) {\n if (typeof spec.exported.name === 'string') {\n const plugin = registeredExports.get(spec.exported.name)\n if (plugin) {\n const variableName = spec.local?.name || spec.exported.name\n // find the matching variable declaration by iterating over the top-level declarations\n for (const decl of program.body) {\n if (\n decl.type === 'VariableDeclaration' &&\n decl.declarations[0]\n ) {\n const variable = decl.declarations[0]\n if (\n variable.type === 'VariableDeclarator' &&\n variable.id.type === 'Identifier' &&\n variable.id.name === variableName\n ) {\n onExportFound(variable, spec.exported.name, plugin)\n break\n }\n }\n }\n }\n }\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["types","parse","parseAst","mergeImportDeclarations","importStatement","print","sourceMap","SourceMapConsumer","visit"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ async function transform({
|
|
|
8
8
|
source,
|
|
9
9
|
plugins
|
|
10
10
|
}) {
|
|
11
|
-
var _a, _b, _c;
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
12
|
let appliedChanges = false;
|
|
13
13
|
let ast;
|
|
14
14
|
const foundExports = [];
|
|
@@ -44,22 +44,45 @@ async function transform({
|
|
|
44
44
|
}
|
|
45
45
|
registeredExports.set(exportName, plugin);
|
|
46
46
|
}
|
|
47
|
+
function onExportFound(decl, exportName, plugin) {
|
|
48
|
+
const pluginAppliedChanges = plugin.onExportFound({
|
|
49
|
+
decl,
|
|
50
|
+
ctx: { ...ctx, preferredQuote }
|
|
51
|
+
});
|
|
52
|
+
if (pluginAppliedChanges) {
|
|
53
|
+
appliedChanges = true;
|
|
54
|
+
}
|
|
55
|
+
registeredExports.delete(exportName);
|
|
56
|
+
foundExports.push(exportName);
|
|
57
|
+
}
|
|
47
58
|
const program = ast.program;
|
|
48
59
|
for (const n of program.body) {
|
|
49
|
-
if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
decl,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration") {
|
|
61
|
+
if (((_b = n.declaration) == null ? void 0 : _b.type) === "VariableDeclaration") {
|
|
62
|
+
const decl = n.declaration.declarations[0];
|
|
63
|
+
if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
|
|
64
|
+
const plugin = registeredExports.get(decl.id.name);
|
|
65
|
+
if (plugin) {
|
|
66
|
+
onExportFound(decl, decl.id.name, plugin);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else if (n.declaration === null && n.specifiers) {
|
|
70
|
+
for (const spec of n.specifiers) {
|
|
71
|
+
if (typeof spec.exported.name === "string") {
|
|
72
|
+
const plugin = registeredExports.get(spec.exported.name);
|
|
73
|
+
if (plugin) {
|
|
74
|
+
const variableName = ((_c = spec.local) == null ? void 0 : _c.name) || spec.exported.name;
|
|
75
|
+
for (const decl of program.body) {
|
|
76
|
+
if (decl.type === "VariableDeclaration" && decl.declarations[0]) {
|
|
77
|
+
const variable = decl.declarations[0];
|
|
78
|
+
if (variable.type === "VariableDeclarator" && variable.id.type === "Identifier" && variable.id.name === variableName) {
|
|
79
|
+
onExportFound(variable, spec.exported.name, plugin);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
60
85
|
}
|
|
61
|
-
registeredExports.delete(decl.id.name);
|
|
62
|
-
foundExports.push(decl.id.name);
|
|
63
86
|
}
|
|
64
87
|
}
|
|
65
88
|
}
|
|
@@ -195,7 +218,7 @@ async function transform({
|
|
|
195
218
|
if (importDeclarationsToRemove.length > 0) {
|
|
196
219
|
appliedChanges = true;
|
|
197
220
|
for (const importDeclaration of importDeclarationsToRemove) {
|
|
198
|
-
if (((
|
|
221
|
+
if (((_d = importDeclaration.specifiers) == null ? void 0 : _d.length) === 0) {
|
|
199
222
|
const index = program.body.indexOf(importDeclaration);
|
|
200
223
|
if (index !== -1) {
|
|
201
224
|
program.body.splice(index, 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (\n registeredExports.size > 0 &&\n n.type === 'ExportNamedDeclaration' &&\n n.declaration?.type === 'VariableDeclaration'\n ) {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(decl.id.name)\n // store the export so we can later return it once the file is transformed\n foundExports.push(decl.id.name)\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["importStatement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.js","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n function onExportFound(\n decl: types.namedTypes.VariableDeclarator,\n exportName: string,\n plugin: TransformPlugin,\n ) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(exportName)\n // store the export so we can later return it once the file is transformed\n foundExports.push(exportName)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (registeredExports.size > 0 && n.type === 'ExportNamedDeclaration') {\n // direct export of a variable declaration, e.g. `export const Route = createFileRoute('/path')`\n if (n.declaration?.type === 'VariableDeclaration') {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n onExportFound(decl, decl.id.name, plugin)\n }\n }\n }\n // this is an export without a declaration, e.g. `export { Route }`\n else if (n.declaration === null && n.specifiers) {\n for (const spec of n.specifiers) {\n if (typeof spec.exported.name === 'string') {\n const plugin = registeredExports.get(spec.exported.name)\n if (plugin) {\n const variableName = spec.local?.name || spec.exported.name\n // find the matching variable declaration by iterating over the top-level declarations\n for (const decl of program.body) {\n if (\n decl.type === 'VariableDeclaration' &&\n decl.declarations[0]\n ) {\n const variable = decl.declarations[0]\n if (\n variable.type === 'VariableDeclarator' &&\n variable.id.type === 'Identifier' &&\n variable.id.name === variableName\n ) {\n onExportFound(variable, spec.exported.name, plugin)\n break\n }\n }\n }\n }\n }\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["importStatement"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-generator",
|
|
3
|
-
"version": "1.121.
|
|
3
|
+
"version": "1.121.6",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"source-map": "^0.7.4",
|
|
55
55
|
"tsx": "^4.19.2",
|
|
56
56
|
"zod": "^3.24.2",
|
|
57
|
-
"@tanstack/router-core": "^1.121.
|
|
57
|
+
"@tanstack/router-core": "^1.121.2",
|
|
58
58
|
"@tanstack/router-utils": "^1.121.0",
|
|
59
59
|
"@tanstack/virtual-file-routes": "^1.120.17"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@tanstack/react-router": "^1.121.
|
|
62
|
+
"@tanstack/react-router": "^1.121.2"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {}
|
|
65
65
|
}
|
|
@@ -56,35 +56,69 @@ export async function transform({
|
|
|
56
56
|
registeredExports.set(exportName, plugin)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function onExportFound(
|
|
60
|
+
decl: types.namedTypes.VariableDeclarator,
|
|
61
|
+
exportName: string,
|
|
62
|
+
plugin: TransformPlugin,
|
|
63
|
+
) {
|
|
64
|
+
const pluginAppliedChanges = plugin.onExportFound({
|
|
65
|
+
decl,
|
|
66
|
+
ctx: { ...ctx, preferredQuote },
|
|
67
|
+
})
|
|
68
|
+
if (pluginAppliedChanges) {
|
|
69
|
+
appliedChanges = true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// export is handled, remove it from the registered exports
|
|
73
|
+
registeredExports.delete(exportName)
|
|
74
|
+
// store the export so we can later return it once the file is transformed
|
|
75
|
+
foundExports.push(exportName)
|
|
76
|
+
}
|
|
77
|
+
|
|
59
78
|
const program: types.namedTypes.Program = ast.program
|
|
60
79
|
// first pass: find registered exports
|
|
61
80
|
for (const n of program.body) {
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
n.type === '
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
81
|
+
if (registeredExports.size > 0 && n.type === 'ExportNamedDeclaration') {
|
|
82
|
+
// direct export of a variable declaration, e.g. `export const Route = createFileRoute('/path')`
|
|
83
|
+
if (n.declaration?.type === 'VariableDeclaration') {
|
|
84
|
+
const decl = n.declaration.declarations[0]
|
|
85
|
+
if (
|
|
86
|
+
decl &&
|
|
87
|
+
decl.type === 'VariableDeclarator' &&
|
|
88
|
+
decl.id.type === 'Identifier'
|
|
89
|
+
) {
|
|
90
|
+
const plugin = registeredExports.get(decl.id.name)
|
|
91
|
+
if (plugin) {
|
|
92
|
+
onExportFound(decl, decl.id.name, plugin)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// this is an export without a declaration, e.g. `export { Route }`
|
|
97
|
+
else if (n.declaration === null && n.specifiers) {
|
|
98
|
+
for (const spec of n.specifiers) {
|
|
99
|
+
if (typeof spec.exported.name === 'string') {
|
|
100
|
+
const plugin = registeredExports.get(spec.exported.name)
|
|
101
|
+
if (plugin) {
|
|
102
|
+
const variableName = spec.local?.name || spec.exported.name
|
|
103
|
+
// find the matching variable declaration by iterating over the top-level declarations
|
|
104
|
+
for (const decl of program.body) {
|
|
105
|
+
if (
|
|
106
|
+
decl.type === 'VariableDeclaration' &&
|
|
107
|
+
decl.declarations[0]
|
|
108
|
+
) {
|
|
109
|
+
const variable = decl.declarations[0]
|
|
110
|
+
if (
|
|
111
|
+
variable.type === 'VariableDeclarator' &&
|
|
112
|
+
variable.id.type === 'Identifier' &&
|
|
113
|
+
variable.id.name === variableName
|
|
114
|
+
) {
|
|
115
|
+
onExportFound(variable, spec.exported.name, plugin)
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
82
121
|
}
|
|
83
|
-
|
|
84
|
-
// export is handled, remove it from the registered exports
|
|
85
|
-
registeredExports.delete(decl.id.name)
|
|
86
|
-
// store the export so we can later return it once the file is transformed
|
|
87
|
-
foundExports.push(decl.id.name)
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
}
|