@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.js CHANGED
@@ -25,6 +25,7 @@ function canonicalizeChainDSL(form) {
25
25
  kind: "form-ir",
26
26
  irVersion: IR_VERSION,
27
27
  elements: canonicalizeElements(form.elements),
28
+ rootAnnotations: [],
28
29
  typeRegistry: {},
29
30
  provenance: CHAIN_DSL_PROVENANCE
30
31
  };
@@ -342,6 +343,7 @@ function canonicalizeTSDoc(analysis, source) {
342
343
  irVersion: IR_VERSION2,
343
344
  elements,
344
345
  typeRegistry: analysis.typeRegistry,
346
+ ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations },
345
347
  ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { annotations: analysis.annotations },
346
348
  provenance
347
349
  };
@@ -433,6 +435,9 @@ function generateJsonSchemaFromIR(ir, options) {
433
435
  const ctx = makeContext(options);
434
436
  for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
435
437
  ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
438
+ if (typeDef.constraints && typeDef.constraints.length > 0) {
439
+ applyConstraints(ctx.defs[name], typeDef.constraints, ctx);
440
+ }
436
441
  if (typeDef.annotations && typeDef.annotations.length > 0) {
437
442
  applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);
438
443
  }
@@ -601,7 +606,9 @@ function generateTypeNode(type, ctx) {
601
606
  }
602
607
  }
603
608
  function generatePrimitiveType(type) {
604
- return { type: type.primitiveKind };
609
+ return {
610
+ type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
611
+ };
605
612
  }
606
613
  function generateEnumType(type) {
607
614
  const hasDisplayNames = type.members.some((m) => m.displayName !== void 0);
@@ -774,7 +781,7 @@ function applyAnnotations(schema, annotations, ctx) {
774
781
  case "deprecated":
775
782
  schema.deprecated = true;
776
783
  if (annotation.message !== void 0 && annotation.message !== "") {
777
- schema["x-formspec-deprecation-description"] = annotation.message;
784
+ schema[`${ctx.vendorPrefix}-deprecation-description`] = annotation.message;
778
785
  }
779
786
  break;
780
787
  case "placeholder":
@@ -1282,83 +1289,6 @@ var init_schema2 = __esm({
1282
1289
  }
1283
1290
  });
1284
1291
 
1285
- // src/analyzer/program.ts
1286
- import * as ts from "typescript";
1287
- import * as path from "path";
1288
- function createProgramContext(filePath) {
1289
- const absolutePath = path.resolve(filePath);
1290
- const fileDir = path.dirname(absolutePath);
1291
- const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
1292
- let compilerOptions;
1293
- let fileNames;
1294
- if (configPath) {
1295
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
1296
- if (configFile.error) {
1297
- throw new Error(
1298
- `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
1299
- );
1300
- }
1301
- const parsed = ts.parseJsonConfigFileContent(
1302
- configFile.config,
1303
- ts.sys,
1304
- path.dirname(configPath)
1305
- );
1306
- if (parsed.errors.length > 0) {
1307
- const errorMessages = parsed.errors.map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
1308
- throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
1309
- }
1310
- compilerOptions = parsed.options;
1311
- fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
1312
- } else {
1313
- compilerOptions = {
1314
- target: ts.ScriptTarget.ES2022,
1315
- module: ts.ModuleKind.NodeNext,
1316
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
1317
- strict: true,
1318
- skipLibCheck: true,
1319
- declaration: true
1320
- };
1321
- fileNames = [absolutePath];
1322
- }
1323
- const program = ts.createProgram(fileNames, compilerOptions);
1324
- const sourceFile = program.getSourceFile(absolutePath);
1325
- if (!sourceFile) {
1326
- throw new Error(`Could not find source file: ${absolutePath}`);
1327
- }
1328
- return {
1329
- program,
1330
- checker: program.getTypeChecker(),
1331
- sourceFile
1332
- };
1333
- }
1334
- function findNodeByName(sourceFile, name, predicate, getName) {
1335
- let result = null;
1336
- function visit(node) {
1337
- if (result) return;
1338
- if (predicate(node) && getName(node) === name) {
1339
- result = node;
1340
- return;
1341
- }
1342
- ts.forEachChild(node, visit);
1343
- }
1344
- visit(sourceFile);
1345
- return result;
1346
- }
1347
- function findClassByName(sourceFile, className) {
1348
- return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
1349
- }
1350
- function findInterfaceByName(sourceFile, interfaceName) {
1351
- return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
1352
- }
1353
- function findTypeAliasByName(sourceFile, aliasName) {
1354
- return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
1355
- }
1356
- var init_program = __esm({
1357
- "src/analyzer/program.ts"() {
1358
- "use strict";
1359
- }
1360
- });
1361
-
1362
1292
  // src/analyzer/json-utils.ts
1363
1293
  function tryParseJson(text) {
1364
1294
  try {
@@ -1374,7 +1304,7 @@ var init_json_utils = __esm({
1374
1304
  });
1375
1305
 
1376
1306
  // src/analyzer/tsdoc-parser.ts
1377
- import * as ts2 from "typescript";
1307
+ import * as ts from "typescript";
1378
1308
  import {
1379
1309
  TSDocParser,
1380
1310
  TSDocConfiguration,
@@ -1446,10 +1376,10 @@ function parseTSDocTags(node, file = "", options) {
1446
1376
  let placeholderProvenance;
1447
1377
  const sourceFile = node.getSourceFile();
1448
1378
  const sourceText = sourceFile.getFullText();
1449
- const commentRanges = ts2.getLeadingCommentRanges(sourceText, node.getFullStart());
1379
+ const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
1450
1380
  if (commentRanges) {
1451
1381
  for (const range of commentRanges) {
1452
- if (range.kind !== ts2.SyntaxKind.MultiLineCommentTrivia) {
1382
+ if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
1453
1383
  continue;
1454
1384
  }
1455
1385
  const commentText = sourceText.substring(range.pos, range.end);
@@ -1467,26 +1397,31 @@ function parseTSDocTags(node, file = "", options) {
1467
1397
  const text2 = extractBlockText(block).trim();
1468
1398
  if (text2 === "") continue;
1469
1399
  const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
1470
- if (tagName === "displayName") {
1471
- if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
1472
- displayName = text2;
1473
- displayNameProvenance = provenance2;
1474
- }
1475
- } else if (tagName === "format") {
1476
- annotations.push({
1477
- kind: "annotation",
1478
- annotationKind: "format",
1479
- value: text2,
1480
- provenance: provenance2
1481
- });
1482
- } else {
1483
- if (tagName === "description" && description === void 0) {
1400
+ switch (tagName) {
1401
+ case "displayName":
1402
+ if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
1403
+ displayName = text2;
1404
+ displayNameProvenance = provenance2;
1405
+ }
1406
+ break;
1407
+ case "format":
1408
+ annotations.push({
1409
+ kind: "annotation",
1410
+ annotationKind: "format",
1411
+ value: text2,
1412
+ provenance: provenance2
1413
+ });
1414
+ break;
1415
+ case "description":
1484
1416
  description = text2;
1485
1417
  descriptionProvenance = provenance2;
1486
- } else if (tagName === "placeholder" && placeholder === void 0) {
1487
- placeholder = text2;
1488
- placeholderProvenance = provenance2;
1489
- }
1418
+ break;
1419
+ case "placeholder":
1420
+ if (placeholder === void 0) {
1421
+ placeholder = text2;
1422
+ placeholderProvenance = provenance2;
1423
+ }
1424
+ break;
1490
1425
  }
1491
1426
  continue;
1492
1427
  }
@@ -1516,6 +1451,13 @@ function parseTSDocTags(node, file = "", options) {
1516
1451
  descriptionProvenance = provenanceForComment(range, sourceFile, file, "remarks");
1517
1452
  }
1518
1453
  }
1454
+ if (description === void 0) {
1455
+ const summary = extractPlainText(docComment.summarySection).trim();
1456
+ if (summary !== "") {
1457
+ description = summary;
1458
+ descriptionProvenance = provenanceForComment(range, sourceFile, file, "summary");
1459
+ }
1460
+ }
1519
1461
  }
1520
1462
  }
1521
1463
  if (displayName !== void 0 && displayNameProvenance !== void 0) {
@@ -1542,7 +1484,7 @@ function parseTSDocTags(node, file = "", options) {
1542
1484
  provenance: placeholderProvenance
1543
1485
  });
1544
1486
  }
1545
- const jsDocTagsAll = ts2.getJSDocTags(node);
1487
+ const jsDocTagsAll = ts.getJSDocTags(node);
1546
1488
  for (const tag of jsDocTagsAll) {
1547
1489
  const tagName = normalizeConstraintTagName(tag.tagName.text);
1548
1490
  if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
@@ -1565,7 +1507,7 @@ function parseTSDocTags(node, file = "", options) {
1565
1507
  function extractDisplayNameMetadata(node) {
1566
1508
  let displayName;
1567
1509
  const memberDisplayNames = /* @__PURE__ */ new Map();
1568
- for (const tag of ts2.getJSDocTags(node)) {
1510
+ for (const tag of ts.getJSDocTags(node)) {
1569
1511
  const tagName = normalizeConstraintTagName(tag.tagName.text);
1570
1512
  if (tagName !== "displayName") continue;
1571
1513
  const commentText = getTagCommentText(tag);
@@ -1586,11 +1528,11 @@ function extractDisplayNameMetadata(node) {
1586
1528
  }
1587
1529
  function extractPathTarget(text) {
1588
1530
  const trimmed = text.trimStart();
1589
- const match = /^:([a-zA-Z_]\w*)\s+([\s\S]*)$/.exec(trimmed);
1590
- if (!match?.[1] || !match[2]) return null;
1531
+ const match = /^:([a-zA-Z_]\w*)(?:\s+([\s\S]*))?$/.exec(trimmed);
1532
+ if (!match?.[1]) return null;
1591
1533
  return {
1592
1534
  path: { segments: [match[1]] },
1593
- remainingText: match[2]
1535
+ remainingText: match[2] ?? ""
1594
1536
  };
1595
1537
  }
1596
1538
  function extractBlockText(block) {
@@ -1853,7 +1795,7 @@ function getTagCommentText(tag) {
1853
1795
  if (typeof tag.comment === "string") {
1854
1796
  return tag.comment;
1855
1797
  }
1856
- return ts2.getTextOfJSDocComment(tag.comment);
1798
+ return ts.getTextOfJSDocComment(tag.comment);
1857
1799
  }
1858
1800
  var NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT, parserCache;
1859
1801
  var init_tsdoc_parser = __esm({
@@ -1879,7 +1821,7 @@ var init_tsdoc_parser = __esm({
1879
1821
  });
1880
1822
 
1881
1823
  // src/analyzer/jsdoc-constraints.ts
1882
- import * as ts3 from "typescript";
1824
+ import * as ts2 from "typescript";
1883
1825
  function extractJSDocConstraintNodes(node, file = "", options) {
1884
1826
  const result = parseTSDocTags(node, file, options);
1885
1827
  return [...result.constraints];
@@ -1891,18 +1833,18 @@ function extractJSDocAnnotationNodes(node, file = "", options) {
1891
1833
  function extractDefaultValueAnnotation(initializer, file = "") {
1892
1834
  if (!initializer) return null;
1893
1835
  let value;
1894
- if (ts3.isStringLiteral(initializer)) {
1836
+ if (ts2.isStringLiteral(initializer)) {
1895
1837
  value = initializer.text;
1896
- } else if (ts3.isNumericLiteral(initializer)) {
1838
+ } else if (ts2.isNumericLiteral(initializer)) {
1897
1839
  value = Number(initializer.text);
1898
- } else if (initializer.kind === ts3.SyntaxKind.TrueKeyword) {
1840
+ } else if (initializer.kind === ts2.SyntaxKind.TrueKeyword) {
1899
1841
  value = true;
1900
- } else if (initializer.kind === ts3.SyntaxKind.FalseKeyword) {
1842
+ } else if (initializer.kind === ts2.SyntaxKind.FalseKeyword) {
1901
1843
  value = false;
1902
- } else if (initializer.kind === ts3.SyntaxKind.NullKeyword) {
1844
+ } else if (initializer.kind === ts2.SyntaxKind.NullKeyword) {
1903
1845
  value = null;
1904
- } else if (ts3.isPrefixUnaryExpression(initializer)) {
1905
- if (initializer.operator === ts3.SyntaxKind.MinusToken && ts3.isNumericLiteral(initializer.operand)) {
1846
+ } else if (ts2.isPrefixUnaryExpression(initializer)) {
1847
+ if (initializer.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(initializer.operand)) {
1906
1848
  value = -Number(initializer.operand.text);
1907
1849
  }
1908
1850
  }
@@ -1929,12 +1871,12 @@ var init_jsdoc_constraints = __esm({
1929
1871
  });
1930
1872
 
1931
1873
  // src/analyzer/class-analyzer.ts
1932
- import * as ts4 from "typescript";
1874
+ import * as ts3 from "typescript";
1933
1875
  function isObjectType(type) {
1934
- return !!(type.flags & ts4.TypeFlags.Object);
1876
+ return !!(type.flags & ts3.TypeFlags.Object);
1935
1877
  }
1936
1878
  function isTypeReference(type) {
1937
- return !!(type.flags & ts4.TypeFlags.Object) && !!(type.objectFlags & ts4.ObjectFlags.Reference);
1879
+ return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
1938
1880
  }
1939
1881
  function makeParseOptions(extensionRegistry, fieldType) {
1940
1882
  if (extensionRegistry === void 0 && fieldType === void 0) {
@@ -1959,7 +1901,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1959
1901
  const instanceMethods = [];
1960
1902
  const staticMethods = [];
1961
1903
  for (const member of classDecl.members) {
1962
- if (ts4.isPropertyDeclaration(member)) {
1904
+ if (ts3.isPropertyDeclaration(member)) {
1963
1905
  const fieldNode = analyzeFieldToIR(
1964
1906
  member,
1965
1907
  checker,
@@ -1972,10 +1914,10 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1972
1914
  fields.push(fieldNode);
1973
1915
  fieldLayouts.push({});
1974
1916
  }
1975
- } else if (ts4.isMethodDeclaration(member)) {
1917
+ } else if (ts3.isMethodDeclaration(member)) {
1976
1918
  const methodInfo = analyzeMethod(member, checker);
1977
1919
  if (methodInfo) {
1978
- const isStatic = member.modifiers?.some((m) => m.kind === ts4.SyntaxKind.StaticKeyword);
1920
+ const isStatic = member.modifiers?.some((m) => m.kind === ts3.SyntaxKind.StaticKeyword);
1979
1921
  if (isStatic) {
1980
1922
  staticMethods.push(methodInfo);
1981
1923
  } else {
@@ -2005,7 +1947,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
2005
1947
  );
2006
1948
  const visiting = /* @__PURE__ */ new Set();
2007
1949
  for (const member of interfaceDecl.members) {
2008
- if (ts4.isPropertySignature(member)) {
1950
+ if (ts3.isPropertySignature(member)) {
2009
1951
  const fieldNode = analyzeInterfacePropertyToIR(
2010
1952
  member,
2011
1953
  checker,
@@ -2031,10 +1973,10 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
2031
1973
  };
2032
1974
  }
2033
1975
  function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
2034
- if (!ts4.isTypeLiteralNode(typeAlias.type)) {
1976
+ if (!ts3.isTypeLiteralNode(typeAlias.type)) {
2035
1977
  const sourceFile = typeAlias.getSourceFile();
2036
1978
  const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
2037
- const kindDesc = ts4.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1979
+ const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
2038
1980
  return {
2039
1981
  ok: false,
2040
1982
  error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
@@ -2050,7 +1992,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
2050
1992
  );
2051
1993
  const visiting = /* @__PURE__ */ new Set();
2052
1994
  for (const member of typeAlias.type.members) {
2053
- if (ts4.isPropertySignature(member)) {
1995
+ if (ts3.isPropertySignature(member)) {
2054
1996
  const fieldNode = analyzeInterfacePropertyToIR(
2055
1997
  member,
2056
1998
  checker,
@@ -2078,7 +2020,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
2078
2020
  };
2079
2021
  }
2080
2022
  function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
2081
- if (!ts4.isIdentifier(prop.name)) {
2023
+ if (!ts3.isIdentifier(prop.name)) {
2082
2024
  return null;
2083
2025
  }
2084
2026
  const name = prop.name.text;
@@ -2095,12 +2037,14 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
2095
2037
  extensionRegistry
2096
2038
  );
2097
2039
  const constraints = [];
2098
- if (prop.type) {
2040
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
2099
2041
  constraints.push(
2100
2042
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
2101
2043
  );
2102
2044
  }
2103
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
2045
+ constraints.push(
2046
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
2047
+ );
2104
2048
  let annotations = [];
2105
2049
  annotations.push(
2106
2050
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -2121,7 +2065,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
2121
2065
  };
2122
2066
  }
2123
2067
  function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
2124
- if (!ts4.isIdentifier(prop.name)) {
2068
+ if (!ts3.isIdentifier(prop.name)) {
2125
2069
  return null;
2126
2070
  }
2127
2071
  const name = prop.name.text;
@@ -2138,12 +2082,14 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
2138
2082
  extensionRegistry
2139
2083
  );
2140
2084
  const constraints = [];
2141
- if (prop.type) {
2085
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
2142
2086
  constraints.push(
2143
2087
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
2144
2088
  );
2145
2089
  }
2146
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
2090
+ constraints.push(
2091
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
2092
+ );
2147
2093
  let annotations = [];
2148
2094
  annotations.push(
2149
2095
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -2232,7 +2178,7 @@ function resolveRegisteredCustomType(sourceNode, extensionRegistry, checker) {
2232
2178
  return resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker);
2233
2179
  }
2234
2180
  function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker) {
2235
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2181
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2236
2182
  return resolveRegisteredCustomTypeFromTypeNode(typeNode.type, extensionRegistry, checker);
2237
2183
  }
2238
2184
  const typeName = getTypeNodeRegistrationName(typeNode);
@@ -2247,8 +2193,8 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
2247
2193
  payload: null
2248
2194
  };
2249
2195
  }
2250
- if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
2251
- const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts4.isTypeAliasDeclaration);
2196
+ if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
2197
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2252
2198
  if (aliasDecl !== void 0) {
2253
2199
  return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
2254
2200
  }
@@ -2256,22 +2202,22 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
2256
2202
  return null;
2257
2203
  }
2258
2204
  function extractTypeNodeFromSource(sourceNode) {
2259
- if (ts4.isPropertyDeclaration(sourceNode) || ts4.isPropertySignature(sourceNode) || ts4.isParameter(sourceNode) || ts4.isTypeAliasDeclaration(sourceNode)) {
2205
+ if (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode) || ts3.isTypeAliasDeclaration(sourceNode)) {
2260
2206
  return sourceNode.type;
2261
2207
  }
2262
- if (ts4.isTypeNode(sourceNode)) {
2208
+ if (ts3.isTypeNode(sourceNode)) {
2263
2209
  return sourceNode;
2264
2210
  }
2265
2211
  return void 0;
2266
2212
  }
2267
2213
  function getTypeNodeRegistrationName(typeNode) {
2268
- if (ts4.isTypeReferenceNode(typeNode)) {
2269
- return ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
2214
+ if (ts3.isTypeReferenceNode(typeNode)) {
2215
+ return ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
2270
2216
  }
2271
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2217
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2272
2218
  return getTypeNodeRegistrationName(typeNode.type);
2273
2219
  }
2274
- if (typeNode.kind === ts4.SyntaxKind.BigIntKeyword || typeNode.kind === ts4.SyntaxKind.StringKeyword || typeNode.kind === ts4.SyntaxKind.NumberKeyword || typeNode.kind === ts4.SyntaxKind.BooleanKeyword) {
2220
+ if (typeNode.kind === ts3.SyntaxKind.BigIntKeyword || typeNode.kind === ts3.SyntaxKind.StringKeyword || typeNode.kind === ts3.SyntaxKind.NumberKeyword || typeNode.kind === ts3.SyntaxKind.BooleanKeyword) {
2275
2221
  return typeNode.getText();
2276
2222
  }
2277
2223
  return null;
@@ -2281,19 +2227,34 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2281
2227
  if (customType) {
2282
2228
  return customType;
2283
2229
  }
2284
- if (type.flags & ts4.TypeFlags.String) {
2230
+ const primitiveAlias = tryResolveNamedPrimitiveAlias(
2231
+ type,
2232
+ checker,
2233
+ file,
2234
+ typeRegistry,
2235
+ visiting,
2236
+ sourceNode,
2237
+ extensionRegistry
2238
+ );
2239
+ if (primitiveAlias) {
2240
+ return primitiveAlias;
2241
+ }
2242
+ if (type.flags & ts3.TypeFlags.String) {
2285
2243
  return { kind: "primitive", primitiveKind: "string" };
2286
2244
  }
2287
- if (type.flags & ts4.TypeFlags.Number) {
2245
+ if (type.flags & ts3.TypeFlags.Number) {
2288
2246
  return { kind: "primitive", primitiveKind: "number" };
2289
2247
  }
2290
- if (type.flags & ts4.TypeFlags.Boolean) {
2248
+ if (type.flags & (ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral)) {
2249
+ return { kind: "primitive", primitiveKind: "bigint" };
2250
+ }
2251
+ if (type.flags & ts3.TypeFlags.Boolean) {
2291
2252
  return { kind: "primitive", primitiveKind: "boolean" };
2292
2253
  }
2293
- if (type.flags & ts4.TypeFlags.Null) {
2254
+ if (type.flags & ts3.TypeFlags.Null) {
2294
2255
  return { kind: "primitive", primitiveKind: "null" };
2295
2256
  }
2296
- if (type.flags & ts4.TypeFlags.Undefined) {
2257
+ if (type.flags & ts3.TypeFlags.Undefined) {
2297
2258
  return { kind: "primitive", primitiveKind: "null" };
2298
2259
  }
2299
2260
  if (type.isStringLiteral()) {
@@ -2335,6 +2296,75 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
2335
2296
  }
2336
2297
  return { kind: "primitive", primitiveKind: "string" };
2337
2298
  }
2299
+ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
2300
+ if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
2301
+ return null;
2302
+ }
2303
+ const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
2304
+ if (!aliasDecl) {
2305
+ return null;
2306
+ }
2307
+ const aliasName = aliasDecl.name.text;
2308
+ if (!typeRegistry[aliasName]) {
2309
+ const aliasType = checker.getTypeFromTypeNode(aliasDecl.type);
2310
+ const constraints = [
2311
+ ...extractJSDocConstraintNodes(aliasDecl, file, makeParseOptions(extensionRegistry)),
2312
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry)
2313
+ ];
2314
+ const annotations = extractJSDocAnnotationNodes(
2315
+ aliasDecl,
2316
+ file,
2317
+ makeParseOptions(extensionRegistry)
2318
+ );
2319
+ typeRegistry[aliasName] = {
2320
+ name: aliasName,
2321
+ type: resolveAliasedPrimitiveTarget(
2322
+ aliasType,
2323
+ checker,
2324
+ file,
2325
+ typeRegistry,
2326
+ visiting,
2327
+ extensionRegistry
2328
+ ),
2329
+ ...constraints.length > 0 && { constraints },
2330
+ ...annotations.length > 0 && { annotations },
2331
+ provenance: provenanceForDeclaration(aliasDecl, file)
2332
+ };
2333
+ }
2334
+ return { kind: "reference", name: aliasName, typeArguments: [] };
2335
+ }
2336
+ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
2337
+ const typeNode = sourceNode && (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode)) ? sourceNode.type : void 0;
2338
+ if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
2339
+ return void 0;
2340
+ }
2341
+ return checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2342
+ }
2343
+ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
2344
+ if (!ts3.isTypeReferenceNode(typeNode)) {
2345
+ return false;
2346
+ }
2347
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
2348
+ if (!aliasDecl) {
2349
+ return false;
2350
+ }
2351
+ const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
2352
+ return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
2353
+ }
2354
+ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, extensionRegistry) {
2355
+ const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
2356
+ if (nestedAliasDecl !== void 0) {
2357
+ return resolveAliasedPrimitiveTarget(
2358
+ checker.getTypeFromTypeNode(nestedAliasDecl.type),
2359
+ checker,
2360
+ file,
2361
+ typeRegistry,
2362
+ visiting,
2363
+ extensionRegistry
2364
+ );
2365
+ }
2366
+ return resolveTypeNode(type, checker, file, typeRegistry, visiting, void 0, extensionRegistry);
2367
+ }
2338
2368
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
2339
2369
  const typeName = getNamedTypeName(type);
2340
2370
  const namedDecl = getNamedTypeDeclaration(type);
@@ -2347,13 +2377,13 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
2347
2377
  (memberTypeNode) => !isNullishTypeNode(resolveAliasedTypeNode(memberTypeNode, checker))
2348
2378
  );
2349
2379
  const nonNullTypes = allTypes.filter(
2350
- (memberType) => !(memberType.flags & (ts4.TypeFlags.Null | ts4.TypeFlags.Undefined))
2380
+ (memberType) => !(memberType.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
2351
2381
  );
2352
2382
  const nonNullMembers = nonNullTypes.map((memberType, index) => ({
2353
2383
  memberType,
2354
2384
  sourceNode: nonNullSourceNodes.length === nonNullTypes.length ? nonNullSourceNodes[index] : void 0
2355
2385
  }));
2356
- const hasNull = allTypes.some((t) => t.flags & ts4.TypeFlags.Null);
2386
+ const hasNull = allTypes.some((t) => t.flags & ts3.TypeFlags.Null);
2357
2387
  const memberDisplayNames = /* @__PURE__ */ new Map();
2358
2388
  if (namedDecl) {
2359
2389
  for (const [value, label] of extractDisplayNameMetadata(namedDecl).memberDisplayNames) {
@@ -2382,7 +2412,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
2382
2412
  const displayName = memberDisplayNames.get(String(value));
2383
2413
  return displayName !== void 0 ? { value, displayName } : { value };
2384
2414
  });
2385
- const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts4.TypeFlags.BooleanLiteral);
2415
+ const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts3.TypeFlags.BooleanLiteral);
2386
2416
  if (isBooleanUnion2) {
2387
2417
  const boolNode = { kind: "primitive", primitiveKind: "boolean" };
2388
2418
  const result = hasNull ? {
@@ -2468,7 +2498,7 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, exten
2468
2498
  if (type.getProperties().length > 0) {
2469
2499
  return null;
2470
2500
  }
2471
- const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
2501
+ const indexInfo = checker.getIndexInfoOfType(type, ts3.IndexKind.String);
2472
2502
  if (!indexInfo) {
2473
2503
  return null;
2474
2504
  }
@@ -2579,7 +2609,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
2579
2609
  const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
2580
2610
  if (!declaration) continue;
2581
2611
  const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
2582
- const optional = !!(prop.flags & ts4.SymbolFlags.Optional);
2612
+ const optional = !!(prop.flags & ts3.SymbolFlags.Optional);
2583
2613
  const propTypeNode = resolveTypeNode(
2584
2614
  propType,
2585
2615
  checker,
@@ -2624,11 +2654,11 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2624
2654
  for (const symbol of symbols) {
2625
2655
  const declarations = symbol.declarations;
2626
2656
  if (!declarations) continue;
2627
- const classDecl = declarations.find(ts4.isClassDeclaration);
2657
+ const classDecl = declarations.find(ts3.isClassDeclaration);
2628
2658
  if (classDecl) {
2629
2659
  const map = /* @__PURE__ */ new Map();
2630
2660
  for (const member of classDecl.members) {
2631
- if (ts4.isPropertyDeclaration(member) && ts4.isIdentifier(member.name)) {
2661
+ if (ts3.isPropertyDeclaration(member) && ts3.isIdentifier(member.name)) {
2632
2662
  const fieldNode = analyzeFieldToIR(
2633
2663
  member,
2634
2664
  checker,
@@ -2648,7 +2678,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2648
2678
  }
2649
2679
  return map;
2650
2680
  }
2651
- const interfaceDecl = declarations.find(ts4.isInterfaceDeclaration);
2681
+ const interfaceDecl = declarations.find(ts3.isInterfaceDeclaration);
2652
2682
  if (interfaceDecl) {
2653
2683
  return buildFieldNodeInfoMap(
2654
2684
  interfaceDecl.members,
@@ -2659,8 +2689,8 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
2659
2689
  extensionRegistry
2660
2690
  );
2661
2691
  }
2662
- const typeAliasDecl = declarations.find(ts4.isTypeAliasDeclaration);
2663
- if (typeAliasDecl && ts4.isTypeLiteralNode(typeAliasDecl.type)) {
2692
+ const typeAliasDecl = declarations.find(ts3.isTypeAliasDeclaration);
2693
+ if (typeAliasDecl && ts3.isTypeLiteralNode(typeAliasDecl.type)) {
2664
2694
  return buildFieldNodeInfoMap(
2665
2695
  typeAliasDecl.type.members,
2666
2696
  checker,
@@ -2679,10 +2709,10 @@ function extractArrayElementTypeNode(sourceNode, checker) {
2679
2709
  return void 0;
2680
2710
  }
2681
2711
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
2682
- if (ts4.isArrayTypeNode(resolvedTypeNode)) {
2712
+ if (ts3.isArrayTypeNode(resolvedTypeNode)) {
2683
2713
  return resolvedTypeNode.elementType;
2684
2714
  }
2685
- if (ts4.isTypeReferenceNode(resolvedTypeNode) && ts4.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
2715
+ if (ts3.isTypeReferenceNode(resolvedTypeNode) && ts3.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
2686
2716
  return resolvedTypeNode.typeArguments[0];
2687
2717
  }
2688
2718
  return void 0;
@@ -2693,17 +2723,17 @@ function extractUnionMemberTypeNodes(sourceNode, checker) {
2693
2723
  return [];
2694
2724
  }
2695
2725
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
2696
- return ts4.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
2726
+ return ts3.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
2697
2727
  }
2698
2728
  function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
2699
- if (ts4.isParenthesizedTypeNode(typeNode)) {
2729
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
2700
2730
  return resolveAliasedTypeNode(typeNode.type, checker, visited);
2701
2731
  }
2702
- if (!ts4.isTypeReferenceNode(typeNode) || !ts4.isIdentifier(typeNode.typeName)) {
2732
+ if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
2703
2733
  return typeNode;
2704
2734
  }
2705
2735
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
2706
- const aliasDecl = symbol?.declarations?.find(ts4.isTypeAliasDeclaration);
2736
+ const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
2707
2737
  if (aliasDecl === void 0 || visited.has(aliasDecl)) {
2708
2738
  return typeNode;
2709
2739
  }
@@ -2711,15 +2741,15 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
2711
2741
  return resolveAliasedTypeNode(aliasDecl.type, checker, visited);
2712
2742
  }
2713
2743
  function isNullishTypeNode(typeNode) {
2714
- if (typeNode.kind === ts4.SyntaxKind.NullKeyword || typeNode.kind === ts4.SyntaxKind.UndefinedKeyword) {
2744
+ if (typeNode.kind === ts3.SyntaxKind.NullKeyword || typeNode.kind === ts3.SyntaxKind.UndefinedKeyword) {
2715
2745
  return true;
2716
2746
  }
2717
- return ts4.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts4.SyntaxKind.NullKeyword || typeNode.literal.kind === ts4.SyntaxKind.UndefinedKeyword);
2747
+ return ts3.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts3.SyntaxKind.NullKeyword || typeNode.literal.kind === ts3.SyntaxKind.UndefinedKeyword);
2718
2748
  }
2719
2749
  function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, extensionRegistry) {
2720
2750
  const map = /* @__PURE__ */ new Map();
2721
2751
  for (const member of members) {
2722
- if (ts4.isPropertySignature(member)) {
2752
+ if (ts3.isPropertySignature(member)) {
2723
2753
  const fieldNode = analyzeInterfacePropertyToIR(
2724
2754
  member,
2725
2755
  checker,
@@ -2740,7 +2770,7 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, e
2740
2770
  return map;
2741
2771
  }
2742
2772
  function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegistry, depth = 0) {
2743
- if (!ts4.isTypeReferenceNode(typeNode)) return [];
2773
+ if (!ts3.isTypeReferenceNode(typeNode)) return [];
2744
2774
  if (depth >= MAX_ALIAS_CHAIN_DEPTH) {
2745
2775
  const aliasName = typeNode.typeName.getText();
2746
2776
  throw new Error(
@@ -2749,9 +2779,9 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
2749
2779
  }
2750
2780
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
2751
2781
  if (!symbol?.declarations) return [];
2752
- const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
2782
+ const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
2753
2783
  if (!aliasDecl) return [];
2754
- if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
2784
+ if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
2755
2785
  const aliasFieldType = resolveTypeNode(
2756
2786
  checker.getTypeAtLocation(aliasDecl.type),
2757
2787
  checker,
@@ -2767,13 +2797,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
2767
2797
  makeParseOptions(extensionRegistry, aliasFieldType)
2768
2798
  );
2769
2799
  constraints.push(
2770
- ...extractTypeAliasConstraintNodes(
2771
- aliasDecl.type,
2772
- checker,
2773
- file,
2774
- extensionRegistry,
2775
- depth + 1
2776
- )
2800
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry, depth + 1)
2777
2801
  );
2778
2802
  return constraints;
2779
2803
  }
@@ -2800,14 +2824,14 @@ function getNamedTypeName(type) {
2800
2824
  const symbol = type.getSymbol();
2801
2825
  if (symbol?.declarations) {
2802
2826
  const decl = symbol.declarations[0];
2803
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
2804
- const name = ts4.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
2827
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
2828
+ const name = ts3.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
2805
2829
  if (name) return name;
2806
2830
  }
2807
2831
  }
2808
2832
  const aliasSymbol = type.aliasSymbol;
2809
2833
  if (aliasSymbol?.declarations) {
2810
- const aliasDecl = aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
2834
+ const aliasDecl = aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
2811
2835
  if (aliasDecl) {
2812
2836
  return aliasDecl.name.text;
2813
2837
  }
@@ -2818,24 +2842,24 @@ function getNamedTypeDeclaration(type) {
2818
2842
  const symbol = type.getSymbol();
2819
2843
  if (symbol?.declarations) {
2820
2844
  const decl = symbol.declarations[0];
2821
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
2845
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
2822
2846
  return decl;
2823
2847
  }
2824
2848
  }
2825
2849
  const aliasSymbol = type.aliasSymbol;
2826
2850
  if (aliasSymbol?.declarations) {
2827
- return aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
2851
+ return aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
2828
2852
  }
2829
2853
  return void 0;
2830
2854
  }
2831
2855
  function analyzeMethod(method, checker) {
2832
- if (!ts4.isIdentifier(method.name)) {
2856
+ if (!ts3.isIdentifier(method.name)) {
2833
2857
  return null;
2834
2858
  }
2835
2859
  const name = method.name.text;
2836
2860
  const parameters = [];
2837
2861
  for (const param of method.parameters) {
2838
- if (ts4.isIdentifier(param.name)) {
2862
+ if (ts3.isIdentifier(param.name)) {
2839
2863
  const paramInfo = analyzeParameter(param, checker);
2840
2864
  parameters.push(paramInfo);
2841
2865
  }
@@ -2846,7 +2870,7 @@ function analyzeMethod(method, checker) {
2846
2870
  return { name, parameters, returnTypeNode, returnType };
2847
2871
  }
2848
2872
  function analyzeParameter(param, checker) {
2849
- const name = ts4.isIdentifier(param.name) ? param.name.text : "param";
2873
+ const name = ts3.isIdentifier(param.name) ? param.name.text : "param";
2850
2874
  const typeNode = param.type;
2851
2875
  const type = checker.getTypeAtLocation(param);
2852
2876
  const formSpecExportName = detectFormSpecReference(typeNode);
@@ -2855,15 +2879,15 @@ function analyzeParameter(param, checker) {
2855
2879
  }
2856
2880
  function detectFormSpecReference(typeNode) {
2857
2881
  if (!typeNode) return null;
2858
- if (!ts4.isTypeReferenceNode(typeNode)) return null;
2859
- const typeName = ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts4.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
2882
+ if (!ts3.isTypeReferenceNode(typeNode)) return null;
2883
+ const typeName = ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts3.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
2860
2884
  if (typeName !== "InferSchema" && typeName !== "InferFormSchema") return null;
2861
2885
  const typeArg = typeNode.typeArguments?.[0];
2862
- if (!typeArg || !ts4.isTypeQueryNode(typeArg)) return null;
2863
- if (ts4.isIdentifier(typeArg.exprName)) {
2886
+ if (!typeArg || !ts3.isTypeQueryNode(typeArg)) return null;
2887
+ if (ts3.isIdentifier(typeArg.exprName)) {
2864
2888
  return typeArg.exprName.text;
2865
2889
  }
2866
- if (ts4.isQualifiedName(typeArg.exprName)) {
2890
+ if (ts3.isQualifiedName(typeArg.exprName)) {
2867
2891
  return typeArg.exprName.right.text;
2868
2892
  }
2869
2893
  return null;
@@ -2883,14 +2907,939 @@ var init_class_analyzer = __esm({
2883
2907
  }
2884
2908
  });
2885
2909
 
2910
+ // src/analyzer/program.ts
2911
+ import * as ts4 from "typescript";
2912
+ import * as path from "path";
2913
+ function createProgramContext(filePath) {
2914
+ const absolutePath = path.resolve(filePath);
2915
+ const fileDir = path.dirname(absolutePath);
2916
+ const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
2917
+ let compilerOptions;
2918
+ let fileNames;
2919
+ if (configPath) {
2920
+ const configFile = ts4.readConfigFile(configPath, ts4.sys.readFile.bind(ts4.sys));
2921
+ if (configFile.error) {
2922
+ throw new Error(
2923
+ `Error reading tsconfig.json: ${ts4.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
2924
+ );
2925
+ }
2926
+ const parsed = ts4.parseJsonConfigFileContent(
2927
+ configFile.config,
2928
+ ts4.sys,
2929
+ path.dirname(configPath)
2930
+ );
2931
+ if (parsed.errors.length > 0) {
2932
+ const errorMessages = parsed.errors.map((e) => ts4.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
2933
+ throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
2934
+ }
2935
+ compilerOptions = parsed.options;
2936
+ fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
2937
+ } else {
2938
+ compilerOptions = {
2939
+ target: ts4.ScriptTarget.ES2022,
2940
+ module: ts4.ModuleKind.NodeNext,
2941
+ moduleResolution: ts4.ModuleResolutionKind.NodeNext,
2942
+ strict: true,
2943
+ skipLibCheck: true,
2944
+ declaration: true
2945
+ };
2946
+ fileNames = [absolutePath];
2947
+ }
2948
+ const program = ts4.createProgram(fileNames, compilerOptions);
2949
+ const sourceFile = program.getSourceFile(absolutePath);
2950
+ if (!sourceFile) {
2951
+ throw new Error(`Could not find source file: ${absolutePath}`);
2952
+ }
2953
+ return {
2954
+ program,
2955
+ checker: program.getTypeChecker(),
2956
+ sourceFile
2957
+ };
2958
+ }
2959
+ function findNodeByName(sourceFile, name, predicate, getName) {
2960
+ let result = null;
2961
+ function visit(node) {
2962
+ if (result) return;
2963
+ if (predicate(node) && getName(node) === name) {
2964
+ result = node;
2965
+ return;
2966
+ }
2967
+ ts4.forEachChild(node, visit);
2968
+ }
2969
+ visit(sourceFile);
2970
+ return result;
2971
+ }
2972
+ function findClassByName(sourceFile, className) {
2973
+ return findNodeByName(sourceFile, className, ts4.isClassDeclaration, (n) => n.name?.text);
2974
+ }
2975
+ function findInterfaceByName(sourceFile, interfaceName) {
2976
+ return findNodeByName(sourceFile, interfaceName, ts4.isInterfaceDeclaration, (n) => n.name.text);
2977
+ }
2978
+ function findTypeAliasByName(sourceFile, aliasName) {
2979
+ return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
2980
+ }
2981
+ function analyzeNamedTypeToIR(filePath, typeName, extensionRegistry) {
2982
+ const ctx = createProgramContext(filePath);
2983
+ const classDecl = findClassByName(ctx.sourceFile, typeName);
2984
+ if (classDecl !== null) {
2985
+ return analyzeClassToIR(classDecl, ctx.checker, filePath, extensionRegistry);
2986
+ }
2987
+ const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
2988
+ if (interfaceDecl !== null) {
2989
+ return analyzeInterfaceToIR(interfaceDecl, ctx.checker, filePath, extensionRegistry);
2990
+ }
2991
+ const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
2992
+ if (typeAlias !== null) {
2993
+ const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, filePath, extensionRegistry);
2994
+ if (result.ok) {
2995
+ return result.analysis;
2996
+ }
2997
+ throw new Error(result.error);
2998
+ }
2999
+ throw new Error(
3000
+ `Type "${typeName}" not found as a class, interface, or type alias in ${filePath}`
3001
+ );
3002
+ }
3003
+ var init_program = __esm({
3004
+ "src/analyzer/program.ts"() {
3005
+ "use strict";
3006
+ init_class_analyzer();
3007
+ }
3008
+ });
3009
+
3010
+ // src/validate/constraint-validator.ts
3011
+ import { normalizeConstraintTagName as normalizeConstraintTagName2 } from "@formspec/core";
3012
+ function addContradiction(ctx, message, primary, related) {
3013
+ ctx.diagnostics.push({
3014
+ code: "CONTRADICTING_CONSTRAINTS",
3015
+ message,
3016
+ severity: "error",
3017
+ primaryLocation: primary,
3018
+ relatedLocations: [related]
3019
+ });
3020
+ }
3021
+ function addTypeMismatch(ctx, message, primary) {
3022
+ ctx.diagnostics.push({
3023
+ code: "TYPE_MISMATCH",
3024
+ message,
3025
+ severity: "error",
3026
+ primaryLocation: primary,
3027
+ relatedLocations: []
3028
+ });
3029
+ }
3030
+ function addUnknownExtension(ctx, message, primary) {
3031
+ ctx.diagnostics.push({
3032
+ code: "UNKNOWN_EXTENSION",
3033
+ message,
3034
+ severity: "warning",
3035
+ primaryLocation: primary,
3036
+ relatedLocations: []
3037
+ });
3038
+ }
3039
+ function addUnknownPathTarget(ctx, message, primary) {
3040
+ ctx.diagnostics.push({
3041
+ code: "UNKNOWN_PATH_TARGET",
3042
+ message,
3043
+ severity: "error",
3044
+ primaryLocation: primary,
3045
+ relatedLocations: []
3046
+ });
3047
+ }
3048
+ function addConstraintBroadening(ctx, message, primary, related) {
3049
+ ctx.diagnostics.push({
3050
+ code: "CONSTRAINT_BROADENING",
3051
+ message,
3052
+ severity: "error",
3053
+ primaryLocation: primary,
3054
+ relatedLocations: [related]
3055
+ });
3056
+ }
3057
+ function getExtensionIdFromConstraintId(constraintId) {
3058
+ const separator = constraintId.lastIndexOf("/");
3059
+ if (separator <= 0) {
3060
+ return null;
3061
+ }
3062
+ return constraintId.slice(0, separator);
3063
+ }
3064
+ function findNumeric(constraints, constraintKind) {
3065
+ return constraints.find((c) => c.constraintKind === constraintKind);
3066
+ }
3067
+ function findLength(constraints, constraintKind) {
3068
+ return constraints.find((c) => c.constraintKind === constraintKind);
3069
+ }
3070
+ function findAllowedMembers(constraints) {
3071
+ return constraints.filter(
3072
+ (c) => c.constraintKind === "allowedMembers"
3073
+ );
3074
+ }
3075
+ function findConstConstraints(constraints) {
3076
+ return constraints.filter(
3077
+ (c) => c.constraintKind === "const"
3078
+ );
3079
+ }
3080
+ function jsonValueEquals(left, right) {
3081
+ if (left === right) {
3082
+ return true;
3083
+ }
3084
+ if (Array.isArray(left) || Array.isArray(right)) {
3085
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
3086
+ return false;
3087
+ }
3088
+ return left.every((item, index) => jsonValueEquals(item, right[index]));
3089
+ }
3090
+ if (isJsonObject(left) || isJsonObject(right)) {
3091
+ if (!isJsonObject(left) || !isJsonObject(right)) {
3092
+ return false;
3093
+ }
3094
+ const leftKeys = Object.keys(left).sort();
3095
+ const rightKeys = Object.keys(right).sort();
3096
+ if (leftKeys.length !== rightKeys.length) {
3097
+ return false;
3098
+ }
3099
+ return leftKeys.every((key, index) => {
3100
+ const rightKey = rightKeys[index];
3101
+ if (rightKey !== key) {
3102
+ return false;
3103
+ }
3104
+ const leftValue = left[key];
3105
+ const rightValue = right[rightKey];
3106
+ return leftValue !== void 0 && rightValue !== void 0 && jsonValueEquals(leftValue, rightValue);
3107
+ });
3108
+ }
3109
+ return false;
3110
+ }
3111
+ function isJsonObject(value) {
3112
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3113
+ }
3114
+ function isOrderedBoundConstraint(constraint) {
3115
+ 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";
3116
+ }
3117
+ function pathKey(constraint) {
3118
+ return constraint.path?.segments.join(".") ?? "";
3119
+ }
3120
+ function orderedBoundFamily(kind) {
3121
+ switch (kind) {
3122
+ case "minimum":
3123
+ case "exclusiveMinimum":
3124
+ return "numeric-lower";
3125
+ case "maximum":
3126
+ case "exclusiveMaximum":
3127
+ return "numeric-upper";
3128
+ case "minLength":
3129
+ return "minLength";
3130
+ case "minItems":
3131
+ return "minItems";
3132
+ case "maxLength":
3133
+ return "maxLength";
3134
+ case "maxItems":
3135
+ return "maxItems";
3136
+ default: {
3137
+ const _exhaustive = kind;
3138
+ return _exhaustive;
3139
+ }
3140
+ }
3141
+ }
3142
+ function isNumericLowerKind(kind) {
3143
+ return kind === "minimum" || kind === "exclusiveMinimum";
3144
+ }
3145
+ function isNumericUpperKind(kind) {
3146
+ return kind === "maximum" || kind === "exclusiveMaximum";
3147
+ }
3148
+ function describeConstraintTag(constraint) {
3149
+ return `@${constraint.constraintKind}`;
3150
+ }
3151
+ function compareConstraintStrength(current, previous) {
3152
+ const family = orderedBoundFamily(current.constraintKind);
3153
+ if (family === "numeric-lower") {
3154
+ if (!isNumericLowerKind(current.constraintKind) || !isNumericLowerKind(previous.constraintKind)) {
3155
+ throw new Error("numeric-lower family received non-numeric lower-bound constraint");
3156
+ }
3157
+ if (current.value !== previous.value) {
3158
+ return current.value > previous.value ? 1 : -1;
3159
+ }
3160
+ if (current.constraintKind === "exclusiveMinimum" && previous.constraintKind === "minimum") {
3161
+ return 1;
3162
+ }
3163
+ if (current.constraintKind === "minimum" && previous.constraintKind === "exclusiveMinimum") {
3164
+ return -1;
3165
+ }
3166
+ return 0;
3167
+ }
3168
+ if (family === "numeric-upper") {
3169
+ if (!isNumericUpperKind(current.constraintKind) || !isNumericUpperKind(previous.constraintKind)) {
3170
+ throw new Error("numeric-upper family received non-numeric upper-bound constraint");
3171
+ }
3172
+ if (current.value !== previous.value) {
3173
+ return current.value < previous.value ? 1 : -1;
3174
+ }
3175
+ if (current.constraintKind === "exclusiveMaximum" && previous.constraintKind === "maximum") {
3176
+ return 1;
3177
+ }
3178
+ if (current.constraintKind === "maximum" && previous.constraintKind === "exclusiveMaximum") {
3179
+ return -1;
3180
+ }
3181
+ return 0;
3182
+ }
3183
+ switch (family) {
3184
+ case "minLength":
3185
+ case "minItems":
3186
+ if (current.value === previous.value) {
3187
+ return 0;
3188
+ }
3189
+ return current.value > previous.value ? 1 : -1;
3190
+ case "maxLength":
3191
+ case "maxItems":
3192
+ if (current.value === previous.value) {
3193
+ return 0;
3194
+ }
3195
+ return current.value < previous.value ? 1 : -1;
3196
+ default: {
3197
+ const _exhaustive = family;
3198
+ return _exhaustive;
3199
+ }
3200
+ }
3201
+ }
3202
+ function checkConstraintBroadening(ctx, fieldName, constraints) {
3203
+ const strongestByKey = /* @__PURE__ */ new Map();
3204
+ for (const constraint of constraints) {
3205
+ if (!isOrderedBoundConstraint(constraint)) {
3206
+ continue;
3207
+ }
3208
+ const key = `${orderedBoundFamily(constraint.constraintKind)}:${pathKey(constraint)}`;
3209
+ const previous = strongestByKey.get(key);
3210
+ if (previous === void 0) {
3211
+ strongestByKey.set(key, constraint);
3212
+ continue;
3213
+ }
3214
+ const strength = compareConstraintStrength(constraint, previous);
3215
+ if (strength < 0) {
3216
+ const displayFieldName = formatPathTargetFieldName(
3217
+ fieldName,
3218
+ constraint.path?.segments ?? []
3219
+ );
3220
+ addConstraintBroadening(
3221
+ ctx,
3222
+ `Field "${displayFieldName}": ${describeConstraintTag(constraint)} (${String(constraint.value)}) is broader than earlier ${describeConstraintTag(previous)} (${String(previous.value)}). Constraints can only narrow.`,
3223
+ constraint.provenance,
3224
+ previous.provenance
3225
+ );
3226
+ continue;
3227
+ }
3228
+ if (strength <= 0) {
3229
+ continue;
3230
+ }
3231
+ strongestByKey.set(key, constraint);
3232
+ }
3233
+ }
3234
+ function compareCustomConstraintStrength(current, previous) {
3235
+ const order = current.comparePayloads(current.constraint.payload, previous.constraint.payload);
3236
+ const equalPayloadTiebreaker = order === 0 ? compareSemanticInclusivity(current.role.inclusive, previous.role.inclusive) : order;
3237
+ switch (current.role.bound) {
3238
+ case "lower":
3239
+ return equalPayloadTiebreaker;
3240
+ case "upper":
3241
+ return equalPayloadTiebreaker === 0 ? 0 : -equalPayloadTiebreaker;
3242
+ case "exact":
3243
+ return order === 0 ? 0 : Number.NaN;
3244
+ default: {
3245
+ const _exhaustive = current.role.bound;
3246
+ return _exhaustive;
3247
+ }
3248
+ }
3249
+ }
3250
+ function compareSemanticInclusivity(currentInclusive, previousInclusive) {
3251
+ if (currentInclusive === previousInclusive) {
3252
+ return 0;
3253
+ }
3254
+ return currentInclusive ? -1 : 1;
3255
+ }
3256
+ function customConstraintsContradict(lower, upper) {
3257
+ const order = lower.comparePayloads(lower.constraint.payload, upper.constraint.payload);
3258
+ if (order > 0) {
3259
+ return true;
3260
+ }
3261
+ if (order < 0) {
3262
+ return false;
3263
+ }
3264
+ return !lower.role.inclusive || !upper.role.inclusive;
3265
+ }
3266
+ function describeCustomConstraintTag(constraint) {
3267
+ return constraint.provenance.tagName ?? constraint.constraintId;
3268
+ }
3269
+ function checkCustomConstraintSemantics(ctx, fieldName, constraints) {
3270
+ if (ctx.extensionRegistry === void 0) {
3271
+ return;
3272
+ }
3273
+ const strongestByKey = /* @__PURE__ */ new Map();
3274
+ const lowerByFamily = /* @__PURE__ */ new Map();
3275
+ const upperByFamily = /* @__PURE__ */ new Map();
3276
+ for (const constraint of constraints) {
3277
+ if (constraint.constraintKind !== "custom") {
3278
+ continue;
3279
+ }
3280
+ const registration = ctx.extensionRegistry.findConstraint(constraint.constraintId);
3281
+ if (registration?.comparePayloads === void 0 || registration.semanticRole === void 0) {
3282
+ continue;
3283
+ }
3284
+ const entry = {
3285
+ constraint,
3286
+ comparePayloads: registration.comparePayloads,
3287
+ role: registration.semanticRole
3288
+ };
3289
+ const familyKey = `${registration.semanticRole.family}:${pathKey(constraint)}`;
3290
+ const boundKey = `${familyKey}:${registration.semanticRole.bound}`;
3291
+ const previous = strongestByKey.get(boundKey);
3292
+ if (previous !== void 0) {
3293
+ const strength = compareCustomConstraintStrength(entry, previous);
3294
+ if (Number.isNaN(strength)) {
3295
+ addContradiction(
3296
+ ctx,
3297
+ `Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} conflicts with ${describeCustomConstraintTag(previous.constraint)}`,
3298
+ constraint.provenance,
3299
+ previous.constraint.provenance
3300
+ );
3301
+ continue;
3302
+ }
3303
+ if (strength < 0) {
3304
+ addConstraintBroadening(
3305
+ ctx,
3306
+ `Field "${formatPathTargetFieldName(fieldName, constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(constraint)} is broader than earlier ${describeCustomConstraintTag(previous.constraint)}. Constraints can only narrow.`,
3307
+ constraint.provenance,
3308
+ previous.constraint.provenance
3309
+ );
3310
+ continue;
3311
+ }
3312
+ if (strength > 0) {
3313
+ strongestByKey.set(boundKey, entry);
3314
+ }
3315
+ } else {
3316
+ strongestByKey.set(boundKey, entry);
3317
+ }
3318
+ if (registration.semanticRole.bound === "lower") {
3319
+ lowerByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
3320
+ } else if (registration.semanticRole.bound === "upper") {
3321
+ upperByFamily.set(familyKey, strongestByKey.get(boundKey) ?? entry);
3322
+ }
3323
+ }
3324
+ for (const [familyKey, lower] of lowerByFamily) {
3325
+ const upper = upperByFamily.get(familyKey);
3326
+ if (upper === void 0) {
3327
+ continue;
3328
+ }
3329
+ if (!customConstraintsContradict(lower, upper)) {
3330
+ continue;
3331
+ }
3332
+ addContradiction(
3333
+ ctx,
3334
+ `Field "${formatPathTargetFieldName(fieldName, lower.constraint.path?.segments ?? [])}": ${describeCustomConstraintTag(lower.constraint)} contradicts ${describeCustomConstraintTag(upper.constraint)}`,
3335
+ lower.constraint.provenance,
3336
+ upper.constraint.provenance
3337
+ );
3338
+ }
3339
+ }
3340
+ function checkNumericContradictions(ctx, fieldName, constraints) {
3341
+ const min = findNumeric(constraints, "minimum");
3342
+ const max = findNumeric(constraints, "maximum");
3343
+ const exMin = findNumeric(constraints, "exclusiveMinimum");
3344
+ const exMax = findNumeric(constraints, "exclusiveMaximum");
3345
+ if (min !== void 0 && max !== void 0 && min.value > max.value) {
3346
+ addContradiction(
3347
+ ctx,
3348
+ `Field "${fieldName}": minimum (${String(min.value)}) is greater than maximum (${String(max.value)})`,
3349
+ min.provenance,
3350
+ max.provenance
3351
+ );
3352
+ }
3353
+ if (exMin !== void 0 && max !== void 0 && exMin.value >= max.value) {
3354
+ addContradiction(
3355
+ ctx,
3356
+ `Field "${fieldName}": exclusiveMinimum (${String(exMin.value)}) is greater than or equal to maximum (${String(max.value)})`,
3357
+ exMin.provenance,
3358
+ max.provenance
3359
+ );
3360
+ }
3361
+ if (min !== void 0 && exMax !== void 0 && min.value >= exMax.value) {
3362
+ addContradiction(
3363
+ ctx,
3364
+ `Field "${fieldName}": minimum (${String(min.value)}) is greater than or equal to exclusiveMaximum (${String(exMax.value)})`,
3365
+ min.provenance,
3366
+ exMax.provenance
3367
+ );
3368
+ }
3369
+ if (exMin !== void 0 && exMax !== void 0 && exMin.value >= exMax.value) {
3370
+ addContradiction(
3371
+ ctx,
3372
+ `Field "${fieldName}": exclusiveMinimum (${String(exMin.value)}) is greater than or equal to exclusiveMaximum (${String(exMax.value)})`,
3373
+ exMin.provenance,
3374
+ exMax.provenance
3375
+ );
3376
+ }
3377
+ }
3378
+ function checkLengthContradictions(ctx, fieldName, constraints) {
3379
+ const minLen = findLength(constraints, "minLength");
3380
+ const maxLen = findLength(constraints, "maxLength");
3381
+ if (minLen !== void 0 && maxLen !== void 0 && minLen.value > maxLen.value) {
3382
+ addContradiction(
3383
+ ctx,
3384
+ `Field "${fieldName}": minLength (${String(minLen.value)}) is greater than maxLength (${String(maxLen.value)})`,
3385
+ minLen.provenance,
3386
+ maxLen.provenance
3387
+ );
3388
+ }
3389
+ const minItems = findLength(constraints, "minItems");
3390
+ const maxItems = findLength(constraints, "maxItems");
3391
+ if (minItems !== void 0 && maxItems !== void 0 && minItems.value > maxItems.value) {
3392
+ addContradiction(
3393
+ ctx,
3394
+ `Field "${fieldName}": minItems (${String(minItems.value)}) is greater than maxItems (${String(maxItems.value)})`,
3395
+ minItems.provenance,
3396
+ maxItems.provenance
3397
+ );
3398
+ }
3399
+ }
3400
+ function checkAllowedMembersContradiction(ctx, fieldName, constraints) {
3401
+ const members = findAllowedMembers(constraints);
3402
+ if (members.length < 2) return;
3403
+ const firstSet = new Set(members[0]?.members ?? []);
3404
+ for (let i = 1; i < members.length; i++) {
3405
+ const current = members[i];
3406
+ if (current === void 0) continue;
3407
+ for (const m of firstSet) {
3408
+ if (!current.members.includes(m)) {
3409
+ firstSet.delete(m);
3410
+ }
3411
+ }
3412
+ }
3413
+ if (firstSet.size === 0) {
3414
+ const first = members[0];
3415
+ const second = members[1];
3416
+ if (first !== void 0 && second !== void 0) {
3417
+ addContradiction(
3418
+ ctx,
3419
+ `Field "${fieldName}": allowedMembers constraints have an empty intersection (no valid values remain)`,
3420
+ first.provenance,
3421
+ second.provenance
3422
+ );
3423
+ }
3424
+ }
3425
+ }
3426
+ function checkConstContradictions(ctx, fieldName, constraints) {
3427
+ const constConstraints = findConstConstraints(constraints);
3428
+ if (constConstraints.length < 2) return;
3429
+ const first = constConstraints[0];
3430
+ if (first === void 0) return;
3431
+ for (let i = 1; i < constConstraints.length; i++) {
3432
+ const current = constConstraints[i];
3433
+ if (current === void 0) continue;
3434
+ if (jsonValueEquals(first.value, current.value)) {
3435
+ continue;
3436
+ }
3437
+ addContradiction(
3438
+ ctx,
3439
+ `Field "${fieldName}": conflicting @const constraints require both ${JSON.stringify(first.value)} and ${JSON.stringify(current.value)}`,
3440
+ first.provenance,
3441
+ current.provenance
3442
+ );
3443
+ }
3444
+ }
3445
+ function typeLabel(type) {
3446
+ switch (type.kind) {
3447
+ case "primitive":
3448
+ return type.primitiveKind;
3449
+ case "enum":
3450
+ return "enum";
3451
+ case "array":
3452
+ return "array";
3453
+ case "object":
3454
+ return "object";
3455
+ case "record":
3456
+ return "record";
3457
+ case "union":
3458
+ return "union";
3459
+ case "reference":
3460
+ return `reference(${type.name})`;
3461
+ case "dynamic":
3462
+ return `dynamic(${type.dynamicKind})`;
3463
+ case "custom":
3464
+ return `custom(${type.typeId})`;
3465
+ default: {
3466
+ const _exhaustive = type;
3467
+ return String(_exhaustive);
3468
+ }
3469
+ }
3470
+ }
3471
+ function dereferenceType(ctx, type) {
3472
+ let current = type;
3473
+ const seen = /* @__PURE__ */ new Set();
3474
+ while (current.kind === "reference") {
3475
+ if (seen.has(current.name)) {
3476
+ return current;
3477
+ }
3478
+ seen.add(current.name);
3479
+ const definition = ctx.typeRegistry[current.name];
3480
+ if (definition === void 0) {
3481
+ return current;
3482
+ }
3483
+ current = definition.type;
3484
+ }
3485
+ return current;
3486
+ }
3487
+ function collectReferencedTypeConstraints(ctx, type) {
3488
+ const collected = [];
3489
+ let current = type;
3490
+ const seen = /* @__PURE__ */ new Set();
3491
+ while (current.kind === "reference") {
3492
+ if (seen.has(current.name)) {
3493
+ break;
3494
+ }
3495
+ seen.add(current.name);
3496
+ const definition = ctx.typeRegistry[current.name];
3497
+ if (definition === void 0) {
3498
+ break;
3499
+ }
3500
+ if (definition.constraints !== void 0) {
3501
+ collected.push(...definition.constraints);
3502
+ }
3503
+ current = definition.type;
3504
+ }
3505
+ return collected;
3506
+ }
3507
+ function resolvePathTargetType(ctx, type, segments) {
3508
+ const effectiveType = dereferenceType(ctx, type);
3509
+ if (segments.length === 0) {
3510
+ return { kind: "resolved", type: effectiveType };
3511
+ }
3512
+ if (effectiveType.kind === "array") {
3513
+ return resolvePathTargetType(ctx, effectiveType.items, segments);
3514
+ }
3515
+ if (effectiveType.kind === "object") {
3516
+ const [segment, ...rest] = segments;
3517
+ if (segment === void 0) {
3518
+ throw new Error("Invariant violation: object path traversal requires a segment");
3519
+ }
3520
+ const property = effectiveType.properties.find((prop) => prop.name === segment);
3521
+ if (property === void 0) {
3522
+ return { kind: "missing-property", segment };
3523
+ }
3524
+ return resolvePathTargetType(ctx, property.type, rest);
3525
+ }
3526
+ return { kind: "unresolvable", type: effectiveType };
3527
+ }
3528
+ function isNullType(type) {
3529
+ return type.kind === "primitive" && type.primitiveKind === "null";
3530
+ }
3531
+ function collectCustomConstraintCandidateTypes(ctx, type) {
3532
+ const effectiveType = dereferenceType(ctx, type);
3533
+ const candidates = [effectiveType];
3534
+ if (effectiveType.kind === "array") {
3535
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, effectiveType.items));
3536
+ }
3537
+ if (effectiveType.kind === "union") {
3538
+ const memberTypes = effectiveType.members.map((member) => dereferenceType(ctx, member));
3539
+ const nonNullMembers = memberTypes.filter((member) => !isNullType(member));
3540
+ if (nonNullMembers.length === 1 && nonNullMembers.length < memberTypes.length) {
3541
+ const [nullableMember] = nonNullMembers;
3542
+ if (nullableMember !== void 0) {
3543
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, nullableMember));
3544
+ }
3545
+ }
3546
+ }
3547
+ return candidates;
3548
+ }
3549
+ function formatPathTargetFieldName(fieldName, path4) {
3550
+ return path4.length === 0 ? fieldName : `${fieldName}.${path4.join(".")}`;
3551
+ }
3552
+ function checkConstraintOnType(ctx, fieldName, type, constraint) {
3553
+ const effectiveType = dereferenceType(ctx, type);
3554
+ const isNumber = effectiveType.kind === "primitive" && ["number", "integer", "bigint"].includes(effectiveType.primitiveKind);
3555
+ const isString = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "string";
3556
+ const isArray = effectiveType.kind === "array";
3557
+ const isEnum = effectiveType.kind === "enum";
3558
+ const arrayItemType = effectiveType.kind === "array" ? dereferenceType(ctx, effectiveType.items) : void 0;
3559
+ const isStringArray = arrayItemType?.kind === "primitive" && arrayItemType.primitiveKind === "string";
3560
+ const label = typeLabel(effectiveType);
3561
+ const ck = constraint.constraintKind;
3562
+ switch (ck) {
3563
+ case "minimum":
3564
+ case "maximum":
3565
+ case "exclusiveMinimum":
3566
+ case "exclusiveMaximum":
3567
+ case "multipleOf": {
3568
+ if (!isNumber) {
3569
+ addTypeMismatch(
3570
+ ctx,
3571
+ `Field "${fieldName}": constraint "${ck}" is only valid on number fields, but field type is "${label}"`,
3572
+ constraint.provenance
3573
+ );
3574
+ }
3575
+ break;
3576
+ }
3577
+ case "minLength":
3578
+ case "maxLength":
3579
+ case "pattern": {
3580
+ if (!isString && !isStringArray) {
3581
+ addTypeMismatch(
3582
+ ctx,
3583
+ `Field "${fieldName}": constraint "${ck}" is only valid on string fields or string array items, but field type is "${label}"`,
3584
+ constraint.provenance
3585
+ );
3586
+ }
3587
+ break;
3588
+ }
3589
+ case "minItems":
3590
+ case "maxItems":
3591
+ case "uniqueItems": {
3592
+ if (!isArray) {
3593
+ addTypeMismatch(
3594
+ ctx,
3595
+ `Field "${fieldName}": constraint "${ck}" is only valid on array fields, but field type is "${label}"`,
3596
+ constraint.provenance
3597
+ );
3598
+ }
3599
+ break;
3600
+ }
3601
+ case "allowedMembers": {
3602
+ if (!isEnum) {
3603
+ addTypeMismatch(
3604
+ ctx,
3605
+ `Field "${fieldName}": constraint "allowedMembers" is only valid on enum fields, but field type is "${label}"`,
3606
+ constraint.provenance
3607
+ );
3608
+ }
3609
+ break;
3610
+ }
3611
+ case "const": {
3612
+ const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "integer", "bigint", "boolean", "null"].includes(
3613
+ effectiveType.primitiveKind
3614
+ ) || effectiveType.kind === "enum";
3615
+ if (!isPrimitiveConstType) {
3616
+ addTypeMismatch(
3617
+ ctx,
3618
+ `Field "${fieldName}": constraint "const" is only valid on primitive or enum fields, but field type is "${label}"`,
3619
+ constraint.provenance
3620
+ );
3621
+ break;
3622
+ }
3623
+ if (effectiveType.kind === "primitive") {
3624
+ const valueType = constraint.value === null ? "null" : Array.isArray(constraint.value) ? "array" : typeof constraint.value;
3625
+ const expectedValueType = effectiveType.primitiveKind === "integer" || effectiveType.primitiveKind === "bigint" ? "number" : effectiveType.primitiveKind;
3626
+ if (valueType !== expectedValueType) {
3627
+ addTypeMismatch(
3628
+ ctx,
3629
+ `Field "${fieldName}": @const value type "${valueType}" is incompatible with field type "${effectiveType.primitiveKind}"`,
3630
+ constraint.provenance
3631
+ );
3632
+ }
3633
+ break;
3634
+ }
3635
+ const memberValues = effectiveType.members.map((member) => member.value);
3636
+ if (!memberValues.some((member) => jsonValueEquals(member, constraint.value))) {
3637
+ addTypeMismatch(
3638
+ ctx,
3639
+ `Field "${fieldName}": @const value ${JSON.stringify(constraint.value)} is not one of the enum members`,
3640
+ constraint.provenance
3641
+ );
3642
+ }
3643
+ break;
3644
+ }
3645
+ case "custom": {
3646
+ checkCustomConstraint(ctx, fieldName, effectiveType, constraint);
3647
+ break;
3648
+ }
3649
+ default: {
3650
+ const _exhaustive = constraint;
3651
+ throw new Error(
3652
+ `Unhandled constraint kind: ${_exhaustive.constraintKind}`
3653
+ );
3654
+ }
3655
+ }
3656
+ }
3657
+ function checkTypeApplicability(ctx, fieldName, type, constraints) {
3658
+ for (const constraint of constraints) {
3659
+ if (constraint.path) {
3660
+ const resolution = resolvePathTargetType(ctx, type, constraint.path.segments);
3661
+ const targetFieldName = formatPathTargetFieldName(fieldName, constraint.path.segments);
3662
+ if (resolution.kind === "missing-property") {
3663
+ addUnknownPathTarget(
3664
+ ctx,
3665
+ `Field "${targetFieldName}": path-targeted constraint "${constraint.constraintKind}" references unknown path segment "${resolution.segment}"`,
3666
+ constraint.provenance
3667
+ );
3668
+ continue;
3669
+ }
3670
+ if (resolution.kind === "unresolvable") {
3671
+ addTypeMismatch(
3672
+ ctx,
3673
+ `Field "${targetFieldName}": path-targeted constraint "${constraint.constraintKind}" is invalid because type "${typeLabel(resolution.type)}" cannot be traversed`,
3674
+ constraint.provenance
3675
+ );
3676
+ continue;
3677
+ }
3678
+ checkConstraintOnType(ctx, targetFieldName, resolution.type, constraint);
3679
+ continue;
3680
+ }
3681
+ checkConstraintOnType(ctx, fieldName, type, constraint);
3682
+ }
3683
+ }
3684
+ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3685
+ if (ctx.extensionRegistry === void 0) return;
3686
+ const registration = ctx.extensionRegistry.findConstraint(constraint.constraintId);
3687
+ if (registration === void 0) {
3688
+ addUnknownExtension(
3689
+ ctx,
3690
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not registered in the extension registry`,
3691
+ constraint.provenance
3692
+ );
3693
+ return;
3694
+ }
3695
+ const candidateTypes = collectCustomConstraintCandidateTypes(ctx, type);
3696
+ const normalizedTagName = constraint.provenance.tagName === void 0 ? void 0 : normalizeConstraintTagName2(constraint.provenance.tagName.replace(/^@/, ""));
3697
+ if (normalizedTagName !== void 0) {
3698
+ const tagRegistration = ctx.extensionRegistry.findConstraintTag(normalizedTagName);
3699
+ const extensionId = getExtensionIdFromConstraintId(constraint.constraintId);
3700
+ if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && !candidateTypes.some(
3701
+ (candidateType) => tagRegistration.registration.isApplicableToType?.(candidateType) !== false
3702
+ )) {
3703
+ addTypeMismatch(
3704
+ ctx,
3705
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3706
+ constraint.provenance
3707
+ );
3708
+ return;
3709
+ }
3710
+ }
3711
+ if (registration.applicableTypes === null) {
3712
+ if (!candidateTypes.some((candidateType) => registration.isApplicableToType?.(candidateType) !== false)) {
3713
+ addTypeMismatch(
3714
+ ctx,
3715
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3716
+ constraint.provenance
3717
+ );
3718
+ }
3719
+ return;
3720
+ }
3721
+ const applicableTypes = registration.applicableTypes;
3722
+ const matchesApplicableType = candidateTypes.some(
3723
+ (candidateType) => applicableTypes.includes(candidateType.kind) && registration.isApplicableToType?.(candidateType) !== false
3724
+ );
3725
+ if (!matchesApplicableType) {
3726
+ addTypeMismatch(
3727
+ ctx,
3728
+ `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
3729
+ constraint.provenance
3730
+ );
3731
+ }
3732
+ }
3733
+ function validateFieldNode(ctx, field) {
3734
+ validateConstraints(ctx, field.name, field.type, [
3735
+ ...collectReferencedTypeConstraints(ctx, field.type),
3736
+ ...field.constraints
3737
+ ]);
3738
+ if (field.type.kind === "object") {
3739
+ for (const prop of field.type.properties) {
3740
+ validateObjectProperty(ctx, field.name, prop);
3741
+ }
3742
+ }
3743
+ }
3744
+ function validateObjectProperty(ctx, parentName, prop) {
3745
+ const qualifiedName = `${parentName}.${prop.name}`;
3746
+ validateConstraints(ctx, qualifiedName, prop.type, [
3747
+ ...collectReferencedTypeConstraints(ctx, prop.type),
3748
+ ...prop.constraints
3749
+ ]);
3750
+ if (prop.type.kind === "object") {
3751
+ for (const nestedProp of prop.type.properties) {
3752
+ validateObjectProperty(ctx, qualifiedName, nestedProp);
3753
+ }
3754
+ }
3755
+ }
3756
+ function validateConstraints(ctx, name, type, constraints) {
3757
+ checkNumericContradictions(ctx, name, constraints);
3758
+ checkLengthContradictions(ctx, name, constraints);
3759
+ checkAllowedMembersContradiction(ctx, name, constraints);
3760
+ checkConstContradictions(ctx, name, constraints);
3761
+ checkConstraintBroadening(ctx, name, constraints);
3762
+ checkCustomConstraintSemantics(ctx, name, constraints);
3763
+ checkTypeApplicability(ctx, name, type, constraints);
3764
+ }
3765
+ function validateElement(ctx, element) {
3766
+ switch (element.kind) {
3767
+ case "field":
3768
+ validateFieldNode(ctx, element);
3769
+ break;
3770
+ case "group":
3771
+ for (const child of element.elements) {
3772
+ validateElement(ctx, child);
3773
+ }
3774
+ break;
3775
+ case "conditional":
3776
+ for (const child of element.elements) {
3777
+ validateElement(ctx, child);
3778
+ }
3779
+ break;
3780
+ default: {
3781
+ const _exhaustive = element;
3782
+ throw new Error(`Unhandled element kind: ${_exhaustive.kind}`);
3783
+ }
3784
+ }
3785
+ }
3786
+ function validateIR(ir, options) {
3787
+ const ctx = {
3788
+ diagnostics: [],
3789
+ extensionRegistry: options?.extensionRegistry,
3790
+ typeRegistry: ir.typeRegistry
3791
+ };
3792
+ for (const element of ir.elements) {
3793
+ validateElement(ctx, element);
3794
+ }
3795
+ return {
3796
+ diagnostics: ctx.diagnostics,
3797
+ valid: ctx.diagnostics.every((d) => d.severity !== "error")
3798
+ };
3799
+ }
3800
+ var init_constraint_validator = __esm({
3801
+ "src/validate/constraint-validator.ts"() {
3802
+ "use strict";
3803
+ }
3804
+ });
3805
+
3806
+ // src/validate/index.ts
3807
+ var init_validate = __esm({
3808
+ "src/validate/index.ts"() {
3809
+ "use strict";
3810
+ init_constraint_validator();
3811
+ }
3812
+ });
3813
+
2886
3814
  // src/generators/class-schema.ts
2887
3815
  function generateClassSchemas(analysis, source, options) {
2888
3816
  const ir = canonicalizeTSDoc(analysis, source);
3817
+ const validationResult = validateIR(ir, {
3818
+ ...options?.extensionRegistry !== void 0 && {
3819
+ extensionRegistry: options.extensionRegistry
3820
+ },
3821
+ ...options?.vendorPrefix !== void 0 && { vendorPrefix: options.vendorPrefix }
3822
+ });
3823
+ if (!validationResult.valid) {
3824
+ throw new Error(formatValidationError(validationResult.diagnostics));
3825
+ }
2889
3826
  return {
2890
3827
  jsonSchema: generateJsonSchemaFromIR(ir, options),
2891
3828
  uiSchema: generateUiSchemaFromIR(ir)
2892
3829
  };
2893
3830
  }
3831
+ function formatValidationError(diagnostics) {
3832
+ const lines = diagnostics.map((diagnostic) => {
3833
+ const primary = formatLocation(diagnostic.primaryLocation);
3834
+ const related = diagnostic.relatedLocations.length > 0 ? ` [related: ${diagnostic.relatedLocations.map(formatLocation).join(", ")}]` : "";
3835
+ return `${diagnostic.code}: ${diagnostic.message} (${primary})${related}`;
3836
+ });
3837
+ return `FormSpec validation failed:
3838
+ ${lines.map((line) => `- ${line}`).join("\n")}`;
3839
+ }
3840
+ function formatLocation(location) {
3841
+ return `${location.file}:${String(location.line)}:${String(location.column)}`;
3842
+ }
2894
3843
  function generateSchemasFromClass(options) {
2895
3844
  const ctx = createProgramContext(options.filePath);
2896
3845
  const classDecl = findClassByName(ctx.sourceFile, options.className);
@@ -2913,44 +3862,12 @@ function generateSchemasFromClass(options) {
2913
3862
  );
2914
3863
  }
2915
3864
  function generateSchemas(options) {
2916
- const ctx = createProgramContext(options.filePath);
2917
- const source = { file: options.filePath };
2918
- const classDecl = findClassByName(ctx.sourceFile, options.typeName);
2919
- if (classDecl) {
2920
- const analysis = analyzeClassToIR(
2921
- classDecl,
2922
- ctx.checker,
2923
- options.filePath,
2924
- options.extensionRegistry
2925
- );
2926
- return generateClassSchemas(analysis, source, options);
2927
- }
2928
- const interfaceDecl = findInterfaceByName(ctx.sourceFile, options.typeName);
2929
- if (interfaceDecl) {
2930
- const analysis = analyzeInterfaceToIR(
2931
- interfaceDecl,
2932
- ctx.checker,
2933
- options.filePath,
2934
- options.extensionRegistry
2935
- );
2936
- return generateClassSchemas(analysis, source, options);
2937
- }
2938
- const typeAlias = findTypeAliasByName(ctx.sourceFile, options.typeName);
2939
- if (typeAlias) {
2940
- const result = analyzeTypeAliasToIR(
2941
- typeAlias,
2942
- ctx.checker,
2943
- options.filePath,
2944
- options.extensionRegistry
2945
- );
2946
- if (result.ok) {
2947
- return generateClassSchemas(result.analysis, source, options);
2948
- }
2949
- throw new Error(result.error);
2950
- }
2951
- throw new Error(
2952
- `Type "${options.typeName}" not found as a class, interface, or type alias in ${options.filePath}`
3865
+ const analysis = analyzeNamedTypeToIR(
3866
+ options.filePath,
3867
+ options.typeName,
3868
+ options.extensionRegistry
2953
3869
  );
3870
+ return generateClassSchemas(analysis, { file: options.filePath }, options);
2954
3871
  }
2955
3872
  var init_class_schema = __esm({
2956
3873
  "src/generators/class-schema.ts"() {
@@ -2960,13 +3877,14 @@ var init_class_schema = __esm({
2960
3877
  init_canonicalize();
2961
3878
  init_ir_generator();
2962
3879
  init_ir_generator2();
3880
+ init_validate();
2963
3881
  }
2964
3882
  });
2965
3883
 
2966
3884
  // src/generators/mixed-authoring.ts
2967
3885
  function buildMixedAuthoringSchemas(options) {
2968
3886
  const { filePath, typeName, overlays, ...schemaOptions } = options;
2969
- const analysis = analyzeNamedType(filePath, typeName, schemaOptions.extensionRegistry);
3887
+ const analysis = analyzeNamedTypeToIR(filePath, typeName, schemaOptions.extensionRegistry);
2970
3888
  const composedAnalysis = composeAnalysisWithOverlays(analysis, overlays);
2971
3889
  const ir = canonicalizeTSDoc(composedAnalysis, { file: filePath });
2972
3890
  return {
@@ -2974,29 +3892,6 @@ function buildMixedAuthoringSchemas(options) {
2974
3892
  uiSchema: generateUiSchemaFromIR(ir)
2975
3893
  };
2976
3894
  }
2977
- function analyzeNamedType(filePath, typeName, extensionRegistry) {
2978
- const ctx = createProgramContext(filePath);
2979
- const source = { file: filePath };
2980
- const classDecl = findClassByName(ctx.sourceFile, typeName);
2981
- if (classDecl !== null) {
2982
- return analyzeClassToIR(classDecl, ctx.checker, source.file, extensionRegistry);
2983
- }
2984
- const interfaceDecl = findInterfaceByName(ctx.sourceFile, typeName);
2985
- if (interfaceDecl !== null) {
2986
- return analyzeInterfaceToIR(interfaceDecl, ctx.checker, source.file, extensionRegistry);
2987
- }
2988
- const typeAlias = findTypeAliasByName(ctx.sourceFile, typeName);
2989
- if (typeAlias !== null) {
2990
- const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, source.file, extensionRegistry);
2991
- if (result.ok) {
2992
- return result.analysis;
2993
- }
2994
- throw new Error(result.error);
2995
- }
2996
- throw new Error(
2997
- `Type "${typeName}" not found as a class, interface, or type alias in ${filePath}`
2998
- );
2999
- }
3000
3895
  function composeAnalysisWithOverlays(analysis, overlays) {
3001
3896
  const overlayIR = canonicalizeChainDSL(overlays);
3002
3897
  const overlayFields = collectOverlayFields(overlayIR.elements);
@@ -3168,7 +4063,6 @@ var init_mixed_authoring = __esm({
3168
4063
  init_ir_generator2();
3169
4064
  init_canonicalize();
3170
4065
  init_program();
3171
- init_class_analyzer();
3172
4066
  }
3173
4067
  });
3174
4068