langium-zod 0.5.3 → 0.6.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/README.md +23 -0
- package/dist/api.d.ts +123 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +151 -0
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts +76 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +105 -12
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +133 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -0
- package/dist/config.js.map +1 -1
- package/dist/conformance.d.ts.map +1 -1
- package/dist/conformance.js.map +1 -1
- package/dist/di.d.ts +154 -0
- package/dist/di.d.ts.map +1 -1
- package/dist/di.js +98 -0
- package/dist/di.js.map +1 -1
- package/dist/emitters/domain.d.ts +23 -0
- package/dist/emitters/domain.d.ts.map +1 -0
- package/dist/emitters/domain.js +269 -0
- package/dist/emitters/domain.js.map +1 -0
- package/dist/errors.d.ts +62 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +62 -0
- package/dist/errors.js.map +1 -1
- package/dist/extractor.d.ts +83 -0
- package/dist/extractor.d.ts.map +1 -1
- package/dist/extractor.js +91 -3
- package/dist/extractor.js.map +1 -1
- package/dist/generator.d.ts +81 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +99 -14
- package/dist/generator.js.map +1 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/projection.d.ts.map +1 -1
- package/dist/projection.js.map +1 -1
- package/dist/recursion-detector.d.ts +66 -0
- package/dist/recursion-detector.d.ts.map +1 -1
- package/dist/recursion-detector.js +66 -0
- package/dist/recursion-detector.js.map +1 -1
- package/dist/ref-utils.d.ts +79 -0
- package/dist/ref-utils.d.ts.map +1 -1
- package/dist/ref-utils.js +79 -0
- package/dist/ref-utils.js.map +1 -1
- package/dist/type-mapper.d.ts.map +1 -1
- package/dist/type-mapper.js.map +1 -1
- package/dist/types.d.ts +163 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -64,3 +64,26 @@ Generated output uses Zod 4 and exports named schemas like `<TypeName>Schema`.
|
|
|
64
64
|
- Langium 4.x
|
|
65
65
|
- Zod 4.x
|
|
66
66
|
|
|
67
|
+
## Domain target (experimental)
|
|
68
|
+
|
|
69
|
+
Besides Zod schemas, langium-zod can emit a **domain surface** — quirk-free read
|
|
70
|
+
interfaces, a `toDomain(node)` read projection, and field-precise write accessors:
|
|
71
|
+
|
|
72
|
+
langium-zod generate --domain --domain-out src/generated/domain.ts
|
|
73
|
+
|
|
74
|
+
Mechanical rules are generic (a single cross-reference flattens to a `$refText`
|
|
75
|
+
string). Project-specific renames and read-only merges are supplied via
|
|
76
|
+
`domainOverlays` in `langium-zod.config.js`:
|
|
77
|
+
|
|
78
|
+
export default {
|
|
79
|
+
domainOverlays: {
|
|
80
|
+
types: {
|
|
81
|
+
Choice: { renames: { attributes: 'options' } },
|
|
82
|
+
RosettaFunction: { merges: [{ from: ['conditions', 'postConditions'], to: 'conditions' }] }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
Merges are read-only on the merged name; write accessors target the source
|
|
88
|
+
fields (`addConditions`, `addPostConditions`) — there is no merged setter.
|
|
89
|
+
|
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,127 @@
|
|
|
1
1
|
import type { ZodGeneratorConfig } from './config.js';
|
|
2
2
|
export type PublicZodGeneratorConfig = ZodGeneratorConfig;
|
|
3
|
+
/**
|
|
4
|
+
* Main entry point for programmatic Zod schema generation from a Langium grammar.
|
|
5
|
+
*
|
|
6
|
+
* Accepts a {@link ZodGeneratorConfig} that specifies either a parsed Langium
|
|
7
|
+
* `Grammar` object or a pre-built {@link AstTypesLike} descriptor, then runs the
|
|
8
|
+
* full extraction → projection → code-generation pipeline and returns the
|
|
9
|
+
* generated TypeScript source as a string. When `config.outputPath` is set the
|
|
10
|
+
* result is also written to disk. Conformance artifacts are generated when
|
|
11
|
+
* `config.conformance` is provided.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* This is the primary API for most consumers. It combines {@link extractTypeDescriptors},
|
|
15
|
+
* {@link detectRecursiveTypes}, and {@link generateZodCode} into a single call. Use the
|
|
16
|
+
* lower-level functions directly only when you need fine-grained control over individual
|
|
17
|
+
* pipeline stages (e.g. to inspect descriptors before code generation, or to cache
|
|
18
|
+
* extraction results across multiple code-generation runs).
|
|
19
|
+
*
|
|
20
|
+
* The function is synchronous and writes to disk only when `config.outputPath` is set.
|
|
21
|
+
* It does not shell out or spawn child processes.
|
|
22
|
+
*
|
|
23
|
+
* **Config option decision tree:**
|
|
24
|
+
* - Does your grammar have recursive rules (e.g. `Expression: ... | left=Expression`)? →
|
|
25
|
+
* no action needed; cycle detection is automatic. If you run a custom pipeline, pass the
|
|
26
|
+
* *full* (unprojected) descriptor set to `detectRecursiveTypes` first.
|
|
27
|
+
* - Does your grammar have cross-references (`ref:` properties)? →
|
|
28
|
+
* if you need runtime ref-text validation in a live language server, enable
|
|
29
|
+
* `crossRefValidation: true` and use the emitted `create*Schema()` factories.
|
|
30
|
+
* Otherwise leave it off — unconstrained `ReferenceSchema` is lighter and sufficient for
|
|
31
|
+
* batch/offline validation.
|
|
32
|
+
* - Do you want to strip Langium internal bookkeeping fields (`$container`, `$document`,
|
|
33
|
+
* `$cstNode`, etc.)? → set `stripInternals: true`. These fields are never meaningful
|
|
34
|
+
* in a validation context and inflate the generated schema.
|
|
35
|
+
* - Do you need form labels and descriptions driven by the grammar? → enable `formMetadata: true`.
|
|
36
|
+
* Only properties whose grammar rule has a JSDoc/grammar comment get a `description`; every
|
|
37
|
+
* property gets a humanized `title` regardless.
|
|
38
|
+
* - Are you using Zod 4's `z.looseObject`? → the default `objectStyle: 'loose'` emits
|
|
39
|
+
* `z.looseObject(...)`. Switch to `objectStyle: 'strict'` + `.strict()` on the schema only
|
|
40
|
+
* when you need hard rejection of unknown properties (e.g. strict API request validation).
|
|
41
|
+
*
|
|
42
|
+
* @param config - Generator configuration including the grammar or AST types,
|
|
43
|
+
* optional output path, include/exclude filters, projection, and feature flags.
|
|
44
|
+
* @returns The generated TypeScript source containing all Zod schema exports.
|
|
45
|
+
* @throws {@link ZodGeneratorError} when required configuration is missing, when
|
|
46
|
+
* `conformance` is enabled without `outputPath`, or when a grammar property type
|
|
47
|
+
* cannot be mapped to a Zod schema.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { createLangiumGrammarServices } from 'langium/grammar';
|
|
52
|
+
* import { NodeFileSystem } from 'langium/node';
|
|
53
|
+
* import { generateZodSchemas } from 'langium-zod';
|
|
54
|
+
*
|
|
55
|
+
* const { grammar } = createLangiumGrammarServices(NodeFileSystem);
|
|
56
|
+
* // assume `parsedGrammar` is a Grammar node obtained from Langium
|
|
57
|
+
* const source = generateZodSchemas({
|
|
58
|
+
* grammar: parsedGrammar,
|
|
59
|
+
* outputPath: 'src/generated/zod-schemas.ts',
|
|
60
|
+
* stripInternals: true,
|
|
61
|
+
* });
|
|
62
|
+
* console.log(source); // TypeScript source with Zod schema exports
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* // Using a pre-built AstTypesLike descriptor (skips grammar parsing)
|
|
68
|
+
* import { generateZodSchemas } from 'langium-zod';
|
|
69
|
+
* import { collectAst } from 'langium/grammar';
|
|
70
|
+
*
|
|
71
|
+
* const astTypes = collectAst(myGrammar);
|
|
72
|
+
* const source = generateZodSchemas({ astTypes });
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @useWhen
|
|
76
|
+
* - You have a parsed Langium `Grammar` object and want Zod schemas as a TypeScript string.
|
|
77
|
+
* - You are integrating langium-zod into a build pipeline (Vite plugin, codegen script, etc.).
|
|
78
|
+
* - You need conformance artifacts (type-guard files) alongside the schema output.
|
|
79
|
+
* - You want to write generated schemas to disk in a single call.
|
|
80
|
+
*
|
|
81
|
+
* @avoidWhen
|
|
82
|
+
* - You only need to inspect the intermediate type descriptors without generating code —
|
|
83
|
+
* use {@link extractTypeDescriptors} directly instead.
|
|
84
|
+
* - You are running inside the Langium DI container — prefer {@link DefaultZodSchemaGenerator}
|
|
85
|
+
* which injects services automatically.
|
|
86
|
+
* - You want to generate schemas for only a subset of types at runtime — pass `include`/`exclude`
|
|
87
|
+
* in the config rather than post-processing the output.
|
|
88
|
+
*
|
|
89
|
+
* @never
|
|
90
|
+
* - NEVER omit both `grammar` and `astTypes` — the function throws {@link ZodGeneratorError}
|
|
91
|
+
* immediately. BECAUSE there is no default grammar source and no way to recover silently.
|
|
92
|
+
* FIX: provide at least `{ grammar: parsedGrammar }` or `{ astTypes: collectAst(grammar) }`.
|
|
93
|
+
* - NEVER enable `conformance` without setting `outputPath` — the function will throw before
|
|
94
|
+
* writing any output. BECAUSE the conformance module needs to derive a sibling output path
|
|
95
|
+
* from the schema file's directory. FIX: always set `outputPath` when `conformance` is truthy.
|
|
96
|
+
* - NEVER pass a `Grammar[]` array when grammars share type names across files without
|
|
97
|
+
* verifying that Langium's `collectAst()` merges them correctly. BECAUSE duplicate type names
|
|
98
|
+
* will silently overwrite each other in the type map, producing truncated schemas.
|
|
99
|
+
* FIX: run `collectAst` separately and inspect the merged map before generation.
|
|
100
|
+
* - NEVER call with `crossRefValidation: true` on grammars with no cross-reference properties —
|
|
101
|
+
* it emits dead `create*Schema` factory functions that add noise without benefit.
|
|
102
|
+
* FIX: only enable `crossRefValidation` when your grammar has at least one `ref:` property.
|
|
103
|
+
* - NEVER remove the `// @ts-nocheck` comment from generated output files. BECAUSE the
|
|
104
|
+
* getter-based recursive property syntax (emitted for self-referential types) is not always
|
|
105
|
+
* accepted by TypeScript's strict object-literal type checker — removing the comment causes
|
|
106
|
+
* immediate TS build failures in grammars with recursive rules. FIX: treat generated files as
|
|
107
|
+
* opaque artifacts; place any hand-written extensions in a separate file that imports the schema.
|
|
108
|
+
* - NEVER commit generated schemas as the sole copy of your schema logic. BECAUSE any grammar
|
|
109
|
+
* edit (new rule, renamed property, changed cardinality) produces stale schemas that pass
|
|
110
|
+
* TypeScript but fail at Zod validation runtime. FIX: wire `langium-zod generate` as a
|
|
111
|
+
* pre-build or CI step so schema freshness is enforced automatically.
|
|
112
|
+
*
|
|
113
|
+
* @category Generation
|
|
114
|
+
* @see {@link extractTypeDescriptors}
|
|
115
|
+
* @see {@link detectRecursiveTypes}
|
|
116
|
+
* @see {@link generateZodCode}
|
|
117
|
+
* @see {@link ZodGeneratorConfig}
|
|
118
|
+
*/
|
|
3
119
|
export declare function generateZodSchemas(config: ZodGeneratorConfig): string;
|
|
120
|
+
/**
|
|
121
|
+
* Programmatic entry point for the domain target. Runs the same extract pipeline
|
|
122
|
+
* as {@link generateZodSchemas}, then emits the domain surface (read interfaces +
|
|
123
|
+
* `toDomain` projection + field-precise write accessors). Writes to
|
|
124
|
+
* `config.domainOutputPath` when set.
|
|
125
|
+
*/
|
|
126
|
+
export declare function generateDomainSchemas(config: ZodGeneratorConfig): string;
|
|
4
127
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAUtD,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAS1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmHG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAkGrE;AAcD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA4BxE"}
|
package/dist/api.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ZodGeneratorError } from './errors.js';
|
|
|
6
6
|
import { extractTypeDescriptors } from './extractor.js';
|
|
7
7
|
import { generateZodCode } from './generator.js';
|
|
8
8
|
import { applyProjectionToDescriptors, resolveEffectiveStripFields } from './projection.js';
|
|
9
|
+
import { generateDomainCode } from './emitters/domain.js';
|
|
9
10
|
import { detectRecursiveTypes } from './recursion-detector.js';
|
|
10
11
|
function resolveAstTypes(astTypes) {
|
|
11
12
|
return {
|
|
@@ -13,6 +14,122 @@ function resolveAstTypes(astTypes) {
|
|
|
13
14
|
unions: astTypes.unions ?? []
|
|
14
15
|
};
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Main entry point for programmatic Zod schema generation from a Langium grammar.
|
|
19
|
+
*
|
|
20
|
+
* Accepts a {@link ZodGeneratorConfig} that specifies either a parsed Langium
|
|
21
|
+
* `Grammar` object or a pre-built {@link AstTypesLike} descriptor, then runs the
|
|
22
|
+
* full extraction → projection → code-generation pipeline and returns the
|
|
23
|
+
* generated TypeScript source as a string. When `config.outputPath` is set the
|
|
24
|
+
* result is also written to disk. Conformance artifacts are generated when
|
|
25
|
+
* `config.conformance` is provided.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* This is the primary API for most consumers. It combines {@link extractTypeDescriptors},
|
|
29
|
+
* {@link detectRecursiveTypes}, and {@link generateZodCode} into a single call. Use the
|
|
30
|
+
* lower-level functions directly only when you need fine-grained control over individual
|
|
31
|
+
* pipeline stages (e.g. to inspect descriptors before code generation, or to cache
|
|
32
|
+
* extraction results across multiple code-generation runs).
|
|
33
|
+
*
|
|
34
|
+
* The function is synchronous and writes to disk only when `config.outputPath` is set.
|
|
35
|
+
* It does not shell out or spawn child processes.
|
|
36
|
+
*
|
|
37
|
+
* **Config option decision tree:**
|
|
38
|
+
* - Does your grammar have recursive rules (e.g. `Expression: ... | left=Expression`)? →
|
|
39
|
+
* no action needed; cycle detection is automatic. If you run a custom pipeline, pass the
|
|
40
|
+
* *full* (unprojected) descriptor set to `detectRecursiveTypes` first.
|
|
41
|
+
* - Does your grammar have cross-references (`ref:` properties)? →
|
|
42
|
+
* if you need runtime ref-text validation in a live language server, enable
|
|
43
|
+
* `crossRefValidation: true` and use the emitted `create*Schema()` factories.
|
|
44
|
+
* Otherwise leave it off — unconstrained `ReferenceSchema` is lighter and sufficient for
|
|
45
|
+
* batch/offline validation.
|
|
46
|
+
* - Do you want to strip Langium internal bookkeeping fields (`$container`, `$document`,
|
|
47
|
+
* `$cstNode`, etc.)? → set `stripInternals: true`. These fields are never meaningful
|
|
48
|
+
* in a validation context and inflate the generated schema.
|
|
49
|
+
* - Do you need form labels and descriptions driven by the grammar? → enable `formMetadata: true`.
|
|
50
|
+
* Only properties whose grammar rule has a JSDoc/grammar comment get a `description`; every
|
|
51
|
+
* property gets a humanized `title` regardless.
|
|
52
|
+
* - Are you using Zod 4's `z.looseObject`? → the default `objectStyle: 'loose'` emits
|
|
53
|
+
* `z.looseObject(...)`. Switch to `objectStyle: 'strict'` + `.strict()` on the schema only
|
|
54
|
+
* when you need hard rejection of unknown properties (e.g. strict API request validation).
|
|
55
|
+
*
|
|
56
|
+
* @param config - Generator configuration including the grammar or AST types,
|
|
57
|
+
* optional output path, include/exclude filters, projection, and feature flags.
|
|
58
|
+
* @returns The generated TypeScript source containing all Zod schema exports.
|
|
59
|
+
* @throws {@link ZodGeneratorError} when required configuration is missing, when
|
|
60
|
+
* `conformance` is enabled without `outputPath`, or when a grammar property type
|
|
61
|
+
* cannot be mapped to a Zod schema.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { createLangiumGrammarServices } from 'langium/grammar';
|
|
66
|
+
* import { NodeFileSystem } from 'langium/node';
|
|
67
|
+
* import { generateZodSchemas } from 'langium-zod';
|
|
68
|
+
*
|
|
69
|
+
* const { grammar } = createLangiumGrammarServices(NodeFileSystem);
|
|
70
|
+
* // assume `parsedGrammar` is a Grammar node obtained from Langium
|
|
71
|
+
* const source = generateZodSchemas({
|
|
72
|
+
* grammar: parsedGrammar,
|
|
73
|
+
* outputPath: 'src/generated/zod-schemas.ts',
|
|
74
|
+
* stripInternals: true,
|
|
75
|
+
* });
|
|
76
|
+
* console.log(source); // TypeScript source with Zod schema exports
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* // Using a pre-built AstTypesLike descriptor (skips grammar parsing)
|
|
82
|
+
* import { generateZodSchemas } from 'langium-zod';
|
|
83
|
+
* import { collectAst } from 'langium/grammar';
|
|
84
|
+
*
|
|
85
|
+
* const astTypes = collectAst(myGrammar);
|
|
86
|
+
* const source = generateZodSchemas({ astTypes });
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @useWhen
|
|
90
|
+
* - You have a parsed Langium `Grammar` object and want Zod schemas as a TypeScript string.
|
|
91
|
+
* - You are integrating langium-zod into a build pipeline (Vite plugin, codegen script, etc.).
|
|
92
|
+
* - You need conformance artifacts (type-guard files) alongside the schema output.
|
|
93
|
+
* - You want to write generated schemas to disk in a single call.
|
|
94
|
+
*
|
|
95
|
+
* @avoidWhen
|
|
96
|
+
* - You only need to inspect the intermediate type descriptors without generating code —
|
|
97
|
+
* use {@link extractTypeDescriptors} directly instead.
|
|
98
|
+
* - You are running inside the Langium DI container — prefer {@link DefaultZodSchemaGenerator}
|
|
99
|
+
* which injects services automatically.
|
|
100
|
+
* - You want to generate schemas for only a subset of types at runtime — pass `include`/`exclude`
|
|
101
|
+
* in the config rather than post-processing the output.
|
|
102
|
+
*
|
|
103
|
+
* @never
|
|
104
|
+
* - NEVER omit both `grammar` and `astTypes` — the function throws {@link ZodGeneratorError}
|
|
105
|
+
* immediately. BECAUSE there is no default grammar source and no way to recover silently.
|
|
106
|
+
* FIX: provide at least `{ grammar: parsedGrammar }` or `{ astTypes: collectAst(grammar) }`.
|
|
107
|
+
* - NEVER enable `conformance` without setting `outputPath` — the function will throw before
|
|
108
|
+
* writing any output. BECAUSE the conformance module needs to derive a sibling output path
|
|
109
|
+
* from the schema file's directory. FIX: always set `outputPath` when `conformance` is truthy.
|
|
110
|
+
* - NEVER pass a `Grammar[]` array when grammars share type names across files without
|
|
111
|
+
* verifying that Langium's `collectAst()` merges them correctly. BECAUSE duplicate type names
|
|
112
|
+
* will silently overwrite each other in the type map, producing truncated schemas.
|
|
113
|
+
* FIX: run `collectAst` separately and inspect the merged map before generation.
|
|
114
|
+
* - NEVER call with `crossRefValidation: true` on grammars with no cross-reference properties —
|
|
115
|
+
* it emits dead `create*Schema` factory functions that add noise without benefit.
|
|
116
|
+
* FIX: only enable `crossRefValidation` when your grammar has at least one `ref:` property.
|
|
117
|
+
* - NEVER remove the `// @ts-nocheck` comment from generated output files. BECAUSE the
|
|
118
|
+
* getter-based recursive property syntax (emitted for self-referential types) is not always
|
|
119
|
+
* accepted by TypeScript's strict object-literal type checker — removing the comment causes
|
|
120
|
+
* immediate TS build failures in grammars with recursive rules. FIX: treat generated files as
|
|
121
|
+
* opaque artifacts; place any hand-written extensions in a separate file that imports the schema.
|
|
122
|
+
* - NEVER commit generated schemas as the sole copy of your schema logic. BECAUSE any grammar
|
|
123
|
+
* edit (new rule, renamed property, changed cardinality) produces stale schemas that pass
|
|
124
|
+
* TypeScript but fail at Zod validation runtime. FIX: wire `langium-zod generate` as a
|
|
125
|
+
* pre-build or CI step so schema freshness is enforced automatically.
|
|
126
|
+
*
|
|
127
|
+
* @category Generation
|
|
128
|
+
* @see {@link extractTypeDescriptors}
|
|
129
|
+
* @see {@link detectRecursiveTypes}
|
|
130
|
+
* @see {@link generateZodCode}
|
|
131
|
+
* @see {@link ZodGeneratorConfig}
|
|
132
|
+
*/
|
|
16
133
|
export function generateZodSchemas(config) {
|
|
17
134
|
let rawAstTypes;
|
|
18
135
|
if (config.astTypes) {
|
|
@@ -104,4 +221,38 @@ function buildDescriptorPipeline(astTypes, config) {
|
|
|
104
221
|
});
|
|
105
222
|
return descriptors;
|
|
106
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Programmatic entry point for the domain target. Runs the same extract pipeline
|
|
226
|
+
* as {@link generateZodSchemas}, then emits the domain surface (read interfaces +
|
|
227
|
+
* `toDomain` projection + field-precise write accessors). Writes to
|
|
228
|
+
* `config.domainOutputPath` when set.
|
|
229
|
+
*/
|
|
230
|
+
export function generateDomainSchemas(config) {
|
|
231
|
+
let rawAstTypes;
|
|
232
|
+
if (config.astTypes) {
|
|
233
|
+
rawAstTypes = config.astTypes;
|
|
234
|
+
}
|
|
235
|
+
else if (config.grammar) {
|
|
236
|
+
rawAstTypes = collectAst(config.grammar);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
throw new ZodGeneratorError('Missing grammar or astTypes in ZodGeneratorConfig', {
|
|
240
|
+
suggestion: "Provide astTypes from Langium's collectAst() or pass a grammar object"
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
const astTypes = resolveAstTypes(rawAstTypes);
|
|
244
|
+
const descriptors = buildDescriptorPipeline(astTypes, config);
|
|
245
|
+
// Note: regexOverrides (regex-enum upgrades) are intentionally NOT applied here —
|
|
246
|
+
// the domain surface uses type references + primitives, never regex-enum shapes.
|
|
247
|
+
const source = generateDomainCode(descriptors, {
|
|
248
|
+
projection: config.projection,
|
|
249
|
+
stripInternals: config.stripInternals,
|
|
250
|
+
overlays: config.domainOverlays
|
|
251
|
+
});
|
|
252
|
+
if (config.domainOutputPath) {
|
|
253
|
+
mkdirSync(dirname(config.domainOutputPath), { recursive: true });
|
|
254
|
+
writeFileSync(config.domainOutputPath, source, 'utf8');
|
|
255
|
+
}
|
|
256
|
+
return source;
|
|
257
|
+
}
|
|
107
258
|
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAK/D,SAAS,eAAe,CAAC,QAAsB;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -10,14 +10,90 @@ export interface LangiumZodConfig extends Omit<ZodGeneratorConfig, 'grammar' | '
|
|
|
10
10
|
/** Explicit output path. Overrides derived path from langium-config.json `out` field. */
|
|
11
11
|
outputPath?: string;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Merges CLI `--include` / `--exclude` flag values with the base filter from a
|
|
15
|
+
* user config file, producing a deduplicated, conflict-free filter pair.
|
|
16
|
+
*
|
|
17
|
+
* CLI arguments take precedence over the config file values. Any name that appears
|
|
18
|
+
* in both `include` and `exclude` is removed from `include` so that the exclude
|
|
19
|
+
* list is authoritative.
|
|
20
|
+
*
|
|
21
|
+
* @param base - Baseline include/exclude arrays from the user's
|
|
22
|
+
* `langium-zod.config.js`, used when the corresponding CLI flag is absent.
|
|
23
|
+
* @param includeArg - Raw comma-separated string from `--include`, or `undefined`
|
|
24
|
+
* when the flag was not passed.
|
|
25
|
+
* @param excludeArg - Raw comma-separated string from `--exclude`, or `undefined`
|
|
26
|
+
* when the flag was not passed.
|
|
27
|
+
* @returns A resolved `{ include, exclude }` pair ready to merge into the
|
|
28
|
+
* generator config.
|
|
29
|
+
*/
|
|
13
30
|
export declare function resolveFilterOverrides(base: Pick<LangiumZodConfig, 'include' | 'exclude'>, includeArg?: string, excludeArg?: string): Pick<LangiumZodConfig, 'include' | 'exclude'>;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the subset of `requested` names that are not present in
|
|
33
|
+
* `availableTypeNames`.
|
|
34
|
+
*
|
|
35
|
+
* Used to surface warnings when the user's `--include` or `--exclude` list
|
|
36
|
+
* references type names that do not exist in the parsed grammar, helping catch
|
|
37
|
+
* typos before generation runs.
|
|
38
|
+
*
|
|
39
|
+
* @param requested - The type names requested by the user (include or exclude
|
|
40
|
+
* list). Returns an empty array immediately when this is `undefined` or empty.
|
|
41
|
+
* @param availableTypeNames - All type names present in the parsed Langium grammar
|
|
42
|
+
* (both interface types and union/datatype rule types).
|
|
43
|
+
* @returns An array of names from `requested` that are absent from
|
|
44
|
+
* `availableTypeNames`.
|
|
45
|
+
*/
|
|
14
46
|
export declare function getUnknownFilterNames(requested: string[] | undefined, availableTypeNames: string[]): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Options accepted by the programmatic {@link generate} function.
|
|
49
|
+
*
|
|
50
|
+
* Allows the core generation logic to be invoked directly from other tools or
|
|
51
|
+
* scripts without going through the CLI argument parser.
|
|
52
|
+
*/
|
|
15
53
|
export interface GenerateOptions {
|
|
16
54
|
/** Absolute path to langium-config.json */
|
|
17
55
|
langiumConfigPath: string;
|
|
18
56
|
/** Merged generator config (from user's langium-zod.config.js + CLI flags) */
|
|
19
57
|
config?: LangiumZodConfig;
|
|
20
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Programmatic entry point for the `langium-zod generate` command.
|
|
61
|
+
*
|
|
62
|
+
* Loads `langium-config.json` from `opts.langiumConfigPath`, resolves the grammar
|
|
63
|
+
* file path, parses the grammar with Langium services (including eager import
|
|
64
|
+
* loading so cross-file references link correctly), then calls
|
|
65
|
+
* {@link generateZodSchemas} with the merged configuration. Prints a success
|
|
66
|
+
* message to stdout when generation completes.
|
|
67
|
+
*
|
|
68
|
+
* @param opts - {@link GenerateOptions} specifying the langium config path and
|
|
69
|
+
* optional pre-merged generator config.
|
|
70
|
+
* @throws `Error` when the langium-config.json or grammar file cannot be found, or
|
|
71
|
+
* when the config defines no languages.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { generate } from 'langium-zod';
|
|
76
|
+
* import { resolve } from 'node:path';
|
|
77
|
+
*
|
|
78
|
+
* await generate({
|
|
79
|
+
* langiumConfigPath: resolve(process.cwd(), 'langium-config.json'),
|
|
80
|
+
* config: {
|
|
81
|
+
* outputPath: 'src/generated/zod-schemas.ts',
|
|
82
|
+
* stripInternals: true,
|
|
83
|
+
* },
|
|
84
|
+
* });
|
|
85
|
+
* // Prints: ✓ Generated Zod schemas → src/generated/zod-schemas.ts
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
21
88
|
export declare function generate(opts: GenerateOptions): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* CLI entry point executed when the `langium-zod` binary is invoked directly.
|
|
91
|
+
*
|
|
92
|
+
* Parses `process.argv`, resolves `langium-config.json`, loads an optional
|
|
93
|
+
* `langium-zod.config.js` from the same directory, merges all CLI flag overrides
|
|
94
|
+
* (--out, --include, --exclude, --projection, --strip-internals, --conformance,
|
|
95
|
+
* --cross-ref-validation), then delegates to {@link generate}. Exits the process
|
|
96
|
+
* with code 1 on error.
|
|
97
|
+
*/
|
|
22
98
|
export declare function main(): Promise<void>;
|
|
23
99
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAgBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAQtD,kEAAkE;AAClE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAgBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAQtD,kEAAkE;AAClE,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,kBAAkB,EAClB,SAAS,GAAG,UAAU,GAAG,UAAU,CACpC;IACC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAuCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,SAAS,CAAC,EACnD,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,SAAS,CAAC,CAc/C;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,EAC/B,kBAAkB,EAAE,MAAM,EAAE,GAC3B,MAAM,EAAE,CAOV;AA2ED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA2GnE;AAMD;;;;;;;;GAQG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA6G1C"}
|
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
12
12
|
import { URI } from 'langium';
|
|
13
13
|
import { createLangiumGrammarServices, resolveImportUri } from 'langium/grammar';
|
|
14
14
|
import { NodeFileSystem } from 'langium/node';
|
|
15
|
-
import { generateZodSchemas } from './api.js';
|
|
15
|
+
import { generateZodSchemas, generateDomainSchemas } from './api.js';
|
|
16
16
|
import { resolveAstTypesPath } from './conformance.js';
|
|
17
17
|
import { loadProjectionConfig } from './projection.js';
|
|
18
18
|
function parseCsvList(value) {
|
|
@@ -39,6 +39,23 @@ function getArgValue(args, flag) {
|
|
|
39
39
|
}
|
|
40
40
|
return value;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Merges CLI `--include` / `--exclude` flag values with the base filter from a
|
|
44
|
+
* user config file, producing a deduplicated, conflict-free filter pair.
|
|
45
|
+
*
|
|
46
|
+
* CLI arguments take precedence over the config file values. Any name that appears
|
|
47
|
+
* in both `include` and `exclude` is removed from `include` so that the exclude
|
|
48
|
+
* list is authoritative.
|
|
49
|
+
*
|
|
50
|
+
* @param base - Baseline include/exclude arrays from the user's
|
|
51
|
+
* `langium-zod.config.js`, used when the corresponding CLI flag is absent.
|
|
52
|
+
* @param includeArg - Raw comma-separated string from `--include`, or `undefined`
|
|
53
|
+
* when the flag was not passed.
|
|
54
|
+
* @param excludeArg - Raw comma-separated string from `--exclude`, or `undefined`
|
|
55
|
+
* when the flag was not passed.
|
|
56
|
+
* @returns A resolved `{ include, exclude }` pair ready to merge into the
|
|
57
|
+
* generator config.
|
|
58
|
+
*/
|
|
42
59
|
export function resolveFilterOverrides(base, includeArg, excludeArg) {
|
|
43
60
|
const includeFromCli = includeArg === undefined ? undefined : parseCsvList(includeArg);
|
|
44
61
|
const excludeFromCli = excludeArg === undefined ? undefined : parseCsvList(excludeArg);
|
|
@@ -56,11 +73,24 @@ function warnUnknownFilterNames(filterName, requested, availableTypeNames) {
|
|
|
56
73
|
if (unknown.length === 0) {
|
|
57
74
|
return;
|
|
58
75
|
}
|
|
59
|
-
const availableList = availableTypeNames.length > 0
|
|
60
|
-
? availableTypeNames.join(', ')
|
|
61
|
-
: '(none)';
|
|
76
|
+
const availableList = availableTypeNames.length > 0 ? availableTypeNames.join(', ') : '(none)';
|
|
62
77
|
console.warn(`Warning: Unknown ${filterName} type name(s): ${unknown.join(', ')}. Available types: ${availableList}`);
|
|
63
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns the subset of `requested` names that are not present in
|
|
81
|
+
* `availableTypeNames`.
|
|
82
|
+
*
|
|
83
|
+
* Used to surface warnings when the user's `--include` or `--exclude` list
|
|
84
|
+
* references type names that do not exist in the parsed grammar, helping catch
|
|
85
|
+
* typos before generation runs.
|
|
86
|
+
*
|
|
87
|
+
* @param requested - The type names requested by the user (include or exclude
|
|
88
|
+
* list). Returns an empty array immediately when this is `undefined` or empty.
|
|
89
|
+
* @param availableTypeNames - All type names present in the parsed Langium grammar
|
|
90
|
+
* (both interface types and union/datatype rule types).
|
|
91
|
+
* @returns An array of names from `requested` that are absent from
|
|
92
|
+
* `availableTypeNames`.
|
|
93
|
+
*/
|
|
64
94
|
export function getUnknownFilterNames(requested, availableTypeNames) {
|
|
65
95
|
if (!requested || requested.length === 0) {
|
|
66
96
|
return [];
|
|
@@ -89,6 +119,8 @@ OPTIONS
|
|
|
89
119
|
--ast-types <path> Path to generated AST declarations (ast.ts)
|
|
90
120
|
--conformance-out <path> Output path for conformance artifact
|
|
91
121
|
--cross-ref-validation Emit runtime cross-reference schema factories
|
|
122
|
+
--domain Also emit the domain surface (domain.ts)
|
|
123
|
+
--domain-out <path> Output path for the domain surface
|
|
92
124
|
--help Show this help message
|
|
93
125
|
|
|
94
126
|
CONFIGURATION
|
|
@@ -128,6 +160,35 @@ async function eagerLoad(document, documents, visited = new Set()) {
|
|
|
128
160
|
}
|
|
129
161
|
}
|
|
130
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Programmatic entry point for the `langium-zod generate` command.
|
|
165
|
+
*
|
|
166
|
+
* Loads `langium-config.json` from `opts.langiumConfigPath`, resolves the grammar
|
|
167
|
+
* file path, parses the grammar with Langium services (including eager import
|
|
168
|
+
* loading so cross-file references link correctly), then calls
|
|
169
|
+
* {@link generateZodSchemas} with the merged configuration. Prints a success
|
|
170
|
+
* message to stdout when generation completes.
|
|
171
|
+
*
|
|
172
|
+
* @param opts - {@link GenerateOptions} specifying the langium config path and
|
|
173
|
+
* optional pre-merged generator config.
|
|
174
|
+
* @throws `Error` when the langium-config.json or grammar file cannot be found, or
|
|
175
|
+
* when the config defines no languages.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import { generate } from 'langium-zod';
|
|
180
|
+
* import { resolve } from 'node:path';
|
|
181
|
+
*
|
|
182
|
+
* await generate({
|
|
183
|
+
* langiumConfigPath: resolve(process.cwd(), 'langium-config.json'),
|
|
184
|
+
* config: {
|
|
185
|
+
* outputPath: 'src/generated/zod-schemas.ts',
|
|
186
|
+
* stripInternals: true,
|
|
187
|
+
* },
|
|
188
|
+
* });
|
|
189
|
+
* // Prints: ✓ Generated Zod schemas → src/generated/zod-schemas.ts
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
131
192
|
export async function generate(opts) {
|
|
132
193
|
const { langiumConfigPath } = opts;
|
|
133
194
|
const userConfig = opts.config ?? {};
|
|
@@ -177,7 +238,7 @@ export async function generate(opts) {
|
|
|
177
238
|
await eagerLoad(entryDocument, langiumDocuments);
|
|
178
239
|
// Build (parse + link) all loaded documents
|
|
179
240
|
await documentBuilder.build(langiumDocuments.all.toArray(), {
|
|
180
|
-
validation: false
|
|
241
|
+
validation: false
|
|
181
242
|
});
|
|
182
243
|
const grammar = entryDocument.parseResult.value;
|
|
183
244
|
const availableTypeNames = [
|
|
@@ -189,17 +250,39 @@ export async function generate(opts) {
|
|
|
189
250
|
warnUnknownFilterNames('include', userConfig.include, availableTypeNames);
|
|
190
251
|
warnUnknownFilterNames('exclude', userConfig.exclude, availableTypeNames);
|
|
191
252
|
// ── 4. Generate schemas ──────────────────────────────────────────────────
|
|
192
|
-
const { langiumConfig: _ignored, outputPath: _op, ...restConfig } = userConfig;
|
|
253
|
+
const { langiumConfig: _ignored, outputPath: _op, emitDomain: _emitDomain, domainOutputPath: _domainOutputPath, ...restConfig } = userConfig;
|
|
193
254
|
generateZodSchemas({
|
|
194
255
|
grammar,
|
|
195
256
|
outputPath,
|
|
196
|
-
...restConfig
|
|
257
|
+
...restConfig
|
|
197
258
|
});
|
|
198
259
|
console.log(`✓ Generated Zod schemas → ${outputPath}`);
|
|
260
|
+
if (userConfig.emitDomain) {
|
|
261
|
+
const domainOutputPath = userConfig.domainOutputPath ?? join(outDir, 'domain.ts');
|
|
262
|
+
generateDomainSchemas({
|
|
263
|
+
grammar,
|
|
264
|
+
domainOutputPath,
|
|
265
|
+
stripInternals: restConfig.stripInternals,
|
|
266
|
+
projection: restConfig.projection,
|
|
267
|
+
domainOverlays: restConfig.domainOverlays,
|
|
268
|
+
include: restConfig.include,
|
|
269
|
+
exclude: restConfig.exclude
|
|
270
|
+
});
|
|
271
|
+
console.log(`✓ Generated domain surface → ${domainOutputPath}`);
|
|
272
|
+
}
|
|
199
273
|
}
|
|
200
274
|
// ────────────────────────────────────────────────────────────────────────────
|
|
201
275
|
// CLI entry point
|
|
202
276
|
// ────────────────────────────────────────────────────────────────────────────
|
|
277
|
+
/**
|
|
278
|
+
* CLI entry point executed when the `langium-zod` binary is invoked directly.
|
|
279
|
+
*
|
|
280
|
+
* Parses `process.argv`, resolves `langium-config.json`, loads an optional
|
|
281
|
+
* `langium-zod.config.js` from the same directory, merges all CLI flag overrides
|
|
282
|
+
* (--out, --include, --exclude, --projection, --strip-internals, --conformance,
|
|
283
|
+
* --cross-ref-validation), then delegates to {@link generate}. Exits the process
|
|
284
|
+
* with code 1 on error.
|
|
285
|
+
*/
|
|
203
286
|
export async function main() {
|
|
204
287
|
const args = process.argv.slice(2);
|
|
205
288
|
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
@@ -225,16 +308,15 @@ export async function main() {
|
|
|
225
308
|
const stripInternalsEnabled = args.includes('--strip-internals');
|
|
226
309
|
const conformanceEnabled = args.includes('--conformance');
|
|
227
310
|
const crossRefValidationEnabled = args.includes('--cross-ref-validation');
|
|
311
|
+
const domainEnabled = args.includes('--domain');
|
|
312
|
+
const domainOutFlagValue = getArgValue(args, '--domain-out');
|
|
228
313
|
// ── Locate langium-config.json ───────────────────────────────────────────
|
|
229
314
|
const configFileName = configFlagValue ?? 'langium-config.json';
|
|
230
315
|
const langiumConfigPath = resolve(process.cwd(), configFileName);
|
|
231
316
|
// ── Load optional langium-zod.config.js ──────────────────────────────────
|
|
232
317
|
const configDir = dirname(langiumConfigPath);
|
|
233
318
|
let userConfig = {};
|
|
234
|
-
for (const candidate of [
|
|
235
|
-
'langium-zod.config.js',
|
|
236
|
-
'langium-zod.config.mjs',
|
|
237
|
-
]) {
|
|
319
|
+
for (const candidate of ['langium-zod.config.js', 'langium-zod.config.mjs']) {
|
|
238
320
|
const candidatePath = join(configDir, candidate);
|
|
239
321
|
if (existsSync(candidatePath)) {
|
|
240
322
|
const mod = await import(pathToFileURL(candidatePath).href);
|
|
@@ -269,7 +351,9 @@ export async function main() {
|
|
|
269
351
|
...userConfig,
|
|
270
352
|
conformance: {
|
|
271
353
|
astTypesPath: astTypesFlagValue ? resolve(process.cwd(), astTypesFlagValue) : undefined,
|
|
272
|
-
outputPath: conformanceOutFlagValue
|
|
354
|
+
outputPath: conformanceOutFlagValue
|
|
355
|
+
? resolve(process.cwd(), conformanceOutFlagValue)
|
|
356
|
+
: undefined
|
|
273
357
|
}
|
|
274
358
|
};
|
|
275
359
|
}
|
|
@@ -279,6 +363,15 @@ export async function main() {
|
|
|
279
363
|
crossRefValidation: true
|
|
280
364
|
};
|
|
281
365
|
}
|
|
366
|
+
if (domainEnabled) {
|
|
367
|
+
userConfig = {
|
|
368
|
+
...userConfig,
|
|
369
|
+
emitDomain: true,
|
|
370
|
+
domainOutputPath: domainOutFlagValue
|
|
371
|
+
? resolve(process.cwd(), domainOutFlagValue)
|
|
372
|
+
: userConfig.domainOutputPath
|
|
373
|
+
};
|
|
374
|
+
}
|
|
282
375
|
try {
|
|
283
376
|
await generate({ langiumConfigPath, config: userConfig });
|
|
284
377
|
}
|