@specverse/engines 4.1.28 → 4.2.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/assets/examples/manifests/frontend-only.yaml +3 -6
- package/assets/examples/manifests/fullstack-app.yaml +5 -7
- package/assets/examples/manifests/fullstack-monorepo.yaml +3 -6
- package/dist/inference/comprehensive-engine.d.ts.map +1 -1
- package/dist/inference/comprehensive-engine.js +3 -19
- package/dist/inference/comprehensive-engine.js.map +1 -1
- package/dist/inference/core/rule-engine.d.ts +31 -0
- package/dist/inference/core/rule-engine.d.ts.map +1 -1
- package/dist/inference/core/rule-engine.js +117 -33
- package/dist/inference/core/rule-engine.js.map +1 -1
- package/dist/inference/core/rule-file-types.d.ts +0 -2
- package/dist/inference/core/rule-file-types.d.ts.map +1 -1
- package/dist/inference/core/rule-file-types.js +3 -6
- package/dist/inference/core/rule-file-types.js.map +1 -1
- package/dist/inference/core/rule-loader.d.ts +5 -15
- package/dist/inference/core/rule-loader.d.ts.map +1 -1
- package/dist/inference/core/rule-loader.js +43 -132
- package/dist/inference/core/rule-loader.js.map +1 -1
- package/dist/inference/core/types.d.ts +0 -6
- package/dist/inference/core/types.d.ts.map +1 -1
- package/dist/inference/core/types.js +0 -4
- package/dist/inference/core/types.js.map +1 -1
- package/dist/inference/logical/generators/component-type-resolver.d.ts +0 -26
- package/dist/inference/logical/generators/component-type-resolver.d.ts.map +1 -1
- package/dist/inference/logical/generators/component-type-resolver.js +0 -19
- package/dist/inference/logical/generators/component-type-resolver.js.map +1 -1
- package/dist/inference/logical/generators/specialist-view-expander.d.ts +1 -17
- package/dist/inference/logical/generators/specialist-view-expander.d.ts.map +1 -1
- package/dist/inference/logical/generators/specialist-view-expander.js +0 -15
- package/dist/inference/logical/generators/specialist-view-expander.js.map +1 -1
- package/dist/inference/logical/generators/view-generator.d.ts +4 -14
- package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
- package/dist/inference/logical/generators/view-generator.js +6 -26
- package/dist/inference/logical/generators/view-generator.js.map +1 -1
- package/dist/inference/logical/index.d.ts +2 -2
- package/dist/inference/logical/index.d.ts.map +1 -1
- package/dist/inference/logical/logical-engine.d.ts.map +1 -1
- package/dist/inference/logical/logical-engine.js +17 -80
- package/dist/inference/logical/logical-engine.js.map +1 -1
- package/dist/inference/quint-transpiler.d.ts +5 -3
- package/dist/inference/quint-transpiler.d.ts.map +1 -1
- package/dist/inference/quint-transpiler.js +11 -6
- package/dist/inference/quint-transpiler.js.map +1 -1
- package/dist/libs/instance-factories/applications/templates/generic/main-generator.js +3 -3
- package/dist/libs/instance-factories/applications/templates/react/api-client-generator.js +16 -6
- package/dist/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.js +110 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.js +121 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/detail-body-composer.js +78 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/form-body-composer.js +190 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/helpers-emitter.js +45 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/html-to-jsx.js +192 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/list-body-composer.js +46 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/orchestrator.js +30 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/package-json-generator.js +38 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/regen-safety.js +89 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/view-emitter.js +56 -0
- package/dist/libs/instance-factories/applications/templates/react-starter/views-generator.js +66 -0
- package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +14 -11
- package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +11 -3
- package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +27 -17
- package/dist/libs/instance-factories/shared/path-resolver.js +1 -1
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +15 -22
- package/dist/realize/index.js.map +1 -1
- package/dist/registry/utils/manifest-adapter.d.ts +8 -1
- package/dist/registry/utils/manifest-adapter.d.ts.map +1 -1
- package/dist/registry/utils/manifest-adapter.js +8 -1
- package/dist/registry/utils/manifest-adapter.js.map +1 -1
- package/libs/instance-factories/applications/react-app-starter.yaml +150 -0
- package/libs/instance-factories/applications/templates/generic/main-generator.ts +3 -3
- package/libs/instance-factories/applications/templates/react/api-client-generator.ts +16 -6
- package/libs/instance-factories/applications/templates/react-starter/README.md +211 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/dashboard-body-composer.test.ts +153 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/detail-body-composer.test.ts +145 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/form-body-composer.test.ts +175 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/helpers-emitter.test.ts +55 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/html-to-jsx.test.ts +140 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/list-body-composer.test.ts +146 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/orchestrator.test.ts +163 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p2-factory-imports.test.ts +116 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/parity-p3-rendered-output.test.ts +183 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/regen-safety.test.ts +144 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/starter-generators.test.ts +114 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/view-emitter.test.ts +107 -0
- package/libs/instance-factories/applications/templates/react-starter/__tests__/views-generator.test.ts +139 -0
- package/libs/instance-factories/applications/templates/react-starter/app-tsx-generator.ts +141 -0
- package/libs/instance-factories/applications/templates/react-starter/dashboard-body-composer.ts +174 -0
- package/libs/instance-factories/applications/templates/react-starter/detail-body-composer.ts +135 -0
- package/libs/instance-factories/applications/templates/react-starter/form-body-composer.ts +306 -0
- package/libs/instance-factories/applications/templates/react-starter/helpers-emitter.ts +60 -0
- package/libs/instance-factories/applications/templates/react-starter/html-to-jsx.ts +334 -0
- package/libs/instance-factories/applications/templates/react-starter/list-body-composer.ts +120 -0
- package/libs/instance-factories/applications/templates/react-starter/orchestrator.ts +80 -0
- package/libs/instance-factories/applications/templates/react-starter/package-json-generator.ts +57 -0
- package/libs/instance-factories/applications/templates/react-starter/regen-safety.ts +157 -0
- package/libs/instance-factories/applications/templates/react-starter/skeletons/dashboard.tsx.template +47 -0
- package/libs/instance-factories/applications/templates/react-starter/skeletons/detail.tsx.template +94 -0
- package/libs/instance-factories/applications/templates/react-starter/skeletons/form.tsx.template +114 -0
- package/libs/instance-factories/applications/templates/react-starter/skeletons/list.tsx.template +72 -0
- package/libs/instance-factories/applications/templates/react-starter/view-emitter.ts +151 -0
- package/libs/instance-factories/applications/templates/react-starter/views-generator.ts +137 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.ts +14 -11
- package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +11 -3
- package/libs/instance-factories/services/templates/prisma/controller-generator.ts +27 -17
- package/libs/instance-factories/shared/path-resolver.ts +8 -2
- package/package.json +3 -3
- package/dist/libs/instance-factories/applications/templates/react/_view-components-source.js +0 -530
- package/dist/libs/instance-factories/applications/templates/react/app-tsx-generator.js +0 -73
- package/dist/libs/instance-factories/applications/templates/react/field-helpers-generator.js +0 -99
- package/dist/libs/instance-factories/applications/templates/react/package-json-generator.js +0 -49
- package/dist/libs/instance-factories/applications/templates/react/pattern-adapter-generator.js +0 -156
- package/dist/libs/instance-factories/applications/templates/react/react-pattern-adapter.js +0 -935
- package/dist/libs/instance-factories/applications/templates/react/relationship-field-generator.js +0 -143
- package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.js +0 -646
- package/dist/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.js +0 -65
- package/dist/libs/instance-factories/applications/templates/react/view-dashboard-generator.js +0 -143
- package/dist/libs/instance-factories/applications/templates/react/view-detail-generator.js +0 -143
- package/dist/libs/instance-factories/applications/templates/react/view-form-generator.js +0 -355
- package/dist/libs/instance-factories/applications/templates/react/view-list-generator.js +0 -91
- package/dist/libs/instance-factories/applications/templates/react/view-router-generator.js +0 -79
- package/dist/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.js.bak +0 -244
- package/dist/libs/instance-factories/views/index.js +0 -48
- package/dist/libs/instance-factories/views/templates/react/adapters/antd-adapter.js +0 -742
- package/dist/libs/instance-factories/views/templates/react/adapters/mui-adapter.js +0 -824
- package/dist/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.js +0 -719
- package/dist/libs/instance-factories/views/templates/react/app-generator.js +0 -45
- package/dist/libs/instance-factories/views/templates/react/components-generator.js +0 -820
- package/dist/libs/instance-factories/views/templates/react/forms-generator.js +0 -275
- package/dist/libs/instance-factories/views/templates/react/frontend-package-json-generator.js +0 -46
- package/dist/libs/instance-factories/views/templates/react/hooks-generator.js +0 -81
- package/dist/libs/instance-factories/views/templates/react/index-css-generator.js +0 -9
- package/dist/libs/instance-factories/views/templates/react/index-html-generator.js +0 -23
- package/dist/libs/instance-factories/views/templates/react/main-tsx-generator.js +0 -21
- package/dist/libs/instance-factories/views/templates/react/react-component-generator.js +0 -299
- package/dist/libs/instance-factories/views/templates/react/router-generator.js +0 -136
- package/dist/libs/instance-factories/views/templates/react/router-generic-generator.js +0 -107
- package/dist/libs/instance-factories/views/templates/react/shared-utils-generator.js +0 -187
- package/dist/libs/instance-factories/views/templates/react/spec-json-generator.js +0 -7
- package/dist/libs/instance-factories/views/templates/react/types-generator.js +0 -56
- package/dist/libs/instance-factories/views/templates/react/views-metadata-generator.js +0 -27
- package/dist/libs/instance-factories/views/templates/react/vite-config-generator.js +0 -29
- package/dist/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js +0 -261
- package/dist/libs/instance-factories/views/templates/shared/adapter-types.js +0 -34
- package/dist/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -800
- package/dist/libs/instance-factories/views/templates/shared/base-generator.js +0 -305
- package/dist/libs/instance-factories/views/templates/shared/component-metadata.js +0 -517
- package/dist/libs/instance-factories/views/templates/shared/composite-pattern-types.js +0 -0
- package/dist/libs/instance-factories/views/templates/shared/composite-patterns.js +0 -445
- package/dist/libs/instance-factories/views/templates/shared/index.js +0 -80
- package/dist/libs/instance-factories/views/templates/shared/pattern-validator.js +0 -210
- package/dist/libs/instance-factories/views/templates/shared/property-mapper.js +0 -492
- package/dist/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -321
- package/dist/realize/index.js.bak +0 -758
- package/libs/instance-factories/applications/react-app.yaml +0 -186
- package/libs/instance-factories/applications/templates/react/_view-components-source.ts +0 -555
- package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +0 -94
- package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +0 -106
- package/libs/instance-factories/applications/templates/react/package-json-generator.ts +0 -57
- package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +0 -179
- package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +0 -1347
- package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +0 -150
- package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +0 -704
- package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +0 -84
- package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +0 -150
- package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +0 -150
- package/libs/instance-factories/applications/templates/react/view-form-generator.ts +0 -362
- package/libs/instance-factories/applications/templates/react/view-list-generator.ts +0 -98
- package/libs/instance-factories/applications/templates/react/view-router-generator.ts +0 -89
- package/libs/instance-factories/views/README.md +0 -62
- package/libs/instance-factories/views/index.d.ts +0 -13
- package/libs/instance-factories/views/index.d.ts.map +0 -1
- package/libs/instance-factories/views/index.js +0 -18
- package/libs/instance-factories/views/index.js.map +0 -1
- package/libs/instance-factories/views/index.ts +0 -45
- package/libs/instance-factories/views/react-components.yaml +0 -129
- package/libs/instance-factories/views/templates/ARCHITECTURE.md +0 -198
- package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +0 -869
- package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +0 -953
- package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +0 -806
- package/libs/instance-factories/views/templates/react/app-generator.ts +0 -55
- package/libs/instance-factories/views/templates/react/components-generator.ts +0 -938
- package/libs/instance-factories/views/templates/react/forms-generator.ts +0 -325
- package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +0 -57
- package/libs/instance-factories/views/templates/react/hooks-generator.ts +0 -106
- package/libs/instance-factories/views/templates/react/index-css-generator.ts +0 -14
- package/libs/instance-factories/views/templates/react/index-html-generator.ts +0 -34
- package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +0 -29
- package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +0 -152
- package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/react/react-component-generator.js +0 -398
- package/libs/instance-factories/views/templates/react/react-component-generator.js.map +0 -1
- package/libs/instance-factories/views/templates/react/react-component-generator.ts +0 -533
- package/libs/instance-factories/views/templates/react/router-generator.ts +0 -197
- package/libs/instance-factories/views/templates/react/router-generic-generator.ts +0 -132
- package/libs/instance-factories/views/templates/react/shared-utils-generator.ts +0 -196
- package/libs/instance-factories/views/templates/react/spec-json-generator.ts +0 -17
- package/libs/instance-factories/views/templates/react/types-generator.ts +0 -76
- package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +0 -42
- package/libs/instance-factories/views/templates/react/vite-config-generator.ts +0 -38
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +0 -1
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +0 -474
- package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +0 -242
- package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +0 -77
- package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/adapter-types.js +0 -47
- package/libs/instance-factories/views/templates/shared/adapter-types.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/adapter-types.ts +0 -142
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +0 -63
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +0 -822
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +0 -908
- package/libs/instance-factories/views/templates/shared/base-generator.d.ts +0 -247
- package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/base-generator.js +0 -363
- package/libs/instance-factories/views/templates/shared/base-generator.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/base-generator.ts +0 -608
- package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +0 -254
- package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/component-metadata.js +0 -602
- package/libs/instance-factories/views/templates/shared/component-metadata.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/component-metadata.ts +0 -803
- package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +0 -250
- package/libs/instance-factories/views/templates/shared/composite-patterns.ts +0 -535
- package/libs/instance-factories/views/templates/shared/index.ts +0 -68
- package/libs/instance-factories/views/templates/shared/pattern-validator.ts +0 -279
- package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +0 -149
- package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/property-mapper.js +0 -580
- package/libs/instance-factories/views/templates/shared/property-mapper.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/property-mapper.ts +0 -700
- package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +0 -143
- package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +0 -1
- package/libs/instance-factories/views/templates/shared/syntax-mapper.js +0 -420
- package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +0 -1
- package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +0 -539
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Router Setup Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates router.tsx with routes based on spec views
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { TemplateContext } from '@specverse/types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate router.tsx with React Router v6 setup
|
|
11
|
-
*/
|
|
12
|
-
export default function generateRouter(context: TemplateContext): string {
|
|
13
|
-
const { spec, models = [], views = [] } = context;
|
|
14
|
-
|
|
15
|
-
// Extract views from spec if not provided
|
|
16
|
-
const specViews = views.length > 0 ? views : (spec?.views ? Object.entries(spec.views) : []);
|
|
17
|
-
|
|
18
|
-
// Generate imports
|
|
19
|
-
const imports: string[] = [];
|
|
20
|
-
const routes: string[] = [];
|
|
21
|
-
|
|
22
|
-
// Add home route
|
|
23
|
-
routes.push(` {
|
|
24
|
-
path: '/',
|
|
25
|
-
element: <div className="home-page">
|
|
26
|
-
<h1>Welcome</h1>
|
|
27
|
-
<nav>
|
|
28
|
-
<ul>
|
|
29
|
-
${generateHomeLinks(specViews, models)}
|
|
30
|
-
</ul>
|
|
31
|
-
</nav>
|
|
32
|
-
</div>
|
|
33
|
-
}`);
|
|
34
|
-
|
|
35
|
-
// Track used paths to ensure uniqueness
|
|
36
|
-
const usedPaths = new Set<string>();
|
|
37
|
-
|
|
38
|
-
// Generate routes for each view
|
|
39
|
-
specViews.forEach((viewEntry: any) => {
|
|
40
|
-
const [viewName, viewDef] = Array.isArray(viewEntry) ? viewEntry : [viewEntry.name, viewEntry];
|
|
41
|
-
|
|
42
|
-
// Determine route pattern based on view type
|
|
43
|
-
const viewType = viewDef?.type || 'list';
|
|
44
|
-
const model = Array.isArray(viewDef?.model) ? viewDef.model[0] : viewDef?.model;
|
|
45
|
-
|
|
46
|
-
if (!model) return;
|
|
47
|
-
|
|
48
|
-
const modelLower = model.toLowerCase();
|
|
49
|
-
const modelPlural = modelLower + 's'; // Simple pluralization
|
|
50
|
-
|
|
51
|
-
imports.push(`import ${viewName} from './components/${viewName}';`);
|
|
52
|
-
|
|
53
|
-
// Generate unique path based on view name and type
|
|
54
|
-
const basePath = `/${modelPlural}`;
|
|
55
|
-
|
|
56
|
-
switch (viewType) {
|
|
57
|
-
case 'list':
|
|
58
|
-
// Use view name to create unique path if multiple list views
|
|
59
|
-
const listPath = usedPaths.has(basePath)
|
|
60
|
-
? `${basePath}/${viewName.toLowerCase().replace(/view$/, '')}`
|
|
61
|
-
: basePath;
|
|
62
|
-
|
|
63
|
-
if (!usedPaths.has(listPath)) {
|
|
64
|
-
routes.push(` {
|
|
65
|
-
path: '${listPath}',
|
|
66
|
-
element: <${viewName} />
|
|
67
|
-
}`);
|
|
68
|
-
usedPaths.add(listPath);
|
|
69
|
-
}
|
|
70
|
-
break;
|
|
71
|
-
|
|
72
|
-
case 'detail':
|
|
73
|
-
const detailPath = `${basePath}/:id`;
|
|
74
|
-
if (!usedPaths.has(detailPath)) {
|
|
75
|
-
routes.push(` {
|
|
76
|
-
path: '${detailPath}',
|
|
77
|
-
element: <${viewName} />
|
|
78
|
-
}`);
|
|
79
|
-
usedPaths.add(detailPath);
|
|
80
|
-
}
|
|
81
|
-
break;
|
|
82
|
-
|
|
83
|
-
case 'form':
|
|
84
|
-
const newPath = `${basePath}/new`;
|
|
85
|
-
const editPath = `${basePath}/:id/edit`;
|
|
86
|
-
|
|
87
|
-
if (!usedPaths.has(newPath)) {
|
|
88
|
-
routes.push(` {
|
|
89
|
-
path: '${newPath}',
|
|
90
|
-
element: <${viewName} />
|
|
91
|
-
}`);
|
|
92
|
-
usedPaths.add(newPath);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (!usedPaths.has(editPath)) {
|
|
96
|
-
routes.push(` {
|
|
97
|
-
path: '${editPath}',
|
|
98
|
-
element: <${viewName} />
|
|
99
|
-
}`);
|
|
100
|
-
usedPaths.add(editPath);
|
|
101
|
-
}
|
|
102
|
-
break;
|
|
103
|
-
|
|
104
|
-
case 'dashboard':
|
|
105
|
-
// Use model name in dashboard path for uniqueness
|
|
106
|
-
const dashPath = modelLower === 'author' || modelLower === 'user'
|
|
107
|
-
? '/dashboard'
|
|
108
|
-
: `/dashboard/${modelLower}`;
|
|
109
|
-
|
|
110
|
-
if (!usedPaths.has(dashPath)) {
|
|
111
|
-
routes.push(` {
|
|
112
|
-
path: '${dashPath}',
|
|
113
|
-
element: <${viewName} />
|
|
114
|
-
}`);
|
|
115
|
-
usedPaths.add(dashPath);
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
return `/**
|
|
122
|
-
* React Router Configuration
|
|
123
|
-
* Auto-generated by SpecVerse
|
|
124
|
-
*/
|
|
125
|
-
|
|
126
|
-
import { createBrowserRouter } from 'react-router-dom';
|
|
127
|
-
${imports.join('\n')}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Application Router
|
|
131
|
-
*/
|
|
132
|
-
export const router = createBrowserRouter([
|
|
133
|
-
${routes.join(',\n')}
|
|
134
|
-
]);
|
|
135
|
-
`;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Generate navigation links for home page
|
|
140
|
-
*/
|
|
141
|
-
function generateHomeLinks(views: any[], models: any[]): string {
|
|
142
|
-
const links: string[] = [];
|
|
143
|
-
const usedPaths = new Set<string>();
|
|
144
|
-
|
|
145
|
-
views.forEach((viewEntry: any) => {
|
|
146
|
-
const [viewName, viewDef] = Array.isArray(viewEntry) ? viewEntry : [viewEntry.name, viewEntry];
|
|
147
|
-
const viewType = viewDef?.type || 'list';
|
|
148
|
-
const model = Array.isArray(viewDef?.model) ? viewDef.model[0] : viewDef?.model;
|
|
149
|
-
|
|
150
|
-
if (!model) return;
|
|
151
|
-
|
|
152
|
-
const modelLower = model.toLowerCase();
|
|
153
|
-
const modelPlural = modelLower + 's';
|
|
154
|
-
const basePath = `/${modelPlural}`;
|
|
155
|
-
|
|
156
|
-
// Generate descriptive label from view name
|
|
157
|
-
const viewLabel = viewName.replace(/View$/, '').replace(/([A-Z])/g, ' $1').trim();
|
|
158
|
-
|
|
159
|
-
switch (viewType) {
|
|
160
|
-
case 'list':
|
|
161
|
-
const listPath = usedPaths.has(basePath)
|
|
162
|
-
? `${basePath}/${viewName.toLowerCase().replace(/view$/, '')}`
|
|
163
|
-
: basePath;
|
|
164
|
-
|
|
165
|
-
if (!usedPaths.has(listPath)) {
|
|
166
|
-
links.push(` <li><a href="${listPath}">${viewLabel}</a></li>`);
|
|
167
|
-
usedPaths.add(listPath);
|
|
168
|
-
}
|
|
169
|
-
break;
|
|
170
|
-
|
|
171
|
-
case 'form':
|
|
172
|
-
const formPath = `${basePath}/new`;
|
|
173
|
-
if (!usedPaths.has(formPath)) {
|
|
174
|
-
links.push(` <li><a href="${formPath}">Create ${model}</a></li>`);
|
|
175
|
-
usedPaths.add(formPath);
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
|
|
179
|
-
case 'dashboard':
|
|
180
|
-
const dashPath = modelLower === 'author' || modelLower === 'user'
|
|
181
|
-
? '/dashboard'
|
|
182
|
-
: `/dashboard/${modelLower}`;
|
|
183
|
-
|
|
184
|
-
if (!usedPaths.has(dashPath)) {
|
|
185
|
-
links.push(` <li><a href="${dashPath}">${viewLabel}</a></li>`);
|
|
186
|
-
usedPaths.add(dashPath);
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
|
|
190
|
-
case 'detail':
|
|
191
|
-
// Don't add detail views to home links (they require IDs)
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
return links.join('\n');
|
|
197
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Router Generator (App Shell)
|
|
3
|
-
*
|
|
4
|
-
* Generates App.tsx with app-demo-quality navigation and routing.
|
|
5
|
-
* Matches app-demo's visual patterns: sidebar, active states, model grouping,
|
|
6
|
-
* specialist view links.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { TemplateContext } from '@specverse/types';
|
|
10
|
-
|
|
11
|
-
export default function generateRouter(context: TemplateContext): string {
|
|
12
|
-
const { spec, models = [], views = [] } = context;
|
|
13
|
-
|
|
14
|
-
const specViews = views.length > 0 ? views : (spec?.views || []);
|
|
15
|
-
const viewsArray = Array.isArray(specViews) ? specViews : Object.values(specViews);
|
|
16
|
-
|
|
17
|
-
// Collect view info grouped by model
|
|
18
|
-
const modelViews = new Map<string, Array<{ name: string; type: string; path: string }>>();
|
|
19
|
-
const viewImports: string[] = [];
|
|
20
|
-
const routeEntries: string[] = [];
|
|
21
|
-
|
|
22
|
-
viewsArray.forEach((viewDef: any) => {
|
|
23
|
-
const viewName = viewDef.name;
|
|
24
|
-
if (!viewName) return;
|
|
25
|
-
const model = Array.isArray(viewDef.model) ? viewDef.model[0] : viewDef.model;
|
|
26
|
-
if (!model) return;
|
|
27
|
-
|
|
28
|
-
const viewType = viewDef.type || 'list';
|
|
29
|
-
const modelLower = model.toLowerCase();
|
|
30
|
-
const path = `/${modelLower}${viewType}`;
|
|
31
|
-
|
|
32
|
-
viewImports.push(`import ${viewName} from './components/${viewName}';`);
|
|
33
|
-
routeEntries.push(` <Route path="${path}" element={<${viewName} />} />`);
|
|
34
|
-
|
|
35
|
-
if (!modelViews.has(model)) modelViews.set(model, []);
|
|
36
|
-
modelViews.get(model)!.push({ name: viewName, type: viewType, path });
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Get app name from spec
|
|
40
|
-
const appName = spec?.componentName || spec?.metadata?.component || spec?.name || 'App';
|
|
41
|
-
|
|
42
|
-
// Build sidebar sections per model
|
|
43
|
-
const sidebarSections = Array.from(modelViews.entries()).map(([model, views]) => {
|
|
44
|
-
const lower = model.toLowerCase();
|
|
45
|
-
const listView = views.find(v => v.type === 'list');
|
|
46
|
-
const formView = views.find(v => v.type === 'form');
|
|
47
|
-
const specialistViews = views.filter(v => !['list', 'detail', 'form'].includes(v.type));
|
|
48
|
-
|
|
49
|
-
const specialistLinks = specialistViews.map(v => {
|
|
50
|
-
const label = v.type.charAt(0).toUpperCase() + v.type.slice(1);
|
|
51
|
-
const icon = v.type === 'board' ? '▦' : v.type === 'timeline' ? '⏱' : v.type === 'calendar' ? '📅' : v.type === 'dashboard' ? '📊' : v.type === 'analytics' ? '📈' : '◆';
|
|
52
|
-
return ` <Link to="${v.path}" className={\`flex items-center gap-2 px-2 py-1.5 rounded text-sm transition-all \${location.pathname === '${v.path}' ? 'bg-blue-50 text-blue-700 font-medium border border-blue-200' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900 border border-transparent'}\`}>
|
|
53
|
-
<span className="text-xs">${icon}</span> ${label}
|
|
54
|
-
</Link>`;
|
|
55
|
-
}).join('\n');
|
|
56
|
-
|
|
57
|
-
return ` {/* ${model} */}
|
|
58
|
-
<div>
|
|
59
|
-
<h3 className="px-2 text-xs font-semibold text-gray-400 uppercase tracking-wider mb-1">${model}s</h3>
|
|
60
|
-
<div className="space-y-0.5">
|
|
61
|
-
${listView ? ` <Link to="${listView.path}" className={\`flex items-center gap-2 px-2 py-1.5 rounded text-sm transition-all \${location.pathname === '${listView.path}' ? 'bg-blue-50 text-blue-700 font-medium border border-blue-200' : 'text-gray-700 hover:bg-gray-50 border border-transparent'}\`}>
|
|
62
|
-
<span className="text-xs">☰</span> Browse
|
|
63
|
-
</Link>` : ''}
|
|
64
|
-
${formView ? ` <Link to="${formView.path}" className={\`flex items-center gap-2 px-2 py-1.5 rounded text-sm transition-all \${location.pathname === '${formView.path}' ? 'bg-blue-50 text-blue-700 font-medium border border-blue-200' : 'text-gray-700 hover:bg-gray-50 border border-transparent'}\`}>
|
|
65
|
-
<span className="text-xs">+</span> New
|
|
66
|
-
</Link>` : ''}
|
|
67
|
-
${specialistLinks}
|
|
68
|
-
</div>
|
|
69
|
-
</div>`;
|
|
70
|
-
}).join('\n\n');
|
|
71
|
-
|
|
72
|
-
// Default route
|
|
73
|
-
const firstModel = Array.from(modelViews.keys())[0]?.toLowerCase() || 'unknown';
|
|
74
|
-
const hasDashboard = viewsArray.some((v: any) => v.type === 'dashboard');
|
|
75
|
-
const defaultElement = hasDashboard
|
|
76
|
-
? viewsArray.find((v: any) => v.type === 'dashboard')?.name || `${Array.from(modelViews.keys())[0]}ListView`
|
|
77
|
-
: `${Array.from(modelViews.keys())[0] || 'Unknown'}ListView`;
|
|
78
|
-
|
|
79
|
-
return `import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';
|
|
80
|
-
${viewImports.join('\n')}
|
|
81
|
-
|
|
82
|
-
function Sidebar() {
|
|
83
|
-
const location = useLocation();
|
|
84
|
-
return (
|
|
85
|
-
<aside className="w-60 bg-white border-r border-gray-200 flex flex-col">
|
|
86
|
-
{/* App Header */}
|
|
87
|
-
<div className="px-4 py-5 border-b border-gray-100">
|
|
88
|
-
<h1 className="text-lg font-bold text-gray-900">${appName}</h1>
|
|
89
|
-
<p className="text-xs text-gray-400 mt-0.5">Generated from specification</p>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
{/* Navigation */}
|
|
93
|
-
<nav className="flex-1 overflow-y-auto px-3 py-4 space-y-5">
|
|
94
|
-
${sidebarSections}
|
|
95
|
-
</nav>
|
|
96
|
-
|
|
97
|
-
{/* Footer */}
|
|
98
|
-
<div className="px-4 py-3 border-t border-gray-100 text-xs text-gray-400">
|
|
99
|
-
Powered by SpecVerse
|
|
100
|
-
</div>
|
|
101
|
-
</aside>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function App() {
|
|
106
|
-
return (
|
|
107
|
-
<Router>
|
|
108
|
-
<div className="flex h-screen bg-gray-50 overflow-hidden">
|
|
109
|
-
<Sidebar />
|
|
110
|
-
<main className="flex-1 overflow-y-auto">
|
|
111
|
-
<Routes>
|
|
112
|
-
<Route path="/" element={<${defaultElement} />} />
|
|
113
|
-
${routeEntries.join('\n')}
|
|
114
|
-
<Route path="*" element={
|
|
115
|
-
<div className="flex items-center justify-center h-full">
|
|
116
|
-
<div className="text-center">
|
|
117
|
-
<h1 className="text-4xl font-bold text-gray-300 mb-2">404</h1>
|
|
118
|
-
<p className="text-gray-500">Page not found</p>
|
|
119
|
-
<Link to="/" className="mt-4 inline-block text-blue-600 hover:text-blue-700 text-sm">← Back to home</Link>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
} />
|
|
123
|
-
</Routes>
|
|
124
|
-
</main>
|
|
125
|
-
</div>
|
|
126
|
-
</Router>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export default App;
|
|
131
|
-
`;
|
|
132
|
-
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Utilities Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates field-helpers.ts, relationship-utils.ts, and view-helpers.ts
|
|
5
|
-
* into the frontend's src/lib/ directory. These are imported by all view components.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { TemplateContext } from '@specverse/types';
|
|
9
|
-
|
|
10
|
-
export default function generateSharedUtils(context: TemplateContext): { files: Array<{ path: string; content: string }> } {
|
|
11
|
-
const files = [
|
|
12
|
-
{ path: 'field-helpers.ts', content: generateFieldHelpers() },
|
|
13
|
-
{ path: 'view-helpers.tsx', content: generateViewHelpers() },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
return { files };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function generateFieldHelpers(): string {
|
|
20
|
-
return `/**
|
|
21
|
-
* Field Helpers — shared utilities for field classification and display
|
|
22
|
-
* Generated by SpecVerse React factory
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
const METADATA_FIELDS = new Set([
|
|
26
|
-
'id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'deletedAt', 'version'
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
const AUTO_PATTERNS = new Set(['now', 'uuid4', 'autoincrement', 'auto']);
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Check if a field is auto-generated (should be hidden from forms)
|
|
33
|
-
*/
|
|
34
|
-
export function isAutoField(name: string, attr: any): boolean {
|
|
35
|
-
if (attr?.auto && AUTO_PATTERNS.has(attr.auto)) return true;
|
|
36
|
-
if (name === 'id') return true;
|
|
37
|
-
if (METADATA_FIELDS.has(name) && attr?.type?.toLowerCase().includes('date')) return true;
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Check if a field is metadata (shown last, styled muted)
|
|
43
|
-
*/
|
|
44
|
-
export function isMetadataField(name: string): boolean {
|
|
45
|
-
return METADATA_FIELDS.has(name);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Get the best display name for an entity
|
|
50
|
-
* Searches common name fields in priority order
|
|
51
|
-
*/
|
|
52
|
-
export function getEntityDisplayName(entity: any): string {
|
|
53
|
-
if (!entity) return 'Unknown';
|
|
54
|
-
const METADATA = new Set(['id', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', 'deletedAt', 'version']);
|
|
55
|
-
// Check common name fields first
|
|
56
|
-
for (const field of ['name', 'title', 'displayName', 'label', 'username', 'email', 'subject', 'message', 'description']) {
|
|
57
|
-
if (entity[field]) return String(entity[field]);
|
|
58
|
-
}
|
|
59
|
-
// Fall back to first non-metadata string value
|
|
60
|
-
for (const [key, val] of Object.entries(entity)) {
|
|
61
|
-
if (!METADATA.has(key) && val && typeof val === 'string' && !String(val).match(/^[0-9a-f-]{36}$/i)) {
|
|
62
|
-
return String(val);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return entity.id ? String(entity.id).slice(0, 8) + '...' : 'Unknown';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Classify attributes into ordered groups for display
|
|
70
|
-
*/
|
|
71
|
-
export function classifyFields(attributes: Array<{ name: string; type: string; auto?: string; required?: boolean }>): {
|
|
72
|
-
business: typeof attributes;
|
|
73
|
-
lifecycle: typeof attributes;
|
|
74
|
-
metadata: typeof attributes;
|
|
75
|
-
} {
|
|
76
|
-
const business: typeof attributes = [];
|
|
77
|
-
const lifecycle: typeof attributes = [];
|
|
78
|
-
const metadata: typeof attributes = [];
|
|
79
|
-
|
|
80
|
-
for (const attr of attributes) {
|
|
81
|
-
if (isAutoField(attr.name, attr) || isMetadataField(attr.name)) {
|
|
82
|
-
metadata.push(attr);
|
|
83
|
-
} else if (attr.name === 'status' || attr.name === 'state' || attr.name === 'phase') {
|
|
84
|
-
lifecycle.push(attr);
|
|
85
|
-
} else {
|
|
86
|
-
business.push(attr);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return { business, lifecycle, metadata };
|
|
91
|
-
}
|
|
92
|
-
`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function generateViewHelpers(): string {
|
|
96
|
-
return `/**
|
|
97
|
-
* View Helpers — formatting, colors, and UI utilities
|
|
98
|
-
* Generated by SpecVerse React factory
|
|
99
|
-
*/
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Format a value for display
|
|
103
|
-
*/
|
|
104
|
-
export function formatValue(value: any, type?: string): string {
|
|
105
|
-
if (value === null || value === undefined) return '—';
|
|
106
|
-
if (type?.toLowerCase().includes('date') || type?.toLowerCase().includes('timestamp')) {
|
|
107
|
-
return formatDate(value);
|
|
108
|
-
}
|
|
109
|
-
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
|
|
110
|
-
return String(value);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Format a date for display (relative for recent, absolute for old)
|
|
115
|
-
*/
|
|
116
|
-
export function formatDate(value: any): string {
|
|
117
|
-
if (!value) return '—';
|
|
118
|
-
const date = new Date(value);
|
|
119
|
-
if (isNaN(date.getTime())) return String(value);
|
|
120
|
-
|
|
121
|
-
const now = new Date();
|
|
122
|
-
const diff = now.getTime() - date.getTime();
|
|
123
|
-
const minutes = Math.floor(diff / 60000);
|
|
124
|
-
const hours = Math.floor(diff / 3600000);
|
|
125
|
-
const days = Math.floor(diff / 86400000);
|
|
126
|
-
|
|
127
|
-
if (minutes < 1) return 'just now';
|
|
128
|
-
if (minutes < 60) return \`\${minutes}m ago\`;
|
|
129
|
-
if (hours < 24) return \`\${hours}h ago\`;
|
|
130
|
-
if (days < 7) return \`\${days}d ago\`;
|
|
131
|
-
return date.toLocaleDateString();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Truncate text with ellipsis
|
|
136
|
-
*/
|
|
137
|
-
export function truncate(text: string, max: number = 60): string {
|
|
138
|
-
if (!text || text.length <= max) return text;
|
|
139
|
-
return text.slice(0, max) + '...';
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Get a Tailwind color class for a lifecycle status
|
|
144
|
-
*/
|
|
145
|
-
export function statusColor(status: string): { bg: string; text: string; dot: string } {
|
|
146
|
-
const s = status?.toLowerCase().replace(/[_-]/g, '') || '';
|
|
147
|
-
|
|
148
|
-
// Green states
|
|
149
|
-
if (['active', 'done', 'completed', 'approved', 'published', 'resolved'].includes(s)) {
|
|
150
|
-
return { bg: 'bg-green-50', text: 'text-green-700', dot: 'bg-green-500' };
|
|
151
|
-
}
|
|
152
|
-
// Blue states
|
|
153
|
-
if (['inprogress', 'processing', 'review', 'pending'].includes(s)) {
|
|
154
|
-
return { bg: 'bg-blue-50', text: 'text-blue-700', dot: 'bg-blue-500' };
|
|
155
|
-
}
|
|
156
|
-
// Yellow states
|
|
157
|
-
if (['draft', 'todo', 'planning', 'waiting', 'scheduled'].includes(s)) {
|
|
158
|
-
return { bg: 'bg-yellow-50', text: 'text-yellow-700', dot: 'bg-yellow-500' };
|
|
159
|
-
}
|
|
160
|
-
// Red states
|
|
161
|
-
if (['cancelled', 'rejected', 'failed', 'overdue', 'blocked'].includes(s)) {
|
|
162
|
-
return { bg: 'bg-red-50', text: 'text-red-700', dot: 'bg-red-500' };
|
|
163
|
-
}
|
|
164
|
-
// Gray states
|
|
165
|
-
if (['archived', 'closed', 'deprecated', 'inactive', 'disabled'].includes(s)) {
|
|
166
|
-
return { bg: 'bg-gray-50', text: 'text-gray-500', dot: 'bg-gray-400' };
|
|
167
|
-
}
|
|
168
|
-
// Default: indigo
|
|
169
|
-
return { bg: 'bg-indigo-50', text: 'text-indigo-700', dot: 'bg-indigo-500' };
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* StatusBadge component — matches app-demo's lifecycle badge styling
|
|
174
|
-
*/
|
|
175
|
-
export function StatusBadge({ status, variant = 'default' }: { status: string; variant?: 'default' | 'lifecycle' }) {
|
|
176
|
-
if (!status) return null;
|
|
177
|
-
|
|
178
|
-
// Lifecycle badges use purple (matching app-demo)
|
|
179
|
-
if (variant === 'lifecycle') {
|
|
180
|
-
return (
|
|
181
|
-
<span className="px-2 py-1 bg-purple-100 text-purple-700 rounded text-xs font-medium">
|
|
182
|
-
{status.replace(/[_-]/g, ' ')}
|
|
183
|
-
</span>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const colors = statusColor(status);
|
|
188
|
-
return (
|
|
189
|
-
<span className={\`inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium \${colors.bg} \${colors.text}\`}>
|
|
190
|
-
<span className={\`w-1.5 h-1.5 rounded-full \${colors.dot}\`}></span>
|
|
191
|
-
{status.replace(/[_-]/g, ' ')}
|
|
192
|
-
</span>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
`;
|
|
196
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Full Spec JSON Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates spec.json with the complete AI-optimized specification
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { TemplateContext } from '@specverse/types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate spec.json - the complete AI-optimized spec
|
|
11
|
-
*/
|
|
12
|
-
export default function generateSpecJson(context: TemplateContext): string {
|
|
13
|
-
const { spec } = context;
|
|
14
|
-
|
|
15
|
-
// Return the full spec as formatted JSON
|
|
16
|
-
return JSON.stringify(spec, null, 2);
|
|
17
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React TypeScript Types Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeScript interfaces from model definitions
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { TemplateContext } from '@specverse/types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate TypeScript interface for a model
|
|
11
|
-
*/
|
|
12
|
-
export default function generateModelTypes(context: TemplateContext): string {
|
|
13
|
-
const { model } = context;
|
|
14
|
-
|
|
15
|
-
if (!model) {
|
|
16
|
-
throw new Error('Model is required in template context');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const modelName = model.name;
|
|
20
|
-
|
|
21
|
-
// Convert attributes to object if it's an array
|
|
22
|
-
let attributes = model.attributes || {};
|
|
23
|
-
if (Array.isArray(attributes)) {
|
|
24
|
-
const obj: Record<string, any> = {};
|
|
25
|
-
attributes.forEach((attr: any) => {
|
|
26
|
-
if (attr && typeof attr === 'object' && attr.name) {
|
|
27
|
-
obj[attr.name] = attr;
|
|
28
|
-
} else if (Array.isArray(attr) && attr.length >= 2) {
|
|
29
|
-
obj[attr[0]] = attr[1];
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
attributes = obj;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Generate interface properties
|
|
36
|
-
const properties = Object.entries(attributes).map(([name, attr]: [string, any]) => {
|
|
37
|
-
const tsType = mapToTypeScript(attr.type);
|
|
38
|
-
const optional = !attr.constraints?.required ? '?' : '';
|
|
39
|
-
return ` ${name}${optional}: ${tsType};`;
|
|
40
|
-
}).join('\n');
|
|
41
|
-
|
|
42
|
-
return `/**
|
|
43
|
-
* ${modelName} Type Definition
|
|
44
|
-
* Auto-generated from SpecVerse model
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
export interface ${modelName} {
|
|
48
|
-
${properties}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type Create${modelName}Input = Omit<${modelName}, 'id' | 'createdAt' | 'updatedAt'>;
|
|
52
|
-
export type Update${modelName}Input = Partial<Create${modelName}Input>;
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Map SpecVerse types to TypeScript types
|
|
58
|
-
*/
|
|
59
|
-
function mapToTypeScript(type: string): string {
|
|
60
|
-
const typeMap: Record<string, string> = {
|
|
61
|
-
'String': 'string',
|
|
62
|
-
'Integer': 'number',
|
|
63
|
-
'Float': 'number',
|
|
64
|
-
'Boolean': 'boolean',
|
|
65
|
-
'Date': 'string',
|
|
66
|
-
'DateTime': 'string',
|
|
67
|
-
'Timestamp': 'string',
|
|
68
|
-
'UUID': 'string',
|
|
69
|
-
'Email': 'string',
|
|
70
|
-
'URL': 'string',
|
|
71
|
-
'JSON': 'Record<string, any>',
|
|
72
|
-
'Array': 'any[]',
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
return typeMap[type] || 'any';
|
|
76
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Views Metadata JSON Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates views-metadata.json with controller-based view definitions
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { TemplateContext } from '@specverse/types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate views-metadata.json
|
|
11
|
-
*/
|
|
12
|
-
export default function generateViewsMetadata(context: TemplateContext): string {
|
|
13
|
-
const { spec, views = [] } = context;
|
|
14
|
-
|
|
15
|
-
// Extract views from spec if not provided
|
|
16
|
-
const specViews = views.length > 0 ? views : (spec?.views || []);
|
|
17
|
-
const viewsArray = Array.isArray(specViews) ? specViews : Object.values(specViews);
|
|
18
|
-
|
|
19
|
-
// Build metadata object
|
|
20
|
-
const metadata: Record<string, any> = {};
|
|
21
|
-
|
|
22
|
-
viewsArray.forEach((viewDef: any) => {
|
|
23
|
-
const viewName = viewDef.name;
|
|
24
|
-
|
|
25
|
-
// Extract only the essential metadata for runtime
|
|
26
|
-
metadata[viewName] = {
|
|
27
|
-
name: viewName,
|
|
28
|
-
type: viewDef.type || 'list',
|
|
29
|
-
...(viewDef.description && { description: viewDef.description }),
|
|
30
|
-
model: viewDef.model, // Keep as-is (string or array for multi-model views)
|
|
31
|
-
...(viewDef.uiComponents && { uiComponents: viewDef.uiComponents }),
|
|
32
|
-
...(viewDef.subscriptions && viewDef.subscriptions.length > 0 && {
|
|
33
|
-
subscriptions: viewDef.subscriptions
|
|
34
|
-
}),
|
|
35
|
-
routing: viewDef.routing || {
|
|
36
|
-
path: `/${viewName.toLowerCase().replace(/view$/, '')}`
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return JSON.stringify(metadata, null, 2);
|
|
42
|
-
}
|