@openpkg-ts/extract 0.23.2 → 0.24.0

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.
@@ -89,9 +89,76 @@ var BUILTIN_TYPES = new Set([
89
89
  "BigInt64Array",
90
90
  "BigUint64Array"
91
91
  ]);
92
+ var ARRAY_PROTOTYPE_METHODS = new Set([
93
+ "pop",
94
+ "push",
95
+ "shift",
96
+ "unshift",
97
+ "splice",
98
+ "sort",
99
+ "reverse",
100
+ "fill",
101
+ "copyWithin",
102
+ "concat",
103
+ "join",
104
+ "slice",
105
+ "indexOf",
106
+ "lastIndexOf",
107
+ "includes",
108
+ "find",
109
+ "findIndex",
110
+ "findLast",
111
+ "findLastIndex",
112
+ "filter",
113
+ "map",
114
+ "reduce",
115
+ "reduceRight",
116
+ "every",
117
+ "some",
118
+ "flat",
119
+ "flatMap",
120
+ "forEach",
121
+ "entries",
122
+ "keys",
123
+ "values",
124
+ "at",
125
+ "with",
126
+ "toReversed",
127
+ "toSorted",
128
+ "toSpliced",
129
+ "length",
130
+ Symbol.iterator.toString(),
131
+ "toString",
132
+ "toLocaleString"
133
+ ]);
92
134
  function isPrimitiveName(name) {
93
135
  return PRIMITIVES.has(name);
94
136
  }
137
+ function isBuiltinSymbol(symbol) {
138
+ if (!symbol)
139
+ return false;
140
+ const declarations = symbol.getDeclarations();
141
+ if (!declarations || declarations.length === 0)
142
+ return false;
143
+ const sourceFile = declarations[0].getSourceFile();
144
+ const fileName = sourceFile.fileName;
145
+ return fileName.includes("/typescript/lib/lib.") || fileName.includes("\\typescript\\lib\\lib.");
146
+ }
147
+ function getTypeOrigin(type, _checker) {
148
+ const symbol = type.getSymbol() ?? type.aliasSymbol;
149
+ if (!symbol)
150
+ return;
151
+ const declarations = symbol.getDeclarations();
152
+ if (!declarations || declarations.length === 0)
153
+ return;
154
+ const fileName = declarations[0].getSourceFile().fileName;
155
+ const match = fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
156
+ if (!match)
157
+ return;
158
+ if (match[1] === "typescript")
159
+ return;
160
+ return match[1];
161
+ }
95
162
  function isBuiltinGeneric(name) {
96
163
  return BUILTIN_GENERICS.has(name);
97
164
  }
@@ -170,8 +237,8 @@ function buildSchema(type, checker, ctx, _depth = 0) {
170
237
  return { type: "number", enum: [literal] };
171
238
  }
172
239
  if (type.flags & ts.TypeFlags.BooleanLiteral) {
173
- const typeString = checker.typeToString(type);
174
- return { type: "boolean", enum: [typeString === "true"] };
240
+ const typeString2 = checker.typeToString(type);
241
+ return { type: "boolean", enum: [typeString2 === "true"] };
175
242
  }
176
243
  if (type.isUnion()) {
177
244
  const types = type.types;
@@ -193,12 +260,27 @@ function buildSchema(type, checker, ctx, _depth = 0) {
193
260
  return { anyOf: types.map((t) => buildSchema(t, checker, ctx)) };
194
261
  }
195
262
  if (type.isIntersection()) {
263
+ const filteredTypes = type.types.filter((t) => !(t.flags & ts.TypeFlags.Never));
264
+ if (filteredTypes.length === 0) {
265
+ return { type: "never" };
266
+ }
267
+ if (filteredTypes.length === 1) {
268
+ return buildSchema(filteredTypes[0], checker, ctx);
269
+ }
196
270
  if (ctx) {
197
271
  return withDepth(ctx, () => ({
198
- allOf: type.types.map((t) => buildSchema(t, checker, ctx))
272
+ allOf: filteredTypes.map((t) => buildSchema(t, checker, ctx))
199
273
  }));
200
274
  }
201
- return { allOf: type.types.map((t) => buildSchema(t, checker, ctx)) };
275
+ return { allOf: filteredTypes.map((t) => buildSchema(t, checker, ctx)) };
276
+ }
277
+ const typeString = checker.typeToString(type);
278
+ if (typeString === "never[]" || typeString === "[]") {
279
+ return { type: "array", prefixedItems: [], minItems: 0, maxItems: 0 };
280
+ }
281
+ const symbol = type.getSymbol() || type.aliasSymbol;
282
+ if (symbol?.getName() === "Array" && isBuiltinSymbol(symbol)) {
283
+ return { type: "array", items: {} };
202
284
  }
203
285
  if (checker.isArrayType(type)) {
204
286
  const typeRef2 = type;
@@ -218,12 +300,20 @@ function buildSchema(type, checker, ctx, _depth = 0) {
218
300
  const typeRef2 = type;
219
301
  const elementTypes = typeRef2.typeArguments ?? [];
220
302
  if (ctx) {
221
- return withDepth(ctx, () => ({
222
- type: "array",
223
- prefixedItems: elementTypes.map((t) => buildSchema(t, checker, ctx)),
224
- minItems: elementTypes.length,
225
- maxItems: elementTypes.length
226
- }));
303
+ return withDepth(ctx, () => {
304
+ const prevInTupleElement = ctx.inTupleElement;
305
+ ctx.inTupleElement = true;
306
+ try {
307
+ return {
308
+ type: "array",
309
+ prefixedItems: elementTypes.map((t) => buildSchema(t, checker, ctx)),
310
+ minItems: elementTypes.length,
311
+ maxItems: elementTypes.length
312
+ };
313
+ } finally {
314
+ ctx.inTupleElement = prevInTupleElement;
315
+ }
316
+ });
227
317
  }
228
318
  return {
229
319
  type: "array",
@@ -240,16 +330,27 @@ function buildSchema(type, checker, ctx, _depth = 0) {
240
330
  return { $ref: `#/types/${name}` };
241
331
  }
242
332
  if (name && (isBuiltinGeneric(name) || !isAnonymous(typeRef.target))) {
333
+ const packageOrigin = getTypeOrigin(typeRef.target, checker);
243
334
  if (ctx) {
244
- return withDepth(ctx, () => ({
245
- $ref: `#/types/${name}`,
246
- typeArguments: typeRef.typeArguments.map((t) => buildSchema(t, checker, ctx))
247
- }));
335
+ return withDepth(ctx, () => {
336
+ const schema2 = {
337
+ $ref: `#/types/${name}`,
338
+ typeArguments: typeRef.typeArguments.map((t) => buildSchema(t, checker, ctx))
339
+ };
340
+ if (packageOrigin) {
341
+ schema2["x-ts-package"] = packageOrigin;
342
+ }
343
+ return schema2;
344
+ });
248
345
  }
249
- return {
346
+ const schema = {
250
347
  $ref: `#/types/${name}`,
251
348
  typeArguments: typeRef.typeArguments.map((t) => buildSchema(t, checker, ctx))
252
349
  };
350
+ if (packageOrigin) {
351
+ schema["x-ts-package"] = packageOrigin;
352
+ }
353
+ return schema;
253
354
  }
254
355
  }
255
356
  if (type.flags & ts.TypeFlags.Object) {
@@ -258,7 +359,6 @@ function buildSchema(type, checker, ctx, _depth = 0) {
258
359
  return buildFunctionSchema(callSignatures, checker, ctx);
259
360
  }
260
361
  }
261
- const symbol = type.getSymbol() || type.aliasSymbol;
262
362
  if (symbol && !isAnonymous(type)) {
263
363
  const name = symbol.getName();
264
364
  if (isPrimitiveName(name)) {
@@ -268,7 +368,12 @@ function buildSchema(type, checker, ctx, _depth = 0) {
268
368
  return { $ref: `#/types/${name}` };
269
369
  }
270
370
  if (!name.startsWith("__")) {
271
- return { $ref: `#/types/${name}` };
371
+ const packageOrigin = getTypeOrigin(type, checker);
372
+ const schema = { $ref: `#/types/${name}` };
373
+ if (packageOrigin) {
374
+ schema["x-ts-package"] = packageOrigin;
375
+ }
376
+ return schema;
272
377
  }
273
378
  }
274
379
  if (type.flags & ts.TypeFlags.Object) {
@@ -314,6 +419,9 @@ function buildObjectSchema(properties, checker, ctx) {
314
419
  const propName = prop.getName();
315
420
  if (propName.startsWith("_"))
316
421
  continue;
422
+ if (ARRAY_PROTOTYPE_METHODS.has(propName)) {
423
+ continue;
424
+ }
317
425
  const propType = checker.getTypeOfSymbol(prop);
318
426
  props[propName] = buildSchema(propType, checker, ctx);
319
427
  if (!(prop.flags & ts.SymbolFlags.Optional)) {
@@ -632,6 +740,8 @@ class TypeRegistry {
632
740
  const propName = prop.getName();
633
741
  if (propName.startsWith("_"))
634
742
  continue;
743
+ if (ARRAY_PROTOTYPE_METHODS.has(propName))
744
+ continue;
635
745
  const propType = checker.getTypeOfSymbol(prop);
636
746
  this.registerType(propType, ctx);
637
747
  props[propName] = buildSchema(propType, checker, ctx);
@@ -685,6 +795,42 @@ function stripTypeParamSeparator(text) {
685
795
  }
686
796
  return text.trim() || undefined;
687
797
  }
798
+ function extractSeeTagText(tag) {
799
+ const fullText = tag.getText();
800
+ const seeMatch = fullText.match(/@see\s+(.+?)(?:\s*\*\s*@|\s*\*\/|$)/s);
801
+ if (seeMatch) {
802
+ let text = seeMatch[1].trim();
803
+ text = text.replace(/\s*\*\s*$/gm, "").trim();
804
+ if (text)
805
+ return text;
806
+ }
807
+ if (tag.comment) {
808
+ if (typeof tag.comment === "string") {
809
+ if (!tag.comment.startsWith("://")) {
810
+ return tag.comment;
811
+ }
812
+ }
813
+ if (Array.isArray(tag.comment)) {
814
+ const parts = [];
815
+ for (const part of tag.comment) {
816
+ if (ts3.isJSDocLink(part) || ts3.isJSDocLinkCode(part) || ts3.isJSDocLinkPlain(part)) {
817
+ if (part.name) {
818
+ parts.push(part.name.getText());
819
+ }
820
+ if (part.text) {
821
+ parts.push(part.text);
822
+ }
823
+ } else if (part.kind === ts3.SyntaxKind.JSDocText) {
824
+ parts.push(part.text);
825
+ }
826
+ }
827
+ const result = parts.join("").trim();
828
+ if (result && !result.startsWith("://"))
829
+ return result;
830
+ }
831
+ }
832
+ return typeof tag.comment === "string" ? tag.comment : ts3.getTextOfJSDocComment(tag.comment) ?? "";
833
+ }
688
834
  function getJSDocComment(node) {
689
835
  const jsDocTags = ts3.getJSDocTags(node);
690
836
  const tags = jsDocTags.map((tag) => {
@@ -709,6 +855,10 @@ function getJSDocComment(node) {
709
855
  const text = stripTypeParamSeparator(rawText) ?? "";
710
856
  return { name: tag.tagName.text, text };
711
857
  }
858
+ if (tag.tagName.text === "see") {
859
+ const text = extractSeeTagText(tag);
860
+ return { name: tag.tagName.text, text };
861
+ }
712
862
  return { name: tag.tagName.text, text: rawText };
713
863
  });
714
864
  const jsDocComments = ts3.getJSDocCommentsAndTags(node).filter(ts3.isJSDoc);
@@ -759,10 +909,33 @@ function extractTypeParameters(node, checker) {
759
909
  const defType = checker.getTypeAtLocation(tp.default);
760
910
  defaultType = checker.typeToString(defType);
761
911
  }
912
+ let variance;
913
+ let isConst;
914
+ const modifiers = ts3.getModifiers(tp);
915
+ if (modifiers) {
916
+ let hasIn = false;
917
+ let hasOut = false;
918
+ for (const mod of modifiers) {
919
+ if (mod.kind === ts3.SyntaxKind.InKeyword)
920
+ hasIn = true;
921
+ if (mod.kind === ts3.SyntaxKind.OutKeyword)
922
+ hasOut = true;
923
+ if (mod.kind === ts3.SyntaxKind.ConstKeyword)
924
+ isConst = true;
925
+ }
926
+ if (hasIn && hasOut)
927
+ variance = "inout";
928
+ else if (hasIn)
929
+ variance = "in";
930
+ else if (hasOut)
931
+ variance = "out";
932
+ }
762
933
  return {
763
934
  name,
764
935
  ...constraint ? { constraint } : {},
765
- ...defaultType ? { default: defaultType } : {}
936
+ ...defaultType ? { default: defaultType } : {},
937
+ ...variance ? { variance } : {},
938
+ ...isConst ? { const: isConst } : {}
766
939
  };
767
940
  });
768
941
  }
@@ -781,6 +954,67 @@ function isSymbolDeprecated(symbol) {
781
954
  }
782
955
  return false;
783
956
  }
957
+ function getJSDocForSignature(signature) {
958
+ const decl = signature.getDeclaration();
959
+ if (!decl) {
960
+ return { tags: [], examples: [] };
961
+ }
962
+ return getJSDocComment(decl);
963
+ }
964
+ function extractTypeParametersFromSignature(signature, checker) {
965
+ const typeParams = signature.getTypeParameters();
966
+ if (!typeParams || typeParams.length === 0) {
967
+ return;
968
+ }
969
+ return typeParams.map((tp) => {
970
+ const name = tp.getSymbol()?.getName() ?? "T";
971
+ let constraint;
972
+ const constraintType = tp.getConstraint();
973
+ if (constraintType) {
974
+ constraint = checker.typeToString(constraintType);
975
+ }
976
+ let defaultType;
977
+ const defaultT = tp.getDefault();
978
+ if (defaultT) {
979
+ defaultType = checker.typeToString(defaultT);
980
+ }
981
+ let variance;
982
+ let isConst;
983
+ const tpSymbol = tp.getSymbol();
984
+ const declarations = tpSymbol?.getDeclarations() ?? [];
985
+ for (const decl of declarations) {
986
+ if (ts3.isTypeParameterDeclaration(decl)) {
987
+ const modifiers = ts3.getModifiers(decl);
988
+ if (modifiers) {
989
+ let hasIn = false;
990
+ let hasOut = false;
991
+ for (const mod of modifiers) {
992
+ if (mod.kind === ts3.SyntaxKind.InKeyword)
993
+ hasIn = true;
994
+ if (mod.kind === ts3.SyntaxKind.OutKeyword)
995
+ hasOut = true;
996
+ if (mod.kind === ts3.SyntaxKind.ConstKeyword)
997
+ isConst = true;
998
+ }
999
+ if (hasIn && hasOut)
1000
+ variance = "inout";
1001
+ else if (hasIn)
1002
+ variance = "in";
1003
+ else if (hasOut)
1004
+ variance = "out";
1005
+ }
1006
+ break;
1007
+ }
1008
+ }
1009
+ return {
1010
+ name,
1011
+ ...constraint ? { constraint } : {},
1012
+ ...defaultType ? { default: defaultType } : {},
1013
+ ...variance ? { variance } : {},
1014
+ ...isConst ? { const: isConst } : {}
1015
+ };
1016
+ });
1017
+ }
784
1018
 
785
1019
  // src/compiler/program.ts
786
1020
  import * as path from "node:path";
@@ -855,142 +1089,600 @@ function createProgram({
855
1089
  };
856
1090
  }
857
1091
 
858
- // src/types/parameters.ts
859
- import ts5 from "typescript";
860
- function extractParameters(signature, ctx) {
861
- const { typeChecker: checker } = ctx;
862
- const result = [];
863
- const signatureDecl = signature.getDeclaration();
864
- const jsdocTags = signatureDecl ? ts5.getJSDocTags(signatureDecl) : [];
865
- for (const param of signature.getParameters()) {
866
- const decl = param.valueDeclaration;
867
- const type = checker.getTypeOfSymbolAtLocation(param, decl ?? param.valueDeclaration);
868
- if (decl && ts5.isObjectBindingPattern(decl.name)) {
869
- const expandedParams = expandBindingPattern(decl, type, jsdocTags, ctx);
870
- result.push(...expandedParams);
871
- } else {
872
- registerReferencedTypes(type, ctx);
873
- result.push({
874
- name: param.getName(),
875
- schema: buildSchema(type, checker, ctx),
876
- required: !(param.flags & 16777216)
877
- });
878
- }
879
- }
880
- return result;
881
- }
882
- function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
883
- const { typeChecker: checker } = ctx;
884
- const result = [];
885
- const bindingPattern = paramDecl.name;
886
- const allProperties = getEffectiveProperties(paramType, checker);
887
- const inferredAlias = inferParamAlias(jsdocTags);
888
- for (const element of bindingPattern.elements) {
889
- if (!ts5.isBindingElement(element))
890
- continue;
891
- const propertyName = element.propertyName ? ts5.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts5.isIdentifier(element.name) ? element.name.text : element.name.getText();
892
- const propSymbol = allProperties.get(propertyName);
893
- if (!propSymbol)
894
- continue;
895
- const propType = checker.getTypeOfSymbol(propSymbol);
896
- registerReferencedTypes(propType, ctx);
897
- const isOptional = !!(propSymbol.flags & ts5.SymbolFlags.Optional) || element.initializer !== undefined;
898
- const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
899
- const param = {
900
- name: propertyName,
901
- schema: buildSchema(propType, checker, ctx),
902
- required: !isOptional
903
- };
904
- if (description) {
905
- param.description = description;
906
- }
907
- if (element.initializer) {
908
- param.default = extractDefaultValue(element.initializer);
909
- }
910
- result.push(param);
911
- }
912
- return result;
913
- }
914
- function getEffectiveProperties(type, _checker) {
915
- const properties = new Map;
916
- if (type.isIntersection()) {
917
- for (const subType of type.types) {
918
- for (const prop of subType.getProperties()) {
919
- properties.set(prop.getName(), prop);
920
- }
921
- }
922
- } else {
923
- for (const prop of type.getProperties()) {
924
- properties.set(prop.getName(), prop);
925
- }
926
- }
927
- return properties;
1092
+ // src/schema/standard-schema.ts
1093
+ import { spawn, spawnSync } from "node:child_process";
1094
+ import * as fs from "node:fs";
1095
+ import * as os from "node:os";
1096
+ import * as path2 from "node:path";
1097
+ function isStandardJSONSchema(obj) {
1098
+ if (typeof obj !== "object" || obj === null)
1099
+ return false;
1100
+ const std = obj["~standard"];
1101
+ if (typeof std !== "object" || std === null)
1102
+ return false;
1103
+ const stdObj = std;
1104
+ if (stdObj.version !== 1)
1105
+ return false;
1106
+ if (typeof stdObj.vendor !== "string")
1107
+ return false;
1108
+ const jsonSchema = stdObj.jsonSchema;
1109
+ if (typeof jsonSchema !== "object" || jsonSchema === null)
1110
+ return false;
1111
+ const jsObj = jsonSchema;
1112
+ return typeof jsObj.output === "function" && typeof jsObj.input === "function";
928
1113
  }
929
- function inferParamAlias(jsdocTags) {
930
- const prefixes = [];
931
- for (const tag of jsdocTags) {
932
- if (tag.tagName.text !== "param")
933
- continue;
934
- const tagText = typeof tag.comment === "string" ? tag.comment : ts5.getTextOfJSDocComment(tag.comment) ?? "";
935
- const paramTag = tag;
936
- const paramName = paramTag.name?.getText() ?? "";
937
- if (paramName.includes(".")) {
938
- const prefix = paramName.split(".")[0];
939
- if (prefix && !prefix.startsWith("__")) {
940
- prefixes.push(prefix);
941
- }
942
- } else if (tagText.includes(".")) {
943
- const match = tagText.match(/^(\w+)\./);
944
- if (match && !match[1].startsWith("__")) {
945
- prefixes.push(match[1]);
946
- }
947
- }
1114
+ var cachedRuntime;
1115
+ function commandExists(cmd) {
1116
+ try {
1117
+ const result = spawnSync(process.platform === "win32" ? "where" : "which", [cmd], {
1118
+ stdio: "ignore"
1119
+ });
1120
+ return result.status === 0;
1121
+ } catch {
1122
+ return false;
948
1123
  }
949
- if (prefixes.length === 0)
950
- return;
951
- const counts = new Map;
952
- for (const p of prefixes)
953
- counts.set(p, (counts.get(p) ?? 0) + 1);
954
- return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
955
1124
  }
956
- function extractDefaultValue(initializer) {
957
- if (ts5.isStringLiteral(initializer)) {
958
- return initializer.text;
1125
+ function detectTsRuntime() {
1126
+ if (cachedRuntime !== undefined) {
1127
+ return cachedRuntime;
959
1128
  }
960
- if (ts5.isNumericLiteral(initializer)) {
961
- return Number(initializer.text);
1129
+ const nodeVersion = parseInt(process.versions.node.split(".")[0], 10);
1130
+ if (nodeVersion >= 22) {
1131
+ cachedRuntime = {
1132
+ cmd: "node",
1133
+ args: ["--experimental-strip-types", "--no-warnings"],
1134
+ name: "node (native)"
1135
+ };
1136
+ return cachedRuntime;
962
1137
  }
963
- if (initializer.kind === ts5.SyntaxKind.TrueKeyword) {
964
- return true;
1138
+ if (commandExists("bun")) {
1139
+ cachedRuntime = {
1140
+ cmd: "bun",
1141
+ args: ["run"],
1142
+ name: "bun"
1143
+ };
1144
+ return cachedRuntime;
965
1145
  }
966
- if (initializer.kind === ts5.SyntaxKind.FalseKeyword) {
967
- return false;
1146
+ if (commandExists("tsx")) {
1147
+ cachedRuntime = {
1148
+ cmd: "tsx",
1149
+ args: [],
1150
+ name: "tsx"
1151
+ };
1152
+ return cachedRuntime;
968
1153
  }
969
- if (initializer.kind === ts5.SyntaxKind.NullKeyword) {
970
- return null;
1154
+ if (commandExists("ts-node")) {
1155
+ cachedRuntime = {
1156
+ cmd: "ts-node",
1157
+ args: ["--transpile-only"],
1158
+ name: "ts-node"
1159
+ };
1160
+ return cachedRuntime;
971
1161
  }
972
- return initializer.getText();
1162
+ cachedRuntime = null;
1163
+ return null;
973
1164
  }
974
- function registerReferencedTypes(type, ctx, depth = 0) {
975
- if (depth > ctx.maxTypeDepth)
976
- return;
977
- if (ctx.visitedTypes.has(type))
978
- return;
979
- const isPrimitive = type.flags & (ts5.TypeFlags.String | ts5.TypeFlags.Number | ts5.TypeFlags.Boolean | ts5.TypeFlags.Void | ts5.TypeFlags.Undefined | ts5.TypeFlags.Null | ts5.TypeFlags.Any | ts5.TypeFlags.Unknown | ts5.TypeFlags.Never | ts5.TypeFlags.StringLiteral | ts5.TypeFlags.NumberLiteral | ts5.TypeFlags.BooleanLiteral);
980
- if (!isPrimitive) {
981
- ctx.visitedTypes.add(type);
982
- }
983
- const { typeChecker: checker, typeRegistry } = ctx;
984
- typeRegistry.registerType(type, ctx);
985
- const typeArgs = type.typeArguments;
986
- if (typeArgs) {
987
- for (const arg of typeArgs) {
988
- registerReferencedTypes(arg, ctx, depth + 1);
989
- }
990
- }
991
- if (type.isUnion()) {
992
- for (const t of type.types) {
993
- registerReferencedTypes(t, ctx, depth + 1);
1165
+ var WORKER_SCRIPT = `
1166
+ const path = require('path');
1167
+ const { pathToFileURL } = require('url');
1168
+
1169
+ // TypeBox detection: schemas have Symbol.for('TypeBox.Kind') and are JSON Schema
1170
+ const TYPEBOX_KIND = Symbol.for('TypeBox.Kind');
1171
+
1172
+ function isTypeBoxSchema(obj) {
1173
+ if (!obj || typeof obj !== 'object') return false;
1174
+ // TypeBox schemas always have Kind symbol (Union, Object, String, etc.)
1175
+ // Also check for common JSON Schema props to avoid false positives
1176
+ if (!obj[TYPEBOX_KIND]) return false;
1177
+ return typeof obj.type === 'string' || 'anyOf' in obj || 'oneOf' in obj || 'allOf' in obj;
1178
+ }
1179
+
1180
+ function sanitizeTypeBoxSchema(schema) {
1181
+ // JSON.stringify removes symbol keys, keeping only JSON Schema props
1182
+ return JSON.parse(JSON.stringify(schema));
1183
+ }
1184
+
1185
+ async function extract() {
1186
+ // With node -e, argv is: [node, arg1, arg2, ...]
1187
+ // (the -e script is NOT in argv)
1188
+ const [modulePath, optionsJson] = process.argv.slice(1);
1189
+ const { target, libraryOptions } = JSON.parse(optionsJson || '{}');
1190
+
1191
+ try {
1192
+ // Import the module using dynamic import (works with ESM and CJS)
1193
+ const absPath = path.resolve(modulePath);
1194
+ const mod = await import(pathToFileURL(absPath).href);
1195
+ const results = [];
1196
+
1197
+ // Build exports map - handle both ESM and CJS (where exports are in mod.default)
1198
+ const exports = {};
1199
+ for (const [name, value] of Object.entries(mod)) {
1200
+ if (name === 'default' && typeof value === 'object' && value !== null) {
1201
+ // CJS module: spread default exports
1202
+ Object.assign(exports, value);
1203
+ } else if (name !== 'default') {
1204
+ exports[name] = value;
1205
+ }
1206
+ }
1207
+
1208
+ // Check each export
1209
+ for (const [name, value] of Object.entries(exports)) {
1210
+ if (name.startsWith('_')) continue;
1211
+ if (typeof value !== 'object' || value === null) continue;
1212
+
1213
+ // Priority 1: Standard JSON Schema (Zod 4.2+, ArkType 2.1.28+, Valibot 1.2+)
1214
+ const std = value['~standard'];
1215
+ if (std && typeof std === 'object' && std.version === 1 && typeof std.vendor === 'string' && std.jsonSchema && typeof std.jsonSchema.output === 'function') {
1216
+ try {
1217
+ // Per spec: pass options object with target and optional libraryOptions
1218
+ const options = { target: target || 'draft-2020-12', ...(libraryOptions && { libraryOptions }) };
1219
+ const outputSchema = std.jsonSchema.output(options);
1220
+ const inputSchema = typeof std.jsonSchema.input === 'function' ? std.jsonSchema.input(options) : undefined;
1221
+ results.push({
1222
+ exportName: name,
1223
+ vendor: std.vendor,
1224
+ outputSchema,
1225
+ inputSchema
1226
+ });
1227
+ } catch (e) {
1228
+ // Skip schemas that fail to extract
1229
+ }
1230
+ continue;
1231
+ }
1232
+
1233
+ // Priority 2: TypeBox (schema IS JSON Schema)
1234
+ if (isTypeBoxSchema(value)) {
1235
+ try {
1236
+ results.push({
1237
+ exportName: name,
1238
+ vendor: 'typebox',
1239
+ outputSchema: sanitizeTypeBoxSchema(value)
1240
+ });
1241
+ } catch (e) {
1242
+ // Skip schemas that fail to extract
1243
+ }
1244
+ continue;
1245
+ }
1246
+ }
1247
+
1248
+ console.log(JSON.stringify({ success: true, results }));
1249
+ } catch (e) {
1250
+ console.log(JSON.stringify({ success: false, error: e.message }));
1251
+ }
1252
+ }
1253
+
1254
+ extract();
1255
+ `;
1256
+ var TS_WORKER_SCRIPT = `
1257
+ import * as path from 'path';
1258
+ import { pathToFileURL } from 'url';
1259
+
1260
+ // TypeBox detection
1261
+ const TYPEBOX_KIND = Symbol.for('TypeBox.Kind');
1262
+
1263
+ function isTypeBoxSchema(obj: unknown): boolean {
1264
+ if (!obj || typeof obj !== 'object') return false;
1265
+ const o = obj as Record<string | symbol, unknown>;
1266
+ if (!o[TYPEBOX_KIND]) return false;
1267
+ return typeof o.type === 'string' || 'anyOf' in o || 'oneOf' in o || 'allOf' in o;
1268
+ }
1269
+
1270
+ function sanitizeTypeBoxSchema(schema: unknown): unknown {
1271
+ return JSON.parse(JSON.stringify(schema));
1272
+ }
1273
+
1274
+ async function extract() {
1275
+ const [,, modulePath, optionsJson] = process.argv;
1276
+ const { target, libraryOptions } = JSON.parse(optionsJson || '{}');
1277
+
1278
+ try {
1279
+ const absPath = path.resolve(modulePath);
1280
+ const mod = await import(pathToFileURL(absPath).href);
1281
+ const results: Array<{exportName: string; vendor: string; outputSchema: unknown; inputSchema?: unknown}> = [];
1282
+
1283
+ // Build exports map
1284
+ const exports: Record<string, unknown> = {};
1285
+ for (const [name, value] of Object.entries(mod)) {
1286
+ if (name === 'default' && typeof value === 'object' && value !== null) {
1287
+ Object.assign(exports, value);
1288
+ } else if (name !== 'default') {
1289
+ exports[name] = value;
1290
+ }
1291
+ }
1292
+
1293
+ // Check each export
1294
+ for (const [name, value] of Object.entries(exports)) {
1295
+ if (name.startsWith('_')) continue;
1296
+ if (typeof value !== 'object' || value === null) continue;
1297
+
1298
+ const v = value as Record<string, unknown>;
1299
+ const std = v['~standard'] as Record<string, unknown> | undefined;
1300
+
1301
+ // Standard JSON Schema
1302
+ if (std && typeof std === 'object' && std.version === 1 && typeof std.vendor === 'string') {
1303
+ const jsonSchema = std.jsonSchema as Record<string, unknown> | undefined;
1304
+ if (jsonSchema && typeof jsonSchema.output === 'function') {
1305
+ try {
1306
+ const options = { target: target || 'draft-2020-12', ...(libraryOptions && { libraryOptions }) };
1307
+ const outputSchema = (jsonSchema.output as Function)(options);
1308
+ const inputSchema = typeof jsonSchema.input === 'function' ? (jsonSchema.input as Function)(options) : undefined;
1309
+ results.push({ exportName: name, vendor: std.vendor as string, outputSchema, inputSchema });
1310
+ } catch {}
1311
+ continue;
1312
+ }
1313
+ }
1314
+
1315
+ // TypeBox
1316
+ if (isTypeBoxSchema(value)) {
1317
+ try {
1318
+ results.push({ exportName: name, vendor: 'typebox', outputSchema: sanitizeTypeBoxSchema(value) });
1319
+ } catch {}
1320
+ }
1321
+ }
1322
+
1323
+ console.log(JSON.stringify({ success: true, results }));
1324
+ } catch (e) {
1325
+ console.log(JSON.stringify({ success: false, error: (e as Error).message }));
1326
+ }
1327
+ }
1328
+
1329
+ extract();
1330
+ `;
1331
+ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
1332
+ const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
1333
+ const result = {
1334
+ schemas: new Map,
1335
+ errors: []
1336
+ };
1337
+ const runtime = detectTsRuntime();
1338
+ if (!runtime) {
1339
+ result.errors.push("No TypeScript runtime available. Install bun, tsx, or ts-node, or use Node 22+.");
1340
+ return result;
1341
+ }
1342
+ if (!fs.existsSync(tsFilePath)) {
1343
+ result.errors.push(`TypeScript file not found: ${tsFilePath}`);
1344
+ return result;
1345
+ }
1346
+ const tempDir = os.tmpdir();
1347
+ const workerPath = path2.join(tempDir, `openpkg-extract-worker-${Date.now()}.ts`);
1348
+ try {
1349
+ fs.writeFileSync(workerPath, TS_WORKER_SCRIPT);
1350
+ const optionsJson = JSON.stringify({ target, libraryOptions });
1351
+ const args = [...runtime.args, workerPath, tsFilePath, optionsJson];
1352
+ return await new Promise((resolve) => {
1353
+ const child = spawn(runtime.cmd, args, {
1354
+ timeout,
1355
+ stdio: ["ignore", "pipe", "pipe"],
1356
+ cwd: path2.dirname(tsFilePath)
1357
+ });
1358
+ let stdout = "";
1359
+ let stderr = "";
1360
+ child.stdout.on("data", (data) => {
1361
+ stdout += data.toString();
1362
+ });
1363
+ child.stderr.on("data", (data) => {
1364
+ stderr += data.toString();
1365
+ });
1366
+ child.on("close", (code) => {
1367
+ try {
1368
+ fs.unlinkSync(workerPath);
1369
+ } catch {}
1370
+ if (code !== 0) {
1371
+ result.errors.push(`Extraction failed (${runtime.name}): ${stderr || `exit code ${code}`}`);
1372
+ resolve(result);
1373
+ return;
1374
+ }
1375
+ try {
1376
+ const parsed = JSON.parse(stdout);
1377
+ if (!parsed.success) {
1378
+ result.errors.push(`Extraction failed: ${parsed.error}`);
1379
+ resolve(result);
1380
+ return;
1381
+ }
1382
+ for (const item of parsed.results) {
1383
+ result.schemas.set(item.exportName, {
1384
+ exportName: item.exportName,
1385
+ vendor: item.vendor,
1386
+ outputSchema: item.outputSchema,
1387
+ inputSchema: item.inputSchema
1388
+ });
1389
+ }
1390
+ } catch (e) {
1391
+ result.errors.push(`Failed to parse extraction output: ${e}`);
1392
+ }
1393
+ resolve(result);
1394
+ });
1395
+ child.on("error", (err) => {
1396
+ try {
1397
+ fs.unlinkSync(workerPath);
1398
+ } catch {}
1399
+ result.errors.push(`Subprocess error: ${err.message}`);
1400
+ resolve(result);
1401
+ });
1402
+ });
1403
+ } catch (e) {
1404
+ try {
1405
+ fs.unlinkSync(workerPath);
1406
+ } catch {}
1407
+ result.errors.push(`Failed to create worker script: ${e}`);
1408
+ return result;
1409
+ }
1410
+ }
1411
+ function readTsconfigOutDir(baseDir) {
1412
+ const tsconfigPath = path2.join(baseDir, "tsconfig.json");
1413
+ try {
1414
+ if (!fs.existsSync(tsconfigPath)) {
1415
+ return null;
1416
+ }
1417
+ const content = fs.readFileSync(tsconfigPath, "utf-8");
1418
+ const stripped = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
1419
+ const tsconfig = JSON.parse(stripped);
1420
+ if (tsconfig.compilerOptions?.outDir) {
1421
+ return tsconfig.compilerOptions.outDir.replace(/^\.\//, "");
1422
+ }
1423
+ } catch {}
1424
+ return null;
1425
+ }
1426
+ function resolveCompiledPath(tsPath, baseDir) {
1427
+ const relativePath = path2.relative(baseDir, tsPath);
1428
+ const withoutExt = relativePath.replace(/\.tsx?$/, "");
1429
+ const srcPrefix = withoutExt.replace(/^src\//, "");
1430
+ const tsconfigOutDir = readTsconfigOutDir(baseDir);
1431
+ const extensions = [".js", ".mjs", ".cjs"];
1432
+ const candidates = [];
1433
+ if (tsconfigOutDir) {
1434
+ for (const ext of extensions) {
1435
+ candidates.push(path2.join(baseDir, tsconfigOutDir, `${srcPrefix}${ext}`));
1436
+ }
1437
+ }
1438
+ const commonOutDirs = ["dist", "build", "lib", "out"];
1439
+ for (const outDir of commonOutDirs) {
1440
+ if (outDir === tsconfigOutDir)
1441
+ continue;
1442
+ for (const ext of extensions) {
1443
+ candidates.push(path2.join(baseDir, outDir, `${srcPrefix}${ext}`));
1444
+ }
1445
+ }
1446
+ for (const ext of extensions) {
1447
+ candidates.push(path2.join(baseDir, `${withoutExt}${ext}`));
1448
+ }
1449
+ const workspaceMatch = baseDir.match(/^(.+\/packages\/[^/]+)$/);
1450
+ if (workspaceMatch) {
1451
+ const pkgRoot = workspaceMatch[1];
1452
+ for (const ext of extensions) {
1453
+ candidates.push(path2.join(pkgRoot, "dist", `${srcPrefix}${ext}`));
1454
+ }
1455
+ }
1456
+ for (const candidate of candidates) {
1457
+ if (fs.existsSync(candidate)) {
1458
+ return candidate;
1459
+ }
1460
+ }
1461
+ return null;
1462
+ }
1463
+ async function extractStandardSchemas(compiledJsPath, options = {}) {
1464
+ const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
1465
+ const result = {
1466
+ schemas: new Map,
1467
+ errors: []
1468
+ };
1469
+ if (!fs.existsSync(compiledJsPath)) {
1470
+ result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
1471
+ return result;
1472
+ }
1473
+ const optionsJson = JSON.stringify({ target, libraryOptions });
1474
+ return new Promise((resolve) => {
1475
+ const child = spawn("node", ["-e", WORKER_SCRIPT, compiledJsPath, optionsJson], {
1476
+ timeout,
1477
+ stdio: ["ignore", "pipe", "pipe"]
1478
+ });
1479
+ let stdout = "";
1480
+ let stderr = "";
1481
+ child.stdout.on("data", (data) => {
1482
+ stdout += data.toString();
1483
+ });
1484
+ child.stderr.on("data", (data) => {
1485
+ stderr += data.toString();
1486
+ });
1487
+ child.on("close", (code) => {
1488
+ if (code !== 0) {
1489
+ result.errors.push(`Extraction process failed: ${stderr || `exit code ${code}`}`);
1490
+ resolve(result);
1491
+ return;
1492
+ }
1493
+ try {
1494
+ const parsed = JSON.parse(stdout);
1495
+ if (!parsed.success) {
1496
+ result.errors.push(`Extraction failed: ${parsed.error}`);
1497
+ resolve(result);
1498
+ return;
1499
+ }
1500
+ for (const item of parsed.results) {
1501
+ result.schemas.set(item.exportName, {
1502
+ exportName: item.exportName,
1503
+ vendor: item.vendor,
1504
+ outputSchema: item.outputSchema,
1505
+ inputSchema: item.inputSchema
1506
+ });
1507
+ }
1508
+ } catch (e) {
1509
+ result.errors.push(`Failed to parse extraction output: ${e}`);
1510
+ }
1511
+ resolve(result);
1512
+ });
1513
+ child.on("error", (err) => {
1514
+ result.errors.push(`Subprocess error: ${err.message}`);
1515
+ resolve(result);
1516
+ });
1517
+ });
1518
+ }
1519
+ async function extractStandardSchemasFromProject(entryFile, baseDir, options = {}) {
1520
+ const { preferDirectTs, ...extractOptions } = options;
1521
+ const isTypeScript = /\.tsx?$/.test(entryFile);
1522
+ if (!preferDirectTs) {
1523
+ const compiledPath = resolveCompiledPath(entryFile, baseDir);
1524
+ if (compiledPath) {
1525
+ const result = await extractStandardSchemas(compiledPath, extractOptions);
1526
+ return {
1527
+ ...result,
1528
+ info: { method: "compiled", path: compiledPath }
1529
+ };
1530
+ }
1531
+ }
1532
+ if (isTypeScript) {
1533
+ const runtime2 = detectTsRuntime();
1534
+ if (runtime2) {
1535
+ const result = await extractStandardSchemasFromTs(entryFile, extractOptions);
1536
+ return {
1537
+ ...result,
1538
+ info: { method: "direct-ts", runtime: runtime2.name, path: entryFile }
1539
+ };
1540
+ }
1541
+ }
1542
+ const runtime = detectTsRuntime();
1543
+ const hint = isTypeScript && !runtime ? " Install bun, tsx, or ts-node for direct TS execution." : "";
1544
+ return {
1545
+ schemas: new Map,
1546
+ errors: [`Could not find compiled JS for ${entryFile}.${hint}`]
1547
+ };
1548
+ }
1549
+
1550
+ // src/types/parameters.ts
1551
+ import ts5 from "typescript";
1552
+ function extractParameters(signature, ctx) {
1553
+ const { typeChecker: checker } = ctx;
1554
+ const result = [];
1555
+ const signatureDecl = signature.getDeclaration();
1556
+ const jsdocTags = signatureDecl ? ts5.getJSDocTags(signatureDecl) : [];
1557
+ for (const param of signature.getParameters()) {
1558
+ const decl = param.valueDeclaration;
1559
+ const type = checker.getTypeOfSymbolAtLocation(param, decl ?? param.valueDeclaration);
1560
+ if (decl && ts5.isObjectBindingPattern(decl.name)) {
1561
+ const expandedParams = expandBindingPattern(decl, type, jsdocTags, ctx);
1562
+ result.push(...expandedParams);
1563
+ } else {
1564
+ registerReferencedTypes(type, ctx);
1565
+ result.push({
1566
+ name: param.getName(),
1567
+ schema: buildSchema(type, checker, ctx),
1568
+ required: !(param.flags & 16777216)
1569
+ });
1570
+ }
1571
+ }
1572
+ return result;
1573
+ }
1574
+ function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
1575
+ const { typeChecker: checker } = ctx;
1576
+ const result = [];
1577
+ const bindingPattern = paramDecl.name;
1578
+ const allProperties = getEffectiveProperties(paramType, checker);
1579
+ const inferredAlias = inferParamAlias(jsdocTags);
1580
+ for (const element of bindingPattern.elements) {
1581
+ if (!ts5.isBindingElement(element))
1582
+ continue;
1583
+ const propertyName = element.propertyName ? ts5.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts5.isIdentifier(element.name) ? element.name.text : element.name.getText();
1584
+ const propSymbol = allProperties.get(propertyName);
1585
+ if (!propSymbol)
1586
+ continue;
1587
+ const propType = checker.getTypeOfSymbol(propSymbol);
1588
+ registerReferencedTypes(propType, ctx);
1589
+ const isOptional = !!(propSymbol.flags & ts5.SymbolFlags.Optional) || element.initializer !== undefined;
1590
+ const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
1591
+ const param = {
1592
+ name: propertyName,
1593
+ schema: buildSchema(propType, checker, ctx),
1594
+ required: !isOptional
1595
+ };
1596
+ if (description) {
1597
+ param.description = description;
1598
+ }
1599
+ if (element.initializer) {
1600
+ param.default = extractDefaultValue(element.initializer);
1601
+ }
1602
+ result.push(param);
1603
+ }
1604
+ return result;
1605
+ }
1606
+ function getEffectiveProperties(type, _checker) {
1607
+ const properties = new Map;
1608
+ if (type.isIntersection()) {
1609
+ for (const subType of type.types) {
1610
+ for (const prop of subType.getProperties()) {
1611
+ properties.set(prop.getName(), prop);
1612
+ }
1613
+ }
1614
+ } else {
1615
+ for (const prop of type.getProperties()) {
1616
+ properties.set(prop.getName(), prop);
1617
+ }
1618
+ }
1619
+ return properties;
1620
+ }
1621
+ function inferParamAlias(jsdocTags) {
1622
+ const prefixes = [];
1623
+ for (const tag of jsdocTags) {
1624
+ if (tag.tagName.text !== "param")
1625
+ continue;
1626
+ const tagText = typeof tag.comment === "string" ? tag.comment : ts5.getTextOfJSDocComment(tag.comment) ?? "";
1627
+ const paramTag = tag;
1628
+ const paramName = paramTag.name?.getText() ?? "";
1629
+ if (paramName.includes(".")) {
1630
+ const prefix = paramName.split(".")[0];
1631
+ if (prefix && !prefix.startsWith("__")) {
1632
+ prefixes.push(prefix);
1633
+ }
1634
+ } else if (tagText.includes(".")) {
1635
+ const match = tagText.match(/^(\w+)\./);
1636
+ if (match && !match[1].startsWith("__")) {
1637
+ prefixes.push(match[1]);
1638
+ }
1639
+ }
1640
+ }
1641
+ if (prefixes.length === 0)
1642
+ return;
1643
+ const counts = new Map;
1644
+ for (const p of prefixes)
1645
+ counts.set(p, (counts.get(p) ?? 0) + 1);
1646
+ return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
1647
+ }
1648
+ function extractDefaultValue(initializer) {
1649
+ if (ts5.isStringLiteral(initializer)) {
1650
+ return initializer.text;
1651
+ }
1652
+ if (ts5.isNumericLiteral(initializer)) {
1653
+ return Number(initializer.text);
1654
+ }
1655
+ if (initializer.kind === ts5.SyntaxKind.TrueKeyword) {
1656
+ return true;
1657
+ }
1658
+ if (initializer.kind === ts5.SyntaxKind.FalseKeyword) {
1659
+ return false;
1660
+ }
1661
+ if (initializer.kind === ts5.SyntaxKind.NullKeyword) {
1662
+ return null;
1663
+ }
1664
+ return initializer.getText();
1665
+ }
1666
+ function registerReferencedTypes(type, ctx, depth = 0) {
1667
+ if (depth > ctx.maxTypeDepth)
1668
+ return;
1669
+ if (ctx.visitedTypes.has(type))
1670
+ return;
1671
+ const isPrimitive = type.flags & (ts5.TypeFlags.String | ts5.TypeFlags.Number | ts5.TypeFlags.Boolean | ts5.TypeFlags.Void | ts5.TypeFlags.Undefined | ts5.TypeFlags.Null | ts5.TypeFlags.Any | ts5.TypeFlags.Unknown | ts5.TypeFlags.Never | ts5.TypeFlags.StringLiteral | ts5.TypeFlags.NumberLiteral | ts5.TypeFlags.BooleanLiteral);
1672
+ if (!isPrimitive) {
1673
+ ctx.visitedTypes.add(type);
1674
+ }
1675
+ const { typeChecker: checker, typeRegistry } = ctx;
1676
+ typeRegistry.registerType(type, ctx);
1677
+ const typeArgs = type.typeArguments;
1678
+ if (typeArgs) {
1679
+ for (const arg of typeArgs) {
1680
+ registerReferencedTypes(arg, ctx, depth + 1);
1681
+ }
1682
+ }
1683
+ if (type.isUnion()) {
1684
+ for (const t of type.types) {
1685
+ registerReferencedTypes(t, ctx, depth + 1);
994
1686
  }
995
1687
  }
996
1688
  if (type.isIntersection()) {
@@ -1008,7 +1700,149 @@ function registerReferencedTypes(type, ctx, depth = 0) {
1008
1700
  }
1009
1701
 
1010
1702
  // src/serializers/classes.ts
1703
+ import ts7 from "typescript";
1704
+
1705
+ // src/serializers/context.ts
1011
1706
  import ts6 from "typescript";
1707
+ function createContext(program, sourceFile, options = {}) {
1708
+ return {
1709
+ typeChecker: program.getTypeChecker(),
1710
+ program,
1711
+ sourceFile,
1712
+ maxTypeDepth: options.maxTypeDepth ?? 4,
1713
+ maxExternalTypeDepth: options.maxExternalTypeDepth ?? 2,
1714
+ currentDepth: 0,
1715
+ resolveExternalTypes: options.resolveExternalTypes ?? true,
1716
+ typeRegistry: new TypeRegistry,
1717
+ exportedIds: new Set,
1718
+ visitedTypes: new Set
1719
+ };
1720
+ }
1721
+ function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
1722
+ const { typeChecker: checker } = ctx;
1723
+ const inherited = [];
1724
+ const visited = new Set;
1725
+ const typeToWalk = isStatic ? classType.getSymbol()?.valueDeclaration && checker.getTypeOfSymbolAtLocation(classType.getSymbol(), classType.getSymbol().valueDeclaration) : classType;
1726
+ if (!typeToWalk)
1727
+ return inherited;
1728
+ walkBaseTypes(typeToWalk, ownMemberNames, inherited, visited, ctx, isStatic);
1729
+ return inherited;
1730
+ }
1731
+ function walkBaseTypes(type, ownMemberNames, inherited, visited, ctx, isStatic) {
1732
+ if (visited.has(type))
1733
+ return;
1734
+ visited.add(type);
1735
+ const { typeChecker: checker } = ctx;
1736
+ const baseTypes = type.getBaseTypes?.() ?? [];
1737
+ for (const baseType of baseTypes) {
1738
+ const baseSymbol = baseType.getSymbol();
1739
+ const baseName = baseSymbol?.getName() ?? "unknown";
1740
+ const properties = isStatic ? getStaticMembers(baseType, checker) : baseType.getProperties();
1741
+ for (const prop of properties) {
1742
+ const propName = prop.getName();
1743
+ if (ownMemberNames.has(propName))
1744
+ continue;
1745
+ if (inherited.some((m) => m.name === propName))
1746
+ continue;
1747
+ if (propName.startsWith("#") || propName.startsWith("__"))
1748
+ continue;
1749
+ const member = serializeInheritedMember(prop, baseName, ctx, isStatic);
1750
+ if (member) {
1751
+ inherited.push(member);
1752
+ }
1753
+ }
1754
+ walkBaseTypes(baseType, ownMemberNames, inherited, visited, ctx, isStatic);
1755
+ }
1756
+ }
1757
+ function getStaticMembers(classType, checker) {
1758
+ const symbol = classType.getSymbol();
1759
+ if (!symbol)
1760
+ return [];
1761
+ const decl = symbol.valueDeclaration;
1762
+ if (!decl)
1763
+ return [];
1764
+ const constructorType = checker.getTypeOfSymbolAtLocation(symbol, decl);
1765
+ return constructorType.getProperties().filter((prop) => {
1766
+ const name = prop.getName();
1767
+ return name !== "prototype" && name !== "constructor" && !name.startsWith("__");
1768
+ });
1769
+ }
1770
+ function serializeInheritedMember(symbol, inheritedFrom, ctx, isStatic) {
1771
+ const { typeChecker: checker } = ctx;
1772
+ const name = symbol.getName();
1773
+ const declarations = symbol.getDeclarations() ?? [];
1774
+ const decl = declarations[0];
1775
+ if (!decl)
1776
+ return null;
1777
+ const type = checker.getTypeOfSymbol(symbol);
1778
+ registerReferencedTypes(type, ctx);
1779
+ let visibility;
1780
+ if (decl && ts6.canHaveModifiers(decl)) {
1781
+ const modifiers = ts6.getModifiers(decl);
1782
+ if (modifiers) {
1783
+ for (const mod of modifiers) {
1784
+ if (mod.kind === ts6.SyntaxKind.PrivateKeyword)
1785
+ visibility = "private";
1786
+ else if (mod.kind === ts6.SyntaxKind.ProtectedKeyword)
1787
+ visibility = "protected";
1788
+ else if (mod.kind === ts6.SyntaxKind.PublicKeyword)
1789
+ visibility = "public";
1790
+ }
1791
+ }
1792
+ }
1793
+ if (visibility === "private")
1794
+ return null;
1795
+ const { description, tags } = getJSDocComment(decl);
1796
+ let kind = "property";
1797
+ const callSigs = type.getCallSignatures();
1798
+ if (callSigs.length > 0) {
1799
+ kind = "method";
1800
+ } else if (ts6.isGetAccessorDeclaration(decl)) {
1801
+ kind = "getter";
1802
+ } else if (ts6.isSetAccessorDeclaration(decl)) {
1803
+ kind = "setter";
1804
+ }
1805
+ const flags = {};
1806
+ if (isStatic)
1807
+ flags.static = true;
1808
+ if (decl && ts6.canHaveModifiers(decl)) {
1809
+ const modifiers = ts6.getModifiers(decl);
1810
+ if (modifiers?.some((m) => m.kind === ts6.SyntaxKind.ReadonlyKeyword)) {
1811
+ flags.readonly = true;
1812
+ }
1813
+ }
1814
+ let signatures;
1815
+ if (kind === "method" && callSigs.length > 0) {
1816
+ signatures = callSigs.map((sig, index) => {
1817
+ const params = extractParameters(sig, ctx);
1818
+ const returnType = checker.getReturnTypeOfSignature(sig);
1819
+ registerReferencedTypes(returnType, ctx);
1820
+ const sigDoc = getJSDocForSignature(sig);
1821
+ return {
1822
+ parameters: params.length > 0 ? params : undefined,
1823
+ returns: {
1824
+ schema: buildSchema(returnType, checker, ctx)
1825
+ },
1826
+ ...sigDoc.description ? { description: sigDoc.description } : {},
1827
+ ...sigDoc.tags.length > 0 ? { tags: sigDoc.tags } : {},
1828
+ ...callSigs.length > 1 ? { overloadIndex: index } : {}
1829
+ };
1830
+ });
1831
+ }
1832
+ return {
1833
+ name,
1834
+ kind,
1835
+ inheritedFrom,
1836
+ description,
1837
+ tags: tags.length > 0 ? tags : undefined,
1838
+ visibility,
1839
+ schema: kind !== "method" ? buildSchema(type, checker, ctx) : undefined,
1840
+ signatures,
1841
+ flags: Object.keys(flags).length > 0 ? flags : undefined
1842
+ };
1843
+ }
1844
+
1845
+ // src/serializers/classes.ts
1012
1846
  function serializeClass(node, ctx) {
1013
1847
  const { typeChecker: checker } = ctx;
1014
1848
  const symbol = checker.getSymbolAtLocation(node.name ?? node);
@@ -1027,11 +1861,11 @@ function serializeClass(node, ctx) {
1027
1861
  const memberName = getMemberName(member);
1028
1862
  if (memberName?.startsWith("#"))
1029
1863
  continue;
1030
- if (ts6.isPropertyDeclaration(member)) {
1864
+ if (ts7.isPropertyDeclaration(member)) {
1031
1865
  const propMember = serializeProperty(member, ctx);
1032
1866
  if (propMember)
1033
1867
  members.push(propMember);
1034
- } else if (ts6.isMethodDeclaration(member)) {
1868
+ } else if (ts7.isMethodDeclaration(member)) {
1035
1869
  const methodMember = serializeMethod(member, ctx);
1036
1870
  if (methodMember?.name) {
1037
1871
  if (!methodsByName.has(methodMember.name)) {
@@ -1046,17 +1880,28 @@ function serializeClass(node, ctx) {
1046
1880
  }
1047
1881
  }
1048
1882
  }
1049
- } else if (ts6.isConstructorDeclaration(member)) {
1883
+ } else if (ts7.isConstructorDeclaration(member)) {
1050
1884
  const ctorSig = serializeConstructor(member, ctx);
1051
1885
  if (ctorSig)
1052
1886
  signatures.push(ctorSig);
1053
- } else if (ts6.isGetAccessorDeclaration(member) || ts6.isSetAccessorDeclaration(member)) {
1887
+ } else if (ts7.isGetAccessorDeclaration(member) || ts7.isSetAccessorDeclaration(member)) {
1054
1888
  const accessorMember = serializeAccessor(member, ctx);
1055
1889
  if (accessorMember)
1056
1890
  members.push(accessorMember);
1057
1891
  }
1058
1892
  }
1059
1893
  members.push(...methodsByName.values());
1894
+ const ownMemberNames = new Set;
1895
+ for (const member of node.members) {
1896
+ const memberName = getMemberName(member);
1897
+ if (memberName)
1898
+ ownMemberNames.add(memberName);
1899
+ }
1900
+ const classType = checker.getTypeAtLocation(node);
1901
+ const inheritedInstance = getInheritedMembers(classType, ownMemberNames, ctx, false);
1902
+ members.push(...inheritedInstance);
1903
+ const inheritedStatic = getInheritedMembers(classType, ownMemberNames, ctx, true);
1904
+ members.push(...inheritedStatic);
1060
1905
  const extendsClause = getExtendsClause(node, checker);
1061
1906
  const implementsClause = getImplementsClause(node, checker);
1062
1907
  return {
@@ -1076,37 +1921,37 @@ function serializeClass(node, ctx) {
1076
1921
  };
1077
1922
  }
1078
1923
  function getMemberName(member) {
1079
- if (ts6.isConstructorDeclaration(member))
1924
+ if (ts7.isConstructorDeclaration(member))
1080
1925
  return "constructor";
1081
1926
  if (!member.name)
1082
1927
  return;
1083
- if (ts6.isIdentifier(member.name))
1928
+ if (ts7.isIdentifier(member.name))
1084
1929
  return member.name.text;
1085
- if (ts6.isPrivateIdentifier(member.name))
1930
+ if (ts7.isPrivateIdentifier(member.name))
1086
1931
  return member.name.text;
1087
1932
  return member.name.getText();
1088
1933
  }
1089
1934
  function getVisibility(member) {
1090
- const modifiers = ts6.canHaveModifiers(member) ? ts6.getModifiers(member) : undefined;
1935
+ const modifiers = ts7.canHaveModifiers(member) ? ts7.getModifiers(member) : undefined;
1091
1936
  if (!modifiers)
1092
1937
  return;
1093
1938
  for (const mod of modifiers) {
1094
- if (mod.kind === ts6.SyntaxKind.PrivateKeyword)
1939
+ if (mod.kind === ts7.SyntaxKind.PrivateKeyword)
1095
1940
  return "private";
1096
- if (mod.kind === ts6.SyntaxKind.ProtectedKeyword)
1941
+ if (mod.kind === ts7.SyntaxKind.ProtectedKeyword)
1097
1942
  return "protected";
1098
- if (mod.kind === ts6.SyntaxKind.PublicKeyword)
1943
+ if (mod.kind === ts7.SyntaxKind.PublicKeyword)
1099
1944
  return "public";
1100
1945
  }
1101
1946
  return;
1102
1947
  }
1103
1948
  function isStatic(member) {
1104
- const modifiers = ts6.canHaveModifiers(member) ? ts6.getModifiers(member) : undefined;
1105
- return modifiers?.some((m) => m.kind === ts6.SyntaxKind.StaticKeyword) ?? false;
1949
+ const modifiers = ts7.canHaveModifiers(member) ? ts7.getModifiers(member) : undefined;
1950
+ return modifiers?.some((m) => m.kind === ts7.SyntaxKind.StaticKeyword) ?? false;
1106
1951
  }
1107
1952
  function isReadonly(member) {
1108
- const modifiers = ts6.canHaveModifiers(member) ? ts6.getModifiers(member) : undefined;
1109
- return modifiers?.some((m) => m.kind === ts6.SyntaxKind.ReadonlyKeyword) ?? false;
1953
+ const modifiers = ts7.canHaveModifiers(member) ? ts7.getModifiers(member) : undefined;
1954
+ return modifiers?.some((m) => m.kind === ts7.SyntaxKind.ReadonlyKeyword) ?? false;
1110
1955
  }
1111
1956
  function serializeProperty(node, ctx) {
1112
1957
  const { typeChecker: checker } = ctx;
@@ -1144,15 +1989,22 @@ function serializeMethod(node, ctx) {
1144
1989
  const visibility = getVisibility(node);
1145
1990
  const type = checker.getTypeAtLocation(node);
1146
1991
  const callSignatures = type.getCallSignatures();
1147
- const signatures = callSignatures.map((sig) => {
1992
+ const signatures = callSignatures.map((sig, index) => {
1148
1993
  const params = extractParameters(sig, ctx);
1149
1994
  const returnType = checker.getReturnTypeOfSignature(sig);
1150
1995
  registerReferencedTypes(returnType, ctx);
1996
+ const sigDoc = getJSDocForSignature(sig);
1997
+ const sigTypeParams = extractTypeParametersFromSignature(sig, checker);
1151
1998
  return {
1152
1999
  parameters: params.length > 0 ? params : undefined,
1153
2000
  returns: {
1154
2001
  schema: buildSchema(returnType, checker, ctx)
1155
- }
2002
+ },
2003
+ ...sigDoc.description ? { description: sigDoc.description } : {},
2004
+ ...sigDoc.tags.length > 0 ? { tags: sigDoc.tags } : {},
2005
+ ...sigDoc.examples.length > 0 ? { examples: sigDoc.examples } : {},
2006
+ ...sigTypeParams ? { typeParameters: sigTypeParams } : {},
2007
+ ...callSignatures.length > 1 ? { overloadIndex: index } : {}
1156
2008
  };
1157
2009
  });
1158
2010
  const flags = {};
@@ -1160,8 +2012,8 @@ function serializeMethod(node, ctx) {
1160
2012
  flags.static = true;
1161
2013
  if (node.asteriskToken)
1162
2014
  flags.generator = true;
1163
- const modifiers = ts6.getModifiers(node);
1164
- if (modifiers?.some((m) => m.kind === ts6.SyntaxKind.AsyncKeyword)) {
2015
+ const modifiers = ts7.getModifiers(node);
2016
+ if (modifiers?.some((m) => m.kind === ts7.SyntaxKind.AsyncKeyword)) {
1165
2017
  flags.async = true;
1166
2018
  }
1167
2019
  return {
@@ -1196,7 +2048,7 @@ function serializeAccessor(node, ctx) {
1196
2048
  const type = checker.getTypeAtLocation(node);
1197
2049
  const schema = buildSchema(type, checker, ctx);
1198
2050
  registerReferencedTypes(type, ctx);
1199
- const kind = ts6.isGetAccessorDeclaration(node) ? "getter" : "setter";
2051
+ const kind = ts7.isGetAccessorDeclaration(node) ? "getter" : "setter";
1200
2052
  const flags = {};
1201
2053
  if (isStatic(node))
1202
2054
  flags.static = true;
@@ -1214,7 +2066,7 @@ function getExtendsClause(node, checker) {
1214
2066
  if (!node.heritageClauses)
1215
2067
  return;
1216
2068
  for (const clause of node.heritageClauses) {
1217
- if (clause.token === ts6.SyntaxKind.ExtendsKeyword) {
2069
+ if (clause.token === ts7.SyntaxKind.ExtendsKeyword) {
1218
2070
  const expr = clause.types[0];
1219
2071
  if (expr) {
1220
2072
  const type = checker.getTypeAtLocation(expr);
@@ -1229,7 +2081,7 @@ function getImplementsClause(node, checker) {
1229
2081
  if (!node.heritageClauses)
1230
2082
  return;
1231
2083
  for (const clause of node.heritageClauses) {
1232
- if (clause.token === ts6.SyntaxKind.ImplementsKeyword) {
2084
+ if (clause.token === ts7.SyntaxKind.ImplementsKeyword) {
1233
2085
  return clause.types.map((expr) => {
1234
2086
  const type = checker.getTypeAtLocation(expr);
1235
2087
  const symbol = type.getSymbol();
@@ -1268,226 +2120,54 @@ function serializeEnum(node, ctx) {
1268
2120
  id: memberName,
1269
2121
  name: memberName,
1270
2122
  kind: "enum-member",
1271
- ...schema ? { schema } : {},
1272
- ...memberDesc ? { description: memberDesc } : {}
1273
- };
1274
- });
1275
- return {
1276
- id: name,
1277
- name,
1278
- kind: "enum",
1279
- description,
1280
- tags,
1281
- source,
1282
- members,
1283
- ...deprecated ? { deprecated: true } : {},
1284
- ...examples.length > 0 ? { examples } : {}
1285
- };
1286
- }
1287
-
1288
- // src/serializers/functions.ts
1289
- function serializeFunctionExport(node, ctx) {
1290
- const symbol = ctx.typeChecker.getSymbolAtLocation(node.name ?? node);
1291
- const name = symbol?.getName() ?? node.name?.getText();
1292
- if (!name)
1293
- return null;
1294
- const deprecated = isSymbolDeprecated(symbol);
1295
- const declSourceFile = node.getSourceFile();
1296
- const { description, tags, examples } = getJSDocComment(node);
1297
- const source = getSourceLocation(node, declSourceFile);
1298
- const typeParameters = extractTypeParameters(node, ctx.typeChecker);
1299
- const type = ctx.typeChecker.getTypeAtLocation(node);
1300
- const callSignatures = type.getCallSignatures();
1301
- const signatures = callSignatures.map((sig) => {
1302
- const params = extractParameters(sig, ctx);
1303
- const returnType = ctx.typeChecker.getReturnTypeOfSignature(sig);
1304
- registerReferencedTypes(returnType, ctx);
1305
- return {
1306
- parameters: params,
1307
- returns: {
1308
- schema: buildSchema(returnType, ctx.typeChecker, ctx)
1309
- }
1310
- };
1311
- });
1312
- return {
1313
- id: name,
1314
- name,
1315
- kind: "function",
1316
- description,
1317
- tags,
1318
- source,
1319
- typeParameters,
1320
- signatures,
1321
- ...deprecated ? { deprecated: true } : {},
1322
- ...examples.length > 0 ? { examples } : {}
1323
- };
1324
- }
1325
-
1326
- // src/serializers/interfaces.ts
1327
- import ts7 from "typescript";
1328
- function serializeInterface(node, ctx) {
1329
- const { typeChecker: checker } = ctx;
1330
- const symbol = checker.getSymbolAtLocation(node.name ?? node);
1331
- const name = symbol?.getName() ?? node.name?.getText();
1332
- if (!name)
1333
- return null;
1334
- const deprecated = isSymbolDeprecated(symbol);
1335
- const declSourceFile = node.getSourceFile();
1336
- const { description, tags, examples } = getJSDocComment(node);
1337
- const source = getSourceLocation(node, declSourceFile);
1338
- const typeParameters = extractTypeParameters(node, checker);
1339
- const members = [];
1340
- const methodsByName = new Map;
1341
- for (const member of node.members) {
1342
- if (ts7.isPropertySignature(member)) {
1343
- const propMember = serializePropertySignature(member, ctx);
1344
- if (propMember)
1345
- members.push(propMember);
1346
- } else if (ts7.isMethodSignature(member)) {
1347
- const methodMember = serializeMethodSignature(member, ctx);
1348
- if (methodMember?.name) {
1349
- if (!methodsByName.has(methodMember.name)) {
1350
- methodsByName.set(methodMember.name, methodMember);
1351
- }
1352
- }
1353
- } else if (ts7.isCallSignatureDeclaration(member)) {
1354
- const callMember = serializeCallSignature(member, ctx);
1355
- if (callMember)
1356
- members.push(callMember);
1357
- } else if (ts7.isIndexSignatureDeclaration(member)) {
1358
- const indexMember = serializeIndexSignature(member, ctx);
1359
- if (indexMember)
1360
- members.push(indexMember);
1361
- }
1362
- }
1363
- members.push(...methodsByName.values());
1364
- const extendsClause = getInterfaceExtends(node, checker);
1365
- return {
1366
- id: name,
1367
- name,
1368
- kind: "interface",
1369
- description,
1370
- tags,
1371
- source,
1372
- typeParameters,
1373
- members: members.length > 0 ? members : undefined,
1374
- extends: extendsClause,
1375
- ...deprecated ? { deprecated: true } : {},
1376
- ...examples.length > 0 ? { examples } : {}
1377
- };
1378
- }
1379
- function serializePropertySignature(node, ctx) {
1380
- const { typeChecker: checker } = ctx;
1381
- const name = node.name.getText();
1382
- const { description, tags } = getJSDocComment(node);
1383
- const type = checker.getTypeAtLocation(node);
1384
- const schema = buildSchema(type, checker, ctx);
1385
- registerReferencedTypes(type, ctx);
1386
- const flags = {};
1387
- if (node.questionToken)
1388
- flags.optional = true;
1389
- if (node.modifiers?.some((m) => m.kind === ts7.SyntaxKind.ReadonlyKeyword)) {
1390
- flags.readonly = true;
1391
- }
1392
- return {
1393
- name,
1394
- kind: "property",
1395
- description,
1396
- tags: tags.length > 0 ? tags : undefined,
1397
- schema,
1398
- flags: Object.keys(flags).length > 0 ? flags : undefined
1399
- };
1400
- }
1401
- function serializeMethodSignature(node, ctx) {
1402
- const { typeChecker: checker } = ctx;
1403
- const name = node.name.getText();
1404
- const { description, tags } = getJSDocComment(node);
1405
- const type = checker.getTypeAtLocation(node);
1406
- const callSignatures = type.getCallSignatures();
1407
- const signatures = callSignatures.map((sig) => {
1408
- const params = extractParameters(sig, ctx);
1409
- const returnType = checker.getReturnTypeOfSignature(sig);
1410
- registerReferencedTypes(returnType, ctx);
1411
- return {
1412
- parameters: params.length > 0 ? params : undefined,
1413
- returns: {
1414
- schema: buildSchema(returnType, checker, ctx)
1415
- }
1416
- };
1417
- });
1418
- const flags = {};
1419
- if (node.questionToken)
1420
- flags.optional = true;
1421
- return {
1422
- name,
1423
- kind: "method",
1424
- description,
1425
- tags: tags.length > 0 ? tags : undefined,
1426
- signatures: signatures.length > 0 ? signatures : undefined,
1427
- flags: Object.keys(flags).length > 0 ? flags : undefined
1428
- };
1429
- }
1430
- function serializeCallSignature(node, ctx) {
1431
- const { typeChecker: checker } = ctx;
1432
- const { description, tags } = getJSDocComment(node);
1433
- const sig = checker.getSignatureFromDeclaration(node);
1434
- if (!sig)
1435
- return null;
1436
- const params = extractParameters(sig, ctx);
1437
- const returnType = checker.getReturnTypeOfSignature(sig);
1438
- registerReferencedTypes(returnType, ctx);
1439
- return {
1440
- name: "()",
1441
- kind: "call-signature",
1442
- description,
1443
- tags: tags.length > 0 ? tags : undefined,
1444
- signatures: [
1445
- {
1446
- parameters: params.length > 0 ? params : undefined,
1447
- returns: {
1448
- schema: buildSchema(returnType, checker, ctx)
1449
- }
1450
- }
1451
- ]
1452
- };
1453
- }
1454
- function serializeIndexSignature(node, ctx) {
1455
- const { typeChecker: checker } = ctx;
1456
- const { description, tags } = getJSDocComment(node);
1457
- const valueType = node.type ? checker.getTypeAtLocation(node.type) : checker.getAnyType();
1458
- const valueSchema = buildSchema(valueType, checker, ctx);
1459
- registerReferencedTypes(valueType, ctx);
1460
- const keyParam = node.parameters[0];
1461
- const keyType = keyParam?.type ? checker.getTypeAtLocation(keyParam.type) : checker.getStringType();
1462
- const keyTypeName = checker.typeToString(keyType);
2123
+ ...schema ? { schema } : {},
2124
+ ...memberDesc ? { description: memberDesc } : {}
2125
+ };
2126
+ });
1463
2127
  return {
1464
- name: `[${keyTypeName}]`,
1465
- kind: "index-signature",
2128
+ id: name,
2129
+ name,
2130
+ kind: "enum",
1466
2131
  description,
1467
- tags: tags.length > 0 ? tags : undefined,
1468
- schema: {
1469
- type: "object",
1470
- additionalProperties: valueSchema
1471
- }
2132
+ tags,
2133
+ source,
2134
+ members,
2135
+ ...deprecated ? { deprecated: true } : {},
2136
+ ...examples.length > 0 ? { examples } : {}
1472
2137
  };
1473
2138
  }
1474
- function getInterfaceExtends(node, checker) {
1475
- if (!node.heritageClauses)
1476
- return;
1477
- for (const clause of node.heritageClauses) {
1478
- if (clause.token === ts7.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
1479
- const names = clause.types.map((expr) => {
1480
- const type = checker.getTypeAtLocation(expr);
1481
- return type.getSymbol()?.getName() ?? expr.expression.getText();
1482
- });
1483
- return names.join(" & ");
2139
+
2140
+ // src/serializers/functions.ts
2141
+ import ts8 from "typescript";
2142
+ function buildReturnSchema(sig, ctx) {
2143
+ const returnType = ctx.typeChecker.getReturnTypeOfSignature(sig);
2144
+ registerReferencedTypes(returnType, ctx);
2145
+ const schema = buildSchema(returnType, ctx.typeChecker, ctx);
2146
+ const declaration = sig.getDeclaration();
2147
+ if (declaration && ts8.isFunctionLike(declaration) && declaration.type) {
2148
+ const returnTypeNode = declaration.type;
2149
+ if (ts8.isTypePredicateNode(returnTypeNode)) {
2150
+ const parameterName = ts8.isIdentifier(returnTypeNode.parameterName) ? returnTypeNode.parameterName.text : returnTypeNode.parameterName.getText();
2151
+ let predicateTypeSchema = { type: "unknown" };
2152
+ if (returnTypeNode.type) {
2153
+ const predicateType = ctx.typeChecker.getTypeAtLocation(returnTypeNode.type);
2154
+ predicateTypeSchema = buildSchema(predicateType, ctx.typeChecker, ctx);
2155
+ registerReferencedTypes(predicateType, ctx);
2156
+ }
2157
+ const baseSchema = typeof schema === "string" ? { type: schema } : schema;
2158
+ const schemaWithPredicate = {
2159
+ ...baseSchema,
2160
+ "x-ts-type-predicate": {
2161
+ parameterName,
2162
+ type: predicateTypeSchema
2163
+ }
2164
+ };
2165
+ return { schema: schemaWithPredicate };
1484
2166
  }
1485
2167
  }
1486
- return;
2168
+ return { schema };
1487
2169
  }
1488
-
1489
- // src/serializers/type-aliases.ts
1490
- function serializeTypeAlias(node, ctx) {
2170
+ function serializeFunctionExport(node, ctx) {
1491
2171
  const symbol = ctx.typeChecker.getSymbolAtLocation(node.name ?? node);
1492
2172
  const name = symbol?.getName() ?? node.name?.getText();
1493
2173
  if (!name)
@@ -1498,673 +2178,448 @@ function serializeTypeAlias(node, ctx) {
1498
2178
  const source = getSourceLocation(node, declSourceFile);
1499
2179
  const typeParameters = extractTypeParameters(node, ctx.typeChecker);
1500
2180
  const type = ctx.typeChecker.getTypeAtLocation(node);
1501
- registerReferencedTypes(type, ctx);
1502
- const schema = buildSchema(type, ctx.typeChecker, ctx);
2181
+ const callSignatures = type.getCallSignatures();
2182
+ const signatures = callSignatures.map((sig, index) => {
2183
+ const params = extractParameters(sig, ctx);
2184
+ const sigDoc = getJSDocForSignature(sig);
2185
+ const sigTypeParams = extractTypeParametersFromSignature(sig, ctx.typeChecker);
2186
+ return {
2187
+ parameters: params,
2188
+ returns: buildReturnSchema(sig, ctx),
2189
+ ...sigDoc.description ? { description: sigDoc.description } : {},
2190
+ ...sigDoc.tags.length > 0 ? { tags: sigDoc.tags } : {},
2191
+ ...sigDoc.examples.length > 0 ? { examples: sigDoc.examples } : {},
2192
+ ...sigTypeParams ? { typeParameters: sigTypeParams } : {},
2193
+ ...callSignatures.length > 1 ? { overloadIndex: index } : {}
2194
+ };
2195
+ });
1503
2196
  return {
1504
2197
  id: name,
1505
2198
  name,
1506
- kind: "type",
2199
+ kind: "function",
1507
2200
  description,
1508
2201
  tags,
1509
2202
  source,
1510
2203
  typeParameters,
1511
- schema,
2204
+ signatures,
1512
2205
  ...deprecated ? { deprecated: true } : {},
1513
2206
  ...examples.length > 0 ? { examples } : {}
1514
2207
  };
1515
2208
  }
1516
2209
 
1517
- // src/schema/registry.ts
1518
- function isTypeReference(type) {
1519
- return !!(type.flags & 524288 && type.objectFlags && type.objectFlags & 4);
1520
- }
1521
- function getNonNullableType(type) {
1522
- if (type.isUnion()) {
1523
- const nonNullable = type.types.filter((t) => !(t.flags & 32768) && !(t.flags & 65536));
1524
- if (nonNullable.length === 1) {
1525
- return nonNullable[0];
1526
- }
1527
- }
1528
- return type;
1529
- }
1530
- var adapters = [];
1531
- function registerAdapter(adapter) {
1532
- adapters.push(adapter);
1533
- }
1534
- function findAdapter(type, checker) {
1535
- return adapters.find((a) => a.matches(type, checker));
1536
- }
1537
- function isSchemaType(type, checker) {
1538
- return adapters.some((a) => a.matches(type, checker));
1539
- }
1540
- function extractSchemaType(type, checker) {
1541
- const adapter = findAdapter(type, checker);
1542
- if (!adapter)
1543
- return null;
1544
- const outputType = adapter.extractOutputType(type, checker);
1545
- if (!outputType)
1546
- return null;
1547
- const inputType = adapter.extractInputType?.(type, checker) ?? undefined;
1548
- return {
1549
- adapter,
1550
- outputType,
1551
- inputType
1552
- };
1553
- }
1554
-
1555
- // src/schema/adapters/arktype.ts
1556
- var ARKTYPE_TYPE_PATTERN = /^Type</;
1557
- var arktypeAdapter = {
1558
- id: "arktype",
1559
- packages: ["arktype"],
1560
- matches(type, checker) {
1561
- const typeName = checker.typeToString(type);
1562
- return ARKTYPE_TYPE_PATTERN.test(typeName);
1563
- },
1564
- extractOutputType(type, checker) {
1565
- if (!isTypeReference(type)) {
1566
- return null;
1567
- }
1568
- const args = checker.getTypeArguments(type);
1569
- if (args.length < 1) {
1570
- return null;
1571
- }
1572
- return args[0];
1573
- },
1574
- extractInputType(type, checker) {
1575
- if (!isTypeReference(type)) {
1576
- return null;
1577
- }
1578
- const args = checker.getTypeArguments(type);
1579
- if (args.length < 2) {
1580
- return null;
1581
- }
1582
- return args[1];
1583
- }
1584
- };
1585
-
1586
- // src/schema/adapters/typebox.ts
1587
- var TYPEBOX_TYPE_PATTERN = /^T[A-Z]/;
1588
- var typeboxAdapter = {
1589
- id: "typebox",
1590
- packages: ["@sinclair/typebox"],
1591
- matches(type, checker) {
1592
- const typeName = checker.typeToString(type);
1593
- if (!TYPEBOX_TYPE_PATTERN.test(typeName)) {
1594
- return false;
1595
- }
1596
- const typeProperty = type.getProperty("type");
1597
- return typeProperty !== undefined;
1598
- },
1599
- extractOutputType(type, checker) {
1600
- const staticSymbol = type.getProperty("static");
1601
- if (staticSymbol) {
1602
- return checker.getTypeOfSymbol(staticSymbol);
1603
- }
1604
- return null;
1605
- }
1606
- };
1607
-
1608
- // src/schema/adapters/valibot.ts
1609
- var VALIBOT_TYPE_PATTERN = /Schema(<|$)/;
1610
- var valibotAdapter = {
1611
- id: "valibot",
1612
- packages: ["valibot"],
1613
- matches(type, checker) {
1614
- const typeName = checker.typeToString(type);
1615
- return VALIBOT_TYPE_PATTERN.test(typeName) && !typeName.includes("Zod");
1616
- },
1617
- extractOutputType(type, checker) {
1618
- const typesSymbol = type.getProperty("~types");
1619
- if (!typesSymbol) {
1620
- return null;
1621
- }
1622
- let typesType = checker.getTypeOfSymbol(typesSymbol);
1623
- typesType = getNonNullableType(typesType);
1624
- const outputSymbol = typesType.getProperty("output");
1625
- if (!outputSymbol) {
1626
- return null;
1627
- }
1628
- return checker.getTypeOfSymbol(outputSymbol);
1629
- },
1630
- extractInputType(type, checker) {
1631
- const typesSymbol = type.getProperty("~types");
1632
- if (!typesSymbol) {
1633
- return null;
1634
- }
1635
- let typesType = checker.getTypeOfSymbol(typesSymbol);
1636
- typesType = getNonNullableType(typesType);
1637
- const inputSymbol = typesType.getProperty("input");
1638
- if (!inputSymbol) {
1639
- return null;
1640
- }
1641
- return checker.getTypeOfSymbol(inputSymbol);
1642
- }
1643
- };
1644
-
1645
- // src/schema/adapters/zod.ts
1646
- var ZOD_TYPE_PATTERN = /^Zod[A-Z]/;
1647
- var zodAdapter = {
1648
- id: "zod",
1649
- packages: ["zod"],
1650
- matches(type, checker) {
1651
- const typeName = checker.typeToString(type);
1652
- return ZOD_TYPE_PATTERN.test(typeName);
1653
- },
1654
- extractOutputType(type, checker) {
1655
- const outputSymbol = type.getProperty("_output");
1656
- if (outputSymbol) {
1657
- return checker.getTypeOfSymbol(outputSymbol);
1658
- }
1659
- const typeSymbol = type.getProperty("_type");
1660
- if (typeSymbol) {
1661
- return checker.getTypeOfSymbol(typeSymbol);
1662
- }
1663
- return null;
1664
- },
1665
- extractInputType(type, checker) {
1666
- const inputSymbol = type.getProperty("_input");
1667
- if (inputSymbol) {
1668
- return checker.getTypeOfSymbol(inputSymbol);
1669
- }
1670
- return null;
1671
- }
1672
- };
1673
-
1674
- // src/schema/adapters/index.ts
1675
- registerAdapter(zodAdapter);
1676
- registerAdapter(valibotAdapter);
1677
- registerAdapter(arktypeAdapter);
1678
- registerAdapter(typeboxAdapter);
1679
-
1680
- // src/serializers/variables.ts
1681
- function serializeVariable(node, statement, ctx) {
1682
- const symbol = ctx.typeChecker.getSymbolAtLocation(node.name);
1683
- const name = symbol?.getName() ?? node.name.getText();
2210
+ // src/serializers/interfaces.ts
2211
+ import ts9 from "typescript";
2212
+ function serializeInterface(node, ctx) {
2213
+ const { typeChecker: checker } = ctx;
2214
+ const symbol = checker.getSymbolAtLocation(node.name ?? node);
2215
+ const name = symbol?.getName() ?? node.name?.getText();
1684
2216
  if (!name)
1685
2217
  return null;
1686
2218
  const deprecated = isSymbolDeprecated(symbol);
1687
2219
  const declSourceFile = node.getSourceFile();
1688
- const { description, tags, examples } = getJSDocComment(statement);
2220
+ const { description, tags, examples } = getJSDocComment(node);
1689
2221
  const source = getSourceLocation(node, declSourceFile);
1690
- const type = ctx.typeChecker.getTypeAtLocation(node);
1691
- const schemaExtraction = extractSchemaType(type, ctx.typeChecker);
1692
- const typeToSerialize = schemaExtraction?.outputType ?? type;
1693
- registerReferencedTypes(typeToSerialize, ctx);
1694
- const schema = buildSchema(typeToSerialize, ctx.typeChecker, ctx);
1695
- const flags = schemaExtraction ? {
1696
- schemaLibrary: schemaExtraction.adapter.id,
1697
- ...schemaExtraction.inputType && schemaExtraction.inputType !== schemaExtraction.outputType ? { hasTransform: true } : {}
1698
- } : undefined;
2222
+ const typeParameters = extractTypeParameters(node, checker);
2223
+ const members = [];
2224
+ const methodsByName = new Map;
2225
+ for (const member of node.members) {
2226
+ if (ts9.isPropertySignature(member)) {
2227
+ const propMember = serializePropertySignature(member, ctx);
2228
+ if (propMember)
2229
+ members.push(propMember);
2230
+ } else if (ts9.isMethodSignature(member)) {
2231
+ const methodMember = serializeMethodSignature(member, ctx);
2232
+ if (methodMember?.name) {
2233
+ if (!methodsByName.has(methodMember.name)) {
2234
+ methodsByName.set(methodMember.name, methodMember);
2235
+ }
2236
+ }
2237
+ } else if (ts9.isCallSignatureDeclaration(member)) {
2238
+ const callMember = serializeCallSignature(member, ctx);
2239
+ if (callMember)
2240
+ members.push(callMember);
2241
+ } else if (ts9.isIndexSignatureDeclaration(member)) {
2242
+ const indexMember = serializeIndexSignature(member, ctx);
2243
+ if (indexMember)
2244
+ members.push(indexMember);
2245
+ }
2246
+ }
2247
+ members.push(...methodsByName.values());
2248
+ const extendsClause = getInterfaceExtends(node, checker);
1699
2249
  return {
1700
2250
  id: name,
1701
2251
  name,
1702
- kind: "variable",
2252
+ kind: "interface",
1703
2253
  description,
1704
2254
  tags,
1705
2255
  source,
1706
- schema,
1707
- ...flags ? { flags } : {},
2256
+ typeParameters,
2257
+ members: members.length > 0 ? members : undefined,
2258
+ extends: extendsClause,
1708
2259
  ...deprecated ? { deprecated: true } : {},
1709
2260
  ...examples.length > 0 ? { examples } : {}
1710
2261
  };
1711
2262
  }
1712
-
1713
- // src/schema/standard-schema.ts
1714
- import { spawn, spawnSync } from "node:child_process";
1715
- import * as fs from "node:fs";
1716
- import * as os from "node:os";
1717
- import * as path2 from "node:path";
1718
- function isStandardJSONSchema(obj) {
1719
- if (typeof obj !== "object" || obj === null)
1720
- return false;
1721
- const std = obj["~standard"];
1722
- if (typeof std !== "object" || std === null)
1723
- return false;
1724
- const stdObj = std;
1725
- if (stdObj.version !== 1)
1726
- return false;
1727
- if (typeof stdObj.vendor !== "string")
1728
- return false;
1729
- const jsonSchema = stdObj.jsonSchema;
1730
- if (typeof jsonSchema !== "object" || jsonSchema === null)
1731
- return false;
1732
- const jsObj = jsonSchema;
1733
- return typeof jsObj.output === "function" && typeof jsObj.input === "function";
1734
- }
1735
- var cachedRuntime;
1736
- function commandExists(cmd) {
1737
- try {
1738
- const result = spawnSync(process.platform === "win32" ? "where" : "which", [cmd], {
1739
- stdio: "ignore"
1740
- });
1741
- return result.status === 0;
1742
- } catch {
1743
- return false;
2263
+ function serializePropertySignature(node, ctx) {
2264
+ const { typeChecker: checker } = ctx;
2265
+ const name = node.name.getText();
2266
+ const { description, tags } = getJSDocComment(node);
2267
+ const type = checker.getTypeAtLocation(node);
2268
+ const schema = buildSchema(type, checker, ctx);
2269
+ registerReferencedTypes(type, ctx);
2270
+ const flags = {};
2271
+ if (node.questionToken)
2272
+ flags.optional = true;
2273
+ if (node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.ReadonlyKeyword)) {
2274
+ flags.readonly = true;
1744
2275
  }
2276
+ return {
2277
+ name,
2278
+ kind: "property",
2279
+ description,
2280
+ tags: tags.length > 0 ? tags : undefined,
2281
+ schema,
2282
+ flags: Object.keys(flags).length > 0 ? flags : undefined
2283
+ };
1745
2284
  }
1746
- function detectTsRuntime() {
1747
- if (cachedRuntime !== undefined) {
1748
- return cachedRuntime;
1749
- }
1750
- const nodeVersion = parseInt(process.versions.node.split(".")[0], 10);
1751
- if (nodeVersion >= 22) {
1752
- cachedRuntime = {
1753
- cmd: "node",
1754
- args: ["--experimental-strip-types", "--no-warnings"],
1755
- name: "node (native)"
1756
- };
1757
- return cachedRuntime;
1758
- }
1759
- if (commandExists("bun")) {
1760
- cachedRuntime = {
1761
- cmd: "bun",
1762
- args: ["run"],
1763
- name: "bun"
1764
- };
1765
- return cachedRuntime;
1766
- }
1767
- if (commandExists("tsx")) {
1768
- cachedRuntime = {
1769
- cmd: "tsx",
1770
- args: [],
1771
- name: "tsx"
1772
- };
1773
- return cachedRuntime;
1774
- }
1775
- if (commandExists("ts-node")) {
1776
- cachedRuntime = {
1777
- cmd: "ts-node",
1778
- args: ["--transpile-only"],
1779
- name: "ts-node"
2285
+ function serializeMethodSignature(node, ctx) {
2286
+ const { typeChecker: checker } = ctx;
2287
+ const name = node.name.getText();
2288
+ const { description, tags } = getJSDocComment(node);
2289
+ const type = checker.getTypeAtLocation(node);
2290
+ const callSignatures = type.getCallSignatures();
2291
+ const signatures = callSignatures.map((sig, index) => {
2292
+ const params = extractParameters(sig, ctx);
2293
+ const returnType = checker.getReturnTypeOfSignature(sig);
2294
+ registerReferencedTypes(returnType, ctx);
2295
+ const sigDoc = getJSDocForSignature(sig);
2296
+ const sigTypeParams = extractTypeParametersFromSignature(sig, checker);
2297
+ return {
2298
+ parameters: params.length > 0 ? params : undefined,
2299
+ returns: {
2300
+ schema: buildSchema(returnType, checker, ctx)
2301
+ },
2302
+ ...sigDoc.description ? { description: sigDoc.description } : {},
2303
+ ...sigDoc.tags.length > 0 ? { tags: sigDoc.tags } : {},
2304
+ ...sigDoc.examples.length > 0 ? { examples: sigDoc.examples } : {},
2305
+ ...sigTypeParams ? { typeParameters: sigTypeParams } : {},
2306
+ ...callSignatures.length > 1 ? { overloadIndex: index } : {}
1780
2307
  };
1781
- return cachedRuntime;
1782
- }
1783
- cachedRuntime = null;
1784
- return null;
1785
- }
1786
- var WORKER_SCRIPT = `
1787
- const path = require('path');
1788
- const { pathToFileURL } = require('url');
1789
-
1790
- // TypeBox detection: schemas have Symbol.for('TypeBox.Kind') and are JSON Schema
1791
- const TYPEBOX_KIND = Symbol.for('TypeBox.Kind');
1792
-
1793
- function isTypeBoxSchema(obj) {
1794
- if (!obj || typeof obj !== 'object') return false;
1795
- // TypeBox schemas always have Kind symbol (Union, Object, String, etc.)
1796
- // Also check for common JSON Schema props to avoid false positives
1797
- if (!obj[TYPEBOX_KIND]) return false;
1798
- return typeof obj.type === 'string' || 'anyOf' in obj || 'oneOf' in obj || 'allOf' in obj;
1799
- }
1800
-
1801
- function sanitizeTypeBoxSchema(schema) {
1802
- // JSON.stringify removes symbol keys, keeping only JSON Schema props
1803
- return JSON.parse(JSON.stringify(schema));
2308
+ });
2309
+ const flags = {};
2310
+ if (node.questionToken)
2311
+ flags.optional = true;
2312
+ return {
2313
+ name,
2314
+ kind: "method",
2315
+ description,
2316
+ tags: tags.length > 0 ? tags : undefined,
2317
+ signatures: signatures.length > 0 ? signatures : undefined,
2318
+ flags: Object.keys(flags).length > 0 ? flags : undefined
2319
+ };
1804
2320
  }
1805
-
1806
- async function extract() {
1807
- // With node -e, argv is: [node, arg1, arg2, ...]
1808
- // (the -e script is NOT in argv)
1809
- const [modulePath, optionsJson] = process.argv.slice(1);
1810
- const { target, libraryOptions } = JSON.parse(optionsJson || '{}');
1811
-
1812
- try {
1813
- // Import the module using dynamic import (works with ESM and CJS)
1814
- const absPath = path.resolve(modulePath);
1815
- const mod = await import(pathToFileURL(absPath).href);
1816
- const results = [];
1817
-
1818
- // Build exports map - handle both ESM and CJS (where exports are in mod.default)
1819
- const exports = {};
1820
- for (const [name, value] of Object.entries(mod)) {
1821
- if (name === 'default' && typeof value === 'object' && value !== null) {
1822
- // CJS module: spread default exports
1823
- Object.assign(exports, value);
1824
- } else if (name !== 'default') {
1825
- exports[name] = value;
1826
- }
1827
- }
1828
-
1829
- // Check each export
1830
- for (const [name, value] of Object.entries(exports)) {
1831
- if (name.startsWith('_')) continue;
1832
- if (typeof value !== 'object' || value === null) continue;
1833
-
1834
- // Priority 1: Standard JSON Schema (Zod 4.2+, ArkType 2.1.28+, Valibot 1.2+)
1835
- const std = value['~standard'];
1836
- if (std && typeof std === 'object' && std.version === 1 && typeof std.vendor === 'string' && std.jsonSchema && typeof std.jsonSchema.output === 'function') {
1837
- try {
1838
- // Per spec: pass options object with target and optional libraryOptions
1839
- const options = { target: target || 'draft-2020-12', ...(libraryOptions && { libraryOptions }) };
1840
- const outputSchema = std.jsonSchema.output(options);
1841
- const inputSchema = typeof std.jsonSchema.input === 'function' ? std.jsonSchema.input(options) : undefined;
1842
- results.push({
1843
- exportName: name,
1844
- vendor: std.vendor,
1845
- outputSchema,
1846
- inputSchema
1847
- });
1848
- } catch (e) {
1849
- // Skip schemas that fail to extract
1850
- }
1851
- continue;
1852
- }
1853
-
1854
- // Priority 2: TypeBox (schema IS JSON Schema)
1855
- if (isTypeBoxSchema(value)) {
1856
- try {
1857
- results.push({
1858
- exportName: name,
1859
- vendor: 'typebox',
1860
- outputSchema: sanitizeTypeBoxSchema(value)
1861
- });
1862
- } catch (e) {
1863
- // Skip schemas that fail to extract
2321
+ function serializeCallSignature(node, ctx) {
2322
+ const { typeChecker: checker } = ctx;
2323
+ const { description, tags } = getJSDocComment(node);
2324
+ const sig = checker.getSignatureFromDeclaration(node);
2325
+ if (!sig)
2326
+ return null;
2327
+ const params = extractParameters(sig, ctx);
2328
+ const returnType = checker.getReturnTypeOfSignature(sig);
2329
+ registerReferencedTypes(returnType, ctx);
2330
+ return {
2331
+ name: "()",
2332
+ kind: "call-signature",
2333
+ description,
2334
+ tags: tags.length > 0 ? tags : undefined,
2335
+ signatures: [
2336
+ {
2337
+ parameters: params.length > 0 ? params : undefined,
2338
+ returns: {
2339
+ schema: buildSchema(returnType, checker, ctx)
1864
2340
  }
1865
- continue;
1866
2341
  }
2342
+ ]
2343
+ };
2344
+ }
2345
+ function serializeIndexSignature(node, ctx) {
2346
+ const { typeChecker: checker } = ctx;
2347
+ const { description, tags } = getJSDocComment(node);
2348
+ const valueType = node.type ? checker.getTypeAtLocation(node.type) : checker.getAnyType();
2349
+ const valueSchema = buildSchema(valueType, checker, ctx);
2350
+ registerReferencedTypes(valueType, ctx);
2351
+ const keyParam = node.parameters[0];
2352
+ const keyType = keyParam?.type ? checker.getTypeAtLocation(keyParam.type) : checker.getStringType();
2353
+ const keyTypeName = checker.typeToString(keyType);
2354
+ return {
2355
+ name: `[${keyTypeName}]`,
2356
+ kind: "index-signature",
2357
+ description,
2358
+ tags: tags.length > 0 ? tags : undefined,
2359
+ schema: {
2360
+ type: "object",
2361
+ additionalProperties: valueSchema
2362
+ }
2363
+ };
2364
+ }
2365
+ function getInterfaceExtends(node, checker) {
2366
+ if (!node.heritageClauses)
2367
+ return;
2368
+ for (const clause of node.heritageClauses) {
2369
+ if (clause.token === ts9.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
2370
+ const names = clause.types.map((expr) => {
2371
+ const type = checker.getTypeAtLocation(expr);
2372
+ return type.getSymbol()?.getName() ?? expr.expression.getText();
2373
+ });
2374
+ return names.join(" & ");
1867
2375
  }
1868
-
1869
- console.log(JSON.stringify({ success: true, results }));
1870
- } catch (e) {
1871
- console.log(JSON.stringify({ success: false, error: e.message }));
1872
2376
  }
2377
+ return;
1873
2378
  }
1874
2379
 
1875
- extract();
1876
- `;
1877
- var TS_WORKER_SCRIPT = `
1878
- import * as path from 'path';
1879
- import { pathToFileURL } from 'url';
1880
-
1881
- // TypeBox detection
1882
- const TYPEBOX_KIND = Symbol.for('TypeBox.Kind');
1883
-
1884
- function isTypeBoxSchema(obj: unknown): boolean {
1885
- if (!obj || typeof obj !== 'object') return false;
1886
- const o = obj as Record<string | symbol, unknown>;
1887
- if (!o[TYPEBOX_KIND]) return false;
1888
- return typeof o.type === 'string' || 'anyOf' in o || 'oneOf' in o || 'allOf' in o;
2380
+ // src/serializers/type-aliases.ts
2381
+ import ts10 from "typescript";
2382
+ function buildIntersectionSchemaFromNode(node, ctx) {
2383
+ const types = node.types;
2384
+ const schemas = [];
2385
+ for (const typeNode of types) {
2386
+ const type = ctx.typeChecker.getTypeAtLocation(typeNode);
2387
+ registerReferencedTypes(type, ctx);
2388
+ schemas.push(buildSchema(type, ctx.typeChecker, ctx));
2389
+ }
2390
+ if (schemas.length === 0) {
2391
+ return { type: "never" };
2392
+ }
2393
+ if (schemas.length === 1) {
2394
+ return schemas[0];
2395
+ }
2396
+ return { allOf: schemas };
1889
2397
  }
1890
-
1891
- function sanitizeTypeBoxSchema(schema: unknown): unknown {
1892
- return JSON.parse(JSON.stringify(schema));
2398
+ function serializeTypeAlias(node, ctx) {
2399
+ const symbol = ctx.typeChecker.getSymbolAtLocation(node.name ?? node);
2400
+ const name = symbol?.getName() ?? node.name?.getText();
2401
+ if (!name)
2402
+ return null;
2403
+ const deprecated = isSymbolDeprecated(symbol);
2404
+ const declSourceFile = node.getSourceFile();
2405
+ const { description, tags, examples } = getJSDocComment(node);
2406
+ const source = getSourceLocation(node, declSourceFile);
2407
+ const typeParameters = extractTypeParameters(node, ctx.typeChecker);
2408
+ const type = ctx.typeChecker.getTypeAtLocation(node);
2409
+ registerReferencedTypes(type, ctx);
2410
+ let schema;
2411
+ if (ts10.isIntersectionTypeNode(node.type)) {
2412
+ schema = buildIntersectionSchemaFromNode(node.type, ctx);
2413
+ } else {
2414
+ schema = buildSchema(type, ctx.typeChecker, ctx);
2415
+ }
2416
+ return {
2417
+ id: name,
2418
+ name,
2419
+ kind: "type",
2420
+ description,
2421
+ tags,
2422
+ source,
2423
+ typeParameters,
2424
+ schema,
2425
+ ...deprecated ? { deprecated: true } : {},
2426
+ ...examples.length > 0 ? { examples } : {}
2427
+ };
1893
2428
  }
1894
2429
 
1895
- async function extract() {
1896
- const [,, modulePath, optionsJson] = process.argv;
1897
- const { target, libraryOptions } = JSON.parse(optionsJson || '{}');
1898
-
1899
- try {
1900
- const absPath = path.resolve(modulePath);
1901
- const mod = await import(pathToFileURL(absPath).href);
1902
- const results: Array<{exportName: string; vendor: string; outputSchema: unknown; inputSchema?: unknown}> = [];
1903
-
1904
- // Build exports map
1905
- const exports: Record<string, unknown> = {};
1906
- for (const [name, value] of Object.entries(mod)) {
1907
- if (name === 'default' && typeof value === 'object' && value !== null) {
1908
- Object.assign(exports, value);
1909
- } else if (name !== 'default') {
1910
- exports[name] = value;
1911
- }
1912
- }
1913
-
1914
- // Check each export
1915
- for (const [name, value] of Object.entries(exports)) {
1916
- if (name.startsWith('_')) continue;
1917
- if (typeof value !== 'object' || value === null) continue;
1918
-
1919
- const v = value as Record<string, unknown>;
1920
- const std = v['~standard'] as Record<string, unknown> | undefined;
1921
-
1922
- // Standard JSON Schema
1923
- if (std && typeof std === 'object' && std.version === 1 && typeof std.vendor === 'string') {
1924
- const jsonSchema = std.jsonSchema as Record<string, unknown> | undefined;
1925
- if (jsonSchema && typeof jsonSchema.output === 'function') {
1926
- try {
1927
- const options = { target: target || 'draft-2020-12', ...(libraryOptions && { libraryOptions }) };
1928
- const outputSchema = (jsonSchema.output as Function)(options);
1929
- const inputSchema = typeof jsonSchema.input === 'function' ? (jsonSchema.input as Function)(options) : undefined;
1930
- results.push({ exportName: name, vendor: std.vendor as string, outputSchema, inputSchema });
1931
- } catch {}
1932
- continue;
1933
- }
1934
- }
1935
-
1936
- // TypeBox
1937
- if (isTypeBoxSchema(value)) {
1938
- try {
1939
- results.push({ exportName: name, vendor: 'typebox', outputSchema: sanitizeTypeBoxSchema(value) });
1940
- } catch {}
1941
- }
2430
+ // src/schema/registry.ts
2431
+ function isTypeReference(type) {
2432
+ return !!(type.flags & 524288 && type.objectFlags && type.objectFlags & 4);
2433
+ }
2434
+ function getNonNullableType(type) {
2435
+ if (type.isUnion()) {
2436
+ const nonNullable = type.types.filter((t) => !(t.flags & 32768) && !(t.flags & 65536));
2437
+ if (nonNullable.length === 1) {
2438
+ return nonNullable[0];
1942
2439
  }
1943
-
1944
- console.log(JSON.stringify({ success: true, results }));
1945
- } catch (e) {
1946
- console.log(JSON.stringify({ success: false, error: (e as Error).message }));
1947
2440
  }
2441
+ return type;
1948
2442
  }
1949
-
1950
- extract();
1951
- `;
1952
- async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
1953
- const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
1954
- const result = {
1955
- schemas: new Map,
1956
- errors: []
2443
+ var adapters = [];
2444
+ function registerAdapter(adapter) {
2445
+ adapters.push(adapter);
2446
+ }
2447
+ function findAdapter(type, checker) {
2448
+ return adapters.find((a) => a.matches(type, checker));
2449
+ }
2450
+ function isSchemaType(type, checker) {
2451
+ return adapters.some((a) => a.matches(type, checker));
2452
+ }
2453
+ function extractSchemaType(type, checker) {
2454
+ const adapter = findAdapter(type, checker);
2455
+ if (!adapter)
2456
+ return null;
2457
+ const outputType = adapter.extractOutputType(type, checker);
2458
+ if (!outputType)
2459
+ return null;
2460
+ const inputType = adapter.extractInputType?.(type, checker) ?? undefined;
2461
+ return {
2462
+ adapter,
2463
+ outputType,
2464
+ inputType
1957
2465
  };
1958
- const runtime = detectTsRuntime();
1959
- if (!runtime) {
1960
- result.errors.push("No TypeScript runtime available. Install bun, tsx, or ts-node, or use Node 22+.");
1961
- return result;
1962
- }
1963
- if (!fs.existsSync(tsFilePath)) {
1964
- result.errors.push(`TypeScript file not found: ${tsFilePath}`);
1965
- return result;
2466
+ }
2467
+
2468
+ // src/schema/adapters/arktype.ts
2469
+ var ARKTYPE_TYPE_PATTERN = /^Type</;
2470
+ var arktypeAdapter = {
2471
+ id: "arktype",
2472
+ packages: ["arktype"],
2473
+ matches(type, checker) {
2474
+ const typeName = checker.typeToString(type);
2475
+ return ARKTYPE_TYPE_PATTERN.test(typeName);
2476
+ },
2477
+ extractOutputType(type, checker) {
2478
+ if (!isTypeReference(type)) {
2479
+ return null;
2480
+ }
2481
+ const args = checker.getTypeArguments(type);
2482
+ if (args.length < 1) {
2483
+ return null;
2484
+ }
2485
+ return args[0];
2486
+ },
2487
+ extractInputType(type, checker) {
2488
+ if (!isTypeReference(type)) {
2489
+ return null;
2490
+ }
2491
+ const args = checker.getTypeArguments(type);
2492
+ if (args.length < 2) {
2493
+ return null;
2494
+ }
2495
+ return args[1];
1966
2496
  }
1967
- const tempDir = os.tmpdir();
1968
- const workerPath = path2.join(tempDir, `openpkg-extract-worker-${Date.now()}.ts`);
1969
- try {
1970
- fs.writeFileSync(workerPath, TS_WORKER_SCRIPT);
1971
- const optionsJson = JSON.stringify({ target, libraryOptions });
1972
- const args = [...runtime.args, workerPath, tsFilePath, optionsJson];
1973
- return await new Promise((resolve) => {
1974
- const child = spawn(runtime.cmd, args, {
1975
- timeout,
1976
- stdio: ["ignore", "pipe", "pipe"],
1977
- cwd: path2.dirname(tsFilePath)
1978
- });
1979
- let stdout = "";
1980
- let stderr = "";
1981
- child.stdout.on("data", (data) => {
1982
- stdout += data.toString();
1983
- });
1984
- child.stderr.on("data", (data) => {
1985
- stderr += data.toString();
1986
- });
1987
- child.on("close", (code) => {
1988
- try {
1989
- fs.unlinkSync(workerPath);
1990
- } catch {}
1991
- if (code !== 0) {
1992
- result.errors.push(`Extraction failed (${runtime.name}): ${stderr || `exit code ${code}`}`);
1993
- resolve(result);
1994
- return;
1995
- }
1996
- try {
1997
- const parsed = JSON.parse(stdout);
1998
- if (!parsed.success) {
1999
- result.errors.push(`Extraction failed: ${parsed.error}`);
2000
- resolve(result);
2001
- return;
2002
- }
2003
- for (const item of parsed.results) {
2004
- result.schemas.set(item.exportName, {
2005
- exportName: item.exportName,
2006
- vendor: item.vendor,
2007
- outputSchema: item.outputSchema,
2008
- inputSchema: item.inputSchema
2009
- });
2010
- }
2011
- } catch (e) {
2012
- result.errors.push(`Failed to parse extraction output: ${e}`);
2013
- }
2014
- resolve(result);
2015
- });
2016
- child.on("error", (err) => {
2017
- try {
2018
- fs.unlinkSync(workerPath);
2019
- } catch {}
2020
- result.errors.push(`Subprocess error: ${err.message}`);
2021
- resolve(result);
2022
- });
2023
- });
2024
- } catch (e) {
2025
- try {
2026
- fs.unlinkSync(workerPath);
2027
- } catch {}
2028
- result.errors.push(`Failed to create worker script: ${e}`);
2029
- return result;
2497
+ };
2498
+
2499
+ // src/schema/adapters/typebox.ts
2500
+ var TYPEBOX_TYPE_PATTERN = /^T[A-Z]/;
2501
+ var typeboxAdapter = {
2502
+ id: "typebox",
2503
+ packages: ["@sinclair/typebox"],
2504
+ matches(type, checker) {
2505
+ const typeName = checker.typeToString(type);
2506
+ if (!TYPEBOX_TYPE_PATTERN.test(typeName)) {
2507
+ return false;
2508
+ }
2509
+ const typeProperty = type.getProperty("type");
2510
+ return typeProperty !== undefined;
2511
+ },
2512
+ extractOutputType(type, checker) {
2513
+ const staticSymbol = type.getProperty("static");
2514
+ if (staticSymbol) {
2515
+ return checker.getTypeOfSymbol(staticSymbol);
2516
+ }
2517
+ return null;
2030
2518
  }
2031
- }
2032
- function readTsconfigOutDir(baseDir) {
2033
- const tsconfigPath = path2.join(baseDir, "tsconfig.json");
2034
- try {
2035
- if (!fs.existsSync(tsconfigPath)) {
2519
+ };
2520
+
2521
+ // src/schema/adapters/valibot.ts
2522
+ var VALIBOT_TYPE_PATTERN = /Schema(<|$)/;
2523
+ var valibotAdapter = {
2524
+ id: "valibot",
2525
+ packages: ["valibot"],
2526
+ matches(type, checker) {
2527
+ const typeName = checker.typeToString(type);
2528
+ return VALIBOT_TYPE_PATTERN.test(typeName) && !typeName.includes("Zod");
2529
+ },
2530
+ extractOutputType(type, checker) {
2531
+ const typesSymbol = type.getProperty("~types");
2532
+ if (!typesSymbol) {
2036
2533
  return null;
2037
2534
  }
2038
- const content = fs.readFileSync(tsconfigPath, "utf-8");
2039
- const stripped = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
2040
- const tsconfig = JSON.parse(stripped);
2041
- if (tsconfig.compilerOptions?.outDir) {
2042
- return tsconfig.compilerOptions.outDir.replace(/^\.\//, "");
2043
- }
2044
- } catch {}
2045
- return null;
2046
- }
2047
- function resolveCompiledPath(tsPath, baseDir) {
2048
- const relativePath = path2.relative(baseDir, tsPath);
2049
- const withoutExt = relativePath.replace(/\.tsx?$/, "");
2050
- const srcPrefix = withoutExt.replace(/^src\//, "");
2051
- const tsconfigOutDir = readTsconfigOutDir(baseDir);
2052
- const extensions = [".js", ".mjs", ".cjs"];
2053
- const candidates = [];
2054
- if (tsconfigOutDir) {
2055
- for (const ext of extensions) {
2056
- candidates.push(path2.join(baseDir, tsconfigOutDir, `${srcPrefix}${ext}`));
2535
+ let typesType = checker.getTypeOfSymbol(typesSymbol);
2536
+ typesType = getNonNullableType(typesType);
2537
+ const outputSymbol = typesType.getProperty("output");
2538
+ if (!outputSymbol) {
2539
+ return null;
2057
2540
  }
2058
- }
2059
- const commonOutDirs = ["dist", "build", "lib", "out"];
2060
- for (const outDir of commonOutDirs) {
2061
- if (outDir === tsconfigOutDir)
2062
- continue;
2063
- for (const ext of extensions) {
2064
- candidates.push(path2.join(baseDir, outDir, `${srcPrefix}${ext}`));
2541
+ return checker.getTypeOfSymbol(outputSymbol);
2542
+ },
2543
+ extractInputType(type, checker) {
2544
+ const typesSymbol = type.getProperty("~types");
2545
+ if (!typesSymbol) {
2546
+ return null;
2065
2547
  }
2066
- }
2067
- for (const ext of extensions) {
2068
- candidates.push(path2.join(baseDir, `${withoutExt}${ext}`));
2069
- }
2070
- const workspaceMatch = baseDir.match(/^(.+\/packages\/[^/]+)$/);
2071
- if (workspaceMatch) {
2072
- const pkgRoot = workspaceMatch[1];
2073
- for (const ext of extensions) {
2074
- candidates.push(path2.join(pkgRoot, "dist", `${srcPrefix}${ext}`));
2548
+ let typesType = checker.getTypeOfSymbol(typesSymbol);
2549
+ typesType = getNonNullableType(typesType);
2550
+ const inputSymbol = typesType.getProperty("input");
2551
+ if (!inputSymbol) {
2552
+ return null;
2075
2553
  }
2554
+ return checker.getTypeOfSymbol(inputSymbol);
2076
2555
  }
2077
- for (const candidate of candidates) {
2078
- if (fs.existsSync(candidate)) {
2079
- return candidate;
2556
+ };
2557
+
2558
+ // src/schema/adapters/zod.ts
2559
+ var ZOD_TYPE_PATTERN = /^Zod[A-Z]/;
2560
+ var zodAdapter = {
2561
+ id: "zod",
2562
+ packages: ["zod"],
2563
+ matches(type, checker) {
2564
+ const typeName = checker.typeToString(type);
2565
+ return ZOD_TYPE_PATTERN.test(typeName);
2566
+ },
2567
+ extractOutputType(type, checker) {
2568
+ const outputSymbol = type.getProperty("_output");
2569
+ if (outputSymbol) {
2570
+ return checker.getTypeOfSymbol(outputSymbol);
2080
2571
  }
2081
- }
2082
- return null;
2083
- }
2084
- async function extractStandardSchemas(compiledJsPath, options = {}) {
2085
- const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
2086
- const result = {
2087
- schemas: new Map,
2088
- errors: []
2089
- };
2090
- if (!fs.existsSync(compiledJsPath)) {
2091
- result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
2092
- return result;
2093
- }
2094
- const optionsJson = JSON.stringify({ target, libraryOptions });
2095
- return new Promise((resolve) => {
2096
- const child = spawn("node", ["-e", WORKER_SCRIPT, compiledJsPath, optionsJson], {
2097
- timeout,
2098
- stdio: ["ignore", "pipe", "pipe"]
2099
- });
2100
- let stdout = "";
2101
- let stderr = "";
2102
- child.stdout.on("data", (data) => {
2103
- stdout += data.toString();
2104
- });
2105
- child.stderr.on("data", (data) => {
2106
- stderr += data.toString();
2107
- });
2108
- child.on("close", (code) => {
2109
- if (code !== 0) {
2110
- result.errors.push(`Extraction process failed: ${stderr || `exit code ${code}`}`);
2111
- resolve(result);
2112
- return;
2113
- }
2114
- try {
2115
- const parsed = JSON.parse(stdout);
2116
- if (!parsed.success) {
2117
- result.errors.push(`Extraction failed: ${parsed.error}`);
2118
- resolve(result);
2119
- return;
2120
- }
2121
- for (const item of parsed.results) {
2122
- result.schemas.set(item.exportName, {
2123
- exportName: item.exportName,
2124
- vendor: item.vendor,
2125
- outputSchema: item.outputSchema,
2126
- inputSchema: item.inputSchema
2127
- });
2128
- }
2129
- } catch (e) {
2130
- result.errors.push(`Failed to parse extraction output: ${e}`);
2131
- }
2132
- resolve(result);
2133
- });
2134
- child.on("error", (err) => {
2135
- result.errors.push(`Subprocess error: ${err.message}`);
2136
- resolve(result);
2137
- });
2138
- });
2139
- }
2140
- async function extractStandardSchemasFromProject(entryFile, baseDir, options = {}) {
2141
- const { preferDirectTs, ...extractOptions } = options;
2142
- const isTypeScript = /\.tsx?$/.test(entryFile);
2143
- if (!preferDirectTs) {
2144
- const compiledPath = resolveCompiledPath(entryFile, baseDir);
2145
- if (compiledPath) {
2146
- const result = await extractStandardSchemas(compiledPath, extractOptions);
2147
- return {
2148
- ...result,
2149
- info: { method: "compiled", path: compiledPath }
2150
- };
2572
+ const typeSymbol = type.getProperty("_type");
2573
+ if (typeSymbol) {
2574
+ return checker.getTypeOfSymbol(typeSymbol);
2151
2575
  }
2152
- }
2153
- if (isTypeScript) {
2154
- const runtime2 = detectTsRuntime();
2155
- if (runtime2) {
2156
- const result = await extractStandardSchemasFromTs(entryFile, extractOptions);
2157
- return {
2158
- ...result,
2159
- info: { method: "direct-ts", runtime: runtime2.name, path: entryFile }
2160
- };
2576
+ return null;
2577
+ },
2578
+ extractInputType(type, checker) {
2579
+ const inputSymbol = type.getProperty("_input");
2580
+ if (inputSymbol) {
2581
+ return checker.getTypeOfSymbol(inputSymbol);
2161
2582
  }
2583
+ return null;
2162
2584
  }
2163
- const runtime = detectTsRuntime();
2164
- const hint = isTypeScript && !runtime ? " Install bun, tsx, or ts-node for direct TS execution." : "";
2585
+ };
2586
+
2587
+ // src/schema/adapters/index.ts
2588
+ registerAdapter(zodAdapter);
2589
+ registerAdapter(valibotAdapter);
2590
+ registerAdapter(arktypeAdapter);
2591
+ registerAdapter(typeboxAdapter);
2592
+
2593
+ // src/serializers/variables.ts
2594
+ function serializeVariable(node, statement, ctx) {
2595
+ const symbol = ctx.typeChecker.getSymbolAtLocation(node.name);
2596
+ const name = symbol?.getName() ?? node.name.getText();
2597
+ if (!name)
2598
+ return null;
2599
+ const deprecated = isSymbolDeprecated(symbol);
2600
+ const declSourceFile = node.getSourceFile();
2601
+ const { description, tags, examples } = getJSDocComment(statement);
2602
+ const source = getSourceLocation(node, declSourceFile);
2603
+ const type = ctx.typeChecker.getTypeAtLocation(node);
2604
+ const schemaExtraction = extractSchemaType(type, ctx.typeChecker);
2605
+ const typeToSerialize = schemaExtraction?.outputType ?? type;
2606
+ registerReferencedTypes(typeToSerialize, ctx);
2607
+ const schema = buildSchema(typeToSerialize, ctx.typeChecker, ctx);
2608
+ const flags = schemaExtraction ? {
2609
+ schemaLibrary: schemaExtraction.adapter.id,
2610
+ ...schemaExtraction.inputType && schemaExtraction.inputType !== schemaExtraction.outputType ? { hasTransform: true } : {}
2611
+ } : undefined;
2165
2612
  return {
2166
- schemas: new Map,
2167
- errors: [`Could not find compiled JS for ${entryFile}.${hint}`]
2613
+ id: name,
2614
+ name,
2615
+ kind: "variable",
2616
+ description,
2617
+ tags,
2618
+ source,
2619
+ schema,
2620
+ ...flags ? { flags } : {},
2621
+ ...deprecated ? { deprecated: true } : {},
2622
+ ...examples.length > 0 ? { examples } : {}
2168
2623
  };
2169
2624
  }
2170
2625
 
@@ -2381,6 +2836,18 @@ function normalizeStandardType(schema, options) {
2381
2836
  result[keyword] = schema[keyword];
2382
2837
  }
2383
2838
  }
2839
+ for (const key of Object.keys(schema)) {
2840
+ if (key.startsWith("x-ts-") && schema[key] !== undefined) {
2841
+ const value = schema[key];
2842
+ if (isSchemaLike(value)) {
2843
+ result[key] = normalizeSchemaInternal(value, options);
2844
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2845
+ result[key] = normalizeGenericObject(value, options);
2846
+ } else {
2847
+ result[key] = value;
2848
+ }
2849
+ }
2850
+ }
2384
2851
  return result;
2385
2852
  }
2386
2853
  function normalizeRef(schema, options) {
@@ -2388,6 +2855,11 @@ function normalizeRef(schema, options) {
2388
2855
  if (schema.typeArguments && schema.typeArguments.length > 0) {
2389
2856
  result["x-ts-type-arguments"] = schema.typeArguments.map((arg) => normalizeSchemaInternal(arg, options));
2390
2857
  }
2858
+ for (const key of Object.keys(schema)) {
2859
+ if (key.startsWith("x-ts-") && schema[key] !== undefined) {
2860
+ result[key] = schema[key];
2861
+ }
2862
+ }
2391
2863
  return result;
2392
2864
  }
2393
2865
  function normalizeCombinator(keyword, schemas, originalSchema, options) {
@@ -2589,23 +3061,7 @@ function isOptionalMember(member) {
2589
3061
  import * as fs2 from "node:fs";
2590
3062
  import * as path3 from "node:path";
2591
3063
  import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
2592
- import ts8 from "typescript";
2593
-
2594
- // src/serializers/context.ts
2595
- function createContext(program, sourceFile, options = {}) {
2596
- return {
2597
- typeChecker: program.getTypeChecker(),
2598
- program,
2599
- sourceFile,
2600
- maxTypeDepth: options.maxTypeDepth ?? 4,
2601
- maxExternalTypeDepth: options.maxExternalTypeDepth ?? 2,
2602
- currentDepth: 0,
2603
- resolveExternalTypes: options.resolveExternalTypes ?? true,
2604
- typeRegistry: new TypeRegistry,
2605
- exportedIds: new Set,
2606
- visitedTypes: new Set
2607
- };
2608
- }
3064
+ import ts11 from "typescript";
2609
3065
 
2610
3066
  // src/builder/schema-merger.ts
2611
3067
  function mergeRuntimeSchemas(staticExports, runtimeSchemas) {
@@ -2907,11 +3363,11 @@ function collectAllRefsWithContext(obj, refs, state) {
2907
3363
  function findTypeDefinition(typeName, program, sourceFile) {
2908
3364
  const checker = program.getTypeChecker();
2909
3365
  const findInNode = (node) => {
2910
- if ((ts8.isInterfaceDeclaration(node) || ts8.isTypeAliasDeclaration(node) || ts8.isClassDeclaration(node) || ts8.isEnumDeclaration(node)) && node.name?.text === typeName) {
3366
+ if ((ts11.isInterfaceDeclaration(node) || ts11.isTypeAliasDeclaration(node) || ts11.isClassDeclaration(node) || ts11.isEnumDeclaration(node)) && node.name?.text === typeName) {
2911
3367
  const sf = node.getSourceFile();
2912
3368
  return sf.fileName;
2913
3369
  }
2914
- return ts8.forEachChild(node, findInNode);
3370
+ return ts11.forEachChild(node, findInNode);
2915
3371
  };
2916
3372
  const entryResult = findInNode(sourceFile);
2917
3373
  if (entryResult)
@@ -2923,7 +3379,7 @@ function findTypeDefinition(typeName, program, sourceFile) {
2923
3379
  return result;
2924
3380
  }
2925
3381
  }
2926
- const symbol = checker.resolveName(typeName, sourceFile, ts8.SymbolFlags.Type, false);
3382
+ const symbol = checker.resolveName(typeName, sourceFile, ts11.SymbolFlags.Type, false);
2927
3383
  if (symbol?.declarations?.[0]) {
2928
3384
  return symbol.declarations[0].getSourceFile().fileName;
2929
3385
  }
@@ -2940,7 +3396,7 @@ function isExternalType2(definedIn, baseDir) {
2940
3396
  }
2941
3397
  function hasInternalTag(typeName, program, sourceFile) {
2942
3398
  const checker = program.getTypeChecker();
2943
- const symbol = checker.resolveName(typeName, sourceFile, ts8.SymbolFlags.Type, false);
3399
+ const symbol = checker.resolveName(typeName, sourceFile, ts11.SymbolFlags.Type, false);
2944
3400
  if (!symbol)
2945
3401
  return false;
2946
3402
  const jsTags = symbol.getJsDocTags();
@@ -2989,36 +3445,36 @@ function collectForgottenExports(exports, types, program, sourceFile, exportedId
2989
3445
  }
2990
3446
  function resolveExportTarget(symbol, checker) {
2991
3447
  let targetSymbol = symbol;
2992
- if (symbol.flags & ts8.SymbolFlags.Alias) {
3448
+ if (symbol.flags & ts11.SymbolFlags.Alias) {
2993
3449
  const aliasTarget = checker.getAliasedSymbol(symbol);
2994
3450
  if (aliasTarget && aliasTarget !== symbol) {
2995
3451
  targetSymbol = aliasTarget;
2996
3452
  }
2997
3453
  }
2998
3454
  const declarations = targetSymbol.declarations ?? [];
2999
- const declaration = targetSymbol.valueDeclaration || declarations.find((decl) => decl.kind !== ts8.SyntaxKind.ExportSpecifier) || declarations[0];
3455
+ const declaration = targetSymbol.valueDeclaration || declarations.find((decl) => decl.kind !== ts11.SyntaxKind.ExportSpecifier) || declarations[0];
3000
3456
  return { declaration, targetSymbol };
3001
3457
  }
3002
3458
  function serializeDeclaration(declaration, exportSymbol, _targetSymbol, exportName, ctx) {
3003
3459
  let result = null;
3004
- if (ts8.isFunctionDeclaration(declaration)) {
3460
+ if (ts11.isFunctionDeclaration(declaration)) {
3005
3461
  result = serializeFunctionExport(declaration, ctx);
3006
- } else if (ts8.isClassDeclaration(declaration)) {
3462
+ } else if (ts11.isClassDeclaration(declaration)) {
3007
3463
  result = serializeClass(declaration, ctx);
3008
- } else if (ts8.isInterfaceDeclaration(declaration)) {
3464
+ } else if (ts11.isInterfaceDeclaration(declaration)) {
3009
3465
  result = serializeInterface(declaration, ctx);
3010
- } else if (ts8.isTypeAliasDeclaration(declaration)) {
3466
+ } else if (ts11.isTypeAliasDeclaration(declaration)) {
3011
3467
  result = serializeTypeAlias(declaration, ctx);
3012
- } else if (ts8.isEnumDeclaration(declaration)) {
3468
+ } else if (ts11.isEnumDeclaration(declaration)) {
3013
3469
  result = serializeEnum(declaration, ctx);
3014
- } else if (ts8.isVariableDeclaration(declaration)) {
3470
+ } else if (ts11.isVariableDeclaration(declaration)) {
3015
3471
  const varStatement = declaration.parent?.parent;
3016
- if (varStatement && ts8.isVariableStatement(varStatement)) {
3472
+ if (varStatement && ts11.isVariableStatement(varStatement)) {
3017
3473
  result = serializeVariable(declaration, varStatement, ctx);
3018
3474
  }
3019
- } else if (ts8.isNamespaceExport(declaration) || ts8.isModuleDeclaration(declaration)) {
3475
+ } else if (ts11.isNamespaceExport(declaration) || ts11.isModuleDeclaration(declaration)) {
3020
3476
  result = serializeNamespaceExport(exportSymbol, exportName, ctx);
3021
- } else if (ts8.isSourceFile(declaration)) {
3477
+ } else if (ts11.isSourceFile(declaration)) {
3022
3478
  result = serializeNamespaceExport(exportSymbol, exportName, ctx);
3023
3479
  }
3024
3480
  if (result) {
@@ -3031,7 +3487,7 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
3031
3487
  const members = [];
3032
3488
  const checker = ctx.program.getTypeChecker();
3033
3489
  let targetSymbol = symbol;
3034
- if (symbol.flags & ts8.SymbolFlags.Alias) {
3490
+ if (symbol.flags & ts11.SymbolFlags.Alias) {
3035
3491
  const aliased = checker.getAliasedSymbol(symbol);
3036
3492
  if (aliased && aliased !== symbol) {
3037
3493
  targetSymbol = aliased;
@@ -3058,30 +3514,31 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
3058
3514
  function serializeNamespaceMember(symbol, memberName, ctx) {
3059
3515
  const checker = ctx.program.getTypeChecker();
3060
3516
  let targetSymbol = symbol;
3061
- if (symbol.flags & ts8.SymbolFlags.Alias) {
3517
+ if (symbol.flags & ts11.SymbolFlags.Alias) {
3062
3518
  const aliased = checker.getAliasedSymbol(symbol);
3063
3519
  if (aliased && aliased !== symbol) {
3064
3520
  targetSymbol = aliased;
3065
3521
  }
3066
3522
  }
3067
3523
  const declarations = targetSymbol.declarations ?? [];
3068
- const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts8.SyntaxKind.ExportSpecifier) || declarations[0];
3524
+ const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts11.SyntaxKind.ExportSpecifier) || declarations[0];
3069
3525
  if (!declaration)
3070
3526
  return null;
3527
+ const type = checker.getTypeAtLocation(declaration);
3528
+ const callSignatures = type.getCallSignatures();
3529
+ const deprecated = isSymbolDeprecated(targetSymbol);
3071
3530
  let kind = "variable";
3072
- if (ts8.isFunctionDeclaration(declaration) || ts8.isFunctionExpression(declaration)) {
3531
+ if (ts11.isFunctionDeclaration(declaration) || ts11.isFunctionExpression(declaration)) {
3073
3532
  kind = "function";
3074
- } else if (ts8.isClassDeclaration(declaration)) {
3533
+ } else if (ts11.isClassDeclaration(declaration)) {
3075
3534
  kind = "class";
3076
- } else if (ts8.isInterfaceDeclaration(declaration)) {
3535
+ } else if (ts11.isInterfaceDeclaration(declaration)) {
3077
3536
  kind = "interface";
3078
- } else if (ts8.isTypeAliasDeclaration(declaration)) {
3537
+ } else if (ts11.isTypeAliasDeclaration(declaration)) {
3079
3538
  kind = "type";
3080
- } else if (ts8.isEnumDeclaration(declaration)) {
3539
+ } else if (ts11.isEnumDeclaration(declaration)) {
3081
3540
  kind = "enum";
3082
- } else if (ts8.isVariableDeclaration(declaration)) {
3083
- const type = checker.getTypeAtLocation(declaration);
3084
- const callSignatures = type.getCallSignatures();
3541
+ } else if (ts11.isVariableDeclaration(declaration)) {
3085
3542
  if (callSignatures.length > 0) {
3086
3543
  kind = "function";
3087
3544
  }
@@ -3089,10 +3546,38 @@ function serializeNamespaceMember(symbol, memberName, ctx) {
3089
3546
  const docComment = targetSymbol.getDocumentationComment(checker);
3090
3547
  const description = docComment.map((c) => c.text).join(`
3091
3548
  `) || undefined;
3549
+ let signatures;
3550
+ if (kind === "function" && callSignatures.length > 0) {
3551
+ signatures = callSignatures.map((sig, index) => {
3552
+ const params = extractParameters(sig, ctx);
3553
+ const returnType = checker.getReturnTypeOfSignature(sig);
3554
+ registerReferencedTypes(returnType, ctx);
3555
+ const returnSchema = buildSchema(returnType, ctx.typeChecker, ctx);
3556
+ const sigDoc = getJSDocForSignature(sig);
3557
+ const sigTypeParams = extractTypeParametersFromSignature(sig, ctx.typeChecker);
3558
+ return {
3559
+ parameters: params,
3560
+ returns: { schema: returnSchema },
3561
+ ...sigDoc.description ? { description: sigDoc.description } : {},
3562
+ ...sigDoc.tags.length > 0 ? { tags: sigDoc.tags } : {},
3563
+ ...sigDoc.examples.length > 0 ? { examples: sigDoc.examples } : {},
3564
+ ...sigTypeParams ? { typeParameters: sigTypeParams } : {},
3565
+ ...callSignatures.length > 1 ? { overloadIndex: index } : {}
3566
+ };
3567
+ });
3568
+ }
3569
+ let schema;
3570
+ if (kind !== "function") {
3571
+ registerReferencedTypes(type, ctx);
3572
+ schema = buildSchema(type, ctx.typeChecker, ctx);
3573
+ }
3092
3574
  return {
3093
3575
  name: memberName,
3094
3576
  kind,
3095
- ...description ? { description } : {}
3577
+ ...description ? { description } : {},
3578
+ ...signatures ? { signatures } : {},
3579
+ ...schema ? { schema } : {},
3580
+ ...deprecated ? { flags: { deprecated: true } } : {}
3096
3581
  };
3097
3582
  }
3098
3583
  function getJSDocFromExportSymbol(symbol) {
@@ -3100,11 +3585,11 @@ function getJSDocFromExportSymbol(symbol) {
3100
3585
  const examples = [];
3101
3586
  const decl = symbol.declarations?.[0];
3102
3587
  if (decl) {
3103
- const exportDecl = ts8.isNamespaceExport(decl) ? decl.parent : decl;
3104
- if (exportDecl && ts8.isExportDeclaration(exportDecl)) {
3105
- const jsDocs = ts8.getJSDocCommentsAndTags(exportDecl);
3588
+ const exportDecl = ts11.isNamespaceExport(decl) ? decl.parent : decl;
3589
+ if (exportDecl && ts11.isExportDeclaration(exportDecl)) {
3590
+ const jsDocs = ts11.getJSDocCommentsAndTags(exportDecl);
3106
3591
  for (const doc of jsDocs) {
3107
- if (ts8.isJSDoc(doc) && doc.comment) {
3592
+ if (ts11.isJSDoc(doc) && doc.comment) {
3108
3593
  const commentText = typeof doc.comment === "string" ? doc.comment : doc.comment.map((c) => ("text" in c) ? c.text : "").join("");
3109
3594
  if (commentText) {
3110
3595
  return {
@@ -3189,4 +3674,4 @@ async function getPackageMeta(entryFile, baseDir) {
3189
3674
  } catch {}
3190
3675
  return { name: path3.basename(searchDir) };
3191
3676
  }
3192
- export { BUILTIN_TYPE_SCHEMAS, isPrimitiveName, isBuiltinGeneric, isAnonymous, buildSchema, isPureRefSchema, withDescription, schemaIsAny, schemasAreEqual, deduplicateSchemas, findDiscriminatorProperty, TypeRegistry, getJSDocComment, getSourceLocation, getParamDescription, extractTypeParameters, isSymbolDeprecated, createProgram, extractParameters, registerReferencedTypes, serializeClass, serializeEnum, serializeFunctionExport, serializeInterface, serializeTypeAlias, isTypeReference, getNonNullableType, registerAdapter, findAdapter, isSchemaType, extractSchemaType, arktypeAdapter, typeboxAdapter, valibotAdapter, zodAdapter, serializeVariable, isStandardJSONSchema, detectTsRuntime, extractStandardSchemasFromTs, resolveCompiledPath, extractStandardSchemas, extractStandardSchemasFromProject, normalizeSchema, normalizeExport, normalizeType, normalizeMembers, extract };
3677
+ export { BUILTIN_TYPE_SCHEMAS, ARRAY_PROTOTYPE_METHODS, isPrimitiveName, getTypeOrigin, isBuiltinGeneric, isAnonymous, buildSchema, isPureRefSchema, withDescription, schemaIsAny, schemasAreEqual, deduplicateSchemas, findDiscriminatorProperty, TypeRegistry, getJSDocComment, getSourceLocation, getParamDescription, extractTypeParameters, isSymbolDeprecated, createProgram, isStandardJSONSchema, detectTsRuntime, extractStandardSchemasFromTs, resolveCompiledPath, extractStandardSchemas, extractStandardSchemasFromProject, extractParameters, registerReferencedTypes, serializeClass, serializeEnum, serializeFunctionExport, serializeInterface, serializeTypeAlias, isTypeReference, getNonNullableType, registerAdapter, findAdapter, isSchemaType, extractSchemaType, arktypeAdapter, typeboxAdapter, valibotAdapter, zodAdapter, serializeVariable, normalizeSchema, normalizeExport, normalizeType, normalizeMembers, extract };