@aiready/doc-drift 0.13.4 → 0.13.6
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/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-test.log +6 -6
- package/dist/{chunk-NWJ6PSNT.mjs → chunk-6EHZXHM7.mjs} +26 -12
- package/dist/chunk-MAPV5YQR.mjs +142 -0
- package/dist/{chunk-5BGWZWHD.mjs → chunk-P74XAVQ3.mjs} +21 -6
- package/dist/cli.js +21 -9
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +39 -20
- package/dist/index.mjs +19 -12
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +1 -0
- package/src/__tests__/provider.test.ts +1 -0
- package/src/__tests__/scoring.test.ts +1 -0
- package/src/analyzer.ts +34 -20
- package/src/scoring.ts +29 -12
- package/src/types.ts +2 -0
- package/dist/chunk-5EFFNN6L.mjs +0 -145
- package/dist/chunk-BBGJNBVI.mjs +0 -189
- package/dist/chunk-CGSYYULO.mjs +0 -145
- package/dist/chunk-E3YCVHHH.mjs +0 -152
- package/dist/chunk-FMK4O4O7.mjs +0 -143
- package/dist/chunk-TSLAGWBV.mjs +0 -165
- package/dist/chunk-VLBPAYS3.mjs +0 -209
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/doc-drift@0.13.
|
|
3
|
+
> @aiready/doc-drift@0.13.6 build /Users/pengcao/projects/aiready/packages/doc-drift
|
|
4
4
|
> tsup src/index.ts src/cli.ts --format cjs,esm --dts
|
|
5
5
|
|
|
6
6
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
[34mCLI[39m Target: es2020
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
-
[32mESM[39m [1mdist/
|
|
13
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m2.37 KB[39m
|
|
12
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m2.59 KB[39m
|
|
14
13
|
[32mESM[39m [1mdist/cli.mjs [22m[32m1.39 KB[39m
|
|
15
|
-
[32mESM[39m
|
|
16
|
-
[
|
|
17
|
-
[32mCJS[39m [1mdist/
|
|
18
|
-
[32mCJS[39m
|
|
14
|
+
[32mESM[39m [1mdist/chunk-MAPV5YQR.mjs [22m[32m4.40 KB[39m
|
|
15
|
+
[32mESM[39m ⚡️ Build success in 55ms
|
|
16
|
+
[32mCJS[39m [1mdist/index.js [22m[32m7.71 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m7.11 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 56ms
|
|
19
19
|
DTS Build start
|
|
20
|
-
DTS ⚡️ Build success in
|
|
20
|
+
DTS ⚡️ Build success in 4610ms
|
|
21
21
|
DTS dist/cli.d.ts 108.00 B
|
|
22
|
-
DTS dist/index.d.ts 2.
|
|
22
|
+
DTS dist/index.d.ts 2.83 KB
|
|
23
23
|
DTS dist/cli.d.mts 108.00 B
|
|
24
|
-
DTS dist/index.d.mts 2.
|
|
24
|
+
DTS dist/index.d.mts 2.83 KB
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/doc-drift@0.13.
|
|
3
|
+
> @aiready/doc-drift@0.13.5 test /Users/pengcao/projects/aiready/packages/doc-drift
|
|
4
4
|
> vitest run
|
|
5
5
|
|
|
6
6
|
[?25l
|
|
7
7
|
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/pengcao/projects/aiready/packages/doc-drift[39m
|
|
8
8
|
|
|
9
|
-
[32m✓[39m src/__tests__/
|
|
10
|
-
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m1 test[22m[2m)[22m[
|
|
11
|
-
[32m✓[39m src/__tests__/
|
|
9
|
+
[32m✓[39m src/__tests__/provider.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m1 test[22m[2m)[22m[33m 316[2mms[22m[39m
|
|
11
|
+
[32m✓[39m src/__tests__/scoring.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 47[2mms[22m[39m
|
|
12
12
|
|
|
13
13
|
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
14
14
|
[2m Tests [22m [1m[32m5 passed[39m[22m[90m (5)[39m
|
|
15
|
-
[2m Start at [22m 10:
|
|
16
|
-
[2m Duration [22m
|
|
15
|
+
[2m Start at [22m 10:12:34
|
|
16
|
+
[2m Duration [22m 5.35s[2m (transform 2.37s, setup 0ms, import 10.75s, tests 370ms, environment 5ms)[22m
|
|
17
17
|
|
|
18
18
|
[?25h
|
|
@@ -21,12 +21,11 @@ async function analyzeDocDrift(options) {
|
|
|
21
21
|
const files = await scanFiles(options);
|
|
22
22
|
const issues = [];
|
|
23
23
|
const staleMonths = options.staleMonths ?? 6;
|
|
24
|
-
const staleSeconds = staleMonths * 30 * 24 * 60 * 60;
|
|
25
24
|
let uncommentedExports = 0;
|
|
26
25
|
let totalExports = 0;
|
|
27
26
|
let outdatedComments = 0;
|
|
28
27
|
let undocumentedComplexity = 0;
|
|
29
|
-
|
|
28
|
+
let actualDrift = 0;
|
|
30
29
|
let processed = 0;
|
|
31
30
|
for (const file of files) {
|
|
32
31
|
processed++;
|
|
@@ -63,10 +62,11 @@ async function analyzeDocDrift(options) {
|
|
|
63
62
|
const docContent = doc.content;
|
|
64
63
|
if (exp.type === "function" && exp.parameters) {
|
|
65
64
|
const params = exp.parameters;
|
|
66
|
-
const missingParams = params.filter(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
const missingParams = params.filter((p) => {
|
|
66
|
+
const regex = new RegExp(`\\b${p}\\b`, "i");
|
|
67
|
+
return !regex.test(docContent);
|
|
68
|
+
});
|
|
69
|
+
if (missingParams.length > 0) {
|
|
70
70
|
outdatedComments++;
|
|
71
71
|
issues.push({
|
|
72
72
|
type: IssueType.DocDrift,
|
|
@@ -74,10 +74,9 @@ async function analyzeDocDrift(options) {
|
|
|
74
74
|
message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
|
|
75
75
|
location: { file, line: exp.loc?.start.line || 1 }
|
|
76
76
|
});
|
|
77
|
-
continue;
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
|
-
if (exp.loc) {
|
|
79
|
+
if (exp.loc && doc.loc) {
|
|
81
80
|
if (!fileLineStamps) {
|
|
82
81
|
fileLineStamps = getFileCommitTimestamps(file);
|
|
83
82
|
}
|
|
@@ -86,8 +85,21 @@ async function analyzeDocDrift(options) {
|
|
|
86
85
|
exp.loc.start.line,
|
|
87
86
|
exp.loc.end.line
|
|
88
87
|
);
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const docModified = getLineRangeLastModifiedCached(
|
|
89
|
+
fileLineStamps,
|
|
90
|
+
doc.loc.start.line,
|
|
91
|
+
doc.loc.end.line
|
|
92
|
+
);
|
|
93
|
+
if (bodyModified > 0 && docModified > 0) {
|
|
94
|
+
const DRIFT_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
95
|
+
if (bodyModified - docModified > DRIFT_THRESHOLD_SECONDS) {
|
|
96
|
+
actualDrift++;
|
|
97
|
+
issues.push({
|
|
98
|
+
type: IssueType.DocDrift,
|
|
99
|
+
severity: Severity.Major,
|
|
100
|
+
message: `Documentation drift: logic was modified on ${new Date(bodyModified * 1e3).toLocaleDateString()} but documentation was last updated on ${new Date(docModified * 1e3).toLocaleDateString()}.`,
|
|
101
|
+
location: { file, line: doc.loc.start.line }
|
|
102
|
+
});
|
|
91
103
|
}
|
|
92
104
|
}
|
|
93
105
|
}
|
|
@@ -103,7 +115,8 @@ async function analyzeDocDrift(options) {
|
|
|
103
115
|
uncommentedExports,
|
|
104
116
|
totalExports,
|
|
105
117
|
outdatedComments,
|
|
106
|
-
undocumentedComplexity
|
|
118
|
+
undocumentedComplexity,
|
|
119
|
+
actualDrift
|
|
107
120
|
});
|
|
108
121
|
return {
|
|
109
122
|
summary: {
|
|
@@ -117,7 +130,8 @@ async function analyzeDocDrift(options) {
|
|
|
117
130
|
uncommentedExports,
|
|
118
131
|
totalExports,
|
|
119
132
|
outdatedComments,
|
|
120
|
-
undocumentedComplexity
|
|
133
|
+
undocumentedComplexity,
|
|
134
|
+
actualDrift
|
|
121
135
|
},
|
|
122
136
|
recommendations: riskResult.recommendations
|
|
123
137
|
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/analyzer.ts
|
|
9
|
+
import {
|
|
10
|
+
scanFiles,
|
|
11
|
+
calculateDocDrift,
|
|
12
|
+
getFileCommitTimestamps,
|
|
13
|
+
getLineRangeLastModifiedCached,
|
|
14
|
+
Severity,
|
|
15
|
+
IssueType,
|
|
16
|
+
emitProgress,
|
|
17
|
+
getParser
|
|
18
|
+
} from "@aiready/core";
|
|
19
|
+
import { readFileSync } from "fs";
|
|
20
|
+
async function analyzeDocDrift(options) {
|
|
21
|
+
const files = await scanFiles(options);
|
|
22
|
+
const issues = [];
|
|
23
|
+
let uncommentedExports = 0;
|
|
24
|
+
let totalExports = 0;
|
|
25
|
+
let outdatedComments = 0;
|
|
26
|
+
let undocumentedComplexity = 0;
|
|
27
|
+
let actualDrift = 0;
|
|
28
|
+
let processed = 0;
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
processed++;
|
|
31
|
+
emitProgress(
|
|
32
|
+
processed,
|
|
33
|
+
files.length,
|
|
34
|
+
"doc-drift",
|
|
35
|
+
"analyzing files",
|
|
36
|
+
options.onProgress
|
|
37
|
+
);
|
|
38
|
+
const parser = getParser(file);
|
|
39
|
+
if (!parser) continue;
|
|
40
|
+
let code;
|
|
41
|
+
try {
|
|
42
|
+
code = readFileSync(file, "utf-8");
|
|
43
|
+
} catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
await parser.initialize();
|
|
48
|
+
const parseResult = parser.parse(code, file);
|
|
49
|
+
let fileLineStamps;
|
|
50
|
+
for (const exp of parseResult.exports) {
|
|
51
|
+
if (exp.type === "function" || exp.type === "class") {
|
|
52
|
+
totalExports++;
|
|
53
|
+
if (!exp.documentation) {
|
|
54
|
+
uncommentedExports++;
|
|
55
|
+
if (exp.loc) {
|
|
56
|
+
const lines = exp.loc.end.line - exp.loc.start.line;
|
|
57
|
+
if (lines > 20) undocumentedComplexity++;
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
const doc = exp.documentation;
|
|
61
|
+
const docContent = doc.content;
|
|
62
|
+
if (exp.type === "function" && exp.parameters) {
|
|
63
|
+
const params = exp.parameters;
|
|
64
|
+
const missingParams = params.filter((p) => {
|
|
65
|
+
const regex = new RegExp(`\\b${p}\\b`, "i");
|
|
66
|
+
return !regex.test(docContent);
|
|
67
|
+
});
|
|
68
|
+
if (missingParams.length > 0) {
|
|
69
|
+
outdatedComments++;
|
|
70
|
+
issues.push({
|
|
71
|
+
type: IssueType.DocDrift,
|
|
72
|
+
severity: Severity.Major,
|
|
73
|
+
message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
|
|
74
|
+
location: { file, line: exp.loc?.start.line || 1 }
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (exp.loc && doc.loc) {
|
|
79
|
+
if (!fileLineStamps) {
|
|
80
|
+
fileLineStamps = getFileCommitTimestamps(file);
|
|
81
|
+
}
|
|
82
|
+
const bodyModified = getLineRangeLastModifiedCached(
|
|
83
|
+
fileLineStamps,
|
|
84
|
+
exp.loc.start.line,
|
|
85
|
+
exp.loc.end.line
|
|
86
|
+
);
|
|
87
|
+
const docModified = getLineRangeLastModifiedCached(
|
|
88
|
+
fileLineStamps,
|
|
89
|
+
doc.loc.start.line,
|
|
90
|
+
doc.loc.end.line
|
|
91
|
+
);
|
|
92
|
+
if (bodyModified > 0 && docModified > 0) {
|
|
93
|
+
const DRIFT_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
94
|
+
if (bodyModified - docModified > DRIFT_THRESHOLD_SECONDS) {
|
|
95
|
+
actualDrift++;
|
|
96
|
+
issues.push({
|
|
97
|
+
type: IssueType.DocDrift,
|
|
98
|
+
severity: Severity.Major,
|
|
99
|
+
message: `Documentation drift: logic was modified on ${new Date(bodyModified * 1e3).toLocaleDateString()} but documentation was last updated on ${new Date(docModified * 1e3).toLocaleDateString()}.`,
|
|
100
|
+
location: { file, line: doc.loc.start.line }
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.warn(`Doc-drift: Failed to parse ${file}: ${error}`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const riskResult = calculateDocDrift({
|
|
114
|
+
uncommentedExports,
|
|
115
|
+
totalExports,
|
|
116
|
+
outdatedComments,
|
|
117
|
+
undocumentedComplexity,
|
|
118
|
+
actualDrift
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
summary: {
|
|
122
|
+
filesAnalyzed: files.length,
|
|
123
|
+
functionsAnalyzed: totalExports,
|
|
124
|
+
score: riskResult.score,
|
|
125
|
+
rating: riskResult.rating
|
|
126
|
+
},
|
|
127
|
+
issues,
|
|
128
|
+
rawData: {
|
|
129
|
+
uncommentedExports,
|
|
130
|
+
totalExports,
|
|
131
|
+
outdatedComments,
|
|
132
|
+
undocumentedComplexity,
|
|
133
|
+
actualDrift
|
|
134
|
+
},
|
|
135
|
+
recommendations: riskResult.recommendations
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
__require,
|
|
141
|
+
analyzeDocDrift
|
|
142
|
+
};
|
|
@@ -26,6 +26,7 @@ async function analyzeDocDrift(options) {
|
|
|
26
26
|
let totalExports = 0;
|
|
27
27
|
let outdatedComments = 0;
|
|
28
28
|
let undocumentedComplexity = 0;
|
|
29
|
+
let actualDrift = 0;
|
|
29
30
|
const now = Math.floor(Date.now() / 1e3);
|
|
30
31
|
let processed = 0;
|
|
31
32
|
for (const file of files) {
|
|
@@ -75,10 +76,9 @@ async function analyzeDocDrift(options) {
|
|
|
75
76
|
message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
|
|
76
77
|
location: { file, line: exp.loc?.start.line || 1 }
|
|
77
78
|
});
|
|
78
|
-
continue;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
if (exp.loc) {
|
|
81
|
+
if (exp.loc && doc.loc) {
|
|
82
82
|
if (!fileLineStamps) {
|
|
83
83
|
fileLineStamps = getFileCommitTimestamps(file);
|
|
84
84
|
}
|
|
@@ -87,8 +87,21 @@ async function analyzeDocDrift(options) {
|
|
|
87
87
|
exp.loc.start.line,
|
|
88
88
|
exp.loc.end.line
|
|
89
89
|
);
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const docModified = getLineRangeLastModifiedCached(
|
|
91
|
+
fileLineStamps,
|
|
92
|
+
doc.loc.start.line,
|
|
93
|
+
doc.loc.end.line
|
|
94
|
+
);
|
|
95
|
+
if (bodyModified > 0 && docModified > 0) {
|
|
96
|
+
const DRIFT_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
97
|
+
if (bodyModified - docModified > DRIFT_THRESHOLD_SECONDS) {
|
|
98
|
+
actualDrift++;
|
|
99
|
+
issues.push({
|
|
100
|
+
type: IssueType.DocDrift,
|
|
101
|
+
severity: Severity.Major,
|
|
102
|
+
message: `Documentation drift: logic was modified on ${new Date(bodyModified * 1e3).toLocaleDateString()} but documentation was last updated on ${new Date(docModified * 1e3).toLocaleDateString()}.`,
|
|
103
|
+
location: { file, line: doc.loc.start.line }
|
|
104
|
+
});
|
|
92
105
|
}
|
|
93
106
|
}
|
|
94
107
|
}
|
|
@@ -104,7 +117,8 @@ async function analyzeDocDrift(options) {
|
|
|
104
117
|
uncommentedExports,
|
|
105
118
|
totalExports,
|
|
106
119
|
outdatedComments,
|
|
107
|
-
undocumentedComplexity
|
|
120
|
+
undocumentedComplexity,
|
|
121
|
+
actualDrift
|
|
108
122
|
});
|
|
109
123
|
return {
|
|
110
124
|
summary: {
|
|
@@ -118,7 +132,8 @@ async function analyzeDocDrift(options) {
|
|
|
118
132
|
uncommentedExports,
|
|
119
133
|
totalExports,
|
|
120
134
|
outdatedComments,
|
|
121
|
-
undocumentedComplexity
|
|
135
|
+
undocumentedComplexity,
|
|
136
|
+
actualDrift
|
|
122
137
|
},
|
|
123
138
|
recommendations: riskResult.recommendations
|
|
124
139
|
};
|
package/dist/cli.js
CHANGED
|
@@ -41,13 +41,11 @@ var import_fs = require("fs");
|
|
|
41
41
|
async function analyzeDocDrift(options) {
|
|
42
42
|
const files = await (0, import_core.scanFiles)(options);
|
|
43
43
|
const issues = [];
|
|
44
|
-
const staleMonths = options.staleMonths ?? 6;
|
|
45
|
-
const staleSeconds = staleMonths * 30 * 24 * 60 * 60;
|
|
46
44
|
let uncommentedExports = 0;
|
|
47
45
|
let totalExports = 0;
|
|
48
46
|
let outdatedComments = 0;
|
|
49
47
|
let undocumentedComplexity = 0;
|
|
50
|
-
|
|
48
|
+
let actualDrift = 0;
|
|
51
49
|
let processed = 0;
|
|
52
50
|
for (const file of files) {
|
|
53
51
|
processed++;
|
|
@@ -96,10 +94,9 @@ async function analyzeDocDrift(options) {
|
|
|
96
94
|
message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
|
|
97
95
|
location: { file, line: exp.loc?.start.line || 1 }
|
|
98
96
|
});
|
|
99
|
-
continue;
|
|
100
97
|
}
|
|
101
98
|
}
|
|
102
|
-
if (exp.loc) {
|
|
99
|
+
if (exp.loc && doc.loc) {
|
|
103
100
|
if (!fileLineStamps) {
|
|
104
101
|
fileLineStamps = (0, import_core.getFileCommitTimestamps)(file);
|
|
105
102
|
}
|
|
@@ -108,8 +105,21 @@ async function analyzeDocDrift(options) {
|
|
|
108
105
|
exp.loc.start.line,
|
|
109
106
|
exp.loc.end.line
|
|
110
107
|
);
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
const docModified = (0, import_core.getLineRangeLastModifiedCached)(
|
|
109
|
+
fileLineStamps,
|
|
110
|
+
doc.loc.start.line,
|
|
111
|
+
doc.loc.end.line
|
|
112
|
+
);
|
|
113
|
+
if (bodyModified > 0 && docModified > 0) {
|
|
114
|
+
const DRIFT_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
115
|
+
if (bodyModified - docModified > DRIFT_THRESHOLD_SECONDS) {
|
|
116
|
+
actualDrift++;
|
|
117
|
+
issues.push({
|
|
118
|
+
type: import_core.IssueType.DocDrift,
|
|
119
|
+
severity: import_core.Severity.Major,
|
|
120
|
+
message: `Documentation drift: logic was modified on ${new Date(bodyModified * 1e3).toLocaleDateString()} but documentation was last updated on ${new Date(docModified * 1e3).toLocaleDateString()}.`,
|
|
121
|
+
location: { file, line: doc.loc.start.line }
|
|
122
|
+
});
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
125
|
}
|
|
@@ -125,7 +135,8 @@ async function analyzeDocDrift(options) {
|
|
|
125
135
|
uncommentedExports,
|
|
126
136
|
totalExports,
|
|
127
137
|
outdatedComments,
|
|
128
|
-
undocumentedComplexity
|
|
138
|
+
undocumentedComplexity,
|
|
139
|
+
actualDrift
|
|
129
140
|
});
|
|
130
141
|
return {
|
|
131
142
|
summary: {
|
|
@@ -139,7 +150,8 @@ async function analyzeDocDrift(options) {
|
|
|
139
150
|
uncommentedExports,
|
|
140
151
|
totalExports,
|
|
141
152
|
outdatedComments,
|
|
142
|
-
undocumentedComplexity
|
|
153
|
+
undocumentedComplexity,
|
|
154
|
+
actualDrift
|
|
143
155
|
},
|
|
144
156
|
recommendations: riskResult.recommendations
|
|
145
157
|
};
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -49,15 +49,31 @@ interface DocDriftReport {
|
|
|
49
49
|
outdatedComments: number;
|
|
50
50
|
/** Count of complex functions without sufficient documentation */
|
|
51
51
|
undocumentedComplexity: number;
|
|
52
|
+
/** Number of functions where code changed after docs */
|
|
53
|
+
actualDrift: number;
|
|
52
54
|
};
|
|
53
55
|
/** AI-generated remediation advice */
|
|
54
56
|
recommendations: string[];
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Analyzes documentation drift across a set of files.
|
|
61
|
+
* This tool detects:
|
|
62
|
+
* 1. Missing documentation for complex functions/classes.
|
|
63
|
+
* 2. Signature mismatches (parameters not mentioned in docs).
|
|
64
|
+
* 3. Temporal drift (logic changed after documentation was last updated).
|
|
65
|
+
*
|
|
66
|
+
* @param options - Analysis configuration including include/exclude patterns and drift thresholds.
|
|
67
|
+
* @returns A comprehensive report with drift scores and specific issues.
|
|
68
|
+
*/
|
|
57
69
|
declare function analyzeDocDrift(options: DocDriftOptions): Promise<DocDriftReport>;
|
|
58
70
|
|
|
59
71
|
/**
|
|
60
|
-
* Convert doc-drift report into a ToolScoringOutput.
|
|
72
|
+
* Convert doc-drift report into a standardized ToolScoringOutput.
|
|
73
|
+
*
|
|
74
|
+
* @param report - The detailed doc-drift report including raw metrics.
|
|
75
|
+
* @returns Standardized scoring and risk factor breakdown.
|
|
76
|
+
* @lastUpdated 2026-03-18
|
|
61
77
|
*/
|
|
62
78
|
declare function calculateDocDriftScore(report: DocDriftReport): ToolScoringOutput;
|
|
63
79
|
|
package/dist/index.d.ts
CHANGED
|
@@ -49,15 +49,31 @@ interface DocDriftReport {
|
|
|
49
49
|
outdatedComments: number;
|
|
50
50
|
/** Count of complex functions without sufficient documentation */
|
|
51
51
|
undocumentedComplexity: number;
|
|
52
|
+
/** Number of functions where code changed after docs */
|
|
53
|
+
actualDrift: number;
|
|
52
54
|
};
|
|
53
55
|
/** AI-generated remediation advice */
|
|
54
56
|
recommendations: string[];
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Analyzes documentation drift across a set of files.
|
|
61
|
+
* This tool detects:
|
|
62
|
+
* 1. Missing documentation for complex functions/classes.
|
|
63
|
+
* 2. Signature mismatches (parameters not mentioned in docs).
|
|
64
|
+
* 3. Temporal drift (logic changed after documentation was last updated).
|
|
65
|
+
*
|
|
66
|
+
* @param options - Analysis configuration including include/exclude patterns and drift thresholds.
|
|
67
|
+
* @returns A comprehensive report with drift scores and specific issues.
|
|
68
|
+
*/
|
|
57
69
|
declare function analyzeDocDrift(options: DocDriftOptions): Promise<DocDriftReport>;
|
|
58
70
|
|
|
59
71
|
/**
|
|
60
|
-
* Convert doc-drift report into a ToolScoringOutput.
|
|
72
|
+
* Convert doc-drift report into a standardized ToolScoringOutput.
|
|
73
|
+
*
|
|
74
|
+
* @param report - The detailed doc-drift report including raw metrics.
|
|
75
|
+
* @returns Standardized scoring and risk factor breakdown.
|
|
76
|
+
* @lastUpdated 2026-03-18
|
|
61
77
|
*/
|
|
62
78
|
declare function calculateDocDriftScore(report: DocDriftReport): ToolScoringOutput;
|
|
63
79
|
|
package/dist/index.js
CHANGED
|
@@ -36,13 +36,11 @@ var import_fs = require("fs");
|
|
|
36
36
|
async function analyzeDocDrift(options) {
|
|
37
37
|
const files = await (0, import_core.scanFiles)(options);
|
|
38
38
|
const issues = [];
|
|
39
|
-
const staleMonths = options.staleMonths ?? 6;
|
|
40
|
-
const staleSeconds = staleMonths * 30 * 24 * 60 * 60;
|
|
41
39
|
let uncommentedExports = 0;
|
|
42
40
|
let totalExports = 0;
|
|
43
41
|
let outdatedComments = 0;
|
|
44
42
|
let undocumentedComplexity = 0;
|
|
45
|
-
|
|
43
|
+
let actualDrift = 0;
|
|
46
44
|
let processed = 0;
|
|
47
45
|
for (const file of files) {
|
|
48
46
|
processed++;
|
|
@@ -91,10 +89,9 @@ async function analyzeDocDrift(options) {
|
|
|
91
89
|
message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
|
|
92
90
|
location: { file, line: exp.loc?.start.line || 1 }
|
|
93
91
|
});
|
|
94
|
-
continue;
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
|
-
if (exp.loc) {
|
|
94
|
+
if (exp.loc && doc.loc) {
|
|
98
95
|
if (!fileLineStamps) {
|
|
99
96
|
fileLineStamps = (0, import_core.getFileCommitTimestamps)(file);
|
|
100
97
|
}
|
|
@@ -103,8 +100,21 @@ async function analyzeDocDrift(options) {
|
|
|
103
100
|
exp.loc.start.line,
|
|
104
101
|
exp.loc.end.line
|
|
105
102
|
);
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const docModified = (0, import_core.getLineRangeLastModifiedCached)(
|
|
104
|
+
fileLineStamps,
|
|
105
|
+
doc.loc.start.line,
|
|
106
|
+
doc.loc.end.line
|
|
107
|
+
);
|
|
108
|
+
if (bodyModified > 0 && docModified > 0) {
|
|
109
|
+
const DRIFT_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
110
|
+
if (bodyModified - docModified > DRIFT_THRESHOLD_SECONDS) {
|
|
111
|
+
actualDrift++;
|
|
112
|
+
issues.push({
|
|
113
|
+
type: import_core.IssueType.DocDrift,
|
|
114
|
+
severity: import_core.Severity.Major,
|
|
115
|
+
message: `Documentation drift: logic was modified on ${new Date(bodyModified * 1e3).toLocaleDateString()} but documentation was last updated on ${new Date(docModified * 1e3).toLocaleDateString()}.`,
|
|
116
|
+
location: { file, line: doc.loc.start.line }
|
|
117
|
+
});
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
}
|
|
@@ -120,7 +130,8 @@ async function analyzeDocDrift(options) {
|
|
|
120
130
|
uncommentedExports,
|
|
121
131
|
totalExports,
|
|
122
132
|
outdatedComments,
|
|
123
|
-
undocumentedComplexity
|
|
133
|
+
undocumentedComplexity,
|
|
134
|
+
actualDrift
|
|
124
135
|
});
|
|
125
136
|
return {
|
|
126
137
|
summary: {
|
|
@@ -134,7 +145,8 @@ async function analyzeDocDrift(options) {
|
|
|
134
145
|
uncommentedExports,
|
|
135
146
|
totalExports,
|
|
136
147
|
outdatedComments,
|
|
137
|
-
undocumentedComplexity
|
|
148
|
+
undocumentedComplexity,
|
|
149
|
+
actualDrift
|
|
138
150
|
},
|
|
139
151
|
recommendations: riskResult.recommendations
|
|
140
152
|
};
|
|
@@ -173,26 +185,33 @@ function calculateDocDriftScore(report) {
|
|
|
173
185
|
uncommentedExports: rawData.uncommentedExports,
|
|
174
186
|
totalExports: rawData.totalExports,
|
|
175
187
|
outdatedComments: rawData.outdatedComments,
|
|
176
|
-
undocumentedComplexity: rawData.undocumentedComplexity
|
|
188
|
+
undocumentedComplexity: rawData.undocumentedComplexity,
|
|
189
|
+
actualDrift: rawData.actualDrift
|
|
177
190
|
});
|
|
178
191
|
const factors = [
|
|
179
192
|
{
|
|
180
|
-
name: "
|
|
193
|
+
name: "Undocumented Complexity",
|
|
181
194
|
impact: -Math.min(
|
|
182
|
-
|
|
183
|
-
rawData.
|
|
195
|
+
50,
|
|
196
|
+
rawData.undocumentedComplexity / Math.max(1, rawData.totalExports) / 0.2 * 100 * 0.5
|
|
184
197
|
),
|
|
185
|
-
description: `${rawData.
|
|
198
|
+
description: `${rawData.undocumentedComplexity} complex functions lack docs (high risk)`
|
|
186
199
|
},
|
|
187
200
|
{
|
|
188
|
-
name: "Outdated Comments",
|
|
189
|
-
impact: -Math.min(
|
|
190
|
-
|
|
201
|
+
name: "Outdated/Incomplete Comments",
|
|
202
|
+
impact: -Math.min(
|
|
203
|
+
30,
|
|
204
|
+
rawData.outdatedComments / Math.max(1, rawData.totalExports) / 0.4 * 100 * 0.3
|
|
205
|
+
),
|
|
206
|
+
description: `${rawData.outdatedComments} functions with parameter-mismatch in docs`
|
|
191
207
|
},
|
|
192
208
|
{
|
|
193
|
-
name: "
|
|
194
|
-
impact: -Math.min(
|
|
195
|
-
|
|
209
|
+
name: "Uncommented Exports",
|
|
210
|
+
impact: -Math.min(
|
|
211
|
+
20,
|
|
212
|
+
rawData.uncommentedExports / Math.max(1, rawData.totalExports) / 0.8 * 100 * 0.2
|
|
213
|
+
),
|
|
214
|
+
description: `${rawData.uncommentedExports} uncommented exports`
|
|
196
215
|
}
|
|
197
216
|
];
|
|
198
217
|
const recommendations = riskResult.recommendations.map((rec) => ({
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeDocDrift
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MAPV5YQR.mjs";
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
6
|
import { ToolRegistry } from "@aiready/core";
|
|
@@ -44,26 +44,33 @@ function calculateDocDriftScore(report) {
|
|
|
44
44
|
uncommentedExports: rawData.uncommentedExports,
|
|
45
45
|
totalExports: rawData.totalExports,
|
|
46
46
|
outdatedComments: rawData.outdatedComments,
|
|
47
|
-
undocumentedComplexity: rawData.undocumentedComplexity
|
|
47
|
+
undocumentedComplexity: rawData.undocumentedComplexity,
|
|
48
|
+
actualDrift: rawData.actualDrift
|
|
48
49
|
});
|
|
49
50
|
const factors = [
|
|
50
51
|
{
|
|
51
|
-
name: "
|
|
52
|
+
name: "Undocumented Complexity",
|
|
52
53
|
impact: -Math.min(
|
|
53
|
-
|
|
54
|
-
rawData.
|
|
54
|
+
50,
|
|
55
|
+
rawData.undocumentedComplexity / Math.max(1, rawData.totalExports) / 0.2 * 100 * 0.5
|
|
55
56
|
),
|
|
56
|
-
description: `${rawData.
|
|
57
|
+
description: `${rawData.undocumentedComplexity} complex functions lack docs (high risk)`
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
|
-
name: "Outdated Comments",
|
|
60
|
-
impact: -Math.min(
|
|
61
|
-
|
|
60
|
+
name: "Outdated/Incomplete Comments",
|
|
61
|
+
impact: -Math.min(
|
|
62
|
+
30,
|
|
63
|
+
rawData.outdatedComments / Math.max(1, rawData.totalExports) / 0.4 * 100 * 0.3
|
|
64
|
+
),
|
|
65
|
+
description: `${rawData.outdatedComments} functions with parameter-mismatch in docs`
|
|
62
66
|
},
|
|
63
67
|
{
|
|
64
|
-
name: "
|
|
65
|
-
impact: -Math.min(
|
|
66
|
-
|
|
68
|
+
name: "Uncommented Exports",
|
|
69
|
+
impact: -Math.min(
|
|
70
|
+
20,
|
|
71
|
+
rawData.uncommentedExports / Math.max(1, rawData.totalExports) / 0.8 * 100 * 0.2
|
|
72
|
+
),
|
|
73
|
+
description: `${rawData.uncommentedExports} uncommented exports`
|
|
67
74
|
}
|
|
68
75
|
];
|
|
69
76
|
const recommendations = riskResult.recommendations.map((rec) => ({
|