@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
@@ -71,6 +71,7 @@ function canonicalizeChainDSL(form) {
71
71
  kind: "form-ir",
72
72
  irVersion: import_core.IR_VERSION,
73
73
  elements: canonicalizeElements(form.elements),
74
+ rootAnnotations: [],
74
75
  typeRegistry: {},
75
76
  provenance: CHAIN_DSL_PROVENANCE
76
77
  };
@@ -376,6 +377,7 @@ function canonicalizeTSDoc(analysis, source) {
376
377
  irVersion: import_core2.IR_VERSION,
377
378
  elements,
378
379
  typeRegistry: analysis.typeRegistry,
380
+ ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations },
379
381
  ...analysis.annotations !== void 0 && analysis.annotations.length > 0 && { annotations: analysis.annotations },
380
382
  provenance
381
383
  };
@@ -436,85 +438,17 @@ function wrapInConditional(field, layout, provenance) {
436
438
  }
437
439
 
438
440
  // src/analyzer/program.ts
439
- var ts = __toESM(require("typescript"), 1);
441
+ var ts4 = __toESM(require("typescript"), 1);
440
442
  var path = __toESM(require("path"), 1);
441
- function createProgramContext(filePath) {
442
- const absolutePath = path.resolve(filePath);
443
- const fileDir = path.dirname(absolutePath);
444
- const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
445
- let compilerOptions;
446
- let fileNames;
447
- if (configPath) {
448
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
449
- if (configFile.error) {
450
- throw new Error(
451
- `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
452
- );
453
- }
454
- const parsed = ts.parseJsonConfigFileContent(
455
- configFile.config,
456
- ts.sys,
457
- path.dirname(configPath)
458
- );
459
- if (parsed.errors.length > 0) {
460
- const errorMessages = parsed.errors.map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
461
- throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
462
- }
463
- compilerOptions = parsed.options;
464
- fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
465
- } else {
466
- compilerOptions = {
467
- target: ts.ScriptTarget.ES2022,
468
- module: ts.ModuleKind.NodeNext,
469
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
470
- strict: true,
471
- skipLibCheck: true,
472
- declaration: true
473
- };
474
- fileNames = [absolutePath];
475
- }
476
- const program = ts.createProgram(fileNames, compilerOptions);
477
- const sourceFile = program.getSourceFile(absolutePath);
478
- if (!sourceFile) {
479
- throw new Error(`Could not find source file: ${absolutePath}`);
480
- }
481
- return {
482
- program,
483
- checker: program.getTypeChecker(),
484
- sourceFile
485
- };
486
- }
487
- function findNodeByName(sourceFile, name, predicate, getName) {
488
- let result = null;
489
- function visit(node) {
490
- if (result) return;
491
- if (predicate(node) && getName(node) === name) {
492
- result = node;
493
- return;
494
- }
495
- ts.forEachChild(node, visit);
496
- }
497
- visit(sourceFile);
498
- return result;
499
- }
500
- function findClassByName(sourceFile, className) {
501
- return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
502
- }
503
- function findInterfaceByName(sourceFile, interfaceName) {
504
- return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
505
- }
506
- function findTypeAliasByName(sourceFile, aliasName) {
507
- return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
508
- }
509
443
 
510
444
  // src/analyzer/class-analyzer.ts
511
- var ts4 = __toESM(require("typescript"), 1);
445
+ var ts3 = __toESM(require("typescript"), 1);
512
446
 
513
447
  // src/analyzer/jsdoc-constraints.ts
514
- var ts3 = __toESM(require("typescript"), 1);
448
+ var ts2 = __toESM(require("typescript"), 1);
515
449
 
516
450
  // src/analyzer/tsdoc-parser.ts
517
- var ts2 = __toESM(require("typescript"), 1);
451
+ var ts = __toESM(require("typescript"), 1);
518
452
  var import_tsdoc = require("@microsoft/tsdoc");
519
453
  var import_core3 = require("@formspec/core");
520
454
 
@@ -600,10 +534,10 @@ function parseTSDocTags(node, file = "", options) {
600
534
  let placeholderProvenance;
601
535
  const sourceFile = node.getSourceFile();
602
536
  const sourceText = sourceFile.getFullText();
603
- const commentRanges = ts2.getLeadingCommentRanges(sourceText, node.getFullStart());
537
+ const commentRanges = ts.getLeadingCommentRanges(sourceText, node.getFullStart());
604
538
  if (commentRanges) {
605
539
  for (const range of commentRanges) {
606
- if (range.kind !== ts2.SyntaxKind.MultiLineCommentTrivia) {
540
+ if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
607
541
  continue;
608
542
  }
609
543
  const commentText = sourceText.substring(range.pos, range.end);
@@ -621,26 +555,31 @@ function parseTSDocTags(node, file = "", options) {
621
555
  const text2 = extractBlockText(block).trim();
622
556
  if (text2 === "") continue;
623
557
  const provenance2 = provenanceForComment(range, sourceFile, file, tagName);
624
- if (tagName === "displayName") {
625
- if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
626
- displayName = text2;
627
- displayNameProvenance = provenance2;
628
- }
629
- } else if (tagName === "format") {
630
- annotations.push({
631
- kind: "annotation",
632
- annotationKind: "format",
633
- value: text2,
634
- provenance: provenance2
635
- });
636
- } else {
637
- if (tagName === "description" && description === void 0) {
558
+ switch (tagName) {
559
+ case "displayName":
560
+ if (!isMemberTargetDisplayName(text2) && displayName === void 0) {
561
+ displayName = text2;
562
+ displayNameProvenance = provenance2;
563
+ }
564
+ break;
565
+ case "format":
566
+ annotations.push({
567
+ kind: "annotation",
568
+ annotationKind: "format",
569
+ value: text2,
570
+ provenance: provenance2
571
+ });
572
+ break;
573
+ case "description":
638
574
  description = text2;
639
575
  descriptionProvenance = provenance2;
640
- } else if (tagName === "placeholder" && placeholder === void 0) {
641
- placeholder = text2;
642
- placeholderProvenance = provenance2;
643
- }
576
+ break;
577
+ case "placeholder":
578
+ if (placeholder === void 0) {
579
+ placeholder = text2;
580
+ placeholderProvenance = provenance2;
581
+ }
582
+ break;
644
583
  }
645
584
  continue;
646
585
  }
@@ -670,6 +609,13 @@ function parseTSDocTags(node, file = "", options) {
670
609
  descriptionProvenance = provenanceForComment(range, sourceFile, file, "remarks");
671
610
  }
672
611
  }
612
+ if (description === void 0) {
613
+ const summary = extractPlainText(docComment.summarySection).trim();
614
+ if (summary !== "") {
615
+ description = summary;
616
+ descriptionProvenance = provenanceForComment(range, sourceFile, file, "summary");
617
+ }
618
+ }
673
619
  }
674
620
  }
675
621
  if (displayName !== void 0 && displayNameProvenance !== void 0) {
@@ -696,7 +642,7 @@ function parseTSDocTags(node, file = "", options) {
696
642
  provenance: placeholderProvenance
697
643
  });
698
644
  }
699
- const jsDocTagsAll = ts2.getJSDocTags(node);
645
+ const jsDocTagsAll = ts.getJSDocTags(node);
700
646
  for (const tag of jsDocTagsAll) {
701
647
  const tagName = (0, import_core3.normalizeConstraintTagName)(tag.tagName.text);
702
648
  if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
@@ -719,7 +665,7 @@ function parseTSDocTags(node, file = "", options) {
719
665
  function extractDisplayNameMetadata(node) {
720
666
  let displayName;
721
667
  const memberDisplayNames = /* @__PURE__ */ new Map();
722
- for (const tag of ts2.getJSDocTags(node)) {
668
+ for (const tag of ts.getJSDocTags(node)) {
723
669
  const tagName = (0, import_core3.normalizeConstraintTagName)(tag.tagName.text);
724
670
  if (tagName !== "displayName") continue;
725
671
  const commentText = getTagCommentText(tag);
@@ -740,11 +686,11 @@ function extractDisplayNameMetadata(node) {
740
686
  }
741
687
  function extractPathTarget(text) {
742
688
  const trimmed = text.trimStart();
743
- const match = /^:([a-zA-Z_]\w*)\s+([\s\S]*)$/.exec(trimmed);
744
- if (!match?.[1] || !match[2]) return null;
689
+ const match = /^:([a-zA-Z_]\w*)(?:\s+([\s\S]*))?$/.exec(trimmed);
690
+ if (!match?.[1]) return null;
745
691
  return {
746
692
  path: { segments: [match[1]] },
747
- remainingText: match[2]
693
+ remainingText: match[2] ?? ""
748
694
  };
749
695
  }
750
696
  function extractBlockText(block) {
@@ -1007,7 +953,7 @@ function getTagCommentText(tag) {
1007
953
  if (typeof tag.comment === "string") {
1008
954
  return tag.comment;
1009
955
  }
1010
- return ts2.getTextOfJSDocComment(tag.comment);
956
+ return ts.getTextOfJSDocComment(tag.comment);
1011
957
  }
1012
958
 
1013
959
  // src/analyzer/jsdoc-constraints.ts
@@ -1022,18 +968,18 @@ function extractJSDocAnnotationNodes(node, file = "", options) {
1022
968
  function extractDefaultValueAnnotation(initializer, file = "") {
1023
969
  if (!initializer) return null;
1024
970
  let value;
1025
- if (ts3.isStringLiteral(initializer)) {
971
+ if (ts2.isStringLiteral(initializer)) {
1026
972
  value = initializer.text;
1027
- } else if (ts3.isNumericLiteral(initializer)) {
973
+ } else if (ts2.isNumericLiteral(initializer)) {
1028
974
  value = Number(initializer.text);
1029
- } else if (initializer.kind === ts3.SyntaxKind.TrueKeyword) {
975
+ } else if (initializer.kind === ts2.SyntaxKind.TrueKeyword) {
1030
976
  value = true;
1031
- } else if (initializer.kind === ts3.SyntaxKind.FalseKeyword) {
977
+ } else if (initializer.kind === ts2.SyntaxKind.FalseKeyword) {
1032
978
  value = false;
1033
- } else if (initializer.kind === ts3.SyntaxKind.NullKeyword) {
979
+ } else if (initializer.kind === ts2.SyntaxKind.NullKeyword) {
1034
980
  value = null;
1035
- } else if (ts3.isPrefixUnaryExpression(initializer)) {
1036
- if (initializer.operator === ts3.SyntaxKind.MinusToken && ts3.isNumericLiteral(initializer.operand)) {
981
+ } else if (ts2.isPrefixUnaryExpression(initializer)) {
982
+ if (initializer.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(initializer.operand)) {
1037
983
  value = -Number(initializer.operand.text);
1038
984
  }
1039
985
  }
@@ -1055,10 +1001,10 @@ function extractDefaultValueAnnotation(initializer, file = "") {
1055
1001
 
1056
1002
  // src/analyzer/class-analyzer.ts
1057
1003
  function isObjectType(type) {
1058
- return !!(type.flags & ts4.TypeFlags.Object);
1004
+ return !!(type.flags & ts3.TypeFlags.Object);
1059
1005
  }
1060
1006
  function isTypeReference(type) {
1061
- return !!(type.flags & ts4.TypeFlags.Object) && !!(type.objectFlags & ts4.ObjectFlags.Reference);
1007
+ return !!(type.flags & ts3.TypeFlags.Object) && !!(type.objectFlags & ts3.ObjectFlags.Reference);
1062
1008
  }
1063
1009
  var RESOLVING_TYPE_PLACEHOLDER = {
1064
1010
  kind: "object",
@@ -1088,7 +1034,7 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1088
1034
  const instanceMethods = [];
1089
1035
  const staticMethods = [];
1090
1036
  for (const member of classDecl.members) {
1091
- if (ts4.isPropertyDeclaration(member)) {
1037
+ if (ts3.isPropertyDeclaration(member)) {
1092
1038
  const fieldNode = analyzeFieldToIR(
1093
1039
  member,
1094
1040
  checker,
@@ -1101,10 +1047,10 @@ function analyzeClassToIR(classDecl, checker, file = "", extensionRegistry) {
1101
1047
  fields.push(fieldNode);
1102
1048
  fieldLayouts.push({});
1103
1049
  }
1104
- } else if (ts4.isMethodDeclaration(member)) {
1050
+ } else if (ts3.isMethodDeclaration(member)) {
1105
1051
  const methodInfo = analyzeMethod(member, checker);
1106
1052
  if (methodInfo) {
1107
- const isStatic = member.modifiers?.some((m) => m.kind === ts4.SyntaxKind.StaticKeyword);
1053
+ const isStatic = member.modifiers?.some((m) => m.kind === ts3.SyntaxKind.StaticKeyword);
1108
1054
  if (isStatic) {
1109
1055
  staticMethods.push(methodInfo);
1110
1056
  } else {
@@ -1134,7 +1080,7 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
1134
1080
  );
1135
1081
  const visiting = /* @__PURE__ */ new Set();
1136
1082
  for (const member of interfaceDecl.members) {
1137
- if (ts4.isPropertySignature(member)) {
1083
+ if (ts3.isPropertySignature(member)) {
1138
1084
  const fieldNode = analyzeInterfacePropertyToIR(
1139
1085
  member,
1140
1086
  checker,
@@ -1160,10 +1106,10 @@ function analyzeInterfaceToIR(interfaceDecl, checker, file = "", extensionRegist
1160
1106
  };
1161
1107
  }
1162
1108
  function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry) {
1163
- if (!ts4.isTypeLiteralNode(typeAlias.type)) {
1109
+ if (!ts3.isTypeLiteralNode(typeAlias.type)) {
1164
1110
  const sourceFile = typeAlias.getSourceFile();
1165
1111
  const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
1166
- const kindDesc = ts4.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1112
+ const kindDesc = ts3.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1167
1113
  return {
1168
1114
  ok: false,
1169
1115
  error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
@@ -1179,7 +1125,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
1179
1125
  );
1180
1126
  const visiting = /* @__PURE__ */ new Set();
1181
1127
  for (const member of typeAlias.type.members) {
1182
- if (ts4.isPropertySignature(member)) {
1128
+ if (ts3.isPropertySignature(member)) {
1183
1129
  const fieldNode = analyzeInterfacePropertyToIR(
1184
1130
  member,
1185
1131
  checker,
@@ -1207,7 +1153,7 @@ function analyzeTypeAliasToIR(typeAlias, checker, file = "", extensionRegistry)
1207
1153
  };
1208
1154
  }
1209
1155
  function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
1210
- if (!ts4.isIdentifier(prop.name)) {
1156
+ if (!ts3.isIdentifier(prop.name)) {
1211
1157
  return null;
1212
1158
  }
1213
1159
  const name = prop.name.text;
@@ -1224,12 +1170,14 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
1224
1170
  extensionRegistry
1225
1171
  );
1226
1172
  const constraints = [];
1227
- if (prop.type) {
1173
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
1228
1174
  constraints.push(
1229
1175
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
1230
1176
  );
1231
1177
  }
1232
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
1178
+ constraints.push(
1179
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
1180
+ );
1233
1181
  let annotations = [];
1234
1182
  annotations.push(
1235
1183
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -1250,7 +1198,7 @@ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting, extension
1250
1198
  };
1251
1199
  }
1252
1200
  function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting, extensionRegistry) {
1253
- if (!ts4.isIdentifier(prop.name)) {
1201
+ if (!ts3.isIdentifier(prop.name)) {
1254
1202
  return null;
1255
1203
  }
1256
1204
  const name = prop.name.text;
@@ -1267,12 +1215,14 @@ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visitin
1267
1215
  extensionRegistry
1268
1216
  );
1269
1217
  const constraints = [];
1270
- if (prop.type) {
1218
+ if (prop.type && !shouldEmitPrimitiveAliasDefinition(prop.type, checker)) {
1271
1219
  constraints.push(
1272
1220
  ...extractTypeAliasConstraintNodes(prop.type, checker, file, extensionRegistry)
1273
1221
  );
1274
1222
  }
1275
- constraints.push(...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type)));
1223
+ constraints.push(
1224
+ ...extractJSDocConstraintNodes(prop, file, makeParseOptions(extensionRegistry, type))
1225
+ );
1276
1226
  let annotations = [];
1277
1227
  annotations.push(
1278
1228
  ...extractJSDocAnnotationNodes(prop, file, makeParseOptions(extensionRegistry, type))
@@ -1361,7 +1311,7 @@ function resolveRegisteredCustomType(sourceNode, extensionRegistry, checker) {
1361
1311
  return resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker);
1362
1312
  }
1363
1313
  function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, checker) {
1364
- if (ts4.isParenthesizedTypeNode(typeNode)) {
1314
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
1365
1315
  return resolveRegisteredCustomTypeFromTypeNode(typeNode.type, extensionRegistry, checker);
1366
1316
  }
1367
1317
  const typeName = getTypeNodeRegistrationName(typeNode);
@@ -1376,8 +1326,8 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
1376
1326
  payload: null
1377
1327
  };
1378
1328
  }
1379
- if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
1380
- const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts4.isTypeAliasDeclaration);
1329
+ if (ts3.isTypeReferenceNode(typeNode) && ts3.isIdentifier(typeNode.typeName)) {
1330
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
1381
1331
  if (aliasDecl !== void 0) {
1382
1332
  return resolveRegisteredCustomTypeFromTypeNode(aliasDecl.type, extensionRegistry, checker);
1383
1333
  }
@@ -1385,22 +1335,22 @@ function resolveRegisteredCustomTypeFromTypeNode(typeNode, extensionRegistry, ch
1385
1335
  return null;
1386
1336
  }
1387
1337
  function extractTypeNodeFromSource(sourceNode) {
1388
- if (ts4.isPropertyDeclaration(sourceNode) || ts4.isPropertySignature(sourceNode) || ts4.isParameter(sourceNode) || ts4.isTypeAliasDeclaration(sourceNode)) {
1338
+ if (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode) || ts3.isTypeAliasDeclaration(sourceNode)) {
1389
1339
  return sourceNode.type;
1390
1340
  }
1391
- if (ts4.isTypeNode(sourceNode)) {
1341
+ if (ts3.isTypeNode(sourceNode)) {
1392
1342
  return sourceNode;
1393
1343
  }
1394
1344
  return void 0;
1395
1345
  }
1396
1346
  function getTypeNodeRegistrationName(typeNode) {
1397
- if (ts4.isTypeReferenceNode(typeNode)) {
1398
- return ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
1347
+ if (ts3.isTypeReferenceNode(typeNode)) {
1348
+ return ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : typeNode.typeName.right.text;
1399
1349
  }
1400
- if (ts4.isParenthesizedTypeNode(typeNode)) {
1350
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
1401
1351
  return getTypeNodeRegistrationName(typeNode.type);
1402
1352
  }
1403
- if (typeNode.kind === ts4.SyntaxKind.BigIntKeyword || typeNode.kind === ts4.SyntaxKind.StringKeyword || typeNode.kind === ts4.SyntaxKind.NumberKeyword || typeNode.kind === ts4.SyntaxKind.BooleanKeyword) {
1353
+ if (typeNode.kind === ts3.SyntaxKind.BigIntKeyword || typeNode.kind === ts3.SyntaxKind.StringKeyword || typeNode.kind === ts3.SyntaxKind.NumberKeyword || typeNode.kind === ts3.SyntaxKind.BooleanKeyword) {
1404
1354
  return typeNode.getText();
1405
1355
  }
1406
1356
  return null;
@@ -1410,19 +1360,34 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
1410
1360
  if (customType) {
1411
1361
  return customType;
1412
1362
  }
1413
- if (type.flags & ts4.TypeFlags.String) {
1363
+ const primitiveAlias = tryResolveNamedPrimitiveAlias(
1364
+ type,
1365
+ checker,
1366
+ file,
1367
+ typeRegistry,
1368
+ visiting,
1369
+ sourceNode,
1370
+ extensionRegistry
1371
+ );
1372
+ if (primitiveAlias) {
1373
+ return primitiveAlias;
1374
+ }
1375
+ if (type.flags & ts3.TypeFlags.String) {
1414
1376
  return { kind: "primitive", primitiveKind: "string" };
1415
1377
  }
1416
- if (type.flags & ts4.TypeFlags.Number) {
1378
+ if (type.flags & ts3.TypeFlags.Number) {
1417
1379
  return { kind: "primitive", primitiveKind: "number" };
1418
1380
  }
1419
- if (type.flags & ts4.TypeFlags.Boolean) {
1381
+ if (type.flags & (ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral)) {
1382
+ return { kind: "primitive", primitiveKind: "bigint" };
1383
+ }
1384
+ if (type.flags & ts3.TypeFlags.Boolean) {
1420
1385
  return { kind: "primitive", primitiveKind: "boolean" };
1421
1386
  }
1422
- if (type.flags & ts4.TypeFlags.Null) {
1387
+ if (type.flags & ts3.TypeFlags.Null) {
1423
1388
  return { kind: "primitive", primitiveKind: "null" };
1424
1389
  }
1425
- if (type.flags & ts4.TypeFlags.Undefined) {
1390
+ if (type.flags & ts3.TypeFlags.Undefined) {
1426
1391
  return { kind: "primitive", primitiveKind: "null" };
1427
1392
  }
1428
1393
  if (type.isStringLiteral()) {
@@ -1464,6 +1429,75 @@ function resolveTypeNode(type, checker, file, typeRegistry, visiting, sourceNode
1464
1429
  }
1465
1430
  return { kind: "primitive", primitiveKind: "string" };
1466
1431
  }
1432
+ function tryResolveNamedPrimitiveAlias(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
1433
+ if (!(type.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null))) {
1434
+ return null;
1435
+ }
1436
+ const aliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration) ?? getReferencedTypeAliasDeclaration(sourceNode, checker);
1437
+ if (!aliasDecl) {
1438
+ return null;
1439
+ }
1440
+ const aliasName = aliasDecl.name.text;
1441
+ if (!typeRegistry[aliasName]) {
1442
+ const aliasType = checker.getTypeFromTypeNode(aliasDecl.type);
1443
+ const constraints = [
1444
+ ...extractJSDocConstraintNodes(aliasDecl, file, makeParseOptions(extensionRegistry)),
1445
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry)
1446
+ ];
1447
+ const annotations = extractJSDocAnnotationNodes(
1448
+ aliasDecl,
1449
+ file,
1450
+ makeParseOptions(extensionRegistry)
1451
+ );
1452
+ typeRegistry[aliasName] = {
1453
+ name: aliasName,
1454
+ type: resolveAliasedPrimitiveTarget(
1455
+ aliasType,
1456
+ checker,
1457
+ file,
1458
+ typeRegistry,
1459
+ visiting,
1460
+ extensionRegistry
1461
+ ),
1462
+ ...constraints.length > 0 && { constraints },
1463
+ ...annotations.length > 0 && { annotations },
1464
+ provenance: provenanceForDeclaration(aliasDecl, file)
1465
+ };
1466
+ }
1467
+ return { kind: "reference", name: aliasName, typeArguments: [] };
1468
+ }
1469
+ function getReferencedTypeAliasDeclaration(sourceNode, checker) {
1470
+ const typeNode = sourceNode && (ts3.isPropertyDeclaration(sourceNode) || ts3.isPropertySignature(sourceNode) || ts3.isParameter(sourceNode)) ? sourceNode.type : void 0;
1471
+ if (!typeNode || !ts3.isTypeReferenceNode(typeNode)) {
1472
+ return void 0;
1473
+ }
1474
+ return checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
1475
+ }
1476
+ function shouldEmitPrimitiveAliasDefinition(typeNode, checker) {
1477
+ if (!ts3.isTypeReferenceNode(typeNode)) {
1478
+ return false;
1479
+ }
1480
+ const aliasDecl = checker.getSymbolAtLocation(typeNode.typeName)?.declarations?.find(ts3.isTypeAliasDeclaration);
1481
+ if (!aliasDecl) {
1482
+ return false;
1483
+ }
1484
+ const resolved = checker.getTypeFromTypeNode(aliasDecl.type);
1485
+ return !!(resolved.flags & (ts3.TypeFlags.String | ts3.TypeFlags.Number | ts3.TypeFlags.BigInt | ts3.TypeFlags.BigIntLiteral | ts3.TypeFlags.Boolean | ts3.TypeFlags.Null));
1486
+ }
1487
+ function resolveAliasedPrimitiveTarget(type, checker, file, typeRegistry, visiting, extensionRegistry) {
1488
+ const nestedAliasDecl = type.aliasSymbol?.declarations?.find(ts3.isTypeAliasDeclaration);
1489
+ if (nestedAliasDecl !== void 0) {
1490
+ return resolveAliasedPrimitiveTarget(
1491
+ checker.getTypeFromTypeNode(nestedAliasDecl.type),
1492
+ checker,
1493
+ file,
1494
+ typeRegistry,
1495
+ visiting,
1496
+ extensionRegistry
1497
+ );
1498
+ }
1499
+ return resolveTypeNode(type, checker, file, typeRegistry, visiting, void 0, extensionRegistry);
1500
+ }
1467
1501
  function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNode, extensionRegistry) {
1468
1502
  const typeName = getNamedTypeName(type);
1469
1503
  const namedDecl = getNamedTypeDeclaration(type);
@@ -1476,13 +1510,13 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
1476
1510
  (memberTypeNode) => !isNullishTypeNode(resolveAliasedTypeNode(memberTypeNode, checker))
1477
1511
  );
1478
1512
  const nonNullTypes = allTypes.filter(
1479
- (memberType) => !(memberType.flags & (ts4.TypeFlags.Null | ts4.TypeFlags.Undefined))
1513
+ (memberType) => !(memberType.flags & (ts3.TypeFlags.Null | ts3.TypeFlags.Undefined))
1480
1514
  );
1481
1515
  const nonNullMembers = nonNullTypes.map((memberType, index) => ({
1482
1516
  memberType,
1483
1517
  sourceNode: nonNullSourceNodes.length === nonNullTypes.length ? nonNullSourceNodes[index] : void 0
1484
1518
  }));
1485
- const hasNull = allTypes.some((t) => t.flags & ts4.TypeFlags.Null);
1519
+ const hasNull = allTypes.some((t) => t.flags & ts3.TypeFlags.Null);
1486
1520
  const memberDisplayNames = /* @__PURE__ */ new Map();
1487
1521
  if (namedDecl) {
1488
1522
  for (const [value, label] of extractDisplayNameMetadata(namedDecl).memberDisplayNames) {
@@ -1511,7 +1545,7 @@ function resolveUnionType(type, checker, file, typeRegistry, visiting, sourceNod
1511
1545
  const displayName = memberDisplayNames.get(String(value));
1512
1546
  return displayName !== void 0 ? { value, displayName } : { value };
1513
1547
  });
1514
- const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts4.TypeFlags.BooleanLiteral);
1548
+ const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts3.TypeFlags.BooleanLiteral);
1515
1549
  if (isBooleanUnion2) {
1516
1550
  const boolNode = { kind: "primitive", primitiveKind: "boolean" };
1517
1551
  const result = hasNull ? {
@@ -1597,7 +1631,7 @@ function tryResolveRecordType(type, checker, file, typeRegistry, visiting, exten
1597
1631
  if (type.getProperties().length > 0) {
1598
1632
  return null;
1599
1633
  }
1600
- const indexInfo = checker.getIndexInfoOfType(type, ts4.IndexKind.String);
1634
+ const indexInfo = checker.getIndexInfoOfType(type, ts3.IndexKind.String);
1601
1635
  if (!indexInfo) {
1602
1636
  return null;
1603
1637
  }
@@ -1708,7 +1742,7 @@ function resolveObjectType(type, checker, file, typeRegistry, visiting, extensio
1708
1742
  const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
1709
1743
  if (!declaration) continue;
1710
1744
  const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
1711
- const optional = !!(prop.flags & ts4.SymbolFlags.Optional);
1745
+ const optional = !!(prop.flags & ts3.SymbolFlags.Optional);
1712
1746
  const propTypeNode = resolveTypeNode(
1713
1747
  propType,
1714
1748
  checker,
@@ -1753,11 +1787,11 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
1753
1787
  for (const symbol of symbols) {
1754
1788
  const declarations = symbol.declarations;
1755
1789
  if (!declarations) continue;
1756
- const classDecl = declarations.find(ts4.isClassDeclaration);
1790
+ const classDecl = declarations.find(ts3.isClassDeclaration);
1757
1791
  if (classDecl) {
1758
1792
  const map = /* @__PURE__ */ new Map();
1759
1793
  for (const member of classDecl.members) {
1760
- if (ts4.isPropertyDeclaration(member) && ts4.isIdentifier(member.name)) {
1794
+ if (ts3.isPropertyDeclaration(member) && ts3.isIdentifier(member.name)) {
1761
1795
  const fieldNode = analyzeFieldToIR(
1762
1796
  member,
1763
1797
  checker,
@@ -1777,7 +1811,7 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
1777
1811
  }
1778
1812
  return map;
1779
1813
  }
1780
- const interfaceDecl = declarations.find(ts4.isInterfaceDeclaration);
1814
+ const interfaceDecl = declarations.find(ts3.isInterfaceDeclaration);
1781
1815
  if (interfaceDecl) {
1782
1816
  return buildFieldNodeInfoMap(
1783
1817
  interfaceDecl.members,
@@ -1788,8 +1822,8 @@ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visitin
1788
1822
  extensionRegistry
1789
1823
  );
1790
1824
  }
1791
- const typeAliasDecl = declarations.find(ts4.isTypeAliasDeclaration);
1792
- if (typeAliasDecl && ts4.isTypeLiteralNode(typeAliasDecl.type)) {
1825
+ const typeAliasDecl = declarations.find(ts3.isTypeAliasDeclaration);
1826
+ if (typeAliasDecl && ts3.isTypeLiteralNode(typeAliasDecl.type)) {
1793
1827
  return buildFieldNodeInfoMap(
1794
1828
  typeAliasDecl.type.members,
1795
1829
  checker,
@@ -1808,10 +1842,10 @@ function extractArrayElementTypeNode(sourceNode, checker) {
1808
1842
  return void 0;
1809
1843
  }
1810
1844
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
1811
- if (ts4.isArrayTypeNode(resolvedTypeNode)) {
1845
+ if (ts3.isArrayTypeNode(resolvedTypeNode)) {
1812
1846
  return resolvedTypeNode.elementType;
1813
1847
  }
1814
- if (ts4.isTypeReferenceNode(resolvedTypeNode) && ts4.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
1848
+ if (ts3.isTypeReferenceNode(resolvedTypeNode) && ts3.isIdentifier(resolvedTypeNode.typeName) && resolvedTypeNode.typeName.text === "Array" && resolvedTypeNode.typeArguments?.[0]) {
1815
1849
  return resolvedTypeNode.typeArguments[0];
1816
1850
  }
1817
1851
  return void 0;
@@ -1822,17 +1856,17 @@ function extractUnionMemberTypeNodes(sourceNode, checker) {
1822
1856
  return [];
1823
1857
  }
1824
1858
  const resolvedTypeNode = resolveAliasedTypeNode(typeNode, checker);
1825
- return ts4.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
1859
+ return ts3.isUnionTypeNode(resolvedTypeNode) ? [...resolvedTypeNode.types] : [];
1826
1860
  }
1827
1861
  function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
1828
- if (ts4.isParenthesizedTypeNode(typeNode)) {
1862
+ if (ts3.isParenthesizedTypeNode(typeNode)) {
1829
1863
  return resolveAliasedTypeNode(typeNode.type, checker, visited);
1830
1864
  }
1831
- if (!ts4.isTypeReferenceNode(typeNode) || !ts4.isIdentifier(typeNode.typeName)) {
1865
+ if (!ts3.isTypeReferenceNode(typeNode) || !ts3.isIdentifier(typeNode.typeName)) {
1832
1866
  return typeNode;
1833
1867
  }
1834
1868
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
1835
- const aliasDecl = symbol?.declarations?.find(ts4.isTypeAliasDeclaration);
1869
+ const aliasDecl = symbol?.declarations?.find(ts3.isTypeAliasDeclaration);
1836
1870
  if (aliasDecl === void 0 || visited.has(aliasDecl)) {
1837
1871
  return typeNode;
1838
1872
  }
@@ -1840,15 +1874,15 @@ function resolveAliasedTypeNode(typeNode, checker, visited = /* @__PURE__ */ new
1840
1874
  return resolveAliasedTypeNode(aliasDecl.type, checker, visited);
1841
1875
  }
1842
1876
  function isNullishTypeNode(typeNode) {
1843
- if (typeNode.kind === ts4.SyntaxKind.NullKeyword || typeNode.kind === ts4.SyntaxKind.UndefinedKeyword) {
1877
+ if (typeNode.kind === ts3.SyntaxKind.NullKeyword || typeNode.kind === ts3.SyntaxKind.UndefinedKeyword) {
1844
1878
  return true;
1845
1879
  }
1846
- return ts4.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts4.SyntaxKind.NullKeyword || typeNode.literal.kind === ts4.SyntaxKind.UndefinedKeyword);
1880
+ return ts3.isLiteralTypeNode(typeNode) && (typeNode.literal.kind === ts3.SyntaxKind.NullKeyword || typeNode.literal.kind === ts3.SyntaxKind.UndefinedKeyword);
1847
1881
  }
1848
1882
  function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, extensionRegistry) {
1849
1883
  const map = /* @__PURE__ */ new Map();
1850
1884
  for (const member of members) {
1851
- if (ts4.isPropertySignature(member)) {
1885
+ if (ts3.isPropertySignature(member)) {
1852
1886
  const fieldNode = analyzeInterfacePropertyToIR(
1853
1887
  member,
1854
1888
  checker,
@@ -1870,7 +1904,7 @@ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting, e
1870
1904
  }
1871
1905
  var MAX_ALIAS_CHAIN_DEPTH = 8;
1872
1906
  function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegistry, depth = 0) {
1873
- if (!ts4.isTypeReferenceNode(typeNode)) return [];
1907
+ if (!ts3.isTypeReferenceNode(typeNode)) return [];
1874
1908
  if (depth >= MAX_ALIAS_CHAIN_DEPTH) {
1875
1909
  const aliasName = typeNode.typeName.getText();
1876
1910
  throw new Error(
@@ -1879,9 +1913,9 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
1879
1913
  }
1880
1914
  const symbol = checker.getSymbolAtLocation(typeNode.typeName);
1881
1915
  if (!symbol?.declarations) return [];
1882
- const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
1916
+ const aliasDecl = symbol.declarations.find(ts3.isTypeAliasDeclaration);
1883
1917
  if (!aliasDecl) return [];
1884
- if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
1918
+ if (ts3.isTypeLiteralNode(aliasDecl.type)) return [];
1885
1919
  const aliasFieldType = resolveTypeNode(
1886
1920
  checker.getTypeAtLocation(aliasDecl.type),
1887
1921
  checker,
@@ -1897,13 +1931,7 @@ function extractTypeAliasConstraintNodes(typeNode, checker, file, extensionRegis
1897
1931
  makeParseOptions(extensionRegistry, aliasFieldType)
1898
1932
  );
1899
1933
  constraints.push(
1900
- ...extractTypeAliasConstraintNodes(
1901
- aliasDecl.type,
1902
- checker,
1903
- file,
1904
- extensionRegistry,
1905
- depth + 1
1906
- )
1934
+ ...extractTypeAliasConstraintNodes(aliasDecl.type, checker, file, extensionRegistry, depth + 1)
1907
1935
  );
1908
1936
  return constraints;
1909
1937
  }
@@ -1930,14 +1958,14 @@ function getNamedTypeName(type) {
1930
1958
  const symbol = type.getSymbol();
1931
1959
  if (symbol?.declarations) {
1932
1960
  const decl = symbol.declarations[0];
1933
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
1934
- const name = ts4.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
1961
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
1962
+ const name = ts3.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
1935
1963
  if (name) return name;
1936
1964
  }
1937
1965
  }
1938
1966
  const aliasSymbol = type.aliasSymbol;
1939
1967
  if (aliasSymbol?.declarations) {
1940
- const aliasDecl = aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
1968
+ const aliasDecl = aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
1941
1969
  if (aliasDecl) {
1942
1970
  return aliasDecl.name.text;
1943
1971
  }
@@ -1948,24 +1976,24 @@ function getNamedTypeDeclaration(type) {
1948
1976
  const symbol = type.getSymbol();
1949
1977
  if (symbol?.declarations) {
1950
1978
  const decl = symbol.declarations[0];
1951
- if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
1979
+ if (decl && (ts3.isClassDeclaration(decl) || ts3.isInterfaceDeclaration(decl) || ts3.isTypeAliasDeclaration(decl))) {
1952
1980
  return decl;
1953
1981
  }
1954
1982
  }
1955
1983
  const aliasSymbol = type.aliasSymbol;
1956
1984
  if (aliasSymbol?.declarations) {
1957
- return aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
1985
+ return aliasSymbol.declarations.find(ts3.isTypeAliasDeclaration);
1958
1986
  }
1959
1987
  return void 0;
1960
1988
  }
1961
1989
  function analyzeMethod(method, checker) {
1962
- if (!ts4.isIdentifier(method.name)) {
1990
+ if (!ts3.isIdentifier(method.name)) {
1963
1991
  return null;
1964
1992
  }
1965
1993
  const name = method.name.text;
1966
1994
  const parameters = [];
1967
1995
  for (const param of method.parameters) {
1968
- if (ts4.isIdentifier(param.name)) {
1996
+ if (ts3.isIdentifier(param.name)) {
1969
1997
  const paramInfo = analyzeParameter(param, checker);
1970
1998
  parameters.push(paramInfo);
1971
1999
  }
@@ -1976,7 +2004,7 @@ function analyzeMethod(method, checker) {
1976
2004
  return { name, parameters, returnTypeNode, returnType };
1977
2005
  }
1978
2006
  function analyzeParameter(param, checker) {
1979
- const name = ts4.isIdentifier(param.name) ? param.name.text : "param";
2007
+ const name = ts3.isIdentifier(param.name) ? param.name.text : "param";
1980
2008
  const typeNode = param.type;
1981
2009
  const type = checker.getTypeAtLocation(param);
1982
2010
  const formSpecExportName = detectFormSpecReference(typeNode);
@@ -1985,20 +2013,90 @@ function analyzeParameter(param, checker) {
1985
2013
  }
1986
2014
  function detectFormSpecReference(typeNode) {
1987
2015
  if (!typeNode) return null;
1988
- if (!ts4.isTypeReferenceNode(typeNode)) return null;
1989
- const typeName = ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts4.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
2016
+ if (!ts3.isTypeReferenceNode(typeNode)) return null;
2017
+ const typeName = ts3.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts3.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
1990
2018
  if (typeName !== "InferSchema" && typeName !== "InferFormSchema") return null;
1991
2019
  const typeArg = typeNode.typeArguments?.[0];
1992
- if (!typeArg || !ts4.isTypeQueryNode(typeArg)) return null;
1993
- if (ts4.isIdentifier(typeArg.exprName)) {
2020
+ if (!typeArg || !ts3.isTypeQueryNode(typeArg)) return null;
2021
+ if (ts3.isIdentifier(typeArg.exprName)) {
1994
2022
  return typeArg.exprName.text;
1995
2023
  }
1996
- if (ts4.isQualifiedName(typeArg.exprName)) {
2024
+ if (ts3.isQualifiedName(typeArg.exprName)) {
1997
2025
  return typeArg.exprName.right.text;
1998
2026
  }
1999
2027
  return null;
2000
2028
  }
2001
2029
 
2030
+ // src/analyzer/program.ts
2031
+ function createProgramContext(filePath) {
2032
+ const absolutePath = path.resolve(filePath);
2033
+ const fileDir = path.dirname(absolutePath);
2034
+ const configPath = ts4.findConfigFile(fileDir, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.json");
2035
+ let compilerOptions;
2036
+ let fileNames;
2037
+ if (configPath) {
2038
+ const configFile = ts4.readConfigFile(configPath, ts4.sys.readFile.bind(ts4.sys));
2039
+ if (configFile.error) {
2040
+ throw new Error(
2041
+ `Error reading tsconfig.json: ${ts4.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
2042
+ );
2043
+ }
2044
+ const parsed = ts4.parseJsonConfigFileContent(
2045
+ configFile.config,
2046
+ ts4.sys,
2047
+ path.dirname(configPath)
2048
+ );
2049
+ if (parsed.errors.length > 0) {
2050
+ const errorMessages = parsed.errors.map((e) => ts4.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
2051
+ throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
2052
+ }
2053
+ compilerOptions = parsed.options;
2054
+ fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
2055
+ } else {
2056
+ compilerOptions = {
2057
+ target: ts4.ScriptTarget.ES2022,
2058
+ module: ts4.ModuleKind.NodeNext,
2059
+ moduleResolution: ts4.ModuleResolutionKind.NodeNext,
2060
+ strict: true,
2061
+ skipLibCheck: true,
2062
+ declaration: true
2063
+ };
2064
+ fileNames = [absolutePath];
2065
+ }
2066
+ const program = ts4.createProgram(fileNames, compilerOptions);
2067
+ const sourceFile = program.getSourceFile(absolutePath);
2068
+ if (!sourceFile) {
2069
+ throw new Error(`Could not find source file: ${absolutePath}`);
2070
+ }
2071
+ return {
2072
+ program,
2073
+ checker: program.getTypeChecker(),
2074
+ sourceFile
2075
+ };
2076
+ }
2077
+ function findNodeByName(sourceFile, name, predicate, getName) {
2078
+ let result = null;
2079
+ function visit(node) {
2080
+ if (result) return;
2081
+ if (predicate(node) && getName(node) === name) {
2082
+ result = node;
2083
+ return;
2084
+ }
2085
+ ts4.forEachChild(node, visit);
2086
+ }
2087
+ visit(sourceFile);
2088
+ return result;
2089
+ }
2090
+ function findClassByName(sourceFile, className) {
2091
+ return findNodeByName(sourceFile, className, ts4.isClassDeclaration, (n) => n.name?.text);
2092
+ }
2093
+ function findInterfaceByName(sourceFile, interfaceName) {
2094
+ return findNodeByName(sourceFile, interfaceName, ts4.isInterfaceDeclaration, (n) => n.name.text);
2095
+ }
2096
+ function findTypeAliasByName(sourceFile, aliasName) {
2097
+ return findNodeByName(sourceFile, aliasName, ts4.isTypeAliasDeclaration, (n) => n.name.text);
2098
+ }
2099
+
2002
2100
  // src/json-schema/ir-generator.ts
2003
2101
  function makeContext(options) {
2004
2102
  const vendorPrefix = options?.vendorPrefix ?? "x-formspec";
@@ -2017,6 +2115,9 @@ function generateJsonSchemaFromIR(ir, options) {
2017
2115
  const ctx = makeContext(options);
2018
2116
  for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
2019
2117
  ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
2118
+ if (typeDef.constraints && typeDef.constraints.length > 0) {
2119
+ applyConstraints(ctx.defs[name], typeDef.constraints, ctx);
2120
+ }
2020
2121
  if (typeDef.annotations && typeDef.annotations.length > 0) {
2021
2122
  applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);
2022
2123
  }
@@ -2185,7 +2286,9 @@ function generateTypeNode(type, ctx) {
2185
2286
  }
2186
2287
  }
2187
2288
  function generatePrimitiveType(type) {
2188
- return { type: type.primitiveKind };
2289
+ return {
2290
+ type: type.primitiveKind === "integer" || type.primitiveKind === "bigint" ? "integer" : type.primitiveKind
2291
+ };
2189
2292
  }
2190
2293
  function generateEnumType(type) {
2191
2294
  const hasDisplayNames = type.members.some((m) => m.displayName !== void 0);
@@ -2358,7 +2461,7 @@ function applyAnnotations(schema, annotations, ctx) {
2358
2461
  case "deprecated":
2359
2462
  schema.deprecated = true;
2360
2463
  if (annotation.message !== void 0 && annotation.message !== "") {
2361
- schema["x-formspec-deprecation-description"] = annotation.message;
2464
+ schema[`${ctx.vendorPrefix}-deprecation-description`] = annotation.message;
2362
2465
  }
2363
2466
  break;
2364
2467
  case "placeholder":
@@ -2649,15 +2752,6 @@ function generateUiSchemaFromIR(ir) {
2649
2752
  return parseOrThrow(uiSchema, result, "UI Schema");
2650
2753
  }
2651
2754
 
2652
- // src/generators/class-schema.ts
2653
- function generateClassSchemas(analysis, source, options) {
2654
- const ir = canonicalizeTSDoc(analysis, source);
2655
- return {
2656
- jsonSchema: generateJsonSchemaFromIR(ir, options),
2657
- uiSchema: generateUiSchemaFromIR(ir)
2658
- };
2659
- }
2660
-
2661
2755
  // src/validate/constraint-validator.ts
2662
2756
  var import_core4 = require("@formspec/core");
2663
2757
  function addContradiction(ctx, message, primary, related) {
@@ -3135,6 +3229,26 @@ function dereferenceType(ctx, type) {
3135
3229
  }
3136
3230
  return current;
3137
3231
  }
3232
+ function collectReferencedTypeConstraints(ctx, type) {
3233
+ const collected = [];
3234
+ let current = type;
3235
+ const seen = /* @__PURE__ */ new Set();
3236
+ while (current.kind === "reference") {
3237
+ if (seen.has(current.name)) {
3238
+ break;
3239
+ }
3240
+ seen.add(current.name);
3241
+ const definition = ctx.typeRegistry[current.name];
3242
+ if (definition === void 0) {
3243
+ break;
3244
+ }
3245
+ if (definition.constraints !== void 0) {
3246
+ collected.push(...definition.constraints);
3247
+ }
3248
+ current = definition.type;
3249
+ }
3250
+ return collected;
3251
+ }
3138
3252
  function resolvePathTargetType(ctx, type, segments) {
3139
3253
  const effectiveType = dereferenceType(ctx, type);
3140
3254
  if (segments.length === 0) {
@@ -3156,12 +3270,33 @@ function resolvePathTargetType(ctx, type, segments) {
3156
3270
  }
3157
3271
  return { kind: "unresolvable", type: effectiveType };
3158
3272
  }
3273
+ function isNullType(type) {
3274
+ return type.kind === "primitive" && type.primitiveKind === "null";
3275
+ }
3276
+ function collectCustomConstraintCandidateTypes(ctx, type) {
3277
+ const effectiveType = dereferenceType(ctx, type);
3278
+ const candidates = [effectiveType];
3279
+ if (effectiveType.kind === "array") {
3280
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, effectiveType.items));
3281
+ }
3282
+ if (effectiveType.kind === "union") {
3283
+ const memberTypes = effectiveType.members.map((member) => dereferenceType(ctx, member));
3284
+ const nonNullMembers = memberTypes.filter((member) => !isNullType(member));
3285
+ if (nonNullMembers.length === 1 && nonNullMembers.length < memberTypes.length) {
3286
+ const [nullableMember] = nonNullMembers;
3287
+ if (nullableMember !== void 0) {
3288
+ candidates.push(...collectCustomConstraintCandidateTypes(ctx, nullableMember));
3289
+ }
3290
+ }
3291
+ }
3292
+ return candidates;
3293
+ }
3159
3294
  function formatPathTargetFieldName(fieldName, path2) {
3160
3295
  return path2.length === 0 ? fieldName : `${fieldName}.${path2.join(".")}`;
3161
3296
  }
3162
3297
  function checkConstraintOnType(ctx, fieldName, type, constraint) {
3163
3298
  const effectiveType = dereferenceType(ctx, type);
3164
- const isNumber = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "number";
3299
+ const isNumber = effectiveType.kind === "primitive" && ["number", "integer", "bigint"].includes(effectiveType.primitiveKind);
3165
3300
  const isString = effectiveType.kind === "primitive" && effectiveType.primitiveKind === "string";
3166
3301
  const isArray = effectiveType.kind === "array";
3167
3302
  const isEnum = effectiveType.kind === "enum";
@@ -3219,7 +3354,9 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
3219
3354
  break;
3220
3355
  }
3221
3356
  case "const": {
3222
- const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "boolean", "null"].includes(effectiveType.primitiveKind) || effectiveType.kind === "enum";
3357
+ const isPrimitiveConstType = effectiveType.kind === "primitive" && ["string", "number", "integer", "bigint", "boolean", "null"].includes(
3358
+ effectiveType.primitiveKind
3359
+ ) || effectiveType.kind === "enum";
3223
3360
  if (!isPrimitiveConstType) {
3224
3361
  addTypeMismatch(
3225
3362
  ctx,
@@ -3230,7 +3367,8 @@ function checkConstraintOnType(ctx, fieldName, type, constraint) {
3230
3367
  }
3231
3368
  if (effectiveType.kind === "primitive") {
3232
3369
  const valueType = constraint.value === null ? "null" : Array.isArray(constraint.value) ? "array" : typeof constraint.value;
3233
- if (valueType !== effectiveType.primitiveKind) {
3370
+ const expectedValueType = effectiveType.primitiveKind === "integer" || effectiveType.primitiveKind === "bigint" ? "number" : effectiveType.primitiveKind;
3371
+ if (valueType !== expectedValueType) {
3234
3372
  addTypeMismatch(
3235
3373
  ctx,
3236
3374
  `Field "${fieldName}": @const value type "${valueType}" is incompatible with field type "${effectiveType.primitiveKind}"`,
@@ -3299,11 +3437,14 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3299
3437
  );
3300
3438
  return;
3301
3439
  }
3440
+ const candidateTypes = collectCustomConstraintCandidateTypes(ctx, type);
3302
3441
  const normalizedTagName = constraint.provenance.tagName === void 0 ? void 0 : (0, import_core4.normalizeConstraintTagName)(constraint.provenance.tagName.replace(/^@/, ""));
3303
3442
  if (normalizedTagName !== void 0) {
3304
3443
  const tagRegistration = ctx.extensionRegistry.findConstraintTag(normalizedTagName);
3305
3444
  const extensionId = getExtensionIdFromConstraintId(constraint.constraintId);
3306
- if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && tagRegistration.registration.isApplicableToType?.(type) === false) {
3445
+ if (extensionId !== null && tagRegistration?.extensionId === extensionId && tagRegistration.registration.constraintName === registration.constraintName && !candidateTypes.some(
3446
+ (candidateType) => tagRegistration.registration.isApplicableToType?.(candidateType) !== false
3447
+ )) {
3307
3448
  addTypeMismatch(
3308
3449
  ctx,
3309
3450
  `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
@@ -3313,7 +3454,7 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3313
3454
  }
3314
3455
  }
3315
3456
  if (registration.applicableTypes === null) {
3316
- if (registration.isApplicableToType?.(type) === false) {
3457
+ if (!candidateTypes.some((candidateType) => registration.isApplicableToType?.(candidateType) !== false)) {
3317
3458
  addTypeMismatch(
3318
3459
  ctx,
3319
3460
  `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
@@ -3322,7 +3463,11 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3322
3463
  }
3323
3464
  return;
3324
3465
  }
3325
- if (!registration.applicableTypes.includes(type.kind) || registration.isApplicableToType?.(type) === false) {
3466
+ const applicableTypes = registration.applicableTypes;
3467
+ const matchesApplicableType = candidateTypes.some(
3468
+ (candidateType) => applicableTypes.includes(candidateType.kind) && registration.isApplicableToType?.(candidateType) !== false
3469
+ );
3470
+ if (!matchesApplicableType) {
3326
3471
  addTypeMismatch(
3327
3472
  ctx,
3328
3473
  `Field "${fieldName}": custom constraint "${constraint.constraintId}" is not applicable to type "${typeLabel(type)}"`,
@@ -3331,7 +3476,10 @@ function checkCustomConstraint(ctx, fieldName, type, constraint) {
3331
3476
  }
3332
3477
  }
3333
3478
  function validateFieldNode(ctx, field) {
3334
- validateConstraints(ctx, field.name, field.type, field.constraints);
3479
+ validateConstraints(ctx, field.name, field.type, [
3480
+ ...collectReferencedTypeConstraints(ctx, field.type),
3481
+ ...field.constraints
3482
+ ]);
3335
3483
  if (field.type.kind === "object") {
3336
3484
  for (const prop of field.type.properties) {
3337
3485
  validateObjectProperty(ctx, field.name, prop);
@@ -3340,7 +3488,10 @@ function validateFieldNode(ctx, field) {
3340
3488
  }
3341
3489
  function validateObjectProperty(ctx, parentName, prop) {
3342
3490
  const qualifiedName = `${parentName}.${prop.name}`;
3343
- validateConstraints(ctx, qualifiedName, prop.type, prop.constraints);
3491
+ validateConstraints(ctx, qualifiedName, prop.type, [
3492
+ ...collectReferencedTypeConstraints(ctx, prop.type),
3493
+ ...prop.constraints
3494
+ ]);
3344
3495
  if (prop.type.kind === "object") {
3345
3496
  for (const nestedProp of prop.type.properties) {
3346
3497
  validateObjectProperty(ctx, qualifiedName, nestedProp);
@@ -3392,6 +3543,36 @@ function validateIR(ir, options) {
3392
3543
  };
3393
3544
  }
3394
3545
 
3546
+ // src/generators/class-schema.ts
3547
+ function generateClassSchemas(analysis, source, options) {
3548
+ const ir = canonicalizeTSDoc(analysis, source);
3549
+ const validationResult = validateIR(ir, {
3550
+ ...options?.extensionRegistry !== void 0 && {
3551
+ extensionRegistry: options.extensionRegistry
3552
+ },
3553
+ ...options?.vendorPrefix !== void 0 && { vendorPrefix: options.vendorPrefix }
3554
+ });
3555
+ if (!validationResult.valid) {
3556
+ throw new Error(formatValidationError(validationResult.diagnostics));
3557
+ }
3558
+ return {
3559
+ jsonSchema: generateJsonSchemaFromIR(ir, options),
3560
+ uiSchema: generateUiSchemaFromIR(ir)
3561
+ };
3562
+ }
3563
+ function formatValidationError(diagnostics) {
3564
+ const lines = diagnostics.map((diagnostic) => {
3565
+ const primary = formatLocation(diagnostic.primaryLocation);
3566
+ const related = diagnostic.relatedLocations.length > 0 ? ` [related: ${diagnostic.relatedLocations.map(formatLocation).join(", ")}]` : "";
3567
+ return `${diagnostic.code}: ${diagnostic.message} (${primary})${related}`;
3568
+ });
3569
+ return `FormSpec validation failed:
3570
+ ${lines.map((line) => `- ${line}`).join("\n")}`;
3571
+ }
3572
+ function formatLocation(location) {
3573
+ return `${location.file}:${String(location.line)}:${String(location.column)}`;
3574
+ }
3575
+
3395
3576
  // src/extensions/registry.ts
3396
3577
  function createExtensionRegistry(extensions) {
3397
3578
  const typeMap = /* @__PURE__ */ new Map();
@@ -3493,6 +3674,7 @@ function typeToJsonSchema(type, checker) {
3493
3674
  provenance: fieldProvenance
3494
3675
  }
3495
3676
  ],
3677
+ rootAnnotations: [],
3496
3678
  typeRegistry,
3497
3679
  provenance: fieldProvenance
3498
3680
  };