@hyperfrontend/project-scope 0.2.1 → 0.2.2

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