@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,451 @@
|
|
|
1
|
+
// @fitness-ignore-file throws-documentation -- Functions throw self-documenting typed errors
|
|
2
|
+
// @fitness-ignore-file toctou-race-condition -- TOCTOU acceptable in this non-concurrent context
|
|
3
|
+
// @fitness-ignore-file file-length-limit -- complex check with tightly coupled hash/normalization/scoring logic; splitting would risk losing the duplicate-detection contract
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Duplicate Utility Functions check
|
|
6
|
+
*
|
|
7
|
+
* Detects duplicate utility functions that should be consolidated.
|
|
8
|
+
* Flags TWO types of issues:
|
|
9
|
+
* 1. Identical implementations - true duplicates that must be deduplicated
|
|
10
|
+
* 2. Same-named functions with different implementations - consolidation opportunities
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { basename, dirname } from 'node:path';
|
|
14
|
+
import { defineCheck, getCheckConfig, } from '@opensip-cli/fitness';
|
|
15
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
16
|
+
import * as ts from 'typescript';
|
|
17
|
+
/**
|
|
18
|
+
* Common utility function name patterns
|
|
19
|
+
*/
|
|
20
|
+
const UTILITY_PATTERNS = [
|
|
21
|
+
/^format[A-Z]/, // formatDate, formatCurrency
|
|
22
|
+
/^parse[A-Z]/, // parseJson, parseDate
|
|
23
|
+
/^is[A-Z]/, // isValid, isEmpty
|
|
24
|
+
/^has[A-Z]/, // hasValue, hasKey
|
|
25
|
+
/^to[A-Z]/, // toString, toNumber
|
|
26
|
+
/^get[A-Z]/, // getValue, getDefault
|
|
27
|
+
/^validate[A-Z]/, // validateEmail, validatePhone
|
|
28
|
+
/^sanitize[A-Z]/, // sanitizeInput, sanitizeHtml
|
|
29
|
+
/^normalize[A-Z]/, // normalizeUrl, normalizeText
|
|
30
|
+
/^debounce/,
|
|
31
|
+
/^throttle/,
|
|
32
|
+
/^sleep/,
|
|
33
|
+
/^delay/,
|
|
34
|
+
/^retry/,
|
|
35
|
+
/^clamp/,
|
|
36
|
+
/^range/,
|
|
37
|
+
/^chunk/,
|
|
38
|
+
/^unique/,
|
|
39
|
+
/^flatten/,
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Minimum function body length (characters) to consider for duplicate detection.
|
|
43
|
+
* Very short functions (1-2 lines) are often trivial and not worth flagging.
|
|
44
|
+
*/
|
|
45
|
+
const MIN_FUNCTION_BODY_LENGTH = 50;
|
|
46
|
+
/**
|
|
47
|
+
* Functions that are intentionally domain-specific and should NOT be flagged
|
|
48
|
+
* as duplicates. Limited to genuinely generic identifiers — config / factory
|
|
49
|
+
* / logger / common type-guard names — that almost any TS codebase will hit.
|
|
50
|
+
*
|
|
51
|
+
* Project-specific names (e.g. opensip's `getCurrentCorrelationId`,
|
|
52
|
+
* `formatDuration`, `getRemoteUrl`, `sanitizeForPrompt`) belong in a recipe's
|
|
53
|
+
* `checks.config['duplicate-utility-functions'].additionalDomainSpecificFunctions`
|
|
54
|
+
* block. The check reads that list via {@link getCheckConfig} and merges it
|
|
55
|
+
* with these defaults.
|
|
56
|
+
*/
|
|
57
|
+
const DOMAIN_SPECIFIC_FUNCTIONS = new Set([
|
|
58
|
+
// Config / factory pattern - each domain has its own configuration
|
|
59
|
+
'getConfig',
|
|
60
|
+
'getDefaultConfig',
|
|
61
|
+
'getContainer',
|
|
62
|
+
'getFactory',
|
|
63
|
+
// Logger / shared singletons
|
|
64
|
+
'getLogger',
|
|
65
|
+
// Common predicates that have multiple legitimate definitions
|
|
66
|
+
'isPlainObject',
|
|
67
|
+
'isStringArray',
|
|
68
|
+
'isCommentLine',
|
|
69
|
+
'isTestFile',
|
|
70
|
+
'isValidEmail',
|
|
71
|
+
// Common formatter / parser names that vary by input shape
|
|
72
|
+
'formatDate',
|
|
73
|
+
'formatTimestamp',
|
|
74
|
+
'parseArgs',
|
|
75
|
+
// Common validation entry points
|
|
76
|
+
'validateConfig',
|
|
77
|
+
'validateSchema',
|
|
78
|
+
// Common error-message helper
|
|
79
|
+
'getErrorMessage',
|
|
80
|
+
// AST predicates / shared kernel helpers — each layer (engine, lang adapter,
|
|
81
|
+
// graph adapter) legitimately defines its own implementation tuned to its
|
|
82
|
+
// node shape; the architecture rules prevent cross-layer imports.
|
|
83
|
+
'isPropertyAccess',
|
|
84
|
+
'isFunctionLike',
|
|
85
|
+
'getSharedSourceFile',
|
|
86
|
+
'getLineNumber',
|
|
87
|
+
'isReturnValueDiscarded',
|
|
88
|
+
// Plugin / package discovery (mirrored in fitness + simulation discovery walkers)
|
|
89
|
+
'hasPackageJson',
|
|
90
|
+
// Language-adapter parsers and dir normalizers — one per graph-* pack
|
|
91
|
+
// (graph-go, graph-java, graph-python, graph-rust, graph-typescript) by
|
|
92
|
+
// design; cross-pack imports are forbidden by .config/dependency-cruiser.cjs.
|
|
93
|
+
'normalizeProjectDir',
|
|
94
|
+
'parseProject',
|
|
95
|
+
// Tokenizer helper present in several language-adapter strip-comment passes
|
|
96
|
+
'isIdentChar',
|
|
97
|
+
// Assertion validation — fitness engine + simulation engine each own one
|
|
98
|
+
'validateAssertions',
|
|
99
|
+
]);
|
|
100
|
+
/**
|
|
101
|
+
* Build the effective domain-specific set by merging built-in defaults with
|
|
102
|
+
* the recipe-provided augmentation for `duplicate-utility-functions`.
|
|
103
|
+
*/
|
|
104
|
+
function buildEffectiveDomainSpecificSet() {
|
|
105
|
+
const cfg = getCheckConfig('duplicate-utility-functions');
|
|
106
|
+
if (!cfg.additionalDomainSpecificFunctions ||
|
|
107
|
+
cfg.additionalDomainSpecificFunctions.length === 0) {
|
|
108
|
+
return DOMAIN_SPECIFIC_FUNCTIONS;
|
|
109
|
+
}
|
|
110
|
+
const merged = new Set(DOMAIN_SPECIFIC_FUNCTIONS);
|
|
111
|
+
for (const name of cfg.additionalDomainSpecificFunctions)
|
|
112
|
+
merged.add(name);
|
|
113
|
+
return merged;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get unique directories from a list of function locations
|
|
117
|
+
*/
|
|
118
|
+
function getUniqueDirectories(locations) {
|
|
119
|
+
/* v8 ignore next -- defensive guard */
|
|
120
|
+
if (!Array.isArray(locations)) {
|
|
121
|
+
return new Set();
|
|
122
|
+
}
|
|
123
|
+
return new Set(locations.map((l) => dirname(l.file)));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Flatten all locations from hash groups into a single array
|
|
127
|
+
*/
|
|
128
|
+
function flattenHashGroups(hashGroups) {
|
|
129
|
+
const allLocations = [];
|
|
130
|
+
if (hashGroups.size === 0) {
|
|
131
|
+
return allLocations;
|
|
132
|
+
}
|
|
133
|
+
for (const locations of hashGroups.values()) {
|
|
134
|
+
if (Array.isArray(locations) && locations.length > 0) {
|
|
135
|
+
allLocations.push(...locations);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return allLocations;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get first location from each hash group (unique implementations)
|
|
142
|
+
*/
|
|
143
|
+
function getFirstFromEachHashGroup(hashGroups) {
|
|
144
|
+
const uniqueImpls = [];
|
|
145
|
+
if (hashGroups.size === 0) {
|
|
146
|
+
return uniqueImpls;
|
|
147
|
+
}
|
|
148
|
+
for (const locations of hashGroups.values()) {
|
|
149
|
+
/* v8 ignore next -- defensive guard */
|
|
150
|
+
if (!Array.isArray(locations) || locations.length === 0) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const first = locations[0];
|
|
154
|
+
if (first) {
|
|
155
|
+
uniqueImpls.push(first);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return uniqueImpls;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Format other files for display in violation message
|
|
162
|
+
*/
|
|
163
|
+
function formatOtherFiles(locations) {
|
|
164
|
+
const otherFiles = locations
|
|
165
|
+
.slice(1)
|
|
166
|
+
.map((l) => basename(l.file))
|
|
167
|
+
.slice(0, 3);
|
|
168
|
+
const moreCount = locations.length > 4 ? ` (+${locations.length - 4} more)` : '';
|
|
169
|
+
return `${otherFiles.join(', ')}${moreCount}`;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Add a function to the functions-by-name collection
|
|
173
|
+
*/
|
|
174
|
+
function addFunctionToCollection(functionsByName, fn) {
|
|
175
|
+
let nameGroup = functionsByName.get(fn.name);
|
|
176
|
+
if (!nameGroup) {
|
|
177
|
+
nameGroup = new Map();
|
|
178
|
+
functionsByName.set(fn.name, nameGroup);
|
|
179
|
+
}
|
|
180
|
+
let hashGroup = nameGroup.get(fn.bodyHash);
|
|
181
|
+
if (!hashGroup) {
|
|
182
|
+
hashGroup = [];
|
|
183
|
+
nameGroup.set(fn.bodyHash, hashGroup);
|
|
184
|
+
}
|
|
185
|
+
hashGroup.push(fn);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Check if locations represent a valid duplicate across multiple directories.
|
|
189
|
+
*/
|
|
190
|
+
function isValidCrossDirectoryDuplicate(locations) {
|
|
191
|
+
/* v8 ignore next -- defensive guard */
|
|
192
|
+
if (!Array.isArray(locations) || locations.length <= 1) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
const locationDirs = getUniqueDirectories(locations);
|
|
196
|
+
return locationDirs.size > 1;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Remove single-line comments from code
|
|
200
|
+
*/
|
|
201
|
+
function removeSingleLineComments(code) {
|
|
202
|
+
return code
|
|
203
|
+
.split('\n')
|
|
204
|
+
.map((line) => {
|
|
205
|
+
const commentIndex = line.indexOf('//');
|
|
206
|
+
return commentIndex === -1 ? line : line.slice(0, commentIndex);
|
|
207
|
+
})
|
|
208
|
+
.join('\n');
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Remove multi-line comments from code
|
|
212
|
+
* Uses iterative approach to avoid regex backtracking issues.
|
|
213
|
+
*/
|
|
214
|
+
function removeMultiLineComments(code) {
|
|
215
|
+
let result = '';
|
|
216
|
+
let i = 0;
|
|
217
|
+
while (i < code.length) {
|
|
218
|
+
if (code[i] === '/' && code[i + 1] === '*') {
|
|
219
|
+
const endIndex = code.indexOf('*/', i + 2);
|
|
220
|
+
if (endIndex === -1) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
i = endIndex + 2;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
result += code[i];
|
|
227
|
+
i++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Normalize function body for comparison.
|
|
234
|
+
* Removes whitespace, comments, and normalizes identifiers.
|
|
235
|
+
*/
|
|
236
|
+
function normalizeBody(body) {
|
|
237
|
+
let normalized = body;
|
|
238
|
+
normalized = removeSingleLineComments(normalized);
|
|
239
|
+
normalized = removeMultiLineComments(normalized);
|
|
240
|
+
normalized = normalized.replaceAll(/\s+/g, ' ');
|
|
241
|
+
normalized = normalized.trim();
|
|
242
|
+
return normalized;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Generate a hash of the normalized function body.
|
|
246
|
+
* Uses SHA-256 for content-addressable deduplication (not for security purposes).
|
|
247
|
+
*/
|
|
248
|
+
function hashBody(body) {
|
|
249
|
+
const normalized = normalizeBody(body);
|
|
250
|
+
return createHash('sha256').update(normalized).digest('hex');
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Check if function name matches utility patterns. The `domainSpecific`
|
|
254
|
+
* argument is the effective allowlist (built-in defaults plus any
|
|
255
|
+
* recipe-supplied augmentation).
|
|
256
|
+
*/
|
|
257
|
+
function isUtilityFunction(name, domainSpecific) {
|
|
258
|
+
if (domainSpecific.has(name)) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return UTILITY_PATTERNS.some((pattern) => pattern.test(name));
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Extract utility functions from a file with their body hashes
|
|
265
|
+
*/
|
|
266
|
+
function extractUtilityFunctionsWithBody(filePath, content, domainSpecific) {
|
|
267
|
+
const functions = [];
|
|
268
|
+
try {
|
|
269
|
+
const sourceFile = getSharedSourceFile(filePath, content);
|
|
270
|
+
/* v8 ignore next -- defensive guard */
|
|
271
|
+
if (!sourceFile)
|
|
272
|
+
return [];
|
|
273
|
+
const visit = (node) => {
|
|
274
|
+
// Check function declarations
|
|
275
|
+
if (ts.isFunctionDeclaration(node) && node.name && node.body) {
|
|
276
|
+
const name = node.name.text;
|
|
277
|
+
if (isUtilityFunction(name, domainSpecific)) {
|
|
278
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
279
|
+
const body = node.body.getText(sourceFile);
|
|
280
|
+
functions.push({
|
|
281
|
+
name,
|
|
282
|
+
line: line + 1,
|
|
283
|
+
file: filePath,
|
|
284
|
+
bodyHash: hashBody(body),
|
|
285
|
+
bodyLength: body.length,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Check arrow functions assigned to variables
|
|
290
|
+
if (ts.isVariableDeclaration(node) &&
|
|
291
|
+
ts.isIdentifier(node.name) &&
|
|
292
|
+
node.initializer &&
|
|
293
|
+
ts.isArrowFunction(node.initializer)) {
|
|
294
|
+
const name = node.name.text;
|
|
295
|
+
if (isUtilityFunction(name, domainSpecific)) {
|
|
296
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
297
|
+
const body = node.initializer.body.getText(sourceFile);
|
|
298
|
+
functions.push({
|
|
299
|
+
name,
|
|
300
|
+
line: line + 1,
|
|
301
|
+
file: filePath,
|
|
302
|
+
bodyHash: hashBody(body),
|
|
303
|
+
bodyLength: body.length,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
ts.forEachChild(node, visit);
|
|
308
|
+
};
|
|
309
|
+
visit(sourceFile);
|
|
310
|
+
/* v8 ignore next 1 -- defensive catch: parse failures already handled */
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// @swallow-ok Ignore parse errors
|
|
314
|
+
}
|
|
315
|
+
return functions;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Create a violation for identical implementations
|
|
319
|
+
*/
|
|
320
|
+
function createIdenticalViolation(name, locations) {
|
|
321
|
+
const first = locations[0];
|
|
322
|
+
if (!first) {
|
|
323
|
+
throw new Error(`createIdenticalViolation called with empty locations array for '${name}'`);
|
|
324
|
+
}
|
|
325
|
+
const otherFilesStr = formatOtherFiles(locations);
|
|
326
|
+
return {
|
|
327
|
+
line: first.line,
|
|
328
|
+
message: `Utility function '${name}' has identical implementation in ${locations.length} locations`,
|
|
329
|
+
severity: 'warning',
|
|
330
|
+
suggestion: `Move '${name}' to packages/shared/backend/foundation/utils/ or a relevant domain utils module. Also in: ${otherFilesStr}`,
|
|
331
|
+
type: 'duplicate-utility-identical',
|
|
332
|
+
match: name,
|
|
333
|
+
filePath: first.file,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Create a violation for similar implementations (same name, different body)
|
|
338
|
+
*/
|
|
339
|
+
function createSimilarViolation(name, uniqueImpls) {
|
|
340
|
+
const first = uniqueImpls[0];
|
|
341
|
+
if (!first) {
|
|
342
|
+
throw new Error(`createSimilarViolation called with empty uniqueImpls array for '${name}'`);
|
|
343
|
+
}
|
|
344
|
+
const otherFilesStr = formatOtherFiles(uniqueImpls);
|
|
345
|
+
const numImplementations = uniqueImpls.length;
|
|
346
|
+
return {
|
|
347
|
+
line: first.line,
|
|
348
|
+
message: `Utility function '${name}' has ${numImplementations} different implementations - consider consolidation with options`,
|
|
349
|
+
severity: 'warning',
|
|
350
|
+
suggestion: `Create a unified '${name}' function with configurable options in packages/shared/backend/foundation/utils/. Different implementations found in: ${otherFilesStr}`,
|
|
351
|
+
type: 'duplicate-utility-similar',
|
|
352
|
+
match: name,
|
|
353
|
+
filePath: first.file,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
async function collectFunctionsFromFiles(files, domainSpecific) {
|
|
357
|
+
const functionsByName = new Map();
|
|
358
|
+
for (const filePath of files.paths) {
|
|
359
|
+
try {
|
|
360
|
+
// @fitness-ignore-next-line performance-anti-patterns -- sequential file reading to control memory; FileAccessor is lazy
|
|
361
|
+
const content = await files.read(filePath);
|
|
362
|
+
const functions = extractUtilityFunctionsWithBody(filePath, content, domainSpecific);
|
|
363
|
+
const validFunctions = functions.filter((fn) => fn.bodyLength >= MIN_FUNCTION_BODY_LENGTH);
|
|
364
|
+
for (const fn of validFunctions) {
|
|
365
|
+
void addFunctionToCollection(functionsByName, fn);
|
|
366
|
+
}
|
|
367
|
+
/* v8 ignore next 1 -- defensive catch: parse failures already handled */
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// @swallow-ok Skip unreadable files
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return functionsByName;
|
|
374
|
+
}
|
|
375
|
+
function findIdenticalViolations(name, hashGroups) {
|
|
376
|
+
const violations = [];
|
|
377
|
+
for (const locations of hashGroups.values()) {
|
|
378
|
+
if (isValidCrossDirectoryDuplicate(locations)) {
|
|
379
|
+
violations.push(createIdenticalViolation(name, locations));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return violations;
|
|
383
|
+
}
|
|
384
|
+
function findSimilarViolation(name, hashGroups) {
|
|
385
|
+
if (hashGroups.size <= 1) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
const uniqueImpls = getFirstFromEachHashGroup(hashGroups);
|
|
389
|
+
/* v8 ignore next -- defensive guard */
|
|
390
|
+
if (!Array.isArray(uniqueImpls) || uniqueImpls.length <= 1) {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
const implDirs = getUniqueDirectories(uniqueImpls);
|
|
394
|
+
if (implDirs.size <= 1) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return createSimilarViolation(name, uniqueImpls);
|
|
398
|
+
}
|
|
399
|
+
function processFunctionGroup(name, hashGroups) {
|
|
400
|
+
const allLocations = flattenHashGroups(hashGroups);
|
|
401
|
+
const dirs = getUniqueDirectories(allLocations);
|
|
402
|
+
if (dirs.size <= 1 || hashGroups.size === 0) {
|
|
403
|
+
return [];
|
|
404
|
+
}
|
|
405
|
+
const violations = [...findIdenticalViolations(name, hashGroups)];
|
|
406
|
+
const similarViolation = findSimilarViolation(name, hashGroups);
|
|
407
|
+
if (similarViolation) {
|
|
408
|
+
violations.push(similarViolation);
|
|
409
|
+
}
|
|
410
|
+
return violations;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Check: quality/duplicate-utility-functions
|
|
414
|
+
*
|
|
415
|
+
* Detects utility functions that should be consolidated across the codebase.
|
|
416
|
+
* Reports two types of issues:
|
|
417
|
+
* - IDENTICAL: Same name, same implementation (true duplicates)
|
|
418
|
+
* - SIMILAR: Same name, different implementation (consolidation opportunities)
|
|
419
|
+
*/
|
|
420
|
+
export const duplicateUtilityFunctions = defineCheck({
|
|
421
|
+
id: 'aa303a1e-f3f8-4a11-ade2-9e29af89c299',
|
|
422
|
+
slug: 'duplicate-utility-functions',
|
|
423
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
424
|
+
contentFilter: 'strip-strings',
|
|
425
|
+
confidence: 'high',
|
|
426
|
+
description: 'Detect duplicate and similar utility functions',
|
|
427
|
+
longDescription: `**Purpose:** Detects utility functions that are duplicated or similarly named across the codebase, flagging consolidation opportunities into shared packages.
|
|
428
|
+
|
|
429
|
+
**Detects:** Cross-file analysis using TypeScript AST extraction and SHA-256 body hashing.
|
|
430
|
+
- **Identical duplicates:** Same-named utility functions with identical normalized bodies in different directories
|
|
431
|
+
- **Similar implementations:** Same-named utility functions with different bodies across directories (consolidation with options pattern)
|
|
432
|
+
- Targets functions matching utility name patterns: \`format*\`, \`parse*\`, \`is*\`, \`has*\`, \`to*\`, \`get*\`, \`validate*\`, \`sanitize*\`, \`normalize*\`, \`debounce\`, \`throttle\`, \`sleep\`, \`retry\`, etc.
|
|
433
|
+
- Skips domain-specific functions listed in \`DOMAIN_SPECIFIC_FUNCTIONS\` and bodies under 50 characters
|
|
434
|
+
|
|
435
|
+
**Why it matters:** Duplicated utilities create maintenance risk and inconsistent behavior. A single shared implementation in \`foundation/utils\` ensures consistent behavior and reduces code volume.
|
|
436
|
+
|
|
437
|
+
**Scope:** General best practice`,
|
|
438
|
+
tags: ['quality', 'dry', 'utilities', 'duplication'],
|
|
439
|
+
fileTypes: ['ts'],
|
|
440
|
+
async analyzeAll(files) {
|
|
441
|
+
const domainSpecific = buildEffectiveDomainSpecificSet();
|
|
442
|
+
const functionsByName = await collectFunctionsFromFiles(files, domainSpecific);
|
|
443
|
+
const violations = [];
|
|
444
|
+
for (const [name, hashGroups] of functionsByName) {
|
|
445
|
+
// @fitness-ignore-next-line performance-anti-patterns -- spread aggregates small violation arrays from pure function
|
|
446
|
+
violations.push(...processFunctionGroup(name, hashGroups));
|
|
447
|
+
}
|
|
448
|
+
return violations;
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
//# sourceMappingURL=duplicate-utility-functions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-utility-functions.js","sourceRoot":"","sources":["../../../../src/checks/quality/code-structure/duplicate-utility-functions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/code-structure/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/checks/quality/code-structure/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No Any Types Check
|
|
3
|
+
*
|
|
4
|
+
* Detects usage of 'any' type in TypeScript code. The 'any' type bypasses
|
|
5
|
+
* type checking and should be replaced with 'unknown' with proper type narrowing.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check: quality/no-any-types
|
|
9
|
+
*
|
|
10
|
+
* Detects usage of any type - use unknown with type narrowing instead.
|
|
11
|
+
*/
|
|
12
|
+
export declare const noAnyTypes: import("@opensip-cli/fitness").Check;
|
|
13
|
+
//# sourceMappingURL=no-any-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-any-types.d.ts","sourceRoot":"","sources":["../../../../src/checks/quality/code-structure/no-any-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwFH;;;;GAIG;AACH,eAAO,MAAM,UAAU,sCA2BrB,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview No Any Types Check
|
|
3
|
+
*
|
|
4
|
+
* Detects usage of 'any' type in TypeScript code. The 'any' type bypasses
|
|
5
|
+
* type checking and should be replaced with 'unknown' with proper type narrowing.
|
|
6
|
+
*/
|
|
7
|
+
import { defineCheck } from '@opensip-cli/fitness';
|
|
8
|
+
import { getSharedSourceFile } from '@opensip-cli/lang-typescript';
|
|
9
|
+
import * as ts from 'typescript';
|
|
10
|
+
/**
|
|
11
|
+
* Quick filter keywords for 'any' type patterns
|
|
12
|
+
*/
|
|
13
|
+
const QUICK_FILTER_KEYWORDS = [': any', 'any)', 'any,', 'any;', '<any', 'any>'];
|
|
14
|
+
/**
|
|
15
|
+
* Find lines with eslint-disable-next-line comments
|
|
16
|
+
*/
|
|
17
|
+
function findDisabledLines(content) {
|
|
18
|
+
const disabledLines = new Set();
|
|
19
|
+
const lines = content.split('\n');
|
|
20
|
+
for (const [i, line] of lines.entries()) {
|
|
21
|
+
if (line?.includes('eslint-disable-next-line')) {
|
|
22
|
+
disabledLines.add(i + 1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return disabledLines;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Analyze a file for 'any' type usage
|
|
29
|
+
*/
|
|
30
|
+
function analyzeFile(content, filePath) {
|
|
31
|
+
const violations = [];
|
|
32
|
+
const disabledLines = findDisabledLines(content);
|
|
33
|
+
try {
|
|
34
|
+
const sourceFile = getSharedSourceFile(filePath, content);
|
|
35
|
+
/* v8 ignore next -- defensive guard */
|
|
36
|
+
if (!sourceFile)
|
|
37
|
+
return violations;
|
|
38
|
+
const visit = (node) => {
|
|
39
|
+
if (node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
40
|
+
const parent = node.parent;
|
|
41
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
42
|
+
// Skip if this line has an eslint-disable-next-line comment
|
|
43
|
+
if (disabledLines.has(line)) {
|
|
44
|
+
ts.forEachChild(node, visit);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Get context from parent
|
|
48
|
+
let context = 'type annotation';
|
|
49
|
+
if (ts.isParameter(parent)) {
|
|
50
|
+
context = 'function parameter';
|
|
51
|
+
}
|
|
52
|
+
else if (ts.isVariableDeclaration(parent)) {
|
|
53
|
+
context = 'variable declaration';
|
|
54
|
+
}
|
|
55
|
+
else if (ts.isPropertySignature(parent) || ts.isPropertyDeclaration(parent)) {
|
|
56
|
+
context = 'property';
|
|
57
|
+
}
|
|
58
|
+
else if (ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent)) {
|
|
59
|
+
context = 'return type';
|
|
60
|
+
}
|
|
61
|
+
else if (ts.isTypeAliasDeclaration(parent)) {
|
|
62
|
+
context = 'type alias';
|
|
63
|
+
}
|
|
64
|
+
violations.push({
|
|
65
|
+
line: line + 1,
|
|
66
|
+
column: character + 1,
|
|
67
|
+
message: `'any' type used in ${context}`,
|
|
68
|
+
severity: 'error',
|
|
69
|
+
type: 'any-type',
|
|
70
|
+
suggestion: "Replace 'any' with 'unknown' and add type narrowing with type guards or assertion functions.",
|
|
71
|
+
match: 'any',
|
|
72
|
+
filePath,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
ts.forEachChild(node, visit);
|
|
76
|
+
};
|
|
77
|
+
visit(sourceFile);
|
|
78
|
+
/* v8 ignore next 1 -- defensive catch: parse failures already handled */
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// @swallow-ok Skip files that fail to parse
|
|
82
|
+
}
|
|
83
|
+
return violations;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check: quality/no-any-types
|
|
87
|
+
*
|
|
88
|
+
* Detects usage of any type - use unknown with type narrowing instead.
|
|
89
|
+
*/
|
|
90
|
+
export const noAnyTypes = defineCheck({
|
|
91
|
+
id: '3d456769-bbcb-461f-8efd-e7b340dcb1b8',
|
|
92
|
+
slug: 'no-any-types',
|
|
93
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
94
|
+
description: 'Detect usage of any type - use unknown with type narrowing instead',
|
|
95
|
+
longDescription: `**Purpose:** Detects usage of the \`any\` type in TypeScript code, which bypasses type checking and should be replaced with \`unknown\` plus proper type narrowing.
|
|
96
|
+
|
|
97
|
+
**Detects:** Analyzes each file individually using TypeScript AST traversal for \`AnyKeyword\` nodes.
|
|
98
|
+
- \`any\` in function parameters, variable declarations, property signatures, return types, and type aliases
|
|
99
|
+
- Respects \`eslint-disable-next-line\` comments on the preceding line
|
|
100
|
+
- Uses a quick-filter optimization: skips files not containing \`: any\`, \`any)\`, \`any,\`, \`any;\`, \`<any\`, or \`any>\`
|
|
101
|
+
|
|
102
|
+
**Why it matters:** The \`any\` type disables TypeScript's type safety, hiding bugs that would otherwise be caught at compile time. Using \`unknown\` with type guards preserves safety while handling dynamic data.
|
|
103
|
+
|
|
104
|
+
**Scope:** General best practice`,
|
|
105
|
+
tags: ['quality', 'type-safety', 'code-quality'],
|
|
106
|
+
fileTypes: ['ts', 'tsx'],
|
|
107
|
+
confidence: 'high',
|
|
108
|
+
analyze(content, filePath) {
|
|
109
|
+
// Quick filter: skip files without 'any' type patterns
|
|
110
|
+
if (!QUICK_FILTER_KEYWORDS.some((kw) => content.includes(kw))) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
return analyzeFile(content, filePath);
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=no-any-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-any-types.js","sourceRoot":"","sources":["../../../../src/checks/quality/code-structure/no-any-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Regression tests for two `null-safety` FP fixes.
|
|
3
|
+
*
|
|
4
|
+
* 1. Cross-line guard: a property access guarded by an enclosing `if` / `&&`
|
|
5
|
+
* on a PREVIOUS line (e.g. `if (candidates.length === 1 && candidates[0])
|
|
6
|
+
* { … candidates[0].bodyHash … }`) was flagged because the safety scan was
|
|
7
|
+
* line-local. The fix walks enclosing conditions.
|
|
8
|
+
* 2. Immutable combinators: `.merge(...)` chained on a factory result
|
|
9
|
+
* (e.g. OTel `detectResources(...).merge(...)`) returns a non-null value
|
|
10
|
+
* and is now a known-safe fluent method.
|
|
11
|
+
*
|
|
12
|
+
* Genuine unguarded access on a call/element result must still fire.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=null-safety-fp.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-safety-fp.test.d.ts","sourceRoot":"","sources":["../../../../../src/checks/quality/data-integrity/__tests__/null-safety-fp.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|