@hyperfrontend/project-scope 0.2.1 → 0.2.2

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