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,1004 @@
1
+ /**
2
+ * Typography Detector - Typography scale detection
3
+ *
4
+ * Detects typography scale patterns including:
5
+ * - CSS custom properties for typography (--font-size-*, --line-height-*, --font-weight-*)
6
+ * - Theme typography objects (theme.typography.*, theme.fontSizes.*, etc.)
7
+ * - Tailwind typography classes (text-sm, text-lg, font-bold, leading-tight, etc.)
8
+ * - Typography scale values (12px, 14px, 16px, 18px, 20px, 24px, etc.)
9
+ *
10
+ * Flags hardcoded typography values:
11
+ * - Arbitrary font sizes (13px, 17px, etc.)
12
+ * - Arbitrary line heights (1.3, 1.7, etc.)
13
+ * - Arbitrary font weights (450, 550, etc.)
14
+ * - Hardcoded font families
15
+ *
16
+ * @requirements 9.4 - THE Styling_Detector SHALL detect typography scale adherence
17
+ */
18
+ import { RegexDetector } from '../base/index.js';
19
+ // ============================================================================
20
+ // Constants
21
+ // ============================================================================
22
+ /**
23
+ * Standard typography scale font sizes (in px)
24
+ */
25
+ export const TYPOGRAPHY_SCALE_PX = [10, 11, 12, 13, 14, 16, 18, 20, 24, 28, 30, 32, 36, 40, 48, 56, 64, 72, 80, 96];
26
+ /**
27
+ * Standard typography scale font sizes (in rem, based on 16px base)
28
+ */
29
+ export const TYPOGRAPHY_SCALE_REM = [0.625, 0.6875, 0.75, 0.8125, 0.875, 1, 1.125, 1.25, 1.5, 1.75, 1.875, 2, 2.25, 2.5, 3, 3.5, 4, 4.5, 5, 6];
30
+ /**
31
+ * Standard line height values
32
+ */
33
+ export const LINE_HEIGHT_SCALE = [1, 1.25, 1.375, 1.5, 1.625, 1.75, 2];
34
+ /**
35
+ * Standard font weight values
36
+ */
37
+ export const FONT_WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
38
+ /**
39
+ * Regex pattern for CSS custom properties for typography
40
+ */
41
+ export const CSS_TYPOGRAPHY_PROPERTY_PATTERN = /var\(\s*--(?:font-size|fs|text|line-height|lh|font-weight|fw|font-family|ff|typography|type)[-_]?([a-zA-Z0-9_-]*)\s*(?:,\s*[^)]+)?\)/g;
42
+ /**
43
+ * Regex patterns for theme typography object usage
44
+ */
45
+ export const THEME_TYPOGRAPHY_PATTERNS = [
46
+ // theme.typography.*, theme.fontSizes.*, theme.lineHeights.*, theme.fontWeights.*
47
+ /theme\.(?:typography|fontSizes?|lineHeights?|fontWeights?|fonts?)\.([a-zA-Z0-9_.[\]]+)/g,
48
+ // ${theme.typography.*} in template literals
49
+ /\$\{theme\.(?:typography|fontSizes?|lineHeights?|fontWeights?|fonts?)\.([a-zA-Z0-9_.[\]]+)\}/g,
50
+ // props.theme.typography.*
51
+ /props\.theme\.(?:typography|fontSizes?|lineHeights?|fontWeights?|fonts?)\.([a-zA-Z0-9_.[\]]+)/g,
52
+ // typography.*, fontSizes.* (standalone typography object)
53
+ /\b(?:typography|fontSizes?|lineHeights?|fontWeights?)\.([a-zA-Z0-9_.[\]]+)/g,
54
+ ];
55
+ /**
56
+ * Tailwind typography class patterns
57
+ */
58
+ export const TAILWIND_TYPOGRAPHY_PATTERNS = [
59
+ // Font size classes: text-xs, text-sm, text-base, text-lg, text-xl, text-2xl, etc.
60
+ /\btext-(?:xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)\b/g,
61
+ // Font weight classes: font-thin, font-light, font-normal, font-medium, font-semibold, font-bold, font-extrabold, font-black
62
+ /\bfont-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)\b/g,
63
+ // Line height classes: leading-none, leading-tight, leading-snug, leading-normal, leading-relaxed, leading-loose
64
+ /\bleading-(?:none|tight|snug|normal|relaxed|loose|\d+)\b/g,
65
+ // Letter spacing classes: tracking-tighter, tracking-tight, tracking-normal, tracking-wide, tracking-wider, tracking-widest
66
+ /\btracking-(?:tighter|tight|normal|wide|wider|widest)\b/g,
67
+ // Font family classes: font-sans, font-serif, font-mono
68
+ /\bfont-(?:sans|serif|mono)\b/g,
69
+ ];
70
+ /**
71
+ * Tailwind arbitrary typography value patterns
72
+ */
73
+ export const TAILWIND_ARBITRARY_TYPOGRAPHY_PATTERN = /\b(?:text|font|leading|tracking)-\[([^\]]+)\]/g;
74
+ /**
75
+ * Hardcoded font size patterns
76
+ */
77
+ export const HARDCODED_FONT_SIZE_PATTERNS = {
78
+ // Pixel font sizes: 13px, 17px, etc.
79
+ px: /(?<![a-zA-Z0-9_-])(\d+)px\b/g,
80
+ // Rem font sizes: 0.9rem, 1.1rem, etc.
81
+ rem: /(?<![a-zA-Z0-9_-])(\d+(?:\.\d+)?)rem\b/g,
82
+ // Em font sizes: 0.9em, 1.1em, etc.
83
+ em: /(?<![a-zA-Z0-9_-])(\d+(?:\.\d+)?)em\b/g,
84
+ };
85
+ /**
86
+ * Hardcoded line height pattern (unitless values like 1.3, 1.7)
87
+ */
88
+ export const HARDCODED_LINE_HEIGHT_PATTERN = /line-height\s*:\s*(\d+(?:\.\d+)?)\s*[;}\n]/g;
89
+ /**
90
+ * Hardcoded font weight pattern (non-standard values like 450, 550)
91
+ */
92
+ export const HARDCODED_FONT_WEIGHT_PATTERN = /font-weight\s*:\s*(\d+)\s*[;}\n]/g;
93
+ /**
94
+ * Hardcoded font family pattern
95
+ */
96
+ export const HARDCODED_FONT_FAMILY_PATTERN = /font-family\s*:\s*(['"]?)([^;}\n'"]+)\1\s*[;}\n]/g;
97
+ /**
98
+ * CSS properties that commonly use typography values
99
+ */
100
+ export const TYPOGRAPHY_PROPERTIES = [
101
+ 'font-size',
102
+ 'line-height',
103
+ 'font-weight',
104
+ 'font-family',
105
+ 'letter-spacing',
106
+ 'text-transform',
107
+ ];
108
+ /**
109
+ * Allowed hardcoded typography values (common exceptions)
110
+ */
111
+ export const ALLOWED_TYPOGRAPHY_VALUES = new Set([
112
+ 'inherit',
113
+ 'initial',
114
+ 'unset',
115
+ 'normal',
116
+ 'none',
117
+ '0',
118
+ '100%',
119
+ ]);
120
+ /**
121
+ * Allowed font families (system fonts and common stacks)
122
+ */
123
+ export const ALLOWED_FONT_FAMILIES = new Set([
124
+ 'inherit',
125
+ 'initial',
126
+ 'unset',
127
+ 'system-ui',
128
+ '-apple-system',
129
+ 'BlinkMacSystemFont',
130
+ 'sans-serif',
131
+ 'serif',
132
+ 'monospace',
133
+ 'cursive',
134
+ 'fantasy',
135
+ ]);
136
+ /**
137
+ * File patterns to exclude from hardcoded typography detection
138
+ */
139
+ export const EXCLUDED_FILE_PATTERNS = [
140
+ /\.test\.[jt]sx?$/,
141
+ /\.spec\.[jt]sx?$/,
142
+ /\.stories\.[jt]sx?$/,
143
+ /design-tokens?\//,
144
+ /tokens?\//,
145
+ /theme\//,
146
+ /\.config\.[jt]s$/,
147
+ /tailwind\.config/,
148
+ /typography\.[jt]s$/,
149
+ /fonts?\.[jt]s$/,
150
+ ];
151
+ // ============================================================================
152
+ // Helper Functions
153
+ // ============================================================================
154
+ /**
155
+ * Check if a file should be excluded from hardcoded typography detection
156
+ */
157
+ export function shouldExcludeFile(filePath) {
158
+ return EXCLUDED_FILE_PATTERNS.some(pattern => pattern.test(filePath));
159
+ }
160
+ /**
161
+ * Check if a value is in the allowed typography values list
162
+ */
163
+ export function isAllowedTypographyValue(value) {
164
+ return ALLOWED_TYPOGRAPHY_VALUES.has(value.toLowerCase().trim());
165
+ }
166
+ /**
167
+ * Check if a font family is allowed
168
+ */
169
+ export function isAllowedFontFamily(value) {
170
+ const normalized = value.toLowerCase().trim().replace(/['"]/g, '');
171
+ // Check if any part of the font stack is a system font
172
+ const parts = normalized.split(',').map(p => p.trim());
173
+ return parts.some(part => ALLOWED_FONT_FAMILIES.has(part));
174
+ }
175
+ /**
176
+ * Check if a font size is on the typography scale
177
+ */
178
+ export function isOnTypographyScale(value, unit) {
179
+ if (unit === 'px') {
180
+ return TYPOGRAPHY_SCALE_PX.includes(value);
181
+ }
182
+ // For rem/em, check with some tolerance for floating point
183
+ return TYPOGRAPHY_SCALE_REM.some(v => Math.abs(v - value) < 0.001);
184
+ }
185
+ /**
186
+ * Check if a line height is on the standard scale
187
+ */
188
+ export function isOnLineHeightScale(value) {
189
+ return LINE_HEIGHT_SCALE.some(v => Math.abs(v - value) < 0.001);
190
+ }
191
+ /**
192
+ * Check if a font weight is on the standard scale
193
+ */
194
+ export function isOnFontWeightScale(value) {
195
+ return FONT_WEIGHT_SCALE.includes(value);
196
+ }
197
+ /**
198
+ * Find the nearest font size on the typography scale
199
+ */
200
+ export function findNearestFontSize(value, unit) {
201
+ const scale = unit === 'px' ? TYPOGRAPHY_SCALE_PX : TYPOGRAPHY_SCALE_REM;
202
+ let nearest = scale[0];
203
+ let minDiff = Math.abs(value - nearest);
204
+ for (const scaleValue of scale) {
205
+ const diff = Math.abs(value - scaleValue);
206
+ if (diff < minDiff) {
207
+ minDiff = diff;
208
+ nearest = scaleValue;
209
+ }
210
+ }
211
+ return nearest;
212
+ }
213
+ /**
214
+ * Find the nearest line height on the scale
215
+ */
216
+ export function findNearestLineHeight(value) {
217
+ let nearest = LINE_HEIGHT_SCALE[0];
218
+ let minDiff = Math.abs(value - nearest);
219
+ for (const scaleValue of LINE_HEIGHT_SCALE) {
220
+ const diff = Math.abs(value - scaleValue);
221
+ if (diff < minDiff) {
222
+ minDiff = diff;
223
+ nearest = scaleValue;
224
+ }
225
+ }
226
+ return nearest;
227
+ }
228
+ /**
229
+ * Find the nearest font weight on the scale
230
+ */
231
+ export function findNearestFontWeight(value) {
232
+ let nearest = FONT_WEIGHT_SCALE[0];
233
+ let minDiff = Math.abs(value - nearest);
234
+ for (const scaleValue of FONT_WEIGHT_SCALE) {
235
+ const diff = Math.abs(value - scaleValue);
236
+ if (diff < minDiff) {
237
+ minDiff = diff;
238
+ nearest = scaleValue;
239
+ }
240
+ }
241
+ return nearest;
242
+ }
243
+ /**
244
+ * Check if a position is inside a comment
245
+ */
246
+ function isInsideComment(content, index) {
247
+ const beforeIndex = content.slice(0, index);
248
+ // Check for single-line comment
249
+ const lastNewline = beforeIndex.lastIndexOf('\n');
250
+ const currentLine = beforeIndex.slice(lastNewline + 1);
251
+ if (currentLine.includes('//')) {
252
+ const commentStart = currentLine.indexOf('//');
253
+ const positionInLine = index - lastNewline - 1;
254
+ if (positionInLine > commentStart) {
255
+ return true;
256
+ }
257
+ }
258
+ // Check for multi-line comment
259
+ const lastBlockCommentStart = beforeIndex.lastIndexOf('/*');
260
+ const lastBlockCommentEnd = beforeIndex.lastIndexOf('*/');
261
+ if (lastBlockCommentStart > lastBlockCommentEnd) {
262
+ return true;
263
+ }
264
+ return false;
265
+ }
266
+ /**
267
+ * Extract CSS property name from a line
268
+ */
269
+ function extractCSSProperty(line) {
270
+ // Match CSS property: property-name: value
271
+ const cssMatch = line.match(/([a-zA-Z-]+)\s*:/);
272
+ if (cssMatch && cssMatch[1]) {
273
+ return cssMatch[1];
274
+ }
275
+ // Match JS object property: propertyName: value
276
+ const jsMatch = line.match(/([a-zA-Z]+)\s*:/);
277
+ if (jsMatch && jsMatch[1]) {
278
+ // Convert camelCase to kebab-case
279
+ return jsMatch[1].replace(/([A-Z])/g, '-$1').toLowerCase();
280
+ }
281
+ return undefined;
282
+ }
283
+ /**
284
+ * Detect CSS custom property usage for typography
285
+ */
286
+ export function detectCSSTypographyProperties(content, file) {
287
+ const results = [];
288
+ const lines = content.split('\n');
289
+ const regex = new RegExp(CSS_TYPOGRAPHY_PROPERTY_PATTERN.source, CSS_TYPOGRAPHY_PROPERTY_PATTERN.flags);
290
+ let match;
291
+ while ((match = regex.exec(content)) !== null) {
292
+ const beforeMatch = content.slice(0, match.index);
293
+ const lineNumber = beforeMatch.split('\n').length;
294
+ const lastNewline = beforeMatch.lastIndexOf('\n');
295
+ const column = match.index - lastNewline;
296
+ results.push({
297
+ type: 'css-typography-property',
298
+ file,
299
+ line: lineNumber,
300
+ column,
301
+ matchedText: match[0],
302
+ typographyValue: match[1] || '',
303
+ context: lines[lineNumber - 1] || '',
304
+ });
305
+ }
306
+ return results;
307
+ }
308
+ /**
309
+ * Detect theme typography object usage
310
+ */
311
+ export function detectThemeTypography(content, file) {
312
+ const results = [];
313
+ const lines = content.split('\n');
314
+ for (const pattern of THEME_TYPOGRAPHY_PATTERNS) {
315
+ const regex = new RegExp(pattern.source, pattern.flags);
316
+ let match;
317
+ while ((match = regex.exec(content)) !== null) {
318
+ const beforeMatch = content.slice(0, match.index);
319
+ const lineNumber = beforeMatch.split('\n').length;
320
+ const lastNewline = beforeMatch.lastIndexOf('\n');
321
+ const column = match.index - lastNewline;
322
+ results.push({
323
+ type: 'theme-typography',
324
+ file,
325
+ line: lineNumber,
326
+ column,
327
+ matchedText: match[0],
328
+ typographyValue: match[1] || match[0],
329
+ context: lines[lineNumber - 1] || '',
330
+ });
331
+ }
332
+ }
333
+ return results;
334
+ }
335
+ /**
336
+ * Detect Tailwind typography classes
337
+ */
338
+ export function detectTailwindTypography(content, file) {
339
+ const results = [];
340
+ const lines = content.split('\n');
341
+ for (const pattern of TAILWIND_TYPOGRAPHY_PATTERNS) {
342
+ const regex = new RegExp(pattern.source, pattern.flags);
343
+ let match;
344
+ while ((match = regex.exec(content)) !== null) {
345
+ const beforeMatch = content.slice(0, match.index);
346
+ const lineNumber = beforeMatch.split('\n').length;
347
+ const lastNewline = beforeMatch.lastIndexOf('\n');
348
+ const column = match.index - lastNewline;
349
+ results.push({
350
+ type: 'tailwind-typography',
351
+ file,
352
+ line: lineNumber,
353
+ column,
354
+ matchedText: match[0],
355
+ typographyValue: match[0],
356
+ context: lines[lineNumber - 1] || '',
357
+ });
358
+ }
359
+ }
360
+ return results;
361
+ }
362
+ /**
363
+ * Detect Tailwind arbitrary typography values
364
+ */
365
+ export function detectTailwindArbitraryTypography(content, file) {
366
+ const results = [];
367
+ const lines = content.split('\n');
368
+ const regex = new RegExp(TAILWIND_ARBITRARY_TYPOGRAPHY_PATTERN.source, TAILWIND_ARBITRARY_TYPOGRAPHY_PATTERN.flags);
369
+ let match;
370
+ while ((match = regex.exec(content)) !== null) {
371
+ const value = match[1] || '';
372
+ // Skip allowed values
373
+ if (isAllowedTypographyValue(value)) {
374
+ continue;
375
+ }
376
+ const beforeMatch = content.slice(0, match.index);
377
+ const lineNumber = beforeMatch.split('\n').length;
378
+ const lastNewline = beforeMatch.lastIndexOf('\n');
379
+ const column = match.index - lastNewline;
380
+ const endColumn = column + match[0].length;
381
+ // Determine the type based on the prefix
382
+ const prefix = match[0].split('-[')[0] || '';
383
+ let type = 'arbitrary-font-size';
384
+ if (prefix === 'font') {
385
+ type = 'arbitrary-font-weight';
386
+ }
387
+ else if (prefix === 'leading') {
388
+ type = 'arbitrary-line-height';
389
+ }
390
+ results.push({
391
+ type,
392
+ file,
393
+ line: lineNumber,
394
+ column,
395
+ endLine: lineNumber,
396
+ endColumn,
397
+ value: match[0],
398
+ suggestedToken: suggestTypographyToken(value, type),
399
+ lineContent: lines[lineNumber - 1] || '',
400
+ });
401
+ }
402
+ return results;
403
+ }
404
+ /**
405
+ * Detect arbitrary font size values
406
+ */
407
+ export function detectArbitraryFontSizes(content, file) {
408
+ const results = [];
409
+ const lines = content.split('\n');
410
+ // Check each font size pattern type
411
+ const fontSizePatterns = [
412
+ { pattern: HARDCODED_FONT_SIZE_PATTERNS.px, unit: 'px' },
413
+ { pattern: HARDCODED_FONT_SIZE_PATTERNS.rem, unit: 'rem' },
414
+ { pattern: HARDCODED_FONT_SIZE_PATTERNS.em, unit: 'em' },
415
+ ];
416
+ for (const { pattern, unit } of fontSizePatterns) {
417
+ const regex = new RegExp(pattern.source, pattern.flags);
418
+ let match;
419
+ while ((match = regex.exec(content)) !== null) {
420
+ const numValue = parseFloat(match[1] || '0');
421
+ const value = `${numValue}${unit}`;
422
+ // Skip allowed values
423
+ if (isAllowedTypographyValue(value)) {
424
+ continue;
425
+ }
426
+ const beforeMatch = content.slice(0, match.index);
427
+ const lineNumber = beforeMatch.split('\n').length;
428
+ const lineContent = lines[lineNumber - 1] || '';
429
+ // Only flag if this is a font-size property
430
+ const property = extractCSSProperty(lineContent);
431
+ if (property && !['font-size', 'font'].includes(property)) {
432
+ continue;
433
+ }
434
+ // Skip CSS custom property definitions
435
+ if (/^\s*--[a-zA-Z0-9_-]+\s*:/.test(lineContent)) {
436
+ continue;
437
+ }
438
+ // Skip if inside a comment
439
+ if (isInsideComment(content, match.index)) {
440
+ continue;
441
+ }
442
+ // Check if value is on the typography scale
443
+ if (isOnTypographyScale(numValue, unit)) {
444
+ continue;
445
+ }
446
+ const lastNewline = beforeMatch.lastIndexOf('\n');
447
+ const column = match.index - lastNewline;
448
+ const endColumn = column + value.length;
449
+ const hardcodedInfo = {
450
+ type: 'arbitrary-font-size',
451
+ file,
452
+ line: lineNumber,
453
+ column,
454
+ endLine: lineNumber,
455
+ endColumn,
456
+ value,
457
+ suggestedToken: suggestFontSizeToken(numValue, unit),
458
+ lineContent,
459
+ };
460
+ if (property !== undefined) {
461
+ hardcodedInfo.property = property;
462
+ }
463
+ results.push(hardcodedInfo);
464
+ }
465
+ }
466
+ return results;
467
+ }
468
+ /**
469
+ * Detect arbitrary line height values
470
+ */
471
+ export function detectArbitraryLineHeights(content, file) {
472
+ const results = [];
473
+ const lines = content.split('\n');
474
+ const regex = new RegExp(HARDCODED_LINE_HEIGHT_PATTERN.source, HARDCODED_LINE_HEIGHT_PATTERN.flags);
475
+ let match;
476
+ while ((match = regex.exec(content)) !== null) {
477
+ const numValue = parseFloat(match[1] || '0');
478
+ // Skip allowed values
479
+ if (isAllowedTypographyValue(match[1] || '')) {
480
+ continue;
481
+ }
482
+ const beforeMatch = content.slice(0, match.index);
483
+ const lineNumber = beforeMatch.split('\n').length;
484
+ const lineContent = lines[lineNumber - 1] || '';
485
+ // Skip CSS custom property definitions
486
+ if (/^\s*--[a-zA-Z0-9_-]+\s*:/.test(lineContent)) {
487
+ continue;
488
+ }
489
+ // Skip if inside a comment
490
+ if (isInsideComment(content, match.index)) {
491
+ continue;
492
+ }
493
+ // Check if value is on the line height scale
494
+ if (isOnLineHeightScale(numValue)) {
495
+ continue;
496
+ }
497
+ const lastNewline = beforeMatch.lastIndexOf('\n');
498
+ const valueStart = lineContent.indexOf(match[1] || '');
499
+ const column = valueStart >= 0 ? valueStart + 1 : match.index - lastNewline;
500
+ const endColumn = column + (match[1] || '').length;
501
+ results.push({
502
+ type: 'arbitrary-line-height',
503
+ file,
504
+ line: lineNumber,
505
+ column,
506
+ endLine: lineNumber,
507
+ endColumn,
508
+ value: match[1] || '',
509
+ property: 'line-height',
510
+ suggestedToken: suggestLineHeightToken(numValue),
511
+ lineContent,
512
+ });
513
+ }
514
+ return results;
515
+ }
516
+ /**
517
+ * Detect arbitrary font weight values
518
+ */
519
+ export function detectArbitraryFontWeights(content, file) {
520
+ const results = [];
521
+ const lines = content.split('\n');
522
+ const regex = new RegExp(HARDCODED_FONT_WEIGHT_PATTERN.source, HARDCODED_FONT_WEIGHT_PATTERN.flags);
523
+ let match;
524
+ while ((match = regex.exec(content)) !== null) {
525
+ const numValue = parseInt(match[1] || '0', 10);
526
+ // Skip allowed values
527
+ if (isAllowedTypographyValue(match[1] || '')) {
528
+ continue;
529
+ }
530
+ const beforeMatch = content.slice(0, match.index);
531
+ const lineNumber = beforeMatch.split('\n').length;
532
+ const lineContent = lines[lineNumber - 1] || '';
533
+ // Skip CSS custom property definitions
534
+ if (/^\s*--[a-zA-Z0-9_-]+\s*:/.test(lineContent)) {
535
+ continue;
536
+ }
537
+ // Skip if inside a comment
538
+ if (isInsideComment(content, match.index)) {
539
+ continue;
540
+ }
541
+ // Check if value is on the font weight scale
542
+ if (isOnFontWeightScale(numValue)) {
543
+ continue;
544
+ }
545
+ const lastNewline = beforeMatch.lastIndexOf('\n');
546
+ const valueStart = lineContent.indexOf(match[1] || '');
547
+ const column = valueStart >= 0 ? valueStart + 1 : match.index - lastNewline;
548
+ const endColumn = column + (match[1] || '').length;
549
+ results.push({
550
+ type: 'arbitrary-font-weight',
551
+ file,
552
+ line: lineNumber,
553
+ column,
554
+ endLine: lineNumber,
555
+ endColumn,
556
+ value: match[1] || '',
557
+ property: 'font-weight',
558
+ suggestedToken: suggestFontWeightToken(numValue),
559
+ lineContent,
560
+ });
561
+ }
562
+ return results;
563
+ }
564
+ /**
565
+ * Detect hardcoded font family values
566
+ */
567
+ export function detectHardcodedFontFamilies(content, file) {
568
+ const results = [];
569
+ const lines = content.split('\n');
570
+ const regex = new RegExp(HARDCODED_FONT_FAMILY_PATTERN.source, HARDCODED_FONT_FAMILY_PATTERN.flags);
571
+ let match;
572
+ while ((match = regex.exec(content)) !== null) {
573
+ const fontFamily = match[2] || '';
574
+ // Skip allowed font families
575
+ if (isAllowedFontFamily(fontFamily)) {
576
+ continue;
577
+ }
578
+ const beforeMatch = content.slice(0, match.index);
579
+ const lineNumber = beforeMatch.split('\n').length;
580
+ const lineContent = lines[lineNumber - 1] || '';
581
+ // Skip CSS custom property definitions
582
+ if (/^\s*--[a-zA-Z0-9_-]+\s*:/.test(lineContent)) {
583
+ continue;
584
+ }
585
+ // Skip if inside a comment
586
+ if (isInsideComment(content, match.index)) {
587
+ continue;
588
+ }
589
+ const lastNewline = beforeMatch.lastIndexOf('\n');
590
+ const valueStart = lineContent.indexOf(fontFamily);
591
+ const column = valueStart >= 0 ? valueStart + 1 : match.index - lastNewline;
592
+ const endColumn = column + fontFamily.length;
593
+ results.push({
594
+ type: 'hardcoded-font-family',
595
+ file,
596
+ line: lineNumber,
597
+ column,
598
+ endLine: lineNumber,
599
+ endColumn,
600
+ value: fontFamily,
601
+ property: 'font-family',
602
+ suggestedToken: 'Use a font token from your design system (e.g., --font-family-sans, theme.fonts.body)',
603
+ lineContent,
604
+ });
605
+ }
606
+ return results;
607
+ }
608
+ /**
609
+ * Suggest a typography token for a hardcoded value
610
+ */
611
+ export function suggestTypographyToken(value, type) {
612
+ switch (type) {
613
+ case 'arbitrary-font-size': {
614
+ const match = value.match(/^(\d+(?:\.\d+)?)(px|rem|em)?$/);
615
+ if (match) {
616
+ const num = parseFloat(match[1] || '0');
617
+ const unit = (match[2] || 'px');
618
+ return suggestFontSizeToken(num, unit);
619
+ }
620
+ return 'Use a font size token (e.g., text-base, --font-size-md)';
621
+ }
622
+ case 'arbitrary-line-height': {
623
+ const num = parseFloat(value);
624
+ if (!isNaN(num)) {
625
+ return suggestLineHeightToken(num);
626
+ }
627
+ return 'Use a line height token (e.g., leading-normal, --line-height-base)';
628
+ }
629
+ case 'arbitrary-font-weight': {
630
+ const num = parseInt(value, 10);
631
+ if (!isNaN(num)) {
632
+ return suggestFontWeightToken(num);
633
+ }
634
+ return 'Use a font weight token (e.g., font-medium, --font-weight-medium)';
635
+ }
636
+ case 'hardcoded-font-family':
637
+ return 'Use a font family token (e.g., font-sans, --font-family-sans)';
638
+ default:
639
+ return 'Use a typography token from your design system';
640
+ }
641
+ }
642
+ /**
643
+ * Suggest a font size token
644
+ */
645
+ function suggestFontSizeToken(value, unit) {
646
+ const nearest = findNearestFontSize(value, unit);
647
+ const tailwindSizes = {
648
+ 10: 'text-[10px]',
649
+ 12: 'text-xs',
650
+ 14: 'text-sm',
651
+ 16: 'text-base',
652
+ 18: 'text-lg',
653
+ 20: 'text-xl',
654
+ 24: 'text-2xl',
655
+ 30: 'text-3xl',
656
+ 36: 'text-4xl',
657
+ 48: 'text-5xl',
658
+ 64: 'text-6xl',
659
+ };
660
+ if (unit === 'px' && tailwindSizes[nearest]) {
661
+ return `${tailwindSizes[nearest]} or --font-size-${nearest}`;
662
+ }
663
+ return `${nearest}${unit} or use --font-size-* token`;
664
+ }
665
+ /**
666
+ * Suggest a line height token
667
+ */
668
+ function suggestLineHeightToken(value) {
669
+ const nearest = findNearestLineHeight(value);
670
+ const tailwindLineHeights = {
671
+ 1: 'leading-none',
672
+ 1.25: 'leading-tight',
673
+ 1.375: 'leading-snug',
674
+ 1.5: 'leading-normal',
675
+ 1.625: 'leading-relaxed',
676
+ 1.75: 'leading-relaxed',
677
+ 2: 'leading-loose',
678
+ };
679
+ if (tailwindLineHeights[nearest]) {
680
+ return `${tailwindLineHeights[nearest]} or --line-height-${nearest}`;
681
+ }
682
+ return `${nearest} or use --line-height-* token`;
683
+ }
684
+ /**
685
+ * Suggest a font weight token
686
+ */
687
+ function suggestFontWeightToken(value) {
688
+ const nearest = findNearestFontWeight(value);
689
+ const tailwindWeights = {
690
+ 100: 'font-thin',
691
+ 200: 'font-extralight',
692
+ 300: 'font-light',
693
+ 400: 'font-normal',
694
+ 500: 'font-medium',
695
+ 600: 'font-semibold',
696
+ 700: 'font-bold',
697
+ 800: 'font-extrabold',
698
+ 900: 'font-black',
699
+ };
700
+ if (tailwindWeights[nearest]) {
701
+ return `${tailwindWeights[nearest]} or --font-weight-${nearest}`;
702
+ }
703
+ return `${nearest} or use --font-weight-* token`;
704
+ }
705
+ /**
706
+ * Analyze typography patterns in a file
707
+ */
708
+ export function analyzeTypography(content, file) {
709
+ // Skip excluded files for hardcoded typography detection
710
+ const skipHardcodedDetection = shouldExcludeFile(file);
711
+ // Detect typography patterns
712
+ const cssTypographyProperties = detectCSSTypographyProperties(content, file);
713
+ const themeTypography = detectThemeTypography(content, file);
714
+ const tailwindTypography = detectTailwindTypography(content, file);
715
+ const typographyPatterns = [
716
+ ...cssTypographyProperties,
717
+ ...themeTypography,
718
+ ...tailwindTypography,
719
+ ];
720
+ // Detect hardcoded values (unless file is excluded)
721
+ let hardcodedValues = [];
722
+ if (!skipHardcodedDetection) {
723
+ const tailwindArbitrary = detectTailwindArbitraryTypography(content, file);
724
+ const arbitraryFontSizes = detectArbitraryFontSizes(content, file);
725
+ const arbitraryLineHeights = detectArbitraryLineHeights(content, file);
726
+ const arbitraryFontWeights = detectArbitraryFontWeights(content, file);
727
+ const hardcodedFontFamilies = detectHardcodedFontFamilies(content, file);
728
+ hardcodedValues = [
729
+ ...tailwindArbitrary,
730
+ ...arbitraryFontSizes,
731
+ ...arbitraryLineHeights,
732
+ ...arbitraryFontWeights,
733
+ ...hardcodedFontFamilies,
734
+ ];
735
+ }
736
+ // Calculate confidence
737
+ const hasTypographyPatterns = typographyPatterns.length > 0;
738
+ const hasHardcodedValues = hardcodedValues.length > 0;
739
+ let typographyTokenConfidence = 0;
740
+ if (hasTypographyPatterns && !hasHardcodedValues) {
741
+ typographyTokenConfidence = 1.0;
742
+ }
743
+ else if (hasTypographyPatterns && hasHardcodedValues) {
744
+ const ratio = typographyPatterns.length / (typographyPatterns.length + hardcodedValues.length);
745
+ typographyTokenConfidence = ratio;
746
+ }
747
+ else if (!hasTypographyPatterns && hasHardcodedValues) {
748
+ typographyTokenConfidence = 0;
749
+ }
750
+ else {
751
+ typographyTokenConfidence = 0.5; // No typography styling detected
752
+ }
753
+ return {
754
+ typographyPatterns,
755
+ hardcodedValues,
756
+ usesCSSTypographyProperties: cssTypographyProperties.length > 0,
757
+ usesThemeTypography: themeTypography.length > 0,
758
+ usesTailwindTypography: tailwindTypography.length > 0,
759
+ typographyTokenConfidence,
760
+ };
761
+ }
762
+ // ============================================================================
763
+ // Typography Detector Class
764
+ // ============================================================================
765
+ /**
766
+ * Detector for typography scale adherence patterns
767
+ *
768
+ * Identifies typography token usage and flags hardcoded typography values
769
+ * that should use design tokens instead.
770
+ *
771
+ * @requirements 9.4 - THE Styling_Detector SHALL detect typography scale adherence
772
+ */
773
+ export class TypographyDetector extends RegexDetector {
774
+ id = 'styling/typography';
775
+ category = 'styling';
776
+ subcategory = 'typography';
777
+ name = 'Typography Detector';
778
+ description = 'Detects typography scale adherence and flags hardcoded typography values';
779
+ supportedLanguages = ['typescript', 'javascript', 'css'];
780
+ /**
781
+ * Detect typography patterns and violations
782
+ */
783
+ async detect(context) {
784
+ const patterns = [];
785
+ const violations = [];
786
+ // Analyze the file
787
+ const analysis = analyzeTypography(context.content, context.file);
788
+ // Create pattern matches for typography patterns
789
+ if (analysis.usesCSSTypographyProperties) {
790
+ patterns.push(this.createCSSTypographyPropertyPattern(context.file, analysis));
791
+ }
792
+ if (analysis.usesThemeTypography) {
793
+ patterns.push(this.createThemeTypographyPattern(context.file, analysis));
794
+ }
795
+ if (analysis.usesTailwindTypography) {
796
+ patterns.push(this.createTailwindTypographyPattern(context.file, analysis));
797
+ }
798
+ // Create violations for hardcoded values
799
+ for (const hardcoded of analysis.hardcodedValues) {
800
+ violations.push(this.createHardcodedTypographyViolation(hardcoded));
801
+ }
802
+ return this.createResult(patterns, violations, analysis.typographyTokenConfidence);
803
+ }
804
+ /**
805
+ * Create a pattern match for CSS typography property usage
806
+ */
807
+ createCSSTypographyPropertyPattern(file, analysis) {
808
+ const cssPatterns = analysis.typographyPatterns.filter(p => p.type === 'css-typography-property');
809
+ const firstPattern = cssPatterns[0];
810
+ return {
811
+ patternId: `${this.id}/css-property`,
812
+ location: {
813
+ file,
814
+ line: firstPattern?.line || 1,
815
+ column: firstPattern?.column || 1,
816
+ },
817
+ confidence: 1.0,
818
+ isOutlier: false,
819
+ };
820
+ }
821
+ /**
822
+ * Create a pattern match for theme typography usage
823
+ */
824
+ createThemeTypographyPattern(file, analysis) {
825
+ const themePatterns = analysis.typographyPatterns.filter(p => p.type === 'theme-typography');
826
+ const firstPattern = themePatterns[0];
827
+ return {
828
+ patternId: `${this.id}/theme`,
829
+ location: {
830
+ file,
831
+ line: firstPattern?.line || 1,
832
+ column: firstPattern?.column || 1,
833
+ },
834
+ confidence: 1.0,
835
+ isOutlier: false,
836
+ };
837
+ }
838
+ /**
839
+ * Create a pattern match for Tailwind typography usage
840
+ */
841
+ createTailwindTypographyPattern(file, analysis) {
842
+ const tailwindPatterns = analysis.typographyPatterns.filter(p => p.type === 'tailwind-typography');
843
+ const firstPattern = tailwindPatterns[0];
844
+ return {
845
+ patternId: `${this.id}/tailwind`,
846
+ location: {
847
+ file,
848
+ line: firstPattern?.line || 1,
849
+ column: firstPattern?.column || 1,
850
+ },
851
+ confidence: 1.0,
852
+ isOutlier: false,
853
+ };
854
+ }
855
+ /**
856
+ * Create a violation for a hardcoded typography value
857
+ */
858
+ createHardcodedTypographyViolation(hardcoded) {
859
+ const typeDescriptions = {
860
+ 'arbitrary-font-size': 'arbitrary font size',
861
+ 'arbitrary-line-height': 'arbitrary line height',
862
+ 'arbitrary-font-weight': 'arbitrary font weight',
863
+ 'hardcoded-font-family': 'hardcoded font family',
864
+ };
865
+ const typeDescription = typeDescriptions[hardcoded.type] || 'hardcoded typography';
866
+ const propertyInfo = hardcoded.property ? ` in '${hardcoded.property}'` : '';
867
+ const violation = {
868
+ id: `${this.id}-${hardcoded.file}-${hardcoded.line}-${hardcoded.column}`,
869
+ patternId: this.id,
870
+ severity: 'warning',
871
+ file: hardcoded.file,
872
+ range: {
873
+ start: { line: hardcoded.line - 1, character: hardcoded.column - 1 },
874
+ end: { line: hardcoded.endLine - 1, character: hardcoded.endColumn - 1 },
875
+ },
876
+ message: `${typeDescription.charAt(0).toUpperCase() + typeDescription.slice(1)} '${hardcoded.value}'${propertyInfo} doesn't follow the typography scale`,
877
+ explanation: `Using hardcoded typography values instead of design tokens makes it difficult to maintain consistent typography across the application. Use values from your typography scale (Tailwind classes, CSS custom properties, or theme tokens).`,
878
+ expected: hardcoded.suggestedToken || 'A typography token',
879
+ actual: hardcoded.value,
880
+ aiExplainAvailable: true,
881
+ aiFixAvailable: true,
882
+ firstSeen: new Date(),
883
+ occurrences: 1,
884
+ };
885
+ const quickFix = this.createQuickFixForHardcodedTypography(hardcoded);
886
+ if (quickFix !== undefined) {
887
+ violation.quickFix = quickFix;
888
+ }
889
+ return violation;
890
+ }
891
+ /**
892
+ * Create a quick fix for replacing a hardcoded typography value with a token
893
+ */
894
+ createQuickFixForHardcodedTypography(hardcoded) {
895
+ // Only provide quick fix if we have a suggested token
896
+ if (!hardcoded.suggestedToken) {
897
+ return undefined;
898
+ }
899
+ // Extract the first suggested token (before "or")
900
+ const suggestedToken = hardcoded.suggestedToken.split(' or ')[0] || hardcoded.suggestedToken;
901
+ // Determine the replacement based on context
902
+ let replacement;
903
+ if (hardcoded.lineContent.includes('var(')) {
904
+ // Already using CSS custom properties, suggest a different custom property
905
+ replacement = `var(${suggestedToken.replace(/\./g, '-')})`;
906
+ }
907
+ else if (hardcoded.lineContent.includes('${') || hardcoded.lineContent.includes('`')) {
908
+ // Template literal context (styled-components, emotion)
909
+ replacement = `\${${suggestedToken}}`;
910
+ }
911
+ else {
912
+ // Default: suggest the token directly
913
+ replacement = suggestedToken;
914
+ }
915
+ return {
916
+ title: `Replace with typography token: ${suggestedToken}`,
917
+ kind: 'quickfix',
918
+ edit: {
919
+ changes: {
920
+ [hardcoded.file]: [
921
+ {
922
+ range: {
923
+ start: { line: hardcoded.line - 1, character: hardcoded.column - 1 },
924
+ end: { line: hardcoded.endLine - 1, character: hardcoded.endColumn - 1 },
925
+ },
926
+ newText: replacement,
927
+ },
928
+ ],
929
+ },
930
+ },
931
+ isPreferred: true,
932
+ confidence: 0.7,
933
+ preview: `Replace '${hardcoded.value}' with '${replacement}'`,
934
+ };
935
+ }
936
+ /**
937
+ * Generate a quick fix for a violation
938
+ */
939
+ generateQuickFix(violation) {
940
+ // Check if this is a typography violation
941
+ if (!violation.message.includes('typography') &&
942
+ !violation.message.includes('font') &&
943
+ !violation.message.includes('line height')) {
944
+ return null;
945
+ }
946
+ // Extract the value from the message
947
+ const valueMatch = violation.message.match(/['"]([^'"]+)['"]/);
948
+ if (!valueMatch || !valueMatch[1]) {
949
+ return null;
950
+ }
951
+ const value = valueMatch[1];
952
+ let suggestedToken;
953
+ // Determine the type and suggest replacement
954
+ if (violation.message.includes('font size')) {
955
+ const match = value.match(/^(\d+(?:\.\d+)?)(px|rem|em)?$/);
956
+ if (match) {
957
+ suggestedToken = suggestTypographyToken(value, 'arbitrary-font-size');
958
+ }
959
+ else {
960
+ return null;
961
+ }
962
+ }
963
+ else if (violation.message.includes('line height')) {
964
+ suggestedToken = suggestTypographyToken(value, 'arbitrary-line-height');
965
+ }
966
+ else if (violation.message.includes('font weight')) {
967
+ suggestedToken = suggestTypographyToken(value, 'arbitrary-font-weight');
968
+ }
969
+ else if (violation.message.includes('font family')) {
970
+ suggestedToken = suggestTypographyToken(value, 'hardcoded-font-family');
971
+ }
972
+ else {
973
+ return null;
974
+ }
975
+ const firstSuggestion = suggestedToken.split(' or ')[0] || suggestedToken;
976
+ return {
977
+ title: `Replace with typography token: ${firstSuggestion}`,
978
+ kind: 'quickfix',
979
+ edit: {
980
+ changes: {
981
+ [violation.file]: [
982
+ {
983
+ range: violation.range,
984
+ newText: firstSuggestion,
985
+ },
986
+ ],
987
+ },
988
+ },
989
+ isPreferred: true,
990
+ confidence: 0.7,
991
+ preview: `Replace '${value}' with '${firstSuggestion}'`,
992
+ };
993
+ }
994
+ }
995
+ // ============================================================================
996
+ // Factory Function
997
+ // ============================================================================
998
+ /**
999
+ * Create a new TypographyDetector instance
1000
+ */
1001
+ export function createTypographyDetector() {
1002
+ return new TypographyDetector();
1003
+ }
1004
+ //# sourceMappingURL=typography.js.map