@doccov/sdk 0.28.3 → 0.29.2

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