@openpkg-ts/sdk 0.34.0 → 0.35.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.
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  toPagefindRecords,
26
26
  toSearchIndex,
27
27
  toSearchIndexJSON
28
- } from "./shared/chunk-91b592v7.js";
28
+ } from "./shared/chunk-skapcfq1.js";
29
29
 
30
30
  // src/primitives/diff.ts
31
31
  import {
@@ -45,7 +45,10 @@ function loadConfig(cwd) {
45
45
  try {
46
46
  const content = fs.readFileSync(configPath, "utf-8");
47
47
  return JSON.parse(content);
48
- } catch {}
48
+ } catch (err) {
49
+ const msg = err instanceof SyntaxError ? err.message : String(err);
50
+ console.warn(`Warning: Invalid JSON in ${CONFIG_FILENAME}: ${msg}`);
51
+ }
49
52
  }
50
53
  const pkgPath = path.join(cwd, "package.json");
51
54
  if (fs.existsSync(pkgPath)) {
@@ -55,7 +58,10 @@ function loadConfig(cwd) {
55
58
  if (pkg.openpkg) {
56
59
  return pkg.openpkg;
57
60
  }
58
- } catch {}
61
+ } catch (err) {
62
+ const msg = err instanceof SyntaxError ? err.message : String(err);
63
+ console.warn(`Warning: Invalid JSON in package.json: ${msg}`);
64
+ }
59
65
  }
60
66
  return null;
61
67
  }
@@ -73,6 +79,7 @@ function mergeConfig(fileConfig, cliOptions) {
73
79
  }
74
80
  // src/core/loader.ts
75
81
  import * as fs2 from "node:fs";
82
+ import { validateSpec } from "@openpkg-ts/spec";
76
83
 
77
84
  // src/render/html.ts
78
85
  var defaultCSS = `
@@ -1098,7 +1105,21 @@ function loadSpec(spec) {
1098
1105
  return createDocsInstance(spec);
1099
1106
  }
1100
1107
  function createDocs(input) {
1101
- const spec = typeof input === "string" ? JSON.parse(fs2.readFileSync(input, "utf-8")) : input;
1108
+ let spec;
1109
+ if (typeof input === "string") {
1110
+ try {
1111
+ spec = JSON.parse(fs2.readFileSync(input, "utf-8"));
1112
+ } catch (err) {
1113
+ throw new Error(`Failed to parse spec file: ${err instanceof Error ? err.message : String(err)}`);
1114
+ }
1115
+ } else {
1116
+ spec = input;
1117
+ }
1118
+ const validation = validateSpec(spec);
1119
+ if (!validation.ok) {
1120
+ const errors = validation.errors.slice(0, 5).map((e) => `${e.instancePath || "/"}: ${e.message}`).join("; ");
1121
+ throw new Error(`Invalid OpenPkg spec: ${errors}`);
1122
+ }
1102
1123
  return createDocsInstance(spec);
1103
1124
  }
1104
1125
  function createDocsInstance(spec) {
@@ -2514,9 +2535,11 @@ function buildSchemaInternal(type, checker, ctx) {
2514
2535
  function buildFunctionSchema(callSignatures, checker, ctx) {
2515
2536
  const buildSignatures = () => {
2516
2537
  const signatures = callSignatures.map((sig) => {
2517
- const params = sig.getParameters().map((param) => {
2518
- const paramType = checker.getTypeOfSymbolAtLocation(param, param.valueDeclaration);
2538
+ const params = sig.getParameters().flatMap((param) => {
2519
2539
  const decl = param.valueDeclaration;
2540
+ if (!decl)
2541
+ return [];
2542
+ const paramType = checker.getTypeOfSymbolAtLocation(param, decl);
2520
2543
  const isOptional = !!decl?.questionToken || !!decl?.initializer;
2521
2544
  return {
2522
2545
  name: param.getName(),
@@ -2697,7 +2720,9 @@ function extractParameters(signature, ctx) {
2697
2720
  const jsdocTags = signatureDecl ? ts4.getJSDocTags(signatureDecl) : [];
2698
2721
  for (const param of signature.getParameters()) {
2699
2722
  const decl = param.valueDeclaration;
2700
- const type = checker.getTypeOfSymbolAtLocation(param, decl ?? param.valueDeclaration);
2723
+ if (!decl)
2724
+ continue;
2725
+ const type = checker.getTypeOfSymbolAtLocation(param, decl);
2701
2726
  if (decl && ts4.isObjectBindingPattern(decl.name)) {
2702
2727
  const expandedParams = expandBindingPattern(decl, type, jsdocTags, ctx);
2703
2728
  result.push(...expandedParams);
@@ -2842,7 +2867,12 @@ function registerReferencedTypes(type, ctx, depth = 0) {
2842
2867
  }
2843
2868
  if (type.flags & ts4.TypeFlags.Object) {
2844
2869
  const props = type.getProperties();
2845
- for (const prop of props.slice(0, 20)) {
2870
+ const limit = ctx.maxProperties;
2871
+ if (props.length > limit && ctx.onTruncation) {
2872
+ const typeName = type.getSymbol()?.getName() ?? "anonymous";
2873
+ ctx.onTruncation(typeName, props.length, limit);
2874
+ }
2875
+ for (const prop of props.slice(0, limit)) {
2846
2876
  const propType = checker.getTypeOfSymbol(prop);
2847
2877
  registerReferencedTypes(propType, ctx, depth + 1);
2848
2878
  }
@@ -3041,7 +3071,12 @@ class TypeRegistry {
3041
3071
  }
3042
3072
  const props = {};
3043
3073
  const required = [];
3044
- for (const prop of properties.slice(0, 20)) {
3074
+ const limit = ctx.maxProperties;
3075
+ if (properties.length > limit && ctx.onTruncation) {
3076
+ const typeName = type.getSymbol()?.getName() ?? "anonymous";
3077
+ ctx.onTruncation(typeName, properties.length, limit);
3078
+ }
3079
+ for (const prop of properties.slice(0, limit)) {
3045
3080
  const propName = prop.getName();
3046
3081
  if (propName.startsWith("_"))
3047
3082
  continue;
@@ -3075,7 +3110,9 @@ function createContext(program, sourceFile, options = {}) {
3075
3110
  typeRegistry: new TypeRegistry,
3076
3111
  exportedIds: new Set,
3077
3112
  visitedTypes: new Set,
3078
- includePrivate: options.includePrivate ?? false
3113
+ includePrivate: options.includePrivate ?? false,
3114
+ maxProperties: options.maxProperties ?? 20,
3115
+ onTruncation: options.onTruncation
3079
3116
  };
3080
3117
  }
3081
3118
  function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
@@ -3083,7 +3120,12 @@ function getInheritedMembers(classType, ownMemberNames, ctx, isStatic = false) {
3083
3120
  const inherited = [];
3084
3121
  const visited = new Set;
3085
3122
  const inheritedNames = new Set;
3086
- const typeToWalk = isStatic ? classType.getSymbol()?.valueDeclaration && checker.getTypeOfSymbolAtLocation(classType.getSymbol(), classType.getSymbol().valueDeclaration) : classType;
3123
+ let typeToWalk = classType;
3124
+ if (isStatic) {
3125
+ const symbol = classType.getSymbol();
3126
+ const valueDecl = symbol?.valueDeclaration;
3127
+ typeToWalk = symbol && valueDecl ? checker.getTypeOfSymbolAtLocation(symbol, valueDecl) : undefined;
3128
+ }
3087
3129
  if (!typeToWalk)
3088
3130
  return inherited;
3089
3131
  walkBaseTypes(typeToWalk, ownMemberNames, inherited, inheritedNames, visited, ctx, isStatic);
@@ -3234,6 +3276,8 @@ function serializeClass(node, ctx) {
3234
3276
  methodsByName.set(methodMember.name, methodMember);
3235
3277
  } else {
3236
3278
  const existing = methodsByName.get(methodMember.name);
3279
+ if (!existing)
3280
+ continue;
3237
3281
  if (!existing.description && methodMember.description) {
3238
3282
  existing.description = methodMember.description;
3239
3283
  }
@@ -4707,9 +4751,9 @@ function getDescriptionPreview(symbol, checker) {
4707
4751
  }
4708
4752
  // src/builder/spec-builder.ts
4709
4753
  import * as fs7 from "node:fs";
4710
- import * as path7 from "node:path";
4754
+ import * as path8 from "node:path";
4711
4755
  import { SCHEMA_URL, SCHEMA_VERSION } from "@openpkg-ts/spec";
4712
- import ts15 from "typescript";
4756
+ import ts16 from "typescript";
4713
4757
 
4714
4758
  // src/ast/resolve.ts
4715
4759
  import ts13 from "typescript";
@@ -4746,6 +4790,7 @@ import { spawn, spawnSync } from "node:child_process";
4746
4790
  import * as fs5 from "node:fs";
4747
4791
  import * as os from "node:os";
4748
4792
  import * as path5 from "node:path";
4793
+ var MAX_BUFFER_SIZE = 10 * 1024 * 1024;
4749
4794
  function isStandardJSONSchema(obj) {
4750
4795
  if (typeof obj !== "object" || obj === null)
4751
4796
  return false;
@@ -4845,6 +4890,7 @@ async function extract() {
4845
4890
  const absPath = path.resolve(modulePath);
4846
4891
  const mod = await import(pathToFileURL(absPath).href);
4847
4892
  const results = [];
4893
+ const warnings = [];
4848
4894
 
4849
4895
  // Build exports map - handle both ESM and CJS (where exports are in mod.default)
4850
4896
  const exports = {};
@@ -4877,7 +4923,7 @@ async function extract() {
4877
4923
  inputSchema
4878
4924
  });
4879
4925
  } catch (e) {
4880
- // Skip schemas that fail to extract
4926
+ warnings.push({ code: 'SCHEMA_FAILED', message: String(e), exportName: name });
4881
4927
  }
4882
4928
  continue;
4883
4929
  }
@@ -4891,15 +4937,15 @@ async function extract() {
4891
4937
  outputSchema: sanitizeTypeBoxSchema(value)
4892
4938
  });
4893
4939
  } catch (e) {
4894
- // Skip schemas that fail to extract
4940
+ warnings.push({ code: 'TYPEBOX_FAILED', message: String(e), exportName: name });
4895
4941
  }
4896
4942
  continue;
4897
4943
  }
4898
4944
  }
4899
4945
 
4900
- console.log(JSON.stringify({ success: true, results }));
4946
+ console.log(JSON.stringify({ success: true, results, warnings }));
4901
4947
  } catch (e) {
4902
- console.log(JSON.stringify({ success: false, error: e.message }));
4948
+ console.log(JSON.stringify({ success: false, error: e.message, warnings: [] }));
4903
4949
  }
4904
4950
  }
4905
4951
 
@@ -4931,6 +4977,7 @@ async function extract() {
4931
4977
  const absPath = path.resolve(modulePath);
4932
4978
  const mod = await import(pathToFileURL(absPath).href);
4933
4979
  const results: Array<{exportName: string; vendor: string; outputSchema: unknown; inputSchema?: unknown}> = [];
4980
+ const warnings: Array<{code: string; message: string; exportName?: string}> = [];
4934
4981
 
4935
4982
  // Build exports map
4936
4983
  const exports: Record<string, unknown> = {};
@@ -4959,7 +5006,9 @@ async function extract() {
4959
5006
  const outputSchema = (jsonSchema.output as Function)(options);
4960
5007
  const inputSchema = typeof jsonSchema.input === 'function' ? (jsonSchema.input as Function)(options) : undefined;
4961
5008
  results.push({ exportName: name, vendor: std.vendor as string, outputSchema, inputSchema });
4962
- } catch {}
5009
+ } catch (e) {
5010
+ warnings.push({ code: 'SCHEMA_FAILED', message: String(e), exportName: name });
5011
+ }
4963
5012
  continue;
4964
5013
  }
4965
5014
  }
@@ -4968,13 +5017,15 @@ async function extract() {
4968
5017
  if (isTypeBoxSchema(value)) {
4969
5018
  try {
4970
5019
  results.push({ exportName: name, vendor: 'typebox', outputSchema: sanitizeTypeBoxSchema(value) });
4971
- } catch {}
5020
+ } catch (e) {
5021
+ warnings.push({ code: 'TYPEBOX_FAILED', message: String(e), exportName: name });
5022
+ }
4972
5023
  }
4973
5024
  }
4974
5025
 
4975
- console.log(JSON.stringify({ success: true, results }));
5026
+ console.log(JSON.stringify({ success: true, results, warnings }));
4976
5027
  } catch (e) {
4977
- console.log(JSON.stringify({ success: false, error: (e as Error).message }));
5028
+ console.log(JSON.stringify({ success: false, error: (e as Error).message, warnings: [] }));
4978
5029
  }
4979
5030
  }
4980
5031
 
@@ -4984,7 +5035,8 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
4984
5035
  const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
4985
5036
  const result = {
4986
5037
  schemas: new Map,
4987
- errors: []
5038
+ errors: [],
5039
+ warnings: []
4988
5040
  };
4989
5041
  const runtime = detectTsRuntime();
4990
5042
  if (!runtime) {
@@ -5009,16 +5061,32 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5009
5061
  });
5010
5062
  let stdout = "";
5011
5063
  let stderr = "";
5064
+ let stdoutTruncated = false;
5065
+ let stderrTruncated = false;
5012
5066
  child.stdout.on("data", (data) => {
5013
- stdout += data.toString();
5067
+ if (stdout.length < MAX_BUFFER_SIZE) {
5068
+ const chunk = data.toString();
5069
+ stdout += chunk.slice(0, MAX_BUFFER_SIZE - stdout.length);
5070
+ if (stdout.length >= MAX_BUFFER_SIZE)
5071
+ stdoutTruncated = true;
5072
+ }
5014
5073
  });
5015
5074
  child.stderr.on("data", (data) => {
5016
- stderr += data.toString();
5075
+ if (stderr.length < MAX_BUFFER_SIZE) {
5076
+ const chunk = data.toString();
5077
+ stderr += chunk.slice(0, MAX_BUFFER_SIZE - stderr.length);
5078
+ if (stderr.length >= MAX_BUFFER_SIZE)
5079
+ stderrTruncated = true;
5080
+ }
5017
5081
  });
5018
5082
  child.on("close", (code) => {
5019
5083
  try {
5020
5084
  fs5.unlinkSync(workerPath);
5021
- } catch {}
5085
+ } catch (cleanupErr) {
5086
+ if (cleanupErr?.code !== "ENOENT") {
5087
+ result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
5088
+ }
5089
+ }
5022
5090
  if (code !== 0) {
5023
5091
  result.errors.push(`Extraction failed (${runtime.name}): ${stderr || `exit code ${code}`}`);
5024
5092
  resolve2(result);
@@ -5039,15 +5107,34 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5039
5107
  inputSchema: item.inputSchema
5040
5108
  });
5041
5109
  }
5110
+ if (Array.isArray(parsed.warnings)) {
5111
+ for (const w of parsed.warnings) {
5112
+ result.warnings.push({
5113
+ code: w.code,
5114
+ message: w.message,
5115
+ exportName: w.exportName
5116
+ });
5117
+ }
5118
+ }
5042
5119
  } catch (e) {
5043
5120
  result.errors.push(`Failed to parse extraction output: ${e}`);
5044
5121
  }
5122
+ if (stdoutTruncated) {
5123
+ result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stdout exceeded 10MB buffer limit" });
5124
+ }
5125
+ if (stderrTruncated) {
5126
+ result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stderr exceeded 10MB buffer limit" });
5127
+ }
5045
5128
  resolve2(result);
5046
5129
  });
5047
5130
  child.on("error", (err) => {
5048
5131
  try {
5049
5132
  fs5.unlinkSync(workerPath);
5050
- } catch {}
5133
+ } catch (cleanupErr) {
5134
+ if (cleanupErr?.code !== "ENOENT") {
5135
+ result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
5136
+ }
5137
+ }
5051
5138
  result.errors.push(`Subprocess error: ${err.message}`);
5052
5139
  resolve2(result);
5053
5140
  });
@@ -5055,7 +5142,11 @@ async function extractStandardSchemasFromTs(tsFilePath, options = {}) {
5055
5142
  } catch (e) {
5056
5143
  try {
5057
5144
  fs5.unlinkSync(workerPath);
5058
- } catch {}
5145
+ } catch (cleanupErr) {
5146
+ if (cleanupErr?.code !== "ENOENT") {
5147
+ result.warnings.push({ code: "CLEANUP_FAILED", message: String(cleanupErr) });
5148
+ }
5149
+ }
5059
5150
  result.errors.push(`Failed to create worker script: ${e}`);
5060
5151
  return result;
5061
5152
  }
@@ -5072,7 +5163,7 @@ function readTsconfigOutDir(baseDir) {
5072
5163
  if (tsconfig.compilerOptions?.outDir) {
5073
5164
  return tsconfig.compilerOptions.outDir.replace(/^\.\//, "");
5074
5165
  }
5075
- } catch {}
5166
+ } catch (_e) {}
5076
5167
  return null;
5077
5168
  }
5078
5169
  function resolveCompiledPath(tsPath, baseDir) {
@@ -5116,7 +5207,8 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
5116
5207
  const { timeout = 1e4, target = "draft-2020-12", libraryOptions } = options;
5117
5208
  const result = {
5118
5209
  schemas: new Map,
5119
- errors: []
5210
+ errors: [],
5211
+ warnings: []
5120
5212
  };
5121
5213
  if (!fs5.existsSync(compiledJsPath)) {
5122
5214
  result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
@@ -5130,11 +5222,23 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
5130
5222
  });
5131
5223
  let stdout = "";
5132
5224
  let stderr = "";
5225
+ let stdoutTruncated = false;
5226
+ let stderrTruncated = false;
5133
5227
  child.stdout.on("data", (data) => {
5134
- stdout += data.toString();
5228
+ if (stdout.length < MAX_BUFFER_SIZE) {
5229
+ const chunk = data.toString();
5230
+ stdout += chunk.slice(0, MAX_BUFFER_SIZE - stdout.length);
5231
+ if (stdout.length >= MAX_BUFFER_SIZE)
5232
+ stdoutTruncated = true;
5233
+ }
5135
5234
  });
5136
5235
  child.stderr.on("data", (data) => {
5137
- stderr += data.toString();
5236
+ if (stderr.length < MAX_BUFFER_SIZE) {
5237
+ const chunk = data.toString();
5238
+ stderr += chunk.slice(0, MAX_BUFFER_SIZE - stderr.length);
5239
+ if (stderr.length >= MAX_BUFFER_SIZE)
5240
+ stderrTruncated = true;
5241
+ }
5138
5242
  });
5139
5243
  child.on("close", (code) => {
5140
5244
  if (code !== 0) {
@@ -5157,9 +5261,24 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
5157
5261
  inputSchema: item.inputSchema
5158
5262
  });
5159
5263
  }
5264
+ if (Array.isArray(parsed.warnings)) {
5265
+ for (const w of parsed.warnings) {
5266
+ result.warnings.push({
5267
+ code: w.code,
5268
+ message: w.message,
5269
+ exportName: w.exportName
5270
+ });
5271
+ }
5272
+ }
5160
5273
  } catch (e) {
5161
5274
  result.errors.push(`Failed to parse extraction output: ${e}`);
5162
5275
  }
5276
+ if (stdoutTruncated) {
5277
+ result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stdout exceeded 10MB buffer limit" });
5278
+ }
5279
+ if (stderrTruncated) {
5280
+ result.warnings.push({ code: "OUTPUT_TRUNCATED", message: "stderr exceeded 10MB buffer limit" });
5281
+ }
5163
5282
  resolve2(result);
5164
5283
  });
5165
5284
  child.on("error", (err) => {
@@ -5195,7 +5314,8 @@ async function extractStandardSchemasFromProject(entryFile, baseDir, options = {
5195
5314
  const hint = isTypeScript && !runtime ? " Install bun, tsx, or ts-node for direct TS execution." : "";
5196
5315
  return {
5197
5316
  schemas: new Map,
5198
- errors: [`Could not find compiled JS for ${entryFile}.${hint}`]
5317
+ errors: [`Could not find compiled JS for ${entryFile}.${hint}`],
5318
+ warnings: []
5199
5319
  };
5200
5320
  }
5201
5321
 
@@ -5394,72 +5514,149 @@ function mergeRuntimeSchemas(staticExports, runtimeSchemas) {
5394
5514
  return { merged, exports };
5395
5515
  }
5396
5516
 
5397
- // src/builder/spec-builder.ts
5398
- var typeDefinitionCache = null;
5399
- function getTypeDefinitionCache() {
5400
- if (!typeDefinitionCache) {
5401
- typeDefinitionCache = new Map;
5517
+ // src/builder/type-cache.ts
5518
+ import ts15 from "typescript";
5519
+
5520
+ // src/utils/cache-manager.ts
5521
+ class CacheManager {
5522
+ cache;
5523
+ maxSize;
5524
+ ttl;
5525
+ constructor(options = {}) {
5526
+ this.maxSize = options.maxSize ?? 1000;
5527
+ this.ttl = options.ttl;
5528
+ this.cache = new Map;
5529
+ }
5530
+ get(key) {
5531
+ const entry = this.cache.get(key);
5532
+ if (!entry)
5533
+ return;
5534
+ if (entry.expiresAt && Date.now() > entry.expiresAt) {
5535
+ this.cache.delete(key);
5536
+ return;
5537
+ }
5538
+ this.cache.delete(key);
5539
+ this.cache.set(key, entry);
5540
+ return entry.value;
5402
5541
  }
5403
- return typeDefinitionCache;
5404
- }
5405
- var internalTagCache = null;
5406
- function getInternalTagCache() {
5407
- if (!internalTagCache) {
5408
- internalTagCache = new Map;
5542
+ has(key) {
5543
+ const entry = this.cache.get(key);
5544
+ if (!entry)
5545
+ return false;
5546
+ if (entry.expiresAt && Date.now() > entry.expiresAt) {
5547
+ this.cache.delete(key);
5548
+ return false;
5549
+ }
5550
+ return true;
5551
+ }
5552
+ set(key, value) {
5553
+ if (this.cache.has(key)) {
5554
+ this.cache.delete(key);
5555
+ }
5556
+ if (this.cache.size >= this.maxSize) {
5557
+ const firstKey = this.cache.keys().next().value;
5558
+ if (firstKey !== undefined) {
5559
+ this.cache.delete(firstKey);
5560
+ }
5561
+ }
5562
+ const entry = {
5563
+ value,
5564
+ ...this.ttl ? { expiresAt: Date.now() + this.ttl } : {}
5565
+ };
5566
+ this.cache.set(key, entry);
5567
+ }
5568
+ delete(key) {
5569
+ return this.cache.delete(key);
5570
+ }
5571
+ clear() {
5572
+ this.cache.clear();
5573
+ }
5574
+ get size() {
5575
+ return this.cache.size;
5576
+ }
5577
+ keys() {
5578
+ return this.cache.keys();
5579
+ }
5580
+ values() {
5581
+ const result = [];
5582
+ const now = Date.now();
5583
+ for (const [key, entry] of this.cache) {
5584
+ if (entry.expiresAt && now > entry.expiresAt) {
5585
+ this.cache.delete(key);
5586
+ continue;
5587
+ }
5588
+ result.push(entry.value);
5589
+ }
5590
+ return result;
5409
5591
  }
5410
- return internalTagCache;
5411
5592
  }
5593
+
5594
+ // src/builder/type-cache.ts
5595
+ var typeDefinitionCache = new CacheManager({ maxSize: 1000 });
5596
+ var internalTagCache = new CacheManager({ maxSize: 1000 });
5597
+ var regexCache = new CacheManager({ maxSize: 100 });
5412
5598
  function clearTypeDefinitionCache() {
5413
- typeDefinitionCache = null;
5414
- internalTagCache = null;
5599
+ typeDefinitionCache.clear();
5600
+ internalTagCache.clear();
5601
+ regexCache.clear();
5415
5602
  }
5416
- var YIELD_BATCH_SIZE = 5;
5417
- function computeDegradedStats(exports) {
5418
- let exportsWithoutDescription = 0;
5419
- let paramsWithoutDocs = 0;
5420
- let missingExamples = 0;
5421
- for (const exp of exports) {
5422
- if (!exp.description)
5423
- exportsWithoutDescription++;
5424
- if (!exp.examples || exp.examples.length === 0)
5425
- missingExamples++;
5426
- const signatures = exp.signatures;
5427
- if (signatures) {
5428
- for (const sig of signatures) {
5429
- for (const param of sig.parameters ?? []) {
5430
- if (!param.description)
5431
- paramsWithoutDocs++;
5432
- }
5603
+ function getRegexCache() {
5604
+ return regexCache;
5605
+ }
5606
+ function findTypeDefinition(typeName, program, sourceFile) {
5607
+ if (typeDefinitionCache.has(typeName)) {
5608
+ return typeDefinitionCache.get(typeName);
5609
+ }
5610
+ const checker = program.getTypeChecker();
5611
+ const findInNode = (node) => {
5612
+ if ((ts15.isInterfaceDeclaration(node) || ts15.isTypeAliasDeclaration(node) || ts15.isClassDeclaration(node) || ts15.isEnumDeclaration(node)) && node.name?.text === typeName) {
5613
+ const sf = node.getSourceFile();
5614
+ return sf.fileName;
5615
+ }
5616
+ return ts15.forEachChild(node, findInNode);
5617
+ };
5618
+ const entryResult = findInNode(sourceFile);
5619
+ if (entryResult) {
5620
+ typeDefinitionCache.set(typeName, entryResult);
5621
+ return entryResult;
5622
+ }
5623
+ for (const sf of program.getSourceFiles()) {
5624
+ if (sf.isDeclarationFile && !sf.fileName.includes("node_modules")) {
5625
+ const result = findInNode(sf);
5626
+ if (result) {
5627
+ typeDefinitionCache.set(typeName, result);
5628
+ return result;
5433
5629
  }
5434
5630
  }
5435
5631
  }
5436
- return { exportsWithoutDescription, paramsWithoutDocs, missingExamples };
5632
+ const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
5633
+ if (symbol?.declarations?.[0]) {
5634
+ const result = symbol.declarations[0].getSourceFile().fileName;
5635
+ typeDefinitionCache.set(typeName, result);
5636
+ return result;
5637
+ }
5638
+ typeDefinitionCache.set(typeName, undefined);
5639
+ return;
5437
5640
  }
5438
- function buildVerificationSummary(discoveredCount, extractedCount, tracker) {
5439
- const skippedDetails = [];
5440
- const failedDetails = [];
5441
- for (const entry of tracker.values()) {
5442
- if (entry.status === "skipped" && entry.skipReason) {
5443
- skippedDetails.push({ name: entry.name, reason: entry.skipReason });
5444
- } else if (entry.status === "failed" && entry.error) {
5445
- failedDetails.push({ name: entry.name, error: entry.error });
5446
- }
5641
+ function hasInternalTag(typeName, program, sourceFile) {
5642
+ const cached = internalTagCache.get(typeName);
5643
+ if (cached !== undefined) {
5644
+ return cached;
5447
5645
  }
5448
- const skipped = skippedDetails.length;
5449
- const failed = failedDetails.length;
5450
- const delta = discoveredCount - extractedCount - skipped;
5451
- return {
5452
- discovered: discoveredCount,
5453
- extracted: extractedCount,
5454
- skipped,
5455
- failed,
5456
- delta,
5457
- details: {
5458
- skipped: skippedDetails,
5459
- failed: failedDetails
5460
- }
5461
- };
5646
+ const checker = program.getTypeChecker();
5647
+ const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
5648
+ if (!symbol) {
5649
+ internalTagCache.set(typeName, false);
5650
+ return false;
5651
+ }
5652
+ const jsTags = symbol.getJsDocTags();
5653
+ const isInternal = jsTags.some((tag) => tag.name === "internal");
5654
+ internalTagCache.set(typeName, isInternal);
5655
+ return isInternal;
5462
5656
  }
5657
+
5658
+ // src/builder/verification.ts
5659
+ import * as path7 from "node:path";
5463
5660
  var BUILTIN_TYPES2 = new Set([
5464
5661
  "Array",
5465
5662
  "ArrayBuffer",
@@ -5518,19 +5715,39 @@ var BUILTIN_TYPES2 = new Set([
5518
5715
  "InstanceType",
5519
5716
  "ThisType"
5520
5717
  ]);
5521
- function matchesPattern(name, pattern) {
5522
- if (!pattern.includes("*"))
5523
- return name === pattern;
5524
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
5525
- return regex.test(name);
5526
- }
5527
- function shouldIncludeExport(name, only, ignore) {
5528
- if (ignore?.some((p) => matchesPattern(name, p)))
5529
- return false;
5530
- if (only && only.length > 0) {
5531
- return only.some((p) => matchesPattern(name, p));
5718
+ function buildVerificationSummary(discoveredCount, extractedCount, tracker) {
5719
+ const skippedDetails = [];
5720
+ const failedDetails = [];
5721
+ for (const entry of tracker.values()) {
5722
+ if (entry.status === "skipped" && entry.skipReason) {
5723
+ skippedDetails.push({ name: entry.name, reason: entry.skipReason });
5724
+ } else if (entry.status === "failed" && entry.error) {
5725
+ failedDetails.push({ name: entry.name, error: entry.error });
5726
+ }
5532
5727
  }
5533
- return true;
5728
+ const skipped = skippedDetails.length;
5729
+ const failed = failedDetails.length;
5730
+ const delta = discoveredCount - extractedCount - skipped;
5731
+ return {
5732
+ discovered: discoveredCount,
5733
+ extracted: extractedCount,
5734
+ skipped,
5735
+ failed,
5736
+ delta,
5737
+ details: {
5738
+ skipped: skippedDetails,
5739
+ failed: failedDetails
5740
+ }
5741
+ };
5742
+ }
5743
+ function isExternalType2(definedIn, baseDir) {
5744
+ if (!definedIn)
5745
+ return true;
5746
+ if (definedIn.includes("node_modules"))
5747
+ return true;
5748
+ const normalizedDefined = path7.resolve(definedIn);
5749
+ const normalizedBase = path7.resolve(baseDir);
5750
+ return !normalizedDefined.startsWith(normalizedBase);
5534
5751
  }
5535
5752
  function shouldSkipDanglingRef(name) {
5536
5753
  if (name.startsWith("__"))
@@ -5543,255 +5760,6 @@ function shouldSkipDanglingRef(name) {
5543
5760
  return true;
5544
5761
  return false;
5545
5762
  }
5546
- async function extract(options) {
5547
- clearTypeDefinitionCache();
5548
- const {
5549
- entryFile,
5550
- baseDir,
5551
- content,
5552
- maxTypeDepth,
5553
- maxExternalTypeDepth,
5554
- resolveExternalTypes,
5555
- includeSchema,
5556
- only,
5557
- ignore,
5558
- onProgress,
5559
- isDtsSource,
5560
- includePrivate
5561
- } = options;
5562
- const diagnostics = [];
5563
- let exports = [];
5564
- const result = createProgram({ entryFile, baseDir, content });
5565
- const { program, sourceFile } = result;
5566
- if (!sourceFile) {
5567
- return {
5568
- spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5569
- diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
5570
- };
5571
- }
5572
- const typeChecker = program.getTypeChecker();
5573
- const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
5574
- if (!moduleSymbol) {
5575
- return {
5576
- spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5577
- diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
5578
- };
5579
- }
5580
- const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
5581
- const exportedIds = new Set;
5582
- for (const symbol of exportedSymbols) {
5583
- exportedIds.add(symbol.getName());
5584
- }
5585
- const exportTracker = new Map;
5586
- for (const symbol of exportedSymbols) {
5587
- const name = symbol.getName();
5588
- const included = shouldIncludeExport(name, only, ignore);
5589
- exportTracker.set(name, {
5590
- name,
5591
- discovered: true,
5592
- status: included ? "pending" : "skipped",
5593
- ...included ? {} : { skipReason: "filtered" }
5594
- });
5595
- }
5596
- const ctx = createContext(program, sourceFile, {
5597
- maxTypeDepth,
5598
- maxExternalTypeDepth,
5599
- resolveExternalTypes,
5600
- includePrivate
5601
- });
5602
- ctx.exportedIds = exportedIds;
5603
- const filteredSymbols = exportedSymbols.filter((s) => shouldIncludeExport(s.getName(), only, ignore));
5604
- const total = filteredSymbols.length;
5605
- for (let i = 0;i < filteredSymbols.length; i++) {
5606
- const symbol = filteredSymbols[i];
5607
- const exportName = symbol.getName();
5608
- const tracker = exportTracker.get(exportName);
5609
- onProgress?.(i + 1, total, exportName);
5610
- if (i > 0 && i % YIELD_BATCH_SIZE === 0) {
5611
- await new Promise((r) => setImmediate(r));
5612
- }
5613
- try {
5614
- const { declaration, targetSymbol, isTypeOnly } = resolveExportTarget2(symbol, typeChecker);
5615
- if (!declaration) {
5616
- let externalPackage;
5617
- const allDecls = [
5618
- ...targetSymbol.declarations ?? [],
5619
- ...symbol.declarations ?? []
5620
- ];
5621
- for (const decl of allDecls) {
5622
- const sf = decl.getSourceFile();
5623
- if (sf?.fileName.includes("node_modules")) {
5624
- const match = sf.fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
5625
- if (match) {
5626
- externalPackage = match[1];
5627
- break;
5628
- }
5629
- }
5630
- if (ts15.isExportSpecifier(decl)) {
5631
- const exportDecl = decl.parent?.parent;
5632
- if (exportDecl && ts15.isExportDeclaration(exportDecl) && exportDecl.moduleSpecifier) {
5633
- const moduleText = exportDecl.moduleSpecifier.getText().slice(1, -1);
5634
- if (!moduleText.startsWith(".") && !moduleText.startsWith("/")) {
5635
- externalPackage = moduleText;
5636
- break;
5637
- }
5638
- }
5639
- }
5640
- }
5641
- if (externalPackage) {
5642
- const shouldResolve = matchesExternalPattern(externalPackage, options.externals?.include, options.externals?.exclude);
5643
- if (shouldResolve) {
5644
- const resolvedModule = resolveExternalModule(externalPackage, sourceFile.fileName, program.getCompilerOptions());
5645
- if (resolvedModule) {
5646
- const visitedExternals = new Set;
5647
- const extractedExport = extractExternalExport(exportName, resolvedModule, program, ctx, visitedExternals);
5648
- if (extractedExport) {
5649
- exports.push(extractedExport);
5650
- tracker.status = "success";
5651
- tracker.kind = extractedExport.kind;
5652
- continue;
5653
- }
5654
- }
5655
- }
5656
- const externalExport = {
5657
- id: exportName,
5658
- name: exportName,
5659
- kind: "external",
5660
- source: {
5661
- package: externalPackage
5662
- }
5663
- };
5664
- exports.push(externalExport);
5665
- tracker.status = "success";
5666
- tracker.kind = "external";
5667
- } else {
5668
- tracker.status = "skipped";
5669
- tracker.skipReason = "no-declaration";
5670
- }
5671
- continue;
5672
- }
5673
- const exp = serializeDeclaration2(declaration, symbol, targetSymbol, exportName, ctx, isTypeOnly);
5674
- if (exp) {
5675
- exports.push(exp);
5676
- tracker.status = "success";
5677
- tracker.kind = exp.kind;
5678
- } else {
5679
- tracker.status = "skipped";
5680
- tracker.skipReason = "internal";
5681
- }
5682
- } catch (err) {
5683
- const errorMsg = err instanceof Error ? err.message : String(err);
5684
- tracker.status = "failed";
5685
- tracker.error = errorMsg;
5686
- diagnostics.push({
5687
- message: `Failed to serialize '${exportName}': ${errorMsg}`,
5688
- severity: "warning",
5689
- code: "SERIALIZATION_FAILED"
5690
- });
5691
- }
5692
- }
5693
- const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
5694
- const meta = await getPackageMeta(entryFile, baseDir);
5695
- const types = ctx.typeRegistry.getAll();
5696
- const projectBaseDir = baseDir ?? path7.dirname(entryFile);
5697
- const definedTypes = new Set(types.map((t) => t.id));
5698
- const forgottenExports = collectForgottenExports(exports, types, program, sourceFile, exportedIds, projectBaseDir, definedTypes);
5699
- for (const forgotten of forgottenExports) {
5700
- const refSummary = forgotten.referencedBy.slice(0, 3).map((r) => `${r.exportName} (${r.location})`).join(", ");
5701
- const moreRefs = forgotten.referencedBy.length > 3 ? ` +${forgotten.referencedBy.length - 3} more` : "";
5702
- if (forgotten.isExternal) {
5703
- diagnostics.push({
5704
- message: `External type '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
5705
- severity: "info",
5706
- code: "EXTERNAL_TYPE_REF",
5707
- suggestion: forgotten.definedIn ? `Type is from: ${forgotten.definedIn}` : "Type is from an external package"
5708
- });
5709
- } else {
5710
- diagnostics.push({
5711
- message: `Forgotten export: '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
5712
- severity: "warning",
5713
- code: "FORGOTTEN_EXPORT",
5714
- suggestion: forgotten.fix ?? `Export this type from your public API`,
5715
- location: forgotten.definedIn ? { file: forgotten.definedIn } : undefined
5716
- });
5717
- }
5718
- }
5719
- const externalTypes = types.filter((t) => t.kind === "external");
5720
- if (externalTypes.length > 0) {
5721
- diagnostics.push({
5722
- message: `${externalTypes.length} external type(s) from dependencies: ${externalTypes.slice(0, 5).map((t) => t.id).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
5723
- severity: "info",
5724
- code: "EXTERNAL_TYPES"
5725
- });
5726
- }
5727
- let runtimeMetadata;
5728
- if (options.schemaExtraction === "hybrid") {
5729
- const projectBaseDir2 = baseDir || path7.dirname(entryFile);
5730
- const runtimeResult = await extractStandardSchemasFromProject(entryFile, projectBaseDir2, {
5731
- target: options.schemaTarget || "draft-2020-12",
5732
- timeout: 15000
5733
- });
5734
- if (runtimeResult.schemas.size > 0) {
5735
- const mergeResult = mergeRuntimeSchemas(exports, runtimeResult.schemas);
5736
- exports = mergeResult.exports;
5737
- const method = runtimeResult.info?.method === "direct-ts" ? `direct-ts (${runtimeResult.info.runtime})` : "compiled";
5738
- runtimeMetadata = {
5739
- extracted: runtimeResult.schemas.size,
5740
- merged: mergeResult.merged,
5741
- vendors: [...new Set([...runtimeResult.schemas.values()].map((s) => s.vendor))],
5742
- errors: runtimeResult.errors,
5743
- method
5744
- };
5745
- }
5746
- for (const error of runtimeResult.errors) {
5747
- diagnostics.push({
5748
- message: `Runtime schema extraction: ${error}`,
5749
- severity: "warning",
5750
- code: "RUNTIME_SCHEMA_ERROR"
5751
- });
5752
- }
5753
- }
5754
- const normalizedExports = exports.map((exp) => normalizeExport(exp, { dialect: "draft-2020-12" }));
5755
- const normalizedTypes = types.map((t) => normalizeType(t, { dialect: "draft-2020-12" }));
5756
- const spec = {
5757
- ...includeSchema ? { $schema: SCHEMA_URL } : {},
5758
- openpkg: SCHEMA_VERSION,
5759
- meta,
5760
- exports: normalizedExports,
5761
- types: normalizedTypes,
5762
- generation: {
5763
- generator: "@openpkg-ts/sdk",
5764
- timestamp: new Date().toISOString(),
5765
- mode: isDtsSource ? "declaration-only" : "source",
5766
- ...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {},
5767
- ...isDtsSource && {
5768
- limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
5769
- },
5770
- ...verification.details.skipped.length > 0 && {
5771
- skipped: verification.details.skipped
5772
- }
5773
- }
5774
- };
5775
- const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
5776
- const degradedMode = isDtsSource ? { reason: "dts-source", stats: computeDegradedStats(normalizedExports) } : undefined;
5777
- if (verification.failed > 0) {
5778
- const failedNames = verification.details.failed.map((f) => f.name).join(", ");
5779
- diagnostics.push({
5780
- message: `Export verification: ${verification.failed} export(s) failed: ${failedNames}`,
5781
- severity: "warning",
5782
- code: "EXPORT_VERIFICATION_FAILED",
5783
- suggestion: "Check serialization errors for these exports"
5784
- });
5785
- }
5786
- return {
5787
- spec,
5788
- diagnostics,
5789
- verification,
5790
- ...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {},
5791
- ...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {},
5792
- ...degradedMode ? { degradedMode } : {}
5793
- };
5794
- }
5795
5763
  function collectAllRefsWithContext(obj, refs, state) {
5796
5764
  if (obj === null || obj === undefined)
5797
5765
  return;
@@ -5835,68 +5803,6 @@ function collectAllRefsWithContext(obj, refs, state) {
5835
5803
  }
5836
5804
  }
5837
5805
  }
5838
- function findTypeDefinition(typeName, program, sourceFile) {
5839
- const cache = getTypeDefinitionCache();
5840
- if (cache.has(typeName)) {
5841
- return cache.get(typeName);
5842
- }
5843
- const checker = program.getTypeChecker();
5844
- const findInNode = (node) => {
5845
- if ((ts15.isInterfaceDeclaration(node) || ts15.isTypeAliasDeclaration(node) || ts15.isClassDeclaration(node) || ts15.isEnumDeclaration(node)) && node.name?.text === typeName) {
5846
- const sf = node.getSourceFile();
5847
- return sf.fileName;
5848
- }
5849
- return ts15.forEachChild(node, findInNode);
5850
- };
5851
- const entryResult = findInNode(sourceFile);
5852
- if (entryResult) {
5853
- cache.set(typeName, entryResult);
5854
- return entryResult;
5855
- }
5856
- for (const sf of program.getSourceFiles()) {
5857
- if (sf.isDeclarationFile && !sf.fileName.includes("node_modules")) {
5858
- const result = findInNode(sf);
5859
- if (result) {
5860
- cache.set(typeName, result);
5861
- return result;
5862
- }
5863
- }
5864
- }
5865
- const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
5866
- if (symbol?.declarations?.[0]) {
5867
- const result = symbol.declarations[0].getSourceFile().fileName;
5868
- cache.set(typeName, result);
5869
- return result;
5870
- }
5871
- cache.set(typeName, undefined);
5872
- return;
5873
- }
5874
- function isExternalType2(definedIn, baseDir) {
5875
- if (!definedIn)
5876
- return true;
5877
- if (definedIn.includes("node_modules"))
5878
- return true;
5879
- const normalizedDefined = path7.resolve(definedIn);
5880
- const normalizedBase = path7.resolve(baseDir);
5881
- return !normalizedDefined.startsWith(normalizedBase);
5882
- }
5883
- function hasInternalTag(typeName, program, sourceFile) {
5884
- const cache = getInternalTagCache();
5885
- const cached = cache.get(typeName);
5886
- if (cached !== undefined) {
5887
- return cached;
5888
- }
5889
- const checker = program.getTypeChecker();
5890
- const symbol = checker.resolveName(typeName, sourceFile, ts15.SymbolFlags.Type, false);
5891
- if (!symbol) {
5892
- cache.set(typeName, false);
5893
- return false;
5894
- }
5895
- const jsTags = symbol.getJsDocTags();
5896
- const isInternal = jsTags.some((tag) => tag.name === "internal");
5897
- cache.set(typeName, isInternal);
5898
- return isInternal;
5899
- }
5900
5806
  function collectForgottenExports(exports, types, program, sourceFile, exportedIds, baseDir, definedTypes) {
5901
5807
  const referencedTypes = new Map;
5902
5808
  for (const exp of exports) {
@@ -5937,29 +5843,336 @@ function collectForgottenExports(exports, types, program, sourceFile, exportedId
5937
5843
  }
5938
5844
  return forgottenExports;
5939
5845
  }
5846
+
5847
+ // src/builder/spec-builder.ts
5848
+ var YIELD_BATCH_SIZE = 5;
5849
+ function computeDegradedStats(exports) {
5850
+ let exportsWithoutDescription = 0;
5851
+ let paramsWithoutDocs = 0;
5852
+ let missingExamples = 0;
5853
+ for (const exp of exports) {
5854
+ if (!exp.description)
5855
+ exportsWithoutDescription++;
5856
+ if (!exp.examples || exp.examples.length === 0)
5857
+ missingExamples++;
5858
+ const signatures = exp.signatures;
5859
+ if (signatures) {
5860
+ for (const sig of signatures) {
5861
+ for (const param of sig.parameters ?? []) {
5862
+ if (!param.description)
5863
+ paramsWithoutDocs++;
5864
+ }
5865
+ }
5866
+ }
5867
+ }
5868
+ return { exportsWithoutDescription, paramsWithoutDocs, missingExamples };
5869
+ }
5870
+ function matchesPattern(name, pattern) {
5871
+ if (!pattern.includes("*"))
5872
+ return name === pattern;
5873
+ const regexCache2 = getRegexCache();
5874
+ let regex = regexCache2.get(pattern);
5875
+ if (!regex) {
5876
+ regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
5877
+ regexCache2.set(pattern, regex);
5878
+ }
5879
+ return regex.test(name);
5880
+ }
5881
+ function shouldIncludeExport(name, only, ignore) {
5882
+ if (ignore?.some((p) => matchesPattern(name, p)))
5883
+ return false;
5884
+ if (only && only.length > 0) {
5885
+ return only.some((p) => matchesPattern(name, p));
5886
+ }
5887
+ return true;
5888
+ }
5889
+ async function extract(options) {
5890
+ clearTypeDefinitionCache();
5891
+ try {
5892
+ const {
5893
+ entryFile,
5894
+ baseDir,
5895
+ content,
5896
+ maxTypeDepth,
5897
+ maxExternalTypeDepth,
5898
+ resolveExternalTypes,
5899
+ includeSchema,
5900
+ only,
5901
+ ignore,
5902
+ onProgress,
5903
+ isDtsSource,
5904
+ includePrivate,
5905
+ maxProperties,
5906
+ onTruncation
5907
+ } = options;
5908
+ const diagnostics = [];
5909
+ let exports = [];
5910
+ const result = createProgram({ entryFile, baseDir, content });
5911
+ const { program, sourceFile } = result;
5912
+ if (!sourceFile) {
5913
+ return {
5914
+ spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5915
+ diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
5916
+ };
5917
+ }
5918
+ const typeChecker = program.getTypeChecker();
5919
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
5920
+ if (!moduleSymbol) {
5921
+ return {
5922
+ spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
5923
+ diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
5924
+ };
5925
+ }
5926
+ const exportedSymbols = typeChecker.getExportsOfModule(moduleSymbol);
5927
+ const exportedIds = new Set;
5928
+ for (const symbol of exportedSymbols) {
5929
+ exportedIds.add(symbol.getName());
5930
+ }
5931
+ const exportTracker = new Map;
5932
+ for (const symbol of exportedSymbols) {
5933
+ const name = symbol.getName();
5934
+ const included = shouldIncludeExport(name, only, ignore);
5935
+ exportTracker.set(name, {
5936
+ name,
5937
+ discovered: true,
5938
+ status: included ? "pending" : "skipped",
5939
+ ...included ? {} : { skipReason: "filtered" }
5940
+ });
5941
+ }
5942
+ const ctx = createContext(program, sourceFile, {
5943
+ maxTypeDepth,
5944
+ maxExternalTypeDepth,
5945
+ resolveExternalTypes,
5946
+ includePrivate,
5947
+ maxProperties,
5948
+ onTruncation
5949
+ });
5950
+ ctx.exportedIds = exportedIds;
5951
+ const filteredSymbols = exportedSymbols.filter((s) => shouldIncludeExport(s.getName(), only, ignore));
5952
+ const total = filteredSymbols.length;
5953
+ for (let i = 0;i < filteredSymbols.length; i++) {
5954
+ const symbol = filteredSymbols[i];
5955
+ const exportName = symbol.getName();
5956
+ const tracker = exportTracker.get(exportName);
5957
+ if (!tracker)
5958
+ continue;
5959
+ onProgress?.(i + 1, total, exportName);
5960
+ if (i > 0 && i % YIELD_BATCH_SIZE === 0) {
5961
+ await new Promise((r) => setImmediate(r));
5962
+ }
5963
+ try {
5964
+ const { declaration, targetSymbol, isTypeOnly } = resolveExportTarget2(symbol, typeChecker);
5965
+ if (!declaration) {
5966
+ let externalPackage;
5967
+ const allDecls = [...targetSymbol.declarations ?? [], ...symbol.declarations ?? []];
5968
+ for (const decl of allDecls) {
5969
+ const sf = decl.getSourceFile();
5970
+ if (sf?.fileName.includes("node_modules")) {
5971
+ const match = sf.fileName.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
5972
+ if (match) {
5973
+ externalPackage = match[1];
5974
+ break;
5975
+ }
5976
+ }
5977
+ if (ts16.isExportSpecifier(decl)) {
5978
+ const exportDecl = decl.parent?.parent;
5979
+ if (exportDecl && ts16.isExportDeclaration(exportDecl) && exportDecl.moduleSpecifier) {
5980
+ const moduleText = exportDecl.moduleSpecifier.getText().slice(1, -1);
5981
+ if (!moduleText.startsWith(".") && !moduleText.startsWith("/")) {
5982
+ externalPackage = moduleText;
5983
+ break;
5984
+ }
5985
+ }
5986
+ }
5987
+ }
5988
+ if (externalPackage) {
5989
+ const shouldResolve = matchesExternalPattern(externalPackage, options.externals?.include, options.externals?.exclude);
5990
+ if (shouldResolve) {
5991
+ const resolvedModule = resolveExternalModule(externalPackage, sourceFile.fileName, program.getCompilerOptions());
5992
+ if (resolvedModule) {
5993
+ const visitedExternals = new Set;
5994
+ const extractedExport = extractExternalExport(exportName, resolvedModule, program, ctx, visitedExternals);
5995
+ if (extractedExport) {
5996
+ exports.push(extractedExport);
5997
+ tracker.status = "success";
5998
+ tracker.kind = extractedExport.kind;
5999
+ continue;
6000
+ }
6001
+ }
6002
+ }
6003
+ const externalExport = {
6004
+ id: exportName,
6005
+ name: exportName,
6006
+ kind: "external",
6007
+ source: {
6008
+ package: externalPackage
6009
+ }
6010
+ };
6011
+ exports.push(externalExport);
6012
+ tracker.status = "success";
6013
+ tracker.kind = "external";
6014
+ } else {
6015
+ tracker.status = "skipped";
6016
+ tracker.skipReason = "no-declaration";
6017
+ }
6018
+ continue;
6019
+ }
6020
+ const exp = serializeDeclaration2(declaration, symbol, targetSymbol, exportName, ctx, isTypeOnly);
6021
+ if (exp) {
6022
+ exports.push(exp);
6023
+ tracker.status = "success";
6024
+ tracker.kind = exp.kind;
6025
+ } else {
6026
+ tracker.status = "skipped";
6027
+ tracker.skipReason = "internal";
6028
+ }
6029
+ } catch (err) {
6030
+ const errorMsg = err instanceof Error ? err.message : String(err);
6031
+ tracker.status = "failed";
6032
+ tracker.error = errorMsg;
6033
+ diagnostics.push({
6034
+ message: `Failed to serialize '${exportName}': ${errorMsg}`,
6035
+ severity: "warning",
6036
+ code: "SERIALIZATION_FAILED"
6037
+ });
6038
+ }
6039
+ }
6040
+ const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
6041
+ const meta = await getPackageMeta(entryFile, baseDir);
6042
+ const types = ctx.typeRegistry.getAll();
6043
+ const projectBaseDir = baseDir ?? path8.dirname(entryFile);
6044
+ const definedTypes = new Set(types.map((t) => t.id));
6045
+ const forgottenExports = collectForgottenExports(exports, types, program, sourceFile, exportedIds, projectBaseDir, definedTypes);
6046
+ for (const forgotten of forgottenExports) {
6047
+ const refSummary = forgotten.referencedBy.slice(0, 3).map((r) => `${r.exportName} (${r.location})`).join(", ");
6048
+ const moreRefs = forgotten.referencedBy.length > 3 ? ` +${forgotten.referencedBy.length - 3} more` : "";
6049
+ if (forgotten.isExternal) {
6050
+ diagnostics.push({
6051
+ message: `External type '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
6052
+ severity: "info",
6053
+ code: "EXTERNAL_TYPE_REF",
6054
+ suggestion: forgotten.definedIn ? `Type is from: ${forgotten.definedIn}` : "Type is from an external package"
6055
+ });
6056
+ } else {
6057
+ diagnostics.push({
6058
+ message: `Forgotten export: '${forgotten.name}' referenced by: ${refSummary}${moreRefs}`,
6059
+ severity: "warning",
6060
+ code: "FORGOTTEN_EXPORT",
6061
+ suggestion: forgotten.fix ?? `Export this type from your public API`,
6062
+ location: forgotten.definedIn ? { file: forgotten.definedIn } : undefined
6063
+ });
6064
+ }
6065
+ }
6066
+ const externalTypes = types.filter((t) => t.kind === "external");
6067
+ if (externalTypes.length > 0) {
6068
+ diagnostics.push({
6069
+ message: `${externalTypes.length} external type(s) from dependencies: ${externalTypes.slice(0, 5).map((t) => t.id).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
6070
+ severity: "info",
6071
+ code: "EXTERNAL_TYPES"
6072
+ });
6073
+ }
6074
+ let runtimeMetadata;
6075
+ if (options.schemaExtraction === "hybrid") {
6076
+ const projectBaseDir2 = baseDir || path8.dirname(entryFile);
6077
+ const runtimeResult = await extractStandardSchemasFromProject(entryFile, projectBaseDir2, {
6078
+ target: options.schemaTarget || "draft-2020-12",
6079
+ timeout: 15000
6080
+ });
6081
+ if (runtimeResult.schemas.size > 0) {
6082
+ const mergeResult = mergeRuntimeSchemas(exports, runtimeResult.schemas);
6083
+ exports = mergeResult.exports;
6084
+ const method = runtimeResult.info?.method === "direct-ts" ? `direct-ts (${runtimeResult.info.runtime})` : "compiled";
6085
+ runtimeMetadata = {
6086
+ extracted: runtimeResult.schemas.size,
6087
+ merged: mergeResult.merged,
6088
+ vendors: [...new Set([...runtimeResult.schemas.values()].map((s) => s.vendor))],
6089
+ errors: runtimeResult.errors,
6090
+ warnings: runtimeResult.warnings,
6091
+ method
6092
+ };
6093
+ }
6094
+ for (const error of runtimeResult.errors) {
6095
+ diagnostics.push({
6096
+ message: `Runtime schema extraction: ${error}`,
6097
+ severity: "warning",
6098
+ code: "RUNTIME_SCHEMA_ERROR"
6099
+ });
6100
+ }
6101
+ for (const warning of runtimeResult.warnings) {
6102
+ diagnostics.push({
6103
+ message: `Schema extraction skipped${warning.exportName ? ` (${warning.exportName})` : ""}: ${warning.message}`,
6104
+ severity: "warning",
6105
+ code: warning.code
6106
+ });
6107
+ }
6108
+ }
6109
+ const normalizedExports = exports.map((exp) => normalizeExport(exp, { dialect: "draft-2020-12" }));
6110
+ const normalizedTypes = types.map((t) => normalizeType(t, { dialect: "draft-2020-12" }));
6111
+ const spec = {
6112
+ ...includeSchema ? { $schema: SCHEMA_URL } : {},
6113
+ openpkg: SCHEMA_VERSION,
6114
+ meta,
6115
+ exports: normalizedExports,
6116
+ types: normalizedTypes,
6117
+ generation: {
6118
+ generator: "@openpkg-ts/sdk",
6119
+ timestamp: new Date().toISOString(),
6120
+ mode: isDtsSource ? "declaration-only" : "source",
6121
+ ...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {},
6122
+ ...isDtsSource && {
6123
+ limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
6124
+ },
6125
+ ...verification.details.skipped.length > 0 && {
6126
+ skipped: verification.details.skipped
6127
+ }
6128
+ }
6129
+ };
6130
+ const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
6131
+ const degradedMode = isDtsSource ? { reason: "dts-source", stats: computeDegradedStats(normalizedExports) } : undefined;
6132
+ if (verification.failed > 0) {
6133
+ const failedNames = verification.details.failed.map((f) => f.name).join(", ");
6134
+ diagnostics.push({
6135
+ message: `Export verification: ${verification.failed} export(s) failed: ${failedNames}`,
6136
+ severity: "warning",
6137
+ code: "EXPORT_VERIFICATION_FAILED",
6138
+ suggestion: "Check serialization errors for these exports"
6139
+ });
6140
+ }
6141
+ return {
6142
+ spec,
6143
+ diagnostics,
6144
+ verification,
6145
+ ...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {},
6146
+ ...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {},
6147
+ ...degradedMode ? { degradedMode } : {}
6148
+ };
6149
+ } finally {
6150
+ clearTypeDefinitionCache();
6151
+ }
6152
+ }
5940
6153
  function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportName, ctx, isTypeOnly = false) {
5941
6154
  let result = null;
5942
- if (ts15.isFunctionDeclaration(declaration)) {
6155
+ if (ts16.isFunctionDeclaration(declaration)) {
5943
6156
  result = serializeFunctionExport(declaration, ctx);
5944
- } else if (ts15.isClassDeclaration(declaration)) {
6157
+ } else if (ts16.isClassDeclaration(declaration)) {
5945
6158
  result = serializeClass(declaration, ctx);
5946
- } else if (ts15.isInterfaceDeclaration(declaration)) {
6159
+ } else if (ts16.isInterfaceDeclaration(declaration)) {
5947
6160
  result = serializeInterface(declaration, ctx);
5948
- } else if (ts15.isTypeAliasDeclaration(declaration)) {
6161
+ } else if (ts16.isTypeAliasDeclaration(declaration)) {
5949
6162
  result = serializeTypeAlias(declaration, ctx);
5950
- } else if (ts15.isEnumDeclaration(declaration)) {
6163
+ } else if (ts16.isEnumDeclaration(declaration)) {
5951
6164
  result = serializeEnum(declaration, ctx);
5952
- } else if (ts15.isVariableDeclaration(declaration)) {
6165
+ } else if (ts16.isVariableDeclaration(declaration)) {
5953
6166
  const varStatement = declaration.parent?.parent;
5954
- if (varStatement && ts15.isVariableStatement(varStatement)) {
5955
- if (declaration.initializer && ts15.isArrowFunction(declaration.initializer)) {
5956
- const varName = ts15.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
6167
+ if (varStatement && ts16.isVariableStatement(varStatement)) {
6168
+ if (declaration.initializer && ts16.isArrowFunction(declaration.initializer)) {
6169
+ const varName = ts16.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
5957
6170
  result = serializeFunctionExport(declaration.initializer, ctx, varName);
5958
6171
  } else {
5959
6172
  result = serializeVariable(declaration, varStatement, ctx);
5960
6173
  }
5961
6174
  }
5962
- } else if (ts15.isNamespaceExport(declaration) || ts15.isModuleDeclaration(declaration)) {
6175
+ } else if (ts16.isNamespaceExport(declaration) || ts16.isModuleDeclaration(declaration)) {
5963
6176
  try {
5964
6177
  result = serializeNamespaceExport(exportSymbol, exportName, ctx);
5965
6178
  } catch {
@@ -5972,7 +6185,7 @@ function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportN
5972
6185
  examples: []
5973
6186
  };
5974
6187
  }
5975
- } else if (ts15.isNamespaceImport(declaration)) {
6188
+ } else if (ts16.isNamespaceImport(declaration)) {
5976
6189
  try {
5977
6190
  result = serializeNamespaceExport(exportSymbol, exportName, ctx);
5978
6191
  } catch {
@@ -5985,7 +6198,7 @@ function serializeDeclaration2(declaration, exportSymbol, _targetSymbol, exportN
5985
6198
  examples: []
5986
6199
  };
5987
6200
  }
5988
- } else if (ts15.isSourceFile(declaration)) {
6201
+ } else if (ts16.isSourceFile(declaration)) {
5989
6202
  try {
5990
6203
  result = serializeNamespaceExport(exportSymbol, exportName, ctx);
5991
6204
  } catch {
@@ -6015,7 +6228,7 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
6015
6228
  const members = [];
6016
6229
  const checker = ctx.program.getTypeChecker();
6017
6230
  let targetSymbol = symbol;
6018
- if (symbol.flags & ts15.SymbolFlags.Alias) {
6231
+ if (symbol.flags & ts16.SymbolFlags.Alias) {
6019
6232
  const aliased = checker.getAliasedSymbol(symbol);
6020
6233
  if (aliased && aliased !== symbol) {
6021
6234
  targetSymbol = aliased;
@@ -6042,31 +6255,31 @@ function serializeNamespaceExport(symbol, exportName, ctx) {
6042
6255
  function serializeNamespaceMember(symbol, memberName, ctx) {
6043
6256
  const checker = ctx.program.getTypeChecker();
6044
6257
  let targetSymbol = symbol;
6045
- if (symbol.flags & ts15.SymbolFlags.Alias) {
6258
+ if (symbol.flags & ts16.SymbolFlags.Alias) {
6046
6259
  const aliased = checker.getAliasedSymbol(symbol);
6047
6260
  if (aliased && aliased !== symbol) {
6048
6261
  targetSymbol = aliased;
6049
6262
  }
6050
6263
  }
6051
6264
  const declarations = targetSymbol.declarations ?? [];
6052
- const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts15.SyntaxKind.ExportSpecifier) || declarations[0];
6265
+ const declaration = targetSymbol.valueDeclaration || declarations.find((d) => d.kind !== ts16.SyntaxKind.ExportSpecifier) || declarations[0];
6053
6266
  if (!declaration)
6054
6267
  return null;
6055
6268
  const type = checker.getTypeAtLocation(declaration);
6056
6269
  const callSignatures = type.getCallSignatures();
6057
6270
  const deprecated = isSymbolDeprecated(targetSymbol);
6058
6271
  let kind = "variable";
6059
- if (ts15.isFunctionDeclaration(declaration) || ts15.isFunctionExpression(declaration)) {
6272
+ if (ts16.isFunctionDeclaration(declaration) || ts16.isFunctionExpression(declaration)) {
6060
6273
  kind = "function";
6061
- } else if (ts15.isClassDeclaration(declaration)) {
6274
+ } else if (ts16.isClassDeclaration(declaration)) {
6062
6275
  kind = "class";
6063
- } else if (ts15.isInterfaceDeclaration(declaration)) {
6276
+ } else if (ts16.isInterfaceDeclaration(declaration)) {
6064
6277
  kind = "interface";
6065
- } else if (ts15.isTypeAliasDeclaration(declaration)) {
6278
+ } else if (ts16.isTypeAliasDeclaration(declaration)) {
6066
6279
  kind = "type";
6067
- } else if (ts15.isEnumDeclaration(declaration)) {
6280
+ } else if (ts16.isEnumDeclaration(declaration)) {
6068
6281
  kind = "enum";
6069
- } else if (ts15.isVariableDeclaration(declaration)) {
6282
+ } else if (ts16.isVariableDeclaration(declaration)) {
6070
6283
  if (callSignatures.length > 0) {
6071
6284
  kind = "function";
6072
6285
  }
@@ -6113,11 +6326,11 @@ function getJSDocFromExportSymbol(symbol) {
6113
6326
  const examples = [];
6114
6327
  const decl = symbol.declarations?.[0];
6115
6328
  if (decl) {
6116
- const exportDecl = ts15.isNamespaceExport(decl) ? decl.parent : decl;
6117
- if (exportDecl && ts15.isExportDeclaration(exportDecl)) {
6118
- const jsDocs = ts15.getJSDocCommentsAndTags(exportDecl);
6329
+ const exportDecl = ts16.isNamespaceExport(decl) ? decl.parent : decl;
6330
+ if (exportDecl && ts16.isExportDeclaration(exportDecl)) {
6331
+ const jsDocs = ts16.getJSDocCommentsAndTags(exportDecl);
6119
6332
  for (const doc of jsDocs) {
6120
- if (ts15.isJSDoc(doc) && doc.comment) {
6333
+ if (ts16.isJSDoc(doc) && doc.comment) {
6121
6334
  const commentText = typeof doc.comment === "string" ? doc.comment : doc.comment.map((c) => ("text" in c) ? c.text : "").join("");
6122
6335
  if (commentText) {
6123
6336
  return {
@@ -6179,7 +6392,7 @@ function createEmptySpec(entryFile, includeSchema, isDtsSource) {
6179
6392
  return {
6180
6393
  ...includeSchema ? { $schema: SCHEMA_URL } : {},
6181
6394
  openpkg: SCHEMA_VERSION,
6182
- meta: { name: path7.basename(entryFile, path7.extname(entryFile)) },
6395
+ meta: { name: path8.basename(entryFile, path8.extname(entryFile)) },
6183
6396
  exports: [],
6184
6397
  generation: {
6185
6398
  generator: "@openpkg-ts/sdk",
@@ -6192,19 +6405,19 @@ function createEmptySpec(entryFile, includeSchema, isDtsSource) {
6192
6405
  };
6193
6406
  }
6194
6407
  async function getPackageMeta(entryFile, baseDir) {
6195
- const searchDir = baseDir ?? path7.dirname(entryFile);
6196
- const pkgPath = path7.join(searchDir, "package.json");
6408
+ const searchDir = baseDir ?? path8.dirname(entryFile);
6409
+ const pkgPath = path8.join(searchDir, "package.json");
6197
6410
  try {
6198
6411
  if (fs7.existsSync(pkgPath)) {
6199
6412
  const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
6200
6413
  return {
6201
- name: pkg.name ?? path7.basename(searchDir),
6414
+ name: pkg.name ?? path8.basename(searchDir),
6202
6415
  version: pkg.version,
6203
6416
  description: pkg.description
6204
6417
  };
6205
6418
  }
6206
6419
  } catch {}
6207
- return { name: path7.basename(searchDir) };
6420
+ return { name: path8.basename(searchDir) };
6208
6421
  }
6209
6422
 
6210
6423
  // src/primitives/spec.ts
@@ -6326,6 +6539,7 @@ export {
6326
6539
  analyzeSpec,
6327
6540
  TypeRegistry,
6328
6541
  QueryBuilder,
6542
+ CacheManager,
6329
6543
  CONFIG_FILENAME,
6330
6544
  BUILTIN_TYPE_SCHEMAS,
6331
6545
  ARRAY_PROTOTYPE_METHODS