@formspec/build 0.1.0-alpha.14 → 0.1.0-alpha.15
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/__tests__/extension-runtime.integration.test.d.ts +2 -0
- package/dist/__tests__/extension-runtime.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fixtures/edge-cases.d.ts +11 -0
- package/dist/__tests__/fixtures/edge-cases.d.ts.map +1 -1
- package/dist/__tests__/fixtures/example-a-builtins.d.ts +6 -6
- package/dist/__tests__/fixtures/example-interface-types.d.ts +26 -26
- package/dist/__tests__/fixtures/example-interface-types.d.ts.map +1 -1
- package/dist/__tests__/jsdoc-constraints.test.d.ts +4 -5
- package/dist/__tests__/jsdoc-constraints.test.d.ts.map +1 -1
- package/dist/__tests__/parity/fixtures/plan-status/chain-dsl.d.ts +19 -0
- package/dist/__tests__/parity/fixtures/plan-status/chain-dsl.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/plan-status/expected-ir.d.ts +6 -0
- package/dist/__tests__/parity/fixtures/plan-status/expected-ir.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/plan-status/tsdoc.d.ts +17 -0
- package/dist/__tests__/parity/fixtures/plan-status/tsdoc.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/usd-cents/chain-dsl.d.ts +9 -0
- package/dist/__tests__/parity/fixtures/usd-cents/chain-dsl.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/usd-cents/expected-ir.d.ts +6 -0
- package/dist/__tests__/parity/fixtures/usd-cents/expected-ir.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/usd-cents/tsdoc.d.ts +19 -0
- package/dist/__tests__/parity/fixtures/usd-cents/tsdoc.d.ts.map +1 -0
- package/dist/__tests__/parity/utils.d.ts +6 -1
- package/dist/__tests__/parity/utils.d.ts.map +1 -1
- package/dist/analyzer/class-analyzer.d.ts +1 -1
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/jsdoc-constraints.d.ts +7 -51
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +6 -8
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +387 -98
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +15 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +385 -98
- package/dist/browser.js.map +1 -1
- package/dist/build.d.ts +131 -5
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +3 -3
- package/dist/cli.cjs +272 -69
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +271 -72
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +257 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +20 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +255 -71
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +461 -137
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +459 -139
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts +8 -2
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts +24 -2
- package/dist/json-schema/ir-generator.d.ts.map +1 -1
- package/dist/json-schema/types.d.ts +1 -1
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/validate/constraint-validator.d.ts +3 -7
- package/dist/validate/constraint-validator.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -202,7 +202,7 @@ function canonicalizeArrayField(field) {
|
|
|
202
202
|
const itemsType = {
|
|
203
203
|
kind: "object",
|
|
204
204
|
properties: itemProperties,
|
|
205
|
-
additionalProperties:
|
|
205
|
+
additionalProperties: true
|
|
206
206
|
};
|
|
207
207
|
const type = { kind: "array", items: itemsType };
|
|
208
208
|
const constraints = [];
|
|
@@ -237,7 +237,7 @@ function canonicalizeObjectField(field) {
|
|
|
237
237
|
const type = {
|
|
238
238
|
kind: "object",
|
|
239
239
|
properties,
|
|
240
|
-
additionalProperties:
|
|
240
|
+
additionalProperties: true
|
|
241
241
|
};
|
|
242
242
|
return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
|
|
243
243
|
}
|
|
@@ -437,11 +437,21 @@ var init_canonicalize = __esm({
|
|
|
437
437
|
});
|
|
438
438
|
|
|
439
439
|
// src/json-schema/ir-generator.ts
|
|
440
|
-
function makeContext() {
|
|
441
|
-
|
|
440
|
+
function makeContext(options) {
|
|
441
|
+
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
442
|
+
if (!vendorPrefix.startsWith("x-")) {
|
|
443
|
+
throw new Error(
|
|
444
|
+
`Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
defs: {},
|
|
449
|
+
extensionRegistry: options?.extensionRegistry,
|
|
450
|
+
vendorPrefix
|
|
451
|
+
};
|
|
442
452
|
}
|
|
443
|
-
function generateJsonSchemaFromIR(ir) {
|
|
444
|
-
const ctx = makeContext();
|
|
453
|
+
function generateJsonSchemaFromIR(ir, options) {
|
|
454
|
+
const ctx = makeContext(options);
|
|
445
455
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
446
456
|
ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
|
|
447
457
|
}
|
|
@@ -493,16 +503,16 @@ function generateFieldSchema(field, ctx) {
|
|
|
493
503
|
directConstraints.push(c);
|
|
494
504
|
}
|
|
495
505
|
}
|
|
496
|
-
applyConstraints(schema, directConstraints);
|
|
497
|
-
applyAnnotations(schema, field.annotations);
|
|
506
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
507
|
+
applyAnnotations(schema, field.annotations, ctx);
|
|
498
508
|
if (pathConstraints.length === 0) {
|
|
499
509
|
return schema;
|
|
500
510
|
}
|
|
501
|
-
return applyPathTargetedConstraints(schema, pathConstraints);
|
|
511
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx);
|
|
502
512
|
}
|
|
503
|
-
function applyPathTargetedConstraints(schema, pathConstraints) {
|
|
513
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
504
514
|
if (schema.type === "array" && schema.items) {
|
|
505
|
-
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints);
|
|
515
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx);
|
|
506
516
|
return schema;
|
|
507
517
|
}
|
|
508
518
|
const byTarget = /* @__PURE__ */ new Map();
|
|
@@ -516,7 +526,7 @@ function applyPathTargetedConstraints(schema, pathConstraints) {
|
|
|
516
526
|
const propertyOverrides = {};
|
|
517
527
|
for (const [target, constraints] of byTarget) {
|
|
518
528
|
const subSchema = {};
|
|
519
|
-
applyConstraints(subSchema, constraints);
|
|
529
|
+
applyConstraints(subSchema, constraints, ctx);
|
|
520
530
|
propertyOverrides[target] = subSchema;
|
|
521
531
|
}
|
|
522
532
|
if (schema.$ref) {
|
|
@@ -560,6 +570,8 @@ function generateTypeNode(type, ctx) {
|
|
|
560
570
|
return generateArrayType(type, ctx);
|
|
561
571
|
case "object":
|
|
562
572
|
return generateObjectType(type, ctx);
|
|
573
|
+
case "record":
|
|
574
|
+
return generateRecordType(type, ctx);
|
|
563
575
|
case "union":
|
|
564
576
|
return generateUnionType(type, ctx);
|
|
565
577
|
case "reference":
|
|
@@ -567,7 +579,7 @@ function generateTypeNode(type, ctx) {
|
|
|
567
579
|
case "dynamic":
|
|
568
580
|
return generateDynamicType(type);
|
|
569
581
|
case "custom":
|
|
570
|
-
return generateCustomType(type);
|
|
582
|
+
return generateCustomType(type, ctx);
|
|
571
583
|
default: {
|
|
572
584
|
const _exhaustive = type;
|
|
573
585
|
return _exhaustive;
|
|
@@ -616,16 +628,27 @@ function generateObjectType(type, ctx) {
|
|
|
616
628
|
}
|
|
617
629
|
return schema;
|
|
618
630
|
}
|
|
631
|
+
function generateRecordType(type, ctx) {
|
|
632
|
+
return {
|
|
633
|
+
type: "object",
|
|
634
|
+
additionalProperties: generateTypeNode(type.valueType, ctx)
|
|
635
|
+
};
|
|
636
|
+
}
|
|
619
637
|
function generatePropertySchema(prop, ctx) {
|
|
620
638
|
const schema = generateTypeNode(prop.type, ctx);
|
|
621
|
-
applyConstraints(schema, prop.constraints);
|
|
622
|
-
applyAnnotations(schema, prop.annotations);
|
|
639
|
+
applyConstraints(schema, prop.constraints, ctx);
|
|
640
|
+
applyAnnotations(schema, prop.annotations, ctx);
|
|
623
641
|
return schema;
|
|
624
642
|
}
|
|
625
643
|
function generateUnionType(type, ctx) {
|
|
626
644
|
if (isBooleanUnion(type)) {
|
|
627
645
|
return { type: "boolean" };
|
|
628
646
|
}
|
|
647
|
+
if (isNullableUnion(type)) {
|
|
648
|
+
return {
|
|
649
|
+
oneOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
650
|
+
};
|
|
651
|
+
}
|
|
629
652
|
return {
|
|
630
653
|
anyOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
631
654
|
};
|
|
@@ -635,6 +658,13 @@ function isBooleanUnion(type) {
|
|
|
635
658
|
const kinds = type.members.map((m) => m.kind);
|
|
636
659
|
return kinds.every((k) => k === "primitive") && type.members.every((m) => m.kind === "primitive" && m.primitiveKind === "boolean");
|
|
637
660
|
}
|
|
661
|
+
function isNullableUnion(type) {
|
|
662
|
+
if (type.members.length !== 2) return false;
|
|
663
|
+
const nullCount = type.members.filter(
|
|
664
|
+
(m) => m.kind === "primitive" && m.primitiveKind === "null"
|
|
665
|
+
).length;
|
|
666
|
+
return nullCount === 1;
|
|
667
|
+
}
|
|
638
668
|
function generateReferenceType(type) {
|
|
639
669
|
return { $ref: `#/$defs/${type.name}` };
|
|
640
670
|
}
|
|
@@ -655,10 +685,7 @@ function generateDynamicType(type) {
|
|
|
655
685
|
"x-formspec-schemaSource": type.sourceKey
|
|
656
686
|
};
|
|
657
687
|
}
|
|
658
|
-
function
|
|
659
|
-
return { type: "object" };
|
|
660
|
-
}
|
|
661
|
-
function applyConstraints(schema, constraints) {
|
|
688
|
+
function applyConstraints(schema, constraints, ctx) {
|
|
662
689
|
for (const constraint of constraints) {
|
|
663
690
|
switch (constraint.constraintKind) {
|
|
664
691
|
case "minimum":
|
|
@@ -703,6 +730,7 @@ function applyConstraints(schema, constraints) {
|
|
|
703
730
|
case "allowedMembers":
|
|
704
731
|
break;
|
|
705
732
|
case "custom":
|
|
733
|
+
applyCustomConstraint(schema, constraint, ctx);
|
|
706
734
|
break;
|
|
707
735
|
default: {
|
|
708
736
|
const _exhaustive = constraint;
|
|
@@ -711,7 +739,7 @@ function applyConstraints(schema, constraints) {
|
|
|
711
739
|
}
|
|
712
740
|
}
|
|
713
741
|
}
|
|
714
|
-
function applyAnnotations(schema, annotations) {
|
|
742
|
+
function applyAnnotations(schema, annotations, ctx) {
|
|
715
743
|
for (const annotation of annotations) {
|
|
716
744
|
switch (annotation.annotationKind) {
|
|
717
745
|
case "displayName":
|
|
@@ -731,6 +759,7 @@ function applyAnnotations(schema, annotations) {
|
|
|
731
759
|
case "formatHint":
|
|
732
760
|
break;
|
|
733
761
|
case "custom":
|
|
762
|
+
applyCustomAnnotation(schema, annotation, ctx);
|
|
734
763
|
break;
|
|
735
764
|
default: {
|
|
736
765
|
const _exhaustive = annotation;
|
|
@@ -739,6 +768,36 @@ function applyAnnotations(schema, annotations) {
|
|
|
739
768
|
}
|
|
740
769
|
}
|
|
741
770
|
}
|
|
771
|
+
function generateCustomType(type, ctx) {
|
|
772
|
+
const registration = ctx.extensionRegistry?.findType(type.typeId);
|
|
773
|
+
if (registration === void 0) {
|
|
774
|
+
throw new Error(
|
|
775
|
+
`Cannot generate JSON Schema for custom type "${type.typeId}" without a matching extension registration`
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
779
|
+
}
|
|
780
|
+
function applyCustomConstraint(schema, constraint, ctx) {
|
|
781
|
+
const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);
|
|
782
|
+
if (registration === void 0) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
Object.assign(schema, registration.toJsonSchema(constraint.payload, ctx.vendorPrefix));
|
|
788
|
+
}
|
|
789
|
+
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
790
|
+
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
791
|
+
if (registration === void 0) {
|
|
792
|
+
throw new Error(
|
|
793
|
+
`Cannot generate JSON Schema for custom annotation "${annotation.annotationId}" without a matching extension registration`
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
if (registration.toJsonSchema === void 0) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
Object.assign(schema, registration.toJsonSchema(annotation.value, ctx.vendorPrefix));
|
|
800
|
+
}
|
|
742
801
|
var init_ir_generator = __esm({
|
|
743
802
|
"src/json-schema/ir-generator.ts"() {
|
|
744
803
|
"use strict";
|
|
@@ -746,9 +805,9 @@ var init_ir_generator = __esm({
|
|
|
746
805
|
});
|
|
747
806
|
|
|
748
807
|
// src/json-schema/generator.ts
|
|
749
|
-
function generateJsonSchema(form) {
|
|
808
|
+
function generateJsonSchema(form, options) {
|
|
750
809
|
const ir = canonicalizeChainDSL(form);
|
|
751
|
-
return generateJsonSchemaFromIR(ir);
|
|
810
|
+
return generateJsonSchemaFromIR(ir, options);
|
|
752
811
|
}
|
|
753
812
|
var init_generator = __esm({
|
|
754
813
|
"src/json-schema/generator.ts"() {
|
|
@@ -1010,6 +1069,61 @@ var init_types = __esm({
|
|
|
1010
1069
|
}
|
|
1011
1070
|
});
|
|
1012
1071
|
|
|
1072
|
+
// src/extensions/registry.ts
|
|
1073
|
+
function createExtensionRegistry(extensions) {
|
|
1074
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
1075
|
+
const constraintMap = /* @__PURE__ */ new Map();
|
|
1076
|
+
const annotationMap = /* @__PURE__ */ new Map();
|
|
1077
|
+
for (const ext of extensions) {
|
|
1078
|
+
if (ext.types !== void 0) {
|
|
1079
|
+
for (const type of ext.types) {
|
|
1080
|
+
const qualifiedId = `${ext.extensionId}/${type.typeName}`;
|
|
1081
|
+
if (typeMap.has(qualifiedId)) {
|
|
1082
|
+
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
1083
|
+
}
|
|
1084
|
+
typeMap.set(qualifiedId, type);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (ext.constraints !== void 0) {
|
|
1088
|
+
for (const constraint of ext.constraints) {
|
|
1089
|
+
const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
|
|
1090
|
+
if (constraintMap.has(qualifiedId)) {
|
|
1091
|
+
throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
|
|
1092
|
+
}
|
|
1093
|
+
constraintMap.set(qualifiedId, constraint);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (ext.annotations !== void 0) {
|
|
1097
|
+
for (const annotation of ext.annotations) {
|
|
1098
|
+
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
1099
|
+
if (annotationMap.has(qualifiedId)) {
|
|
1100
|
+
throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
|
|
1101
|
+
}
|
|
1102
|
+
annotationMap.set(qualifiedId, annotation);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
return {
|
|
1107
|
+
extensions,
|
|
1108
|
+
findType: (typeId) => typeMap.get(typeId),
|
|
1109
|
+
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1110
|
+
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
var init_registry = __esm({
|
|
1114
|
+
"src/extensions/registry.ts"() {
|
|
1115
|
+
"use strict";
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
// src/extensions/index.ts
|
|
1120
|
+
var init_extensions = __esm({
|
|
1121
|
+
"src/extensions/index.ts"() {
|
|
1122
|
+
"use strict";
|
|
1123
|
+
init_registry();
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1013
1127
|
// src/json-schema/schema.ts
|
|
1014
1128
|
var import_zod3, jsonSchemaTypeSchema, jsonSchema7Schema;
|
|
1015
1129
|
var init_schema2 = __esm({
|
|
@@ -1182,6 +1296,15 @@ function createFormSpecTSDocConfig() {
|
|
|
1182
1296
|
})
|
|
1183
1297
|
);
|
|
1184
1298
|
}
|
|
1299
|
+
for (const tagName of ["displayName", "description"]) {
|
|
1300
|
+
config.addTagDefinition(
|
|
1301
|
+
new import_tsdoc.TSDocTagDefinition({
|
|
1302
|
+
tagName: "@" + tagName,
|
|
1303
|
+
syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
|
|
1304
|
+
allowMultiple: true
|
|
1305
|
+
})
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1185
1308
|
return config;
|
|
1186
1309
|
}
|
|
1187
1310
|
function getParser() {
|
|
@@ -1210,6 +1333,27 @@ function parseTSDocTags(node, file = "") {
|
|
|
1210
1333
|
const docComment = parserContext.docComment;
|
|
1211
1334
|
for (const block of docComment.customBlocks) {
|
|
1212
1335
|
const tagName = (0, import_core3.normalizeConstraintTagName)(block.blockTag.tagName.substring(1));
|
|
1336
|
+
if (tagName === "displayName" || tagName === "description") {
|
|
1337
|
+
const text2 = extractBlockText(block).trim();
|
|
1338
|
+
if (text2 === "") continue;
|
|
1339
|
+
const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
|
|
1340
|
+
if (tagName === "displayName") {
|
|
1341
|
+
annotations.push({
|
|
1342
|
+
kind: "annotation",
|
|
1343
|
+
annotationKind: "displayName",
|
|
1344
|
+
value: text2,
|
|
1345
|
+
provenance: provenance2
|
|
1346
|
+
});
|
|
1347
|
+
} else {
|
|
1348
|
+
annotations.push({
|
|
1349
|
+
kind: "annotation",
|
|
1350
|
+
annotationKind: "description",
|
|
1351
|
+
value: text2,
|
|
1352
|
+
provenance: provenance2
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
continue;
|
|
1356
|
+
}
|
|
1213
1357
|
if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
|
|
1214
1358
|
const text = extractBlockText(block).trim();
|
|
1215
1359
|
if (text === "") continue;
|
|
@@ -1241,41 +1385,6 @@ function parseTSDocTags(node, file = "") {
|
|
|
1241
1385
|
constraints.push(constraintNode);
|
|
1242
1386
|
}
|
|
1243
1387
|
}
|
|
1244
|
-
let displayName;
|
|
1245
|
-
let description;
|
|
1246
|
-
let displayNameTag;
|
|
1247
|
-
let descriptionTag;
|
|
1248
|
-
for (const tag of jsDocTagsAll) {
|
|
1249
|
-
const tagName = tag.tagName.text;
|
|
1250
|
-
const commentText = getTagCommentText(tag);
|
|
1251
|
-
if (commentText === void 0 || commentText.trim() === "") {
|
|
1252
|
-
continue;
|
|
1253
|
-
}
|
|
1254
|
-
const trimmed = commentText.trim();
|
|
1255
|
-
if (tagName === "Field_displayName") {
|
|
1256
|
-
displayName = trimmed;
|
|
1257
|
-
displayNameTag = tag;
|
|
1258
|
-
} else if (tagName === "Field_description") {
|
|
1259
|
-
description = trimmed;
|
|
1260
|
-
descriptionTag = tag;
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
if (displayName !== void 0 && displayNameTag) {
|
|
1264
|
-
annotations.push({
|
|
1265
|
-
kind: "annotation",
|
|
1266
|
-
annotationKind: "displayName",
|
|
1267
|
-
value: displayName,
|
|
1268
|
-
provenance: provenanceForJSDocTag(displayNameTag, file)
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
|
-
if (description !== void 0 && descriptionTag) {
|
|
1272
|
-
annotations.push({
|
|
1273
|
-
kind: "annotation",
|
|
1274
|
-
annotationKind: "description",
|
|
1275
|
-
value: description,
|
|
1276
|
-
provenance: provenanceForJSDocTag(descriptionTag, file)
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
1388
|
return { constraints, annotations };
|
|
1280
1389
|
}
|
|
1281
1390
|
function extractPathTarget(text) {
|
|
@@ -1469,14 +1578,12 @@ function extractDefaultValueAnnotation(initializer, file = "") {
|
|
|
1469
1578
|
}
|
|
1470
1579
|
};
|
|
1471
1580
|
}
|
|
1472
|
-
var ts3
|
|
1581
|
+
var ts3;
|
|
1473
1582
|
var init_jsdoc_constraints = __esm({
|
|
1474
1583
|
"src/analyzer/jsdoc-constraints.ts"() {
|
|
1475
1584
|
"use strict";
|
|
1476
1585
|
ts3 = __toESM(require("typescript"), 1);
|
|
1477
|
-
import_core4 = require("@formspec/core");
|
|
1478
1586
|
init_tsdoc_parser();
|
|
1479
|
-
init_json_utils();
|
|
1480
1587
|
}
|
|
1481
1588
|
});
|
|
1482
1589
|
|
|
@@ -1574,18 +1681,19 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
|
1574
1681
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1575
1682
|
const optional = prop.questionToken !== void 0;
|
|
1576
1683
|
const provenance = provenanceForNode(prop, file);
|
|
1577
|
-
|
|
1684
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1578
1685
|
const constraints = [];
|
|
1579
1686
|
if (prop.type) {
|
|
1580
1687
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1581
1688
|
}
|
|
1582
1689
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1583
|
-
|
|
1690
|
+
let annotations = [];
|
|
1584
1691
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1585
1692
|
const defaultAnnotation = extractDefaultValueAnnotation(prop.initializer, file);
|
|
1586
1693
|
if (defaultAnnotation) {
|
|
1587
1694
|
annotations.push(defaultAnnotation);
|
|
1588
1695
|
}
|
|
1696
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1589
1697
|
return {
|
|
1590
1698
|
kind: "field",
|
|
1591
1699
|
name,
|
|
@@ -1604,14 +1712,15 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1604
1712
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1605
1713
|
const optional = prop.questionToken !== void 0;
|
|
1606
1714
|
const provenance = provenanceForNode(prop, file);
|
|
1607
|
-
|
|
1715
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1608
1716
|
const constraints = [];
|
|
1609
1717
|
if (prop.type) {
|
|
1610
1718
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1611
1719
|
}
|
|
1612
1720
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1613
|
-
|
|
1721
|
+
let annotations = [];
|
|
1614
1722
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1723
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1615
1724
|
return {
|
|
1616
1725
|
kind: "field",
|
|
1617
1726
|
name,
|
|
@@ -1622,6 +1731,68 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1622
1731
|
provenance
|
|
1623
1732
|
};
|
|
1624
1733
|
}
|
|
1734
|
+
function applyEnumMemberDisplayNames(type, annotations) {
|
|
1735
|
+
if (!annotations.some(
|
|
1736
|
+
(annotation) => annotation.annotationKind === "displayName" && annotation.value.trim().startsWith(":")
|
|
1737
|
+
)) {
|
|
1738
|
+
return { type, annotations: [...annotations] };
|
|
1739
|
+
}
|
|
1740
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1741
|
+
const nextType = rewriteEnumDisplayNames(type, annotations, consumed);
|
|
1742
|
+
if (consumed.size === 0) {
|
|
1743
|
+
return { type, annotations: [...annotations] };
|
|
1744
|
+
}
|
|
1745
|
+
return {
|
|
1746
|
+
type: nextType,
|
|
1747
|
+
annotations: annotations.filter((annotation) => !consumed.has(annotation))
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
function rewriteEnumDisplayNames(type, annotations, consumed) {
|
|
1751
|
+
switch (type.kind) {
|
|
1752
|
+
case "enum":
|
|
1753
|
+
return applyEnumMemberDisplayNamesToEnum(type, annotations, consumed);
|
|
1754
|
+
case "union": {
|
|
1755
|
+
return {
|
|
1756
|
+
...type,
|
|
1757
|
+
members: type.members.map(
|
|
1758
|
+
(member) => rewriteEnumDisplayNames(member, annotations, consumed)
|
|
1759
|
+
)
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
default:
|
|
1763
|
+
return type;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
function applyEnumMemberDisplayNamesToEnum(type, annotations, consumed) {
|
|
1767
|
+
const displayNames = /* @__PURE__ */ new Map();
|
|
1768
|
+
for (const annotation of annotations) {
|
|
1769
|
+
if (annotation.annotationKind !== "displayName") continue;
|
|
1770
|
+
const parsed = parseEnumMemberDisplayName(annotation.value);
|
|
1771
|
+
if (!parsed) continue;
|
|
1772
|
+
consumed.add(annotation);
|
|
1773
|
+
const member = type.members.find((m) => String(m.value) === parsed.value);
|
|
1774
|
+
if (!member) continue;
|
|
1775
|
+
displayNames.set(String(member.value), parsed.label);
|
|
1776
|
+
}
|
|
1777
|
+
if (displayNames.size === 0) {
|
|
1778
|
+
return type;
|
|
1779
|
+
}
|
|
1780
|
+
return {
|
|
1781
|
+
...type,
|
|
1782
|
+
members: type.members.map((member) => {
|
|
1783
|
+
const displayName = displayNames.get(String(member.value));
|
|
1784
|
+
return displayName !== void 0 ? { ...member, displayName } : member;
|
|
1785
|
+
})
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
function parseEnumMemberDisplayName(value) {
|
|
1789
|
+
const trimmed = value.trim();
|
|
1790
|
+
const match = /^:([^\s]+)\s+([\s\S]+)$/.exec(trimmed);
|
|
1791
|
+
if (!match?.[1] || !match[2]) return null;
|
|
1792
|
+
const label = match[2].trim();
|
|
1793
|
+
if (label === "") return null;
|
|
1794
|
+
return { value: match[1], label };
|
|
1795
|
+
}
|
|
1625
1796
|
function resolveTypeNode(type, checker, file, typeRegistry, visiting) {
|
|
1626
1797
|
if (type.flags & ts4.TypeFlags.String) {
|
|
1627
1798
|
return { kind: "primitive", primitiveKind: "string" };
|
|
@@ -1732,7 +1903,30 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting) {
|
|
|
1732
1903
|
const items = elementType ? resolveTypeNode(elementType, checker, file, typeRegistry, visiting) : { kind: "primitive", primitiveKind: "string" };
|
|
1733
1904
|
return { kind: "array", items };
|
|
1734
1905
|
}
|
|
1906
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting) {
|
|
1907
|
+
if (type.getProperties().length > 0) {
|
|
1908
|
+
return null;
|
|
1909
|
+
}
|
|
1910
|
+
const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
|
|
1911
|
+
if (!indexInfo) {
|
|
1912
|
+
return null;
|
|
1913
|
+
}
|
|
1914
|
+
if (visiting.has(type)) {
|
|
1915
|
+
return null;
|
|
1916
|
+
}
|
|
1917
|
+
visiting.add(type);
|
|
1918
|
+
try {
|
|
1919
|
+
const valueType = resolveTypeNode(indexInfo.type, checker, file, typeRegistry, visiting);
|
|
1920
|
+
return { kind: "record", valueType };
|
|
1921
|
+
} finally {
|
|
1922
|
+
visiting.delete(type);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1735
1925
|
function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
1926
|
+
const recordNode = tryResolveRecordType(type, checker, file, typeRegistry, visiting);
|
|
1927
|
+
if (recordNode) {
|
|
1928
|
+
return recordNode;
|
|
1929
|
+
}
|
|
1736
1930
|
if (visiting.has(type)) {
|
|
1737
1931
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
1738
1932
|
}
|
|
@@ -1764,7 +1958,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
1764
1958
|
const objectNode = {
|
|
1765
1959
|
kind: "object",
|
|
1766
1960
|
properties,
|
|
1767
|
-
additionalProperties:
|
|
1961
|
+
additionalProperties: true
|
|
1768
1962
|
};
|
|
1769
1963
|
if (typeName) {
|
|
1770
1964
|
typeRegistry[typeName] = {
|
|
@@ -1991,7 +2185,9 @@ __export(index_exports, {
|
|
|
1991
2185
|
categorizationSchema: () => categorizationSchema,
|
|
1992
2186
|
categorySchema: () => categorySchema,
|
|
1993
2187
|
controlSchema: () => controlSchema,
|
|
2188
|
+
createExtensionRegistry: () => createExtensionRegistry,
|
|
1994
2189
|
generateJsonSchema: () => generateJsonSchema,
|
|
2190
|
+
generateJsonSchemaFromIR: () => generateJsonSchemaFromIR,
|
|
1995
2191
|
generateSchemas: () => generateSchemas,
|
|
1996
2192
|
generateSchemasFromClass: () => generateSchemasFromClass,
|
|
1997
2193
|
generateUiSchema: () => generateUiSchema,
|
|
@@ -2012,15 +2208,19 @@ __export(index_exports, {
|
|
|
2012
2208
|
verticalLayoutSchema: () => verticalLayoutSchema,
|
|
2013
2209
|
writeSchemas: () => writeSchemas
|
|
2014
2210
|
});
|
|
2015
|
-
function buildFormSchemas(form) {
|
|
2211
|
+
function buildFormSchemas(form, options) {
|
|
2016
2212
|
return {
|
|
2017
|
-
jsonSchema: generateJsonSchema(form),
|
|
2213
|
+
jsonSchema: generateJsonSchema(form, options),
|
|
2018
2214
|
uiSchema: generateUiSchema(form)
|
|
2019
2215
|
};
|
|
2020
2216
|
}
|
|
2021
2217
|
function writeSchemas(form, options) {
|
|
2022
|
-
const { outDir, name = "schema", indent = 2 } = options;
|
|
2023
|
-
const
|
|
2218
|
+
const { outDir, name = "schema", indent = 2, extensionRegistry, vendorPrefix } = options;
|
|
2219
|
+
const buildOptions = extensionRegistry === void 0 && vendorPrefix === void 0 ? void 0 : {
|
|
2220
|
+
extensionRegistry,
|
|
2221
|
+
vendorPrefix
|
|
2222
|
+
};
|
|
2223
|
+
const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form, buildOptions);
|
|
2024
2224
|
if (!fs.existsSync(outDir)) {
|
|
2025
2225
|
fs.mkdirSync(outDir, { recursive: true });
|
|
2026
2226
|
}
|
|
@@ -2036,12 +2236,15 @@ var init_index = __esm({
|
|
|
2036
2236
|
"use strict";
|
|
2037
2237
|
init_generator();
|
|
2038
2238
|
init_generator2();
|
|
2239
|
+
init_ir_generator();
|
|
2039
2240
|
fs = __toESM(require("fs"), 1);
|
|
2040
2241
|
path2 = __toESM(require("path"), 1);
|
|
2041
2242
|
init_types();
|
|
2243
|
+
init_extensions();
|
|
2042
2244
|
init_schema();
|
|
2043
2245
|
init_schema2();
|
|
2044
2246
|
init_generator();
|
|
2247
|
+
init_ir_generator();
|
|
2045
2248
|
init_generator2();
|
|
2046
2249
|
init_class_schema();
|
|
2047
2250
|
}
|