@opensip-cli/checks-typescript 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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/all-checks-execute.test.d.ts +12 -0
- package/dist/__tests__/all-checks-execute.test.d.ts.map +1 -0
- package/dist/__tests__/all-checks-execute.test.js +846 -0
- package/dist/__tests__/all-checks-execute.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts +9 -0
- package/dist/__tests__/behavior-fixtures-2.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-2.test.js +625 -0
- package/dist/__tests__/behavior-fixtures-2.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts +7 -0
- package/dist/__tests__/behavior-fixtures-3.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-3.test.js +658 -0
- package/dist/__tests__/behavior-fixtures-3.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts +8 -0
- package/dist/__tests__/behavior-fixtures-4.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-4.test.js +590 -0
- package/dist/__tests__/behavior-fixtures-4.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts +7 -0
- package/dist/__tests__/behavior-fixtures-5.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-5.test.js +548 -0
- package/dist/__tests__/behavior-fixtures-5.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts +18 -0
- package/dist/__tests__/behavior-fixtures-6.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures-6.test.js +1700 -0
- package/dist/__tests__/behavior-fixtures-6.test.js.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts +10 -0
- package/dist/__tests__/behavior-fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-fixtures.test.js +812 -0
- package/dist/__tests__/behavior-fixtures.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures-2.test.d.ts +6 -0
- package/dist/__tests__/branch-fixtures-2.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures-2.test.js +1369 -0
- package/dist/__tests__/branch-fixtures-2.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures-3.test.d.ts +7 -0
- package/dist/__tests__/branch-fixtures-3.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures-3.test.js +877 -0
- package/dist/__tests__/branch-fixtures-3.test.js.map +1 -0
- package/dist/__tests__/branch-fixtures.test.d.ts +6 -0
- package/dist/__tests__/branch-fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/branch-fixtures.test.js +1072 -0
- package/dist/__tests__/branch-fixtures.test.js.map +1 -0
- package/dist/__tests__/checks.test.d.ts +2 -0
- package/dist/__tests__/checks.test.d.ts.map +1 -0
- package/dist/__tests__/checks.test.js +39 -0
- package/dist/__tests__/checks.test.js.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts +19 -0
- package/dist/__tests__/fixture-coverage.allowlist.d.ts.map +1 -0
- package/dist/__tests__/fixture-coverage.allowlist.js +27 -0
- package/dist/__tests__/fixture-coverage.allowlist.js.map +1 -0
- package/dist/__tests__/fixture-coverage.test.d.ts +13 -0
- package/dist/__tests__/fixture-coverage.test.d.ts.map +1 -0
- package/dist/__tests__/fixture-coverage.test.js +57 -0
- package/dist/__tests__/fixture-coverage.test.js.map +1 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.d.ts +2 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.d.ts.map +1 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.js +75 -0
- package/dist/__tests__/no-bootstrap-tool-import.test.js.map +1 -0
- package/dist/__tests__/phantom-dependency-detection.test.d.ts +12 -0
- package/dist/__tests__/phantom-dependency-detection.test.d.ts.map +1 -0
- package/dist/__tests__/phantom-dependency-detection.test.js +112 -0
- package/dist/__tests__/phantom-dependency-detection.test.js.map +1 -0
- package/dist/__tests__/typescript-frontend.test.d.ts +8 -0
- package/dist/__tests__/typescript-frontend.test.d.ts.map +1 -0
- package/dist/__tests__/typescript-frontend.test.js +57 -0
- package/dist/__tests__/typescript-frontend.test.js.map +1 -0
- package/dist/checks/architecture/circular-import-detection.d.ts +14 -0
- package/dist/checks/architecture/circular-import-detection.d.ts.map +1 -0
- package/dist/checks/architecture/circular-import-detection.js +55 -0
- package/dist/checks/architecture/circular-import-detection.js.map +1 -0
- package/dist/checks/architecture/contracts-schema-consistency.d.ts +11 -0
- package/dist/checks/architecture/contracts-schema-consistency.d.ts.map +1 -0
- package/dist/checks/architecture/contracts-schema-consistency.js +75 -0
- package/dist/checks/architecture/contracts-schema-consistency.js.map +1 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts +12 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.d.ts.map +1 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.js +92 -0
- package/dist/checks/architecture/drizzle-orm-migration-guardrails.js.map +1 -0
- package/dist/checks/architecture/index.d.ts +10 -0
- package/dist/checks/architecture/index.d.ts.map +1 -0
- package/dist/checks/architecture/index.js +10 -0
- package/dist/checks/architecture/index.js.map +1 -0
- package/dist/checks/architecture/missing-type-exports.d.ts +13 -0
- package/dist/checks/architecture/missing-type-exports.d.ts.map +1 -0
- package/dist/checks/architecture/missing-type-exports.js +245 -0
- package/dist/checks/architecture/missing-type-exports.js.map +1 -0
- package/dist/checks/architecture/module-coupling-fan-out.d.ts +20 -0
- package/dist/checks/architecture/module-coupling-fan-out.d.ts.map +1 -0
- package/dist/checks/architecture/module-coupling-fan-out.js +120 -0
- package/dist/checks/architecture/module-coupling-fan-out.js.map +1 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.d.ts +38 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.d.ts.map +1 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.js +95 -0
- package/dist/checks/architecture/no-bootstrap-tool-import.js.map +1 -0
- package/dist/checks/architecture/package-json-exports-field.d.ts +10 -0
- package/dist/checks/architecture/package-json-exports-field.d.ts.map +1 -0
- package/dist/checks/architecture/package-json-exports-field.js +56 -0
- package/dist/checks/architecture/package-json-exports-field.js.map +1 -0
- package/dist/checks/architecture/phantom-dependency-detection.d.ts +22 -0
- package/dist/checks/architecture/phantom-dependency-detection.d.ts.map +1 -0
- package/dist/checks/architecture/phantom-dependency-detection.js +330 -0
- package/dist/checks/architecture/phantom-dependency-detection.js.map +1 -0
- package/dist/checks/architecture/tsconfig-extends-validation.d.ts +10 -0
- package/dist/checks/architecture/tsconfig-extends-validation.d.ts.map +1 -0
- package/dist/checks/architecture/tsconfig-extends-validation.js +78 -0
- package/dist/checks/architecture/tsconfig-extends-validation.js.map +1 -0
- package/dist/checks/index.d.ts +6 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +6 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/quality/api/api-contract-validation.d.ts +15 -0
- package/dist/checks/quality/api/api-contract-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/api-contract-validation.js +316 -0
- package/dist/checks/quality/api/api-contract-validation.js.map +1 -0
- package/dist/checks/quality/api/api-response-validation.d.ts +14 -0
- package/dist/checks/quality/api/api-response-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/api-response-validation.js +209 -0
- package/dist/checks/quality/api/api-response-validation.js.map +1 -0
- package/dist/checks/quality/api/fastify-route-validation.d.ts +14 -0
- package/dist/checks/quality/api/fastify-route-validation.d.ts.map +1 -0
- package/dist/checks/quality/api/fastify-route-validation.js +298 -0
- package/dist/checks/quality/api/fastify-route-validation.js.map +1 -0
- package/dist/checks/quality/api/fastify-schema-coverage.d.ts +11 -0
- package/dist/checks/quality/api/fastify-schema-coverage.d.ts.map +1 -0
- package/dist/checks/quality/api/fastify-schema-coverage.js +261 -0
- package/dist/checks/quality/api/fastify-schema-coverage.js.map +1 -0
- package/dist/checks/quality/api/index.d.ts +5 -0
- package/dist/checks/quality/api/index.d.ts.map +1 -0
- package/dist/checks/quality/api/index.js +5 -0
- package/dist/checks/quality/api/index.js.map +1 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts +32 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.js +451 -0
- package/dist/checks/quality/code-structure/duplicate-utility-functions.js.map +1 -0
- package/dist/checks/quality/code-structure/index.d.ts +3 -0
- package/dist/checks/quality/code-structure/index.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/index.js +3 -0
- package/dist/checks/quality/code-structure/index.js.map +1 -0
- package/dist/checks/quality/code-structure/no-any-types.d.ts +13 -0
- package/dist/checks/quality/code-structure/no-any-types.d.ts.map +1 -0
- package/dist/checks/quality/code-structure/no-any-types.js +116 -0
- package/dist/checks/quality/code-structure/no-any-types.js.map +1 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts +15 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js +51 -0
- package/dist/checks/quality/data-integrity/__tests__/null-safety-fp.test.js.map +1 -0
- package/dist/checks/quality/data-integrity/array-validation.d.ts +16 -0
- package/dist/checks/quality/data-integrity/array-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/array-validation.js +508 -0
- package/dist/checks/quality/data-integrity/array-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.d.ts +14 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.js +235 -0
- package/dist/checks/quality/data-integrity/database-index-coverage.js.map +1 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.d.ts +16 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.js +328 -0
- package/dist/checks/quality/data-integrity/database-schema-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts +14 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.js +157 -0
- package/dist/checks/quality/data-integrity/in-memory-repository-detection.js.map +1 -0
- package/dist/checks/quality/data-integrity/index.d.ts +8 -0
- package/dist/checks/quality/data-integrity/index.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/index.js +8 -0
- package/dist/checks/quality/data-integrity/index.js.map +1 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.d.ts +12 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.js +180 -0
- package/dist/checks/quality/data-integrity/missing-input-validation.js.map +1 -0
- package/dist/checks/quality/data-integrity/null-safety.d.ts +33 -0
- package/dist/checks/quality/data-integrity/null-safety.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/null-safety.js +766 -0
- package/dist/checks/quality/data-integrity/null-safety.js.map +1 -0
- package/dist/checks/quality/data-integrity/numeric-validation.d.ts +12 -0
- package/dist/checks/quality/data-integrity/numeric-validation.d.ts.map +1 -0
- package/dist/checks/quality/data-integrity/numeric-validation.js +409 -0
- package/dist/checks/quality/data-integrity/numeric-validation.js.map +1 -0
- package/dist/checks/quality/frontend/a11y-form-labels.d.ts +14 -0
- package/dist/checks/quality/frontend/a11y-form-labels.d.ts.map +1 -0
- package/dist/checks/quality/frontend/a11y-form-labels.js +93 -0
- package/dist/checks/quality/frontend/a11y-form-labels.js.map +1 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.d.ts +14 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.d.ts.map +1 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.js +88 -0
- package/dist/checks/quality/frontend/a11y-semantic-html.js.map +1 -0
- package/dist/checks/quality/frontend/index.d.ts +4 -0
- package/dist/checks/quality/frontend/index.d.ts.map +1 -0
- package/dist/checks/quality/frontend/index.js +4 -0
- package/dist/checks/quality/frontend/index.js.map +1 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts +13 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.d.ts.map +1 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.js +159 -0
- package/dist/checks/quality/frontend/test-only-frontend-modules.js.map +1 -0
- package/dist/checks/quality/incomplete-regex-escaping.d.ts +13 -0
- package/dist/checks/quality/incomplete-regex-escaping.d.ts.map +1 -0
- package/dist/checks/quality/incomplete-regex-escaping.js +207 -0
- package/dist/checks/quality/incomplete-regex-escaping.js.map +1 -0
- package/dist/checks/quality/index.d.ts +11 -0
- package/dist/checks/quality/index.d.ts.map +1 -0
- package/dist/checks/quality/index.js +11 -0
- package/dist/checks/quality/index.js.map +1 -0
- package/dist/checks/quality/linting/index.d.ts +2 -0
- package/dist/checks/quality/linting/index.d.ts.map +1 -0
- package/dist/checks/quality/linting/index.js +2 -0
- package/dist/checks/quality/linting/index.js.map +1 -0
- package/dist/checks/quality/linting/typescript-frontend.d.ts +25 -0
- package/dist/checks/quality/linting/typescript-frontend.d.ts.map +1 -0
- package/dist/checks/quality/linting/typescript-frontend.js +159 -0
- package/dist/checks/quality/linting/typescript-frontend.js.map +1 -0
- package/dist/checks/quality/observability/index.d.ts +5 -0
- package/dist/checks/quality/observability/index.d.ts.map +1 -0
- package/dist/checks/quality/observability/index.js +5 -0
- package/dist/checks/quality/observability/index.js.map +1 -0
- package/dist/checks/quality/observability/logger-event-name-format.d.ts +12 -0
- package/dist/checks/quality/observability/logger-event-name-format.d.ts.map +1 -0
- package/dist/checks/quality/observability/logger-event-name-format.js +124 -0
- package/dist/checks/quality/observability/logger-event-name-format.js.map +1 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts +5 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.d.ts.map +1 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.js +77 -0
- package/dist/checks/quality/observability/no-hardcoded-correlation-id.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts +11 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js +107 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/analyzer.test.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts +12 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js +94 -0
- package/dist/checks/quality/observability/observability-coverage/__tests__/logger-detector.test.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts +13 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.js +117 -0
- package/dist/checks/quality/observability/observability-coverage/analyzer.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/index.d.ts +4 -0
- package/dist/checks/quality/observability/observability-coverage/index.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/index.js +4 -0
- package/dist/checks/quality/observability/observability-coverage/index.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts +29 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.js +111 -0
- package/dist/checks/quality/observability/observability-coverage/logger-detector.js.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/types.d.ts +64 -0
- package/dist/checks/quality/observability/observability-coverage/types.d.ts.map +1 -0
- package/dist/checks/quality/observability/observability-coverage/types.js +6 -0
- package/dist/checks/quality/observability/observability-coverage/types.js.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts +22 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.d.ts.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.js +212 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.js.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts +11 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.d.ts.map +1 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.js +46 -0
- package/dist/checks/quality/observability/pii-exposure-in-logs.test.js.map +1 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts +14 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.d.ts.map +1 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js +61 -0
- package/dist/checks/quality/patterns/__tests__/toctou-fp.test.js.map +1 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.d.ts +26 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.d.ts.map +1 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.js +410 -0
- package/dist/checks/quality/patterns/async-waterfall-detection.js.map +1 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts +13 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.d.ts.map +1 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.js +220 -0
- package/dist/checks/quality/patterns/dispose-pattern-completeness.js.map +1 -0
- package/dist/checks/quality/patterns/error-handling-quality.d.ts +17 -0
- package/dist/checks/quality/patterns/error-handling-quality.d.ts.map +1 -0
- package/dist/checks/quality/patterns/error-handling-quality.js +335 -0
- package/dist/checks/quality/patterns/error-handling-quality.js.map +1 -0
- package/dist/checks/quality/patterns/index.d.ts +10 -0
- package/dist/checks/quality/patterns/index.d.ts.map +1 -0
- package/dist/checks/quality/patterns/index.js +10 -0
- package/dist/checks/quality/patterns/index.js.map +1 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts +16 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.d.ts.map +1 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js +205 -0
- package/dist/checks/quality/patterns/lifecycle-cleanup-enforcement.js.map +1 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.d.ts +16 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.d.ts.map +1 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.js +328 -0
- package/dist/checks/quality/patterns/result-pattern-consistency.js.map +1 -0
- package/dist/checks/quality/patterns/silent-early-returns.d.ts +23 -0
- package/dist/checks/quality/patterns/silent-early-returns.d.ts.map +1 -0
- package/dist/checks/quality/patterns/silent-early-returns.js +266 -0
- package/dist/checks/quality/patterns/silent-early-returns.js.map +1 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts +13 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.d.ts.map +1 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.js +163 -0
- package/dist/checks/quality/patterns/stream-buffer-size-limits.js.map +1 -0
- package/dist/checks/quality/patterns/throws-documentation.d.ts +23 -0
- package/dist/checks/quality/patterns/throws-documentation.d.ts.map +1 -0
- package/dist/checks/quality/patterns/throws-documentation.js +519 -0
- package/dist/checks/quality/patterns/throws-documentation.js.map +1 -0
- package/dist/checks/quality/patterns/toctou-race-condition.d.ts +48 -0
- package/dist/checks/quality/patterns/toctou-race-condition.d.ts.map +1 -0
- package/dist/checks/quality/patterns/toctou-race-condition.js +639 -0
- package/dist/checks/quality/patterns/toctou-race-condition.js.map +1 -0
- package/dist/checks/quality/stubbed-implementation-detection.d.ts +24 -0
- package/dist/checks/quality/stubbed-implementation-detection.d.ts.map +1 -0
- package/dist/checks/quality/stubbed-implementation-detection.js +355 -0
- package/dist/checks/quality/stubbed-implementation-detection.js.map +1 -0
- package/dist/checks/quality/unused-config-options.d.ts +12 -0
- package/dist/checks/quality/unused-config-options.d.ts.map +1 -0
- package/dist/checks/quality/unused-config-options.js +245 -0
- package/dist/checks/quality/unused-config-options.js.map +1 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts +2 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js +79 -0
- package/dist/checks/resilience/__tests__/callback-invocation-safe.test.js.map +1 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts +12 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.js +34 -0
- package/dist/checks/resilience/__tests__/context-leakage-fp.test.js.map +1 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.d.ts +11 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.d.ts.map +1 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.js +54 -0
- package/dist/checks/resilience/__tests__/context-mutation.test.js.map +1 -0
- package/dist/checks/resilience/callback-invocation-safe.d.ts +34 -0
- package/dist/checks/resilience/callback-invocation-safe.d.ts.map +1 -0
- package/dist/checks/resilience/callback-invocation-safe.js +247 -0
- package/dist/checks/resilience/callback-invocation-safe.js.map +1 -0
- package/dist/checks/resilience/context-leakage.d.ts +25 -0
- package/dist/checks/resilience/context-leakage.d.ts.map +1 -0
- package/dist/checks/resilience/context-leakage.js +435 -0
- package/dist/checks/resilience/context-leakage.js.map +1 -0
- package/dist/checks/resilience/context-mutation.d.ts +21 -0
- package/dist/checks/resilience/context-mutation.d.ts.map +1 -0
- package/dist/checks/resilience/context-mutation.js +368 -0
- package/dist/checks/resilience/context-mutation.js.map +1 -0
- package/dist/checks/resilience/detached-promises.d.ts +40 -0
- package/dist/checks/resilience/detached-promises.d.ts.map +1 -0
- package/dist/checks/resilience/detached-promises.js +646 -0
- package/dist/checks/resilience/detached-promises.js.map +1 -0
- package/dist/checks/resilience/index.d.ts +7 -0
- package/dist/checks/resilience/index.d.ts.map +1 -0
- package/dist/checks/resilience/index.js +7 -0
- package/dist/checks/resilience/index.js.map +1 -0
- package/dist/checks/resilience/no-raw-fetch.d.ts +11 -0
- package/dist/checks/resilience/no-raw-fetch.d.ts.map +1 -0
- package/dist/checks/resilience/no-raw-fetch.js +110 -0
- package/dist/checks/resilience/no-raw-fetch.js.map +1 -0
- package/dist/checks/resilience/no-unbounded-concurrency.d.ts +11 -0
- package/dist/checks/resilience/no-unbounded-concurrency.d.ts.map +1 -0
- package/dist/checks/resilience/no-unbounded-concurrency.js +117 -0
- package/dist/checks/resilience/no-unbounded-concurrency.js.map +1 -0
- package/dist/checks/security/__tests__/sql-injection.test.d.ts +17 -0
- package/dist/checks/security/__tests__/sql-injection.test.d.ts.map +1 -0
- package/dist/checks/security/__tests__/sql-injection.test.js +97 -0
- package/dist/checks/security/__tests__/sql-injection.test.js.map +1 -0
- package/dist/checks/security/index.d.ts +4 -0
- package/dist/checks/security/index.d.ts.map +1 -0
- package/dist/checks/security/index.js +4 -0
- package/dist/checks/security/index.js.map +1 -0
- package/dist/checks/security/input-sanitization.d.ts +20 -0
- package/dist/checks/security/input-sanitization.d.ts.map +1 -0
- package/dist/checks/security/input-sanitization.js +255 -0
- package/dist/checks/security/input-sanitization.js.map +1 -0
- package/dist/checks/security/sql-injection.d.ts +24 -0
- package/dist/checks/security/sql-injection.d.ts.map +1 -0
- package/dist/checks/security/sql-injection.js +330 -0
- package/dist/checks/security/sql-injection.js.map +1 -0
- package/dist/checks/security/unsafe-secret-comparison.d.ts +17 -0
- package/dist/checks/security/unsafe-secret-comparison.d.ts.map +1 -0
- package/dist/checks/security/unsafe-secret-comparison.js +227 -0
- package/dist/checks/security/unsafe-secret-comparison.js.map +1 -0
- package/dist/checks/testing/index.d.ts +2 -0
- package/dist/checks/testing/index.d.ts.map +1 -0
- package/dist/checks/testing/index.js +2 -0
- package/dist/checks/testing/index.js.map +1 -0
- package/dist/checks/testing/mock-implementations-in-production.d.ts +12 -0
- package/dist/checks/testing/mock-implementations-in-production.d.ts.map +1 -0
- package/dist/checks/testing/mock-implementations-in-production.js +211 -0
- package/dist/checks/testing/mock-implementations-in-production.js.map +1 -0
- package/dist/display/architecture.d.ts +9 -0
- package/dist/display/architecture.d.ts.map +1 -0
- package/dist/display/architecture.js +18 -0
- package/dist/display/architecture.js.map +1 -0
- package/dist/display/index.d.ts +20 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +30 -0
- package/dist/display/index.js.map +1 -0
- package/dist/display/quality.d.ts +7 -0
- package/dist/display/quality.d.ts.map +1 -0
- package/dist/display/quality.js +39 -0
- package/dist/display/quality.js.map +1 -0
- package/dist/display/resilience.d.ts +7 -0
- package/dist/display/resilience.d.ts.map +1 -0
- package/dist/display/resilience.js +13 -0
- package/dist/display/resilience.js.map +1 -0
- package/dist/display/security-testing.d.ts +9 -0
- package/dist/display/security-testing.d.ts.map +1 -0
- package/dist/display/security-testing.js +14 -0
- package/dist/display/security-testing.js.map +1 -0
- package/dist/display/types.d.ts +6 -0
- package/dist/display/types.d.ts.map +1 -0
- package/dist/display/types.js +6 -0
- package/dist/display/types.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// @fitness-ignore-file duplicate-implementation-detection -- similar patterns across diagnostic modules
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Database Index Coverage check
|
|
4
|
+
*
|
|
5
|
+
* Validates that database queries have appropriate indexes.
|
|
6
|
+
* Detects queries that may cause full table scans.
|
|
7
|
+
*/
|
|
8
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
9
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
10
|
+
import * as ts from 'typescript';
|
|
11
|
+
/**
|
|
12
|
+
* Create a violation object with common fields
|
|
13
|
+
* @param ctx - Violation context
|
|
14
|
+
* @param node - TypeScript node
|
|
15
|
+
* @param props - Violation properties
|
|
16
|
+
* @returns CheckViolation object
|
|
17
|
+
*/
|
|
18
|
+
function createViolation(ctx, node, props) {
|
|
19
|
+
const { line: lineIdx, character } = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
20
|
+
const line = lineIdx + 1;
|
|
21
|
+
return {
|
|
22
|
+
line,
|
|
23
|
+
column: character + 1,
|
|
24
|
+
message: props.message,
|
|
25
|
+
severity: 'warning',
|
|
26
|
+
suggestion: props.suggestion,
|
|
27
|
+
type: props.type,
|
|
28
|
+
match: props.match,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if file is a repository/database file
|
|
33
|
+
*/
|
|
34
|
+
function isRepositoryFile(filePath) {
|
|
35
|
+
return (filePath.includes('/repositories/') ||
|
|
36
|
+
filePath.includes('/database/') ||
|
|
37
|
+
filePath.includes('-repository.ts') ||
|
|
38
|
+
filePath.includes('.repository.ts'));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a where clause references potentially unindexed columns
|
|
42
|
+
* @param node - The CallExpression node
|
|
43
|
+
* @param ctx - Violation context
|
|
44
|
+
* @returns CheckViolation or null
|
|
45
|
+
*/
|
|
46
|
+
function checkFindOperationWhereClause(node, ctx) {
|
|
47
|
+
const whereArg = node.arguments[0];
|
|
48
|
+
if (!whereArg || !ts.isObjectLiteralExpression(whereArg)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const whereClause = whereArg.properties.find((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'where');
|
|
52
|
+
if (!whereClause || !ts.isPropertyAssignment(whereClause)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const potentialIssues = checkWhereClause(whereClause.initializer);
|
|
56
|
+
if (potentialIssues.length === 0) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return createViolation(ctx, node, {
|
|
60
|
+
message: `Query may use non-indexed columns: ${potentialIssues.join(', ')}`,
|
|
61
|
+
suggestion: `Add database index for column(s) ${potentialIssues.join(', ')} or refactor query to use indexed columns like 'id', 'createdAt', or foreign keys`,
|
|
62
|
+
type: 'potential-full-scan',
|
|
63
|
+
match: node.getText(ctx.sourceFile).slice(0, 60),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check for leading wildcard LIKE in query text
|
|
68
|
+
* @param node - The CallExpression node
|
|
69
|
+
* @param queryText - Lowercase query text
|
|
70
|
+
* @param queryArg - The string literal argument
|
|
71
|
+
* @param ctx - Violation context
|
|
72
|
+
* @returns CheckViolation or null
|
|
73
|
+
*/
|
|
74
|
+
function checkLeadingWildcardLike(node, queryText, queryArg, ctx) {
|
|
75
|
+
const hasLeadingWildcard = queryText.includes("like '%") || queryText.includes('like "%');
|
|
76
|
+
if (!hasLeadingWildcard) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return createViolation(ctx, node, {
|
|
80
|
+
message: 'Query uses LIKE with leading wildcard, cannot use index',
|
|
81
|
+
suggestion: "Replace LIKE '%term%' with full-text search (OpenSearch) or use LIKE 'term%' (trailing wildcard only) to enable index usage",
|
|
82
|
+
type: 'leading-wildcard-like',
|
|
83
|
+
match: queryArg.text.slice(0, 60),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check for unbounded SELECT * queries
|
|
88
|
+
* @param node - The CallExpression node
|
|
89
|
+
* @param queryText - Lowercase query text
|
|
90
|
+
* @param queryArg - The string literal argument
|
|
91
|
+
* @param ctx - Violation context
|
|
92
|
+
* @returns CheckViolation or null
|
|
93
|
+
*/
|
|
94
|
+
function checkUnboundedSelect(node, queryText, queryArg, ctx) {
|
|
95
|
+
const hasSelectStar = queryText.includes('select *');
|
|
96
|
+
const hasBound = queryText.includes('limit') || queryText.includes('top');
|
|
97
|
+
if (!hasSelectStar || hasBound) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return createViolation(ctx, node, {
|
|
101
|
+
message: 'SELECT * without LIMIT may scan entire table',
|
|
102
|
+
suggestion: "Add 'LIMIT n' clause to bound the result set, or select specific columns instead of '*'",
|
|
103
|
+
type: 'unbounded-select',
|
|
104
|
+
match: queryArg.text.slice(0, 60),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check raw query methods for issues
|
|
109
|
+
* @param node - The CallExpression node
|
|
110
|
+
* @param ctx - Violation context
|
|
111
|
+
* @returns Array of violations
|
|
112
|
+
*/
|
|
113
|
+
function checkRawQueryMethod(node, ctx) {
|
|
114
|
+
const violations = [];
|
|
115
|
+
const queryArg = node.arguments[0];
|
|
116
|
+
if (!queryArg || !ts.isStringLiteral(queryArg)) {
|
|
117
|
+
return violations;
|
|
118
|
+
}
|
|
119
|
+
const queryText = queryArg.text.toLowerCase();
|
|
120
|
+
const wildcardViolation = checkLeadingWildcardLike(node, queryText, queryArg, ctx);
|
|
121
|
+
if (wildcardViolation) {
|
|
122
|
+
violations.push(wildcardViolation);
|
|
123
|
+
}
|
|
124
|
+
const unboundedViolation = checkUnboundedSelect(node, queryText, queryArg, ctx);
|
|
125
|
+
if (unboundedViolation) {
|
|
126
|
+
violations.push(unboundedViolation);
|
|
127
|
+
}
|
|
128
|
+
return violations;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Analyze a call expression for index coverage issues
|
|
132
|
+
* @param node - The CallExpression node
|
|
133
|
+
* @param ctx - Violation context
|
|
134
|
+
* @returns Array of violations
|
|
135
|
+
*/
|
|
136
|
+
function analyzeCallExpression(node, ctx) {
|
|
137
|
+
const violations = [];
|
|
138
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
139
|
+
if (!ts.isPropertyAccessExpression(node.expression)) {
|
|
140
|
+
return violations;
|
|
141
|
+
}
|
|
142
|
+
const methodName = node.expression.name.getText(ctx.sourceFile);
|
|
143
|
+
const findMethods = ['find', 'findOne', 'findBy', 'findOneBy'];
|
|
144
|
+
const rawQueryMethods = ['query', 'createQueryBuilder'];
|
|
145
|
+
if (findMethods.includes(methodName)) {
|
|
146
|
+
const violation = checkFindOperationWhereClause(node, ctx);
|
|
147
|
+
if (violation) {
|
|
148
|
+
violations.push(violation);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (rawQueryMethods.includes(methodName)) {
|
|
152
|
+
violations.push(...checkRawQueryMethod(node, ctx));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Other method names - no index coverage check needed
|
|
156
|
+
}
|
|
157
|
+
return violations;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Analyze a file for index coverage issues
|
|
161
|
+
* @param content - The file content
|
|
162
|
+
* @param absolutePath - The file path
|
|
163
|
+
* @returns Array of violations
|
|
164
|
+
*/
|
|
165
|
+
function analyzeFile(content, absolutePath) {
|
|
166
|
+
const violations = [];
|
|
167
|
+
// Filter to repository/database files
|
|
168
|
+
if (!isRepositoryFile(absolutePath)) {
|
|
169
|
+
return violations;
|
|
170
|
+
}
|
|
171
|
+
const sourceFile = getSharedSourceFile(absolutePath, content);
|
|
172
|
+
/* v8 ignore next -- defensive guard */
|
|
173
|
+
if (!sourceFile)
|
|
174
|
+
return [];
|
|
175
|
+
const ctx = { absolutePath, content, sourceFile };
|
|
176
|
+
const visit = (node) => {
|
|
177
|
+
if (ts.isCallExpression(node)) {
|
|
178
|
+
violations.push(...analyzeCallExpression(node, ctx));
|
|
179
|
+
}
|
|
180
|
+
ts.forEachChild(node, visit);
|
|
181
|
+
};
|
|
182
|
+
visit(sourceFile);
|
|
183
|
+
return violations;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Check where clause for potentially unindexed columns
|
|
187
|
+
* @param node - The where clause node
|
|
188
|
+
* @returns Array of potentially problematic column names
|
|
189
|
+
*/
|
|
190
|
+
function checkWhereClause(node) {
|
|
191
|
+
const potentialIssues = [];
|
|
192
|
+
// Columns that are commonly not indexed and should be flagged
|
|
193
|
+
const riskyColumns = ['description', 'notes', 'content', 'body', 'text', 'metadata'];
|
|
194
|
+
if (!ts.isObjectLiteralExpression(node)) {
|
|
195
|
+
return potentialIssues;
|
|
196
|
+
}
|
|
197
|
+
for (const prop of node.properties) {
|
|
198
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const columnName = prop.name.text.toLowerCase();
|
|
202
|
+
if (riskyColumns.some((r) => columnName.includes(r))) {
|
|
203
|
+
potentialIssues.push(prop.name.text);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return potentialIssues;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check: quality/database-index-coverage
|
|
210
|
+
*
|
|
211
|
+
* Validates that database queries reference indexed columns
|
|
212
|
+
* to prevent performance issues from full table scans.
|
|
213
|
+
*/
|
|
214
|
+
export const databaseIndexCoverage = defineCheck({
|
|
215
|
+
id: '51b5848f-b260-44f0-83e6-ce42a776cd05',
|
|
216
|
+
slug: 'database-index-coverage',
|
|
217
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
218
|
+
confidence: 'high',
|
|
219
|
+
description: 'Validate database queries have appropriate indexes',
|
|
220
|
+
longDescription: `**Purpose:** Validates that database queries in repository files reference indexed columns and avoid patterns that cause full table scans.
|
|
221
|
+
|
|
222
|
+
**Detects:**
|
|
223
|
+
- TypeORM \`find\`/\`findOne\`/\`findBy\`/\`findOneBy\` calls whose \`where\` clause references commonly unindexed columns (\`description\`, \`notes\`, \`content\`, \`body\`, \`text\`, \`metadata\`)
|
|
224
|
+
- Raw \`query\`/\`createQueryBuilder\` calls with \`LIKE '%...\` (leading wildcard) which cannot use indexes
|
|
225
|
+
- \`SELECT *\` without \`LIMIT\` or \`TOP\` clause, risking unbounded result sets
|
|
226
|
+
- Only scans files in \`/repositories/\`, \`/database/\`, or files named \`*-repository.ts\`/\`*.repository.ts\`
|
|
227
|
+
|
|
228
|
+
**Why it matters:** Queries on unindexed columns or with leading wildcards cause O(N) full table scans, degrading performance as data grows.
|
|
229
|
+
|
|
230
|
+
**Scope:** General best practice. Analyzes each file individually.`,
|
|
231
|
+
tags: ['quality', 'database', 'performance', 'indexes'],
|
|
232
|
+
fileTypes: ['ts'],
|
|
233
|
+
analyze: analyzeFile,
|
|
234
|
+
});
|
|
235
|
+
//# sourceMappingURL=database-index-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-index-coverage.js","sourceRoot":"","sources":["../../../../src/checks/quality/data-integrity/database-index-coverage.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAuB,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAWjC;;;;;;GAMG;AACH,SAAS,eAAe,CACtB,GAAqB,EACrB,IAAa,EACb,KAKC;IAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC,6BAA6B,CAC/E,IAAI,CAAC,QAAQ,EAAE,CAChB,CAAC;IACF,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC;IAEzB,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,SAAS,GAAG,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,SAAS;QACnB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,OAAO,CACL,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QACnC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC/B,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QACnC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,6BAA6B,CACpC,IAAuB,EACvB,GAAqB;IAErB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CACxF,CAAC;IAEF,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,eAAe,GAAG,gBAAgB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAClE,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE;QAChC,OAAO,EAAE,sCAAsC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC3E,UAAU,EAAE,oCAAoC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,mFAAmF;QAC7J,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KACjD,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,wBAAwB,CAC/B,IAAuB,EACvB,SAAiB,EACjB,QAA0B,EAC1B,GAAqB;IAErB,MAAM,kBAAkB,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC1F,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE;QAChC,OAAO,EAAE,yDAAyD;QAClE,UAAU,EACR,6HAA6H;QAC/H,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAC3B,IAAuB,EACvB,SAAiB,EACjB,QAA0B,EAC1B,GAAqB;IAErB,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1E,IAAI,CAAC,aAAa,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE;QAChC,OAAO,EAAE,8CAA8C;QACvD,UAAU,EACR,yFAAyF;QAC3F,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,IAAuB,EAAE,GAAqB;IACzE,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAE9C,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IACnF,IAAI,iBAAiB,EAAE,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAChF,IAAI,kBAAkB,EAAE,CAAC;QACvB,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAAC,IAAuB,EAAE,GAAqB;IAC3E,MAAM,UAAU,GAAqB,EAAE,CAAC;IAExC,gDAAgD;IAChD,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACpD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/D,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;IAExD,IAAI,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,6BAA6B,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3D,IAAI,SAAS,EAAE,CAAC;YACd,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;SAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAChD,UAAU,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IACrD,CAAC;SAAM,CAAC;QACN,sDAAsD;IACxD,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,OAAe,EAAE,YAAoB;IACxD,MAAM,UAAU,GAAqB,EAAE,CAAC;IAExC,sCAAsC;IACtC,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,EAAE,CAAC;QACpC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC9D,uCAAuC;IACvC,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,GAAG,GAAqB,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAEpE,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,EAAE;QAC9B,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,UAAU,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACvD,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,KAAK,CAAC,UAAU,CAAC,CAAC;IAClB,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,IAAa;IACrC,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,8DAA8D;IAC9D,MAAM,YAAY,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAErF,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAClE,SAAS;QACX,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC;IAC/C,EAAE,EAAE,sCAAsC;IAC1C,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE;IAErE,UAAU,EAAE,MAAM;IAClB,WAAW,EAAE,oDAAoD;IACjE,eAAe,EAAE;;;;;;;;;;mEAUgD;IACjE,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC;IACvD,SAAS,EAAE,CAAC,IAAI,CAAC;IAEjB,OAAO,EAAE,WAAW;CACrB,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Database Schema Validation check
|
|
3
|
+
*
|
|
4
|
+
* Validates database schema definitions for best practices:
|
|
5
|
+
* - Primary key definitions
|
|
6
|
+
* - Foreign key relationships
|
|
7
|
+
* - Appropriate column types
|
|
8
|
+
* - Index definitions
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Check: quality/database-schema-validation
|
|
12
|
+
*
|
|
13
|
+
* Validates database schema definitions follow best practices.
|
|
14
|
+
*/
|
|
15
|
+
export declare const databaseSchemaValidation: import("@opensip-cli/fitness").Check;
|
|
16
|
+
//# sourceMappingURL=database-schema-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-schema-validation.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/data-integrity/database-schema-validation.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAyYH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,sCAsBnC,CAAC"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// @fitness-ignore-file batch-operation-limits -- iterates bounded collections (config entries, registry items, or small analysis results)
|
|
2
|
+
// @fitness-ignore-file unused-config-options -- Config options reserved for future use or environment-specific
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Database Schema Validation check
|
|
5
|
+
*
|
|
6
|
+
* Validates database schema definitions for best practices:
|
|
7
|
+
* - Primary key definitions
|
|
8
|
+
* - Foreign key relationships
|
|
9
|
+
* - Appropriate column types
|
|
10
|
+
* - Index definitions
|
|
11
|
+
*/
|
|
12
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
13
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
14
|
+
import * as ts from 'typescript';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Code Snippet Helpers
|
|
17
|
+
// =============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Determine which audit columns are missing.
|
|
20
|
+
*
|
|
21
|
+
* @param hasCreatedAt - Has createdAt column
|
|
22
|
+
* @param hasUpdatedAt - Has updatedAt column
|
|
23
|
+
* @returns Description of missing columns
|
|
24
|
+
*/
|
|
25
|
+
function getMissingAuditColumnsDescription(hasCreatedAt, hasUpdatedAt) {
|
|
26
|
+
if (!hasCreatedAt && !hasUpdatedAt) {
|
|
27
|
+
return 'createdAt and updatedAt';
|
|
28
|
+
}
|
|
29
|
+
if (!hasCreatedAt) {
|
|
30
|
+
return 'createdAt';
|
|
31
|
+
}
|
|
32
|
+
return 'updatedAt';
|
|
33
|
+
}
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Decorator Analysis Helpers
|
|
36
|
+
// =============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Check if a class has the @Entity decorator.
|
|
39
|
+
*
|
|
40
|
+
* @param node - Class declaration node
|
|
41
|
+
* @returns True if has Entity decorator
|
|
42
|
+
*/
|
|
43
|
+
function hasEntityDecorator(node) {
|
|
44
|
+
return (node.modifiers?.some((m) => ts.isDecorator(m) &&
|
|
45
|
+
ts.isCallExpression(m.expression) &&
|
|
46
|
+
ts.isIdentifier(m.expression.expression) &&
|
|
47
|
+
m.expression.expression.text === 'Entity') ?? false);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the decorator name from a decorator node if it's a call expression.
|
|
51
|
+
*
|
|
52
|
+
* @param decorator - Decorator node
|
|
53
|
+
* @returns Decorator name or null
|
|
54
|
+
*/
|
|
55
|
+
function getDecoratorName(decorator) {
|
|
56
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
57
|
+
if (!ts.isCallExpression(decorator.expression)) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
61
|
+
if (!ts.isIdentifier(decorator.expression.expression)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return decorator.expression.expression.text;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a Column decorator has nullable: true without a default value.
|
|
68
|
+
*
|
|
69
|
+
* @param decorator - Decorator node
|
|
70
|
+
* @returns True if nullable without default
|
|
71
|
+
*/
|
|
72
|
+
function isNullableWithoutDefault(decorator) {
|
|
73
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
74
|
+
if (!ts.isCallExpression(decorator.expression)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const arg = decorator.expression.arguments[0];
|
|
78
|
+
if (!arg || !ts.isObjectLiteralExpression(arg)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const isNullable = arg.properties.some((p) => ts.isPropertyAssignment(p) &&
|
|
82
|
+
ts.isIdentifier(p.name) &&
|
|
83
|
+
p.name.text === 'nullable' &&
|
|
84
|
+
p.initializer.kind === ts.SyntaxKind.TrueKeyword);
|
|
85
|
+
const hasDefault = arg.properties.some((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'default');
|
|
86
|
+
return isNullable && !hasDefault;
|
|
87
|
+
}
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// Violation Creation Helpers
|
|
90
|
+
// =============================================================================
|
|
91
|
+
/**
|
|
92
|
+
* Create a violation for a nullable column without default.
|
|
93
|
+
*
|
|
94
|
+
* @param propName - Property name
|
|
95
|
+
* @param line - Line number (0-indexed)
|
|
96
|
+
* @returns Violation object
|
|
97
|
+
*/
|
|
98
|
+
function createNullableColumnViolation(propName, line) {
|
|
99
|
+
return {
|
|
100
|
+
line: line + 1,
|
|
101
|
+
column: 0,
|
|
102
|
+
message: `Column '${propName}' is nullable - consider adding default value`,
|
|
103
|
+
severity: 'warning',
|
|
104
|
+
suggestion: `Add default: null or default: '' to @Column({ nullable: true, default: ... }) for '${propName}' to avoid undefined behavior`,
|
|
105
|
+
type: 'nullable-without-default',
|
|
106
|
+
match: propName,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a violation for missing primary key.
|
|
111
|
+
*
|
|
112
|
+
* @param ctx - Analysis context
|
|
113
|
+
* @param node - Class declaration node
|
|
114
|
+
* @returns Violation object
|
|
115
|
+
*/
|
|
116
|
+
function createMissingPrimaryKeyViolation(ctx, node) {
|
|
117
|
+
const { line: lineIdx, character } = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
118
|
+
const line = lineIdx + 1;
|
|
119
|
+
const className = node.name?.getText(ctx.sourceFile) ?? 'Entity';
|
|
120
|
+
return {
|
|
121
|
+
line,
|
|
122
|
+
column: character + 1,
|
|
123
|
+
message: 'Entity missing primary key column',
|
|
124
|
+
severity: 'error',
|
|
125
|
+
suggestion: `Add '@PrimaryGeneratedColumn('uuid') id: string;' to ${className} for proper identity management`,
|
|
126
|
+
type: 'missing-primary-key',
|
|
127
|
+
match: className,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a violation for missing audit columns.
|
|
132
|
+
*
|
|
133
|
+
* @param ctx - Analysis context
|
|
134
|
+
* @param node - Class declaration node
|
|
135
|
+
* @param state - Entity analysis state
|
|
136
|
+
* @returns Violation object
|
|
137
|
+
*/
|
|
138
|
+
function createMissingAuditColumnsViolation(ctx, node, state) {
|
|
139
|
+
const { line: lineIdx, character } = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
140
|
+
const line = lineIdx + 1;
|
|
141
|
+
const className = node.name?.getText(ctx.sourceFile) ?? 'Entity';
|
|
142
|
+
const missing = getMissingAuditColumnsDescription(state.hasCreatedAt, state.hasUpdatedAt);
|
|
143
|
+
return {
|
|
144
|
+
line,
|
|
145
|
+
column: character + 1,
|
|
146
|
+
message: 'Entity missing audit columns (createdAt/updatedAt)',
|
|
147
|
+
severity: 'warning',
|
|
148
|
+
suggestion: `Add '@CreateDateColumn() createdAt: Date;' and '@UpdateDateColumn() updatedAt: Date;' to ${className} for audit trail (missing: ${missing})`,
|
|
149
|
+
type: 'missing-audit-columns',
|
|
150
|
+
match: className,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// =============================================================================
|
|
154
|
+
// Property Analysis
|
|
155
|
+
// =============================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Process a single property member and update state/violations.
|
|
158
|
+
*
|
|
159
|
+
* @param member - Property declaration
|
|
160
|
+
* @param ctx - Analysis context
|
|
161
|
+
* @param state - Entity analysis state
|
|
162
|
+
* @param violations - Violations array to append to
|
|
163
|
+
*/
|
|
164
|
+
function processPropertyMember(member, ctx, state, violations) {
|
|
165
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
166
|
+
if (!ts.isIdentifier(member.name)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const propName = member.name.text;
|
|
170
|
+
const { line } = ctx.sourceFile.getLineAndCharacterOfPosition(member.getStart());
|
|
171
|
+
/* v8 ignore next -- defensive nullish fallback */
|
|
172
|
+
const decorators = ts.getDecorators(member) ?? [];
|
|
173
|
+
for (const decorator of decorators) {
|
|
174
|
+
const decoratorName = getDecoratorName(decorator);
|
|
175
|
+
if (!decoratorName) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
updateStateFromDecorator(decoratorName, state);
|
|
179
|
+
checkColumnDecorator({ decorator, decoratorName, propName, line, violations });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Update entity state based on decorator name.
|
|
184
|
+
*
|
|
185
|
+
* @param decoratorName - Name of the decorator
|
|
186
|
+
* @param state - State to update
|
|
187
|
+
*/
|
|
188
|
+
function updateStateFromDecorator(decoratorName, state) {
|
|
189
|
+
if (decoratorName === 'PrimaryGeneratedColumn' || decoratorName === 'PrimaryColumn') {
|
|
190
|
+
state.hasIdColumn = true;
|
|
191
|
+
}
|
|
192
|
+
if (decoratorName === 'CreateDateColumn') {
|
|
193
|
+
state.hasCreatedAt = true;
|
|
194
|
+
}
|
|
195
|
+
if (decoratorName === 'UpdateDateColumn') {
|
|
196
|
+
state.hasUpdatedAt = true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Check if a Column decorator has violations.
|
|
201
|
+
*
|
|
202
|
+
* @param options - Options containing decorator and analysis context
|
|
203
|
+
*/
|
|
204
|
+
function checkColumnDecorator(options) {
|
|
205
|
+
const { decorator, decoratorName, propName, line, violations } = options;
|
|
206
|
+
// Validate array parameter
|
|
207
|
+
/* v8 ignore next -- defensive guard */
|
|
208
|
+
if (!Array.isArray(violations)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (decoratorName !== 'Column') {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (isNullableWithoutDefault(decorator)) {
|
|
215
|
+
violations.push(createNullableColumnViolation(propName, line));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// =============================================================================
|
|
219
|
+
// Entity Class Analysis
|
|
220
|
+
// =============================================================================
|
|
221
|
+
/**
|
|
222
|
+
* Analyze an entity class for schema validation issues.
|
|
223
|
+
*
|
|
224
|
+
* @param node - Class declaration node
|
|
225
|
+
* @param ctx - Analysis context
|
|
226
|
+
* @param violations - Violations array to append to
|
|
227
|
+
*/
|
|
228
|
+
function analyzeEntityClass(node, ctx, violations) {
|
|
229
|
+
// Validate array parameter
|
|
230
|
+
/* v8 ignore next -- defensive guard */
|
|
231
|
+
if (!Array.isArray(violations)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const state = {
|
|
235
|
+
hasIdColumn: false,
|
|
236
|
+
hasCreatedAt: false,
|
|
237
|
+
hasUpdatedAt: false,
|
|
238
|
+
};
|
|
239
|
+
// Process all property members
|
|
240
|
+
for (const member of node.members) {
|
|
241
|
+
if (ts.isPropertyDeclaration(member)) {
|
|
242
|
+
processPropertyMember(member, ctx, state, violations);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Check for missing primary key
|
|
246
|
+
if (!state.hasIdColumn) {
|
|
247
|
+
violations.push(createMissingPrimaryKeyViolation(ctx, node));
|
|
248
|
+
}
|
|
249
|
+
// Check for missing audit columns
|
|
250
|
+
if (!state.hasCreatedAt || !state.hasUpdatedAt) {
|
|
251
|
+
violations.push(createMissingAuditColumnsViolation(ctx, node, state));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// =============================================================================
|
|
255
|
+
// Main Analysis Function
|
|
256
|
+
// =============================================================================
|
|
257
|
+
/**
|
|
258
|
+
* Check if file is an entity/schema file
|
|
259
|
+
*/
|
|
260
|
+
function isEntityFile(filePath) {
|
|
261
|
+
return (filePath.includes('/entities/') ||
|
|
262
|
+
filePath.includes('/models/') ||
|
|
263
|
+
filePath.includes('.entity.ts') ||
|
|
264
|
+
filePath.includes('.model.ts'));
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Analyze a file for schema validation issues.
|
|
268
|
+
*
|
|
269
|
+
* @param content - File content
|
|
270
|
+
* @param absolutePath - Absolute path to the file
|
|
271
|
+
* @returns Array of violations found
|
|
272
|
+
*/
|
|
273
|
+
function analyzeFile(content, absolutePath) {
|
|
274
|
+
const violations = [];
|
|
275
|
+
// Filter to entity/schema files
|
|
276
|
+
if (!isEntityFile(absolutePath)) {
|
|
277
|
+
return violations;
|
|
278
|
+
}
|
|
279
|
+
// Check if file contains TypeORM entity
|
|
280
|
+
if (!content.includes('@Entity') && !content.includes('@Table')) {
|
|
281
|
+
return violations;
|
|
282
|
+
}
|
|
283
|
+
const sourceFile = getSharedSourceFile(absolutePath, content);
|
|
284
|
+
/* v8 ignore next -- defensive guard */
|
|
285
|
+
if (!sourceFile)
|
|
286
|
+
return [];
|
|
287
|
+
const ctx = {
|
|
288
|
+
absolutePath,
|
|
289
|
+
content,
|
|
290
|
+
sourceFile,
|
|
291
|
+
lines: content.split('\n'),
|
|
292
|
+
};
|
|
293
|
+
const visit = (node) => {
|
|
294
|
+
if (ts.isClassDeclaration(node) && hasEntityDecorator(node)) {
|
|
295
|
+
analyzeEntityClass(node, ctx, violations);
|
|
296
|
+
}
|
|
297
|
+
ts.forEachChild(node, visit);
|
|
298
|
+
};
|
|
299
|
+
visit(sourceFile);
|
|
300
|
+
return violations;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check: quality/database-schema-validation
|
|
304
|
+
*
|
|
305
|
+
* Validates database schema definitions follow best practices.
|
|
306
|
+
*/
|
|
307
|
+
export const databaseSchemaValidation = defineCheck({
|
|
308
|
+
id: 'b052a199-cf3c-4c31-8707-6d60331621a8',
|
|
309
|
+
slug: 'database-schema-validation',
|
|
310
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'server'] },
|
|
311
|
+
confidence: 'high',
|
|
312
|
+
description: 'Validate database schema definitions follow best practices',
|
|
313
|
+
longDescription: `**Purpose:** Validates that TypeORM entity classes follow schema best practices for primary keys, audit columns, and nullable column defaults.
|
|
314
|
+
|
|
315
|
+
**Detects:**
|
|
316
|
+
- Entity classes (decorated with \`@Entity\`) missing a \`@PrimaryGeneratedColumn\` or \`@PrimaryColumn\` decorator
|
|
317
|
+
- Entity classes missing \`@CreateDateColumn\` and/or \`@UpdateDateColumn\` audit columns
|
|
318
|
+
- \`@Column({ nullable: true })\` without a \`default\` value, which can cause undefined behavior
|
|
319
|
+
- Only scans files in \`/entities/\`, \`/models/\`, or files named \`*.entity.ts\`/\`*.model.ts\` that contain \`@Entity\` or \`@Table\`
|
|
320
|
+
|
|
321
|
+
**Why it matters:** Missing primary keys break identity management, missing audit columns lose change history, and nullable columns without defaults cause subtle data integrity bugs.
|
|
322
|
+
|
|
323
|
+
**Scope:** General best practice. Analyzes each file individually.`,
|
|
324
|
+
tags: ['quality', 'database', 'schema', 'typeorm'],
|
|
325
|
+
fileTypes: ['ts'],
|
|
326
|
+
analyze: analyzeFile,
|
|
327
|
+
});
|
|
328
|
+
//# sourceMappingURL=database-schema-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-schema-validation.js","sourceRoot":"","sources":["../../../../src/checks/quality/data-integrity/database-schema-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview In-Memory Repository Detection Check
|
|
3
|
+
*
|
|
4
|
+
* Detects repository classes using Map or in-memory storage in production code.
|
|
5
|
+
* These are often placeholders that should be replaced with DynamoDB implementations.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check: quality/in-memory-repository-detection
|
|
9
|
+
*
|
|
10
|
+
* Detects repository classes using Map or in-memory storage instead of
|
|
11
|
+
* proper persistence.
|
|
12
|
+
*/
|
|
13
|
+
export declare const inMemoryRepositoryDetection: import("@opensip-cli/fitness").Check;
|
|
14
|
+
//# sourceMappingURL=in-memory-repository-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-repository-detection.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/data-integrity/in-memory-repository-detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6JH;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,sCAuBtC,CAAC"}
|