@formspec/build 0.1.0-alpha.4 → 0.1.0-alpha.41
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 +238 -93
- package/dist/analyzer/class-analyzer.d.ts +135 -0
- package/dist/analyzer/class-analyzer.d.ts.map +1 -0
- package/dist/analyzer/jsdoc-constraints.d.ts +53 -0
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -0
- package/dist/analyzer/program.d.ts +94 -0
- package/dist/analyzer/program.d.ts.map +1 -0
- package/dist/analyzer/tsdoc-parser.d.ts +126 -0
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -0
- package/dist/browser.cjs +2113 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.ts +74 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +2070 -0
- package/dist/browser.js.map +1 -0
- package/dist/build-alpha.d.ts +1501 -0
- package/dist/build-beta.d.ts +1501 -0
- package/dist/build-internal.d.ts +1501 -0
- package/dist/build.d.ts +1194 -43
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts +22 -0
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -0
- package/dist/canonicalize/index.d.ts +8 -0
- package/dist/canonicalize/index.d.ts.map +1 -0
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +38 -0
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -0
- package/dist/cli.cjs +6715 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +6687 -103
- package/dist/cli.js.map +1 -1
- package/dist/extensions/index.d.ts +8 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/registry.d.ts +83 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/generators/class-schema.d.ts +347 -0
- package/dist/generators/class-schema.d.ts.map +1 -0
- package/dist/generators/discovered-schema.d.ts +152 -0
- package/dist/generators/discovered-schema.d.ts.map +1 -0
- package/dist/generators/method-schema.d.ts +72 -0
- package/dist/generators/method-schema.d.ts.map +1 -0
- package/dist/generators/mixed-authoring.d.ts +52 -0
- package/dist/generators/mixed-authoring.d.ts.map +1 -0
- package/dist/index.cjs +6412 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +50 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6387 -107
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +5573 -0
- package/dist/internals.cjs.map +1 -0
- package/dist/internals.d.ts +32 -0
- package/dist/internals.d.ts.map +1 -0
- package/dist/internals.js +5554 -0
- package/dist/internals.js.map +1 -0
- package/dist/json-schema/generator.d.ts +32 -6
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts +149 -0
- package/dist/json-schema/ir-generator.d.ts.map +1 -0
- package/dist/json-schema/schema.d.ts +23 -0
- package/dist/json-schema/schema.d.ts.map +1 -0
- package/dist/json-schema/types.d.ts +76 -2
- package/dist/json-schema/types.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 +12 -0
- package/dist/metadata/policy.d.ts.map +1 -0
- package/dist/metadata/resolve.d.ts +21 -0
- package/dist/metadata/resolve.d.ts.map +1 -0
- package/dist/static-build.d.ts +61 -0
- package/dist/static-build.d.ts.map +1 -0
- package/dist/ui-schema/generator.d.ts +18 -2
- package/dist/ui-schema/generator.d.ts.map +1 -1
- package/dist/ui-schema/ir-generator.d.ts +54 -0
- package/dist/ui-schema/ir-generator.d.ts.map +1 -0
- package/dist/ui-schema/schema.d.ts +429 -0
- package/dist/ui-schema/schema.d.ts.map +1 -0
- package/dist/ui-schema/types.d.ts +179 -35
- package/dist/ui-schema/types.d.ts.map +1 -1
- package/dist/validate/constraint-validator.d.ts +85 -0
- package/dist/validate/constraint-validator.d.ts.map +1 -0
- package/dist/validate/index.d.ts +9 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/package.json +31 -11
- package/dist/__tests__/cli.test.d.ts +0 -2
- package/dist/__tests__/cli.test.d.ts.map +0 -1
- package/dist/__tests__/cli.test.js +0 -178
- package/dist/__tests__/cli.test.js.map +0 -1
- package/dist/__tests__/edge-cases.test.d.ts +0 -7
- package/dist/__tests__/edge-cases.test.d.ts.map +0 -1
- package/dist/__tests__/edge-cases.test.js +0 -217
- package/dist/__tests__/edge-cases.test.js.map +0 -1
- package/dist/__tests__/generator.test.d.ts +0 -2
- package/dist/__tests__/generator.test.d.ts.map +0 -1
- package/dist/__tests__/generator.test.js +0 -225
- package/dist/__tests__/generator.test.js.map +0 -1
- package/dist/__tests__/integration.test.d.ts +0 -8
- package/dist/__tests__/integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration.test.js +0 -163
- package/dist/__tests__/integration.test.js.map +0 -1
- package/dist/__tests__/write-schemas.test.d.ts +0 -2
- package/dist/__tests__/write-schemas.test.d.ts.map +0 -1
- package/dist/__tests__/write-schemas.test.js +0 -196
- package/dist/__tests__/write-schemas.test.js.map +0 -1
- package/dist/json-schema/generator.js +0 -161
- package/dist/json-schema/generator.js.map +0 -1
- package/dist/json-schema/types.js +0 -7
- package/dist/json-schema/types.js.map +0 -1
- package/dist/ui-schema/generator.js +0 -150
- package/dist/ui-schema/generator.js.map +0 -1
- package/dist/ui-schema/types.js +0 -8
- package/dist/ui-schema/types.js.map +0 -1
package/dist/browser.cjs
ADDED
|
@@ -0,0 +1,2113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/browser.ts
|
|
21
|
+
var browser_exports = {};
|
|
22
|
+
__export(browser_exports, {
|
|
23
|
+
buildFormSchemas: () => buildFormSchemas,
|
|
24
|
+
canonicalizeChainDSL: () => canonicalizeChainDSL,
|
|
25
|
+
categorizationSchema: () => categorizationSchema,
|
|
26
|
+
categorySchema: () => categorySchema,
|
|
27
|
+
controlSchema: () => controlSchema,
|
|
28
|
+
createExtensionRegistry: () => createExtensionRegistry,
|
|
29
|
+
generateJsonSchema: () => generateJsonSchema,
|
|
30
|
+
generateJsonSchemaFromIR: () => generateJsonSchemaFromIR,
|
|
31
|
+
generateUiSchema: () => generateUiSchema,
|
|
32
|
+
getSchemaExtension: () => getSchemaExtension,
|
|
33
|
+
groupLayoutSchema: () => groupLayoutSchema,
|
|
34
|
+
horizontalLayoutSchema: () => horizontalLayoutSchema,
|
|
35
|
+
jsonSchema7Schema: () => jsonSchema7Schema,
|
|
36
|
+
jsonSchemaTypeSchema: () => jsonSchemaTypeSchema,
|
|
37
|
+
labelElementSchema: () => labelElementSchema,
|
|
38
|
+
ruleConditionSchema: () => ruleConditionSchema,
|
|
39
|
+
ruleEffectSchema: () => ruleEffectSchema,
|
|
40
|
+
ruleSchema: () => ruleSchema,
|
|
41
|
+
schemaBasedConditionSchema: () => schemaBasedConditionSchema,
|
|
42
|
+
setSchemaExtension: () => setSchemaExtension,
|
|
43
|
+
uiSchemaElementSchema: () => uiSchemaElementSchema,
|
|
44
|
+
uiSchemaElementTypeSchema: () => uiSchemaElementTypeSchema,
|
|
45
|
+
uiSchemaSchema: () => uiSchema,
|
|
46
|
+
validateIR: () => validateIR,
|
|
47
|
+
verticalLayoutSchema: () => verticalLayoutSchema
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(browser_exports);
|
|
50
|
+
|
|
51
|
+
// src/canonicalize/chain-dsl-canonicalizer.ts
|
|
52
|
+
var import_internals = require("@formspec/core/internals");
|
|
53
|
+
|
|
54
|
+
// src/metadata/policy.ts
|
|
55
|
+
var NOOP_INFLECT = () => "";
|
|
56
|
+
function normalizePluralization(input) {
|
|
57
|
+
if (input?.mode === "infer-if-missing") {
|
|
58
|
+
return {
|
|
59
|
+
mode: "infer-if-missing",
|
|
60
|
+
infer: () => "",
|
|
61
|
+
inflect: input.inflect
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (input?.mode === "require-explicit") {
|
|
65
|
+
return {
|
|
66
|
+
mode: "require-explicit",
|
|
67
|
+
infer: () => "",
|
|
68
|
+
inflect: NOOP_INFLECT
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
mode: "disabled",
|
|
73
|
+
infer: () => "",
|
|
74
|
+
inflect: NOOP_INFLECT
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function normalizeScalarPolicy(input) {
|
|
78
|
+
if (input?.mode === "infer-if-missing") {
|
|
79
|
+
return {
|
|
80
|
+
mode: "infer-if-missing",
|
|
81
|
+
infer: input.infer,
|
|
82
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (input?.mode === "require-explicit") {
|
|
86
|
+
return {
|
|
87
|
+
mode: "require-explicit",
|
|
88
|
+
infer: () => "",
|
|
89
|
+
pluralization: normalizePluralization(input.pluralization)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
mode: "disabled",
|
|
94
|
+
infer: () => "",
|
|
95
|
+
pluralization: normalizePluralization(input?.pluralization)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function normalizeDeclarationPolicy(input) {
|
|
99
|
+
return {
|
|
100
|
+
apiName: normalizeScalarPolicy(input?.apiName),
|
|
101
|
+
displayName: normalizeScalarPolicy(input?.displayName)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function normalizeEnumMemberDisplayNamePolicy(input) {
|
|
105
|
+
if (input?.mode === "infer-if-missing") {
|
|
106
|
+
return {
|
|
107
|
+
mode: "infer-if-missing",
|
|
108
|
+
infer: input.infer
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (input?.mode === "require-explicit") {
|
|
112
|
+
return {
|
|
113
|
+
mode: "require-explicit",
|
|
114
|
+
infer: () => ""
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
mode: "disabled",
|
|
119
|
+
infer: () => ""
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function normalizeEnumMemberPolicy(input) {
|
|
123
|
+
return {
|
|
124
|
+
displayName: normalizeEnumMemberDisplayNamePolicy(input?.displayName)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function normalizeMetadataPolicy(input) {
|
|
128
|
+
return {
|
|
129
|
+
type: normalizeDeclarationPolicy(input?.type),
|
|
130
|
+
field: normalizeDeclarationPolicy(input?.field),
|
|
131
|
+
method: normalizeDeclarationPolicy(input?.method),
|
|
132
|
+
enumMember: normalizeEnumMemberPolicy(input?.enumMember)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function getDeclarationMetadataPolicy(policy, declarationKind) {
|
|
136
|
+
return policy[declarationKind];
|
|
137
|
+
}
|
|
138
|
+
function makeMetadataContext(surface, declarationKind, logicalName, buildContext) {
|
|
139
|
+
return {
|
|
140
|
+
surface,
|
|
141
|
+
declarationKind,
|
|
142
|
+
logicalName,
|
|
143
|
+
...buildContext !== void 0 && { buildContext }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/metadata/resolve.ts
|
|
148
|
+
function toExplicitScalar(value) {
|
|
149
|
+
return value !== void 0 && value.trim() !== "" ? { value, source: "explicit" } : void 0;
|
|
150
|
+
}
|
|
151
|
+
function toExplicitResolvedMetadata(explicit) {
|
|
152
|
+
if (explicit === void 0) {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
const apiName = toExplicitScalar(explicit.apiName);
|
|
156
|
+
const displayName = toExplicitScalar(explicit.displayName);
|
|
157
|
+
const apiNamePlural = toExplicitScalar(explicit.apiNamePlural);
|
|
158
|
+
const displayNamePlural = toExplicitScalar(explicit.displayNamePlural);
|
|
159
|
+
const metadata = {
|
|
160
|
+
...apiName !== void 0 && { apiName },
|
|
161
|
+
...displayName !== void 0 && { displayName },
|
|
162
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
163
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
164
|
+
};
|
|
165
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
166
|
+
}
|
|
167
|
+
function resolveScalar(current, policy, context, metadataLabel) {
|
|
168
|
+
if (current !== void 0) {
|
|
169
|
+
return current;
|
|
170
|
+
}
|
|
171
|
+
if (policy.mode === "require-explicit") {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
if (policy.mode !== "infer-if-missing") {
|
|
177
|
+
return void 0;
|
|
178
|
+
}
|
|
179
|
+
const inferredValue = policy.infer(context);
|
|
180
|
+
return inferredValue.trim() !== "" ? { value: inferredValue, source: "inferred" } : void 0;
|
|
181
|
+
}
|
|
182
|
+
function resolvePlural(current, singular, policy, context, metadataLabel) {
|
|
183
|
+
if (current !== void 0) {
|
|
184
|
+
return current;
|
|
185
|
+
}
|
|
186
|
+
if (policy.mode === "require-explicit") {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} "${context.logicalName}" on the ${context.surface} surface.`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (singular === void 0 || policy.mode !== "infer-if-missing") {
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
const pluralValue = policy.inflect({ ...context, singular: singular.value });
|
|
195
|
+
return pluralValue.trim() !== "" ? { value: pluralValue, source: "inferred" } : void 0;
|
|
196
|
+
}
|
|
197
|
+
function resolveResolvedMetadata(current, policy, context) {
|
|
198
|
+
const apiName = resolveScalar(current?.apiName, policy.apiName, context, "apiName");
|
|
199
|
+
const displayName = resolveScalar(
|
|
200
|
+
current?.displayName,
|
|
201
|
+
policy.displayName,
|
|
202
|
+
context,
|
|
203
|
+
"displayName"
|
|
204
|
+
);
|
|
205
|
+
const apiNamePlural = resolvePlural(
|
|
206
|
+
current?.apiNamePlural,
|
|
207
|
+
apiName,
|
|
208
|
+
policy.apiName.pluralization,
|
|
209
|
+
context,
|
|
210
|
+
"apiNamePlural"
|
|
211
|
+
);
|
|
212
|
+
const displayNamePlural = resolvePlural(
|
|
213
|
+
current?.displayNamePlural,
|
|
214
|
+
displayName,
|
|
215
|
+
policy.displayName.pluralization,
|
|
216
|
+
context,
|
|
217
|
+
"displayNamePlural"
|
|
218
|
+
);
|
|
219
|
+
if (apiName === void 0 && displayName === void 0 && apiNamePlural === void 0 && displayNamePlural === void 0) {
|
|
220
|
+
return void 0;
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
...apiName !== void 0 && { apiName },
|
|
224
|
+
...displayName !== void 0 && { displayName },
|
|
225
|
+
...apiNamePlural !== void 0 && { apiNamePlural },
|
|
226
|
+
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function resolveEnumMemberDisplayName(current, policy, context) {
|
|
230
|
+
if (current !== void 0) {
|
|
231
|
+
return current;
|
|
232
|
+
}
|
|
233
|
+
if (policy.mode === "require-explicit") {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`Metadata policy requires explicit displayName for enum member "${context.logicalName}" on the ${context.surface} surface.`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
if (policy.mode !== "infer-if-missing") {
|
|
239
|
+
return void 0;
|
|
240
|
+
}
|
|
241
|
+
const inferredValue = policy.infer(context).trim();
|
|
242
|
+
return inferredValue !== "" ? inferredValue : void 0;
|
|
243
|
+
}
|
|
244
|
+
function resolveEnumTypeMetadata(type, options) {
|
|
245
|
+
const members = type.members.map((member) => {
|
|
246
|
+
const displayName = resolveEnumMemberDisplayName(
|
|
247
|
+
member.displayName,
|
|
248
|
+
options.policy.enumMember.displayName,
|
|
249
|
+
{
|
|
250
|
+
surface: options.surface,
|
|
251
|
+
logicalName: String(member.value),
|
|
252
|
+
memberValue: member.value,
|
|
253
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
if (displayName === member.displayName) {
|
|
257
|
+
return member;
|
|
258
|
+
}
|
|
259
|
+
return displayName === void 0 ? { value: member.value } : { value: member.value, displayName };
|
|
260
|
+
});
|
|
261
|
+
return members.some((member, index) => member !== type.members[index]) ? { ...type, members } : type;
|
|
262
|
+
}
|
|
263
|
+
function resolveTypeNodeMetadata(type, options) {
|
|
264
|
+
switch (type.kind) {
|
|
265
|
+
case "array":
|
|
266
|
+
return {
|
|
267
|
+
...type,
|
|
268
|
+
items: resolveTypeNodeMetadata(type.items, options)
|
|
269
|
+
};
|
|
270
|
+
case "object":
|
|
271
|
+
return {
|
|
272
|
+
...type,
|
|
273
|
+
properties: type.properties.map((property) => resolveObjectPropertyMetadata(property, options))
|
|
274
|
+
};
|
|
275
|
+
case "record":
|
|
276
|
+
return {
|
|
277
|
+
...type,
|
|
278
|
+
valueType: resolveTypeNodeMetadata(type.valueType, options)
|
|
279
|
+
};
|
|
280
|
+
case "union":
|
|
281
|
+
return {
|
|
282
|
+
...type,
|
|
283
|
+
members: type.members.map((member) => resolveTypeNodeMetadata(member, options))
|
|
284
|
+
};
|
|
285
|
+
case "enum":
|
|
286
|
+
return resolveEnumTypeMetadata(type, options);
|
|
287
|
+
case "reference":
|
|
288
|
+
case "primitive":
|
|
289
|
+
case "dynamic":
|
|
290
|
+
case "custom":
|
|
291
|
+
return type;
|
|
292
|
+
default: {
|
|
293
|
+
const _exhaustive = type;
|
|
294
|
+
return _exhaustive;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function resolveObjectPropertyMetadata(property, options) {
|
|
299
|
+
const metadata = resolveResolvedMetadata(property.metadata, options.policy.field, {
|
|
300
|
+
surface: options.surface,
|
|
301
|
+
declarationKind: "field",
|
|
302
|
+
logicalName: property.name,
|
|
303
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
304
|
+
});
|
|
305
|
+
return {
|
|
306
|
+
...property,
|
|
307
|
+
...metadata !== void 0 && { metadata },
|
|
308
|
+
type: resolveTypeNodeMetadata(property.type, options)
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function resolveFieldMetadataNode(field, options) {
|
|
312
|
+
const metadata = resolveResolvedMetadata(field.metadata, options.policy.field, {
|
|
313
|
+
surface: options.surface,
|
|
314
|
+
declarationKind: "field",
|
|
315
|
+
logicalName: field.name,
|
|
316
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
317
|
+
});
|
|
318
|
+
return {
|
|
319
|
+
...field,
|
|
320
|
+
...metadata !== void 0 && { metadata },
|
|
321
|
+
type: resolveTypeNodeMetadata(field.type, options)
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function resolveFormElementMetadata(element, options) {
|
|
325
|
+
switch (element.kind) {
|
|
326
|
+
case "field":
|
|
327
|
+
return resolveFieldMetadataNode(element, options);
|
|
328
|
+
case "group":
|
|
329
|
+
return {
|
|
330
|
+
...element,
|
|
331
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
332
|
+
};
|
|
333
|
+
case "conditional":
|
|
334
|
+
return {
|
|
335
|
+
...element,
|
|
336
|
+
elements: element.elements.map((child) => resolveFormElementMetadata(child, options))
|
|
337
|
+
};
|
|
338
|
+
default: {
|
|
339
|
+
const _exhaustive = element;
|
|
340
|
+
return _exhaustive;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function resolveTypeDefinitionMetadata(typeDefinition, options) {
|
|
345
|
+
const metadata = resolveResolvedMetadata(typeDefinition.metadata, options.policy.type, {
|
|
346
|
+
surface: options.surface,
|
|
347
|
+
declarationKind: "type",
|
|
348
|
+
logicalName: typeDefinition.name,
|
|
349
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
350
|
+
});
|
|
351
|
+
return {
|
|
352
|
+
...typeDefinition,
|
|
353
|
+
...metadata !== void 0 && { metadata },
|
|
354
|
+
type: resolveTypeNodeMetadata(typeDefinition.type, options)
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function resolveMetadata(explicit, policy, context) {
|
|
358
|
+
return resolveResolvedMetadata(toExplicitResolvedMetadata(explicit), policy, context);
|
|
359
|
+
}
|
|
360
|
+
function getSerializedName(logicalName, metadata) {
|
|
361
|
+
return metadata?.apiName?.value ?? logicalName;
|
|
362
|
+
}
|
|
363
|
+
function getDisplayName(metadata) {
|
|
364
|
+
return metadata?.displayName?.value;
|
|
365
|
+
}
|
|
366
|
+
function resolveFormIRMetadata(ir, options) {
|
|
367
|
+
const metadata = options.resolveRootTypeMetadata === false ? ir.metadata : resolveResolvedMetadata(ir.metadata, options.policy.type, {
|
|
368
|
+
surface: options.surface,
|
|
369
|
+
declarationKind: "type",
|
|
370
|
+
logicalName: options.rootLogicalName ?? ir.name ?? "FormSpec",
|
|
371
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
372
|
+
});
|
|
373
|
+
return {
|
|
374
|
+
...ir,
|
|
375
|
+
...metadata !== void 0 && { metadata },
|
|
376
|
+
elements: ir.elements.map((element) => resolveFormElementMetadata(element, options)),
|
|
377
|
+
typeRegistry: Object.fromEntries(
|
|
378
|
+
Object.entries(ir.typeRegistry).map(([name, definition]) => [
|
|
379
|
+
name,
|
|
380
|
+
resolveTypeDefinitionMetadata(definition, options)
|
|
381
|
+
])
|
|
382
|
+
)
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/canonicalize/chain-dsl-canonicalizer.ts
|
|
387
|
+
var CHAIN_DSL_PROVENANCE = {
|
|
388
|
+
surface: "chain-dsl",
|
|
389
|
+
file: "",
|
|
390
|
+
line: 0,
|
|
391
|
+
column: 0
|
|
392
|
+
};
|
|
393
|
+
function isGroup(el) {
|
|
394
|
+
return el._type === "group";
|
|
395
|
+
}
|
|
396
|
+
function isConditional(el) {
|
|
397
|
+
return el._type === "conditional";
|
|
398
|
+
}
|
|
399
|
+
function isField(el) {
|
|
400
|
+
return el._type === "field";
|
|
401
|
+
}
|
|
402
|
+
function canonicalizeChainDSL(form, options) {
|
|
403
|
+
const metadataPolicy = normalizeMetadataPolicy(
|
|
404
|
+
options?.metadata ?? (0, import_internals._getFormSpecMetadataPolicy)(form)
|
|
405
|
+
);
|
|
406
|
+
const ir = {
|
|
407
|
+
kind: "form-ir",
|
|
408
|
+
irVersion: import_internals.IR_VERSION,
|
|
409
|
+
elements: canonicalizeElements(form.elements, metadataPolicy),
|
|
410
|
+
rootAnnotations: [],
|
|
411
|
+
typeRegistry: {},
|
|
412
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
413
|
+
};
|
|
414
|
+
return resolveFormIRMetadata(ir, {
|
|
415
|
+
policy: metadataPolicy,
|
|
416
|
+
surface: "chain-dsl",
|
|
417
|
+
// Chain DSL has no root/type-metadata authoring surface, so only resolve
|
|
418
|
+
// field/type-registry metadata and enum-member labels here.
|
|
419
|
+
resolveRootTypeMetadata: false
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
function canonicalizeElements(elements, metadataPolicy) {
|
|
423
|
+
return elements.map((element) => canonicalizeElement(element, metadataPolicy));
|
|
424
|
+
}
|
|
425
|
+
function canonicalizeElement(element, metadataPolicy) {
|
|
426
|
+
if (isField(element)) {
|
|
427
|
+
return canonicalizeField(element, metadataPolicy);
|
|
428
|
+
}
|
|
429
|
+
if (isGroup(element)) {
|
|
430
|
+
return canonicalizeGroup(element, metadataPolicy);
|
|
431
|
+
}
|
|
432
|
+
if (isConditional(element)) {
|
|
433
|
+
return canonicalizeConditional(element, metadataPolicy);
|
|
434
|
+
}
|
|
435
|
+
const _exhaustive = element;
|
|
436
|
+
throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);
|
|
437
|
+
}
|
|
438
|
+
function canonicalizeField(field, metadataPolicy) {
|
|
439
|
+
switch (field._field) {
|
|
440
|
+
case "text":
|
|
441
|
+
return canonicalizeTextField(field, metadataPolicy);
|
|
442
|
+
case "number":
|
|
443
|
+
return canonicalizeNumberField(field, metadataPolicy);
|
|
444
|
+
case "boolean":
|
|
445
|
+
return canonicalizeBooleanField(field, metadataPolicy);
|
|
446
|
+
case "enum":
|
|
447
|
+
return canonicalizeStaticEnumField(field, metadataPolicy);
|
|
448
|
+
case "dynamic_enum":
|
|
449
|
+
return canonicalizeDynamicEnumField(field, metadataPolicy);
|
|
450
|
+
case "dynamic_schema":
|
|
451
|
+
return canonicalizeDynamicSchemaField(field, metadataPolicy);
|
|
452
|
+
case "array":
|
|
453
|
+
return canonicalizeArrayField(field, metadataPolicy);
|
|
454
|
+
case "object":
|
|
455
|
+
return canonicalizeObjectField(field, metadataPolicy);
|
|
456
|
+
default: {
|
|
457
|
+
const _exhaustive = field;
|
|
458
|
+
throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function canonicalizeTextField(field, metadataPolicy) {
|
|
463
|
+
const type = { kind: "primitive", primitiveKind: "string" };
|
|
464
|
+
const constraints = [];
|
|
465
|
+
if (field.minLength !== void 0) {
|
|
466
|
+
const c = {
|
|
467
|
+
kind: "constraint",
|
|
468
|
+
constraintKind: "minLength",
|
|
469
|
+
value: field.minLength,
|
|
470
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
471
|
+
};
|
|
472
|
+
constraints.push(c);
|
|
473
|
+
}
|
|
474
|
+
if (field.maxLength !== void 0) {
|
|
475
|
+
const c = {
|
|
476
|
+
kind: "constraint",
|
|
477
|
+
constraintKind: "maxLength",
|
|
478
|
+
value: field.maxLength,
|
|
479
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
480
|
+
};
|
|
481
|
+
constraints.push(c);
|
|
482
|
+
}
|
|
483
|
+
if (field.pattern !== void 0) {
|
|
484
|
+
const c = {
|
|
485
|
+
kind: "constraint",
|
|
486
|
+
constraintKind: "pattern",
|
|
487
|
+
pattern: field.pattern,
|
|
488
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
489
|
+
};
|
|
490
|
+
constraints.push(c);
|
|
491
|
+
}
|
|
492
|
+
return buildFieldNode(
|
|
493
|
+
field.name,
|
|
494
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
495
|
+
type,
|
|
496
|
+
field.required,
|
|
497
|
+
buildAnnotations(getExplicitDisplayName(field), field.placeholder),
|
|
498
|
+
constraints
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
function canonicalizeNumberField(field, metadataPolicy) {
|
|
502
|
+
const type = { kind: "primitive", primitiveKind: "number" };
|
|
503
|
+
const constraints = [];
|
|
504
|
+
if (field.min !== void 0) {
|
|
505
|
+
const c = {
|
|
506
|
+
kind: "constraint",
|
|
507
|
+
constraintKind: "minimum",
|
|
508
|
+
value: field.min,
|
|
509
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
510
|
+
};
|
|
511
|
+
constraints.push(c);
|
|
512
|
+
}
|
|
513
|
+
if (field.max !== void 0) {
|
|
514
|
+
const c = {
|
|
515
|
+
kind: "constraint",
|
|
516
|
+
constraintKind: "maximum",
|
|
517
|
+
value: field.max,
|
|
518
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
519
|
+
};
|
|
520
|
+
constraints.push(c);
|
|
521
|
+
}
|
|
522
|
+
if (field.multipleOf !== void 0) {
|
|
523
|
+
const c = {
|
|
524
|
+
kind: "constraint",
|
|
525
|
+
constraintKind: "multipleOf",
|
|
526
|
+
value: field.multipleOf,
|
|
527
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
528
|
+
};
|
|
529
|
+
constraints.push(c);
|
|
530
|
+
}
|
|
531
|
+
return buildFieldNode(
|
|
532
|
+
field.name,
|
|
533
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
534
|
+
type,
|
|
535
|
+
field.required,
|
|
536
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
537
|
+
constraints
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
function canonicalizeBooleanField(field, metadataPolicy) {
|
|
541
|
+
const type = { kind: "primitive", primitiveKind: "boolean" };
|
|
542
|
+
return buildFieldNode(
|
|
543
|
+
field.name,
|
|
544
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
545
|
+
type,
|
|
546
|
+
field.required,
|
|
547
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
function canonicalizeStaticEnumField(field, metadataPolicy) {
|
|
551
|
+
const members = field.options.map((opt) => {
|
|
552
|
+
if (typeof opt === "string") {
|
|
553
|
+
return { value: opt };
|
|
554
|
+
}
|
|
555
|
+
return { value: opt.id, displayName: opt.label };
|
|
556
|
+
});
|
|
557
|
+
const type = { kind: "enum", members };
|
|
558
|
+
return buildFieldNode(
|
|
559
|
+
field.name,
|
|
560
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
561
|
+
type,
|
|
562
|
+
field.required,
|
|
563
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
function canonicalizeDynamicEnumField(field, metadataPolicy) {
|
|
567
|
+
const type = {
|
|
568
|
+
kind: "dynamic",
|
|
569
|
+
dynamicKind: "enum",
|
|
570
|
+
sourceKey: field.source,
|
|
571
|
+
parameterFields: field.params ? [...field.params] : []
|
|
572
|
+
};
|
|
573
|
+
return buildFieldNode(
|
|
574
|
+
field.name,
|
|
575
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
576
|
+
type,
|
|
577
|
+
field.required,
|
|
578
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
function canonicalizeDynamicSchemaField(field, metadataPolicy) {
|
|
582
|
+
const type = {
|
|
583
|
+
kind: "dynamic",
|
|
584
|
+
dynamicKind: "schema",
|
|
585
|
+
sourceKey: field.schemaSource,
|
|
586
|
+
parameterFields: []
|
|
587
|
+
};
|
|
588
|
+
return buildFieldNode(
|
|
589
|
+
field.name,
|
|
590
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
591
|
+
type,
|
|
592
|
+
field.required,
|
|
593
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
function canonicalizeArrayField(field, metadataPolicy) {
|
|
597
|
+
const itemProperties = buildObjectProperties(field.items, metadataPolicy);
|
|
598
|
+
const itemsType = {
|
|
599
|
+
kind: "object",
|
|
600
|
+
properties: itemProperties,
|
|
601
|
+
additionalProperties: true
|
|
602
|
+
};
|
|
603
|
+
const type = { kind: "array", items: itemsType };
|
|
604
|
+
const constraints = [];
|
|
605
|
+
if (field.minItems !== void 0) {
|
|
606
|
+
const c = {
|
|
607
|
+
kind: "constraint",
|
|
608
|
+
constraintKind: "minItems",
|
|
609
|
+
value: field.minItems,
|
|
610
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
611
|
+
};
|
|
612
|
+
constraints.push(c);
|
|
613
|
+
}
|
|
614
|
+
if (field.maxItems !== void 0) {
|
|
615
|
+
const c = {
|
|
616
|
+
kind: "constraint",
|
|
617
|
+
constraintKind: "maxItems",
|
|
618
|
+
value: field.maxItems,
|
|
619
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
620
|
+
};
|
|
621
|
+
constraints.push(c);
|
|
622
|
+
}
|
|
623
|
+
return buildFieldNode(
|
|
624
|
+
field.name,
|
|
625
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
626
|
+
type,
|
|
627
|
+
field.required,
|
|
628
|
+
buildAnnotations(getExplicitDisplayName(field)),
|
|
629
|
+
constraints
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
function canonicalizeObjectField(field, metadataPolicy) {
|
|
633
|
+
const properties = buildObjectProperties(field.properties, metadataPolicy);
|
|
634
|
+
const type = {
|
|
635
|
+
kind: "object",
|
|
636
|
+
properties,
|
|
637
|
+
additionalProperties: true
|
|
638
|
+
};
|
|
639
|
+
return buildFieldNode(
|
|
640
|
+
field.name,
|
|
641
|
+
resolveFieldMetadata(field.name, field, metadataPolicy),
|
|
642
|
+
type,
|
|
643
|
+
field.required,
|
|
644
|
+
buildAnnotations(getExplicitDisplayName(field))
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
function canonicalizeGroup(g, metadataPolicy) {
|
|
648
|
+
return {
|
|
649
|
+
kind: "group",
|
|
650
|
+
label: g.label,
|
|
651
|
+
elements: canonicalizeElements(g.elements, metadataPolicy),
|
|
652
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function canonicalizeConditional(c, metadataPolicy) {
|
|
656
|
+
return {
|
|
657
|
+
kind: "conditional",
|
|
658
|
+
fieldName: c.field,
|
|
659
|
+
// Conditional values from the chain DSL are JSON-serializable primitives
|
|
660
|
+
// (strings, numbers, booleans) produced by the `is()` predicate helper.
|
|
661
|
+
value: assertJsonValue(c.value),
|
|
662
|
+
elements: canonicalizeElements(c.elements, metadataPolicy),
|
|
663
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function assertJsonValue(v) {
|
|
667
|
+
if (v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
668
|
+
return v;
|
|
669
|
+
}
|
|
670
|
+
if (Array.isArray(v)) {
|
|
671
|
+
return v.map(assertJsonValue);
|
|
672
|
+
}
|
|
673
|
+
if (typeof v === "object") {
|
|
674
|
+
const result = {};
|
|
675
|
+
for (const [key, val] of Object.entries(v)) {
|
|
676
|
+
result[key] = assertJsonValue(val);
|
|
677
|
+
}
|
|
678
|
+
return result;
|
|
679
|
+
}
|
|
680
|
+
throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);
|
|
681
|
+
}
|
|
682
|
+
function buildFieldNode(name, metadata, type, required, annotations, constraints = []) {
|
|
683
|
+
return {
|
|
684
|
+
kind: "field",
|
|
685
|
+
name,
|
|
686
|
+
...metadata !== void 0 && { metadata },
|
|
687
|
+
type,
|
|
688
|
+
required: required === true,
|
|
689
|
+
constraints,
|
|
690
|
+
annotations,
|
|
691
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function buildAnnotations(label, placeholder) {
|
|
695
|
+
const annotations = [];
|
|
696
|
+
if (label !== void 0) {
|
|
697
|
+
const a = {
|
|
698
|
+
kind: "annotation",
|
|
699
|
+
annotationKind: "displayName",
|
|
700
|
+
value: label,
|
|
701
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
702
|
+
};
|
|
703
|
+
annotations.push(a);
|
|
704
|
+
}
|
|
705
|
+
if (placeholder !== void 0) {
|
|
706
|
+
const a = {
|
|
707
|
+
kind: "annotation",
|
|
708
|
+
annotationKind: "placeholder",
|
|
709
|
+
value: placeholder,
|
|
710
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
711
|
+
};
|
|
712
|
+
annotations.push(a);
|
|
713
|
+
}
|
|
714
|
+
return annotations;
|
|
715
|
+
}
|
|
716
|
+
function buildObjectProperties(elements, metadataPolicy, insideConditional = false) {
|
|
717
|
+
const properties = [];
|
|
718
|
+
for (const el of elements) {
|
|
719
|
+
if (isField(el)) {
|
|
720
|
+
const fieldNode = canonicalizeField(el, metadataPolicy);
|
|
721
|
+
properties.push({
|
|
722
|
+
name: fieldNode.name,
|
|
723
|
+
...fieldNode.metadata !== void 0 && { metadata: fieldNode.metadata },
|
|
724
|
+
type: fieldNode.type,
|
|
725
|
+
// Fields inside a conditional branch are always optional in the
|
|
726
|
+
// data schema, regardless of their `required` flag — the condition
|
|
727
|
+
// may not be met, so the field may be absent.
|
|
728
|
+
optional: insideConditional || !fieldNode.required,
|
|
729
|
+
constraints: fieldNode.constraints,
|
|
730
|
+
annotations: fieldNode.annotations,
|
|
731
|
+
provenance: CHAIN_DSL_PROVENANCE
|
|
732
|
+
});
|
|
733
|
+
} else if (isGroup(el)) {
|
|
734
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, insideConditional));
|
|
735
|
+
} else if (isConditional(el)) {
|
|
736
|
+
properties.push(...buildObjectProperties(el.elements, metadataPolicy, true));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return properties;
|
|
740
|
+
}
|
|
741
|
+
function getExplicitDisplayName(field) {
|
|
742
|
+
if (field.label !== void 0 && field.displayName !== void 0) {
|
|
743
|
+
throw new Error('Chain DSL fields cannot specify both "label" and "displayName".');
|
|
744
|
+
}
|
|
745
|
+
return field.displayName ?? field.label;
|
|
746
|
+
}
|
|
747
|
+
function resolveFieldMetadata(logicalName, field, metadataPolicy) {
|
|
748
|
+
const displayName = getExplicitDisplayName(field);
|
|
749
|
+
return resolveMetadata(
|
|
750
|
+
{
|
|
751
|
+
...field.apiName !== void 0 && { apiName: field.apiName },
|
|
752
|
+
...displayName !== void 0 && { displayName }
|
|
753
|
+
},
|
|
754
|
+
getDeclarationMetadataPolicy(metadataPolicy, "field"),
|
|
755
|
+
makeMetadataContext("chain-dsl", "field", logicalName)
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/canonicalize/tsdoc-canonicalizer.ts
|
|
760
|
+
var import_internals2 = require("@formspec/core/internals");
|
|
761
|
+
|
|
762
|
+
// src/metadata/collision-guards.ts
|
|
763
|
+
function assertUniqueSerializedNames(entries, scope) {
|
|
764
|
+
const seen = /* @__PURE__ */ new Map();
|
|
765
|
+
for (const entry of entries) {
|
|
766
|
+
const previous = seen.get(entry.serializedName);
|
|
767
|
+
if (previous !== void 0) {
|
|
768
|
+
if (previous.logicalName === entry.logicalName && previous.category === entry.category) {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
throw new Error(
|
|
772
|
+
`Serialized name collision in ${scope}: ${previous.category} "${previous.logicalName}" and ${entry.category} "${entry.logicalName}" both resolve to "${entry.serializedName}".`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
seen.set(entry.serializedName, entry);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function collectFlattenedFields(elements) {
|
|
779
|
+
const fields = [];
|
|
780
|
+
for (const element of elements) {
|
|
781
|
+
switch (element.kind) {
|
|
782
|
+
case "field":
|
|
783
|
+
fields.push(element);
|
|
784
|
+
break;
|
|
785
|
+
case "group":
|
|
786
|
+
case "conditional":
|
|
787
|
+
fields.push(...collectFlattenedFields(element.elements));
|
|
788
|
+
break;
|
|
789
|
+
default: {
|
|
790
|
+
const exhaustive = element;
|
|
791
|
+
void exhaustive;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return fields;
|
|
796
|
+
}
|
|
797
|
+
function validateObjectProperties(properties, scope) {
|
|
798
|
+
assertUniqueSerializedNames(
|
|
799
|
+
properties.map((property) => ({
|
|
800
|
+
logicalName: property.name,
|
|
801
|
+
serializedName: getSerializedName(property.name, property.metadata),
|
|
802
|
+
category: "object property"
|
|
803
|
+
})),
|
|
804
|
+
scope
|
|
805
|
+
);
|
|
806
|
+
for (const property of properties) {
|
|
807
|
+
validateTypeNode(
|
|
808
|
+
property.type,
|
|
809
|
+
`${scope}.${getSerializedName(property.name, property.metadata)}`
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
function validateTypeNode(type, scope) {
|
|
814
|
+
switch (type.kind) {
|
|
815
|
+
case "array":
|
|
816
|
+
validateTypeNode(type.items, `${scope}[]`);
|
|
817
|
+
break;
|
|
818
|
+
case "object":
|
|
819
|
+
validateObjectProperties(type.properties, scope);
|
|
820
|
+
break;
|
|
821
|
+
case "record":
|
|
822
|
+
validateTypeNode(type.valueType, `${scope}.*`);
|
|
823
|
+
break;
|
|
824
|
+
case "union":
|
|
825
|
+
type.members.forEach((member, index) => {
|
|
826
|
+
validateTypeNode(member, `${scope}|${String(index)}`);
|
|
827
|
+
});
|
|
828
|
+
break;
|
|
829
|
+
case "reference":
|
|
830
|
+
case "primitive":
|
|
831
|
+
case "enum":
|
|
832
|
+
case "dynamic":
|
|
833
|
+
case "custom":
|
|
834
|
+
break;
|
|
835
|
+
default: {
|
|
836
|
+
const exhaustive = type;
|
|
837
|
+
void exhaustive;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function validateTypeDefinitions(typeRegistry) {
|
|
842
|
+
const definitions = Object.values(typeRegistry);
|
|
843
|
+
assertUniqueSerializedNames(
|
|
844
|
+
definitions.map((definition) => ({
|
|
845
|
+
logicalName: definition.name,
|
|
846
|
+
serializedName: getSerializedName(definition.name, definition.metadata),
|
|
847
|
+
category: "type definition"
|
|
848
|
+
})),
|
|
849
|
+
"$defs"
|
|
850
|
+
);
|
|
851
|
+
for (const definition of definitions) {
|
|
852
|
+
validateTypeDefinition(definition);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
function validateTypeDefinition(definition) {
|
|
856
|
+
validateTypeNode(
|
|
857
|
+
definition.type,
|
|
858
|
+
`type "${getSerializedName(definition.name, definition.metadata)}"`
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
function assertNoSerializedNameCollisions(ir) {
|
|
862
|
+
assertUniqueSerializedNames(
|
|
863
|
+
collectFlattenedFields(ir.elements).map((field) => ({
|
|
864
|
+
logicalName: field.name,
|
|
865
|
+
serializedName: getSerializedName(field.name, field.metadata),
|
|
866
|
+
category: "field"
|
|
867
|
+
})),
|
|
868
|
+
"form root"
|
|
869
|
+
);
|
|
870
|
+
for (const field of collectFlattenedFields(ir.elements)) {
|
|
871
|
+
validateTypeNode(field.type, `field "${getSerializedName(field.name, field.metadata)}"`);
|
|
872
|
+
}
|
|
873
|
+
validateTypeDefinitions(ir.typeRegistry);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// src/json-schema/ir-generator.ts
|
|
877
|
+
function makeContext(options) {
|
|
878
|
+
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
879
|
+
const rawEnumSerialization = options?.enumSerialization;
|
|
880
|
+
if (!vendorPrefix.startsWith("x-")) {
|
|
881
|
+
throw new Error(
|
|
882
|
+
`Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
if (rawEnumSerialization !== void 0 && rawEnumSerialization !== "enum" && rawEnumSerialization !== "oneOf") {
|
|
886
|
+
throw new Error(
|
|
887
|
+
`Invalid enumSerialization "${rawEnumSerialization}". Expected "enum" or "oneOf".`
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
const enumSerialization = rawEnumSerialization ?? "enum";
|
|
891
|
+
return {
|
|
892
|
+
defs: {},
|
|
893
|
+
typeNameMap: {},
|
|
894
|
+
typeRegistry: {},
|
|
895
|
+
extensionRegistry: options?.extensionRegistry,
|
|
896
|
+
vendorPrefix,
|
|
897
|
+
enumSerialization
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function generateJsonSchemaFromIR(ir, options) {
|
|
901
|
+
assertNoSerializedNameCollisions(ir);
|
|
902
|
+
const ctx = {
|
|
903
|
+
...makeContext(options),
|
|
904
|
+
typeRegistry: ir.typeRegistry,
|
|
905
|
+
typeNameMap: Object.fromEntries(
|
|
906
|
+
Object.entries(ir.typeRegistry).map(([name, typeDef]) => [
|
|
907
|
+
name,
|
|
908
|
+
getSerializedName(name, typeDef.metadata)
|
|
909
|
+
])
|
|
910
|
+
)
|
|
911
|
+
};
|
|
912
|
+
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
913
|
+
const schemaName = ctx.typeNameMap[name] ?? name;
|
|
914
|
+
ctx.defs[schemaName] = generateTypeNode(typeDef.type, ctx);
|
|
915
|
+
applyResolvedMetadata(ctx.defs[schemaName], typeDef.metadata);
|
|
916
|
+
if (typeDef.constraints && typeDef.constraints.length > 0) {
|
|
917
|
+
applyConstraints(ctx.defs[schemaName], typeDef.constraints, ctx);
|
|
918
|
+
}
|
|
919
|
+
if (typeDef.annotations && typeDef.annotations.length > 0) {
|
|
920
|
+
applyAnnotations(ctx.defs[schemaName], typeDef.annotations, ctx);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const properties = {};
|
|
924
|
+
const required = [];
|
|
925
|
+
collectFields(ir.elements, properties, required, ctx);
|
|
926
|
+
const uniqueRequired = [...new Set(required)];
|
|
927
|
+
const result = {
|
|
928
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
929
|
+
type: "object",
|
|
930
|
+
properties,
|
|
931
|
+
...uniqueRequired.length > 0 && { required: uniqueRequired }
|
|
932
|
+
};
|
|
933
|
+
applyResolvedMetadata(result, ir.metadata);
|
|
934
|
+
if (ir.annotations && ir.annotations.length > 0) {
|
|
935
|
+
applyAnnotations(result, ir.annotations, ctx);
|
|
936
|
+
}
|
|
937
|
+
if (Object.keys(ctx.defs).length > 0) {
|
|
938
|
+
result.$defs = ctx.defs;
|
|
939
|
+
}
|
|
940
|
+
return result;
|
|
941
|
+
}
|
|
942
|
+
function collectFields(elements, properties, required, ctx) {
|
|
943
|
+
for (const element of elements) {
|
|
944
|
+
switch (element.kind) {
|
|
945
|
+
case "field":
|
|
946
|
+
properties[getSerializedFieldName(element)] = generateFieldSchema(element, ctx);
|
|
947
|
+
if (element.required) {
|
|
948
|
+
required.push(getSerializedFieldName(element));
|
|
949
|
+
}
|
|
950
|
+
break;
|
|
951
|
+
case "group":
|
|
952
|
+
collectFields(element.elements, properties, required, ctx);
|
|
953
|
+
break;
|
|
954
|
+
case "conditional":
|
|
955
|
+
collectFields(element.elements, properties, required, ctx);
|
|
956
|
+
break;
|
|
957
|
+
default: {
|
|
958
|
+
const _exhaustive = element;
|
|
959
|
+
void _exhaustive;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
function generateFieldSchema(field, ctx) {
|
|
965
|
+
const schema = generateTypeNode(field.type, ctx);
|
|
966
|
+
const itemStringSchema = schema.type === "array" && schema.items?.type === "string" ? schema.items : void 0;
|
|
967
|
+
const directConstraints = [];
|
|
968
|
+
const itemConstraints = [];
|
|
969
|
+
const pathConstraints = [];
|
|
970
|
+
for (const c of field.constraints) {
|
|
971
|
+
if (c.path) {
|
|
972
|
+
pathConstraints.push(c);
|
|
973
|
+
} else if (itemStringSchema !== void 0 && isStringItemConstraint(c)) {
|
|
974
|
+
itemConstraints.push(c);
|
|
975
|
+
} else {
|
|
976
|
+
directConstraints.push(c);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
980
|
+
if (itemStringSchema !== void 0) {
|
|
981
|
+
applyConstraints(itemStringSchema, itemConstraints, ctx);
|
|
982
|
+
}
|
|
983
|
+
const rootAnnotations = [];
|
|
984
|
+
const itemAnnotations = [];
|
|
985
|
+
for (const annotation of field.annotations) {
|
|
986
|
+
if (itemStringSchema !== void 0 && annotation.annotationKind === "format") {
|
|
987
|
+
itemAnnotations.push(annotation);
|
|
988
|
+
} else {
|
|
989
|
+
rootAnnotations.push(annotation);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
applyResolvedMetadata(schema, field.metadata);
|
|
993
|
+
applyAnnotations(schema, rootAnnotations, ctx);
|
|
994
|
+
if (itemStringSchema !== void 0) {
|
|
995
|
+
applyAnnotations(itemStringSchema, itemAnnotations, ctx);
|
|
996
|
+
}
|
|
997
|
+
if (pathConstraints.length === 0) {
|
|
998
|
+
return schema;
|
|
999
|
+
}
|
|
1000
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx, field.type);
|
|
1001
|
+
}
|
|
1002
|
+
function isStringItemConstraint(constraint) {
|
|
1003
|
+
switch (constraint.constraintKind) {
|
|
1004
|
+
case "minLength":
|
|
1005
|
+
case "maxLength":
|
|
1006
|
+
case "pattern":
|
|
1007
|
+
return true;
|
|
1008
|
+
default:
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx, typeNode) {
|
|
1013
|
+
if (schema.type === "array" && schema.items) {
|
|
1014
|
+
const referencedType = typeNode?.kind === "reference" ? resolveReferencedType(typeNode, ctx) : void 0;
|
|
1015
|
+
const nestedType = typeNode?.kind === "array" ? typeNode.items : referencedType?.kind === "array" ? referencedType.items : void 0;
|
|
1016
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);
|
|
1017
|
+
return schema;
|
|
1018
|
+
}
|
|
1019
|
+
const propertyOverrides = buildPropertyOverrides(pathConstraints, typeNode, ctx);
|
|
1020
|
+
const nullableValueBranch = getNullableUnionValueSchema(schema);
|
|
1021
|
+
if (nullableValueBranch !== void 0) {
|
|
1022
|
+
const updatedNullableValueBranch = applyPathTargetedConstraints(
|
|
1023
|
+
nullableValueBranch,
|
|
1024
|
+
pathConstraints,
|
|
1025
|
+
ctx,
|
|
1026
|
+
resolveTraversableTypeNode(typeNode, ctx)
|
|
1027
|
+
);
|
|
1028
|
+
if (schema.oneOf !== void 0) {
|
|
1029
|
+
schema.oneOf = schema.oneOf.map(
|
|
1030
|
+
(branch) => branch === nullableValueBranch ? updatedNullableValueBranch : branch
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
return schema;
|
|
1034
|
+
}
|
|
1035
|
+
if (schema.$ref) {
|
|
1036
|
+
const { $ref, ...rest } = schema;
|
|
1037
|
+
const refPart = { $ref };
|
|
1038
|
+
const overridePart = {
|
|
1039
|
+
properties: propertyOverrides,
|
|
1040
|
+
...rest
|
|
1041
|
+
};
|
|
1042
|
+
return { allOf: [refPart, overridePart] };
|
|
1043
|
+
}
|
|
1044
|
+
if (schema.type === "object" && schema.properties) {
|
|
1045
|
+
const missingOverrides = {};
|
|
1046
|
+
for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
|
|
1047
|
+
if (schema.properties[target]) {
|
|
1048
|
+
mergeSchemaOverride(schema.properties[target], overrideSchema);
|
|
1049
|
+
} else {
|
|
1050
|
+
missingOverrides[target] = overrideSchema;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (Object.keys(missingOverrides).length === 0) {
|
|
1054
|
+
return schema;
|
|
1055
|
+
}
|
|
1056
|
+
return {
|
|
1057
|
+
allOf: [schema, { properties: missingOverrides }]
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
if (schema.allOf) {
|
|
1061
|
+
schema.allOf = [...schema.allOf, { properties: propertyOverrides }];
|
|
1062
|
+
return schema;
|
|
1063
|
+
}
|
|
1064
|
+
return schema;
|
|
1065
|
+
}
|
|
1066
|
+
function generateTypeNode(type, ctx) {
|
|
1067
|
+
switch (type.kind) {
|
|
1068
|
+
case "primitive":
|
|
1069
|
+
return generatePrimitiveType(type);
|
|
1070
|
+
case "enum":
|
|
1071
|
+
return generateEnumType(type, ctx);
|
|
1072
|
+
case "array":
|
|
1073
|
+
return generateArrayType(type, ctx);
|
|
1074
|
+
case "object":
|
|
1075
|
+
return generateObjectType(type, ctx);
|
|
1076
|
+
case "record":
|
|
1077
|
+
return generateRecordType(type, ctx);
|
|
1078
|
+
case "union":
|
|
1079
|
+
return generateUnionType(type, ctx);
|
|
1080
|
+
case "reference":
|
|
1081
|
+
return generateReferenceType(type, ctx);
|
|
1082
|
+
case "dynamic":
|
|
1083
|
+
return generateDynamicType(type);
|
|
1084
|
+
case "custom":
|
|
1085
|
+
return generateCustomType(type, ctx);
|
|
1086
|
+
default: {
|
|
1087
|
+
const _exhaustive = type;
|
|
1088
|
+
return _exhaustive;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function generatePrimitiveType(type) {
|
|
1093
|
+
return {
|
|
1094
|
+
type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
function generateEnumType(type, ctx) {
|
|
1098
|
+
if (ctx.enumSerialization === "oneOf") {
|
|
1099
|
+
return {
|
|
1100
|
+
oneOf: type.members.map((m) => ({
|
|
1101
|
+
const: m.value,
|
|
1102
|
+
title: m.displayName ?? String(m.value)
|
|
1103
|
+
}))
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
const schema = { enum: type.members.map((m) => m.value) };
|
|
1107
|
+
const displayNames = buildEnumDisplayNameExtension(type);
|
|
1108
|
+
if (displayNames !== void 0) {
|
|
1109
|
+
schema[`${ctx.vendorPrefix}-display-names`] = displayNames;
|
|
1110
|
+
}
|
|
1111
|
+
return schema;
|
|
1112
|
+
}
|
|
1113
|
+
function buildEnumDisplayNameExtension(type) {
|
|
1114
|
+
if (!type.members.some((member) => member.displayName !== void 0)) {
|
|
1115
|
+
return void 0;
|
|
1116
|
+
}
|
|
1117
|
+
const displayNames = /* @__PURE__ */ Object.create(null);
|
|
1118
|
+
for (const member of type.members) {
|
|
1119
|
+
const key = String(member.value);
|
|
1120
|
+
if (Object.hasOwn(displayNames, key)) {
|
|
1121
|
+
throw new Error(
|
|
1122
|
+
`Enum display-name key "${key}" is ambiguous after stringification. Use oneOf serialization for mixed string/number enum values that collide.`
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
displayNames[key] = member.displayName ?? key;
|
|
1126
|
+
}
|
|
1127
|
+
return displayNames;
|
|
1128
|
+
}
|
|
1129
|
+
function generateArrayType(type, ctx) {
|
|
1130
|
+
return {
|
|
1131
|
+
type: "array",
|
|
1132
|
+
items: generateTypeNode(type.items, ctx)
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
function generateObjectType(type, ctx) {
|
|
1136
|
+
const properties = {};
|
|
1137
|
+
const required = [];
|
|
1138
|
+
for (const prop of type.properties) {
|
|
1139
|
+
const propertyName = getSerializedObjectPropertyName(prop);
|
|
1140
|
+
properties[propertyName] = generatePropertySchema(prop, ctx);
|
|
1141
|
+
if (!prop.optional) {
|
|
1142
|
+
required.push(propertyName);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
const schema = { type: "object", properties };
|
|
1146
|
+
if (required.length > 0) {
|
|
1147
|
+
schema.required = required;
|
|
1148
|
+
}
|
|
1149
|
+
if (!type.additionalProperties) {
|
|
1150
|
+
schema.additionalProperties = false;
|
|
1151
|
+
}
|
|
1152
|
+
return schema;
|
|
1153
|
+
}
|
|
1154
|
+
function generateRecordType(type, ctx) {
|
|
1155
|
+
return {
|
|
1156
|
+
type: "object",
|
|
1157
|
+
additionalProperties: generateTypeNode(type.valueType, ctx)
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function generatePropertySchema(prop, ctx) {
|
|
1161
|
+
const schema = generateTypeNode(prop.type, ctx);
|
|
1162
|
+
applyConstraints(schema, prop.constraints, ctx);
|
|
1163
|
+
applyResolvedMetadata(schema, prop.metadata);
|
|
1164
|
+
applyAnnotations(schema, prop.annotations, ctx);
|
|
1165
|
+
return schema;
|
|
1166
|
+
}
|
|
1167
|
+
function generateUnionType(type, ctx) {
|
|
1168
|
+
if (isBooleanUnion(type)) {
|
|
1169
|
+
return { type: "boolean" };
|
|
1170
|
+
}
|
|
1171
|
+
if (isNullableUnion(type)) {
|
|
1172
|
+
return {
|
|
1173
|
+
oneOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
return {
|
|
1177
|
+
anyOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
function isBooleanUnion(type) {
|
|
1181
|
+
if (type.members.length !== 2) return false;
|
|
1182
|
+
const kinds = type.members.map((m) => m.kind);
|
|
1183
|
+
return kinds.every((k) => k === "primitive") && type.members.every((m) => m.kind === "primitive" && m.primitiveKind === "boolean");
|
|
1184
|
+
}
|
|
1185
|
+
function isNullableUnion(type) {
|
|
1186
|
+
if (type.members.length !== 2) return false;
|
|
1187
|
+
const nullCount = type.members.filter(
|
|
1188
|
+
(m) => m.kind === "primitive" && m.primitiveKind === "null"
|
|
1189
|
+
).length;
|
|
1190
|
+
return nullCount === 1;
|
|
1191
|
+
}
|
|
1192
|
+
function generateReferenceType(type, ctx) {
|
|
1193
|
+
return { $ref: `#/$defs/${getSerializedTypeName(type.name, ctx)}` };
|
|
1194
|
+
}
|
|
1195
|
+
function getSerializedFieldName(field) {
|
|
1196
|
+
return getSerializedName(field.name, field.metadata);
|
|
1197
|
+
}
|
|
1198
|
+
function getSerializedObjectPropertyName(property) {
|
|
1199
|
+
return getSerializedName(property.name, property.metadata);
|
|
1200
|
+
}
|
|
1201
|
+
function getSerializedTypeName(logicalName, ctx) {
|
|
1202
|
+
return ctx.typeNameMap[logicalName] ?? logicalName;
|
|
1203
|
+
}
|
|
1204
|
+
function applyResolvedMetadata(schema, metadata) {
|
|
1205
|
+
const displayName = getDisplayName(metadata);
|
|
1206
|
+
if (displayName !== void 0) {
|
|
1207
|
+
schema.title = displayName;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
function resolveReferencedType(type, ctx) {
|
|
1211
|
+
return ctx.typeRegistry[type.name]?.type;
|
|
1212
|
+
}
|
|
1213
|
+
function dereferenceTypeNode(typeNode, ctx) {
|
|
1214
|
+
if (typeNode?.kind !== "reference") {
|
|
1215
|
+
return typeNode;
|
|
1216
|
+
}
|
|
1217
|
+
return resolveReferencedType(typeNode, ctx);
|
|
1218
|
+
}
|
|
1219
|
+
function unwrapNullableTypeNode(typeNode) {
|
|
1220
|
+
if (typeNode?.kind !== "union" || !isNullableUnion(typeNode)) {
|
|
1221
|
+
return typeNode;
|
|
1222
|
+
}
|
|
1223
|
+
return typeNode.members.find(
|
|
1224
|
+
(member) => !(member.kind === "primitive" && member.primitiveKind === "null")
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
function resolveTraversableTypeNode(typeNode, ctx) {
|
|
1228
|
+
const dereferenced = dereferenceTypeNode(typeNode, ctx);
|
|
1229
|
+
const unwrapped = unwrapNullableTypeNode(dereferenced);
|
|
1230
|
+
if (unwrapped !== dereferenced) {
|
|
1231
|
+
return resolveTraversableTypeNode(unwrapped, ctx);
|
|
1232
|
+
}
|
|
1233
|
+
return dereferenced;
|
|
1234
|
+
}
|
|
1235
|
+
function resolveSerializedPropertyName(logicalName, typeNode, ctx) {
|
|
1236
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1237
|
+
if (effectiveType?.kind === "array") {
|
|
1238
|
+
return resolveSerializedPropertyName(logicalName, effectiveType.items, ctx);
|
|
1239
|
+
}
|
|
1240
|
+
if (effectiveType?.kind === "object") {
|
|
1241
|
+
const property = effectiveType.properties.find((candidate) => candidate.name === logicalName);
|
|
1242
|
+
return property === void 0 ? logicalName : getSerializedObjectPropertyName(property);
|
|
1243
|
+
}
|
|
1244
|
+
return logicalName;
|
|
1245
|
+
}
|
|
1246
|
+
function resolveTargetTypeNode(logicalName, typeNode, ctx) {
|
|
1247
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1248
|
+
if (effectiveType?.kind === "array") {
|
|
1249
|
+
return resolveTargetTypeNode(logicalName, effectiveType.items, ctx);
|
|
1250
|
+
}
|
|
1251
|
+
if (effectiveType?.kind !== "object") {
|
|
1252
|
+
return void 0;
|
|
1253
|
+
}
|
|
1254
|
+
return effectiveType.properties.find((candidate) => candidate.name === logicalName)?.type;
|
|
1255
|
+
}
|
|
1256
|
+
function buildPropertyOverrides(pathConstraints, typeNode, ctx) {
|
|
1257
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
1258
|
+
for (const constraint of pathConstraints) {
|
|
1259
|
+
const target = constraint.path?.segments[0];
|
|
1260
|
+
if (!target) {
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
const grouped = byTarget.get(target) ?? [];
|
|
1264
|
+
grouped.push(constraint);
|
|
1265
|
+
byTarget.set(target, grouped);
|
|
1266
|
+
}
|
|
1267
|
+
const overrides = {};
|
|
1268
|
+
for (const [target, constraints] of byTarget) {
|
|
1269
|
+
overrides[resolveSerializedPropertyName(target, typeNode, ctx)] = buildPathOverrideSchema(
|
|
1270
|
+
constraints.map(stripLeadingPathSegment),
|
|
1271
|
+
resolveTargetTypeNode(target, typeNode, ctx),
|
|
1272
|
+
ctx
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
return overrides;
|
|
1276
|
+
}
|
|
1277
|
+
function buildPathOverrideSchema(constraints, typeNode, ctx) {
|
|
1278
|
+
const schema = {};
|
|
1279
|
+
const directConstraints = [];
|
|
1280
|
+
const nestedConstraints = [];
|
|
1281
|
+
for (const constraint of constraints) {
|
|
1282
|
+
if (constraint.path === void 0 || constraint.path.segments.length === 0) {
|
|
1283
|
+
directConstraints.push(constraint);
|
|
1284
|
+
} else {
|
|
1285
|
+
nestedConstraints.push(constraint);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
1289
|
+
if (nestedConstraints.length === 0) {
|
|
1290
|
+
return schema;
|
|
1291
|
+
}
|
|
1292
|
+
const effectiveType = resolveTraversableTypeNode(typeNode, ctx);
|
|
1293
|
+
if (effectiveType?.kind === "array") {
|
|
1294
|
+
schema.items = buildPathOverrideSchema(nestedConstraints, effectiveType.items, ctx);
|
|
1295
|
+
return schema;
|
|
1296
|
+
}
|
|
1297
|
+
schema.properties = buildPropertyOverrides(nestedConstraints, effectiveType, ctx);
|
|
1298
|
+
return schema;
|
|
1299
|
+
}
|
|
1300
|
+
function mergeSchemaOverride(target, override) {
|
|
1301
|
+
const nullableValueBranch = getNullableUnionValueSchema(target);
|
|
1302
|
+
if (nullableValueBranch !== void 0) {
|
|
1303
|
+
mergeSchemaOverride(nullableValueBranch, override);
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
if (override.properties !== void 0) {
|
|
1307
|
+
const mergedProperties = target.properties ?? {};
|
|
1308
|
+
for (const [name, propertyOverride] of Object.entries(override.properties)) {
|
|
1309
|
+
const existing = mergedProperties[name];
|
|
1310
|
+
if (existing === void 0) {
|
|
1311
|
+
mergedProperties[name] = propertyOverride;
|
|
1312
|
+
} else {
|
|
1313
|
+
mergeSchemaOverride(existing, propertyOverride);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
target.properties = mergedProperties;
|
|
1317
|
+
}
|
|
1318
|
+
if (override.items !== void 0) {
|
|
1319
|
+
if (target.items === void 0) {
|
|
1320
|
+
target.items = override.items;
|
|
1321
|
+
} else {
|
|
1322
|
+
mergeSchemaOverride(target.items, override.items);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
for (const [key, value] of Object.entries(override)) {
|
|
1326
|
+
if (key === "properties" || key === "items") {
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
target[key] = value;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function stripLeadingPathSegment(constraint) {
|
|
1333
|
+
const segments = constraint.path?.segments;
|
|
1334
|
+
if (segments === void 0 || segments.length === 0) {
|
|
1335
|
+
return constraint;
|
|
1336
|
+
}
|
|
1337
|
+
const [, ...rest] = segments;
|
|
1338
|
+
if (rest.length === 0) {
|
|
1339
|
+
const { path: _path, ...stripped } = constraint;
|
|
1340
|
+
return stripped;
|
|
1341
|
+
}
|
|
1342
|
+
return {
|
|
1343
|
+
...constraint,
|
|
1344
|
+
path: { segments: rest }
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
function getNullableUnionValueSchema(schema) {
|
|
1348
|
+
if (schema.oneOf?.length !== 2) {
|
|
1349
|
+
return void 0;
|
|
1350
|
+
}
|
|
1351
|
+
const valueSchema = schema.oneOf.find((branch) => branch.type !== "null");
|
|
1352
|
+
const nullSchema = schema.oneOf.find((branch) => branch.type === "null");
|
|
1353
|
+
return valueSchema !== void 0 && nullSchema !== void 0 ? valueSchema : void 0;
|
|
1354
|
+
}
|
|
1355
|
+
function generateDynamicType(type) {
|
|
1356
|
+
if (type.dynamicKind === "enum") {
|
|
1357
|
+
const schema = {
|
|
1358
|
+
type: "string",
|
|
1359
|
+
"x-formspec-source": type.sourceKey
|
|
1360
|
+
};
|
|
1361
|
+
if (type.parameterFields.length > 0) {
|
|
1362
|
+
schema["x-formspec-params"] = [...type.parameterFields];
|
|
1363
|
+
}
|
|
1364
|
+
return schema;
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
type: "object",
|
|
1368
|
+
additionalProperties: true,
|
|
1369
|
+
"x-formspec-schemaSource": type.sourceKey
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
function applyConstraints(schema, constraints, ctx) {
|
|
1373
|
+
for (const constraint of constraints) {
|
|
1374
|
+
switch (constraint.constraintKind) {
|
|
1375
|
+
case "minimum":
|
|
1376
|
+
schema.minimum = constraint.value;
|
|
1377
|
+
break;
|
|
1378
|
+
case "maximum":
|
|
1379
|
+
schema.maximum = constraint.value;
|
|
1380
|
+
break;
|
|
1381
|
+
case "exclusiveMinimum":
|
|
1382
|
+
schema.exclusiveMinimum = constraint.value;
|
|
1383
|
+
break;
|
|
1384
|
+
case "exclusiveMaximum":
|
|
1385
|
+
schema.exclusiveMaximum = constraint.value;
|
|
1386
|
+
break;
|
|
1387
|
+
case "multipleOf": {
|
|
1388
|
+
const { value } = constraint;
|
|
1389
|
+
if (value === 1 && schema.type === "number") {
|
|
1390
|
+
schema.type = "integer";
|
|
1391
|
+
} else {
|
|
1392
|
+
schema.multipleOf = value;
|
|
1393
|
+
}
|
|
1394
|
+
break;
|
|
1395
|
+
}
|
|
1396
|
+
case "minLength":
|
|
1397
|
+
schema.minLength = constraint.value;
|
|
1398
|
+
break;
|
|
1399
|
+
case "maxLength":
|
|
1400
|
+
schema.maxLength = constraint.value;
|
|
1401
|
+
break;
|
|
1402
|
+
case "minItems":
|
|
1403
|
+
schema.minItems = constraint.value;
|
|
1404
|
+
break;
|
|
1405
|
+
case "maxItems":
|
|
1406
|
+
schema.maxItems = constraint.value;
|
|
1407
|
+
break;
|
|
1408
|
+
case "pattern":
|
|
1409
|
+
schema.pattern = constraint.pattern;
|
|
1410
|
+
break;
|
|
1411
|
+
case "uniqueItems":
|
|
1412
|
+
schema.uniqueItems = constraint.value;
|
|
1413
|
+
break;
|
|
1414
|
+
case "const":
|
|
1415
|
+
schema.const = constraint.value;
|
|
1416
|
+
break;
|
|
1417
|
+
case "allowedMembers":
|
|
1418
|
+
break;
|
|
1419
|
+
case "custom":
|
|
1420
|
+
applyCustomConstraint(schema, constraint, ctx);
|
|
1421
|
+
break;
|
|
1422
|
+
default: {
|
|
1423
|
+
const _exhaustive = constraint;
|
|
1424
|
+
void _exhaustive;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
function applyAnnotations(schema, annotations, ctx) {
|
|
1430
|
+
for (const annotation of annotations) {
|
|
1431
|
+
switch (annotation.annotationKind) {
|
|
1432
|
+
case "displayName":
|
|
1433
|
+
schema.title ??= annotation.value;
|
|
1434
|
+
break;
|
|
1435
|
+
case "description":
|
|
1436
|
+
schema.description = annotation.value;
|
|
1437
|
+
break;
|
|
1438
|
+
case "remarks":
|
|
1439
|
+
schema[`${ctx.vendorPrefix}-remarks`] = annotation.value;
|
|
1440
|
+
break;
|
|
1441
|
+
case "defaultValue":
|
|
1442
|
+
schema.default = annotation.value;
|
|
1443
|
+
break;
|
|
1444
|
+
case "format":
|
|
1445
|
+
schema.format = annotation.value;
|
|
1446
|
+
break;
|
|
1447
|
+
case "deprecated":
|
|
1448
|
+
schema.deprecated = true;
|
|
1449
|
+
if (annotation.message !== void 0 && annotation.message !== "") {
|
|
1450
|
+
schema[`${ctx.vendorPrefix}-deprecation-description`] = annotation.message;
|
|
1451
|
+
}
|
|
1452
|
+
break;
|
|
1453
|
+
case "placeholder":
|
|
1454
|
+
break;
|
|
1455
|
+
case "formatHint":
|
|
1456
|
+
break;
|
|
1457
|
+
case "custom":
|
|
1458
|
+
applyCustomAnnotation(schema, annotation, ctx);
|
|
1459
|
+
break;
|
|
1460
|
+
default: {
|
|
1461
|
+
const _exhaustive = annotation;
|
|
1462
|
+
void _exhaustive;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function generateCustomType(type, ctx) {
|
|
1468
|
+
const registration = ctx.extensionRegistry?.findType(type.typeId);
|
|
1469
|
+
if (registration === void 0) {
|
|
1470
|
+
throw new Error(
|
|
1471
|
+
`Cannot generate JSON Schema for custom type "${type.typeId}" without a matching extension registration`
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
1475
|
+
}
|
|
1476
|
+
function applyCustomConstraint(schema, constraint, ctx) {
|
|
1477
|
+
const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);
|
|
1478
|
+
if (registration === void 0) {
|
|
1479
|
+
throw new Error(
|
|
1480
|
+
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
assignVendorPrefixedExtensionKeywords(
|
|
1484
|
+
schema,
|
|
1485
|
+
registration.toJsonSchema(constraint.payload, ctx.vendorPrefix),
|
|
1486
|
+
ctx.vendorPrefix,
|
|
1487
|
+
`custom constraint "${constraint.constraintId}"`
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
1491
|
+
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
1492
|
+
if (registration === void 0) {
|
|
1493
|
+
throw new Error(
|
|
1494
|
+
`Cannot generate JSON Schema for custom annotation "${annotation.annotationId}" without a matching extension registration`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
if (registration.toJsonSchema === void 0) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
assignVendorPrefixedExtensionKeywords(
|
|
1501
|
+
schema,
|
|
1502
|
+
registration.toJsonSchema(annotation.value, ctx.vendorPrefix),
|
|
1503
|
+
ctx.vendorPrefix,
|
|
1504
|
+
`custom annotation "${annotation.annotationId}"`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPrefix, source) {
|
|
1508
|
+
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
1509
|
+
if (!key.startsWith(`${vendorPrefix}-`)) {
|
|
1510
|
+
throw new Error(
|
|
1511
|
+
`Cannot apply ${source}: extension hooks may only emit "${vendorPrefix}-*" JSON Schema keywords`
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
schema[key] = value;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
// src/json-schema/generator.ts
|
|
1519
|
+
function generateJsonSchema(form, options) {
|
|
1520
|
+
const metadata = options?.metadata;
|
|
1521
|
+
const vendorPrefix = options?.vendorPrefix;
|
|
1522
|
+
const enumSerialization = options?.enumSerialization;
|
|
1523
|
+
const ir = canonicalizeChainDSL(
|
|
1524
|
+
form,
|
|
1525
|
+
metadata !== void 0 ? { metadata } : void 0
|
|
1526
|
+
);
|
|
1527
|
+
const internalOptions = vendorPrefix === void 0 && enumSerialization === void 0 ? void 0 : {
|
|
1528
|
+
...vendorPrefix !== void 0 && { vendorPrefix },
|
|
1529
|
+
...enumSerialization !== void 0 && { enumSerialization }
|
|
1530
|
+
};
|
|
1531
|
+
return generateJsonSchemaFromIR(ir, internalOptions);
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// src/ui-schema/schema.ts
|
|
1535
|
+
var import_zod = require("zod");
|
|
1536
|
+
var jsonPointerSchema = import_zod.z.string();
|
|
1537
|
+
var ruleEffectSchema = import_zod.z.enum(["SHOW", "HIDE", "ENABLE", "DISABLE"]);
|
|
1538
|
+
var uiSchemaElementTypeSchema = import_zod.z.enum([
|
|
1539
|
+
"Control",
|
|
1540
|
+
"VerticalLayout",
|
|
1541
|
+
"HorizontalLayout",
|
|
1542
|
+
"Group",
|
|
1543
|
+
"Categorization",
|
|
1544
|
+
"Category",
|
|
1545
|
+
"Label"
|
|
1546
|
+
]);
|
|
1547
|
+
var ruleConditionSchema = import_zod.z.lazy(
|
|
1548
|
+
() => import_zod.z.object({
|
|
1549
|
+
const: import_zod.z.unknown().optional(),
|
|
1550
|
+
enum: import_zod.z.array(import_zod.z.unknown()).readonly().optional(),
|
|
1551
|
+
type: import_zod.z.string().optional(),
|
|
1552
|
+
not: ruleConditionSchema.optional(),
|
|
1553
|
+
minimum: import_zod.z.number().optional(),
|
|
1554
|
+
maximum: import_zod.z.number().optional(),
|
|
1555
|
+
exclusiveMinimum: import_zod.z.number().optional(),
|
|
1556
|
+
exclusiveMaximum: import_zod.z.number().optional(),
|
|
1557
|
+
minLength: import_zod.z.number().optional(),
|
|
1558
|
+
properties: import_zod.z.record(import_zod.z.string(), ruleConditionSchema).optional(),
|
|
1559
|
+
required: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1560
|
+
allOf: import_zod.z.array(ruleConditionSchema).optional()
|
|
1561
|
+
}).strict()
|
|
1562
|
+
);
|
|
1563
|
+
var schemaBasedConditionSchema = import_zod.z.object({
|
|
1564
|
+
scope: jsonPointerSchema,
|
|
1565
|
+
schema: ruleConditionSchema
|
|
1566
|
+
}).strict();
|
|
1567
|
+
var ruleSchema = import_zod.z.object({
|
|
1568
|
+
effect: ruleEffectSchema,
|
|
1569
|
+
condition: schemaBasedConditionSchema
|
|
1570
|
+
}).strict();
|
|
1571
|
+
var uiSchemaElementSchema = import_zod.z.lazy(
|
|
1572
|
+
() => import_zod.z.union([
|
|
1573
|
+
controlSchema,
|
|
1574
|
+
verticalLayoutSchema,
|
|
1575
|
+
horizontalLayoutSchema,
|
|
1576
|
+
groupLayoutSchema,
|
|
1577
|
+
categorizationSchema,
|
|
1578
|
+
categorySchema,
|
|
1579
|
+
labelElementSchema
|
|
1580
|
+
])
|
|
1581
|
+
);
|
|
1582
|
+
var controlSchema = import_zod.z.object({
|
|
1583
|
+
type: import_zod.z.literal("Control"),
|
|
1584
|
+
scope: jsonPointerSchema,
|
|
1585
|
+
label: import_zod.z.union([import_zod.z.string(), import_zod.z.literal(false)]).optional(),
|
|
1586
|
+
rule: ruleSchema.optional(),
|
|
1587
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1588
|
+
}).passthrough();
|
|
1589
|
+
var verticalLayoutSchema = import_zod.z.lazy(
|
|
1590
|
+
() => import_zod.z.object({
|
|
1591
|
+
type: import_zod.z.literal("VerticalLayout"),
|
|
1592
|
+
elements: import_zod.z.array(uiSchemaElementSchema),
|
|
1593
|
+
rule: ruleSchema.optional(),
|
|
1594
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1595
|
+
}).passthrough()
|
|
1596
|
+
);
|
|
1597
|
+
var horizontalLayoutSchema = import_zod.z.lazy(
|
|
1598
|
+
() => import_zod.z.object({
|
|
1599
|
+
type: import_zod.z.literal("HorizontalLayout"),
|
|
1600
|
+
elements: import_zod.z.array(uiSchemaElementSchema),
|
|
1601
|
+
rule: ruleSchema.optional(),
|
|
1602
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1603
|
+
}).passthrough()
|
|
1604
|
+
);
|
|
1605
|
+
var groupLayoutSchema = import_zod.z.lazy(
|
|
1606
|
+
() => import_zod.z.object({
|
|
1607
|
+
type: import_zod.z.literal("Group"),
|
|
1608
|
+
label: import_zod.z.string(),
|
|
1609
|
+
elements: import_zod.z.array(uiSchemaElementSchema),
|
|
1610
|
+
rule: ruleSchema.optional(),
|
|
1611
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1612
|
+
}).passthrough()
|
|
1613
|
+
);
|
|
1614
|
+
var categorySchema = import_zod.z.lazy(
|
|
1615
|
+
() => import_zod.z.object({
|
|
1616
|
+
type: import_zod.z.literal("Category"),
|
|
1617
|
+
label: import_zod.z.string(),
|
|
1618
|
+
elements: import_zod.z.array(uiSchemaElementSchema),
|
|
1619
|
+
rule: ruleSchema.optional(),
|
|
1620
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1621
|
+
}).passthrough()
|
|
1622
|
+
);
|
|
1623
|
+
var categorizationSchema = import_zod.z.lazy(
|
|
1624
|
+
() => import_zod.z.object({
|
|
1625
|
+
type: import_zod.z.literal("Categorization"),
|
|
1626
|
+
elements: import_zod.z.array(categorySchema),
|
|
1627
|
+
label: import_zod.z.string().optional(),
|
|
1628
|
+
rule: ruleSchema.optional(),
|
|
1629
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1630
|
+
}).passthrough()
|
|
1631
|
+
);
|
|
1632
|
+
var labelElementSchema = import_zod.z.object({
|
|
1633
|
+
type: import_zod.z.literal("Label"),
|
|
1634
|
+
text: import_zod.z.string(),
|
|
1635
|
+
rule: ruleSchema.optional(),
|
|
1636
|
+
options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
1637
|
+
}).passthrough();
|
|
1638
|
+
var uiSchema = import_zod.z.lazy(
|
|
1639
|
+
() => import_zod.z.union([verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorizationSchema])
|
|
1640
|
+
);
|
|
1641
|
+
|
|
1642
|
+
// src/ui-schema/ir-generator.ts
|
|
1643
|
+
var import_zod2 = require("zod");
|
|
1644
|
+
function parseOrThrow(schema, value, label) {
|
|
1645
|
+
try {
|
|
1646
|
+
return schema.parse(value);
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
if (error instanceof import_zod2.z.ZodError) {
|
|
1649
|
+
throw new Error(
|
|
1650
|
+
`Generated ${label} failed validation:
|
|
1651
|
+
${error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n")}`
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
throw error;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
function fieldToScope(fieldName) {
|
|
1658
|
+
return `#/properties/${fieldName}`;
|
|
1659
|
+
}
|
|
1660
|
+
function createShowRule(fieldName, value) {
|
|
1661
|
+
return {
|
|
1662
|
+
effect: "SHOW",
|
|
1663
|
+
condition: {
|
|
1664
|
+
scope: fieldToScope(fieldName),
|
|
1665
|
+
schema: { const: value }
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
function flattenConditionSchema(scope, schema) {
|
|
1670
|
+
if (schema.allOf === void 0) {
|
|
1671
|
+
if (scope === "#") {
|
|
1672
|
+
return [schema];
|
|
1673
|
+
}
|
|
1674
|
+
const fieldName = scope.replace("#/properties/", "");
|
|
1675
|
+
return [
|
|
1676
|
+
{
|
|
1677
|
+
properties: {
|
|
1678
|
+
[fieldName]: schema
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
];
|
|
1682
|
+
}
|
|
1683
|
+
return schema.allOf.flatMap((member) => flattenConditionSchema(scope, member));
|
|
1684
|
+
}
|
|
1685
|
+
function combineRules(parentRule, childRule) {
|
|
1686
|
+
return {
|
|
1687
|
+
effect: "SHOW",
|
|
1688
|
+
condition: {
|
|
1689
|
+
scope: "#",
|
|
1690
|
+
schema: {
|
|
1691
|
+
allOf: [
|
|
1692
|
+
...flattenConditionSchema(parentRule.condition.scope, parentRule.condition.schema),
|
|
1693
|
+
...flattenConditionSchema(childRule.condition.scope, childRule.condition.schema)
|
|
1694
|
+
]
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
function getFieldDisplayName(field) {
|
|
1700
|
+
const resolvedDisplayName = getDisplayName(field.metadata);
|
|
1701
|
+
if (resolvedDisplayName !== void 0) {
|
|
1702
|
+
return resolvedDisplayName;
|
|
1703
|
+
}
|
|
1704
|
+
return field.annotations.find((annotation) => annotation.annotationKind === "displayName")?.value;
|
|
1705
|
+
}
|
|
1706
|
+
function fieldNodeToControl(field, fieldNameMap, parentRule) {
|
|
1707
|
+
const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === "placeholder");
|
|
1708
|
+
const serializedName = fieldNameMap.get(field.name) ?? getSerializedName(field.name, field.metadata);
|
|
1709
|
+
const displayName = getFieldDisplayName(field);
|
|
1710
|
+
const control = {
|
|
1711
|
+
type: "Control",
|
|
1712
|
+
scope: fieldToScope(serializedName),
|
|
1713
|
+
...displayName !== void 0 && { label: displayName },
|
|
1714
|
+
...placeholderAnnotation !== void 0 && {
|
|
1715
|
+
options: { placeholder: placeholderAnnotation.value }
|
|
1716
|
+
},
|
|
1717
|
+
...parentRule !== void 0 && { rule: parentRule }
|
|
1718
|
+
};
|
|
1719
|
+
return control;
|
|
1720
|
+
}
|
|
1721
|
+
function groupNodeToLayout(group, fieldNameMap, parentRule) {
|
|
1722
|
+
return {
|
|
1723
|
+
type: "Group",
|
|
1724
|
+
label: group.label,
|
|
1725
|
+
elements: irElementsToUiSchema(group.elements, fieldNameMap, parentRule),
|
|
1726
|
+
...parentRule !== void 0 && { rule: parentRule }
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
|
|
1730
|
+
const result = [];
|
|
1731
|
+
for (const element of elements) {
|
|
1732
|
+
switch (element.kind) {
|
|
1733
|
+
case "field": {
|
|
1734
|
+
result.push(fieldNodeToControl(element, fieldNameMap, parentRule));
|
|
1735
|
+
break;
|
|
1736
|
+
}
|
|
1737
|
+
case "group": {
|
|
1738
|
+
result.push(groupNodeToLayout(element, fieldNameMap, parentRule));
|
|
1739
|
+
break;
|
|
1740
|
+
}
|
|
1741
|
+
case "conditional": {
|
|
1742
|
+
const newRule = createShowRule(fieldNameMap.get(element.fieldName) ?? element.fieldName, element.value);
|
|
1743
|
+
const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
|
|
1744
|
+
const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
|
|
1745
|
+
result.push(...childElements);
|
|
1746
|
+
break;
|
|
1747
|
+
}
|
|
1748
|
+
default: {
|
|
1749
|
+
const _exhaustive = element;
|
|
1750
|
+
void _exhaustive;
|
|
1751
|
+
throw new Error("Unhandled IR element kind");
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
return result;
|
|
1756
|
+
}
|
|
1757
|
+
function generateUiSchemaFromIR(ir) {
|
|
1758
|
+
assertNoSerializedNameCollisions(ir);
|
|
1759
|
+
const fieldNameMap = collectFieldNameMap(ir.elements);
|
|
1760
|
+
const result = {
|
|
1761
|
+
type: "VerticalLayout",
|
|
1762
|
+
elements: irElementsToUiSchema(ir.elements, fieldNameMap)
|
|
1763
|
+
};
|
|
1764
|
+
return parseOrThrow(uiSchema, result, "UI Schema");
|
|
1765
|
+
}
|
|
1766
|
+
function collectFieldNameMap(elements) {
|
|
1767
|
+
const map = /* @__PURE__ */ new Map();
|
|
1768
|
+
for (const element of elements) {
|
|
1769
|
+
switch (element.kind) {
|
|
1770
|
+
case "field":
|
|
1771
|
+
map.set(element.name, getSerializedName(element.name, element.metadata));
|
|
1772
|
+
break;
|
|
1773
|
+
case "group":
|
|
1774
|
+
case "conditional":
|
|
1775
|
+
for (const [key, value] of collectFieldNameMap(element.elements)) {
|
|
1776
|
+
map.set(key, value);
|
|
1777
|
+
}
|
|
1778
|
+
break;
|
|
1779
|
+
default: {
|
|
1780
|
+
const _exhaustive = element;
|
|
1781
|
+
void _exhaustive;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return map;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/ui-schema/generator.ts
|
|
1789
|
+
function generateUiSchema(form, options) {
|
|
1790
|
+
const ir = canonicalizeChainDSL(
|
|
1791
|
+
form,
|
|
1792
|
+
options?.metadata !== void 0 ? { metadata: options.metadata } : void 0
|
|
1793
|
+
);
|
|
1794
|
+
return generateUiSchemaFromIR(ir);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
// src/json-schema/types.ts
|
|
1798
|
+
function setSchemaExtension(schema, key, value) {
|
|
1799
|
+
schema[key] = value;
|
|
1800
|
+
}
|
|
1801
|
+
function getSchemaExtension(schema, key) {
|
|
1802
|
+
return schema[key];
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// src/extensions/registry.ts
|
|
1806
|
+
var import_internals3 = require("@formspec/core/internals");
|
|
1807
|
+
var import_internal = require("@formspec/analysis/internal");
|
|
1808
|
+
var BUILTIN_METADATA_TAGS = /* @__PURE__ */ new Set(["apiName", "displayName"]);
|
|
1809
|
+
function buildConstraintTagSources(extensions) {
|
|
1810
|
+
return extensions.map((extension) => ({
|
|
1811
|
+
extensionId: extension.extensionId,
|
|
1812
|
+
...extension.constraintTags !== void 0 ? {
|
|
1813
|
+
constraintTags: extension.constraintTags.map((tag) => ({
|
|
1814
|
+
tagName: (0, import_internal.normalizeFormSpecTagName)(tag.tagName)
|
|
1815
|
+
}))
|
|
1816
|
+
} : {}
|
|
1817
|
+
}));
|
|
1818
|
+
}
|
|
1819
|
+
function createExtensionRegistry(extensions) {
|
|
1820
|
+
const reservedTagSources = buildConstraintTagSources(extensions);
|
|
1821
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
1822
|
+
const typeNameMap = /* @__PURE__ */ new Map();
|
|
1823
|
+
const constraintMap = /* @__PURE__ */ new Map();
|
|
1824
|
+
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
1825
|
+
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
1826
|
+
const annotationMap = /* @__PURE__ */ new Map();
|
|
1827
|
+
const metadataSlotMap = /* @__PURE__ */ new Map();
|
|
1828
|
+
const metadataTagMap = /* @__PURE__ */ new Map();
|
|
1829
|
+
for (const ext of extensions) {
|
|
1830
|
+
if (ext.types !== void 0) {
|
|
1831
|
+
for (const type of ext.types) {
|
|
1832
|
+
const qualifiedId = `${ext.extensionId}/${type.typeName}`;
|
|
1833
|
+
if (typeMap.has(qualifiedId)) {
|
|
1834
|
+
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
1835
|
+
}
|
|
1836
|
+
typeMap.set(qualifiedId, type);
|
|
1837
|
+
for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
|
|
1838
|
+
if (typeNameMap.has(sourceTypeName)) {
|
|
1839
|
+
throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
|
|
1840
|
+
}
|
|
1841
|
+
typeNameMap.set(sourceTypeName, {
|
|
1842
|
+
extensionId: ext.extensionId,
|
|
1843
|
+
registration: type
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
if (type.builtinConstraintBroadenings !== void 0) {
|
|
1847
|
+
for (const broadening of type.builtinConstraintBroadenings) {
|
|
1848
|
+
const key = `${qualifiedId}:${broadening.tagName}`;
|
|
1849
|
+
if (builtinBroadeningMap.has(key)) {
|
|
1850
|
+
throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
|
|
1851
|
+
}
|
|
1852
|
+
builtinBroadeningMap.set(key, {
|
|
1853
|
+
extensionId: ext.extensionId,
|
|
1854
|
+
registration: broadening
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (ext.constraints !== void 0) {
|
|
1861
|
+
for (const constraint of ext.constraints) {
|
|
1862
|
+
const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
|
|
1863
|
+
if (constraintMap.has(qualifiedId)) {
|
|
1864
|
+
throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
|
|
1865
|
+
}
|
|
1866
|
+
constraintMap.set(qualifiedId, constraint);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
if (ext.constraintTags !== void 0) {
|
|
1870
|
+
for (const tag of ext.constraintTags) {
|
|
1871
|
+
const canonicalTagName = (0, import_internal.normalizeFormSpecTagName)(tag.tagName);
|
|
1872
|
+
if (constraintTagMap.has(canonicalTagName)) {
|
|
1873
|
+
throw new Error(`Duplicate custom constraint tag: "@${canonicalTagName}"`);
|
|
1874
|
+
}
|
|
1875
|
+
constraintTagMap.set(canonicalTagName, {
|
|
1876
|
+
extensionId: ext.extensionId,
|
|
1877
|
+
registration: tag
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
if (ext.annotations !== void 0) {
|
|
1882
|
+
for (const annotation of ext.annotations) {
|
|
1883
|
+
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
1884
|
+
if (annotationMap.has(qualifiedId)) {
|
|
1885
|
+
throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
|
|
1886
|
+
}
|
|
1887
|
+
annotationMap.set(qualifiedId, annotation);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
if (ext.metadataSlots !== void 0) {
|
|
1891
|
+
for (const slot of ext.metadataSlots) {
|
|
1892
|
+
if (metadataSlotMap.has(slot.slotId)) {
|
|
1893
|
+
throw new Error(`Duplicate metadata slot ID: "${slot.slotId}"`);
|
|
1894
|
+
}
|
|
1895
|
+
metadataSlotMap.set(slot.slotId, true);
|
|
1896
|
+
const canonicalTagName = (0, import_internal.normalizeFormSpecTagName)(slot.tagName);
|
|
1897
|
+
if (slot.allowBare === false && (slot.qualifiers?.length ?? 0) === 0) {
|
|
1898
|
+
throw new Error(
|
|
1899
|
+
`Metadata tag "@${canonicalTagName}" must allow bare usage or declare at least one qualifier.`
|
|
1900
|
+
);
|
|
1901
|
+
}
|
|
1902
|
+
if (metadataTagMap.has(canonicalTagName)) {
|
|
1903
|
+
throw new Error(`Duplicate metadata tag: "@${canonicalTagName}"`);
|
|
1904
|
+
}
|
|
1905
|
+
if (BUILTIN_METADATA_TAGS.has(canonicalTagName)) {
|
|
1906
|
+
throw new Error(
|
|
1907
|
+
`Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
if (constraintTagMap.has(canonicalTagName)) {
|
|
1911
|
+
throw new Error(
|
|
1912
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1915
|
+
if (Object.hasOwn(import_internals3.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals3.normalizeConstraintTagName)(canonicalTagName))) {
|
|
1916
|
+
throw new Error(
|
|
1917
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals3.normalizeConstraintTagName)(canonicalTagName)}".`
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1920
|
+
const existingTag = (0, import_internal.getTagDefinition)(canonicalTagName, reservedTagSources);
|
|
1921
|
+
if (existingTag !== null) {
|
|
1922
|
+
throw BUILTIN_METADATA_TAGS.has(existingTag.canonicalName) ? new Error(
|
|
1923
|
+
`Metadata tag "@${canonicalTagName}" conflicts with built-in metadata tags.`
|
|
1924
|
+
) : new Error(
|
|
1925
|
+
`Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${existingTag.canonicalName}".`
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
metadataTagMap.set(canonicalTagName, true);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
return {
|
|
1933
|
+
extensions,
|
|
1934
|
+
findType: (typeId) => typeMap.get(typeId),
|
|
1935
|
+
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
1936
|
+
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1937
|
+
findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal.normalizeFormSpecTagName)(tagName)),
|
|
1938
|
+
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
1939
|
+
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
// src/json-schema/schema.ts
|
|
1944
|
+
var import_zod3 = require("zod");
|
|
1945
|
+
var jsonSchemaTypeSchema = import_zod3.z.enum([
|
|
1946
|
+
"string",
|
|
1947
|
+
"number",
|
|
1948
|
+
"integer",
|
|
1949
|
+
"boolean",
|
|
1950
|
+
"object",
|
|
1951
|
+
"array",
|
|
1952
|
+
"null"
|
|
1953
|
+
]);
|
|
1954
|
+
var jsonSchema7Schema = import_zod3.z.lazy(
|
|
1955
|
+
() => import_zod3.z.object({
|
|
1956
|
+
$schema: import_zod3.z.string().optional(),
|
|
1957
|
+
$id: import_zod3.z.string().optional(),
|
|
1958
|
+
$ref: import_zod3.z.string().optional(),
|
|
1959
|
+
// Metadata
|
|
1960
|
+
title: import_zod3.z.string().optional(),
|
|
1961
|
+
description: import_zod3.z.string().optional(),
|
|
1962
|
+
deprecated: import_zod3.z.boolean().optional(),
|
|
1963
|
+
// Type
|
|
1964
|
+
type: import_zod3.z.union([jsonSchemaTypeSchema, import_zod3.z.array(jsonSchemaTypeSchema)]).optional(),
|
|
1965
|
+
// String validation
|
|
1966
|
+
minLength: import_zod3.z.number().optional(),
|
|
1967
|
+
maxLength: import_zod3.z.number().optional(),
|
|
1968
|
+
pattern: import_zod3.z.string().optional(),
|
|
1969
|
+
// Number validation
|
|
1970
|
+
minimum: import_zod3.z.number().optional(),
|
|
1971
|
+
maximum: import_zod3.z.number().optional(),
|
|
1972
|
+
exclusiveMinimum: import_zod3.z.number().optional(),
|
|
1973
|
+
exclusiveMaximum: import_zod3.z.number().optional(),
|
|
1974
|
+
// Enum
|
|
1975
|
+
enum: import_zod3.z.array(import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()])).readonly().optional(),
|
|
1976
|
+
const: import_zod3.z.union([import_zod3.z.string(), import_zod3.z.number(), import_zod3.z.boolean(), import_zod3.z.null()]).optional(),
|
|
1977
|
+
// Object
|
|
1978
|
+
properties: import_zod3.z.record(import_zod3.z.string(), jsonSchema7Schema).optional(),
|
|
1979
|
+
required: import_zod3.z.array(import_zod3.z.string()).optional(),
|
|
1980
|
+
additionalProperties: import_zod3.z.union([import_zod3.z.boolean(), jsonSchema7Schema]).optional(),
|
|
1981
|
+
// Array
|
|
1982
|
+
items: import_zod3.z.union([jsonSchema7Schema, import_zod3.z.array(jsonSchema7Schema)]).optional(),
|
|
1983
|
+
minItems: import_zod3.z.number().optional(),
|
|
1984
|
+
maxItems: import_zod3.z.number().optional(),
|
|
1985
|
+
// Composition
|
|
1986
|
+
allOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1987
|
+
anyOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1988
|
+
oneOf: import_zod3.z.array(jsonSchema7Schema).optional(),
|
|
1989
|
+
not: jsonSchema7Schema.optional(),
|
|
1990
|
+
// Conditional
|
|
1991
|
+
if: jsonSchema7Schema.optional(),
|
|
1992
|
+
then: jsonSchema7Schema.optional(),
|
|
1993
|
+
else: jsonSchema7Schema.optional(),
|
|
1994
|
+
// Format
|
|
1995
|
+
format: import_zod3.z.string().optional(),
|
|
1996
|
+
// Default
|
|
1997
|
+
default: import_zod3.z.unknown().optional(),
|
|
1998
|
+
// FormSpec extensions
|
|
1999
|
+
"x-formspec-source": import_zod3.z.string().optional(),
|
|
2000
|
+
"x-formspec-params": import_zod3.z.array(import_zod3.z.string()).readonly().optional(),
|
|
2001
|
+
"x-formspec-schemaSource": import_zod3.z.string().optional()
|
|
2002
|
+
}).passthrough()
|
|
2003
|
+
);
|
|
2004
|
+
|
|
2005
|
+
// src/validate/constraint-validator.ts
|
|
2006
|
+
var import_internal2 = require("@formspec/analysis/internal");
|
|
2007
|
+
function validateFieldNode(ctx, field) {
|
|
2008
|
+
const analysis = (0, import_internal2.analyzeConstraintTargets)(
|
|
2009
|
+
field.name,
|
|
2010
|
+
field.type,
|
|
2011
|
+
field.constraints,
|
|
2012
|
+
ctx.typeRegistry,
|
|
2013
|
+
ctx.extensionRegistry === void 0 ? void 0 : {
|
|
2014
|
+
extensionRegistry: ctx.extensionRegistry
|
|
2015
|
+
}
|
|
2016
|
+
);
|
|
2017
|
+
ctx.diagnostics.push(...analysis.diagnostics);
|
|
2018
|
+
if (field.type.kind === "object") {
|
|
2019
|
+
for (const property of field.type.properties) {
|
|
2020
|
+
validateObjectProperty(ctx, field.name, property);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
function validateObjectProperty(ctx, parentName, property) {
|
|
2025
|
+
const qualifiedName = `${parentName}.${property.name}`;
|
|
2026
|
+
const analysis = (0, import_internal2.analyzeConstraintTargets)(
|
|
2027
|
+
qualifiedName,
|
|
2028
|
+
property.type,
|
|
2029
|
+
property.constraints,
|
|
2030
|
+
ctx.typeRegistry,
|
|
2031
|
+
ctx.extensionRegistry === void 0 ? void 0 : {
|
|
2032
|
+
extensionRegistry: ctx.extensionRegistry
|
|
2033
|
+
}
|
|
2034
|
+
);
|
|
2035
|
+
ctx.diagnostics.push(...analysis.diagnostics);
|
|
2036
|
+
if (property.type.kind === "object") {
|
|
2037
|
+
for (const nestedProperty of property.type.properties) {
|
|
2038
|
+
validateObjectProperty(ctx, qualifiedName, nestedProperty);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
function validateElement(ctx, element) {
|
|
2043
|
+
switch (element.kind) {
|
|
2044
|
+
case "field":
|
|
2045
|
+
validateFieldNode(ctx, element);
|
|
2046
|
+
break;
|
|
2047
|
+
case "group":
|
|
2048
|
+
for (const child of element.elements) {
|
|
2049
|
+
validateElement(ctx, child);
|
|
2050
|
+
}
|
|
2051
|
+
break;
|
|
2052
|
+
case "conditional":
|
|
2053
|
+
for (const child of element.elements) {
|
|
2054
|
+
validateElement(ctx, child);
|
|
2055
|
+
}
|
|
2056
|
+
break;
|
|
2057
|
+
default: {
|
|
2058
|
+
const exhaustive = element;
|
|
2059
|
+
throw new Error(`Unhandled element kind: ${String(exhaustive)}`);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
function validateIR(ir, options) {
|
|
2064
|
+
const ctx = {
|
|
2065
|
+
diagnostics: [],
|
|
2066
|
+
extensionRegistry: options?.extensionRegistry,
|
|
2067
|
+
typeRegistry: ir.typeRegistry
|
|
2068
|
+
};
|
|
2069
|
+
for (const element of ir.elements) {
|
|
2070
|
+
validateElement(ctx, element);
|
|
2071
|
+
}
|
|
2072
|
+
return {
|
|
2073
|
+
diagnostics: ctx.diagnostics,
|
|
2074
|
+
valid: ctx.diagnostics.every((diagnostic) => diagnostic.severity !== "error")
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
// src/browser.ts
|
|
2079
|
+
function buildFormSchemas(form, options) {
|
|
2080
|
+
return {
|
|
2081
|
+
jsonSchema: generateJsonSchema(form, options),
|
|
2082
|
+
uiSchema: generateUiSchema(form, options)
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2086
|
+
0 && (module.exports = {
|
|
2087
|
+
buildFormSchemas,
|
|
2088
|
+
canonicalizeChainDSL,
|
|
2089
|
+
categorizationSchema,
|
|
2090
|
+
categorySchema,
|
|
2091
|
+
controlSchema,
|
|
2092
|
+
createExtensionRegistry,
|
|
2093
|
+
generateJsonSchema,
|
|
2094
|
+
generateJsonSchemaFromIR,
|
|
2095
|
+
generateUiSchema,
|
|
2096
|
+
getSchemaExtension,
|
|
2097
|
+
groupLayoutSchema,
|
|
2098
|
+
horizontalLayoutSchema,
|
|
2099
|
+
jsonSchema7Schema,
|
|
2100
|
+
jsonSchemaTypeSchema,
|
|
2101
|
+
labelElementSchema,
|
|
2102
|
+
ruleConditionSchema,
|
|
2103
|
+
ruleEffectSchema,
|
|
2104
|
+
ruleSchema,
|
|
2105
|
+
schemaBasedConditionSchema,
|
|
2106
|
+
setSchemaExtension,
|
|
2107
|
+
uiSchemaElementSchema,
|
|
2108
|
+
uiSchemaElementTypeSchema,
|
|
2109
|
+
uiSchemaSchema,
|
|
2110
|
+
validateIR,
|
|
2111
|
+
verticalLayoutSchema
|
|
2112
|
+
});
|
|
2113
|
+
//# sourceMappingURL=browser.cjs.map
|