@tanstack/router-generator 1.166.29 → 1.166.31
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.
- package/dist/cjs/config.cjs +0 -1
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +0 -3
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +5 -4
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +2 -2
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/generator.cjs +1 -44
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/index.cjs +0 -2
- package/dist/cjs/index.d.cts +1 -2
- package/dist/cjs/template.cjs +15 -12
- package/dist/cjs/template.cjs.map +1 -1
- package/dist/cjs/transform/transform.cjs +283 -266
- package/dist/cjs/transform/transform.cjs.map +1 -1
- package/dist/cjs/transform/transform.d.cts +1 -3
- package/dist/cjs/transform/types.d.cts +1 -7
- package/dist/cjs/utils.cjs +0 -16
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +0 -24
- package/dist/esm/config.d.ts +0 -3
- package/dist/esm/config.js +0 -1
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.js +6 -5
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
- package/dist/esm/filesystem/virtual/getRouteNodes.js +3 -3
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
- package/dist/esm/generator.js +2 -45
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/index.d.ts +1 -2
- package/dist/esm/index.js +1 -2
- package/dist/esm/template.js +15 -12
- package/dist/esm/template.js.map +1 -1
- package/dist/esm/transform/transform.d.ts +1 -3
- package/dist/esm/transform/transform.js +280 -265
- package/dist/esm/transform/transform.js.map +1 -1
- package/dist/esm/transform/types.d.ts +1 -7
- package/dist/esm/utils.d.ts +0 -24
- package/dist/esm/utils.js +1 -15
- package/dist/esm/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/config.ts +0 -1
- package/src/filesystem/physical/getRouteNodes.ts +10 -4
- package/src/filesystem/virtual/getRouteNodes.ts +7 -2
- package/src/generator.ts +0 -66
- package/src/index.ts +1 -7
- package/src/template.ts +16 -36
- package/src/transform/transform.ts +633 -446
- package/src/transform/types.ts +1 -8
- package/src/utils.ts +5 -43
- package/dist/cjs/transform/utils.cjs +0 -34
- package/dist/cjs/transform/utils.cjs.map +0 -1
- package/dist/cjs/transform/utils.d.cts +0 -2
- package/dist/esm/transform/utils.d.ts +0 -2
- package/dist/esm/transform/utils.js +0 -34
- package/dist/esm/transform/utils.js.map +0 -1
- package/src/transform/utils.ts +0 -42
|
@@ -1,298 +1,313 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import MagicString from "magic-string";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
3
|
import { parseAst } from "@tanstack/router-utils";
|
|
4
|
-
import { parse, print, types, visit } from "recast";
|
|
5
|
-
import { SourceMapConsumer } from "source-map";
|
|
6
4
|
//#region src/transform/transform.ts
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
let appliedChanges = false;
|
|
5
|
+
var routeConstructors = ["createFileRoute", "createLazyFileRoute"];
|
|
6
|
+
function transform({ ctx, source, node }) {
|
|
10
7
|
let ast;
|
|
11
8
|
try {
|
|
12
|
-
ast =
|
|
13
|
-
|
|
14
|
-
parser: { parse(code) {
|
|
15
|
-
return parseAst({
|
|
16
|
-
code,
|
|
17
|
-
tokens: true
|
|
18
|
-
});
|
|
19
|
-
} }
|
|
20
|
-
});
|
|
21
|
-
} catch (e) {
|
|
22
|
-
console.error("Error parsing code", ctx.routeId, source, e);
|
|
9
|
+
ast = parseAst({ code: source });
|
|
10
|
+
} catch (error) {
|
|
23
11
|
return {
|
|
24
12
|
result: "error",
|
|
25
|
-
error
|
|
13
|
+
error
|
|
26
14
|
};
|
|
27
15
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (identifier.name === "createFileRoute" && ctx.lazy) {
|
|
59
|
-
identifier.name = "createLazyFileRoute";
|
|
60
|
-
appliedChanges = true;
|
|
61
|
-
} else if (identifier.name === "createLazyFileRoute" && !ctx.lazy) {
|
|
62
|
-
identifier.name = "createFileRoute";
|
|
63
|
-
appliedChanges = true;
|
|
64
|
-
}
|
|
65
|
-
} else throw new Error(`expected "Route" export to be initialized by a CallExpression`);
|
|
66
|
-
routeExportHandled = true;
|
|
16
|
+
const exportedRouteNames = getExportedRouteNames(ast.program.body);
|
|
17
|
+
if (exportedRouteNames.size === 0) return { result: "no-route-export" };
|
|
18
|
+
const { calls: routeCalls, hasUnsupportedRouteId, hasMalformedRouteCall } = findExportedRouteCalls(ast.program.body, exportedRouteNames);
|
|
19
|
+
if (routeCalls.length === 0 && hasMalformedRouteCall) return {
|
|
20
|
+
result: "error",
|
|
21
|
+
error: /* @__PURE__ */ new Error(`expected Route export in ${ctx.routeId} to use createFileRoute('/path')({...}) or createLazyFileRoute('/path')({...})`)
|
|
22
|
+
};
|
|
23
|
+
if (routeCalls.length === 0 && hasUnsupportedRouteId) return {
|
|
24
|
+
result: "error",
|
|
25
|
+
error: /* @__PURE__ */ new Error(`expected route id to be a string literal or plain template literal in ${ctx.routeId}`)
|
|
26
|
+
};
|
|
27
|
+
if (routeCalls.length === 0) return { result: "not-modified" };
|
|
28
|
+
if (routeCalls.length > 1) return {
|
|
29
|
+
result: "error",
|
|
30
|
+
error: /* @__PURE__ */ new Error(`expected exactly one createFileRoute/createLazyFileRoute call in ${ctx.routeId}`)
|
|
31
|
+
};
|
|
32
|
+
const routeCall = routeCalls[0];
|
|
33
|
+
const routeIdQuote = getRouteIdQuote(source, routeCall.routeIdArg);
|
|
34
|
+
const createFileRouteProps = getCreateFileRouteProps(routeCall.optionsArg);
|
|
35
|
+
if (createFileRouteProps) node.createFileRouteProps = createFileRouteProps;
|
|
36
|
+
const expectedCallee = getExpectedRouteConstructor(ctx.lazy);
|
|
37
|
+
const expectedRouteId = `${routeIdQuote}${ctx.routeId}${routeIdQuote}`;
|
|
38
|
+
const currentRouteId = source.slice(routeCall.routeIdArg.start, routeCall.routeIdArg.end);
|
|
39
|
+
const targetModule = `@tanstack/${ctx.target}-router`;
|
|
40
|
+
const imports = parseTargetImports(ast.program.body, source, targetModule);
|
|
41
|
+
const s = new MagicString(source);
|
|
42
|
+
let modified = false;
|
|
43
|
+
if (routeCall.callee.name !== expectedCallee) {
|
|
44
|
+
s.update(routeCall.callee.start, routeCall.callee.end, expectedCallee);
|
|
45
|
+
modified = true;
|
|
67
46
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (n.declaration?.type === "VariableDeclaration") {
|
|
72
|
-
const decl = n.declaration.declarations[0];
|
|
73
|
-
if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
|
|
74
|
-
if (decl.id.name === "Route") onExportFound(decl);
|
|
75
|
-
}
|
|
76
|
-
} else if (n.declaration === null && n.specifiers) {
|
|
77
|
-
for (const spec of n.specifiers) if (typeof spec.exported.name === "string") {
|
|
78
|
-
if (spec.exported.name === "Route") {
|
|
79
|
-
const variableName = spec.local?.name || spec.exported.name;
|
|
80
|
-
for (const decl of program.body) if (decl.type === "VariableDeclaration" && decl.declarations[0]) {
|
|
81
|
-
const variable = decl.declarations[0];
|
|
82
|
-
if (variable.type === "VariableDeclarator" && variable.id.type === "Identifier" && variable.id.name === variableName) {
|
|
83
|
-
onExportFound(variable);
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (routeExportHandled) break;
|
|
47
|
+
if (currentRouteId !== expectedRouteId) {
|
|
48
|
+
s.update(routeCall.routeIdArg.start, routeCall.routeIdArg.end, expectedRouteId);
|
|
49
|
+
modified = true;
|
|
92
50
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
51
|
+
if (updateRouteImports({
|
|
52
|
+
imports,
|
|
53
|
+
source,
|
|
54
|
+
s,
|
|
55
|
+
targetModule,
|
|
56
|
+
required: expectedCallee,
|
|
57
|
+
lineEnding: getLineEnding(source)
|
|
58
|
+
})) modified = true;
|
|
59
|
+
if (!modified) return { result: "not-modified" };
|
|
60
|
+
return {
|
|
61
|
+
result: "modified",
|
|
62
|
+
output: s.toString()
|
|
97
63
|
};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}];
|
|
112
|
-
} else {
|
|
113
|
-
imports.required = [{
|
|
114
|
-
source: targetModule,
|
|
115
|
-
specifiers: [{ imported: "createFileRoute" }]
|
|
116
|
-
}];
|
|
117
|
-
imports.banned = [{
|
|
118
|
-
source: targetModule,
|
|
119
|
-
specifiers: [{ imported: "createLazyFileRoute" }]
|
|
120
|
-
}];
|
|
64
|
+
}
|
|
65
|
+
function getExportedRouteNames(body) {
|
|
66
|
+
const exportedRouteNames = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const statement of body) {
|
|
68
|
+
if (!t.isExportNamedDeclaration(statement) || statement.source) continue;
|
|
69
|
+
if (t.isVariableDeclaration(statement.declaration)) {
|
|
70
|
+
for (const declarator of statement.declaration.declarations) if (t.isIdentifier(declarator.id) && declarator.id.name === "Route") exportedRouteNames.add("Route");
|
|
71
|
+
}
|
|
72
|
+
for (const specifier of statement.specifiers) {
|
|
73
|
+
if (!t.isExportSpecifier(specifier) || getExportedName(specifier.exported) !== "Route") continue;
|
|
74
|
+
const localName = getLocalBindingName(specifier.local);
|
|
75
|
+
if (localName) exportedRouteNames.add(localName);
|
|
76
|
+
}
|
|
121
77
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
78
|
+
return exportedRouteNames;
|
|
79
|
+
}
|
|
80
|
+
function findExportedRouteCalls(body, exportedRouteNames) {
|
|
81
|
+
const calls = [];
|
|
82
|
+
let hasUnsupportedRouteId = false;
|
|
83
|
+
let hasMalformedRouteCall = false;
|
|
84
|
+
for (const statement of body) {
|
|
85
|
+
const declaration = getVariableDeclaration(statement);
|
|
86
|
+
if (!declaration) continue;
|
|
87
|
+
for (const declarator of declaration.declarations) {
|
|
88
|
+
if (!t.isIdentifier(declarator.id) || !exportedRouteNames.has(declarator.id.name)) continue;
|
|
89
|
+
const init = getRouteConstructorInit(declarator.init);
|
|
90
|
+
if (!init) {
|
|
91
|
+
if (isDirectRouteConstructorCall(declarator.init)) hasMalformedRouteCall = true;
|
|
92
|
+
continue;
|
|
131
93
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
importKind: n.importKind
|
|
94
|
+
const routeIdArg = init.innerCall.arguments[0];
|
|
95
|
+
if (isSupportedRouteId(routeIdArg)) calls.push({
|
|
96
|
+
callee: init.callee,
|
|
97
|
+
routeIdArg,
|
|
98
|
+
optionsArg: init.outerCall.arguments[0]
|
|
138
99
|
});
|
|
139
|
-
|
|
140
|
-
const bannedImports = imports.banned.filter(filterImport)[0];
|
|
141
|
-
if (!requiredImports && !bannedImports) continue;
|
|
142
|
-
const importSpecifiersToRemove = [];
|
|
143
|
-
if (n.specifiers) {
|
|
144
|
-
for (const spec of n.specifiers) {
|
|
145
|
-
if (!requiredImports && !bannedImports) break;
|
|
146
|
-
if (spec.type === "ImportSpecifier" && typeof spec.imported.name === "string") {
|
|
147
|
-
if (requiredImports) {
|
|
148
|
-
const requiredImportIndex = requiredImports.specifiers.findIndex((imp) => imp.imported === spec.imported.name);
|
|
149
|
-
if (requiredImportIndex !== -1) {
|
|
150
|
-
requiredImports.specifiers.splice(requiredImportIndex, 1);
|
|
151
|
-
if (requiredImports.specifiers.length === 0) {
|
|
152
|
-
imports.required = imports.required.splice(imports.required.indexOf(requiredImports), 1);
|
|
153
|
-
requiredImports = void 0;
|
|
154
|
-
}
|
|
155
|
-
} else importStatementCandidates.push(n);
|
|
156
|
-
}
|
|
157
|
-
if (bannedImports) {
|
|
158
|
-
if (bannedImports.specifiers.findIndex((imp) => imp.imported === spec.imported.name) !== -1) importSpecifiersToRemove.push(spec);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
if (importSpecifiersToRemove.length > 0) {
|
|
163
|
-
appliedChanges = true;
|
|
164
|
-
n.specifiers = n.specifiers.filter((spec) => !importSpecifiersToRemove.includes(spec));
|
|
165
|
-
if (n.specifiers.length === 0) importDeclarationsToRemove.push(n);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
100
|
+
else hasUnsupportedRouteId = true;
|
|
168
101
|
}
|
|
169
102
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
103
|
+
return {
|
|
104
|
+
calls,
|
|
105
|
+
hasUnsupportedRouteId,
|
|
106
|
+
hasMalformedRouteCall
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function getVariableDeclaration(statement) {
|
|
110
|
+
const declaration = t.isExportNamedDeclaration(statement) ? statement.declaration : statement;
|
|
111
|
+
return t.isVariableDeclaration(declaration) ? declaration : null;
|
|
112
|
+
}
|
|
113
|
+
function getExportedName(node) {
|
|
114
|
+
return t.isIdentifier(node) ? node.name : node.value;
|
|
115
|
+
}
|
|
116
|
+
function getLocalBindingName(node) {
|
|
117
|
+
return t.isIdentifier(node) ? node.name : null;
|
|
118
|
+
}
|
|
119
|
+
function getRouteConstructorInit(expression) {
|
|
120
|
+
if (!expression || !t.isCallExpression(expression)) return null;
|
|
121
|
+
if (!t.isCallExpression(expression.callee)) return null;
|
|
122
|
+
const innerCall = expression.callee;
|
|
123
|
+
if (!t.isIdentifier(innerCall.callee) || !isRouteConstructor(innerCall.callee)) return null;
|
|
124
|
+
return {
|
|
125
|
+
callee: innerCall.callee,
|
|
126
|
+
outerCall: expression,
|
|
127
|
+
innerCall
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function isDirectRouteConstructorCall(expression) {
|
|
131
|
+
return !!expression && t.isCallExpression(expression) && t.isIdentifier(expression.callee) && isRouteConstructor(expression.callee);
|
|
132
|
+
}
|
|
133
|
+
function isRouteConstructor(callee) {
|
|
134
|
+
return routeConstructors.includes(callee.name);
|
|
135
|
+
}
|
|
136
|
+
function isSupportedRouteId(arg) {
|
|
137
|
+
return !!arg && (t.isStringLiteral(arg) || t.isTemplateLiteral(arg) && arg.expressions.length === 0);
|
|
138
|
+
}
|
|
139
|
+
function getRouteIdQuote(source, arg) {
|
|
140
|
+
const raw = source.slice(arg.start, arg.end);
|
|
141
|
+
if (raw.startsWith("'")) return "'";
|
|
142
|
+
if (raw.startsWith("\"")) return "\"";
|
|
143
|
+
return "`";
|
|
144
|
+
}
|
|
145
|
+
function getCreateFileRouteProps(arg) {
|
|
146
|
+
if (!arg || !t.isObjectExpression(arg)) return;
|
|
147
|
+
const props = /* @__PURE__ */ new Set();
|
|
148
|
+
for (const property of arg.properties) {
|
|
149
|
+
if (!t.isObjectProperty(property) || property.computed) continue;
|
|
150
|
+
if (t.isIdentifier(property.key)) {
|
|
151
|
+
props.add(property.key.name);
|
|
152
|
+
continue;
|
|
187
153
|
}
|
|
154
|
+
if (t.isStringLiteral(property.key)) props.add(property.key.value);
|
|
155
|
+
}
|
|
156
|
+
return props;
|
|
157
|
+
}
|
|
158
|
+
function parseTargetImports(body, source, targetModule) {
|
|
159
|
+
const imports = [];
|
|
160
|
+
for (const statement of body) {
|
|
161
|
+
if (!t.isImportDeclaration(statement) || statement.importKind === "type" || statement.source.value !== targetModule) continue;
|
|
162
|
+
const rawSource = source.slice(statement.source.start, statement.source.end);
|
|
163
|
+
const importStatement = source.slice(statement.start, statement.end);
|
|
164
|
+
imports.push({
|
|
165
|
+
declaration: statement,
|
|
166
|
+
defaultImport: statement.specifiers.find((specifier) => t.isImportDefaultSpecifier(specifier))?.local.name,
|
|
167
|
+
namespace: statement.specifiers.find((specifier) => t.isImportNamespaceSpecifier(specifier))?.local.name,
|
|
168
|
+
named: statement.specifiers.filter((specifier) => t.isImportSpecifier(specifier)).map((specifier) => ({
|
|
169
|
+
imported: t.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value,
|
|
170
|
+
local: specifier.local.name,
|
|
171
|
+
importKind: specifier.importKind ?? void 0
|
|
172
|
+
})),
|
|
173
|
+
moduleName: statement.source.value,
|
|
174
|
+
quote: rawSource[0],
|
|
175
|
+
semicolon: importStatement.trimEnd().endsWith(";")
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return imports;
|
|
179
|
+
}
|
|
180
|
+
function updateRouteImports({ imports, source, s, targetModule, required, lineEnding }) {
|
|
181
|
+
const analysis = analyzeRouteImports(imports, required);
|
|
182
|
+
if (analysis.kind === "ok") return false;
|
|
183
|
+
if (analysis.kind === "rename") {
|
|
184
|
+
s.update(analysis.imported.start, analysis.imported.end, analysis.next);
|
|
185
|
+
s.update(analysis.local.start, analysis.local.end, analysis.next);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
return normalizeRouteImports({
|
|
189
|
+
imports,
|
|
190
|
+
source,
|
|
191
|
+
s,
|
|
192
|
+
targetModule,
|
|
193
|
+
required,
|
|
194
|
+
lineEnding
|
|
188
195
|
});
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
}
|
|
197
|
+
function analyzeRouteImports(imports, required) {
|
|
198
|
+
const opposite = getOtherRouteConstructor(required);
|
|
199
|
+
let requiredCount = 0;
|
|
200
|
+
let oppositeCount = 0;
|
|
201
|
+
let renameCandidate;
|
|
202
|
+
for (const declaration of imports) for (const specifier of declaration.declaration.specifiers) {
|
|
203
|
+
if (!t.isImportSpecifier(specifier)) continue;
|
|
204
|
+
const imported = specifier.imported;
|
|
205
|
+
if (!t.isIdentifier(imported)) return { kind: "normalize" };
|
|
206
|
+
if (!isRouteConstructorName(imported.name)) continue;
|
|
207
|
+
if (specifier.local.name !== imported.name) return { kind: "normalize" };
|
|
208
|
+
if (imported.name === required) {
|
|
209
|
+
requiredCount++;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (imported.name === opposite) {
|
|
213
|
+
oppositeCount++;
|
|
214
|
+
renameCandidate = {
|
|
215
|
+
imported,
|
|
216
|
+
local: specifier.local,
|
|
217
|
+
next: required
|
|
218
|
+
};
|
|
194
219
|
}
|
|
195
220
|
}
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
});
|
|
201
|
-
let transformedCode = printResult.code;
|
|
202
|
-
if (printResult.map) transformedCode = await fixTransformedOutputText({
|
|
203
|
-
originalCode: source,
|
|
204
|
-
transformedCode,
|
|
205
|
-
sourceMap: printResult.map,
|
|
206
|
-
preferredQuote
|
|
207
|
-
});
|
|
208
|
-
return {
|
|
209
|
-
result: "modified",
|
|
210
|
-
output: transformedCode
|
|
221
|
+
if (requiredCount === 1 && oppositeCount === 0) return { kind: "ok" };
|
|
222
|
+
if (requiredCount === 0 && oppositeCount === 1 && renameCandidate) return {
|
|
223
|
+
kind: "rename",
|
|
224
|
+
...renameCandidate
|
|
211
225
|
};
|
|
226
|
+
return { kind: "normalize" };
|
|
212
227
|
}
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
for (let col = 0; col < line.length; col++) {
|
|
222
|
-
const mapped = consumer.originalPositionFor({
|
|
223
|
-
line: transformedLineNum,
|
|
224
|
-
column: col
|
|
225
|
-
});
|
|
226
|
-
if (mapped.line != null && mapped.line > 0) {
|
|
227
|
-
origLineText = originalLines[mapped.line - 1];
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (origLineText !== void 0) {
|
|
232
|
-
if (origLineText === line) return origLineText;
|
|
233
|
-
return fixLine(line, {
|
|
234
|
-
originalLine: origLineText,
|
|
235
|
-
useOriginalSemicolon: true,
|
|
236
|
-
useOriginalQuotes: true,
|
|
237
|
-
fallbackQuote: preferredQuote
|
|
238
|
-
});
|
|
239
|
-
} else return fixLine(line, {
|
|
240
|
-
originalLine: null,
|
|
241
|
-
useOriginalSemicolon: false,
|
|
242
|
-
useOriginalQuotes: false,
|
|
243
|
-
fallbackQuote: preferredQuote,
|
|
244
|
-
fallbackSemicolon: defaultUsesSemicolons
|
|
228
|
+
function normalizeRouteImports({ imports, source, s, targetModule, required, lineEnding }) {
|
|
229
|
+
const owner = imports.find((declaration) => hasNamedImport(declaration.named, required)) ?? imports.find((declaration) => !declaration.namespace);
|
|
230
|
+
let modified = false;
|
|
231
|
+
for (const declaration of imports) {
|
|
232
|
+
const named = normalizeNamedImports({
|
|
233
|
+
named: declaration.named,
|
|
234
|
+
required,
|
|
235
|
+
isOwner: declaration === owner
|
|
245
236
|
});
|
|
246
|
-
|
|
237
|
+
if (sameNamedImports(declaration.named, named)) continue;
|
|
238
|
+
const replacement = renderImportDeclaration({
|
|
239
|
+
...declaration,
|
|
240
|
+
named
|
|
241
|
+
});
|
|
242
|
+
if (replacement === null) {
|
|
243
|
+
s.remove(declaration.declaration.start, getRemovalEnd(source, declaration.declaration.end));
|
|
244
|
+
modified = true;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
s.update(declaration.declaration.start, declaration.declaration.end, replacement);
|
|
248
|
+
modified = true;
|
|
249
|
+
}
|
|
250
|
+
if (!owner) {
|
|
251
|
+
const quote = imports[0]?.quote ?? "'";
|
|
252
|
+
const semicolon = imports[0]?.semicolon ?? false;
|
|
253
|
+
s.prepend(`import { ${required} } from ${quote}${targetModule}${quote}${semicolon ? ";" : ""}${lineEnding}`);
|
|
254
|
+
modified = true;
|
|
255
|
+
}
|
|
256
|
+
return modified;
|
|
247
257
|
}
|
|
248
|
-
function
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\s*$/, "");
|
|
260
|
-
if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ";";
|
|
258
|
+
function normalizeNamedImports({ named, required, isOwner }) {
|
|
259
|
+
const banned = getOtherRouteConstructor(required);
|
|
260
|
+
const nextNamed = [];
|
|
261
|
+
const seen = /* @__PURE__ */ new Set();
|
|
262
|
+
for (const specifier of named) {
|
|
263
|
+
if (specifier.imported === banned) continue;
|
|
264
|
+
if (specifier.local === required && (specifier.imported !== required || !isOwner)) continue;
|
|
265
|
+
const key = `${specifier.importKind ?? "value"}:${specifier.imported}:${specifier.local}`;
|
|
266
|
+
if (seen.has(key)) continue;
|
|
267
|
+
seen.add(key);
|
|
268
|
+
nextNamed.push(specifier);
|
|
261
269
|
}
|
|
262
|
-
|
|
270
|
+
if (isOwner && !hasNamedImport(nextNamed, required)) nextNamed.push({
|
|
271
|
+
imported: required,
|
|
272
|
+
local: required
|
|
273
|
+
});
|
|
274
|
+
return nextNamed;
|
|
263
275
|
}
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
if (!originalQuote) originalQuote = fallbackQuote;
|
|
267
|
-
return fixQuotesToPreferred(line, originalQuote);
|
|
276
|
+
function getExpectedRouteConstructor(lazy) {
|
|
277
|
+
return lazy ? "createLazyFileRoute" : "createFileRoute";
|
|
268
278
|
}
|
|
269
|
-
function
|
|
270
|
-
return
|
|
271
|
-
return `${quote}${content.replaceAll(quote, `\\${quote}`)}${quote}`;
|
|
272
|
-
});
|
|
279
|
+
function getOtherRouteConstructor(constructor) {
|
|
280
|
+
return constructor === "createFileRoute" ? "createLazyFileRoute" : "createFileRoute";
|
|
273
281
|
}
|
|
274
|
-
function
|
|
275
|
-
|
|
276
|
-
return match ? match[1] : null;
|
|
282
|
+
function hasNamedImport(named, required) {
|
|
283
|
+
return named.some((specifier) => specifier.imported === required && specifier.local === required && specifier.importKind !== "type");
|
|
277
284
|
}
|
|
278
|
-
function
|
|
279
|
-
|
|
280
|
-
const total = lines.length;
|
|
281
|
-
return lines.filter((l) => l.endsWith(";")).length > total / 2;
|
|
285
|
+
function sameNamedImports(left, right) {
|
|
286
|
+
return left.length === right.length && left.every((specifier, index) => specifier.imported === right[index].imported && specifier.local === right[index].local && specifier.importKind === right[index].importKind);
|
|
282
287
|
}
|
|
283
|
-
function
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return "\"
|
|
288
|
+
function isRouteConstructorName(value) {
|
|
289
|
+
return routeConstructors.includes(value);
|
|
290
|
+
}
|
|
291
|
+
function renderImportDeclaration(importDeclaration) {
|
|
292
|
+
const parts = [];
|
|
293
|
+
if (importDeclaration.defaultImport) parts.push(importDeclaration.defaultImport);
|
|
294
|
+
if (importDeclaration.namespace) parts.push(`* as ${importDeclaration.namespace}`);
|
|
295
|
+
if (importDeclaration.named.length > 0) parts.push(`{ ${importDeclaration.named.map((specifier) => `${specifier.importKind === "type" ? "type " : ""}${specifier.imported === specifier.local ? specifier.imported : `${specifier.imported} as ${specifier.local}`}`).join(", ")} }`);
|
|
296
|
+
if (parts.length === 0) return null;
|
|
297
|
+
return `import ${parts.join(", ")} from ${importDeclaration.quote}${importDeclaration.moduleName}${importDeclaration.quote}${importDeclaration.semicolon ? ";" : ""}`;
|
|
298
|
+
}
|
|
299
|
+
function getLineEnding(source) {
|
|
300
|
+
if (source.includes("\r\n")) return "\r\n";
|
|
301
|
+
if (source.includes("\n")) return "\n";
|
|
302
|
+
if (source.includes("\r")) return "\r";
|
|
303
|
+
return "\n";
|
|
304
|
+
}
|
|
305
|
+
function getRemovalEnd(source, end) {
|
|
306
|
+
let pos = end;
|
|
307
|
+
while (pos < source.length && (source[pos] === " " || source[pos] === " ")) pos++;
|
|
308
|
+
if (source[pos] === "\r" && source[pos + 1] === "\n") return pos + 2;
|
|
309
|
+
if (source[pos] === "\n" || source[pos] === "\r") return pos + 1;
|
|
310
|
+
return end;
|
|
296
311
|
}
|
|
297
312
|
//#endregion
|
|
298
313
|
export { transform };
|