@mercurjs/dashboard-sdk 2.3.8-canary.2 → 2.3.8-canary.3
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/index.cjs +29 -0
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +24 -0
- package/dist/{types-BTgTMD_t.d.cts → types-DG9Yya-_.d.cts} +104 -5
- package/dist/{types-BTgTMD_t.d.ts → types-DG9Yya-_.d.ts} +104 -5
- package/dist/vite.cjs +613 -634
- package/dist/vite.d.cts +4 -4
- package/dist/vite.d.ts +4 -4
- package/dist/vite.js +615 -635
- package/package.json +1 -1
package/dist/vite.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
} from "./chunk-3RG5ZIWI.js";
|
|
4
4
|
|
|
5
5
|
// src/plugin.ts
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import path5 from "path";
|
|
7
|
+
import fs6 from "fs";
|
|
8
8
|
import { createRequire } from "module";
|
|
9
9
|
|
|
10
10
|
// src/utils.ts
|
|
@@ -26,7 +26,8 @@ import {
|
|
|
26
26
|
isStringLiteral,
|
|
27
27
|
isVariableDeclaration,
|
|
28
28
|
isVariableDeclarator,
|
|
29
|
-
isArrayExpression
|
|
29
|
+
isArrayExpression,
|
|
30
|
+
isUnaryExpression
|
|
30
31
|
} from "@babel/types";
|
|
31
32
|
var traverse;
|
|
32
33
|
if (typeof _traverse === "function") {
|
|
@@ -44,6 +45,8 @@ var I18N_VIRTUAL_MODULE = "virtual:mercur/i18n";
|
|
|
44
45
|
var WIDGETS_VIRTUAL_MODULE = "virtual:mercur/widgets";
|
|
45
46
|
var NAVIGATION_VIRTUAL_MODULE = "virtual:mercur/navigation";
|
|
46
47
|
var CUSTOM_FIELDS_VIRTUAL_MODULE = "virtual:mercur/custom-fields";
|
|
48
|
+
var LAYOUTS_VIRTUAL_MODULE = "virtual:mercur/layouts";
|
|
49
|
+
var PREFERENCES_VIRTUAL_MODULE = "virtual:mercur/preferences";
|
|
47
50
|
var RESOLVED_CONFIG_MODULE = "\0" + CONFIG_VIRTUAL_MODULE;
|
|
48
51
|
var RESOLVED_ROUTES_MODULE = "\0" + ROUTES_VIRTUAL_MODULE;
|
|
49
52
|
var RESOLVED_MENU_ITEMS_MODULE = "\0" + MENU_ITEMS_VIRTUAL_MODULE;
|
|
@@ -51,6 +54,8 @@ var RESOLVED_I18N_MODULE = "\0" + I18N_VIRTUAL_MODULE;
|
|
|
51
54
|
var RESOLVED_WIDGETS_MODULE = "\0" + WIDGETS_VIRTUAL_MODULE;
|
|
52
55
|
var RESOLVED_NAVIGATION_MODULE = "\0" + NAVIGATION_VIRTUAL_MODULE;
|
|
53
56
|
var RESOLVED_CUSTOM_FIELDS_MODULE = "\0" + CUSTOM_FIELDS_VIRTUAL_MODULE;
|
|
57
|
+
var RESOLVED_LAYOUTS_MODULE = "\0" + LAYOUTS_VIRTUAL_MODULE;
|
|
58
|
+
var RESOLVED_PREFERENCES_MODULE = "\0" + PREFERENCES_VIRTUAL_MODULE;
|
|
54
59
|
var VIRTUAL_MODULES = [
|
|
55
60
|
CONFIG_VIRTUAL_MODULE,
|
|
56
61
|
ROUTES_VIRTUAL_MODULE,
|
|
@@ -58,8 +63,12 @@ var VIRTUAL_MODULES = [
|
|
|
58
63
|
I18N_VIRTUAL_MODULE,
|
|
59
64
|
WIDGETS_VIRTUAL_MODULE,
|
|
60
65
|
NAVIGATION_VIRTUAL_MODULE,
|
|
61
|
-
CUSTOM_FIELDS_VIRTUAL_MODULE
|
|
66
|
+
CUSTOM_FIELDS_VIRTUAL_MODULE,
|
|
67
|
+
LAYOUTS_VIRTUAL_MODULE,
|
|
68
|
+
PREFERENCES_VIRTUAL_MODULE
|
|
62
69
|
];
|
|
70
|
+
var LAYOUT_PREFERENCES_FILE = "_layouts";
|
|
71
|
+
var NAVIGATION_FILE = "_navigation";
|
|
63
72
|
|
|
64
73
|
// src/utils.ts
|
|
65
74
|
function normalizePath(filePath) {
|
|
@@ -98,9 +107,9 @@ function resolveExports(moduleExports) {
|
|
|
98
107
|
}
|
|
99
108
|
return moduleExports;
|
|
100
109
|
}
|
|
101
|
-
async function getFileExports(
|
|
110
|
+
async function getFileExports(path6) {
|
|
102
111
|
const { unregister } = await safeRegister();
|
|
103
|
-
const module = __require(
|
|
112
|
+
const module = __require(path6);
|
|
104
113
|
unregister();
|
|
105
114
|
return resolveExports(module);
|
|
106
115
|
}
|
|
@@ -126,13 +135,13 @@ function hasDefaultExport(ast) {
|
|
|
126
135
|
ExportDefaultDeclaration() {
|
|
127
136
|
found = true;
|
|
128
137
|
},
|
|
129
|
-
AssignmentExpression(
|
|
130
|
-
if (
|
|
138
|
+
AssignmentExpression(path6) {
|
|
139
|
+
if (path6.node.left.type === "MemberExpression" && path6.node.left.object.type === "Identifier" && path6.node.left.object.name === "exports" && path6.node.left.property.type === "Identifier" && path6.node.left.property.name === "default") {
|
|
131
140
|
found = true;
|
|
132
141
|
}
|
|
133
142
|
},
|
|
134
|
-
ExportNamedDeclaration(
|
|
135
|
-
const specifiers =
|
|
143
|
+
ExportNamedDeclaration(path6) {
|
|
144
|
+
const specifiers = path6.node.specifiers;
|
|
136
145
|
if (specifiers?.some(
|
|
137
146
|
(s) => s.type === "ExportSpecifier" && s.exported.type === "Identifier" && s.exported.name === "default"
|
|
138
147
|
)) {
|
|
@@ -144,252 +153,16 @@ function hasDefaultExport(ast) {
|
|
|
144
153
|
}
|
|
145
154
|
|
|
146
155
|
// src/routes.ts
|
|
147
|
-
import
|
|
148
|
-
import
|
|
149
|
-
function getRoute(file, routesDir) {
|
|
150
|
-
const importPath = normalizePath(file);
|
|
151
|
-
const normalizedRoutesDir = normalizePath(routesDir);
|
|
152
|
-
return importPath.replace(normalizedRoutesDir, "").replace(/\[\[\*\]\]/g, "*?").replace(/\[\*\]/g, "*").replace(/\(([^[\])]+)\)/g, "$1?").replace(/\[\[([^\]]+)\]\]/g, ":$1?").replace(/\[([^\]]+)\]/g, ":$1").replace(
|
|
153
|
-
new RegExp(
|
|
154
|
-
`/page\\.(${VALID_FILE_EXTENSIONS.map((ext) => ext.slice(1)).join("|")})$`
|
|
155
|
-
),
|
|
156
|
-
""
|
|
157
|
-
) || "/";
|
|
158
|
-
}
|
|
159
|
-
function crawlRoutes(dir, pattern = "page") {
|
|
160
|
-
const files = [];
|
|
161
|
-
if (!fs2.existsSync(dir)) {
|
|
162
|
-
return files;
|
|
163
|
-
}
|
|
164
|
-
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
165
|
-
for (const entry of entries) {
|
|
166
|
-
const fullPath = path2.join(dir, entry.name);
|
|
167
|
-
if (entry.isDirectory()) {
|
|
168
|
-
files.push(...crawlRoutes(fullPath, pattern));
|
|
169
|
-
} else if (entry.isFile()) {
|
|
170
|
-
const ext = path2.extname(entry.name);
|
|
171
|
-
const baseName = path2.basename(entry.name, ext);
|
|
172
|
-
if (baseName === pattern && VALID_FILE_EXTENSIONS.includes(ext)) {
|
|
173
|
-
files.push(fullPath);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return files;
|
|
178
|
-
}
|
|
179
|
-
function hasConfigPublic(ast) {
|
|
180
|
-
let found = false;
|
|
181
|
-
traverse(ast, {
|
|
182
|
-
ExportNamedDeclaration(path10) {
|
|
183
|
-
const declaration = path10.node.declaration;
|
|
184
|
-
if (!isVariableDeclaration(declaration)) return;
|
|
185
|
-
for (const decl of declaration.declarations) {
|
|
186
|
-
if (isVariableDeclarator(decl) && isIdentifier(decl.id, { name: "config" }) && decl.init?.type === "ObjectExpression") {
|
|
187
|
-
const publicProp = decl.init.properties.find(
|
|
188
|
-
(prop) => isObjectProperty(prop) && isIdentifier(prop.key, { name: "public" }) && isBooleanLiteral(prop.value, { value: true })
|
|
189
|
-
);
|
|
190
|
-
if (publicProp) {
|
|
191
|
-
found = true;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
return found;
|
|
198
|
-
}
|
|
199
|
-
function getNamedExports(ast) {
|
|
200
|
-
let hasHandle = false;
|
|
201
|
-
let hasLoader = false;
|
|
202
|
-
traverse(ast, {
|
|
203
|
-
ExportNamedDeclaration(path10) {
|
|
204
|
-
const declaration = path10.node.declaration;
|
|
205
|
-
if (declaration?.type === "VariableDeclaration") {
|
|
206
|
-
declaration.declarations.forEach((decl) => {
|
|
207
|
-
if (decl.id.type === "Identifier" && decl.id.name === "handle") {
|
|
208
|
-
hasHandle = true;
|
|
209
|
-
}
|
|
210
|
-
if (decl.id.type === "Identifier" && decl.id.name === "loader") {
|
|
211
|
-
hasLoader = true;
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "loader") {
|
|
216
|
-
hasLoader = true;
|
|
217
|
-
}
|
|
218
|
-
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "handle") {
|
|
219
|
-
hasHandle = true;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
return { hasHandle, hasLoader };
|
|
224
|
-
}
|
|
225
|
-
function generateRouteComponentName(index) {
|
|
226
|
-
return `RouteComponent${index}`;
|
|
227
|
-
}
|
|
228
|
-
function generateHandleName(index) {
|
|
229
|
-
return `RouteHandle${index}`;
|
|
230
|
-
}
|
|
231
|
-
function generateLoaderName(index) {
|
|
232
|
-
return `RouteLoader${index}`;
|
|
233
|
-
}
|
|
234
|
-
function generateImports(file, index, hasHandle, hasLoader) {
|
|
235
|
-
const imports = [];
|
|
236
|
-
const componentName = generateRouteComponentName(index);
|
|
237
|
-
const importPath = normalizePath(file);
|
|
238
|
-
if (!hasHandle && !hasLoader) {
|
|
239
|
-
imports.push(`import ${componentName} from "${importPath}"`);
|
|
240
|
-
} else {
|
|
241
|
-
const namedImports = [
|
|
242
|
-
hasHandle && `handle as ${generateHandleName(index)}`,
|
|
243
|
-
hasLoader && `loader as ${generateLoaderName(index)}`
|
|
244
|
-
].filter(Boolean).join(", ");
|
|
245
|
-
imports.push(`import ${componentName}, { ${namedImports} } from "${importPath}"`);
|
|
246
|
-
}
|
|
247
|
-
return imports;
|
|
248
|
-
}
|
|
249
|
-
function generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic) {
|
|
250
|
-
return {
|
|
251
|
-
Component: generateRouteComponentName(index),
|
|
252
|
-
path: routePath,
|
|
253
|
-
handle: hasHandle ? generateHandleName(index) : void 0,
|
|
254
|
-
loader: hasLoader ? generateLoaderName(index) : void 0,
|
|
255
|
-
isPublic
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
function formatRoute(route, indent = " ") {
|
|
259
|
-
let result = `${indent}{
|
|
260
|
-
`;
|
|
261
|
-
result += `${indent} Component: ${route.Component},
|
|
262
|
-
`;
|
|
263
|
-
result += `${indent} path: "${route.path}"`;
|
|
264
|
-
if (route.handle) {
|
|
265
|
-
result += `,
|
|
266
|
-
${indent} handle: ${route.handle}`;
|
|
267
|
-
}
|
|
268
|
-
if (route.loader) {
|
|
269
|
-
result += `,
|
|
270
|
-
${indent} loader: ${route.loader}`;
|
|
271
|
-
}
|
|
272
|
-
if (route.isPublic) {
|
|
273
|
-
result += `,
|
|
274
|
-
${indent} isPublic: true`;
|
|
275
|
-
}
|
|
276
|
-
if (route.children?.length) {
|
|
277
|
-
result += `,
|
|
278
|
-
${indent} children: [
|
|
279
|
-
`;
|
|
280
|
-
result += route.children.map((child) => formatRoute(child, indent + " ")).join(",\n");
|
|
281
|
-
result += `
|
|
282
|
-
${indent} ]`;
|
|
283
|
-
}
|
|
284
|
-
result += `
|
|
285
|
-
${indent}}`;
|
|
286
|
-
return result;
|
|
287
|
-
}
|
|
288
|
-
function parseFile(file, routesDir, index) {
|
|
289
|
-
try {
|
|
290
|
-
const code = fs2.readFileSync(file, "utf-8");
|
|
291
|
-
const ast = parse(code, getParserOptions(file));
|
|
292
|
-
if (!hasDefaultExport(ast)) {
|
|
293
|
-
return null;
|
|
294
|
-
}
|
|
295
|
-
const { hasHandle, hasLoader } = getNamedExports(ast);
|
|
296
|
-
const isPublic = hasConfigPublic(ast);
|
|
297
|
-
const routePath = getRoute(file, routesDir);
|
|
298
|
-
const imports = generateImports(file, index, hasHandle, hasLoader);
|
|
299
|
-
const route = generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic);
|
|
300
|
-
return {
|
|
301
|
-
imports,
|
|
302
|
-
route
|
|
303
|
-
};
|
|
304
|
-
} catch {
|
|
305
|
-
return null;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
function buildRouteTree(results) {
|
|
309
|
-
const routeMap = /* @__PURE__ */ new Map();
|
|
310
|
-
const sortedResults = [...results].sort(
|
|
311
|
-
(a, b) => a.route.path.split("/").length - b.route.path.split("/").length
|
|
312
|
-
);
|
|
313
|
-
for (const result of sortedResults) {
|
|
314
|
-
const routePath = result.route.path;
|
|
315
|
-
const isParallel = routePath.includes("/@");
|
|
316
|
-
if (isParallel) {
|
|
317
|
-
const parentPath = routePath.split("/@")[0];
|
|
318
|
-
const parent = routeMap.get(parentPath);
|
|
319
|
-
if (parent) {
|
|
320
|
-
parent.route.children = parent.route.children ?? [];
|
|
321
|
-
parent.route.children.push({
|
|
322
|
-
...result.route,
|
|
323
|
-
path: result.route.path.replace("/@", "/")
|
|
324
|
-
});
|
|
325
|
-
parent.imports.push(...result.imports);
|
|
326
|
-
} else {
|
|
327
|
-
routeMap.set(routePath, result);
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
routeMap.set(routePath, result);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return Array.from(routeMap.values());
|
|
334
|
-
}
|
|
335
|
-
function generateRoutes({ srcDir, pluginExtensions }) {
|
|
336
|
-
const routesDir = path2.join(srcDir, "routes");
|
|
337
|
-
let index = 0;
|
|
338
|
-
const results = [];
|
|
339
|
-
for (const file of crawlRoutes(routesDir)) {
|
|
340
|
-
const result = parseFile(file, routesDir, index);
|
|
341
|
-
if (result) {
|
|
342
|
-
results.push(result);
|
|
343
|
-
index++;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
const pluginDeclarations = pluginExtensions.map(
|
|
347
|
-
(ext, i) => `import __plugin${i} from "${normalizePath(ext)}"`
|
|
348
|
-
);
|
|
349
|
-
const pluginSpreads = pluginExtensions.map(
|
|
350
|
-
(_, i) => ` ...(__plugin${i}.routeModule?.routes ?? [])`
|
|
351
|
-
);
|
|
352
|
-
const routeTree = buildRouteTree(results);
|
|
353
|
-
const appImports = routeTree.flatMap((r) => r.imports);
|
|
354
|
-
const appRoutes = routeTree.map((r) => formatRoute(r.route));
|
|
355
|
-
const allImports = [...appImports];
|
|
356
|
-
const allRoutes = [...appRoutes, ...pluginSpreads];
|
|
357
|
-
if (allImports.length === 0 && pluginDeclarations.length === 0 && allRoutes.length === 0) {
|
|
358
|
-
return `export const customRoutes = []`;
|
|
359
|
-
}
|
|
360
|
-
return `${allImports.join("\n")}
|
|
361
|
-
|
|
362
|
-
${pluginDeclarations.join("\n")}
|
|
156
|
+
import fs5 from "fs";
|
|
157
|
+
import path4 from "path";
|
|
363
158
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
159
|
+
// src/layers.ts
|
|
160
|
+
import fs4 from "fs";
|
|
161
|
+
import path3 from "path";
|
|
368
162
|
|
|
369
163
|
// src/menu-items.ts
|
|
370
|
-
import
|
|
371
|
-
|
|
372
|
-
function crawlRoutes2(dir, pattern = "page") {
|
|
373
|
-
const files = [];
|
|
374
|
-
if (!fs3.existsSync(dir)) {
|
|
375
|
-
return files;
|
|
376
|
-
}
|
|
377
|
-
const entries = fs3.readdirSync(dir, { withFileTypes: true });
|
|
378
|
-
for (const entry of entries) {
|
|
379
|
-
const fullPath = path3.join(dir, entry.name);
|
|
380
|
-
if (entry.isDirectory()) {
|
|
381
|
-
files.push(...crawlRoutes2(fullPath, pattern));
|
|
382
|
-
} else if (entry.isFile()) {
|
|
383
|
-
const ext = path3.extname(entry.name);
|
|
384
|
-
const baseName = path3.basename(entry.name, ext);
|
|
385
|
-
if (baseName === pattern && VALID_FILE_EXTENSIONS.includes(ext)) {
|
|
386
|
-
files.push(fullPath);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return files;
|
|
391
|
-
}
|
|
392
|
-
function getRoute2(file, routesDir) {
|
|
164
|
+
import fs2 from "fs";
|
|
165
|
+
function getRoute(file, routesDir) {
|
|
393
166
|
const importPath = normalizePath(file);
|
|
394
167
|
const normalizedRoutesDir = normalizePath(routesDir);
|
|
395
168
|
return importPath.replace(normalizedRoutesDir, "").replace(/\[\[\*\]\]/g, "*?").replace(/\[\*\]/g, "*").replace(/\(([^[\])]+)\)/g, "$1?").replace(/\[\[([^\]]+)\]\]/g, ":$1?").replace(/\[([^\]]+)\]/g, ":$1").replace(
|
|
@@ -399,9 +172,9 @@ function getRoute2(file, routesDir) {
|
|
|
399
172
|
""
|
|
400
173
|
) || "/";
|
|
401
174
|
}
|
|
402
|
-
function getConfigObjectProperties(
|
|
403
|
-
if (isVariableDeclarator(
|
|
404
|
-
const decl = isIdentifier(
|
|
175
|
+
function getConfigObjectProperties(path6) {
|
|
176
|
+
if (isVariableDeclarator(path6.node)) {
|
|
177
|
+
const decl = isIdentifier(path6.node.id, { name: "config" }) ? path6.node : null;
|
|
405
178
|
if (!decl) return null;
|
|
406
179
|
if (isCallExpression(decl.init) && decl.init.arguments.length > 0 && isObjectExpression(decl.init.arguments[0])) {
|
|
407
180
|
return decl.init.arguments[0].properties;
|
|
@@ -411,7 +184,7 @@ function getConfigObjectProperties(path10) {
|
|
|
411
184
|
}
|
|
412
185
|
return null;
|
|
413
186
|
}
|
|
414
|
-
const declaration =
|
|
187
|
+
const declaration = path6.node.declaration;
|
|
415
188
|
if (isVariableDeclaration(declaration)) {
|
|
416
189
|
const configDecl = declaration.declarations.find(
|
|
417
190
|
(d) => isVariableDeclarator(d) && isIdentifier(d.id, { name: "config" })
|
|
@@ -487,21 +260,21 @@ function processConfigProperties(properties) {
|
|
|
487
260
|
}
|
|
488
261
|
function getRouteConfig(file) {
|
|
489
262
|
try {
|
|
490
|
-
const code =
|
|
263
|
+
const code = fs2.readFileSync(file, "utf-8");
|
|
491
264
|
const ast = parse(code, getParserOptions(file));
|
|
492
265
|
let config = null;
|
|
493
266
|
let configFound = false;
|
|
494
267
|
traverse(ast, {
|
|
495
|
-
VariableDeclarator(
|
|
268
|
+
VariableDeclarator(path6) {
|
|
496
269
|
if (configFound) return;
|
|
497
|
-
const properties = getConfigObjectProperties(
|
|
270
|
+
const properties = getConfigObjectProperties(path6);
|
|
498
271
|
if (!properties) return;
|
|
499
272
|
config = processConfigProperties(properties);
|
|
500
273
|
if (config) configFound = true;
|
|
501
274
|
},
|
|
502
|
-
ExportNamedDeclaration(
|
|
275
|
+
ExportNamedDeclaration(path6) {
|
|
503
276
|
if (configFound) return;
|
|
504
|
-
const properties = getConfigObjectProperties(
|
|
277
|
+
const properties = getConfigObjectProperties(path6);
|
|
505
278
|
if (!properties) return;
|
|
506
279
|
config = processConfigProperties(properties);
|
|
507
280
|
if (config) configFound = true;
|
|
@@ -524,7 +297,7 @@ function generateMenuItem(config, file, routesDir, index) {
|
|
|
524
297
|
return {
|
|
525
298
|
label: `${configName}.label`,
|
|
526
299
|
icon: config.icon ? `${configName}.icon` : void 0,
|
|
527
|
-
path:
|
|
300
|
+
path: getRoute(file, routesDir),
|
|
528
301
|
rank: config.rank,
|
|
529
302
|
nested: config.nested,
|
|
530
303
|
group: config.group,
|
|
@@ -554,75 +327,485 @@ function parseMenuItemFile(file, routesDir, index) {
|
|
|
554
327
|
if (!config) {
|
|
555
328
|
return null;
|
|
556
329
|
}
|
|
557
|
-
return {
|
|
558
|
-
import: generateImport(file, index),
|
|
559
|
-
menuItem: generateMenuItem(config, file, routesDir, index)
|
|
560
|
-
};
|
|
330
|
+
return {
|
|
331
|
+
import: generateImport(file, index),
|
|
332
|
+
menuItem: generateMenuItem(config, file, routesDir, index)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function generateMenuItems(config) {
|
|
336
|
+
const { header, names } = emitLayers(config);
|
|
337
|
+
return `${header}
|
|
338
|
+
|
|
339
|
+
const byPath = new Map()
|
|
340
|
+
for (const item of [
|
|
341
|
+
${spreadLayers(names, "menuItemModule", "menuItems")}
|
|
342
|
+
]) {
|
|
343
|
+
byPath.set(item.path, item)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export default { menuItems: [...byPath.values()] }`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/widgets.ts
|
|
350
|
+
import fs3 from "fs";
|
|
351
|
+
import path2 from "path";
|
|
352
|
+
function readNumber(value) {
|
|
353
|
+
if (isNumericLiteral(value)) return value.value;
|
|
354
|
+
if (isUnaryExpression(value) && value.operator === "-" && isNumericLiteral(value.argument)) {
|
|
355
|
+
return -value.argument.value;
|
|
356
|
+
}
|
|
357
|
+
return void 0;
|
|
358
|
+
}
|
|
359
|
+
function extractStrings(value, zones) {
|
|
360
|
+
if (isStringLiteral(value)) {
|
|
361
|
+
zones.push(value.value);
|
|
362
|
+
} else if (isArrayExpression(value)) {
|
|
363
|
+
for (const el of value.elements) {
|
|
364
|
+
if (isStringLiteral(el)) zones.push(el.value);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function readWidgetConfig(properties) {
|
|
369
|
+
const zones = [];
|
|
370
|
+
const permissions = [];
|
|
371
|
+
let id;
|
|
372
|
+
let label;
|
|
373
|
+
let section;
|
|
374
|
+
let order;
|
|
375
|
+
let replace;
|
|
376
|
+
for (const prop of properties) {
|
|
377
|
+
if (!isObjectProperty(prop)) continue;
|
|
378
|
+
if (isIdentifier(prop.key, { name: "zone" })) {
|
|
379
|
+
extractStrings(prop.value, zones);
|
|
380
|
+
}
|
|
381
|
+
if (isIdentifier(prop.key, { name: "permission" })) {
|
|
382
|
+
extractStrings(prop.value, permissions);
|
|
383
|
+
}
|
|
384
|
+
if (isIdentifier(prop.key, { name: "id" }) && isStringLiteral(prop.value)) {
|
|
385
|
+
id = prop.value.value;
|
|
386
|
+
}
|
|
387
|
+
if (isIdentifier(prop.key, { name: "label" }) && isStringLiteral(prop.value)) {
|
|
388
|
+
label = prop.value.value;
|
|
389
|
+
}
|
|
390
|
+
if (isIdentifier(prop.key, { name: "section" }) && isStringLiteral(prop.value)) {
|
|
391
|
+
section = prop.value.value;
|
|
392
|
+
}
|
|
393
|
+
if (isIdentifier(prop.key, { name: "order" })) {
|
|
394
|
+
order = readNumber(prop.value);
|
|
395
|
+
}
|
|
396
|
+
if (isIdentifier(prop.key, { name: "replace" }) && isStringLiteral(prop.value)) {
|
|
397
|
+
replace = prop.value.value;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (zones.length === 0) return null;
|
|
401
|
+
return { zones, id, label, permissions, section, order, replace };
|
|
402
|
+
}
|
|
403
|
+
function getConfigProperties(node) {
|
|
404
|
+
if (isCallExpression(node) && node.arguments.length > 0 && isObjectExpression(node.arguments[0])) {
|
|
405
|
+
return node.arguments[0].properties;
|
|
406
|
+
}
|
|
407
|
+
if (isObjectExpression(node)) {
|
|
408
|
+
return node.properties;
|
|
409
|
+
}
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
function getWidgetConfig(file) {
|
|
413
|
+
try {
|
|
414
|
+
const code = fs3.readFileSync(file, "utf-8");
|
|
415
|
+
const ast = parse(code, getParserOptions(file));
|
|
416
|
+
if (!hasDefaultExport(ast)) return null;
|
|
417
|
+
let info = null;
|
|
418
|
+
const visit = (declaration) => {
|
|
419
|
+
if (info) return;
|
|
420
|
+
if (!isVariableDeclaration(declaration)) return;
|
|
421
|
+
for (const decl of declaration.declarations) {
|
|
422
|
+
if (isVariableDeclarator(decl) && isIdentifier(decl.id, { name: "config" })) {
|
|
423
|
+
const props = getConfigProperties(decl.init);
|
|
424
|
+
if (props) info = readWidgetConfig(props);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
traverse(ast, {
|
|
429
|
+
ExportNamedDeclaration(p) {
|
|
430
|
+
visit(p.node.declaration);
|
|
431
|
+
},
|
|
432
|
+
VariableDeclaration(p) {
|
|
433
|
+
visit(p.node);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
return info;
|
|
437
|
+
} catch {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function hashPath(relative) {
|
|
442
|
+
let hash = 0;
|
|
443
|
+
for (let i = 0; i < relative.length; i++) {
|
|
444
|
+
hash = (hash << 5) - hash + relative.charCodeAt(i);
|
|
445
|
+
hash |= 0;
|
|
446
|
+
}
|
|
447
|
+
return Math.abs(hash).toString(36).slice(0, 6);
|
|
448
|
+
}
|
|
449
|
+
function widgetId(info, file, widgetsDir) {
|
|
450
|
+
if (info.id) return info.id;
|
|
451
|
+
const relative = normalizePath(path2.relative(widgetsDir, file));
|
|
452
|
+
return `Widget-${hashPath(relative)}`;
|
|
453
|
+
}
|
|
454
|
+
function parseWidgetFile(file, widgetsDir, index) {
|
|
455
|
+
const info = getWidgetConfig(file);
|
|
456
|
+
if (!info) return null;
|
|
457
|
+
const name = `Widget${index}`;
|
|
458
|
+
const importPath = normalizePath(file);
|
|
459
|
+
const zonesLiteral = JSON.stringify(info.zones);
|
|
460
|
+
const id = widgetId(info, file, widgetsDir);
|
|
461
|
+
return {
|
|
462
|
+
import: `import ${name} from "${importPath}"`,
|
|
463
|
+
entry: ` { Component: ${name}, zone: ${zonesLiteral}, widgetId: ${JSON.stringify(
|
|
464
|
+
id
|
|
465
|
+
)}${info.label ? `, label: ${JSON.stringify(info.label)}` : ""}${info.permissions.length ? `, permission: ${JSON.stringify(info.permissions)}` : ""}${info.section ? `, section: ${JSON.stringify(info.section)}` : ""}${info.order !== void 0 ? `, order: ${info.order}` : ""}${info.replace ? `, replace: ${JSON.stringify(info.replace)}` : ""} }`
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function collectWidgets(srcDir, startIndex = 0) {
|
|
469
|
+
const widgetsDir = path2.join(srcDir, "widgets");
|
|
470
|
+
let index = startIndex;
|
|
471
|
+
const results = [];
|
|
472
|
+
for (const file of crawlModuleFiles(widgetsDir)) {
|
|
473
|
+
const result = parseWidgetFile(file, widgetsDir, index);
|
|
474
|
+
if (result) {
|
|
475
|
+
results.push(result);
|
|
476
|
+
index++;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
imports: results.map((r) => r.import),
|
|
481
|
+
entries: results.map((r) => r.entry)
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function generateWidgets(config) {
|
|
485
|
+
const { header, names } = emitLayers(config);
|
|
486
|
+
return `${header}
|
|
487
|
+
|
|
488
|
+
const byId = new Map()
|
|
489
|
+
for (const widget of [
|
|
490
|
+
${spreadLayers(names, "widgetModule", "widgets")}
|
|
491
|
+
]) {
|
|
492
|
+
byId.set(widget.widgetId, widget)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export default { widgets: [...byId.values()] }`;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/layers.ts
|
|
499
|
+
function layerSources({
|
|
500
|
+
pluginExtensions,
|
|
501
|
+
projectDir,
|
|
502
|
+
srcDir
|
|
503
|
+
}) {
|
|
504
|
+
return [
|
|
505
|
+
...pluginExtensions.map((entry) => ({ entry })),
|
|
506
|
+
...projectDir ? [{ srcDir: projectDir }] : [],
|
|
507
|
+
{ srcDir }
|
|
508
|
+
];
|
|
509
|
+
}
|
|
510
|
+
function findFile(dir, stem) {
|
|
511
|
+
for (const ext of VALID_FILE_EXTENSIONS) {
|
|
512
|
+
const file = path3.join(dir, `${stem}${ext}`);
|
|
513
|
+
if (fs4.existsSync(file)) return file;
|
|
514
|
+
}
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
function collectLayer(srcDir, layer, startIndex = 0) {
|
|
518
|
+
const name = `__layer${layer}`;
|
|
519
|
+
const routesDir = path3.join(srcDir, "routes");
|
|
520
|
+
let index = startIndex;
|
|
521
|
+
const routeResults = [];
|
|
522
|
+
const menuItemResults = [];
|
|
523
|
+
for (const file of crawlRoutes(routesDir)) {
|
|
524
|
+
const route = parseFile(file, routesDir, index);
|
|
525
|
+
if (route) routeResults.push(route);
|
|
526
|
+
const menuItem = parseMenuItemFile(file, routesDir, index);
|
|
527
|
+
if (menuItem) menuItemResults.push(menuItem);
|
|
528
|
+
index++;
|
|
529
|
+
}
|
|
530
|
+
const routeTree = buildRouteTree(routeResults);
|
|
531
|
+
const routeImports = routeTree.flatMap((r) => r.imports);
|
|
532
|
+
const routes = routeTree.map((r) => formatRoute(r.route));
|
|
533
|
+
const menuItemImports = menuItemResults.map((r) => r.import);
|
|
534
|
+
const menuItems = menuItemResults.map((r) => formatMenuItem(r.menuItem));
|
|
535
|
+
const widgets = collectWidgets(srcDir, index);
|
|
536
|
+
index += widgets.entries.length;
|
|
537
|
+
const cfFiles = crawlModuleFiles(path3.join(srcDir, "custom-fields"));
|
|
538
|
+
const cfImports = cfFiles.map(
|
|
539
|
+
(file, i) => `import __cf${layer}_${i} from "${normalizePath(file)}"`
|
|
540
|
+
);
|
|
541
|
+
const cfRefs = cfFiles.map((_, i) => ` __cf${layer}_${i}`);
|
|
542
|
+
const layoutFiles = crawlModuleFiles(path3.join(srcDir, "layouts"));
|
|
543
|
+
const layoutImports = layoutFiles.map(
|
|
544
|
+
(file, i) => `import __layout${layer}_${i} from "${normalizePath(file)}"`
|
|
545
|
+
);
|
|
546
|
+
const layoutRefs = layoutFiles.map((_, i) => ` __layout${layer}_${i}`);
|
|
547
|
+
const i18nFile = findFile(path3.join(srcDir, "i18n"), "index");
|
|
548
|
+
const i18nName = `__i18n${layer}`;
|
|
549
|
+
const navigationFile = findFile(srcDir, NAVIGATION_FILE);
|
|
550
|
+
const navigationName = `__navigation${layer}`;
|
|
551
|
+
const preferencesFile = findFile(srcDir, LAYOUT_PREFERENCES_FILE);
|
|
552
|
+
const preferencesName = `__preferences${layer}`;
|
|
553
|
+
const imports = [
|
|
554
|
+
...routeImports,
|
|
555
|
+
...menuItemImports,
|
|
556
|
+
...widgets.imports,
|
|
557
|
+
...cfImports,
|
|
558
|
+
...layoutImports,
|
|
559
|
+
...i18nFile ? [`import ${i18nName} from "${normalizePath(i18nFile)}"`] : [],
|
|
560
|
+
...navigationFile ? [`import ${navigationName} from "${normalizePath(navigationFile)}"`] : [],
|
|
561
|
+
...preferencesFile ? [`import ${preferencesName} from "${normalizePath(preferencesFile)}"`] : []
|
|
562
|
+
];
|
|
563
|
+
const declaration = `const ${name} = {
|
|
564
|
+
routeModule: { routes: [
|
|
565
|
+
${routes.join(",\n")}
|
|
566
|
+
] },
|
|
567
|
+
menuItemModule: { menuItems: [
|
|
568
|
+
${menuItems.join(",\n")}
|
|
569
|
+
] },
|
|
570
|
+
widgetModule: { widgets: [
|
|
571
|
+
${widgets.entries.join(",\n")}
|
|
572
|
+
] },
|
|
573
|
+
customFieldsModule: { configs: [
|
|
574
|
+
${cfRefs.join(",\n")}
|
|
575
|
+
] },
|
|
576
|
+
layoutModule: { layouts: [
|
|
577
|
+
${layoutRefs.join(",\n")}
|
|
578
|
+
] },
|
|
579
|
+
i18nModule: ${i18nFile ? i18nName : "{}"},
|
|
580
|
+
navigationModule: ${navigationFile ? navigationName : "{}"},
|
|
581
|
+
preferenceModule: ${preferencesFile ? preferencesName : "{}"},
|
|
582
|
+
}`;
|
|
583
|
+
return { imports, declaration, name, nextIndex: index };
|
|
584
|
+
}
|
|
585
|
+
function emitLayers(config) {
|
|
586
|
+
const lines = [];
|
|
587
|
+
const declarations = [];
|
|
588
|
+
const names = [];
|
|
589
|
+
let index = 0;
|
|
590
|
+
layerSources(config).forEach((source, layer) => {
|
|
591
|
+
if ("entry" in source) {
|
|
592
|
+
const name = `__layer${layer}`;
|
|
593
|
+
lines.push(`import ${name} from "${normalizePath(source.entry)}"`);
|
|
594
|
+
names.push(name);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const collected = collectLayer(source.srcDir, layer, index);
|
|
598
|
+
index = collected.nextIndex;
|
|
599
|
+
lines.push(...collected.imports);
|
|
600
|
+
declarations.push(collected.declaration);
|
|
601
|
+
names.push(collected.name);
|
|
602
|
+
});
|
|
603
|
+
return { header: [...lines, ...declarations].join("\n"), names };
|
|
604
|
+
}
|
|
605
|
+
function spreadLayers(names, key, list) {
|
|
606
|
+
return names.map((name) => ` ...(${name}.${key}?.${list} ?? [])`).join(",\n");
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// src/routes.ts
|
|
610
|
+
function getRoute2(file, routesDir) {
|
|
611
|
+
const importPath = normalizePath(file);
|
|
612
|
+
const normalizedRoutesDir = normalizePath(routesDir);
|
|
613
|
+
return importPath.replace(normalizedRoutesDir, "").replace(/\[\[\*\]\]/g, "*?").replace(/\[\*\]/g, "*").replace(/\(([^[\])]+)\)/g, "$1?").replace(/\[\[([^\]]+)\]\]/g, ":$1?").replace(/\[([^\]]+)\]/g, ":$1").replace(
|
|
614
|
+
new RegExp(
|
|
615
|
+
`/page\\.(${VALID_FILE_EXTENSIONS.map((ext) => ext.slice(1)).join("|")})$`
|
|
616
|
+
),
|
|
617
|
+
""
|
|
618
|
+
) || "/";
|
|
619
|
+
}
|
|
620
|
+
function crawlRoutes(dir, pattern = "page") {
|
|
621
|
+
const files = [];
|
|
622
|
+
if (!fs5.existsSync(dir)) {
|
|
623
|
+
return files;
|
|
624
|
+
}
|
|
625
|
+
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
626
|
+
for (const entry of entries) {
|
|
627
|
+
const fullPath = path4.join(dir, entry.name);
|
|
628
|
+
if (entry.isDirectory()) {
|
|
629
|
+
files.push(...crawlRoutes(fullPath, pattern));
|
|
630
|
+
} else if (entry.isFile()) {
|
|
631
|
+
const ext = path4.extname(entry.name);
|
|
632
|
+
const baseName = path4.basename(entry.name, ext);
|
|
633
|
+
if (baseName === pattern && VALID_FILE_EXTENSIONS.includes(ext)) {
|
|
634
|
+
files.push(fullPath);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return files;
|
|
639
|
+
}
|
|
640
|
+
function hasConfigPublic(ast) {
|
|
641
|
+
let found = false;
|
|
642
|
+
traverse(ast, {
|
|
643
|
+
ExportNamedDeclaration(path6) {
|
|
644
|
+
const declaration = path6.node.declaration;
|
|
645
|
+
if (!isVariableDeclaration(declaration)) return;
|
|
646
|
+
for (const decl of declaration.declarations) {
|
|
647
|
+
if (isVariableDeclarator(decl) && isIdentifier(decl.id, { name: "config" }) && decl.init?.type === "ObjectExpression") {
|
|
648
|
+
const publicProp = decl.init.properties.find(
|
|
649
|
+
(prop) => isObjectProperty(prop) && isIdentifier(prop.key, { name: "public" }) && isBooleanLiteral(prop.value, { value: true })
|
|
650
|
+
);
|
|
651
|
+
if (publicProp) {
|
|
652
|
+
found = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
return found;
|
|
659
|
+
}
|
|
660
|
+
function getNamedExports(ast) {
|
|
661
|
+
let hasHandle = false;
|
|
662
|
+
let hasLoader = false;
|
|
663
|
+
traverse(ast, {
|
|
664
|
+
ExportNamedDeclaration(path6) {
|
|
665
|
+
const declaration = path6.node.declaration;
|
|
666
|
+
if (declaration?.type === "VariableDeclaration") {
|
|
667
|
+
declaration.declarations.forEach((decl) => {
|
|
668
|
+
if (decl.id.type === "Identifier" && decl.id.name === "handle") {
|
|
669
|
+
hasHandle = true;
|
|
670
|
+
}
|
|
671
|
+
if (decl.id.type === "Identifier" && decl.id.name === "loader") {
|
|
672
|
+
hasLoader = true;
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "loader") {
|
|
677
|
+
hasLoader = true;
|
|
678
|
+
}
|
|
679
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "handle") {
|
|
680
|
+
hasHandle = true;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
return { hasHandle, hasLoader };
|
|
685
|
+
}
|
|
686
|
+
function generateRouteComponentName(index) {
|
|
687
|
+
return `RouteComponent${index}`;
|
|
688
|
+
}
|
|
689
|
+
function generateHandleName(index) {
|
|
690
|
+
return `RouteHandle${index}`;
|
|
691
|
+
}
|
|
692
|
+
function generateLoaderName(index) {
|
|
693
|
+
return `RouteLoader${index}`;
|
|
694
|
+
}
|
|
695
|
+
function generateImports(file, index, hasHandle, hasLoader) {
|
|
696
|
+
const imports = [];
|
|
697
|
+
const componentName = generateRouteComponentName(index);
|
|
698
|
+
const importPath = normalizePath(file);
|
|
699
|
+
if (!hasHandle && !hasLoader) {
|
|
700
|
+
imports.push(`import ${componentName} from "${importPath}"`);
|
|
701
|
+
} else {
|
|
702
|
+
const namedImports = [
|
|
703
|
+
hasHandle && `handle as ${generateHandleName(index)}`,
|
|
704
|
+
hasLoader && `loader as ${generateLoaderName(index)}`
|
|
705
|
+
].filter(Boolean).join(", ");
|
|
706
|
+
imports.push(`import ${componentName}, { ${namedImports} } from "${importPath}"`);
|
|
707
|
+
}
|
|
708
|
+
return imports;
|
|
709
|
+
}
|
|
710
|
+
function generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic) {
|
|
711
|
+
return {
|
|
712
|
+
Component: generateRouteComponentName(index),
|
|
713
|
+
path: routePath,
|
|
714
|
+
handle: hasHandle ? generateHandleName(index) : void 0,
|
|
715
|
+
loader: hasLoader ? generateLoaderName(index) : void 0,
|
|
716
|
+
isPublic
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
function formatRoute(route, indent = " ") {
|
|
720
|
+
let result = `${indent}{
|
|
721
|
+
`;
|
|
722
|
+
result += `${indent} Component: ${route.Component},
|
|
723
|
+
`;
|
|
724
|
+
result += `${indent} path: "${route.path}"`;
|
|
725
|
+
if (route.handle) {
|
|
726
|
+
result += `,
|
|
727
|
+
${indent} handle: ${route.handle}`;
|
|
728
|
+
}
|
|
729
|
+
if (route.loader) {
|
|
730
|
+
result += `,
|
|
731
|
+
${indent} loader: ${route.loader}`;
|
|
732
|
+
}
|
|
733
|
+
if (route.isPublic) {
|
|
734
|
+
result += `,
|
|
735
|
+
${indent} isPublic: true`;
|
|
736
|
+
}
|
|
737
|
+
if (route.children?.length) {
|
|
738
|
+
result += `,
|
|
739
|
+
${indent} children: [
|
|
740
|
+
`;
|
|
741
|
+
result += route.children.map((child) => formatRoute(child, indent + " ")).join(",\n");
|
|
742
|
+
result += `
|
|
743
|
+
${indent} ]`;
|
|
744
|
+
}
|
|
745
|
+
result += `
|
|
746
|
+
${indent}}`;
|
|
747
|
+
return result;
|
|
561
748
|
}
|
|
562
|
-
function
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (result) {
|
|
569
|
-
results.push(result);
|
|
570
|
-
index++;
|
|
749
|
+
function parseFile(file, routesDir, index) {
|
|
750
|
+
try {
|
|
751
|
+
const code = fs5.readFileSync(file, "utf-8");
|
|
752
|
+
const ast = parse(code, getParserOptions(file));
|
|
753
|
+
if (!hasDefaultExport(ast)) {
|
|
754
|
+
return null;
|
|
571
755
|
}
|
|
756
|
+
const { hasHandle, hasLoader } = getNamedExports(ast);
|
|
757
|
+
const isPublic = hasConfigPublic(ast);
|
|
758
|
+
const routePath = getRoute2(file, routesDir);
|
|
759
|
+
const imports = generateImports(file, index, hasHandle, hasLoader);
|
|
760
|
+
const route = generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic);
|
|
761
|
+
return {
|
|
762
|
+
imports,
|
|
763
|
+
route
|
|
764
|
+
};
|
|
765
|
+
} catch {
|
|
766
|
+
return null;
|
|
572
767
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
);
|
|
576
|
-
const
|
|
577
|
-
(
|
|
768
|
+
}
|
|
769
|
+
function buildRouteTree(results) {
|
|
770
|
+
const routeMap = /* @__PURE__ */ new Map();
|
|
771
|
+
const sortedResults = [...results].sort(
|
|
772
|
+
(a, b) => a.route.path.split("/").length - b.route.path.split("/").length
|
|
578
773
|
);
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
774
|
+
for (const result of sortedResults) {
|
|
775
|
+
const routePath = result.route.path;
|
|
776
|
+
const isParallel = routePath.includes("/@");
|
|
777
|
+
if (isParallel) {
|
|
778
|
+
const parentPath = routePath.split("/@")[0];
|
|
779
|
+
const parent = routeMap.get(parentPath);
|
|
780
|
+
if (parent) {
|
|
781
|
+
parent.route.children = parent.route.children ?? [];
|
|
782
|
+
parent.route.children.push({
|
|
783
|
+
...result.route,
|
|
784
|
+
path: result.route.path.replace("/@", "/")
|
|
785
|
+
});
|
|
786
|
+
parent.imports.push(...result.imports);
|
|
787
|
+
} else {
|
|
788
|
+
routeMap.set(routePath, result);
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
routeMap.set(routePath, result);
|
|
792
|
+
}
|
|
585
793
|
}
|
|
586
|
-
return
|
|
587
|
-
|
|
588
|
-
|
|
794
|
+
return Array.from(routeMap.values());
|
|
795
|
+
}
|
|
796
|
+
function generateRoutes(config) {
|
|
797
|
+
const { header, names } = emitLayers(config);
|
|
798
|
+
return `${header}
|
|
589
799
|
|
|
590
|
-
export
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
]
|
|
594
|
-
}`;
|
|
800
|
+
export const customRoutes = [
|
|
801
|
+
${spreadLayers(names, "routeModule", "routes")}
|
|
802
|
+
]`;
|
|
595
803
|
}
|
|
596
804
|
|
|
597
805
|
// src/i18n.ts
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const i18nDir = path4.join(srcDir, "i18n");
|
|
602
|
-
if (!fs4.existsSync(i18nDir)) {
|
|
603
|
-
return null;
|
|
604
|
-
}
|
|
605
|
-
for (const ext of VALID_FILE_EXTENSIONS) {
|
|
606
|
-
const filePath = path4.join(i18nDir, `index${ext}`);
|
|
607
|
-
if (fs4.existsSync(filePath)) {
|
|
608
|
-
return filePath;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
function generateI18n({ srcDir, pluginExtensions }) {
|
|
614
|
-
const indexFile = findI18nIndex(srcDir);
|
|
615
|
-
const imports = [
|
|
616
|
-
...indexFile ? [`import appI18n from "${normalizePath(indexFile)}"`] : [],
|
|
617
|
-
...pluginExtensions.map(
|
|
618
|
-
(ext, i) => `import __plugin${i} from "${normalizePath(ext)}"`
|
|
619
|
-
)
|
|
620
|
-
];
|
|
621
|
-
const sources = [
|
|
622
|
-
...pluginExtensions.map((_, i) => `(__plugin${i}.i18nModule ?? {})`),
|
|
623
|
-
...indexFile ? ["appI18n"] : []
|
|
624
|
-
];
|
|
625
|
-
return `${imports.join("\n")}
|
|
806
|
+
function generateI18n(config) {
|
|
807
|
+
const { header, names } = emitLayers(config);
|
|
808
|
+
return `${header}
|
|
626
809
|
|
|
627
810
|
function deepMerge(target, source) {
|
|
628
811
|
const result = { ...target }
|
|
@@ -648,205 +831,62 @@ function mergeResources(target, source) {
|
|
|
648
831
|
return result
|
|
649
832
|
}
|
|
650
833
|
|
|
651
|
-
export default [${
|
|
834
|
+
export default [${names.map((name) => `(${name}.i18nModule ?? {})`).join(", ")}].reduce(mergeResources, {})
|
|
652
835
|
`;
|
|
653
836
|
}
|
|
654
837
|
|
|
655
|
-
// src/
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
function readWidgetConfig(properties) {
|
|
668
|
-
const zones = [];
|
|
669
|
-
const permissions = [];
|
|
670
|
-
let id;
|
|
671
|
-
let label;
|
|
672
|
-
for (const prop of properties) {
|
|
673
|
-
if (!isObjectProperty(prop)) continue;
|
|
674
|
-
if (isIdentifier(prop.key, { name: "zone" })) {
|
|
675
|
-
extractStrings(prop.value, zones);
|
|
676
|
-
}
|
|
677
|
-
if (isIdentifier(prop.key, { name: "permission" })) {
|
|
678
|
-
extractStrings(prop.value, permissions);
|
|
679
|
-
}
|
|
680
|
-
if (isIdentifier(prop.key, { name: "id" }) && isStringLiteral(prop.value)) {
|
|
681
|
-
id = prop.value.value;
|
|
838
|
+
// src/navigation.ts
|
|
839
|
+
function generateNavigation(config) {
|
|
840
|
+
const { header, names } = emitLayers(config);
|
|
841
|
+
return `${header}
|
|
842
|
+
|
|
843
|
+
const groups = new Map()
|
|
844
|
+
const items = new Map()
|
|
845
|
+
for (const navigation of [${names.map((name) => `${name}.navigationModule ?? {}`).join(", ")}]) {
|
|
846
|
+
for (const group of navigation.groups ?? []) {
|
|
847
|
+
if (group?.id) groups.set(group.id, { ...(groups.get(group.id) ?? {}), ...group })
|
|
682
848
|
}
|
|
683
|
-
|
|
684
|
-
|
|
849
|
+
for (const item of navigation.items ?? []) {
|
|
850
|
+
if (item?.id) items.set(item.id, { ...(items.get(item.id) ?? {}), ...item })
|
|
685
851
|
}
|
|
686
|
-
}
|
|
687
|
-
if (zones.length === 0) return null;
|
|
688
|
-
return { zones, id, label, permissions };
|
|
689
|
-
}
|
|
690
|
-
function getConfigProperties(node) {
|
|
691
|
-
if (isCallExpression(node) && node.arguments.length > 0 && isObjectExpression(node.arguments[0])) {
|
|
692
|
-
return node.arguments[0].properties;
|
|
693
|
-
}
|
|
694
|
-
if (isObjectExpression(node)) {
|
|
695
|
-
return node.properties;
|
|
696
|
-
}
|
|
697
|
-
return null;
|
|
698
|
-
}
|
|
699
|
-
function getWidgetConfig(file) {
|
|
700
|
-
try {
|
|
701
|
-
const code = fs5.readFileSync(file, "utf-8");
|
|
702
|
-
const ast = parse(code, getParserOptions(file));
|
|
703
|
-
if (!hasDefaultExport(ast)) return null;
|
|
704
|
-
let info = null;
|
|
705
|
-
const visit = (declaration) => {
|
|
706
|
-
if (info) return;
|
|
707
|
-
if (!isVariableDeclaration(declaration)) return;
|
|
708
|
-
for (const decl of declaration.declarations) {
|
|
709
|
-
if (isVariableDeclarator(decl) && isIdentifier(decl.id, { name: "config" })) {
|
|
710
|
-
const props = getConfigProperties(decl.init);
|
|
711
|
-
if (props) info = readWidgetConfig(props);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
traverse(ast, {
|
|
716
|
-
ExportNamedDeclaration(p) {
|
|
717
|
-
visit(p.node.declaration);
|
|
718
|
-
},
|
|
719
|
-
VariableDeclaration(p) {
|
|
720
|
-
visit(p.node);
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
return info;
|
|
724
|
-
} catch {
|
|
725
|
-
return null;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
function hashPath(relative) {
|
|
729
|
-
let hash = 0;
|
|
730
|
-
for (let i = 0; i < relative.length; i++) {
|
|
731
|
-
hash = (hash << 5) - hash + relative.charCodeAt(i);
|
|
732
|
-
hash |= 0;
|
|
733
|
-
}
|
|
734
|
-
return Math.abs(hash).toString(36).slice(0, 6);
|
|
735
|
-
}
|
|
736
|
-
function widgetId(info, file, widgetsDir) {
|
|
737
|
-
if (info.id) return info.id;
|
|
738
|
-
const relative = normalizePath(path5.relative(widgetsDir, file));
|
|
739
|
-
return `Widget-${hashPath(relative)}`;
|
|
740
|
-
}
|
|
741
|
-
function parseWidgetFile(file, widgetsDir, index) {
|
|
742
|
-
const info = getWidgetConfig(file);
|
|
743
|
-
if (!info) return null;
|
|
744
|
-
const name = `Widget${index}`;
|
|
745
|
-
const importPath = normalizePath(file);
|
|
746
|
-
const zonesLiteral = JSON.stringify(info.zones);
|
|
747
|
-
const id = widgetId(info, file, widgetsDir);
|
|
748
|
-
return {
|
|
749
|
-
import: `import ${name} from "${importPath}"`,
|
|
750
|
-
entry: ` { Component: ${name}, zone: ${zonesLiteral}, widgetId: ${JSON.stringify(
|
|
751
|
-
id
|
|
752
|
-
)}${info.label ? `, label: ${JSON.stringify(info.label)}` : ""}${info.permissions.length ? `, permission: ${JSON.stringify(info.permissions)}` : ""} }`
|
|
753
|
-
};
|
|
754
852
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
let index = startIndex;
|
|
758
|
-
const results = [];
|
|
759
|
-
for (const file of crawlModuleFiles(widgetsDir)) {
|
|
760
|
-
const result = parseWidgetFile(file, widgetsDir, index);
|
|
761
|
-
if (result) {
|
|
762
|
-
results.push(result);
|
|
763
|
-
index++;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
return {
|
|
767
|
-
imports: results.map((r) => r.import),
|
|
768
|
-
entries: results.map((r) => r.entry)
|
|
769
|
-
};
|
|
853
|
+
|
|
854
|
+
export default { groups: [...groups.values()], items: [...items.values()] }`;
|
|
770
855
|
}
|
|
771
|
-
function generateWidgets({
|
|
772
|
-
srcDir,
|
|
773
|
-
pluginExtensions
|
|
774
|
-
}) {
|
|
775
|
-
const { imports, entries: widgetEntries } = collectWidgets(srcDir);
|
|
776
|
-
const pluginDeclarations = pluginExtensions.map(
|
|
777
|
-
(ext, i) => `import __plugin${i} from "${normalizePath(ext)}"`
|
|
778
|
-
);
|
|
779
|
-
const pluginSpreads = pluginExtensions.map(
|
|
780
|
-
(_, i) => ` ...(__plugin${i}.widgetModule?.widgets ?? [])`
|
|
781
|
-
);
|
|
782
|
-
const entries = [...widgetEntries, ...pluginSpreads];
|
|
783
|
-
if (imports.length === 0 && pluginDeclarations.length === 0 && entries.length === 0) {
|
|
784
|
-
return `export default { widgets: [] }`;
|
|
785
|
-
}
|
|
786
|
-
return `${imports.join("\n")}
|
|
787
856
|
|
|
788
|
-
|
|
857
|
+
// src/custom-fields.ts
|
|
858
|
+
function generateCustomFields(config) {
|
|
859
|
+
const { header, names } = emitLayers(config);
|
|
860
|
+
return `${header}
|
|
789
861
|
|
|
790
862
|
export default {
|
|
791
|
-
|
|
792
|
-
${
|
|
863
|
+
configs: [
|
|
864
|
+
${spreadLayers(names, "customFieldsModule", "configs")}
|
|
793
865
|
]
|
|
794
866
|
}`;
|
|
795
867
|
}
|
|
796
868
|
|
|
797
|
-
// src/
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
function generateNavigation({ srcDir }) {
|
|
808
|
-
const file = findNavigationFile(srcDir);
|
|
809
|
-
if (!file) {
|
|
810
|
-
return `export default { items: [] }`;
|
|
811
|
-
}
|
|
812
|
-
return `import navigationConfig from "${normalizePath(file)}"
|
|
813
|
-
export default navigationConfig`;
|
|
869
|
+
// src/layouts-module.ts
|
|
870
|
+
function generateLayouts(config) {
|
|
871
|
+
const { header, names } = emitLayers(config);
|
|
872
|
+
return `${header}
|
|
873
|
+
|
|
874
|
+
const byId = new Map()
|
|
875
|
+
for (const layout of [
|
|
876
|
+
${spreadLayers(names, "layoutModule", "layouts")}
|
|
877
|
+
]) {
|
|
878
|
+
if (layout?.id) byId.set(layout.id, layout)
|
|
814
879
|
}
|
|
815
880
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
function generateCustomFields({
|
|
819
|
-
srcDir,
|
|
820
|
-
pluginExtensions
|
|
821
|
-
}) {
|
|
822
|
-
const dir = path7.join(srcDir, "custom-fields");
|
|
823
|
-
const files = crawlModuleFiles(dir);
|
|
824
|
-
const imports = files.map(
|
|
825
|
-
(file, i) => `import __cf${i} from "${normalizePath(file)}"`
|
|
826
|
-
);
|
|
827
|
-
const localRefs = files.map((_, i) => `__cf${i}`);
|
|
828
|
-
const pluginDeclarations = pluginExtensions.map(
|
|
829
|
-
(ext, i) => `const __plugin${i} = (await import("${normalizePath(ext)}")).default`
|
|
830
|
-
);
|
|
831
|
-
const pluginSpreads = pluginExtensions.map(
|
|
832
|
-
(_, i) => ` ...(__plugin${i}.customFieldsModule?.configs ?? [])`
|
|
833
|
-
);
|
|
834
|
-
const configs = [
|
|
835
|
-
...pluginSpreads,
|
|
836
|
-
...localRefs.map((ref) => ` ${ref}`)
|
|
837
|
-
];
|
|
838
|
-
if (configs.length === 0 && pluginDeclarations.length === 0) {
|
|
839
|
-
return `export default { configs: [] }`;
|
|
840
|
-
}
|
|
841
|
-
return `${imports.join("\n")}
|
|
881
|
+
export default { layouts: [...byId.values()] }`;
|
|
882
|
+
}
|
|
842
883
|
|
|
843
|
-
|
|
884
|
+
// src/preferences-module.ts
|
|
885
|
+
function generatePreferences(config) {
|
|
886
|
+
const { header, names } = emitLayers(config);
|
|
887
|
+
return `${header}
|
|
844
888
|
|
|
845
|
-
export default {
|
|
846
|
-
configs: [
|
|
847
|
-
${configs.join(",\n")}
|
|
848
|
-
]
|
|
849
|
-
}`;
|
|
889
|
+
export default { layers: [${names.map((name) => `${name}.preferenceModule ?? {}`).join(", ")}] }`;
|
|
850
890
|
}
|
|
851
891
|
|
|
852
892
|
// src/virtual-modules.ts
|
|
@@ -881,6 +921,12 @@ function loadVirtualModule({
|
|
|
881
921
|
if (id === RESOLVED_CUSTOM_FIELDS_MODULE) {
|
|
882
922
|
return generateCustomFields(mercurConfig);
|
|
883
923
|
}
|
|
924
|
+
if (id === RESOLVED_LAYOUTS_MODULE) {
|
|
925
|
+
return generateLayouts(mercurConfig);
|
|
926
|
+
}
|
|
927
|
+
if (id === RESOLVED_PREFERENCES_MODULE) {
|
|
928
|
+
return generatePreferences(mercurConfig);
|
|
929
|
+
}
|
|
884
930
|
return null;
|
|
885
931
|
}
|
|
886
932
|
function loadConfigModule(mercurConfig) {
|
|
@@ -898,19 +944,42 @@ function loadI18nModule(mercurConfig) {
|
|
|
898
944
|
|
|
899
945
|
// src/plugin.ts
|
|
900
946
|
function isRouteFile(file) {
|
|
901
|
-
const basename =
|
|
947
|
+
const basename = path5.basename(file, path5.extname(file));
|
|
902
948
|
return basename === "page";
|
|
903
949
|
}
|
|
904
950
|
function isWidgetFile(file) {
|
|
905
951
|
return normalizeSep(file).includes("/src/widgets/");
|
|
906
952
|
}
|
|
907
953
|
function isNavigationFile(file) {
|
|
908
|
-
const basename =
|
|
909
|
-
return basename ===
|
|
954
|
+
const basename = path5.basename(file, path5.extname(file));
|
|
955
|
+
return basename === NAVIGATION_FILE;
|
|
956
|
+
}
|
|
957
|
+
function isPreferencesFile(file) {
|
|
958
|
+
const basename = path5.basename(file, path5.extname(file));
|
|
959
|
+
return basename === LAYOUT_PREFERENCES_FILE;
|
|
910
960
|
}
|
|
911
961
|
function isCustomFieldFile(file) {
|
|
912
962
|
return normalizeSep(file).includes("/src/custom-fields/");
|
|
913
963
|
}
|
|
964
|
+
function isLayoutFile(file) {
|
|
965
|
+
return normalizeSep(file).includes("/layouts/");
|
|
966
|
+
}
|
|
967
|
+
function isI18nFile(file) {
|
|
968
|
+
return normalizeSep(file).includes("/i18n/");
|
|
969
|
+
}
|
|
970
|
+
var LAYERED_MODULES = [
|
|
971
|
+
RESOLVED_ROUTES_MODULE,
|
|
972
|
+
RESOLVED_MENU_ITEMS_MODULE,
|
|
973
|
+
RESOLVED_WIDGETS_MODULE,
|
|
974
|
+
RESOLVED_NAVIGATION_MODULE,
|
|
975
|
+
RESOLVED_CUSTOM_FIELDS_MODULE,
|
|
976
|
+
RESOLVED_LAYOUTS_MODULE,
|
|
977
|
+
RESOLVED_PREFERENCES_MODULE,
|
|
978
|
+
RESOLVED_I18N_MODULE
|
|
979
|
+
];
|
|
980
|
+
function isExtensionFile(file) {
|
|
981
|
+
return isRouteFile(file) || isWidgetFile(file) || isNavigationFile(file) || isPreferencesFile(file) || isCustomFieldFile(file) || isLayoutFile(file) || isI18nFile(file);
|
|
982
|
+
}
|
|
914
983
|
function normalizeSep(file) {
|
|
915
984
|
return file.replace(/\\/g, "/");
|
|
916
985
|
}
|
|
@@ -931,7 +1000,7 @@ function isMedusaVirtualModule(id) {
|
|
|
931
1000
|
return MEDUSA_VIRTUAL_MODULES.includes(id);
|
|
932
1001
|
}
|
|
933
1002
|
function filterResolvableDeps(specifiers, fromDir) {
|
|
934
|
-
const require2 = createRequire(
|
|
1003
|
+
const require2 = createRequire(path5.join(fromDir, "noop.js"));
|
|
935
1004
|
return specifiers.filter((specifier) => {
|
|
936
1005
|
try {
|
|
937
1006
|
require2.resolve(specifier);
|
|
@@ -949,44 +1018,44 @@ function isResolvedMedusaVirtualModule(id) {
|
|
|
949
1018
|
}
|
|
950
1019
|
function findNodeModulesRoot(configDir) {
|
|
951
1020
|
let dir = configDir;
|
|
952
|
-
while (dir !==
|
|
953
|
-
const candidate =
|
|
954
|
-
if (
|
|
1021
|
+
while (dir !== path5.dirname(dir)) {
|
|
1022
|
+
const candidate = path5.join(dir, "node_modules");
|
|
1023
|
+
if (fs6.existsSync(candidate) && fs6.statSync(candidate).isDirectory()) {
|
|
955
1024
|
return candidate;
|
|
956
1025
|
}
|
|
957
|
-
dir =
|
|
1026
|
+
dir = path5.dirname(dir);
|
|
958
1027
|
}
|
|
959
|
-
return
|
|
1028
|
+
return path5.join(configDir, "node_modules");
|
|
960
1029
|
}
|
|
961
1030
|
function resolvePluginRoot(resolve, configDir, nodeModulesRoot) {
|
|
962
1031
|
if (resolve.startsWith(".")) {
|
|
963
1032
|
try {
|
|
964
|
-
const resolved =
|
|
965
|
-
return
|
|
1033
|
+
const resolved = path5.resolve(configDir, resolve);
|
|
1034
|
+
return fs6.existsSync(resolved) ? fs6.realpathSync(resolved) : null;
|
|
966
1035
|
} catch {
|
|
967
1036
|
return null;
|
|
968
1037
|
}
|
|
969
1038
|
}
|
|
970
|
-
const require2 = createRequire(
|
|
1039
|
+
const require2 = createRequire(path5.join(configDir, "noop.js"));
|
|
971
1040
|
try {
|
|
972
|
-
return
|
|
973
|
-
|
|
1041
|
+
return fs6.realpathSync(
|
|
1042
|
+
path5.dirname(require2.resolve(`${resolve}/package.json`))
|
|
974
1043
|
);
|
|
975
1044
|
} catch {
|
|
976
1045
|
}
|
|
977
1046
|
try {
|
|
978
|
-
let dir =
|
|
979
|
-
while (dir !==
|
|
980
|
-
if (
|
|
981
|
-
return
|
|
1047
|
+
let dir = path5.dirname(require2.resolve(resolve));
|
|
1048
|
+
while (dir !== path5.dirname(dir)) {
|
|
1049
|
+
if (fs6.existsSync(path5.join(dir, "package.json"))) {
|
|
1050
|
+
return fs6.realpathSync(dir);
|
|
982
1051
|
}
|
|
983
|
-
dir =
|
|
1052
|
+
dir = path5.dirname(dir);
|
|
984
1053
|
}
|
|
985
1054
|
} catch {
|
|
986
1055
|
}
|
|
987
1056
|
try {
|
|
988
|
-
const packagePath =
|
|
989
|
-
return
|
|
1057
|
+
const packagePath = path5.join(nodeModulesRoot, resolve);
|
|
1058
|
+
return fs6.existsSync(packagePath) ? fs6.realpathSync(packagePath) : null;
|
|
990
1059
|
} catch {
|
|
991
1060
|
return null;
|
|
992
1061
|
}
|
|
@@ -1004,13 +1073,13 @@ function resolvePluginExtensions(plugins, configDir, appType) {
|
|
|
1004
1073
|
);
|
|
1005
1074
|
continue;
|
|
1006
1075
|
}
|
|
1007
|
-
const extFile =
|
|
1076
|
+
const extFile = path5.join(
|
|
1008
1077
|
pluginRoot,
|
|
1009
1078
|
".medusa/server/src",
|
|
1010
1079
|
appType,
|
|
1011
1080
|
"index.mjs"
|
|
1012
1081
|
);
|
|
1013
|
-
if (
|
|
1082
|
+
if (fs6.existsSync(extFile)) {
|
|
1014
1083
|
extensions.push(extFile);
|
|
1015
1084
|
}
|
|
1016
1085
|
}
|
|
@@ -1024,7 +1093,7 @@ function trimTrailingSlashes(value) {
|
|
|
1024
1093
|
return end === value.length ? value : value.slice(0, end);
|
|
1025
1094
|
}
|
|
1026
1095
|
async function loadMedusaConfig(medusaConfigPath, root, options) {
|
|
1027
|
-
const configDir =
|
|
1096
|
+
const configDir = path5.dirname(medusaConfigPath);
|
|
1028
1097
|
try {
|
|
1029
1098
|
const previousCwd = process.cwd();
|
|
1030
1099
|
let mod;
|
|
@@ -1054,7 +1123,7 @@ async function loadMedusaConfig(medusaConfigPath, root, options) {
|
|
|
1054
1123
|
const value = modules[key];
|
|
1055
1124
|
if (!value || typeof value !== "object" || !value.options?.appDir)
|
|
1056
1125
|
continue;
|
|
1057
|
-
const appDir =
|
|
1126
|
+
const appDir = path5.resolve(configDir, value.options.appDir);
|
|
1058
1127
|
if (appDir === root) {
|
|
1059
1128
|
base = value.options.path;
|
|
1060
1129
|
appType = key === "vendor_ui" ? "vendor" : "admin";
|
|
@@ -1065,7 +1134,9 @@ async function loadMedusaConfig(medusaConfigPath, root, options) {
|
|
|
1065
1134
|
(plugin) => plugin.resolve !== "@medusajs/draft-order"
|
|
1066
1135
|
) ?? [];
|
|
1067
1136
|
const pluginExtensions = resolvePluginExtensions(plugins, configDir, appType);
|
|
1068
|
-
|
|
1137
|
+
const projectCandidate = path5.join(configDir, "src", appType);
|
|
1138
|
+
const projectDir = fs6.existsSync(projectCandidate) && fs6.realpathSync(projectCandidate) !== root ? projectCandidate : void 0;
|
|
1139
|
+
return { base, pluginExtensions, projectDir, vendorAppUrl };
|
|
1069
1140
|
} catch (error) {
|
|
1070
1141
|
console.warn(
|
|
1071
1142
|
`[@mercurjs/dashboard-sdk] Could not load the Medusa config from "${medusaConfigPath}": ${error instanceof Error ? error.message : String(error)}. Building with base "/" and no plugin extensions \u2014 if this panel is served under a sub-path (e.g. /dashboard), its assets will not resolve.`
|
|
@@ -1081,11 +1152,11 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1081
1152
|
async config(viteConfig) {
|
|
1082
1153
|
root = viteConfig.root || process.cwd();
|
|
1083
1154
|
const isDevelopment = (viteConfig.mode || process.env.NODE_ENV || "development") !== "production";
|
|
1084
|
-
const medusaConfigPath =
|
|
1155
|
+
const medusaConfigPath = path5.resolve(
|
|
1085
1156
|
root,
|
|
1086
1157
|
pluginConfig.medusaConfigPath
|
|
1087
1158
|
);
|
|
1088
|
-
const { base, pluginExtensions, vendorAppUrl } = await loadMedusaConfig(
|
|
1159
|
+
const { base, pluginExtensions, projectDir, vendorAppUrl } = await loadMedusaConfig(
|
|
1089
1160
|
medusaConfigPath,
|
|
1090
1161
|
root,
|
|
1091
1162
|
{
|
|
@@ -1093,7 +1164,7 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1093
1164
|
vendorUrl: pluginConfig.vendorUrl
|
|
1094
1165
|
}
|
|
1095
1166
|
);
|
|
1096
|
-
const srcDir =
|
|
1167
|
+
const srcDir = path5.join(root, "src");
|
|
1097
1168
|
const backendUrl = pluginConfig.backendUrl ?? "http://localhost:9000";
|
|
1098
1169
|
const imageLimit = pluginConfig.imageLimit ?? 2 * 1024 * 1024;
|
|
1099
1170
|
config = {
|
|
@@ -1102,6 +1173,7 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1102
1173
|
base,
|
|
1103
1174
|
root,
|
|
1104
1175
|
srcDir,
|
|
1176
|
+
projectDir,
|
|
1105
1177
|
pluginExtensions,
|
|
1106
1178
|
imageLimit
|
|
1107
1179
|
};
|
|
@@ -1116,16 +1188,7 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1116
1188
|
dedupe: ["i18next", "react-i18next", "react", "react-dom"]
|
|
1117
1189
|
},
|
|
1118
1190
|
optimizeDeps: {
|
|
1119
|
-
exclude: [
|
|
1120
|
-
"virtual:mercur/config",
|
|
1121
|
-
"virtual:mercur/routes",
|
|
1122
|
-
"virtual:mercur/menu-items",
|
|
1123
|
-
"virtual:mercur/i18n",
|
|
1124
|
-
"virtual:mercur/widgets",
|
|
1125
|
-
"virtual:mercur/navigation",
|
|
1126
|
-
"virtual:mercur/custom-fields",
|
|
1127
|
-
...MEDUSA_VIRTUAL_MODULES
|
|
1128
|
-
],
|
|
1191
|
+
exclude: [...VIRTUAL_MODULES, ...MEDUSA_VIRTUAL_MODULES],
|
|
1129
1192
|
include: filterResolvableDeps(
|
|
1130
1193
|
[
|
|
1131
1194
|
"react",
|
|
@@ -1171,10 +1234,9 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1171
1234
|
}
|
|
1172
1235
|
};
|
|
1173
1236
|
const handleChange = (file) => {
|
|
1174
|
-
if (
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
if (isCustomFieldFile(file)) invalidate(RESOLVED_CUSTOM_FIELDS_MODULE, true);
|
|
1237
|
+
if (!isExtensionFile(file)) return;
|
|
1238
|
+
for (const moduleId of LAYERED_MODULES) invalidate(moduleId, false);
|
|
1239
|
+
server.ws.send({ type: "full-reload" });
|
|
1178
1240
|
};
|
|
1179
1241
|
server.watcher.on("add", handleChange);
|
|
1180
1242
|
server.watcher.on("unlink", handleChange);
|
|
@@ -1184,103 +1246,21 @@ function mercurDashboardPlugin(pluginConfig) {
|
|
|
1184
1246
|
const mod = server.moduleGraph.getModuleById(moduleId);
|
|
1185
1247
|
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
1186
1248
|
};
|
|
1187
|
-
if (
|
|
1188
|
-
|
|
1189
|
-
if (isNavigationFile(file)) invalidate(RESOLVED_NAVIGATION_MODULE);
|
|
1190
|
-
if (isCustomFieldFile(file)) invalidate(RESOLVED_CUSTOM_FIELDS_MODULE);
|
|
1249
|
+
if (!isExtensionFile(file)) return;
|
|
1250
|
+
for (const moduleId of LAYERED_MODULES) invalidate(moduleId);
|
|
1191
1251
|
}
|
|
1192
1252
|
};
|
|
1193
1253
|
}
|
|
1194
1254
|
|
|
1195
1255
|
// src/generate-plugin-entry.ts
|
|
1196
|
-
import path9 from "path";
|
|
1197
|
-
import fs8 from "fs";
|
|
1198
|
-
function findI18nIndex2(srcDir) {
|
|
1199
|
-
const i18nDir = path9.join(srcDir, "i18n");
|
|
1200
|
-
if (!fs8.existsSync(i18nDir)) return null;
|
|
1201
|
-
for (const ext of VALID_FILE_EXTENSIONS) {
|
|
1202
|
-
const filePath = path9.join(i18nDir, `index${ext}`);
|
|
1203
|
-
if (fs8.existsSync(filePath)) return filePath;
|
|
1204
|
-
}
|
|
1205
|
-
return null;
|
|
1206
|
-
}
|
|
1207
1256
|
function generatePluginEntryModule(srcDir) {
|
|
1208
|
-
const
|
|
1209
|
-
const files = crawlRoutes(routesDir);
|
|
1210
|
-
let index = 0;
|
|
1211
|
-
const routeResults = [];
|
|
1212
|
-
const menuItemResults = [];
|
|
1213
|
-
for (const file of files) {
|
|
1214
|
-
const route = parseFile(file, routesDir, index);
|
|
1215
|
-
if (route) {
|
|
1216
|
-
routeResults.push(route);
|
|
1217
|
-
}
|
|
1218
|
-
const menuItem = parseMenuItemFile(file, routesDir, index);
|
|
1219
|
-
if (menuItem) {
|
|
1220
|
-
menuItemResults.push(menuItem);
|
|
1221
|
-
}
|
|
1222
|
-
index++;
|
|
1223
|
-
}
|
|
1224
|
-
const routeTree = buildRouteTree(routeResults.filter(Boolean));
|
|
1225
|
-
const routeImports = routeTree.flatMap((r) => r.imports);
|
|
1226
|
-
const routes = routeTree.map((r) => formatRoute(r.route));
|
|
1227
|
-
const menuItemImports = menuItemResults.filter(Boolean).map((r) => r.import);
|
|
1228
|
-
const menuItems = menuItemResults.filter(Boolean).map((r) => formatMenuItem(r.menuItem));
|
|
1229
|
-
const { imports: widgetImports, entries: widgetEntries } = collectWidgets(
|
|
1230
|
-
srcDir,
|
|
1231
|
-
index
|
|
1232
|
-
);
|
|
1233
|
-
const cfFiles = crawlModuleFiles(path9.join(srcDir, "custom-fields"));
|
|
1234
|
-
const cfImports = cfFiles.map(
|
|
1235
|
-
(file, i) => `import __cf${i} from "${normalizePath(file)}"`
|
|
1236
|
-
);
|
|
1237
|
-
const cfRefs = cfFiles.map((_, i) => ` __cf${i}`);
|
|
1238
|
-
const i18nFile = findI18nIndex2(srcDir);
|
|
1239
|
-
const i18nImport = i18nFile ? `import i18nResources from "${normalizePath(i18nFile)}"` : "";
|
|
1240
|
-
const i18nValue = i18nFile ? "i18nResources" : "{}";
|
|
1241
|
-
const allImports = [
|
|
1242
|
-
...routeImports,
|
|
1243
|
-
...menuItemImports,
|
|
1244
|
-
...widgetImports,
|
|
1245
|
-
...cfImports
|
|
1246
|
-
];
|
|
1247
|
-
if (i18nImport) allImports.push(i18nImport);
|
|
1257
|
+
const { imports, declaration, name } = collectLayer(srcDir, 0);
|
|
1248
1258
|
return `// Auto-generated plugin extensions entry
|
|
1249
|
-
${
|
|
1250
|
-
|
|
1251
|
-
const routeModule = {
|
|
1252
|
-
routes: [
|
|
1253
|
-
${routes.join(",\n")}
|
|
1254
|
-
]
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
const menuItemModule = {
|
|
1258
|
-
menuItems: [
|
|
1259
|
-
${menuItems.join(",\n")}
|
|
1260
|
-
]
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
const widgetModule = {
|
|
1264
|
-
widgets: [
|
|
1265
|
-
${widgetEntries.join(",\n")}
|
|
1266
|
-
]
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
const customFieldsModule = {
|
|
1270
|
-
configs: [
|
|
1271
|
-
${cfRefs.join(",\n")}
|
|
1272
|
-
]
|
|
1273
|
-
}
|
|
1259
|
+
${imports.join("\n")}
|
|
1274
1260
|
|
|
1275
|
-
|
|
1276
|
-
routeModule,
|
|
1277
|
-
menuItemModule,
|
|
1278
|
-
widgetModule,
|
|
1279
|
-
customFieldsModule,
|
|
1280
|
-
i18nModule: ${i18nValue},
|
|
1281
|
-
}
|
|
1261
|
+
${declaration}
|
|
1282
1262
|
|
|
1283
|
-
export default
|
|
1263
|
+
export default ${name}
|
|
1284
1264
|
`;
|
|
1285
1265
|
}
|
|
1286
1266
|
export {
|