@hyperfrontend/project-scope 0.2.0 → 0.2.2

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