@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.
- package/dist/analysis/index.d.ts +28 -2
- package/dist/analysis/index.js +1 -1
- package/dist/index.d.ts +182 -18
- package/dist/index.js +90 -15
- package/dist/shared/{chunk-cbe8089a.js → chunk-v62zsv8j.js} +261 -53
- package/dist/types/index.d.ts +34 -2
- package/package.json +3 -3
package/dist/analysis/index.d.ts
CHANGED
|
@@ -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 };
|
package/dist/analysis/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,63 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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,
|
|
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<
|
|
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<
|
|
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:
|
|
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<
|
|
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<
|
|
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):
|
|
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<
|
|
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<
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
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?:
|
|
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-
|
|
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.
|
|
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
|
-
...
|
|
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:
|
|
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(
|
|
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
|
|
2289
|
-
import * as
|
|
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 =
|
|
2348
|
-
if (!
|
|
2555
|
+
const fullPath = path3.resolve(reportPath);
|
|
2556
|
+
if (!fs3.existsSync(fullPath)) {
|
|
2349
2557
|
return null;
|
|
2350
2558
|
}
|
|
2351
|
-
const content =
|
|
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 =
|
|
2359
|
-
const dir =
|
|
2360
|
-
if (!
|
|
2361
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
2563
|
-
import * as
|
|
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 =
|
|
2878
|
+
const relativePath = path4.relative(baseDir, tsPath);
|
|
2671
2879
|
const withoutExt = relativePath.replace(/\.tsx?$/, "");
|
|
2672
2880
|
const candidates = [
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
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 (
|
|
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 (!
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2940
|
+
resolve3(result);
|
|
2733
2941
|
});
|
|
2734
2942
|
child.on("error", (err) => {
|
|
2735
2943
|
result.errors.push(`Subprocess error: ${err.message}`);
|
|
2736
|
-
|
|
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
|
|
2778
|
-
import * as
|
|
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 =
|
|
2817
|
-
if (!
|
|
2818
|
-
|
|
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 =
|
|
2822
|
-
|
|
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 =
|
|
2826
|
-
if (!
|
|
3033
|
+
const historyDir = path5.resolve(cwd, HISTORY_DIR);
|
|
3034
|
+
if (!fs5.existsSync(historyDir)) {
|
|
2827
3035
|
return [];
|
|
2828
3036
|
}
|
|
2829
|
-
const files =
|
|
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 =
|
|
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 =
|
|
2874
|
-
if (!
|
|
3081
|
+
const historyDir = path5.resolve(cwd, HISTORY_DIR);
|
|
3082
|
+
if (!fs5.existsSync(historyDir)) {
|
|
2875
3083
|
return 0;
|
|
2876
3084
|
}
|
|
2877
|
-
const files =
|
|
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
|
-
|
|
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 =
|
|
2891
|
-
if (!
|
|
3098
|
+
const historyDir = path5.resolve(cwd, HISTORY_DIR);
|
|
3099
|
+
if (!fs5.existsSync(historyDir)) {
|
|
2892
3100
|
return 0;
|
|
2893
3101
|
}
|
|
2894
|
-
const files =
|
|
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 =
|
|
2899
|
-
const content =
|
|
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
|
-
|
|
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 };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
/**
|
|
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.
|
|
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.
|
|
51
|
-
"@openpkg-ts/extract": "^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",
|