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,890 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Methods Detector - HTTP method usage pattern detection
|
|
3
|
+
*
|
|
4
|
+
* Detects HTTP method usage patterns including:
|
|
5
|
+
* - HTTP method usage (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
|
|
6
|
+
* - RESTful method conventions (GET for read, POST for create, PUT/PATCH for update, DELETE for remove)
|
|
7
|
+
* - Express/Fastify method handlers (router.get, router.post, etc.)
|
|
8
|
+
* - Next.js App Router method exports (export function GET, POST, etc.)
|
|
9
|
+
* - Fetch API method usage (fetch with method option)
|
|
10
|
+
* - Axios method usage (axios.get, axios.post, etc.)
|
|
11
|
+
*
|
|
12
|
+
* Flags violations:
|
|
13
|
+
* - Using POST for read operations (should be GET)
|
|
14
|
+
* - Using GET for mutations (should be POST/PUT/PATCH/DELETE)
|
|
15
|
+
* - Missing method handlers for common operations
|
|
16
|
+
* - Inconsistent method usage across similar endpoints
|
|
17
|
+
* - Using PUT when PATCH is more appropriate (partial updates)
|
|
18
|
+
*
|
|
19
|
+
* @requirements 10.2 - THE API_Detector SHALL detect HTTP method usage patterns (POST vs PUT vs PATCH)
|
|
20
|
+
*/
|
|
21
|
+
import { RegexDetector } from '../base/index.js';
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Constants
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* All supported HTTP methods
|
|
27
|
+
*/
|
|
28
|
+
export const HTTP_METHODS = [
|
|
29
|
+
'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* HTTP methods for read operations
|
|
33
|
+
*/
|
|
34
|
+
export const READ_METHODS = ['GET', 'HEAD', 'OPTIONS'];
|
|
35
|
+
/**
|
|
36
|
+
* HTTP methods for mutation operations
|
|
37
|
+
*/
|
|
38
|
+
export const MUTATION_METHODS = ['POST', 'PUT', 'PATCH', 'DELETE'];
|
|
39
|
+
/**
|
|
40
|
+
* RESTful method conventions mapping
|
|
41
|
+
*/
|
|
42
|
+
export const RESTFUL_METHOD_CONVENTIONS = {
|
|
43
|
+
// Read operations should use GET
|
|
44
|
+
read: ['GET'],
|
|
45
|
+
get: ['GET'],
|
|
46
|
+
fetch: ['GET'],
|
|
47
|
+
list: ['GET'],
|
|
48
|
+
find: ['GET'],
|
|
49
|
+
search: ['GET'],
|
|
50
|
+
query: ['GET'],
|
|
51
|
+
// Create operations should use POST
|
|
52
|
+
create: ['POST'],
|
|
53
|
+
add: ['POST'],
|
|
54
|
+
insert: ['POST'],
|
|
55
|
+
new: ['POST'],
|
|
56
|
+
// Update operations should use PUT or PATCH
|
|
57
|
+
update: ['PUT', 'PATCH'],
|
|
58
|
+
edit: ['PUT', 'PATCH'],
|
|
59
|
+
modify: ['PUT', 'PATCH'],
|
|
60
|
+
change: ['PUT', 'PATCH'],
|
|
61
|
+
replace: ['PUT'],
|
|
62
|
+
// Partial update operations should use PATCH
|
|
63
|
+
patch: ['PATCH'],
|
|
64
|
+
partial: ['PATCH'],
|
|
65
|
+
// Delete operations should use DELETE
|
|
66
|
+
delete: ['DELETE'],
|
|
67
|
+
remove: ['DELETE'],
|
|
68
|
+
destroy: ['DELETE'],
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Keywords indicating read operations
|
|
72
|
+
*/
|
|
73
|
+
export const READ_OPERATION_KEYWORDS = new Set([
|
|
74
|
+
'get', 'fetch', 'find', 'list', 'search', 'query', 'read', 'load', 'retrieve',
|
|
75
|
+
'show', 'view', 'display', 'check', 'verify', 'validate', 'exists', 'count',
|
|
76
|
+
]);
|
|
77
|
+
/**
|
|
78
|
+
* Keywords indicating mutation operations
|
|
79
|
+
*/
|
|
80
|
+
export const MUTATION_OPERATION_KEYWORDS = new Set([
|
|
81
|
+
'create', 'add', 'insert', 'new', 'post', 'submit', 'save',
|
|
82
|
+
'update', 'edit', 'modify', 'change', 'patch', 'put', 'replace',
|
|
83
|
+
'delete', 'remove', 'destroy', 'clear', 'reset', 'cancel',
|
|
84
|
+
]);
|
|
85
|
+
/**
|
|
86
|
+
* Keywords indicating partial update operations
|
|
87
|
+
*/
|
|
88
|
+
export const PARTIAL_UPDATE_KEYWORDS = new Set([
|
|
89
|
+
'patch', 'partial', 'update', 'modify', 'change', 'edit',
|
|
90
|
+
]);
|
|
91
|
+
/**
|
|
92
|
+
* Keywords indicating full replacement operations
|
|
93
|
+
*/
|
|
94
|
+
export const FULL_REPLACEMENT_KEYWORDS = new Set([
|
|
95
|
+
'replace', 'set', 'overwrite', 'reset',
|
|
96
|
+
]);
|
|
97
|
+
/**
|
|
98
|
+
* Express/Fastify route handler patterns
|
|
99
|
+
*/
|
|
100
|
+
export const EXPRESS_METHOD_PATTERNS = [
|
|
101
|
+
// TypeScript/JavaScript patterns - Express/Fastify route handler (router.get, app.post)
|
|
102
|
+
/(?:router|app|server|fastify)\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/gi,
|
|
103
|
+
// router.route('/path').get(handler).post(handler)
|
|
104
|
+
/\.route\s*\(\s*['"`]([^'"`]+)['"`]\s*\)\s*\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
105
|
+
// Python patterns - FastAPI, Flask
|
|
106
|
+
/@(?:app|router)\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/gi,
|
|
107
|
+
/@api_view\s*\(\s*\[\s*['"`](GET|POST|PUT|PATCH|DELETE)['"`]/gi,
|
|
108
|
+
];
|
|
109
|
+
/**
|
|
110
|
+
* Next.js App Router method export patterns
|
|
111
|
+
*/
|
|
112
|
+
export const NEXTJS_METHOD_EXPORT_PATTERN = /export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s*\(/gi;
|
|
113
|
+
/**
|
|
114
|
+
* Fetch API method patterns
|
|
115
|
+
*/
|
|
116
|
+
export const FETCH_METHOD_PATTERNS = [
|
|
117
|
+
// fetch(url, { method: 'POST' }) - matches fetch with method option in config object
|
|
118
|
+
/fetch\s*\(\s*[^,]+,\s*\{[^}]*method\s*:\s*['"`](GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)['"`]/gi,
|
|
119
|
+
];
|
|
120
|
+
/**
|
|
121
|
+
* Axios method patterns
|
|
122
|
+
*/
|
|
123
|
+
export const AXIOS_METHOD_PATTERNS = [
|
|
124
|
+
// axios.get(url), axios.post(url, data)
|
|
125
|
+
/axios\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
126
|
+
// axios({ method: 'POST', url: ... })
|
|
127
|
+
/axios\s*\(\s*\{[^}]*method\s*:\s*['"`](GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)['"`]/gi,
|
|
128
|
+
// axios.request({ method: 'POST' })
|
|
129
|
+
/axios\.request\s*\(\s*\{[^}]*method\s*:\s*['"`](GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)['"`]/gi,
|
|
130
|
+
];
|
|
131
|
+
/**
|
|
132
|
+
* Generic HTTP client patterns
|
|
133
|
+
*/
|
|
134
|
+
export const HTTP_CLIENT_PATTERNS = [
|
|
135
|
+
// http.get, http.post, etc.
|
|
136
|
+
/(?:http|client|api)\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
137
|
+
// request({ method: 'POST' })
|
|
138
|
+
/request\s*\(\s*\{[^}]*method\s*:\s*['"`](GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)['"`]/gi,
|
|
139
|
+
// got.get, got.post, etc.
|
|
140
|
+
/got\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
141
|
+
// ky.get, ky.post, etc.
|
|
142
|
+
/ky\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
143
|
+
// superagent.get, superagent.post, etc.
|
|
144
|
+
/superagent\.(get|post|put|patch|delete|head|options)\s*\(/gi,
|
|
145
|
+
];
|
|
146
|
+
/**
|
|
147
|
+
* File patterns to exclude from detection
|
|
148
|
+
*/
|
|
149
|
+
export const EXCLUDED_FILE_PATTERNS = [
|
|
150
|
+
/\.test\.[jt]sx?$/,
|
|
151
|
+
/\.spec\.[jt]sx?$/,
|
|
152
|
+
/\.stories\.[jt]sx?$/,
|
|
153
|
+
/\.d\.ts$/,
|
|
154
|
+
/node_modules\//,
|
|
155
|
+
/\.mock\.[jt]sx?$/,
|
|
156
|
+
];
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Helper Functions
|
|
159
|
+
// ============================================================================
|
|
160
|
+
/**
|
|
161
|
+
* Check if a file should be excluded from detection
|
|
162
|
+
*/
|
|
163
|
+
export function shouldExcludeFile(filePath) {
|
|
164
|
+
return EXCLUDED_FILE_PATTERNS.some(pattern => pattern.test(filePath));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Normalize HTTP method to uppercase
|
|
168
|
+
*/
|
|
169
|
+
export function normalizeMethod(method) {
|
|
170
|
+
return method.toUpperCase();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if a method is a read method
|
|
174
|
+
*/
|
|
175
|
+
export function isReadMethod(method) {
|
|
176
|
+
return READ_METHODS.includes(method);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if a method is a mutation method
|
|
180
|
+
*/
|
|
181
|
+
export function isMutationMethod(method) {
|
|
182
|
+
return MUTATION_METHODS.includes(method);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Infer operation type from context (route path, function name, etc.)
|
|
186
|
+
*/
|
|
187
|
+
export function inferOperationType(context, routePath) {
|
|
188
|
+
const lowerContext = context.toLowerCase();
|
|
189
|
+
const lowerPath = routePath?.toLowerCase() || '';
|
|
190
|
+
// Check for delete operations
|
|
191
|
+
if (lowerContext.includes('delete') ||
|
|
192
|
+
lowerContext.includes('remove') ||
|
|
193
|
+
lowerContext.includes('destroy')) {
|
|
194
|
+
return 'delete';
|
|
195
|
+
}
|
|
196
|
+
// Check for create operations
|
|
197
|
+
if (lowerContext.includes('create') ||
|
|
198
|
+
lowerContext.includes('add') ||
|
|
199
|
+
lowerContext.includes('insert') ||
|
|
200
|
+
lowerContext.includes('new')) {
|
|
201
|
+
return 'create';
|
|
202
|
+
}
|
|
203
|
+
// Check for update operations
|
|
204
|
+
if (lowerContext.includes('update') ||
|
|
205
|
+
lowerContext.includes('edit') ||
|
|
206
|
+
lowerContext.includes('modify') ||
|
|
207
|
+
lowerContext.includes('patch') ||
|
|
208
|
+
lowerContext.includes('put')) {
|
|
209
|
+
return 'update';
|
|
210
|
+
}
|
|
211
|
+
// Check for read operations
|
|
212
|
+
for (const keyword of READ_OPERATION_KEYWORDS) {
|
|
213
|
+
if (lowerContext.includes(keyword) || lowerPath.includes(keyword)) {
|
|
214
|
+
return 'read';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return 'unknown';
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Check if position is inside a comment
|
|
221
|
+
*/
|
|
222
|
+
function isInsideComment(content, index) {
|
|
223
|
+
const beforeIndex = content.slice(0, index);
|
|
224
|
+
// Check for single-line comment
|
|
225
|
+
const lastNewline = beforeIndex.lastIndexOf('\n');
|
|
226
|
+
const currentLine = beforeIndex.slice(lastNewline + 1);
|
|
227
|
+
if (currentLine.includes('//')) {
|
|
228
|
+
const commentStart = currentLine.indexOf('//');
|
|
229
|
+
const positionInLine = index - lastNewline - 1;
|
|
230
|
+
if (positionInLine > commentStart) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Check for multi-line comment
|
|
235
|
+
const lastBlockCommentStart = beforeIndex.lastIndexOf('/*');
|
|
236
|
+
const lastBlockCommentEnd = beforeIndex.lastIndexOf('*/');
|
|
237
|
+
if (lastBlockCommentStart > lastBlockCommentEnd) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get line and column from index
|
|
244
|
+
*/
|
|
245
|
+
function getPositionFromIndex(content, index) {
|
|
246
|
+
const beforeMatch = content.slice(0, index);
|
|
247
|
+
const lineNumber = beforeMatch.split('\n').length;
|
|
248
|
+
const lastNewline = beforeMatch.lastIndexOf('\n');
|
|
249
|
+
const column = index - lastNewline;
|
|
250
|
+
return { line: lineNumber, column };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Detect Express/Fastify route handlers
|
|
254
|
+
*/
|
|
255
|
+
export function detectExpressHandlers(content, file) {
|
|
256
|
+
const results = [];
|
|
257
|
+
const lines = content.split('\n');
|
|
258
|
+
for (const pattern of EXPRESS_METHOD_PATTERNS) {
|
|
259
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
260
|
+
let match;
|
|
261
|
+
while ((match = regex.exec(content)) !== null) {
|
|
262
|
+
if (isInsideComment(content, match.index)) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const { line, column } = getPositionFromIndex(content, match.index);
|
|
266
|
+
// Handle different capture group orders
|
|
267
|
+
let method;
|
|
268
|
+
let routePath;
|
|
269
|
+
if (pattern.source.includes('\\.route')) {
|
|
270
|
+
// .route('/path').get() pattern - path is first, method is second
|
|
271
|
+
routePath = match[1];
|
|
272
|
+
method = match[2] || 'GET';
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// router.get('/path') pattern - method is first, path is second
|
|
276
|
+
method = match[1] || 'GET';
|
|
277
|
+
routePath = match[2];
|
|
278
|
+
}
|
|
279
|
+
const normalizedMethod = normalizeMethod(method);
|
|
280
|
+
const lineContent = lines[line - 1] || '';
|
|
281
|
+
results.push({
|
|
282
|
+
type: 'express-handler',
|
|
283
|
+
method: normalizedMethod,
|
|
284
|
+
file,
|
|
285
|
+
line,
|
|
286
|
+
column,
|
|
287
|
+
matchedText: match[0],
|
|
288
|
+
routePath,
|
|
289
|
+
operationType: inferOperationType(lineContent, routePath),
|
|
290
|
+
context: lineContent,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return results;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Detect Next.js App Router method exports
|
|
298
|
+
*/
|
|
299
|
+
export function detectNextjsMethodExports(content, file) {
|
|
300
|
+
const results = [];
|
|
301
|
+
const lines = content.split('\n');
|
|
302
|
+
// Only check files that look like Next.js route files
|
|
303
|
+
if (!file.includes('/app/') && !file.includes('\\app\\')) {
|
|
304
|
+
return results;
|
|
305
|
+
}
|
|
306
|
+
const regex = new RegExp(NEXTJS_METHOD_EXPORT_PATTERN.source, NEXTJS_METHOD_EXPORT_PATTERN.flags);
|
|
307
|
+
let match;
|
|
308
|
+
while ((match = regex.exec(content)) !== null) {
|
|
309
|
+
if (isInsideComment(content, match.index)) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const { line, column } = getPositionFromIndex(content, match.index);
|
|
313
|
+
const method = normalizeMethod(match[1] || 'GET');
|
|
314
|
+
const lineContent = lines[line - 1] || '';
|
|
315
|
+
// Infer route path from file path
|
|
316
|
+
const routeMatch = file.match(/\/app(\/(?:api\/)?[^/]+(?:\/[^/]+)*?)\/route\.[jt]sx?$/);
|
|
317
|
+
const routePath = routeMatch ? routeMatch[1] : undefined;
|
|
318
|
+
results.push({
|
|
319
|
+
type: 'nextjs-app-router',
|
|
320
|
+
method,
|
|
321
|
+
file,
|
|
322
|
+
line,
|
|
323
|
+
column,
|
|
324
|
+
matchedText: match[0],
|
|
325
|
+
routePath,
|
|
326
|
+
operationType: inferOperationType(lineContent, routePath),
|
|
327
|
+
context: lineContent,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return results;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Detect Fetch API method usage
|
|
334
|
+
*/
|
|
335
|
+
export function detectFetchApiUsage(content, file) {
|
|
336
|
+
const results = [];
|
|
337
|
+
const lines = content.split('\n');
|
|
338
|
+
for (const pattern of FETCH_METHOD_PATTERNS) {
|
|
339
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
340
|
+
let match;
|
|
341
|
+
while ((match = regex.exec(content)) !== null) {
|
|
342
|
+
if (isInsideComment(content, match.index)) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const { line, column } = getPositionFromIndex(content, match.index);
|
|
346
|
+
const method = normalizeMethod(match[1] || 'GET');
|
|
347
|
+
const lineContent = lines[line - 1] || '';
|
|
348
|
+
results.push({
|
|
349
|
+
type: 'fetch-api',
|
|
350
|
+
method,
|
|
351
|
+
file,
|
|
352
|
+
line,
|
|
353
|
+
column,
|
|
354
|
+
matchedText: match[0],
|
|
355
|
+
operationType: inferOperationType(lineContent),
|
|
356
|
+
context: lineContent,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return results;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Detect Axios method usage
|
|
364
|
+
*/
|
|
365
|
+
export function detectAxiosUsage(content, file) {
|
|
366
|
+
const results = [];
|
|
367
|
+
const lines = content.split('\n');
|
|
368
|
+
for (const pattern of AXIOS_METHOD_PATTERNS) {
|
|
369
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
370
|
+
let match;
|
|
371
|
+
while ((match = regex.exec(content)) !== null) {
|
|
372
|
+
if (isInsideComment(content, match.index)) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
const { line, column } = getPositionFromIndex(content, match.index);
|
|
376
|
+
const method = normalizeMethod(match[1] || 'GET');
|
|
377
|
+
const lineContent = lines[line - 1] || '';
|
|
378
|
+
results.push({
|
|
379
|
+
type: 'axios-method',
|
|
380
|
+
method,
|
|
381
|
+
file,
|
|
382
|
+
line,
|
|
383
|
+
column,
|
|
384
|
+
matchedText: match[0],
|
|
385
|
+
operationType: inferOperationType(lineContent),
|
|
386
|
+
context: lineContent,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return results;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Detect generic HTTP client usage
|
|
394
|
+
*/
|
|
395
|
+
export function detectHttpClientUsage(content, file) {
|
|
396
|
+
const results = [];
|
|
397
|
+
const lines = content.split('\n');
|
|
398
|
+
for (const pattern of HTTP_CLIENT_PATTERNS) {
|
|
399
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
400
|
+
let match;
|
|
401
|
+
while ((match = regex.exec(content)) !== null) {
|
|
402
|
+
if (isInsideComment(content, match.index)) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const { line, column } = getPositionFromIndex(content, match.index);
|
|
406
|
+
const method = normalizeMethod(match[1] || 'GET');
|
|
407
|
+
const lineContent = lines[line - 1] || '';
|
|
408
|
+
results.push({
|
|
409
|
+
type: 'http-client',
|
|
410
|
+
method,
|
|
411
|
+
file,
|
|
412
|
+
line,
|
|
413
|
+
column,
|
|
414
|
+
matchedText: match[0],
|
|
415
|
+
operationType: inferOperationType(lineContent),
|
|
416
|
+
context: lineContent,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return results;
|
|
421
|
+
}
|
|
422
|
+
// ============================================================================
|
|
423
|
+
// Violation Detection Functions
|
|
424
|
+
// ============================================================================
|
|
425
|
+
/**
|
|
426
|
+
* Detect POST used for read operations
|
|
427
|
+
*/
|
|
428
|
+
export function detectPostForReadViolations(methodUsages, file) {
|
|
429
|
+
const violations = [];
|
|
430
|
+
for (const usage of methodUsages) {
|
|
431
|
+
if (usage.method !== 'POST')
|
|
432
|
+
continue;
|
|
433
|
+
const context = (usage.context || '').toLowerCase();
|
|
434
|
+
const routePath = (usage.routePath || '').toLowerCase();
|
|
435
|
+
// Check if this looks like a read operation
|
|
436
|
+
let isReadOperation = false;
|
|
437
|
+
for (const keyword of READ_OPERATION_KEYWORDS) {
|
|
438
|
+
if (context.includes(keyword) || routePath.includes(keyword)) {
|
|
439
|
+
isReadOperation = true;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// Also check for common read patterns in route paths
|
|
444
|
+
if (routePath.includes('/search') ||
|
|
445
|
+
routePath.includes('/find') ||
|
|
446
|
+
routePath.includes('/list') ||
|
|
447
|
+
routePath.includes('/query')) {
|
|
448
|
+
isReadOperation = true;
|
|
449
|
+
}
|
|
450
|
+
if (isReadOperation) {
|
|
451
|
+
violations.push({
|
|
452
|
+
type: 'post-for-read',
|
|
453
|
+
file,
|
|
454
|
+
line: usage.line,
|
|
455
|
+
column: usage.column,
|
|
456
|
+
endLine: usage.line,
|
|
457
|
+
endColumn: usage.column + usage.matchedText.length,
|
|
458
|
+
method: usage.method,
|
|
459
|
+
issue: `Using POST for read operation. Consider using GET for idempotent read operations.`,
|
|
460
|
+
suggestedFix: 'Use GET method for read operations',
|
|
461
|
+
suggestedMethod: 'GET',
|
|
462
|
+
lineContent: usage.context || '',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return violations;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Detect GET used for mutation operations
|
|
470
|
+
*/
|
|
471
|
+
export function detectGetForMutationViolations(methodUsages, file) {
|
|
472
|
+
const violations = [];
|
|
473
|
+
for (const usage of methodUsages) {
|
|
474
|
+
if (usage.method !== 'GET')
|
|
475
|
+
continue;
|
|
476
|
+
const context = (usage.context || '').toLowerCase();
|
|
477
|
+
const routePath = (usage.routePath || '').toLowerCase();
|
|
478
|
+
// Check if this looks like a mutation operation
|
|
479
|
+
let isMutationOperation = false;
|
|
480
|
+
let suggestedMethod = 'POST';
|
|
481
|
+
// Check for delete operations
|
|
482
|
+
if (context.includes('delete') ||
|
|
483
|
+
context.includes('remove') ||
|
|
484
|
+
routePath.includes('/delete') ||
|
|
485
|
+
routePath.includes('/remove')) {
|
|
486
|
+
isMutationOperation = true;
|
|
487
|
+
suggestedMethod = 'DELETE';
|
|
488
|
+
}
|
|
489
|
+
// Check for create operations
|
|
490
|
+
else if (context.includes('create') ||
|
|
491
|
+
context.includes('add') ||
|
|
492
|
+
context.includes('insert') ||
|
|
493
|
+
routePath.includes('/create') ||
|
|
494
|
+
routePath.includes('/add')) {
|
|
495
|
+
isMutationOperation = true;
|
|
496
|
+
suggestedMethod = 'POST';
|
|
497
|
+
}
|
|
498
|
+
// Check for update operations
|
|
499
|
+
else if (context.includes('update') ||
|
|
500
|
+
context.includes('edit') ||
|
|
501
|
+
context.includes('modify') ||
|
|
502
|
+
routePath.includes('/update') ||
|
|
503
|
+
routePath.includes('/edit')) {
|
|
504
|
+
isMutationOperation = true;
|
|
505
|
+
suggestedMethod = 'PATCH';
|
|
506
|
+
}
|
|
507
|
+
if (isMutationOperation) {
|
|
508
|
+
violations.push({
|
|
509
|
+
type: 'get-for-mutation',
|
|
510
|
+
file,
|
|
511
|
+
line: usage.line,
|
|
512
|
+
column: usage.column,
|
|
513
|
+
endLine: usage.line,
|
|
514
|
+
endColumn: usage.column + usage.matchedText.length,
|
|
515
|
+
method: usage.method,
|
|
516
|
+
issue: `Using GET for mutation operation. GET requests should be idempotent and not modify server state.`,
|
|
517
|
+
suggestedFix: `Use ${suggestedMethod} method for this operation`,
|
|
518
|
+
suggestedMethod,
|
|
519
|
+
lineContent: usage.context || '',
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return violations;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Detect PUT used when PATCH is more appropriate
|
|
527
|
+
*/
|
|
528
|
+
export function detectPutForPartialUpdateViolations(methodUsages, file) {
|
|
529
|
+
const violations = [];
|
|
530
|
+
for (const usage of methodUsages) {
|
|
531
|
+
if (usage.method !== 'PUT')
|
|
532
|
+
continue;
|
|
533
|
+
const context = (usage.context || '').toLowerCase();
|
|
534
|
+
const routePath = (usage.routePath || '').toLowerCase();
|
|
535
|
+
// Check if this looks like a partial update operation
|
|
536
|
+
let isPartialUpdate = false;
|
|
537
|
+
for (const keyword of PARTIAL_UPDATE_KEYWORDS) {
|
|
538
|
+
if (context.includes(keyword) && !context.includes('replace')) {
|
|
539
|
+
isPartialUpdate = true;
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// Check route path for partial update indicators
|
|
544
|
+
if (routePath.includes('/patch') ||
|
|
545
|
+
routePath.includes('/partial') ||
|
|
546
|
+
(routePath.includes('/update') && !routePath.includes('/replace'))) {
|
|
547
|
+
isPartialUpdate = true;
|
|
548
|
+
}
|
|
549
|
+
// Check for full replacement indicators (these are OK with PUT)
|
|
550
|
+
for (const keyword of FULL_REPLACEMENT_KEYWORDS) {
|
|
551
|
+
if (context.includes(keyword) || routePath.includes(keyword)) {
|
|
552
|
+
isPartialUpdate = false;
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (isPartialUpdate) {
|
|
557
|
+
violations.push({
|
|
558
|
+
type: 'put-for-partial',
|
|
559
|
+
file,
|
|
560
|
+
line: usage.line,
|
|
561
|
+
column: usage.column,
|
|
562
|
+
endLine: usage.line,
|
|
563
|
+
endColumn: usage.column + usage.matchedText.length,
|
|
564
|
+
method: usage.method,
|
|
565
|
+
issue: `Using PUT for partial update. PUT should replace the entire resource; use PATCH for partial updates.`,
|
|
566
|
+
suggestedFix: 'Use PATCH method for partial updates',
|
|
567
|
+
suggestedMethod: 'PATCH',
|
|
568
|
+
lineContent: usage.context || '',
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return violations;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Detect inconsistent method usage across similar endpoints
|
|
576
|
+
*/
|
|
577
|
+
export function detectInconsistentMethodUsage(methodUsages, file) {
|
|
578
|
+
const violations = [];
|
|
579
|
+
// Group usages by operation type
|
|
580
|
+
const operationGroups = new Map();
|
|
581
|
+
for (const usage of methodUsages) {
|
|
582
|
+
if (usage.operationType && usage.operationType !== 'unknown') {
|
|
583
|
+
const existing = operationGroups.get(usage.operationType) || [];
|
|
584
|
+
existing.push(usage);
|
|
585
|
+
operationGroups.set(usage.operationType, existing);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Check for inconsistencies within each operation type
|
|
589
|
+
for (const [operationType, usages] of operationGroups) {
|
|
590
|
+
if (usages.length < 2)
|
|
591
|
+
continue;
|
|
592
|
+
const methodCounts = new Map();
|
|
593
|
+
for (const usage of usages) {
|
|
594
|
+
methodCounts.set(usage.method, (methodCounts.get(usage.method) || 0) + 1);
|
|
595
|
+
}
|
|
596
|
+
// Find the dominant method
|
|
597
|
+
let dominantMethod = null;
|
|
598
|
+
let maxCount = 0;
|
|
599
|
+
for (const [method, count] of methodCounts) {
|
|
600
|
+
if (count > maxCount) {
|
|
601
|
+
maxCount = count;
|
|
602
|
+
dominantMethod = method;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
// Flag usages that don't match the dominant method
|
|
606
|
+
if (dominantMethod && methodCounts.size > 1) {
|
|
607
|
+
for (const usage of usages) {
|
|
608
|
+
if (usage.method !== dominantMethod) {
|
|
609
|
+
violations.push({
|
|
610
|
+
type: 'inconsistent-method',
|
|
611
|
+
file,
|
|
612
|
+
line: usage.line,
|
|
613
|
+
column: usage.column,
|
|
614
|
+
endLine: usage.line,
|
|
615
|
+
endColumn: usage.column + usage.matchedText.length,
|
|
616
|
+
method: usage.method,
|
|
617
|
+
issue: `Inconsistent HTTP method for ${operationType} operation. Most ${operationType} operations use ${dominantMethod}.`,
|
|
618
|
+
suggestedFix: `Consider using ${dominantMethod} for consistency`,
|
|
619
|
+
suggestedMethod: dominantMethod,
|
|
620
|
+
lineContent: usage.context || '',
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return violations;
|
|
627
|
+
}
|
|
628
|
+
// ============================================================================
|
|
629
|
+
// Main Analysis Function
|
|
630
|
+
// ============================================================================
|
|
631
|
+
/**
|
|
632
|
+
* Analyze HTTP method patterns in a file
|
|
633
|
+
*/
|
|
634
|
+
export function analyzeHttpMethods(content, file) {
|
|
635
|
+
// Skip excluded files
|
|
636
|
+
if (shouldExcludeFile(file)) {
|
|
637
|
+
return {
|
|
638
|
+
methodUsages: [],
|
|
639
|
+
violations: [],
|
|
640
|
+
methodsUsed: new Set(),
|
|
641
|
+
usesRestfulConventions: true,
|
|
642
|
+
patternAdherenceConfidence: 1.0,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
// Detect all HTTP method usages
|
|
646
|
+
const expressHandlers = detectExpressHandlers(content, file);
|
|
647
|
+
const nextjsExports = detectNextjsMethodExports(content, file);
|
|
648
|
+
const fetchUsages = detectFetchApiUsage(content, file);
|
|
649
|
+
const axiosUsages = detectAxiosUsage(content, file);
|
|
650
|
+
const httpClientUsages = detectHttpClientUsage(content, file);
|
|
651
|
+
const methodUsages = [
|
|
652
|
+
...expressHandlers,
|
|
653
|
+
...nextjsExports,
|
|
654
|
+
...fetchUsages,
|
|
655
|
+
...axiosUsages,
|
|
656
|
+
...httpClientUsages,
|
|
657
|
+
];
|
|
658
|
+
// Collect all methods used
|
|
659
|
+
const methodsUsed = new Set();
|
|
660
|
+
for (const usage of methodUsages) {
|
|
661
|
+
methodsUsed.add(usage.method);
|
|
662
|
+
}
|
|
663
|
+
// Detect violations
|
|
664
|
+
const postForReadViolations = detectPostForReadViolations(methodUsages, file);
|
|
665
|
+
const getForMutationViolations = detectGetForMutationViolations(methodUsages, file);
|
|
666
|
+
const putForPartialViolations = detectPutForPartialUpdateViolations(methodUsages, file);
|
|
667
|
+
const inconsistentViolations = detectInconsistentMethodUsage(methodUsages, file);
|
|
668
|
+
const violations = [
|
|
669
|
+
...postForReadViolations,
|
|
670
|
+
...getForMutationViolations,
|
|
671
|
+
...putForPartialViolations,
|
|
672
|
+
...inconsistentViolations,
|
|
673
|
+
];
|
|
674
|
+
// Determine if file uses RESTful conventions
|
|
675
|
+
const usesRestfulConventions = violations.length === 0 && methodUsages.length > 0;
|
|
676
|
+
// Calculate confidence
|
|
677
|
+
let patternAdherenceConfidence = 1.0;
|
|
678
|
+
if (methodUsages.length > 0 && violations.length > 0) {
|
|
679
|
+
patternAdherenceConfidence = Math.max(0, 1 - (violations.length / methodUsages.length));
|
|
680
|
+
}
|
|
681
|
+
else if (methodUsages.length === 0) {
|
|
682
|
+
patternAdherenceConfidence = 0.5; // No HTTP methods detected
|
|
683
|
+
}
|
|
684
|
+
return {
|
|
685
|
+
methodUsages,
|
|
686
|
+
violations,
|
|
687
|
+
methodsUsed,
|
|
688
|
+
usesRestfulConventions,
|
|
689
|
+
patternAdherenceConfidence,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
// ============================================================================
|
|
693
|
+
// HTTP Methods Detector Class
|
|
694
|
+
// ============================================================================
|
|
695
|
+
/**
|
|
696
|
+
* Detector for HTTP method usage patterns
|
|
697
|
+
*
|
|
698
|
+
* Identifies HTTP method usage patterns and flags violations of RESTful conventions.
|
|
699
|
+
*
|
|
700
|
+
* @requirements 10.2 - THE API_Detector SHALL detect HTTP method usage patterns (POST vs PUT vs PATCH)
|
|
701
|
+
*/
|
|
702
|
+
export class HttpMethodsDetector extends RegexDetector {
|
|
703
|
+
id = 'api/http-methods';
|
|
704
|
+
category = 'api';
|
|
705
|
+
subcategory = 'http-methods';
|
|
706
|
+
name = 'HTTP Methods Detector';
|
|
707
|
+
description = 'Detects HTTP method usage patterns and flags RESTful convention violations';
|
|
708
|
+
supportedLanguages = ['typescript', 'javascript', 'python'];
|
|
709
|
+
/**
|
|
710
|
+
* Detect HTTP method patterns and violations
|
|
711
|
+
*/
|
|
712
|
+
async detect(context) {
|
|
713
|
+
const patterns = [];
|
|
714
|
+
const violations = [];
|
|
715
|
+
// Analyze the file
|
|
716
|
+
const analysis = analyzeHttpMethods(context.content, context.file);
|
|
717
|
+
// Create pattern matches for method usages by type
|
|
718
|
+
const patternTypes = new Set(analysis.methodUsages.map(u => u.type));
|
|
719
|
+
for (const patternType of patternTypes) {
|
|
720
|
+
const firstOfType = analysis.methodUsages.find(u => u.type === patternType);
|
|
721
|
+
if (firstOfType) {
|
|
722
|
+
patterns.push({
|
|
723
|
+
patternId: `${this.id}/${patternType}`,
|
|
724
|
+
location: {
|
|
725
|
+
file: context.file,
|
|
726
|
+
line: firstOfType.line,
|
|
727
|
+
column: firstOfType.column,
|
|
728
|
+
},
|
|
729
|
+
confidence: 1.0,
|
|
730
|
+
isOutlier: false,
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
// Create pattern matches for each HTTP method used
|
|
735
|
+
for (const method of analysis.methodsUsed) {
|
|
736
|
+
const firstUsage = analysis.methodUsages.find(u => u.method === method);
|
|
737
|
+
if (firstUsage) {
|
|
738
|
+
patterns.push({
|
|
739
|
+
patternId: `${this.id}/method-${method.toLowerCase()}`,
|
|
740
|
+
location: {
|
|
741
|
+
file: context.file,
|
|
742
|
+
line: firstUsage.line,
|
|
743
|
+
column: firstUsage.column,
|
|
744
|
+
},
|
|
745
|
+
confidence: 1.0,
|
|
746
|
+
isOutlier: false,
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// Create violations
|
|
751
|
+
for (const violation of analysis.violations) {
|
|
752
|
+
violations.push(this.createViolation(violation));
|
|
753
|
+
}
|
|
754
|
+
return this.createResult(patterns, violations, analysis.patternAdherenceConfidence);
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Create a Violation from HttpMethodViolationInfo
|
|
758
|
+
*/
|
|
759
|
+
createViolation(info) {
|
|
760
|
+
const severityMap = {
|
|
761
|
+
'post-for-read': 'warning',
|
|
762
|
+
'get-for-mutation': 'error',
|
|
763
|
+
'put-for-partial': 'info',
|
|
764
|
+
'inconsistent-method': 'info',
|
|
765
|
+
'missing-method-handler': 'info',
|
|
766
|
+
'non-restful-method': 'warning',
|
|
767
|
+
};
|
|
768
|
+
const violation = {
|
|
769
|
+
id: `${this.id}-${info.file}-${info.line}-${info.column}`,
|
|
770
|
+
patternId: this.id,
|
|
771
|
+
severity: severityMap[info.type] || 'warning',
|
|
772
|
+
file: info.file,
|
|
773
|
+
range: {
|
|
774
|
+
start: { line: info.line - 1, character: info.column - 1 },
|
|
775
|
+
end: { line: info.endLine - 1, character: info.endColumn - 1 },
|
|
776
|
+
},
|
|
777
|
+
message: info.issue,
|
|
778
|
+
explanation: this.getExplanation(info.type),
|
|
779
|
+
expected: info.suggestedMethod || 'Appropriate HTTP method',
|
|
780
|
+
actual: info.method,
|
|
781
|
+
aiExplainAvailable: true,
|
|
782
|
+
aiFixAvailable: !!info.suggestedMethod,
|
|
783
|
+
firstSeen: new Date(),
|
|
784
|
+
occurrences: 1,
|
|
785
|
+
};
|
|
786
|
+
if (info.suggestedMethod) {
|
|
787
|
+
const quickFix = this.createQuickFixForViolation(info);
|
|
788
|
+
if (quickFix) {
|
|
789
|
+
violation.quickFix = quickFix;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return violation;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Get explanation for a violation type
|
|
796
|
+
*/
|
|
797
|
+
getExplanation(type) {
|
|
798
|
+
const explanations = {
|
|
799
|
+
'post-for-read': 'GET requests are idempotent and cacheable, making them ideal for read operations. ' +
|
|
800
|
+
'Using POST for reads prevents caching and violates REST conventions. ' +
|
|
801
|
+
'Exception: Complex queries with large payloads may use POST.',
|
|
802
|
+
'get-for-mutation': 'GET requests should be safe and idempotent - they should not modify server state. ' +
|
|
803
|
+
'Using GET for mutations can cause unintended side effects from browser prefetching, ' +
|
|
804
|
+
'link crawlers, and cached responses.',
|
|
805
|
+
'put-for-partial': 'PUT is intended to replace an entire resource. For partial updates, use PATCH. ' +
|
|
806
|
+
'This follows REST semantics and makes the API behavior more predictable.',
|
|
807
|
+
'inconsistent-method': 'Using different HTTP methods for similar operations makes the API harder to understand. ' +
|
|
808
|
+
'Consistent method usage improves API discoverability and reduces errors.',
|
|
809
|
+
'missing-method-handler': 'Common CRUD operations should have corresponding HTTP method handlers. ' +
|
|
810
|
+
'Missing handlers may indicate incomplete API implementation.',
|
|
811
|
+
'non-restful-method': 'RESTful APIs use HTTP methods to indicate the action being performed. ' +
|
|
812
|
+
'Using verbs in URLs or non-standard methods reduces API clarity.',
|
|
813
|
+
};
|
|
814
|
+
return explanations[type] || 'Follow RESTful HTTP method conventions for consistency.';
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Create a quick fix for a violation
|
|
818
|
+
*/
|
|
819
|
+
createQuickFixForViolation(info) {
|
|
820
|
+
if (!info.suggestedMethod) {
|
|
821
|
+
return undefined;
|
|
822
|
+
}
|
|
823
|
+
// Determine the replacement text based on the pattern
|
|
824
|
+
const oldMethod = info.method.toLowerCase();
|
|
825
|
+
const newMethod = info.suggestedMethod.toLowerCase();
|
|
826
|
+
// Create a replacement that changes the method in the matched text
|
|
827
|
+
const newText = info.lineContent.replace(new RegExp(`\\b${oldMethod}\\b`, 'i'), newMethod);
|
|
828
|
+
return {
|
|
829
|
+
title: `Change HTTP method from ${info.method} to ${info.suggestedMethod}`,
|
|
830
|
+
kind: 'quickfix',
|
|
831
|
+
edit: {
|
|
832
|
+
changes: {
|
|
833
|
+
[info.file]: [
|
|
834
|
+
{
|
|
835
|
+
range: {
|
|
836
|
+
start: { line: info.line - 1, character: 0 },
|
|
837
|
+
end: { line: info.line - 1, character: info.lineContent.length },
|
|
838
|
+
},
|
|
839
|
+
newText,
|
|
840
|
+
},
|
|
841
|
+
],
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
isPreferred: true,
|
|
845
|
+
confidence: 0.7,
|
|
846
|
+
preview: `Replace '${info.method}' with '${info.suggestedMethod}'`,
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Generate a quick fix for a violation
|
|
851
|
+
*/
|
|
852
|
+
generateQuickFix(violation) {
|
|
853
|
+
// Check if this is an HTTP method violation
|
|
854
|
+
if (!violation.patternId.startsWith('api/http-methods')) {
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
// Extract the suggested method from the expected field
|
|
858
|
+
const suggestedMethod = violation.expected;
|
|
859
|
+
if (!suggestedMethod || !HTTP_METHODS.includes(suggestedMethod)) {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
return {
|
|
863
|
+
title: `Change HTTP method to ${suggestedMethod}`,
|
|
864
|
+
kind: 'quickfix',
|
|
865
|
+
edit: {
|
|
866
|
+
changes: {
|
|
867
|
+
[violation.file]: [
|
|
868
|
+
{
|
|
869
|
+
range: violation.range,
|
|
870
|
+
newText: suggestedMethod,
|
|
871
|
+
},
|
|
872
|
+
],
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
isPreferred: true,
|
|
876
|
+
confidence: 0.7,
|
|
877
|
+
preview: `Replace '${violation.actual}' with '${suggestedMethod}'`,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
// ============================================================================
|
|
882
|
+
// Factory Function
|
|
883
|
+
// ============================================================================
|
|
884
|
+
/**
|
|
885
|
+
* Create a new HttpMethodsDetector instance
|
|
886
|
+
*/
|
|
887
|
+
export function createHttpMethodsDetector() {
|
|
888
|
+
return new HttpMethodsDetector();
|
|
889
|
+
}
|
|
890
|
+
//# sourceMappingURL=http-methods.js.map
|