@formspec/build 0.1.0-alpha.40 → 0.1.0-alpha.42
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/dist/browser.cjs +305 -23
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +305 -23
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +10 -0
- package/dist/build-beta.d.ts +10 -0
- package/dist/build-internal.d.ts +10 -0
- package/dist/build.d.ts +10 -0
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -1
- package/dist/cli.cjs +243 -33
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +243 -33
- package/dist/cli.js.map +1 -1
- package/dist/generators/class-schema.d.ts +5 -0
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/discovered-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts +9 -2
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/index.cjs +222 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +222 -30
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +199 -33
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +199 -33
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts +5 -0
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts +5 -0
- package/dist/json-schema/ir-generator.d.ts.map +1 -1
- package/dist/metadata/policy.d.ts +3 -2
- package/dist/metadata/policy.d.ts.map +1 -1
- package/dist/metadata/resolve.d.ts +1 -0
- package/dist/metadata/resolve.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/internals.cjs
CHANGED
|
@@ -106,11 +106,35 @@ function normalizeDeclarationPolicy(input) {
|
|
|
106
106
|
displayName: normalizeScalarPolicy(input?.displayName)
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
|
+
function normalizeEnumMemberDisplayNamePolicy(input) {
|
|
110
|
+
if (input?.mode === "infer-if-missing") {
|
|
111
|
+
return {
|
|
112
|
+
mode: "infer-if-missing",
|
|
113
|
+
infer: input.infer
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (input?.mode === "require-explicit") {
|
|
117
|
+
return {
|
|
118
|
+
mode: "require-explicit",
|
|
119
|
+
infer: () => ""
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
mode: "disabled",
|
|
124
|
+
infer: () => ""
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function normalizeEnumMemberPolicy(input) {
|
|
128
|
+
return {
|
|
129
|
+
displayName: normalizeEnumMemberDisplayNamePolicy(input?.displayName)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
109
132
|
function normalizeMetadataPolicy(input) {
|
|
110
133
|
return {
|
|
111
134
|
type: normalizeDeclarationPolicy(input?.type),
|
|
112
135
|
field: normalizeDeclarationPolicy(input?.field),
|
|
113
|
-
method: normalizeDeclarationPolicy(input?.method)
|
|
136
|
+
method: normalizeDeclarationPolicy(input?.method),
|
|
137
|
+
enumMember: normalizeEnumMemberPolicy(input?.enumMember)
|
|
114
138
|
};
|
|
115
139
|
}
|
|
116
140
|
function getDeclarationMetadataPolicy(policy, declarationKind) {
|
|
@@ -207,6 +231,40 @@ function resolveResolvedMetadata(current, policy, context) {
|
|
|
207
231
|
...displayNamePlural !== void 0 && { displayNamePlural }
|
|
208
232
|
};
|
|
209
233
|
}
|
|
234
|
+
function resolveEnumMemberDisplayName(current, policy, context) {
|
|
235
|
+
if (current !== void 0) {
|
|
236
|
+
return current;
|
|
237
|
+
}
|
|
238
|
+
if (policy.mode === "require-explicit") {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`Metadata policy requires explicit displayName for enum member "${context.logicalName}" on the ${context.surface} surface.`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (policy.mode !== "infer-if-missing") {
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
const inferredValue = policy.infer(context).trim();
|
|
247
|
+
return inferredValue !== "" ? inferredValue : void 0;
|
|
248
|
+
}
|
|
249
|
+
function resolveEnumTypeMetadata(type, options) {
|
|
250
|
+
const members = type.members.map((member) => {
|
|
251
|
+
const displayName = resolveEnumMemberDisplayName(
|
|
252
|
+
member.displayName,
|
|
253
|
+
options.policy.enumMember.displayName,
|
|
254
|
+
{
|
|
255
|
+
surface: options.surface,
|
|
256
|
+
logicalName: String(member.value),
|
|
257
|
+
memberValue: member.value,
|
|
258
|
+
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
if (displayName === member.displayName) {
|
|
262
|
+
return member;
|
|
263
|
+
}
|
|
264
|
+
return displayName === void 0 ? { value: member.value } : { value: member.value, displayName };
|
|
265
|
+
});
|
|
266
|
+
return members.some((member, index) => member !== type.members[index]) ? { ...type, members } : type;
|
|
267
|
+
}
|
|
210
268
|
function resolveTypeNodeMetadata(type, options) {
|
|
211
269
|
switch (type.kind) {
|
|
212
270
|
case "array":
|
|
@@ -229,9 +287,10 @@ function resolveTypeNodeMetadata(type, options) {
|
|
|
229
287
|
...type,
|
|
230
288
|
members: type.members.map((member) => resolveTypeNodeMetadata(member, options))
|
|
231
289
|
};
|
|
290
|
+
case "enum":
|
|
291
|
+
return resolveEnumTypeMetadata(type, options);
|
|
232
292
|
case "reference":
|
|
233
293
|
case "primitive":
|
|
234
|
-
case "enum":
|
|
235
294
|
case "dynamic":
|
|
236
295
|
case "custom":
|
|
237
296
|
return type;
|
|
@@ -310,11 +369,10 @@ function getDisplayName(metadata) {
|
|
|
310
369
|
return metadata?.displayName?.value;
|
|
311
370
|
}
|
|
312
371
|
function resolveFormIRMetadata(ir, options) {
|
|
313
|
-
const
|
|
314
|
-
const metadata = resolveResolvedMetadata(ir.metadata, options.policy.type, {
|
|
372
|
+
const metadata = options.resolveRootTypeMetadata === false ? ir.metadata : resolveResolvedMetadata(ir.metadata, options.policy.type, {
|
|
315
373
|
surface: options.surface,
|
|
316
374
|
declarationKind: "type",
|
|
317
|
-
logicalName: rootLogicalName,
|
|
375
|
+
logicalName: options.rootLogicalName ?? ir.name ?? "FormSpec",
|
|
318
376
|
...options.buildContext !== void 0 && { buildContext: options.buildContext }
|
|
319
377
|
});
|
|
320
378
|
return {
|
|
@@ -350,7 +408,7 @@ function canonicalizeChainDSL(form, options) {
|
|
|
350
408
|
const metadataPolicy = normalizeMetadataPolicy(
|
|
351
409
|
options?.metadata ?? (0, import_internals._getFormSpecMetadataPolicy)(form)
|
|
352
410
|
);
|
|
353
|
-
|
|
411
|
+
const ir = {
|
|
354
412
|
kind: "form-ir",
|
|
355
413
|
irVersion: import_internals.IR_VERSION,
|
|
356
414
|
elements: canonicalizeElements(form.elements, metadataPolicy),
|
|
@@ -358,6 +416,13 @@ function canonicalizeChainDSL(form, options) {
|
|
|
358
416
|
typeRegistry: {},
|
|
359
417
|
provenance: CHAIN_DSL_PROVENANCE
|
|
360
418
|
};
|
|
419
|
+
return resolveFormIRMetadata(ir, {
|
|
420
|
+
policy: metadataPolicy,
|
|
421
|
+
surface: "chain-dsl",
|
|
422
|
+
// Chain DSL has no root/type-metadata authoring surface, so only resolve
|
|
423
|
+
// field/type-registry metadata and enum-member labels here.
|
|
424
|
+
resolveRootTypeMetadata: false
|
|
425
|
+
});
|
|
361
426
|
}
|
|
362
427
|
function canonicalizeElements(elements, metadataPolicy) {
|
|
363
428
|
return elements.map((element) => canonicalizeElement(element, metadataPolicy));
|
|
@@ -4197,17 +4262,25 @@ function assertNoSerializedNameCollisions(ir) {
|
|
|
4197
4262
|
// src/json-schema/ir-generator.ts
|
|
4198
4263
|
function makeContext(options) {
|
|
4199
4264
|
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
4265
|
+
const rawEnumSerialization = options?.enumSerialization;
|
|
4200
4266
|
if (!vendorPrefix.startsWith("x-")) {
|
|
4201
4267
|
throw new Error(
|
|
4202
4268
|
`Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
|
|
4203
4269
|
);
|
|
4204
4270
|
}
|
|
4271
|
+
if (rawEnumSerialization !== void 0 && rawEnumSerialization !== "enum" && rawEnumSerialization !== "oneOf") {
|
|
4272
|
+
throw new Error(
|
|
4273
|
+
`Invalid enumSerialization "${rawEnumSerialization}". Expected "enum" or "oneOf".`
|
|
4274
|
+
);
|
|
4275
|
+
}
|
|
4276
|
+
const enumSerialization = rawEnumSerialization ?? "enum";
|
|
4205
4277
|
return {
|
|
4206
4278
|
defs: {},
|
|
4207
4279
|
typeNameMap: {},
|
|
4208
4280
|
typeRegistry: {},
|
|
4209
4281
|
extensionRegistry: options?.extensionRegistry,
|
|
4210
|
-
vendorPrefix
|
|
4282
|
+
vendorPrefix,
|
|
4283
|
+
enumSerialization
|
|
4211
4284
|
};
|
|
4212
4285
|
}
|
|
4213
4286
|
function generateJsonSchemaFromIR(ir, options) {
|
|
@@ -4381,7 +4454,7 @@ function generateTypeNode(type, ctx) {
|
|
|
4381
4454
|
case "primitive":
|
|
4382
4455
|
return generatePrimitiveType(type);
|
|
4383
4456
|
case "enum":
|
|
4384
|
-
return generateEnumType(type);
|
|
4457
|
+
return generateEnumType(type, ctx);
|
|
4385
4458
|
case "array":
|
|
4386
4459
|
return generateArrayType(type, ctx);
|
|
4387
4460
|
case "object":
|
|
@@ -4407,20 +4480,37 @@ function generatePrimitiveType(type) {
|
|
|
4407
4480
|
type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
|
|
4408
4481
|
};
|
|
4409
4482
|
}
|
|
4410
|
-
function generateEnumType(type) {
|
|
4411
|
-
|
|
4412
|
-
if (hasDisplayNames) {
|
|
4483
|
+
function generateEnumType(type, ctx) {
|
|
4484
|
+
if (ctx.enumSerialization === "oneOf") {
|
|
4413
4485
|
return {
|
|
4414
|
-
oneOf: type.members.map((m) => {
|
|
4415
|
-
const
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
}
|
|
4419
|
-
return entry;
|
|
4420
|
-
})
|
|
4486
|
+
oneOf: type.members.map((m) => ({
|
|
4487
|
+
const: m.value,
|
|
4488
|
+
title: m.displayName ?? String(m.value)
|
|
4489
|
+
}))
|
|
4421
4490
|
};
|
|
4422
4491
|
}
|
|
4423
|
-
|
|
4492
|
+
const schema = { enum: type.members.map((m) => m.value) };
|
|
4493
|
+
const displayNames = buildEnumDisplayNameExtension(type);
|
|
4494
|
+
if (displayNames !== void 0) {
|
|
4495
|
+
schema[`${ctx.vendorPrefix}-display-names`] = displayNames;
|
|
4496
|
+
}
|
|
4497
|
+
return schema;
|
|
4498
|
+
}
|
|
4499
|
+
function buildEnumDisplayNameExtension(type) {
|
|
4500
|
+
if (!type.members.some((member) => member.displayName !== void 0)) {
|
|
4501
|
+
return void 0;
|
|
4502
|
+
}
|
|
4503
|
+
const displayNames = /* @__PURE__ */ Object.create(null);
|
|
4504
|
+
for (const member of type.members) {
|
|
4505
|
+
const key = String(member.value);
|
|
4506
|
+
if (Object.hasOwn(displayNames, key)) {
|
|
4507
|
+
throw new Error(
|
|
4508
|
+
`Enum display-name key "${key}" is ambiguous after stringification. Use oneOf serialization for mixed string/number enum values that collide.`
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
displayNames[key] = member.displayName ?? key;
|
|
4512
|
+
}
|
|
4513
|
+
return displayNames;
|
|
4424
4514
|
}
|
|
4425
4515
|
function generateArrayType(type, ctx) {
|
|
4426
4516
|
return {
|
|
@@ -4769,6 +4859,66 @@ function generateCustomType(type, ctx) {
|
|
|
4769
4859
|
}
|
|
4770
4860
|
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
4771
4861
|
}
|
|
4862
|
+
var JSON_SCHEMA_STRUCTURAL_KEYWORDS = /* @__PURE__ */ new Set([
|
|
4863
|
+
"$schema",
|
|
4864
|
+
"$ref",
|
|
4865
|
+
"$defs",
|
|
4866
|
+
"$id",
|
|
4867
|
+
"$anchor",
|
|
4868
|
+
"$dynamicRef",
|
|
4869
|
+
"$dynamicAnchor",
|
|
4870
|
+
"$vocabulary",
|
|
4871
|
+
"$comment",
|
|
4872
|
+
"type",
|
|
4873
|
+
"enum",
|
|
4874
|
+
"const",
|
|
4875
|
+
"properties",
|
|
4876
|
+
"patternProperties",
|
|
4877
|
+
"additionalProperties",
|
|
4878
|
+
"required",
|
|
4879
|
+
"items",
|
|
4880
|
+
"prefixItems",
|
|
4881
|
+
"additionalItems",
|
|
4882
|
+
"contains",
|
|
4883
|
+
"allOf",
|
|
4884
|
+
"oneOf",
|
|
4885
|
+
"anyOf",
|
|
4886
|
+
"not",
|
|
4887
|
+
"if",
|
|
4888
|
+
"then",
|
|
4889
|
+
"else",
|
|
4890
|
+
"minimum",
|
|
4891
|
+
"maximum",
|
|
4892
|
+
"exclusiveMinimum",
|
|
4893
|
+
"exclusiveMaximum",
|
|
4894
|
+
"multipleOf",
|
|
4895
|
+
"minLength",
|
|
4896
|
+
"maxLength",
|
|
4897
|
+
"pattern",
|
|
4898
|
+
"minItems",
|
|
4899
|
+
"maxItems",
|
|
4900
|
+
"uniqueItems",
|
|
4901
|
+
"minProperties",
|
|
4902
|
+
"maxProperties",
|
|
4903
|
+
"minContains",
|
|
4904
|
+
"maxContains",
|
|
4905
|
+
"format",
|
|
4906
|
+
"title",
|
|
4907
|
+
"description",
|
|
4908
|
+
"default",
|
|
4909
|
+
"deprecated",
|
|
4910
|
+
"readOnly",
|
|
4911
|
+
"writeOnly",
|
|
4912
|
+
"examples",
|
|
4913
|
+
"dependentRequired",
|
|
4914
|
+
"dependentSchemas",
|
|
4915
|
+
"propertyNames",
|
|
4916
|
+
"unevaluatedItems",
|
|
4917
|
+
"unevaluatedProperties",
|
|
4918
|
+
"contentEncoding",
|
|
4919
|
+
"contentMediaType",
|
|
4920
|
+
"contentSchema"
|
|
4921
|
+
]);
|
|
4772
4922
|
function applyCustomConstraint(schema, constraint, ctx) {
|
|
4773
4923
|
const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);
|
|
4774
4924
|
if (registration === void 0) {
|
|
@@ -4776,12 +4926,25 @@ function applyCustomConstraint(schema, constraint, ctx) {
|
|
|
4776
4926
|
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
4777
4927
|
);
|
|
4778
4928
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4929
|
+
const extensionSchema = registration.toJsonSchema(constraint.payload, ctx.vendorPrefix);
|
|
4930
|
+
if (registration.emitsVocabularyKeywords) {
|
|
4931
|
+
const target = schema;
|
|
4932
|
+
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
4933
|
+
if (JSON_SCHEMA_STRUCTURAL_KEYWORDS.has(key)) {
|
|
4934
|
+
throw new Error(
|
|
4935
|
+
`Custom constraint "${constraint.constraintId}" with emitsVocabularyKeywords must not overwrite standard JSON Schema keyword "${key}"`
|
|
4936
|
+
);
|
|
4937
|
+
}
|
|
4938
|
+
target[key] = value;
|
|
4939
|
+
}
|
|
4940
|
+
} else {
|
|
4941
|
+
assignVendorPrefixedExtensionKeywords(
|
|
4942
|
+
schema,
|
|
4943
|
+
extensionSchema,
|
|
4944
|
+
ctx.vendorPrefix,
|
|
4945
|
+
`custom constraint "${constraint.constraintId}"`
|
|
4946
|
+
);
|
|
4947
|
+
}
|
|
4785
4948
|
}
|
|
4786
4949
|
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
4787
4950
|
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
@@ -5337,7 +5500,7 @@ function createExtensionRegistry(extensions) {
|
|
|
5337
5500
|
|
|
5338
5501
|
// src/generators/method-schema.ts
|
|
5339
5502
|
var import_internals6 = require("@formspec/core/internals");
|
|
5340
|
-
function typeToJsonSchema(type, checker) {
|
|
5503
|
+
function typeToJsonSchema(type, checker, options) {
|
|
5341
5504
|
const typeRegistry = {};
|
|
5342
5505
|
const visiting = /* @__PURE__ */ new Set();
|
|
5343
5506
|
const diagnostics = [];
|
|
@@ -5377,7 +5540,10 @@ function typeToJsonSchema(type, checker) {
|
|
|
5377
5540
|
typeRegistry,
|
|
5378
5541
|
provenance: fieldProvenance
|
|
5379
5542
|
};
|
|
5380
|
-
const schema = generateJsonSchemaFromIR(
|
|
5543
|
+
const schema = generateJsonSchemaFromIR(
|
|
5544
|
+
ir,
|
|
5545
|
+
options?.enumSerialization === void 0 ? void 0 : { enumSerialization: options.enumSerialization }
|
|
5546
|
+
);
|
|
5381
5547
|
const fieldSchema = schema.properties?.["__result"];
|
|
5382
5548
|
if (fieldSchema) {
|
|
5383
5549
|
if (schema.$defs && Object.keys(schema.$defs).length > 0) {
|
|
@@ -5387,16 +5553,16 @@ function typeToJsonSchema(type, checker) {
|
|
|
5387
5553
|
}
|
|
5388
5554
|
return { type: "object" };
|
|
5389
5555
|
}
|
|
5390
|
-
function generateMethodSchemas(method, checker, loadedFormSpecs) {
|
|
5391
|
-
const returnType = typeToJsonSchema(method.returnType, checker);
|
|
5392
|
-
const params = generateParamsSchemas(method.parameters, checker, loadedFormSpecs);
|
|
5556
|
+
function generateMethodSchemas(method, checker, loadedFormSpecs, options) {
|
|
5557
|
+
const returnType = typeToJsonSchema(method.returnType, checker, options);
|
|
5558
|
+
const params = generateParamsSchemas(method.parameters, checker, loadedFormSpecs, options);
|
|
5393
5559
|
return {
|
|
5394
5560
|
name: method.name,
|
|
5395
5561
|
params,
|
|
5396
5562
|
returnType
|
|
5397
5563
|
};
|
|
5398
5564
|
}
|
|
5399
|
-
function generateParamsSchemas(parameters, checker, loadedFormSpecs) {
|
|
5565
|
+
function generateParamsSchemas(parameters, checker, loadedFormSpecs, options) {
|
|
5400
5566
|
if (parameters.length === 0) {
|
|
5401
5567
|
return null;
|
|
5402
5568
|
}
|
|
@@ -5417,7 +5583,7 @@ function generateParamsSchemas(parameters, checker, loadedFormSpecs) {
|
|
|
5417
5583
|
}
|
|
5418
5584
|
if (parameters.length === 1 && parameters[0]) {
|
|
5419
5585
|
const param = parameters[0];
|
|
5420
|
-
const jsonSchema = typeToJsonSchema(param.type, checker);
|
|
5586
|
+
const jsonSchema = typeToJsonSchema(param.type, checker, options);
|
|
5421
5587
|
return {
|
|
5422
5588
|
jsonSchema,
|
|
5423
5589
|
uiSchema: null,
|
|
@@ -5427,7 +5593,7 @@ function generateParamsSchemas(parameters, checker, loadedFormSpecs) {
|
|
|
5427
5593
|
const properties = {};
|
|
5428
5594
|
const required = [];
|
|
5429
5595
|
for (const param of parameters) {
|
|
5430
|
-
const paramSchema = typeToJsonSchema(param.type, checker);
|
|
5596
|
+
const paramSchema = typeToJsonSchema(param.type, checker, options);
|
|
5431
5597
|
properties[param.name] = paramSchema;
|
|
5432
5598
|
if (!param.optional) {
|
|
5433
5599
|
required.push(param.name);
|