@aiready/doc-drift 0.13.5 → 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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/doc-drift@0.13.5 build /Users/pengcao/projects/aiready/packages/doc-drift
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
  CLI Building entry: src/cli.ts, src/index.ts
@@ -9,16 +9,16 @@
9
9
  CLI Target: es2020
10
10
  CJS Build start
11
11
  ESM Build start
12
- CJS dist/cli.js 7.25 KB
13
- CJS dist/index.js 7.85 KB
14
- CJS ⚡️ Build success in 122ms
15
12
  ESM dist/index.mjs 2.59 KB
16
13
  ESM dist/cli.mjs 1.39 KB
17
- ESM dist/chunk-P74XAVQ3.mjs 4.54 KB
18
- ESM ⚡️ Build success in 124ms
14
+ ESM dist/chunk-MAPV5YQR.mjs 4.40 KB
15
+ ESM ⚡️ Build success in 55ms
16
+ CJS dist/index.js 7.71 KB
17
+ CJS dist/cli.js 7.11 KB
18
+ CJS ⚡️ Build success in 56ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 5302ms
20
+ DTS ⚡️ Build success in 4610ms
21
21
  DTS dist/cli.d.ts 108.00 B
22
- DTS dist/index.d.ts 2.66 KB
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.66 KB
24
+ DTS dist/index.d.mts 2.83 KB
@@ -1,18 +1,18 @@
1
1
 
2
2
  
3
- > @aiready/doc-drift@0.13.3 test /Users/pengcao/projects/aiready/packages/doc-drift
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
   RUN  v4.0.18 /Users/pengcao/projects/aiready/packages/doc-drift
8
8
 
9
- ✓ src/__tests__/scoring.test.ts (2 tests) 12ms
10
- ✓ src/__tests__/analyzer.test.ts (1 test) 47ms
11
- ✓ src/__tests__/provider.test.ts (2 tests) 8ms
9
+ ✓ src/__tests__/provider.test.ts (2 tests) 7ms
10
+ ✓ src/__tests__/analyzer.test.ts (1 test) 316ms
11
+ ✓ src/__tests__/scoring.test.ts (2 tests) 47ms
12
12
 
13
13
   Test Files  3 passed (3)
14
14
   Tests  5 passed (5)
15
-  Start at  10:36:26
16
-  Duration  1.89s (transform 1.09s, setup 0ms, import 3.19s, tests 66ms, environment 0ms)
15
+  Start at  10:12:34
16
+  Duration  5.35s (transform 2.37s, setup 0ms, import 10.75s, tests 370ms, environment 5ms)
17
17
 
18
18
  [?25h
@@ -0,0 +1,143 @@
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
+ const staleMonths = options.staleMonths ?? 6;
24
+ let uncommentedExports = 0;
25
+ let totalExports = 0;
26
+ let outdatedComments = 0;
27
+ let undocumentedComplexity = 0;
28
+ let actualDrift = 0;
29
+ let processed = 0;
30
+ for (const file of files) {
31
+ processed++;
32
+ emitProgress(
33
+ processed,
34
+ files.length,
35
+ "doc-drift",
36
+ "analyzing files",
37
+ options.onProgress
38
+ );
39
+ const parser = getParser(file);
40
+ if (!parser) continue;
41
+ let code;
42
+ try {
43
+ code = readFileSync(file, "utf-8");
44
+ } catch {
45
+ continue;
46
+ }
47
+ try {
48
+ await parser.initialize();
49
+ const parseResult = parser.parse(code, file);
50
+ let fileLineStamps;
51
+ for (const exp of parseResult.exports) {
52
+ if (exp.type === "function" || exp.type === "class") {
53
+ totalExports++;
54
+ if (!exp.documentation) {
55
+ uncommentedExports++;
56
+ if (exp.loc) {
57
+ const lines = exp.loc.end.line - exp.loc.start.line;
58
+ if (lines > 20) undocumentedComplexity++;
59
+ }
60
+ } else {
61
+ const doc = exp.documentation;
62
+ const docContent = doc.content;
63
+ if (exp.type === "function" && exp.parameters) {
64
+ const params = exp.parameters;
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
+ outdatedComments++;
71
+ issues.push({
72
+ type: IssueType.DocDrift,
73
+ severity: Severity.Major,
74
+ message: `Documentation mismatch: function parameters (${missingParams.join(", ")}) are not mentioned in the docs.`,
75
+ location: { file, line: exp.loc?.start.line || 1 }
76
+ });
77
+ }
78
+ }
79
+ if (exp.loc && doc.loc) {
80
+ if (!fileLineStamps) {
81
+ fileLineStamps = getFileCommitTimestamps(file);
82
+ }
83
+ const bodyModified = getLineRangeLastModifiedCached(
84
+ fileLineStamps,
85
+ exp.loc.start.line,
86
+ exp.loc.end.line
87
+ );
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
+ });
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ } catch (error) {
110
+ console.warn(`Doc-drift: Failed to parse ${file}: ${error}`);
111
+ continue;
112
+ }
113
+ }
114
+ const riskResult = calculateDocDrift({
115
+ uncommentedExports,
116
+ totalExports,
117
+ outdatedComments,
118
+ undocumentedComplexity,
119
+ actualDrift
120
+ });
121
+ return {
122
+ summary: {
123
+ filesAnalyzed: files.length,
124
+ functionsAnalyzed: totalExports,
125
+ score: riskResult.score,
126
+ rating: riskResult.rating
127
+ },
128
+ issues,
129
+ rawData: {
130
+ uncommentedExports,
131
+ totalExports,
132
+ outdatedComments,
133
+ undocumentedComplexity,
134
+ actualDrift
135
+ },
136
+ recommendations: riskResult.recommendations
137
+ };
138
+ }
139
+
140
+ export {
141
+ __require,
142
+ analyzeDocDrift
143
+ };
@@ -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
+ };
package/dist/cli.js CHANGED
@@ -41,14 +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
- const now = Math.floor(Date.now() / 1e3);
52
49
  let processed = 0;
53
50
  for (const file of files) {
54
51
  processed++;
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __require,
3
3
  analyzeDocDrift
4
- } from "./chunk-P74XAVQ3.mjs";
4
+ } from "./chunk-MAPV5YQR.mjs";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
package/dist/index.d.mts CHANGED
@@ -69,7 +69,11 @@ interface DocDriftReport {
69
69
  declare function analyzeDocDrift(options: DocDriftOptions): Promise<DocDriftReport>;
70
70
 
71
71
  /**
72
- * 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
73
77
  */
74
78
  declare function calculateDocDriftScore(report: DocDriftReport): ToolScoringOutput;
75
79
 
package/dist/index.d.ts CHANGED
@@ -69,7 +69,11 @@ interface DocDriftReport {
69
69
  declare function analyzeDocDrift(options: DocDriftOptions): Promise<DocDriftReport>;
70
70
 
71
71
  /**
72
- * 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
73
77
  */
74
78
  declare function calculateDocDriftScore(report: DocDriftReport): ToolScoringOutput;
75
79
 
package/dist/index.js CHANGED
@@ -36,14 +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
- const now = Math.floor(Date.now() / 1e3);
47
44
  let processed = 0;
48
45
  for (const file of files) {
49
46
  processed++;
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  analyzeDocDrift
3
- } from "./chunk-P74XAVQ3.mjs";
3
+ } from "./chunk-MAPV5YQR.mjs";
4
4
 
5
5
  // src/index.ts
6
6
  import { ToolRegistry } from "@aiready/core";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/doc-drift",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "AI-Readiness: Documentation Drift Detection",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -10,7 +10,7 @@
10
10
  "commander": "^14.0.0",
11
11
  "glob": "^13.0.0",
12
12
  "picocolors": "^1.0.0",
13
- "@aiready/core": "0.23.6"
13
+ "@aiready/core": "0.23.7"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@types/node": "^24.0.0",
package/src/analyzer.ts CHANGED
@@ -27,8 +27,7 @@ export async function analyzeDocDrift(
27
27
  // Use core scanFiles which respects .gitignore recursively
28
28
  const files = await scanFiles(options);
29
29
  const issues: DocDriftIssue[] = [];
30
- const staleMonths = options.staleMonths ?? 6;
31
- const staleSeconds = staleMonths * 30 * 24 * 60 * 60;
30
+ // const staleSeconds = staleMonths * 30 * 24 * 60 * 60; // Unused, removed
32
31
 
33
32
  let uncommentedExports = 0;
34
33
  let totalExports = 0;
@@ -36,7 +35,7 @@ export async function analyzeDocDrift(
36
35
  let undocumentedComplexity = 0;
37
36
  let actualDrift = 0;
38
37
 
39
- const now = Math.floor(Date.now() / 1000);
38
+ // const now = Math.floor(Date.now() / 1000); // Unused, removed
40
39
 
41
40
  let processed = 0;
42
41
  for (const file of files) {
package/src/scoring.ts CHANGED
@@ -3,7 +3,11 @@ import type { ToolScoringOutput } from '@aiready/core';
3
3
  import type { DocDriftReport } from './types';
4
4
 
5
5
  /**
6
- * Convert doc-drift report into a ToolScoringOutput.
6
+ * Convert doc-drift report into a standardized ToolScoringOutput.
7
+ *
8
+ * @param report - The detailed doc-drift report including raw metrics.
9
+ * @returns Standardized scoring and risk factor breakdown.
10
+ * @lastUpdated 2026-03-18
7
11
  */
8
12
  export function calculateDocDriftScore(
9
13
  report: DocDriftReport