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,970 @@
1
+ /**
2
+ * State Patterns Detector - State management pattern detection
3
+ *
4
+ * Detects local vs global state usage patterns in React components.
5
+ * Identifies state management inconsistencies and suggests improvements.
6
+ *
7
+ * @requirements 8.5 - THE Component_Detector SHALL detect state management patterns (local vs global)
8
+ */
9
+ import { ASTDetector } from '../base/index.js';
10
+ // ============================================================================
11
+ // Constants
12
+ // ============================================================================
13
+ /**
14
+ * Default configuration for state pattern detection
15
+ */
16
+ export const DEFAULT_STATE_PATTERN_CONFIG = {
17
+ propDrillingThreshold: 3,
18
+ detectServerState: true,
19
+ flagMixedPatterns: true,
20
+ maxLocalStateVariables: 5,
21
+ };
22
+ /**
23
+ * Redux hook patterns
24
+ */
25
+ export const REDUX_HOOKS = ['useSelector', 'useDispatch', 'useStore'];
26
+ /**
27
+ * Zustand hook patterns
28
+ */
29
+ export const ZUSTAND_PATTERNS = [
30
+ /use[A-Z][a-zA-Z]*Store/, // useUserStore, useCartStore, etc.
31
+ /create\s*\(/, // create() from zustand
32
+ ];
33
+ /**
34
+ * Jotai patterns
35
+ */
36
+ export const JOTAI_HOOKS = ['useAtom', 'useAtomValue', 'useSetAtom'];
37
+ /**
38
+ * Recoil patterns
39
+ */
40
+ export const RECOIL_HOOKS = ['useRecoilState', 'useRecoilValue', 'useSetRecoilState', 'useRecoilCallback'];
41
+ /**
42
+ * React Query / TanStack Query patterns
43
+ */
44
+ export const REACT_QUERY_HOOKS = ['useQuery', 'useMutation', 'useInfiniteQuery', 'useQueries'];
45
+ /**
46
+ * SWR patterns
47
+ */
48
+ export const SWR_HOOKS = ['useSWR', 'useSWRMutation', 'useSWRInfinite'];
49
+ /**
50
+ * MobX patterns
51
+ */
52
+ export const MOBX_PATTERNS = ['observer', 'useObserver', 'useLocalObservable'];
53
+ /**
54
+ * Valtio patterns
55
+ */
56
+ export const VALTIO_HOOKS = ['useSnapshot', 'useProxy'];
57
+ // ============================================================================
58
+ // Helper Functions - Component Detection
59
+ // ============================================================================
60
+ /**
61
+ * Check if a node represents a React component
62
+ */
63
+ export function isReactComponent(node, content) {
64
+ if (node.type === 'function_declaration' ||
65
+ node.type === 'arrow_function' ||
66
+ node.type === 'function_expression') {
67
+ const name = getComponentName(node, content);
68
+ if (!name || !/^[A-Z]/.test(name)) {
69
+ return false;
70
+ }
71
+ const nodeText = node.text;
72
+ return nodeText.includes('<') && (nodeText.includes('/>') || nodeText.includes('</'));
73
+ }
74
+ return false;
75
+ }
76
+ /**
77
+ * Get the component name from a node
78
+ */
79
+ export function getComponentName(node, content) {
80
+ if (node.type === 'function_declaration') {
81
+ const nameNode = node.children.find(c => c.type === 'identifier');
82
+ return nameNode?.text;
83
+ }
84
+ const lines = content.split('\n');
85
+ const line = lines[node.startPosition.row];
86
+ if (line) {
87
+ const match = line.match(/(?:const|let|var|export\s+(?:const|let|var)?)\s+([A-Z][a-zA-Z0-9]*)\s*[=:]/);
88
+ if (match && match[1]) {
89
+ return match[1];
90
+ }
91
+ }
92
+ return undefined;
93
+ }
94
+ // ============================================================================
95
+ // Helper Functions - Local State Detection
96
+ // ============================================================================
97
+ /**
98
+ * Detect useState usage in a component
99
+ */
100
+ export function detectUseState(nodeText) {
101
+ const results = [];
102
+ // Match: const [value, setValue] = useState(initial)
103
+ const useStateMatches = nodeText.matchAll(/const\s+\[\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\]\s*=\s*useState\s*(?:<[^>]*>)?\s*\(([^)]*)\)/g);
104
+ for (const match of useStateMatches) {
105
+ if (match[1] && match[2]) {
106
+ const beforeMatch = nodeText.slice(0, match.index);
107
+ const line = beforeMatch.split('\n').length;
108
+ results.push({
109
+ type: 'local',
110
+ pattern: 'useState',
111
+ variableNames: [match[1], match[2]],
112
+ line,
113
+ column: 1,
114
+ derivedFromProps: match[3]?.includes('props') || false,
115
+ });
116
+ }
117
+ }
118
+ return results;
119
+ }
120
+ /**
121
+ * Detect useReducer usage in a component
122
+ */
123
+ export function detectUseReducer(nodeText) {
124
+ const results = [];
125
+ // Match: const [state, dispatch] = useReducer(reducer, initial)
126
+ const useReducerMatches = nodeText.matchAll(/const\s+\[\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\]\s*=\s*useReducer\s*\(/g);
127
+ for (const match of useReducerMatches) {
128
+ if (match[1] && match[2]) {
129
+ const beforeMatch = nodeText.slice(0, match.index);
130
+ const line = beforeMatch.split('\n').length;
131
+ results.push({
132
+ type: 'local',
133
+ pattern: 'useReducer',
134
+ variableNames: [match[1], match[2]],
135
+ line,
136
+ column: 1,
137
+ derivedFromProps: false,
138
+ });
139
+ }
140
+ }
141
+ return results;
142
+ }
143
+ /**
144
+ * Detect useRef usage for mutable values in a component
145
+ */
146
+ export function detectUseRef(nodeText) {
147
+ const results = [];
148
+ // Match: const ref = useRef(initial)
149
+ const useRefMatches = nodeText.matchAll(/const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*useRef\s*(?:<[^>]*>)?\s*\(([^)]*)\)/g);
150
+ for (const match of useRefMatches) {
151
+ if (match[1]) {
152
+ const beforeMatch = nodeText.slice(0, match.index);
153
+ const line = beforeMatch.split('\n').length;
154
+ // Only count as state if it's used for mutable values (not DOM refs)
155
+ const refName = match[1];
156
+ const initialValue = match[2] || '';
157
+ const isDOMRef = initialValue === 'null' && nodeText.includes(`ref={${refName}}`);
158
+ if (!isDOMRef) {
159
+ results.push({
160
+ type: 'local',
161
+ pattern: 'useRef',
162
+ variableNames: [refName],
163
+ line,
164
+ column: 1,
165
+ derivedFromProps: initialValue.includes('props'),
166
+ });
167
+ }
168
+ }
169
+ }
170
+ return results;
171
+ }
172
+ /**
173
+ * Detect all local state patterns in a component
174
+ */
175
+ export function detectLocalState(nodeText) {
176
+ return [
177
+ ...detectUseState(nodeText),
178
+ ...detectUseReducer(nodeText),
179
+ ...detectUseRef(nodeText),
180
+ ];
181
+ }
182
+ // ============================================================================
183
+ // Helper Functions - Global State Detection
184
+ // ============================================================================
185
+ /**
186
+ * Detect useContext usage in a component
187
+ */
188
+ export function detectUseContext(nodeText) {
189
+ const results = [];
190
+ // Match: const value = useContext(SomeContext)
191
+ const useContextMatches = nodeText.matchAll(/const\s+(?:\{([^}]+)\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\s*=\s*useContext\s*\(\s*([A-Z][a-zA-Z0-9]*(?:Context)?)\s*\)/g);
192
+ for (const match of useContextMatches) {
193
+ const beforeMatch = nodeText.slice(0, match.index);
194
+ const line = beforeMatch.split('\n').length;
195
+ // Handle destructured or single variable
196
+ let variableNames = [];
197
+ if (match[1]) {
198
+ // Destructured: const { value1, value2 } = useContext(...)
199
+ variableNames = match[1].split(',').map(v => v.trim().split(':')[0]?.trim() || '').filter(v => v);
200
+ }
201
+ else if (match[2]) {
202
+ // Single variable: const ctx = useContext(...)
203
+ variableNames = [match[2]];
204
+ }
205
+ if (variableNames.length > 0) {
206
+ results.push({
207
+ type: 'global',
208
+ pattern: 'useContext',
209
+ variableNames,
210
+ line,
211
+ column: 1,
212
+ derivedFromProps: false,
213
+ });
214
+ }
215
+ }
216
+ return results;
217
+ }
218
+ /**
219
+ * Detect Redux hooks usage in a component
220
+ */
221
+ export function detectRedux(nodeText) {
222
+ const results = [];
223
+ // Detect useSelector
224
+ const useSelectorMatches = nodeText.matchAll(/const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*useSelector\s*\(/g);
225
+ for (const match of useSelectorMatches) {
226
+ if (match[1]) {
227
+ const beforeMatch = nodeText.slice(0, match.index);
228
+ const line = beforeMatch.split('\n').length;
229
+ results.push({
230
+ type: 'global',
231
+ pattern: 'redux',
232
+ variableNames: [match[1]],
233
+ line,
234
+ column: 1,
235
+ derivedFromProps: false,
236
+ });
237
+ }
238
+ }
239
+ // Detect useDispatch
240
+ const useDispatchMatches = nodeText.matchAll(/const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*useDispatch\s*\(\s*\)/g);
241
+ for (const match of useDispatchMatches) {
242
+ if (match[1]) {
243
+ const beforeMatch = nodeText.slice(0, match.index);
244
+ const line = beforeMatch.split('\n').length;
245
+ results.push({
246
+ type: 'global',
247
+ pattern: 'redux',
248
+ variableNames: [match[1]],
249
+ line,
250
+ column: 1,
251
+ derivedFromProps: false,
252
+ });
253
+ }
254
+ }
255
+ return results;
256
+ }
257
+ /**
258
+ * Detect Zustand store hooks usage in a component
259
+ */
260
+ export function detectZustand(nodeText) {
261
+ const results = [];
262
+ // Match: const value = useXxxStore() or const { a, b } = useXxxStore()
263
+ const zustandMatches = nodeText.matchAll(/const\s+(?:\{([^}]+)\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\s*=\s*(use[A-Z][a-zA-Z]*Store)\s*\(/g);
264
+ for (const match of zustandMatches) {
265
+ const beforeMatch = nodeText.slice(0, match.index);
266
+ const line = beforeMatch.split('\n').length;
267
+ let variableNames = [];
268
+ if (match[1]) {
269
+ variableNames = match[1].split(',').map(v => v.trim().split(':')[0]?.trim() || '').filter(v => v);
270
+ }
271
+ else if (match[2]) {
272
+ variableNames = [match[2]];
273
+ }
274
+ if (variableNames.length > 0) {
275
+ results.push({
276
+ type: 'global',
277
+ pattern: 'zustand',
278
+ variableNames,
279
+ line,
280
+ column: 1,
281
+ derivedFromProps: false,
282
+ });
283
+ }
284
+ }
285
+ return results;
286
+ }
287
+ /**
288
+ * Detect Jotai atoms usage in a component
289
+ */
290
+ export function detectJotai(nodeText) {
291
+ const results = [];
292
+ // Match useAtom, useAtomValue, useSetAtom
293
+ for (const hook of JOTAI_HOOKS) {
294
+ const pattern = new RegExp(`const\\s+(?:\\[([^\\]]+)\\]|([a-zA-Z_$][a-zA-Z0-9_$]*))\\s*=\\s*${hook}\\s*\\(`, 'g');
295
+ const matches = nodeText.matchAll(pattern);
296
+ for (const match of matches) {
297
+ const beforeMatch = nodeText.slice(0, match.index);
298
+ const line = beforeMatch.split('\n').length;
299
+ let variableNames = [];
300
+ if (match[1]) {
301
+ variableNames = match[1].split(',').map(v => v.trim()).filter(v => v);
302
+ }
303
+ else if (match[2]) {
304
+ variableNames = [match[2]];
305
+ }
306
+ if (variableNames.length > 0) {
307
+ results.push({
308
+ type: 'global',
309
+ pattern: 'jotai',
310
+ variableNames,
311
+ line,
312
+ column: 1,
313
+ derivedFromProps: false,
314
+ });
315
+ }
316
+ }
317
+ }
318
+ return results;
319
+ }
320
+ /**
321
+ * Detect Recoil atoms usage in a component
322
+ */
323
+ export function detectRecoil(nodeText) {
324
+ const results = [];
325
+ for (const hook of RECOIL_HOOKS) {
326
+ const pattern = new RegExp(`const\\s+(?:\\[([^\\]]+)\\]|([a-zA-Z_$][a-zA-Z0-9_$]*))\\s*=\\s*${hook}\\s*\\(`, 'g');
327
+ const matches = nodeText.matchAll(pattern);
328
+ for (const match of matches) {
329
+ const beforeMatch = nodeText.slice(0, match.index);
330
+ const line = beforeMatch.split('\n').length;
331
+ let variableNames = [];
332
+ if (match[1]) {
333
+ variableNames = match[1].split(',').map(v => v.trim()).filter(v => v);
334
+ }
335
+ else if (match[2]) {
336
+ variableNames = [match[2]];
337
+ }
338
+ if (variableNames.length > 0) {
339
+ results.push({
340
+ type: 'global',
341
+ pattern: 'recoil',
342
+ variableNames,
343
+ line,
344
+ column: 1,
345
+ derivedFromProps: false,
346
+ });
347
+ }
348
+ }
349
+ }
350
+ return results;
351
+ }
352
+ /**
353
+ * Detect React Query / TanStack Query usage in a component
354
+ */
355
+ export function detectReactQuery(nodeText) {
356
+ const results = [];
357
+ for (const hook of REACT_QUERY_HOOKS) {
358
+ const pattern = new RegExp(`const\\s+(?:\\{([^}]+)\\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\\s*=\\s*${hook}\\s*\\(`, 'g');
359
+ const matches = nodeText.matchAll(pattern);
360
+ for (const match of matches) {
361
+ const beforeMatch = nodeText.slice(0, match.index);
362
+ const line = beforeMatch.split('\n').length;
363
+ let variableNames = [];
364
+ if (match[1]) {
365
+ variableNames = match[1].split(',').map(v => v.trim().split(':')[0]?.trim() || '').filter(v => v);
366
+ }
367
+ else if (match[2]) {
368
+ variableNames = [match[2]];
369
+ }
370
+ if (variableNames.length > 0) {
371
+ results.push({
372
+ type: 'global',
373
+ pattern: 'react-query',
374
+ variableNames,
375
+ line,
376
+ column: 1,
377
+ derivedFromProps: false,
378
+ });
379
+ }
380
+ }
381
+ }
382
+ return results;
383
+ }
384
+ /**
385
+ * Detect SWR usage in a component
386
+ */
387
+ export function detectSWR(nodeText) {
388
+ const results = [];
389
+ for (const hook of SWR_HOOKS) {
390
+ const pattern = new RegExp(`const\\s+(?:\\{([^}]+)\\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\\s*=\\s*${hook}\\s*\\(`, 'g');
391
+ const matches = nodeText.matchAll(pattern);
392
+ for (const match of matches) {
393
+ const beforeMatch = nodeText.slice(0, match.index);
394
+ const line = beforeMatch.split('\n').length;
395
+ let variableNames = [];
396
+ if (match[1]) {
397
+ variableNames = match[1].split(',').map(v => v.trim().split(':')[0]?.trim() || '').filter(v => v);
398
+ }
399
+ else if (match[2]) {
400
+ variableNames = [match[2]];
401
+ }
402
+ if (variableNames.length > 0) {
403
+ results.push({
404
+ type: 'global',
405
+ pattern: 'swr',
406
+ variableNames,
407
+ line,
408
+ column: 1,
409
+ derivedFromProps: false,
410
+ });
411
+ }
412
+ }
413
+ }
414
+ return results;
415
+ }
416
+ /**
417
+ * Detect MobX usage in a component
418
+ */
419
+ export function detectMobX(nodeText) {
420
+ const results = [];
421
+ // Check for observer wrapper
422
+ if (nodeText.includes('observer(') || nodeText.includes('observer<')) {
423
+ results.push({
424
+ type: 'global',
425
+ pattern: 'mobx',
426
+ variableNames: ['observer'],
427
+ line: 1,
428
+ column: 1,
429
+ derivedFromProps: false,
430
+ });
431
+ }
432
+ // Check for useLocalObservable
433
+ const useLocalObservableMatches = nodeText.matchAll(/const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*useLocalObservable\s*\(/g);
434
+ for (const match of useLocalObservableMatches) {
435
+ if (match[1]) {
436
+ const beforeMatch = nodeText.slice(0, match.index);
437
+ const line = beforeMatch.split('\n').length;
438
+ results.push({
439
+ type: 'global',
440
+ pattern: 'mobx',
441
+ variableNames: [match[1]],
442
+ line,
443
+ column: 1,
444
+ derivedFromProps: false,
445
+ });
446
+ }
447
+ }
448
+ return results;
449
+ }
450
+ /**
451
+ * Detect Valtio usage in a component
452
+ */
453
+ export function detectValtio(nodeText) {
454
+ const results = [];
455
+ for (const hook of VALTIO_HOOKS) {
456
+ const pattern = new RegExp(`const\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=\\s*${hook}\\s*\\(`, 'g');
457
+ const matches = nodeText.matchAll(pattern);
458
+ for (const match of matches) {
459
+ if (match[1]) {
460
+ const beforeMatch = nodeText.slice(0, match.index);
461
+ const line = beforeMatch.split('\n').length;
462
+ results.push({
463
+ type: 'global',
464
+ pattern: 'valtio',
465
+ variableNames: [match[1]],
466
+ line,
467
+ column: 1,
468
+ derivedFromProps: false,
469
+ });
470
+ }
471
+ }
472
+ }
473
+ return results;
474
+ }
475
+ /**
476
+ * Detect all global state patterns in a component
477
+ */
478
+ export function detectGlobalState(nodeText, config) {
479
+ const results = [
480
+ ...detectUseContext(nodeText),
481
+ ...detectRedux(nodeText),
482
+ ...detectZustand(nodeText),
483
+ ...detectJotai(nodeText),
484
+ ...detectRecoil(nodeText),
485
+ ...detectMobX(nodeText),
486
+ ...detectValtio(nodeText),
487
+ ];
488
+ // Add server state patterns if configured
489
+ if (config.detectServerState) {
490
+ results.push(...detectReactQuery(nodeText), ...detectSWR(nodeText));
491
+ }
492
+ return results;
493
+ }
494
+ // ============================================================================
495
+ // Helper Functions - Issue Detection
496
+ // ============================================================================
497
+ /**
498
+ * Detect prop drilling patterns
499
+ */
500
+ export function detectPropDrilling(nodeText, props) {
501
+ const passedDownProps = [];
502
+ // Check if props are passed down to child components
503
+ for (const prop of props) {
504
+ // Match: <Component propName={propName} /> or propName={props.propName}
505
+ const passedDownPattern = new RegExp(`<[A-Z][a-zA-Z0-9]*[^>]*\\s+(?:${prop}|[a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=\\s*\\{\\s*(?:${prop}|props\\.${prop})\\s*\\}`, 'g');
506
+ if (passedDownPattern.test(nodeText)) {
507
+ passedDownProps.push(prop);
508
+ }
509
+ }
510
+ return passedDownProps;
511
+ }
512
+ /**
513
+ * Detect state management issues in a component
514
+ */
515
+ export function detectStateIssues(localState, globalState, passedDownProps, config) {
516
+ const issues = [];
517
+ // Check for mixed state management patterns
518
+ if (config.flagMixedPatterns) {
519
+ const globalPatterns = new Set(globalState.map(s => s.pattern));
520
+ // Exclude server state patterns from mixed pattern detection
521
+ const clientStatePatterns = new Set([...globalPatterns].filter(p => p !== 'react-query' && p !== 'swr'));
522
+ if (clientStatePatterns.size > 1) {
523
+ const patternList = [...clientStatePatterns].join(', ');
524
+ issues.push({
525
+ type: 'mixed-patterns',
526
+ description: `Component uses multiple global state management patterns: ${patternList}`,
527
+ severity: 'warning',
528
+ suggestion: 'Consider standardizing on a single state management solution for consistency',
529
+ line: globalState[0]?.line || 1,
530
+ column: 1,
531
+ });
532
+ }
533
+ }
534
+ // Check for excessive local state
535
+ if (localState.length > config.maxLocalStateVariables) {
536
+ issues.push({
537
+ type: 'local-should-lift',
538
+ description: `Component has ${localState.length} local state variables, which may indicate complex state that should be extracted`,
539
+ severity: 'info',
540
+ suggestion: 'Consider extracting related state into a custom hook or using useReducer',
541
+ line: localState[0]?.line || 1,
542
+ column: 1,
543
+ });
544
+ }
545
+ // Check for potential prop drilling
546
+ if (passedDownProps.length >= config.propDrillingThreshold) {
547
+ issues.push({
548
+ type: 'prop-drilling',
549
+ description: `${passedDownProps.length} props are being passed down to child components`,
550
+ severity: 'info',
551
+ suggestion: 'Consider using Context or a state management library to avoid prop drilling',
552
+ line: 1,
553
+ column: 1,
554
+ });
555
+ }
556
+ // Check for state derived from props (potential issue)
557
+ const derivedState = localState.filter(s => s.derivedFromProps);
558
+ if (derivedState.length > 0) {
559
+ issues.push({
560
+ type: 'global-should-be-local',
561
+ description: `${derivedState.length} state variable(s) are derived from props, which can cause sync issues`,
562
+ severity: 'info',
563
+ suggestion: 'Consider computing derived values directly or using useMemo instead of useState',
564
+ line: derivedState[0]?.line || 1,
565
+ column: 1,
566
+ });
567
+ }
568
+ return issues;
569
+ }
570
+ /**
571
+ * Calculate state complexity score for a component
572
+ */
573
+ export function calculateComplexityScore(localState, globalState, issues) {
574
+ let score = 0;
575
+ // Base score from state count
576
+ score += localState.length * 1;
577
+ score += globalState.length * 2; // Global state adds more complexity
578
+ // Add complexity for issues
579
+ for (const issue of issues) {
580
+ switch (issue.severity) {
581
+ case 'error':
582
+ score += 5;
583
+ break;
584
+ case 'warning':
585
+ score += 3;
586
+ break;
587
+ case 'info':
588
+ score += 1;
589
+ break;
590
+ }
591
+ }
592
+ // Add complexity for mixed patterns
593
+ const uniquePatterns = new Set([
594
+ ...localState.map(s => s.pattern),
595
+ ...globalState.map(s => s.pattern),
596
+ ]);
597
+ score += (uniquePatterns.size - 1) * 2;
598
+ return score;
599
+ }
600
+ /**
601
+ * Extract props from component signature
602
+ */
603
+ export function extractPropsFromComponent(nodeText) {
604
+ const props = [];
605
+ // Match destructured props: ({ prop1, prop2, prop3 })
606
+ const destructuringMatch = nodeText.match(/\(\s*\{\s*([^}]+)\s*\}/);
607
+ if (destructuringMatch && destructuringMatch[1]) {
608
+ const propsStr = destructuringMatch[1];
609
+ const propParts = propsStr.split(',');
610
+ for (const part of propParts) {
611
+ const trimmed = part.trim();
612
+ if (trimmed.startsWith('...'))
613
+ continue;
614
+ const propMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
615
+ if (propMatch && propMatch[1]) {
616
+ props.push(propMatch[1]);
617
+ }
618
+ }
619
+ }
620
+ // Also check for props.propName access
621
+ const directAccessMatches = nodeText.matchAll(/props\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g);
622
+ for (const match of directAccessMatches) {
623
+ if (match[1] && !props.includes(match[1])) {
624
+ props.push(match[1]);
625
+ }
626
+ }
627
+ return props;
628
+ }
629
+ // ============================================================================
630
+ // Helper Functions - Analysis
631
+ // ============================================================================
632
+ /**
633
+ * Analyze a single component's state patterns
634
+ */
635
+ export function analyzeComponentState(node, content, filePath, config) {
636
+ const componentName = getComponentName(node, content);
637
+ if (!componentName) {
638
+ return null;
639
+ }
640
+ const nodeText = node.text;
641
+ const localState = detectLocalState(nodeText);
642
+ const globalState = detectGlobalState(nodeText, config);
643
+ const props = extractPropsFromComponent(nodeText);
644
+ const passedDownProps = detectPropDrilling(nodeText, props);
645
+ const issues = detectStateIssues(localState, globalState, passedDownProps, config);
646
+ const complexityScore = calculateComplexityScore(localState, globalState, issues);
647
+ return {
648
+ componentName,
649
+ filePath,
650
+ line: node.startPosition.row + 1,
651
+ column: node.startPosition.column + 1,
652
+ localState,
653
+ globalState,
654
+ issues,
655
+ passedDownProps,
656
+ complexityScore,
657
+ };
658
+ }
659
+ /**
660
+ * Find dominant pattern from a list
661
+ */
662
+ function findDominantPattern(patterns, excludeValue) {
663
+ const counts = new Map();
664
+ for (const pattern of patterns) {
665
+ if (pattern !== excludeValue) {
666
+ counts.set(pattern, (counts.get(pattern) || 0) + 1);
667
+ }
668
+ }
669
+ let dominant = excludeValue;
670
+ let maxCount = 0;
671
+ for (const [pattern, count] of counts) {
672
+ if (count > maxCount) {
673
+ maxCount = count;
674
+ dominant = pattern;
675
+ }
676
+ }
677
+ const total = patterns.filter(p => p !== excludeValue).length;
678
+ const confidence = total > 0 ? maxCount / total : 0;
679
+ return { dominant, confidence };
680
+ }
681
+ /**
682
+ * Analyze state patterns across multiple components
683
+ */
684
+ export function analyzeStatePatterns(components) {
685
+ if (components.length === 0) {
686
+ return {
687
+ components: [],
688
+ dominantLocalPattern: 'none',
689
+ dominantGlobalPattern: 'none',
690
+ confidence: { localPattern: 0, globalPattern: 0 },
691
+ componentsWithIssues: [],
692
+ healthScore: 1.0,
693
+ };
694
+ }
695
+ // Collect all patterns
696
+ const localPatterns = [];
697
+ const globalPatterns = [];
698
+ for (const comp of components) {
699
+ for (const state of comp.localState) {
700
+ localPatterns.push(state.pattern);
701
+ }
702
+ for (const state of comp.globalState) {
703
+ globalPatterns.push(state.pattern);
704
+ }
705
+ }
706
+ // Find dominant patterns
707
+ const localResult = findDominantPattern(localPatterns, 'none');
708
+ const globalResult = findDominantPattern(globalPatterns, 'none');
709
+ // Find components with issues
710
+ const componentsWithIssues = components.filter(c => c.issues.length > 0);
711
+ // Calculate health score
712
+ const totalIssues = components.reduce((sum, c) => sum + c.issues.length, 0);
713
+ const avgComplexity = components.reduce((sum, c) => sum + c.complexityScore, 0) / components.length;
714
+ const healthScore = Math.max(0, 1 - (totalIssues * 0.1) - (avgComplexity * 0.02));
715
+ return {
716
+ components,
717
+ dominantLocalPattern: localResult.dominant,
718
+ dominantGlobalPattern: globalResult.dominant,
719
+ confidence: {
720
+ localPattern: localResult.confidence,
721
+ globalPattern: globalResult.confidence,
722
+ },
723
+ componentsWithIssues,
724
+ healthScore,
725
+ };
726
+ }
727
+ // ============================================================================
728
+ // Pattern Description Helpers
729
+ // ============================================================================
730
+ export const LOCAL_PATTERN_DESCRIPTIONS = {
731
+ 'useState': 'React useState hook',
732
+ 'useReducer': 'React useReducer hook',
733
+ 'useRef': 'React useRef for mutable values',
734
+ 'class-state': 'Class component state',
735
+ 'none': 'no local state',
736
+ };
737
+ export const GLOBAL_PATTERN_DESCRIPTIONS = {
738
+ 'useContext': 'React Context API',
739
+ 'redux': 'Redux (useSelector/useDispatch)',
740
+ 'zustand': 'Zustand store',
741
+ 'jotai': 'Jotai atoms',
742
+ 'recoil': 'Recoil atoms',
743
+ 'react-query': 'React Query / TanStack Query',
744
+ 'swr': 'SWR',
745
+ 'mobx': 'MobX',
746
+ 'valtio': 'Valtio',
747
+ 'none': 'no global state',
748
+ };
749
+ // ============================================================================
750
+ // State Pattern Detector Class
751
+ // ============================================================================
752
+ /**
753
+ * Detector for state management patterns
754
+ *
755
+ * Identifies local vs global state usage patterns and detects
756
+ * state management inconsistencies.
757
+ *
758
+ * @requirements 8.5 - THE Component_Detector SHALL detect state management patterns (local vs global)
759
+ */
760
+ export class StatePatternDetector extends ASTDetector {
761
+ id = 'components/state-patterns';
762
+ category = 'components';
763
+ subcategory = 'state-management';
764
+ name = 'State Pattern Detector';
765
+ description = 'Detects local vs global state usage patterns and identifies state management inconsistencies';
766
+ supportedLanguages = ['typescript', 'javascript'];
767
+ config;
768
+ constructor(config = {}) {
769
+ super();
770
+ this.config = { ...DEFAULT_STATE_PATTERN_CONFIG, ...config };
771
+ }
772
+ /**
773
+ * Detect state patterns in the project
774
+ */
775
+ async detect(context) {
776
+ const patterns = [];
777
+ const violations = [];
778
+ // Find all components in the file
779
+ const componentInfos = this.findComponentsInFile(context);
780
+ if (componentInfos.length === 0) {
781
+ return this.createEmptyResult();
782
+ }
783
+ // Analyze patterns across all components
784
+ const analysis = analyzeStatePatterns(componentInfos);
785
+ // Create pattern matches for detected patterns
786
+ if (analysis.dominantLocalPattern !== 'none' && analysis.confidence.localPattern > 0.3) {
787
+ patterns.push(this.createLocalStatePattern(context.file, analysis));
788
+ }
789
+ if (analysis.dominantGlobalPattern !== 'none' && analysis.confidence.globalPattern > 0.3) {
790
+ patterns.push(this.createGlobalStatePattern(context.file, analysis));
791
+ }
792
+ // Generate violations for components with issues
793
+ for (const comp of analysis.componentsWithIssues) {
794
+ if (comp.filePath === context.file) {
795
+ for (const issue of comp.issues) {
796
+ const violation = this.createIssueViolation(context.file, comp, issue);
797
+ violations.push(violation);
798
+ }
799
+ }
800
+ }
801
+ const overallConfidence = Math.max(analysis.confidence.localPattern, analysis.confidence.globalPattern, analysis.healthScore);
802
+ return this.createResult(patterns, violations, overallConfidence);
803
+ }
804
+ /**
805
+ * Generate a quick fix for state pattern violations
806
+ */
807
+ generateQuickFix(violation) {
808
+ // Generate quick fixes based on issue type
809
+ if (violation.message.includes('mixed-patterns')) {
810
+ return {
811
+ title: 'Standardize state management',
812
+ kind: 'refactor',
813
+ edit: { changes: {} },
814
+ isPreferred: false,
815
+ confidence: 0.5,
816
+ preview: 'Consider refactoring to use a single state management solution',
817
+ };
818
+ }
819
+ if (violation.message.includes('prop drilling')) {
820
+ return {
821
+ title: 'Extract to Context',
822
+ kind: 'refactor',
823
+ edit: { changes: {} },
824
+ isPreferred: true,
825
+ confidence: 0.6,
826
+ preview: 'Create a Context provider to avoid prop drilling',
827
+ };
828
+ }
829
+ if (violation.message.includes('local state variables')) {
830
+ return {
831
+ title: 'Extract to custom hook',
832
+ kind: 'refactor',
833
+ edit: { changes: {} },
834
+ isPreferred: true,
835
+ confidence: 0.7,
836
+ preview: 'Extract related state into a custom hook',
837
+ };
838
+ }
839
+ return null;
840
+ }
841
+ /**
842
+ * Find all React components in a file
843
+ */
844
+ findComponentsInFile(context) {
845
+ const components = [];
846
+ if (context.ast) {
847
+ // Use AST to find components
848
+ const functionNodes = this.findNodesByTypes(context.ast, [
849
+ 'function_declaration',
850
+ 'arrow_function',
851
+ 'function_expression',
852
+ ]);
853
+ for (const node of functionNodes) {
854
+ if (isReactComponent(node, context.content)) {
855
+ const info = analyzeComponentState(node, context.content, context.file, this.config);
856
+ if (info) {
857
+ components.push(info);
858
+ }
859
+ }
860
+ }
861
+ }
862
+ else {
863
+ // Fallback: use regex-based detection
864
+ const componentMatches = this.findComponentsWithRegex(context.content, context.file);
865
+ components.push(...componentMatches);
866
+ }
867
+ return components;
868
+ }
869
+ /**
870
+ * Find components using regex (fallback when AST is not available)
871
+ */
872
+ findComponentsWithRegex(content, filePath) {
873
+ const components = [];
874
+ // Match component patterns
875
+ const patterns = [
876
+ // Arrow function: const Button = ({ ... }) => ...
877
+ /(?:export\s+)?const\s+([A-Z][a-zA-Z0-9]*)\s*(?::\s*(?:React\.)?(?:FC|FunctionComponent)\s*<[^>]*>\s*)?=\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\n\}/g,
878
+ // Function declaration: function Button({ ... }) { ... }
879
+ /(?:export\s+)?function\s+([A-Z][a-zA-Z0-9]*)\s*\([^)]*\)\s*\{[\s\S]*?\n\}/g,
880
+ ];
881
+ for (const pattern of patterns) {
882
+ let match;
883
+ while ((match = pattern.exec(content)) !== null) {
884
+ const componentName = match[1];
885
+ if (!componentName)
886
+ continue;
887
+ const sourceCode = match[0];
888
+ const beforeMatch = content.slice(0, match.index);
889
+ const line = beforeMatch.split('\n').length;
890
+ // Check if it returns JSX
891
+ if (!sourceCode.includes('<') || (!sourceCode.includes('/>') && !sourceCode.includes('</'))) {
892
+ continue;
893
+ }
894
+ const localState = detectLocalState(sourceCode);
895
+ const globalState = detectGlobalState(sourceCode, this.config);
896
+ const props = extractPropsFromComponent(sourceCode);
897
+ const passedDownProps = detectPropDrilling(sourceCode, props);
898
+ const issues = detectStateIssues(localState, globalState, passedDownProps, this.config);
899
+ const complexityScore = calculateComplexityScore(localState, globalState, issues);
900
+ components.push({
901
+ componentName,
902
+ filePath,
903
+ line,
904
+ column: 1,
905
+ localState,
906
+ globalState,
907
+ issues,
908
+ passedDownProps,
909
+ complexityScore,
910
+ });
911
+ }
912
+ }
913
+ return components;
914
+ }
915
+ /**
916
+ * Create a pattern match for local state patterns
917
+ */
918
+ createLocalStatePattern(file, analysis) {
919
+ return {
920
+ patternId: `state-local-${analysis.dominantLocalPattern}`,
921
+ location: { file, line: 1, column: 1 },
922
+ confidence: analysis.confidence.localPattern,
923
+ isOutlier: false,
924
+ };
925
+ }
926
+ /**
927
+ * Create a pattern match for global state patterns
928
+ */
929
+ createGlobalStatePattern(file, analysis) {
930
+ return {
931
+ patternId: `state-global-${analysis.dominantGlobalPattern}`,
932
+ location: { file, line: 1, column: 1 },
933
+ confidence: analysis.confidence.globalPattern,
934
+ isOutlier: false,
935
+ };
936
+ }
937
+ /**
938
+ * Create a violation for a state issue
939
+ */
940
+ createIssueViolation(file, component, issue) {
941
+ const range = {
942
+ start: { line: issue.line, character: issue.column },
943
+ end: { line: issue.line, character: issue.column + 1 },
944
+ };
945
+ return {
946
+ id: `state-${issue.type}-${component.componentName}-${file.replace(/[^a-zA-Z0-9]/g, '-')}`,
947
+ patternId: 'components/state-patterns',
948
+ severity: issue.severity,
949
+ file,
950
+ range,
951
+ message: `[${component.componentName}] ${issue.description}`,
952
+ expected: issue.suggestion,
953
+ actual: issue.description,
954
+ aiExplainAvailable: true,
955
+ aiFixAvailable: issue.type === 'prop-drilling' || issue.type === 'local-should-lift',
956
+ firstSeen: new Date(),
957
+ occurrences: 1,
958
+ };
959
+ }
960
+ }
961
+ // ============================================================================
962
+ // Factory Function
963
+ // ============================================================================
964
+ /**
965
+ * Create a new StatePatternDetector instance
966
+ */
967
+ export function createStatePatternDetector(config) {
968
+ return new StatePatternDetector(config);
969
+ }
970
+ //# sourceMappingURL=state-patterns.js.map