@hyperfrontend/project-scope 0.2.1 → 0.2.3

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