@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
package/cli-legacy.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LEGACY CLI - DO NOT USE
|
|
5
|
+
* This is the old monolithic CLI implementation kept for reference only.
|
|
6
|
+
* Use cli.js instead - it has the new modular architecture with ESLint integration.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { Command } = require('commander');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const MultiRuleRunner = require('./core/multi-rule-runner');
|
|
14
|
+
const ConfigManager = require('./core/config-manager');
|
|
15
|
+
const ReportGenerator = require('./core/report-generator');
|
|
16
|
+
const { version } = require('./package.json');
|
|
17
|
+
|
|
18
|
+
const program = new Command();
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.name('sunlint')
|
|
22
|
+
.description('☀️ Sun Lint - Coding Standards Checker | Multi-rule Quality & Security Analysis')
|
|
23
|
+
.version(version);
|
|
24
|
+
|
|
25
|
+
// Rule selection
|
|
26
|
+
program
|
|
27
|
+
.option('-r, --rule <rule>', 'Run single rule (e.g., C019)')
|
|
28
|
+
.option('-R, --rules <rules>', 'Run multiple rules (e.g., C019,C006,C021)')
|
|
29
|
+
.option('-a, --all', 'Run all available rules')
|
|
30
|
+
.option('-c, --category <category>', 'Run rules by category (quality,security,logging,naming)')
|
|
31
|
+
.option('--quality', 'Run all code quality rules')
|
|
32
|
+
.option('--security', 'Run all secure coding rules')
|
|
33
|
+
.option('--preset <preset>', 'Use predefined rule preset (recommended,strict,beginner)')
|
|
34
|
+
|
|
35
|
+
// Input/Output
|
|
36
|
+
.option('-i, --input <path>', 'Input file or directory to analyze', 'src')
|
|
37
|
+
.option('-f, --format <format>', 'Output format (eslint,json,summary,table)', 'eslint')
|
|
38
|
+
.option('-o, --output <file>', 'Output file path')
|
|
39
|
+
.option('--config <file>', 'Configuration file path', '.sunlint.json')
|
|
40
|
+
|
|
41
|
+
// CI/CD and Git integration
|
|
42
|
+
.option('--changed-files', 'Only analyze files changed in current branch (git diff)')
|
|
43
|
+
.option('--staged-files', 'Only analyze staged files (git diff --cached)')
|
|
44
|
+
.option('--diff-base <ref>', 'Compare against specific git reference (e.g., origin/main)')
|
|
45
|
+
.option('--since <commit>', 'Only analyze files changed since specific commit')
|
|
46
|
+
.option('--pr-mode', 'Enable PR mode (changed files + baseline comparison)')
|
|
47
|
+
.option('--baseline <file>', 'Load baseline results to compare against')
|
|
48
|
+
.option('--save-baseline <file>', 'Save current results as baseline')
|
|
49
|
+
.option('--fail-on-new-violations', 'Exit with error only on new violations (not existing)')
|
|
50
|
+
|
|
51
|
+
// Rule control
|
|
52
|
+
.option('--exclude-rules <rules>', 'Exclude specific rules (e.g., C019,C006)')
|
|
53
|
+
.option('--include-rules <rules>', 'Include only specific rules (e.g., C019,C006)')
|
|
54
|
+
.option('--disable-rule <rule>', 'Disable specific rule')
|
|
55
|
+
.option('--enable-rule <rule>', 'Enable specific rule')
|
|
56
|
+
.option('--severity <level>', 'Minimum severity level (error,warning,info)', 'info')
|
|
57
|
+
.option('--languages <langs>', 'Target languages (typescript,dart,kotlin)')
|
|
58
|
+
|
|
59
|
+
// Advanced options
|
|
60
|
+
.option('--ai', 'Enable AI-powered analysis')
|
|
61
|
+
.option('--no-ai', 'Force disable AI analysis (use heuristic only)')
|
|
62
|
+
.option('--no-cache', 'Disable result caching')
|
|
63
|
+
.option('--max-concurrent <n>', 'Maximum concurrent rule execution', '5')
|
|
64
|
+
.option('--timeout <ms>', 'Timeout for rule execution (ms)', '30000')
|
|
65
|
+
.option('--fix', 'Auto-fix issues when possible')
|
|
66
|
+
.option('--dry-run', 'Show what would be analyzed without running')
|
|
67
|
+
.option('--verbose', 'Enable verbose logging')
|
|
68
|
+
.option('--quiet', 'Suppress non-error output')
|
|
69
|
+
.option('--debug', 'Enable debug mode');
|
|
70
|
+
|
|
71
|
+
program.action(async (options) => {
|
|
72
|
+
try {
|
|
73
|
+
// Sun Lint banner
|
|
74
|
+
console.log(chalk.yellow.bold('☀️ Sun Lint - Coding Standards Checker'));
|
|
75
|
+
console.log(chalk.gray(`Version: ${version} | Sun* Engineering`));
|
|
76
|
+
|
|
77
|
+
if (options.debug) {
|
|
78
|
+
console.log(chalk.yellow('Debug mode enabled'));
|
|
79
|
+
console.log('Options:', options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle quality/security shortcuts
|
|
83
|
+
if (options.quality) {
|
|
84
|
+
options.category = 'quality';
|
|
85
|
+
}
|
|
86
|
+
if (options.security) {
|
|
87
|
+
options.category = 'security';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Load configuration
|
|
91
|
+
const configManager = new ConfigManager();
|
|
92
|
+
const config = await configManager.loadConfig(options.config, options);
|
|
93
|
+
|
|
94
|
+
if (options.verbose) {
|
|
95
|
+
console.log(chalk.gray('Configuration loaded:'), config);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Validate input
|
|
99
|
+
if (!fs.existsSync(options.input)) {
|
|
100
|
+
console.error(chalk.red(`❌ Input path not found: ${options.input}`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Show dry run info
|
|
105
|
+
if (options.dryRun) {
|
|
106
|
+
console.log(chalk.yellow('🔍 Dry run mode - Analysis preview:'));
|
|
107
|
+
await showDryRunPreview(config, options);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Initialize multi-rule runner
|
|
112
|
+
const runner = new MultiRuleRunner(config, options);
|
|
113
|
+
|
|
114
|
+
// Get rules to run
|
|
115
|
+
const rulesToRun = await getRulesToRun(config, options);
|
|
116
|
+
|
|
117
|
+
if (rulesToRun.length === 0) {
|
|
118
|
+
console.log(chalk.yellow('⚠️ No rules to run'));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!options.quiet) {
|
|
123
|
+
const rulesByCategory = categorizeRules(rulesToRun);
|
|
124
|
+
console.log(chalk.green(`🚀 Running ${rulesToRun.length} rules on: ${options.input}`));
|
|
125
|
+
|
|
126
|
+
if (rulesByCategory.quality.length > 0) {
|
|
127
|
+
console.log(chalk.blue(` 📋 Quality rules: ${rulesByCategory.quality.map(r => r.id).join(', ')}`));
|
|
128
|
+
}
|
|
129
|
+
if (rulesByCategory.security.length > 0) {
|
|
130
|
+
console.log(chalk.red(` 🔒 Security rules: ${rulesByCategory.security.map(r => r.id).join(', ')}`));
|
|
131
|
+
}
|
|
132
|
+
if (rulesByCategory.other.length > 0) {
|
|
133
|
+
console.log(chalk.gray(` ⚙️ Other rules: ${rulesByCategory.other.map(r => r.id).join(', ')}`));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Run analysis
|
|
138
|
+
const startTime = Date.now();
|
|
139
|
+
const results = await runner.runRules(rulesToRun, options.input, options);
|
|
140
|
+
const duration = Date.now() - startTime;
|
|
141
|
+
|
|
142
|
+
// Generate report
|
|
143
|
+
const reportGenerator = new ReportGenerator(config, options);
|
|
144
|
+
const report = await reportGenerator.generateReport(results, {
|
|
145
|
+
duration,
|
|
146
|
+
rulesRun: rulesToRun.length,
|
|
147
|
+
filesAnalyzed: results.filesAnalyzed || 0
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Output results
|
|
151
|
+
await outputResults(report, options);
|
|
152
|
+
|
|
153
|
+
// Exit with appropriate code
|
|
154
|
+
const allResults = results.results || [];
|
|
155
|
+
const hasErrors = allResults.some(r =>
|
|
156
|
+
r.violations && r.violations.some(v => v.severity === 'error')
|
|
157
|
+
);
|
|
158
|
+
process.exit(hasErrors ? 1 : 0);
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(chalk.red('❌ Sun Lint Error:'), error.message);
|
|
162
|
+
if (options.debug) {
|
|
163
|
+
console.error(error.stack);
|
|
164
|
+
}
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
async function getRulesToRun(config, options) {
|
|
170
|
+
const allRules = config.rules || {};
|
|
171
|
+
const rulesRegistry = require('./config/rules-registry.json');
|
|
172
|
+
|
|
173
|
+
let selectedRules = [];
|
|
174
|
+
|
|
175
|
+
if (options.rule) {
|
|
176
|
+
// Single rule
|
|
177
|
+
selectedRules = [options.rule];
|
|
178
|
+
} else if (options.rules) {
|
|
179
|
+
// Multiple rules
|
|
180
|
+
selectedRules = options.rules.split(',').map(r => r.trim());
|
|
181
|
+
} else if (options.all) {
|
|
182
|
+
// All rules
|
|
183
|
+
selectedRules = Object.keys(rulesRegistry.rules);
|
|
184
|
+
} else if (options.category) {
|
|
185
|
+
// Rules by category
|
|
186
|
+
const category = rulesRegistry.categories[options.category];
|
|
187
|
+
if (category && category.rules) {
|
|
188
|
+
selectedRules = category.rules;
|
|
189
|
+
}
|
|
190
|
+
} else if (options.preset) {
|
|
191
|
+
// Load preset using ConfigManager
|
|
192
|
+
try {
|
|
193
|
+
const ConfigManager = require('./core/config-manager');
|
|
194
|
+
const configManager = new ConfigManager();
|
|
195
|
+
|
|
196
|
+
const presetName = options.preset.startsWith('@sun/sunlint/')
|
|
197
|
+
? options.preset
|
|
198
|
+
: `@sun/sunlint/${options.preset}`;
|
|
199
|
+
const presetConfig = await configManager.loadPreset(presetName);
|
|
200
|
+
if (presetConfig && presetConfig.rules) {
|
|
201
|
+
selectedRules = Object.keys(presetConfig.rules).filter(ruleId =>
|
|
202
|
+
presetConfig.rules[ruleId] !== 'off' && presetConfig.rules[ruleId] !== false
|
|
203
|
+
);
|
|
204
|
+
console.log(chalk.blue(`🎯 Using preset: ${presetName}`));
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error(chalk.red(`❌ Failed to load preset '${options.preset}':`), error.message);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Default: use config rules
|
|
212
|
+
selectedRules = Object.keys(allRules).filter(ruleId =>
|
|
213
|
+
allRules[ruleId] !== 'off' && allRules[ruleId] !== false
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Filter out excluded rules
|
|
218
|
+
if (options.excludeRules) {
|
|
219
|
+
const excludedRules = options.excludeRules.split(',').map(r => r.trim());
|
|
220
|
+
selectedRules = selectedRules.filter(rule => !excludedRules.includes(rule));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Filter by severity
|
|
224
|
+
if (options.severity) {
|
|
225
|
+
const minSeverity = options.severity;
|
|
226
|
+
const severityLevels = { info: 0, warning: 1, error: 2 };
|
|
227
|
+
const minLevel = severityLevels[minSeverity] || 0;
|
|
228
|
+
|
|
229
|
+
selectedRules = selectedRules.filter(ruleId => {
|
|
230
|
+
const rule = rulesRegistry.rules[ruleId];
|
|
231
|
+
if (!rule) return false;
|
|
232
|
+
const ruleLevel = severityLevels[rule.severity] || 0;
|
|
233
|
+
return ruleLevel >= minLevel;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Filter by languages
|
|
238
|
+
if (options.languages) {
|
|
239
|
+
const targetLanguages = options.languages.split(',').map(l => l.trim());
|
|
240
|
+
selectedRules = selectedRules.filter(ruleId => {
|
|
241
|
+
const rule = rulesRegistry.rules[ruleId];
|
|
242
|
+
if (!rule) return false;
|
|
243
|
+
return rule.languages.some(lang => targetLanguages.includes(lang));
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Convert to rule objects
|
|
248
|
+
return selectedRules.map(ruleId => ({
|
|
249
|
+
id: ruleId,
|
|
250
|
+
...rulesRegistry.rules[ruleId]
|
|
251
|
+
})).filter(rule => rule.name); // Filter out invalid rules
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function categorizeRules(rules) {
|
|
255
|
+
const categories = {
|
|
256
|
+
quality: [],
|
|
257
|
+
security: [],
|
|
258
|
+
other: []
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
rules.forEach(rule => {
|
|
262
|
+
if (rule.category === 'security' || rule.id.startsWith('S')) {
|
|
263
|
+
categories.security.push(rule);
|
|
264
|
+
} else if (['logging', 'naming', 'validation', 'design'].includes(rule.category)) {
|
|
265
|
+
categories.quality.push(rule);
|
|
266
|
+
} else {
|
|
267
|
+
categories.other.push(rule);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return categories;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function showDryRunPreview(config, options) {
|
|
275
|
+
const rulesToRun = await getRulesToRun(config, options);
|
|
276
|
+
const rulesByCategory = categorizeRules(rulesToRun);
|
|
277
|
+
|
|
278
|
+
console.log(chalk.blue('📋 Sun Lint Analysis Preview:'));
|
|
279
|
+
console.log(chalk.gray(`Input: ${options.input}`));
|
|
280
|
+
console.log(chalk.gray(`Format: ${options.format}`));
|
|
281
|
+
console.log(chalk.gray(`Rules to run: ${rulesToRun.length}`));
|
|
282
|
+
|
|
283
|
+
if (rulesByCategory.quality.length > 0) {
|
|
284
|
+
console.log(chalk.blue('📋 Quality Rules:'));
|
|
285
|
+
rulesByCategory.quality.forEach(rule => {
|
|
286
|
+
console.log(` ${chalk.cyan(rule.id)}: ${rule.name} (${rule.severity})`);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (rulesByCategory.security.length > 0) {
|
|
291
|
+
console.log(chalk.red('🔒 Security Rules:'));
|
|
292
|
+
rulesByCategory.security.forEach(rule => {
|
|
293
|
+
console.log(` ${chalk.cyan(rule.id)}: ${rule.name} (${rule.severity})`);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (rulesByCategory.other.length > 0) {
|
|
298
|
+
console.log(chalk.white('⚙️ Other Rules:'));
|
|
299
|
+
rulesByCategory.other.forEach(rule => {
|
|
300
|
+
console.log(` ${chalk.cyan(rule.id)}: ${rule.name} (${rule.severity})`);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function outputResults(report, options) {
|
|
306
|
+
// Console output
|
|
307
|
+
if (!options.quiet) {
|
|
308
|
+
console.log(report.formatted);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// File output
|
|
312
|
+
if (options.output) {
|
|
313
|
+
fs.writeFileSync(options.output, JSON.stringify(report.raw, null, 2));
|
|
314
|
+
console.log(chalk.green(`📄 Report saved to: ${options.output}`));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Summary
|
|
318
|
+
if (report.summary && !options.quiet) {
|
|
319
|
+
console.log(chalk.blue('\n📊 Sun Lint Summary:'));
|
|
320
|
+
console.log(report.summary);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Error handling
|
|
325
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
326
|
+
console.error(chalk.red('Sun Lint - Unhandled Rejection:'), promise, chalk.red('reason:'), reason);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
process.on('uncaughtException', (error) => {
|
|
331
|
+
console.error(chalk.red('Sun Lint - Uncaught Exception:'), error);
|
|
332
|
+
process.exit(1);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Help examples
|
|
336
|
+
program.addHelpText('after', `
|
|
337
|
+
Examples:
|
|
338
|
+
$ sunlint --rule=C019 --input=src
|
|
339
|
+
$ sunlint --rules=C019,C006 --input=src --format=json
|
|
340
|
+
$ sunlint --all --input=src --format=summary
|
|
341
|
+
$ sunlint --quality --input=src
|
|
342
|
+
$ sunlint --security --input=src
|
|
343
|
+
$ sunlint --category=logging --input=src
|
|
344
|
+
$ sunlint --preset=recommended --input=src
|
|
345
|
+
$ sunlint --config=.sunlint.json --input=src
|
|
346
|
+
$ sunlint --rule=C019 --input=src --output=report.json
|
|
347
|
+
$ sunlint --all --input=src --exclude-rules=C006,C031
|
|
348
|
+
$ sunlint --rule=C019 --input=src --ai
|
|
349
|
+
$ sunlint --rule=C019 --input=src --no-ai
|
|
350
|
+
$ sunlint --all --input=src --severity=error --ai
|
|
351
|
+
|
|
352
|
+
Sun* Engineering - Coding Standards Made Simple ☀️
|
|
353
|
+
`);
|
|
354
|
+
|
|
355
|
+
program.parse();
|
package/cli.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SunLint CLI Entry Point
|
|
5
|
+
* Main CLI entry point with modular architecture
|
|
6
|
+
* Following Rule C005: Single responsibility - only handle CLI bootstrapping
|
|
7
|
+
* Following Rule C014: Dependency injection for services
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const { createCliProgram } = require('./core/cli-program');
|
|
12
|
+
const CliActionHandler = require('./core/cli-action-handler');
|
|
13
|
+
|
|
14
|
+
// Create CLI program
|
|
15
|
+
const program = createCliProgram();
|
|
16
|
+
|
|
17
|
+
// Set up main action handler
|
|
18
|
+
program.action(async (options) => {
|
|
19
|
+
const actionHandler = new CliActionHandler(options);
|
|
20
|
+
await actionHandler.execute();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Global error handling
|
|
24
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
25
|
+
console.error(chalk.red('Sun Lint - Unhandled Rejection:'), promise, chalk.red('reason:'), reason);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
process.on('uncaughtException', (error) => {
|
|
30
|
+
console.error(chalk.red('Sun Lint - Uncaught Exception:'), error);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Parse CLI arguments
|
|
35
|
+
program.parse();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": {
|
|
3
|
+
"C006": true,
|
|
4
|
+
"C019": true,
|
|
5
|
+
"C032": true,
|
|
6
|
+
"C045": true
|
|
7
|
+
},
|
|
8
|
+
"categories": ["quality", "security"],
|
|
9
|
+
"integration": {
|
|
10
|
+
"eslint": {
|
|
11
|
+
"enabled": true,
|
|
12
|
+
"legacySupport": false,
|
|
13
|
+
"autoDetect": true,
|
|
14
|
+
"fallbackToStandalone": true
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"compatibility": {
|
|
18
|
+
"eslintV8": false,
|
|
19
|
+
"eslintV9": true,
|
|
20
|
+
"strictConfigValidation": false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sun/sunlint/beginner",
|
|
3
|
+
"description": "Beginner-friendly configuration with warnings only",
|
|
4
|
+
"rules": {
|
|
5
|
+
"C019": "warning",
|
|
6
|
+
"C029": "warning",
|
|
7
|
+
"C006": "info"
|
|
8
|
+
},
|
|
9
|
+
"categories": {
|
|
10
|
+
"quality": "warning",
|
|
11
|
+
"security": "warning",
|
|
12
|
+
"logging": "warning",
|
|
13
|
+
"naming": "info",
|
|
14
|
+
"validation": "warning"
|
|
15
|
+
},
|
|
16
|
+
"languages": ["typescript"],
|
|
17
|
+
"ignorePatterns": [
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/build/**",
|
|
20
|
+
"**/dist/**",
|
|
21
|
+
"**/*.generated.*",
|
|
22
|
+
"**/*.min.*",
|
|
23
|
+
"**/test/**",
|
|
24
|
+
"**/tests/**"
|
|
25
|
+
],
|
|
26
|
+
"ai": {
|
|
27
|
+
"enabled": false,
|
|
28
|
+
"fallbackToPattern": true
|
|
29
|
+
},
|
|
30
|
+
"reporting": {
|
|
31
|
+
"exitOnError": false,
|
|
32
|
+
"showProgress": true,
|
|
33
|
+
"includeContext": true,
|
|
34
|
+
"showFixSuggestions": true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sun/sunlint/ci",
|
|
3
|
+
"description": "Configuration optimized for CI/CD pipelines",
|
|
4
|
+
"rules": {
|
|
5
|
+
"C019": "error",
|
|
6
|
+
"C029": "error",
|
|
7
|
+
"C006": "off"
|
|
8
|
+
},
|
|
9
|
+
"categories": {
|
|
10
|
+
"quality": "error",
|
|
11
|
+
"security": "error",
|
|
12
|
+
"logging": "error",
|
|
13
|
+
"naming": "off",
|
|
14
|
+
"validation": "error"
|
|
15
|
+
},
|
|
16
|
+
"languages": ["typescript", "dart", "javascript"],
|
|
17
|
+
"ignorePatterns": [
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/build/**",
|
|
20
|
+
"**/dist/**",
|
|
21
|
+
"**/*.generated.*",
|
|
22
|
+
"**/*.min.*",
|
|
23
|
+
"coverage/**"
|
|
24
|
+
],
|
|
25
|
+
"ai": {
|
|
26
|
+
"enabled": false,
|
|
27
|
+
"fallbackToPattern": true
|
|
28
|
+
},
|
|
29
|
+
"output": {
|
|
30
|
+
"format": "github",
|
|
31
|
+
"console": false,
|
|
32
|
+
"summary": true,
|
|
33
|
+
"file": "sunlint-report.json"
|
|
34
|
+
},
|
|
35
|
+
"performance": {
|
|
36
|
+
"maxConcurrentRules": 10,
|
|
37
|
+
"timeoutMs": 60000,
|
|
38
|
+
"cacheEnabled": true
|
|
39
|
+
},
|
|
40
|
+
"reporting": {
|
|
41
|
+
"exitOnError": true,
|
|
42
|
+
"showProgress": false,
|
|
43
|
+
"includeContext": false,
|
|
44
|
+
"showFixSuggestions": false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sun/sunlint/recommended",
|
|
3
|
+
"description": "Sun* Engineering recommended configuration",
|
|
4
|
+
"rules": {
|
|
5
|
+
"C019": "warning",
|
|
6
|
+
"C029": "error",
|
|
7
|
+
"C006": "off"
|
|
8
|
+
},
|
|
9
|
+
"categories": {
|
|
10
|
+
"quality": "warning",
|
|
11
|
+
"security": "error",
|
|
12
|
+
"logging": "warning",
|
|
13
|
+
"naming": "off",
|
|
14
|
+
"validation": "error"
|
|
15
|
+
},
|
|
16
|
+
"languages": ["typescript", "dart"],
|
|
17
|
+
"ignorePatterns": [
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/build/**",
|
|
20
|
+
"**/dist/**",
|
|
21
|
+
"**/*.generated.*",
|
|
22
|
+
"**/*.min.*"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sun/sunlint/strict",
|
|
3
|
+
"description": "Strict configuration for production projects",
|
|
4
|
+
"rules": {
|
|
5
|
+
"C019": "error",
|
|
6
|
+
"C029": "error",
|
|
7
|
+
"C006": "warning"
|
|
8
|
+
},
|
|
9
|
+
"categories": {
|
|
10
|
+
"quality": "error",
|
|
11
|
+
"security": "error",
|
|
12
|
+
"logging": "error",
|
|
13
|
+
"naming": "warning",
|
|
14
|
+
"validation": "error"
|
|
15
|
+
},
|
|
16
|
+
"languages": ["typescript", "dart", "javascript"],
|
|
17
|
+
"ignorePatterns": [
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/build/**",
|
|
20
|
+
"**/dist/**",
|
|
21
|
+
"**/*.generated.*",
|
|
22
|
+
"**/*.min.*"
|
|
23
|
+
],
|
|
24
|
+
"ai": {
|
|
25
|
+
"enabled": true,
|
|
26
|
+
"fallbackToPattern": false
|
|
27
|
+
},
|
|
28
|
+
"reporting": {
|
|
29
|
+
"exitOnError": true,
|
|
30
|
+
"showProgress": true
|
|
31
|
+
}
|
|
32
|
+
}
|