@formspec/build 0.1.0-alpha.43 → 0.1.0-alpha.45

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 (44) hide show
  1. package/dist/analyzer/class-analyzer.d.ts.map +1 -1
  2. package/dist/analyzer/program.d.ts +4 -1
  3. package/dist/analyzer/program.d.ts.map +1 -1
  4. package/dist/analyzer/tsdoc-parser.d.ts.map +1 -1
  5. package/dist/browser.cjs +35 -9
  6. package/dist/browser.cjs.map +1 -1
  7. package/dist/browser.js +36 -12
  8. package/dist/browser.js.map +1 -1
  9. package/dist/build-alpha.d.ts +106 -5
  10. package/dist/build-beta.d.ts +106 -5
  11. package/dist/build-internal.d.ts +106 -5
  12. package/dist/build.d.ts +106 -5
  13. package/dist/cli.cjs +343 -59
  14. package/dist/cli.cjs.map +1 -1
  15. package/dist/cli.js +339 -58
  16. package/dist/cli.js.map +1 -1
  17. package/dist/extensions/index.d.ts +1 -1
  18. package/dist/extensions/index.d.ts.map +1 -1
  19. package/dist/extensions/registry.d.ts +64 -5
  20. package/dist/extensions/registry.d.ts.map +1 -1
  21. package/dist/extensions/symbol-registry.d.ts +33 -0
  22. package/dist/extensions/symbol-registry.d.ts.map +1 -0
  23. package/dist/generators/class-schema.d.ts +16 -0
  24. package/dist/generators/class-schema.d.ts.map +1 -1
  25. package/dist/generators/discovered-schema.d.ts.map +1 -1
  26. package/dist/index.cjs +328 -51
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +329 -54
  31. package/dist/index.js.map +1 -1
  32. package/dist/internals.cjs +124 -10
  33. package/dist/internals.cjs.map +1 -1
  34. package/dist/internals.d.ts +1 -1
  35. package/dist/internals.d.ts.map +1 -1
  36. package/dist/internals.js +125 -13
  37. package/dist/internals.js.map +1 -1
  38. package/dist/json-schema/generator.d.ts.map +1 -1
  39. package/dist/metadata/collision-guards.d.ts.map +1 -1
  40. package/dist/metadata/policy.d.ts.map +1 -1
  41. package/dist/metadata/resolve.d.ts.map +1 -1
  42. package/dist/ui-schema/ir-generator.d.ts.map +1 -1
  43. package/dist/validate/constraint-validator.d.ts.map +1 -1
  44. package/package.json +5 -5
@@ -275,7 +275,9 @@ function resolveTypeNodeMetadata(type, options) {
275
275
  case "object":
276
276
  return {
277
277
  ...type,
278
- properties: type.properties.map((property) => resolveObjectPropertyMetadata(property, options))
278
+ properties: type.properties.map(
279
+ (property) => resolveObjectPropertyMetadata(property, options)
280
+ )
279
281
  };
280
282
  case "record":
281
283
  return {
@@ -1632,6 +1634,71 @@ function isObjectType(type) {
1632
1634
  function isIntersectionType(type) {
1633
1635
  return !!(type.flags & ts3.TypeFlags.Intersection);
1634
1636
  }
1637
+ function collectBrandIdentifiers(type) {
1638
+ if (!type.isIntersection()) {
1639
+ return [];
1640
+ }
1641
+ const brands = [];
1642
+ for (const prop of type.getProperties()) {
1643
+ const decl = prop.valueDeclaration ?? prop.declarations?.[0];
1644
+ if (decl === void 0) continue;
1645
+ if (!ts3.isPropertySignature(decl) && !ts3.isPropertyDeclaration(decl)) continue;
1646
+ if (!ts3.isComputedPropertyName(decl.name)) continue;
1647
+ if (!ts3.isIdentifier(decl.name.expression)) continue;
1648
+ brands.push(decl.name.expression.text);
1649
+ }
1650
+ return brands;
1651
+ }
1652
+ function resolveCanonicalSymbol(type, checker) {
1653
+ const raw = type.aliasSymbol ?? type.getSymbol();
1654
+ if (raw === void 0) return void 0;
1655
+ return raw.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(raw) : raw;
1656
+ }
1657
+ function resolveSymbolBasedCustomType(type, extensionRegistry, checker) {
1658
+ if (extensionRegistry === void 0) {
1659
+ return null;
1660
+ }
1661
+ const canonical = resolveCanonicalSymbol(type, checker);
1662
+ if (canonical === void 0) {
1663
+ return null;
1664
+ }
1665
+ const registration = extensionRegistry.findTypeBySymbol(canonical);
1666
+ if (registration === void 0) {
1667
+ return null;
1668
+ }
1669
+ return {
1670
+ kind: "custom",
1671
+ typeId: `${registration.extensionId}/${registration.registration.typeName}`,
1672
+ payload: null
1673
+ };
1674
+ }
1675
+ function isIntegerBrandedType(type) {
1676
+ if (!type.isIntersection()) {
1677
+ return false;
1678
+ }
1679
+ const hasNumberBase = type.types.some((member) => !!(member.flags & ts3.TypeFlags.Number));
1680
+ if (!hasNumberBase) {
1681
+ return false;
1682
+ }
1683
+ return collectBrandIdentifiers(type).includes("__integerBrand");
1684
+ }
1685
+ function resolveBrandedCustomType(type, extensionRegistry) {
1686
+ if (extensionRegistry === void 0) {
1687
+ return null;
1688
+ }
1689
+ for (const brand of collectBrandIdentifiers(type)) {
1690
+ const registration = extensionRegistry.findTypeByBrand(brand);
1691
+ if (registration === void 0) {
1692
+ continue;
1693
+ }
1694
+ return {
1695
+ kind: "custom",
1696
+ typeId: `${registration.extensionId}/${registration.registration.typeName}`,
1697
+ payload: null
1698
+ };
1699
+ }
1700
+ return null;
1701
+ }
1635
1702
  function isResolvableObjectLikeAliasTypeNode(typeNode) {
1636
1703
  if (ts3.isParenthesizedTypeNode(typeNode)) {
1637
1704
  return isResolvableObjectLikeAliasTypeNode(typeNode.type);
@@ -2743,6 +2810,14 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2743
2810
  if (customType) {
2744
2811
  return customType;
2745
2812
  }
2813
+ const symbolCustomType = resolveSymbolBasedCustomType(type, extensionRegistry, checker);
2814
+ if (symbolCustomType) {
2815
+ return symbolCustomType;
2816
+ }
2817
+ const brandedCustomType = resolveBrandedCustomType(type, extensionRegistry);
2818
+ if (brandedCustomType) {
2819
+ return brandedCustomType;
2820
+ }
2746
2821
  const primitiveAlias = tryResolveNamedPrimitiveAlias(
2747
2822
  type,
2748
2823
  checker,
@@ -2757,6 +2832,9 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2757
2832
  if (primitiveAlias) {
2758
2833
  return primitiveAlias;
2759
2834
  }
2835
+ if (isIntegerBrandedType(type)) {
2836
+ return { kind: "primitive", primitiveKind: "integer" };
2837
+ }
2760
2838
  if (type.flags & ts3.TypeFlags.String) {
2761
2839
  return { kind: "primitive", primitiveKind: "string" };
2762
2840
  }
@@ -2859,7 +2937,7 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2859
2937
  return { kind: "primitive", primitiveKind: "string" };
2860
2938
  }
2861
2939
  function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, metadataPolicy = createAnalyzerMetadataPolicy(void 0), extensionRegistry, diagnostics) {
2862
- if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
2940
+ if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null)) && !isIntegerBrandedType(type)) {
2863
2941
  return null;
2864
2942
  }
2865
2943
  const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
@@ -2945,6 +3023,9 @@ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiti
2945
3023
  visitedAliases
2946
3024
  );
2947
3025
  }
3026
+ if (isIntegerBrandedType(type)) {
3027
+ return { kind: "primitive", primitiveKind: "integer" };
3028
+ }
2948
3029
  if (type.flags & ts3.TypeFlags.String) {
2949
3030
  return { kind: "primitive", primitiveKind: "string" };
2950
3031
  }
@@ -3681,7 +3762,7 @@ function createProgramContextFromProgram(program, filePath) {
3681
3762
  sourceFile
3682
3763
  };
3683
3764
  }
3684
- function createProgramContext(filePath) {
3765
+ function createProgramContext(filePath, additionalFiles) {
3685
3766
  const absolutePath = path.resolve(filePath);
3686
3767
  const fileDir = path.dirname(absolutePath);
3687
3768
  const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
@@ -3704,7 +3785,8 @@ function createProgramContext(filePath) {
3704
3785
  throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
3705
3786
  }
3706
3787
  compilerOptions = parsed.options;
3707
- fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
3788
+ const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
3789
+ fileNames = [.../* @__PURE__ */ new Set([...parsed.fileNames, absolutePath, ...normalizedAdditional])];
3708
3790
  } else {
3709
3791
  compilerOptions = {
3710
3792
  target: ts4.ScriptTarget.ES2022,
@@ -3714,7 +3796,8 @@ function createProgramContext(filePath) {
3714
3796
  skipLibCheck: true,
3715
3797
  declaration: true
3716
3798
  };
3717
- fileNames = [absolutePath];
3799
+ const normalizedAdditional = (additionalFiles ?? []).map((f) => path.resolve(f));
3800
+ fileNames = [.../* @__PURE__ */ new Set([absolutePath, ...normalizedAdditional])];
3718
3801
  }
3719
3802
  const program = ts4.createProgram(fileNames, compilerOptions);
3720
3803
  const sourceFile = program.getSourceFile(absolutePath);
@@ -4008,7 +4091,7 @@ function makeFileProvenance(filePath) {
4008
4091
  }
4009
4092
 
4010
4093
  // src/generators/class-schema.ts
4011
- var ts5 = __toESM(require("typescript"), 1);
4094
+ var ts6 = __toESM(require("typescript"), 1);
4012
4095
 
4013
4096
  // src/metadata/collision-guards.ts
4014
4097
  function assertUniqueSerializedNames(entries, scope) {
@@ -4724,7 +4807,7 @@ function generateCustomType(type, ctx) {
4724
4807
  }
4725
4808
  return registration.toJsonSchema(type.payload, ctx.vendorPrefix);
4726
4809
  }
4727
- var JSON_SCHEMA_STRUCTURAL_KEYWORDS = /* @__PURE__ */ new Set([
4810
+ var VOCABULARY_MODE_BLOCKED_KEYWORDS = /* @__PURE__ */ new Set([
4728
4811
  "$schema",
4729
4812
  "$ref",
4730
4813
  "$defs",
@@ -4795,7 +4878,7 @@ function applyCustomConstraint(schema, constraint, ctx) {
4795
4878
  if (registration.emitsVocabularyKeywords) {
4796
4879
  const target = schema;
4797
4880
  for (const [key, value] of Object.entries(extensionSchema)) {
4798
- if (JSON_SCHEMA_STRUCTURAL_KEYWORDS.has(key)) {
4881
+ if (VOCABULARY_MODE_BLOCKED_KEYWORDS.has(key)) {
4799
4882
  throw new Error(
4800
4883
  `Custom constraint "${constraint.constraintId}" with emitsVocabularyKeywords must not overwrite standard JSON Schema keyword "${key}"`
4801
4884
  );
@@ -4855,8 +4938,10 @@ function buildConstraintTagSources(extensions) {
4855
4938
  }
4856
4939
  function createExtensionRegistry(extensions) {
4857
4940
  const reservedTagSources = buildConstraintTagSources(extensions);
4941
+ let symbolMap = /* @__PURE__ */ new Map();
4858
4942
  const typeMap = /* @__PURE__ */ new Map();
4859
4943
  const typeNameMap = /* @__PURE__ */ new Map();
4944
+ const brandMap = /* @__PURE__ */ new Map();
4860
4945
  const constraintMap = /* @__PURE__ */ new Map();
4861
4946
  const constraintTagMap = /* @__PURE__ */ new Map();
4862
4947
  const builtinBroadeningMap = /* @__PURE__ */ new Map();
@@ -4880,6 +4965,20 @@ function createExtensionRegistry(extensions) {
4880
4965
  registration: type
4881
4966
  });
4882
4967
  }
4968
+ if (type.brand !== void 0) {
4969
+ if (type.brand === "__integerBrand") {
4970
+ throw new Error(
4971
+ `Brand "__integerBrand" is reserved for the builtin Integer type and cannot be registered by extensions`
4972
+ );
4973
+ }
4974
+ if (brandMap.has(type.brand)) {
4975
+ throw new Error(`Duplicate custom type brand: "${type.brand}"`);
4976
+ }
4977
+ brandMap.set(type.brand, {
4978
+ extensionId: ext.extensionId,
4979
+ registration: type
4980
+ });
4981
+ }
4883
4982
  if (type.builtinConstraintBroadenings !== void 0) {
4884
4983
  for (const broadening of type.builtinConstraintBroadenings) {
4885
4984
  const key = `${qualifiedId}:${broadening.tagName}`;
@@ -4949,7 +5048,10 @@ function createExtensionRegistry(extensions) {
4949
5048
  `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${canonicalTagName}".`
4950
5049
  );
4951
5050
  }
4952
- if (Object.hasOwn(import_internals5.BUILTIN_CONSTRAINT_DEFINITIONS, (0, import_internals5.normalizeConstraintTagName)(canonicalTagName))) {
5051
+ if (Object.hasOwn(
5052
+ import_internals5.BUILTIN_CONSTRAINT_DEFINITIONS,
5053
+ (0, import_internals5.normalizeConstraintTagName)(canonicalTagName)
5054
+ )) {
4953
5055
  throw new Error(
4954
5056
  `Metadata tag "@${canonicalTagName}" conflicts with existing FormSpec tag "@${(0, import_internals5.normalizeConstraintTagName)(canonicalTagName)}".`
4955
5057
  );
@@ -4970,6 +5072,11 @@ function createExtensionRegistry(extensions) {
4970
5072
  extensions,
4971
5073
  findType: (typeId) => typeMap.get(typeId),
4972
5074
  findTypeByName: (typeName) => typeNameMap.get(typeName),
5075
+ findTypeByBrand: (brand) => brandMap.get(brand),
5076
+ findTypeBySymbol: (symbol) => symbolMap.get(symbol),
5077
+ setSymbolMap: (map) => {
5078
+ symbolMap = map;
5079
+ },
4973
5080
  findConstraint: (constraintId) => constraintMap.get(constraintId),
4974
5081
  findConstraintTag: (tagName) => constraintTagMap.get((0, import_internal3.normalizeFormSpecTagName)(tagName)),
4975
5082
  findBuiltinConstraintBroadening: (typeId, tagName) => builtinBroadeningMap.get(`${typeId}:${tagName}`),
@@ -4977,6 +5084,10 @@ function createExtensionRegistry(extensions) {
4977
5084
  };
4978
5085
  }
4979
5086
 
5087
+ // src/extensions/symbol-registry.ts
5088
+ var ts5 = __toESM(require("typescript"), 1);
5089
+ var path2 = __toESM(require("path"), 1);
5090
+
4980
5091
  // src/ui-schema/schema.ts
4981
5092
  var import_zod = require("zod");
4982
5093
  var jsonPointerSchema = import_zod.z.string();
@@ -5185,7 +5296,10 @@ function irElementsToUiSchema(elements, fieldNameMap, parentRule) {
5185
5296
  break;
5186
5297
  }
5187
5298
  case "conditional": {
5188
- const newRule = createShowRule(fieldNameMap.get(element.fieldName) ?? element.fieldName, element.value);
5299
+ const newRule = createShowRule(
5300
+ fieldNameMap.get(element.fieldName) ?? element.fieldName,
5301
+ element.value
5302
+ );
5189
5303
  const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
5190
5304
  const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);
5191
5305
  result.push(...childElements);