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,821 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Ordering Detector - Import organization detection
|
|
3
|
+
*
|
|
4
|
+
* Detects import grouping patterns and import sorting patterns.
|
|
5
|
+
* Identifies how imports are organized (external packages first, then internal modules,
|
|
6
|
+
* then relative imports), whether they are sorted alphabetically within groups,
|
|
7
|
+
* and whether blank lines separate groups.
|
|
8
|
+
*
|
|
9
|
+
* @requirements 7.5 - THE Structural_Detector SHALL detect import ordering and grouping patterns
|
|
10
|
+
*/
|
|
11
|
+
import { StructuralDetector } from '../base/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Common Node.js built-in modules
|
|
14
|
+
*/
|
|
15
|
+
export const BUILTIN_MODULES = [
|
|
16
|
+
'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
|
|
17
|
+
'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
|
|
18
|
+
'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode',
|
|
19
|
+
'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys',
|
|
20
|
+
'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'worker_threads', 'zlib',
|
|
21
|
+
// Node.js prefixed modules
|
|
22
|
+
'node:assert', 'node:buffer', 'node:child_process', 'node:cluster',
|
|
23
|
+
'node:console', 'node:constants', 'node:crypto', 'node:dgram', 'node:dns',
|
|
24
|
+
'node:domain', 'node:events', 'node:fs', 'node:http', 'node:https',
|
|
25
|
+
'node:module', 'node:net', 'node:os', 'node:path', 'node:perf_hooks',
|
|
26
|
+
'node:process', 'node:punycode', 'node:querystring', 'node:readline',
|
|
27
|
+
'node:repl', 'node:stream', 'node:string_decoder', 'node:sys', 'node:timers',
|
|
28
|
+
'node:tls', 'node:tty', 'node:url', 'node:util', 'node:v8', 'node:vm',
|
|
29
|
+
'node:worker_threads', 'node:zlib',
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Common internal alias patterns
|
|
33
|
+
* Note: @types/ is excluded as it's an external package namespace
|
|
34
|
+
*/
|
|
35
|
+
export const INTERNAL_ALIAS_PATTERNS = [
|
|
36
|
+
/^@\//, // @/components
|
|
37
|
+
/^~\//, // ~/utils
|
|
38
|
+
/^@(?!types\/)[a-z]+\//, // @app/, @lib/, @drift/ (but not @types/)
|
|
39
|
+
/^#/, // #utils (Node.js subpath imports)
|
|
40
|
+
];
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Helper Functions
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* Python standard library modules (subset of most common)
|
|
46
|
+
*/
|
|
47
|
+
export const PYTHON_STDLIB_MODULES = [
|
|
48
|
+
'abc', 'argparse', 'asyncio', 'base64', 'collections', 'contextlib',
|
|
49
|
+
'copy', 'csv', 'dataclasses', 'datetime', 'decimal', 'enum', 'functools',
|
|
50
|
+
'hashlib', 'http', 'importlib', 'inspect', 'io', 'itertools', 'json',
|
|
51
|
+
'logging', 'math', 'multiprocessing', 'os', 'pathlib', 'pickle', 'random',
|
|
52
|
+
're', 'shutil', 'socket', 'sqlite3', 'ssl', 'string', 'subprocess', 'sys',
|
|
53
|
+
'tempfile', 'threading', 'time', 'traceback', 'typing', 'unittest', 'urllib',
|
|
54
|
+
'uuid', 'warnings', 'xml', 'zipfile',
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Determine the type of a Python import based on its source
|
|
58
|
+
*/
|
|
59
|
+
export function getPythonImportType(source) {
|
|
60
|
+
// Check for standard library modules
|
|
61
|
+
const baseModule = source.split('.')[0] || source;
|
|
62
|
+
if (PYTHON_STDLIB_MODULES.includes(baseModule)) {
|
|
63
|
+
return 'builtin';
|
|
64
|
+
}
|
|
65
|
+
// Check for relative imports
|
|
66
|
+
if (source.startsWith('.')) {
|
|
67
|
+
if (source === '.') {
|
|
68
|
+
return 'index';
|
|
69
|
+
}
|
|
70
|
+
if (source.startsWith('..')) {
|
|
71
|
+
return 'parent';
|
|
72
|
+
}
|
|
73
|
+
return 'sibling';
|
|
74
|
+
}
|
|
75
|
+
// Everything else is external (third-party)
|
|
76
|
+
return 'external';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse Python import statements from file content
|
|
80
|
+
*/
|
|
81
|
+
export function parsePythonImports(content) {
|
|
82
|
+
const imports = [];
|
|
83
|
+
const lines = content.split('\n');
|
|
84
|
+
// Python import patterns
|
|
85
|
+
const importPatterns = [
|
|
86
|
+
// import module
|
|
87
|
+
/^import\s+(\S+)/,
|
|
88
|
+
// from module import ...
|
|
89
|
+
/^from\s+(\S+)\s+import/,
|
|
90
|
+
];
|
|
91
|
+
for (let i = 0; i < lines.length; i++) {
|
|
92
|
+
const line = lines[i];
|
|
93
|
+
const trimmedLine = line.trim();
|
|
94
|
+
const lineNumber = i + 1;
|
|
95
|
+
// Skip empty lines and comments
|
|
96
|
+
if (!trimmedLine || trimmedLine.startsWith('#')) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// Skip if we're past the import section (Python convention: imports at top)
|
|
100
|
+
if (!trimmedLine.startsWith('import') && !trimmedLine.startsWith('from') &&
|
|
101
|
+
imports.length > 0 && !trimmedLine.startsWith('(') && !trimmedLine.endsWith(',')) {
|
|
102
|
+
// Check if this looks like code (not a continuation)
|
|
103
|
+
if (/^(def|class|async|@|\w+\s*=)/.test(trimmedLine)) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Try to match import patterns
|
|
108
|
+
for (const pattern of importPatterns) {
|
|
109
|
+
const match = trimmedLine.match(pattern);
|
|
110
|
+
if (match && match[1]) {
|
|
111
|
+
const source = match[1];
|
|
112
|
+
imports.push({
|
|
113
|
+
source,
|
|
114
|
+
type: getPythonImportType(source),
|
|
115
|
+
line: lineNumber,
|
|
116
|
+
statement: trimmedLine,
|
|
117
|
+
isTypeOnly: trimmedLine.includes('TYPE_CHECKING') || trimmedLine.includes('typing'),
|
|
118
|
+
isSideEffect: false,
|
|
119
|
+
});
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return imports;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Determine the type of an import based on its source
|
|
128
|
+
*/
|
|
129
|
+
export function getImportType(source) {
|
|
130
|
+
// Check for built-in modules
|
|
131
|
+
const baseModule = source.split('/')[0] || source;
|
|
132
|
+
if (BUILTIN_MODULES.includes(baseModule)) {
|
|
133
|
+
return 'builtin';
|
|
134
|
+
}
|
|
135
|
+
// Check for internal aliases
|
|
136
|
+
for (const pattern of INTERNAL_ALIAS_PATTERNS) {
|
|
137
|
+
if (pattern.test(source)) {
|
|
138
|
+
return 'internal';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Check for relative imports
|
|
142
|
+
if (source === '.' || source === './') {
|
|
143
|
+
return 'index';
|
|
144
|
+
}
|
|
145
|
+
if (source.startsWith('./')) {
|
|
146
|
+
return 'sibling';
|
|
147
|
+
}
|
|
148
|
+
if (source.startsWith('../')) {
|
|
149
|
+
return 'parent';
|
|
150
|
+
}
|
|
151
|
+
// Everything else is external (from node_modules)
|
|
152
|
+
return 'external';
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Parse import statements from file content
|
|
156
|
+
*/
|
|
157
|
+
export function parseImports(content, filePath) {
|
|
158
|
+
// Use Python parser for .py files
|
|
159
|
+
if (filePath?.endsWith('.py')) {
|
|
160
|
+
return parsePythonImports(content);
|
|
161
|
+
}
|
|
162
|
+
const imports = [];
|
|
163
|
+
const lines = content.split('\n');
|
|
164
|
+
// Regex patterns for different import styles
|
|
165
|
+
const importPatterns = [
|
|
166
|
+
// Standard import: import { foo } from 'bar'
|
|
167
|
+
/^import\s+(?:type\s+)?(?:\{[^}]*\}|\*\s+as\s+\w+|\w+(?:\s*,\s*\{[^}]*\})?)\s+from\s+['"]([^'"]+)['"]/,
|
|
168
|
+
// Side-effect import: import 'bar'
|
|
169
|
+
/^import\s+['"]([^'"]+)['"]/,
|
|
170
|
+
// Dynamic import at top level (less common but valid)
|
|
171
|
+
/^(?:const|let|var)\s+\w+\s*=\s*(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/,
|
|
172
|
+
];
|
|
173
|
+
let inMultilineImport = false;
|
|
174
|
+
let multilineStart = 0;
|
|
175
|
+
let multilineContent = '';
|
|
176
|
+
for (let i = 0; i < lines.length; i++) {
|
|
177
|
+
const line = lines[i];
|
|
178
|
+
const trimmedLine = line.trim();
|
|
179
|
+
const lineNumber = i + 1;
|
|
180
|
+
// Skip empty lines and comments
|
|
181
|
+
if (!trimmedLine || trimmedLine.startsWith('//') || trimmedLine.startsWith('/*')) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
// Handle multiline imports
|
|
185
|
+
if (inMultilineImport) {
|
|
186
|
+
multilineContent += ' ' + trimmedLine;
|
|
187
|
+
if (trimmedLine.includes('from')) {
|
|
188
|
+
inMultilineImport = false;
|
|
189
|
+
const fullStatement = multilineContent;
|
|
190
|
+
for (const pattern of importPatterns) {
|
|
191
|
+
const match = fullStatement.match(pattern);
|
|
192
|
+
if (match && match[1]) {
|
|
193
|
+
const source = match[1];
|
|
194
|
+
imports.push({
|
|
195
|
+
source,
|
|
196
|
+
type: getImportType(source),
|
|
197
|
+
line: multilineStart,
|
|
198
|
+
statement: fullStatement,
|
|
199
|
+
isTypeOnly: fullStatement.includes('import type'),
|
|
200
|
+
isSideEffect: !fullStatement.includes('from'),
|
|
201
|
+
});
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
multilineContent = '';
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
// Check if this is the start of a multiline import
|
|
210
|
+
if (trimmedLine.startsWith('import') && !trimmedLine.includes('from') && !trimmedLine.match(/^import\s+['"]/)) {
|
|
211
|
+
inMultilineImport = true;
|
|
212
|
+
multilineStart = lineNumber;
|
|
213
|
+
multilineContent = trimmedLine;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Try to match single-line imports
|
|
217
|
+
for (const pattern of importPatterns) {
|
|
218
|
+
const match = trimmedLine.match(pattern);
|
|
219
|
+
if (match && match[1]) {
|
|
220
|
+
const source = match[1];
|
|
221
|
+
imports.push({
|
|
222
|
+
source,
|
|
223
|
+
type: getImportType(source),
|
|
224
|
+
line: lineNumber,
|
|
225
|
+
statement: trimmedLine,
|
|
226
|
+
isTypeOnly: trimmedLine.includes('import type'),
|
|
227
|
+
isSideEffect: !trimmedLine.includes('from'),
|
|
228
|
+
});
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return imports;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Check if imports are sorted alphabetically
|
|
237
|
+
*/
|
|
238
|
+
export function areImportsSorted(imports) {
|
|
239
|
+
if (imports.length <= 1) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
for (let i = 1; i < imports.length; i++) {
|
|
243
|
+
const prev = imports[i - 1].source.toLowerCase();
|
|
244
|
+
const curr = imports[i].source.toLowerCase();
|
|
245
|
+
if (prev > curr) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Detect import groups based on blank lines and import types
|
|
253
|
+
*/
|
|
254
|
+
export function detectImportGroups(imports, content) {
|
|
255
|
+
if (imports.length === 0) {
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
const lines = content.split('\n');
|
|
259
|
+
const groups = [];
|
|
260
|
+
let currentGroup = [];
|
|
261
|
+
let currentType = null;
|
|
262
|
+
for (let i = 0; i < imports.length; i++) {
|
|
263
|
+
const imp = imports[i];
|
|
264
|
+
const prevImp = imports[i - 1];
|
|
265
|
+
// Check if there's a blank line between this import and the previous one
|
|
266
|
+
let hasBlankLineBefore = false;
|
|
267
|
+
if (prevImp) {
|
|
268
|
+
for (let lineNum = prevImp.line; lineNum < imp.line - 1; lineNum++) {
|
|
269
|
+
const line = lines[lineNum];
|
|
270
|
+
if (line !== undefined && line.trim() === '') {
|
|
271
|
+
hasBlankLineBefore = true;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Start a new group if:
|
|
277
|
+
// 1. This is the first import
|
|
278
|
+
// 2. There's a blank line before this import
|
|
279
|
+
// 3. The import type changed (and we're detecting type-based grouping)
|
|
280
|
+
const _typeChanged = currentType !== null && imp.type !== currentType;
|
|
281
|
+
void _typeChanged; // Suppress unused variable warning - kept for future type-based grouping detection
|
|
282
|
+
const shouldStartNewGroup = currentGroup.length === 0 || hasBlankLineBefore;
|
|
283
|
+
if (shouldStartNewGroup && currentGroup.length > 0) {
|
|
284
|
+
groups.push({
|
|
285
|
+
type: currentType,
|
|
286
|
+
imports: currentGroup,
|
|
287
|
+
startLine: currentGroup[0].line,
|
|
288
|
+
endLine: currentGroup[currentGroup.length - 1].line,
|
|
289
|
+
isSorted: areImportsSorted(currentGroup),
|
|
290
|
+
});
|
|
291
|
+
currentGroup = [];
|
|
292
|
+
}
|
|
293
|
+
currentGroup.push(imp);
|
|
294
|
+
currentType = imp.type;
|
|
295
|
+
}
|
|
296
|
+
// Add the last group
|
|
297
|
+
if (currentGroup.length > 0) {
|
|
298
|
+
groups.push({
|
|
299
|
+
type: currentType,
|
|
300
|
+
imports: currentGroup,
|
|
301
|
+
startLine: currentGroup[0].line,
|
|
302
|
+
endLine: currentGroup[currentGroup.length - 1].line,
|
|
303
|
+
isSorted: areImportsSorted(currentGroup),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return groups;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Check if groups are separated by blank lines
|
|
310
|
+
*/
|
|
311
|
+
export function hasBlankLineSeparators(groups, content) {
|
|
312
|
+
if (groups.length <= 1) {
|
|
313
|
+
return true; // No separators needed for single group
|
|
314
|
+
}
|
|
315
|
+
const lines = content.split('\n');
|
|
316
|
+
for (let i = 1; i < groups.length; i++) {
|
|
317
|
+
const prevGroup = groups[i - 1];
|
|
318
|
+
const currGroup = groups[i];
|
|
319
|
+
// Check for blank line between groups
|
|
320
|
+
let hasBlankLine = false;
|
|
321
|
+
for (let lineNum = prevGroup.endLine; lineNum < currGroup.startLine - 1; lineNum++) {
|
|
322
|
+
const line = lines[lineNum];
|
|
323
|
+
if (line !== undefined && line.trim() === '') {
|
|
324
|
+
hasBlankLine = true;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (!hasBlankLine) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Check if imports are grouped by type
|
|
336
|
+
*/
|
|
337
|
+
export function areImportsGroupedByType(groups) {
|
|
338
|
+
if (groups.length === 0) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
// Check if each group contains only one type of import
|
|
342
|
+
for (const group of groups) {
|
|
343
|
+
const types = new Set(group.imports.map(imp => imp.type));
|
|
344
|
+
if (types.size > 1) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get the order of import types from groups
|
|
352
|
+
*/
|
|
353
|
+
export function getGroupOrder(groups) {
|
|
354
|
+
const order = [];
|
|
355
|
+
const seen = new Set();
|
|
356
|
+
for (const group of groups) {
|
|
357
|
+
for (const imp of group.imports) {
|
|
358
|
+
if (!seen.has(imp.type)) {
|
|
359
|
+
seen.add(imp.type);
|
|
360
|
+
order.push(imp.type);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return order;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Analyze import ordering in a single file
|
|
368
|
+
*/
|
|
369
|
+
export function analyzeFileImports(content, filePath) {
|
|
370
|
+
const imports = parseImports(content, filePath);
|
|
371
|
+
const groups = detectImportGroups(imports, content);
|
|
372
|
+
const isGrouped = areImportsGroupedByType(groups);
|
|
373
|
+
const hasSeparators = hasBlankLineSeparators(groups, content);
|
|
374
|
+
const isSortedWithinGroups = groups.every(g => g.isSorted);
|
|
375
|
+
const groupOrder = getGroupOrder(groups);
|
|
376
|
+
return {
|
|
377
|
+
imports,
|
|
378
|
+
groups,
|
|
379
|
+
isGrouped,
|
|
380
|
+
hasBlankLineSeparators: hasSeparators,
|
|
381
|
+
isSortedWithinGroups,
|
|
382
|
+
groupOrder,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Analyze import ordering patterns across multiple files
|
|
387
|
+
*/
|
|
388
|
+
export function analyzeImportOrdering(fileContents) {
|
|
389
|
+
let filesAnalyzed = 0;
|
|
390
|
+
let filesWithGroupedImports = 0;
|
|
391
|
+
let filesWithSortedImports = 0;
|
|
392
|
+
let filesWithBlankLineSeparators = 0;
|
|
393
|
+
const groupOrders = [];
|
|
394
|
+
for (const [filePath, content] of fileContents) {
|
|
395
|
+
const analysis = analyzeFileImports(content, filePath);
|
|
396
|
+
// Skip files with no imports or only one import
|
|
397
|
+
if (analysis.imports.length <= 1) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
filesAnalyzed++;
|
|
401
|
+
if (analysis.isGrouped) {
|
|
402
|
+
filesWithGroupedImports++;
|
|
403
|
+
}
|
|
404
|
+
if (analysis.isSortedWithinGroups) {
|
|
405
|
+
filesWithSortedImports++;
|
|
406
|
+
}
|
|
407
|
+
if (analysis.hasBlankLineSeparators) {
|
|
408
|
+
filesWithBlankLineSeparators++;
|
|
409
|
+
}
|
|
410
|
+
if (analysis.groupOrder.length > 0) {
|
|
411
|
+
groupOrders.push(analysis.groupOrder);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// Calculate patterns
|
|
415
|
+
let groupingPattern;
|
|
416
|
+
let sortingPattern;
|
|
417
|
+
let confidence;
|
|
418
|
+
if (filesAnalyzed === 0) {
|
|
419
|
+
return {
|
|
420
|
+
groupingPattern: 'unknown',
|
|
421
|
+
sortingPattern: 'unknown',
|
|
422
|
+
confidence: 0,
|
|
423
|
+
filesAnalyzed: 0,
|
|
424
|
+
filesWithGroupedImports: 0,
|
|
425
|
+
filesWithSortedImports: 0,
|
|
426
|
+
filesWithBlankLineSeparators: 0,
|
|
427
|
+
dominantGroupOrder: [],
|
|
428
|
+
patternConsistency: 0,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
const groupedRatio = filesWithGroupedImports / filesAnalyzed;
|
|
432
|
+
const sortedRatio = filesWithSortedImports / filesAnalyzed;
|
|
433
|
+
// Determine grouping pattern
|
|
434
|
+
if (groupedRatio >= 0.8) {
|
|
435
|
+
groupingPattern = 'grouped';
|
|
436
|
+
}
|
|
437
|
+
else if (groupedRatio <= 0.2) {
|
|
438
|
+
groupingPattern = 'ungrouped';
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
groupingPattern = 'mixed';
|
|
442
|
+
}
|
|
443
|
+
// Determine sorting pattern
|
|
444
|
+
if (sortedRatio >= 0.8) {
|
|
445
|
+
sortingPattern = 'alphabetical';
|
|
446
|
+
}
|
|
447
|
+
else if (sortedRatio <= 0.2) {
|
|
448
|
+
sortingPattern = 'unsorted';
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
sortingPattern = 'mixed';
|
|
452
|
+
}
|
|
453
|
+
// Find dominant group order
|
|
454
|
+
const dominantGroupOrder = findDominantGroupOrder(groupOrders);
|
|
455
|
+
// Calculate pattern consistency
|
|
456
|
+
const patternConsistency = calculatePatternConsistency(groupOrders, dominantGroupOrder);
|
|
457
|
+
// Calculate overall confidence
|
|
458
|
+
confidence = (groupedRatio + sortedRatio + patternConsistency) / 3;
|
|
459
|
+
return {
|
|
460
|
+
groupingPattern,
|
|
461
|
+
sortingPattern,
|
|
462
|
+
confidence,
|
|
463
|
+
filesAnalyzed,
|
|
464
|
+
filesWithGroupedImports,
|
|
465
|
+
filesWithSortedImports,
|
|
466
|
+
filesWithBlankLineSeparators,
|
|
467
|
+
dominantGroupOrder,
|
|
468
|
+
patternConsistency,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Find the most common group order
|
|
473
|
+
*/
|
|
474
|
+
function findDominantGroupOrder(groupOrders) {
|
|
475
|
+
if (groupOrders.length === 0) {
|
|
476
|
+
return [];
|
|
477
|
+
}
|
|
478
|
+
// Convert orders to strings for comparison
|
|
479
|
+
const orderCounts = new Map();
|
|
480
|
+
for (const order of groupOrders) {
|
|
481
|
+
const key = order.join(',');
|
|
482
|
+
if (!orderCounts.has(key)) {
|
|
483
|
+
orderCounts.set(key, { order, count: 0 });
|
|
484
|
+
}
|
|
485
|
+
orderCounts.get(key).count++;
|
|
486
|
+
}
|
|
487
|
+
// Find the most common order
|
|
488
|
+
let maxCount = 0;
|
|
489
|
+
let dominantOrder = [];
|
|
490
|
+
for (const { order, count } of orderCounts.values()) {
|
|
491
|
+
if (count > maxCount) {
|
|
492
|
+
maxCount = count;
|
|
493
|
+
dominantOrder = order;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return dominantOrder;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Calculate how consistently files follow the dominant pattern
|
|
500
|
+
*/
|
|
501
|
+
function calculatePatternConsistency(groupOrders, dominantOrder) {
|
|
502
|
+
if (groupOrders.length === 0 || dominantOrder.length === 0) {
|
|
503
|
+
return 0;
|
|
504
|
+
}
|
|
505
|
+
const dominantKey = dominantOrder.join(',');
|
|
506
|
+
let matchingFiles = 0;
|
|
507
|
+
for (const order of groupOrders) {
|
|
508
|
+
if (order.join(',') === dominantKey) {
|
|
509
|
+
matchingFiles++;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return matchingFiles / groupOrders.length;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Get the expected group order description
|
|
516
|
+
*/
|
|
517
|
+
export function getGroupOrderDescription(order) {
|
|
518
|
+
if (order.length === 0) {
|
|
519
|
+
return 'no specific order';
|
|
520
|
+
}
|
|
521
|
+
const typeNames = {
|
|
522
|
+
builtin: 'Node.js built-ins',
|
|
523
|
+
external: 'external packages',
|
|
524
|
+
internal: 'internal aliases',
|
|
525
|
+
parent: 'parent imports',
|
|
526
|
+
sibling: 'sibling imports',
|
|
527
|
+
index: 'index imports',
|
|
528
|
+
};
|
|
529
|
+
return order.map(t => typeNames[t]).join(' → ');
|
|
530
|
+
}
|
|
531
|
+
// ============================================================================
|
|
532
|
+
// Import Ordering Detector Class
|
|
533
|
+
// ============================================================================
|
|
534
|
+
/**
|
|
535
|
+
* Detector for import ordering and grouping patterns
|
|
536
|
+
*
|
|
537
|
+
* Identifies how imports are organized in a project:
|
|
538
|
+
* - Grouping by type (external, internal, relative)
|
|
539
|
+
* - Alphabetical sorting within groups
|
|
540
|
+
* - Blank line separators between groups
|
|
541
|
+
*
|
|
542
|
+
* @requirements 7.5 - THE Structural_Detector SHALL detect import ordering and grouping patterns
|
|
543
|
+
*/
|
|
544
|
+
export class ImportOrderingDetector extends StructuralDetector {
|
|
545
|
+
id = 'structural/import-ordering';
|
|
546
|
+
category = 'structural';
|
|
547
|
+
subcategory = 'import-ordering';
|
|
548
|
+
name = 'Import Ordering Detector';
|
|
549
|
+
description = 'Detects import grouping and sorting patterns';
|
|
550
|
+
supportedLanguages = [
|
|
551
|
+
'typescript',
|
|
552
|
+
'javascript',
|
|
553
|
+
'python',
|
|
554
|
+
];
|
|
555
|
+
/**
|
|
556
|
+
* Detect import ordering patterns in the project
|
|
557
|
+
*/
|
|
558
|
+
async detect(context) {
|
|
559
|
+
const patterns = [];
|
|
560
|
+
const violations = [];
|
|
561
|
+
// Analyze the current file's imports
|
|
562
|
+
const fileAnalysis = analyzeFileImports(context.content, context.file);
|
|
563
|
+
// Skip files with no imports or only one import
|
|
564
|
+
if (fileAnalysis.imports.length <= 1) {
|
|
565
|
+
return this.createResult(patterns, violations, 0);
|
|
566
|
+
}
|
|
567
|
+
// Build file contents map for project-wide analysis
|
|
568
|
+
const fileContents = new Map();
|
|
569
|
+
fileContents.set(context.file, context.content);
|
|
570
|
+
// Analyze project-wide patterns (using available context)
|
|
571
|
+
const projectAnalysis = analyzeImportOrdering(fileContents);
|
|
572
|
+
// Create pattern matches
|
|
573
|
+
if (projectAnalysis.groupingPattern !== 'unknown') {
|
|
574
|
+
patterns.push(this.createGroupingPattern(context.file, projectAnalysis));
|
|
575
|
+
}
|
|
576
|
+
if (projectAnalysis.sortingPattern !== 'unknown') {
|
|
577
|
+
patterns.push(this.createSortingPattern(context.file, projectAnalysis));
|
|
578
|
+
}
|
|
579
|
+
if (projectAnalysis.dominantGroupOrder.length > 0) {
|
|
580
|
+
patterns.push(this.createGroupOrderPattern(context.file, projectAnalysis));
|
|
581
|
+
}
|
|
582
|
+
// Check for violations in the current file
|
|
583
|
+
const groupingViolation = this.checkGroupingConsistency(context.file, fileAnalysis, projectAnalysis);
|
|
584
|
+
if (groupingViolation) {
|
|
585
|
+
violations.push(groupingViolation);
|
|
586
|
+
}
|
|
587
|
+
const sortingViolation = this.checkSortingConsistency(context.file, fileAnalysis, projectAnalysis);
|
|
588
|
+
if (sortingViolation) {
|
|
589
|
+
violations.push(sortingViolation);
|
|
590
|
+
}
|
|
591
|
+
const separatorViolation = this.checkBlankLineSeparators(context.file, fileAnalysis, projectAnalysis);
|
|
592
|
+
if (separatorViolation) {
|
|
593
|
+
violations.push(separatorViolation);
|
|
594
|
+
}
|
|
595
|
+
return this.createResult(patterns, violations, projectAnalysis.confidence);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Generate a quick fix for import ordering violations
|
|
599
|
+
*/
|
|
600
|
+
generateQuickFix(violation) {
|
|
601
|
+
if (violation.patternId === 'structural/import-ordering-grouping') {
|
|
602
|
+
return {
|
|
603
|
+
title: 'Group imports by type',
|
|
604
|
+
kind: 'quickfix',
|
|
605
|
+
edit: {
|
|
606
|
+
changes: {},
|
|
607
|
+
documentChanges: [],
|
|
608
|
+
},
|
|
609
|
+
isPreferred: true,
|
|
610
|
+
confidence: 0.7,
|
|
611
|
+
preview: 'Reorganize imports into groups (external, internal, relative)',
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
if (violation.patternId === 'structural/import-ordering-sorting') {
|
|
615
|
+
return {
|
|
616
|
+
title: 'Sort imports alphabetically',
|
|
617
|
+
kind: 'quickfix',
|
|
618
|
+
edit: {
|
|
619
|
+
changes: {},
|
|
620
|
+
documentChanges: [],
|
|
621
|
+
},
|
|
622
|
+
isPreferred: true,
|
|
623
|
+
confidence: 0.8,
|
|
624
|
+
preview: 'Sort imports alphabetically within each group',
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
if (violation.patternId === 'structural/import-ordering-separators') {
|
|
628
|
+
return {
|
|
629
|
+
title: 'Add blank lines between import groups',
|
|
630
|
+
kind: 'quickfix',
|
|
631
|
+
edit: {
|
|
632
|
+
changes: {},
|
|
633
|
+
documentChanges: [],
|
|
634
|
+
},
|
|
635
|
+
isPreferred: false,
|
|
636
|
+
confidence: 0.6,
|
|
637
|
+
preview: 'Add blank lines to separate import groups',
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Create a pattern match for import grouping
|
|
644
|
+
*/
|
|
645
|
+
createGroupingPattern(file, analysis) {
|
|
646
|
+
return {
|
|
647
|
+
patternId: `import-ordering-grouping-${analysis.groupingPattern}`,
|
|
648
|
+
location: { file, line: 1, column: 1 },
|
|
649
|
+
confidence: analysis.confidence,
|
|
650
|
+
isOutlier: false,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Create a pattern match for import sorting
|
|
655
|
+
*/
|
|
656
|
+
createSortingPattern(file, analysis) {
|
|
657
|
+
return {
|
|
658
|
+
patternId: `import-ordering-sorting-${analysis.sortingPattern}`,
|
|
659
|
+
location: { file, line: 1, column: 1 },
|
|
660
|
+
confidence: analysis.confidence,
|
|
661
|
+
isOutlier: false,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Create a pattern match for group order
|
|
666
|
+
*/
|
|
667
|
+
createGroupOrderPattern(file, analysis) {
|
|
668
|
+
const orderKey = analysis.dominantGroupOrder.join('-');
|
|
669
|
+
return {
|
|
670
|
+
patternId: `import-ordering-order-${orderKey}`,
|
|
671
|
+
location: { file, line: 1, column: 1 },
|
|
672
|
+
confidence: analysis.patternConsistency,
|
|
673
|
+
isOutlier: false,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Check if the file's import grouping follows the project pattern
|
|
678
|
+
*/
|
|
679
|
+
checkGroupingConsistency(file, fileAnalysis, projectAnalysis) {
|
|
680
|
+
// Skip if project pattern is unknown or mixed
|
|
681
|
+
if (projectAnalysis.groupingPattern === 'unknown' || projectAnalysis.groupingPattern === 'mixed') {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
// Check if file follows the pattern
|
|
685
|
+
const fileIsGrouped = fileAnalysis.isGrouped;
|
|
686
|
+
const projectExpectsGrouped = projectAnalysis.groupingPattern === 'grouped';
|
|
687
|
+
if (fileIsGrouped === projectExpectsGrouped) {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
const range = {
|
|
691
|
+
start: { line: 1, character: 1 },
|
|
692
|
+
end: { line: 1, character: 1 },
|
|
693
|
+
};
|
|
694
|
+
let message;
|
|
695
|
+
let expected;
|
|
696
|
+
let actual;
|
|
697
|
+
if (projectExpectsGrouped) {
|
|
698
|
+
message = `Imports are not grouped by type. Project uses grouped imports (${getGroupOrderDescription(projectAnalysis.dominantGroupOrder)}).`;
|
|
699
|
+
expected = 'imports grouped by type';
|
|
700
|
+
actual = 'ungrouped imports';
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
message = `Imports are grouped but project uses ungrouped imports.`;
|
|
704
|
+
expected = 'ungrouped imports';
|
|
705
|
+
actual = 'grouped imports';
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
id: `import-ordering-grouping-${file.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
709
|
+
patternId: 'structural/import-ordering-grouping',
|
|
710
|
+
severity: 'info',
|
|
711
|
+
file,
|
|
712
|
+
range,
|
|
713
|
+
message,
|
|
714
|
+
expected,
|
|
715
|
+
actual,
|
|
716
|
+
aiExplainAvailable: true,
|
|
717
|
+
aiFixAvailable: true,
|
|
718
|
+
firstSeen: new Date(),
|
|
719
|
+
occurrences: 1,
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Check if the file's import sorting follows the project pattern
|
|
724
|
+
*/
|
|
725
|
+
checkSortingConsistency(file, fileAnalysis, projectAnalysis) {
|
|
726
|
+
// Skip if project pattern is unknown or mixed
|
|
727
|
+
if (projectAnalysis.sortingPattern === 'unknown' || projectAnalysis.sortingPattern === 'mixed') {
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
// Check if file follows the pattern
|
|
731
|
+
const fileIsSorted = fileAnalysis.isSortedWithinGroups;
|
|
732
|
+
const projectExpectsSorted = projectAnalysis.sortingPattern === 'alphabetical';
|
|
733
|
+
if (fileIsSorted === projectExpectsSorted) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
// Find the first unsorted group for better error reporting
|
|
737
|
+
const unsortedGroup = fileAnalysis.groups.find(g => !g.isSorted);
|
|
738
|
+
const line = unsortedGroup?.startLine || 1;
|
|
739
|
+
const range = {
|
|
740
|
+
start: { line, character: 1 },
|
|
741
|
+
end: { line, character: 1 },
|
|
742
|
+
};
|
|
743
|
+
let message;
|
|
744
|
+
let expected;
|
|
745
|
+
let actual;
|
|
746
|
+
if (projectExpectsSorted) {
|
|
747
|
+
message = `Imports are not sorted alphabetically. Project uses alphabetically sorted imports.`;
|
|
748
|
+
expected = 'alphabetically sorted imports';
|
|
749
|
+
actual = 'unsorted imports';
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
message = `Imports are sorted but project does not enforce alphabetical sorting.`;
|
|
753
|
+
expected = 'no specific sorting';
|
|
754
|
+
actual = 'alphabetically sorted imports';
|
|
755
|
+
}
|
|
756
|
+
return {
|
|
757
|
+
id: `import-ordering-sorting-${file.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
758
|
+
patternId: 'structural/import-ordering-sorting',
|
|
759
|
+
severity: 'info',
|
|
760
|
+
file,
|
|
761
|
+
range,
|
|
762
|
+
message,
|
|
763
|
+
expected,
|
|
764
|
+
actual,
|
|
765
|
+
aiExplainAvailable: true,
|
|
766
|
+
aiFixAvailable: true,
|
|
767
|
+
firstSeen: new Date(),
|
|
768
|
+
occurrences: 1,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Check if the file uses blank line separators between import groups
|
|
773
|
+
*/
|
|
774
|
+
checkBlankLineSeparators(file, fileAnalysis, projectAnalysis) {
|
|
775
|
+
// Skip if project doesn't use grouped imports
|
|
776
|
+
if (projectAnalysis.groupingPattern !== 'grouped') {
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
// Skip if file has only one group
|
|
780
|
+
if (fileAnalysis.groups.length <= 1) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
// Check if project uses blank line separators
|
|
784
|
+
const projectUsesSeparators = projectAnalysis.filesWithBlankLineSeparators > projectAnalysis.filesAnalyzed * 0.7;
|
|
785
|
+
if (!projectUsesSeparators) {
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
// Check if file has blank line separators
|
|
789
|
+
if (fileAnalysis.hasBlankLineSeparators) {
|
|
790
|
+
return null;
|
|
791
|
+
}
|
|
792
|
+
const range = {
|
|
793
|
+
start: { line: 1, character: 1 },
|
|
794
|
+
end: { line: 1, character: 1 },
|
|
795
|
+
};
|
|
796
|
+
return {
|
|
797
|
+
id: `import-ordering-separators-${file.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
798
|
+
patternId: 'structural/import-ordering-separators',
|
|
799
|
+
severity: 'info',
|
|
800
|
+
file,
|
|
801
|
+
range,
|
|
802
|
+
message: `Import groups are not separated by blank lines. Project uses blank lines between import groups.`,
|
|
803
|
+
expected: 'blank lines between import groups',
|
|
804
|
+
actual: 'no blank lines between import groups',
|
|
805
|
+
aiExplainAvailable: true,
|
|
806
|
+
aiFixAvailable: true,
|
|
807
|
+
firstSeen: new Date(),
|
|
808
|
+
occurrences: 1,
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// ============================================================================
|
|
813
|
+
// Factory Function
|
|
814
|
+
// ============================================================================
|
|
815
|
+
/**
|
|
816
|
+
* Create a new ImportOrderingDetector instance
|
|
817
|
+
*/
|
|
818
|
+
export function createImportOrderingDetector() {
|
|
819
|
+
return new ImportOrderingDetector();
|
|
820
|
+
}
|
|
821
|
+
//# sourceMappingURL=import-ordering.js.map
|