@formspec/build 0.1.0-alpha.17 → 0.1.0-alpha.19
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 +74 -128
- package/dist/__tests__/class-schema.test.d.ts +2 -0
- package/dist/__tests__/class-schema.test.d.ts.map +1 -0
- package/dist/__tests__/date-extension.integration.test.d.ts +2 -0
- package/dist/__tests__/date-extension.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fixtures/class-schema-regressions.d.ts +83 -0
- package/dist/__tests__/fixtures/class-schema-regressions.d.ts.map +1 -0
- package/dist/__tests__/fixtures/example-date-extension.d.ts +12 -0
- package/dist/__tests__/fixtures/example-date-extension.d.ts.map +1 -0
- package/dist/__tests__/fixtures/extension-forms.d.ts +7 -0
- package/dist/__tests__/fixtures/extension-forms.d.ts.map +1 -0
- package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts.map +1 -1
- package/dist/__tests__/fixtures/named-primitive-aliases.d.ts +15 -0
- package/dist/__tests__/fixtures/named-primitive-aliases.d.ts.map +1 -0
- package/dist/__tests__/fixtures/nested-array-path-constraints.d.ts +14 -0
- package/dist/__tests__/fixtures/nested-array-path-constraints.d.ts.map +1 -0
- package/dist/__tests__/fixtures/sample-forms.d.ts +10 -0
- package/dist/__tests__/fixtures/sample-forms.d.ts.map +1 -1
- package/dist/__tests__/generate-schemas.test.d.ts +2 -0
- package/dist/__tests__/generate-schemas.test.d.ts.map +1 -0
- package/dist/__tests__/parity/parity.test.d.ts +6 -2
- package/dist/__tests__/parity/parity.test.d.ts.map +1 -1
- package/dist/__tests__/parity/utils.d.ts +9 -4
- package/dist/__tests__/parity/utils.d.ts.map +1 -1
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +15 -0
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +5 -0
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
- package/dist/browser.cjs +73 -10
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +73 -10
- package/dist/browser.js.map +1 -1
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -1
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -1
- package/dist/cli.cjs +1147 -252
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1142 -248
- package/dist/cli.js.map +1 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/generators/mixed-authoring.d.ts.map +1 -1
- package/dist/index.cjs +1121 -239
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1121 -239
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +377 -195
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +377 -195
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/ir-generator.d.ts.map +1 -1
- package/dist/validate/constraint-validator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/browser.cjs
CHANGED
|
@@ -70,6 +70,7 @@ function canonicalizeChainDSL(form) {
|
|
|
70
70
|
kind: "form-ir",
|
|
71
71
|
irVersion: import_core.IR_VERSION,
|
|
72
72
|
elements: canonicalizeElements(form.elements),
|
|
73
|
+
rootAnnotations: [],
|
|
73
74
|
typeRegistry: {},
|
|
74
75
|
provenance: CHAIN_DSL_PROVENANCE
|
|
75
76
|
};
|
|
@@ -380,6 +381,9 @@ function generateJsonSchemaFromIR(ir, options) {
|
|
|
380
381
|
const ctx = makeContext(options);
|
|
381
382
|
for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
|
|
382
383
|
ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
|
|
384
|
+
if (typeDef.constraints && typeDef.constraints.length > 0) {
|
|
385
|
+
applyConstraints(ctx.defs[name], typeDef.constraints, ctx);
|
|
386
|
+
}
|
|
383
387
|
if (typeDef.annotations && typeDef.annotations.length > 0) {
|
|
384
388
|
applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);
|
|
385
389
|
}
|
|
@@ -548,7 +552,9 @@ function generateTypeNode(type, ctx) {
|
|
|
548
552
|
}
|
|
549
553
|
}
|
|
550
554
|
function generatePrimitiveType(type) {
|
|
551
|
-
return {
|
|
555
|
+
return {
|
|
556
|
+
type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
|
|
557
|
+
};
|
|
552
558
|
}
|
|
553
559
|
function generateEnumType(type) {
|
|
554
560
|
const hasDisplayNames = type.members.some((m) => m.displayName !== void 0);
|
|
@@ -721,7 +727,7 @@ function applyAnnotations(schema, annotations, ctx) {
|
|
|
721
727
|
case "deprecated":
|
|
722
728
|
schema.deprecated = true;
|
|
723
729
|
if (annotation.message !== void 0 && annotation.message !== "") {
|
|
724
|
-
schema[
|
|
730
|
+
schema[`${ctx.vendorPrefix}-deprecation-description`] = annotation.message;
|
|
725
731
|
}
|
|
726
732
|
break;
|
|
727
733
|
case "placeholder":
|
|
@@ -1651,6 +1657,26 @@ function dereferenceType(ctx, type) {
|
|
|
1651
1657
|
}
|
|
1652
1658
|
return current;
|
|
1653
1659
|
}
|
|
1660
|
+
function collectReferencedTypeConstraints(ctx, type) {
|
|
1661
|
+
const collected = [];
|
|
1662
|
+
let current = type;
|
|
1663
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1664
|
+
while (current.kind === "reference") {
|
|
1665
|
+
if (seen.has(current.name)) {
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1668
|
+
seen.add(current.name);
|
|
1669
|
+
const definition = ctx.typeRegistry[current.name];
|
|
1670
|
+
if (definition === void 0) {
|
|
1671
|
+
break;
|
|
1672
|
+
}
|
|
1673
|
+
if (definition.constraints !== void 0) {
|
|
1674
|
+
collected.push(...definition.constraints);
|
|
1675
|
+
}
|
|
1676
|
+
current = definition.type;
|
|
1677
|
+
}
|
|
1678
|
+
return collected;
|
|
1679
|
+
}
|
|
1654
1680
|
function resolvePathTargetType(ctx, type, segments) {
|
|
1655
1681
|
const effectiveType = dereferenceType(ctx, type);
|
|
1656
1682
|
if (segments.length === 0) {
|
|
@@ -1672,12 +1698,33 @@ function resolvePathTargetType(ctx, type, segments) {
|
|
|
1672
1698
|
}
|
|
1673
1699
|
return { kind: "unresolvable", type: effectiveType };
|
|
1674
1700
|
}
|
|
1701
|
+
function isNullType(type) {
|
|
1702
|
+
return type.kind === "primitive" && type.primitiveKind === "null";
|
|
1703
|
+
}
|
|
1704
|
+
function collectCustomConstraintCandidateTypes(ctx, type) {
|
|
1705
|
+
const effectiveType = dereferenceType(ctx, type);
|
|
1706
|
+
const candidates = [effectiveType];
|
|
1707
|
+
if (effectiveType.kind === "array") {
|
|
1708
|
+
candidates.push(...collectCustomConstraintCandidateTypes(ctx, effectiveType.items));
|
|
1709
|
+
}
|
|
1710
|
+
if (effectiveType.kind === "union") {
|
|
1711
|
+
const memberTypes = effectiveType.members.map((member) => dereferenceType(ctx, member));
|
|
1712
|
+
const nonNullMembers = memberTypes.filter((member) => !isNullType(member));
|
|
1713
|
+
if (nonNullMembers.length === 1 && nonNullMembers.length < memberTypes.length) {
|
|
1714
|
+
const [nullableMember] = nonNullMembers;
|
|
1715
|
+
if (nullableMember !== void 0) {
|
|
1716
|
+
candidates.push(...collectCustomConstraintCandidateTypes(ctx, nullableMember));
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
return candidates;
|
|
1721
|
+
}
|
|
1675
1722
|
function formatPathTargetFieldName(fieldName, path) {
|
|
1676
1723
|
return path.length === 0 ? fieldName : `${fieldName}.${path.join(".")}`;
|
|
1677
1724
|
}
|
|
1678
1725
|
function checkConstraintOnType(ctx, fieldName, type, constraint) {
|
|
1679
1726
|
const effectiveType = dereferenceType(ctx, type);
|
|
1680
|
-
const isNumber = effectiveType.kind === "primitive" &&
|
|
1727
|
+
const isNumber = effectiveType.kind === "primitive" && ["number", "integer", "bigint"].includes(effectiveType.primitiveKind);
|
|
1681
1728
|
const isString = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "string";
|
|
1682
1729
|
const isArray = effectiveType.kind === "array";
|
|
1683
1730
|
const isEnum = effectiveType.kind === "enum";
|
|
@@ -1735,7 +1782,9 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
|
|
|
1735
1782
|
break;
|
|
1736
1783
|
}
|
|
1737
1784
|
case "const": {
|
|
1738
|
-
const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "boolean", "null"].includes(
|
|
1785
|
+
const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "integer", "bigint", "boolean", "null"].includes(
|
|
1786
|
+
effectiveType.primitiveKind
|
|
1787
|
+
) || effectiveType.kind === "enum";
|
|
1739
1788
|
if (!isPrimitiveConstType) {
|
|
1740
1789
|
addTypeMismatch(
|
|
1741
1790
|
ctx,
|
|
@@ -1746,7 +1795,8 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
|
|
|
1746
1795
|
}
|
|
1747
1796
|
if (effectiveType.kind === "primitive") {
|
|
1748
1797
|
const valueType = constraint.value === null ? "null" : Array.isArray(constraint.value) ? "array" : typeof constraint.value;
|
|
1749
|
-
|
|
1798
|
+
const expectedValueType = effectiveType.primitiveKind === "integer" || effectiveType.primitiveKind === "bigint" ? "number" : effectiveType.primitiveKind;
|
|
1799
|
+
if (valueType !== expectedValueType) {
|
|
1750
1800
|
addTypeMismatch(
|
|
1751
1801
|
ctx,
|
|
1752
1802
|
`Field "${fieldName}": @const value type "${valueType}" is incompatible with field type "${effectiveType.primitiveKind}"`,
|
|
@@ -1815,11 +1865,14 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
|
|
|
1815
1865
|
);
|
|
1816
1866
|
return;
|
|
1817
1867
|
}
|
|
1868
|
+
const candidateTypes = collectCustomConstraintCandidateTypes(ctx, type);
|
|
1818
1869
|
const normalizedTagName = constraint.provenance.tagName === void 0 ? void 0 : (0, import_core3.normalizeConstraintTagName)(constraint.provenance.tagName.replace(/^@/, ""));
|
|
1819
1870
|
if (normalizedTagName !== void 0) {
|
|
1820
1871
|
const tagRegistration = ctx.extensionRegistry.findConstraintTag(normalizedTagName);
|
|
1821
1872
|
const extensionId = getExtensionIdFromConstraintId(constraint.constraintId);
|
|
1822
|
-
if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName &&
|
|
1873
|
+
if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && !candidateTypes.some(
|
|
1874
|
+
(candidateType) => tagRegistration.registration.isApplicableToType?.(candidateType) !== false
|
|
1875
|
+
)) {
|
|
1823
1876
|
addTypeMismatch(
|
|
1824
1877
|
ctx,
|
|
1825
1878
|
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
@@ -1829,7 +1882,7 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
|
|
|
1829
1882
|
}
|
|
1830
1883
|
}
|
|
1831
1884
|
if (registration.applicableTypes === null) {
|
|
1832
|
-
if (registration.isApplicableToType?.(
|
|
1885
|
+
if (!candidateTypes.some((candidateType) => registration.isApplicableToType?.(candidateType) !== false)) {
|
|
1833
1886
|
addTypeMismatch(
|
|
1834
1887
|
ctx,
|
|
1835
1888
|
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
@@ -1838,7 +1891,11 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
|
|
|
1838
1891
|
}
|
|
1839
1892
|
return;
|
|
1840
1893
|
}
|
|
1841
|
-
|
|
1894
|
+
const applicableTypes = registration.applicableTypes;
|
|
1895
|
+
const matchesApplicableType = candidateTypes.some(
|
|
1896
|
+
(candidateType) => applicableTypes.includes(candidateType.kind) && registration.isApplicableToType?.(candidateType) !== false
|
|
1897
|
+
);
|
|
1898
|
+
if (!matchesApplicableType) {
|
|
1842
1899
|
addTypeMismatch(
|
|
1843
1900
|
ctx,
|
|
1844
1901
|
`Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
|
|
@@ -1847,7 +1904,10 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
|
|
|
1847
1904
|
}
|
|
1848
1905
|
}
|
|
1849
1906
|
function validateFieldNode(ctx, field) {
|
|
1850
|
-
validateConstraints(ctx, field.name, field.type,
|
|
1907
|
+
validateConstraints(ctx, field.name, field.type, [
|
|
1908
|
+
...collectReferencedTypeConstraints(ctx, field.type),
|
|
1909
|
+
...field.constraints
|
|
1910
|
+
]);
|
|
1851
1911
|
if (field.type.kind === "object") {
|
|
1852
1912
|
for (const prop of field.type.properties) {
|
|
1853
1913
|
validateObjectProperty(ctx, field.name, prop);
|
|
@@ -1856,7 +1916,10 @@ function validateFieldNode(ctx, field) {
|
|
|
1856
1916
|
}
|
|
1857
1917
|
function validateObjectProperty(ctx, parentName, prop) {
|
|
1858
1918
|
const qualifiedName = `${parentName}.${prop.name}`;
|
|
1859
|
-
validateConstraints(ctx, qualifiedName, prop.type,
|
|
1919
|
+
validateConstraints(ctx, qualifiedName, prop.type, [
|
|
1920
|
+
...collectReferencedTypeConstraints(ctx, prop.type),
|
|
1921
|
+
...prop.constraints
|
|
1922
|
+
]);
|
|
1860
1923
|
if (prop.type.kind === "object") {
|
|
1861
1924
|
for (const nestedProp of prop.type.properties) {
|
|
1862
1925
|
validateObjectProperty(ctx, qualifiedName, nestedProp);
|