@metaobjectsdev/codegen-ts 0.9.0 → 0.11.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/column-mapper.d.ts +12 -6
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +68 -28
- package/dist/column-mapper.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -1
- package/dist/docs-paths.d.ts +58 -0
- package/dist/docs-paths.d.ts.map +1 -0
- package/dist/docs-paths.js +89 -0
- package/dist/docs-paths.js.map +1 -0
- package/dist/enum-import.d.ts +14 -0
- package/dist/enum-import.d.ts.map +1 -0
- package/dist/enum-import.js +35 -0
- package/dist/enum-import.js.map +1 -0
- package/dist/enum-shared.d.ts +32 -0
- package/dist/enum-shared.d.ts.map +1 -0
- package/dist/enum-shared.js +83 -0
- package/dist/enum-shared.js.map +1 -0
- package/dist/generator-registry.d.ts +22 -0
- package/dist/generator-registry.d.ts.map +1 -0
- package/dist/generator-registry.js +161 -0
- package/dist/generator-registry.js.map +1 -0
- package/dist/generator.d.ts +6 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js.map +1 -1
- package/dist/generators/api-doc-render.d.ts +17 -0
- package/dist/generators/api-doc-render.d.ts.map +1 -0
- package/dist/generators/api-doc-render.js +431 -0
- package/dist/generators/api-doc-render.js.map +1 -0
- package/dist/generators/api-docs-file.d.ts +21 -0
- package/dist/generators/api-docs-file.d.ts.map +1 -0
- package/dist/generators/api-docs-file.js +112 -0
- package/dist/generators/api-docs-file.js.map +1 -0
- package/dist/generators/api-field-shape.d.ts +39 -0
- package/dist/generators/api-field-shape.d.ts.map +1 -0
- package/dist/generators/api-field-shape.js +92 -0
- package/dist/generators/api-field-shape.js.map +1 -0
- package/dist/generators/api-label.d.ts +3 -0
- package/dist/generators/api-label.d.ts.map +1 -0
- package/dist/generators/api-label.js +8 -0
- package/dist/generators/api-label.js.map +1 -0
- package/dist/generators/api-model.d.ts +122 -0
- package/dist/generators/api-model.d.ts.map +1 -0
- package/dist/generators/api-model.js +809 -0
- package/dist/generators/api-model.js.map +1 -0
- package/dist/generators/docs-data-builder.d.ts +26 -4
- package/dist/generators/docs-data-builder.d.ts.map +1 -1
- package/dist/generators/docs-data-builder.js +439 -167
- package/dist/generators/docs-data-builder.js.map +1 -1
- package/dist/generators/docs-data.d.ts +136 -27
- package/dist/generators/docs-data.d.ts.map +1 -1
- package/dist/generators/docs-data.js +1 -1
- package/dist/generators/docs-data.js.map +1 -1
- package/dist/generators/docs-file.d.ts +19 -0
- package/dist/generators/docs-file.d.ts.map +1 -1
- package/dist/generators/docs-file.js +154 -27
- package/dist/generators/docs-file.js.map +1 -1
- package/dist/generators/entity-file.d.ts.map +1 -1
- package/dist/generators/entity-file.js +29 -14
- package/dist/generators/entity-file.js.map +1 -1
- package/dist/generators/extractor-file.d.ts.map +1 -1
- package/dist/generators/extractor-file.js +2 -1
- package/dist/generators/extractor-file.js.map +1 -1
- package/dist/generators/field-anchor.d.ts +7 -0
- package/dist/generators/field-anchor.d.ts.map +1 -0
- package/dist/generators/field-anchor.js +23 -0
- package/dist/generators/field-anchor.js.map +1 -0
- package/dist/generators/index.d.ts +8 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +6 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/mermaid-er.d.ts +14 -0
- package/dist/generators/mermaid-er.d.ts.map +1 -1
- package/dist/generators/mermaid-er.js +14 -0
- package/dist/generators/mermaid-er.js.map +1 -1
- package/dist/generators/output-parser-file.d.ts.map +1 -1
- package/dist/generators/output-parser-file.js +3 -4
- package/dist/generators/output-parser-file.js.map +1 -1
- package/dist/generators/output-prompt-file.d.ts.map +1 -1
- package/dist/generators/output-prompt-file.js +2 -2
- package/dist/generators/output-prompt-file.js.map +1 -1
- package/dist/generators/prompt-render-file.d.ts.map +1 -1
- package/dist/generators/prompt-render-file.js +3 -4
- package/dist/generators/prompt-render-file.js.map +1 -1
- package/dist/generators/queries-file.d.ts.map +1 -1
- package/dist/generators/queries-file.js +8 -3
- package/dist/generators/queries-file.js.map +1 -1
- package/dist/generators/render-helper-file.d.ts.map +1 -1
- package/dist/generators/render-helper-file.js +2 -2
- package/dist/generators/render-helper-file.js.map +1 -1
- package/dist/generators/routes-file-hono.d.ts.map +1 -1
- package/dist/generators/routes-file-hono.js +5 -1
- package/dist/generators/routes-file-hono.js.map +1 -1
- package/dist/generators/routes-file.d.ts +3 -0
- package/dist/generators/routes-file.d.ts.map +1 -1
- package/dist/generators/routes-file.js +6 -1
- package/dist/generators/routes-file.js.map +1 -1
- package/dist/generators/template-doc-builder.d.ts +19 -0
- package/dist/generators/template-doc-builder.d.ts.map +1 -0
- package/dist/generators/template-doc-builder.js +220 -0
- package/dist/generators/template-doc-builder.js.map +1 -0
- package/dist/generators/template-doc-data.d.ts +62 -0
- package/dist/generators/template-doc-data.d.ts.map +1 -0
- package/dist/generators/template-doc-data.js +16 -0
- package/dist/generators/template-doc-data.js.map +1 -0
- package/dist/generators/template-payload-tree.d.ts +15 -0
- package/dist/generators/template-payload-tree.d.ts.map +1 -0
- package/dist/generators/template-payload-tree.js +61 -0
- package/dist/generators/template-payload-tree.js.map +1 -0
- package/dist/generators/template-source-annotate.d.ts +74 -0
- package/dist/generators/template-source-annotate.d.ts.map +1 -0
- package/dist/generators/template-source-annotate.js +184 -0
- package/dist/generators/template-source-annotate.js.map +1 -0
- package/dist/generators/template-source-render.d.ts +24 -0
- package/dist/generators/template-source-render.d.ts.map +1 -0
- package/dist/generators/template-source-render.js +175 -0
- package/dist/generators/template-source-render.js.map +1 -0
- package/dist/generators/trace-helper-file.d.ts +9 -0
- package/dist/generators/trace-helper-file.d.ts.map +1 -0
- package/dist/generators/trace-helper-file.js +196 -0
- package/dist/generators/trace-helper-file.js.map +1 -0
- package/dist/import-path.d.ts +18 -0
- package/dist/import-path.d.ts.map +1 -1
- package/dist/import-path.js +21 -0
- package/dist/import-path.js.map +1 -1
- package/dist/index.d.ts +29 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/dist/metaobjects-config.d.ts +101 -2
- package/dist/metaobjects-config.d.ts.map +1 -1
- package/dist/metaobjects-config.js +46 -0
- package/dist/metaobjects-config.js.map +1 -1
- package/dist/naming.d.ts +39 -2
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +52 -3
- package/dist/naming.js.map +1 -1
- package/dist/payload-codegen.d.ts.map +1 -1
- package/dist/payload-codegen.js +14 -6
- package/dist/payload-codegen.js.map +1 -1
- package/dist/pk-resolver.d.ts.map +1 -1
- package/dist/pk-resolver.js +4 -2
- package/dist/pk-resolver.js.map +1 -1
- package/dist/projection/extract-view-spec.d.ts.map +1 -1
- package/dist/projection/extract-view-spec.js +52 -26
- package/dist/projection/extract-view-spec.js.map +1 -1
- package/dist/relation-resolver.d.ts +16 -0
- package/dist/relation-resolver.d.ts.map +1 -1
- package/dist/relation-resolver.js +82 -1
- package/dist/relation-resolver.js.map +1 -1
- package/dist/render-context.d.ts +25 -2
- package/dist/render-context.d.ts.map +1 -1
- package/dist/render-context.js +7 -0
- package/dist/render-context.js.map +1 -1
- package/dist/render-engine/embedded-templates.generated.d.ts +2 -0
- package/dist/render-engine/embedded-templates.generated.d.ts.map +1 -0
- package/dist/render-engine/embedded-templates.generated.js +15 -0
- package/dist/render-engine/embedded-templates.generated.js.map +1 -0
- package/dist/render-engine/framework-provider.d.ts.map +1 -1
- package/dist/render-engine/framework-provider.js +26 -13
- package/dist/render-engine/framework-provider.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +20 -0
- package/dist/runner.js.map +1 -1
- package/dist/templates/docs-file.d.ts +2 -6
- package/dist/templates/docs-file.d.ts.map +1 -1
- package/dist/templates/docs-file.js +2 -5
- package/dist/templates/docs-file.js.map +1 -1
- package/dist/templates/drizzle-schema.d.ts.map +1 -1
- package/dist/templates/drizzle-schema.js +72 -23
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-constants.d.ts +7 -0
- package/dist/templates/entity-constants.d.ts.map +1 -1
- package/dist/templates/entity-constants.js +3 -3
- package/dist/templates/entity-constants.js.map +1 -1
- package/dist/templates/entity-file.d.ts.map +1 -1
- package/dist/templates/entity-file.js +16 -5
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/enums-file.d.ts +11 -0
- package/dist/templates/enums-file.d.ts.map +1 -0
- package/dist/templates/enums-file.js +44 -0
- package/dist/templates/enums-file.js.map +1 -0
- package/dist/templates/extract-delegate-emitter.d.ts.map +1 -1
- package/dist/templates/extract-delegate-emitter.js +6 -8
- package/dist/templates/extract-delegate-emitter.js.map +1 -1
- package/dist/templates/extractor.d.ts.map +1 -1
- package/dist/templates/extractor.js +58 -41
- package/dist/templates/extractor.js.map +1 -1
- package/dist/templates/field-meta.d.ts.map +1 -1
- package/dist/templates/field-meta.js +2 -6
- package/dist/templates/field-meta.js.map +1 -1
- package/dist/templates/filter-allowlist.d.ts +7 -2
- package/dist/templates/filter-allowlist.d.ts.map +1 -1
- package/dist/templates/filter-allowlist.js +18 -10
- package/dist/templates/filter-allowlist.js.map +1 -1
- package/dist/templates/filter-shared.js +2 -2
- package/dist/templates/filter-shared.js.map +1 -1
- package/dist/templates/filter-type.d.ts +7 -1
- package/dist/templates/filter-type.d.ts.map +1 -1
- package/dist/templates/filter-type.js +10 -6
- package/dist/templates/filter-type.js.map +1 -1
- package/dist/templates/find-templates.d.ts +4 -0
- package/dist/templates/find-templates.d.ts.map +1 -0
- package/dist/templates/find-templates.js +15 -0
- package/dist/templates/find-templates.js.map +1 -0
- package/dist/templates/fr010-field-mapping.d.ts +2 -0
- package/dist/templates/fr010-field-mapping.d.ts.map +1 -1
- package/dist/templates/fr010-field-mapping.js +15 -11
- package/dist/templates/fr010-field-mapping.js.map +1 -1
- package/dist/templates/inferred-types.d.ts +44 -7
- package/dist/templates/inferred-types.d.ts.map +1 -1
- package/dist/templates/inferred-types.js +121 -19
- package/dist/templates/inferred-types.js.map +1 -1
- package/dist/templates/mermaid-er.d.ts +35 -2
- package/dist/templates/mermaid-er.d.ts.map +1 -1
- package/dist/templates/mermaid-er.js +174 -7
- package/dist/templates/mermaid-er.js.map +1 -1
- package/dist/templates/output-format-spec-emitter.js +1 -1
- package/dist/templates/output-format-spec-emitter.js.map +1 -1
- package/dist/templates/output-parser.d.ts.map +1 -1
- package/dist/templates/output-parser.js +31 -80
- package/dist/templates/output-parser.js.map +1 -1
- package/dist/templates/output-prompt.d.ts.map +1 -1
- package/dist/templates/output-prompt.js +2 -2
- package/dist/templates/output-prompt.js.map +1 -1
- package/dist/templates/queries-file.d.ts.map +1 -1
- package/dist/templates/queries-file.js +113 -5
- package/dist/templates/queries-file.js.map +1 -1
- package/dist/templates/queries.d.ts +7 -2
- package/dist/templates/queries.d.ts.map +1 -1
- package/dist/templates/queries.js +15 -15
- package/dist/templates/queries.js.map +1 -1
- package/dist/templates/relations-block.d.ts.map +1 -1
- package/dist/templates/relations-block.js +12 -3
- package/dist/templates/relations-block.js.map +1 -1
- package/dist/templates/render-helper.d.ts.map +1 -1
- package/dist/templates/render-helper.js +5 -5
- package/dist/templates/render-helper.js.map +1 -1
- package/dist/templates/routes-file-hono.d.ts.map +1 -1
- package/dist/templates/routes-file-hono.js +1 -2
- package/dist/templates/routes-file-hono.js.map +1 -1
- package/dist/templates/routes-file.d.ts.map +1 -1
- package/dist/templates/routes-file.js +184 -7
- package/dist/templates/routes-file.js.map +1 -1
- package/dist/templates/tph-discriminator.d.ts +56 -0
- package/dist/templates/tph-discriminator.d.ts.map +1 -0
- package/dist/templates/tph-discriminator.js +180 -0
- package/dist/templates/tph-discriminator.js.map +1 -0
- package/dist/templates/value-object-file.d.ts +2 -1
- package/dist/templates/value-object-file.d.ts.map +1 -1
- package/dist/templates/value-object-file.js +33 -5
- package/dist/templates/value-object-file.js.map +1 -1
- package/dist/templates/zod-validators.d.ts +65 -2
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +202 -22
- package/dist/templates/zod-validators.js.map +1 -1
- package/package.json +103 -34
- package/src/column-mapper.ts +79 -32
- package/src/constants.ts +18 -0
- package/src/docs-paths.ts +128 -0
- package/src/enum-import.ts +43 -0
- package/src/enum-shared.ts +95 -0
- package/src/generator-registry.ts +204 -0
- package/src/generator.ts +6 -0
- package/src/generators/api-doc-render.ts +572 -0
- package/src/generators/api-docs-file.ts +146 -0
- package/src/generators/api-field-shape.ts +114 -0
- package/src/generators/api-label.ts +7 -0
- package/src/generators/api-model.ts +1067 -0
- package/src/generators/docs-data-builder.ts +483 -189
- package/src/generators/docs-data.ts +139 -28
- package/src/generators/docs-file.ts +205 -39
- package/src/generators/entity-file.ts +31 -15
- package/src/generators/extractor-file.ts +2 -1
- package/src/generators/field-anchor.ts +24 -0
- package/src/generators/index.ts +8 -1
- package/src/generators/mermaid-er.ts +14 -0
- package/src/generators/output-parser-file.ts +3 -4
- package/src/generators/output-prompt-file.ts +2 -1
- package/src/generators/prompt-render-file.ts +3 -4
- package/src/generators/queries-file.ts +9 -3
- package/src/generators/render-helper-file.ts +2 -1
- package/src/generators/routes-file-hono.ts +5 -1
- package/src/generators/routes-file.ts +7 -1
- package/src/generators/template-doc-builder.ts +306 -0
- package/src/generators/template-doc-data.ts +85 -0
- package/src/generators/template-payload-tree.ts +71 -0
- package/src/generators/template-source-annotate.ts +290 -0
- package/src/generators/template-source-render.ts +203 -0
- package/src/generators/trace-helper-file.ts +301 -0
- package/src/import-path.ts +28 -0
- package/src/index.ts +55 -4
- package/src/metaobjects-config.ts +146 -2
- package/src/naming.ts +73 -3
- package/src/payload-codegen.ts +16 -5
- package/src/pk-resolver.ts +4 -2
- package/src/projection/extract-view-spec.ts +50 -31
- package/src/relation-resolver.ts +103 -1
- package/src/render-context.ts +32 -2
- package/src/render-engine/embedded-templates.generated.ts +14 -0
- package/src/render-engine/framework-provider.ts +25 -11
- package/src/runner.ts +24 -0
- package/src/templates/docs-file.ts +2 -9
- package/src/templates/drizzle-schema.ts +80 -28
- package/src/templates/entity-constants.ts +3 -3
- package/src/templates/entity-file.ts +16 -5
- package/src/templates/enums-file.ts +50 -0
- package/src/templates/extract-delegate-emitter.ts +6 -7
- package/src/templates/extractor.ts +70 -40
- package/src/templates/field-meta.ts +1 -7
- package/src/templates/filter-allowlist.ts +18 -11
- package/src/templates/filter-shared.ts +2 -2
- package/src/templates/filter-type.ts +9 -7
- package/src/templates/find-templates.ts +15 -0
- package/src/templates/fr010-field-mapping.ts +15 -13
- package/src/templates/inferred-types.ts +122 -21
- package/src/templates/mermaid-er.ts +176 -8
- package/src/templates/output-format-spec-emitter.ts +1 -1
- package/src/templates/output-parser.ts +31 -80
- package/src/templates/output-prompt.ts +2 -1
- package/src/templates/queries-file.ts +133 -4
- package/src/templates/queries.ts +21 -15
- package/src/templates/relations-block.ts +19 -3
- package/src/templates/render-helper.ts +5 -4
- package/src/templates/routes-file-hono.ts +1 -2
- package/src/templates/routes-file.ts +234 -7
- package/src/templates/tph-discriminator.ts +232 -0
- package/src/templates/value-object-file.ts +39 -5
- package/src/templates/zod-validators.ts +225 -21
- package/templates/api/agent-api.md.mustache +30 -0
- package/templates/api/entity-api.md.mustache +69 -0
- package/templates/api/index.md.mustache +21 -0
- package/templates/docs/entity-page.md.mustache +33 -21
- package/templates/docs/template-page.md.mustache +56 -0
- package/dist/templates/extract-schema-emitter.d.ts +0 -8
- package/dist/templates/extract-schema-emitter.d.ts.map +0 -1
- package/dist/templates/extract-schema-emitter.js +0 -81
- package/dist/templates/extract-schema-emitter.js.map +0 -1
- package/src/templates/extract-schema-emitter.ts +0 -111
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/codegen-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0-rc.1",
|
|
4
4
|
"description": "TypeScript codegen engine for MetaObjects — emits Drizzle, Zod, and Fastify artifacts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,9 +20,70 @@
|
|
|
20
20
|
"bun": "./src/templates/zod-validators.ts",
|
|
21
21
|
"types": "./dist/templates/zod-validators.d.ts",
|
|
22
22
|
"default": "./dist/templates/zod-validators.js"
|
|
23
|
+
},
|
|
24
|
+
"./templates/entity-file": {
|
|
25
|
+
"bun": "./src/templates/entity-file.ts",
|
|
26
|
+
"types": "./dist/templates/entity-file.d.ts",
|
|
27
|
+
"default": "./dist/templates/entity-file.js"
|
|
28
|
+
},
|
|
29
|
+
"./templates/drizzle-schema": {
|
|
30
|
+
"bun": "./src/templates/drizzle-schema.ts",
|
|
31
|
+
"types": "./dist/templates/drizzle-schema.d.ts",
|
|
32
|
+
"default": "./dist/templates/drizzle-schema.js"
|
|
33
|
+
},
|
|
34
|
+
"./templates/inferred-types": {
|
|
35
|
+
"bun": "./src/templates/inferred-types.ts",
|
|
36
|
+
"types": "./dist/templates/inferred-types.d.ts",
|
|
37
|
+
"default": "./dist/templates/inferred-types.js"
|
|
38
|
+
},
|
|
39
|
+
"./templates/barrel": {
|
|
40
|
+
"bun": "./src/templates/barrel.ts",
|
|
41
|
+
"types": "./dist/templates/barrel.d.ts",
|
|
42
|
+
"default": "./dist/templates/barrel.js"
|
|
43
|
+
},
|
|
44
|
+
"./templates/filter-type": {
|
|
45
|
+
"bun": "./src/templates/filter-type.ts",
|
|
46
|
+
"types": "./dist/templates/filter-type.d.ts",
|
|
47
|
+
"default": "./dist/templates/filter-type.js"
|
|
48
|
+
},
|
|
49
|
+
"./templates/filter-allowlist": {
|
|
50
|
+
"bun": "./src/templates/filter-allowlist.ts",
|
|
51
|
+
"types": "./dist/templates/filter-allowlist.d.ts",
|
|
52
|
+
"default": "./dist/templates/filter-allowlist.js"
|
|
53
|
+
},
|
|
54
|
+
"./templates/entity-constants": {
|
|
55
|
+
"bun": "./src/templates/entity-constants.ts",
|
|
56
|
+
"types": "./dist/templates/entity-constants.d.ts",
|
|
57
|
+
"default": "./dist/templates/entity-constants.js"
|
|
58
|
+
},
|
|
59
|
+
"./templates/queries-file": {
|
|
60
|
+
"bun": "./src/templates/queries-file.ts",
|
|
61
|
+
"types": "./dist/templates/queries-file.d.ts",
|
|
62
|
+
"default": "./dist/templates/queries-file.js"
|
|
63
|
+
},
|
|
64
|
+
"./templates/routes-file": {
|
|
65
|
+
"bun": "./src/templates/routes-file.ts",
|
|
66
|
+
"types": "./dist/templates/routes-file.d.ts",
|
|
67
|
+
"default": "./dist/templates/routes-file.js"
|
|
68
|
+
},
|
|
69
|
+
"./templates/value-object-file": {
|
|
70
|
+
"bun": "./src/templates/value-object-file.ts",
|
|
71
|
+
"types": "./dist/templates/value-object-file.d.ts",
|
|
72
|
+
"default": "./dist/templates/value-object-file.js"
|
|
73
|
+
},
|
|
74
|
+
"./templates/projection-decl": {
|
|
75
|
+
"bun": "./src/templates/projection-decl.ts",
|
|
76
|
+
"types": "./dist/templates/projection-decl.d.ts",
|
|
77
|
+
"default": "./dist/templates/projection-decl.js"
|
|
23
78
|
}
|
|
24
79
|
},
|
|
25
|
-
"files": [
|
|
80
|
+
"files": [
|
|
81
|
+
"dist",
|
|
82
|
+
"src",
|
|
83
|
+
"templates",
|
|
84
|
+
"README.md",
|
|
85
|
+
"LICENSE"
|
|
86
|
+
],
|
|
26
87
|
"scripts": {
|
|
27
88
|
"build": "tsc -p .",
|
|
28
89
|
"typecheck": "tsc -p tsconfig.typecheck.json"
|
|
@@ -31,36 +92,44 @@
|
|
|
31
92
|
"author": "Doug Mealing <doug@dougmealing.com>",
|
|
32
93
|
"homepage": "https://metaobjects.dev",
|
|
33
94
|
"bugs": {
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
"repository": {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
"keywords": [
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
"url": "https://github.com/metaobjectsdev/metaobjects/issues"
|
|
96
|
+
},
|
|
97
|
+
"repository": {
|
|
98
|
+
"type": "git",
|
|
99
|
+
"url": "https://github.com/metaobjectsdev/metaobjects.git",
|
|
100
|
+
"directory": "server/typescript/packages/codegen-ts"
|
|
101
|
+
},
|
|
102
|
+
"keywords": [
|
|
103
|
+
"metaobjects",
|
|
104
|
+
"codegen",
|
|
105
|
+
"drizzle",
|
|
106
|
+
"zod",
|
|
107
|
+
"fastify",
|
|
108
|
+
"typescript"
|
|
109
|
+
],
|
|
110
|
+
"publishConfig": {
|
|
111
|
+
"access": "public"
|
|
112
|
+
},
|
|
113
|
+
"dependencies": {
|
|
114
|
+
"@metaobjectsdev/metadata": "0.11.0-rc.1",
|
|
115
|
+
"@metaobjectsdev/render": "0.11.0-rc.1",
|
|
116
|
+
"@biomejs/js-api": "^0.7.0",
|
|
117
|
+
"@biomejs/wasm-nodejs": "^1.9.4",
|
|
118
|
+
"ts-poet": "^6.10.0"
|
|
119
|
+
},
|
|
120
|
+
"peerDependencies": {
|
|
121
|
+
"drizzle-orm": ">=0.36.0",
|
|
122
|
+
"zod": ">=3.23.0"
|
|
123
|
+
},
|
|
124
|
+
"devDependencies": {
|
|
125
|
+
"@biomejs/biome": "^1.9.0",
|
|
126
|
+
"@metaobjectsdev/codegen-ts-react": "0.11.0-rc.1",
|
|
127
|
+
"@metaobjectsdev/migrate-ts": "0.11.0-rc.1",
|
|
128
|
+
"@metaobjectsdev/runtime-ts": "0.11.0-rc.1",
|
|
129
|
+
"bun-types": "latest",
|
|
130
|
+
"drizzle-orm": "^0.36.0",
|
|
131
|
+
"hono": "^4.6.0",
|
|
132
|
+
"typescript": "^5.6.0",
|
|
133
|
+
"zod": "^3.23.0"
|
|
134
|
+
}
|
|
66
135
|
}
|
package/src/column-mapper.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
FIELD_SUBTYPE_TIME,
|
|
16
16
|
FIELD_SUBTYPE_TIMESTAMP,
|
|
17
17
|
FIELD_SUBTYPE_OBJECT,
|
|
18
|
-
FIELD_SUBTYPE_CLASS,
|
|
19
18
|
FIELD_SUBTYPE_ENUM,
|
|
20
19
|
FIELD_SUBTYPE_UUID,
|
|
21
20
|
VALIDATOR_SUBTYPE_REQUIRED,
|
|
@@ -27,6 +26,8 @@ import {
|
|
|
27
26
|
FIELD_ATTR_UNIQUE,
|
|
28
27
|
FIELD_ATTR_DEFAULT,
|
|
29
28
|
FIELD_ATTR_OBJECT_REF,
|
|
29
|
+
FIELD_ATTR_STORAGE,
|
|
30
|
+
STORAGE_JSONB,
|
|
30
31
|
VALIDATOR_ATTR_MAX,
|
|
31
32
|
FIELD_ATTR_DB_COLUMN_TYPE,
|
|
32
33
|
DB_COLUMN_TYPE_UUID,
|
|
@@ -35,7 +36,7 @@ import {
|
|
|
35
36
|
} from "@metaobjectsdev/metadata";
|
|
36
37
|
import { columnNameFromField } from "./naming.js";
|
|
37
38
|
import { enumValues } from "./enum-meta.js";
|
|
38
|
-
import { DEFAULT_COLUMN_NAMING_STRATEGY } from "@metaobjectsdev/metadata";
|
|
39
|
+
import { DEFAULT_COLUMN_NAMING_STRATEGY, stripPackage } from "@metaobjectsdev/metadata";
|
|
39
40
|
import type { Dialect, ColumnNamingStrategy } from "./metaobjects-config.js";
|
|
40
41
|
|
|
41
42
|
export type { Dialect };
|
|
@@ -82,7 +83,6 @@ function sqliteJsonArrayElementTsType(subType: string): string | undefined {
|
|
|
82
83
|
switch (subType) {
|
|
83
84
|
case FIELD_SUBTYPE_STRING:
|
|
84
85
|
case FIELD_SUBTYPE_ENUM:
|
|
85
|
-
case FIELD_SUBTYPE_CLASS:
|
|
86
86
|
case FIELD_SUBTYPE_UUID:
|
|
87
87
|
case FIELD_SUBTYPE_DATE:
|
|
88
88
|
case FIELD_SUBTYPE_TIME:
|
|
@@ -134,15 +134,20 @@ export interface ColumnSpec {
|
|
|
134
134
|
checkConstraint?: string;
|
|
135
135
|
/**
|
|
136
136
|
* Optional `.$type<...>()` chain target. Renderer (drizzle-schema.ts) emits
|
|
137
|
-
*
|
|
138
|
-
*
|
|
137
|
+
* it ahead of the modifiers chain, using ts-poet `imp()` for objectRef
|
|
138
|
+
* variants so the cross-module type import auto-hoists. `array` controls the
|
|
139
|
+
* `[]` suffix: a single value (`VO`) vs a collection (`VO[]`).
|
|
139
140
|
* `kind: "scalar"` covers string[]/number[]/boolean[] — no import needed.
|
|
140
|
-
* `kind: "objectRef"` covers SourceLens
|
|
141
|
-
*
|
|
141
|
+
* `kind: "objectRef"` covers SourceLens/Dissent/etc. — only the bare VO `name`
|
|
142
|
+
* is carried; the renderer resolves the import MODULE via the shared
|
|
143
|
+
* `valueObjectModuleSpecifier` (layout/package/extStyle-aware, identical to the
|
|
144
|
+
* field's TS type + Zod schema). A single Postgres jsonb object column
|
|
145
|
+
* (`array: false`) gets `.$type<VO>()`; an array of VOs held in one jsonb
|
|
146
|
+
* column gets `.$type<VO[]>()`.
|
|
142
147
|
*/
|
|
143
148
|
dollarTypeRef?:
|
|
144
|
-
| { kind: "scalar"; tsType: "string" | "number" | "boolean" }
|
|
145
|
-
| { kind: "objectRef"; name: string;
|
|
149
|
+
| { kind: "scalar"; tsType: "string" | "number" | "boolean"; array: boolean }
|
|
150
|
+
| { kind: "objectRef"; name: string; array: boolean };
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
/**
|
|
@@ -163,8 +168,9 @@ export interface ColumnSpec {
|
|
|
163
168
|
*/
|
|
164
169
|
function pgColumnTypeOverride(
|
|
165
170
|
field: MetaField,
|
|
171
|
+
timestampMode: "date" | "string" = "string",
|
|
166
172
|
): { fnName: string; fnOptions?: Record<string, unknown> } | undefined {
|
|
167
|
-
const dbColumnType = field.
|
|
173
|
+
const dbColumnType = field.attr(FIELD_ATTR_DB_COLUMN_TYPE);
|
|
168
174
|
if (typeof dbColumnType !== "string") return undefined;
|
|
169
175
|
switch (dbColumnType) {
|
|
170
176
|
case DB_COLUMN_TYPE_UUID:
|
|
@@ -173,9 +179,10 @@ function pgColumnTypeOverride(
|
|
|
173
179
|
return { fnName: "jsonb" };
|
|
174
180
|
case DB_COLUMN_TYPE_TIMESTAMP_WITH_TZ:
|
|
175
181
|
// Drizzle pg-core: timestamp(col, { withTimezone: true }) → timestamptz.
|
|
176
|
-
// mode
|
|
177
|
-
//
|
|
178
|
-
|
|
182
|
+
// mode defaults to "string" (ISO-8601 wire contract, matching the generated
|
|
183
|
+
// Zod); a consumer can opt into "date" (drizzle's native mode) via
|
|
184
|
+
// codegen.timestampMode when its hand-written code works with JS Dates.
|
|
185
|
+
return { fnName: "timestamp", fnOptions: { mode: timestampMode, withTimezone: true } };
|
|
179
186
|
default:
|
|
180
187
|
return undefined;
|
|
181
188
|
}
|
|
@@ -184,7 +191,7 @@ function pgColumnTypeOverride(
|
|
|
184
191
|
/** Resolve max length from validator.length child or @maxLength attr.
|
|
185
192
|
* Uses field.validators() (effective) so inherited validators are seen. */
|
|
186
193
|
function getMaxLength(field: MetaField): number | undefined {
|
|
187
|
-
const lenAttr = field.
|
|
194
|
+
const lenAttr = field.attr(FIELD_ATTR_MAX_LENGTH);
|
|
188
195
|
if (typeof lenAttr === "number") return lenAttr;
|
|
189
196
|
for (const child of field.validators()) {
|
|
190
197
|
if (child.subType === VALIDATOR_SUBTYPE_LENGTH) {
|
|
@@ -198,14 +205,24 @@ function getMaxLength(field: MetaField): number | undefined {
|
|
|
198
205
|
/** Check for validator.required child OR @required attr.
|
|
199
206
|
* Uses field.validators() (effective) so inherited validators are seen. */
|
|
200
207
|
function isRequired(field: MetaField): boolean {
|
|
201
|
-
if (field.
|
|
208
|
+
if (field.attr(FIELD_ATTR_REQUIRED) === true) return true;
|
|
202
209
|
return field.validators().some((child) => child.subType === VALIDATOR_SUBTYPE_REQUIRED);
|
|
203
210
|
}
|
|
204
211
|
|
|
212
|
+
/** The bare (package-stripped) @objectRef name on a field.object, or undefined
|
|
213
|
+
* when unset. Used as the `.$type<VO>()` target + its sibling-module import.
|
|
214
|
+
* A fully-qualified ref (acme::ai::SourceLens) strips to the short name. */
|
|
215
|
+
function objectRefBaseName(field: MetaField): string | undefined {
|
|
216
|
+
const ref = field.attr(FIELD_ATTR_OBJECT_REF);
|
|
217
|
+
if (typeof ref === "string" && ref.length > 0) return stripPackage(ref);
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
205
221
|
export function mapColumnType(
|
|
206
222
|
field: MetaField,
|
|
207
223
|
dialect: Dialect,
|
|
208
224
|
strategy: ColumnNamingStrategy = DEFAULT_COLUMN_NAMING_STRATEGY,
|
|
225
|
+
timestampMode: "date" | "string" = "string",
|
|
209
226
|
): ColumnSpec {
|
|
210
227
|
const dbName = field.column ?? columnNameFromField(field.name, strategy);
|
|
211
228
|
const importModule = dialect === "sqlite" ? "drizzle-orm/sqlite-core" : "drizzle-orm/pg-core";
|
|
@@ -243,13 +260,21 @@ export function mapColumnType(
|
|
|
243
260
|
// isn't a silent rounding hazard.
|
|
244
261
|
leadingComment = "TODO: SQLite has no decimal type; stored as text. Convert at the application boundary or migrate to Postgres for native numeric.";
|
|
245
262
|
break;
|
|
263
|
+
case FIELD_SUBTYPE_OBJECT:
|
|
264
|
+
// A nested object is stored as a single JSON column (the default
|
|
265
|
+
// single-jsonb-column storage). SQLite has no native jsonb, so the
|
|
266
|
+
// idiomatic Drizzle form is text(..., { mode: "json" }) — agreeing with
|
|
267
|
+
// migrate-ts/expected-schema, which maps field.object → { kind: "json" }
|
|
268
|
+
// (JSON on SQLite). @storage flattened expansion is a separate codegen
|
|
269
|
+
// gap; the column TYPE here is the single-column JSON representation.
|
|
270
|
+
fnName = "text";
|
|
271
|
+
fnOptions = { mode: "json" };
|
|
272
|
+
break;
|
|
246
273
|
case FIELD_SUBTYPE_DATE:
|
|
247
274
|
case FIELD_SUBTYPE_TIME:
|
|
248
275
|
case FIELD_SUBTYPE_TIMESTAMP:
|
|
249
276
|
case FIELD_SUBTYPE_STRING:
|
|
250
277
|
case FIELD_SUBTYPE_ENUM:
|
|
251
|
-
case FIELD_SUBTYPE_CLASS:
|
|
252
|
-
case FIELD_SUBTYPE_OBJECT:
|
|
253
278
|
case FIELD_SUBTYPE_UUID:
|
|
254
279
|
// SQLite has no native uuid type; store as TEXT (string native binding).
|
|
255
280
|
fnName = "text";
|
|
@@ -263,7 +288,7 @@ export function mapColumnType(
|
|
|
263
288
|
// A physical @dbColumnType override wins over the subtype default (Postgres
|
|
264
289
|
// only; SQLite has no native analogue and falls through above). Resolved
|
|
265
290
|
// first so the override-precedence matches migrate-ts's expected-schema.
|
|
266
|
-
const override = pgColumnTypeOverride(field);
|
|
291
|
+
const override = pgColumnTypeOverride(field, timestampMode);
|
|
267
292
|
if (override !== undefined) {
|
|
268
293
|
// Override fully determines the physical type; skip the subtype switch.
|
|
269
294
|
fnName = override.fnName;
|
|
@@ -302,7 +327,7 @@ export function mapColumnType(
|
|
|
302
327
|
// inconsistent with the string-typed schema + wire contract and
|
|
303
328
|
// throws on a string write. See SP-B api-contract-generated lane.
|
|
304
329
|
fnName = "timestamp";
|
|
305
|
-
fnOptions = { mode:
|
|
330
|
+
fnOptions = { mode: timestampMode };
|
|
306
331
|
break;
|
|
307
332
|
case FIELD_SUBTYPE_UUID:
|
|
308
333
|
// Postgres native uuid column; native TS binding stays `string`.
|
|
@@ -314,8 +339,8 @@ export function mapColumnType(
|
|
|
314
339
|
// declared @precision/@scale (mirroring migrate-ts/expected-schema so
|
|
315
340
|
// codegen and the DDL agree), falling back to a sane default.
|
|
316
341
|
fnName = "numeric";
|
|
317
|
-
const precision = field.
|
|
318
|
-
const scale = field.
|
|
342
|
+
const precision = field.attr(FIELD_ATTR_PRECISION);
|
|
343
|
+
const scale = field.attr(FIELD_ATTR_SCALE);
|
|
319
344
|
if (typeof precision === "number" && typeof scale === "number") {
|
|
320
345
|
fnOptions = { precision, scale };
|
|
321
346
|
} else if (typeof precision === "number") {
|
|
@@ -335,9 +360,15 @@ export function mapColumnType(
|
|
|
335
360
|
}
|
|
336
361
|
break;
|
|
337
362
|
}
|
|
338
|
-
case FIELD_SUBTYPE_ENUM:
|
|
339
|
-
case FIELD_SUBTYPE_CLASS:
|
|
340
363
|
case FIELD_SUBTYPE_OBJECT:
|
|
364
|
+
// A nested object is stored as a single jsonb column (the default
|
|
365
|
+
// single-jsonb-column storage), matching migrate-ts/expected-schema,
|
|
366
|
+
// which maps field.object → { kind: "json" } → JSONB on Postgres.
|
|
367
|
+
// @storage flattened expansion is a separate codegen gap; the column
|
|
368
|
+
// TYPE here is the single-column jsonb representation.
|
|
369
|
+
fnName = "jsonb";
|
|
370
|
+
break;
|
|
371
|
+
case FIELD_SUBTYPE_ENUM:
|
|
341
372
|
default:
|
|
342
373
|
fnName = "text";
|
|
343
374
|
break;
|
|
@@ -360,7 +391,11 @@ export function mapColumnType(
|
|
|
360
391
|
|
|
361
392
|
const modifiers: string[] = [];
|
|
362
393
|
|
|
363
|
-
|
|
394
|
+
// Postgres native arrays (text[]/integer[]/…) apply to SCALAR array fields
|
|
395
|
+
// only. An object-typed field is stored as a single jsonb column holding the
|
|
396
|
+
// JSON array (storage jsonb/subdocument), so it gets NO native .array() — the
|
|
397
|
+
// array-ness is carried by the .$type<VO[]>() annotation computed below.
|
|
398
|
+
if (dialect === "postgres" && isArray && subType !== FIELD_SUBTYPE_OBJECT) {
|
|
364
399
|
modifiers.push(".array()");
|
|
365
400
|
}
|
|
366
401
|
|
|
@@ -379,12 +414,12 @@ export function mapColumnType(
|
|
|
379
414
|
modifiers.push(".notNull()");
|
|
380
415
|
}
|
|
381
416
|
|
|
382
|
-
if (field.
|
|
417
|
+
if (field.attr(FIELD_ATTR_UNIQUE) === true) {
|
|
383
418
|
modifiers.push(".unique()");
|
|
384
419
|
}
|
|
385
420
|
|
|
386
421
|
let defaultExpr: DefaultExpr | undefined;
|
|
387
|
-
const defaultAttr = field.
|
|
422
|
+
const defaultAttr = field.attr(FIELD_ATTR_DEFAULT);
|
|
388
423
|
if (defaultAttr !== undefined) {
|
|
389
424
|
// SQL-expression detection runs on the raw string value — a string like
|
|
390
425
|
// "CURRENT_TIMESTAMP" or "now" must be emitted as sql`...`, not a literal.
|
|
@@ -407,21 +442,33 @@ export function mapColumnType(
|
|
|
407
442
|
}
|
|
408
443
|
}
|
|
409
444
|
|
|
410
|
-
//
|
|
411
|
-
//
|
|
445
|
+
// jsonb / JSON-in-text columns infer as `unknown` in Drizzle without a
|
|
446
|
+
// .$type<>() annotation. Carry the logical TS type so the column is typed:
|
|
447
|
+
// - SQLite isArray: arrays serialize as JSON-in-text → .$type<E[]>() (scalar
|
|
448
|
+
// element type, or the @objectRef VO for object arrays).
|
|
449
|
+
// - Postgres field.object: a single jsonb column → .$type<VO>(), or
|
|
450
|
+
// .$type<VO[]>() when isArray (the JSON array lives in the one column; no
|
|
451
|
+
// native .array() is emitted for object storage — see modifiers above).
|
|
452
|
+
// Scalar Postgres arrays use native .array() (already element-typed by
|
|
453
|
+
// Drizzle) so they need no $type.
|
|
412
454
|
let dollarTypeRef: ColumnSpec["dollarTypeRef"];
|
|
413
455
|
if (dialect === "sqlite" && isArray) {
|
|
414
456
|
if (subType === FIELD_SUBTYPE_OBJECT) {
|
|
415
|
-
const
|
|
416
|
-
if (
|
|
417
|
-
dollarTypeRef = { kind: "objectRef", name:
|
|
457
|
+
const base = objectRefBaseName(field);
|
|
458
|
+
if (base !== undefined) {
|
|
459
|
+
dollarTypeRef = { kind: "objectRef", name: base, array: true };
|
|
418
460
|
}
|
|
419
461
|
} else {
|
|
420
462
|
const scalar = sqliteJsonArrayElementTsType(subType);
|
|
421
463
|
if (scalar !== undefined) {
|
|
422
|
-
dollarTypeRef = { kind: "scalar", tsType: scalar as "string" | "number" | "boolean" };
|
|
464
|
+
dollarTypeRef = { kind: "scalar", tsType: scalar as "string" | "number" | "boolean", array: true };
|
|
423
465
|
}
|
|
424
466
|
}
|
|
467
|
+
} else if (dialect === "postgres" && subType === FIELD_SUBTYPE_OBJECT) {
|
|
468
|
+
const base = objectRefBaseName(field);
|
|
469
|
+
if (base !== undefined) {
|
|
470
|
+
dollarTypeRef = { kind: "objectRef", name: base, array: isArray };
|
|
471
|
+
}
|
|
425
472
|
}
|
|
426
473
|
|
|
427
474
|
const result: ColumnSpec = {
|
package/src/constants.ts
CHANGED
|
@@ -8,3 +8,21 @@ export const EXTRA_SUFFIX = ".extra";
|
|
|
8
8
|
|
|
9
9
|
/** Default outDir used by tests + as a sane default for generate(). */
|
|
10
10
|
export const DEFAULT_OUT_DIR = "./src/db/entities";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Codegen-control attributes.
|
|
14
|
+
//
|
|
15
|
+
// These are per-entity opt-in/opt-out flags read by generators (NOT metamodel
|
|
16
|
+
// vocabulary — they tune codegen, not the model). Named here so the literals
|
|
17
|
+
// aren't scattered as magic strings across the generator packages (compile-time
|
|
18
|
+
// typo safety), matching the metadata package's constants discipline.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/** `@emitTanstack: false` — skip the TanStack hooks + grid generators for an entity. */
|
|
22
|
+
export const CODEGEN_ATTR_EMIT_TANSTACK = "emitTanstack";
|
|
23
|
+
/** `@emitGrid: true` — opt a TPH subtype IN to its own per-subtype grid (default: the polymorphic base grid is the single source). */
|
|
24
|
+
export const CODEGEN_ATTR_EMIT_GRID = "emitGrid";
|
|
25
|
+
/** `@emitForm: false` — skip the React form generator for an entity. */
|
|
26
|
+
export const CODEGEN_ATTR_EMIT_FORM = "emitForm";
|
|
27
|
+
/** `@emitRoutes: false` — skip the Fastify routes generator for an entity. */
|
|
28
|
+
export const CODEGEN_ATTR_EMIT_ROUTES = "emitRoutes";
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// docs-paths.ts — the SINGLE source of truth for where a docs page is written
|
|
2
|
+
// AND how one page links to another. The file location and every inbound link
|
|
3
|
+
// href are derived from the SAME functions here, so they can never diverge.
|
|
4
|
+
//
|
|
5
|
+
// Why this matters: pages are placed by short name. In "flat" layout two nodes
|
|
6
|
+
// that share a short name across different packages (e.g. `acme::sales::Order`
|
|
7
|
+
// and `acme::billing::Order`) would both want `Order.md` and one would silently
|
|
8
|
+
// overwrite the other. `assertNoDuplicateDocPaths()` is the hard backstop that
|
|
9
|
+
// turns that data-loss into a clear error; "package" layout folds pages under
|
|
10
|
+
// package-path subdirs (`acme/sales/Order.md`) so multi-package models work.
|
|
11
|
+
|
|
12
|
+
import { PACKAGE_SEPARATOR } from "@metaobjectsdev/metadata";
|
|
13
|
+
import { relative as posixRelative } from "node:path/posix";
|
|
14
|
+
import { packageToPath, type OutputLayout } from "./import-path.js";
|
|
15
|
+
|
|
16
|
+
/** The minimal shape needed to place a docs page / compute a link to it: a
|
|
17
|
+
* short name and its EFFECTIVE package. Build one from a metadata node via
|
|
18
|
+
* `docPageNode()`. */
|
|
19
|
+
export interface DocPageNode {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly package?: string | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** A metadata node enough to derive page placement. `resolutionKey()` carries
|
|
25
|
+
* the EFFECTIVE package (own package OR the file-default captured at parse
|
|
26
|
+
* time) folded as `<pkg>::<name>` — `.package` alone is often undefined for
|
|
27
|
+
* objects (FR5d keeps object fqn() bare), so we read placement off the
|
|
28
|
+
* resolution key instead. */
|
|
29
|
+
interface PlaceableNode {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
resolutionKey(): string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Effective package of a placeable node: the prefix of `resolutionKey()`
|
|
35
|
+
* before the trailing `::<name>`, or undefined when the node is package-less. */
|
|
36
|
+
export function effectivePackage(node: PlaceableNode): string | undefined {
|
|
37
|
+
const key = node.resolutionKey();
|
|
38
|
+
const suffix = `${PACKAGE_SEPARATOR}${node.name}`;
|
|
39
|
+
if (key === node.name) return undefined;
|
|
40
|
+
if (key.endsWith(suffix)) {
|
|
41
|
+
const pkg = key.slice(0, key.length - suffix.length);
|
|
42
|
+
return pkg === "" ? undefined : pkg;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Build a placement node ({name, effective package}) from a metadata node. The
|
|
48
|
+
* single bridge from a loaded node to the path/href helpers — so file location
|
|
49
|
+
* and link href derive from the SAME effective package. */
|
|
50
|
+
export function docPageNode(node: PlaceableNode): DocPageNode {
|
|
51
|
+
return { name: node.name, package: effectivePackage(node) };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Output path (relative to the docs out dir) for a node's `.md` page.
|
|
55
|
+
* Flat → `<name>.md` (today's value, byte-identical). Package → folded under
|
|
56
|
+
* the package path (`acme/sales/Order.md`); a package-less node stays at root. */
|
|
57
|
+
export function docPageOutputPath(layout: OutputLayout, node: DocPageNode): string {
|
|
58
|
+
const filename = `${node.name}.md`;
|
|
59
|
+
if (layout === "flat") return filename;
|
|
60
|
+
const dir = packageToPath(node.package);
|
|
61
|
+
return dir === "" ? filename : `${dir}/${filename}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Relative href FROM `fromNode`'s page TO `toNode`'s page. Derived from the
|
|
65
|
+
* same `docPageOutputPath()` placement, so a link always points at the file's
|
|
66
|
+
* real location in BOTH layouts. Flat → `./<to>.md`; package → a correct
|
|
67
|
+
* relative path (e.g. `../comms/OrderEmail.md`). */
|
|
68
|
+
export function docPageHref(
|
|
69
|
+
layout: OutputLayout,
|
|
70
|
+
fromNode: DocPageNode,
|
|
71
|
+
toNode: DocPageNode,
|
|
72
|
+
): string {
|
|
73
|
+
const toPath = docPageOutputPath(layout, toNode);
|
|
74
|
+
if (layout === "flat") return `./${toPath}`;
|
|
75
|
+
// Relative path from the FROM page's directory to the TO page — the same
|
|
76
|
+
// raw-path rule surfaceCrossHref uses, so the two can never diverge.
|
|
77
|
+
return surfaceCrossHref(docPageOutputPath(layout, fromNode), toPath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Relative href between two doc pages whose output paths (relative to the shared
|
|
81
|
+
* docs outDir) may sit under different surface sub-roots — e.g. model `Order.md`
|
|
82
|
+
* and api `api/Order.md`. The shared relative-path rule, over raw paths;
|
|
83
|
+
* docPageHref delegates its package-layout branch here. */
|
|
84
|
+
export function surfaceCrossHref(fromOutputPath: string, toOutputPath: string): string {
|
|
85
|
+
const fromDir = fromOutputPath.includes("/") ? fromOutputPath.slice(0, fromOutputPath.lastIndexOf("/")) : "";
|
|
86
|
+
const rel = posixRelative(fromDir, toOutputPath);
|
|
87
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Href FROM a page (at `fromOutputPath`, relative to the docs root) TO a page
|
|
91
|
+
* (`page`, relative to the surface's own root) in an api surface. Relative via
|
|
92
|
+
* `surfaceCrossHref` when the surface is in the same tree; absolute `baseUrl/page`
|
|
93
|
+
* when the surface declares a baseUrl (federated / separate repo). */
|
|
94
|
+
export function apiSurfaceHref(
|
|
95
|
+
fromOutputPath: string,
|
|
96
|
+
surface: { subDir: string; baseUrl?: string },
|
|
97
|
+
page: string,
|
|
98
|
+
): string {
|
|
99
|
+
if (surface.baseUrl !== undefined && surface.baseUrl !== "") {
|
|
100
|
+
return `${surface.baseUrl.replace(/\/$/, "")}/${page}`;
|
|
101
|
+
}
|
|
102
|
+
return surfaceCrossHref(fromOutputPath, `${surface.subDir}/${page}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** A page about to be emitted, paired with the FQN of the node that produced it
|
|
106
|
+
* (for a precise collision diagnostic). */
|
|
107
|
+
export interface DocPagePlacement {
|
|
108
|
+
path: string;
|
|
109
|
+
fqn: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Hard backstop against silent overwrite (ALL layouts): if two placements
|
|
113
|
+
* resolve to the SAME output path, THROW naming both colliding node FQNs and
|
|
114
|
+
* the path. Guarantees a docs run never silently drops a page. */
|
|
115
|
+
export function assertNoDuplicateDocPaths(placements: DocPagePlacement[]): void {
|
|
116
|
+
const seen = new Map<string, string>();
|
|
117
|
+
for (const { path, fqn } of placements) {
|
|
118
|
+
const prior = seen.get(path);
|
|
119
|
+
if (prior !== undefined) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`docs: duplicate output path "${path}" from nodes ${prior} and ${fqn} — ` +
|
|
122
|
+
`use package layout (outputLayout: "package" / meta docs --layout package) ` +
|
|
123
|
+
`to disambiguate.`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
seen.set(path, fqn);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// FR-019 — import-specifier resolution for shared + provided enums.
|
|
2
|
+
//
|
|
3
|
+
// A consuming entity file references a shared enum `E` by importing it:
|
|
4
|
+
// • materialized (non-@provided) → from the generated shared enums module
|
|
5
|
+
// (`./enums`, at the entity-module target root, package-layout-aware).
|
|
6
|
+
// • @provided → from the per-port-configured module
|
|
7
|
+
// (`ctx.providedEnumModule`). Missing config ⇒ a codegen-time error naming
|
|
8
|
+
// the enum + the config key (ADR-0026: namespace is config, not metadata).
|
|
9
|
+
|
|
10
|
+
import { withExt } from "./render-context.js";
|
|
11
|
+
import type { RenderContext } from "./render-context.js";
|
|
12
|
+
import { relativeModuleSpecifier } from "./import-path.js";
|
|
13
|
+
import { SHARED_ENUMS_BASENAME } from "./templates/enums-file.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Specifier to import a MATERIALIZED shared enum into an entity file in
|
|
17
|
+
* `entityPkg`. The shared module sits at the entity-module target root; in
|
|
18
|
+
* package layout the entity may be nested, so the `./enums` base is adjusted by
|
|
19
|
+
* package depth.
|
|
20
|
+
*/
|
|
21
|
+
export function sharedEnumImportSpecifier(
|
|
22
|
+
ctx: RenderContext,
|
|
23
|
+
entityPkg: string | undefined,
|
|
24
|
+
): string {
|
|
25
|
+
const base = withExt(`./${SHARED_ENUMS_BASENAME}`, ctx.extStyle);
|
|
26
|
+
return relativeModuleSpecifier(ctx.selfTarget.outputLayout, entityPkg, base);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Specifier to import an externally-PROVIDED enum. Resolved from codegen config
|
|
31
|
+
* (`providedEnumModule`); throws a clear codegen-time error when unset.
|
|
32
|
+
*/
|
|
33
|
+
export function providedEnumImportSpecifier(ctx: RenderContext, enumName: string): string {
|
|
34
|
+
const mod = ctx.providedEnumModule;
|
|
35
|
+
if (mod === undefined || mod === "") {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`provided enum "${enumName}" is marked @provided but no module is configured ` +
|
|
38
|
+
`to import it from. Set "providedEnumModule" in your codegen config (e.g. ` +
|
|
39
|
+
`providedEnumModule: "@your-app/enums") so the generated code can reference "${enumName}".`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return mod;
|
|
43
|
+
}
|