@sun-asterisk/sunlint 1.0.7 → 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 +30 -3
- package/CONTRIBUTING.md +235 -0
- package/PROJECT_STRUCTURE.md +60 -0
- package/README.md +73 -52
- 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/integrations/eslint/base.config.js +125 -0
- package/config/integrations/eslint/simple.config.js +24 -0
- package/config/presets/strict.json +0 -1
- package/config/rule-analysis-strategies.js +74 -0
- package/config/{rules-registry.json → rules/rules-registry.json} +22 -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 +9 -3
- package/core/config-merger.js +40 -1
- package/core/config-validator.js +2 -2
- package/core/enhanced-rules-registry.js +331 -0
- package/core/file-targeting-service.js +92 -23
- 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 +1 -1
- package/core/rule-selection-service.js +10 -2
- package/docs/AI.md +163 -0
- package/docs/ARCHITECTURE.md +78 -0
- package/docs/CI-CD-GUIDE.md +315 -0
- package/docs/COMMAND-EXAMPLES.md +256 -0
- package/docs/CONFIGURATION.md +414 -0
- package/docs/DEBUG.md +86 -0
- package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
- package/docs/DISTRIBUTION.md +153 -0
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
- package/docs/ESLINT_INTEGRATION.md +238 -0
- package/docs/FOLDER_STRUCTURE.md +59 -0
- package/docs/HEURISTIC_VS_AI.md +113 -0
- package/docs/README.md +32 -0
- package/docs/RELEASE_GUIDE.md +230 -0
- package/engines/eslint-engine.js +601 -0
- package/engines/heuristic-engine.js +860 -0
- package/engines/openai-engine.js +374 -0
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -0
- package/integrations/eslint/README.md +99 -0
- package/integrations/eslint/configs/.eslintrc.js +98 -0
- package/integrations/eslint/configs/eslint.config.js +133 -0
- package/integrations/eslint/configs/eslint.config.simple.js +24 -0
- package/integrations/eslint/package.json +23 -0
- package/integrations/eslint/plugin/index.js +164 -0
- package/integrations/eslint/plugin/package.json +13 -0
- package/integrations/eslint/plugin/rules/common/c002-no-duplicate-code.js +204 -0
- package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +246 -0
- package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +216 -0
- package/integrations/eslint/plugin/rules/common/c010-limit-block-nesting.js +90 -0
- package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
- package/integrations/eslint/plugin/rules/common/c014-abstract-dependency-preferred.js +38 -0
- package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
- package/integrations/eslint/plugin/rules/common/c018-no-generic-throw.js +335 -0
- package/integrations/eslint/plugin/rules/common/c023-no-duplicate-variable-name-in-scope.js +142 -0
- package/integrations/eslint/plugin/rules/common/c029-catch-block-logging.js +115 -0
- package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +294 -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/c042-boolean-name-prefix.js +406 -0
- package/integrations/eslint/plugin/rules/common/c043-no-console-or-print.js +300 -0
- package/integrations/eslint/plugin/rules/common/c047-no-duplicate-retry-logic.js +239 -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/s003-no-unvalidated-redirect.js +86 -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/integrations/eslint/plugin/rules/security/s047-secure-random-passwords.js +108 -0
- package/integrations/eslint/plugin/rules/security/s055-verification-rest-check-the-incoming-content-type.js +143 -0
- package/integrations/eslint/plugin/rules/typescript/t002-interface-prefix-i.js +42 -0
- package/integrations/eslint/plugin/rules/typescript/t003-ts-ignore-reason.js +48 -0
- package/integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js +95 -0
- package/integrations/eslint/plugin/rules/typescript/t007-no-fn-in-constructor.js +52 -0
- package/integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js +48 -0
- 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/integrations/eslint/tsconfig.json +27 -0
- package/package.json +29 -16
- 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/universal/C010/generic.js +0 -0
- package/rules/universal/C010/tree-sitter-analyzer.js +0 -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/config/sunlint-schema.json +0 -159
- 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/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/config/{default.json → defaults/default.json} +0 -0
- /package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +0 -0
- /package/config/{typescript/custom-rules-new.js → schemas/sunlint-schema.json} +0 -0
- /package/config/{typescript → testing}/test-s005-working.ts +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +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
|
@@ -47,43 +47,59 @@ class FileTargetingService {
|
|
|
47
47
|
*/
|
|
48
48
|
applyFiltering(files, config, cliOptions) {
|
|
49
49
|
let filteredFiles = [...files];
|
|
50
|
+
const debug = cliOptions?.debug || false;
|
|
51
|
+
|
|
52
|
+
if (debug) console.log(`🔍 [DEBUG] applyFiltering: start with ${filteredFiles.length} files`);
|
|
53
|
+
if (debug) console.log(`🔍 [DEBUG] config.include:`, config.include);
|
|
54
|
+
if (debug) console.log(`🔍 [DEBUG] cliOptions.include:`, cliOptions.include);
|
|
50
55
|
|
|
51
56
|
// 1. Apply config include patterns first (medium priority)
|
|
52
57
|
if (config.include && config.include.length > 0) {
|
|
53
|
-
filteredFiles = this.applyIncludePatterns(filteredFiles, config.include);
|
|
58
|
+
filteredFiles = this.applyIncludePatterns(filteredFiles, config.include, debug);
|
|
59
|
+
if (debug) console.log(`🔍 [DEBUG] After config include: ${filteredFiles.length} files`);
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
// 2. Apply CLI include overrides (highest priority - completely overrides config)
|
|
57
63
|
if (cliOptions.include) {
|
|
58
64
|
// CLI include completely replaces config include - start fresh from all files
|
|
59
|
-
filteredFiles = this.applyIncludePatterns([...files], cliOptions.include);
|
|
65
|
+
filteredFiles = this.applyIncludePatterns([...files], cliOptions.include, debug);
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
// 3. Apply config exclude patterns
|
|
63
69
|
if (config.exclude && config.exclude.length > 0) {
|
|
64
|
-
|
|
70
|
+
if (debug) console.log(`🔍 [DEBUG] About to apply config exclude patterns: ${config.exclude}`);
|
|
71
|
+
if (debug) console.log(`🔍 [DEBUG] Files before config exclude: ${filteredFiles.length}`);
|
|
72
|
+
filteredFiles = this.applyExcludePatterns(filteredFiles, config.exclude, debug);
|
|
73
|
+
if (debug) console.log(`🔍 [DEBUG] Files after config exclude: ${filteredFiles.length}`);
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
// 4. Apply CLI exclude overrides (highest priority)
|
|
68
77
|
if (cliOptions.exclude) {
|
|
69
|
-
|
|
78
|
+
if (debug) console.log(`🔍 [DEBUG] About to apply CLI exclude patterns: ${cliOptions.exclude}`);
|
|
79
|
+
if (debug) console.log(`🔍 [DEBUG] Files before CLI exclude: ${filteredFiles.length}`);
|
|
80
|
+
filteredFiles = this.applyExcludePatterns(filteredFiles, cliOptions.exclude, debug);
|
|
81
|
+
if (debug) console.log(`🔍 [DEBUG] Files after CLI exclude: ${filteredFiles.length}`);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
// 5. Apply language-specific filtering
|
|
73
85
|
if (cliOptions.languages || config.languages) {
|
|
74
|
-
filteredFiles = this.applyLanguageFiltering(filteredFiles, config, cliOptions);
|
|
86
|
+
filteredFiles = this.applyLanguageFiltering(filteredFiles, config, cliOptions, debug);
|
|
87
|
+
if (debug) console.log(`🔍 [DEBUG] After language filtering: ${filteredFiles.length} files`);
|
|
75
88
|
}
|
|
76
89
|
|
|
77
90
|
// 6. Apply only-source filtering (exclude tests, configs, etc.)
|
|
78
91
|
if (cliOptions.onlySource) {
|
|
79
92
|
filteredFiles = this.applyOnlySourceFiltering(filteredFiles);
|
|
93
|
+
if (debug) console.log(`🔍 [DEBUG] After onlySource filtering: ${filteredFiles.length} files`);
|
|
80
94
|
} else {
|
|
81
95
|
// 8. Handle test files normally
|
|
82
96
|
if (config.testPatterns) {
|
|
83
97
|
filteredFiles = this.handleTestFiles(filteredFiles, config.testPatterns, cliOptions, config);
|
|
98
|
+
if (debug) console.log(`🔍 [DEBUG] After test files handling: ${filteredFiles.length} files`);
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
|
|
102
|
+
if (debug) console.log(`🔍 [DEBUG] Final filtered files: ${filteredFiles.length}`);
|
|
87
103
|
return filteredFiles;
|
|
88
104
|
}
|
|
89
105
|
|
|
@@ -91,7 +107,11 @@ class FileTargetingService {
|
|
|
91
107
|
* Apply language-specific filtering
|
|
92
108
|
* Rule C005: Single responsibility - language filtering only
|
|
93
109
|
*/
|
|
94
|
-
applyLanguageFiltering(files, config, cliOptions) {
|
|
110
|
+
applyLanguageFiltering(files, config, cliOptions, debug = false) {
|
|
111
|
+
if (debug) console.log(`🔍 [DEBUG] === applyLanguageFiltering ENTRY ===`);
|
|
112
|
+
if (debug) console.log(`🔍 [DEBUG] Input files.length: ${files.length}`);
|
|
113
|
+
if (debug) console.log(`🔍 [DEBUG] Sample input files:`, files.slice(0, 3));
|
|
114
|
+
|
|
95
115
|
// Determine target languages from CLI or config
|
|
96
116
|
let targetLanguages;
|
|
97
117
|
if (cliOptions.languages) {
|
|
@@ -102,78 +122,118 @@ class FileTargetingService {
|
|
|
102
122
|
targetLanguages = Object.keys(config.languages || {});
|
|
103
123
|
}
|
|
104
124
|
|
|
125
|
+
if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: cliOptions.languages = ${cliOptions.languages}`);
|
|
126
|
+
if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: config.languages =`, config.languages);
|
|
127
|
+
if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: targetLanguages =`, targetLanguages);
|
|
128
|
+
|
|
105
129
|
if (targetLanguages.length === 0) {
|
|
130
|
+
if (debug) console.log(`🔍 [DEBUG] applyLanguageFiltering: No language filtering, returning all files`);
|
|
106
131
|
return files; // No language filtering
|
|
107
132
|
}
|
|
108
133
|
|
|
109
134
|
let languageFiles = [];
|
|
110
135
|
|
|
111
136
|
for (const language of targetLanguages) {
|
|
137
|
+
if (debug) console.log(`🔍 [DEBUG] Processing language: ${language}`);
|
|
112
138
|
if (Array.isArray(config.languages)) {
|
|
113
139
|
// New array format - use isLanguageFile method
|
|
114
140
|
const langFiles = files.filter(file => this.isLanguageFile(file, language));
|
|
115
141
|
languageFiles.push(...langFiles);
|
|
142
|
+
if (debug) console.log(`🔍 [DEBUG] Array format - found ${langFiles.length} files for ${language}`);
|
|
116
143
|
} else {
|
|
117
144
|
// Legacy object format - use include/exclude patterns
|
|
118
145
|
const langConfig = config.languages[language];
|
|
119
|
-
if (!langConfig)
|
|
146
|
+
if (!langConfig) {
|
|
147
|
+
if (debug) console.log(`🔍 [DEBUG] No config for language: ${language}`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
120
150
|
|
|
121
151
|
let langFiles = [...files];
|
|
152
|
+
if (debug) console.log(`🔍 [DEBUG] Starting with ${langFiles.length} files for ${language}`);
|
|
122
153
|
|
|
123
154
|
// Apply language-specific include patterns
|
|
124
155
|
if (langConfig.include && langConfig.include.length > 0) {
|
|
125
|
-
langFiles = this.applyIncludePatterns(langFiles, langConfig.include);
|
|
156
|
+
langFiles = this.applyIncludePatterns(langFiles, langConfig.include, debug);
|
|
157
|
+
if (debug) console.log(`🔍 [DEBUG] After include patterns ${langConfig.include}: ${langFiles.length} files`);
|
|
126
158
|
}
|
|
127
159
|
|
|
128
160
|
// Apply language-specific exclude patterns
|
|
129
161
|
if (langConfig.exclude && langConfig.exclude.length > 0) {
|
|
130
|
-
langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude);
|
|
162
|
+
langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude, debug);
|
|
163
|
+
if (debug) console.log(`🔍 [DEBUG] After exclude patterns ${langConfig.exclude}: ${langFiles.length} files`);
|
|
131
164
|
}
|
|
132
165
|
|
|
133
166
|
languageFiles.push(...langFiles);
|
|
167
|
+
if (debug) console.log(`🔍 [DEBUG] Added ${langFiles.length} files for ${language}, total: ${languageFiles.length}`);
|
|
134
168
|
}
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
// Remove duplicates
|
|
138
|
-
|
|
172
|
+
const finalFiles = [...new Set(languageFiles)];
|
|
173
|
+
if (debug) console.log(`🔍 [DEBUG] Final language files after dedup: ${finalFiles.length}`);
|
|
174
|
+
return finalFiles;
|
|
139
175
|
}
|
|
140
176
|
|
|
141
177
|
/**
|
|
142
178
|
* Apply include patterns using minimatch
|
|
143
179
|
* Rule C006: applyIncludePatterns - verb-noun naming
|
|
144
180
|
*/
|
|
145
|
-
applyIncludePatterns(files, patterns) {
|
|
181
|
+
applyIncludePatterns(files, patterns, debug = false) {
|
|
146
182
|
if (!patterns) return files;
|
|
147
183
|
|
|
148
184
|
// Normalize patterns to array
|
|
149
185
|
const patternArray = Array.isArray(patterns) ? patterns : [patterns];
|
|
150
186
|
if (patternArray.length === 0) return files;
|
|
151
187
|
|
|
152
|
-
|
|
188
|
+
if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - input files:`, files.length);
|
|
189
|
+
if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - patterns:`, patternArray);
|
|
190
|
+
if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - sample input files:`, files.slice(0, 3));
|
|
191
|
+
|
|
192
|
+
const result = files.filter(file => {
|
|
153
193
|
return patternArray.some(pattern => {
|
|
154
194
|
const normalizedFile = this.normalizePath(file);
|
|
155
|
-
|
|
195
|
+
const match = minimatch(normalizedFile, pattern, { dot: true });
|
|
196
|
+
if (debug && file.includes('.ts') && !file.includes('.test.')) {
|
|
197
|
+
console.log(`🔍 [DEBUG] Testing: '${file}' -> '${normalizedFile}' vs '${pattern}' = ${match}`);
|
|
198
|
+
}
|
|
199
|
+
return match;
|
|
156
200
|
});
|
|
157
201
|
});
|
|
202
|
+
|
|
203
|
+
if (debug) console.log(`🔍 [DEBUG] applyIncludePatterns - result:`, result.length);
|
|
204
|
+
return result;
|
|
158
205
|
}
|
|
159
206
|
|
|
160
207
|
/**
|
|
161
208
|
* Apply exclude patterns using minimatch
|
|
162
209
|
* Rule C006: applyExcludePatterns - verb-noun naming
|
|
163
210
|
*/
|
|
164
|
-
applyExcludePatterns(files, patterns) {
|
|
211
|
+
applyExcludePatterns(files, patterns, debug = false) {
|
|
165
212
|
if (!patterns) return files;
|
|
166
213
|
|
|
167
214
|
// Normalize patterns to array
|
|
168
215
|
const patternArray = Array.isArray(patterns) ? patterns : [patterns];
|
|
169
216
|
if (patternArray.length === 0) return files;
|
|
170
217
|
|
|
171
|
-
|
|
172
|
-
|
|
218
|
+
// Filter out negation patterns (starting with !) - these should not be in exclude patterns
|
|
219
|
+
const excludePatterns = patternArray.filter(pattern => !pattern.startsWith('!'));
|
|
220
|
+
|
|
221
|
+
if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - input files: ${files.length}`);
|
|
222
|
+
if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - original patterns:`, patternArray);
|
|
223
|
+
if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - filtered patterns:`, excludePatterns);
|
|
224
|
+
|
|
225
|
+
if (excludePatterns.length === 0) return files;
|
|
226
|
+
|
|
227
|
+
const result = files.filter(file => {
|
|
228
|
+
return !excludePatterns.some(pattern => {
|
|
173
229
|
const normalizedFile = this.normalizePath(file);
|
|
174
|
-
|
|
230
|
+
const match = minimatch(normalizedFile, pattern, { dot: true });
|
|
231
|
+
return match;
|
|
175
232
|
});
|
|
176
233
|
});
|
|
234
|
+
|
|
235
|
+
if (debug) console.log(`🔍 [DEBUG] applyExcludePatterns - result: ${result.length}`);
|
|
236
|
+
return result;
|
|
177
237
|
}
|
|
178
238
|
|
|
179
239
|
/**
|
|
@@ -208,13 +268,22 @@ class FileTargetingService {
|
|
|
208
268
|
*/
|
|
209
269
|
async collectFiles(inputPath) {
|
|
210
270
|
const files = [];
|
|
211
|
-
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const stats = fs.statSync(inputPath);
|
|
212
274
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
275
|
+
if (stats.isFile()) {
|
|
276
|
+
files.push(path.resolve(inputPath));
|
|
277
|
+
} else if (stats.isDirectory()) {
|
|
278
|
+
const dirFiles = await this.collectFilesFromDirectory(inputPath);
|
|
279
|
+
files.push(...dirFiles);
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error.code === 'ENOENT') {
|
|
283
|
+
console.warn(`⚠️ Path not found: ${inputPath}`);
|
|
284
|
+
return files; // Return empty array instead of throwing
|
|
285
|
+
}
|
|
286
|
+
throw error; // Re-throw other errors
|
|
218
287
|
}
|
|
219
288
|
|
|
220
289
|
return files;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis Engine Interface
|
|
3
|
+
* Following Rule C014: Dependency Injection interface
|
|
4
|
+
* Following Rule C015: Use domain language - clear interface naming
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class AnalysisEngineInterface {
|
|
8
|
+
/**
|
|
9
|
+
* Constructor for Analysis Engine
|
|
10
|
+
* @param {string} id - Engine ID (e.g., 'eslint', 'heuristic', 'openai')
|
|
11
|
+
* @param {string} version - Engine version
|
|
12
|
+
* @param {string[]} supportedLanguages - Array of supported languages
|
|
13
|
+
*/
|
|
14
|
+
constructor(id, version, supportedLanguages = []) {
|
|
15
|
+
this.id = id;
|
|
16
|
+
this.version = version;
|
|
17
|
+
this.supportedLanguages = supportedLanguages;
|
|
18
|
+
this.initialized = false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Initialize the analysis engine
|
|
23
|
+
* Following Rule C006: Verb-noun naming
|
|
24
|
+
* @param {Object} config - Engine-specific configuration
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async initialize(config) {
|
|
28
|
+
throw new Error(`Method initialize() must be implemented by ${this.constructor.name}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Analyze files with given rules
|
|
33
|
+
* Following Rule C006: Verb-noun naming
|
|
34
|
+
* @param {string[]} files - Array of file paths to analyze
|
|
35
|
+
* @param {Object[]} rules - Array of rule objects to apply
|
|
36
|
+
* @param {Object} options - Analysis options
|
|
37
|
+
* @returns {Promise<Object>} Analysis results
|
|
38
|
+
*/
|
|
39
|
+
async analyze(files, rules, options) {
|
|
40
|
+
throw new Error(`Method analyze() must be implemented by ${this.constructor.name}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get supported rules for this engine
|
|
45
|
+
* Following Rule C006: Verb-noun naming
|
|
46
|
+
* @returns {string[]} Array of supported rule IDs
|
|
47
|
+
*/
|
|
48
|
+
getSupportedRules() {
|
|
49
|
+
throw new Error(`Method getSupportedRules() must be implemented by ${this.constructor.name}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if a specific rule is supported
|
|
54
|
+
* Following Rule C006: Verb-noun naming
|
|
55
|
+
* @param {string} ruleId - Rule ID to check
|
|
56
|
+
* @returns {boolean} True if rule is supported
|
|
57
|
+
*/
|
|
58
|
+
isRuleSupported(ruleId) {
|
|
59
|
+
return this.getSupportedRules().includes(ruleId);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if a language is supported
|
|
64
|
+
* Following Rule C006: Verb-noun naming
|
|
65
|
+
* @param {string} language - Language to check
|
|
66
|
+
* @returns {boolean} True if language is supported
|
|
67
|
+
*/
|
|
68
|
+
isLanguageSupported(language) {
|
|
69
|
+
return this.supportedLanguages.includes(language) ||
|
|
70
|
+
this.supportedLanguages.includes('all') ||
|
|
71
|
+
this.supportedLanguages.length === 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get engine metadata
|
|
76
|
+
* Following Rule C006: Verb-noun naming
|
|
77
|
+
* @returns {Object} Engine metadata
|
|
78
|
+
*/
|
|
79
|
+
getEngineInfo() {
|
|
80
|
+
return {
|
|
81
|
+
name: this.name,
|
|
82
|
+
version: this.version,
|
|
83
|
+
supportedLanguages: this.supportedLanguages,
|
|
84
|
+
supportedRules: this.getSupportedRules(),
|
|
85
|
+
initialized: this.initialized
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Cleanup engine resources
|
|
91
|
+
* Following Rule C006: Verb-noun naming
|
|
92
|
+
* @returns {Promise<void>}
|
|
93
|
+
*/
|
|
94
|
+
async cleanup() {
|
|
95
|
+
// Default implementation - engines can override if needed
|
|
96
|
+
this.initialized = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = AnalysisEngineInterface;
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const glob = require('glob');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const FileTargetingService = require('./file-targeting-service');
|
|
6
|
-
|
|
7
|
-
class MultiRuleRunner {
|
|
8
|
-
constructor(config, options) {
|
|
9
|
-
this.config = config;
|
|
10
|
-
this.options = options;
|
|
11
|
-
this.ruleCache = new Map();
|
|
12
|
-
this.fileTargetingService = new FileTargetingService();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async runRules(rules, inputPath, options) {
|
|
16
|
-
console.log(chalk.blue(`🔄 Analyzing ${rules.length} rules...`));
|
|
17
|
-
|
|
18
|
-
// Get files to analyze
|
|
19
|
-
const files = await this.getFilesToAnalyze(inputPath, options);
|
|
20
|
-
|
|
21
|
-
console.log(chalk.gray(`📁 Found ${files ? files.length : 'undefined'} files to analyze`));
|
|
22
|
-
|
|
23
|
-
if (!files || files.length === 0) {
|
|
24
|
-
console.log(chalk.yellow('⚠️ No files found to analyze'));
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Group files by language
|
|
29
|
-
const filesByLanguage = this.groupFilesByLanguage(files);
|
|
30
|
-
|
|
31
|
-
// Run rules in parallel (with concurrency limit)
|
|
32
|
-
const maxConcurrent = parseInt(options.maxConcurrent) || 5;
|
|
33
|
-
const timeout = parseInt(options.timeout) || 30000;
|
|
34
|
-
|
|
35
|
-
const results = [];
|
|
36
|
-
|
|
37
|
-
// Process rules in batches
|
|
38
|
-
for (let i = 0; i < rules.length; i += maxConcurrent) {
|
|
39
|
-
const batch = rules.slice(i, i + maxConcurrent);
|
|
40
|
-
|
|
41
|
-
const batchPromises = batch.map(async (rule) => {
|
|
42
|
-
try {
|
|
43
|
-
return await this.runSingleRule(rule, filesByLanguage, options, timeout);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error(chalk.red(`❌ Rule ${rule.id} failed:`), error.message);
|
|
46
|
-
return {
|
|
47
|
-
ruleId: rule.id,
|
|
48
|
-
ruleName: rule.name,
|
|
49
|
-
violations: [],
|
|
50
|
-
error: error.message,
|
|
51
|
-
status: 'failed'
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const batchResults = await Promise.all(batchPromises);
|
|
57
|
-
results.push(...batchResults);
|
|
58
|
-
|
|
59
|
-
if (options.verbose) {
|
|
60
|
-
console.log(chalk.gray(`✅ Completed batch ${Math.floor(i/maxConcurrent) + 1}/${Math.ceil(rules.length/maxConcurrent)}`));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return this.consolidateResults(results, files.length);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async runSingleRule(rule, filesByLanguage, options, timeout) {
|
|
68
|
-
if (options.verbose) {
|
|
69
|
-
console.log(chalk.gray(`🔍 Running rule ${rule.id}: ${rule.name}`));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const startTime = Date.now();
|
|
73
|
-
|
|
74
|
-
// Load rule analyzer
|
|
75
|
-
const analyzer = await this.loadRuleAnalyzer(rule);
|
|
76
|
-
|
|
77
|
-
if (!analyzer) {
|
|
78
|
-
return {
|
|
79
|
-
ruleId: rule.id,
|
|
80
|
-
ruleName: rule.name,
|
|
81
|
-
violations: [],
|
|
82
|
-
error: 'Analyzer not found',
|
|
83
|
-
status: 'skipped'
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const violations = [];
|
|
88
|
-
|
|
89
|
-
// Run analyzer for each supported language
|
|
90
|
-
for (const language of rule.languages) {
|
|
91
|
-
const languageFiles = filesByLanguage[language] || [];
|
|
92
|
-
|
|
93
|
-
if (languageFiles.length === 0) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
// Run with timeout
|
|
99
|
-
const languageViolations = await Promise.race([
|
|
100
|
-
analyzer.analyze(languageFiles, language, this.config),
|
|
101
|
-
new Promise((_, reject) =>
|
|
102
|
-
setTimeout(() => reject(new Error('Timeout')), timeout)
|
|
103
|
-
)
|
|
104
|
-
]);
|
|
105
|
-
|
|
106
|
-
violations.push(...languageViolations);
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error(chalk.yellow(`⚠️ Rule ${rule.id} failed for ${language}:`), error.message);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const duration = Date.now() - startTime;
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
ruleId: rule.id,
|
|
116
|
-
ruleName: rule.name,
|
|
117
|
-
category: rule.category,
|
|
118
|
-
severity: rule.severity,
|
|
119
|
-
violations,
|
|
120
|
-
filesAnalyzed: Object.values(filesByLanguage).flat().length,
|
|
121
|
-
duration,
|
|
122
|
-
status: 'completed'
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async loadRuleAnalyzer(rule) {
|
|
127
|
-
// Check cache first
|
|
128
|
-
if (this.ruleCache.has(rule.id)) {
|
|
129
|
-
return this.ruleCache.get(rule.id);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const analyzerPath = path.resolve(__dirname, '..', rule.analyzer);
|
|
134
|
-
|
|
135
|
-
if (!fs.existsSync(analyzerPath)) {
|
|
136
|
-
console.error(chalk.yellow(`⚠️ Analyzer not found for rule ${rule.id}: ${analyzerPath}`));
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const analyzer = require(analyzerPath);
|
|
141
|
-
this.ruleCache.set(rule.id, analyzer);
|
|
142
|
-
return analyzer;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
console.error(chalk.red(`❌ Failed to load analyzer for rule ${rule.id}:`), error.message);
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async getFilesToAnalyze(inputPath, options) {
|
|
150
|
-
// Use centralized file targeting service - convert single path to array
|
|
151
|
-
const inputPaths = Array.isArray(inputPath) ? inputPath : [inputPath];
|
|
152
|
-
const result = await this.fileTargetingService.getTargetFiles(inputPaths, this.config, options);
|
|
153
|
-
return result.files; // Extract files array from result object
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
groupFilesByLanguage(files) {
|
|
157
|
-
const rulesRegistry = require('../config/rules-registry.json');
|
|
158
|
-
const languageConfig = rulesRegistry.languages;
|
|
159
|
-
|
|
160
|
-
const filesByLanguage = {};
|
|
161
|
-
|
|
162
|
-
files.forEach(file => {
|
|
163
|
-
const ext = path.extname(file);
|
|
164
|
-
|
|
165
|
-
for (const [language, config] of Object.entries(languageConfig)) {
|
|
166
|
-
if (config.extensions.includes(ext)) {
|
|
167
|
-
if (!filesByLanguage[language]) {
|
|
168
|
-
filesByLanguage[language] = [];
|
|
169
|
-
}
|
|
170
|
-
filesByLanguage[language].push(file);
|
|
171
|
-
break; // File belongs to first matching language
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
return filesByLanguage;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
consolidateResults(results, totalFiles) {
|
|
180
|
-
const consolidatedResults = {
|
|
181
|
-
filesAnalyzed: totalFiles,
|
|
182
|
-
rulesRun: results.length,
|
|
183
|
-
totalViolations: 0,
|
|
184
|
-
violationsBySeverity: { error: 0, warning: 0, info: 0 },
|
|
185
|
-
violationsByRule: {},
|
|
186
|
-
violationsByFile: {},
|
|
187
|
-
results: []
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
results.forEach(result => {
|
|
191
|
-
consolidatedResults.results.push(result);
|
|
192
|
-
|
|
193
|
-
if (result.violations) {
|
|
194
|
-
consolidatedResults.totalViolations += result.violations.length;
|
|
195
|
-
|
|
196
|
-
// Count by severity
|
|
197
|
-
result.violations.forEach(violation => {
|
|
198
|
-
const severity = violation.severity || result.severity || 'warning';
|
|
199
|
-
consolidatedResults.violationsBySeverity[severity] =
|
|
200
|
-
(consolidatedResults.violationsBySeverity[severity] || 0) + 1;
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Count by rule
|
|
204
|
-
consolidatedResults.violationsByRule[result.ruleId] = result.violations.length;
|
|
205
|
-
|
|
206
|
-
// Count by file
|
|
207
|
-
result.violations.forEach(violation => {
|
|
208
|
-
const file = violation.file || violation.filePath;
|
|
209
|
-
if (file) {
|
|
210
|
-
consolidatedResults.violationsByFile[file] =
|
|
211
|
-
(consolidatedResults.violationsByFile[file] || 0) + 1;
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
return consolidatedResults;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
module.exports = MultiRuleRunner;
|
package/core/output-service.js
CHANGED
|
@@ -35,7 +35,7 @@ class OutputService {
|
|
|
35
35
|
|
|
36
36
|
generateReport(results, metadata, options = {}) {
|
|
37
37
|
const allViolations = [];
|
|
38
|
-
let totalFiles = results.filesAnalyzed || results.totalFiles || results.fileCount || 0;
|
|
38
|
+
let totalFiles = results.filesAnalyzed || results.summary?.totalFiles || results.totalFiles || results.fileCount || 0;
|
|
39
39
|
|
|
40
40
|
// Collect all violations - handle both file-based and rule-based results
|
|
41
41
|
if (results.results) {
|
|
@@ -16,7 +16,7 @@ class RuleMappingService {
|
|
|
16
16
|
*/
|
|
17
17
|
createEslintToSunlintMapping() {
|
|
18
18
|
return {
|
|
19
|
-
// Custom rules mapping (using actual rule IDs from eslint
|
|
19
|
+
// Custom rules mapping (using actual rule IDs from integrations/eslint/plugin/rules)
|
|
20
20
|
'custom/c002': 'C002',
|
|
21
21
|
'custom/c003': 'C003',
|
|
22
22
|
'custom/c006': 'C006',
|
|
@@ -15,7 +15,7 @@ class RuleSelectionService {
|
|
|
15
15
|
async selectRules(config, options) {
|
|
16
16
|
// Load rules registry
|
|
17
17
|
try {
|
|
18
|
-
this.rulesRegistry = require('../config/rules-registry.json');
|
|
18
|
+
this.rulesRegistry = require('../config/rules/rules-registry.json');
|
|
19
19
|
} catch (error) {
|
|
20
20
|
console.log(chalk.yellow('⚠️ Rules registry not found, using minimal rule set'));
|
|
21
21
|
this.rulesRegistry = this.getMinimalRuleSet();
|
|
@@ -40,6 +40,14 @@ class RuleSelectionService {
|
|
|
40
40
|
if (options.verbose) {
|
|
41
41
|
console.log(chalk.blue(`📋 Found ${selectedRules.length} total rules (${registryRules.length} registry + ${eslintSupportedRules.length} ESLint)`));
|
|
42
42
|
}
|
|
43
|
+
} else if (options.quality) {
|
|
44
|
+
// Handle --quality shortcut
|
|
45
|
+
const categoryRules = this.getRulesByCategory('quality');
|
|
46
|
+
selectedRules = categoryRules;
|
|
47
|
+
} else if (options.security) {
|
|
48
|
+
// Handle --security shortcut
|
|
49
|
+
const categoryRules = this.getRulesByCategory('security');
|
|
50
|
+
selectedRules = categoryRules;
|
|
43
51
|
} else if (options.category) {
|
|
44
52
|
const categoryRules = this.getRulesByCategory(options.category);
|
|
45
53
|
selectedRules = categoryRules;
|
|
@@ -96,7 +104,7 @@ class RuleSelectionService {
|
|
|
96
104
|
'C043', 'C047', 'C048', 'C076', 'T002', 'T003', 'T004', 'T007', 'T011',
|
|
97
105
|
'T019', 'T025', 'T026'
|
|
98
106
|
],
|
|
99
|
-
'security': ['S003', 'S005', 'S006', 'S008', 'S009', 'S010', 'S011', 'S012', 'S014', 'S015', 'S016', 'S017', 'S018', 'S019', 'S020', 'S022', 'S023', 'S025', 'S026', 'S027', 'S029', 'S030', 'S033', 'S034', 'S035', 'S036', 'S037', 'S038', 'S039', 'S041', 'S042', 'S043', 'S044', 'S045', 'S046', 'S047', 'S048', 'S050', 'S052', 'S054', 'S055', 'S057', 'S058'],
|
|
107
|
+
'security': ['S001', 'S002', 'S003', 'S005', 'S006', 'S007', 'S008', 'S009', 'S010', 'S011', 'S012', 'S013', 'S014', 'S015', 'S016', 'S017', 'S018', 'S019', 'S020', 'S022', 'S023', 'S025', 'S026', 'S027', 'S029', 'S030', 'S033', 'S034', 'S035', 'S036', 'S037', 'S038', 'S039', 'S041', 'S042', 'S043', 'S044', 'S045', 'S046', 'S047', 'S048', 'S050', 'S052', 'S054', 'S055', 'S057', 'S058'],
|
|
100
108
|
'naming': ['C006'],
|
|
101
109
|
'logging': ['C019', 'S057'],
|
|
102
110
|
'validation': ['C031', 'S018', 'S025', 'S026']
|