@atlashub/smartstack-cli 4.34.0 → 4.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-entry.mjs +6 -293
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/application/templates-frontend.md +62 -93
- package/templates/skills/cli-app-sync/SKILL.md +2 -2
- package/templates/skills/cli-app-sync/references/comparison-map.md +1 -1
- package/templates/skills/documentation/steps/step-03-validate.md +12 -14
- package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +0 -126
package/dist/mcp-entry.mjs
CHANGED
|
@@ -26102,7 +26102,7 @@ var init_types3 = __esm({
|
|
|
26102
26102
|
includeLayouts: external_exports.boolean().default(true).describe("Generate layout components"),
|
|
26103
26103
|
includeGuards: external_exports.boolean().default(true).describe("Include route guards for permissions"),
|
|
26104
26104
|
generateRegistry: external_exports.boolean().default(true).describe("Generate navRoutes.generated.ts"),
|
|
26105
|
-
outputFormat: external_exports.enum(["standalone", "
|
|
26105
|
+
outputFormat: external_exports.enum(["standalone", "componentRegistry"]).default("componentRegistry").describe('Output format: "componentRegistry" (v3.7+, default) generates PageRegistry.register() calls for DynamicRouter. "standalone" generates createBrowserRouter() for non-SmartStack projects.'),
|
|
26106
26106
|
dryRun: external_exports.boolean().default(false).describe("Preview without writing files")
|
|
26107
26107
|
}).optional()
|
|
26108
26108
|
});
|
|
@@ -57901,9 +57901,6 @@ ensuring frontend routes stay synchronized with backend NavRoute attributes.`,
|
|
|
57901
57901
|
function toKebabCase(segment) {
|
|
57902
57902
|
return segment.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
57903
57903
|
}
|
|
57904
|
-
function toCamelCase2(segment) {
|
|
57905
|
-
return segment.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
57906
|
-
}
|
|
57907
57904
|
function capitalize(str) {
|
|
57908
57905
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
57909
57906
|
}
|
|
@@ -57975,16 +57972,6 @@ async function scaffoldRoutes(input, config2) {
|
|
|
57975
57972
|
result.files.push({ path: registryFile, content: registryContent, type: "created" });
|
|
57976
57973
|
}
|
|
57977
57974
|
const outputFormat = options?.outputFormat ?? "componentRegistry";
|
|
57978
|
-
if (outputFormat === "clientRoutes") {
|
|
57979
|
-
if (!result.warnings) result.warnings = [];
|
|
57980
|
-
result.warnings.push('outputFormat "clientRoutes" is DEPRECATED. Use "applicationRoutes" instead (same behavior, correct naming).');
|
|
57981
|
-
}
|
|
57982
|
-
if (outputFormat === "applicationRoutes") {
|
|
57983
|
-
if (!result.warnings) result.warnings = [];
|
|
57984
|
-
result.warnings.push(
|
|
57985
|
-
'outputFormat "applicationRoutes" is DEPRECATED (v3.7+). Use "componentRegistry" for PageRegistry + DynamicRouter pattern. See: DynamicRouter replaces manual App.tsx wiring.'
|
|
57986
|
-
);
|
|
57987
|
-
}
|
|
57988
57975
|
if (outputFormat === "componentRegistry") {
|
|
57989
57976
|
const pageFiles = await discoverPageFiles(webPath, navRoutes);
|
|
57990
57977
|
const registryContent = generateComponentRegistry(navRoutes, pageFiles, webPath);
|
|
@@ -58003,121 +57990,9 @@ async function scaffoldRoutes(input, config2) {
|
|
|
58003
57990
|
result.instructions.push("1. Ensure `main.tsx` imports `./extensions/componentRegistry.generated`");
|
|
58004
57991
|
result.instructions.push("2. Ensure navigation seed data has matching `componentKey` values");
|
|
58005
57992
|
result.instructions.push("3. DynamicRouter resolves routes automatically \u2014 no App.tsx wiring needed");
|
|
58006
|
-
}
|
|
58007
|
-
if (outputFormat === "applicationRoutes" || outputFormat === "clientRoutes") {
|
|
58008
|
-
const pageFiles = await discoverPageFiles(webPath, navRoutes);
|
|
58009
|
-
const applicationRoutesContent = generateApplicationRoutesConfig(navRoutes, pageFiles, includeGuards);
|
|
58010
|
-
const applicationRoutesFile = path19.join(routesPath, "applicationRoutes.generated.tsx");
|
|
58011
|
-
if (!dryRun) {
|
|
58012
|
-
await ensureDirectory(routesPath);
|
|
58013
|
-
await writeText(applicationRoutesFile, applicationRoutesContent);
|
|
58014
|
-
}
|
|
58015
|
-
result.files.push({ path: applicationRoutesFile, content: applicationRoutesContent, type: "created" });
|
|
58016
|
-
const routeCount = navRoutes.length * 4;
|
|
58017
|
-
result.instructions.push(`Generated ${routeCount} routes (4 CRUD per NavRoute) for ${navRoutes.length} NavRoutes in applicationRoutes format`);
|
|
58018
|
-
result.instructions.push("");
|
|
58019
|
-
result.instructions.push("## App.tsx Wiring Instructions");
|
|
58020
|
-
result.instructions.push("");
|
|
58021
|
-
result.instructions.push("**Detect App.tsx pattern first**, then follow the matching instructions:");
|
|
58022
|
-
result.instructions.push("");
|
|
58023
|
-
const routeTree = buildRouteTree(navRoutes);
|
|
58024
|
-
result.instructions.push("### Pattern A: mergeRoutes (applicationRoutes pattern)");
|
|
58025
|
-
result.instructions.push("");
|
|
58026
|
-
result.instructions.push("Routes are FLAT (no nested children) \u2014 compatible with `mergeRoutes()`.");
|
|
58027
|
-
result.instructions.push("Each NavRoute generates 4 routes: list, create, detail (:id), edit (:id/edit).");
|
|
58028
|
-
result.instructions.push("");
|
|
58029
|
-
result.instructions.push("**IMPORTANT:** Pages are lazy-loaded. Use `<Suspense fallback={<PageLoader />}>` wrapper.");
|
|
58030
|
-
result.instructions.push("");
|
|
58031
|
-
result.instructions.push("```tsx");
|
|
58032
|
-
result.instructions.push("import { lazy, Suspense } from 'react';");
|
|
58033
|
-
result.instructions.push("import { PageLoader } from '@/components/ui/PageLoader';");
|
|
58034
|
-
result.instructions.push("");
|
|
58035
|
-
const importedComponents = /* @__PURE__ */ new Set();
|
|
58036
|
-
for (const [_app, modules] of Object.entries(routeTree)) {
|
|
58037
|
-
for (const [, moduleRoutes] of Object.entries(modules)) {
|
|
58038
|
-
for (const route of moduleRoutes) {
|
|
58039
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58040
|
-
if (discovery) {
|
|
58041
|
-
for (const page of [discovery.list, discovery.create, discovery.detail, discovery.edit]) {
|
|
58042
|
-
if (page && !importedComponents.has(page.componentName)) {
|
|
58043
|
-
importedComponents.add(page.componentName);
|
|
58044
|
-
result.instructions.push(`const ${page.componentName} = lazy(() =>`);
|
|
58045
|
-
result.instructions.push(` import('${page.importPath}').then(m => ({ default: m.${page.componentName} }))`);
|
|
58046
|
-
result.instructions.push(");");
|
|
58047
|
-
}
|
|
58048
|
-
}
|
|
58049
|
-
} else {
|
|
58050
|
-
const { entityPlural, entitySingular, basePath } = deriveEntityNames(route.navRoute);
|
|
58051
|
-
for (const comp of [`${entityPlural}Page`, `${entitySingular}CreatePage`, `${entitySingular}DetailPage`, `${entitySingular}EditPage`]) {
|
|
58052
|
-
if (!importedComponents.has(comp)) {
|
|
58053
|
-
importedComponents.add(comp);
|
|
58054
|
-
result.instructions.push(`// TODO: const ${comp} = lazy(() => import('${basePath}/${comp}').then(m => ({ default: m.${comp} })));`);
|
|
58055
|
-
}
|
|
58056
|
-
}
|
|
58057
|
-
}
|
|
58058
|
-
}
|
|
58059
|
-
}
|
|
58060
|
-
}
|
|
58061
|
-
result.instructions.push("");
|
|
58062
|
-
result.instructions.push("const applicationRoutes = {");
|
|
58063
|
-
for (const [app, modules] of Object.entries(routeTree)) {
|
|
58064
|
-
result.instructions.push(` '${toKebabCase(app)}': [`);
|
|
58065
|
-
for (const [, moduleRoutes] of Object.entries(modules)) {
|
|
58066
|
-
for (const route of moduleRoutes) {
|
|
58067
|
-
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
58068
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58069
|
-
const { entityPlural, entitySingular } = deriveEntityNames(route.navRoute);
|
|
58070
|
-
const listComp = discovery?.list?.componentName || `${entityPlural}Page`;
|
|
58071
|
-
const createComp = discovery?.create?.componentName || `${entitySingular}CreatePage`;
|
|
58072
|
-
const detailComp = discovery?.detail?.componentName || `${entitySingular}DetailPage`;
|
|
58073
|
-
const editComp = discovery?.edit?.componentName || `${entitySingular}EditPage`;
|
|
58074
|
-
result.instructions.push(` // === ${entityPlural.toLowerCase()} (NavRoute: ${route.navRoute}) ===`);
|
|
58075
|
-
result.instructions.push(` { path: '${modulePath}', element: <Suspense fallback={<PageLoader />}><${listComp} /></Suspense> },`);
|
|
58076
|
-
result.instructions.push(` { path: '${modulePath}/create', element: <Suspense fallback={<PageLoader />}><${createComp} /></Suspense> },`);
|
|
58077
|
-
result.instructions.push(` { path: '${modulePath}/:id', element: <Suspense fallback={<PageLoader />}><${detailComp} /></Suspense> },`);
|
|
58078
|
-
result.instructions.push(` { path: '${modulePath}/:id/edit', element: <Suspense fallback={<PageLoader />}><${editComp} /></Suspense> },`);
|
|
58079
|
-
}
|
|
58080
|
-
}
|
|
58081
|
-
result.instructions.push(" ],");
|
|
58082
|
-
}
|
|
58083
|
-
result.instructions.push("};");
|
|
58084
|
-
result.instructions.push("```");
|
|
58085
|
-
result.instructions.push("");
|
|
58086
|
-
result.instructions.push("Routes are automatically injected into BOTH standard and tenant-prefixed trees by `mergeRoutes()`.");
|
|
58087
|
-
result.instructions.push("");
|
|
58088
|
-
result.instructions.push('### Pattern B: JSX Routes (if App.tsx uses `<Route path="/{application}" element={<{Layout} />}>`)');
|
|
58089
|
-
result.instructions.push("");
|
|
58090
|
-
result.instructions.push("Insert `<Route>` children INSIDE the appropriate Layout wrapper.");
|
|
58091
|
-
result.instructions.push("**IMPORTANT:** Use `<Suspense fallback={<PageLoader />}>` for lazy-loaded pages.");
|
|
58092
|
-
result.instructions.push("");
|
|
58093
|
-
for (const [app, modules] of Object.entries(routeTree)) {
|
|
58094
|
-
const layoutName = getLayoutName(app);
|
|
58095
|
-
result.instructions.push(`#### ${capitalize(app)} application (inside \`<Route path="/${toKebabCase(app)}" element={<${layoutName} />}>\`):`);
|
|
58096
|
-
result.instructions.push("");
|
|
58097
|
-
result.instructions.push("```tsx");
|
|
58098
|
-
for (const [, moduleRoutes] of Object.entries(modules)) {
|
|
58099
|
-
for (const route of moduleRoutes) {
|
|
58100
|
-
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
58101
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58102
|
-
const { entityPlural, entitySingular } = deriveEntityNames(route.navRoute);
|
|
58103
|
-
const listComp = discovery?.list?.componentName || `${entityPlural}Page`;
|
|
58104
|
-
const createComp = discovery?.create?.componentName || `${entitySingular}CreatePage`;
|
|
58105
|
-
const detailComp = discovery?.detail?.componentName || `${entitySingular}DetailPage`;
|
|
58106
|
-
const editComp = discovery?.edit?.componentName || `${entitySingular}EditPage`;
|
|
58107
|
-
result.instructions.push(`<Route path="${modulePath}" element={<Suspense fallback={<PageLoader />}><${listComp} /></Suspense>} />`);
|
|
58108
|
-
result.instructions.push(`<Route path="${modulePath}/create" element={<Suspense fallback={<PageLoader />}><${createComp} /></Suspense>} />`);
|
|
58109
|
-
result.instructions.push(`<Route path="${modulePath}/:id" element={<Suspense fallback={<PageLoader />}><${detailComp} /></Suspense>} />`);
|
|
58110
|
-
result.instructions.push(`<Route path="${modulePath}/:id/edit" element={<Suspense fallback={<PageLoader />}><${editComp} /></Suspense>} />`);
|
|
58111
|
-
}
|
|
58112
|
-
}
|
|
58113
|
-
result.instructions.push("```");
|
|
58114
|
-
result.instructions.push("");
|
|
58115
|
-
result.instructions.push("**IMPORTANT:** Also add the same routes inside the tenant-prefixed block (`/t/:slug/...`)");
|
|
58116
|
-
result.instructions.push("");
|
|
58117
|
-
}
|
|
58118
57993
|
} else {
|
|
58119
57994
|
if (!result.warnings) result.warnings = [];
|
|
58120
|
-
result.warnings.push("STANDALONE MODE: createBrowserRouter() is
|
|
57995
|
+
result.warnings.push("STANDALONE MODE: createBrowserRouter() is for non-SmartStack projects. SmartStack uses DynamicRouter + PageRegistry (v3.7+).");
|
|
58121
57996
|
result.warnings.push("All routes are in TODO commented state \u2014 manual activation required");
|
|
58122
57997
|
const routerContent = generateRouterConfig(navRoutes, includeGuards);
|
|
58123
57998
|
const routerFile = path19.join(routesPath, "index.tsx");
|
|
@@ -58610,164 +58485,6 @@ async function discoverPageFiles(webPath, routes) {
|
|
|
58610
58485
|
}
|
|
58611
58486
|
return pageMap;
|
|
58612
58487
|
}
|
|
58613
|
-
function generateApplicationRoutesConfig(routes, pageFiles, includeGuards) {
|
|
58614
|
-
const routeTree = buildRouteTree(routes);
|
|
58615
|
-
const lines = [
|
|
58616
|
-
"/**",
|
|
58617
|
-
" * Application Routes Configuration",
|
|
58618
|
-
" *",
|
|
58619
|
-
" * Auto-generated by SmartStack MCP - DO NOT EDIT MANUALLY",
|
|
58620
|
-
' * Run `scaffold_routes` with outputFormat: "applicationRoutes" to regenerate.',
|
|
58621
|
-
" *",
|
|
58622
|
-
" * These routes are FLAT (not nested children) \u2014 compatible with mergeRoutes().",
|
|
58623
|
-
" * Each NavRoute generates up to 4 CRUD routes: list, create, detail, edit.",
|
|
58624
|
-
" */",
|
|
58625
|
-
"",
|
|
58626
|
-
"import type { RouteObject } from 'react-router-dom';",
|
|
58627
|
-
"import type { ApplicationRouteExtensions } from '@atlashub/smartstack';",
|
|
58628
|
-
"import { lazy, Suspense } from 'react';",
|
|
58629
|
-
"import { Navigate } from 'react-router-dom';",
|
|
58630
|
-
"import { PageLoader } from '@/components/ui/PageLoader';"
|
|
58631
|
-
];
|
|
58632
|
-
if (includeGuards) {
|
|
58633
|
-
lines.push("import { ROUTES } from './navRoutes.generated';");
|
|
58634
|
-
lines.push("import { PermissionGuard } from './guards';");
|
|
58635
|
-
}
|
|
58636
|
-
lines.push("");
|
|
58637
|
-
const importedComponents = /* @__PURE__ */ new Set();
|
|
58638
|
-
for (const route of routes) {
|
|
58639
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58640
|
-
if (discovery) {
|
|
58641
|
-
for (const page of [discovery.list, discovery.create, discovery.detail, discovery.edit]) {
|
|
58642
|
-
if (page && !importedComponents.has(page.componentName)) {
|
|
58643
|
-
importedComponents.add(page.componentName);
|
|
58644
|
-
lines.push(`const ${page.componentName} = lazy(() =>`);
|
|
58645
|
-
lines.push(` import('${page.importPath}').then(m => ({ default: m.${page.componentName} }))`);
|
|
58646
|
-
lines.push(");");
|
|
58647
|
-
}
|
|
58648
|
-
}
|
|
58649
|
-
}
|
|
58650
|
-
}
|
|
58651
|
-
for (const route of routes) {
|
|
58652
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58653
|
-
const { entityPlural, entitySingular, basePath } = deriveEntityNames(route.navRoute);
|
|
58654
|
-
if (!discovery?.list && !importedComponents.has(`${entityPlural}Page`)) {
|
|
58655
|
-
importedComponents.add(`${entityPlural}Page`);
|
|
58656
|
-
lines.push(`const ${entityPlural}Page = lazy(() =>`);
|
|
58657
|
-
lines.push(` import('${basePath}/${entityPlural}Page').then(m => ({ default: m.${entityPlural}Page }))`);
|
|
58658
|
-
lines.push(");");
|
|
58659
|
-
}
|
|
58660
|
-
if (!discovery?.create && !importedComponents.has(`${entitySingular}CreatePage`)) {
|
|
58661
|
-
importedComponents.add(`${entitySingular}CreatePage`);
|
|
58662
|
-
lines.push(`const ${entitySingular}CreatePage = lazy(() =>`);
|
|
58663
|
-
lines.push(` import('${basePath}/${entitySingular}CreatePage').then(m => ({ default: m.${entitySingular}CreatePage }))`);
|
|
58664
|
-
lines.push(");");
|
|
58665
|
-
}
|
|
58666
|
-
if (!discovery?.detail && !importedComponents.has(`${entitySingular}DetailPage`)) {
|
|
58667
|
-
importedComponents.add(`${entitySingular}DetailPage`);
|
|
58668
|
-
lines.push(`const ${entitySingular}DetailPage = lazy(() =>`);
|
|
58669
|
-
lines.push(` import('${basePath}/${entitySingular}DetailPage').then(m => ({ default: m.${entitySingular}DetailPage }))`);
|
|
58670
|
-
lines.push(");");
|
|
58671
|
-
}
|
|
58672
|
-
if (!discovery?.edit && !importedComponents.has(`${entitySingular}EditPage`)) {
|
|
58673
|
-
importedComponents.add(`${entitySingular}EditPage`);
|
|
58674
|
-
lines.push(`const ${entitySingular}EditPage = lazy(() =>`);
|
|
58675
|
-
lines.push(` import('${basePath}/${entitySingular}EditPage').then(m => ({ default: m.${entitySingular}EditPage }))`);
|
|
58676
|
-
lines.push(");");
|
|
58677
|
-
}
|
|
58678
|
-
}
|
|
58679
|
-
lines.push("");
|
|
58680
|
-
for (const [app, modules] of Object.entries(routeTree)) {
|
|
58681
|
-
const appCamel = toCamelCase2(app);
|
|
58682
|
-
const appKebab = toKebabCase(app);
|
|
58683
|
-
const appUpper = capitalize(appCamel);
|
|
58684
|
-
const layoutName = getLayoutName(app);
|
|
58685
|
-
lines.push("/**");
|
|
58686
|
-
lines.push(` * Routes for ${appUpper} application`);
|
|
58687
|
-
lines.push(` * Flat routes for mergeRoutes() \u2014 children of <Route path="/${appKebab}" element={<${layoutName} />}>`);
|
|
58688
|
-
lines.push(" */");
|
|
58689
|
-
lines.push(`export const ${appCamel}Routes: RouteObject[] = [`);
|
|
58690
|
-
for (const [, moduleRoutes] of Object.entries(modules)) {
|
|
58691
|
-
for (const route of moduleRoutes) {
|
|
58692
|
-
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
58693
|
-
const discovery = pageFiles.get(route.navRoute);
|
|
58694
|
-
const { entityPlural, entitySingular } = deriveEntityNames(route.navRoute);
|
|
58695
|
-
const permGuardOpen = includeGuards && route.permissions.length > 0 ? `<PermissionGuard permissions={ROUTES['${route.navRoute}'].permissions}>` : "";
|
|
58696
|
-
const permGuardClose = permGuardOpen ? "</PermissionGuard>" : "";
|
|
58697
|
-
lines.push(` // === ${entityPlural.toLowerCase()} (NavRoute: ${route.navRoute}) ===`);
|
|
58698
|
-
const listComp = discovery?.list?.componentName || `${entityPlural}Page`;
|
|
58699
|
-
const listElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${listComp} />${permGuardClose}</Suspense>`;
|
|
58700
|
-
lines.push(` { path: '${modulePath}', element: ${listElement} },`);
|
|
58701
|
-
const createComp = discovery?.create?.componentName || `${entitySingular}CreatePage`;
|
|
58702
|
-
const createElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${createComp} />${permGuardClose}</Suspense>`;
|
|
58703
|
-
lines.push(` { path: '${modulePath}/create', element: ${createElement} },`);
|
|
58704
|
-
const detailComp = discovery?.detail?.componentName || `${entitySingular}DetailPage`;
|
|
58705
|
-
const detailElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${detailComp} />${permGuardClose}</Suspense>`;
|
|
58706
|
-
lines.push(` { path: '${modulePath}/:id', element: ${detailElement} },`);
|
|
58707
|
-
const editComp = discovery?.edit?.componentName || `${entitySingular}EditPage`;
|
|
58708
|
-
const editElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${editComp} />${permGuardClose}</Suspense>`;
|
|
58709
|
-
lines.push(` { path: '${modulePath}/:id/edit', element: ${editElement} },`);
|
|
58710
|
-
}
|
|
58711
|
-
}
|
|
58712
|
-
lines.push("");
|
|
58713
|
-
lines.push(" // --- Parent redirect routes ---");
|
|
58714
|
-
let appFirstPath;
|
|
58715
|
-
const moduleRedirects = /* @__PURE__ */ new Map();
|
|
58716
|
-
for (const [moduleName, modRoutes] of Object.entries(modules)) {
|
|
58717
|
-
if (modRoutes.length > 0) {
|
|
58718
|
-
const firstRoute = modRoutes[0];
|
|
58719
|
-
const segments = firstRoute.navRoute.split(".").slice(1).map(toKebabCase);
|
|
58720
|
-
const firstFullPath = segments.join("/");
|
|
58721
|
-
const moduleKebab = toKebabCase(moduleName);
|
|
58722
|
-
if (!appFirstPath) {
|
|
58723
|
-
appFirstPath = firstFullPath;
|
|
58724
|
-
}
|
|
58725
|
-
if (segments.length > 1 && !moduleRedirects.has(moduleKebab)) {
|
|
58726
|
-
moduleRedirects.set(moduleKebab, firstFullPath);
|
|
58727
|
-
}
|
|
58728
|
-
}
|
|
58729
|
-
}
|
|
58730
|
-
for (const [modulePath, targetPath] of moduleRedirects) {
|
|
58731
|
-
lines.push(` { path: '${modulePath}', element: <Navigate to="${targetPath}" replace /> },`);
|
|
58732
|
-
}
|
|
58733
|
-
if (appFirstPath) {
|
|
58734
|
-
lines.push(` { path: '', element: <Navigate to="${appFirstPath}" replace /> },`);
|
|
58735
|
-
}
|
|
58736
|
-
lines.push("];");
|
|
58737
|
-
lines.push("");
|
|
58738
|
-
}
|
|
58739
|
-
const appKeys = Object.keys(routeTree);
|
|
58740
|
-
lines.push("/** All generated routes grouped by application */");
|
|
58741
|
-
lines.push("export const generatedRoutes: Record<string, RouteObject[]> = {");
|
|
58742
|
-
for (const app of appKeys) {
|
|
58743
|
-
const appCamel = toCamelCase2(app);
|
|
58744
|
-
const appKebab = toKebabCase(app);
|
|
58745
|
-
lines.push(` '${appKebab}': ${appCamel}Routes,`);
|
|
58746
|
-
}
|
|
58747
|
-
lines.push("};");
|
|
58748
|
-
lines.push("");
|
|
58749
|
-
lines.push("/**");
|
|
58750
|
-
lines.push(" * Application route extensions for mergeRoutes() pattern.");
|
|
58751
|
-
lines.push(" * Import and spread into your App.tsx applicationRoutes:");
|
|
58752
|
-
lines.push(" *");
|
|
58753
|
-
lines.push(" * ```tsx");
|
|
58754
|
-
lines.push(" * import { applicationRouteExtensions } from './routes/applicationRoutes.generated';");
|
|
58755
|
-
lines.push(" * const applicationRoutes = {");
|
|
58756
|
-
lines.push(" * ...applicationRouteExtensions,");
|
|
58757
|
-
lines.push(" * // your additional routes...");
|
|
58758
|
-
lines.push(" * };");
|
|
58759
|
-
lines.push(" * ```");
|
|
58760
|
-
lines.push(" */");
|
|
58761
|
-
lines.push("export const applicationRouteExtensions: Record<string, RouteObject[]> = {");
|
|
58762
|
-
for (const app of appKeys) {
|
|
58763
|
-
const appCamel = toCamelCase2(app);
|
|
58764
|
-
const appKebab = toKebabCase(app);
|
|
58765
|
-
lines.push(` '${appKebab}': ${appCamel}Routes,`);
|
|
58766
|
-
}
|
|
58767
|
-
lines.push("};");
|
|
58768
|
-
lines.push("");
|
|
58769
|
-
return lines.join("\n");
|
|
58770
|
-
}
|
|
58771
58488
|
function generateComponentRegistry(navRoutes, pageFiles, _webPath) {
|
|
58772
58489
|
const lines = [];
|
|
58773
58490
|
lines.push("/**");
|
|
@@ -58803,9 +58520,6 @@ function generateComponentRegistry(navRoutes, pageFiles, _webPath) {
|
|
|
58803
58520
|
}
|
|
58804
58521
|
return lines.join("\n");
|
|
58805
58522
|
}
|
|
58806
|
-
function getLayoutName(_application) {
|
|
58807
|
-
return "AppLayout";
|
|
58808
|
-
}
|
|
58809
58523
|
function deriveEntityNames(navRoute) {
|
|
58810
58524
|
const parts = navRoute.split(".");
|
|
58811
58525
|
const lastSegment = parts[parts.length - 1];
|
|
@@ -58911,7 +58625,7 @@ and generates corresponding frontend routing infrastructure.`,
|
|
|
58911
58625
|
includeLayouts: { type: "boolean", default: true },
|
|
58912
58626
|
includeGuards: { type: "boolean", default: true },
|
|
58913
58627
|
generateRegistry: { type: "boolean", default: true },
|
|
58914
|
-
outputFormat: { type: "string", enum: ["standalone", "
|
|
58628
|
+
outputFormat: { type: "string", enum: ["standalone", "componentRegistry"], default: "componentRegistry", description: "componentRegistry (v3.7+, default): PageRegistry.register() calls for DynamicRouter. standalone: createBrowserRouter() for non-SmartStack projects." },
|
|
58915
58629
|
dryRun: { type: "boolean", default: false }
|
|
58916
58630
|
}
|
|
58917
58631
|
}
|
|
@@ -59149,7 +58863,7 @@ async function validateApiClients(webPath, backendRoutes, result) {
|
|
|
59149
58863
|
}
|
|
59150
58864
|
}
|
|
59151
58865
|
async function validateRoutes(webPath, backendRoutes, result) {
|
|
59152
|
-
const routeCandidates = ["
|
|
58866
|
+
const routeCandidates = ["index.tsx"];
|
|
59153
58867
|
let routesContent = "";
|
|
59154
58868
|
for (const candidate of routeCandidates) {
|
|
59155
58869
|
const candidatePath = path20.join(webPath, "src", "routes", candidate);
|
|
@@ -59246,10 +58960,9 @@ async function validateAppWiring(webPath, backendRoutes, result) {
|
|
|
59246
58960
|
);
|
|
59247
58961
|
return;
|
|
59248
58962
|
}
|
|
59249
|
-
const hasApplicationRoutesImport = appContent.includes("applicationRoutes.generated") || appContent.includes("clientRoutes.generated");
|
|
59250
58963
|
const hasRoutesImport = appContent.includes("from './routes") || appContent.includes("from '../routes");
|
|
59251
58964
|
const hasInlineRoutes = appContent.includes("<Route ");
|
|
59252
|
-
result.appWiring.routesImported =
|
|
58965
|
+
result.appWiring.routesImported = hasRoutesImport || hasInlineRoutes;
|
|
59253
58966
|
const hasDynamicRouter = appContent.includes("DynamicRouter") || appContent.includes("<DynamicRouter");
|
|
59254
58967
|
const hasComponentRegistry = appContent.includes("componentRegistry.generated");
|
|
59255
58968
|
if (hasDynamicRouter || hasComponentRegistry) {
|
|
@@ -59291,7 +59004,7 @@ async function validateAppWiring(webPath, backendRoutes, result) {
|
|
|
59291
59004
|
}
|
|
59292
59005
|
}
|
|
59293
59006
|
async function validateCrudRoutes(webPath, backendRoutes, result) {
|
|
59294
|
-
const routeCandidates = ["
|
|
59007
|
+
const routeCandidates = ["index.tsx"];
|
|
59295
59008
|
let routesContent = "";
|
|
59296
59009
|
for (const candidate of routeCandidates) {
|
|
59297
59010
|
const candidatePath = path20.join(webPath, "src", "routes", candidate);
|