@sun-asterisk/sunlint 1.0.5
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/CHANGELOG.md +202 -0
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/cli-legacy.js +355 -0
- package/cli.js +35 -0
- package/config/default.json +22 -0
- package/config/presets/beginner.json +36 -0
- package/config/presets/ci.json +46 -0
- package/config/presets/recommended.json +24 -0
- package/config/presets/strict.json +32 -0
- package/config/rules-registry.json +681 -0
- package/config/sunlint-schema.json +166 -0
- package/config/typescript/custom-rules-new.js +0 -0
- package/config/typescript/custom-rules.js +9 -0
- package/config/typescript/eslint.config.js +110 -0
- package/config/typescript/package-lock.json +1585 -0
- package/config/typescript/package.json +13 -0
- package/config/typescript/security-rules/index.js +90 -0
- package/config/typescript/security-rules/s005-no-origin-auth.js +95 -0
- package/config/typescript/security-rules/s006-activation-recovery-secret-not-plaintext.js +69 -0
- package/config/typescript/security-rules/s008-crypto-agility.js +62 -0
- package/config/typescript/security-rules/s009-no-insecure-crypto.js +103 -0
- package/config/typescript/security-rules/s010-no-insecure-random-in-sensitive-context.js +123 -0
- package/config/typescript/security-rules/s011-no-insecure-uuid.js +66 -0
- package/config/typescript/security-rules/s012-hardcode-secret.js +71 -0
- package/config/typescript/security-rules/s014-insecure-tls-version.js +50 -0
- package/config/typescript/security-rules/s015-insecure-tls-certificate.js +43 -0
- package/config/typescript/security-rules/s016-sensitive-query-parameter.js +59 -0
- package/config/typescript/security-rules/s017-no-sql-injection.js +193 -0
- package/config/typescript/security-rules/s018-positive-input-validation.js +56 -0
- package/config/typescript/security-rules/s019-no-raw-user-input-in-email.js +113 -0
- package/config/typescript/security-rules/s020-no-eval-dynamic-execution.js +89 -0
- package/config/typescript/security-rules/s022-output-encoding.js +78 -0
- package/config/typescript/security-rules/s023-no-json-injection.js +300 -0
- package/config/typescript/security-rules/s025-server-side-input-validation.js +217 -0
- package/config/typescript/security-rules/s026-json-schema-validation.js +68 -0
- package/config/typescript/security-rules/s027-no-hardcoded-secrets.js +80 -0
- package/config/typescript/security-rules/s029-require-csrf-protection.js +79 -0
- package/config/typescript/security-rules/s030-no-directory-browsing.js +78 -0
- package/config/typescript/security-rules/s033-require-samesite-cookie.js +80 -0
- package/config/typescript/security-rules/s034-require-host-cookie-prefix.js +77 -0
- package/config/typescript/security-rules/s035-cookie-specific-path.js +74 -0
- package/config/typescript/security-rules/s036-no-unsafe-file-include.js +68 -0
- package/config/typescript/security-rules/s037-require-anti-cache-headers.js +70 -0
- package/config/typescript/security-rules/s038-no-version-disclosure.js +74 -0
- package/config/typescript/security-rules/s039-no-session-token-in-url.js +63 -0
- package/config/typescript/security-rules/s041-require-session-invalidate-on-logout.js +211 -0
- package/config/typescript/security-rules/s042-require-periodic-reauthentication.js +294 -0
- package/config/typescript/security-rules/s043-terminate-sessions-on-password-change.js +254 -0
- package/config/typescript/security-rules/s044-require-full-session-for-sensitive-operations.js +292 -0
- package/config/typescript/security-rules/s045-anti-automation-controls.js +46 -0
- package/config/typescript/security-rules/s046-secure-notification-on-auth-change.js +44 -0
- package/config/typescript/security-rules/s048-password-credential-recovery.js +54 -0
- package/config/typescript/security-rules/s050-session-token-weak-hash.js +94 -0
- package/config/typescript/security-rules/s052-secure-random-authentication-code.js +66 -0
- package/config/typescript/security-rules/s054-verification-default-account.js +109 -0
- package/config/typescript/security-rules/s057-utc-logging.js +54 -0
- package/config/typescript/security-rules/s058-no-ssrf.js +73 -0
- package/config/typescript/test-s005-working.ts +22 -0
- package/config/typescript/tsconfig.json +29 -0
- package/core/ai-analyzer.js +169 -0
- package/core/analysis-orchestrator.js +705 -0
- package/core/cli-action-handler.js +230 -0
- package/core/cli-program.js +106 -0
- package/core/config-manager.js +396 -0
- package/core/config-merger.js +136 -0
- package/core/config-override-processor.js +74 -0
- package/core/config-preset-resolver.js +65 -0
- package/core/config-source-loader.js +152 -0
- package/core/config-validator.js +126 -0
- package/core/dependency-manager.js +105 -0
- package/core/eslint-engine-service.js +312 -0
- package/core/eslint-instance-manager.js +104 -0
- package/core/eslint-integration-service.js +363 -0
- package/core/git-utils.js +170 -0
- package/core/multi-rule-runner.js +239 -0
- package/core/output-service.js +250 -0
- package/core/report-generator.js +320 -0
- package/core/rule-mapping-service.js +309 -0
- package/core/rule-selection-service.js +121 -0
- package/core/sunlint-engine-service.js +23 -0
- package/core/typescript-analyzer.js +262 -0
- package/core/typescript-engine.js +313 -0
- 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/DEBUG.md +86 -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/docs/RULE-RESPONSIBILITY-MATRIX.md +204 -0
- package/eslint-integration/.eslintrc.js +98 -0
- package/eslint-integration/cli.js +35 -0
- package/eslint-integration/eslint-plugin-custom/c002-no-duplicate-code.js +204 -0
- package/eslint-integration/eslint-plugin-custom/c003-no-vague-abbreviations.js +246 -0
- package/eslint-integration/eslint-plugin-custom/c006-function-name-verb-noun.js +207 -0
- package/eslint-integration/eslint-plugin-custom/c010-limit-block-nesting.js +90 -0
- package/eslint-integration/eslint-plugin-custom/c013-no-dead-code.js +43 -0
- package/eslint-integration/eslint-plugin-custom/c014-abstract-dependency-preferred.js +38 -0
- package/eslint-integration/eslint-plugin-custom/c017-limit-constructor-logic.js +39 -0
- package/eslint-integration/eslint-plugin-custom/c018-no-generic-throw.js +335 -0
- package/eslint-integration/eslint-plugin-custom/c023-no-duplicate-variable-name-in-scope.js +142 -0
- package/eslint-integration/eslint-plugin-custom/c027-limit-function-nesting.js +50 -0
- package/eslint-integration/eslint-plugin-custom/c029-catch-block-logging.js +80 -0
- package/eslint-integration/eslint-plugin-custom/c030-use-custom-error-classes.js +294 -0
- package/eslint-integration/eslint-plugin-custom/c034-no-implicit-return.js +34 -0
- package/eslint-integration/eslint-plugin-custom/c035-no-empty-catch.js +32 -0
- package/eslint-integration/eslint-plugin-custom/c041-no-config-inline.js +64 -0
- package/eslint-integration/eslint-plugin-custom/c042-boolean-name-prefix.js +406 -0
- package/eslint-integration/eslint-plugin-custom/c043-no-console-or-print.js +300 -0
- package/eslint-integration/eslint-plugin-custom/c047-no-duplicate-retry-logic.js +239 -0
- package/eslint-integration/eslint-plugin-custom/c048-no-var-declaration.js +31 -0
- package/eslint-integration/eslint-plugin-custom/c076-one-assert-per-test.js +184 -0
- package/eslint-integration/eslint-plugin-custom/index.js +155 -0
- package/eslint-integration/eslint-plugin-custom/package.json +13 -0
- package/eslint-integration/eslint-plugin-custom/package.json.bak +9 -0
- package/eslint-integration/eslint-plugin-custom/s003-no-unvalidated-redirect.js +86 -0
- package/eslint-integration/eslint-plugin-custom/s005-no-origin-auth.js +95 -0
- package/eslint-integration/eslint-plugin-custom/s006-activation-recovery-secret-not-plaintext.js +69 -0
- package/eslint-integration/eslint-plugin-custom/s008-crypto-agility.js +62 -0
- package/eslint-integration/eslint-plugin-custom/s009-no-insecure-crypto.js +103 -0
- package/eslint-integration/eslint-plugin-custom/s010-no-insecure-random-in-sensitive-context.js +123 -0
- package/eslint-integration/eslint-plugin-custom/s011-no-insecure-uuid.js +66 -0
- package/eslint-integration/eslint-plugin-custom/s012-hardcode-secret.js +71 -0
- package/eslint-integration/eslint-plugin-custom/s014-insecure-tls-version.js +50 -0
- package/eslint-integration/eslint-plugin-custom/s015-insecure-tls-certificate.js +43 -0
- package/eslint-integration/eslint-plugin-custom/s016-sensitive-query-parameter.js +59 -0
- package/eslint-integration/eslint-plugin-custom/s017-no-sql-injection.js +193 -0
- package/eslint-integration/eslint-plugin-custom/s018-positive-input-validation.js +56 -0
- package/eslint-integration/eslint-plugin-custom/s019-no-raw-user-input-in-email.js +113 -0
- package/eslint-integration/eslint-plugin-custom/s020-no-eval-dynamic-execution.js +89 -0
- package/eslint-integration/eslint-plugin-custom/s022-output-encoding.js +78 -0
- package/eslint-integration/eslint-plugin-custom/s023-no-json-injection.js +300 -0
- package/eslint-integration/eslint-plugin-custom/s025-server-side-input-validation.js +217 -0
- package/eslint-integration/eslint-plugin-custom/s026-json-schema-validation.js +68 -0
- package/eslint-integration/eslint-plugin-custom/s027-no-hardcoded-secrets.js +80 -0
- package/eslint-integration/eslint-plugin-custom/s029-require-csrf-protection.js +79 -0
- package/eslint-integration/eslint-plugin-custom/s030-no-directory-browsing.js +78 -0
- package/eslint-integration/eslint-plugin-custom/s033-require-samesite-cookie.js +80 -0
- package/eslint-integration/eslint-plugin-custom/s034-require-host-cookie-prefix.js +77 -0
- package/eslint-integration/eslint-plugin-custom/s035-cookie-specific-path.js +74 -0
- package/eslint-integration/eslint-plugin-custom/s036-no-unsafe-file-include.js +68 -0
- package/eslint-integration/eslint-plugin-custom/s037-require-anti-cache-headers.js +70 -0
- package/eslint-integration/eslint-plugin-custom/s038-no-version-disclosure.js +74 -0
- package/eslint-integration/eslint-plugin-custom/s039-no-session-token-in-url.js +63 -0
- package/eslint-integration/eslint-plugin-custom/s041-require-session-invalidate-on-logout.js +211 -0
- package/eslint-integration/eslint-plugin-custom/s042-require-periodic-reauthentication.js +294 -0
- package/eslint-integration/eslint-plugin-custom/s043-terminate-sessions-on-password-change.js +254 -0
- package/eslint-integration/eslint-plugin-custom/s044-require-full-session-for-sensitive-operations.js +292 -0
- package/eslint-integration/eslint-plugin-custom/s045-anti-automation-controls.js +46 -0
- package/eslint-integration/eslint-plugin-custom/s046-secure-notification-on-auth-change.js +44 -0
- package/eslint-integration/eslint-plugin-custom/s047-secure-random-passwords.js +108 -0
- package/eslint-integration/eslint-plugin-custom/s048-password-credential-recovery.js +54 -0
- package/eslint-integration/eslint-plugin-custom/s050-session-token-weak-hash.js +94 -0
- package/eslint-integration/eslint-plugin-custom/s052-secure-random-authentication-code.js +66 -0
- package/eslint-integration/eslint-plugin-custom/s054-verification-default-account.js +109 -0
- package/eslint-integration/eslint-plugin-custom/s055-verification-rest-check-the-incoming-content-type.js +143 -0
- package/eslint-integration/eslint-plugin-custom/s057-utc-logging.js +54 -0
- package/eslint-integration/eslint-plugin-custom/s058-no-ssrf.js +73 -0
- package/eslint-integration/eslint-plugin-custom/t002-interface-prefix-i.js +42 -0
- package/eslint-integration/eslint-plugin-custom/t003-ts-ignore-reason.js +48 -0
- package/eslint-integration/eslint-plugin-custom/t004-interface-public-only.js +160 -0
- package/eslint-integration/eslint-plugin-custom/t007-no-fn-in-constructor.js +52 -0
- package/eslint-integration/eslint-plugin-custom/t011-no-real-time-dependency.js +175 -0
- package/eslint-integration/eslint-plugin-custom/t019-no-empty-type.js +95 -0
- package/eslint-integration/eslint-plugin-custom/t025-no-nested-union-tuple.js +48 -0
- package/eslint-integration/eslint-plugin-custom/t026-limit-nested-generics.js +377 -0
- package/eslint-integration/eslint.config.js +125 -0
- package/eslint-integration/eslint.config.simple.js +24 -0
- package/eslint-integration/node_modules/eslint-plugin-custom/package.json +0 -0
- package/eslint-integration/package.json +23 -0
- package/eslint-integration/sample.ts +53 -0
- package/eslint-integration/test-s003.js +5 -0
- package/eslint-integration/tsconfig.json +27 -0
- package/examples/.github/workflows/code-quality.yml +111 -0
- package/examples/.sunlint.json +42 -0
- package/examples/README.md +47 -0
- package/examples/package.json +33 -0
- package/package.json +100 -0
- package/rules/C006_function_naming/analyzer.js +338 -0
- package/rules/C006_function_naming/config.json +86 -0
- package/rules/C019_log_level_usage/analyzer.js +359 -0
- package/rules/C019_log_level_usage/config.json +121 -0
- package/rules/C029_catch_block_logging/analyzer.js +339 -0
- package/rules/C029_catch_block_logging/config.json +59 -0
- package/rules/C031_validation_separation/README.md +72 -0
- package/rules/C031_validation_separation/analyzer.js +186 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Action Handler
|
|
3
|
+
* Following Rule C005: Single responsibility - handle CLI execution flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const ConfigManager = require('./config-manager');
|
|
9
|
+
const RuleSelectionService = require('./rule-selection-service');
|
|
10
|
+
const AnalysisOrchestrator = require('./analysis-orchestrator');
|
|
11
|
+
const OutputService = require('./output-service');
|
|
12
|
+
const GitUtils = require('./git-utils');
|
|
13
|
+
|
|
14
|
+
class CliActionHandler {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.configManager = null;
|
|
18
|
+
this.ruleSelectionService = new RuleSelectionService();
|
|
19
|
+
this.analysisOrchestrator = new AnalysisOrchestrator();
|
|
20
|
+
this.outputService = new OutputService(options);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async execute() {
|
|
24
|
+
try {
|
|
25
|
+
this.displayBanner();
|
|
26
|
+
this.handleShortcuts();
|
|
27
|
+
|
|
28
|
+
// Load configuration
|
|
29
|
+
const config = await this.loadConfiguration();
|
|
30
|
+
|
|
31
|
+
// Validate input
|
|
32
|
+
this.validateInput();
|
|
33
|
+
|
|
34
|
+
// Show dry run preview if requested
|
|
35
|
+
if (this.options.dryRun) {
|
|
36
|
+
await this.showDryRunPreview(config);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Select rules to run
|
|
41
|
+
const rulesToRun = await this.ruleSelectionService.selectRules(config, this.options);
|
|
42
|
+
|
|
43
|
+
if (rulesToRun.length === 0) {
|
|
44
|
+
console.log(chalk.yellow('⚠️ No rules to run'));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Display analysis info
|
|
49
|
+
this.displayAnalysisInfo(rulesToRun);
|
|
50
|
+
|
|
51
|
+
// Run analysis
|
|
52
|
+
const startTime = Date.now();
|
|
53
|
+
const results = await this.analysisOrchestrator.runAnalysis(rulesToRun, this.options, config);
|
|
54
|
+
const duration = Date.now() - startTime;
|
|
55
|
+
|
|
56
|
+
// Output results
|
|
57
|
+
await this.outputService.outputResults(results, this.options, {
|
|
58
|
+
duration,
|
|
59
|
+
rulesRun: rulesToRun.length
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Exit with appropriate code
|
|
63
|
+
this.handleExit(results);
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(chalk.red('❌ Sun Lint Error:'), error.message);
|
|
67
|
+
if (this.options.debug) {
|
|
68
|
+
console.error(error.stack);
|
|
69
|
+
}
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
displayBanner() {
|
|
75
|
+
// Skip banner in quiet mode or JSON format
|
|
76
|
+
if (this.options.quiet || this.options.format === 'json') {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { version } = require('../package.json');
|
|
81
|
+
console.log(chalk.yellow.bold('☀️ Sun Lint - Coding Standards Checker'));
|
|
82
|
+
console.log(chalk.gray(`Version: ${version} | Sun* Engineering`));
|
|
83
|
+
|
|
84
|
+
if (this.options.debug) {
|
|
85
|
+
console.log(chalk.yellow('Debug mode enabled'));
|
|
86
|
+
console.log('Options:', this.options);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
handleShortcuts() {
|
|
91
|
+
if (this.options.quality) {
|
|
92
|
+
this.options.category = 'quality';
|
|
93
|
+
}
|
|
94
|
+
if (this.options.security) {
|
|
95
|
+
this.options.category = 'security';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle ESLint integration options
|
|
99
|
+
if (this.options.eslintIntegration) {
|
|
100
|
+
this.options.eslintIntegration = true;
|
|
101
|
+
}
|
|
102
|
+
if (this.options.noEslintIntegration) {
|
|
103
|
+
this.options.eslintIntegration = false;
|
|
104
|
+
}
|
|
105
|
+
if (this.options.eslintMergeRules !== undefined) {
|
|
106
|
+
this.options.eslintMergeRules = this.options.eslintMergeRules;
|
|
107
|
+
}
|
|
108
|
+
if (this.options.eslintPreserveConfig !== undefined) {
|
|
109
|
+
this.options.eslintPreserveConfig = this.options.eslintPreserveConfig;
|
|
110
|
+
}
|
|
111
|
+
if (this.options.eslintRunAfter) {
|
|
112
|
+
this.options.eslintRunAfter = true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async loadConfiguration() {
|
|
117
|
+
try {
|
|
118
|
+
if (!this.configManager) {
|
|
119
|
+
this.configManager = new ConfigManager();
|
|
120
|
+
}
|
|
121
|
+
return await this.configManager.loadConfig(this.options.config, this.options);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.log(chalk.yellow('⚠️ Using default configuration'));
|
|
124
|
+
return { rules: {} };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
validateInput() {
|
|
129
|
+
// Handle git-based file filtering
|
|
130
|
+
if (this.options.changedFiles || this.options.stagedFiles || this.options.since || this.options.prMode) {
|
|
131
|
+
this.handleGitFileFiltering();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Regular input validation
|
|
136
|
+
if (!fs.existsSync(this.options.input)) {
|
|
137
|
+
console.error(chalk.red(`❌ Input path not found: ${this.options.input}`));
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
handleGitFileFiltering() {
|
|
143
|
+
try {
|
|
144
|
+
let files = [];
|
|
145
|
+
|
|
146
|
+
if (this.options.changedFiles) {
|
|
147
|
+
const diffBase = this.options.diffBase || GitUtils.getPRDiffBase('main');
|
|
148
|
+
files = GitUtils.getChangedFiles(diffBase);
|
|
149
|
+
if (!this.options.quiet) {
|
|
150
|
+
console.log(chalk.blue(`🔄 Analyzing changed files vs ${diffBase}`));
|
|
151
|
+
}
|
|
152
|
+
} else if (this.options.stagedFiles) {
|
|
153
|
+
files = GitUtils.getStagedFiles();
|
|
154
|
+
if (!this.options.quiet) {
|
|
155
|
+
console.log(chalk.blue('🔄 Analyzing staged files'));
|
|
156
|
+
}
|
|
157
|
+
} else if (this.options.since) {
|
|
158
|
+
files = GitUtils.getFilesSince(this.options.since);
|
|
159
|
+
if (!this.options.quiet) {
|
|
160
|
+
console.log(chalk.blue(`🔄 Analyzing files changed since ${this.options.since}`));
|
|
161
|
+
}
|
|
162
|
+
} else if (this.options.prMode) {
|
|
163
|
+
const diffBase = this.options.diffBase || GitUtils.getPRDiffBase('main');
|
|
164
|
+
files = GitUtils.getChangedFiles(diffBase);
|
|
165
|
+
if (!this.options.quiet) {
|
|
166
|
+
console.log(chalk.blue(`🔄 PR mode: analyzing changes vs ${diffBase}`));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Filter for TypeScript/JavaScript files
|
|
171
|
+
const sourceFiles = GitUtils.filterSourceFiles(files);
|
|
172
|
+
|
|
173
|
+
if (sourceFiles.length === 0) {
|
|
174
|
+
console.log(chalk.yellow('⚠️ No TypeScript/JavaScript files found in git changes'));
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Update input to be the filtered file list
|
|
179
|
+
this.options.input = sourceFiles;
|
|
180
|
+
this.options.isFileList = true;
|
|
181
|
+
|
|
182
|
+
if (!this.options.quiet) {
|
|
183
|
+
console.log(chalk.green(`📁 Found ${sourceFiles.length} source files to analyze`));
|
|
184
|
+
if (this.options.verbose) {
|
|
185
|
+
sourceFiles.forEach(file => console.log(` ${chalk.gray(file)}`));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error(chalk.red(`❌ Git operation failed: ${error.message}`));
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async showDryRunPreview(config) {
|
|
196
|
+
console.log(chalk.yellow('🔍 Dry run mode - Analysis preview:'));
|
|
197
|
+
const rulesToRun = await this.ruleSelectionService.selectRules(config, this.options);
|
|
198
|
+
|
|
199
|
+
console.log(chalk.blue('📋 Sun Lint Analysis Preview:'));
|
|
200
|
+
console.log(chalk.gray(`Input: ${this.options.input}`));
|
|
201
|
+
console.log(chalk.gray(`Format: ${this.options.format}`));
|
|
202
|
+
console.log(chalk.gray(`Rules to run: ${rulesToRun.length}`));
|
|
203
|
+
|
|
204
|
+
if (rulesToRun.length > 0) {
|
|
205
|
+
console.log(chalk.blue('📋 Selected Rules:'));
|
|
206
|
+
rulesToRun.forEach(rule => {
|
|
207
|
+
console.log(` ${chalk.cyan(rule.id)}: ${rule.name} (${rule.severity})`);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
displayAnalysisInfo(rulesToRun) {
|
|
213
|
+
if (this.options.quiet || this.options.format === 'json') return;
|
|
214
|
+
|
|
215
|
+
console.log(chalk.green(`🚀 Running ${rulesToRun.length} rules on: ${this.options.input}`));
|
|
216
|
+
|
|
217
|
+
const ruleIds = rulesToRun.map(r => r.id).join(', ');
|
|
218
|
+
console.log(chalk.blue(` 📋 Rules: ${ruleIds}`));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
handleExit(results) {
|
|
222
|
+
const allResults = results.results || [];
|
|
223
|
+
const hasErrors = allResults.some(r =>
|
|
224
|
+
r.violations && r.violations.some(v => v.severity === 'error')
|
|
225
|
+
);
|
|
226
|
+
process.exit(hasErrors ? 1 : 0);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
module.exports = CliActionHandler;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Program Definition
|
|
3
|
+
* Following Rule C005: Single responsibility - only handle CLI structure
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { Command } = require('commander');
|
|
7
|
+
const { version } = require('../package.json');
|
|
8
|
+
|
|
9
|
+
function createCliProgram() {
|
|
10
|
+
const program = new Command();
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('sunlint')
|
|
14
|
+
.description('☀️ Sun Lint - Coding Standards Checker | Multi-rule Quality & Security Analysis')
|
|
15
|
+
.version(version);
|
|
16
|
+
|
|
17
|
+
// Rule selection options
|
|
18
|
+
program
|
|
19
|
+
.option('-r, --rule <rule>', 'Run single rule (e.g., C019)')
|
|
20
|
+
.option('--rules <rules>', 'Run multiple rules (comma-separated, e.g., C019,C006,S005)')
|
|
21
|
+
.option('-a, --all', 'Run all available rules')
|
|
22
|
+
.option('-c, --category <category>', 'Run rules by category (quality,security,logging,naming)')
|
|
23
|
+
.option('--quality', 'Run all code quality rules')
|
|
24
|
+
.option('--security', 'Run all secure coding rules');
|
|
25
|
+
|
|
26
|
+
// TypeScript specific options (Phase 1 focus)
|
|
27
|
+
program
|
|
28
|
+
.option('--typescript', 'Enable TypeScript-specific analysis')
|
|
29
|
+
.option('--typescript-engine <engine>', 'TypeScript analysis engine (eslint,sunlint,hybrid)', 'sunlint')
|
|
30
|
+
.option('--ensure-deps', 'Ensure ESLint dependencies are installed');
|
|
31
|
+
|
|
32
|
+
// Input/Output options
|
|
33
|
+
program
|
|
34
|
+
.option('-i, --input <path>', 'Input file or directory to analyze', 'src')
|
|
35
|
+
.option('-f, --format <format>', 'Output format (eslint,json,summary,table)', 'eslint')
|
|
36
|
+
.option('-o, --output <file>', 'Output file path')
|
|
37
|
+
.option('--config <file>', 'Configuration file path', '.sunlint.json');
|
|
38
|
+
|
|
39
|
+
// CI/CD and Git integration options
|
|
40
|
+
program
|
|
41
|
+
.option('--changed-files', 'Only analyze files changed in current branch (git diff)')
|
|
42
|
+
.option('--staged-files', 'Only analyze staged files (git diff --cached)')
|
|
43
|
+
.option('--diff-base <ref>', 'Compare against specific git reference (e.g., origin/main)')
|
|
44
|
+
.option('--since <commit>', 'Only analyze files changed since specific commit')
|
|
45
|
+
.option('--pr-mode', 'Enable PR mode (changed files + baseline comparison)')
|
|
46
|
+
.option('--baseline <file>', 'Load baseline results to compare against')
|
|
47
|
+
.option('--save-baseline <file>', 'Save current results as baseline')
|
|
48
|
+
.option('--fail-on-new-violations', 'Exit with error only on new violations (not existing)');
|
|
49
|
+
|
|
50
|
+
// Advanced options
|
|
51
|
+
program
|
|
52
|
+
.option('--dry-run', 'Show what would be analyzed without running')
|
|
53
|
+
.option('--verbose', 'Enable verbose logging')
|
|
54
|
+
.option('--quiet', 'Suppress non-error output')
|
|
55
|
+
.option('--debug', 'Enable debug mode')
|
|
56
|
+
.option('--ai', 'Enable AI-powered analysis')
|
|
57
|
+
.option('--no-ai', 'Force disable AI analysis (use heuristic only)');
|
|
58
|
+
|
|
59
|
+
// ESLint Integration options
|
|
60
|
+
program
|
|
61
|
+
.option('--eslint-integration', 'Enable ESLint integration (merge with existing ESLint config)')
|
|
62
|
+
.option('--no-eslint-integration', 'Disable ESLint integration')
|
|
63
|
+
.option('--eslint-merge-rules', 'Merge SunLint and user ESLint rules (default: true)')
|
|
64
|
+
.option('--eslint-preserve-config', 'Preserve user ESLint configuration (default: true)')
|
|
65
|
+
.option('--eslint-run-after', 'Run ESLint after SunLint (instead of merged execution)');
|
|
66
|
+
|
|
67
|
+
// Help examples
|
|
68
|
+
program.addHelpText('after', `
|
|
69
|
+
Examples:
|
|
70
|
+
$ sunlint --rule=C019 --input=src
|
|
71
|
+
$ sunlint --rules=C019,C006,S005 --input=src
|
|
72
|
+
$ sunlint --all --input=src
|
|
73
|
+
$ sunlint --quality --input=src
|
|
74
|
+
$ sunlint --security --input=src
|
|
75
|
+
$ sunlint --category=logging --input=src
|
|
76
|
+
|
|
77
|
+
TypeScript Analysis (Phase 1):
|
|
78
|
+
$ sunlint --typescript --input=src
|
|
79
|
+
$ sunlint --rule=C006 --typescript --input=src
|
|
80
|
+
$ sunlint --rules=C019,S005 --typescript --input=src
|
|
81
|
+
$ sunlint --typescript-engine=eslint --input=src
|
|
82
|
+
|
|
83
|
+
CI/CD Integration:
|
|
84
|
+
$ sunlint --all --changed-files --format=summary --no-ai
|
|
85
|
+
$ sunlint --all --changed-files --diff-base=origin/main --fail-on-new-violations
|
|
86
|
+
$ sunlint --all --staged-files --format=summary
|
|
87
|
+
$ sunlint --all --pr-mode --diff-base=origin/main
|
|
88
|
+
|
|
89
|
+
ESLint Integration:
|
|
90
|
+
$ sunlint --typescript --eslint-integration --input=src
|
|
91
|
+
$ sunlint --all --eslint-integration --eslint-merge-rules --input=src
|
|
92
|
+
$ sunlint --all --eslint-integration --eslint-run-after --input=src
|
|
93
|
+
$ sunlint --typescript --eslint-integration --changed-files
|
|
94
|
+
|
|
95
|
+
AI-powered Analysis:
|
|
96
|
+
$ sunlint --rule=C019 --input=src --ai
|
|
97
|
+
$ sunlint --all --input=src --ai
|
|
98
|
+
$ sunlint --quality --input=src --no-ai
|
|
99
|
+
|
|
100
|
+
Sun* Engineering - Coding Standards Made Simple ☀️
|
|
101
|
+
`);
|
|
102
|
+
|
|
103
|
+
return program;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { createCliProgram };
|