doc-freshness-checker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +305 -0
  3. package/dist/cache/cacheManager.d.ts +42 -0
  4. package/dist/cache/cacheManager.js +138 -0
  5. package/dist/cache/cacheManager.js.map +1 -0
  6. package/dist/cache/cacheManager.test.d.ts +1 -0
  7. package/dist/cache/cacheManager.test.js +142 -0
  8. package/dist/cache/cacheManager.test.js.map +1 -0
  9. package/dist/cli.d.ts +32 -0
  10. package/dist/cli.js +137 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/cli.test.d.ts +1 -0
  13. package/dist/cli.test.js +184 -0
  14. package/dist/cli.test.js.map +1 -0
  15. package/dist/config/defaults.d.ts +5 -0
  16. package/dist/config/defaults.js +135 -0
  17. package/dist/config/defaults.js.map +1 -0
  18. package/dist/config/defineConfig.d.ts +28 -0
  19. package/dist/config/defineConfig.js +30 -0
  20. package/dist/config/defineConfig.js.map +1 -0
  21. package/dist/config/defineConfig.test.d.ts +1 -0
  22. package/dist/config/defineConfig.test.js +10 -0
  23. package/dist/config/defineConfig.test.js.map +1 -0
  24. package/dist/config/loader.d.ts +7 -0
  25. package/dist/config/loader.js +250 -0
  26. package/dist/config/loader.js.map +1 -0
  27. package/dist/config/loader.test.d.ts +1 -0
  28. package/dist/config/loader.test.js +276 -0
  29. package/dist/config/loader.test.js.map +1 -0
  30. package/dist/git/changeTracker.d.ts +44 -0
  31. package/dist/git/changeTracker.js +149 -0
  32. package/dist/git/changeTracker.js.map +1 -0
  33. package/dist/git/changeTracker.test.d.ts +1 -0
  34. package/dist/git/changeTracker.test.js +184 -0
  35. package/dist/git/changeTracker.test.js.map +1 -0
  36. package/dist/graph/codeDocGraph.d.ts +43 -0
  37. package/dist/graph/codeDocGraph.js +103 -0
  38. package/dist/graph/codeDocGraph.js.map +1 -0
  39. package/dist/graph/codeDocGraph.test.d.ts +1 -0
  40. package/dist/graph/codeDocGraph.test.js +78 -0
  41. package/dist/graph/codeDocGraph.test.js.map +1 -0
  42. package/dist/graph/graphBuilder.d.ts +17 -0
  43. package/dist/graph/graphBuilder.js +76 -0
  44. package/dist/graph/graphBuilder.js.map +1 -0
  45. package/dist/graph/graphBuilder.test.d.ts +1 -0
  46. package/dist/graph/graphBuilder.test.js +87 -0
  47. package/dist/graph/graphBuilder.test.js.map +1 -0
  48. package/dist/index.d.ts +37 -0
  49. package/dist/index.js +37 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/parsers/documentParser.d.ts +22 -0
  52. package/dist/parsers/documentParser.js +76 -0
  53. package/dist/parsers/documentParser.js.map +1 -0
  54. package/dist/parsers/documentParser.test.d.ts +1 -0
  55. package/dist/parsers/documentParser.test.js +116 -0
  56. package/dist/parsers/documentParser.test.js.map +1 -0
  57. package/dist/parsers/extractors/baseExtractor.d.ts +19 -0
  58. package/dist/parsers/extractors/baseExtractor.js +33 -0
  59. package/dist/parsers/extractors/baseExtractor.js.map +1 -0
  60. package/dist/parsers/extractors/baseExtractor.test.d.ts +1 -0
  61. package/dist/parsers/extractors/baseExtractor.test.js +43 -0
  62. package/dist/parsers/extractors/baseExtractor.test.js.map +1 -0
  63. package/dist/parsers/extractors/codePatternExtractor.d.ts +13 -0
  64. package/dist/parsers/extractors/codePatternExtractor.js +108 -0
  65. package/dist/parsers/extractors/codePatternExtractor.js.map +1 -0
  66. package/dist/parsers/extractors/codePatternExtractor.test.d.ts +1 -0
  67. package/dist/parsers/extractors/codePatternExtractor.test.js +49 -0
  68. package/dist/parsers/extractors/codePatternExtractor.test.js.map +1 -0
  69. package/dist/parsers/extractors/dependencyExtractor.d.ts +12 -0
  70. package/dist/parsers/extractors/dependencyExtractor.js +92 -0
  71. package/dist/parsers/extractors/dependencyExtractor.js.map +1 -0
  72. package/dist/parsers/extractors/dependencyExtractor.test.d.ts +1 -0
  73. package/dist/parsers/extractors/dependencyExtractor.test.js +48 -0
  74. package/dist/parsers/extractors/dependencyExtractor.test.js.map +1 -0
  75. package/dist/parsers/extractors/directoryStructureExtractor.d.ts +34 -0
  76. package/dist/parsers/extractors/directoryStructureExtractor.js +168 -0
  77. package/dist/parsers/extractors/directoryStructureExtractor.js.map +1 -0
  78. package/dist/parsers/extractors/directoryStructureExtractor.test.d.ts +1 -0
  79. package/dist/parsers/extractors/directoryStructureExtractor.test.js +121 -0
  80. package/dist/parsers/extractors/directoryStructureExtractor.test.js.map +1 -0
  81. package/dist/parsers/extractors/externalUrlExtractor.d.ts +14 -0
  82. package/dist/parsers/extractors/externalUrlExtractor.js +53 -0
  83. package/dist/parsers/extractors/externalUrlExtractor.js.map +1 -0
  84. package/dist/parsers/extractors/externalUrlExtractor.test.d.ts +1 -0
  85. package/dist/parsers/extractors/externalUrlExtractor.test.js +85 -0
  86. package/dist/parsers/extractors/externalUrlExtractor.test.js.map +1 -0
  87. package/dist/parsers/extractors/filePathExtractor.d.ts +18 -0
  88. package/dist/parsers/extractors/filePathExtractor.js +72 -0
  89. package/dist/parsers/extractors/filePathExtractor.js.map +1 -0
  90. package/dist/parsers/extractors/filePathExtractor.test.d.ts +1 -0
  91. package/dist/parsers/extractors/filePathExtractor.test.js +73 -0
  92. package/dist/parsers/extractors/filePathExtractor.test.js.map +1 -0
  93. package/dist/parsers/extractors/versionExtractor.d.ts +11 -0
  94. package/dist/parsers/extractors/versionExtractor.js +74 -0
  95. package/dist/parsers/extractors/versionExtractor.js.map +1 -0
  96. package/dist/parsers/extractors/versionExtractor.test.d.ts +1 -0
  97. package/dist/parsers/extractors/versionExtractor.test.js +55 -0
  98. package/dist/parsers/extractors/versionExtractor.test.js.map +1 -0
  99. package/dist/plugins/plugin.d.ts +32 -0
  100. package/dist/plugins/plugin.js +40 -0
  101. package/dist/plugins/plugin.js.map +1 -0
  102. package/dist/plugins/plugin.test.d.ts +1 -0
  103. package/dist/plugins/plugin.test.js +23 -0
  104. package/dist/plugins/plugin.test.js.map +1 -0
  105. package/dist/reporters/consoleReporter.d.ts +15 -0
  106. package/dist/reporters/consoleReporter.js +73 -0
  107. package/dist/reporters/consoleReporter.js.map +1 -0
  108. package/dist/reporters/consoleReporter.test.d.ts +1 -0
  109. package/dist/reporters/consoleReporter.test.js +155 -0
  110. package/dist/reporters/consoleReporter.test.js.map +1 -0
  111. package/dist/reporters/enhancedReporter.d.ts +12 -0
  112. package/dist/reporters/enhancedReporter.js +81 -0
  113. package/dist/reporters/enhancedReporter.js.map +1 -0
  114. package/dist/reporters/enhancedReporter.test.d.ts +1 -0
  115. package/dist/reporters/enhancedReporter.test.js +152 -0
  116. package/dist/reporters/enhancedReporter.test.js.map +1 -0
  117. package/dist/reporters/jsonReporter.d.ts +11 -0
  118. package/dist/reporters/jsonReporter.js +20 -0
  119. package/dist/reporters/jsonReporter.js.map +1 -0
  120. package/dist/reporters/jsonReporter.test.d.ts +1 -0
  121. package/dist/reporters/jsonReporter.test.js +31 -0
  122. package/dist/reporters/jsonReporter.test.js.map +1 -0
  123. package/dist/reporters/markdownReporter.d.ts +11 -0
  124. package/dist/reporters/markdownReporter.js +55 -0
  125. package/dist/reporters/markdownReporter.js.map +1 -0
  126. package/dist/reporters/markdownReporter.test.d.ts +1 -0
  127. package/dist/reporters/markdownReporter.test.js +136 -0
  128. package/dist/reporters/markdownReporter.test.js.map +1 -0
  129. package/dist/runner.d.ts +9 -0
  130. package/dist/runner.js +265 -0
  131. package/dist/runner.js.map +1 -0
  132. package/dist/runner.test.d.ts +1 -0
  133. package/dist/runner.test.js +353 -0
  134. package/dist/runner.test.js.map +1 -0
  135. package/dist/scoring/freshnessScorer.d.ts +40 -0
  136. package/dist/scoring/freshnessScorer.js +170 -0
  137. package/dist/scoring/freshnessScorer.js.map +1 -0
  138. package/dist/scoring/freshnessScorer.test.d.ts +1 -0
  139. package/dist/scoring/freshnessScorer.test.js +397 -0
  140. package/dist/scoring/freshnessScorer.test.js.map +1 -0
  141. package/dist/semantic/vectorSearch.d.ts +84 -0
  142. package/dist/semantic/vectorSearch.js +484 -0
  143. package/dist/semantic/vectorSearch.js.map +1 -0
  144. package/dist/semantic/vectorSearch.test.d.ts +1 -0
  145. package/dist/semantic/vectorSearch.test.js +660 -0
  146. package/dist/semantic/vectorSearch.test.js.map +1 -0
  147. package/dist/setupTests.d.ts +4 -0
  148. package/dist/setupTests.js +11 -0
  149. package/dist/setupTests.js.map +1 -0
  150. package/dist/test-utils/console.d.ts +2 -0
  151. package/dist/test-utils/console.js +3 -0
  152. package/dist/test-utils/console.js.map +1 -0
  153. package/dist/test-utils/factories.d.ts +3 -0
  154. package/dist/test-utils/factories.js +25 -0
  155. package/dist/test-utils/factories.js.map +1 -0
  156. package/dist/test-utils/tempFiles.d.ts +1 -0
  157. package/dist/test-utils/tempFiles.js +12 -0
  158. package/dist/test-utils/tempFiles.js.map +1 -0
  159. package/dist/types.d.ts +304 -0
  160. package/dist/types.js +5 -0
  161. package/dist/types.js.map +1 -0
  162. package/dist/utils/boundedMap.d.ts +8 -0
  163. package/dist/utils/boundedMap.js +22 -0
  164. package/dist/utils/boundedMap.js.map +1 -0
  165. package/dist/utils/boundedMap.test.d.ts +1 -0
  166. package/dist/utils/boundedMap.test.js +57 -0
  167. package/dist/utils/boundedMap.test.js.map +1 -0
  168. package/dist/utils/illustrativePatterns.d.ts +28 -0
  169. package/dist/utils/illustrativePatterns.js +80 -0
  170. package/dist/utils/illustrativePatterns.js.map +1 -0
  171. package/dist/utils/illustrativePatterns.test.d.ts +1 -0
  172. package/dist/utils/illustrativePatterns.test.js +48 -0
  173. package/dist/utils/illustrativePatterns.test.js.map +1 -0
  174. package/dist/utils/incremental.d.ts +36 -0
  175. package/dist/utils/incremental.js +87 -0
  176. package/dist/utils/incremental.js.map +1 -0
  177. package/dist/utils/incremental.test.d.ts +1 -0
  178. package/dist/utils/incremental.test.js +84 -0
  179. package/dist/utils/incremental.test.js.map +1 -0
  180. package/dist/utils/parallel.d.ts +14 -0
  181. package/dist/utils/parallel.js +43 -0
  182. package/dist/utils/parallel.js.map +1 -0
  183. package/dist/utils/parallel.test.d.ts +1 -0
  184. package/dist/utils/parallel.test.js +48 -0
  185. package/dist/utils/parallel.test.js.map +1 -0
  186. package/dist/utils/pathSecurity.d.ts +12 -0
  187. package/dist/utils/pathSecurity.js +22 -0
  188. package/dist/utils/pathSecurity.js.map +1 -0
  189. package/dist/utils/pathSecurity.test.d.ts +1 -0
  190. package/dist/utils/pathSecurity.test.js +34 -0
  191. package/dist/utils/pathSecurity.test.js.map +1 -0
  192. package/dist/utils/similarity.d.ts +12 -0
  193. package/dist/utils/similarity.js +64 -0
  194. package/dist/utils/similarity.js.map +1 -0
  195. package/dist/utils/similarity.test.d.ts +1 -0
  196. package/dist/utils/similarity.test.js +49 -0
  197. package/dist/utils/similarity.test.js.map +1 -0
  198. package/dist/utils/validation.d.ts +13 -0
  199. package/dist/utils/validation.js +24 -0
  200. package/dist/utils/validation.js.map +1 -0
  201. package/dist/utils/validation.test.d.ts +1 -0
  202. package/dist/utils/validation.test.js +28 -0
  203. package/dist/utils/validation.test.js.map +1 -0
  204. package/dist/validators/codePatternValidator.d.ts +28 -0
  205. package/dist/validators/codePatternValidator.js +200 -0
  206. package/dist/validators/codePatternValidator.js.map +1 -0
  207. package/dist/validators/codePatternValidator.test.d.ts +1 -0
  208. package/dist/validators/codePatternValidator.test.js +86 -0
  209. package/dist/validators/codePatternValidator.test.js.map +1 -0
  210. package/dist/validators/dependencyValidator.d.ts +12 -0
  211. package/dist/validators/dependencyValidator.js +102 -0
  212. package/dist/validators/dependencyValidator.js.map +1 -0
  213. package/dist/validators/dependencyValidator.test.d.ts +1 -0
  214. package/dist/validators/dependencyValidator.test.js +179 -0
  215. package/dist/validators/dependencyValidator.test.js.map +1 -0
  216. package/dist/validators/directoryValidator.d.ts +30 -0
  217. package/dist/validators/directoryValidator.js +192 -0
  218. package/dist/validators/directoryValidator.js.map +1 -0
  219. package/dist/validators/directoryValidator.test.d.ts +1 -0
  220. package/dist/validators/directoryValidator.test.js +193 -0
  221. package/dist/validators/directoryValidator.test.js.map +1 -0
  222. package/dist/validators/fileValidator.d.ts +16 -0
  223. package/dist/validators/fileValidator.js +114 -0
  224. package/dist/validators/fileValidator.js.map +1 -0
  225. package/dist/validators/fileValidator.test.d.ts +1 -0
  226. package/dist/validators/fileValidator.test.js +108 -0
  227. package/dist/validators/fileValidator.test.js.map +1 -0
  228. package/dist/validators/urlValidator.d.ts +25 -0
  229. package/dist/validators/urlValidator.js +320 -0
  230. package/dist/validators/urlValidator.js.map +1 -0
  231. package/dist/validators/urlValidator.test.d.ts +1 -0
  232. package/dist/validators/urlValidator.test.js +252 -0
  233. package/dist/validators/urlValidator.test.js.map +1 -0
  234. package/dist/validators/validationEngine.d.ts +23 -0
  235. package/dist/validators/validationEngine.js +117 -0
  236. package/dist/validators/validationEngine.js.map +1 -0
  237. package/dist/validators/validationEngine.test.d.ts +1 -0
  238. package/dist/validators/validationEngine.test.js +82 -0
  239. package/dist/validators/validationEngine.test.js.map +1 -0
  240. package/dist/validators/versionValidator.d.ts +18 -0
  241. package/dist/validators/versionValidator.js +211 -0
  242. package/dist/validators/versionValidator.js.map +1 -0
  243. package/dist/validators/versionValidator.test.d.ts +1 -0
  244. package/dist/validators/versionValidator.test.js +308 -0
  245. package/dist/validators/versionValidator.test.js.map +1 -0
  246. package/package.json +98 -0
@@ -0,0 +1,353 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { run, runWithConfig } from './runner.js';
4
+ import { withOutputFile } from './test-utils/tempFiles.js';
5
+ import { captureConsoleLog, captureConsoleWarn } from './test-utils/console.js';
6
+ vi.mock('fastembed', () => ({
7
+ EmbeddingModel: { BGESmallENV15: 'BGESmallENV15' },
8
+ FlagEmbedding: {
9
+ init: vi.fn().mockResolvedValue({
10
+ passageEmbed: vi.fn().mockImplementation((texts) => {
11
+ return (async function* () {
12
+ yield texts.map(() => new Float32Array(384).fill(0.1));
13
+ })();
14
+ }),
15
+ queryEmbed: vi.fn().mockResolvedValue(new Float32Array(384).fill(0.1)),
16
+ }),
17
+ },
18
+ }));
19
+ vi.mock('glob', () => ({
20
+ glob: vi.fn().mockResolvedValue([]),
21
+ }));
22
+ vi.mock('child_process', () => ({
23
+ execFileSync: vi.fn().mockReturnValue(''),
24
+ }));
25
+ describe('runner', () => {
26
+ const cacheRoot = path.join(process.cwd(), '.doc-freshness-cache');
27
+ const transientCacheDirs = [
28
+ '.doc-freshness-cache/runner-inc',
29
+ '.doc-freshness-cache/runner-vs',
30
+ '.doc-freshness-cache/runner-vs-v',
31
+ '.doc-freshness-cache/runner-vs-nograph',
32
+ '.doc-freshness-cache/rv-clear',
33
+ ];
34
+ const captureLog = captureConsoleLog;
35
+ const captureWarn = captureConsoleWarn;
36
+ const baseConfig = {
37
+ rootDir: process.cwd(),
38
+ include: [],
39
+ exclude: [],
40
+ urlValidation: { enabled: false },
41
+ rules: {
42
+ 'file-path': { enabled: false },
43
+ 'external-url': { enabled: false },
44
+ version: { enabled: false },
45
+ 'directory-structure': { enabled: false },
46
+ 'code-pattern': { enabled: false },
47
+ dependency: { enabled: false },
48
+ },
49
+ graph: { enabled: false },
50
+ git: { enabled: false },
51
+ freshnessScoring: { enabled: false },
52
+ vectorSearch: { enabled: false },
53
+ cache: { enabled: false },
54
+ incremental: { enabled: false },
55
+ reporters: [],
56
+ verbose: false,
57
+ };
58
+ afterAll(async () => {
59
+ await Promise.all(transientCacheDirs.map((dir) => fs.promises.rm(path.join(process.cwd(), dir), { recursive: true, force: true }).catch(() => { })));
60
+ });
61
+ it('returns validation results with summary', async () => {
62
+ const results = await run({ ...baseConfig, include: ['src/parsers/extractors/baseExtractor.ts'] });
63
+ expect(results.summary).toBeDefined();
64
+ expect(typeof results.summary.total).toBe('number');
65
+ expect(typeof results.summary.valid).toBe('number');
66
+ expect(typeof results.summary.errors).toBe('number');
67
+ });
68
+ it('returns empty results when no docs match', async () => {
69
+ const results = await run({ ...baseConfig, include: ['nonexistent/**/*.md'] });
70
+ expect(results.summary.total).toBe(0);
71
+ expect(results.documents).toEqual([]);
72
+ });
73
+ it('clears cache when clearCache is set', async () => {
74
+ const cacheDir = path.join(process.cwd(), '.doc-freshness-cache', 'runner-test');
75
+ await fs.promises.mkdir(cacheDir, { recursive: true });
76
+ await fs.promises.writeFile(path.join(cacheDir, 'dummy.json'), '{}');
77
+ await run({
78
+ ...baseConfig,
79
+ cache: { enabled: true, dir: '.doc-freshness-cache/runner-test' },
80
+ clearCache: true,
81
+ });
82
+ const exists = await fs.promises
83
+ .access(cacheDir)
84
+ .then(() => true)
85
+ .catch(() => false);
86
+ expect(exists).toBe(false);
87
+ });
88
+ it('registers custom extractors and validators', async () => {
89
+ const extract = vi.fn().mockReturnValue([]);
90
+ const validateBatch = vi.fn().mockResolvedValue([]);
91
+ await run({
92
+ ...baseConfig,
93
+ customExtractors: [{ extract, supportsFormat: () => true }],
94
+ customValidators: { custom: { validateBatch } },
95
+ });
96
+ expect(true).toBe(true);
97
+ });
98
+ describe('verbose mode', () => {
99
+ it('logs config file path and source patterns', async () => {
100
+ const spy = captureLog();
101
+ await run({ ...baseConfig, verbose: true, _configFile: 'my-config.json', sourcePatterns: ['src/**'] });
102
+ const output = spy.mock.calls.flat().join('\n');
103
+ expect(output).toContain('my-config.json');
104
+ expect(output).toContain('src/**');
105
+ });
106
+ it('logs no-config notice', async () => {
107
+ const spy = captureLog();
108
+ await run({ ...baseConfig, verbose: true, _noConfigFile: true });
109
+ expect(spy.mock.calls.flat().join('\n')).toContain('No config file');
110
+ });
111
+ it('logs scan/validation progress', async () => {
112
+ const spy = captureLog();
113
+ await run({ ...baseConfig, verbose: true });
114
+ const output = spy.mock.calls.flat().join('\n');
115
+ expect(output).toContain('Scanning');
116
+ expect(output).toContain('Found');
117
+ expect(output).toContain('Extracted');
118
+ expect(output).toContain('Validating');
119
+ });
120
+ it('logs cache cleared', async () => {
121
+ const spy = captureLog();
122
+ await run({
123
+ ...baseConfig,
124
+ verbose: true,
125
+ clearCache: true,
126
+ cache: { enabled: true, dir: '.doc-freshness-cache/rv-clear' },
127
+ });
128
+ expect(spy.mock.calls.flat().join('\n')).toContain('Cache cleared');
129
+ });
130
+ });
131
+ describe('reporters', () => {
132
+ it('generates console report', async () => {
133
+ const spy = captureLog();
134
+ await run({ ...baseConfig, reporters: ['console'] });
135
+ expect(spy.mock.calls.flat().join('\n')).toContain('Documentation Freshness Report');
136
+ });
137
+ it('generates json to stdout without outputPath', async () => {
138
+ const spy = captureLog();
139
+ await run({ ...baseConfig, reporters: ['json'] });
140
+ const jsonStr = spy.mock.calls.flat().find((a) => typeof a === 'string' && a.startsWith('{'));
141
+ expect(JSON.parse(jsonStr)).toHaveProperty('summary');
142
+ });
143
+ it('generates markdown to stdout', async () => {
144
+ const spy = captureLog();
145
+ await run({ ...baseConfig, reporters: ['markdown'] });
146
+ expect(spy.mock.calls.flat().join('\n')).toContain('# Documentation Freshness Report');
147
+ });
148
+ it('generates enhanced to stdout', async () => {
149
+ const spy = captureLog();
150
+ await run({ ...baseConfig, reporters: ['enhanced'], graph: { enabled: true }, cache: { enabled: false } });
151
+ expect(spy.mock.calls.flat().join('\n')).toContain('Documentation Freshness Scan Report');
152
+ });
153
+ it('warns for unknown reporter in verbose', async () => {
154
+ const spy = captureWarn();
155
+ captureLog();
156
+ await run({ ...baseConfig, reporters: ['unknown'], verbose: true });
157
+ expect(spy.mock.calls.flat().join('\n')).toContain('Unknown reporter');
158
+ });
159
+ it.each(['json', 'markdown', 'enhanced'])('writes %s report to file with outputPath', async (reporter) => {
160
+ await withOutputFile(cacheRoot, `test-${reporter}.out`, async (outputPath) => {
161
+ const cfg = { ...baseConfig, reporters: [reporter], outputPath, cache: { enabled: false } };
162
+ if (reporter === 'enhanced')
163
+ cfg.graph = { enabled: true };
164
+ captureLog();
165
+ await run(cfg);
166
+ expect(await fs.promises.readFile(outputPath, 'utf-8')).toBeTruthy();
167
+ });
168
+ });
169
+ it.each(['json', 'markdown', 'enhanced'])('logs output path for %s in verbose mode', async (reporter) => {
170
+ await withOutputFile(cacheRoot, `test-v-${reporter}.out`, async (outputPath) => {
171
+ const cfg = {
172
+ ...baseConfig,
173
+ reporters: [reporter],
174
+ outputPath,
175
+ verbose: true,
176
+ cache: { enabled: false },
177
+ };
178
+ if (reporter === 'enhanced')
179
+ cfg.graph = { enabled: true };
180
+ const spy = captureLog();
181
+ await run(cfg);
182
+ expect(spy.mock.calls.flat().join('\n')).toContain('written to');
183
+ });
184
+ });
185
+ });
186
+ describe('graph and scoring', () => {
187
+ it('builds graph with git and saves cache', async () => {
188
+ captureLog();
189
+ const cacheDir = '.doc-freshness-cache/runner-graph';
190
+ try {
191
+ await run({ ...baseConfig, graph: { enabled: true }, cache: { enabled: true, dir: cacheDir } });
192
+ const exists = await fs.promises
193
+ .access(path.join(process.cwd(), cacheDir, 'graph-cache.json'))
194
+ .then(() => true)
195
+ .catch(() => false);
196
+ expect(exists).toBe(true);
197
+ }
198
+ finally {
199
+ await fs.promises.rm(path.join(process.cwd(), cacheDir), { recursive: true, force: true }).catch(() => { });
200
+ }
201
+ });
202
+ it('generates json with scores to file', async () => {
203
+ await withOutputFile(cacheRoot, 'test-scored.json', async (outputPath) => {
204
+ captureLog();
205
+ await run({
206
+ ...baseConfig,
207
+ reporters: ['json'],
208
+ outputPath,
209
+ graph: { enabled: true },
210
+ freshnessScoring: { enabled: true },
211
+ cache: { enabled: false },
212
+ });
213
+ expect(JSON.parse(await fs.promises.readFile(outputPath, 'utf-8'))).toHaveProperty('summary');
214
+ });
215
+ });
216
+ it('generates markdown with scores to file', async () => {
217
+ await withOutputFile(cacheRoot, 'test-scored.md', async (outputPath) => {
218
+ captureLog();
219
+ await run({
220
+ ...baseConfig,
221
+ reporters: ['markdown'],
222
+ outputPath,
223
+ graph: { enabled: true },
224
+ freshnessScoring: { enabled: true },
225
+ cache: { enabled: false },
226
+ });
227
+ expect(await fs.promises.readFile(outputPath, 'utf-8')).toContain('Freshness Scores');
228
+ });
229
+ });
230
+ it('generates enhanced with scores to file', async () => {
231
+ await withOutputFile(cacheRoot, 'test-enhanced-scored.md', async (outputPath) => {
232
+ captureLog();
233
+ await run({
234
+ ...baseConfig,
235
+ reporters: ['enhanced'],
236
+ outputPath,
237
+ graph: { enabled: true },
238
+ freshnessScoring: { enabled: true },
239
+ cache: { enabled: false },
240
+ });
241
+ expect(await fs.promises.readFile(outputPath, 'utf-8')).toContain('Documentation Freshness Scan Report');
242
+ });
243
+ });
244
+ });
245
+ describe('incremental mode', () => {
246
+ it('filters changed files with verbose logging', async () => {
247
+ const spy = captureLog();
248
+ await run({
249
+ ...baseConfig,
250
+ incremental: { enabled: true },
251
+ verbose: true,
252
+ cache: { dir: '.doc-freshness-cache/runner-inc' },
253
+ });
254
+ expect(spy.mock.calls.flat().join('\n')).toContain('Incremental');
255
+ });
256
+ });
257
+ it('loads URL cache when cache is enabled', async () => {
258
+ const cacheDir = '.doc-freshness-cache/runner-url';
259
+ const fullDir = path.join(process.cwd(), cacheDir);
260
+ await fs.promises.mkdir(fullDir, { recursive: true });
261
+ await fs.promises.writeFile(path.join(fullDir, 'url-cache.json'), '{}');
262
+ try {
263
+ expect(await run({ ...baseConfig, cache: { enabled: true, dir: cacheDir } })).toBeDefined();
264
+ }
265
+ finally {
266
+ await fs.promises.rm(fullDir, { recursive: true, force: true }).catch(() => { });
267
+ }
268
+ });
269
+ describe('vector search', () => {
270
+ it('runs vector search when enabled', async () => {
271
+ const spy = captureLog();
272
+ await run({
273
+ ...baseConfig,
274
+ vectorSearch: { enabled: true },
275
+ cache: { dir: '.doc-freshness-cache/runner-vs' },
276
+ });
277
+ const output = spy.mock.calls.flat().join('\n');
278
+ expect(output).toContain('semantic analysis');
279
+ expect(output).toContain('Analyzed');
280
+ });
281
+ it('runs vector search with verbose logging and graph', async () => {
282
+ const spy = captureLog();
283
+ await run({
284
+ ...baseConfig,
285
+ vectorSearch: { enabled: true },
286
+ graph: { enabled: true },
287
+ verbose: true,
288
+ cache: { dir: '.doc-freshness-cache/runner-vs-v' },
289
+ });
290
+ const output = spy.mock.calls.flat().join('\n');
291
+ expect(output).toContain('Indexing documentation');
292
+ expect(output).toContain('Finding semantic mismatches');
293
+ });
294
+ });
295
+ describe('runWithConfig', () => {
296
+ it('loads config from path and runs', async () => {
297
+ captureLog();
298
+ const result = await runWithConfig('/nonexistent/path.json');
299
+ expect(result.summary).toBeDefined();
300
+ });
301
+ });
302
+ describe('vector search without prior graph', () => {
303
+ it('builds source index independently when graph not enabled', async () => {
304
+ const spy = captureLog();
305
+ await run({
306
+ ...baseConfig,
307
+ vectorSearch: { enabled: true },
308
+ graph: { enabled: false },
309
+ verbose: true,
310
+ cache: { dir: '.doc-freshness-cache/runner-vs-nograph' },
311
+ });
312
+ const output = spy.mock.calls.flat().join('\n');
313
+ expect(output).toContain('Building source code index');
314
+ });
315
+ });
316
+ describe('reporters with freshness scores', () => {
317
+ it('console reporter uses generateWithScores when scores available', async () => {
318
+ const spy = captureLog();
319
+ await run({
320
+ ...baseConfig,
321
+ reporters: ['console'],
322
+ graph: { enabled: true },
323
+ freshnessScoring: { enabled: true },
324
+ cache: { enabled: false },
325
+ });
326
+ expect(spy.mock.calls.flat().join('\n')).toContain('Freshness Scores');
327
+ });
328
+ it('json reporter generates with scores', async () => {
329
+ const spy = captureLog();
330
+ await run({
331
+ ...baseConfig,
332
+ reporters: ['json'],
333
+ graph: { enabled: true },
334
+ freshnessScoring: { enabled: true },
335
+ cache: { enabled: false },
336
+ });
337
+ const jsonStr = spy.mock.calls.flat().find((a) => typeof a === 'string' && a.startsWith('{'));
338
+ expect(JSON.parse(jsonStr)).toHaveProperty('summary');
339
+ });
340
+ it('markdown reporter generates with scores to stdout', async () => {
341
+ const spy = captureLog();
342
+ await run({
343
+ ...baseConfig,
344
+ reporters: ['markdown'],
345
+ graph: { enabled: true },
346
+ freshnessScoring: { enabled: true },
347
+ cache: { enabled: false },
348
+ });
349
+ expect(spy.mock.calls.flat().join('\n')).toContain('Freshness Scores');
350
+ });
351
+ });
352
+ });
353
+ //# sourceMappingURL=runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.test.js","sourceRoot":"","sources":["../src/runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { DocFreshnessConfig, DocScore, Document, ProjectScores, ValidationResults } from '../types.js';
2
+ import type { CodeDocGraph } from '../graph/codeDocGraph.js';
3
+ import type { GitChangeTracker } from '../git/changeTracker.js';
4
+ /**
5
+ * Calculates freshness scores for documentation
6
+ */
7
+ export declare class FreshnessScorer {
8
+ private weights;
9
+ private thresholds;
10
+ constructor(config: DocFreshnessConfig);
11
+ /**
12
+ * Calculate freshness score for a single document
13
+ * Returns score 0-100 (100 = perfectly fresh)
14
+ */
15
+ calculateDocScore(doc: Document, validationResults: ValidationResults, gitTracker: GitChangeTracker | null, graph: CodeDocGraph | null): DocScore;
16
+ /**
17
+ * Calculate score based on how many references are still valid
18
+ */
19
+ private calculateReferenceValidityScore;
20
+ /**
21
+ * Calculate score based on time difference between doc and code updates
22
+ */
23
+ private calculateGitTimeDeltaScore;
24
+ /**
25
+ * Calculate score based on how frequently referenced code changes
26
+ */
27
+ private calculateChangeFrequencyScore;
28
+ /**
29
+ * Calculate what percentage of symbols in referenced files are documented
30
+ */
31
+ private calculateSymbolCoverageScore;
32
+ /**
33
+ * Convert numeric score to letter grade
34
+ */
35
+ private scoreToGrade;
36
+ /**
37
+ * Calculate scores for all documents
38
+ */
39
+ calculateProjectScores(documents: Document[], validationResults: ValidationResults, gitTracker: GitChangeTracker | null, graph: CodeDocGraph | null): ProjectScores;
40
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Calculates freshness scores for documentation
3
+ */
4
+ export class FreshnessScorer {
5
+ weights;
6
+ thresholds;
7
+ constructor(config) {
8
+ // Configurable weights for different factors
9
+ this.weights = {
10
+ referenceValidity: config.freshnessScoring?.weights?.referenceValidity ?? 0.4,
11
+ gitTimeDelta: config.freshnessScoring?.weights?.gitTimeDelta ?? 0.3,
12
+ codeChangeFrequency: config.freshnessScoring?.weights?.codeChangeFrequency ?? 0.15,
13
+ symbolCoverage: config.freshnessScoring?.weights?.symbolCoverage ?? 0.15,
14
+ };
15
+ this.thresholds = {
16
+ gradeA: config.freshnessScoring?.thresholds?.gradeA ?? 90,
17
+ gradeB: config.freshnessScoring?.thresholds?.gradeB ?? 80,
18
+ gradeC: config.freshnessScoring?.thresholds?.gradeC ?? 70,
19
+ gradeD: config.freshnessScoring?.thresholds?.gradeD ?? 60,
20
+ };
21
+ }
22
+ /**
23
+ * Calculate freshness score for a single document
24
+ * Returns score 0-100 (100 = perfectly fresh)
25
+ */
26
+ calculateDocScore(doc, validationResults, gitTracker, graph) {
27
+ const scores = {
28
+ referenceValidity: this.calculateReferenceValidityScore(doc, validationResults),
29
+ gitTimeDelta: this.calculateGitTimeDeltaScore(doc, gitTracker, graph),
30
+ codeChangeFrequency: this.calculateChangeFrequencyScore(doc, gitTracker, graph),
31
+ symbolCoverage: this.calculateSymbolCoverageScore(doc, graph),
32
+ };
33
+ // Calculate weighted total
34
+ const totalScore = scores.referenceValidity * this.weights.referenceValidity +
35
+ scores.gitTimeDelta * this.weights.gitTimeDelta +
36
+ scores.codeChangeFrequency * this.weights.codeChangeFrequency +
37
+ scores.symbolCoverage * this.weights.symbolCoverage;
38
+ return {
39
+ document: doc.path,
40
+ totalScore: Math.round(totalScore),
41
+ factors: scores,
42
+ grade: this.scoreToGrade(totalScore),
43
+ };
44
+ }
45
+ /**
46
+ * Calculate score based on how many references are still valid
47
+ */
48
+ calculateReferenceValidityScore(doc, validationResults) {
49
+ const docResults = validationResults.documents.find((d) => d.path === doc.path);
50
+ if (!docResults || doc.references.length === 0) {
51
+ return 100; // No references = assume fresh
52
+ }
53
+ const totalRefs = doc.references.length;
54
+ const invalidRefs = docResults.issues.filter((i) => i.severity === 'error').length;
55
+ return Math.round(((totalRefs - invalidRefs) / totalRefs) * 100);
56
+ }
57
+ /**
58
+ * Calculate score based on time difference between doc and code updates
59
+ */
60
+ calculateGitTimeDeltaScore(doc, gitTracker, graph) {
61
+ if (!gitTracker?.isGitRepo()) {
62
+ return 75; // Default score for non-git repos
63
+ }
64
+ const docCommitInfo = gitTracker.getFileCommitInfo(doc.path);
65
+ if (!docCommitInfo) {
66
+ return 50; // Doc not in git
67
+ }
68
+ const referencedFiles = graph?.getCodeReferencedByDoc(doc.path);
69
+ if (!referencedFiles || referencedFiles.size === 0) {
70
+ return 100; // No code references
71
+ }
72
+ let maxCodeTimestamp = 0;
73
+ for (const codeFile of referencedFiles) {
74
+ const codeCommitInfo = gitTracker.getFileCommitInfo(codeFile);
75
+ if (codeCommitInfo && codeCommitInfo.timestamp > maxCodeTimestamp) {
76
+ maxCodeTimestamp = codeCommitInfo.timestamp;
77
+ }
78
+ }
79
+ if (maxCodeTimestamp === 0) {
80
+ return 75; // Code not in git
81
+ }
82
+ // Doc was updated after code = fresh
83
+ if (docCommitInfo.timestamp >= maxCodeTimestamp) {
84
+ return 100;
85
+ }
86
+ // Calculate decay based on time difference
87
+ const daysDiff = (maxCodeTimestamp - docCommitInfo.timestamp) / (1000 * 60 * 60 * 24);
88
+ // Score decays: 100 at 0 days, ~50 at 30 days, ~25 at 90 days
89
+ const decayRate = 0.02;
90
+ return Math.max(0, Math.round(100 * Math.exp(-decayRate * daysDiff)));
91
+ }
92
+ /**
93
+ * Calculate score based on how frequently referenced code changes
94
+ */
95
+ calculateChangeFrequencyScore(doc, gitTracker, graph) {
96
+ if (!gitTracker?.isGitRepo()) {
97
+ return 75;
98
+ }
99
+ const referencedFiles = graph?.getCodeReferencedByDoc(doc.path);
100
+ if (!referencedFiles || referencedFiles.size === 0) {
101
+ return 100;
102
+ }
103
+ // High-churn code is harder to keep documented
104
+ // This is informational - not a penalty
105
+ return 75; // Placeholder - would need git log analysis
106
+ }
107
+ /**
108
+ * Calculate what percentage of symbols in referenced files are documented
109
+ */
110
+ calculateSymbolCoverageScore(doc, graph) {
111
+ const referencedFiles = graph?.getCodeReferencedByDoc(doc.path);
112
+ if (!referencedFiles || referencedFiles.size === 0) {
113
+ return 100;
114
+ }
115
+ const docSymbols = new Set(doc.references.filter((r) => r.type === 'code-pattern').map((r) => r.value));
116
+ let totalSymbols = 0;
117
+ let documentedSymbols = 0;
118
+ for (const codeFile of referencedFiles) {
119
+ const fileSymbols = graph?.codeSymbols?.get(codeFile);
120
+ if (fileSymbols) {
121
+ totalSymbols += fileSymbols.size;
122
+ for (const symbol of fileSymbols) {
123
+ if (docSymbols.has(symbol)) {
124
+ documentedSymbols++;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ if (totalSymbols === 0) {
130
+ return 100;
131
+ }
132
+ return Math.round((documentedSymbols / totalSymbols) * 100);
133
+ }
134
+ /**
135
+ * Convert numeric score to letter grade
136
+ */
137
+ scoreToGrade(score) {
138
+ if (score >= this.thresholds.gradeA)
139
+ return 'A';
140
+ if (score >= this.thresholds.gradeB)
141
+ return 'B';
142
+ if (score >= this.thresholds.gradeC)
143
+ return 'C';
144
+ if (score >= this.thresholds.gradeD)
145
+ return 'D';
146
+ return 'F';
147
+ }
148
+ /**
149
+ * Calculate scores for all documents
150
+ */
151
+ calculateProjectScores(documents, validationResults, gitTracker, graph) {
152
+ const docScores = documents.map((doc) => this.calculateDocScore(doc, validationResults, gitTracker, graph));
153
+ // Calculate overall project score
154
+ const avgScore = docScores.length > 0 ? docScores.reduce((sum, d) => sum + d.totalScore, 0) / docScores.length : 100;
155
+ return {
156
+ projectScore: Math.round(avgScore),
157
+ projectGrade: this.scoreToGrade(avgScore),
158
+ documents: docScores,
159
+ summary: {
160
+ total: docScores.length,
161
+ gradeA: docScores.filter((d) => d.grade === 'A').length,
162
+ gradeB: docScores.filter((d) => d.grade === 'B').length,
163
+ gradeC: docScores.filter((d) => d.grade === 'C').length,
164
+ gradeD: docScores.filter((d) => d.grade === 'D').length,
165
+ gradeF: docScores.filter((d) => d.grade === 'F').length,
166
+ },
167
+ };
168
+ }
169
+ }
170
+ //# sourceMappingURL=freshnessScorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshnessScorer.js","sourceRoot":"","sources":["../../src/scoring/freshnessScorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};