@formspec/build 0.1.0-alpha.27 → 0.1.0-alpha.29
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/LICENSE +21 -0
- package/README.md +3 -2
- package/dist/analyzer/class-analyzer.d.ts +12 -6
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +3 -2
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/browser.cjs +485 -76
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +486 -77
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +18 -2
- package/dist/build-beta.d.ts +18 -2
- package/dist/build-internal.d.ts +18 -2
- package/dist/build.d.ts +18 -2
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts +5 -2
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -1
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +5 -1
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -1
- package/dist/cli.cjs +1460 -143
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1458 -139
- package/dist/cli.js.map +1 -1
- package/dist/generators/class-schema.d.ts +6 -1
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/generators/mixed-authoring.d.ts.map +1 -1
- package/dist/index.cjs +1425 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1425 -139
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +1416 -178
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +1416 -176
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts +3 -1
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts.map +1 -1
- package/dist/metadata/collision-guards.d.ts +3 -0
- package/dist/metadata/collision-guards.d.ts.map +1 -0
- package/dist/metadata/index.d.ts +7 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/policy.d.ts +11 -0
- package/dist/metadata/policy.d.ts.map +1 -0
- package/dist/metadata/resolve.d.ts +20 -0
- package/dist/metadata/resolve.d.ts.map +1 -0
- package/dist/ui-schema/generator.d.ts +11 -2
- package/dist/ui-schema/generator.d.ts.map +1 -1
- package/dist/ui-schema/ir-generator.d.ts +2 -1
- package/dist/ui-schema/ir-generator.d.ts.map +1 -1
- package/package.json +7 -6
package/dist/cli.cjs
CHANGED
|
@@ -30,6 +30,334 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
mod
|
|
31
31
|
));
|
|
32
32
|
|
|
33
|
+
// src/metadata/policy.ts
|
|
34
|
+
function normalizePluralization(input) {
|
|
35
|
+
if (input?.mode === "infer-if-missing") {
|
|
36
|
+
return {
|
|
37
|
+
mode: "infer-if-missing",
|
|
38
|
+
infer: () => "",
|
|
39
|
+
inflect: input.inflect
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (input?.mode === "require-explicit") {
|
|
43
|
+
return {
|
|
44
|
+
mode: "require-explicit",
|
|
45
|
+
infer: () => "",
|
|
46
|
+
inflect: NOOP_INFLECT
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
mode: "disabled",
|
|
51
|
+
infer: () => "",
|
|
52
|
+
inflect: NOOP_INFLECT
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function normalizeScalarPolicy(input) {
|
|
56
|
+
if (input?.mode === "infer-if-missing") {
|
|
57
|
+
return {
|
|
58
|
+
mode: "infer-if-missing",
|
|
59
|
+
infer: input.infer,
|
|
60
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (input?.mode === "require-explicit") {
|
|
64
|
+
return {
|
|
65
|
+
mode: "require-explicit",
|
|
66
|
+
infer: () => "",
|
|
67
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
mode: "disabled",
|
|
72
|
+
infer: () => "",
|
|
73
|
+
pluralization: normalizePluralization(input?.pluralization)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function normalizeDeclarationPolicy(input) {
|
|
77
|
+
return {
|
|
78
|
+
apiName: normalizeScalarPolicy(input?.apiName),
|
|
79
|
+
displayName: normalizeScalarPolicy(input?.displayName)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function normalizeMetadataPolicy(input) {
|
|
83
|
+
return {
|
|
84
|
+
type: normalizeDeclarationPolicy(input?.type),
|
|
85
|
+
field: normalizeDeclarationPolicy(input?.field),
|
|
86
|
+
method: normalizeDeclarationPolicy(input?.method)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function getDeclarationMetadataPolicy(policy, declarationKind) {
|
|
90
|
+
return policy[declarationKind];
|
|
91
|
+
}
|
|
92
|
+
function makeMetadataContext(surface, declarationKind, logicalName, buildContext) {
|
|
93
|
+
return {
|
|
94
|
+
surface,
|
|
95
|
+
declarationKind,
|
|
96
|
+
logicalName,
|
|
97
|
+
...buildContext !== void 0 && { buildContext }
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var NOOP_INFLECT;
|
|
101
|
+
var init_policy = __esm({
|
|
102
|
+
"src/metadata/policy.ts"() {
|
|
103
|
+
"use strict";
|
|
104
|
+
NOOP_INFLECT = () => "";
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// src/metadata/resolve.ts
|
|
109
|
+
function toExplicitScalar(value) {
|
|
110
|
+
return value !== void 0 && value.trim() !== "" ? { value, source: "explicit" } : void 0;
|
|
111
|
+
}
|
|
112
|
+
function toExplicitResolvedMetadata(explicit) {
|
|
113
|
+
if (explicit === void 0) {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
const apiName = toExplicitScalar(explicit.apiName);
|
|
117
|
+
const displayName = toExplicitScalar(explicit.displayName);
|
|
118
|
+
const apiNamePlural = toExplicitScalar(explicit.apiNamePlural);
|
|
119
|
+
const displayNamePlural = toExplicitScalar(explicit.displayNamePlural);
|
|
120
|
+
const metadata = {
|
|
121
|
+
...apiName !== void 0 && { apiName },
|
|
122
|
+
...displayName !== void 0 && { displayName },
|
|
123
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
124
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
125
|
+
};
|
|
126
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
127
|
+
}
|
|
128
|
+
function resolveScalar(current, policy, context, metadataLabel) {
|
|
129
|
+
if (current !== void 0) {
|
|
130
|
+
return current;
|
|
131
|
+
}
|
|
132
|
+
if (policy.mode === "require-explicit") {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (policy.mode !== "infer-if-missing") {
|
|
138
|
+
return void 0;
|
|
139
|
+
}
|
|
140
|
+
const inferredValue = policy.infer(context);
|
|
141
|
+
return inferredValue.trim() !== "" ? { value: inferredValue, source: "inferred" } : void 0;
|
|
142
|
+
}
|
|
143
|
+
function resolvePlural(current, singular, policy, context, metadataLabel) {
|
|
144
|
+
if (current !== void 0) {
|
|
145
|
+
return current;
|
|
146
|
+
}
|
|
147
|
+
if (policy.mode === "require-explicit") {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (singular === void 0 || policy.mode !== "infer-if-missing") {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
const pluralValue = policy.inflect({ ...context, singular: singular.value });
|
|
156
|
+
return pluralValue.trim() !== "" ? { value: pluralValue, source: "inferred" } : void 0;
|
|
157
|
+
}
|
|
158
|
+
function resolveResolvedMetadata(current, policy, context) {
|
|
159
|
+
const apiName = resolveScalar(current?.apiName, policy.apiName, context, "apiName");
|
|
160
|
+
const displayName = resolveScalar(
|
|
161
|
+
current?.displayName,
|
|
162
|
+
policy.displayName,
|
|
163
|
+
context,
|
|
164
|
+
"displayName"
|
|
165
|
+
);
|
|
166
|
+
const apiNamePlural = resolvePlural(
|
|
167
|
+
current?.apiNamePlural,
|
|
168
|
+
apiName,
|
|
169
|
+
policy.apiName.pluralization,
|
|
170
|
+
context,
|
|
171
|
+
"apiNamePlural"
|
|
172
|
+
);
|
|
173
|
+
const displayNamePlural = resolvePlural(
|
|
174
|
+
current?.displayNamePlural,
|
|
175
|
+
displayName,
|
|
176
|
+
policy.displayName.pluralization,
|
|
177
|
+
context,
|
|
178
|
+
"displayNamePlural"
|
|
179
|
+
);
|
|
180
|
+
if (apiName === void 0 && displayName === void 0 && apiNamePlural === void 0 && displayNamePlural === void 0) {
|
|
181
|
+
return void 0;
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
...apiName !== void 0 && { apiName },
|
|
185
|
+
...displayName !== void 0 && { displayName },
|
|
186
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
187
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function pickResolvedMetadataValue(baseValue, overlayValue) {
|
|
191
|
+
if (overlayValue?.source === "explicit") {
|
|
192
|
+
return overlayValue;
|
|
193
|
+
}
|
|
194
|
+
if (baseValue?.source === "explicit") {
|
|
195
|
+
return baseValue;
|
|
196
|
+
}
|
|
197
|
+
return baseValue ?? overlayValue;
|
|
198
|
+
}
|
|
199
|
+
function resolveTypeNodeMetadata(type, options) {
|
|
200
|
+
switch (type.kind) {
|
|
201
|
+
case "array":
|
|
202
|
+
return {
|
|
203
|
+
...type,
|
|
204
|
+
items: resolveTypeNodeMetadata(type.items, options)
|
|
205
|
+
};
|
|
206
|
+
case "object":
|
|
207
|
+
return {
|
|
208
|
+
...type,
|
|
209
|
+
properties: type.properties.map((property) => resolveObjectPropertyMetadata(property, options))
|
|
210
|
+
};
|
|
211
|
+
case "record":
|
|
212
|
+
return {
|
|
213
|
+
...type,
|
|
214
|
+
valueType: resolveTypeNodeMetadata(type.valueType, options)
|
|
215
|
+
};
|
|
216
|
+
case "union":
|
|
217
|
+
return {
|
|
218
|
+
...type,
|
|
219
|
+
members: type.members.map((member) => resolveTypeNodeMetadata(member, options))
|
|
220
|
+
};
|
|
221
|
+
case "reference":
|
|
222
|
+
case "primitive":
|
|
223
|
+
case "enum":
|
|
224
|
+
case "dynamic":
|
|
225
|
+
case "custom":
|
|
226
|
+
return type;
|
|
227
|
+
default: {
|
|
228
|
+
const _exhaustive = type;
|
|
229
|
+
return _exhaustive;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function resolveObjectPropertyMetadata(property, options) {
|
|
234
|
+
const metadata = resolveResolvedMetadata(property.metadata, options.policy.field, {
|
|
235
|
+
surface: options.surface,
|
|
236
|
+
declarationKind: "field",
|
|
237
|
+
logicalName: property.name,
|
|
238
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
...property,
|
|
242
|
+
...metadata !== void 0 && { metadata },
|
|
243
|
+
type: resolveTypeNodeMetadata(property.type, options)
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function resolveFieldMetadataNode(field, options) {
|
|
247
|
+
const metadata = resolveResolvedMetadata(field.metadata, options.policy.field, {
|
|
248
|
+
surface: options.surface,
|
|
249
|
+
declarationKind: "field",
|
|
250
|
+
logicalName: field.name,
|
|
251
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
...field,
|
|
255
|
+
...metadata !== void 0 && { metadata },
|
|
256
|
+
type: resolveTypeNodeMetadata(field.type, options)
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function resolveFormElementMetadata(element, options) {
|
|
260
|
+
switch (element.kind) {
|
|
261
|
+
case "field":
|
|
262
|
+
return resolveFieldMetadataNode(element, options);
|
|
263
|
+
case "group":
|
|
264
|
+
return {
|
|
265
|
+
...element,
|
|
266
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
267
|
+
};
|
|
268
|
+
case "conditional":
|
|
269
|
+
return {
|
|
270
|
+
...element,
|
|
271
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
272
|
+
};
|
|
273
|
+
default: {
|
|
274
|
+
const _exhaustive = element;
|
|
275
|
+
return _exhaustive;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function resolveTypeDefinitionMetadata(typeDefinition, options) {
|
|
280
|
+
const metadata = resolveResolvedMetadata(typeDefinition.metadata, options.policy.type, {
|
|
281
|
+
surface: options.surface,
|
|
282
|
+
declarationKind: "type",
|
|
283
|
+
logicalName: typeDefinition.name,
|
|
284
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
...typeDefinition,
|
|
288
|
+
...metadata !== void 0 && { metadata },
|
|
289
|
+
type: resolveTypeNodeMetadata(typeDefinition.type, options)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function resolveMetadata(explicit, policy, context) {
|
|
293
|
+
return resolveResolvedMetadata(toExplicitResolvedMetadata(explicit), policy, context);
|
|
294
|
+
}
|
|
295
|
+
function mergeResolvedMetadata(baseMetadata, overlayMetadata) {
|
|
296
|
+
const apiName = pickResolvedMetadataValue(baseMetadata?.apiName, overlayMetadata?.apiName);
|
|
297
|
+
const displayName = pickResolvedMetadataValue(
|
|
298
|
+
baseMetadata?.displayName,
|
|
299
|
+
overlayMetadata?.displayName
|
|
300
|
+
);
|
|
301
|
+
const apiNamePlural = pickResolvedMetadataValue(
|
|
302
|
+
baseMetadata?.apiNamePlural,
|
|
303
|
+
overlayMetadata?.apiNamePlural
|
|
304
|
+
);
|
|
305
|
+
const displayNamePlural = pickResolvedMetadataValue(
|
|
306
|
+
baseMetadata?.displayNamePlural,
|
|
307
|
+
overlayMetadata?.displayNamePlural
|
|
308
|
+
);
|
|
309
|
+
if (apiName === void 0 && displayName === void 0 && apiNamePlural === void 0 && displayNamePlural === void 0) {
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
...apiName !== void 0 && { apiName },
|
|
314
|
+
...displayName !== void 0 && { displayName },
|
|
315
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
316
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
function getSerializedName(logicalName, metadata) {
|
|
320
|
+
return metadata?.apiName?.value ?? logicalName;
|
|
321
|
+
}
|
|
322
|
+
function getDisplayName(metadata) {
|
|
323
|
+
return metadata?.displayName?.value;
|
|
324
|
+
}
|
|
325
|
+
function resolveFormIRMetadata(ir, options) {
|
|
326
|
+
const rootLogicalName = options.rootLogicalName ?? ir.name ?? "FormSpec";
|
|
327
|
+
const metadata = resolveResolvedMetadata(ir.metadata, options.policy.type, {
|
|
328
|
+
surface: options.surface,
|
|
329
|
+
declarationKind: "type",
|
|
330
|
+
logicalName: rootLogicalName,
|
|
331
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
332
|
+
});
|
|
333
|
+
return {
|
|
334
|
+
...ir,
|
|
335
|
+
...metadata !== void 0 && { metadata },
|
|
336
|
+
elements: ir.elements.map((element) => resolveFormElementMetadata(element, options)),
|
|
337
|
+
typeRegistry: Object.fromEntries(
|
|
338
|
+
Object.entries(ir.typeRegistry).map(([name, definition]) => [
|
|
339
|
+
name,
|
|
340
|
+
resolveTypeDefinitionMetadata(definition, options)
|
|
341
|
+
])
|
|
342
|
+
)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
var init_resolve = __esm({
|
|
346
|
+
"src/metadata/resolve.ts"() {
|
|
347
|
+
"use strict";
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// src/metadata/index.ts
|
|
352
|
+
var init_metadata = __esm({
|
|
353
|
+
"src/metadata/index.ts"() {
|
|
354
|
+
"use strict";
|
|
355
|
+
init_policy();
|
|
356
|
+
init_resolve();
|
|
357
|
+
init_resolve();
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
33
361
|
// src/canonicalize/chain-dsl-canonicalizer.ts
|
|
34
362
|
function isGroup(el) {
|
|
35
363
|
return el._type === "group";
|
|
@@ -40,57 +368,60 @@ function isConditional(el) {
|
|
|
40
368
|
function isField(el) {
|
|
41
369
|
return el._type === "field";
|
|
42
370
|
}
|
|
43
|
-
function canonicalizeChainDSL(form) {
|
|
371
|
+
function canonicalizeChainDSL(form, options) {
|
|
372
|
+
const metadataPolicy = normalizeMetadataPolicy(
|
|
373
|
+
options?.metadata ?? (0, import_internals._getFormSpecMetadataPolicy)(form)
|
|
374
|
+
);
|
|
44
375
|
return {
|
|
45
376
|
kind: "form-ir",
|
|
46
377
|
irVersion: import_internals.IR_VERSION,
|
|
47
|
-
elements: canonicalizeElements(form.elements),
|
|
378
|
+
elements: canonicalizeElements(form.elements, metadataPolicy),
|
|
48
379
|
rootAnnotations: [],
|
|
49
380
|
typeRegistry: {},
|
|
50
381
|
provenance: CHAIN_DSL_PROVENANCE
|
|
51
382
|
};
|
|
52
383
|
}
|
|
53
|
-
function canonicalizeElements(elements) {
|
|
54
|
-
return elements.map(canonicalizeElement);
|
|
384
|
+
function canonicalizeElements(elements, metadataPolicy) {
|
|
385
|
+
return elements.map((element) => canonicalizeElement(element, metadataPolicy));
|
|
55
386
|
}
|
|
56
|
-
function canonicalizeElement(element) {
|
|
387
|
+
function canonicalizeElement(element, metadataPolicy) {
|
|
57
388
|
if (isField(element)) {
|
|
58
|
-
return canonicalizeField(element);
|
|
389
|
+
return canonicalizeField(element, metadataPolicy);
|
|
59
390
|
}
|
|
60
391
|
if (isGroup(element)) {
|
|
61
|
-
return canonicalizeGroup(element);
|
|
392
|
+
return canonicalizeGroup(element, metadataPolicy);
|
|
62
393
|
}
|
|
63
394
|
if (isConditional(element)) {
|
|
64
|
-
return canonicalizeConditional(element);
|
|
395
|
+
return canonicalizeConditional(element, metadataPolicy);
|
|
65
396
|
}
|
|
66
397
|
const _exhaustive = element;
|
|
67
398
|
throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);
|
|
68
399
|
}
|
|
69
|
-
function canonicalizeField(field) {
|
|
400
|
+
function canonicalizeField(field, metadataPolicy) {
|
|
70
401
|
switch (field._field) {
|
|
71
402
|
case "text":
|
|
72
|
-
return canonicalizeTextField(field);
|
|
403
|
+
return canonicalizeTextField(field, metadataPolicy);
|
|
73
404
|
case "number":
|
|
74
|
-
return canonicalizeNumberField(field);
|
|
405
|
+
return canonicalizeNumberField(field, metadataPolicy);
|
|
75
406
|
case "boolean":
|
|
76
|
-
return canonicalizeBooleanField(field);
|
|
407
|
+
return canonicalizeBooleanField(field, metadataPolicy);
|
|
77
408
|
case "enum":
|
|
78
|
-
return canonicalizeStaticEnumField(field);
|
|
409
|
+
return canonicalizeStaticEnumField(field, metadataPolicy);
|
|
79
410
|
case "dynamic_enum":
|
|
80
|
-
return canonicalizeDynamicEnumField(field);
|
|
411
|
+
return canonicalizeDynamicEnumField(field, metadataPolicy);
|
|
81
412
|
case "dynamic_schema":
|
|
82
|
-
return canonicalizeDynamicSchemaField(field);
|
|
413
|
+
return canonicalizeDynamicSchemaField(field, metadataPolicy);
|
|
83
414
|
case "array":
|
|
84
|
-
return canonicalizeArrayField(field);
|
|
415
|
+
return canonicalizeArrayField(field, metadataPolicy);
|
|
85
416
|
case "object":
|
|
86
|
-
return canonicalizeObjectField(field);
|
|
417
|
+
return canonicalizeObjectField(field, metadataPolicy);
|
|
87
418
|
default: {
|
|
88
419
|
const _exhaustive = field;
|
|
89
420
|
throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);
|
|
90
421
|
}
|
|
91
422
|
}
|
|
92
423
|
}
|
|
93
|
-
function canonicalizeTextField(field) {
|
|
424
|
+
function canonicalizeTextField(field, metadataPolicy) {
|
|
94
425
|
const type = { kind: "primitive", primitiveKind: "string" };
|
|
95
426
|
const constraints = [];
|
|
96
427
|
if (field.minLength !== void 0) {
|
|
@@ -122,13 +453,14 @@ function canonicalizeTextField(field) {
|
|
|
122
453
|
}
|
|
123
454
|
return buildFieldNode(
|
|
124
455
|
field.name,
|
|
456
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
125
457
|
type,
|
|
126
458
|
field.required,
|
|
127
|
-
buildAnnotations(field
|
|
459
|
+
buildAnnotations(getExplicitDisplayName(field), field.placeholder),
|
|
128
460
|
constraints
|
|
129
461
|
);
|
|
130
462
|
}
|
|
131
|
-
function canonicalizeNumberField(field) {
|
|
463
|
+
function canonicalizeNumberField(field, metadataPolicy) {
|
|
132
464
|
const type = { kind: "primitive", primitiveKind: "number" };
|
|
133
465
|
const constraints = [];
|
|
134
466
|
if (field.min !== void 0) {
|
|
@@ -160,17 +492,24 @@ function canonicalizeNumberField(field) {
|
|
|
160
492
|
}
|
|
161
493
|
return buildFieldNode(
|
|
162
494
|
field.name,
|
|
495
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
163
496
|
type,
|
|
164
497
|
field.required,
|
|
165
|
-
buildAnnotations(field
|
|
498
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
166
499
|
constraints
|
|
167
500
|
);
|
|
168
501
|
}
|
|
169
|
-
function canonicalizeBooleanField(field) {
|
|
502
|
+
function canonicalizeBooleanField(field, metadataPolicy) {
|
|
170
503
|
const type = { kind: "primitive", primitiveKind: "boolean" };
|
|
171
|
-
return buildFieldNode(
|
|
504
|
+
return buildFieldNode(
|
|
505
|
+
field.name,
|
|
506
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
507
|
+
type,
|
|
508
|
+
field.required,
|
|
509
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
510
|
+
);
|
|
172
511
|
}
|
|
173
|
-
function canonicalizeStaticEnumField(field) {
|
|
512
|
+
function canonicalizeStaticEnumField(field, metadataPolicy) {
|
|
174
513
|
const members = field.options.map((opt) => {
|
|
175
514
|
if (typeof opt === "string") {
|
|
176
515
|
return { value: opt };
|
|
@@ -178,28 +517,46 @@ function canonicalizeStaticEnumField(field) {
|
|
|
178
517
|
return { value: opt.id, displayName: opt.label };
|
|
179
518
|
});
|
|
180
519
|
const type = { kind: "enum", members };
|
|
181
|
-
return buildFieldNode(
|
|
520
|
+
return buildFieldNode(
|
|
521
|
+
field.name,
|
|
522
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
523
|
+
type,
|
|
524
|
+
field.required,
|
|
525
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
526
|
+
);
|
|
182
527
|
}
|
|
183
|
-
function canonicalizeDynamicEnumField(field) {
|
|
528
|
+
function canonicalizeDynamicEnumField(field, metadataPolicy) {
|
|
184
529
|
const type = {
|
|
185
530
|
kind: "dynamic",
|
|
186
531
|
dynamicKind: "enum",
|
|
187
532
|
sourceKey: field.source,
|
|
188
533
|
parameterFields: field.params ? [...field.params] : []
|
|
189
534
|
};
|
|
190
|
-
return buildFieldNode(
|
|
535
|
+
return buildFieldNode(
|
|
536
|
+
field.name,
|
|
537
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
538
|
+
type,
|
|
539
|
+
field.required,
|
|
540
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
541
|
+
);
|
|
191
542
|
}
|
|
192
|
-
function canonicalizeDynamicSchemaField(field) {
|
|
543
|
+
function canonicalizeDynamicSchemaField(field, metadataPolicy) {
|
|
193
544
|
const type = {
|
|
194
545
|
kind: "dynamic",
|
|
195
546
|
dynamicKind: "schema",
|
|
196
547
|
sourceKey: field.schemaSource,
|
|
197
548
|
parameterFields: []
|
|
198
549
|
};
|
|
199
|
-
return buildFieldNode(
|
|
550
|
+
return buildFieldNode(
|
|
551
|
+
field.name,
|
|
552
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
553
|
+
type,
|
|
554
|
+
field.required,
|
|
555
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
556
|
+
);
|
|
200
557
|
}
|
|
201
|
-
function canonicalizeArrayField(field) {
|
|
202
|
-
const itemProperties = buildObjectProperties(field.items);
|
|
558
|
+
function canonicalizeArrayField(field, metadataPolicy) {
|
|
559
|
+
const itemProperties = buildObjectProperties(field.items, metadataPolicy);
|
|
203
560
|
const itemsType = {
|
|
204
561
|
kind: "object",
|
|
205
562
|
properties: itemProperties,
|
|
@@ -227,37 +584,44 @@ function canonicalizeArrayField(field) {
|
|
|
227
584
|
}
|
|
228
585
|
return buildFieldNode(
|
|
229
586
|
field.name,
|
|
587
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
230
588
|
type,
|
|
231
589
|
field.required,
|
|
232
|
-
buildAnnotations(field
|
|
590
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
233
591
|
constraints
|
|
234
592
|
);
|
|
235
593
|
}
|
|
236
|
-
function canonicalizeObjectField(field) {
|
|
237
|
-
const properties = buildObjectProperties(field.properties);
|
|
594
|
+
function canonicalizeObjectField(field, metadataPolicy) {
|
|
595
|
+
const properties = buildObjectProperties(field.properties, metadataPolicy);
|
|
238
596
|
const type = {
|
|
239
597
|
kind: "object",
|
|
240
598
|
properties,
|
|
241
599
|
additionalProperties: true
|
|
242
600
|
};
|
|
243
|
-
return buildFieldNode(
|
|
601
|
+
return buildFieldNode(
|
|
602
|
+
field.name,
|
|
603
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
604
|
+
type,
|
|
605
|
+
field.required,
|
|
606
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
607
|
+
);
|
|
244
608
|
}
|
|
245
|
-
function canonicalizeGroup(g) {
|
|
609
|
+
function canonicalizeGroup(g, metadataPolicy) {
|
|
246
610
|
return {
|
|
247
611
|
kind: "group",
|
|
248
612
|
label: g.label,
|
|
249
|
-
elements: canonicalizeElements(g.elements),
|
|
613
|
+
elements: canonicalizeElements(g.elements, metadataPolicy),
|
|
250
614
|
provenance: CHAIN_DSL_PROVENANCE
|
|
251
615
|
};
|
|
252
616
|
}
|
|
253
|
-
function canonicalizeConditional(c) {
|
|
617
|
+
function canonicalizeConditional(c, metadataPolicy) {
|
|
254
618
|
return {
|
|
255
619
|
kind: "conditional",
|
|
256
620
|
fieldName: c.field,
|
|
257
621
|
// Conditional values from the chain DSL are JSON-serializable primitives
|
|
258
622
|
// (strings, numbers, booleans) produced by the `is()` predicate helper.
|
|
259
623
|
value: assertJsonValue(c.value),
|
|
260
|
-
elements: canonicalizeElements(c.elements),
|
|
624
|
+
elements: canonicalizeElements(c.elements, metadataPolicy),
|
|
261
625
|
provenance: CHAIN_DSL_PROVENANCE
|
|
262
626
|
};
|
|
263
627
|
}
|
|
@@ -277,10 +641,11 @@ function assertJsonValue(v) {
|
|
|
277
641
|
}
|
|
278
642
|
throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);
|
|
279
643
|
}
|
|
280
|
-
function buildFieldNode(name, type, required, annotations, constraints = []) {
|
|
644
|
+
function buildFieldNode(name, metadata, type, required, annotations, constraints = []) {
|
|
281
645
|
return {
|
|
282
646
|
kind: "field",
|
|
283
647
|
name,
|
|
648
|
+
...metadata !== void 0 && { metadata },
|
|
284
649
|
type,
|
|
285
650
|
required: required === true,
|
|
286
651
|
constraints,
|
|
@@ -310,13 +675,14 @@ function buildAnnotations(label, placeholder) {
|
|
|
310
675
|
}
|
|
311
676
|
return annotations;
|
|
312
677
|
}
|
|
313
|
-
function buildObjectProperties(elements, insideConditional = false) {
|
|
678
|
+
function buildObjectProperties(elements, metadataPolicy, insideConditional = false) {
|
|
314
679
|
const properties = [];
|
|
315
680
|
for (const el of elements) {
|
|
316
681
|
if (isField(el)) {
|
|
317
|
-
const fieldNode = canonicalizeField(el);
|
|
682
|
+
const fieldNode = canonicalizeField(el, metadataPolicy);
|
|
318
683
|
properties.push({
|
|
319
684
|
name: fieldNode.name,
|
|
685
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
320
686
|
type: fieldNode.type,
|
|
321
687
|
// Fields inside a conditional branch are always optional in the
|
|
322
688
|
// data schema, regardless of their `required` flag — the condition
|
|
@@ -327,18 +693,36 @@ function buildObjectProperties(elements, insideConditional = false) {
|
|
|
327
693
|
provenance: CHAIN_DSL_PROVENANCE
|
|
328
694
|
});
|
|
329
695
|
} else if (isGroup(el)) {
|
|
330
|
-
properties.push(...buildObjectProperties(el.elements, insideConditional));
|
|
696
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, insideConditional));
|
|
331
697
|
} else if (isConditional(el)) {
|
|
332
|
-
properties.push(...buildObjectProperties(el.elements, true));
|
|
698
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, true));
|
|
333
699
|
}
|
|
334
700
|
}
|
|
335
701
|
return properties;
|
|
336
702
|
}
|
|
703
|
+
function getExplicitDisplayName(field) {
|
|
704
|
+
if (field.label !== void 0 && field.displayName !== void 0) {
|
|
705
|
+
throw new Error('Chain DSL fields cannot specify both "label" and "displayName".');
|
|
706
|
+
}
|
|
707
|
+
return field.displayName ?? field.label;
|
|
708
|
+
}
|
|
709
|
+
function resolveFieldMetadata(logicalName, field, metadataPolicy) {
|
|
710
|
+
const displayName = getExplicitDisplayName(field);
|
|
711
|
+
return resolveMetadata(
|
|
712
|
+
{
|
|
713
|
+
...field.apiName !== void 0 && { apiName: field.apiName },
|
|
714
|
+
...displayName !== void 0 && { displayName }
|
|
715
|
+
},
|
|
716
|
+
getDeclarationMetadataPolicy(metadataPolicy, "field"),
|
|
717
|
+
makeMetadataContext("chain-dsl", "field", logicalName)
|
|
718
|
+
);
|
|
719
|
+
}
|
|
337
720
|
var import_internals, CHAIN_DSL_PROVENANCE;
|
|
338
721
|
var init_chain_dsl_canonicalizer = __esm({
|
|
339
722
|
"src/canonicalize/chain-dsl-canonicalizer.ts"() {
|
|
340
723
|
"use strict";
|
|
341
724
|
import_internals = require("@formspec/core/internals");
|
|
725
|
+
init_metadata();
|
|
342
726
|
CHAIN_DSL_PROVENANCE = {
|
|
343
727
|
surface: "chain-dsl",
|
|
344
728
|
file: "",
|
|
@@ -349,7 +733,7 @@ var init_chain_dsl_canonicalizer = __esm({
|
|
|
349
733
|
});
|
|
350
734
|
|
|
351
735
|
// src/canonicalize/tsdoc-canonicalizer.ts
|
|
352
|
-
function canonicalizeTSDoc(analysis, source) {
|
|
736
|
+
function canonicalizeTSDoc(analysis, source, options) {
|
|
353
737
|
const file = source?.file ?? "";
|
|
354
738
|
const provenance = {
|
|
355
739
|
surface: "tsdoc",
|
|
@@ -358,15 +742,21 @@ function canonicalizeTSDoc(analysis, source) {
|
|
|
358
742
|
column: 0
|
|
359
743
|
};
|
|
360
744
|
const elements = assembleElements(analysis.fields, analysis.fieldLayouts, provenance);
|
|
361
|
-
|
|
745
|
+
const ir = {
|
|
362
746
|
kind: "form-ir",
|
|
747
|
+
name: analysis.name,
|
|
363
748
|
irVersion: import_internals2.IR_VERSION,
|
|
364
749
|
elements,
|
|
750
|
+
...analysis.metadata !== void 0 && { metadata: analysis.metadata },
|
|
365
751
|
typeRegistry: analysis.typeRegistry,
|
|
366
752
|
...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations },
|
|
367
753
|
...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { annotations: analysis.annotations },
|
|
368
754
|
provenance
|
|
369
755
|
};
|
|
756
|
+
return resolveFormIRMetadata(ir, {
|
|
757
|
+
policy: normalizeMetadataPolicy(options?.metadata),
|
|
758
|
+
surface: "tsdoc"
|
|
759
|
+
});
|
|
370
760
|
}
|
|
371
761
|
function assembleElements(fields, layouts, provenance) {
|
|
372
762
|
const elements = [];
|
|
@@ -427,6 +817,7 @@ var init_tsdoc_canonicalizer = __esm({
|
|
|
427
817
|
"src/canonicalize/tsdoc-canonicalizer.ts"() {
|
|
428
818
|
"use strict";
|
|
429
819
|
import_internals2 = require("@formspec/core/internals");
|
|
820
|
+
init_metadata();
|
|
430
821
|
}
|
|
431
822
|
});
|
|
432
823
|
|
|
@@ -439,6 +830,126 @@ var init_canonicalize = __esm({
|
|
|
439
830
|
}
|
|
440
831
|
});
|
|
441
832
|
|
|
833
|
+
// src/metadata/collision-guards.ts
|
|
834
|
+
function assertUniqueSerializedNames(entries, scope) {
|
|
835
|
+
const seen = /* @__PURE__ */ new Map();
|
|
836
|
+
for (const entry of entries) {
|
|
837
|
+
const previous = seen.get(entry.serializedName);
|
|
838
|
+
if (previous !== void 0) {
|
|
839
|
+
if (previous.logicalName === entry.logicalName && previous.category === entry.category) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
throw new Error(
|
|
843
|
+
`Serialized name collision in ${scope}: ${previous.category} "${previous.logicalName}" and ${entry.category} "${entry.logicalName}" both resolve to "${entry.serializedName}".`
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
seen.set(entry.serializedName, entry);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function collectFlattenedFields(elements) {
|
|
850
|
+
const fields = [];
|
|
851
|
+
for (const element of elements) {
|
|
852
|
+
switch (element.kind) {
|
|
853
|
+
case "field":
|
|
854
|
+
fields.push(element);
|
|
855
|
+
break;
|
|
856
|
+
case "group":
|
|
857
|
+
case "conditional":
|
|
858
|
+
fields.push(...collectFlattenedFields(element.elements));
|
|
859
|
+
break;
|
|
860
|
+
default: {
|
|
861
|
+
const exhaustive = element;
|
|
862
|
+
void exhaustive;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return fields;
|
|
867
|
+
}
|
|
868
|
+
function validateObjectProperties(properties, scope) {
|
|
869
|
+
assertUniqueSerializedNames(
|
|
870
|
+
properties.map((property) => ({
|
|
871
|
+
logicalName: property.name,
|
|
872
|
+
serializedName: getSerializedName(property.name, property.metadata),
|
|
873
|
+
category: "object property"
|
|
874
|
+
})),
|
|
875
|
+
scope
|
|
876
|
+
);
|
|
877
|
+
for (const property of properties) {
|
|
878
|
+
validateTypeNode(
|
|
879
|
+
property.type,
|
|
880
|
+
`${scope}.${getSerializedName(property.name, property.metadata)}`
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function validateTypeNode(type, scope) {
|
|
885
|
+
switch (type.kind) {
|
|
886
|
+
case "array":
|
|
887
|
+
validateTypeNode(type.items, `${scope}[]`);
|
|
888
|
+
break;
|
|
889
|
+
case "object":
|
|
890
|
+
validateObjectProperties(type.properties, scope);
|
|
891
|
+
break;
|
|
892
|
+
case "record":
|
|
893
|
+
validateTypeNode(type.valueType, `${scope}.*`);
|
|
894
|
+
break;
|
|
895
|
+
case "union":
|
|
896
|
+
type.members.forEach((member, index) => {
|
|
897
|
+
validateTypeNode(member, `${scope}|${String(index)}`);
|
|
898
|
+
});
|
|
899
|
+
break;
|
|
900
|
+
case "reference":
|
|
901
|
+
case "primitive":
|
|
902
|
+
case "enum":
|
|
903
|
+
case "dynamic":
|
|
904
|
+
case "custom":
|
|
905
|
+
break;
|
|
906
|
+
default: {
|
|
907
|
+
const exhaustive = type;
|
|
908
|
+
void exhaustive;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function validateTypeDefinitions(typeRegistry) {
|
|
913
|
+
const definitions = Object.values(typeRegistry);
|
|
914
|
+
assertUniqueSerializedNames(
|
|
915
|
+
definitions.map((definition) => ({
|
|
916
|
+
logicalName: definition.name,
|
|
917
|
+
serializedName: getSerializedName(definition.name, definition.metadata),
|
|
918
|
+
category: "type definition"
|
|
919
|
+
})),
|
|
920
|
+
"$defs"
|
|
921
|
+
);
|
|
922
|
+
for (const definition of definitions) {
|
|
923
|
+
validateTypeDefinition(definition);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function validateTypeDefinition(definition) {
|
|
927
|
+
validateTypeNode(
|
|
928
|
+
definition.type,
|
|
929
|
+
`type "${getSerializedName(definition.name, definition.metadata)}"`
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
function assertNoSerializedNameCollisions(ir) {
|
|
933
|
+
assertUniqueSerializedNames(
|
|
934
|
+
collectFlattenedFields(ir.elements).map((field) => ({
|
|
935
|
+
logicalName: field.name,
|
|
936
|
+
serializedName: getSerializedName(field.name, field.metadata),
|
|
937
|
+
category: "field"
|
|
938
|
+
})),
|
|
939
|
+
"form root"
|
|
940
|
+
);
|
|
941
|
+
for (const field of collectFlattenedFields(ir.elements)) {
|
|
942
|
+
validateTypeNode(field.type, `field "${getSerializedName(field.name, field.metadata)}"`);
|
|
943
|
+
}
|
|
944
|
+
validateTypeDefinitions(ir.typeRegistry);
|
|
945
|
+
}
|
|
946
|
+
var init_collision_guards = __esm({
|
|
947
|
+
"src/metadata/collision-guards.ts"() {
|
|
948
|
+
"use strict";
|
|
949
|
+
init_resolve();
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
|
|
442
953
|
// src/json-schema/ir-generator.ts
|
|
443
954
|
function makeContext(options) {
|
|
444
955
|
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
@@ -449,19 +960,33 @@ function makeContext(options) {
|
|
|
449
960
|
}
|
|
450
961
|
return {
|
|
451
962
|
defs: {},
|
|
963
|
+
typeNameMap: {},
|
|
964
|
+
typeRegistry: {},
|
|
452
965
|
extensionRegistry: options?.extensionRegistry,
|
|
453
966
|
vendorPrefix
|
|
454
967
|
};
|
|
455
968
|
}
|
|
456
969
|
function generateJsonSchemaFromIR(ir, options) {
|
|
457
|
-
|
|
970
|
+
assertNoSerializedNameCollisions(ir);
|
|
971
|
+
const ctx = {
|
|
972
|
+
...makeContext(options),
|
|
973
|
+
typeRegistry: ir.typeRegistry,
|
|
974
|
+
typeNameMap: Object.fromEntries(
|
|
975
|
+
Object.entries(ir.typeRegistry).map(([name, typeDef]) => [
|
|
976
|
+
name,
|
|
977
|
+
getSerializedName(name, typeDef.metadata)
|
|
978
|
+
])
|
|
979
|
+
)
|
|
980
|
+
};
|
|
458
981
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
459
|
-
ctx.
|
|
982
|
+
const schemaName = ctx.typeNameMap[name] ?? name;
|
|
983
|
+
ctx.defs[schemaName] = generateTypeNode(typeDef.type, ctx);
|
|
984
|
+
applyResolvedMetadata(ctx.defs[schemaName], typeDef.metadata);
|
|
460
985
|
if (typeDef.constraints && typeDef.constraints.length > 0) {
|
|
461
|
-
applyConstraints(ctx.defs[
|
|
986
|
+
applyConstraints(ctx.defs[schemaName], typeDef.constraints, ctx);
|
|
462
987
|
}
|
|
463
988
|
if (typeDef.annotations && typeDef.annotations.length > 0) {
|
|
464
|
-
applyAnnotations(ctx.defs[
|
|
989
|
+
applyAnnotations(ctx.defs[schemaName], typeDef.annotations, ctx);
|
|
465
990
|
}
|
|
466
991
|
}
|
|
467
992
|
const properties = {};
|
|
@@ -474,6 +999,7 @@ function generateJsonSchemaFromIR(ir, options) {
|
|
|
474
999
|
properties,
|
|
475
1000
|
...uniqueRequired.length > 0 && { required: uniqueRequired }
|
|
476
1001
|
};
|
|
1002
|
+
applyResolvedMetadata(result, ir.metadata);
|
|
477
1003
|
if (ir.annotations && ir.annotations.length > 0) {
|
|
478
1004
|
applyAnnotations(result, ir.annotations, ctx);
|
|
479
1005
|
}
|
|
@@ -486,9 +1012,9 @@ function collectFields(elements, properties, required, ctx) {
|
|
|
486
1012
|
for (const element of elements) {
|
|
487
1013
|
switch (element.kind) {
|
|
488
1014
|
case "field":
|
|
489
|
-
properties[element.name] = generateFieldSchema(element, ctx);
|
|
1015
|
+
properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
|
|
490
1016
|
if (element.required) {
|
|
491
|
-
required.push(element.name);
|
|
1017
|
+
required.push(getSerializedName(element.name, element.metadata));
|
|
492
1018
|
}
|
|
493
1019
|
break;
|
|
494
1020
|
case "group":
|
|
@@ -532,6 +1058,7 @@ function generateFieldSchema(field, ctx) {
|
|
|
532
1058
|
rootAnnotations.push(annotation);
|
|
533
1059
|
}
|
|
534
1060
|
}
|
|
1061
|
+
applyResolvedMetadata(schema, field.metadata);
|
|
535
1062
|
applyAnnotations(schema, rootAnnotations, ctx);
|
|
536
1063
|
if (itemStringSchema !== void 0) {
|
|
537
1064
|
applyAnnotations(itemStringSchema, itemAnnotations, ctx);
|
|
@@ -539,7 +1066,7 @@ function generateFieldSchema(field, ctx) {
|
|
|
539
1066
|
if (pathConstraints.length === 0) {
|
|
540
1067
|
return schema;
|
|
541
1068
|
}
|
|
542
|
-
return applyPathTargetedConstraints(schema, pathConstraints, ctx);
|
|
1069
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx, field.type);
|
|
543
1070
|
}
|
|
544
1071
|
function isStringItemConstraint(constraint) {
|
|
545
1072
|
switch (constraint.constraintKind) {
|
|
@@ -551,9 +1078,11 @@ function isStringItemConstraint(constraint) {
|
|
|
551
1078
|
return false;
|
|
552
1079
|
}
|
|
553
1080
|
}
|
|
554
|
-
function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
1081
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
|
|
555
1082
|
if (schema.type === "array" && schema.items) {
|
|
556
|
-
|
|
1083
|
+
const referencedType = typeNode?.kind === "reference" ? resolveReferencedType(typeNode, ctx) : void 0;
|
|
1084
|
+
const nestedType = typeNode?.kind === "array" ? typeNode.items : referencedType?.kind === "array" ? referencedType.items : void 0;
|
|
1085
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
|
|
557
1086
|
return schema;
|
|
558
1087
|
}
|
|
559
1088
|
const byTarget = /* @__PURE__ */ new Map();
|
|
@@ -568,7 +1097,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
|
568
1097
|
for (const [target, constraints] of byTarget) {
|
|
569
1098
|
const subSchema = {};
|
|
570
1099
|
applyConstraints(subSchema, constraints, ctx);
|
|
571
|
-
propertyOverrides[target] = subSchema;
|
|
1100
|
+
propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;
|
|
572
1101
|
}
|
|
573
1102
|
if (schema.$ref) {
|
|
574
1103
|
const { $ref, ...rest } = schema;
|
|
@@ -616,7 +1145,7 @@ function generateTypeNode(type, ctx) {
|
|
|
616
1145
|
case "union":
|
|
617
1146
|
return generateUnionType(type, ctx);
|
|
618
1147
|
case "reference":
|
|
619
|
-
return generateReferenceType(type);
|
|
1148
|
+
return generateReferenceType(type, ctx);
|
|
620
1149
|
case "dynamic":
|
|
621
1150
|
return generateDynamicType(type);
|
|
622
1151
|
case "custom":
|
|
@@ -657,9 +1186,10 @@ function generateObjectType(type, ctx) {
|
|
|
657
1186
|
const properties = {};
|
|
658
1187
|
const required = [];
|
|
659
1188
|
for (const prop of type.properties) {
|
|
660
|
-
|
|
1189
|
+
const propertyName = getSerializedName(prop.name, prop.metadata);
|
|
1190
|
+
properties[propertyName] = generatePropertySchema(prop, ctx);
|
|
661
1191
|
if (!prop.optional) {
|
|
662
|
-
required.push(
|
|
1192
|
+
required.push(propertyName);
|
|
663
1193
|
}
|
|
664
1194
|
}
|
|
665
1195
|
const schema = { type: "object", properties };
|
|
@@ -680,6 +1210,7 @@ function generateRecordType(type, ctx) {
|
|
|
680
1210
|
function generatePropertySchema(prop, ctx) {
|
|
681
1211
|
const schema = generateTypeNode(prop.type, ctx);
|
|
682
1212
|
applyConstraints(schema, prop.constraints, ctx);
|
|
1213
|
+
applyResolvedMetadata(schema, prop.metadata);
|
|
683
1214
|
applyAnnotations(schema, prop.annotations, ctx);
|
|
684
1215
|
return schema;
|
|
685
1216
|
}
|
|
@@ -708,8 +1239,28 @@ function isNullableUnion(type) {
|
|
|
708
1239
|
).length;
|
|
709
1240
|
return nullCount === 1;
|
|
710
1241
|
}
|
|
711
|
-
function generateReferenceType(type) {
|
|
712
|
-
return { $ref: `#/$defs/${type.name}` };
|
|
1242
|
+
function generateReferenceType(type, ctx) {
|
|
1243
|
+
return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
|
|
1244
|
+
}
|
|
1245
|
+
function applyResolvedMetadata(schema, metadata) {
|
|
1246
|
+
const displayName = getDisplayName(metadata);
|
|
1247
|
+
if (displayName !== void 0) {
|
|
1248
|
+
schema.title = displayName;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function resolveReferencedType(type, ctx) {
|
|
1252
|
+
return ctx.typeRegistry[type.name]?.type;
|
|
1253
|
+
}
|
|
1254
|
+
function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
|
|
1255
|
+
if (typeNode?.kind === "object") {
|
|
1256
|
+
const property = typeNode.properties.find((candidate) => candidate.name === logicalName);
|
|
1257
|
+
return property === void 0 ? logicalName : getSerializedName(property.name, property.metadata);
|
|
1258
|
+
}
|
|
1259
|
+
if (typeNode?.kind === "reference") {
|
|
1260
|
+
const referencedType = resolveReferencedType(typeNode, ctx);
|
|
1261
|
+
return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
|
|
1262
|
+
}
|
|
1263
|
+
return logicalName;
|
|
713
1264
|
}
|
|
714
1265
|
function generateDynamicType(type) {
|
|
715
1266
|
if (type.dynamicKind === "enum") {
|
|
@@ -789,7 +1340,7 @@ function applyAnnotations(schema, annotations, ctx) {
|
|
|
789
1340
|
for (const annotation of annotations) {
|
|
790
1341
|
switch (annotation.annotationKind) {
|
|
791
1342
|
case "displayName":
|
|
792
|
-
schema.title
|
|
1343
|
+
schema.title ??= annotation.value;
|
|
793
1344
|
break;
|
|
794
1345
|
case "description":
|
|
795
1346
|
schema.description = annotation.value;
|
|
@@ -876,12 +1427,17 @@ function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPr
|
|
|
876
1427
|
var init_ir_generator = __esm({
|
|
877
1428
|
"src/json-schema/ir-generator.ts"() {
|
|
878
1429
|
"use strict";
|
|
1430
|
+
init_metadata();
|
|
1431
|
+
init_collision_guards();
|
|
879
1432
|
}
|
|
880
1433
|
});
|
|
881
1434
|
|
|
882
1435
|
// src/json-schema/generator.ts
|
|
883
1436
|
function generateJsonSchema(form, options) {
|
|
884
|
-
const ir = canonicalizeChainDSL(
|
|
1437
|
+
const ir = canonicalizeChainDSL(
|
|
1438
|
+
form,
|
|
1439
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
1440
|
+
);
|
|
885
1441
|
const internalOptions = options?.vendorPrefix === void 0 ? void 0 : { vendorPrefix: options.vendorPrefix };
|
|
886
1442
|
return generateJsonSchemaFromIR(ir, internalOptions);
|
|
887
1443
|
}
|
|
@@ -1063,13 +1619,21 @@ function combineRules(parentRule, childRule) {
|
|
|
1063
1619
|
}
|
|
1064
1620
|
};
|
|
1065
1621
|
}
|
|
1066
|
-
function
|
|
1067
|
-
const
|
|
1622
|
+
function getFieldDisplayName(field) {
|
|
1623
|
+
const resolvedDisplayName = getDisplayName(field.metadata);
|
|
1624
|
+
if (resolvedDisplayName !== void 0) {
|
|
1625
|
+
return resolvedDisplayName;
|
|
1626
|
+
}
|
|
1627
|
+
return field.annotations.find((annotation) => annotation.annotationKind === "displayName")?.value;
|
|
1628
|
+
}
|
|
1629
|
+
function fieldNodeToControl(field, fieldNameMap, parentRule) {
|
|
1068
1630
|
const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === "placeholder");
|
|
1631
|
+
const serializedName = fieldNameMap.get(field.name) ?? getSerializedName(field.name, field.metadata);
|
|
1632
|
+
const displayName = getFieldDisplayName(field);
|
|
1069
1633
|
const control = {
|
|
1070
1634
|
type: "Control",
|
|
1071
|
-
scope: fieldToScope(
|
|
1072
|
-
...
|
|
1635
|
+
scope: fieldToScope(serializedName),
|
|
1636
|
+
...displayName !== void 0 && { label: displayName },
|
|
1073
1637
|
...placeholderAnnotation !== void 0 && {
|
|
1074
1638
|
options: { placeholder: placeholderAnnotation.value }
|
|
1075
1639
|
},
|
|
@@ -1077,30 +1641,30 @@ function fieldNodeToControl(field, parentRule) {
|
|
|
1077
1641
|
};
|
|
1078
1642
|
return control;
|
|
1079
1643
|
}
|
|
1080
|
-
function groupNodeToLayout(group, parentRule) {
|
|
1644
|
+
function groupNodeToLayout(group, fieldNameMap, parentRule) {
|
|
1081
1645
|
return {
|
|
1082
1646
|
type: "Group",
|
|
1083
1647
|
label: group.label,
|
|
1084
|
-
elements: irElementsToUiSchema(group.elements, parentRule),
|
|
1648
|
+
elements: irElementsToUiSchema(group.elements, fieldNameMap, parentRule),
|
|
1085
1649
|
...parentRule !== void 0 && { rule: parentRule }
|
|
1086
1650
|
};
|
|
1087
1651
|
}
|
|
1088
|
-
function irElementsToUiSchema(elements, parentRule) {
|
|
1652
|
+
function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
|
|
1089
1653
|
const result = [];
|
|
1090
1654
|
for (const element of elements) {
|
|
1091
1655
|
switch (element.kind) {
|
|
1092
1656
|
case "field": {
|
|
1093
|
-
result.push(fieldNodeToControl(element, parentRule));
|
|
1657
|
+
result.push(fieldNodeToControl(element, fieldNameMap, parentRule));
|
|
1094
1658
|
break;
|
|
1095
1659
|
}
|
|
1096
1660
|
case "group": {
|
|
1097
|
-
result.push(groupNodeToLayout(element, parentRule));
|
|
1661
|
+
result.push(groupNodeToLayout(element, fieldNameMap, parentRule));
|
|
1098
1662
|
break;
|
|
1099
1663
|
}
|
|
1100
1664
|
case "conditional": {
|
|
1101
|
-
const newRule = createShowRule(element.fieldName, element.value);
|
|
1665
|
+
const newRule = createShowRule(fieldNameMap.get(element.fieldName) ?? element.fieldName, element.value);
|
|
1102
1666
|
const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
|
|
1103
|
-
const childElements = irElementsToUiSchema(element.elements, combinedRule);
|
|
1667
|
+
const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
|
|
1104
1668
|
result.push(...childElements);
|
|
1105
1669
|
break;
|
|
1106
1670
|
}
|
|
@@ -1114,24 +1678,52 @@ function irElementsToUiSchema(elements, parentRule) {
|
|
|
1114
1678
|
return result;
|
|
1115
1679
|
}
|
|
1116
1680
|
function generateUiSchemaFromIR(ir) {
|
|
1681
|
+
assertNoSerializedNameCollisions(ir);
|
|
1682
|
+
const fieldNameMap = collectFieldNameMap(ir.elements);
|
|
1117
1683
|
const result = {
|
|
1118
1684
|
type: "VerticalLayout",
|
|
1119
|
-
elements: irElementsToUiSchema(ir.elements)
|
|
1685
|
+
elements: irElementsToUiSchema(ir.elements, fieldNameMap)
|
|
1120
1686
|
};
|
|
1121
1687
|
return parseOrThrow(uiSchema, result, "UI Schema");
|
|
1122
1688
|
}
|
|
1689
|
+
function collectFieldNameMap(elements) {
|
|
1690
|
+
const map = /* @__PURE__ */ new Map();
|
|
1691
|
+
for (const element of elements) {
|
|
1692
|
+
switch (element.kind) {
|
|
1693
|
+
case "field":
|
|
1694
|
+
map.set(element.name, getSerializedName(element.name, element.metadata));
|
|
1695
|
+
break;
|
|
1696
|
+
case "group":
|
|
1697
|
+
case "conditional":
|
|
1698
|
+
for (const [key, value] of collectFieldNameMap(element.elements)) {
|
|
1699
|
+
map.set(key, value);
|
|
1700
|
+
}
|
|
1701
|
+
break;
|
|
1702
|
+
default: {
|
|
1703
|
+
const _exhaustive = element;
|
|
1704
|
+
void _exhaustive;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return map;
|
|
1709
|
+
}
|
|
1123
1710
|
var import_zod2;
|
|
1124
1711
|
var init_ir_generator2 = __esm({
|
|
1125
1712
|
"src/ui-schema/ir-generator.ts"() {
|
|
1126
1713
|
"use strict";
|
|
1714
|
+
init_metadata();
|
|
1715
|
+
init_collision_guards();
|
|
1127
1716
|
init_schema();
|
|
1128
1717
|
import_zod2 = require("zod");
|
|
1129
1718
|
}
|
|
1130
1719
|
});
|
|
1131
1720
|
|
|
1132
1721
|
// src/ui-schema/generator.ts
|
|
1133
|
-
function generateUiSchema(form) {
|
|
1134
|
-
const ir = canonicalizeChainDSL(
|
|
1722
|
+
function generateUiSchema(form, options) {
|
|
1723
|
+
const ir = canonicalizeChainDSL(
|
|
1724
|
+
form,
|
|
1725
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
1726
|
+
);
|
|
1135
1727
|
return generateUiSchemaFromIR(ir);
|
|
1136
1728
|
}
|
|
1137
1729
|
var init_generator2 = __esm({
|
|
@@ -2185,7 +2777,76 @@ function makeParseOptions(extensionRegistry, fieldType, checker, subjectType, ho
|
|
|
2185
2777
|
...hostType !== void 0 && { hostType }
|
|
2186
2778
|
};
|
|
2187
2779
|
}
|
|
2188
|
-
function
|
|
2780
|
+
function makeExplicitScalarMetadata(value) {
|
|
2781
|
+
return value === void 0 || value === "" ? void 0 : { value, source: "explicit" };
|
|
2782
|
+
}
|
|
2783
|
+
function extractExplicitMetadata(node) {
|
|
2784
|
+
let apiName;
|
|
2785
|
+
let displayName;
|
|
2786
|
+
let apiNamePlural;
|
|
2787
|
+
let displayNamePlural;
|
|
2788
|
+
for (const tag of getLeadingParsedTags(node)) {
|
|
2789
|
+
const value = tag.argumentText.trim();
|
|
2790
|
+
if (value === "") {
|
|
2791
|
+
continue;
|
|
2792
|
+
}
|
|
2793
|
+
if (tag.normalizedTagName === "apiName") {
|
|
2794
|
+
if (tag.target === null) {
|
|
2795
|
+
apiName ??= value;
|
|
2796
|
+
} else if (tag.target.kind === "variant") {
|
|
2797
|
+
if (tag.target.rawText === "singular") {
|
|
2798
|
+
apiName ??= value;
|
|
2799
|
+
} else if (tag.target.rawText === "plural") {
|
|
2800
|
+
apiNamePlural ??= value;
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
continue;
|
|
2804
|
+
}
|
|
2805
|
+
if (tag.normalizedTagName === "displayName") {
|
|
2806
|
+
if (tag.target === null) {
|
|
2807
|
+
displayName ??= value;
|
|
2808
|
+
} else if (tag.target.kind === "variant") {
|
|
2809
|
+
if (tag.target.rawText === "singular") {
|
|
2810
|
+
displayName ??= value;
|
|
2811
|
+
} else if (tag.target.rawText === "plural") {
|
|
2812
|
+
displayNamePlural ??= value;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
const resolvedApiName = makeExplicitScalarMetadata(apiName);
|
|
2818
|
+
const resolvedDisplayName = makeExplicitScalarMetadata(displayName);
|
|
2819
|
+
const resolvedApiNamePlural = makeExplicitScalarMetadata(apiNamePlural);
|
|
2820
|
+
const resolvedDisplayNamePlural = makeExplicitScalarMetadata(displayNamePlural);
|
|
2821
|
+
const metadata = {
|
|
2822
|
+
...resolvedApiName !== void 0 && { apiName: resolvedApiName },
|
|
2823
|
+
...resolvedDisplayName !== void 0 && { displayName: resolvedDisplayName },
|
|
2824
|
+
...resolvedApiNamePlural !== void 0 && { apiNamePlural: resolvedApiNamePlural },
|
|
2825
|
+
...resolvedDisplayNamePlural !== void 0 && {
|
|
2826
|
+
displayNamePlural: resolvedDisplayNamePlural
|
|
2827
|
+
}
|
|
2828
|
+
};
|
|
2829
|
+
return Object.keys(metadata).length === 0 ? void 0 : metadata;
|
|
2830
|
+
}
|
|
2831
|
+
function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, buildContext) {
|
|
2832
|
+
const explicit = extractExplicitMetadata(node);
|
|
2833
|
+
return resolveMetadata(
|
|
2834
|
+
{
|
|
2835
|
+
...explicit?.apiName !== void 0 && { apiName: explicit.apiName.value },
|
|
2836
|
+
...explicit?.displayName !== void 0 && { displayName: explicit.displayName.value },
|
|
2837
|
+
...explicit?.apiNamePlural !== void 0 && {
|
|
2838
|
+
apiNamePlural: explicit.apiNamePlural.value
|
|
2839
|
+
},
|
|
2840
|
+
...explicit?.displayNamePlural !== void 0 && {
|
|
2841
|
+
displayNamePlural: explicit.displayNamePlural.value
|
|
2842
|
+
}
|
|
2843
|
+
},
|
|
2844
|
+
getDeclarationMetadataPolicy(metadataPolicy, declarationKind),
|
|
2845
|
+
makeMetadataContext("tsdoc", declarationKind, logicalName, buildContext)
|
|
2846
|
+
);
|
|
2847
|
+
}
|
|
2848
|
+
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2849
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2189
2850
|
const name = classDecl.name?.text ?? "AnonymousClass";
|
|
2190
2851
|
const fields = [];
|
|
2191
2852
|
const fieldLayouts = [];
|
|
@@ -2212,6 +2873,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2212
2873
|
visiting,
|
|
2213
2874
|
diagnostics,
|
|
2214
2875
|
classType,
|
|
2876
|
+
normalizedMetadataPolicy,
|
|
2215
2877
|
extensionRegistry
|
|
2216
2878
|
);
|
|
2217
2879
|
if (fieldNode) {
|
|
@@ -2230,9 +2892,25 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2230
2892
|
}
|
|
2231
2893
|
}
|
|
2232
2894
|
}
|
|
2895
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2896
|
+
fields,
|
|
2897
|
+
classDecl,
|
|
2898
|
+
classType,
|
|
2899
|
+
checker,
|
|
2900
|
+
file,
|
|
2901
|
+
diagnostics,
|
|
2902
|
+
normalizedMetadataPolicy
|
|
2903
|
+
);
|
|
2904
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, classDecl, {
|
|
2905
|
+
checker,
|
|
2906
|
+
declaration: classDecl,
|
|
2907
|
+
subjectType: classType,
|
|
2908
|
+
hostType: classType
|
|
2909
|
+
});
|
|
2233
2910
|
return {
|
|
2234
2911
|
name,
|
|
2235
|
-
|
|
2912
|
+
...metadata !== void 0 && { metadata },
|
|
2913
|
+
fields: specializedFields,
|
|
2236
2914
|
fieldLayouts,
|
|
2237
2915
|
typeRegistry,
|
|
2238
2916
|
...annotations.length > 0 && { annotations },
|
|
@@ -2241,7 +2919,8 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2241
2919
|
staticMethods
|
|
2242
2920
|
};
|
|
2243
2921
|
}
|
|
2244
|
-
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry) {
|
|
2922
|
+
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2923
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2245
2924
|
const name = interfaceDecl.name.text;
|
|
2246
2925
|
const fields = [];
|
|
2247
2926
|
const typeRegistry = {};
|
|
@@ -2265,6 +2944,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2265
2944
|
visiting,
|
|
2266
2945
|
diagnostics,
|
|
2267
2946
|
interfaceType,
|
|
2947
|
+
normalizedMetadataPolicy,
|
|
2268
2948
|
extensionRegistry
|
|
2269
2949
|
);
|
|
2270
2950
|
if (fieldNode) {
|
|
@@ -2272,10 +2952,26 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2272
2952
|
}
|
|
2273
2953
|
}
|
|
2274
2954
|
}
|
|
2275
|
-
const
|
|
2955
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2956
|
+
fields,
|
|
2957
|
+
interfaceDecl,
|
|
2958
|
+
interfaceType,
|
|
2959
|
+
checker,
|
|
2960
|
+
file,
|
|
2961
|
+
diagnostics,
|
|
2962
|
+
normalizedMetadataPolicy
|
|
2963
|
+
);
|
|
2964
|
+
const fieldLayouts = specializedFields.map(() => ({}));
|
|
2965
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, interfaceDecl, {
|
|
2966
|
+
checker,
|
|
2967
|
+
declaration: interfaceDecl,
|
|
2968
|
+
subjectType: interfaceType,
|
|
2969
|
+
hostType: interfaceType
|
|
2970
|
+
});
|
|
2276
2971
|
return {
|
|
2277
2972
|
name,
|
|
2278
|
-
|
|
2973
|
+
...metadata !== void 0 && { metadata },
|
|
2974
|
+
fields: specializedFields,
|
|
2279
2975
|
fieldLayouts,
|
|
2280
2976
|
typeRegistry,
|
|
2281
2977
|
...annotations.length > 0 && { annotations },
|
|
@@ -2284,7 +2980,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2284
2980
|
staticMethods: []
|
|
2285
2981
|
};
|
|
2286
2982
|
}
|
|
2287
|
-
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
|
|
2983
|
+
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2288
2984
|
if (!ts3.isTypeLiteralNode(typeAlias.type)) {
|
|
2289
2985
|
const sourceFile = typeAlias.getSourceFile();
|
|
2290
2986
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
@@ -2294,6 +2990,8 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2294
2990
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
|
|
2295
2991
|
};
|
|
2296
2992
|
}
|
|
2993
|
+
const typeLiteral = typeAlias.type;
|
|
2994
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2297
2995
|
const name = typeAlias.name.text;
|
|
2298
2996
|
const fields = [];
|
|
2299
2997
|
const typeRegistry = {};
|
|
@@ -2307,7 +3005,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2307
3005
|
const annotations = [...typeAliasDoc.annotations];
|
|
2308
3006
|
diagnostics.push(...typeAliasDoc.diagnostics);
|
|
2309
3007
|
const visiting = /* @__PURE__ */ new Set();
|
|
2310
|
-
for (const member of
|
|
3008
|
+
for (const member of typeLiteral.members) {
|
|
2311
3009
|
if (ts3.isPropertySignature(member)) {
|
|
2312
3010
|
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2313
3011
|
member,
|
|
@@ -2317,6 +3015,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2317
3015
|
visiting,
|
|
2318
3016
|
diagnostics,
|
|
2319
3017
|
aliasType,
|
|
3018
|
+
normalizedMetadataPolicy,
|
|
2320
3019
|
extensionRegistry
|
|
2321
3020
|
);
|
|
2322
3021
|
if (fieldNode) {
|
|
@@ -2324,12 +3023,28 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2324
3023
|
}
|
|
2325
3024
|
}
|
|
2326
3025
|
}
|
|
3026
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
3027
|
+
fields,
|
|
3028
|
+
typeAlias,
|
|
3029
|
+
aliasType,
|
|
3030
|
+
checker,
|
|
3031
|
+
file,
|
|
3032
|
+
diagnostics,
|
|
3033
|
+
normalizedMetadataPolicy
|
|
3034
|
+
);
|
|
3035
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, typeAlias, {
|
|
3036
|
+
checker,
|
|
3037
|
+
declaration: typeAlias,
|
|
3038
|
+
subjectType: aliasType,
|
|
3039
|
+
hostType: aliasType
|
|
3040
|
+
});
|
|
2327
3041
|
return {
|
|
2328
3042
|
ok: true,
|
|
2329
3043
|
analysis: {
|
|
2330
3044
|
name,
|
|
2331
|
-
|
|
2332
|
-
|
|
3045
|
+
...metadata !== void 0 && { metadata },
|
|
3046
|
+
fields: specializedFields,
|
|
3047
|
+
fieldLayouts: specializedFields.map(() => ({})),
|
|
2333
3048
|
typeRegistry,
|
|
2334
3049
|
...annotations.length > 0 && { annotations },
|
|
2335
3050
|
...diagnostics.length > 0 && { diagnostics },
|
|
@@ -2338,7 +3053,444 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2338
3053
|
}
|
|
2339
3054
|
};
|
|
2340
3055
|
}
|
|
2341
|
-
function
|
|
3056
|
+
function makeAnalysisDiagnostic(code, message, primaryLocation, relatedLocations = []) {
|
|
3057
|
+
return {
|
|
3058
|
+
code,
|
|
3059
|
+
message,
|
|
3060
|
+
severity: "error",
|
|
3061
|
+
primaryLocation,
|
|
3062
|
+
relatedLocations
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
function getLeadingParsedTags(node) {
|
|
3066
|
+
const sourceFile = node.getSourceFile();
|
|
3067
|
+
const sourceText = sourceFile.getFullText();
|
|
3068
|
+
const commentRanges = ts3.getLeadingCommentRanges(sourceText, node.getFullStart());
|
|
3069
|
+
if (commentRanges === void 0) {
|
|
3070
|
+
return [];
|
|
3071
|
+
}
|
|
3072
|
+
const parsedTags = [];
|
|
3073
|
+
for (const range of commentRanges) {
|
|
3074
|
+
if (range.kind !== ts3.SyntaxKind.MultiLineCommentTrivia) {
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
const commentText = sourceText.slice(range.pos, range.end);
|
|
3078
|
+
if (!commentText.startsWith("/**")) {
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
parsedTags.push(...(0, import_internal2.parseCommentBlock)(commentText, { offset: range.pos }).tags);
|
|
3082
|
+
}
|
|
3083
|
+
return parsedTags;
|
|
3084
|
+
}
|
|
3085
|
+
function resolveDiscriminatorProperty(node, checker, fieldName) {
|
|
3086
|
+
const subjectType = checker.getTypeAtLocation(node);
|
|
3087
|
+
const propertySymbol = subjectType.getProperty(fieldName);
|
|
3088
|
+
if (propertySymbol === void 0) {
|
|
3089
|
+
return null;
|
|
3090
|
+
}
|
|
3091
|
+
const declaration = propertySymbol.valueDeclaration ?? propertySymbol.declarations?.find(
|
|
3092
|
+
(candidate) => ts3.isPropertyDeclaration(candidate) || ts3.isPropertySignature(candidate)
|
|
3093
|
+
) ?? propertySymbol.declarations?.[0];
|
|
3094
|
+
return {
|
|
3095
|
+
declaration,
|
|
3096
|
+
type: checker.getTypeOfSymbolAtLocation(propertySymbol, declaration ?? node),
|
|
3097
|
+
optional: !!(propertySymbol.flags & ts3.SymbolFlags.Optional) || declaration !== void 0 && "questionToken" in declaration && declaration.questionToken !== void 0
|
|
3098
|
+
};
|
|
3099
|
+
}
|
|
3100
|
+
function isLocalTypeParameterName(node, typeParameterName) {
|
|
3101
|
+
return node.typeParameters?.some((typeParameter) => typeParameter.name.text === typeParameterName) ?? false;
|
|
3102
|
+
}
|
|
3103
|
+
function isNullishSemanticType(type) {
|
|
3104
|
+
if (type.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined | ts3.TypeFlags.Void | ts3.TypeFlags.Unknown | ts3.TypeFlags.Any)) {
|
|
3105
|
+
return true;
|
|
3106
|
+
}
|
|
3107
|
+
return type.isUnion() && type.types.some((member) => isNullishSemanticType(member));
|
|
3108
|
+
}
|
|
3109
|
+
function isStringLikeSemanticType(type) {
|
|
3110
|
+
if (type.flags & ts3.TypeFlags.StringLike) {
|
|
3111
|
+
return true;
|
|
3112
|
+
}
|
|
3113
|
+
if (type.isUnion()) {
|
|
3114
|
+
return type.types.length > 0 && type.types.every((member) => isStringLikeSemanticType(member));
|
|
3115
|
+
}
|
|
3116
|
+
return false;
|
|
3117
|
+
}
|
|
3118
|
+
function extractDiscriminatorDirective(node, file, diagnostics) {
|
|
3119
|
+
const discriminatorTags = getLeadingParsedTags(node).filter(
|
|
3120
|
+
(tag) => tag.normalizedTagName === "discriminator"
|
|
3121
|
+
);
|
|
3122
|
+
if (discriminatorTags.length === 0) {
|
|
3123
|
+
return null;
|
|
3124
|
+
}
|
|
3125
|
+
const [firstTag, ...duplicateTags] = discriminatorTags;
|
|
3126
|
+
for (const _duplicateTag of duplicateTags) {
|
|
3127
|
+
diagnostics.push(
|
|
3128
|
+
makeAnalysisDiagnostic(
|
|
3129
|
+
"DUPLICATE_TAG",
|
|
3130
|
+
'Duplicate "@discriminator" tag. Only one discriminator declaration is allowed per declaration.',
|
|
3131
|
+
provenanceForNode(node, file)
|
|
3132
|
+
)
|
|
3133
|
+
);
|
|
3134
|
+
}
|
|
3135
|
+
if (firstTag === void 0) {
|
|
3136
|
+
return null;
|
|
3137
|
+
}
|
|
3138
|
+
const firstTarget = firstTag.target;
|
|
3139
|
+
if (firstTarget?.path === null || firstTarget?.valid !== true) {
|
|
3140
|
+
diagnostics.push(
|
|
3141
|
+
makeAnalysisDiagnostic(
|
|
3142
|
+
"INVALID_TAG_ARGUMENT",
|
|
3143
|
+
'Tag "@discriminator" requires a direct path target like ":kind".',
|
|
3144
|
+
provenanceForNode(node, file)
|
|
3145
|
+
)
|
|
3146
|
+
);
|
|
3147
|
+
return null;
|
|
3148
|
+
}
|
|
3149
|
+
if (firstTarget.path.segments.length !== 1) {
|
|
3150
|
+
diagnostics.push(
|
|
3151
|
+
makeAnalysisDiagnostic(
|
|
3152
|
+
"INVALID_TAG_ARGUMENT",
|
|
3153
|
+
'Tag "@discriminator" only supports direct property targets in v1; nested paths are out of scope.',
|
|
3154
|
+
provenanceForNode(node, file)
|
|
3155
|
+
)
|
|
3156
|
+
);
|
|
3157
|
+
return null;
|
|
3158
|
+
}
|
|
3159
|
+
const typeParameterName = firstTag.argumentText.trim();
|
|
3160
|
+
if (!/^[A-Za-z_$][\w$]*$/u.test(typeParameterName)) {
|
|
3161
|
+
diagnostics.push(
|
|
3162
|
+
makeAnalysisDiagnostic(
|
|
3163
|
+
"INVALID_TAG_ARGUMENT",
|
|
3164
|
+
'Tag "@discriminator" requires a local type parameter name as its source operand.',
|
|
3165
|
+
provenanceForNode(node, file)
|
|
3166
|
+
)
|
|
3167
|
+
);
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
return {
|
|
3171
|
+
fieldName: firstTarget.path.segments[0] ?? firstTarget.rawText,
|
|
3172
|
+
typeParameterName,
|
|
3173
|
+
provenance: provenanceForNode(node, file)
|
|
3174
|
+
};
|
|
3175
|
+
}
|
|
3176
|
+
function validateDiscriminatorDirective(node, checker, file, diagnostics) {
|
|
3177
|
+
const directive = extractDiscriminatorDirective(node, file, diagnostics);
|
|
3178
|
+
if (directive === null) {
|
|
3179
|
+
return null;
|
|
3180
|
+
}
|
|
3181
|
+
if (!isLocalTypeParameterName(node, directive.typeParameterName)) {
|
|
3182
|
+
diagnostics.push(
|
|
3183
|
+
makeAnalysisDiagnostic(
|
|
3184
|
+
"INVALID_TAG_ARGUMENT",
|
|
3185
|
+
`Tag "@discriminator" references "${directive.typeParameterName}", but the source operand must be a type parameter declared on the same declaration.`,
|
|
3186
|
+
directive.provenance
|
|
3187
|
+
)
|
|
3188
|
+
);
|
|
3189
|
+
return null;
|
|
3190
|
+
}
|
|
3191
|
+
const property = resolveDiscriminatorProperty(node, checker, directive.fieldName);
|
|
3192
|
+
if (property === null) {
|
|
3193
|
+
diagnostics.push(
|
|
3194
|
+
makeAnalysisDiagnostic(
|
|
3195
|
+
"UNKNOWN_PATH_TARGET",
|
|
3196
|
+
`Tag "@discriminator" targets "${directive.fieldName}", but no direct property with that name exists on this declaration.`,
|
|
3197
|
+
directive.provenance
|
|
3198
|
+
)
|
|
3199
|
+
);
|
|
3200
|
+
return null;
|
|
3201
|
+
}
|
|
3202
|
+
if (property.optional) {
|
|
3203
|
+
diagnostics.push(
|
|
3204
|
+
makeAnalysisDiagnostic(
|
|
3205
|
+
"TYPE_MISMATCH",
|
|
3206
|
+
`Discriminator field "${directive.fieldName}" must be required; optional discriminator fields are not supported.`,
|
|
3207
|
+
directive.provenance,
|
|
3208
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3209
|
+
)
|
|
3210
|
+
);
|
|
3211
|
+
return null;
|
|
3212
|
+
}
|
|
3213
|
+
if (isNullishSemanticType(property.type)) {
|
|
3214
|
+
diagnostics.push(
|
|
3215
|
+
makeAnalysisDiagnostic(
|
|
3216
|
+
"TYPE_MISMATCH",
|
|
3217
|
+
`Discriminator field "${directive.fieldName}" must not be nullable.`,
|
|
3218
|
+
directive.provenance,
|
|
3219
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3220
|
+
)
|
|
3221
|
+
);
|
|
3222
|
+
return null;
|
|
3223
|
+
}
|
|
3224
|
+
if (!isStringLikeSemanticType(property.type)) {
|
|
3225
|
+
diagnostics.push(
|
|
3226
|
+
makeAnalysisDiagnostic(
|
|
3227
|
+
"TYPE_MISMATCH",
|
|
3228
|
+
`Discriminator field "${directive.fieldName}" must be string-like.`,
|
|
3229
|
+
directive.provenance,
|
|
3230
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3231
|
+
)
|
|
3232
|
+
);
|
|
3233
|
+
return null;
|
|
3234
|
+
}
|
|
3235
|
+
return directive;
|
|
3236
|
+
}
|
|
3237
|
+
function getConcreteTypeArgumentForDiscriminator(node, subjectType, checker, typeParameterName) {
|
|
3238
|
+
const typeParameterIndex = node.typeParameters?.findIndex(
|
|
3239
|
+
(typeParameter) => typeParameter.name.text === typeParameterName
|
|
3240
|
+
) ?? -1;
|
|
3241
|
+
if (typeParameterIndex < 0) {
|
|
3242
|
+
return null;
|
|
3243
|
+
}
|
|
3244
|
+
const referenceTypeArguments = (isTypeReference(subjectType) ? subjectType.typeArguments : void 0) ?? subjectType.aliasTypeArguments;
|
|
3245
|
+
if (referenceTypeArguments?.[typeParameterIndex] !== void 0) {
|
|
3246
|
+
return referenceTypeArguments[typeParameterIndex] ?? null;
|
|
3247
|
+
}
|
|
3248
|
+
const localTypeParameter = node.typeParameters?.[typeParameterIndex];
|
|
3249
|
+
return localTypeParameter === void 0 ? null : checker.getTypeAtLocation(localTypeParameter);
|
|
3250
|
+
}
|
|
3251
|
+
function resolveLiteralDiscriminatorPropertyValue(boundType, fieldName, checker, provenance, diagnostics) {
|
|
3252
|
+
const propertySymbol = boundType.getProperty(fieldName);
|
|
3253
|
+
if (propertySymbol === void 0) {
|
|
3254
|
+
return void 0;
|
|
3255
|
+
}
|
|
3256
|
+
const declaration = propertySymbol.valueDeclaration ?? propertySymbol.declarations?.[0];
|
|
3257
|
+
const anchorNode = declaration ?? boundType.symbol.declarations?.[0] ?? null;
|
|
3258
|
+
const resolvedAnchorNode = anchorNode ?? resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
3259
|
+
if (resolvedAnchorNode === null) {
|
|
3260
|
+
return void 0;
|
|
3261
|
+
}
|
|
3262
|
+
const propertyType = checker.getTypeOfSymbolAtLocation(
|
|
3263
|
+
propertySymbol,
|
|
3264
|
+
resolvedAnchorNode
|
|
3265
|
+
);
|
|
3266
|
+
if (propertyType.isStringLiteral()) {
|
|
3267
|
+
return propertyType.value;
|
|
3268
|
+
}
|
|
3269
|
+
if (propertyType.isUnion()) {
|
|
3270
|
+
const nonNullMembers = propertyType.types.filter(
|
|
3271
|
+
(member) => !(member.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
|
|
3272
|
+
);
|
|
3273
|
+
if (nonNullMembers.length > 0 && nonNullMembers.every((member) => member.isStringLiteral())) {
|
|
3274
|
+
diagnostics.push(
|
|
3275
|
+
makeAnalysisDiagnostic(
|
|
3276
|
+
"INVALID_TAG_ARGUMENT",
|
|
3277
|
+
"Discriminator resolution for union-valued identity properties is out of scope for v1.",
|
|
3278
|
+
provenance
|
|
3279
|
+
)
|
|
3280
|
+
);
|
|
3281
|
+
return null;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
return void 0;
|
|
3285
|
+
}
|
|
3286
|
+
function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
|
|
3287
|
+
const declaration = resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
3288
|
+
if (declaration === null) {
|
|
3289
|
+
return void 0;
|
|
3290
|
+
}
|
|
3291
|
+
const metadata = resolveNodeMetadata(
|
|
3292
|
+
metadataPolicy,
|
|
3293
|
+
"type",
|
|
3294
|
+
getDiscriminatorLogicalName(boundType, declaration, checker),
|
|
3295
|
+
declaration,
|
|
3296
|
+
{
|
|
3297
|
+
checker,
|
|
3298
|
+
declaration,
|
|
3299
|
+
subjectType: boundType
|
|
3300
|
+
}
|
|
3301
|
+
);
|
|
3302
|
+
return metadata?.apiName;
|
|
3303
|
+
}
|
|
3304
|
+
function resolveNamedDiscriminatorDeclaration(type, checker, seen = /* @__PURE__ */ new Set()) {
|
|
3305
|
+
if (seen.has(type)) {
|
|
3306
|
+
return null;
|
|
3307
|
+
}
|
|
3308
|
+
seen.add(type);
|
|
3309
|
+
const symbol = type.aliasSymbol ?? type.getSymbol();
|
|
3310
|
+
if (symbol !== void 0) {
|
|
3311
|
+
const aliased = symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : void 0;
|
|
3312
|
+
const targetSymbol = aliased ?? symbol;
|
|
3313
|
+
const declaration = targetSymbol.declarations?.find(
|
|
3314
|
+
(candidate) => ts3.isClassDeclaration(candidate) || ts3.isInterfaceDeclaration(candidate) || ts3.isTypeAliasDeclaration(candidate) || ts3.isEnumDeclaration(candidate)
|
|
3315
|
+
);
|
|
3316
|
+
if (declaration !== void 0) {
|
|
3317
|
+
if (ts3.isTypeAliasDeclaration(declaration) && ts3.isTypeReferenceNode(declaration.type) && checker.getTypeFromTypeNode(declaration.type) !== type) {
|
|
3318
|
+
return resolveNamedDiscriminatorDeclaration(
|
|
3319
|
+
checker.getTypeFromTypeNode(declaration.type),
|
|
3320
|
+
checker,
|
|
3321
|
+
seen
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
return declaration;
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
return null;
|
|
3328
|
+
}
|
|
3329
|
+
function resolveDiscriminatorValue(boundType, fieldName, checker, provenance, diagnostics, metadataPolicy) {
|
|
3330
|
+
if (boundType === null) {
|
|
3331
|
+
diagnostics.push(
|
|
3332
|
+
makeAnalysisDiagnostic(
|
|
3333
|
+
"INVALID_TAG_ARGUMENT",
|
|
3334
|
+
"Discriminator resolution failed because no concrete type argument is available for the referenced type parameter.",
|
|
3335
|
+
provenance
|
|
3336
|
+
)
|
|
3337
|
+
);
|
|
3338
|
+
return null;
|
|
3339
|
+
}
|
|
3340
|
+
if (boundType.isStringLiteral()) {
|
|
3341
|
+
return boundType.value;
|
|
3342
|
+
}
|
|
3343
|
+
if (boundType.isUnion()) {
|
|
3344
|
+
const nonNullMembers = boundType.types.filter(
|
|
3345
|
+
(member) => !(member.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
|
|
3346
|
+
);
|
|
3347
|
+
if (nonNullMembers.every((member) => member.isStringLiteral())) {
|
|
3348
|
+
diagnostics.push(
|
|
3349
|
+
makeAnalysisDiagnostic(
|
|
3350
|
+
"INVALID_TAG_ARGUMENT",
|
|
3351
|
+
"Discriminator resolution for unions of string literals is out of scope for v1.",
|
|
3352
|
+
provenance
|
|
3353
|
+
)
|
|
3354
|
+
);
|
|
3355
|
+
return null;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
const literalIdentityValue = resolveLiteralDiscriminatorPropertyValue(
|
|
3359
|
+
boundType,
|
|
3360
|
+
fieldName,
|
|
3361
|
+
checker,
|
|
3362
|
+
provenance,
|
|
3363
|
+
diagnostics
|
|
3364
|
+
);
|
|
3365
|
+
if (literalIdentityValue !== void 0) {
|
|
3366
|
+
return literalIdentityValue;
|
|
3367
|
+
}
|
|
3368
|
+
const apiName = resolveDiscriminatorApiName(boundType, checker, metadataPolicy);
|
|
3369
|
+
if (apiName?.source === "explicit") {
|
|
3370
|
+
return apiName.value;
|
|
3371
|
+
}
|
|
3372
|
+
if (apiName?.source === "inferred") {
|
|
3373
|
+
return apiName.value;
|
|
3374
|
+
}
|
|
3375
|
+
diagnostics.push(
|
|
3376
|
+
makeAnalysisDiagnostic(
|
|
3377
|
+
"INVALID_TAG_ARGUMENT",
|
|
3378
|
+
"Discriminator resolution could not derive a JSON-facing discriminator value from the referenced type argument.",
|
|
3379
|
+
provenance
|
|
3380
|
+
)
|
|
3381
|
+
);
|
|
3382
|
+
return null;
|
|
3383
|
+
}
|
|
3384
|
+
function getDeclarationName(node) {
|
|
3385
|
+
if (ts3.isClassDeclaration(node) || ts3.isInterfaceDeclaration(node) || ts3.isTypeAliasDeclaration(node) || ts3.isEnumDeclaration(node)) {
|
|
3386
|
+
return node.name?.text ?? "anonymous";
|
|
3387
|
+
}
|
|
3388
|
+
return "anonymous";
|
|
3389
|
+
}
|
|
3390
|
+
function getResolvedTypeArguments(type) {
|
|
3391
|
+
return (isTypeReference(type) ? type.typeArguments : void 0) ?? type.aliasTypeArguments ?? [];
|
|
3392
|
+
}
|
|
3393
|
+
function getDiscriminatorLogicalName(type, declaration, checker) {
|
|
3394
|
+
const baseName = getDeclarationName(declaration);
|
|
3395
|
+
const typeArguments = getResolvedTypeArguments(type);
|
|
3396
|
+
return typeArguments.length === 0 ? baseName : buildInstantiatedReferenceName(baseName, typeArguments, checker);
|
|
3397
|
+
}
|
|
3398
|
+
function applyDeclarationDiscriminatorToFields(fields, node, subjectType, checker, file, diagnostics, metadataPolicy) {
|
|
3399
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
3400
|
+
if (directive === null) {
|
|
3401
|
+
return [...fields];
|
|
3402
|
+
}
|
|
3403
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
3404
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
3405
|
+
node,
|
|
3406
|
+
subjectType,
|
|
3407
|
+
checker,
|
|
3408
|
+
directive.typeParameterName
|
|
3409
|
+
),
|
|
3410
|
+
directive.fieldName,
|
|
3411
|
+
checker,
|
|
3412
|
+
directive.provenance,
|
|
3413
|
+
diagnostics,
|
|
3414
|
+
metadataPolicy
|
|
3415
|
+
);
|
|
3416
|
+
if (discriminatorValue === null) {
|
|
3417
|
+
return [...fields];
|
|
3418
|
+
}
|
|
3419
|
+
return fields.map(
|
|
3420
|
+
(field) => field.name === directive.fieldName ? {
|
|
3421
|
+
...field,
|
|
3422
|
+
type: {
|
|
3423
|
+
kind: "enum",
|
|
3424
|
+
members: [{ value: discriminatorValue }]
|
|
3425
|
+
}
|
|
3426
|
+
} : field
|
|
3427
|
+
);
|
|
3428
|
+
}
|
|
3429
|
+
function buildInstantiatedReferenceName(baseName, typeArguments, checker) {
|
|
3430
|
+
const renderedArguments = typeArguments.map(
|
|
3431
|
+
(typeArgument) => checker.typeToString(typeArgument).replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "")
|
|
3432
|
+
).filter((value) => value !== "");
|
|
3433
|
+
return renderedArguments.length === 0 ? baseName : `${baseName}__${renderedArguments.join("__")}`;
|
|
3434
|
+
}
|
|
3435
|
+
function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy, extensionRegistry, diagnostics) {
|
|
3436
|
+
const typeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
3437
|
+
if (typeNode === void 0) {
|
|
3438
|
+
return [];
|
|
3439
|
+
}
|
|
3440
|
+
const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
|
|
3441
|
+
if (!ts3.isTypeReferenceNode(resolvedTypeNode) || resolvedTypeNode.typeArguments === void 0) {
|
|
3442
|
+
return [];
|
|
3443
|
+
}
|
|
3444
|
+
return resolvedTypeNode.typeArguments.map((argumentNode) => {
|
|
3445
|
+
const argumentType = checker.getTypeFromTypeNode(argumentNode);
|
|
3446
|
+
return {
|
|
3447
|
+
tsType: argumentType,
|
|
3448
|
+
typeNode: resolveTypeNode(
|
|
3449
|
+
argumentType,
|
|
3450
|
+
checker,
|
|
3451
|
+
file,
|
|
3452
|
+
typeRegistry,
|
|
3453
|
+
visiting,
|
|
3454
|
+
argumentNode,
|
|
3455
|
+
metadataPolicy,
|
|
3456
|
+
extensionRegistry,
|
|
3457
|
+
diagnostics
|
|
3458
|
+
)
|
|
3459
|
+
};
|
|
3460
|
+
});
|
|
3461
|
+
}
|
|
3462
|
+
function applyDiscriminatorToObjectProperties(properties, node, subjectType, checker, file, diagnostics, metadataPolicy) {
|
|
3463
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
3464
|
+
if (directive === null) {
|
|
3465
|
+
return properties;
|
|
3466
|
+
}
|
|
3467
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
3468
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
3469
|
+
node,
|
|
3470
|
+
subjectType,
|
|
3471
|
+
checker,
|
|
3472
|
+
directive.typeParameterName
|
|
3473
|
+
),
|
|
3474
|
+
directive.fieldName,
|
|
3475
|
+
checker,
|
|
3476
|
+
directive.provenance,
|
|
3477
|
+
diagnostics,
|
|
3478
|
+
metadataPolicy
|
|
3479
|
+
);
|
|
3480
|
+
if (discriminatorValue === null) {
|
|
3481
|
+
return properties;
|
|
3482
|
+
}
|
|
3483
|
+
return properties.map(
|
|
3484
|
+
(property) => property.name === directive.fieldName ? {
|
|
3485
|
+
...property,
|
|
3486
|
+
type: {
|
|
3487
|
+
kind: "enum",
|
|
3488
|
+
members: [{ value: discriminatorValue }]
|
|
3489
|
+
}
|
|
3490
|
+
} : property
|
|
3491
|
+
);
|
|
3492
|
+
}
|
|
3493
|
+
function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, metadataPolicy, extensionRegistry) {
|
|
2342
3494
|
if (!ts3.isIdentifier(prop.name)) {
|
|
2343
3495
|
return null;
|
|
2344
3496
|
}
|
|
@@ -2353,6 +3505,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2353
3505
|
typeRegistry,
|
|
2354
3506
|
visiting,
|
|
2355
3507
|
prop,
|
|
3508
|
+
metadataPolicy,
|
|
2356
3509
|
extensionRegistry,
|
|
2357
3510
|
diagnostics
|
|
2358
3511
|
);
|
|
@@ -2376,9 +3529,16 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2376
3529
|
annotations.push(defaultAnnotation);
|
|
2377
3530
|
}
|
|
2378
3531
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
3532
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
|
|
3533
|
+
checker,
|
|
3534
|
+
declaration: prop,
|
|
3535
|
+
subjectType: tsType,
|
|
3536
|
+
hostType
|
|
3537
|
+
});
|
|
2379
3538
|
return {
|
|
2380
3539
|
kind: "field",
|
|
2381
3540
|
name,
|
|
3541
|
+
...metadata !== void 0 && { metadata },
|
|
2382
3542
|
type,
|
|
2383
3543
|
required: !optional,
|
|
2384
3544
|
constraints,
|
|
@@ -2386,7 +3546,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2386
3546
|
provenance
|
|
2387
3547
|
};
|
|
2388
3548
|
}
|
|
2389
|
-
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, extensionRegistry) {
|
|
3549
|
+
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, metadataPolicy, extensionRegistry) {
|
|
2390
3550
|
if (!ts3.isIdentifier(prop.name)) {
|
|
2391
3551
|
return null;
|
|
2392
3552
|
}
|
|
@@ -2401,6 +3561,7 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2401
3561
|
typeRegistry,
|
|
2402
3562
|
visiting,
|
|
2403
3563
|
prop,
|
|
3564
|
+
metadataPolicy,
|
|
2404
3565
|
extensionRegistry,
|
|
2405
3566
|
diagnostics
|
|
2406
3567
|
);
|
|
@@ -2420,9 +3581,16 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2420
3581
|
let annotations = [];
|
|
2421
3582
|
annotations.push(...docResult.annotations);
|
|
2422
3583
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
3584
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
|
|
3585
|
+
checker,
|
|
3586
|
+
declaration: prop,
|
|
3587
|
+
subjectType: tsType,
|
|
3588
|
+
hostType
|
|
3589
|
+
});
|
|
2423
3590
|
return {
|
|
2424
3591
|
kind: "field",
|
|
2425
3592
|
name,
|
|
3593
|
+
...metadata !== void 0 && { metadata },
|
|
2426
3594
|
type,
|
|
2427
3595
|
required: !optional,
|
|
2428
3596
|
constraints,
|
|
@@ -2547,7 +3715,7 @@ function getTypeNodeRegistrationName(typeNode) {
|
|
|
2547
3715
|
}
|
|
2548
3716
|
return null;
|
|
2549
3717
|
}
|
|
2550
|
-
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3718
|
+
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2551
3719
|
const customType = resolveRegisteredCustomType(sourceNode, extensionRegistry, checker);
|
|
2552
3720
|
if (customType) {
|
|
2553
3721
|
return customType;
|
|
@@ -2559,6 +3727,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2559
3727
|
typeRegistry,
|
|
2560
3728
|
visiting,
|
|
2561
3729
|
sourceNode,
|
|
3730
|
+
metadataPolicy,
|
|
2562
3731
|
extensionRegistry,
|
|
2563
3732
|
diagnostics
|
|
2564
3733
|
);
|
|
@@ -2603,6 +3772,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2603
3772
|
typeRegistry,
|
|
2604
3773
|
visiting,
|
|
2605
3774
|
sourceNode,
|
|
3775
|
+
metadataPolicy,
|
|
2606
3776
|
extensionRegistry,
|
|
2607
3777
|
diagnostics
|
|
2608
3778
|
);
|
|
@@ -2615,6 +3785,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2615
3785
|
typeRegistry,
|
|
2616
3786
|
visiting,
|
|
2617
3787
|
sourceNode,
|
|
3788
|
+
metadataPolicy,
|
|
2618
3789
|
extensionRegistry,
|
|
2619
3790
|
diagnostics
|
|
2620
3791
|
);
|
|
@@ -2626,13 +3797,15 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2626
3797
|
file,
|
|
2627
3798
|
typeRegistry,
|
|
2628
3799
|
visiting,
|
|
3800
|
+
sourceNode,
|
|
3801
|
+
metadataPolicy,
|
|
2629
3802
|
extensionRegistry,
|
|
2630
3803
|
diagnostics
|
|
2631
3804
|
);
|
|
2632
3805
|
}
|
|
2633
3806
|
return { kind: "primitive", primitiveKind: "string" };
|
|
2634
3807
|
}
|
|
2635
|
-
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3808
|
+
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2636
3809
|
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
|
|
2637
3810
|
return null;
|
|
2638
3811
|
}
|
|
@@ -2652,14 +3825,21 @@ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiti
|
|
|
2652
3825
|
file,
|
|
2653
3826
|
makeParseOptions(extensionRegistry)
|
|
2654
3827
|
);
|
|
3828
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "type", aliasName, aliasDecl, {
|
|
3829
|
+
checker,
|
|
3830
|
+
declaration: aliasDecl,
|
|
3831
|
+
subjectType: aliasType
|
|
3832
|
+
});
|
|
2655
3833
|
typeRegistry[aliasName] = {
|
|
2656
3834
|
name: aliasName,
|
|
3835
|
+
...metadata !== void 0 && { metadata },
|
|
2657
3836
|
type: resolveAliasedPrimitiveTarget(
|
|
2658
3837
|
aliasType,
|
|
2659
3838
|
checker,
|
|
2660
3839
|
file,
|
|
2661
3840
|
typeRegistry,
|
|
2662
3841
|
visiting,
|
|
3842
|
+
metadataPolicy,
|
|
2663
3843
|
extensionRegistry,
|
|
2664
3844
|
diagnostics
|
|
2665
3845
|
),
|
|
@@ -2688,7 +3868,7 @@ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
|
2688
3868
|
const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
|
|
2689
3869
|
return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
|
|
2690
3870
|
}
|
|
2691
|
-
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, extensionRegistry, diagnostics) {
|
|
3871
|
+
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2692
3872
|
const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
2693
3873
|
if (nestedAliasDecl !== void 0) {
|
|
2694
3874
|
return resolveAliasedPrimitiveTarget(
|
|
@@ -2697,6 +3877,7 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
2697
3877
|
file,
|
|
2698
3878
|
typeRegistry,
|
|
2699
3879
|
visiting,
|
|
3880
|
+
metadataPolicy,
|
|
2700
3881
|
extensionRegistry,
|
|
2701
3882
|
diagnostics
|
|
2702
3883
|
);
|
|
@@ -2708,11 +3889,12 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
2708
3889
|
typeRegistry,
|
|
2709
3890
|
visiting,
|
|
2710
3891
|
void 0,
|
|
3892
|
+
metadataPolicy,
|
|
2711
3893
|
extensionRegistry,
|
|
2712
3894
|
diagnostics
|
|
2713
3895
|
);
|
|
2714
3896
|
}
|
|
2715
|
-
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3897
|
+
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2716
3898
|
const typeName = getNamedTypeName(type);
|
|
2717
3899
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2718
3900
|
if (typeName && typeName in typeRegistry) {
|
|
@@ -2747,8 +3929,14 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2747
3929
|
return result;
|
|
2748
3930
|
}
|
|
2749
3931
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
3932
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", typeName, namedDecl, {
|
|
3933
|
+
checker,
|
|
3934
|
+
declaration: namedDecl,
|
|
3935
|
+
subjectType: type
|
|
3936
|
+
}) : void 0;
|
|
2750
3937
|
typeRegistry[typeName] = {
|
|
2751
3938
|
name: typeName,
|
|
3939
|
+
...metadata !== void 0 && { metadata },
|
|
2752
3940
|
type: result,
|
|
2753
3941
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2754
3942
|
provenance: provenanceForDeclaration(namedDecl ?? sourceNode, file)
|
|
@@ -2802,6 +3990,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2802
3990
|
typeRegistry,
|
|
2803
3991
|
visiting,
|
|
2804
3992
|
nonNullMembers[0].sourceNode ?? sourceNode,
|
|
3993
|
+
metadataPolicy,
|
|
2805
3994
|
extensionRegistry,
|
|
2806
3995
|
diagnostics
|
|
2807
3996
|
);
|
|
@@ -2819,6 +4008,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2819
4008
|
typeRegistry,
|
|
2820
4009
|
visiting,
|
|
2821
4010
|
memberSourceNode ?? sourceNode,
|
|
4011
|
+
metadataPolicy,
|
|
2822
4012
|
extensionRegistry,
|
|
2823
4013
|
diagnostics
|
|
2824
4014
|
)
|
|
@@ -2828,7 +4018,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2828
4018
|
}
|
|
2829
4019
|
return registerNamed({ kind: "union", members });
|
|
2830
4020
|
}
|
|
2831
|
-
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
4021
|
+
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2832
4022
|
const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
|
|
2833
4023
|
const elementType = typeArgs?.[0];
|
|
2834
4024
|
const elementSourceNode = extractArrayElementTypeNode(sourceNode, checker);
|
|
@@ -2839,12 +4029,13 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2839
4029
|
typeRegistry,
|
|
2840
4030
|
visiting,
|
|
2841
4031
|
elementSourceNode,
|
|
4032
|
+
metadataPolicy,
|
|
2842
4033
|
extensionRegistry,
|
|
2843
4034
|
diagnostics
|
|
2844
4035
|
) : { kind: "primitive", primitiveKind: "string" };
|
|
2845
4036
|
return { kind: "array", items };
|
|
2846
4037
|
}
|
|
2847
|
-
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, extensionRegistry, diagnostics) {
|
|
4038
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2848
4039
|
if (type.getProperties().length > 0) {
|
|
2849
4040
|
return null;
|
|
2850
4041
|
}
|
|
@@ -2859,6 +4050,7 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, exten
|
|
|
2859
4050
|
typeRegistry,
|
|
2860
4051
|
visiting,
|
|
2861
4052
|
void 0,
|
|
4053
|
+
metadataPolicy,
|
|
2862
4054
|
extensionRegistry,
|
|
2863
4055
|
diagnostics
|
|
2864
4056
|
);
|
|
@@ -2889,35 +4081,76 @@ function typeNodeContainsReference(type, targetName) {
|
|
|
2889
4081
|
}
|
|
2890
4082
|
}
|
|
2891
4083
|
}
|
|
2892
|
-
function
|
|
4084
|
+
function shouldEmitResolvedObjectProperty(property, declaration) {
|
|
4085
|
+
if (property.name.startsWith("__@")) {
|
|
4086
|
+
return false;
|
|
4087
|
+
}
|
|
4088
|
+
if (declaration !== void 0 && "name" in declaration && declaration.name !== void 0) {
|
|
4089
|
+
const name = declaration.name;
|
|
4090
|
+
if (ts3.isComputedPropertyName(name) || ts3.isPrivateIdentifier(name)) {
|
|
4091
|
+
return false;
|
|
4092
|
+
}
|
|
4093
|
+
if (!ts3.isIdentifier(name) && !ts3.isStringLiteral(name) && !ts3.isNumericLiteral(name)) {
|
|
4094
|
+
return false;
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
return true;
|
|
4098
|
+
}
|
|
4099
|
+
function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
4100
|
+
const collectedDiagnostics = diagnostics ?? [];
|
|
2893
4101
|
const typeName = getNamedTypeName(type);
|
|
2894
4102
|
const namedTypeName = typeName ?? void 0;
|
|
2895
4103
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2896
|
-
const
|
|
4104
|
+
const referenceTypeArguments = extractReferenceTypeArguments(
|
|
4105
|
+
type,
|
|
4106
|
+
checker,
|
|
4107
|
+
file,
|
|
4108
|
+
typeRegistry,
|
|
4109
|
+
visiting,
|
|
4110
|
+
sourceNode,
|
|
4111
|
+
metadataPolicy,
|
|
4112
|
+
extensionRegistry,
|
|
4113
|
+
collectedDiagnostics
|
|
4114
|
+
);
|
|
4115
|
+
const instantiatedTypeName = namedTypeName !== void 0 && referenceTypeArguments.length > 0 ? buildInstantiatedReferenceName(
|
|
4116
|
+
namedTypeName,
|
|
4117
|
+
referenceTypeArguments.map((argument) => argument.tsType),
|
|
4118
|
+
checker
|
|
4119
|
+
) : void 0;
|
|
4120
|
+
const registryTypeName = instantiatedTypeName ?? namedTypeName;
|
|
4121
|
+
const shouldRegisterNamedType = registryTypeName !== void 0 && !(registryTypeName === "Record" && namedDecl?.getSourceFile().fileName !== file);
|
|
2897
4122
|
const clearNamedTypeRegistration = () => {
|
|
2898
|
-
if (
|
|
4123
|
+
if (registryTypeName === void 0 || !shouldRegisterNamedType) {
|
|
2899
4124
|
return;
|
|
2900
4125
|
}
|
|
2901
|
-
Reflect.deleteProperty(typeRegistry,
|
|
4126
|
+
Reflect.deleteProperty(typeRegistry, registryTypeName);
|
|
2902
4127
|
};
|
|
2903
4128
|
if (visiting.has(type)) {
|
|
2904
|
-
if (
|
|
2905
|
-
return {
|
|
4129
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
4130
|
+
return {
|
|
4131
|
+
kind: "reference",
|
|
4132
|
+
name: registryTypeName,
|
|
4133
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4134
|
+
};
|
|
2906
4135
|
}
|
|
2907
4136
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
2908
4137
|
}
|
|
2909
|
-
if (
|
|
2910
|
-
typeRegistry[
|
|
2911
|
-
name:
|
|
4138
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && !typeRegistry[registryTypeName]) {
|
|
4139
|
+
typeRegistry[registryTypeName] = {
|
|
4140
|
+
name: registryTypeName,
|
|
2912
4141
|
type: RESOLVING_TYPE_PLACEHOLDER,
|
|
2913
4142
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2914
4143
|
};
|
|
2915
4144
|
}
|
|
2916
4145
|
visiting.add(type);
|
|
2917
|
-
if (
|
|
2918
|
-
if (typeRegistry[
|
|
4146
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && typeRegistry[registryTypeName]?.type !== void 0) {
|
|
4147
|
+
if (typeRegistry[registryTypeName].type !== RESOLVING_TYPE_PLACEHOLDER) {
|
|
2919
4148
|
visiting.delete(type);
|
|
2920
|
-
return {
|
|
4149
|
+
return {
|
|
4150
|
+
kind: "reference",
|
|
4151
|
+
name: registryTypeName,
|
|
4152
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4153
|
+
};
|
|
2921
4154
|
}
|
|
2922
4155
|
}
|
|
2923
4156
|
const recordNode = tryResolveRecordType(
|
|
@@ -2926,25 +4159,36 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2926
4159
|
file,
|
|
2927
4160
|
typeRegistry,
|
|
2928
4161
|
visiting,
|
|
4162
|
+
metadataPolicy,
|
|
2929
4163
|
extensionRegistry,
|
|
2930
|
-
|
|
4164
|
+
collectedDiagnostics
|
|
2931
4165
|
);
|
|
2932
4166
|
if (recordNode) {
|
|
2933
4167
|
visiting.delete(type);
|
|
2934
|
-
if (
|
|
2935
|
-
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType,
|
|
4168
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
4169
|
+
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType, registryTypeName);
|
|
2936
4170
|
if (!isRecursiveRecord) {
|
|
2937
4171
|
clearNamedTypeRegistration();
|
|
2938
4172
|
return recordNode;
|
|
2939
4173
|
}
|
|
2940
4174
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2941
|
-
|
|
2942
|
-
|
|
4175
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
|
|
4176
|
+
checker,
|
|
4177
|
+
declaration: namedDecl,
|
|
4178
|
+
subjectType: type
|
|
4179
|
+
}) : void 0;
|
|
4180
|
+
typeRegistry[registryTypeName] = {
|
|
4181
|
+
name: registryTypeName,
|
|
4182
|
+
...metadata !== void 0 && { metadata },
|
|
2943
4183
|
type: recordNode,
|
|
2944
4184
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2945
4185
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2946
4186
|
};
|
|
2947
|
-
return {
|
|
4187
|
+
return {
|
|
4188
|
+
kind: "reference",
|
|
4189
|
+
name: registryTypeName,
|
|
4190
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4191
|
+
};
|
|
2948
4192
|
}
|
|
2949
4193
|
return recordNode;
|
|
2950
4194
|
}
|
|
@@ -2955,12 +4199,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2955
4199
|
file,
|
|
2956
4200
|
typeRegistry,
|
|
2957
4201
|
visiting,
|
|
2958
|
-
|
|
4202
|
+
metadataPolicy,
|
|
4203
|
+
collectedDiagnostics,
|
|
2959
4204
|
extensionRegistry
|
|
2960
4205
|
);
|
|
2961
4206
|
for (const prop of type.getProperties()) {
|
|
2962
4207
|
const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
2963
4208
|
if (!declaration) continue;
|
|
4209
|
+
if (!shouldEmitResolvedObjectProperty(prop, declaration)) continue;
|
|
2964
4210
|
const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
|
|
2965
4211
|
const optional = !!(prop.flags & ts3.SymbolFlags.Optional);
|
|
2966
4212
|
const propTypeNode = resolveTypeNode(
|
|
@@ -2970,12 +4216,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2970
4216
|
typeRegistry,
|
|
2971
4217
|
visiting,
|
|
2972
4218
|
declaration,
|
|
4219
|
+
metadataPolicy,
|
|
2973
4220
|
extensionRegistry,
|
|
2974
|
-
|
|
4221
|
+
collectedDiagnostics
|
|
2975
4222
|
);
|
|
2976
4223
|
const fieldNodeInfo = fieldInfoMap?.get(prop.name);
|
|
2977
4224
|
properties.push({
|
|
2978
4225
|
name: prop.name,
|
|
4226
|
+
...fieldNodeInfo?.metadata !== void 0 && { metadata: fieldNodeInfo.metadata },
|
|
2979
4227
|
type: propTypeNode,
|
|
2980
4228
|
optional,
|
|
2981
4229
|
constraints: fieldNodeInfo?.constraints ?? [],
|
|
@@ -2986,22 +4234,40 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2986
4234
|
visiting.delete(type);
|
|
2987
4235
|
const objectNode = {
|
|
2988
4236
|
kind: "object",
|
|
2989
|
-
properties
|
|
4237
|
+
properties: namedDecl !== void 0 && (ts3.isClassDeclaration(namedDecl) || ts3.isInterfaceDeclaration(namedDecl) || ts3.isTypeAliasDeclaration(namedDecl)) ? applyDiscriminatorToObjectProperties(
|
|
4238
|
+
properties,
|
|
4239
|
+
namedDecl,
|
|
4240
|
+
type,
|
|
4241
|
+
checker,
|
|
4242
|
+
file,
|
|
4243
|
+
collectedDiagnostics,
|
|
4244
|
+
metadataPolicy
|
|
4245
|
+
) : properties,
|
|
2990
4246
|
additionalProperties: true
|
|
2991
4247
|
};
|
|
2992
|
-
if (
|
|
4248
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
2993
4249
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2994
|
-
|
|
2995
|
-
|
|
4250
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
|
|
4251
|
+
checker,
|
|
4252
|
+
declaration: namedDecl,
|
|
4253
|
+
subjectType: type
|
|
4254
|
+
}) : void 0;
|
|
4255
|
+
typeRegistry[registryTypeName] = {
|
|
4256
|
+
name: registryTypeName,
|
|
4257
|
+
...metadata !== void 0 && { metadata },
|
|
2996
4258
|
type: objectNode,
|
|
2997
4259
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2998
4260
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2999
4261
|
};
|
|
3000
|
-
return {
|
|
4262
|
+
return {
|
|
4263
|
+
kind: "reference",
|
|
4264
|
+
name: registryTypeName,
|
|
4265
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4266
|
+
};
|
|
3001
4267
|
}
|
|
3002
4268
|
return objectNode;
|
|
3003
4269
|
}
|
|
3004
|
-
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting, diagnostics, extensionRegistry) {
|
|
4270
|
+
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting, metadataPolicy, diagnostics, extensionRegistry) {
|
|
3005
4271
|
const symbols = [type.getSymbol(), type.aliasSymbol].filter(
|
|
3006
4272
|
(s) => s?.declarations != null && s.declarations.length > 0
|
|
3007
4273
|
);
|
|
@@ -3022,10 +4288,12 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3022
4288
|
visiting,
|
|
3023
4289
|
diagnostics,
|
|
3024
4290
|
hostType,
|
|
4291
|
+
metadataPolicy,
|
|
3025
4292
|
extensionRegistry
|
|
3026
4293
|
);
|
|
3027
4294
|
if (fieldNode) {
|
|
3028
4295
|
map.set(fieldNode.name, {
|
|
4296
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
3029
4297
|
constraints: [...fieldNode.constraints],
|
|
3030
4298
|
annotations: [...fieldNode.annotations],
|
|
3031
4299
|
provenance: fieldNode.provenance
|
|
@@ -3043,6 +4311,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3043
4311
|
file,
|
|
3044
4312
|
typeRegistry,
|
|
3045
4313
|
visiting,
|
|
4314
|
+
metadataPolicy,
|
|
3046
4315
|
checker.getTypeAtLocation(interfaceDecl),
|
|
3047
4316
|
diagnostics,
|
|
3048
4317
|
extensionRegistry
|
|
@@ -3056,6 +4325,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3056
4325
|
file,
|
|
3057
4326
|
typeRegistry,
|
|
3058
4327
|
visiting,
|
|
4328
|
+
metadataPolicy,
|
|
3059
4329
|
checker.getTypeAtLocation(typeAliasDecl),
|
|
3060
4330
|
diagnostics,
|
|
3061
4331
|
extensionRegistry
|
|
@@ -3107,7 +4377,7 @@ function isNullishTypeNode(typeNode) {
|
|
|
3107
4377
|
}
|
|
3108
4378
|
return ts3.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts3.SyntaxKind.NullKeyword || typeNode.literal.kind === ts3.SyntaxKind.UndefinedKeyword);
|
|
3109
4379
|
}
|
|
3110
|
-
function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, hostType, diagnostics, extensionRegistry) {
|
|
4380
|
+
function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, metadataPolicy, hostType, diagnostics, extensionRegistry) {
|
|
3111
4381
|
const map = /* @__PURE__ */ new Map();
|
|
3112
4382
|
for (const member of members) {
|
|
3113
4383
|
if (ts3.isPropertySignature(member)) {
|
|
@@ -3119,10 +4389,12 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, h
|
|
|
3119
4389
|
visiting,
|
|
3120
4390
|
diagnostics,
|
|
3121
4391
|
hostType,
|
|
4392
|
+
metadataPolicy,
|
|
3122
4393
|
extensionRegistry
|
|
3123
4394
|
);
|
|
3124
4395
|
if (fieldNode) {
|
|
3125
4396
|
map.set(fieldNode.name, {
|
|
4397
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
3126
4398
|
constraints: [...fieldNode.constraints],
|
|
3127
4399
|
annotations: [...fieldNode.annotations],
|
|
3128
4400
|
provenance: fieldNode.provenance
|
|
@@ -3152,6 +4424,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
3152
4424
|
{},
|
|
3153
4425
|
/* @__PURE__ */ new Set(),
|
|
3154
4426
|
aliasDecl.type,
|
|
4427
|
+
void 0,
|
|
3155
4428
|
extensionRegistry
|
|
3156
4429
|
);
|
|
3157
4430
|
const constraints = extractJSDocConstraintNodes(
|
|
@@ -3255,13 +4528,15 @@ function detectFormSpecReference(typeNode) {
|
|
|
3255
4528
|
}
|
|
3256
4529
|
return null;
|
|
3257
4530
|
}
|
|
3258
|
-
var ts3, RESOLVING_TYPE_PLACEHOLDER, MAX_ALIAS_CHAIN_DEPTH;
|
|
4531
|
+
var ts3, import_internal2, RESOLVING_TYPE_PLACEHOLDER, MAX_ALIAS_CHAIN_DEPTH;
|
|
3259
4532
|
var init_class_analyzer = __esm({
|
|
3260
4533
|
"src/analyzer/class-analyzer.ts"() {
|
|
3261
4534
|
"use strict";
|
|
3262
4535
|
ts3 = __toESM(require("typescript"), 1);
|
|
4536
|
+
import_internal2 = require("@formspec/analysis/internal");
|
|
3263
4537
|
init_jsdoc_constraints();
|
|
3264
4538
|
init_tsdoc_parser();
|
|
4539
|
+
init_metadata();
|
|
3265
4540
|
RESOLVING_TYPE_PLACEHOLDER = {
|
|
3266
4541
|
kind: "object",
|
|
3267
4542
|
properties: [],
|
|
@@ -3352,19 +4627,37 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3352
4627
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3353
4628
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3354
4629
|
}
|
|
3355
|
-
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry) {
|
|
4630
|
+
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPolicy) {
|
|
3356
4631
|
const ctx = createProgramContext(filePath);
|
|
3357
|
-
return analyzeNamedTypeToIRFromProgramContext(
|
|
4632
|
+
return analyzeNamedTypeToIRFromProgramContext(
|
|
4633
|
+
ctx,
|
|
4634
|
+
filePath,
|
|
4635
|
+
typeName,
|
|
4636
|
+
extensionRegistry,
|
|
4637
|
+
metadataPolicy
|
|
4638
|
+
);
|
|
3358
4639
|
}
|
|
3359
|
-
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry) {
|
|
4640
|
+
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy) {
|
|
3360
4641
|
const analysisFilePath = path.resolve(filePath);
|
|
3361
4642
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
3362
4643
|
if (classDecl !== null) {
|
|
3363
|
-
return analyzeClassToIR(
|
|
4644
|
+
return analyzeClassToIR(
|
|
4645
|
+
classDecl,
|
|
4646
|
+
ctx.checker,
|
|
4647
|
+
analysisFilePath,
|
|
4648
|
+
extensionRegistry,
|
|
4649
|
+
metadataPolicy
|
|
4650
|
+
);
|
|
3364
4651
|
}
|
|
3365
4652
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
|
|
3366
4653
|
if (interfaceDecl !== null) {
|
|
3367
|
-
return analyzeInterfaceToIR(
|
|
4654
|
+
return analyzeInterfaceToIR(
|
|
4655
|
+
interfaceDecl,
|
|
4656
|
+
ctx.checker,
|
|
4657
|
+
analysisFilePath,
|
|
4658
|
+
extensionRegistry,
|
|
4659
|
+
metadataPolicy
|
|
4660
|
+
);
|
|
3368
4661
|
}
|
|
3369
4662
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
|
|
3370
4663
|
if (typeAlias !== null) {
|
|
@@ -3372,7 +4665,8 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3372
4665
|
typeAlias,
|
|
3373
4666
|
ctx.checker,
|
|
3374
4667
|
analysisFilePath,
|
|
3375
|
-
extensionRegistry
|
|
4668
|
+
extensionRegistry,
|
|
4669
|
+
metadataPolicy
|
|
3376
4670
|
);
|
|
3377
4671
|
if (result.ok) {
|
|
3378
4672
|
return result.analysis;
|
|
@@ -3395,7 +4689,7 @@ var init_program = __esm({
|
|
|
3395
4689
|
|
|
3396
4690
|
// src/validate/constraint-validator.ts
|
|
3397
4691
|
function validateFieldNode(ctx, field) {
|
|
3398
|
-
const analysis = (0,
|
|
4692
|
+
const analysis = (0, import_internal3.analyzeConstraintTargets)(
|
|
3399
4693
|
field.name,
|
|
3400
4694
|
field.type,
|
|
3401
4695
|
field.constraints,
|
|
@@ -3413,7 +4707,7 @@ function validateFieldNode(ctx, field) {
|
|
|
3413
4707
|
}
|
|
3414
4708
|
function validateObjectProperty(ctx, parentName, property) {
|
|
3415
4709
|
const qualifiedName = `${parentName}.${property.name}`;
|
|
3416
|
-
const analysis = (0,
|
|
4710
|
+
const analysis = (0, import_internal3.analyzeConstraintTargets)(
|
|
3417
4711
|
qualifiedName,
|
|
3418
4712
|
property.type,
|
|
3419
4713
|
property.constraints,
|
|
@@ -3464,11 +4758,11 @@ function validateIR(ir, options) {
|
|
|
3464
4758
|
valid: ctx.diagnostics.every((diagnostic) => diagnostic.severity !== "error")
|
|
3465
4759
|
};
|
|
3466
4760
|
}
|
|
3467
|
-
var
|
|
4761
|
+
var import_internal3;
|
|
3468
4762
|
var init_constraint_validator = __esm({
|
|
3469
4763
|
"src/validate/constraint-validator.ts"() {
|
|
3470
4764
|
"use strict";
|
|
3471
|
-
|
|
4765
|
+
import_internal3 = require("@formspec/analysis/internal");
|
|
3472
4766
|
}
|
|
3473
4767
|
});
|
|
3474
4768
|
|
|
@@ -3488,7 +4782,11 @@ function generateClassSchemas(analysis, source, options) {
|
|
|
3488
4782
|
if (errorDiagnostics !== void 0 && errorDiagnostics.length > 0) {
|
|
3489
4783
|
throw new Error(formatValidationError(errorDiagnostics));
|
|
3490
4784
|
}
|
|
3491
|
-
const ir = canonicalizeTSDoc(
|
|
4785
|
+
const ir = canonicalizeTSDoc(
|
|
4786
|
+
analysis,
|
|
4787
|
+
source,
|
|
4788
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
4789
|
+
);
|
|
3492
4790
|
const validationResult = validateIR(ir, {
|
|
3493
4791
|
...options?.extensionRegistry !== void 0 && {
|
|
3494
4792
|
extensionRegistry: options.extensionRegistry
|
|
@@ -3525,13 +4823,15 @@ function generateSchemasFromClass(options) {
|
|
|
3525
4823
|
classDecl,
|
|
3526
4824
|
ctx.checker,
|
|
3527
4825
|
options.filePath,
|
|
3528
|
-
options.extensionRegistry
|
|
4826
|
+
options.extensionRegistry,
|
|
4827
|
+
options.metadata
|
|
3529
4828
|
);
|
|
3530
4829
|
return generateClassSchemas(
|
|
3531
4830
|
analysis,
|
|
3532
4831
|
{ file: options.filePath },
|
|
3533
4832
|
{
|
|
3534
4833
|
extensionRegistry: options.extensionRegistry,
|
|
4834
|
+
metadata: options.metadata,
|
|
3535
4835
|
vendorPrefix: options.vendorPrefix
|
|
3536
4836
|
}
|
|
3537
4837
|
);
|
|
@@ -3549,13 +4849,15 @@ function generateSchemasFromProgram(options) {
|
|
|
3549
4849
|
ctx,
|
|
3550
4850
|
options.filePath,
|
|
3551
4851
|
options.typeName,
|
|
3552
|
-
options.extensionRegistry
|
|
4852
|
+
options.extensionRegistry,
|
|
4853
|
+
options.metadata
|
|
3553
4854
|
);
|
|
3554
4855
|
return generateClassSchemas(
|
|
3555
4856
|
analysis,
|
|
3556
4857
|
{ file: options.filePath },
|
|
3557
4858
|
{
|
|
3558
4859
|
extensionRegistry: options.extensionRegistry,
|
|
4860
|
+
metadata: options.metadata,
|
|
3559
4861
|
vendorPrefix: options.vendorPrefix
|
|
3560
4862
|
}
|
|
3561
4863
|
);
|
|
@@ -3577,16 +4879,28 @@ var init_class_schema = __esm({
|
|
|
3577
4879
|
// src/generators/mixed-authoring.ts
|
|
3578
4880
|
function buildMixedAuthoringSchemas(options) {
|
|
3579
4881
|
const { filePath, typeName, overlays, ...schemaOptions } = options;
|
|
3580
|
-
const analysis = analyzeNamedTypeToIR(
|
|
3581
|
-
|
|
3582
|
-
|
|
4882
|
+
const analysis = analyzeNamedTypeToIR(
|
|
4883
|
+
filePath,
|
|
4884
|
+
typeName,
|
|
4885
|
+
schemaOptions.extensionRegistry,
|
|
4886
|
+
schemaOptions.metadata
|
|
4887
|
+
);
|
|
4888
|
+
const composedAnalysis = composeAnalysisWithOverlays(analysis, overlays, schemaOptions.metadata);
|
|
4889
|
+
const ir = canonicalizeTSDoc(
|
|
4890
|
+
composedAnalysis,
|
|
4891
|
+
{ file: filePath },
|
|
4892
|
+
schemaOptions.metadata !== void 0 ? { metadata: schemaOptions.metadata } : void 0
|
|
4893
|
+
);
|
|
3583
4894
|
return {
|
|
3584
4895
|
jsonSchema: generateJsonSchemaFromIR(ir, schemaOptions),
|
|
3585
4896
|
uiSchema: generateUiSchemaFromIR(ir)
|
|
3586
4897
|
};
|
|
3587
4898
|
}
|
|
3588
|
-
function composeAnalysisWithOverlays(analysis, overlays) {
|
|
3589
|
-
const overlayIR = canonicalizeChainDSL(
|
|
4899
|
+
function composeAnalysisWithOverlays(analysis, overlays, metadata) {
|
|
4900
|
+
const overlayIR = canonicalizeChainDSL(
|
|
4901
|
+
overlays,
|
|
4902
|
+
metadata !== void 0 ? { metadata } : void 0
|
|
4903
|
+
);
|
|
3590
4904
|
const overlayFields = collectOverlayFields(overlayIR.elements);
|
|
3591
4905
|
if (overlayFields.length === 0) {
|
|
3592
4906
|
return analysis;
|
|
@@ -3642,8 +4956,10 @@ function collectOverlayFields(elements) {
|
|
|
3642
4956
|
}
|
|
3643
4957
|
function mergeFieldOverlay(baseField, overlayField, typeRegistry) {
|
|
3644
4958
|
assertSupportedOverlayField(baseField, overlayField);
|
|
4959
|
+
const metadata = mergeResolvedMetadata(baseField.metadata, overlayField.metadata);
|
|
3645
4960
|
return {
|
|
3646
4961
|
...baseField,
|
|
4962
|
+
...metadata !== void 0 && { metadata },
|
|
3647
4963
|
type: mergeFieldType(baseField, overlayField, typeRegistry),
|
|
3648
4964
|
annotations: mergeAnnotations(baseField.annotations, overlayField.annotations)
|
|
3649
4965
|
};
|
|
@@ -3756,6 +5072,7 @@ var init_mixed_authoring = __esm({
|
|
|
3756
5072
|
init_ir_generator2();
|
|
3757
5073
|
init_canonicalize();
|
|
3758
5074
|
init_program();
|
|
5075
|
+
init_metadata();
|
|
3759
5076
|
}
|
|
3760
5077
|
});
|
|
3761
5078
|
|
|
@@ -3777,12 +5094,12 @@ __export(index_exports, {
|
|
|
3777
5094
|
function buildFormSchemas(form, options) {
|
|
3778
5095
|
return {
|
|
3779
5096
|
jsonSchema: generateJsonSchema(form, options),
|
|
3780
|
-
uiSchema: generateUiSchema(form)
|
|
5097
|
+
uiSchema: generateUiSchema(form, options)
|
|
3781
5098
|
};
|
|
3782
5099
|
}
|
|
3783
5100
|
function writeSchemas(form, options) {
|
|
3784
|
-
const { outDir, name = "schema", indent = 2, vendorPrefix } = options;
|
|
3785
|
-
const buildOptions = vendorPrefix === void 0 ? void 0 : { vendorPrefix };
|
|
5101
|
+
const { outDir, name = "schema", indent = 2, vendorPrefix, metadata } = options;
|
|
5102
|
+
const buildOptions = vendorPrefix === void 0 && metadata === void 0 ? void 0 : { vendorPrefix, metadata };
|
|
3786
5103
|
const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form, buildOptions);
|
|
3787
5104
|
if (!fs.existsSync(outDir)) {
|
|
3788
5105
|
fs.mkdirSync(outDir, { recursive: true });
|