driftdetect-detectors 0.1.0

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 (509) hide show
  1. package/dist/accessibility/alt-text.d.ts +63 -0
  2. package/dist/accessibility/alt-text.d.ts.map +1 -0
  3. package/dist/accessibility/alt-text.js +100 -0
  4. package/dist/accessibility/alt-text.js.map +1 -0
  5. package/dist/accessibility/aria-roles.d.ts +65 -0
  6. package/dist/accessibility/aria-roles.d.ts.map +1 -0
  7. package/dist/accessibility/aria-roles.js +87 -0
  8. package/dist/accessibility/aria-roles.js.map +1 -0
  9. package/dist/accessibility/focus-management.d.ts +62 -0
  10. package/dist/accessibility/focus-management.d.ts.map +1 -0
  11. package/dist/accessibility/focus-management.js +88 -0
  12. package/dist/accessibility/focus-management.js.map +1 -0
  13. package/dist/accessibility/heading-hierarchy.d.ts +66 -0
  14. package/dist/accessibility/heading-hierarchy.d.ts.map +1 -0
  15. package/dist/accessibility/heading-hierarchy.js +94 -0
  16. package/dist/accessibility/heading-hierarchy.js.map +1 -0
  17. package/dist/accessibility/index.d.ts +25 -0
  18. package/dist/accessibility/index.d.ts.map +1 -0
  19. package/dist/accessibility/index.js +21 -0
  20. package/dist/accessibility/index.js.map +1 -0
  21. package/dist/accessibility/keyboard-nav.d.ts +63 -0
  22. package/dist/accessibility/keyboard-nav.d.ts.map +1 -0
  23. package/dist/accessibility/keyboard-nav.js +86 -0
  24. package/dist/accessibility/keyboard-nav.js.map +1 -0
  25. package/dist/accessibility/semantic-html.d.ts +76 -0
  26. package/dist/accessibility/semantic-html.d.ts.map +1 -0
  27. package/dist/accessibility/semantic-html.js +204 -0
  28. package/dist/accessibility/semantic-html.js.map +1 -0
  29. package/dist/api/client-patterns.d.ts +121 -0
  30. package/dist/api/client-patterns.d.ts.map +1 -0
  31. package/dist/api/client-patterns.js +478 -0
  32. package/dist/api/client-patterns.js.map +1 -0
  33. package/dist/api/error-format.d.ts +140 -0
  34. package/dist/api/error-format.d.ts.map +1 -0
  35. package/dist/api/error-format.js +614 -0
  36. package/dist/api/error-format.js.map +1 -0
  37. package/dist/api/http-methods.d.ts +255 -0
  38. package/dist/api/http-methods.d.ts.map +1 -0
  39. package/dist/api/http-methods.js +890 -0
  40. package/dist/api/http-methods.js.map +1 -0
  41. package/dist/api/index.d.ts +16 -0
  42. package/dist/api/index.d.ts.map +1 -0
  43. package/dist/api/index.js +37 -0
  44. package/dist/api/index.js.map +1 -0
  45. package/dist/api/pagination.d.ts +133 -0
  46. package/dist/api/pagination.d.ts.map +1 -0
  47. package/dist/api/pagination.js +521 -0
  48. package/dist/api/pagination.js.map +1 -0
  49. package/dist/api/response-envelope.d.ts +261 -0
  50. package/dist/api/response-envelope.d.ts.map +1 -0
  51. package/dist/api/response-envelope.js +1050 -0
  52. package/dist/api/response-envelope.js.map +1 -0
  53. package/dist/api/retry-patterns.d.ts +117 -0
  54. package/dist/api/retry-patterns.d.ts.map +1 -0
  55. package/dist/api/retry-patterns.js +480 -0
  56. package/dist/api/retry-patterns.js.map +1 -0
  57. package/dist/api/route-structure.d.ts +128 -0
  58. package/dist/api/route-structure.d.ts.map +1 -0
  59. package/dist/api/route-structure.js +738 -0
  60. package/dist/api/route-structure.js.map +1 -0
  61. package/dist/auth/audit-logging.d.ts +80 -0
  62. package/dist/auth/audit-logging.d.ts.map +1 -0
  63. package/dist/auth/audit-logging.js +370 -0
  64. package/dist/auth/audit-logging.js.map +1 -0
  65. package/dist/auth/index.d.ts +33 -0
  66. package/dist/auth/index.d.ts.map +1 -0
  67. package/dist/auth/index.js +49 -0
  68. package/dist/auth/index.js.map +1 -0
  69. package/dist/auth/middleware-usage.d.ts +65 -0
  70. package/dist/auth/middleware-usage.d.ts.map +1 -0
  71. package/dist/auth/middleware-usage.js +192 -0
  72. package/dist/auth/middleware-usage.js.map +1 -0
  73. package/dist/auth/permission-checks.d.ts +60 -0
  74. package/dist/auth/permission-checks.d.ts.map +1 -0
  75. package/dist/auth/permission-checks.js +159 -0
  76. package/dist/auth/permission-checks.js.map +1 -0
  77. package/dist/auth/rbac-patterns.d.ts +68 -0
  78. package/dist/auth/rbac-patterns.d.ts.map +1 -0
  79. package/dist/auth/rbac-patterns.js +143 -0
  80. package/dist/auth/rbac-patterns.js.map +1 -0
  81. package/dist/auth/resource-ownership.d.ts +77 -0
  82. package/dist/auth/resource-ownership.d.ts.map +1 -0
  83. package/dist/auth/resource-ownership.js +324 -0
  84. package/dist/auth/resource-ownership.js.map +1 -0
  85. package/dist/auth/token-handling.d.ts +64 -0
  86. package/dist/auth/token-handling.d.ts.map +1 -0
  87. package/dist/auth/token-handling.js +151 -0
  88. package/dist/auth/token-handling.js.map +1 -0
  89. package/dist/base/ast-detector.d.ts +421 -0
  90. package/dist/base/ast-detector.d.ts.map +1 -0
  91. package/dist/base/ast-detector.js +699 -0
  92. package/dist/base/ast-detector.js.map +1 -0
  93. package/dist/base/base-detector.d.ts +366 -0
  94. package/dist/base/base-detector.d.ts.map +1 -0
  95. package/dist/base/base-detector.js +170 -0
  96. package/dist/base/base-detector.js.map +1 -0
  97. package/dist/base/index.d.ts +12 -0
  98. package/dist/base/index.d.ts.map +1 -0
  99. package/dist/base/index.js +17 -0
  100. package/dist/base/index.js.map +1 -0
  101. package/dist/base/regex-detector.d.ts +421 -0
  102. package/dist/base/regex-detector.d.ts.map +1 -0
  103. package/dist/base/regex-detector.js +537 -0
  104. package/dist/base/regex-detector.js.map +1 -0
  105. package/dist/base/structural-detector.d.ts +424 -0
  106. package/dist/base/structural-detector.d.ts.map +1 -0
  107. package/dist/base/structural-detector.js +731 -0
  108. package/dist/base/structural-detector.js.map +1 -0
  109. package/dist/base/types.d.ts +53 -0
  110. package/dist/base/types.d.ts.map +1 -0
  111. package/dist/base/types.js +5 -0
  112. package/dist/base/types.js.map +1 -0
  113. package/dist/components/component-structure.d.ts +163 -0
  114. package/dist/components/component-structure.d.ts.map +1 -0
  115. package/dist/components/component-structure.js +500 -0
  116. package/dist/components/component-structure.js.map +1 -0
  117. package/dist/components/composition.d.ts +287 -0
  118. package/dist/components/composition.d.ts.map +1 -0
  119. package/dist/components/composition.js +1123 -0
  120. package/dist/components/composition.js.map +1 -0
  121. package/dist/components/duplicate-detection.d.ts +251 -0
  122. package/dist/components/duplicate-detection.d.ts.map +1 -0
  123. package/dist/components/duplicate-detection.js +804 -0
  124. package/dist/components/duplicate-detection.js.map +1 -0
  125. package/dist/components/index.d.ts +16 -0
  126. package/dist/components/index.d.ts.map +1 -0
  127. package/dist/components/index.js +51 -0
  128. package/dist/components/index.js.map +1 -0
  129. package/dist/components/near-duplicate.d.ts +402 -0
  130. package/dist/components/near-duplicate.d.ts.map +1 -0
  131. package/dist/components/near-duplicate.js +1090 -0
  132. package/dist/components/near-duplicate.js.map +1 -0
  133. package/dist/components/props-patterns.d.ts +194 -0
  134. package/dist/components/props-patterns.d.ts.map +1 -0
  135. package/dist/components/props-patterns.js +795 -0
  136. package/dist/components/props-patterns.js.map +1 -0
  137. package/dist/components/ref-forwarding.d.ts +250 -0
  138. package/dist/components/ref-forwarding.d.ts.map +1 -0
  139. package/dist/components/ref-forwarding.js +832 -0
  140. package/dist/components/ref-forwarding.js.map +1 -0
  141. package/dist/components/state-patterns.d.ts +291 -0
  142. package/dist/components/state-patterns.d.ts.map +1 -0
  143. package/dist/components/state-patterns.js +970 -0
  144. package/dist/components/state-patterns.js.map +1 -0
  145. package/dist/config/config-validation.d.ts +74 -0
  146. package/dist/config/config-validation.d.ts.map +1 -0
  147. package/dist/config/config-validation.js +446 -0
  148. package/dist/config/config-validation.js.map +1 -0
  149. package/dist/config/default-values.d.ts +72 -0
  150. package/dist/config/default-values.d.ts.map +1 -0
  151. package/dist/config/default-values.js +386 -0
  152. package/dist/config/default-values.js.map +1 -0
  153. package/dist/config/env-naming.d.ts +73 -0
  154. package/dist/config/env-naming.d.ts.map +1 -0
  155. package/dist/config/env-naming.js +429 -0
  156. package/dist/config/env-naming.js.map +1 -0
  157. package/dist/config/environment-detection.d.ts +72 -0
  158. package/dist/config/environment-detection.d.ts.map +1 -0
  159. package/dist/config/environment-detection.js +400 -0
  160. package/dist/config/environment-detection.js.map +1 -0
  161. package/dist/config/feature-flags.d.ts +72 -0
  162. package/dist/config/feature-flags.d.ts.map +1 -0
  163. package/dist/config/feature-flags.js +384 -0
  164. package/dist/config/feature-flags.js.map +1 -0
  165. package/dist/config/index.d.ts +27 -0
  166. package/dist/config/index.d.ts.map +1 -0
  167. package/dist/config/index.js +43 -0
  168. package/dist/config/index.js.map +1 -0
  169. package/dist/config/required-optional.d.ts +71 -0
  170. package/dist/config/required-optional.d.ts.map +1 -0
  171. package/dist/config/required-optional.js +344 -0
  172. package/dist/config/required-optional.js.map +1 -0
  173. package/dist/data-access/connection-pooling.d.ts +63 -0
  174. package/dist/data-access/connection-pooling.d.ts.map +1 -0
  175. package/dist/data-access/connection-pooling.js +297 -0
  176. package/dist/data-access/connection-pooling.js.map +1 -0
  177. package/dist/data-access/dto-patterns.d.ts +64 -0
  178. package/dist/data-access/dto-patterns.d.ts.map +1 -0
  179. package/dist/data-access/dto-patterns.js +291 -0
  180. package/dist/data-access/dto-patterns.js.map +1 -0
  181. package/dist/data-access/index.d.ts +31 -0
  182. package/dist/data-access/index.d.ts.map +1 -0
  183. package/dist/data-access/index.js +49 -0
  184. package/dist/data-access/index.js.map +1 -0
  185. package/dist/data-access/n-plus-one.d.ts +60 -0
  186. package/dist/data-access/n-plus-one.d.ts.map +1 -0
  187. package/dist/data-access/n-plus-one.js +264 -0
  188. package/dist/data-access/n-plus-one.js.map +1 -0
  189. package/dist/data-access/query-patterns.d.ts +64 -0
  190. package/dist/data-access/query-patterns.d.ts.map +1 -0
  191. package/dist/data-access/query-patterns.js +314 -0
  192. package/dist/data-access/query-patterns.js.map +1 -0
  193. package/dist/data-access/repository-pattern.d.ts +62 -0
  194. package/dist/data-access/repository-pattern.d.ts.map +1 -0
  195. package/dist/data-access/repository-pattern.js +257 -0
  196. package/dist/data-access/repository-pattern.js.map +1 -0
  197. package/dist/data-access/transaction-patterns.d.ts +61 -0
  198. package/dist/data-access/transaction-patterns.d.ts.map +1 -0
  199. package/dist/data-access/transaction-patterns.js +277 -0
  200. package/dist/data-access/transaction-patterns.js.map +1 -0
  201. package/dist/data-access/validation-patterns.d.ts +62 -0
  202. package/dist/data-access/validation-patterns.d.ts.map +1 -0
  203. package/dist/data-access/validation-patterns.js +301 -0
  204. package/dist/data-access/validation-patterns.js.map +1 -0
  205. package/dist/documentation/deprecation.d.ts +62 -0
  206. package/dist/documentation/deprecation.d.ts.map +1 -0
  207. package/dist/documentation/deprecation.js +83 -0
  208. package/dist/documentation/deprecation.js.map +1 -0
  209. package/dist/documentation/example-code.d.ts +64 -0
  210. package/dist/documentation/example-code.d.ts.map +1 -0
  211. package/dist/documentation/example-code.js +79 -0
  212. package/dist/documentation/example-code.js.map +1 -0
  213. package/dist/documentation/index.d.ts +22 -0
  214. package/dist/documentation/index.d.ts.map +1 -0
  215. package/dist/documentation/index.js +19 -0
  216. package/dist/documentation/index.js.map +1 -0
  217. package/dist/documentation/jsdoc-patterns.d.ts +72 -0
  218. package/dist/documentation/jsdoc-patterns.d.ts.map +1 -0
  219. package/dist/documentation/jsdoc-patterns.js +92 -0
  220. package/dist/documentation/jsdoc-patterns.js.map +1 -0
  221. package/dist/documentation/readme-structure.d.ts +67 -0
  222. package/dist/documentation/readme-structure.d.ts.map +1 -0
  223. package/dist/documentation/readme-structure.js +76 -0
  224. package/dist/documentation/readme-structure.js.map +1 -0
  225. package/dist/documentation/todo-patterns.d.ts +67 -0
  226. package/dist/documentation/todo-patterns.d.ts.map +1 -0
  227. package/dist/documentation/todo-patterns.js +73 -0
  228. package/dist/documentation/todo-patterns.js.map +1 -0
  229. package/dist/errors/async-errors.d.ts +72 -0
  230. package/dist/errors/async-errors.d.ts.map +1 -0
  231. package/dist/errors/async-errors.js +214 -0
  232. package/dist/errors/async-errors.js.map +1 -0
  233. package/dist/errors/circuit-breaker.d.ts +53 -0
  234. package/dist/errors/circuit-breaker.d.ts.map +1 -0
  235. package/dist/errors/circuit-breaker.js +241 -0
  236. package/dist/errors/circuit-breaker.js.map +1 -0
  237. package/dist/errors/error-codes.d.ts +73 -0
  238. package/dist/errors/error-codes.d.ts.map +1 -0
  239. package/dist/errors/error-codes.js +211 -0
  240. package/dist/errors/error-codes.js.map +1 -0
  241. package/dist/errors/error-logging.d.ts +73 -0
  242. package/dist/errors/error-logging.d.ts.map +1 -0
  243. package/dist/errors/error-logging.js +256 -0
  244. package/dist/errors/error-logging.js.map +1 -0
  245. package/dist/errors/error-propagation.d.ts +73 -0
  246. package/dist/errors/error-propagation.d.ts.map +1 -0
  247. package/dist/errors/error-propagation.js +244 -0
  248. package/dist/errors/error-propagation.js.map +1 -0
  249. package/dist/errors/exception-hierarchy.d.ts +75 -0
  250. package/dist/errors/exception-hierarchy.d.ts.map +1 -0
  251. package/dist/errors/exception-hierarchy.js +259 -0
  252. package/dist/errors/exception-hierarchy.js.map +1 -0
  253. package/dist/errors/index.d.ts +31 -0
  254. package/dist/errors/index.d.ts.map +1 -0
  255. package/dist/errors/index.js +49 -0
  256. package/dist/errors/index.js.map +1 -0
  257. package/dist/errors/try-catch-placement.d.ts +73 -0
  258. package/dist/errors/try-catch-placement.d.ts.map +1 -0
  259. package/dist/errors/try-catch-placement.js +214 -0
  260. package/dist/errors/try-catch-placement.js.map +1 -0
  261. package/dist/index.d.ts +221 -0
  262. package/dist/index.d.ts.map +1 -0
  263. package/dist/index.js +245 -0
  264. package/dist/index.js.map +1 -0
  265. package/dist/logging/context-fields.d.ts +48 -0
  266. package/dist/logging/context-fields.d.ts.map +1 -0
  267. package/dist/logging/context-fields.js +160 -0
  268. package/dist/logging/context-fields.js.map +1 -0
  269. package/dist/logging/correlation-ids.d.ts +44 -0
  270. package/dist/logging/correlation-ids.d.ts.map +1 -0
  271. package/dist/logging/correlation-ids.js +144 -0
  272. package/dist/logging/correlation-ids.js.map +1 -0
  273. package/dist/logging/health-checks.d.ts +45 -0
  274. package/dist/logging/health-checks.d.ts.map +1 -0
  275. package/dist/logging/health-checks.js +165 -0
  276. package/dist/logging/health-checks.js.map +1 -0
  277. package/dist/logging/index.d.ts +31 -0
  278. package/dist/logging/index.d.ts.map +1 -0
  279. package/dist/logging/index.js +49 -0
  280. package/dist/logging/index.js.map +1 -0
  281. package/dist/logging/log-levels.d.ts +46 -0
  282. package/dist/logging/log-levels.d.ts.map +1 -0
  283. package/dist/logging/log-levels.js +178 -0
  284. package/dist/logging/log-levels.js.map +1 -0
  285. package/dist/logging/metric-naming.d.ts +46 -0
  286. package/dist/logging/metric-naming.d.ts.map +1 -0
  287. package/dist/logging/metric-naming.js +157 -0
  288. package/dist/logging/metric-naming.js.map +1 -0
  289. package/dist/logging/pii-redaction.d.ts +44 -0
  290. package/dist/logging/pii-redaction.d.ts.map +1 -0
  291. package/dist/logging/pii-redaction.js +166 -0
  292. package/dist/logging/pii-redaction.js.map +1 -0
  293. package/dist/logging/structured-format.d.ts +53 -0
  294. package/dist/logging/structured-format.d.ts.map +1 -0
  295. package/dist/logging/structured-format.js +235 -0
  296. package/dist/logging/structured-format.js.map +1 -0
  297. package/dist/performance/bundle-size.d.ts +79 -0
  298. package/dist/performance/bundle-size.d.ts.map +1 -0
  299. package/dist/performance/bundle-size.js +276 -0
  300. package/dist/performance/bundle-size.js.map +1 -0
  301. package/dist/performance/caching-patterns.d.ts +78 -0
  302. package/dist/performance/caching-patterns.d.ts.map +1 -0
  303. package/dist/performance/caching-patterns.js +257 -0
  304. package/dist/performance/caching-patterns.js.map +1 -0
  305. package/dist/performance/code-splitting.d.ts +86 -0
  306. package/dist/performance/code-splitting.d.ts.map +1 -0
  307. package/dist/performance/code-splitting.js +447 -0
  308. package/dist/performance/code-splitting.js.map +1 -0
  309. package/dist/performance/debounce-throttle.d.ts +75 -0
  310. package/dist/performance/debounce-throttle.d.ts.map +1 -0
  311. package/dist/performance/debounce-throttle.js +232 -0
  312. package/dist/performance/debounce-throttle.js.map +1 -0
  313. package/dist/performance/index.d.ts +28 -0
  314. package/dist/performance/index.d.ts.map +1 -0
  315. package/dist/performance/index.js +39 -0
  316. package/dist/performance/index.js.map +1 -0
  317. package/dist/performance/lazy-loading.d.ts +75 -0
  318. package/dist/performance/lazy-loading.d.ts.map +1 -0
  319. package/dist/performance/lazy-loading.js +233 -0
  320. package/dist/performance/lazy-loading.js.map +1 -0
  321. package/dist/performance/memoization.d.ts +75 -0
  322. package/dist/performance/memoization.d.ts.map +1 -0
  323. package/dist/performance/memoization.js +251 -0
  324. package/dist/performance/memoization.js.map +1 -0
  325. package/dist/registry/detector-registry.d.ts +266 -0
  326. package/dist/registry/detector-registry.d.ts.map +1 -0
  327. package/dist/registry/detector-registry.js +526 -0
  328. package/dist/registry/detector-registry.js.map +1 -0
  329. package/dist/registry/index.d.ts +10 -0
  330. package/dist/registry/index.d.ts.map +1 -0
  331. package/dist/registry/index.js +10 -0
  332. package/dist/registry/index.js.map +1 -0
  333. package/dist/registry/loader.d.ts +232 -0
  334. package/dist/registry/loader.d.ts.map +1 -0
  335. package/dist/registry/loader.js +419 -0
  336. package/dist/registry/loader.js.map +1 -0
  337. package/dist/registry/types.d.ts +111 -0
  338. package/dist/registry/types.d.ts.map +1 -0
  339. package/dist/registry/types.js +19 -0
  340. package/dist/registry/types.js.map +1 -0
  341. package/dist/security/csp-headers.d.ts +78 -0
  342. package/dist/security/csp-headers.d.ts.map +1 -0
  343. package/dist/security/csp-headers.js +401 -0
  344. package/dist/security/csp-headers.js.map +1 -0
  345. package/dist/security/csrf-protection.d.ts +72 -0
  346. package/dist/security/csrf-protection.d.ts.map +1 -0
  347. package/dist/security/csrf-protection.js +344 -0
  348. package/dist/security/csrf-protection.js.map +1 -0
  349. package/dist/security/index.d.ts +30 -0
  350. package/dist/security/index.d.ts.map +1 -0
  351. package/dist/security/index.js +48 -0
  352. package/dist/security/index.js.map +1 -0
  353. package/dist/security/input-sanitization.d.ts +74 -0
  354. package/dist/security/input-sanitization.d.ts.map +1 -0
  355. package/dist/security/input-sanitization.js +373 -0
  356. package/dist/security/input-sanitization.js.map +1 -0
  357. package/dist/security/rate-limiting.d.ts +81 -0
  358. package/dist/security/rate-limiting.d.ts.map +1 -0
  359. package/dist/security/rate-limiting.js +535 -0
  360. package/dist/security/rate-limiting.js.map +1 -0
  361. package/dist/security/secret-management.d.ts +83 -0
  362. package/dist/security/secret-management.d.ts.map +1 -0
  363. package/dist/security/secret-management.js +547 -0
  364. package/dist/security/secret-management.js.map +1 -0
  365. package/dist/security/sql-injection.d.ts +76 -0
  366. package/dist/security/sql-injection.d.ts.map +1 -0
  367. package/dist/security/sql-injection.js +383 -0
  368. package/dist/security/sql-injection.js.map +1 -0
  369. package/dist/security/xss-prevention.d.ts +80 -0
  370. package/dist/security/xss-prevention.d.ts.map +1 -0
  371. package/dist/security/xss-prevention.js +416 -0
  372. package/dist/security/xss-prevention.js.map +1 -0
  373. package/dist/structural/barrel-exports.d.ts +178 -0
  374. package/dist/structural/barrel-exports.d.ts.map +1 -0
  375. package/dist/structural/barrel-exports.js +553 -0
  376. package/dist/structural/barrel-exports.js.map +1 -0
  377. package/dist/structural/circular-deps.d.ts +140 -0
  378. package/dist/structural/circular-deps.d.ts.map +1 -0
  379. package/dist/structural/circular-deps.js +422 -0
  380. package/dist/structural/circular-deps.js.map +1 -0
  381. package/dist/structural/co-location.d.ts +202 -0
  382. package/dist/structural/co-location.d.ts.map +1 -0
  383. package/dist/structural/co-location.js +640 -0
  384. package/dist/structural/co-location.js.map +1 -0
  385. package/dist/structural/directory-structure.d.ts +151 -0
  386. package/dist/structural/directory-structure.d.ts.map +1 -0
  387. package/dist/structural/directory-structure.js +457 -0
  388. package/dist/structural/directory-structure.js.map +1 -0
  389. package/dist/structural/file-naming.d.ts +61 -0
  390. package/dist/structural/file-naming.d.ts.map +1 -0
  391. package/dist/structural/file-naming.js +231 -0
  392. package/dist/structural/file-naming.js.map +1 -0
  393. package/dist/structural/import-ordering.d.ts +212 -0
  394. package/dist/structural/import-ordering.d.ts.map +1 -0
  395. package/dist/structural/import-ordering.js +821 -0
  396. package/dist/structural/import-ordering.js.map +1 -0
  397. package/dist/structural/index.d.ts +23 -0
  398. package/dist/structural/index.d.ts.map +1 -0
  399. package/dist/structural/index.js +26 -0
  400. package/dist/structural/index.js.map +1 -0
  401. package/dist/structural/module-boundaries.d.ts +164 -0
  402. package/dist/structural/module-boundaries.d.ts.map +1 -0
  403. package/dist/structural/module-boundaries.js +616 -0
  404. package/dist/structural/module-boundaries.js.map +1 -0
  405. package/dist/structural/package-boundaries.d.ts +182 -0
  406. package/dist/structural/package-boundaries.d.ts.map +1 -0
  407. package/dist/structural/package-boundaries.js +602 -0
  408. package/dist/structural/package-boundaries.js.map +1 -0
  409. package/dist/styling/class-naming.d.ts +263 -0
  410. package/dist/styling/class-naming.d.ts.map +1 -0
  411. package/dist/styling/class-naming.js +892 -0
  412. package/dist/styling/class-naming.js.map +1 -0
  413. package/dist/styling/color-usage.d.ts +213 -0
  414. package/dist/styling/color-usage.d.ts.map +1 -0
  415. package/dist/styling/color-usage.js +732 -0
  416. package/dist/styling/color-usage.js.map +1 -0
  417. package/dist/styling/design-tokens.d.ts +212 -0
  418. package/dist/styling/design-tokens.d.ts.map +1 -0
  419. package/dist/styling/design-tokens.js +748 -0
  420. package/dist/styling/design-tokens.js.map +1 -0
  421. package/dist/styling/index.d.ts +16 -0
  422. package/dist/styling/index.d.ts.map +1 -0
  423. package/dist/styling/index.js +56 -0
  424. package/dist/styling/index.js.map +1 -0
  425. package/dist/styling/responsive.d.ts +304 -0
  426. package/dist/styling/responsive.d.ts.map +1 -0
  427. package/dist/styling/responsive.js +888 -0
  428. package/dist/styling/responsive.js.map +1 -0
  429. package/dist/styling/spacing-scale.d.ts +248 -0
  430. package/dist/styling/spacing-scale.d.ts.map +1 -0
  431. package/dist/styling/spacing-scale.js +865 -0
  432. package/dist/styling/spacing-scale.js.map +1 -0
  433. package/dist/styling/tailwind-patterns.d.ts +305 -0
  434. package/dist/styling/tailwind-patterns.d.ts.map +1 -0
  435. package/dist/styling/tailwind-patterns.js +1181 -0
  436. package/dist/styling/tailwind-patterns.js.map +1 -0
  437. package/dist/styling/typography.d.ts +281 -0
  438. package/dist/styling/typography.d.ts.map +1 -0
  439. package/dist/styling/typography.js +1004 -0
  440. package/dist/styling/typography.js.map +1 -0
  441. package/dist/styling/z-index-scale.d.ts +270 -0
  442. package/dist/styling/z-index-scale.d.ts.map +1 -0
  443. package/dist/styling/z-index-scale.js +714 -0
  444. package/dist/styling/z-index-scale.js.map +1 -0
  445. package/dist/testing/co-location.d.ts +42 -0
  446. package/dist/testing/co-location.d.ts.map +1 -0
  447. package/dist/testing/co-location.js +134 -0
  448. package/dist/testing/co-location.js.map +1 -0
  449. package/dist/testing/describe-naming.d.ts +47 -0
  450. package/dist/testing/describe-naming.d.ts.map +1 -0
  451. package/dist/testing/describe-naming.js +150 -0
  452. package/dist/testing/describe-naming.js.map +1 -0
  453. package/dist/testing/file-naming.d.ts +44 -0
  454. package/dist/testing/file-naming.d.ts.map +1 -0
  455. package/dist/testing/file-naming.js +131 -0
  456. package/dist/testing/file-naming.js.map +1 -0
  457. package/dist/testing/fixture-patterns.d.ts +52 -0
  458. package/dist/testing/fixture-patterns.d.ts.map +1 -0
  459. package/dist/testing/fixture-patterns.js +228 -0
  460. package/dist/testing/fixture-patterns.js.map +1 -0
  461. package/dist/testing/index.d.ts +31 -0
  462. package/dist/testing/index.d.ts.map +1 -0
  463. package/dist/testing/index.js +49 -0
  464. package/dist/testing/index.js.map +1 -0
  465. package/dist/testing/mock-patterns.d.ts +53 -0
  466. package/dist/testing/mock-patterns.d.ts.map +1 -0
  467. package/dist/testing/mock-patterns.js +264 -0
  468. package/dist/testing/mock-patterns.js.map +1 -0
  469. package/dist/testing/setup-teardown.d.ts +55 -0
  470. package/dist/testing/setup-teardown.d.ts.map +1 -0
  471. package/dist/testing/setup-teardown.js +262 -0
  472. package/dist/testing/setup-teardown.js.map +1 -0
  473. package/dist/testing/test-structure.d.ts +51 -0
  474. package/dist/testing/test-structure.d.ts.map +1 -0
  475. package/dist/testing/test-structure.js +225 -0
  476. package/dist/testing/test-structure.js.map +1 -0
  477. package/dist/types/any-usage.d.ts +99 -0
  478. package/dist/types/any-usage.d.ts.map +1 -0
  479. package/dist/types/any-usage.js +641 -0
  480. package/dist/types/any-usage.js.map +1 -0
  481. package/dist/types/file-location.d.ts +76 -0
  482. package/dist/types/file-location.d.ts.map +1 -0
  483. package/dist/types/file-location.js +395 -0
  484. package/dist/types/file-location.js.map +1 -0
  485. package/dist/types/generic-patterns.d.ts +97 -0
  486. package/dist/types/generic-patterns.d.ts.map +1 -0
  487. package/dist/types/generic-patterns.js +615 -0
  488. package/dist/types/generic-patterns.js.map +1 -0
  489. package/dist/types/index.d.ts +31 -0
  490. package/dist/types/index.d.ts.map +1 -0
  491. package/dist/types/index.js +43 -0
  492. package/dist/types/index.js.map +1 -0
  493. package/dist/types/interface-vs-type.d.ts +81 -0
  494. package/dist/types/interface-vs-type.d.ts.map +1 -0
  495. package/dist/types/interface-vs-type.js +440 -0
  496. package/dist/types/interface-vs-type.js.map +1 -0
  497. package/dist/types/naming-conventions.d.ts +84 -0
  498. package/dist/types/naming-conventions.d.ts.map +1 -0
  499. package/dist/types/naming-conventions.js +455 -0
  500. package/dist/types/naming-conventions.js.map +1 -0
  501. package/dist/types/type-assertions.d.ts +98 -0
  502. package/dist/types/type-assertions.d.ts.map +1 -0
  503. package/dist/types/type-assertions.js +639 -0
  504. package/dist/types/type-assertions.js.map +1 -0
  505. package/dist/types/utility-types.d.ts +110 -0
  506. package/dist/types/utility-types.d.ts.map +1 -0
  507. package/dist/types/utility-types.js +547 -0
  508. package/dist/types/utility-types.js.map +1 -0
  509. package/package.json +44 -0
@@ -0,0 +1,832 @@
1
+ /**
2
+ * Ref Forwarding Detector - Ref forwarding pattern detection
3
+ *
4
+ * Detects ref forwarding patterns including React.forwardRef usage,
5
+ * useImperativeHandle, ref prop forwarding, callback refs, and ref merging.
6
+ * Identifies issues and suggests improvements.
7
+ *
8
+ * @requirements 8.7 - THE Component_Detector SHALL detect ref forwarding patterns
9
+ */
10
+ import { ASTDetector } from '../base/index.js';
11
+ // ============================================================================
12
+ // Constants
13
+ // ============================================================================
14
+ /**
15
+ * Default configuration for ref forwarding detection
16
+ */
17
+ export const DEFAULT_REF_FORWARDING_CONFIG = {
18
+ maxImperativeHandleMethods: 5,
19
+ flagUnusedRefs: true,
20
+ flagMissingForwardRef: true,
21
+ };
22
+ /**
23
+ * Common ref-related hook names
24
+ */
25
+ export const REF_HOOKS = ['useRef', 'useImperativeHandle', 'useCallback'];
26
+ /**
27
+ * DOM element names that commonly receive refs
28
+ */
29
+ export const DOM_ELEMENTS_WITH_REFS = [
30
+ 'input', 'textarea', 'select', 'button', 'form',
31
+ 'div', 'span', 'section', 'article', 'nav', 'header', 'footer',
32
+ 'canvas', 'video', 'audio', 'img', 'iframe',
33
+ 'table', 'tbody', 'thead', 'tr', 'td', 'th',
34
+ 'ul', 'ol', 'li', 'a', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
35
+ ];
36
+ // ============================================================================
37
+ // Helper Functions - Component Detection
38
+ // ============================================================================
39
+ /**
40
+ * Check if a node represents a React component
41
+ */
42
+ export function isReactComponent(node, content) {
43
+ if (node.type === 'function_declaration' ||
44
+ node.type === 'arrow_function' ||
45
+ node.type === 'function_expression') {
46
+ const name = getComponentName(node, content);
47
+ if (!name || !/^[A-Z]/.test(name)) {
48
+ return false;
49
+ }
50
+ const nodeText = node.text;
51
+ return nodeText.includes('<') && (nodeText.includes('/>') || nodeText.includes('</'));
52
+ }
53
+ return false;
54
+ }
55
+ /**
56
+ * Get the component name from a node
57
+ */
58
+ export function getComponentName(node, content) {
59
+ if (node.type === 'function_declaration') {
60
+ const nameNode = node.children.find(c => c.type === 'identifier');
61
+ return nameNode?.text;
62
+ }
63
+ const lines = content.split('\n');
64
+ const line = lines[node.startPosition.row];
65
+ if (line) {
66
+ const match = line.match(/(?:const|let|var|export\s+(?:const|let|var)?)\s+([A-Z][a-zA-Z0-9]*)\s*[=:]/);
67
+ if (match && match[1]) {
68
+ return match[1];
69
+ }
70
+ }
71
+ return undefined;
72
+ }
73
+ // ============================================================================
74
+ // Helper Functions - forwardRef Detection
75
+ // ============================================================================
76
+ /**
77
+ * Detect React.forwardRef usage in content
78
+ */
79
+ export function detectForwardRef(content) {
80
+ const results = [];
81
+ // Pattern 1: const Component = forwardRef((props, ref) => ...)
82
+ const forwardRefPattern = /(?:const|let|var)\s+([A-Z][a-zA-Z0-9]*)\s*=\s*(?:React\.)?forwardRef\s*(?:<[^>]*>)?\s*\(\s*(?:\([^)]*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\)|function\s*\([^)]*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\))/g;
83
+ let match;
84
+ while ((match = forwardRefPattern.exec(content)) !== null) {
85
+ const beforeMatch = content.slice(0, match.index);
86
+ const line = beforeMatch.split('\n').length;
87
+ const refName = match[2] || match[3] || 'ref';
88
+ results.push({
89
+ pattern: 'forwardRef',
90
+ variableName: refName,
91
+ line,
92
+ column: 1,
93
+ forwardedToDOM: false,
94
+ forwardedToChild: false,
95
+ });
96
+ }
97
+ // Pattern 2: export default forwardRef(...)
98
+ const exportForwardRefPattern = /export\s+default\s+(?:React\.)?forwardRef\s*(?:<[^>]*>)?\s*\(/g;
99
+ while ((match = exportForwardRefPattern.exec(content)) !== null) {
100
+ const beforeMatch = content.slice(0, match.index);
101
+ const line = beforeMatch.split('\n').length;
102
+ results.push({
103
+ pattern: 'forwardRef',
104
+ variableName: 'ref',
105
+ line,
106
+ column: 1,
107
+ forwardedToDOM: false,
108
+ forwardedToChild: false,
109
+ });
110
+ }
111
+ return results;
112
+ }
113
+ /**
114
+ * Check if component is wrapped with forwardRef
115
+ */
116
+ export function isWrappedWithForwardRef(content, componentName) {
117
+ // Check for: const Component = forwardRef(...)
118
+ const pattern1 = new RegExp(`const\\s+${componentName}\\s*=\\s*(?:React\\.)?forwardRef`);
119
+ // Check for: export default forwardRef(Component)
120
+ const pattern2 = new RegExp(`export\\s+default\\s+(?:React\\.)?forwardRef\\s*\\(\\s*${componentName}`);
121
+ // Check for: forwardRef<...>((props, ref) => ...) assigned to component
122
+ const pattern3 = new RegExp(`${componentName}\\s*=\\s*(?:React\\.)?forwardRef`);
123
+ return pattern1.test(content) || pattern2.test(content) || pattern3.test(content);
124
+ }
125
+ // ============================================================================
126
+ // Helper Functions - useImperativeHandle Detection
127
+ // ============================================================================
128
+ /**
129
+ * Detect useImperativeHandle usage in content
130
+ */
131
+ export function detectUseImperativeHandle(content) {
132
+ const results = [];
133
+ // Pattern: useImperativeHandle(ref, () => ({ method1, method2 }), [deps])
134
+ const imperativePattern = /useImperativeHandle\s*\(\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*\(\)\s*=>\s*\(\s*\{([^}]*)\}/g;
135
+ let match;
136
+ while ((match = imperativePattern.exec(content)) !== null) {
137
+ const beforeMatch = content.slice(0, match.index);
138
+ const line = beforeMatch.split('\n').length;
139
+ const refName = match[1] || 'ref';
140
+ const methodsStr = match[2] || '';
141
+ // Extract method names
142
+ const methods = methodsStr
143
+ .split(',')
144
+ .map(m => m.trim().split(':')[0]?.trim() || '')
145
+ .filter(m => m && /^[a-zA-Z_$]/.test(m));
146
+ results.push({
147
+ pattern: 'useImperativeHandle',
148
+ variableName: refName,
149
+ line,
150
+ column: 1,
151
+ forwardedToDOM: false,
152
+ forwardedToChild: false,
153
+ exposedMethods: methods,
154
+ });
155
+ }
156
+ // Simpler pattern without extracting methods
157
+ const simplePattern = /useImperativeHandle\s*\(\s*([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
158
+ while ((match = simplePattern.exec(content)) !== null) {
159
+ const beforeMatch = content.slice(0, match.index);
160
+ const line = beforeMatch.split('\n').length;
161
+ const refName = match[1] || 'ref';
162
+ // Check if we already have this one
163
+ if (!results.some(r => r.line === line && r.pattern === 'useImperativeHandle')) {
164
+ results.push({
165
+ pattern: 'useImperativeHandle',
166
+ variableName: refName,
167
+ line,
168
+ column: 1,
169
+ forwardedToDOM: false,
170
+ forwardedToChild: false,
171
+ });
172
+ }
173
+ }
174
+ return results;
175
+ }
176
+ /**
177
+ * Check if useImperativeHandle is used without forwardRef
178
+ */
179
+ export function hasImperativeWithoutForwardRef(content) {
180
+ const hasImperative = /useImperativeHandle\s*\(/.test(content);
181
+ const hasForwardRef = /(?:React\.)?forwardRef\s*[(<]/.test(content);
182
+ return hasImperative && !hasForwardRef;
183
+ }
184
+ // ============================================================================
185
+ // Helper Functions - useRef Detection
186
+ // ============================================================================
187
+ /**
188
+ * Detect useRef usage in content
189
+ */
190
+ export function detectUseRef(content) {
191
+ const results = [];
192
+ // Pattern: const ref = useRef<Type>(initial)
193
+ const useRefPattern = /const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*useRef\s*(?:<([^>]*)>)?\s*\(([^)]*)\)/g;
194
+ let match;
195
+ while ((match = useRefPattern.exec(content)) !== null) {
196
+ const beforeMatch = content.slice(0, match.index);
197
+ const line = beforeMatch.split('\n').length;
198
+ const refName = match[1] || 'ref';
199
+ const typeAnnotation = match[2] || '';
200
+ const initialValue = match[3] || '';
201
+ // Determine if this is a DOM ref or mutable ref
202
+ const isDOMRef = initialValue.trim() === 'null' ||
203
+ typeAnnotation.includes('Element') ||
204
+ typeAnnotation.includes('HTML');
205
+ // Check if ref is used on a DOM element
206
+ const refUsagePattern = new RegExp(`ref\\s*=\\s*\\{\\s*${refName}\\s*\\}`);
207
+ const forwardedToDOM = refUsagePattern.test(content);
208
+ results.push({
209
+ pattern: isDOMRef ? 'useRef-dom' : 'useRef-mutable',
210
+ variableName: refName,
211
+ line,
212
+ column: 1,
213
+ forwardedToDOM,
214
+ forwardedToChild: false,
215
+ });
216
+ }
217
+ return results;
218
+ }
219
+ /**
220
+ * Check if a ref is used in the component
221
+ */
222
+ export function isRefUsed(content, refName) {
223
+ // Check for ref={refName} or ref.current
224
+ const usagePattern = new RegExp(`ref\\s*=\\s*\\{\\s*${refName}\\s*\\}|${refName}\\.current`, 'g');
225
+ return usagePattern.test(content);
226
+ }
227
+ // ============================================================================
228
+ // Helper Functions - Ref Prop Forwarding Detection
229
+ // ============================================================================
230
+ /**
231
+ * Detect ref prop forwarding to DOM elements
232
+ */
233
+ export function detectRefPropToDom(content) {
234
+ const results = [];
235
+ // Pattern: <element ref={ref} /> or <element ref={props.ref} />
236
+ const domRefPattern = /<([a-z][a-zA-Z0-9]*)[^>]*\s+ref\s*=\s*\{([^}]+)\}/g;
237
+ let match;
238
+ while ((match = domRefPattern.exec(content)) !== null) {
239
+ const beforeMatch = content.slice(0, match.index);
240
+ const line = beforeMatch.split('\n').length;
241
+ const elementName = match[1] || '';
242
+ const refValue = match[2]?.trim() || '';
243
+ // Only count if it's a DOM element (lowercase)
244
+ if (DOM_ELEMENTS_WITH_REFS.includes(elementName.toLowerCase())) {
245
+ results.push({
246
+ pattern: 'ref-prop-to-dom',
247
+ variableName: refValue,
248
+ line,
249
+ column: 1,
250
+ forwardedToDOM: true,
251
+ forwardedToChild: false,
252
+ targetName: elementName,
253
+ });
254
+ }
255
+ }
256
+ return results;
257
+ }
258
+ /**
259
+ * Detect ref prop forwarding to child components
260
+ */
261
+ export function detectRefPropToChild(content) {
262
+ const results = [];
263
+ // Pattern: <Component ref={ref} /> (PascalCase component)
264
+ const childRefPattern = /<([A-Z][a-zA-Z0-9]*)[^>]*\s+ref\s*=\s*\{([^}]+)\}/g;
265
+ let match;
266
+ while ((match = childRefPattern.exec(content)) !== null) {
267
+ const beforeMatch = content.slice(0, match.index);
268
+ const line = beforeMatch.split('\n').length;
269
+ const componentName = match[1] || '';
270
+ const refValue = match[2]?.trim() || '';
271
+ results.push({
272
+ pattern: 'ref-prop-to-child',
273
+ variableName: refValue,
274
+ line,
275
+ column: 1,
276
+ forwardedToDOM: false,
277
+ forwardedToChild: true,
278
+ targetName: componentName,
279
+ });
280
+ }
281
+ return results;
282
+ }
283
+ // ============================================================================
284
+ // Helper Functions - Callback Ref Detection
285
+ // ============================================================================
286
+ /**
287
+ * Detect callback ref patterns
288
+ */
289
+ export function detectCallbackRef(content) {
290
+ const results = [];
291
+ // Pattern 1: ref={(el) => ...} or ref={el => ...}
292
+ const inlineCallbackPattern = /ref\s*=\s*\{\s*\(?([a-zA-Z_$][a-zA-Z0-9_$]*)\)?\s*=>/g;
293
+ let match;
294
+ while ((match = inlineCallbackPattern.exec(content)) !== null) {
295
+ const beforeMatch = content.slice(0, match.index);
296
+ const line = beforeMatch.split('\n').length;
297
+ const paramName = match[1] || 'el';
298
+ results.push({
299
+ pattern: 'callback-ref',
300
+ variableName: paramName,
301
+ line,
302
+ column: 1,
303
+ forwardedToDOM: false,
304
+ forwardedToChild: false,
305
+ });
306
+ }
307
+ // Pattern 2: ref={callbackRef} where callbackRef is a function
308
+ // This is harder to detect without type info, so we look for common patterns
309
+ const callbackRefPattern = /const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*(?:useCallback\s*\(\s*)?\(?([a-zA-Z_$][a-zA-Z0-9_$]*)\)?\s*=>\s*\{[^}]*\.\s*current\s*=/g;
310
+ while ((match = callbackRefPattern.exec(content)) !== null) {
311
+ const beforeMatch = content.slice(0, match.index);
312
+ const line = beforeMatch.split('\n').length;
313
+ const refName = match[1] || 'callbackRef';
314
+ results.push({
315
+ pattern: 'callback-ref',
316
+ variableName: refName,
317
+ line,
318
+ column: 1,
319
+ forwardedToDOM: false,
320
+ forwardedToChild: false,
321
+ });
322
+ }
323
+ return results;
324
+ }
325
+ // ============================================================================
326
+ // Helper Functions - Ref Merging Detection
327
+ // ============================================================================
328
+ /**
329
+ * Detect ref merging patterns (multiple refs combined)
330
+ */
331
+ export function detectRefMerging(content) {
332
+ const results = [];
333
+ // Pattern 1: useMergeRefs or mergeRefs utility
334
+ const mergeRefsPattern = /(?:useMergeRefs|mergeRefs)\s*\(\s*\[([^\]]+)\]/g;
335
+ let match;
336
+ while ((match = mergeRefsPattern.exec(content)) !== null) {
337
+ const beforeMatch = content.slice(0, match.index);
338
+ const line = beforeMatch.split('\n').length;
339
+ const refsStr = match[1] || '';
340
+ const refs = refsStr.split(',').map(r => r.trim()).filter(r => r);
341
+ results.push({
342
+ pattern: 'ref-merging',
343
+ variableName: refs.join(', '),
344
+ line,
345
+ column: 1,
346
+ forwardedToDOM: false,
347
+ forwardedToChild: false,
348
+ });
349
+ }
350
+ // Pattern 2: Callback ref that assigns to multiple refs
351
+ const multiAssignPattern = /ref\s*=\s*\{\s*\(?([a-zA-Z_$][a-zA-Z0-9_$]*)\)?\s*=>\s*\{[^}]*\.current\s*=[^}]*\.current\s*=/g;
352
+ while ((match = multiAssignPattern.exec(content)) !== null) {
353
+ const beforeMatch = content.slice(0, match.index);
354
+ const line = beforeMatch.split('\n').length;
355
+ results.push({
356
+ pattern: 'ref-merging',
357
+ variableName: 'merged',
358
+ line,
359
+ column: 1,
360
+ forwardedToDOM: false,
361
+ forwardedToChild: false,
362
+ });
363
+ }
364
+ // Pattern 3: composeRefs utility
365
+ const composeRefsPattern = /composeRefs\s*\(/g;
366
+ while ((match = composeRefsPattern.exec(content)) !== null) {
367
+ const beforeMatch = content.slice(0, match.index);
368
+ const line = beforeMatch.split('\n').length;
369
+ results.push({
370
+ pattern: 'ref-merging',
371
+ variableName: 'composed',
372
+ line,
373
+ column: 1,
374
+ forwardedToDOM: false,
375
+ forwardedToChild: false,
376
+ });
377
+ }
378
+ return results;
379
+ }
380
+ // ============================================================================
381
+ // Helper Functions - Issue Detection
382
+ // ============================================================================
383
+ /**
384
+ * Check if component accepts ref prop but doesn't use forwardRef
385
+ */
386
+ export function detectMissingForwardRef(content) {
387
+ // Check if component has ref in props
388
+ const hasRefProp = /\(\s*\{[^}]*\bref\b[^}]*\}/.test(content) ||
389
+ /props\.ref/.test(content);
390
+ // Check if wrapped with forwardRef
391
+ const hasForwardRef = /(?:React\.)?forwardRef\s*[(<]/.test(content);
392
+ return hasRefProp && !hasForwardRef;
393
+ }
394
+ /**
395
+ * Detect ref forwarding issues in a component
396
+ */
397
+ export function detectRefIssues(content, refUsages, config) {
398
+ const issues = [];
399
+ // Check for useImperativeHandle without forwardRef
400
+ if (hasImperativeWithoutForwardRef(content)) {
401
+ const imperativeUsage = refUsages.find(r => r.pattern === 'useImperativeHandle');
402
+ issues.push({
403
+ type: 'imperative-without-forwardRef',
404
+ description: 'useImperativeHandle is used without forwardRef wrapper',
405
+ severity: 'error',
406
+ suggestion: 'Wrap the component with React.forwardRef to properly expose imperative methods',
407
+ line: imperativeUsage?.line || 1,
408
+ column: 1,
409
+ });
410
+ }
411
+ // Check for excessive imperative handle methods
412
+ for (const usage of refUsages) {
413
+ if (usage.pattern === 'useImperativeHandle' && usage.exposedMethods) {
414
+ if (usage.exposedMethods.length > config.maxImperativeHandleMethods) {
415
+ issues.push({
416
+ type: 'excessive-imperative-handle',
417
+ description: `useImperativeHandle exposes ${usage.exposedMethods.length} methods (max: ${config.maxImperativeHandleMethods})`,
418
+ severity: 'warning',
419
+ suggestion: 'Consider reducing the number of exposed methods or using a different pattern',
420
+ line: usage.line,
421
+ column: 1,
422
+ });
423
+ }
424
+ }
425
+ }
426
+ // Check for missing forwardRef
427
+ if (config.flagMissingForwardRef && detectMissingForwardRef(content)) {
428
+ issues.push({
429
+ type: 'missing-forwardRef',
430
+ description: 'Component accepts ref prop but is not wrapped with forwardRef',
431
+ severity: 'warning',
432
+ suggestion: 'Wrap the component with React.forwardRef to properly forward refs',
433
+ line: 1,
434
+ column: 1,
435
+ });
436
+ }
437
+ // Check for unused refs
438
+ if (config.flagUnusedRefs) {
439
+ for (const usage of refUsages) {
440
+ if ((usage.pattern === 'useRef-dom' || usage.pattern === 'useRef-mutable') &&
441
+ !isRefUsed(content, usage.variableName)) {
442
+ issues.push({
443
+ type: 'unused-ref',
444
+ description: `Ref '${usage.variableName}' is declared but never used`,
445
+ severity: 'info',
446
+ suggestion: 'Remove the unused ref or use it in the component',
447
+ line: usage.line,
448
+ column: 1,
449
+ });
450
+ }
451
+ }
452
+ }
453
+ return issues;
454
+ }
455
+ // ============================================================================
456
+ // Helper Functions - Analysis
457
+ // ============================================================================
458
+ /**
459
+ * Collect all ref usages from content
460
+ */
461
+ export function collectRefUsages(content) {
462
+ return [
463
+ ...detectForwardRef(content),
464
+ ...detectUseImperativeHandle(content),
465
+ ...detectUseRef(content),
466
+ ...detectRefPropToDom(content),
467
+ ...detectRefPropToChild(content),
468
+ ...detectCallbackRef(content),
469
+ ...detectRefMerging(content),
470
+ ];
471
+ }
472
+ /**
473
+ * Analyze a single component's ref patterns
474
+ */
475
+ export function analyzeComponentRefs(nodeText, content, filePath, componentName, line, config) {
476
+ const refUsages = collectRefUsages(nodeText);
477
+ const issues = detectRefIssues(nodeText, refUsages, config);
478
+ const usesForwardRef = refUsages.some(r => r.pattern === 'forwardRef');
479
+ const usesImperativeHandle = refUsages.some(r => r.pattern === 'useImperativeHandle');
480
+ const acceptsRefProp = /\(\s*\{[^}]*\bref\b[^}]*\}/.test(nodeText) ||
481
+ /props\.ref/.test(nodeText) ||
482
+ /,\s*ref\s*\)/.test(nodeText);
483
+ return {
484
+ componentName,
485
+ filePath,
486
+ line,
487
+ column: 1,
488
+ usesForwardRef,
489
+ usesImperativeHandle,
490
+ refUsages,
491
+ issues,
492
+ acceptsRefProp,
493
+ isWrappedWithForwardRef: isWrappedWithForwardRef(content, componentName),
494
+ };
495
+ }
496
+ /**
497
+ * Find dominant pattern from a list
498
+ */
499
+ function findDominantPattern(patterns) {
500
+ const counts = new Map();
501
+ for (const pattern of patterns) {
502
+ if (pattern !== 'none') {
503
+ counts.set(pattern, (counts.get(pattern) || 0) + 1);
504
+ }
505
+ }
506
+ let dominant = 'none';
507
+ let maxCount = 0;
508
+ for (const [pattern, count] of counts) {
509
+ if (count > maxCount) {
510
+ maxCount = count;
511
+ dominant = pattern;
512
+ }
513
+ }
514
+ const total = patterns.filter(p => p !== 'none').length;
515
+ const confidence = total > 0 ? maxCount / total : 0;
516
+ return { dominant, confidence };
517
+ }
518
+ /**
519
+ * Analyze ref forwarding patterns across multiple components
520
+ */
521
+ export function analyzeRefForwardingPatterns(components) {
522
+ if (components.length === 0) {
523
+ return {
524
+ components: [],
525
+ dominantPattern: 'none',
526
+ patternCounts: {
527
+ 'forwardRef': 0,
528
+ 'useImperativeHandle': 0,
529
+ 'ref-prop-to-dom': 0,
530
+ 'ref-prop-to-child': 0,
531
+ 'callback-ref': 0,
532
+ 'useRef-dom': 0,
533
+ 'useRef-mutable': 0,
534
+ 'ref-merging': 0,
535
+ 'none': 0,
536
+ },
537
+ confidence: 0,
538
+ componentsWithIssues: [],
539
+ healthScore: 1.0,
540
+ };
541
+ }
542
+ // Collect all patterns
543
+ const allPatterns = [];
544
+ const patternCounts = {
545
+ 'forwardRef': 0,
546
+ 'useImperativeHandle': 0,
547
+ 'ref-prop-to-dom': 0,
548
+ 'ref-prop-to-child': 0,
549
+ 'callback-ref': 0,
550
+ 'useRef-dom': 0,
551
+ 'useRef-mutable': 0,
552
+ 'ref-merging': 0,
553
+ 'none': 0,
554
+ };
555
+ for (const comp of components) {
556
+ for (const usage of comp.refUsages) {
557
+ allPatterns.push(usage.pattern);
558
+ patternCounts[usage.pattern]++;
559
+ }
560
+ if (comp.refUsages.length === 0) {
561
+ patternCounts['none']++;
562
+ }
563
+ }
564
+ // Find dominant pattern
565
+ const { dominant, confidence } = findDominantPattern(allPatterns);
566
+ // Find components with issues
567
+ const componentsWithIssues = components.filter(c => c.issues.length > 0);
568
+ // Calculate health score
569
+ let healthScore = 1.0;
570
+ const totalIssues = components.reduce((sum, c) => sum + c.issues.length, 0);
571
+ if (totalIssues > 0) {
572
+ healthScore = Math.max(0, 1 - (totalIssues * 0.1));
573
+ }
574
+ return {
575
+ components,
576
+ dominantPattern: dominant,
577
+ patternCounts,
578
+ confidence,
579
+ componentsWithIssues,
580
+ healthScore,
581
+ };
582
+ }
583
+ // ============================================================================
584
+ // Pattern Description Helpers
585
+ // ============================================================================
586
+ const PATTERN_DESCRIPTIONS = {
587
+ 'forwardRef': 'React.forwardRef wrapper',
588
+ 'useImperativeHandle': 'useImperativeHandle hook',
589
+ 'ref-prop-to-dom': 'ref forwarded to DOM element',
590
+ 'ref-prop-to-child': 'ref forwarded to child component',
591
+ 'callback-ref': 'callback ref pattern',
592
+ 'useRef-dom': 'useRef for DOM access',
593
+ 'useRef-mutable': 'useRef for mutable values',
594
+ 'ref-merging': 'multiple refs merged',
595
+ 'none': 'no ref pattern',
596
+ };
597
+ const ISSUE_DESCRIPTIONS = {
598
+ 'missing-forwardRef': 'missing forwardRef wrapper',
599
+ 'incorrect-ref-typing': 'incorrect ref typing',
600
+ 'ref-not-forwarded': 'ref not forwarded to element',
601
+ 'imperative-without-forwardRef': 'useImperativeHandle without forwardRef',
602
+ 'excessive-imperative-handle': 'too many methods exposed via useImperativeHandle',
603
+ 'unused-ref': 'unused ref declaration',
604
+ 'ref-in-render': 'ref accessed during render',
605
+ };
606
+ /**
607
+ * Get human-readable description for a pattern
608
+ */
609
+ export function getPatternDescription(pattern) {
610
+ return PATTERN_DESCRIPTIONS[pattern] || pattern;
611
+ }
612
+ /**
613
+ * Get human-readable description for an issue
614
+ */
615
+ export function getIssueDescription(issue) {
616
+ return ISSUE_DESCRIPTIONS[issue] || issue;
617
+ }
618
+ // ============================================================================
619
+ // Ref Forwarding Detector Class
620
+ // ============================================================================
621
+ /**
622
+ * Detector for ref forwarding patterns
623
+ *
624
+ * Identifies ref forwarding patterns including forwardRef, useImperativeHandle,
625
+ * ref prop forwarding, callback refs, and ref merging. Reports issues when
626
+ * components don't follow best practices.
627
+ *
628
+ * @requirements 8.7 - THE Component_Detector SHALL detect ref forwarding patterns
629
+ */
630
+ export class RefForwardingDetector extends ASTDetector {
631
+ id = 'components/ref-forwarding';
632
+ category = 'components';
633
+ subcategory = 'ref-forwarding';
634
+ name = 'Ref Forwarding Detector';
635
+ description = 'Detects ref forwarding patterns and identifies issues with ref handling';
636
+ supportedLanguages = ['typescript', 'javascript'];
637
+ config;
638
+ constructor(config = {}) {
639
+ super();
640
+ this.config = { ...DEFAULT_REF_FORWARDING_CONFIG, ...config };
641
+ }
642
+ /**
643
+ * Detect ref forwarding patterns in the project
644
+ */
645
+ async detect(context) {
646
+ const patterns = [];
647
+ const violations = [];
648
+ // Find all components in the file
649
+ const componentInfos = this.findComponentsInFile(context);
650
+ if (componentInfos.length === 0) {
651
+ return this.createEmptyResult();
652
+ }
653
+ // Analyze patterns across all components
654
+ const analysis = analyzeRefForwardingPatterns(componentInfos);
655
+ // Create pattern matches for detected patterns
656
+ for (const [pattern, count] of Object.entries(analysis.patternCounts)) {
657
+ if (count > 0 && pattern !== 'none') {
658
+ patterns.push(this.createPatternMatch(context.file, pattern, count, analysis));
659
+ }
660
+ }
661
+ // Generate violations for components with issues in current file
662
+ for (const comp of analysis.componentsWithIssues) {
663
+ if (comp.filePath === context.file) {
664
+ for (const issue of comp.issues) {
665
+ violations.push(this.createViolation(context.file, comp, issue));
666
+ }
667
+ }
668
+ }
669
+ return this.createResult(patterns, violations, analysis.confidence);
670
+ }
671
+ /**
672
+ * Find all React components in a file
673
+ */
674
+ findComponentsInFile(context) {
675
+ const components = [];
676
+ if (context.ast) {
677
+ // Use AST to find components
678
+ const functionNodes = this.findNodesByTypes(context.ast, [
679
+ 'function_declaration',
680
+ 'arrow_function',
681
+ 'function_expression',
682
+ ]);
683
+ for (const node of functionNodes) {
684
+ if (isReactComponent(node, context.content)) {
685
+ const componentName = getComponentName(node, context.content);
686
+ if (componentName) {
687
+ const info = analyzeComponentRefs(node.text, context.content, context.file, componentName, node.startPosition.row + 1, this.config);
688
+ components.push(info);
689
+ }
690
+ }
691
+ }
692
+ }
693
+ else {
694
+ // Fallback: use regex-based detection
695
+ const componentMatches = this.findComponentsWithRegex(context.content, context.file);
696
+ components.push(...componentMatches);
697
+ }
698
+ return components;
699
+ }
700
+ /**
701
+ * Find components using regex (fallback when AST is not available)
702
+ */
703
+ findComponentsWithRegex(content, filePath) {
704
+ const components = [];
705
+ const seenComponents = new Set();
706
+ // Arrow function: const Button = (...) => ...
707
+ const arrowPattern = /(?:export\s+)?const\s+([A-Z][a-zA-Z0-9]*)\s*(?::\s*[^=]+)?\s*=\s*(?:React\.)?(?:forwardRef\s*(?:<[^>]*>)?\s*\()?\s*\(/g;
708
+ // Function declaration: function Button(...) { ... }
709
+ const functionPattern = /(?:export\s+)?function\s+([A-Z][a-zA-Z0-9]*)\s*\(/g;
710
+ const processMatch = (match, _pattern) => {
711
+ const componentName = match[1];
712
+ if (!componentName || seenComponents.has(componentName))
713
+ return;
714
+ const beforeMatch = content.slice(0, match.index);
715
+ const lineNumber = beforeMatch.split('\n').length;
716
+ // Get component body (simplified)
717
+ const startIndex = match.index;
718
+ const endIndex = Math.min(startIndex + 5000, content.length);
719
+ const componentText = content.slice(startIndex, endIndex);
720
+ // Check if it looks like a React component
721
+ if (componentText.includes('<') && (componentText.includes('/>') || componentText.includes('</'))) {
722
+ seenComponents.add(componentName);
723
+ const info = analyzeComponentRefs(componentText, content, filePath, componentName, lineNumber, this.config);
724
+ components.push(info);
725
+ }
726
+ };
727
+ let match;
728
+ while ((match = arrowPattern.exec(content)) !== null) {
729
+ processMatch(match, arrowPattern);
730
+ }
731
+ while ((match = functionPattern.exec(content)) !== null) {
732
+ processMatch(match, functionPattern);
733
+ }
734
+ return components;
735
+ }
736
+ /**
737
+ * Create a pattern match for a ref pattern
738
+ */
739
+ createPatternMatch(file, pattern, count, analysis) {
740
+ const total = Object.values(analysis.patternCounts).reduce((a, b) => a + b, 0) - analysis.patternCounts['none'];
741
+ const confidence = total > 0 ? count / total : 0;
742
+ return {
743
+ patternId: `ref-forwarding-${pattern}`,
744
+ location: { file, line: 1, column: 1 },
745
+ confidence,
746
+ isOutlier: confidence < 0.2,
747
+ };
748
+ }
749
+ /**
750
+ * Create a violation for a ref issue
751
+ */
752
+ createViolation(file, component, issue) {
753
+ const range = {
754
+ start: { line: issue.line, character: issue.column },
755
+ end: { line: issue.line, character: issue.column + 10 },
756
+ };
757
+ const quickFix = this.generateQuickFixForIssue(issue, component);
758
+ const violation = {
759
+ id: `ref-forwarding-${component.componentName}-${issue.type}-${file.replace(/[^a-zA-Z0-9]/g, '-')}`,
760
+ patternId: 'components/ref-forwarding',
761
+ severity: issue.severity,
762
+ file,
763
+ range,
764
+ message: `${component.componentName}: ${issue.description}`,
765
+ expected: 'Proper ref forwarding pattern',
766
+ actual: getIssueDescription(issue.type),
767
+ aiExplainAvailable: true,
768
+ aiFixAvailable: true,
769
+ firstSeen: new Date(),
770
+ occurrences: 1,
771
+ };
772
+ if (quickFix) {
773
+ violation.quickFix = quickFix;
774
+ }
775
+ return violation;
776
+ }
777
+ /**
778
+ * Generate a quick fix for a ref issue
779
+ */
780
+ generateQuickFixForIssue(issue, component) {
781
+ switch (issue.type) {
782
+ case 'missing-forwardRef':
783
+ return {
784
+ title: `Wrap ${component.componentName} with forwardRef`,
785
+ kind: 'quickfix',
786
+ edit: { changes: {} },
787
+ isPreferred: true,
788
+ confidence: 0.8,
789
+ preview: `const ${component.componentName} = forwardRef((props, ref) => { ... })`,
790
+ };
791
+ case 'imperative-without-forwardRef':
792
+ return {
793
+ title: `Add forwardRef wrapper to ${component.componentName}`,
794
+ kind: 'quickfix',
795
+ edit: { changes: {} },
796
+ isPreferred: true,
797
+ confidence: 0.9,
798
+ preview: `const ${component.componentName} = forwardRef((props, ref) => { useImperativeHandle(ref, ...) })`,
799
+ };
800
+ case 'unused-ref':
801
+ return {
802
+ title: 'Remove unused ref',
803
+ kind: 'quickfix',
804
+ edit: { changes: {} },
805
+ isPreferred: false,
806
+ confidence: 0.7,
807
+ preview: 'Remove the unused useRef declaration',
808
+ };
809
+ default:
810
+ return undefined;
811
+ }
812
+ }
813
+ /**
814
+ * Generate a quick fix for a violation
815
+ */
816
+ generateQuickFix(violation) {
817
+ if (violation.quickFix) {
818
+ return violation.quickFix;
819
+ }
820
+ return null;
821
+ }
822
+ }
823
+ // ============================================================================
824
+ // Factory Function
825
+ // ============================================================================
826
+ /**
827
+ * Create a new RefForwardingDetector instance
828
+ */
829
+ export function createRefForwardingDetector(config) {
830
+ return new RefForwardingDetector(config);
831
+ }
832
+ //# sourceMappingURL=ref-forwarding.js.map