@formspec/build 0.1.0-alpha.13 → 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/README.md +20 -20
- package/dist/__tests__/alias-chain-propagation.test.d.ts +9 -0
- package/dist/__tests__/alias-chain-propagation.test.d.ts.map +1 -0
- 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/alias-chains.d.ts +37 -0
- package/dist/__tests__/fixtures/alias-chains.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 +13 -13
- package/dist/__tests__/fixtures/example-interface-types.d.ts +33 -33
- 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__/json-utils.test.d.ts +5 -0
- package/dist/__tests__/json-utils.test.d.ts.map +1 -0
- 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/__tests__/path-target-parser.test.d.ts +9 -0
- package/dist/__tests__/path-target-parser.test.d.ts.map +1 -0
- 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 +8 -52
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/json-utils.d.ts +22 -0
- package/dist/analyzer/json-utils.d.ts.map +1 -0
- package/dist/analyzer/tsdoc-parser.d.ts +24 -12
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +452 -94
- 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 +450 -94
- package/dist/browser.js.map +1 -1
- package/dist/build.d.ts +132 -5
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +3 -3
- package/dist/cli.cjs +406 -104
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +407 -104
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +386 -102
- 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 +386 -104
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +597 -172
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +597 -172
- 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 +25 -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 +3 -3
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,9 @@ __export(index_exports, {
|
|
|
34
34
|
categorizationSchema: () => categorizationSchema,
|
|
35
35
|
categorySchema: () => categorySchema,
|
|
36
36
|
controlSchema: () => controlSchema,
|
|
37
|
+
createExtensionRegistry: () => createExtensionRegistry,
|
|
37
38
|
generateJsonSchema: () => generateJsonSchema,
|
|
39
|
+
generateJsonSchemaFromIR: () => generateJsonSchemaFromIR,
|
|
38
40
|
generateSchemas: () => generateSchemas,
|
|
39
41
|
generateSchemasFromClass: () => generateSchemasFromClass,
|
|
40
42
|
generateUiSchema: () => generateUiSchema,
|
|
@@ -236,7 +238,7 @@ function canonicalizeArrayField(field) {
|
|
|
236
238
|
const itemsType = {
|
|
237
239
|
kind: "object",
|
|
238
240
|
properties: itemProperties,
|
|
239
|
-
additionalProperties:
|
|
241
|
+
additionalProperties: true
|
|
240
242
|
};
|
|
241
243
|
const type = { kind: "array", items: itemsType };
|
|
242
244
|
const constraints = [];
|
|
@@ -271,7 +273,7 @@ function canonicalizeObjectField(field) {
|
|
|
271
273
|
const type = {
|
|
272
274
|
kind: "object",
|
|
273
275
|
properties,
|
|
274
|
-
additionalProperties:
|
|
276
|
+
additionalProperties: true
|
|
275
277
|
};
|
|
276
278
|
return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
|
|
277
279
|
}
|
|
@@ -443,11 +445,21 @@ function wrapInConditional(field, layout, provenance) {
|
|
|
443
445
|
}
|
|
444
446
|
|
|
445
447
|
// src/json-schema/ir-generator.ts
|
|
446
|
-
function makeContext() {
|
|
447
|
-
|
|
448
|
+
function makeContext(options) {
|
|
449
|
+
const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
|
|
450
|
+
if (!vendorPrefix.startsWith("x-")) {
|
|
451
|
+
throw new Error(
|
|
452
|
+
`Invalid vendorPrefix "${vendorPrefix}". Extension JSON Schema keywords must start with "x-".`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
defs: {},
|
|
457
|
+
extensionRegistry: options?.extensionRegistry,
|
|
458
|
+
vendorPrefix
|
|
459
|
+
};
|
|
448
460
|
}
|
|
449
|
-
function generateJsonSchemaFromIR(ir) {
|
|
450
|
-
const ctx = makeContext();
|
|
461
|
+
function generateJsonSchemaFromIR(ir, options) {
|
|
462
|
+
const ctx = makeContext(options);
|
|
451
463
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
452
464
|
ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
|
|
453
465
|
}
|
|
@@ -490,8 +502,70 @@ function collectFields(elements, properties, required, ctx) {
|
|
|
490
502
|
}
|
|
491
503
|
function generateFieldSchema(field, ctx) {
|
|
492
504
|
const schema = generateTypeNode(field.type, ctx);
|
|
493
|
-
|
|
494
|
-
|
|
505
|
+
const directConstraints = [];
|
|
506
|
+
const pathConstraints = [];
|
|
507
|
+
for (const c of field.constraints) {
|
|
508
|
+
if (c.path) {
|
|
509
|
+
pathConstraints.push(c);
|
|
510
|
+
} else {
|
|
511
|
+
directConstraints.push(c);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
applyConstraints(schema, directConstraints, ctx);
|
|
515
|
+
applyAnnotations(schema, field.annotations, ctx);
|
|
516
|
+
if (pathConstraints.length === 0) {
|
|
517
|
+
return schema;
|
|
518
|
+
}
|
|
519
|
+
return applyPathTargetedConstraints(schema, pathConstraints, ctx);
|
|
520
|
+
}
|
|
521
|
+
function applyPathTargetedConstraints(schema, pathConstraints, ctx) {
|
|
522
|
+
if (schema.type === "array" && schema.items) {
|
|
523
|
+
schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx);
|
|
524
|
+
return schema;
|
|
525
|
+
}
|
|
526
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
527
|
+
for (const c of pathConstraints) {
|
|
528
|
+
const target = c.path?.segments[0];
|
|
529
|
+
if (!target) continue;
|
|
530
|
+
const group = byTarget.get(target) ?? [];
|
|
531
|
+
group.push(c);
|
|
532
|
+
byTarget.set(target, group);
|
|
533
|
+
}
|
|
534
|
+
const propertyOverrides = {};
|
|
535
|
+
for (const [target, constraints] of byTarget) {
|
|
536
|
+
const subSchema = {};
|
|
537
|
+
applyConstraints(subSchema, constraints, ctx);
|
|
538
|
+
propertyOverrides[target] = subSchema;
|
|
539
|
+
}
|
|
540
|
+
if (schema.$ref) {
|
|
541
|
+
const { $ref, ...rest } = schema;
|
|
542
|
+
const refPart = { $ref };
|
|
543
|
+
const overridePart = {
|
|
544
|
+
properties: propertyOverrides,
|
|
545
|
+
...rest
|
|
546
|
+
};
|
|
547
|
+
return { allOf: [refPart, overridePart] };
|
|
548
|
+
}
|
|
549
|
+
if (schema.type === "object" && schema.properties) {
|
|
550
|
+
const missingOverrides = {};
|
|
551
|
+
for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {
|
|
552
|
+
if (schema.properties[target]) {
|
|
553
|
+
Object.assign(schema.properties[target], overrideSchema);
|
|
554
|
+
} else {
|
|
555
|
+
missingOverrides[target] = overrideSchema;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (Object.keys(missingOverrides).length === 0) {
|
|
559
|
+
return schema;
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
allOf: [schema, { properties: missingOverrides }]
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
if (schema.allOf) {
|
|
566
|
+
schema.allOf = [...schema.allOf, { properties: propertyOverrides }];
|
|
567
|
+
return schema;
|
|
568
|
+
}
|
|
495
569
|
return schema;
|
|
496
570
|
}
|
|
497
571
|
function generateTypeNode(type, ctx) {
|
|
@@ -504,6 +578,8 @@ function generateTypeNode(type, ctx) {
|
|
|
504
578
|
return generateArrayType(type, ctx);
|
|
505
579
|
case "object":
|
|
506
580
|
return generateObjectType(type, ctx);
|
|
581
|
+
case "record":
|
|
582
|
+
return generateRecordType(type, ctx);
|
|
507
583
|
case "union":
|
|
508
584
|
return generateUnionType(type, ctx);
|
|
509
585
|
case "reference":
|
|
@@ -511,7 +587,7 @@ function generateTypeNode(type, ctx) {
|
|
|
511
587
|
case "dynamic":
|
|
512
588
|
return generateDynamicType(type);
|
|
513
589
|
case "custom":
|
|
514
|
-
return generateCustomType(type);
|
|
590
|
+
return generateCustomType(type, ctx);
|
|
515
591
|
default: {
|
|
516
592
|
const _exhaustive = type;
|
|
517
593
|
return _exhaustive;
|
|
@@ -560,16 +636,27 @@ function generateObjectType(type, ctx) {
|
|
|
560
636
|
}
|
|
561
637
|
return schema;
|
|
562
638
|
}
|
|
639
|
+
function generateRecordType(type, ctx) {
|
|
640
|
+
return {
|
|
641
|
+
type: "object",
|
|
642
|
+
additionalProperties: generateTypeNode(type.valueType, ctx)
|
|
643
|
+
};
|
|
644
|
+
}
|
|
563
645
|
function generatePropertySchema(prop, ctx) {
|
|
564
646
|
const schema = generateTypeNode(prop.type, ctx);
|
|
565
|
-
applyConstraints(schema, prop.constraints);
|
|
566
|
-
applyAnnotations(schema, prop.annotations);
|
|
647
|
+
applyConstraints(schema, prop.constraints, ctx);
|
|
648
|
+
applyAnnotations(schema, prop.annotations, ctx);
|
|
567
649
|
return schema;
|
|
568
650
|
}
|
|
569
651
|
function generateUnionType(type, ctx) {
|
|
570
652
|
if (isBooleanUnion(type)) {
|
|
571
653
|
return { type: "boolean" };
|
|
572
654
|
}
|
|
655
|
+
if (isNullableUnion(type)) {
|
|
656
|
+
return {
|
|
657
|
+
oneOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
658
|
+
};
|
|
659
|
+
}
|
|
573
660
|
return {
|
|
574
661
|
anyOf: type.members.map((m) => generateTypeNode(m, ctx))
|
|
575
662
|
};
|
|
@@ -579,6 +666,13 @@ function isBooleanUnion(type) {
|
|
|
579
666
|
const kinds = type.members.map((m) => m.kind);
|
|
580
667
|
return kinds.every((k) => k === "primitive") && type.members.every((m) => m.kind === "primitive" && m.primitiveKind === "boolean");
|
|
581
668
|
}
|
|
669
|
+
function isNullableUnion(type) {
|
|
670
|
+
if (type.members.length !== 2) return false;
|
|
671
|
+
const nullCount = type.members.filter(
|
|
672
|
+
(m) => m.kind === "primitive" && m.primitiveKind === "null"
|
|
673
|
+
).length;
|
|
674
|
+
return nullCount === 1;
|
|
675
|
+
}
|
|
582
676
|
function generateReferenceType(type) {
|
|
583
677
|
return { $ref: `#/$defs/${type.name}` };
|
|
584
678
|
}
|
|
@@ -599,10 +693,7 @@ function generateDynamicType(type) {
|
|
|
599
693
|
"x-formspec-schemaSource": type.sourceKey
|
|
600
694
|
};
|
|
601
695
|
}
|
|
602
|
-
function
|
|
603
|
-
return { type: "object" };
|
|
604
|
-
}
|
|
605
|
-
function applyConstraints(schema, constraints) {
|
|
696
|
+
function applyConstraints(schema, constraints, ctx) {
|
|
606
697
|
for (const constraint of constraints) {
|
|
607
698
|
switch (constraint.constraintKind) {
|
|
608
699
|
case "minimum":
|
|
@@ -647,6 +738,7 @@ function applyConstraints(schema, constraints) {
|
|
|
647
738
|
case "allowedMembers":
|
|
648
739
|
break;
|
|
649
740
|
case "custom":
|
|
741
|
+
applyCustomConstraint(schema, constraint, ctx);
|
|
650
742
|
break;
|
|
651
743
|
default: {
|
|
652
744
|
const _exhaustive = constraint;
|
|
@@ -655,7 +747,7 @@ function applyConstraints(schema, constraints) {
|
|
|
655
747
|
}
|
|
656
748
|
}
|
|
657
749
|
}
|
|
658
|
-
function applyAnnotations(schema, annotations) {
|
|
750
|
+
function applyAnnotations(schema, annotations, ctx) {
|
|
659
751
|
for (const annotation of annotations) {
|
|
660
752
|
switch (annotation.annotationKind) {
|
|
661
753
|
case "displayName":
|
|
@@ -675,6 +767,7 @@ function applyAnnotations(schema, annotations) {
|
|
|
675
767
|
case "formatHint":
|
|
676
768
|
break;
|
|
677
769
|
case "custom":
|
|
770
|
+
applyCustomAnnotation(schema, annotation, ctx);
|
|
678
771
|
break;
|
|
679
772
|
default: {
|
|
680
773
|
const _exhaustive = annotation;
|
|
@@ -683,11 +776,41 @@ function applyAnnotations(schema, annotations) {
|
|
|
683
776
|
}
|
|
684
777
|
}
|
|
685
778
|
}
|
|
779
|
+
function generateCustomType(type, ctx) {
|
|
780
|
+
const registration = ctx.extensionRegistry?.findType(type.typeId);
|
|
781
|
+
if (registration === void 0) {
|
|
782
|
+
throw new Error(
|
|
783
|
+
`Cannot generate JSON Schema for custom type "${type.typeId}" without a matching extension registration`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
|
|
787
|
+
}
|
|
788
|
+
function applyCustomConstraint(schema, constraint, ctx) {
|
|
789
|
+
const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);
|
|
790
|
+
if (registration === void 0) {
|
|
791
|
+
throw new Error(
|
|
792
|
+
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
Object.assign(schema, registration.toJsonSchema(constraint.payload, ctx.vendorPrefix));
|
|
796
|
+
}
|
|
797
|
+
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
798
|
+
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
799
|
+
if (registration === void 0) {
|
|
800
|
+
throw new Error(
|
|
801
|
+
`Cannot generate JSON Schema for custom annotation "${annotation.annotationId}" without a matching extension registration`
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
if (registration.toJsonSchema === void 0) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
Object.assign(schema, registration.toJsonSchema(annotation.value, ctx.vendorPrefix));
|
|
808
|
+
}
|
|
686
809
|
|
|
687
810
|
// src/json-schema/generator.ts
|
|
688
|
-
function generateJsonSchema(form) {
|
|
811
|
+
function generateJsonSchema(form, options) {
|
|
689
812
|
const ir = canonicalizeChainDSL(form);
|
|
690
|
-
return generateJsonSchemaFromIR(ir);
|
|
813
|
+
return generateJsonSchemaFromIR(ir, options);
|
|
691
814
|
}
|
|
692
815
|
|
|
693
816
|
// src/ui-schema/schema.ts
|
|
@@ -921,6 +1044,48 @@ function getSchemaExtension(schema, key) {
|
|
|
921
1044
|
return schema[key];
|
|
922
1045
|
}
|
|
923
1046
|
|
|
1047
|
+
// src/extensions/registry.ts
|
|
1048
|
+
function createExtensionRegistry(extensions) {
|
|
1049
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
1050
|
+
const constraintMap = /* @__PURE__ */ new Map();
|
|
1051
|
+
const annotationMap = /* @__PURE__ */ new Map();
|
|
1052
|
+
for (const ext of extensions) {
|
|
1053
|
+
if (ext.types !== void 0) {
|
|
1054
|
+
for (const type of ext.types) {
|
|
1055
|
+
const qualifiedId = `${ext.extensionId}/${type.typeName}`;
|
|
1056
|
+
if (typeMap.has(qualifiedId)) {
|
|
1057
|
+
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
1058
|
+
}
|
|
1059
|
+
typeMap.set(qualifiedId, type);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
if (ext.constraints !== void 0) {
|
|
1063
|
+
for (const constraint of ext.constraints) {
|
|
1064
|
+
const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;
|
|
1065
|
+
if (constraintMap.has(qualifiedId)) {
|
|
1066
|
+
throw new Error(`Duplicate custom constraint ID: "${qualifiedId}"`);
|
|
1067
|
+
}
|
|
1068
|
+
constraintMap.set(qualifiedId, constraint);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
if (ext.annotations !== void 0) {
|
|
1072
|
+
for (const annotation of ext.annotations) {
|
|
1073
|
+
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
1074
|
+
if (annotationMap.has(qualifiedId)) {
|
|
1075
|
+
throw new Error(`Duplicate custom annotation ID: "${qualifiedId}"`);
|
|
1076
|
+
}
|
|
1077
|
+
annotationMap.set(qualifiedId, annotation);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
return {
|
|
1082
|
+
extensions,
|
|
1083
|
+
findType: (typeId) => typeMap.get(typeId),
|
|
1084
|
+
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1085
|
+
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
924
1089
|
// src/json-schema/schema.ts
|
|
925
1090
|
var import_zod3 = require("zod");
|
|
926
1091
|
var jsonSchemaTypeSchema = import_zod3.z.enum([
|
|
@@ -1060,26 +1225,36 @@ var ts4 = __toESM(require("typescript"), 1);
|
|
|
1060
1225
|
|
|
1061
1226
|
// src/analyzer/jsdoc-constraints.ts
|
|
1062
1227
|
var ts3 = __toESM(require("typescript"), 1);
|
|
1063
|
-
var import_core4 = require("@formspec/core");
|
|
1064
1228
|
|
|
1065
1229
|
// src/analyzer/tsdoc-parser.ts
|
|
1066
1230
|
var ts2 = __toESM(require("typescript"), 1);
|
|
1067
1231
|
var import_tsdoc = require("@microsoft/tsdoc");
|
|
1068
1232
|
var import_core3 = require("@formspec/core");
|
|
1233
|
+
|
|
1234
|
+
// src/analyzer/json-utils.ts
|
|
1235
|
+
function tryParseJson(text) {
|
|
1236
|
+
try {
|
|
1237
|
+
return JSON.parse(text);
|
|
1238
|
+
} catch {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// src/analyzer/tsdoc-parser.ts
|
|
1069
1244
|
var NUMERIC_CONSTRAINT_MAP = {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1245
|
+
minimum: "minimum",
|
|
1246
|
+
maximum: "maximum",
|
|
1247
|
+
exclusiveMinimum: "exclusiveMinimum",
|
|
1248
|
+
exclusiveMaximum: "exclusiveMaximum",
|
|
1249
|
+
multipleOf: "multipleOf"
|
|
1074
1250
|
};
|
|
1075
1251
|
var LENGTH_CONSTRAINT_MAP = {
|
|
1076
|
-
|
|
1077
|
-
|
|
1252
|
+
minLength: "minLength",
|
|
1253
|
+
maxLength: "maxLength",
|
|
1254
|
+
minItems: "minItems",
|
|
1255
|
+
maxItems: "maxItems"
|
|
1078
1256
|
};
|
|
1079
|
-
var TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["
|
|
1080
|
-
function isBuiltinConstraintName(tagName) {
|
|
1081
|
-
return tagName in import_core3.BUILTIN_CONSTRAINT_DEFINITIONS;
|
|
1082
|
-
}
|
|
1257
|
+
var TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["pattern", "enumOptions"]);
|
|
1083
1258
|
function createFormSpecTSDocConfig() {
|
|
1084
1259
|
const config = new import_tsdoc.TSDocConfiguration();
|
|
1085
1260
|
for (const tagName of Object.keys(import_core3.BUILTIN_CONSTRAINT_DEFINITIONS)) {
|
|
@@ -1091,6 +1266,15 @@ function createFormSpecTSDocConfig() {
|
|
|
1091
1266
|
})
|
|
1092
1267
|
);
|
|
1093
1268
|
}
|
|
1269
|
+
for (const tagName of ["displayName", "description"]) {
|
|
1270
|
+
config.addTagDefinition(
|
|
1271
|
+
new import_tsdoc.TSDocTagDefinition({
|
|
1272
|
+
tagName: "@" + tagName,
|
|
1273
|
+
syntaxKind: import_tsdoc.TSDocTagSyntaxKind.BlockTag,
|
|
1274
|
+
allowMultiple: true
|
|
1275
|
+
})
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1094
1278
|
return config;
|
|
1095
1279
|
}
|
|
1096
1280
|
var sharedParser;
|
|
@@ -1119,7 +1303,28 @@ function parseTSDocTags(node, file = "") {
|
|
|
1119
1303
|
);
|
|
1120
1304
|
const docComment = parserContext.docComment;
|
|
1121
1305
|
for (const block of docComment.customBlocks) {
|
|
1122
|
-
const tagName = block.blockTag.tagName.substring(1);
|
|
1306
|
+
const tagName = (0, import_core3.normalizeConstraintTagName)(block.blockTag.tagName.substring(1));
|
|
1307
|
+
if (tagName === "displayName" || tagName === "description") {
|
|
1308
|
+
const text2 = extractBlockText(block).trim();
|
|
1309
|
+
if (text2 === "") continue;
|
|
1310
|
+
const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
|
|
1311
|
+
if (tagName === "displayName") {
|
|
1312
|
+
annotations.push({
|
|
1313
|
+
kind: "annotation",
|
|
1314
|
+
annotationKind: "displayName",
|
|
1315
|
+
value: text2,
|
|
1316
|
+
provenance: provenance2
|
|
1317
|
+
});
|
|
1318
|
+
} else {
|
|
1319
|
+
annotations.push({
|
|
1320
|
+
kind: "annotation",
|
|
1321
|
+
annotationKind: "description",
|
|
1322
|
+
value: text2,
|
|
1323
|
+
provenance: provenance2
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1123
1328
|
if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
|
|
1124
1329
|
const text = extractBlockText(block).trim();
|
|
1125
1330
|
if (text === "") continue;
|
|
@@ -1140,7 +1345,7 @@ function parseTSDocTags(node, file = "") {
|
|
|
1140
1345
|
}
|
|
1141
1346
|
const jsDocTagsAll = ts2.getJSDocTags(node);
|
|
1142
1347
|
for (const tag of jsDocTagsAll) {
|
|
1143
|
-
const tagName = tag.tagName.text;
|
|
1348
|
+
const tagName = (0, import_core3.normalizeConstraintTagName)(tag.tagName.text);
|
|
1144
1349
|
if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
|
|
1145
1350
|
const commentText = getTagCommentText(tag);
|
|
1146
1351
|
if (commentText === void 0 || commentText.trim() === "") continue;
|
|
@@ -1151,43 +1356,17 @@ function parseTSDocTags(node, file = "") {
|
|
|
1151
1356
|
constraints.push(constraintNode);
|
|
1152
1357
|
}
|
|
1153
1358
|
}
|
|
1154
|
-
let displayName;
|
|
1155
|
-
let description;
|
|
1156
|
-
let displayNameTag;
|
|
1157
|
-
let descriptionTag;
|
|
1158
|
-
for (const tag of jsDocTagsAll) {
|
|
1159
|
-
const tagName = tag.tagName.text;
|
|
1160
|
-
const commentText = getTagCommentText(tag);
|
|
1161
|
-
if (commentText === void 0 || commentText.trim() === "") {
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
const trimmed = commentText.trim();
|
|
1165
|
-
if (tagName === "Field_displayName") {
|
|
1166
|
-
displayName = trimmed;
|
|
1167
|
-
displayNameTag = tag;
|
|
1168
|
-
} else if (tagName === "Field_description") {
|
|
1169
|
-
description = trimmed;
|
|
1170
|
-
descriptionTag = tag;
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
if (displayName !== void 0 && displayNameTag) {
|
|
1174
|
-
annotations.push({
|
|
1175
|
-
kind: "annotation",
|
|
1176
|
-
annotationKind: "displayName",
|
|
1177
|
-
value: displayName,
|
|
1178
|
-
provenance: provenanceForJSDocTag(displayNameTag, file)
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
if (description !== void 0 && descriptionTag) {
|
|
1182
|
-
annotations.push({
|
|
1183
|
-
kind: "annotation",
|
|
1184
|
-
annotationKind: "description",
|
|
1185
|
-
value: description,
|
|
1186
|
-
provenance: provenanceForJSDocTag(descriptionTag, file)
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
1359
|
return { constraints, annotations };
|
|
1190
1360
|
}
|
|
1361
|
+
function extractPathTarget(text) {
|
|
1362
|
+
const trimmed = text.trimStart();
|
|
1363
|
+
const match = /^:([a-zA-Z_]\w*)\s+([\s\S]*)$/.exec(trimmed);
|
|
1364
|
+
if (!match?.[1] || !match[2]) return null;
|
|
1365
|
+
return {
|
|
1366
|
+
path: { segments: [match[1]] },
|
|
1367
|
+
remainingText: match[2]
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1191
1370
|
function extractBlockText(block) {
|
|
1192
1371
|
return extractPlainText(block.content);
|
|
1193
1372
|
}
|
|
@@ -1207,12 +1386,15 @@ function extractPlainText(node) {
|
|
|
1207
1386
|
return result;
|
|
1208
1387
|
}
|
|
1209
1388
|
function parseConstraintValue(tagName, text, provenance) {
|
|
1210
|
-
if (!isBuiltinConstraintName(tagName)) {
|
|
1389
|
+
if (!(0, import_core3.isBuiltinConstraintName)(tagName)) {
|
|
1211
1390
|
return null;
|
|
1212
1391
|
}
|
|
1392
|
+
const pathResult = extractPathTarget(text);
|
|
1393
|
+
const effectiveText = pathResult ? pathResult.remainingText : text;
|
|
1394
|
+
const path3 = pathResult?.path;
|
|
1213
1395
|
const expectedType = import_core3.BUILTIN_CONSTRAINT_DEFINITIONS[tagName];
|
|
1214
1396
|
if (expectedType === "number") {
|
|
1215
|
-
const value = Number(
|
|
1397
|
+
const value = Number(effectiveText);
|
|
1216
1398
|
if (Number.isNaN(value)) {
|
|
1217
1399
|
return null;
|
|
1218
1400
|
}
|
|
@@ -1222,6 +1404,7 @@ function parseConstraintValue(tagName, text, provenance) {
|
|
|
1222
1404
|
kind: "constraint",
|
|
1223
1405
|
constraintKind: numericKind,
|
|
1224
1406
|
value,
|
|
1407
|
+
...path3 && { path: path3 },
|
|
1225
1408
|
provenance
|
|
1226
1409
|
};
|
|
1227
1410
|
}
|
|
@@ -1231,42 +1414,41 @@ function parseConstraintValue(tagName, text, provenance) {
|
|
|
1231
1414
|
kind: "constraint",
|
|
1232
1415
|
constraintKind: lengthKind,
|
|
1233
1416
|
value,
|
|
1417
|
+
...path3 && { path: path3 },
|
|
1234
1418
|
provenance
|
|
1235
1419
|
};
|
|
1236
1420
|
}
|
|
1237
1421
|
return null;
|
|
1238
1422
|
}
|
|
1239
1423
|
if (expectedType === "json") {
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
members.push(id);
|
|
1253
|
-
}
|
|
1424
|
+
const parsed = tryParseJson(effectiveText);
|
|
1425
|
+
if (!Array.isArray(parsed)) {
|
|
1426
|
+
return null;
|
|
1427
|
+
}
|
|
1428
|
+
const members = [];
|
|
1429
|
+
for (const item of parsed) {
|
|
1430
|
+
if (typeof item === "string" || typeof item === "number") {
|
|
1431
|
+
members.push(item);
|
|
1432
|
+
} else if (typeof item === "object" && item !== null && "id" in item) {
|
|
1433
|
+
const id = item["id"];
|
|
1434
|
+
if (typeof id === "string" || typeof id === "number") {
|
|
1435
|
+
members.push(id);
|
|
1254
1436
|
}
|
|
1255
1437
|
}
|
|
1256
|
-
return {
|
|
1257
|
-
kind: "constraint",
|
|
1258
|
-
constraintKind: "allowedMembers",
|
|
1259
|
-
members,
|
|
1260
|
-
provenance
|
|
1261
|
-
};
|
|
1262
|
-
} catch {
|
|
1263
|
-
return null;
|
|
1264
1438
|
}
|
|
1439
|
+
return {
|
|
1440
|
+
kind: "constraint",
|
|
1441
|
+
constraintKind: "allowedMembers",
|
|
1442
|
+
members,
|
|
1443
|
+
...path3 && { path: path3 },
|
|
1444
|
+
provenance
|
|
1445
|
+
};
|
|
1265
1446
|
}
|
|
1266
1447
|
return {
|
|
1267
1448
|
kind: "constraint",
|
|
1268
1449
|
constraintKind: "pattern",
|
|
1269
|
-
pattern:
|
|
1450
|
+
pattern: effectiveText,
|
|
1451
|
+
...path3 && { path: path3 },
|
|
1270
1452
|
provenance
|
|
1271
1453
|
};
|
|
1272
1454
|
}
|
|
@@ -1438,18 +1620,19 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
|
|
|
1438
1620
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1439
1621
|
const optional = prop.questionToken !== void 0;
|
|
1440
1622
|
const provenance = provenanceForNode(prop, file);
|
|
1441
|
-
|
|
1623
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1442
1624
|
const constraints = [];
|
|
1443
1625
|
if (prop.type) {
|
|
1444
1626
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1445
1627
|
}
|
|
1446
1628
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1447
|
-
|
|
1629
|
+
let annotations = [];
|
|
1448
1630
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1449
1631
|
const defaultAnnotation = extractDefaultValueAnnotation(prop.initializer, file);
|
|
1450
1632
|
if (defaultAnnotation) {
|
|
1451
1633
|
annotations.push(defaultAnnotation);
|
|
1452
1634
|
}
|
|
1635
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1453
1636
|
return {
|
|
1454
1637
|
kind: "field",
|
|
1455
1638
|
name,
|
|
@@ -1468,14 +1651,15 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1468
1651
|
const tsType = checker.getTypeAtLocation(prop);
|
|
1469
1652
|
const optional = prop.questionToken !== void 0;
|
|
1470
1653
|
const provenance = provenanceForNode(prop, file);
|
|
1471
|
-
|
|
1654
|
+
let type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
|
|
1472
1655
|
const constraints = [];
|
|
1473
1656
|
if (prop.type) {
|
|
1474
1657
|
constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
|
|
1475
1658
|
}
|
|
1476
1659
|
constraints.push(...extractJSDocConstraintNodes(prop, file));
|
|
1477
|
-
|
|
1660
|
+
let annotations = [];
|
|
1478
1661
|
annotations.push(...extractJSDocAnnotationNodes(prop, file));
|
|
1662
|
+
({ type, annotations } = applyEnumMemberDisplayNames(type, annotations));
|
|
1479
1663
|
return {
|
|
1480
1664
|
kind: "field",
|
|
1481
1665
|
name,
|
|
@@ -1486,6 +1670,68 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
|
|
|
1486
1670
|
provenance
|
|
1487
1671
|
};
|
|
1488
1672
|
}
|
|
1673
|
+
function applyEnumMemberDisplayNames(type, annotations) {
|
|
1674
|
+
if (!annotations.some(
|
|
1675
|
+
(annotation) => annotation.annotationKind === "displayName" && annotation.value.trim().startsWith(":")
|
|
1676
|
+
)) {
|
|
1677
|
+
return { type, annotations: [...annotations] };
|
|
1678
|
+
}
|
|
1679
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1680
|
+
const nextType = rewriteEnumDisplayNames(type, annotations, consumed);
|
|
1681
|
+
if (consumed.size === 0) {
|
|
1682
|
+
return { type, annotations: [...annotations] };
|
|
1683
|
+
}
|
|
1684
|
+
return {
|
|
1685
|
+
type: nextType,
|
|
1686
|
+
annotations: annotations.filter((annotation) => !consumed.has(annotation))
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
function rewriteEnumDisplayNames(type, annotations, consumed) {
|
|
1690
|
+
switch (type.kind) {
|
|
1691
|
+
case "enum":
|
|
1692
|
+
return applyEnumMemberDisplayNamesToEnum(type, annotations, consumed);
|
|
1693
|
+
case "union": {
|
|
1694
|
+
return {
|
|
1695
|
+
...type,
|
|
1696
|
+
members: type.members.map(
|
|
1697
|
+
(member) => rewriteEnumDisplayNames(member, annotations, consumed)
|
|
1698
|
+
)
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
default:
|
|
1702
|
+
return type;
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
function applyEnumMemberDisplayNamesToEnum(type, annotations, consumed) {
|
|
1706
|
+
const displayNames = /* @__PURE__ */ new Map();
|
|
1707
|
+
for (const annotation of annotations) {
|
|
1708
|
+
if (annotation.annotationKind !== "displayName") continue;
|
|
1709
|
+
const parsed = parseEnumMemberDisplayName(annotation.value);
|
|
1710
|
+
if (!parsed) continue;
|
|
1711
|
+
consumed.add(annotation);
|
|
1712
|
+
const member = type.members.find((m) => String(m.value) === parsed.value);
|
|
1713
|
+
if (!member) continue;
|
|
1714
|
+
displayNames.set(String(member.value), parsed.label);
|
|
1715
|
+
}
|
|
1716
|
+
if (displayNames.size === 0) {
|
|
1717
|
+
return type;
|
|
1718
|
+
}
|
|
1719
|
+
return {
|
|
1720
|
+
...type,
|
|
1721
|
+
members: type.members.map((member) => {
|
|
1722
|
+
const displayName = displayNames.get(String(member.value));
|
|
1723
|
+
return displayName !== void 0 ? { ...member, displayName } : member;
|
|
1724
|
+
})
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
function parseEnumMemberDisplayName(value) {
|
|
1728
|
+
const trimmed = value.trim();
|
|
1729
|
+
const match = /^:([^\s]+)\s+([\s\S]+)$/.exec(trimmed);
|
|
1730
|
+
if (!match?.[1] || !match[2]) return null;
|
|
1731
|
+
const label = match[2].trim();
|
|
1732
|
+
if (label === "") return null;
|
|
1733
|
+
return { value: match[1], label };
|
|
1734
|
+
}
|
|
1489
1735
|
function resolveTypeNode(type, checker, file, typeRegistry, visiting) {
|
|
1490
1736
|
if (type.flags & ts4.TypeFlags.String) {
|
|
1491
1737
|
return { kind: "primitive", primitiveKind: "string" };
|
|
@@ -1596,7 +1842,30 @@ function resolveArrayType(type, checker, file, typeRegistry, visiting) {
|
|
|
1596
1842
|
const items = elementType ? resolveTypeNode(elementType, checker, file, typeRegistry, visiting) : { kind: "primitive", primitiveKind: "string" };
|
|
1597
1843
|
return { kind: "array", items };
|
|
1598
1844
|
}
|
|
1845
|
+
function tryResolveRecordType(type, checker, file, typeRegistry, visiting) {
|
|
1846
|
+
if (type.getProperties().length > 0) {
|
|
1847
|
+
return null;
|
|
1848
|
+
}
|
|
1849
|
+
const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
|
|
1850
|
+
if (!indexInfo) {
|
|
1851
|
+
return null;
|
|
1852
|
+
}
|
|
1853
|
+
if (visiting.has(type)) {
|
|
1854
|
+
return null;
|
|
1855
|
+
}
|
|
1856
|
+
visiting.add(type);
|
|
1857
|
+
try {
|
|
1858
|
+
const valueType = resolveTypeNode(indexInfo.type, checker, file, typeRegistry, visiting);
|
|
1859
|
+
return { kind: "record", valueType };
|
|
1860
|
+
} finally {
|
|
1861
|
+
visiting.delete(type);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1599
1864
|
function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
1865
|
+
const recordNode = tryResolveRecordType(type, checker, file, typeRegistry, visiting);
|
|
1866
|
+
if (recordNode) {
|
|
1867
|
+
return recordNode;
|
|
1868
|
+
}
|
|
1600
1869
|
if (visiting.has(type)) {
|
|
1601
1870
|
return { kind: "object", properties: [], additionalProperties: false };
|
|
1602
1871
|
}
|
|
@@ -1628,7 +1897,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
|
|
|
1628
1897
|
const objectNode = {
|
|
1629
1898
|
kind: "object",
|
|
1630
1899
|
properties,
|
|
1631
|
-
additionalProperties:
|
|
1900
|
+
additionalProperties: true
|
|
1632
1901
|
};
|
|
1633
1902
|
if (typeName) {
|
|
1634
1903
|
typeRegistry[typeName] = {
|
|
@@ -1697,14 +1966,23 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting) {
|
|
|
1697
1966
|
}
|
|
1698
1967
|
return map;
|
|
1699
1968
|
}
|
|
1700
|
-
|
|
1969
|
+
var MAX_ALIAS_CHAIN_DEPTH = 8;
|
|
1970
|
+
function extractTypeAliasConstraintNodes(typeNode, checker, file, depth = 0) {
|
|
1701
1971
|
if (!ts4.isTypeReferenceNode(typeNode)) return [];
|
|
1972
|
+
if (depth >= MAX_ALIAS_CHAIN_DEPTH) {
|
|
1973
|
+
const aliasName = typeNode.typeName.getText();
|
|
1974
|
+
throw new Error(
|
|
1975
|
+
`Type alias chain exceeds maximum depth of ${String(MAX_ALIAS_CHAIN_DEPTH)} at alias "${aliasName}" in ${file}. Simplify the alias chain or check for circular references.`
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1702
1978
|
const symbol = checker.getSymbolAtLocation(typeNode.typeName);
|
|
1703
1979
|
if (!symbol?.declarations) return [];
|
|
1704
1980
|
const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
|
|
1705
1981
|
if (!aliasDecl) return [];
|
|
1706
1982
|
if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
|
|
1707
|
-
|
|
1983
|
+
const constraints = extractJSDocConstraintNodes(aliasDecl, file);
|
|
1984
|
+
constraints.push(...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, depth + 1));
|
|
1985
|
+
return constraints;
|
|
1708
1986
|
}
|
|
1709
1987
|
function provenanceForNode(node, file) {
|
|
1710
1988
|
const sourceFile = node.getSourceFile();
|
|
@@ -1822,15 +2100,19 @@ function generateSchemas(options) {
|
|
|
1822
2100
|
}
|
|
1823
2101
|
|
|
1824
2102
|
// src/index.ts
|
|
1825
|
-
function buildFormSchemas(form) {
|
|
2103
|
+
function buildFormSchemas(form, options) {
|
|
1826
2104
|
return {
|
|
1827
|
-
jsonSchema: generateJsonSchema(form),
|
|
2105
|
+
jsonSchema: generateJsonSchema(form, options),
|
|
1828
2106
|
uiSchema: generateUiSchema(form)
|
|
1829
2107
|
};
|
|
1830
2108
|
}
|
|
1831
2109
|
function writeSchemas(form, options) {
|
|
1832
|
-
const { outDir, name = "schema", indent = 2 } = options;
|
|
1833
|
-
const
|
|
2110
|
+
const { outDir, name = "schema", indent = 2, extensionRegistry, vendorPrefix } = options;
|
|
2111
|
+
const buildOptions = extensionRegistry === void 0 && vendorPrefix === void 0 ? void 0 : {
|
|
2112
|
+
extensionRegistry,
|
|
2113
|
+
vendorPrefix
|
|
2114
|
+
};
|
|
2115
|
+
const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form, buildOptions);
|
|
1834
2116
|
if (!fs.existsSync(outDir)) {
|
|
1835
2117
|
fs.mkdirSync(outDir, { recursive: true });
|
|
1836
2118
|
}
|
|
@@ -1846,7 +2128,9 @@ function writeSchemas(form, options) {
|
|
|
1846
2128
|
categorizationSchema,
|
|
1847
2129
|
categorySchema,
|
|
1848
2130
|
controlSchema,
|
|
2131
|
+
createExtensionRegistry,
|
|
1849
2132
|
generateJsonSchema,
|
|
2133
|
+
generateJsonSchemaFromIR,
|
|
1850
2134
|
generateSchemas,
|
|
1851
2135
|
generateSchemasFromClass,
|
|
1852
2136
|
generateUiSchema,
|