@mercurjs/dashboard-sdk 2.0.0-canary.9 → 2.0.0-canary.91
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 +433 -149
- package/dist/index.d.cts +14 -6
- package/package.json +4 -1
package/dist/index.cjs
CHANGED
|
@@ -30,24 +30,49 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
generatePluginEntryModule: () => generatePluginEntryModule,
|
|
34
|
+
mercurDashboardPlugin: () => mercurDashboardPlugin
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/plugin.ts
|
|
39
39
|
var import_path5 = __toESM(require("path"), 1);
|
|
40
|
+
var import_fs4 = __toESM(require("fs"), 1);
|
|
41
|
+
|
|
42
|
+
// src/babel.ts
|
|
43
|
+
var import_parser = require("@babel/parser");
|
|
44
|
+
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
45
|
+
var import_types = require("@babel/types");
|
|
46
|
+
var traverse;
|
|
47
|
+
if (typeof import_traverse.default === "function") {
|
|
48
|
+
traverse = import_traverse.default;
|
|
49
|
+
} else {
|
|
50
|
+
traverse = import_traverse.default.default;
|
|
51
|
+
}
|
|
40
52
|
|
|
41
53
|
// src/utils.ts
|
|
54
|
+
function normalizePath(filePath) {
|
|
55
|
+
return filePath.replace(/\\/g, "/");
|
|
56
|
+
}
|
|
57
|
+
function getParserOptions(file) {
|
|
58
|
+
const options = {
|
|
59
|
+
sourceType: "module",
|
|
60
|
+
plugins: ["jsx"]
|
|
61
|
+
};
|
|
62
|
+
if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
63
|
+
options.plugins.push("typescript");
|
|
64
|
+
}
|
|
65
|
+
return options;
|
|
66
|
+
}
|
|
42
67
|
function resolveExports(moduleExports) {
|
|
43
68
|
if ("default" in moduleExports && moduleExports.default && "default" in moduleExports.default) {
|
|
44
69
|
return resolveExports(moduleExports.default);
|
|
45
70
|
}
|
|
46
71
|
return moduleExports;
|
|
47
72
|
}
|
|
48
|
-
async function getFileExports(
|
|
73
|
+
async function getFileExports(path7) {
|
|
49
74
|
const { unregister } = await safeRegister();
|
|
50
|
-
const module2 = require(
|
|
75
|
+
const module2 = require(path7);
|
|
51
76
|
unregister();
|
|
52
77
|
return resolveExports(module2);
|
|
53
78
|
}
|
|
@@ -67,13 +92,31 @@ var safeRegister = async () => {
|
|
|
67
92
|
}
|
|
68
93
|
return res;
|
|
69
94
|
};
|
|
70
|
-
function
|
|
71
|
-
|
|
95
|
+
function hasDefaultExport(ast) {
|
|
96
|
+
let found = false;
|
|
97
|
+
traverse(ast, {
|
|
98
|
+
ExportDefaultDeclaration() {
|
|
99
|
+
found = true;
|
|
100
|
+
},
|
|
101
|
+
AssignmentExpression(path7) {
|
|
102
|
+
if (path7.node.left.type === "MemberExpression" && path7.node.left.object.type === "Identifier" && path7.node.left.object.name === "exports" && path7.node.left.property.type === "Identifier" && path7.node.left.property.name === "default") {
|
|
103
|
+
found = true;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
ExportNamedDeclaration(path7) {
|
|
107
|
+
const specifiers = path7.node.specifiers;
|
|
108
|
+
if (specifiers?.some(
|
|
109
|
+
(s) => s.type === "ExportSpecifier" && s.exported.type === "Identifier" && s.exported.name === "default"
|
|
110
|
+
)) {
|
|
111
|
+
found = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return found;
|
|
72
116
|
}
|
|
73
117
|
|
|
74
118
|
// src/constants.ts
|
|
75
119
|
var VALID_FILE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
76
|
-
var CONFIG_NAME = "mercur.config.ts";
|
|
77
120
|
var CONFIG_VIRTUAL_MODULE = "virtual:mercur/config";
|
|
78
121
|
var ROUTES_VIRTUAL_MODULE = "virtual:mercur/routes";
|
|
79
122
|
var COMPONENTS_VIRTUAL_MODULE = "virtual:mercur/components";
|
|
@@ -98,17 +141,17 @@ var import_path4 = __toESM(require("path"), 1);
|
|
|
98
141
|
// src/routes.ts
|
|
99
142
|
var import_fs = __toESM(require("fs"), 1);
|
|
100
143
|
var import_path = __toESM(require("path"), 1);
|
|
101
|
-
function getRoute(file,
|
|
144
|
+
function getRoute(file, routesDir) {
|
|
102
145
|
const importPath = normalizePath(file);
|
|
103
|
-
const
|
|
104
|
-
return importPath.replace(
|
|
146
|
+
const normalizedRoutesDir = normalizePath(routesDir);
|
|
147
|
+
return importPath.replace(normalizedRoutesDir, "").replace(/\[\[\*\]\]/g, "*?").replace(/\[\*\]/g, "*").replace(/\(([^\[\]\)]+)\)/g, "$1?").replace(/\[\[([^\]]+)\]\]/g, ":$1?").replace(/\[([^\]]+)\]/g, ":$1").replace(
|
|
105
148
|
new RegExp(
|
|
106
149
|
`/page\\.(${VALID_FILE_EXTENSIONS.map((ext) => ext.slice(1)).join("|")})$`
|
|
107
150
|
),
|
|
108
151
|
""
|
|
109
152
|
) || "/";
|
|
110
153
|
}
|
|
111
|
-
function
|
|
154
|
+
function crawlRoutes(dir, pattern = "page") {
|
|
112
155
|
const files = [];
|
|
113
156
|
if (!import_fs.default.existsSync(dir)) {
|
|
114
157
|
return files;
|
|
@@ -117,7 +160,7 @@ function crawlPages(dir, pattern = "page") {
|
|
|
117
160
|
for (const entry of entries) {
|
|
118
161
|
const fullPath = import_path.default.join(dir, entry.name);
|
|
119
162
|
if (entry.isDirectory()) {
|
|
120
|
-
files.push(...
|
|
163
|
+
files.push(...crawlRoutes(fullPath, pattern));
|
|
121
164
|
} else if (entry.isFile()) {
|
|
122
165
|
const ext = import_path.default.extname(entry.name);
|
|
123
166
|
const baseName = import_path.default.basename(entry.name, ext);
|
|
@@ -128,31 +171,51 @@ function crawlPages(dir, pattern = "page") {
|
|
|
128
171
|
}
|
|
129
172
|
return files;
|
|
130
173
|
}
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
174
|
+
function hasConfigPublic(ast) {
|
|
175
|
+
let found = false;
|
|
176
|
+
traverse(ast, {
|
|
177
|
+
ExportNamedDeclaration(path7) {
|
|
178
|
+
const declaration = path7.node.declaration;
|
|
179
|
+
if (!(0, import_types.isVariableDeclaration)(declaration)) return;
|
|
180
|
+
for (const decl of declaration.declarations) {
|
|
181
|
+
if ((0, import_types.isVariableDeclarator)(decl) && (0, import_types.isIdentifier)(decl.id, { name: "config" }) && decl.init?.type === "ObjectExpression") {
|
|
182
|
+
const publicProp = decl.init.properties.find(
|
|
183
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "public" }) && (0, import_types.isBooleanLiteral)(prop.value, { value: true })
|
|
184
|
+
);
|
|
185
|
+
if (publicProp) {
|
|
186
|
+
found = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return found;
|
|
193
|
+
}
|
|
194
|
+
function getNamedExports(ast) {
|
|
195
|
+
let hasHandle = false;
|
|
196
|
+
let hasLoader = false;
|
|
197
|
+
traverse(ast, {
|
|
198
|
+
ExportNamedDeclaration(path7) {
|
|
199
|
+
const declaration = path7.node.declaration;
|
|
200
|
+
if (declaration?.type === "VariableDeclaration") {
|
|
201
|
+
declaration.declarations.forEach((decl) => {
|
|
202
|
+
if (decl.id.type === "Identifier" && decl.id.name === "handle") {
|
|
203
|
+
hasHandle = true;
|
|
204
|
+
}
|
|
205
|
+
if (decl.id.type === "Identifier" && decl.id.name === "loader") {
|
|
206
|
+
hasLoader = true;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "loader") {
|
|
211
|
+
hasLoader = true;
|
|
212
|
+
}
|
|
213
|
+
if (declaration?.type === "FunctionDeclaration" && declaration.id?.name === "handle") {
|
|
214
|
+
hasHandle = true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return { hasHandle, hasLoader };
|
|
156
219
|
}
|
|
157
220
|
function generateRouteComponentName(index) {
|
|
158
221
|
return `RouteComponent${index}`;
|
|
@@ -217,19 +280,25 @@ ${indent} ]`;
|
|
|
217
280
|
${indent}}`;
|
|
218
281
|
return result;
|
|
219
282
|
}
|
|
220
|
-
function parseFile(file,
|
|
221
|
-
|
|
283
|
+
function parseFile(file, routesDir, index) {
|
|
284
|
+
try {
|
|
285
|
+
const code = import_fs.default.readFileSync(file, "utf-8");
|
|
286
|
+
const ast = (0, import_parser.parse)(code, getParserOptions(file));
|
|
287
|
+
if (!hasDefaultExport(ast)) {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
const { hasHandle, hasLoader } = getNamedExports(ast);
|
|
291
|
+
const isPublic = hasConfigPublic(ast);
|
|
292
|
+
const routePath = getRoute(file, routesDir);
|
|
293
|
+
const imports = generateImports(file, index, hasHandle, hasLoader);
|
|
294
|
+
const route = generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic);
|
|
295
|
+
return {
|
|
296
|
+
imports,
|
|
297
|
+
route
|
|
298
|
+
};
|
|
299
|
+
} catch {
|
|
222
300
|
return null;
|
|
223
301
|
}
|
|
224
|
-
const { hasHandle, hasLoader } = getNamedExports(file);
|
|
225
|
-
const isPublic = hasConfigPublic(file);
|
|
226
|
-
const routePath = getRoute(file, pagesDir);
|
|
227
|
-
const imports = generateImports(file, index, hasHandle, hasLoader);
|
|
228
|
-
const route = generateRouteObject(routePath, index, hasHandle, hasLoader, isPublic);
|
|
229
|
-
return {
|
|
230
|
-
imports,
|
|
231
|
-
route
|
|
232
|
-
};
|
|
233
302
|
}
|
|
234
303
|
function buildRouteTree(results) {
|
|
235
304
|
const routeMap = /* @__PURE__ */ new Map();
|
|
@@ -243,7 +312,7 @@ function buildRouteTree(results) {
|
|
|
243
312
|
const parentPath = routePath.split("/@")[0];
|
|
244
313
|
const parent = routeMap.get(parentPath);
|
|
245
314
|
if (parent) {
|
|
246
|
-
parent.route.children = parent.route.children
|
|
315
|
+
parent.route.children = parent.route.children ?? [];
|
|
247
316
|
parent.route.children.push({
|
|
248
317
|
...result.route,
|
|
249
318
|
path: result.route.path.replace("/@", "/")
|
|
@@ -258,38 +327,44 @@ function buildRouteTree(results) {
|
|
|
258
327
|
}
|
|
259
328
|
return Array.from(routeMap.values());
|
|
260
329
|
}
|
|
261
|
-
function generateRoutes({ srcDir }) {
|
|
262
|
-
const
|
|
263
|
-
const files = crawlPages(pagesDir);
|
|
264
|
-
if (files.length === 0) {
|
|
265
|
-
return `export const customRoutes = []`;
|
|
266
|
-
}
|
|
330
|
+
function generateRoutes({ srcDir, pluginExtensions }) {
|
|
331
|
+
const routesDir = import_path.default.join(srcDir, "routes");
|
|
267
332
|
let index = 0;
|
|
268
333
|
const results = [];
|
|
269
|
-
for (const file of
|
|
270
|
-
const result = parseFile(file,
|
|
334
|
+
for (const file of crawlRoutes(routesDir)) {
|
|
335
|
+
const result = parseFile(file, routesDir, index);
|
|
271
336
|
if (result) {
|
|
272
337
|
results.push(result);
|
|
273
338
|
index++;
|
|
274
339
|
}
|
|
275
340
|
}
|
|
276
|
-
|
|
341
|
+
const pluginDeclarations = pluginExtensions.map(
|
|
342
|
+
(ext, i) => `const __plugin${i} = (await import("${normalizePath(ext)}")).default`
|
|
343
|
+
);
|
|
344
|
+
const pluginSpreads = pluginExtensions.map(
|
|
345
|
+
(_, i) => ` ...(__plugin${i}.routeModule?.routes ?? [])`
|
|
346
|
+
);
|
|
347
|
+
const routeTree = buildRouteTree(results);
|
|
348
|
+
const appImports = routeTree.flatMap((r) => r.imports);
|
|
349
|
+
const appRoutes = routeTree.map((r) => formatRoute(r.route));
|
|
350
|
+
const allImports = [...appImports];
|
|
351
|
+
const allRoutes = [...appRoutes, ...pluginSpreads];
|
|
352
|
+
if (allImports.length === 0 && pluginDeclarations.length === 0 && allRoutes.length === 0) {
|
|
277
353
|
return `export const customRoutes = []`;
|
|
278
354
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return `${imports.join("\n")}
|
|
355
|
+
return `${allImports.join("\n")}
|
|
356
|
+
|
|
357
|
+
${pluginDeclarations.join("\n")}
|
|
283
358
|
|
|
284
359
|
export const customRoutes = [
|
|
285
|
-
${
|
|
360
|
+
${allRoutes.join(",\n")}
|
|
286
361
|
]`;
|
|
287
362
|
}
|
|
288
363
|
|
|
289
364
|
// src/menu-items.ts
|
|
290
365
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
291
366
|
var import_path2 = __toESM(require("path"), 1);
|
|
292
|
-
function
|
|
367
|
+
function crawlRoutes2(dir, pattern = "page") {
|
|
293
368
|
const files = [];
|
|
294
369
|
if (!import_fs2.default.existsSync(dir)) {
|
|
295
370
|
return files;
|
|
@@ -298,7 +373,7 @@ function crawlPages2(dir, pattern = "page") {
|
|
|
298
373
|
for (const entry of entries) {
|
|
299
374
|
const fullPath = import_path2.default.join(dir, entry.name);
|
|
300
375
|
if (entry.isDirectory()) {
|
|
301
|
-
files.push(...
|
|
376
|
+
files.push(...crawlRoutes2(fullPath, pattern));
|
|
302
377
|
} else if (entry.isFile()) {
|
|
303
378
|
const ext = import_path2.default.extname(entry.name);
|
|
304
379
|
const baseName = import_path2.default.basename(entry.name, ext);
|
|
@@ -309,39 +384,100 @@ function crawlPages2(dir, pattern = "page") {
|
|
|
309
384
|
}
|
|
310
385
|
return files;
|
|
311
386
|
}
|
|
312
|
-
function getRoute2(file,
|
|
387
|
+
function getRoute2(file, routesDir) {
|
|
313
388
|
const importPath = normalizePath(file);
|
|
314
|
-
const
|
|
315
|
-
return importPath.replace(
|
|
389
|
+
const normalizedRoutesDir = normalizePath(routesDir);
|
|
390
|
+
return importPath.replace(normalizedRoutesDir, "").replace(/\[\[\*\]\]/g, "*?").replace(/\[\*\]/g, "*").replace(/\(([^\[\]\)]+)\)/g, "$1?").replace(/\[\[([^\]]+)\]\]/g, ":$1?").replace(/\[([^\]]+)\]/g, ":$1").replace(
|
|
316
391
|
new RegExp(
|
|
317
392
|
`/page\\.(${VALID_FILE_EXTENSIONS.map((ext) => ext.slice(1)).join("|")})$`
|
|
318
393
|
),
|
|
319
394
|
""
|
|
320
395
|
) || "/";
|
|
321
396
|
}
|
|
322
|
-
function
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
397
|
+
function getConfigObjectProperties(path7) {
|
|
398
|
+
if ((0, import_types.isVariableDeclarator)(path7.node)) {
|
|
399
|
+
const decl = (0, import_types.isIdentifier)(path7.node.id, { name: "config" }) ? path7.node : null;
|
|
400
|
+
if (!decl) return null;
|
|
401
|
+
if ((0, import_types.isCallExpression)(decl.init) && decl.init.arguments.length > 0 && (0, import_types.isObjectExpression)(decl.init.arguments[0])) {
|
|
402
|
+
return decl.init.arguments[0].properties;
|
|
403
|
+
}
|
|
404
|
+
if ((0, import_types.isObjectExpression)(decl.init)) {
|
|
405
|
+
return decl.init.properties;
|
|
406
|
+
}
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
const declaration = path7.node.declaration;
|
|
410
|
+
if ((0, import_types.isVariableDeclaration)(declaration)) {
|
|
411
|
+
const configDecl = declaration.declarations.find(
|
|
412
|
+
(d) => (0, import_types.isVariableDeclarator)(d) && (0, import_types.isIdentifier)(d.id, { name: "config" })
|
|
413
|
+
);
|
|
414
|
+
if (configDecl && (0, import_types.isCallExpression)(configDecl.init) && configDecl.init.arguments.length > 0 && (0, import_types.isObjectExpression)(configDecl.init.arguments[0])) {
|
|
415
|
+
return configDecl.init.arguments[0].properties;
|
|
416
|
+
}
|
|
417
|
+
const directDecl = declaration.declarations.find(
|
|
418
|
+
(d) => (0, import_types.isVariableDeclarator)(d) && (0, import_types.isIdentifier)(d.id, { name: "config" })
|
|
419
|
+
);
|
|
420
|
+
if (directDecl && (0, import_types.isObjectExpression)(directDecl.init)) {
|
|
421
|
+
return directDecl.init.properties;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
function processConfigProperties(properties) {
|
|
427
|
+
const hasProperty = (name) => properties.some(
|
|
428
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name })
|
|
429
|
+
);
|
|
430
|
+
const hasLabel = hasProperty("label");
|
|
431
|
+
if (!hasLabel) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
const hasIcon = hasProperty("icon");
|
|
435
|
+
const nested = properties.find(
|
|
436
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "nested" })
|
|
437
|
+
);
|
|
438
|
+
let nestedValue;
|
|
439
|
+
if (nested && (0, import_types.isObjectProperty)(nested) && (0, import_types.isStringLiteral)(nested.value)) {
|
|
440
|
+
nestedValue = nested.value.value;
|
|
441
|
+
}
|
|
442
|
+
const translationNs = properties.find(
|
|
443
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "translationNs" })
|
|
444
|
+
);
|
|
445
|
+
let translationNsValue;
|
|
446
|
+
if (translationNs && (0, import_types.isObjectProperty)(translationNs) && (0, import_types.isStringLiteral)(translationNs.value)) {
|
|
447
|
+
translationNsValue = translationNs.value.value;
|
|
328
448
|
}
|
|
449
|
+
const rank = properties.find(
|
|
450
|
+
(prop) => (0, import_types.isObjectProperty)(prop) && (0, import_types.isIdentifier)(prop.key, { name: "rank" })
|
|
451
|
+
);
|
|
452
|
+
let rankValue;
|
|
453
|
+
if (rank && (0, import_types.isObjectProperty)(rank) && (0, import_types.isNumericLiteral)(rank.value)) {
|
|
454
|
+
rankValue = rank.value.value;
|
|
455
|
+
}
|
|
456
|
+
return { label: hasLabel, icon: hasIcon, rank: rankValue, nested: nestedValue, translationNs: translationNsValue };
|
|
329
457
|
}
|
|
330
|
-
function
|
|
458
|
+
function getRouteConfig(file) {
|
|
331
459
|
try {
|
|
332
|
-
const
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
460
|
+
const code = import_fs2.default.readFileSync(file, "utf-8");
|
|
461
|
+
const ast = (0, import_parser.parse)(code, getParserOptions(file));
|
|
462
|
+
let config = null;
|
|
463
|
+
let configFound = false;
|
|
464
|
+
traverse(ast, {
|
|
465
|
+
VariableDeclarator(path7) {
|
|
466
|
+
if (configFound) return;
|
|
467
|
+
const properties = getConfigObjectProperties(path7);
|
|
468
|
+
if (!properties) return;
|
|
469
|
+
config = processConfigProperties(properties);
|
|
470
|
+
if (config) configFound = true;
|
|
471
|
+
},
|
|
472
|
+
ExportNamedDeclaration(path7) {
|
|
473
|
+
if (configFound) return;
|
|
474
|
+
const properties = getConfigObjectProperties(path7);
|
|
475
|
+
if (!properties) return;
|
|
476
|
+
config = processConfigProperties(properties);
|
|
477
|
+
if (config) configFound = true;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
return config;
|
|
345
481
|
} catch {
|
|
346
482
|
return null;
|
|
347
483
|
}
|
|
@@ -353,12 +489,12 @@ function generateImport(file, index) {
|
|
|
353
489
|
const importPath = normalizePath(file);
|
|
354
490
|
return `import { config as ${generateRouteConfigName(index)} } from "${importPath}"`;
|
|
355
491
|
}
|
|
356
|
-
function generateMenuItem(config, file,
|
|
492
|
+
function generateMenuItem(config, file, routesDir, index) {
|
|
357
493
|
const configName = generateRouteConfigName(index);
|
|
358
494
|
return {
|
|
359
495
|
label: `${configName}.label`,
|
|
360
496
|
icon: config.icon ? `${configName}.icon` : void 0,
|
|
361
|
-
path: getRoute2(file,
|
|
497
|
+
path: getRoute2(file, routesDir),
|
|
362
498
|
rank: config.rank,
|
|
363
499
|
nested: config.nested,
|
|
364
500
|
translationNs: config.translationNs ? `${configName}.translationNs` : void 0
|
|
@@ -377,44 +513,47 @@ function formatMenuItem(menuItem) {
|
|
|
377
513
|
${parts.join(",\n")}
|
|
378
514
|
}`;
|
|
379
515
|
}
|
|
380
|
-
function
|
|
381
|
-
|
|
382
|
-
return null;
|
|
383
|
-
}
|
|
384
|
-
const config = getConfigProperties(file);
|
|
516
|
+
function parseMenuItemFile(file, routesDir, index) {
|
|
517
|
+
const config = getRouteConfig(file);
|
|
385
518
|
if (!config) {
|
|
386
519
|
return null;
|
|
387
520
|
}
|
|
388
521
|
return {
|
|
389
522
|
import: generateImport(file, index),
|
|
390
|
-
menuItem: generateMenuItem(config, file,
|
|
523
|
+
menuItem: generateMenuItem(config, file, routesDir, index)
|
|
391
524
|
};
|
|
392
525
|
}
|
|
393
|
-
function generateMenuItems({ srcDir }) {
|
|
394
|
-
const
|
|
395
|
-
const files = crawlPages2(pagesDir);
|
|
396
|
-
if (files.length === 0) {
|
|
397
|
-
return `export default { menuItems: [] }`;
|
|
398
|
-
}
|
|
526
|
+
function generateMenuItems({ srcDir, pluginExtensions }) {
|
|
527
|
+
const routesDir = import_path2.default.join(srcDir, "routes");
|
|
399
528
|
let index = 0;
|
|
400
529
|
const results = [];
|
|
401
|
-
for (const file of
|
|
402
|
-
const result =
|
|
530
|
+
for (const file of crawlRoutes2(routesDir)) {
|
|
531
|
+
const result = parseMenuItemFile(file, routesDir, index);
|
|
403
532
|
if (result) {
|
|
404
533
|
results.push(result);
|
|
405
534
|
index++;
|
|
406
535
|
}
|
|
407
536
|
}
|
|
408
|
-
|
|
537
|
+
const pluginDeclarations = pluginExtensions.map(
|
|
538
|
+
(ext, i) => `const __plugin${i} = (await import("${normalizePath(ext)}")).default`
|
|
539
|
+
);
|
|
540
|
+
const pluginSpreads = pluginExtensions.map(
|
|
541
|
+
(_, i) => ` ...(__plugin${i}.menuItemModule?.menuItems ?? [])`
|
|
542
|
+
);
|
|
543
|
+
const appImports = results.map((r) => r.import);
|
|
544
|
+
const appMenuItems = results.map((r) => formatMenuItem(r.menuItem));
|
|
545
|
+
const allImports = [...appImports];
|
|
546
|
+
const allMenuItems = [...appMenuItems, ...pluginSpreads];
|
|
547
|
+
if (allImports.length === 0 && pluginDeclarations.length === 0 && allMenuItems.length === 0) {
|
|
409
548
|
return `export default { menuItems: [] }`;
|
|
410
549
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
550
|
+
return `${allImports.join("\n")}
|
|
551
|
+
|
|
552
|
+
${pluginDeclarations.join("\n")}
|
|
414
553
|
|
|
415
554
|
export default {
|
|
416
555
|
menuItems: [
|
|
417
|
-
${
|
|
556
|
+
${allMenuItems.join(",\n")}
|
|
418
557
|
]
|
|
419
558
|
}`;
|
|
420
559
|
}
|
|
@@ -506,47 +645,138 @@ function loadI18nModule(mercurConfig) {
|
|
|
506
645
|
}
|
|
507
646
|
|
|
508
647
|
// src/plugin.ts
|
|
509
|
-
function
|
|
510
|
-
const
|
|
511
|
-
return
|
|
512
|
-
...config,
|
|
513
|
-
backendUrl: config.backendUrl ?? "http://localhost:9000",
|
|
514
|
-
root,
|
|
515
|
-
srcDir,
|
|
516
|
-
configPath: import_path5.default.resolve(root, CONFIG_NAME)
|
|
517
|
-
};
|
|
648
|
+
function isRouteFile(file) {
|
|
649
|
+
const basename = import_path5.default.basename(file, import_path5.default.extname(file));
|
|
650
|
+
return basename === "page";
|
|
518
651
|
}
|
|
519
|
-
|
|
520
|
-
|
|
652
|
+
var UI_MODULE_KEYS = ["admin_ui", "vendor_ui"];
|
|
653
|
+
function findNodeModulesRoot(configDir) {
|
|
654
|
+
let dir = configDir;
|
|
655
|
+
while (dir !== import_path5.default.dirname(dir)) {
|
|
656
|
+
const candidate = import_path5.default.join(dir, "node_modules");
|
|
657
|
+
if (import_fs4.default.existsSync(candidate) && import_fs4.default.statSync(candidate).isDirectory()) {
|
|
658
|
+
return candidate;
|
|
659
|
+
}
|
|
660
|
+
dir = import_path5.default.dirname(dir);
|
|
661
|
+
}
|
|
662
|
+
return import_path5.default.join(configDir, "node_modules");
|
|
663
|
+
}
|
|
664
|
+
function resolvePluginRoot(resolve, configDir, nodeModulesRoot) {
|
|
521
665
|
try {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
666
|
+
if (resolve.startsWith(".")) {
|
|
667
|
+
const resolved = import_path5.default.resolve(configDir, resolve);
|
|
668
|
+
if (import_fs4.default.existsSync(resolved)) {
|
|
669
|
+
return import_fs4.default.realpathSync(resolved);
|
|
670
|
+
}
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
const packagePath = import_path5.default.join(nodeModulesRoot, resolve);
|
|
674
|
+
if (!import_fs4.default.existsSync(packagePath)) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
return import_fs4.default.realpathSync(packagePath);
|
|
678
|
+
} catch {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
function resolvePluginExtensions(plugins, configDir, appType) {
|
|
683
|
+
const nodeModulesRoot = findNodeModulesRoot(configDir);
|
|
684
|
+
const extensions = [];
|
|
685
|
+
for (const plugin of plugins) {
|
|
686
|
+
const resolve = typeof plugin === "string" ? plugin : plugin?.resolve;
|
|
687
|
+
if (!resolve || typeof resolve !== "string") continue;
|
|
688
|
+
const pluginRoot = resolvePluginRoot(resolve, configDir, nodeModulesRoot);
|
|
689
|
+
if (!pluginRoot) continue;
|
|
690
|
+
const extFile = import_path5.default.join(
|
|
691
|
+
pluginRoot,
|
|
692
|
+
".medusa/server/src",
|
|
693
|
+
appType,
|
|
694
|
+
"index.mjs"
|
|
529
695
|
);
|
|
696
|
+
if (import_fs4.default.existsSync(extFile)) {
|
|
697
|
+
extensions.push(extFile);
|
|
698
|
+
}
|
|
530
699
|
}
|
|
700
|
+
return extensions;
|
|
531
701
|
}
|
|
532
|
-
function
|
|
533
|
-
|
|
534
|
-
|
|
702
|
+
async function loadMedusaConfig(medusaConfigPath, root) {
|
|
703
|
+
try {
|
|
704
|
+
const mod = await getFileExports(medusaConfigPath);
|
|
705
|
+
const medusaConfig = mod.default ?? mod;
|
|
706
|
+
const modules = medusaConfig?.modules ?? {};
|
|
707
|
+
const configDir = import_path5.default.dirname(medusaConfigPath);
|
|
708
|
+
let base;
|
|
709
|
+
let appType = "admin";
|
|
710
|
+
for (const key of UI_MODULE_KEYS) {
|
|
711
|
+
const value = modules[key];
|
|
712
|
+
if (!value || typeof value !== "object" || !value.options?.appDir)
|
|
713
|
+
continue;
|
|
714
|
+
const appDir = import_path5.default.resolve(configDir, value.options.appDir);
|
|
715
|
+
if (appDir === root) {
|
|
716
|
+
base = value.options.path;
|
|
717
|
+
appType = key === "vendor_ui" ? "vendor" : "admin";
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
const plugins = medusaConfig?.plugins?.filter(
|
|
722
|
+
(plugin) => plugin.resolve !== "@medusajs/draft-order"
|
|
723
|
+
) ?? [];
|
|
724
|
+
const pluginExtensions = resolvePluginExtensions(plugins, configDir, appType);
|
|
725
|
+
return { base, pluginExtensions };
|
|
726
|
+
} catch {
|
|
727
|
+
return { pluginExtensions: [] };
|
|
728
|
+
}
|
|
535
729
|
}
|
|
536
|
-
function
|
|
730
|
+
function mercurDashboardPlugin(pluginConfig) {
|
|
537
731
|
let root;
|
|
538
732
|
let config;
|
|
539
733
|
return {
|
|
540
734
|
name: "@mercurjs/dashboard-sdk",
|
|
541
735
|
async config(viteConfig) {
|
|
542
736
|
root = viteConfig.root || process.cwd();
|
|
543
|
-
|
|
737
|
+
const medusaConfigPath = import_path5.default.resolve(
|
|
738
|
+
root,
|
|
739
|
+
pluginConfig.medusaConfigPath
|
|
740
|
+
);
|
|
741
|
+
const { base, pluginExtensions } = await loadMedusaConfig(
|
|
742
|
+
medusaConfigPath,
|
|
743
|
+
root
|
|
744
|
+
);
|
|
745
|
+
const srcDir = import_path5.default.join(root, "src");
|
|
746
|
+
const backendUrl = pluginConfig.backendUrl ?? "http://localhost:9000";
|
|
747
|
+
config = {
|
|
748
|
+
...pluginConfig,
|
|
749
|
+
backendUrl,
|
|
750
|
+
base,
|
|
751
|
+
root,
|
|
752
|
+
srcDir,
|
|
753
|
+
pluginExtensions
|
|
754
|
+
};
|
|
544
755
|
return {
|
|
756
|
+
base: config.base,
|
|
545
757
|
define: {
|
|
546
|
-
|
|
758
|
+
__BACKEND_URL__: JSON.stringify(config.backendUrl),
|
|
759
|
+
__BASE__: JSON.stringify(config.base || "/")
|
|
547
760
|
},
|
|
548
761
|
optimizeDeps: {
|
|
549
|
-
exclude: [
|
|
762
|
+
exclude: [
|
|
763
|
+
"virtual:mercur/config",
|
|
764
|
+
"virtual:mercur/routes",
|
|
765
|
+
"virtual:mercur/components",
|
|
766
|
+
"virtual:mercur/menu-items",
|
|
767
|
+
"virtual:mercur/i18n"
|
|
768
|
+
],
|
|
769
|
+
include: [
|
|
770
|
+
"react",
|
|
771
|
+
"react/jsx-runtime",
|
|
772
|
+
"react-dom/client",
|
|
773
|
+
"react-router-dom",
|
|
774
|
+
"react-i18next",
|
|
775
|
+
"@medusajs/ui",
|
|
776
|
+
"@medusajs/dashboard",
|
|
777
|
+
"@medusajs/js-sdk",
|
|
778
|
+
"@tanstack/react-query"
|
|
779
|
+
]
|
|
550
780
|
}
|
|
551
781
|
};
|
|
552
782
|
},
|
|
@@ -563,24 +793,19 @@ function dashboardPlugin() {
|
|
|
563
793
|
return loadVirtualModule({ cwd: root, id, mercurConfig: config });
|
|
564
794
|
},
|
|
565
795
|
configureServer(server) {
|
|
566
|
-
const
|
|
567
|
-
if (!
|
|
796
|
+
const handleRouteChange = (file) => {
|
|
797
|
+
if (!isRouteFile(file)) return;
|
|
568
798
|
const mod = server.moduleGraph.getModuleById(RESOLVED_ROUTES_MODULE);
|
|
569
799
|
if (mod) {
|
|
570
800
|
server.moduleGraph.invalidateModule(mod);
|
|
571
801
|
server.ws.send({ type: "full-reload" });
|
|
572
802
|
}
|
|
573
803
|
};
|
|
574
|
-
server.watcher.on("add",
|
|
575
|
-
server.watcher.on("unlink",
|
|
804
|
+
server.watcher.on("add", handleRouteChange);
|
|
805
|
+
server.watcher.on("unlink", handleRouteChange);
|
|
576
806
|
},
|
|
577
807
|
handleHotUpdate({ file, server }) {
|
|
578
|
-
|
|
579
|
-
if (file === configPath) {
|
|
580
|
-
server.restart();
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
if (isPageFile(file)) {
|
|
808
|
+
if (isRouteFile(file)) {
|
|
584
809
|
const mod = server.moduleGraph.getModuleById(RESOLVED_ROUTES_MODULE);
|
|
585
810
|
if (mod) {
|
|
586
811
|
server.moduleGraph.invalidateModule(mod);
|
|
@@ -590,12 +815,71 @@ function dashboardPlugin() {
|
|
|
590
815
|
};
|
|
591
816
|
}
|
|
592
817
|
|
|
593
|
-
// src/
|
|
594
|
-
|
|
595
|
-
|
|
818
|
+
// src/generate-plugin-entry.ts
|
|
819
|
+
var import_path6 = __toESM(require("path"), 1);
|
|
820
|
+
var import_fs5 = __toESM(require("fs"), 1);
|
|
821
|
+
function findI18nIndex2(srcDir) {
|
|
822
|
+
const i18nDir = import_path6.default.join(srcDir, "i18n");
|
|
823
|
+
if (!import_fs5.default.existsSync(i18nDir)) return null;
|
|
824
|
+
for (const ext of VALID_FILE_EXTENSIONS) {
|
|
825
|
+
const filePath = import_path6.default.join(i18nDir, `index${ext}`);
|
|
826
|
+
if (import_fs5.default.existsSync(filePath)) return filePath;
|
|
827
|
+
}
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
function generatePluginEntryModule(srcDir) {
|
|
831
|
+
const routesDir = import_path6.default.join(srcDir, "routes");
|
|
832
|
+
const files = crawlRoutes(routesDir);
|
|
833
|
+
let index = 0;
|
|
834
|
+
const routeResults = [];
|
|
835
|
+
const menuItemResults = [];
|
|
836
|
+
for (const file of files) {
|
|
837
|
+
const route = parseFile(file, routesDir, index);
|
|
838
|
+
if (route) {
|
|
839
|
+
routeResults.push(route);
|
|
840
|
+
}
|
|
841
|
+
const menuItem = parseMenuItemFile(file, routesDir, index);
|
|
842
|
+
if (menuItem) {
|
|
843
|
+
menuItemResults.push(menuItem);
|
|
844
|
+
}
|
|
845
|
+
index++;
|
|
846
|
+
}
|
|
847
|
+
const routeTree = buildRouteTree(routeResults.filter(Boolean));
|
|
848
|
+
const routeImports = routeTree.flatMap((r) => r.imports);
|
|
849
|
+
const routes = routeTree.map((r) => formatRoute(r.route));
|
|
850
|
+
const menuItemImports = menuItemResults.filter(Boolean).map((r) => r.import);
|
|
851
|
+
const menuItems = menuItemResults.filter(Boolean).map((r) => formatMenuItem(r.menuItem));
|
|
852
|
+
const i18nFile = findI18nIndex2(srcDir);
|
|
853
|
+
const i18nImport = i18nFile ? `import i18nResources from "${normalizePath(i18nFile)}"` : "";
|
|
854
|
+
const i18nValue = i18nFile ? "i18nResources" : "{}";
|
|
855
|
+
const allImports = [...routeImports, ...menuItemImports];
|
|
856
|
+
if (i18nImport) allImports.push(i18nImport);
|
|
857
|
+
return `// Auto-generated plugin extensions entry
|
|
858
|
+
${allImports.join("\n")}
|
|
859
|
+
|
|
860
|
+
const routeModule = {
|
|
861
|
+
routes: [
|
|
862
|
+
${routes.join(",\n")}
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const menuItemModule = {
|
|
867
|
+
menuItems: [
|
|
868
|
+
${menuItems.join(",\n")}
|
|
869
|
+
]
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const plugin = {
|
|
873
|
+
routeModule,
|
|
874
|
+
menuItemModule,
|
|
875
|
+
i18nModule: ${i18nValue},
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
export default plugin
|
|
879
|
+
`;
|
|
596
880
|
}
|
|
597
881
|
// Annotate the CommonJS export names for ESM import in node:
|
|
598
882
|
0 && (module.exports = {
|
|
599
|
-
|
|
600
|
-
|
|
883
|
+
generatePluginEntryModule,
|
|
884
|
+
mercurDashboardPlugin
|
|
601
885
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as Vite from 'vite';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
3
|
|
|
4
|
-
declare function dashboardPlugin(): Vite.Plugin;
|
|
5
|
-
|
|
6
4
|
interface MercurConfig {
|
|
5
|
+
medusaConfigPath: string;
|
|
6
|
+
backendUrl?: string;
|
|
7
7
|
name?: string;
|
|
8
8
|
logo?: string;
|
|
9
9
|
components?: {
|
|
@@ -14,13 +14,14 @@ interface MercurConfig {
|
|
|
14
14
|
i18n?: {
|
|
15
15
|
defaultLanguage: string;
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
enableSellerRegistration?: boolean;
|
|
18
18
|
}
|
|
19
19
|
interface BuiltMercurConfig extends MercurConfig {
|
|
20
20
|
backendUrl: string;
|
|
21
|
+
base?: string;
|
|
21
22
|
root: string;
|
|
22
23
|
srcDir: string;
|
|
23
|
-
|
|
24
|
+
pluginExtensions: string[];
|
|
24
25
|
}
|
|
25
26
|
type RouteConfig = {
|
|
26
27
|
label: string;
|
|
@@ -31,6 +32,13 @@ type RouteConfig = {
|
|
|
31
32
|
public?: boolean;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
declare function
|
|
35
|
+
declare function mercurDashboardPlugin(pluginConfig: MercurConfig): Vite.Plugin;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generates a plugin entry module for a given source directory (e.g. src/vendor).
|
|
39
|
+
* Scans routes, menu items, and i18n — outputs a single module string
|
|
40
|
+
* that exports default `{ routeModule, menuItemModule, i18nModule }`.
|
|
41
|
+
*/
|
|
42
|
+
declare function generatePluginEntryModule(srcDir: string): string;
|
|
35
43
|
|
|
36
|
-
export { type BuiltMercurConfig, type MercurConfig, type RouteConfig,
|
|
44
|
+
export { type BuiltMercurConfig, type MercurConfig, type RouteConfig, generatePluginEntryModule, mercurDashboardPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercurjs/dashboard-sdk",
|
|
3
|
-
"version": "2.0.0-canary.
|
|
3
|
+
"version": "2.0.0-canary.91",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/mercurjs/mercur",
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@babel/parser": "7.25.6",
|
|
29
|
+
"@babel/traverse": "7.25.6",
|
|
30
|
+
"@babel/types": "7.25.6",
|
|
28
31
|
"esbuild-register": "^3.6.0"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|