@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.js
CHANGED
|
@@ -9,8 +9,336 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/metadata/policy.ts
|
|
13
|
+
function normalizePluralization(input) {
|
|
14
|
+
if (input?.mode === "infer-if-missing") {
|
|
15
|
+
return {
|
|
16
|
+
mode: "infer-if-missing",
|
|
17
|
+
infer: () => "",
|
|
18
|
+
inflect: input.inflect
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (input?.mode === "require-explicit") {
|
|
22
|
+
return {
|
|
23
|
+
mode: "require-explicit",
|
|
24
|
+
infer: () => "",
|
|
25
|
+
inflect: NOOP_INFLECT
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
mode: "disabled",
|
|
30
|
+
infer: () => "",
|
|
31
|
+
inflect: NOOP_INFLECT
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function normalizeScalarPolicy(input) {
|
|
35
|
+
if (input?.mode === "infer-if-missing") {
|
|
36
|
+
return {
|
|
37
|
+
mode: "infer-if-missing",
|
|
38
|
+
infer: input.infer,
|
|
39
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (input?.mode === "require-explicit") {
|
|
43
|
+
return {
|
|
44
|
+
mode: "require-explicit",
|
|
45
|
+
infer: () => "",
|
|
46
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
mode: "disabled",
|
|
51
|
+
infer: () => "",
|
|
52
|
+
pluralization: normalizePluralization(input?.pluralization)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function normalizeDeclarationPolicy(input) {
|
|
56
|
+
return {
|
|
57
|
+
apiName: normalizeScalarPolicy(input?.apiName),
|
|
58
|
+
displayName: normalizeScalarPolicy(input?.displayName)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function normalizeMetadataPolicy(input) {
|
|
62
|
+
return {
|
|
63
|
+
type: normalizeDeclarationPolicy(input?.type),
|
|
64
|
+
field: normalizeDeclarationPolicy(input?.field),
|
|
65
|
+
method: normalizeDeclarationPolicy(input?.method)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function getDeclarationMetadataPolicy(policy, declarationKind) {
|
|
69
|
+
return policy[declarationKind];
|
|
70
|
+
}
|
|
71
|
+
function makeMetadataContext(surface, declarationKind, logicalName, buildContext) {
|
|
72
|
+
return {
|
|
73
|
+
surface,
|
|
74
|
+
declarationKind,
|
|
75
|
+
logicalName,
|
|
76
|
+
...buildContext !== void 0 && { buildContext }
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var NOOP_INFLECT;
|
|
80
|
+
var init_policy = __esm({
|
|
81
|
+
"src/metadata/policy.ts"() {
|
|
82
|
+
"use strict";
|
|
83
|
+
NOOP_INFLECT = () => "";
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// src/metadata/resolve.ts
|
|
88
|
+
function toExplicitScalar(value) {
|
|
89
|
+
return value !== void 0 && value.trim() !== "" ? { value, source: "explicit" } : void 0;
|
|
90
|
+
}
|
|
91
|
+
function toExplicitResolvedMetadata(explicit) {
|
|
92
|
+
if (explicit === void 0) {
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
const apiName = toExplicitScalar(explicit.apiName);
|
|
96
|
+
const displayName = toExplicitScalar(explicit.displayName);
|
|
97
|
+
const apiNamePlural = toExplicitScalar(explicit.apiNamePlural);
|
|
98
|
+
const displayNamePlural = toExplicitScalar(explicit.displayNamePlural);
|
|
99
|
+
const metadata = {
|
|
100
|
+
...apiName !== void 0 && { apiName },
|
|
101
|
+
...displayName !== void 0 && { displayName },
|
|
102
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
103
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
104
|
+
};
|
|
105
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
106
|
+
}
|
|
107
|
+
function resolveScalar(current, policy, context, metadataLabel) {
|
|
108
|
+
if (current !== void 0) {
|
|
109
|
+
return current;
|
|
110
|
+
}
|
|
111
|
+
if (policy.mode === "require-explicit") {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (policy.mode !== "infer-if-missing") {
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
const inferredValue = policy.infer(context);
|
|
120
|
+
return inferredValue.trim() !== "" ? { value: inferredValue, source: "inferred" } : void 0;
|
|
121
|
+
}
|
|
122
|
+
function resolvePlural(current, singular, policy, context, metadataLabel) {
|
|
123
|
+
if (current !== void 0) {
|
|
124
|
+
return current;
|
|
125
|
+
}
|
|
126
|
+
if (policy.mode === "require-explicit") {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
if (singular === void 0 || policy.mode !== "infer-if-missing") {
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
const pluralValue = policy.inflect({ ...context, singular: singular.value });
|
|
135
|
+
return pluralValue.trim() !== "" ? { value: pluralValue, source: "inferred" } : void 0;
|
|
136
|
+
}
|
|
137
|
+
function resolveResolvedMetadata(current, policy, context) {
|
|
138
|
+
const apiName = resolveScalar(current?.apiName, policy.apiName, context, "apiName");
|
|
139
|
+
const displayName = resolveScalar(
|
|
140
|
+
current?.displayName,
|
|
141
|
+
policy.displayName,
|
|
142
|
+
context,
|
|
143
|
+
"displayName"
|
|
144
|
+
);
|
|
145
|
+
const apiNamePlural = resolvePlural(
|
|
146
|
+
current?.apiNamePlural,
|
|
147
|
+
apiName,
|
|
148
|
+
policy.apiName.pluralization,
|
|
149
|
+
context,
|
|
150
|
+
"apiNamePlural"
|
|
151
|
+
);
|
|
152
|
+
const displayNamePlural = resolvePlural(
|
|
153
|
+
current?.displayNamePlural,
|
|
154
|
+
displayName,
|
|
155
|
+
policy.displayName.pluralization,
|
|
156
|
+
context,
|
|
157
|
+
"displayNamePlural"
|
|
158
|
+
);
|
|
159
|
+
if (apiName === void 0 && displayName === void 0 && apiNamePlural === void 0 && displayNamePlural === void 0) {
|
|
160
|
+
return void 0;
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
...apiName !== void 0 && { apiName },
|
|
164
|
+
...displayName !== void 0 && { displayName },
|
|
165
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
166
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function pickResolvedMetadataValue(baseValue, overlayValue) {
|
|
170
|
+
if (overlayValue?.source === "explicit") {
|
|
171
|
+
return overlayValue;
|
|
172
|
+
}
|
|
173
|
+
if (baseValue?.source === "explicit") {
|
|
174
|
+
return baseValue;
|
|
175
|
+
}
|
|
176
|
+
return baseValue ?? overlayValue;
|
|
177
|
+
}
|
|
178
|
+
function resolveTypeNodeMetadata(type, options) {
|
|
179
|
+
switch (type.kind) {
|
|
180
|
+
case "array":
|
|
181
|
+
return {
|
|
182
|
+
...type,
|
|
183
|
+
items: resolveTypeNodeMetadata(type.items, options)
|
|
184
|
+
};
|
|
185
|
+
case "object":
|
|
186
|
+
return {
|
|
187
|
+
...type,
|
|
188
|
+
properties: type.properties.map((property) => resolveObjectPropertyMetadata(property, options))
|
|
189
|
+
};
|
|
190
|
+
case "record":
|
|
191
|
+
return {
|
|
192
|
+
...type,
|
|
193
|
+
valueType: resolveTypeNodeMetadata(type.valueType, options)
|
|
194
|
+
};
|
|
195
|
+
case "union":
|
|
196
|
+
return {
|
|
197
|
+
...type,
|
|
198
|
+
members: type.members.map((member) => resolveTypeNodeMetadata(member, options))
|
|
199
|
+
};
|
|
200
|
+
case "reference":
|
|
201
|
+
case "primitive":
|
|
202
|
+
case "enum":
|
|
203
|
+
case "dynamic":
|
|
204
|
+
case "custom":
|
|
205
|
+
return type;
|
|
206
|
+
default: {
|
|
207
|
+
const _exhaustive = type;
|
|
208
|
+
return _exhaustive;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function resolveObjectPropertyMetadata(property, options) {
|
|
213
|
+
const metadata = resolveResolvedMetadata(property.metadata, options.policy.field, {
|
|
214
|
+
surface: options.surface,
|
|
215
|
+
declarationKind: "field",
|
|
216
|
+
logicalName: property.name,
|
|
217
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
...property,
|
|
221
|
+
...metadata !== void 0 && { metadata },
|
|
222
|
+
type: resolveTypeNodeMetadata(property.type, options)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function resolveFieldMetadataNode(field, options) {
|
|
226
|
+
const metadata = resolveResolvedMetadata(field.metadata, options.policy.field, {
|
|
227
|
+
surface: options.surface,
|
|
228
|
+
declarationKind: "field",
|
|
229
|
+
logicalName: field.name,
|
|
230
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
231
|
+
});
|
|
232
|
+
return {
|
|
233
|
+
...field,
|
|
234
|
+
...metadata !== void 0 && { metadata },
|
|
235
|
+
type: resolveTypeNodeMetadata(field.type, options)
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function resolveFormElementMetadata(element, options) {
|
|
239
|
+
switch (element.kind) {
|
|
240
|
+
case "field":
|
|
241
|
+
return resolveFieldMetadataNode(element, options);
|
|
242
|
+
case "group":
|
|
243
|
+
return {
|
|
244
|
+
...element,
|
|
245
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
246
|
+
};
|
|
247
|
+
case "conditional":
|
|
248
|
+
return {
|
|
249
|
+
...element,
|
|
250
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
251
|
+
};
|
|
252
|
+
default: {
|
|
253
|
+
const _exhaustive = element;
|
|
254
|
+
return _exhaustive;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function resolveTypeDefinitionMetadata(typeDefinition, options) {
|
|
259
|
+
const metadata = resolveResolvedMetadata(typeDefinition.metadata, options.policy.type, {
|
|
260
|
+
surface: options.surface,
|
|
261
|
+
declarationKind: "type",
|
|
262
|
+
logicalName: typeDefinition.name,
|
|
263
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
...typeDefinition,
|
|
267
|
+
...metadata !== void 0 && { metadata },
|
|
268
|
+
type: resolveTypeNodeMetadata(typeDefinition.type, options)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function resolveMetadata(explicit, policy, context) {
|
|
272
|
+
return resolveResolvedMetadata(toExplicitResolvedMetadata(explicit), policy, context);
|
|
273
|
+
}
|
|
274
|
+
function mergeResolvedMetadata(baseMetadata, overlayMetadata) {
|
|
275
|
+
const apiName = pickResolvedMetadataValue(baseMetadata?.apiName, overlayMetadata?.apiName);
|
|
276
|
+
const displayName = pickResolvedMetadataValue(
|
|
277
|
+
baseMetadata?.displayName,
|
|
278
|
+
overlayMetadata?.displayName
|
|
279
|
+
);
|
|
280
|
+
const apiNamePlural = pickResolvedMetadataValue(
|
|
281
|
+
baseMetadata?.apiNamePlural,
|
|
282
|
+
overlayMetadata?.apiNamePlural
|
|
283
|
+
);
|
|
284
|
+
const displayNamePlural = pickResolvedMetadataValue(
|
|
285
|
+
baseMetadata?.displayNamePlural,
|
|
286
|
+
overlayMetadata?.displayNamePlural
|
|
287
|
+
);
|
|
288
|
+
if (apiName === void 0 && displayName === void 0 && apiNamePlural === void 0 && displayNamePlural === void 0) {
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
...apiName !== void 0 && { apiName },
|
|
293
|
+
...displayName !== void 0 && { displayName },
|
|
294
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
295
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
function getSerializedName(logicalName, metadata) {
|
|
299
|
+
return metadata?.apiName?.value ?? logicalName;
|
|
300
|
+
}
|
|
301
|
+
function getDisplayName(metadata) {
|
|
302
|
+
return metadata?.displayName?.value;
|
|
303
|
+
}
|
|
304
|
+
function resolveFormIRMetadata(ir, options) {
|
|
305
|
+
const rootLogicalName = options.rootLogicalName ?? ir.name ?? "FormSpec";
|
|
306
|
+
const metadata = resolveResolvedMetadata(ir.metadata, options.policy.type, {
|
|
307
|
+
surface: options.surface,
|
|
308
|
+
declarationKind: "type",
|
|
309
|
+
logicalName: rootLogicalName,
|
|
310
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
311
|
+
});
|
|
312
|
+
return {
|
|
313
|
+
...ir,
|
|
314
|
+
...metadata !== void 0 && { metadata },
|
|
315
|
+
elements: ir.elements.map((element) => resolveFormElementMetadata(element, options)),
|
|
316
|
+
typeRegistry: Object.fromEntries(
|
|
317
|
+
Object.entries(ir.typeRegistry).map(([name, definition]) => [
|
|
318
|
+
name,
|
|
319
|
+
resolveTypeDefinitionMetadata(definition, options)
|
|
320
|
+
])
|
|
321
|
+
)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
var init_resolve = __esm({
|
|
325
|
+
"src/metadata/resolve.ts"() {
|
|
326
|
+
"use strict";
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// src/metadata/index.ts
|
|
331
|
+
var init_metadata = __esm({
|
|
332
|
+
"src/metadata/index.ts"() {
|
|
333
|
+
"use strict";
|
|
334
|
+
init_policy();
|
|
335
|
+
init_resolve();
|
|
336
|
+
init_resolve();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
12
340
|
// src/canonicalize/chain-dsl-canonicalizer.ts
|
|
13
|
-
import { IR_VERSION } from "@formspec/core/internals";
|
|
341
|
+
import { IR_VERSION, _getFormSpecMetadataPolicy } from "@formspec/core/internals";
|
|
14
342
|
function isGroup(el) {
|
|
15
343
|
return el._type === "group";
|
|
16
344
|
}
|
|
@@ -20,57 +348,60 @@ function isConditional(el) {
|
|
|
20
348
|
function isField(el) {
|
|
21
349
|
return el._type === "field";
|
|
22
350
|
}
|
|
23
|
-
function canonicalizeChainDSL(form) {
|
|
351
|
+
function canonicalizeChainDSL(form, options) {
|
|
352
|
+
const metadataPolicy = normalizeMetadataPolicy(
|
|
353
|
+
options?.metadata ?? _getFormSpecMetadataPolicy(form)
|
|
354
|
+
);
|
|
24
355
|
return {
|
|
25
356
|
kind: "form-ir",
|
|
26
357
|
irVersion: IR_VERSION,
|
|
27
|
-
elements: canonicalizeElements(form.elements),
|
|
358
|
+
elements: canonicalizeElements(form.elements, metadataPolicy),
|
|
28
359
|
rootAnnotations: [],
|
|
29
360
|
typeRegistry: {},
|
|
30
361
|
provenance: CHAIN_DSL_PROVENANCE
|
|
31
362
|
};
|
|
32
363
|
}
|
|
33
|
-
function canonicalizeElements(elements) {
|
|
34
|
-
return elements.map(canonicalizeElement);
|
|
364
|
+
function canonicalizeElements(elements, metadataPolicy) {
|
|
365
|
+
return elements.map((element) => canonicalizeElement(element, metadataPolicy));
|
|
35
366
|
}
|
|
36
|
-
function canonicalizeElement(element) {
|
|
367
|
+
function canonicalizeElement(element, metadataPolicy) {
|
|
37
368
|
if (isField(element)) {
|
|
38
|
-
return canonicalizeField(element);
|
|
369
|
+
return canonicalizeField(element, metadataPolicy);
|
|
39
370
|
}
|
|
40
371
|
if (isGroup(element)) {
|
|
41
|
-
return canonicalizeGroup(element);
|
|
372
|
+
return canonicalizeGroup(element, metadataPolicy);
|
|
42
373
|
}
|
|
43
374
|
if (isConditional(element)) {
|
|
44
|
-
return canonicalizeConditional(element);
|
|
375
|
+
return canonicalizeConditional(element, metadataPolicy);
|
|
45
376
|
}
|
|
46
377
|
const _exhaustive = element;
|
|
47
378
|
throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);
|
|
48
379
|
}
|
|
49
|
-
function canonicalizeField(field) {
|
|
380
|
+
function canonicalizeField(field, metadataPolicy) {
|
|
50
381
|
switch (field._field) {
|
|
51
382
|
case "text":
|
|
52
|
-
return canonicalizeTextField(field);
|
|
383
|
+
return canonicalizeTextField(field, metadataPolicy);
|
|
53
384
|
case "number":
|
|
54
|
-
return canonicalizeNumberField(field);
|
|
385
|
+
return canonicalizeNumberField(field, metadataPolicy);
|
|
55
386
|
case "boolean":
|
|
56
|
-
return canonicalizeBooleanField(field);
|
|
387
|
+
return canonicalizeBooleanField(field, metadataPolicy);
|
|
57
388
|
case "enum":
|
|
58
|
-
return canonicalizeStaticEnumField(field);
|
|
389
|
+
return canonicalizeStaticEnumField(field, metadataPolicy);
|
|
59
390
|
case "dynamic_enum":
|
|
60
|
-
return canonicalizeDynamicEnumField(field);
|
|
391
|
+
return canonicalizeDynamicEnumField(field, metadataPolicy);
|
|
61
392
|
case "dynamic_schema":
|
|
62
|
-
return canonicalizeDynamicSchemaField(field);
|
|
393
|
+
return canonicalizeDynamicSchemaField(field, metadataPolicy);
|
|
63
394
|
case "array":
|
|
64
|
-
return canonicalizeArrayField(field);
|
|
395
|
+
return canonicalizeArrayField(field, metadataPolicy);
|
|
65
396
|
case "object":
|
|
66
|
-
return canonicalizeObjectField(field);
|
|
397
|
+
return canonicalizeObjectField(field, metadataPolicy);
|
|
67
398
|
default: {
|
|
68
399
|
const _exhaustive = field;
|
|
69
400
|
throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);
|
|
70
401
|
}
|
|
71
402
|
}
|
|
72
403
|
}
|
|
73
|
-
function canonicalizeTextField(field) {
|
|
404
|
+
function canonicalizeTextField(field, metadataPolicy) {
|
|
74
405
|
const type = { kind: "primitive", primitiveKind: "string" };
|
|
75
406
|
const constraints = [];
|
|
76
407
|
if (field.minLength !== void 0) {
|
|
@@ -102,13 +433,14 @@ function canonicalizeTextField(field) {
|
|
|
102
433
|
}
|
|
103
434
|
return buildFieldNode(
|
|
104
435
|
field.name,
|
|
436
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
105
437
|
type,
|
|
106
438
|
field.required,
|
|
107
|
-
buildAnnotations(field
|
|
439
|
+
buildAnnotations(getExplicitDisplayName(field), field.placeholder),
|
|
108
440
|
constraints
|
|
109
441
|
);
|
|
110
442
|
}
|
|
111
|
-
function canonicalizeNumberField(field) {
|
|
443
|
+
function canonicalizeNumberField(field, metadataPolicy) {
|
|
112
444
|
const type = { kind: "primitive", primitiveKind: "number" };
|
|
113
445
|
const constraints = [];
|
|
114
446
|
if (field.min !== void 0) {
|
|
@@ -140,17 +472,24 @@ function canonicalizeNumberField(field) {
|
|
|
140
472
|
}
|
|
141
473
|
return buildFieldNode(
|
|
142
474
|
field.name,
|
|
475
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
143
476
|
type,
|
|
144
477
|
field.required,
|
|
145
|
-
buildAnnotations(field
|
|
478
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
146
479
|
constraints
|
|
147
480
|
);
|
|
148
481
|
}
|
|
149
|
-
function canonicalizeBooleanField(field) {
|
|
482
|
+
function canonicalizeBooleanField(field, metadataPolicy) {
|
|
150
483
|
const type = { kind: "primitive", primitiveKind: "boolean" };
|
|
151
|
-
return buildFieldNode(
|
|
484
|
+
return buildFieldNode(
|
|
485
|
+
field.name,
|
|
486
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
487
|
+
type,
|
|
488
|
+
field.required,
|
|
489
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
490
|
+
);
|
|
152
491
|
}
|
|
153
|
-
function canonicalizeStaticEnumField(field) {
|
|
492
|
+
function canonicalizeStaticEnumField(field, metadataPolicy) {
|
|
154
493
|
const members = field.options.map((opt) => {
|
|
155
494
|
if (typeof opt === "string") {
|
|
156
495
|
return { value: opt };
|
|
@@ -158,28 +497,46 @@ function canonicalizeStaticEnumField(field) {
|
|
|
158
497
|
return { value: opt.id, displayName: opt.label };
|
|
159
498
|
});
|
|
160
499
|
const type = { kind: "enum", members };
|
|
161
|
-
return buildFieldNode(
|
|
500
|
+
return buildFieldNode(
|
|
501
|
+
field.name,
|
|
502
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
503
|
+
type,
|
|
504
|
+
field.required,
|
|
505
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
506
|
+
);
|
|
162
507
|
}
|
|
163
|
-
function canonicalizeDynamicEnumField(field) {
|
|
508
|
+
function canonicalizeDynamicEnumField(field, metadataPolicy) {
|
|
164
509
|
const type = {
|
|
165
510
|
kind: "dynamic",
|
|
166
511
|
dynamicKind: "enum",
|
|
167
512
|
sourceKey: field.source,
|
|
168
513
|
parameterFields: field.params ? [...field.params] : []
|
|
169
514
|
};
|
|
170
|
-
return buildFieldNode(
|
|
515
|
+
return buildFieldNode(
|
|
516
|
+
field.name,
|
|
517
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
518
|
+
type,
|
|
519
|
+
field.required,
|
|
520
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
521
|
+
);
|
|
171
522
|
}
|
|
172
|
-
function canonicalizeDynamicSchemaField(field) {
|
|
523
|
+
function canonicalizeDynamicSchemaField(field, metadataPolicy) {
|
|
173
524
|
const type = {
|
|
174
525
|
kind: "dynamic",
|
|
175
526
|
dynamicKind: "schema",
|
|
176
527
|
sourceKey: field.schemaSource,
|
|
177
528
|
parameterFields: []
|
|
178
529
|
};
|
|
179
|
-
return buildFieldNode(
|
|
530
|
+
return buildFieldNode(
|
|
531
|
+
field.name,
|
|
532
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
533
|
+
type,
|
|
534
|
+
field.required,
|
|
535
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
536
|
+
);
|
|
180
537
|
}
|
|
181
|
-
function canonicalizeArrayField(field) {
|
|
182
|
-
const itemProperties = buildObjectProperties(field.items);
|
|
538
|
+
function canonicalizeArrayField(field, metadataPolicy) {
|
|
539
|
+
const itemProperties = buildObjectProperties(field.items, metadataPolicy);
|
|
183
540
|
const itemsType = {
|
|
184
541
|
kind: "object",
|
|
185
542
|
properties: itemProperties,
|
|
@@ -207,37 +564,44 @@ function canonicalizeArrayField(field) {
|
|
|
207
564
|
}
|
|
208
565
|
return buildFieldNode(
|
|
209
566
|
field.name,
|
|
567
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
210
568
|
type,
|
|
211
569
|
field.required,
|
|
212
|
-
buildAnnotations(field
|
|
570
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
213
571
|
constraints
|
|
214
572
|
);
|
|
215
573
|
}
|
|
216
|
-
function canonicalizeObjectField(field) {
|
|
217
|
-
const properties = buildObjectProperties(field.properties);
|
|
574
|
+
function canonicalizeObjectField(field, metadataPolicy) {
|
|
575
|
+
const properties = buildObjectProperties(field.properties, metadataPolicy);
|
|
218
576
|
const type = {
|
|
219
577
|
kind: "object",
|
|
220
578
|
properties,
|
|
221
579
|
additionalProperties: true
|
|
222
580
|
};
|
|
223
|
-
return buildFieldNode(
|
|
581
|
+
return buildFieldNode(
|
|
582
|
+
field.name,
|
|
583
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
584
|
+
type,
|
|
585
|
+
field.required,
|
|
586
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
587
|
+
);
|
|
224
588
|
}
|
|
225
|
-
function canonicalizeGroup(g) {
|
|
589
|
+
function canonicalizeGroup(g, metadataPolicy) {
|
|
226
590
|
return {
|
|
227
591
|
kind: "group",
|
|
228
592
|
label: g.label,
|
|
229
|
-
elements: canonicalizeElements(g.elements),
|
|
593
|
+
elements: canonicalizeElements(g.elements, metadataPolicy),
|
|
230
594
|
provenance: CHAIN_DSL_PROVENANCE
|
|
231
595
|
};
|
|
232
596
|
}
|
|
233
|
-
function canonicalizeConditional(c) {
|
|
597
|
+
function canonicalizeConditional(c, metadataPolicy) {
|
|
234
598
|
return {
|
|
235
599
|
kind: "conditional",
|
|
236
600
|
fieldName: c.field,
|
|
237
601
|
// Conditional values from the chain DSL are JSON-serializable primitives
|
|
238
602
|
// (strings, numbers, booleans) produced by the `is()` predicate helper.
|
|
239
603
|
value: assertJsonValue(c.value),
|
|
240
|
-
elements: canonicalizeElements(c.elements),
|
|
604
|
+
elements: canonicalizeElements(c.elements, metadataPolicy),
|
|
241
605
|
provenance: CHAIN_DSL_PROVENANCE
|
|
242
606
|
};
|
|
243
607
|
}
|
|
@@ -257,10 +621,11 @@ function assertJsonValue(v) {
|
|
|
257
621
|
}
|
|
258
622
|
throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);
|
|
259
623
|
}
|
|
260
|
-
function buildFieldNode(name, type, required, annotations, constraints = []) {
|
|
624
|
+
function buildFieldNode(name, metadata, type, required, annotations, constraints = []) {
|
|
261
625
|
return {
|
|
262
626
|
kind: "field",
|
|
263
627
|
name,
|
|
628
|
+
...metadata !== void 0 && { metadata },
|
|
264
629
|
type,
|
|
265
630
|
required: required === true,
|
|
266
631
|
constraints,
|
|
@@ -290,13 +655,14 @@ function buildAnnotations(label, placeholder) {
|
|
|
290
655
|
}
|
|
291
656
|
return annotations;
|
|
292
657
|
}
|
|
293
|
-
function buildObjectProperties(elements, insideConditional = false) {
|
|
658
|
+
function buildObjectProperties(elements, metadataPolicy, insideConditional = false) {
|
|
294
659
|
const properties = [];
|
|
295
660
|
for (const el of elements) {
|
|
296
661
|
if (isField(el)) {
|
|
297
|
-
const fieldNode = canonicalizeField(el);
|
|
662
|
+
const fieldNode = canonicalizeField(el, metadataPolicy);
|
|
298
663
|
properties.push({
|
|
299
664
|
name: fieldNode.name,
|
|
665
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
300
666
|
type: fieldNode.type,
|
|
301
667
|
// Fields inside a conditional branch are always optional in the
|
|
302
668
|
// data schema, regardless of their `required` flag — the condition
|
|
@@ -307,17 +673,35 @@ function buildObjectProperties(elements, insideConditional = false) {
|
|
|
307
673
|
provenance: CHAIN_DSL_PROVENANCE
|
|
308
674
|
});
|
|
309
675
|
} else if (isGroup(el)) {
|
|
310
|
-
properties.push(...buildObjectProperties(el.elements, insideConditional));
|
|
676
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, insideConditional));
|
|
311
677
|
} else if (isConditional(el)) {
|
|
312
|
-
properties.push(...buildObjectProperties(el.elements, true));
|
|
678
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, true));
|
|
313
679
|
}
|
|
314
680
|
}
|
|
315
681
|
return properties;
|
|
316
682
|
}
|
|
683
|
+
function getExplicitDisplayName(field) {
|
|
684
|
+
if (field.label !== void 0 && field.displayName !== void 0) {
|
|
685
|
+
throw new Error('Chain DSL fields cannot specify both "label" and "displayName".');
|
|
686
|
+
}
|
|
687
|
+
return field.displayName ?? field.label;
|
|
688
|
+
}
|
|
689
|
+
function resolveFieldMetadata(logicalName, field, metadataPolicy) {
|
|
690
|
+
const displayName = getExplicitDisplayName(field);
|
|
691
|
+
return resolveMetadata(
|
|
692
|
+
{
|
|
693
|
+
...field.apiName !== void 0 && { apiName: field.apiName },
|
|
694
|
+
...displayName !== void 0 && { displayName }
|
|
695
|
+
},
|
|
696
|
+
getDeclarationMetadataPolicy(metadataPolicy, "field"),
|
|
697
|
+
makeMetadataContext("chain-dsl", "field", logicalName)
|
|
698
|
+
);
|
|
699
|
+
}
|
|
317
700
|
var CHAIN_DSL_PROVENANCE;
|
|
318
701
|
var init_chain_dsl_canonicalizer = __esm({
|
|
319
702
|
"src/canonicalize/chain-dsl-canonicalizer.ts"() {
|
|
320
703
|
"use strict";
|
|
704
|
+
init_metadata();
|
|
321
705
|
CHAIN_DSL_PROVENANCE = {
|
|
322
706
|
surface: "chain-dsl",
|
|
323
707
|
file: "",
|
|
@@ -329,7 +713,7 @@ var init_chain_dsl_canonicalizer = __esm({
|
|
|
329
713
|
|
|
330
714
|
// src/canonicalize/tsdoc-canonicalizer.ts
|
|
331
715
|
import { IR_VERSION as IR_VERSION2 } from "@formspec/core/internals";
|
|
332
|
-
function canonicalizeTSDoc(analysis, source) {
|
|
716
|
+
function canonicalizeTSDoc(analysis, source, options) {
|
|
333
717
|
const file = source?.file ?? "";
|
|
334
718
|
const provenance = {
|
|
335
719
|
surface: "tsdoc",
|
|
@@ -338,15 +722,21 @@ function canonicalizeTSDoc(analysis, source) {
|
|
|
338
722
|
column: 0
|
|
339
723
|
};
|
|
340
724
|
const elements = assembleElements(analysis.fields, analysis.fieldLayouts, provenance);
|
|
341
|
-
|
|
725
|
+
const ir = {
|
|
342
726
|
kind: "form-ir",
|
|
727
|
+
name: analysis.name,
|
|
343
728
|
irVersion: IR_VERSION2,
|
|
344
729
|
elements,
|
|
730
|
+
...analysis.metadata !== void 0 && { metadata: analysis.metadata },
|
|
345
731
|
typeRegistry: analysis.typeRegistry,
|
|
346
732
|
...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations },
|
|
347
733
|
...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { annotations: analysis.annotations },
|
|
348
734
|
provenance
|
|
349
735
|
};
|
|
736
|
+
return resolveFormIRMetadata(ir, {
|
|
737
|
+
policy: normalizeMetadataPolicy(options?.metadata),
|
|
738
|
+
surface: "tsdoc"
|
|
739
|
+
});
|
|
350
740
|
}
|
|
351
741
|
function assembleElements(fields, layouts, provenance) {
|
|
352
742
|
const elements = [];
|
|
@@ -405,6 +795,7 @@ function wrapInConditional(field, layout, provenance) {
|
|
|
405
795
|
var init_tsdoc_canonicalizer = __esm({
|
|
406
796
|
"src/canonicalize/tsdoc-canonicalizer.ts"() {
|
|
407
797
|
"use strict";
|
|
798
|
+
init_metadata();
|
|
408
799
|
}
|
|
409
800
|
});
|
|
410
801
|
|
|
@@ -417,6 +808,126 @@ var init_canonicalize = __esm({
|
|
|
417
808
|
}
|
|
418
809
|
});
|
|
419
810
|
|
|
811
|
+
// src/metadata/collision-guards.ts
|
|
812
|
+
function assertUniqueSerializedNames(entries, scope) {
|
|
813
|
+
const seen = /* @__PURE__ */ new Map();
|
|
814
|
+
for (const entry of entries) {
|
|
815
|
+
const previous = seen.get(entry.serializedName);
|
|
816
|
+
if (previous !== void 0) {
|
|
817
|
+
if (previous.logicalName === entry.logicalName && previous.category === entry.category) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
throw new Error(
|
|
821
|
+
`Serialized name collision in ${scope}: ${previous.category} "${previous.logicalName}" and ${entry.category} "${entry.logicalName}" both resolve to "${entry.serializedName}".`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
seen.set(entry.serializedName, entry);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
function collectFlattenedFields(elements) {
|
|
828
|
+
const fields = [];
|
|
829
|
+
for (const element of elements) {
|
|
830
|
+
switch (element.kind) {
|
|
831
|
+
case "field":
|
|
832
|
+
fields.push(element);
|
|
833
|
+
break;
|
|
834
|
+
case "group":
|
|
835
|
+
case "conditional":
|
|
836
|
+
fields.push(...collectFlattenedFields(element.elements));
|
|
837
|
+
break;
|
|
838
|
+
default: {
|
|
839
|
+
const exhaustive = element;
|
|
840
|
+
void exhaustive;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return fields;
|
|
845
|
+
}
|
|
846
|
+
function validateObjectProperties(properties, scope) {
|
|
847
|
+
assertUniqueSerializedNames(
|
|
848
|
+
properties.map((property) => ({
|
|
849
|
+
logicalName: property.name,
|
|
850
|
+
serializedName: getSerializedName(property.name, property.metadata),
|
|
851
|
+
category: "object property"
|
|
852
|
+
})),
|
|
853
|
+
scope
|
|
854
|
+
);
|
|
855
|
+
for (const property of properties) {
|
|
856
|
+
validateTypeNode(
|
|
857
|
+
property.type,
|
|
858
|
+
`${scope}.${getSerializedName(property.name, property.metadata)}`
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
function validateTypeNode(type, scope) {
|
|
863
|
+
switch (type.kind) {
|
|
864
|
+
case "array":
|
|
865
|
+
validateTypeNode(type.items, `${scope}[]`);
|
|
866
|
+
break;
|
|
867
|
+
case "object":
|
|
868
|
+
validateObjectProperties(type.properties, scope);
|
|
869
|
+
break;
|
|
870
|
+
case "record":
|
|
871
|
+
validateTypeNode(type.valueType, `${scope}.*`);
|
|
872
|
+
break;
|
|
873
|
+
case "union":
|
|
874
|
+
type.members.forEach((member, index) => {
|
|
875
|
+
validateTypeNode(member, `${scope}|${String(index)}`);
|
|
876
|
+
});
|
|
877
|
+
break;
|
|
878
|
+
case "reference":
|
|
879
|
+
case "primitive":
|
|
880
|
+
case "enum":
|
|
881
|
+
case "dynamic":
|
|
882
|
+
case "custom":
|
|
883
|
+
break;
|
|
884
|
+
default: {
|
|
885
|
+
const exhaustive = type;
|
|
886
|
+
void exhaustive;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
function validateTypeDefinitions(typeRegistry) {
|
|
891
|
+
const definitions = Object.values(typeRegistry);
|
|
892
|
+
assertUniqueSerializedNames(
|
|
893
|
+
definitions.map((definition) => ({
|
|
894
|
+
logicalName: definition.name,
|
|
895
|
+
serializedName: getSerializedName(definition.name, definition.metadata),
|
|
896
|
+
category: "type definition"
|
|
897
|
+
})),
|
|
898
|
+
"$defs"
|
|
899
|
+
);
|
|
900
|
+
for (const definition of definitions) {
|
|
901
|
+
validateTypeDefinition(definition);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
function validateTypeDefinition(definition) {
|
|
905
|
+
validateTypeNode(
|
|
906
|
+
definition.type,
|
|
907
|
+
`type "${getSerializedName(definition.name, definition.metadata)}"`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
function assertNoSerializedNameCollisions(ir) {
|
|
911
|
+
assertUniqueSerializedNames(
|
|
912
|
+
collectFlattenedFields(ir.elements).map((field) => ({
|
|
913
|
+
logicalName: field.name,
|
|
914
|
+
serializedName: getSerializedName(field.name, field.metadata),
|
|
915
|
+
category: "field"
|
|
916
|
+
})),
|
|
917
|
+
"form root"
|
|
918
|
+
);
|
|
919
|
+
for (const field of collectFlattenedFields(ir.elements)) {
|
|
920
|
+
validateTypeNode(field.type, `field "${getSerializedName(field.name, field.metadata)}"`);
|
|
921
|
+
}
|
|
922
|
+
validateTypeDefinitions(ir.typeRegistry);
|
|
923
|
+
}
|
|
924
|
+
var init_collision_guards = __esm({
|
|
925
|
+
"src/metadata/collision-guards.ts"() {
|
|
926
|
+
"use strict";
|
|
927
|
+
init_resolve();
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
|
|
420
931
|
// src/json-schema/ir-generator.ts
|
|
421
932
|
function makeContext(options) {
|
|
422
933
|
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
@@ -427,19 +938,33 @@ function makeContext(options) {
|
|
|
427
938
|
}
|
|
428
939
|
return {
|
|
429
940
|
defs: {},
|
|
941
|
+
typeNameMap: {},
|
|
942
|
+
typeRegistry: {},
|
|
430
943
|
extensionRegistry: options?.extensionRegistry,
|
|
431
944
|
vendorPrefix
|
|
432
945
|
};
|
|
433
946
|
}
|
|
434
947
|
function generateJsonSchemaFromIR(ir, options) {
|
|
435
|
-
|
|
948
|
+
assertNoSerializedNameCollisions(ir);
|
|
949
|
+
const ctx = {
|
|
950
|
+
...makeContext(options),
|
|
951
|
+
typeRegistry: ir.typeRegistry,
|
|
952
|
+
typeNameMap: Object.fromEntries(
|
|
953
|
+
Object.entries(ir.typeRegistry).map(([name, typeDef]) => [
|
|
954
|
+
name,
|
|
955
|
+
getSerializedName(name, typeDef.metadata)
|
|
956
|
+
])
|
|
957
|
+
)
|
|
958
|
+
};
|
|
436
959
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
437
|
-
ctx.
|
|
960
|
+
const schemaName = ctx.typeNameMap[name] ?? name;
|
|
961
|
+
ctx.defs[schemaName] = generateTypeNode(typeDef.type, ctx);
|
|
962
|
+
applyResolvedMetadata(ctx.defs[schemaName], typeDef.metadata);
|
|
438
963
|
if (typeDef.constraints && typeDef.constraints.length > 0) {
|
|
439
|
-
applyConstraints(ctx.defs[
|
|
964
|
+
applyConstraints(ctx.defs[schemaName], typeDef.constraints, ctx);
|
|
440
965
|
}
|
|
441
966
|
if (typeDef.annotations && typeDef.annotations.length > 0) {
|
|
442
|
-
applyAnnotations(ctx.defs[
|
|
967
|
+
applyAnnotations(ctx.defs[schemaName], typeDef.annotations, ctx);
|
|
443
968
|
}
|
|
444
969
|
}
|
|
445
970
|
const properties = {};
|
|
@@ -452,6 +977,7 @@ function generateJsonSchemaFromIR(ir, options) {
|
|
|
452
977
|
properties,
|
|
453
978
|
...uniqueRequired.length > 0 && { required: uniqueRequired }
|
|
454
979
|
};
|
|
980
|
+
applyResolvedMetadata(result, ir.metadata);
|
|
455
981
|
if (ir.annotations && ir.annotations.length > 0) {
|
|
456
982
|
applyAnnotations(result, ir.annotations, ctx);
|
|
457
983
|
}
|
|
@@ -464,9 +990,9 @@ function collectFields(elements, properties, required, ctx) {
|
|
|
464
990
|
for (const element of elements) {
|
|
465
991
|
switch (element.kind) {
|
|
466
992
|
case "field":
|
|
467
|
-
properties[element.name] = generateFieldSchema(element, ctx);
|
|
993
|
+
properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);
|
|
468
994
|
if (element.required) {
|
|
469
|
-
required.push(element.name);
|
|
995
|
+
required.push(getSerializedName(element.name, element.metadata));
|
|
470
996
|
}
|
|
471
997
|
break;
|
|
472
998
|
case "group":
|
|
@@ -510,6 +1036,7 @@ function generateFieldSchema(field, ctx) {
|
|
|
510
1036
|
rootAnnotations.push(annotation);
|
|
511
1037
|
}
|
|
512
1038
|
}
|
|
1039
|
+
applyResolvedMetadata(schema, field.metadata);
|
|
513
1040
|
applyAnnotations(schema, rootAnnotations, ctx);
|
|
514
1041
|
if (itemStringSchema !== void 0) {
|
|
515
1042
|
applyAnnotations(itemStringSchema, itemAnnotations, ctx);
|
|
@@ -517,7 +1044,7 @@ function generateFieldSchema(field, ctx) {
|
|
|
517
1044
|
if (pathConstraints.length === 0) {
|
|
518
1045
|
return schema;
|
|
519
1046
|
}
|
|
520
|
-
return applyPathTargetedConstraints(schema, pathConstraints, ctx);
|
|
1047
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx, field.type);
|
|
521
1048
|
}
|
|
522
1049
|
function isStringItemConstraint(constraint) {
|
|
523
1050
|
switch (constraint.constraintKind) {
|
|
@@ -529,9 +1056,11 @@ function isStringItemConstraint(constraint) {
|
|
|
529
1056
|
return false;
|
|
530
1057
|
}
|
|
531
1058
|
}
|
|
532
|
-
function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
1059
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
|
|
533
1060
|
if (schema.type === "array" && schema.items) {
|
|
534
|
-
|
|
1061
|
+
const referencedType = typeNode?.kind === "reference" ? resolveReferencedType(typeNode, ctx) : void 0;
|
|
1062
|
+
const nestedType = typeNode?.kind === "array" ? typeNode.items : referencedType?.kind === "array" ? referencedType.items : void 0;
|
|
1063
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
|
|
535
1064
|
return schema;
|
|
536
1065
|
}
|
|
537
1066
|
const byTarget = /* @__PURE__ */ new Map();
|
|
@@ -546,7 +1075,7 @@ function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
|
546
1075
|
for (const [target, constraints] of byTarget) {
|
|
547
1076
|
const subSchema = {};
|
|
548
1077
|
applyConstraints(subSchema, constraints, ctx);
|
|
549
|
-
propertyOverrides[target] = subSchema;
|
|
1078
|
+
propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;
|
|
550
1079
|
}
|
|
551
1080
|
if (schema.$ref) {
|
|
552
1081
|
const { $ref, ...rest } = schema;
|
|
@@ -594,7 +1123,7 @@ function generateTypeNode(type, ctx) {
|
|
|
594
1123
|
case "union":
|
|
595
1124
|
return generateUnionType(type, ctx);
|
|
596
1125
|
case "reference":
|
|
597
|
-
return generateReferenceType(type);
|
|
1126
|
+
return generateReferenceType(type, ctx);
|
|
598
1127
|
case "dynamic":
|
|
599
1128
|
return generateDynamicType(type);
|
|
600
1129
|
case "custom":
|
|
@@ -635,9 +1164,10 @@ function generateObjectType(type, ctx) {
|
|
|
635
1164
|
const properties = {};
|
|
636
1165
|
const required = [];
|
|
637
1166
|
for (const prop of type.properties) {
|
|
638
|
-
|
|
1167
|
+
const propertyName = getSerializedName(prop.name, prop.metadata);
|
|
1168
|
+
properties[propertyName] = generatePropertySchema(prop, ctx);
|
|
639
1169
|
if (!prop.optional) {
|
|
640
|
-
required.push(
|
|
1170
|
+
required.push(propertyName);
|
|
641
1171
|
}
|
|
642
1172
|
}
|
|
643
1173
|
const schema = { type: "object", properties };
|
|
@@ -658,6 +1188,7 @@ function generateRecordType(type, ctx) {
|
|
|
658
1188
|
function generatePropertySchema(prop, ctx) {
|
|
659
1189
|
const schema = generateTypeNode(prop.type, ctx);
|
|
660
1190
|
applyConstraints(schema, prop.constraints, ctx);
|
|
1191
|
+
applyResolvedMetadata(schema, prop.metadata);
|
|
661
1192
|
applyAnnotations(schema, prop.annotations, ctx);
|
|
662
1193
|
return schema;
|
|
663
1194
|
}
|
|
@@ -686,8 +1217,28 @@ function isNullableUnion(type) {
|
|
|
686
1217
|
).length;
|
|
687
1218
|
return nullCount === 1;
|
|
688
1219
|
}
|
|
689
|
-
function generateReferenceType(type) {
|
|
690
|
-
return { $ref: `#/$defs/${type.name}` };
|
|
1220
|
+
function generateReferenceType(type, ctx) {
|
|
1221
|
+
return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };
|
|
1222
|
+
}
|
|
1223
|
+
function applyResolvedMetadata(schema, metadata) {
|
|
1224
|
+
const displayName = getDisplayName(metadata);
|
|
1225
|
+
if (displayName !== void 0) {
|
|
1226
|
+
schema.title = displayName;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
function resolveReferencedType(type, ctx) {
|
|
1230
|
+
return ctx.typeRegistry[type.name]?.type;
|
|
1231
|
+
}
|
|
1232
|
+
function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
|
|
1233
|
+
if (typeNode?.kind === "object") {
|
|
1234
|
+
const property = typeNode.properties.find((candidate) => candidate.name === logicalName);
|
|
1235
|
+
return property === void 0 ? logicalName : getSerializedName(property.name, property.metadata);
|
|
1236
|
+
}
|
|
1237
|
+
if (typeNode?.kind === "reference") {
|
|
1238
|
+
const referencedType = resolveReferencedType(typeNode, ctx);
|
|
1239
|
+
return referencedType === void 0 ? logicalName : resolveSerializedPropertyName(logicalName, referencedType, ctx);
|
|
1240
|
+
}
|
|
1241
|
+
return logicalName;
|
|
691
1242
|
}
|
|
692
1243
|
function generateDynamicType(type) {
|
|
693
1244
|
if (type.dynamicKind === "enum") {
|
|
@@ -767,7 +1318,7 @@ function applyAnnotations(schema, annotations, ctx) {
|
|
|
767
1318
|
for (const annotation of annotations) {
|
|
768
1319
|
switch (annotation.annotationKind) {
|
|
769
1320
|
case "displayName":
|
|
770
|
-
schema.title
|
|
1321
|
+
schema.title ??= annotation.value;
|
|
771
1322
|
break;
|
|
772
1323
|
case "description":
|
|
773
1324
|
schema.description = annotation.value;
|
|
@@ -854,12 +1405,17 @@ function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPr
|
|
|
854
1405
|
var init_ir_generator = __esm({
|
|
855
1406
|
"src/json-schema/ir-generator.ts"() {
|
|
856
1407
|
"use strict";
|
|
1408
|
+
init_metadata();
|
|
1409
|
+
init_collision_guards();
|
|
857
1410
|
}
|
|
858
1411
|
});
|
|
859
1412
|
|
|
860
1413
|
// src/json-schema/generator.ts
|
|
861
1414
|
function generateJsonSchema(form, options) {
|
|
862
|
-
const ir = canonicalizeChainDSL(
|
|
1415
|
+
const ir = canonicalizeChainDSL(
|
|
1416
|
+
form,
|
|
1417
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
1418
|
+
);
|
|
863
1419
|
const internalOptions = options?.vendorPrefix === void 0 ? void 0 : { vendorPrefix: options.vendorPrefix };
|
|
864
1420
|
return generateJsonSchemaFromIR(ir, internalOptions);
|
|
865
1421
|
}
|
|
@@ -1042,13 +1598,21 @@ function combineRules(parentRule, childRule) {
|
|
|
1042
1598
|
}
|
|
1043
1599
|
};
|
|
1044
1600
|
}
|
|
1045
|
-
function
|
|
1046
|
-
const
|
|
1601
|
+
function getFieldDisplayName(field) {
|
|
1602
|
+
const resolvedDisplayName = getDisplayName(field.metadata);
|
|
1603
|
+
if (resolvedDisplayName !== void 0) {
|
|
1604
|
+
return resolvedDisplayName;
|
|
1605
|
+
}
|
|
1606
|
+
return field.annotations.find((annotation) => annotation.annotationKind === "displayName")?.value;
|
|
1607
|
+
}
|
|
1608
|
+
function fieldNodeToControl(field, fieldNameMap, parentRule) {
|
|
1047
1609
|
const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === "placeholder");
|
|
1610
|
+
const serializedName = fieldNameMap.get(field.name) ?? getSerializedName(field.name, field.metadata);
|
|
1611
|
+
const displayName = getFieldDisplayName(field);
|
|
1048
1612
|
const control = {
|
|
1049
1613
|
type: "Control",
|
|
1050
|
-
scope: fieldToScope(
|
|
1051
|
-
...
|
|
1614
|
+
scope: fieldToScope(serializedName),
|
|
1615
|
+
...displayName !== void 0 && { label: displayName },
|
|
1052
1616
|
...placeholderAnnotation !== void 0 && {
|
|
1053
1617
|
options: { placeholder: placeholderAnnotation.value }
|
|
1054
1618
|
},
|
|
@@ -1056,30 +1620,30 @@ function fieldNodeToControl(field, parentRule) {
|
|
|
1056
1620
|
};
|
|
1057
1621
|
return control;
|
|
1058
1622
|
}
|
|
1059
|
-
function groupNodeToLayout(group, parentRule) {
|
|
1623
|
+
function groupNodeToLayout(group, fieldNameMap, parentRule) {
|
|
1060
1624
|
return {
|
|
1061
1625
|
type: "Group",
|
|
1062
1626
|
label: group.label,
|
|
1063
|
-
elements: irElementsToUiSchema(group.elements, parentRule),
|
|
1627
|
+
elements: irElementsToUiSchema(group.elements, fieldNameMap, parentRule),
|
|
1064
1628
|
...parentRule !== void 0 && { rule: parentRule }
|
|
1065
1629
|
};
|
|
1066
1630
|
}
|
|
1067
|
-
function irElementsToUiSchema(elements, parentRule) {
|
|
1631
|
+
function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
|
|
1068
1632
|
const result = [];
|
|
1069
1633
|
for (const element of elements) {
|
|
1070
1634
|
switch (element.kind) {
|
|
1071
1635
|
case "field": {
|
|
1072
|
-
result.push(fieldNodeToControl(element, parentRule));
|
|
1636
|
+
result.push(fieldNodeToControl(element, fieldNameMap, parentRule));
|
|
1073
1637
|
break;
|
|
1074
1638
|
}
|
|
1075
1639
|
case "group": {
|
|
1076
|
-
result.push(groupNodeToLayout(element, parentRule));
|
|
1640
|
+
result.push(groupNodeToLayout(element, fieldNameMap, parentRule));
|
|
1077
1641
|
break;
|
|
1078
1642
|
}
|
|
1079
1643
|
case "conditional": {
|
|
1080
|
-
const newRule = createShowRule(element.fieldName, element.value);
|
|
1644
|
+
const newRule = createShowRule(fieldNameMap.get(element.fieldName) ?? element.fieldName, element.value);
|
|
1081
1645
|
const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
|
|
1082
|
-
const childElements = irElementsToUiSchema(element.elements, combinedRule);
|
|
1646
|
+
const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
|
|
1083
1647
|
result.push(...childElements);
|
|
1084
1648
|
break;
|
|
1085
1649
|
}
|
|
@@ -1093,22 +1657,50 @@ function irElementsToUiSchema(elements, parentRule) {
|
|
|
1093
1657
|
return result;
|
|
1094
1658
|
}
|
|
1095
1659
|
function generateUiSchemaFromIR(ir) {
|
|
1660
|
+
assertNoSerializedNameCollisions(ir);
|
|
1661
|
+
const fieldNameMap = collectFieldNameMap(ir.elements);
|
|
1096
1662
|
const result = {
|
|
1097
1663
|
type: "VerticalLayout",
|
|
1098
|
-
elements: irElementsToUiSchema(ir.elements)
|
|
1664
|
+
elements: irElementsToUiSchema(ir.elements, fieldNameMap)
|
|
1099
1665
|
};
|
|
1100
1666
|
return parseOrThrow(uiSchema, result, "UI Schema");
|
|
1101
1667
|
}
|
|
1668
|
+
function collectFieldNameMap(elements) {
|
|
1669
|
+
const map = /* @__PURE__ */ new Map();
|
|
1670
|
+
for (const element of elements) {
|
|
1671
|
+
switch (element.kind) {
|
|
1672
|
+
case "field":
|
|
1673
|
+
map.set(element.name, getSerializedName(element.name, element.metadata));
|
|
1674
|
+
break;
|
|
1675
|
+
case "group":
|
|
1676
|
+
case "conditional":
|
|
1677
|
+
for (const [key, value] of collectFieldNameMap(element.elements)) {
|
|
1678
|
+
map.set(key, value);
|
|
1679
|
+
}
|
|
1680
|
+
break;
|
|
1681
|
+
default: {
|
|
1682
|
+
const _exhaustive = element;
|
|
1683
|
+
void _exhaustive;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
return map;
|
|
1688
|
+
}
|
|
1102
1689
|
var init_ir_generator2 = __esm({
|
|
1103
1690
|
"src/ui-schema/ir-generator.ts"() {
|
|
1104
1691
|
"use strict";
|
|
1692
|
+
init_metadata();
|
|
1693
|
+
init_collision_guards();
|
|
1105
1694
|
init_schema();
|
|
1106
1695
|
}
|
|
1107
1696
|
});
|
|
1108
1697
|
|
|
1109
1698
|
// src/ui-schema/generator.ts
|
|
1110
|
-
function generateUiSchema(form) {
|
|
1111
|
-
const ir = canonicalizeChainDSL(
|
|
1699
|
+
function generateUiSchema(form, options) {
|
|
1700
|
+
const ir = canonicalizeChainDSL(
|
|
1701
|
+
form,
|
|
1702
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
1703
|
+
);
|
|
1112
1704
|
return generateUiSchemaFromIR(ir);
|
|
1113
1705
|
}
|
|
1114
1706
|
var init_generator2 = __esm({
|
|
@@ -2169,6 +2761,9 @@ var init_jsdoc_constraints = __esm({
|
|
|
2169
2761
|
|
|
2170
2762
|
// src/analyzer/class-analyzer.ts
|
|
2171
2763
|
import * as ts3 from "typescript";
|
|
2764
|
+
import {
|
|
2765
|
+
parseCommentBlock as parseCommentBlock2
|
|
2766
|
+
} from "@formspec/analysis/internal";
|
|
2172
2767
|
function isObjectType(type) {
|
|
2173
2768
|
return !!(type.flags & ts3.TypeFlags.Object);
|
|
2174
2769
|
}
|
|
@@ -2187,7 +2782,76 @@ function makeParseOptions(extensionRegistry, fieldType, checker, subjectType, ho
|
|
|
2187
2782
|
...hostType !== void 0 && { hostType }
|
|
2188
2783
|
};
|
|
2189
2784
|
}
|
|
2190
|
-
function
|
|
2785
|
+
function makeExplicitScalarMetadata(value) {
|
|
2786
|
+
return value === void 0 || value === "" ? void 0 : { value, source: "explicit" };
|
|
2787
|
+
}
|
|
2788
|
+
function extractExplicitMetadata(node) {
|
|
2789
|
+
let apiName;
|
|
2790
|
+
let displayName;
|
|
2791
|
+
let apiNamePlural;
|
|
2792
|
+
let displayNamePlural;
|
|
2793
|
+
for (const tag of getLeadingParsedTags(node)) {
|
|
2794
|
+
const value = tag.argumentText.trim();
|
|
2795
|
+
if (value === "") {
|
|
2796
|
+
continue;
|
|
2797
|
+
}
|
|
2798
|
+
if (tag.normalizedTagName === "apiName") {
|
|
2799
|
+
if (tag.target === null) {
|
|
2800
|
+
apiName ??= value;
|
|
2801
|
+
} else if (tag.target.kind === "variant") {
|
|
2802
|
+
if (tag.target.rawText === "singular") {
|
|
2803
|
+
apiName ??= value;
|
|
2804
|
+
} else if (tag.target.rawText === "plural") {
|
|
2805
|
+
apiNamePlural ??= value;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
if (tag.normalizedTagName === "displayName") {
|
|
2811
|
+
if (tag.target === null) {
|
|
2812
|
+
displayName ??= value;
|
|
2813
|
+
} else if (tag.target.kind === "variant") {
|
|
2814
|
+
if (tag.target.rawText === "singular") {
|
|
2815
|
+
displayName ??= value;
|
|
2816
|
+
} else if (tag.target.rawText === "plural") {
|
|
2817
|
+
displayNamePlural ??= value;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
const resolvedApiName = makeExplicitScalarMetadata(apiName);
|
|
2823
|
+
const resolvedDisplayName = makeExplicitScalarMetadata(displayName);
|
|
2824
|
+
const resolvedApiNamePlural = makeExplicitScalarMetadata(apiNamePlural);
|
|
2825
|
+
const resolvedDisplayNamePlural = makeExplicitScalarMetadata(displayNamePlural);
|
|
2826
|
+
const metadata = {
|
|
2827
|
+
...resolvedApiName !== void 0 && { apiName: resolvedApiName },
|
|
2828
|
+
...resolvedDisplayName !== void 0 && { displayName: resolvedDisplayName },
|
|
2829
|
+
...resolvedApiNamePlural !== void 0 && { apiNamePlural: resolvedApiNamePlural },
|
|
2830
|
+
...resolvedDisplayNamePlural !== void 0 && {
|
|
2831
|
+
displayNamePlural: resolvedDisplayNamePlural
|
|
2832
|
+
}
|
|
2833
|
+
};
|
|
2834
|
+
return Object.keys(metadata).length === 0 ? void 0 : metadata;
|
|
2835
|
+
}
|
|
2836
|
+
function resolveNodeMetadata(metadataPolicy, declarationKind, logicalName, node, buildContext) {
|
|
2837
|
+
const explicit = extractExplicitMetadata(node);
|
|
2838
|
+
return resolveMetadata(
|
|
2839
|
+
{
|
|
2840
|
+
...explicit?.apiName !== void 0 && { apiName: explicit.apiName.value },
|
|
2841
|
+
...explicit?.displayName !== void 0 && { displayName: explicit.displayName.value },
|
|
2842
|
+
...explicit?.apiNamePlural !== void 0 && {
|
|
2843
|
+
apiNamePlural: explicit.apiNamePlural.value
|
|
2844
|
+
},
|
|
2845
|
+
...explicit?.displayNamePlural !== void 0 && {
|
|
2846
|
+
displayNamePlural: explicit.displayNamePlural.value
|
|
2847
|
+
}
|
|
2848
|
+
},
|
|
2849
|
+
getDeclarationMetadataPolicy(metadataPolicy, declarationKind),
|
|
2850
|
+
makeMetadataContext("tsdoc", declarationKind, logicalName, buildContext)
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2854
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2191
2855
|
const name = classDecl.name?.text ?? "AnonymousClass";
|
|
2192
2856
|
const fields = [];
|
|
2193
2857
|
const fieldLayouts = [];
|
|
@@ -2214,6 +2878,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2214
2878
|
visiting,
|
|
2215
2879
|
diagnostics,
|
|
2216
2880
|
classType,
|
|
2881
|
+
normalizedMetadataPolicy,
|
|
2217
2882
|
extensionRegistry
|
|
2218
2883
|
);
|
|
2219
2884
|
if (fieldNode) {
|
|
@@ -2232,9 +2897,25 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2232
2897
|
}
|
|
2233
2898
|
}
|
|
2234
2899
|
}
|
|
2900
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2901
|
+
fields,
|
|
2902
|
+
classDecl,
|
|
2903
|
+
classType,
|
|
2904
|
+
checker,
|
|
2905
|
+
file,
|
|
2906
|
+
diagnostics,
|
|
2907
|
+
normalizedMetadataPolicy
|
|
2908
|
+
);
|
|
2909
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, classDecl, {
|
|
2910
|
+
checker,
|
|
2911
|
+
declaration: classDecl,
|
|
2912
|
+
subjectType: classType,
|
|
2913
|
+
hostType: classType
|
|
2914
|
+
});
|
|
2235
2915
|
return {
|
|
2236
2916
|
name,
|
|
2237
|
-
|
|
2917
|
+
...metadata !== void 0 && { metadata },
|
|
2918
|
+
fields: specializedFields,
|
|
2238
2919
|
fieldLayouts,
|
|
2239
2920
|
typeRegistry,
|
|
2240
2921
|
...annotations.length > 0 && { annotations },
|
|
@@ -2243,7 +2924,8 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
|
|
|
2243
2924
|
staticMethods
|
|
2244
2925
|
};
|
|
2245
2926
|
}
|
|
2246
|
-
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry) {
|
|
2927
|
+
function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2928
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2247
2929
|
const name = interfaceDecl.name.text;
|
|
2248
2930
|
const fields = [];
|
|
2249
2931
|
const typeRegistry = {};
|
|
@@ -2267,6 +2949,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2267
2949
|
visiting,
|
|
2268
2950
|
diagnostics,
|
|
2269
2951
|
interfaceType,
|
|
2952
|
+
normalizedMetadataPolicy,
|
|
2270
2953
|
extensionRegistry
|
|
2271
2954
|
);
|
|
2272
2955
|
if (fieldNode) {
|
|
@@ -2274,10 +2957,26 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2274
2957
|
}
|
|
2275
2958
|
}
|
|
2276
2959
|
}
|
|
2277
|
-
const
|
|
2960
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
2961
|
+
fields,
|
|
2962
|
+
interfaceDecl,
|
|
2963
|
+
interfaceType,
|
|
2964
|
+
checker,
|
|
2965
|
+
file,
|
|
2966
|
+
diagnostics,
|
|
2967
|
+
normalizedMetadataPolicy
|
|
2968
|
+
);
|
|
2969
|
+
const fieldLayouts = specializedFields.map(() => ({}));
|
|
2970
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, interfaceDecl, {
|
|
2971
|
+
checker,
|
|
2972
|
+
declaration: interfaceDecl,
|
|
2973
|
+
subjectType: interfaceType,
|
|
2974
|
+
hostType: interfaceType
|
|
2975
|
+
});
|
|
2278
2976
|
return {
|
|
2279
2977
|
name,
|
|
2280
|
-
|
|
2978
|
+
...metadata !== void 0 && { metadata },
|
|
2979
|
+
fields: specializedFields,
|
|
2281
2980
|
fieldLayouts,
|
|
2282
2981
|
typeRegistry,
|
|
2283
2982
|
...annotations.length > 0 && { annotations },
|
|
@@ -2286,7 +2985,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
|
|
|
2286
2985
|
staticMethods: []
|
|
2287
2986
|
};
|
|
2288
2987
|
}
|
|
2289
|
-
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
|
|
2988
|
+
function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry, metadataPolicy) {
|
|
2290
2989
|
if (!ts3.isTypeLiteralNode(typeAlias.type)) {
|
|
2291
2990
|
const sourceFile = typeAlias.getSourceFile();
|
|
2292
2991
|
const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
|
|
@@ -2296,6 +2995,8 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2296
2995
|
error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
|
|
2297
2996
|
};
|
|
2298
2997
|
}
|
|
2998
|
+
const typeLiteral = typeAlias.type;
|
|
2999
|
+
const normalizedMetadataPolicy = normalizeMetadataPolicy(metadataPolicy);
|
|
2299
3000
|
const name = typeAlias.name.text;
|
|
2300
3001
|
const fields = [];
|
|
2301
3002
|
const typeRegistry = {};
|
|
@@ -2309,7 +3010,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2309
3010
|
const annotations = [...typeAliasDoc.annotations];
|
|
2310
3011
|
diagnostics.push(...typeAliasDoc.diagnostics);
|
|
2311
3012
|
const visiting = /* @__PURE__ */ new Set();
|
|
2312
|
-
for (const member of
|
|
3013
|
+
for (const member of typeLiteral.members) {
|
|
2313
3014
|
if (ts3.isPropertySignature(member)) {
|
|
2314
3015
|
const fieldNode = analyzeInterfacePropertyToIR(
|
|
2315
3016
|
member,
|
|
@@ -2319,6 +3020,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2319
3020
|
visiting,
|
|
2320
3021
|
diagnostics,
|
|
2321
3022
|
aliasType,
|
|
3023
|
+
normalizedMetadataPolicy,
|
|
2322
3024
|
extensionRegistry
|
|
2323
3025
|
);
|
|
2324
3026
|
if (fieldNode) {
|
|
@@ -2326,12 +3028,28 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2326
3028
|
}
|
|
2327
3029
|
}
|
|
2328
3030
|
}
|
|
3031
|
+
const specializedFields = applyDeclarationDiscriminatorToFields(
|
|
3032
|
+
fields,
|
|
3033
|
+
typeAlias,
|
|
3034
|
+
aliasType,
|
|
3035
|
+
checker,
|
|
3036
|
+
file,
|
|
3037
|
+
diagnostics,
|
|
3038
|
+
normalizedMetadataPolicy
|
|
3039
|
+
);
|
|
3040
|
+
const metadata = resolveNodeMetadata(normalizedMetadataPolicy, "type", name, typeAlias, {
|
|
3041
|
+
checker,
|
|
3042
|
+
declaration: typeAlias,
|
|
3043
|
+
subjectType: aliasType,
|
|
3044
|
+
hostType: aliasType
|
|
3045
|
+
});
|
|
2329
3046
|
return {
|
|
2330
3047
|
ok: true,
|
|
2331
3048
|
analysis: {
|
|
2332
3049
|
name,
|
|
2333
|
-
|
|
2334
|
-
|
|
3050
|
+
...metadata !== void 0 && { metadata },
|
|
3051
|
+
fields: specializedFields,
|
|
3052
|
+
fieldLayouts: specializedFields.map(() => ({})),
|
|
2335
3053
|
typeRegistry,
|
|
2336
3054
|
...annotations.length > 0 && { annotations },
|
|
2337
3055
|
...diagnostics.length > 0 && { diagnostics },
|
|
@@ -2340,7 +3058,444 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
|
|
|
2340
3058
|
}
|
|
2341
3059
|
};
|
|
2342
3060
|
}
|
|
2343
|
-
function
|
|
3061
|
+
function makeAnalysisDiagnostic(code, message, primaryLocation, relatedLocations = []) {
|
|
3062
|
+
return {
|
|
3063
|
+
code,
|
|
3064
|
+
message,
|
|
3065
|
+
severity: "error",
|
|
3066
|
+
primaryLocation,
|
|
3067
|
+
relatedLocations
|
|
3068
|
+
};
|
|
3069
|
+
}
|
|
3070
|
+
function getLeadingParsedTags(node) {
|
|
3071
|
+
const sourceFile = node.getSourceFile();
|
|
3072
|
+
const sourceText = sourceFile.getFullText();
|
|
3073
|
+
const commentRanges = ts3.getLeadingCommentRanges(sourceText, node.getFullStart());
|
|
3074
|
+
if (commentRanges === void 0) {
|
|
3075
|
+
return [];
|
|
3076
|
+
}
|
|
3077
|
+
const parsedTags = [];
|
|
3078
|
+
for (const range of commentRanges) {
|
|
3079
|
+
if (range.kind !== ts3.SyntaxKind.MultiLineCommentTrivia) {
|
|
3080
|
+
continue;
|
|
3081
|
+
}
|
|
3082
|
+
const commentText = sourceText.slice(range.pos, range.end);
|
|
3083
|
+
if (!commentText.startsWith("/**")) {
|
|
3084
|
+
continue;
|
|
3085
|
+
}
|
|
3086
|
+
parsedTags.push(...parseCommentBlock2(commentText, { offset: range.pos }).tags);
|
|
3087
|
+
}
|
|
3088
|
+
return parsedTags;
|
|
3089
|
+
}
|
|
3090
|
+
function resolveDiscriminatorProperty(node, checker, fieldName) {
|
|
3091
|
+
const subjectType = checker.getTypeAtLocation(node);
|
|
3092
|
+
const propertySymbol = subjectType.getProperty(fieldName);
|
|
3093
|
+
if (propertySymbol === void 0) {
|
|
3094
|
+
return null;
|
|
3095
|
+
}
|
|
3096
|
+
const declaration = propertySymbol.valueDeclaration ?? propertySymbol.declarations?.find(
|
|
3097
|
+
(candidate) => ts3.isPropertyDeclaration(candidate) || ts3.isPropertySignature(candidate)
|
|
3098
|
+
) ?? propertySymbol.declarations?.[0];
|
|
3099
|
+
return {
|
|
3100
|
+
declaration,
|
|
3101
|
+
type: checker.getTypeOfSymbolAtLocation(propertySymbol, declaration ?? node),
|
|
3102
|
+
optional: !!(propertySymbol.flags & ts3.SymbolFlags.Optional) || declaration !== void 0 && "questionToken" in declaration && declaration.questionToken !== void 0
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
function isLocalTypeParameterName(node, typeParameterName) {
|
|
3106
|
+
return node.typeParameters?.some((typeParameter) => typeParameter.name.text === typeParameterName) ?? false;
|
|
3107
|
+
}
|
|
3108
|
+
function isNullishSemanticType(type) {
|
|
3109
|
+
if (type.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined | ts3.TypeFlags.Void | ts3.TypeFlags.Unknown | ts3.TypeFlags.Any)) {
|
|
3110
|
+
return true;
|
|
3111
|
+
}
|
|
3112
|
+
return type.isUnion() && type.types.some((member) => isNullishSemanticType(member));
|
|
3113
|
+
}
|
|
3114
|
+
function isStringLikeSemanticType(type) {
|
|
3115
|
+
if (type.flags & ts3.TypeFlags.StringLike) {
|
|
3116
|
+
return true;
|
|
3117
|
+
}
|
|
3118
|
+
if (type.isUnion()) {
|
|
3119
|
+
return type.types.length > 0 && type.types.every((member) => isStringLikeSemanticType(member));
|
|
3120
|
+
}
|
|
3121
|
+
return false;
|
|
3122
|
+
}
|
|
3123
|
+
function extractDiscriminatorDirective(node, file, diagnostics) {
|
|
3124
|
+
const discriminatorTags = getLeadingParsedTags(node).filter(
|
|
3125
|
+
(tag) => tag.normalizedTagName === "discriminator"
|
|
3126
|
+
);
|
|
3127
|
+
if (discriminatorTags.length === 0) {
|
|
3128
|
+
return null;
|
|
3129
|
+
}
|
|
3130
|
+
const [firstTag, ...duplicateTags] = discriminatorTags;
|
|
3131
|
+
for (const _duplicateTag of duplicateTags) {
|
|
3132
|
+
diagnostics.push(
|
|
3133
|
+
makeAnalysisDiagnostic(
|
|
3134
|
+
"DUPLICATE_TAG",
|
|
3135
|
+
'Duplicate "@discriminator" tag. Only one discriminator declaration is allowed per declaration.',
|
|
3136
|
+
provenanceForNode(node, file)
|
|
3137
|
+
)
|
|
3138
|
+
);
|
|
3139
|
+
}
|
|
3140
|
+
if (firstTag === void 0) {
|
|
3141
|
+
return null;
|
|
3142
|
+
}
|
|
3143
|
+
const firstTarget = firstTag.target;
|
|
3144
|
+
if (firstTarget?.path === null || firstTarget?.valid !== true) {
|
|
3145
|
+
diagnostics.push(
|
|
3146
|
+
makeAnalysisDiagnostic(
|
|
3147
|
+
"INVALID_TAG_ARGUMENT",
|
|
3148
|
+
'Tag "@discriminator" requires a direct path target like ":kind".',
|
|
3149
|
+
provenanceForNode(node, file)
|
|
3150
|
+
)
|
|
3151
|
+
);
|
|
3152
|
+
return null;
|
|
3153
|
+
}
|
|
3154
|
+
if (firstTarget.path.segments.length !== 1) {
|
|
3155
|
+
diagnostics.push(
|
|
3156
|
+
makeAnalysisDiagnostic(
|
|
3157
|
+
"INVALID_TAG_ARGUMENT",
|
|
3158
|
+
'Tag "@discriminator" only supports direct property targets in v1; nested paths are out of scope.',
|
|
3159
|
+
provenanceForNode(node, file)
|
|
3160
|
+
)
|
|
3161
|
+
);
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
3164
|
+
const typeParameterName = firstTag.argumentText.trim();
|
|
3165
|
+
if (!/^[A-Za-z_$][\w$]*$/u.test(typeParameterName)) {
|
|
3166
|
+
diagnostics.push(
|
|
3167
|
+
makeAnalysisDiagnostic(
|
|
3168
|
+
"INVALID_TAG_ARGUMENT",
|
|
3169
|
+
'Tag "@discriminator" requires a local type parameter name as its source operand.',
|
|
3170
|
+
provenanceForNode(node, file)
|
|
3171
|
+
)
|
|
3172
|
+
);
|
|
3173
|
+
return null;
|
|
3174
|
+
}
|
|
3175
|
+
return {
|
|
3176
|
+
fieldName: firstTarget.path.segments[0] ?? firstTarget.rawText,
|
|
3177
|
+
typeParameterName,
|
|
3178
|
+
provenance: provenanceForNode(node, file)
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
function validateDiscriminatorDirective(node, checker, file, diagnostics) {
|
|
3182
|
+
const directive = extractDiscriminatorDirective(node, file, diagnostics);
|
|
3183
|
+
if (directive === null) {
|
|
3184
|
+
return null;
|
|
3185
|
+
}
|
|
3186
|
+
if (!isLocalTypeParameterName(node, directive.typeParameterName)) {
|
|
3187
|
+
diagnostics.push(
|
|
3188
|
+
makeAnalysisDiagnostic(
|
|
3189
|
+
"INVALID_TAG_ARGUMENT",
|
|
3190
|
+
`Tag "@discriminator" references "${directive.typeParameterName}", but the source operand must be a type parameter declared on the same declaration.`,
|
|
3191
|
+
directive.provenance
|
|
3192
|
+
)
|
|
3193
|
+
);
|
|
3194
|
+
return null;
|
|
3195
|
+
}
|
|
3196
|
+
const property = resolveDiscriminatorProperty(node, checker, directive.fieldName);
|
|
3197
|
+
if (property === null) {
|
|
3198
|
+
diagnostics.push(
|
|
3199
|
+
makeAnalysisDiagnostic(
|
|
3200
|
+
"UNKNOWN_PATH_TARGET",
|
|
3201
|
+
`Tag "@discriminator" targets "${directive.fieldName}", but no direct property with that name exists on this declaration.`,
|
|
3202
|
+
directive.provenance
|
|
3203
|
+
)
|
|
3204
|
+
);
|
|
3205
|
+
return null;
|
|
3206
|
+
}
|
|
3207
|
+
if (property.optional) {
|
|
3208
|
+
diagnostics.push(
|
|
3209
|
+
makeAnalysisDiagnostic(
|
|
3210
|
+
"TYPE_MISMATCH",
|
|
3211
|
+
`Discriminator field "${directive.fieldName}" must be required; optional discriminator fields are not supported.`,
|
|
3212
|
+
directive.provenance,
|
|
3213
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3214
|
+
)
|
|
3215
|
+
);
|
|
3216
|
+
return null;
|
|
3217
|
+
}
|
|
3218
|
+
if (isNullishSemanticType(property.type)) {
|
|
3219
|
+
diagnostics.push(
|
|
3220
|
+
makeAnalysisDiagnostic(
|
|
3221
|
+
"TYPE_MISMATCH",
|
|
3222
|
+
`Discriminator field "${directive.fieldName}" must not be nullable.`,
|
|
3223
|
+
directive.provenance,
|
|
3224
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3225
|
+
)
|
|
3226
|
+
);
|
|
3227
|
+
return null;
|
|
3228
|
+
}
|
|
3229
|
+
if (!isStringLikeSemanticType(property.type)) {
|
|
3230
|
+
diagnostics.push(
|
|
3231
|
+
makeAnalysisDiagnostic(
|
|
3232
|
+
"TYPE_MISMATCH",
|
|
3233
|
+
`Discriminator field "${directive.fieldName}" must be string-like.`,
|
|
3234
|
+
directive.provenance,
|
|
3235
|
+
property.declaration !== void 0 ? [provenanceForNode(property.declaration, file)] : []
|
|
3236
|
+
)
|
|
3237
|
+
);
|
|
3238
|
+
return null;
|
|
3239
|
+
}
|
|
3240
|
+
return directive;
|
|
3241
|
+
}
|
|
3242
|
+
function getConcreteTypeArgumentForDiscriminator(node, subjectType, checker, typeParameterName) {
|
|
3243
|
+
const typeParameterIndex = node.typeParameters?.findIndex(
|
|
3244
|
+
(typeParameter) => typeParameter.name.text === typeParameterName
|
|
3245
|
+
) ?? -1;
|
|
3246
|
+
if (typeParameterIndex < 0) {
|
|
3247
|
+
return null;
|
|
3248
|
+
}
|
|
3249
|
+
const referenceTypeArguments = (isTypeReference(subjectType) ? subjectType.typeArguments : void 0) ?? subjectType.aliasTypeArguments;
|
|
3250
|
+
if (referenceTypeArguments?.[typeParameterIndex] !== void 0) {
|
|
3251
|
+
return referenceTypeArguments[typeParameterIndex] ?? null;
|
|
3252
|
+
}
|
|
3253
|
+
const localTypeParameter = node.typeParameters?.[typeParameterIndex];
|
|
3254
|
+
return localTypeParameter === void 0 ? null : checker.getTypeAtLocation(localTypeParameter);
|
|
3255
|
+
}
|
|
3256
|
+
function resolveLiteralDiscriminatorPropertyValue(boundType, fieldName, checker, provenance, diagnostics) {
|
|
3257
|
+
const propertySymbol = boundType.getProperty(fieldName);
|
|
3258
|
+
if (propertySymbol === void 0) {
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
const declaration = propertySymbol.valueDeclaration ?? propertySymbol.declarations?.[0];
|
|
3262
|
+
const anchorNode = declaration ?? boundType.symbol.declarations?.[0] ?? null;
|
|
3263
|
+
const resolvedAnchorNode = anchorNode ?? resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
3264
|
+
if (resolvedAnchorNode === null) {
|
|
3265
|
+
return void 0;
|
|
3266
|
+
}
|
|
3267
|
+
const propertyType = checker.getTypeOfSymbolAtLocation(
|
|
3268
|
+
propertySymbol,
|
|
3269
|
+
resolvedAnchorNode
|
|
3270
|
+
);
|
|
3271
|
+
if (propertyType.isStringLiteral()) {
|
|
3272
|
+
return propertyType.value;
|
|
3273
|
+
}
|
|
3274
|
+
if (propertyType.isUnion()) {
|
|
3275
|
+
const nonNullMembers = propertyType.types.filter(
|
|
3276
|
+
(member) => !(member.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
|
|
3277
|
+
);
|
|
3278
|
+
if (nonNullMembers.length > 0 && nonNullMembers.every((member) => member.isStringLiteral())) {
|
|
3279
|
+
diagnostics.push(
|
|
3280
|
+
makeAnalysisDiagnostic(
|
|
3281
|
+
"INVALID_TAG_ARGUMENT",
|
|
3282
|
+
"Discriminator resolution for union-valued identity properties is out of scope for v1.",
|
|
3283
|
+
provenance
|
|
3284
|
+
)
|
|
3285
|
+
);
|
|
3286
|
+
return null;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
return void 0;
|
|
3290
|
+
}
|
|
3291
|
+
function resolveDiscriminatorApiName(boundType, checker, metadataPolicy) {
|
|
3292
|
+
const declaration = resolveNamedDiscriminatorDeclaration(boundType, checker);
|
|
3293
|
+
if (declaration === null) {
|
|
3294
|
+
return void 0;
|
|
3295
|
+
}
|
|
3296
|
+
const metadata = resolveNodeMetadata(
|
|
3297
|
+
metadataPolicy,
|
|
3298
|
+
"type",
|
|
3299
|
+
getDiscriminatorLogicalName(boundType, declaration, checker),
|
|
3300
|
+
declaration,
|
|
3301
|
+
{
|
|
3302
|
+
checker,
|
|
3303
|
+
declaration,
|
|
3304
|
+
subjectType: boundType
|
|
3305
|
+
}
|
|
3306
|
+
);
|
|
3307
|
+
return metadata?.apiName;
|
|
3308
|
+
}
|
|
3309
|
+
function resolveNamedDiscriminatorDeclaration(type, checker, seen = /* @__PURE__ */ new Set()) {
|
|
3310
|
+
if (seen.has(type)) {
|
|
3311
|
+
return null;
|
|
3312
|
+
}
|
|
3313
|
+
seen.add(type);
|
|
3314
|
+
const symbol = type.aliasSymbol ?? type.getSymbol();
|
|
3315
|
+
if (symbol !== void 0) {
|
|
3316
|
+
const aliased = symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : void 0;
|
|
3317
|
+
const targetSymbol = aliased ?? symbol;
|
|
3318
|
+
const declaration = targetSymbol.declarations?.find(
|
|
3319
|
+
(candidate) => ts3.isClassDeclaration(candidate) || ts3.isInterfaceDeclaration(candidate) || ts3.isTypeAliasDeclaration(candidate) || ts3.isEnumDeclaration(candidate)
|
|
3320
|
+
);
|
|
3321
|
+
if (declaration !== void 0) {
|
|
3322
|
+
if (ts3.isTypeAliasDeclaration(declaration) && ts3.isTypeReferenceNode(declaration.type) && checker.getTypeFromTypeNode(declaration.type) !== type) {
|
|
3323
|
+
return resolveNamedDiscriminatorDeclaration(
|
|
3324
|
+
checker.getTypeFromTypeNode(declaration.type),
|
|
3325
|
+
checker,
|
|
3326
|
+
seen
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
return declaration;
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
return null;
|
|
3333
|
+
}
|
|
3334
|
+
function resolveDiscriminatorValue(boundType, fieldName, checker, provenance, diagnostics, metadataPolicy) {
|
|
3335
|
+
if (boundType === null) {
|
|
3336
|
+
diagnostics.push(
|
|
3337
|
+
makeAnalysisDiagnostic(
|
|
3338
|
+
"INVALID_TAG_ARGUMENT",
|
|
3339
|
+
"Discriminator resolution failed because no concrete type argument is available for the referenced type parameter.",
|
|
3340
|
+
provenance
|
|
3341
|
+
)
|
|
3342
|
+
);
|
|
3343
|
+
return null;
|
|
3344
|
+
}
|
|
3345
|
+
if (boundType.isStringLiteral()) {
|
|
3346
|
+
return boundType.value;
|
|
3347
|
+
}
|
|
3348
|
+
if (boundType.isUnion()) {
|
|
3349
|
+
const nonNullMembers = boundType.types.filter(
|
|
3350
|
+
(member) => !(member.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
|
|
3351
|
+
);
|
|
3352
|
+
if (nonNullMembers.every((member) => member.isStringLiteral())) {
|
|
3353
|
+
diagnostics.push(
|
|
3354
|
+
makeAnalysisDiagnostic(
|
|
3355
|
+
"INVALID_TAG_ARGUMENT",
|
|
3356
|
+
"Discriminator resolution for unions of string literals is out of scope for v1.",
|
|
3357
|
+
provenance
|
|
3358
|
+
)
|
|
3359
|
+
);
|
|
3360
|
+
return null;
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
const literalIdentityValue = resolveLiteralDiscriminatorPropertyValue(
|
|
3364
|
+
boundType,
|
|
3365
|
+
fieldName,
|
|
3366
|
+
checker,
|
|
3367
|
+
provenance,
|
|
3368
|
+
diagnostics
|
|
3369
|
+
);
|
|
3370
|
+
if (literalIdentityValue !== void 0) {
|
|
3371
|
+
return literalIdentityValue;
|
|
3372
|
+
}
|
|
3373
|
+
const apiName = resolveDiscriminatorApiName(boundType, checker, metadataPolicy);
|
|
3374
|
+
if (apiName?.source === "explicit") {
|
|
3375
|
+
return apiName.value;
|
|
3376
|
+
}
|
|
3377
|
+
if (apiName?.source === "inferred") {
|
|
3378
|
+
return apiName.value;
|
|
3379
|
+
}
|
|
3380
|
+
diagnostics.push(
|
|
3381
|
+
makeAnalysisDiagnostic(
|
|
3382
|
+
"INVALID_TAG_ARGUMENT",
|
|
3383
|
+
"Discriminator resolution could not derive a JSON-facing discriminator value from the referenced type argument.",
|
|
3384
|
+
provenance
|
|
3385
|
+
)
|
|
3386
|
+
);
|
|
3387
|
+
return null;
|
|
3388
|
+
}
|
|
3389
|
+
function getDeclarationName(node) {
|
|
3390
|
+
if (ts3.isClassDeclaration(node) || ts3.isInterfaceDeclaration(node) || ts3.isTypeAliasDeclaration(node) || ts3.isEnumDeclaration(node)) {
|
|
3391
|
+
return node.name?.text ?? "anonymous";
|
|
3392
|
+
}
|
|
3393
|
+
return "anonymous";
|
|
3394
|
+
}
|
|
3395
|
+
function getResolvedTypeArguments(type) {
|
|
3396
|
+
return (isTypeReference(type) ? type.typeArguments : void 0) ?? type.aliasTypeArguments ?? [];
|
|
3397
|
+
}
|
|
3398
|
+
function getDiscriminatorLogicalName(type, declaration, checker) {
|
|
3399
|
+
const baseName = getDeclarationName(declaration);
|
|
3400
|
+
const typeArguments = getResolvedTypeArguments(type);
|
|
3401
|
+
return typeArguments.length === 0 ? baseName : buildInstantiatedReferenceName(baseName, typeArguments, checker);
|
|
3402
|
+
}
|
|
3403
|
+
function applyDeclarationDiscriminatorToFields(fields, node, subjectType, checker, file, diagnostics, metadataPolicy) {
|
|
3404
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
3405
|
+
if (directive === null) {
|
|
3406
|
+
return [...fields];
|
|
3407
|
+
}
|
|
3408
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
3409
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
3410
|
+
node,
|
|
3411
|
+
subjectType,
|
|
3412
|
+
checker,
|
|
3413
|
+
directive.typeParameterName
|
|
3414
|
+
),
|
|
3415
|
+
directive.fieldName,
|
|
3416
|
+
checker,
|
|
3417
|
+
directive.provenance,
|
|
3418
|
+
diagnostics,
|
|
3419
|
+
metadataPolicy
|
|
3420
|
+
);
|
|
3421
|
+
if (discriminatorValue === null) {
|
|
3422
|
+
return [...fields];
|
|
3423
|
+
}
|
|
3424
|
+
return fields.map(
|
|
3425
|
+
(field) => field.name === directive.fieldName ? {
|
|
3426
|
+
...field,
|
|
3427
|
+
type: {
|
|
3428
|
+
kind: "enum",
|
|
3429
|
+
members: [{ value: discriminatorValue }]
|
|
3430
|
+
}
|
|
3431
|
+
} : field
|
|
3432
|
+
);
|
|
3433
|
+
}
|
|
3434
|
+
function buildInstantiatedReferenceName(baseName, typeArguments, checker) {
|
|
3435
|
+
const renderedArguments = typeArguments.map(
|
|
3436
|
+
(typeArgument) => checker.typeToString(typeArgument).replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "")
|
|
3437
|
+
).filter((value) => value !== "");
|
|
3438
|
+
return renderedArguments.length === 0 ? baseName : `${baseName}__${renderedArguments.join("__")}`;
|
|
3439
|
+
}
|
|
3440
|
+
function extractReferenceTypeArguments(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy, extensionRegistry, diagnostics) {
|
|
3441
|
+
const typeNode = sourceNode === void 0 ? void 0 : extractTypeNodeFromSource(sourceNode);
|
|
3442
|
+
if (typeNode === void 0) {
|
|
3443
|
+
return [];
|
|
3444
|
+
}
|
|
3445
|
+
const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
|
|
3446
|
+
if (!ts3.isTypeReferenceNode(resolvedTypeNode) || resolvedTypeNode.typeArguments === void 0) {
|
|
3447
|
+
return [];
|
|
3448
|
+
}
|
|
3449
|
+
return resolvedTypeNode.typeArguments.map((argumentNode) => {
|
|
3450
|
+
const argumentType = checker.getTypeFromTypeNode(argumentNode);
|
|
3451
|
+
return {
|
|
3452
|
+
tsType: argumentType,
|
|
3453
|
+
typeNode: resolveTypeNode(
|
|
3454
|
+
argumentType,
|
|
3455
|
+
checker,
|
|
3456
|
+
file,
|
|
3457
|
+
typeRegistry,
|
|
3458
|
+
visiting,
|
|
3459
|
+
argumentNode,
|
|
3460
|
+
metadataPolicy,
|
|
3461
|
+
extensionRegistry,
|
|
3462
|
+
diagnostics
|
|
3463
|
+
)
|
|
3464
|
+
};
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
function applyDiscriminatorToObjectProperties(properties, node, subjectType, checker, file, diagnostics, metadataPolicy) {
|
|
3468
|
+
const directive = validateDiscriminatorDirective(node, checker, file, diagnostics);
|
|
3469
|
+
if (directive === null) {
|
|
3470
|
+
return properties;
|
|
3471
|
+
}
|
|
3472
|
+
const discriminatorValue = resolveDiscriminatorValue(
|
|
3473
|
+
getConcreteTypeArgumentForDiscriminator(
|
|
3474
|
+
node,
|
|
3475
|
+
subjectType,
|
|
3476
|
+
checker,
|
|
3477
|
+
directive.typeParameterName
|
|
3478
|
+
),
|
|
3479
|
+
directive.fieldName,
|
|
3480
|
+
checker,
|
|
3481
|
+
directive.provenance,
|
|
3482
|
+
diagnostics,
|
|
3483
|
+
metadataPolicy
|
|
3484
|
+
);
|
|
3485
|
+
if (discriminatorValue === null) {
|
|
3486
|
+
return properties;
|
|
3487
|
+
}
|
|
3488
|
+
return properties.map(
|
|
3489
|
+
(property) => property.name === directive.fieldName ? {
|
|
3490
|
+
...property,
|
|
3491
|
+
type: {
|
|
3492
|
+
kind: "enum",
|
|
3493
|
+
members: [{ value: discriminatorValue }]
|
|
3494
|
+
}
|
|
3495
|
+
} : property
|
|
3496
|
+
);
|
|
3497
|
+
}
|
|
3498
|
+
function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, metadataPolicy, extensionRegistry) {
|
|
2344
3499
|
if (!ts3.isIdentifier(prop.name)) {
|
|
2345
3500
|
return null;
|
|
2346
3501
|
}
|
|
@@ -2355,6 +3510,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2355
3510
|
typeRegistry,
|
|
2356
3511
|
visiting,
|
|
2357
3512
|
prop,
|
|
3513
|
+
metadataPolicy,
|
|
2358
3514
|
extensionRegistry,
|
|
2359
3515
|
diagnostics
|
|
2360
3516
|
);
|
|
@@ -2378,9 +3534,16 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2378
3534
|
annotations.push(defaultAnnotation);
|
|
2379
3535
|
}
|
|
2380
3536
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
3537
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
|
|
3538
|
+
checker,
|
|
3539
|
+
declaration: prop,
|
|
3540
|
+
subjectType: tsType,
|
|
3541
|
+
hostType
|
|
3542
|
+
});
|
|
2381
3543
|
return {
|
|
2382
3544
|
kind: "field",
|
|
2383
3545
|
name,
|
|
3546
|
+
...metadata !== void 0 && { metadata },
|
|
2384
3547
|
type,
|
|
2385
3548
|
required: !optional,
|
|
2386
3549
|
constraints,
|
|
@@ -2388,7 +3551,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, diagnosti
|
|
|
2388
3551
|
provenance
|
|
2389
3552
|
};
|
|
2390
3553
|
}
|
|
2391
|
-
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, extensionRegistry) {
|
|
3554
|
+
function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, diagnostics, hostType, metadataPolicy, extensionRegistry) {
|
|
2392
3555
|
if (!ts3.isIdentifier(prop.name)) {
|
|
2393
3556
|
return null;
|
|
2394
3557
|
}
|
|
@@ -2403,6 +3566,7 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2403
3566
|
typeRegistry,
|
|
2404
3567
|
visiting,
|
|
2405
3568
|
prop,
|
|
3569
|
+
metadataPolicy,
|
|
2406
3570
|
extensionRegistry,
|
|
2407
3571
|
diagnostics
|
|
2408
3572
|
);
|
|
@@ -2422,9 +3586,16 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
2422
3586
|
let annotations = [];
|
|
2423
3587
|
annotations.push(...docResult.annotations);
|
|
2424
3588
|
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
3589
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "field", name, prop, {
|
|
3590
|
+
checker,
|
|
3591
|
+
declaration: prop,
|
|
3592
|
+
subjectType: tsType,
|
|
3593
|
+
hostType
|
|
3594
|
+
});
|
|
2425
3595
|
return {
|
|
2426
3596
|
kind: "field",
|
|
2427
3597
|
name,
|
|
3598
|
+
...metadata !== void 0 && { metadata },
|
|
2428
3599
|
type,
|
|
2429
3600
|
required: !optional,
|
|
2430
3601
|
constraints,
|
|
@@ -2549,7 +3720,7 @@ function getTypeNodeRegistrationName(typeNode) {
|
|
|
2549
3720
|
}
|
|
2550
3721
|
return null;
|
|
2551
3722
|
}
|
|
2552
|
-
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3723
|
+
function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2553
3724
|
const customType = resolveRegisteredCustomType(sourceNode, extensionRegistry, checker);
|
|
2554
3725
|
if (customType) {
|
|
2555
3726
|
return customType;
|
|
@@ -2561,6 +3732,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2561
3732
|
typeRegistry,
|
|
2562
3733
|
visiting,
|
|
2563
3734
|
sourceNode,
|
|
3735
|
+
metadataPolicy,
|
|
2564
3736
|
extensionRegistry,
|
|
2565
3737
|
diagnostics
|
|
2566
3738
|
);
|
|
@@ -2605,6 +3777,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2605
3777
|
typeRegistry,
|
|
2606
3778
|
visiting,
|
|
2607
3779
|
sourceNode,
|
|
3780
|
+
metadataPolicy,
|
|
2608
3781
|
extensionRegistry,
|
|
2609
3782
|
diagnostics
|
|
2610
3783
|
);
|
|
@@ -2617,6 +3790,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2617
3790
|
typeRegistry,
|
|
2618
3791
|
visiting,
|
|
2619
3792
|
sourceNode,
|
|
3793
|
+
metadataPolicy,
|
|
2620
3794
|
extensionRegistry,
|
|
2621
3795
|
diagnostics
|
|
2622
3796
|
);
|
|
@@ -2628,13 +3802,15 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
|
|
|
2628
3802
|
file,
|
|
2629
3803
|
typeRegistry,
|
|
2630
3804
|
visiting,
|
|
3805
|
+
sourceNode,
|
|
3806
|
+
metadataPolicy,
|
|
2631
3807
|
extensionRegistry,
|
|
2632
3808
|
diagnostics
|
|
2633
3809
|
);
|
|
2634
3810
|
}
|
|
2635
3811
|
return { kind: "primitive", primitiveKind: "string" };
|
|
2636
3812
|
}
|
|
2637
|
-
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3813
|
+
function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2638
3814
|
if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
|
|
2639
3815
|
return null;
|
|
2640
3816
|
}
|
|
@@ -2654,14 +3830,21 @@ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiti
|
|
|
2654
3830
|
file,
|
|
2655
3831
|
makeParseOptions(extensionRegistry)
|
|
2656
3832
|
);
|
|
3833
|
+
const metadata = resolveNodeMetadata(metadataPolicy, "type", aliasName, aliasDecl, {
|
|
3834
|
+
checker,
|
|
3835
|
+
declaration: aliasDecl,
|
|
3836
|
+
subjectType: aliasType
|
|
3837
|
+
});
|
|
2657
3838
|
typeRegistry[aliasName] = {
|
|
2658
3839
|
name: aliasName,
|
|
3840
|
+
...metadata !== void 0 && { metadata },
|
|
2659
3841
|
type: resolveAliasedPrimitiveTarget(
|
|
2660
3842
|
aliasType,
|
|
2661
3843
|
checker,
|
|
2662
3844
|
file,
|
|
2663
3845
|
typeRegistry,
|
|
2664
3846
|
visiting,
|
|
3847
|
+
metadataPolicy,
|
|
2665
3848
|
extensionRegistry,
|
|
2666
3849
|
diagnostics
|
|
2667
3850
|
),
|
|
@@ -2690,7 +3873,7 @@ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
|
|
|
2690
3873
|
const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
|
|
2691
3874
|
return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
|
|
2692
3875
|
}
|
|
2693
|
-
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, extensionRegistry, diagnostics) {
|
|
3876
|
+
function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2694
3877
|
const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
|
|
2695
3878
|
if (nestedAliasDecl !== void 0) {
|
|
2696
3879
|
return resolveAliasedPrimitiveTarget(
|
|
@@ -2699,6 +3882,7 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
2699
3882
|
file,
|
|
2700
3883
|
typeRegistry,
|
|
2701
3884
|
visiting,
|
|
3885
|
+
metadataPolicy,
|
|
2702
3886
|
extensionRegistry,
|
|
2703
3887
|
diagnostics
|
|
2704
3888
|
);
|
|
@@ -2710,11 +3894,12 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
|
|
|
2710
3894
|
typeRegistry,
|
|
2711
3895
|
visiting,
|
|
2712
3896
|
void 0,
|
|
3897
|
+
metadataPolicy,
|
|
2713
3898
|
extensionRegistry,
|
|
2714
3899
|
diagnostics
|
|
2715
3900
|
);
|
|
2716
3901
|
}
|
|
2717
|
-
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
3902
|
+
function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2718
3903
|
const typeName = getNamedTypeName(type);
|
|
2719
3904
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2720
3905
|
if (typeName && typeName in typeRegistry) {
|
|
@@ -2749,8 +3934,14 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2749
3934
|
return result;
|
|
2750
3935
|
}
|
|
2751
3936
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
3937
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", typeName, namedDecl, {
|
|
3938
|
+
checker,
|
|
3939
|
+
declaration: namedDecl,
|
|
3940
|
+
subjectType: type
|
|
3941
|
+
}) : void 0;
|
|
2752
3942
|
typeRegistry[typeName] = {
|
|
2753
3943
|
name: typeName,
|
|
3944
|
+
...metadata !== void 0 && { metadata },
|
|
2754
3945
|
type: result,
|
|
2755
3946
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2756
3947
|
provenance: provenanceForDeclaration(namedDecl ?? sourceNode, file)
|
|
@@ -2804,6 +3995,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2804
3995
|
typeRegistry,
|
|
2805
3996
|
visiting,
|
|
2806
3997
|
nonNullMembers[0].sourceNode ?? sourceNode,
|
|
3998
|
+
metadataPolicy,
|
|
2807
3999
|
extensionRegistry,
|
|
2808
4000
|
diagnostics
|
|
2809
4001
|
);
|
|
@@ -2821,6 +4013,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2821
4013
|
typeRegistry,
|
|
2822
4014
|
visiting,
|
|
2823
4015
|
memberSourceNode ?? sourceNode,
|
|
4016
|
+
metadataPolicy,
|
|
2824
4017
|
extensionRegistry,
|
|
2825
4018
|
diagnostics
|
|
2826
4019
|
)
|
|
@@ -2830,7 +4023,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2830
4023
|
}
|
|
2831
4024
|
return registerNamed({ kind: "union", members });
|
|
2832
4025
|
}
|
|
2833
|
-
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry, diagnostics) {
|
|
4026
|
+
function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2834
4027
|
const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
|
|
2835
4028
|
const elementType = typeArgs?.[0];
|
|
2836
4029
|
const elementSourceNode = extractArrayElementTypeNode(sourceNode, checker);
|
|
@@ -2841,12 +4034,13 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting, sourceNod
|
|
|
2841
4034
|
typeRegistry,
|
|
2842
4035
|
visiting,
|
|
2843
4036
|
elementSourceNode,
|
|
4037
|
+
metadataPolicy,
|
|
2844
4038
|
extensionRegistry,
|
|
2845
4039
|
diagnostics
|
|
2846
4040
|
) : { kind: "primitive", primitiveKind: "string" };
|
|
2847
4041
|
return { kind: "array", items };
|
|
2848
4042
|
}
|
|
2849
|
-
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, extensionRegistry, diagnostics) {
|
|
4043
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
2850
4044
|
if (type.getProperties().length > 0) {
|
|
2851
4045
|
return null;
|
|
2852
4046
|
}
|
|
@@ -2861,6 +4055,7 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, exten
|
|
|
2861
4055
|
typeRegistry,
|
|
2862
4056
|
visiting,
|
|
2863
4057
|
void 0,
|
|
4058
|
+
metadataPolicy,
|
|
2864
4059
|
extensionRegistry,
|
|
2865
4060
|
diagnostics
|
|
2866
4061
|
);
|
|
@@ -2891,35 +4086,76 @@ function typeNodeContainsReference(type, targetName) {
|
|
|
2891
4086
|
}
|
|
2892
4087
|
}
|
|
2893
4088
|
}
|
|
2894
|
-
function
|
|
4089
|
+
function shouldEmitResolvedObjectProperty(property, declaration) {
|
|
4090
|
+
if (property.name.startsWith("__@")) {
|
|
4091
|
+
return false;
|
|
4092
|
+
}
|
|
4093
|
+
if (declaration !== void 0 && "name" in declaration && declaration.name !== void 0) {
|
|
4094
|
+
const name = declaration.name;
|
|
4095
|
+
if (ts3.isComputedPropertyName(name) || ts3.isPrivateIdentifier(name)) {
|
|
4096
|
+
return false;
|
|
4097
|
+
}
|
|
4098
|
+
if (!ts3.isIdentifier(name) && !ts3.isStringLiteral(name) && !ts3.isNumericLiteral(name)) {
|
|
4099
|
+
return false;
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
return true;
|
|
4103
|
+
}
|
|
4104
|
+
function resolveObjectType(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = normalizeMetadataPolicy(void 0), extensionRegistry, diagnostics) {
|
|
4105
|
+
const collectedDiagnostics = diagnostics ?? [];
|
|
2895
4106
|
const typeName = getNamedTypeName(type);
|
|
2896
4107
|
const namedTypeName = typeName ?? void 0;
|
|
2897
4108
|
const namedDecl = getNamedTypeDeclaration(type);
|
|
2898
|
-
const
|
|
4109
|
+
const referenceTypeArguments = extractReferenceTypeArguments(
|
|
4110
|
+
type,
|
|
4111
|
+
checker,
|
|
4112
|
+
file,
|
|
4113
|
+
typeRegistry,
|
|
4114
|
+
visiting,
|
|
4115
|
+
sourceNode,
|
|
4116
|
+
metadataPolicy,
|
|
4117
|
+
extensionRegistry,
|
|
4118
|
+
collectedDiagnostics
|
|
4119
|
+
);
|
|
4120
|
+
const instantiatedTypeName = namedTypeName !== void 0 && referenceTypeArguments.length > 0 ? buildInstantiatedReferenceName(
|
|
4121
|
+
namedTypeName,
|
|
4122
|
+
referenceTypeArguments.map((argument) => argument.tsType),
|
|
4123
|
+
checker
|
|
4124
|
+
) : void 0;
|
|
4125
|
+
const registryTypeName = instantiatedTypeName ?? namedTypeName;
|
|
4126
|
+
const shouldRegisterNamedType = registryTypeName !== void 0 && !(registryTypeName === "Record" && namedDecl?.getSourceFile().fileName !== file);
|
|
2899
4127
|
const clearNamedTypeRegistration = () => {
|
|
2900
|
-
if (
|
|
4128
|
+
if (registryTypeName === void 0 || !shouldRegisterNamedType) {
|
|
2901
4129
|
return;
|
|
2902
4130
|
}
|
|
2903
|
-
Reflect.deleteProperty(typeRegistry,
|
|
4131
|
+
Reflect.deleteProperty(typeRegistry, registryTypeName);
|
|
2904
4132
|
};
|
|
2905
4133
|
if (visiting.has(type)) {
|
|
2906
|
-
if (
|
|
2907
|
-
return {
|
|
4134
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
4135
|
+
return {
|
|
4136
|
+
kind: "reference",
|
|
4137
|
+
name: registryTypeName,
|
|
4138
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4139
|
+
};
|
|
2908
4140
|
}
|
|
2909
4141
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
2910
4142
|
}
|
|
2911
|
-
if (
|
|
2912
|
-
typeRegistry[
|
|
2913
|
-
name:
|
|
4143
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && !typeRegistry[registryTypeName]) {
|
|
4144
|
+
typeRegistry[registryTypeName] = {
|
|
4145
|
+
name: registryTypeName,
|
|
2914
4146
|
type: RESOLVING_TYPE_PLACEHOLDER,
|
|
2915
4147
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2916
4148
|
};
|
|
2917
4149
|
}
|
|
2918
4150
|
visiting.add(type);
|
|
2919
|
-
if (
|
|
2920
|
-
if (typeRegistry[
|
|
4151
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType && typeRegistry[registryTypeName]?.type !== void 0) {
|
|
4152
|
+
if (typeRegistry[registryTypeName].type !== RESOLVING_TYPE_PLACEHOLDER) {
|
|
2921
4153
|
visiting.delete(type);
|
|
2922
|
-
return {
|
|
4154
|
+
return {
|
|
4155
|
+
kind: "reference",
|
|
4156
|
+
name: registryTypeName,
|
|
4157
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4158
|
+
};
|
|
2923
4159
|
}
|
|
2924
4160
|
}
|
|
2925
4161
|
const recordNode = tryResolveRecordType(
|
|
@@ -2928,25 +4164,36 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2928
4164
|
file,
|
|
2929
4165
|
typeRegistry,
|
|
2930
4166
|
visiting,
|
|
4167
|
+
metadataPolicy,
|
|
2931
4168
|
extensionRegistry,
|
|
2932
|
-
|
|
4169
|
+
collectedDiagnostics
|
|
2933
4170
|
);
|
|
2934
4171
|
if (recordNode) {
|
|
2935
4172
|
visiting.delete(type);
|
|
2936
|
-
if (
|
|
2937
|
-
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType,
|
|
4173
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
4174
|
+
const isRecursiveRecord = typeNodeContainsReference(recordNode.valueType, registryTypeName);
|
|
2938
4175
|
if (!isRecursiveRecord) {
|
|
2939
4176
|
clearNamedTypeRegistration();
|
|
2940
4177
|
return recordNode;
|
|
2941
4178
|
}
|
|
2942
4179
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2943
|
-
|
|
2944
|
-
|
|
4180
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
|
|
4181
|
+
checker,
|
|
4182
|
+
declaration: namedDecl,
|
|
4183
|
+
subjectType: type
|
|
4184
|
+
}) : void 0;
|
|
4185
|
+
typeRegistry[registryTypeName] = {
|
|
4186
|
+
name: registryTypeName,
|
|
4187
|
+
...metadata !== void 0 && { metadata },
|
|
2945
4188
|
type: recordNode,
|
|
2946
4189
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
2947
4190
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
2948
4191
|
};
|
|
2949
|
-
return {
|
|
4192
|
+
return {
|
|
4193
|
+
kind: "reference",
|
|
4194
|
+
name: registryTypeName,
|
|
4195
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4196
|
+
};
|
|
2950
4197
|
}
|
|
2951
4198
|
return recordNode;
|
|
2952
4199
|
}
|
|
@@ -2957,12 +4204,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2957
4204
|
file,
|
|
2958
4205
|
typeRegistry,
|
|
2959
4206
|
visiting,
|
|
2960
|
-
|
|
4207
|
+
metadataPolicy,
|
|
4208
|
+
collectedDiagnostics,
|
|
2961
4209
|
extensionRegistry
|
|
2962
4210
|
);
|
|
2963
4211
|
for (const prop of type.getProperties()) {
|
|
2964
4212
|
const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
2965
4213
|
if (!declaration) continue;
|
|
4214
|
+
if (!shouldEmitResolvedObjectProperty(prop, declaration)) continue;
|
|
2966
4215
|
const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
|
|
2967
4216
|
const optional = !!(prop.flags & ts3.SymbolFlags.Optional);
|
|
2968
4217
|
const propTypeNode = resolveTypeNode(
|
|
@@ -2972,12 +4221,14 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2972
4221
|
typeRegistry,
|
|
2973
4222
|
visiting,
|
|
2974
4223
|
declaration,
|
|
4224
|
+
metadataPolicy,
|
|
2975
4225
|
extensionRegistry,
|
|
2976
|
-
|
|
4226
|
+
collectedDiagnostics
|
|
2977
4227
|
);
|
|
2978
4228
|
const fieldNodeInfo = fieldInfoMap?.get(prop.name);
|
|
2979
4229
|
properties.push({
|
|
2980
4230
|
name: prop.name,
|
|
4231
|
+
...fieldNodeInfo?.metadata !== void 0 && { metadata: fieldNodeInfo.metadata },
|
|
2981
4232
|
type: propTypeNode,
|
|
2982
4233
|
optional,
|
|
2983
4234
|
constraints: fieldNodeInfo?.constraints ?? [],
|
|
@@ -2988,22 +4239,40 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
|
|
|
2988
4239
|
visiting.delete(type);
|
|
2989
4240
|
const objectNode = {
|
|
2990
4241
|
kind: "object",
|
|
2991
|
-
properties
|
|
4242
|
+
properties: namedDecl !== void 0 && (ts3.isClassDeclaration(namedDecl) || ts3.isInterfaceDeclaration(namedDecl) || ts3.isTypeAliasDeclaration(namedDecl)) ? applyDiscriminatorToObjectProperties(
|
|
4243
|
+
properties,
|
|
4244
|
+
namedDecl,
|
|
4245
|
+
type,
|
|
4246
|
+
checker,
|
|
4247
|
+
file,
|
|
4248
|
+
collectedDiagnostics,
|
|
4249
|
+
metadataPolicy
|
|
4250
|
+
) : properties,
|
|
2992
4251
|
additionalProperties: true
|
|
2993
4252
|
};
|
|
2994
|
-
if (
|
|
4253
|
+
if (registryTypeName !== void 0 && shouldRegisterNamedType) {
|
|
2995
4254
|
const annotations = namedDecl ? extractJSDocAnnotationNodes(namedDecl, file, makeParseOptions(extensionRegistry)) : void 0;
|
|
2996
|
-
|
|
2997
|
-
|
|
4255
|
+
const metadata = namedDecl !== void 0 ? resolveNodeMetadata(metadataPolicy, "type", registryTypeName, namedDecl, {
|
|
4256
|
+
checker,
|
|
4257
|
+
declaration: namedDecl,
|
|
4258
|
+
subjectType: type
|
|
4259
|
+
}) : void 0;
|
|
4260
|
+
typeRegistry[registryTypeName] = {
|
|
4261
|
+
name: registryTypeName,
|
|
4262
|
+
...metadata !== void 0 && { metadata },
|
|
2998
4263
|
type: objectNode,
|
|
2999
4264
|
...annotations !== void 0 && annotations.length > 0 && { annotations },
|
|
3000
4265
|
provenance: provenanceForDeclaration(namedDecl, file)
|
|
3001
4266
|
};
|
|
3002
|
-
return {
|
|
4267
|
+
return {
|
|
4268
|
+
kind: "reference",
|
|
4269
|
+
name: registryTypeName,
|
|
4270
|
+
typeArguments: referenceTypeArguments.map((argument) => argument.typeNode)
|
|
4271
|
+
};
|
|
3003
4272
|
}
|
|
3004
4273
|
return objectNode;
|
|
3005
4274
|
}
|
|
3006
|
-
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting, diagnostics, extensionRegistry) {
|
|
4275
|
+
function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting, metadataPolicy, diagnostics, extensionRegistry) {
|
|
3007
4276
|
const symbols = [type.getSymbol(), type.aliasSymbol].filter(
|
|
3008
4277
|
(s) => s?.declarations != null && s.declarations.length > 0
|
|
3009
4278
|
);
|
|
@@ -3024,10 +4293,12 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3024
4293
|
visiting,
|
|
3025
4294
|
diagnostics,
|
|
3026
4295
|
hostType,
|
|
4296
|
+
metadataPolicy,
|
|
3027
4297
|
extensionRegistry
|
|
3028
4298
|
);
|
|
3029
4299
|
if (fieldNode) {
|
|
3030
4300
|
map.set(fieldNode.name, {
|
|
4301
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
3031
4302
|
constraints: [...fieldNode.constraints],
|
|
3032
4303
|
annotations: [...fieldNode.annotations],
|
|
3033
4304
|
provenance: fieldNode.provenance
|
|
@@ -3045,6 +4316,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3045
4316
|
file,
|
|
3046
4317
|
typeRegistry,
|
|
3047
4318
|
visiting,
|
|
4319
|
+
metadataPolicy,
|
|
3048
4320
|
checker.getTypeAtLocation(interfaceDecl),
|
|
3049
4321
|
diagnostics,
|
|
3050
4322
|
extensionRegistry
|
|
@@ -3058,6 +4330,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
|
|
|
3058
4330
|
file,
|
|
3059
4331
|
typeRegistry,
|
|
3060
4332
|
visiting,
|
|
4333
|
+
metadataPolicy,
|
|
3061
4334
|
checker.getTypeAtLocation(typeAliasDecl),
|
|
3062
4335
|
diagnostics,
|
|
3063
4336
|
extensionRegistry
|
|
@@ -3109,7 +4382,7 @@ function isNullishTypeNode(typeNode) {
|
|
|
3109
4382
|
}
|
|
3110
4383
|
return ts3.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts3.SyntaxKind.NullKeyword || typeNode.literal.kind === ts3.SyntaxKind.UndefinedKeyword);
|
|
3111
4384
|
}
|
|
3112
|
-
function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, hostType, diagnostics, extensionRegistry) {
|
|
4385
|
+
function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, metadataPolicy, hostType, diagnostics, extensionRegistry) {
|
|
3113
4386
|
const map = /* @__PURE__ */ new Map();
|
|
3114
4387
|
for (const member of members) {
|
|
3115
4388
|
if (ts3.isPropertySignature(member)) {
|
|
@@ -3121,10 +4394,12 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, h
|
|
|
3121
4394
|
visiting,
|
|
3122
4395
|
diagnostics,
|
|
3123
4396
|
hostType,
|
|
4397
|
+
metadataPolicy,
|
|
3124
4398
|
extensionRegistry
|
|
3125
4399
|
);
|
|
3126
4400
|
if (fieldNode) {
|
|
3127
4401
|
map.set(fieldNode.name, {
|
|
4402
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
3128
4403
|
constraints: [...fieldNode.constraints],
|
|
3129
4404
|
annotations: [...fieldNode.annotations],
|
|
3130
4405
|
provenance: fieldNode.provenance
|
|
@@ -3154,6 +4429,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
|
|
|
3154
4429
|
{},
|
|
3155
4430
|
/* @__PURE__ */ new Set(),
|
|
3156
4431
|
aliasDecl.type,
|
|
4432
|
+
void 0,
|
|
3157
4433
|
extensionRegistry
|
|
3158
4434
|
);
|
|
3159
4435
|
const constraints = extractJSDocConstraintNodes(
|
|
@@ -3263,6 +4539,7 @@ var init_class_analyzer = __esm({
|
|
|
3263
4539
|
"use strict";
|
|
3264
4540
|
init_jsdoc_constraints();
|
|
3265
4541
|
init_tsdoc_parser();
|
|
4542
|
+
init_metadata();
|
|
3266
4543
|
RESOLVING_TYPE_PLACEHOLDER = {
|
|
3267
4544
|
kind: "object",
|
|
3268
4545
|
properties: [],
|
|
@@ -3355,19 +4632,37 @@ function findInterfaceByName(sourceFile, interfaceName) {
|
|
|
3355
4632
|
function findTypeAliasByName(sourceFile, aliasName) {
|
|
3356
4633
|
return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
|
|
3357
4634
|
}
|
|
3358
|
-
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry) {
|
|
4635
|
+
function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry, metadataPolicy) {
|
|
3359
4636
|
const ctx = createProgramContext(filePath);
|
|
3360
|
-
return analyzeNamedTypeToIRFromProgramContext(
|
|
4637
|
+
return analyzeNamedTypeToIRFromProgramContext(
|
|
4638
|
+
ctx,
|
|
4639
|
+
filePath,
|
|
4640
|
+
typeName,
|
|
4641
|
+
extensionRegistry,
|
|
4642
|
+
metadataPolicy
|
|
4643
|
+
);
|
|
3361
4644
|
}
|
|
3362
|
-
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry) {
|
|
4645
|
+
function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensionRegistry, metadataPolicy) {
|
|
3363
4646
|
const analysisFilePath = path.resolve(filePath);
|
|
3364
4647
|
const classDecl = findClassByName(ctx.sourceFile, typeName);
|
|
3365
4648
|
if (classDecl !== null) {
|
|
3366
|
-
return analyzeClassToIR(
|
|
4649
|
+
return analyzeClassToIR(
|
|
4650
|
+
classDecl,
|
|
4651
|
+
ctx.checker,
|
|
4652
|
+
analysisFilePath,
|
|
4653
|
+
extensionRegistry,
|
|
4654
|
+
metadataPolicy
|
|
4655
|
+
);
|
|
3367
4656
|
}
|
|
3368
4657
|
const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
|
|
3369
4658
|
if (interfaceDecl !== null) {
|
|
3370
|
-
return analyzeInterfaceToIR(
|
|
4659
|
+
return analyzeInterfaceToIR(
|
|
4660
|
+
interfaceDecl,
|
|
4661
|
+
ctx.checker,
|
|
4662
|
+
analysisFilePath,
|
|
4663
|
+
extensionRegistry,
|
|
4664
|
+
metadataPolicy
|
|
4665
|
+
);
|
|
3371
4666
|
}
|
|
3372
4667
|
const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
|
|
3373
4668
|
if (typeAlias !== null) {
|
|
@@ -3375,7 +4670,8 @@ function analyzeNamedTypeToIRFromProgramContext(ctx, filePath, typeName, extensi
|
|
|
3375
4670
|
typeAlias,
|
|
3376
4671
|
ctx.checker,
|
|
3377
4672
|
analysisFilePath,
|
|
3378
|
-
extensionRegistry
|
|
4673
|
+
extensionRegistry,
|
|
4674
|
+
metadataPolicy
|
|
3379
4675
|
);
|
|
3380
4676
|
if (result.ok) {
|
|
3381
4677
|
return result.analysis;
|
|
@@ -3490,7 +4786,11 @@ function generateClassSchemas(analysis, source, options) {
|
|
|
3490
4786
|
if (errorDiagnostics !== void 0 && errorDiagnostics.length > 0) {
|
|
3491
4787
|
throw new Error(formatValidationError(errorDiagnostics));
|
|
3492
4788
|
}
|
|
3493
|
-
const ir = canonicalizeTSDoc(
|
|
4789
|
+
const ir = canonicalizeTSDoc(
|
|
4790
|
+
analysis,
|
|
4791
|
+
source,
|
|
4792
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
4793
|
+
);
|
|
3494
4794
|
const validationResult = validateIR(ir, {
|
|
3495
4795
|
...options?.extensionRegistry !== void 0 && {
|
|
3496
4796
|
extensionRegistry: options.extensionRegistry
|
|
@@ -3527,13 +4827,15 @@ function generateSchemasFromClass(options) {
|
|
|
3527
4827
|
classDecl,
|
|
3528
4828
|
ctx.checker,
|
|
3529
4829
|
options.filePath,
|
|
3530
|
-
options.extensionRegistry
|
|
4830
|
+
options.extensionRegistry,
|
|
4831
|
+
options.metadata
|
|
3531
4832
|
);
|
|
3532
4833
|
return generateClassSchemas(
|
|
3533
4834
|
analysis,
|
|
3534
4835
|
{ file: options.filePath },
|
|
3535
4836
|
{
|
|
3536
4837
|
extensionRegistry: options.extensionRegistry,
|
|
4838
|
+
metadata: options.metadata,
|
|
3537
4839
|
vendorPrefix: options.vendorPrefix
|
|
3538
4840
|
}
|
|
3539
4841
|
);
|
|
@@ -3551,13 +4853,15 @@ function generateSchemasFromProgram(options) {
|
|
|
3551
4853
|
ctx,
|
|
3552
4854
|
options.filePath,
|
|
3553
4855
|
options.typeName,
|
|
3554
|
-
options.extensionRegistry
|
|
4856
|
+
options.extensionRegistry,
|
|
4857
|
+
options.metadata
|
|
3555
4858
|
);
|
|
3556
4859
|
return generateClassSchemas(
|
|
3557
4860
|
analysis,
|
|
3558
4861
|
{ file: options.filePath },
|
|
3559
4862
|
{
|
|
3560
4863
|
extensionRegistry: options.extensionRegistry,
|
|
4864
|
+
metadata: options.metadata,
|
|
3561
4865
|
vendorPrefix: options.vendorPrefix
|
|
3562
4866
|
}
|
|
3563
4867
|
);
|
|
@@ -3577,16 +4881,28 @@ var init_class_schema = __esm({
|
|
|
3577
4881
|
// src/generators/mixed-authoring.ts
|
|
3578
4882
|
function buildMixedAuthoringSchemas(options) {
|
|
3579
4883
|
const { filePath, typeName, overlays, ...schemaOptions } = options;
|
|
3580
|
-
const analysis = analyzeNamedTypeToIR(
|
|
3581
|
-
|
|
3582
|
-
|
|
4884
|
+
const analysis = analyzeNamedTypeToIR(
|
|
4885
|
+
filePath,
|
|
4886
|
+
typeName,
|
|
4887
|
+
schemaOptions.extensionRegistry,
|
|
4888
|
+
schemaOptions.metadata
|
|
4889
|
+
);
|
|
4890
|
+
const composedAnalysis = composeAnalysisWithOverlays(analysis, overlays, schemaOptions.metadata);
|
|
4891
|
+
const ir = canonicalizeTSDoc(
|
|
4892
|
+
composedAnalysis,
|
|
4893
|
+
{ file: filePath },
|
|
4894
|
+
schemaOptions.metadata !== void 0 ? { metadata: schemaOptions.metadata } : void 0
|
|
4895
|
+
);
|
|
3583
4896
|
return {
|
|
3584
4897
|
jsonSchema: generateJsonSchemaFromIR(ir, schemaOptions),
|
|
3585
4898
|
uiSchema: generateUiSchemaFromIR(ir)
|
|
3586
4899
|
};
|
|
3587
4900
|
}
|
|
3588
|
-
function composeAnalysisWithOverlays(analysis, overlays) {
|
|
3589
|
-
const overlayIR = canonicalizeChainDSL(
|
|
4901
|
+
function composeAnalysisWithOverlays(analysis, overlays, metadata) {
|
|
4902
|
+
const overlayIR = canonicalizeChainDSL(
|
|
4903
|
+
overlays,
|
|
4904
|
+
metadata !== void 0 ? { metadata } : void 0
|
|
4905
|
+
);
|
|
3590
4906
|
const overlayFields = collectOverlayFields(overlayIR.elements);
|
|
3591
4907
|
if (overlayFields.length === 0) {
|
|
3592
4908
|
return analysis;
|
|
@@ -3642,8 +4958,10 @@ function collectOverlayFields(elements) {
|
|
|
3642
4958
|
}
|
|
3643
4959
|
function mergeFieldOverlay(baseField, overlayField, typeRegistry) {
|
|
3644
4960
|
assertSupportedOverlayField(baseField, overlayField);
|
|
4961
|
+
const metadata = mergeResolvedMetadata(baseField.metadata, overlayField.metadata);
|
|
3645
4962
|
return {
|
|
3646
4963
|
...baseField,
|
|
4964
|
+
...metadata !== void 0 && { metadata },
|
|
3647
4965
|
type: mergeFieldType(baseField, overlayField, typeRegistry),
|
|
3648
4966
|
annotations: mergeAnnotations(baseField.annotations, overlayField.annotations)
|
|
3649
4967
|
};
|
|
@@ -3756,6 +5074,7 @@ var init_mixed_authoring = __esm({
|
|
|
3756
5074
|
init_ir_generator2();
|
|
3757
5075
|
init_canonicalize();
|
|
3758
5076
|
init_program();
|
|
5077
|
+
init_metadata();
|
|
3759
5078
|
}
|
|
3760
5079
|
});
|
|
3761
5080
|
|
|
@@ -3779,12 +5098,12 @@ import * as path2 from "path";
|
|
|
3779
5098
|
function buildFormSchemas(form, options) {
|
|
3780
5099
|
return {
|
|
3781
5100
|
jsonSchema: generateJsonSchema(form, options),
|
|
3782
|
-
uiSchema: generateUiSchema(form)
|
|
5101
|
+
uiSchema: generateUiSchema(form, options)
|
|
3783
5102
|
};
|
|
3784
5103
|
}
|
|
3785
5104
|
function writeSchemas(form, options) {
|
|
3786
|
-
const { outDir, name = "schema", indent = 2, vendorPrefix } = options;
|
|
3787
|
-
const buildOptions = vendorPrefix === void 0 ? void 0 : { vendorPrefix };
|
|
5105
|
+
const { outDir, name = "schema", indent = 2, vendorPrefix, metadata } = options;
|
|
5106
|
+
const buildOptions = vendorPrefix === void 0 && metadata === void 0 ? void 0 : { vendorPrefix, metadata };
|
|
3788
5107
|
const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form, buildOptions);
|
|
3789
5108
|
if (!fs.existsSync(outDir)) {
|
|
3790
5109
|
fs.mkdirSync(outDir, { recursive: true });
|