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,888 @@
1
+ /**
2
+ * Responsive Detector - Breakpoint usage pattern detection
3
+ *
4
+ * Detects responsive breakpoint patterns including:
5
+ * - Tailwind responsive prefixes (sm:, md:, lg:, xl:, 2xl:)
6
+ * - CSS media queries (@media (min-width: ...), @media (max-width: ...))
7
+ * - CSS container queries (@container)
8
+ * - Theme breakpoint usage (theme.breakpoints.*, theme.screens.*)
9
+ * - CSS custom property breakpoints (var(--breakpoint-*))
10
+ * - Mobile-first vs desktop-first approaches
11
+ *
12
+ * Flags inconsistent responsive usage:
13
+ * - Inconsistent breakpoint ordering (e.g., lg: before md:)
14
+ * - Mixing mobile-first and desktop-first approaches
15
+ * - Arbitrary breakpoint values not matching the design system
16
+ * - Missing responsive variants for key breakpoints
17
+ * - Hardcoded pixel values in media queries instead of using design tokens
18
+ *
19
+ * @requirements 9.8 - THE Styling_Detector SHALL detect responsive breakpoint usage patterns
20
+ */
21
+ import { RegexDetector } from '../base/index.js';
22
+ // ============================================================================
23
+ // Constants
24
+ // ============================================================================
25
+ /**
26
+ * Standard Tailwind breakpoints (in pixels)
27
+ */
28
+ export const TAILWIND_BREAKPOINTS = {
29
+ sm: 640,
30
+ md: 768,
31
+ lg: 1024,
32
+ xl: 1280,
33
+ '2xl': 1536,
34
+ };
35
+ /**
36
+ * Tailwind breakpoint order (mobile-first)
37
+ */
38
+ export const TAILWIND_BREAKPOINT_ORDER = ['sm', 'md', 'lg', 'xl', '2xl'];
39
+ /**
40
+ * Common design system breakpoints (in pixels)
41
+ */
42
+ export const COMMON_BREAKPOINTS = {
43
+ xs: 320,
44
+ sm: 640,
45
+ md: 768,
46
+ lg: 1024,
47
+ xl: 1280,
48
+ '2xl': 1536,
49
+ '3xl': 1920,
50
+ };
51
+ /**
52
+ * Tailwind responsive prefix pattern
53
+ * Matches: sm:flex, md:hidden, lg:grid-cols-3, xl:p-4, 2xl:text-lg
54
+ */
55
+ export const TAILWIND_RESPONSIVE_PATTERN = /\b(sm|md|lg|xl|2xl):([a-z][a-z0-9-]*(?:-[a-z0-9]+)*(?:\[[^\]]+\])?)/gi;
56
+ /**
57
+ * CSS media query pattern (min-width - mobile-first)
58
+ * Matches: @media (min-width: 768px), @media screen and (min-width: 1024px)
59
+ */
60
+ export const CSS_MEDIA_QUERY_MIN_WIDTH_PATTERN = /@media\s+(?:screen\s+and\s+)?\(\s*min-width\s*:\s*(\d+(?:\.\d+)?)(px|em|rem)\s*\)/gi;
61
+ /**
62
+ * CSS media query pattern (max-width - desktop-first)
63
+ * Matches: @media (max-width: 768px), @media screen and (max-width: 1024px)
64
+ */
65
+ export const CSS_MEDIA_QUERY_MAX_WIDTH_PATTERN = /@media\s+(?:screen\s+and\s+)?\(\s*max-width\s*:\s*(\d+(?:\.\d+)?)(px|em|rem)\s*\)/gi;
66
+ /**
67
+ * CSS container query pattern
68
+ * Matches: @container (min-width: 400px), @container sidebar (min-width: 300px)
69
+ */
70
+ export const CSS_CONTAINER_QUERY_PATTERN = /@container\s*(?:\w+\s*)?\(\s*(?:min|max)-width\s*:\s*(\d+(?:\.\d+)?)(px|em|rem)\s*\)/gi;
71
+ /**
72
+ * Theme breakpoint usage patterns
73
+ */
74
+ export const THEME_BREAKPOINT_PATTERNS = [
75
+ // theme.breakpoints.*, theme.screens.*
76
+ /theme\.(?:breakpoints|screens)\.([a-zA-Z0-9_]+)/g,
77
+ // ${theme.breakpoints.*} in template literals
78
+ /\$\{theme\.(?:breakpoints|screens)\.([a-zA-Z0-9_]+)\}/g,
79
+ // props.theme.breakpoints.*
80
+ /props\.theme\.(?:breakpoints|screens)\.([a-zA-Z0-9_]+)/g,
81
+ ];
82
+ /**
83
+ * CSS custom property breakpoint patterns
84
+ * Matches: var(--breakpoint-sm), var(--screen-md)
85
+ */
86
+ export const CSS_BREAKPOINT_PROPERTY_PATTERN = /var\(\s*--(?:breakpoint|screen|bp)[-_]?([a-zA-Z0-9_-]*)\s*(?:,\s*[^)]+)?\)/gi;
87
+ /**
88
+ * Hardcoded media query pixel values (arbitrary values)
89
+ */
90
+ export const HARDCODED_MEDIA_QUERY_PATTERN = /@media\s+(?:screen\s+and\s+)?\(\s*(?:min|max)-width\s*:\s*(\d+(?:\.\d+)?)(px)\s*\)/gi;
91
+ /**
92
+ * File patterns to exclude from responsive detection
93
+ */
94
+ export const EXCLUDED_FILE_PATTERNS = [
95
+ /\.test\.[jt]sx?$/,
96
+ /\.spec\.[jt]sx?$/,
97
+ /\.stories\.[jt]sx?$/,
98
+ /tailwind\.config\.[jt]s$/,
99
+ /postcss\.config\.[jt]s$/,
100
+ ];
101
+ /**
102
+ * Allowed arbitrary breakpoint values (common exceptions)
103
+ */
104
+ export const ALLOWED_BREAKPOINT_VALUES = new Set([
105
+ 320, 375, 414, 480, // Common mobile sizes
106
+ 640, 768, 1024, 1280, 1536, 1920, // Standard breakpoints
107
+ ]);
108
+ // ============================================================================
109
+ // Helper Functions
110
+ // ============================================================================
111
+ /**
112
+ * Check if a file should be excluded from responsive detection
113
+ */
114
+ export function shouldExcludeFile(filePath) {
115
+ return EXCLUDED_FILE_PATTERNS.some(pattern => pattern.test(filePath));
116
+ }
117
+ /**
118
+ * Check if a position is inside a comment
119
+ */
120
+ function isInsideComment(content, index) {
121
+ const beforeIndex = content.slice(0, index);
122
+ // Check for single-line comment
123
+ const lastNewline = beforeIndex.lastIndexOf('\n');
124
+ const currentLine = beforeIndex.slice(lastNewline + 1);
125
+ if (currentLine.includes('//')) {
126
+ const commentStart = currentLine.indexOf('//');
127
+ const positionInLine = index - lastNewline - 1;
128
+ if (positionInLine > commentStart) {
129
+ return true;
130
+ }
131
+ }
132
+ // Check for multi-line comment
133
+ const lastBlockCommentStart = beforeIndex.lastIndexOf('/*');
134
+ const lastBlockCommentEnd = beforeIndex.lastIndexOf('*/');
135
+ if (lastBlockCommentStart > lastBlockCommentEnd) {
136
+ return true;
137
+ }
138
+ return false;
139
+ }
140
+ /**
141
+ * Check if a breakpoint value is in the standard set
142
+ */
143
+ export function isStandardBreakpoint(value) {
144
+ return Object.values(TAILWIND_BREAKPOINTS).includes(value);
145
+ }
146
+ /**
147
+ * Check if a breakpoint value is allowed (standard or common exception)
148
+ */
149
+ export function isAllowedBreakpointValue(value) {
150
+ return ALLOWED_BREAKPOINT_VALUES.has(value) || isStandardBreakpoint(value);
151
+ }
152
+ /**
153
+ * Get the breakpoint order index for a Tailwind breakpoint
154
+ */
155
+ export function getBreakpointOrderIndex(breakpoint) {
156
+ return TAILWIND_BREAKPOINT_ORDER.indexOf(breakpoint);
157
+ }
158
+ /**
159
+ * Find the nearest standard breakpoint value
160
+ */
161
+ export function findNearestBreakpoint(value) {
162
+ const breakpoints = Object.entries(TAILWIND_BREAKPOINTS);
163
+ let nearest = breakpoints[0];
164
+ let minDiff = Math.abs(value - nearest[1]);
165
+ for (const [name, bpValue] of breakpoints) {
166
+ const diff = Math.abs(value - bpValue);
167
+ if (diff < minDiff) {
168
+ minDiff = diff;
169
+ nearest = [name, bpValue];
170
+ }
171
+ }
172
+ return { name: nearest[0], value: nearest[1] };
173
+ }
174
+ /**
175
+ * Suggest a standard breakpoint for an arbitrary value
176
+ */
177
+ export function suggestBreakpoint(value) {
178
+ const nearest = findNearestBreakpoint(value);
179
+ return `Use standard breakpoint '${nearest.name}' (${nearest.value}px) instead of ${value}px`;
180
+ }
181
+ /**
182
+ * Convert em/rem to pixels (assuming 16px base)
183
+ */
184
+ export function convertToPixels(value, unit) {
185
+ if (unit === 'em' || unit === 'rem') {
186
+ return value * 16;
187
+ }
188
+ return value;
189
+ }
190
+ /**
191
+ * Detect Tailwind responsive prefixes in content
192
+ */
193
+ export function detectTailwindResponsive(content, file) {
194
+ const results = [];
195
+ const lines = content.split('\n');
196
+ const regex = new RegExp(TAILWIND_RESPONSIVE_PATTERN.source, TAILWIND_RESPONSIVE_PATTERN.flags);
197
+ let match;
198
+ while ((match = regex.exec(content)) !== null) {
199
+ // Skip if inside a comment
200
+ if (isInsideComment(content, match.index)) {
201
+ continue;
202
+ }
203
+ const beforeMatch = content.slice(0, match.index);
204
+ const lineNumber = beforeMatch.split('\n').length;
205
+ const lastNewline = beforeMatch.lastIndexOf('\n');
206
+ const column = match.index - lastNewline;
207
+ const breakpoint = match[1] || '';
208
+ const breakpointValue = TAILWIND_BREAKPOINTS[breakpoint];
209
+ results.push({
210
+ type: 'tailwind-responsive',
211
+ file,
212
+ line: lineNumber,
213
+ column,
214
+ matchedText: match[0],
215
+ breakpoint,
216
+ breakpointValue,
217
+ context: lines[lineNumber - 1] || '',
218
+ });
219
+ }
220
+ return results;
221
+ }
222
+ /**
223
+ * Detect CSS media queries (min-width - mobile-first)
224
+ */
225
+ export function detectCSSMediaQueriesMinWidth(content, file) {
226
+ const results = [];
227
+ const lines = content.split('\n');
228
+ const regex = new RegExp(CSS_MEDIA_QUERY_MIN_WIDTH_PATTERN.source, CSS_MEDIA_QUERY_MIN_WIDTH_PATTERN.flags);
229
+ let match;
230
+ while ((match = regex.exec(content)) !== null) {
231
+ // Skip if inside a comment
232
+ if (isInsideComment(content, match.index)) {
233
+ continue;
234
+ }
235
+ const beforeMatch = content.slice(0, match.index);
236
+ const lineNumber = beforeMatch.split('\n').length;
237
+ const lastNewline = beforeMatch.lastIndexOf('\n');
238
+ const column = match.index - lastNewline;
239
+ const value = parseFloat(match[1] || '0');
240
+ const unit = match[2] || 'px';
241
+ const breakpointValue = convertToPixels(value, unit);
242
+ results.push({
243
+ type: 'mobile-first',
244
+ file,
245
+ line: lineNumber,
246
+ column,
247
+ matchedText: match[0],
248
+ breakpoint: `${value}${unit}`,
249
+ breakpointValue,
250
+ context: lines[lineNumber - 1] || '',
251
+ });
252
+ }
253
+ return results;
254
+ }
255
+ /**
256
+ * Detect CSS media queries (max-width - desktop-first)
257
+ */
258
+ export function detectCSSMediaQueriesMaxWidth(content, file) {
259
+ const results = [];
260
+ const lines = content.split('\n');
261
+ const regex = new RegExp(CSS_MEDIA_QUERY_MAX_WIDTH_PATTERN.source, CSS_MEDIA_QUERY_MAX_WIDTH_PATTERN.flags);
262
+ let match;
263
+ while ((match = regex.exec(content)) !== null) {
264
+ // Skip if inside a comment
265
+ if (isInsideComment(content, match.index)) {
266
+ continue;
267
+ }
268
+ const beforeMatch = content.slice(0, match.index);
269
+ const lineNumber = beforeMatch.split('\n').length;
270
+ const lastNewline = beforeMatch.lastIndexOf('\n');
271
+ const column = match.index - lastNewline;
272
+ const value = parseFloat(match[1] || '0');
273
+ const unit = match[2] || 'px';
274
+ const breakpointValue = convertToPixels(value, unit);
275
+ results.push({
276
+ type: 'desktop-first',
277
+ file,
278
+ line: lineNumber,
279
+ column,
280
+ matchedText: match[0],
281
+ breakpoint: `${value}${unit}`,
282
+ breakpointValue,
283
+ context: lines[lineNumber - 1] || '',
284
+ });
285
+ }
286
+ return results;
287
+ }
288
+ /**
289
+ * Detect CSS container queries
290
+ */
291
+ export function detectCSSContainerQueries(content, file) {
292
+ const results = [];
293
+ const lines = content.split('\n');
294
+ const regex = new RegExp(CSS_CONTAINER_QUERY_PATTERN.source, CSS_CONTAINER_QUERY_PATTERN.flags);
295
+ let match;
296
+ while ((match = regex.exec(content)) !== null) {
297
+ // Skip if inside a comment
298
+ if (isInsideComment(content, match.index)) {
299
+ continue;
300
+ }
301
+ const beforeMatch = content.slice(0, match.index);
302
+ const lineNumber = beforeMatch.split('\n').length;
303
+ const lastNewline = beforeMatch.lastIndexOf('\n');
304
+ const column = match.index - lastNewline;
305
+ const value = parseFloat(match[1] || '0');
306
+ const unit = match[2] || 'px';
307
+ const breakpointValue = convertToPixels(value, unit);
308
+ results.push({
309
+ type: 'css-container-query',
310
+ file,
311
+ line: lineNumber,
312
+ column,
313
+ matchedText: match[0],
314
+ breakpoint: `${value}${unit}`,
315
+ breakpointValue,
316
+ context: lines[lineNumber - 1] || '',
317
+ });
318
+ }
319
+ return results;
320
+ }
321
+ /**
322
+ * Detect theme breakpoint usage
323
+ */
324
+ export function detectThemeBreakpoints(content, file) {
325
+ const results = [];
326
+ const lines = content.split('\n');
327
+ for (const pattern of THEME_BREAKPOINT_PATTERNS) {
328
+ const regex = new RegExp(pattern.source, pattern.flags);
329
+ let match;
330
+ while ((match = regex.exec(content)) !== null) {
331
+ // Skip if inside a comment
332
+ if (isInsideComment(content, match.index)) {
333
+ continue;
334
+ }
335
+ const beforeMatch = content.slice(0, match.index);
336
+ const lineNumber = beforeMatch.split('\n').length;
337
+ const lastNewline = beforeMatch.lastIndexOf('\n');
338
+ const column = match.index - lastNewline;
339
+ const breakpoint = match[1] || '';
340
+ const breakpointValue = TAILWIND_BREAKPOINTS[breakpoint];
341
+ results.push({
342
+ type: 'theme-breakpoint',
343
+ file,
344
+ line: lineNumber,
345
+ column,
346
+ matchedText: match[0],
347
+ breakpoint,
348
+ breakpointValue,
349
+ context: lines[lineNumber - 1] || '',
350
+ });
351
+ }
352
+ }
353
+ return results;
354
+ }
355
+ /**
356
+ * Detect CSS custom property breakpoints
357
+ */
358
+ export function detectCSSBreakpointProperties(content, file) {
359
+ const results = [];
360
+ const lines = content.split('\n');
361
+ const regex = new RegExp(CSS_BREAKPOINT_PROPERTY_PATTERN.source, CSS_BREAKPOINT_PROPERTY_PATTERN.flags);
362
+ let match;
363
+ while ((match = regex.exec(content)) !== null) {
364
+ // Skip if inside a comment
365
+ if (isInsideComment(content, match.index)) {
366
+ continue;
367
+ }
368
+ const beforeMatch = content.slice(0, match.index);
369
+ const lineNumber = beforeMatch.split('\n').length;
370
+ const lastNewline = beforeMatch.lastIndexOf('\n');
371
+ const column = match.index - lastNewline;
372
+ const breakpoint = match[1] || '';
373
+ const breakpointValue = TAILWIND_BREAKPOINTS[breakpoint];
374
+ results.push({
375
+ type: 'css-breakpoint-property',
376
+ file,
377
+ line: lineNumber,
378
+ column,
379
+ matchedText: match[0],
380
+ breakpoint,
381
+ breakpointValue,
382
+ context: lines[lineNumber - 1] || '',
383
+ });
384
+ }
385
+ return results;
386
+ }
387
+ /**
388
+ * Extract all class names from a className attribute
389
+ */
390
+ function extractClassNamesFromLine(line) {
391
+ const classNames = [];
392
+ // Match className="..." or class="..."
393
+ const classAttrMatch = line.match(/(?:className|class)=["']([^"']+)["']/);
394
+ if (classAttrMatch && classAttrMatch[1]) {
395
+ classNames.push(...classAttrMatch[1].split(/\s+/).filter(Boolean));
396
+ }
397
+ // Match className={`...`} template literals
398
+ const templateMatch = line.match(/(?:className|class)=\{`([^`]+)`\}/);
399
+ if (templateMatch && templateMatch[1]) {
400
+ // Extract static parts (ignore ${...} expressions)
401
+ const staticParts = templateMatch[1].replace(/\$\{[^}]+\}/g, ' ');
402
+ classNames.push(...staticParts.split(/\s+/).filter(Boolean));
403
+ }
404
+ return classNames;
405
+ }
406
+ /**
407
+ * Detect inconsistent breakpoint ordering in Tailwind classes
408
+ */
409
+ export function detectInconsistentBreakpointOrder(content, file) {
410
+ const results = [];
411
+ const lines = content.split('\n');
412
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
413
+ const line = lines[lineIndex];
414
+ const classNames = extractClassNamesFromLine(line);
415
+ if (classNames.length === 0)
416
+ continue;
417
+ // Group responsive classes by their base class
418
+ const responsiveGroups = new Map();
419
+ classNames.forEach((className, index) => {
420
+ const match = className.match(/^(sm|md|lg|xl|2xl):(.+)$/);
421
+ if (match) {
422
+ const breakpoint = match[1];
423
+ const baseClass = match[2];
424
+ // Extract the property prefix (e.g., 'flex' from 'flex', 'p' from 'p-4')
425
+ const propertyMatch = baseClass.match(/^([a-z]+(?:-[a-z]+)*?)(?:-\d|$|\[)/i);
426
+ const propertyPrefix = propertyMatch ? propertyMatch[1] : baseClass;
427
+ if (!responsiveGroups.has(propertyPrefix)) {
428
+ responsiveGroups.set(propertyPrefix, []);
429
+ }
430
+ responsiveGroups.get(propertyPrefix).push({ breakpoint, className, index });
431
+ }
432
+ });
433
+ // Check each group for ordering issues
434
+ for (const [_propertyPrefix, group] of responsiveGroups) {
435
+ if (group.length < 2)
436
+ continue;
437
+ // Check if breakpoints are in correct order
438
+ for (let i = 0; i < group.length - 1; i++) {
439
+ const current = group[i];
440
+ const next = group[i + 1];
441
+ const currentOrder = getBreakpointOrderIndex(current.breakpoint);
442
+ const nextOrder = getBreakpointOrderIndex(next.breakpoint);
443
+ // If current breakpoint should come after next (wrong order)
444
+ if (currentOrder > nextOrder && current.index < next.index) {
445
+ const classIndex = line.indexOf(current.className);
446
+ const column = classIndex >= 0 ? classIndex + 1 : 1;
447
+ results.push({
448
+ type: 'inconsistent-breakpoint-order',
449
+ file,
450
+ line: lineIndex + 1,
451
+ column,
452
+ endLine: lineIndex + 1,
453
+ endColumn: column + current.className.length,
454
+ breakpoints: [current.breakpoint, next.breakpoint],
455
+ issue: `Breakpoint '${current.breakpoint}:' appears before '${next.breakpoint}:' but should come after (mobile-first order: sm → md → lg → xl → 2xl)`,
456
+ suggestedFix: `Reorder classes to follow mobile-first breakpoint order: ${TAILWIND_BREAKPOINT_ORDER.join(' → ')}`,
457
+ lineContent: line,
458
+ });
459
+ }
460
+ }
461
+ }
462
+ }
463
+ return results;
464
+ }
465
+ /**
466
+ * Detect mixed mobile-first and desktop-first approaches
467
+ */
468
+ export function detectMixedApproach(mobileFirstPatterns, desktopFirstPatterns, file) {
469
+ const results = [];
470
+ // Only flag if both approaches are used significantly
471
+ if (mobileFirstPatterns.length > 0 && desktopFirstPatterns.length > 0) {
472
+ const totalPatterns = mobileFirstPatterns.length + desktopFirstPatterns.length;
473
+ const mobileFirstRatio = mobileFirstPatterns.length / totalPatterns;
474
+ // If neither approach is dominant (both > 20%), flag as mixed
475
+ if (mobileFirstRatio > 0.2 && mobileFirstRatio < 0.8) {
476
+ // Flag the minority approach patterns
477
+ const minorityPatterns = mobileFirstRatio > 0.5 ? desktopFirstPatterns : mobileFirstPatterns;
478
+ const dominantApproach = mobileFirstRatio > 0.5 ? 'mobile-first (min-width)' : 'desktop-first (max-width)';
479
+ for (const pattern of minorityPatterns) {
480
+ results.push({
481
+ type: 'mixed-approach',
482
+ file,
483
+ line: pattern.line,
484
+ column: pattern.column,
485
+ endLine: pattern.line,
486
+ endColumn: pattern.column + pattern.matchedText.length,
487
+ breakpoints: [pattern.breakpoint || ''],
488
+ issue: `File mixes mobile-first and desktop-first approaches. This media query uses ${pattern.type === 'mobile-first' ? 'min-width' : 'max-width'}, but the file predominantly uses ${dominantApproach}`,
489
+ suggestedFix: `Consider standardizing on ${dominantApproach} approach for consistency`,
490
+ lineContent: pattern.context || '',
491
+ });
492
+ }
493
+ }
494
+ }
495
+ return results;
496
+ }
497
+ /**
498
+ * Detect arbitrary/hardcoded breakpoint values in media queries
499
+ */
500
+ export function detectArbitraryBreakpoints(content, file) {
501
+ const results = [];
502
+ const lines = content.split('\n');
503
+ const regex = new RegExp(HARDCODED_MEDIA_QUERY_PATTERN.source, HARDCODED_MEDIA_QUERY_PATTERN.flags);
504
+ let match;
505
+ while ((match = regex.exec(content)) !== null) {
506
+ // Skip if inside a comment
507
+ if (isInsideComment(content, match.index)) {
508
+ continue;
509
+ }
510
+ const value = parseFloat(match[1] || '0');
511
+ // Skip if it's a standard breakpoint value
512
+ if (isAllowedBreakpointValue(value)) {
513
+ continue;
514
+ }
515
+ const beforeMatch = content.slice(0, match.index);
516
+ const lineNumber = beforeMatch.split('\n').length;
517
+ const lastNewline = beforeMatch.lastIndexOf('\n');
518
+ const column = match.index - lastNewline;
519
+ const endColumn = column + match[0].length;
520
+ results.push({
521
+ type: 'arbitrary-breakpoint',
522
+ file,
523
+ line: lineNumber,
524
+ column,
525
+ endLine: lineNumber,
526
+ endColumn,
527
+ breakpoints: [`${value}px`],
528
+ issue: `Arbitrary breakpoint value '${value}px' doesn't match standard design system breakpoints`,
529
+ suggestedFix: suggestBreakpoint(value),
530
+ lineContent: lines[lineNumber - 1] || '',
531
+ });
532
+ }
533
+ return results;
534
+ }
535
+ /**
536
+ * Analyze responsive patterns in a file
537
+ */
538
+ export function analyzeResponsive(content, file) {
539
+ // Skip excluded files
540
+ if (shouldExcludeFile(file)) {
541
+ return {
542
+ patterns: [],
543
+ violations: [],
544
+ usesTailwindResponsive: false,
545
+ usesCSSMediaQueries: false,
546
+ usesCSSContainerQueries: false,
547
+ usesThemeBreakpoints: false,
548
+ usesCSSBreakpointProperties: false,
549
+ usesMobileFirst: false,
550
+ usesDesktopFirst: false,
551
+ responsiveConsistencyConfidence: 1.0,
552
+ };
553
+ }
554
+ // Detect all patterns
555
+ const tailwindResponsive = detectTailwindResponsive(content, file);
556
+ const mobileFirstQueries = detectCSSMediaQueriesMinWidth(content, file);
557
+ const desktopFirstQueries = detectCSSMediaQueriesMaxWidth(content, file);
558
+ const containerQueries = detectCSSContainerQueries(content, file);
559
+ const themeBreakpoints = detectThemeBreakpoints(content, file);
560
+ const cssBreakpointProperties = detectCSSBreakpointProperties(content, file);
561
+ const allPatterns = [
562
+ ...tailwindResponsive,
563
+ ...mobileFirstQueries,
564
+ ...desktopFirstQueries,
565
+ ...containerQueries,
566
+ ...themeBreakpoints,
567
+ ...cssBreakpointProperties,
568
+ ];
569
+ // Detect violations
570
+ const breakpointOrderViolations = detectInconsistentBreakpointOrder(content, file);
571
+ const mixedApproachViolations = detectMixedApproach(mobileFirstQueries, desktopFirstQueries, file);
572
+ const arbitraryBreakpointViolations = detectArbitraryBreakpoints(content, file);
573
+ const allViolations = [
574
+ ...breakpointOrderViolations,
575
+ ...mixedApproachViolations,
576
+ ...arbitraryBreakpointViolations,
577
+ ];
578
+ // Calculate confidence
579
+ const hasPatterns = allPatterns.length > 0;
580
+ const hasViolations = allViolations.length > 0;
581
+ let responsiveConsistencyConfidence = 0;
582
+ if (hasPatterns && !hasViolations) {
583
+ responsiveConsistencyConfidence = 1.0;
584
+ }
585
+ else if (hasPatterns && hasViolations) {
586
+ const ratio = allPatterns.length / (allPatterns.length + allViolations.length);
587
+ responsiveConsistencyConfidence = ratio;
588
+ }
589
+ else if (!hasPatterns && hasViolations) {
590
+ responsiveConsistencyConfidence = 0;
591
+ }
592
+ else {
593
+ responsiveConsistencyConfidence = 0.5; // No responsive patterns detected
594
+ }
595
+ return {
596
+ patterns: allPatterns,
597
+ violations: allViolations,
598
+ usesTailwindResponsive: tailwindResponsive.length > 0,
599
+ usesCSSMediaQueries: mobileFirstQueries.length > 0 || desktopFirstQueries.length > 0,
600
+ usesCSSContainerQueries: containerQueries.length > 0,
601
+ usesThemeBreakpoints: themeBreakpoints.length > 0,
602
+ usesCSSBreakpointProperties: cssBreakpointProperties.length > 0,
603
+ usesMobileFirst: mobileFirstQueries.length > 0,
604
+ usesDesktopFirst: desktopFirstQueries.length > 0,
605
+ responsiveConsistencyConfidence,
606
+ };
607
+ }
608
+ // ============================================================================
609
+ // Responsive Detector Class
610
+ // ============================================================================
611
+ /**
612
+ * Detector for responsive breakpoint usage patterns
613
+ *
614
+ * Identifies responsive patterns (Tailwind prefixes, CSS media queries, container queries)
615
+ * and flags inconsistent breakpoint usage.
616
+ *
617
+ * @requirements 9.8 - THE Styling_Detector SHALL detect responsive breakpoint usage patterns
618
+ */
619
+ export class ResponsiveDetector extends RegexDetector {
620
+ id = 'styling/responsive';
621
+ category = 'styling';
622
+ subcategory = 'responsive';
623
+ name = 'Responsive Detector';
624
+ description = 'Detects responsive breakpoint usage patterns and flags inconsistent breakpoint ordering, mixed approaches, and arbitrary values';
625
+ supportedLanguages = ['typescript', 'javascript', 'css'];
626
+ /**
627
+ * Detect responsive patterns and violations
628
+ */
629
+ async detect(context) {
630
+ const patterns = [];
631
+ const violations = [];
632
+ // Analyze the file
633
+ const analysis = analyzeResponsive(context.content, context.file);
634
+ // Create pattern matches for responsive patterns
635
+ if (analysis.usesTailwindResponsive) {
636
+ patterns.push(this.createTailwindResponsivePattern(context.file, analysis));
637
+ }
638
+ if (analysis.usesCSSMediaQueries) {
639
+ patterns.push(this.createCSSMediaQueryPattern(context.file, analysis));
640
+ }
641
+ if (analysis.usesCSSContainerQueries) {
642
+ patterns.push(this.createCSSContainerQueryPattern(context.file, analysis));
643
+ }
644
+ if (analysis.usesThemeBreakpoints) {
645
+ patterns.push(this.createThemeBreakpointPattern(context.file, analysis));
646
+ }
647
+ if (analysis.usesCSSBreakpointProperties) {
648
+ patterns.push(this.createCSSBreakpointPropertyPattern(context.file, analysis));
649
+ }
650
+ // Create violations
651
+ for (const violation of analysis.violations) {
652
+ violations.push(this.createResponsiveViolation(violation));
653
+ }
654
+ return this.createResult(patterns, violations, analysis.responsiveConsistencyConfidence);
655
+ }
656
+ /**
657
+ * Create a pattern match for Tailwind responsive usage
658
+ */
659
+ createTailwindResponsivePattern(file, analysis) {
660
+ const tailwindPatterns = analysis.patterns.filter(p => p.type === 'tailwind-responsive');
661
+ const firstPattern = tailwindPatterns[0];
662
+ return {
663
+ patternId: `${this.id}/tailwind`,
664
+ location: {
665
+ file,
666
+ line: firstPattern?.line || 1,
667
+ column: firstPattern?.column || 1,
668
+ },
669
+ confidence: 1.0,
670
+ isOutlier: false,
671
+ };
672
+ }
673
+ /**
674
+ * Create a pattern match for CSS media query usage
675
+ */
676
+ createCSSMediaQueryPattern(file, analysis) {
677
+ const mediaQueryPatterns = analysis.patterns.filter(p => p.type === 'mobile-first' || p.type === 'desktop-first');
678
+ const firstPattern = mediaQueryPatterns[0];
679
+ return {
680
+ patternId: `${this.id}/media-query`,
681
+ location: {
682
+ file,
683
+ line: firstPattern?.line || 1,
684
+ column: firstPattern?.column || 1,
685
+ },
686
+ confidence: 1.0,
687
+ isOutlier: false,
688
+ };
689
+ }
690
+ /**
691
+ * Create a pattern match for CSS container query usage
692
+ */
693
+ createCSSContainerQueryPattern(file, analysis) {
694
+ const containerPatterns = analysis.patterns.filter(p => p.type === 'css-container-query');
695
+ const firstPattern = containerPatterns[0];
696
+ return {
697
+ patternId: `${this.id}/container-query`,
698
+ location: {
699
+ file,
700
+ line: firstPattern?.line || 1,
701
+ column: firstPattern?.column || 1,
702
+ },
703
+ confidence: 1.0,
704
+ isOutlier: false,
705
+ };
706
+ }
707
+ /**
708
+ * Create a pattern match for theme breakpoint usage
709
+ */
710
+ createThemeBreakpointPattern(file, analysis) {
711
+ const themePatterns = analysis.patterns.filter(p => p.type === 'theme-breakpoint');
712
+ const firstPattern = themePatterns[0];
713
+ return {
714
+ patternId: `${this.id}/theme`,
715
+ location: {
716
+ file,
717
+ line: firstPattern?.line || 1,
718
+ column: firstPattern?.column || 1,
719
+ },
720
+ confidence: 1.0,
721
+ isOutlier: false,
722
+ };
723
+ }
724
+ /**
725
+ * Create a pattern match for CSS breakpoint property usage
726
+ */
727
+ createCSSBreakpointPropertyPattern(file, analysis) {
728
+ const cssPatterns = analysis.patterns.filter(p => p.type === 'css-breakpoint-property');
729
+ const firstPattern = cssPatterns[0];
730
+ return {
731
+ patternId: `${this.id}/css-property`,
732
+ location: {
733
+ file,
734
+ line: firstPattern?.line || 1,
735
+ column: firstPattern?.column || 1,
736
+ },
737
+ confidence: 1.0,
738
+ isOutlier: false,
739
+ };
740
+ }
741
+ /**
742
+ * Create a violation for a responsive issue
743
+ */
744
+ createResponsiveViolation(violationInfo) {
745
+ const severity = violationInfo.type === 'arbitrary-breakpoint' ? 'warning' : 'info';
746
+ const violation = {
747
+ id: `${this.id}-${violationInfo.file}-${violationInfo.line}-${violationInfo.column}`,
748
+ patternId: this.id,
749
+ severity,
750
+ file: violationInfo.file,
751
+ range: {
752
+ start: { line: violationInfo.line - 1, character: violationInfo.column - 1 },
753
+ end: { line: violationInfo.endLine - 1, character: violationInfo.endColumn - 1 },
754
+ },
755
+ message: violationInfo.issue,
756
+ explanation: this.getExplanation(violationInfo),
757
+ expected: this.getExpectedValue(violationInfo),
758
+ actual: violationInfo.breakpoints.join(', '),
759
+ aiExplainAvailable: true,
760
+ aiFixAvailable: violationInfo.type === 'arbitrary-breakpoint',
761
+ firstSeen: new Date(),
762
+ occurrences: 1,
763
+ };
764
+ const quickFix = this.createQuickFixForViolation(violationInfo);
765
+ if (quickFix !== undefined) {
766
+ violation.quickFix = quickFix;
767
+ }
768
+ return violation;
769
+ }
770
+ /**
771
+ * Get explanation for a responsive violation
772
+ */
773
+ getExplanation(violationInfo) {
774
+ switch (violationInfo.type) {
775
+ case 'inconsistent-breakpoint-order':
776
+ return `Tailwind responsive classes should follow mobile-first ordering (sm → md → lg → xl → 2xl). This ensures styles cascade correctly from smaller to larger screens. Incorrect ordering can lead to unexpected style overrides.`;
777
+ case 'mixed-approach':
778
+ return `Mixing mobile-first (min-width) and desktop-first (max-width) media queries in the same file creates confusion and can lead to conflicting styles. Choose one approach and use it consistently throughout your codebase.`;
779
+ case 'arbitrary-breakpoint':
780
+ return `Using arbitrary breakpoint values instead of standard design system breakpoints makes it harder to maintain consistent responsive behavior. Standard breakpoints (640px, 768px, 1024px, 1280px, 1536px) ensure consistency across your application.`;
781
+ case 'hardcoded-media-query':
782
+ return `Hardcoded pixel values in media queries should be replaced with design tokens or CSS custom properties for maintainability. This allows breakpoints to be changed in one place.`;
783
+ case 'missing-responsive-variant':
784
+ return `Key responsive breakpoints should have corresponding style variants to ensure proper display across all device sizes.`;
785
+ default:
786
+ return `Responsive patterns should be consistent throughout the codebase for maintainability.`;
787
+ }
788
+ }
789
+ /**
790
+ * Get expected value for a responsive violation
791
+ */
792
+ getExpectedValue(violationInfo) {
793
+ switch (violationInfo.type) {
794
+ case 'inconsistent-breakpoint-order':
795
+ return `Breakpoints in order: ${TAILWIND_BREAKPOINT_ORDER.join(' → ')}`;
796
+ case 'mixed-approach':
797
+ return `Consistent use of either mobile-first (min-width) or desktop-first (max-width)`;
798
+ case 'arbitrary-breakpoint':
799
+ return `Standard breakpoint value (${Object.entries(TAILWIND_BREAKPOINTS).map(([k, v]) => `${k}: ${v}px`).join(', ')})`;
800
+ case 'hardcoded-media-query':
801
+ return `CSS custom property or design token (e.g., var(--breakpoint-md))`;
802
+ case 'missing-responsive-variant':
803
+ return `Responsive variants for key breakpoints`;
804
+ default:
805
+ return `Consistent responsive pattern`;
806
+ }
807
+ }
808
+ /**
809
+ * Create a quick fix for a responsive violation
810
+ */
811
+ createQuickFixForViolation(violationInfo) {
812
+ if (violationInfo.type !== 'arbitrary-breakpoint') {
813
+ return undefined;
814
+ }
815
+ // Extract the pixel value from the breakpoint
816
+ const pxMatch = violationInfo.breakpoints[0]?.match(/(\d+)px/);
817
+ if (!pxMatch) {
818
+ return undefined;
819
+ }
820
+ const value = parseInt(pxMatch[1], 10);
821
+ const nearest = findNearestBreakpoint(value);
822
+ // Create replacement text
823
+ const replacement = violationInfo.lineContent.replace(new RegExp(`${value}px`), `${nearest.value}px`);
824
+ return {
825
+ title: `Replace with standard breakpoint: ${nearest.name} (${nearest.value}px)`,
826
+ kind: 'quickfix',
827
+ edit: {
828
+ changes: {
829
+ [violationInfo.file]: [
830
+ {
831
+ range: {
832
+ start: { line: violationInfo.line - 1, character: 0 },
833
+ end: { line: violationInfo.line - 1, character: violationInfo.lineContent.length },
834
+ },
835
+ newText: replacement,
836
+ },
837
+ ],
838
+ },
839
+ },
840
+ isPreferred: true,
841
+ confidence: 0.7,
842
+ preview: `Replace '${value}px' with '${nearest.value}px' (${nearest.name})`,
843
+ };
844
+ }
845
+ /**
846
+ * Generate a quick fix for a violation
847
+ */
848
+ generateQuickFix(violation) {
849
+ // Check if this is a responsive violation with arbitrary breakpoint
850
+ if (!violation.message.includes('breakpoint') && !violation.message.includes('Breakpoint')) {
851
+ return null;
852
+ }
853
+ // Extract the pixel value from the message
854
+ const pxMatch = violation.actual.match(/(\d+)px/);
855
+ if (!pxMatch) {
856
+ return null;
857
+ }
858
+ const value = parseInt(pxMatch[1], 10);
859
+ const nearest = findNearestBreakpoint(value);
860
+ return {
861
+ title: `Replace with standard breakpoint: ${nearest.name} (${nearest.value}px)`,
862
+ kind: 'quickfix',
863
+ edit: {
864
+ changes: {
865
+ [violation.file]: [
866
+ {
867
+ range: violation.range,
868
+ newText: `${nearest.value}px`,
869
+ },
870
+ ],
871
+ },
872
+ },
873
+ isPreferred: true,
874
+ confidence: 0.7,
875
+ preview: `Replace '${value}px' with '${nearest.value}px' (${nearest.name})`,
876
+ };
877
+ }
878
+ }
879
+ // ============================================================================
880
+ // Factory Function
881
+ // ============================================================================
882
+ /**
883
+ * Create a new ResponsiveDetector instance
884
+ */
885
+ export function createResponsiveDetector() {
886
+ return new ResponsiveDetector();
887
+ }
888
+ //# sourceMappingURL=responsive.js.map