@doccov/sdk 0.25.12 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,13 +5,30 @@ interface DetectedSchemaEntry {
5
5
  schema: Record<string, unknown>;
6
6
  vendor: string;
7
7
  }
8
- import { DocCovSpec } from "@doccov/spec";
8
+ import { DocCovSpec, TypeReferenceLocation } from "@doccov/spec";
9
9
  import { OpenPkg } from "@openpkg-ts/spec";
10
10
  type OpenPkgSpec = OpenPkg;
11
+ /** Forgotten from extract package (different shape than spec type) */
12
+ interface ExtractForgottenExport {
13
+ name: string;
14
+ definedIn?: string;
15
+ referencedBy: Array<{
16
+ typeName: string;
17
+ exportName: string;
18
+ location: TypeReferenceLocation;
19
+ path?: string;
20
+ }>;
21
+ isExternal: boolean;
22
+ fix?: string;
23
+ }
11
24
  interface BuildDocCovOptions {
12
25
  openpkgPath: string;
13
26
  openpkg: OpenPkgSpec;
14
27
  packagePath?: string;
28
+ /** Forgotten exports from extraction (for API surface calculation) */
29
+ forgottenExports?: ExtractForgottenExport[];
30
+ /** Type names to ignore in API surface calculation */
31
+ apiSurfaceIgnore?: string[];
15
32
  }
16
33
  /**
17
34
  * Build a DocCov spec from an OpenPkg spec.
@@ -467,6 +484,7 @@ declare function getExportMissing(exp: SpecExport7, doccov: DocCovSpec2): Missin
467
484
  declare function isExportFullyDocumented(exp: SpecExport7, doccov: DocCovSpec2): boolean;
468
485
  import { DocCovSpec as DocCovSpec3 } from "@doccov/spec";
469
486
  import { OpenPkg as OpenPkg3 } from "@openpkg-ts/spec";
487
+ import { ApiSurfaceResult, DocumentationHealth } from "@doccov/spec";
470
488
  /**
471
489
  * Drift summary with category breakdown.
472
490
  */
@@ -572,6 +590,14 @@ interface DocCovReport {
572
590
  * Per-coverage data, keyed by ID.
573
591
  */
574
592
  exports: Record<string, ExportCoverageData>;
593
+ /**
594
+ * API surface analysis (forgotten exports).
595
+ */
596
+ apiSurface?: ApiSurfaceResult;
597
+ /**
598
+ * Unified documentation health score.
599
+ */
600
+ health?: DocumentationHealth;
575
601
  }
576
602
  /**
577
603
  * Generate a DocCov report from an OpenPkg spec.
@@ -666,4 +692,4 @@ interface SchemaDetectionResult {
666
692
  noCompiledJsWarning?: boolean;
667
693
  }
668
694
  declare function detectRuntimeSchemas(context: SchemaDetectionContext): Promise<SchemaDetectionResult>;
669
- export { saveSnapshot, saveReport, renderSparkline, renderApiSurface, pruneHistory, pruneByTier, parseAssertions, loadSnapshotsForDays, loadSnapshots, loadCachedReport, isExportFullyDocumented, isCachedReportValid, hasNonAssertionComments, groupDriftsByCategory, getTrend, getExtendedTrend, getExportScore, getExportMissing, getExportDrift, getExportAnalysis, getDriftSummary, generateWeeklySummaries, generateReportFromDocCov, generateReport, formatDriftSummaryLine, formatDelta, ensureSpecCoverage, detectRuntimeSchemas, detectExampleRuntimeErrors, detectExampleAssertionFailures, computeSnapshot, computeExportDrift, computeDrift, categorizeDrift, calculateAggregateCoverage, buildExportRegistry, buildDocCovSpec, WeeklySummary, SchemaDetectionResult, SchemaDetectionContext, RetentionTier, RETENTION_DAYS, OpenPkgSpec, HISTORY_DIR, ExtendedTrendAnalysis, ExportDriftResult, DriftSummary, DriftResult, DetectedSchemaEntry, CoverageTrend, CoverageSnapshot, CategorizedDrift, BuildDocCovOptions };
695
+ export { saveSnapshot, saveReport, renderSparkline, renderApiSurface, pruneHistory, pruneByTier, parseAssertions, loadSnapshotsForDays, loadSnapshots, loadCachedReport, isExportFullyDocumented, isCachedReportValid, hasNonAssertionComments, groupDriftsByCategory, getTrend, getExtendedTrend, getExportScore, getExportMissing, getExportDrift, getExportAnalysis, getDriftSummary, generateWeeklySummaries, generateReportFromDocCov, generateReport, formatDriftSummaryLine, formatDelta, ensureSpecCoverage, detectRuntimeSchemas, detectExampleRuntimeErrors, detectExampleAssertionFailures, computeSnapshot, computeExportDrift, computeDrift, categorizeDrift, calculateAggregateCoverage, buildExportRegistry, buildDocCovSpec, WeeklySummary, SchemaDetectionResult, SchemaDetectionContext, RetentionTier, RETENTION_DAYS, OpenPkgSpec, HISTORY_DIR, ExtractForgottenExport, ExtendedTrendAnalysis, ExportDriftResult, DriftSummary, DriftResult, DetectedSchemaEntry, CoverageTrend, CoverageSnapshot, CategorizedDrift, BuildDocCovOptions };
@@ -38,7 +38,7 @@ import {
38
38
  renderSparkline,
39
39
  saveReport,
40
40
  saveSnapshot
41
- } from "../shared/chunk-cbe8089a.js";
41
+ } from "../shared/chunk-v62zsv8j.js";
42
42
  import"../shared/chunk-esptwrfq.js";
43
43
  export {
44
44
  saveSnapshot,
package/dist/index.d.ts CHANGED
@@ -1,10 +1,63 @@
1
- import { DocCovSpec } from "@doccov/spec";
1
+ import { DocumentationHealth, DriftCategory, MissingDocRule } from "@doccov/spec";
2
+ /**
3
+ * Input data for computing documentation health score.
4
+ */
5
+ interface HealthInput {
6
+ /** Coverage score (0-100) */
7
+ coverageScore: number;
8
+ /** Number of documented exports */
9
+ documentedExports: number;
10
+ /** Total exports analyzed */
11
+ totalExports: number;
12
+ /** Missing docs by rule */
13
+ missingByRule: Record<MissingDocRule, number>;
14
+ /** Total drift issues */
15
+ driftIssues: number;
16
+ /** Fixable drift issues */
17
+ fixableDrift: number;
18
+ /** Drift by category */
19
+ driftByCategory: Record<DriftCategory, number>;
20
+ /** Example validation results (optional) */
21
+ examples?: {
22
+ passed: number;
23
+ failed: number;
24
+ total: number;
25
+ };
26
+ }
27
+ /**
28
+ * Compute unified documentation health score.
29
+ *
30
+ * Formula: health = completeness × (1 - drift_ratio × 0.5)
31
+ * - Max 50% drift penalty
32
+ * - Optional 30% example penalty if examples validated
33
+ *
34
+ * Score thresholds: green 80+, yellow 60-79, red <60
35
+ */
36
+ declare function computeHealth(input: HealthInput): DocumentationHealth;
37
+ import { DocCovSpec, TypeReferenceLocation } from "@doccov/spec";
2
38
  import { OpenPkg } from "@openpkg-ts/spec";
3
39
  type OpenPkgSpec = OpenPkg;
40
+ /** Forgotten from extract package (different shape than spec type) */
41
+ interface ExtractForgottenExport {
42
+ name: string;
43
+ definedIn?: string;
44
+ referencedBy: Array<{
45
+ typeName: string;
46
+ exportName: string;
47
+ location: TypeReferenceLocation;
48
+ path?: string;
49
+ }>;
50
+ isExternal: boolean;
51
+ fix?: string;
52
+ }
4
53
  interface BuildDocCovOptions {
5
54
  openpkgPath: string;
6
55
  openpkg: OpenPkgSpec;
7
56
  packagePath?: string;
57
+ /** Forgotten exports from extraction (for API surface calculation) */
58
+ forgottenExports?: ExtractForgottenExport[];
59
+ /** Type names to ignore in API surface calculation */
60
+ apiSurfaceIgnore?: string[];
8
61
  }
9
62
  /**
10
63
  * Build a DocCov spec from an OpenPkg spec.
@@ -26,19 +79,19 @@ type SpecDocDrift = {
26
79
  /**
27
80
  * Drift categories group related drift types for progressive disclosure.
28
81
  */
29
- type DriftCategory = "structural" | "semantic" | "example";
82
+ type DriftCategory2 = "structural" | "semantic" | "example";
30
83
  /**
31
84
  * Maps each drift type to its category.
32
85
  */
33
- declare const DRIFT_CATEGORIES: Record<DriftType, DriftCategory>;
86
+ declare const DRIFT_CATEGORIES: Record<DriftType, DriftCategory2>;
34
87
  /**
35
88
  * Human-readable category labels.
36
89
  */
37
- declare const DRIFT_CATEGORY_LABELS: Record<DriftCategory, string>;
90
+ declare const DRIFT_CATEGORY_LABELS: Record<DriftCategory2, string>;
38
91
  /**
39
92
  * Category descriptions for help text.
40
93
  */
41
- declare const DRIFT_CATEGORY_DESCRIPTIONS: Record<DriftCategory, string>;
94
+ declare const DRIFT_CATEGORY_DESCRIPTIONS: Record<DriftCategory2, string>;
42
95
  /**
43
96
  * Result of computing drift for a single export.
44
97
  */
@@ -75,7 +128,7 @@ interface ExportRegistry {
75
128
  * Extended drift with category and fixability metadata.
76
129
  */
77
130
  interface CategorizedDrift extends SpecDocDrift {
78
- category: DriftCategory;
131
+ category: DriftCategory2;
79
132
  fixable: boolean;
80
133
  }
81
134
  /**
@@ -83,7 +136,7 @@ interface CategorizedDrift extends SpecDocDrift {
83
136
  */
84
137
  interface DriftSummary {
85
138
  total: number;
86
- byCategory: Record<DriftCategory, number>;
139
+ byCategory: Record<DriftCategory2, number>;
87
140
  fixable: number;
88
141
  }
89
142
  /**
@@ -119,7 +172,7 @@ declare function categorizeDrift(drift: SpecDocDrift): CategorizedDrift;
119
172
  * console.log(grouped.example.length); // Number of example issues
120
173
  * ```
121
174
  */
122
- declare function groupDriftsByCategory(drifts: SpecDocDrift[]): Record<DriftCategory, CategorizedDrift[]>;
175
+ declare function groupDriftsByCategory(drifts: SpecDocDrift[]): Record<DriftCategory2, CategorizedDrift[]>;
123
176
  /**
124
177
  * Get drift summary counts by category.
125
178
  *
@@ -284,7 +337,7 @@ declare function hasNonAssertionComments(code: string): boolean;
284
337
  * Detect assertion failures by comparing stdout to expected values.
285
338
  */
286
339
  declare function detectExampleAssertionFailures(entry: SpecExport2, runtimeResults: Map<number, ExampleRunResult>): SpecDocDrift[];
287
- import { DocCovDrift, DocCovSpec as DocCovSpec2, ExportAnalysis, MissingDocRule } from "@doccov/spec";
340
+ import { DocCovDrift, DocCovSpec as DocCovSpec2, ExportAnalysis, MissingDocRule as MissingDocRule2 } from "@doccov/spec";
288
341
  import { SpecExport as SpecExport7 } from "@openpkg-ts/spec";
289
342
  /**
290
343
  * Get the full analysis data for an export.
@@ -317,7 +370,7 @@ declare function getExportDrift(exp: SpecExport7, doccov: DocCovSpec2): DocCovDr
317
370
  * @param doccov - The DocCov spec containing analysis data
318
371
  * @returns Array of missing rule IDs or empty array if none
319
372
  */
320
- declare function getExportMissing(exp: SpecExport7, doccov: DocCovSpec2): MissingDocRule[];
373
+ declare function getExportMissing(exp: SpecExport7, doccov: DocCovSpec2): MissingDocRule2[];
321
374
  /**
322
375
  * Check if an has complete documentation.
323
376
  *
@@ -328,6 +381,7 @@ declare function getExportMissing(exp: SpecExport7, doccov: DocCovSpec2): Missin
328
381
  declare function isExportFullyDocumented(exp: SpecExport7, doccov: DocCovSpec2): boolean;
329
382
  import { DocCovSpec as DocCovSpec3 } from "@doccov/spec";
330
383
  import { OpenPkg as OpenPkg2 } from "@openpkg-ts/spec";
384
+ import { ApiSurfaceResult, DocumentationHealth as DocumentationHealth2 } from "@doccov/spec";
331
385
  /**
332
386
  * DocCov report schema version.
333
387
  */
@@ -387,7 +441,7 @@ interface DriftReportSummary {
387
441
  /**
388
442
  * Count of issues per category.
389
443
  */
390
- byCategory: Record<DriftCategory, number>;
444
+ byCategory: Record<DriftCategory2, number>;
391
445
  /**
392
446
  * Number of auto-fixable issues.
393
447
  */
@@ -409,7 +463,7 @@ interface DriftReport {
409
463
  /**
410
464
  * Issues grouped by category.
411
465
  */
412
- byCategory: Record<DriftCategory, CategorizedDrift[]>;
466
+ byCategory: Record<DriftCategory2, CategorizedDrift[]>;
413
467
  /**
414
468
  * Flat list of all drift issues (backward compatible).
415
469
  */
@@ -503,6 +557,14 @@ interface DocCovReport {
503
557
  * Per-coverage data, keyed by ID.
504
558
  */
505
559
  exports: Record<string, ExportCoverageData>;
560
+ /**
561
+ * API surface analysis (forgotten exports).
562
+ */
563
+ apiSurface?: ApiSurfaceResult;
564
+ /**
565
+ * Unified documentation health score.
566
+ */
567
+ health?: DocumentationHealth2;
506
568
  }
507
569
  /**
508
570
  * Generate a DocCov report from an OpenPkg spec.
@@ -748,6 +810,17 @@ type ExampleValidationMode = "presence" | "typecheck" | "run";
748
810
  */
749
811
  type SchemaExtractionMode = "static" | "runtime" | "hybrid";
750
812
  /**
813
+ * API surface configuration options.
814
+ */
815
+ interface ApiSurfaceConfig {
816
+ /** Minimum completeness percentage to pass (0-100) */
817
+ minCompleteness?: number;
818
+ /** Warning threshold - warn when below this (0-100) */
819
+ warnBelow?: number;
820
+ /** Type names to ignore (won't be flagged as forgotten exports) */
821
+ ignore?: string[];
822
+ }
823
+ /**
751
824
  * Check command configuration options.
752
825
  */
753
826
  interface CheckConfig {
@@ -759,10 +832,22 @@ interface CheckConfig {
759
832
  * - 'run': Execute examples and validate assertions
760
833
  */
761
834
  examples?: ExampleValidationMode | ExampleValidationMode[] | string;
762
- /** Minimum coverage percentage required (0-100) */
835
+ /** Minimum health score required (0-100). Unified metric combining coverage + accuracy. */
836
+ minHealth?: number;
837
+ /**
838
+ * Minimum coverage percentage required (0-100)
839
+ * @deprecated Use `minHealth` instead. Will be removed in next major.
840
+ */
763
841
  minCoverage?: number;
764
- /** Maximum drift percentage allowed (0-100) */
842
+ /**
843
+ * Maximum drift percentage allowed (0-100)
844
+ * @deprecated Use `minHealth` instead. Drift is now factored into health score.
845
+ */
765
846
  maxDrift?: number;
847
+ /** Minimum API surface completeness percentage (0-100) - deprecated, use apiSurface.minCompleteness */
848
+ minApiSurface?: number;
849
+ /** API surface configuration */
850
+ apiSurface?: ApiSurfaceConfig;
766
851
  }
767
852
  /**
768
853
  * Normalized DocCov configuration.
@@ -849,6 +934,20 @@ interface AnalysisResult {
849
934
  fromCache?: boolean;
850
935
  /** Cache validation details (if cache was checked) */
851
936
  cacheStatus?: CacheValidationResult;
937
+ /** Forgotten exports (types referenced but not exported) */
938
+ forgottenExports?: ForgottenExportResult[];
939
+ }
940
+ interface ForgottenExportResult {
941
+ name: string;
942
+ definedIn?: string;
943
+ referencedBy: Array<{
944
+ typeName: string;
945
+ exportName: string;
946
+ location: "return" | "parameter" | "property" | "extends" | "type-parameter";
947
+ path?: string;
948
+ }>;
949
+ isExternal: boolean;
950
+ fix?: string;
852
951
  }
853
952
  interface AnalysisMetadata {
854
953
  baseDir: string;
@@ -959,7 +1058,7 @@ interface WorkspacePackage {
959
1058
  private: boolean;
960
1059
  }
961
1060
  /** Entry point source - where the entry was detected from */
962
- type EntryPointSource = "types" | "exports" | "main" | "module" | "fallback";
1061
+ type EntryPointSource = "types" | "exports" | "main" | "module" | "fallback" | "explicit";
963
1062
  /** Entry point detection result */
964
1063
  interface EntryPointInfo {
965
1064
  /** Path to entry file (relative to package root) */
@@ -1510,6 +1609,55 @@ declare function categorizeDrifts(drifts: SpecDocDrift[]): {
1510
1609
  fixable: SpecDocDrift[];
1511
1610
  nonFixable: SpecDocDrift[];
1512
1611
  };
1612
+ import { ApiSurfaceResult as ApiSurfaceResult2 } from "@doccov/spec";
1613
+ /** Fix for a forgotten */
1614
+ interface ForgottenExportFix {
1615
+ type: "forgotten-export";
1616
+ typeName: string;
1617
+ targetFile: string;
1618
+ exportStatement: string;
1619
+ insertPosition: "append" | {
1620
+ afterLine: number;
1621
+ };
1622
+ }
1623
+ /** Result of applying forgotten fixes */
1624
+ interface ApplyForgottenExportResult {
1625
+ filesModified: number;
1626
+ fixesApplied: number;
1627
+ errors: Array<{
1628
+ file: string;
1629
+ error: string;
1630
+ }>;
1631
+ }
1632
+ /** Options for generating fixes */
1633
+ interface GenerateForgottenExportFixesOptions {
1634
+ /** Base directory for resolving paths */
1635
+ baseDir: string;
1636
+ /** Entry file for the package */
1637
+ entryFile: string;
1638
+ }
1639
+ /**
1640
+ * Generate fixes for forgotten exports.
1641
+ * Groups fixes by target file and generates minimal statements.
1642
+ */
1643
+ declare function generateForgottenExportFixes(apiSurface: ApiSurfaceResult2, options: GenerateForgottenExportFixesOptions): ForgottenExportFix[];
1644
+ /**
1645
+ * Group fixes by target file for efficient application.
1646
+ */
1647
+ declare function groupFixesByFile(fixes: ForgottenExportFix[]): Map<string, ForgottenExportFix[]>;
1648
+ /**
1649
+ * Apply forgotten fixes to files.
1650
+ * Reads files, finds best insertion points, and applies edits.
1651
+ */
1652
+ declare function applyForgottenExportFixes(fixes: ForgottenExportFix[]): Promise<ApplyForgottenExportResult>;
1653
+ /**
1654
+ * Preview forgotten fixes without applying them.
1655
+ * Returns a map of file paths to the changes that would be made.
1656
+ */
1657
+ declare function previewForgottenExportFixes(fixes: ForgottenExportFix[]): Map<string, {
1658
+ insertLine: number;
1659
+ statements: string[];
1660
+ }>;
1513
1661
  import { SpecDiff } from "@openpkg-ts/spec";
1514
1662
  type MemberChangeType = "added" | "removed" | "signature-changed";
1515
1663
  interface MemberChange {
@@ -1690,6 +1838,22 @@ interface SpecDiffWithDocs extends SpecDiff2 {
1690
1838
  memberChanges?: MemberChange[];
1691
1839
  /** Breaking changes categorized by severity (high/medium/low) */
1692
1840
  categorizedBreaking?: CategorizedBreaking[];
1841
+ /** Coverage score from old spec */
1842
+ oldCoverage: number;
1843
+ /** Coverage score from new spec */
1844
+ newCoverage: number;
1845
+ /** Change in coverage (newCoverage - oldCoverage) */
1846
+ coverageDelta: number;
1847
+ /** Number of new drift issues introduced */
1848
+ driftIntroduced: number;
1849
+ /** Number of drift issues resolved */
1850
+ driftResolved: number;
1851
+ /** New exports that are undocumented */
1852
+ newUndocumented: string[];
1853
+ /** Exports with improved coverage */
1854
+ improvedExports: string[];
1855
+ /** Exports with regressed coverage */
1856
+ regressedExports: string[];
1693
1857
  }
1694
1858
  /**
1695
1859
  * Options for diffSpecWithDocs
@@ -2515,7 +2679,7 @@ interface SpecSummary {
2515
2679
  * ```
2516
2680
  */
2517
2681
  declare function extractSpecSummary(openpkg: OpenPkg8, doccov: DocCovSpec4): SpecSummary;
2518
- import { OpenPkg as OpenPkg_kdpxrtnzlr } from "@openpkg-ts/spec";
2682
+ import { OpenPkg as OpenPkg_tgtzybcxvb } from "@openpkg-ts/spec";
2519
2683
  /**
2520
2684
  * Build Plan types for AI-powered repository scanning.
2521
2685
  */
@@ -2612,7 +2776,7 @@ interface BuildPlanExecutionResult {
2612
2776
  /** Whether all required steps succeeded */
2613
2777
  success: boolean;
2614
2778
  /** Generated OpenPkg spec (if successful) */
2615
- spec?: OpenPkg_kdpxrtnzlr;
2779
+ spec?: OpenPkg_tgtzybcxvb;
2616
2780
  /** Results for each step */
2617
2781
  stepResults: BuildPlanStepResult[];
2618
2782
  /** Total execution time in milliseconds */
@@ -2620,4 +2784,4 @@ interface BuildPlanExecutionResult {
2620
2784
  /** Overall error message if failed */
2621
2785
  error?: string;
2622
2786
  }
2623
- export { validateSpecCache, validateExamples, typecheckExamples, typecheckExample, shouldValidate, serializeJSDoc, saveSpecCache, saveSnapshot, saveReport, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, resolveCompiledPath, renderSparkline, renderApiSurface, readPackageJson, pruneHistory, pruneByTier, parseGitHubUrl2 as parseScanGitHubUrl, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseExamplesFlag, parseAssertions, mergeFixes, mergeFilters, loadSpecCache, loadSnapshots, loadCachedReport, listWorkspacePackages, isStandardJSONSchema, isSchemaType, isFixableDrift, isExportFullyDocumented, isExecutableLang, installDependencies, hashString, hashFiles, hashFile, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, groupDriftsByCategory, getUndocumentedExports, getTrend, getSupportedLibraries, getSpecCachePath, getRunCommand, getReportPath, getRegisteredAdapters, getPrimaryBuildScript, getInstallCommand, getExtendedTrend, getExportScore, getExportMissing, getExportDrift, getExportAnalysis, getDriftSummary, getDocumentedExports, getDocsImpactSummary, getDiffReportPath, generateReportFromDocCov, generateReport, generateFixesForExport, generateFix, formatPackageList, formatDriftSummaryLine, formatDelta, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, findAdapter, fetchSpecFromGitHub, fetchSpec, fetchGitHubContext, extractStandardSchemasFromProject, extractStandardSchemas, extractSpecSummary, extractSchemaType, extractSchemaOutputType, extractPackageSpec, extractImports, extractFunctionCalls, ensureSpecCoverage, diffSpecWithDocs, diffHashes, detectRuntimeSchemas, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, computeSnapshot, computeExportDrift, computeDrift, clearSpecCache, categorizeDrifts, categorizeDrift, calculateAggregateCoverage, buildRawUrl, buildExportRegistry, buildDocCovSpec, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, WorkspaceConfig, VALIDATION_INFO, TypecheckValidationResult, TypecheckResult, TypecheckOptions, SummaryDriftIssue, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, SpecSummary, SpecDocDrift, SpecDiffWithDocs, SpecCacheConfig, SpecCache, SchemaExtractionResult, SchemaExtractionMode, SchemaDetectionResult, SchemaDetectionContext, SchemaAdapter, SandboxFileSystem, SPEC_CACHE_FILE, RuntimeDrift, RunValidationResult, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, RetentionTier, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, ReleaseTag, RETENTION_DAYS, REPORT_VERSION, REPORT_EXTENSIONS, ProjectInfo, PresenceResult, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, NodeFileSystem, MonorepoType, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LLMAssertion, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, HISTORY_DIR, GitHubRepoMetadata, GitHubProjectContext, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, FetchGitHubContextOptions, ExtractStandardSchemasOptions, ExtendedTrendAnalysis, ExportReference, ExportDriftResult, ExportCoverageData, ExampleValidationTypeError, ExampleValidationResult, ExampleValidationOptions, ExampleValidationMode, ExampleValidation, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, DriftType, DriftSummary, DriftResult, DriftReportSummary, DriftReport, DriftCategory, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovReport, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic, DetectedSchemaEntry, DetectedPackageManager, DRIFT_CATEGORY_LABELS, DRIFT_CATEGORY_DESCRIPTIONS, DRIFT_CATEGORIES, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageTrend, CoverageSummary, CoverageSnapshot, CommandRunner, CommandResult, CheckConfig, CategorizedDrift, CacheValidationResult, CacheContext, CACHE_VERSION, BuildPlanTarget, BuildPlanStepResult, BuildPlanStep, BuildPlanExecutionResult, BuildPlanEnvironment, BuildPlan, BuildInfo, BuildHints, BuildDocCovOptions, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult, ALL_VALIDATIONS };
2787
+ export { validateSpecCache, validateExamples, typecheckExamples, typecheckExample, shouldValidate, serializeJSDoc, saveSpecCache, saveSnapshot, saveReport, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, resolveCompiledPath, renderSparkline, renderApiSurface, readPackageJson, pruneHistory, pruneByTier, previewForgottenExportFixes, parseGitHubUrl2 as parseScanGitHubUrl, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseExamplesFlag, parseAssertions, mergeFixes, mergeFilters, loadSpecCache, loadSnapshots, loadCachedReport, listWorkspacePackages, isStandardJSONSchema, isSchemaType, isFixableDrift, isExportFullyDocumented, isExecutableLang, installDependencies, hashString, hashFiles, hashFile, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, groupFixesByFile, groupDriftsByCategory, getUndocumentedExports, getTrend, getSupportedLibraries, getSpecCachePath, getRunCommand, getReportPath, getRegisteredAdapters, getPrimaryBuildScript, getInstallCommand, getExtendedTrend, getExportScore, getExportMissing, getExportDrift, getExportAnalysis, getDriftSummary, getDocumentedExports, getDocsImpactSummary, getDiffReportPath, generateReportFromDocCov, generateReport, generateForgottenExportFixes, generateFixesForExport, generateFix, formatPackageList, formatDriftSummaryLine, formatDelta, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, findAdapter, fetchSpecFromGitHub, fetchSpec, fetchGitHubContext, extractStandardSchemasFromProject, extractStandardSchemas, extractSpecSummary, extractSchemaType, extractSchemaOutputType, extractPackageSpec, extractImports, extractFunctionCalls, ensureSpecCoverage, diffSpecWithDocs, diffHashes, detectRuntimeSchemas, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, computeSnapshot, computeHealth, computeExportDrift, computeDrift, clearSpecCache, categorizeDrifts, categorizeDrift, calculateAggregateCoverage, buildRawUrl, buildExportRegistry, buildDocCovSpec, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyForgottenExportFixes, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, WorkspaceConfig, VALIDATION_INFO, TypecheckValidationResult, TypecheckResult, TypecheckOptions, SummaryDriftIssue, StandardSchemaExtractionResult, StandardSchemaExtractionOutput, StandardJSONSchemaV1, SpecSummary, SpecDocDrift, SpecDiffWithDocs, SpecCacheConfig, SpecCache, SchemaExtractionResult, SchemaExtractionMode, SchemaDetectionResult, SchemaDetectionContext, SchemaAdapter, SandboxFileSystem, SPEC_CACHE_FILE, RuntimeDrift, RunValidationResult, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, RetentionTier, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, ReleaseTag, RETENTION_DAYS, REPORT_VERSION, REPORT_EXTENSIONS, ProjectInfo, PresenceResult, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, NodeFileSystem, MonorepoType, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LLMAssertion, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, HealthInput, HISTORY_DIR, GitHubRepoMetadata, GitHubProjectContext, GenerateForgottenExportFixesOptions, ForgottenExportResult, ForgottenExportFix, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, FetchGitHubContextOptions, ExtractStandardSchemasOptions, ExtendedTrendAnalysis, ExportReference, ExportDriftResult, ExportCoverageData, ExampleValidationTypeError, ExampleValidationResult, ExampleValidationOptions, ExampleValidationMode, ExampleValidation, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, DriftType, DriftSummary, DriftResult, DriftReportSummary, DriftReport, DriftCategory2 as DriftCategory, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovReport, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic, DetectedSchemaEntry, DetectedPackageManager, DRIFT_CATEGORY_LABELS, DRIFT_CATEGORY_DESCRIPTIONS, DRIFT_CATEGORIES, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageTrend, CoverageSummary, CoverageSnapshot, CommandRunner, CommandResult, CheckConfig, CategorizedDrift, CacheValidationResult, CacheContext, CACHE_VERSION, BuildPlanTarget, BuildPlanStepResult, BuildPlanStep, BuildPlanExecutionResult, BuildPlanEnvironment, BuildPlan, BuildInfo, BuildHints, BuildDocCovOptions, ApplyForgottenExportResult, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult, ALL_VALIDATIONS };
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  HISTORY_DIR,
6
6
  RETENTION_DAYS,
7
7
  applyEdits,
8
+ applyForgottenExportFixes,
8
9
  applyPatchToJSDoc,
9
10
  buildDocCovSpec,
10
11
  buildExportRegistry,
@@ -13,6 +14,7 @@ import {
13
14
  categorizeDrifts,
14
15
  computeDrift,
15
16
  computeExportDrift,
17
+ computeHealth,
16
18
  computeSnapshot,
17
19
  createSourceFile,
18
20
  detectExampleAssertionFailures,
@@ -26,6 +28,7 @@ import {
26
28
  formatDriftSummaryLine,
27
29
  generateFix,
28
30
  generateFixesForExport,
31
+ generateForgottenExportFixes,
29
32
  generateReport,
30
33
  generateReportFromDocCov,
31
34
  getDriftSummary,
@@ -36,6 +39,7 @@ import {
36
39
  getExtendedTrend,
37
40
  getTrend,
38
41
  groupDriftsByCategory,
42
+ groupFixesByFile,
39
43
  hasNonAssertionComments,
40
44
  isBuiltInIdentifier,
41
45
  isExportFullyDocumented,
@@ -46,6 +50,7 @@ import {
46
50
  mergeFixes,
47
51
  parseAssertions,
48
52
  parseJSDocToPatch,
53
+ previewForgottenExportFixes,
49
54
  pruneByTier,
50
55
  pruneHistory,
51
56
  renderApiSurface,
@@ -55,7 +60,7 @@ import {
55
60
  saveSnapshot,
56
61
  serializeJSDoc,
57
62
  ts
58
- } from "./shared/chunk-cbe8089a.js";
63
+ } from "./shared/chunk-v62zsv8j.js";
59
64
  import {
60
65
  mergeFilters,
61
66
  parseListFlag
@@ -290,7 +295,8 @@ async function runAnalysis(input) {
290
295
  sourceFiles
291
296
  },
292
297
  diagnostics,
293
- specDiagnostics
298
+ specDiagnostics,
299
+ forgottenExports: extractResult.forgottenExports
294
300
  };
295
301
  }
296
302
 
@@ -617,7 +623,7 @@ ${extraction.errors.map((e) => ` - ${e}`).join(`
617
623
  `)}`);
618
624
  }
619
625
  }
620
- const result = runAnalysis({
626
+ const result = await runAnalysis({
621
627
  entryFile,
622
628
  packageDir,
623
629
  content,
@@ -868,7 +874,8 @@ class DocCov {
868
874
  ...analysis.specDiagnostics,
869
875
  ...filterOutcome.diagnostics
870
876
  ],
871
- metadata: this.normalizeMetadata(analysis.metadata)
877
+ metadata: this.normalizeMetadata(analysis.metadata),
878
+ forgottenExports: analysis.forgottenExports
872
879
  };
873
880
  }
874
881
  async analyzeFileWithDiagnostics(filePath, analyzeOptions = {}) {
@@ -907,7 +914,8 @@ class DocCov {
907
914
  ...filterOutcome.diagnostics
908
915
  ],
909
916
  metadata,
910
- fromCache: false
917
+ fromCache: false,
918
+ forgottenExports: analysis.forgottenExports
911
919
  };
912
920
  if (useCache) {
913
921
  this.saveToCache(result, resolvedPath, analysis.metadata);
@@ -2487,7 +2495,7 @@ function extractMethodCallsAST(code) {
2487
2495
  if (ts.isIdentifier(objectExpr.expression)) {
2488
2496
  objectName = objectExpr.expression.text;
2489
2497
  }
2490
- } else if (ts.isThisKeyword(objectExpr)) {
2498
+ } else if (objectExpr.kind === ts.SyntaxKind.ThisKeyword) {
2491
2499
  objectName = "this";
2492
2500
  }
2493
2501
  if (objectName && !isBuiltInIdentifier(objectName)) {
@@ -3105,22 +3113,84 @@ function diffSpecWithDocs(oldSpec, newSpec, options = {}) {
3105
3113
  const baseDiff = diffSpec(oldSpec, newSpec);
3106
3114
  const memberChanges = diffMemberChanges(oldSpec, newSpec, baseDiff.breaking);
3107
3115
  const categorizedBreaking = categorizeBreakingChanges(baseDiff.breaking, oldSpec, newSpec, memberChanges);
3116
+ const { oldCoverage, newCoverage, coverageDelta, improvedExports, regressedExports } = computeCoverageMetrics(oldSpec, newSpec);
3117
+ const { driftIntroduced, driftResolved } = computeDriftMetrics(oldSpec, newSpec);
3118
+ const oldExportIds = new Set(oldSpec.exports?.map((e) => e.id) ?? []);
3119
+ const newUndocumented = (newSpec.exports ?? []).filter((e) => !oldExportIds.has(e.id) && !hasDocumentation(e)).map((e) => e.name);
3120
+ const baseResult = {
3121
+ ...baseDiff,
3122
+ memberChanges: memberChanges.length > 0 ? memberChanges : undefined,
3123
+ categorizedBreaking: categorizedBreaking.length > 0 ? categorizedBreaking : undefined,
3124
+ oldCoverage,
3125
+ newCoverage,
3126
+ coverageDelta,
3127
+ driftIntroduced,
3128
+ driftResolved,
3129
+ newUndocumented,
3130
+ improvedExports,
3131
+ regressedExports
3132
+ };
3108
3133
  if (!options.markdownFiles?.length) {
3109
- return {
3110
- ...baseDiff,
3111
- memberChanges: memberChanges.length > 0 ? memberChanges : undefined,
3112
- categorizedBreaking: categorizedBreaking.length > 0 ? categorizedBreaking : undefined
3113
- };
3134
+ return baseResult;
3114
3135
  }
3115
3136
  const newExportNames = newSpec.exports?.map((e) => e.name) ?? [];
3116
3137
  const docsImpact = analyzeDocsImpact(baseDiff, options.markdownFiles, newExportNames, memberChanges);
3117
3138
  return {
3118
- ...baseDiff,
3119
- docsImpact,
3120
- memberChanges: memberChanges.length > 0 ? memberChanges : undefined,
3121
- categorizedBreaking: categorizedBreaking.length > 0 ? categorizedBreaking : undefined
3139
+ ...baseResult,
3140
+ docsImpact
3122
3141
  };
3123
3142
  }
3143
+ function computeCoverageMetrics(oldSpec, newSpec) {
3144
+ const oldCoverage = getSpecCoverage(oldSpec);
3145
+ const newCoverage = getSpecCoverage(newSpec);
3146
+ const coverageDelta = newCoverage - oldCoverage;
3147
+ const oldExportScores = new Map;
3148
+ for (const exp of oldSpec.exports ?? []) {
3149
+ const enriched = exp;
3150
+ oldExportScores.set(exp.id, enriched.docs?.coverageScore ?? 0);
3151
+ }
3152
+ const improvedExports = [];
3153
+ const regressedExports = [];
3154
+ for (const exp of newSpec.exports ?? []) {
3155
+ const enriched = exp;
3156
+ const oldScore = oldExportScores.get(exp.id);
3157
+ if (oldScore === undefined)
3158
+ continue;
3159
+ const newScore = enriched.docs?.coverageScore ?? 0;
3160
+ if (newScore > oldScore) {
3161
+ improvedExports.push(exp.name);
3162
+ } else if (newScore < oldScore) {
3163
+ regressedExports.push(exp.name);
3164
+ }
3165
+ }
3166
+ return { oldCoverage, newCoverage, coverageDelta, improvedExports, regressedExports };
3167
+ }
3168
+ function getSpecCoverage(spec) {
3169
+ const exports = spec.exports ?? [];
3170
+ if (exports.length === 0)
3171
+ return 0;
3172
+ const totalScore = exports.reduce((sum, exp) => {
3173
+ const enriched = exp;
3174
+ return sum + (enriched.docs?.coverageScore ?? 0);
3175
+ }, 0);
3176
+ return Math.round(totalScore / exports.length);
3177
+ }
3178
+ function computeDriftMetrics(oldSpec, newSpec) {
3179
+ const oldDriftCount = countDriftIssues(oldSpec);
3180
+ const newDriftCount = countDriftIssues(newSpec);
3181
+ const driftIntroduced = Math.max(0, newDriftCount - oldDriftCount);
3182
+ const driftResolved = Math.max(0, oldDriftCount - newDriftCount);
3183
+ return { driftIntroduced, driftResolved };
3184
+ }
3185
+ function countDriftIssues(spec) {
3186
+ return (spec.exports ?? []).reduce((sum, exp) => {
3187
+ const enriched = exp;
3188
+ return sum + (enriched.docs?.drift?.length ?? 0);
3189
+ }, 0);
3190
+ }
3191
+ function hasDocumentation(exp) {
3192
+ return Boolean(exp.docs?.description || exp.description);
3193
+ }
3124
3194
  function hasDocsImpact(diff) {
3125
3195
  if (!diff.docsImpact)
3126
3196
  return false;
@@ -3575,6 +3645,7 @@ export {
3575
3645
  readPackageJson,
3576
3646
  pruneHistory,
3577
3647
  pruneByTier,
3648
+ previewForgottenExportFixes,
3578
3649
  parseGitHubUrl2 as parseScanGitHubUrl,
3579
3650
  parseMarkdownFiles,
3580
3651
  parseMarkdownFile,
@@ -3601,6 +3672,7 @@ export {
3601
3672
  hasNonAssertionComments,
3602
3673
  hasDocsImpact,
3603
3674
  hasDocsForExport,
3675
+ groupFixesByFile,
3604
3676
  groupDriftsByCategory,
3605
3677
  getUndocumentedExports,
3606
3678
  getTrend,
@@ -3622,6 +3694,7 @@ export {
3622
3694
  getDiffReportPath,
3623
3695
  generateReportFromDocCov,
3624
3696
  generateReport,
3697
+ generateForgottenExportFixes,
3625
3698
  generateFixesForExport,
3626
3699
  generateFix,
3627
3700
  formatPackageList,
@@ -3658,6 +3731,7 @@ export {
3658
3731
  createSourceFile,
3659
3732
  createNodeCommandRunner,
3660
3733
  computeSnapshot,
3734
+ computeHealth,
3661
3735
  computeExportDrift,
3662
3736
  computeDrift,
3663
3737
  clearSpecCache,
@@ -3671,6 +3745,7 @@ export {
3671
3745
  buildCloneUrl,
3672
3746
  blockReferencesExport,
3673
3747
  applyPatchToJSDoc,
3748
+ applyForgottenExportFixes,
3674
3749
  applyEdits,
3675
3750
  analyzeProject,
3676
3751
  analyzeFile,
@@ -3,6 +3,57 @@ import {
3
3
  REPORT_VERSION
4
4
  } from "./chunk-esptwrfq.js";
5
5
 
6
+ // src/analysis/health.ts
7
+ function computeHealth(input) {
8
+ const {
9
+ coverageScore,
10
+ documentedExports,
11
+ totalExports,
12
+ missingByRule,
13
+ driftIssues,
14
+ fixableDrift,
15
+ driftByCategory,
16
+ examples
17
+ } = input;
18
+ const completenessScore = coverageScore;
19
+ const driftRatio = documentedExports > 0 ? driftIssues / documentedExports : 0;
20
+ const driftPenalty = Math.min(driftRatio * 0.5, 0.5);
21
+ const accuracyScore = Math.round((1 - driftPenalty) * 100);
22
+ let exampleScore;
23
+ if (examples && examples.total > 0) {
24
+ exampleScore = Math.round(examples.passed / examples.total * 100);
25
+ }
26
+ let health = completenessScore * (1 - driftPenalty);
27
+ if (exampleScore !== undefined) {
28
+ const examplePenalty = (100 - exampleScore) / 100 * 0.3;
29
+ health = health * (1 - examplePenalty);
30
+ }
31
+ const result = {
32
+ score: Math.round(health),
33
+ completeness: {
34
+ score: Math.round(completenessScore),
35
+ documented: documentedExports,
36
+ total: totalExports,
37
+ missing: missingByRule
38
+ },
39
+ accuracy: {
40
+ score: accuracyScore,
41
+ issues: driftIssues,
42
+ fixable: fixableDrift,
43
+ byCategory: driftByCategory
44
+ }
45
+ };
46
+ if (examples) {
47
+ result.examples = {
48
+ score: exampleScore,
49
+ passed: examples.passed,
50
+ failed: examples.failed,
51
+ total: examples.total
52
+ };
53
+ }
54
+ return result;
55
+ }
56
+
6
57
  // src/fix/deterministic-fixes.ts
7
58
  var FIXABLE_DRIFT_TYPES = new Set([
8
59
  "param-mismatch",
@@ -797,6 +848,123 @@ function createSourceFile(filePath) {
797
848
  const content = fs.readFileSync(filePath, "utf-8");
798
849
  return ts.createSourceFile(path.basename(filePath), content, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
799
850
  }
851
+
852
+ // src/fix/forgotten-exports.ts
853
+ import * as fs2 from "node:fs";
854
+ import * as path2 from "node:path";
855
+ function generateForgottenExportFixes(apiSurface, options) {
856
+ const { baseDir, entryFile } = options;
857
+ const fixes = [];
858
+ for (const forgotten of apiSurface.forgotten) {
859
+ if (forgotten.isExternal)
860
+ continue;
861
+ if (!forgotten.fix)
862
+ continue;
863
+ const targetFile = forgotten.fix.targetFile ? path2.resolve(baseDir, forgotten.fix.targetFile) : path2.resolve(baseDir, entryFile);
864
+ fixes.push({
865
+ type: "forgotten-export",
866
+ typeName: forgotten.name,
867
+ targetFile,
868
+ exportStatement: forgotten.fix.exportStatement,
869
+ insertPosition: "append"
870
+ });
871
+ }
872
+ return fixes;
873
+ }
874
+ function groupFixesByFile(fixes) {
875
+ const grouped = new Map;
876
+ for (const fix of fixes) {
877
+ const existing = grouped.get(fix.targetFile) ?? [];
878
+ existing.push(fix);
879
+ grouped.set(fix.targetFile, existing);
880
+ }
881
+ return grouped;
882
+ }
883
+ async function applyForgottenExportFixes(fixes) {
884
+ const result = {
885
+ filesModified: 0,
886
+ fixesApplied: 0,
887
+ errors: []
888
+ };
889
+ const grouped = groupFixesByFile(fixes);
890
+ for (const [filePath, fileFixes] of grouped) {
891
+ try {
892
+ if (!fs2.existsSync(filePath)) {
893
+ result.errors.push({
894
+ file: filePath,
895
+ error: "File not found"
896
+ });
897
+ continue;
898
+ }
899
+ const content = await fs2.promises.readFile(filePath, "utf8");
900
+ const lines = content.split(`
901
+ `);
902
+ const insertLine = findBestInsertionPoint(lines, fileFixes);
903
+ const statements = fileFixes.map((f) => f.exportStatement);
904
+ const uniqueStatements = [...new Set(statements)];
905
+ const newContent = insertExportStatements(lines, insertLine, uniqueStatements);
906
+ await fs2.promises.writeFile(filePath, newContent, "utf8");
907
+ result.filesModified++;
908
+ result.fixesApplied += uniqueStatements.length;
909
+ } catch (err) {
910
+ result.errors.push({
911
+ file: filePath,
912
+ error: err instanceof Error ? err.message : String(err)
913
+ });
914
+ }
915
+ }
916
+ return result;
917
+ }
918
+ function findBestInsertionPoint(lines, _fixes) {
919
+ let lastExportLine = -1;
920
+ let lastReExportLine = -1;
921
+ for (let i = 0;i < lines.length; i++) {
922
+ const line = lines[i].trim();
923
+ if (line.match(/^export\s+(\*|\{[^}]*\})\s+from\s+['"]/)) {
924
+ lastReExportLine = i;
925
+ }
926
+ if (line.startsWith("export ")) {
927
+ lastExportLine = i;
928
+ }
929
+ }
930
+ if (lastReExportLine >= 0) {
931
+ return lastReExportLine + 1;
932
+ }
933
+ if (lastExportLine >= 0) {
934
+ return lastExportLine + 1;
935
+ }
936
+ return lines.length;
937
+ }
938
+ function insertExportStatements(lines, insertLine, statements) {
939
+ const newLines = [...lines];
940
+ const needsBlankBefore = insertLine > 0 && newLines[insertLine - 1]?.trim() !== "" && !newLines[insertLine - 1]?.trim().startsWith("export");
941
+ const insertBlock = statements.join(`
942
+ `);
943
+ if (needsBlankBefore) {
944
+ newLines.splice(insertLine, 0, "", insertBlock);
945
+ } else {
946
+ newLines.splice(insertLine, 0, insertBlock);
947
+ }
948
+ return newLines.join(`
949
+ `);
950
+ }
951
+ function previewForgottenExportFixes(fixes) {
952
+ const previews = new Map;
953
+ const grouped = groupFixesByFile(fixes);
954
+ for (const [filePath, fileFixes] of grouped) {
955
+ try {
956
+ if (!fs2.existsSync(filePath))
957
+ continue;
958
+ const content = fs2.readFileSync(filePath, "utf8");
959
+ const lines = content.split(`
960
+ `);
961
+ const insertLine = findBestInsertionPoint(lines, fileFixes);
962
+ const statements = [...new Set(fileFixes.map((f) => f.exportStatement))];
963
+ previews.set(filePath, { insertLine, statements });
964
+ } catch {}
965
+ }
966
+ return previews;
967
+ }
800
968
  // src/analysis/drift/example-drift.ts
801
969
  import ts2 from "typescript";
802
970
 
@@ -2019,7 +2187,7 @@ function computeExportDrift(entry, registry) {
2019
2187
  // src/analysis/doccov-builder.ts
2020
2188
  import { DRIFT_CATEGORIES } from "@doccov/spec";
2021
2189
  function buildDocCovSpec(options) {
2022
- const { openpkg, openpkgPath } = options;
2190
+ const { openpkg, openpkgPath, forgottenExports, apiSurfaceIgnore } = options;
2023
2191
  const registry = buildExportRegistry(openpkg);
2024
2192
  const exports = {};
2025
2193
  let totalScore = 0;
@@ -2062,8 +2230,18 @@ function buildDocCovSpec(options) {
2062
2230
  }
2063
2231
  }
2064
2232
  const exportCount = openpkg.exports?.length ?? 0;
2233
+ const coverageScore = exportCount > 0 ? Math.round(totalScore / exportCount) : 100;
2234
+ const health = computeHealth({
2235
+ coverageScore,
2236
+ documentedExports: documentedCount,
2237
+ totalExports: exportCount,
2238
+ missingByRule,
2239
+ driftIssues: totalDrift,
2240
+ fixableDrift,
2241
+ driftByCategory
2242
+ });
2065
2243
  const summary = {
2066
- score: exportCount > 0 ? Math.round(totalScore / exportCount) : 100,
2244
+ score: coverageScore,
2067
2245
  totalExports: exportCount,
2068
2246
  documentedExports: documentedCount,
2069
2247
  missingByRule,
@@ -2071,8 +2249,10 @@ function buildDocCovSpec(options) {
2071
2249
  total: totalDrift,
2072
2250
  fixable: fixableDrift,
2073
2251
  byCategory: driftByCategory
2074
- }
2252
+ },
2253
+ health
2075
2254
  };
2255
+ const apiSurface = computeApiSurface(forgottenExports, openpkg.types?.length ?? 0, apiSurfaceIgnore);
2076
2256
  return {
2077
2257
  doccov: "1.0.0",
2078
2258
  source: {
@@ -2083,7 +2263,33 @@ function buildDocCovSpec(options) {
2083
2263
  },
2084
2264
  generatedAt: new Date().toISOString(),
2085
2265
  summary,
2086
- exports
2266
+ exports,
2267
+ ...apiSurface ? { apiSurface } : {}
2268
+ };
2269
+ }
2270
+ function computeApiSurface(forgottenExports, exportedTypesCount, ignoreList) {
2271
+ if (!forgottenExports)
2272
+ return;
2273
+ const ignoreSet = new Set(ignoreList ?? []);
2274
+ const filteredExports = forgottenExports.filter((f) => !ignoreSet.has(f.name));
2275
+ const forgotten = filteredExports.map((f) => ({
2276
+ name: f.name,
2277
+ definedIn: f.definedIn ? { file: f.definedIn } : undefined,
2278
+ referencedBy: f.referencedBy.map((r) => ({
2279
+ exportName: r.exportName,
2280
+ location: r.location
2281
+ })),
2282
+ isExternal: f.isExternal,
2283
+ fix: f.fix ? { targetFile: f.definedIn ?? "index.ts", exportStatement: f.fix } : undefined
2284
+ }));
2285
+ const forgottenCount = forgotten.length;
2286
+ const totalReferenced = exportedTypesCount + forgottenCount;
2287
+ const completeness = totalReferenced > 0 ? Math.round(exportedTypesCount / totalReferenced * 100) : 100;
2288
+ return {
2289
+ totalReferenced,
2290
+ exported: exportedTypesCount,
2291
+ forgotten,
2292
+ completeness
2087
2293
  };
2088
2294
  }
2089
2295
  function computeExportCoverage(exp) {
@@ -2141,13 +2347,14 @@ function computeExportCoverage(exp) {
2141
2347
  }
2142
2348
  function toCategorizedDrift(drift) {
2143
2349
  const driftType = drift.type;
2350
+ const specDrift = { ...drift, type: driftType };
2144
2351
  return {
2145
2352
  type: driftType,
2146
2353
  target: drift.target,
2147
2354
  issue: drift.issue,
2148
2355
  suggestion: drift.suggestion,
2149
2356
  category: DRIFT_CATEGORIES[driftType],
2150
- fixable: isFixableDrift(drift)
2357
+ fixable: isFixableDrift(specDrift)
2151
2358
  };
2152
2359
  }
2153
2360
 
@@ -2285,8 +2492,8 @@ function isExportFullyDocumented(exp, doccov) {
2285
2492
  }
2286
2493
 
2287
2494
  // src/analysis/report.ts
2288
- import * as fs2 from "node:fs";
2289
- import * as path2 from "node:path";
2495
+ import * as fs3 from "node:fs";
2496
+ import * as path3 from "node:path";
2290
2497
  function generateReport(spec, openpkgPath = "openpkg.json") {
2291
2498
  const doccov = buildDocCovSpec({ openpkg: spec, openpkgPath });
2292
2499
  return generateReportFromDocCov(spec, doccov);
@@ -2339,28 +2546,29 @@ function generateReportFromDocCov(openpkg, doccov) {
2339
2546
  version: openpkg.meta.version
2340
2547
  },
2341
2548
  coverage,
2342
- exports: exportsData
2549
+ exports: exportsData,
2550
+ apiSurface: doccov.apiSurface
2343
2551
  };
2344
2552
  }
2345
2553
  function loadCachedReport(reportPath = DEFAULT_REPORT_PATH) {
2346
2554
  try {
2347
- const fullPath = path2.resolve(reportPath);
2348
- if (!fs2.existsSync(fullPath)) {
2555
+ const fullPath = path3.resolve(reportPath);
2556
+ if (!fs3.existsSync(fullPath)) {
2349
2557
  return null;
2350
2558
  }
2351
- const content = fs2.readFileSync(fullPath, "utf-8");
2559
+ const content = fs3.readFileSync(fullPath, "utf-8");
2352
2560
  return JSON.parse(content);
2353
2561
  } catch {
2354
2562
  return null;
2355
2563
  }
2356
2564
  }
2357
2565
  function saveReport(report, reportPath = DEFAULT_REPORT_PATH) {
2358
- const fullPath = path2.resolve(reportPath);
2359
- const dir = path2.dirname(fullPath);
2360
- if (!fs2.existsSync(dir)) {
2361
- fs2.mkdirSync(dir, { recursive: true });
2566
+ const fullPath = path3.resolve(reportPath);
2567
+ const dir = path3.dirname(fullPath);
2568
+ if (!fs3.existsSync(dir)) {
2569
+ fs3.mkdirSync(dir, { recursive: true });
2362
2570
  }
2363
- fs2.writeFileSync(fullPath, JSON.stringify(report, null, 2));
2571
+ fs3.writeFileSync(fullPath, JSON.stringify(report, null, 2));
2364
2572
  }
2365
2573
  function isCachedReportValid(reportPath = DEFAULT_REPORT_PATH, sourceFiles = []) {
2366
2574
  const report = loadCachedReport(reportPath);
@@ -2370,7 +2578,7 @@ function isCachedReportValid(reportPath = DEFAULT_REPORT_PATH, sourceFiles = [])
2370
2578
  const reportTime = new Date(report.generatedAt).getTime();
2371
2579
  for (const file of sourceFiles) {
2372
2580
  try {
2373
- const stat = fs2.statSync(file);
2581
+ const stat = fs3.statSync(file);
2374
2582
  if (stat.mtimeMs > reportTime) {
2375
2583
  return false;
2376
2584
  }
@@ -2559,8 +2767,8 @@ function renderApiSurface(spec) {
2559
2767
 
2560
2768
  // src/extract/schema/standard-schema.ts
2561
2769
  import { spawn } from "node:child_process";
2562
- import * as fs3 from "node:fs";
2563
- import * as path3 from "node:path";
2770
+ import * as fs4 from "node:fs";
2771
+ import * as path4 from "node:path";
2564
2772
  function isStandardJSONSchema(obj) {
2565
2773
  if (typeof obj !== "object" || obj === null)
2566
2774
  return false;
@@ -2667,16 +2875,16 @@ async function extract() {
2667
2875
  extract();
2668
2876
  `;
2669
2877
  function resolveCompiledPath(tsPath, baseDir) {
2670
- const relativePath = path3.relative(baseDir, tsPath);
2878
+ const relativePath = path4.relative(baseDir, tsPath);
2671
2879
  const withoutExt = relativePath.replace(/\.tsx?$/, "");
2672
2880
  const candidates = [
2673
- path3.join(baseDir, `${withoutExt}.js`),
2674
- path3.join(baseDir, "dist", `${withoutExt.replace(/^src\//, "")}.js`),
2675
- path3.join(baseDir, "build", `${withoutExt.replace(/^src\//, "")}.js`),
2676
- path3.join(baseDir, "lib", `${withoutExt.replace(/^src\//, "")}.js`)
2881
+ path4.join(baseDir, `${withoutExt}.js`),
2882
+ path4.join(baseDir, "dist", `${withoutExt.replace(/^src\//, "")}.js`),
2883
+ path4.join(baseDir, "build", `${withoutExt.replace(/^src\//, "")}.js`),
2884
+ path4.join(baseDir, "lib", `${withoutExt.replace(/^src\//, "")}.js`)
2677
2885
  ];
2678
2886
  for (const candidate of candidates) {
2679
- if (fs3.existsSync(candidate)) {
2887
+ if (fs4.existsSync(candidate)) {
2680
2888
  return candidate;
2681
2889
  }
2682
2890
  }
@@ -2688,11 +2896,11 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
2688
2896
  schemas: new Map,
2689
2897
  errors: []
2690
2898
  };
2691
- if (!fs3.existsSync(compiledJsPath)) {
2899
+ if (!fs4.existsSync(compiledJsPath)) {
2692
2900
  result.errors.push(`Compiled JS not found: ${compiledJsPath}`);
2693
2901
  return result;
2694
2902
  }
2695
- return new Promise((resolve2) => {
2903
+ return new Promise((resolve3) => {
2696
2904
  const child = spawn("node", ["-e", WORKER_SCRIPT, compiledJsPath, target], {
2697
2905
  timeout,
2698
2906
  stdio: ["ignore", "pipe", "pipe"]
@@ -2708,14 +2916,14 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
2708
2916
  child.on("close", (code) => {
2709
2917
  if (code !== 0) {
2710
2918
  result.errors.push(`Extraction process failed: ${stderr || `exit code ${code}`}`);
2711
- resolve2(result);
2919
+ resolve3(result);
2712
2920
  return;
2713
2921
  }
2714
2922
  try {
2715
2923
  const parsed = JSON.parse(stdout);
2716
2924
  if (!parsed.success) {
2717
2925
  result.errors.push(`Extraction failed: ${parsed.error}`);
2718
- resolve2(result);
2926
+ resolve3(result);
2719
2927
  return;
2720
2928
  }
2721
2929
  for (const item of parsed.results) {
@@ -2729,11 +2937,11 @@ async function extractStandardSchemas(compiledJsPath, options = {}) {
2729
2937
  } catch (e) {
2730
2938
  result.errors.push(`Failed to parse extraction output: ${e}`);
2731
2939
  }
2732
- resolve2(result);
2940
+ resolve3(result);
2733
2941
  });
2734
2942
  child.on("error", (err) => {
2735
2943
  result.errors.push(`Subprocess error: ${err.message}`);
2736
- resolve2(result);
2944
+ resolve3(result);
2737
2945
  });
2738
2946
  });
2739
2947
  }
@@ -2774,8 +2982,8 @@ async function detectRuntimeSchemas(context) {
2774
2982
  }
2775
2983
 
2776
2984
  // src/analysis/history.ts
2777
- import * as fs4 from "node:fs";
2778
- import * as path4 from "node:path";
2985
+ import * as fs5 from "node:fs";
2986
+ import * as path5 from "node:path";
2779
2987
  var HISTORY_DIR = ".doccov/history";
2780
2988
  var RETENTION_DAYS = {
2781
2989
  free: 7,
@@ -2813,24 +3021,24 @@ function computeSnapshot(spec, options) {
2813
3021
  };
2814
3022
  }
2815
3023
  function saveSnapshot(snapshot, cwd) {
2816
- const historyDir = path4.resolve(cwd, HISTORY_DIR);
2817
- if (!fs4.existsSync(historyDir)) {
2818
- fs4.mkdirSync(historyDir, { recursive: true });
3024
+ const historyDir = path5.resolve(cwd, HISTORY_DIR);
3025
+ if (!fs5.existsSync(historyDir)) {
3026
+ fs5.mkdirSync(historyDir, { recursive: true });
2819
3027
  }
2820
3028
  const filename = getSnapshotFilename(new Date(snapshot.timestamp));
2821
- const filepath = path4.join(historyDir, filename);
2822
- fs4.writeFileSync(filepath, JSON.stringify(snapshot, null, 2));
3029
+ const filepath = path5.join(historyDir, filename);
3030
+ fs5.writeFileSync(filepath, JSON.stringify(snapshot, null, 2));
2823
3031
  }
2824
3032
  function loadSnapshots(cwd) {
2825
- const historyDir = path4.resolve(cwd, HISTORY_DIR);
2826
- if (!fs4.existsSync(historyDir)) {
3033
+ const historyDir = path5.resolve(cwd, HISTORY_DIR);
3034
+ if (!fs5.existsSync(historyDir)) {
2827
3035
  return [];
2828
3036
  }
2829
- const files = fs4.readdirSync(historyDir).filter((f) => f.endsWith(".json")).sort().reverse();
3037
+ const files = fs5.readdirSync(historyDir).filter((f) => f.endsWith(".json")).sort().reverse();
2830
3038
  const snapshots = [];
2831
3039
  for (const file of files) {
2832
3040
  try {
2833
- const content = fs4.readFileSync(path4.join(historyDir, file), "utf-8");
3041
+ const content = fs5.readFileSync(path5.join(historyDir, file), "utf-8");
2834
3042
  snapshots.push(JSON.parse(content));
2835
3043
  } catch {}
2836
3044
  }
@@ -2870,15 +3078,15 @@ function formatDelta(delta) {
2870
3078
  return "→0%";
2871
3079
  }
2872
3080
  function pruneHistory(cwd, keepCount = 100) {
2873
- const historyDir = path4.resolve(cwd, HISTORY_DIR);
2874
- if (!fs4.existsSync(historyDir)) {
3081
+ const historyDir = path5.resolve(cwd, HISTORY_DIR);
3082
+ if (!fs5.existsSync(historyDir)) {
2875
3083
  return 0;
2876
3084
  }
2877
- const files = fs4.readdirSync(historyDir).filter((f) => f.endsWith(".json")).sort().reverse();
3085
+ const files = fs5.readdirSync(historyDir).filter((f) => f.endsWith(".json")).sort().reverse();
2878
3086
  const toDelete = files.slice(keepCount);
2879
3087
  for (const file of toDelete) {
2880
3088
  try {
2881
- fs4.unlinkSync(path4.join(historyDir, file));
3089
+ fs5.unlinkSync(path5.join(historyDir, file));
2882
3090
  } catch {}
2883
3091
  }
2884
3092
  return toDelete.length;
@@ -2887,20 +3095,20 @@ function pruneByTier(cwd, tier) {
2887
3095
  const retentionDays = RETENTION_DAYS[tier];
2888
3096
  const cutoffDate = new Date;
2889
3097
  cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
2890
- const historyDir = path4.resolve(cwd, HISTORY_DIR);
2891
- if (!fs4.existsSync(historyDir)) {
3098
+ const historyDir = path5.resolve(cwd, HISTORY_DIR);
3099
+ if (!fs5.existsSync(historyDir)) {
2892
3100
  return 0;
2893
3101
  }
2894
- const files = fs4.readdirSync(historyDir).filter((f) => f.endsWith(".json"));
3102
+ const files = fs5.readdirSync(historyDir).filter((f) => f.endsWith(".json"));
2895
3103
  let deleted = 0;
2896
3104
  for (const file of files) {
2897
3105
  try {
2898
- const filepath = path4.join(historyDir, file);
2899
- const content = fs4.readFileSync(filepath, "utf-8");
3106
+ const filepath = path5.join(historyDir, file);
3107
+ const content = fs5.readFileSync(filepath, "utf-8");
2900
3108
  const snapshot = JSON.parse(content);
2901
3109
  const snapshotDate = new Date(snapshot.timestamp);
2902
3110
  if (snapshotDate < cutoffDate) {
2903
- fs4.unlinkSync(filepath);
3111
+ fs5.unlinkSync(filepath);
2904
3112
  deleted++;
2905
3113
  }
2906
3114
  } catch {}
@@ -3000,4 +3208,4 @@ function getExtendedTrend(spec, cwd, options) {
3000
3208
  };
3001
3209
  }
3002
3210
 
3003
- export { isFixableDrift, generateFix, generateFixesForExport, mergeFixes, categorizeDrifts, ts, parseJSDocToPatch, applyPatchToJSDoc, serializeJSDoc, findJSDocLocation, applyEdits, createSourceFile, isBuiltInIdentifier, detectExampleRuntimeErrors, parseAssertions, hasNonAssertionComments, detectExampleAssertionFailures, buildExportRegistry, computeDrift, computeExportDrift, buildDocCovSpec, DRIFT_CATEGORIES2 as DRIFT_CATEGORIES, DRIFT_CATEGORY_LABELS, DRIFT_CATEGORY_DESCRIPTIONS, categorizeDrift, groupDriftsByCategory, getDriftSummary, formatDriftSummaryLine, calculateAggregateCoverage, ensureSpecCoverage, getExportAnalysis, getExportScore, getExportDrift, getExportMissing, isExportFullyDocumented, generateReport, generateReportFromDocCov, loadCachedReport, saveReport, isCachedReportValid, renderApiSurface, isStandardJSONSchema, resolveCompiledPath, extractStandardSchemas, extractStandardSchemasFromProject, detectRuntimeSchemas, HISTORY_DIR, RETENTION_DAYS, computeSnapshot, saveSnapshot, loadSnapshots, getTrend, renderSparkline, formatDelta, pruneHistory, pruneByTier, loadSnapshotsForDays, generateWeeklySummaries, getExtendedTrend };
3211
+ export { computeHealth, isFixableDrift, generateFix, generateFixesForExport, mergeFixes, categorizeDrifts, ts, parseJSDocToPatch, applyPatchToJSDoc, serializeJSDoc, findJSDocLocation, applyEdits, createSourceFile, generateForgottenExportFixes, groupFixesByFile, applyForgottenExportFixes, previewForgottenExportFixes, isBuiltInIdentifier, detectExampleRuntimeErrors, parseAssertions, hasNonAssertionComments, detectExampleAssertionFailures, buildExportRegistry, computeDrift, computeExportDrift, buildDocCovSpec, DRIFT_CATEGORIES2 as DRIFT_CATEGORIES, DRIFT_CATEGORY_LABELS, DRIFT_CATEGORY_DESCRIPTIONS, categorizeDrift, groupDriftsByCategory, getDriftSummary, formatDriftSummaryLine, calculateAggregateCoverage, ensureSpecCoverage, getExportAnalysis, getExportScore, getExportDrift, getExportMissing, isExportFullyDocumented, generateReport, generateReportFromDocCov, loadCachedReport, saveReport, isCachedReportValid, renderApiSurface, isStandardJSONSchema, resolveCompiledPath, extractStandardSchemas, extractStandardSchemasFromProject, detectRuntimeSchemas, HISTORY_DIR, RETENTION_DAYS, computeSnapshot, saveSnapshot, loadSnapshots, getTrend, renderSparkline, formatDelta, pruneHistory, pruneByTier, loadSnapshotsForDays, generateWeeklySummaries, getExtendedTrend };
@@ -24,6 +24,17 @@ type ExampleValidationMode = "presence" | "typecheck" | "run";
24
24
  */
25
25
  type SchemaExtractionMode = "static" | "runtime" | "hybrid";
26
26
  /**
27
+ * API surface configuration options.
28
+ */
29
+ interface ApiSurfaceConfig {
30
+ /** Minimum completeness percentage to pass (0-100) */
31
+ minCompleteness?: number;
32
+ /** Warning threshold - warn when below this (0-100) */
33
+ warnBelow?: number;
34
+ /** Type names to ignore (won't be flagged as forgotten exports) */
35
+ ignore?: string[];
36
+ }
37
+ /**
27
38
  * Check command configuration options.
28
39
  */
29
40
  interface CheckConfig {
@@ -35,10 +46,22 @@ interface CheckConfig {
35
46
  * - 'run': Execute examples and validate assertions
36
47
  */
37
48
  examples?: ExampleValidationMode | ExampleValidationMode[] | string;
38
- /** Minimum coverage percentage required (0-100) */
49
+ /** Minimum health score required (0-100). Unified metric combining coverage + accuracy. */
50
+ minHealth?: number;
51
+ /**
52
+ * Minimum coverage percentage required (0-100)
53
+ * @deprecated Use `minHealth` instead. Will be removed in next major.
54
+ */
39
55
  minCoverage?: number;
40
- /** Maximum drift percentage allowed (0-100) */
56
+ /**
57
+ * Maximum drift percentage allowed (0-100)
58
+ * @deprecated Use `minHealth` instead. Drift is now factored into health score.
59
+ */
41
60
  maxDrift?: number;
61
+ /** Minimum API surface completeness percentage (0-100) - deprecated, use apiSurface.minCompleteness */
62
+ minApiSurface?: number;
63
+ /** API surface configuration */
64
+ apiSurface?: ApiSurfaceConfig;
42
65
  }
43
66
  /**
44
67
  * Normalized DocCov configuration.
@@ -155,6 +178,7 @@ interface CategorizedDrift extends SpecDocDrift {
155
178
  category: DriftCategory;
156
179
  fixable: boolean;
157
180
  }
181
+ import { ApiSurfaceResult, DocumentationHealth } from "@doccov/spec";
158
182
  /**
159
183
  * DocCov report schema version.
160
184
  */
@@ -330,5 +354,13 @@ interface DocCovReport {
330
354
  * Per-coverage data, keyed by ID.
331
355
  */
332
356
  exports: Record<string, ExportCoverageData>;
357
+ /**
358
+ * API surface analysis (forgotten exports).
359
+ */
360
+ apiSurface?: ApiSurfaceResult;
361
+ /**
362
+ * Unified documentation health score.
363
+ */
364
+ health?: DocumentationHealth;
333
365
  }
334
366
  export { parseListFlag, mergeFilters, getReportPath, getDiffReportPath, ResolvedFilters, ReleaseTag, REPORT_VERSION, REPORT_EXTENSIONS, FilterSource, FilterOptions, ExportCoverageData, DriftReportSummary, DriftReport, DocCovReport, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageSummary };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doccov/sdk",
3
- "version": "0.25.12",
3
+ "version": "0.27.0",
4
4
  "description": "DocCov SDK - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
@@ -47,8 +47,8 @@
47
47
  "dist"
48
48
  ],
49
49
  "dependencies": {
50
- "@doccov/spec": "^0.24.1",
51
- "@openpkg-ts/extract": "^0.15.0",
50
+ "@doccov/spec": "^0.27.0",
51
+ "@openpkg-ts/extract": "^0.16.0",
52
52
  "@openpkg-ts/spec": "^0.12.0",
53
53
  "@vercel/sandbox": "^1.0.3",
54
54
  "mdast": "^3.0.0",