@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,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Stubbed Implementation Detection Check
|
|
3
|
+
*
|
|
4
|
+
* Detects patterns indicating incomplete or placeholder implementations:
|
|
5
|
+
* - Empty object stubs: `({}) as Type`
|
|
6
|
+
* - Promise.resolve() placeholders
|
|
7
|
+
* - Hardcoded stub returns
|
|
8
|
+
* - Placeholder comments
|
|
9
|
+
*
|
|
10
|
+
* False-positive reduction: the check walks the AST for context to skip:
|
|
11
|
+
* - Promise.resolve() in lifecycle methods (destroy/dispose/close/shutdown/cleanup)
|
|
12
|
+
* - Promise.resolve() inside conditional blocks (guard clauses)
|
|
13
|
+
* - Promise.resolve() in functions with substantive statements
|
|
14
|
+
* - { success: true, data: [] } inside conditional branches or functions with multiple returns
|
|
15
|
+
* - ({}) as T where T is a generic type parameter
|
|
16
|
+
* - ({}) as T used as Proxy target
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Check: quality/stubbed-implementation-detection
|
|
20
|
+
*
|
|
21
|
+
* Detects incomplete or placeholder implementations.
|
|
22
|
+
*/
|
|
23
|
+
export declare const stubbedImplementationDetection: import("@opensip-cli/fitness").Check;
|
|
24
|
+
//# sourceMappingURL=stubbed-implementation-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stubbed-implementation-detection.d.ts","sourceRoot":"","sources":["../../../src/checks/quality/stubbed-implementation-detection.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAgUH;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,sCA8EzC,CAAC"}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// @fitness-ignore-file unused-config-options -- Config options reserved for future use or environment-specific
|
|
2
|
+
// @fitness-ignore-file stubbed-implementation-detection -- longDescription documents the patterns this check detects, triggering self-detection
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Stubbed Implementation Detection Check
|
|
5
|
+
*
|
|
6
|
+
* Detects patterns indicating incomplete or placeholder implementations:
|
|
7
|
+
* - Empty object stubs: `({}) as Type`
|
|
8
|
+
* - Promise.resolve() placeholders
|
|
9
|
+
* - Hardcoded stub returns
|
|
10
|
+
* - Placeholder comments
|
|
11
|
+
*
|
|
12
|
+
* False-positive reduction: the check walks the AST for context to skip:
|
|
13
|
+
* - Promise.resolve() in lifecycle methods (destroy/dispose/close/shutdown/cleanup)
|
|
14
|
+
* - Promise.resolve() inside conditional blocks (guard clauses)
|
|
15
|
+
* - Promise.resolve() in functions with substantive statements
|
|
16
|
+
* - { success: true, data: [] } inside conditional branches or functions with multiple returns
|
|
17
|
+
* - ({}) as T where T is a generic type parameter
|
|
18
|
+
* - ({}) as T used as Proxy target
|
|
19
|
+
*/
|
|
20
|
+
import { defineCheck, isTestFile } from '@opensip-cli/fitness';
|
|
21
|
+
import { findEnclosingFunctionBody, getEnclosingFunctionName, getSharedSourceFile, isInsideConditionalBlock, } from '@opensip-cli/lang-typescript';
|
|
22
|
+
import * as ts from 'typescript';
|
|
23
|
+
/** Placeholder comment patterns - using explicit RegExp constructors for safety */
|
|
24
|
+
const PLACEHOLDER_PATTERNS = [
|
|
25
|
+
new RegExp(String.raw `\/\/\s*Placeholder\s*(implementation|for|:|-)`, 'i'),
|
|
26
|
+
new RegExp(String.raw `\/\/\s*STUB\s*[:|-]`, 'i'),
|
|
27
|
+
new RegExp(String.raw `\/\/\s*Not\s+implemented`, 'i'),
|
|
28
|
+
];
|
|
29
|
+
/** Primitive types that should be skipped when checking empty object stubs */
|
|
30
|
+
const PRIMITIVE_TYPES = new Set([
|
|
31
|
+
'string',
|
|
32
|
+
'number',
|
|
33
|
+
'boolean',
|
|
34
|
+
'null',
|
|
35
|
+
'undefined',
|
|
36
|
+
'void',
|
|
37
|
+
'never',
|
|
38
|
+
'unknown',
|
|
39
|
+
]);
|
|
40
|
+
/** Pattern for Promise.resolve stubs - matches exact form without backtracking */
|
|
41
|
+
const PROMISE_RESOLVE_PATTERN = new RegExp(String.raw `^Promise\.resolve\((undefined|null|void 0)?\)$`);
|
|
42
|
+
/** Pattern for hardcoded stub returns with success: true */
|
|
43
|
+
const STUB_RETURN_PATTERN = new RegExp(String.raw `success:\s*true[\s\S]*data:\s*(\[\]|null|\{\})`, 'i');
|
|
44
|
+
/** Lifecycle teardown method names that commonly return Promise.resolve() */
|
|
45
|
+
const LIFECYCLE_METHOD_NAMES = new Set(['destroy', 'dispose', 'close', 'shutdown', 'cleanup']);
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// AST HELPER UTILITIES
|
|
48
|
+
// =============================================================================
|
|
49
|
+
// Function-scope helpers (findEnclosingFunctionBody, getEnclosingFunctionName,
|
|
50
|
+
// isInsideConditionalBlock) are imported from @opensip-cli/lang-typescript.
|
|
51
|
+
/**
|
|
52
|
+
* Check whether a function body contains substantive statements beyond a single return.
|
|
53
|
+
* "Substantive" means assignments, method calls, logging, variable declarations with initializers, etc.
|
|
54
|
+
*/
|
|
55
|
+
function functionBodyHasSubstantiveStatements(body, returnNode) {
|
|
56
|
+
for (const stmt of body.statements) {
|
|
57
|
+
// Skip the return statement itself
|
|
58
|
+
if (stmt === returnNode)
|
|
59
|
+
continue;
|
|
60
|
+
// Skip variable declarations without initializers (just type annotations)
|
|
61
|
+
if (ts.isVariableStatement(stmt)) {
|
|
62
|
+
const hasInitializer = stmt.declarationList.declarations.some((d) => d.initializer !== undefined);
|
|
63
|
+
if (hasInitializer)
|
|
64
|
+
return true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Any other statement (expression statement, if, for, etc.) is substantive
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Recursively check if a node contains an await or call expression before a given position.
|
|
74
|
+
*/
|
|
75
|
+
function containsAwaitOrCallBefore(node, returnPos) {
|
|
76
|
+
if (node.getStart() >= returnPos)
|
|
77
|
+
return false;
|
|
78
|
+
if (ts.isAwaitExpression(node))
|
|
79
|
+
return true;
|
|
80
|
+
if (ts.isCallExpression(node) && node.getStart() < returnPos)
|
|
81
|
+
return true;
|
|
82
|
+
let found = false;
|
|
83
|
+
ts.forEachChild(node, (child) => {
|
|
84
|
+
if (!found && containsAwaitOrCallBefore(child, returnPos)) {
|
|
85
|
+
found = true;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return found;
|
|
89
|
+
}
|
|
90
|
+
function functionBodyHasAwaitOrCallsBefore(body, returnNode) {
|
|
91
|
+
const returnPos = returnNode.getStart();
|
|
92
|
+
for (const stmt of body.statements) {
|
|
93
|
+
if (stmt === returnNode)
|
|
94
|
+
break;
|
|
95
|
+
if (containsAwaitOrCallBefore(stmt, returnPos))
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check whether the function has multiple return statements (indicating branches, not a stub).
|
|
102
|
+
*/
|
|
103
|
+
function functionHasMultipleReturns(body) {
|
|
104
|
+
let returnCount = 0;
|
|
105
|
+
const visit = (node) => {
|
|
106
|
+
if (ts.isReturnStatement(node)) {
|
|
107
|
+
returnCount++;
|
|
108
|
+
}
|
|
109
|
+
// Do not descend into nested functions
|
|
110
|
+
if (ts.isFunctionDeclaration(node) ||
|
|
111
|
+
ts.isFunctionExpression(node) ||
|
|
112
|
+
ts.isArrowFunction(node) ||
|
|
113
|
+
ts.isMethodDeclaration(node)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
ts.forEachChild(node, visit);
|
|
117
|
+
};
|
|
118
|
+
for (const stmt of body.statements) {
|
|
119
|
+
visit(stmt);
|
|
120
|
+
}
|
|
121
|
+
return returnCount > 1;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check whether a node's type parameters include the given type name.
|
|
125
|
+
*/
|
|
126
|
+
function nodeHasTypeParameter(node, typeText, sourceFile) {
|
|
127
|
+
if (!node.typeParameters)
|
|
128
|
+
return false;
|
|
129
|
+
return node.typeParameters.some((tp) => tp.name.getText(sourceFile) === typeText);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check whether the type in an as-expression refers to a generic type parameter
|
|
133
|
+
* rather than a concrete type. Walks up the AST to find enclosing function/class
|
|
134
|
+
* type parameters and checks if the cast target matches one.
|
|
135
|
+
*/
|
|
136
|
+
function isGenericTypeParameter(typeText, node, sourceFile) {
|
|
137
|
+
let current = node.parent;
|
|
138
|
+
while (!ts.isSourceFile(current)) {
|
|
139
|
+
// Check function-like or class declarations for type parameters
|
|
140
|
+
if ((ts.isFunctionDeclaration(current) ||
|
|
141
|
+
ts.isMethodDeclaration(current) ||
|
|
142
|
+
ts.isFunctionExpression(current) ||
|
|
143
|
+
ts.isArrowFunction(current) ||
|
|
144
|
+
ts.isClassDeclaration(current)) &&
|
|
145
|
+
nodeHasTypeParameter(current, typeText, sourceFile)) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
current = current.parent;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Check whether the as-expression is the target argument of a `new Proxy(...)` call.
|
|
154
|
+
*/
|
|
155
|
+
function isProxyTarget(node, sourceFile) {
|
|
156
|
+
const parent = node.parent;
|
|
157
|
+
// Direct parent should be a NewExpression: new Proxy({} as T, handler)
|
|
158
|
+
if (ts.isNewExpression(parent)) {
|
|
159
|
+
const exprText = parent.expression.getText(sourceFile);
|
|
160
|
+
if (exprText === 'Proxy' && parent.arguments?.[0] === node) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Or it could be wrapped in parentheses: new Proxy(({} as T), handler)
|
|
165
|
+
if (ts.isParenthesizedExpression(parent)) {
|
|
166
|
+
return isProxyTarget(parent, sourceFile);
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
// =============================================================================
|
|
171
|
+
// CHECK FUNCTIONS
|
|
172
|
+
// =============================================================================
|
|
173
|
+
function checkEmptyObjectStub(options) {
|
|
174
|
+
const { node, sourceFile } = options;
|
|
175
|
+
if (!ts.isAsExpression(node) && !ts.isTypeAssertionExpression(node))
|
|
176
|
+
return null;
|
|
177
|
+
const expression = node.expression;
|
|
178
|
+
if (!ts.isObjectLiteralExpression(expression) || expression.properties.length > 0)
|
|
179
|
+
return null;
|
|
180
|
+
const typeText = node.type.getText(sourceFile);
|
|
181
|
+
// Skip primitives and Record types
|
|
182
|
+
const isPrimitive = PRIMITIVE_TYPES.has(typeText);
|
|
183
|
+
const isRecordType = typeText.startsWith('Record<') && typeText.endsWith('>');
|
|
184
|
+
if (isPrimitive || isRecordType)
|
|
185
|
+
return null;
|
|
186
|
+
// Skip if type is a generic type parameter (e.g., T in deepMerge<T>)
|
|
187
|
+
if (isGenericTypeParameter(typeText, node, sourceFile))
|
|
188
|
+
return null;
|
|
189
|
+
// Skip if this is the target of a new Proxy(...) call
|
|
190
|
+
if (isProxyTarget(node, sourceFile))
|
|
191
|
+
return null;
|
|
192
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
193
|
+
const lineNum = line + 1;
|
|
194
|
+
const matchText = node.getText(sourceFile);
|
|
195
|
+
return {
|
|
196
|
+
line: lineNum,
|
|
197
|
+
column: character + 1,
|
|
198
|
+
message: `Empty object stub: ({}) as ${typeText} - will crash at runtime`,
|
|
199
|
+
severity: 'error',
|
|
200
|
+
suggestion: `Implement the actual ${typeText} object with all required properties, or use a factory function/builder to create valid instances`,
|
|
201
|
+
match: matchText,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function checkPromiseResolveStub(options) {
|
|
205
|
+
const { node, sourceFile } = options;
|
|
206
|
+
if (!ts.isReturnStatement(node) || !node.expression || !ts.isCallExpression(node.expression))
|
|
207
|
+
return null;
|
|
208
|
+
const callText = node.expression.getText(sourceFile);
|
|
209
|
+
if (!PROMISE_RESOLVE_PATTERN.test(callText))
|
|
210
|
+
return null;
|
|
211
|
+
// Skip if inside a conditional block (guard clause / early return)
|
|
212
|
+
if (isInsideConditionalBlock(node))
|
|
213
|
+
return null;
|
|
214
|
+
// Skip if enclosing function is a lifecycle teardown method
|
|
215
|
+
const funcName = getEnclosingFunctionName(node, sourceFile);
|
|
216
|
+
if (funcName && LIFECYCLE_METHOD_NAMES.has(funcName))
|
|
217
|
+
return null;
|
|
218
|
+
// Skip if the function body has substantive statements (real work + async wrapping)
|
|
219
|
+
const body = findEnclosingFunctionBody(node);
|
|
220
|
+
if (body && functionBodyHasSubstantiveStatements(body, node))
|
|
221
|
+
return null;
|
|
222
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
223
|
+
return {
|
|
224
|
+
line: line + 1,
|
|
225
|
+
column: character + 1,
|
|
226
|
+
message: 'Placeholder return: Promise.resolve() - method does nothing',
|
|
227
|
+
severity: 'error',
|
|
228
|
+
suggestion: 'Implement the actual async logic for this method, or if this is intentional no-op, add a comment explaining why',
|
|
229
|
+
match: callText,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function checkHardcodedStubReturn(options) {
|
|
233
|
+
const { node, sourceFile } = options;
|
|
234
|
+
if (!ts.isReturnStatement(node) ||
|
|
235
|
+
!node.expression ||
|
|
236
|
+
!ts.isObjectLiteralExpression(node.expression))
|
|
237
|
+
return null;
|
|
238
|
+
const returnText = node.expression.getText(sourceFile);
|
|
239
|
+
if (!STUB_RETURN_PATTERN.test(returnText))
|
|
240
|
+
return null;
|
|
241
|
+
// Skip if inside a conditional block (branch return, not the only path)
|
|
242
|
+
if (isInsideConditionalBlock(node))
|
|
243
|
+
return null;
|
|
244
|
+
// Skip if the function has multiple return statements (indicates branching logic)
|
|
245
|
+
const body = findEnclosingFunctionBody(node);
|
|
246
|
+
if (body && functionHasMultipleReturns(body))
|
|
247
|
+
return null;
|
|
248
|
+
// Skip if the function body contains await expressions or calls before this return
|
|
249
|
+
if (body && functionBodyHasAwaitOrCallsBefore(body, node))
|
|
250
|
+
return null;
|
|
251
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
252
|
+
return {
|
|
253
|
+
line: line + 1,
|
|
254
|
+
column: character + 1,
|
|
255
|
+
message: 'Hardcoded stub return: { success: true, data: [] }',
|
|
256
|
+
severity: 'warning',
|
|
257
|
+
suggestion: 'Replace this stub with actual implementation that fetches/processes real data',
|
|
258
|
+
match: returnText.slice(0, 80),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function checkLineForPlaceholder(line, lineNum) {
|
|
262
|
+
for (const pattern of PLACEHOLDER_PATTERNS) {
|
|
263
|
+
if (pattern.test(line)) {
|
|
264
|
+
return {
|
|
265
|
+
line: lineNum,
|
|
266
|
+
column: 0,
|
|
267
|
+
message: 'Placeholder comment indicates unfinished implementation',
|
|
268
|
+
severity: 'warning',
|
|
269
|
+
suggestion: 'Complete the implementation or create a ticket to track this work, then remove the placeholder comment',
|
|
270
|
+
match: line.trim(),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Check: quality/stubbed-implementation-detection
|
|
278
|
+
*
|
|
279
|
+
* Detects incomplete or placeholder implementations.
|
|
280
|
+
*/
|
|
281
|
+
export const stubbedImplementationDetection = defineCheck({
|
|
282
|
+
id: '12218d58-5dea-4aba-ba7b-fc1822d03ec4',
|
|
283
|
+
slug: 'stubbed-implementation-detection',
|
|
284
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
285
|
+
contentFilter: 'raw',
|
|
286
|
+
confidence: 'high',
|
|
287
|
+
description: 'Detects incomplete/placeholder implementations',
|
|
288
|
+
longDescription: `**Purpose:** Detects incomplete or placeholder implementations that will fail at runtime or silently do nothing.
|
|
289
|
+
|
|
290
|
+
**Detects:**
|
|
291
|
+
- Empty object stubs: \`({}) as Type\` where Type is not a primitive or Record (will crash at runtime)
|
|
292
|
+
- Placeholder returns: \`return Promise.resolve(undefined|null|void 0)\` indicating a no-op async method
|
|
293
|
+
- Hardcoded stub returns: \`return { success: true, data: []|null|{} }\` patterns
|
|
294
|
+
- Placeholder comments: \`// Placeholder implementation\`, \`// STUB:\`, \`// Not implemented\`
|
|
295
|
+
|
|
296
|
+
**Skips (not false positives):**
|
|
297
|
+
- Test files (\`*.test.ts\`, files under \`__tests__/\`, \`__fixtures__/\`) — stub patterns in tests are intentional
|
|
298
|
+
- Promise.resolve() in lifecycle methods (destroy, dispose, close, shutdown, cleanup)
|
|
299
|
+
- Promise.resolve() inside conditional blocks (guard clauses)
|
|
300
|
+
- Promise.resolve() in functions with substantive statements (real synchronous work)
|
|
301
|
+
- Hardcoded stub returns inside conditional branches or functions with multiple returns
|
|
302
|
+
- Hardcoded stub returns in functions with await/call expressions before the return
|
|
303
|
+
- \`({}) as T\` where T is a generic type parameter
|
|
304
|
+
- \`({}) as T\` used as a Proxy target
|
|
305
|
+
|
|
306
|
+
**Why it matters:** Stubbed implementations pass type checks but fail at runtime. Detecting them early prevents production crashes and silent data loss.
|
|
307
|
+
|
|
308
|
+
**Scope:** General best practice. Analyzes each file individually (\`analyze\`). Uses TypeScript AST parsing on production files (excludes tests and fixtures).`,
|
|
309
|
+
tags: ['quality', 'code-quality', 'best-practices'],
|
|
310
|
+
fileTypes: ['ts', 'tsx'],
|
|
311
|
+
analyze(content, filePath) {
|
|
312
|
+
const violations = [];
|
|
313
|
+
// Test files routinely use stub patterns (empty type-asserted objects,
|
|
314
|
+
// Promise.resolve()) as intentional fixtures or compile-time drift
|
|
315
|
+
// detectors. Skip AST stub detection in tests; placeholder-comment
|
|
316
|
+
// scanning below is also already test-aware.
|
|
317
|
+
const inTestFile = isTestFile(filePath);
|
|
318
|
+
try {
|
|
319
|
+
const sourceFile = getSharedSourceFile(filePath, content);
|
|
320
|
+
if (!sourceFile)
|
|
321
|
+
return [];
|
|
322
|
+
const visit = (node) => {
|
|
323
|
+
const nodeOptions = { node, sourceFile };
|
|
324
|
+
if (!inTestFile) {
|
|
325
|
+
const emptyStub = checkEmptyObjectStub(nodeOptions);
|
|
326
|
+
if (emptyStub)
|
|
327
|
+
violations.push(emptyStub);
|
|
328
|
+
const promiseStub = checkPromiseResolveStub(nodeOptions);
|
|
329
|
+
if (promiseStub)
|
|
330
|
+
violations.push(promiseStub);
|
|
331
|
+
const hardcodedStub = checkHardcodedStubReturn(nodeOptions);
|
|
332
|
+
if (hardcodedStub)
|
|
333
|
+
violations.push(hardcodedStub);
|
|
334
|
+
}
|
|
335
|
+
ts.forEachChild(node, visit);
|
|
336
|
+
};
|
|
337
|
+
visit(sourceFile);
|
|
338
|
+
// Check for placeholder comments (skip test files — placeholder comments
|
|
339
|
+
// in tests are intentional)
|
|
340
|
+
if (!isTestFile(filePath)) {
|
|
341
|
+
const lines = content.split('\n');
|
|
342
|
+
for (const [i, line] of lines.entries()) {
|
|
343
|
+
const placeholder = checkLineForPlaceholder(line ?? '', i + 1);
|
|
344
|
+
if (placeholder)
|
|
345
|
+
violations.push(placeholder);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// @swallow-ok Skip files that fail to parse
|
|
351
|
+
}
|
|
352
|
+
return violations;
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
//# sourceMappingURL=stubbed-implementation-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stubbed-implementation-detection.js","sourceRoot":"","sources":["../../../src/checks/quality/stubbed-implementation-detection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unused Configuration Options Check
|
|
3
|
+
*
|
|
4
|
+
* Detects configuration properties that are defined but never accessed.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Check: quality/unused-config-options
|
|
8
|
+
*
|
|
9
|
+
* Detects configuration properties defined but never accessed.
|
|
10
|
+
*/
|
|
11
|
+
export declare const unusedConfigOptions: import("@opensip-cli/fitness").Check;
|
|
12
|
+
//# sourceMappingURL=unused-config-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unused-config-options.d.ts","sourceRoot":"","sources":["../../../src/checks/quality/unused-config-options.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AA0PH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,sCA2B9B,CAAC"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// @fitness-ignore-file toctou-race-condition -- TOCTOU acceptable in this non-concurrent context
|
|
2
|
+
// @fitness-ignore-file unused-config-options -- Config options reserved for future use or environment-specific
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Unused Configuration Options Check
|
|
5
|
+
*
|
|
6
|
+
* Detects configuration properties that are defined but never accessed.
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from '@opensip-cli/core';
|
|
9
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
10
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
11
|
+
import * as ts from 'typescript';
|
|
12
|
+
/**
|
|
13
|
+
* Common property names that are ubiquitous and would cause false positives
|
|
14
|
+
*/
|
|
15
|
+
const COMMON_PROPERTY_NAMES = new Set([
|
|
16
|
+
// Very common config properties used everywhere
|
|
17
|
+
'enabled',
|
|
18
|
+
'disabled',
|
|
19
|
+
'timeout',
|
|
20
|
+
'retries',
|
|
21
|
+
'debug',
|
|
22
|
+
'verbose',
|
|
23
|
+
'name',
|
|
24
|
+
'type',
|
|
25
|
+
'id',
|
|
26
|
+
'key',
|
|
27
|
+
'value',
|
|
28
|
+
'data',
|
|
29
|
+
'options',
|
|
30
|
+
'config',
|
|
31
|
+
'settings',
|
|
32
|
+
'port',
|
|
33
|
+
'host',
|
|
34
|
+
'url',
|
|
35
|
+
'path',
|
|
36
|
+
'level',
|
|
37
|
+
'mode',
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Paths where this check should not run (CLI, scripts, test utilities)
|
|
41
|
+
*/
|
|
42
|
+
const NON_CONFIG_CONSUMER_PATTERNS = [
|
|
43
|
+
/\/cli\//,
|
|
44
|
+
/\/scripts\//,
|
|
45
|
+
/\/bin\//,
|
|
46
|
+
/__tests__\//,
|
|
47
|
+
/\.test\./,
|
|
48
|
+
/\.spec\./,
|
|
49
|
+
/\/testing\//,
|
|
50
|
+
// Type definition files only
|
|
51
|
+
/types\.ts$/,
|
|
52
|
+
/interfaces\.ts$/,
|
|
53
|
+
/index\.d\.ts$/,
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Check if a path should be excluded from analysis
|
|
57
|
+
*/
|
|
58
|
+
function shouldExcludePath(filePath) {
|
|
59
|
+
return NON_CONFIG_CONSUMER_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if interface is a Config/Options interface.
|
|
63
|
+
*/
|
|
64
|
+
function isConfigInterface(interfaceName) {
|
|
65
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
66
|
+
return interfaceName.includes('Config') || interfaceName.includes('Options');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Extract property from interface member.
|
|
70
|
+
*/
|
|
71
|
+
function extractPropertyFromMember(member, sourceFile, interfaceName, filePath) {
|
|
72
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
73
|
+
if (!ts.isPropertySignature(member))
|
|
74
|
+
return null;
|
|
75
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
76
|
+
if (!ts.isIdentifier(member.name))
|
|
77
|
+
return null;
|
|
78
|
+
const propName = member.name.text;
|
|
79
|
+
// Skip common property names that would cause many false positives
|
|
80
|
+
if (COMMON_PROPERTY_NAMES.has(propName))
|
|
81
|
+
return null;
|
|
82
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(member.getStart());
|
|
83
|
+
return {
|
|
84
|
+
name: propName,
|
|
85
|
+
interfaceName,
|
|
86
|
+
filePath,
|
|
87
|
+
line: line + 1,
|
|
88
|
+
isOptional: member.questionToken !== undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Extract config properties from interface members
|
|
93
|
+
*/
|
|
94
|
+
function extractInterfaceProperties(node, sourceFile, filePath) {
|
|
95
|
+
const properties = [];
|
|
96
|
+
const interfaceName = node.name.text;
|
|
97
|
+
for (const member of node.members) {
|
|
98
|
+
const prop = extractPropertyFromMember(member, sourceFile, interfaceName, filePath);
|
|
99
|
+
if (!prop)
|
|
100
|
+
continue;
|
|
101
|
+
properties.push(prop);
|
|
102
|
+
}
|
|
103
|
+
return properties;
|
|
104
|
+
}
|
|
105
|
+
function isConfigFilePath(filePath) {
|
|
106
|
+
return filePath.includes('config') || filePath.includes('Config');
|
|
107
|
+
}
|
|
108
|
+
async function extractConfigPropertiesFromFile(filePath, files) {
|
|
109
|
+
// @lazy-ok -- visit function's conditionals are not pre-await validation guards
|
|
110
|
+
const content = await files.read(filePath);
|
|
111
|
+
const sourceFile = getSharedSourceFile(filePath, content);
|
|
112
|
+
/* v8 ignore next -- defensive guard */
|
|
113
|
+
if (!sourceFile)
|
|
114
|
+
return [];
|
|
115
|
+
const properties = [];
|
|
116
|
+
const visit = (node) => {
|
|
117
|
+
ts.forEachChild(node, visit);
|
|
118
|
+
if (!ts.isInterfaceDeclaration(node))
|
|
119
|
+
return;
|
|
120
|
+
/* v8 ignore next -- defensive AST/type guard */
|
|
121
|
+
if (!isConfigInterface(node.name.text))
|
|
122
|
+
return;
|
|
123
|
+
properties.push(...extractInterfaceProperties(node, sourceFile, filePath));
|
|
124
|
+
};
|
|
125
|
+
void visit(sourceFile);
|
|
126
|
+
return properties;
|
|
127
|
+
}
|
|
128
|
+
async function collectConfigProperties(files) {
|
|
129
|
+
logger.debug({
|
|
130
|
+
evt: 'fitness.collect_config_properties.start',
|
|
131
|
+
msg: 'Collecting config properties',
|
|
132
|
+
});
|
|
133
|
+
const configProperties = [];
|
|
134
|
+
for (const filePath of files.paths) {
|
|
135
|
+
if (shouldExcludePath(filePath) || !isConfigFilePath(filePath))
|
|
136
|
+
continue;
|
|
137
|
+
try {
|
|
138
|
+
// @fitness-ignore-next-line performance-anti-patterns -- sequential file reading to control memory; FileAccessor is lazy
|
|
139
|
+
const props = await extractConfigPropertiesFromFile(filePath, files);
|
|
140
|
+
configProperties.push(...props);
|
|
141
|
+
/* v8 ignore next 1 -- defensive catch: parse failures already handled */
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// @swallow-ok Skip unreadable files
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
logger.debug({
|
|
148
|
+
evt: 'fitness.collect_config_properties.complete',
|
|
149
|
+
count: configProperties.length,
|
|
150
|
+
msg: 'Config properties collected',
|
|
151
|
+
});
|
|
152
|
+
return configProperties;
|
|
153
|
+
}
|
|
154
|
+
async function countPropertyAccesses(files) {
|
|
155
|
+
logger.debug({
|
|
156
|
+
evt: 'fitness.count_property_accesses.start',
|
|
157
|
+
msg: 'Counting property accesses across files',
|
|
158
|
+
});
|
|
159
|
+
const accessCounts = new Map();
|
|
160
|
+
for (const filePath of files.paths) {
|
|
161
|
+
try {
|
|
162
|
+
// @fitness-ignore-next-line performance-anti-patterns -- sequential file reading to control memory; FileAccessor is lazy
|
|
163
|
+
const content = await files.read(filePath);
|
|
164
|
+
const sourceFile = getSharedSourceFile(filePath, content);
|
|
165
|
+
/* v8 ignore next -- defensive guard */
|
|
166
|
+
if (!sourceFile)
|
|
167
|
+
continue;
|
|
168
|
+
const visit = (node) => {
|
|
169
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
170
|
+
const propertyName = node.name.text;
|
|
171
|
+
/* v8 ignore next -- defensive nullish fallback */
|
|
172
|
+
accessCounts.set(propertyName, (accessCounts.get(propertyName) ?? 0) + 1);
|
|
173
|
+
}
|
|
174
|
+
if (ts.isBindingElement(node) && ts.isIdentifier(node.name)) {
|
|
175
|
+
const propertyName = node.name.text;
|
|
176
|
+
/* v8 ignore next -- defensive nullish fallback */
|
|
177
|
+
accessCounts.set(propertyName, (accessCounts.get(propertyName) ?? 0) + 1);
|
|
178
|
+
}
|
|
179
|
+
ts.forEachChild(node, visit);
|
|
180
|
+
};
|
|
181
|
+
void visit(sourceFile);
|
|
182
|
+
/* v8 ignore next 1 -- defensive catch: parse failures already handled */
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// @swallow-ok Skip unreadable files
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return accessCounts;
|
|
189
|
+
}
|
|
190
|
+
function createViolationForUnusedProperty(prop) {
|
|
191
|
+
return {
|
|
192
|
+
line: prop.line,
|
|
193
|
+
column: 0,
|
|
194
|
+
message: `Config property '${prop.name}' in ${prop.interfaceName} is never accessed`,
|
|
195
|
+
severity: 'warning',
|
|
196
|
+
suggestion: `Remove unused config property '${prop.name}' from ${prop.interfaceName}, or implement code that uses this configuration option`,
|
|
197
|
+
match: prop.name,
|
|
198
|
+
filePath: prop.filePath,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function findUnusedProperties(configProperties, accessCounts) {
|
|
202
|
+
const violations = [];
|
|
203
|
+
for (const prop of configProperties) {
|
|
204
|
+
if (prop.isOptional)
|
|
205
|
+
continue;
|
|
206
|
+
/* v8 ignore next -- defensive nullish fallback */
|
|
207
|
+
const count = accessCounts.get(prop.name) ?? 0;
|
|
208
|
+
if (count === 0) {
|
|
209
|
+
violations.push(createViolationForUnusedProperty(prop));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return violations;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check: quality/unused-config-options
|
|
216
|
+
*
|
|
217
|
+
* Detects configuration properties defined but never accessed.
|
|
218
|
+
*/
|
|
219
|
+
export const unusedConfigOptions = defineCheck({
|
|
220
|
+
id: '09006e97-77fd-4a75-9a9a-d5ed0abb9d9f',
|
|
221
|
+
slug: 'unused-config-options',
|
|
222
|
+
scope: { languages: ['json', 'typescript', 'yaml'], concerns: ['config'] },
|
|
223
|
+
contentFilter: 'raw',
|
|
224
|
+
confidence: 'high',
|
|
225
|
+
description: 'Detects configuration properties defined but never accessed',
|
|
226
|
+
longDescription: `**Purpose:** Detects configuration properties that are defined in Config/Options interfaces but never accessed anywhere in the codebase.
|
|
227
|
+
|
|
228
|
+
**Detects:**
|
|
229
|
+
- Required (non-optional) properties in interfaces containing \`Config\` or \`Options\` in their name
|
|
230
|
+
- Properties with zero \`PropertyAccessExpression\` or \`BindingElement\` references across all scanned files
|
|
231
|
+
- Excludes common property names (\`enabled\`, \`timeout\`, \`port\`, \`host\`, etc.) to reduce false positives
|
|
232
|
+
|
|
233
|
+
**Why it matters:** Unused config properties add cognitive overhead and suggest incomplete implementations or abandoned features that should be cleaned up.
|
|
234
|
+
|
|
235
|
+
**Scope:** General best practice. Cross-file analysis (\`analyzeAll\`). Scans config files for property definitions, then counts access patterns across all production files.`,
|
|
236
|
+
tags: ['quality', 'code-quality', 'maintainability'],
|
|
237
|
+
fileTypes: ['ts', 'tsx'],
|
|
238
|
+
async analyzeAll(files) {
|
|
239
|
+
// @fitness-ignore-next-line async-waterfall-detection -- Both scan all files independently; parallelizing would double peak memory by loading file contents twice concurrently
|
|
240
|
+
const configProperties = await collectConfigProperties(files);
|
|
241
|
+
const accessCounts = await countPropertyAccesses(files);
|
|
242
|
+
return findUnusedProperties(configProperties, accessCounts);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
//# sourceMappingURL=unused-config-options.js.map
|