@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/cli.cjs CHANGED
@@ -45,6 +45,7 @@ function canonicalizeChainDSL(form) {
45
45
  kind: "form-ir",
46
46
  irVersion: import_core.IR_VERSION,
47
47
  elements: canonicalizeElements(form.elements),
48
+ rootAnnotations: [],
48
49
  typeRegistry: {},
49
50
  provenance: CHAIN_DSL_PROVENANCE
50
51
  };
@@ -362,6 +363,7 @@ function canonicalizeTSDoc(analysis, source) {
362
363
  irVersion: import_core2.IR_VERSION,
363
364
  elements,
364
365
  typeRegistry: analysis.typeRegistry,
366
+ ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations },
365
367
  ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { annotations: analysis.annotations },
366
368
  provenance
367
369
  };
@@ -455,6 +457,9 @@ function generateJsonSchemaFromIR(ir, options) {
455
457
  const ctx = makeContext(options);
456
458
  for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
457
459
  ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
460
+ if (typeDef.constraints && typeDef.constraints.length > 0) {
461
+ applyConstraints(ctx.defs[name], typeDef.constraints, ctx);
462
+ }
458
463
  if (typeDef.annotations && typeDef.annotations.length > 0) {
459
464
  applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);
460
465
  }
@@ -623,7 +628,9 @@ function generateTypeNode(type, ctx) {
623
628
  }
624
629
  }
625
630
  function generatePrimitiveType(type) {
626
- return { type: type.primitiveKind };
631
+ return {
632
+ type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
633
+ };
627
634
  }
628
635
  function generateEnumType(type) {
629
636
  const hasDisplayNames = type.members.some((m) => m.displayName !== void 0);
@@ -796,7 +803,7 @@ function applyAnnotations(schema, annotations, ctx) {
796
803
  case "deprecated":
797
804
  schema.deprecated = true;
798
805
  if (annotation.message !== void 0 && annotation.message !== "") {
799
- schema["x-formspec-deprecation-description"] = annotation.message;
806
+ schema[`${ctx.vendorPrefix}-deprecation-description`] = annotation.message;
800
807
  }
801
808
  break;
802
809
  case "placeholder":
@@ -1305,84 +1312,6 @@ var init_schema2 = __esm({
1305
1312
  }
1306
1313
  });
1307
1314
 
1308
- // src/analyzer/program.ts
1309
- function createProgramContext(filePath) {
1310
- const absolutePath = path.resolve(filePath);
1311
- const fileDir = path.dirname(absolutePath);
1312
- const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
1313
- let compilerOptions;
1314
- let fileNames;
1315
- if (configPath) {
1316
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
1317
- if (configFile.error) {
1318
- throw new Error(
1319
- `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
1320
- );
1321
- }
1322
- const parsed = ts.parseJsonConfigFileContent(
1323
- configFile.config,
1324
- ts.sys,
1325
- path.dirname(configPath)
1326
- );
1327
- if (parsed.errors.length > 0) {
1328
- const errorMessages = parsed.errors.map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
1329
- throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
1330
- }
1331
- compilerOptions = parsed.options;
1332
- fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
1333
- } else {
1334
- compilerOptions = {
1335
- target: ts.ScriptTarget.ES2022,
1336
- module: ts.ModuleKind.NodeNext,
1337
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
1338
- strict: true,
1339
- skipLibCheck: true,
1340
- declaration: true
1341
- };
1342
- fileNames = [absolutePath];
1343
- }
1344
- const program = ts.createProgram(fileNames, compilerOptions);
1345
- const sourceFile = program.getSourceFile(absolutePath);
1346
- if (!sourceFile) {
1347
- throw new Error(`Could not find source file: ${absolutePath}`);
1348
- }
1349
- return {
1350
- program,
1351
- checker: program.getTypeChecker(),
1352
- sourceFile
1353
- };
1354
- }
1355
- function findNodeByName(sourceFile, name, predicate, getName) {
1356
- let result = null;
1357
- function visit(node) {
1358
- if (result) return;
1359
- if (predicate(node) && getName(node) === name) {
1360
- result = node;
1361
- return;
1362
- }
1363
- ts.forEachChild(node, visit);
1364
- }
1365
- visit(sourceFile);
1366
- return result;
1367
- }
1368
- function findClassByName(sourceFile, className) {
1369
- return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
1370
- }
1371
- function findInterfaceByName(sourceFile, interfaceName) {
1372
- return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
1373
- }
1374
- function findTypeAliasByName(sourceFile, aliasName) {
1375
- return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
1376
- }
1377
- var ts, path;
1378
- var init_program = __esm({
1379
- "src/analyzer/program.ts"() {
1380
- "use strict";
1381
- ts = __toESM(require("typescript"), 1);
1382
- path = __toESM(require("path"), 1);
1383
- }
1384
- });
1385
-
1386
1315
  // src/analyzer/json-utils.ts
1387
1316
  function tryParseJson(text) {
1388
1317
  try {
@@ -1455,10 +1384,10 @@ function parseTSDocTags(node, file = "", options) {
1455
1384
  let placeholderProvenance;
1456
1385
  const sourceFile = node.getSourceFile();
1457
1386
  const sourceText = sourceFile.getFullText();
1458
- const commentRanges = ts2.getLeadingCommentRanges(sourceText, node.getFullStart());
1387
+ const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
1459
1388
  if (commentRanges) {
1460
1389
  for (const range of commentRanges) {
1461
- if (range.kind !== ts2.SyntaxKind.MultiLineCommentTrivia) {
1390
+ if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
1462
1391
  continue;
1463
1392
  }
1464
1393
  const commentText = sourceText.substring(range.pos, range.end);
@@ -1476,26 +1405,31 @@ function parseTSDocTags(node, file = "", options) {
1476
1405
  const text2 = extractBlockText(block).trim();
1477
1406
  if (text2 === "") continue;
1478
1407
  const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
1479
- if (tagName === "displayName") {
1480
- if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
1481
- displayName = text2;
1482
- displayNameProvenance = provenance2;
1483
- }
1484
- } else if (tagName === "format") {
1485
- annotations.push({
1486
- kind: "annotation",
1487
- annotationKind: "format",
1488
- value: text2,
1489
- provenance: provenance2
1490
- });
1491
- } else {
1492
- if (tagName === "description" && description === void 0) {
1408
+ switch (tagName) {
1409
+ case "displayName":
1410
+ if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
1411
+ displayName = text2;
1412
+ displayNameProvenance = provenance2;
1413
+ }
1414
+ break;
1415
+ case "format":
1416
+ annotations.push({
1417
+ kind: "annotation",
1418
+ annotationKind: "format",
1419
+ value: text2,
1420
+ provenance: provenance2
1421
+ });
1422
+ break;
1423
+ case "description":
1493
1424
  description = text2;
1494
1425
  descriptionProvenance = provenance2;
1495
- } else if (tagName === "placeholder" && placeholder === void 0) {
1496
- placeholder = text2;
1497
- placeholderProvenance = provenance2;
1498
- }
1426
+ break;
1427
+ case "placeholder":
1428
+ if (placeholder === void 0) {
1429
+ placeholder = text2;
1430
+ placeholderProvenance = provenance2;
1431
+ }
1432
+ break;
1499
1433
  }
1500
1434
  continue;
1501
1435
  }
@@ -1525,6 +1459,13 @@ function parseTSDocTags(node, file = "", options) {
1525
1459
  descriptionProvenance = provenanceForComment(range, sourceFile, file, "remarks");
1526
1460
  }
1527
1461
  }
1462
+ if (description === void 0) {
1463
+ const summary = extractPlainText(docComment.summarySection).trim();
1464
+ if (summary !== "") {
1465
+ description = summary;
1466
+ descriptionProvenance = provenanceForComment(range, sourceFile, file, "summary");
1467
+ }
1468
+ }
1528
1469
  }
1529
1470
  }
1530
1471
  if (displayName !== void 0 && displayNameProvenance !== void 0) {
@@ -1551,7 +1492,7 @@ function parseTSDocTags(node, file = "", options) {
1551
1492
  provenance: placeholderProvenance
1552
1493
  });
1553
1494
  }
1554
- const jsDocTagsAll = ts2.getJSDocTags(node);
1495
+ const jsDocTagsAll = ts.getJSDocTags(node);
1555
1496
  for (const tag of jsDocTagsAll) {
1556
1497
  const tagName = (0, import_core3.normalizeConstraintTagName)(tag.tagName.text);
1557
1498
  if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
@@ -1574,7 +1515,7 @@ function parseTSDocTags(node, file = "", options) {
1574
1515
  function extractDisplayNameMetadata(node) {
1575
1516
  let displayName;
1576
1517
  const memberDisplayNames = /* @__PURE__ */ new Map();
1577
- for (const tag of ts2.getJSDocTags(node)) {
1518
+ for (const tag of ts.getJSDocTags(node)) {
1578
1519
  const tagName = (0, import_core3.normalizeConstraintTagName)(tag.tagName.text);
1579
1520
  if (tagName !== "displayName") continue;
1580
1521
  const commentText = getTagCommentText(tag);
@@ -1595,11 +1536,11 @@ function extractDisplayNameMetadata(node) {
1595
1536
  }
1596
1537
  function extractPathTarget(text) {
1597
1538
  const trimmed = text.trimStart();
1598
- const match = /^:([a-zA-Z_]\w*)\s+([\s\S]*)$/.exec(trimmed);
1599
- if (!match?.[1] || !match[2]) return null;
1539
+ const match = /^:([a-zA-Z_]\w*)(?:\s+([\s\S]*))?$/.exec(trimmed);
1540
+ if (!match?.[1]) return null;
1600
1541
  return {
1601
1542
  path: { segments: [match[1]] },
1602
- remainingText: match[2]
1543
+ remainingText: match[2] ?? ""
1603
1544
  };
1604
1545
  }
1605
1546
  function extractBlockText(block) {
@@ -1862,13 +1803,13 @@ function getTagCommentText(tag) {
1862
1803
  if (typeof tag.comment === "string") {
1863
1804
  return tag.comment;
1864
1805
  }
1865
- return ts2.getTextOfJSDocComment(tag.comment);
1806
+ return ts.getTextOfJSDocComment(tag.comment);
1866
1807
  }
1867
- var ts2, import_tsdoc, import_core3, NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT, parserCache;
1808
+ var ts, import_tsdoc, import_core3, NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT, parserCache;
1868
1809
  var init_tsdoc_parser = __esm({
1869
1810
  "src/analyzer/tsdoc-parser.ts"() {
1870
1811
  "use strict";
1871
- ts2 = __toESM(require("typescript"), 1);
1812
+ ts = __toESM(require("typescript"), 1);
1872
1813
  import_tsdoc = require("@microsoft/tsdoc");
1873
1814
  import_core3 = require("@formspec/core");
1874
1815
  init_json_utils();
@@ -1902,18 +1843,18 @@ function extractJSDocAnnotationNodes(node, file = "", options) {
1902
1843
  function extractDefaultValueAnnotation(initializer, file = "") {
1903
1844
  if (!initializer) return null;
1904
1845
  let value;
1905
- if (ts3.isStringLiteral(initializer)) {
1846
+ if (ts2.isStringLiteral(initializer)) {
1906
1847
  value = initializer.text;
1907
- } else if (ts3.isNumericLiteral(initializer)) {
1848
+ } else if (ts2.isNumericLiteral(initializer)) {
1908
1849
  value = Number(initializer.text);
1909
- } else if (initializer.kind === ts3.SyntaxKind.TrueKeyword) {
1850
+ } else if (initializer.kind === ts2.SyntaxKind.TrueKeyword) {
1910
1851
  value = true;
1911
- } else if (initializer.kind === ts3.SyntaxKind.FalseKeyword) {
1852
+ } else if (initializer.kind === ts2.SyntaxKind.FalseKeyword) {
1912
1853
  value = false;
1913
- } else if (initializer.kind === ts3.SyntaxKind.NullKeyword) {
1854
+ } else if (initializer.kind === ts2.SyntaxKind.NullKeyword) {
1914
1855
  value = null;
1915
- } else if (ts3.isPrefixUnaryExpression(initializer)) {
1916
- if (initializer.operator === ts3.SyntaxKind.MinusToken && ts3.isNumericLiteral(initializer.operand)) {
1856
+ } else if (ts2.isPrefixUnaryExpression(initializer)) {
1857
+ if (initializer.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(initializer.operand)) {
1917
1858
  value = -Number(initializer.operand.text);
1918
1859
  }
1919
1860
  }
@@ -1932,21 +1873,21 @@ function extractDefaultValueAnnotation(initializer, file = "") {
1932
1873
  }
1933
1874
  };
1934
1875
  }
1935
- var ts3;
1876
+ var ts2;
1936
1877
  var init_jsdoc_constraints = __esm({
1937
1878
  "src/analyzer/jsdoc-constraints.ts"() {
1938
1879
  "use strict";
1939
- ts3 = __toESM(require("typescript"), 1);
1880
+ ts2 = __toESM(require("typescript"), 1);
1940
1881
  init_tsdoc_parser();
1941
1882
  }
1942
1883
  });
1943
1884
 
1944
1885
  // src/analyzer/class-analyzer.ts
1945
1886
  function isObjectType(type) {
1946
- return !!(type.flags & ts4.TypeFlags.Object);
1887
+ return !!(type.flags & ts3.TypeFlags.Object);
1947
1888
  }
1948
1889
  function isTypeReference(type) {
1949
- return !!(type.flags & ts4.TypeFlags.Object) && !!(type.objectFlags & ts4.ObjectFlags.Reference);
1890
+ return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
1950
1891
  }
1951
1892
  function makeParseOptions(extensionRegistry, fieldType) {
1952
1893
  if (extensionRegistry === void 0 && fieldType === void 0) {
@@ -1971,7 +1912,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1971
1912
  const instanceMethods = [];
1972
1913
  const staticMethods = [];
1973
1914
  for (const member of classDecl.members) {
1974
- if (ts4.isPropertyDeclaration(member)) {
1915
+ if (ts3.isPropertyDeclaration(member)) {
1975
1916
  const fieldNode = analyzeFieldToIR(
1976
1917
  member,
1977
1918
  checker,
@@ -1984,10 +1925,10 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1984
1925
  fields.push(fieldNode);
1985
1926
  fieldLayouts.push({});
1986
1927
  }
1987
- } else if (ts4.isMethodDeclaration(member)) {
1928
+ } else if (ts3.isMethodDeclaration(member)) {
1988
1929
  const methodInfo = analyzeMethod(member, checker);
1989
1930
  if (methodInfo) {
1990
- const isStatic = member.modifiers?.some((m) => m.kind === ts4.SyntaxKind.StaticKeyword);
1931
+ const isStatic = member.modifiers?.some((m) => m.kind === ts3.SyntaxKind.StaticKeyword);
1991
1932
  if (isStatic) {
1992
1933
  staticMethods.push(methodInfo);
1993
1934
  } else {
@@ -2017,7 +1958,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
2017
1958
  );
2018
1959
  const visiting = /* @__PURE__ */ new Set();
2019
1960
  for (const member of interfaceDecl.members) {
2020
- if (ts4.isPropertySignature(member)) {
1961
+ if (ts3.isPropertySignature(member)) {
2021
1962
  const fieldNode = analyzeInterfacePropertyToIR(
2022
1963
  member,
2023
1964
  checker,
@@ -2043,10 +1984,10 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
2043
1984
  };
2044
1985
  }
2045
1986
  function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
2046
- if (!ts4.isTypeLiteralNode(typeAlias.type)) {
1987
+ if (!ts3.isTypeLiteralNode(typeAlias.type)) {
2047
1988
  const sourceFile = typeAlias.getSourceFile();
2048
1989
  const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
2049
- const kindDesc = ts4.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1990
+ const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
2050
1991
  return {
2051
1992
  ok: false,
2052
1993
  error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
@@ -2062,7 +2003,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
2062
2003
  );
2063
2004
  const visiting = /* @__PURE__ */ new Set();
2064
2005
  for (const member of typeAlias.type.members) {
2065
- if (ts4.isPropertySignature(member)) {
2006
+ if (ts3.isPropertySignature(member)) {
2066
2007
  const fieldNode = analyzeInterfacePropertyToIR(
2067
2008
  member,
2068
2009
  checker,
@@ -2090,7 +2031,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
2090
2031
  };
2091
2032
  }
2092
2033
  function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
2093
- if (!ts4.isIdentifier(prop.name)) {
2034
+ if (!ts3.isIdentifier(prop.name)) {
2094
2035
  return null;
2095
2036
  }
2096
2037
  const name = prop.name.text;
@@ -2107,12 +2048,14 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
2107
2048
  extensionRegistry
2108
2049
  );
2109
2050
  const constraints = [];
2110
- if (prop.type) {
2051
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
2111
2052
  constraints.push(
2112
2053
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
2113
2054
  );
2114
2055
  }
2115
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
2056
+ constraints.push(
2057
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
2058
+ );
2116
2059
  let annotations = [];
2117
2060
  annotations.push(
2118
2061
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -2133,7 +2076,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
2133
2076
  };
2134
2077
  }
2135
2078
  function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
2136
- if (!ts4.isIdentifier(prop.name)) {
2079
+ if (!ts3.isIdentifier(prop.name)) {
2137
2080
  return null;
2138
2081
  }
2139
2082
  const name = prop.name.text;
@@ -2150,12 +2093,14 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
2150
2093
  extensionRegistry
2151
2094
  );
2152
2095
  const constraints = [];
2153
- if (prop.type) {
2096
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
2154
2097
  constraints.push(
2155
2098
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
2156
2099
  );
2157
2100
  }
2158
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
2101
+ constraints.push(
2102
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
2103
+ );
2159
2104
  let annotations = [];
2160
2105
  annotations.push(
2161
2106
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -2244,7 +2189,7 @@ function resolveRegisteredCustomType(sourceNode, extensionRegistry, checker) {
2244
2189
  return resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker);
2245
2190
  }
2246
2191
  function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker) {
2247
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2192
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2248
2193
  return resolveRegisteredCustomTypeFromTypeNode(typeNode.type, extensionRegistry, checker);
2249
2194
  }
2250
2195
  const typeName = getTypeNodeRegistrationName(typeNode);
@@ -2259,8 +2204,8 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
2259
2204
  payload: null
2260
2205
  };
2261
2206
  }
2262
- if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
2263
- const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts4.isTypeAliasDeclaration);
2207
+ if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
2208
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2264
2209
  if (aliasDecl !== void 0) {
2265
2210
  return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
2266
2211
  }
@@ -2268,22 +2213,22 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
2268
2213
  return null;
2269
2214
  }
2270
2215
  function extractTypeNodeFromSource(sourceNode) {
2271
- if (ts4.isPropertyDeclaration(sourceNode) || ts4.isPropertySignature(sourceNode) || ts4.isParameter(sourceNode) || ts4.isTypeAliasDeclaration(sourceNode)) {
2216
+ if (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode) || ts3.isTypeAliasDeclaration(sourceNode)) {
2272
2217
  return sourceNode.type;
2273
2218
  }
2274
- if (ts4.isTypeNode(sourceNode)) {
2219
+ if (ts3.isTypeNode(sourceNode)) {
2275
2220
  return sourceNode;
2276
2221
  }
2277
2222
  return void 0;
2278
2223
  }
2279
2224
  function getTypeNodeRegistrationName(typeNode) {
2280
- if (ts4.isTypeReferenceNode(typeNode)) {
2281
- return ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
2225
+ if (ts3.isTypeReferenceNode(typeNode)) {
2226
+ return ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
2282
2227
  }
2283
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2228
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2284
2229
  return getTypeNodeRegistrationName(typeNode.type);
2285
2230
  }
2286
- if (typeNode.kind === ts4.SyntaxKind.BigIntKeyword || typeNode.kind === ts4.SyntaxKind.StringKeyword || typeNode.kind === ts4.SyntaxKind.NumberKeyword || typeNode.kind === ts4.SyntaxKind.BooleanKeyword) {
2231
+ if (typeNode.kind === ts3.SyntaxKind.BigIntKeyword || typeNode.kind === ts3.SyntaxKind.StringKeyword || typeNode.kind === ts3.SyntaxKind.NumberKeyword || typeNode.kind === ts3.SyntaxKind.BooleanKeyword) {
2287
2232
  return typeNode.getText();
2288
2233
  }
2289
2234
  return null;
@@ -2293,19 +2238,34 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2293
2238
  if (customType) {
2294
2239
  return customType;
2295
2240
  }
2296
- if (type.flags & ts4.TypeFlags.String) {
2241
+ const primitiveAlias = tryResolveNamedPrimitiveAlias(
2242
+ type,
2243
+ checker,
2244
+ file,
2245
+ typeRegistry,
2246
+ visiting,
2247
+ sourceNode,
2248
+ extensionRegistry
2249
+ );
2250
+ if (primitiveAlias) {
2251
+ return primitiveAlias;
2252
+ }
2253
+ if (type.flags & ts3.TypeFlags.String) {
2297
2254
  return { kind: "primitive", primitiveKind: "string" };
2298
2255
  }
2299
- if (type.flags & ts4.TypeFlags.Number) {
2256
+ if (type.flags & ts3.TypeFlags.Number) {
2300
2257
  return { kind: "primitive", primitiveKind: "number" };
2301
2258
  }
2302
- if (type.flags & ts4.TypeFlags.Boolean) {
2259
+ if (type.flags & (ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral)) {
2260
+ return { kind: "primitive", primitiveKind: "bigint" };
2261
+ }
2262
+ if (type.flags & ts3.TypeFlags.Boolean) {
2303
2263
  return { kind: "primitive", primitiveKind: "boolean" };
2304
2264
  }
2305
- if (type.flags & ts4.TypeFlags.Null) {
2265
+ if (type.flags & ts3.TypeFlags.Null) {
2306
2266
  return { kind: "primitive", primitiveKind: "null" };
2307
2267
  }
2308
- if (type.flags & ts4.TypeFlags.Undefined) {
2268
+ if (type.flags & ts3.TypeFlags.Undefined) {
2309
2269
  return { kind: "primitive", primitiveKind: "null" };
2310
2270
  }
2311
2271
  if (type.isStringLiteral()) {
@@ -2347,6 +2307,75 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2347
2307
  }
2348
2308
  return { kind: "primitive", primitiveKind: "string" };
2349
2309
  }
2310
+ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
2311
+ if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
2312
+ return null;
2313
+ }
2314
+ const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
2315
+ if (!aliasDecl) {
2316
+ return null;
2317
+ }
2318
+ const aliasName = aliasDecl.name.text;
2319
+ if (!typeRegistry[aliasName]) {
2320
+ const aliasType = checker.getTypeFromTypeNode(aliasDecl.type);
2321
+ const constraints = [
2322
+ ...extractJSDocConstraintNodes(aliasDecl, file, makeParseOptions(extensionRegistry)),
2323
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry)
2324
+ ];
2325
+ const annotations = extractJSDocAnnotationNodes(
2326
+ aliasDecl,
2327
+ file,
2328
+ makeParseOptions(extensionRegistry)
2329
+ );
2330
+ typeRegistry[aliasName] = {
2331
+ name: aliasName,
2332
+ type: resolveAliasedPrimitiveTarget(
2333
+ aliasType,
2334
+ checker,
2335
+ file,
2336
+ typeRegistry,
2337
+ visiting,
2338
+ extensionRegistry
2339
+ ),
2340
+ ...constraints.length > 0 && { constraints },
2341
+ ...annotations.length > 0 && { annotations },
2342
+ provenance: provenanceForDeclaration(aliasDecl, file)
2343
+ };
2344
+ }
2345
+ return { kind: "reference", name: aliasName, typeArguments: [] };
2346
+ }
2347
+ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
2348
+ const typeNode = sourceNode && (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode)) ? sourceNode.type : void 0;
2349
+ if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
2350
+ return void 0;
2351
+ }
2352
+ return checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2353
+ }
2354
+ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
2355
+ if (!ts3.isTypeReferenceNode(typeNode)) {
2356
+ return false;
2357
+ }
2358
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2359
+ if (!aliasDecl) {
2360
+ return false;
2361
+ }
2362
+ const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
2363
+ return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
2364
+ }
2365
+ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, extensionRegistry) {
2366
+ const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
2367
+ if (nestedAliasDecl !== void 0) {
2368
+ return resolveAliasedPrimitiveTarget(
2369
+ checker.getTypeFromTypeNode(nestedAliasDecl.type),
2370
+ checker,
2371
+ file,
2372
+ typeRegistry,
2373
+ visiting,
2374
+ extensionRegistry
2375
+ );
2376
+ }
2377
+ return resolveTypeNode(type, checker, file, typeRegistry, visiting, void 0, extensionRegistry);
2378
+ }
2350
2379
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
2351
2380
  const typeName = getNamedTypeName(type);
2352
2381
  const namedDecl = getNamedTypeDeclaration(type);
@@ -2359,13 +2388,13 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
2359
2388
  (memberTypeNode) => !isNullishTypeNode(resolveAliasedTypeNode(memberTypeNode, checker))
2360
2389
  );
2361
2390
  const nonNullTypes = allTypes.filter(
2362
- (memberType) => !(memberType.flags & (ts4.TypeFlags.Null | ts4.TypeFlags.Undefined))
2391
+ (memberType) => !(memberType.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
2363
2392
  );
2364
2393
  const nonNullMembers = nonNullTypes.map((memberType, index) => ({
2365
2394
  memberType,
2366
2395
  sourceNode: nonNullSourceNodes.length === nonNullTypes.length ? nonNullSourceNodes[index] : void 0
2367
2396
  }));
2368
- const hasNull = allTypes.some((t) => t.flags & ts4.TypeFlags.Null);
2397
+ const hasNull = allTypes.some((t) => t.flags & ts3.TypeFlags.Null);
2369
2398
  const memberDisplayNames = /* @__PURE__ */ new Map();
2370
2399
  if (namedDecl) {
2371
2400
  for (const [value, label] of extractDisplayNameMetadata(namedDecl).memberDisplayNames) {
@@ -2394,7 +2423,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
2394
2423
  const displayName = memberDisplayNames.get(String(value));
2395
2424
  return displayName !== void 0 ? { value, displayName } : { value };
2396
2425
  });
2397
- const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts4.TypeFlags.BooleanLiteral);
2426
+ const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts3.TypeFlags.BooleanLiteral);
2398
2427
  if (isBooleanUnion2) {
2399
2428
  const boolNode = { kind: "primitive", primitiveKind: "boolean" };
2400
2429
  const result = hasNull ? {
@@ -2480,7 +2509,7 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, exten
2480
2509
  if (type.getProperties().length > 0) {
2481
2510
  return null;
2482
2511
  }
2483
- const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
2512
+ const indexInfo = checker.getIndexInfoOfType(type, ts3.IndexKind.String);
2484
2513
  if (!indexInfo) {
2485
2514
  return null;
2486
2515
  }
@@ -2591,7 +2620,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
2591
2620
  const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
2592
2621
  if (!declaration) continue;
2593
2622
  const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
2594
- const optional = !!(prop.flags & ts4.SymbolFlags.Optional);
2623
+ const optional = !!(prop.flags & ts3.SymbolFlags.Optional);
2595
2624
  const propTypeNode = resolveTypeNode(
2596
2625
  propType,
2597
2626
  checker,
@@ -2636,11 +2665,11 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2636
2665
  for (const symbol of symbols) {
2637
2666
  const declarations = symbol.declarations;
2638
2667
  if (!declarations) continue;
2639
- const classDecl = declarations.find(ts4.isClassDeclaration);
2668
+ const classDecl = declarations.find(ts3.isClassDeclaration);
2640
2669
  if (classDecl) {
2641
2670
  const map = /* @__PURE__ */ new Map();
2642
2671
  for (const member of classDecl.members) {
2643
- if (ts4.isPropertyDeclaration(member) && ts4.isIdentifier(member.name)) {
2672
+ if (ts3.isPropertyDeclaration(member) && ts3.isIdentifier(member.name)) {
2644
2673
  const fieldNode = analyzeFieldToIR(
2645
2674
  member,
2646
2675
  checker,
@@ -2660,7 +2689,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2660
2689
  }
2661
2690
  return map;
2662
2691
  }
2663
- const interfaceDecl = declarations.find(ts4.isInterfaceDeclaration);
2692
+ const interfaceDecl = declarations.find(ts3.isInterfaceDeclaration);
2664
2693
  if (interfaceDecl) {
2665
2694
  return buildFieldNodeInfoMap(
2666
2695
  interfaceDecl.members,
@@ -2671,8 +2700,8 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2671
2700
  extensionRegistry
2672
2701
  );
2673
2702
  }
2674
- const typeAliasDecl = declarations.find(ts4.isTypeAliasDeclaration);
2675
- if (typeAliasDecl && ts4.isTypeLiteralNode(typeAliasDecl.type)) {
2703
+ const typeAliasDecl = declarations.find(ts3.isTypeAliasDeclaration);
2704
+ if (typeAliasDecl && ts3.isTypeLiteralNode(typeAliasDecl.type)) {
2676
2705
  return buildFieldNodeInfoMap(
2677
2706
  typeAliasDecl.type.members,
2678
2707
  checker,
@@ -2691,10 +2720,10 @@ function extractArrayElementTypeNode(sourceNode, checker) {
2691
2720
  return void 0;
2692
2721
  }
2693
2722
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
2694
- if (ts4.isArrayTypeNode(resolvedTypeNode)) {
2723
+ if (ts3.isArrayTypeNode(resolvedTypeNode)) {
2695
2724
  return resolvedTypeNode.elementType;
2696
2725
  }
2697
- if (ts4.isTypeReferenceNode(resolvedTypeNode) && ts4.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
2726
+ if (ts3.isTypeReferenceNode(resolvedTypeNode) && ts3.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
2698
2727
  return resolvedTypeNode.typeArguments[0];
2699
2728
  }
2700
2729
  return void 0;
@@ -2705,17 +2734,17 @@ function extractUnionMemberTypeNodes(sourceNode, checker) {
2705
2734
  return [];
2706
2735
  }
2707
2736
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
2708
- return ts4.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
2737
+ return ts3.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
2709
2738
  }
2710
2739
  function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
2711
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2740
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2712
2741
  return resolveAliasedTypeNode(typeNode.type, checker, visited);
2713
2742
  }
2714
- if (!ts4.isTypeReferenceNode(typeNode) || !ts4.isIdentifier(typeNode.typeName)) {
2743
+ if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
2715
2744
  return typeNode;
2716
2745
  }
2717
2746
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
2718
- const aliasDecl = symbol?.declarations?.find(ts4.isTypeAliasDeclaration);
2747
+ const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
2719
2748
  if (aliasDecl === void 0 || visited.has(aliasDecl)) {
2720
2749
  return typeNode;
2721
2750
  }
@@ -2723,15 +2752,15 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
2723
2752
  return resolveAliasedTypeNode(aliasDecl.type, checker, visited);
2724
2753
  }
2725
2754
  function isNullishTypeNode(typeNode) {
2726
- if (typeNode.kind === ts4.SyntaxKind.NullKeyword || typeNode.kind === ts4.SyntaxKind.UndefinedKeyword) {
2755
+ if (typeNode.kind === ts3.SyntaxKind.NullKeyword || typeNode.kind === ts3.SyntaxKind.UndefinedKeyword) {
2727
2756
  return true;
2728
2757
  }
2729
- return ts4.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts4.SyntaxKind.NullKeyword || typeNode.literal.kind === ts4.SyntaxKind.UndefinedKeyword);
2758
+ return ts3.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts3.SyntaxKind.NullKeyword || typeNode.literal.kind === ts3.SyntaxKind.UndefinedKeyword);
2730
2759
  }
2731
2760
  function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, extensionRegistry) {
2732
2761
  const map = /* @__PURE__ */ new Map();
2733
2762
  for (const member of members) {
2734
- if (ts4.isPropertySignature(member)) {
2763
+ if (ts3.isPropertySignature(member)) {
2735
2764
  const fieldNode = analyzeInterfacePropertyToIR(
2736
2765
  member,
2737
2766
  checker,
@@ -2752,7 +2781,7 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, e
2752
2781
  return map;
2753
2782
  }
2754
2783
  function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegistry, depth = 0) {
2755
- if (!ts4.isTypeReferenceNode(typeNode)) return [];
2784
+ if (!ts3.isTypeReferenceNode(typeNode)) return [];
2756
2785
  if (depth >= MAX_ALIAS_CHAIN_DEPTH) {
2757
2786
  const aliasName = typeNode.typeName.getText();
2758
2787
  throw new Error(
@@ -2761,9 +2790,9 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
2761
2790
  }
2762
2791
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
2763
2792
  if (!symbol?.declarations) return [];
2764
- const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
2793
+ const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
2765
2794
  if (!aliasDecl) return [];
2766
- if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
2795
+ if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
2767
2796
  const aliasFieldType = resolveTypeNode(
2768
2797
  checker.getTypeAtLocation(aliasDecl.type),
2769
2798
  checker,
@@ -2779,13 +2808,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
2779
2808
  makeParseOptions(extensionRegistry, aliasFieldType)
2780
2809
  );
2781
2810
  constraints.push(
2782
- ...extractTypeAliasConstraintNodes(
2783
- aliasDecl.type,
2784
- checker,
2785
- file,
2786
- extensionRegistry,
2787
- depth + 1
2788
- )
2811
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry, depth + 1)
2789
2812
  );
2790
2813
  return constraints;
2791
2814
  }
@@ -2812,14 +2835,14 @@ function getNamedTypeName(type) {
2812
2835
  const symbol = type.getSymbol();
2813
2836
  if (symbol?.declarations) {
2814
2837
  const decl = symbol.declarations[0];
2815
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
2816
- const name = ts4.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
2838
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
2839
+ const name = ts3.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
2817
2840
  if (name) return name;
2818
2841
  }
2819
2842
  }
2820
2843
  const aliasSymbol = type.aliasSymbol;
2821
2844
  if (aliasSymbol?.declarations) {
2822
- const aliasDecl = aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
2845
+ const aliasDecl = aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
2823
2846
  if (aliasDecl) {
2824
2847
  return aliasDecl.name.text;
2825
2848
  }
@@ -2830,24 +2853,24 @@ function getNamedTypeDeclaration(type) {
2830
2853
  const symbol = type.getSymbol();
2831
2854
  if (symbol?.declarations) {
2832
2855
  const decl = symbol.declarations[0];
2833
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
2856
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
2834
2857
  return decl;
2835
2858
  }
2836
2859
  }
2837
2860
  const aliasSymbol = type.aliasSymbol;
2838
2861
  if (aliasSymbol?.declarations) {
2839
- return aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
2862
+ return aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
2840
2863
  }
2841
2864
  return void 0;
2842
2865
  }
2843
2866
  function analyzeMethod(method, checker) {
2844
- if (!ts4.isIdentifier(method.name)) {
2867
+ if (!ts3.isIdentifier(method.name)) {
2845
2868
  return null;
2846
2869
  }
2847
2870
  const name = method.name.text;
2848
2871
  const parameters = [];
2849
2872
  for (const param of method.parameters) {
2850
- if (ts4.isIdentifier(param.name)) {
2873
+ if (ts3.isIdentifier(param.name)) {
2851
2874
  const paramInfo = analyzeParameter(param, checker);
2852
2875
  parameters.push(paramInfo);
2853
2876
  }
@@ -2858,7 +2881,7 @@ function analyzeMethod(method, checker) {
2858
2881
  return { name, parameters, returnTypeNode, returnType };
2859
2882
  }
2860
2883
  function analyzeParameter(param, checker) {
2861
- const name = ts4.isIdentifier(param.name) ? param.name.text : "param";
2884
+ const name = ts3.isIdentifier(param.name) ? param.name.text : "param";
2862
2885
  const typeNode = param.type;
2863
2886
  const type = checker.getTypeAtLocation(param);
2864
2887
  const formSpecExportName = detectFormSpecReference(typeNode);
@@ -2867,24 +2890,24 @@ function analyzeParameter(param, checker) {
2867
2890
  }
2868
2891
  function detectFormSpecReference(typeNode) {
2869
2892
  if (!typeNode) return null;
2870
- if (!ts4.isTypeReferenceNode(typeNode)) return null;
2871
- const typeName = ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts4.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
2893
+ if (!ts3.isTypeReferenceNode(typeNode)) return null;
2894
+ const typeName = ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts3.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
2872
2895
  if (typeName !== "InferSchema" && typeName !== "InferFormSchema") return null;
2873
2896
  const typeArg = typeNode.typeArguments?.[0];
2874
- if (!typeArg || !ts4.isTypeQueryNode(typeArg)) return null;
2875
- if (ts4.isIdentifier(typeArg.exprName)) {
2897
+ if (!typeArg || !ts3.isTypeQueryNode(typeArg)) return null;
2898
+ if (ts3.isIdentifier(typeArg.exprName)) {
2876
2899
  return typeArg.exprName.text;
2877
2900
  }
2878
- if (ts4.isQualifiedName(typeArg.exprName)) {
2901
+ if (ts3.isQualifiedName(typeArg.exprName)) {
2879
2902
  return typeArg.exprName.right.text;
2880
2903
  }
2881
2904
  return null;
2882
2905
  }
2883
- var ts4, RESOLVING_TYPE_PLACEHOLDER, MAX_ALIAS_CHAIN_DEPTH;
2906
+ var ts3, RESOLVING_TYPE_PLACEHOLDER, MAX_ALIAS_CHAIN_DEPTH;
2884
2907
  var init_class_analyzer = __esm({
2885
2908
  "src/analyzer/class-analyzer.ts"() {
2886
2909
  "use strict";
2887
- ts4 = __toESM(require("typescript"), 1);
2910
+ ts3 = __toESM(require("typescript"), 1);
2888
2911
  init_jsdoc_constraints();
2889
2912
  init_tsdoc_parser();
2890
2913
  RESOLVING_TYPE_PLACEHOLDER = {
@@ -2896,14 +2919,941 @@ var init_class_analyzer = __esm({
2896
2919
  }
2897
2920
  });
2898
2921
 
2922
+ // src/analyzer/program.ts
2923
+ function createProgramContext(filePath) {
2924
+ const absolutePath = path.resolve(filePath);
2925
+ const fileDir = path.dirname(absolutePath);
2926
+ const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
2927
+ let compilerOptions;
2928
+ let fileNames;
2929
+ if (configPath) {
2930
+ const configFile = ts4.readConfigFile(configPath, ts4.sys.readFile.bind(ts4.sys));
2931
+ if (configFile.error) {
2932
+ throw new Error(
2933
+ `Error reading tsconfig.json: ${ts4.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
2934
+ );
2935
+ }
2936
+ const parsed = ts4.parseJsonConfigFileContent(
2937
+ configFile.config,
2938
+ ts4.sys,
2939
+ path.dirname(configPath)
2940
+ );
2941
+ if (parsed.errors.length > 0) {
2942
+ const errorMessages = parsed.errors.map((e) => ts4.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
2943
+ throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
2944
+ }
2945
+ compilerOptions = parsed.options;
2946
+ fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
2947
+ } else {
2948
+ compilerOptions = {
2949
+ target: ts4.ScriptTarget.ES2022,
2950
+ module: ts4.ModuleKind.NodeNext,
2951
+ moduleResolution: ts4.ModuleResolutionKind.NodeNext,
2952
+ strict: true,
2953
+ skipLibCheck: true,
2954
+ declaration: true
2955
+ };
2956
+ fileNames = [absolutePath];
2957
+ }
2958
+ const program = ts4.createProgram(fileNames, compilerOptions);
2959
+ const sourceFile = program.getSourceFile(absolutePath);
2960
+ if (!sourceFile) {
2961
+ throw new Error(`Could not find source file: ${absolutePath}`);
2962
+ }
2963
+ return {
2964
+ program,
2965
+ checker: program.getTypeChecker(),
2966
+ sourceFile
2967
+ };
2968
+ }
2969
+ function findNodeByName(sourceFile, name, predicate, getName) {
2970
+ let result = null;
2971
+ function visit(node) {
2972
+ if (result) return;
2973
+ if (predicate(node) && getName(node) === name) {
2974
+ result = node;
2975
+ return;
2976
+ }
2977
+ ts4.forEachChild(node, visit);
2978
+ }
2979
+ visit(sourceFile);
2980
+ return result;
2981
+ }
2982
+ function findClassByName(sourceFile, className) {
2983
+ return findNodeByName(sourceFile, className, ts4.isClassDeclaration, (n) => n.name?.text);
2984
+ }
2985
+ function findInterfaceByName(sourceFile, interfaceName) {
2986
+ return findNodeByName(sourceFile, interfaceName, ts4.isInterfaceDeclaration, (n) => n.name.text);
2987
+ }
2988
+ function findTypeAliasByName(sourceFile, aliasName) {
2989
+ return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
2990
+ }
2991
+ function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry) {
2992
+ const ctx = createProgramContext(filePath);
2993
+ const classDecl = findClassByName(ctx.sourceFile, typeName);
2994
+ if (classDecl !== null) {
2995
+ return analyzeClassToIR(classDecl, ctx.checker, filePath, extensionRegistry);
2996
+ }
2997
+ const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
2998
+ if (interfaceDecl !== null) {
2999
+ return analyzeInterfaceToIR(interfaceDecl, ctx.checker, filePath, extensionRegistry);
3000
+ }
3001
+ const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
3002
+ if (typeAlias !== null) {
3003
+ const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, filePath, extensionRegistry);
3004
+ if (result.ok) {
3005
+ return result.analysis;
3006
+ }
3007
+ throw new Error(result.error);
3008
+ }
3009
+ throw new Error(
3010
+ `Type "${typeName}" not found as a class, interface, or type alias in ${filePath}`
3011
+ );
3012
+ }
3013
+ var ts4, path;
3014
+ var init_program = __esm({
3015
+ "src/analyzer/program.ts"() {
3016
+ "use strict";
3017
+ ts4 = __toESM(require("typescript"), 1);
3018
+ path = __toESM(require("path"), 1);
3019
+ init_class_analyzer();
3020
+ }
3021
+ });
3022
+
3023
+ // src/validate/constraint-validator.ts
3024
+ function addContradiction(ctx, message, primary, related) {
3025
+ ctx.diagnostics.push({
3026
+ code: "CONTRADICTING_CONSTRAINTS",
3027
+ message,
3028
+ severity: "error",
3029
+ primaryLocation: primary,
3030
+ relatedLocations: [related]
3031
+ });
3032
+ }
3033
+ function addTypeMismatch(ctx, message, primary) {
3034
+ ctx.diagnostics.push({
3035
+ code: "TYPE_MISMATCH",
3036
+ message,
3037
+ severity: "error",
3038
+ primaryLocation: primary,
3039
+ relatedLocations: []
3040
+ });
3041
+ }
3042
+ function addUnknownExtension(ctx, message, primary) {
3043
+ ctx.diagnostics.push({
3044
+ code: "UNKNOWN_EXTENSION",
3045
+ message,
3046
+ severity: "warning",
3047
+ primaryLocation: primary,
3048
+ relatedLocations: []
3049
+ });
3050
+ }
3051
+ function addUnknownPathTarget(ctx, message, primary) {
3052
+ ctx.diagnostics.push({
3053
+ code: "UNKNOWN_PATH_TARGET",
3054
+ message,
3055
+ severity: "error",
3056
+ primaryLocation: primary,
3057
+ relatedLocations: []
3058
+ });
3059
+ }
3060
+ function addConstraintBroadening(ctx, message, primary, related) {
3061
+ ctx.diagnostics.push({
3062
+ code: "CONSTRAINT_BROADENING",
3063
+ message,
3064
+ severity: "error",
3065
+ primaryLocation: primary,
3066
+ relatedLocations: [related]
3067
+ });
3068
+ }
3069
+ function getExtensionIdFromConstraintId(constraintId) {
3070
+ const separator = constraintId.lastIndexOf("/");
3071
+ if (separator <= 0) {
3072
+ return null;
3073
+ }
3074
+ return constraintId.slice(0, separator);
3075
+ }
3076
+ function findNumeric(constraints, constraintKind) {
3077
+ return constraints.find((c) => c.constraintKind === constraintKind);
3078
+ }
3079
+ function findLength(constraints, constraintKind) {
3080
+ return constraints.find((c) => c.constraintKind === constraintKind);
3081
+ }
3082
+ function findAllowedMembers(constraints) {
3083
+ return constraints.filter(
3084
+ (c) => c.constraintKind === "allowedMembers"
3085
+ );
3086
+ }
3087
+ function findConstConstraints(constraints) {
3088
+ return constraints.filter(
3089
+ (c) => c.constraintKind === "const"
3090
+ );
3091
+ }
3092
+ function jsonValueEquals(left, right) {
3093
+ if (left === right) {
3094
+ return true;
3095
+ }
3096
+ if (Array.isArray(left) || Array.isArray(right)) {
3097
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
3098
+ return false;
3099
+ }
3100
+ return left.every((item, index) => jsonValueEquals(item, right[index]));
3101
+ }
3102
+ if (isJsonObject(left) || isJsonObject(right)) {
3103
+ if (!isJsonObject(left) || !isJsonObject(right)) {
3104
+ return false;
3105
+ }
3106
+ const leftKeys = Object.keys(left).sort();
3107
+ const rightKeys = Object.keys(right).sort();
3108
+ if (leftKeys.length !== rightKeys.length) {
3109
+ return false;
3110
+ }
3111
+ return leftKeys.every((key, index) => {
3112
+ const rightKey = rightKeys[index];
3113
+ if (rightKey !== key) {
3114
+ return false;
3115
+ }
3116
+ const leftValue = left[key];
3117
+ const rightValue = right[rightKey];
3118
+ return leftValue !== void 0 && rightValue !== void 0 && jsonValueEquals(leftValue, rightValue);
3119
+ });
3120
+ }
3121
+ return false;
3122
+ }
3123
+ function isJsonObject(value) {
3124
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3125
+ }
3126
+ function isOrderedBoundConstraint(constraint) {
3127
+ return constraint.constraintKind === "minimum" || constraint.constraintKind === "exclusiveMinimum" || constraint.constraintKind === "minLength" || constraint.constraintKind === "minItems" || constraint.constraintKind === "maximum" || constraint.constraintKind === "exclusiveMaximum" || constraint.constraintKind === "maxLength" || constraint.constraintKind === "maxItems";
3128
+ }
3129
+ function pathKey(constraint) {
3130
+ return constraint.path?.segments.join(".") ?? "";
3131
+ }
3132
+ function orderedBoundFamily(kind) {
3133
+ switch (kind) {
3134
+ case "minimum":
3135
+ case "exclusiveMinimum":
3136
+ return "numeric-lower";
3137
+ case "maximum":
3138
+ case "exclusiveMaximum":
3139
+ return "numeric-upper";
3140
+ case "minLength":
3141
+ return "minLength";
3142
+ case "minItems":
3143
+ return "minItems";
3144
+ case "maxLength":
3145
+ return "maxLength";
3146
+ case "maxItems":
3147
+ return "maxItems";
3148
+ default: {
3149
+ const _exhaustive = kind;
3150
+ return _exhaustive;
3151
+ }
3152
+ }
3153
+ }
3154
+ function isNumericLowerKind(kind) {
3155
+ return kind === "minimum" || kind === "exclusiveMinimum";
3156
+ }
3157
+ function isNumericUpperKind(kind) {
3158
+ return kind === "maximum" || kind === "exclusiveMaximum";
3159
+ }
3160
+ function describeConstraintTag(constraint) {
3161
+ return `@${constraint.constraintKind}`;
3162
+ }
3163
+ function compareConstraintStrength(current, previous) {
3164
+ const family = orderedBoundFamily(current.constraintKind);
3165
+ if (family === "numeric-lower") {
3166
+ if (!isNumericLowerKind(current.constraintKind) || !isNumericLowerKind(previous.constraintKind)) {
3167
+ throw new Error("numeric-lower family received non-numeric lower-bound constraint");
3168
+ }
3169
+ if (current.value !== previous.value) {
3170
+ return current.value > previous.value ? 1 : -1;
3171
+ }
3172
+ if (current.constraintKind === "exclusiveMinimum" && previous.constraintKind === "minimum") {
3173
+ return 1;
3174
+ }
3175
+ if (current.constraintKind === "minimum" && previous.constraintKind === "exclusiveMinimum") {
3176
+ return -1;
3177
+ }
3178
+ return 0;
3179
+ }
3180
+ if (family === "numeric-upper") {
3181
+ if (!isNumericUpperKind(current.constraintKind) || !isNumericUpperKind(previous.constraintKind)) {
3182
+ throw new Error("numeric-upper family received non-numeric upper-bound constraint");
3183
+ }
3184
+ if (current.value !== previous.value) {
3185
+ return current.value < previous.value ? 1 : -1;
3186
+ }
3187
+ if (current.constraintKind === "exclusiveMaximum" && previous.constraintKind === "maximum") {
3188
+ return 1;
3189
+ }
3190
+ if (current.constraintKind === "maximum" && previous.constraintKind === "exclusiveMaximum") {
3191
+ return -1;
3192
+ }
3193
+ return 0;
3194
+ }
3195
+ switch (family) {
3196
+ case "minLength":
3197
+ case "minItems":
3198
+ if (current.value === previous.value) {
3199
+ return 0;
3200
+ }
3201
+ return current.value > previous.value ? 1 : -1;
3202
+ case "maxLength":
3203
+ case "maxItems":
3204
+ if (current.value === previous.value) {
3205
+ return 0;
3206
+ }
3207
+ return current.value < previous.value ? 1 : -1;
3208
+ default: {
3209
+ const _exhaustive = family;
3210
+ return _exhaustive;
3211
+ }
3212
+ }
3213
+ }
3214
+ function checkConstraintBroadening(ctx, fieldName, constraints) {
3215
+ const strongestByKey = /* @__PURE__ */ new Map();
3216
+ for (const constraint of constraints) {
3217
+ if (!isOrderedBoundConstraint(constraint)) {
3218
+ continue;
3219
+ }
3220
+ const key = `${orderedBoundFamily(constraint.constraintKind)}:${pathKey(constraint)}`;
3221
+ const previous = strongestByKey.get(key);
3222
+ if (previous === void 0) {
3223
+ strongestByKey.set(key, constraint);
3224
+ continue;
3225
+ }
3226
+ const strength = compareConstraintStrength(constraint, previous);
3227
+ if (strength < 0) {
3228
+ const displayFieldName = formatPathTargetFieldName(
3229
+ fieldName,
3230
+ constraint.path?.segments ?? []
3231
+ );
3232
+ addConstraintBroadening(
3233
+ ctx,
3234
+ `Field "${displayFieldName}": ${describeConstraintTag(constraint)} (${String(constraint.value)}) is broader than earlier ${describeConstraintTag(previous)} (${String(previous.value)}). Constraints can only narrow.`,
3235
+ constraint.provenance,
3236
+ previous.provenance
3237
+ );
3238
+ continue;
3239
+ }
3240
+ if (strength <= 0) {
3241
+ continue;
3242
+ }
3243
+ strongestByKey.set(key, constraint);
3244
+ }
3245
+ }
3246
+ function compareCustomConstraintStrength(current, previous) {
3247
+ const order = current.comparePayloads(current.constraint.payload, previous.constraint.payload);
3248
+ const equalPayloadTiebreaker = order === 0 ? compareSemanticInclusivity(current.role.inclusive, previous.role.inclusive) : order;
3249
+ switch (current.role.bound) {
3250
+ case "lower":
3251
+ return equalPayloadTiebreaker;
3252
+ case "upper":
3253
+ return equalPayloadTiebreaker === 0 ? 0 : -equalPayloadTiebreaker;
3254
+ case "exact":
3255
+ return order === 0 ? 0 : Number.NaN;
3256
+ default: {
3257
+ const _exhaustive = current.role.bound;
3258
+ return _exhaustive;
3259
+ }
3260
+ }
3261
+ }
3262
+ function compareSemanticInclusivity(currentInclusive, previousInclusive) {
3263
+ if (currentInclusive === previousInclusive) {
3264
+ return 0;
3265
+ }
3266
+ return currentInclusive ? -1 : 1;
3267
+ }
3268
+ function customConstraintsContradict(lower, upper) {
3269
+ const order = lower.comparePayloads(lower.constraint.payload, upper.constraint.payload);
3270
+ if (order > 0) {
3271
+ return true;
3272
+ }
3273
+ if (order < 0) {
3274
+ return false;
3275
+ }
3276
+ return !lower.role.inclusive || !upper.role.inclusive;
3277
+ }
3278
+ function describeCustomConstraintTag(constraint) {
3279
+ return constraint.provenance.tagName ?? constraint.constraintId;
3280
+ }
3281
+ function checkCustomConstraintSemantics(ctx, fieldName, constraints) {
3282
+ if (ctx.extensionRegistry === void 0) {
3283
+ return;
3284
+ }
3285
+ const strongestByKey = /* @__PURE__ */ new Map();
3286
+ const lowerByFamily = /* @__PURE__ */ new Map();
3287
+ const upperByFamily = /* @__PURE__ */ new Map();
3288
+ for (const constraint of constraints) {
3289
+ if (constraint.constraintKind !== "custom") {
3290
+ continue;
3291
+ }
3292
+ const registration = ctx.extensionRegistry.findConstraint(constraint.constraintId);
3293
+ if (registration?.comparePayloads === void 0 || registration.semanticRole === void 0) {
3294
+ continue;
3295
+ }
3296
+ const entry = {
3297
+ constraint,
3298
+ comparePayloads: registration.comparePayloads,
3299
+ role: registration.semanticRole
3300
+ };
3301
+ const familyKey = `${registration.semanticRole.family}:${pathKey(constraint)}`;
3302
+ const boundKey = `${familyKey}:${registration.semanticRole.bound}`;
3303
+ const previous = strongestByKey.get(boundKey);
3304
+ if (previous !== void 0) {
3305
+ const strength = compareCustomConstraintStrength(entry, previous);
3306
+ if (Number.isNaN(strength)) {
3307
+ addContradiction(
3308
+ ctx,
3309
+ `Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} conflicts with ${describeCustomConstraintTag(previous.constraint)}`,
3310
+ constraint.provenance,
3311
+ previous.constraint.provenance
3312
+ );
3313
+ continue;
3314
+ }
3315
+ if (strength < 0) {
3316
+ addConstraintBroadening(
3317
+ ctx,
3318
+ `Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} is broader than earlier ${describeCustomConstraintTag(previous.constraint)}. Constraints can only narrow.`,
3319
+ constraint.provenance,
3320
+ previous.constraint.provenance
3321
+ );
3322
+ continue;
3323
+ }
3324
+ if (strength > 0) {
3325
+ strongestByKey.set(boundKey, entry);
3326
+ }
3327
+ } else {
3328
+ strongestByKey.set(boundKey, entry);
3329
+ }
3330
+ if (registration.semanticRole.bound === "lower") {
3331
+ lowerByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
3332
+ } else if (registration.semanticRole.bound === "upper") {
3333
+ upperByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
3334
+ }
3335
+ }
3336
+ for (const [familyKey, lower] of lowerByFamily) {
3337
+ const upper = upperByFamily.get(familyKey);
3338
+ if (upper === void 0) {
3339
+ continue;
3340
+ }
3341
+ if (!customConstraintsContradict(lower, upper)) {
3342
+ continue;
3343
+ }
3344
+ addContradiction(
3345
+ ctx,
3346
+ `Field "${formatPathTargetFieldName(fieldName, lower.constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(lower.constraint)} contradicts ${describeCustomConstraintTag(upper.constraint)}`,
3347
+ lower.constraint.provenance,
3348
+ upper.constraint.provenance
3349
+ );
3350
+ }
3351
+ }
3352
+ function checkNumericContradictions(ctx, fieldName, constraints) {
3353
+ const min = findNumeric(constraints, "minimum");
3354
+ const max = findNumeric(constraints, "maximum");
3355
+ const exMin = findNumeric(constraints, "exclusiveMinimum");
3356
+ const exMax = findNumeric(constraints, "exclusiveMaximum");
3357
+ if (min !== void 0 && max !== void 0 && min.value > max.value) {
3358
+ addContradiction(
3359
+ ctx,
3360
+ `Field "${fieldName}": minimum (${String(min.value)}) is greater than maximum (${String(max.value)})`,
3361
+ min.provenance,
3362
+ max.provenance
3363
+ );
3364
+ }
3365
+ if (exMin !== void 0 && max !== void 0 && exMin.value >= max.value) {
3366
+ addContradiction(
3367
+ ctx,
3368
+ `Field "${fieldName}": exclusiveMinimum (${String(exMin.value)}) is greater than or equal to maximum (${String(max.value)})`,
3369
+ exMin.provenance,
3370
+ max.provenance
3371
+ );
3372
+ }
3373
+ if (min !== void 0 && exMax !== void 0 && min.value >= exMax.value) {
3374
+ addContradiction(
3375
+ ctx,
3376
+ `Field "${fieldName}": minimum (${String(min.value)}) is greater than or equal to exclusiveMaximum (${String(exMax.value)})`,
3377
+ min.provenance,
3378
+ exMax.provenance
3379
+ );
3380
+ }
3381
+ if (exMin !== void 0 && exMax !== void 0 && exMin.value >= exMax.value) {
3382
+ addContradiction(
3383
+ ctx,
3384
+ `Field "${fieldName}": exclusiveMinimum (${String(exMin.value)}) is greater than or equal to exclusiveMaximum (${String(exMax.value)})`,
3385
+ exMin.provenance,
3386
+ exMax.provenance
3387
+ );
3388
+ }
3389
+ }
3390
+ function checkLengthContradictions(ctx, fieldName, constraints) {
3391
+ const minLen = findLength(constraints, "minLength");
3392
+ const maxLen = findLength(constraints, "maxLength");
3393
+ if (minLen !== void 0 && maxLen !== void 0 && minLen.value > maxLen.value) {
3394
+ addContradiction(
3395
+ ctx,
3396
+ `Field "${fieldName}": minLength (${String(minLen.value)}) is greater than maxLength (${String(maxLen.value)})`,
3397
+ minLen.provenance,
3398
+ maxLen.provenance
3399
+ );
3400
+ }
3401
+ const minItems = findLength(constraints, "minItems");
3402
+ const maxItems = findLength(constraints, "maxItems");
3403
+ if (minItems !== void 0 && maxItems !== void 0 && minItems.value > maxItems.value) {
3404
+ addContradiction(
3405
+ ctx,
3406
+ `Field "${fieldName}": minItems (${String(minItems.value)}) is greater than maxItems (${String(maxItems.value)})`,
3407
+ minItems.provenance,
3408
+ maxItems.provenance
3409
+ );
3410
+ }
3411
+ }
3412
+ function checkAllowedMembersContradiction(ctx, fieldName, constraints) {
3413
+ const members = findAllowedMembers(constraints);
3414
+ if (members.length < 2) return;
3415
+ const firstSet = new Set(members[0]?.members ?? []);
3416
+ for (let i = 1; i < members.length; i++) {
3417
+ const current = members[i];
3418
+ if (current === void 0) continue;
3419
+ for (const m of firstSet) {
3420
+ if (!current.members.includes(m)) {
3421
+ firstSet.delete(m);
3422
+ }
3423
+ }
3424
+ }
3425
+ if (firstSet.size === 0) {
3426
+ const first = members[0];
3427
+ const second = members[1];
3428
+ if (first !== void 0 && second !== void 0) {
3429
+ addContradiction(
3430
+ ctx,
3431
+ `Field "${fieldName}": allowedMembers constraints have an empty intersection (no valid values remain)`,
3432
+ first.provenance,
3433
+ second.provenance
3434
+ );
3435
+ }
3436
+ }
3437
+ }
3438
+ function checkConstContradictions(ctx, fieldName, constraints) {
3439
+ const constConstraints = findConstConstraints(constraints);
3440
+ if (constConstraints.length < 2) return;
3441
+ const first = constConstraints[0];
3442
+ if (first === void 0) return;
3443
+ for (let i = 1; i < constConstraints.length; i++) {
3444
+ const current = constConstraints[i];
3445
+ if (current === void 0) continue;
3446
+ if (jsonValueEquals(first.value, current.value)) {
3447
+ continue;
3448
+ }
3449
+ addContradiction(
3450
+ ctx,
3451
+ `Field "${fieldName}": conflicting @const constraints require both ${JSON.stringify(first.value)} and ${JSON.stringify(current.value)}`,
3452
+ first.provenance,
3453
+ current.provenance
3454
+ );
3455
+ }
3456
+ }
3457
+ function typeLabel(type) {
3458
+ switch (type.kind) {
3459
+ case "primitive":
3460
+ return type.primitiveKind;
3461
+ case "enum":
3462
+ return "enum";
3463
+ case "array":
3464
+ return "array";
3465
+ case "object":
3466
+ return "object";
3467
+ case "record":
3468
+ return "record";
3469
+ case "union":
3470
+ return "union";
3471
+ case "reference":
3472
+ return `reference(${type.name})`;
3473
+ case "dynamic":
3474
+ return `dynamic(${type.dynamicKind})`;
3475
+ case "custom":
3476
+ return `custom(${type.typeId})`;
3477
+ default: {
3478
+ const _exhaustive = type;
3479
+ return String(_exhaustive);
3480
+ }
3481
+ }
3482
+ }
3483
+ function dereferenceType(ctx, type) {
3484
+ let current = type;
3485
+ const seen = /* @__PURE__ */ new Set();
3486
+ while (current.kind === "reference") {
3487
+ if (seen.has(current.name)) {
3488
+ return current;
3489
+ }
3490
+ seen.add(current.name);
3491
+ const definition = ctx.typeRegistry[current.name];
3492
+ if (definition === void 0) {
3493
+ return current;
3494
+ }
3495
+ current = definition.type;
3496
+ }
3497
+ return current;
3498
+ }
3499
+ function collectReferencedTypeConstraints(ctx, type) {
3500
+ const collected = [];
3501
+ let current = type;
3502
+ const seen = /* @__PURE__ */ new Set();
3503
+ while (current.kind === "reference") {
3504
+ if (seen.has(current.name)) {
3505
+ break;
3506
+ }
3507
+ seen.add(current.name);
3508
+ const definition = ctx.typeRegistry[current.name];
3509
+ if (definition === void 0) {
3510
+ break;
3511
+ }
3512
+ if (definition.constraints !== void 0) {
3513
+ collected.push(...definition.constraints);
3514
+ }
3515
+ current = definition.type;
3516
+ }
3517
+ return collected;
3518
+ }
3519
+ function resolvePathTargetType(ctx, type, segments) {
3520
+ const effectiveType = dereferenceType(ctx, type);
3521
+ if (segments.length === 0) {
3522
+ return { kind: "resolved", type: effectiveType };
3523
+ }
3524
+ if (effectiveType.kind === "array") {
3525
+ return resolvePathTargetType(ctx, effectiveType.items, segments);
3526
+ }
3527
+ if (effectiveType.kind === "object") {
3528
+ const [segment, ...rest] = segments;
3529
+ if (segment === void 0) {
3530
+ throw new Error("Invariant violation: object path traversal requires a segment");
3531
+ }
3532
+ const property = effectiveType.properties.find((prop) => prop.name === segment);
3533
+ if (property === void 0) {
3534
+ return { kind: "missing-property", segment };
3535
+ }
3536
+ return resolvePathTargetType(ctx, property.type, rest);
3537
+ }
3538
+ return { kind: "unresolvable", type: effectiveType };
3539
+ }
3540
+ function isNullType(type) {
3541
+ return type.kind === "primitive" && type.primitiveKind === "null";
3542
+ }
3543
+ function collectCustomConstraintCandidateTypes(ctx, type) {
3544
+ const effectiveType = dereferenceType(ctx, type);
3545
+ const candidates = [effectiveType];
3546
+ if (effectiveType.kind === "array") {
3547
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, effectiveType.items));
3548
+ }
3549
+ if (effectiveType.kind === "union") {
3550
+ const memberTypes = effectiveType.members.map((member) => dereferenceType(ctx, member));
3551
+ const nonNullMembers = memberTypes.filter((member) => !isNullType(member));
3552
+ if (nonNullMembers.length === 1 && nonNullMembers.length < memberTypes.length) {
3553
+ const [nullableMember] = nonNullMembers;
3554
+ if (nullableMember !== void 0) {
3555
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, nullableMember));
3556
+ }
3557
+ }
3558
+ }
3559
+ return candidates;
3560
+ }
3561
+ function formatPathTargetFieldName(fieldName, path4) {
3562
+ return path4.length === 0 ? fieldName : `${fieldName}.${path4.join(".")}`;
3563
+ }
3564
+ function checkConstraintOnType(ctx, fieldName, type, constraint) {
3565
+ const effectiveType = dereferenceType(ctx, type);
3566
+ const isNumber = effectiveType.kind === "primitive" && ["number", "integer", "bigint"].includes(effectiveType.primitiveKind);
3567
+ const isString = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "string";
3568
+ const isArray = effectiveType.kind === "array";
3569
+ const isEnum = effectiveType.kind === "enum";
3570
+ const arrayItemType = effectiveType.kind === "array" ? dereferenceType(ctx, effectiveType.items) : void 0;
3571
+ const isStringArray = arrayItemType?.kind === "primitive" && arrayItemType.primitiveKind === "string";
3572
+ const label = typeLabel(effectiveType);
3573
+ const ck = constraint.constraintKind;
3574
+ switch (ck) {
3575
+ case "minimum":
3576
+ case "maximum":
3577
+ case "exclusiveMinimum":
3578
+ case "exclusiveMaximum":
3579
+ case "multipleOf": {
3580
+ if (!isNumber) {
3581
+ addTypeMismatch(
3582
+ ctx,
3583
+ `Field "${fieldName}": constraint "${ck}" is only valid on number fields, but field type is "${label}"`,
3584
+ constraint.provenance
3585
+ );
3586
+ }
3587
+ break;
3588
+ }
3589
+ case "minLength":
3590
+ case "maxLength":
3591
+ case "pattern": {
3592
+ if (!isString && !isStringArray) {
3593
+ addTypeMismatch(
3594
+ ctx,
3595
+ `Field "${fieldName}": constraint "${ck}" is only valid on string fields or string array items, but field type is "${label}"`,
3596
+ constraint.provenance
3597
+ );
3598
+ }
3599
+ break;
3600
+ }
3601
+ case "minItems":
3602
+ case "maxItems":
3603
+ case "uniqueItems": {
3604
+ if (!isArray) {
3605
+ addTypeMismatch(
3606
+ ctx,
3607
+ `Field "${fieldName}": constraint "${ck}" is only valid on array fields, but field type is "${label}"`,
3608
+ constraint.provenance
3609
+ );
3610
+ }
3611
+ break;
3612
+ }
3613
+ case "allowedMembers": {
3614
+ if (!isEnum) {
3615
+ addTypeMismatch(
3616
+ ctx,
3617
+ `Field "${fieldName}": constraint "allowedMembers" is only valid on enum fields, but field type is "${label}"`,
3618
+ constraint.provenance
3619
+ );
3620
+ }
3621
+ break;
3622
+ }
3623
+ case "const": {
3624
+ const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "integer", "bigint", "boolean", "null"].includes(
3625
+ effectiveType.primitiveKind
3626
+ ) || effectiveType.kind === "enum";
3627
+ if (!isPrimitiveConstType) {
3628
+ addTypeMismatch(
3629
+ ctx,
3630
+ `Field "${fieldName}": constraint "const" is only valid on primitive or enum fields, but field type is "${label}"`,
3631
+ constraint.provenance
3632
+ );
3633
+ break;
3634
+ }
3635
+ if (effectiveType.kind === "primitive") {
3636
+ const valueType = constraint.value === null ? "null" : Array.isArray(constraint.value) ? "array" : typeof constraint.value;
3637
+ const expectedValueType = effectiveType.primitiveKind === "integer" || effectiveType.primitiveKind === "bigint" ? "number" : effectiveType.primitiveKind;
3638
+ if (valueType !== expectedValueType) {
3639
+ addTypeMismatch(
3640
+ ctx,
3641
+ `Field "${fieldName}": @const value type "${valueType}" is incompatible with field type "${effectiveType.primitiveKind}"`,
3642
+ constraint.provenance
3643
+ );
3644
+ }
3645
+ break;
3646
+ }
3647
+ const memberValues = effectiveType.members.map((member) => member.value);
3648
+ if (!memberValues.some((member) => jsonValueEquals(member, constraint.value))) {
3649
+ addTypeMismatch(
3650
+ ctx,
3651
+ `Field "${fieldName}": @const value ${JSON.stringify(constraint.value)} is not one of the enum members`,
3652
+ constraint.provenance
3653
+ );
3654
+ }
3655
+ break;
3656
+ }
3657
+ case "custom": {
3658
+ checkCustomConstraint(ctx, fieldName, effectiveType, constraint);
3659
+ break;
3660
+ }
3661
+ default: {
3662
+ const _exhaustive = constraint;
3663
+ throw new Error(
3664
+ `Unhandled constraint kind: ${_exhaustive.constraintKind}`
3665
+ );
3666
+ }
3667
+ }
3668
+ }
3669
+ function checkTypeApplicability(ctx, fieldName, type, constraints) {
3670
+ for (const constraint of constraints) {
3671
+ if (constraint.path) {
3672
+ const resolution = resolvePathTargetType(ctx, type, constraint.path.segments);
3673
+ const targetFieldName = formatPathTargetFieldName(fieldName, constraint.path.segments);
3674
+ if (resolution.kind === "missing-property") {
3675
+ addUnknownPathTarget(
3676
+ ctx,
3677
+ `Field "${targetFieldName}": path-targeted constraint "${constraint.constraintKind}" references unknown path segment "${resolution.segment}"`,
3678
+ constraint.provenance
3679
+ );
3680
+ continue;
3681
+ }
3682
+ if (resolution.kind === "unresolvable") {
3683
+ addTypeMismatch(
3684
+ ctx,
3685
+ `Field "${targetFieldName}": path-targeted constraint "${constraint.constraintKind}" is invalid because type "${typeLabel(resolution.type)}" cannot be traversed`,
3686
+ constraint.provenance
3687
+ );
3688
+ continue;
3689
+ }
3690
+ checkConstraintOnType(ctx, targetFieldName, resolution.type, constraint);
3691
+ continue;
3692
+ }
3693
+ checkConstraintOnType(ctx, fieldName, type, constraint);
3694
+ }
3695
+ }
3696
+ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3697
+ if (ctx.extensionRegistry === void 0) return;
3698
+ const registration = ctx.extensionRegistry.findConstraint(constraint.constraintId);
3699
+ if (registration === void 0) {
3700
+ addUnknownExtension(
3701
+ ctx,
3702
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not registered in the extension registry`,
3703
+ constraint.provenance
3704
+ );
3705
+ return;
3706
+ }
3707
+ const candidateTypes = collectCustomConstraintCandidateTypes(ctx, type);
3708
+ const normalizedTagName = constraint.provenance.tagName === void 0 ? void 0 : (0, import_core4.normalizeConstraintTagName)(constraint.provenance.tagName.replace(/^@/, ""));
3709
+ if (normalizedTagName !== void 0) {
3710
+ const tagRegistration = ctx.extensionRegistry.findConstraintTag(normalizedTagName);
3711
+ const extensionId = getExtensionIdFromConstraintId(constraint.constraintId);
3712
+ if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && !candidateTypes.some(
3713
+ (candidateType) => tagRegistration.registration.isApplicableToType?.(candidateType) !== false
3714
+ )) {
3715
+ addTypeMismatch(
3716
+ ctx,
3717
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3718
+ constraint.provenance
3719
+ );
3720
+ return;
3721
+ }
3722
+ }
3723
+ if (registration.applicableTypes === null) {
3724
+ if (!candidateTypes.some((candidateType) => registration.isApplicableToType?.(candidateType) !== false)) {
3725
+ addTypeMismatch(
3726
+ ctx,
3727
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3728
+ constraint.provenance
3729
+ );
3730
+ }
3731
+ return;
3732
+ }
3733
+ const applicableTypes = registration.applicableTypes;
3734
+ const matchesApplicableType = candidateTypes.some(
3735
+ (candidateType) => applicableTypes.includes(candidateType.kind) && registration.isApplicableToType?.(candidateType) !== false
3736
+ );
3737
+ if (!matchesApplicableType) {
3738
+ addTypeMismatch(
3739
+ ctx,
3740
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3741
+ constraint.provenance
3742
+ );
3743
+ }
3744
+ }
3745
+ function validateFieldNode(ctx, field) {
3746
+ validateConstraints(ctx, field.name, field.type, [
3747
+ ...collectReferencedTypeConstraints(ctx, field.type),
3748
+ ...field.constraints
3749
+ ]);
3750
+ if (field.type.kind === "object") {
3751
+ for (const prop of field.type.properties) {
3752
+ validateObjectProperty(ctx, field.name, prop);
3753
+ }
3754
+ }
3755
+ }
3756
+ function validateObjectProperty(ctx, parentName, prop) {
3757
+ const qualifiedName = `${parentName}.${prop.name}`;
3758
+ validateConstraints(ctx, qualifiedName, prop.type, [
3759
+ ...collectReferencedTypeConstraints(ctx, prop.type),
3760
+ ...prop.constraints
3761
+ ]);
3762
+ if (prop.type.kind === "object") {
3763
+ for (const nestedProp of prop.type.properties) {
3764
+ validateObjectProperty(ctx, qualifiedName, nestedProp);
3765
+ }
3766
+ }
3767
+ }
3768
+ function validateConstraints(ctx, name, type, constraints) {
3769
+ checkNumericContradictions(ctx, name, constraints);
3770
+ checkLengthContradictions(ctx, name, constraints);
3771
+ checkAllowedMembersContradiction(ctx, name, constraints);
3772
+ checkConstContradictions(ctx, name, constraints);
3773
+ checkConstraintBroadening(ctx, name, constraints);
3774
+ checkCustomConstraintSemantics(ctx, name, constraints);
3775
+ checkTypeApplicability(ctx, name, type, constraints);
3776
+ }
3777
+ function validateElement(ctx, element) {
3778
+ switch (element.kind) {
3779
+ case "field":
3780
+ validateFieldNode(ctx, element);
3781
+ break;
3782
+ case "group":
3783
+ for (const child of element.elements) {
3784
+ validateElement(ctx, child);
3785
+ }
3786
+ break;
3787
+ case "conditional":
3788
+ for (const child of element.elements) {
3789
+ validateElement(ctx, child);
3790
+ }
3791
+ break;
3792
+ default: {
3793
+ const _exhaustive = element;
3794
+ throw new Error(`Unhandled element kind: ${_exhaustive.kind}`);
3795
+ }
3796
+ }
3797
+ }
3798
+ function validateIR(ir, options) {
3799
+ const ctx = {
3800
+ diagnostics: [],
3801
+ extensionRegistry: options?.extensionRegistry,
3802
+ typeRegistry: ir.typeRegistry
3803
+ };
3804
+ for (const element of ir.elements) {
3805
+ validateElement(ctx, element);
3806
+ }
3807
+ return {
3808
+ diagnostics: ctx.diagnostics,
3809
+ valid: ctx.diagnostics.every((d) => d.severity !== "error")
3810
+ };
3811
+ }
3812
+ var import_core4;
3813
+ var init_constraint_validator = __esm({
3814
+ "src/validate/constraint-validator.ts"() {
3815
+ "use strict";
3816
+ import_core4 = require("@formspec/core");
3817
+ }
3818
+ });
3819
+
3820
+ // src/validate/index.ts
3821
+ var init_validate = __esm({
3822
+ "src/validate/index.ts"() {
3823
+ "use strict";
3824
+ init_constraint_validator();
3825
+ }
3826
+ });
3827
+
2899
3828
  // src/generators/class-schema.ts
2900
3829
  function generateClassSchemas(analysis, source, options) {
2901
3830
  const ir = canonicalizeTSDoc(analysis, source);
3831
+ const validationResult = validateIR(ir, {
3832
+ ...options?.extensionRegistry !== void 0 && {
3833
+ extensionRegistry: options.extensionRegistry
3834
+ },
3835
+ ...options?.vendorPrefix !== void 0 && { vendorPrefix: options.vendorPrefix }
3836
+ });
3837
+ if (!validationResult.valid) {
3838
+ throw new Error(formatValidationError(validationResult.diagnostics));
3839
+ }
2902
3840
  return {
2903
3841
  jsonSchema: generateJsonSchemaFromIR(ir, options),
2904
3842
  uiSchema: generateUiSchemaFromIR(ir)
2905
3843
  };
2906
3844
  }
3845
+ function formatValidationError(diagnostics) {
3846
+ const lines = diagnostics.map((diagnostic) => {
3847
+ const primary = formatLocation(diagnostic.primaryLocation);
3848
+ const related = diagnostic.relatedLocations.length > 0 ? ` [related: ${diagnostic.relatedLocations.map(formatLocation).join(", ")}]` : "";
3849
+ return `${diagnostic.code}: ${diagnostic.message} (${primary})${related}`;
3850
+ });
3851
+ return `FormSpec validation failed:
3852
+ ${lines.map((line) => `- ${line}`).join("\n")}`;
3853
+ }
3854
+ function formatLocation(location) {
3855
+ return `${location.file}:${String(location.line)}:${String(location.column)}`;
3856
+ }
2907
3857
  function generateSchemasFromClass(options) {
2908
3858
  const ctx = createProgramContext(options.filePath);
2909
3859
  const classDecl = findClassByName(ctx.sourceFile, options.className);
@@ -2926,44 +3876,12 @@ function generateSchemasFromClass(options) {
2926
3876
  );
2927
3877
  }
2928
3878
  function generateSchemas(options) {
2929
- const ctx = createProgramContext(options.filePath);
2930
- const source = { file: options.filePath };
2931
- const classDecl = findClassByName(ctx.sourceFile, options.typeName);
2932
- if (classDecl) {
2933
- const analysis = analyzeClassToIR(
2934
- classDecl,
2935
- ctx.checker,
2936
- options.filePath,
2937
- options.extensionRegistry
2938
- );
2939
- return generateClassSchemas(analysis, source, options);
2940
- }
2941
- const interfaceDecl = findInterfaceByName(ctx.sourceFile, options.typeName);
2942
- if (interfaceDecl) {
2943
- const analysis = analyzeInterfaceToIR(
2944
- interfaceDecl,
2945
- ctx.checker,
2946
- options.filePath,
2947
- options.extensionRegistry
2948
- );
2949
- return generateClassSchemas(analysis, source, options);
2950
- }
2951
- const typeAlias = findTypeAliasByName(ctx.sourceFile, options.typeName);
2952
- if (typeAlias) {
2953
- const result = analyzeTypeAliasToIR(
2954
- typeAlias,
2955
- ctx.checker,
2956
- options.filePath,
2957
- options.extensionRegistry
2958
- );
2959
- if (result.ok) {
2960
- return generateClassSchemas(result.analysis, source, options);
2961
- }
2962
- throw new Error(result.error);
2963
- }
2964
- throw new Error(
2965
- `Type "${options.typeName}" not found as a class, interface, or type alias in ${options.filePath}`
3879
+ const analysis = analyzeNamedTypeToIR(
3880
+ options.filePath,
3881
+ options.typeName,
3882
+ options.extensionRegistry
2966
3883
  );
3884
+ return generateClassSchemas(analysis, { file: options.filePath }, options);
2967
3885
  }
2968
3886
  var init_class_schema = __esm({
2969
3887
  "src/generators/class-schema.ts"() {
@@ -2973,13 +3891,14 @@ var init_class_schema = __esm({
2973
3891
  init_canonicalize();
2974
3892
  init_ir_generator();
2975
3893
  init_ir_generator2();
3894
+ init_validate();
2976
3895
  }
2977
3896
  });
2978
3897
 
2979
3898
  // src/generators/mixed-authoring.ts
2980
3899
  function buildMixedAuthoringSchemas(options) {
2981
3900
  const { filePath, typeName, overlays, ...schemaOptions } = options;
2982
- const analysis = analyzeNamedType(filePath, typeName, schemaOptions.extensionRegistry);
3901
+ const analysis = analyzeNamedTypeToIR(filePath, typeName, schemaOptions.extensionRegistry);
2983
3902
  const composedAnalysis = composeAnalysisWithOverlays(analysis, overlays);
2984
3903
  const ir = canonicalizeTSDoc(composedAnalysis, { file: filePath });
2985
3904
  return {
@@ -2987,29 +3906,6 @@ function buildMixedAuthoringSchemas(options) {
2987
3906
  uiSchema: generateUiSchemaFromIR(ir)
2988
3907
  };
2989
3908
  }
2990
- function analyzeNamedType(filePath, typeName, extensionRegistry) {
2991
- const ctx = createProgramContext(filePath);
2992
- const source = { file: filePath };
2993
- const classDecl = findClassByName(ctx.sourceFile, typeName);
2994
- if (classDecl !== null) {
2995
- return analyzeClassToIR(classDecl, ctx.checker, source.file, extensionRegistry);
2996
- }
2997
- const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
2998
- if (interfaceDecl !== null) {
2999
- return analyzeInterfaceToIR(interfaceDecl, ctx.checker, source.file, extensionRegistry);
3000
- }
3001
- const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
3002
- if (typeAlias !== null) {
3003
- const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, source.file, extensionRegistry);
3004
- if (result.ok) {
3005
- return result.analysis;
3006
- }
3007
- throw new Error(result.error);
3008
- }
3009
- throw new Error(
3010
- `Type "${typeName}" not found as a class, interface, or type alias in ${filePath}`
3011
- );
3012
- }
3013
3909
  function composeAnalysisWithOverlays(analysis, overlays) {
3014
3910
  const overlayIR = canonicalizeChainDSL(overlays);
3015
3911
  const overlayFields = collectOverlayFields(overlayIR.elements);
@@ -3181,7 +4077,6 @@ var init_mixed_authoring = __esm({
3181
4077
  init_ir_generator2();
3182
4078
  init_canonicalize();
3183
4079
  init_program();
3184
- init_class_analyzer();
3185
4080
  }
3186
4081
  });
3187
4082