@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/cli/index.esm.js CHANGED
@@ -1,445 +1,25 @@
1
+ import { join as join$1, resolve, parse, dirname, basename } from 'node:path';
1
2
  import { parseArgs } from 'node:util';
2
- import { join as join$1, resolve, parse as parse$1, dirname, basename } from 'node:path';
3
+ import { isArray } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js';
4
+ import { stringify, parse as parse$1 } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js';
5
+ import { freeze, entries, keys, defineProperties, values } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js';
6
+ import { dateNow, createDate } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js';
3
7
  import { existsSync, readFileSync, statSync, lstatSync, readdirSync } from 'node:fs';
4
-
5
- /**
6
- * Safe copies of Console built-in methods.
7
- *
8
- * These references are captured at module initialization time to protect against
9
- * prototype pollution attacks. Import only what you need for tree-shaking.
10
- *
11
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/console
12
- */
13
- const _console = globalThis.console;
14
- /**
15
- * (Safe copy) Outputs a message to the console.
16
- */
17
- const log = _console.log.bind(_console);
18
- /**
19
- * (Safe copy) Outputs a warning message to the console.
20
- */
21
- const warn = _console.warn.bind(_console);
22
- /**
23
- * (Safe copy) Outputs an error message to the console.
24
- */
25
- const error = _console.error.bind(_console);
26
- /**
27
- * (Safe copy) Outputs an informational message to the console.
28
- */
29
- const info = _console.info.bind(_console);
30
- /**
31
- * (Safe copy) Outputs a debug message to the console.
32
- */
33
- const debug = _console.debug.bind(_console);
34
- /**
35
- * (Safe copy) Outputs a stack trace to the console.
36
- */
37
- _console.trace.bind(_console);
38
- /**
39
- * (Safe copy) Displays an interactive listing of the properties of a specified object.
40
- */
41
- _console.dir.bind(_console);
42
- /**
43
- * (Safe copy) Displays tabular data as a table.
44
- */
45
- _console.table.bind(_console);
46
- /**
47
- * (Safe copy) Writes an error message to the console if the assertion is false.
48
- */
49
- _console.assert.bind(_console);
50
- /**
51
- * (Safe copy) Clears the console.
52
- */
53
- _console.clear.bind(_console);
54
- /**
55
- * (Safe copy) Logs the number of times that this particular call to count() has been called.
56
- */
57
- _console.count.bind(_console);
58
- /**
59
- * (Safe copy) Resets the counter used with console.count().
60
- */
61
- _console.countReset.bind(_console);
62
- /**
63
- * (Safe copy) Creates a new inline group in the console.
64
- */
65
- _console.group.bind(_console);
66
- /**
67
- * (Safe copy) Creates a new inline group in the console that is initially collapsed.
68
- */
69
- _console.groupCollapsed.bind(_console);
70
- /**
71
- * (Safe copy) Exits the current inline group.
72
- */
73
- _console.groupEnd.bind(_console);
74
- /**
75
- * (Safe copy) Starts a timer with a name specified as an input parameter.
76
- */
77
- _console.time.bind(_console);
78
- /**
79
- * (Safe copy) Stops a timer that was previously started.
80
- */
81
- _console.timeEnd.bind(_console);
82
- /**
83
- * (Safe copy) Logs the current value of a timer that was previously started.
84
- */
85
- _console.timeLog.bind(_console);
86
-
87
- /**
88
- * Safe copies of Object built-in methods.
89
- *
90
- * These references are captured at module initialization time to protect against
91
- * prototype pollution attacks. Import only what you need for tree-shaking.
92
- *
93
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
94
- */
95
- const _Object = globalThis.Object;
96
- /**
97
- * (Safe copy) Prevents modification of existing property attributes and values,
98
- * and prevents the addition of new properties.
99
- */
100
- const freeze = _Object.freeze;
101
- /**
102
- * (Safe copy) Returns the names of the enumerable string properties and methods of an object.
103
- */
104
- const keys = _Object.keys;
105
- /**
106
- * (Safe copy) Returns an array of key/values of the enumerable own properties of an object.
107
- */
108
- const entries = _Object.entries;
109
- /**
110
- * (Safe copy) Returns an array of values of the enumerable own properties of an object.
111
- */
112
- const values = _Object.values;
113
- /**
114
- * (Safe copy) Adds one or more properties to an object, and/or modifies attributes of existing properties.
115
- */
116
- const defineProperties = _Object.defineProperties;
117
-
118
- const registeredClasses = [];
119
-
120
- /**
121
- * Safe copies of Array built-in static methods.
122
- *
123
- * These references are captured at module initialization time to protect against
124
- * prototype pollution attacks. Import only what you need for tree-shaking.
125
- *
126
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
127
- */
128
- const _Array = globalThis.Array;
129
- /**
130
- * (Safe copy) Determines whether the passed value is an Array.
131
- */
132
- const isArray = _Array.isArray;
133
-
134
- /**
135
- * Returns the data type of the target.
136
- * Uses native `typeof` operator, however, makes distinction between `null`, `array`, and `object`.
137
- * Also, when classes are registered via `registerClass`, it checks if objects are instance of any known registered class.
138
- *
139
- * @param target - The target to get the data type of.
140
- * @returns The data type of the target.
141
- */
142
- const getType = (target) => {
143
- if (target === null)
144
- return 'null';
145
- const nativeDataType = typeof target;
146
- if (nativeDataType === 'object') {
147
- if (isArray(target))
148
- return 'array';
149
- for (const registeredClass of registeredClasses) {
150
- if (target instanceof registeredClass)
151
- return registeredClass.name;
152
- }
153
- }
154
- return nativeDataType;
155
- };
156
-
157
- /**
158
- * Safe copies of Error built-ins via factory functions.
159
- *
160
- * Since constructors cannot be safely captured via Object.assign, this module
161
- * provides factory functions that use Reflect.construct internally.
162
- *
163
- * These references are captured at module initialization time to protect against
164
- * prototype pollution attacks. Import only what you need for tree-shaking.
165
- *
166
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
167
- */
168
- const _Error = globalThis.Error;
169
- const _Reflect$3 = globalThis.Reflect;
170
- /**
171
- * (Safe copy) Creates a new Error using the captured Error constructor.
172
- * Use this instead of `new Error()`.
173
- *
174
- * @param message - Optional error message.
175
- * @param options - Optional error options.
176
- * @returns A new Error instance.
177
- */
178
- const createError = (message, options) => _Reflect$3.construct(_Error, [message, options]);
179
-
180
- /**
181
- * Safe copies of Map built-in via factory function.
182
- *
183
- * Since constructors cannot be safely captured via Object.assign, this module
184
- * provides a factory function that uses Reflect.construct internally.
185
- *
186
- * These references are captured at module initialization time to protect against
187
- * prototype pollution attacks. Import only what you need for tree-shaking.
188
- *
189
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/map
190
- */
191
- const _Map = globalThis.Map;
192
- const _Reflect$2 = globalThis.Reflect;
193
- /**
194
- * (Safe copy) Creates a new Map using the captured Map constructor.
195
- * Use this instead of `new Map()`.
196
- *
197
- * @param iterable - Optional iterable of key-value pairs.
198
- * @returns A new Map instance.
199
- */
200
- const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
201
-
202
- /**
203
- * Safe copies of Date built-in via factory function and static methods.
204
- *
205
- * Since constructors cannot be safely captured via Object.assign, this module
206
- * provides a factory function that uses Reflect.construct internally.
207
- *
208
- * These references are captured at module initialization time to protect against
209
- * prototype pollution attacks. Import only what you need for tree-shaking.
210
- *
211
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/date
212
- */
213
- const _Date = globalThis.Date;
214
- const _Reflect$1 = globalThis.Reflect;
215
- function createDate(...args) {
216
- return _Reflect$1.construct(_Date, args);
217
- }
218
- /**
219
- * (Safe copy) Returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
220
- */
221
- const dateNow = _Date.now;
222
-
223
- /**
224
- * Safe copies of Math built-in methods.
225
- *
226
- * These references are captured at module initialization time to protect against
227
- * prototype pollution attacks. Import only what you need for tree-shaking.
228
- *
229
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/math
230
- */
231
- const _Math = globalThis.Math;
232
- /**
233
- * (Safe copy) Returns the value of a number rounded to the nearest integer.
234
- */
235
- const round = _Math.round;
236
- /**
237
- * (Safe copy) Returns the smaller of zero or more numbers.
238
- */
239
- const min = _Math.min;
240
-
241
- /**
242
- * Safe copies of Set built-in via factory function.
243
- *
244
- * Since constructors cannot be safely captured via Object.assign, this module
245
- * provides a factory function that uses Reflect.construct internally.
246
- *
247
- * These references are captured at module initialization time to protect against
248
- * prototype pollution attacks. Import only what you need for tree-shaking.
249
- *
250
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
251
- */
252
- const _Set = globalThis.Set;
253
- const _Reflect = globalThis.Reflect;
254
- /**
255
- * (Safe copy) Creates a new Set using the captured Set constructor.
256
- * Use this instead of `new Set()`.
257
- *
258
- * @param iterable - Optional iterable of values.
259
- * @returns A new Set instance.
260
- */
261
- const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
262
-
263
- /* eslint-disable @typescript-eslint/no-explicit-any */
264
- /**
265
- * Creates a wrapper function that only executes the wrapped function if the condition function returns true.
266
- *
267
- * @param func - The function to be conditionally executed.
268
- * @param conditionFunc - A function that returns a boolean, determining if `func` should be executed.
269
- * @returns A wrapped version of `func` that executes conditionally.
270
- */
271
- function createConditionalExecutionFunction(func, conditionFunc) {
272
- return function (...args) {
273
- if (conditionFunc()) {
274
- return func(...args);
275
- }
276
- };
277
- }
278
-
279
- /* eslint-disable @typescript-eslint/no-explicit-any */
280
- /**
281
- * Creates a wrapper function that silently ignores any errors thrown by the wrapped void function.
282
- * This function is specifically for wrapping functions that do not return a value (void functions).
283
- * Exceptions are swallowed without any logging or handling.
284
- *
285
- * @param func - The void function to be wrapped.
286
- * @returns A wrapped version of the input function that ignores errors.
287
- */
288
- function createErrorIgnoringFunction(func) {
289
- return function (...args) {
290
- try {
291
- func(...args);
292
- }
293
- catch {
294
- // Deliberately swallowing/ignoring the exception
295
- }
296
- };
297
- }
298
-
299
- /* eslint-disable @typescript-eslint/no-unused-vars */
300
- /**
301
- * A no-operation function (noop) that does nothing regardless of the arguments passed.
302
- * It is designed to be as permissive as possible in its typing without using the `Function` keyword.
303
- *
304
- * @param args - Any arguments passed to the function (ignored)
305
- */
306
- const noop = (...args) => {
307
- // Intentionally does nothing
308
- };
309
-
310
- const logLevels = ['none', 'error', 'warn', 'log', 'info', 'debug'];
311
- const priority = {
312
- error: 4,
313
- warn: 3,
314
- log: 2,
315
- info: 1,
316
- debug: 0,
317
- };
318
- /**
319
- * Validates whether a given string is a valid log level.
320
- *
321
- * @param level - The log level to validate
322
- * @returns True if the level is valid, false otherwise
323
- */
324
- function isValidLogLevel(level) {
325
- return logLevels.includes(level);
326
- }
327
- /**
328
- * Creates a log level configuration manager for controlling logging behavior.
329
- * Provides methods to get, set, and evaluate log levels based on priority.
330
- *
331
- * @param level - The initial log level (defaults to 'error')
332
- * @returns A configuration object with log level management methods
333
- * @throws {Error} When the provided level is not a valid log level
334
- */
335
- function createLogLevelConfig(level = 'error') {
336
- if (!isValidLogLevel(level)) {
337
- throw createError('Cannot create log level configuration with a valid default log level');
338
- }
339
- const state = { level };
340
- const getLogLevel = () => state.level;
341
- const setLogLevel = (level) => {
342
- if (!isValidLogLevel(level)) {
343
- throw createError(`Cannot set value '${level}' level. Expected levels are ${logLevels}.`);
344
- }
345
- state.level = level;
346
- };
347
- const shouldLog = (level) => {
348
- if (state.level === 'none' || level === 'none' || !isValidLogLevel(level)) {
349
- return false;
350
- }
351
- return priority[level] >= priority[state.level];
352
- };
353
- return freeze({
354
- getLogLevel,
355
- setLogLevel,
356
- shouldLog,
357
- });
358
- }
359
-
360
- /**
361
- * Creates a logger instance with configurable log level filtering.
362
- * Each log function is wrapped to respect the current log level setting.
363
- *
364
- * @param error - Function to handle error-level logs (required)
365
- * @param warn - Function to handle warning-level logs (optional, defaults to noop)
366
- * @param log - Function to handle standard logs (optional, defaults to noop)
367
- * @param info - Function to handle info-level logs (optional, defaults to noop)
368
- * @param debug - Function to handle debug-level logs (optional, defaults to noop)
369
- * @returns A frozen logger object with log methods and level control
370
- * @throws {ErrorLevelFn} When any provided log function is invalid
371
- */
372
- function createLogger(error, warn = noop, log = noop, info = noop, debug = noop) {
373
- if (notValidLogFn(error)) {
374
- throw createError(notFnMsg('error'));
375
- }
376
- if (notValidLogFn(warn)) {
377
- throw createError(notFnMsg('warn'));
378
- }
379
- if (notValidLogFn(log)) {
380
- throw createError(notFnMsg('log'));
381
- }
382
- if (notValidLogFn(info)) {
383
- throw createError(notFnMsg('info'));
384
- }
385
- if (notValidLogFn(debug)) {
386
- throw createError(notFnMsg('debug'));
387
- }
388
- const { setLogLevel, getLogLevel, shouldLog } = createLogLevelConfig();
389
- const wrapLogFn = (fn, level) => {
390
- if (fn === noop)
391
- return fn;
392
- const condition = () => shouldLog(level);
393
- return createConditionalExecutionFunction(createErrorIgnoringFunction(fn), condition);
394
- };
395
- return freeze({
396
- error: wrapLogFn(error, 'error'),
397
- warn: wrapLogFn(warn, 'warn'),
398
- log: wrapLogFn(log, 'log'),
399
- info: wrapLogFn(info, 'info'),
400
- debug: wrapLogFn(debug, 'debug'),
401
- setLogLevel,
402
- getLogLevel,
403
- });
404
- }
405
- /**
406
- * Validates whether a given value is a valid log function.
407
- *
408
- * @param fn - The value to validate
409
- * @returns True if the value is not a function (invalid), false if it is valid
410
- */
411
- function notValidLogFn(fn) {
412
- return getType(fn) !== 'function' && fn !== noop;
413
- }
414
- /**
415
- * Generates an error message for invalid log function parameters.
416
- *
417
- * @param label - The name of the log function that failed validation
418
- * @returns A formatted error message string
419
- */
420
- function notFnMsg(label) {
421
- return `Cannot create a logger when ${label} is not a function`;
422
- }
423
-
424
- createLogger(error, warn, log, info, debug);
425
-
426
- /**
427
- * Safe copies of JSON built-in methods.
428
- *
429
- * These references are captured at module initialization time to protect against
430
- * prototype pollution attacks. Import only what you need for tree-shaking.
431
- *
432
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
433
- */
434
- const _JSON = globalThis.JSON;
435
- /**
436
- * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
437
- */
438
- const parse = _JSON.parse;
439
- /**
440
- * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
441
- */
442
- const stringify = _JSON.stringify;
8
+ import { error, warn, log, info, debug } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js';
9
+ import { createSet } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js';
10
+ import { createLogger } from '../_dependencies/@hyperfrontend/logging/index.esm.js';
11
+ import { createError } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js';
12
+ import { createMap } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js';
13
+ import { min, round } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js';
14
+ import { parseInt, parseFloat } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js';
15
+ import { getFileStat, isDirectory, exists } from '../_shared/core/fs/stat/index.esm.js';
16
+ import { join } from '../_shared/core/path/join/index.esm.js';
17
+ import { createConfigError } from '../_shared/core/errors/structured-errors/index.esm.js';
18
+ import { createCache } from '../_shared/core/cache/index.esm.js';
19
+ import { matchGlobPattern } from '../_shared/core/patterns/glob/index.esm.js';
20
+ import { collectAllDependencies, parseVersionString, locateConfigFile, filterScriptsByCommand } from '../_shared/tech/shared-utils/detector-helpers/index.esm.js';
21
+ import { pnpmWorkspacesDetector } from '../_shared/tech/monorepo/pnpm-workspaces/index.esm.js';
22
+ import { CONFIG_PATTERNS } from '../_shared/project/config/patterns/index.esm.js';
443
23
 
444
24
  /**
445
25
  * Global log level registry.
@@ -457,7 +37,7 @@ let globalLogLevel = null;
457
37
  *
458
38
  * @param level - The log level to set globally
459
39
  *
460
- * @example
40
+ * @example Enabling debug logging globally
461
41
  * ```typescript
462
42
  * import { setGlobalLogLevel } from '@hyperfrontend/project-scope/core'
463
43
  *
@@ -504,6 +84,13 @@ function isSensitiveKey(key) {
504
84
  *
505
85
  * @param obj - Object to sanitize
506
86
  * @returns New object with sensitive values redacted
87
+ *
88
+ * @example Sanitizing sensitive data
89
+ * ```typescript
90
+ * const config = { apiKey: 'secret123', endpoint: 'https://api.example.com' }
91
+ * const safe = sanitize(config)
92
+ * // => { apiKey: '[REDACTED]', endpoint: 'https://api.example.com' }
93
+ * ```
507
94
  */
508
95
  function sanitize(obj) {
509
96
  if (obj === null || obj === undefined) {
@@ -554,7 +141,7 @@ function formatMessage(namespace, message, meta) {
554
141
  * @param options - Logger configuration options
555
142
  * @returns A configured scoped logger instance
556
143
  *
557
- * @example
144
+ * @example Creating a scoped logger
558
145
  * ```typescript
559
146
  * const logger = createScopedLogger('project-scope')
560
147
  * logger.setLogLevel('debug')
@@ -591,7 +178,7 @@ function createScopedLogger(namespace, options = {}) {
591
178
  * Default logger instance for the project-scope library.
592
179
  * Use this for general logging within the library.
593
180
  *
594
- * @example
181
+ * @example Using the default logger
595
182
  * ```typescript
596
183
  * import { logger } from '@hyperfrontend/project-scope/core'
597
184
  *
@@ -609,6 +196,15 @@ const fsLogger = createScopedLogger('project-scope:fs');
609
196
  * @param code - The category code for this type of filesystem failure
610
197
  * @param context - Additional context including path, operation, and cause
611
198
  * @returns A configured Error object with code and context properties
199
+ *
200
+ * @example Creating a file system error
201
+ * ```typescript
202
+ * throw createFileSystemError(
203
+ * 'Cannot read file',
204
+ * 'FS_READ_ERROR',
205
+ * { path: './missing.txt', operation: 'read' }
206
+ * )
207
+ * ```
612
208
  */
613
209
  function createFileSystemError(message, code, context) {
614
210
  const error = createError(message);
@@ -626,7 +222,7 @@ function createFileSystemError(message, code, context) {
626
222
  * @returns File contents as string
627
223
  * @throws {Error} If file doesn't exist or can't be read
628
224
  *
629
- * @example
225
+ * @example Reading file contents
630
226
  * ```typescript
631
227
  * import { readFileContent } from '@hyperfrontend/project-scope'
632
228
  *
@@ -653,6 +249,14 @@ function readFileContent(filePath, encoding = 'utf-8') {
653
249
  * @param filePath - Path to file
654
250
  * @param encoding - File encoding (default: utf-8)
655
251
  * @returns File contents or null if file doesn't exist
252
+ *
253
+ * @example Reading file if it exists
254
+ * ```typescript
255
+ * const content = readFileIfExists('./optional-config.json')
256
+ * if (content) {
257
+ * // File existed, use content
258
+ * }
259
+ * ```
656
260
  */
657
261
  function readFileIfExists(filePath, encoding = 'utf-8') {
658
262
  if (!existsSync(filePath)) {
@@ -666,56 +270,6 @@ function readFileIfExists(filePath, encoding = 'utf-8') {
666
270
  }
667
271
  }
668
272
 
669
- createScopedLogger('project-scope:fs:write');
670
-
671
- /**
672
- * Get file stats with error handling.
673
- *
674
- * @param filePath - Path to file
675
- * @param followSymlinks - Whether to follow symlinks (default: true)
676
- * @returns File stats or null if path doesn't exist
677
- */
678
- function getFileStat(filePath, followSymlinks = true) {
679
- if (!existsSync(filePath)) {
680
- return null;
681
- }
682
- try {
683
- const stat = followSymlinks ? statSync(filePath) : lstatSync(filePath);
684
- return {
685
- isFile: stat.isFile(),
686
- isDirectory: stat.isDirectory(),
687
- isSymlink: stat.isSymbolicLink(),
688
- size: stat.size,
689
- created: stat.birthtime,
690
- modified: stat.mtime,
691
- accessed: stat.atime,
692
- mode: stat.mode,
693
- };
694
- }
695
- catch {
696
- return null;
697
- }
698
- }
699
- /**
700
- * Check if path is a directory.
701
- *
702
- * @param dirPath - Path to check
703
- * @returns True if path is a directory
704
- */
705
- function isDirectory(dirPath) {
706
- const stats = getFileStat(dirPath);
707
- return stats?.isDirectory ?? false;
708
- }
709
- /**
710
- * Check if path exists.
711
- *
712
- * @param filePath - Path to check
713
- * @returns True if path exists
714
- */
715
- function exists(filePath) {
716
- return existsSync(filePath);
717
- }
718
-
719
273
  const fsDirLogger = createScopedLogger('project-scope:fs:dir');
720
274
  /**
721
275
  * List immediate contents of a directory.
@@ -724,7 +278,7 @@ const fsDirLogger = createScopedLogger('project-scope:fs:dir');
724
278
  * @returns Array of entries with metadata for each file/directory
725
279
  * @throws {Error} If directory doesn't exist or isn't a directory
726
280
  *
727
- * @example
281
+ * @example Listing directory contents
728
282
  * ```typescript
729
283
  * import { readDirectory } from '@hyperfrontend/project-scope'
730
284
  *
@@ -765,17 +319,6 @@ function readDirectory(dirPath) {
765
319
  }
766
320
  }
767
321
 
768
- /**
769
- * Join path segments.
770
- * Uses platform-specific separators (e.g., / or \).
771
- *
772
- * @param paths - Path segments to join
773
- * @returns Joined path
774
- */
775
- function join(...paths) {
776
- return join$1(...paths);
777
- }
778
-
779
322
  const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
780
323
  /**
781
324
  * Generic upward directory traversal.
@@ -784,11 +327,20 @@ const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
784
327
  * @param startPath - Starting directory
785
328
  * @param predicate - Function to test each directory
786
329
  * @returns First matching directory or null
330
+ *
331
+ * @example Finding directory containing README
332
+ * ```typescript
333
+ * // Find first directory containing a README
334
+ * const readmeDir = traverseUpward('./src/utils', (dir) =>
335
+ * existsSync(join(dir, 'README.md'))
336
+ * )
337
+ * // => '/project' or null
338
+ * ```
787
339
  */
788
340
  function traverseUpward(startPath, predicate) {
789
341
  fsTraversalLogger.debug('Starting upward traversal', { startPath });
790
342
  let currentPath = resolve(startPath);
791
- const rootPath = parse$1(currentPath).root;
343
+ const rootPath = parse(currentPath).root;
792
344
  while (currentPath !== rootPath) {
793
345
  if (predicate(currentPath)) {
794
346
  fsTraversalLogger.debug('Upward traversal found match', { startPath, foundPath: currentPath });
@@ -809,6 +361,17 @@ function traverseUpward(startPath, predicate) {
809
361
  * @param startPath - Starting directory
810
362
  * @param markers - Array of marker file names to search for
811
363
  * @returns First directory containing any marker, or null
364
+ *
365
+ * @example Finding project root by marker files
366
+ * ```typescript
367
+ * // Find project root by looking for common marker files
368
+ * const projectRoot = locateByMarkers('./src/components', [
369
+ * 'package.json',
370
+ * 'nx.json',
371
+ * 'tsconfig.base.json'
372
+ * ])
373
+ * // => '/workspace/my-project'
374
+ * ```
812
375
  */
813
376
  function locateByMarkers(startPath, markers) {
814
377
  fsTraversalLogger.debug('Locating by markers', { startPath, markers });
@@ -819,42 +382,7 @@ function locateByMarkers(startPath, markers) {
819
382
  return result;
820
383
  }
821
384
 
822
- /**
823
- * Create a structured error with code and optional context.
824
- *
825
- * @param message - The human-readable error message
826
- * @param code - The machine-readable error code for programmatic handling
827
- * @param context - Additional contextual information about the error
828
- * @returns Structured error instance with code and context properties
829
- *
830
- * @example
831
- * ```typescript
832
- * import { createStructuredError } from '@hyperfrontend/project-scope'
833
- *
834
- * throw createStructuredError(
835
- * 'Configuration file not found',
836
- * 'CONFIG_NOT_FOUND',
837
- * { path: './config.json', searched: ['./config.json', './settings.json'] }
838
- * )
839
- * ```
840
- */
841
- function createStructuredError(message, code, context) {
842
- const error = createError(message);
843
- error.code = code;
844
- error.context = context ?? {};
845
- return error;
846
- }
847
- /**
848
- * Create a configuration-related error.
849
- *
850
- * @param message - The human-readable error message
851
- * @param code - The machine-readable error code for programmatic handling
852
- * @param context - Additional contextual information (e.g., file path, config key)
853
- * @returns Structured error instance tagged with type 'config'
854
- */
855
- function createConfigError(message, code, context) {
856
- return createStructuredError(message, code, { ...context, type: 'config' });
857
- }
385
+ createScopedLogger('project-scope:fs:write');
858
386
 
859
387
  const packageLogger = createScopedLogger('project-scope:project:package');
860
388
  /**
@@ -926,13 +454,21 @@ function validatePackageJson(data) {
926
454
  * @param projectPath - Project directory path or path to package.json
927
455
  * @returns Parsed package.json
928
456
  * @throws {Error} Error if file doesn't exist or is invalid
457
+ *
458
+ * @example Reading package.json
459
+ * ```typescript
460
+ * import { readPackageJson } from '@hyperfrontend/project-scope'
461
+ *
462
+ * const pkg = readPackageJson('/path/to/project')
463
+ * console.log(pkg.name, pkg.version)
464
+ * ```
929
465
  */
930
466
  function readPackageJson(projectPath) {
931
467
  const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
932
468
  packageLogger.debug('Reading package.json', { path: packageJsonPath });
933
469
  const content = readFileContent(packageJsonPath);
934
470
  try {
935
- const data = parse(content);
471
+ const data = parse$1(content);
936
472
  const validated = validatePackageJson(data);
937
473
  packageLogger.debug('Package.json read successfully', { path: packageJsonPath, name: validated.name });
938
474
  return validated;
@@ -954,6 +490,16 @@ function readPackageJson(projectPath) {
954
490
  *
955
491
  * @param projectPath - Project directory path or path to package.json
956
492
  * @returns Parsed package.json or null if not found
493
+ *
494
+ * @example Reading package.json if it exists
495
+ * ```typescript
496
+ * import { readPackageJsonIfExists } from '@hyperfrontend/project-scope'
497
+ *
498
+ * const pkg = readPackageJsonIfExists('/path/to/project')
499
+ * if (pkg) {
500
+ * console.log('Found:', pkg.name)
501
+ * }
502
+ * ```
957
503
  */
958
504
  function readPackageJsonIfExists(projectPath) {
959
505
  const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
@@ -963,7 +509,7 @@ function readPackageJsonIfExists(projectPath) {
963
509
  return null;
964
510
  }
965
511
  try {
966
- const validated = validatePackageJson(parse(content));
512
+ const validated = validatePackageJson(parse$1(content));
967
513
  packageLogger.debug('Package.json loaded', { path: packageJsonPath, name: validated.name });
968
514
  return validated;
969
515
  }
@@ -978,6 +524,15 @@ function readPackageJsonIfExists(projectPath) {
978
524
  *
979
525
  * @param packageJson - Parsed package.json
980
526
  * @returns All dependencies categorized
527
+ *
528
+ * @example Extracting all dependencies
529
+ * ```typescript
530
+ * import { getDependencies } from '@hyperfrontend/project-scope'
531
+ *
532
+ * const deps = getDependencies(packageJson)
533
+ * console.log('Runtime:', Object.keys(deps.dependencies))
534
+ * console.log('Dev:', Object.keys(deps.devDependencies))
535
+ * ```
981
536
  */
982
537
  function getDependencies(packageJson) {
983
538
  return {
@@ -994,6 +549,16 @@ createScopedLogger('project-scope:heuristics:deps');
994
549
  *
995
550
  * @param projectPath - Project directory
996
551
  * @returns Dependencies grouped by runtime, dev, peer, and optional
552
+ *
553
+ * @example Getting project dependencies
554
+ * ```typescript
555
+ * import { getProjectDependencies } from '@hyperfrontend/project-scope'
556
+ *
557
+ * const deps = getProjectDependencies('/path/to/project')
558
+ * console.log('Runtime:', deps.runtime) // ['express', 'lodash']
559
+ * console.log('Dev:', deps.development) // ['jest', 'typescript']
560
+ * console.log('Total:', deps.total) // 15
561
+ * ```
997
562
  */
998
563
  function getProjectDependencies(projectPath) {
999
564
  const packageJson = readPackageJsonIfExists(projectPath);
@@ -1020,326 +585,6 @@ function getProjectDependencies(projectPath) {
1020
585
  };
1021
586
  }
1022
587
 
1023
- /**
1024
- * Global registry of all caches for bulk operations.
1025
- */
1026
- const cacheRegistry = createSet();
1027
- /**
1028
- * Create a cache with optional TTL and size limits.
1029
- *
1030
- * The cache provides a simple key-value store with:
1031
- * - Optional TTL (time-to-live) for automatic expiration
1032
- * - Optional maxSize for limiting cache size with FIFO eviction
1033
- * - Lazy expiration (entries are checked on access)
1034
- *
1035
- * @param options - Cache configuration options
1036
- * @returns Cache instance
1037
- *
1038
- * @example
1039
- * ```typescript
1040
- * // Basic cache
1041
- * const cache = createCache<string, number>()
1042
- * cache.set('answer', 42)
1043
- * cache.get('answer') // 42
1044
- *
1045
- * // Cache with TTL (expires after 60 seconds)
1046
- * const ttlCache = createCache<string, object>({ ttl: 60000 })
1047
- *
1048
- * // Cache with max size (evicts oldest when full)
1049
- * const lruCache = createCache<string, object>({ maxSize: 100 })
1050
- *
1051
- * // Combined options
1052
- * const configCache = createCache<string, object>({
1053
- * ttl: 30000,
1054
- * maxSize: 50
1055
- * })
1056
- * ```
1057
- */
1058
- function createCache(options) {
1059
- const { ttl, maxSize } = options ?? {};
1060
- const store = createMap();
1061
- const insertionOrder = [];
1062
- /**
1063
- * Check if an entry is expired.
1064
- *
1065
- * @param entry - Cache entry to check
1066
- * @returns True if entry is expired
1067
- */
1068
- function isExpired(entry) {
1069
- if (ttl === undefined)
1070
- return false;
1071
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
1072
- return Date.now() - entry.timestamp > ttl;
1073
- }
1074
- /**
1075
- * Evict oldest entries to make room for new ones.
1076
- */
1077
- function evictIfNeeded() {
1078
- if (maxSize === undefined)
1079
- return;
1080
- while (store.size >= maxSize && insertionOrder.length > 0) {
1081
- const oldestKey = insertionOrder.shift();
1082
- if (oldestKey !== undefined) {
1083
- store.delete(oldestKey);
1084
- }
1085
- }
1086
- }
1087
- /**
1088
- * Remove key from insertion order tracking.
1089
- *
1090
- * @param key - Key to remove from order tracking
1091
- */
1092
- function removeFromOrder(key) {
1093
- const index = insertionOrder.indexOf(key);
1094
- if (index !== -1) {
1095
- insertionOrder.splice(index, 1);
1096
- }
1097
- }
1098
- const cache = {
1099
- get(key) {
1100
- const entry = store.get(key);
1101
- if (!entry)
1102
- return undefined;
1103
- if (isExpired(entry)) {
1104
- store.delete(key);
1105
- removeFromOrder(key);
1106
- return undefined;
1107
- }
1108
- return entry.value;
1109
- },
1110
- set(key, value) {
1111
- if (store.has(key)) {
1112
- removeFromOrder(key);
1113
- }
1114
- else {
1115
- evictIfNeeded();
1116
- }
1117
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
1118
- store.set(key, { value, timestamp: Date.now() });
1119
- insertionOrder.push(key);
1120
- },
1121
- has(key) {
1122
- const entry = store.get(key);
1123
- if (!entry)
1124
- return false;
1125
- if (isExpired(entry)) {
1126
- store.delete(key);
1127
- removeFromOrder(key);
1128
- return false;
1129
- }
1130
- return true;
1131
- },
1132
- delete(key) {
1133
- removeFromOrder(key);
1134
- return store.delete(key);
1135
- },
1136
- clear() {
1137
- store.clear();
1138
- insertionOrder.length = 0;
1139
- },
1140
- size() {
1141
- return store.size;
1142
- },
1143
- keys() {
1144
- return [...insertionOrder];
1145
- },
1146
- };
1147
- cacheRegistry.add(cache);
1148
- return freeze(cache);
1149
- }
1150
-
1151
- /**
1152
- * Match path against glob pattern using safe character iteration.
1153
- * Avoids regex to prevent ReDoS attacks.
1154
- *
1155
- * Supported patterns:
1156
- * - * matches any characters except /
1157
- * - ** matches any characters including /
1158
- * - ? matches exactly one character except /
1159
- * - {a,b,c} matches any of the alternatives
1160
- *
1161
- * @param path - The filesystem path to test against the pattern
1162
- * @param pattern - The glob pattern to match against
1163
- * @returns True if path matches pattern
1164
- *
1165
- * @example
1166
- * ```typescript
1167
- * import { matchGlobPattern } from '@hyperfrontend/project-scope'
1168
- *
1169
- * matchGlobPattern('src/utils/helper.ts', '\*\*\/*.ts') // true
1170
- * matchGlobPattern('test.spec.ts', '\*.spec.ts') // true
1171
- * matchGlobPattern('config.json', '\*.{json,yaml}') // true
1172
- * matchGlobPattern('src/index.ts', 'src/\*.ts') // true
1173
- * ```
1174
- */
1175
- function matchGlobPattern(path, pattern) {
1176
- return matchSegments(path.split('/'), pattern.split('/'), 0, 0);
1177
- }
1178
- /**
1179
- * Internal recursive function to match path segments against pattern segments.
1180
- *
1181
- * @param pathParts - Array of path segments split by '/'
1182
- * @param patternParts - Array of pattern segments split by '/'
1183
- * @param pathIdx - Current index in pathParts being examined
1184
- * @param patternIdx - Current index in patternParts being examined
1185
- * @returns True if remaining segments match
1186
- */
1187
- function matchSegments(pathParts, patternParts, pathIdx, patternIdx) {
1188
- if (pathIdx === pathParts.length && patternIdx === patternParts.length) {
1189
- return true;
1190
- }
1191
- if (patternIdx >= patternParts.length) {
1192
- return false;
1193
- }
1194
- const patternPart = patternParts[patternIdx];
1195
- if (patternPart === '**') {
1196
- for (let i = pathIdx; i <= pathParts.length; i++) {
1197
- if (matchSegments(pathParts, patternParts, i, patternIdx + 1)) {
1198
- return true;
1199
- }
1200
- }
1201
- return false;
1202
- }
1203
- if (pathIdx >= pathParts.length) {
1204
- return false;
1205
- }
1206
- const pathPart = pathParts[pathIdx];
1207
- if (matchSegment(pathPart, patternPart)) {
1208
- return matchSegments(pathParts, patternParts, pathIdx + 1, patternIdx + 1);
1209
- }
1210
- return false;
1211
- }
1212
- /**
1213
- * Match a single path segment against a pattern segment.
1214
- * Handles *, ?, and {a,b,c} patterns.
1215
- *
1216
- * @param text - The path segment text to match
1217
- * @param pattern - The pattern segment to match against
1218
- * @returns True if the text matches the pattern
1219
- */
1220
- function matchSegment(text, pattern) {
1221
- let textIdx = 0;
1222
- let patternIdx = 0;
1223
- while (patternIdx < pattern.length) {
1224
- const char = pattern[patternIdx];
1225
- if (char === '*') {
1226
- patternIdx++;
1227
- if (patternIdx === pattern.length) {
1228
- return true;
1229
- }
1230
- for (let i = textIdx; i <= text.length; i++) {
1231
- if (matchSegmentFrom(text, i, pattern, patternIdx)) {
1232
- return true;
1233
- }
1234
- }
1235
- return false;
1236
- }
1237
- else if (char === '?') {
1238
- if (textIdx >= text.length) {
1239
- return false;
1240
- }
1241
- textIdx++;
1242
- patternIdx++;
1243
- }
1244
- else if (char === '{') {
1245
- const closeIdx = findClosingBrace(pattern, patternIdx);
1246
- if (closeIdx === -1) {
1247
- if (textIdx >= text.length || text[textIdx] !== char) {
1248
- return false;
1249
- }
1250
- textIdx++;
1251
- patternIdx++;
1252
- }
1253
- else {
1254
- const alternatives = extractAlternatives(pattern.slice(patternIdx + 1, closeIdx));
1255
- for (const alt of alternatives) {
1256
- if (matchSegmentFrom(text, textIdx, text.slice(0, textIdx) + alt + pattern.slice(closeIdx + 1), textIdx)) {
1257
- return true;
1258
- }
1259
- }
1260
- return false;
1261
- }
1262
- }
1263
- else {
1264
- if (textIdx >= text.length || text[textIdx] !== char) {
1265
- return false;
1266
- }
1267
- textIdx++;
1268
- patternIdx++;
1269
- }
1270
- }
1271
- return textIdx === text.length;
1272
- }
1273
- /**
1274
- * Helper to match from a specific position.
1275
- *
1276
- * @param text - The full text being matched
1277
- * @param textIdx - The starting index in text to match from
1278
- * @param pattern - The full pattern being matched
1279
- * @param patternIdx - The starting index in pattern to match from
1280
- * @returns True if the text matches the pattern from the given positions
1281
- */
1282
- function matchSegmentFrom(text, textIdx, pattern, patternIdx) {
1283
- const remainingText = text.slice(textIdx);
1284
- const remainingPattern = pattern.slice(patternIdx);
1285
- return matchSegment(remainingText, remainingPattern);
1286
- }
1287
- /**
1288
- * Find closing brace for {a,b,c} pattern.
1289
- *
1290
- * @param pattern - The pattern string to search within
1291
- * @param startIdx - The index of the opening brace
1292
- * @returns The index of the matching closing brace, or -1 if not found
1293
- */
1294
- function findClosingBrace(pattern, startIdx) {
1295
- let depth = 0;
1296
- for (let i = startIdx; i < pattern.length; i++) {
1297
- if (pattern[i] === '{') {
1298
- depth++;
1299
- }
1300
- else if (pattern[i] === '}') {
1301
- depth--;
1302
- if (depth === 0) {
1303
- return i;
1304
- }
1305
- }
1306
- }
1307
- return -1;
1308
- }
1309
- /**
1310
- * Extract alternatives from {a,b,c} pattern content.
1311
- *
1312
- * @param content - The content between braces (without the braces themselves)
1313
- * @returns Array of alternative strings split by commas at depth 0
1314
- */
1315
- function extractAlternatives(content) {
1316
- const alternatives = [];
1317
- let current = '';
1318
- let depth = 0;
1319
- for (let i = 0; i < content.length; i++) {
1320
- const char = content[i];
1321
- if (char === '{') {
1322
- depth++;
1323
- current += char;
1324
- }
1325
- else if (char === '}') {
1326
- depth--;
1327
- current += char;
1328
- }
1329
- else if (char === ',' && depth === 0) {
1330
- alternatives.push(current);
1331
- current = '';
1332
- }
1333
- else {
1334
- current += char;
1335
- }
1336
- }
1337
- if (current) {
1338
- alternatives.push(current);
1339
- }
1340
- return alternatives;
1341
- }
1342
-
1343
588
  const walkLogger = createScopedLogger('project-scope:project:walk');
1344
589
  /**
1345
590
  * Reads .gitignore file from the given directory and extracts
@@ -1405,6 +650,18 @@ function matchPattern(path, pattern) {
1405
650
  * @param startPath - Root directory to begin traversal
1406
651
  * @param visitor - Callback function invoked for each file system entry
1407
652
  * @param options - Configuration for traversal behavior
653
+ *
654
+ * @example Walking a directory tree
655
+ * ```typescript
656
+ * import { walkDirectory } from '@hyperfrontend/project-scope'
657
+ *
658
+ * const tsFiles: string[] = []
659
+ * walkDirectory('./src', (entry) => {
660
+ * if (entry.isFile && entry.name.endsWith('.ts')) {
661
+ * tsFiles.push(entry.relativePath)
662
+ * }
663
+ * }, { maxDepth: 5, respectGitignore: true })
664
+ * ```
1408
665
  */
1409
666
  function walkDirectory(startPath, visitor, options) {
1410
667
  walkLogger.debug('Starting directory walk', {
@@ -1501,7 +758,7 @@ function matchesPatterns(path, patterns) {
1501
758
  * @param options - Configuration for search behavior
1502
759
  * @returns List of relative file paths that match the patterns
1503
760
  *
1504
- * @example
761
+ * @example Finding files by pattern
1505
762
  * ```typescript
1506
763
  * import { findFiles } from '@hyperfrontend/project-scope'
1507
764
  *
@@ -1615,7 +872,7 @@ function discoverFromExports(exports$1, entryPoints) {
1615
872
  * @param options - Discovery options
1616
873
  * @returns Array of discovered entry points sorted by confidence
1617
874
  *
1618
- * @example
875
+ * @example Discovering project entry points
1619
876
  * ```typescript
1620
877
  * import { discoverEntryPoints } from '@hyperfrontend/project-scope'
1621
878
  *
@@ -1782,80 +1039,32 @@ function discoverEntryPoints(projectPath, options) {
1782
1039
  return result;
1783
1040
  }
1784
1041
 
1785
- /**
1786
- * Get combined dependencies from package.json.
1787
- * Merges dependencies, devDependencies, peerDependencies, and optionalDependencies.
1788
- *
1789
- * @param packageJson - The package.json object to extract dependencies from
1790
- * @returns Combined dependencies as a single record
1791
- */
1792
- function collectAllDependencies(packageJson) {
1793
- return {
1794
- ...packageJson?.dependencies,
1795
- ...packageJson?.devDependencies,
1796
- ...packageJson?.peerDependencies,
1797
- ...packageJson?.optionalDependencies,
1798
- };
1799
- }
1800
- /**
1801
- * Extract clean version from dependency version string.
1802
- * Removes semver prefixes like ^, ~, >=, etc.
1803
- * Uses character-by-character parsing to avoid ReDoS vulnerabilities.
1804
- *
1805
- * @param versionString - The version string with optional prefix characters
1806
- * @returns The cleaned version string without prefix characters
1807
- */
1808
- function parseVersionString(versionString) {
1809
- if (versionString === undefined || versionString === null)
1810
- return undefined;
1811
- let start = 0;
1812
- while (start < versionString.length) {
1813
- const char = versionString[start];
1814
- if (char !== '^' && char !== '~' && char !== '>' && char !== '=' && char !== '<') {
1815
- break;
1816
- }
1817
- start++;
1818
- }
1819
- return versionString.slice(start);
1820
- }
1821
- /**
1822
- * Find first matching config file in project.
1823
- * Note: Name avoids similarity to fs.readFile/fs.readFileSync.
1824
- *
1825
- * @param projectPath - The project directory path
1826
- * @param patterns - Array of config file patterns to search for
1827
- * @returns The first matching config file path or undefined
1828
- */
1829
- function locateConfigFile(projectPath, patterns) {
1830
- for (const pattern of patterns) {
1831
- const fullPath = join(projectPath, pattern);
1832
- if (exists(fullPath)) {
1833
- return pattern;
1834
- }
1835
- }
1836
- return undefined;
1837
- }
1838
- /**
1839
- * Find scripts containing a specific command.
1840
- *
1841
- * @param scripts - The scripts object from package.json
1842
- * @param command - The command string to search for
1843
- * @returns Array of script names that contain the command
1844
- */
1845
- function filterScriptsByCommand(scripts, command) {
1846
- if (!scripts)
1847
- return [];
1848
- return entries(scripts)
1849
- .filter(([, script]) => script.includes(command))
1850
- .map(([name]) => name);
1851
- }
1852
-
1853
1042
  /**
1854
1043
  * Detect Express in project.
1855
1044
  *
1856
1045
  * @param projectPath - Project directory path
1857
1046
  * @param packageJson - Optional pre-loaded package.json
1858
1047
  * @returns Detection result or null if not detected
1048
+ * @example Detecting Express framework
1049
+ * ```typescript
1050
+ * const pkg = {
1051
+ * dependencies: { express: '^4.18.2', cors: '^2.8.5' },
1052
+ * devDependencies: { '@types/express': '^4.17.17' },
1053
+ * }
1054
+ *
1055
+ * const result = expressDetector('/path/to/project', pkg)
1056
+ * // => {
1057
+ * // id: 'express',
1058
+ * // name: 'Express',
1059
+ * // version: '4.18.2',
1060
+ * // confidence: 100,
1061
+ * // detectedFrom: [
1062
+ * // { type: 'package.json', field: 'dependencies.express' },
1063
+ * // { type: 'package.json', field: 'dependencies.@types/express' },
1064
+ * // { type: 'package.json', field: 'dependencies (express middleware)' },
1065
+ * // ],
1066
+ * // }
1067
+ * ```
1859
1068
  */
1860
1069
  function expressDetector(projectPath, packageJson) {
1861
1070
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1890,84 +1099,109 @@ function expressDetector(projectPath, packageJson) {
1890
1099
  }
1891
1100
 
1892
1101
  /**
1893
- * Detect NestJS in project.
1102
+ * Detect Fastify in project.
1894
1103
  *
1895
1104
  * @param projectPath - Project directory path
1896
1105
  * @param packageJson - Optional pre-loaded package.json
1897
1106
  * @returns Detection result or null if not detected
1107
+ * @example Detecting Fastify framework
1108
+ * ```typescript
1109
+ * const pkg = {
1110
+ * dependencies: { fastify: '^4.24.0', '@fastify/cors': '^8.4.0' },
1111
+ * }
1112
+ *
1113
+ * const result = fastifyDetector('/path/to/project', pkg)
1114
+ * // => {
1115
+ * // id: 'fastify',
1116
+ * // name: 'Fastify',
1117
+ * // version: '4.24.0',
1118
+ * // confidence: 95,
1119
+ * // detectedFrom: [
1120
+ * // { type: 'package.json', field: 'dependencies.fastify' },
1121
+ * // { type: 'package.json', field: 'dependencies (fastify plugins)' },
1122
+ * // ],
1123
+ * // }
1124
+ * ```
1898
1125
  */
1899
- function nestDetector(projectPath, packageJson) {
1126
+ function fastifyDetector(projectPath, packageJson) {
1900
1127
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1901
1128
  const sources = [];
1902
1129
  let confidence = 0;
1903
1130
  let version;
1904
- let configPath;
1905
1131
  const deps = collectAllDependencies(pkg);
1906
- if (deps['@nestjs/core']) {
1907
- confidence += 70;
1908
- version = parseVersionString(deps['@nestjs/core']);
1909
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1910
- }
1911
- if (deps['@nestjs/common']) {
1912
- confidence += 15;
1913
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
1132
+ if (deps['fastify']) {
1133
+ confidence += 80;
1134
+ version = parseVersionString(deps['fastify']);
1135
+ sources.push({ type: 'package.json', field: 'dependencies.fastify' });
1914
1136
  }
1915
- if (exists(join$1(projectPath, 'nest-cli.json'))) {
1137
+ const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1138
+ if (fastifyPlugins.length > 0) {
1916
1139
  confidence += 15;
1917
- configPath = 'nest-cli.json';
1918
- sources.push({ type: 'config-file', path: 'nest-cli.json' });
1140
+ sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1919
1141
  }
1920
- const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1921
- if (nestPackages.length > 2) {
1142
+ if (deps['@types/fastify']) {
1922
1143
  confidence += 5;
1923
- sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
1144
+ sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
1924
1145
  }
1925
1146
  if (confidence === 0) {
1926
1147
  return null;
1927
1148
  }
1928
1149
  return {
1929
- id: 'nestjs',
1930
- name: 'NestJS',
1150
+ id: 'fastify',
1151
+ name: 'Fastify',
1931
1152
  version,
1932
- configPath,
1933
1153
  confidence: min(confidence, 100),
1934
1154
  detectedFrom: sources,
1935
1155
  };
1936
1156
  }
1937
1157
 
1938
1158
  /**
1939
- * Detect Fastify in project.
1159
+ * Detect Hono in project.
1940
1160
  *
1941
1161
  * @param projectPath - Project directory path
1942
1162
  * @param packageJson - Optional pre-loaded package.json
1943
1163
  * @returns Detection result or null if not detected
1164
+ * @example Detecting Hono framework
1165
+ * ```typescript
1166
+ * const pkg = {
1167
+ * dependencies: { hono: '^3.11.0', '@hono/node-server': '^1.3.0' },
1168
+ * }
1169
+ *
1170
+ * const result = honoDetector('/path/to/project', pkg)
1171
+ * // => {
1172
+ * // id: 'hono',
1173
+ * // name: 'Hono',
1174
+ * // version: '3.11.0',
1175
+ * // confidence: 100,
1176
+ * // detectedFrom: [
1177
+ * // { type: 'package.json', field: 'dependencies.hono' },
1178
+ * // { type: 'package.json', field: 'dependencies (@hono adapters)' },
1179
+ * // ],
1180
+ * // }
1181
+ * ```
1944
1182
  */
1945
- function fastifyDetector(projectPath, packageJson) {
1183
+ function honoDetector(projectPath, packageJson) {
1946
1184
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1947
1185
  const sources = [];
1948
1186
  let confidence = 0;
1949
1187
  let version;
1950
1188
  const deps = collectAllDependencies(pkg);
1951
- if (deps['fastify']) {
1952
- confidence += 80;
1953
- version = parseVersionString(deps['fastify']);
1954
- sources.push({ type: 'package.json', field: 'dependencies.fastify' });
1189
+ if (deps['hono']) {
1190
+ confidence += 85;
1191
+ version = parseVersionString(deps['hono']);
1192
+ sources.push({ type: 'package.json', field: 'dependencies.hono' });
1955
1193
  }
1956
- const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1957
- if (fastifyPlugins.length > 0) {
1194
+ const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
1195
+ if (honoAdapters.length > 0) {
1958
1196
  confidence += 15;
1959
- sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1960
- }
1961
- if (deps['@types/fastify']) {
1962
- confidence += 5;
1963
- sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
1197
+ sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1964
1198
  }
1965
1199
  if (confidence === 0) {
1966
1200
  return null;
1967
1201
  }
1968
1202
  return {
1969
- id: 'fastify',
1970
- name: 'Fastify',
1203
+ id: 'hono',
1204
+ name: 'Hono',
1971
1205
  version,
1972
1206
  confidence: min(confidence, 100),
1973
1207
  detectedFrom: sources,
@@ -1980,6 +1214,26 @@ function fastifyDetector(projectPath, packageJson) {
1980
1214
  * @param projectPath - Project directory path
1981
1215
  * @param packageJson - Optional pre-loaded package.json
1982
1216
  * @returns Detection result or null if not detected
1217
+ * @example Detecting Koa framework
1218
+ * ```typescript
1219
+ * const pkg = {
1220
+ * dependencies: { koa: '^2.14.2', 'koa-router': '^12.0.0' },
1221
+ * devDependencies: { '@types/koa': '^2.13.9' },
1222
+ * }
1223
+ *
1224
+ * const result = koaDetector('/path/to/project', pkg)
1225
+ * // => {
1226
+ * // id: 'koa',
1227
+ * // name: 'Koa',
1228
+ * // version: '2.14.2',
1229
+ * // confidence: 100,
1230
+ * // detectedFrom: [
1231
+ * // { type: 'package.json', field: 'dependencies.koa' },
1232
+ * // { type: 'package.json', field: 'dependencies.@types/koa' },
1233
+ * // { type: 'package.json', field: 'dependencies (koa middleware)' },
1234
+ * // ],
1235
+ * // }
1236
+ * ```
1983
1237
  */
1984
1238
  function koaDetector(projectPath, packageJson) {
1985
1239
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2014,35 +1268,72 @@ function koaDetector(projectPath, packageJson) {
2014
1268
  }
2015
1269
 
2016
1270
  /**
2017
- * Detect Hono in project.
1271
+ * Detect NestJS in project.
2018
1272
  *
2019
1273
  * @param projectPath - Project directory path
2020
1274
  * @param packageJson - Optional pre-loaded package.json
2021
1275
  * @returns Detection result or null if not detected
1276
+ * @example Detecting NestJS framework
1277
+ * ```typescript
1278
+ * // Project with nest-cli.json and NestJS packages
1279
+ * const pkg = {
1280
+ * dependencies: {
1281
+ * '@nestjs/core': '^10.2.0',
1282
+ * '@nestjs/common': '^10.2.0',
1283
+ * '@nestjs/platform-express': '^10.2.0',
1284
+ * },
1285
+ * }
1286
+ *
1287
+ * const result = nestDetector('/path/to/nest-project', pkg)
1288
+ * // => {
1289
+ * // id: 'nestjs',
1290
+ * // name: 'NestJS',
1291
+ * // version: '10.2.0',
1292
+ * // configPath: 'nest-cli.json', // if present
1293
+ * // confidence: 100,
1294
+ * // detectedFrom: [
1295
+ * // { type: 'package.json', field: 'dependencies.@nestjs/core' },
1296
+ * // { type: 'package.json', field: 'dependencies.@nestjs/common' },
1297
+ * // { type: 'config-file', path: 'nest-cli.json' },
1298
+ * // { type: 'package.json', field: 'dependencies (@nestjs packages)' },
1299
+ * // ],
1300
+ * // }
1301
+ * ```
2022
1302
  */
2023
- function honoDetector(projectPath, packageJson) {
1303
+ function nestDetector(projectPath, packageJson) {
2024
1304
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2025
1305
  const sources = [];
2026
1306
  let confidence = 0;
2027
1307
  let version;
1308
+ let configPath;
2028
1309
  const deps = collectAllDependencies(pkg);
2029
- if (deps['hono']) {
2030
- confidence += 85;
2031
- version = parseVersionString(deps['hono']);
2032
- sources.push({ type: 'package.json', field: 'dependencies.hono' });
1310
+ if (deps['@nestjs/core']) {
1311
+ confidence += 70;
1312
+ version = parseVersionString(deps['@nestjs/core']);
1313
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
2033
1314
  }
2034
- const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
2035
- if (honoAdapters.length > 0) {
1315
+ if (deps['@nestjs/common']) {
2036
1316
  confidence += 15;
2037
- sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1317
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
1318
+ }
1319
+ if (exists(join$1(projectPath, 'nest-cli.json'))) {
1320
+ confidence += 15;
1321
+ configPath = 'nest-cli.json';
1322
+ sources.push({ type: 'config-file', path: 'nest-cli.json' });
1323
+ }
1324
+ const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1325
+ if (nestPackages.length > 2) {
1326
+ confidence += 5;
1327
+ sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
2038
1328
  }
2039
1329
  if (confidence === 0) {
2040
1330
  return null;
2041
1331
  }
2042
1332
  return {
2043
- id: 'hono',
2044
- name: 'Hono',
1333
+ id: 'nestjs',
1334
+ name: 'NestJS',
2045
1335
  version,
1336
+ configPath,
2046
1337
  confidence: min(confidence, 100),
2047
1338
  detectedFrom: sources,
2048
1339
  };
@@ -2057,99 +1348,64 @@ const backendDetectors = [
2057
1348
  { id: 'hono', name: 'Hono', detect: honoDetector },
2058
1349
  ];
2059
1350
 
2060
- /** Config patterns for Webpack */
2061
- const WEBPACK_CONFIG_PATTERNS = [
2062
- 'webpack.config.js',
2063
- 'webpack.config.ts',
2064
- 'webpack.config.cjs',
2065
- 'webpack.config.mjs',
2066
- 'webpack.config.babel.js',
2067
- ];
1351
+ /** Config patterns for Babel */
1352
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
2068
1353
  /**
2069
- * Detect Webpack in project.
1354
+ * Detect Babel in project.
2070
1355
  *
2071
1356
  * @param projectPath - Project directory path
2072
1357
  * @param packageJson - Optional pre-loaded package.json
2073
1358
  * @returns Detection result or null if not detected
1359
+ *
1360
+ * @example Detecting Babel compiler
1361
+ * ```typescript
1362
+ * const result = babelDetector('/path/to/project', {
1363
+ * name: 'my-app',
1364
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
1365
+ * })
1366
+ * // => {
1367
+ * // id: 'babel',
1368
+ * // name: 'Babel',
1369
+ * // version: '7.23.0',
1370
+ * // confidence: 60,
1371
+ * // detectedFrom: [
1372
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
1373
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
1374
+ * // ]
1375
+ * // }
1376
+ * ```
2074
1377
  */
2075
- function webpackDetector(projectPath, packageJson) {
1378
+ function babelDetector(projectPath, packageJson) {
2076
1379
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2077
1380
  const sources = [];
2078
1381
  let confidence = 0;
2079
1382
  let version;
2080
1383
  const deps = collectAllDependencies(pkg);
2081
- if (deps['webpack']) {
1384
+ if (deps['@babel/core']) {
2082
1385
  confidence += 50;
2083
- version = parseVersionString(deps['webpack']);
2084
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1386
+ version = parseVersionString(deps['@babel/core']);
1387
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
2085
1388
  }
2086
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1389
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
2087
1390
  if (configPath) {
2088
1391
  confidence += 40;
2089
1392
  sources.push({ type: 'config-file', path: configPath });
2090
1393
  }
2091
- if (deps['webpack-cli']) {
2092
- confidence += 10;
2093
- sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
2094
- }
2095
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
2096
- for (const name of scriptMatches) {
2097
- confidence = min(confidence + 5, 100);
2098
- sources.push({ type: 'package.json', field: `scripts.${name}` });
2099
- }
2100
- if (confidence === 0) {
2101
- return null;
2102
- }
2103
- return {
2104
- id: 'webpack',
2105
- name: 'Webpack',
2106
- version,
2107
- configPath,
2108
- confidence: min(confidence, 100),
2109
- detectedFrom: sources,
2110
- };
2111
- }
2112
-
2113
- /** Config patterns for Vite */
2114
- const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
2115
- /**
2116
- * Detect Vite in project.
2117
- *
2118
- * @param projectPath - Project directory path
2119
- * @param packageJson - Optional pre-loaded package.json
2120
- * @returns Detection result or null if not detected
2121
- */
2122
- function viteDetector(projectPath, packageJson) {
2123
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2124
- const sources = [];
2125
- let confidence = 0;
2126
- let version;
2127
- const deps = collectAllDependencies(pkg);
2128
- if (deps['vite']) {
2129
- confidence += 60;
2130
- version = parseVersionString(deps['vite']);
2131
- sources.push({ type: 'package.json', field: 'dependencies.vite' });
2132
- }
2133
- const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
2134
- if (configPath) {
2135
- confidence += 35;
2136
- sources.push({ type: 'config-file', path: configPath });
2137
- }
2138
- if (deps['vitest']) {
2139
- confidence += 10;
2140
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1394
+ if (pkg && 'babel' in pkg) {
1395
+ confidence += 30;
1396
+ sources.push({ type: 'package.json', field: 'babel' });
2141
1397
  }
2142
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
2143
- if (vitePlugins.length > 0) {
1398
+ const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1399
+ if (babelPackages.length > 1) {
2144
1400
  confidence += 10;
2145
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1401
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
2146
1402
  }
2147
1403
  if (confidence === 0) {
2148
1404
  return null;
2149
1405
  }
2150
1406
  return {
2151
- id: 'vite',
2152
- name: 'Vite',
1407
+ id: 'babel',
1408
+ name: 'Babel',
2153
1409
  version,
2154
1410
  configPath,
2155
1411
  confidence: min(confidence, 100),
@@ -2157,78 +1413,116 @@ function viteDetector(projectPath, packageJson) {
2157
1413
  };
2158
1414
  }
2159
1415
 
2160
- /** Config patterns for Rollup */
2161
- const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
2162
1416
  /**
2163
- * Detect Rollup in project.
1417
+ * Detect esbuild in project.
2164
1418
  *
2165
1419
  * @param projectPath - Project directory path
2166
1420
  * @param packageJson - Optional pre-loaded package.json
2167
1421
  * @returns Detection result or null if not detected
1422
+ *
1423
+ * @example Detecting esbuild bundler
1424
+ * ```typescript
1425
+ * const result = esbuildDetector('/path/to/project', {
1426
+ * name: 'my-lib',
1427
+ * devDependencies: { 'esbuild': '^0.19.0' },
1428
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
1429
+ * })
1430
+ * // => {
1431
+ * // id: 'esbuild',
1432
+ * // name: 'esbuild',
1433
+ * // version: '0.19.0',
1434
+ * // confidence: 80,
1435
+ * // detectedFrom: [
1436
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
1437
+ * // { type: 'package.json', field: 'scripts.build' }
1438
+ * // ]
1439
+ * // }
1440
+ * ```
2168
1441
  */
2169
- function rollupDetector(projectPath, packageJson) {
1442
+ function esbuildDetector(projectPath, packageJson) {
2170
1443
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2171
1444
  const sources = [];
2172
1445
  let confidence = 0;
2173
1446
  let version;
2174
1447
  const deps = collectAllDependencies(pkg);
2175
- if (deps['rollup']) {
2176
- confidence += 55;
2177
- version = parseVersionString(deps['rollup']);
2178
- sources.push({ type: 'package.json', field: 'dependencies.rollup' });
2179
- }
2180
- const configPath = locateConfigFile(projectPath, ROLLUP_CONFIG_PATTERNS);
2181
- if (configPath) {
2182
- confidence += 40;
2183
- sources.push({ type: 'config-file', path: configPath });
1448
+ if (deps['esbuild']) {
1449
+ confidence += 70;
1450
+ version = parseVersionString(deps['esbuild']);
1451
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
2184
1452
  }
2185
- const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
2186
- if (rollupPlugins.length > 0) {
2187
- confidence += 10;
2188
- sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1453
+ const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1454
+ if (esbuildPlugins.length > 0) {
1455
+ confidence += 15;
1456
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
2189
1457
  }
2190
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1458
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
2191
1459
  for (const name of scriptMatches) {
2192
- confidence = min(confidence + 5, 100);
1460
+ confidence = min(confidence + 10, 100);
2193
1461
  sources.push({ type: 'package.json', field: `scripts.${name}` });
2194
1462
  }
2195
1463
  if (confidence === 0) {
2196
1464
  return null;
2197
1465
  }
2198
1466
  return {
2199
- id: 'rollup',
2200
- name: 'Rollup',
1467
+ id: 'esbuild',
1468
+ name: 'esbuild',
2201
1469
  version,
2202
- configPath,
2203
1470
  confidence: min(confidence, 100),
2204
1471
  detectedFrom: sources,
2205
1472
  };
2206
1473
  }
2207
1474
 
1475
+ /** Config patterns for Parcel */
1476
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
2208
1477
  /**
2209
- * Detect esbuild in project.
1478
+ * Detect Parcel in project.
2210
1479
  *
2211
1480
  * @param projectPath - Project directory path
2212
1481
  * @param packageJson - Optional pre-loaded package.json
2213
1482
  * @returns Detection result or null if not detected
1483
+ *
1484
+ * @example Detecting Parcel bundler
1485
+ * ```typescript
1486
+ * const result = parcelDetector('/path/to/project', {
1487
+ * name: 'my-app',
1488
+ * devDependencies: { 'parcel': '^2.10.0' },
1489
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
1490
+ * })
1491
+ * // => {
1492
+ * // id: 'parcel',
1493
+ * // name: 'Parcel',
1494
+ * // version: '2.10.0',
1495
+ * // confidence: 80,
1496
+ * // detectedFrom: [
1497
+ * // { type: 'package.json', field: 'dependencies.parcel' },
1498
+ * // { type: 'package.json', field: 'scripts.dev' },
1499
+ * // { type: 'package.json', field: 'scripts.build' }
1500
+ * // ]
1501
+ * // }
1502
+ * ```
2214
1503
  */
2215
- function esbuildDetector(projectPath, packageJson) {
1504
+ function parcelDetector(projectPath, packageJson) {
2216
1505
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2217
1506
  const sources = [];
2218
1507
  let confidence = 0;
2219
1508
  let version;
2220
1509
  const deps = collectAllDependencies(pkg);
2221
- if (deps['esbuild']) {
2222
- confidence += 70;
2223
- version = parseVersionString(deps['esbuild']);
2224
- sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
1510
+ if (deps['parcel']) {
1511
+ confidence += 60;
1512
+ version = parseVersionString(deps['parcel']);
1513
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
2225
1514
  }
2226
- const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
2227
- if (esbuildPlugins.length > 0) {
2228
- confidence += 15;
2229
- sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
1515
+ if (deps['parcel-bundler']) {
1516
+ confidence += 60;
1517
+ version = parseVersionString(deps['parcel-bundler']);
1518
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
2230
1519
  }
2231
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1520
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1521
+ if (configPath) {
1522
+ confidence += 30;
1523
+ sources.push({ type: 'config-file', path: configPath });
1524
+ }
1525
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
2232
1526
  for (const name of scriptMatches) {
2233
1527
  confidence = min(confidence + 10, 100);
2234
1528
  sources.push({ type: 'package.json', field: `scripts.${name}` });
@@ -2237,54 +1531,78 @@ function esbuildDetector(projectPath, packageJson) {
2237
1531
  return null;
2238
1532
  }
2239
1533
  return {
2240
- id: 'esbuild',
2241
- name: 'esbuild',
1534
+ id: 'parcel',
1535
+ name: 'Parcel',
2242
1536
  version,
1537
+ configPath,
2243
1538
  confidence: min(confidence, 100),
2244
1539
  detectedFrom: sources,
2245
1540
  };
2246
1541
  }
2247
1542
 
2248
- /** Config patterns for Babel */
2249
- const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1543
+ /** Config patterns for Rollup */
1544
+ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
2250
1545
  /**
2251
- * Detect Babel in project.
1546
+ * Detect Rollup in project.
2252
1547
  *
2253
1548
  * @param projectPath - Project directory path
2254
1549
  * @param packageJson - Optional pre-loaded package.json
2255
1550
  * @returns Detection result or null if not detected
1551
+ *
1552
+ * @example Detecting Rollup bundler
1553
+ * ```typescript
1554
+ * const result = rollupDetector('/path/to/project', {
1555
+ * name: 'my-lib',
1556
+ * devDependencies: {
1557
+ * 'rollup': '^4.0.0',
1558
+ * '@rollup/plugin-node-resolve': '^15.0.0',
1559
+ * '@rollup/plugin-commonjs': '^25.0.0'
1560
+ * }
1561
+ * })
1562
+ * // => {
1563
+ * // id: 'rollup',
1564
+ * // name: 'Rollup',
1565
+ * // version: '4.0.0',
1566
+ * // confidence: 65,
1567
+ * // detectedFrom: [
1568
+ * // { type: 'package.json', field: 'dependencies.rollup' },
1569
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
1570
+ * // ]
1571
+ * // }
1572
+ * ```
2256
1573
  */
2257
- function babelDetector(projectPath, packageJson) {
1574
+ function rollupDetector(projectPath, packageJson) {
2258
1575
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2259
1576
  const sources = [];
2260
1577
  let confidence = 0;
2261
1578
  let version;
2262
1579
  const deps = collectAllDependencies(pkg);
2263
- if (deps['@babel/core']) {
2264
- confidence += 50;
2265
- version = parseVersionString(deps['@babel/core']);
2266
- sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1580
+ if (deps['rollup']) {
1581
+ confidence += 55;
1582
+ version = parseVersionString(deps['rollup']);
1583
+ sources.push({ type: 'package.json', field: 'dependencies.rollup' });
2267
1584
  }
2268
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1585
+ const configPath = locateConfigFile(projectPath, ROLLUP_CONFIG_PATTERNS);
2269
1586
  if (configPath) {
2270
1587
  confidence += 40;
2271
1588
  sources.push({ type: 'config-file', path: configPath });
2272
1589
  }
2273
- if (pkg && 'babel' in pkg) {
2274
- confidence += 30;
2275
- sources.push({ type: 'package.json', field: 'babel' });
2276
- }
2277
- const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
2278
- if (babelPackages.length > 1) {
1590
+ const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1591
+ if (rollupPlugins.length > 0) {
2279
1592
  confidence += 10;
2280
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1593
+ sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1594
+ }
1595
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1596
+ for (const name of scriptMatches) {
1597
+ confidence = min(confidence + 5, 100);
1598
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
2281
1599
  }
2282
1600
  if (confidence === 0) {
2283
1601
  return null;
2284
1602
  }
2285
1603
  return {
2286
- id: 'babel',
2287
- name: 'Babel',
1604
+ id: 'rollup',
1605
+ name: 'Rollup',
2288
1606
  version,
2289
1607
  configPath,
2290
1608
  confidence: min(confidence, 100),
@@ -2300,6 +1618,24 @@ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
2300
1618
  * @param projectPath - Project directory path
2301
1619
  * @param packageJson - Optional pre-loaded package.json
2302
1620
  * @returns Detection result or null if not detected
1621
+ *
1622
+ * @example Detecting SWC compiler
1623
+ * ```typescript
1624
+ * const result = swcDetector('/path/to/project', {
1625
+ * name: 'my-app',
1626
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
1627
+ * })
1628
+ * // => {
1629
+ * // id: 'swc',
1630
+ * // name: 'SWC',
1631
+ * // version: '1.3.0',
1632
+ * // confidence: 70,
1633
+ * // detectedFrom: [
1634
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
1635
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
1636
+ * // ]
1637
+ * // }
1638
+ * ```
2303
1639
  */
2304
1640
  function swcDetector(projectPath, packageJson) {
2305
1641
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2339,47 +1675,142 @@ function swcDetector(projectPath, packageJson) {
2339
1675
  };
2340
1676
  }
2341
1677
 
2342
- /** Config patterns for Parcel */
2343
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1678
+ /** Config patterns for Vite */
1679
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
2344
1680
  /**
2345
- * Detect Parcel in project.
1681
+ * Detect Vite in project.
2346
1682
  *
2347
1683
  * @param projectPath - Project directory path
2348
1684
  * @param packageJson - Optional pre-loaded package.json
2349
1685
  * @returns Detection result or null if not detected
1686
+ *
1687
+ * @example Detecting Vite build tool
1688
+ * ```typescript
1689
+ * const result = viteDetector('/path/to/project', {
1690
+ * name: 'my-app',
1691
+ * devDependencies: {
1692
+ * 'vite': '^5.0.0',
1693
+ * '@vitejs/plugin-react': '^4.0.0',
1694
+ * 'vitest': '^1.0.0'
1695
+ * }
1696
+ * })
1697
+ * // => {
1698
+ * // id: 'vite',
1699
+ * // name: 'Vite',
1700
+ * // version: '5.0.0',
1701
+ * // confidence: 80,
1702
+ * // detectedFrom: [
1703
+ * // { type: 'package.json', field: 'dependencies.vite' },
1704
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1705
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1706
+ * // ]
1707
+ * // }
1708
+ * ```
2350
1709
  */
2351
- function parcelDetector(projectPath, packageJson) {
1710
+ function viteDetector(projectPath, packageJson) {
2352
1711
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2353
1712
  const sources = [];
2354
1713
  let confidence = 0;
2355
1714
  let version;
2356
1715
  const deps = collectAllDependencies(pkg);
2357
- if (deps['parcel']) {
2358
- confidence += 60;
2359
- version = parseVersionString(deps['parcel']);
2360
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
2361
- }
2362
- if (deps['parcel-bundler']) {
1716
+ if (deps['vite']) {
2363
1717
  confidence += 60;
2364
- version = parseVersionString(deps['parcel-bundler']);
2365
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1718
+ version = parseVersionString(deps['vite']);
1719
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
2366
1720
  }
2367
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1721
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
2368
1722
  if (configPath) {
2369
- confidence += 30;
1723
+ confidence += 35;
2370
1724
  sources.push({ type: 'config-file', path: configPath });
2371
1725
  }
2372
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
2373
- for (const name of scriptMatches) {
2374
- confidence = min(confidence + 10, 100);
1726
+ if (deps['vitest']) {
1727
+ confidence += 10;
1728
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1729
+ }
1730
+ const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1731
+ if (vitePlugins.length > 0) {
1732
+ confidence += 10;
1733
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1734
+ }
1735
+ if (confidence === 0) {
1736
+ return null;
1737
+ }
1738
+ return {
1739
+ id: 'vite',
1740
+ name: 'Vite',
1741
+ version,
1742
+ configPath,
1743
+ confidence: min(confidence, 100),
1744
+ detectedFrom: sources,
1745
+ };
1746
+ }
1747
+
1748
+ /** Config patterns for Webpack */
1749
+ const WEBPACK_CONFIG_PATTERNS = [
1750
+ 'webpack.config.js',
1751
+ 'webpack.config.ts',
1752
+ 'webpack.config.cjs',
1753
+ 'webpack.config.mjs',
1754
+ 'webpack.config.babel.js',
1755
+ ];
1756
+ /**
1757
+ * Detect Webpack in project.
1758
+ *
1759
+ * @param projectPath - Project directory path
1760
+ * @param packageJson - Optional pre-loaded package.json
1761
+ * @returns Detection result or null if not detected
1762
+ *
1763
+ * @example Detecting Webpack bundler
1764
+ * ```typescript
1765
+ * const result = webpackDetector('/path/to/project', {
1766
+ * name: 'my-app',
1767
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1768
+ * scripts: { 'build': 'webpack --mode production' }
1769
+ * })
1770
+ * // => {
1771
+ * // id: 'webpack',
1772
+ * // name: 'Webpack',
1773
+ * // version: '5.89.0',
1774
+ * // confidence: 65,
1775
+ * // detectedFrom: [
1776
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1777
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1778
+ * // { type: 'package.json', field: 'scripts.build' }
1779
+ * // ]
1780
+ * // }
1781
+ * ```
1782
+ */
1783
+ function webpackDetector(projectPath, packageJson) {
1784
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1785
+ const sources = [];
1786
+ let confidence = 0;
1787
+ let version;
1788
+ const deps = collectAllDependencies(pkg);
1789
+ if (deps['webpack']) {
1790
+ confidence += 50;
1791
+ version = parseVersionString(deps['webpack']);
1792
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1793
+ }
1794
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1795
+ if (configPath) {
1796
+ confidence += 40;
1797
+ sources.push({ type: 'config-file', path: configPath });
1798
+ }
1799
+ if (deps['webpack-cli']) {
1800
+ confidence += 10;
1801
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1802
+ }
1803
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1804
+ for (const name of scriptMatches) {
1805
+ confidence = min(confidence + 5, 100);
2375
1806
  sources.push({ type: 'package.json', field: `scripts.${name}` });
2376
1807
  }
2377
1808
  if (confidence === 0) {
2378
1809
  return null;
2379
1810
  }
2380
1811
  return {
2381
- id: 'parcel',
2382
- name: 'Parcel',
1812
+ id: 'webpack',
1813
+ name: 'Webpack',
2383
1814
  version,
2384
1815
  configPath,
2385
1816
  confidence: min(confidence, 100),
@@ -2399,81 +1830,187 @@ const buildToolDetectors = [
2399
1830
  ];
2400
1831
 
2401
1832
  /**
2402
- * Detect React in project.
1833
+ * Detect Angular in project.
2403
1834
  *
2404
1835
  * @param projectPath - Project directory path
2405
1836
  * @param packageJson - Optional pre-loaded package.json
2406
1837
  * @returns Detection result or null if not detected
1838
+ *
1839
+ * @example Detecting Angular framework
1840
+ * ```typescript
1841
+ * const result = angularDetector('/path/to/angular-app', {
1842
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1843
+ * })
1844
+ * // => {
1845
+ * // id: 'angular',
1846
+ * // name: 'Angular',
1847
+ * // category: 'frontend',
1848
+ * // version: '17.0.0',
1849
+ * // confidence: 85,
1850
+ * // detectedFrom: [
1851
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1852
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1853
+ * // ]
1854
+ * // }
1855
+ * ```
2407
1856
  */
2408
- function reactDetector(projectPath, packageJson) {
1857
+ function angularDetector(projectPath, packageJson) {
2409
1858
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2410
1859
  const sources = [];
2411
1860
  let confidence = 0;
2412
1861
  let version;
2413
- const metaFrameworks = [];
2414
1862
  const deps = collectAllDependencies(pkg);
2415
- if (deps['react']) {
2416
- confidence += 60;
2417
- version = parseVersionString(deps['react']);
2418
- sources.push({ type: 'package.json', field: 'dependencies.react' });
1863
+ if (deps['@angular/core']) {
1864
+ confidence += 70;
1865
+ version = parseVersionString(deps['@angular/core']);
1866
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
2419
1867
  }
2420
- if (deps['react-dom']) {
2421
- confidence += 20;
2422
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1868
+ if (deps['@angular/cli']) {
1869
+ confidence += 15;
1870
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
2423
1871
  }
2424
- if (deps['react-native']) {
2425
- confidence += 20;
2426
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1872
+ if (exists(join$1(projectPath, 'angular.json'))) {
1873
+ confidence += 15;
1874
+ sources.push({ type: 'config-file', path: 'angular.json' });
2427
1875
  }
2428
- const hasJsxFiles = exists(join$1(projectPath, 'src', 'App.tsx')) ||
2429
- exists(join$1(projectPath, 'src', 'App.jsx')) ||
2430
- exists(join$1(projectPath, 'src', 'index.tsx')) ||
2431
- exists(join$1(projectPath, 'src', 'index.jsx'));
2432
- if (hasJsxFiles) {
2433
- confidence += 10;
2434
- sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1876
+ if (deps['angular'] && !deps['@angular/core']) {
1877
+ return {
1878
+ id: 'angularjs',
1879
+ name: 'AngularJS (Legacy)',
1880
+ category: 'frontend',
1881
+ version: parseVersionString(deps['angular']),
1882
+ confidence: 80,
1883
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1884
+ };
2435
1885
  }
2436
- if (deps['next']) {
2437
- metaFrameworks.push({
2438
- id: 'nextjs',
2439
- name: 'Next.js',
2440
- category: 'meta-framework',
2441
- version: parseVersionString(deps['next']),
2442
- confidence: 90,
2443
- detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
2444
- });
1886
+ if (confidence === 0) {
1887
+ return null;
1888
+ }
1889
+ return {
1890
+ id: 'angular',
1891
+ name: 'Angular',
1892
+ category: 'frontend',
1893
+ version,
1894
+ confidence: min(confidence, 100),
1895
+ detectedFrom: sources,
1896
+ };
1897
+ }
1898
+
1899
+ /**
1900
+ * Detect Astro in project.
1901
+ *
1902
+ * @param projectPath - Project directory path
1903
+ * @param packageJson - Optional pre-loaded package.json
1904
+ * @returns Detection result or null if not detected
1905
+ *
1906
+ * @example Detecting Astro framework
1907
+ * ```typescript
1908
+ * const result = astroDetector('/path/to/astro-project', {
1909
+ * dependencies: { 'astro': '^4.0.0' }
1910
+ * })
1911
+ * // => {
1912
+ * // id: 'astro',
1913
+ * // name: 'Astro',
1914
+ * // category: 'meta-framework',
1915
+ * // version: '4.0.0',
1916
+ * // confidence: 70,
1917
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1918
+ * // }
1919
+ * ```
1920
+ */
1921
+ function astroDetector(projectPath, packageJson) {
1922
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1923
+ const sources = [];
1924
+ let confidence = 0;
1925
+ let version;
1926
+ const deps = collectAllDependencies(pkg);
1927
+ if (deps['astro']) {
1928
+ confidence += 70;
1929
+ version = parseVersionString(deps['astro']);
1930
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1931
+ }
1932
+ if (exists(join$1(projectPath, 'astro.config.mjs')) ||
1933
+ exists(join$1(projectPath, 'astro.config.ts')) ||
1934
+ exists(join$1(projectPath, 'astro.config.js'))) {
1935
+ confidence += 25;
1936
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
2445
1937
  }
1938
+ if (exists(join$1(projectPath, 'src', 'pages'))) {
1939
+ confidence += 5;
1940
+ sources.push({ type: 'directory', path: 'src/pages/' });
1941
+ }
1942
+ if (confidence === 0) {
1943
+ return null;
1944
+ }
1945
+ return {
1946
+ id: 'astro',
1947
+ name: 'Astro',
1948
+ category: 'meta-framework',
1949
+ version,
1950
+ confidence: min(confidence, 100),
1951
+ detectedFrom: sources,
1952
+ };
1953
+ }
1954
+
1955
+ /**
1956
+ * Detect Gatsby in project.
1957
+ *
1958
+ * @param projectPath - Project directory path
1959
+ * @param packageJson - Optional pre-loaded package.json
1960
+ * @returns Detection result or null if not detected
1961
+ *
1962
+ * @example Detecting Gatsby framework
1963
+ * ```typescript
1964
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1965
+ * dependencies: {
1966
+ * 'gatsby': '^5.0.0',
1967
+ * 'gatsby-plugin-image': '^3.0.0',
1968
+ * 'gatsby-source-filesystem': '^5.0.0'
1969
+ * }
1970
+ * })
1971
+ * // => {
1972
+ * // id: 'gatsby',
1973
+ * // name: 'Gatsby',
1974
+ * // category: 'meta-framework',
1975
+ * // version: '5.0.0',
1976
+ * // confidence: 75,
1977
+ * // detectedFrom: [
1978
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1979
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1980
+ * // ]
1981
+ * // }
1982
+ * ```
1983
+ */
1984
+ function gatsbyDetector(projectPath, packageJson) {
1985
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1986
+ const sources = [];
1987
+ let confidence = 0;
1988
+ let version;
1989
+ const deps = collectAllDependencies(pkg);
2446
1990
  if (deps['gatsby']) {
2447
- metaFrameworks.push({
2448
- id: 'gatsby',
2449
- name: 'Gatsby',
2450
- category: 'meta-framework',
2451
- version: parseVersionString(deps['gatsby']),
2452
- confidence: 90,
2453
- detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
2454
- });
1991
+ confidence += 70;
1992
+ version = parseVersionString(deps['gatsby']);
1993
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
2455
1994
  }
2456
- if (deps['@remix-run/react'] || deps['remix']) {
2457
- metaFrameworks.push({
2458
- id: 'remix',
2459
- name: 'Remix',
2460
- category: 'meta-framework',
2461
- version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
2462
- confidence: 90,
2463
- detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
2464
- });
1995
+ if (exists(join$1(projectPath, 'gatsby-config.js')) || exists(join$1(projectPath, 'gatsby-config.ts'))) {
1996
+ confidence += 25;
1997
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1998
+ }
1999
+ const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
2000
+ if (gatsbyPlugins.length > 0) {
2001
+ confidence += 5;
2002
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
2465
2003
  }
2466
2004
  if (confidence === 0) {
2467
2005
  return null;
2468
2006
  }
2469
2007
  return {
2470
- id: 'react',
2471
- name: 'React',
2472
- category: 'frontend',
2008
+ id: 'gatsby',
2009
+ name: 'Gatsby',
2010
+ category: 'meta-framework',
2473
2011
  version,
2474
2012
  confidence: min(confidence, 100),
2475
2013
  detectedFrom: sources,
2476
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2477
2014
  };
2478
2015
  }
2479
2016
 
@@ -2483,6 +2020,21 @@ function reactDetector(projectPath, packageJson) {
2483
2020
  * @param projectPath - Project directory path
2484
2021
  * @param packageJson - Optional pre-loaded package.json
2485
2022
  * @returns Detection result or null if not detected
2023
+ *
2024
+ * @example Detecting Next.js framework
2025
+ * ```typescript
2026
+ * const result = nextjsDetector('/path/to/nextjs-app', {
2027
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
2028
+ * })
2029
+ * // => {
2030
+ * // id: 'nextjs',
2031
+ * // name: 'Next.js',
2032
+ * // category: 'meta-framework',
2033
+ * // version: '14.0.0',
2034
+ * // confidence: 70,
2035
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
2036
+ * // }
2037
+ * ```
2486
2038
  */
2487
2039
  function nextjsDetector(projectPath, packageJson) {
2488
2040
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2522,37 +2074,52 @@ function nextjsDetector(projectPath, packageJson) {
2522
2074
  }
2523
2075
 
2524
2076
  /**
2525
- * Detect Remix in project.
2077
+ * Detect Nuxt in project.
2526
2078
  *
2527
2079
  * @param projectPath - Project directory path
2528
2080
  * @param packageJson - Optional pre-loaded package.json
2529
2081
  * @returns Detection result or null if not detected
2082
+ *
2083
+ * @example Detecting Nuxt framework
2084
+ * ```typescript
2085
+ * const result = nuxtDetector('/path/to/nuxt-app', {
2086
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
2087
+ * })
2088
+ * // => {
2089
+ * // id: 'nuxt',
2090
+ * // name: 'Nuxt',
2091
+ * // category: 'meta-framework',
2092
+ * // version: '3.0.0',
2093
+ * // confidence: 70,
2094
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
2095
+ * // }
2096
+ * ```
2530
2097
  */
2531
- function remixDetector(projectPath, packageJson) {
2098
+ function nuxtDetector(projectPath, packageJson) {
2532
2099
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2533
2100
  const sources = [];
2534
2101
  let confidence = 0;
2535
2102
  let version;
2536
2103
  const deps = collectAllDependencies(pkg);
2537
- if (deps['@remix-run/react']) {
2104
+ if (deps['nuxt'] || deps['nuxt3']) {
2538
2105
  confidence += 70;
2539
- version = parseVersionString(deps['@remix-run/react']);
2540
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
2106
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
2107
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
2541
2108
  }
2542
- if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
2543
- confidence += 20;
2544
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
2109
+ if (exists(join$1(projectPath, 'nuxt.config.js')) || exists(join$1(projectPath, 'nuxt.config.ts'))) {
2110
+ confidence += 25;
2111
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
2545
2112
  }
2546
- if (exists(join$1(projectPath, 'remix.config.js')) || exists(join$1(projectPath, 'remix.config.ts'))) {
2547
- confidence += 10;
2548
- sources.push({ type: 'config-file', path: 'remix.config.*' });
2113
+ if (exists(join$1(projectPath, 'pages'))) {
2114
+ confidence += 5;
2115
+ sources.push({ type: 'directory', path: 'pages/' });
2549
2116
  }
2550
2117
  if (confidence === 0) {
2551
2118
  return null;
2552
2119
  }
2553
2120
  return {
2554
- id: 'remix',
2555
- name: 'Remix',
2121
+ id: 'nuxt',
2122
+ name: 'Nuxt',
2556
2123
  category: 'meta-framework',
2557
2124
  version,
2558
2125
  confidence: min(confidence, 100),
@@ -2561,39 +2128,59 @@ function remixDetector(projectPath, packageJson) {
2561
2128
  }
2562
2129
 
2563
2130
  /**
2564
- * Detect Gatsby in project.
2131
+ * Detect Qwik in project.
2565
2132
  *
2566
2133
  * @param projectPath - Project directory path
2567
2134
  * @param packageJson - Optional pre-loaded package.json
2568
2135
  * @returns Detection result or null if not detected
2136
+ *
2137
+ * @example Detecting Qwik framework
2138
+ * ```typescript
2139
+ * const result = qwikDetector('/path/to/qwik-app', {
2140
+ * dependencies: {
2141
+ * '@builder.io/qwik': '^1.0.0',
2142
+ * '@builder.io/qwik-city': '^1.0.0'
2143
+ * }
2144
+ * })
2145
+ * // => {
2146
+ * // id: 'qwik',
2147
+ * // name: 'Qwik',
2148
+ * // category: 'frontend',
2149
+ * // version: '1.0.0',
2150
+ * // confidence: 90,
2151
+ * // detectedFrom: [
2152
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
2153
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
2154
+ * // ]
2155
+ * // }
2156
+ * ```
2569
2157
  */
2570
- function gatsbyDetector(projectPath, packageJson) {
2158
+ function qwikDetector(projectPath, packageJson) {
2571
2159
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2572
2160
  const sources = [];
2573
2161
  let confidence = 0;
2574
2162
  let version;
2575
2163
  const deps = collectAllDependencies(pkg);
2576
- if (deps['gatsby']) {
2164
+ if (deps['@builder.io/qwik']) {
2577
2165
  confidence += 70;
2578
- version = parseVersionString(deps['gatsby']);
2579
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
2166
+ version = parseVersionString(deps['@builder.io/qwik']);
2167
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2580
2168
  }
2581
- if (exists(join$1(projectPath, 'gatsby-config.js')) || exists(join$1(projectPath, 'gatsby-config.ts'))) {
2582
- confidence += 25;
2583
- sources.push({ type: 'config-file', path: 'gatsby-config.*' });
2169
+ if (deps['@builder.io/qwik-city']) {
2170
+ confidence += 20;
2171
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
2584
2172
  }
2585
- const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
2586
- if (gatsbyPlugins.length > 0) {
2587
- confidence += 5;
2588
- sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
2173
+ if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
2174
+ confidence += 10;
2175
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
2589
2176
  }
2590
2177
  if (confidence === 0) {
2591
2178
  return null;
2592
2179
  }
2593
2180
  return {
2594
- id: 'gatsby',
2595
- name: 'Gatsby',
2596
- category: 'meta-framework',
2181
+ id: 'qwik',
2182
+ name: 'Qwik',
2183
+ category: 'frontend',
2597
2184
  version,
2598
2185
  confidence: min(confidence, 100),
2599
2186
  detectedFrom: sources,
@@ -2601,53 +2188,94 @@ function gatsbyDetector(projectPath, packageJson) {
2601
2188
  }
2602
2189
 
2603
2190
  /**
2604
- * Detect Vue in project.
2191
+ * Detect React in project.
2605
2192
  *
2606
2193
  * @param projectPath - Project directory path
2607
2194
  * @param packageJson - Optional pre-loaded package.json
2608
2195
  * @returns Detection result or null if not detected
2196
+ *
2197
+ * @example Detecting React library
2198
+ * ```typescript
2199
+ * const result = reactDetector('/path/to/react-app', {
2200
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
2201
+ * })
2202
+ * // => {
2203
+ * // id: 'react',
2204
+ * // name: 'React',
2205
+ * // category: 'frontend',
2206
+ * // version: '18.0.0',
2207
+ * // confidence: 80,
2208
+ * // detectedFrom: [
2209
+ * // { type: 'package.json', field: 'dependencies.react' },
2210
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
2211
+ * // ]
2212
+ * // }
2213
+ * ```
2609
2214
  */
2610
- function vueDetector(projectPath, packageJson) {
2215
+ function reactDetector(projectPath, packageJson) {
2611
2216
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2612
2217
  const sources = [];
2613
2218
  let confidence = 0;
2614
2219
  let version;
2615
2220
  const metaFrameworks = [];
2616
2221
  const deps = collectAllDependencies(pkg);
2617
- if (deps['vue']) {
2618
- confidence += 70;
2619
- version = parseVersionString(deps['vue']);
2620
- sources.push({ type: 'package.json', field: 'dependencies.vue' });
2222
+ if (deps['react']) {
2223
+ confidence += 60;
2224
+ version = parseVersionString(deps['react']);
2225
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
2621
2226
  }
2622
- if (deps['@vue/cli-service']) {
2623
- confidence += 15;
2624
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2227
+ if (deps['react-dom']) {
2228
+ confidence += 20;
2229
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
2625
2230
  }
2626
- const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
2627
- if (hasVueFiles) {
2231
+ if (deps['react-native']) {
2232
+ confidence += 20;
2233
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
2234
+ }
2235
+ const hasJsxFiles = exists(join$1(projectPath, 'src', 'App.tsx')) ||
2236
+ exists(join$1(projectPath, 'src', 'App.jsx')) ||
2237
+ exists(join$1(projectPath, 'src', 'index.tsx')) ||
2238
+ exists(join$1(projectPath, 'src', 'index.jsx'));
2239
+ if (hasJsxFiles) {
2628
2240
  confidence += 10;
2629
- sources.push({ type: 'directory', path: 'src/*.vue' });
2241
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
2630
2242
  }
2631
- if (exists(join$1(projectPath, 'vue.config.js'))) {
2632
- confidence += 5;
2633
- sources.push({ type: 'config-file', path: 'vue.config.js' });
2243
+ if (deps['next']) {
2244
+ metaFrameworks.push({
2245
+ id: 'nextjs',
2246
+ name: 'Next.js',
2247
+ category: 'meta-framework',
2248
+ version: parseVersionString(deps['next']),
2249
+ confidence: 90,
2250
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
2251
+ });
2634
2252
  }
2635
- if (deps['nuxt'] || deps['nuxt3']) {
2253
+ if (deps['gatsby']) {
2636
2254
  metaFrameworks.push({
2637
- id: 'nuxt',
2638
- name: 'Nuxt',
2255
+ id: 'gatsby',
2256
+ name: 'Gatsby',
2639
2257
  category: 'meta-framework',
2640
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
2258
+ version: parseVersionString(deps['gatsby']),
2641
2259
  confidence: 90,
2642
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
2260
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
2261
+ });
2262
+ }
2263
+ if (deps['@remix-run/react'] || deps['remix']) {
2264
+ metaFrameworks.push({
2265
+ id: 'remix',
2266
+ name: 'Remix',
2267
+ category: 'meta-framework',
2268
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
2269
+ confidence: 90,
2270
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
2643
2271
  });
2644
2272
  }
2645
2273
  if (confidence === 0) {
2646
2274
  return null;
2647
2275
  }
2648
2276
  return {
2649
- id: 'vue',
2650
- name: 'Vue',
2277
+ id: 'react',
2278
+ name: 'React',
2651
2279
  category: 'frontend',
2652
2280
  version,
2653
2281
  confidence: min(confidence, 100),
@@ -2657,37 +2285,58 @@ function vueDetector(projectPath, packageJson) {
2657
2285
  }
2658
2286
 
2659
2287
  /**
2660
- * Detect Nuxt in project.
2288
+ * Detect Remix in project.
2661
2289
  *
2662
2290
  * @param projectPath - Project directory path
2663
2291
  * @param packageJson - Optional pre-loaded package.json
2664
2292
  * @returns Detection result or null if not detected
2293
+ *
2294
+ * @example Detecting Remix framework
2295
+ * ```typescript
2296
+ * const result = remixDetector('/path/to/remix-app', {
2297
+ * dependencies: {
2298
+ * '@remix-run/react': '^2.0.0',
2299
+ * '@remix-run/node': '^2.0.0'
2300
+ * }
2301
+ * })
2302
+ * // => {
2303
+ * // id: 'remix',
2304
+ * // name: 'Remix',
2305
+ * // category: 'meta-framework',
2306
+ * // version: '2.0.0',
2307
+ * // confidence: 90,
2308
+ * // detectedFrom: [
2309
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
2310
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
2311
+ * // ]
2312
+ * // }
2313
+ * ```
2665
2314
  */
2666
- function nuxtDetector(projectPath, packageJson) {
2315
+ function remixDetector(projectPath, packageJson) {
2667
2316
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2668
2317
  const sources = [];
2669
2318
  let confidence = 0;
2670
2319
  let version;
2671
2320
  const deps = collectAllDependencies(pkg);
2672
- if (deps['nuxt'] || deps['nuxt3']) {
2321
+ if (deps['@remix-run/react']) {
2673
2322
  confidence += 70;
2674
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
2675
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
2323
+ version = parseVersionString(deps['@remix-run/react']);
2324
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
2676
2325
  }
2677
- if (exists(join$1(projectPath, 'nuxt.config.js')) || exists(join$1(projectPath, 'nuxt.config.ts'))) {
2678
- confidence += 25;
2679
- sources.push({ type: 'config-file', path: 'nuxt.config.*' });
2326
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
2327
+ confidence += 20;
2328
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
2680
2329
  }
2681
- if (exists(join$1(projectPath, 'pages'))) {
2682
- confidence += 5;
2683
- sources.push({ type: 'directory', path: 'pages/' });
2330
+ if (exists(join$1(projectPath, 'remix.config.js')) || exists(join$1(projectPath, 'remix.config.ts'))) {
2331
+ confidence += 10;
2332
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
2684
2333
  }
2685
2334
  if (confidence === 0) {
2686
2335
  return null;
2687
2336
  }
2688
2337
  return {
2689
- id: 'nuxt',
2690
- name: 'Nuxt',
2338
+ id: 'remix',
2339
+ name: 'Remix',
2691
2340
  category: 'meta-framework',
2692
2341
  version,
2693
2342
  confidence: min(confidence, 100),
@@ -2696,47 +2345,55 @@ function nuxtDetector(projectPath, packageJson) {
2696
2345
  }
2697
2346
 
2698
2347
  /**
2699
- * Detect Angular in project.
2348
+ * Detect Solid in project.
2700
2349
  *
2701
2350
  * @param projectPath - Project directory path
2702
2351
  * @param packageJson - Optional pre-loaded package.json
2703
2352
  * @returns Detection result or null if not detected
2353
+ *
2354
+ * @example Detecting Solid.js framework
2355
+ * ```typescript
2356
+ * const result = solidDetector('/path/to/solid-app', {
2357
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
2358
+ * })
2359
+ * // => {
2360
+ * // id: 'solid',
2361
+ * // name: 'Solid',
2362
+ * // category: 'frontend',
2363
+ * // version: '1.8.0',
2364
+ * // confidence: 90,
2365
+ * // detectedFrom: [
2366
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
2367
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
2368
+ * // ]
2369
+ * // }
2370
+ * ```
2704
2371
  */
2705
- function angularDetector(projectPath, packageJson) {
2372
+ function solidDetector(projectPath, packageJson) {
2706
2373
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2707
2374
  const sources = [];
2708
2375
  let confidence = 0;
2709
2376
  let version;
2710
2377
  const deps = collectAllDependencies(pkg);
2711
- if (deps['@angular/core']) {
2378
+ if (deps['solid-js']) {
2712
2379
  confidence += 70;
2713
- version = parseVersionString(deps['@angular/core']);
2714
- sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
2715
- }
2716
- if (deps['@angular/cli']) {
2717
- confidence += 15;
2718
- sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
2380
+ version = parseVersionString(deps['solid-js']);
2381
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
2719
2382
  }
2720
- if (exists(join$1(projectPath, 'angular.json'))) {
2721
- confidence += 15;
2722
- sources.push({ type: 'config-file', path: 'angular.json' });
2383
+ if (deps['vite-plugin-solid']) {
2384
+ confidence += 20;
2385
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
2723
2386
  }
2724
- if (deps['angular'] && !deps['@angular/core']) {
2725
- return {
2726
- id: 'angularjs',
2727
- name: 'AngularJS (Legacy)',
2728
- category: 'frontend',
2729
- version: parseVersionString(deps['angular']),
2730
- confidence: 80,
2731
- detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
2732
- };
2387
+ if (deps['solid-start'] || deps['@solidjs/start']) {
2388
+ confidence += 10;
2389
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
2733
2390
  }
2734
2391
  if (confidence === 0) {
2735
2392
  return null;
2736
2393
  }
2737
2394
  return {
2738
- id: 'angular',
2739
- name: 'Angular',
2395
+ id: 'solid',
2396
+ name: 'Solid',
2740
2397
  category: 'frontend',
2741
2398
  version,
2742
2399
  confidence: min(confidence, 100),
@@ -2750,6 +2407,21 @@ function angularDetector(projectPath, packageJson) {
2750
2407
  * @param projectPath - Project directory path
2751
2408
  * @param packageJson - Optional pre-loaded package.json
2752
2409
  * @returns Detection result or null if not detected
2410
+ *
2411
+ * @example Detecting Svelte framework
2412
+ * ```typescript
2413
+ * const result = svelteDetector('/path/to/svelte-app', {
2414
+ * devDependencies: { 'svelte': '^4.0.0' }
2415
+ * })
2416
+ * // => {
2417
+ * // id: 'svelte',
2418
+ * // name: 'Svelte',
2419
+ * // category: 'frontend',
2420
+ * // version: '4.0.0',
2421
+ * // confidence: 70,
2422
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
2423
+ * // }
2424
+ * ```
2753
2425
  */
2754
2426
  function svelteDetector(projectPath, packageJson) {
2755
2427
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2802,6 +2474,21 @@ function svelteDetector(projectPath, packageJson) {
2802
2474
  * @param projectPath - Project directory path
2803
2475
  * @param packageJson - Optional pre-loaded package.json
2804
2476
  * @returns Detection result or null if not detected
2477
+ *
2478
+ * @example Detecting SvelteKit framework
2479
+ * ```typescript
2480
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
2481
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
2482
+ * })
2483
+ * // => {
2484
+ * // id: 'sveltekit',
2485
+ * // name: 'SvelteKit',
2486
+ * // category: 'meta-framework',
2487
+ * // version: '2.0.0',
2488
+ * // confidence: 70,
2489
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
2490
+ * // }
2491
+ * ```
2805
2492
  */
2806
2493
  function sveltekitDetector(projectPath, packageJson) {
2807
2494
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2836,121 +2523,76 @@ function sveltekitDetector(projectPath, packageJson) {
2836
2523
  }
2837
2524
 
2838
2525
  /**
2839
- * Detect Solid in project.
2526
+ * Detect Vue in project.
2840
2527
  *
2841
2528
  * @param projectPath - Project directory path
2842
2529
  * @param packageJson - Optional pre-loaded package.json
2843
2530
  * @returns Detection result or null if not detected
2844
- */
2845
- function solidDetector(projectPath, packageJson) {
2846
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2847
- const sources = [];
2848
- let confidence = 0;
2849
- let version;
2850
- const deps = collectAllDependencies(pkg);
2851
- if (deps['solid-js']) {
2852
- confidence += 70;
2853
- version = parseVersionString(deps['solid-js']);
2854
- sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
2855
- }
2856
- if (deps['vite-plugin-solid']) {
2857
- confidence += 20;
2858
- sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
2859
- }
2860
- if (deps['solid-start'] || deps['@solidjs/start']) {
2861
- confidence += 10;
2862
- sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
2863
- }
2864
- if (confidence === 0) {
2865
- return null;
2866
- }
2867
- return {
2868
- id: 'solid',
2869
- name: 'Solid',
2870
- category: 'frontend',
2871
- version,
2872
- confidence: min(confidence, 100),
2873
- detectedFrom: sources,
2874
- };
2875
- }
2876
-
2877
- /**
2878
- * Detect Qwik in project.
2879
2531
  *
2880
- * @param projectPath - Project directory path
2881
- * @param packageJson - Optional pre-loaded package.json
2882
- * @returns Detection result or null if not detected
2532
+ * @example Detecting Vue.js framework
2533
+ * ```typescript
2534
+ * const result = vueDetector('/path/to/vue-app', {
2535
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
2536
+ * })
2537
+ * // => {
2538
+ * // id: 'vue',
2539
+ * // name: 'Vue',
2540
+ * // category: 'frontend',
2541
+ * // version: '3.0.0',
2542
+ * // confidence: 85,
2543
+ * // detectedFrom: [
2544
+ * // { type: 'package.json', field: 'dependencies.vue' },
2545
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
2546
+ * // ]
2547
+ * // }
2548
+ * ```
2883
2549
  */
2884
- function qwikDetector(projectPath, packageJson) {
2550
+ function vueDetector(projectPath, packageJson) {
2885
2551
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2886
2552
  const sources = [];
2887
2553
  let confidence = 0;
2888
2554
  let version;
2555
+ const metaFrameworks = [];
2889
2556
  const deps = collectAllDependencies(pkg);
2890
- if (deps['@builder.io/qwik']) {
2557
+ if (deps['vue']) {
2891
2558
  confidence += 70;
2892
- version = parseVersionString(deps['@builder.io/qwik']);
2893
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2559
+ version = parseVersionString(deps['vue']);
2560
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2894
2561
  }
2895
- if (deps['@builder.io/qwik-city']) {
2896
- confidence += 20;
2897
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
2562
+ if (deps['@vue/cli-service']) {
2563
+ confidence += 15;
2564
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2898
2565
  }
2899
- if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
2566
+ const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
2567
+ if (hasVueFiles) {
2900
2568
  confidence += 10;
2901
- sources.push({ type: 'config-file', path: 'qwik.config.*' });
2902
- }
2903
- if (confidence === 0) {
2904
- return null;
2905
- }
2906
- return {
2907
- id: 'qwik',
2908
- name: 'Qwik',
2909
- category: 'frontend',
2910
- version,
2911
- confidence: min(confidence, 100),
2912
- detectedFrom: sources,
2913
- };
2914
- }
2915
-
2916
- /**
2917
- * Detect Astro in project.
2918
- *
2919
- * @param projectPath - Project directory path
2920
- * @param packageJson - Optional pre-loaded package.json
2921
- * @returns Detection result or null if not detected
2922
- */
2923
- function astroDetector(projectPath, packageJson) {
2924
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2925
- const sources = [];
2926
- let confidence = 0;
2927
- let version;
2928
- const deps = collectAllDependencies(pkg);
2929
- if (deps['astro']) {
2930
- confidence += 70;
2931
- version = parseVersionString(deps['astro']);
2932
- sources.push({ type: 'package.json', field: 'dependencies.astro' });
2933
- }
2934
- if (exists(join$1(projectPath, 'astro.config.mjs')) ||
2935
- exists(join$1(projectPath, 'astro.config.ts')) ||
2936
- exists(join$1(projectPath, 'astro.config.js'))) {
2937
- confidence += 25;
2938
- sources.push({ type: 'config-file', path: 'astro.config.*' });
2569
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2939
2570
  }
2940
- if (exists(join$1(projectPath, 'src', 'pages'))) {
2571
+ if (exists(join$1(projectPath, 'vue.config.js'))) {
2941
2572
  confidence += 5;
2942
- sources.push({ type: 'directory', path: 'src/pages/' });
2573
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
2574
+ }
2575
+ if (deps['nuxt'] || deps['nuxt3']) {
2576
+ metaFrameworks.push({
2577
+ id: 'nuxt',
2578
+ name: 'Nuxt',
2579
+ category: 'meta-framework',
2580
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
2581
+ confidence: 90,
2582
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
2583
+ });
2943
2584
  }
2944
2585
  if (confidence === 0) {
2945
2586
  return null;
2946
2587
  }
2947
2588
  return {
2948
- id: 'astro',
2949
- name: 'Astro',
2950
- category: 'meta-framework',
2589
+ id: 'vue',
2590
+ name: 'Vue',
2591
+ category: 'frontend',
2951
2592
  version,
2952
2593
  confidence: min(confidence, 100),
2953
2594
  detectedFrom: sources,
2595
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2954
2596
  };
2955
2597
  }
2956
2598
 
@@ -2977,6 +2619,14 @@ const frameworkDetectors = [
2977
2619
  * @param projectPath - Project directory path
2978
2620
  * @param packageJson - Optional pre-loaded package.json
2979
2621
  * @returns Detection result or null if not detected
2622
+ *
2623
+ * @example Detecting AngularJS framework
2624
+ * ```typescript
2625
+ * const result = angularJSDetector('/path/to/project', {
2626
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
2627
+ * })
2628
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
2629
+ * ```
2980
2630
  */
2981
2631
  function angularJSDetector(projectPath, packageJson) {
2982
2632
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3020,6 +2670,14 @@ function angularJSDetector(projectPath, packageJson) {
3020
2670
  * @param projectPath - Project directory path
3021
2671
  * @param packageJson - Optional pre-loaded package.json
3022
2672
  * @returns Detection result or null if not detected
2673
+ *
2674
+ * @example Detecting Backbone.js framework
2675
+ * ```typescript
2676
+ * const result = backboneDetector('/path/to/project', {
2677
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2678
+ * })
2679
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2680
+ * ```
3023
2681
  */
3024
2682
  function backboneDetector(projectPath, packageJson) {
3025
2683
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3063,6 +2721,15 @@ function backboneDetector(projectPath, packageJson) {
3063
2721
  * @param projectPath - Project directory path
3064
2722
  * @param packageJson - Optional pre-loaded package.json
3065
2723
  * @returns Detection result or null if not detected
2724
+ *
2725
+ * @example Detecting Ember.js framework
2726
+ * ```typescript
2727
+ * const result = emberDetector('/path/to/project', {
2728
+ * dependencies: { 'ember-source': '^4.0.0' },
2729
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2730
+ * })
2731
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2732
+ * ```
3066
2733
  */
3067
2734
  function emberDetector(projectPath, packageJson) {
3068
2735
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3102,6 +2769,14 @@ function emberDetector(projectPath, packageJson) {
3102
2769
  * @param projectPath - Project directory path
3103
2770
  * @param packageJson - Optional pre-loaded package.json
3104
2771
  * @returns Detection result or null if not detected
2772
+ *
2773
+ * @example Detecting jQuery library
2774
+ * ```typescript
2775
+ * const result = jqueryDetector('/path/to/project', {
2776
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2777
+ * })
2778
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2779
+ * ```
3105
2780
  */
3106
2781
  function jqueryDetector(projectPath, packageJson) {
3107
2782
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3143,6 +2818,56 @@ const legacyDetectors = [
3143
2818
  { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
3144
2819
  ];
3145
2820
 
2821
+ /**
2822
+ * Detect Biome in project.
2823
+ *
2824
+ * @param projectPath - Project directory path
2825
+ * @param packageJson - Optional pre-loaded package.json
2826
+ * @returns Detection result or null if not detected
2827
+ *
2828
+ * @example Detecting Biome linter
2829
+ * ```typescript
2830
+ * const result = biomeDetector('/path/to/project', {
2831
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2832
+ * })
2833
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2834
+ * ```
2835
+ */
2836
+ function biomeDetector(projectPath, packageJson) {
2837
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2838
+ const sources = [];
2839
+ let confidence = 0;
2840
+ let configPath;
2841
+ let version;
2842
+ const deps = collectAllDependencies(pkg);
2843
+ if (deps['@biomejs/biome']) {
2844
+ confidence += 70;
2845
+ version = parseVersionString(deps['@biomejs/biome']);
2846
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2847
+ }
2848
+ if (exists(join$1(projectPath, 'biome.json'))) {
2849
+ confidence += 30;
2850
+ configPath = 'biome.json';
2851
+ sources.push({ type: 'config-file', path: 'biome.json' });
2852
+ }
2853
+ if (!configPath && exists(join$1(projectPath, 'biome.jsonc'))) {
2854
+ confidence += 30;
2855
+ configPath = 'biome.jsonc';
2856
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2857
+ }
2858
+ if (confidence === 0) {
2859
+ return null;
2860
+ }
2861
+ return {
2862
+ id: 'biome',
2863
+ name: 'Biome',
2864
+ version,
2865
+ configPath,
2866
+ confidence: min(confidence, 100),
2867
+ detectedFrom: sources,
2868
+ };
2869
+ }
2870
+
3146
2871
  /** Config patterns for ESLint */
3147
2872
  const ESLINT_CONFIG_PATTERNS = [
3148
2873
  'eslint.config.js',
@@ -3162,6 +2887,15 @@ const ESLINT_CONFIG_PATTERNS = [
3162
2887
  * @param projectPath - Project directory path
3163
2888
  * @param packageJson - Optional pre-loaded package.json
3164
2889
  * @returns Detection result or null if not detected
2890
+ *
2891
+ * @example Detecting ESLint linter
2892
+ * ```typescript
2893
+ * const result = eslintDetector('/path/to/project', {
2894
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2895
+ * scripts: { lint: 'eslint src/' },
2896
+ * })
2897
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2898
+ * ```
3165
2899
  */
3166
2900
  function eslintDetector(projectPath, packageJson) {
3167
2901
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3225,6 +2959,15 @@ const PRETTIER_CONFIG_PATTERNS = [
3225
2959
  * @param projectPath - Project directory path
3226
2960
  * @param packageJson - Optional pre-loaded package.json
3227
2961
  * @returns Detection result or null if not detected
2962
+ *
2963
+ * @example Detecting Prettier formatter
2964
+ * ```typescript
2965
+ * const result = prettierDetector('/path/to/project', {
2966
+ * devDependencies: { prettier: '^3.0.0' },
2967
+ * scripts: { format: 'prettier --write .' },
2968
+ * })
2969
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2970
+ * ```
3228
2971
  */
3229
2972
  function prettierDetector(projectPath, packageJson) {
3230
2973
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3287,6 +3030,14 @@ const STYLELINT_CONFIG_PATTERNS = [
3287
3030
  * @param projectPath - Project directory path
3288
3031
  * @param packageJson - Optional pre-loaded package.json
3289
3032
  * @returns Detection result or null if not detected
3033
+ *
3034
+ * @example Detecting Stylelint linter
3035
+ * ```typescript
3036
+ * const result = stylelintDetector('/path/to/project', {
3037
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
3038
+ * })
3039
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
3040
+ * ```
3290
3041
  */
3291
3042
  function stylelintDetector(projectPath, packageJson) {
3292
3043
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3308,59 +3059,17 @@ function stylelintDetector(projectPath, packageJson) {
3308
3059
  break;
3309
3060
  }
3310
3061
  }
3311
- const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
3312
- if (stylelintPlugins.length > 0) {
3313
- confidence += 5;
3314
- sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
3315
- }
3316
- if (confidence === 0) {
3317
- return null;
3318
- }
3319
- return {
3320
- id: 'stylelint',
3321
- name: 'Stylelint',
3322
- version,
3323
- configPath,
3324
- confidence: min(confidence, 100),
3325
- detectedFrom: sources,
3326
- };
3327
- }
3328
-
3329
- /**
3330
- * Detect Biome in project.
3331
- *
3332
- * @param projectPath - Project directory path
3333
- * @param packageJson - Optional pre-loaded package.json
3334
- * @returns Detection result or null if not detected
3335
- */
3336
- function biomeDetector(projectPath, packageJson) {
3337
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3338
- const sources = [];
3339
- let confidence = 0;
3340
- let configPath;
3341
- let version;
3342
- const deps = collectAllDependencies(pkg);
3343
- if (deps['@biomejs/biome']) {
3344
- confidence += 70;
3345
- version = parseVersionString(deps['@biomejs/biome']);
3346
- sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
3347
- }
3348
- if (exists(join$1(projectPath, 'biome.json'))) {
3349
- confidence += 30;
3350
- configPath = 'biome.json';
3351
- sources.push({ type: 'config-file', path: 'biome.json' });
3352
- }
3353
- if (!configPath && exists(join$1(projectPath, 'biome.jsonc'))) {
3354
- confidence += 30;
3355
- configPath = 'biome.jsonc';
3356
- sources.push({ type: 'config-file', path: 'biome.jsonc' });
3062
+ const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
3063
+ if (stylelintPlugins.length > 0) {
3064
+ confidence += 5;
3065
+ sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
3357
3066
  }
3358
3067
  if (confidence === 0) {
3359
3068
  return null;
3360
3069
  }
3361
3070
  return {
3362
- id: 'biome',
3363
- name: 'Biome',
3071
+ id: 'stylelint',
3072
+ name: 'Stylelint',
3364
3073
  version,
3365
3074
  configPath,
3366
3075
  confidence: min(confidence, 100),
@@ -3377,140 +3086,179 @@ const lintingDetectors = [
3377
3086
  ];
3378
3087
 
3379
3088
  /**
3380
- * Detect NX in project.
3089
+ * Detect Lerna in project.
3381
3090
  *
3382
3091
  * @param workspacePath - Workspace directory path
3383
3092
  * @param packageJson - Optional pre-loaded package.json
3384
3093
  * @returns Detection result or null if not detected
3094
+ *
3095
+ * @example Detecting Lerna monorepo
3096
+ * ```typescript
3097
+ * // Project with lerna.json config file
3098
+ * const result = lernaDetector('/path/to/lerna-project')
3099
+ * // => {
3100
+ * // id: 'lerna',
3101
+ * // name: 'Lerna',
3102
+ * // confidence: 80,
3103
+ * // configPath: 'lerna.json',
3104
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
3105
+ * // }
3106
+ * ```
3385
3107
  */
3386
- function nxDetector(workspacePath, packageJson) {
3108
+ function lernaDetector(workspacePath, packageJson) {
3387
3109
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3388
3110
  const sources = [];
3389
3111
  let confidence = 0;
3390
3112
  let version;
3391
- let workspaceLayout;
3392
- const nxJsonPath = join$1(workspacePath, 'nx.json');
3393
- if (exists(nxJsonPath)) {
3394
- confidence += 70;
3395
- sources.push({ type: 'config-file', path: 'nx.json' });
3113
+ let configPath;
3114
+ const lernaJsonPath = join$1(workspacePath, 'lerna.json');
3115
+ if (exists(lernaJsonPath)) {
3116
+ confidence += 80;
3117
+ configPath = 'lerna.json';
3118
+ sources.push({ type: 'config-file', path: 'lerna.json' });
3396
3119
  }
3397
3120
  const deps = collectAllDependencies(pkg);
3398
- if (deps['nx']) {
3399
- confidence += 20;
3400
- version = parseVersionString(deps['nx']);
3401
- sources.push({ type: 'package.json', field: 'dependencies.nx' });
3402
- }
3403
- const hasApps = exists(join$1(workspacePath, 'apps'));
3404
- const hasLibs = exists(join$1(workspacePath, 'libs'));
3405
- if (hasApps || hasLibs) {
3406
- confidence += 10;
3407
- sources.push({ type: 'directory', path: 'apps/ or libs/' });
3408
- workspaceLayout = {
3409
- appsDir: hasApps ? 'apps' : '',
3410
- libsDir: hasLibs ? 'libs' : '',
3411
- };
3121
+ if (deps['lerna']) {
3122
+ confidence += 15;
3123
+ version = parseVersionString(deps['lerna']);
3124
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
3412
3125
  }
3413
- const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
3414
- if (nxPackages.length > 0) {
3415
- confidence += 10;
3416
- sources.push({ type: 'package.json', field: '@nx/* packages' });
3126
+ if (exists(join$1(workspacePath, 'packages'))) {
3127
+ confidence += 5;
3128
+ sources.push({ type: 'directory', path: 'packages/' });
3417
3129
  }
3418
3130
  if (confidence === 0) {
3419
3131
  return null;
3420
3132
  }
3421
3133
  return {
3422
- id: 'nx',
3423
- name: 'NX',
3134
+ id: 'lerna',
3135
+ name: 'Lerna',
3424
3136
  version,
3425
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
3137
+ configPath,
3426
3138
  confidence: min(confidence, 100),
3427
3139
  detectedFrom: sources,
3428
- workspaceLayout,
3429
3140
  };
3430
3141
  }
3431
3142
 
3432
3143
  /**
3433
- * Detect Turborepo in project.
3144
+ * Detect npm workspaces in project.
3434
3145
  *
3435
3146
  * @param workspacePath - Workspace directory path
3436
3147
  * @param packageJson - Optional pre-loaded package.json
3437
3148
  * @returns Detection result or null if not detected
3149
+ *
3150
+ * @example Detecting npm workspaces
3151
+ * ```typescript
3152
+ * // Project with workspaces in package.json and package-lock.json
3153
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
3154
+ * // => {
3155
+ * // id: 'npm-workspaces',
3156
+ * // name: 'npm Workspaces',
3157
+ * // confidence: 90,
3158
+ * // configPath: 'package.json',
3159
+ * // detectedFrom: [
3160
+ * // { type: 'package.json', field: 'workspaces' },
3161
+ * // { type: 'lockfile', path: 'package-lock.json' }
3162
+ * // ]
3163
+ * // }
3164
+ * ```
3438
3165
  */
3439
- function turborepoDetector(workspacePath, packageJson) {
3166
+ function npmWorkspacesDetector(workspacePath, packageJson) {
3440
3167
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3441
3168
  const sources = [];
3442
3169
  let confidence = 0;
3443
- let version;
3444
- let configPath;
3445
- const turboJsonPath = join$1(workspacePath, 'turbo.json');
3446
- if (exists(turboJsonPath)) {
3170
+ if (pkg?.workspaces) {
3447
3171
  confidence += 80;
3448
- configPath = 'turbo.json';
3449
- sources.push({ type: 'config-file', path: 'turbo.json' });
3172
+ sources.push({ type: 'package.json', field: 'workspaces' });
3450
3173
  }
3451
- const deps = collectAllDependencies(pkg);
3452
- if (deps['turbo']) {
3453
- confidence += 15;
3454
- version = parseVersionString(deps['turbo']);
3455
- sources.push({ type: 'package.json', field: 'dependencies.turbo' });
3174
+ if (exists(join$1(workspacePath, 'package-lock.json'))) {
3175
+ confidence += 10;
3176
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
3456
3177
  }
3457
- const scripts = pkg?.scripts ?? {};
3458
- if (values(scripts).some((s) => s?.includes('turbo'))) {
3459
- confidence += 5;
3460
- sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
3178
+ if (exists(join$1(workspacePath, 'yarn.lock'))) {
3179
+ return null;
3461
3180
  }
3462
3181
  if (confidence === 0) {
3463
3182
  return null;
3464
3183
  }
3465
3184
  return {
3466
- id: 'turborepo',
3467
- name: 'Turborepo',
3468
- version,
3469
- configPath,
3185
+ id: 'npm-workspaces',
3186
+ name: 'npm Workspaces',
3187
+ configPath: 'package.json',
3470
3188
  confidence: min(confidence, 100),
3471
3189
  detectedFrom: sources,
3472
3190
  };
3473
3191
  }
3474
3192
 
3475
3193
  /**
3476
- * Detect Lerna in project.
3194
+ * Detect NX in project.
3477
3195
  *
3478
3196
  * @param workspacePath - Workspace directory path
3479
3197
  * @param packageJson - Optional pre-loaded package.json
3480
3198
  * @returns Detection result or null if not detected
3199
+ *
3200
+ * @example Detecting NX workspace
3201
+ * ```typescript
3202
+ * // Project with nx.json and apps/libs directories
3203
+ * const result = nxDetector('/path/to/nx-workspace')
3204
+ * // => {
3205
+ * // id: 'nx',
3206
+ * // name: 'NX',
3207
+ * // confidence: 100,
3208
+ * // configPath: 'nx.json',
3209
+ * // version: '17.0.0',
3210
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
3211
+ * // detectedFrom: [
3212
+ * // { type: 'config-file', path: 'nx.json' },
3213
+ * // { type: 'package.json', field: 'dependencies.nx' },
3214
+ * // { type: 'directory', path: 'apps/ or libs/' }
3215
+ * // ]
3216
+ * // }
3217
+ * ```
3481
3218
  */
3482
- function lernaDetector(workspacePath, packageJson) {
3219
+ function nxDetector(workspacePath, packageJson) {
3483
3220
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3484
3221
  const sources = [];
3485
3222
  let confidence = 0;
3486
3223
  let version;
3487
- let configPath;
3488
- const lernaJsonPath = join$1(workspacePath, 'lerna.json');
3489
- if (exists(lernaJsonPath)) {
3490
- confidence += 80;
3491
- configPath = 'lerna.json';
3492
- sources.push({ type: 'config-file', path: 'lerna.json' });
3224
+ let workspaceLayout;
3225
+ const nxJsonPath = join$1(workspacePath, 'nx.json');
3226
+ if (exists(nxJsonPath)) {
3227
+ confidence += 70;
3228
+ sources.push({ type: 'config-file', path: 'nx.json' });
3493
3229
  }
3494
3230
  const deps = collectAllDependencies(pkg);
3495
- if (deps['lerna']) {
3496
- confidence += 15;
3497
- version = parseVersionString(deps['lerna']);
3498
- sources.push({ type: 'package.json', field: 'dependencies.lerna' });
3231
+ if (deps['nx']) {
3232
+ confidence += 20;
3233
+ version = parseVersionString(deps['nx']);
3234
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
3499
3235
  }
3500
- if (exists(join$1(workspacePath, 'packages'))) {
3501
- confidence += 5;
3502
- sources.push({ type: 'directory', path: 'packages/' });
3236
+ const hasApps = exists(join$1(workspacePath, 'apps'));
3237
+ const hasLibs = exists(join$1(workspacePath, 'libs'));
3238
+ if (hasApps || hasLibs) {
3239
+ confidence += 10;
3240
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
3241
+ workspaceLayout = {
3242
+ appsDir: hasApps ? 'apps' : '',
3243
+ libsDir: hasLibs ? 'libs' : '',
3244
+ };
3245
+ }
3246
+ const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
3247
+ if (nxPackages.length > 0) {
3248
+ confidence += 10;
3249
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
3503
3250
  }
3504
3251
  if (confidence === 0) {
3505
3252
  return null;
3506
3253
  }
3507
3254
  return {
3508
- id: 'lerna',
3509
- name: 'Lerna',
3255
+ id: 'nx',
3256
+ name: 'NX',
3510
3257
  version,
3511
- configPath,
3258
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
3512
3259
  confidence: min(confidence, 100),
3513
3260
  detectedFrom: sources,
3261
+ workspaceLayout,
3514
3262
  };
3515
3263
  }
3516
3264
 
@@ -3520,6 +3268,19 @@ function lernaDetector(workspacePath, packageJson) {
3520
3268
  * @param workspacePath - Workspace directory path
3521
3269
  * @param packageJson - Optional pre-loaded package.json
3522
3270
  * @returns Detection result or null if not detected
3271
+ *
3272
+ * @example Detecting Rush monorepo
3273
+ * ```typescript
3274
+ * // Project with rush.json config file
3275
+ * const result = rushDetector('/path/to/rush-project')
3276
+ * // => {
3277
+ * // id: 'rush',
3278
+ * // name: 'Rush',
3279
+ * // confidence: 90,
3280
+ * // configPath: 'rush.json',
3281
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
3282
+ * // }
3283
+ * ```
3523
3284
  */
3524
3285
  function rushDetector(workspacePath, packageJson) {
3525
3286
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -3557,66 +3318,60 @@ function rushDetector(workspacePath, packageJson) {
3557
3318
  }
3558
3319
 
3559
3320
  /**
3560
- * Detect pnpm workspaces in project.
3561
- *
3562
- * @param workspacePath - Workspace directory path
3563
- * @returns Detection result or null if not detected
3564
- */
3565
- function pnpmWorkspacesDetector(workspacePath) {
3566
- const sources = [];
3567
- let confidence = 0;
3568
- let configPath;
3569
- const pnpmWorkspacePath = join$1(workspacePath, 'pnpm-workspace.yaml');
3570
- if (exists(pnpmWorkspacePath)) {
3571
- confidence += 90;
3572
- configPath = 'pnpm-workspace.yaml';
3573
- sources.push({ type: 'config-file', path: 'pnpm-workspace.yaml' });
3574
- }
3575
- if (exists(join$1(workspacePath, 'pnpm-lock.yaml'))) {
3576
- confidence += 10;
3577
- sources.push({ type: 'lockfile', path: 'pnpm-lock.yaml' });
3578
- }
3579
- if (confidence === 0) {
3580
- return null;
3581
- }
3582
- return {
3583
- id: 'pnpm-workspaces',
3584
- name: 'pnpm Workspaces',
3585
- configPath,
3586
- confidence: min(confidence, 100),
3587
- detectedFrom: sources,
3588
- };
3589
- }
3590
-
3591
- /**
3592
- * Detect npm workspaces in project.
3321
+ * Detect Turborepo in project.
3593
3322
  *
3594
3323
  * @param workspacePath - Workspace directory path
3595
3324
  * @param packageJson - Optional pre-loaded package.json
3596
3325
  * @returns Detection result or null if not detected
3326
+ *
3327
+ * @example Detecting Turborepo monorepo
3328
+ * ```typescript
3329
+ * // Project with turbo.json and turbo dependency
3330
+ * const result = turborepoDetector('/path/to/turbo-project')
3331
+ * // => {
3332
+ * // id: 'turborepo',
3333
+ * // name: 'Turborepo',
3334
+ * // confidence: 95,
3335
+ * // configPath: 'turbo.json',
3336
+ * // version: '2.0.0',
3337
+ * // detectedFrom: [
3338
+ * // { type: 'config-file', path: 'turbo.json' },
3339
+ * // { type: 'package.json', field: 'dependencies.turbo' }
3340
+ * // ]
3341
+ * // }
3342
+ * ```
3597
3343
  */
3598
- function npmWorkspacesDetector(workspacePath, packageJson) {
3344
+ function turborepoDetector(workspacePath, packageJson) {
3599
3345
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3600
3346
  const sources = [];
3601
3347
  let confidence = 0;
3602
- if (pkg?.workspaces) {
3348
+ let version;
3349
+ let configPath;
3350
+ const turboJsonPath = join$1(workspacePath, 'turbo.json');
3351
+ if (exists(turboJsonPath)) {
3603
3352
  confidence += 80;
3604
- sources.push({ type: 'package.json', field: 'workspaces' });
3353
+ configPath = 'turbo.json';
3354
+ sources.push({ type: 'config-file', path: 'turbo.json' });
3605
3355
  }
3606
- if (exists(join$1(workspacePath, 'package-lock.json'))) {
3607
- confidence += 10;
3608
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
3356
+ const deps = collectAllDependencies(pkg);
3357
+ if (deps['turbo']) {
3358
+ confidence += 15;
3359
+ version = parseVersionString(deps['turbo']);
3360
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
3609
3361
  }
3610
- if (exists(join$1(workspacePath, 'yarn.lock'))) {
3611
- return null;
3362
+ const scripts = pkg?.scripts ?? {};
3363
+ if (values(scripts).some((s) => s?.includes('turbo'))) {
3364
+ confidence += 5;
3365
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
3612
3366
  }
3613
3367
  if (confidence === 0) {
3614
3368
  return null;
3615
3369
  }
3616
3370
  return {
3617
- id: 'npm-workspaces',
3618
- name: 'npm Workspaces',
3619
- configPath: 'package.json',
3371
+ id: 'turborepo',
3372
+ name: 'Turborepo',
3373
+ version,
3374
+ configPath,
3620
3375
  confidence: min(confidence, 100),
3621
3376
  detectedFrom: sources,
3622
3377
  };
@@ -3628,6 +3383,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
3628
3383
  * @param workspacePath - Workspace directory path
3629
3384
  * @param packageJson - Optional pre-loaded package.json
3630
3385
  * @returns Detection result or null if not detected
3386
+ *
3387
+ * @example Detecting yarn workspaces
3388
+ * ```typescript
3389
+ * // Project with workspaces in package.json and yarn.lock
3390
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
3391
+ * // => {
3392
+ * // id: 'yarn-workspaces',
3393
+ * // name: 'Yarn Workspaces',
3394
+ * // confidence: 100,
3395
+ * // configPath: 'package.json',
3396
+ * // detectedFrom: [
3397
+ * // { type: 'package.json', field: 'workspaces' },
3398
+ * // { type: 'lockfile', path: 'yarn.lock' },
3399
+ * // { type: 'config-file', path: '.yarnrc.yml' }
3400
+ * // ]
3401
+ * // }
3402
+ * ```
3631
3403
  */
3632
3404
  function yarnWorkspacesDetector(workspacePath, packageJson) {
3633
3405
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -3668,107 +3440,125 @@ const monorepoDetectors = [
3668
3440
  { id: 'yarn-workspaces', name: 'Yarn Workspaces', detect: yarnWorkspacesDetector },
3669
3441
  ];
3670
3442
 
3671
- /** Config patterns for Jest */
3672
- const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
3443
+ /** Config patterns for Cypress */
3444
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3673
3445
  /**
3674
- * Detect Jest in project.
3446
+ * Detect Cypress in project.
3675
3447
  *
3676
3448
  * @param projectPath - Project directory path
3677
3449
  * @param packageJson - Optional pre-loaded package.json
3678
3450
  * @returns Detection result or null if not detected
3451
+ *
3452
+ * @example Detecting Cypress testing framework
3453
+ * ```typescript
3454
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
3455
+ *
3456
+ * const result = cypressDetector('./my-project')
3457
+ * if (result) {
3458
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
3459
+ * // => "Cypress 13.6.0 detected (95% confidence)"
3460
+ * }
3461
+ * ```
3679
3462
  */
3680
- function jestDetector(projectPath, packageJson) {
3463
+ function cypressDetector(projectPath, packageJson) {
3681
3464
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3682
3465
  const sources = [];
3683
3466
  let confidence = 0;
3684
3467
  let version;
3685
3468
  const deps = collectAllDependencies(pkg);
3686
- if (deps['jest']) {
3469
+ if (deps['cypress']) {
3687
3470
  confidence += 60;
3688
- version = parseVersionString(deps['jest']);
3689
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
3471
+ version = parseVersionString(deps['cypress']);
3472
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
3690
3473
  }
3691
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
3474
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3692
3475
  if (configPath) {
3693
3476
  confidence += 30;
3694
3477
  sources.push({ type: 'config-file', path: configPath });
3695
3478
  }
3696
- if (pkg && 'jest' in pkg) {
3697
- confidence += 20;
3698
- sources.push({ type: 'package.json', field: 'jest' });
3699
- }
3700
- const testScript = pkg?.scripts?.['test'] ?? '';
3701
- if (testScript.includes('jest')) {
3479
+ if (exists(join$1(projectPath, 'cypress'))) {
3702
3480
  confidence += 10;
3703
- sources.push({ type: 'package.json', field: 'scripts.test' });
3704
- }
3705
- if (deps['@types/jest']) {
3706
- confidence += 5;
3707
- sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
3481
+ sources.push({ type: 'directory', path: 'cypress/' });
3708
3482
  }
3709
- if (deps['ts-jest']) {
3483
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3484
+ if (e2eScript.includes('cypress')) {
3710
3485
  confidence += 5;
3711
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3486
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3712
3487
  }
3713
3488
  if (confidence === 0) {
3714
3489
  return null;
3715
3490
  }
3716
3491
  return {
3717
- id: 'jest',
3718
- name: 'Jest',
3719
- type: 'unit',
3492
+ id: 'cypress',
3493
+ name: 'Cypress',
3494
+ type: 'e2e',
3720
3495
  version,
3721
3496
  configPath,
3722
3497
  confidence: min(confidence, 100),
3723
3498
  detectedFrom: sources,
3724
3499
  };
3725
3500
  }
3726
-
3727
- /** Config patterns for Vitest */
3728
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3501
+
3502
+ /** Config patterns for Jest */
3503
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
3729
3504
  /**
3730
- * Detect Vitest in project.
3505
+ * Detect Jest in project.
3731
3506
  *
3732
3507
  * @param projectPath - Project directory path
3733
3508
  * @param packageJson - Optional pre-loaded package.json
3734
3509
  * @returns Detection result or null if not detected
3510
+ *
3511
+ * @example Detecting Jest testing framework
3512
+ * ```typescript
3513
+ * import { jestDetector } from '@hyperfrontend/project-scope'
3514
+ *
3515
+ * const result = jestDetector('./my-project')
3516
+ * if (result) {
3517
+ * console.log(`Jest ${result.version} detected`)
3518
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
3519
+ * // => "Sources: ['package.json', 'config-file']"
3520
+ * }
3521
+ * ```
3735
3522
  */
3736
- function vitestDetector(projectPath, packageJson) {
3523
+ function jestDetector(projectPath, packageJson) {
3737
3524
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3738
3525
  const sources = [];
3739
3526
  let confidence = 0;
3740
3527
  let version;
3741
3528
  const deps = collectAllDependencies(pkg);
3742
- if (deps['vitest']) {
3743
- confidence += 70;
3744
- version = parseVersionString(deps['vitest']);
3745
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3529
+ if (deps['jest']) {
3530
+ confidence += 60;
3531
+ version = parseVersionString(deps['jest']);
3532
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
3746
3533
  }
3747
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3534
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
3748
3535
  if (configPath) {
3749
- confidence += 25;
3536
+ confidence += 30;
3750
3537
  sources.push({ type: 'config-file', path: configPath });
3751
3538
  }
3752
- if (!configPath) {
3753
- const viteConfig = exists(join$1(projectPath, 'vite.config.ts')) ||
3754
- exists(join$1(projectPath, 'vite.config.js')) ||
3755
- exists(join$1(projectPath, 'vite.config.mjs'));
3756
- if (viteConfig && deps['vitest']) {
3757
- confidence += 5;
3758
- sources.push({ type: 'config-file', path: 'vite.config.*' });
3759
- }
3539
+ if (pkg && 'jest' in pkg) {
3540
+ confidence += 20;
3541
+ sources.push({ type: 'package.json', field: 'jest' });
3760
3542
  }
3761
3543
  const testScript = pkg?.scripts?.['test'] ?? '';
3762
- if (testScript.includes('vitest')) {
3544
+ if (testScript.includes('jest')) {
3763
3545
  confidence += 10;
3764
3546
  sources.push({ type: 'package.json', field: 'scripts.test' });
3765
3547
  }
3548
+ if (deps['@types/jest']) {
3549
+ confidence += 5;
3550
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
3551
+ }
3552
+ if (deps['ts-jest']) {
3553
+ confidence += 5;
3554
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3555
+ }
3766
3556
  if (confidence === 0) {
3767
3557
  return null;
3768
3558
  }
3769
3559
  return {
3770
- id: 'vitest',
3771
- name: 'Vitest',
3560
+ id: 'jest',
3561
+ name: 'Jest',
3772
3562
  type: 'unit',
3773
3563
  version,
3774
3564
  configPath,
@@ -3785,6 +3575,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
3785
3575
  * @param projectPath - Project directory path
3786
3576
  * @param packageJson - Optional pre-loaded package.json
3787
3577
  * @returns Detection result or null if not detected
3578
+ *
3579
+ * @example Detecting Mocha testing framework
3580
+ * ```typescript
3581
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
3582
+ *
3583
+ * const result = mochaDetector('./my-project')
3584
+ * if (result) {
3585
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
3586
+ * // => "Mocha 10.2.0 detected (95%)"
3587
+ * }
3588
+ * ```
3788
3589
  */
3789
3590
  function mochaDetector(projectPath, packageJson) {
3790
3591
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3829,37 +3630,53 @@ function mochaDetector(projectPath, packageJson) {
3829
3630
  };
3830
3631
  }
3831
3632
 
3832
- /** Config patterns for Cypress */
3833
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3633
+ /** Config patterns for Playwright */
3634
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3834
3635
  /**
3835
- * Detect Cypress in project.
3636
+ * Detect Playwright in project.
3836
3637
  *
3837
3638
  * @param projectPath - Project directory path
3838
3639
  * @param packageJson - Optional pre-loaded package.json
3839
3640
  * @returns Detection result or null if not detected
3641
+ *
3642
+ * @example Detecting Playwright testing framework
3643
+ * ```typescript
3644
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
3645
+ *
3646
+ * const result = playwrightDetector('./my-project')
3647
+ * if (result) {
3648
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
3649
+ * // => "Playwright 1.42.0 (e2e tests)"
3650
+ * }
3651
+ * ```
3840
3652
  */
3841
- function cypressDetector(projectPath, packageJson) {
3653
+ function playwrightDetector(projectPath, packageJson) {
3842
3654
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3843
3655
  const sources = [];
3844
3656
  let confidence = 0;
3845
3657
  let version;
3846
3658
  const deps = collectAllDependencies(pkg);
3847
- if (deps['cypress']) {
3848
- confidence += 60;
3849
- version = parseVersionString(deps['cypress']);
3850
- sources.push({ type: 'package.json', field: 'dependencies.cypress' });
3659
+ if (deps['@playwright/test']) {
3660
+ confidence += 70;
3661
+ version = parseVersionString(deps['@playwright/test']);
3662
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3851
3663
  }
3852
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3664
+ if (deps['playwright']) {
3665
+ confidence += 50;
3666
+ version = version ?? parseVersionString(deps['playwright']);
3667
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3668
+ }
3669
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3853
3670
  if (configPath) {
3854
- confidence += 30;
3671
+ confidence += 25;
3855
3672
  sources.push({ type: 'config-file', path: configPath });
3856
3673
  }
3857
- if (exists(join$1(projectPath, 'cypress'))) {
3858
- confidence += 10;
3859
- sources.push({ type: 'directory', path: 'cypress/' });
3674
+ if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3675
+ confidence += 5;
3676
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3860
3677
  }
3861
3678
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3862
- if (e2eScript.includes('cypress')) {
3679
+ if (e2eScript.includes('playwright')) {
3863
3680
  confidence += 5;
3864
3681
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3865
3682
  }
@@ -3867,8 +3684,8 @@ function cypressDetector(projectPath, packageJson) {
3867
3684
  return null;
3868
3685
  }
3869
3686
  return {
3870
- id: 'cypress',
3871
- name: 'Cypress',
3687
+ id: 'playwright',
3688
+ name: 'Playwright',
3872
3689
  type: 'e2e',
3873
3690
  version,
3874
3691
  configPath,
@@ -3877,52 +3694,64 @@ function cypressDetector(projectPath, packageJson) {
3877
3694
  };
3878
3695
  }
3879
3696
 
3880
- /** Config patterns for Playwright */
3881
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3697
+ /** Config patterns for Vitest */
3698
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3882
3699
  /**
3883
- * Detect Playwright in project.
3700
+ * Detect Vitest in project.
3884
3701
  *
3885
3702
  * @param projectPath - Project directory path
3886
3703
  * @param packageJson - Optional pre-loaded package.json
3887
3704
  * @returns Detection result or null if not detected
3705
+ *
3706
+ * @example Detecting Vitest testing framework
3707
+ * ```typescript
3708
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3709
+ *
3710
+ * const result = vitestDetector('./my-project')
3711
+ * if (result) {
3712
+ * console.log(`Vitest ${result.version} detected`)
3713
+ * console.log('Config:', result.configPath)
3714
+ * // => "Config: vitest.config.ts"
3715
+ * }
3716
+ * ```
3888
3717
  */
3889
- function playwrightDetector(projectPath, packageJson) {
3718
+ function vitestDetector(projectPath, packageJson) {
3890
3719
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3891
3720
  const sources = [];
3892
3721
  let confidence = 0;
3893
3722
  let version;
3894
3723
  const deps = collectAllDependencies(pkg);
3895
- if (deps['@playwright/test']) {
3724
+ if (deps['vitest']) {
3896
3725
  confidence += 70;
3897
- version = parseVersionString(deps['@playwright/test']);
3898
- sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3899
- }
3900
- if (deps['playwright']) {
3901
- confidence += 50;
3902
- version = version ?? parseVersionString(deps['playwright']);
3903
- sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3726
+ version = parseVersionString(deps['vitest']);
3727
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3904
3728
  }
3905
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3729
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3906
3730
  if (configPath) {
3907
3731
  confidence += 25;
3908
3732
  sources.push({ type: 'config-file', path: configPath });
3909
3733
  }
3910
- if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3911
- confidence += 5;
3912
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3734
+ if (!configPath) {
3735
+ const viteConfig = exists(join$1(projectPath, 'vite.config.ts')) ||
3736
+ exists(join$1(projectPath, 'vite.config.js')) ||
3737
+ exists(join$1(projectPath, 'vite.config.mjs'));
3738
+ if (viteConfig && deps['vitest']) {
3739
+ confidence += 5;
3740
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3741
+ }
3913
3742
  }
3914
- const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3915
- if (e2eScript.includes('playwright')) {
3916
- confidence += 5;
3917
- sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3743
+ const testScript = pkg?.scripts?.['test'] ?? '';
3744
+ if (testScript.includes('vitest')) {
3745
+ confidence += 10;
3746
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3918
3747
  }
3919
3748
  if (confidence === 0) {
3920
3749
  return null;
3921
3750
  }
3922
3751
  return {
3923
- id: 'playwright',
3924
- name: 'Playwright',
3925
- type: 'e2e',
3752
+ id: 'vitest',
3753
+ name: 'Vitest',
3754
+ type: 'unit',
3926
3755
  version,
3927
3756
  configPath,
3928
3757
  confidence: min(confidence, 100),
@@ -3952,7 +3781,7 @@ function checkTsConfigStrict(projectPath) {
3952
3781
  return undefined;
3953
3782
  try {
3954
3783
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3955
- const parsed = parse(cleanContent);
3784
+ const parsed = parse$1(cleanContent);
3956
3785
  return parsed?.compilerOptions?.strict === true;
3957
3786
  }
3958
3787
  catch {
@@ -3965,6 +3794,19 @@ function checkTsConfigStrict(projectPath) {
3965
3794
  * @param projectPath - Project directory path
3966
3795
  * @param packageJson - Optional pre-loaded package.json
3967
3796
  * @returns Detection result or null if not detected
3797
+ *
3798
+ * @example Detecting TypeScript
3799
+ * ```typescript
3800
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3801
+ *
3802
+ * const result = typescriptDetector('./my-project')
3803
+ * if (result) {
3804
+ * console.log(`TypeScript ${result.version}`)
3805
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3806
+ * // => "TypeScript 5.3.0"
3807
+ * // => "Strict mode: true"
3808
+ * }
3809
+ * ```
3968
3810
  */
3969
3811
  function typescriptDetector(projectPath, packageJson) {
3970
3812
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4016,6 +3858,17 @@ function typescriptDetector(projectPath, packageJson) {
4016
3858
  * @param projectPath - Project directory path
4017
3859
  * @param packageJson - Optional pre-loaded package.json
4018
3860
  * @returns Detection result or null if not detected
3861
+ *
3862
+ * @example Detecting Flow type system
3863
+ * ```typescript
3864
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3865
+ *
3866
+ * const result = flowDetector('./my-project')
3867
+ * if (result) {
3868
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3869
+ * // => "Flow 0.232.0 with config: .flowconfig"
3870
+ * }
3871
+ * ```
4019
3872
  */
4020
3873
  function flowDetector(projectPath, packageJson) {
4021
3874
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4073,6 +3926,18 @@ function hasJsDocTypes(content) {
4073
3926
  * @param projectPath - Project directory path
4074
3927
  * @param packageJson - Optional pre-loaded package.json
4075
3928
  * @returns Detection result or null if not detected
3929
+ *
3930
+ * @example Detecting JSDoc type annotations
3931
+ * ```typescript
3932
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3933
+ *
3934
+ * const result = jsdocDetector('./my-project')
3935
+ * if (result) {
3936
+ * console.log('JSDoc types detected')
3937
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3938
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3939
+ * }
3940
+ * ```
4076
3941
  */
4077
3942
  function jsdocDetector(projectPath, packageJson) {
4078
3943
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4089,7 +3954,7 @@ function jsdocDetector(projectPath, packageJson) {
4089
3954
  if (content) {
4090
3955
  try {
4091
3956
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
4092
- const parsed = parse(cleanContent);
3957
+ const parsed = parse$1(cleanContent);
4093
3958
  if (parsed?.compilerOptions?.checkJs === true || parsed?.compilerOptions?.allowJs === true) {
4094
3959
  confidence += 30;
4095
3960
  sources.push({ type: 'config-file', path: 'tsconfig.json (checkJs/allowJs)' });
@@ -4166,7 +4031,7 @@ function isDetectAllOptions(value) {
4166
4031
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
4167
4032
  * @returns All detection results organized by category
4168
4033
  *
4169
- * @example
4034
+ * @example Running all tech detectors
4170
4035
  * ```typescript
4171
4036
  * import { detectAll } from '@hyperfrontend/project-scope'
4172
4037
  *
@@ -4258,7 +4123,7 @@ const projectTypeLogger = createScopedLogger('project-scope:heuristics:project-t
4258
4123
  * @param options - Detection options
4259
4124
  * @returns Project type detection result with confidence score
4260
4125
  *
4261
- * @example
4126
+ * @example Detecting project type
4262
4127
  * ```typescript
4263
4128
  * import { detectProjectType } from '@hyperfrontend/project-scope'
4264
4129
  *
@@ -4376,7 +4241,7 @@ function detectProjectType(projectPath, options) {
4376
4241
  const projectJsonContent = readFileIfExists(projectJsonPath);
4377
4242
  if (projectJsonContent) {
4378
4243
  try {
4379
- const projectJson = parse(projectJsonContent);
4244
+ const projectJson = parse$1(projectJsonContent);
4380
4245
  if (projectJson.projectType) {
4381
4246
  const nxType = projectJson.projectType === 'library' ? 'library' : 'application';
4382
4247
  typeScores[nxType] += 50;
@@ -4436,6 +4301,15 @@ createScopedLogger('project-scope:root');
4436
4301
  * @param startPath - Starting path
4437
4302
  * @param markers - Files to search for
4438
4303
  * @returns Root directory path or null
4304
+ *
4305
+ * @example Finding root by marker files
4306
+ * ```typescript
4307
+ * import { findRootDirectory } from '@hyperfrontend/project-scope'
4308
+ *
4309
+ * // Find monorepo root by looking for nx.json or lerna.json
4310
+ * const root = findRootDirectory('./libs/my-lib', ['nx.json', 'lerna.json'])
4311
+ * // => '/path/to/monorepo'
4312
+ * ```
4439
4313
  */
4440
4314
  function findRootDirectory(startPath, markers) {
4441
4315
  return locateByMarkers(startPath, markers);
@@ -4452,7 +4326,7 @@ const NX_CONFIG_FILES = ['nx.json', 'workspace.json'];
4452
4326
  * @param path - Directory path to check
4453
4327
  * @returns True if the directory contains nx.json or workspace.json
4454
4328
  *
4455
- * @example
4329
+ * @example Checking for NX workspace
4456
4330
  * ```typescript
4457
4331
  * import { isNxWorkspace } from '@hyperfrontend/project-scope'
4458
4332
  *
@@ -4477,7 +4351,7 @@ function isNxWorkspace(path) {
4477
4351
  * @param startPath - Starting path to search from
4478
4352
  * @returns Workspace root path or null if not found
4479
4353
  *
4480
- * @example
4354
+ * @example Finding NX workspace root
4481
4355
  * ```typescript
4482
4356
  * import { findNxWorkspaceRoot } from '@hyperfrontend/project-scope'
4483
4357
  *
@@ -4499,178 +4373,8 @@ function findNxWorkspaceRoot(startPath) {
4499
4373
  return result;
4500
4374
  }
4501
4375
 
4502
- createScopedLogger('project-scope:nx:devkit');
4503
-
4504
4376
  createScopedLogger('project-scope:nx:config');
4505
4377
 
4506
- /**
4507
- * Known configuration file patterns organized by type.
4508
- */
4509
- const CONFIG_PATTERNS = {
4510
- 'package.json': {
4511
- patterns: ['package.json'],
4512
- format: 'json',
4513
- description: 'NPM package manifest',
4514
- },
4515
- 'package-lock.json': {
4516
- patterns: ['package-lock.json'],
4517
- format: 'json',
4518
- description: 'NPM lockfile',
4519
- },
4520
- 'pnpm-lock.yaml': {
4521
- patterns: ['pnpm-lock.yaml'],
4522
- format: 'yaml',
4523
- description: 'PNPM lockfile',
4524
- },
4525
- 'yarn.lock': {
4526
- patterns: ['yarn.lock'],
4527
- format: 'text',
4528
- description: 'Yarn lockfile',
4529
- },
4530
- '.npmrc': {
4531
- patterns: ['.npmrc'],
4532
- format: 'ini',
4533
- description: 'NPM configuration',
4534
- sensitive: true,
4535
- },
4536
- tsconfig: {
4537
- patterns: ['tsconfig.json', 'tsconfig.*.json'],
4538
- format: 'jsonc',
4539
- description: 'TypeScript configuration',
4540
- canExtend: true,
4541
- },
4542
- nx: {
4543
- patterns: ['nx.json'],
4544
- format: 'json',
4545
- description: 'NX workspace configuration',
4546
- },
4547
- 'project.json': {
4548
- patterns: ['project.json', '**/project.json'],
4549
- format: 'json',
4550
- description: 'NX project configuration',
4551
- },
4552
- 'workspace.json': {
4553
- patterns: ['workspace.json'],
4554
- format: 'json',
4555
- description: 'NX workspace projects (deprecated)',
4556
- },
4557
- turbo: {
4558
- patterns: ['turbo.json'],
4559
- format: 'jsonc',
4560
- description: 'TurboRepo configuration',
4561
- },
4562
- lerna: {
4563
- patterns: ['lerna.json'],
4564
- format: 'json',
4565
- description: 'Lerna configuration',
4566
- },
4567
- webpack: {
4568
- patterns: ['webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs', 'webpack.config.mjs'],
4569
- format: 'js',
4570
- description: 'Webpack configuration',
4571
- },
4572
- rollup: {
4573
- patterns: ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs'],
4574
- format: 'js',
4575
- description: 'Rollup configuration',
4576
- },
4577
- vite: {
4578
- patterns: ['vite.config.js', 'vite.config.ts', 'vite.config.mjs'],
4579
- format: 'js',
4580
- description: 'Vite configuration',
4581
- },
4582
- esbuild: {
4583
- patterns: ['esbuild.config.js', 'esbuild.config.ts', 'esbuild.config.mjs'],
4584
- format: 'js',
4585
- description: 'esbuild configuration',
4586
- },
4587
- babel: {
4588
- patterns: ['babel.config.js', 'babel.config.json', '.babelrc', '.babelrc.js', '.babelrc.json'],
4589
- format: 'json',
4590
- description: 'Babel configuration',
4591
- },
4592
- swc: {
4593
- patterns: ['.swcrc'],
4594
- format: 'json',
4595
- description: 'SWC configuration',
4596
- },
4597
- jest: {
4598
- patterns: ['jest.config.js', 'jest.config.ts', 'jest.config.mjs'],
4599
- description: 'Jest configuration',
4600
- },
4601
- vitest: {
4602
- patterns: ['vitest.config.js', 'vitest.config.ts'],
4603
- description: 'Vitest configuration',
4604
- },
4605
- cypress: {
4606
- patterns: ['cypress.config.js', 'cypress.config.ts'],
4607
- description: 'Cypress configuration',
4608
- },
4609
- playwright: {
4610
- patterns: ['playwright.config.js', 'playwright.config.ts'],
4611
- description: 'Playwright configuration',
4612
- },
4613
- next: {
4614
- patterns: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
4615
- format: 'js',
4616
- description: 'Next.js configuration',
4617
- },
4618
- angular: {
4619
- patterns: ['angular.json'],
4620
- format: 'json',
4621
- description: 'Angular CLI configuration',
4622
- },
4623
- nuxt: {
4624
- patterns: ['nuxt.config.js', 'nuxt.config.ts'],
4625
- format: 'js',
4626
- description: 'Nuxt.js configuration',
4627
- },
4628
- svelte: {
4629
- patterns: ['svelte.config.js', 'svelte.config.ts'],
4630
- format: 'js',
4631
- description: 'SvelteKit configuration',
4632
- },
4633
- astro: {
4634
- patterns: ['astro.config.js', 'astro.config.ts', 'astro.config.mjs'],
4635
- format: 'js',
4636
- description: 'Astro configuration',
4637
- },
4638
- eslint: {
4639
- patterns: [
4640
- 'eslint.config.js',
4641
- 'eslint.config.cjs',
4642
- 'eslint.config.mjs',
4643
- '.eslintrc',
4644
- '.eslintrc.js',
4645
- '.eslintrc.json',
4646
- '.eslintrc.yml',
4647
- ],
4648
- format: 'js',
4649
- description: 'ESLint configuration',
4650
- },
4651
- prettier: {
4652
- patterns: ['prettier.config.js', 'prettier.config.cjs', '.prettierrc', '.prettierrc.js', '.prettierrc.json', '.prettierrc.yml'],
4653
- format: 'json',
4654
- description: 'Prettier configuration',
4655
- },
4656
- env: {
4657
- patterns: ['.env', '.env.*', '*.env'],
4658
- format: 'dotenv',
4659
- description: 'Environment variables',
4660
- sensitive: true,
4661
- },
4662
- '.gitignore': {
4663
- patterns: ['.gitignore'],
4664
- format: 'text',
4665
- description: 'Git ignore patterns',
4666
- },
4667
- '.gitattributes': {
4668
- patterns: ['.gitattributes'],
4669
- format: 'text',
4670
- description: 'Git attributes',
4671
- },
4672
- };
4673
-
4674
4378
  const configLogger = createScopedLogger('project-scope:config');
4675
4379
  /**
4676
4380
  * Cache for config detection results.
@@ -4688,7 +4392,7 @@ const configDetectionCache = createCache({ ttl: 30000, maxSize: 50 });
4688
4392
  * @param options - Detection options
4689
4393
  * @returns Array of detected configuration files
4690
4394
  *
4691
- * @example
4395
+ * @example Detecting configuration files
4692
4396
  * ```typescript
4693
4397
  * import { detectConfigs } from '@hyperfrontend/project-scope'
4694
4398
  *
@@ -4765,25 +4469,6 @@ function detectConfigs(rootPath, types, options) {
4765
4469
  return results;
4766
4470
  }
4767
4471
 
4768
- /**
4769
- * Safe copies of Number built-in methods and constants.
4770
- *
4771
- * These references are captured at module initialization time to protect against
4772
- * prototype pollution attacks. Import only what you need for tree-shaking.
4773
- *
4774
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/number
4775
- */
4776
- const _parseInt = globalThis.parseInt;
4777
- const _parseFloat = globalThis.parseFloat;
4778
- /**
4779
- * (Safe copy) Parses a string and returns an integer.
4780
- */
4781
- const parseInt = _parseInt;
4782
- /**
4783
- * (Safe copy) Parses a string and returns a floating point number.
4784
- */
4785
- const parseFloat = _parseFloat;
4786
-
4787
4472
  /**
4788
4473
  * Detect config type from file name.
4789
4474
  * Uses safe character-by-character matching to prevent ReDoS attacks.
@@ -4995,11 +4680,23 @@ function parseDotenv(content) {
4995
4680
  * @param type - Category of configuration (e.g., typescript, eslint)
4996
4681
  * @param format - Whether to strip comments (jsonc) or parse strictly (json)
4997
4682
  * @returns Configuration object with parsed data and extends references
4683
+ *
4684
+ * @example Parsing JSON configuration
4685
+ * ```typescript
4686
+ * import { parseJsonConfig } from '@hyperfrontend/project-scope'
4687
+ *
4688
+ * const config = parseJsonConfig(
4689
+ * 'tsconfig.json',
4690
+ * '{ "extends": "./base.json", "compilerOptions": {} }',
4691
+ * 'typescript'
4692
+ * )
4693
+ * // => { type: 'typescript', path: 'tsconfig.json', data: {...}, extends: ['./base.json'] }
4694
+ * ```
4998
4695
  */
4999
4696
  function parseJsonConfig(filePath, content, type, format = 'json') {
5000
4697
  const cleanContent = format === 'jsonc' ? stripJsonComments(content) : content;
5001
4698
  try {
5002
- const data = parse(cleanContent);
4699
+ const data = parse$1(cleanContent);
5003
4700
  let extendsPath;
5004
4701
  if (typeof data['extends'] === 'string') {
5005
4702
  extendsPath = [data['extends']];
@@ -5030,6 +4727,14 @@ function parseJsonConfig(filePath, content, type, format = 'json') {
5030
4727
  * @param content - Raw file content to parse
5031
4728
  * @param type - Category of configuration (e.g., github-actions, docker-compose)
5032
4729
  * @returns Configuration object with parsed YAML data
4730
+ *
4731
+ * @example Parsing YAML configuration
4732
+ * ```typescript
4733
+ * import { parseYamlConfig } from '@hyperfrontend/project-scope'
4734
+ *
4735
+ * const config = parseYamlConfig('.github/workflows/ci.yml', yamlContent, 'github-actions')
4736
+ * // => { type: 'github-actions', path: '...', format: 'yaml', data: {...} }
4737
+ * ```
5033
4738
  */
5034
4739
  function parseYamlConfig(filePath, content, type) {
5035
4740
  const data = parseSimpleYaml(content);
@@ -5046,6 +4751,14 @@ function parseYamlConfig(filePath, content, type) {
5046
4751
  * @param filePath - Path to config file
5047
4752
  * @param type - Optional config type (auto-detected if not provided)
5048
4753
  * @returns Parsed configuration
4754
+ *
4755
+ * @example Parsing a configuration file
4756
+ * ```typescript
4757
+ * import { parseConfig } from '@hyperfrontend/project-scope'
4758
+ *
4759
+ * const tsConfig = parseConfig('/project/tsconfig.json')
4760
+ * const eslintConfig = parseConfig('/project/.eslintrc.yml', 'eslint')
4761
+ * ```
5049
4762
  */
5050
4763
  function parseConfig(filePath, type) {
5051
4764
  const content = readFileContent(filePath);
@@ -5178,7 +4891,7 @@ function normalizeConfigFormat(format) {
5178
4891
  * @param options - Analysis options
5179
4892
  * @returns Complete analysis result
5180
4893
  *
5181
- * @example
4894
+ * @example Basic project analysis
5182
4895
  * ```typescript
5183
4896
  * const result = analyzeProject('./my-project')
5184
4897
  * console.log(result.projectType) // 'application' | 'library' | ...
@@ -5511,6 +5224,26 @@ function parseAnalyzeArgs(args) {
5511
5224
  *
5512
5225
  * @param options - Configuration for the analyze operation
5513
5226
  * @returns Command execution result with exit code and output
5227
+ *
5228
+ * @example Basic analysis of current directory
5229
+ * ```typescript
5230
+ * const result = analyzeCommand({ depth: 'basic' })
5231
+ * if (result.exitCode === 0) {
5232
+ * console.log(result.output)
5233
+ * // => "Project Type: Library\nWorkspace: NX Monorepo\n..."
5234
+ * }
5235
+ * ```
5236
+ *
5237
+ * @example JSON output with filters
5238
+ * ```typescript
5239
+ * const result = analyzeCommand({
5240
+ * path: './apps/frontend',
5241
+ * format: 'json',
5242
+ * depth: 'deep',
5243
+ * exclude: ['node_modules', 'dist'],
5244
+ * })
5245
+ * // => { exitCode: 0, output: '{"type":"application",...}' }
5246
+ * ```
5514
5247
  */
5515
5248
  function analyzeCommand(options) {
5516
5249
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -5790,6 +5523,26 @@ function parseConfigArgs(args) {
5790
5523
  *
5791
5524
  * @param options - Configuration command options
5792
5525
  * @returns Command execution result with exit code and output
5526
+ *
5527
+ * @example Detect all configs in a project
5528
+ * ```typescript
5529
+ * const result = configCommand({ path: './my-project' })
5530
+ * if (result.exitCode === 0) {
5531
+ * console.log(result.output)
5532
+ * // => "TypeScript: tsconfig.json\nLinting: eslint.config.js\n..."
5533
+ * }
5534
+ * ```
5535
+ *
5536
+ * @example Filter by type with contents
5537
+ * ```typescript
5538
+ * const result = configCommand({
5539
+ * path: './my-project',
5540
+ * type: 'tsconfig',
5541
+ * showContents: true,
5542
+ * format: 'json',
5543
+ * })
5544
+ * // => { exitCode: 0, output: '[{"type":"tsconfig","path":"tsconfig.json",...}]' }
5545
+ * ```
5793
5546
  */
5794
5547
  function configCommand(options) {
5795
5548
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -5999,6 +5752,25 @@ function parseDepsArgs(args) {
5999
5752
  *
6000
5753
  * @param options - Parsed command options
6001
5754
  * @returns Command execution result with exit code and output
5755
+ *
5756
+ * @example List all dependencies
5757
+ * ```typescript
5758
+ * const result = depsCommand({ path: './my-project' })
5759
+ * if (result.exitCode === 0) {
5760
+ * console.log(result.output)
5761
+ * // => "Dependencies\n============\nProduction (3):\n react ^18.2.0\n..."
5762
+ * }
5763
+ * ```
5764
+ *
5765
+ * @example Filter to dev dependencies as JSON
5766
+ * ```typescript
5767
+ * const result = depsCommand({
5768
+ * path: './my-project',
5769
+ * type: 'development',
5770
+ * format: 'json',
5771
+ * })
5772
+ * // => { exitCode: 0, output: '{"devDependencies":{"typescript":"^5.0.0",...}}' }
5773
+ * ```
6002
5774
  */
6003
5775
  function depsCommand(options) {
6004
5776
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -6275,6 +6047,27 @@ function parseTreeArgs(args) {
6275
6047
  *
6276
6048
  * @param options - Configuration for the tree operation
6277
6049
  * @returns Command execution result with exit code and output
6050
+ *
6051
+ * @example Basic tree of current directory
6052
+ * ```typescript
6053
+ * const result = treeCommand({ depth: 2 })
6054
+ * if (result.exitCode === 0) {
6055
+ * console.log(result.output)
6056
+ * // => "src/\n├── index.ts\n├── lib/\n│ └── utils.ts\n..."
6057
+ * }
6058
+ * ```
6059
+ *
6060
+ * @example Directories only with metadata
6061
+ * ```typescript
6062
+ * const result = treeCommand({
6063
+ * path: './project',
6064
+ * dirsOnly: true,
6065
+ * showSize: true,
6066
+ * ignore: ['node_modules', '.git'],
6067
+ * format: 'json',
6068
+ * })
6069
+ * // => { exitCode: 0, output: '[{"name":"src","isDirectory":true,...}]' }
6070
+ * ```
6278
6071
  */
6279
6072
  function treeCommand(options) {
6280
6073
  const rootPath = options.path ? resolve(options.path) : process.cwd();
@@ -6432,7 +6225,7 @@ function parseGlobalOptions(args) {
6432
6225
  * @param args - Command line arguments (typically process.argv.slice(2))
6433
6226
  * @returns Command result with exit code and optional output/error
6434
6227
  *
6435
- * @example
6228
+ * @example Running analysis via CLI
6436
6229
  * ```typescript
6437
6230
  * import { run } from '@hyperfrontend/project-scope'
6438
6231
  *
@@ -6493,4 +6286,3 @@ function run(args) {
6493
6286
  }
6494
6287
 
6495
6288
  export { analyzeCommand, analyzeCommandDef, configCommand, configCommandDef, depsCommand, depsCommandDef, run, treeCommand, treeCommandDef };
6496
- //# sourceMappingURL=index.esm.js.map