@hyperfrontend/project-scope 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +3 -4
  3. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs.js +7 -0
  4. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js +5 -0
  5. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.cjs.js +13 -0
  6. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js +8 -0
  7. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.cjs.js +10 -0
  8. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js +8 -0
  9. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs.js +6 -0
  10. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js +5 -0
  11. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.cjs.js +7 -0
  12. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js +5 -0
  13. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js +6 -0
  14. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js +5 -0
  15. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js +9 -0
  16. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js +6 -0
  17. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.cjs.js +7 -0
  18. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js +7 -0
  19. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs.js +15 -0
  20. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js +9 -0
  21. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js +6 -0
  22. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js +5 -0
  23. package/_dependencies/@hyperfrontend/logging/index.cjs.js +191 -0
  24. package/_dependencies/@hyperfrontend/logging/index.d.ts +151 -0
  25. package/_dependencies/@hyperfrontend/logging/index.esm.js +186 -0
  26. package/_shared/core/cache/index.cjs.js +135 -0
  27. package/_shared/core/cache/index.esm.js +128 -0
  28. package/_shared/core/errors/structured-errors/index.cjs.js +28 -0
  29. package/_shared/core/errors/structured-errors/index.esm.js +23 -0
  30. package/_shared/core/fs/guard/index.cjs.js +7 -0
  31. package/_shared/core/fs/guard/index.esm.js +5 -0
  32. package/_shared/core/fs/stat/index.cjs.js +47 -0
  33. package/_shared/core/fs/stat/index.esm.js +41 -0
  34. package/_shared/core/path/confine/index.cjs.js +22 -0
  35. package/_shared/core/path/confine/index.esm.js +19 -0
  36. package/_shared/core/path/join/index.cjs.js +13 -0
  37. package/_shared/core/path/join/index.esm.js +10 -0
  38. package/_shared/core/path/normalize/index.cjs.js +37 -0
  39. package/_shared/core/path/normalize/index.esm.js +31 -0
  40. package/_shared/core/path/resolve/index.cjs.js +47 -0
  41. package/_shared/core/path/resolve/index.esm.js +41 -0
  42. package/_shared/core/path/segments/index.cjs.js +38 -0
  43. package/_shared/core/path/segments/index.esm.js +31 -0
  44. package/_shared/core/patterns/glob/index.cjs.js +145 -0
  45. package/_shared/core/patterns/glob/index.esm.js +136 -0
  46. package/_shared/core/platform/detect/index.cjs.js +103 -0
  47. package/_shared/core/platform/detect/index.esm.js +95 -0
  48. package/_shared/core/platform/line-endings/index.cjs.js +52 -0
  49. package/_shared/core/platform/line-endings/index.esm.js +44 -0
  50. package/_shared/project/config/patterns/index.cjs.js +172 -0
  51. package/_shared/project/config/patterns/index.esm.js +169 -0
  52. package/_shared/tech/monorepo/pnpm-workspaces/index.cjs.js +33 -0
  53. package/_shared/tech/monorepo/pnpm-workspaces/index.esm.js +31 -0
  54. package/_shared/tech/shared-utils/detector-helpers/index.cjs.js +48 -0
  55. package/_shared/tech/shared-utils/detector-helpers/index.esm.js +43 -0
  56. package/_shared/vfs/types/index.cjs.js +14 -0
  57. package/_shared/vfs/types/index.esm.js +12 -0
  58. package/cli/index.cjs.js +1706 -1910
  59. package/cli/index.d.ts +273 -7
  60. package/cli/index.d.ts.map +1 -1
  61. package/cli/index.esm.js +1593 -1797
  62. package/core/encoding/index.cjs.js +86 -401
  63. package/core/encoding/index.d.ts +186 -3
  64. package/core/encoding/index.d.ts.map +1 -1
  65. package/core/encoding/index.esm.js +78 -392
  66. package/core/fs/index.cjs.js +243 -583
  67. package/core/fs/index.d.ts +479 -6
  68. package/core/fs/index.d.ts.map +1 -1
  69. package/core/fs/index.esm.js +233 -573
  70. package/core/index.cjs.js +526 -1746
  71. package/core/index.d.ts +486 -9
  72. package/core/index.d.ts.map +1 -1
  73. package/core/index.esm.js +515 -1732
  74. package/core/path/index.cjs.js +8 -234
  75. package/core/path/index.d.ts +327 -5
  76. package/core/path/index.d.ts.map +1 -1
  77. package/core/path/index.esm.js +8 -235
  78. package/core/platform/index.cjs.js +5 -216
  79. package/core/platform/index.d.ts +185 -3
  80. package/core/platform/index.d.ts.map +1 -1
  81. package/core/platform/index.esm.js +3 -212
  82. package/heuristics/dependencies/index.cjs.js +105 -493
  83. package/heuristics/dependencies/index.d.ts +99 -2
  84. package/heuristics/dependencies/index.d.ts.map +1 -1
  85. package/heuristics/dependencies/index.esm.js +81 -469
  86. package/heuristics/entry-points/index.cjs.js +93 -796
  87. package/heuristics/entry-points/index.d.ts +123 -2
  88. package/heuristics/entry-points/index.d.ts.map +1 -1
  89. package/heuristics/entry-points/index.esm.js +74 -777
  90. package/heuristics/framework/index.cjs.js +1483 -1411
  91. package/heuristics/framework/index.d.ts +104 -2
  92. package/heuristics/framework/index.d.ts.map +1 -1
  93. package/heuristics/framework/index.esm.js +1419 -1347
  94. package/heuristics/index.cjs.js +3220 -3306
  95. package/heuristics/index.d.ts +4 -5
  96. package/heuristics/index.d.ts.map +1 -1
  97. package/heuristics/index.esm.js +3244 -3330
  98. package/heuristics/project-type/index.cjs.js +1489 -1438
  99. package/heuristics/project-type/index.d.ts +64 -2
  100. package/heuristics/project-type/index.d.ts.map +1 -1
  101. package/heuristics/project-type/index.esm.js +1419 -1368
  102. package/index.cjs.js +3058 -3532
  103. package/index.d.ts +44 -10
  104. package/index.d.ts.map +1 -1
  105. package/index.esm.js +2914 -3376
  106. package/models/index.cjs.js +0 -1
  107. package/models/index.d.ts +20 -14
  108. package/models/index.d.ts.map +1 -1
  109. package/models/index.esm.js +0 -1
  110. package/nx/index.cjs.js +166 -579
  111. package/nx/index.d.ts +279 -4
  112. package/nx/index.d.ts.map +1 -1
  113. package/nx/index.esm.js +148 -556
  114. package/package.json +13 -12
  115. package/project/config/index.cjs.js +127 -1063
  116. package/project/config/index.d.ts +202 -4
  117. package/project/config/index.d.ts.map +1 -1
  118. package/project/config/index.esm.js +110 -1044
  119. package/project/index.cjs.js +328 -1101
  120. package/project/index.d.ts +4 -5
  121. package/project/index.d.ts.map +1 -1
  122. package/project/index.esm.js +307 -1077
  123. package/project/package/index.cjs.js +196 -473
  124. package/project/package/index.d.ts +280 -3
  125. package/project/package/index.d.ts.map +1 -1
  126. package/project/package/index.esm.js +183 -459
  127. package/project/root/index.cjs.js +109 -417
  128. package/project/root/index.d.ts +83 -2
  129. package/project/root/index.d.ts.map +1 -1
  130. package/project/root/index.esm.js +98 -406
  131. package/project/traversal/index.cjs.js +96 -622
  132. package/project/traversal/index.d.ts +165 -3
  133. package/project/traversal/index.d.ts.map +1 -1
  134. package/project/traversal/index.esm.js +82 -608
  135. package/tech/backend/index.cjs.js +223 -508
  136. package/tech/backend/index.d.ts +205 -8
  137. package/tech/backend/index.d.ts.map +1 -1
  138. package/tech/backend/index.esm.js +202 -487
  139. package/tech/build/index.cjs.js +350 -636
  140. package/tech/build/index.d.ts +276 -10
  141. package/tech/build/index.d.ts.map +1 -1
  142. package/tech/build/index.esm.js +328 -614
  143. package/tech/frontend/index.cjs.js +507 -685
  144. package/tech/frontend/index.d.ts +379 -15
  145. package/tech/frontend/index.d.ts.map +1 -1
  146. package/tech/frontend/index.esm.js +483 -661
  147. package/tech/index.cjs.js +1581 -1420
  148. package/tech/index.d.ts +55 -32
  149. package/tech/index.d.ts.map +1 -1
  150. package/tech/index.esm.js +1515 -1354
  151. package/tech/legacy/index.cjs.js +99 -449
  152. package/tech/legacy/index.d.ts +125 -7
  153. package/tech/legacy/index.d.ts.map +1 -1
  154. package/tech/legacy/index.esm.js +81 -431
  155. package/tech/linting/index.cjs.js +138 -523
  156. package/tech/linting/index.d.ts +129 -7
  157. package/tech/linting/index.d.ts.map +1 -1
  158. package/tech/linting/index.esm.js +118 -503
  159. package/tech/monorepo/index.cjs.js +246 -573
  160. package/tech/monorepo/index.d.ts +241 -10
  161. package/tech/monorepo/index.d.ts.map +1 -1
  162. package/tech/monorepo/index.esm.js +226 -553
  163. package/tech/testing/index.cjs.js +216 -571
  164. package/tech/testing/index.d.ts +176 -8
  165. package/tech/testing/index.d.ts.map +1 -1
  166. package/tech/testing/index.esm.js +198 -553
  167. package/tech/types/index.cjs.js +123 -506
  168. package/tech/types/index.d.ts +120 -2
  169. package/tech/types/index.d.ts.map +1 -1
  170. package/tech/types/index.esm.js +101 -484
  171. package/vfs/index.cjs.js +647 -1142
  172. package/vfs/index.d.ts +360 -6
  173. package/vfs/index.d.ts.map +1 -1
  174. package/vfs/index.esm.js +672 -1167
  175. package/ARCHITECTURE.md +0 -370
  176. package/analyze.d.ts +0 -33
  177. package/analyze.d.ts.map +0 -1
  178. package/cli/commands/analyze.d.ts +0 -28
  179. package/cli/commands/analyze.d.ts.map +0 -1
  180. package/cli/commands/config.d.ts +0 -27
  181. package/cli/commands/config.d.ts.map +0 -1
  182. package/cli/commands/deps.d.ts +0 -24
  183. package/cli/commands/deps.d.ts.map +0 -1
  184. package/cli/commands/tree.d.ts +0 -36
  185. package/cli/commands/tree.d.ts.map +0 -1
  186. package/cli/index.cjs.js.map +0 -1
  187. package/cli/index.esm.js.map +0 -1
  188. package/cli/run.d.ts +0 -25
  189. package/cli/run.d.ts.map +0 -1
  190. package/cli/types.d.ts +0 -55
  191. package/cli/types.d.ts.map +0 -1
  192. package/core/cache.d.ts +0 -158
  193. package/core/cache.d.ts.map +0 -1
  194. package/core/encoding/convert.d.ts +0 -32
  195. package/core/encoding/convert.d.ts.map +0 -1
  196. package/core/encoding/detect.d.ts +0 -91
  197. package/core/encoding/detect.d.ts.map +0 -1
  198. package/core/encoding/index.cjs.js.map +0 -1
  199. package/core/encoding/index.esm.js.map +0 -1
  200. package/core/errors/structured-errors.d.ts +0 -66
  201. package/core/errors/structured-errors.d.ts.map +0 -1
  202. package/core/fs/directory.d.ts +0 -91
  203. package/core/fs/directory.d.ts.map +0 -1
  204. package/core/fs/index.cjs.js.map +0 -1
  205. package/core/fs/index.esm.js.map +0 -1
  206. package/core/fs/read.d.ts +0 -94
  207. package/core/fs/read.d.ts.map +0 -1
  208. package/core/fs/stat.d.ts +0 -58
  209. package/core/fs/stat.d.ts.map +0 -1
  210. package/core/fs/traversal.d.ts +0 -26
  211. package/core/fs/traversal.d.ts.map +0 -1
  212. package/core/fs/write.d.ts +0 -75
  213. package/core/fs/write.d.ts.map +0 -1
  214. package/core/index.cjs.js.map +0 -1
  215. package/core/index.esm.js.map +0 -1
  216. package/core/logger.d.ts +0 -111
  217. package/core/logger.d.ts.map +0 -1
  218. package/core/path/index.cjs.js.map +0 -1
  219. package/core/path/index.esm.js.map +0 -1
  220. package/core/path/join.d.ts +0 -17
  221. package/core/path/join.d.ts.map +0 -1
  222. package/core/path/normalize.d.ts +0 -37
  223. package/core/path/normalize.d.ts.map +0 -1
  224. package/core/path/resolve.d.ts +0 -52
  225. package/core/path/resolve.d.ts.map +0 -1
  226. package/core/path/segments.d.ts +0 -59
  227. package/core/path/segments.d.ts.map +0 -1
  228. package/core/patterns/glob.d.ts +0 -42
  229. package/core/patterns/glob.d.ts.map +0 -1
  230. package/core/platform/detect.d.ts +0 -66
  231. package/core/platform/detect.d.ts.map +0 -1
  232. package/core/platform/index.cjs.js.map +0 -1
  233. package/core/platform/index.esm.js.map +0 -1
  234. package/core/platform/line-endings.d.ts +0 -48
  235. package/core/platform/line-endings.d.ts.map +0 -1
  236. package/heuristics/dependencies/analyze.d.ts +0 -77
  237. package/heuristics/dependencies/analyze.d.ts.map +0 -1
  238. package/heuristics/dependencies/index.cjs.js.map +0 -1
  239. package/heuristics/dependencies/index.esm.js.map +0 -1
  240. package/heuristics/entry-points/discover.d.ts +0 -113
  241. package/heuristics/entry-points/discover.d.ts.map +0 -1
  242. package/heuristics/entry-points/index.cjs.js.map +0 -1
  243. package/heuristics/entry-points/index.esm.js.map +0 -1
  244. package/heuristics/framework/identify.d.ts +0 -84
  245. package/heuristics/framework/identify.d.ts.map +0 -1
  246. package/heuristics/framework/index.cjs.js.map +0 -1
  247. package/heuristics/framework/index.esm.js.map +0 -1
  248. package/heuristics/index.cjs.js.map +0 -1
  249. package/heuristics/index.esm.js.map +0 -1
  250. package/heuristics/project-type/detect.d.ts +0 -61
  251. package/heuristics/project-type/detect.d.ts.map +0 -1
  252. package/heuristics/project-type/index.cjs.js.map +0 -1
  253. package/heuristics/project-type/index.esm.js.map +0 -1
  254. package/index.cjs.js.map +0 -1
  255. package/index.esm.js.map +0 -1
  256. package/models/index.cjs.js.map +0 -1
  257. package/models/index.esm.js.map +0 -1
  258. package/nx/detect.d.ts +0 -105
  259. package/nx/detect.d.ts.map +0 -1
  260. package/nx/devkit-loader.d.ts +0 -62
  261. package/nx/devkit-loader.d.ts.map +0 -1
  262. package/nx/index.cjs.js.map +0 -1
  263. package/nx/index.esm.js.map +0 -1
  264. package/nx/project-config.d.ts +0 -111
  265. package/nx/project-config.d.ts.map +0 -1
  266. package/project/config/detect.d.ts +0 -77
  267. package/project/config/detect.d.ts.map +0 -1
  268. package/project/config/index.cjs.js.map +0 -1
  269. package/project/config/index.esm.js.map +0 -1
  270. package/project/config/parse.d.ts +0 -53
  271. package/project/config/parse.d.ts.map +0 -1
  272. package/project/config/patterns.d.ts +0 -31
  273. package/project/config/patterns.d.ts.map +0 -1
  274. package/project/index.cjs.js.map +0 -1
  275. package/project/index.esm.js.map +0 -1
  276. package/project/package/dependencies.d.ts +0 -101
  277. package/project/package/dependencies.d.ts.map +0 -1
  278. package/project/package/index.cjs.js.map +0 -1
  279. package/project/package/index.esm.js.map +0 -1
  280. package/project/package/read.d.ts +0 -67
  281. package/project/package/read.d.ts.map +0 -1
  282. package/project/root/detect.d.ts +0 -65
  283. package/project/root/detect.d.ts.map +0 -1
  284. package/project/root/index.cjs.js.map +0 -1
  285. package/project/root/index.esm.js.map +0 -1
  286. package/project/traversal/index.cjs.js.map +0 -1
  287. package/project/traversal/index.esm.js.map +0 -1
  288. package/project/traversal/search.d.ts +0 -59
  289. package/project/traversal/search.d.ts.map +0 -1
  290. package/project/traversal/walk.d.ts +0 -63
  291. package/project/traversal/walk.d.ts.map +0 -1
  292. package/tech/backend/detect-all.d.ts +0 -13
  293. package/tech/backend/detect-all.d.ts.map +0 -1
  294. package/tech/backend/express.d.ts +0 -11
  295. package/tech/backend/express.d.ts.map +0 -1
  296. package/tech/backend/fastify.d.ts +0 -11
  297. package/tech/backend/fastify.d.ts.map +0 -1
  298. package/tech/backend/hono.d.ts +0 -11
  299. package/tech/backend/hono.d.ts.map +0 -1
  300. package/tech/backend/index.cjs.js.map +0 -1
  301. package/tech/backend/index.esm.js.map +0 -1
  302. package/tech/backend/koa.d.ts +0 -11
  303. package/tech/backend/koa.d.ts.map +0 -1
  304. package/tech/backend/nestjs.d.ts +0 -11
  305. package/tech/backend/nestjs.d.ts.map +0 -1
  306. package/tech/backend/types.d.ts +0 -31
  307. package/tech/backend/types.d.ts.map +0 -1
  308. package/tech/build/babel.d.ts +0 -13
  309. package/tech/build/babel.d.ts.map +0 -1
  310. package/tech/build/detect-all.d.ts +0 -13
  311. package/tech/build/detect-all.d.ts.map +0 -1
  312. package/tech/build/esbuild.d.ts +0 -11
  313. package/tech/build/esbuild.d.ts.map +0 -1
  314. package/tech/build/index.cjs.js.map +0 -1
  315. package/tech/build/index.esm.js.map +0 -1
  316. package/tech/build/parcel.d.ts +0 -13
  317. package/tech/build/parcel.d.ts.map +0 -1
  318. package/tech/build/rollup.d.ts +0 -13
  319. package/tech/build/rollup.d.ts.map +0 -1
  320. package/tech/build/swc.d.ts +0 -13
  321. package/tech/build/swc.d.ts.map +0 -1
  322. package/tech/build/types.d.ts +0 -31
  323. package/tech/build/types.d.ts.map +0 -1
  324. package/tech/build/vite.d.ts +0 -13
  325. package/tech/build/vite.d.ts.map +0 -1
  326. package/tech/build/webpack.d.ts +0 -13
  327. package/tech/build/webpack.d.ts.map +0 -1
  328. package/tech/frontend/angular.d.ts +0 -11
  329. package/tech/frontend/angular.d.ts.map +0 -1
  330. package/tech/frontend/astro.d.ts +0 -11
  331. package/tech/frontend/astro.d.ts.map +0 -1
  332. package/tech/frontend/detect-all.d.ts +0 -13
  333. package/tech/frontend/detect-all.d.ts.map +0 -1
  334. package/tech/frontend/gatsby.d.ts +0 -11
  335. package/tech/frontend/gatsby.d.ts.map +0 -1
  336. package/tech/frontend/index.cjs.js.map +0 -1
  337. package/tech/frontend/index.esm.js.map +0 -1
  338. package/tech/frontend/nextjs.d.ts +0 -11
  339. package/tech/frontend/nextjs.d.ts.map +0 -1
  340. package/tech/frontend/nuxt.d.ts +0 -11
  341. package/tech/frontend/nuxt.d.ts.map +0 -1
  342. package/tech/frontend/qwik.d.ts +0 -11
  343. package/tech/frontend/qwik.d.ts.map +0 -1
  344. package/tech/frontend/react.d.ts +0 -11
  345. package/tech/frontend/react.d.ts.map +0 -1
  346. package/tech/frontend/remix.d.ts +0 -11
  347. package/tech/frontend/remix.d.ts.map +0 -1
  348. package/tech/frontend/solid.d.ts +0 -11
  349. package/tech/frontend/solid.d.ts.map +0 -1
  350. package/tech/frontend/svelte.d.ts +0 -11
  351. package/tech/frontend/svelte.d.ts.map +0 -1
  352. package/tech/frontend/sveltekit.d.ts +0 -11
  353. package/tech/frontend/sveltekit.d.ts.map +0 -1
  354. package/tech/frontend/types.d.ts +0 -35
  355. package/tech/frontend/types.d.ts.map +0 -1
  356. package/tech/frontend/vue.d.ts +0 -11
  357. package/tech/frontend/vue.d.ts.map +0 -1
  358. package/tech/index.cjs.js.map +0 -1
  359. package/tech/index.esm.js.map +0 -1
  360. package/tech/legacy/angularjs.d.ts +0 -12
  361. package/tech/legacy/angularjs.d.ts.map +0 -1
  362. package/tech/legacy/backbone.d.ts +0 -11
  363. package/tech/legacy/backbone.d.ts.map +0 -1
  364. package/tech/legacy/detect-all.d.ts +0 -13
  365. package/tech/legacy/detect-all.d.ts.map +0 -1
  366. package/tech/legacy/ember.d.ts +0 -11
  367. package/tech/legacy/ember.d.ts.map +0 -1
  368. package/tech/legacy/index.cjs.js.map +0 -1
  369. package/tech/legacy/index.esm.js.map +0 -1
  370. package/tech/legacy/jquery.d.ts +0 -11
  371. package/tech/legacy/jquery.d.ts.map +0 -1
  372. package/tech/legacy/types.d.ts +0 -33
  373. package/tech/legacy/types.d.ts.map +0 -1
  374. package/tech/linting/biome.d.ts +0 -11
  375. package/tech/linting/biome.d.ts.map +0 -1
  376. package/tech/linting/detect-all.d.ts +0 -13
  377. package/tech/linting/detect-all.d.ts.map +0 -1
  378. package/tech/linting/eslint.d.ts +0 -13
  379. package/tech/linting/eslint.d.ts.map +0 -1
  380. package/tech/linting/index.cjs.js.map +0 -1
  381. package/tech/linting/index.esm.js.map +0 -1
  382. package/tech/linting/prettier.d.ts +0 -13
  383. package/tech/linting/prettier.d.ts.map +0 -1
  384. package/tech/linting/stylelint.d.ts +0 -13
  385. package/tech/linting/stylelint.d.ts.map +0 -1
  386. package/tech/linting/types.d.ts +0 -31
  387. package/tech/linting/types.d.ts.map +0 -1
  388. package/tech/monorepo/detect-all.d.ts +0 -13
  389. package/tech/monorepo/detect-all.d.ts.map +0 -1
  390. package/tech/monorepo/index.cjs.js.map +0 -1
  391. package/tech/monorepo/index.esm.js.map +0 -1
  392. package/tech/monorepo/lerna.d.ts +0 -11
  393. package/tech/monorepo/lerna.d.ts.map +0 -1
  394. package/tech/monorepo/npm-workspaces.d.ts +0 -11
  395. package/tech/monorepo/npm-workspaces.d.ts.map +0 -1
  396. package/tech/monorepo/nx.d.ts +0 -11
  397. package/tech/monorepo/nx.d.ts.map +0 -1
  398. package/tech/monorepo/pnpm-workspaces.d.ts +0 -9
  399. package/tech/monorepo/pnpm-workspaces.d.ts.map +0 -1
  400. package/tech/monorepo/rush.d.ts +0 -11
  401. package/tech/monorepo/rush.d.ts.map +0 -1
  402. package/tech/monorepo/turborepo.d.ts +0 -11
  403. package/tech/monorepo/turborepo.d.ts.map +0 -1
  404. package/tech/monorepo/types.d.ts +0 -39
  405. package/tech/monorepo/types.d.ts.map +0 -1
  406. package/tech/monorepo/yarn-workspaces.d.ts +0 -11
  407. package/tech/monorepo/yarn-workspaces.d.ts.map +0 -1
  408. package/tech/shared-utils/detector-helpers.d.ts +0 -52
  409. package/tech/shared-utils/detector-helpers.d.ts.map +0 -1
  410. package/tech/shared-utils/types.d.ts +0 -41
  411. package/tech/shared-utils/types.d.ts.map +0 -1
  412. package/tech/testing/cypress.d.ts +0 -13
  413. package/tech/testing/cypress.d.ts.map +0 -1
  414. package/tech/testing/detect-all.d.ts +0 -13
  415. package/tech/testing/detect-all.d.ts.map +0 -1
  416. package/tech/testing/index.cjs.js.map +0 -1
  417. package/tech/testing/index.esm.js.map +0 -1
  418. package/tech/testing/jest.d.ts +0 -13
  419. package/tech/testing/jest.d.ts.map +0 -1
  420. package/tech/testing/mocha.d.ts +0 -13
  421. package/tech/testing/mocha.d.ts.map +0 -1
  422. package/tech/testing/playwright.d.ts +0 -13
  423. package/tech/testing/playwright.d.ts.map +0 -1
  424. package/tech/testing/types.d.ts +0 -35
  425. package/tech/testing/types.d.ts.map +0 -1
  426. package/tech/testing/vitest.d.ts +0 -13
  427. package/tech/testing/vitest.d.ts.map +0 -1
  428. package/tech/types/detectors.d.ts +0 -67
  429. package/tech/types/detectors.d.ts.map +0 -1
  430. package/tech/types/index.cjs.js.map +0 -1
  431. package/tech/types/index.esm.js.map +0 -1
  432. package/vfs/commit.d.ts +0 -32
  433. package/vfs/commit.d.ts.map +0 -1
  434. package/vfs/diff.d.ts +0 -73
  435. package/vfs/diff.d.ts.map +0 -1
  436. package/vfs/factory.d.ts +0 -37
  437. package/vfs/factory.d.ts.map +0 -1
  438. package/vfs/fs-tree.d.ts +0 -13
  439. package/vfs/fs-tree.d.ts.map +0 -1
  440. package/vfs/index.cjs.js.map +0 -1
  441. package/vfs/index.esm.js.map +0 -1
  442. package/vfs/types.d.ts +0 -179
  443. package/vfs/types.d.ts.map +0 -1
package/cli/index.esm.js CHANGED
@@ -1,445 +1,26 @@
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 { isSafePath } from '../_shared/core/fs/guard/index.esm.js';
16
+ import { getFileStat, isDirectory, exists } from '../_shared/core/fs/stat/index.esm.js';
17
+ import { join } from '../_shared/core/path/join/index.esm.js';
18
+ import { createConfigError } from '../_shared/core/errors/structured-errors/index.esm.js';
19
+ import { createCache } from '../_shared/core/cache/index.esm.js';
20
+ import { matchGlobPattern } from '../_shared/core/patterns/glob/index.esm.js';
21
+ import { collectAllDependencies, parseVersionString, locateConfigFile, filterScriptsByCommand } from '../_shared/tech/shared-utils/detector-helpers/index.esm.js';
22
+ import { pnpmWorkspacesDetector } from '../_shared/tech/monorepo/pnpm-workspaces/index.esm.js';
23
+ import { CONFIG_PATTERNS } from '../_shared/project/config/patterns/index.esm.js';
443
24
 
444
25
  /**
445
26
  * Global log level registry.
@@ -457,7 +38,7 @@ let globalLogLevel = null;
457
38
  *
458
39
  * @param level - The log level to set globally
459
40
  *
460
- * @example
41
+ * @example Enabling debug logging globally
461
42
  * ```typescript
462
43
  * import { setGlobalLogLevel } from '@hyperfrontend/project-scope/core'
463
44
  *
@@ -504,6 +85,13 @@ function isSensitiveKey(key) {
504
85
  *
505
86
  * @param obj - Object to sanitize
506
87
  * @returns New object with sensitive values redacted
88
+ *
89
+ * @example Sanitizing sensitive data
90
+ * ```typescript
91
+ * const config = { apiKey: 'secret123', endpoint: 'https://api.example.com' }
92
+ * const safe = sanitize(config)
93
+ * // => { apiKey: '[REDACTED]', endpoint: 'https://api.example.com' }
94
+ * ```
507
95
  */
508
96
  function sanitize(obj) {
509
97
  if (obj === null || obj === undefined) {
@@ -554,7 +142,7 @@ function formatMessage(namespace, message, meta) {
554
142
  * @param options - Logger configuration options
555
143
  * @returns A configured scoped logger instance
556
144
  *
557
- * @example
145
+ * @example Creating a scoped logger
558
146
  * ```typescript
559
147
  * const logger = createScopedLogger('project-scope')
560
148
  * logger.setLogLevel('debug')
@@ -591,7 +179,7 @@ function createScopedLogger(namespace, options = {}) {
591
179
  * Default logger instance for the project-scope library.
592
180
  * Use this for general logging within the library.
593
181
  *
594
- * @example
182
+ * @example Using the default logger
595
183
  * ```typescript
596
184
  * import { logger } from '@hyperfrontend/project-scope/core'
597
185
  *
@@ -609,6 +197,15 @@ const fsLogger = createScopedLogger('project-scope:fs');
609
197
  * @param code - The category code for this type of filesystem failure
610
198
  * @param context - Additional context including path, operation, and cause
611
199
  * @returns A configured Error object with code and context properties
200
+ *
201
+ * @example Creating a file system error
202
+ * ```typescript
203
+ * throw createFileSystemError(
204
+ * 'Cannot read file',
205
+ * 'FS_READ_ERROR',
206
+ * { path: './missing.txt', operation: 'read' }
207
+ * )
208
+ * ```
612
209
  */
613
210
  function createFileSystemError(message, code, context) {
614
211
  const error = createError(message);
@@ -626,7 +223,7 @@ function createFileSystemError(message, code, context) {
626
223
  * @returns File contents as string
627
224
  * @throws {Error} If file doesn't exist or can't be read
628
225
  *
629
- * @example
226
+ * @example Reading file contents
630
227
  * ```typescript
631
228
  * import { readFileContent } from '@hyperfrontend/project-scope'
632
229
  *
@@ -635,6 +232,9 @@ function createFileSystemError(message, code, context) {
635
232
  * ```
636
233
  */
637
234
  function readFileContent(filePath, encoding = 'utf-8') {
235
+ if (!isSafePath(filePath)) {
236
+ throw createFileSystemError(`Unsafe file path: ${filePath}`, 'FS_READ_ERROR', { path: filePath, operation: 'read' });
237
+ }
638
238
  if (!existsSync(filePath)) {
639
239
  fsLogger.debug('File not found', { path: filePath });
640
240
  throw createFileSystemError(`File not found: ${filePath}`, 'FS_NOT_FOUND', { path: filePath, operation: 'read' });
@@ -653,9 +253,17 @@ function readFileContent(filePath, encoding = 'utf-8') {
653
253
  * @param filePath - Path to file
654
254
  * @param encoding - File encoding (default: utf-8)
655
255
  * @returns File contents or null if file doesn't exist
256
+ *
257
+ * @example Reading file if it exists
258
+ * ```typescript
259
+ * const content = readFileIfExists('./optional-config.json')
260
+ * if (content) {
261
+ * // File existed, use content
262
+ * }
263
+ * ```
656
264
  */
657
265
  function readFileIfExists(filePath, encoding = 'utf-8') {
658
- if (!existsSync(filePath)) {
266
+ if (!isSafePath(filePath) || !existsSync(filePath)) {
659
267
  return null;
660
268
  }
661
269
  try {
@@ -666,56 +274,6 @@ function readFileIfExists(filePath, encoding = 'utf-8') {
666
274
  }
667
275
  }
668
276
 
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
277
  const fsDirLogger = createScopedLogger('project-scope:fs:dir');
720
278
  /**
721
279
  * List immediate contents of a directory.
@@ -724,7 +282,7 @@ const fsDirLogger = createScopedLogger('project-scope:fs:dir');
724
282
  * @returns Array of entries with metadata for each file/directory
725
283
  * @throws {Error} If directory doesn't exist or isn't a directory
726
284
  *
727
- * @example
285
+ * @example Listing directory contents
728
286
  * ```typescript
729
287
  * import { readDirectory } from '@hyperfrontend/project-scope'
730
288
  *
@@ -765,17 +323,6 @@ function readDirectory(dirPath) {
765
323
  }
766
324
  }
767
325
 
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
326
  const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
780
327
  /**
781
328
  * Generic upward directory traversal.
@@ -784,11 +331,20 @@ const fsTraversalLogger = createScopedLogger('project-scope:fs:traversal');
784
331
  * @param startPath - Starting directory
785
332
  * @param predicate - Function to test each directory
786
333
  * @returns First matching directory or null
334
+ *
335
+ * @example Finding directory containing README
336
+ * ```typescript
337
+ * // Find first directory containing a README
338
+ * const readmeDir = traverseUpward('./src/utils', (dir) =>
339
+ * existsSync(join(dir, 'README.md'))
340
+ * )
341
+ * // => '/project' or null
342
+ * ```
787
343
  */
788
344
  function traverseUpward(startPath, predicate) {
789
345
  fsTraversalLogger.debug('Starting upward traversal', { startPath });
790
346
  let currentPath = resolve(startPath);
791
- const rootPath = parse$1(currentPath).root;
347
+ const rootPath = parse(currentPath).root;
792
348
  while (currentPath !== rootPath) {
793
349
  if (predicate(currentPath)) {
794
350
  fsTraversalLogger.debug('Upward traversal found match', { startPath, foundPath: currentPath });
@@ -809,6 +365,17 @@ function traverseUpward(startPath, predicate) {
809
365
  * @param startPath - Starting directory
810
366
  * @param markers - Array of marker file names to search for
811
367
  * @returns First directory containing any marker, or null
368
+ *
369
+ * @example Finding project root by marker files
370
+ * ```typescript
371
+ * // Find project root by looking for common marker files
372
+ * const projectRoot = locateByMarkers('./src/components', [
373
+ * 'package.json',
374
+ * 'nx.json',
375
+ * 'tsconfig.base.json'
376
+ * ])
377
+ * // => '/workspace/my-project'
378
+ * ```
812
379
  */
813
380
  function locateByMarkers(startPath, markers) {
814
381
  fsTraversalLogger.debug('Locating by markers', { startPath, markers });
@@ -819,42 +386,7 @@ function locateByMarkers(startPath, markers) {
819
386
  return result;
820
387
  }
821
388
 
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
- }
389
+ createScopedLogger('project-scope:fs:write');
858
390
 
859
391
  const packageLogger = createScopedLogger('project-scope:project:package');
860
392
  /**
@@ -926,13 +458,21 @@ function validatePackageJson(data) {
926
458
  * @param projectPath - Project directory path or path to package.json
927
459
  * @returns Parsed package.json
928
460
  * @throws {Error} Error if file doesn't exist or is invalid
461
+ *
462
+ * @example Reading package.json
463
+ * ```typescript
464
+ * import { readPackageJson } from '@hyperfrontend/project-scope'
465
+ *
466
+ * const pkg = readPackageJson('/path/to/project')
467
+ * console.log(pkg.name, pkg.version)
468
+ * ```
929
469
  */
930
470
  function readPackageJson(projectPath) {
931
471
  const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
932
472
  packageLogger.debug('Reading package.json', { path: packageJsonPath });
933
473
  const content = readFileContent(packageJsonPath);
934
474
  try {
935
- const data = parse(content);
475
+ const data = parse$1(content);
936
476
  const validated = validatePackageJson(data);
937
477
  packageLogger.debug('Package.json read successfully', { path: packageJsonPath, name: validated.name });
938
478
  return validated;
@@ -954,16 +494,26 @@ function readPackageJson(projectPath) {
954
494
  *
955
495
  * @param projectPath - Project directory path or path to package.json
956
496
  * @returns Parsed package.json or null if not found
957
- */
958
- function readPackageJsonIfExists(projectPath) {
959
- const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
497
+ *
498
+ * @example Reading package.json if it exists
499
+ * ```typescript
500
+ * import { readPackageJsonIfExists } from '@hyperfrontend/project-scope'
501
+ *
502
+ * const pkg = readPackageJsonIfExists('/path/to/project')
503
+ * if (pkg) {
504
+ * console.log('Found:', pkg.name)
505
+ * }
506
+ * ```
507
+ */
508
+ function readPackageJsonIfExists(projectPath) {
509
+ const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : join$1(projectPath, 'package.json');
960
510
  const content = readFileIfExists(packageJsonPath);
961
511
  if (!content) {
962
512
  packageLogger.debug('Package.json not found', { path: packageJsonPath });
963
513
  return null;
964
514
  }
965
515
  try {
966
- const validated = validatePackageJson(parse(content));
516
+ const validated = validatePackageJson(parse$1(content));
967
517
  packageLogger.debug('Package.json loaded', { path: packageJsonPath, name: validated.name });
968
518
  return validated;
969
519
  }
@@ -978,6 +528,15 @@ function readPackageJsonIfExists(projectPath) {
978
528
  *
979
529
  * @param packageJson - Parsed package.json
980
530
  * @returns All dependencies categorized
531
+ *
532
+ * @example Extracting all dependencies
533
+ * ```typescript
534
+ * import { getDependencies } from '@hyperfrontend/project-scope'
535
+ *
536
+ * const deps = getDependencies(packageJson)
537
+ * console.log('Runtime:', Object.keys(deps.dependencies))
538
+ * console.log('Dev:', Object.keys(deps.devDependencies))
539
+ * ```
981
540
  */
982
541
  function getDependencies(packageJson) {
983
542
  return {
@@ -994,6 +553,16 @@ createScopedLogger('project-scope:heuristics:deps');
994
553
  *
995
554
  * @param projectPath - Project directory
996
555
  * @returns Dependencies grouped by runtime, dev, peer, and optional
556
+ *
557
+ * @example Getting project dependencies
558
+ * ```typescript
559
+ * import { getProjectDependencies } from '@hyperfrontend/project-scope'
560
+ *
561
+ * const deps = getProjectDependencies('/path/to/project')
562
+ * console.log('Runtime:', deps.runtime) // ['express', 'lodash']
563
+ * console.log('Dev:', deps.development) // ['jest', 'typescript']
564
+ * console.log('Total:', deps.total) // 15
565
+ * ```
997
566
  */
998
567
  function getProjectDependencies(projectPath) {
999
568
  const packageJson = readPackageJsonIfExists(projectPath);
@@ -1020,326 +589,6 @@ function getProjectDependencies(projectPath) {
1020
589
  };
1021
590
  }
1022
591
 
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
592
  const walkLogger = createScopedLogger('project-scope:project:walk');
1344
593
  /**
1345
594
  * Reads .gitignore file from the given directory and extracts
@@ -1405,6 +654,18 @@ function matchPattern(path, pattern) {
1405
654
  * @param startPath - Root directory to begin traversal
1406
655
  * @param visitor - Callback function invoked for each file system entry
1407
656
  * @param options - Configuration for traversal behavior
657
+ *
658
+ * @example Walking a directory tree
659
+ * ```typescript
660
+ * import { walkDirectory } from '@hyperfrontend/project-scope'
661
+ *
662
+ * const tsFiles: string[] = []
663
+ * walkDirectory('./src', (entry) => {
664
+ * if (entry.isFile && entry.name.endsWith('.ts')) {
665
+ * tsFiles.push(entry.relativePath)
666
+ * }
667
+ * }, { maxDepth: 5, respectGitignore: true })
668
+ * ```
1408
669
  */
1409
670
  function walkDirectory(startPath, visitor, options) {
1410
671
  walkLogger.debug('Starting directory walk', {
@@ -1501,7 +762,7 @@ function matchesPatterns(path, patterns) {
1501
762
  * @param options - Configuration for search behavior
1502
763
  * @returns List of relative file paths that match the patterns
1503
764
  *
1504
- * @example
765
+ * @example Finding files by pattern
1505
766
  * ```typescript
1506
767
  * import { findFiles } from '@hyperfrontend/project-scope'
1507
768
  *
@@ -1615,7 +876,7 @@ function discoverFromExports(exports$1, entryPoints) {
1615
876
  * @param options - Discovery options
1616
877
  * @returns Array of discovered entry points sorted by confidence
1617
878
  *
1618
- * @example
879
+ * @example Discovering project entry points
1619
880
  * ```typescript
1620
881
  * import { discoverEntryPoints } from '@hyperfrontend/project-scope'
1621
882
  *
@@ -1782,80 +1043,32 @@ function discoverEntryPoints(projectPath, options) {
1782
1043
  return result;
1783
1044
  }
1784
1045
 
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
1046
  /**
1854
1047
  * Detect Express in project.
1855
1048
  *
1856
1049
  * @param projectPath - Project directory path
1857
1050
  * @param packageJson - Optional pre-loaded package.json
1858
1051
  * @returns Detection result or null if not detected
1052
+ * @example Detecting Express framework
1053
+ * ```typescript
1054
+ * const pkg = {
1055
+ * dependencies: { express: '^4.18.2', cors: '^2.8.5' },
1056
+ * devDependencies: { '@types/express': '^4.17.17' },
1057
+ * }
1058
+ *
1059
+ * const result = expressDetector('/path/to/project', pkg)
1060
+ * // => {
1061
+ * // id: 'express',
1062
+ * // name: 'Express',
1063
+ * // version: '4.18.2',
1064
+ * // confidence: 100,
1065
+ * // detectedFrom: [
1066
+ * // { type: 'package.json', field: 'dependencies.express' },
1067
+ * // { type: 'package.json', field: 'dependencies.@types/express' },
1068
+ * // { type: 'package.json', field: 'dependencies (express middleware)' },
1069
+ * // ],
1070
+ * // }
1071
+ * ```
1859
1072
  */
1860
1073
  function expressDetector(projectPath, packageJson) {
1861
1074
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1890,84 +1103,109 @@ function expressDetector(projectPath, packageJson) {
1890
1103
  }
1891
1104
 
1892
1105
  /**
1893
- * Detect NestJS in project.
1106
+ * Detect Fastify in project.
1894
1107
  *
1895
1108
  * @param projectPath - Project directory path
1896
1109
  * @param packageJson - Optional pre-loaded package.json
1897
1110
  * @returns Detection result or null if not detected
1111
+ * @example Detecting Fastify framework
1112
+ * ```typescript
1113
+ * const pkg = {
1114
+ * dependencies: { fastify: '^4.24.0', '@fastify/cors': '^8.4.0' },
1115
+ * }
1116
+ *
1117
+ * const result = fastifyDetector('/path/to/project', pkg)
1118
+ * // => {
1119
+ * // id: 'fastify',
1120
+ * // name: 'Fastify',
1121
+ * // version: '4.24.0',
1122
+ * // confidence: 95,
1123
+ * // detectedFrom: [
1124
+ * // { type: 'package.json', field: 'dependencies.fastify' },
1125
+ * // { type: 'package.json', field: 'dependencies (fastify plugins)' },
1126
+ * // ],
1127
+ * // }
1128
+ * ```
1898
1129
  */
1899
- function nestDetector(projectPath, packageJson) {
1130
+ function fastifyDetector(projectPath, packageJson) {
1900
1131
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1901
1132
  const sources = [];
1902
1133
  let confidence = 0;
1903
1134
  let version;
1904
- let configPath;
1905
1135
  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' });
1136
+ if (deps['fastify']) {
1137
+ confidence += 80;
1138
+ version = parseVersionString(deps['fastify']);
1139
+ sources.push({ type: 'package.json', field: 'dependencies.fastify' });
1914
1140
  }
1915
- if (exists(join$1(projectPath, 'nest-cli.json'))) {
1141
+ const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1142
+ if (fastifyPlugins.length > 0) {
1916
1143
  confidence += 15;
1917
- configPath = 'nest-cli.json';
1918
- sources.push({ type: 'config-file', path: 'nest-cli.json' });
1144
+ sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1919
1145
  }
1920
- const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1921
- if (nestPackages.length > 2) {
1146
+ if (deps['@types/fastify']) {
1922
1147
  confidence += 5;
1923
- sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
1148
+ sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
1924
1149
  }
1925
1150
  if (confidence === 0) {
1926
1151
  return null;
1927
1152
  }
1928
1153
  return {
1929
- id: 'nestjs',
1930
- name: 'NestJS',
1154
+ id: 'fastify',
1155
+ name: 'Fastify',
1931
1156
  version,
1932
- configPath,
1933
1157
  confidence: min(confidence, 100),
1934
1158
  detectedFrom: sources,
1935
1159
  };
1936
1160
  }
1937
1161
 
1938
1162
  /**
1939
- * Detect Fastify in project.
1163
+ * Detect Hono in project.
1940
1164
  *
1941
1165
  * @param projectPath - Project directory path
1942
1166
  * @param packageJson - Optional pre-loaded package.json
1943
1167
  * @returns Detection result or null if not detected
1168
+ * @example Detecting Hono framework
1169
+ * ```typescript
1170
+ * const pkg = {
1171
+ * dependencies: { hono: '^3.11.0', '@hono/node-server': '^1.3.0' },
1172
+ * }
1173
+ *
1174
+ * const result = honoDetector('/path/to/project', pkg)
1175
+ * // => {
1176
+ * // id: 'hono',
1177
+ * // name: 'Hono',
1178
+ * // version: '3.11.0',
1179
+ * // confidence: 100,
1180
+ * // detectedFrom: [
1181
+ * // { type: 'package.json', field: 'dependencies.hono' },
1182
+ * // { type: 'package.json', field: 'dependencies (@hono adapters)' },
1183
+ * // ],
1184
+ * // }
1185
+ * ```
1944
1186
  */
1945
- function fastifyDetector(projectPath, packageJson) {
1187
+ function honoDetector(projectPath, packageJson) {
1946
1188
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1947
1189
  const sources = [];
1948
1190
  let confidence = 0;
1949
1191
  let version;
1950
1192
  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' });
1193
+ if (deps['hono']) {
1194
+ confidence += 85;
1195
+ version = parseVersionString(deps['hono']);
1196
+ sources.push({ type: 'package.json', field: 'dependencies.hono' });
1955
1197
  }
1956
- const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1957
- if (fastifyPlugins.length > 0) {
1198
+ const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
1199
+ if (honoAdapters.length > 0) {
1958
1200
  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' });
1201
+ sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1964
1202
  }
1965
1203
  if (confidence === 0) {
1966
1204
  return null;
1967
1205
  }
1968
1206
  return {
1969
- id: 'fastify',
1970
- name: 'Fastify',
1207
+ id: 'hono',
1208
+ name: 'Hono',
1971
1209
  version,
1972
1210
  confidence: min(confidence, 100),
1973
1211
  detectedFrom: sources,
@@ -1980,6 +1218,26 @@ function fastifyDetector(projectPath, packageJson) {
1980
1218
  * @param projectPath - Project directory path
1981
1219
  * @param packageJson - Optional pre-loaded package.json
1982
1220
  * @returns Detection result or null if not detected
1221
+ * @example Detecting Koa framework
1222
+ * ```typescript
1223
+ * const pkg = {
1224
+ * dependencies: { koa: '^2.14.2', 'koa-router': '^12.0.0' },
1225
+ * devDependencies: { '@types/koa': '^2.13.9' },
1226
+ * }
1227
+ *
1228
+ * const result = koaDetector('/path/to/project', pkg)
1229
+ * // => {
1230
+ * // id: 'koa',
1231
+ * // name: 'Koa',
1232
+ * // version: '2.14.2',
1233
+ * // confidence: 100,
1234
+ * // detectedFrom: [
1235
+ * // { type: 'package.json', field: 'dependencies.koa' },
1236
+ * // { type: 'package.json', field: 'dependencies.@types/koa' },
1237
+ * // { type: 'package.json', field: 'dependencies (koa middleware)' },
1238
+ * // ],
1239
+ * // }
1240
+ * ```
1983
1241
  */
1984
1242
  function koaDetector(projectPath, packageJson) {
1985
1243
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2014,35 +1272,72 @@ function koaDetector(projectPath, packageJson) {
2014
1272
  }
2015
1273
 
2016
1274
  /**
2017
- * Detect Hono in project.
1275
+ * Detect NestJS in project.
2018
1276
  *
2019
1277
  * @param projectPath - Project directory path
2020
1278
  * @param packageJson - Optional pre-loaded package.json
2021
1279
  * @returns Detection result or null if not detected
1280
+ * @example Detecting NestJS framework
1281
+ * ```typescript
1282
+ * // Project with nest-cli.json and NestJS packages
1283
+ * const pkg = {
1284
+ * dependencies: {
1285
+ * '@nestjs/core': '^10.2.0',
1286
+ * '@nestjs/common': '^10.2.0',
1287
+ * '@nestjs/platform-express': '^10.2.0',
1288
+ * },
1289
+ * }
1290
+ *
1291
+ * const result = nestDetector('/path/to/nest-project', pkg)
1292
+ * // => {
1293
+ * // id: 'nestjs',
1294
+ * // name: 'NestJS',
1295
+ * // version: '10.2.0',
1296
+ * // configPath: 'nest-cli.json', // if present
1297
+ * // confidence: 100,
1298
+ * // detectedFrom: [
1299
+ * // { type: 'package.json', field: 'dependencies.@nestjs/core' },
1300
+ * // { type: 'package.json', field: 'dependencies.@nestjs/common' },
1301
+ * // { type: 'config-file', path: 'nest-cli.json' },
1302
+ * // { type: 'package.json', field: 'dependencies (@nestjs packages)' },
1303
+ * // ],
1304
+ * // }
1305
+ * ```
2022
1306
  */
2023
- function honoDetector(projectPath, packageJson) {
1307
+ function nestDetector(projectPath, packageJson) {
2024
1308
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2025
1309
  const sources = [];
2026
1310
  let confidence = 0;
2027
1311
  let version;
1312
+ let configPath;
2028
1313
  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' });
2033
- }
2034
- const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
2035
- if (honoAdapters.length > 0) {
1314
+ if (deps['@nestjs/core']) {
1315
+ confidence += 70;
1316
+ version = parseVersionString(deps['@nestjs/core']);
1317
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1318
+ }
1319
+ if (deps['@nestjs/common']) {
2036
1320
  confidence += 15;
2037
- sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1321
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
1322
+ }
1323
+ if (exists(join$1(projectPath, 'nest-cli.json'))) {
1324
+ confidence += 15;
1325
+ configPath = 'nest-cli.json';
1326
+ sources.push({ type: 'config-file', path: 'nest-cli.json' });
1327
+ }
1328
+ const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1329
+ if (nestPackages.length > 2) {
1330
+ confidence += 5;
1331
+ sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
2038
1332
  }
2039
1333
  if (confidence === 0) {
2040
1334
  return null;
2041
1335
  }
2042
1336
  return {
2043
- id: 'hono',
2044
- name: 'Hono',
1337
+ id: 'nestjs',
1338
+ name: 'NestJS',
2045
1339
  version,
1340
+ configPath,
2046
1341
  confidence: min(confidence, 100),
2047
1342
  detectedFrom: sources,
2048
1343
  };
@@ -2057,99 +1352,64 @@ const backendDetectors = [
2057
1352
  { id: 'hono', name: 'Hono', detect: honoDetector },
2058
1353
  ];
2059
1354
 
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
- ];
1355
+ /** Config patterns for Babel */
1356
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
2068
1357
  /**
2069
- * Detect Webpack in project.
1358
+ * Detect Babel in project.
2070
1359
  *
2071
1360
  * @param projectPath - Project directory path
2072
1361
  * @param packageJson - Optional pre-loaded package.json
2073
1362
  * @returns Detection result or null if not detected
1363
+ *
1364
+ * @example Detecting Babel compiler
1365
+ * ```typescript
1366
+ * const result = babelDetector('/path/to/project', {
1367
+ * name: 'my-app',
1368
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
1369
+ * })
1370
+ * // => {
1371
+ * // id: 'babel',
1372
+ * // name: 'Babel',
1373
+ * // version: '7.23.0',
1374
+ * // confidence: 60,
1375
+ * // detectedFrom: [
1376
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
1377
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
1378
+ * // ]
1379
+ * // }
1380
+ * ```
2074
1381
  */
2075
- function webpackDetector(projectPath, packageJson) {
1382
+ function babelDetector(projectPath, packageJson) {
2076
1383
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2077
1384
  const sources = [];
2078
1385
  let confidence = 0;
2079
1386
  let version;
2080
1387
  const deps = collectAllDependencies(pkg);
2081
- if (deps['webpack']) {
1388
+ if (deps['@babel/core']) {
2082
1389
  confidence += 50;
2083
- version = parseVersionString(deps['webpack']);
2084
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1390
+ version = parseVersionString(deps['@babel/core']);
1391
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
2085
1392
  }
2086
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1393
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
2087
1394
  if (configPath) {
2088
1395
  confidence += 40;
2089
1396
  sources.push({ type: 'config-file', path: configPath });
2090
1397
  }
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' });
1398
+ if (pkg && 'babel' in pkg) {
1399
+ confidence += 30;
1400
+ sources.push({ type: 'package.json', field: 'babel' });
2141
1401
  }
2142
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
2143
- if (vitePlugins.length > 0) {
1402
+ const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1403
+ if (babelPackages.length > 1) {
2144
1404
  confidence += 10;
2145
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1405
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
2146
1406
  }
2147
1407
  if (confidence === 0) {
2148
1408
  return null;
2149
1409
  }
2150
1410
  return {
2151
- id: 'vite',
2152
- name: 'Vite',
1411
+ id: 'babel',
1412
+ name: 'Babel',
2153
1413
  version,
2154
1414
  configPath,
2155
1415
  confidence: min(confidence, 100),
@@ -2157,78 +1417,116 @@ function viteDetector(projectPath, packageJson) {
2157
1417
  };
2158
1418
  }
2159
1419
 
2160
- /** Config patterns for Rollup */
2161
- const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
2162
1420
  /**
2163
- * Detect Rollup in project.
1421
+ * Detect esbuild in project.
2164
1422
  *
2165
1423
  * @param projectPath - Project directory path
2166
1424
  * @param packageJson - Optional pre-loaded package.json
2167
1425
  * @returns Detection result or null if not detected
1426
+ *
1427
+ * @example Detecting esbuild bundler
1428
+ * ```typescript
1429
+ * const result = esbuildDetector('/path/to/project', {
1430
+ * name: 'my-lib',
1431
+ * devDependencies: { 'esbuild': '^0.19.0' },
1432
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
1433
+ * })
1434
+ * // => {
1435
+ * // id: 'esbuild',
1436
+ * // name: 'esbuild',
1437
+ * // version: '0.19.0',
1438
+ * // confidence: 80,
1439
+ * // detectedFrom: [
1440
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
1441
+ * // { type: 'package.json', field: 'scripts.build' }
1442
+ * // ]
1443
+ * // }
1444
+ * ```
2168
1445
  */
2169
- function rollupDetector(projectPath, packageJson) {
1446
+ function esbuildDetector(projectPath, packageJson) {
2170
1447
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2171
1448
  const sources = [];
2172
1449
  let confidence = 0;
2173
1450
  let version;
2174
1451
  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 });
1452
+ if (deps['esbuild']) {
1453
+ confidence += 70;
1454
+ version = parseVersionString(deps['esbuild']);
1455
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
2184
1456
  }
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)' });
1457
+ const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1458
+ if (esbuildPlugins.length > 0) {
1459
+ confidence += 15;
1460
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
2189
1461
  }
2190
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1462
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
2191
1463
  for (const name of scriptMatches) {
2192
- confidence = min(confidence + 5, 100);
1464
+ confidence = min(confidence + 10, 100);
2193
1465
  sources.push({ type: 'package.json', field: `scripts.${name}` });
2194
1466
  }
2195
1467
  if (confidence === 0) {
2196
1468
  return null;
2197
1469
  }
2198
1470
  return {
2199
- id: 'rollup',
2200
- name: 'Rollup',
1471
+ id: 'esbuild',
1472
+ name: 'esbuild',
2201
1473
  version,
2202
- configPath,
2203
1474
  confidence: min(confidence, 100),
2204
1475
  detectedFrom: sources,
2205
1476
  };
2206
1477
  }
2207
1478
 
1479
+ /** Config patterns for Parcel */
1480
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
2208
1481
  /**
2209
- * Detect esbuild in project.
1482
+ * Detect Parcel in project.
2210
1483
  *
2211
1484
  * @param projectPath - Project directory path
2212
1485
  * @param packageJson - Optional pre-loaded package.json
2213
1486
  * @returns Detection result or null if not detected
1487
+ *
1488
+ * @example Detecting Parcel bundler
1489
+ * ```typescript
1490
+ * const result = parcelDetector('/path/to/project', {
1491
+ * name: 'my-app',
1492
+ * devDependencies: { 'parcel': '^2.10.0' },
1493
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
1494
+ * })
1495
+ * // => {
1496
+ * // id: 'parcel',
1497
+ * // name: 'Parcel',
1498
+ * // version: '2.10.0',
1499
+ * // confidence: 80,
1500
+ * // detectedFrom: [
1501
+ * // { type: 'package.json', field: 'dependencies.parcel' },
1502
+ * // { type: 'package.json', field: 'scripts.dev' },
1503
+ * // { type: 'package.json', field: 'scripts.build' }
1504
+ * // ]
1505
+ * // }
1506
+ * ```
2214
1507
  */
2215
- function esbuildDetector(projectPath, packageJson) {
1508
+ function parcelDetector(projectPath, packageJson) {
2216
1509
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2217
1510
  const sources = [];
2218
1511
  let confidence = 0;
2219
1512
  let version;
2220
1513
  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' });
1514
+ if (deps['parcel']) {
1515
+ confidence += 60;
1516
+ version = parseVersionString(deps['parcel']);
1517
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
2225
1518
  }
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)' });
1519
+ if (deps['parcel-bundler']) {
1520
+ confidence += 60;
1521
+ version = parseVersionString(deps['parcel-bundler']);
1522
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
2230
1523
  }
2231
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1524
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1525
+ if (configPath) {
1526
+ confidence += 30;
1527
+ sources.push({ type: 'config-file', path: configPath });
1528
+ }
1529
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
2232
1530
  for (const name of scriptMatches) {
2233
1531
  confidence = min(confidence + 10, 100);
2234
1532
  sources.push({ type: 'package.json', field: `scripts.${name}` });
@@ -2237,54 +1535,78 @@ function esbuildDetector(projectPath, packageJson) {
2237
1535
  return null;
2238
1536
  }
2239
1537
  return {
2240
- id: 'esbuild',
2241
- name: 'esbuild',
1538
+ id: 'parcel',
1539
+ name: 'Parcel',
2242
1540
  version,
1541
+ configPath,
2243
1542
  confidence: min(confidence, 100),
2244
1543
  detectedFrom: sources,
2245
1544
  };
2246
1545
  }
2247
1546
 
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'];
1547
+ /** Config patterns for Rollup */
1548
+ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.config.mjs', 'rollup.config.cjs'];
2250
1549
  /**
2251
- * Detect Babel in project.
1550
+ * Detect Rollup in project.
2252
1551
  *
2253
1552
  * @param projectPath - Project directory path
2254
1553
  * @param packageJson - Optional pre-loaded package.json
2255
1554
  * @returns Detection result or null if not detected
1555
+ *
1556
+ * @example Detecting Rollup bundler
1557
+ * ```typescript
1558
+ * const result = rollupDetector('/path/to/project', {
1559
+ * name: 'my-lib',
1560
+ * devDependencies: {
1561
+ * 'rollup': '^4.0.0',
1562
+ * '@rollup/plugin-node-resolve': '^15.0.0',
1563
+ * '@rollup/plugin-commonjs': '^25.0.0'
1564
+ * }
1565
+ * })
1566
+ * // => {
1567
+ * // id: 'rollup',
1568
+ * // name: 'Rollup',
1569
+ * // version: '4.0.0',
1570
+ * // confidence: 65,
1571
+ * // detectedFrom: [
1572
+ * // { type: 'package.json', field: 'dependencies.rollup' },
1573
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
1574
+ * // ]
1575
+ * // }
1576
+ * ```
2256
1577
  */
2257
- function babelDetector(projectPath, packageJson) {
1578
+ function rollupDetector(projectPath, packageJson) {
2258
1579
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2259
1580
  const sources = [];
2260
1581
  let confidence = 0;
2261
1582
  let version;
2262
1583
  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' });
1584
+ if (deps['rollup']) {
1585
+ confidence += 55;
1586
+ version = parseVersionString(deps['rollup']);
1587
+ sources.push({ type: 'package.json', field: 'dependencies.rollup' });
2267
1588
  }
2268
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1589
+ const configPath = locateConfigFile(projectPath, ROLLUP_CONFIG_PATTERNS);
2269
1590
  if (configPath) {
2270
1591
  confidence += 40;
2271
1592
  sources.push({ type: 'config-file', path: configPath });
2272
1593
  }
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) {
1594
+ const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1595
+ if (rollupPlugins.length > 0) {
2279
1596
  confidence += 10;
2280
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1597
+ sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1598
+ }
1599
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1600
+ for (const name of scriptMatches) {
1601
+ confidence = min(confidence + 5, 100);
1602
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
2281
1603
  }
2282
1604
  if (confidence === 0) {
2283
1605
  return null;
2284
1606
  }
2285
1607
  return {
2286
- id: 'babel',
2287
- name: 'Babel',
1608
+ id: 'rollup',
1609
+ name: 'Rollup',
2288
1610
  version,
2289
1611
  configPath,
2290
1612
  confidence: min(confidence, 100),
@@ -2300,6 +1622,24 @@ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
2300
1622
  * @param projectPath - Project directory path
2301
1623
  * @param packageJson - Optional pre-loaded package.json
2302
1624
  * @returns Detection result or null if not detected
1625
+ *
1626
+ * @example Detecting SWC compiler
1627
+ * ```typescript
1628
+ * const result = swcDetector('/path/to/project', {
1629
+ * name: 'my-app',
1630
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
1631
+ * })
1632
+ * // => {
1633
+ * // id: 'swc',
1634
+ * // name: 'SWC',
1635
+ * // version: '1.3.0',
1636
+ * // confidence: 70,
1637
+ * // detectedFrom: [
1638
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
1639
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
1640
+ * // ]
1641
+ * // }
1642
+ * ```
2303
1643
  */
2304
1644
  function swcDetector(projectPath, packageJson) {
2305
1645
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2339,47 +1679,142 @@ function swcDetector(projectPath, packageJson) {
2339
1679
  };
2340
1680
  }
2341
1681
 
2342
- /** Config patterns for Parcel */
2343
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1682
+ /** Config patterns for Vite */
1683
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
2344
1684
  /**
2345
- * Detect Parcel in project.
1685
+ * Detect Vite in project.
2346
1686
  *
2347
1687
  * @param projectPath - Project directory path
2348
1688
  * @param packageJson - Optional pre-loaded package.json
2349
1689
  * @returns Detection result or null if not detected
1690
+ *
1691
+ * @example Detecting Vite build tool
1692
+ * ```typescript
1693
+ * const result = viteDetector('/path/to/project', {
1694
+ * name: 'my-app',
1695
+ * devDependencies: {
1696
+ * 'vite': '^5.0.0',
1697
+ * '@vitejs/plugin-react': '^4.0.0',
1698
+ * 'vitest': '^1.0.0'
1699
+ * }
1700
+ * })
1701
+ * // => {
1702
+ * // id: 'vite',
1703
+ * // name: 'Vite',
1704
+ * // version: '5.0.0',
1705
+ * // confidence: 80,
1706
+ * // detectedFrom: [
1707
+ * // { type: 'package.json', field: 'dependencies.vite' },
1708
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1709
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1710
+ * // ]
1711
+ * // }
1712
+ * ```
2350
1713
  */
2351
- function parcelDetector(projectPath, packageJson) {
1714
+ function viteDetector(projectPath, packageJson) {
2352
1715
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2353
1716
  const sources = [];
2354
1717
  let confidence = 0;
2355
1718
  let version;
2356
1719
  const deps = collectAllDependencies(pkg);
2357
- if (deps['parcel']) {
1720
+ if (deps['vite']) {
2358
1721
  confidence += 60;
2359
- version = parseVersionString(deps['parcel']);
2360
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1722
+ version = parseVersionString(deps['vite']);
1723
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
2361
1724
  }
2362
- if (deps['parcel-bundler']) {
2363
- confidence += 60;
2364
- version = parseVersionString(deps['parcel-bundler']);
2365
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1725
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1726
+ if (configPath) {
1727
+ confidence += 35;
1728
+ sources.push({ type: 'config-file', path: configPath });
2366
1729
  }
2367
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1730
+ if (deps['vitest']) {
1731
+ confidence += 10;
1732
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1733
+ }
1734
+ const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1735
+ if (vitePlugins.length > 0) {
1736
+ confidence += 10;
1737
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1738
+ }
1739
+ if (confidence === 0) {
1740
+ return null;
1741
+ }
1742
+ return {
1743
+ id: 'vite',
1744
+ name: 'Vite',
1745
+ version,
1746
+ configPath,
1747
+ confidence: min(confidence, 100),
1748
+ detectedFrom: sources,
1749
+ };
1750
+ }
1751
+
1752
+ /** Config patterns for Webpack */
1753
+ const WEBPACK_CONFIG_PATTERNS = [
1754
+ 'webpack.config.js',
1755
+ 'webpack.config.ts',
1756
+ 'webpack.config.cjs',
1757
+ 'webpack.config.mjs',
1758
+ 'webpack.config.babel.js',
1759
+ ];
1760
+ /**
1761
+ * Detect Webpack in project.
1762
+ *
1763
+ * @param projectPath - Project directory path
1764
+ * @param packageJson - Optional pre-loaded package.json
1765
+ * @returns Detection result or null if not detected
1766
+ *
1767
+ * @example Detecting Webpack bundler
1768
+ * ```typescript
1769
+ * const result = webpackDetector('/path/to/project', {
1770
+ * name: 'my-app',
1771
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1772
+ * scripts: { 'build': 'webpack --mode production' }
1773
+ * })
1774
+ * // => {
1775
+ * // id: 'webpack',
1776
+ * // name: 'Webpack',
1777
+ * // version: '5.89.0',
1778
+ * // confidence: 65,
1779
+ * // detectedFrom: [
1780
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1781
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1782
+ * // { type: 'package.json', field: 'scripts.build' }
1783
+ * // ]
1784
+ * // }
1785
+ * ```
1786
+ */
1787
+ function webpackDetector(projectPath, packageJson) {
1788
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1789
+ const sources = [];
1790
+ let confidence = 0;
1791
+ let version;
1792
+ const deps = collectAllDependencies(pkg);
1793
+ if (deps['webpack']) {
1794
+ confidence += 50;
1795
+ version = parseVersionString(deps['webpack']);
1796
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1797
+ }
1798
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
2368
1799
  if (configPath) {
2369
- confidence += 30;
1800
+ confidence += 40;
2370
1801
  sources.push({ type: 'config-file', path: configPath });
2371
1802
  }
2372
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1803
+ if (deps['webpack-cli']) {
1804
+ confidence += 10;
1805
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1806
+ }
1807
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
2373
1808
  for (const name of scriptMatches) {
2374
- confidence = min(confidence + 10, 100);
1809
+ confidence = min(confidence + 5, 100);
2375
1810
  sources.push({ type: 'package.json', field: `scripts.${name}` });
2376
1811
  }
2377
1812
  if (confidence === 0) {
2378
1813
  return null;
2379
1814
  }
2380
1815
  return {
2381
- id: 'parcel',
2382
- name: 'Parcel',
1816
+ id: 'webpack',
1817
+ name: 'Webpack',
2383
1818
  version,
2384
1819
  configPath,
2385
1820
  confidence: min(confidence, 100),
@@ -2399,81 +1834,187 @@ const buildToolDetectors = [
2399
1834
  ];
2400
1835
 
2401
1836
  /**
2402
- * Detect React in project.
1837
+ * Detect Angular in project.
2403
1838
  *
2404
1839
  * @param projectPath - Project directory path
2405
1840
  * @param packageJson - Optional pre-loaded package.json
2406
1841
  * @returns Detection result or null if not detected
1842
+ *
1843
+ * @example Detecting Angular framework
1844
+ * ```typescript
1845
+ * const result = angularDetector('/path/to/angular-app', {
1846
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1847
+ * })
1848
+ * // => {
1849
+ * // id: 'angular',
1850
+ * // name: 'Angular',
1851
+ * // category: 'frontend',
1852
+ * // version: '17.0.0',
1853
+ * // confidence: 85,
1854
+ * // detectedFrom: [
1855
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1856
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1857
+ * // ]
1858
+ * // }
1859
+ * ```
2407
1860
  */
2408
- function reactDetector(projectPath, packageJson) {
1861
+ function angularDetector(projectPath, packageJson) {
2409
1862
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2410
1863
  const sources = [];
2411
1864
  let confidence = 0;
2412
1865
  let version;
2413
- const metaFrameworks = [];
2414
1866
  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' });
1867
+ if (deps['@angular/core']) {
1868
+ confidence += 70;
1869
+ version = parseVersionString(deps['@angular/core']);
1870
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
2419
1871
  }
2420
- if (deps['react-dom']) {
2421
- confidence += 20;
2422
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1872
+ if (deps['@angular/cli']) {
1873
+ confidence += 15;
1874
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
2423
1875
  }
2424
- if (deps['react-native']) {
2425
- confidence += 20;
2426
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1876
+ if (exists(join$1(projectPath, 'angular.json'))) {
1877
+ confidence += 15;
1878
+ sources.push({ type: 'config-file', path: 'angular.json' });
2427
1879
  }
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' });
1880
+ if (deps['angular'] && !deps['@angular/core']) {
1881
+ return {
1882
+ id: 'angularjs',
1883
+ name: 'AngularJS (Legacy)',
1884
+ category: 'frontend',
1885
+ version: parseVersionString(deps['angular']),
1886
+ confidence: 80,
1887
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1888
+ };
2435
1889
  }
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
- });
1890
+ if (confidence === 0) {
1891
+ return null;
1892
+ }
1893
+ return {
1894
+ id: 'angular',
1895
+ name: 'Angular',
1896
+ category: 'frontend',
1897
+ version,
1898
+ confidence: min(confidence, 100),
1899
+ detectedFrom: sources,
1900
+ };
1901
+ }
1902
+
1903
+ /**
1904
+ * Detect Astro in project.
1905
+ *
1906
+ * @param projectPath - Project directory path
1907
+ * @param packageJson - Optional pre-loaded package.json
1908
+ * @returns Detection result or null if not detected
1909
+ *
1910
+ * @example Detecting Astro framework
1911
+ * ```typescript
1912
+ * const result = astroDetector('/path/to/astro-project', {
1913
+ * dependencies: { 'astro': '^4.0.0' }
1914
+ * })
1915
+ * // => {
1916
+ * // id: 'astro',
1917
+ * // name: 'Astro',
1918
+ * // category: 'meta-framework',
1919
+ * // version: '4.0.0',
1920
+ * // confidence: 70,
1921
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1922
+ * // }
1923
+ * ```
1924
+ */
1925
+ function astroDetector(projectPath, packageJson) {
1926
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1927
+ const sources = [];
1928
+ let confidence = 0;
1929
+ let version;
1930
+ const deps = collectAllDependencies(pkg);
1931
+ if (deps['astro']) {
1932
+ confidence += 70;
1933
+ version = parseVersionString(deps['astro']);
1934
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1935
+ }
1936
+ if (exists(join$1(projectPath, 'astro.config.mjs')) ||
1937
+ exists(join$1(projectPath, 'astro.config.ts')) ||
1938
+ exists(join$1(projectPath, 'astro.config.js'))) {
1939
+ confidence += 25;
1940
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
1941
+ }
1942
+ if (exists(join$1(projectPath, 'src', 'pages'))) {
1943
+ confidence += 5;
1944
+ sources.push({ type: 'directory', path: 'src/pages/' });
1945
+ }
1946
+ if (confidence === 0) {
1947
+ return null;
2445
1948
  }
1949
+ return {
1950
+ id: 'astro',
1951
+ name: 'Astro',
1952
+ category: 'meta-framework',
1953
+ version,
1954
+ confidence: min(confidence, 100),
1955
+ detectedFrom: sources,
1956
+ };
1957
+ }
1958
+
1959
+ /**
1960
+ * Detect Gatsby in project.
1961
+ *
1962
+ * @param projectPath - Project directory path
1963
+ * @param packageJson - Optional pre-loaded package.json
1964
+ * @returns Detection result or null if not detected
1965
+ *
1966
+ * @example Detecting Gatsby framework
1967
+ * ```typescript
1968
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1969
+ * dependencies: {
1970
+ * 'gatsby': '^5.0.0',
1971
+ * 'gatsby-plugin-image': '^3.0.0',
1972
+ * 'gatsby-source-filesystem': '^5.0.0'
1973
+ * }
1974
+ * })
1975
+ * // => {
1976
+ * // id: 'gatsby',
1977
+ * // name: 'Gatsby',
1978
+ * // category: 'meta-framework',
1979
+ * // version: '5.0.0',
1980
+ * // confidence: 75,
1981
+ * // detectedFrom: [
1982
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1983
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1984
+ * // ]
1985
+ * // }
1986
+ * ```
1987
+ */
1988
+ function gatsbyDetector(projectPath, packageJson) {
1989
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1990
+ const sources = [];
1991
+ let confidence = 0;
1992
+ let version;
1993
+ const deps = collectAllDependencies(pkg);
2446
1994
  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
- });
1995
+ confidence += 70;
1996
+ version = parseVersionString(deps['gatsby']);
1997
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
2455
1998
  }
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
- });
1999
+ if (exists(join$1(projectPath, 'gatsby-config.js')) || exists(join$1(projectPath, 'gatsby-config.ts'))) {
2000
+ confidence += 25;
2001
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
2002
+ }
2003
+ const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
2004
+ if (gatsbyPlugins.length > 0) {
2005
+ confidence += 5;
2006
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
2465
2007
  }
2466
2008
  if (confidence === 0) {
2467
2009
  return null;
2468
2010
  }
2469
2011
  return {
2470
- id: 'react',
2471
- name: 'React',
2472
- category: 'frontend',
2012
+ id: 'gatsby',
2013
+ name: 'Gatsby',
2014
+ category: 'meta-framework',
2473
2015
  version,
2474
2016
  confidence: min(confidence, 100),
2475
2017
  detectedFrom: sources,
2476
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2477
2018
  };
2478
2019
  }
2479
2020
 
@@ -2483,6 +2024,21 @@ function reactDetector(projectPath, packageJson) {
2483
2024
  * @param projectPath - Project directory path
2484
2025
  * @param packageJson - Optional pre-loaded package.json
2485
2026
  * @returns Detection result or null if not detected
2027
+ *
2028
+ * @example Detecting Next.js framework
2029
+ * ```typescript
2030
+ * const result = nextjsDetector('/path/to/nextjs-app', {
2031
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
2032
+ * })
2033
+ * // => {
2034
+ * // id: 'nextjs',
2035
+ * // name: 'Next.js',
2036
+ * // category: 'meta-framework',
2037
+ * // version: '14.0.0',
2038
+ * // confidence: 70,
2039
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
2040
+ * // }
2041
+ * ```
2486
2042
  */
2487
2043
  function nextjsDetector(projectPath, packageJson) {
2488
2044
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2522,37 +2078,52 @@ function nextjsDetector(projectPath, packageJson) {
2522
2078
  }
2523
2079
 
2524
2080
  /**
2525
- * Detect Remix in project.
2081
+ * Detect Nuxt in project.
2526
2082
  *
2527
2083
  * @param projectPath - Project directory path
2528
2084
  * @param packageJson - Optional pre-loaded package.json
2529
2085
  * @returns Detection result or null if not detected
2086
+ *
2087
+ * @example Detecting Nuxt framework
2088
+ * ```typescript
2089
+ * const result = nuxtDetector('/path/to/nuxt-app', {
2090
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
2091
+ * })
2092
+ * // => {
2093
+ * // id: 'nuxt',
2094
+ * // name: 'Nuxt',
2095
+ * // category: 'meta-framework',
2096
+ * // version: '3.0.0',
2097
+ * // confidence: 70,
2098
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
2099
+ * // }
2100
+ * ```
2530
2101
  */
2531
- function remixDetector(projectPath, packageJson) {
2102
+ function nuxtDetector(projectPath, packageJson) {
2532
2103
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2533
2104
  const sources = [];
2534
2105
  let confidence = 0;
2535
2106
  let version;
2536
2107
  const deps = collectAllDependencies(pkg);
2537
- if (deps['@remix-run/react']) {
2108
+ if (deps['nuxt'] || deps['nuxt3']) {
2538
2109
  confidence += 70;
2539
- version = parseVersionString(deps['@remix-run/react']);
2540
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
2110
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
2111
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
2541
2112
  }
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/*' });
2113
+ if (exists(join$1(projectPath, 'nuxt.config.js')) || exists(join$1(projectPath, 'nuxt.config.ts'))) {
2114
+ confidence += 25;
2115
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
2545
2116
  }
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.*' });
2117
+ if (exists(join$1(projectPath, 'pages'))) {
2118
+ confidence += 5;
2119
+ sources.push({ type: 'directory', path: 'pages/' });
2549
2120
  }
2550
2121
  if (confidence === 0) {
2551
2122
  return null;
2552
2123
  }
2553
2124
  return {
2554
- id: 'remix',
2555
- name: 'Remix',
2125
+ id: 'nuxt',
2126
+ name: 'Nuxt',
2556
2127
  category: 'meta-framework',
2557
2128
  version,
2558
2129
  confidence: min(confidence, 100),
@@ -2561,39 +2132,59 @@ function remixDetector(projectPath, packageJson) {
2561
2132
  }
2562
2133
 
2563
2134
  /**
2564
- * Detect Gatsby in project.
2135
+ * Detect Qwik in project.
2565
2136
  *
2566
2137
  * @param projectPath - Project directory path
2567
2138
  * @param packageJson - Optional pre-loaded package.json
2568
2139
  * @returns Detection result or null if not detected
2140
+ *
2141
+ * @example Detecting Qwik framework
2142
+ * ```typescript
2143
+ * const result = qwikDetector('/path/to/qwik-app', {
2144
+ * dependencies: {
2145
+ * '@builder.io/qwik': '^1.0.0',
2146
+ * '@builder.io/qwik-city': '^1.0.0'
2147
+ * }
2148
+ * })
2149
+ * // => {
2150
+ * // id: 'qwik',
2151
+ * // name: 'Qwik',
2152
+ * // category: 'frontend',
2153
+ * // version: '1.0.0',
2154
+ * // confidence: 90,
2155
+ * // detectedFrom: [
2156
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
2157
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
2158
+ * // ]
2159
+ * // }
2160
+ * ```
2569
2161
  */
2570
- function gatsbyDetector(projectPath, packageJson) {
2162
+ function qwikDetector(projectPath, packageJson) {
2571
2163
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2572
2164
  const sources = [];
2573
2165
  let confidence = 0;
2574
2166
  let version;
2575
2167
  const deps = collectAllDependencies(pkg);
2576
- if (deps['gatsby']) {
2168
+ if (deps['@builder.io/qwik']) {
2577
2169
  confidence += 70;
2578
- version = parseVersionString(deps['gatsby']);
2579
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
2170
+ version = parseVersionString(deps['@builder.io/qwik']);
2171
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2580
2172
  }
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.*' });
2173
+ if (deps['@builder.io/qwik-city']) {
2174
+ confidence += 20;
2175
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
2584
2176
  }
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)' });
2177
+ if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
2178
+ confidence += 10;
2179
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
2589
2180
  }
2590
2181
  if (confidence === 0) {
2591
2182
  return null;
2592
2183
  }
2593
2184
  return {
2594
- id: 'gatsby',
2595
- name: 'Gatsby',
2596
- category: 'meta-framework',
2185
+ id: 'qwik',
2186
+ name: 'Qwik',
2187
+ category: 'frontend',
2597
2188
  version,
2598
2189
  confidence: min(confidence, 100),
2599
2190
  detectedFrom: sources,
@@ -2601,53 +2192,94 @@ function gatsbyDetector(projectPath, packageJson) {
2601
2192
  }
2602
2193
 
2603
2194
  /**
2604
- * Detect Vue in project.
2195
+ * Detect React in project.
2605
2196
  *
2606
2197
  * @param projectPath - Project directory path
2607
2198
  * @param packageJson - Optional pre-loaded package.json
2608
2199
  * @returns Detection result or null if not detected
2200
+ *
2201
+ * @example Detecting React library
2202
+ * ```typescript
2203
+ * const result = reactDetector('/path/to/react-app', {
2204
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
2205
+ * })
2206
+ * // => {
2207
+ * // id: 'react',
2208
+ * // name: 'React',
2209
+ * // category: 'frontend',
2210
+ * // version: '18.0.0',
2211
+ * // confidence: 80,
2212
+ * // detectedFrom: [
2213
+ * // { type: 'package.json', field: 'dependencies.react' },
2214
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
2215
+ * // ]
2216
+ * // }
2217
+ * ```
2609
2218
  */
2610
- function vueDetector(projectPath, packageJson) {
2219
+ function reactDetector(projectPath, packageJson) {
2611
2220
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2612
2221
  const sources = [];
2613
2222
  let confidence = 0;
2614
2223
  let version;
2615
2224
  const metaFrameworks = [];
2616
2225
  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' });
2226
+ if (deps['react']) {
2227
+ confidence += 60;
2228
+ version = parseVersionString(deps['react']);
2229
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
2621
2230
  }
2622
- if (deps['@vue/cli-service']) {
2623
- confidence += 15;
2624
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2231
+ if (deps['react-dom']) {
2232
+ confidence += 20;
2233
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
2625
2234
  }
2626
- const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
2627
- if (hasVueFiles) {
2235
+ if (deps['react-native']) {
2236
+ confidence += 20;
2237
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
2238
+ }
2239
+ const hasJsxFiles = exists(join$1(projectPath, 'src', 'App.tsx')) ||
2240
+ exists(join$1(projectPath, 'src', 'App.jsx')) ||
2241
+ exists(join$1(projectPath, 'src', 'index.tsx')) ||
2242
+ exists(join$1(projectPath, 'src', 'index.jsx'));
2243
+ if (hasJsxFiles) {
2628
2244
  confidence += 10;
2629
- sources.push({ type: 'directory', path: 'src/*.vue' });
2245
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
2630
2246
  }
2631
- if (exists(join$1(projectPath, 'vue.config.js'))) {
2632
- confidence += 5;
2633
- sources.push({ type: 'config-file', path: 'vue.config.js' });
2247
+ if (deps['next']) {
2248
+ metaFrameworks.push({
2249
+ id: 'nextjs',
2250
+ name: 'Next.js',
2251
+ category: 'meta-framework',
2252
+ version: parseVersionString(deps['next']),
2253
+ confidence: 90,
2254
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
2255
+ });
2634
2256
  }
2635
- if (deps['nuxt'] || deps['nuxt3']) {
2257
+ if (deps['gatsby']) {
2636
2258
  metaFrameworks.push({
2637
- id: 'nuxt',
2638
- name: 'Nuxt',
2259
+ id: 'gatsby',
2260
+ name: 'Gatsby',
2639
2261
  category: 'meta-framework',
2640
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
2262
+ version: parseVersionString(deps['gatsby']),
2641
2263
  confidence: 90,
2642
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
2264
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
2265
+ });
2266
+ }
2267
+ if (deps['@remix-run/react'] || deps['remix']) {
2268
+ metaFrameworks.push({
2269
+ id: 'remix',
2270
+ name: 'Remix',
2271
+ category: 'meta-framework',
2272
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
2273
+ confidence: 90,
2274
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
2643
2275
  });
2644
2276
  }
2645
2277
  if (confidence === 0) {
2646
2278
  return null;
2647
2279
  }
2648
2280
  return {
2649
- id: 'vue',
2650
- name: 'Vue',
2281
+ id: 'react',
2282
+ name: 'React',
2651
2283
  category: 'frontend',
2652
2284
  version,
2653
2285
  confidence: min(confidence, 100),
@@ -2657,37 +2289,58 @@ function vueDetector(projectPath, packageJson) {
2657
2289
  }
2658
2290
 
2659
2291
  /**
2660
- * Detect Nuxt in project.
2292
+ * Detect Remix in project.
2661
2293
  *
2662
2294
  * @param projectPath - Project directory path
2663
2295
  * @param packageJson - Optional pre-loaded package.json
2664
2296
  * @returns Detection result or null if not detected
2297
+ *
2298
+ * @example Detecting Remix framework
2299
+ * ```typescript
2300
+ * const result = remixDetector('/path/to/remix-app', {
2301
+ * dependencies: {
2302
+ * '@remix-run/react': '^2.0.0',
2303
+ * '@remix-run/node': '^2.0.0'
2304
+ * }
2305
+ * })
2306
+ * // => {
2307
+ * // id: 'remix',
2308
+ * // name: 'Remix',
2309
+ * // category: 'meta-framework',
2310
+ * // version: '2.0.0',
2311
+ * // confidence: 90,
2312
+ * // detectedFrom: [
2313
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
2314
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
2315
+ * // ]
2316
+ * // }
2317
+ * ```
2665
2318
  */
2666
- function nuxtDetector(projectPath, packageJson) {
2319
+ function remixDetector(projectPath, packageJson) {
2667
2320
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2668
2321
  const sources = [];
2669
2322
  let confidence = 0;
2670
2323
  let version;
2671
2324
  const deps = collectAllDependencies(pkg);
2672
- if (deps['nuxt'] || deps['nuxt3']) {
2325
+ if (deps['@remix-run/react']) {
2673
2326
  confidence += 70;
2674
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
2675
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
2327
+ version = parseVersionString(deps['@remix-run/react']);
2328
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
2676
2329
  }
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.*' });
2330
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
2331
+ confidence += 20;
2332
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
2680
2333
  }
2681
- if (exists(join$1(projectPath, 'pages'))) {
2682
- confidence += 5;
2683
- sources.push({ type: 'directory', path: 'pages/' });
2334
+ if (exists(join$1(projectPath, 'remix.config.js')) || exists(join$1(projectPath, 'remix.config.ts'))) {
2335
+ confidence += 10;
2336
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
2684
2337
  }
2685
2338
  if (confidence === 0) {
2686
2339
  return null;
2687
2340
  }
2688
2341
  return {
2689
- id: 'nuxt',
2690
- name: 'Nuxt',
2342
+ id: 'remix',
2343
+ name: 'Remix',
2691
2344
  category: 'meta-framework',
2692
2345
  version,
2693
2346
  confidence: min(confidence, 100),
@@ -2696,47 +2349,55 @@ function nuxtDetector(projectPath, packageJson) {
2696
2349
  }
2697
2350
 
2698
2351
  /**
2699
- * Detect Angular in project.
2352
+ * Detect Solid in project.
2700
2353
  *
2701
2354
  * @param projectPath - Project directory path
2702
2355
  * @param packageJson - Optional pre-loaded package.json
2703
2356
  * @returns Detection result or null if not detected
2357
+ *
2358
+ * @example Detecting Solid.js framework
2359
+ * ```typescript
2360
+ * const result = solidDetector('/path/to/solid-app', {
2361
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
2362
+ * })
2363
+ * // => {
2364
+ * // id: 'solid',
2365
+ * // name: 'Solid',
2366
+ * // category: 'frontend',
2367
+ * // version: '1.8.0',
2368
+ * // confidence: 90,
2369
+ * // detectedFrom: [
2370
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
2371
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
2372
+ * // ]
2373
+ * // }
2374
+ * ```
2704
2375
  */
2705
- function angularDetector(projectPath, packageJson) {
2376
+ function solidDetector(projectPath, packageJson) {
2706
2377
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2707
2378
  const sources = [];
2708
2379
  let confidence = 0;
2709
2380
  let version;
2710
2381
  const deps = collectAllDependencies(pkg);
2711
- if (deps['@angular/core']) {
2382
+ if (deps['solid-js']) {
2712
2383
  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' });
2384
+ version = parseVersionString(deps['solid-js']);
2385
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
2719
2386
  }
2720
- if (exists(join$1(projectPath, 'angular.json'))) {
2721
- confidence += 15;
2722
- sources.push({ type: 'config-file', path: 'angular.json' });
2387
+ if (deps['vite-plugin-solid']) {
2388
+ confidence += 20;
2389
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
2723
2390
  }
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
- };
2391
+ if (deps['solid-start'] || deps['@solidjs/start']) {
2392
+ confidence += 10;
2393
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
2733
2394
  }
2734
2395
  if (confidence === 0) {
2735
2396
  return null;
2736
2397
  }
2737
2398
  return {
2738
- id: 'angular',
2739
- name: 'Angular',
2399
+ id: 'solid',
2400
+ name: 'Solid',
2740
2401
  category: 'frontend',
2741
2402
  version,
2742
2403
  confidence: min(confidence, 100),
@@ -2750,6 +2411,21 @@ function angularDetector(projectPath, packageJson) {
2750
2411
  * @param projectPath - Project directory path
2751
2412
  * @param packageJson - Optional pre-loaded package.json
2752
2413
  * @returns Detection result or null if not detected
2414
+ *
2415
+ * @example Detecting Svelte framework
2416
+ * ```typescript
2417
+ * const result = svelteDetector('/path/to/svelte-app', {
2418
+ * devDependencies: { 'svelte': '^4.0.0' }
2419
+ * })
2420
+ * // => {
2421
+ * // id: 'svelte',
2422
+ * // name: 'Svelte',
2423
+ * // category: 'frontend',
2424
+ * // version: '4.0.0',
2425
+ * // confidence: 70,
2426
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
2427
+ * // }
2428
+ * ```
2753
2429
  */
2754
2430
  function svelteDetector(projectPath, packageJson) {
2755
2431
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2802,6 +2478,21 @@ function svelteDetector(projectPath, packageJson) {
2802
2478
  * @param projectPath - Project directory path
2803
2479
  * @param packageJson - Optional pre-loaded package.json
2804
2480
  * @returns Detection result or null if not detected
2481
+ *
2482
+ * @example Detecting SvelteKit framework
2483
+ * ```typescript
2484
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
2485
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
2486
+ * })
2487
+ * // => {
2488
+ * // id: 'sveltekit',
2489
+ * // name: 'SvelteKit',
2490
+ * // category: 'meta-framework',
2491
+ * // version: '2.0.0',
2492
+ * // confidence: 70,
2493
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
2494
+ * // }
2495
+ * ```
2805
2496
  */
2806
2497
  function sveltekitDetector(projectPath, packageJson) {
2807
2498
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2836,121 +2527,76 @@ function sveltekitDetector(projectPath, packageJson) {
2836
2527
  }
2837
2528
 
2838
2529
  /**
2839
- * Detect Solid in project.
2530
+ * Detect Vue in project.
2840
2531
  *
2841
2532
  * @param projectPath - Project directory path
2842
2533
  * @param packageJson - Optional pre-loaded package.json
2843
2534
  * @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
2535
  *
2880
- * @param projectPath - Project directory path
2881
- * @param packageJson - Optional pre-loaded package.json
2882
- * @returns Detection result or null if not detected
2536
+ * @example Detecting Vue.js framework
2537
+ * ```typescript
2538
+ * const result = vueDetector('/path/to/vue-app', {
2539
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
2540
+ * })
2541
+ * // => {
2542
+ * // id: 'vue',
2543
+ * // name: 'Vue',
2544
+ * // category: 'frontend',
2545
+ * // version: '3.0.0',
2546
+ * // confidence: 85,
2547
+ * // detectedFrom: [
2548
+ * // { type: 'package.json', field: 'dependencies.vue' },
2549
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
2550
+ * // ]
2551
+ * // }
2552
+ * ```
2883
2553
  */
2884
- function qwikDetector(projectPath, packageJson) {
2554
+ function vueDetector(projectPath, packageJson) {
2885
2555
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2886
2556
  const sources = [];
2887
2557
  let confidence = 0;
2888
2558
  let version;
2559
+ const metaFrameworks = [];
2889
2560
  const deps = collectAllDependencies(pkg);
2890
- if (deps['@builder.io/qwik']) {
2561
+ if (deps['vue']) {
2891
2562
  confidence += 70;
2892
- version = parseVersionString(deps['@builder.io/qwik']);
2893
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
2563
+ version = parseVersionString(deps['vue']);
2564
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2894
2565
  }
2895
- if (deps['@builder.io/qwik-city']) {
2896
- confidence += 20;
2897
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
2566
+ if (deps['@vue/cli-service']) {
2567
+ confidence += 15;
2568
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2898
2569
  }
2899
- if (exists(join$1(projectPath, 'qwik.config.ts')) || exists(join$1(projectPath, 'qwik.config.js'))) {
2570
+ const hasVueFiles = exists(join$1(projectPath, 'src', 'App.vue')) || exists(join$1(projectPath, 'src', 'main.vue'));
2571
+ if (hasVueFiles) {
2900
2572
  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.*' });
2573
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2939
2574
  }
2940
- if (exists(join$1(projectPath, 'src', 'pages'))) {
2575
+ if (exists(join$1(projectPath, 'vue.config.js'))) {
2941
2576
  confidence += 5;
2942
- sources.push({ type: 'directory', path: 'src/pages/' });
2577
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
2578
+ }
2579
+ if (deps['nuxt'] || deps['nuxt3']) {
2580
+ metaFrameworks.push({
2581
+ id: 'nuxt',
2582
+ name: 'Nuxt',
2583
+ category: 'meta-framework',
2584
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
2585
+ confidence: 90,
2586
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
2587
+ });
2943
2588
  }
2944
2589
  if (confidence === 0) {
2945
2590
  return null;
2946
2591
  }
2947
2592
  return {
2948
- id: 'astro',
2949
- name: 'Astro',
2950
- category: 'meta-framework',
2593
+ id: 'vue',
2594
+ name: 'Vue',
2595
+ category: 'frontend',
2951
2596
  version,
2952
2597
  confidence: min(confidence, 100),
2953
2598
  detectedFrom: sources,
2599
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2954
2600
  };
2955
2601
  }
2956
2602
 
@@ -2977,6 +2623,14 @@ const frameworkDetectors = [
2977
2623
  * @param projectPath - Project directory path
2978
2624
  * @param packageJson - Optional pre-loaded package.json
2979
2625
  * @returns Detection result or null if not detected
2626
+ *
2627
+ * @example Detecting AngularJS framework
2628
+ * ```typescript
2629
+ * const result = angularJSDetector('/path/to/project', {
2630
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
2631
+ * })
2632
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
2633
+ * ```
2980
2634
  */
2981
2635
  function angularJSDetector(projectPath, packageJson) {
2982
2636
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3020,6 +2674,14 @@ function angularJSDetector(projectPath, packageJson) {
3020
2674
  * @param projectPath - Project directory path
3021
2675
  * @param packageJson - Optional pre-loaded package.json
3022
2676
  * @returns Detection result or null if not detected
2677
+ *
2678
+ * @example Detecting Backbone.js framework
2679
+ * ```typescript
2680
+ * const result = backboneDetector('/path/to/project', {
2681
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2682
+ * })
2683
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2684
+ * ```
3023
2685
  */
3024
2686
  function backboneDetector(projectPath, packageJson) {
3025
2687
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3063,6 +2725,15 @@ function backboneDetector(projectPath, packageJson) {
3063
2725
  * @param projectPath - Project directory path
3064
2726
  * @param packageJson - Optional pre-loaded package.json
3065
2727
  * @returns Detection result or null if not detected
2728
+ *
2729
+ * @example Detecting Ember.js framework
2730
+ * ```typescript
2731
+ * const result = emberDetector('/path/to/project', {
2732
+ * dependencies: { 'ember-source': '^4.0.0' },
2733
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2734
+ * })
2735
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2736
+ * ```
3066
2737
  */
3067
2738
  function emberDetector(projectPath, packageJson) {
3068
2739
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3102,6 +2773,14 @@ function emberDetector(projectPath, packageJson) {
3102
2773
  * @param projectPath - Project directory path
3103
2774
  * @param packageJson - Optional pre-loaded package.json
3104
2775
  * @returns Detection result or null if not detected
2776
+ *
2777
+ * @example Detecting jQuery library
2778
+ * ```typescript
2779
+ * const result = jqueryDetector('/path/to/project', {
2780
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2781
+ * })
2782
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2783
+ * ```
3105
2784
  */
3106
2785
  function jqueryDetector(projectPath, packageJson) {
3107
2786
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3143,6 +2822,56 @@ const legacyDetectors = [
3143
2822
  { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
3144
2823
  ];
3145
2824
 
2825
+ /**
2826
+ * Detect Biome in project.
2827
+ *
2828
+ * @param projectPath - Project directory path
2829
+ * @param packageJson - Optional pre-loaded package.json
2830
+ * @returns Detection result or null if not detected
2831
+ *
2832
+ * @example Detecting Biome linter
2833
+ * ```typescript
2834
+ * const result = biomeDetector('/path/to/project', {
2835
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2836
+ * })
2837
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2838
+ * ```
2839
+ */
2840
+ function biomeDetector(projectPath, packageJson) {
2841
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2842
+ const sources = [];
2843
+ let confidence = 0;
2844
+ let configPath;
2845
+ let version;
2846
+ const deps = collectAllDependencies(pkg);
2847
+ if (deps['@biomejs/biome']) {
2848
+ confidence += 70;
2849
+ version = parseVersionString(deps['@biomejs/biome']);
2850
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2851
+ }
2852
+ if (exists(join$1(projectPath, 'biome.json'))) {
2853
+ confidence += 30;
2854
+ configPath = 'biome.json';
2855
+ sources.push({ type: 'config-file', path: 'biome.json' });
2856
+ }
2857
+ if (!configPath && exists(join$1(projectPath, 'biome.jsonc'))) {
2858
+ confidence += 30;
2859
+ configPath = 'biome.jsonc';
2860
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2861
+ }
2862
+ if (confidence === 0) {
2863
+ return null;
2864
+ }
2865
+ return {
2866
+ id: 'biome',
2867
+ name: 'Biome',
2868
+ version,
2869
+ configPath,
2870
+ confidence: min(confidence, 100),
2871
+ detectedFrom: sources,
2872
+ };
2873
+ }
2874
+
3146
2875
  /** Config patterns for ESLint */
3147
2876
  const ESLINT_CONFIG_PATTERNS = [
3148
2877
  'eslint.config.js',
@@ -3162,6 +2891,15 @@ const ESLINT_CONFIG_PATTERNS = [
3162
2891
  * @param projectPath - Project directory path
3163
2892
  * @param packageJson - Optional pre-loaded package.json
3164
2893
  * @returns Detection result or null if not detected
2894
+ *
2895
+ * @example Detecting ESLint linter
2896
+ * ```typescript
2897
+ * const result = eslintDetector('/path/to/project', {
2898
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2899
+ * scripts: { lint: 'eslint src/' },
2900
+ * })
2901
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2902
+ * ```
3165
2903
  */
3166
2904
  function eslintDetector(projectPath, packageJson) {
3167
2905
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3225,6 +2963,15 @@ const PRETTIER_CONFIG_PATTERNS = [
3225
2963
  * @param projectPath - Project directory path
3226
2964
  * @param packageJson - Optional pre-loaded package.json
3227
2965
  * @returns Detection result or null if not detected
2966
+ *
2967
+ * @example Detecting Prettier formatter
2968
+ * ```typescript
2969
+ * const result = prettierDetector('/path/to/project', {
2970
+ * devDependencies: { prettier: '^3.0.0' },
2971
+ * scripts: { format: 'prettier --write .' },
2972
+ * })
2973
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2974
+ * ```
3228
2975
  */
3229
2976
  function prettierDetector(projectPath, packageJson) {
3230
2977
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3287,6 +3034,14 @@ const STYLELINT_CONFIG_PATTERNS = [
3287
3034
  * @param projectPath - Project directory path
3288
3035
  * @param packageJson - Optional pre-loaded package.json
3289
3036
  * @returns Detection result or null if not detected
3037
+ *
3038
+ * @example Detecting Stylelint linter
3039
+ * ```typescript
3040
+ * const result = stylelintDetector('/path/to/project', {
3041
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
3042
+ * })
3043
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
3044
+ * ```
3290
3045
  */
3291
3046
  function stylelintDetector(projectPath, packageJson) {
3292
3047
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3308,59 +3063,17 @@ function stylelintDetector(projectPath, packageJson) {
3308
3063
  break;
3309
3064
  }
3310
3065
  }
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' });
3066
+ const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
3067
+ if (stylelintPlugins.length > 0) {
3068
+ confidence += 5;
3069
+ sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
3357
3070
  }
3358
3071
  if (confidence === 0) {
3359
3072
  return null;
3360
3073
  }
3361
3074
  return {
3362
- id: 'biome',
3363
- name: 'Biome',
3075
+ id: 'stylelint',
3076
+ name: 'Stylelint',
3364
3077
  version,
3365
3078
  configPath,
3366
3079
  confidence: min(confidence, 100),
@@ -3377,140 +3090,179 @@ const lintingDetectors = [
3377
3090
  ];
3378
3091
 
3379
3092
  /**
3380
- * Detect NX in project.
3093
+ * Detect Lerna in project.
3381
3094
  *
3382
3095
  * @param workspacePath - Workspace directory path
3383
3096
  * @param packageJson - Optional pre-loaded package.json
3384
3097
  * @returns Detection result or null if not detected
3098
+ *
3099
+ * @example Detecting Lerna monorepo
3100
+ * ```typescript
3101
+ * // Project with lerna.json config file
3102
+ * const result = lernaDetector('/path/to/lerna-project')
3103
+ * // => {
3104
+ * // id: 'lerna',
3105
+ * // name: 'Lerna',
3106
+ * // confidence: 80,
3107
+ * // configPath: 'lerna.json',
3108
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
3109
+ * // }
3110
+ * ```
3385
3111
  */
3386
- function nxDetector(workspacePath, packageJson) {
3112
+ function lernaDetector(workspacePath, packageJson) {
3387
3113
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3388
3114
  const sources = [];
3389
3115
  let confidence = 0;
3390
3116
  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' });
3117
+ let configPath;
3118
+ const lernaJsonPath = join$1(workspacePath, 'lerna.json');
3119
+ if (exists(lernaJsonPath)) {
3120
+ confidence += 80;
3121
+ configPath = 'lerna.json';
3122
+ sources.push({ type: 'config-file', path: 'lerna.json' });
3396
3123
  }
3397
3124
  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
- };
3125
+ if (deps['lerna']) {
3126
+ confidence += 15;
3127
+ version = parseVersionString(deps['lerna']);
3128
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
3412
3129
  }
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' });
3130
+ if (exists(join$1(workspacePath, 'packages'))) {
3131
+ confidence += 5;
3132
+ sources.push({ type: 'directory', path: 'packages/' });
3417
3133
  }
3418
3134
  if (confidence === 0) {
3419
3135
  return null;
3420
3136
  }
3421
3137
  return {
3422
- id: 'nx',
3423
- name: 'NX',
3138
+ id: 'lerna',
3139
+ name: 'Lerna',
3424
3140
  version,
3425
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
3141
+ configPath,
3426
3142
  confidence: min(confidence, 100),
3427
3143
  detectedFrom: sources,
3428
- workspaceLayout,
3429
3144
  };
3430
3145
  }
3431
3146
 
3432
3147
  /**
3433
- * Detect Turborepo in project.
3148
+ * Detect npm workspaces in project.
3434
3149
  *
3435
3150
  * @param workspacePath - Workspace directory path
3436
3151
  * @param packageJson - Optional pre-loaded package.json
3437
3152
  * @returns Detection result or null if not detected
3153
+ *
3154
+ * @example Detecting npm workspaces
3155
+ * ```typescript
3156
+ * // Project with workspaces in package.json and package-lock.json
3157
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
3158
+ * // => {
3159
+ * // id: 'npm-workspaces',
3160
+ * // name: 'npm Workspaces',
3161
+ * // confidence: 90,
3162
+ * // configPath: 'package.json',
3163
+ * // detectedFrom: [
3164
+ * // { type: 'package.json', field: 'workspaces' },
3165
+ * // { type: 'lockfile', path: 'package-lock.json' }
3166
+ * // ]
3167
+ * // }
3168
+ * ```
3438
3169
  */
3439
- function turborepoDetector(workspacePath, packageJson) {
3170
+ function npmWorkspacesDetector(workspacePath, packageJson) {
3440
3171
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3441
3172
  const sources = [];
3442
3173
  let confidence = 0;
3443
- let version;
3444
- let configPath;
3445
- const turboJsonPath = join$1(workspacePath, 'turbo.json');
3446
- if (exists(turboJsonPath)) {
3174
+ if (pkg?.workspaces) {
3447
3175
  confidence += 80;
3448
- configPath = 'turbo.json';
3449
- sources.push({ type: 'config-file', path: 'turbo.json' });
3176
+ sources.push({ type: 'package.json', field: 'workspaces' });
3450
3177
  }
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' });
3178
+ if (exists(join$1(workspacePath, 'package-lock.json'))) {
3179
+ confidence += 10;
3180
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
3456
3181
  }
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)' });
3182
+ if (exists(join$1(workspacePath, 'yarn.lock'))) {
3183
+ return null;
3461
3184
  }
3462
3185
  if (confidence === 0) {
3463
3186
  return null;
3464
3187
  }
3465
3188
  return {
3466
- id: 'turborepo',
3467
- name: 'Turborepo',
3468
- version,
3469
- configPath,
3189
+ id: 'npm-workspaces',
3190
+ name: 'npm Workspaces',
3191
+ configPath: 'package.json',
3470
3192
  confidence: min(confidence, 100),
3471
3193
  detectedFrom: sources,
3472
3194
  };
3473
3195
  }
3474
3196
 
3475
3197
  /**
3476
- * Detect Lerna in project.
3198
+ * Detect NX in project.
3477
3199
  *
3478
3200
  * @param workspacePath - Workspace directory path
3479
3201
  * @param packageJson - Optional pre-loaded package.json
3480
3202
  * @returns Detection result or null if not detected
3203
+ *
3204
+ * @example Detecting NX workspace
3205
+ * ```typescript
3206
+ * // Project with nx.json and apps/libs directories
3207
+ * const result = nxDetector('/path/to/nx-workspace')
3208
+ * // => {
3209
+ * // id: 'nx',
3210
+ * // name: 'NX',
3211
+ * // confidence: 100,
3212
+ * // configPath: 'nx.json',
3213
+ * // version: '17.0.0',
3214
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
3215
+ * // detectedFrom: [
3216
+ * // { type: 'config-file', path: 'nx.json' },
3217
+ * // { type: 'package.json', field: 'dependencies.nx' },
3218
+ * // { type: 'directory', path: 'apps/ or libs/' }
3219
+ * // ]
3220
+ * // }
3221
+ * ```
3481
3222
  */
3482
- function lernaDetector(workspacePath, packageJson) {
3223
+ function nxDetector(workspacePath, packageJson) {
3483
3224
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3484
3225
  const sources = [];
3485
3226
  let confidence = 0;
3486
3227
  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' });
3228
+ let workspaceLayout;
3229
+ const nxJsonPath = join$1(workspacePath, 'nx.json');
3230
+ if (exists(nxJsonPath)) {
3231
+ confidence += 70;
3232
+ sources.push({ type: 'config-file', path: 'nx.json' });
3493
3233
  }
3494
3234
  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' });
3235
+ if (deps['nx']) {
3236
+ confidence += 20;
3237
+ version = parseVersionString(deps['nx']);
3238
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
3499
3239
  }
3500
- if (exists(join$1(workspacePath, 'packages'))) {
3501
- confidence += 5;
3502
- sources.push({ type: 'directory', path: 'packages/' });
3240
+ const hasApps = exists(join$1(workspacePath, 'apps'));
3241
+ const hasLibs = exists(join$1(workspacePath, 'libs'));
3242
+ if (hasApps || hasLibs) {
3243
+ confidence += 10;
3244
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
3245
+ workspaceLayout = {
3246
+ appsDir: hasApps ? 'apps' : '',
3247
+ libsDir: hasLibs ? 'libs' : '',
3248
+ };
3249
+ }
3250
+ const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
3251
+ if (nxPackages.length > 0) {
3252
+ confidence += 10;
3253
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
3503
3254
  }
3504
3255
  if (confidence === 0) {
3505
3256
  return null;
3506
3257
  }
3507
3258
  return {
3508
- id: 'lerna',
3509
- name: 'Lerna',
3259
+ id: 'nx',
3260
+ name: 'NX',
3510
3261
  version,
3511
- configPath,
3262
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
3512
3263
  confidence: min(confidence, 100),
3513
3264
  detectedFrom: sources,
3265
+ workspaceLayout,
3514
3266
  };
3515
3267
  }
3516
3268
 
@@ -3520,6 +3272,19 @@ function lernaDetector(workspacePath, packageJson) {
3520
3272
  * @param workspacePath - Workspace directory path
3521
3273
  * @param packageJson - Optional pre-loaded package.json
3522
3274
  * @returns Detection result or null if not detected
3275
+ *
3276
+ * @example Detecting Rush monorepo
3277
+ * ```typescript
3278
+ * // Project with rush.json config file
3279
+ * const result = rushDetector('/path/to/rush-project')
3280
+ * // => {
3281
+ * // id: 'rush',
3282
+ * // name: 'Rush',
3283
+ * // confidence: 90,
3284
+ * // configPath: 'rush.json',
3285
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
3286
+ * // }
3287
+ * ```
3523
3288
  */
3524
3289
  function rushDetector(workspacePath, packageJson) {
3525
3290
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -3557,66 +3322,60 @@ function rushDetector(workspacePath, packageJson) {
3557
3322
  }
3558
3323
 
3559
3324
  /**
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.
3325
+ * Detect Turborepo in project.
3593
3326
  *
3594
3327
  * @param workspacePath - Workspace directory path
3595
3328
  * @param packageJson - Optional pre-loaded package.json
3596
3329
  * @returns Detection result or null if not detected
3330
+ *
3331
+ * @example Detecting Turborepo monorepo
3332
+ * ```typescript
3333
+ * // Project with turbo.json and turbo dependency
3334
+ * const result = turborepoDetector('/path/to/turbo-project')
3335
+ * // => {
3336
+ * // id: 'turborepo',
3337
+ * // name: 'Turborepo',
3338
+ * // confidence: 95,
3339
+ * // configPath: 'turbo.json',
3340
+ * // version: '2.0.0',
3341
+ * // detectedFrom: [
3342
+ * // { type: 'config-file', path: 'turbo.json' },
3343
+ * // { type: 'package.json', field: 'dependencies.turbo' }
3344
+ * // ]
3345
+ * // }
3346
+ * ```
3597
3347
  */
3598
- function npmWorkspacesDetector(workspacePath, packageJson) {
3348
+ function turborepoDetector(workspacePath, packageJson) {
3599
3349
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
3600
3350
  const sources = [];
3601
3351
  let confidence = 0;
3602
- if (pkg?.workspaces) {
3352
+ let version;
3353
+ let configPath;
3354
+ const turboJsonPath = join$1(workspacePath, 'turbo.json');
3355
+ if (exists(turboJsonPath)) {
3603
3356
  confidence += 80;
3604
- sources.push({ type: 'package.json', field: 'workspaces' });
3357
+ configPath = 'turbo.json';
3358
+ sources.push({ type: 'config-file', path: 'turbo.json' });
3605
3359
  }
3606
- if (exists(join$1(workspacePath, 'package-lock.json'))) {
3607
- confidence += 10;
3608
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
3360
+ const deps = collectAllDependencies(pkg);
3361
+ if (deps['turbo']) {
3362
+ confidence += 15;
3363
+ version = parseVersionString(deps['turbo']);
3364
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
3609
3365
  }
3610
- if (exists(join$1(workspacePath, 'yarn.lock'))) {
3611
- return null;
3366
+ const scripts = pkg?.scripts ?? {};
3367
+ if (values(scripts).some((s) => s?.includes('turbo'))) {
3368
+ confidence += 5;
3369
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
3612
3370
  }
3613
3371
  if (confidence === 0) {
3614
3372
  return null;
3615
3373
  }
3616
3374
  return {
3617
- id: 'npm-workspaces',
3618
- name: 'npm Workspaces',
3619
- configPath: 'package.json',
3375
+ id: 'turborepo',
3376
+ name: 'Turborepo',
3377
+ version,
3378
+ configPath,
3620
3379
  confidence: min(confidence, 100),
3621
3380
  detectedFrom: sources,
3622
3381
  };
@@ -3628,6 +3387,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
3628
3387
  * @param workspacePath - Workspace directory path
3629
3388
  * @param packageJson - Optional pre-loaded package.json
3630
3389
  * @returns Detection result or null if not detected
3390
+ *
3391
+ * @example Detecting yarn workspaces
3392
+ * ```typescript
3393
+ * // Project with workspaces in package.json and yarn.lock
3394
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
3395
+ * // => {
3396
+ * // id: 'yarn-workspaces',
3397
+ * // name: 'Yarn Workspaces',
3398
+ * // confidence: 100,
3399
+ * // configPath: 'package.json',
3400
+ * // detectedFrom: [
3401
+ * // { type: 'package.json', field: 'workspaces' },
3402
+ * // { type: 'lockfile', path: 'yarn.lock' },
3403
+ * // { type: 'config-file', path: '.yarnrc.yml' }
3404
+ * // ]
3405
+ * // }
3406
+ * ```
3631
3407
  */
3632
3408
  function yarnWorkspacesDetector(workspacePath, packageJson) {
3633
3409
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -3668,107 +3444,125 @@ const monorepoDetectors = [
3668
3444
  { id: 'yarn-workspaces', name: 'Yarn Workspaces', detect: yarnWorkspacesDetector },
3669
3445
  ];
3670
3446
 
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'];
3447
+ /** Config patterns for Cypress */
3448
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3673
3449
  /**
3674
- * Detect Jest in project.
3450
+ * Detect Cypress in project.
3675
3451
  *
3676
3452
  * @param projectPath - Project directory path
3677
3453
  * @param packageJson - Optional pre-loaded package.json
3678
3454
  * @returns Detection result or null if not detected
3455
+ *
3456
+ * @example Detecting Cypress testing framework
3457
+ * ```typescript
3458
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
3459
+ *
3460
+ * const result = cypressDetector('./my-project')
3461
+ * if (result) {
3462
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
3463
+ * // => "Cypress 13.6.0 detected (95% confidence)"
3464
+ * }
3465
+ * ```
3679
3466
  */
3680
- function jestDetector(projectPath, packageJson) {
3467
+ function cypressDetector(projectPath, packageJson) {
3681
3468
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3682
3469
  const sources = [];
3683
3470
  let confidence = 0;
3684
3471
  let version;
3685
3472
  const deps = collectAllDependencies(pkg);
3686
- if (deps['jest']) {
3473
+ if (deps['cypress']) {
3687
3474
  confidence += 60;
3688
- version = parseVersionString(deps['jest']);
3689
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
3475
+ version = parseVersionString(deps['cypress']);
3476
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
3690
3477
  }
3691
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
3478
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3692
3479
  if (configPath) {
3693
3480
  confidence += 30;
3694
3481
  sources.push({ type: 'config-file', path: configPath });
3695
3482
  }
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')) {
3483
+ if (exists(join$1(projectPath, 'cypress'))) {
3702
3484
  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' });
3485
+ sources.push({ type: 'directory', path: 'cypress/' });
3708
3486
  }
3709
- if (deps['ts-jest']) {
3487
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3488
+ if (e2eScript.includes('cypress')) {
3710
3489
  confidence += 5;
3711
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3490
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3712
3491
  }
3713
3492
  if (confidence === 0) {
3714
3493
  return null;
3715
3494
  }
3716
3495
  return {
3717
- id: 'jest',
3718
- name: 'Jest',
3719
- type: 'unit',
3496
+ id: 'cypress',
3497
+ name: 'Cypress',
3498
+ type: 'e2e',
3720
3499
  version,
3721
3500
  configPath,
3722
3501
  confidence: min(confidence, 100),
3723
3502
  detectedFrom: sources,
3724
3503
  };
3725
3504
  }
3726
-
3727
- /** Config patterns for Vitest */
3728
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3505
+
3506
+ /** Config patterns for Jest */
3507
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
3729
3508
  /**
3730
- * Detect Vitest in project.
3509
+ * Detect Jest in project.
3731
3510
  *
3732
3511
  * @param projectPath - Project directory path
3733
3512
  * @param packageJson - Optional pre-loaded package.json
3734
3513
  * @returns Detection result or null if not detected
3514
+ *
3515
+ * @example Detecting Jest testing framework
3516
+ * ```typescript
3517
+ * import { jestDetector } from '@hyperfrontend/project-scope'
3518
+ *
3519
+ * const result = jestDetector('./my-project')
3520
+ * if (result) {
3521
+ * console.log(`Jest ${result.version} detected`)
3522
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
3523
+ * // => "Sources: ['package.json', 'config-file']"
3524
+ * }
3525
+ * ```
3735
3526
  */
3736
- function vitestDetector(projectPath, packageJson) {
3527
+ function jestDetector(projectPath, packageJson) {
3737
3528
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3738
3529
  const sources = [];
3739
3530
  let confidence = 0;
3740
3531
  let version;
3741
3532
  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' });
3533
+ if (deps['jest']) {
3534
+ confidence += 60;
3535
+ version = parseVersionString(deps['jest']);
3536
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
3746
3537
  }
3747
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3538
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
3748
3539
  if (configPath) {
3749
- confidence += 25;
3540
+ confidence += 30;
3750
3541
  sources.push({ type: 'config-file', path: configPath });
3751
3542
  }
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
- }
3543
+ if (pkg && 'jest' in pkg) {
3544
+ confidence += 20;
3545
+ sources.push({ type: 'package.json', field: 'jest' });
3760
3546
  }
3761
3547
  const testScript = pkg?.scripts?.['test'] ?? '';
3762
- if (testScript.includes('vitest')) {
3548
+ if (testScript.includes('jest')) {
3763
3549
  confidence += 10;
3764
3550
  sources.push({ type: 'package.json', field: 'scripts.test' });
3765
3551
  }
3552
+ if (deps['@types/jest']) {
3553
+ confidence += 5;
3554
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
3555
+ }
3556
+ if (deps['ts-jest']) {
3557
+ confidence += 5;
3558
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3559
+ }
3766
3560
  if (confidence === 0) {
3767
3561
  return null;
3768
3562
  }
3769
3563
  return {
3770
- id: 'vitest',
3771
- name: 'Vitest',
3564
+ id: 'jest',
3565
+ name: 'Jest',
3772
3566
  type: 'unit',
3773
3567
  version,
3774
3568
  configPath,
@@ -3785,6 +3579,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
3785
3579
  * @param projectPath - Project directory path
3786
3580
  * @param packageJson - Optional pre-loaded package.json
3787
3581
  * @returns Detection result or null if not detected
3582
+ *
3583
+ * @example Detecting Mocha testing framework
3584
+ * ```typescript
3585
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
3586
+ *
3587
+ * const result = mochaDetector('./my-project')
3588
+ * if (result) {
3589
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
3590
+ * // => "Mocha 10.2.0 detected (95%)"
3591
+ * }
3592
+ * ```
3788
3593
  */
3789
3594
  function mochaDetector(projectPath, packageJson) {
3790
3595
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3829,37 +3634,53 @@ function mochaDetector(projectPath, packageJson) {
3829
3634
  };
3830
3635
  }
3831
3636
 
3832
- /** Config patterns for Cypress */
3833
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3637
+ /** Config patterns for Playwright */
3638
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3834
3639
  /**
3835
- * Detect Cypress in project.
3640
+ * Detect Playwright in project.
3836
3641
  *
3837
3642
  * @param projectPath - Project directory path
3838
3643
  * @param packageJson - Optional pre-loaded package.json
3839
3644
  * @returns Detection result or null if not detected
3645
+ *
3646
+ * @example Detecting Playwright testing framework
3647
+ * ```typescript
3648
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
3649
+ *
3650
+ * const result = playwrightDetector('./my-project')
3651
+ * if (result) {
3652
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
3653
+ * // => "Playwright 1.42.0 (e2e tests)"
3654
+ * }
3655
+ * ```
3840
3656
  */
3841
- function cypressDetector(projectPath, packageJson) {
3657
+ function playwrightDetector(projectPath, packageJson) {
3842
3658
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3843
3659
  const sources = [];
3844
3660
  let confidence = 0;
3845
3661
  let version;
3846
3662
  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' });
3663
+ if (deps['@playwright/test']) {
3664
+ confidence += 70;
3665
+ version = parseVersionString(deps['@playwright/test']);
3666
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3851
3667
  }
3852
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3668
+ if (deps['playwright']) {
3669
+ confidence += 50;
3670
+ version = version ?? parseVersionString(deps['playwright']);
3671
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3672
+ }
3673
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3853
3674
  if (configPath) {
3854
- confidence += 30;
3675
+ confidence += 25;
3855
3676
  sources.push({ type: 'config-file', path: configPath });
3856
3677
  }
3857
- if (exists(join$1(projectPath, 'cypress'))) {
3858
- confidence += 10;
3859
- sources.push({ type: 'directory', path: 'cypress/' });
3678
+ if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3679
+ confidence += 5;
3680
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3860
3681
  }
3861
3682
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3862
- if (e2eScript.includes('cypress')) {
3683
+ if (e2eScript.includes('playwright')) {
3863
3684
  confidence += 5;
3864
3685
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3865
3686
  }
@@ -3867,8 +3688,8 @@ function cypressDetector(projectPath, packageJson) {
3867
3688
  return null;
3868
3689
  }
3869
3690
  return {
3870
- id: 'cypress',
3871
- name: 'Cypress',
3691
+ id: 'playwright',
3692
+ name: 'Playwright',
3872
3693
  type: 'e2e',
3873
3694
  version,
3874
3695
  configPath,
@@ -3877,52 +3698,64 @@ function cypressDetector(projectPath, packageJson) {
3877
3698
  };
3878
3699
  }
3879
3700
 
3880
- /** Config patterns for Playwright */
3881
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3701
+ /** Config patterns for Vitest */
3702
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3882
3703
  /**
3883
- * Detect Playwright in project.
3704
+ * Detect Vitest in project.
3884
3705
  *
3885
3706
  * @param projectPath - Project directory path
3886
3707
  * @param packageJson - Optional pre-loaded package.json
3887
3708
  * @returns Detection result or null if not detected
3709
+ *
3710
+ * @example Detecting Vitest testing framework
3711
+ * ```typescript
3712
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3713
+ *
3714
+ * const result = vitestDetector('./my-project')
3715
+ * if (result) {
3716
+ * console.log(`Vitest ${result.version} detected`)
3717
+ * console.log('Config:', result.configPath)
3718
+ * // => "Config: vitest.config.ts"
3719
+ * }
3720
+ * ```
3888
3721
  */
3889
- function playwrightDetector(projectPath, packageJson) {
3722
+ function vitestDetector(projectPath, packageJson) {
3890
3723
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3891
3724
  const sources = [];
3892
3725
  let confidence = 0;
3893
3726
  let version;
3894
3727
  const deps = collectAllDependencies(pkg);
3895
- if (deps['@playwright/test']) {
3728
+ if (deps['vitest']) {
3896
3729
  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' });
3730
+ version = parseVersionString(deps['vitest']);
3731
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3904
3732
  }
3905
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3733
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3906
3734
  if (configPath) {
3907
3735
  confidence += 25;
3908
3736
  sources.push({ type: 'config-file', path: configPath });
3909
3737
  }
3910
- if (exists(join$1(projectPath, 'e2e')) || exists(join$1(projectPath, 'tests'))) {
3911
- confidence += 5;
3912
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3738
+ if (!configPath) {
3739
+ const viteConfig = exists(join$1(projectPath, 'vite.config.ts')) ||
3740
+ exists(join$1(projectPath, 'vite.config.js')) ||
3741
+ exists(join$1(projectPath, 'vite.config.mjs'));
3742
+ if (viteConfig && deps['vitest']) {
3743
+ confidence += 5;
3744
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3745
+ }
3913
3746
  }
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' });
3747
+ const testScript = pkg?.scripts?.['test'] ?? '';
3748
+ if (testScript.includes('vitest')) {
3749
+ confidence += 10;
3750
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3918
3751
  }
3919
3752
  if (confidence === 0) {
3920
3753
  return null;
3921
3754
  }
3922
3755
  return {
3923
- id: 'playwright',
3924
- name: 'Playwright',
3925
- type: 'e2e',
3756
+ id: 'vitest',
3757
+ name: 'Vitest',
3758
+ type: 'unit',
3926
3759
  version,
3927
3760
  configPath,
3928
3761
  confidence: min(confidence, 100),
@@ -3952,7 +3785,7 @@ function checkTsConfigStrict(projectPath) {
3952
3785
  return undefined;
3953
3786
  try {
3954
3787
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3955
- const parsed = parse(cleanContent);
3788
+ const parsed = parse$1(cleanContent);
3956
3789
  return parsed?.compilerOptions?.strict === true;
3957
3790
  }
3958
3791
  catch {
@@ -3965,6 +3798,19 @@ function checkTsConfigStrict(projectPath) {
3965
3798
  * @param projectPath - Project directory path
3966
3799
  * @param packageJson - Optional pre-loaded package.json
3967
3800
  * @returns Detection result or null if not detected
3801
+ *
3802
+ * @example Detecting TypeScript
3803
+ * ```typescript
3804
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3805
+ *
3806
+ * const result = typescriptDetector('./my-project')
3807
+ * if (result) {
3808
+ * console.log(`TypeScript ${result.version}`)
3809
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3810
+ * // => "TypeScript 5.3.0"
3811
+ * // => "Strict mode: true"
3812
+ * }
3813
+ * ```
3968
3814
  */
3969
3815
  function typescriptDetector(projectPath, packageJson) {
3970
3816
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4016,6 +3862,17 @@ function typescriptDetector(projectPath, packageJson) {
4016
3862
  * @param projectPath - Project directory path
4017
3863
  * @param packageJson - Optional pre-loaded package.json
4018
3864
  * @returns Detection result or null if not detected
3865
+ *
3866
+ * @example Detecting Flow type system
3867
+ * ```typescript
3868
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3869
+ *
3870
+ * const result = flowDetector('./my-project')
3871
+ * if (result) {
3872
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3873
+ * // => "Flow 0.232.0 with config: .flowconfig"
3874
+ * }
3875
+ * ```
4019
3876
  */
4020
3877
  function flowDetector(projectPath, packageJson) {
4021
3878
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4073,6 +3930,18 @@ function hasJsDocTypes(content) {
4073
3930
  * @param projectPath - Project directory path
4074
3931
  * @param packageJson - Optional pre-loaded package.json
4075
3932
  * @returns Detection result or null if not detected
3933
+ *
3934
+ * @example Detecting JSDoc type annotations
3935
+ * ```typescript
3936
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3937
+ *
3938
+ * const result = jsdocDetector('./my-project')
3939
+ * if (result) {
3940
+ * console.log('JSDoc types detected')
3941
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3942
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3943
+ * }
3944
+ * ```
4076
3945
  */
4077
3946
  function jsdocDetector(projectPath, packageJson) {
4078
3947
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -4089,7 +3958,7 @@ function jsdocDetector(projectPath, packageJson) {
4089
3958
  if (content) {
4090
3959
  try {
4091
3960
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
4092
- const parsed = parse(cleanContent);
3961
+ const parsed = parse$1(cleanContent);
4093
3962
  if (parsed?.compilerOptions?.checkJs === true || parsed?.compilerOptions?.allowJs === true) {
4094
3963
  confidence += 30;
4095
3964
  sources.push({ type: 'config-file', path: 'tsconfig.json (checkJs/allowJs)' });
@@ -4166,7 +4035,7 @@ function isDetectAllOptions(value) {
4166
4035
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
4167
4036
  * @returns All detection results organized by category
4168
4037
  *
4169
- * @example
4038
+ * @example Running all tech detectors
4170
4039
  * ```typescript
4171
4040
  * import { detectAll } from '@hyperfrontend/project-scope'
4172
4041
  *
@@ -4258,7 +4127,7 @@ const projectTypeLogger = createScopedLogger('project-scope:heuristics:project-t
4258
4127
  * @param options - Detection options
4259
4128
  * @returns Project type detection result with confidence score
4260
4129
  *
4261
- * @example
4130
+ * @example Detecting project type
4262
4131
  * ```typescript
4263
4132
  * import { detectProjectType } from '@hyperfrontend/project-scope'
4264
4133
  *
@@ -4376,7 +4245,7 @@ function detectProjectType(projectPath, options) {
4376
4245
  const projectJsonContent = readFileIfExists(projectJsonPath);
4377
4246
  if (projectJsonContent) {
4378
4247
  try {
4379
- const projectJson = parse(projectJsonContent);
4248
+ const projectJson = parse$1(projectJsonContent);
4380
4249
  if (projectJson.projectType) {
4381
4250
  const nxType = projectJson.projectType === 'library' ? 'library' : 'application';
4382
4251
  typeScores[nxType] += 50;
@@ -4436,6 +4305,15 @@ createScopedLogger('project-scope:root');
4436
4305
  * @param startPath - Starting path
4437
4306
  * @param markers - Files to search for
4438
4307
  * @returns Root directory path or null
4308
+ *
4309
+ * @example Finding root by marker files
4310
+ * ```typescript
4311
+ * import { findRootDirectory } from '@hyperfrontend/project-scope'
4312
+ *
4313
+ * // Find monorepo root by looking for nx.json or lerna.json
4314
+ * const root = findRootDirectory('./libs/my-lib', ['nx.json', 'lerna.json'])
4315
+ * // => '/path/to/monorepo'
4316
+ * ```
4439
4317
  */
4440
4318
  function findRootDirectory(startPath, markers) {
4441
4319
  return locateByMarkers(startPath, markers);
@@ -4452,7 +4330,7 @@ const NX_CONFIG_FILES = ['nx.json', 'workspace.json'];
4452
4330
  * @param path - Directory path to check
4453
4331
  * @returns True if the directory contains nx.json or workspace.json
4454
4332
  *
4455
- * @example
4333
+ * @example Checking for NX workspace
4456
4334
  * ```typescript
4457
4335
  * import { isNxWorkspace } from '@hyperfrontend/project-scope'
4458
4336
  *
@@ -4477,7 +4355,7 @@ function isNxWorkspace(path) {
4477
4355
  * @param startPath - Starting path to search from
4478
4356
  * @returns Workspace root path or null if not found
4479
4357
  *
4480
- * @example
4358
+ * @example Finding NX workspace root
4481
4359
  * ```typescript
4482
4360
  * import { findNxWorkspaceRoot } from '@hyperfrontend/project-scope'
4483
4361
  *
@@ -4499,178 +4377,8 @@ function findNxWorkspaceRoot(startPath) {
4499
4377
  return result;
4500
4378
  }
4501
4379
 
4502
- createScopedLogger('project-scope:nx:devkit');
4503
-
4504
4380
  createScopedLogger('project-scope:nx:config');
4505
4381
 
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
4382
  const configLogger = createScopedLogger('project-scope:config');
4675
4383
  /**
4676
4384
  * Cache for config detection results.
@@ -4688,7 +4396,7 @@ const configDetectionCache = createCache({ ttl: 30000, maxSize: 50 });
4688
4396
  * @param options - Detection options
4689
4397
  * @returns Array of detected configuration files
4690
4398
  *
4691
- * @example
4399
+ * @example Detecting configuration files
4692
4400
  * ```typescript
4693
4401
  * import { detectConfigs } from '@hyperfrontend/project-scope'
4694
4402
  *
@@ -4765,25 +4473,6 @@ function detectConfigs(rootPath, types, options) {
4765
4473
  return results;
4766
4474
  }
4767
4475
 
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
4476
  /**
4788
4477
  * Detect config type from file name.
4789
4478
  * Uses safe character-by-character matching to prevent ReDoS attacks.
@@ -4995,11 +4684,23 @@ function parseDotenv(content) {
4995
4684
  * @param type - Category of configuration (e.g., typescript, eslint)
4996
4685
  * @param format - Whether to strip comments (jsonc) or parse strictly (json)
4997
4686
  * @returns Configuration object with parsed data and extends references
4687
+ *
4688
+ * @example Parsing JSON configuration
4689
+ * ```typescript
4690
+ * import { parseJsonConfig } from '@hyperfrontend/project-scope'
4691
+ *
4692
+ * const config = parseJsonConfig(
4693
+ * 'tsconfig.json',
4694
+ * '{ "extends": "./base.json", "compilerOptions": {} }',
4695
+ * 'typescript'
4696
+ * )
4697
+ * // => { type: 'typescript', path: 'tsconfig.json', data: {...}, extends: ['./base.json'] }
4698
+ * ```
4998
4699
  */
4999
4700
  function parseJsonConfig(filePath, content, type, format = 'json') {
5000
4701
  const cleanContent = format === 'jsonc' ? stripJsonComments(content) : content;
5001
4702
  try {
5002
- const data = parse(cleanContent);
4703
+ const data = parse$1(cleanContent);
5003
4704
  let extendsPath;
5004
4705
  if (typeof data['extends'] === 'string') {
5005
4706
  extendsPath = [data['extends']];
@@ -5030,6 +4731,14 @@ function parseJsonConfig(filePath, content, type, format = 'json') {
5030
4731
  * @param content - Raw file content to parse
5031
4732
  * @param type - Category of configuration (e.g., github-actions, docker-compose)
5032
4733
  * @returns Configuration object with parsed YAML data
4734
+ *
4735
+ * @example Parsing YAML configuration
4736
+ * ```typescript
4737
+ * import { parseYamlConfig } from '@hyperfrontend/project-scope'
4738
+ *
4739
+ * const config = parseYamlConfig('.github/workflows/ci.yml', yamlContent, 'github-actions')
4740
+ * // => { type: 'github-actions', path: '...', format: 'yaml', data: {...} }
4741
+ * ```
5033
4742
  */
5034
4743
  function parseYamlConfig(filePath, content, type) {
5035
4744
  const data = parseSimpleYaml(content);
@@ -5046,6 +4755,14 @@ function parseYamlConfig(filePath, content, type) {
5046
4755
  * @param filePath - Path to config file
5047
4756
  * @param type - Optional config type (auto-detected if not provided)
5048
4757
  * @returns Parsed configuration
4758
+ *
4759
+ * @example Parsing a configuration file
4760
+ * ```typescript
4761
+ * import { parseConfig } from '@hyperfrontend/project-scope'
4762
+ *
4763
+ * const tsConfig = parseConfig('/project/tsconfig.json')
4764
+ * const eslintConfig = parseConfig('/project/.eslintrc.yml', 'eslint')
4765
+ * ```
5049
4766
  */
5050
4767
  function parseConfig(filePath, type) {
5051
4768
  const content = readFileContent(filePath);
@@ -5178,7 +4895,7 @@ function normalizeConfigFormat(format) {
5178
4895
  * @param options - Analysis options
5179
4896
  * @returns Complete analysis result
5180
4897
  *
5181
- * @example
4898
+ * @example Basic project analysis
5182
4899
  * ```typescript
5183
4900
  * const result = analyzeProject('./my-project')
5184
4901
  * console.log(result.projectType) // 'application' | 'library' | ...
@@ -5511,6 +5228,26 @@ function parseAnalyzeArgs(args) {
5511
5228
  *
5512
5229
  * @param options - Configuration for the analyze operation
5513
5230
  * @returns Command execution result with exit code and output
5231
+ *
5232
+ * @example Basic analysis of current directory
5233
+ * ```typescript
5234
+ * const result = analyzeCommand({ depth: 'basic' })
5235
+ * if (result.exitCode === 0) {
5236
+ * console.log(result.output)
5237
+ * // => "Project Type: Library\nWorkspace: NX Monorepo\n..."
5238
+ * }
5239
+ * ```
5240
+ *
5241
+ * @example JSON output with filters
5242
+ * ```typescript
5243
+ * const result = analyzeCommand({
5244
+ * path: './apps/frontend',
5245
+ * format: 'json',
5246
+ * depth: 'deep',
5247
+ * exclude: ['node_modules', 'dist'],
5248
+ * })
5249
+ * // => { exitCode: 0, output: '{"type":"application",...}' }
5250
+ * ```
5514
5251
  */
5515
5252
  function analyzeCommand(options) {
5516
5253
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -5790,6 +5527,26 @@ function parseConfigArgs(args) {
5790
5527
  *
5791
5528
  * @param options - Configuration command options
5792
5529
  * @returns Command execution result with exit code and output
5530
+ *
5531
+ * @example Detect all configs in a project
5532
+ * ```typescript
5533
+ * const result = configCommand({ path: './my-project' })
5534
+ * if (result.exitCode === 0) {
5535
+ * console.log(result.output)
5536
+ * // => "TypeScript: tsconfig.json\nLinting: eslint.config.js\n..."
5537
+ * }
5538
+ * ```
5539
+ *
5540
+ * @example Filter by type with contents
5541
+ * ```typescript
5542
+ * const result = configCommand({
5543
+ * path: './my-project',
5544
+ * type: 'tsconfig',
5545
+ * showContents: true,
5546
+ * format: 'json',
5547
+ * })
5548
+ * // => { exitCode: 0, output: '[{"type":"tsconfig","path":"tsconfig.json",...}]' }
5549
+ * ```
5793
5550
  */
5794
5551
  function configCommand(options) {
5795
5552
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -5999,6 +5756,25 @@ function parseDepsArgs(args) {
5999
5756
  *
6000
5757
  * @param options - Parsed command options
6001
5758
  * @returns Command execution result with exit code and output
5759
+ *
5760
+ * @example List all dependencies
5761
+ * ```typescript
5762
+ * const result = depsCommand({ path: './my-project' })
5763
+ * if (result.exitCode === 0) {
5764
+ * console.log(result.output)
5765
+ * // => "Dependencies\n============\nProduction (3):\n react ^18.2.0\n..."
5766
+ * }
5767
+ * ```
5768
+ *
5769
+ * @example Filter to dev dependencies as JSON
5770
+ * ```typescript
5771
+ * const result = depsCommand({
5772
+ * path: './my-project',
5773
+ * type: 'development',
5774
+ * format: 'json',
5775
+ * })
5776
+ * // => { exitCode: 0, output: '{"devDependencies":{"typescript":"^5.0.0",...}}' }
5777
+ * ```
6002
5778
  */
6003
5779
  function depsCommand(options) {
6004
5780
  const projectPath = options.path ? resolve(options.path) : process.cwd();
@@ -6275,6 +6051,27 @@ function parseTreeArgs(args) {
6275
6051
  *
6276
6052
  * @param options - Configuration for the tree operation
6277
6053
  * @returns Command execution result with exit code and output
6054
+ *
6055
+ * @example Basic tree of current directory
6056
+ * ```typescript
6057
+ * const result = treeCommand({ depth: 2 })
6058
+ * if (result.exitCode === 0) {
6059
+ * console.log(result.output)
6060
+ * // => "src/\n├── index.ts\n├── lib/\n│ └── utils.ts\n..."
6061
+ * }
6062
+ * ```
6063
+ *
6064
+ * @example Directories only with metadata
6065
+ * ```typescript
6066
+ * const result = treeCommand({
6067
+ * path: './project',
6068
+ * dirsOnly: true,
6069
+ * showSize: true,
6070
+ * ignore: ['node_modules', '.git'],
6071
+ * format: 'json',
6072
+ * })
6073
+ * // => { exitCode: 0, output: '[{"name":"src","isDirectory":true,...}]' }
6074
+ * ```
6278
6075
  */
6279
6076
  function treeCommand(options) {
6280
6077
  const rootPath = options.path ? resolve(options.path) : process.cwd();
@@ -6432,7 +6229,7 @@ function parseGlobalOptions(args) {
6432
6229
  * @param args - Command line arguments (typically process.argv.slice(2))
6433
6230
  * @returns Command result with exit code and optional output/error
6434
6231
  *
6435
- * @example
6232
+ * @example Running analysis via CLI
6436
6233
  * ```typescript
6437
6234
  * import { run } from '@hyperfrontend/project-scope'
6438
6235
  *
@@ -6493,4 +6290,3 @@ function run(args) {
6493
6290
  }
6494
6291
 
6495
6292
  export { analyzeCommand, analyzeCommandDef, configCommand, configCommandDef, depsCommand, depsCommandDef, run, treeCommand, treeCommandDef };
6496
- //# sourceMappingURL=index.esm.js.map