rsbuild-plugin-react-router 0.1.1 → 0.3.0
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/README.md +185 -204
- package/dist/451.js +1087 -0
- package/dist/bounded-cache.d.ts +1 -0
- package/dist/build-manifest.d.ts +1 -1
- package/dist/build-output-transforms.d.ts +30 -0
- package/dist/concurrency.d.ts +2 -0
- package/dist/config-imports.d.ts +3 -0
- package/dist/constants.d.ts +3 -0
- package/dist/dev-generation.d.ts +25 -0
- package/dist/dev-runtime-artifacts.d.ts +39 -0
- package/dist/dev-runtime-compilation.d.ts +32 -0
- package/dist/dev-runtime-controller.d.ts +14 -0
- package/dist/dev-runtime-session.d.ts +34 -0
- package/dist/dev-server.d.ts +11 -2
- package/dist/export-utils.d.ts +15 -7
- package/dist/index.cjs +3085 -1272
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2039 -1299
- package/dist/lazy-compilation.d.ts +5 -0
- package/dist/manifest.d.ts +32 -9
- package/dist/modify-browser-manifest.d.ts +30 -13
- package/dist/parallel-route-transform-protocol.d.ts +25 -0
- package/dist/parallel-route-transform-worker.d.ts +1 -0
- package/dist/parallel-route-transform-worker.js +38 -0
- package/dist/parallel-route-transforms.d.ts +14 -0
- package/dist/performance.d.ts +26 -0
- package/dist/plugin-utils.d.ts +2 -12
- package/dist/prerender-build.d.ts +32 -0
- package/dist/prerender.d.ts +28 -2
- package/dist/react-router-config.d.ts +8 -1
- package/dist/route-artifacts.d.ts +33 -0
- package/dist/route-ast.d.ts +21 -0
- package/dist/route-chunks.d.ts +9 -1
- package/dist/route-component-transform.d.ts +5 -0
- package/dist/route-export-pruning.d.ts +6 -0
- package/dist/route-export-resolution.d.ts +5 -0
- package/dist/route-transform-tasks.d.ts +47 -0
- package/dist/route-watch.d.ts +27 -0
- package/dist/server-build-plan.d.ts +22 -0
- package/dist/server-utils.d.ts +3 -2
- package/dist/templates/entry.client.js +3 -3
- package/dist/templates/entry.server.cjs +11 -8
- package/dist/templates/entry.server.js +5 -5
- package/dist/typegen.d.ts +2 -0
- package/dist/types.d.ts +30 -12
- package/dist/virtual-modules.d.ts +2 -0
- package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
- package/dist/yuku.d.ts +15 -0
- package/package.json +26 -22
- package/src/bounded-cache.ts +18 -0
- package/src/build-manifest.ts +168 -0
- package/src/build-output-transforms.ts +273 -0
- package/src/concurrency.ts +34 -0
- package/src/config-imports.ts +45 -0
- package/src/constants.ts +91 -0
- package/src/dev-generation.ts +700 -0
- package/src/dev-runtime-artifacts.ts +207 -0
- package/src/dev-runtime-compilation.ts +92 -0
- package/src/dev-runtime-controller.ts +462 -0
- package/src/dev-runtime-session.ts +184 -0
- package/src/dev-server.ts +58 -0
- package/src/export-utils.ts +219 -0
- package/src/index.ts +1025 -0
- package/src/lazy-compilation.ts +94 -0
- package/src/manifest.ts +480 -0
- package/src/modify-browser-manifest.ts +245 -0
- package/src/parallel-route-transform-protocol.ts +35 -0
- package/src/parallel-route-transform-worker.ts +82 -0
- package/src/parallel-route-transforms.ts +332 -0
- package/src/performance.ts +254 -0
- package/src/plugin-utils.ts +82 -0
- package/src/prerender-build.ts +623 -0
- package/src/prerender.ts +367 -0
- package/src/react-router-config.ts +220 -0
- package/src/route-artifacts.ts +155 -0
- package/src/route-ast.ts +163 -0
- package/src/route-chunks.ts +857 -0
- package/src/route-component-transform.ts +314 -0
- package/src/route-config.ts +106 -0
- package/src/route-export-pruning.ts +668 -0
- package/src/route-export-resolution.ts +329 -0
- package/src/route-transform-tasks.ts +249 -0
- package/src/route-watch.ts +322 -0
- package/src/server-build-plan.ts +91 -0
- package/src/server-utils.ts +210 -0
- package/src/ssr-externals.ts +59 -0
- package/src/templates/context.ts +12 -0
- package/src/templates/entry.client.tsx +12 -0
- package/src/templates/entry.server.tsx +76 -0
- package/src/typegen.ts +49 -0
- package/src/types.ts +82 -0
- package/src/validation/validate-plugin-order.ts +76 -0
- package/src/virtual-modules.ts +30 -0
- package/src/warnings/warn-on-client-source-maps.ts +96 -0
- package/src/yuku.ts +67 -0
- package/dist/906.js +0 -1
- package/dist/946.js +0 -1
- package/dist/babel.d.ts +0 -8
- package/dist/rslib-runtime.js +0 -23
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NAMED_COMPONENT_EXPORTS,
|
|
3
|
+
NAMED_COMPONENT_EXPORTS_SET,
|
|
4
|
+
} from './constants.js';
|
|
5
|
+
import type { ParseResult } from 'yuku-parser';
|
|
6
|
+
import {
|
|
7
|
+
callExpression,
|
|
8
|
+
exportNamedDeclaration,
|
|
9
|
+
exportSpecifier,
|
|
10
|
+
getExportedName,
|
|
11
|
+
getProgram,
|
|
12
|
+
identifier,
|
|
13
|
+
importDeclaration,
|
|
14
|
+
patternIncludesName,
|
|
15
|
+
variableDeclaration,
|
|
16
|
+
type AnyNode,
|
|
17
|
+
} from './route-ast.js';
|
|
18
|
+
|
|
19
|
+
export function toFunctionExpression(decl: AnyNode): AnyNode {
|
|
20
|
+
return {
|
|
21
|
+
...decl,
|
|
22
|
+
type: 'FunctionExpression',
|
|
23
|
+
declare: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function toClassExpression(decl: AnyNode): AnyNode {
|
|
28
|
+
return {
|
|
29
|
+
...decl,
|
|
30
|
+
type: 'ClassExpression',
|
|
31
|
+
declare: undefined,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const getComponentExportName = (exportedName: string): string | null => {
|
|
36
|
+
if (exportedName === 'default') {
|
|
37
|
+
return 'Component';
|
|
38
|
+
}
|
|
39
|
+
return isNamedComponentExport(exportedName) ? exportedName : null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const getImportInsertionIndex = (program: AnyNode): number => {
|
|
43
|
+
let index = 0;
|
|
44
|
+
for (const statement of program.body ?? []) {
|
|
45
|
+
if (
|
|
46
|
+
statement.type !== 'ExpressionStatement' ||
|
|
47
|
+
(statement.directive === undefined &&
|
|
48
|
+
statement.expression?.type !== 'Literal')
|
|
49
|
+
) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
index += 1;
|
|
53
|
+
}
|
|
54
|
+
return index;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const declarationIncludesName = (
|
|
58
|
+
declaration: AnyNode,
|
|
59
|
+
name: string
|
|
60
|
+
): boolean => {
|
|
61
|
+
if (declaration.type === 'VariableDeclaration') {
|
|
62
|
+
return (declaration.declarations ?? []).some((declarator: AnyNode) =>
|
|
63
|
+
patternIncludesName(declarator.id, name)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
(declaration.type === 'FunctionDeclaration' ||
|
|
68
|
+
declaration.type === 'ClassDeclaration' ||
|
|
69
|
+
declaration.type === 'TSEnumDeclaration') &&
|
|
70
|
+
declaration.id?.name
|
|
71
|
+
) {
|
|
72
|
+
return declaration.id.name === name;
|
|
73
|
+
}
|
|
74
|
+
if (declaration.type === 'ImportDeclaration') {
|
|
75
|
+
return (declaration.specifiers ?? []).some(
|
|
76
|
+
(specifier: AnyNode) => specifier.local?.name === name
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const hasTopLevelBindingName = (program: AnyNode, name: string): boolean => {
|
|
83
|
+
for (const statement of program.body ?? []) {
|
|
84
|
+
if (statement.type === 'ImportDeclaration') {
|
|
85
|
+
if (declarationIncludesName(statement, name)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (statement.type === 'ExportDefaultDeclaration') {
|
|
92
|
+
if (statement.declaration?.id?.name === name) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const declaration =
|
|
99
|
+
statement.type === 'ExportNamedDeclaration'
|
|
100
|
+
? statement.declaration
|
|
101
|
+
: statement;
|
|
102
|
+
if (declaration && declarationIncludesName(declaration, name)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const transformRoute = (ast: ParseResult | AnyNode): void => {
|
|
110
|
+
const program = getProgram(ast);
|
|
111
|
+
const usedNames = new Set<string>();
|
|
112
|
+
const hocs: Array<[string, string]> = [];
|
|
113
|
+
const componentWrapperDeclarations: AnyNode[] = [];
|
|
114
|
+
|
|
115
|
+
function getUid(name: string) {
|
|
116
|
+
let uid = `_${name}`;
|
|
117
|
+
let index = 2;
|
|
118
|
+
while (usedNames.has(uid) || hasTopLevelBindingName(program, uid)) {
|
|
119
|
+
uid = `_${name}${index++}`;
|
|
120
|
+
}
|
|
121
|
+
usedNames.add(uid);
|
|
122
|
+
return uid;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getHocUid(hocName: string) {
|
|
126
|
+
const uid = getUid(hocName);
|
|
127
|
+
hocs.push([hocName, uid]);
|
|
128
|
+
return identifier(uid);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function wrapNamedComponentDeclaration(name: string, declaration: AnyNode) {
|
|
132
|
+
const uid = getHocUid(`with${name}Props`);
|
|
133
|
+
const expression =
|
|
134
|
+
declaration.type === 'FunctionDeclaration'
|
|
135
|
+
? toFunctionExpression(declaration)
|
|
136
|
+
: declaration.type === 'ClassDeclaration'
|
|
137
|
+
? toClassExpression(declaration)
|
|
138
|
+
: declaration;
|
|
139
|
+
return variableDeclaration(name, callExpression(uid, [expression]));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const statement of [...(program.body ?? [])]) {
|
|
143
|
+
if (statement.type === 'ExportDefaultDeclaration') {
|
|
144
|
+
const declaration = statement.declaration;
|
|
145
|
+
if (!declaration) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (
|
|
149
|
+
declaration.declare === true ||
|
|
150
|
+
declaration.type === 'TSInterfaceDeclaration'
|
|
151
|
+
) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const uid = getHocUid('withComponentProps');
|
|
155
|
+
if (
|
|
156
|
+
(declaration.type === 'FunctionDeclaration' ||
|
|
157
|
+
declaration.type === 'ClassDeclaration') &&
|
|
158
|
+
declaration.id?.name
|
|
159
|
+
) {
|
|
160
|
+
const statementIndex = program.body.indexOf(statement);
|
|
161
|
+
program.body.splice(statementIndex, 0, declaration);
|
|
162
|
+
statement.declaration = callExpression(uid, [
|
|
163
|
+
identifier(declaration.id.name),
|
|
164
|
+
]);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const expression =
|
|
168
|
+
declaration.type === 'FunctionDeclaration'
|
|
169
|
+
? toFunctionExpression(declaration)
|
|
170
|
+
: declaration.type === 'ClassDeclaration'
|
|
171
|
+
? toClassExpression(declaration)
|
|
172
|
+
: declaration;
|
|
173
|
+
statement.declaration = callExpression(uid, [expression]);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (statement.type !== 'ExportNamedDeclaration') {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (statement.exportKind === 'type') {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const declaration = statement.declaration;
|
|
184
|
+
if (declaration?.type === 'VariableDeclaration') {
|
|
185
|
+
for (const declarator of declaration.declarations ?? []) {
|
|
186
|
+
if (
|
|
187
|
+
declarator.id?.type !== 'Identifier' ||
|
|
188
|
+
!declarator.init ||
|
|
189
|
+
!isNamedComponentExport(declarator.id.name)
|
|
190
|
+
) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const uid = getHocUid(`with${declarator.id.name}Props`);
|
|
194
|
+
declarator.init = callExpression(uid, [declarator.init]);
|
|
195
|
+
}
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
(declaration?.type === 'FunctionDeclaration' ||
|
|
201
|
+
declaration?.type === 'ClassDeclaration') &&
|
|
202
|
+
declaration.id?.name &&
|
|
203
|
+
isNamedComponentExport(declaration.id.name)
|
|
204
|
+
) {
|
|
205
|
+
const name = declaration.id.name;
|
|
206
|
+
statement.declaration = wrapNamedComponentDeclaration(name, declaration);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (statement.source) {
|
|
211
|
+
const importSpecifiers: Array<{ local: string; imported: string }> = [];
|
|
212
|
+
const sourceWrapperDeclarations: AnyNode[] = [];
|
|
213
|
+
const wrappedExportSpecifiers: AnyNode[] = [];
|
|
214
|
+
statement.specifiers = (statement.specifiers ?? []).filter(
|
|
215
|
+
(specifier: AnyNode) => {
|
|
216
|
+
if (
|
|
217
|
+
specifier.type !== 'ExportSpecifier' ||
|
|
218
|
+
specifier.exportKind === 'type'
|
|
219
|
+
) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
const exportedName = getExportedName(specifier);
|
|
223
|
+
const importedName = getExportedName(specifier.local);
|
|
224
|
+
const componentExportName = exportedName
|
|
225
|
+
? getComponentExportName(exportedName)
|
|
226
|
+
: null;
|
|
227
|
+
if (!exportedName || !importedName || !componentExportName) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
const sourceLocalName = getUid(`${exportedName}Source`);
|
|
231
|
+
const wrappedLocalName = getUid(exportedName);
|
|
232
|
+
const uid = getHocUid(`with${componentExportName}Props`);
|
|
233
|
+
importSpecifiers.push({
|
|
234
|
+
imported: importedName,
|
|
235
|
+
local: sourceLocalName,
|
|
236
|
+
});
|
|
237
|
+
sourceWrapperDeclarations.push(
|
|
238
|
+
variableDeclaration(
|
|
239
|
+
wrappedLocalName,
|
|
240
|
+
callExpression(uid, [identifier(sourceLocalName)])
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
wrappedExportSpecifiers.push(
|
|
244
|
+
exportSpecifier(wrappedLocalName, exportedName)
|
|
245
|
+
);
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
if (importSpecifiers.length > 0) {
|
|
250
|
+
const statementIndex = program.body.indexOf(statement);
|
|
251
|
+
const replacementStatements = [
|
|
252
|
+
importDeclaration(importSpecifiers, String(statement.source.value)),
|
|
253
|
+
];
|
|
254
|
+
if (statement.specifiers.length > 0) {
|
|
255
|
+
replacementStatements.push(statement);
|
|
256
|
+
}
|
|
257
|
+
replacementStatements.push(...sourceWrapperDeclarations);
|
|
258
|
+
replacementStatements.push(
|
|
259
|
+
exportNamedDeclaration(wrappedExportSpecifiers)
|
|
260
|
+
);
|
|
261
|
+
program.body.splice(statementIndex, 1, ...replacementStatements);
|
|
262
|
+
}
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
267
|
+
if (
|
|
268
|
+
specifier.type !== 'ExportSpecifier' ||
|
|
269
|
+
specifier.exportKind === 'type'
|
|
270
|
+
) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const exportedName = getExportedName(specifier);
|
|
274
|
+
const componentExportName = exportedName
|
|
275
|
+
? getComponentExportName(exportedName)
|
|
276
|
+
: null;
|
|
277
|
+
if (!exportedName || !componentExportName) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const localName = specifier.local?.name;
|
|
281
|
+
if (!localName) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const wrappedLocalName = getUid(exportedName);
|
|
285
|
+
const uid = getHocUid(`with${componentExportName}Props`);
|
|
286
|
+
componentWrapperDeclarations.push(
|
|
287
|
+
variableDeclaration(
|
|
288
|
+
wrappedLocalName,
|
|
289
|
+
callExpression(uid, [identifier(localName)])
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
specifier.local = identifier(wrappedLocalName);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
program.body.push(...componentWrapperDeclarations);
|
|
297
|
+
|
|
298
|
+
if (hocs.length > 0) {
|
|
299
|
+
program.body.splice(
|
|
300
|
+
getImportInsertionIndex(program),
|
|
301
|
+
0,
|
|
302
|
+
importDeclaration(
|
|
303
|
+
hocs.map(([name, local]) => ({ imported: name, local })),
|
|
304
|
+
'virtual/react-router/with-props'
|
|
305
|
+
)
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
function isNamedComponentExport(
|
|
311
|
+
name: string
|
|
312
|
+
): name is (typeof NAMED_COMPONENT_EXPORTS)[number] {
|
|
313
|
+
return NAMED_COMPONENT_EXPORTS_SET.has(name);
|
|
314
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { RouteConfigEntry } from '@react-router/dev/routes';
|
|
2
|
+
|
|
3
|
+
type ValidationResult =
|
|
4
|
+
| { valid: true; routeConfig: RouteConfigEntry[] }
|
|
5
|
+
| { valid: false; message: string };
|
|
6
|
+
|
|
7
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
|
|
8
|
+
typeof value === 'object' && value !== null;
|
|
9
|
+
|
|
10
|
+
const isThenable = (value: unknown): value is Promise<unknown> =>
|
|
11
|
+
isPlainObject(value) && 'then' in value && 'catch' in value;
|
|
12
|
+
|
|
13
|
+
const validateEntry = (
|
|
14
|
+
entry: unknown,
|
|
15
|
+
path: string,
|
|
16
|
+
issues: string[]
|
|
17
|
+
): entry is RouteConfigEntry => {
|
|
18
|
+
if (isThenable(entry)) {
|
|
19
|
+
issues.push(
|
|
20
|
+
`${path}\nInvalid type: Expected object but received a promise. Did you forget to await?`
|
|
21
|
+
);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (!isPlainObject(entry)) {
|
|
25
|
+
issues.push(`${path}\nInvalid type: Expected object.`);
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (typeof entry.file !== 'string') {
|
|
29
|
+
issues.push(`${path}.file\nInvalid type: Expected string.`);
|
|
30
|
+
}
|
|
31
|
+
if ('id' in entry && entry.id === 'root') {
|
|
32
|
+
issues.push(`${path}.id\nA route cannot use the reserved id 'root'.`);
|
|
33
|
+
}
|
|
34
|
+
if (
|
|
35
|
+
'path' in entry &&
|
|
36
|
+
entry.path !== undefined &&
|
|
37
|
+
typeof entry.path !== 'string'
|
|
38
|
+
) {
|
|
39
|
+
issues.push(`${path}.path\nInvalid type: Expected string.`);
|
|
40
|
+
}
|
|
41
|
+
if (
|
|
42
|
+
'index' in entry &&
|
|
43
|
+
entry.index !== undefined &&
|
|
44
|
+
typeof entry.index !== 'boolean'
|
|
45
|
+
) {
|
|
46
|
+
issues.push(`${path}.index\nInvalid type: Expected boolean.`);
|
|
47
|
+
}
|
|
48
|
+
if (
|
|
49
|
+
'caseSensitive' in entry &&
|
|
50
|
+
entry.caseSensitive !== undefined &&
|
|
51
|
+
typeof entry.caseSensitive !== 'boolean'
|
|
52
|
+
) {
|
|
53
|
+
issues.push(`${path}.caseSensitive\nInvalid type: Expected boolean.`);
|
|
54
|
+
}
|
|
55
|
+
if ('children' in entry && entry.children !== undefined) {
|
|
56
|
+
if (!Array.isArray(entry.children)) {
|
|
57
|
+
issues.push(`${path}.children\nInvalid type: Expected array.`);
|
|
58
|
+
} else {
|
|
59
|
+
entry.children.forEach((child, index) =>
|
|
60
|
+
validateEntry(child, `${path}.children.${index}`, issues)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return issues.length === 0;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const validateRouteConfig = ({
|
|
68
|
+
routeConfigFile,
|
|
69
|
+
routeConfig,
|
|
70
|
+
}: {
|
|
71
|
+
routeConfigFile: string;
|
|
72
|
+
routeConfig: unknown;
|
|
73
|
+
}): ValidationResult => {
|
|
74
|
+
if (!routeConfig) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
message: `Route config must be the default export in "${routeConfigFile}".`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(routeConfig)) {
|
|
81
|
+
return {
|
|
82
|
+
valid: false,
|
|
83
|
+
message: `Route config in "${routeConfigFile}" must be an array.`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const issues: string[] = [];
|
|
88
|
+
routeConfig.forEach((entry, index) =>
|
|
89
|
+
validateEntry(entry, `routes.${index}`, issues)
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (issues.length > 0) {
|
|
93
|
+
return {
|
|
94
|
+
valid: false,
|
|
95
|
+
message: [
|
|
96
|
+
`Route config in "${routeConfigFile}" is invalid.`,
|
|
97
|
+
issues.join('\n\n'),
|
|
98
|
+
].join('\n\n'),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
valid: true,
|
|
104
|
+
routeConfig: routeConfig as RouteConfigEntry[],
|
|
105
|
+
};
|
|
106
|
+
};
|