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.
- package/dist/accessibility/alt-text.d.ts +63 -0
- package/dist/accessibility/alt-text.d.ts.map +1 -0
- package/dist/accessibility/alt-text.js +100 -0
- package/dist/accessibility/alt-text.js.map +1 -0
- package/dist/accessibility/aria-roles.d.ts +65 -0
- package/dist/accessibility/aria-roles.d.ts.map +1 -0
- package/dist/accessibility/aria-roles.js +87 -0
- package/dist/accessibility/aria-roles.js.map +1 -0
- package/dist/accessibility/focus-management.d.ts +62 -0
- package/dist/accessibility/focus-management.d.ts.map +1 -0
- package/dist/accessibility/focus-management.js +88 -0
- package/dist/accessibility/focus-management.js.map +1 -0
- package/dist/accessibility/heading-hierarchy.d.ts +66 -0
- package/dist/accessibility/heading-hierarchy.d.ts.map +1 -0
- package/dist/accessibility/heading-hierarchy.js +94 -0
- package/dist/accessibility/heading-hierarchy.js.map +1 -0
- package/dist/accessibility/index.d.ts +25 -0
- package/dist/accessibility/index.d.ts.map +1 -0
- package/dist/accessibility/index.js +21 -0
- package/dist/accessibility/index.js.map +1 -0
- package/dist/accessibility/keyboard-nav.d.ts +63 -0
- package/dist/accessibility/keyboard-nav.d.ts.map +1 -0
- package/dist/accessibility/keyboard-nav.js +86 -0
- package/dist/accessibility/keyboard-nav.js.map +1 -0
- package/dist/accessibility/semantic-html.d.ts +76 -0
- package/dist/accessibility/semantic-html.d.ts.map +1 -0
- package/dist/accessibility/semantic-html.js +204 -0
- package/dist/accessibility/semantic-html.js.map +1 -0
- package/dist/api/client-patterns.d.ts +121 -0
- package/dist/api/client-patterns.d.ts.map +1 -0
- package/dist/api/client-patterns.js +478 -0
- package/dist/api/client-patterns.js.map +1 -0
- package/dist/api/error-format.d.ts +140 -0
- package/dist/api/error-format.d.ts.map +1 -0
- package/dist/api/error-format.js +614 -0
- package/dist/api/error-format.js.map +1 -0
- package/dist/api/http-methods.d.ts +255 -0
- package/dist/api/http-methods.d.ts.map +1 -0
- package/dist/api/http-methods.js +890 -0
- package/dist/api/http-methods.js.map +1 -0
- package/dist/api/index.d.ts +16 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +37 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/pagination.d.ts +133 -0
- package/dist/api/pagination.d.ts.map +1 -0
- package/dist/api/pagination.js +521 -0
- package/dist/api/pagination.js.map +1 -0
- package/dist/api/response-envelope.d.ts +261 -0
- package/dist/api/response-envelope.d.ts.map +1 -0
- package/dist/api/response-envelope.js +1050 -0
- package/dist/api/response-envelope.js.map +1 -0
- package/dist/api/retry-patterns.d.ts +117 -0
- package/dist/api/retry-patterns.d.ts.map +1 -0
- package/dist/api/retry-patterns.js +480 -0
- package/dist/api/retry-patterns.js.map +1 -0
- package/dist/api/route-structure.d.ts +128 -0
- package/dist/api/route-structure.d.ts.map +1 -0
- package/dist/api/route-structure.js +738 -0
- package/dist/api/route-structure.js.map +1 -0
- package/dist/auth/audit-logging.d.ts +80 -0
- package/dist/auth/audit-logging.d.ts.map +1 -0
- package/dist/auth/audit-logging.js +370 -0
- package/dist/auth/audit-logging.js.map +1 -0
- package/dist/auth/index.d.ts +33 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +49 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware-usage.d.ts +65 -0
- package/dist/auth/middleware-usage.d.ts.map +1 -0
- package/dist/auth/middleware-usage.js +192 -0
- package/dist/auth/middleware-usage.js.map +1 -0
- package/dist/auth/permission-checks.d.ts +60 -0
- package/dist/auth/permission-checks.d.ts.map +1 -0
- package/dist/auth/permission-checks.js +159 -0
- package/dist/auth/permission-checks.js.map +1 -0
- package/dist/auth/rbac-patterns.d.ts +68 -0
- package/dist/auth/rbac-patterns.d.ts.map +1 -0
- package/dist/auth/rbac-patterns.js +143 -0
- package/dist/auth/rbac-patterns.js.map +1 -0
- package/dist/auth/resource-ownership.d.ts +77 -0
- package/dist/auth/resource-ownership.d.ts.map +1 -0
- package/dist/auth/resource-ownership.js +324 -0
- package/dist/auth/resource-ownership.js.map +1 -0
- package/dist/auth/token-handling.d.ts +64 -0
- package/dist/auth/token-handling.d.ts.map +1 -0
- package/dist/auth/token-handling.js +151 -0
- package/dist/auth/token-handling.js.map +1 -0
- package/dist/base/ast-detector.d.ts +421 -0
- package/dist/base/ast-detector.d.ts.map +1 -0
- package/dist/base/ast-detector.js +699 -0
- package/dist/base/ast-detector.js.map +1 -0
- package/dist/base/base-detector.d.ts +366 -0
- package/dist/base/base-detector.d.ts.map +1 -0
- package/dist/base/base-detector.js +170 -0
- package/dist/base/base-detector.js.map +1 -0
- package/dist/base/index.d.ts +12 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +17 -0
- package/dist/base/index.js.map +1 -0
- package/dist/base/regex-detector.d.ts +421 -0
- package/dist/base/regex-detector.d.ts.map +1 -0
- package/dist/base/regex-detector.js +537 -0
- package/dist/base/regex-detector.js.map +1 -0
- package/dist/base/structural-detector.d.ts +424 -0
- package/dist/base/structural-detector.d.ts.map +1 -0
- package/dist/base/structural-detector.js +731 -0
- package/dist/base/structural-detector.js.map +1 -0
- package/dist/base/types.d.ts +53 -0
- package/dist/base/types.d.ts.map +1 -0
- package/dist/base/types.js +5 -0
- package/dist/base/types.js.map +1 -0
- package/dist/components/component-structure.d.ts +163 -0
- package/dist/components/component-structure.d.ts.map +1 -0
- package/dist/components/component-structure.js +500 -0
- package/dist/components/component-structure.js.map +1 -0
- package/dist/components/composition.d.ts +287 -0
- package/dist/components/composition.d.ts.map +1 -0
- package/dist/components/composition.js +1123 -0
- package/dist/components/composition.js.map +1 -0
- package/dist/components/duplicate-detection.d.ts +251 -0
- package/dist/components/duplicate-detection.d.ts.map +1 -0
- package/dist/components/duplicate-detection.js +804 -0
- package/dist/components/duplicate-detection.js.map +1 -0
- package/dist/components/index.d.ts +16 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +51 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/near-duplicate.d.ts +402 -0
- package/dist/components/near-duplicate.d.ts.map +1 -0
- package/dist/components/near-duplicate.js +1090 -0
- package/dist/components/near-duplicate.js.map +1 -0
- package/dist/components/props-patterns.d.ts +194 -0
- package/dist/components/props-patterns.d.ts.map +1 -0
- package/dist/components/props-patterns.js +795 -0
- package/dist/components/props-patterns.js.map +1 -0
- package/dist/components/ref-forwarding.d.ts +250 -0
- package/dist/components/ref-forwarding.d.ts.map +1 -0
- package/dist/components/ref-forwarding.js +832 -0
- package/dist/components/ref-forwarding.js.map +1 -0
- package/dist/components/state-patterns.d.ts +291 -0
- package/dist/components/state-patterns.d.ts.map +1 -0
- package/dist/components/state-patterns.js +970 -0
- package/dist/components/state-patterns.js.map +1 -0
- package/dist/config/config-validation.d.ts +74 -0
- package/dist/config/config-validation.d.ts.map +1 -0
- package/dist/config/config-validation.js +446 -0
- package/dist/config/config-validation.js.map +1 -0
- package/dist/config/default-values.d.ts +72 -0
- package/dist/config/default-values.d.ts.map +1 -0
- package/dist/config/default-values.js +386 -0
- package/dist/config/default-values.js.map +1 -0
- package/dist/config/env-naming.d.ts +73 -0
- package/dist/config/env-naming.d.ts.map +1 -0
- package/dist/config/env-naming.js +429 -0
- package/dist/config/env-naming.js.map +1 -0
- package/dist/config/environment-detection.d.ts +72 -0
- package/dist/config/environment-detection.d.ts.map +1 -0
- package/dist/config/environment-detection.js +400 -0
- package/dist/config/environment-detection.js.map +1 -0
- package/dist/config/feature-flags.d.ts +72 -0
- package/dist/config/feature-flags.d.ts.map +1 -0
- package/dist/config/feature-flags.js +384 -0
- package/dist/config/feature-flags.js.map +1 -0
- package/dist/config/index.d.ts +27 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +43 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/required-optional.d.ts +71 -0
- package/dist/config/required-optional.d.ts.map +1 -0
- package/dist/config/required-optional.js +344 -0
- package/dist/config/required-optional.js.map +1 -0
- package/dist/data-access/connection-pooling.d.ts +63 -0
- package/dist/data-access/connection-pooling.d.ts.map +1 -0
- package/dist/data-access/connection-pooling.js +297 -0
- package/dist/data-access/connection-pooling.js.map +1 -0
- package/dist/data-access/dto-patterns.d.ts +64 -0
- package/dist/data-access/dto-patterns.d.ts.map +1 -0
- package/dist/data-access/dto-patterns.js +291 -0
- package/dist/data-access/dto-patterns.js.map +1 -0
- package/dist/data-access/index.d.ts +31 -0
- package/dist/data-access/index.d.ts.map +1 -0
- package/dist/data-access/index.js +49 -0
- package/dist/data-access/index.js.map +1 -0
- package/dist/data-access/n-plus-one.d.ts +60 -0
- package/dist/data-access/n-plus-one.d.ts.map +1 -0
- package/dist/data-access/n-plus-one.js +264 -0
- package/dist/data-access/n-plus-one.js.map +1 -0
- package/dist/data-access/query-patterns.d.ts +64 -0
- package/dist/data-access/query-patterns.d.ts.map +1 -0
- package/dist/data-access/query-patterns.js +314 -0
- package/dist/data-access/query-patterns.js.map +1 -0
- package/dist/data-access/repository-pattern.d.ts +62 -0
- package/dist/data-access/repository-pattern.d.ts.map +1 -0
- package/dist/data-access/repository-pattern.js +257 -0
- package/dist/data-access/repository-pattern.js.map +1 -0
- package/dist/data-access/transaction-patterns.d.ts +61 -0
- package/dist/data-access/transaction-patterns.d.ts.map +1 -0
- package/dist/data-access/transaction-patterns.js +277 -0
- package/dist/data-access/transaction-patterns.js.map +1 -0
- package/dist/data-access/validation-patterns.d.ts +62 -0
- package/dist/data-access/validation-patterns.d.ts.map +1 -0
- package/dist/data-access/validation-patterns.js +301 -0
- package/dist/data-access/validation-patterns.js.map +1 -0
- package/dist/documentation/deprecation.d.ts +62 -0
- package/dist/documentation/deprecation.d.ts.map +1 -0
- package/dist/documentation/deprecation.js +83 -0
- package/dist/documentation/deprecation.js.map +1 -0
- package/dist/documentation/example-code.d.ts +64 -0
- package/dist/documentation/example-code.d.ts.map +1 -0
- package/dist/documentation/example-code.js +79 -0
- package/dist/documentation/example-code.js.map +1 -0
- package/dist/documentation/index.d.ts +22 -0
- package/dist/documentation/index.d.ts.map +1 -0
- package/dist/documentation/index.js +19 -0
- package/dist/documentation/index.js.map +1 -0
- package/dist/documentation/jsdoc-patterns.d.ts +72 -0
- package/dist/documentation/jsdoc-patterns.d.ts.map +1 -0
- package/dist/documentation/jsdoc-patterns.js +92 -0
- package/dist/documentation/jsdoc-patterns.js.map +1 -0
- package/dist/documentation/readme-structure.d.ts +67 -0
- package/dist/documentation/readme-structure.d.ts.map +1 -0
- package/dist/documentation/readme-structure.js +76 -0
- package/dist/documentation/readme-structure.js.map +1 -0
- package/dist/documentation/todo-patterns.d.ts +67 -0
- package/dist/documentation/todo-patterns.d.ts.map +1 -0
- package/dist/documentation/todo-patterns.js +73 -0
- package/dist/documentation/todo-patterns.js.map +1 -0
- package/dist/errors/async-errors.d.ts +72 -0
- package/dist/errors/async-errors.d.ts.map +1 -0
- package/dist/errors/async-errors.js +214 -0
- package/dist/errors/async-errors.js.map +1 -0
- package/dist/errors/circuit-breaker.d.ts +53 -0
- package/dist/errors/circuit-breaker.d.ts.map +1 -0
- package/dist/errors/circuit-breaker.js +241 -0
- package/dist/errors/circuit-breaker.js.map +1 -0
- package/dist/errors/error-codes.d.ts +73 -0
- package/dist/errors/error-codes.d.ts.map +1 -0
- package/dist/errors/error-codes.js +211 -0
- package/dist/errors/error-codes.js.map +1 -0
- package/dist/errors/error-logging.d.ts +73 -0
- package/dist/errors/error-logging.d.ts.map +1 -0
- package/dist/errors/error-logging.js +256 -0
- package/dist/errors/error-logging.js.map +1 -0
- package/dist/errors/error-propagation.d.ts +73 -0
- package/dist/errors/error-propagation.d.ts.map +1 -0
- package/dist/errors/error-propagation.js +244 -0
- package/dist/errors/error-propagation.js.map +1 -0
- package/dist/errors/exception-hierarchy.d.ts +75 -0
- package/dist/errors/exception-hierarchy.d.ts.map +1 -0
- package/dist/errors/exception-hierarchy.js +259 -0
- package/dist/errors/exception-hierarchy.js.map +1 -0
- package/dist/errors/index.d.ts +31 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +49 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/try-catch-placement.d.ts +73 -0
- package/dist/errors/try-catch-placement.d.ts.map +1 -0
- package/dist/errors/try-catch-placement.js +214 -0
- package/dist/errors/try-catch-placement.js.map +1 -0
- package/dist/index.d.ts +221 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/context-fields.d.ts +48 -0
- package/dist/logging/context-fields.d.ts.map +1 -0
- package/dist/logging/context-fields.js +160 -0
- package/dist/logging/context-fields.js.map +1 -0
- package/dist/logging/correlation-ids.d.ts +44 -0
- package/dist/logging/correlation-ids.d.ts.map +1 -0
- package/dist/logging/correlation-ids.js +144 -0
- package/dist/logging/correlation-ids.js.map +1 -0
- package/dist/logging/health-checks.d.ts +45 -0
- package/dist/logging/health-checks.d.ts.map +1 -0
- package/dist/logging/health-checks.js +165 -0
- package/dist/logging/health-checks.js.map +1 -0
- package/dist/logging/index.d.ts +31 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +49 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/log-levels.d.ts +46 -0
- package/dist/logging/log-levels.d.ts.map +1 -0
- package/dist/logging/log-levels.js +178 -0
- package/dist/logging/log-levels.js.map +1 -0
- package/dist/logging/metric-naming.d.ts +46 -0
- package/dist/logging/metric-naming.d.ts.map +1 -0
- package/dist/logging/metric-naming.js +157 -0
- package/dist/logging/metric-naming.js.map +1 -0
- package/dist/logging/pii-redaction.d.ts +44 -0
- package/dist/logging/pii-redaction.d.ts.map +1 -0
- package/dist/logging/pii-redaction.js +166 -0
- package/dist/logging/pii-redaction.js.map +1 -0
- package/dist/logging/structured-format.d.ts +53 -0
- package/dist/logging/structured-format.d.ts.map +1 -0
- package/dist/logging/structured-format.js +235 -0
- package/dist/logging/structured-format.js.map +1 -0
- package/dist/performance/bundle-size.d.ts +79 -0
- package/dist/performance/bundle-size.d.ts.map +1 -0
- package/dist/performance/bundle-size.js +276 -0
- package/dist/performance/bundle-size.js.map +1 -0
- package/dist/performance/caching-patterns.d.ts +78 -0
- package/dist/performance/caching-patterns.d.ts.map +1 -0
- package/dist/performance/caching-patterns.js +257 -0
- package/dist/performance/caching-patterns.js.map +1 -0
- package/dist/performance/code-splitting.d.ts +86 -0
- package/dist/performance/code-splitting.d.ts.map +1 -0
- package/dist/performance/code-splitting.js +447 -0
- package/dist/performance/code-splitting.js.map +1 -0
- package/dist/performance/debounce-throttle.d.ts +75 -0
- package/dist/performance/debounce-throttle.d.ts.map +1 -0
- package/dist/performance/debounce-throttle.js +232 -0
- package/dist/performance/debounce-throttle.js.map +1 -0
- package/dist/performance/index.d.ts +28 -0
- package/dist/performance/index.d.ts.map +1 -0
- package/dist/performance/index.js +39 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/performance/lazy-loading.d.ts +75 -0
- package/dist/performance/lazy-loading.d.ts.map +1 -0
- package/dist/performance/lazy-loading.js +233 -0
- package/dist/performance/lazy-loading.js.map +1 -0
- package/dist/performance/memoization.d.ts +75 -0
- package/dist/performance/memoization.d.ts.map +1 -0
- package/dist/performance/memoization.js +251 -0
- package/dist/performance/memoization.js.map +1 -0
- package/dist/registry/detector-registry.d.ts +266 -0
- package/dist/registry/detector-registry.d.ts.map +1 -0
- package/dist/registry/detector-registry.js +526 -0
- package/dist/registry/detector-registry.js.map +1 -0
- package/dist/registry/index.d.ts +10 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +10 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/loader.d.ts +232 -0
- package/dist/registry/loader.d.ts.map +1 -0
- package/dist/registry/loader.js +419 -0
- package/dist/registry/loader.js.map +1 -0
- package/dist/registry/types.d.ts +111 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +19 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/security/csp-headers.d.ts +78 -0
- package/dist/security/csp-headers.d.ts.map +1 -0
- package/dist/security/csp-headers.js +401 -0
- package/dist/security/csp-headers.js.map +1 -0
- package/dist/security/csrf-protection.d.ts +72 -0
- package/dist/security/csrf-protection.d.ts.map +1 -0
- package/dist/security/csrf-protection.js +344 -0
- package/dist/security/csrf-protection.js.map +1 -0
- package/dist/security/index.d.ts +30 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +48 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/input-sanitization.d.ts +74 -0
- package/dist/security/input-sanitization.d.ts.map +1 -0
- package/dist/security/input-sanitization.js +373 -0
- package/dist/security/input-sanitization.js.map +1 -0
- package/dist/security/rate-limiting.d.ts +81 -0
- package/dist/security/rate-limiting.d.ts.map +1 -0
- package/dist/security/rate-limiting.js +535 -0
- package/dist/security/rate-limiting.js.map +1 -0
- package/dist/security/secret-management.d.ts +83 -0
- package/dist/security/secret-management.d.ts.map +1 -0
- package/dist/security/secret-management.js +547 -0
- package/dist/security/secret-management.js.map +1 -0
- package/dist/security/sql-injection.d.ts +76 -0
- package/dist/security/sql-injection.d.ts.map +1 -0
- package/dist/security/sql-injection.js +383 -0
- package/dist/security/sql-injection.js.map +1 -0
- package/dist/security/xss-prevention.d.ts +80 -0
- package/dist/security/xss-prevention.d.ts.map +1 -0
- package/dist/security/xss-prevention.js +416 -0
- package/dist/security/xss-prevention.js.map +1 -0
- package/dist/structural/barrel-exports.d.ts +178 -0
- package/dist/structural/barrel-exports.d.ts.map +1 -0
- package/dist/structural/barrel-exports.js +553 -0
- package/dist/structural/barrel-exports.js.map +1 -0
- package/dist/structural/circular-deps.d.ts +140 -0
- package/dist/structural/circular-deps.d.ts.map +1 -0
- package/dist/structural/circular-deps.js +422 -0
- package/dist/structural/circular-deps.js.map +1 -0
- package/dist/structural/co-location.d.ts +202 -0
- package/dist/structural/co-location.d.ts.map +1 -0
- package/dist/structural/co-location.js +640 -0
- package/dist/structural/co-location.js.map +1 -0
- package/dist/structural/directory-structure.d.ts +151 -0
- package/dist/structural/directory-structure.d.ts.map +1 -0
- package/dist/structural/directory-structure.js +457 -0
- package/dist/structural/directory-structure.js.map +1 -0
- package/dist/structural/file-naming.d.ts +61 -0
- package/dist/structural/file-naming.d.ts.map +1 -0
- package/dist/structural/file-naming.js +231 -0
- package/dist/structural/file-naming.js.map +1 -0
- package/dist/structural/import-ordering.d.ts +212 -0
- package/dist/structural/import-ordering.d.ts.map +1 -0
- package/dist/structural/import-ordering.js +821 -0
- package/dist/structural/import-ordering.js.map +1 -0
- package/dist/structural/index.d.ts +23 -0
- package/dist/structural/index.d.ts.map +1 -0
- package/dist/structural/index.js +26 -0
- package/dist/structural/index.js.map +1 -0
- package/dist/structural/module-boundaries.d.ts +164 -0
- package/dist/structural/module-boundaries.d.ts.map +1 -0
- package/dist/structural/module-boundaries.js +616 -0
- package/dist/structural/module-boundaries.js.map +1 -0
- package/dist/structural/package-boundaries.d.ts +182 -0
- package/dist/structural/package-boundaries.d.ts.map +1 -0
- package/dist/structural/package-boundaries.js +602 -0
- package/dist/structural/package-boundaries.js.map +1 -0
- package/dist/styling/class-naming.d.ts +263 -0
- package/dist/styling/class-naming.d.ts.map +1 -0
- package/dist/styling/class-naming.js +892 -0
- package/dist/styling/class-naming.js.map +1 -0
- package/dist/styling/color-usage.d.ts +213 -0
- package/dist/styling/color-usage.d.ts.map +1 -0
- package/dist/styling/color-usage.js +732 -0
- package/dist/styling/color-usage.js.map +1 -0
- package/dist/styling/design-tokens.d.ts +212 -0
- package/dist/styling/design-tokens.d.ts.map +1 -0
- package/dist/styling/design-tokens.js +748 -0
- package/dist/styling/design-tokens.js.map +1 -0
- package/dist/styling/index.d.ts +16 -0
- package/dist/styling/index.d.ts.map +1 -0
- package/dist/styling/index.js +56 -0
- package/dist/styling/index.js.map +1 -0
- package/dist/styling/responsive.d.ts +304 -0
- package/dist/styling/responsive.d.ts.map +1 -0
- package/dist/styling/responsive.js +888 -0
- package/dist/styling/responsive.js.map +1 -0
- package/dist/styling/spacing-scale.d.ts +248 -0
- package/dist/styling/spacing-scale.d.ts.map +1 -0
- package/dist/styling/spacing-scale.js +865 -0
- package/dist/styling/spacing-scale.js.map +1 -0
- package/dist/styling/tailwind-patterns.d.ts +305 -0
- package/dist/styling/tailwind-patterns.d.ts.map +1 -0
- package/dist/styling/tailwind-patterns.js +1181 -0
- package/dist/styling/tailwind-patterns.js.map +1 -0
- package/dist/styling/typography.d.ts +281 -0
- package/dist/styling/typography.d.ts.map +1 -0
- package/dist/styling/typography.js +1004 -0
- package/dist/styling/typography.js.map +1 -0
- package/dist/styling/z-index-scale.d.ts +270 -0
- package/dist/styling/z-index-scale.d.ts.map +1 -0
- package/dist/styling/z-index-scale.js +714 -0
- package/dist/styling/z-index-scale.js.map +1 -0
- package/dist/testing/co-location.d.ts +42 -0
- package/dist/testing/co-location.d.ts.map +1 -0
- package/dist/testing/co-location.js +134 -0
- package/dist/testing/co-location.js.map +1 -0
- package/dist/testing/describe-naming.d.ts +47 -0
- package/dist/testing/describe-naming.d.ts.map +1 -0
- package/dist/testing/describe-naming.js +150 -0
- package/dist/testing/describe-naming.js.map +1 -0
- package/dist/testing/file-naming.d.ts +44 -0
- package/dist/testing/file-naming.d.ts.map +1 -0
- package/dist/testing/file-naming.js +131 -0
- package/dist/testing/file-naming.js.map +1 -0
- package/dist/testing/fixture-patterns.d.ts +52 -0
- package/dist/testing/fixture-patterns.d.ts.map +1 -0
- package/dist/testing/fixture-patterns.js +228 -0
- package/dist/testing/fixture-patterns.js.map +1 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +49 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-patterns.d.ts +53 -0
- package/dist/testing/mock-patterns.d.ts.map +1 -0
- package/dist/testing/mock-patterns.js +264 -0
- package/dist/testing/mock-patterns.js.map +1 -0
- package/dist/testing/setup-teardown.d.ts +55 -0
- package/dist/testing/setup-teardown.d.ts.map +1 -0
- package/dist/testing/setup-teardown.js +262 -0
- package/dist/testing/setup-teardown.js.map +1 -0
- package/dist/testing/test-structure.d.ts +51 -0
- package/dist/testing/test-structure.d.ts.map +1 -0
- package/dist/testing/test-structure.js +225 -0
- package/dist/testing/test-structure.js.map +1 -0
- package/dist/types/any-usage.d.ts +99 -0
- package/dist/types/any-usage.d.ts.map +1 -0
- package/dist/types/any-usage.js +641 -0
- package/dist/types/any-usage.js.map +1 -0
- package/dist/types/file-location.d.ts +76 -0
- package/dist/types/file-location.d.ts.map +1 -0
- package/dist/types/file-location.js +395 -0
- package/dist/types/file-location.js.map +1 -0
- package/dist/types/generic-patterns.d.ts +97 -0
- package/dist/types/generic-patterns.d.ts.map +1 -0
- package/dist/types/generic-patterns.js +615 -0
- package/dist/types/generic-patterns.js.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +43 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/interface-vs-type.d.ts +81 -0
- package/dist/types/interface-vs-type.d.ts.map +1 -0
- package/dist/types/interface-vs-type.js +440 -0
- package/dist/types/interface-vs-type.js.map +1 -0
- package/dist/types/naming-conventions.d.ts +84 -0
- package/dist/types/naming-conventions.d.ts.map +1 -0
- package/dist/types/naming-conventions.js +455 -0
- package/dist/types/naming-conventions.js.map +1 -0
- package/dist/types/type-assertions.d.ts +98 -0
- package/dist/types/type-assertions.d.ts.map +1 -0
- package/dist/types/type-assertions.js +639 -0
- package/dist/types/type-assertions.js.map +1 -0
- package/dist/types/utility-types.d.ts +110 -0
- package/dist/types/utility-types.d.ts.map +1 -0
- package/dist/types/utility-types.js +547 -0
- package/dist/types/utility-types.js.map +1 -0
- 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
|