@openpkg-ts/extract 0.25.0 → 0.27.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/bin/tspec.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  detectTsRuntime,
4
4
  extract,
5
5
  resolveCompiledPath
6
- } from "../shared/chunk-2zvzqxtn.js";
6
+ } from "../shared/chunk-v9c97d62.js";
7
7
 
8
8
  // src/cli/spec.ts
9
9
  import * as fs from "node:fs";
@@ -412,7 +412,7 @@ function summary(options) {
412
412
  }
413
413
  // src/cli/spec.ts
414
414
  function createProgram() {
415
- const program = new Command("tspec").description("Extract TypeScript package API to OpenPkg spec").argument("[entry]", "Entry point file").option("-o, --output <file>", "Output file", "openpkg.json").option("--max-depth <n>", "Max type depth (default: 4)").option("--skip-resolve", "Skip external type resolution").option("--runtime", "Enable Standard Schema runtime extraction").option("--only <exports>", "Only extract these exports (comma-separated, supports * wildcards)").option("--ignore <exports>", "Ignore these exports (comma-separated, supports * wildcards)").option("-v, --verbose", "Show detailed output").action(async (entry, options) => {
415
+ const program = new Command("tspec").description("Extract TypeScript package API to OpenPkg spec").argument("[entry]", "Entry point file").option("-o, --output <file>", "Output file", "openpkg.json").option("--max-depth <n>", "Max type depth (default: 4)").option("--skip-resolve", "Skip external type resolution").option("--runtime", "Enable Standard Schema runtime extraction").option("--only <exports>", "Only extract these exports (comma-separated, supports * wildcards)").option("--ignore <exports>", "Ignore these exports (comma-separated, supports * wildcards)").option("-v, --verbose", "Show detailed output").option("--verify", "Enable export count verification mode (exit 1 on failures)").action(async (entry, options) => {
416
416
  let entryFile;
417
417
  let fromDts = false;
418
418
  if (entry) {
@@ -428,8 +428,9 @@ function createProgram() {
428
428
  fromDts = found.fromDts;
429
429
  }
430
430
  if (fromDts) {
431
- console.warn(" Using .d.ts file. TSDoc comments may be missing.");
432
- console.warn(` Consider: tspec src/index.ts
431
+ console.log("Mode: Declaration-only (.d.ts)");
432
+ console.log(" Types and signatures will be extracted");
433
+ console.log(` JSDoc comments unavailable (stripped during compilation)
433
434
  `);
434
435
  }
435
436
  if (options.runtime) {
@@ -459,7 +460,8 @@ function createProgram() {
459
460
  resolveExternalTypes: !options.skipResolve,
460
461
  schemaExtraction: options.runtime ? "hybrid" : "static",
461
462
  ...options.only ? { only: options.only.split(",").map((s) => s.trim()) } : {},
462
- ...options.ignore ? { ignore: options.ignore.split(",").map((s) => s.trim()) } : {}
463
+ ...options.ignore ? { ignore: options.ignore.split(",").map((s) => s.trim()) } : {},
464
+ isDtsSource: fromDts
463
465
  });
464
466
  const normalized = normalize(result.spec);
465
467
  const validation = validateSpec(normalized);
@@ -473,6 +475,15 @@ function createProgram() {
473
475
  }
474
476
  fs.writeFileSync(options.output, JSON.stringify(normalized, null, 2));
475
477
  spin.success(`Extracted to ${options.output}`);
478
+ if (result.degradedMode) {
479
+ const { stats } = result.degradedMode;
480
+ const total = normalized.exports.length;
481
+ console.log(`
482
+ Extraction completed in declaration-only mode:`);
483
+ console.log(` ${stats.exportsWithoutDescription}/${total} exports missing descriptions`);
484
+ console.log(` ${stats.paramsWithoutDocs} parameters without documentation`);
485
+ console.log(` ${stats.missingExamples} exports without examples`);
486
+ }
476
487
  if (result.runtimeSchemas) {
477
488
  const { extracted, merged, vendors, method } = result.runtimeSchemas;
478
489
  const via = method ? ` via ${method}` : "";
@@ -488,7 +499,34 @@ function createProgram() {
488
499
  if (result.runtimeSchemas) {
489
500
  sum.addKeyValue("Runtime Schemas", result.runtimeSchemas.merged);
490
501
  }
502
+ if (result.verification) {
503
+ const v = result.verification;
504
+ sum.addKeyValue("Discovered", v.discovered);
505
+ sum.addKeyValue("Extracted", v.extracted);
506
+ if (v.failed > 0) {
507
+ sum.addWithThreshold("Failed", v.failed, { value: 0, operator: "<=" });
508
+ }
509
+ }
491
510
  sum.print();
511
+ if (result.verification?.failed) {
512
+ console.log(`
513
+ Failed exports:`);
514
+ for (const f of result.verification.details.failed) {
515
+ console.log(` - ${f.name}: ${f.error}`);
516
+ }
517
+ }
518
+ if (options.verbose && result.verification?.details.skipped.length) {
519
+ console.log(`
520
+ Skipped exports:`);
521
+ for (const s of result.verification.details.skipped) {
522
+ console.log(` - ${s.name}: ${s.reason}`);
523
+ }
524
+ }
525
+ if (options.verify && result.verification?.failed) {
526
+ const v = result.verification;
527
+ spin.fail(`Expected ${v.discovered} exports, got ${v.extracted}`);
528
+ process.exit(1);
529
+ }
492
530
  });
493
531
  return program;
494
532
  }
@@ -831,7 +831,7 @@ function extractSeeTagText(tag) {
831
831
  }
832
832
  return typeof tag.comment === "string" ? tag.comment : ts3.getTextOfJSDocComment(tag.comment) ?? "";
833
833
  }
834
- function getJSDocComment(node) {
834
+ function getJSDocComment(node, symbol, checker) {
835
835
  const jsDocTags = ts3.getJSDocTags(node);
836
836
  const tags = jsDocTags.map((tag) => {
837
837
  const rawText = typeof tag.comment === "string" ? tag.comment : ts3.getTextOfJSDocComment(tag.comment) ?? "";
@@ -869,6 +869,13 @@ function getJSDocComment(node) {
869
869
  description = typeof firstDoc.comment === "string" ? firstDoc.comment : ts3.getTextOfJSDocComment(firstDoc.comment);
870
870
  }
871
871
  }
872
+ if (!description && symbol && checker) {
873
+ const docComment = symbol.getDocumentationComment(checker);
874
+ if (docComment.length > 0) {
875
+ description = docComment.map((c) => c.text).join(`
876
+ `);
877
+ }
878
+ }
872
879
  const examples = parseExamplesFromTags(tags);
873
880
  return { description, tags, examples };
874
881
  }
@@ -954,12 +961,13 @@ function isSymbolDeprecated(symbol) {
954
961
  }
955
962
  return false;
956
963
  }
957
- function getJSDocForSignature(signature) {
964
+ function getJSDocForSignature(signature, checker) {
958
965
  const decl = signature.getDeclaration();
959
966
  if (!decl) {
960
967
  return { tags: [], examples: [] };
961
968
  }
962
- return getJSDocComment(decl);
969
+ const symbol = checker?.getSymbolAtLocation(decl);
970
+ return getJSDocComment(decl, symbol, checker);
963
971
  }
964
972
  function extractTypeParametersFromSignature(signature, checker) {
965
973
  const typeParams = signature.getTypeParameters();
@@ -1819,7 +1827,7 @@ function serializeInheritedMember(symbol, inheritedFrom, ctx, isStatic) {
1819
1827
  const params = extractParameters(sig, ctx);
1820
1828
  const returnType = checker.getReturnTypeOfSignature(sig);
1821
1829
  registerReferencedTypes(returnType, ctx);
1822
- const sigDoc = getJSDocForSignature(sig);
1830
+ const sigDoc = getJSDocForSignature(sig, checker);
1823
1831
  return {
1824
1832
  parameters: params.length > 0 ? params : undefined,
1825
1833
  returns: {
@@ -1853,7 +1861,7 @@ function serializeClass(node, ctx) {
1853
1861
  return null;
1854
1862
  const deprecated = isSymbolDeprecated(symbol);
1855
1863
  const declSourceFile = node.getSourceFile();
1856
- const { description, tags, examples } = getJSDocComment(node);
1864
+ const { description, tags, examples } = getJSDocComment(node, symbol, checker);
1857
1865
  const source = getSourceLocation(node, declSourceFile);
1858
1866
  const typeParameters = extractTypeParameters(node, checker);
1859
1867
  const members = [];
@@ -1995,7 +2003,7 @@ function serializeMethod(node, ctx) {
1995
2003
  const params = extractParameters(sig, ctx);
1996
2004
  const returnType = checker.getReturnTypeOfSignature(sig);
1997
2005
  registerReferencedTypes(returnType, ctx);
1998
- const sigDoc = getJSDocForSignature(sig);
2006
+ const sigDoc = getJSDocForSignature(sig, checker);
1999
2007
  const sigTypeParams = extractTypeParametersFromSignature(sig, checker);
2000
2008
  return {
2001
2009
  parameters: params.length > 0 ? params : undefined,
@@ -2103,7 +2111,7 @@ function serializeEnum(node, ctx) {
2103
2111
  return null;
2104
2112
  const deprecated = isSymbolDeprecated(symbol);
2105
2113
  const declSourceFile = node.getSourceFile();
2106
- const { description, tags, examples } = getJSDocComment(node);
2114
+ const { description, tags, examples } = getJSDocComment(node, symbol, checker);
2107
2115
  const source = getSourceLocation(node, declSourceFile);
2108
2116
  const members = node.members.map((member) => {
2109
2117
  const memberSymbol = checker.getSymbolAtLocation(member.name);
@@ -2176,14 +2184,14 @@ function serializeFunctionExport(node, ctx) {
2176
2184
  return null;
2177
2185
  const deprecated = isSymbolDeprecated(symbol);
2178
2186
  const declSourceFile = node.getSourceFile();
2179
- const { description, tags, examples } = getJSDocComment(node);
2187
+ const { description, tags, examples } = getJSDocComment(node, symbol, ctx.typeChecker);
2180
2188
  const source = getSourceLocation(node, declSourceFile);
2181
2189
  const typeParameters = extractTypeParameters(node, ctx.typeChecker);
2182
2190
  const type = ctx.typeChecker.getTypeAtLocation(node);
2183
2191
  const callSignatures = type.getCallSignatures();
2184
2192
  const signatures = callSignatures.map((sig, index) => {
2185
2193
  const params = extractParameters(sig, ctx);
2186
- const sigDoc = getJSDocForSignature(sig);
2194
+ const sigDoc = getJSDocForSignature(sig, ctx.typeChecker);
2187
2195
  const sigTypeParams = extractTypeParametersFromSignature(sig, ctx.typeChecker);
2188
2196
  return {
2189
2197
  parameters: params,
@@ -2219,7 +2227,7 @@ function serializeInterface(node, ctx) {
2219
2227
  return null;
2220
2228
  const deprecated = isSymbolDeprecated(symbol);
2221
2229
  const declSourceFile = node.getSourceFile();
2222
- const { description, tags, examples } = getJSDocComment(node);
2230
+ const { description, tags, examples } = getJSDocComment(node, symbol, checker);
2223
2231
  const source = getSourceLocation(node, declSourceFile);
2224
2232
  const typeParameters = extractTypeParameters(node, checker);
2225
2233
  const members = [];
@@ -2294,7 +2302,7 @@ function serializeMethodSignature(node, ctx) {
2294
2302
  const params = extractParameters(sig, ctx);
2295
2303
  const returnType = checker.getReturnTypeOfSignature(sig);
2296
2304
  registerReferencedTypes(returnType, ctx);
2297
- const sigDoc = getJSDocForSignature(sig);
2305
+ const sigDoc = getJSDocForSignature(sig, checker);
2298
2306
  const sigTypeParams = extractTypeParametersFromSignature(sig, checker);
2299
2307
  return {
2300
2308
  parameters: params.length > 0 ? params : undefined,
@@ -2404,7 +2412,7 @@ function serializeTypeAlias(node, ctx) {
2404
2412
  return null;
2405
2413
  const deprecated = isSymbolDeprecated(symbol);
2406
2414
  const declSourceFile = node.getSourceFile();
2407
- const { description, tags, examples } = getJSDocComment(node);
2415
+ const { description, tags, examples } = getJSDocComment(node, symbol, ctx.typeChecker);
2408
2416
  const source = getSourceLocation(node, declSourceFile);
2409
2417
  const typeParameters = extractTypeParameters(node, ctx.typeChecker);
2410
2418
  const type = ctx.typeChecker.getTypeAtLocation(node);
@@ -2600,7 +2608,7 @@ function serializeVariable(node, statement, ctx) {
2600
2608
  return null;
2601
2609
  const deprecated = isSymbolDeprecated(symbol);
2602
2610
  const declSourceFile = node.getSourceFile();
2603
- const { description, tags, examples } = getJSDocComment(statement);
2611
+ const { description, tags, examples } = getJSDocComment(statement, symbol, ctx.typeChecker);
2604
2612
  const source = getSourceLocation(node, declSourceFile);
2605
2613
  const type = ctx.typeChecker.getTypeAtLocation(node);
2606
2614
  const schemaExtraction = extractSchemaType(type, ctx.typeChecker);
@@ -3113,6 +3121,52 @@ function clearTypeDefinitionCache() {
3113
3121
  internalTagCache = null;
3114
3122
  }
3115
3123
  var YIELD_BATCH_SIZE = 5;
3124
+ function computeDegradedStats(exports) {
3125
+ let exportsWithoutDescription = 0;
3126
+ let paramsWithoutDocs = 0;
3127
+ let missingExamples = 0;
3128
+ for (const exp of exports) {
3129
+ if (!exp.description)
3130
+ exportsWithoutDescription++;
3131
+ if (!exp.examples || exp.examples.length === 0)
3132
+ missingExamples++;
3133
+ const signatures = exp.signatures;
3134
+ if (signatures) {
3135
+ for (const sig of signatures) {
3136
+ for (const param of sig.parameters ?? []) {
3137
+ if (!param.description)
3138
+ paramsWithoutDocs++;
3139
+ }
3140
+ }
3141
+ }
3142
+ }
3143
+ return { exportsWithoutDescription, paramsWithoutDocs, missingExamples };
3144
+ }
3145
+ function buildVerificationSummary(discoveredCount, extractedCount, tracker) {
3146
+ const skippedDetails = [];
3147
+ const failedDetails = [];
3148
+ for (const entry of tracker.values()) {
3149
+ if (entry.status === "skipped" && entry.skipReason) {
3150
+ skippedDetails.push({ name: entry.name, reason: entry.skipReason });
3151
+ } else if (entry.status === "failed" && entry.error) {
3152
+ failedDetails.push({ name: entry.name, error: entry.error });
3153
+ }
3154
+ }
3155
+ const skipped = skippedDetails.length;
3156
+ const failed = failedDetails.length;
3157
+ const delta = discoveredCount - extractedCount - skipped;
3158
+ return {
3159
+ discovered: discoveredCount,
3160
+ extracted: extractedCount,
3161
+ skipped,
3162
+ failed,
3163
+ delta,
3164
+ details: {
3165
+ skipped: skippedDetails,
3166
+ failed: failedDetails
3167
+ }
3168
+ };
3169
+ }
3116
3170
  var BUILTIN_TYPES2 = new Set([
3117
3171
  "Array",
3118
3172
  "ArrayBuffer",
@@ -3208,7 +3262,8 @@ async function extract(options) {
3208
3262
  includeSchema,
3209
3263
  only,
3210
3264
  ignore,
3211
- onProgress
3265
+ onProgress,
3266
+ isDtsSource
3212
3267
  } = options;
3213
3268
  const diagnostics = [];
3214
3269
  let exports = [];
@@ -3216,7 +3271,7 @@ async function extract(options) {
3216
3271
  const { program, sourceFile } = result;
3217
3272
  if (!sourceFile) {
3218
3273
  return {
3219
- spec: createEmptySpec(entryFile, includeSchema),
3274
+ spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
3220
3275
  diagnostics: [{ message: `Could not load source file: ${entryFile}`, severity: "error" }]
3221
3276
  };
3222
3277
  }
@@ -3224,7 +3279,7 @@ async function extract(options) {
3224
3279
  const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
3225
3280
  if (!moduleSymbol) {
3226
3281
  return {
3227
- spec: createEmptySpec(entryFile, includeSchema),
3282
+ spec: createEmptySpec(entryFile, includeSchema, isDtsSource),
3228
3283
  diagnostics: [{ message: "Could not get module symbol", severity: "warning" }]
3229
3284
  };
3230
3285
  }
@@ -3233,6 +3288,17 @@ async function extract(options) {
3233
3288
  for (const symbol of exportedSymbols) {
3234
3289
  exportedIds.add(symbol.getName());
3235
3290
  }
3291
+ const exportTracker = new Map;
3292
+ for (const symbol of exportedSymbols) {
3293
+ const name = symbol.getName();
3294
+ const included = shouldIncludeExport(name, only, ignore);
3295
+ exportTracker.set(name, {
3296
+ name,
3297
+ discovered: true,
3298
+ status: included ? "pending" : "skipped",
3299
+ ...included ? {} : { skipReason: "filtered" }
3300
+ });
3301
+ }
3236
3302
  const ctx = createContext(program, sourceFile, {
3237
3303
  maxTypeDepth,
3238
3304
  maxExternalTypeDepth,
@@ -3244,24 +3310,39 @@ async function extract(options) {
3244
3310
  for (let i = 0;i < filteredSymbols.length; i++) {
3245
3311
  const symbol = filteredSymbols[i];
3246
3312
  const exportName = symbol.getName();
3313
+ const tracker = exportTracker.get(exportName);
3247
3314
  onProgress?.(i + 1, total, exportName);
3248
3315
  if (i > 0 && i % YIELD_BATCH_SIZE === 0) {
3249
3316
  await new Promise((r) => setImmediate(r));
3250
3317
  }
3251
3318
  try {
3252
3319
  const { declaration, targetSymbol } = resolveExportTarget(symbol, typeChecker);
3253
- if (!declaration)
3320
+ if (!declaration) {
3321
+ tracker.status = "skipped";
3322
+ tracker.skipReason = "no-declaration";
3254
3323
  continue;
3324
+ }
3255
3325
  const exp = serializeDeclaration(declaration, symbol, targetSymbol, exportName, ctx);
3256
- if (exp)
3326
+ if (exp) {
3257
3327
  exports.push(exp);
3328
+ tracker.status = "success";
3329
+ tracker.kind = exp.kind;
3330
+ } else {
3331
+ tracker.status = "skipped";
3332
+ tracker.skipReason = "internal";
3333
+ }
3258
3334
  } catch (err) {
3335
+ const errorMsg = err instanceof Error ? err.message : String(err);
3336
+ tracker.status = "failed";
3337
+ tracker.error = errorMsg;
3259
3338
  diagnostics.push({
3260
- message: `Failed to serialize ${exportName}: ${err}`,
3261
- severity: "warning"
3339
+ message: `Failed to serialize '${exportName}': ${errorMsg}`,
3340
+ severity: "warning",
3341
+ code: "SERIALIZATION_FAILED"
3262
3342
  });
3263
3343
  }
3264
3344
  }
3345
+ const verification = buildVerificationSummary(exportedSymbols.length, exports.length, exportTracker);
3265
3346
  const meta = await getPackageMeta(entryFile, baseDir);
3266
3347
  const types = ctx.typeRegistry.getAll();
3267
3348
  const projectBaseDir = baseDir ?? path3.dirname(entryFile);
@@ -3333,15 +3414,31 @@ async function extract(options) {
3333
3414
  generation: {
3334
3415
  generator: "@openpkg-ts/extract",
3335
3416
  timestamp: new Date().toISOString(),
3336
- ...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {}
3417
+ mode: isDtsSource ? "declaration-only" : "source",
3418
+ ...options.schemaExtraction === "hybrid" ? { schemaExtraction: "hybrid" } : {},
3419
+ ...isDtsSource && {
3420
+ limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
3421
+ }
3337
3422
  }
3338
3423
  };
3339
3424
  const internalForgotten = forgottenExports.filter((f) => !f.isExternal);
3425
+ const degradedMode = isDtsSource ? { reason: "dts-source", stats: computeDegradedStats(normalizedExports) } : undefined;
3426
+ if (verification.failed > 0) {
3427
+ const failedNames = verification.details.failed.map((f) => f.name).join(", ");
3428
+ diagnostics.push({
3429
+ message: `Export verification: ${verification.failed} export(s) failed: ${failedNames}`,
3430
+ severity: "warning",
3431
+ code: "EXPORT_VERIFICATION_FAILED",
3432
+ suggestion: "Check serialization errors for these exports"
3433
+ });
3434
+ }
3340
3435
  return {
3341
3436
  spec,
3342
3437
  diagnostics,
3438
+ verification,
3343
3439
  ...internalForgotten.length > 0 ? { forgottenExports: internalForgotten } : {},
3344
- ...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {}
3440
+ ...runtimeMetadata ? { runtimeSchemas: runtimeMetadata } : {},
3441
+ ...degradedMode ? { degradedMode } : {}
3345
3442
  };
3346
3443
  }
3347
3444
  function collectAllRefsWithContext(obj, refs, state) {
@@ -3599,7 +3696,7 @@ function serializeNamespaceMember(symbol, memberName, ctx) {
3599
3696
  const returnType = checker.getReturnTypeOfSignature(sig);
3600
3697
  registerReferencedTypes(returnType, ctx);
3601
3698
  const returnSchema = buildSchema(returnType, ctx.typeChecker, ctx);
3602
- const sigDoc = getJSDocForSignature(sig);
3699
+ const sigDoc = getJSDocForSignature(sig, checker);
3603
3700
  const sigTypeParams = extractTypeParametersFromSignature(sig, ctx.typeChecker);
3604
3701
  return {
3605
3702
  parameters: params,
@@ -3693,7 +3790,7 @@ function withExportName(entry, exportName) {
3693
3790
  name: entry.name
3694
3791
  };
3695
3792
  }
3696
- function createEmptySpec(entryFile, includeSchema) {
3793
+ function createEmptySpec(entryFile, includeSchema, isDtsSource) {
3697
3794
  return {
3698
3795
  ...includeSchema ? { $schema: SCHEMA_URL } : {},
3699
3796
  openpkg: SCHEMA_VERSION,
@@ -3701,7 +3798,11 @@ function createEmptySpec(entryFile, includeSchema) {
3701
3798
  exports: [],
3702
3799
  generation: {
3703
3800
  generator: "@openpkg-ts/extract",
3704
- timestamp: new Date().toISOString()
3801
+ timestamp: new Date().toISOString(),
3802
+ mode: isDtsSource ? "declaration-only" : "source",
3803
+ ...isDtsSource && {
3804
+ limitations: ["No JSDoc descriptions", "No @example tags", "No @param descriptions"]
3805
+ }
3705
3806
  }
3706
3807
  };
3707
3808
  }
@@ -43,7 +43,7 @@ declare class TypeRegistry {
43
43
  }
44
44
  import { SpecExample, SpecSource, SpecTag, SpecTypeParameter } from "@openpkg-ts/spec";
45
45
  import ts3 from "typescript";
46
- declare function getJSDocComment(node: ts3.Node): {
46
+ declare function getJSDocComment(node: ts3.Node, symbol?: ts3.Symbol, checker?: ts3.TypeChecker): {
47
47
  description?: string;
48
48
  tags: SpecTag[];
49
49
  examples: SpecExample[];
@@ -239,6 +239,8 @@ interface ExtractOptions {
239
239
  ignore?: string[];
240
240
  /** Progress callback for tracking extraction progress */
241
241
  onProgress?: (current: number, total: number, item: string) => void;
242
+ /** Whether source is a .d.ts file (degraded mode - TSDoc may be missing) */
243
+ isDtsSource?: boolean;
242
244
  }
243
245
  interface ExtractResult {
244
246
  spec: OpenPkg;
@@ -257,6 +259,17 @@ interface ExtractResult {
257
259
  /** Extraction method used: 'compiled' or 'direct-ts (runtime)' */
258
260
  method?: string;
259
261
  };
262
+ /** Degraded mode info when extracting from .d.ts files */
263
+ degradedMode?: {
264
+ reason: "dts-source";
265
+ stats: {
266
+ exportsWithoutDescription: number;
267
+ paramsWithoutDocs: number;
268
+ missingExamples: number;
269
+ };
270
+ };
271
+ /** Export verification comparing discovered vs extracted */
272
+ verification?: ExportVerification;
260
273
  }
261
274
  interface Diagnostic {
262
275
  message: string;
@@ -284,6 +297,29 @@ interface ForgottenExport {
284
297
  isExternal: boolean;
285
298
  fix?: string;
286
299
  }
300
+ /** Verification result comparing discovered vs extracted exports */
301
+ interface ExportVerification {
302
+ /** Total exports discovered by TypeScript */
303
+ discovered: number;
304
+ /** Exports successfully extracted */
305
+ extracted: number;
306
+ /** Exports skipped (filtered, no-declaration, internal) */
307
+ skipped: number;
308
+ /** Exports that failed during serialization */
309
+ failed: number;
310
+ /** Delta: discovered - extracted */
311
+ delta: number;
312
+ details: {
313
+ skipped: Array<{
314
+ name: string;
315
+ reason: "filtered" | "no-declaration" | "internal";
316
+ }>;
317
+ failed: Array<{
318
+ name: string;
319
+ error: string;
320
+ }>;
321
+ };
322
+ }
287
323
  declare function extract(options: ExtractOptions): Promise<ExtractResult>;
288
324
  import ts4 from "typescript";
289
325
  interface ProgramOptions {
package/dist/src/index.js CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  valibotAdapter,
49
49
  withDescription,
50
50
  zodAdapter
51
- } from "../shared/chunk-2zvzqxtn.js";
51
+ } from "../shared/chunk-v9c97d62.js";
52
52
  // src/types/utils.ts
53
53
  function isExported(node) {
54
54
  const modifiers = node.modifiers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/extract",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "TypeScript export extraction to OpenPkg spec",
5
5
  "keywords": [
6
6
  "openpkg",
@@ -40,7 +40,7 @@
40
40
  "format": "biome format --write src/"
41
41
  },
42
42
  "dependencies": {
43
- "@openpkg-ts/spec": "^0.24.0",
43
+ "@openpkg-ts/spec": "^0.26.0",
44
44
  "chalk": "^5.4.1",
45
45
  "commander": "^12.0.0",
46
46
  "tree-sitter-wasms": "^0.1.13",