@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,601 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Analysis Engine Plugin
|
|
3
|
+
* Following Rule C005: Single responsibility - ESLint integration
|
|
4
|
+
* Following Rule C014: Dependency injection - implements interface
|
|
5
|
+
* Following Rule C015: Use domain language - clear ESLint terms
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const AnalysisEngineInterface = require('../core/interfaces/analysis-engine.interface');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
class ESLintEngine extends AnalysisEngineInterface {
|
|
13
|
+
constructor() {
|
|
14
|
+
super('eslint', '8.x', ['typescript', 'javascript']);
|
|
15
|
+
|
|
16
|
+
this.eslint = null;
|
|
17
|
+
this.configFiles = new Map();
|
|
18
|
+
this.ruleMapping = new Map();
|
|
19
|
+
|
|
20
|
+
// Load rule mapping immediately (synchronous)
|
|
21
|
+
try {
|
|
22
|
+
this.loadRuleMappingSync();
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('🚨 Constructor failed to load mapping:', error.message);
|
|
25
|
+
this.createDefaultRuleMapping();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Load SunLint to ESLint rule mapping (synchronous)
|
|
31
|
+
*/
|
|
32
|
+
loadRuleMappingSync() {
|
|
33
|
+
try {
|
|
34
|
+
const mappingPath = path.resolve(__dirname, '../config/eslint-rule-mapping.json');
|
|
35
|
+
|
|
36
|
+
if (fs.existsSync(mappingPath)) {
|
|
37
|
+
const mappingData = JSON.parse(fs.readFileSync(mappingPath, 'utf8'));
|
|
38
|
+
const mapping = mappingData.mappings || mappingData;
|
|
39
|
+
|
|
40
|
+
for (const [sunlintRule, eslintRules] of Object.entries(mapping)) {
|
|
41
|
+
this.ruleMapping.set(sunlintRule, eslintRules);
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
// Create default mapping for common rules
|
|
45
|
+
this.createDefaultRuleMapping();
|
|
46
|
+
console.warn('⚠️ Using default ESLint rule mapping');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn('⚠️ [ESLintEngine] Failed to load ESLint rule mapping:', error.message);
|
|
51
|
+
this.createDefaultRuleMapping();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize ESLint engine with configuration
|
|
57
|
+
* Following Rule C006: Verb-noun naming
|
|
58
|
+
* @param {Object} config - Engine configuration
|
|
59
|
+
*/
|
|
60
|
+
async initialize(config) {
|
|
61
|
+
try {
|
|
62
|
+
// Store verbosity setting for use in other methods
|
|
63
|
+
this.verbose = config?.verbose || false;
|
|
64
|
+
|
|
65
|
+
// Dynamically import ESLint
|
|
66
|
+
const { ESLint } = await this.loadESLint();
|
|
67
|
+
|
|
68
|
+
// Initialize ESLint with base configuration (v9+ compatible)
|
|
69
|
+
this.eslint = new ESLint({
|
|
70
|
+
overrideConfigFile: true, // Replaces useEslintrc: false
|
|
71
|
+
overrideConfig: this.createBaseConfig(),
|
|
72
|
+
fix: config?.fix || false,
|
|
73
|
+
cache: config?.cache || false,
|
|
74
|
+
cwd: process.cwd()
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Rule mapping already loaded in constructor
|
|
78
|
+
if (this.verbose) {
|
|
79
|
+
console.log(`🔧 [ESLintEngine] Initialize: Rule mapping size = ${this.ruleMapping.size}`);
|
|
80
|
+
console.log(`🔧 ESLint engine initialized`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.initialized = true;
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Failed to initialize ESLint engine:', error.message);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Load ESLint dynamically
|
|
93
|
+
* Following Rule C006: Verb-noun naming
|
|
94
|
+
* @returns {Promise<Object>} ESLint module
|
|
95
|
+
*/
|
|
96
|
+
async loadESLint() {
|
|
97
|
+
try {
|
|
98
|
+
// Try to load ESLint from node_modules
|
|
99
|
+
return await import('eslint');
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// Fallback to require for older versions
|
|
102
|
+
try {
|
|
103
|
+
return require('eslint');
|
|
104
|
+
} catch (requireError) {
|
|
105
|
+
throw new Error('ESLint not found. Please install ESLint: npm install eslint');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Create base ESLint configuration
|
|
112
|
+
* Following Rule C006: Verb-noun naming
|
|
113
|
+
* @returns {Object} ESLint configuration
|
|
114
|
+
*/
|
|
115
|
+
createBaseConfig() {
|
|
116
|
+
// ESLint v9+ flat config format
|
|
117
|
+
return {
|
|
118
|
+
languageOptions: {
|
|
119
|
+
ecmaVersion: 'latest',
|
|
120
|
+
sourceType: 'module',
|
|
121
|
+
parserOptions: {
|
|
122
|
+
ecmaFeatures: {
|
|
123
|
+
jsx: true
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
globals: {
|
|
127
|
+
console: 'readonly',
|
|
128
|
+
process: 'readonly',
|
|
129
|
+
Buffer: 'readonly',
|
|
130
|
+
__dirname: 'readonly',
|
|
131
|
+
__filename: 'readonly',
|
|
132
|
+
module: 'readonly',
|
|
133
|
+
require: 'readonly',
|
|
134
|
+
exports: 'readonly',
|
|
135
|
+
global: 'readonly'
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
plugins: {},
|
|
139
|
+
rules: {}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Load SunLint to ESLint rule mapping
|
|
145
|
+
* Following Rule C006: Verb-noun naming
|
|
146
|
+
*/
|
|
147
|
+
async loadRuleMapping() {
|
|
148
|
+
// Rule mapping already loaded in constructor - skip async load
|
|
149
|
+
console.log(`� [ESLintEngine] Skipping async loadRuleMapping, using constructor mapping (size: ${this.ruleMapping.size})`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create default rule mapping
|
|
155
|
+
* Following Rule C006: Verb-noun naming
|
|
156
|
+
*/
|
|
157
|
+
createDefaultRuleMapping() {
|
|
158
|
+
console.log(`🚨 [ESLintEngine] createDefaultRuleMapping() called - MAPPING WILL BE OVERWRITTEN!`);
|
|
159
|
+
|
|
160
|
+
// Map common SunLint rules to ESLint equivalents
|
|
161
|
+
const defaultMappings = {
|
|
162
|
+
'C005': ['max-statements-per-line', 'complexity'],
|
|
163
|
+
'C006': ['func-names', 'func-name-matching'],
|
|
164
|
+
'C007': ['spaced-comment', 'no-inline-comments'],
|
|
165
|
+
'C014': ['no-new'],
|
|
166
|
+
'C019': ['no-console'],
|
|
167
|
+
'C031': ['no-implicit-coercion'],
|
|
168
|
+
'C033': ['prefer-const', 'no-var'],
|
|
169
|
+
'C037': ['consistent-return'],
|
|
170
|
+
'C040': ['no-duplicate-imports']
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// CLEAR existing mapping first
|
|
174
|
+
console.log(`🚨 [ESLintEngine] Clearing existing ${this.ruleMapping.size} rules`);
|
|
175
|
+
this.ruleMapping.clear();
|
|
176
|
+
|
|
177
|
+
for (const [sunlintRule, eslintRules] of Object.entries(defaultMappings)) {
|
|
178
|
+
this.ruleMapping.set(sunlintRule, eslintRules);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log(`🚨 [ESLintEngine] Set ${this.ruleMapping.size} default rules`);
|
|
182
|
+
console.warn('⚠️ Using default ESLint rule mapping');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Load React ESLint plugin
|
|
187
|
+
* Following Rule C006: Verb-noun naming
|
|
188
|
+
*/
|
|
189
|
+
loadReactPlugin() {
|
|
190
|
+
try {
|
|
191
|
+
// Try current working directory first
|
|
192
|
+
return require(require.resolve('eslint-plugin-react', { paths: [process.cwd()] }));
|
|
193
|
+
} catch (error) {
|
|
194
|
+
try {
|
|
195
|
+
// Fallback to main package
|
|
196
|
+
return require('eslint-plugin-react');
|
|
197
|
+
} catch (fallbackError) {
|
|
198
|
+
console.warn('⚠️ React ESLint plugin not available:', error.message);
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Load React Hooks ESLint plugin
|
|
206
|
+
* Following Rule C006: Verb-noun naming
|
|
207
|
+
*/
|
|
208
|
+
loadReactHooksPlugin() {
|
|
209
|
+
try {
|
|
210
|
+
// Try current working directory first
|
|
211
|
+
return require(require.resolve('eslint-plugin-react-hooks', { paths: [process.cwd()] }));
|
|
212
|
+
} catch (error) {
|
|
213
|
+
try {
|
|
214
|
+
// Fallback to main package
|
|
215
|
+
return require('eslint-plugin-react-hooks');
|
|
216
|
+
} catch (fallbackError) {
|
|
217
|
+
console.warn('⚠️ React Hooks ESLint plugin not available:', error.message);
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Load TypeScript parser
|
|
225
|
+
* Following Rule C006: Verb-noun naming
|
|
226
|
+
*/
|
|
227
|
+
loadTypeScriptParser() {
|
|
228
|
+
try {
|
|
229
|
+
return require('@typescript-eslint/parser');
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.warn('⚠️ TypeScript parser not available:', error.message);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Load TypeScript ESLint plugin
|
|
238
|
+
* Following Rule C006: Verb-noun naming
|
|
239
|
+
*/
|
|
240
|
+
loadTypeScriptPlugin() {
|
|
241
|
+
try {
|
|
242
|
+
return require('@typescript-eslint/eslint-plugin');
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.warn('⚠️ TypeScript ESLint plugin not available:', error.message);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Load custom ESLint plugin with SunLint rules
|
|
251
|
+
* Following Rule C006: Verb-noun naming
|
|
252
|
+
*/
|
|
253
|
+
loadCustomPlugin() {
|
|
254
|
+
try {
|
|
255
|
+
const customRulesPath = path.resolve(__dirname, '../integrations/eslint/plugin/rules');
|
|
256
|
+
const plugin = {
|
|
257
|
+
rules: {}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Load all custom rules dynamically
|
|
261
|
+
const ruleDirs = ['common', 'typescript', 'security'];
|
|
262
|
+
for (const dir of ruleDirs) {
|
|
263
|
+
const dirPath = path.join(customRulesPath, dir);
|
|
264
|
+
if (fs.existsSync(dirPath)) {
|
|
265
|
+
const ruleFiles = fs.readdirSync(dirPath).filter(file => file.endsWith('.js'));
|
|
266
|
+
for (const file of ruleFiles) {
|
|
267
|
+
const rulePath = path.join(dirPath, file);
|
|
268
|
+
try {
|
|
269
|
+
const rule = require(rulePath);
|
|
270
|
+
// Keep full filename as rule name for Security rules, remove prefix for others
|
|
271
|
+
const ruleName = dir === 'security' ?
|
|
272
|
+
file.replace('.js', '') :
|
|
273
|
+
file.replace('.js', '').replace(/^[ct]\d+-/, ''); // Remove prefix like c010-, t020-
|
|
274
|
+
plugin.rules[ruleName] = rule;
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.warn(`⚠️ Failed to load custom rule ${file}:`, error.message);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
console.log(`✅ [ESLintEngine] Loaded ${Object.keys(plugin.rules).length} custom rules`);
|
|
283
|
+
return plugin;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.warn('⚠️ Failed to load custom plugin:', error.message);
|
|
286
|
+
return { rules: {} };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Analyze files using ESLint
|
|
292
|
+
* Following Rule C006: Verb-noun naming
|
|
293
|
+
* @param {string[]} files - Files to analyze
|
|
294
|
+
* @param {Object[]} rules - Rules to apply
|
|
295
|
+
* @param {Object} options - Analysis options
|
|
296
|
+
* @returns {Promise<Object>} Analysis results
|
|
297
|
+
*/
|
|
298
|
+
async analyze(files, rules, options) {
|
|
299
|
+
if (!this.initialized) {
|
|
300
|
+
throw new Error('ESLint engine not initialized');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const results = {
|
|
304
|
+
results: [],
|
|
305
|
+
filesAnalyzed: 0,
|
|
306
|
+
engine: 'eslint',
|
|
307
|
+
metadata: {
|
|
308
|
+
rulesAnalyzed: [],
|
|
309
|
+
eslintRulesUsed: []
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
// Filter files for JS/TS only
|
|
315
|
+
const jstsFiles = files.filter(file => this.isJavaScriptTypeScriptFile(file));
|
|
316
|
+
|
|
317
|
+
if (jstsFiles.length === 0) {
|
|
318
|
+
console.warn('⚠️ No JavaScript/TypeScript files found for ESLint analysis');
|
|
319
|
+
return results;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Convert SunLint rules to ESLint rules
|
|
323
|
+
const eslintConfig = await this.createAnalysisConfig(rules);
|
|
324
|
+
|
|
325
|
+
if (Object.keys(eslintConfig.rules).length === 0) {
|
|
326
|
+
console.warn('⚠️ No ESLint rules mapped from SunLint rules');
|
|
327
|
+
return results;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Reconfigure ESLint with analysis-specific rules (v9+ compatible)
|
|
331
|
+
const { ESLint } = await this.loadESLint();
|
|
332
|
+
const eslintInstance = new ESLint({
|
|
333
|
+
overrideConfigFile: true,
|
|
334
|
+
overrideConfig: {
|
|
335
|
+
...this.createBaseConfig(),
|
|
336
|
+
...eslintConfig
|
|
337
|
+
},
|
|
338
|
+
cwd: process.cwd()
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Run ESLint analysis
|
|
342
|
+
const eslintResults = await eslintInstance.lintFiles(jstsFiles);
|
|
343
|
+
|
|
344
|
+
// Convert ESLint results to SunLint format
|
|
345
|
+
results.results = this.convertESLintResults(eslintResults, rules);
|
|
346
|
+
results.filesAnalyzed = jstsFiles.length;
|
|
347
|
+
results.metadata.rulesAnalyzed = rules.map(r => r.id);
|
|
348
|
+
results.metadata.eslintRulesUsed = Object.keys(eslintConfig.rules);
|
|
349
|
+
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error('❌ ESLint analysis failed:', error.message);
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return results;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Check if file is JavaScript or TypeScript
|
|
360
|
+
* Following Rule C006: Verb-noun naming
|
|
361
|
+
* @param {string} filePath - File path to check
|
|
362
|
+
* @returns {boolean} True if JS/TS file
|
|
363
|
+
*/
|
|
364
|
+
isJavaScriptTypeScriptFile(filePath) {
|
|
365
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
366
|
+
return ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'].includes(ext);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Check if rules need React plugins
|
|
371
|
+
*/
|
|
372
|
+
needsReactPlugins(rules) {
|
|
373
|
+
return rules.some(rule => {
|
|
374
|
+
const ruleId = typeof rule === 'string' ? rule : rule.id || rule.name;
|
|
375
|
+
return ruleId && ruleId.startsWith('R');
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Check if rules need TypeScript plugins
|
|
381
|
+
*/
|
|
382
|
+
needsTypeScriptPlugins(rules) {
|
|
383
|
+
return rules.some(rule => {
|
|
384
|
+
const ruleId = typeof rule === 'string' ? rule : rule.id || rule.name;
|
|
385
|
+
return ruleId && ruleId.startsWith('T');
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Build dynamic plugins based on rules being analyzed
|
|
391
|
+
* @param {Array} rules - Rules to analyze
|
|
392
|
+
* @returns {Object} Plugin configuration
|
|
393
|
+
*/
|
|
394
|
+
buildPluginConfig(rules) {
|
|
395
|
+
const plugins = {
|
|
396
|
+
'custom': this.loadCustomPlugin()
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// Only load TypeScript plugin if needed
|
|
400
|
+
if (this.needsTypeScriptPlugins(rules)) {
|
|
401
|
+
plugins['@typescript-eslint'] = this.loadTypeScriptPlugin();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Only load React plugins if needed
|
|
405
|
+
if (this.needsReactPlugins(rules)) {
|
|
406
|
+
plugins['react'] = this.loadReactPlugin();
|
|
407
|
+
plugins['react-hooks'] = this.loadReactHooksPlugin();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return plugins;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Create ESLint configuration for analysis
|
|
415
|
+
* Following Rule C006: Verb-noun naming
|
|
416
|
+
* @param {Object[]} rules - SunLint rules
|
|
417
|
+
* @returns {Promise<Object>} ESLint configuration
|
|
418
|
+
*/
|
|
419
|
+
async createAnalysisConfig(rules) {
|
|
420
|
+
// ESLint v9+ flat config format
|
|
421
|
+
const config = {
|
|
422
|
+
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'], // Add file patterns
|
|
423
|
+
languageOptions: {
|
|
424
|
+
ecmaVersion: 'latest',
|
|
425
|
+
sourceType: 'module',
|
|
426
|
+
parser: this.loadTypeScriptParser(),
|
|
427
|
+
parserOptions: {
|
|
428
|
+
ecmaFeatures: {
|
|
429
|
+
jsx: true
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
globals: {
|
|
433
|
+
console: 'readonly',
|
|
434
|
+
process: 'readonly',
|
|
435
|
+
Buffer: 'readonly',
|
|
436
|
+
__dirname: 'readonly',
|
|
437
|
+
__filename: 'readonly',
|
|
438
|
+
module: 'readonly',
|
|
439
|
+
require: 'readonly',
|
|
440
|
+
exports: 'readonly',
|
|
441
|
+
global: 'readonly'
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
plugins: this.buildPluginConfig(rules),
|
|
445
|
+
settings: this.needsReactPlugins(rules) ? {
|
|
446
|
+
react: {
|
|
447
|
+
version: 'detect'
|
|
448
|
+
}
|
|
449
|
+
} : {},
|
|
450
|
+
rules: {}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// Map SunLint rules to ESLint rules
|
|
454
|
+
for (const rule of rules) {
|
|
455
|
+
const eslintRules = this.ruleMapping.get(rule.id);
|
|
456
|
+
|
|
457
|
+
if (eslintRules && Array.isArray(eslintRules)) {
|
|
458
|
+
for (const eslintRule of eslintRules) {
|
|
459
|
+
// Set rule severity based on SunLint rule
|
|
460
|
+
const severity = this.mapSeverity(rule.severity || 'warning');
|
|
461
|
+
config.rules[eslintRule] = severity;
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
// Check if it's a custom rule (C010, etc.)
|
|
465
|
+
const customRuleName = `custom/${rule.id.toLowerCase()}`;
|
|
466
|
+
const ruleConfig = this.mapSeverity(rule.severity || 'warning');
|
|
467
|
+
|
|
468
|
+
// Add rule configuration for specific rules
|
|
469
|
+
if (rule.id === 'C010') {
|
|
470
|
+
config.rules[customRuleName] = [ruleConfig, { maxDepth: 3 }];
|
|
471
|
+
} else {
|
|
472
|
+
config.rules[customRuleName] = ruleConfig;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return config;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Map SunLint severity to ESLint severity
|
|
482
|
+
* Following Rule C006: Verb-noun naming
|
|
483
|
+
* @param {string} sunlintSeverity - SunLint severity level
|
|
484
|
+
* @returns {number|string} ESLint severity
|
|
485
|
+
*/
|
|
486
|
+
mapSeverity(sunlintSeverity) {
|
|
487
|
+
switch (sunlintSeverity.toLowerCase()) {
|
|
488
|
+
case 'error': return 'error';
|
|
489
|
+
case 'warning': return 'warn';
|
|
490
|
+
case 'info': return 'warn';
|
|
491
|
+
default: return 'warn';
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Convert ESLint results to SunLint format
|
|
497
|
+
* Following Rule C006: Verb-noun naming
|
|
498
|
+
* @param {Object[]} eslintResults - ESLint results
|
|
499
|
+
* @param {Object[]} originalRules - Original SunLint rules
|
|
500
|
+
* @returns {Object[]} SunLint formatted results
|
|
501
|
+
*/
|
|
502
|
+
convertESLintResults(eslintResults, originalRules) {
|
|
503
|
+
const sunlintResults = [];
|
|
504
|
+
|
|
505
|
+
for (const eslintResult of eslintResults) {
|
|
506
|
+
if (eslintResult.messages.length === 0) continue;
|
|
507
|
+
|
|
508
|
+
const fileResult = {
|
|
509
|
+
file: eslintResult.filePath,
|
|
510
|
+
violations: []
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
for (const message of eslintResult.messages) {
|
|
514
|
+
const violation = {
|
|
515
|
+
ruleId: this.mapESLintRuleToSunLint(message.ruleId, originalRules),
|
|
516
|
+
message: message.message,
|
|
517
|
+
severity: message.severity === 2 ? 'error' : 'warning',
|
|
518
|
+
line: message.line,
|
|
519
|
+
column: message.column,
|
|
520
|
+
endLine: message.endLine,
|
|
521
|
+
endColumn: message.endColumn,
|
|
522
|
+
engine: 'eslint',
|
|
523
|
+
eslintRule: message.ruleId,
|
|
524
|
+
fix: message.fix ? {
|
|
525
|
+
range: message.fix.range,
|
|
526
|
+
text: message.fix.text
|
|
527
|
+
} : null
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
fileResult.violations.push(violation);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (fileResult.violations.length > 0) {
|
|
534
|
+
sunlintResults.push(fileResult);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return sunlintResults;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Map ESLint rule back to SunLint rule
|
|
543
|
+
* Following Rule C006: Verb-noun naming
|
|
544
|
+
* @param {string} eslintRuleId - ESLint rule ID
|
|
545
|
+
* @param {Object[]} originalRules - Original SunLint rules
|
|
546
|
+
* @returns {string} SunLint rule ID
|
|
547
|
+
*/
|
|
548
|
+
mapESLintRuleToSunLint(eslintRuleId, originalRules) {
|
|
549
|
+
// Find which SunLint rule maps to this ESLint rule
|
|
550
|
+
for (const [sunlintRule, eslintRules] of this.ruleMapping.entries()) {
|
|
551
|
+
if (eslintRules.includes(eslintRuleId)) {
|
|
552
|
+
// Verify this rule was actually requested
|
|
553
|
+
const requestedRule = originalRules.find(r => r.id === sunlintRule);
|
|
554
|
+
if (requestedRule) {
|
|
555
|
+
return sunlintRule;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Fallback to ESLint rule ID if no mapping found
|
|
561
|
+
return eslintRuleId;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Get supported rules
|
|
566
|
+
* Following Rule C006: Verb-noun naming
|
|
567
|
+
* @returns {string[]} Supported rule IDs
|
|
568
|
+
*/
|
|
569
|
+
getSupportedRules() {
|
|
570
|
+
return Array.from(this.ruleMapping.keys());
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Check if rule is supported
|
|
575
|
+
* Following Rule C006: Verb-noun naming
|
|
576
|
+
* @param {string} ruleId - Rule ID to check
|
|
577
|
+
* @returns {boolean} True if supported
|
|
578
|
+
*/
|
|
579
|
+
isRuleSupported(ruleId) {
|
|
580
|
+
const supported = this.ruleMapping.has(ruleId);
|
|
581
|
+
if (this.verbose) {
|
|
582
|
+
console.log(`🔍 [ESLintEngine] isRuleSupported(${ruleId}): ${supported} (mapping size: ${this.ruleMapping.size})`);
|
|
583
|
+
}
|
|
584
|
+
return supported;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Cleanup ESLint engine resources
|
|
589
|
+
* Following Rule C006: Verb-noun naming
|
|
590
|
+
*/
|
|
591
|
+
async cleanup() {
|
|
592
|
+
this.eslint = null;
|
|
593
|
+
this.configFiles.clear();
|
|
594
|
+
this.ruleMapping.clear();
|
|
595
|
+
|
|
596
|
+
await super.cleanup();
|
|
597
|
+
console.log('🔧 ESLint engine cleanup completed');
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
module.exports = ESLintEngine;
|