@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
@@ -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
  }
@@ -1191,102 +672,194 @@ const backendDetectors = [
1191
672
  { id: 'hono', name: 'Hono', detect: honoDetector },
1192
673
  ];
1193
674
 
1194
- /** Config patterns for Webpack */
1195
- const WEBPACK_CONFIG_PATTERNS = [
1196
- 'webpack.config.js',
1197
- 'webpack.config.ts',
1198
- 'webpack.config.cjs',
1199
- 'webpack.config.mjs',
1200
- 'webpack.config.babel.js',
1201
- ];
675
+ /** Config patterns for Babel */
676
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1202
677
  /**
1203
- * Detect Webpack in project.
678
+ * Detect Babel in project.
1204
679
  *
1205
680
  * @param projectPath - Project directory path
1206
681
  * @param packageJson - Optional pre-loaded package.json
1207
682
  * @returns Detection result or null if not detected
683
+ *
684
+ * @example Detecting Babel compiler
685
+ * ```typescript
686
+ * const result = babelDetector('/path/to/project', {
687
+ * name: 'my-app',
688
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
689
+ * })
690
+ * // => {
691
+ * // id: 'babel',
692
+ * // name: 'Babel',
693
+ * // version: '7.23.0',
694
+ * // confidence: 60,
695
+ * // detectedFrom: [
696
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
697
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
698
+ * // ]
699
+ * // }
700
+ * ```
1208
701
  */
1209
- function webpackDetector(projectPath, packageJson) {
702
+ function babelDetector(projectPath, packageJson) {
1210
703
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1211
704
  const sources = [];
1212
705
  let confidence = 0;
1213
706
  let version;
1214
707
  const deps = collectAllDependencies(pkg);
1215
- if (deps['webpack']) {
708
+ if (deps['@babel/core']) {
1216
709
  confidence += 50;
1217
- version = parseVersionString(deps['webpack']);
1218
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
710
+ version = parseVersionString(deps['@babel/core']);
711
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1219
712
  }
1220
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
713
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1221
714
  if (configPath) {
1222
715
  confidence += 40;
1223
716
  sources.push({ type: 'config-file', path: configPath });
1224
717
  }
1225
- if (deps['webpack-cli']) {
718
+ if (pkg && 'babel' in pkg) {
719
+ confidence += 30;
720
+ sources.push({ type: 'package.json', field: 'babel' });
721
+ }
722
+ const babelPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@babel/'));
723
+ if (babelPackages.length > 1) {
1226
724
  confidence += 10;
1227
- sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
725
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1228
726
  }
1229
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
727
+ if (confidence === 0) {
728
+ return null;
729
+ }
730
+ return {
731
+ id: 'babel',
732
+ name: 'Babel',
733
+ version,
734
+ configPath,
735
+ confidence: index_cjs_js$8.min(confidence, 100),
736
+ detectedFrom: sources,
737
+ };
738
+ }
739
+
740
+ /**
741
+ * Detect esbuild in project.
742
+ *
743
+ * @param projectPath - Project directory path
744
+ * @param packageJson - Optional pre-loaded package.json
745
+ * @returns Detection result or null if not detected
746
+ *
747
+ * @example Detecting esbuild bundler
748
+ * ```typescript
749
+ * const result = esbuildDetector('/path/to/project', {
750
+ * name: 'my-lib',
751
+ * devDependencies: { 'esbuild': '^0.19.0' },
752
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
753
+ * })
754
+ * // => {
755
+ * // id: 'esbuild',
756
+ * // name: 'esbuild',
757
+ * // version: '0.19.0',
758
+ * // confidence: 80,
759
+ * // detectedFrom: [
760
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
761
+ * // { type: 'package.json', field: 'scripts.build' }
762
+ * // ]
763
+ * // }
764
+ * ```
765
+ */
766
+ function esbuildDetector(projectPath, packageJson) {
767
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
768
+ const sources = [];
769
+ let confidence = 0;
770
+ let version;
771
+ const deps = collectAllDependencies(pkg);
772
+ if (deps['esbuild']) {
773
+ confidence += 70;
774
+ version = parseVersionString(deps['esbuild']);
775
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
776
+ }
777
+ const esbuildPlugins = index_cjs_js$2.keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
778
+ if (esbuildPlugins.length > 0) {
779
+ confidence += 15;
780
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
781
+ }
782
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1230
783
  for (const name of scriptMatches) {
1231
- confidence = min(confidence + 5, 100);
784
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
1232
785
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1233
786
  }
1234
787
  if (confidence === 0) {
1235
788
  return null;
1236
789
  }
1237
790
  return {
1238
- id: 'webpack',
1239
- name: 'Webpack',
791
+ id: 'esbuild',
792
+ name: 'esbuild',
1240
793
  version,
1241
- configPath,
1242
- confidence: min(confidence, 100),
794
+ confidence: index_cjs_js$8.min(confidence, 100),
1243
795
  detectedFrom: sources,
1244
796
  };
1245
797
  }
1246
798
 
1247
- /** Config patterns for Vite */
1248
- const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
799
+ /** Config patterns for Parcel */
800
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1249
801
  /**
1250
- * Detect Vite in project.
802
+ * Detect Parcel in project.
1251
803
  *
1252
804
  * @param projectPath - Project directory path
1253
805
  * @param packageJson - Optional pre-loaded package.json
1254
806
  * @returns Detection result or null if not detected
807
+ *
808
+ * @example Detecting Parcel bundler
809
+ * ```typescript
810
+ * const result = parcelDetector('/path/to/project', {
811
+ * name: 'my-app',
812
+ * devDependencies: { 'parcel': '^2.10.0' },
813
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
814
+ * })
815
+ * // => {
816
+ * // id: 'parcel',
817
+ * // name: 'Parcel',
818
+ * // version: '2.10.0',
819
+ * // confidence: 80,
820
+ * // detectedFrom: [
821
+ * // { type: 'package.json', field: 'dependencies.parcel' },
822
+ * // { type: 'package.json', field: 'scripts.dev' },
823
+ * // { type: 'package.json', field: 'scripts.build' }
824
+ * // ]
825
+ * // }
826
+ * ```
1255
827
  */
1256
- function viteDetector(projectPath, packageJson) {
828
+ function parcelDetector(projectPath, packageJson) {
1257
829
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1258
830
  const sources = [];
1259
831
  let confidence = 0;
1260
832
  let version;
1261
833
  const deps = collectAllDependencies(pkg);
1262
- if (deps['vite']) {
834
+ if (deps['parcel']) {
1263
835
  confidence += 60;
1264
- version = parseVersionString(deps['vite']);
1265
- sources.push({ type: 'package.json', field: 'dependencies.vite' });
836
+ version = parseVersionString(deps['parcel']);
837
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1266
838
  }
1267
- const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
839
+ if (deps['parcel-bundler']) {
840
+ confidence += 60;
841
+ version = parseVersionString(deps['parcel-bundler']);
842
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
843
+ }
844
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1268
845
  if (configPath) {
1269
- confidence += 35;
846
+ confidence += 30;
1270
847
  sources.push({ type: 'config-file', path: configPath });
1271
848
  }
1272
- if (deps['vitest']) {
1273
- confidence += 10;
1274
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1275
- }
1276
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1277
- if (vitePlugins.length > 0) {
1278
- confidence += 10;
1279
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
849
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
850
+ for (const name of scriptMatches) {
851
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
852
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1280
853
  }
1281
854
  if (confidence === 0) {
1282
855
  return null;
1283
856
  }
1284
857
  return {
1285
- id: 'vite',
1286
- name: 'Vite',
858
+ id: 'parcel',
859
+ name: 'Parcel',
1287
860
  version,
1288
861
  configPath,
1289
- confidence: min(confidence, 100),
862
+ confidence: index_cjs_js$8.min(confidence, 100),
1290
863
  detectedFrom: sources,
1291
864
  };
1292
865
  }
@@ -1299,6 +872,28 @@ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.
1299
872
  * @param projectPath - Project directory path
1300
873
  * @param packageJson - Optional pre-loaded package.json
1301
874
  * @returns Detection result or null if not detected
875
+ *
876
+ * @example Detecting Rollup bundler
877
+ * ```typescript
878
+ * const result = rollupDetector('/path/to/project', {
879
+ * name: 'my-lib',
880
+ * devDependencies: {
881
+ * 'rollup': '^4.0.0',
882
+ * '@rollup/plugin-node-resolve': '^15.0.0',
883
+ * '@rollup/plugin-commonjs': '^25.0.0'
884
+ * }
885
+ * })
886
+ * // => {
887
+ * // id: 'rollup',
888
+ * // name: 'Rollup',
889
+ * // version: '4.0.0',
890
+ * // confidence: 65,
891
+ * // detectedFrom: [
892
+ * // { type: 'package.json', field: 'dependencies.rollup' },
893
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
894
+ * // ]
895
+ * // }
896
+ * ```
1302
897
  */
1303
898
  function rollupDetector(projectPath, packageJson) {
1304
899
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1316,14 +911,14 @@ function rollupDetector(projectPath, packageJson) {
1316
911
  confidence += 40;
1317
912
  sources.push({ type: 'config-file', path: configPath });
1318
913
  }
1319
- const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
914
+ const rollupPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1320
915
  if (rollupPlugins.length > 0) {
1321
916
  confidence += 10;
1322
917
  sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1323
918
  }
1324
919
  const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1325
920
  for (const name of scriptMatches) {
1326
- confidence = min(confidence + 5, 100);
921
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1327
922
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1328
923
  }
1329
924
  if (confidence === 0) {
@@ -1334,280 +929,412 @@ function rollupDetector(projectPath, packageJson) {
1334
929
  name: 'Rollup',
1335
930
  version,
1336
931
  configPath,
1337
- confidence: min(confidence, 100),
932
+ confidence: index_cjs_js$8.min(confidence, 100),
1338
933
  detectedFrom: sources,
1339
934
  };
1340
935
  }
1341
936
 
937
+ /** Config patterns for SWC */
938
+ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1342
939
  /**
1343
- * Detect esbuild in project.
940
+ * Detect SWC in project.
1344
941
  *
1345
942
  * @param projectPath - Project directory path
1346
943
  * @param packageJson - Optional pre-loaded package.json
1347
944
  * @returns Detection result or null if not detected
945
+ *
946
+ * @example Detecting SWC compiler
947
+ * ```typescript
948
+ * const result = swcDetector('/path/to/project', {
949
+ * name: 'my-app',
950
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
951
+ * })
952
+ * // => {
953
+ * // id: 'swc',
954
+ * // name: 'SWC',
955
+ * // version: '1.3.0',
956
+ * // confidence: 70,
957
+ * // detectedFrom: [
958
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
959
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
960
+ * // ]
961
+ * // }
962
+ * ```
1348
963
  */
1349
- function esbuildDetector(projectPath, packageJson) {
964
+ function swcDetector(projectPath, packageJson) {
1350
965
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1351
966
  const sources = [];
1352
967
  let confidence = 0;
1353
968
  let version;
1354
969
  const deps = collectAllDependencies(pkg);
1355
- if (deps['esbuild']) {
1356
- confidence += 70;
1357
- version = parseVersionString(deps['esbuild']);
1358
- sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
970
+ if (deps['@swc/core']) {
971
+ confidence += 60;
972
+ version = parseVersionString(deps['@swc/core']);
973
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1359
974
  }
1360
- const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1361
- if (esbuildPlugins.length > 0) {
1362
- confidence += 15;
1363
- sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
975
+ const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
976
+ if (configPath) {
977
+ confidence += 35;
978
+ sources.push({ type: 'config-file', path: configPath });
1364
979
  }
1365
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1366
- for (const name of scriptMatches) {
1367
- confidence = min(confidence + 10, 100);
1368
- sources.push({ type: 'package.json', field: `scripts.${name}` });
980
+ if (deps['@swc/cli']) {
981
+ confidence += 10;
982
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
983
+ }
984
+ const swcPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
985
+ if (swcPlugins.length > 1) {
986
+ confidence += 5;
987
+ sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1369
988
  }
1370
989
  if (confidence === 0) {
1371
990
  return null;
1372
991
  }
1373
992
  return {
1374
- id: 'esbuild',
1375
- name: 'esbuild',
993
+ id: 'swc',
994
+ name: 'SWC',
1376
995
  version,
1377
- confidence: min(confidence, 100),
996
+ configPath,
997
+ confidence: index_cjs_js$8.min(confidence, 100),
1378
998
  detectedFrom: sources,
1379
999
  };
1380
1000
  }
1381
1001
 
1382
- /** Config patterns for Babel */
1383
- const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1002
+ /** Config patterns for Vite */
1003
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
1384
1004
  /**
1385
- * Detect Babel in project.
1005
+ * Detect Vite in project.
1386
1006
  *
1387
1007
  * @param projectPath - Project directory path
1388
1008
  * @param packageJson - Optional pre-loaded package.json
1389
1009
  * @returns Detection result or null if not detected
1010
+ *
1011
+ * @example Detecting Vite build tool
1012
+ * ```typescript
1013
+ * const result = viteDetector('/path/to/project', {
1014
+ * name: 'my-app',
1015
+ * devDependencies: {
1016
+ * 'vite': '^5.0.0',
1017
+ * '@vitejs/plugin-react': '^4.0.0',
1018
+ * 'vitest': '^1.0.0'
1019
+ * }
1020
+ * })
1021
+ * // => {
1022
+ * // id: 'vite',
1023
+ * // name: 'Vite',
1024
+ * // version: '5.0.0',
1025
+ * // confidence: 80,
1026
+ * // detectedFrom: [
1027
+ * // { type: 'package.json', field: 'dependencies.vite' },
1028
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1029
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1030
+ * // ]
1031
+ * // }
1032
+ * ```
1390
1033
  */
1391
- function babelDetector(projectPath, packageJson) {
1034
+ function viteDetector(projectPath, packageJson) {
1392
1035
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1393
1036
  const sources = [];
1394
1037
  let confidence = 0;
1395
1038
  let version;
1396
1039
  const deps = collectAllDependencies(pkg);
1397
- if (deps['@babel/core']) {
1398
- confidence += 50;
1399
- version = parseVersionString(deps['@babel/core']);
1400
- sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1040
+ if (deps['vite']) {
1041
+ confidence += 60;
1042
+ version = parseVersionString(deps['vite']);
1043
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
1401
1044
  }
1402
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1045
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1403
1046
  if (configPath) {
1404
- confidence += 40;
1047
+ confidence += 35;
1405
1048
  sources.push({ type: 'config-file', path: configPath });
1406
1049
  }
1407
- if (pkg && 'babel' in pkg) {
1408
- confidence += 30;
1409
- sources.push({ type: 'package.json', field: 'babel' });
1050
+ if (deps['vitest']) {
1051
+ confidence += 10;
1052
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1410
1053
  }
1411
- const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1412
- if (babelPackages.length > 1) {
1054
+ const vitePlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1055
+ if (vitePlugins.length > 0) {
1413
1056
  confidence += 10;
1414
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1057
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1415
1058
  }
1416
1059
  if (confidence === 0) {
1417
1060
  return null;
1418
1061
  }
1419
1062
  return {
1420
- id: 'babel',
1421
- name: 'Babel',
1063
+ id: 'vite',
1064
+ name: 'Vite',
1422
1065
  version,
1423
1066
  configPath,
1424
- confidence: min(confidence, 100),
1067
+ confidence: index_cjs_js$8.min(confidence, 100),
1425
1068
  detectedFrom: sources,
1426
1069
  };
1427
1070
  }
1428
1071
 
1429
- /** Config patterns for SWC */
1430
- const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1072
+ /** Config patterns for Webpack */
1073
+ const WEBPACK_CONFIG_PATTERNS = [
1074
+ 'webpack.config.js',
1075
+ 'webpack.config.ts',
1076
+ 'webpack.config.cjs',
1077
+ 'webpack.config.mjs',
1078
+ 'webpack.config.babel.js',
1079
+ ];
1431
1080
  /**
1432
- * Detect SWC in project.
1081
+ * Detect Webpack in project.
1433
1082
  *
1434
1083
  * @param projectPath - Project directory path
1435
1084
  * @param packageJson - Optional pre-loaded package.json
1436
1085
  * @returns Detection result or null if not detected
1086
+ *
1087
+ * @example Detecting Webpack bundler
1088
+ * ```typescript
1089
+ * const result = webpackDetector('/path/to/project', {
1090
+ * name: 'my-app',
1091
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1092
+ * scripts: { 'build': 'webpack --mode production' }
1093
+ * })
1094
+ * // => {
1095
+ * // id: 'webpack',
1096
+ * // name: 'Webpack',
1097
+ * // version: '5.89.0',
1098
+ * // confidence: 65,
1099
+ * // detectedFrom: [
1100
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1101
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1102
+ * // { type: 'package.json', field: 'scripts.build' }
1103
+ * // ]
1104
+ * // }
1105
+ * ```
1437
1106
  */
1438
- function swcDetector(projectPath, packageJson) {
1107
+ function webpackDetector(projectPath, packageJson) {
1439
1108
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1440
1109
  const sources = [];
1441
1110
  let confidence = 0;
1442
1111
  let version;
1443
1112
  const deps = collectAllDependencies(pkg);
1444
- if (deps['@swc/core']) {
1445
- confidence += 60;
1446
- version = parseVersionString(deps['@swc/core']);
1447
- sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1113
+ if (deps['webpack']) {
1114
+ confidence += 50;
1115
+ version = parseVersionString(deps['webpack']);
1116
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1448
1117
  }
1449
- const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1118
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1450
1119
  if (configPath) {
1451
- confidence += 35;
1120
+ confidence += 40;
1452
1121
  sources.push({ type: 'config-file', path: configPath });
1453
1122
  }
1454
- if (deps['@swc/cli']) {
1123
+ if (deps['webpack-cli']) {
1455
1124
  confidence += 10;
1456
- sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1125
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1457
1126
  }
1458
- const swcPlugins = keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1459
- if (swcPlugins.length > 1) {
1460
- confidence += 5;
1461
- sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1127
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1128
+ for (const name of scriptMatches) {
1129
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1130
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1462
1131
  }
1463
1132
  if (confidence === 0) {
1464
1133
  return null;
1465
1134
  }
1466
1135
  return {
1467
- id: 'swc',
1468
- name: 'SWC',
1136
+ id: 'webpack',
1137
+ name: 'Webpack',
1469
1138
  version,
1470
1139
  configPath,
1471
- confidence: min(confidence, 100),
1140
+ confidence: index_cjs_js$8.min(confidence, 100),
1472
1141
  detectedFrom: sources,
1473
1142
  };
1474
1143
  }
1475
1144
 
1476
- /** Config patterns for Parcel */
1477
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1145
+ /** All build tool detectors */
1146
+ const buildToolDetectors = [
1147
+ { id: 'webpack', name: 'Webpack', detect: webpackDetector },
1148
+ { id: 'vite', name: 'Vite', detect: viteDetector },
1149
+ { id: 'rollup', name: 'Rollup', detect: rollupDetector },
1150
+ { id: 'esbuild', name: 'esbuild', detect: esbuildDetector },
1151
+ { id: 'babel', name: 'Babel', detect: babelDetector },
1152
+ { id: 'swc', name: 'SWC', detect: swcDetector },
1153
+ { id: 'parcel', name: 'Parcel', detect: parcelDetector },
1154
+ ];
1155
+
1478
1156
  /**
1479
- * Detect Parcel in project.
1157
+ * Detect Angular in project.
1480
1158
  *
1481
1159
  * @param projectPath - Project directory path
1482
1160
  * @param packageJson - Optional pre-loaded package.json
1483
1161
  * @returns Detection result or null if not detected
1162
+ *
1163
+ * @example Detecting Angular framework
1164
+ * ```typescript
1165
+ * const result = angularDetector('/path/to/angular-app', {
1166
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1167
+ * })
1168
+ * // => {
1169
+ * // id: 'angular',
1170
+ * // name: 'Angular',
1171
+ * // category: 'frontend',
1172
+ * // version: '17.0.0',
1173
+ * // confidence: 85,
1174
+ * // detectedFrom: [
1175
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1176
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1177
+ * // ]
1178
+ * // }
1179
+ * ```
1484
1180
  */
1485
- function parcelDetector(projectPath, packageJson) {
1181
+ function angularDetector(projectPath, packageJson) {
1486
1182
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1487
1183
  const sources = [];
1488
1184
  let confidence = 0;
1489
1185
  let version;
1490
1186
  const deps = collectAllDependencies(pkg);
1491
- if (deps['parcel']) {
1492
- confidence += 60;
1493
- version = parseVersionString(deps['parcel']);
1494
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1187
+ if (deps['@angular/core']) {
1188
+ confidence += 70;
1189
+ version = parseVersionString(deps['@angular/core']);
1190
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1495
1191
  }
1496
- if (deps['parcel-bundler']) {
1497
- confidence += 60;
1498
- version = parseVersionString(deps['parcel-bundler']);
1499
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1192
+ if (deps['@angular/cli']) {
1193
+ confidence += 15;
1194
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1500
1195
  }
1501
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1502
- if (configPath) {
1503
- confidence += 30;
1504
- sources.push({ type: 'config-file', path: configPath });
1196
+ if (exists(node_path.join(projectPath, 'angular.json'))) {
1197
+ confidence += 15;
1198
+ sources.push({ type: 'config-file', path: 'angular.json' });
1505
1199
  }
1506
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1507
- for (const name of scriptMatches) {
1508
- confidence = min(confidence + 10, 100);
1509
- sources.push({ type: 'package.json', field: `scripts.${name}` });
1200
+ if (deps['angular'] && !deps['@angular/core']) {
1201
+ return {
1202
+ id: 'angularjs',
1203
+ name: 'AngularJS (Legacy)',
1204
+ category: 'frontend',
1205
+ version: parseVersionString(deps['angular']),
1206
+ confidence: 80,
1207
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1208
+ };
1510
1209
  }
1511
1210
  if (confidence === 0) {
1512
1211
  return null;
1513
1212
  }
1514
1213
  return {
1515
- id: 'parcel',
1516
- name: 'Parcel',
1214
+ id: 'angular',
1215
+ name: 'Angular',
1216
+ category: 'frontend',
1517
1217
  version,
1518
- configPath,
1519
- confidence: min(confidence, 100),
1218
+ confidence: index_cjs_js$8.min(confidence, 100),
1520
1219
  detectedFrom: sources,
1521
1220
  };
1522
1221
  }
1523
1222
 
1524
- /** All build tool detectors */
1525
- const buildToolDetectors = [
1526
- { id: 'webpack', name: 'Webpack', detect: webpackDetector },
1527
- { id: 'vite', name: 'Vite', detect: viteDetector },
1528
- { id: 'rollup', name: 'Rollup', detect: rollupDetector },
1529
- { id: 'esbuild', name: 'esbuild', detect: esbuildDetector },
1530
- { id: 'babel', name: 'Babel', detect: babelDetector },
1531
- { id: 'swc', name: 'SWC', detect: swcDetector },
1532
- { id: 'parcel', name: 'Parcel', detect: parcelDetector },
1533
- ];
1534
-
1535
1223
  /**
1536
- * Detect React in project.
1224
+ * Detect Astro in project.
1537
1225
  *
1538
1226
  * @param projectPath - Project directory path
1539
1227
  * @param packageJson - Optional pre-loaded package.json
1540
1228
  * @returns Detection result or null if not detected
1229
+ *
1230
+ * @example Detecting Astro framework
1231
+ * ```typescript
1232
+ * const result = astroDetector('/path/to/astro-project', {
1233
+ * dependencies: { 'astro': '^4.0.0' }
1234
+ * })
1235
+ * // => {
1236
+ * // id: 'astro',
1237
+ * // name: 'Astro',
1238
+ * // category: 'meta-framework',
1239
+ * // version: '4.0.0',
1240
+ * // confidence: 70,
1241
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1242
+ * // }
1243
+ * ```
1541
1244
  */
1542
- function reactDetector(projectPath, packageJson) {
1245
+ function astroDetector(projectPath, packageJson) {
1543
1246
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1544
1247
  const sources = [];
1545
1248
  let confidence = 0;
1546
1249
  let version;
1547
- const metaFrameworks = [];
1548
1250
  const deps = collectAllDependencies(pkg);
1549
- if (deps['react']) {
1550
- confidence += 60;
1551
- version = parseVersionString(deps['react']);
1552
- sources.push({ type: 'package.json', field: 'dependencies.react' });
1553
- }
1554
- if (deps['react-dom']) {
1555
- confidence += 20;
1556
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1251
+ if (deps['astro']) {
1252
+ confidence += 70;
1253
+ version = parseVersionString(deps['astro']);
1254
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1557
1255
  }
1558
- if (deps['react-native']) {
1559
- confidence += 20;
1560
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1256
+ if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
1257
+ exists(node_path.join(projectPath, 'astro.config.ts')) ||
1258
+ exists(node_path.join(projectPath, 'astro.config.js'))) {
1259
+ confidence += 25;
1260
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
1561
1261
  }
1562
- const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1563
- exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1564
- exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1565
- exists(node_path.join(projectPath, 'src', 'index.jsx'));
1566
- if (hasJsxFiles) {
1567
- confidence += 10;
1568
- sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1262
+ if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1263
+ confidence += 5;
1264
+ sources.push({ type: 'directory', path: 'src/pages/' });
1569
1265
  }
1570
- if (deps['next']) {
1571
- metaFrameworks.push({
1572
- id: 'nextjs',
1573
- name: 'Next.js',
1574
- category: 'meta-framework',
1575
- version: parseVersionString(deps['next']),
1576
- confidence: 90,
1577
- detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1578
- });
1266
+ if (confidence === 0) {
1267
+ return null;
1579
1268
  }
1269
+ return {
1270
+ id: 'astro',
1271
+ name: 'Astro',
1272
+ category: 'meta-framework',
1273
+ version,
1274
+ confidence: index_cjs_js$8.min(confidence, 100),
1275
+ detectedFrom: sources,
1276
+ };
1277
+ }
1278
+
1279
+ /**
1280
+ * Detect Gatsby in project.
1281
+ *
1282
+ * @param projectPath - Project directory path
1283
+ * @param packageJson - Optional pre-loaded package.json
1284
+ * @returns Detection result or null if not detected
1285
+ *
1286
+ * @example Detecting Gatsby framework
1287
+ * ```typescript
1288
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1289
+ * dependencies: {
1290
+ * 'gatsby': '^5.0.0',
1291
+ * 'gatsby-plugin-image': '^3.0.0',
1292
+ * 'gatsby-source-filesystem': '^5.0.0'
1293
+ * }
1294
+ * })
1295
+ * // => {
1296
+ * // id: 'gatsby',
1297
+ * // name: 'Gatsby',
1298
+ * // category: 'meta-framework',
1299
+ * // version: '5.0.0',
1300
+ * // confidence: 75,
1301
+ * // detectedFrom: [
1302
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1303
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1304
+ * // ]
1305
+ * // }
1306
+ * ```
1307
+ */
1308
+ function gatsbyDetector(projectPath, packageJson) {
1309
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1310
+ const sources = [];
1311
+ let confidence = 0;
1312
+ let version;
1313
+ const deps = collectAllDependencies(pkg);
1580
1314
  if (deps['gatsby']) {
1581
- metaFrameworks.push({
1582
- id: 'gatsby',
1583
- name: 'Gatsby',
1584
- category: 'meta-framework',
1585
- version: parseVersionString(deps['gatsby']),
1586
- confidence: 90,
1587
- detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1588
- });
1315
+ confidence += 70;
1316
+ version = parseVersionString(deps['gatsby']);
1317
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1589
1318
  }
1590
- if (deps['@remix-run/react'] || deps['remix']) {
1591
- metaFrameworks.push({
1592
- id: 'remix',
1593
- name: 'Remix',
1594
- category: 'meta-framework',
1595
- version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1596
- confidence: 90,
1597
- detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1598
- });
1319
+ if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1320
+ confidence += 25;
1321
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1322
+ }
1323
+ const gatsbyPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1324
+ if (gatsbyPlugins.length > 0) {
1325
+ confidence += 5;
1326
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1599
1327
  }
1600
1328
  if (confidence === 0) {
1601
1329
  return null;
1602
1330
  }
1603
1331
  return {
1604
- id: 'react',
1605
- name: 'React',
1606
- category: 'frontend',
1332
+ id: 'gatsby',
1333
+ name: 'Gatsby',
1334
+ category: 'meta-framework',
1607
1335
  version,
1608
- confidence: min(confidence, 100),
1336
+ confidence: index_cjs_js$8.min(confidence, 100),
1609
1337
  detectedFrom: sources,
1610
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1611
1338
  };
1612
1339
  }
1613
1340
 
@@ -1617,6 +1344,21 @@ function reactDetector(projectPath, packageJson) {
1617
1344
  * @param projectPath - Project directory path
1618
1345
  * @param packageJson - Optional pre-loaded package.json
1619
1346
  * @returns Detection result or null if not detected
1347
+ *
1348
+ * @example Detecting Next.js framework
1349
+ * ```typescript
1350
+ * const result = nextjsDetector('/path/to/nextjs-app', {
1351
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
1352
+ * })
1353
+ * // => {
1354
+ * // id: 'nextjs',
1355
+ * // name: 'Next.js',
1356
+ * // category: 'meta-framework',
1357
+ * // version: '14.0.0',
1358
+ * // confidence: 70,
1359
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
1360
+ * // }
1361
+ * ```
1620
1362
  */
1621
1363
  function nextjsDetector(projectPath, packageJson) {
1622
1364
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1650,230 +1392,335 @@ function nextjsDetector(projectPath, packageJson) {
1650
1392
  name: 'Next.js',
1651
1393
  category: 'meta-framework',
1652
1394
  version,
1653
- confidence: min(confidence, 100),
1395
+ confidence: index_cjs_js$8.min(confidence, 100),
1654
1396
  detectedFrom: sources,
1655
1397
  };
1656
1398
  }
1657
1399
 
1658
1400
  /**
1659
- * Detect Remix in project.
1401
+ * Detect Nuxt in project.
1660
1402
  *
1661
1403
  * @param projectPath - Project directory path
1662
1404
  * @param packageJson - Optional pre-loaded package.json
1663
1405
  * @returns Detection result or null if not detected
1406
+ *
1407
+ * @example Detecting Nuxt framework
1408
+ * ```typescript
1409
+ * const result = nuxtDetector('/path/to/nuxt-app', {
1410
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
1411
+ * })
1412
+ * // => {
1413
+ * // id: 'nuxt',
1414
+ * // name: 'Nuxt',
1415
+ * // category: 'meta-framework',
1416
+ * // version: '3.0.0',
1417
+ * // confidence: 70,
1418
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
1419
+ * // }
1420
+ * ```
1664
1421
  */
1665
- function remixDetector(projectPath, packageJson) {
1422
+ function nuxtDetector(projectPath, packageJson) {
1666
1423
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1667
1424
  const sources = [];
1668
1425
  let confidence = 0;
1669
1426
  let version;
1670
1427
  const deps = collectAllDependencies(pkg);
1671
- if (deps['@remix-run/react']) {
1428
+ if (deps['nuxt'] || deps['nuxt3']) {
1672
1429
  confidence += 70;
1673
- version = parseVersionString(deps['@remix-run/react']);
1674
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1430
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1431
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1675
1432
  }
1676
- if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1677
- confidence += 20;
1678
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1433
+ if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1434
+ confidence += 25;
1435
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1679
1436
  }
1680
- if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1681
- confidence += 10;
1682
- sources.push({ type: 'config-file', path: 'remix.config.*' });
1437
+ if (exists(node_path.join(projectPath, 'pages'))) {
1438
+ confidence += 5;
1439
+ sources.push({ type: 'directory', path: 'pages/' });
1683
1440
  }
1684
1441
  if (confidence === 0) {
1685
1442
  return null;
1686
1443
  }
1687
1444
  return {
1688
- id: 'remix',
1689
- name: 'Remix',
1445
+ id: 'nuxt',
1446
+ name: 'Nuxt',
1690
1447
  category: 'meta-framework',
1691
1448
  version,
1692
- confidence: min(confidence, 100),
1449
+ confidence: index_cjs_js$8.min(confidence, 100),
1693
1450
  detectedFrom: sources,
1694
1451
  };
1695
1452
  }
1696
1453
 
1697
1454
  /**
1698
- * Detect Gatsby in project.
1455
+ * Detect Qwik in project.
1699
1456
  *
1700
1457
  * @param projectPath - Project directory path
1701
1458
  * @param packageJson - Optional pre-loaded package.json
1702
1459
  * @returns Detection result or null if not detected
1460
+ *
1461
+ * @example Detecting Qwik framework
1462
+ * ```typescript
1463
+ * const result = qwikDetector('/path/to/qwik-app', {
1464
+ * dependencies: {
1465
+ * '@builder.io/qwik': '^1.0.0',
1466
+ * '@builder.io/qwik-city': '^1.0.0'
1467
+ * }
1468
+ * })
1469
+ * // => {
1470
+ * // id: 'qwik',
1471
+ * // name: 'Qwik',
1472
+ * // category: 'frontend',
1473
+ * // version: '1.0.0',
1474
+ * // confidence: 90,
1475
+ * // detectedFrom: [
1476
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
1477
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
1478
+ * // ]
1479
+ * // }
1480
+ * ```
1703
1481
  */
1704
- function gatsbyDetector(projectPath, packageJson) {
1482
+ function qwikDetector(projectPath, packageJson) {
1705
1483
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1706
1484
  const sources = [];
1707
1485
  let confidence = 0;
1708
1486
  let version;
1709
1487
  const deps = collectAllDependencies(pkg);
1710
- if (deps['gatsby']) {
1488
+ if (deps['@builder.io/qwik']) {
1711
1489
  confidence += 70;
1712
- version = parseVersionString(deps['gatsby']);
1713
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1490
+ version = parseVersionString(deps['@builder.io/qwik']);
1491
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1714
1492
  }
1715
- if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1716
- confidence += 25;
1717
- sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1493
+ if (deps['@builder.io/qwik-city']) {
1494
+ confidence += 20;
1495
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1718
1496
  }
1719
- const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1720
- if (gatsbyPlugins.length > 0) {
1721
- confidence += 5;
1722
- sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1497
+ if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1498
+ confidence += 10;
1499
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
1723
1500
  }
1724
1501
  if (confidence === 0) {
1725
1502
  return null;
1726
1503
  }
1727
1504
  return {
1728
- id: 'gatsby',
1729
- name: 'Gatsby',
1730
- category: 'meta-framework',
1505
+ id: 'qwik',
1506
+ name: 'Qwik',
1507
+ category: 'frontend',
1731
1508
  version,
1732
- confidence: min(confidence, 100),
1509
+ confidence: index_cjs_js$8.min(confidence, 100),
1733
1510
  detectedFrom: sources,
1734
1511
  };
1735
1512
  }
1736
1513
 
1737
1514
  /**
1738
- * Detect Vue in project.
1515
+ * Detect React in project.
1739
1516
  *
1740
1517
  * @param projectPath - Project directory path
1741
1518
  * @param packageJson - Optional pre-loaded package.json
1742
1519
  * @returns Detection result or null if not detected
1520
+ *
1521
+ * @example Detecting React library
1522
+ * ```typescript
1523
+ * const result = reactDetector('/path/to/react-app', {
1524
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
1525
+ * })
1526
+ * // => {
1527
+ * // id: 'react',
1528
+ * // name: 'React',
1529
+ * // category: 'frontend',
1530
+ * // version: '18.0.0',
1531
+ * // confidence: 80,
1532
+ * // detectedFrom: [
1533
+ * // { type: 'package.json', field: 'dependencies.react' },
1534
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
1535
+ * // ]
1536
+ * // }
1537
+ * ```
1743
1538
  */
1744
- function vueDetector(projectPath, packageJson) {
1539
+ function reactDetector(projectPath, packageJson) {
1745
1540
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1746
1541
  const sources = [];
1747
1542
  let confidence = 0;
1748
1543
  let version;
1749
1544
  const metaFrameworks = [];
1750
1545
  const deps = collectAllDependencies(pkg);
1751
- if (deps['vue']) {
1752
- confidence += 70;
1753
- version = parseVersionString(deps['vue']);
1754
- sources.push({ type: 'package.json', field: 'dependencies.vue' });
1546
+ if (deps['react']) {
1547
+ confidence += 60;
1548
+ version = parseVersionString(deps['react']);
1549
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
1755
1550
  }
1756
- if (deps['@vue/cli-service']) {
1757
- confidence += 15;
1758
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
1551
+ if (deps['react-dom']) {
1552
+ confidence += 20;
1553
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1759
1554
  }
1760
- const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1761
- if (hasVueFiles) {
1555
+ if (deps['react-native']) {
1556
+ confidence += 20;
1557
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1558
+ }
1559
+ const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1560
+ exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1561
+ exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1562
+ exists(node_path.join(projectPath, 'src', 'index.jsx'));
1563
+ if (hasJsxFiles) {
1762
1564
  confidence += 10;
1763
- sources.push({ type: 'directory', path: 'src/*.vue' });
1565
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1764
1566
  }
1765
- if (exists(node_path.join(projectPath, 'vue.config.js'))) {
1766
- confidence += 5;
1767
- sources.push({ type: 'config-file', path: 'vue.config.js' });
1567
+ if (deps['next']) {
1568
+ metaFrameworks.push({
1569
+ id: 'nextjs',
1570
+ name: 'Next.js',
1571
+ category: 'meta-framework',
1572
+ version: parseVersionString(deps['next']),
1573
+ confidence: 90,
1574
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1575
+ });
1768
1576
  }
1769
- if (deps['nuxt'] || deps['nuxt3']) {
1577
+ if (deps['gatsby']) {
1770
1578
  metaFrameworks.push({
1771
- id: 'nuxt',
1772
- name: 'Nuxt',
1579
+ id: 'gatsby',
1580
+ name: 'Gatsby',
1773
1581
  category: 'meta-framework',
1774
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1582
+ version: parseVersionString(deps['gatsby']),
1775
1583
  confidence: 90,
1776
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1584
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1585
+ });
1586
+ }
1587
+ if (deps['@remix-run/react'] || deps['remix']) {
1588
+ metaFrameworks.push({
1589
+ id: 'remix',
1590
+ name: 'Remix',
1591
+ category: 'meta-framework',
1592
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1593
+ confidence: 90,
1594
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1777
1595
  });
1778
1596
  }
1779
1597
  if (confidence === 0) {
1780
1598
  return null;
1781
1599
  }
1782
1600
  return {
1783
- id: 'vue',
1784
- name: 'Vue',
1601
+ id: 'react',
1602
+ name: 'React',
1785
1603
  category: 'frontend',
1786
1604
  version,
1787
- confidence: min(confidence, 100),
1605
+ confidence: index_cjs_js$8.min(confidence, 100),
1788
1606
  detectedFrom: sources,
1789
1607
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1790
1608
  };
1791
1609
  }
1792
1610
 
1793
1611
  /**
1794
- * Detect Nuxt in project.
1612
+ * Detect Remix in project.
1795
1613
  *
1796
1614
  * @param projectPath - Project directory path
1797
1615
  * @param packageJson - Optional pre-loaded package.json
1798
1616
  * @returns Detection result or null if not detected
1617
+ *
1618
+ * @example Detecting Remix framework
1619
+ * ```typescript
1620
+ * const result = remixDetector('/path/to/remix-app', {
1621
+ * dependencies: {
1622
+ * '@remix-run/react': '^2.0.0',
1623
+ * '@remix-run/node': '^2.0.0'
1624
+ * }
1625
+ * })
1626
+ * // => {
1627
+ * // id: 'remix',
1628
+ * // name: 'Remix',
1629
+ * // category: 'meta-framework',
1630
+ * // version: '2.0.0',
1631
+ * // confidence: 90,
1632
+ * // detectedFrom: [
1633
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
1634
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
1635
+ * // ]
1636
+ * // }
1637
+ * ```
1799
1638
  */
1800
- function nuxtDetector(projectPath, packageJson) {
1639
+ function remixDetector(projectPath, packageJson) {
1801
1640
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1802
1641
  const sources = [];
1803
1642
  let confidence = 0;
1804
1643
  let version;
1805
1644
  const deps = collectAllDependencies(pkg);
1806
- if (deps['nuxt'] || deps['nuxt3']) {
1645
+ if (deps['@remix-run/react']) {
1807
1646
  confidence += 70;
1808
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1809
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1647
+ version = parseVersionString(deps['@remix-run/react']);
1648
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1810
1649
  }
1811
- if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1812
- confidence += 25;
1813
- sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1650
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1651
+ confidence += 20;
1652
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1814
1653
  }
1815
- if (exists(node_path.join(projectPath, 'pages'))) {
1816
- confidence += 5;
1817
- sources.push({ type: 'directory', path: 'pages/' });
1654
+ if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1655
+ confidence += 10;
1656
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
1818
1657
  }
1819
1658
  if (confidence === 0) {
1820
1659
  return null;
1821
1660
  }
1822
1661
  return {
1823
- id: 'nuxt',
1824
- name: 'Nuxt',
1662
+ id: 'remix',
1663
+ name: 'Remix',
1825
1664
  category: 'meta-framework',
1826
1665
  version,
1827
- confidence: min(confidence, 100),
1666
+ confidence: index_cjs_js$8.min(confidence, 100),
1828
1667
  detectedFrom: sources,
1829
1668
  };
1830
1669
  }
1831
1670
 
1832
1671
  /**
1833
- * Detect Angular in project.
1672
+ * Detect Solid in project.
1834
1673
  *
1835
1674
  * @param projectPath - Project directory path
1836
1675
  * @param packageJson - Optional pre-loaded package.json
1837
1676
  * @returns Detection result or null if not detected
1677
+ *
1678
+ * @example Detecting Solid.js framework
1679
+ * ```typescript
1680
+ * const result = solidDetector('/path/to/solid-app', {
1681
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
1682
+ * })
1683
+ * // => {
1684
+ * // id: 'solid',
1685
+ * // name: 'Solid',
1686
+ * // category: 'frontend',
1687
+ * // version: '1.8.0',
1688
+ * // confidence: 90,
1689
+ * // detectedFrom: [
1690
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
1691
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
1692
+ * // ]
1693
+ * // }
1694
+ * ```
1838
1695
  */
1839
- function angularDetector(projectPath, packageJson) {
1696
+ function solidDetector(projectPath, packageJson) {
1840
1697
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1841
1698
  const sources = [];
1842
1699
  let confidence = 0;
1843
1700
  let version;
1844
1701
  const deps = collectAllDependencies(pkg);
1845
- if (deps['@angular/core']) {
1702
+ if (deps['solid-js']) {
1846
1703
  confidence += 70;
1847
- version = parseVersionString(deps['@angular/core']);
1848
- sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1849
- }
1850
- if (deps['@angular/cli']) {
1851
- confidence += 15;
1852
- sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1704
+ version = parseVersionString(deps['solid-js']);
1705
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1853
1706
  }
1854
- if (exists(node_path.join(projectPath, 'angular.json'))) {
1855
- confidence += 15;
1856
- sources.push({ type: 'config-file', path: 'angular.json' });
1707
+ if (deps['vite-plugin-solid']) {
1708
+ confidence += 20;
1709
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1857
1710
  }
1858
- if (deps['angular'] && !deps['@angular/core']) {
1859
- return {
1860
- id: 'angularjs',
1861
- name: 'AngularJS (Legacy)',
1862
- category: 'frontend',
1863
- version: parseVersionString(deps['angular']),
1864
- confidence: 80,
1865
- detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1866
- };
1711
+ if (deps['solid-start'] || deps['@solidjs/start']) {
1712
+ confidence += 10;
1713
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1867
1714
  }
1868
1715
  if (confidence === 0) {
1869
1716
  return null;
1870
1717
  }
1871
1718
  return {
1872
- id: 'angular',
1873
- name: 'Angular',
1719
+ id: 'solid',
1720
+ name: 'Solid',
1874
1721
  category: 'frontend',
1875
1722
  version,
1876
- confidence: min(confidence, 100),
1723
+ confidence: index_cjs_js$8.min(confidence, 100),
1877
1724
  detectedFrom: sources,
1878
1725
  };
1879
1726
  }
@@ -1884,6 +1731,21 @@ function angularDetector(projectPath, packageJson) {
1884
1731
  * @param projectPath - Project directory path
1885
1732
  * @param packageJson - Optional pre-loaded package.json
1886
1733
  * @returns Detection result or null if not detected
1734
+ *
1735
+ * @example Detecting Svelte framework
1736
+ * ```typescript
1737
+ * const result = svelteDetector('/path/to/svelte-app', {
1738
+ * devDependencies: { 'svelte': '^4.0.0' }
1739
+ * })
1740
+ * // => {
1741
+ * // id: 'svelte',
1742
+ * // name: 'Svelte',
1743
+ * // category: 'frontend',
1744
+ * // version: '4.0.0',
1745
+ * // confidence: 70,
1746
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
1747
+ * // }
1748
+ * ```
1887
1749
  */
1888
1750
  function svelteDetector(projectPath, packageJson) {
1889
1751
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1924,7 +1786,7 @@ function svelteDetector(projectPath, packageJson) {
1924
1786
  name: 'Svelte',
1925
1787
  category: 'frontend',
1926
1788
  version,
1927
- confidence: min(confidence, 100),
1789
+ confidence: index_cjs_js$8.min(confidence, 100),
1928
1790
  detectedFrom: sources,
1929
1791
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1930
1792
  };
@@ -1936,6 +1798,21 @@ function svelteDetector(projectPath, packageJson) {
1936
1798
  * @param projectPath - Project directory path
1937
1799
  * @param packageJson - Optional pre-loaded package.json
1938
1800
  * @returns Detection result or null if not detected
1801
+ *
1802
+ * @example Detecting SvelteKit framework
1803
+ * ```typescript
1804
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
1805
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
1806
+ * })
1807
+ * // => {
1808
+ * // id: 'sveltekit',
1809
+ * // name: 'SvelteKit',
1810
+ * // category: 'meta-framework',
1811
+ * // version: '2.0.0',
1812
+ * // confidence: 70,
1813
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
1814
+ * // }
1815
+ * ```
1939
1816
  */
1940
1817
  function sveltekitDetector(projectPath, packageJson) {
1941
1818
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1964,127 +1841,82 @@ function sveltekitDetector(projectPath, packageJson) {
1964
1841
  name: 'SvelteKit',
1965
1842
  category: 'meta-framework',
1966
1843
  version,
1967
- confidence: min(confidence, 100),
1844
+ confidence: index_cjs_js$8.min(confidence, 100),
1968
1845
  detectedFrom: sources,
1969
1846
  };
1970
1847
  }
1971
1848
 
1972
1849
  /**
1973
- * Detect Solid in project.
1850
+ * Detect Vue in project.
1974
1851
  *
1975
1852
  * @param projectPath - Project directory path
1976
1853
  * @param packageJson - Optional pre-loaded package.json
1977
1854
  * @returns Detection result or null if not detected
1978
- */
1979
- function solidDetector(projectPath, packageJson) {
1980
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1981
- const sources = [];
1982
- let confidence = 0;
1983
- let version;
1984
- const deps = collectAllDependencies(pkg);
1985
- if (deps['solid-js']) {
1986
- confidence += 70;
1987
- version = parseVersionString(deps['solid-js']);
1988
- sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1989
- }
1990
- if (deps['vite-plugin-solid']) {
1991
- confidence += 20;
1992
- sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1993
- }
1994
- if (deps['solid-start'] || deps['@solidjs/start']) {
1995
- confidence += 10;
1996
- sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1997
- }
1998
- if (confidence === 0) {
1999
- return null;
2000
- }
2001
- return {
2002
- id: 'solid',
2003
- name: 'Solid',
2004
- category: 'frontend',
2005
- version,
2006
- confidence: min(confidence, 100),
2007
- detectedFrom: sources,
2008
- };
2009
- }
2010
-
2011
- /**
2012
- * Detect Qwik in project.
2013
1855
  *
2014
- * @param projectPath - Project directory path
2015
- * @param packageJson - Optional pre-loaded package.json
2016
- * @returns Detection result or null if not detected
1856
+ * @example Detecting Vue.js framework
1857
+ * ```typescript
1858
+ * const result = vueDetector('/path/to/vue-app', {
1859
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
1860
+ * })
1861
+ * // => {
1862
+ * // id: 'vue',
1863
+ * // name: 'Vue',
1864
+ * // category: 'frontend',
1865
+ * // version: '3.0.0',
1866
+ * // confidence: 85,
1867
+ * // detectedFrom: [
1868
+ * // { type: 'package.json', field: 'dependencies.vue' },
1869
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
1870
+ * // ]
1871
+ * // }
1872
+ * ```
2017
1873
  */
2018
- function qwikDetector(projectPath, packageJson) {
1874
+ function vueDetector(projectPath, packageJson) {
2019
1875
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2020
1876
  const sources = [];
2021
1877
  let confidence = 0;
2022
1878
  let version;
1879
+ const metaFrameworks = [];
2023
1880
  const deps = collectAllDependencies(pkg);
2024
- if (deps['@builder.io/qwik']) {
1881
+ if (deps['vue']) {
2025
1882
  confidence += 70;
2026
- version = parseVersionString(deps['@builder.io/qwik']);
2027
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1883
+ version = parseVersionString(deps['vue']);
1884
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2028
1885
  }
2029
- if (deps['@builder.io/qwik-city']) {
2030
- confidence += 20;
2031
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1886
+ if (deps['@vue/cli-service']) {
1887
+ confidence += 15;
1888
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2032
1889
  }
2033
- if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1890
+ const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1891
+ if (hasVueFiles) {
2034
1892
  confidence += 10;
2035
- sources.push({ type: 'config-file', path: 'qwik.config.*' });
2036
- }
2037
- if (confidence === 0) {
2038
- return null;
2039
- }
2040
- return {
2041
- id: 'qwik',
2042
- name: 'Qwik',
2043
- category: 'frontend',
2044
- version,
2045
- confidence: min(confidence, 100),
2046
- detectedFrom: sources,
2047
- };
2048
- }
2049
-
2050
- /**
2051
- * Detect Astro in project.
2052
- *
2053
- * @param projectPath - Project directory path
2054
- * @param packageJson - Optional pre-loaded package.json
2055
- * @returns Detection result or null if not detected
2056
- */
2057
- function astroDetector(projectPath, packageJson) {
2058
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2059
- const sources = [];
2060
- let confidence = 0;
2061
- let version;
2062
- const deps = collectAllDependencies(pkg);
2063
- if (deps['astro']) {
2064
- confidence += 70;
2065
- version = parseVersionString(deps['astro']);
2066
- sources.push({ type: 'package.json', field: 'dependencies.astro' });
2067
- }
2068
- if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
2069
- exists(node_path.join(projectPath, 'astro.config.ts')) ||
2070
- exists(node_path.join(projectPath, 'astro.config.js'))) {
2071
- confidence += 25;
2072
- sources.push({ type: 'config-file', path: 'astro.config.*' });
1893
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2073
1894
  }
2074
- if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1895
+ if (exists(node_path.join(projectPath, 'vue.config.js'))) {
2075
1896
  confidence += 5;
2076
- sources.push({ type: 'directory', path: 'src/pages/' });
1897
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
1898
+ }
1899
+ if (deps['nuxt'] || deps['nuxt3']) {
1900
+ metaFrameworks.push({
1901
+ id: 'nuxt',
1902
+ name: 'Nuxt',
1903
+ category: 'meta-framework',
1904
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1905
+ confidence: 90,
1906
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1907
+ });
2077
1908
  }
2078
1909
  if (confidence === 0) {
2079
1910
  return null;
2080
1911
  }
2081
1912
  return {
2082
- id: 'astro',
2083
- name: 'Astro',
2084
- category: 'meta-framework',
1913
+ id: 'vue',
1914
+ name: 'Vue',
1915
+ category: 'frontend',
2085
1916
  version,
2086
- confidence: min(confidence, 100),
1917
+ confidence: index_cjs_js$8.min(confidence, 100),
2087
1918
  detectedFrom: sources,
1919
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2088
1920
  };
2089
1921
  }
2090
1922
 
@@ -2111,6 +1943,14 @@ const frameworkDetectors = [
2111
1943
  * @param projectPath - Project directory path
2112
1944
  * @param packageJson - Optional pre-loaded package.json
2113
1945
  * @returns Detection result or null if not detected
1946
+ *
1947
+ * @example Detecting AngularJS framework
1948
+ * ```typescript
1949
+ * const result = angularJSDetector('/path/to/project', {
1950
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
1951
+ * })
1952
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
1953
+ * ```
2114
1954
  */
2115
1955
  function angularJSDetector(projectPath, packageJson) {
2116
1956
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2143,7 +1983,7 @@ function angularJSDetector(projectPath, packageJson) {
2143
1983
  name: 'AngularJS',
2144
1984
  category: 'legacy-frontend',
2145
1985
  version,
2146
- confidence: min(confidence, 100),
1986
+ confidence: index_cjs_js$8.min(confidence, 100),
2147
1987
  detectedFrom: sources,
2148
1988
  };
2149
1989
  }
@@ -2154,6 +1994,14 @@ function angularJSDetector(projectPath, packageJson) {
2154
1994
  * @param projectPath - Project directory path
2155
1995
  * @param packageJson - Optional pre-loaded package.json
2156
1996
  * @returns Detection result or null if not detected
1997
+ *
1998
+ * @example Detecting Backbone.js framework
1999
+ * ```typescript
2000
+ * const result = backboneDetector('/path/to/project', {
2001
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2002
+ * })
2003
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2004
+ * ```
2157
2005
  */
2158
2006
  function backboneDetector(projectPath, packageJson) {
2159
2007
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2186,7 +2034,7 @@ function backboneDetector(projectPath, packageJson) {
2186
2034
  name: 'Backbone.js',
2187
2035
  category: 'legacy-frontend',
2188
2036
  version,
2189
- confidence: min(confidence, 100),
2037
+ confidence: index_cjs_js$8.min(confidence, 100),
2190
2038
  detectedFrom: sources,
2191
2039
  };
2192
2040
  }
@@ -2197,6 +2045,15 @@ function backboneDetector(projectPath, packageJson) {
2197
2045
  * @param projectPath - Project directory path
2198
2046
  * @param packageJson - Optional pre-loaded package.json
2199
2047
  * @returns Detection result or null if not detected
2048
+ *
2049
+ * @example Detecting Ember.js framework
2050
+ * ```typescript
2051
+ * const result = emberDetector('/path/to/project', {
2052
+ * dependencies: { 'ember-source': '^4.0.0' },
2053
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2054
+ * })
2055
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2056
+ * ```
2200
2057
  */
2201
2058
  function emberDetector(projectPath, packageJson) {
2202
2059
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2225,7 +2082,7 @@ function emberDetector(projectPath, packageJson) {
2225
2082
  name: 'Ember.js',
2226
2083
  category: 'legacy-frontend',
2227
2084
  version,
2228
- confidence: min(confidence, 100),
2085
+ confidence: index_cjs_js$8.min(confidence, 100),
2229
2086
  detectedFrom: sources,
2230
2087
  };
2231
2088
  }
@@ -2236,47 +2093,105 @@ function emberDetector(projectPath, packageJson) {
2236
2093
  * @param projectPath - Project directory path
2237
2094
  * @param packageJson - Optional pre-loaded package.json
2238
2095
  * @returns Detection result or null if not detected
2096
+ *
2097
+ * @example Detecting jQuery library
2098
+ * ```typescript
2099
+ * const result = jqueryDetector('/path/to/project', {
2100
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2101
+ * })
2102
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2103
+ * ```
2104
+ */
2105
+ function jqueryDetector(projectPath, packageJson) {
2106
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2107
+ const sources = [];
2108
+ let confidence = 0;
2109
+ let version;
2110
+ const deps = collectAllDependencies(pkg);
2111
+ if (deps['jquery']) {
2112
+ confidence += 80;
2113
+ version = parseVersionString(deps['jquery']);
2114
+ sources.push({ type: 'package.json', field: 'dependencies.jquery' });
2115
+ }
2116
+ if (deps['jquery-ui']) {
2117
+ confidence += 10;
2118
+ sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
2119
+ }
2120
+ if (deps['jquery-validation']) {
2121
+ confidence += 5;
2122
+ sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
2123
+ }
2124
+ if (confidence === 0) {
2125
+ return null;
2126
+ }
2127
+ return {
2128
+ id: 'jquery',
2129
+ name: 'jQuery',
2130
+ category: 'legacy-frontend',
2131
+ version,
2132
+ confidence: index_cjs_js$8.min(confidence, 100),
2133
+ detectedFrom: sources,
2134
+ };
2135
+ }
2136
+
2137
+ /** All legacy framework detectors */
2138
+ const legacyDetectors = [
2139
+ { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2140
+ { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2141
+ { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2142
+ { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2143
+ ];
2144
+
2145
+ /**
2146
+ * Detect Biome in project.
2147
+ *
2148
+ * @param projectPath - Project directory path
2149
+ * @param packageJson - Optional pre-loaded package.json
2150
+ * @returns Detection result or null if not detected
2151
+ *
2152
+ * @example Detecting Biome linter
2153
+ * ```typescript
2154
+ * const result = biomeDetector('/path/to/project', {
2155
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2156
+ * })
2157
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2158
+ * ```
2239
2159
  */
2240
- function jqueryDetector(projectPath, packageJson) {
2160
+ function biomeDetector(projectPath, packageJson) {
2241
2161
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2242
2162
  const sources = [];
2243
2163
  let confidence = 0;
2164
+ let configPath;
2244
2165
  let version;
2245
2166
  const deps = collectAllDependencies(pkg);
2246
- if (deps['jquery']) {
2247
- confidence += 80;
2248
- version = parseVersionString(deps['jquery']);
2249
- sources.push({ type: 'package.json', field: 'dependencies.jquery' });
2167
+ if (deps['@biomejs/biome']) {
2168
+ confidence += 70;
2169
+ version = parseVersionString(deps['@biomejs/biome']);
2170
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2250
2171
  }
2251
- if (deps['jquery-ui']) {
2252
- confidence += 10;
2253
- sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
2172
+ if (exists(node_path.join(projectPath, 'biome.json'))) {
2173
+ confidence += 30;
2174
+ configPath = 'biome.json';
2175
+ sources.push({ type: 'config-file', path: 'biome.json' });
2254
2176
  }
2255
- if (deps['jquery-validation']) {
2256
- confidence += 5;
2257
- sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
2177
+ if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2178
+ confidence += 30;
2179
+ configPath = 'biome.jsonc';
2180
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2258
2181
  }
2259
2182
  if (confidence === 0) {
2260
2183
  return null;
2261
2184
  }
2262
2185
  return {
2263
- id: 'jquery',
2264
- name: 'jQuery',
2265
- category: 'legacy-frontend',
2186
+ id: 'biome',
2187
+ name: 'Biome',
2266
2188
  version,
2267
- confidence: min(confidence, 100),
2189
+ configPath,
2190
+ confidence: index_cjs_js$8.min(confidence, 100),
2268
2191
  detectedFrom: sources,
2269
2192
  };
2270
2193
  }
2271
2194
 
2272
- /** All legacy framework detectors */
2273
- const legacyDetectors = [
2274
- { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2275
- { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2276
- { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2277
- { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2278
- ];
2279
-
2280
2195
  /** Config patterns for ESLint */
2281
2196
  const ESLINT_CONFIG_PATTERNS = [
2282
2197
  'eslint.config.js',
@@ -2296,6 +2211,15 @@ const ESLINT_CONFIG_PATTERNS = [
2296
2211
  * @param projectPath - Project directory path
2297
2212
  * @param packageJson - Optional pre-loaded package.json
2298
2213
  * @returns Detection result or null if not detected
2214
+ *
2215
+ * @example Detecting ESLint linter
2216
+ * ```typescript
2217
+ * const result = eslintDetector('/path/to/project', {
2218
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2219
+ * scripts: { lint: 'eslint src/' },
2220
+ * })
2221
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2222
+ * ```
2299
2223
  */
2300
2224
  function eslintDetector(projectPath, packageJson) {
2301
2225
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2317,7 +2241,7 @@ function eslintDetector(projectPath, packageJson) {
2317
2241
  confidence += 30;
2318
2242
  sources.push({ type: 'package.json', field: 'eslintConfig' });
2319
2243
  }
2320
- const eslintPlugins = keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2244
+ const eslintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2321
2245
  if (eslintPlugins.length > 0) {
2322
2246
  confidence += 10;
2323
2247
  sources.push({ type: 'package.json', field: 'dependencies (eslint plugins)' });
@@ -2335,7 +2259,7 @@ function eslintDetector(projectPath, packageJson) {
2335
2259
  name: 'ESLint',
2336
2260
  version,
2337
2261
  configPath,
2338
- confidence: min(confidence, 100),
2262
+ confidence: index_cjs_js$8.min(confidence, 100),
2339
2263
  detectedFrom: sources,
2340
2264
  };
2341
2265
  }
@@ -2359,6 +2283,15 @@ const PRETTIER_CONFIG_PATTERNS = [
2359
2283
  * @param projectPath - Project directory path
2360
2284
  * @param packageJson - Optional pre-loaded package.json
2361
2285
  * @returns Detection result or null if not detected
2286
+ *
2287
+ * @example Detecting Prettier formatter
2288
+ * ```typescript
2289
+ * const result = prettierDetector('/path/to/project', {
2290
+ * devDependencies: { prettier: '^3.0.0' },
2291
+ * scripts: { format: 'prettier --write .' },
2292
+ * })
2293
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2294
+ * ```
2362
2295
  */
2363
2296
  function prettierDetector(projectPath, packageJson) {
2364
2297
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2384,7 +2317,7 @@ function prettierDetector(projectPath, packageJson) {
2384
2317
  confidence += 10;
2385
2318
  sources.push({ type: 'config-file', path: '.prettierignore' });
2386
2319
  }
2387
- const prettierPlugins = keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2320
+ const prettierPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2388
2321
  if (prettierPlugins.length > 0) {
2389
2322
  confidence += 5;
2390
2323
  sources.push({ type: 'package.json', field: 'dependencies (prettier plugins)' });
@@ -2402,7 +2335,7 @@ function prettierDetector(projectPath, packageJson) {
2402
2335
  name: 'Prettier',
2403
2336
  version,
2404
2337
  configPath,
2405
- confidence: min(confidence, 100),
2338
+ confidence: index_cjs_js$8.min(confidence, 100),
2406
2339
  detectedFrom: sources,
2407
2340
  };
2408
2341
  }
@@ -2421,6 +2354,14 @@ const STYLELINT_CONFIG_PATTERNS = [
2421
2354
  * @param projectPath - Project directory path
2422
2355
  * @param packageJson - Optional pre-loaded package.json
2423
2356
  * @returns Detection result or null if not detected
2357
+ *
2358
+ * @example Detecting Stylelint linter
2359
+ * ```typescript
2360
+ * const result = stylelintDetector('/path/to/project', {
2361
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
2362
+ * })
2363
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
2364
+ * ```
2424
2365
  */
2425
2366
  function stylelintDetector(projectPath, packageJson) {
2426
2367
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2442,7 +2383,7 @@ function stylelintDetector(projectPath, packageJson) {
2442
2383
  break;
2443
2384
  }
2444
2385
  }
2445
- const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
2386
+ const stylelintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('stylelint-'));
2446
2387
  if (stylelintPlugins.length > 0) {
2447
2388
  confidence += 5;
2448
2389
  sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
@@ -2455,49 +2396,7 @@ function stylelintDetector(projectPath, packageJson) {
2455
2396
  name: 'Stylelint',
2456
2397
  version,
2457
2398
  configPath,
2458
- confidence: min(confidence, 100),
2459
- detectedFrom: sources,
2460
- };
2461
- }
2462
-
2463
- /**
2464
- * Detect Biome in project.
2465
- *
2466
- * @param projectPath - Project directory path
2467
- * @param packageJson - Optional pre-loaded package.json
2468
- * @returns Detection result or null if not detected
2469
- */
2470
- function biomeDetector(projectPath, packageJson) {
2471
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2472
- const sources = [];
2473
- let confidence = 0;
2474
- let configPath;
2475
- let version;
2476
- const deps = collectAllDependencies(pkg);
2477
- if (deps['@biomejs/biome']) {
2478
- confidence += 70;
2479
- version = parseVersionString(deps['@biomejs/biome']);
2480
- sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2481
- }
2482
- if (exists(node_path.join(projectPath, 'biome.json'))) {
2483
- confidence += 30;
2484
- configPath = 'biome.json';
2485
- sources.push({ type: 'config-file', path: 'biome.json' });
2486
- }
2487
- if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2488
- confidence += 30;
2489
- configPath = 'biome.jsonc';
2490
- sources.push({ type: 'config-file', path: 'biome.jsonc' });
2491
- }
2492
- if (confidence === 0) {
2493
- return null;
2494
- }
2495
- return {
2496
- id: 'biome',
2497
- name: 'Biome',
2498
- version,
2499
- configPath,
2500
- confidence: min(confidence, 100),
2399
+ confidence: index_cjs_js$8.min(confidence, 100),
2501
2400
  detectedFrom: sources,
2502
2401
  };
2503
2402
  }
@@ -2511,140 +2410,179 @@ const lintingDetectors = [
2511
2410
  ];
2512
2411
 
2513
2412
  /**
2514
- * Detect NX in project.
2413
+ * Detect Lerna in project.
2515
2414
  *
2516
2415
  * @param workspacePath - Workspace directory path
2517
2416
  * @param packageJson - Optional pre-loaded package.json
2518
2417
  * @returns Detection result or null if not detected
2418
+ *
2419
+ * @example Detecting Lerna monorepo
2420
+ * ```typescript
2421
+ * // Project with lerna.json config file
2422
+ * const result = lernaDetector('/path/to/lerna-project')
2423
+ * // => {
2424
+ * // id: 'lerna',
2425
+ * // name: 'Lerna',
2426
+ * // confidence: 80,
2427
+ * // configPath: 'lerna.json',
2428
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
2429
+ * // }
2430
+ * ```
2519
2431
  */
2520
- function nxDetector(workspacePath, packageJson) {
2432
+ function lernaDetector(workspacePath, packageJson) {
2521
2433
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2522
2434
  const sources = [];
2523
2435
  let confidence = 0;
2524
2436
  let version;
2525
- let workspaceLayout;
2526
- const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2527
- if (exists(nxJsonPath)) {
2528
- confidence += 70;
2529
- sources.push({ type: 'config-file', path: 'nx.json' });
2437
+ let configPath;
2438
+ const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2439
+ if (exists(lernaJsonPath)) {
2440
+ confidence += 80;
2441
+ configPath = 'lerna.json';
2442
+ sources.push({ type: 'config-file', path: 'lerna.json' });
2530
2443
  }
2531
2444
  const deps = collectAllDependencies(pkg);
2532
- if (deps['nx']) {
2533
- confidence += 20;
2534
- version = parseVersionString(deps['nx']);
2535
- sources.push({ type: 'package.json', field: 'dependencies.nx' });
2536
- }
2537
- const hasApps = exists(node_path.join(workspacePath, 'apps'));
2538
- const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2539
- if (hasApps || hasLibs) {
2540
- confidence += 10;
2541
- sources.push({ type: 'directory', path: 'apps/ or libs/' });
2542
- workspaceLayout = {
2543
- appsDir: hasApps ? 'apps' : '',
2544
- libsDir: hasLibs ? 'libs' : '',
2545
- };
2445
+ if (deps['lerna']) {
2446
+ confidence += 15;
2447
+ version = parseVersionString(deps['lerna']);
2448
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2546
2449
  }
2547
- const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2548
- if (nxPackages.length > 0) {
2549
- confidence += 10;
2550
- sources.push({ type: 'package.json', field: '@nx/* packages' });
2450
+ if (exists(node_path.join(workspacePath, 'packages'))) {
2451
+ confidence += 5;
2452
+ sources.push({ type: 'directory', path: 'packages/' });
2551
2453
  }
2552
2454
  if (confidence === 0) {
2553
2455
  return null;
2554
2456
  }
2555
2457
  return {
2556
- id: 'nx',
2557
- name: 'NX',
2458
+ id: 'lerna',
2459
+ name: 'Lerna',
2558
2460
  version,
2559
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2560
- confidence: min(confidence, 100),
2461
+ configPath,
2462
+ confidence: index_cjs_js$8.min(confidence, 100),
2561
2463
  detectedFrom: sources,
2562
- workspaceLayout,
2563
2464
  };
2564
2465
  }
2565
2466
 
2566
2467
  /**
2567
- * Detect Turborepo in project.
2468
+ * Detect npm workspaces in project.
2568
2469
  *
2569
2470
  * @param workspacePath - Workspace directory path
2570
2471
  * @param packageJson - Optional pre-loaded package.json
2571
2472
  * @returns Detection result or null if not detected
2473
+ *
2474
+ * @example Detecting npm workspaces
2475
+ * ```typescript
2476
+ * // Project with workspaces in package.json and package-lock.json
2477
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
2478
+ * // => {
2479
+ * // id: 'npm-workspaces',
2480
+ * // name: 'npm Workspaces',
2481
+ * // confidence: 90,
2482
+ * // configPath: 'package.json',
2483
+ * // detectedFrom: [
2484
+ * // { type: 'package.json', field: 'workspaces' },
2485
+ * // { type: 'lockfile', path: 'package-lock.json' }
2486
+ * // ]
2487
+ * // }
2488
+ * ```
2572
2489
  */
2573
- function turborepoDetector(workspacePath, packageJson) {
2490
+ function npmWorkspacesDetector(workspacePath, packageJson) {
2574
2491
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2575
2492
  const sources = [];
2576
2493
  let confidence = 0;
2577
- let version;
2578
- let configPath;
2579
- const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2580
- if (exists(turboJsonPath)) {
2494
+ if (pkg?.workspaces) {
2581
2495
  confidence += 80;
2582
- configPath = 'turbo.json';
2583
- sources.push({ type: 'config-file', path: 'turbo.json' });
2496
+ sources.push({ type: 'package.json', field: 'workspaces' });
2584
2497
  }
2585
- const deps = collectAllDependencies(pkg);
2586
- if (deps['turbo']) {
2587
- confidence += 15;
2588
- version = parseVersionString(deps['turbo']);
2589
- sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2498
+ if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2499
+ confidence += 10;
2500
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
2590
2501
  }
2591
- const scripts = pkg?.scripts ?? {};
2592
- if (values(scripts).some((s) => s?.includes('turbo'))) {
2593
- confidence += 5;
2594
- sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2502
+ if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2503
+ return null;
2595
2504
  }
2596
2505
  if (confidence === 0) {
2597
2506
  return null;
2598
2507
  }
2599
2508
  return {
2600
- id: 'turborepo',
2601
- name: 'Turborepo',
2602
- version,
2603
- configPath,
2604
- confidence: min(confidence, 100),
2509
+ id: 'npm-workspaces',
2510
+ name: 'npm Workspaces',
2511
+ configPath: 'package.json',
2512
+ confidence: index_cjs_js$8.min(confidence, 100),
2605
2513
  detectedFrom: sources,
2606
2514
  };
2607
2515
  }
2608
2516
 
2609
2517
  /**
2610
- * Detect Lerna in project.
2518
+ * Detect NX in project.
2611
2519
  *
2612
2520
  * @param workspacePath - Workspace directory path
2613
2521
  * @param packageJson - Optional pre-loaded package.json
2614
2522
  * @returns Detection result or null if not detected
2523
+ *
2524
+ * @example Detecting NX workspace
2525
+ * ```typescript
2526
+ * // Project with nx.json and apps/libs directories
2527
+ * const result = nxDetector('/path/to/nx-workspace')
2528
+ * // => {
2529
+ * // id: 'nx',
2530
+ * // name: 'NX',
2531
+ * // confidence: 100,
2532
+ * // configPath: 'nx.json',
2533
+ * // version: '17.0.0',
2534
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
2535
+ * // detectedFrom: [
2536
+ * // { type: 'config-file', path: 'nx.json' },
2537
+ * // { type: 'package.json', field: 'dependencies.nx' },
2538
+ * // { type: 'directory', path: 'apps/ or libs/' }
2539
+ * // ]
2540
+ * // }
2541
+ * ```
2615
2542
  */
2616
- function lernaDetector(workspacePath, packageJson) {
2543
+ function nxDetector(workspacePath, packageJson) {
2617
2544
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2618
2545
  const sources = [];
2619
2546
  let confidence = 0;
2620
2547
  let version;
2621
- let configPath;
2622
- const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2623
- if (exists(lernaJsonPath)) {
2624
- confidence += 80;
2625
- configPath = 'lerna.json';
2626
- sources.push({ type: 'config-file', path: 'lerna.json' });
2548
+ let workspaceLayout;
2549
+ const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2550
+ if (exists(nxJsonPath)) {
2551
+ confidence += 70;
2552
+ sources.push({ type: 'config-file', path: 'nx.json' });
2627
2553
  }
2628
2554
  const deps = collectAllDependencies(pkg);
2629
- if (deps['lerna']) {
2630
- confidence += 15;
2631
- version = parseVersionString(deps['lerna']);
2632
- sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2555
+ if (deps['nx']) {
2556
+ confidence += 20;
2557
+ version = parseVersionString(deps['nx']);
2558
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
2633
2559
  }
2634
- if (exists(node_path.join(workspacePath, 'packages'))) {
2635
- confidence += 5;
2636
- sources.push({ type: 'directory', path: 'packages/' });
2560
+ const hasApps = exists(node_path.join(workspacePath, 'apps'));
2561
+ const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2562
+ if (hasApps || hasLibs) {
2563
+ confidence += 10;
2564
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
2565
+ workspaceLayout = {
2566
+ appsDir: hasApps ? 'apps' : '',
2567
+ libsDir: hasLibs ? 'libs' : '',
2568
+ };
2569
+ }
2570
+ const nxPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2571
+ if (nxPackages.length > 0) {
2572
+ confidence += 10;
2573
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
2637
2574
  }
2638
2575
  if (confidence === 0) {
2639
2576
  return null;
2640
2577
  }
2641
2578
  return {
2642
- id: 'lerna',
2643
- name: 'Lerna',
2579
+ id: 'nx',
2580
+ name: 'NX',
2644
2581
  version,
2645
- configPath,
2646
- confidence: min(confidence, 100),
2582
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2583
+ confidence: index_cjs_js$8.min(confidence, 100),
2647
2584
  detectedFrom: sources,
2585
+ workspaceLayout,
2648
2586
  };
2649
2587
  }
2650
2588
 
@@ -2654,6 +2592,19 @@ function lernaDetector(workspacePath, packageJson) {
2654
2592
  * @param workspacePath - Workspace directory path
2655
2593
  * @param packageJson - Optional pre-loaded package.json
2656
2594
  * @returns Detection result or null if not detected
2595
+ *
2596
+ * @example Detecting Rush monorepo
2597
+ * ```typescript
2598
+ * // Project with rush.json config file
2599
+ * const result = rushDetector('/path/to/rush-project')
2600
+ * // => {
2601
+ * // id: 'rush',
2602
+ * // name: 'Rush',
2603
+ * // confidence: 90,
2604
+ * // configPath: 'rush.json',
2605
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
2606
+ * // }
2607
+ * ```
2657
2608
  */
2658
2609
  function rushDetector(workspacePath, packageJson) {
2659
2610
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2682,76 +2633,70 @@ function rushDetector(workspacePath, packageJson) {
2682
2633
  }
2683
2634
  return {
2684
2635
  id: 'rush',
2685
- name: 'Rush',
2686
- version,
2687
- configPath,
2688
- confidence: min(confidence, 100),
2689
- detectedFrom: sources,
2690
- };
2691
- }
2692
-
2693
- /**
2694
- * Detect pnpm workspaces in project.
2695
- *
2696
- * @param workspacePath - Workspace directory path
2697
- * @returns Detection result or null if not detected
2698
- */
2699
- function pnpmWorkspacesDetector(workspacePath) {
2700
- const sources = [];
2701
- let confidence = 0;
2702
- let configPath;
2703
- const pnpmWorkspacePath = node_path.join(workspacePath, 'pnpm-workspace.yaml');
2704
- if (exists(pnpmWorkspacePath)) {
2705
- confidence += 90;
2706
- configPath = 'pnpm-workspace.yaml';
2707
- sources.push({ type: 'config-file', path: 'pnpm-workspace.yaml' });
2708
- }
2709
- if (exists(node_path.join(workspacePath, 'pnpm-lock.yaml'))) {
2710
- confidence += 10;
2711
- sources.push({ type: 'lockfile', path: 'pnpm-lock.yaml' });
2712
- }
2713
- if (confidence === 0) {
2714
- return null;
2715
- }
2716
- return {
2717
- id: 'pnpm-workspaces',
2718
- name: 'pnpm Workspaces',
2636
+ name: 'Rush',
2637
+ version,
2719
2638
  configPath,
2720
- confidence: min(confidence, 100),
2639
+ confidence: index_cjs_js$8.min(confidence, 100),
2721
2640
  detectedFrom: sources,
2722
2641
  };
2723
2642
  }
2724
2643
 
2725
2644
  /**
2726
- * Detect npm workspaces in project.
2645
+ * Detect Turborepo in project.
2727
2646
  *
2728
2647
  * @param workspacePath - Workspace directory path
2729
2648
  * @param packageJson - Optional pre-loaded package.json
2730
2649
  * @returns Detection result or null if not detected
2650
+ *
2651
+ * @example Detecting Turborepo monorepo
2652
+ * ```typescript
2653
+ * // Project with turbo.json and turbo dependency
2654
+ * const result = turborepoDetector('/path/to/turbo-project')
2655
+ * // => {
2656
+ * // id: 'turborepo',
2657
+ * // name: 'Turborepo',
2658
+ * // confidence: 95,
2659
+ * // configPath: 'turbo.json',
2660
+ * // version: '2.0.0',
2661
+ * // detectedFrom: [
2662
+ * // { type: 'config-file', path: 'turbo.json' },
2663
+ * // { type: 'package.json', field: 'dependencies.turbo' }
2664
+ * // ]
2665
+ * // }
2666
+ * ```
2731
2667
  */
2732
- function npmWorkspacesDetector(workspacePath, packageJson) {
2668
+ function turborepoDetector(workspacePath, packageJson) {
2733
2669
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2734
2670
  const sources = [];
2735
2671
  let confidence = 0;
2736
- if (pkg?.workspaces) {
2672
+ let version;
2673
+ let configPath;
2674
+ const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2675
+ if (exists(turboJsonPath)) {
2737
2676
  confidence += 80;
2738
- sources.push({ type: 'package.json', field: 'workspaces' });
2677
+ configPath = 'turbo.json';
2678
+ sources.push({ type: 'config-file', path: 'turbo.json' });
2739
2679
  }
2740
- if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2741
- confidence += 10;
2742
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
2680
+ const deps = collectAllDependencies(pkg);
2681
+ if (deps['turbo']) {
2682
+ confidence += 15;
2683
+ version = parseVersionString(deps['turbo']);
2684
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2743
2685
  }
2744
- if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2745
- return null;
2686
+ const scripts = pkg?.scripts ?? {};
2687
+ if (index_cjs_js$2.values(scripts).some((s) => s?.includes('turbo'))) {
2688
+ confidence += 5;
2689
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2746
2690
  }
2747
2691
  if (confidence === 0) {
2748
2692
  return null;
2749
2693
  }
2750
2694
  return {
2751
- id: 'npm-workspaces',
2752
- name: 'npm Workspaces',
2753
- configPath: 'package.json',
2754
- confidence: min(confidence, 100),
2695
+ id: 'turborepo',
2696
+ name: 'Turborepo',
2697
+ version,
2698
+ configPath,
2699
+ confidence: index_cjs_js$8.min(confidence, 100),
2755
2700
  detectedFrom: sources,
2756
2701
  };
2757
2702
  }
@@ -2762,6 +2707,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
2762
2707
  * @param workspacePath - Workspace directory path
2763
2708
  * @param packageJson - Optional pre-loaded package.json
2764
2709
  * @returns Detection result or null if not detected
2710
+ *
2711
+ * @example Detecting yarn workspaces
2712
+ * ```typescript
2713
+ * // Project with workspaces in package.json and yarn.lock
2714
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
2715
+ * // => {
2716
+ * // id: 'yarn-workspaces',
2717
+ * // name: 'Yarn Workspaces',
2718
+ * // confidence: 100,
2719
+ * // configPath: 'package.json',
2720
+ * // detectedFrom: [
2721
+ * // { type: 'package.json', field: 'workspaces' },
2722
+ * // { type: 'lockfile', path: 'yarn.lock' },
2723
+ * // { type: 'config-file', path: '.yarnrc.yml' }
2724
+ * // ]
2725
+ * // }
2726
+ * ```
2765
2727
  */
2766
2728
  function yarnWorkspacesDetector(workspacePath, packageJson) {
2767
2729
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2786,7 +2748,7 @@ function yarnWorkspacesDetector(workspacePath, packageJson) {
2786
2748
  id: 'yarn-workspaces',
2787
2749
  name: 'Yarn Workspaces',
2788
2750
  configPath: 'package.json',
2789
- confidence: min(confidence, 100),
2751
+ confidence: index_cjs_js$8.min(confidence, 100),
2790
2752
  detectedFrom: sources,
2791
2753
  };
2792
2754
  }
@@ -2802,111 +2764,129 @@ const monorepoDetectors = [
2802
2764
  { id: 'yarn-workspaces', name: 'Yarn Workspaces', detect: yarnWorkspacesDetector },
2803
2765
  ];
2804
2766
 
2805
- /** Config patterns for Jest */
2806
- const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2767
+ /** Config patterns for Cypress */
2768
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2807
2769
  /**
2808
- * Detect Jest in project.
2770
+ * Detect Cypress in project.
2809
2771
  *
2810
2772
  * @param projectPath - Project directory path
2811
2773
  * @param packageJson - Optional pre-loaded package.json
2812
2774
  * @returns Detection result or null if not detected
2775
+ *
2776
+ * @example Detecting Cypress testing framework
2777
+ * ```typescript
2778
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
2779
+ *
2780
+ * const result = cypressDetector('./my-project')
2781
+ * if (result) {
2782
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
2783
+ * // => "Cypress 13.6.0 detected (95% confidence)"
2784
+ * }
2785
+ * ```
2813
2786
  */
2814
- function jestDetector(projectPath, packageJson) {
2787
+ function cypressDetector(projectPath, packageJson) {
2815
2788
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2816
2789
  const sources = [];
2817
2790
  let confidence = 0;
2818
2791
  let version;
2819
2792
  const deps = collectAllDependencies(pkg);
2820
- if (deps['jest']) {
2793
+ if (deps['cypress']) {
2821
2794
  confidence += 60;
2822
- version = parseVersionString(deps['jest']);
2823
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
2795
+ version = parseVersionString(deps['cypress']);
2796
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2824
2797
  }
2825
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2798
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2826
2799
  if (configPath) {
2827
2800
  confidence += 30;
2828
2801
  sources.push({ type: 'config-file', path: configPath });
2829
2802
  }
2830
- if (pkg && 'jest' in pkg) {
2831
- confidence += 20;
2832
- sources.push({ type: 'package.json', field: 'jest' });
2833
- }
2834
- const testScript = pkg?.scripts?.['test'] ?? '';
2835
- if (testScript.includes('jest')) {
2803
+ if (exists(node_path.join(projectPath, 'cypress'))) {
2836
2804
  confidence += 10;
2837
- sources.push({ type: 'package.json', field: 'scripts.test' });
2838
- }
2839
- if (deps['@types/jest']) {
2840
- confidence += 5;
2841
- sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2805
+ sources.push({ type: 'directory', path: 'cypress/' });
2842
2806
  }
2843
- if (deps['ts-jest']) {
2807
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2808
+ if (e2eScript.includes('cypress')) {
2844
2809
  confidence += 5;
2845
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2810
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2846
2811
  }
2847
2812
  if (confidence === 0) {
2848
2813
  return null;
2849
2814
  }
2850
2815
  return {
2851
- id: 'jest',
2852
- name: 'Jest',
2853
- type: 'unit',
2816
+ id: 'cypress',
2817
+ name: 'Cypress',
2818
+ type: 'e2e',
2854
2819
  version,
2855
2820
  configPath,
2856
- confidence: min(confidence, 100),
2821
+ confidence: index_cjs_js$8.min(confidence, 100),
2857
2822
  detectedFrom: sources,
2858
2823
  };
2859
2824
  }
2860
2825
 
2861
- /** Config patterns for Vitest */
2862
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
2826
+ /** Config patterns for Jest */
2827
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2863
2828
  /**
2864
- * Detect Vitest in project.
2829
+ * Detect Jest in project.
2865
2830
  *
2866
2831
  * @param projectPath - Project directory path
2867
2832
  * @param packageJson - Optional pre-loaded package.json
2868
2833
  * @returns Detection result or null if not detected
2834
+ *
2835
+ * @example Detecting Jest testing framework
2836
+ * ```typescript
2837
+ * import { jestDetector } from '@hyperfrontend/project-scope'
2838
+ *
2839
+ * const result = jestDetector('./my-project')
2840
+ * if (result) {
2841
+ * console.log(`Jest ${result.version} detected`)
2842
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
2843
+ * // => "Sources: ['package.json', 'config-file']"
2844
+ * }
2845
+ * ```
2869
2846
  */
2870
- function vitestDetector(projectPath, packageJson) {
2847
+ function jestDetector(projectPath, packageJson) {
2871
2848
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2872
2849
  const sources = [];
2873
2850
  let confidence = 0;
2874
2851
  let version;
2875
2852
  const deps = collectAllDependencies(pkg);
2876
- if (deps['vitest']) {
2877
- confidence += 70;
2878
- version = parseVersionString(deps['vitest']);
2879
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
2853
+ if (deps['jest']) {
2854
+ confidence += 60;
2855
+ version = parseVersionString(deps['jest']);
2856
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
2880
2857
  }
2881
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
2858
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2882
2859
  if (configPath) {
2883
- confidence += 25;
2860
+ confidence += 30;
2884
2861
  sources.push({ type: 'config-file', path: configPath });
2885
2862
  }
2886
- if (!configPath) {
2887
- const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
2888
- exists(node_path.join(projectPath, 'vite.config.js')) ||
2889
- exists(node_path.join(projectPath, 'vite.config.mjs'));
2890
- if (viteConfig && deps['vitest']) {
2891
- confidence += 5;
2892
- sources.push({ type: 'config-file', path: 'vite.config.*' });
2893
- }
2863
+ if (pkg && 'jest' in pkg) {
2864
+ confidence += 20;
2865
+ sources.push({ type: 'package.json', field: 'jest' });
2894
2866
  }
2895
2867
  const testScript = pkg?.scripts?.['test'] ?? '';
2896
- if (testScript.includes('vitest')) {
2868
+ if (testScript.includes('jest')) {
2897
2869
  confidence += 10;
2898
2870
  sources.push({ type: 'package.json', field: 'scripts.test' });
2899
2871
  }
2872
+ if (deps['@types/jest']) {
2873
+ confidence += 5;
2874
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2875
+ }
2876
+ if (deps['ts-jest']) {
2877
+ confidence += 5;
2878
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2879
+ }
2900
2880
  if (confidence === 0) {
2901
2881
  return null;
2902
2882
  }
2903
2883
  return {
2904
- id: 'vitest',
2905
- name: 'Vitest',
2884
+ id: 'jest',
2885
+ name: 'Jest',
2906
2886
  type: 'unit',
2907
2887
  version,
2908
2888
  configPath,
2909
- confidence: min(confidence, 100),
2889
+ confidence: index_cjs_js$8.min(confidence, 100),
2910
2890
  detectedFrom: sources,
2911
2891
  };
2912
2892
  }
@@ -2919,6 +2899,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
2919
2899
  * @param projectPath - Project directory path
2920
2900
  * @param packageJson - Optional pre-loaded package.json
2921
2901
  * @returns Detection result or null if not detected
2902
+ *
2903
+ * @example Detecting Mocha testing framework
2904
+ * ```typescript
2905
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
2906
+ *
2907
+ * const result = mochaDetector('./my-project')
2908
+ * if (result) {
2909
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
2910
+ * // => "Mocha 10.2.0 detected (95%)"
2911
+ * }
2912
+ * ```
2922
2913
  */
2923
2914
  function mochaDetector(projectPath, packageJson) {
2924
2915
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2958,42 +2949,58 @@ function mochaDetector(projectPath, packageJson) {
2958
2949
  type: 'unit',
2959
2950
  version,
2960
2951
  configPath,
2961
- confidence: min(confidence, 100),
2952
+ confidence: index_cjs_js$8.min(confidence, 100),
2962
2953
  detectedFrom: sources,
2963
2954
  };
2964
2955
  }
2965
2956
 
2966
- /** Config patterns for Cypress */
2967
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2957
+ /** Config patterns for Playwright */
2958
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
2968
2959
  /**
2969
- * Detect Cypress in project.
2960
+ * Detect Playwright in project.
2970
2961
  *
2971
2962
  * @param projectPath - Project directory path
2972
2963
  * @param packageJson - Optional pre-loaded package.json
2973
2964
  * @returns Detection result or null if not detected
2965
+ *
2966
+ * @example Detecting Playwright testing framework
2967
+ * ```typescript
2968
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
2969
+ *
2970
+ * const result = playwrightDetector('./my-project')
2971
+ * if (result) {
2972
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
2973
+ * // => "Playwright 1.42.0 (e2e tests)"
2974
+ * }
2975
+ * ```
2974
2976
  */
2975
- function cypressDetector(projectPath, packageJson) {
2977
+ function playwrightDetector(projectPath, packageJson) {
2976
2978
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2977
2979
  const sources = [];
2978
2980
  let confidence = 0;
2979
2981
  let version;
2980
2982
  const deps = collectAllDependencies(pkg);
2981
- if (deps['cypress']) {
2982
- confidence += 60;
2983
- version = parseVersionString(deps['cypress']);
2984
- sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2983
+ if (deps['@playwright/test']) {
2984
+ confidence += 70;
2985
+ version = parseVersionString(deps['@playwright/test']);
2986
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
2985
2987
  }
2986
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2988
+ if (deps['playwright']) {
2989
+ confidence += 50;
2990
+ version = version ?? parseVersionString(deps['playwright']);
2991
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
2992
+ }
2993
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
2987
2994
  if (configPath) {
2988
- confidence += 30;
2995
+ confidence += 25;
2989
2996
  sources.push({ type: 'config-file', path: configPath });
2990
2997
  }
2991
- if (exists(node_path.join(projectPath, 'cypress'))) {
2992
- confidence += 10;
2993
- sources.push({ type: 'directory', path: 'cypress/' });
2998
+ if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
2999
+ confidence += 5;
3000
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
2994
3001
  }
2995
3002
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2996
- if (e2eScript.includes('cypress')) {
3003
+ if (e2eScript.includes('playwright')) {
2997
3004
  confidence += 5;
2998
3005
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2999
3006
  }
@@ -3001,65 +3008,77 @@ function cypressDetector(projectPath, packageJson) {
3001
3008
  return null;
3002
3009
  }
3003
3010
  return {
3004
- id: 'cypress',
3005
- name: 'Cypress',
3011
+ id: 'playwright',
3012
+ name: 'Playwright',
3006
3013
  type: 'e2e',
3007
3014
  version,
3008
3015
  configPath,
3009
- confidence: min(confidence, 100),
3016
+ confidence: index_cjs_js$8.min(confidence, 100),
3010
3017
  detectedFrom: sources,
3011
3018
  };
3012
3019
  }
3013
3020
 
3014
- /** Config patterns for Playwright */
3015
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3021
+ /** Config patterns for Vitest */
3022
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3016
3023
  /**
3017
- * Detect Playwright in project.
3024
+ * Detect Vitest in project.
3018
3025
  *
3019
3026
  * @param projectPath - Project directory path
3020
3027
  * @param packageJson - Optional pre-loaded package.json
3021
3028
  * @returns Detection result or null if not detected
3029
+ *
3030
+ * @example Detecting Vitest testing framework
3031
+ * ```typescript
3032
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3033
+ *
3034
+ * const result = vitestDetector('./my-project')
3035
+ * if (result) {
3036
+ * console.log(`Vitest ${result.version} detected`)
3037
+ * console.log('Config:', result.configPath)
3038
+ * // => "Config: vitest.config.ts"
3039
+ * }
3040
+ * ```
3022
3041
  */
3023
- function playwrightDetector(projectPath, packageJson) {
3042
+ function vitestDetector(projectPath, packageJson) {
3024
3043
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3025
3044
  const sources = [];
3026
3045
  let confidence = 0;
3027
3046
  let version;
3028
3047
  const deps = collectAllDependencies(pkg);
3029
- if (deps['@playwright/test']) {
3048
+ if (deps['vitest']) {
3030
3049
  confidence += 70;
3031
- version = parseVersionString(deps['@playwright/test']);
3032
- sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3033
- }
3034
- if (deps['playwright']) {
3035
- confidence += 50;
3036
- version = version ?? parseVersionString(deps['playwright']);
3037
- sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3050
+ version = parseVersionString(deps['vitest']);
3051
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3038
3052
  }
3039
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3053
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3040
3054
  if (configPath) {
3041
3055
  confidence += 25;
3042
3056
  sources.push({ type: 'config-file', path: configPath });
3043
3057
  }
3044
- if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
3045
- confidence += 5;
3046
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3058
+ if (!configPath) {
3059
+ const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
3060
+ exists(node_path.join(projectPath, 'vite.config.js')) ||
3061
+ exists(node_path.join(projectPath, 'vite.config.mjs'));
3062
+ if (viteConfig && deps['vitest']) {
3063
+ confidence += 5;
3064
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3065
+ }
3047
3066
  }
3048
- const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3049
- if (e2eScript.includes('playwright')) {
3050
- confidence += 5;
3051
- sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3067
+ const testScript = pkg?.scripts?.['test'] ?? '';
3068
+ if (testScript.includes('vitest')) {
3069
+ confidence += 10;
3070
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3052
3071
  }
3053
3072
  if (confidence === 0) {
3054
3073
  return null;
3055
3074
  }
3056
3075
  return {
3057
- id: 'playwright',
3058
- name: 'Playwright',
3059
- type: 'e2e',
3076
+ id: 'vitest',
3077
+ name: 'Vitest',
3078
+ type: 'unit',
3060
3079
  version,
3061
3080
  configPath,
3062
- confidence: min(confidence, 100),
3081
+ confidence: index_cjs_js$8.min(confidence, 100),
3063
3082
  detectedFrom: sources,
3064
3083
  };
3065
3084
  }
@@ -3086,7 +3105,7 @@ function checkTsConfigStrict(projectPath) {
3086
3105
  return undefined;
3087
3106
  try {
3088
3107
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3089
- const parsed = parse(cleanContent);
3108
+ const parsed = index_cjs_js$6.parse(cleanContent);
3090
3109
  return parsed?.compilerOptions?.strict === true;
3091
3110
  }
3092
3111
  catch {
@@ -3099,6 +3118,19 @@ function checkTsConfigStrict(projectPath) {
3099
3118
  * @param projectPath - Project directory path
3100
3119
  * @param packageJson - Optional pre-loaded package.json
3101
3120
  * @returns Detection result or null if not detected
3121
+ *
3122
+ * @example Detecting TypeScript
3123
+ * ```typescript
3124
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3125
+ *
3126
+ * const result = typescriptDetector('./my-project')
3127
+ * if (result) {
3128
+ * console.log(`TypeScript ${result.version}`)
3129
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3130
+ * // => "TypeScript 5.3.0"
3131
+ * // => "Strict mode: true"
3132
+ * }
3133
+ * ```
3102
3134
  */
3103
3135
  function typescriptDetector(projectPath, packageJson) {
3104
3136
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3125,7 +3157,7 @@ function typescriptDetector(projectPath, packageJson) {
3125
3157
  break;
3126
3158
  }
3127
3159
  }
3128
- const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
3160
+ const typePackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@types/'));
3129
3161
  if (typePackages.length > 0) {
3130
3162
  confidence += 10;
3131
3163
  sources.push({ type: 'package.json', field: '@types/* packages' });
@@ -3140,7 +3172,7 @@ function typescriptDetector(projectPath, packageJson) {
3140
3172
  version,
3141
3173
  configPath,
3142
3174
  strictMode,
3143
- confidence: min(confidence, 100),
3175
+ confidence: index_cjs_js$8.min(confidence, 100),
3144
3176
  detectedFrom: sources,
3145
3177
  };
3146
3178
  }
@@ -3150,6 +3182,17 @@ function typescriptDetector(projectPath, packageJson) {
3150
3182
  * @param projectPath - Project directory path
3151
3183
  * @param packageJson - Optional pre-loaded package.json
3152
3184
  * @returns Detection result or null if not detected
3185
+ *
3186
+ * @example Detecting Flow type system
3187
+ * ```typescript
3188
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3189
+ *
3190
+ * const result = flowDetector('./my-project')
3191
+ * if (result) {
3192
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3193
+ * // => "Flow 0.232.0 with config: .flowconfig"
3194
+ * }
3195
+ * ```
3153
3196
  */
3154
3197
  function flowDetector(projectPath, packageJson) {
3155
3198
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3184,7 +3227,7 @@ function flowDetector(projectPath, packageJson) {
3184
3227
  name: 'Flow',
3185
3228
  version,
3186
3229
  configPath,
3187
- confidence: min(confidence, 100),
3230
+ confidence: index_cjs_js$8.min(confidence, 100),
3188
3231
  detectedFrom: sources,
3189
3232
  };
3190
3233
  }
@@ -3207,6 +3250,18 @@ function hasJsDocTypes(content) {
3207
3250
  * @param projectPath - Project directory path
3208
3251
  * @param packageJson - Optional pre-loaded package.json
3209
3252
  * @returns Detection result or null if not detected
3253
+ *
3254
+ * @example Detecting JSDoc type annotations
3255
+ * ```typescript
3256
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3257
+ *
3258
+ * const result = jsdocDetector('./my-project')
3259
+ * if (result) {
3260
+ * console.log('JSDoc types detected')
3261
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3262
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3263
+ * }
3264
+ * ```
3210
3265
  */
3211
3266
  function jsdocDetector(projectPath, packageJson) {
3212
3267
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3223,7 +3278,7 @@ function jsdocDetector(projectPath, packageJson) {
3223
3278
  if (content) {
3224
3279
  try {
3225
3280
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3226
- const parsed = parse(cleanContent);
3281
+ const parsed = index_cjs_js$6.parse(cleanContent);
3227
3282
  if (parsed?.compilerOptions?.checkJs === true || parsed?.compilerOptions?.allowJs === true) {
3228
3283
  confidence += 30;
3229
3284
  sources.push({ type: 'config-file', path: 'tsconfig.json (checkJs/allowJs)' });
@@ -3262,7 +3317,7 @@ function jsdocDetector(projectPath, packageJson) {
3262
3317
  return {
3263
3318
  id: 'jsdoc',
3264
3319
  name: 'JSDoc',
3265
- confidence: min(confidence, 100),
3320
+ confidence: index_cjs_js$8.min(confidence, 100),
3266
3321
  detectedFrom: sources,
3267
3322
  };
3268
3323
  }
@@ -3300,7 +3355,7 @@ function isDetectAllOptions(value) {
3300
3355
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
3301
3356
  * @returns All detection results organized by category
3302
3357
  *
3303
- * @example
3358
+ * @example Running all tech detectors
3304
3359
  * ```typescript
3305
3360
  * import { detectAll } from '@hyperfrontend/project-scope'
3306
3361
  *
@@ -3417,7 +3472,7 @@ function buildSummary(frontend, backend, testing) {
3417
3472
  * @param options - Identification options
3418
3473
  * @returns Framework identification result
3419
3474
  *
3420
- * @example
3475
+ * @example Identifying all frameworks in project
3421
3476
  * ```typescript
3422
3477
  * import { identifyFrameworks } from '@hyperfrontend/project-scope'
3423
3478
  *
@@ -3532,6 +3587,14 @@ function identifyFrameworks(projectPath, options) {
3532
3587
  * Clear the framework identification cache.
3533
3588
  *
3534
3589
  * Useful for testing or when the project files have changed.
3590
+ *
3591
+ * @example Clearing the framework cache
3592
+ * ```typescript
3593
+ * import { clearFrameworkIdentificationCache } from '@hyperfrontend/project-scope'
3594
+ *
3595
+ * // Reset cache before re-identifying frameworks
3596
+ * clearFrameworkIdentificationCache()
3597
+ * ```
3535
3598
  */
3536
3599
  function clearFrameworkIdentificationCache() {
3537
3600
  frameworkIdCache.clear();
@@ -3543,6 +3606,15 @@ function clearFrameworkIdentificationCache() {
3543
3606
  * @param frameworkId - Framework identifier to check
3544
3607
  * @param minConfidence - Minimum confidence threshold (default: 50)
3545
3608
  * @returns True if the framework is detected with sufficient confidence
3609
+ *
3610
+ * @example Checking for a specific framework
3611
+ * ```typescript
3612
+ * import { usesFramework } from '@hyperfrontend/project-scope'
3613
+ *
3614
+ * if (usesFramework('/path/to/project', 'react', 70)) {
3615
+ * console.log('Project uses React with high confidence')
3616
+ * }
3617
+ * ```
3546
3618
  */
3547
3619
  function usesFramework(projectPath, frameworkId, minConfidence = 50) {
3548
3620
  const identification = identifyFrameworks(projectPath, { minConfidence });
@@ -3553,4 +3625,3 @@ function usesFramework(projectPath, frameworkId, minConfidence = 50) {
3553
3625
  exports.clearFrameworkIdentificationCache = clearFrameworkIdentificationCache;
3554
3626
  exports.identifyFrameworks = identifyFrameworks;
3555
3627
  exports.usesFramework = usesFramework;
3556
- //# sourceMappingURL=index.cjs.js.map