@sun-asterisk/sunlint 1.0.6 → 1.1.3
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/.sunlint.json +35 -0
- package/CHANGELOG.md +135 -169
- package/CONTRIBUTING.md +235 -0
- package/PROJECT_STRUCTURE.md +60 -0
- package/README.md +77 -50
- package/cli.js +1 -0
- package/config/README.md +88 -0
- package/config/defaults/ai-rules-context.json +231 -0
- package/config/engines/engines.json +49 -0
- package/config/engines/eslint-rule-mapping.json +74 -0
- package/config/eslint-rule-mapping.json +126 -0
- package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +4 -0
- package/config/presets/beginner.json +1 -1
- package/config/presets/ci.json +3 -2
- package/config/presets/recommended.json +1 -1
- package/config/presets/strict.json +2 -2
- package/config/rule-analysis-strategies.js +74 -0
- package/config/{rules-registry.json → rules/rules-registry.json} +82 -0
- package/core/analysis-orchestrator.js +383 -591
- package/core/ast-modules/README.md +103 -0
- package/core/ast-modules/base-parser.js +90 -0
- package/core/ast-modules/index.js +97 -0
- package/core/ast-modules/package.json +37 -0
- package/core/ast-modules/parsers/eslint-js-parser.js +147 -0
- package/core/ast-modules/parsers/eslint-ts-parser.js +106 -0
- package/core/ast-modules/parsers/javascript-parser.js +187 -0
- package/core/ast-modules/parsers/typescript-parser.js +187 -0
- package/core/cli-action-handler.js +271 -255
- package/core/cli-program.js +18 -4
- package/core/config-manager.js +18 -11
- package/core/config-merger.js +52 -1
- package/core/config-validator.js +2 -2
- package/core/enhanced-rules-registry.js +331 -0
- package/core/file-targeting-service.js +93 -29
- package/core/interfaces/analysis-engine.interface.js +100 -0
- package/core/multi-rule-runner.js +0 -221
- package/core/output-service.js +1 -1
- package/core/rule-mapping-service.js +9 -1
- package/core/rule-selection-service.js +10 -2
- package/docs/CONFIGURATION.md +414 -0
- package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
- package/engines/eslint-engine.js +601 -0
- package/engines/heuristic-engine.js +860 -0
- package/engines/openai-engine.js +374 -0
- package/integrations/eslint/README.md +99 -0
- package/{eslint-integration → integrations/eslint/configs}/.eslintrc.js +1 -1
- package/integrations/eslint/configs/eslint.config.js +133 -0
- package/integrations/eslint/configs/eslint.config.simple.js +24 -0
- package/integrations/eslint/plugin/index.js +164 -0
- package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c006-function-name-verb-noun.js +11 -2
- package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
- package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
- package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c029-catch-block-logging.js +35 -0
- package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
- package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
- package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
- package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
- package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
- package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
- package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
- package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
- package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
- package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t003-ts-ignore-reason.js +3 -3
- package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t007-no-fn-in-constructor.js +1 -1
- package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
- package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
- package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
- package/integrations/eslint/test-c041-rule.js +87 -0
- package/package.json +29 -19
- package/rules/README.md +252 -0
- package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
- package/rules/common/C002_no_duplicate_code/config.json +23 -0
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
- package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
- package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
- package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
- package/rules/common/C013_no_dead_code/analyzer.js +206 -0
- package/rules/common/C014_dependency_injection/analyzer.js +338 -0
- package/rules/common/C017_constructor_logic/analyzer.js +314 -0
- package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
- package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
- package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
- package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
- package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
- package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
- package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
- package/rules/docs/C002_no_duplicate_code.md +57 -0
- package/rules/index.js +149 -0
- package/rules/migration/converter.js +385 -0
- package/rules/migration/mapping.json +164 -0
- package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
- package/rules/security/S026_json_schema_validation/config.json +27 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
- package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
- package/rules/security/S029_csrf_protection/analyzer.js +264 -0
- package/rules/tests/C002_no_duplicate_code.test.js +50 -0
- package/rules/utils/ast-utils.js +191 -0
- package/rules/utils/base-analyzer.js +98 -0
- package/rules/utils/pattern-matchers.js +239 -0
- package/rules/utils/rule-helpers.js +264 -0
- package/rules/utils/severity-constants.js +93 -0
- package/scripts/build-release.sh +117 -0
- package/scripts/ci-report.js +179 -0
- package/scripts/install.sh +196 -0
- package/scripts/manual-release.sh +338 -0
- package/scripts/merge-reports.js +424 -0
- package/scripts/pre-release-test.sh +175 -0
- package/scripts/prepare-release.sh +202 -0
- package/scripts/setup-github-registry.sh +42 -0
- package/scripts/test-scripts/README.md +22 -0
- package/scripts/test-scripts/test-c041-comparison.js +114 -0
- package/scripts/test-scripts/test-c041-eslint.js +67 -0
- package/scripts/test-scripts/test-eslint-rules.js +146 -0
- package/scripts/test-scripts/test-real-world.js +44 -0
- package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
- package/scripts/trigger-release.sh +285 -0
- package/scripts/validate-rule-structure.js +148 -0
- package/scripts/verify-install.sh +82 -0
- package/cli-legacy.js +0 -355
- package/config/sunlint-schema.json +0 -166
- package/config/typescript/custom-rules-new.js +0 -0
- package/config/typescript/custom-rules.js +0 -9
- package/config/typescript/package-lock.json +0 -1585
- package/config/typescript/package.json +0 -13
- package/config/typescript/security-rules/index.js +0 -90
- package/config/typescript/security-rules/s005-no-origin-auth.js +0 -95
- package/config/typescript/security-rules/s006-activation-recovery-secret-not-plaintext.js +0 -69
- package/config/typescript/security-rules/s008-crypto-agility.js +0 -62
- package/config/typescript/security-rules/s009-no-insecure-crypto.js +0 -103
- package/config/typescript/security-rules/s010-no-insecure-random-in-sensitive-context.js +0 -123
- package/config/typescript/security-rules/s011-no-insecure-uuid.js +0 -66
- package/config/typescript/security-rules/s012-hardcode-secret.js +0 -71
- package/config/typescript/security-rules/s014-insecure-tls-version.js +0 -50
- package/config/typescript/security-rules/s015-insecure-tls-certificate.js +0 -43
- package/config/typescript/security-rules/s016-sensitive-query-parameter.js +0 -59
- package/config/typescript/security-rules/s017-no-sql-injection.js +0 -193
- package/config/typescript/security-rules/s018-positive-input-validation.js +0 -56
- package/config/typescript/security-rules/s019-no-raw-user-input-in-email.js +0 -113
- package/config/typescript/security-rules/s020-no-eval-dynamic-execution.js +0 -89
- package/config/typescript/security-rules/s022-output-encoding.js +0 -78
- package/config/typescript/security-rules/s023-no-json-injection.js +0 -300
- package/config/typescript/security-rules/s025-server-side-input-validation.js +0 -217
- package/config/typescript/security-rules/s026-json-schema-validation.js +0 -68
- package/config/typescript/security-rules/s027-no-hardcoded-secrets.js +0 -80
- package/config/typescript/security-rules/s029-require-csrf-protection.js +0 -79
- package/config/typescript/security-rules/s030-no-directory-browsing.js +0 -78
- package/config/typescript/security-rules/s033-require-samesite-cookie.js +0 -80
- package/config/typescript/security-rules/s034-require-host-cookie-prefix.js +0 -77
- package/config/typescript/security-rules/s035-cookie-specific-path.js +0 -74
- package/config/typescript/security-rules/s036-no-unsafe-file-include.js +0 -68
- package/config/typescript/security-rules/s037-require-anti-cache-headers.js +0 -70
- package/config/typescript/security-rules/s038-no-version-disclosure.js +0 -74
- package/config/typescript/security-rules/s039-no-session-token-in-url.js +0 -63
- package/config/typescript/security-rules/s041-require-session-invalidate-on-logout.js +0 -211
- package/config/typescript/security-rules/s042-require-periodic-reauthentication.js +0 -294
- package/config/typescript/security-rules/s043-terminate-sessions-on-password-change.js +0 -254
- package/config/typescript/security-rules/s044-require-full-session-for-sensitive-operations.js +0 -292
- package/config/typescript/security-rules/s045-anti-automation-controls.js +0 -46
- package/config/typescript/security-rules/s046-secure-notification-on-auth-change.js +0 -44
- package/config/typescript/security-rules/s048-password-credential-recovery.js +0 -54
- package/config/typescript/security-rules/s050-session-token-weak-hash.js +0 -94
- package/config/typescript/security-rules/s052-secure-random-authentication-code.js +0 -66
- package/config/typescript/security-rules/s054-verification-default-account.js +0 -109
- package/config/typescript/security-rules/s057-utc-logging.js +0 -54
- package/config/typescript/security-rules/s058-no-ssrf.js +0 -73
- package/config/typescript/tsconfig.json +0 -29
- package/core/ai-analyzer.js +0 -169
- package/core/eslint-engine-service.js +0 -312
- package/core/eslint-instance-manager.js +0 -104
- package/core/eslint-integration-service.js +0 -363
- package/core/sunlint-engine-service.js +0 -23
- package/core/typescript-analyzer.js +0 -262
- package/core/typescript-engine.js +0 -313
- package/docs/ENHANCED_FILE_TARGETING.md +0 -0
- package/docs/FILE_TARGETING_COMPARISON.md +0 -0
- package/docs/RULE-RESPONSIBILITY-MATRIX.md +0 -204
- package/eslint-integration/cli.js +0 -35
- package/eslint-integration/eslint-plugin-custom/c013-no-dead-code.js +0 -43
- package/eslint-integration/eslint-plugin-custom/c017-limit-constructor-logic.js +0 -39
- package/eslint-integration/eslint-plugin-custom/c027-limit-function-nesting.js +0 -50
- package/eslint-integration/eslint-plugin-custom/c034-no-implicit-return.js +0 -34
- package/eslint-integration/eslint-plugin-custom/c035-no-empty-catch.js +0 -32
- package/eslint-integration/eslint-plugin-custom/c041-no-config-inline.js +0 -64
- package/eslint-integration/eslint-plugin-custom/c048-no-var-declaration.js +0 -31
- package/eslint-integration/eslint-plugin-custom/index.js +0 -155
- package/eslint-integration/eslint-plugin-custom/package.json.bak +0 -9
- package/eslint-integration/eslint-plugin-custom/t004-interface-public-only.js +0 -160
- package/eslint-integration/eslint-plugin-custom/t011-no-real-time-dependency.js +0 -175
- package/eslint-integration/eslint-plugin-custom/t026-limit-nested-generics.js +0 -377
- package/eslint-integration/sample.ts +0 -53
- package/eslint-integration/test-s003.js +0 -5
- package/examples/.github/workflows/code-quality.yml +0 -111
- package/examples/README.md +0 -69
- package/examples/basic-typescript-demo/.eslintrc.json +0 -18
- package/examples/basic-typescript-demo/.next/cache/eslint/.cache_1othrmo +0 -1
- package/examples/basic-typescript-demo/.sunlint.json +0 -29
- package/examples/basic-typescript-demo/eslint.config.mjs +0 -37
- package/examples/basic-typescript-demo/next-env.d.ts +0 -5
- package/examples/basic-typescript-demo/next.config.mjs +0 -4
- package/examples/basic-typescript-demo/package-lock.json +0 -5656
- package/examples/basic-typescript-demo/package.json +0 -34
- package/examples/basic-typescript-demo/src/app/layout.tsx +0 -18
- package/examples/basic-typescript-demo/src/app/page.tsx +0 -48
- package/examples/basic-typescript-demo/src/config.ts +0 -14
- package/examples/basic-typescript-demo/src/good-practices.ts +0 -58
- package/examples/basic-typescript-demo/src/types.generated.ts +0 -13
- package/examples/basic-typescript-demo/src/user.test.ts +0 -19
- package/examples/basic-typescript-demo/src/violations.ts +0 -61
- package/examples/basic-typescript-demo/tsconfig.json +0 -27
- package/examples/eslint-integration-demo/.eslintrc.js +0 -38
- package/examples/eslint-integration-demo/.sunlint.json +0 -42
- package/examples/eslint-integration-demo/next-env.d.ts +0 -5
- package/examples/eslint-integration-demo/next.config.js +0 -8
- package/examples/eslint-integration-demo/package-lock.json +0 -5740
- package/examples/eslint-integration-demo/package.json +0 -37
- package/examples/eslint-integration-demo/src/api.test.ts +0 -20
- package/examples/eslint-integration-demo/src/conflict-test.tsx +0 -44
- package/examples/eslint-integration-demo/src/naming-conflicts.ts +0 -50
- package/examples/eslint-integration-demo/tsconfig.json +0 -26
- package/examples/file-targeting-demo/global.d.ts +0 -11
- package/examples/file-targeting-demo/jest.config.js +0 -8
- package/examples/file-targeting-demo/sample.ts +0 -53
- package/examples/file-targeting-demo/src/server.js +0 -11
- package/examples/file-targeting-demo/src/server.test.js +0 -11
- package/examples/file-targeting-demo/src/types.d.ts +0 -4
- package/examples/file-targeting-demo/src/types.generated.ts +0 -10
- package/examples/file-targeting-demo/user-service.test.ts +0 -15
- package/examples/file-targeting-demo/user-service.ts +0 -13
- package/examples/file-targeting-demo/utils.js +0 -15
- package/examples/multi-language-project/.eslintrc.json +0 -38
- package/examples/multi-language-project/package.json +0 -37
- package/examples/multi-language-project/src/sample.ts +0 -39
- package/examples/rule-test-fixtures/README.md +0 -67
- package/examples/rule-test-fixtures/rules/C006_function_naming/clean/typescript-clean.ts +0 -64
- package/examples/rule-test-fixtures/rules/C006_function_naming/violations/dart-violations.dart +0 -56
- package/examples/rule-test-fixtures/rules/C006_function_naming/violations/typescript-violations.ts +0 -47
- package/examples/rule-test-fixtures/rules/C019_log_level_usage/clean/typescript-clean.ts +0 -93
- package/examples/rule-test-fixtures/rules/C019_log_level_usage/violations/dart-violations.dart +0 -75
- package/examples/rule-test-fixtures/rules/C019_log_level_usage/violations/typescript-violations.ts +0 -84
- package/examples/rule-test-fixtures/rules/C029_catch_block_logging/violations/typescript-violations.ts +0 -37
- /package/config/{default.json → defaults/default.json} +0 -0
- /package/{eslint-integration/eslint.config.js → config/integrations/eslint/base.config.js} +0 -0
- /package/{eslint-integration/eslint.config.simple.js → config/integrations/eslint/simple.config.js} +0 -0
- /package/{examples/rule-test-fixtures/rules/C029_catch_block_logging/clean/typescript-clean.ts → config/schemas/sunlint-schema.json} +0 -0
- /package/config/{typescript → testing}/test-s005-working.ts +0 -0
- /package/{examples/eslint-integration-demo/test-file-targeting.sh → engines/tree-sitter-parser.js} +0 -0
- /package/{examples/enhanced-config.json → engines/universal-ast-engine.js} +0 -0
- /package/{eslint-integration → integrations/eslint}/package.json +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin}/package.json +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c002-no-duplicate-code.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c003-no-vague-abbreviations.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c010-limit-block-nesting.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c014-abstract-dependency-preferred.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c018-no-generic-throw.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c023-no-duplicate-variable-name-in-scope.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c030-use-custom-error-classes.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c042-boolean-name-prefix.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c043-no-console-or-print.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/common}/c047-no-duplicate-retry-logic.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s003-no-unvalidated-redirect.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s047-secure-random-passwords.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s055-verification-rest-check-the-incoming-content-type.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom → integrations/eslint/plugin/rules/typescript}/t002-interface-prefix-i.js +0 -0
- /package/{eslint-integration/eslint-plugin-custom/t019-no-empty-type.js → integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js} +0 -0
- /package/{eslint-integration/eslint-plugin-custom/t025-no-nested-union-tuple.js → integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js} +0 -0
- /package/{eslint-integration → integrations/eslint}/tsconfig.json +0 -0
- /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
- /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
- /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
- /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
- /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
- /package/{examples/basic-typescript-demo/test-file-targeting.sh → rules/universal/C010/generic.js} +0 -0
- /package/{examples/basic-typescript-demo/test-config-priority.sh → rules/universal/C010/tree-sitter-analyzer.js} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint rule: S007 – Plaintext OTP Check
|
|
3
|
+
* Rule ID: custom/s007
|
|
4
|
+
* Description: Verify that OTPs are not stored or transmitted in plaintext form.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Verify that OTPs are not stored or transmitted in plaintext form.',
|
|
14
|
+
recommended: true,
|
|
15
|
+
url: 'https://owasp.org/www-community/vulnerabilities/Insecure_Storage',
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
plaintextOtp:
|
|
19
|
+
'OTP should not be stored or transmitted in plaintext. Consider hashing or encrypting it.',
|
|
20
|
+
},
|
|
21
|
+
schema: [],
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
create(context) {
|
|
25
|
+
return {
|
|
26
|
+
Property(node) {
|
|
27
|
+
if (
|
|
28
|
+
node.key &&
|
|
29
|
+
node.key.type === 'Identifier' &&
|
|
30
|
+
/otp/i.test(node.key.name) &&
|
|
31
|
+
node.value &&
|
|
32
|
+
node.value.type === 'Identifier' &&
|
|
33
|
+
!/hash|encrypt|bcrypt|sha/i.test(node.value.name)
|
|
34
|
+
) {
|
|
35
|
+
context.report({
|
|
36
|
+
node,
|
|
37
|
+
messageId: 'plaintextOtp',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
CallExpression(node) {
|
|
43
|
+
const calleeName = getCalleeName(node.callee);
|
|
44
|
+
if (!calleeName) return;
|
|
45
|
+
|
|
46
|
+
if (/(insert|update|save|query|create)/i.test(calleeName)) {
|
|
47
|
+
for (const arg of node.arguments) {
|
|
48
|
+
const text = context.getSourceCode().getText(arg);
|
|
49
|
+
if (/otp/i.test(text) && !/hash|encrypt|bcrypt|sha/i.test(text)) {
|
|
50
|
+
context.report({
|
|
51
|
+
node: arg,
|
|
52
|
+
messageId: 'plaintextOtp',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// ===== Helper function =====
|
|
63
|
+
|
|
64
|
+
function getCalleeName(callee) {
|
|
65
|
+
if (callee.type === 'Identifier') {
|
|
66
|
+
return callee.name;
|
|
67
|
+
} else if (
|
|
68
|
+
callee.type === 'MemberExpression' &&
|
|
69
|
+
callee.property.type === 'Identifier'
|
|
70
|
+
) {
|
|
71
|
+
return callee.property.name;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint rule: S013 – Enforce TLS Usage
|
|
3
|
+
* Rule ID: custom-tls/s013
|
|
4
|
+
*/
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const HTTP_REGEX = /^http:\/\//i;
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: "problem",
|
|
12
|
+
docs: {
|
|
13
|
+
description:
|
|
14
|
+
"Ensure all client connections use TLS (HTTPS) and prevent unencrypted (HTTP) connections.",
|
|
15
|
+
recommended: true,
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
insecureUrl:
|
|
19
|
+
"Unencrypted connection detected (http://). Always use HTTPS (TLS).",
|
|
20
|
+
},
|
|
21
|
+
schema: [],
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
create(context) {
|
|
25
|
+
/** Báo lỗi nếu node là string chứa http:// */
|
|
26
|
+
function reportIfHttp(node, text) {
|
|
27
|
+
if (HTTP_REGEX.test(text)) {
|
|
28
|
+
context.report({ node, messageId: "insecureUrl" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
// String literal
|
|
34
|
+
Literal(node) {
|
|
35
|
+
if (typeof node.value === "string") reportIfHttp(node, node.value);
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Template “thuần” (không có ${...})
|
|
39
|
+
TemplateLiteral(node) {
|
|
40
|
+
if (node.expressions.length === 0) {
|
|
41
|
+
const raw = node.quasis.map(q => q.value.raw).join("");
|
|
42
|
+
reportIfHttp(node, raw);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Custom ESLint rule for: T003 – Avoid using @ts-ignore without
|
|
3
|
-
* Rule ID: custom/t003
|
|
4
|
-
* Purpose:
|
|
2
|
+
* Custom ESLint rule for: T003 – Avoid using @ts-ignore without justification
|
|
3
|
+
* Rule ID: custom/t003
|
|
4
|
+
* Purpose: Require clear justification when using @ts-ignore comments
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
"use strict";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Custom ESLint rule for: T007 – Avoid declaring functions inside constructors or class bodies
|
|
3
3
|
* Rule ID: custom/t007
|
|
4
|
-
* Purpose:
|
|
4
|
+
* Purpose: Discourage function declarations within constructors or class methods
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule T019: Do not assign to this arbitrarily
|
|
3
|
+
* @description Maintain proper context and avoid this manipulation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Do not assign to this arbitrarily',
|
|
11
|
+
category: 'Best Practices',
|
|
12
|
+
recommended: true
|
|
13
|
+
},
|
|
14
|
+
fixable: null,
|
|
15
|
+
schema: []
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
create(context) {
|
|
19
|
+
return {
|
|
20
|
+
// Detect direct assignment to 'this'
|
|
21
|
+
AssignmentExpression(node) {
|
|
22
|
+
if (node.left.type === 'ThisExpression') {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
message: 'T019: Do not assign to "this" directly. Use proper binding, arrow functions, or explicit parameter passing.'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// Detect patterns like "const that = this" or "var self = this"
|
|
31
|
+
VariableDeclarator(node) {
|
|
32
|
+
if (node.init && node.init.type === 'ThisExpression') {
|
|
33
|
+
// Common patterns: that, self, _this, me
|
|
34
|
+
const variableName = node.id.name;
|
|
35
|
+
const suspiciousNames = ['that', 'self', '_this', 'me', '_self'];
|
|
36
|
+
|
|
37
|
+
if (suspiciousNames.includes(variableName.toLowerCase())) {
|
|
38
|
+
context.report({
|
|
39
|
+
node,
|
|
40
|
+
message: `T019: Avoid storing "this" in variable "${variableName}". Use arrow functions or proper binding instead.`
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// Detect method calls that bind this arbitrarily
|
|
47
|
+
CallExpression(node) {
|
|
48
|
+
// Detect .bind(this) patterns that might be problematic
|
|
49
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
50
|
+
node.callee.property.name === 'bind' &&
|
|
51
|
+
node.arguments.length > 0) {
|
|
52
|
+
|
|
53
|
+
const bindTarget = node.arguments[0];
|
|
54
|
+
if (bindTarget.type === 'ThisExpression') {
|
|
55
|
+
// Allow legitimate .bind(this) in constructors and specific patterns
|
|
56
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
57
|
+
let currentScope = sourceCode.getScope ? sourceCode.getScope(node) : null;
|
|
58
|
+
|
|
59
|
+
if (!currentScope && context.getScope) {
|
|
60
|
+
currentScope = context.getScope();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const parent = currentScope ? currentScope.block : null;
|
|
64
|
+
const isInConstructor = parent &&
|
|
65
|
+
parent.type === 'FunctionExpression' &&
|
|
66
|
+
parent.parent &&
|
|
67
|
+
parent.parent.key &&
|
|
68
|
+
parent.parent.key.name === 'constructor';
|
|
69
|
+
|
|
70
|
+
if (!isInConstructor) {
|
|
71
|
+
context.report({
|
|
72
|
+
node,
|
|
73
|
+
message: 'T019: Consider using arrow functions instead of .bind(this) for cleaner context handling.'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule T020: Avoid export default for multi-responsibility modules
|
|
3
|
+
* @description Improve tree-shaking and module clarity
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'suggestion',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Avoid export default for multi-responsibility modules',
|
|
11
|
+
category: 'Best Practices',
|
|
12
|
+
recommended: true
|
|
13
|
+
},
|
|
14
|
+
fixable: null,
|
|
15
|
+
schema: []
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
create(context) {
|
|
19
|
+
let hasDefaultExport = false;
|
|
20
|
+
let namedExports = [];
|
|
21
|
+
let exportedFunctions = [];
|
|
22
|
+
let exportedClasses = [];
|
|
23
|
+
let exportedConstants = [];
|
|
24
|
+
|
|
25
|
+
function analyzeExport(node, exportType) {
|
|
26
|
+
if (exportType === 'default') {
|
|
27
|
+
hasDefaultExport = true;
|
|
28
|
+
} else {
|
|
29
|
+
namedExports.push(node);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
// Track export default statements
|
|
35
|
+
ExportDefaultDeclaration(node) {
|
|
36
|
+
hasDefaultExport = true;
|
|
37
|
+
|
|
38
|
+
// Analyze what's being exported as default
|
|
39
|
+
if (node.declaration) {
|
|
40
|
+
if (node.declaration.type === 'FunctionDeclaration') {
|
|
41
|
+
exportedFunctions.push(node.declaration);
|
|
42
|
+
} else if (node.declaration.type === 'ClassDeclaration') {
|
|
43
|
+
exportedClasses.push(node.declaration);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Track named exports
|
|
49
|
+
ExportNamedDeclaration(node) {
|
|
50
|
+
namedExports.push(node);
|
|
51
|
+
|
|
52
|
+
if (node.declaration) {
|
|
53
|
+
if (node.declaration.type === 'FunctionDeclaration') {
|
|
54
|
+
exportedFunctions.push(node.declaration);
|
|
55
|
+
} else if (node.declaration.type === 'ClassDeclaration') {
|
|
56
|
+
exportedClasses.push(node.declaration);
|
|
57
|
+
} else if (node.declaration.type === 'VariableDeclaration') {
|
|
58
|
+
exportedConstants.push(node.declaration);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (node.specifiers) {
|
|
63
|
+
node.specifiers.forEach(spec => {
|
|
64
|
+
if (spec.type === 'ExportSpecifier') {
|
|
65
|
+
namedExports.push(spec);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Check at the end of the program
|
|
72
|
+
'Program:exit'() {
|
|
73
|
+
if (!hasDefaultExport) {
|
|
74
|
+
return; // No default export, rule doesn't apply
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Count total exports
|
|
78
|
+
const totalNamedExports = namedExports.length;
|
|
79
|
+
const totalFunctions = exportedFunctions.length;
|
|
80
|
+
const totalClasses = exportedClasses.length;
|
|
81
|
+
const totalConstants = exportedConstants.length;
|
|
82
|
+
|
|
83
|
+
// Multi-responsibility indicators:
|
|
84
|
+
// 1. Multiple named exports alongside default export
|
|
85
|
+
// 2. Multiple functions being exported
|
|
86
|
+
// 3. Multiple classes being exported
|
|
87
|
+
// 4. Mix of functions, classes, and constants
|
|
88
|
+
|
|
89
|
+
const isMultiResponsibility =
|
|
90
|
+
totalNamedExports > 0 || // Has both default and named exports
|
|
91
|
+
totalFunctions > 1 || // Multiple functions
|
|
92
|
+
totalClasses > 1 || // Multiple classes
|
|
93
|
+
(totalFunctions > 0 && totalClasses > 0) || // Mix of functions and classes
|
|
94
|
+
(totalConstants > 2); // Too many constants
|
|
95
|
+
|
|
96
|
+
if (isMultiResponsibility) {
|
|
97
|
+
// Find the default export node to report
|
|
98
|
+
const sourceCode = context.getSourceCode();
|
|
99
|
+
const defaultExportNode = sourceCode.ast.body.find(
|
|
100
|
+
node => node.type === 'ExportDefaultDeclaration'
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (defaultExportNode) {
|
|
104
|
+
let message = 'T020: Avoid export default for multi-responsibility modules. ';
|
|
105
|
+
|
|
106
|
+
if (totalNamedExports > 0) {
|
|
107
|
+
message += `Found ${totalNamedExports} named exports alongside default export. `;
|
|
108
|
+
}
|
|
109
|
+
if (totalFunctions > 1) {
|
|
110
|
+
message += `Found ${totalFunctions} exported functions. `;
|
|
111
|
+
}
|
|
112
|
+
if (totalClasses > 1) {
|
|
113
|
+
message += `Found ${totalClasses} exported classes. `;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
message += 'Consider using only named exports for better tree-shaking and clarity.';
|
|
117
|
+
|
|
118
|
+
context.report({
|
|
119
|
+
node: defaultExportNode,
|
|
120
|
+
message
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule T021: Limit deeply nested generics
|
|
3
|
+
* @description Improve code readability and TypeScript performance
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'suggestion',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Limit deeply nested generics',
|
|
11
|
+
category: 'Best Practices',
|
|
12
|
+
recommended: true
|
|
13
|
+
},
|
|
14
|
+
fixable: null,
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
maxDepth: {
|
|
20
|
+
type: 'integer',
|
|
21
|
+
minimum: 1,
|
|
22
|
+
default: 3
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: false
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
create(context) {
|
|
31
|
+
const options = context.options[0] || {};
|
|
32
|
+
const maxDepth = options.maxDepth || 3;
|
|
33
|
+
|
|
34
|
+
function getGenericDepth(typeNode) {
|
|
35
|
+
if (!typeNode) return 0;
|
|
36
|
+
|
|
37
|
+
switch (typeNode.type) {
|
|
38
|
+
case 'TSTypeReference':
|
|
39
|
+
// Generic types like Array<T>, Promise<U>, etc.
|
|
40
|
+
// ESLint uses 'typeArguments' instead of 'typeParameters'
|
|
41
|
+
if (typeNode.typeArguments && typeNode.typeArguments.params) {
|
|
42
|
+
let maxChildDepth = 0;
|
|
43
|
+
for (const param of typeNode.typeArguments.params) {
|
|
44
|
+
const childDepth = getGenericDepth(param);
|
|
45
|
+
maxChildDepth = Math.max(maxChildDepth, childDepth);
|
|
46
|
+
}
|
|
47
|
+
return 1 + maxChildDepth;
|
|
48
|
+
}
|
|
49
|
+
return 0;
|
|
50
|
+
|
|
51
|
+
case 'TSArrayType':
|
|
52
|
+
// Array types like T[]
|
|
53
|
+
return 1 + getGenericDepth(typeNode.elementType);
|
|
54
|
+
|
|
55
|
+
case 'TSUnionType':
|
|
56
|
+
case 'TSIntersectionType':
|
|
57
|
+
// Union types like A | B or intersection types A & B
|
|
58
|
+
let maxDepth = 0;
|
|
59
|
+
for (const typeItem of typeNode.types) {
|
|
60
|
+
maxDepth = Math.max(maxDepth, getGenericDepth(typeItem));
|
|
61
|
+
}
|
|
62
|
+
return maxDepth;
|
|
63
|
+
|
|
64
|
+
case 'TSTupleType':
|
|
65
|
+
// Tuple types like [A, B, C]
|
|
66
|
+
let maxTupleDepth = 0;
|
|
67
|
+
for (const elementType of typeNode.elementTypes) {
|
|
68
|
+
maxTupleDepth = Math.max(maxTupleDepth, getGenericDepth(elementType));
|
|
69
|
+
}
|
|
70
|
+
return 1 + maxTupleDepth;
|
|
71
|
+
|
|
72
|
+
case 'TSMappedType':
|
|
73
|
+
// Mapped types like { [K in keyof T]: U }
|
|
74
|
+
return 1 + getGenericDepth(typeNode.typeAnnotation);
|
|
75
|
+
|
|
76
|
+
case 'TSConditionalType':
|
|
77
|
+
// Conditional types like T extends U ? A : B
|
|
78
|
+
return 1 + Math.max(
|
|
79
|
+
getGenericDepth(typeNode.trueType),
|
|
80
|
+
getGenericDepth(typeNode.falseType)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
default:
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function checkTypeDepth(node, typeName) {
|
|
89
|
+
const depth = getGenericDepth(node);
|
|
90
|
+
if (depth > maxDepth) {
|
|
91
|
+
context.report({
|
|
92
|
+
node,
|
|
93
|
+
message: `T021: Generic nesting depth of ${depth} exceeds maximum of ${maxDepth}. Consider breaking down complex types into intermediate type aliases for better readability and TypeScript compiler performance.`
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
// Check type aliases - this is the main entry point
|
|
100
|
+
TSTypeAliasDeclaration(node) {
|
|
101
|
+
checkTypeDepth(node.typeAnnotation, node.id.name);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Check interface properties
|
|
105
|
+
TSPropertySignature(node) {
|
|
106
|
+
if (node.typeAnnotation && node.typeAnnotation.typeAnnotation) {
|
|
107
|
+
checkTypeDepth(node.typeAnnotation.typeAnnotation, 'property');
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Check function parameters
|
|
112
|
+
TSParameterProperty(node) {
|
|
113
|
+
if (node.parameter && node.parameter.typeAnnotation) {
|
|
114
|
+
checkTypeDepth(node.parameter.typeAnnotation.typeAnnotation, 'parameter');
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Check function return types
|
|
119
|
+
TSFunctionType(node) {
|
|
120
|
+
if (node.typeAnnotation && node.typeAnnotation.typeAnnotation) {
|
|
121
|
+
checkTypeDepth(node.typeAnnotation.typeAnnotation, 'return type');
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Check variable declarations
|
|
126
|
+
VariableDeclarator(node) {
|
|
127
|
+
if (node.id && node.id.typeAnnotation && node.id.typeAnnotation.typeAnnotation) {
|
|
128
|
+
checkTypeDepth(node.id.typeAnnotation.typeAnnotation, 'variable');
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// Check generic constraints
|
|
133
|
+
TSTypeParameter(node) {
|
|
134
|
+
if (node.constraint) {
|
|
135
|
+
checkTypeDepth(node.constraint, 'generic constraint');
|
|
136
|
+
}
|
|
137
|
+
if (node.default) {
|
|
138
|
+
checkTypeDepth(node.default, 'generic default');
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
// Check method signatures
|
|
143
|
+
TSMethodSignature(node) {
|
|
144
|
+
if (node.typeAnnotation && node.typeAnnotation.typeAnnotation) {
|
|
145
|
+
checkTypeDepth(node.typeAnnotation.typeAnnotation, 'method return type');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const rule = require('./plugin/rules/common/c041-no-config-inline.js');
|
|
4
|
+
|
|
5
|
+
// Simple test cases
|
|
6
|
+
const testCases = [
|
|
7
|
+
// Should NOT flag (false positives to avoid)
|
|
8
|
+
{ code: 'const inputType = "password";', shouldError: false, desc: 'InputType definition' },
|
|
9
|
+
{ code: 'const fieldType = "password";', shouldError: false, desc: 'Field type' },
|
|
10
|
+
{ code: 'const usePassword = "password_validation";', shouldError: false, desc: 'Hook usage' },
|
|
11
|
+
{ code: 'const testPassword = "test123";', shouldError: false, desc: 'Test data' },
|
|
12
|
+
{ code: 'const mockSecret = "mock_secret_key";', shouldError: false, desc: 'Mock data' },
|
|
13
|
+
{ code: 'const route = "/reset_password";', shouldError: false, desc: 'Route path' },
|
|
14
|
+
|
|
15
|
+
// SHOULD flag (real sensitive data)
|
|
16
|
+
{ code: 'const dbPassword = "MySecretP@ssw0rd123";', shouldError: true, desc: 'Real hardcoded password' },
|
|
17
|
+
{ code: 'const apiKey = "sk-1234567890abcdef1234567890abcdef";', shouldError: true, desc: 'Real API key' },
|
|
18
|
+
{ code: 'const authToken = "bearer_token_12345678901234567";', shouldError: true, desc: 'Real auth token' }
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
console.log('🧪 Testing ESLint C041 rule manually...\n');
|
|
22
|
+
|
|
23
|
+
let passed = 0;
|
|
24
|
+
let failed = 0;
|
|
25
|
+
|
|
26
|
+
// Mock context for testing
|
|
27
|
+
function createMockContext(code) {
|
|
28
|
+
return {
|
|
29
|
+
getSourceCode: () => ({
|
|
30
|
+
lines: code.split('\n')
|
|
31
|
+
}),
|
|
32
|
+
report: ({ node, messageId }) => {
|
|
33
|
+
return { reported: true, messageId };
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
testCases.forEach((testCase, index) => {
|
|
39
|
+
try {
|
|
40
|
+
let reported = false;
|
|
41
|
+
|
|
42
|
+
// Parse the code to extract literal nodes (simplified)
|
|
43
|
+
const literalMatch = testCase.code.match(/"([^"]+)"/);
|
|
44
|
+
if (literalMatch) {
|
|
45
|
+
const mockNode = {
|
|
46
|
+
value: literalMatch[1],
|
|
47
|
+
loc: { start: { line: 1 } }
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const mockContext = {
|
|
51
|
+
getSourceCode: () => ({
|
|
52
|
+
lines: [testCase.code]
|
|
53
|
+
}),
|
|
54
|
+
report: ({ node, messageId }) => {
|
|
55
|
+
reported = true;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const ruleImplementation = rule.create(mockContext);
|
|
60
|
+
ruleImplementation.Literal(mockNode);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const testPassed = reported === testCase.shouldError;
|
|
64
|
+
|
|
65
|
+
if (testPassed) {
|
|
66
|
+
console.log(`✅ Test ${index + 1}: ${testCase.desc}`);
|
|
67
|
+
passed++;
|
|
68
|
+
} else {
|
|
69
|
+
console.log(`❌ Test ${index + 1}: ${testCase.desc}`);
|
|
70
|
+
console.log(` Expected: ${testCase.shouldError ? 'Should flag' : 'Should NOT flag'}`);
|
|
71
|
+
console.log(` Actual: ${reported ? 'Flagged' : 'Not flagged'}`);
|
|
72
|
+
failed++;
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.log(`💥 Test ${index + 1}: ${testCase.desc} - Error: ${error.message}`);
|
|
76
|
+
failed++;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
console.log(`\n📊 Test Results: ${passed} passed, ${failed} failed`);
|
|
81
|
+
console.log(`Success rate: ${Math.round((passed / (passed + failed)) * 100)}%`);
|
|
82
|
+
|
|
83
|
+
if (failed === 0) {
|
|
84
|
+
console.log('\n🎉 All ESLint rule tests passed!');
|
|
85
|
+
} else {
|
|
86
|
+
console.log('\n⚠️ Some tests failed. Review the rule logic.');
|
|
87
|
+
}
|