@doccov/sdk 0.9.0 → 0.10.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +1632 -820
  2. package/dist/index.js +5729 -4922
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SpecDocDrift, SpecExport } from "@openpkg-ts/spec";
1
+ import { DriftCategory, SpecDocDrift, SpecExport } from "@openpkg-ts/spec";
2
2
  interface ExampleRunResult {
3
3
  success: boolean;
4
4
  stdout: string;
@@ -48,6 +48,37 @@ declare function runExamplesWithPackage(examples: string[], options: RunExamples
48
48
  import { OpenPkg } from "@openpkg-ts/spec";
49
49
  type OpenPkgSpec = OpenPkg;
50
50
  /**
51
+ * Result of computing drift for a single export.
52
+ */
53
+ type ExportDriftResult = {
54
+ id: string;
55
+ drift: SpecDocDrift[];
56
+ };
57
+ /**
58
+ * Result of computing drift for all exports.
59
+ */
60
+ type DriftResult = {
61
+ exports: Map<string, SpecDocDrift[]>;
62
+ };
63
+ /**
64
+ * Build a registry of all export/type names for cross-reference validation.
65
+ */
66
+ declare function buildExportRegistry(spec: OpenPkgSpec): Set<string>;
67
+ /**
68
+ * Compute drift for all exports in a spec.
69
+ *
70
+ * @param spec - The OpenPkg spec to analyze
71
+ * @returns Drift results per */
72
+ declare function computeDrift(spec: OpenPkgSpec): DriftResult;
73
+ /**
74
+ * Compute drift for a single export.
75
+ *
76
+ * @param entry - The to analyze
77
+ * @param exportRegistry - Registry of known names for link validation
78
+ * @returns Array of drift issues detected
79
+ */
80
+ declare function computeExportDrift(entry: SpecExport, exportRegistry?: Set<string>): SpecDocDrift[];
81
+ /**
51
82
  * Detect runtime errors in @example blocks.
52
83
  * Results are provided externally after running examples via runExamples().
53
84
  */
@@ -70,589 +101,1585 @@ declare function hasNonAssertionComments(code: string): boolean;
70
101
  */
71
102
  declare function detectExampleAssertionFailures(entry: SpecExport, runtimeResults: Map<number, ExampleRunResult>): SpecDocDrift[];
72
103
  /**
73
- * Project detection types for I/O-agnostic project analysis.
74
- * Used by both CLI (NodeFileSystem) and API (SandboxFileSystem).
104
+ * Extended drift with category and fixability metadata.
75
105
  */
106
+ interface CategorizedDrift extends SpecDocDrift {
107
+ category: DriftCategory;
108
+ fixable: boolean;
109
+ }
76
110
  /**
77
- * Minimal filesystem interface for I/O-agnostic detection.
78
- * Implementations: NodeFileSystem (CLI), SandboxFileSystem (API)
111
+ * Categorize a single drift issue.
112
+ *
113
+ * @param drift - The drift to categorize
114
+ * @returns The drift with category and fixable metadata
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const drift: SpecDocDrift = {
119
+ * type: 'param-type-mismatch',
120
+ * target: 'userId',
121
+ * issue: 'Type mismatch'
122
+ * };
123
+ * const categorized = categorizeDrift(drift);
124
+ * console.log(categorized.category); // => 'structural'
125
+ * console.log(categorized.fixable); // => true
126
+ * ```
79
127
  */
80
- interface FileSystem {
81
- /** Check if a file or directory exists */
82
- exists(path: string): Promise<boolean>;
83
- /** Read file contents as string */
84
- readFile(path: string): Promise<string>;
85
- /** List directory contents (file/folder names only) */
86
- readDir(path: string): Promise<string[]>;
87
- /** Check if path is a directory */
88
- isDirectory(path: string): Promise<boolean>;
89
- }
90
- /** Supported package managers */
91
- type PackageManager = "npm" | "yarn" | "pnpm" | "bun";
92
- /** Package manager detection result with install/run commands */
93
- interface PackageManagerInfo {
94
- /** Package manager name */
95
- name: PackageManager;
96
- /** Lockfile that was detected (null if none found) */
97
- lockfile: string | null;
98
- /** Arguments for install command, e.g. ['install', '--frozen-lockfile'] */
99
- installArgs: string[];
100
- /** Prefix for running scripts, e.g. ['npm', 'run'] or ['pnpm'] */
101
- runPrefix: string[];
102
- }
103
- /** Monorepo type based on configuration */
104
- type MonorepoType = "npm-workspaces" | "pnpm-workspaces" | "lerna" | "none";
105
- /** Monorepo detection result */
106
- interface MonorepoInfo {
107
- /** Whether this is a monorepo */
108
- isMonorepo: boolean;
109
- /** Type of monorepo configuration */
110
- type: MonorepoType;
111
- /** Workspace patterns from config (e.g. ['packages/*']) */
112
- patterns: string[];
113
- /** Resolved workspace packages */
114
- packages: WorkspacePackage[];
115
- }
116
- /** A package within a monorepo workspace */
117
- interface WorkspacePackage {
118
- /** Package name from package.json */
119
- name: string;
120
- /** Relative path to package directory */
121
- path: string;
122
- /** Whether the package is marked as private */
123
- private: boolean;
124
- }
125
- /** Entry point source - where the entry was detected from */
126
- type EntryPointSource = "types" | "exports" | "main" | "module" | "fallback";
127
- /** Entry point detection result */
128
- interface EntryPointInfo {
129
- /** Path to entry file (relative to package root) */
130
- path: string;
131
- /** Where the entry point was detected from */
132
- source: EntryPointSource;
133
- /** Whether this is a .d.ts file (no source available) */
134
- isDeclarationOnly: boolean;
135
- }
136
- /** Build configuration detection result */
137
- interface BuildInfo {
138
- /** Build-related script names found (e.g. ['build', 'build:types']) */
139
- scripts: string[];
140
- /** Whether any build script was found */
141
- hasBuildScript: boolean;
142
- /** Whether TypeScript is configured/installed */
143
- hasTypeScript: boolean;
144
- /** Indicators for exotic project types */
145
- exoticIndicators: {
146
- /** WASM project (Cargo.toml or wasm-pack scripts) */
147
- wasm: boolean;
148
- /** napi-rs native addon project */
149
- napi: boolean;
150
- };
151
- }
152
- /** Complete project analysis result */
153
- interface ProjectInfo {
154
- /** Package manager info */
155
- packageManager: PackageManagerInfo;
156
- /** Monorepo info */
157
- monorepo: MonorepoInfo;
158
- /** Entry point info */
159
- entryPoint: EntryPointInfo;
160
- /** Build info */
161
- build: BuildInfo;
162
- }
163
- /** Options for analyzeProject() */
164
- interface AnalyzeProjectOptions {
165
- /** Target package name for monorepos */
166
- targetPackage?: string;
167
- }
128
+ declare function categorizeDrift(drift: SpecDocDrift): CategorizedDrift;
168
129
  /**
169
- * Detect build configuration and exotic project indicators.
130
+ * Group drifts by category.
170
131
  *
171
- * @param fs - FileSystem implementation
172
- * @param packagePath - Path to package directory (default: ".")
173
- * @returns Build info including scripts and exotic indicators
132
+ * @param drifts - Array of drift issues to group
133
+ * @returns Drifts organized by category
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * const grouped = groupDriftsByCategory(spec.docs.drift ?? []);
138
+ * console.log(grouped.structural.length); // Number of structural issues
139
+ * console.log(grouped.semantic.length); // Number of semantic issues
140
+ * console.log(grouped.example.length); // Number of example issues
141
+ * ```
174
142
  */
175
- declare function detectBuildInfo(fs: FileSystem, packagePath?: string): Promise<BuildInfo>;
143
+ declare function groupDriftsByCategory(drifts: SpecDocDrift[]): Record<DriftCategory, CategorizedDrift[]>;
176
144
  /**
177
- * Get the primary build script name to run.
178
- * Prefers 'build' over 'compile' over 'tsc'.
145
+ * Summary of drift issues by category.
179
146
  */
180
- declare function getPrimaryBuildScript(buildInfo: BuildInfo): string | null;
147
+ interface DriftSummary {
148
+ total: number;
149
+ byCategory: Record<DriftCategory, number>;
150
+ fixable: number;
151
+ }
181
152
  /**
182
- * Detect the TypeScript entry point for a package.
153
+ * Get drift summary counts by category.
183
154
  *
184
- * Priority order:
185
- * 1. package.json -> types or typings field
186
- * 2. package.json -> exports["."].types
187
- * 3. package.json -> main field (resolve to .ts)
188
- * 4. package.json -> module field (resolve to .ts)
189
- * 5. Common fallback paths
155
+ * @param drifts - Array of drift issues
156
+ * @returns Summary with totals, category breakdown, and fixable count
190
157
  *
191
- * @param fs - FileSystem implementation
192
- * @param packagePath - Path to package directory (default: ".")
193
- * @returns Entry point info
194
- * @throws Error if no entry point can be found
158
+ * @example
159
+ * ```ts
160
+ * const summary = getDriftSummary(exportEntry.docs?.drift ?? []);
161
+ * console.log(`${summary.total} issues: ${summary.fixable} fixable`);
162
+ * // => "5 issues: 3 fixable"
163
+ * ```
195
164
  */
196
- declare function detectEntryPoint(fs: FileSystem, packagePath?: string): Promise<EntryPointInfo>;
197
- import { Sandbox } from "@vercel/sandbox";
165
+ declare function getDriftSummary(drifts: SpecDocDrift[]): DriftSummary;
198
166
  /**
199
- * Node.js filesystem implementation for CLI usage.
200
- * Wraps Node.js fs module with a base path.
167
+ * Format drift summary for CLI output (single line).
168
+ *
169
+ * @param summary - Drift summary to format
170
+ * @returns Human-readable summary string
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * const summary = getDriftSummary(drifts);
175
+ * console.log(formatDriftSummaryLine(summary));
176
+ * // => "5 issues (3 structural, 1 semantic, 1 example)"
177
+ * ```
201
178
  */
202
- declare class NodeFileSystem implements FileSystem {
203
- private basePath;
204
- constructor(basePath: string);
205
- private resolve;
206
- exists(relativePath: string): Promise<boolean>;
207
- readFile(relativePath: string): Promise<string>;
208
- readDir(relativePath: string): Promise<string[]>;
209
- isDirectory(relativePath: string): Promise<boolean>;
179
+ declare function formatDriftSummaryLine(summary: DriftSummary): string;
180
+ import { OpenPkg as OpenPkg2, SpecDocDrift as SpecDocDrift2, SpecDocsMetadata, SpecExport as SpecExport3 } from "@openpkg-ts/spec";
181
+ import { SpecExport as SpecExport2, SpecExportKind } from "@openpkg-ts/spec";
182
+ import * as TS from "typescript";
183
+ /**
184
+ * Represents a single parameter in a JSDoc patch
185
+ */
186
+ interface JSDocParam {
187
+ name: string;
188
+ type?: string;
189
+ description?: string;
190
+ optional?: boolean;
210
191
  }
211
192
  /**
212
- * Vercel Sandbox filesystem implementation for API usage.
213
- * Uses sandbox.runCommand() with shell commands.
193
+ * Represents a return type in a JSDoc patch
214
194
  */
215
- declare class SandboxFileSystem implements FileSystem {
216
- private sandbox;
217
- constructor(sandbox: Sandbox);
218
- exists(path: string): Promise<boolean>;
219
- readFile(path: string): Promise<string>;
220
- readDir(path: string): Promise<string[]>;
221
- isDirectory(path: string): Promise<boolean>;
195
+ interface JSDocReturn {
196
+ type?: string;
197
+ description?: string;
222
198
  }
223
199
  /**
224
- * Detect if a project is a monorepo and list its packages.
225
- *
226
- * Detection triggers (in order):
227
- * 1. package.json has workspaces field (npm/yarn)
228
- * 2. pnpm-workspace.yaml exists
229
- * 3. lerna.json exists
200
+ * Represents a generic tag in a JSDoc patch
230
201
  */
231
- declare function detectMonorepo(fs: FileSystem): Promise<MonorepoInfo>;
202
+ interface JSDocTag {
203
+ name: string;
204
+ text: string;
205
+ }
232
206
  /**
233
- * Find a package by name or path in a list of workspace packages.
207
+ * A patchable representation of a JSDoc comment
234
208
  */
235
- declare function findPackageByName(packages: WorkspacePackage[], nameOrPath: string): WorkspacePackage | undefined;
209
+ interface JSDocPatch {
210
+ description?: string;
211
+ params?: JSDocParam[];
212
+ returns?: JSDocReturn;
213
+ examples?: string[];
214
+ deprecated?: string | false;
215
+ async?: boolean;
216
+ type?: string;
217
+ typeParams?: Array<{
218
+ name: string;
219
+ constraint?: string;
220
+ description?: string;
221
+ }>;
222
+ otherTags?: JSDocTag[];
223
+ }
236
224
  /**
237
- * Format package list for display in error messages.
225
+ * Represents an edit to be applied to a source file
238
226
  */
239
- declare function formatPackageList(packages: WorkspacePackage[], limit?: number): string;
227
+ interface JSDocEdit {
228
+ filePath: string;
229
+ symbolName: string;
230
+ startLine: number;
231
+ endLine: number;
232
+ hasExisting: boolean;
233
+ existingJSDoc?: string;
234
+ newJSDoc: string;
235
+ indent: string;
236
+ }
240
237
  /**
241
- * Detect package manager based on lockfile presence and package.json hints.
242
- *
243
- * Resolution order:
244
- * 1. packageManager field in package.json (e.g., "pnpm@9.0.0")
245
- * 2. Most recently modified lockfile (when multiple exist)
246
- * 3. Static priority order: pnpm > bun > yarn > npm
247
- * 4. Default to npm
238
+ * Result of applying edits to source files
248
239
  */
249
- declare function detectPackageManager(fs: FileSystem): Promise<PackageManagerInfo>;
240
+ interface ApplyEditsResult {
241
+ filesModified: number;
242
+ editsApplied: number;
243
+ errors: Array<{
244
+ file: string;
245
+ error: string;
246
+ }>;
247
+ }
250
248
  /**
251
- * Get install command for a package manager.
252
- * Returns [command, ...args] array.
249
+ * Parse a JSDoc comment string into a patchable structure
253
250
  */
254
- declare function getInstallCommand(pm: PackageManagerInfo): string[];
251
+ declare function parseJSDocToPatch(jsDocText: string): JSDocPatch;
255
252
  /**
256
- * Get run command for a package manager script.
257
- * Returns [command, ...args, scriptName] array.
253
+ * Apply a partial patch to an existing JSDoc patch, preserving unmodified content
258
254
  */
259
- declare function getRunCommand(pm: PackageManagerInfo, script: string): string[];
255
+ declare function applyPatchToJSDoc(existing: JSDocPatch, updates: Partial<JSDocPatch>): JSDocPatch;
260
256
  /**
261
- * Safely parse a JSON file, returning null on any error.
257
+ * Serialize a JSDocPatch back to a formatted comment string
262
258
  */
263
- declare function safeParseJson<T = Record<string, unknown>>(fs: FileSystem, path: string): Promise<T | null>;
259
+ declare function serializeJSDoc(patch: JSDocPatch, indent?: string): string;
264
260
  /**
265
- * Standard package.json structure for detection purposes.
261
+ * Find the JSDoc location for a declaration in a source file
266
262
  */
267
- interface PackageJson {
268
- name?: string;
269
- version?: string;
270
- private?: boolean;
271
- main?: string;
272
- module?: string;
273
- types?: string;
274
- typings?: string;
275
- exports?: PackageExports;
276
- workspaces?: string[] | {
277
- packages: string[];
278
- };
279
- scripts?: Record<string, string>;
280
- dependencies?: Record<string, string>;
281
- devDependencies?: Record<string, string>;
282
- }
263
+ declare function findJSDocLocation(sourceFile: TS.SourceFile, symbolName: string, approximateLine?: number): {
264
+ startLine: number;
265
+ endLine: number;
266
+ declarationLine: number;
267
+ hasExisting: boolean;
268
+ existingJSDoc?: string;
269
+ indent: string;
270
+ } | null;
283
271
  /**
284
- * Package.json exports field structure.
272
+ * Apply a batch of edits to source files
285
273
  */
286
- type PackageExports = string | {
287
- "."?: string | {
288
- types?: string;
289
- import?: string;
290
- require?: string;
291
- default?: string;
292
- };
293
- [key: string]: unknown;
294
- };
274
+ declare function applyEdits(edits: JSDocEdit[]): Promise<ApplyEditsResult>;
295
275
  /**
296
- * Read and parse package.json from a directory.
276
+ * Create a TypeScript source file from a file path
297
277
  */
298
- declare function readPackageJson(fs: FileSystem, dir: string): Promise<PackageJson | null>;
278
+ declare function createSourceFile(filePath: string): TS.SourceFile;
299
279
  /**
300
- * Analyze a project's structure for scanning.
301
- *
302
- * This is the main entry point for project detection. It combines all
303
- * detection functions into a single call that returns complete project info.
304
- *
305
- * For monorepos, you must specify the target package via options.targetPackage.
306
- * If not specified and a monorepo is detected, an error is thrown with the
307
- * list of available packages.
308
- *
309
- * @param fs - FileSystem implementation (NodeFileSystem or SandboxFileSystem)
310
- * @param options - Options including targetPackage for monorepos
311
- * @returns Complete project info
312
- * @throws Error if monorepo detected without targetPackage specified
313
- * @throws Error if targetPackage not found in monorepo
314
- *
315
- * @example
316
- * ```typescript
317
- * import { NodeFileSystem, analyzeProject } from '@doccov/sdk';
318
- *
319
- * // Single package
320
- * const singleFs = new NodeFileSystem('/path/to/package');
321
- * const singleProject = await analyzeProject(singleFs);
322
- *
323
- * // Monorepo with target package
324
- * const monoFs = new NodeFileSystem('/path/to/monorepo');
325
- * const monoProject = await analyzeProject(monoFs, { targetPackage: '@scope/core' });
326
- * ```
280
+ * Quality rule severity levels.
327
281
  */
328
- declare function analyzeProject2(fs: FileSystem, options?: AnalyzeProjectOptions): Promise<ProjectInfo>;
329
- interface DocCovOptions {
330
- includePrivate?: boolean;
331
- followImports?: boolean;
332
- maxDepth?: number;
333
- resolveExternalTypes?: boolean;
334
- }
335
- /** @deprecated Use DocCovOptions instead */
336
- type OpenPkgOptions = DocCovOptions;
337
- declare function extractPackageSpec(entryFile: string, packageDir?: string, content?: string, options?: OpenPkgOptions): Promise<OpenPkgSpec>;
338
- interface FilterOptions {
339
- include?: string[];
340
- exclude?: string[];
282
+ type QualitySeverity = "error" | "warn" | "off";
283
+ /**
284
+ * Context passed to quality rule checks.
285
+ */
286
+ interface RuleContext {
287
+ export: SpecExport2;
288
+ rawJSDoc?: string;
341
289
  }
342
290
  /**
343
- * Configuration types for DocCov.
344
- * These types are shared between CLI and API.
291
+ * A violation reported by a quality rule.
345
292
  */
293
+ interface QualityViolation {
294
+ ruleId: string;
295
+ severity: "error" | "warn";
296
+ message: string;
297
+ line?: number;
298
+ fixable: boolean;
299
+ }
346
300
  /**
347
- * Documentation configuration options.
301
+ * A quality rule checks one aspect of documentation quality.
302
+ * Rules can contribute to coverage score, lint violations, or both.
348
303
  */
349
- interface DocsConfig {
350
- /** Glob patterns for markdown docs to include */
351
- include?: string[];
352
- /** Glob patterns for markdown docs to exclude */
353
- exclude?: string[];
304
+ interface QualityRule {
305
+ /** Unique rule identifier */
306
+ id: string;
307
+ /** Human-readable name */
308
+ name: string;
309
+ /** What this rule checks */
310
+ description: string;
311
+ /**
312
+ * Which kinds this rule applies to.
313
+ * If undefined, applies to all kinds.
314
+ */
315
+ appliesTo?: SpecExportKind[];
316
+ /**
317
+ * Does this rule contribute to coverage score?
318
+ * If true, the rule is counted as a "signal" for coverage calculation.
319
+ */
320
+ affectsCoverage: boolean;
321
+ /**
322
+ * Default lint severity. Set to 'off' if rule is coverage-only.
323
+ */
324
+ defaultSeverity: QualitySeverity;
325
+ /**
326
+ * Check if the satisfies this rule.
327
+ * Returns true if satisfied, false if not.
328
+ */
329
+ check(ctx: RuleContext): boolean;
330
+ /**
331
+ * Get detailed violation info when check returns false.
332
+ * Only called if check() returns false and severity !== 'off'.
333
+ */
334
+ getViolation?(ctx: RuleContext): QualityViolation;
335
+ /**
336
+ * Generate a fix for the violation.
337
+ * Only called if check() returns false and fix is requested.
338
+ */
339
+ fix?(ctx: RuleContext): JSDocPatch | null;
354
340
  }
355
341
  /**
356
- * Check command configuration options.
342
+ * User configuration for quality rules.
357
343
  */
358
- interface CheckConfig {
359
- /** Enable lint checks (default: true) */
360
- lint?: boolean;
361
- /** Enable typecheck for examples (default: true) */
362
- typecheck?: boolean;
363
- /** Enable runtime execution of examples (default: false) */
364
- exec?: boolean;
344
+ interface QualityConfig {
345
+ rules: Record<string, QualitySeverity>;
365
346
  }
366
347
  /**
367
- * Lint severity level.
348
+ * Result of evaluating quality for a single export.
368
349
  */
369
- type LintSeverity = "error" | "warn" | "off";
350
+ interface QualityResult {
351
+ /** Coverage score (0-100) */
352
+ coverageScore: number;
353
+ /** Coverage details */
354
+ coverage: {
355
+ /** Rule IDs that passed */
356
+ satisfied: string[];
357
+ /** Rule IDs that failed */
358
+ missing: string[];
359
+ /** All applicable rule IDs */
360
+ applicable: string[];
361
+ };
362
+ /** Lint violations (only for rules with severity !== 'off') */
363
+ violations: QualityViolation[];
364
+ /** Summary counts */
365
+ summary: {
366
+ errorCount: number;
367
+ warningCount: number;
368
+ fixableCount: number;
369
+ };
370
+ }
370
371
  /**
371
- * Lint rules configuration.
372
+ * Aggregate result for multiple exports.
372
373
  */
373
- interface LintRulesConfig {
374
- /** Rule severity overrides */
375
- rules?: Record<string, LintSeverity>;
374
+ interface AggregateQualityResult {
375
+ byExport: Map<string, QualityResult>;
376
+ overall: {
377
+ coverageScore: number;
378
+ totalViolations: number;
379
+ errorCount: number;
380
+ warningCount: number;
381
+ };
376
382
  }
377
383
  /**
378
- * Normalized DocCov configuration.
379
- * This is the parsed/normalized form used by commands.
384
+ * An enriched with computed documentation metadata.
385
+ * Extends SpecExport with the `docs` field for coverage analysis.
380
386
  */
381
- interface DocCovConfig {
382
- /** Export include patterns */
383
- include?: string[];
384
- /** Export exclude patterns */
385
- exclude?: string[];
386
- /** Plugins (future) */
387
- plugins?: unknown[];
388
- /** Documentation configuration */
389
- docs?: DocsConfig;
390
- /** Check command configuration */
391
- check?: CheckConfig;
392
- /** Lint configuration */
393
- lint?: LintRulesConfig;
387
+ type EnrichedExport = SpecExport3 & {
388
+ docs?: EnrichedDocsMetadata;
389
+ };
390
+ /**
391
+ * Extended docs metadata with quality violations.
392
+ */
393
+ type EnrichedDocsMetadata = SpecDocsMetadata & {
394
+ violations?: QualityViolation[];
395
+ };
396
+ /**
397
+ * An enriched OpenPkg spec with computed documentation metadata.
398
+ * Extends OpenPkg with per-and aggregate coverage data.
399
+ */
400
+ type EnrichedOpenPkg = Omit<OpenPkg2, "exports"> & {
401
+ exports: EnrichedExport[];
402
+ docs?: EnrichedDocsMetadata;
403
+ /** Drift summary with category breakdown (if drift exists) */
404
+ driftSummary?: DriftSummary;
405
+ };
406
+ interface EnrichOptions {
407
+ /**
408
+ * Per-drift issues to include in enrichment.
409
+ * Map from ID to drift issues.
410
+ */
411
+ driftByExport?: Map<string, SpecDocDrift2[]>;
412
+ /**
413
+ * Quality configuration with rule severities.
414
+ */
415
+ qualityConfig?: QualityConfig;
416
+ /**
417
+ * Per-raw JSDoc text for style rule checks.
418
+ * Map from ID to raw JSDoc string.
419
+ */
420
+ rawJSDocByExport?: Map<string, string>;
394
421
  }
395
422
  /**
396
- * Define a DocCov configuration.
397
- * Helper function for type-safe configuration in doccov.config.ts.
423
+ * Enrich an OpenPkg spec with documentation coverage metadata.
398
424
  *
399
- * @param config - Configuration object
400
- * @returns The configuration object (for type inference)
425
+ * This function computes coverage scores using quality rules,
426
+ * detects drift issues, and produces an EnrichedOpenPkg.
427
+ *
428
+ * @param spec - The pure OpenPkg spec to enrich
429
+ * @param options - Optional enrichment configuration
430
+ * @returns An enriched spec with documentation metadata
401
431
  *
402
432
  * @example
403
- * ```typescript
404
- * // doccov.config.ts
405
- * import { defineConfig } from '@doccov/sdk';
433
+ * ```ts
434
+ * import { DocCov, enrichSpec } from '@doccov/sdk';
406
435
  *
407
- * defineConfig({
408
- * include: ['MyClass', 'myFunction'],
409
- * exclude: ['internal*'],
410
- * docs: {
411
- * include: ['docs/**\/*.md'],
412
- * },
413
- * lint: {
414
- * rules: {
415
- * 'require-description': 'error',
416
- * 'require-example': 'warn',
417
- * },
418
- * },
419
- * });
436
+ * const doccov = new DocCov();
437
+ * const { spec } = await doccov.analyzeFileWithDiagnostics('src/index.ts');
438
+ *
439
+ * // Enrich with coverage data
440
+ * const enriched = enrichSpec(spec);
441
+ * console.log(enriched.docs?.coverageScore); // e.g., 85
442
+ * console.log(enriched.docs?.missing); // e.g., ['has-examples']
420
443
  * ```
421
444
  */
422
- declare function defineConfig(config: DocCovConfig): DocCovConfig;
445
+ declare function enrichSpec(spec: OpenPkg2, options?: EnrichOptions): EnrichedOpenPkg;
446
+ import { OpenPkg as OpenPkg3 } from "@openpkg-ts/spec";
447
+ import { DriftCategory as DriftCategory2, SpecDocDrift as SpecDocDrift3 } from "@openpkg-ts/spec";
423
448
  /**
424
- * Source of filter options.
449
+ * DocCov report schema version.
425
450
  */
426
- type FilterSource = "config" | "override" | "combined";
451
+ declare const REPORT_VERSION = "1.0.0";
427
452
  /**
428
- * Resolved filter options after merging config and overrides.
453
+ * Default directory for DocCov outputs.
429
454
  */
430
- interface ResolvedFilters {
431
- /** Include patterns */
432
- include?: string[];
433
- /** Exclude patterns */
434
- exclude?: string[];
435
- /** Source of the filters */
436
- source?: FilterSource;
437
- /** Whether filters were applied from config */
438
- fromConfig: boolean;
439
- /** Whether filters were applied from overrides */
440
- fromOverride: boolean;
441
- }
455
+ declare const DEFAULT_REPORT_DIR = ".doccov";
442
456
  /**
443
- * Parse a comma-separated list flag into an array.
444
- *
445
- * @param value - String or string array from CLI flag
446
- * @returns Parsed array, or undefined if empty
447
- *
448
- * @example
449
- * ```typescript
450
- * parseListFlag('a,b,c'); // ['a', 'b', 'c']
451
- * parseListFlag(['a,b', 'c']); // ['a', 'b', 'c']
452
- * parseListFlag(undefined); // undefined
453
- * ```
457
+ * Default path for cached DocCov reports.
454
458
  */
455
- declare function parseListFlag(value?: string | string[]): string[] | undefined;
459
+ declare const DEFAULT_REPORT_PATH = ".doccov/report.json";
456
460
  /**
457
- * Merge filter options from config and CLI/API overrides.
458
- *
459
- * Merge behavior:
460
- * - Include: CLI values intersect with config values (narrowing)
461
- * - Exclude: CLI values are added to config values (expanding)
461
+ * File extensions for each report format.
462
+ */
463
+ declare const REPORT_EXTENSIONS: Record<string, string>;
464
+ /**
465
+ * Get the default report path for a given format.
462
466
  *
463
- * @param config - Configuration (from doccov.config.ts)
464
- * @param overrides - Override filters (from CLI flags or API params)
465
- * @returns Merged filter options
467
+ * @param format - The report format (json, markdown, html, github)
468
+ * @param dir - The output directory (defaults to .doccov)
469
+ * @returns The full path to the report file
466
470
  *
467
471
  * @example
468
- * ```typescript
469
- * const config = { include: ['A', 'B', 'C'] };
470
- * const overrides = { include: ['B', 'C', 'D'] };
471
- *
472
- * const resolved = mergeFilters(config, overrides);
473
- * // resolved.include = ['B', 'C'] (intersection)
472
+ * ```ts
473
+ * getReportPath('markdown'); // '.doccov/report.md'
474
+ * getReportPath('html', 'reports'); // 'reports/report.html'
474
475
  * ```
475
476
  */
476
- declare function mergeFilters(config: DocCovConfig | null, overrides: FilterOptions): ResolvedFilters;
477
- import { SpecDocDrift as SpecDocDrift2, SpecExport as SpecExport2 } from "@openpkg-ts/spec";
478
- import * as TS from "typescript";
477
+ declare function getReportPath(format: string, dir?: string): string;
479
478
  /**
480
- * Represents a single parameter in a JSDoc patch
479
+ * Drift summary with category breakdown.
481
480
  */
482
- interface JSDocParam {
483
- name: string;
484
- type?: string;
485
- description?: string;
486
- optional?: boolean;
481
+ interface DriftReportSummary {
482
+ /**
483
+ * Total number of drift issues.
484
+ */
485
+ total: number;
486
+ /**
487
+ * Count of issues per category.
488
+ */
489
+ byCategory: Record<DriftCategory2, number>;
490
+ /**
491
+ * Number of auto-fixable issues.
492
+ */
493
+ fixable: number;
487
494
  }
488
495
  /**
489
- * Represents a return type in a JSDoc patch
496
+ * Drift report with progressive disclosure structure.
497
+ *
498
+ * Provides three levels of detail:
499
+ * 1. Summary - total counts by category
500
+ * 2. By category - grouped drift issues
501
+ * 3. All - flat list for backward compatibility
490
502
  */
491
- interface JSDocReturn {
492
- type?: string;
493
- description?: string;
503
+ interface DriftReport {
504
+ /**
505
+ * High-level summary counts.
506
+ */
507
+ summary: DriftReportSummary;
508
+ /**
509
+ * Issues grouped by category.
510
+ */
511
+ byCategory: Record<DriftCategory2, CategorizedDrift[]>;
512
+ /**
513
+ * Flat list of all drift issues (backward compatible).
514
+ */
515
+ all: CategorizedDrift[];
494
516
  }
495
517
  /**
496
- * Represents a generic tag in a JSDoc patch
518
+ * Coverage summary for an entire package or project.
497
519
  */
498
- interface JSDocTag {
499
- name: string;
500
- text: string;
520
+ interface CoverageSummary {
521
+ /**
522
+ * Overall coverage score (0-100).
523
+ */
524
+ score: number;
525
+ /**
526
+ * Total number of exports analyzed.
527
+ */
528
+ totalExports: number;
529
+ /**
530
+ * Number of fully documented exports.
531
+ */
532
+ documentedExports: number;
533
+ /**
534
+ * Breakdown of missing documentation by rule ID.
535
+ */
536
+ missingByRule: Record<string, number>;
537
+ /**
538
+ * Total number of drift issues detected.
539
+ */
540
+ driftCount: number;
541
+ /**
542
+ * Drift summary with category breakdown.
543
+ */
544
+ driftSummary?: DriftReportSummary;
501
545
  }
502
546
  /**
503
- * A patchable representation of a JSDoc comment
547
+ * Coverage data for a single export.
504
548
  */
505
- interface JSDocPatch {
506
- description?: string;
507
- params?: JSDocParam[];
508
- returns?: JSDocReturn;
509
- examples?: string[];
510
- deprecated?: string | false;
511
- async?: boolean;
512
- type?: string;
513
- typeParams?: Array<{
549
+ interface ExportCoverageData {
550
+ /**
551
+ * Export name.
552
+ */
553
+ name: string;
554
+ /**
555
+ * Export kind (function, class, etc.).
556
+ */
557
+ kind: string;
558
+ /**
559
+ * Coverage score for this (0-100).
560
+ */
561
+ coverageScore: number;
562
+ /**
563
+ * Missing documentation rule IDs.
564
+ */
565
+ missing?: string[];
566
+ /**
567
+ * Drift issues for this export.
568
+ */
569
+ drift?: SpecDocDrift3[];
570
+ }
571
+ /**
572
+ * DocCov report - a persistable coverage analysis result.
573
+ *
574
+ * This is the format saved to `.doccov/report.json` and returned
575
+ * by the `check` command with `--format json`.
576
+ */
577
+ interface DocCovReport {
578
+ /**
579
+ * JSON Schema reference for validation.
580
+ */
581
+ $schema: string;
582
+ /**
583
+ * Report format version.
584
+ */
585
+ version: string;
586
+ /**
587
+ * ISO 8601 timestamp when report was generated.
588
+ */
589
+ generatedAt: string;
590
+ /**
591
+ * Package/project metadata.
592
+ */
593
+ spec: {
514
594
  name: string;
515
- constraint?: string;
516
- description?: string;
517
- }>;
518
- otherTags?: JSDocTag[];
595
+ version?: string;
596
+ };
597
+ /**
598
+ * Aggregate coverage summary.
599
+ */
600
+ coverage: CoverageSummary;
601
+ /**
602
+ * Per-coverage data, keyed by ID.
603
+ */
604
+ exports: Record<string, ExportCoverageData>;
519
605
  }
520
606
  /**
521
- * Represents an edit to be applied to a source file
607
+ * Generate a DocCov report from an OpenPkg spec.
608
+ *
609
+ * @param spec - The pure OpenPkg spec to analyze
610
+ * @returns A DocCov report with coverage analysis
611
+ *
612
+ * @example
613
+ * ```ts
614
+ * import { DocCov, generateReport } from '@doccov/sdk';
615
+ *
616
+ * const doccov = new DocCov();
617
+ * const { spec } = await doccov.analyzeFileWithDiagnostics('src/index.ts');
618
+ * const report = generateReport(spec);
619
+ *
620
+ * console.log(`Coverage: ${report.coverage.score}%`);
621
+ * ```
522
622
  */
523
- interface JSDocEdit {
524
- filePath: string;
525
- symbolName: string;
526
- startLine: number;
527
- endLine: number;
528
- hasExisting: boolean;
529
- existingJSDoc?: string;
530
- newJSDoc: string;
531
- indent: string;
623
+ declare function generateReport(spec: OpenPkg3): DocCovReport;
624
+ /**
625
+ * Generate a DocCov report from an already-enriched spec.
626
+ *
627
+ * Use this when you've already called enrichSpec() and want to avoid
628
+ * recomputing coverage data.
629
+ *
630
+ * @param enriched - The enriched OpenPkg spec
631
+ * @returns A DocCov report with coverage analysis
632
+ */
633
+ declare function generateReportFromEnriched(enriched: EnrichedOpenPkg): DocCovReport;
634
+ /**
635
+ * Load a cached DocCov report from disk.
636
+ *
637
+ * @param reportPath - Path to the report file (defaults to .doccov/report.json)
638
+ * @returns The cached report, or null if not found
639
+ */
640
+ declare function loadCachedReport(reportPath?: string): DocCovReport | null;
641
+ /**
642
+ * Save a DocCov report to disk.
643
+ *
644
+ * @param report - The report to save
645
+ * @param reportPath - Path to save the report (defaults to .doccov/report.json)
646
+ */
647
+ declare function saveReport(report: DocCovReport, reportPath?: string): void;
648
+ /**
649
+ * Check if a cached report is still valid.
650
+ *
651
+ * A report is considered stale if:
652
+ * - It doesn't exist
653
+ * - The spec version has changed
654
+ * - Source files have been modified since generation
655
+ *
656
+ * @param reportPath - Path to the report file
657
+ * @param sourceFiles - Source files to check modification times against
658
+ * @returns True if the cached report is still valid
659
+ */
660
+ declare function isCachedReportValid(reportPath?: string, sourceFiles?: string[]): boolean;
661
+ /**
662
+ * Compute a hash of file contents.
663
+ * Uses truncated SHA-256 for balance of speed and collision resistance.
664
+ *
665
+ * @param filePath - Absolute path to the file
666
+ * @returns 16-character hex hash, or null if file doesn't exist
667
+ */
668
+ declare function hashFile(filePath: string): string | null;
669
+ /**
670
+ * Hash a string value.
671
+ *
672
+ * @param content - String to hash
673
+ * @returns 16-character hex hash
674
+ */
675
+ declare function hashString(content: string): string;
676
+ /**
677
+ * Hash multiple files and return a map of relative paths to hashes.
678
+ *
679
+ * @param filePaths - Array of absolute file paths
680
+ * @param cwd - Base directory for relative path calculation
681
+ * @returns Map of relative paths to their content hashes
682
+ */
683
+ declare function hashFiles(filePaths: string[], cwd: string): Record<string, string>;
684
+ /**
685
+ * Compare two hash maps and return changed files.
686
+ *
687
+ * @param cached - Hash map from cache
688
+ * @param current - Current hash map
689
+ * @returns Array of file paths that changed, were added, or were removed
690
+ */
691
+ declare function diffHashes(cached: Record<string, string>, current: Record<string, string>): string[];
692
+ import { OpenPkg as OpenPkg4 } from "@openpkg-ts/spec";
693
+ /** Current cache format version */
694
+ declare const CACHE_VERSION = "1.0.0";
695
+ /** Default cache file path */
696
+ declare const SPEC_CACHE_FILE = ".doccov/spec.cache.json";
697
+ /**
698
+ * Configuration that affects spec generation output.
699
+ */
700
+ interface SpecCacheConfig {
701
+ resolveExternalTypes: boolean;
532
702
  }
533
703
  /**
534
- * Result of applying edits to source files
704
+ * Cached spec with validation metadata.
535
705
  */
536
- interface ApplyEditsResult {
537
- filesModified: number;
538
- editsApplied: number;
539
- errors: Array<{
540
- file: string;
541
- error: string;
542
- }>;
706
+ interface SpecCache {
707
+ /** Cache format version for migrations */
708
+ cacheVersion: string;
709
+ /** When cache was generated (ISO timestamp) */
710
+ generatedAt: string;
711
+ /** OpenPkg spec version (e.g., "0.3.0") */
712
+ specVersion: string;
713
+ /** Entry file that was analyzed (relative path) */
714
+ entryFile: string;
715
+ /** Hash validation data */
716
+ hashes: {
717
+ /** Hash of tsconfig.json content (null if not found) */
718
+ tsconfig: string | null;
719
+ /** Hash of package.json content */
720
+ packageJson: string;
721
+ /** Source file hashes: relative filepath → content hash */
722
+ sourceFiles: Record<string, string>;
723
+ };
724
+ /** Analysis configuration that affects output */
725
+ config: SpecCacheConfig;
726
+ /** The cached OpenPkg spec */
727
+ spec: OpenPkg4;
543
728
  }
544
729
  /**
545
- * Parse a JSDoc comment string into a patchable structure
730
+ * Result of cache validation.
546
731
  */
547
- declare function parseJSDocToPatch(jsDocText: string): JSDocPatch;
732
+ interface CacheValidationResult {
733
+ /** Whether the cache is valid */
734
+ valid: boolean;
735
+ /** Reason for invalidation (if invalid) */
736
+ reason?: "cache-version-mismatch" | "entry-file-changed" | "config-changed" | "tsconfig-changed" | "package-json-changed" | "source-files-changed";
737
+ /** Files that changed (if reason is source-files-changed) */
738
+ changedFiles?: string[];
739
+ }
548
740
  /**
549
- * Apply a partial patch to an existing JSDoc patch, preserving unmodified content
741
+ * Context needed for cache operations.
550
742
  */
551
- declare function applyPatchToJSDoc(existing: JSDocPatch, updates: Partial<JSDocPatch>): JSDocPatch;
743
+ interface CacheContext {
744
+ /** Entry file being analyzed (absolute path) */
745
+ entryFile: string;
746
+ /** Source files included in analysis (absolute paths) */
747
+ sourceFiles: string[];
748
+ /** Path to tsconfig.json (absolute, or null if not found) */
749
+ tsconfigPath: string | null;
750
+ /** Path to package.json (absolute) */
751
+ packageJsonPath: string;
752
+ /** Configuration that affects output */
753
+ config: SpecCacheConfig;
754
+ /** Working directory */
755
+ cwd: string;
756
+ }
552
757
  /**
553
- * Serialize a JSDocPatch back to a formatted comment string
758
+ * Load cached spec from disk.
759
+ *
760
+ * @param cwd - Working directory
761
+ * @returns Cached spec, or null if not found or invalid JSON
554
762
  */
555
- declare function serializeJSDoc(patch: JSDocPatch, indent?: string): string;
763
+ declare function loadSpecCache(cwd: string): SpecCache | null;
556
764
  /**
557
- * Find the JSDoc location for a declaration in a source file
765
+ * Save spec to cache.
766
+ *
767
+ * @param spec - OpenPkg spec to cache
768
+ * @param context - Cache context with file paths and config
558
769
  */
559
- declare function findJSDocLocation(sourceFile: TS.SourceFile, symbolName: string, approximateLine?: number): {
560
- startLine: number;
561
- endLine: number;
562
- declarationLine: number;
563
- hasExisting: boolean;
564
- existingJSDoc?: string;
565
- indent: string;
566
- } | null;
770
+ declare function saveSpecCache(spec: OpenPkg4, context: CacheContext): void;
567
771
  /**
568
- * Apply a batch of edits to source files
772
+ * Validate if cached spec is still valid.
773
+ *
774
+ * Checks:
775
+ * 1. Cache version matches
776
+ * 2. Entry file matches
777
+ * 3. Config matches
778
+ * 4. tsconfig.json hash matches
779
+ * 5. package.json hash matches
780
+ * 6. All source file hashes match
781
+ *
782
+ * @param cache - Cached spec to validate
783
+ * @param context - Current cache context
784
+ * @returns Validation result
569
785
  */
570
- declare function applyEdits(edits: JSDocEdit[]): Promise<ApplyEditsResult>;
786
+ declare function validateSpecCache(cache: SpecCache, context: CacheContext): CacheValidationResult;
571
787
  /**
572
- * Create a TypeScript source file from a file path
788
+ * Clear the spec cache.
789
+ *
790
+ * @param cwd - Working directory
791
+ * @returns True if cache was deleted, false if it didn't exist
573
792
  */
574
- declare function createSourceFile(filePath: string): TS.SourceFile;
793
+ declare function clearSpecCache(cwd: string): boolean;
575
794
  /**
576
- * Types of fixes that can be generated
795
+ * Get cache file path for a given working directory.
796
+ *
797
+ * @param cwd - Working directory
798
+ * @returns Absolute path to cache file
577
799
  */
578
- type FixType = "add-param" | "remove-param" | "update-param-type" | "update-param-optionality" | "update-return-type" | "update-assertion" | "add-template" | "update-template-constraint" | "add-deprecated" | "remove-deprecated" | "add-async" | "remove-async" | "update-property-type";
800
+ declare function getSpecCachePath(cwd: string): string;
579
801
  /**
580
- * A fix suggestion with the patch to apply
802
+ * Configuration types for DocCov.
803
+ * These types are shared between CLI and API.
581
804
  */
582
- interface FixSuggestion {
583
- type: FixType;
584
- driftType: SpecDocDrift2["type"];
585
- target: string;
586
- description: string;
587
- patch: Partial<JSDocPatch>;
805
+ /**
806
+ * Documentation configuration options.
807
+ */
808
+ interface DocsConfig {
809
+ /** Glob patterns for markdown docs to include */
810
+ include?: string[];
811
+ /** Glob patterns for markdown docs to exclude */
812
+ exclude?: string[];
813
+ }
814
+ /**
815
+ * Example validation modes.
816
+ */
817
+ type ExampleValidationMode = "presence" | "typecheck" | "run";
818
+ /**
819
+ * Check command configuration options.
820
+ */
821
+ interface CheckConfig {
822
+ /**
823
+ * Example validation modes to run.
824
+ * Can be a single mode, array of modes, or comma-separated string.
825
+ * - 'presence': Check that @example blocks exist on exports
826
+ * - 'typecheck': Compile examples with TypeScript
827
+ * - 'run': Execute examples and validate assertions
828
+ */
829
+ examples?: ExampleValidationMode | ExampleValidationMode[] | string;
830
+ /** Minimum coverage percentage required (0-100) */
831
+ minCoverage?: number;
832
+ /** Maximum drift percentage allowed (0-100) */
833
+ maxDrift?: number;
834
+ }
835
+ /**
836
+ * Quality rule severity level.
837
+ */
838
+ type QualitySeverity2 = "error" | "warn" | "off";
839
+ /**
840
+ * Quality rules configuration.
841
+ */
842
+ interface QualityRulesConfig {
843
+ /** Rule severity overrides */
844
+ rules?: Record<string, QualitySeverity2>;
845
+ }
846
+ /**
847
+ * Normalized DocCov configuration.
848
+ * This is the parsed/normalized form used by commands.
849
+ */
850
+ interface DocCovConfig {
851
+ /** Export include patterns */
852
+ include?: string[];
853
+ /** Export exclude patterns */
854
+ exclude?: string[];
855
+ /** Plugins (future) */
856
+ plugins?: unknown[];
857
+ /** Documentation configuration */
858
+ docs?: DocsConfig;
859
+ /** Check command configuration */
860
+ check?: CheckConfig;
861
+ /** Quality rules configuration */
862
+ quality?: QualityRulesConfig;
863
+ }
864
+ /**
865
+ * Define a DocCov configuration.
866
+ * Helper function for type-safe configuration in doccov.config.ts.
867
+ *
868
+ * @param config - Configuration object
869
+ * @returns The configuration object (for type inference)
870
+ *
871
+ * @example
872
+ * ```typescript
873
+ * // doccov.config.ts
874
+ * import { defineConfig } from '@doccov/sdk';
875
+ *
876
+ * defineConfig({
877
+ * include: ['MyClass', 'myFunction'],
878
+ * exclude: ['internal*'],
879
+ * docs: {
880
+ * include: ['docs/**\/*.md'],
881
+ * },
882
+ * quality: {
883
+ * rules: {
884
+ * 'has-description': 'error',
885
+ * 'has-examples': 'warn',
886
+ * },
887
+ * },
888
+ * });
889
+ * ```
890
+ */
891
+ declare function defineConfig(config: DocCovConfig): DocCovConfig;
892
+ /**
893
+ * Project detection types for I/O-agnostic project analysis.
894
+ * Used by both CLI (NodeFileSystem) and API (SandboxFileSystem).
895
+ */
896
+ /**
897
+ * Minimal filesystem interface for I/O-agnostic detection.
898
+ * Implementations: NodeFileSystem (CLI), SandboxFileSystem (API)
899
+ */
900
+ interface FileSystem {
901
+ /** Check if a file or directory exists */
902
+ exists(path: string): Promise<boolean>;
903
+ /** Read file contents as string */
904
+ readFile(path: string): Promise<string>;
905
+ /** List directory contents (file/folder names only) */
906
+ readDir(path: string): Promise<string[]>;
907
+ /** Check if path is a directory */
908
+ isDirectory(path: string): Promise<boolean>;
909
+ }
910
+ /** Supported package managers */
911
+ type PackageManager = "npm" | "yarn" | "pnpm" | "bun";
912
+ /** Package manager detection result with install/run commands */
913
+ interface PackageManagerInfo {
914
+ /** Package manager name */
915
+ name: PackageManager;
916
+ /** Lockfile that was detected (null if none found) */
917
+ lockfile: string | null;
918
+ /** Arguments for install command, e.g. ['install', '--frozen-lockfile'] */
919
+ installArgs: string[];
920
+ /** Prefix for running scripts, e.g. ['npm', 'run'] or ['pnpm'] */
921
+ runPrefix: string[];
922
+ }
923
+ /** Monorepo type based on configuration */
924
+ type MonorepoType = "npm-workspaces" | "pnpm-workspaces" | "lerna" | "none";
925
+ /** Monorepo detection result */
926
+ interface MonorepoInfo {
927
+ /** Whether this is a monorepo */
928
+ isMonorepo: boolean;
929
+ /** Type of monorepo configuration */
930
+ type: MonorepoType;
931
+ /** Workspace patterns from config (e.g. ['packages/*']) */
932
+ patterns: string[];
933
+ /** Resolved workspace packages */
934
+ packages: WorkspacePackage[];
935
+ }
936
+ /** A package within a monorepo workspace */
937
+ interface WorkspacePackage {
938
+ /** Package name from package.json */
939
+ name: string;
940
+ /** Relative path to package directory */
941
+ path: string;
942
+ /** Whether the package is marked as private */
943
+ private: boolean;
944
+ }
945
+ /** Entry point source - where the entry was detected from */
946
+ type EntryPointSource = "types" | "exports" | "main" | "module" | "fallback";
947
+ /** Entry point detection result */
948
+ interface EntryPointInfo {
949
+ /** Path to entry file (relative to package root) */
950
+ path: string;
951
+ /** Where the entry point was detected from */
952
+ source: EntryPointSource;
953
+ /** Whether this is a .d.ts file (no source available) */
954
+ isDeclarationOnly: boolean;
955
+ }
956
+ /** Build configuration detection result */
957
+ interface BuildInfo {
958
+ /** Build-related script names found (e.g. ['build', 'build:types']) */
959
+ scripts: string[];
960
+ /** Whether any build script was found */
961
+ hasBuildScript: boolean;
962
+ /** Whether TypeScript is configured/installed */
963
+ hasTypeScript: boolean;
964
+ /** Indicators for exotic project types */
965
+ exoticIndicators: {
966
+ /** WASM project (Cargo.toml or wasm-pack scripts) */
967
+ wasm: boolean;
968
+ /** napi-rs native addon project */
969
+ napi: boolean;
970
+ };
971
+ }
972
+ /** Complete project analysis result */
973
+ interface ProjectInfo {
974
+ /** Package manager info */
975
+ packageManager: PackageManagerInfo;
976
+ /** Monorepo info */
977
+ monorepo: MonorepoInfo;
978
+ /** Entry point info */
979
+ entryPoint: EntryPointInfo;
980
+ /** Build info */
981
+ build: BuildInfo;
982
+ }
983
+ /** Options for analyzeProject() */
984
+ interface AnalyzeProjectOptions {
985
+ /** Target package name for monorepos */
986
+ targetPackage?: string;
987
+ }
988
+ /**
989
+ * Detect build configuration and exotic project indicators.
990
+ *
991
+ * @param fs - FileSystem implementation
992
+ * @param packagePath - Path to package directory (default: ".")
993
+ * @returns Build info including scripts and exotic indicators
994
+ */
995
+ declare function detectBuildInfo(fs: FileSystem, packagePath?: string): Promise<BuildInfo>;
996
+ /**
997
+ * Get the primary build script name to run.
998
+ * Prefers 'build' over 'compile' over 'tsc'.
999
+ */
1000
+ declare function getPrimaryBuildScript(buildInfo: BuildInfo): string | null;
1001
+ /**
1002
+ * Detect the TypeScript entry point for a package.
1003
+ *
1004
+ * Priority order:
1005
+ * 1. package.json -> types or typings field
1006
+ * 2. package.json -> exports["."].types
1007
+ * 3. package.json -> main field (resolve to .ts)
1008
+ * 4. package.json -> module field (resolve to .ts)
1009
+ * 5. Common fallback paths
1010
+ *
1011
+ * @param fs - FileSystem implementation
1012
+ * @param packagePath - Path to package directory (default: ".")
1013
+ * @returns Entry point info
1014
+ * @throws Error if no entry point can be found
1015
+ */
1016
+ declare function detectEntryPoint(fs: FileSystem, packagePath?: string): Promise<EntryPointInfo>;
1017
+ import { Sandbox } from "@vercel/sandbox";
1018
+ /**
1019
+ * Node.js filesystem implementation for CLI usage.
1020
+ * Wraps Node.js fs module with a base path.
1021
+ */
1022
+ declare class NodeFileSystem implements FileSystem {
1023
+ private basePath;
1024
+ constructor(basePath: string);
1025
+ private resolve;
1026
+ exists(relativePath: string): Promise<boolean>;
1027
+ readFile(relativePath: string): Promise<string>;
1028
+ readDir(relativePath: string): Promise<string[]>;
1029
+ isDirectory(relativePath: string): Promise<boolean>;
1030
+ }
1031
+ /**
1032
+ * Vercel Sandbox filesystem implementation for API usage.
1033
+ * Uses sandbox.runCommand() with shell commands.
1034
+ */
1035
+ declare class SandboxFileSystem implements FileSystem {
1036
+ private sandbox;
1037
+ constructor(sandbox: Sandbox);
1038
+ exists(path: string): Promise<boolean>;
1039
+ readFile(path: string): Promise<string>;
1040
+ readDir(path: string): Promise<string[]>;
1041
+ isDirectory(path: string): Promise<boolean>;
1042
+ }
1043
+ /**
1044
+ * Detect if a project is a monorepo and list its packages.
1045
+ *
1046
+ * Detection triggers (in order):
1047
+ * 1. package.json has workspaces field (npm/yarn)
1048
+ * 2. pnpm-workspace.yaml exists
1049
+ * 3. lerna.json exists
1050
+ */
1051
+ declare function detectMonorepo(fs: FileSystem): Promise<MonorepoInfo>;
1052
+ /**
1053
+ * Find a package by name or path in a list of workspace packages.
1054
+ */
1055
+ declare function findPackageByName(packages: WorkspacePackage[], nameOrPath: string): WorkspacePackage | undefined;
1056
+ /**
1057
+ * Format package list for display in error messages.
1058
+ */
1059
+ declare function formatPackageList(packages: WorkspacePackage[], limit?: number): string;
1060
+ /**
1061
+ * Detect package manager based on lockfile presence and package.json hints.
1062
+ *
1063
+ * Resolution order:
1064
+ * 1. packageManager field in package.json (e.g., "pnpm@9.0.0")
1065
+ * 2. Most recently modified lockfile (when multiple exist)
1066
+ * 3. Static priority order: pnpm > bun > yarn > npm
1067
+ * 4. Default to npm
1068
+ */
1069
+ declare function detectPackageManager(fs: FileSystem): Promise<PackageManagerInfo>;
1070
+ /**
1071
+ * Get install command for a package manager.
1072
+ * Returns [command, ...args] array.
1073
+ */
1074
+ declare function getInstallCommand(pm: PackageManagerInfo): string[];
1075
+ /**
1076
+ * Get run command for a package manager script.
1077
+ * Returns [command, ...args, scriptName] array.
1078
+ */
1079
+ declare function getRunCommand(pm: PackageManagerInfo, script: string): string[];
1080
+ /**
1081
+ * Safely parse a JSON file, returning null on any error.
1082
+ */
1083
+ declare function safeParseJson<T = Record<string, unknown>>(fs: FileSystem, path: string): Promise<T | null>;
1084
+ /**
1085
+ * Standard package.json structure for detection purposes.
1086
+ */
1087
+ interface PackageJson {
1088
+ name?: string;
1089
+ version?: string;
1090
+ private?: boolean;
1091
+ main?: string;
1092
+ module?: string;
1093
+ types?: string;
1094
+ typings?: string;
1095
+ exports?: PackageExports;
1096
+ workspaces?: string[] | {
1097
+ packages: string[];
1098
+ };
1099
+ scripts?: Record<string, string>;
1100
+ dependencies?: Record<string, string>;
1101
+ devDependencies?: Record<string, string>;
1102
+ }
1103
+ /**
1104
+ * Package.json exports field structure.
1105
+ */
1106
+ type PackageExports = string | {
1107
+ "."?: string | {
1108
+ types?: string;
1109
+ import?: string;
1110
+ require?: string;
1111
+ default?: string;
1112
+ };
1113
+ [key: string]: unknown;
1114
+ };
1115
+ /**
1116
+ * Read and parse package.json from a directory.
1117
+ */
1118
+ declare function readPackageJson(fs: FileSystem, dir: string): Promise<PackageJson | null>;
1119
+ /**
1120
+ * Analyze a project's structure for scanning.
1121
+ *
1122
+ * This is the main entry point for project detection. It combines all
1123
+ * detection functions into a single call that returns complete project info.
1124
+ *
1125
+ * For monorepos, you must specify the target package via options.targetPackage.
1126
+ * If not specified and a monorepo is detected, an error is thrown with the
1127
+ * list of available packages.
1128
+ *
1129
+ * @param fs - FileSystem implementation (NodeFileSystem or SandboxFileSystem)
1130
+ * @param options - Options including targetPackage for monorepos
1131
+ * @returns Complete project info
1132
+ * @throws Error if monorepo detected without targetPackage specified
1133
+ * @throws Error if targetPackage not found in monorepo
1134
+ *
1135
+ * @example
1136
+ * ```typescript
1137
+ * import { NodeFileSystem, analyzeProject } from '@doccov/sdk';
1138
+ *
1139
+ * // Single package
1140
+ * const singleFs = new NodeFileSystem('/path/to/package');
1141
+ * const singleProject = await analyzeProject(singleFs);
1142
+ *
1143
+ * // Monorepo with target package
1144
+ * const monoFs = new NodeFileSystem('/path/to/monorepo');
1145
+ * const monoProject = await analyzeProject(monoFs, { targetPackage: '@scope/core' });
1146
+ * ```
1147
+ */
1148
+ declare function analyzeProject2(fs: FileSystem, options?: AnalyzeProjectOptions): Promise<ProjectInfo>;
1149
+ /**
1150
+ * Example validation types and utilities.
1151
+ */
1152
+ /**
1153
+ * Individual example validations that can be run.
1154
+ */
1155
+ type ExampleValidation = "presence" | "typecheck" | "run";
1156
+ /**
1157
+ * All validations (used when --examples is passed without values).
1158
+ */
1159
+ declare const ALL_VALIDATIONS: ExampleValidation[];
1160
+ /**
1161
+ * Describes what each validation does.
1162
+ */
1163
+ declare const VALIDATION_INFO: Record<ExampleValidation, {
1164
+ label: string;
1165
+ description: string;
1166
+ }>;
1167
+ /**
1168
+ * Parse --examples flag value into validation set.
1169
+ *
1170
+ * @example
1171
+ * parseExamplesFlag(true) // ['presence', 'typecheck', 'run']
1172
+ * parseExamplesFlag('presence') // ['presence']
1173
+ * parseExamplesFlag('typecheck,run') // ['typecheck', 'run']
1174
+ * parseExamplesFlag(undefined) // [] (no validation)
1175
+ */
1176
+ declare function parseExamplesFlag(value: boolean | string | undefined): ExampleValidation[];
1177
+ /**
1178
+ * Check if a specific validation is enabled.
1179
+ */
1180
+ declare function shouldValidate(validations: ExampleValidation[], check: ExampleValidation): boolean;
1181
+ import { SpecExport as SpecExport4 } from "@openpkg-ts/spec";
1182
+ interface ExampleTypeError {
1183
+ /** Index of the example in the examples array */
1184
+ exampleIndex: number;
1185
+ /** Line number within the example (1-based) */
1186
+ line: number;
1187
+ /** Column number (1-based) */
1188
+ column: number;
1189
+ /** Error message from TypeScript */
1190
+ message: string;
1191
+ /** TypeScript diagnostic code */
1192
+ code: number;
1193
+ }
1194
+ interface TypecheckResult {
1195
+ /** All type errors found across examples */
1196
+ errors: ExampleTypeError[];
1197
+ /** Number of examples that passed */
1198
+ passed: number;
1199
+ /** Number of examples that failed */
1200
+ failed: number;
1201
+ }
1202
+ interface TypecheckOptions {
1203
+ /** Path to tsconfig.json (auto-detected if not provided) */
1204
+ tsconfig?: string;
1205
+ /** Package name for imports (auto-detected from package.json if not provided) */
1206
+ packageName?: string;
1207
+ /** Export names to include in the virtual import statement */
1208
+ exportNames?: string[];
1209
+ }
1210
+ /**
1211
+ * Options for example validation.
1212
+ */
1213
+ interface ExampleValidationOptions {
1214
+ /** Which validations to run */
1215
+ validations: ExampleValidation[];
1216
+ /** Path to the package being validated */
1217
+ packagePath: string;
1218
+ /** Package name (for import resolution) */
1219
+ packageName?: string;
1220
+ /** All names (for import statements in typecheck) */
1221
+ exportNames?: string[];
1222
+ /** Timeout for runtime execution (ms) */
1223
+ timeout?: number;
1224
+ /** Timeout for package installation (ms) */
1225
+ installTimeout?: number;
1226
+ /** Callback for LLM assertion parsing fallback */
1227
+ llmAssertionParser?: (example: string) => Promise<{
1228
+ hasAssertions: boolean;
1229
+ assertions: LLMAssertion[];
1230
+ } | null>;
1231
+ }
1232
+ /**
1233
+ * LLM-parsed assertion from non-standard comment syntax.
1234
+ */
1235
+ interface LLMAssertion {
1236
+ expected: string;
1237
+ suggestedSyntax: string;
1238
+ }
1239
+ /**
1240
+ * Result of a single example type error.
1241
+ */
1242
+ interface ExampleValidationTypeError {
1243
+ exportName: string;
1244
+ exampleIndex: number;
1245
+ error: ExampleTypeError;
1246
+ }
1247
+ /**
1248
+ * Result of example presence validation.
1249
+ */
1250
+ interface PresenceResult {
1251
+ total: number;
1252
+ withExamples: number;
1253
+ missing: string[];
1254
+ }
1255
+ /**
1256
+ * Result of example typecheck validation.
1257
+ */
1258
+ interface TypecheckValidationResult {
1259
+ passed: number;
1260
+ failed: number;
1261
+ errors: ExampleValidationTypeError[];
1262
+ }
1263
+ /**
1264
+ * Runtime drift issue (runtime error or assertion failure).
1265
+ */
1266
+ interface RuntimeDrift {
1267
+ exportName: string;
1268
+ issue: string;
1269
+ suggestion?: string;
1270
+ }
1271
+ /**
1272
+ * Result of example runtime validation.
1273
+ */
1274
+ interface RunValidationResult {
1275
+ passed: number;
1276
+ failed: number;
1277
+ drifts: RuntimeDrift[];
1278
+ installSuccess: boolean;
1279
+ installError?: string;
1280
+ }
1281
+ /**
1282
+ * Unified result from example validation.
1283
+ */
1284
+ interface ExampleValidationResult {
1285
+ /** Which validations were run */
1286
+ validations: ExampleValidation[];
1287
+ /** Presence validation results (if run) */
1288
+ presence?: PresenceResult;
1289
+ /** Typecheck validation results (if run) */
1290
+ typecheck?: TypecheckValidationResult;
1291
+ /** Runtime validation results (if run) */
1292
+ run?: RunValidationResult;
1293
+ /** Total number of issues found */
1294
+ totalIssues: number;
1295
+ }
1296
+ /**
1297
+ * Validate examples across exports.
1298
+ *
1299
+ * Runs only the validations specified. Each validation is independent:
1300
+ * - `presence`: checks examples exist (doesn't require typecheck or run)
1301
+ * - `typecheck`: type-checks examples (doesn't require presence or run)
1302
+ * - `run`: executes examples (doesn't require presence or typecheck)
1303
+ */
1304
+ declare function validateExamples(exports: SpecExport4[], options: ExampleValidationOptions): Promise<ExampleValidationResult>;
1305
+ interface DocCovOptions {
1306
+ includePrivate?: boolean;
1307
+ followImports?: boolean;
1308
+ maxDepth?: number;
1309
+ resolveExternalTypes?: boolean;
1310
+ /** Enable spec caching (default: true) */
1311
+ useCache?: boolean;
1312
+ /** Working directory for cache operations (default: process.cwd()) */
1313
+ cwd?: string;
1314
+ }
1315
+ /** @deprecated Use DocCovOptions instead */
1316
+ type OpenPkgOptions = DocCovOptions;
1317
+ declare function extractPackageSpec(entryFile: string, packageDir?: string, content?: string, options?: OpenPkgOptions): Promise<OpenPkgSpec>;
1318
+ interface FilterOptions {
1319
+ include?: string[];
1320
+ exclude?: string[];
1321
+ }
1322
+ /**
1323
+ * Source of filter options.
1324
+ */
1325
+ type FilterSource = "config" | "override" | "combined";
1326
+ /**
1327
+ * Resolved filter options after merging config and overrides.
1328
+ */
1329
+ interface ResolvedFilters {
1330
+ /** Include patterns */
1331
+ include?: string[];
1332
+ /** Exclude patterns */
1333
+ exclude?: string[];
1334
+ /** Source of the filters */
1335
+ source?: FilterSource;
1336
+ /** Whether filters were applied from config */
1337
+ fromConfig: boolean;
1338
+ /** Whether filters were applied from overrides */
1339
+ fromOverride: boolean;
1340
+ }
1341
+ /**
1342
+ * Parse a comma-separated list flag into an array.
1343
+ *
1344
+ * @param value - String or string array from CLI flag
1345
+ * @returns Parsed array, or undefined if empty
1346
+ *
1347
+ * @example
1348
+ * ```typescript
1349
+ * parseListFlag('a,b,c'); // ['a', 'b', 'c']
1350
+ * parseListFlag(['a,b', 'c']); // ['a', 'b', 'c']
1351
+ * parseListFlag(undefined); // undefined
1352
+ * ```
1353
+ */
1354
+ declare function parseListFlag(value?: string | string[]): string[] | undefined;
1355
+ /**
1356
+ * Merge filter options from config and CLI/API overrides.
1357
+ *
1358
+ * Merge behavior:
1359
+ * - Include: CLI values intersect with config values (narrowing)
1360
+ * - Exclude: CLI values are added to config values (expanding)
1361
+ *
1362
+ * @param config - Configuration (from doccov.config.ts)
1363
+ * @param overrides - Override filters (from CLI flags or API params)
1364
+ * @returns Merged filter options
1365
+ *
1366
+ * @example
1367
+ * ```typescript
1368
+ * const config = { include: ['A', 'B', 'C'] };
1369
+ * const overrides = { include: ['B', 'C', 'D'] };
1370
+ *
1371
+ * const resolved = mergeFilters(config, overrides);
1372
+ * // resolved.include = ['B', 'C'] (intersection)
1373
+ * ```
1374
+ */
1375
+ declare function mergeFilters(config: DocCovConfig | null, overrides: FilterOptions): ResolvedFilters;
1376
+ import { SpecDocDrift as SpecDocDrift4, SpecExport as SpecExport5 } from "@openpkg-ts/spec";
1377
+ /**
1378
+ * Types of fixes that can be generated
1379
+ */
1380
+ type FixType = "add-param" | "remove-param" | "update-param-type" | "update-param-optionality" | "update-return-type" | "update-assertion" | "add-template" | "update-template-constraint" | "add-deprecated" | "remove-deprecated" | "add-async" | "remove-async" | "update-property-type";
1381
+ /**
1382
+ * A fix suggestion with the patch to apply
1383
+ */
1384
+ interface FixSuggestion {
1385
+ type: FixType;
1386
+ driftType: SpecDocDrift4["type"];
1387
+ target: string;
1388
+ description: string;
1389
+ patch: Partial<JSDocPatch>;
1390
+ }
1391
+ /**
1392
+ * Check if a drift type can be fixed deterministically
1393
+ */
1394
+ declare function isFixableDrift(drift: SpecDocDrift4): boolean;
1395
+ /**
1396
+ * Generate a fix for a single drift issue
1397
+ */
1398
+ declare function generateFix(drift: SpecDocDrift4, exportEntry: SpecExport5, existingPatch?: JSDocPatch): FixSuggestion | null;
1399
+ /**
1400
+ * Generate all fixes for an export's drift issues
1401
+ */
1402
+ declare function generateFixesForExport(exportEntry: SpecExport5, existingPatch?: JSDocPatch): FixSuggestion[];
1403
+ /**
1404
+ * Merge multiple fix patches into a single patch
1405
+ */
1406
+ declare function mergeFixes(fixes: FixSuggestion[], basePatch?: JSDocPatch): JSDocPatch;
1407
+ /**
1408
+ * Get a summary of fixable vs non-fixable drifts
1409
+ */
1410
+ declare function categorizeDrifts(drifts: SpecDocDrift4[]): {
1411
+ fixable: SpecDocDrift4[];
1412
+ nonFixable: SpecDocDrift4[];
1413
+ };
1414
+ import { OpenPkg as OpenPkg5 } from "@openpkg-ts/spec";
1415
+ /**
1416
+ * Parsed components of a GitHub URL.
1417
+ */
1418
+ interface ParsedGitHubUrl {
1419
+ /** Repository owner (user or org) */
1420
+ owner: string;
1421
+ /** Repository name */
1422
+ repo: string;
1423
+ /** Git ref (branch or tag) */
1424
+ ref: string;
1425
+ }
1426
+ /**
1427
+ * Parse a GitHub URL or shorthand into components.
1428
+ *
1429
+ * Supported formats:
1430
+ * - https://github.com/owner/repo
1431
+ * - https://github.com/owner/repo/tree/branch
1432
+ * - https://github.com/owner/repo/tree/v1.0.0
1433
+ * - github.com/owner/repo
1434
+ * - owner/repo (shorthand)
1435
+ * - git@github.com:owner/repo.git
1436
+ *
1437
+ * @param input - GitHub URL or shorthand
1438
+ * @param defaultRef - Default ref if not specified in URL (default: 'main')
1439
+ * @returns Parsed components
1440
+ * @throws Error if the URL format is invalid
1441
+ *
1442
+ * @example
1443
+ * ```typescript
1444
+ * import { parseGitHubUrl } from '@doccov/sdk';
1445
+ *
1446
+ * const parsed = parseGitHubUrl('https://github.com/vercel/next.js/tree/canary');
1447
+ * // { owner: 'vercel', repo: 'next.js', ref: 'canary' }
1448
+ *
1449
+ * const shorthand = parseGitHubUrl('vercel/next.js');
1450
+ * // { owner: 'vercel', repo: 'next.js', ref: 'main' }
1451
+ * ```
1452
+ */
1453
+ declare function parseGitHubUrl(input: string, defaultRef?: string): ParsedGitHubUrl;
1454
+ /**
1455
+ * Build a clone URL from parsed components.
1456
+ *
1457
+ * @param parsed - Parsed GitHub URL components
1458
+ * @returns HTTPS clone URL
1459
+ *
1460
+ * @example
1461
+ * ```typescript
1462
+ * const cloneUrl = buildCloneUrl({ owner: 'vercel', repo: 'next.js', ref: 'main' });
1463
+ * // 'https://github.com/vercel/next.js.git'
1464
+ * ```
1465
+ */
1466
+ declare function buildCloneUrl(parsed: ParsedGitHubUrl): string;
1467
+ /**
1468
+ * Build a display-friendly URL (without protocol or .git suffix).
1469
+ *
1470
+ * @param parsed - Parsed GitHub URL components
1471
+ * @returns Display URL like 'github.com/owner/repo'
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * const displayUrl = buildDisplayUrl({ owner: 'vercel', repo: 'next.js', ref: 'main' });
1476
+ * // 'github.com/vercel/next.js'
1477
+ * ```
1478
+ */
1479
+ declare function buildDisplayUrl(parsed: ParsedGitHubUrl): string;
1480
+ /**
1481
+ * Build a raw.githubusercontent.com URL for a file.
1482
+ *
1483
+ * @param parsed - Parsed GitHub URL components
1484
+ * @param filePath - Path to the file in the repo
1485
+ * @returns Raw content URL
1486
+ */
1487
+ declare function buildRawUrl(parsed: ParsedGitHubUrl, filePath: string): string;
1488
+ /**
1489
+ * Fetch an OpenPkg spec from a GitHub repository.
1490
+ *
1491
+ * Tries the specified ref first, then falls back to 'master' if not found.
1492
+ *
1493
+ * @param parsed - Parsed GitHub URL components
1494
+ * @returns The OpenPkg spec, or null if not found
1495
+ *
1496
+ * @example
1497
+ * ```typescript
1498
+ * import { parseGitHubUrl, fetchSpecFromGitHub } from '@doccov/sdk';
1499
+ *
1500
+ * const parsed = parseGitHubUrl('vercel/next.js');
1501
+ * const spec = await fetchSpecFromGitHub(parsed);
1502
+ * if (spec) {
1503
+ * console.log(`Coverage: ${spec.docs?.coverageScore}%`);
1504
+ * }
1505
+ * ```
1506
+ */
1507
+ declare function fetchSpecFromGitHub(parsed: ParsedGitHubUrl): Promise<OpenPkg5 | null>;
1508
+ /**
1509
+ * Fetch an OpenPkg spec from a GitHub repository by owner/repo/branch.
1510
+ *
1511
+ * Convenience function that creates ParsedGitHubUrl internally.
1512
+ *
1513
+ * @param owner - Repository owner
1514
+ * @param repo - Repository name
1515
+ * @param branch - Branch name (default: 'main')
1516
+ * @returns The OpenPkg spec, or null if not found
1517
+ */
1518
+ declare function fetchSpec(owner: string, repo: string, branch?: string): Promise<OpenPkg5 | null>;
1519
+ /**
1520
+ * Scan types for CLI, API, and SDK consumers.
1521
+ * Single source of truth for scan-related interfaces.
1522
+ */
1523
+ /**
1524
+ * Result of scanning a repository for documentation coverage.
1525
+ * Used by CLI scan command, API endpoints, and SDK consumers.
1526
+ */
1527
+ interface ScanResult {
1528
+ /** GitHub repository owner */
1529
+ owner: string;
1530
+ /** GitHub repository name */
1531
+ repo: string;
1532
+ /** Git ref (branch/tag) that was scanned */
1533
+ ref: string;
1534
+ /** Package name if scanning a monorepo package */
1535
+ packageName?: string;
1536
+ /** Overall documentation coverage percentage (0-100) */
1537
+ coverage: number;
1538
+ /** Number of public exports analyzed */
1539
+ exportCount: number;
1540
+ /** Number of types analyzed */
1541
+ typeCount: number;
1542
+ /** Number of documentation drift issues found */
1543
+ driftCount: number;
1544
+ /** Names of exports missing documentation */
1545
+ undocumented: string[];
1546
+ /** Drift issues found during analysis */
1547
+ drift: DriftIssue[];
1548
+ }
1549
+ /**
1550
+ * A documentation drift issue.
1551
+ */
1552
+ interface DriftIssue {
1553
+ /** Name of the with drift */
1554
+ export: string;
1555
+ /** Type of drift (e.g., 'param-mismatch', 'return-type') */
1556
+ type: string;
1557
+ /** Human-readable description of the issue */
1558
+ issue: string;
1559
+ /** Optional suggestion for fixing the issue */
1560
+ suggestion?: string;
1561
+ }
1562
+ /**
1563
+ * Options for running a scan.
1564
+ */
1565
+ interface ScanOptions {
1566
+ /** GitHub URL or owner/repo shorthand */
1567
+ url: string;
1568
+ /** Git ref (branch/tag) to scan */
1569
+ ref?: string;
1570
+ /** Target package name for monorepos */
1571
+ package?: string;
1572
+ /** Skip dependency installation */
1573
+ skipInstall?: boolean;
1574
+ /** Skip external type resolution */
1575
+ skipResolve?: boolean;
1576
+ }
1577
+ /**
1578
+ * Stages of the scan pipeline.
1579
+ */
1580
+ type ProgressStage = "cloning" | "detecting" | "installing" | "building" | "analyzing" | "complete";
1581
+ /**
1582
+ * Progress event emitted during scan operations.
1583
+ */
1584
+ interface ProgressEvent {
1585
+ /** Current stage of the scan */
1586
+ stage: ProgressStage;
1587
+ /** Human-readable message */
1588
+ message: string;
1589
+ /** Progress percentage (0-100), if known */
1590
+ progress?: number;
1591
+ }
1592
+ /**
1593
+ * Callback for receiving progress events.
1594
+ */
1595
+ type ProgressCallback = (event: ProgressEvent) => void;
1596
+ /**
1597
+ * Result of running a command.
1598
+ */
1599
+ interface CommandResult {
1600
+ /** Exit code (0 = success) */
1601
+ exitCode: number;
1602
+ /** Standard output */
1603
+ stdout: string;
1604
+ /** Standard error */
1605
+ stderr: string;
588
1606
  }
589
1607
  /**
590
- * Check if a drift type can be fixed deterministically
1608
+ * Function that runs a shell command.
1609
+ * Abstracts the difference between Node.js execSync and Sandbox runCommand.
591
1610
  */
592
- declare function isFixableDrift(drift: SpecDocDrift2): boolean;
1611
+ type CommandRunner = (cmd: string, args: string[], options: {
1612
+ cwd: string;
1613
+ timeout?: number;
1614
+ }) => Promise<CommandResult>;
593
1615
  /**
594
- * Generate a fix for a single drift issue
1616
+ * Result of dependency installation.
595
1617
  */
596
- declare function generateFix(drift: SpecDocDrift2, exportEntry: SpecExport2, existingPatch?: JSDocPatch): FixSuggestion | null;
1618
+ interface InstallResult {
1619
+ /** Whether installation succeeded */
1620
+ success: boolean;
1621
+ /** Package manager that was used */
1622
+ packageManager: PackageManager;
1623
+ /** If a fallback was used, which one */
1624
+ fallbackUsed?: PackageManager;
1625
+ /** Error message if installation failed */
1626
+ error?: string;
1627
+ /** Detailed error messages from each attempt */
1628
+ errors?: string[];
1629
+ }
597
1630
  /**
598
- * Generate all fixes for an export's drift issues
1631
+ * Options for dependency installation.
599
1632
  */
600
- declare function generateFixesForExport(exportEntry: SpecExport2, existingPatch?: JSDocPatch): FixSuggestion[];
1633
+ interface InstallOptions {
1634
+ /** Timeout in milliseconds for install commands (default: 180000) */
1635
+ timeout?: number;
1636
+ /** Order of fallback package managers to try */
1637
+ fallbackOrder?: PackageManager[];
1638
+ /** Progress callback for status updates */
1639
+ onProgress?: ProgressCallback;
1640
+ }
601
1641
  /**
602
- * Merge multiple fix patches into a single patch
1642
+ * Install dependencies for a project.
1643
+ *
1644
+ * This consolidates the install logic from CLI scan.ts and API scan-stream.ts:
1645
+ * 1. Detect package manager from lockfile
1646
+ * 2. Try primary install command
1647
+ * 3. Fall back to other package managers if primary fails
1648
+ *
1649
+ * @param fs - FileSystem implementation for package manager detection
1650
+ * @param cwd - Working directory to install in
1651
+ * @param runCommand - Function to run shell commands
1652
+ * @param options - Installation options
1653
+ * @returns Result of the installation attempt
1654
+ *
1655
+ * @example
1656
+ * ```typescript
1657
+ * import { NodeFileSystem, installDependencies, createNodeCommandRunner } from '@doccov/sdk';
1658
+ *
1659
+ * const fs = new NodeFileSystem('/path/to/repo');
1660
+ * const result = await installDependencies(fs, '/path/to/repo', createNodeCommandRunner());
1661
+ *
1662
+ * if (result.success) {
1663
+ * console.log(`Installed using ${result.packageManager}`);
1664
+ * } else {
1665
+ * console.error(`Install failed: ${result.error}`);
1666
+ * }
1667
+ * ```
603
1668
  */
604
- declare function mergeFixes(fixes: FixSuggestion[], basePatch?: JSDocPatch): JSDocPatch;
1669
+ declare function installDependencies(fs: FileSystem, cwd: string, runCommand: CommandRunner, options?: InstallOptions): Promise<InstallResult>;
605
1670
  /**
606
- * Get a summary of fixable vs non-fixable drifts
1671
+ * Create a command runner for Node.js environments using execSync.
1672
+ * This is used by the CLI for local dependency installation.
1673
+ *
1674
+ * @returns CommandRunner that uses child_process.execSync
1675
+ *
1676
+ * @example
1677
+ * ```typescript
1678
+ * const runner = createNodeCommandRunner();
1679
+ * const result = await runner('npm', ['install'], { cwd: '/path/to/repo' });
1680
+ * ```
607
1681
  */
608
- declare function categorizeDrifts(drifts: SpecDocDrift2[]): {
609
- fixable: SpecDocDrift2[];
610
- nonFixable: SpecDocDrift2[];
611
- };
612
- import { SpecExport as SpecExport4 } from "@openpkg-ts/spec";
613
- import { SpecExport as SpecExport3 } from "@openpkg-ts/spec";
614
- type LintSeverity2 = "error" | "warn" | "off";
615
- interface LintViolation {
616
- rule: string;
617
- severity: "error" | "warn";
618
- message: string;
619
- line?: number;
620
- fixable: boolean;
621
- }
622
- interface LintRule {
623
- name: string;
624
- defaultSeverity: LintSeverity2;
625
- check(exp: SpecExport3, rawJSDoc?: string): LintViolation[];
626
- fix?(exp: SpecExport3, rawJSDoc?: string): JSDocPatch | null;
627
- }
628
- interface LintConfig {
629
- rules: Record<string, LintSeverity2>;
630
- }
631
- interface LintResult {
632
- violations: LintViolation[];
633
- errorCount: number;
634
- warningCount: number;
635
- fixableCount: number;
636
- }
637
- /** All available lint rules */
638
- declare const allRules: LintRule[];
639
- /** Default configuration with rule defaults */
640
- declare function getDefaultConfig(): LintConfig;
641
- /** Get a rule by name */
642
- declare function getRule(name: string): LintRule | undefined;
643
- /** Lint a single */
644
- declare function lintExport(exp: SpecExport4, rawJSDoc?: string, config?: LintConfig): LintViolation[];
645
- /** Lint multiple exports and aggregate results */
646
- declare function lintExports(exports: Array<{
647
- export: SpecExport4;
648
- rawJSDoc?: string;
649
- }>, config?: LintConfig): LintResult;
650
- /** Merge user config with defaults */
651
- declare function mergeConfig(userConfig: Partial<LintConfig>): LintConfig;
652
- declare const consistentParamStyle: LintRule;
653
- declare const noEmptyReturns: LintRule;
654
- declare const requireDescription: LintRule;
655
- declare const requireExample: LintRule;
1682
+ declare function createNodeCommandRunner(): CommandRunner;
656
1683
  import { SpecDiff } from "@openpkg-ts/spec";
657
1684
  type MemberChangeType = "added" | "removed" | "signature-changed";
658
1685
  interface MemberChange {
@@ -809,7 +1836,7 @@ declare function getDocumentedExports(markdownFiles: MarkdownDocFile[], exportNa
809
1836
  * Get all exports that lack documentation
810
1837
  */
811
1838
  declare function getUndocumentedExports(markdownFiles: MarkdownDocFile[], exportNames: string[]): string[];
812
- import { CategorizedBreaking, OpenPkg as OpenPkg3, SpecDiff as SpecDiff2 } from "@openpkg-ts/spec";
1839
+ import { CategorizedBreaking, OpenPkg as OpenPkg7, SpecDiff as SpecDiff2 } from "@openpkg-ts/spec";
813
1840
  /**
814
1841
  * Extended spec diff result with docs impact
815
1842
  */
@@ -855,7 +1882,7 @@ interface DiffWithDocsOptions {
855
1882
  * }
856
1883
  * ```
857
1884
  */
858
- declare function diffSpecWithDocs(oldSpec: OpenPkg3, newSpec: OpenPkg3, options?: DiffWithDocsOptions): SpecDiffWithDocs;
1885
+ declare function diffSpecWithDocs(oldSpec: OpenPkg7, newSpec: OpenPkg7, options?: DiffWithDocsOptions): SpecDiffWithDocs;
859
1886
  /**
860
1887
  * Check if a diff has any docs impact
861
1888
  */
@@ -925,6 +1952,10 @@ interface AnalysisResult {
925
1952
  spec: OpenPkgSpec;
926
1953
  diagnostics: Diagnostic[];
927
1954
  metadata: AnalysisMetadata;
1955
+ /** True if result came from cache (no fresh analysis) */
1956
+ fromCache?: boolean;
1957
+ /** Cache validation details (if cache was checked) */
1958
+ cacheStatus?: CacheValidationResult;
928
1959
  }
929
1960
  interface AnalysisMetadata {
930
1961
  baseDir: string;
@@ -932,6 +1963,8 @@ interface AnalysisMetadata {
932
1963
  packageJsonPath?: string;
933
1964
  hasNodeModules: boolean;
934
1965
  resolveExternalTypes: boolean;
1966
+ /** Source files included in analysis (for caching) */
1967
+ sourceFiles?: string[];
935
1968
  }
936
1969
  interface AnalyzeOptions {
937
1970
  filters?: FilterOptions;
@@ -944,6 +1977,23 @@ declare class DocCov {
944
1977
  analyzeProject(entryPath: string, analyzeOptions?: AnalyzeOptions): Promise<OpenPkgSpec>;
945
1978
  analyzeWithDiagnostics(code: string, fileName?: string, analyzeOptions?: AnalyzeOptions): Promise<AnalysisResult>;
946
1979
  analyzeFileWithDiagnostics(filePath: string, analyzeOptions?: AnalyzeOptions): Promise<AnalysisResult>;
1980
+ /**
1981
+ * Try to load spec from cache.
1982
+ * Returns null if cache is invalid or doesn't exist.
1983
+ */
1984
+ private tryLoadFromCache;
1985
+ /**
1986
+ * Save analysis result to cache.
1987
+ */
1988
+ private saveToCache;
1989
+ /**
1990
+ * Find tsconfig.json starting from a directory.
1991
+ */
1992
+ private findTsConfig;
1993
+ /**
1994
+ * Find package.json starting from a directory.
1995
+ */
1996
+ private findPackageJson;
947
1997
  private normalizeDiagnostic;
948
1998
  private mapSeverity;
949
1999
  private normalizeMetadata;
@@ -952,351 +2002,118 @@ declare class DocCov {
952
2002
  declare function analyze(code: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
953
2003
  declare function analyzeFile(filePath: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
954
2004
  /** @deprecated Use DocCov instead */
955
- declare const OpenPkg4: typeof DocCov;
956
- interface ExampleTypeError {
957
- /** Index of the example in the examples array */
958
- exampleIndex: number;
959
- /** Line number within the example (1-based) */
960
- line: number;
961
- /** Column number (1-based) */
962
- column: number;
963
- /** Error message from TypeScript */
964
- message: string;
965
- /** TypeScript diagnostic code */
966
- code: number;
967
- }
968
- interface TypecheckResult {
969
- /** All type errors found across examples */
970
- errors: ExampleTypeError[];
971
- /** Number of examples that passed */
972
- passed: number;
973
- /** Number of examples that failed */
974
- failed: number;
975
- }
976
- interface TypecheckOptions {
977
- /** Path to tsconfig.json (auto-detected if not provided) */
978
- tsconfig?: string;
979
- /** Package name for imports (auto-detected from package.json if not provided) */
980
- packageName?: string;
981
- }
982
- /**
983
- * Type-check a single example
984
- */
985
- declare function typecheckExample(example: string, packagePath: string, options?: TypecheckOptions): ExampleTypeError[];
986
- /**
987
- * Type-check multiple examples
988
- */
989
- declare function typecheckExamples(examples: string[], packagePath: string, options?: TypecheckOptions): TypecheckResult;
990
- /**
991
- * Scan types for CLI, API, and SDK consumers.
992
- * Single source of truth for scan-related interfaces.
993
- */
994
- /**
995
- * Result of scanning a repository for documentation coverage.
996
- * Used by CLI scan command, API endpoints, and SDK consumers.
997
- */
998
- interface ScanResult {
999
- /** GitHub repository owner */
1000
- owner: string;
1001
- /** GitHub repository name */
1002
- repo: string;
1003
- /** Git ref (branch/tag) that was scanned */
1004
- ref: string;
1005
- /** Package name if scanning a monorepo package */
1006
- packageName?: string;
1007
- /** Overall documentation coverage percentage (0-100) */
1008
- coverage: number;
1009
- /** Number of public exports analyzed */
1010
- exportCount: number;
1011
- /** Number of types analyzed */
1012
- typeCount: number;
1013
- /** Number of documentation drift issues found */
1014
- driftCount: number;
1015
- /** Names of exports missing documentation */
1016
- undocumented: string[];
1017
- /** Drift issues found during analysis */
1018
- drift: DriftIssue[];
1019
- }
1020
- /**
1021
- * A documentation drift issue.
1022
- */
1023
- interface DriftIssue {
1024
- /** Name of the with drift */
1025
- export: string;
1026
- /** Type of drift (e.g., 'param-mismatch', 'return-type') */
1027
- type: string;
1028
- /** Human-readable description of the issue */
1029
- issue: string;
1030
- /** Optional suggestion for fixing the issue */
1031
- suggestion?: string;
1032
- }
1033
- /**
1034
- * Options for running a scan.
1035
- */
1036
- interface ScanOptions {
1037
- /** GitHub URL or owner/repo shorthand */
1038
- url: string;
1039
- /** Git ref (branch/tag) to scan */
1040
- ref?: string;
1041
- /** Target package name for monorepos */
1042
- package?: string;
1043
- /** Skip dependency installation */
1044
- skipInstall?: boolean;
1045
- /** Skip external type resolution */
1046
- skipResolve?: boolean;
1047
- }
1048
- /**
1049
- * Stages of the scan pipeline.
1050
- */
1051
- type ProgressStage = "cloning" | "detecting" | "installing" | "building" | "analyzing" | "complete";
1052
- /**
1053
- * Progress event emitted during scan operations.
1054
- */
1055
- interface ProgressEvent {
1056
- /** Current stage of the scan */
1057
- stage: ProgressStage;
1058
- /** Human-readable message */
1059
- message: string;
1060
- /** Progress percentage (0-100), if known */
1061
- progress?: number;
1062
- }
1063
- /**
1064
- * Callback for receiving progress events.
1065
- */
1066
- type ProgressCallback = (event: ProgressEvent) => void;
1067
- import { OpenPkg as OpenPkg5 } from "@openpkg-ts/spec";
1068
- /**
1069
- * Summary of a spec's documentation coverage.
1070
- * Simpler than full ReportStats - focused on scan output.
1071
- */
1072
- interface SpecSummary {
1073
- /** Overall coverage percentage */
1074
- coverage: number;
1075
- /** Number of exports */
1076
- exportCount: number;
1077
- /** Number of types */
1078
- typeCount: number;
1079
- /** Number of drift issues */
1080
- driftCount: number;
1081
- /** Names of undocumented or partially documented exports */
1082
- undocumented: string[];
1083
- /** Drift issues */
1084
- drift: DriftIssue[];
1085
- }
1086
- /**
1087
- * Extract a summary from an OpenPkg spec.
1088
- *
1089
- * This consolidates the logic previously duplicated in:
1090
- * - CLI scan.ts (drift collection)
1091
- * - CLI reports/stats.ts (computeStats)
1092
- * - API scan-stream.ts (inline extraction script)
1093
- *
1094
- * @param spec - The OpenPkg spec to summarize
1095
- * @returns Summary of documentation coverage
1096
- *
1097
- * @example
1098
- * ```typescript
1099
- * import { extractSpecSummary } from '@doccov/sdk';
1100
- *
1101
- * const summary = extractSpecSummary(spec);
1102
- * console.log(`Coverage: ${summary.coverage}%`);
1103
- * console.log(`Undocumented: ${summary.undocumented.length}`);
1104
- * ```
1105
- */
1106
- declare function extractSpecSummary(spec: OpenPkg5): SpecSummary;
1107
- import { OpenPkg as OpenPkg7 } from "@openpkg-ts/spec";
1108
- /**
1109
- * Result of running a command.
1110
- */
1111
- interface CommandResult {
1112
- /** Exit code (0 = success) */
1113
- exitCode: number;
1114
- /** Standard output */
1115
- stdout: string;
1116
- /** Standard error */
1117
- stderr: string;
1118
- }
2005
+ declare const OpenPkg8: typeof DocCov;
2006
+ import { SpecExport as SpecExport6 } from "@openpkg-ts/spec";
2007
+ import { SpecExportKind as SpecExportKind2 } from "@openpkg-ts/spec";
1119
2008
  /**
1120
- * Function that runs a shell command.
1121
- * Abstracts the difference between Node.js execSync and Sandbox runCommand.
2009
+ * Core quality rules - these affect coverage score.
1122
2010
  */
1123
- type CommandRunner = (cmd: string, args: string[], options: {
1124
- cwd: string;
1125
- timeout?: number;
1126
- }) => Promise<CommandResult>;
2011
+ declare const CORE_RULES: QualityRule[];
1127
2012
  /**
1128
- * Result of dependency installation.
2013
+ * Style rules - these don't affect coverage, only lint.
1129
2014
  */
1130
- interface InstallResult {
1131
- /** Whether installation succeeded */
1132
- success: boolean;
1133
- /** Package manager that was used */
1134
- packageManager: PackageManager;
1135
- /** If a fallback was used, which one */
1136
- fallbackUsed?: PackageManager;
1137
- /** Error message if installation failed */
1138
- error?: string;
1139
- /** Detailed error messages from each attempt */
1140
- errors?: string[];
1141
- }
2015
+ declare const STYLE_RULES: QualityRule[];
1142
2016
  /**
1143
- * Options for dependency installation.
2017
+ * All built-in quality rules.
1144
2018
  */
1145
- interface InstallOptions {
1146
- /** Timeout in milliseconds for install commands (default: 180000) */
1147
- timeout?: number;
1148
- /** Order of fallback package managers to try */
1149
- fallbackOrder?: PackageManager[];
1150
- /** Progress callback for status updates */
1151
- onProgress?: ProgressCallback;
1152
- }
2019
+ declare const BUILTIN_RULES: QualityRule[];
1153
2020
  /**
1154
- * Install dependencies for a project.
1155
- *
1156
- * This consolidates the install logic from CLI scan.ts and API scan-stream.ts:
1157
- * 1. Detect package manager from lockfile
1158
- * 2. Try primary install command
1159
- * 3. Fall back to other package managers if primary fails
1160
- *
1161
- * @param fs - FileSystem implementation for package manager detection
1162
- * @param cwd - Working directory to install in
1163
- * @param runCommand - Function to run shell commands
1164
- * @param options - Installation options
1165
- * @returns Result of the installation attempt
1166
- *
1167
- * @example
1168
- * ```typescript
1169
- * import { NodeFileSystem, installDependencies, createNodeCommandRunner } from '@doccov/sdk';
1170
- *
1171
- * const fs = new NodeFileSystem('/path/to/repo');
1172
- * const result = await installDependencies(fs, '/path/to/repo', createNodeCommandRunner());
1173
- *
1174
- * if (result.success) {
1175
- * console.log(`Installed using ${result.packageManager}`);
1176
- * } else {
1177
- * console.error(`Install failed: ${result.error}`);
1178
- * }
1179
- * ```
2021
+ * Get rules that affect coverage calculation.
1180
2022
  */
1181
- declare function installDependencies(fs: FileSystem, cwd: string, runCommand: CommandRunner, options?: InstallOptions): Promise<InstallResult>;
2023
+ declare function getCoverageRules(): QualityRule[];
1182
2024
  /**
1183
- * Create a command runner for Node.js environments using execSync.
1184
- * This is used by the CLI for local dependency installation.
1185
- *
1186
- * @returns CommandRunner that uses child_process.execSync
1187
- *
1188
- * @example
1189
- * ```typescript
1190
- * const runner = createNodeCommandRunner();
1191
- * const result = await runner('npm', ['install'], { cwd: '/path/to/repo' });
1192
- * ```
2025
+ * Get rules applicable to a specific kind.
1193
2026
  */
1194
- declare function createNodeCommandRunner(): CommandRunner;
1195
- import { OpenPkg as OpenPkg6 } from "@openpkg-ts/spec";
2027
+ declare function getRulesForKind(kind: SpecExportKind2): QualityRule[];
1196
2028
  /**
1197
- * Parsed components of a GitHub URL.
2029
+ * Get a rule by ID.
1198
2030
  */
1199
- interface ParsedGitHubUrl {
1200
- /** Repository owner (user or org) */
1201
- owner: string;
1202
- /** Repository name */
1203
- repo: string;
1204
- /** Git ref (branch or tag) */
1205
- ref: string;
1206
- }
2031
+ declare function getRule(id: string): QualityRule | undefined;
1207
2032
  /**
1208
- * Parse a GitHub URL or shorthand into components.
1209
- *
1210
- * Supported formats:
1211
- * - https://github.com/owner/repo
1212
- * - https://github.com/owner/repo/tree/branch
1213
- * - https://github.com/owner/repo/tree/v1.0.0
1214
- * - github.com/owner/repo
1215
- * - owner/repo (shorthand)
1216
- * - git@github.com:owner/repo.git
1217
- *
1218
- * @param input - GitHub URL or shorthand
1219
- * @param defaultRef - Default ref if not specified in URL (default: 'main')
1220
- * @returns Parsed components
1221
- * @throws Error if the URL format is invalid
1222
- *
1223
- * @example
1224
- * ```typescript
1225
- * import { parseGitHubUrl } from '@doccov/sdk';
1226
- *
1227
- * const parsed = parseGitHubUrl('https://github.com/vercel/next.js/tree/canary');
1228
- * // { owner: 'vercel', repo: 'next.js', ref: 'canary' }
1229
- *
1230
- * const shorthand = parseGitHubUrl('vercel/next.js');
1231
- * // { owner: 'vercel', repo: 'next.js', ref: 'main' }
1232
- * ```
2033
+ * Get default configuration with all rule defaults.
1233
2034
  */
1234
- declare function parseGitHubUrl(input: string, defaultRef?: string): ParsedGitHubUrl;
2035
+ declare function getDefaultConfig(): Record<string, QualitySeverity>;
1235
2036
  /**
1236
- * Build a clone URL from parsed components.
2037
+ * Evaluate quality for a single export.
1237
2038
  *
1238
- * @param parsed - Parsed GitHub URL components
1239
- * @returns HTTPS clone URL
1240
- *
1241
- * @example
1242
- * ```typescript
1243
- * const cloneUrl = buildCloneUrl({ owner: 'vercel', repo: 'next.js', ref: 'main' });
1244
- * // 'https://github.com/vercel/next.js.git'
1245
- * ```
2039
+ * @param exp - The to evaluate
2040
+ * @param rawJSDoc - Optional raw JSDoc text for regex-based checks
2041
+ * @param config - Quality configuration with rule severities
2042
+ * @returns Quality result with coverage score and violations
1246
2043
  */
1247
- declare function buildCloneUrl(parsed: ParsedGitHubUrl): string;
2044
+ declare function evaluateExportQuality(exp: SpecExport6, rawJSDoc?: string, config?: QualityConfig): QualityResult;
1248
2045
  /**
1249
- * Build a display-friendly URL (without protocol or .git suffix).
1250
- *
1251
- * @param parsed - Parsed GitHub URL components
1252
- * @returns Display URL like 'github.com/owner/repo'
2046
+ * Evaluate quality for multiple exports.
1253
2047
  *
1254
- * @example
1255
- * ```typescript
1256
- * const displayUrl = buildDisplayUrl({ owner: 'vercel', repo: 'next.js', ref: 'main' });
1257
- * // 'github.com/vercel/next.js'
1258
- * ```
2048
+ * @param exports - Array of exports with optional raw JSDoc
2049
+ * @param config - Quality configuration with rule severities
2050
+ * @returns Aggregate result with per-and overall scores
1259
2051
  */
1260
- declare function buildDisplayUrl(parsed: ParsedGitHubUrl): string;
2052
+ declare function evaluateQuality(exports: Array<{
2053
+ export: SpecExport6;
2054
+ rawJSDoc?: string;
2055
+ }>, config?: QualityConfig): AggregateQualityResult;
1261
2056
  /**
1262
- * Build a raw.githubusercontent.com URL for a file.
2057
+ * Merge user configuration with defaults.
1263
2058
  *
1264
- * @param parsed - Parsed GitHub URL components
1265
- * @param filePath - Path to the file in the repo
1266
- * @returns Raw content URL
2059
+ * @param userConfig - Partial user configuration
2060
+ * @returns Complete configuration with defaults filled in
1267
2061
  */
1268
- declare function buildRawUrl(parsed: ParsedGitHubUrl, filePath: string): string;
2062
+ declare function mergeConfig(userConfig: Partial<QualityConfig>): QualityConfig;
1269
2063
  /**
1270
- * Fetch an OpenPkg spec from a GitHub repository.
2064
+ * Options for resolving a target package/entry point.
2065
+ */
2066
+ interface ResolveTargetOptions {
2067
+ /** Working directory (usually process.cwd()) */
2068
+ cwd: string;
2069
+ /** Target package name for monorepos */
2070
+ package?: string;
2071
+ /** Explicit entry point path (relative to cwd or package dir) */
2072
+ entry?: string;
2073
+ }
2074
+ /**
2075
+ * Result of resolving a target package/entry point.
2076
+ */
2077
+ interface ResolvedTarget {
2078
+ /** Resolved directory containing the package */
2079
+ targetDir: string;
2080
+ /** Resolved entry point file path (absolute) */
2081
+ entryFile: string;
2082
+ /** Package info if this is a monorepo package */
2083
+ packageInfo?: WorkspacePackage;
2084
+ /** Entry point detection info */
2085
+ entryPointInfo: EntryPointInfo;
2086
+ }
2087
+ /**
2088
+ * Resolve a target package and entry point.
1271
2089
  *
1272
- * Tries the specified ref first, then falls back to 'master' if not found.
2090
+ * This consolidates the repeated pattern from CLI commands:
2091
+ * 1. If --package specified, detect monorepo and find the package
2092
+ * 2. If no entry specified, auto-detect entry point
2093
+ * 3. If entry is a directory, detect entry point within it
1273
2094
  *
1274
- * @param parsed - Parsed GitHub URL components
1275
- * @returns The OpenPkg spec, or null if not found
2095
+ * @param fs - FileSystem implementation (NodeFileSystem or SandboxFileSystem)
2096
+ * @param options - Resolution options
2097
+ * @returns Resolved target info
2098
+ * @throws Error if monorepo package not found, or entry point detection fails
1276
2099
  *
1277
2100
  * @example
1278
2101
  * ```typescript
1279
- * import { parseGitHubUrl, fetchSpecFromGitHub } from '@doccov/sdk';
1280
- *
1281
- * const parsed = parseGitHubUrl('vercel/next.js');
1282
- * const spec = await fetchSpecFromGitHub(parsed);
1283
- * if (spec) {
1284
- * console.log(`Coverage: ${spec.docs?.coverageScore}%`);
1285
- * }
1286
- * ```
1287
- */
1288
- declare function fetchSpecFromGitHub(parsed: ParsedGitHubUrl): Promise<OpenPkg6 | null>;
1289
- /**
1290
- * Fetch an OpenPkg spec from a GitHub repository by owner/repo/branch.
2102
+ * import { NodeFileSystem, resolveTarget } from '@doccov/sdk';
1291
2103
  *
1292
- * Convenience function that creates ParsedGitHubUrl internally.
2104
+ * // Simple usage
2105
+ * const fs = new NodeFileSystem(process.cwd());
2106
+ * const { targetDir, entryFile } = await resolveTarget(fs, { cwd: process.cwd() });
1293
2107
  *
1294
- * @param owner - Repository owner
1295
- * @param repo - Repository name
1296
- * @param branch - Branch name (default: 'main')
1297
- * @returns The OpenPkg spec, or null if not found
2108
+ * // With monorepo package
2109
+ * const { targetDir, entryFile, packageInfo } = await resolveTarget(fs, {
2110
+ * cwd: process.cwd(),
2111
+ * package: '@myorg/core',
2112
+ * });
2113
+ * ```
1298
2114
  */
1299
- declare function fetchSpec(owner: string, repo: string, branch?: string): Promise<OpenPkg6 | null>;
2115
+ declare function resolveTarget(fs: FileSystem, options: ResolveTargetOptions): Promise<ResolvedTarget>;
2116
+ import { OpenPkg as OpenPkg9 } from "@openpkg-ts/spec";
1300
2117
  /**
1301
2118
  * Options for creating a ScanOrchestrator.
1302
2119
  */
@@ -1401,7 +2218,7 @@ declare class ScanOrchestrator {
1401
2218
  * @param entryFile - Path to entry file (absolute)
1402
2219
  * @returns OpenPkg spec
1403
2220
  */
1404
- analyze(entryFile: string): Promise<OpenPkg7>;
2221
+ analyze(entryFile: string): Promise<OpenPkg9>;
1405
2222
  /**
1406
2223
  * Run a complete scan workflow.
1407
2224
  *
@@ -1419,56 +2236,51 @@ declare class MonorepoRequiresPackageError extends Error {
1419
2236
  constructor(availablePackages: string[]);
1420
2237
  }
1421
2238
  /**
1422
- * Options for resolving a target package/entry point.
1423
- */
1424
- interface ResolveTargetOptions {
1425
- /** Working directory (usually process.cwd()) */
1426
- cwd: string;
1427
- /** Target package name for monorepos */
1428
- package?: string;
1429
- /** Explicit entry point path (relative to cwd or package dir) */
1430
- entry?: string;
1431
- }
1432
- /**
1433
- * Result of resolving a target package/entry point.
2239
+ * Summary of a spec's documentation coverage.
2240
+ * Simpler than full ReportStats - focused on scan output.
1434
2241
  */
1435
- interface ResolvedTarget {
1436
- /** Resolved directory containing the package */
1437
- targetDir: string;
1438
- /** Resolved entry point file path (absolute) */
1439
- entryFile: string;
1440
- /** Package info if this is a monorepo package */
1441
- packageInfo?: WorkspacePackage;
1442
- /** Entry point detection info */
1443
- entryPointInfo: EntryPointInfo;
2242
+ interface SpecSummary {
2243
+ /** Overall coverage percentage */
2244
+ coverage: number;
2245
+ /** Number of exports */
2246
+ exportCount: number;
2247
+ /** Number of types */
2248
+ typeCount: number;
2249
+ /** Number of drift issues */
2250
+ driftCount: number;
2251
+ /** Names of undocumented or partially documented exports */
2252
+ undocumented: string[];
2253
+ /** Drift issues */
2254
+ drift: DriftIssue[];
1444
2255
  }
1445
2256
  /**
1446
- * Resolve a target package and entry point.
2257
+ * Extract a summary from an enriched OpenPkg spec.
1447
2258
  *
1448
- * This consolidates the repeated pattern from CLI commands:
1449
- * 1. If --package specified, detect monorepo and find the package
1450
- * 2. If no entry specified, auto-detect entry point
1451
- * 3. If entry is a directory, detect entry point within it
2259
+ * This consolidates the logic previously duplicated in:
2260
+ * - CLI scan.ts (drift collection)
2261
+ * - CLI reports/stats.ts (computeStats)
2262
+ * - API scan-stream.ts (inline extraction script)
1452
2263
  *
1453
- * @param fs - FileSystem implementation (NodeFileSystem or SandboxFileSystem)
1454
- * @param options - Resolution options
1455
- * @returns Resolved target info
1456
- * @throws Error if monorepo package not found, or entry point detection fails
2264
+ * @param spec - The enriched OpenPkg spec to summarize (must be enriched via enrichSpec())
2265
+ * @returns Summary of documentation coverage
1457
2266
  *
1458
2267
  * @example
1459
2268
  * ```typescript
1460
- * import { NodeFileSystem, resolveTarget } from '@doccov/sdk';
1461
- *
1462
- * // Simple usage
1463
- * const fs = new NodeFileSystem(process.cwd());
1464
- * const { targetDir, entryFile } = await resolveTarget(fs, { cwd: process.cwd() });
2269
+ * import { enrichSpec, extractSpecSummary } from '@doccov/sdk';
1465
2270
  *
1466
- * // With monorepo package
1467
- * const { targetDir, entryFile, packageInfo } = await resolveTarget(fs, {
1468
- * cwd: process.cwd(),
1469
- * package: '@myorg/core',
1470
- * });
2271
+ * const enriched = enrichSpec(spec);
2272
+ * const summary = extractSpecSummary(enriched);
2273
+ * console.log(`Coverage: ${summary.coverage}%`);
2274
+ * console.log(`Undocumented: ${summary.undocumented.length}`);
1471
2275
  * ```
1472
2276
  */
1473
- declare function resolveTarget(fs: FileSystem, options: ResolveTargetOptions): Promise<ResolvedTarget>;
1474
- export { typecheckExamples, typecheckExample, serializeJSDoc, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, requireExample, requireDescription, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseAssertions, noEmptyReturns, mergeFixes, mergeFilters, mergeConfig, lintExports, lintExport, isFixableDrift, isExecutableLang, installDependencies, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, getUndocumentedExports, getRunCommand, getRule, getPrimaryBuildScript, getInstallCommand, getDocumentedExports, getDocsImpactSummary, getDefaultConfig, generateFixesForExport, generateFix, formatPackageList, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, fetchSpecFromGitHub, fetchSpec, extractSpecSummary, extractPackageSpec, extractImports, extractFunctionCalls, diffSpecWithDocs, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, consistentParamStyle, categorizeDrifts, buildRawUrl, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, allRules, WorkspacePackage, TypecheckResult, TypecheckOptions, SpecSummary, SpecDiffWithDocs, ScanResult, ScanOrchestratorOptions, ScanOrchestrator, ScanOptions, ScanContext, SandboxFileSystem, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, ProjectInfo, ProgressStage, ProgressEvent, ProgressCallback, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg4 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoRequiresPackageError, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LintViolation, LintSeverity2 as LintSeverity, LintRulesConfig, LintRule, LintResult, LintConfig, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, ExportReference, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, DriftIssue, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic, CommandRunner, CommandResult, CheckConfig, BuildInfo, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult };
2277
+ declare function extractSpecSummary(spec: EnrichedOpenPkg): SpecSummary;
2278
+ /**
2279
+ * Type-check a single example
2280
+ */
2281
+ declare function typecheckExample(example: string, packagePath: string, options?: TypecheckOptions): ExampleTypeError[];
2282
+ /**
2283
+ * Type-check multiple examples
2284
+ */
2285
+ declare function typecheckExamples(examples: string[], packagePath: string, options?: TypecheckOptions): TypecheckResult;
2286
+ export { validateSpecCache, validateExamples, typecheckExamples, typecheckExample, shouldValidate, serializeJSDoc, saveSpecCache, saveReport, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseExamplesFlag, parseAssertions, mergeFixes, mergeFilters, mergeConfig, loadSpecCache, loadCachedReport, isFixableDrift, isExecutableLang, isCachedReportValid, installDependencies, hashString, hashFiles, hashFile, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, groupDriftsByCategory, getUndocumentedExports, getSpecCachePath, getRunCommand, getRulesForKind, getRule, getReportPath, getPrimaryBuildScript, getInstallCommand, getDriftSummary, getDocumentedExports, getDocsImpactSummary, getDefaultConfig, getCoverageRules, generateReportFromEnriched, generateReport, generateFixesForExport, generateFix, formatPackageList, formatDriftSummaryLine, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, fetchSpecFromGitHub, fetchSpec, extractSpecSummary, extractPackageSpec, extractImports, extractFunctionCalls, evaluateQuality, evaluateExportQuality, enrichSpec, diffSpecWithDocs, diffHashes, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, computeExportDrift, computeDrift, clearSpecCache, categorizeDrifts, categorizeDrift, buildRawUrl, buildExportRegistry, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, VALIDATION_INFO, TypecheckValidationResult, TypecheckResult, TypecheckOptions, SpecSummary, SpecDiffWithDocs, SpecCacheConfig, SpecCache, ScanResult, ScanOrchestratorOptions, ScanOrchestrator, ScanOptions, ScanContext, SandboxFileSystem, STYLE_RULES, SPEC_CACHE_FILE, RuntimeDrift, RunValidationResult, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, RuleContext, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, REPORT_VERSION, REPORT_EXTENSIONS, QualityViolation, QualitySeverity2 as QualitySeverity, QualityRulesConfig, QualityRule, QualityResult, QualityConfig, ProjectInfo, ProgressStage, ProgressEvent, ProgressCallback, PresenceResult, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg8 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoRequiresPackageError, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LLMAssertion, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, ExportReference, ExportDriftResult, ExportCoverageData, ExampleValidationTypeError, ExampleValidationResult, ExampleValidationOptions, ExampleValidationMode, ExampleValidation, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, EnrichedOpenPkg, EnrichedExport, EnrichedDocsMetadata, EnrichOptions, DriftSummary, DriftResult, DriftReportSummary, DriftReport, DriftIssue, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovReport, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageSummary, CommandRunner, CommandResult, CheckConfig, CategorizedDrift, CacheValidationResult, CacheContext, CORE_RULES, CACHE_VERSION, BuildInfo, BUILTIN_RULES, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult, AggregateQualityResult, ALL_VALIDATIONS };