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,795 @@
1
+ /**
2
+ * Props Patterns Detector - Component props handling pattern detection
3
+ *
4
+ * Detects props patterns including destructuring, defaults, spreading,
5
+ * and type definitions. Identifies inconsistencies and reports violations.
6
+ *
7
+ * @requirements 8.2 - THE Component_Detector SHALL detect props patterns
8
+ * (destructuring, defaults, required vs optional)
9
+ */
10
+ import { ASTDetector } from '../base/index.js';
11
+ // ============================================================================
12
+ // Constants
13
+ // ============================================================================
14
+ /**
15
+ * React FC type patterns
16
+ */
17
+ export const FC_TYPE_PATTERNS = [
18
+ 'FC',
19
+ 'FunctionComponent',
20
+ 'React.FC',
21
+ 'React.FunctionComponent',
22
+ 'VFC',
23
+ 'VoidFunctionComponent',
24
+ 'React.VFC',
25
+ 'React.VoidFunctionComponent',
26
+ ];
27
+ /**
28
+ * Common props type name patterns
29
+ */
30
+ export const PROPS_TYPE_NAME_PATTERNS = [
31
+ /Props$/,
32
+ /^I[A-Z].*Props$/,
33
+ /^T[A-Z].*Props$/,
34
+ ];
35
+ // ============================================================================
36
+ // Helper Functions
37
+ // ============================================================================
38
+ /**
39
+ * Check if a node represents a React component
40
+ */
41
+ export function isReactComponent(node, content) {
42
+ // Check for function/arrow function that returns JSX
43
+ if (node.type === 'function_declaration' ||
44
+ node.type === 'arrow_function' ||
45
+ node.type === 'function_expression') {
46
+ // Component names should be PascalCase
47
+ const name = getComponentName(node, content);
48
+ if (!name || !/^[A-Z]/.test(name)) {
49
+ return false;
50
+ }
51
+ // Check if it returns JSX (simplified check)
52
+ const nodeText = node.text;
53
+ return nodeText.includes('<') && (nodeText.includes('/>') || nodeText.includes('</'));
54
+ }
55
+ return false;
56
+ }
57
+ /**
58
+ * Get the component name from a node
59
+ */
60
+ export function getComponentName(node, content) {
61
+ // For function declarations, get the name directly
62
+ if (node.type === 'function_declaration') {
63
+ const nameNode = node.children.find(c => c.type === 'identifier');
64
+ return nameNode?.text;
65
+ }
66
+ // For arrow functions and function expressions, look for variable declaration
67
+ // This is a simplified approach - in real implementation would need parent context
68
+ const lines = content.split('\n');
69
+ const line = lines[node.startPosition.row];
70
+ if (line) {
71
+ // Match patterns like: const ComponentName = or export const ComponentName =
72
+ const match = line.match(/(?:const|let|var|export\s+(?:const|let|var)?)\s+([A-Z][a-zA-Z0-9]*)\s*[=:]/);
73
+ if (match && match[1]) {
74
+ return match[1];
75
+ }
76
+ }
77
+ return undefined;
78
+ }
79
+ /**
80
+ * Detect the destructuring pattern used in a component
81
+ */
82
+ export function detectDestructuringPattern(node, _content) {
83
+ const nodeText = node.text;
84
+ // Check for signature destructuring: ({ prop1, prop2 }) =>
85
+ // or function Component({ prop1, prop2 })
86
+ if (node.type === 'arrow_function' || node.type === 'function_declaration' || node.type === 'function_expression') {
87
+ // Look for object pattern in parameters
88
+ const hasObjectPatternParam = nodeText.match(/\(\s*\{[^}]*\}\s*(?::[^)]+)?\s*\)/);
89
+ if (hasObjectPatternParam) {
90
+ return 'signature';
91
+ }
92
+ // Check for body destructuring: const { prop1, prop2 } = props
93
+ const hasBodyDestructuring = nodeText.match(/(?:const|let|var)\s+\{[^}]+\}\s*=\s*props/);
94
+ if (hasBodyDestructuring) {
95
+ return 'body';
96
+ }
97
+ // Check for direct props access: props.propName
98
+ const hasDirectAccess = nodeText.match(/props\.[a-zA-Z_$][a-zA-Z0-9_$]*/);
99
+ if (hasDirectAccess) {
100
+ return 'direct-access';
101
+ }
102
+ // Check if component has any props parameter
103
+ const hasPropsParam = nodeText.match(/\(\s*props\s*(?::[^)]+)?\s*\)/) ||
104
+ nodeText.match(/function\s+\w+\s*\(\s*props\s*(?::[^)]+)?\s*\)/);
105
+ if (!hasPropsParam && !hasObjectPatternParam) {
106
+ return 'none';
107
+ }
108
+ }
109
+ return 'unknown';
110
+ }
111
+ /**
112
+ * Detect the default props pattern used in a component
113
+ */
114
+ export function detectDefaultPropsPattern(node, content, componentName) {
115
+ const nodeText = node.text;
116
+ // Check for default parameters in signature: ({ name = 'default' })
117
+ const hasDefaultParams = nodeText.match(/\(\s*\{[^}]*=\s*[^,}]+[^}]*\}/);
118
+ if (hasDefaultParams) {
119
+ return 'default-parameters';
120
+ }
121
+ // Check for destructuring defaults in body: const { name = 'default' } = props
122
+ const hasDestructuringDefaults = nodeText.match(/(?:const|let|var)\s+\{[^}]*=\s*[^,}]+[^}]*\}\s*=\s*props/);
123
+ if (hasDestructuringDefaults) {
124
+ return 'destructuring-defaults';
125
+ }
126
+ // Check for nullish coalescing: props.name ?? 'default'
127
+ const hasNullishCoalescing = nodeText.match(/props\.[a-zA-Z_$][a-zA-Z0-9_$]*\s*\?\?/);
128
+ if (hasNullishCoalescing) {
129
+ return 'nullish-coalescing';
130
+ }
131
+ // Check for logical OR: props.name || 'default'
132
+ const hasLogicalOr = nodeText.match(/props\.[a-zA-Z_$][a-zA-Z0-9_$]*\s*\|\|/);
133
+ if (hasLogicalOr) {
134
+ return 'logical-or';
135
+ }
136
+ // Check for static defaultProps (need to look in surrounding content)
137
+ if (componentName) {
138
+ const defaultPropsPattern = new RegExp(`${componentName}\\.defaultProps\\s*=`);
139
+ if (defaultPropsPattern.test(content)) {
140
+ return 'static-defaultProps';
141
+ }
142
+ }
143
+ return 'none';
144
+ }
145
+ /**
146
+ * Detect the props spreading pattern used in a component
147
+ */
148
+ export function detectSpreadingPattern(node, _content) {
149
+ const nodeText = node.text;
150
+ // Check for rest spread: ({ name, ...rest }) and {...rest}
151
+ const hasRestParam = nodeText.match(/\(\s*\{[^}]*,\s*\.\.\.([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\}/);
152
+ const hasRestSpread = nodeText.match(/\{\s*\.\.\.([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\}/);
153
+ if (hasRestParam && hasRestSpread) {
154
+ return 'rest-spread';
155
+ }
156
+ // Check for full props spread: {...props}
157
+ const hasFullSpread = nodeText.match(/\{\s*\.\.\.props\s*\}/);
158
+ if (hasFullSpread) {
159
+ return 'full-spread';
160
+ }
161
+ // Check for selective spreading (passing individual props)
162
+ const hasSelectiveSpread = nodeText.match(/<[A-Z][a-zA-Z0-9]*[^>]*\s+[a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*\{/);
163
+ if (hasSelectiveSpread && !hasFullSpread && !hasRestSpread) {
164
+ return 'selective-spread';
165
+ }
166
+ return 'none';
167
+ }
168
+ /**
169
+ * Detect the props type definition pattern used in a component
170
+ */
171
+ export function detectTypePattern(node, content, componentName) {
172
+ const nodeText = node.text;
173
+ // Check for inline type: ({ name }: { name: string })
174
+ const hasInlineType = nodeText.match(/\(\s*\{[^}]*\}\s*:\s*\{[^}]+\}\s*\)/);
175
+ if (hasInlineType) {
176
+ return 'inline';
177
+ }
178
+ // Check for FC generic type: FC<Props>, React.FC<Props>
179
+ const hasFCType = FC_TYPE_PATTERNS.some(pattern => {
180
+ const regex = new RegExp(`:\\s*${pattern.replace('.', '\\.')}\\s*<`);
181
+ return regex.test(nodeText) || regex.test(content.split('\n')[node.startPosition.row] || '');
182
+ });
183
+ if (hasFCType) {
184
+ return 'generic';
185
+ }
186
+ // Check for type annotation on props parameter
187
+ const hasTypeAnnotation = nodeText.match(/\(\s*(?:\{[^}]*\}|props)\s*:\s*([A-Z][a-zA-Z0-9]*(?:Props)?)\s*\)/);
188
+ if (hasTypeAnnotation) {
189
+ // Determine if it's interface or type alias by looking in content
190
+ const typeName = hasTypeAnnotation[1];
191
+ if (typeName) {
192
+ const interfacePattern = new RegExp(`interface\\s+${typeName}\\s*\\{`);
193
+ const typePattern = new RegExp(`type\\s+${typeName}\\s*=`);
194
+ if (interfacePattern.test(content)) {
195
+ return 'interface';
196
+ }
197
+ if (typePattern.test(content)) {
198
+ return 'type-alias';
199
+ }
200
+ }
201
+ }
202
+ // Check for propTypes
203
+ if (componentName) {
204
+ const propTypesPattern = new RegExp(`${componentName}\\.propTypes\\s*=`);
205
+ if (propTypesPattern.test(content)) {
206
+ return 'prop-types';
207
+ }
208
+ }
209
+ return 'none';
210
+ }
211
+ /**
212
+ * Extract prop names from a component
213
+ */
214
+ export function extractPropNames(node, _content) {
215
+ const nodeText = node.text;
216
+ const propNames = [];
217
+ // Extract from signature destructuring: ({ prop1, prop2, prop3 = 'default' })
218
+ const signatureMatch = nodeText.match(/\(\s*\{\s*([^}]+)\s*\}/);
219
+ if (signatureMatch && signatureMatch[1]) {
220
+ const propsStr = signatureMatch[1];
221
+ // Split by comma and extract prop names
222
+ const props = propsStr.split(',').map(p => {
223
+ // Handle: prop, prop = default, prop: alias, ...rest
224
+ const trimmed = p.trim();
225
+ if (trimmed.startsWith('...'))
226
+ return null; // Skip rest spread
227
+ const nameMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
228
+ return nameMatch ? nameMatch[1] : null;
229
+ }).filter((p) => p !== null);
230
+ propNames.push(...props);
231
+ }
232
+ // Extract from body destructuring: const { prop1, prop2 } = props
233
+ const bodyMatch = nodeText.match(/(?:const|let|var)\s+\{\s*([^}]+)\s*\}\s*=\s*props/);
234
+ if (bodyMatch && bodyMatch[1]) {
235
+ const propsStr = bodyMatch[1];
236
+ const props = propsStr.split(',').map(p => {
237
+ const trimmed = p.trim();
238
+ if (trimmed.startsWith('...'))
239
+ return null;
240
+ const nameMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
241
+ return nameMatch ? nameMatch[1] : null;
242
+ }).filter((p) => p !== null);
243
+ propNames.push(...props);
244
+ }
245
+ // Extract from direct access: props.propName
246
+ const directAccessMatches = nodeText.matchAll(/props\.([a-zA-Z_$][a-zA-Z0-9_$]*)/g);
247
+ for (const match of directAccessMatches) {
248
+ if (match[1] && !propNames.includes(match[1])) {
249
+ propNames.push(match[1]);
250
+ }
251
+ }
252
+ return [...new Set(propNames)]; // Remove duplicates
253
+ }
254
+ /**
255
+ * Extract prop names that have default values
256
+ */
257
+ export function extractPropsWithDefaults(node, _content) {
258
+ const nodeText = node.text;
259
+ const propsWithDefaults = [];
260
+ // Extract from signature defaults: ({ prop1 = 'default', prop2 = 42 })
261
+ const signatureMatch = nodeText.match(/\(\s*\{\s*([^}]+)\s*\}/);
262
+ if (signatureMatch && signatureMatch[1]) {
263
+ const propsStr = signatureMatch[1];
264
+ const props = propsStr.split(',').map(p => {
265
+ const trimmed = p.trim();
266
+ // Match: propName = defaultValue
267
+ const defaultMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);
268
+ return defaultMatch ? defaultMatch[1] : null;
269
+ }).filter((p) => p !== null);
270
+ propsWithDefaults.push(...props);
271
+ }
272
+ // Extract from body destructuring defaults
273
+ const bodyMatch = nodeText.match(/(?:const|let|var)\s+\{\s*([^}]+)\s*\}\s*=\s*props/);
274
+ if (bodyMatch && bodyMatch[1]) {
275
+ const propsStr = bodyMatch[1];
276
+ const props = propsStr.split(',').map(p => {
277
+ const trimmed = p.trim();
278
+ const defaultMatch = trimmed.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);
279
+ return defaultMatch ? defaultMatch[1] : null;
280
+ }).filter((p) => p !== null);
281
+ propsWithDefaults.push(...props);
282
+ }
283
+ return [...new Set(propsWithDefaults)];
284
+ }
285
+ /**
286
+ * Get props type name from a component
287
+ */
288
+ export function getPropsTypeName(node, content) {
289
+ const nodeText = node.text;
290
+ const line = content.split('\n')[node.startPosition.row] || '';
291
+ // Check for FC<PropsType>
292
+ for (const fcPattern of FC_TYPE_PATTERNS) {
293
+ const regex = new RegExp(`${fcPattern.replace('.', '\\.')}\\s*<\\s*([A-Z][a-zA-Z0-9]*)\\s*>`);
294
+ const match = line.match(regex) || nodeText.match(regex);
295
+ if (match && match[1]) {
296
+ return match[1];
297
+ }
298
+ }
299
+ // Check for type annotation: (props: PropsType) or ({ ... }: PropsType)
300
+ const typeAnnotationMatch = nodeText.match(/\)\s*:\s*([A-Z][a-zA-Z0-9]*(?:Props)?)\s*(?:=>|\{)/);
301
+ if (typeAnnotationMatch && typeAnnotationMatch[1]) {
302
+ return typeAnnotationMatch[1];
303
+ }
304
+ // Check for parameter type: (props: PropsType)
305
+ const paramTypeMatch = nodeText.match(/\(\s*(?:\{[^}]*\}|props)\s*:\s*([A-Z][a-zA-Z0-9]*(?:Props)?)\s*\)/);
306
+ if (paramTypeMatch && paramTypeMatch[1]) {
307
+ return paramTypeMatch[1];
308
+ }
309
+ return undefined;
310
+ }
311
+ /**
312
+ * Check if component uses FC type
313
+ */
314
+ export function usesFCType(node, content) {
315
+ const line = content.split('\n')[node.startPosition.row] || '';
316
+ return FC_TYPE_PATTERNS.some(pattern => {
317
+ const regex = new RegExp(`:\\s*${pattern.replace('.', '\\.')}\\s*<`);
318
+ return regex.test(line);
319
+ });
320
+ }
321
+ /**
322
+ * Analyze a single component's props patterns
323
+ */
324
+ export function analyzeComponentProps(node, content, filePath) {
325
+ const componentName = getComponentName(node, content);
326
+ if (!componentName) {
327
+ return null;
328
+ }
329
+ return {
330
+ componentName,
331
+ filePath,
332
+ line: node.startPosition.row + 1,
333
+ column: node.startPosition.column + 1,
334
+ destructuringPattern: detectDestructuringPattern(node, content),
335
+ defaultPropsPattern: detectDefaultPropsPattern(node, content, componentName),
336
+ spreadingPattern: detectSpreadingPattern(node, content),
337
+ typePattern: detectTypePattern(node, content, componentName),
338
+ propsTypeName: getPropsTypeName(node, content),
339
+ propsWithDefaults: extractPropsWithDefaults(node, content),
340
+ allPropNames: extractPropNames(node, content),
341
+ usesFCType: usesFCType(node, content),
342
+ };
343
+ }
344
+ /**
345
+ * Find the dominant pattern from a list of patterns
346
+ */
347
+ function findDominantPattern(patterns, excludeValues = []) {
348
+ const counts = new Map();
349
+ for (const pattern of patterns) {
350
+ if (!excludeValues.includes(pattern)) {
351
+ counts.set(pattern, (counts.get(pattern) || 0) + 1);
352
+ }
353
+ }
354
+ let dominant = patterns[0] || 'unknown';
355
+ let maxCount = 0;
356
+ for (const [pattern, count] of counts) {
357
+ if (count > maxCount) {
358
+ maxCount = count;
359
+ dominant = pattern;
360
+ }
361
+ }
362
+ const total = patterns.filter(p => !excludeValues.includes(p)).length;
363
+ const confidence = total > 0 ? maxCount / total : 0;
364
+ return { dominant, confidence };
365
+ }
366
+ /**
367
+ * Analyze props patterns across multiple components
368
+ */
369
+ export function analyzePropsPatterns(components) {
370
+ if (components.length === 0) {
371
+ return {
372
+ components: [],
373
+ dominantDestructuringPattern: 'unknown',
374
+ dominantDefaultPropsPattern: 'none',
375
+ dominantSpreadingPattern: 'none',
376
+ dominantTypePattern: 'none',
377
+ confidence: {
378
+ destructuring: 0,
379
+ defaults: 0,
380
+ spreading: 0,
381
+ types: 0,
382
+ },
383
+ inconsistentComponents: [],
384
+ };
385
+ }
386
+ // Find dominant patterns
387
+ const destructuringResult = findDominantPattern(components.map(c => c.destructuringPattern), ['unknown', 'none']);
388
+ const defaultsResult = findDominantPattern(components.map(c => c.defaultPropsPattern), ['unknown', 'none']);
389
+ const spreadingResult = findDominantPattern(components.map(c => c.spreadingPattern), ['unknown', 'none']);
390
+ const typesResult = findDominantPattern(components.map(c => c.typePattern), ['unknown', 'none']);
391
+ // Find inconsistent components
392
+ const inconsistentComponents = components.filter(c => {
393
+ // A component is inconsistent if it uses a different pattern than dominant
394
+ // and the pattern is not 'none' or 'unknown'
395
+ const destructuringInconsistent = c.destructuringPattern !== destructuringResult.dominant &&
396
+ c.destructuringPattern !== 'none' &&
397
+ c.destructuringPattern !== 'unknown' &&
398
+ destructuringResult.confidence > 0.5;
399
+ const defaultsInconsistent = c.defaultPropsPattern !== defaultsResult.dominant &&
400
+ c.defaultPropsPattern !== 'none' &&
401
+ c.defaultPropsPattern !== 'unknown' &&
402
+ defaultsResult.confidence > 0.5;
403
+ const typesInconsistent = c.typePattern !== typesResult.dominant &&
404
+ c.typePattern !== 'none' &&
405
+ c.typePattern !== 'unknown' &&
406
+ typesResult.confidence > 0.5;
407
+ return destructuringInconsistent || defaultsInconsistent || typesInconsistent;
408
+ });
409
+ return {
410
+ components,
411
+ dominantDestructuringPattern: destructuringResult.dominant,
412
+ dominantDefaultPropsPattern: defaultsResult.dominant,
413
+ dominantSpreadingPattern: spreadingResult.dominant,
414
+ dominantTypePattern: typesResult.dominant,
415
+ confidence: {
416
+ destructuring: destructuringResult.confidence,
417
+ defaults: defaultsResult.confidence,
418
+ spreading: spreadingResult.confidence,
419
+ types: typesResult.confidence,
420
+ },
421
+ inconsistentComponents,
422
+ };
423
+ }
424
+ /**
425
+ * Generate a suggestion for refactoring props handling
426
+ */
427
+ export function generatePropsSuggestion(component, targetDestructuring, targetDefaults, targetTypes) {
428
+ const suggestions = [];
429
+ if (component.destructuringPattern !== targetDestructuring &&
430
+ component.destructuringPattern !== 'none' &&
431
+ component.destructuringPattern !== 'unknown') {
432
+ const destructuringDescriptions = {
433
+ 'signature': 'destructure props in function signature',
434
+ 'body': 'destructure props in function body',
435
+ 'direct-access': 'access props directly',
436
+ 'none': 'no props',
437
+ 'unknown': 'unknown pattern',
438
+ };
439
+ suggestions.push(`Consider ${destructuringDescriptions[targetDestructuring]}`);
440
+ }
441
+ if (component.defaultPropsPattern !== targetDefaults &&
442
+ component.defaultPropsPattern !== 'none' &&
443
+ component.defaultPropsPattern !== 'unknown') {
444
+ const defaultsDescriptions = {
445
+ 'static-defaultProps': 'using static defaultProps',
446
+ 'default-parameters': 'using default parameters in signature',
447
+ 'destructuring-defaults': 'using defaults in destructuring',
448
+ 'logical-or': 'using logical OR for defaults',
449
+ 'nullish-coalescing': 'using nullish coalescing for defaults',
450
+ 'none': 'no defaults',
451
+ 'unknown': 'unknown pattern',
452
+ };
453
+ suggestions.push(`Consider ${defaultsDescriptions[targetDefaults]}`);
454
+ }
455
+ if (component.typePattern !== targetTypes &&
456
+ component.typePattern !== 'none' &&
457
+ component.typePattern !== 'unknown') {
458
+ const typeDescriptions = {
459
+ 'interface': 'using interface for props type',
460
+ 'type-alias': 'using type alias for props type',
461
+ 'inline': 'using inline type annotation',
462
+ 'generic': 'using FC<Props> generic type',
463
+ 'prop-types': 'using PropTypes',
464
+ 'none': 'no type definition',
465
+ 'unknown': 'unknown pattern',
466
+ };
467
+ suggestions.push(`Consider ${typeDescriptions[targetTypes]}`);
468
+ }
469
+ return suggestions.join('. ');
470
+ }
471
+ // ============================================================================
472
+ // Pattern Description Helpers
473
+ // ============================================================================
474
+ const DESTRUCTURING_DESCRIPTIONS = {
475
+ 'signature': 'props destructured in function signature',
476
+ 'body': 'props destructured in function body',
477
+ 'direct-access': 'props accessed directly',
478
+ 'none': 'no props',
479
+ 'unknown': 'unknown pattern',
480
+ };
481
+ const DEFAULTS_DESCRIPTIONS = {
482
+ 'static-defaultProps': 'static defaultProps',
483
+ 'default-parameters': 'default parameters in signature',
484
+ 'destructuring-defaults': 'defaults in destructuring',
485
+ 'logical-or': 'logical OR for defaults',
486
+ 'nullish-coalescing': 'nullish coalescing for defaults',
487
+ 'none': 'no defaults',
488
+ 'unknown': 'unknown pattern',
489
+ };
490
+ const TYPE_DESCRIPTIONS = {
491
+ 'interface': 'interface for props type',
492
+ 'type-alias': 'type alias for props type',
493
+ 'inline': 'inline type annotation',
494
+ 'generic': 'FC<Props> generic type',
495
+ 'prop-types': 'PropTypes',
496
+ 'none': 'no type definition',
497
+ 'unknown': 'unknown pattern',
498
+ };
499
+ // ============================================================================
500
+ // Props Patterns Detector Class
501
+ // ============================================================================
502
+ /**
503
+ * Detector for component props patterns
504
+ *
505
+ * Identifies props handling patterns including destructuring, defaults,
506
+ * spreading, and type definitions. Reports violations when components
507
+ * don't follow the dominant pattern.
508
+ *
509
+ * @requirements 8.2 - THE Component_Detector SHALL detect props patterns
510
+ */
511
+ export class PropsPatternDetector extends ASTDetector {
512
+ id = 'components/props-patterns';
513
+ category = 'components';
514
+ subcategory = 'props-handling';
515
+ name = 'Props Pattern Detector';
516
+ description = 'Detects props handling patterns (destructuring, defaults, types) and identifies inconsistencies';
517
+ supportedLanguages = ['typescript', 'javascript'];
518
+ /**
519
+ * Detect props patterns in the project
520
+ */
521
+ async detect(context) {
522
+ const patterns = [];
523
+ const violations = [];
524
+ // If no AST, try to detect patterns from content using regex
525
+ const componentInfos = this.findComponentsInFile(context);
526
+ if (componentInfos.length === 0) {
527
+ return this.createEmptyResult();
528
+ }
529
+ // Analyze patterns across all components
530
+ const analysis = analyzePropsPatterns(componentInfos);
531
+ // Create pattern matches for detected patterns
532
+ if (analysis.dominantDestructuringPattern !== 'unknown' && analysis.confidence.destructuring > 0.3) {
533
+ patterns.push(this.createDestructuringPattern(context.file, analysis));
534
+ }
535
+ if (analysis.dominantDefaultPropsPattern !== 'none' && analysis.confidence.defaults > 0.3) {
536
+ patterns.push(this.createDefaultsPattern(context.file, analysis));
537
+ }
538
+ if (analysis.dominantTypePattern !== 'none' && analysis.confidence.types > 0.3) {
539
+ patterns.push(this.createTypePattern(context.file, analysis));
540
+ }
541
+ // Generate violations for inconsistent components in current file
542
+ for (const inconsistent of analysis.inconsistentComponents) {
543
+ if (inconsistent.filePath === context.file) {
544
+ const violation = this.createInconsistencyViolation(inconsistent, analysis);
545
+ if (violation) {
546
+ violations.push(violation);
547
+ }
548
+ }
549
+ }
550
+ const overallConfidence = Math.max(analysis.confidence.destructuring, analysis.confidence.defaults, analysis.confidence.types);
551
+ return this.createResult(patterns, violations, overallConfidence);
552
+ }
553
+ /**
554
+ * Find all React components in a file
555
+ */
556
+ findComponentsInFile(context) {
557
+ const components = [];
558
+ if (context.ast) {
559
+ // Use AST to find components
560
+ const functionNodes = this.findNodesByTypes(context.ast, [
561
+ 'function_declaration',
562
+ 'arrow_function',
563
+ 'function_expression',
564
+ ]);
565
+ for (const node of functionNodes) {
566
+ if (isReactComponent(node, context.content)) {
567
+ const info = analyzeComponentProps(node, context.content, context.file);
568
+ if (info) {
569
+ components.push(info);
570
+ }
571
+ }
572
+ }
573
+ }
574
+ else {
575
+ // Fallback: use regex-based detection
576
+ const componentMatches = this.findComponentsWithRegex(context.content, context.file);
577
+ components.push(...componentMatches);
578
+ }
579
+ return components;
580
+ }
581
+ /**
582
+ * Find components using regex (fallback when AST is not available)
583
+ */
584
+ findComponentsWithRegex(content, filePath) {
585
+ const components = [];
586
+ const seenComponents = new Set();
587
+ // Multiple patterns for different component styles
588
+ // Arrow function: const Button = ({ name }) => ...
589
+ const arrowPattern = /(?:export\s+)?const\s+([A-Z][a-zA-Z0-9]*)\s*(?::\s*(?:React\.)?(?:FC|FunctionComponent|VFC)\s*<[^>]*>\s*)?=\s*\(/g;
590
+ // Function declaration: function Button({ name }) { ... }
591
+ const functionPattern = /(?:export\s+)?function\s+([A-Z][a-zA-Z0-9]*)\s*\(/g;
592
+ const processPattern = (pattern) => {
593
+ let match;
594
+ while ((match = pattern.exec(content)) !== null) {
595
+ const componentName = match[1];
596
+ if (!componentName || seenComponents.has(componentName))
597
+ continue;
598
+ // Find the line number
599
+ const beforeMatch = content.slice(0, match.index);
600
+ const lineNumber = beforeMatch.split('\n').length;
601
+ // Get the component body - find the matching closing brace/paren
602
+ const startIndex = match.index;
603
+ let braceCount = 0;
604
+ let parenCount = 0;
605
+ let endIndex = startIndex;
606
+ let foundArrow = false;
607
+ let inFunctionBody = false;
608
+ for (let i = startIndex; i < content.length && i < startIndex + 10000; i++) {
609
+ const char = content[i];
610
+ if (char === '(') {
611
+ parenCount++;
612
+ }
613
+ else if (char === ')') {
614
+ parenCount--;
615
+ }
616
+ else if (char === '=' && content[i + 1] === '>') {
617
+ foundArrow = true;
618
+ // Check if next non-whitespace char is { (block body) or something else (expression body)
619
+ let j = i + 2;
620
+ while (j < content.length && /\s/.test(content[j] || ''))
621
+ j++;
622
+ if (content[j] === '{') {
623
+ inFunctionBody = true;
624
+ }
625
+ }
626
+ else if (char === '{') {
627
+ braceCount++;
628
+ }
629
+ else if (char === '}') {
630
+ braceCount--;
631
+ if (inFunctionBody && braceCount === 0 && parenCount <= 0) {
632
+ endIndex = i + 1;
633
+ break;
634
+ }
635
+ }
636
+ else if ((char === ';' || (char === '\n' && i > startIndex + 20)) && foundArrow && !inFunctionBody && parenCount <= 0) {
637
+ // End of arrow function with expression body
638
+ endIndex = i + 1;
639
+ break;
640
+ }
641
+ }
642
+ // If we didn't find a proper end, try to get a reasonable chunk
643
+ if (endIndex === startIndex) {
644
+ endIndex = Math.min(startIndex + 2000, content.length);
645
+ }
646
+ const componentBody = content.slice(startIndex, endIndex);
647
+ // Check if it returns JSX - look for < followed by a tag name
648
+ const hasJSX = /<[A-Za-z]/.test(componentBody);
649
+ if (!hasJSX) {
650
+ continue;
651
+ }
652
+ seenComponents.add(componentName);
653
+ // Create a mock node for analysis
654
+ const mockNode = {
655
+ type: 'function_declaration',
656
+ text: componentBody,
657
+ startPosition: { row: lineNumber - 1, column: 0 },
658
+ endPosition: { row: lineNumber - 1 + componentBody.split('\n').length, column: 0 },
659
+ children: [],
660
+ };
661
+ const info = analyzeComponentProps(mockNode, content, filePath);
662
+ if (info) {
663
+ components.push(info);
664
+ }
665
+ }
666
+ };
667
+ processPattern(arrowPattern);
668
+ processPattern(functionPattern);
669
+ return components;
670
+ }
671
+ /**
672
+ * Create a pattern match for destructuring pattern
673
+ */
674
+ createDestructuringPattern(file, analysis) {
675
+ return {
676
+ patternId: `props-destructuring-${analysis.dominantDestructuringPattern}`,
677
+ location: { file, line: 1, column: 1 },
678
+ confidence: analysis.confidence.destructuring,
679
+ isOutlier: false,
680
+ };
681
+ }
682
+ /**
683
+ * Create a pattern match for defaults pattern
684
+ */
685
+ createDefaultsPattern(file, analysis) {
686
+ return {
687
+ patternId: `props-defaults-${analysis.dominantDefaultPropsPattern}`,
688
+ location: { file, line: 1, column: 1 },
689
+ confidence: analysis.confidence.defaults,
690
+ isOutlier: false,
691
+ };
692
+ }
693
+ /**
694
+ * Create a pattern match for type pattern
695
+ */
696
+ createTypePattern(file, analysis) {
697
+ return {
698
+ patternId: `props-types-${analysis.dominantTypePattern}`,
699
+ location: { file, line: 1, column: 1 },
700
+ confidence: analysis.confidence.types,
701
+ isOutlier: false,
702
+ };
703
+ }
704
+ /**
705
+ * Create a violation for an inconsistent component
706
+ */
707
+ createInconsistencyViolation(component, analysis) {
708
+ const inconsistencies = [];
709
+ // Check destructuring inconsistency
710
+ if (component.destructuringPattern !== analysis.dominantDestructuringPattern &&
711
+ component.destructuringPattern !== 'none' &&
712
+ component.destructuringPattern !== 'unknown' &&
713
+ analysis.confidence.destructuring > 0.5) {
714
+ inconsistencies.push(`uses ${DESTRUCTURING_DESCRIPTIONS[component.destructuringPattern]} but project uses ${DESTRUCTURING_DESCRIPTIONS[analysis.dominantDestructuringPattern]}`);
715
+ }
716
+ // Check defaults inconsistency
717
+ if (component.defaultPropsPattern !== analysis.dominantDefaultPropsPattern &&
718
+ component.defaultPropsPattern !== 'none' &&
719
+ component.defaultPropsPattern !== 'unknown' &&
720
+ analysis.confidence.defaults > 0.5) {
721
+ inconsistencies.push(`uses ${DEFAULTS_DESCRIPTIONS[component.defaultPropsPattern]} but project uses ${DEFAULTS_DESCRIPTIONS[analysis.dominantDefaultPropsPattern]}`);
722
+ }
723
+ // Check type inconsistency
724
+ if (component.typePattern !== analysis.dominantTypePattern &&
725
+ component.typePattern !== 'none' &&
726
+ component.typePattern !== 'unknown' &&
727
+ analysis.confidence.types > 0.5) {
728
+ inconsistencies.push(`uses ${TYPE_DESCRIPTIONS[component.typePattern]} but project uses ${TYPE_DESCRIPTIONS[analysis.dominantTypePattern]}`);
729
+ }
730
+ if (inconsistencies.length === 0) {
731
+ return null;
732
+ }
733
+ const range = {
734
+ start: { line: component.line, character: component.column },
735
+ end: { line: component.line, character: component.column },
736
+ };
737
+ const suggestion = generatePropsSuggestion(component, analysis.dominantDestructuringPattern, analysis.dominantDefaultPropsPattern, analysis.dominantTypePattern);
738
+ return {
739
+ id: `props-pattern-${component.componentName}-${component.filePath.replace(/[^a-zA-Z0-9]/g, '-')}`,
740
+ patternId: 'components/props-patterns',
741
+ severity: 'warning',
742
+ file: component.filePath,
743
+ range,
744
+ message: `Component '${component.componentName}' ${inconsistencies.join('; ')}. ${suggestion}`,
745
+ expected: `Consistent props handling following project patterns`,
746
+ actual: `Inconsistent props handling in ${component.componentName}`,
747
+ aiExplainAvailable: true,
748
+ aiFixAvailable: true,
749
+ firstSeen: new Date(),
750
+ occurrences: 1,
751
+ };
752
+ }
753
+ /**
754
+ * Generate a quick fix for props pattern violations
755
+ */
756
+ generateQuickFix(violation) {
757
+ // Extract the target pattern from the violation message
758
+ const destructuringMatch = violation.message.match(/project uses (props destructured in function signature|props destructured in function body|props accessed directly)/);
759
+ const defaultsMatch = violation.message.match(/project uses (default parameters in signature|defaults in destructuring|static defaultProps)/);
760
+ const typesMatch = violation.message.match(/project uses (interface for props type|type alias for props type|FC<Props> generic type)/);
761
+ if (!destructuringMatch && !defaultsMatch && !typesMatch) {
762
+ return null;
763
+ }
764
+ const suggestions = [];
765
+ if (destructuringMatch)
766
+ suggestions.push(destructuringMatch[1]);
767
+ if (defaultsMatch)
768
+ suggestions.push(defaultsMatch[1]);
769
+ if (typesMatch)
770
+ suggestions.push(typesMatch[1]);
771
+ return {
772
+ title: `Refactor to use ${suggestions.join(', ')}`,
773
+ kind: 'refactor',
774
+ edit: {
775
+ changes: {},
776
+ documentChanges: [
777
+ { uri: violation.file, edits: [] },
778
+ ],
779
+ },
780
+ isPreferred: true,
781
+ confidence: 0.6,
782
+ preview: `Refactor props handling to follow project patterns`,
783
+ };
784
+ }
785
+ }
786
+ // ============================================================================
787
+ // Factory Function
788
+ // ============================================================================
789
+ /**
790
+ * Create a new PropsPatternDetector instance
791
+ */
792
+ export function createPropsPatternDetector() {
793
+ return new PropsPatternDetector();
794
+ }
795
+ //# sourceMappingURL=props-patterns.js.map