@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
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom ESLint rule for: T026 – Limit deeply nested generics
|
|
3
|
-
* Rule ID: custom/t026
|
|
4
|
-
* Purpose: Prevent deeply nested generic type parameters to maintain type readability and reduce cognitive load
|
|
5
|
-
*
|
|
6
|
-
* Following Vietnamese Coding Standards:
|
|
7
|
-
* - Rule C005: Each function should do one thing (this rule focuses solely on generic nesting)
|
|
8
|
-
* - Rule C015: Use domain language in naming (clear error messages in both English and Vietnamese)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
"use strict";
|
|
12
|
-
|
|
13
|
-
module.exports = {
|
|
14
|
-
meta: {
|
|
15
|
-
type: "suggestion",
|
|
16
|
-
docs: {
|
|
17
|
-
description: "Limit deeply nested generics to maintain type readability",
|
|
18
|
-
category: "TypeScript",
|
|
19
|
-
recommended: true,
|
|
20
|
-
},
|
|
21
|
-
fixable: null,
|
|
22
|
-
schema: [
|
|
23
|
-
{
|
|
24
|
-
type: "object",
|
|
25
|
-
properties: {
|
|
26
|
-
maxDepth: {
|
|
27
|
-
type: "integer",
|
|
28
|
-
minimum: 1,
|
|
29
|
-
description: "Maximum allowed depth of nested generics (default: 3)"
|
|
30
|
-
},
|
|
31
|
-
allowUtilityTypes: {
|
|
32
|
-
type: "boolean",
|
|
33
|
-
description: "Whether to allow deeper nesting in utility types like Partial, Pick, etc. (default: true)"
|
|
34
|
-
},
|
|
35
|
-
exemptedTypeNames: {
|
|
36
|
-
type: "array",
|
|
37
|
-
items: { type: "string" },
|
|
38
|
-
description: "List of type names that are exempt from the depth check"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
additionalProperties: false
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
messages: {
|
|
45
|
-
tooDeepNesting: "Generic type nesting is too deep ({{depth}} levels). Maximum allowed is {{maxDepth}} levels. Consider breaking down complex types into simpler ones.",
|
|
46
|
-
tooDeepNestingVietnamese: "Kiểu generic lồng quá sâu ({{depth}} cấp). Tối đa cho phép là {{maxDepth}} cấp. Hãy chia nhỏ kiểu phức tạp thành các kiểu đơn giản hơn."
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
create(context) {
|
|
51
|
-
const options = context.options[0] || {};
|
|
52
|
-
const maxDepth = options.maxDepth || 3;
|
|
53
|
-
const allowUtilityTypes = options.allowUtilityTypes !== false;
|
|
54
|
-
const exemptedTypeNames = new Set(options.exemptedTypeNames || []);
|
|
55
|
-
|
|
56
|
-
// Common TypeScript utility types that might need deeper nesting
|
|
57
|
-
const utilityTypes = new Set([
|
|
58
|
-
'Partial', 'Required', 'Readonly', 'Pick', 'Omit', 'Exclude', 'Extract',
|
|
59
|
-
'NonNullable', 'Parameters', 'ConstructorParameters', 'ReturnType',
|
|
60
|
-
'InstanceType', 'ThisParameterType', 'OmitThisParameter', 'ThisType',
|
|
61
|
-
'Uppercase', 'Lowercase', 'Capitalize', 'Uncapitalize'
|
|
62
|
-
// Note: Removed Promise, Array, Record, Map, Set to properly catch deep nesting
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Calculate the depth of nested generics in a type node
|
|
67
|
-
* @param {Object} node - The TypeScript AST node
|
|
68
|
-
* @param {number} currentDepth - Current depth level
|
|
69
|
-
* @returns {number} The maximum depth found
|
|
70
|
-
*/
|
|
71
|
-
function calculateGenericDepth(node, currentDepth = 0) {
|
|
72
|
-
if (!node) return currentDepth;
|
|
73
|
-
|
|
74
|
-
let maxDepth = currentDepth;
|
|
75
|
-
|
|
76
|
-
switch (node.type) {
|
|
77
|
-
case 'TSTypeReference':
|
|
78
|
-
// Check typeArguments (not typeParameters) for type references
|
|
79
|
-
if (node.typeArguments && node.typeArguments.params) {
|
|
80
|
-
const newDepth = currentDepth + 1;
|
|
81
|
-
for (const param of node.typeArguments.params) {
|
|
82
|
-
const paramDepth = calculateGenericDepth(param, newDepth);
|
|
83
|
-
maxDepth = Math.max(maxDepth, paramDepth);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
break;
|
|
87
|
-
|
|
88
|
-
case 'TSUnionType':
|
|
89
|
-
case 'TSIntersectionType':
|
|
90
|
-
if (node.types) {
|
|
91
|
-
for (const type of node.types) {
|
|
92
|
-
const typeDepth = calculateGenericDepth(type, currentDepth);
|
|
93
|
-
maxDepth = Math.max(maxDepth, typeDepth);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
|
|
98
|
-
case 'TSTupleType':
|
|
99
|
-
if (node.elementTypes) {
|
|
100
|
-
for (const element of node.elementTypes) {
|
|
101
|
-
const elementDepth = calculateGenericDepth(element, currentDepth);
|
|
102
|
-
maxDepth = Math.max(maxDepth, elementDepth);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
|
|
107
|
-
case 'TSArrayType':
|
|
108
|
-
if (node.elementType) {
|
|
109
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.elementType, currentDepth));
|
|
110
|
-
}
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
case 'TSMappedType':
|
|
114
|
-
if (node.typeParameter) {
|
|
115
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.typeParameter, currentDepth));
|
|
116
|
-
}
|
|
117
|
-
if (node.typeAnnotation) {
|
|
118
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.typeAnnotation, currentDepth));
|
|
119
|
-
}
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
|
-
case 'TSConditionalType':
|
|
123
|
-
if (node.checkType) {
|
|
124
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.checkType, currentDepth));
|
|
125
|
-
}
|
|
126
|
-
if (node.extendsType) {
|
|
127
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.extendsType, currentDepth));
|
|
128
|
-
}
|
|
129
|
-
if (node.trueType) {
|
|
130
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.trueType, currentDepth));
|
|
131
|
-
}
|
|
132
|
-
if (node.falseType) {
|
|
133
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.falseType, currentDepth));
|
|
134
|
-
}
|
|
135
|
-
break;
|
|
136
|
-
|
|
137
|
-
case 'TSIndexedAccessType':
|
|
138
|
-
if (node.objectType) {
|
|
139
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.objectType, currentDepth));
|
|
140
|
-
}
|
|
141
|
-
if (node.indexType) {
|
|
142
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.indexType, currentDepth));
|
|
143
|
-
}
|
|
144
|
-
break;
|
|
145
|
-
|
|
146
|
-
case 'TSTypeQuery':
|
|
147
|
-
if (node.exprName) {
|
|
148
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.exprName, currentDepth));
|
|
149
|
-
}
|
|
150
|
-
break;
|
|
151
|
-
|
|
152
|
-
case 'TSFunctionType':
|
|
153
|
-
case 'TSConstructorType':
|
|
154
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
155
|
-
for (const param of node.typeParameters.params) {
|
|
156
|
-
const paramDepth = calculateGenericDepth(param, currentDepth + 1);
|
|
157
|
-
maxDepth = Math.max(maxDepth, paramDepth);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (node.parameters) {
|
|
161
|
-
for (const param of node.parameters) {
|
|
162
|
-
if (param.typeAnnotation) {
|
|
163
|
-
const paramDepth = calculateGenericDepth(param.typeAnnotation.typeAnnotation, currentDepth);
|
|
164
|
-
maxDepth = Math.max(maxDepth, paramDepth);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
if (node.typeAnnotation) {
|
|
169
|
-
maxDepth = Math.max(maxDepth, calculateGenericDepth(node.typeAnnotation.typeAnnotation, currentDepth));
|
|
170
|
-
}
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return maxDepth;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Check if a type reference is a utility type that should be exempted
|
|
179
|
-
* @param {Object} node - The TypeScript type reference node
|
|
180
|
-
* @returns {boolean} Whether this is an exempted utility type
|
|
181
|
-
*/
|
|
182
|
-
function isExemptedType(node) {
|
|
183
|
-
if (node.type !== 'TSTypeReference' || !node.typeName) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
let typeName = '';
|
|
188
|
-
if (node.typeName.type === 'Identifier') {
|
|
189
|
-
typeName = node.typeName.name;
|
|
190
|
-
} else if (node.typeName.type === 'TSQualifiedName') {
|
|
191
|
-
// Handle qualified names like React.Component
|
|
192
|
-
typeName = getQualifiedTypeName(node.typeName);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return exemptedTypeNames.has(typeName) ||
|
|
196
|
-
(allowUtilityTypes && utilityTypes.has(typeName));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Get the full qualified type name from a TSQualifiedName node
|
|
201
|
-
* @param {Object} node - The TSQualifiedName node
|
|
202
|
-
* @returns {string} The full qualified name
|
|
203
|
-
*/
|
|
204
|
-
function getQualifiedTypeName(node) {
|
|
205
|
-
if (node.type === 'Identifier') {
|
|
206
|
-
return node.name;
|
|
207
|
-
}
|
|
208
|
-
if (node.type === 'TSQualifiedName') {
|
|
209
|
-
return `${getQualifiedTypeName(node.left)}.${node.right.name}`;
|
|
210
|
-
}
|
|
211
|
-
return '';
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Check a type node for excessive generic nesting
|
|
216
|
-
* @param {Object} node - The TypeScript AST node to check
|
|
217
|
-
*/
|
|
218
|
-
function checkTypeNode(node) {
|
|
219
|
-
if (!node) return;
|
|
220
|
-
|
|
221
|
-
// Skip utility types if allowed
|
|
222
|
-
if (isExemptedType(node)) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const depth = calculateGenericDepth(node);
|
|
227
|
-
|
|
228
|
-
if (depth > maxDepth) {
|
|
229
|
-
context.report({
|
|
230
|
-
node,
|
|
231
|
-
messageId: "tooDeepNesting",
|
|
232
|
-
data: {
|
|
233
|
-
depth,
|
|
234
|
-
maxDepth
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return {
|
|
241
|
-
// Check type aliases
|
|
242
|
-
TSTypeAliasDeclaration(node) {
|
|
243
|
-
if (node.typeAnnotation) {
|
|
244
|
-
checkTypeNode(node.typeAnnotation);
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
// Check interface declarations
|
|
249
|
-
TSInterfaceDeclaration(node) {
|
|
250
|
-
if (node.extends) {
|
|
251
|
-
for (const extend of node.extends) {
|
|
252
|
-
checkTypeNode(extend);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (node.body && node.body.body) {
|
|
257
|
-
for (const member of node.body.body) {
|
|
258
|
-
if (member.typeAnnotation && member.typeAnnotation.typeAnnotation) {
|
|
259
|
-
checkTypeNode(member.typeAnnotation.typeAnnotation);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
},
|
|
264
|
-
|
|
265
|
-
// Check function declarations
|
|
266
|
-
FunctionDeclaration(node) {
|
|
267
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
268
|
-
for (const param of node.typeParameters.params) {
|
|
269
|
-
if (param.constraint) {
|
|
270
|
-
checkTypeNode(param.constraint);
|
|
271
|
-
}
|
|
272
|
-
if (param.default) {
|
|
273
|
-
checkTypeNode(param.default);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
|
|
279
|
-
// Check function expressions and arrow functions
|
|
280
|
-
FunctionExpression(node) {
|
|
281
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
282
|
-
for (const param of node.typeParameters.params) {
|
|
283
|
-
if (param.constraint) {
|
|
284
|
-
checkTypeNode(param.constraint);
|
|
285
|
-
}
|
|
286
|
-
if (param.default) {
|
|
287
|
-
checkTypeNode(param.default);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
|
|
293
|
-
ArrowFunctionExpression(node) {
|
|
294
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
295
|
-
for (const param of node.typeParameters.params) {
|
|
296
|
-
if (param.constraint) {
|
|
297
|
-
checkTypeNode(param.constraint);
|
|
298
|
-
}
|
|
299
|
-
if (param.default) {
|
|
300
|
-
checkTypeNode(param.default);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
},
|
|
305
|
-
|
|
306
|
-
// Check method definitions
|
|
307
|
-
MethodDefinition(node) {
|
|
308
|
-
if (node.value && node.value.typeParameters && node.value.typeParameters.params) {
|
|
309
|
-
for (const param of node.value.typeParameters.params) {
|
|
310
|
-
if (param.constraint) {
|
|
311
|
-
checkTypeNode(param.constraint);
|
|
312
|
-
}
|
|
313
|
-
if (param.default) {
|
|
314
|
-
checkTypeNode(param.default);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
|
|
320
|
-
// Check variable declarations with type annotations
|
|
321
|
-
VariableDeclarator(node) {
|
|
322
|
-
if (node.id && node.id.typeAnnotation && node.id.typeAnnotation.typeAnnotation) {
|
|
323
|
-
checkTypeNode(node.id.typeAnnotation.typeAnnotation);
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
|
|
327
|
-
// Check property signatures
|
|
328
|
-
TSPropertySignature(node) {
|
|
329
|
-
if (node.typeAnnotation && node.typeAnnotation.typeAnnotation) {
|
|
330
|
-
checkTypeNode(node.typeAnnotation.typeAnnotation);
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
// Check method signatures
|
|
335
|
-
TSMethodSignature(node) {
|
|
336
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
337
|
-
for (const param of node.typeParameters.params) {
|
|
338
|
-
if (param.constraint) {
|
|
339
|
-
checkTypeNode(param.constraint);
|
|
340
|
-
}
|
|
341
|
-
if (param.default) {
|
|
342
|
-
checkTypeNode(param.default);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
|
|
348
|
-
// Check call signatures
|
|
349
|
-
TSCallSignatureDeclaration(node) {
|
|
350
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
351
|
-
for (const param of node.typeParameters.params) {
|
|
352
|
-
if (param.constraint) {
|
|
353
|
-
checkTypeNode(param.constraint);
|
|
354
|
-
}
|
|
355
|
-
if (param.default) {
|
|
356
|
-
checkTypeNode(param.default);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
|
|
362
|
-
// Check construct signatures
|
|
363
|
-
TSConstructSignatureDeclaration(node) {
|
|
364
|
-
if (node.typeParameters && node.typeParameters.params) {
|
|
365
|
-
for (const param of node.typeParameters.params) {
|
|
366
|
-
if (param.constraint) {
|
|
367
|
-
checkTypeNode(param.constraint);
|
|
368
|
-
}
|
|
369
|
-
if (param.default) {
|
|
370
|
-
checkTypeNode(param.default);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
},
|
|
377
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// Test file to verify ESLint integration
|
|
2
|
-
class UserManager {
|
|
3
|
-
private users: any[] = [];
|
|
4
|
-
|
|
5
|
-
constructor() {
|
|
6
|
-
// Rule C032: API call in constructor (should be flagged)
|
|
7
|
-
this.fetchUsers();
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Rule C006: Not verb-noun naming (should be flagged)
|
|
11
|
-
data() {
|
|
12
|
-
return this.users;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Rule C019: Using console.error for non-critical (should be flagged)
|
|
16
|
-
processUser(user: any) {
|
|
17
|
-
if (!user.name) {
|
|
18
|
-
console.error('User name is missing');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
this.users.push(user);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Rule C014: Direct new instead of DI (should be flagged)
|
|
25
|
-
createValidator() {
|
|
26
|
-
return new UserValidator();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private fetchUsers() {
|
|
30
|
-
// Mock API call
|
|
31
|
-
return fetch('/api/users');
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
class UserValidator {
|
|
36
|
-
validate(user: any) {
|
|
37
|
-
return user.name && user.email;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Rule C005: Function doing multiple things (should be flagged)
|
|
42
|
-
function processAndValidateUser(user: any) {
|
|
43
|
-
// Validation logic
|
|
44
|
-
if (!user.name) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Processing logic
|
|
49
|
-
user.processedAt = new Date();
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export { UserManager, UserValidator, processAndValidateUser };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// Test S003 rule patterns
|
|
2
|
-
window.location.href = req.query.redirectUrl; // Should match AssignmentExpression
|
|
3
|
-
location.href = req.body.targetUrl; // Should match AssignmentExpression
|
|
4
|
-
location.replace = req.params.url; // Should match AssignmentExpression
|
|
5
|
-
res.redirect(req.query.returnUrl); // Should match CallExpression
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
name: Code Quality & Security Check
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [main, develop]
|
|
6
|
-
push:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
# Parallel execution for faster CI
|
|
11
|
-
eslint:
|
|
12
|
-
name: ESLint Check
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v4
|
|
16
|
-
with:
|
|
17
|
-
fetch-depth: 0
|
|
18
|
-
|
|
19
|
-
- name: Setup Node.js
|
|
20
|
-
uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: '18'
|
|
23
|
-
cache: 'npm'
|
|
24
|
-
|
|
25
|
-
- name: Install dependencies
|
|
26
|
-
run: npm ci
|
|
27
|
-
|
|
28
|
-
- name: Run ESLint on changed files
|
|
29
|
-
if: github.event_name == 'pull_request'
|
|
30
|
-
run: |
|
|
31
|
-
CHANGED_FILES=$(git diff --name-only --diff-filter=AM origin/${{ github.base_ref }} | grep -E '\.(js|ts|tsx)$' | tr '\n' ' ')
|
|
32
|
-
if [ ! -z "$CHANGED_FILES" ]; then
|
|
33
|
-
npx eslint $CHANGED_FILES
|
|
34
|
-
else
|
|
35
|
-
echo "No JS/TS files changed"
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
- name: Run ESLint full scan
|
|
39
|
-
if: github.event_name == 'push'
|
|
40
|
-
run: npm run lint:eslint
|
|
41
|
-
|
|
42
|
-
sunlint:
|
|
43
|
-
name: SunLint Security & Quality Check
|
|
44
|
-
runs-on: ubuntu-latest
|
|
45
|
-
steps:
|
|
46
|
-
- uses: actions/checkout@v4
|
|
47
|
-
with:
|
|
48
|
-
fetch-depth: 0
|
|
49
|
-
|
|
50
|
-
- name: Setup Node.js
|
|
51
|
-
uses: actions/setup-node@v4
|
|
52
|
-
with:
|
|
53
|
-
node-version: '18'
|
|
54
|
-
cache: 'npm'
|
|
55
|
-
|
|
56
|
-
- name: Install dependencies
|
|
57
|
-
run: npm ci
|
|
58
|
-
|
|
59
|
-
- name: Install SunLint
|
|
60
|
-
run: npm install -g @sun/sunlint
|
|
61
|
-
|
|
62
|
-
- name: Run SunLint on changed files (PR)
|
|
63
|
-
if: github.event_name == 'pull_request'
|
|
64
|
-
run: |
|
|
65
|
-
sunlint --all --changed-files --diff-base=origin/${{ github.base_ref }} \
|
|
66
|
-
--format=github --fail-on-new-violations
|
|
67
|
-
|
|
68
|
-
- name: Run SunLint full scan (Main)
|
|
69
|
-
if: github.event_name == 'push'
|
|
70
|
-
run: |
|
|
71
|
-
sunlint --all --input=. --format=json \
|
|
72
|
-
--save-baseline=sunlint-baseline.json --output=sunlint-report.json
|
|
73
|
-
|
|
74
|
-
- name: Upload SunLint Baseline
|
|
75
|
-
if: github.event_name == 'push'
|
|
76
|
-
uses: actions/upload-artifact@v4
|
|
77
|
-
with:
|
|
78
|
-
name: sunlint-baseline
|
|
79
|
-
path: sunlint-baseline.json
|
|
80
|
-
|
|
81
|
-
- name: Upload SunLint Report
|
|
82
|
-
if: always()
|
|
83
|
-
uses: actions/upload-artifact@v4
|
|
84
|
-
with:
|
|
85
|
-
name: sunlint-report
|
|
86
|
-
path: sunlint-report.json
|
|
87
|
-
|
|
88
|
-
# Combined summary job
|
|
89
|
-
quality-gate:
|
|
90
|
-
name: Quality Gate
|
|
91
|
-
runs-on: ubuntu-latest
|
|
92
|
-
needs: [eslint, sunlint]
|
|
93
|
-
if: always()
|
|
94
|
-
steps:
|
|
95
|
-
- name: Check ESLint Status
|
|
96
|
-
if: needs.eslint.result != 'success'
|
|
97
|
-
run: |
|
|
98
|
-
echo "❌ ESLint check failed"
|
|
99
|
-
exit 1
|
|
100
|
-
|
|
101
|
-
- name: Check SunLint Status
|
|
102
|
-
if: needs.sunlint.result != 'success'
|
|
103
|
-
run: |
|
|
104
|
-
echo "❌ SunLint check failed"
|
|
105
|
-
exit 1
|
|
106
|
-
|
|
107
|
-
- name: Quality Gate Passed
|
|
108
|
-
run: |
|
|
109
|
-
echo "✅ All quality checks passed!"
|
|
110
|
-
echo "📊 ESLint: ${{ needs.eslint.result }}"
|
|
111
|
-
echo "🔒 SunLint: ${{ needs.sunlint.result }}"
|
package/examples/README.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# 🎯 SunLint Examples
|
|
2
|
-
|
|
3
|
-
This folder contains example projects demonstrating different SunLint features and use cases.
|
|
4
|
-
|
|
5
|
-
## 📁 Example Projects
|
|
6
|
-
|
|
7
|
-
### **file-targeting-demo/**
|
|
8
|
-
Demonstrates advanced file targeting capabilities:
|
|
9
|
-
- TypeScript and JavaScript files
|
|
10
|
-
- Test file handling
|
|
11
|
-
- Include/exclude patterns
|
|
12
|
-
- Language-specific filtering
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
# Run examples
|
|
16
|
-
cd file-targeting-demo
|
|
17
|
-
sunlint --all --include="**/*.ts" --exclude-tests --input=. --dry-run
|
|
18
|
-
sunlint --all --languages=typescript,javascript --input=. --dry-run
|
|
19
|
-
sunlint --all --only-source --input=. --dry-run
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### **eslint-integration-demo/**
|
|
23
|
-
Shows ESLint integration features:
|
|
24
|
-
- Merging SunLint + ESLint rules
|
|
25
|
-
- Configuration resolution
|
|
26
|
-
- Conflict handling
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
cd eslint-integration-demo
|
|
30
|
-
sunlint --all --eslint-integration --input=src
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### **multi-language-project/**
|
|
34
|
-
Multi-language project example:
|
|
35
|
-
- TypeScript, Dart, Kotlin support
|
|
36
|
-
- Language-specific configurations
|
|
37
|
-
- Cross-language rule application
|
|
38
|
-
|
|
39
|
-
### **basic-typescript-demo/**
|
|
40
|
-
Simple TypeScript project for testing:
|
|
41
|
-
- Basic TypeScript setup
|
|
42
|
-
- Common violations examples
|
|
43
|
-
- Rule testing scenarios
|
|
44
|
-
|
|
45
|
-
### **rule-test-fixtures/**
|
|
46
|
-
Test fixtures for rule validation:
|
|
47
|
-
- Code samples for each rule
|
|
48
|
-
- Positive and negative test cases
|
|
49
|
-
- Rule behavior verification
|
|
50
|
-
|
|
51
|
-
## 🚀 Quick Start
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# Clone and test any example
|
|
55
|
-
cd examples/file-targeting-demo
|
|
56
|
-
sunlint --all --input=. --dry-run
|
|
57
|
-
|
|
58
|
-
# Test ESLint integration
|
|
59
|
-
cd examples/eslint-integration-demo
|
|
60
|
-
sunlint --all --eslint-integration --input=src
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 📋 Configuration Examples
|
|
64
|
-
|
|
65
|
-
Each example includes:
|
|
66
|
-
- `.sunlint.json` - Project configuration
|
|
67
|
-
- `package.json` - Dependencies and scripts
|
|
68
|
-
- Sample source files with intentional violations
|
|
69
|
-
- Documentation for specific features
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": [
|
|
3
|
-
"next/core-web-vitals"
|
|
4
|
-
],
|
|
5
|
-
"parser": "@typescript-eslint/parser",
|
|
6
|
-
"plugins": ["@typescript-eslint"],
|
|
7
|
-
"rules": {
|
|
8
|
-
"no-unused-vars": "off",
|
|
9
|
-
"@typescript-eslint/no-unused-vars": "warn",
|
|
10
|
-
"no-console": "warn",
|
|
11
|
-
"prefer-const": "error",
|
|
12
|
-
"no-var": "error",
|
|
13
|
-
"eqeqeq": "error",
|
|
14
|
-
"no-implicit-returns": "off",
|
|
15
|
-
"consistent-return": "warn",
|
|
16
|
-
"@typescript-eslint/no-explicit-any": "warn"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[{"/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/app/layout.tsx":"1","/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/app/page.tsx":"2","/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/good-practices.ts":"3","/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/violations.ts":"4"},{"size":323,"mtime":1752239573426,"results":"5","hashOfConfig":"6"},{"size":1462,"mtime":1752239564626,"results":"7","hashOfConfig":"6"},{"size":1371,"mtime":1752239611225,"results":"8","hashOfConfig":"6"},{"size":1594,"mtime":1752239592588,"results":"9","hashOfConfig":"6"},{"filePath":"10","messages":"11","suppressedMessages":"12","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"3g6ohx",{"filePath":"13","messages":"14","suppressedMessages":"15","errorCount":3,"fatalErrorCount":0,"warningCount":9,"fixableErrorCount":2,"fixableWarningCount":0,"source":null},{"filePath":"16","messages":"17","suppressedMessages":"18","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"19","messages":"20","suppressedMessages":"21","errorCount":2,"fatalErrorCount":0,"warningCount":9,"fixableErrorCount":1,"fixableWarningCount":0,"source":null},"/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/app/layout.tsx",[],[],"/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/app/page.tsx",["22","23","24","25","26","27","28","29","30","31","32","33"],[],"/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/good-practices.ts",["34"],[],"/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/test/sunlint-test-project/src/violations.ts",["35","36","37","38","39","40","41","42","43","44","45"],[],{"ruleId":"46","severity":1,"message":"47","line":3,"column":3,"nodeType":"48","messageId":"49","endLine":3,"endColumn":14,"suggestions":"50"},{"ruleId":"51","severity":1,"message":"52","line":6,"column":12,"nodeType":null,"messageId":"53","endLine":6,"endColumn":16},{"ruleId":"51","severity":1,"message":"54","line":11,"column":12,"nodeType":null,"messageId":"53","endLine":11,"endColumn":23},{"ruleId":"55","severity":1,"message":"56","line":11,"column":30,"nodeType":"57","messageId":"58","endLine":11,"endColumn":33,"suggestions":"59"},{"ruleId":"46","severity":1,"message":"47","line":16,"column":5,"nodeType":"48","messageId":"49","endLine":16,"endColumn":18,"suggestions":"60"},{"ruleId":"61","severity":2,"message":"62","line":22,"column":3,"nodeType":"63","messageId":"64","endLine":22,"endColumn":54,"fix":"65"},{"ruleId":"51","severity":1,"message":"66","line":22,"column":7,"nodeType":null,"messageId":"53","endLine":22,"endColumn":21},{"ruleId":"61","severity":2,"message":"62","line":25,"column":3,"nodeType":"63","messageId":"64","endLine":25,"endColumn":29,"fix":"67"},{"ruleId":"68","severity":2,"message":"69","line":28,"column":16,"nodeType":"70","messageId":"49","endLine":28,"endColumn":18},{"ruleId":"46","severity":1,"message":"47","line":29,"column":5,"nodeType":"48","messageId":"49","endLine":29,"endColumn":16,"suggestions":"71"},{"ruleId":"72","severity":1,"message":"73","line":33,"column":12,"nodeType":"74","messageId":"75","endLine":33,"endColumn":27},{"ruleId":"51","severity":1,"message":"76","line":33,"column":12,"nodeType":null,"messageId":"53","endLine":33,"endColumn":27},{"ruleId":"46","severity":1,"message":"47","line":20,"column":3,"nodeType":"48","messageId":"49","endLine":20,"endColumn":16,"suggestions":"77"},{"ruleId":"55","severity":1,"message":"56","line":19,"column":30,"nodeType":"57","messageId":"58","endLine":19,"endColumn":33,"suggestions":"78"},{"ruleId":"46","severity":1,"message":"47","line":20,"column":3,"nodeType":"48","messageId":"49","endLine":20,"endColumn":14,"suggestions":"79"},{"ruleId":"46","severity":1,"message":"47","line":26,"column":3,"nodeType":"48","messageId":"49","endLine":26,"endColumn":16,"suggestions":"80"},{"ruleId":"61","severity":2,"message":"62","line":32,"column":1,"nodeType":"63","messageId":"64","endLine":32,"endColumn":53,"fix":"81"},{"ruleId":"51","severity":1,"message":"82","line":32,"column":5,"nodeType":null,"messageId":"53","endLine":32,"endColumn":19},{"ruleId":"68","severity":2,"message":"69","line":36,"column":14,"nodeType":"70","messageId":"49","endLine":36,"endColumn":16},{"ruleId":"72","severity":1,"message":"83","line":43,"column":10,"nodeType":"74","messageId":"75","endLine":43,"endColumn":22},{"ruleId":"55","severity":1,"message":"56","line":43,"column":29,"nodeType":"57","messageId":"58","endLine":43,"endColumn":32,"suggestions":"84"},{"ruleId":"55","severity":1,"message":"56","line":51,"column":30,"nodeType":"57","messageId":"58","endLine":51,"endColumn":33,"suggestions":"85"},{"ruleId":"51","severity":1,"message":"86","line":58,"column":7,"nodeType":null,"messageId":"53","endLine":58,"endColumn":14},{"ruleId":"51","severity":1,"message":"87","line":59,"column":7,"nodeType":null,"messageId":"53","endLine":59,"endColumn":15},"no-console","Unexpected console statement.","MemberExpression","unexpected",["88"],"@typescript-eslint/no-unused-vars","'data' is defined but never used.","unusedVar","'processUser' is defined but never used.","@typescript-eslint/no-explicit-any","Unexpected any. Specify a different type.","TSAnyKeyword","unexpectedAny",["89","90"],["91"],"no-var","Unexpected var, use let or const instead.","VariableDeclaration","unexpectedVar",{"range":"92","text":"93"},"'unusedVariable' is assigned a value but never used.",{"range":"94","text":"93"},"eqeqeq","Expected '===' and instead saw '=='.","BinaryExpression",["95"],"consistent-return","Expected to return a value at the end of function 'checkPermission'.","FunctionDeclaration","missingReturn","'checkPermission' is defined but never used.",["96"],["97","98"],["99"],["100"],{"range":"101","text":"93"},"'globalVariable' is assigned a value but never used.","Expected to return a value at the end of function 'validateUser'.",["102","103"],["104","105"],"'API_KEY' is assigned a value but never used.","'PASSWORD' is assigned a value but never used.",{"messageId":"106","data":"107","fix":"108","desc":"109"},{"messageId":"110","fix":"111","desc":"112"},{"messageId":"113","fix":"114","desc":"115"},{"messageId":"106","data":"116","fix":"117","desc":"118"},[615,618],"let",[719,722],{"messageId":"106","data":"119","fix":"120","desc":"109"},{"messageId":"106","data":"121","fix":"122","desc":"118"},{"messageId":"110","fix":"123","desc":"112"},{"messageId":"113","fix":"124","desc":"115"},{"messageId":"106","data":"125","fix":"126","desc":"109"},{"messageId":"106","data":"127","fix":"128","desc":"118"},[815,818],{"messageId":"110","fix":"129","desc":"112"},{"messageId":"113","fix":"130","desc":"115"},{"messageId":"110","fix":"131","desc":"112"},{"messageId":"113","fix":"132","desc":"115"},"removeConsole",{"propertyName":"133"},{"range":"134","text":"135"},"Remove the console.log().","suggestUnknown",{"range":"136","text":"137"},"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.","suggestNever",{"range":"138","text":"139"},"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.",{"propertyName":"140"},{"range":"141","text":"135"},"Remove the console.error().",{"propertyName":"133"},{"range":"142","text":"135"},{"propertyName":"140"},{"range":"143","text":"135"},{"range":"144","text":"137"},{"range":"145","text":"139"},{"propertyName":"133"},{"range":"146","text":"135"},{"propertyName":"140"},{"range":"147","text":"135"},{"range":"148","text":"137"},{"range":"149","text":"139"},{"range":"150","text":"137"},{"range":"151","text":"139"},"log",[93,153],"",[354,357],"unknown",[354,357],"never","error",[516,553],[822,850],[584,639],[496,499],[496,499],[505,545],[702,745],[1078,1081],[1078,1081],[1245,1248],[1245,1248]]
|