@formspec/build 0.1.0-alpha.16 → 0.1.0-alpha.17
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__/fixtures/example-numeric-extension.d.ts +20 -0
- package/dist/__tests__/fixtures/example-numeric-extension.d.ts.map +1 -0
- package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts +1 -0
- package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts.map +1 -1
- package/dist/__tests__/numeric-extension.integration.test.d.ts +2 -0
- package/dist/__tests__/numeric-extension.integration.test.d.ts.map +1 -0
- package/dist/analyzer/class-analyzer.d.ts +5 -4
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/jsdoc-constraints.d.ts +3 -2
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +18 -2
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +199 -4
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +199 -4
- package/dist/browser.js.map +1 -1
- package/dist/build.d.ts +28 -2
- package/dist/cli.cjs +547 -84
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +547 -84
- package/dist/cli.js.map +1 -1
- package/dist/extensions/registry.d.ts +25 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/generators/class-schema.d.ts +4 -4
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/index.cjs +546 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +546 -84
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +645 -73
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +643 -71
- package/dist/internals.js.map +1 -1
- package/dist/validate/constraint-validator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/browser.js
CHANGED
|
@@ -704,7 +704,12 @@ function applyCustomConstraint(schema, constraint, ctx) {
|
|
|
704
704
|
`Cannot generate JSON Schema for custom constraint "${constraint.constraintId}" without a matching extension registration`
|
|
705
705
|
);
|
|
706
706
|
}
|
|
707
|
-
|
|
707
|
+
assignVendorPrefixedExtensionKeywords(
|
|
708
|
+
schema,
|
|
709
|
+
registration.toJsonSchema(constraint.payload, ctx.vendorPrefix),
|
|
710
|
+
ctx.vendorPrefix,
|
|
711
|
+
`custom constraint "${constraint.constraintId}"`
|
|
712
|
+
);
|
|
708
713
|
}
|
|
709
714
|
function applyCustomAnnotation(schema, annotation, ctx) {
|
|
710
715
|
const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);
|
|
@@ -716,7 +721,22 @@ function applyCustomAnnotation(schema, annotation, ctx) {
|
|
|
716
721
|
if (registration.toJsonSchema === void 0) {
|
|
717
722
|
return;
|
|
718
723
|
}
|
|
719
|
-
|
|
724
|
+
assignVendorPrefixedExtensionKeywords(
|
|
725
|
+
schema,
|
|
726
|
+
registration.toJsonSchema(annotation.value, ctx.vendorPrefix),
|
|
727
|
+
ctx.vendorPrefix,
|
|
728
|
+
`custom annotation "${annotation.annotationId}"`
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
function assignVendorPrefixedExtensionKeywords(schema, extensionSchema, vendorPrefix, source) {
|
|
732
|
+
for (const [key, value] of Object.entries(extensionSchema)) {
|
|
733
|
+
if (!key.startsWith(`${vendorPrefix}-`)) {
|
|
734
|
+
throw new Error(
|
|
735
|
+
`Cannot apply ${source}: extension hooks may only emit "${vendorPrefix}-*" JSON Schema keywords`
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
schema[key] = value;
|
|
739
|
+
}
|
|
720
740
|
}
|
|
721
741
|
|
|
722
742
|
// src/json-schema/generator.ts
|
|
@@ -965,7 +985,10 @@ function getSchemaExtension(schema, key) {
|
|
|
965
985
|
// src/extensions/registry.ts
|
|
966
986
|
function createExtensionRegistry(extensions) {
|
|
967
987
|
const typeMap = /* @__PURE__ */ new Map();
|
|
988
|
+
const typeNameMap = /* @__PURE__ */ new Map();
|
|
968
989
|
const constraintMap = /* @__PURE__ */ new Map();
|
|
990
|
+
const constraintTagMap = /* @__PURE__ */ new Map();
|
|
991
|
+
const builtinBroadeningMap = /* @__PURE__ */ new Map();
|
|
969
992
|
const annotationMap = /* @__PURE__ */ new Map();
|
|
970
993
|
for (const ext of extensions) {
|
|
971
994
|
if (ext.types !== void 0) {
|
|
@@ -975,6 +998,27 @@ function createExtensionRegistry(extensions) {
|
|
|
975
998
|
throw new Error(`Duplicate custom type ID: "${qualifiedId}"`);
|
|
976
999
|
}
|
|
977
1000
|
typeMap.set(qualifiedId, type);
|
|
1001
|
+
for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {
|
|
1002
|
+
if (typeNameMap.has(sourceTypeName)) {
|
|
1003
|
+
throw new Error(`Duplicate custom type source name: "${sourceTypeName}"`);
|
|
1004
|
+
}
|
|
1005
|
+
typeNameMap.set(sourceTypeName, {
|
|
1006
|
+
extensionId: ext.extensionId,
|
|
1007
|
+
registration: type
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
if (type.builtinConstraintBroadenings !== void 0) {
|
|
1011
|
+
for (const broadening of type.builtinConstraintBroadenings) {
|
|
1012
|
+
const key = `${qualifiedId}:${broadening.tagName}`;
|
|
1013
|
+
if (builtinBroadeningMap.has(key)) {
|
|
1014
|
+
throw new Error(`Duplicate built-in constraint broadening: "${key}"`);
|
|
1015
|
+
}
|
|
1016
|
+
builtinBroadeningMap.set(key, {
|
|
1017
|
+
extensionId: ext.extensionId,
|
|
1018
|
+
registration: broadening
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
978
1022
|
}
|
|
979
1023
|
}
|
|
980
1024
|
if (ext.constraints !== void 0) {
|
|
@@ -986,6 +1030,17 @@ function createExtensionRegistry(extensions) {
|
|
|
986
1030
|
constraintMap.set(qualifiedId, constraint);
|
|
987
1031
|
}
|
|
988
1032
|
}
|
|
1033
|
+
if (ext.constraintTags !== void 0) {
|
|
1034
|
+
for (const tag of ext.constraintTags) {
|
|
1035
|
+
if (constraintTagMap.has(tag.tagName)) {
|
|
1036
|
+
throw new Error(`Duplicate custom constraint tag: "@${tag.tagName}"`);
|
|
1037
|
+
}
|
|
1038
|
+
constraintTagMap.set(tag.tagName, {
|
|
1039
|
+
extensionId: ext.extensionId,
|
|
1040
|
+
registration: tag
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
989
1044
|
if (ext.annotations !== void 0) {
|
|
990
1045
|
for (const annotation of ext.annotations) {
|
|
991
1046
|
const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;
|
|
@@ -999,7 +1054,10 @@ function createExtensionRegistry(extensions) {
|
|
|
999
1054
|
return {
|
|
1000
1055
|
extensions,
|
|
1001
1056
|
findType: (typeId) => typeMap.get(typeId),
|
|
1057
|
+
findTypeByName: (typeName) => typeNameMap.get(typeName),
|
|
1002
1058
|
findConstraint: (constraintId) => constraintMap.get(constraintId),
|
|
1059
|
+
findConstraintTag: (tagName) => constraintTagMap.get(tagName),
|
|
1060
|
+
findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
|
|
1003
1061
|
findAnnotation: (annotationId) => annotationMap.get(annotationId)
|
|
1004
1062
|
};
|
|
1005
1063
|
}
|
|
@@ -1067,6 +1125,7 @@ var jsonSchema7Schema = z3.lazy(
|
|
|
1067
1125
|
);
|
|
1068
1126
|
|
|
1069
1127
|
// src/validate/constraint-validator.ts
|
|
1128
|
+
import { normalizeConstraintTagName } from "@formspec/core";
|
|
1070
1129
|
function addContradiction(ctx, message, primary, related) {
|
|
1071
1130
|
ctx.diagnostics.push({
|
|
1072
1131
|
code: "CONTRADICTING_CONSTRAINTS",
|
|
@@ -1112,6 +1171,13 @@ function addConstraintBroadening(ctx, message, primary, related) {
|
|
|
1112
1171
|
relatedLocations: [related]
|
|
1113
1172
|
});
|
|
1114
1173
|
}
|
|
1174
|
+
function getExtensionIdFromConstraintId(constraintId) {
|
|
1175
|
+
const separator = constraintId.lastIndexOf("/");
|
|
1176
|
+
if (separator <= 0) {
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
return constraintId.slice(0, separator);
|
|
1180
|
+
}
|
|
1115
1181
|
function findNumeric(constraints, constraintKind) {
|
|
1116
1182
|
return constraints.find((c) => c.constraintKind === constraintKind);
|
|
1117
1183
|
}
|
|
@@ -1282,6 +1348,112 @@ function checkConstraintBroadening(ctx, fieldName, constraints) {
|
|
|
1282
1348
|
strongestByKey.set(key, constraint);
|
|
1283
1349
|
}
|
|
1284
1350
|
}
|
|
1351
|
+
function compareCustomConstraintStrength(current, previous) {
|
|
1352
|
+
const order = current.comparePayloads(current.constraint.payload, previous.constraint.payload);
|
|
1353
|
+
const equalPayloadTiebreaker = order === 0 ? compareSemanticInclusivity(current.role.inclusive, previous.role.inclusive) : order;
|
|
1354
|
+
switch (current.role.bound) {
|
|
1355
|
+
case "lower":
|
|
1356
|
+
return equalPayloadTiebreaker;
|
|
1357
|
+
case "upper":
|
|
1358
|
+
return equalPayloadTiebreaker === 0 ? 0 : -equalPayloadTiebreaker;
|
|
1359
|
+
case "exact":
|
|
1360
|
+
return order === 0 ? 0 : Number.NaN;
|
|
1361
|
+
default: {
|
|
1362
|
+
const _exhaustive = current.role.bound;
|
|
1363
|
+
return _exhaustive;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
function compareSemanticInclusivity(currentInclusive, previousInclusive) {
|
|
1368
|
+
if (currentInclusive === previousInclusive) {
|
|
1369
|
+
return 0;
|
|
1370
|
+
}
|
|
1371
|
+
return currentInclusive ? -1 : 1;
|
|
1372
|
+
}
|
|
1373
|
+
function customConstraintsContradict(lower, upper) {
|
|
1374
|
+
const order = lower.comparePayloads(lower.constraint.payload, upper.constraint.payload);
|
|
1375
|
+
if (order > 0) {
|
|
1376
|
+
return true;
|
|
1377
|
+
}
|
|
1378
|
+
if (order < 0) {
|
|
1379
|
+
return false;
|
|
1380
|
+
}
|
|
1381
|
+
return !lower.role.inclusive || !upper.role.inclusive;
|
|
1382
|
+
}
|
|
1383
|
+
function describeCustomConstraintTag(constraint) {
|
|
1384
|
+
return constraint.provenance.tagName ?? constraint.constraintId;
|
|
1385
|
+
}
|
|
1386
|
+
function checkCustomConstraintSemantics(ctx, fieldName, constraints) {
|
|
1387
|
+
if (ctx.extensionRegistry === void 0) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
const strongestByKey = /* @__PURE__ */ new Map();
|
|
1391
|
+
const lowerByFamily = /* @__PURE__ */ new Map();
|
|
1392
|
+
const upperByFamily = /* @__PURE__ */ new Map();
|
|
1393
|
+
for (const constraint of constraints) {
|
|
1394
|
+
if (constraint.constraintKind !== "custom") {
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
const registration = ctx.extensionRegistry.findConstraint(constraint.constraintId);
|
|
1398
|
+
if (registration?.comparePayloads === void 0 || registration.semanticRole === void 0) {
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
const entry = {
|
|
1402
|
+
constraint,
|
|
1403
|
+
comparePayloads: registration.comparePayloads,
|
|
1404
|
+
role: registration.semanticRole
|
|
1405
|
+
};
|
|
1406
|
+
const familyKey = `${registration.semanticRole.family}:${pathKey(constraint)}`;
|
|
1407
|
+
const boundKey = `${familyKey}:${registration.semanticRole.bound}`;
|
|
1408
|
+
const previous = strongestByKey.get(boundKey);
|
|
1409
|
+
if (previous !== void 0) {
|
|
1410
|
+
const strength = compareCustomConstraintStrength(entry, previous);
|
|
1411
|
+
if (Number.isNaN(strength)) {
|
|
1412
|
+
addContradiction(
|
|
1413
|
+
ctx,
|
|
1414
|
+
`Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} conflicts with ${describeCustomConstraintTag(previous.constraint)}`,
|
|
1415
|
+
constraint.provenance,
|
|
1416
|
+
previous.constraint.provenance
|
|
1417
|
+
);
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
if (strength < 0) {
|
|
1421
|
+
addConstraintBroadening(
|
|
1422
|
+
ctx,
|
|
1423
|
+
`Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} is broader than earlier ${describeCustomConstraintTag(previous.constraint)}. Constraints can only narrow.`,
|
|
1424
|
+
constraint.provenance,
|
|
1425
|
+
previous.constraint.provenance
|
|
1426
|
+
);
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
if (strength > 0) {
|
|
1430
|
+
strongestByKey.set(boundKey, entry);
|
|
1431
|
+
}
|
|
1432
|
+
} else {
|
|
1433
|
+
strongestByKey.set(boundKey, entry);
|
|
1434
|
+
}
|
|
1435
|
+
if (registration.semanticRole.bound === "lower") {
|
|
1436
|
+
lowerByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
|
|
1437
|
+
} else if (registration.semanticRole.bound === "upper") {
|
|
1438
|
+
upperByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
for (const [familyKey, lower] of lowerByFamily) {
|
|
1442
|
+
const upper = upperByFamily.get(familyKey);
|
|
1443
|
+
if (upper === void 0) {
|
|
1444
|
+
continue;
|
|
1445
|
+
}
|
|
1446
|
+
if (!customConstraintsContradict(lower, upper)) {
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
addContradiction(
|
|
1450
|
+
ctx,
|
|
1451
|
+
`Field "${formatPathTargetFieldName(fieldName, lower.constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(lower.constraint)} contradicts ${describeCustomConstraintTag(upper.constraint)}`,
|
|
1452
|
+
lower.constraint.provenance,
|
|
1453
|
+
upper.constraint.provenance
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1285
1457
|
function checkNumericContradictions(ctx, fieldName, constraints) {
|
|
1286
1458
|
const min = findNumeric(constraints, "minimum");
|
|
1287
1459
|
const max = findNumeric(constraints, "maximum");
|
|
@@ -1593,8 +1765,30 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
|
|
|
1593
1765
|
);
|
|
1594
1766
|
return;
|
|
1595
1767
|
}
|
|
1596
|
-
|
|
1597
|
-
if (
|
|
1768
|
+
const normalizedTagName = constraint.provenance.tagName === void 0 ? void 0 : normalizeConstraintTagName(constraint.provenance.tagName.replace(/^@/, ""));
|
|
1769
|
+
if (normalizedTagName !== void 0) {
|
|
1770
|
+
const tagRegistration = ctx.extensionRegistry.findConstraintTag(normalizedTagName);
|
|
1771
|
+
const extensionId = getExtensionIdFromConstraintId(constraint.constraintId);
|
|
1772
|
+
if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && tagRegistration.registration.isApplicableToType?.(type) === false) {
|
|
1773
|
+
addTypeMismatch(
|
|
1774
|
+
ctx,
|
|
1775
|
+
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
1776
|
+
constraint.provenance
|
|
1777
|
+
);
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if (registration.applicableTypes === null) {
|
|
1782
|
+
if (registration.isApplicableToType?.(type) === false) {
|
|
1783
|
+
addTypeMismatch(
|
|
1784
|
+
ctx,
|
|
1785
|
+
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
1786
|
+
constraint.provenance
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
if (!registration.applicableTypes.includes(type.kind) || registration.isApplicableToType?.(type) === false) {
|
|
1598
1792
|
addTypeMismatch(
|
|
1599
1793
|
ctx,
|
|
1600
1794
|
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
@@ -1625,6 +1819,7 @@ function validateConstraints(ctx, name, type, constraints) {
|
|
|
1625
1819
|
checkAllowedMembersContradiction(ctx, name, constraints);
|
|
1626
1820
|
checkConstContradictions(ctx, name, constraints);
|
|
1627
1821
|
checkConstraintBroadening(ctx, name, constraints);
|
|
1822
|
+
checkCustomConstraintSemantics(ctx, name, constraints);
|
|
1628
1823
|
checkTypeApplicability(ctx, name, type, constraints);
|
|
1629
1824
|
}
|
|
1630
1825
|
function validateElement(ctx, element) {
|