@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.js
CHANGED
|
@@ -182,7 +182,7 @@ function canonicalizeArrayField(field) {
|
|
|
182
182
|
const itemsType = {
|
|
183
183
|
kind: "object",
|
|
184
184
|
properties: itemProperties,
|
|
185
|
-
additionalProperties:
|
|
185
|
+
additionalProperties: true
|
|
186
186
|
};
|
|
187
187
|
const type = { kind: "array", items: itemsType };
|
|
188
188
|
const constraints = [];
|
|
@@ -217,7 +217,7 @@ function canonicalizeObjectField(field) {
|
|
|
217
217
|
const type = {
|
|
218
218
|
kind: "object",
|
|
219
219
|
properties,
|
|
220
|
-
additionalProperties:
|
|
220
|
+
additionalProperties: true
|
|
221
221
|
};
|
|
222
222
|
return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
|
|
223
223
|
}
|
|
@@ -415,11 +415,21 @@ var init_canonicalize = __esm({
|
|
|
415
415
|
});
|
|
416
416
|
|
|
417
417
|
// src/json-schema/ir-generator.ts
|
|
418
|
-
function makeContext() {
|
|
419
|
-
|
|
418
|
+
function makeContext(options) {
|
|
419
|
+
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
420
|
+
if (!vendorPrefix.startsWith("x-")) {
|
|
421
|
+
throw new Error(
|
|
422
|
+
`Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
defs: {},
|
|
427
|
+
extensionRegistry: options?.extensionRegistry,
|
|
428
|
+
vendorPrefix
|
|
429
|
+
};
|
|
420
430
|
}
|
|
421
|
-
function generateJsonSchemaFromIR(ir) {
|
|
422
|
-
const ctx = makeContext();
|
|
431
|
+
function generateJsonSchemaFromIR(ir, options) {
|
|
432
|
+
const ctx = makeContext(options);
|
|
423
433
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
424
434
|
ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
|
|
425
435
|
}
|
|
@@ -471,16 +481,16 @@ function generateFieldSchema(field, ctx) {
|
|
|
471
481
|
directConstraints.push(c);
|
|
472
482
|
}
|
|
473
483
|
}
|
|
474
|
-
applyConstraints(schema, directConstraints);
|
|
475
|
-
applyAnnotations(schema, field.annotations);
|
|
484
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
485
|
+
applyAnnotations(schema, field.annotations, ctx);
|
|
476
486
|
if (pathConstraints.length === 0) {
|
|
477
487
|
return schema;
|
|
478
488
|
}
|
|
479
|
-
return applyPathTargetedConstraints(schema, pathConstraints);
|
|
489
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx);
|
|
480
490
|
}
|
|
481
|
-
function applyPathTargetedConstraints(schema, pathConstraints) {
|
|
491
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
482
492
|
if (schema.type === "array" && schema.items) {
|
|
483
|
-
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints);
|
|
493
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx);
|
|
484
494
|
return schema;
|
|
485
495
|
}
|
|
486
496
|
const byTarget = /* @__PURE__ */ new Map();
|
|
@@ -494,7 +504,7 @@ function applyPathTargetedConstraints(schema, pathConstraints) {
|
|
|
494
504
|
const propertyOverrides = {};
|
|
495
505
|
for (const [target, constraints] of byTarget) {
|
|
496
506
|
const subSchema = {};
|
|
497
|
-
applyConstraints(subSchema, constraints);
|
|
507
|
+
applyConstraints(subSchema, constraints, ctx);
|
|
498
508
|
propertyOverrides[target] = subSchema;
|
|
499
509
|
}
|
|
500
510
|
if (schema.$ref) {
|
|
@@ -538,6 +548,8 @@ function generateTypeNode(type, ctx) {
|
|
|
538
548
|
return generateArrayType(type, ctx);
|
|
539
549
|
case "object":
|
|
540
550
|
return generateObjectType(type, ctx);
|
|
551
|
+
case "record":
|
|
552
|
+
return generateRecordType(type, ctx);
|
|
541
553
|
case "union":
|
|
542
554
|
return generateUnionType(type, ctx);
|
|
543
555
|
case "reference":
|
|
@@ -545,7 +557,7 @@ function generateTypeNode(type, ctx) {
|
|
|
545
557
|
case "dynamic":
|
|
546
558
|
return generateDynamicType(type);
|
|
547
559
|
case "custom":
|
|
548
|
-
return generateCustomType(type);
|
|
560
|
+
return generateCustomType(type, ctx);
|
|
549
561
|
default: {
|
|
550
562
|
const _exhaustive = type;
|
|
551
563
|
return _exhaustive;
|
|
@@ -594,16 +606,27 @@ function generateObjectType(type, ctx) {
|
|
|
594
606
|
}
|
|
595
607
|
return schema;
|
|
596
608
|
}
|
|
609
|
+
function generateRecordType(type, ctx) {
|
|
610
|
+
return {
|
|
611
|
+
type: "object",
|
|
612
|
+
additionalProperties: generateTypeNode(type.valueType, ctx)
|
|
613
|
+
};
|
|
614
|
+
}
|
|
597
615
|
function generatePropertySchema(prop, ctx) {
|
|
598
616
|
const schema = generateTypeNode(prop.type, ctx);
|
|
599
|
-
applyConstraints(schema, prop.constraints);
|
|
600
|
-
applyAnnotations(schema, prop.annotations);
|
|
617
|
+
applyConstraints(schema, prop.constraints, ctx);
|
|
618
|
+
applyAnnotations(schema, prop.annotations, ctx);
|
|
601
619
|
return schema;
|
|
602
620
|
}
|
|
603
621
|
function generateUnionType(type, ctx) {
|
|
604
622
|
if (isBooleanUnion(type)) {
|
|
605
623
|
return { type: "boolean" };
|
|
606
624
|
}
|
|
625
|
+
if (isNullableUnion(type)) {
|
|
626
|
+
return {
|
|
627
|
+
oneOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
628
|
+
};
|
|
629
|
+
}
|
|
607
630
|
return {
|
|
608
631
|
anyOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
609
632
|
};
|
|
@@ -613,6 +636,13 @@ function isBooleanUnion(type) {
|
|
|
613
636
|
const kinds = type.members.map((m) => m.kind);
|
|
614
637
|
return kinds.every((k) => k === "primitive") && type.members.every((m) => m.kind === "primitive" && m.primitiveKind === "boolean");
|
|
615
638
|
}
|
|
639
|
+
function isNullableUnion(type) {
|
|
640
|
+
if (type.members.length !== 2) return false;
|
|
641
|
+
const nullCount = type.members.filter(
|
|
642
|
+
(m) => m.kind === "primitive" && m.primitiveKind === "null"
|
|
643
|
+
).length;
|
|
644
|
+
return nullCount === 1;
|
|
645
|
+
}
|
|
616
646
|
function generateReferenceType(type) {
|
|
617
647
|
return { $ref: `#/$defs/${type.name}` };
|
|
618
648
|
}
|
|
@@ -633,10 +663,7 @@ function generateDynamicType(type) {
|
|
|
633
663
|
"x-formspec-schemaSource": type.sourceKey
|
|
634
664
|
};
|
|
635
665
|
}
|
|
636
|
-
function
|
|
637
|
-
return { type: "object" };
|
|
638
|
-
}
|
|
639
|
-
function applyConstraints(schema, constraints) {
|
|
666
|
+
function applyConstraints(schema, constraints, ctx) {
|
|
640
667
|
for (const constraint of constraints) {
|
|
641
668
|
switch (constraint.constraintKind) {
|
|
642
669
|
case "minimum":
|
|
@@ -681,6 +708,7 @@ function applyConstraints(schema, constraints) {
|
|
|
681
708
|
case "allowedMembers":
|
|
682
709
|
break;
|
|
683
710
|
case "custom":
|
|
711
|
+
applyCustomConstraint(schema, constraint, ctx);
|
|
684
712
|
break;
|
|
685
713
|
default: {
|
|
686
714
|
const _exhaustive = constraint;
|
|
@@ -689,7 +717,7 @@ function applyConstraints(schema, constraints) {
|
|
|
689
717
|
}
|
|
690
718
|
}
|
|
691
719
|
}
|
|
692
|
-
function applyAnnotations(schema, annotations) {
|
|
720
|
+
function applyAnnotations(schema, annotations, ctx) {
|
|
693
721
|
for (const annotation of annotations) {
|
|
694
722
|
switch (annotation.annotationKind) {
|
|
695
723
|
case "displayName":
|
|
@@ -709,6 +737,7 @@ function applyAnnotations(schema, annotations) {
|
|
|
709
737
|
case "formatHint":
|
|
710
738
|
break;
|
|
711
739
|
case "custom":
|
|
740
|
+
applyCustomAnnotation(schema, annotation, ctx);
|
|
712
741
|
break;
|
|
713
742
|
default: {
|
|
714
743
|
const _exhaustive = annotation;
|
|
@@ -717,6 +746,36 @@ function applyAnnotations(schema, annotations) {
|
|
|
717
746
|
}
|
|
718
747
|
}
|
|
719
748
|
}
|
|
749
|
+
function generateCustomType(type, ctx) {
|
|
750
|
+
const registration = ctx.extensionRegistry?.findType(type.typeId);
|
|
751
|
+
if (registration === void 0) {
|
|
752
|
+
throw new Error(
|
|
753
|
+
`Cannot generate JSON Schema for custom type "${type.typeId}" without a matching extension registration`
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
757
|
+
}
|
|
758
|
+
function applyCustomConstraint(schema, constraint, ctx) {
|
|
759
|
+
const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);
|
|
760
|
+
if (registration === void 0) {
|
|
761
|
+
throw new Error(
|
|
762
|
+
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
Object.assign(schema, registration.toJsonSchema(constraint.payload, ctx.vendorPrefix));
|
|
766
|
+
}
|
|
767
|
+
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
768
|
+
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
769
|
+
if (registration === void 0) {
|
|
770
|
+
throw new Error(
|
|
771
|
+
`Cannot generate JSON Schema for custom annotation "${annotation.annotationId}" without a matching extension registration`
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
if (registration.toJsonSchema === void 0) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
Object.assign(schema, registration.toJsonSchema(annotation.value, ctx.vendorPrefix));
|
|
778
|
+
}
|
|
720
779
|
var init_ir_generator = __esm({
|
|
721
780
|
"src/json-schema/ir-generator.ts"() {
|
|
722
781
|
"use strict";
|
|
@@ -724,9 +783,9 @@ var init_ir_generator = __esm({
|
|
|
724
783
|
});
|
|
725
784
|
|
|
726
785
|
// src/json-schema/generator.ts
|
|
727
|
-
function generateJsonSchema(form) {
|
|
786
|
+
function generateJsonSchema(form, options) {
|
|
728
787
|
const ir = canonicalizeChainDSL(form);
|
|
729
|
-
return generateJsonSchemaFromIR(ir);
|
|
788
|
+
return generateJsonSchemaFromIR(ir, options);
|
|
730
789
|
}
|
|
731
790
|
var init_generator = __esm({
|
|
732
791
|
"src/json-schema/generator.ts"() {
|
|
@@ -987,6 +1046,61 @@ var init_types = __esm({
|
|
|
987
1046
|
}
|
|
988
1047
|
});
|
|
989
1048
|
|
|
1049
|
+
// src/extensions/registry.ts
|
|
1050
|
+
function createExtensionRegistry(extensions) {
|
|
1051
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
1052
|
+
const constraintMap = /* @__PURE__ */ new Map();
|
|
1053
|
+
const annotationMap = /* @__PURE__ */ new Map();
|
|
1054
|
+
for (const ext of extensions) {
|
|
1055
|
+
if (ext.types !== void 0) {
|
|
1056
|
+
for (const type of ext.types) {
|
|
1057
|
+
const qualifiedId = `${ext.extensionId}/${type.typeName}`;
|
|
1058
|
+
if (typeMap.has(qualifiedId)) {
|
|
1059
|
+
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
1060
|
+
}
|
|
1061
|
+
typeMap.set(qualifiedId, type);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (ext.constraints !== void 0) {
|
|
1065
|
+
for (const constraint of ext.constraints) {
|
|
1066
|
+
const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
|
|
1067
|
+
if (constraintMap.has(qualifiedId)) {
|
|
1068
|
+
throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
|
|
1069
|
+
}
|
|
1070
|
+
constraintMap.set(qualifiedId, constraint);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
if (ext.annotations !== void 0) {
|
|
1074
|
+
for (const annotation of ext.annotations) {
|
|
1075
|
+
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
1076
|
+
if (annotationMap.has(qualifiedId)) {
|
|
1077
|
+
throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
|
|
1078
|
+
}
|
|
1079
|
+
annotationMap.set(qualifiedId, annotation);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
return {
|
|
1084
|
+
extensions,
|
|
1085
|
+
findType: (typeId) => typeMap.get(typeId),
|
|
1086
|
+
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1087
|
+
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
var init_registry = __esm({
|
|
1091
|
+
"src/extensions/registry.ts"() {
|
|
1092
|
+
"use strict";
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
// src/extensions/index.ts
|
|
1097
|
+
var init_extensions = __esm({
|
|
1098
|
+
"src/extensions/index.ts"() {
|
|
1099
|
+
"use strict";
|
|
1100
|
+
init_registry();
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
|
|
990
1104
|
// src/json-schema/schema.ts
|
|
991
1105
|
import { z as z3 } from "zod";
|
|
992
1106
|
var jsonSchemaTypeSchema, jsonSchema7Schema;
|
|
@@ -1173,6 +1287,15 @@ function createFormSpecTSDocConfig() {
|
|
|
1173
1287
|
})
|
|
1174
1288
|
);
|
|
1175
1289
|
}
|
|
1290
|
+
for (const tagName of ["displayName", "description"]) {
|
|
1291
|
+
config.addTagDefinition(
|
|
1292
|
+
new TSDocTagDefinition({
|
|
1293
|
+
tagName: "@" + tagName,
|
|
1294
|
+
syntaxKind: TSDocTagSyntaxKind.BlockTag,
|
|
1295
|
+
allowMultiple: true
|
|
1296
|
+
})
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1176
1299
|
return config;
|
|
1177
1300
|
}
|
|
1178
1301
|
function getParser() {
|
|
@@ -1201,6 +1324,27 @@ function parseTSDocTags(node, file = "") {
|
|
|
1201
1324
|
const docComment = parserContext.docComment;
|
|
1202
1325
|
for (const block of docComment.customBlocks) {
|
|
1203
1326
|
const tagName = normalizeConstraintTagName(block.blockTag.tagName.substring(1));
|
|
1327
|
+
if (tagName === "displayName" || tagName === "description") {
|
|
1328
|
+
const text2 = extractBlockText(block).trim();
|
|
1329
|
+
if (text2 === "") continue;
|
|
1330
|
+
const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
|
|
1331
|
+
if (tagName === "displayName") {
|
|
1332
|
+
annotations.push({
|
|
1333
|
+
kind: "annotation",
|
|
1334
|
+
annotationKind: "displayName",
|
|
1335
|
+
value: text2,
|
|
1336
|
+
provenance: provenance2
|
|
1337
|
+
});
|
|
1338
|
+
} else {
|
|
1339
|
+
annotations.push({
|
|
1340
|
+
kind: "annotation",
|
|
1341
|
+
annotationKind: "description",
|
|
1342
|
+
value: text2,
|
|
1343
|
+
provenance: provenance2
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1204
1348
|
if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
|
|
1205
1349
|
const text = extractBlockText(block).trim();
|
|
1206
1350
|
if (text === "") continue;
|
|
@@ -1232,41 +1376,6 @@ function parseTSDocTags(node, file = "") {
|
|
|
1232
1376
|
constraints.push(constraintNode);
|
|
1233
1377
|
}
|
|
1234
1378
|
}
|
|
1235
|
-
let displayName;
|
|
1236
|
-
let description;
|
|
1237
|
-
let displayNameTag;
|
|
1238
|
-
let descriptionTag;
|
|
1239
|
-
for (const tag of jsDocTagsAll) {
|
|
1240
|
-
const tagName = tag.tagName.text;
|
|
1241
|
-
const commentText = getTagCommentText(tag);
|
|
1242
|
-
if (commentText === void 0 || commentText.trim() === "") {
|
|
1243
|
-
continue;
|
|
1244
|
-
}
|
|
1245
|
-
const trimmed = commentText.trim();
|
|
1246
|
-
if (tagName === "Field_displayName") {
|
|
1247
|
-
displayName = trimmed;
|
|
1248
|
-
displayNameTag = tag;
|
|
1249
|
-
} else if (tagName === "Field_description") {
|
|
1250
|
-
description = trimmed;
|
|
1251
|
-
descriptionTag = tag;
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
if (displayName !== void 0 && displayNameTag) {
|
|
1255
|
-
annotations.push({
|
|
1256
|
-
kind: "annotation",
|
|
1257
|
-
annotationKind: "displayName",
|
|
1258
|
-
value: displayName,
|
|
1259
|
-
provenance: provenanceForJSDocTag(displayNameTag, file)
|
|
1260
|
-
});
|
|
1261
|
-
}
|
|
1262
|
-
if (description !== void 0 && descriptionTag) {
|
|
1263
|
-
annotations.push({
|
|
1264
|
-
kind: "annotation",
|
|
1265
|
-
annotationKind: "description",
|
|
1266
|
-
value: description,
|
|
1267
|
-
provenance: provenanceForJSDocTag(descriptionTag, file)
|
|
1268
|
-
});
|
|
1269
|
-
}
|
|
1270
1379
|
return { constraints, annotations };
|
|
1271
1380
|
}
|
|
1272
1381
|
function extractPathTarget(text) {
|
|
@@ -1417,11 +1526,6 @@ var init_tsdoc_parser = __esm({
|
|
|
1417
1526
|
|
|
1418
1527
|
// src/analyzer/jsdoc-constraints.ts
|
|
1419
1528
|
import * as ts3 from "typescript";
|
|
1420
|
-
import {
|
|
1421
|
-
BUILTIN_CONSTRAINT_DEFINITIONS as BUILTIN_CONSTRAINT_DEFINITIONS2,
|
|
1422
|
-
isBuiltinConstraintName as isBuiltinConstraintName2,
|
|
1423
|
-
normalizeConstraintTagName as normalizeConstraintTagName2
|
|
1424
|
-
} from "@formspec/core";
|
|
1425
1529
|
function extractJSDocConstraintNodes(node, file = "") {
|
|
1426
1530
|
const result = parseTSDocTags(node, file);
|
|
1427
1531
|
return [...result.constraints];
|
|
@@ -1467,7 +1571,6 @@ var init_jsdoc_constraints = __esm({
|
|
|
1467
1571
|
"src/analyzer/jsdoc-constraints.ts"() {
|
|
1468
1572
|
"use strict";
|
|
1469
1573
|
init_tsdoc_parser();
|
|
1470
|
-
init_json_utils();
|
|
1471
1574
|
}
|
|
1472
1575
|
});
|
|
1473
1576
|
|
|
@@ -1566,18 +1669,19 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
|
1566
1669
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1567
1670
|
const optional = prop.questionToken !== void 0;
|
|
1568
1671
|
const provenance = provenanceForNode(prop, file);
|
|
1569
|
-
|
|
1672
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1570
1673
|
const constraints = [];
|
|
1571
1674
|
if (prop.type) {
|
|
1572
1675
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1573
1676
|
}
|
|
1574
1677
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1575
|
-
|
|
1678
|
+
let annotations = [];
|
|
1576
1679
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1577
1680
|
const defaultAnnotation = extractDefaultValueAnnotation(prop.initializer, file);
|
|
1578
1681
|
if (defaultAnnotation) {
|
|
1579
1682
|
annotations.push(defaultAnnotation);
|
|
1580
1683
|
}
|
|
1684
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1581
1685
|
return {
|
|
1582
1686
|
kind: "field",
|
|
1583
1687
|
name,
|
|
@@ -1596,14 +1700,15 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1596
1700
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1597
1701
|
const optional = prop.questionToken !== void 0;
|
|
1598
1702
|
const provenance = provenanceForNode(prop, file);
|
|
1599
|
-
|
|
1703
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1600
1704
|
const constraints = [];
|
|
1601
1705
|
if (prop.type) {
|
|
1602
1706
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1603
1707
|
}
|
|
1604
1708
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1605
|
-
|
|
1709
|
+
let annotations = [];
|
|
1606
1710
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1711
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1607
1712
|
return {
|
|
1608
1713
|
kind: "field",
|
|
1609
1714
|
name,
|
|
@@ -1614,6 +1719,68 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1614
1719
|
provenance
|
|
1615
1720
|
};
|
|
1616
1721
|
}
|
|
1722
|
+
function applyEnumMemberDisplayNames(type, annotations) {
|
|
1723
|
+
if (!annotations.some(
|
|
1724
|
+
(annotation) => annotation.annotationKind === "displayName" && annotation.value.trim().startsWith(":")
|
|
1725
|
+
)) {
|
|
1726
|
+
return { type, annotations: [...annotations] };
|
|
1727
|
+
}
|
|
1728
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1729
|
+
const nextType = rewriteEnumDisplayNames(type, annotations, consumed);
|
|
1730
|
+
if (consumed.size === 0) {
|
|
1731
|
+
return { type, annotations: [...annotations] };
|
|
1732
|
+
}
|
|
1733
|
+
return {
|
|
1734
|
+
type: nextType,
|
|
1735
|
+
annotations: annotations.filter((annotation) => !consumed.has(annotation))
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
function rewriteEnumDisplayNames(type, annotations, consumed) {
|
|
1739
|
+
switch (type.kind) {
|
|
1740
|
+
case "enum":
|
|
1741
|
+
return applyEnumMemberDisplayNamesToEnum(type, annotations, consumed);
|
|
1742
|
+
case "union": {
|
|
1743
|
+
return {
|
|
1744
|
+
...type,
|
|
1745
|
+
members: type.members.map(
|
|
1746
|
+
(member) => rewriteEnumDisplayNames(member, annotations, consumed)
|
|
1747
|
+
)
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
default:
|
|
1751
|
+
return type;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
function applyEnumMemberDisplayNamesToEnum(type, annotations, consumed) {
|
|
1755
|
+
const displayNames = /* @__PURE__ */ new Map();
|
|
1756
|
+
for (const annotation of annotations) {
|
|
1757
|
+
if (annotation.annotationKind !== "displayName") continue;
|
|
1758
|
+
const parsed = parseEnumMemberDisplayName(annotation.value);
|
|
1759
|
+
if (!parsed) continue;
|
|
1760
|
+
consumed.add(annotation);
|
|
1761
|
+
const member = type.members.find((m) => String(m.value) === parsed.value);
|
|
1762
|
+
if (!member) continue;
|
|
1763
|
+
displayNames.set(String(member.value), parsed.label);
|
|
1764
|
+
}
|
|
1765
|
+
if (displayNames.size === 0) {
|
|
1766
|
+
return type;
|
|
1767
|
+
}
|
|
1768
|
+
return {
|
|
1769
|
+
...type,
|
|
1770
|
+
members: type.members.map((member) => {
|
|
1771
|
+
const displayName = displayNames.get(String(member.value));
|
|
1772
|
+
return displayName !== void 0 ? { ...member, displayName } : member;
|
|
1773
|
+
})
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
function parseEnumMemberDisplayName(value) {
|
|
1777
|
+
const trimmed = value.trim();
|
|
1778
|
+
const match = /^:([^\s]+)\s+([\s\S]+)$/.exec(trimmed);
|
|
1779
|
+
if (!match?.[1] || !match[2]) return null;
|
|
1780
|
+
const label = match[2].trim();
|
|
1781
|
+
if (label === "") return null;
|
|
1782
|
+
return { value: match[1], label };
|
|
1783
|
+
}
|
|
1617
1784
|
function resolveTypeNode(type, checker, file, typeRegistry, visiting) {
|
|
1618
1785
|
if (type.flags & ts4.TypeFlags.String) {
|
|
1619
1786
|
return { kind: "primitive", primitiveKind: "string" };
|
|
@@ -1724,7 +1891,30 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting) {
|
|
|
1724
1891
|
const items = elementType ? resolveTypeNode(elementType, checker, file, typeRegistry, visiting) : { kind: "primitive", primitiveKind: "string" };
|
|
1725
1892
|
return { kind: "array", items };
|
|
1726
1893
|
}
|
|
1894
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting) {
|
|
1895
|
+
if (type.getProperties().length > 0) {
|
|
1896
|
+
return null;
|
|
1897
|
+
}
|
|
1898
|
+
const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
|
|
1899
|
+
if (!indexInfo) {
|
|
1900
|
+
return null;
|
|
1901
|
+
}
|
|
1902
|
+
if (visiting.has(type)) {
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
visiting.add(type);
|
|
1906
|
+
try {
|
|
1907
|
+
const valueType = resolveTypeNode(indexInfo.type, checker, file, typeRegistry, visiting);
|
|
1908
|
+
return { kind: "record", valueType };
|
|
1909
|
+
} finally {
|
|
1910
|
+
visiting.delete(type);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1727
1913
|
function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
1914
|
+
const recordNode = tryResolveRecordType(type, checker, file, typeRegistry, visiting);
|
|
1915
|
+
if (recordNode) {
|
|
1916
|
+
return recordNode;
|
|
1917
|
+
}
|
|
1728
1918
|
if (visiting.has(type)) {
|
|
1729
1919
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
1730
1920
|
}
|
|
@@ -1756,7 +1946,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
1756
1946
|
const objectNode = {
|
|
1757
1947
|
kind: "object",
|
|
1758
1948
|
properties,
|
|
1759
|
-
additionalProperties:
|
|
1949
|
+
additionalProperties: true
|
|
1760
1950
|
};
|
|
1761
1951
|
if (typeName) {
|
|
1762
1952
|
typeRegistry[typeName] = {
|
|
@@ -1982,7 +2172,9 @@ __export(index_exports, {
|
|
|
1982
2172
|
categorizationSchema: () => categorizationSchema,
|
|
1983
2173
|
categorySchema: () => categorySchema,
|
|
1984
2174
|
controlSchema: () => controlSchema,
|
|
2175
|
+
createExtensionRegistry: () => createExtensionRegistry,
|
|
1985
2176
|
generateJsonSchema: () => generateJsonSchema,
|
|
2177
|
+
generateJsonSchemaFromIR: () => generateJsonSchemaFromIR,
|
|
1986
2178
|
generateSchemas: () => generateSchemas,
|
|
1987
2179
|
generateSchemasFromClass: () => generateSchemasFromClass,
|
|
1988
2180
|
generateUiSchema: () => generateUiSchema,
|
|
@@ -2005,15 +2197,19 @@ __export(index_exports, {
|
|
|
2005
2197
|
});
|
|
2006
2198
|
import * as fs from "fs";
|
|
2007
2199
|
import * as path2 from "path";
|
|
2008
|
-
function buildFormSchemas(form) {
|
|
2200
|
+
function buildFormSchemas(form, options) {
|
|
2009
2201
|
return {
|
|
2010
|
-
jsonSchema: generateJsonSchema(form),
|
|
2202
|
+
jsonSchema: generateJsonSchema(form, options),
|
|
2011
2203
|
uiSchema: generateUiSchema(form)
|
|
2012
2204
|
};
|
|
2013
2205
|
}
|
|
2014
2206
|
function writeSchemas(form, options) {
|
|
2015
|
-
const { outDir, name = "schema", indent = 2 } = options;
|
|
2016
|
-
const
|
|
2207
|
+
const { outDir, name = "schema", indent = 2, extensionRegistry, vendorPrefix } = options;
|
|
2208
|
+
const buildOptions = extensionRegistry === void 0 && vendorPrefix === void 0 ? void 0 : {
|
|
2209
|
+
extensionRegistry,
|
|
2210
|
+
vendorPrefix
|
|
2211
|
+
};
|
|
2212
|
+
const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form, buildOptions);
|
|
2017
2213
|
if (!fs.existsSync(outDir)) {
|
|
2018
2214
|
fs.mkdirSync(outDir, { recursive: true });
|
|
2019
2215
|
}
|
|
@@ -2028,10 +2224,13 @@ var init_index = __esm({
|
|
|
2028
2224
|
"use strict";
|
|
2029
2225
|
init_generator();
|
|
2030
2226
|
init_generator2();
|
|
2227
|
+
init_ir_generator();
|
|
2031
2228
|
init_types();
|
|
2229
|
+
init_extensions();
|
|
2032
2230
|
init_schema();
|
|
2033
2231
|
init_schema2();
|
|
2034
2232
|
init_generator();
|
|
2233
|
+
init_ir_generator();
|
|
2035
2234
|
init_generator2();
|
|
2036
2235
|
init_class_schema();
|
|
2037
2236
|
}
|