@doccov/sdk 0.29.0 → 0.29.4

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.d.ts CHANGED
@@ -664,7 +664,7 @@ declare function hashFiles(filePaths: string[], cwd: string): Record<string, str
664
664
  declare function diffHashes(cached: Record<string, string>, current: Record<string, string>): string[];
665
665
  import { OpenPkg as OpenPkg3 } from "@openpkg-ts/spec";
666
666
  /** Current cache format version - bump when spec extraction logic changes */
667
- declare const CACHE_VERSION = "1.1.0";
667
+ declare const CACHE_VERSION = "1.3.0";
668
668
  /** Default cache file path */
669
669
  declare const SPEC_CACHE_FILE = ".doccov/cache/spec.cache.json";
670
670
  /**
@@ -674,6 +674,35 @@ interface SpecCacheConfig {
674
674
  resolveExternalTypes: boolean;
675
675
  }
676
676
  /**
677
+ * Cached diagnostic from spec analysis.
678
+ */
679
+ interface CachedDiagnostic {
680
+ message: string;
681
+ severity: "error" | "warning" | "info";
682
+ suggestion?: string;
683
+ code?: string;
684
+ location?: {
685
+ file: string;
686
+ line?: number;
687
+ column?: number;
688
+ };
689
+ }
690
+ /**
691
+ * Cached forgotten info.
692
+ */
693
+ interface CachedForgottenExport {
694
+ name: string;
695
+ definedIn?: string;
696
+ referencedBy: Array<{
697
+ typeName: string;
698
+ exportName: string;
699
+ location: "return" | "parameter" | "property" | "extends" | "type-parameter";
700
+ path?: string;
701
+ }>;
702
+ isExternal: boolean;
703
+ fix?: string;
704
+ }
705
+ /**
677
706
  * Cached spec with validation metadata.
678
707
  */
679
708
  interface SpecCache {
@@ -698,6 +727,10 @@ interface SpecCache {
698
727
  config: SpecCacheConfig;
699
728
  /** The cached OpenPkg spec */
700
729
  spec: OpenPkg3;
730
+ /** Cached spec-level diagnostics (info/warning messages from extraction) */
731
+ specDiagnostics?: CachedDiagnostic[];
732
+ /** Cached forgotten exports */
733
+ forgottenExports?: CachedForgottenExport[];
701
734
  }
702
735
  /**
703
736
  * Result of cache validation.
@@ -726,6 +759,10 @@ interface CacheContext {
726
759
  config: SpecCacheConfig;
727
760
  /** Working directory */
728
761
  cwd: string;
762
+ /** Spec-level diagnostics to cache */
763
+ specDiagnostics?: CachedDiagnostic[];
764
+ /** Forgotten exports to cache */
765
+ forgottenExports?: CachedForgottenExport[];
729
766
  }
730
767
  /**
731
768
  * Load cached spec from disk.
@@ -937,7 +974,7 @@ interface DocCovOptions {
937
974
  resolveExternalTypes?: boolean;
938
975
  /** Enable spec caching (default: true) */
939
976
  useCache?: boolean;
940
- /** Working directory for cache operations (default: process.cwd()) */
977
+ /** Working directory for cache operations (default: git repo root or process.cwd()) */
941
978
  cwd?: string;
942
979
  /**
943
980
  * Schema extraction mode for validation libraries (Zod, Valibot, etc.)
@@ -952,6 +989,7 @@ interface Diagnostic {
952
989
  message: string;
953
990
  severity: "error" | "warning" | "info";
954
991
  suggestion?: string;
992
+ code?: string;
955
993
  location?: {
956
994
  file: string;
957
995
  line?: number;
@@ -2580,7 +2618,7 @@ interface SpecSummary {
2580
2618
  * ```
2581
2619
  */
2582
2620
  declare function extractSpecSummary(openpkg: OpenPkg8, doccov: DocCovSpec4): SpecSummary;
2583
- import { OpenPkg as OpenPkg_krlvfzpjos } from "@openpkg-ts/spec";
2621
+ import { OpenPkg as OpenPkg_hlpylamjdn } from "@openpkg-ts/spec";
2584
2622
  /**
2585
2623
  * Build Plan types for AI-powered repository scanning.
2586
2624
  */
@@ -2677,7 +2715,7 @@ interface BuildPlanExecutionResult {
2677
2715
  /** Whether all required steps succeeded */
2678
2716
  success: boolean;
2679
2717
  /** Generated OpenPkg spec (if successful) */
2680
- spec?: OpenPkg_krlvfzpjos;
2718
+ spec?: OpenPkg_hlpylamjdn;
2681
2719
  /** Results for each step */
2682
2720
  stepResults: BuildPlanStepResult[];
2683
2721
  /** Total execution time in milliseconds */
package/dist/index.js CHANGED
@@ -80,61 +80,14 @@ import {
80
80
  getDiffReportPath,
81
81
  getReportPath
82
82
  } from "./shared/chunk-r4wa72ae.js";
83
- // src/openpkg.ts
83
+ // src/analyzer.ts
84
84
  import * as fsSync from "node:fs";
85
- import * as fs4 from "node:fs/promises";
85
+ import * as fs5 from "node:fs/promises";
86
86
  import * as path7 from "node:path";
87
-
88
- // src/analysis/program.ts
89
- import * as path from "node:path";
90
- var DEFAULT_COMPILER_OPTIONS = {
91
- target: ts.ScriptTarget.Latest,
92
- module: ts.ModuleKind.CommonJS,
93
- lib: ["lib.es2021.d.ts"],
94
- declaration: true,
95
- moduleResolution: ts.ModuleResolutionKind.NodeJs
96
- };
97
- function createProgram({
98
- entryFile,
99
- baseDir = path.dirname(entryFile),
100
- content
101
- }) {
102
- const configPath = ts.findConfigFile(baseDir, ts.sys.fileExists, "tsconfig.json");
103
- let compilerOptions = { ...DEFAULT_COMPILER_OPTIONS };
104
- if (configPath) {
105
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
106
- const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath));
107
- compilerOptions = { ...compilerOptions, ...parsedConfig.options };
108
- }
109
- const allowJsVal = compilerOptions.allowJs;
110
- if (typeof allowJsVal === "boolean" && allowJsVal) {
111
- compilerOptions = { ...compilerOptions, allowJs: false, checkJs: false };
112
- }
113
- const compilerHost = ts.createCompilerHost(compilerOptions, true);
114
- let inMemorySource;
115
- if (content !== undefined) {
116
- inMemorySource = ts.createSourceFile(entryFile, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
117
- const originalGetSourceFile = compilerHost.getSourceFile.bind(compilerHost);
118
- compilerHost.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
119
- if (fileName === entryFile) {
120
- return inMemorySource;
121
- }
122
- return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
123
- };
124
- }
125
- const program = ts.createProgram([entryFile], compilerOptions, compilerHost);
126
- const sourceFile = inMemorySource ?? program.getSourceFile(entryFile);
127
- return {
128
- program,
129
- compilerHost,
130
- compilerOptions,
131
- sourceFile,
132
- configPath
133
- };
134
- }
87
+ import { createProgram as createProgram2 } from "@openpkg-ts/extract";
135
88
 
136
89
  // src/analysis/run-analysis.ts
137
- import * as fs from "node:fs";
90
+ import * as fs2 from "node:fs";
138
91
  import * as path3 from "node:path";
139
92
  import { extract } from "@openpkg-ts/extract";
140
93
 
@@ -142,6 +95,18 @@ import { extract } from "@openpkg-ts/extract";
142
95
  import * as path2 from "node:path";
143
96
 
144
97
  // src/options.ts
98
+ import * as fs from "node:fs";
99
+ import * as path from "node:path";
100
+ function findRepoRoot(startDir) {
101
+ let dir = startDir;
102
+ while (dir !== path.dirname(dir)) {
103
+ if (fs.existsSync(path.join(dir, ".git"))) {
104
+ return dir;
105
+ }
106
+ dir = path.dirname(dir);
107
+ }
108
+ return startDir;
109
+ }
145
110
  var DEFAULT_MAX_TYPE_DEPTH = 20;
146
111
  var DEFAULT_OPTIONS = {
147
112
  includePrivate: false,
@@ -155,11 +120,12 @@ function normalizeDocCovOptions(options = {}) {
155
120
  ...options,
156
121
  maxDepth: options.maxDepth ?? DEFAULT_MAX_TYPE_DEPTH,
157
122
  useCache: options.useCache ?? true,
158
- cwd: options.cwd ?? process.cwd()
123
+ cwd: options.cwd ?? findRepoRoot(process.cwd())
159
124
  };
160
125
  }
161
126
 
162
127
  // src/analysis/context.ts
128
+ import { createProgram } from "@openpkg-ts/extract";
163
129
  function createAnalysisContext({
164
130
  entryFile,
165
131
  packageDir,
@@ -192,7 +158,7 @@ function findNearestPackageJson(startDir) {
192
158
  let current = startDir;
193
159
  while (true) {
194
160
  const candidate = path3.join(current, "package.json");
195
- if (fs.existsSync(candidate)) {
161
+ if (fs2.existsSync(candidate)) {
196
162
  return candidate;
197
163
  }
198
164
  const parent = path3.dirname(current);
@@ -224,7 +190,7 @@ function hasNodeModulesDirectoryFallback(startDir) {
224
190
  let current = startDir;
225
191
  while (true) {
226
192
  const candidate = path3.join(current, "node_modules");
227
- if (fs.existsSync(candidate)) {
193
+ if (fs2.existsSync(candidate)) {
228
194
  return true;
229
195
  }
230
196
  const parent = path3.dirname(current);
@@ -285,7 +251,8 @@ async function runAnalysis(input) {
285
251
  specDiagnostics.push({
286
252
  message: diag.message,
287
253
  severity: diag.severity,
288
- suggestion: diag.suggestion
254
+ suggestion: diag.suggestion,
255
+ code: diag.code
289
256
  });
290
257
  }
291
258
  const sourceFiles = program.getSourceFiles().filter((sf) => !sf.isDeclarationFile && sf.fileName.startsWith(baseDir)).map((sf) => sf.fileName);
@@ -307,11 +274,11 @@ async function runAnalysis(input) {
307
274
 
308
275
  // src/cache/hash.ts
309
276
  import * as crypto from "node:crypto";
310
- import * as fs2 from "node:fs";
277
+ import * as fs3 from "node:fs";
311
278
  import * as path4 from "node:path";
312
279
  function hashFile(filePath) {
313
280
  try {
314
- const content = fs2.readFileSync(filePath);
281
+ const content = fs3.readFileSync(filePath);
315
282
  return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
316
283
  } catch {
317
284
  return null;
@@ -346,24 +313,33 @@ function diffHashes(cached, current) {
346
313
  return changed;
347
314
  }
348
315
  // src/cache/spec-cache.ts
349
- import * as fs3 from "node:fs";
316
+ import * as fs4 from "node:fs";
350
317
  import * as path5 from "node:path";
351
- var CACHE_VERSION = "1.1.0";
318
+ var CACHE_VERSION = "1.3.0";
352
319
  var SPEC_CACHE_FILE = ".doccov/cache/spec.cache.json";
353
320
  function loadSpecCache(cwd) {
354
321
  try {
355
322
  const cachePath = path5.resolve(cwd, SPEC_CACHE_FILE);
356
- if (!fs3.existsSync(cachePath)) {
323
+ if (!fs4.existsSync(cachePath)) {
357
324
  return null;
358
325
  }
359
- const content = fs3.readFileSync(cachePath, "utf-8");
326
+ const content = fs4.readFileSync(cachePath, "utf-8");
360
327
  return JSON.parse(content);
361
328
  } catch {
362
329
  return null;
363
330
  }
364
331
  }
365
332
  function saveSpecCache(spec, context) {
366
- const { entryFile, sourceFiles, tsconfigPath, packageJsonPath, config, cwd } = context;
333
+ const {
334
+ entryFile,
335
+ sourceFiles,
336
+ tsconfigPath,
337
+ packageJsonPath,
338
+ config,
339
+ cwd,
340
+ specDiagnostics,
341
+ forgottenExports
342
+ } = context;
367
343
  const cache = {
368
344
  cacheVersion: CACHE_VERSION,
369
345
  generatedAt: new Date().toISOString(),
@@ -375,14 +351,16 @@ function saveSpecCache(spec, context) {
375
351
  sourceFiles: hashFiles(sourceFiles, cwd)
376
352
  },
377
353
  config,
378
- spec
354
+ spec,
355
+ specDiagnostics,
356
+ forgottenExports
379
357
  };
380
358
  const cachePath = path5.resolve(cwd, SPEC_CACHE_FILE);
381
359
  const dir = path5.dirname(cachePath);
382
- if (!fs3.existsSync(dir)) {
383
- fs3.mkdirSync(dir, { recursive: true });
360
+ if (!fs4.existsSync(dir)) {
361
+ fs4.mkdirSync(dir, { recursive: true });
384
362
  }
385
- fs3.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
363
+ fs4.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
386
364
  }
387
365
  function validateSpecCache(cache, context) {
388
366
  const { entryFile, sourceFiles, tsconfigPath, packageJsonPath, config, cwd } = context;
@@ -413,8 +391,8 @@ function validateSpecCache(cache, context) {
413
391
  }
414
392
  function clearSpecCache(cwd) {
415
393
  const cachePath = path5.resolve(cwd, SPEC_CACHE_FILE);
416
- if (fs3.existsSync(cachePath)) {
417
- fs3.unlinkSync(cachePath);
394
+ if (fs4.existsSync(cachePath)) {
395
+ fs4.unlinkSync(cachePath);
418
396
  return true;
419
397
  }
420
398
  return false;
@@ -654,7 +632,7 @@ var applyFilters = (spec, options) => {
654
632
  };
655
633
  };
656
634
 
657
- // src/openpkg.ts
635
+ // src/analyzer.ts
658
636
  class DocCov {
659
637
  options;
660
638
  constructor(options = {}) {
@@ -668,7 +646,7 @@ class DocCov {
668
646
  }
669
647
  async analyzeFile(filePath, analyzeOptions = {}) {
670
648
  const resolvedPath = path7.resolve(filePath);
671
- const content = await fs4.readFile(resolvedPath, "utf-8");
649
+ const content = await fs5.readFile(resolvedPath, "utf-8");
672
650
  const packageDir = resolvePackageDir(resolvedPath);
673
651
  const spec = await extractPackageSpec(resolvedPath, packageDir, content, this.options);
674
652
  return this.applySpecFilters(spec, analyzeOptions.filters).spec;
@@ -710,14 +688,15 @@ class DocCov {
710
688
  const filterOutcome2 = this.applySpecFilters(cacheResult.spec, analyzeOptions.filters);
711
689
  return {
712
690
  spec: filterOutcome2.spec,
713
- diagnostics: filterOutcome2.diagnostics,
691
+ diagnostics: [...cacheResult.specDiagnostics ?? [], ...filterOutcome2.diagnostics],
714
692
  metadata: cacheResult.metadata,
715
693
  fromCache: true,
716
- cacheStatus: { valid: true }
694
+ cacheStatus: { valid: true },
695
+ forgottenExports: cacheResult.forgottenExports
717
696
  };
718
697
  }
719
698
  }
720
- const content = await fs4.readFile(resolvedPath, "utf-8");
699
+ const content = await fs5.readFile(resolvedPath, "utf-8");
721
700
  const detectedSchemas = await this.detectSchemas(resolvedPath, packageDir);
722
701
  const analysis = await runAnalysis({
723
702
  entryFile: resolvedPath,
@@ -740,7 +719,7 @@ class DocCov {
740
719
  forgottenExports: analysis.forgottenExports
741
720
  };
742
721
  if (useCache) {
743
- this.saveToCache(result, resolvedPath, analysis.metadata);
722
+ this.saveToCache(result, resolvedPath, analysis.metadata, analysis.specDiagnostics, analysis.forgottenExports);
744
723
  }
745
724
  return result;
746
725
  }
@@ -780,18 +759,20 @@ class DocCov {
780
759
  hasNodeModules: true,
781
760
  resolveExternalTypes: cache.config.resolveExternalTypes,
782
761
  sourceFiles: cachedSourceFiles
783
- }
762
+ },
763
+ specDiagnostics: cache.specDiagnostics,
764
+ forgottenExports: cache.forgottenExports
784
765
  };
785
766
  }
786
767
  getCurrentSourceFiles(entryFile, baseDir) {
787
768
  try {
788
- const { program } = createProgram({ entryFile, baseDir });
769
+ const { program } = createProgram2({ entryFile, baseDir });
789
770
  return program.getSourceFiles().filter((sf) => !sf.isDeclarationFile && sf.fileName.startsWith(baseDir)).map((sf) => sf.fileName);
790
771
  } catch {
791
772
  return [];
792
773
  }
793
774
  }
794
- saveToCache(result, entryFile, metadata) {
775
+ saveToCache(result, entryFile, metadata, specDiagnostics, forgottenExports) {
795
776
  const { cwd } = this.options;
796
777
  if (!metadata.packageJsonPath) {
797
778
  return;
@@ -804,7 +785,9 @@ class DocCov {
804
785
  config: {
805
786
  resolveExternalTypes: metadata.resolveExternalTypes
806
787
  },
807
- cwd
788
+ cwd,
789
+ specDiagnostics,
790
+ forgottenExports
808
791
  };
809
792
  try {
810
793
  saveSpecCache(result.spec, cacheContext);
@@ -14553,19 +14536,19 @@ function defineConfig(config2) {
14553
14536
  return config2;
14554
14537
  }
14555
14538
  // src/detect/utils.ts
14556
- async function safeParseJson(fs5, path8) {
14539
+ async function safeParseJson(fs6, path8) {
14557
14540
  try {
14558
- if (!await fs5.exists(path8))
14541
+ if (!await fs6.exists(path8))
14559
14542
  return null;
14560
- const content = await fs5.readFile(path8);
14543
+ const content = await fs6.readFile(path8);
14561
14544
  return JSON.parse(content);
14562
14545
  } catch {
14563
14546
  return null;
14564
14547
  }
14565
14548
  }
14566
- async function readPackageJson(fs5, dir) {
14549
+ async function readPackageJson(fs6, dir) {
14567
14550
  const path8 = dir === "." ? "package.json" : `${dir}/package.json`;
14568
- return safeParseJson(fs5, path8);
14551
+ return safeParseJson(fs6, path8);
14569
14552
  }
14570
14553
 
14571
14554
  // src/detect/build.ts
@@ -14595,8 +14578,8 @@ var BUILD_TOOL_PATTERNS = [
14595
14578
  "babel",
14596
14579
  "ncc build"
14597
14580
  ];
14598
- async function detectBuildInfo(fs5, packagePath = ".") {
14599
- const pkgJson = await readPackageJson(fs5, packagePath);
14581
+ async function detectBuildInfo(fs6, packagePath = ".") {
14582
+ const pkgJson = await readPackageJson(fs6, packagePath);
14600
14583
  const scripts = pkgJson?.scripts ?? {};
14601
14584
  const scriptNames = Object.keys(scripts);
14602
14585
  const buildScriptsByName = scriptNames.filter((name) => BUILD_SCRIPT_NAMES.has(name) || BUILD_SCRIPT_PREFIXES.some((prefix) => name.startsWith(prefix)));
@@ -14608,10 +14591,10 @@ async function detectBuildInfo(fs5, packagePath = ".") {
14608
14591
  });
14609
14592
  const buildScripts = [...new Set([...buildScriptsByName, ...buildScriptsByContent])];
14610
14593
  const tsconfigPath = packagePath === "." ? "tsconfig.json" : `${packagePath}/tsconfig.json`;
14611
- const hasTsConfig = await fs5.exists(tsconfigPath);
14594
+ const hasTsConfig = await fs6.exists(tsconfigPath);
14612
14595
  const hasTsDep = pkgJson?.devDependencies?.typescript !== undefined || pkgJson?.dependencies?.typescript !== undefined;
14613
14596
  const hasTypeScript = hasTsConfig || hasTsDep;
14614
- const wasm = await detectWasmProject(fs5, packagePath, pkgJson);
14597
+ const wasm = await detectWasmProject(fs6, packagePath, pkgJson);
14615
14598
  const napi = detectNapiProject(pkgJson);
14616
14599
  return {
14617
14600
  scripts: buildScripts,
@@ -14628,11 +14611,11 @@ var WASM_PACKAGES = new Set([
14628
14611
  "wasm-bindgen",
14629
14612
  "@aspect/aspect-cli"
14630
14613
  ]);
14631
- async function detectWasmProject(fs5, packagePath, pkgJson) {
14614
+ async function detectWasmProject(fs6, packagePath, pkgJson) {
14632
14615
  const pkgCargoPath = packagePath === "." ? "Cargo.toml" : `${packagePath}/Cargo.toml`;
14633
- if (await fs5.exists(pkgCargoPath))
14616
+ if (await fs6.exists(pkgCargoPath))
14634
14617
  return true;
14635
- if (packagePath !== "." && await fs5.exists("Cargo.toml"))
14618
+ if (packagePath !== "." && await fs6.exists("Cargo.toml"))
14636
14619
  return true;
14637
14620
  if (pkgJson) {
14638
14621
  const deps = Object.keys({
@@ -14673,15 +14656,15 @@ function getPrimaryBuildScript(buildInfo) {
14673
14656
  return buildInfo.scripts[0] ?? null;
14674
14657
  }
14675
14658
  // src/detect/entry-point.ts
14676
- async function detectEntryPoint(fs5, packagePath = ".") {
14677
- const pkgJson = await readPackageJson(fs5, packagePath);
14659
+ async function detectEntryPoint(fs6, packagePath = ".") {
14660
+ const pkgJson = await readPackageJson(fs6, packagePath);
14678
14661
  if (!pkgJson) {
14679
14662
  throw new Error("No package.json found - not a valid npm package");
14680
14663
  }
14681
- const tsConfig = await parseTsConfig(fs5, packagePath);
14664
+ const tsConfig = await parseTsConfig(fs6, packagePath);
14682
14665
  const typesField = pkgJson.types || pkgJson.typings;
14683
14666
  if (typesField && typeof typesField === "string") {
14684
- const resolved = await resolveToSource(fs5, packagePath, typesField, tsConfig);
14667
+ const resolved = await resolveToSource(fs6, packagePath, typesField, tsConfig);
14685
14668
  if (resolved) {
14686
14669
  return { ...resolved, source: "types" };
14687
14670
  }
@@ -14691,7 +14674,7 @@ async function detectEntryPoint(fs5, packagePath = ".") {
14691
14674
  if (dotExport && typeof dotExport === "object" && "types" in dotExport) {
14692
14675
  const typesPath = dotExport.types;
14693
14676
  if (typesPath && typeof typesPath === "string") {
14694
- const resolved = await resolveToSource(fs5, packagePath, typesPath, tsConfig);
14677
+ const resolved = await resolveToSource(fs6, packagePath, typesPath, tsConfig);
14695
14678
  if (resolved) {
14696
14679
  return { ...resolved, source: "exports" };
14697
14680
  }
@@ -14699,13 +14682,13 @@ async function detectEntryPoint(fs5, packagePath = ".") {
14699
14682
  }
14700
14683
  }
14701
14684
  if (pkgJson.main && typeof pkgJson.main === "string") {
14702
- const resolved = await resolveToSource(fs5, packagePath, pkgJson.main, tsConfig);
14685
+ const resolved = await resolveToSource(fs6, packagePath, pkgJson.main, tsConfig);
14703
14686
  if (resolved) {
14704
14687
  return { ...resolved, source: "main" };
14705
14688
  }
14706
14689
  }
14707
14690
  if (pkgJson.module && typeof pkgJson.module === "string") {
14708
- const resolved = await resolveToSource(fs5, packagePath, pkgJson.module, tsConfig);
14691
+ const resolved = await resolveToSource(fs6, packagePath, pkgJson.module, tsConfig);
14709
14692
  if (resolved) {
14710
14693
  return { ...resolved, source: "module" };
14711
14694
  }
@@ -14723,27 +14706,27 @@ async function detectEntryPoint(fs5, packagePath = ".") {
14723
14706
  ];
14724
14707
  for (const fallback of fallbacks) {
14725
14708
  const checkPath = packagePath === "." ? fallback : `${packagePath}/${fallback}`;
14726
- if (await fs5.exists(checkPath)) {
14709
+ if (await fs6.exists(checkPath)) {
14727
14710
  return { path: fallback, source: "fallback", isDeclarationOnly: false };
14728
14711
  }
14729
14712
  }
14730
14713
  throw new Error("Could not detect TypeScript entry point. No types field in package.json and no common entry paths found.");
14731
14714
  }
14732
- async function parseTsConfig(fs5, packagePath) {
14715
+ async function parseTsConfig(fs6, packagePath) {
14733
14716
  const tsconfigPath = packagePath === "." ? "tsconfig.json" : `${packagePath}/tsconfig.json`;
14734
- const tsconfig = await safeParseJson(fs5, tsconfigPath);
14717
+ const tsconfig = await safeParseJson(fs6, tsconfigPath);
14735
14718
  if (!tsconfig?.compilerOptions) {
14736
14719
  return null;
14737
14720
  }
14738
14721
  const { outDir, rootDir, baseUrl, paths } = tsconfig.compilerOptions;
14739
14722
  return { outDir, rootDir, baseUrl, paths };
14740
14723
  }
14741
- async function resolveToSource(fs5, basePath, filePath, tsConfig) {
14724
+ async function resolveToSource(fs6, basePath, filePath, tsConfig) {
14742
14725
  const normalized = filePath.replace(/^\.\//, "");
14743
14726
  const checkPath = (p) => basePath === "." ? p : `${basePath}/${p}`;
14744
14727
  const isSourceTs = normalized.endsWith(".ts") && !normalized.endsWith(".d.ts") || normalized.endsWith(".tsx");
14745
14728
  if (isSourceTs) {
14746
- if (await fs5.exists(checkPath(normalized))) {
14729
+ if (await fs6.exists(checkPath(normalized))) {
14747
14730
  return { path: normalized, isDeclarationOnly: false };
14748
14731
  }
14749
14732
  }
@@ -14785,19 +14768,19 @@ async function resolveToSource(fs5, basePath, filePath, tsConfig) {
14785
14768
  for (const candidate of candidates) {
14786
14769
  if (candidate.endsWith(".d.ts"))
14787
14770
  continue;
14788
- if (await fs5.exists(checkPath(candidate))) {
14771
+ if (await fs6.exists(checkPath(candidate))) {
14789
14772
  return { path: candidate, isDeclarationOnly: false };
14790
14773
  }
14791
14774
  }
14792
14775
  if (normalized.endsWith(".d.ts")) {
14793
- if (await fs5.exists(checkPath(normalized))) {
14776
+ if (await fs6.exists(checkPath(normalized))) {
14794
14777
  return { path: normalized, isDeclarationOnly: true };
14795
14778
  }
14796
14779
  }
14797
14780
  return null;
14798
14781
  }
14799
14782
  // src/detect/filesystem.ts
14800
- import * as fs5 from "node:fs";
14783
+ import * as fs6 from "node:fs";
14801
14784
  import * as nodePath from "node:path";
14802
14785
  import { Writable } from "node:stream";
14803
14786
 
@@ -14810,19 +14793,19 @@ class NodeFileSystem {
14810
14793
  return nodePath.join(this.basePath, relativePath);
14811
14794
  }
14812
14795
  async exists(relativePath) {
14813
- return fs5.existsSync(this.resolve(relativePath));
14796
+ return fs6.existsSync(this.resolve(relativePath));
14814
14797
  }
14815
14798
  async readFile(relativePath) {
14816
- return fs5.readFileSync(this.resolve(relativePath), "utf-8");
14799
+ return fs6.readFileSync(this.resolve(relativePath), "utf-8");
14817
14800
  }
14818
14801
  async readDir(relativePath) {
14819
- return fs5.readdirSync(this.resolve(relativePath));
14802
+ return fs6.readdirSync(this.resolve(relativePath));
14820
14803
  }
14821
14804
  async isDirectory(relativePath) {
14822
14805
  const fullPath = this.resolve(relativePath);
14823
- if (!fs5.existsSync(fullPath))
14806
+ if (!fs6.existsSync(fullPath))
14824
14807
  return false;
14825
- return fs5.statSync(fullPath).isDirectory();
14808
+ return fs6.statSync(fullPath).isDirectory();
14826
14809
  }
14827
14810
  }
14828
14811
  function createCaptureStream() {
@@ -14895,11 +14878,11 @@ class SandboxFileSystem {
14895
14878
  }
14896
14879
  }
14897
14880
  // src/detect/monorepo.ts
14898
- async function detectMonorepo(fs6) {
14899
- const pkgJson = await readPackageJson(fs6, ".");
14881
+ async function detectMonorepo(fs7) {
14882
+ const pkgJson = await readPackageJson(fs7, ".");
14900
14883
  if (pkgJson?.workspaces) {
14901
14884
  const patterns = extractWorkspacePatterns(pkgJson.workspaces);
14902
- const packages = await resolveWorkspacePackages(fs6, patterns, pkgJson.name, pkgJson.private);
14885
+ const packages = await resolveWorkspacePackages(fs7, patterns, pkgJson.name, pkgJson.private);
14903
14886
  return {
14904
14887
  isMonorepo: packages.length > 0,
14905
14888
  type: "npm-workspaces",
@@ -14907,10 +14890,10 @@ async function detectMonorepo(fs6) {
14907
14890
  packages
14908
14891
  };
14909
14892
  }
14910
- if (await fs6.exists("pnpm-workspace.yaml")) {
14911
- const content = await fs6.readFile("pnpm-workspace.yaml");
14893
+ if (await fs7.exists("pnpm-workspace.yaml")) {
14894
+ const content = await fs7.readFile("pnpm-workspace.yaml");
14912
14895
  const patterns = parsePnpmWorkspace(content);
14913
- const packages = await resolveWorkspacePackages(fs6, patterns, pkgJson?.name, pkgJson?.private);
14896
+ const packages = await resolveWorkspacePackages(fs7, patterns, pkgJson?.name, pkgJson?.private);
14914
14897
  return {
14915
14898
  isMonorepo: packages.length > 0,
14916
14899
  type: "pnpm-workspaces",
@@ -14918,10 +14901,10 @@ async function detectMonorepo(fs6) {
14918
14901
  packages
14919
14902
  };
14920
14903
  }
14921
- if (await fs6.exists("lerna.json")) {
14922
- const lerna = await safeParseJson(fs6, "lerna.json");
14904
+ if (await fs7.exists("lerna.json")) {
14905
+ const lerna = await safeParseJson(fs7, "lerna.json");
14923
14906
  const patterns = lerna?.packages ?? ["packages/*"];
14924
- const packages = await resolveWorkspacePackages(fs6, patterns, pkgJson?.name, pkgJson?.private);
14907
+ const packages = await resolveWorkspacePackages(fs7, patterns, pkgJson?.name, pkgJson?.private);
14925
14908
  return {
14926
14909
  isMonorepo: packages.length > 0,
14927
14910
  type: "lerna",
@@ -14995,7 +14978,7 @@ function parsePnpmWorkspace(content) {
14995
14978
  }
14996
14979
  return patterns.length > 0 ? patterns : ["packages/*"];
14997
14980
  }
14998
- async function resolveWorkspacePackages(fs6, patterns, rootPackageName, rootIsPrivate) {
14981
+ async function resolveWorkspacePackages(fs7, patterns, rootPackageName, rootIsPrivate) {
14999
14982
  const packages = [];
15000
14983
  const seen = new Set;
15001
14984
  if (rootPackageName && !rootIsPrivate && rootPackageName !== "root") {
@@ -15017,18 +15000,18 @@ async function resolveWorkspacePackages(fs6, patterns, rootPackageName, rootIsPr
15017
15000
  }
15018
15001
  dirsToScan.add("packages");
15019
15002
  for (const dir of dirsToScan) {
15020
- if (!await fs6.exists(dir))
15003
+ if (!await fs7.exists(dir))
15021
15004
  continue;
15022
- if (!await fs6.isDirectory(dir))
15005
+ if (!await fs7.isDirectory(dir))
15023
15006
  continue;
15024
- const subdirs = await fs6.readDir(dir);
15007
+ const subdirs = await fs7.readDir(dir);
15025
15008
  for (const subdir of subdirs) {
15026
15009
  const pkgPath = `${dir}/${subdir}`;
15027
15010
  const pkgJsonPath = `${pkgPath}/package.json`;
15028
- if (!await fs6.exists(pkgJsonPath))
15011
+ if (!await fs7.exists(pkgJsonPath))
15029
15012
  continue;
15030
15013
  try {
15031
- const content = await fs6.readFile(pkgJsonPath);
15014
+ const content = await fs7.readFile(pkgJsonPath);
15032
15015
  const pkg = JSON.parse(content);
15033
15016
  if (pkg.name && !seen.has(pkg.name)) {
15034
15017
  seen.add(pkg.name);
@@ -15100,14 +15083,14 @@ var DEFAULT_PM = {
15100
15083
  installArgs: ["install", "--legacy-peer-deps"],
15101
15084
  runPrefix: ["npm", "run"]
15102
15085
  };
15103
- async function detectPackageManager(fs6) {
15104
- const pkgJson = await safeParseJson(fs6, "package.json");
15086
+ async function detectPackageManager(fs7) {
15087
+ const pkgJson = await safeParseJson(fs7, "package.json");
15105
15088
  if (pkgJson?.packageManager) {
15106
15089
  const pmName = parsePackageManagerField(pkgJson.packageManager);
15107
15090
  if (pmName && PM_CONFIGS[pmName]) {
15108
15091
  const config2 = PM_CONFIGS[pmName];
15109
15092
  for (const lockfile of config2.lockfiles) {
15110
- if (await fs6.exists(lockfile)) {
15093
+ if (await fs7.exists(lockfile)) {
15111
15094
  return { ...config2.info, lockfile };
15112
15095
  }
15113
15096
  }
@@ -15117,7 +15100,7 @@ async function detectPackageManager(fs6) {
15117
15100
  const foundLockfiles = [];
15118
15101
  for (const [pmName, config2] of Object.entries(PM_CONFIGS)) {
15119
15102
  for (const lockfile of config2.lockfiles) {
15120
- if (await fs6.exists(lockfile)) {
15103
+ if (await fs7.exists(lockfile)) {
15121
15104
  foundLockfiles.push({ lockfile, pm: pmName });
15122
15105
  }
15123
15106
  }
@@ -15149,10 +15132,10 @@ function getRunCommand(pm, script) {
15149
15132
  return [...pm.runPrefix, script];
15150
15133
  }
15151
15134
  // src/detect/index.ts
15152
- async function analyzeProject(fs6, options = {}) {
15135
+ async function analyzeProject(fs7, options = {}) {
15153
15136
  const [packageManager, monorepo] = await Promise.all([
15154
- detectPackageManager(fs6),
15155
- detectMonorepo(fs6)
15137
+ detectPackageManager(fs7),
15138
+ detectMonorepo(fs7)
15156
15139
  ]);
15157
15140
  let targetPath = ".";
15158
15141
  if (monorepo.isMonorepo) {
@@ -15169,18 +15152,18 @@ async function analyzeProject(fs6, options = {}) {
15169
15152
  targetPath = pkg.path;
15170
15153
  }
15171
15154
  const [entryPoint, build] = await Promise.all([
15172
- detectEntryPoint(fs6, targetPath),
15173
- detectBuildInfo(fs6, targetPath)
15155
+ detectEntryPoint(fs7, targetPath),
15156
+ detectBuildInfo(fs7, targetPath)
15174
15157
  ]);
15175
15158
  return { packageManager, monorepo, entryPoint, build };
15176
15159
  }
15177
15160
  // src/resolve/index.ts
15178
15161
  import * as path8 from "node:path";
15179
- async function resolveTarget(fs6, options) {
15162
+ async function resolveTarget(fs7, options) {
15180
15163
  let targetDir = options.cwd;
15181
15164
  let packageInfo;
15182
15165
  if (options.package) {
15183
- const mono = await detectMonorepo(fs6);
15166
+ const mono = await detectMonorepo(fs7);
15184
15167
  if (!mono.isMonorepo) {
15185
15168
  throw new Error("Not a monorepo. Remove --package flag for single-package repos.");
15186
15169
  }
@@ -15195,14 +15178,14 @@ async function resolveTarget(fs6, options) {
15195
15178
  let entryFile;
15196
15179
  let entryPointInfo;
15197
15180
  if (!options.entry) {
15198
- entryPointInfo = await detectEntryPoint(fs6, getRelativePath(options.cwd, targetDir));
15181
+ entryPointInfo = await detectEntryPoint(fs7, getRelativePath(options.cwd, targetDir));
15199
15182
  entryFile = path8.join(targetDir, entryPointInfo.path);
15200
15183
  } else {
15201
15184
  const explicitPath = path8.resolve(targetDir, options.entry);
15202
- const isDirectory = await isDir(fs6, getRelativePath(options.cwd, explicitPath));
15185
+ const isDirectory = await isDir(fs7, getRelativePath(options.cwd, explicitPath));
15203
15186
  if (isDirectory) {
15204
15187
  targetDir = explicitPath;
15205
- entryPointInfo = await detectEntryPoint(fs6, getRelativePath(options.cwd, explicitPath));
15188
+ entryPointInfo = await detectEntryPoint(fs7, getRelativePath(options.cwd, explicitPath));
15206
15189
  entryFile = path8.join(explicitPath, entryPointInfo.path);
15207
15190
  } else {
15208
15191
  entryFile = explicitPath;
@@ -15226,13 +15209,13 @@ function getRelativePath(base, target) {
15226
15209
  const rel = path8.relative(base, target);
15227
15210
  return rel || ".";
15228
15211
  }
15229
- async function isDir(fs6, relativePath) {
15230
- const hasPackageJson = await fs6.exists(path8.join(relativePath, "package.json"));
15212
+ async function isDir(fs7, relativePath) {
15213
+ const hasPackageJson = await fs7.exists(path8.join(relativePath, "package.json"));
15231
15214
  if (hasPackageJson)
15232
15215
  return true;
15233
15216
  const commonEntryFiles = ["index.ts", "index.tsx", "src/index.ts", "main.ts"];
15234
15217
  for (const entry of commonEntryFiles) {
15235
- if (await fs6.exists(path8.join(relativePath, entry))) {
15218
+ if (await fs7.exists(path8.join(relativePath, entry))) {
15236
15219
  return true;
15237
15220
  }
15238
15221
  }
@@ -15278,7 +15261,7 @@ function shouldValidate(validations, check2) {
15278
15261
  return validations.includes(check2);
15279
15262
  }
15280
15263
  // src/typecheck/example-typechecker.ts
15281
- import * as fs6 from "node:fs";
15264
+ import * as fs7 from "node:fs";
15282
15265
  import * as path9 from "node:path";
15283
15266
  import ts2 from "typescript";
15284
15267
  function stripCodeBlockMarkers(code) {
@@ -15286,9 +15269,9 @@ function stripCodeBlockMarkers(code) {
15286
15269
  }
15287
15270
  function getPackageName(packagePath) {
15288
15271
  const pkgJsonPath = path9.join(packagePath, "package.json");
15289
- if (fs6.existsSync(pkgJsonPath)) {
15272
+ if (fs7.existsSync(pkgJsonPath)) {
15290
15273
  try {
15291
- const pkgJson = JSON.parse(fs6.readFileSync(pkgJsonPath, "utf-8"));
15274
+ const pkgJson = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
15292
15275
  return pkgJson.name;
15293
15276
  } catch {
15294
15277
  return;
@@ -15300,7 +15283,7 @@ function findTsConfig(packagePath) {
15300
15283
  let dir = packagePath;
15301
15284
  while (dir !== path9.dirname(dir)) {
15302
15285
  const tsConfigPath = path9.join(dir, "tsconfig.json");
15303
- if (fs6.existsSync(tsConfigPath)) {
15286
+ if (fs7.existsSync(tsConfigPath)) {
15304
15287
  return tsConfigPath;
15305
15288
  }
15306
15289
  dir = path9.dirname(dir);
@@ -15323,7 +15306,7 @@ function createVirtualSource(example, packageName, exportNames) {
15323
15306
  `);
15324
15307
  }
15325
15308
  function getCompilerOptions(tsconfigPath) {
15326
- if (tsconfigPath && fs6.existsSync(tsconfigPath)) {
15309
+ if (tsconfigPath && fs7.existsSync(tsconfigPath)) {
15327
15310
  const configFile = ts2.readConfigFile(tsconfigPath, ts2.sys.readFile);
15328
15311
  if (!configFile.error) {
15329
15312
  const parsed = ts2.parseJsonConfigFileContent(configFile.config, ts2.sys, path9.dirname(tsconfigPath));
@@ -15424,7 +15407,7 @@ function typecheckExamples(examples, packagePath, options = {}) {
15424
15407
 
15425
15408
  // src/utils/example-runner.ts
15426
15409
  import { spawn } from "node:child_process";
15427
- import * as fs7 from "node:fs";
15410
+ import * as fs8 from "node:fs";
15428
15411
  import * as os from "node:os";
15429
15412
  import * as path10 from "node:path";
15430
15413
  function stripCodeBlockMarkers2(code) {
@@ -15435,7 +15418,7 @@ async function runExample(code, options = {}) {
15435
15418
  const cleanCode = stripCodeBlockMarkers2(code);
15436
15419
  const tmpFile = path10.join(cwd, `doccov-example-${Date.now()}-${Math.random().toString(36).slice(2)}.ts`);
15437
15420
  try {
15438
- fs7.writeFileSync(tmpFile, cleanCode, "utf-8");
15421
+ fs8.writeFileSync(tmpFile, cleanCode, "utf-8");
15439
15422
  const startTime = Date.now();
15440
15423
  return await new Promise((resolve5) => {
15441
15424
  let stdout = "";
@@ -15490,7 +15473,7 @@ async function runExample(code, options = {}) {
15490
15473
  });
15491
15474
  } finally {
15492
15475
  try {
15493
- fs7.unlinkSync(tmpFile);
15476
+ fs8.unlinkSync(tmpFile);
15494
15477
  } catch {}
15495
15478
  }
15496
15479
  }
@@ -15505,15 +15488,15 @@ async function runExamples(examples, options = {}) {
15505
15488
  return results;
15506
15489
  }
15507
15490
  function detectPackageManager2(cwd) {
15508
- if (fs7.existsSync(path10.join(cwd, "bun.lockb")))
15491
+ if (fs8.existsSync(path10.join(cwd, "bun.lockb")))
15509
15492
  return "bun";
15510
- if (fs7.existsSync(path10.join(cwd, "bun.lock")))
15493
+ if (fs8.existsSync(path10.join(cwd, "bun.lock")))
15511
15494
  return "bun";
15512
- if (fs7.existsSync(path10.join(cwd, "pnpm-lock.yaml")))
15495
+ if (fs8.existsSync(path10.join(cwd, "pnpm-lock.yaml")))
15513
15496
  return "pnpm";
15514
- if (fs7.existsSync(path10.join(cwd, "yarn.lock")))
15497
+ if (fs8.existsSync(path10.join(cwd, "yarn.lock")))
15515
15498
  return "yarn";
15516
- if (fs7.existsSync(path10.join(cwd, "package-lock.json")))
15499
+ if (fs8.existsSync(path10.join(cwd, "package-lock.json")))
15517
15500
  return "npm";
15518
15501
  return "npm";
15519
15502
  }
@@ -15584,9 +15567,9 @@ async function runExamplesWithPackage(examples, options) {
15584
15567
  const absolutePackagePath = path10.resolve(packagePath);
15585
15568
  const workDir = path10.join(os.tmpdir(), `doccov-examples-${Date.now()}-${Math.random().toString(36).slice(2)}`);
15586
15569
  try {
15587
- fs7.mkdirSync(workDir, { recursive: true });
15570
+ fs8.mkdirSync(workDir, { recursive: true });
15588
15571
  const pkgJson = { name: "doccov-example-runner", type: "module" };
15589
- fs7.writeFileSync(path10.join(workDir, "package.json"), JSON.stringify(pkgJson, null, 2));
15572
+ fs8.writeFileSync(path10.join(workDir, "package.json"), JSON.stringify(pkgJson, null, 2));
15590
15573
  const pm = packageManager ?? detectPackageManager2(options.cwd ?? process.cwd());
15591
15574
  const { cmd, args } = getInstallCommand2(pm, absolutePackagePath);
15592
15575
  const installResult = await runCommand(cmd, args, {
@@ -15614,7 +15597,7 @@ async function runExamplesWithPackage(examples, options) {
15614
15597
  };
15615
15598
  } finally {
15616
15599
  try {
15617
- fs7.rmSync(workDir, { recursive: true, force: true });
15600
+ fs8.rmSync(workDir, { recursive: true, force: true });
15618
15601
  } catch {}
15619
15602
  }
15620
15603
  }
@@ -16722,11 +16705,11 @@ async function fetchSpecFromGitHubWithPath(parsed, specPath = "openpkg.json") {
16722
16705
  }
16723
16706
  // src/install/index.ts
16724
16707
  var DEFAULT_FALLBACK_ORDER = ["bun", "npm"];
16725
- async function installDependencies(fs8, cwd, runCommand2, options = {}) {
16708
+ async function installDependencies(fs9, cwd, runCommand2, options = {}) {
16726
16709
  const { timeout = 180000, fallbackOrder = DEFAULT_FALLBACK_ORDER, onProgress } = options;
16727
16710
  const errors3 = [];
16728
16711
  onProgress?.({ stage: "installing", message: "Detecting package manager..." });
16729
- const pmInfo = await detectPackageManager(fs8);
16712
+ const pmInfo = await detectPackageManager(fs9);
16730
16713
  if (pmInfo.lockfile) {
16731
16714
  onProgress?.({
16732
16715
  stage: "installing",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doccov/sdk",
3
- "version": "0.29.0",
3
+ "version": "0.29.4",
4
4
  "description": "DocCov SDK - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",