@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
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
FIELD_SUBTYPE_STRING,
|
|
9
9
|
FIELD_SUBTYPE_INT,
|
|
10
10
|
FIELD_SUBTYPE_LONG,
|
|
11
|
-
FIELD_SUBTYPE_SHORT,
|
|
12
|
-
FIELD_SUBTYPE_BYTE,
|
|
13
11
|
FIELD_SUBTYPE_DOUBLE,
|
|
14
12
|
FIELD_SUBTYPE_FLOAT,
|
|
15
13
|
FIELD_SUBTYPE_DECIMAL,
|
|
@@ -54,8 +52,6 @@ function defaultViewForSubType(subType: string): string {
|
|
|
54
52
|
return VIEW_SUBTYPE_CHECKBOX;
|
|
55
53
|
case FIELD_SUBTYPE_INT:
|
|
56
54
|
case FIELD_SUBTYPE_LONG:
|
|
57
|
-
case FIELD_SUBTYPE_SHORT:
|
|
58
|
-
case FIELD_SUBTYPE_BYTE:
|
|
59
55
|
case FIELD_SUBTYPE_DOUBLE:
|
|
60
56
|
case FIELD_SUBTYPE_FLOAT:
|
|
61
57
|
case FIELD_SUBTYPE_DECIMAL:
|
|
@@ -92,8 +88,6 @@ export function zodTypeFor(field: MetaField): string {
|
|
|
92
88
|
return "z.string()";
|
|
93
89
|
case FIELD_SUBTYPE_INT:
|
|
94
90
|
case FIELD_SUBTYPE_LONG:
|
|
95
|
-
case FIELD_SUBTYPE_SHORT:
|
|
96
|
-
case FIELD_SUBTYPE_BYTE:
|
|
97
91
|
case FIELD_SUBTYPE_CURRENCY:
|
|
98
92
|
return "z.number().int()";
|
|
99
93
|
case FIELD_SUBTYPE_DOUBLE:
|
|
@@ -120,7 +114,7 @@ export function zodTypeFor(field: MetaField): string {
|
|
|
120
114
|
export function currencyMetaFor(field: MetaField): { currency: string; locale: string } | null {
|
|
121
115
|
if (field.subType !== FIELD_SUBTYPE_CURRENCY) return null;
|
|
122
116
|
const currency =
|
|
123
|
-
(field.
|
|
117
|
+
(field.attr(FIELD_ATTR_CURRENCY) as string | undefined) ?? FIELD_ATTR_CURRENCY_DEFAULT;
|
|
124
118
|
const viewChild = field.views().find((c) => c.subType === VIEW_SUBTYPE_CURRENCY);
|
|
125
119
|
const locale =
|
|
126
120
|
(viewChild?.ownAttr(VIEW_CURRENCY_ATTR_LOCALE) as string | undefined) ??
|
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
FIELD_ATTR_SORTABLE_DEFAULT_ORDER,
|
|
6
6
|
FIELD_SUBTYPE_BOOLEAN,
|
|
7
7
|
FIELD_SUBTYPE_INT,
|
|
8
|
-
FIELD_SUBTYPE_SHORT,
|
|
9
|
-
FIELD_SUBTYPE_BYTE,
|
|
10
8
|
FIELD_SUBTYPE_LONG,
|
|
11
9
|
FIELD_SUBTYPE_DOUBLE,
|
|
12
10
|
FIELD_SUBTYPE_FLOAT,
|
|
@@ -14,18 +12,19 @@ import {
|
|
|
14
12
|
FIELD_SUBTYPE_DATE,
|
|
15
13
|
FIELD_SUBTYPE_TIME,
|
|
16
14
|
FIELD_SUBTYPE_TIMESTAMP,
|
|
15
|
+
FIELD_SUBTYPE_CURRENCY,
|
|
17
16
|
opsForSubType,
|
|
18
17
|
} from "@metaobjectsdev/metadata";
|
|
19
18
|
import { sortableFields } from "./filter-shared.js";
|
|
20
19
|
|
|
21
20
|
const NUMBER_SUBTYPES = new Set<string>([
|
|
22
21
|
FIELD_SUBTYPE_INT,
|
|
23
|
-
FIELD_SUBTYPE_SHORT,
|
|
24
|
-
FIELD_SUBTYPE_BYTE,
|
|
25
22
|
FIELD_SUBTYPE_LONG,
|
|
26
23
|
FIELD_SUBTYPE_DOUBLE,
|
|
27
24
|
FIELD_SUBTYPE_FLOAT,
|
|
28
25
|
FIELD_SUBTYPE_DECIMAL,
|
|
26
|
+
// currency is integer minor units — coerces as a number on the wire.
|
|
27
|
+
FIELD_SUBTYPE_CURRENCY,
|
|
29
28
|
]);
|
|
30
29
|
|
|
31
30
|
const DATETIME_SUBTYPES = new Set<string>([
|
|
@@ -42,13 +41,20 @@ function filterSubTypeFor(fieldSubType: string): "string" | "number" | "boolean"
|
|
|
42
41
|
return "string";
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
function filterableFields(entity: MetaObject): MetaField[] {
|
|
44
|
+
function filterableFields(entity: MetaObject, exclude?: string): MetaField[] {
|
|
46
45
|
// fields() returns effective fields, so inherited fields (from extends:/super:) are included in allowlists.
|
|
47
|
-
return entity
|
|
46
|
+
return entity
|
|
47
|
+
.fields()
|
|
48
|
+
.filter((c) => c.attr(FIELD_ATTR_FILTERABLE) === true && c.name !== exclude);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
/**
|
|
52
|
+
* `exclude` (FR-017): drop a field from the allowlist. Used by per-subtype TPH
|
|
53
|
+
* allowlists to omit the discriminator — it's pinned by the per-subtype route
|
|
54
|
+
* path, so a client must not filter on it.
|
|
55
|
+
*/
|
|
56
|
+
export function renderFilterAllowlist(entity: MetaObject, exclude?: string): Code {
|
|
57
|
+
const fields = filterableFields(entity, exclude);
|
|
52
58
|
if (fields.length === 0) {
|
|
53
59
|
return code`
|
|
54
60
|
import type { FilterAllowlist } from "@metaobjectsdev/runtime-ts/drizzle-fastify";
|
|
@@ -72,11 +78,12 @@ ${rows}
|
|
|
72
78
|
`;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
export function renderSortAllowlist(entity: MetaObject): Code {
|
|
81
|
+
export function renderSortAllowlist(entity: MetaObject, exclude?: string): Code {
|
|
76
82
|
// Sortable = explicit @sortable === true, OR (no @sortable AND @filterable === true).
|
|
77
83
|
// @sortable: false explicitly opts out.
|
|
78
84
|
// Uses shared isSortableField predicate — must stay in sync with renderFilterType.
|
|
79
|
-
|
|
85
|
+
// `exclude` (FR-017): per-subtype TPH allowlists omit the discriminator.
|
|
86
|
+
const sortable = sortableFields(entity).filter((f) => f.name !== exclude);
|
|
80
87
|
if (sortable.length === 0) {
|
|
81
88
|
return code`
|
|
82
89
|
import type { SortAllowlist } from "@metaobjectsdev/runtime-ts/drizzle-fastify";
|
|
@@ -86,7 +93,7 @@ export const ${entity.name}SortAllowlist = {} as const satisfies SortAllowlist;
|
|
|
86
93
|
}
|
|
87
94
|
const rows = sortable
|
|
88
95
|
.map((f) => {
|
|
89
|
-
const defaultOrder = f.
|
|
96
|
+
const defaultOrder = f.attr(FIELD_ATTR_SORTABLE_DEFAULT_ORDER) as string | undefined;
|
|
90
97
|
const rule =
|
|
91
98
|
defaultOrder === "asc" || defaultOrder === "desc"
|
|
92
99
|
? `{ defaultOrder: ${JSON.stringify(defaultOrder)} as const }`
|
|
@@ -15,10 +15,10 @@ import { FIELD_ATTR_FILTERABLE, FIELD_ATTR_SORTABLE } from "@metaobjectsdev/meta
|
|
|
15
15
|
* 3. no @sortable → sortable iff @filterable === true
|
|
16
16
|
*/
|
|
17
17
|
export function isSortableField(field: MetaField): boolean {
|
|
18
|
-
const sortableAttr = field.
|
|
18
|
+
const sortableAttr = field.attr(FIELD_ATTR_SORTABLE);
|
|
19
19
|
if (sortableAttr === true) return true;
|
|
20
20
|
if (sortableAttr === false) return false;
|
|
21
|
-
return field.
|
|
21
|
+
return field.attr(FIELD_ATTR_FILTERABLE) === true;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
FIELD_ATTR_FILTERABLE,
|
|
9
9
|
FIELD_SUBTYPE_BOOLEAN,
|
|
10
10
|
FIELD_SUBTYPE_INT,
|
|
11
|
-
FIELD_SUBTYPE_SHORT,
|
|
12
|
-
FIELD_SUBTYPE_BYTE,
|
|
13
11
|
FIELD_SUBTYPE_LONG,
|
|
14
12
|
FIELD_SUBTYPE_DOUBLE,
|
|
15
13
|
FIELD_SUBTYPE_FLOAT,
|
|
@@ -23,8 +21,6 @@ import { isSortableField } from "./filter-shared.js";
|
|
|
23
21
|
// matching the entity field representation (exact decimal string, not lossy number).
|
|
24
22
|
const NUMBER_VALUE_SUBTYPES = new Set<string>([
|
|
25
23
|
FIELD_SUBTYPE_INT,
|
|
26
|
-
FIELD_SUBTYPE_SHORT,
|
|
27
|
-
FIELD_SUBTYPE_BYTE,
|
|
28
24
|
FIELD_SUBTYPE_LONG,
|
|
29
25
|
FIELD_SUBTYPE_DOUBLE,
|
|
30
26
|
FIELD_SUBTYPE_FLOAT,
|
|
@@ -49,10 +45,16 @@ function renderFieldUnion(field: MetaField): string {
|
|
|
49
45
|
return `${tsName} | { ${opEntries.join("; ")} }`;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
|
|
48
|
+
/**
|
|
49
|
+
* `exclude` (FR-017): drop a field from the client filter type. Used by
|
|
50
|
+
* per-subtype TPH filter types to omit the discriminator (it's pinned by the
|
|
51
|
+
* per-subtype route path), keeping the client `<Sub>Filter` type aligned with
|
|
52
|
+
* the server's per-subtype allowlist.
|
|
53
|
+
*/
|
|
54
|
+
export function renderFilterType(entity: MetaObject, exclude?: string): Code {
|
|
53
55
|
// fields() returns effective fields, so inherited fields (from extends:/super:) are included in filter types.
|
|
54
|
-
const allFields = entity.fields();
|
|
55
|
-
const filterableFieldsList = allFields.filter((c) => c.
|
|
56
|
+
const allFields = entity.fields().filter((c) => c.name !== exclude);
|
|
57
|
+
const filterableFieldsList = allFields.filter((c) => c.attr(FIELD_ATTR_FILTERABLE) === true);
|
|
56
58
|
// Sort union uses isSortableField — same predicate as renderSortAllowlist to prevent
|
|
57
59
|
// client/server mismatches (@filterable: true + @sortable: false must be excluded from both).
|
|
58
60
|
const sortFieldNames = allFields.filter(isSortableField).map((f) => `"${f.name}"`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MetaData } from "@metaobjectsdev/metadata";
|
|
2
|
+
import { TYPE_TEMPLATE } from "@metaobjectsdev/metadata";
|
|
3
|
+
|
|
4
|
+
/** All template nodes of `subType` anywhere in the tree (top-level OR nested in entities). */
|
|
5
|
+
export function findTemplates(root: MetaData, subType: string): MetaData[] {
|
|
6
|
+
const out: MetaData[] = [];
|
|
7
|
+
const visit = (node: MetaData) => {
|
|
8
|
+
for (const child of node.ownChildren()) {
|
|
9
|
+
if (child.type === TYPE_TEMPLATE && child.subType === subType) out.push(child);
|
|
10
|
+
visit(child);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
visit(root);
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// server/typescript/packages/codegen-ts/src/templates/fr010-field-mapping.ts
|
|
2
2
|
//
|
|
3
|
-
// Shared field-kind mapping for the FR-010 codegen emitters (
|
|
4
|
-
//
|
|
3
|
+
// Shared field-kind mapping for the FR-010 codegen emitters (the output-format-spec
|
|
4
|
+
// emitter et al.). Maps a metadata field subtype onto the render engine's
|
|
5
5
|
// FieldKind member, the idiomatic nullable TS type used by the extract mirror interface,
|
|
6
6
|
// and the ExtractMap accessor that reads it from the forgiving outcome map.
|
|
7
7
|
//
|
|
@@ -13,14 +13,11 @@ import {
|
|
|
13
13
|
type MetaData,
|
|
14
14
|
TYPE_FIELD,
|
|
15
15
|
FIELD_SUBTYPE_STRING,
|
|
16
|
-
FIELD_SUBTYPE_CLASS,
|
|
17
16
|
FIELD_SUBTYPE_UUID,
|
|
18
17
|
FIELD_SUBTYPE_DATE,
|
|
19
18
|
FIELD_SUBTYPE_TIME,
|
|
20
19
|
FIELD_SUBTYPE_TIMESTAMP,
|
|
21
20
|
FIELD_SUBTYPE_INT,
|
|
22
|
-
FIELD_SUBTYPE_SHORT,
|
|
23
|
-
FIELD_SUBTYPE_BYTE,
|
|
24
21
|
FIELD_SUBTYPE_LONG,
|
|
25
22
|
FIELD_SUBTYPE_CURRENCY,
|
|
26
23
|
FIELD_SUBTYPE_DOUBLE,
|
|
@@ -34,6 +31,7 @@ import {
|
|
|
34
31
|
FIELD_ATTR_COERCE_DEFAULT,
|
|
35
32
|
FIELD_ATTR_DEFAULT,
|
|
36
33
|
FIELD_ATTR_NORMALIZE,
|
|
34
|
+
FIELD_ATTR_XML_TEXT,
|
|
37
35
|
NORMALIZE_DEFAULT,
|
|
38
36
|
type NormalizeMode,
|
|
39
37
|
} from "@metaobjectsdev/metadata";
|
|
@@ -42,7 +40,6 @@ import {
|
|
|
42
40
|
export function scalarKind(subType: string): string | null {
|
|
43
41
|
switch (subType) {
|
|
44
42
|
case FIELD_SUBTYPE_STRING:
|
|
45
|
-
case FIELD_SUBTYPE_CLASS:
|
|
46
43
|
case FIELD_SUBTYPE_UUID:
|
|
47
44
|
case FIELD_SUBTYPE_DATE:
|
|
48
45
|
case FIELD_SUBTYPE_TIME:
|
|
@@ -53,8 +50,6 @@ export function scalarKind(subType: string): string | null {
|
|
|
53
50
|
case FIELD_SUBTYPE_DECIMAL:
|
|
54
51
|
return "STRING";
|
|
55
52
|
case FIELD_SUBTYPE_INT:
|
|
56
|
-
case FIELD_SUBTYPE_SHORT:
|
|
57
|
-
case FIELD_SUBTYPE_BYTE:
|
|
58
53
|
return "INT";
|
|
59
54
|
case FIELD_SUBTYPE_LONG:
|
|
60
55
|
case FIELD_SUBTYPE_CURRENCY:
|
|
@@ -81,14 +76,21 @@ export function isArray(field: MetaData): boolean {
|
|
|
81
76
|
|
|
82
77
|
/** True iff the field's @required is explicitly true (or the string "true"). */
|
|
83
78
|
export function isRequired(field: MetaData): boolean {
|
|
84
|
-
const v = field.
|
|
79
|
+
const v = field.attr(FIELD_ATTR_REQUIRED);
|
|
80
|
+
if (v === true) return true;
|
|
81
|
+
return typeof v === "string" && v.toLowerCase() === "true";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** True iff the field's @xmlText is explicitly true (the XML text-content extract marker). */
|
|
85
|
+
export function xmlText(field: MetaData): boolean {
|
|
86
|
+
const v = field.attr(FIELD_ATTR_XML_TEXT);
|
|
85
87
|
if (v === true) return true;
|
|
86
88
|
return typeof v === "string" && v.toLowerCase() === "true";
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
/** The string members of an enum field's @values attr (empty when absent). */
|
|
90
92
|
export function enumValues(field: MetaData): string[] {
|
|
91
|
-
const v = field.
|
|
93
|
+
const v = field.attr(FIELD_ATTR_VALUES);
|
|
92
94
|
if (Array.isArray(v)) return v.map((e) => String(e));
|
|
93
95
|
return [];
|
|
94
96
|
}
|
|
@@ -98,7 +100,7 @@ export function enumValues(field: MetaData): string[] {
|
|
|
98
100
|
* or null when absent. Read own-attr only — `@coerceDefault` is concrete, never inherited.
|
|
99
101
|
*/
|
|
100
102
|
export function coerceDefault(field: MetaData): string | null {
|
|
101
|
-
const v = field.
|
|
103
|
+
const v = field.attr(FIELD_ATTR_COERCE_DEFAULT);
|
|
102
104
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -106,7 +108,7 @@ export function coerceDefault(field: MetaData): string | null {
|
|
|
106
108
|
* FR-011: the field's `@default` member symbol (absent-fill enum value), or null when absent.
|
|
107
109
|
*/
|
|
108
110
|
export function defaultValue(field: MetaData): string | null {
|
|
109
|
-
const v = field.
|
|
111
|
+
const v = field.attr(FIELD_ATTR_DEFAULT);
|
|
110
112
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -126,7 +128,7 @@ export function resolveNormalize(field: MetaData, ownerObject: MetaData | null):
|
|
|
126
128
|
|
|
127
129
|
/** The `@normalize` attr of a node as a NormalizeMode, or null when absent. */
|
|
128
130
|
function normalizeAttrOf(node: MetaData): NormalizeMode | null {
|
|
129
|
-
const v = node.
|
|
131
|
+
const v = node.attr(FIELD_ATTR_NORMALIZE);
|
|
130
132
|
return typeof v === "string" && v.length > 0 ? (v as NormalizeMode) : null;
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -14,8 +14,6 @@ import {
|
|
|
14
14
|
FIELD_SUBTYPE_OBJECT,
|
|
15
15
|
FIELD_SUBTYPE_STRING,
|
|
16
16
|
FIELD_SUBTYPE_INT,
|
|
17
|
-
FIELD_SUBTYPE_SHORT,
|
|
18
|
-
FIELD_SUBTYPE_BYTE,
|
|
19
17
|
FIELD_SUBTYPE_LONG,
|
|
20
18
|
FIELD_SUBTYPE_DOUBLE,
|
|
21
19
|
FIELD_SUBTYPE_FLOAT,
|
|
@@ -25,23 +23,41 @@ import {
|
|
|
25
23
|
FIELD_SUBTYPE_DATE,
|
|
26
24
|
FIELD_SUBTYPE_TIME,
|
|
27
25
|
FIELD_SUBTYPE_TIMESTAMP,
|
|
28
|
-
FIELD_SUBTYPE_CLASS,
|
|
29
26
|
FIELD_SUBTYPE_UUID,
|
|
30
27
|
FIELD_ATTR_REQUIRED,
|
|
31
28
|
FIELD_ATTR_OBJECT_REF,
|
|
32
29
|
} from "@metaobjectsdev/metadata";
|
|
33
30
|
import { variableNameFromEntity, toPascalCase } from "../naming.js";
|
|
31
|
+
import { valueObjectModuleSpecifier } from "../import-path.js";
|
|
32
|
+
import { stripPackage } from "@metaobjectsdev/metadata";
|
|
34
33
|
import { enumValues } from "../enum-meta.js";
|
|
35
34
|
import { renderDocsFor } from "./jsdoc.js";
|
|
35
|
+
import { sharedEnumForField } from "../enum-shared.js";
|
|
36
|
+
import { sharedEnumImportSpecifier, providedEnumImportSpecifier } from "../enum-import.js";
|
|
37
|
+
import type { RenderContext } from "../render-context.js";
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Emit Drizzle's InferSelectModel / InferInsertModel aliases for an entity.
|
|
41
|
+
*
|
|
42
|
+
* `tphBase` (FR-017): when this entity is a TPH discriminator base, the
|
|
43
|
+
* discriminated-union type (emitted by the tph-discriminator template) owns the
|
|
44
|
+
* bare `<Base>` name, so the raw single-table row type is emitted as `<Base>Row`
|
|
45
|
+
* to avoid a duplicate `export type <Base>`. Insert/Update keep their names
|
|
46
|
+
* (no collision); they describe the physical TPH table row shape.
|
|
47
|
+
*/
|
|
48
|
+
export function renderInferredTypes(entity: MetaObject, tphBase = false, ctx?: RenderContext): Code {
|
|
49
|
+
// The inferred Row/Insert types reference the Drizzle table var, so they must
|
|
50
|
+
// resolve to the SAME (possibly overridden) collection name the schema emits.
|
|
51
|
+
// ctx is optional for bare unit-test calls — those fall back to the default
|
|
52
|
+
// always-pluralize spelling.
|
|
53
|
+
const varName = ctx ? ctx.collectionName(entity.name) : variableNameFromEntity(entity.name);
|
|
39
54
|
const selectSym = imp("InferSelectModel@drizzle-orm");
|
|
40
55
|
const insertSym = imp("InferInsertModel@drizzle-orm");
|
|
41
56
|
const docs = renderDocsFor(entity);
|
|
42
57
|
const docsPrefix = docs ? `${docs}\n` : "";
|
|
58
|
+
const rowName = tphBase ? `${entity.name}Row` : entity.name;
|
|
43
59
|
return code`
|
|
44
|
-
${docsPrefix}export type ${
|
|
60
|
+
${docsPrefix}export type ${rowName} = ${selectSym}<typeof ${varName}>;
|
|
45
61
|
export type ${entity.name}Insert = ${insertSym}<typeof ${varName}>;
|
|
46
62
|
export type ${entity.name}Update = Partial<${entity.name}Insert>;
|
|
47
63
|
`;
|
|
@@ -71,12 +87,23 @@ export function enumUnionString(values: string[]): string {
|
|
|
71
87
|
}
|
|
72
88
|
|
|
73
89
|
/**
|
|
74
|
-
* Emit
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
90
|
+
* Emit the enum type-alias section for an entity file. Three cases per field:
|
|
91
|
+
*
|
|
92
|
+
* • inline enum (members declared directly on the field; no root-abstract super)
|
|
93
|
+
* → `export type <Entity><Field> = "A" | "B";` — UNCHANGED (byte-identical).
|
|
94
|
+
* • shared materialized enum (extends a NON-@provided root-level abstract
|
|
95
|
+
* field.enum) → re-export the materialized type from the shared `./enums`
|
|
96
|
+
* module (`export { type E } from "./enums"`) instead of redeclaring it. The
|
|
97
|
+
* type is materialized ONCE in enums.ts (FR-019).
|
|
98
|
+
* • provided enum (extends a @provided root-level abstract field.enum) →
|
|
99
|
+
* re-export the type from the configured external module
|
|
100
|
+
* (`export { type E } from "<providedEnumModule>"`); metaobjects emits no
|
|
101
|
+
* declaration for it. A missing config is a codegen-time error.
|
|
102
|
+
*
|
|
103
|
+
* `ctx` is required to compute the shared/provided import specifiers. Returns
|
|
104
|
+
* null when the entity has no enum-alias lines to emit.
|
|
78
105
|
*/
|
|
79
|
-
export function renderEnumTypeAliases(entity: MetaObject): Code | null {
|
|
106
|
+
export function renderEnumTypeAliases(entity: MetaObject, ctx?: RenderContext): Code | null {
|
|
80
107
|
// De-duplicate by type-alias name — multiple fields can extend the same abstract enum.
|
|
81
108
|
const seen = new Set<string>();
|
|
82
109
|
const lines: string[] = [];
|
|
@@ -91,7 +118,21 @@ export function renderEnumTypeAliases(entity: MetaObject): Code | null {
|
|
|
91
118
|
if (seen.has(typeName)) continue;
|
|
92
119
|
seen.add(typeName);
|
|
93
120
|
|
|
94
|
-
|
|
121
|
+
// Without a RenderContext (bare unit-test calls) the shared/provided import
|
|
122
|
+
// specifiers can't be computed — fall back to inline emission. Real runs
|
|
123
|
+
// always pass ctx (entity-file template), so shared materialization applies.
|
|
124
|
+
const shared = ctx !== undefined ? sharedEnumForField(field) : undefined;
|
|
125
|
+
if (shared === undefined) {
|
|
126
|
+
// Inline enum — emit the literal union exactly as before.
|
|
127
|
+
lines.push(`export type ${typeName} = ${enumUnionString(values)};`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Shared / provided enum — re-export from the materialized module or the
|
|
131
|
+
// configured external module; never redeclare the union here.
|
|
132
|
+
const spec = shared.provided
|
|
133
|
+
? providedEnumImportSpecifier(ctx!, shared.name)
|
|
134
|
+
: sharedEnumImportSpecifier(ctx!, entity.package);
|
|
135
|
+
lines.push(`export { type ${shared.name} } from ${JSON.stringify(spec)};`);
|
|
95
136
|
}
|
|
96
137
|
|
|
97
138
|
return lines.length > 0 ? code`${lines.join("\n")}` : null;
|
|
@@ -103,11 +144,8 @@ export function renderEnumTypeAliases(entity: MetaObject): Code | null {
|
|
|
103
144
|
|
|
104
145
|
const SCALAR_TS_BY_SUBTYPE: Record<string, string> = {
|
|
105
146
|
[FIELD_SUBTYPE_STRING]: "string",
|
|
106
|
-
[FIELD_SUBTYPE_CLASS]: "string",
|
|
107
147
|
[FIELD_SUBTYPE_UUID]: "string",
|
|
108
148
|
[FIELD_SUBTYPE_INT]: "number",
|
|
109
|
-
[FIELD_SUBTYPE_SHORT]: "number",
|
|
110
|
-
[FIELD_SUBTYPE_BYTE]: "number",
|
|
111
149
|
[FIELD_SUBTYPE_LONG]: "number",
|
|
112
150
|
[FIELD_SUBTYPE_DOUBLE]: "number",
|
|
113
151
|
[FIELD_SUBTYPE_FLOAT]: "number",
|
|
@@ -122,19 +160,68 @@ const SCALAR_TS_BY_SUBTYPE: Record<string, string> = {
|
|
|
122
160
|
[FIELD_SUBTYPE_TIMESTAMP]: "string",
|
|
123
161
|
};
|
|
124
162
|
|
|
163
|
+
/**
|
|
164
|
+
* The PLAIN-STRING TS type expression for a field — the SINGLE source of truth
|
|
165
|
+
* for "what TS type does the codegen give this field". `valueObjectFieldType`
|
|
166
|
+
* (which returns a `Code` so cross-module `field.object` refs hoist via
|
|
167
|
+
* `imp(...)`) makes the SAME per-branch decisions; this string form exists for
|
|
168
|
+
* consumers (the api-docs field-shape builder) that need the type name as text,
|
|
169
|
+
* not a hoisting `Code`. The branch logic MUST stay in lock-step with
|
|
170
|
+
* `valueObjectFieldType` below.
|
|
171
|
+
*
|
|
172
|
+
* • field.object → the referenced object's bare (package-stripped) name, `[]`
|
|
173
|
+
* when an array; `unknown` / `unknown[]` when the @objectRef is missing.
|
|
174
|
+
* • field.enum → the same enum-union alias `enumUnionAliasName` emits
|
|
175
|
+
* (`<Owner><Field>` or the abstract super's PascalCase), `string` fallback.
|
|
176
|
+
* • scalar → SCALAR_TS_BY_SUBTYPE (else `unknown`), `[]` when an array.
|
|
177
|
+
*/
|
|
178
|
+
export function fieldTsTypeString(ownerName: string, field: MetaField): string {
|
|
179
|
+
if (field.subType === FIELD_SUBTYPE_OBJECT) {
|
|
180
|
+
const ref = field.attr(FIELD_ATTR_OBJECT_REF);
|
|
181
|
+
if (typeof ref === "string" && ref.length > 0) {
|
|
182
|
+
const base = stripPackage(ref);
|
|
183
|
+
return field.isArray ? `${base}[]` : base;
|
|
184
|
+
}
|
|
185
|
+
return field.isArray ? "unknown[]" : "unknown";
|
|
186
|
+
}
|
|
187
|
+
if (field.subType === FIELD_SUBTYPE_ENUM) {
|
|
188
|
+
const values = enumValues(field);
|
|
189
|
+
if (values !== undefined) {
|
|
190
|
+
// The emitted TS type is an enum-union ALIAS (`<Owner><Field>`), but its
|
|
191
|
+
// definition IS this literal union — inline it so the documented shape is
|
|
192
|
+
// self-contained (an agent sees the exact allowed values, not an opaque
|
|
193
|
+
// alias name). Array enums wrap the parenthesized union: `(A | B)[]`.
|
|
194
|
+
const union = enumUnionString(values);
|
|
195
|
+
return field.isArray ? `(${union})[]` : union;
|
|
196
|
+
}
|
|
197
|
+
return field.isArray ? "string[]" : "string";
|
|
198
|
+
}
|
|
199
|
+
const scalar = SCALAR_TS_BY_SUBTYPE[field.subType] ?? "unknown";
|
|
200
|
+
return field.isArray ? `${scalar}[]` : scalar;
|
|
201
|
+
}
|
|
202
|
+
|
|
125
203
|
/**
|
|
126
204
|
* One-line TS type expression for a field on a value-only object.
|
|
127
205
|
* Returns a `Code` so cross-module `field.object` refs can be hoisted via
|
|
128
206
|
* ts-poet `imp(...)` — matching how the Zod emitter hoists `<Ref>InsertSchema`.
|
|
129
207
|
*/
|
|
130
|
-
function valueObjectFieldType(entity: MetaObject, field: MetaField): Code {
|
|
208
|
+
function valueObjectFieldType(entity: MetaObject, field: MetaField, ctx?: RenderContext): Code {
|
|
131
209
|
// field.object: import the referenced TS interface from its sibling module
|
|
132
210
|
// so ts-poet hoists the import. Mirrors zod-validators.ts's `<Ref>InsertSchema`
|
|
133
211
|
// import strategy, just for the type alias instead of the schema constant.
|
|
134
212
|
if (field.subType === FIELD_SUBTYPE_OBJECT) {
|
|
135
|
-
const ref = field.
|
|
213
|
+
const ref = field.attr(FIELD_ATTR_OBJECT_REF);
|
|
136
214
|
if (typeof ref === "string" && ref.length > 0) {
|
|
137
|
-
|
|
215
|
+
// @objectRef may be authored fully-qualified (acme::sales::Brief) or bare; the
|
|
216
|
+
// referenced interface is named by the BARE short name. The import MODULE is
|
|
217
|
+
// resolved through the shared layout/package/extStyle-aware helper (the SAME
|
|
218
|
+
// one the Zod schema + Drizzle .$type<> use) so all three agree. Without a
|
|
219
|
+
// ctx (bare unit-test calls) fall back to the flat same-dir specifier.
|
|
220
|
+
const base = stripPackage(ref);
|
|
221
|
+
const moduleSpec = ctx
|
|
222
|
+
? valueObjectModuleSpecifier(base, ctx.packageOf, entity.package, ctx.outputLayout, ctx.extStyle)
|
|
223
|
+
: `./${base}.js`;
|
|
224
|
+
const refImp = imp(`${base}@${moduleSpec}`);
|
|
138
225
|
return field.isArray ? code`${refImp}[]` : code`${refImp}`;
|
|
139
226
|
}
|
|
140
227
|
return field.isArray ? code`unknown[]` : code`unknown`;
|
|
@@ -145,6 +232,20 @@ function valueObjectFieldType(entity: MetaObject, field: MetaField): Code {
|
|
|
145
232
|
const values = enumValues(field);
|
|
146
233
|
if (values !== undefined) {
|
|
147
234
|
const alias = enumUnionAliasName(entity.name, field);
|
|
235
|
+
// FR-019: a shared/provided enum's type lives in another module (./enums or
|
|
236
|
+
// the provided module). Use imp() so ts-poet hoists `import { type E }` —
|
|
237
|
+
// the local interface can then reference E. Inline enums reference the
|
|
238
|
+
// locally-declared `<Entity><Field>` alias as before.
|
|
239
|
+
if (ctx !== undefined) {
|
|
240
|
+
const shared = sharedEnumForField(field);
|
|
241
|
+
if (shared !== undefined) {
|
|
242
|
+
const spec = shared.provided
|
|
243
|
+
? providedEnumImportSpecifier(ctx, shared.name)
|
|
244
|
+
: sharedEnumImportSpecifier(ctx, entity.package);
|
|
245
|
+
const sym = imp(`${shared.name}@${spec}`);
|
|
246
|
+
return field.isArray ? code`${sym}[]` : code`${sym}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
148
249
|
return field.isArray ? code`${alias}[]` : code`${alias}`;
|
|
149
250
|
}
|
|
150
251
|
return field.isArray ? code`string[]` : code`string`;
|
|
@@ -162,15 +263,15 @@ function valueObjectFieldType(entity: MetaObject, field: MetaField): Code {
|
|
|
162
263
|
* trip through Drizzle nullable columns, so the null-bridge is unnecessary
|
|
163
264
|
* here — and forces consumers into a residual cast at the call site.
|
|
164
265
|
*/
|
|
165
|
-
export function renderValueObjectInterface(entity: MetaObject): Code {
|
|
266
|
+
export function renderValueObjectInterface(entity: MetaObject, ctx?: RenderContext): Code {
|
|
166
267
|
const docs = renderDocsFor(entity);
|
|
167
268
|
const docsPrefix = docs ? `${docs}\n` : "";
|
|
168
269
|
|
|
169
270
|
const lines: Code[] = [];
|
|
170
271
|
for (const field of entity.fields()) {
|
|
171
|
-
const required = field.
|
|
272
|
+
const required = field.attr(FIELD_ATTR_REQUIRED) === true;
|
|
172
273
|
const optional = required ? "" : "?";
|
|
173
|
-
const tsType = valueObjectFieldType(entity, field);
|
|
274
|
+
const tsType = valueObjectFieldType(entity, field, ctx);
|
|
174
275
|
lines.push(code` ${field.name}${optional}: ${tsType};`);
|
|
175
276
|
}
|
|
176
277
|
|