@hyperfrontend/project-scope 0.2.1 → 0.2.3

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 (443) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +3 -4
  3. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs.js +7 -0
  4. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js +5 -0
  5. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.cjs.js +13 -0
  6. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js +8 -0
  7. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.cjs.js +10 -0
  8. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js +8 -0
  9. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs.js +6 -0
  10. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js +5 -0
  11. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.cjs.js +7 -0
  12. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js +5 -0
  13. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js +6 -0
  14. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js +5 -0
  15. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js +9 -0
  16. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js +6 -0
  17. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.cjs.js +7 -0
  18. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js +7 -0
  19. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs.js +15 -0
  20. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js +9 -0
  21. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js +6 -0
  22. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js +5 -0
  23. package/_dependencies/@hyperfrontend/logging/index.cjs.js +191 -0
  24. package/_dependencies/@hyperfrontend/logging/index.d.ts +151 -0
  25. package/_dependencies/@hyperfrontend/logging/index.esm.js +186 -0
  26. package/_shared/core/cache/index.cjs.js +135 -0
  27. package/_shared/core/cache/index.esm.js +128 -0
  28. package/_shared/core/errors/structured-errors/index.cjs.js +28 -0
  29. package/_shared/core/errors/structured-errors/index.esm.js +23 -0
  30. package/_shared/core/fs/guard/index.cjs.js +7 -0
  31. package/_shared/core/fs/guard/index.esm.js +5 -0
  32. package/_shared/core/fs/stat/index.cjs.js +47 -0
  33. package/_shared/core/fs/stat/index.esm.js +41 -0
  34. package/_shared/core/path/confine/index.cjs.js +22 -0
  35. package/_shared/core/path/confine/index.esm.js +19 -0
  36. package/_shared/core/path/join/index.cjs.js +13 -0
  37. package/_shared/core/path/join/index.esm.js +10 -0
  38. package/_shared/core/path/normalize/index.cjs.js +37 -0
  39. package/_shared/core/path/normalize/index.esm.js +31 -0
  40. package/_shared/core/path/resolve/index.cjs.js +47 -0
  41. package/_shared/core/path/resolve/index.esm.js +41 -0
  42. package/_shared/core/path/segments/index.cjs.js +38 -0
  43. package/_shared/core/path/segments/index.esm.js +31 -0
  44. package/_shared/core/patterns/glob/index.cjs.js +145 -0
  45. package/_shared/core/patterns/glob/index.esm.js +136 -0
  46. package/_shared/core/platform/detect/index.cjs.js +103 -0
  47. package/_shared/core/platform/detect/index.esm.js +95 -0
  48. package/_shared/core/platform/line-endings/index.cjs.js +52 -0
  49. package/_shared/core/platform/line-endings/index.esm.js +44 -0
  50. package/_shared/project/config/patterns/index.cjs.js +172 -0
  51. package/_shared/project/config/patterns/index.esm.js +169 -0
  52. package/_shared/tech/monorepo/pnpm-workspaces/index.cjs.js +33 -0
  53. package/_shared/tech/monorepo/pnpm-workspaces/index.esm.js +31 -0
  54. package/_shared/tech/shared-utils/detector-helpers/index.cjs.js +48 -0
  55. package/_shared/tech/shared-utils/detector-helpers/index.esm.js +43 -0
  56. package/_shared/vfs/types/index.cjs.js +14 -0
  57. package/_shared/vfs/types/index.esm.js +12 -0
  58. package/cli/index.cjs.js +1706 -1910
  59. package/cli/index.d.ts +273 -7
  60. package/cli/index.d.ts.map +1 -1
  61. package/cli/index.esm.js +1593 -1797
  62. package/core/encoding/index.cjs.js +86 -401
  63. package/core/encoding/index.d.ts +186 -3
  64. package/core/encoding/index.d.ts.map +1 -1
  65. package/core/encoding/index.esm.js +78 -392
  66. package/core/fs/index.cjs.js +243 -583
  67. package/core/fs/index.d.ts +479 -6
  68. package/core/fs/index.d.ts.map +1 -1
  69. package/core/fs/index.esm.js +233 -573
  70. package/core/index.cjs.js +526 -1746
  71. package/core/index.d.ts +486 -9
  72. package/core/index.d.ts.map +1 -1
  73. package/core/index.esm.js +515 -1732
  74. package/core/path/index.cjs.js +8 -234
  75. package/core/path/index.d.ts +327 -5
  76. package/core/path/index.d.ts.map +1 -1
  77. package/core/path/index.esm.js +8 -235
  78. package/core/platform/index.cjs.js +5 -216
  79. package/core/platform/index.d.ts +185 -3
  80. package/core/platform/index.d.ts.map +1 -1
  81. package/core/platform/index.esm.js +3 -212
  82. package/heuristics/dependencies/index.cjs.js +105 -493
  83. package/heuristics/dependencies/index.d.ts +99 -2
  84. package/heuristics/dependencies/index.d.ts.map +1 -1
  85. package/heuristics/dependencies/index.esm.js +81 -469
  86. package/heuristics/entry-points/index.cjs.js +93 -796
  87. package/heuristics/entry-points/index.d.ts +123 -2
  88. package/heuristics/entry-points/index.d.ts.map +1 -1
  89. package/heuristics/entry-points/index.esm.js +74 -777
  90. package/heuristics/framework/index.cjs.js +1483 -1411
  91. package/heuristics/framework/index.d.ts +104 -2
  92. package/heuristics/framework/index.d.ts.map +1 -1
  93. package/heuristics/framework/index.esm.js +1419 -1347
  94. package/heuristics/index.cjs.js +3220 -3306
  95. package/heuristics/index.d.ts +4 -5
  96. package/heuristics/index.d.ts.map +1 -1
  97. package/heuristics/index.esm.js +3244 -3330
  98. package/heuristics/project-type/index.cjs.js +1489 -1438
  99. package/heuristics/project-type/index.d.ts +64 -2
  100. package/heuristics/project-type/index.d.ts.map +1 -1
  101. package/heuristics/project-type/index.esm.js +1419 -1368
  102. package/index.cjs.js +3058 -3532
  103. package/index.d.ts +44 -10
  104. package/index.d.ts.map +1 -1
  105. package/index.esm.js +2914 -3376
  106. package/models/index.cjs.js +0 -1
  107. package/models/index.d.ts +20 -14
  108. package/models/index.d.ts.map +1 -1
  109. package/models/index.esm.js +0 -1
  110. package/nx/index.cjs.js +166 -579
  111. package/nx/index.d.ts +279 -4
  112. package/nx/index.d.ts.map +1 -1
  113. package/nx/index.esm.js +148 -556
  114. package/package.json +13 -12
  115. package/project/config/index.cjs.js +127 -1063
  116. package/project/config/index.d.ts +202 -4
  117. package/project/config/index.d.ts.map +1 -1
  118. package/project/config/index.esm.js +110 -1044
  119. package/project/index.cjs.js +328 -1101
  120. package/project/index.d.ts +4 -5
  121. package/project/index.d.ts.map +1 -1
  122. package/project/index.esm.js +307 -1077
  123. package/project/package/index.cjs.js +196 -473
  124. package/project/package/index.d.ts +280 -3
  125. package/project/package/index.d.ts.map +1 -1
  126. package/project/package/index.esm.js +183 -459
  127. package/project/root/index.cjs.js +109 -417
  128. package/project/root/index.d.ts +83 -2
  129. package/project/root/index.d.ts.map +1 -1
  130. package/project/root/index.esm.js +98 -406
  131. package/project/traversal/index.cjs.js +96 -622
  132. package/project/traversal/index.d.ts +165 -3
  133. package/project/traversal/index.d.ts.map +1 -1
  134. package/project/traversal/index.esm.js +82 -608
  135. package/tech/backend/index.cjs.js +223 -508
  136. package/tech/backend/index.d.ts +205 -8
  137. package/tech/backend/index.d.ts.map +1 -1
  138. package/tech/backend/index.esm.js +202 -487
  139. package/tech/build/index.cjs.js +350 -636
  140. package/tech/build/index.d.ts +276 -10
  141. package/tech/build/index.d.ts.map +1 -1
  142. package/tech/build/index.esm.js +328 -614
  143. package/tech/frontend/index.cjs.js +507 -685
  144. package/tech/frontend/index.d.ts +379 -15
  145. package/tech/frontend/index.d.ts.map +1 -1
  146. package/tech/frontend/index.esm.js +483 -661
  147. package/tech/index.cjs.js +1581 -1420
  148. package/tech/index.d.ts +55 -32
  149. package/tech/index.d.ts.map +1 -1
  150. package/tech/index.esm.js +1515 -1354
  151. package/tech/legacy/index.cjs.js +99 -449
  152. package/tech/legacy/index.d.ts +125 -7
  153. package/tech/legacy/index.d.ts.map +1 -1
  154. package/tech/legacy/index.esm.js +81 -431
  155. package/tech/linting/index.cjs.js +138 -523
  156. package/tech/linting/index.d.ts +129 -7
  157. package/tech/linting/index.d.ts.map +1 -1
  158. package/tech/linting/index.esm.js +118 -503
  159. package/tech/monorepo/index.cjs.js +246 -573
  160. package/tech/monorepo/index.d.ts +241 -10
  161. package/tech/monorepo/index.d.ts.map +1 -1
  162. package/tech/monorepo/index.esm.js +226 -553
  163. package/tech/testing/index.cjs.js +216 -571
  164. package/tech/testing/index.d.ts +176 -8
  165. package/tech/testing/index.d.ts.map +1 -1
  166. package/tech/testing/index.esm.js +198 -553
  167. package/tech/types/index.cjs.js +123 -506
  168. package/tech/types/index.d.ts +120 -2
  169. package/tech/types/index.d.ts.map +1 -1
  170. package/tech/types/index.esm.js +101 -484
  171. package/vfs/index.cjs.js +647 -1142
  172. package/vfs/index.d.ts +360 -6
  173. package/vfs/index.d.ts.map +1 -1
  174. package/vfs/index.esm.js +672 -1167
  175. package/ARCHITECTURE.md +0 -370
  176. package/analyze.d.ts +0 -33
  177. package/analyze.d.ts.map +0 -1
  178. package/cli/commands/analyze.d.ts +0 -28
  179. package/cli/commands/analyze.d.ts.map +0 -1
  180. package/cli/commands/config.d.ts +0 -27
  181. package/cli/commands/config.d.ts.map +0 -1
  182. package/cli/commands/deps.d.ts +0 -24
  183. package/cli/commands/deps.d.ts.map +0 -1
  184. package/cli/commands/tree.d.ts +0 -36
  185. package/cli/commands/tree.d.ts.map +0 -1
  186. package/cli/index.cjs.js.map +0 -1
  187. package/cli/index.esm.js.map +0 -1
  188. package/cli/run.d.ts +0 -25
  189. package/cli/run.d.ts.map +0 -1
  190. package/cli/types.d.ts +0 -55
  191. package/cli/types.d.ts.map +0 -1
  192. package/core/cache.d.ts +0 -158
  193. package/core/cache.d.ts.map +0 -1
  194. package/core/encoding/convert.d.ts +0 -32
  195. package/core/encoding/convert.d.ts.map +0 -1
  196. package/core/encoding/detect.d.ts +0 -91
  197. package/core/encoding/detect.d.ts.map +0 -1
  198. package/core/encoding/index.cjs.js.map +0 -1
  199. package/core/encoding/index.esm.js.map +0 -1
  200. package/core/errors/structured-errors.d.ts +0 -66
  201. package/core/errors/structured-errors.d.ts.map +0 -1
  202. package/core/fs/directory.d.ts +0 -91
  203. package/core/fs/directory.d.ts.map +0 -1
  204. package/core/fs/index.cjs.js.map +0 -1
  205. package/core/fs/index.esm.js.map +0 -1
  206. package/core/fs/read.d.ts +0 -94
  207. package/core/fs/read.d.ts.map +0 -1
  208. package/core/fs/stat.d.ts +0 -58
  209. package/core/fs/stat.d.ts.map +0 -1
  210. package/core/fs/traversal.d.ts +0 -26
  211. package/core/fs/traversal.d.ts.map +0 -1
  212. package/core/fs/write.d.ts +0 -75
  213. package/core/fs/write.d.ts.map +0 -1
  214. package/core/index.cjs.js.map +0 -1
  215. package/core/index.esm.js.map +0 -1
  216. package/core/logger.d.ts +0 -111
  217. package/core/logger.d.ts.map +0 -1
  218. package/core/path/index.cjs.js.map +0 -1
  219. package/core/path/index.esm.js.map +0 -1
  220. package/core/path/join.d.ts +0 -17
  221. package/core/path/join.d.ts.map +0 -1
  222. package/core/path/normalize.d.ts +0 -37
  223. package/core/path/normalize.d.ts.map +0 -1
  224. package/core/path/resolve.d.ts +0 -52
  225. package/core/path/resolve.d.ts.map +0 -1
  226. package/core/path/segments.d.ts +0 -59
  227. package/core/path/segments.d.ts.map +0 -1
  228. package/core/patterns/glob.d.ts +0 -42
  229. package/core/patterns/glob.d.ts.map +0 -1
  230. package/core/platform/detect.d.ts +0 -66
  231. package/core/platform/detect.d.ts.map +0 -1
  232. package/core/platform/index.cjs.js.map +0 -1
  233. package/core/platform/index.esm.js.map +0 -1
  234. package/core/platform/line-endings.d.ts +0 -48
  235. package/core/platform/line-endings.d.ts.map +0 -1
  236. package/heuristics/dependencies/analyze.d.ts +0 -77
  237. package/heuristics/dependencies/analyze.d.ts.map +0 -1
  238. package/heuristics/dependencies/index.cjs.js.map +0 -1
  239. package/heuristics/dependencies/index.esm.js.map +0 -1
  240. package/heuristics/entry-points/discover.d.ts +0 -113
  241. package/heuristics/entry-points/discover.d.ts.map +0 -1
  242. package/heuristics/entry-points/index.cjs.js.map +0 -1
  243. package/heuristics/entry-points/index.esm.js.map +0 -1
  244. package/heuristics/framework/identify.d.ts +0 -84
  245. package/heuristics/framework/identify.d.ts.map +0 -1
  246. package/heuristics/framework/index.cjs.js.map +0 -1
  247. package/heuristics/framework/index.esm.js.map +0 -1
  248. package/heuristics/index.cjs.js.map +0 -1
  249. package/heuristics/index.esm.js.map +0 -1
  250. package/heuristics/project-type/detect.d.ts +0 -61
  251. package/heuristics/project-type/detect.d.ts.map +0 -1
  252. package/heuristics/project-type/index.cjs.js.map +0 -1
  253. package/heuristics/project-type/index.esm.js.map +0 -1
  254. package/index.cjs.js.map +0 -1
  255. package/index.esm.js.map +0 -1
  256. package/models/index.cjs.js.map +0 -1
  257. package/models/index.esm.js.map +0 -1
  258. package/nx/detect.d.ts +0 -105
  259. package/nx/detect.d.ts.map +0 -1
  260. package/nx/devkit-loader.d.ts +0 -62
  261. package/nx/devkit-loader.d.ts.map +0 -1
  262. package/nx/index.cjs.js.map +0 -1
  263. package/nx/index.esm.js.map +0 -1
  264. package/nx/project-config.d.ts +0 -111
  265. package/nx/project-config.d.ts.map +0 -1
  266. package/project/config/detect.d.ts +0 -77
  267. package/project/config/detect.d.ts.map +0 -1
  268. package/project/config/index.cjs.js.map +0 -1
  269. package/project/config/index.esm.js.map +0 -1
  270. package/project/config/parse.d.ts +0 -53
  271. package/project/config/parse.d.ts.map +0 -1
  272. package/project/config/patterns.d.ts +0 -31
  273. package/project/config/patterns.d.ts.map +0 -1
  274. package/project/index.cjs.js.map +0 -1
  275. package/project/index.esm.js.map +0 -1
  276. package/project/package/dependencies.d.ts +0 -101
  277. package/project/package/dependencies.d.ts.map +0 -1
  278. package/project/package/index.cjs.js.map +0 -1
  279. package/project/package/index.esm.js.map +0 -1
  280. package/project/package/read.d.ts +0 -67
  281. package/project/package/read.d.ts.map +0 -1
  282. package/project/root/detect.d.ts +0 -65
  283. package/project/root/detect.d.ts.map +0 -1
  284. package/project/root/index.cjs.js.map +0 -1
  285. package/project/root/index.esm.js.map +0 -1
  286. package/project/traversal/index.cjs.js.map +0 -1
  287. package/project/traversal/index.esm.js.map +0 -1
  288. package/project/traversal/search.d.ts +0 -59
  289. package/project/traversal/search.d.ts.map +0 -1
  290. package/project/traversal/walk.d.ts +0 -63
  291. package/project/traversal/walk.d.ts.map +0 -1
  292. package/tech/backend/detect-all.d.ts +0 -13
  293. package/tech/backend/detect-all.d.ts.map +0 -1
  294. package/tech/backend/express.d.ts +0 -11
  295. package/tech/backend/express.d.ts.map +0 -1
  296. package/tech/backend/fastify.d.ts +0 -11
  297. package/tech/backend/fastify.d.ts.map +0 -1
  298. package/tech/backend/hono.d.ts +0 -11
  299. package/tech/backend/hono.d.ts.map +0 -1
  300. package/tech/backend/index.cjs.js.map +0 -1
  301. package/tech/backend/index.esm.js.map +0 -1
  302. package/tech/backend/koa.d.ts +0 -11
  303. package/tech/backend/koa.d.ts.map +0 -1
  304. package/tech/backend/nestjs.d.ts +0 -11
  305. package/tech/backend/nestjs.d.ts.map +0 -1
  306. package/tech/backend/types.d.ts +0 -31
  307. package/tech/backend/types.d.ts.map +0 -1
  308. package/tech/build/babel.d.ts +0 -13
  309. package/tech/build/babel.d.ts.map +0 -1
  310. package/tech/build/detect-all.d.ts +0 -13
  311. package/tech/build/detect-all.d.ts.map +0 -1
  312. package/tech/build/esbuild.d.ts +0 -11
  313. package/tech/build/esbuild.d.ts.map +0 -1
  314. package/tech/build/index.cjs.js.map +0 -1
  315. package/tech/build/index.esm.js.map +0 -1
  316. package/tech/build/parcel.d.ts +0 -13
  317. package/tech/build/parcel.d.ts.map +0 -1
  318. package/tech/build/rollup.d.ts +0 -13
  319. package/tech/build/rollup.d.ts.map +0 -1
  320. package/tech/build/swc.d.ts +0 -13
  321. package/tech/build/swc.d.ts.map +0 -1
  322. package/tech/build/types.d.ts +0 -31
  323. package/tech/build/types.d.ts.map +0 -1
  324. package/tech/build/vite.d.ts +0 -13
  325. package/tech/build/vite.d.ts.map +0 -1
  326. package/tech/build/webpack.d.ts +0 -13
  327. package/tech/build/webpack.d.ts.map +0 -1
  328. package/tech/frontend/angular.d.ts +0 -11
  329. package/tech/frontend/angular.d.ts.map +0 -1
  330. package/tech/frontend/astro.d.ts +0 -11
  331. package/tech/frontend/astro.d.ts.map +0 -1
  332. package/tech/frontend/detect-all.d.ts +0 -13
  333. package/tech/frontend/detect-all.d.ts.map +0 -1
  334. package/tech/frontend/gatsby.d.ts +0 -11
  335. package/tech/frontend/gatsby.d.ts.map +0 -1
  336. package/tech/frontend/index.cjs.js.map +0 -1
  337. package/tech/frontend/index.esm.js.map +0 -1
  338. package/tech/frontend/nextjs.d.ts +0 -11
  339. package/tech/frontend/nextjs.d.ts.map +0 -1
  340. package/tech/frontend/nuxt.d.ts +0 -11
  341. package/tech/frontend/nuxt.d.ts.map +0 -1
  342. package/tech/frontend/qwik.d.ts +0 -11
  343. package/tech/frontend/qwik.d.ts.map +0 -1
  344. package/tech/frontend/react.d.ts +0 -11
  345. package/tech/frontend/react.d.ts.map +0 -1
  346. package/tech/frontend/remix.d.ts +0 -11
  347. package/tech/frontend/remix.d.ts.map +0 -1
  348. package/tech/frontend/solid.d.ts +0 -11
  349. package/tech/frontend/solid.d.ts.map +0 -1
  350. package/tech/frontend/svelte.d.ts +0 -11
  351. package/tech/frontend/svelte.d.ts.map +0 -1
  352. package/tech/frontend/sveltekit.d.ts +0 -11
  353. package/tech/frontend/sveltekit.d.ts.map +0 -1
  354. package/tech/frontend/types.d.ts +0 -35
  355. package/tech/frontend/types.d.ts.map +0 -1
  356. package/tech/frontend/vue.d.ts +0 -11
  357. package/tech/frontend/vue.d.ts.map +0 -1
  358. package/tech/index.cjs.js.map +0 -1
  359. package/tech/index.esm.js.map +0 -1
  360. package/tech/legacy/angularjs.d.ts +0 -12
  361. package/tech/legacy/angularjs.d.ts.map +0 -1
  362. package/tech/legacy/backbone.d.ts +0 -11
  363. package/tech/legacy/backbone.d.ts.map +0 -1
  364. package/tech/legacy/detect-all.d.ts +0 -13
  365. package/tech/legacy/detect-all.d.ts.map +0 -1
  366. package/tech/legacy/ember.d.ts +0 -11
  367. package/tech/legacy/ember.d.ts.map +0 -1
  368. package/tech/legacy/index.cjs.js.map +0 -1
  369. package/tech/legacy/index.esm.js.map +0 -1
  370. package/tech/legacy/jquery.d.ts +0 -11
  371. package/tech/legacy/jquery.d.ts.map +0 -1
  372. package/tech/legacy/types.d.ts +0 -33
  373. package/tech/legacy/types.d.ts.map +0 -1
  374. package/tech/linting/biome.d.ts +0 -11
  375. package/tech/linting/biome.d.ts.map +0 -1
  376. package/tech/linting/detect-all.d.ts +0 -13
  377. package/tech/linting/detect-all.d.ts.map +0 -1
  378. package/tech/linting/eslint.d.ts +0 -13
  379. package/tech/linting/eslint.d.ts.map +0 -1
  380. package/tech/linting/index.cjs.js.map +0 -1
  381. package/tech/linting/index.esm.js.map +0 -1
  382. package/tech/linting/prettier.d.ts +0 -13
  383. package/tech/linting/prettier.d.ts.map +0 -1
  384. package/tech/linting/stylelint.d.ts +0 -13
  385. package/tech/linting/stylelint.d.ts.map +0 -1
  386. package/tech/linting/types.d.ts +0 -31
  387. package/tech/linting/types.d.ts.map +0 -1
  388. package/tech/monorepo/detect-all.d.ts +0 -13
  389. package/tech/monorepo/detect-all.d.ts.map +0 -1
  390. package/tech/monorepo/index.cjs.js.map +0 -1
  391. package/tech/monorepo/index.esm.js.map +0 -1
  392. package/tech/monorepo/lerna.d.ts +0 -11
  393. package/tech/monorepo/lerna.d.ts.map +0 -1
  394. package/tech/monorepo/npm-workspaces.d.ts +0 -11
  395. package/tech/monorepo/npm-workspaces.d.ts.map +0 -1
  396. package/tech/monorepo/nx.d.ts +0 -11
  397. package/tech/monorepo/nx.d.ts.map +0 -1
  398. package/tech/monorepo/pnpm-workspaces.d.ts +0 -9
  399. package/tech/monorepo/pnpm-workspaces.d.ts.map +0 -1
  400. package/tech/monorepo/rush.d.ts +0 -11
  401. package/tech/monorepo/rush.d.ts.map +0 -1
  402. package/tech/monorepo/turborepo.d.ts +0 -11
  403. package/tech/monorepo/turborepo.d.ts.map +0 -1
  404. package/tech/monorepo/types.d.ts +0 -39
  405. package/tech/monorepo/types.d.ts.map +0 -1
  406. package/tech/monorepo/yarn-workspaces.d.ts +0 -11
  407. package/tech/monorepo/yarn-workspaces.d.ts.map +0 -1
  408. package/tech/shared-utils/detector-helpers.d.ts +0 -52
  409. package/tech/shared-utils/detector-helpers.d.ts.map +0 -1
  410. package/tech/shared-utils/types.d.ts +0 -41
  411. package/tech/shared-utils/types.d.ts.map +0 -1
  412. package/tech/testing/cypress.d.ts +0 -13
  413. package/tech/testing/cypress.d.ts.map +0 -1
  414. package/tech/testing/detect-all.d.ts +0 -13
  415. package/tech/testing/detect-all.d.ts.map +0 -1
  416. package/tech/testing/index.cjs.js.map +0 -1
  417. package/tech/testing/index.esm.js.map +0 -1
  418. package/tech/testing/jest.d.ts +0 -13
  419. package/tech/testing/jest.d.ts.map +0 -1
  420. package/tech/testing/mocha.d.ts +0 -13
  421. package/tech/testing/mocha.d.ts.map +0 -1
  422. package/tech/testing/playwright.d.ts +0 -13
  423. package/tech/testing/playwright.d.ts.map +0 -1
  424. package/tech/testing/types.d.ts +0 -35
  425. package/tech/testing/types.d.ts.map +0 -1
  426. package/tech/testing/vitest.d.ts +0 -13
  427. package/tech/testing/vitest.d.ts.map +0 -1
  428. package/tech/types/detectors.d.ts +0 -67
  429. package/tech/types/detectors.d.ts.map +0 -1
  430. package/tech/types/index.cjs.js.map +0 -1
  431. package/tech/types/index.esm.js.map +0 -1
  432. package/vfs/commit.d.ts +0 -32
  433. package/vfs/commit.d.ts.map +0 -1
  434. package/vfs/diff.d.ts +0 -73
  435. package/vfs/diff.d.ts.map +0 -1
  436. package/vfs/factory.d.ts +0 -37
  437. package/vfs/factory.d.ts.map +0 -1
  438. package/vfs/fs-tree.d.ts +0 -13
  439. package/vfs/fs-tree.d.ts.map +0 -1
  440. package/vfs/index.cjs.js.map +0 -1
  441. package/vfs/index.esm.js.map +0 -1
  442. package/vfs/types.d.ts +0 -179
  443. package/vfs/types.d.ts.map +0 -1
package/tech/index.esm.js CHANGED
@@ -1,547 +1,20 @@
1
+ import { createMap } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js';
2
+ import { freeze, entries, keys, defineProperties, values } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js';
3
+ import { createSet } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js';
4
+ import { isArray } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js';
5
+ import { error, warn, log, info, debug } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js';
6
+ import { stringify, parse } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js';
7
+ import { createLogger } from '../_dependencies/@hyperfrontend/logging/index.esm.js';
1
8
  import { join as join$1 } from 'node:path';
9
+ import { createError } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js';
2
10
  import { existsSync, readFileSync, statSync, lstatSync, readdirSync } from 'node:fs';
3
-
4
- /**
5
- * Safe copies of Map built-in via factory function.
6
- *
7
- * Since constructors cannot be safely captured via Object.assign, this module
8
- * provides a factory function that uses Reflect.construct internally.
9
- *
10
- * These references are captured at module initialization time to protect against
11
- * prototype pollution attacks. Import only what you need for tree-shaking.
12
- *
13
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/map
14
- */
15
- const _Map = globalThis.Map;
16
- const _Reflect$2 = globalThis.Reflect;
17
- /**
18
- * (Safe copy) Creates a new Map using the captured Map constructor.
19
- * Use this instead of `new Map()`.
20
- *
21
- * @param iterable - Optional iterable of key-value pairs.
22
- * @returns A new Map instance.
23
- */
24
- const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
25
-
26
- /**
27
- * Safe copies of Object built-in methods.
28
- *
29
- * These references are captured at module initialization time to protect against
30
- * prototype pollution attacks. Import only what you need for tree-shaking.
31
- *
32
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
33
- */
34
- const _Object = globalThis.Object;
35
- /**
36
- * (Safe copy) Prevents modification of existing property attributes and values,
37
- * and prevents the addition of new properties.
38
- */
39
- const freeze = _Object.freeze;
40
- /**
41
- * (Safe copy) Returns the names of the enumerable string properties and methods of an object.
42
- */
43
- const keys = _Object.keys;
44
- /**
45
- * (Safe copy) Returns an array of key/values of the enumerable own properties of an object.
46
- */
47
- const entries = _Object.entries;
48
- /**
49
- * (Safe copy) Returns an array of values of the enumerable own properties of an object.
50
- */
51
- const values = _Object.values;
52
- /**
53
- * (Safe copy) Adds one or more properties to an object, and/or modifies attributes of existing properties.
54
- */
55
- const defineProperties = _Object.defineProperties;
56
-
57
- /**
58
- * Safe copies of Set built-in via factory function.
59
- *
60
- * Since constructors cannot be safely captured via Object.assign, this module
61
- * provides a factory function that uses Reflect.construct internally.
62
- *
63
- * These references are captured at module initialization time to protect against
64
- * prototype pollution attacks. Import only what you need for tree-shaking.
65
- *
66
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
67
- */
68
- const _Set = globalThis.Set;
69
- const _Reflect$1 = globalThis.Reflect;
70
- /**
71
- * (Safe copy) Creates a new Set using the captured Set constructor.
72
- * Use this instead of `new Set()`.
73
- *
74
- * @param iterable - Optional iterable of values.
75
- * @returns A new Set instance.
76
- */
77
- const createSet = (iterable) => _Reflect$1.construct(_Set, iterable ? [iterable] : []);
78
-
79
- /**
80
- * Global registry of all caches for bulk operations.
81
- */
82
- const cacheRegistry = createSet();
83
- /**
84
- * Create a cache with optional TTL and size limits.
85
- *
86
- * The cache provides a simple key-value store with:
87
- * - Optional TTL (time-to-live) for automatic expiration
88
- * - Optional maxSize for limiting cache size with FIFO eviction
89
- * - Lazy expiration (entries are checked on access)
90
- *
91
- * @param options - Cache configuration options
92
- * @returns Cache instance
93
- *
94
- * @example
95
- * ```typescript
96
- * // Basic cache
97
- * const cache = createCache<string, number>()
98
- * cache.set('answer', 42)
99
- * cache.get('answer') // 42
100
- *
101
- * // Cache with TTL (expires after 60 seconds)
102
- * const ttlCache = createCache<string, object>({ ttl: 60000 })
103
- *
104
- * // Cache with max size (evicts oldest when full)
105
- * const lruCache = createCache<string, object>({ maxSize: 100 })
106
- *
107
- * // Combined options
108
- * const configCache = createCache<string, object>({
109
- * ttl: 30000,
110
- * maxSize: 50
111
- * })
112
- * ```
113
- */
114
- function createCache(options) {
115
- const { ttl, maxSize } = options ?? {};
116
- const store = createMap();
117
- const insertionOrder = [];
118
- /**
119
- * Check if an entry is expired.
120
- *
121
- * @param entry - Cache entry to check
122
- * @returns True if entry is expired
123
- */
124
- function isExpired(entry) {
125
- if (ttl === undefined)
126
- return false;
127
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
128
- return Date.now() - entry.timestamp > ttl;
129
- }
130
- /**
131
- * Evict oldest entries to make room for new ones.
132
- */
133
- function evictIfNeeded() {
134
- if (maxSize === undefined)
135
- return;
136
- while (store.size >= maxSize && insertionOrder.length > 0) {
137
- const oldestKey = insertionOrder.shift();
138
- if (oldestKey !== undefined) {
139
- store.delete(oldestKey);
140
- }
141
- }
142
- }
143
- /**
144
- * Remove key from insertion order tracking.
145
- *
146
- * @param key - Key to remove from order tracking
147
- */
148
- function removeFromOrder(key) {
149
- const index = insertionOrder.indexOf(key);
150
- if (index !== -1) {
151
- insertionOrder.splice(index, 1);
152
- }
153
- }
154
- const cache = {
155
- get(key) {
156
- const entry = store.get(key);
157
- if (!entry)
158
- return undefined;
159
- if (isExpired(entry)) {
160
- store.delete(key);
161
- removeFromOrder(key);
162
- return undefined;
163
- }
164
- return entry.value;
165
- },
166
- set(key, value) {
167
- if (store.has(key)) {
168
- removeFromOrder(key);
169
- }
170
- else {
171
- evictIfNeeded();
172
- }
173
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
174
- store.set(key, { value, timestamp: Date.now() });
175
- insertionOrder.push(key);
176
- },
177
- has(key) {
178
- const entry = store.get(key);
179
- if (!entry)
180
- return false;
181
- if (isExpired(entry)) {
182
- store.delete(key);
183
- removeFromOrder(key);
184
- return false;
185
- }
186
- return true;
187
- },
188
- delete(key) {
189
- removeFromOrder(key);
190
- return store.delete(key);
191
- },
192
- clear() {
193
- store.clear();
194
- insertionOrder.length = 0;
195
- },
196
- size() {
197
- return store.size;
198
- },
199
- keys() {
200
- return [...insertionOrder];
201
- },
202
- };
203
- cacheRegistry.add(cache);
204
- return freeze(cache);
205
- }
206
-
207
- /**
208
- * Safe copies of Array built-in static methods.
209
- *
210
- * These references are captured at module initialization time to protect against
211
- * prototype pollution attacks. Import only what you need for tree-shaking.
212
- *
213
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
214
- */
215
- const _Array = globalThis.Array;
216
- /**
217
- * (Safe copy) Determines whether the passed value is an Array.
218
- */
219
- const isArray = _Array.isArray;
220
-
221
- /**
222
- * Safe copies of Console built-in methods.
223
- *
224
- * These references are captured at module initialization time to protect against
225
- * prototype pollution attacks. Import only what you need for tree-shaking.
226
- *
227
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/console
228
- */
229
- const _console = globalThis.console;
230
- /**
231
- * (Safe copy) Outputs a message to the console.
232
- */
233
- const log = _console.log.bind(_console);
234
- /**
235
- * (Safe copy) Outputs a warning message to the console.
236
- */
237
- const warn = _console.warn.bind(_console);
238
- /**
239
- * (Safe copy) Outputs an error message to the console.
240
- */
241
- const error = _console.error.bind(_console);
242
- /**
243
- * (Safe copy) Outputs an informational message to the console.
244
- */
245
- const info = _console.info.bind(_console);
246
- /**
247
- * (Safe copy) Outputs a debug message to the console.
248
- */
249
- const debug = _console.debug.bind(_console);
250
- /**
251
- * (Safe copy) Outputs a stack trace to the console.
252
- */
253
- _console.trace.bind(_console);
254
- /**
255
- * (Safe copy) Displays an interactive listing of the properties of a specified object.
256
- */
257
- _console.dir.bind(_console);
258
- /**
259
- * (Safe copy) Displays tabular data as a table.
260
- */
261
- _console.table.bind(_console);
262
- /**
263
- * (Safe copy) Writes an error message to the console if the assertion is false.
264
- */
265
- _console.assert.bind(_console);
266
- /**
267
- * (Safe copy) Clears the console.
268
- */
269
- _console.clear.bind(_console);
270
- /**
271
- * (Safe copy) Logs the number of times that this particular call to count() has been called.
272
- */
273
- _console.count.bind(_console);
274
- /**
275
- * (Safe copy) Resets the counter used with console.count().
276
- */
277
- _console.countReset.bind(_console);
278
- /**
279
- * (Safe copy) Creates a new inline group in the console.
280
- */
281
- _console.group.bind(_console);
282
- /**
283
- * (Safe copy) Creates a new inline group in the console that is initially collapsed.
284
- */
285
- _console.groupCollapsed.bind(_console);
286
- /**
287
- * (Safe copy) Exits the current inline group.
288
- */
289
- _console.groupEnd.bind(_console);
290
- /**
291
- * (Safe copy) Starts a timer with a name specified as an input parameter.
292
- */
293
- _console.time.bind(_console);
294
- /**
295
- * (Safe copy) Stops a timer that was previously started.
296
- */
297
- _console.timeEnd.bind(_console);
298
- /**
299
- * (Safe copy) Logs the current value of a timer that was previously started.
300
- */
301
- _console.timeLog.bind(_console);
302
-
303
- /**
304
- * Safe copies of JSON built-in methods.
305
- *
306
- * These references are captured at module initialization time to protect against
307
- * prototype pollution attacks. Import only what you need for tree-shaking.
308
- *
309
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
310
- */
311
- const _JSON = globalThis.JSON;
312
- /**
313
- * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
314
- */
315
- const parse = _JSON.parse;
316
- /**
317
- * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
318
- */
319
- const stringify = _JSON.stringify;
320
-
321
- const registeredClasses = [];
322
-
323
- /**
324
- * Returns the data type of the target.
325
- * Uses native `typeof` operator, however, makes distinction between `null`, `array`, and `object`.
326
- * Also, when classes are registered via `registerClass`, it checks if objects are instance of any known registered class.
327
- *
328
- * @param target - The target to get the data type of.
329
- * @returns The data type of the target.
330
- */
331
- const getType = (target) => {
332
- if (target === null)
333
- return 'null';
334
- const nativeDataType = typeof target;
335
- if (nativeDataType === 'object') {
336
- if (isArray(target))
337
- return 'array';
338
- for (const registeredClass of registeredClasses) {
339
- if (target instanceof registeredClass)
340
- return registeredClass.name;
341
- }
342
- }
343
- return nativeDataType;
344
- };
345
-
346
- /**
347
- * Safe copies of Error built-ins via factory functions.
348
- *
349
- * Since constructors cannot be safely captured via Object.assign, this module
350
- * provides factory functions that use Reflect.construct internally.
351
- *
352
- * These references are captured at module initialization time to protect against
353
- * prototype pollution attacks. Import only what you need for tree-shaking.
354
- *
355
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
356
- */
357
- const _Error = globalThis.Error;
358
- const _Reflect = globalThis.Reflect;
359
- /**
360
- * (Safe copy) Creates a new Error using the captured Error constructor.
361
- * Use this instead of `new Error()`.
362
- *
363
- * @param message - Optional error message.
364
- * @param options - Optional error options.
365
- * @returns A new Error instance.
366
- */
367
- const createError = (message, options) => _Reflect.construct(_Error, [message, options]);
368
-
369
- /**
370
- * Safe copies of Math built-in methods.
371
- *
372
- * These references are captured at module initialization time to protect against
373
- * prototype pollution attacks. Import only what you need for tree-shaking.
374
- *
375
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/math
376
- */
377
- const _Math = globalThis.Math;
378
- /**
379
- * (Safe copy) Returns the smaller of zero or more numbers.
380
- */
381
- const min = _Math.min;
382
-
383
- /* eslint-disable @typescript-eslint/no-explicit-any */
384
- /**
385
- * Creates a wrapper function that only executes the wrapped function if the condition function returns true.
386
- *
387
- * @param func - The function to be conditionally executed.
388
- * @param conditionFunc - A function that returns a boolean, determining if `func` should be executed.
389
- * @returns A wrapped version of `func` that executes conditionally.
390
- */
391
- function createConditionalExecutionFunction(func, conditionFunc) {
392
- return function (...args) {
393
- if (conditionFunc()) {
394
- return func(...args);
395
- }
396
- };
397
- }
398
-
399
- /* eslint-disable @typescript-eslint/no-explicit-any */
400
- /**
401
- * Creates a wrapper function that silently ignores any errors thrown by the wrapped void function.
402
- * This function is specifically for wrapping functions that do not return a value (void functions).
403
- * Exceptions are swallowed without any logging or handling.
404
- *
405
- * @param func - The void function to be wrapped.
406
- * @returns A wrapped version of the input function that ignores errors.
407
- */
408
- function createErrorIgnoringFunction(func) {
409
- return function (...args) {
410
- try {
411
- func(...args);
412
- }
413
- catch {
414
- // Deliberately swallowing/ignoring the exception
415
- }
416
- };
417
- }
418
-
419
- /* eslint-disable @typescript-eslint/no-unused-vars */
420
- /**
421
- * A no-operation function (noop) that does nothing regardless of the arguments passed.
422
- * It is designed to be as permissive as possible in its typing without using the `Function` keyword.
423
- *
424
- * @param args - Any arguments passed to the function (ignored)
425
- */
426
- const noop = (...args) => {
427
- // Intentionally does nothing
428
- };
429
-
430
- const logLevels = ['none', 'error', 'warn', 'log', 'info', 'debug'];
431
- const priority = {
432
- error: 4,
433
- warn: 3,
434
- log: 2,
435
- info: 1,
436
- debug: 0,
437
- };
438
- /**
439
- * Validates whether a given string is a valid log level.
440
- *
441
- * @param level - The log level to validate
442
- * @returns True if the level is valid, false otherwise
443
- */
444
- function isValidLogLevel(level) {
445
- return logLevels.includes(level);
446
- }
447
- /**
448
- * Creates a log level configuration manager for controlling logging behavior.
449
- * Provides methods to get, set, and evaluate log levels based on priority.
450
- *
451
- * @param level - The initial log level (defaults to 'error')
452
- * @returns A configuration object with log level management methods
453
- * @throws {Error} When the provided level is not a valid log level
454
- */
455
- function createLogLevelConfig(level = 'error') {
456
- if (!isValidLogLevel(level)) {
457
- throw createError('Cannot create log level configuration with a valid default log level');
458
- }
459
- const state = { level };
460
- const getLogLevel = () => state.level;
461
- const setLogLevel = (level) => {
462
- if (!isValidLogLevel(level)) {
463
- throw createError(`Cannot set value '${level}' level. Expected levels are ${logLevels}.`);
464
- }
465
- state.level = level;
466
- };
467
- const shouldLog = (level) => {
468
- if (state.level === 'none' || level === 'none' || !isValidLogLevel(level)) {
469
- return false;
470
- }
471
- return priority[level] >= priority[state.level];
472
- };
473
- return freeze({
474
- getLogLevel,
475
- setLogLevel,
476
- shouldLog,
477
- });
478
- }
479
-
480
- /**
481
- * Creates a logger instance with configurable log level filtering.
482
- * Each log function is wrapped to respect the current log level setting.
483
- *
484
- * @param error - Function to handle error-level logs (required)
485
- * @param warn - Function to handle warning-level logs (optional, defaults to noop)
486
- * @param log - Function to handle standard logs (optional, defaults to noop)
487
- * @param info - Function to handle info-level logs (optional, defaults to noop)
488
- * @param debug - Function to handle debug-level logs (optional, defaults to noop)
489
- * @returns A frozen logger object with log methods and level control
490
- * @throws {ErrorLevelFn} When any provided log function is invalid
491
- */
492
- function createLogger(error, warn = noop, log = noop, info = noop, debug = noop) {
493
- if (notValidLogFn(error)) {
494
- throw createError(notFnMsg('error'));
495
- }
496
- if (notValidLogFn(warn)) {
497
- throw createError(notFnMsg('warn'));
498
- }
499
- if (notValidLogFn(log)) {
500
- throw createError(notFnMsg('log'));
501
- }
502
- if (notValidLogFn(info)) {
503
- throw createError(notFnMsg('info'));
504
- }
505
- if (notValidLogFn(debug)) {
506
- throw createError(notFnMsg('debug'));
507
- }
508
- const { setLogLevel, getLogLevel, shouldLog } = createLogLevelConfig();
509
- const wrapLogFn = (fn, level) => {
510
- if (fn === noop)
511
- return fn;
512
- const condition = () => shouldLog(level);
513
- return createConditionalExecutionFunction(createErrorIgnoringFunction(fn), condition);
514
- };
515
- return freeze({
516
- error: wrapLogFn(error, 'error'),
517
- warn: wrapLogFn(warn, 'warn'),
518
- log: wrapLogFn(log, 'log'),
519
- info: wrapLogFn(info, 'info'),
520
- debug: wrapLogFn(debug, 'debug'),
521
- setLogLevel,
522
- getLogLevel,
523
- });
524
- }
525
- /**
526
- * Validates whether a given value is a valid log function.
527
- *
528
- * @param fn - The value to validate
529
- * @returns True if the value is not a function (invalid), false if it is valid
530
- */
531
- function notValidLogFn(fn) {
532
- return getType(fn) !== 'function' && fn !== noop;
533
- }
534
- /**
535
- * Generates an error message for invalid log function parameters.
536
- *
537
- * @param label - The name of the log function that failed validation
538
- * @returns A formatted error message string
539
- */
540
- function notFnMsg(label) {
541
- return `Cannot create a logger when ${label} is not a function`;
542
- }
543
-
544
- createLogger(error, warn, log, info, debug);
11
+ import { min } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js';
12
+ import { isSafePath } from '../_shared/core/fs/guard/index.esm.js';
13
+ import { isDirectory, exists } from '../_shared/core/fs/stat/index.esm.js';
14
+ import { join } from '../_shared/core/path/join/index.esm.js';
15
+ import { createCache } from '../_shared/core/cache/index.esm.js';
16
+ import { collectAllDependencies, parseVersionString, locateConfigFile, filterScriptsByCommand } from '../_shared/tech/shared-utils/detector-helpers/index.esm.js';
17
+ import { pnpmWorkspacesDetector } from '../_shared/tech/monorepo/pnpm-workspaces/index.esm.js';
545
18
 
546
19
  /**
547
20
  * Global log level registry.
@@ -581,6 +54,13 @@ function isSensitiveKey(key) {
581
54
  *
582
55
  * @param obj - Object to sanitize
583
56
  * @returns New object with sensitive values redacted
57
+ *
58
+ * @example Sanitizing sensitive data
59
+ * ```typescript
60
+ * const config = { apiKey: 'secret123', endpoint: 'https://api.example.com' }
61
+ * const safe = sanitize(config)
62
+ * // => { apiKey: '[REDACTED]', endpoint: 'https://api.example.com' }
63
+ * ```
584
64
  */
585
65
  function sanitize(obj) {
586
66
  if (obj === null || obj === undefined) {
@@ -631,7 +111,7 @@ function formatMessage(namespace, message, meta) {
631
111
  * @param options - Logger configuration options
632
112
  * @returns A configured scoped logger instance
633
113
  *
634
- * @example
114
+ * @example Creating a scoped logger
635
115
  * ```typescript
636
116
  * const logger = createScopedLogger('project-scope')
637
117
  * logger.setLogLevel('debug')
@@ -668,7 +148,7 @@ function createScopedLogger(namespace, options = {}) {
668
148
  * Default logger instance for the project-scope library.
669
149
  * Use this for general logging within the library.
670
150
  *
671
- * @example
151
+ * @example Using the default logger
672
152
  * ```typescript
673
153
  * import { logger } from '@hyperfrontend/project-scope/core'
674
154
  *
@@ -686,6 +166,15 @@ createScopedLogger('project-scope:fs');
686
166
  * @param code - The category code for this type of filesystem failure
687
167
  * @param context - Additional context including path, operation, and cause
688
168
  * @returns A configured Error object with code and context properties
169
+ *
170
+ * @example Creating a file system error
171
+ * ```typescript
172
+ * throw createFileSystemError(
173
+ * 'Cannot read file',
174
+ * 'FS_READ_ERROR',
175
+ * { path: './missing.txt', operation: 'read' }
176
+ * )
177
+ * ```
689
178
  */
690
179
  function createFileSystemError(message, code, context) {
691
180
  const error = createError(message);
@@ -701,9 +190,17 @@ function createFileSystemError(message, code, context) {
701
190
  * @param filePath - Path to file
702
191
  * @param encoding - File encoding (default: utf-8)
703
192
  * @returns File contents or null if file doesn't exist
193
+ *
194
+ * @example Reading file if it exists
195
+ * ```typescript
196
+ * const content = readFileIfExists('./optional-config.json')
197
+ * if (content) {
198
+ * // File existed, use content
199
+ * }
200
+ * ```
704
201
  */
705
202
  function readFileIfExists(filePath, encoding = 'utf-8') {
706
- if (!existsSync(filePath)) {
203
+ if (!isSafePath(filePath) || !existsSync(filePath)) {
707
204
  return null;
708
205
  }
709
206
  try {
@@ -714,56 +211,6 @@ function readFileIfExists(filePath, encoding = 'utf-8') {
714
211
  }
715
212
  }
716
213
 
717
- createScopedLogger('project-scope:fs:write');
718
-
719
- /**
720
- * Get file stats with error handling.
721
- *
722
- * @param filePath - Path to file
723
- * @param followSymlinks - Whether to follow symlinks (default: true)
724
- * @returns File stats or null if path doesn't exist
725
- */
726
- function getFileStat(filePath, followSymlinks = true) {
727
- if (!existsSync(filePath)) {
728
- return null;
729
- }
730
- try {
731
- const stat = followSymlinks ? statSync(filePath) : lstatSync(filePath);
732
- return {
733
- isFile: stat.isFile(),
734
- isDirectory: stat.isDirectory(),
735
- isSymlink: stat.isSymbolicLink(),
736
- size: stat.size,
737
- created: stat.birthtime,
738
- modified: stat.mtime,
739
- accessed: stat.atime,
740
- mode: stat.mode,
741
- };
742
- }
743
- catch {
744
- return null;
745
- }
746
- }
747
- /**
748
- * Check if path is a directory.
749
- *
750
- * @param dirPath - Path to check
751
- * @returns True if path is a directory
752
- */
753
- function isDirectory(dirPath) {
754
- const stats = getFileStat(dirPath);
755
- return stats?.isDirectory ?? false;
756
- }
757
- /**
758
- * Check if path exists.
759
- *
760
- * @param filePath - Path to check
761
- * @returns True if path exists
762
- */
763
- function exists(filePath) {
764
- return existsSync(filePath);
765
- }
766
-
767
214
  const fsDirLogger = createScopedLogger('project-scope:fs:dir');
768
215
  /**
769
216
  * List immediate contents of a directory.
@@ -772,7 +219,7 @@ const fsDirLogger = createScopedLogger('project-scope:fs:dir');
772
219
  * @returns Array of entries with metadata for each file/directory
773
220
  * @throws {Error} If directory doesn't exist or isn't a directory
774
221
  *
775
- * @example
222
+ * @example Listing directory contents
776
223
  * ```typescript
777
224
  * import { readDirectory } from '@hyperfrontend/project-scope'
778
225
  *
@@ -813,19 +260,10 @@ function readDirectory(dirPath) {
813
260
  }
814
261
  }
815
262
 
816
- /**
817
- * Join path segments.
818
- * Uses platform-specific separators (e.g., / or \).
819
- *
820
- * @param paths - Path segments to join
821
- * @returns Joined path
822
- */
823
- function join(...paths) {
824
- return join$1(...paths);
825
- }
826
-
827
263
  createScopedLogger('project-scope:fs:traversal');
828
264
 
265
+ createScopedLogger('project-scope:fs:write');
266
+
829
267
  const packageLogger = createScopedLogger('project-scope:project:package');
830
268
  /**
831
269
  * Verifies that a value is an object with only string values,
@@ -895,6 +333,16 @@ function validatePackageJson(data) {
895
333
  *
896
334
  * @param projectPath - Project directory path or path to package.json
897
335
  * @returns Parsed package.json or null if not found
336
+ *
337
+ * @example Reading package.json if it exists
338
+ * ```typescript
339
+ * import { readPackageJsonIfExists } from '@hyperfrontend/project-scope'
340
+ *
341
+ * const pkg = readPackageJsonIfExists('/path/to/project')
342
+ * if (pkg) {
343
+ * console.log('Found:', pkg.name)
344
+ * }
345
+ * ```
898
346
  */
899
347
  function readPackageJsonIfExists(projectPath) {
900
348
  const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
@@ -915,79 +363,31 @@ function readPackageJsonIfExists(projectPath) {
915
363
  }
916
364
 
917
365
  /**
918
- * Get combined dependencies from package.json.
919
- * Merges dependencies, devDependencies, peerDependencies, and optionalDependencies.
366
+ * Detect Express in project.
920
367
  *
921
- * @param packageJson - The package.json object to extract dependencies from
922
- * @returns Combined dependencies as a single record
923
- */
924
- function collectAllDependencies(packageJson) {
925
- return {
926
- ...packageJson?.dependencies,
927
- ...packageJson?.devDependencies,
928
- ...packageJson?.peerDependencies,
929
- ...packageJson?.optionalDependencies,
930
- };
931
- }
932
- /**
933
- * Extract clean version from dependency version string.
934
- * Removes semver prefixes like ^, ~, >=, etc.
935
- * Uses character-by-character parsing to avoid ReDoS vulnerabilities.
368
+ * @param projectPath - Project directory path
369
+ * @param packageJson - Optional pre-loaded package.json
370
+ * @returns Detection result or null if not detected
371
+ * @example Detecting Express framework
372
+ * ```typescript
373
+ * const pkg = {
374
+ * dependencies: { express: '^4.18.2', cors: '^2.8.5' },
375
+ * devDependencies: { '@types/express': '^4.17.17' },
376
+ * }
936
377
  *
937
- * @param versionString - The version string with optional prefix characters
938
- * @returns The cleaned version string without prefix characters
939
- */
940
- function parseVersionString(versionString) {
941
- if (versionString === undefined || versionString === null)
942
- return undefined;
943
- let start = 0;
944
- while (start < versionString.length) {
945
- const char = versionString[start];
946
- if (char !== '^' && char !== '~' && char !== '>' && char !== '=' && char !== '<') {
947
- break;
948
- }
949
- start++;
950
- }
951
- return versionString.slice(start);
952
- }
953
- /**
954
- * Find first matching config file in project.
955
- * Note: Name avoids similarity to fs.readFile/fs.readFileSync.
956
- *
957
- * @param projectPath - The project directory path
958
- * @param patterns - Array of config file patterns to search for
959
- * @returns The first matching config file path or undefined
960
- */
961
- function locateConfigFile(projectPath, patterns) {
962
- for (const pattern of patterns) {
963
- const fullPath = join(projectPath, pattern);
964
- if (exists(fullPath)) {
965
- return pattern;
966
- }
967
- }
968
- return undefined;
969
- }
970
- /**
971
- * Find scripts containing a specific command.
972
- *
973
- * @param scripts - The scripts object from package.json
974
- * @param command - The command string to search for
975
- * @returns Array of script names that contain the command
976
- */
977
- function filterScriptsByCommand(scripts, command) {
978
- if (!scripts)
979
- return [];
980
- return entries(scripts)
981
- .filter(([, script]) => script.includes(command))
982
- .map(([name]) => name);
983
- }
984
-
985
- /**
986
- * Detect Express in project.
987
- *
988
- * @param projectPath - Project directory path
989
- * @param packageJson - Optional pre-loaded package.json
990
- * @returns Detection result or null if not detected
378
+ * const result = expressDetector('/path/to/project', pkg)
379
+ * // => {
380
+ * // id: 'express',
381
+ * // name: 'Express',
382
+ * // version: '4.18.2',
383
+ * // confidence: 100,
384
+ * // detectedFrom: [
385
+ * // { type: 'package.json', field: 'dependencies.express' },
386
+ * // { type: 'package.json', field: 'dependencies.@types/express' },
387
+ * // { type: 'package.json', field: 'dependencies (express middleware)' },
388
+ * // ],
389
+ * // }
390
+ * ```
991
391
  */
992
392
  function expressDetector(projectPath, packageJson) {
993
393
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1022,84 +422,109 @@ function expressDetector(projectPath, packageJson) {
1022
422
  }
1023
423
 
1024
424
  /**
1025
- * Detect NestJS in project.
425
+ * Detect Fastify in project.
1026
426
  *
1027
427
  * @param projectPath - Project directory path
1028
428
  * @param packageJson - Optional pre-loaded package.json
1029
429
  * @returns Detection result or null if not detected
430
+ * @example Detecting Fastify framework
431
+ * ```typescript
432
+ * const pkg = {
433
+ * dependencies: { fastify: '^4.24.0', '@fastify/cors': '^8.4.0' },
434
+ * }
435
+ *
436
+ * const result = fastifyDetector('/path/to/project', pkg)
437
+ * // => {
438
+ * // id: 'fastify',
439
+ * // name: 'Fastify',
440
+ * // version: '4.24.0',
441
+ * // confidence: 95,
442
+ * // detectedFrom: [
443
+ * // { type: 'package.json', field: 'dependencies.fastify' },
444
+ * // { type: 'package.json', field: 'dependencies (fastify plugins)' },
445
+ * // ],
446
+ * // }
447
+ * ```
1030
448
  */
1031
- function nestDetector(projectPath, packageJson) {
449
+ function fastifyDetector(projectPath, packageJson) {
1032
450
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1033
451
  const sources = [];
1034
452
  let confidence = 0;
1035
453
  let version;
1036
- let configPath;
1037
454
  const deps = collectAllDependencies(pkg);
1038
- if (deps['@nestjs/core']) {
1039
- confidence += 70;
1040
- version = parseVersionString(deps['@nestjs/core']);
1041
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1042
- }
1043
- if (deps['@nestjs/common']) {
1044
- confidence += 15;
1045
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
455
+ if (deps['fastify']) {
456
+ confidence += 80;
457
+ version = parseVersionString(deps['fastify']);
458
+ sources.push({ type: 'package.json', field: 'dependencies.fastify' });
1046
459
  }
1047
- if (exists(join$1(projectPath, 'nest-cli.json'))) {
460
+ const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
461
+ if (fastifyPlugins.length > 0) {
1048
462
  confidence += 15;
1049
- configPath = 'nest-cli.json';
1050
- sources.push({ type: 'config-file', path: 'nest-cli.json' });
463
+ sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1051
464
  }
1052
- const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1053
- if (nestPackages.length > 2) {
465
+ if (deps['@types/fastify']) {
1054
466
  confidence += 5;
1055
- sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
467
+ sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
1056
468
  }
1057
469
  if (confidence === 0) {
1058
470
  return null;
1059
471
  }
1060
472
  return {
1061
- id: 'nestjs',
1062
- name: 'NestJS',
473
+ id: 'fastify',
474
+ name: 'Fastify',
1063
475
  version,
1064
- configPath,
1065
476
  confidence: min(confidence, 100),
1066
477
  detectedFrom: sources,
1067
478
  };
1068
479
  }
1069
480
 
1070
481
  /**
1071
- * Detect Fastify in project.
482
+ * Detect Hono in project.
1072
483
  *
1073
484
  * @param projectPath - Project directory path
1074
485
  * @param packageJson - Optional pre-loaded package.json
1075
486
  * @returns Detection result or null if not detected
487
+ * @example Detecting Hono framework
488
+ * ```typescript
489
+ * const pkg = {
490
+ * dependencies: { hono: '^3.11.0', '@hono/node-server': '^1.3.0' },
491
+ * }
492
+ *
493
+ * const result = honoDetector('/path/to/project', pkg)
494
+ * // => {
495
+ * // id: 'hono',
496
+ * // name: 'Hono',
497
+ * // version: '3.11.0',
498
+ * // confidence: 100,
499
+ * // detectedFrom: [
500
+ * // { type: 'package.json', field: 'dependencies.hono' },
501
+ * // { type: 'package.json', field: 'dependencies (@hono adapters)' },
502
+ * // ],
503
+ * // }
504
+ * ```
1076
505
  */
1077
- function fastifyDetector(projectPath, packageJson) {
506
+ function honoDetector(projectPath, packageJson) {
1078
507
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1079
508
  const sources = [];
1080
509
  let confidence = 0;
1081
510
  let version;
1082
511
  const deps = collectAllDependencies(pkg);
1083
- if (deps['fastify']) {
1084
- confidence += 80;
1085
- version = parseVersionString(deps['fastify']);
1086
- sources.push({ type: 'package.json', field: 'dependencies.fastify' });
512
+ if (deps['hono']) {
513
+ confidence += 85;
514
+ version = parseVersionString(deps['hono']);
515
+ sources.push({ type: 'package.json', field: 'dependencies.hono' });
1087
516
  }
1088
- const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1089
- if (fastifyPlugins.length > 0) {
517
+ const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
518
+ if (honoAdapters.length > 0) {
1090
519
  confidence += 15;
1091
- sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1092
- }
1093
- if (deps['@types/fastify']) {
1094
- confidence += 5;
1095
- sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
520
+ sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1096
521
  }
1097
522
  if (confidence === 0) {
1098
523
  return null;
1099
524
  }
1100
525
  return {
1101
- id: 'fastify',
1102
- name: 'Fastify',
526
+ id: 'hono',
527
+ name: 'Hono',
1103
528
  version,
1104
529
  confidence: min(confidence, 100),
1105
530
  detectedFrom: sources,
@@ -1112,6 +537,26 @@ function fastifyDetector(projectPath, packageJson) {
1112
537
  * @param projectPath - Project directory path
1113
538
  * @param packageJson - Optional pre-loaded package.json
1114
539
  * @returns Detection result or null if not detected
540
+ * @example Detecting Koa framework
541
+ * ```typescript
542
+ * const pkg = {
543
+ * dependencies: { koa: '^2.14.2', 'koa-router': '^12.0.0' },
544
+ * devDependencies: { '@types/koa': '^2.13.9' },
545
+ * }
546
+ *
547
+ * const result = koaDetector('/path/to/project', pkg)
548
+ * // => {
549
+ * // id: 'koa',
550
+ * // name: 'Koa',
551
+ * // version: '2.14.2',
552
+ * // confidence: 100,
553
+ * // detectedFrom: [
554
+ * // { type: 'package.json', field: 'dependencies.koa' },
555
+ * // { type: 'package.json', field: 'dependencies.@types/koa' },
556
+ * // { type: 'package.json', field: 'dependencies (koa middleware)' },
557
+ * // ],
558
+ * // }
559
+ * ```
1115
560
  */
1116
561
  function koaDetector(projectPath, packageJson) {
1117
562
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1146,35 +591,72 @@ function koaDetector(projectPath, packageJson) {
1146
591
  }
1147
592
 
1148
593
  /**
1149
- * Detect Hono in project.
594
+ * Detect NestJS in project.
1150
595
  *
1151
596
  * @param projectPath - Project directory path
1152
597
  * @param packageJson - Optional pre-loaded package.json
1153
598
  * @returns Detection result or null if not detected
599
+ * @example Detecting NestJS framework
600
+ * ```typescript
601
+ * // Project with nest-cli.json and NestJS packages
602
+ * const pkg = {
603
+ * dependencies: {
604
+ * '@nestjs/core': '^10.2.0',
605
+ * '@nestjs/common': '^10.2.0',
606
+ * '@nestjs/platform-express': '^10.2.0',
607
+ * },
608
+ * }
609
+ *
610
+ * const result = nestDetector('/path/to/nest-project', pkg)
611
+ * // => {
612
+ * // id: 'nestjs',
613
+ * // name: 'NestJS',
614
+ * // version: '10.2.0',
615
+ * // configPath: 'nest-cli.json', // if present
616
+ * // confidence: 100,
617
+ * // detectedFrom: [
618
+ * // { type: 'package.json', field: 'dependencies.@nestjs/core' },
619
+ * // { type: 'package.json', field: 'dependencies.@nestjs/common' },
620
+ * // { type: 'config-file', path: 'nest-cli.json' },
621
+ * // { type: 'package.json', field: 'dependencies (@nestjs packages)' },
622
+ * // ],
623
+ * // }
624
+ * ```
1154
625
  */
1155
- function honoDetector(projectPath, packageJson) {
626
+ function nestDetector(projectPath, packageJson) {
1156
627
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1157
628
  const sources = [];
1158
629
  let confidence = 0;
1159
630
  let version;
631
+ let configPath;
1160
632
  const deps = collectAllDependencies(pkg);
1161
- if (deps['hono']) {
1162
- confidence += 85;
1163
- version = parseVersionString(deps['hono']);
1164
- sources.push({ type: 'package.json', field: 'dependencies.hono' });
633
+ if (deps['@nestjs/core']) {
634
+ confidence += 70;
635
+ version = parseVersionString(deps['@nestjs/core']);
636
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1165
637
  }
1166
- const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
1167
- if (honoAdapters.length > 0) {
638
+ if (deps['@nestjs/common']) {
1168
639
  confidence += 15;
1169
- sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
640
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
641
+ }
642
+ if (exists(join$1(projectPath, 'nest-cli.json'))) {
643
+ confidence += 15;
644
+ configPath = 'nest-cli.json';
645
+ sources.push({ type: 'config-file', path: 'nest-cli.json' });
646
+ }
647
+ const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
648
+ if (nestPackages.length > 2) {
649
+ confidence += 5;
650
+ sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
1170
651
  }
1171
652
  if (confidence === 0) {
1172
653
  return null;
1173
654
  }
1174
655
  return {
1175
- id: 'hono',
1176
- name: 'Hono',
656
+ id: 'nestjs',
657
+ name: 'NestJS',
1177
658
  version,
659
+ configPath,
1178
660
  confidence: min(confidence, 100),
1179
661
  detectedFrom: sources,
1180
662
  };
@@ -1194,6 +676,19 @@ const backendDetectors = [
1194
676
  * @param projectPath - Project directory path
1195
677
  * @param packageJson - Optional pre-loaded package.json
1196
678
  * @returns Array of detected frameworks, sorted by confidence
679
+ * @example Detecting multiple backend frameworks
680
+ * ```typescript
681
+ * const pkg = {
682
+ * dependencies: { '@nestjs/core': '^10.0.0', '@nestjs/common': '^10.0.0' },
683
+ * devDependencies: { express: '^4.18.0' },
684
+ * }
685
+ *
686
+ * const results = detectBackendFrameworks('/path/to/project', pkg)
687
+ * // => [
688
+ * // { id: 'nestjs', name: 'NestJS', confidence: 85, ... },
689
+ * // { id: 'express', name: 'Express', confidence: 80, ... },
690
+ * // ]
691
+ * ```
1197
692
  */
1198
693
  function detectBackendFrameworks(projectPath, packageJson) {
1199
694
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1207,52 +702,64 @@ function detectBackendFrameworks(projectPath, packageJson) {
1207
702
  return results.sort((a, b) => b.confidence - a.confidence);
1208
703
  }
1209
704
 
1210
- /** Config patterns for Webpack */
1211
- const WEBPACK_CONFIG_PATTERNS = [
1212
- 'webpack.config.js',
1213
- 'webpack.config.ts',
1214
- 'webpack.config.cjs',
1215
- 'webpack.config.mjs',
1216
- 'webpack.config.babel.js',
1217
- ];
705
+ /** Config patterns for Babel */
706
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1218
707
  /**
1219
- * Detect Webpack in project.
708
+ * Detect Babel in project.
1220
709
  *
1221
710
  * @param projectPath - Project directory path
1222
711
  * @param packageJson - Optional pre-loaded package.json
1223
712
  * @returns Detection result or null if not detected
713
+ *
714
+ * @example Detecting Babel compiler
715
+ * ```typescript
716
+ * const result = babelDetector('/path/to/project', {
717
+ * name: 'my-app',
718
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
719
+ * })
720
+ * // => {
721
+ * // id: 'babel',
722
+ * // name: 'Babel',
723
+ * // version: '7.23.0',
724
+ * // confidence: 60,
725
+ * // detectedFrom: [
726
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
727
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
728
+ * // ]
729
+ * // }
730
+ * ```
1224
731
  */
1225
- function webpackDetector(projectPath, packageJson) {
732
+ function babelDetector(projectPath, packageJson) {
1226
733
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1227
734
  const sources = [];
1228
735
  let confidence = 0;
1229
736
  let version;
1230
737
  const deps = collectAllDependencies(pkg);
1231
- if (deps['webpack']) {
738
+ if (deps['@babel/core']) {
1232
739
  confidence += 50;
1233
- version = parseVersionString(deps['webpack']);
1234
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
740
+ version = parseVersionString(deps['@babel/core']);
741
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1235
742
  }
1236
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
743
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1237
744
  if (configPath) {
1238
745
  confidence += 40;
1239
746
  sources.push({ type: 'config-file', path: configPath });
1240
747
  }
1241
- if (deps['webpack-cli']) {
1242
- confidence += 10;
1243
- sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
748
+ if (pkg && 'babel' in pkg) {
749
+ confidence += 30;
750
+ sources.push({ type: 'package.json', field: 'babel' });
1244
751
  }
1245
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1246
- for (const name of scriptMatches) {
1247
- confidence = min(confidence + 5, 100);
1248
- sources.push({ type: 'package.json', field: `scripts.${name}` });
752
+ const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
753
+ if (babelPackages.length > 1) {
754
+ confidence += 10;
755
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1249
756
  }
1250
757
  if (confidence === 0) {
1251
758
  return null;
1252
759
  }
1253
760
  return {
1254
- id: 'webpack',
1255
- name: 'Webpack',
761
+ id: 'babel',
762
+ name: 'Babel',
1256
763
  version,
1257
764
  configPath,
1258
765
  confidence: min(confidence, 100),
@@ -1260,94 +767,126 @@ function webpackDetector(projectPath, packageJson) {
1260
767
  };
1261
768
  }
1262
769
 
1263
- /** Config patterns for Vite */
1264
- const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
1265
770
  /**
1266
- * Detect Vite in project.
771
+ * Detect esbuild in project.
1267
772
  *
1268
773
  * @param projectPath - Project directory path
1269
774
  * @param packageJson - Optional pre-loaded package.json
1270
775
  * @returns Detection result or null if not detected
776
+ *
777
+ * @example Detecting esbuild bundler
778
+ * ```typescript
779
+ * const result = esbuildDetector('/path/to/project', {
780
+ * name: 'my-lib',
781
+ * devDependencies: { 'esbuild': '^0.19.0' },
782
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
783
+ * })
784
+ * // => {
785
+ * // id: 'esbuild',
786
+ * // name: 'esbuild',
787
+ * // version: '0.19.0',
788
+ * // confidence: 80,
789
+ * // detectedFrom: [
790
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
791
+ * // { type: 'package.json', field: 'scripts.build' }
792
+ * // ]
793
+ * // }
794
+ * ```
1271
795
  */
1272
- function viteDetector(projectPath, packageJson) {
796
+ function esbuildDetector(projectPath, packageJson) {
1273
797
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1274
798
  const sources = [];
1275
799
  let confidence = 0;
1276
800
  let version;
1277
801
  const deps = collectAllDependencies(pkg);
1278
- if (deps['vite']) {
1279
- confidence += 60;
1280
- version = parseVersionString(deps['vite']);
1281
- sources.push({ type: 'package.json', field: 'dependencies.vite' });
1282
- }
1283
- const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1284
- if (configPath) {
1285
- confidence += 35;
1286
- sources.push({ type: 'config-file', path: configPath });
802
+ if (deps['esbuild']) {
803
+ confidence += 70;
804
+ version = parseVersionString(deps['esbuild']);
805
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
1287
806
  }
1288
- if (deps['vitest']) {
1289
- confidence += 10;
1290
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
807
+ const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
808
+ if (esbuildPlugins.length > 0) {
809
+ confidence += 15;
810
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
1291
811
  }
1292
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1293
- if (vitePlugins.length > 0) {
1294
- confidence += 10;
1295
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
812
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
813
+ for (const name of scriptMatches) {
814
+ confidence = min(confidence + 10, 100);
815
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1296
816
  }
1297
817
  if (confidence === 0) {
1298
818
  return null;
1299
819
  }
1300
820
  return {
1301
- id: 'vite',
1302
- name: 'Vite',
821
+ id: 'esbuild',
822
+ name: 'esbuild',
1303
823
  version,
1304
- configPath,
1305
824
  confidence: min(confidence, 100),
1306
825
  detectedFrom: sources,
1307
826
  };
1308
827
  }
1309
828
 
1310
- /** Config patterns for Rollup */
1311
- const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
829
+ /** Config patterns for Parcel */
830
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1312
831
  /**
1313
- * Detect Rollup in project.
832
+ * Detect Parcel in project.
1314
833
  *
1315
834
  * @param projectPath - Project directory path
1316
835
  * @param packageJson - Optional pre-loaded package.json
1317
836
  * @returns Detection result or null if not detected
837
+ *
838
+ * @example Detecting Parcel bundler
839
+ * ```typescript
840
+ * const result = parcelDetector('/path/to/project', {
841
+ * name: 'my-app',
842
+ * devDependencies: { 'parcel': '^2.10.0' },
843
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
844
+ * })
845
+ * // => {
846
+ * // id: 'parcel',
847
+ * // name: 'Parcel',
848
+ * // version: '2.10.0',
849
+ * // confidence: 80,
850
+ * // detectedFrom: [
851
+ * // { type: 'package.json', field: 'dependencies.parcel' },
852
+ * // { type: 'package.json', field: 'scripts.dev' },
853
+ * // { type: 'package.json', field: 'scripts.build' }
854
+ * // ]
855
+ * // }
856
+ * ```
1318
857
  */
1319
- function rollupDetector(projectPath, packageJson) {
858
+ function parcelDetector(projectPath, packageJson) {
1320
859
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1321
860
  const sources = [];
1322
861
  let confidence = 0;
1323
862
  let version;
1324
863
  const deps = collectAllDependencies(pkg);
1325
- if (deps['rollup']) {
1326
- confidence += 55;
1327
- version = parseVersionString(deps['rollup']);
1328
- sources.push({ type: 'package.json', field: 'dependencies.rollup' });
864
+ if (deps['parcel']) {
865
+ confidence += 60;
866
+ version = parseVersionString(deps['parcel']);
867
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1329
868
  }
1330
- const configPath = locateConfigFile(projectPath, ROLLUP_CONFIG_PATTERNS);
869
+ if (deps['parcel-bundler']) {
870
+ confidence += 60;
871
+ version = parseVersionString(deps['parcel-bundler']);
872
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
873
+ }
874
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1331
875
  if (configPath) {
1332
- confidence += 40;
876
+ confidence += 30;
1333
877
  sources.push({ type: 'config-file', path: configPath });
1334
878
  }
1335
- const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1336
- if (rollupPlugins.length > 0) {
1337
- confidence += 10;
1338
- sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1339
- }
1340
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
879
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1341
880
  for (const name of scriptMatches) {
1342
- confidence = min(confidence + 5, 100);
881
+ confidence = min(confidence + 10, 100);
1343
882
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1344
883
  }
1345
884
  if (confidence === 0) {
1346
885
  return null;
1347
886
  }
1348
887
  return {
1349
- id: 'rollup',
1350
- name: 'Rollup',
888
+ id: 'parcel',
889
+ name: 'Parcel',
1351
890
  version,
1352
891
  configPath,
1353
892
  confidence: min(confidence, 100),
@@ -1355,86 +894,134 @@ function rollupDetector(projectPath, packageJson) {
1355
894
  };
1356
895
  }
1357
896
 
897
+ /** Config patterns for Rollup */
898
+ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
1358
899
  /**
1359
- * Detect esbuild in project.
900
+ * Detect Rollup in project.
1360
901
  *
1361
902
  * @param projectPath - Project directory path
1362
903
  * @param packageJson - Optional pre-loaded package.json
1363
904
  * @returns Detection result or null if not detected
905
+ *
906
+ * @example Detecting Rollup bundler
907
+ * ```typescript
908
+ * const result = rollupDetector('/path/to/project', {
909
+ * name: 'my-lib',
910
+ * devDependencies: {
911
+ * 'rollup': '^4.0.0',
912
+ * '@rollup/plugin-node-resolve': '^15.0.0',
913
+ * '@rollup/plugin-commonjs': '^25.0.0'
914
+ * }
915
+ * })
916
+ * // => {
917
+ * // id: 'rollup',
918
+ * // name: 'Rollup',
919
+ * // version: '4.0.0',
920
+ * // confidence: 65,
921
+ * // detectedFrom: [
922
+ * // { type: 'package.json', field: 'dependencies.rollup' },
923
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
924
+ * // ]
925
+ * // }
926
+ * ```
1364
927
  */
1365
- function esbuildDetector(projectPath, packageJson) {
928
+ function rollupDetector(projectPath, packageJson) {
1366
929
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1367
930
  const sources = [];
1368
931
  let confidence = 0;
1369
932
  let version;
1370
933
  const deps = collectAllDependencies(pkg);
1371
- if (deps['esbuild']) {
1372
- confidence += 70;
1373
- version = parseVersionString(deps['esbuild']);
1374
- sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
934
+ if (deps['rollup']) {
935
+ confidence += 55;
936
+ version = parseVersionString(deps['rollup']);
937
+ sources.push({ type: 'package.json', field: 'dependencies.rollup' });
1375
938
  }
1376
- const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1377
- if (esbuildPlugins.length > 0) {
1378
- confidence += 15;
1379
- sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
939
+ const configPath = locateConfigFile(projectPath, ROLLUP_CONFIG_PATTERNS);
940
+ if (configPath) {
941
+ confidence += 40;
942
+ sources.push({ type: 'config-file', path: configPath });
1380
943
  }
1381
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
944
+ const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
945
+ if (rollupPlugins.length > 0) {
946
+ confidence += 10;
947
+ sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
948
+ }
949
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1382
950
  for (const name of scriptMatches) {
1383
- confidence = min(confidence + 10, 100);
951
+ confidence = min(confidence + 5, 100);
1384
952
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1385
953
  }
1386
954
  if (confidence === 0) {
1387
955
  return null;
1388
956
  }
1389
957
  return {
1390
- id: 'esbuild',
1391
- name: 'esbuild',
958
+ id: 'rollup',
959
+ name: 'Rollup',
1392
960
  version,
961
+ configPath,
1393
962
  confidence: min(confidence, 100),
1394
963
  detectedFrom: sources,
1395
964
  };
1396
965
  }
1397
966
 
1398
- /** Config patterns for Babel */
1399
- const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
967
+ /** Config patterns for SWC */
968
+ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1400
969
  /**
1401
- * Detect Babel in project.
970
+ * Detect SWC in project.
1402
971
  *
1403
972
  * @param projectPath - Project directory path
1404
973
  * @param packageJson - Optional pre-loaded package.json
1405
974
  * @returns Detection result or null if not detected
975
+ *
976
+ * @example Detecting SWC compiler
977
+ * ```typescript
978
+ * const result = swcDetector('/path/to/project', {
979
+ * name: 'my-app',
980
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
981
+ * })
982
+ * // => {
983
+ * // id: 'swc',
984
+ * // name: 'SWC',
985
+ * // version: '1.3.0',
986
+ * // confidence: 70,
987
+ * // detectedFrom: [
988
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
989
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
990
+ * // ]
991
+ * // }
992
+ * ```
1406
993
  */
1407
- function babelDetector(projectPath, packageJson) {
994
+ function swcDetector(projectPath, packageJson) {
1408
995
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1409
996
  const sources = [];
1410
997
  let confidence = 0;
1411
998
  let version;
1412
999
  const deps = collectAllDependencies(pkg);
1413
- if (deps['@babel/core']) {
1414
- confidence += 50;
1415
- version = parseVersionString(deps['@babel/core']);
1416
- sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1000
+ if (deps['@swc/core']) {
1001
+ confidence += 60;
1002
+ version = parseVersionString(deps['@swc/core']);
1003
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1417
1004
  }
1418
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1005
+ const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1419
1006
  if (configPath) {
1420
- confidence += 40;
1007
+ confidence += 35;
1421
1008
  sources.push({ type: 'config-file', path: configPath });
1422
1009
  }
1423
- if (pkg && 'babel' in pkg) {
1424
- confidence += 30;
1425
- sources.push({ type: 'package.json', field: 'babel' });
1426
- }
1427
- const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1428
- if (babelPackages.length > 1) {
1010
+ if (deps['@swc/cli']) {
1429
1011
  confidence += 10;
1430
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1012
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1013
+ }
1014
+ const swcPlugins = keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1015
+ if (swcPlugins.length > 1) {
1016
+ confidence += 5;
1017
+ sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1431
1018
  }
1432
1019
  if (confidence === 0) {
1433
1020
  return null;
1434
1021
  }
1435
1022
  return {
1436
- id: 'babel',
1437
- name: 'Babel',
1023
+ id: 'swc',
1024
+ name: 'SWC',
1438
1025
  version,
1439
1026
  configPath,
1440
1027
  confidence: min(confidence, 100),
@@ -1442,46 +1029,69 @@ function babelDetector(projectPath, packageJson) {
1442
1029
  };
1443
1030
  }
1444
1031
 
1445
- /** Config patterns for SWC */
1446
- const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1032
+ /** Config patterns for Vite */
1033
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
1447
1034
  /**
1448
- * Detect SWC in project.
1035
+ * Detect Vite in project.
1449
1036
  *
1450
1037
  * @param projectPath - Project directory path
1451
1038
  * @param packageJson - Optional pre-loaded package.json
1452
1039
  * @returns Detection result or null if not detected
1040
+ *
1041
+ * @example Detecting Vite build tool
1042
+ * ```typescript
1043
+ * const result = viteDetector('/path/to/project', {
1044
+ * name: 'my-app',
1045
+ * devDependencies: {
1046
+ * 'vite': '^5.0.0',
1047
+ * '@vitejs/plugin-react': '^4.0.0',
1048
+ * 'vitest': '^1.0.0'
1049
+ * }
1050
+ * })
1051
+ * // => {
1052
+ * // id: 'vite',
1053
+ * // name: 'Vite',
1054
+ * // version: '5.0.0',
1055
+ * // confidence: 80,
1056
+ * // detectedFrom: [
1057
+ * // { type: 'package.json', field: 'dependencies.vite' },
1058
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1059
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1060
+ * // ]
1061
+ * // }
1062
+ * ```
1453
1063
  */
1454
- function swcDetector(projectPath, packageJson) {
1064
+ function viteDetector(projectPath, packageJson) {
1455
1065
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1456
1066
  const sources = [];
1457
1067
  let confidence = 0;
1458
1068
  let version;
1459
1069
  const deps = collectAllDependencies(pkg);
1460
- if (deps['@swc/core']) {
1070
+ if (deps['vite']) {
1461
1071
  confidence += 60;
1462
- version = parseVersionString(deps['@swc/core']);
1463
- sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1072
+ version = parseVersionString(deps['vite']);
1073
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
1464
1074
  }
1465
- const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1075
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1466
1076
  if (configPath) {
1467
1077
  confidence += 35;
1468
1078
  sources.push({ type: 'config-file', path: configPath });
1469
1079
  }
1470
- if (deps['@swc/cli']) {
1080
+ if (deps['vitest']) {
1471
1081
  confidence += 10;
1472
- sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1082
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1473
1083
  }
1474
- const swcPlugins = keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1475
- if (swcPlugins.length > 1) {
1476
- confidence += 5;
1477
- sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1084
+ const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1085
+ if (vitePlugins.length > 0) {
1086
+ confidence += 10;
1087
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1478
1088
  }
1479
1089
  if (confidence === 0) {
1480
1090
  return null;
1481
1091
  }
1482
1092
  return {
1483
- id: 'swc',
1484
- name: 'SWC',
1093
+ id: 'vite',
1094
+ name: 'Vite',
1485
1095
  version,
1486
1096
  configPath,
1487
1097
  confidence: min(confidence, 100),
@@ -1489,47 +1099,72 @@ function swcDetector(projectPath, packageJson) {
1489
1099
  };
1490
1100
  }
1491
1101
 
1492
- /** Config patterns for Parcel */
1493
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1102
+ /** Config patterns for Webpack */
1103
+ const WEBPACK_CONFIG_PATTERNS = [
1104
+ 'webpack.config.js',
1105
+ 'webpack.config.ts',
1106
+ 'webpack.config.cjs',
1107
+ 'webpack.config.mjs',
1108
+ 'webpack.config.babel.js',
1109
+ ];
1494
1110
  /**
1495
- * Detect Parcel in project.
1111
+ * Detect Webpack in project.
1496
1112
  *
1497
1113
  * @param projectPath - Project directory path
1498
1114
  * @param packageJson - Optional pre-loaded package.json
1499
1115
  * @returns Detection result or null if not detected
1116
+ *
1117
+ * @example Detecting Webpack bundler
1118
+ * ```typescript
1119
+ * const result = webpackDetector('/path/to/project', {
1120
+ * name: 'my-app',
1121
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1122
+ * scripts: { 'build': 'webpack --mode production' }
1123
+ * })
1124
+ * // => {
1125
+ * // id: 'webpack',
1126
+ * // name: 'Webpack',
1127
+ * // version: '5.89.0',
1128
+ * // confidence: 65,
1129
+ * // detectedFrom: [
1130
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1131
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1132
+ * // { type: 'package.json', field: 'scripts.build' }
1133
+ * // ]
1134
+ * // }
1135
+ * ```
1500
1136
  */
1501
- function parcelDetector(projectPath, packageJson) {
1137
+ function webpackDetector(projectPath, packageJson) {
1502
1138
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1503
1139
  const sources = [];
1504
1140
  let confidence = 0;
1505
1141
  let version;
1506
1142
  const deps = collectAllDependencies(pkg);
1507
- if (deps['parcel']) {
1508
- confidence += 60;
1509
- version = parseVersionString(deps['parcel']);
1510
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1511
- }
1512
- if (deps['parcel-bundler']) {
1513
- confidence += 60;
1514
- version = parseVersionString(deps['parcel-bundler']);
1515
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1143
+ if (deps['webpack']) {
1144
+ confidence += 50;
1145
+ version = parseVersionString(deps['webpack']);
1146
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1516
1147
  }
1517
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1148
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1518
1149
  if (configPath) {
1519
- confidence += 30;
1150
+ confidence += 40;
1520
1151
  sources.push({ type: 'config-file', path: configPath });
1521
1152
  }
1522
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1153
+ if (deps['webpack-cli']) {
1154
+ confidence += 10;
1155
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1156
+ }
1157
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1523
1158
  for (const name of scriptMatches) {
1524
- confidence = min(confidence + 10, 100);
1159
+ confidence = min(confidence + 5, 100);
1525
1160
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1526
1161
  }
1527
1162
  if (confidence === 0) {
1528
1163
  return null;
1529
1164
  }
1530
1165
  return {
1531
- id: 'parcel',
1532
- name: 'Parcel',
1166
+ id: 'webpack',
1167
+ name: 'Webpack',
1533
1168
  version,
1534
1169
  configPath,
1535
1170
  confidence: min(confidence, 100),
@@ -1553,6 +1188,22 @@ const buildToolDetectors = [
1553
1188
  * @param projectPath - Project directory path
1554
1189
  * @param packageJson - Optional pre-loaded package.json
1555
1190
  * @returns Array of detected build tools, sorted by confidence
1191
+ *
1192
+ * @example Detecting multiple build tools
1193
+ * ```typescript
1194
+ * const tools = detectBuildTools('/path/to/project', {
1195
+ * name: 'my-app',
1196
+ * devDependencies: {
1197
+ * 'vite': '^5.0.0',
1198
+ * '@vitejs/plugin-react': '^4.0.0',
1199
+ * '@babel/core': '^7.23.0'
1200
+ * }
1201
+ * })
1202
+ * // => [
1203
+ * // { id: 'vite', name: 'Vite', version: '5.0.0', confidence: 70, ... },
1204
+ * // { id: 'babel', name: 'Babel', version: '7.23.0', confidence: 50, ... }
1205
+ * // ]
1206
+ * ```
1556
1207
  */
1557
1208
  function detectBuildTools(projectPath, packageJson) {
1558
1209
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1567,81 +1218,187 @@ function detectBuildTools(projectPath, packageJson) {
1567
1218
  }
1568
1219
 
1569
1220
  /**
1570
- * Detect React in project.
1221
+ * Detect Angular in project.
1222
+ *
1223
+ * @param projectPath - Project directory path
1224
+ * @param packageJson - Optional pre-loaded package.json
1225
+ * @returns Detection result or null if not detected
1226
+ *
1227
+ * @example Detecting Angular framework
1228
+ * ```typescript
1229
+ * const result = angularDetector('/path/to/angular-app', {
1230
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1231
+ * })
1232
+ * // => {
1233
+ * // id: 'angular',
1234
+ * // name: 'Angular',
1235
+ * // category: 'frontend',
1236
+ * // version: '17.0.0',
1237
+ * // confidence: 85,
1238
+ * // detectedFrom: [
1239
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1240
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1241
+ * // ]
1242
+ * // }
1243
+ * ```
1244
+ */
1245
+ function angularDetector(projectPath, packageJson) {
1246
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1247
+ const sources = [];
1248
+ let confidence = 0;
1249
+ let version;
1250
+ const deps = collectAllDependencies(pkg);
1251
+ if (deps['@angular/core']) {
1252
+ confidence += 70;
1253
+ version = parseVersionString(deps['@angular/core']);
1254
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1255
+ }
1256
+ if (deps['@angular/cli']) {
1257
+ confidence += 15;
1258
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1259
+ }
1260
+ if (exists(join$1(projectPath, 'angular.json'))) {
1261
+ confidence += 15;
1262
+ sources.push({ type: 'config-file', path: 'angular.json' });
1263
+ }
1264
+ if (deps['angular'] && !deps['@angular/core']) {
1265
+ return {
1266
+ id: 'angularjs',
1267
+ name: 'AngularJS (Legacy)',
1268
+ category: 'frontend',
1269
+ version: parseVersionString(deps['angular']),
1270
+ confidence: 80,
1271
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1272
+ };
1273
+ }
1274
+ if (confidence === 0) {
1275
+ return null;
1276
+ }
1277
+ return {
1278
+ id: 'angular',
1279
+ name: 'Angular',
1280
+ category: 'frontend',
1281
+ version,
1282
+ confidence: min(confidence, 100),
1283
+ detectedFrom: sources,
1284
+ };
1285
+ }
1286
+
1287
+ /**
1288
+ * Detect Astro in project.
1289
+ *
1290
+ * @param projectPath - Project directory path
1291
+ * @param packageJson - Optional pre-loaded package.json
1292
+ * @returns Detection result or null if not detected
1293
+ *
1294
+ * @example Detecting Astro framework
1295
+ * ```typescript
1296
+ * const result = astroDetector('/path/to/astro-project', {
1297
+ * dependencies: { 'astro': '^4.0.0' }
1298
+ * })
1299
+ * // => {
1300
+ * // id: 'astro',
1301
+ * // name: 'Astro',
1302
+ * // category: 'meta-framework',
1303
+ * // version: '4.0.0',
1304
+ * // confidence: 70,
1305
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1306
+ * // }
1307
+ * ```
1308
+ */
1309
+ function astroDetector(projectPath, packageJson) {
1310
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1311
+ const sources = [];
1312
+ let confidence = 0;
1313
+ let version;
1314
+ const deps = collectAllDependencies(pkg);
1315
+ if (deps['astro']) {
1316
+ confidence += 70;
1317
+ version = parseVersionString(deps['astro']);
1318
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1319
+ }
1320
+ if (exists(join$1(projectPath, 'astro.config.mjs')) ||
1321
+ exists(join$1(projectPath, 'astro.config.ts')) ||
1322
+ exists(join$1(projectPath, 'astro.config.js'))) {
1323
+ confidence += 25;
1324
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
1325
+ }
1326
+ if (exists(join$1(projectPath, 'src', 'pages'))) {
1327
+ confidence += 5;
1328
+ sources.push({ type: 'directory', path: 'src/pages/' });
1329
+ }
1330
+ if (confidence === 0) {
1331
+ return null;
1332
+ }
1333
+ return {
1334
+ id: 'astro',
1335
+ name: 'Astro',
1336
+ category: 'meta-framework',
1337
+ version,
1338
+ confidence: min(confidence, 100),
1339
+ detectedFrom: sources,
1340
+ };
1341
+ }
1342
+
1343
+ /**
1344
+ * Detect Gatsby in project.
1571
1345
  *
1572
1346
  * @param projectPath - Project directory path
1573
1347
  * @param packageJson - Optional pre-loaded package.json
1574
1348
  * @returns Detection result or null if not detected
1349
+ *
1350
+ * @example Detecting Gatsby framework
1351
+ * ```typescript
1352
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1353
+ * dependencies: {
1354
+ * 'gatsby': '^5.0.0',
1355
+ * 'gatsby-plugin-image': '^3.0.0',
1356
+ * 'gatsby-source-filesystem': '^5.0.0'
1357
+ * }
1358
+ * })
1359
+ * // => {
1360
+ * // id: 'gatsby',
1361
+ * // name: 'Gatsby',
1362
+ * // category: 'meta-framework',
1363
+ * // version: '5.0.0',
1364
+ * // confidence: 75,
1365
+ * // detectedFrom: [
1366
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1367
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1368
+ * // ]
1369
+ * // }
1370
+ * ```
1575
1371
  */
1576
- function reactDetector(projectPath, packageJson) {
1372
+ function gatsbyDetector(projectPath, packageJson) {
1577
1373
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1578
1374
  const sources = [];
1579
1375
  let confidence = 0;
1580
1376
  let version;
1581
- const metaFrameworks = [];
1582
1377
  const deps = collectAllDependencies(pkg);
1583
- if (deps['react']) {
1584
- confidence += 60;
1585
- version = parseVersionString(deps['react']);
1586
- sources.push({ type: 'package.json', field: 'dependencies.react' });
1587
- }
1588
- if (deps['react-dom']) {
1589
- confidence += 20;
1590
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1591
- }
1592
- if (deps['react-native']) {
1593
- confidence += 20;
1594
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1595
- }
1596
- const hasJsxFiles = exists(join$1(projectPath, 'src', 'App.tsx')) ||
1597
- exists(join$1(projectPath, 'src', 'App.jsx')) ||
1598
- exists(join$1(projectPath, 'src', 'index.tsx')) ||
1599
- exists(join$1(projectPath, 'src', 'index.jsx'));
1600
- if (hasJsxFiles) {
1601
- confidence += 10;
1602
- sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1603
- }
1604
- if (deps['next']) {
1605
- metaFrameworks.push({
1606
- id: 'nextjs',
1607
- name: 'Next.js',
1608
- category: 'meta-framework',
1609
- version: parseVersionString(deps['next']),
1610
- confidence: 90,
1611
- detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1612
- });
1613
- }
1614
1378
  if (deps['gatsby']) {
1615
- metaFrameworks.push({
1616
- id: 'gatsby',
1617
- name: 'Gatsby',
1618
- category: 'meta-framework',
1619
- version: parseVersionString(deps['gatsby']),
1620
- confidence: 90,
1621
- detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1622
- });
1379
+ confidence += 70;
1380
+ version = parseVersionString(deps['gatsby']);
1381
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1623
1382
  }
1624
- if (deps['@remix-run/react'] || deps['remix']) {
1625
- metaFrameworks.push({
1626
- id: 'remix',
1627
- name: 'Remix',
1628
- category: 'meta-framework',
1629
- version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1630
- confidence: 90,
1631
- detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1632
- });
1383
+ if (exists(join$1(projectPath, 'gatsby-config.js')) || exists(join$1(projectPath, 'gatsby-config.ts'))) {
1384
+ confidence += 25;
1385
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1386
+ }
1387
+ const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1388
+ if (gatsbyPlugins.length > 0) {
1389
+ confidence += 5;
1390
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1633
1391
  }
1634
1392
  if (confidence === 0) {
1635
1393
  return null;
1636
1394
  }
1637
1395
  return {
1638
- id: 'react',
1639
- name: 'React',
1640
- category: 'frontend',
1396
+ id: 'gatsby',
1397
+ name: 'Gatsby',
1398
+ category: 'meta-framework',
1641
1399
  version,
1642
1400
  confidence: min(confidence, 100),
1643
1401
  detectedFrom: sources,
1644
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1645
1402
  };
1646
1403
  }
1647
1404
 
@@ -1651,6 +1408,21 @@ function reactDetector(projectPath, packageJson) {
1651
1408
  * @param projectPath - Project directory path
1652
1409
  * @param packageJson - Optional pre-loaded package.json
1653
1410
  * @returns Detection result or null if not detected
1411
+ *
1412
+ * @example Detecting Next.js framework
1413
+ * ```typescript
1414
+ * const result = nextjsDetector('/path/to/nextjs-app', {
1415
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
1416
+ * })
1417
+ * // => {
1418
+ * // id: 'nextjs',
1419
+ * // name: 'Next.js',
1420
+ * // category: 'meta-framework',
1421
+ * // version: '14.0.0',
1422
+ * // confidence: 70,
1423
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
1424
+ * // }
1425
+ * ```
1654
1426
  */
1655
1427
  function nextjsDetector(projectPath, packageJson) {
1656
1428
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1690,37 +1462,52 @@ function nextjsDetector(projectPath, packageJson) {
1690
1462
  }
1691
1463
 
1692
1464
  /**
1693
- * Detect Remix in project.
1465
+ * Detect Nuxt in project.
1694
1466
  *
1695
1467
  * @param projectPath - Project directory path
1696
1468
  * @param packageJson - Optional pre-loaded package.json
1697
1469
  * @returns Detection result or null if not detected
1470
+ *
1471
+ * @example Detecting Nuxt framework
1472
+ * ```typescript
1473
+ * const result = nuxtDetector('/path/to/nuxt-app', {
1474
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
1475
+ * })
1476
+ * // => {
1477
+ * // id: 'nuxt',
1478
+ * // name: 'Nuxt',
1479
+ * // category: 'meta-framework',
1480
+ * // version: '3.0.0',
1481
+ * // confidence: 70,
1482
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
1483
+ * // }
1484
+ * ```
1698
1485
  */
1699
- function remixDetector(projectPath, packageJson) {
1486
+ function nuxtDetector(projectPath, packageJson) {
1700
1487
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1701
1488
  const sources = [];
1702
1489
  let confidence = 0;
1703
1490
  let version;
1704
1491
  const deps = collectAllDependencies(pkg);
1705
- if (deps['@remix-run/react']) {
1492
+ if (deps['nuxt'] || deps['nuxt3']) {
1706
1493
  confidence += 70;
1707
- version = parseVersionString(deps['@remix-run/react']);
1708
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1494
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1495
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1709
1496
  }
1710
- if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1711
- confidence += 20;
1712
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1497
+ if (exists(join$1(projectPath, 'nuxt.config.js')) || exists(join$1(projectPath, 'nuxt.config.ts'))) {
1498
+ confidence += 25;
1499
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1713
1500
  }
1714
- if (exists(join$1(projectPath, 'remix.config.js')) || exists(join$1(projectPath, 'remix.config.ts'))) {
1715
- confidence += 10;
1716
- sources.push({ type: 'config-file', path: 'remix.config.*' });
1501
+ if (exists(join$1(projectPath, 'pages'))) {
1502
+ confidence += 5;
1503
+ sources.push({ type: 'directory', path: 'pages/' });
1717
1504
  }
1718
1505
  if (confidence === 0) {
1719
1506
  return null;
1720
1507
  }
1721
1508
  return {
1722
- id: 'remix',
1723
- name: 'Remix',
1509
+ id: 'nuxt',
1510
+ name: 'Nuxt',
1724
1511
  category: 'meta-framework',
1725
1512
  version,
1726
1513
  confidence: min(confidence, 100),
@@ -1729,39 +1516,59 @@ function remixDetector(projectPath, packageJson) {
1729
1516
  }
1730
1517
 
1731
1518
  /**
1732
- * Detect Gatsby in project.
1519
+ * Detect Qwik in project.
1733
1520
  *
1734
1521
  * @param projectPath - Project directory path
1735
1522
  * @param packageJson - Optional pre-loaded package.json
1736
1523
  * @returns Detection result or null if not detected
1524
+ *
1525
+ * @example Detecting Qwik framework
1526
+ * ```typescript
1527
+ * const result = qwikDetector('/path/to/qwik-app', {
1528
+ * dependencies: {
1529
+ * '@builder.io/qwik': '^1.0.0',
1530
+ * '@builder.io/qwik-city': '^1.0.0'
1531
+ * }
1532
+ * })
1533
+ * // => {
1534
+ * // id: 'qwik',
1535
+ * // name: 'Qwik',
1536
+ * // category: 'frontend',
1537
+ * // version: '1.0.0',
1538
+ * // confidence: 90,
1539
+ * // detectedFrom: [
1540
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
1541
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
1542
+ * // ]
1543
+ * // }
1544
+ * ```
1737
1545
  */
1738
- function gatsbyDetector(projectPath, packageJson) {
1546
+ function qwikDetector(projectPath, packageJson) {
1739
1547
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1740
1548
  const sources = [];
1741
1549
  let confidence = 0;
1742
1550
  let version;
1743
1551
  const deps = collectAllDependencies(pkg);
1744
- if (deps['gatsby']) {
1552
+ if (deps['@builder.io/qwik']) {
1745
1553
  confidence += 70;
1746
- version = parseVersionString(deps['gatsby']);
1747
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1554
+ version = parseVersionString(deps['@builder.io/qwik']);
1555
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1748
1556
  }
1749
- if (exists(join$1(projectPath, 'gatsby-config.js')) || exists(join$1(projectPath, 'gatsby-config.ts'))) {
1750
- confidence += 25;
1751
- sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1557
+ if (deps['@builder.io/qwik-city']) {
1558
+ confidence += 20;
1559
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1752
1560
  }
1753
- const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1754
- if (gatsbyPlugins.length > 0) {
1755
- confidence += 5;
1756
- sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1561
+ if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
1562
+ confidence += 10;
1563
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
1757
1564
  }
1758
1565
  if (confidence === 0) {
1759
1566
  return null;
1760
1567
  }
1761
1568
  return {
1762
- id: 'gatsby',
1763
- name: 'Gatsby',
1764
- category: 'meta-framework',
1569
+ id: 'qwik',
1570
+ name: 'Qwik',
1571
+ category: 'frontend',
1765
1572
  version,
1766
1573
  confidence: min(confidence, 100),
1767
1574
  detectedFrom: sources,
@@ -1769,53 +1576,94 @@ function gatsbyDetector(projectPath, packageJson) {
1769
1576
  }
1770
1577
 
1771
1578
  /**
1772
- * Detect Vue in project.
1579
+ * Detect React in project.
1773
1580
  *
1774
1581
  * @param projectPath - Project directory path
1775
1582
  * @param packageJson - Optional pre-loaded package.json
1776
1583
  * @returns Detection result or null if not detected
1584
+ *
1585
+ * @example Detecting React library
1586
+ * ```typescript
1587
+ * const result = reactDetector('/path/to/react-app', {
1588
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
1589
+ * })
1590
+ * // => {
1591
+ * // id: 'react',
1592
+ * // name: 'React',
1593
+ * // category: 'frontend',
1594
+ * // version: '18.0.0',
1595
+ * // confidence: 80,
1596
+ * // detectedFrom: [
1597
+ * // { type: 'package.json', field: 'dependencies.react' },
1598
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
1599
+ * // ]
1600
+ * // }
1601
+ * ```
1777
1602
  */
1778
- function vueDetector(projectPath, packageJson) {
1603
+ function reactDetector(projectPath, packageJson) {
1779
1604
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1780
1605
  const sources = [];
1781
1606
  let confidence = 0;
1782
1607
  let version;
1783
1608
  const metaFrameworks = [];
1784
1609
  const deps = collectAllDependencies(pkg);
1785
- if (deps['vue']) {
1786
- confidence += 70;
1787
- version = parseVersionString(deps['vue']);
1788
- sources.push({ type: 'package.json', field: 'dependencies.vue' });
1610
+ if (deps['react']) {
1611
+ confidence += 60;
1612
+ version = parseVersionString(deps['react']);
1613
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
1789
1614
  }
1790
- if (deps['@vue/cli-service']) {
1791
- confidence += 15;
1792
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
1615
+ if (deps['react-dom']) {
1616
+ confidence += 20;
1617
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1793
1618
  }
1794
- const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
1795
- if (hasVueFiles) {
1619
+ if (deps['react-native']) {
1620
+ confidence += 20;
1621
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1622
+ }
1623
+ const hasJsxFiles = exists(join$1(projectPath, 'src', 'App.tsx')) ||
1624
+ exists(join$1(projectPath, 'src', 'App.jsx')) ||
1625
+ exists(join$1(projectPath, 'src', 'index.tsx')) ||
1626
+ exists(join$1(projectPath, 'src', 'index.jsx'));
1627
+ if (hasJsxFiles) {
1796
1628
  confidence += 10;
1797
- sources.push({ type: 'directory', path: 'src/*.vue' });
1629
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1798
1630
  }
1799
- if (exists(join$1(projectPath, 'vue.config.js'))) {
1800
- confidence += 5;
1801
- sources.push({ type: 'config-file', path: 'vue.config.js' });
1631
+ if (deps['next']) {
1632
+ metaFrameworks.push({
1633
+ id: 'nextjs',
1634
+ name: 'Next.js',
1635
+ category: 'meta-framework',
1636
+ version: parseVersionString(deps['next']),
1637
+ confidence: 90,
1638
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1639
+ });
1802
1640
  }
1803
- if (deps['nuxt'] || deps['nuxt3']) {
1641
+ if (deps['gatsby']) {
1804
1642
  metaFrameworks.push({
1805
- id: 'nuxt',
1806
- name: 'Nuxt',
1643
+ id: 'gatsby',
1644
+ name: 'Gatsby',
1807
1645
  category: 'meta-framework',
1808
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1646
+ version: parseVersionString(deps['gatsby']),
1809
1647
  confidence: 90,
1810
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1648
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1649
+ });
1650
+ }
1651
+ if (deps['@remix-run/react'] || deps['remix']) {
1652
+ metaFrameworks.push({
1653
+ id: 'remix',
1654
+ name: 'Remix',
1655
+ category: 'meta-framework',
1656
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1657
+ confidence: 90,
1658
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1811
1659
  });
1812
1660
  }
1813
1661
  if (confidence === 0) {
1814
1662
  return null;
1815
1663
  }
1816
1664
  return {
1817
- id: 'vue',
1818
- name: 'Vue',
1665
+ id: 'react',
1666
+ name: 'React',
1819
1667
  category: 'frontend',
1820
1668
  version,
1821
1669
  confidence: min(confidence, 100),
@@ -1825,37 +1673,58 @@ function vueDetector(projectPath, packageJson) {
1825
1673
  }
1826
1674
 
1827
1675
  /**
1828
- * Detect Nuxt in project.
1676
+ * Detect Remix in project.
1829
1677
  *
1830
1678
  * @param projectPath - Project directory path
1831
1679
  * @param packageJson - Optional pre-loaded package.json
1832
1680
  * @returns Detection result or null if not detected
1681
+ *
1682
+ * @example Detecting Remix framework
1683
+ * ```typescript
1684
+ * const result = remixDetector('/path/to/remix-app', {
1685
+ * dependencies: {
1686
+ * '@remix-run/react': '^2.0.0',
1687
+ * '@remix-run/node': '^2.0.0'
1688
+ * }
1689
+ * })
1690
+ * // => {
1691
+ * // id: 'remix',
1692
+ * // name: 'Remix',
1693
+ * // category: 'meta-framework',
1694
+ * // version: '2.0.0',
1695
+ * // confidence: 90,
1696
+ * // detectedFrom: [
1697
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
1698
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
1699
+ * // ]
1700
+ * // }
1701
+ * ```
1833
1702
  */
1834
- function nuxtDetector(projectPath, packageJson) {
1703
+ function remixDetector(projectPath, packageJson) {
1835
1704
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1836
1705
  const sources = [];
1837
1706
  let confidence = 0;
1838
1707
  let version;
1839
1708
  const deps = collectAllDependencies(pkg);
1840
- if (deps['nuxt'] || deps['nuxt3']) {
1709
+ if (deps['@remix-run/react']) {
1841
1710
  confidence += 70;
1842
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1843
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1711
+ version = parseVersionString(deps['@remix-run/react']);
1712
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1844
1713
  }
1845
- if (exists(join$1(projectPath, 'nuxt.config.js')) || exists(join$1(projectPath, 'nuxt.config.ts'))) {
1846
- confidence += 25;
1847
- sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1714
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1715
+ confidence += 20;
1716
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1848
1717
  }
1849
- if (exists(join$1(projectPath, 'pages'))) {
1850
- confidence += 5;
1851
- sources.push({ type: 'directory', path: 'pages/' });
1718
+ if (exists(join$1(projectPath, 'remix.config.js')) || exists(join$1(projectPath, 'remix.config.ts'))) {
1719
+ confidence += 10;
1720
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
1852
1721
  }
1853
1722
  if (confidence === 0) {
1854
1723
  return null;
1855
1724
  }
1856
1725
  return {
1857
- id: 'nuxt',
1858
- name: 'Nuxt',
1726
+ id: 'remix',
1727
+ name: 'Remix',
1859
1728
  category: 'meta-framework',
1860
1729
  version,
1861
1730
  confidence: min(confidence, 100),
@@ -1864,47 +1733,55 @@ function nuxtDetector(projectPath, packageJson) {
1864
1733
  }
1865
1734
 
1866
1735
  /**
1867
- * Detect Angular in project.
1736
+ * Detect Solid in project.
1868
1737
  *
1869
1738
  * @param projectPath - Project directory path
1870
1739
  * @param packageJson - Optional pre-loaded package.json
1871
1740
  * @returns Detection result or null if not detected
1741
+ *
1742
+ * @example Detecting Solid.js framework
1743
+ * ```typescript
1744
+ * const result = solidDetector('/path/to/solid-app', {
1745
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
1746
+ * })
1747
+ * // => {
1748
+ * // id: 'solid',
1749
+ * // name: 'Solid',
1750
+ * // category: 'frontend',
1751
+ * // version: '1.8.0',
1752
+ * // confidence: 90,
1753
+ * // detectedFrom: [
1754
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
1755
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
1756
+ * // ]
1757
+ * // }
1758
+ * ```
1872
1759
  */
1873
- function angularDetector(projectPath, packageJson) {
1760
+ function solidDetector(projectPath, packageJson) {
1874
1761
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1875
1762
  const sources = [];
1876
1763
  let confidence = 0;
1877
1764
  let version;
1878
1765
  const deps = collectAllDependencies(pkg);
1879
- if (deps['@angular/core']) {
1766
+ if (deps['solid-js']) {
1880
1767
  confidence += 70;
1881
- version = parseVersionString(deps['@angular/core']);
1882
- sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1883
- }
1884
- if (deps['@angular/cli']) {
1885
- confidence += 15;
1886
- sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1768
+ version = parseVersionString(deps['solid-js']);
1769
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1887
1770
  }
1888
- if (exists(join$1(projectPath, 'angular.json'))) {
1889
- confidence += 15;
1890
- sources.push({ type: 'config-file', path: 'angular.json' });
1771
+ if (deps['vite-plugin-solid']) {
1772
+ confidence += 20;
1773
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1891
1774
  }
1892
- if (deps['angular'] && !deps['@angular/core']) {
1893
- return {
1894
- id: 'angularjs',
1895
- name: 'AngularJS (Legacy)',
1896
- category: 'frontend',
1897
- version: parseVersionString(deps['angular']),
1898
- confidence: 80,
1899
- detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1900
- };
1775
+ if (deps['solid-start'] || deps['@solidjs/start']) {
1776
+ confidence += 10;
1777
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1901
1778
  }
1902
1779
  if (confidence === 0) {
1903
1780
  return null;
1904
1781
  }
1905
1782
  return {
1906
- id: 'angular',
1907
- name: 'Angular',
1783
+ id: 'solid',
1784
+ name: 'Solid',
1908
1785
  category: 'frontend',
1909
1786
  version,
1910
1787
  confidence: min(confidence, 100),
@@ -1918,6 +1795,21 @@ function angularDetector(projectPath, packageJson) {
1918
1795
  * @param projectPath - Project directory path
1919
1796
  * @param packageJson - Optional pre-loaded package.json
1920
1797
  * @returns Detection result or null if not detected
1798
+ *
1799
+ * @example Detecting Svelte framework
1800
+ * ```typescript
1801
+ * const result = svelteDetector('/path/to/svelte-app', {
1802
+ * devDependencies: { 'svelte': '^4.0.0' }
1803
+ * })
1804
+ * // => {
1805
+ * // id: 'svelte',
1806
+ * // name: 'Svelte',
1807
+ * // category: 'frontend',
1808
+ * // version: '4.0.0',
1809
+ * // confidence: 70,
1810
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
1811
+ * // }
1812
+ * ```
1921
1813
  */
1922
1814
  function svelteDetector(projectPath, packageJson) {
1923
1815
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1970,6 +1862,21 @@ function svelteDetector(projectPath, packageJson) {
1970
1862
  * @param projectPath - Project directory path
1971
1863
  * @param packageJson - Optional pre-loaded package.json
1972
1864
  * @returns Detection result or null if not detected
1865
+ *
1866
+ * @example Detecting SvelteKit framework
1867
+ * ```typescript
1868
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
1869
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
1870
+ * })
1871
+ * // => {
1872
+ * // id: 'sveltekit',
1873
+ * // name: 'SvelteKit',
1874
+ * // category: 'meta-framework',
1875
+ * // version: '2.0.0',
1876
+ * // confidence: 70,
1877
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
1878
+ * // }
1879
+ * ```
1973
1880
  */
1974
1881
  function sveltekitDetector(projectPath, packageJson) {
1975
1882
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2004,121 +1911,76 @@ function sveltekitDetector(projectPath, packageJson) {
2004
1911
  }
2005
1912
 
2006
1913
  /**
2007
- * Detect Solid in project.
1914
+ * Detect Vue in project.
2008
1915
  *
2009
1916
  * @param projectPath - Project directory path
2010
1917
  * @param packageJson - Optional pre-loaded package.json
2011
1918
  * @returns Detection result or null if not detected
2012
- */
2013
- function solidDetector(projectPath, packageJson) {
2014
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2015
- const sources = [];
2016
- let confidence = 0;
2017
- let version;
2018
- const deps = collectAllDependencies(pkg);
2019
- if (deps['solid-js']) {
2020
- confidence += 70;
2021
- version = parseVersionString(deps['solid-js']);
2022
- sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
2023
- }
2024
- if (deps['vite-plugin-solid']) {
2025
- confidence += 20;
2026
- sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
2027
- }
2028
- if (deps['solid-start'] || deps['@solidjs/start']) {
2029
- confidence += 10;
2030
- sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
2031
- }
2032
- if (confidence === 0) {
2033
- return null;
2034
- }
2035
- return {
2036
- id: 'solid',
2037
- name: 'Solid',
2038
- category: 'frontend',
2039
- version,
2040
- confidence: min(confidence, 100),
2041
- detectedFrom: sources,
2042
- };
2043
- }
2044
-
2045
- /**
2046
- * Detect Qwik in project.
2047
1919
  *
2048
- * @param projectPath - Project directory path
2049
- * @param packageJson - Optional pre-loaded package.json
2050
- * @returns Detection result or null if not detected
1920
+ * @example Detecting Vue.js framework
1921
+ * ```typescript
1922
+ * const result = vueDetector('/path/to/vue-app', {
1923
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
1924
+ * })
1925
+ * // => {
1926
+ * // id: 'vue',
1927
+ * // name: 'Vue',
1928
+ * // category: 'frontend',
1929
+ * // version: '3.0.0',
1930
+ * // confidence: 85,
1931
+ * // detectedFrom: [
1932
+ * // { type: 'package.json', field: 'dependencies.vue' },
1933
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
1934
+ * // ]
1935
+ * // }
1936
+ * ```
2051
1937
  */
2052
- function qwikDetector(projectPath, packageJson) {
1938
+ function vueDetector(projectPath, packageJson) {
2053
1939
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2054
1940
  const sources = [];
2055
1941
  let confidence = 0;
2056
1942
  let version;
1943
+ const metaFrameworks = [];
2057
1944
  const deps = collectAllDependencies(pkg);
2058
- if (deps['@builder.io/qwik']) {
1945
+ if (deps['vue']) {
2059
1946
  confidence += 70;
2060
- version = parseVersionString(deps['@builder.io/qwik']);
2061
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1947
+ version = parseVersionString(deps['vue']);
1948
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2062
1949
  }
2063
- if (deps['@builder.io/qwik-city']) {
2064
- confidence += 20;
2065
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1950
+ if (deps['@vue/cli-service']) {
1951
+ confidence += 15;
1952
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2066
1953
  }
2067
- if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
1954
+ const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
1955
+ if (hasVueFiles) {
2068
1956
  confidence += 10;
2069
- sources.push({ type: 'config-file', path: 'qwik.config.*' });
2070
- }
2071
- if (confidence === 0) {
2072
- return null;
2073
- }
2074
- return {
2075
- id: 'qwik',
2076
- name: 'Qwik',
2077
- category: 'frontend',
2078
- version,
2079
- confidence: min(confidence, 100),
2080
- detectedFrom: sources,
2081
- };
2082
- }
2083
-
2084
- /**
2085
- * Detect Astro in project.
2086
- *
2087
- * @param projectPath - Project directory path
2088
- * @param packageJson - Optional pre-loaded package.json
2089
- * @returns Detection result or null if not detected
2090
- */
2091
- function astroDetector(projectPath, packageJson) {
2092
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2093
- const sources = [];
2094
- let confidence = 0;
2095
- let version;
2096
- const deps = collectAllDependencies(pkg);
2097
- if (deps['astro']) {
2098
- confidence += 70;
2099
- version = parseVersionString(deps['astro']);
2100
- sources.push({ type: 'package.json', field: 'dependencies.astro' });
2101
- }
2102
- if (exists(join$1(projectPath, 'astro.config.mjs')) ||
2103
- exists(join$1(projectPath, 'astro.config.ts')) ||
2104
- exists(join$1(projectPath, 'astro.config.js'))) {
2105
- confidence += 25;
2106
- sources.push({ type: 'config-file', path: 'astro.config.*' });
1957
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2107
1958
  }
2108
- if (exists(join$1(projectPath, 'src', 'pages'))) {
1959
+ if (exists(join$1(projectPath, 'vue.config.js'))) {
2109
1960
  confidence += 5;
2110
- sources.push({ type: 'directory', path: 'src/pages/' });
1961
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
1962
+ }
1963
+ if (deps['nuxt'] || deps['nuxt3']) {
1964
+ metaFrameworks.push({
1965
+ id: 'nuxt',
1966
+ name: 'Nuxt',
1967
+ category: 'meta-framework',
1968
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1969
+ confidence: 90,
1970
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1971
+ });
2111
1972
  }
2112
1973
  if (confidence === 0) {
2113
1974
  return null;
2114
1975
  }
2115
1976
  return {
2116
- id: 'astro',
2117
- name: 'Astro',
2118
- category: 'meta-framework',
1977
+ id: 'vue',
1978
+ name: 'Vue',
1979
+ category: 'frontend',
2119
1980
  version,
2120
1981
  confidence: min(confidence, 100),
2121
1982
  detectedFrom: sources,
1983
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2122
1984
  };
2123
1985
  }
2124
1986
 
@@ -2143,6 +2005,17 @@ const frameworkDetectors = [
2143
2005
  * @param projectPath - Project directory path
2144
2006
  * @param packageJson - Optional pre-loaded package.json
2145
2007
  * @returns Array of detected frameworks, sorted by confidence
2008
+ *
2009
+ * @example Detecting multiple frontend frameworks
2010
+ * ```typescript
2011
+ * const frameworks = detectFrontendFrameworks('/path/to/nextjs-app', {
2012
+ * dependencies: { 'react': '^18.0.0', 'next': '^14.0.0' }
2013
+ * })
2014
+ * // => [
2015
+ * // { id: 'nextjs', name: 'Next.js', category: 'meta-framework', confidence: 70, ... },
2016
+ * // { id: 'react', name: 'React', category: 'frontend', confidence: 60, ... }
2017
+ * // ]
2018
+ * ```
2146
2019
  */
2147
2020
  function detectFrontendFrameworks(projectPath, packageJson) {
2148
2021
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2163,6 +2036,14 @@ function detectFrontendFrameworks(projectPath, packageJson) {
2163
2036
  * @param projectPath - Project directory path
2164
2037
  * @param packageJson - Optional pre-loaded package.json
2165
2038
  * @returns Detection result or null if not detected
2039
+ *
2040
+ * @example Detecting AngularJS framework
2041
+ * ```typescript
2042
+ * const result = angularJSDetector('/path/to/project', {
2043
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
2044
+ * })
2045
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
2046
+ * ```
2166
2047
  */
2167
2048
  function angularJSDetector(projectPath, packageJson) {
2168
2049
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2206,6 +2087,14 @@ function angularJSDetector(projectPath, packageJson) {
2206
2087
  * @param projectPath - Project directory path
2207
2088
  * @param packageJson - Optional pre-loaded package.json
2208
2089
  * @returns Detection result or null if not detected
2090
+ *
2091
+ * @example Detecting Backbone.js framework
2092
+ * ```typescript
2093
+ * const result = backboneDetector('/path/to/project', {
2094
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2095
+ * })
2096
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2097
+ * ```
2209
2098
  */
2210
2099
  function backboneDetector(projectPath, packageJson) {
2211
2100
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2249,6 +2138,15 @@ function backboneDetector(projectPath, packageJson) {
2249
2138
  * @param projectPath - Project directory path
2250
2139
  * @param packageJson - Optional pre-loaded package.json
2251
2140
  * @returns Detection result or null if not detected
2141
+ *
2142
+ * @example Detecting Ember.js framework
2143
+ * ```typescript
2144
+ * const result = emberDetector('/path/to/project', {
2145
+ * dependencies: { 'ember-source': '^4.0.0' },
2146
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2147
+ * })
2148
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2149
+ * ```
2252
2150
  */
2253
2151
  function emberDetector(projectPath, packageJson) {
2254
2152
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2288,6 +2186,14 @@ function emberDetector(projectPath, packageJson) {
2288
2186
  * @param projectPath - Project directory path
2289
2187
  * @param packageJson - Optional pre-loaded package.json
2290
2188
  * @returns Detection result or null if not detected
2189
+ *
2190
+ * @example Detecting jQuery library
2191
+ * ```typescript
2192
+ * const result = jqueryDetector('/path/to/project', {
2193
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2194
+ * })
2195
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2196
+ * ```
2291
2197
  */
2292
2198
  function jqueryDetector(projectPath, packageJson) {
2293
2199
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2321,32 +2227,90 @@ function jqueryDetector(projectPath, packageJson) {
2321
2227
  };
2322
2228
  }
2323
2229
 
2324
- /** All legacy framework detectors */
2325
- const legacyDetectors = [
2326
- { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2327
- { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2328
- { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2329
- { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2330
- ];
2331
- /**
2332
- * Detect all legacy frameworks in project.
2333
- *
2334
- * @param projectPath - Project directory path
2335
- * @param packageJson - Optional pre-loaded package.json
2336
- * @returns Array of detected legacy frameworks, sorted by confidence
2337
- */
2338
- function detectLegacyFrameworks(projectPath, packageJson) {
2339
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2340
- const results = [];
2341
- for (const detector of legacyDetectors) {
2342
- const detection = detector.detect(projectPath, pkg ?? undefined);
2343
- if (detection) {
2344
- results.push(detection);
2345
- }
2346
- }
2347
- return results.sort((a, b) => b.confidence - a.confidence);
2348
- }
2349
-
2230
+ /** All legacy framework detectors */
2231
+ const legacyDetectors = [
2232
+ { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2233
+ { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2234
+ { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2235
+ { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2236
+ ];
2237
+ /**
2238
+ * Detect all legacy frameworks in project.
2239
+ *
2240
+ * @param projectPath - Project directory path
2241
+ * @param packageJson - Optional pre-loaded package.json
2242
+ * @returns Array of detected legacy frameworks, sorted by confidence
2243
+ *
2244
+ * @example Detecting legacy frameworks
2245
+ * ```typescript
2246
+ * const results = detectLegacyFrameworks('/path/to/project', {
2247
+ * dependencies: { jquery: '^3.6.0', backbone: '^1.4.0' },
2248
+ * })
2249
+ * // => [{ id: 'jquery', confidence: 80 }, { id: 'backbone', confidence: 70 }]
2250
+ * ```
2251
+ */
2252
+ function detectLegacyFrameworks(projectPath, packageJson) {
2253
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2254
+ const results = [];
2255
+ for (const detector of legacyDetectors) {
2256
+ const detection = detector.detect(projectPath, pkg ?? undefined);
2257
+ if (detection) {
2258
+ results.push(detection);
2259
+ }
2260
+ }
2261
+ return results.sort((a, b) => b.confidence - a.confidence);
2262
+ }
2263
+
2264
+ /**
2265
+ * Detect Biome in project.
2266
+ *
2267
+ * @param projectPath - Project directory path
2268
+ * @param packageJson - Optional pre-loaded package.json
2269
+ * @returns Detection result or null if not detected
2270
+ *
2271
+ * @example Detecting Biome linter
2272
+ * ```typescript
2273
+ * const result = biomeDetector('/path/to/project', {
2274
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2275
+ * })
2276
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2277
+ * ```
2278
+ */
2279
+ function biomeDetector(projectPath, packageJson) {
2280
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2281
+ const sources = [];
2282
+ let confidence = 0;
2283
+ let configPath;
2284
+ let version;
2285
+ const deps = collectAllDependencies(pkg);
2286
+ if (deps['@biomejs/biome']) {
2287
+ confidence += 70;
2288
+ version = parseVersionString(deps['@biomejs/biome']);
2289
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2290
+ }
2291
+ if (exists(join$1(projectPath, 'biome.json'))) {
2292
+ confidence += 30;
2293
+ configPath = 'biome.json';
2294
+ sources.push({ type: 'config-file', path: 'biome.json' });
2295
+ }
2296
+ if (!configPath && exists(join$1(projectPath, 'biome.jsonc'))) {
2297
+ confidence += 30;
2298
+ configPath = 'biome.jsonc';
2299
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2300
+ }
2301
+ if (confidence === 0) {
2302
+ return null;
2303
+ }
2304
+ return {
2305
+ id: 'biome',
2306
+ name: 'Biome',
2307
+ version,
2308
+ configPath,
2309
+ confidence: min(confidence, 100),
2310
+ detectedFrom: sources,
2311
+ };
2312
+ }
2313
+
2350
2314
  /** Config patterns for ESLint */
2351
2315
  const ESLINT_CONFIG_PATTERNS = [
2352
2316
  'eslint.config.js',
@@ -2366,6 +2330,15 @@ const ESLINT_CONFIG_PATTERNS = [
2366
2330
  * @param projectPath - Project directory path
2367
2331
  * @param packageJson - Optional pre-loaded package.json
2368
2332
  * @returns Detection result or null if not detected
2333
+ *
2334
+ * @example Detecting ESLint linter
2335
+ * ```typescript
2336
+ * const result = eslintDetector('/path/to/project', {
2337
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2338
+ * scripts: { lint: 'eslint src/' },
2339
+ * })
2340
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2341
+ * ```
2369
2342
  */
2370
2343
  function eslintDetector(projectPath, packageJson) {
2371
2344
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2429,6 +2402,15 @@ const PRETTIER_CONFIG_PATTERNS = [
2429
2402
  * @param projectPath - Project directory path
2430
2403
  * @param packageJson - Optional pre-loaded package.json
2431
2404
  * @returns Detection result or null if not detected
2405
+ *
2406
+ * @example Detecting Prettier formatter
2407
+ * ```typescript
2408
+ * const result = prettierDetector('/path/to/project', {
2409
+ * devDependencies: { prettier: '^3.0.0' },
2410
+ * scripts: { format: 'prettier --write .' },
2411
+ * })
2412
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2413
+ * ```
2432
2414
  */
2433
2415
  function prettierDetector(projectPath, packageJson) {
2434
2416
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2491,6 +2473,14 @@ const STYLELINT_CONFIG_PATTERNS = [
2491
2473
  * @param projectPath - Project directory path
2492
2474
  * @param packageJson - Optional pre-loaded package.json
2493
2475
  * @returns Detection result or null if not detected
2476
+ *
2477
+ * @example Detecting Stylelint linter
2478
+ * ```typescript
2479
+ * const result = stylelintDetector('/path/to/project', {
2480
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
2481
+ * })
2482
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
2483
+ * ```
2494
2484
  */
2495
2485
  function stylelintDetector(projectPath, packageJson) {
2496
2486
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2530,48 +2520,6 @@ function stylelintDetector(projectPath, packageJson) {
2530
2520
  };
2531
2521
  }
2532
2522
 
2533
- /**
2534
- * Detect Biome in project.
2535
- *
2536
- * @param projectPath - Project directory path
2537
- * @param packageJson - Optional pre-loaded package.json
2538
- * @returns Detection result or null if not detected
2539
- */
2540
- function biomeDetector(projectPath, packageJson) {
2541
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2542
- const sources = [];
2543
- let confidence = 0;
2544
- let configPath;
2545
- let version;
2546
- const deps = collectAllDependencies(pkg);
2547
- if (deps['@biomejs/biome']) {
2548
- confidence += 70;
2549
- version = parseVersionString(deps['@biomejs/biome']);
2550
- sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2551
- }
2552
- if (exists(join$1(projectPath, 'biome.json'))) {
2553
- confidence += 30;
2554
- configPath = 'biome.json';
2555
- sources.push({ type: 'config-file', path: 'biome.json' });
2556
- }
2557
- if (!configPath && exists(join$1(projectPath, 'biome.jsonc'))) {
2558
- confidence += 30;
2559
- configPath = 'biome.jsonc';
2560
- sources.push({ type: 'config-file', path: 'biome.jsonc' });
2561
- }
2562
- if (confidence === 0) {
2563
- return null;
2564
- }
2565
- return {
2566
- id: 'biome',
2567
- name: 'Biome',
2568
- version,
2569
- configPath,
2570
- confidence: min(confidence, 100),
2571
- detectedFrom: sources,
2572
- };
2573
- }
2574
-
2575
2523
  /** All linting tool detectors */
2576
2524
  const lintingDetectors = [
2577
2525
  { id: 'eslint', name: 'ESLint', detect: eslintDetector },
@@ -2585,6 +2533,14 @@ const lintingDetectors = [
2585
2533
  * @param projectPath - Project directory path
2586
2534
  * @param packageJson - Optional pre-loaded package.json
2587
2535
  * @returns Array of detected linting tools, sorted by confidence
2536
+ *
2537
+ * @example Detecting multiple linting tools
2538
+ * ```typescript
2539
+ * const results = detectLintingTools('/path/to/project', {
2540
+ * devDependencies: { eslint: '^8.0.0', prettier: '^3.0.0' },
2541
+ * })
2542
+ * // => [{ id: 'eslint', confidence: 50 }, { id: 'prettier', confidence: 50 }]
2543
+ * ```
2588
2544
  */
2589
2545
  function detectLintingTools(projectPath, packageJson) {
2590
2546
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2599,140 +2555,179 @@ function detectLintingTools(projectPath, packageJson) {
2599
2555
  }
2600
2556
 
2601
2557
  /**
2602
- * Detect NX in project.
2558
+ * Detect Lerna in project.
2603
2559
  *
2604
2560
  * @param workspacePath - Workspace directory path
2605
2561
  * @param packageJson - Optional pre-loaded package.json
2606
2562
  * @returns Detection result or null if not detected
2563
+ *
2564
+ * @example Detecting Lerna monorepo
2565
+ * ```typescript
2566
+ * // Project with lerna.json config file
2567
+ * const result = lernaDetector('/path/to/lerna-project')
2568
+ * // => {
2569
+ * // id: 'lerna',
2570
+ * // name: 'Lerna',
2571
+ * // confidence: 80,
2572
+ * // configPath: 'lerna.json',
2573
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
2574
+ * // }
2575
+ * ```
2607
2576
  */
2608
- function nxDetector(workspacePath, packageJson) {
2577
+ function lernaDetector(workspacePath, packageJson) {
2609
2578
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2610
2579
  const sources = [];
2611
2580
  let confidence = 0;
2612
2581
  let version;
2613
- let workspaceLayout;
2614
- const nxJsonPath = join$1(workspacePath, 'nx.json');
2615
- if (exists(nxJsonPath)) {
2616
- confidence += 70;
2617
- sources.push({ type: 'config-file', path: 'nx.json' });
2582
+ let configPath;
2583
+ const lernaJsonPath = join$1(workspacePath, 'lerna.json');
2584
+ if (exists(lernaJsonPath)) {
2585
+ confidence += 80;
2586
+ configPath = 'lerna.json';
2587
+ sources.push({ type: 'config-file', path: 'lerna.json' });
2618
2588
  }
2619
2589
  const deps = collectAllDependencies(pkg);
2620
- if (deps['nx']) {
2621
- confidence += 20;
2622
- version = parseVersionString(deps['nx']);
2623
- sources.push({ type: 'package.json', field: 'dependencies.nx' });
2624
- }
2625
- const hasApps = exists(join$1(workspacePath, 'apps'));
2626
- const hasLibs = exists(join$1(workspacePath, 'libs'));
2627
- if (hasApps || hasLibs) {
2628
- confidence += 10;
2629
- sources.push({ type: 'directory', path: 'apps/ or libs/' });
2630
- workspaceLayout = {
2631
- appsDir: hasApps ? 'apps' : '',
2632
- libsDir: hasLibs ? 'libs' : '',
2633
- };
2590
+ if (deps['lerna']) {
2591
+ confidence += 15;
2592
+ version = parseVersionString(deps['lerna']);
2593
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2634
2594
  }
2635
- const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2636
- if (nxPackages.length > 0) {
2637
- confidence += 10;
2638
- sources.push({ type: 'package.json', field: '@nx/* packages' });
2595
+ if (exists(join$1(workspacePath, 'packages'))) {
2596
+ confidence += 5;
2597
+ sources.push({ type: 'directory', path: 'packages/' });
2639
2598
  }
2640
2599
  if (confidence === 0) {
2641
2600
  return null;
2642
2601
  }
2643
2602
  return {
2644
- id: 'nx',
2645
- name: 'NX',
2603
+ id: 'lerna',
2604
+ name: 'Lerna',
2646
2605
  version,
2647
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2606
+ configPath,
2648
2607
  confidence: min(confidence, 100),
2649
2608
  detectedFrom: sources,
2650
- workspaceLayout,
2651
2609
  };
2652
2610
  }
2653
2611
 
2654
2612
  /**
2655
- * Detect Turborepo in project.
2613
+ * Detect npm workspaces in project.
2656
2614
  *
2657
2615
  * @param workspacePath - Workspace directory path
2658
2616
  * @param packageJson - Optional pre-loaded package.json
2659
2617
  * @returns Detection result or null if not detected
2618
+ *
2619
+ * @example Detecting npm workspaces
2620
+ * ```typescript
2621
+ * // Project with workspaces in package.json and package-lock.json
2622
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
2623
+ * // => {
2624
+ * // id: 'npm-workspaces',
2625
+ * // name: 'npm Workspaces',
2626
+ * // confidence: 90,
2627
+ * // configPath: 'package.json',
2628
+ * // detectedFrom: [
2629
+ * // { type: 'package.json', field: 'workspaces' },
2630
+ * // { type: 'lockfile', path: 'package-lock.json' }
2631
+ * // ]
2632
+ * // }
2633
+ * ```
2660
2634
  */
2661
- function turborepoDetector(workspacePath, packageJson) {
2635
+ function npmWorkspacesDetector(workspacePath, packageJson) {
2662
2636
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2663
2637
  const sources = [];
2664
2638
  let confidence = 0;
2665
- let version;
2666
- let configPath;
2667
- const turboJsonPath = join$1(workspacePath, 'turbo.json');
2668
- if (exists(turboJsonPath)) {
2639
+ if (pkg?.workspaces) {
2669
2640
  confidence += 80;
2670
- configPath = 'turbo.json';
2671
- sources.push({ type: 'config-file', path: 'turbo.json' });
2641
+ sources.push({ type: 'package.json', field: 'workspaces' });
2672
2642
  }
2673
- const deps = collectAllDependencies(pkg);
2674
- if (deps['turbo']) {
2675
- confidence += 15;
2676
- version = parseVersionString(deps['turbo']);
2677
- sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2643
+ if (exists(join$1(workspacePath, 'package-lock.json'))) {
2644
+ confidence += 10;
2645
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
2678
2646
  }
2679
- const scripts = pkg?.scripts ?? {};
2680
- if (values(scripts).some((s) => s?.includes('turbo'))) {
2681
- confidence += 5;
2682
- sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2647
+ if (exists(join$1(workspacePath, 'yarn.lock'))) {
2648
+ return null;
2683
2649
  }
2684
2650
  if (confidence === 0) {
2685
2651
  return null;
2686
2652
  }
2687
2653
  return {
2688
- id: 'turborepo',
2689
- name: 'Turborepo',
2690
- version,
2691
- configPath,
2654
+ id: 'npm-workspaces',
2655
+ name: 'npm Workspaces',
2656
+ configPath: 'package.json',
2692
2657
  confidence: min(confidence, 100),
2693
2658
  detectedFrom: sources,
2694
2659
  };
2695
2660
  }
2696
2661
 
2697
2662
  /**
2698
- * Detect Lerna in project.
2663
+ * Detect NX in project.
2699
2664
  *
2700
2665
  * @param workspacePath - Workspace directory path
2701
2666
  * @param packageJson - Optional pre-loaded package.json
2702
2667
  * @returns Detection result or null if not detected
2668
+ *
2669
+ * @example Detecting NX workspace
2670
+ * ```typescript
2671
+ * // Project with nx.json and apps/libs directories
2672
+ * const result = nxDetector('/path/to/nx-workspace')
2673
+ * // => {
2674
+ * // id: 'nx',
2675
+ * // name: 'NX',
2676
+ * // confidence: 100,
2677
+ * // configPath: 'nx.json',
2678
+ * // version: '17.0.0',
2679
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
2680
+ * // detectedFrom: [
2681
+ * // { type: 'config-file', path: 'nx.json' },
2682
+ * // { type: 'package.json', field: 'dependencies.nx' },
2683
+ * // { type: 'directory', path: 'apps/ or libs/' }
2684
+ * // ]
2685
+ * // }
2686
+ * ```
2703
2687
  */
2704
- function lernaDetector(workspacePath, packageJson) {
2688
+ function nxDetector(workspacePath, packageJson) {
2705
2689
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2706
2690
  const sources = [];
2707
2691
  let confidence = 0;
2708
2692
  let version;
2709
- let configPath;
2710
- const lernaJsonPath = join$1(workspacePath, 'lerna.json');
2711
- if (exists(lernaJsonPath)) {
2712
- confidence += 80;
2713
- configPath = 'lerna.json';
2714
- sources.push({ type: 'config-file', path: 'lerna.json' });
2693
+ let workspaceLayout;
2694
+ const nxJsonPath = join$1(workspacePath, 'nx.json');
2695
+ if (exists(nxJsonPath)) {
2696
+ confidence += 70;
2697
+ sources.push({ type: 'config-file', path: 'nx.json' });
2715
2698
  }
2716
2699
  const deps = collectAllDependencies(pkg);
2717
- if (deps['lerna']) {
2718
- confidence += 15;
2719
- version = parseVersionString(deps['lerna']);
2720
- sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2700
+ if (deps['nx']) {
2701
+ confidence += 20;
2702
+ version = parseVersionString(deps['nx']);
2703
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
2721
2704
  }
2722
- if (exists(join$1(workspacePath, 'packages'))) {
2723
- confidence += 5;
2724
- sources.push({ type: 'directory', path: 'packages/' });
2705
+ const hasApps = exists(join$1(workspacePath, 'apps'));
2706
+ const hasLibs = exists(join$1(workspacePath, 'libs'));
2707
+ if (hasApps || hasLibs) {
2708
+ confidence += 10;
2709
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
2710
+ workspaceLayout = {
2711
+ appsDir: hasApps ? 'apps' : '',
2712
+ libsDir: hasLibs ? 'libs' : '',
2713
+ };
2714
+ }
2715
+ const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2716
+ if (nxPackages.length > 0) {
2717
+ confidence += 10;
2718
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
2725
2719
  }
2726
2720
  if (confidence === 0) {
2727
2721
  return null;
2728
2722
  }
2729
2723
  return {
2730
- id: 'lerna',
2731
- name: 'Lerna',
2724
+ id: 'nx',
2725
+ name: 'NX',
2732
2726
  version,
2733
- configPath,
2727
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2734
2728
  confidence: min(confidence, 100),
2735
2729
  detectedFrom: sources,
2730
+ workspaceLayout,
2736
2731
  };
2737
2732
  }
2738
2733
 
@@ -2742,6 +2737,19 @@ function lernaDetector(workspacePath, packageJson) {
2742
2737
  * @param workspacePath - Workspace directory path
2743
2738
  * @param packageJson - Optional pre-loaded package.json
2744
2739
  * @returns Detection result or null if not detected
2740
+ *
2741
+ * @example Detecting Rush monorepo
2742
+ * ```typescript
2743
+ * // Project with rush.json config file
2744
+ * const result = rushDetector('/path/to/rush-project')
2745
+ * // => {
2746
+ * // id: 'rush',
2747
+ * // name: 'Rush',
2748
+ * // confidence: 90,
2749
+ * // configPath: 'rush.json',
2750
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
2751
+ * // }
2752
+ * ```
2745
2753
  */
2746
2754
  function rushDetector(workspacePath, packageJson) {
2747
2755
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2779,66 +2787,60 @@ function rushDetector(workspacePath, packageJson) {
2779
2787
  }
2780
2788
 
2781
2789
  /**
2782
- * Detect pnpm workspaces in project.
2783
- *
2784
- * @param workspacePath - Workspace directory path
2785
- * @returns Detection result or null if not detected
2786
- */
2787
- function pnpmWorkspacesDetector(workspacePath) {
2788
- const sources = [];
2789
- let confidence = 0;
2790
- let configPath;
2791
- const pnpmWorkspacePath = join$1(workspacePath, 'pnpm-workspace.yaml');
2792
- if (exists(pnpmWorkspacePath)) {
2793
- confidence += 90;
2794
- configPath = 'pnpm-workspace.yaml';
2795
- sources.push({ type: 'config-file', path: 'pnpm-workspace.yaml' });
2796
- }
2797
- if (exists(join$1(workspacePath, 'pnpm-lock.yaml'))) {
2798
- confidence += 10;
2799
- sources.push({ type: 'lockfile', path: 'pnpm-lock.yaml' });
2800
- }
2801
- if (confidence === 0) {
2802
- return null;
2803
- }
2804
- return {
2805
- id: 'pnpm-workspaces',
2806
- name: 'pnpm Workspaces',
2807
- configPath,
2808
- confidence: min(confidence, 100),
2809
- detectedFrom: sources,
2810
- };
2811
- }
2812
-
2813
- /**
2814
- * Detect npm workspaces in project.
2790
+ * Detect Turborepo in project.
2815
2791
  *
2816
2792
  * @param workspacePath - Workspace directory path
2817
2793
  * @param packageJson - Optional pre-loaded package.json
2818
2794
  * @returns Detection result or null if not detected
2795
+ *
2796
+ * @example Detecting Turborepo monorepo
2797
+ * ```typescript
2798
+ * // Project with turbo.json and turbo dependency
2799
+ * const result = turborepoDetector('/path/to/turbo-project')
2800
+ * // => {
2801
+ * // id: 'turborepo',
2802
+ * // name: 'Turborepo',
2803
+ * // confidence: 95,
2804
+ * // configPath: 'turbo.json',
2805
+ * // version: '2.0.0',
2806
+ * // detectedFrom: [
2807
+ * // { type: 'config-file', path: 'turbo.json' },
2808
+ * // { type: 'package.json', field: 'dependencies.turbo' }
2809
+ * // ]
2810
+ * // }
2811
+ * ```
2819
2812
  */
2820
- function npmWorkspacesDetector(workspacePath, packageJson) {
2813
+ function turborepoDetector(workspacePath, packageJson) {
2821
2814
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2822
2815
  const sources = [];
2823
2816
  let confidence = 0;
2824
- if (pkg?.workspaces) {
2817
+ let version;
2818
+ let configPath;
2819
+ const turboJsonPath = join$1(workspacePath, 'turbo.json');
2820
+ if (exists(turboJsonPath)) {
2825
2821
  confidence += 80;
2826
- sources.push({ type: 'package.json', field: 'workspaces' });
2822
+ configPath = 'turbo.json';
2823
+ sources.push({ type: 'config-file', path: 'turbo.json' });
2827
2824
  }
2828
- if (exists(join$1(workspacePath, 'package-lock.json'))) {
2829
- confidence += 10;
2830
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
2825
+ const deps = collectAllDependencies(pkg);
2826
+ if (deps['turbo']) {
2827
+ confidence += 15;
2828
+ version = parseVersionString(deps['turbo']);
2829
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2831
2830
  }
2832
- if (exists(join$1(workspacePath, 'yarn.lock'))) {
2833
- return null;
2831
+ const scripts = pkg?.scripts ?? {};
2832
+ if (values(scripts).some((s) => s?.includes('turbo'))) {
2833
+ confidence += 5;
2834
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2834
2835
  }
2835
2836
  if (confidence === 0) {
2836
2837
  return null;
2837
2838
  }
2838
2839
  return {
2839
- id: 'npm-workspaces',
2840
- name: 'npm Workspaces',
2841
- configPath: 'package.json',
2840
+ id: 'turborepo',
2841
+ name: 'Turborepo',
2842
+ version,
2843
+ configPath,
2842
2844
  confidence: min(confidence, 100),
2843
2845
  detectedFrom: sources,
2844
2846
  };
@@ -2850,6 +2852,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
2850
2852
  * @param workspacePath - Workspace directory path
2851
2853
  * @param packageJson - Optional pre-loaded package.json
2852
2854
  * @returns Detection result or null if not detected
2855
+ *
2856
+ * @example Detecting yarn workspaces
2857
+ * ```typescript
2858
+ * // Project with workspaces in package.json and yarn.lock
2859
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
2860
+ * // => {
2861
+ * // id: 'yarn-workspaces',
2862
+ * // name: 'Yarn Workspaces',
2863
+ * // confidence: 100,
2864
+ * // configPath: 'package.json',
2865
+ * // detectedFrom: [
2866
+ * // { type: 'package.json', field: 'workspaces' },
2867
+ * // { type: 'lockfile', path: 'yarn.lock' },
2868
+ * // { type: 'config-file', path: '.yarnrc.yml' }
2869
+ * // ]
2870
+ * // }
2871
+ * ```
2853
2872
  */
2854
2873
  function yarnWorkspacesDetector(workspacePath, packageJson) {
2855
2874
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2895,6 +2914,15 @@ const monorepoDetectors = [
2895
2914
  * @param workspacePath - Workspace directory path
2896
2915
  * @param packageJson - Optional pre-loaded package.json
2897
2916
  * @returns Array of detected monorepo tools, sorted by confidence
2917
+ *
2918
+ * @example Detecting monorepo tools
2919
+ * ```typescript
2920
+ * const detections = detectMonorepoTools('/path/to/project')
2921
+ * // => [
2922
+ * // { id: 'nx', name: 'NX', confidence: 90, configPath: 'nx.json', detectedFrom: [...] },
2923
+ * // { id: 'npm-workspaces', name: 'npm Workspaces', confidence: 80, ... }
2924
+ * // ]
2925
+ * ```
2898
2926
  */
2899
2927
  function detectMonorepoTools(workspacePath, packageJson) {
2900
2928
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2908,55 +2936,58 @@ function detectMonorepoTools(workspacePath, packageJson) {
2908
2936
  return results.sort((a, b) => b.confidence - a.confidence);
2909
2937
  }
2910
2938
 
2911
- /** Config patterns for Jest */
2912
- const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2939
+ /** Config patterns for Cypress */
2940
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2913
2941
  /**
2914
- * Detect Jest in project.
2942
+ * Detect Cypress in project.
2915
2943
  *
2916
2944
  * @param projectPath - Project directory path
2917
2945
  * @param packageJson - Optional pre-loaded package.json
2918
2946
  * @returns Detection result or null if not detected
2947
+ *
2948
+ * @example Detecting Cypress testing framework
2949
+ * ```typescript
2950
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
2951
+ *
2952
+ * const result = cypressDetector('./my-project')
2953
+ * if (result) {
2954
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
2955
+ * // => "Cypress 13.6.0 detected (95% confidence)"
2956
+ * }
2957
+ * ```
2919
2958
  */
2920
- function jestDetector(projectPath, packageJson) {
2959
+ function cypressDetector(projectPath, packageJson) {
2921
2960
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2922
2961
  const sources = [];
2923
2962
  let confidence = 0;
2924
2963
  let version;
2925
2964
  const deps = collectAllDependencies(pkg);
2926
- if (deps['jest']) {
2965
+ if (deps['cypress']) {
2927
2966
  confidence += 60;
2928
- version = parseVersionString(deps['jest']);
2929
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
2967
+ version = parseVersionString(deps['cypress']);
2968
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2930
2969
  }
2931
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2970
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2932
2971
  if (configPath) {
2933
2972
  confidence += 30;
2934
2973
  sources.push({ type: 'config-file', path: configPath });
2935
2974
  }
2936
- if (pkg && 'jest' in pkg) {
2937
- confidence += 20;
2938
- sources.push({ type: 'package.json', field: 'jest' });
2939
- }
2940
- const testScript = pkg?.scripts?.['test'] ?? '';
2941
- if (testScript.includes('jest')) {
2975
+ if (exists(join$1(projectPath, 'cypress'))) {
2942
2976
  confidence += 10;
2943
- sources.push({ type: 'package.json', field: 'scripts.test' });
2944
- }
2945
- if (deps['@types/jest']) {
2946
- confidence += 5;
2947
- sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2977
+ sources.push({ type: 'directory', path: 'cypress/' });
2948
2978
  }
2949
- if (deps['ts-jest']) {
2979
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2980
+ if (e2eScript.includes('cypress')) {
2950
2981
  confidence += 5;
2951
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2982
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2952
2983
  }
2953
2984
  if (confidence === 0) {
2954
2985
  return null;
2955
2986
  }
2956
2987
  return {
2957
- id: 'jest',
2958
- name: 'Jest',
2959
- type: 'unit',
2988
+ id: 'cypress',
2989
+ name: 'Cypress',
2990
+ type: 'e2e',
2960
2991
  version,
2961
2992
  configPath,
2962
2993
  confidence: min(confidence, 100),
@@ -2964,51 +2995,66 @@ function jestDetector(projectPath, packageJson) {
2964
2995
  };
2965
2996
  }
2966
2997
 
2967
- /** Config patterns for Vitest */
2968
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
2998
+ /** Config patterns for Jest */
2999
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2969
3000
  /**
2970
- * Detect Vitest in project.
3001
+ * Detect Jest in project.
2971
3002
  *
2972
3003
  * @param projectPath - Project directory path
2973
3004
  * @param packageJson - Optional pre-loaded package.json
2974
3005
  * @returns Detection result or null if not detected
3006
+ *
3007
+ * @example Detecting Jest testing framework
3008
+ * ```typescript
3009
+ * import { jestDetector } from '@hyperfrontend/project-scope'
3010
+ *
3011
+ * const result = jestDetector('./my-project')
3012
+ * if (result) {
3013
+ * console.log(`Jest ${result.version} detected`)
3014
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
3015
+ * // => "Sources: ['package.json', 'config-file']"
3016
+ * }
3017
+ * ```
2975
3018
  */
2976
- function vitestDetector(projectPath, packageJson) {
3019
+ function jestDetector(projectPath, packageJson) {
2977
3020
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2978
3021
  const sources = [];
2979
3022
  let confidence = 0;
2980
3023
  let version;
2981
3024
  const deps = collectAllDependencies(pkg);
2982
- if (deps['vitest']) {
2983
- confidence += 70;
2984
- version = parseVersionString(deps['vitest']);
2985
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3025
+ if (deps['jest']) {
3026
+ confidence += 60;
3027
+ version = parseVersionString(deps['jest']);
3028
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
2986
3029
  }
2987
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3030
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2988
3031
  if (configPath) {
2989
- confidence += 25;
3032
+ confidence += 30;
2990
3033
  sources.push({ type: 'config-file', path: configPath });
2991
3034
  }
2992
- if (!configPath) {
2993
- const viteConfig = exists(join$1(projectPath, 'vite.config.ts')) ||
2994
- exists(join$1(projectPath, 'vite.config.js')) ||
2995
- exists(join$1(projectPath, 'vite.config.mjs'));
2996
- if (viteConfig && deps['vitest']) {
2997
- confidence += 5;
2998
- sources.push({ type: 'config-file', path: 'vite.config.*' });
2999
- }
3035
+ if (pkg && 'jest' in pkg) {
3036
+ confidence += 20;
3037
+ sources.push({ type: 'package.json', field: 'jest' });
3000
3038
  }
3001
3039
  const testScript = pkg?.scripts?.['test'] ?? '';
3002
- if (testScript.includes('vitest')) {
3040
+ if (testScript.includes('jest')) {
3003
3041
  confidence += 10;
3004
3042
  sources.push({ type: 'package.json', field: 'scripts.test' });
3005
3043
  }
3044
+ if (deps['@types/jest']) {
3045
+ confidence += 5;
3046
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
3047
+ }
3048
+ if (deps['ts-jest']) {
3049
+ confidence += 5;
3050
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3051
+ }
3006
3052
  if (confidence === 0) {
3007
3053
  return null;
3008
3054
  }
3009
3055
  return {
3010
- id: 'vitest',
3011
- name: 'Vitest',
3056
+ id: 'jest',
3057
+ name: 'Jest',
3012
3058
  type: 'unit',
3013
3059
  version,
3014
3060
  configPath,
@@ -3025,6 +3071,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
3025
3071
  * @param projectPath - Project directory path
3026
3072
  * @param packageJson - Optional pre-loaded package.json
3027
3073
  * @returns Detection result or null if not detected
3074
+ *
3075
+ * @example Detecting Mocha testing framework
3076
+ * ```typescript
3077
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
3078
+ *
3079
+ * const result = mochaDetector('./my-project')
3080
+ * if (result) {
3081
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
3082
+ * // => "Mocha 10.2.0 detected (95%)"
3083
+ * }
3084
+ * ```
3028
3085
  */
3029
3086
  function mochaDetector(projectPath, packageJson) {
3030
3087
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3069,37 +3126,53 @@ function mochaDetector(projectPath, packageJson) {
3069
3126
  };
3070
3127
  }
3071
3128
 
3072
- /** Config patterns for Cypress */
3073
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3129
+ /** Config patterns for Playwright */
3130
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3074
3131
  /**
3075
- * Detect Cypress in project.
3132
+ * Detect Playwright in project.
3076
3133
  *
3077
3134
  * @param projectPath - Project directory path
3078
3135
  * @param packageJson - Optional pre-loaded package.json
3079
3136
  * @returns Detection result or null if not detected
3137
+ *
3138
+ * @example Detecting Playwright testing framework
3139
+ * ```typescript
3140
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
3141
+ *
3142
+ * const result = playwrightDetector('./my-project')
3143
+ * if (result) {
3144
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
3145
+ * // => "Playwright 1.42.0 (e2e tests)"
3146
+ * }
3147
+ * ```
3080
3148
  */
3081
- function cypressDetector(projectPath, packageJson) {
3149
+ function playwrightDetector(projectPath, packageJson) {
3082
3150
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3083
3151
  const sources = [];
3084
3152
  let confidence = 0;
3085
3153
  let version;
3086
3154
  const deps = collectAllDependencies(pkg);
3087
- if (deps['cypress']) {
3088
- confidence += 60;
3089
- version = parseVersionString(deps['cypress']);
3090
- sources.push({ type: 'package.json', field: 'dependencies.cypress' });
3155
+ if (deps['@playwright/test']) {
3156
+ confidence += 70;
3157
+ version = parseVersionString(deps['@playwright/test']);
3158
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3091
3159
  }
3092
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3160
+ if (deps['playwright']) {
3161
+ confidence += 50;
3162
+ version = version ?? parseVersionString(deps['playwright']);
3163
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3164
+ }
3165
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3093
3166
  if (configPath) {
3094
- confidence += 30;
3167
+ confidence += 25;
3095
3168
  sources.push({ type: 'config-file', path: configPath });
3096
3169
  }
3097
- if (exists(join$1(projectPath, 'cypress'))) {
3098
- confidence += 10;
3099
- sources.push({ type: 'directory', path: 'cypress/' });
3170
+ if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3171
+ confidence += 5;
3172
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3100
3173
  }
3101
3174
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3102
- if (e2eScript.includes('cypress')) {
3175
+ if (e2eScript.includes('playwright')) {
3103
3176
  confidence += 5;
3104
3177
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3105
3178
  }
@@ -3107,8 +3180,8 @@ function cypressDetector(projectPath, packageJson) {
3107
3180
  return null;
3108
3181
  }
3109
3182
  return {
3110
- id: 'cypress',
3111
- name: 'Cypress',
3183
+ id: 'playwright',
3184
+ name: 'Playwright',
3112
3185
  type: 'e2e',
3113
3186
  version,
3114
3187
  configPath,
@@ -3117,52 +3190,64 @@ function cypressDetector(projectPath, packageJson) {
3117
3190
  };
3118
3191
  }
3119
3192
 
3120
- /** Config patterns for Playwright */
3121
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3193
+ /** Config patterns for Vitest */
3194
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3122
3195
  /**
3123
- * Detect Playwright in project.
3196
+ * Detect Vitest in project.
3124
3197
  *
3125
3198
  * @param projectPath - Project directory path
3126
3199
  * @param packageJson - Optional pre-loaded package.json
3127
3200
  * @returns Detection result or null if not detected
3201
+ *
3202
+ * @example Detecting Vitest testing framework
3203
+ * ```typescript
3204
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3205
+ *
3206
+ * const result = vitestDetector('./my-project')
3207
+ * if (result) {
3208
+ * console.log(`Vitest ${result.version} detected`)
3209
+ * console.log('Config:', result.configPath)
3210
+ * // => "Config: vitest.config.ts"
3211
+ * }
3212
+ * ```
3128
3213
  */
3129
- function playwrightDetector(projectPath, packageJson) {
3214
+ function vitestDetector(projectPath, packageJson) {
3130
3215
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3131
3216
  const sources = [];
3132
3217
  let confidence = 0;
3133
3218
  let version;
3134
3219
  const deps = collectAllDependencies(pkg);
3135
- if (deps['@playwright/test']) {
3220
+ if (deps['vitest']) {
3136
3221
  confidence += 70;
3137
- version = parseVersionString(deps['@playwright/test']);
3138
- sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3139
- }
3140
- if (deps['playwright']) {
3141
- confidence += 50;
3142
- version = version ?? parseVersionString(deps['playwright']);
3143
- sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3222
+ version = parseVersionString(deps['vitest']);
3223
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3144
3224
  }
3145
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3225
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3146
3226
  if (configPath) {
3147
3227
  confidence += 25;
3148
3228
  sources.push({ type: 'config-file', path: configPath });
3149
3229
  }
3150
- if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3151
- confidence += 5;
3152
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3230
+ if (!configPath) {
3231
+ const viteConfig = exists(join$1(projectPath, 'vite.config.ts')) ||
3232
+ exists(join$1(projectPath, 'vite.config.js')) ||
3233
+ exists(join$1(projectPath, 'vite.config.mjs'));
3234
+ if (viteConfig && deps['vitest']) {
3235
+ confidence += 5;
3236
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3237
+ }
3153
3238
  }
3154
- const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3155
- if (e2eScript.includes('playwright')) {
3156
- confidence += 5;
3157
- sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3239
+ const testScript = pkg?.scripts?.['test'] ?? '';
3240
+ if (testScript.includes('vitest')) {
3241
+ confidence += 10;
3242
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3158
3243
  }
3159
3244
  if (confidence === 0) {
3160
3245
  return null;
3161
3246
  }
3162
3247
  return {
3163
- id: 'playwright',
3164
- name: 'Playwright',
3165
- type: 'e2e',
3248
+ id: 'vitest',
3249
+ name: 'Vitest',
3250
+ type: 'unit',
3166
3251
  version,
3167
3252
  configPath,
3168
3253
  confidence: min(confidence, 100),
@@ -3184,6 +3269,21 @@ const testingDetectors = [
3184
3269
  * @param projectPath - Project directory path
3185
3270
  * @param packageJson - Optional pre-loaded package.json
3186
3271
  * @returns Array of detected testing frameworks, sorted by confidence
3272
+ *
3273
+ * @example Detecting multiple testing frameworks
3274
+ * ```typescript
3275
+ * import { detectTestingFrameworks } from '@hyperfrontend/project-scope'
3276
+ *
3277
+ * const frameworks = detectTestingFrameworks('./my-project')
3278
+ * // => [
3279
+ * // { id: 'jest', name: 'Jest', type: 'unit', confidence: 95, ... },
3280
+ * // { id: 'cypress', name: 'Cypress', type: 'e2e', confidence: 85, ... }
3281
+ * // ]
3282
+ *
3283
+ * // Results are sorted by confidence (highest first)
3284
+ * const primary = frameworks[0]?.name ?? 'None'
3285
+ * console.log(`Primary testing framework: ${primary}`)
3286
+ * ```
3187
3287
  */
3188
3288
  function detectTestingFrameworks(projectPath, packageJson) {
3189
3289
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3223,6 +3323,19 @@ function checkTsConfigStrict(projectPath) {
3223
3323
  * @param projectPath - Project directory path
3224
3324
  * @param packageJson - Optional pre-loaded package.json
3225
3325
  * @returns Detection result or null if not detected
3326
+ *
3327
+ * @example Detecting TypeScript
3328
+ * ```typescript
3329
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3330
+ *
3331
+ * const result = typescriptDetector('./my-project')
3332
+ * if (result) {
3333
+ * console.log(`TypeScript ${result.version}`)
3334
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3335
+ * // => "TypeScript 5.3.0"
3336
+ * // => "Strict mode: true"
3337
+ * }
3338
+ * ```
3226
3339
  */
3227
3340
  function typescriptDetector(projectPath, packageJson) {
3228
3341
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3274,6 +3387,17 @@ function typescriptDetector(projectPath, packageJson) {
3274
3387
  * @param projectPath - Project directory path
3275
3388
  * @param packageJson - Optional pre-loaded package.json
3276
3389
  * @returns Detection result or null if not detected
3390
+ *
3391
+ * @example Detecting Flow type system
3392
+ * ```typescript
3393
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3394
+ *
3395
+ * const result = flowDetector('./my-project')
3396
+ * if (result) {
3397
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3398
+ * // => "Flow 0.232.0 with config: .flowconfig"
3399
+ * }
3400
+ * ```
3277
3401
  */
3278
3402
  function flowDetector(projectPath, packageJson) {
3279
3403
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3331,6 +3455,18 @@ function hasJsDocTypes(content) {
3331
3455
  * @param projectPath - Project directory path
3332
3456
  * @param packageJson - Optional pre-loaded package.json
3333
3457
  * @returns Detection result or null if not detected
3458
+ *
3459
+ * @example Detecting JSDoc type annotations
3460
+ * ```typescript
3461
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3462
+ *
3463
+ * const result = jsdocDetector('./my-project')
3464
+ * if (result) {
3465
+ * console.log('JSDoc types detected')
3466
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3467
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3468
+ * }
3469
+ * ```
3334
3470
  */
3335
3471
  function jsdocDetector(projectPath, packageJson) {
3336
3472
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3402,6 +3538,20 @@ const typeSystemDetectors = [
3402
3538
  * @param projectPath - Project directory path
3403
3539
  * @param packageJson - Optional pre-loaded package.json
3404
3540
  * @returns Array of detected type systems, sorted by confidence
3541
+ *
3542
+ * @example Detecting all type systems
3543
+ * ```typescript
3544
+ * import { detectTypeSystems } from '@hyperfrontend/project-scope'
3545
+ *
3546
+ * const typeSystems = detectTypeSystems('./my-project')
3547
+ * // => [
3548
+ * // { id: 'typescript', name: 'TypeScript', version: '5.3.0', strictMode: true, confidence: 95, ... },
3549
+ * // { id: 'jsdoc', name: 'JSDoc', confidence: 40, ... }
3550
+ * // ]
3551
+ *
3552
+ * const primary = typeSystems[0]?.name ?? 'None'
3553
+ * console.log(`Primary type system: ${primary}`)
3554
+ * ```
3405
3555
  */
3406
3556
  function detectTypeSystems(projectPath, packageJson) {
3407
3557
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3455,7 +3605,7 @@ function isDetectAllOptions(value) {
3455
3605
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
3456
3606
  * @returns All detection results organized by category
3457
3607
  *
3458
- * @example
3608
+ * @example Running all tech detectors
3459
3609
  * ```typescript
3460
3610
  * import { detectAll } from '@hyperfrontend/project-scope'
3461
3611
  *
@@ -3532,10 +3682,21 @@ function detectAll(projectPath, packageJsonOrOptions) {
3532
3682
  * Clear the tech detection cache.
3533
3683
  *
3534
3684
  * Useful for testing or when the project files have changed.
3685
+ *
3686
+ * @example Clearing the tech detection cache
3687
+ * ```typescript
3688
+ * import { detectAll, clearTechDetectionCache } from '@hyperfrontend/project-scope'
3689
+ *
3690
+ * // Initial detection (cached)
3691
+ * const first = detectAll('./my-project')
3692
+ *
3693
+ * // After modifying package.json, clear cache to re-detect
3694
+ * clearTechDetectionCache()
3695
+ * const fresh = detectAll('./my-project')
3696
+ * ```
3535
3697
  */
3536
3698
  function clearTechDetectionCache() {
3537
3699
  detectAllCache.clear();
3538
3700
  }
3539
3701
 
3540
3702
  export { BABEL_CONFIG_PATTERNS, CYPRESS_CONFIG_PATTERNS, ESLINT_CONFIG_PATTERNS, JEST_CONFIG_PATTERNS, MOCHA_CONFIG_PATTERNS, PARCEL_CONFIG_PATTERNS, PLAYWRIGHT_CONFIG_PATTERNS, PRETTIER_CONFIG_PATTERNS, ROLLUP_CONFIG_PATTERNS, STYLELINT_CONFIG_PATTERNS, SWC_CONFIG_PATTERNS, VITEST_CONFIG_PATTERNS, VITE_CONFIG_PATTERNS, WEBPACK_CONFIG_PATTERNS, allDetectors, angularDetector, angularJSDetector, astroDetector, babelDetector, backboneDetector, backendDetectors, biomeDetector, buildToolDetectors, clearTechDetectionCache, cypressDetector, detectAll, detectBackendFrameworks, detectBuildTools, detectFrontendFrameworks, detectLegacyFrameworks, detectLintingTools, detectMonorepoTools, detectTestingFrameworks, detectTypeSystems, emberDetector, esbuildDetector, eslintDetector, expressDetector, fastifyDetector, flowDetector, frameworkDetectors, gatsbyDetector, honoDetector, jestDetector, jqueryDetector, jsdocDetector, koaDetector, legacyDetectors, lernaDetector, lintingDetectors, mochaDetector, monorepoDetectors, nestDetector, nextjsDetector, npmWorkspacesDetector, nuxtDetector, nxDetector, parcelDetector, playwrightDetector, pnpmWorkspacesDetector, prettierDetector, qwikDetector, reactDetector, remixDetector, rollupDetector, rushDetector, solidDetector, stylelintDetector, svelteDetector, sveltekitDetector, swcDetector, testingDetectors, turborepoDetector, typeSystemDetectors, typescriptDetector, viteDetector, vitestDetector, vueDetector, webpackDetector, yarnWorkspacesDetector };
3541
- //# sourceMappingURL=index.esm.js.map