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,80 @@
1
+ /**
2
+ * Centralized patterns for detecting illustrative/placeholder content in documentation
3
+ *
4
+ * These patterns identify paths, filenames, and code symbols that are commonly used
5
+ * as examples in tutorials and documentation but don't represent actual files/code.
6
+ */
7
+ /**
8
+ * Patterns for detecting illustrative file/directory paths
9
+ * Used by: FilePathExtractor, DirectoryStructureExtractor, FileValidator, DirectoryValidator
10
+ */
11
+ export const ILLUSTRATIVE_PATH_PATTERNS = [
12
+ // Generic placeholder prefixes (case-insensitive)
13
+ /^(?:Your|My|Example|Sample|Demo|Test|Foo|Bar|Baz|Dummy|Mock|Fake|Stub)/i,
14
+ // Common tutorial placeholders
15
+ /^(?:first|second|third|another|some|new)\./i,
16
+ // Very short generic names without extensions
17
+ /^(?:foo|bar|baz|qux|quux)$/i,
18
+ // Paths containing angle brackets or curly braces (template syntax)
19
+ /<[^>]+>/,
20
+ /\{[^}]+\}/,
21
+ // Paths with obvious placeholder segments
22
+ /\/(?:your|my|example|sample)-/i,
23
+ /\/\[.*\]\//,
24
+ ];
25
+ /**
26
+ * Patterns for detecting illustrative code symbol names
27
+ * Used by: CodePatternExtractor, CodePatternValidator
28
+ */
29
+ export const ILLUSTRATIVE_SYMBOL_PATTERNS = [
30
+ // Generic placeholder prefixes followed by PascalCase
31
+ /^(?:Your|My|Example|Sample|Demo|Test|Foo|Bar|Baz|Dummy|Mock|Fake|Stub)[A-Z]/i,
32
+ // HTTP methods used as function names in REST tutorials
33
+ /^(?:POST|GET|PUT|DELETE|PATCH)$/,
34
+ // Very short names (1-2 chars) are likely false positives from word parsing
35
+ /^[a-z]{1,2}$/,
36
+ // Common tutorial component/function names
37
+ /^(?:Chat|App|Button|Card|Modal|Form|Input|List|Item|Header|Footer|Sidebar|Nav|Menu|Page|Home|About|Contact|Login|Signup|Profile|Dashboard|Settings)$/,
38
+ ];
39
+ /**
40
+ * Check if a path looks like an illustrative/placeholder path
41
+ */
42
+ export function isIllustrativePath(itemPath, customPatterns = []) {
43
+ const patterns = [...ILLUSTRATIVE_PATH_PATTERNS, ...customPatterns];
44
+ const segments = itemPath.split('/');
45
+ const filename = segments[segments.length - 1];
46
+ // Check filename against patterns
47
+ for (const pattern of patterns) {
48
+ if (pattern.test(filename)) {
49
+ return true;
50
+ }
51
+ }
52
+ // Check if any segment in the path looks illustrative
53
+ for (const segment of segments.slice(0, -1)) {
54
+ for (const pattern of patterns) {
55
+ if (pattern.test(segment)) {
56
+ return true;
57
+ }
58
+ }
59
+ }
60
+ return false;
61
+ }
62
+ /**
63
+ * Check if a code symbol name looks like an illustrative/placeholder name
64
+ */
65
+ export function isIllustrativeSymbol(name, customPatterns = []) {
66
+ const patterns = [...ILLUSTRATIVE_SYMBOL_PATTERNS, ...customPatterns];
67
+ for (const pattern of patterns) {
68
+ if (pattern.test(name)) {
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+ /**
75
+ * Convert string patterns from config to RegExp objects
76
+ */
77
+ export function compilePatterns(patterns) {
78
+ return patterns.map((p) => new RegExp(p, 'i'));
79
+ }
80
+ //# sourceMappingURL=illustrativePatterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"illustrativePatterns.js","sourceRoot":"","sources":["../../src/utils/illustrativePatterns.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAa;IAClD,kDAAkD;IAClD,yEAAyE;IACzE,+BAA+B;IAC/B,6CAA6C;IAC7C,8CAA8C;IAC9C,6BAA6B;IAC7B,oEAAoE;IACpE,SAAS;IACT,WAAW;IACX,0CAA0C;IAC1C,gCAAgC;IAChC,YAAY;CACb,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAa;IACpD,sDAAsD;IACtD,8EAA8E;IAC9E,wDAAwD;IACxD,iCAAiC;IACjC,4EAA4E;IAC5E,cAAc;IACd,2CAA2C;IAC3C,sJAAsJ;CACvJ,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,iBAA2B,EAAE;IAChF,MAAM,QAAQ,GAAG,CAAC,GAAG,0BAA0B,EAAE,GAAG,cAAc,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE/C,kCAAkC;IAClC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,iBAA2B,EAAE;IAC9E,MAAM,QAAQ,GAAG,CAAC,GAAG,4BAA4B,EAAE,GAAG,cAAc,CAAC,CAAC;IAEtE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAkB;IAChD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import { isIllustrativePath, isIllustrativeSymbol, compilePatterns, ILLUSTRATIVE_PATH_PATTERNS, ILLUSTRATIVE_SYMBOL_PATTERNS, } from './illustrativePatterns.js';
2
+ describe('compilePatterns', () => {
3
+ it('converts string patterns to case-insensitive RegExp', () => {
4
+ const patterns = compilePatterns(['^test', 'example$']);
5
+ expect(patterns).toHaveLength(2);
6
+ expect(patterns[0].test('TestFile')).toBe(true);
7
+ expect(patterns[1].test('myExample')).toBe(true);
8
+ });
9
+ });
10
+ describe('isIllustrativePath', () => {
11
+ it.each([
12
+ 'YourProject/file.ts',
13
+ 'my-project/src/index.ts',
14
+ 'Example.tsx',
15
+ 'sample-app/main.py',
16
+ 'foo',
17
+ 'src/<component>/file.ts',
18
+ 'src/{name}/file.ts',
19
+ 'first.ts',
20
+ ])('detects illustrative path: %s', (p) => {
21
+ expect(isIllustrativePath(p)).toBe(true);
22
+ });
23
+ it.each(['src/utils/helper.ts', 'package.json', 'tsconfig.json'])('does not flag real path: %s', (p) => {
24
+ expect(isIllustrativePath(p)).toBe(false);
25
+ });
26
+ it('supports custom patterns', () => {
27
+ const custom = [/^custom-placeholder/i];
28
+ expect(isIllustrativePath('custom-placeholder.ts', custom)).toBe(true);
29
+ expect(isIllustrativePath('real-file.ts', custom)).toBe(false);
30
+ });
31
+ });
32
+ describe('isIllustrativeSymbol', () => {
33
+ it.each(['YourComponent', 'ExampleService', 'FooBar', 'MockAdapter', 'POST', 'a', 'Chat', 'Dashboard'])('detects illustrative symbol: %s', (s) => {
34
+ expect(isIllustrativeSymbol(s)).toBe(true);
35
+ });
36
+ it.each(['DocumentParser', 'ValidationEngine', 'runParallel'])('does not flag real symbol: %s', (s) => {
37
+ expect(isIllustrativeSymbol(s)).toBe(false);
38
+ });
39
+ });
40
+ describe('pattern arrays are non-empty', () => {
41
+ it('ILLUSTRATIVE_PATH_PATTERNS has entries', () => {
42
+ expect(ILLUSTRATIVE_PATH_PATTERNS.length).toBeGreaterThan(0);
43
+ });
44
+ it('ILLUSTRATIVE_SYMBOL_PATTERNS has entries', () => {
45
+ expect(ILLUSTRATIVE_SYMBOL_PATTERNS.length).toBeGreaterThan(0);
46
+ });
47
+ });
48
+ //# sourceMappingURL=illustrativePatterns.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"illustrativePatterns.test.js","sourceRoot":"","sources":["../../src/utils/illustrativePatterns.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Document, IncrementalStats } from '../types.js';
2
+ /**
3
+ * Incremental checker for skipping unchanged documentation files
4
+ * Uses file hashes to detect changes between runs
5
+ */
6
+ export declare class IncrementalChecker {
7
+ private stateDir;
8
+ private stateFile;
9
+ private previousHashes;
10
+ private currentHashes;
11
+ constructor(stateDir?: string);
12
+ /**
13
+ * Load previous state from cache
14
+ */
15
+ loadState(): Promise<void>;
16
+ /**
17
+ * Save current state to cache
18
+ */
19
+ saveState(): Promise<void>;
20
+ /**
21
+ * Get MD5 hash of a file
22
+ */
23
+ getHash(filePath: string): Promise<string>;
24
+ /**
25
+ * Check if a file has changed since last run
26
+ */
27
+ shouldCheck(filePath: string): Promise<boolean>;
28
+ /**
29
+ * Filter documents to only include changed ones
30
+ */
31
+ filterChanged(documents: Document[]): Promise<Document[]>;
32
+ /**
33
+ * Get statistics about the incremental check
34
+ */
35
+ getStats(totalDocs: number, changedDocs: number): IncrementalStats;
36
+ }
@@ -0,0 +1,87 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import crypto from 'crypto';
4
+ /**
5
+ * Incremental checker for skipping unchanged documentation files
6
+ * Uses file hashes to detect changes between runs
7
+ */
8
+ export class IncrementalChecker {
9
+ stateDir;
10
+ stateFile;
11
+ previousHashes;
12
+ currentHashes;
13
+ constructor(stateDir = '.doc-freshness-cache') {
14
+ this.stateDir = stateDir;
15
+ this.stateFile = path.join(stateDir, 'file-hashes.json');
16
+ this.previousHashes = new Map();
17
+ this.currentHashes = new Map();
18
+ }
19
+ /**
20
+ * Load previous state from cache
21
+ */
22
+ async loadState() {
23
+ try {
24
+ const data = await fs.promises.readFile(this.stateFile, 'utf-8');
25
+ const parsed = JSON.parse(data);
26
+ this.previousHashes = new Map(Object.entries(parsed));
27
+ }
28
+ catch {
29
+ // No previous state
30
+ }
31
+ }
32
+ /**
33
+ * Save current state to cache
34
+ */
35
+ async saveState() {
36
+ await fs.promises.mkdir(this.stateDir, { recursive: true });
37
+ const data = Object.fromEntries(this.currentHashes);
38
+ await fs.promises.writeFile(this.stateFile, JSON.stringify(data, null, 2));
39
+ }
40
+ /**
41
+ * Get MD5 hash of a file
42
+ */
43
+ async getHash(filePath) {
44
+ const content = await fs.promises.readFile(filePath, 'utf-8');
45
+ return crypto.createHash('md5').update(content).digest('hex');
46
+ }
47
+ /**
48
+ * Check if a file has changed since last run
49
+ */
50
+ async shouldCheck(filePath) {
51
+ try {
52
+ const hash = await this.getHash(filePath);
53
+ this.currentHashes.set(filePath, hash);
54
+ const previousHash = this.previousHashes.get(filePath);
55
+ return hash !== previousHash;
56
+ }
57
+ catch {
58
+ // File read error - should check
59
+ return true;
60
+ }
61
+ }
62
+ /**
63
+ * Filter documents to only include changed ones
64
+ */
65
+ async filterChanged(documents) {
66
+ await this.loadState();
67
+ const changed = [];
68
+ for (const doc of documents) {
69
+ if (await this.shouldCheck(doc.absolutePath)) {
70
+ changed.push(doc);
71
+ }
72
+ }
73
+ return changed;
74
+ }
75
+ /**
76
+ * Get statistics about the incremental check
77
+ */
78
+ getStats(totalDocs, changedDocs) {
79
+ return {
80
+ total: totalDocs,
81
+ changed: changedDocs,
82
+ skipped: totalDocs - changedDocs,
83
+ percentSkipped: totalDocs > 0 ? Math.round(((totalDocs - changedDocs) / totalDocs) * 100) : 0,
84
+ };
85
+ }
86
+ }
87
+ //# sourceMappingURL=incremental.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental.js","sourceRoot":"","sources":["../../src/utils/incremental.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ import fs from 'fs';
2
+ import crypto from 'crypto';
3
+ import { IncrementalChecker } from './incremental.js';
4
+ function makeDoc(docPath) {
5
+ return {
6
+ path: docPath,
7
+ absolutePath: `/project/${docPath}`,
8
+ content: 'content',
9
+ format: 'markdown',
10
+ lines: ['content'],
11
+ references: [],
12
+ };
13
+ }
14
+ describe('IncrementalChecker', () => {
15
+ let checker;
16
+ beforeEach(() => {
17
+ checker = new IncrementalChecker('/tmp/test-cache');
18
+ });
19
+ describe('getStats', () => {
20
+ it.each([
21
+ { total: 10, changed: 3, skipped: 7, pct: 70 },
22
+ { total: 0, changed: 0, skipped: 0, pct: 0 },
23
+ { total: 5, changed: 5, skipped: 0, pct: 0 },
24
+ ])('computes stats for total=$total changed=$changed', ({ total, changed, skipped, pct }) => {
25
+ const stats = checker.getStats(total, changed);
26
+ expect(stats).toEqual({ total, changed, skipped, percentSkipped: pct });
27
+ });
28
+ });
29
+ describe('loadState', () => {
30
+ it('loads previous hashes from disk', async () => {
31
+ vi.spyOn(fs.promises, 'readFile').mockResolvedValue(JSON.stringify({ 'file.md': 'abc123' }));
32
+ await checker.loadState();
33
+ });
34
+ it('handles missing state file gracefully', async () => {
35
+ vi.spyOn(fs.promises, 'readFile').mockRejectedValue(new Error('ENOENT'));
36
+ await expect(checker.loadState()).resolves.not.toThrow();
37
+ });
38
+ });
39
+ describe('saveState', () => {
40
+ it('writes current hashes to disk', async () => {
41
+ const mkdirSpy = vi.spyOn(fs.promises, 'mkdir').mockResolvedValue(undefined);
42
+ const writeSpy = vi.spyOn(fs.promises, 'writeFile').mockResolvedValue(undefined);
43
+ await checker.saveState();
44
+ expect(mkdirSpy).toHaveBeenCalledWith('/tmp/test-cache', { recursive: true });
45
+ expect(writeSpy).toHaveBeenCalled();
46
+ });
47
+ });
48
+ describe('shouldCheck', () => {
49
+ it('returns true for new files not in previous state', async () => {
50
+ vi.spyOn(fs.promises, 'readFile').mockResolvedValueOnce(JSON.stringify({})).mockResolvedValueOnce('file content');
51
+ await checker.loadState();
52
+ expect(await checker.shouldCheck('/project/new.md')).toBe(true);
53
+ });
54
+ it('returns false for unchanged files', async () => {
55
+ const content = 'file content';
56
+ const expectedHash = crypto.createHash('md5').update(content).digest('hex');
57
+ vi.spyOn(fs.promises, 'readFile')
58
+ .mockResolvedValueOnce(JSON.stringify({ '/project/same.md': expectedHash }))
59
+ .mockResolvedValueOnce(content);
60
+ await checker.loadState();
61
+ expect(await checker.shouldCheck('/project/same.md')).toBe(false);
62
+ });
63
+ it('returns true when file read fails', async () => {
64
+ vi.spyOn(fs.promises, 'readFile').mockResolvedValueOnce(JSON.stringify({})).mockRejectedValueOnce(new Error('read error'));
65
+ await checker.loadState();
66
+ expect(await checker.shouldCheck('/project/broken.md')).toBe(true);
67
+ });
68
+ });
69
+ describe('filterChanged', () => {
70
+ it('returns only documents whose content has changed', async () => {
71
+ const content = 'unchanged';
72
+ const hash = crypto.createHash('md5').update(content).digest('hex');
73
+ vi.spyOn(fs.promises, 'readFile')
74
+ .mockResolvedValueOnce(JSON.stringify({ '/project/unchanged.md': hash }))
75
+ .mockResolvedValueOnce(content)
76
+ .mockResolvedValueOnce('new content');
77
+ const docs = [makeDoc('unchanged.md'), makeDoc('changed.md')];
78
+ const changed = await checker.filterChanged(docs);
79
+ expect(changed).toHaveLength(1);
80
+ expect(changed[0].path).toBe('changed.md');
81
+ });
82
+ });
83
+ });
84
+ //# sourceMappingURL=incremental.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental.test.js","sourceRoot":"","sources":["../../src/utils/incremental.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Run tasks in parallel with concurrency limit.
3
+ * Individual task failures don't abort remaining tasks --
4
+ * all rejections are collected and re-thrown via Promise.allSettled + Promise.all.
5
+ */
6
+ export declare function runParallel<T>(tasks: Array<() => Promise<T>>, concurrency?: number): Promise<T[]>;
7
+ /**
8
+ * Batch an array into chunks
9
+ */
10
+ export declare function batch<T>(array: T[], size: number): T[][];
11
+ /**
12
+ * Delay execution
13
+ */
14
+ export declare function delay(ms: number): Promise<void>;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Run tasks in parallel with concurrency limit.
3
+ * Individual task failures don't abort remaining tasks --
4
+ * all rejections are collected and re-thrown via Promise.allSettled + Promise.all.
5
+ */
6
+ export async function runParallel(tasks, concurrency = 10) {
7
+ const results = [];
8
+ const executing = new Set();
9
+ for (const task of tasks) {
10
+ const promise = task();
11
+ results.push(promise);
12
+ const cleanup = promise
13
+ .then(() => { }, () => { })
14
+ .then(() => {
15
+ executing.delete(cleanup);
16
+ });
17
+ executing.add(cleanup);
18
+ if (executing.size >= concurrency) {
19
+ await Promise.race(executing);
20
+ }
21
+ }
22
+ return Promise.all(results);
23
+ }
24
+ /**
25
+ * Batch an array into chunks
26
+ */
27
+ export function batch(array, size) {
28
+ if (size <= 0) {
29
+ throw new Error('Batch size must be greater than 0');
30
+ }
31
+ const batches = [];
32
+ for (let i = 0; i < array.length; i += size) {
33
+ batches.push(array.slice(i, i + size));
34
+ }
35
+ return batches;
36
+ }
37
+ /**
38
+ * Delay execution
39
+ */
40
+ export function delay(ms) {
41
+ return new Promise((resolve) => setTimeout(resolve, ms));
42
+ }
43
+ //# sourceMappingURL=parallel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel.js","sourceRoot":"","sources":["../../src/utils/parallel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAI,KAA8B,EAAE,cAAsB,EAAE;IAC3F,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,SAAS,GAAuB,IAAI,GAAG,EAAE,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEtB,MAAM,OAAO,GAAG,OAAO;aACpB,IAAI,CACH,GAAG,EAAE,GAAE,CAAC,EACR,GAAG,EAAE,GAAE,CAAC,CACT;aACA,IAAI,CAAC,GAAG,EAAE;YACT,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACL,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEvB,IAAI,SAAS,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;YAClC,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAI,KAAU,EAAE,IAAY;IAC/C,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,OAAO,GAAU,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import { runParallel, batch, delay } from './parallel.js';
2
+ describe('batch', () => {
3
+ it.each([
4
+ { input: [1, 2, 3, 4, 5], size: 2, expected: [[1, 2], [3, 4], [5]] },
5
+ { input: [1, 2, 3], size: 5, expected: [[1, 2, 3]] },
6
+ { input: [], size: 3, expected: [] },
7
+ ])('splits array of $input.length into chunks of $size', ({ input, size, expected }) => {
8
+ expect(batch(input, size)).toEqual(expected);
9
+ });
10
+ it('throws when batch size is non-positive', () => {
11
+ expect(() => batch([1, 2, 3], 0)).toThrow('Batch size must be greater than 0');
12
+ expect(() => batch([1, 2, 3], -1)).toThrow('Batch size must be greater than 0');
13
+ });
14
+ });
15
+ describe('delay', () => {
16
+ it('resolves after the specified time', async () => {
17
+ const start = Date.now();
18
+ await delay(50);
19
+ expect(Date.now() - start).toBeGreaterThanOrEqual(40);
20
+ });
21
+ });
22
+ describe('runParallel', () => {
23
+ it('runs all tasks and returns results in order', async () => {
24
+ const tasks = [() => Promise.resolve(1), () => Promise.resolve(2), () => Promise.resolve(3)];
25
+ const results = await runParallel(tasks);
26
+ expect(results).toEqual([1, 2, 3]);
27
+ });
28
+ it('respects concurrency limit', async () => {
29
+ let concurrent = 0;
30
+ let maxConcurrent = 0;
31
+ const makeTask = (val) => async () => {
32
+ concurrent++;
33
+ maxConcurrent = Math.max(maxConcurrent, concurrent);
34
+ await delay(20);
35
+ concurrent--;
36
+ return val;
37
+ };
38
+ const tasks = Array.from({ length: 6 }, (_, i) => makeTask(i));
39
+ const results = await runParallel(tasks, 2);
40
+ expect(results).toEqual([0, 1, 2, 3, 4, 5]);
41
+ expect(maxConcurrent).toBeLessThanOrEqual(2);
42
+ });
43
+ it('propagates errors from tasks', async () => {
44
+ const tasks = [() => Promise.resolve(1), () => Promise.reject(new Error('fail'))];
45
+ await expect(runParallel(tasks)).rejects.toThrow('fail');
46
+ });
47
+ });
48
+ //# sourceMappingURL=parallel.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel.test.js","sourceRoot":"","sources":["../../src/utils/parallel.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE1D,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,IAAI,CAAC;QACN,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;QACpE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;QACpD,EAAE,KAAK,EAAE,EAAc,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;KACjD,CAAC,CAAC,oDAAoD,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrF,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;QAC/E,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7F,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE;YAC3C,UAAU,EAAE,CAAC;YACb,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;YAChB,UAAU,EAAE,CAAC;YACb,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAE5C,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,aAAa,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAClF,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Returns true if candidatePath is equal to or nested within rootDir.
3
+ */
4
+ export declare function isWithinRoot(candidatePath: string, rootDir: string): boolean;
5
+ /**
6
+ * Resolve project root from config or process cwd.
7
+ */
8
+ export declare function resolveProjectRoot(configRootDir?: string): string;
9
+ /**
10
+ * Resolve a document directory relative to project root.
11
+ */
12
+ export declare function resolveDocumentDir(rootDir: string, documentPath: string): string;
@@ -0,0 +1,22 @@
1
+ import path from 'path';
2
+ /**
3
+ * Returns true if candidatePath is equal to or nested within rootDir.
4
+ */
5
+ export function isWithinRoot(candidatePath, rootDir) {
6
+ const resolvedRoot = path.resolve(rootDir);
7
+ const resolvedCandidate = path.resolve(candidatePath);
8
+ return resolvedCandidate === resolvedRoot || resolvedCandidate.startsWith(resolvedRoot + path.sep);
9
+ }
10
+ /**
11
+ * Resolve project root from config or process cwd.
12
+ */
13
+ export function resolveProjectRoot(configRootDir) {
14
+ return path.resolve(configRootDir || process.cwd());
15
+ }
16
+ /**
17
+ * Resolve a document directory relative to project root.
18
+ */
19
+ export function resolveDocumentDir(rootDir, documentPath) {
20
+ return path.dirname(path.resolve(rootDir, documentPath));
21
+ }
22
+ //# sourceMappingURL=pathSecurity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathSecurity.js","sourceRoot":"","sources":["../../src/utils/pathSecurity.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,aAAqB,EAAE,OAAe;IACjE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACtD,OAAO,iBAAiB,KAAK,YAAY,IAAI,iBAAiB,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;AACrG,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAsB;IACvD,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,YAAoB;IACtE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import path from 'path';
2
+ import { isWithinRoot, resolveProjectRoot, resolveDocumentDir } from './pathSecurity.js';
3
+ describe('isWithinRoot', () => {
4
+ const root = '/project';
5
+ it.each([
6
+ ['/project/src/file.ts', true],
7
+ ['/project', true],
8
+ ['/project/deep/nested/file.ts', true],
9
+ ['/other/place', false],
10
+ ['/projectExtra/file.ts', false],
11
+ ])('isWithinRoot(%s, /project) => %s', (candidate, expected) => {
12
+ expect(isWithinRoot(candidate, root)).toBe(expected);
13
+ });
14
+ it('resolves relative paths before comparing', () => {
15
+ expect(isWithinRoot('/project/src/../src/file.ts', root)).toBe(true);
16
+ expect(isWithinRoot('/project/../other', root)).toBe(false);
17
+ });
18
+ });
19
+ describe('resolveProjectRoot', () => {
20
+ it('returns resolved configRootDir when provided', () => {
21
+ expect(resolveProjectRoot('/my/project')).toBe(path.resolve('/my/project'));
22
+ });
23
+ it('falls back to process.cwd() when no arg', () => {
24
+ expect(resolveProjectRoot()).toBe(path.resolve(process.cwd()));
25
+ expect(resolveProjectRoot(undefined)).toBe(path.resolve(process.cwd()));
26
+ });
27
+ });
28
+ describe('resolveDocumentDir', () => {
29
+ it('returns the directory of the document relative to rootDir', () => {
30
+ const result = resolveDocumentDir('/project', 'docs/guide/README.md');
31
+ expect(result).toBe(path.resolve('/project', 'docs/guide'));
32
+ });
33
+ });
34
+ //# sourceMappingURL=pathSecurity.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathSecurity.test.js","sourceRoot":"","sources":["../../src/utils/pathSecurity.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,UAAU,CAAC;IAExB,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,sBAAsB,EAAE,IAAI,CAAC;QAC9B,CAAC,UAAU,EAAE,IAAI,CAAC;QAClB,CAAC,8BAA8B,EAAE,IAAI,CAAC;QACtC,CAAC,cAAc,EAAE,KAAK,CAAC;QACvB,CAAC,uBAAuB,EAAE,KAAK,CAAC;KACjC,CAAC,CAAC,kCAAkC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QAC7D,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,YAAY,CAAC,6BAA6B,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,MAAM,CAAC,YAAY,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC;QACtE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Find the most similar string from a list using Levenshtein distance
3
+ */
4
+ export declare function findSimilar(target: string, candidates: string[], maxDistance?: number): string | null;
5
+ /**
6
+ * Calculate Levenshtein distance between two strings
7
+ */
8
+ export declare function levenshteinDistance(a: string, b: string): number;
9
+ /**
10
+ * Calculate similarity ratio (0-1) between two strings
11
+ */
12
+ export declare function similarityRatio(a: string, b: string): number;