@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.
Files changed (55) hide show
  1. package/README.md +74 -128
  2. package/dist/__tests__/class-schema.test.d.ts +2 -0
  3. package/dist/__tests__/class-schema.test.d.ts.map +1 -0
  4. package/dist/__tests__/date-extension.integration.test.d.ts +2 -0
  5. package/dist/__tests__/date-extension.integration.test.d.ts.map +1 -0
  6. package/dist/__tests__/fixtures/class-schema-regressions.d.ts +83 -0
  7. package/dist/__tests__/fixtures/class-schema-regressions.d.ts.map +1 -0
  8. package/dist/__tests__/fixtures/example-date-extension.d.ts +12 -0
  9. package/dist/__tests__/fixtures/example-date-extension.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/extension-forms.d.ts +7 -0
  11. package/dist/__tests__/fixtures/extension-forms.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/mixed-authoring-shipping-address.d.ts.map +1 -1
  13. package/dist/__tests__/fixtures/named-primitive-aliases.d.ts +15 -0
  14. package/dist/__tests__/fixtures/named-primitive-aliases.d.ts.map +1 -0
  15. package/dist/__tests__/fixtures/nested-array-path-constraints.d.ts +14 -0
  16. package/dist/__tests__/fixtures/nested-array-path-constraints.d.ts.map +1 -0
  17. package/dist/__tests__/fixtures/sample-forms.d.ts +10 -0
  18. package/dist/__tests__/fixtures/sample-forms.d.ts.map +1 -1
  19. package/dist/__tests__/generate-schemas.test.d.ts +2 -0
  20. package/dist/__tests__/generate-schemas.test.d.ts.map +1 -0
  21. package/dist/__tests__/parity/parity.test.d.ts +6 -2
  22. package/dist/__tests__/parity/parity.test.d.ts.map +1 -1
  23. package/dist/__tests__/parity/utils.d.ts +9 -4
  24. package/dist/__tests__/parity/utils.d.ts.map +1 -1
  25. package/dist/analyzer/class-analyzer.d.ts.map +1 -1
  26. package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
  27. package/dist/analyzer/program.d.ts +15 -0
  28. package/dist/analyzer/program.d.ts.map +1 -1
  29. package/dist/analyzer/tsdoc-parser.d.ts +5 -0
  30. package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
  31. package/dist/browser.cjs +73 -10
  32. package/dist/browser.cjs.map +1 -1
  33. package/dist/browser.js +73 -10
  34. package/dist/browser.js.map +1 -1
  35. package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -1
  36. package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -1
  37. package/dist/cli.cjs +1147 -252
  38. package/dist/cli.cjs.map +1 -1
  39. package/dist/cli.js +1142 -248
  40. package/dist/cli.js.map +1 -1
  41. package/dist/extensions/registry.d.ts.map +1 -1
  42. package/dist/generators/class-schema.d.ts.map +1 -1
  43. package/dist/generators/method-schema.d.ts.map +1 -1
  44. package/dist/generators/mixed-authoring.d.ts.map +1 -1
  45. package/dist/index.cjs +1121 -239
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.js +1121 -239
  48. package/dist/index.js.map +1 -1
  49. package/dist/internals.cjs +377 -195
  50. package/dist/internals.cjs.map +1 -1
  51. package/dist/internals.js +377 -195
  52. package/dist/internals.js.map +1 -1
  53. package/dist/json-schema/ir-generator.d.ts.map +1 -1
  54. package/dist/validate/constraint-validator.d.ts.map +1 -1
  55. 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 { type: type.primitiveKind };
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["x-formspec-deprecation-description"] = annotation.message;
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" && effectiveType.primitiveKind === "number";
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(effectiveType.primitiveKind) || effectiveType.kind === "enum";
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
- if (valueType !== effectiveType.primitiveKind) {
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 && tagRegistration.registration.isApplicableToType?.(type) === false) {
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?.(type) === false) {
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
- if (!registration.applicableTypes.includes(type.kind) || registration.isApplicableToType?.(type) === false) {
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, field.constraints);
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, prop.constraints);
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);