@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,320 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { table } = require('table');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
class ReportGenerator {
|
|
6
|
+
constructor(config, options) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async generateReport(results, metadata) {
|
|
12
|
+
const report = {
|
|
13
|
+
metadata: {
|
|
14
|
+
...metadata,
|
|
15
|
+
timestamp: new Date().toISOString(),
|
|
16
|
+
tool: '☀️ Sun Lint',
|
|
17
|
+
company: 'Sun*',
|
|
18
|
+
format: this.options?.format || 'eslint'
|
|
19
|
+
},
|
|
20
|
+
raw: results,
|
|
21
|
+
formatted: '',
|
|
22
|
+
summary: ''
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Generate formatted output based on format
|
|
26
|
+
switch (this.options?.format) {
|
|
27
|
+
case 'eslint':
|
|
28
|
+
report.formatted = this.generateESLintFormat(results);
|
|
29
|
+
break;
|
|
30
|
+
case 'json':
|
|
31
|
+
report.formatted = JSON.stringify(results, null, 2);
|
|
32
|
+
break;
|
|
33
|
+
case 'summary':
|
|
34
|
+
report.formatted = this.generateSummaryFormat(results);
|
|
35
|
+
break;
|
|
36
|
+
case 'table':
|
|
37
|
+
report.formatted = this.generateTableFormat(results);
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
report.formatted = this.generateESLintFormat(results);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Generate summary
|
|
44
|
+
report.summary = this.generateSummary(results, metadata);
|
|
45
|
+
|
|
46
|
+
return report;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
generateESLintFormat(results) {
|
|
50
|
+
const violations = this.flattenViolations(results);
|
|
51
|
+
|
|
52
|
+
if (violations.length === 0) {
|
|
53
|
+
return chalk.green('✨ No coding standard violations found!');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const groupedByFile = this.groupViolationsByFile(violations);
|
|
57
|
+
let output = '';
|
|
58
|
+
|
|
59
|
+
for (const [file, fileViolations] of Object.entries(groupedByFile)) {
|
|
60
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
61
|
+
output += `\n${chalk.underline(relativePath)}\n`;
|
|
62
|
+
|
|
63
|
+
fileViolations.forEach(violation => {
|
|
64
|
+
const severityColor = this.getSeverityColor(violation.severity);
|
|
65
|
+
const line = violation.line || 1;
|
|
66
|
+
const column = violation.column || 1;
|
|
67
|
+
|
|
68
|
+
output += ` ${line}:${column} `;
|
|
69
|
+
output += `${severityColor(this.getSeveritySymbol(violation.severity))} `;
|
|
70
|
+
output += `${violation.message} `;
|
|
71
|
+
output += `${chalk.gray(violation.ruleId)}\n`;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Add summary line
|
|
76
|
+
const errorCount = violations.filter(v => v.severity === 'error').length;
|
|
77
|
+
const warningCount = violations.filter(v => v.severity === 'warning').length;
|
|
78
|
+
const infoCount = violations.filter(v => v.severity === 'info').length;
|
|
79
|
+
|
|
80
|
+
output += '\n';
|
|
81
|
+
output += chalk.red(`✖ ${violations.length} problems `);
|
|
82
|
+
output += `(${errorCount} errors, ${warningCount} warnings, ${infoCount} infos)\n`;
|
|
83
|
+
|
|
84
|
+
return output;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
generateSummaryFormat(results) {
|
|
88
|
+
const violations = this.flattenViolations(results);
|
|
89
|
+
let output = '';
|
|
90
|
+
|
|
91
|
+
// Header
|
|
92
|
+
output += chalk.blue.bold('🔍 Coding Standards Analysis Report\n');
|
|
93
|
+
output += chalk.gray('═'.repeat(50)) + '\n\n';
|
|
94
|
+
|
|
95
|
+
// Overview
|
|
96
|
+
output += chalk.white.bold('📊 Overview:\n');
|
|
97
|
+
output += ` Files analyzed: ${results.filesAnalyzed || 0}\n`;
|
|
98
|
+
output += ` Rules executed: ${results.rulesRun || 0}\n`;
|
|
99
|
+
output += ` Total violations: ${violations.length}\n\n`;
|
|
100
|
+
|
|
101
|
+
// Violations by severity
|
|
102
|
+
const bySeverity = results.violationsBySeverity || {};
|
|
103
|
+
output += chalk.white.bold('🚨 Violations by Severity:\n');
|
|
104
|
+
output += ` ${chalk.red('Errors')}: ${bySeverity.error || 0}\n`;
|
|
105
|
+
output += ` ${chalk.yellow('Warnings')}: ${bySeverity.warning || 0}\n`;
|
|
106
|
+
output += ` ${chalk.blue('Info')}: ${bySeverity.info || 0}\n\n`;
|
|
107
|
+
|
|
108
|
+
// Top violated rules
|
|
109
|
+
if (results.violationsByRule && Object.keys(results.violationsByRule).length > 0) {
|
|
110
|
+
output += chalk.white.bold('📏 Most Violated Rules:\n');
|
|
111
|
+
const sortedRules = Object.entries(results.violationsByRule)
|
|
112
|
+
.sort(([,a], [,b]) => b - a)
|
|
113
|
+
.slice(0, 5);
|
|
114
|
+
|
|
115
|
+
sortedRules.forEach(([ruleId, count]) => {
|
|
116
|
+
output += ` ${ruleId}: ${count} violations\n`;
|
|
117
|
+
});
|
|
118
|
+
output += '\n';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Top problematic files
|
|
122
|
+
if (results.violationsByFile && Object.keys(results.violationsByFile).length > 0) {
|
|
123
|
+
output += chalk.white.bold('📁 Most Problematic Files:\n');
|
|
124
|
+
const sortedFiles = Object.entries(results.violationsByFile)
|
|
125
|
+
.sort(([,a], [,b]) => b - a)
|
|
126
|
+
.slice(0, 5);
|
|
127
|
+
|
|
128
|
+
sortedFiles.forEach(([file, count]) => {
|
|
129
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
130
|
+
output += ` ${relativePath}: ${count} violations\n`;
|
|
131
|
+
});
|
|
132
|
+
output += '\n';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Recent violations (first 10)
|
|
136
|
+
if (violations.length > 0) {
|
|
137
|
+
output += chalk.white.bold('🔍 Recent Violations:\n');
|
|
138
|
+
violations.slice(0, 10).forEach(violation => {
|
|
139
|
+
const relativePath = path.relative(process.cwd(), violation.file || '');
|
|
140
|
+
const severityColor = this.getSeverityColor(violation.severity);
|
|
141
|
+
output += ` ${severityColor(violation.severity.toUpperCase())}: ${violation.message}\n`;
|
|
142
|
+
output += ` ${chalk.gray(`at ${relativePath}:${violation.line || 1}:${violation.column || 1} (${violation.ruleId})`)}\n`;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
generateTableFormat(results) {
|
|
150
|
+
const violations = this.flattenViolations(results);
|
|
151
|
+
|
|
152
|
+
if (violations.length === 0) {
|
|
153
|
+
return chalk.green('✨ No coding standard violations found!');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check if this is an integrated analysis with source information
|
|
157
|
+
const hasSourceInfo = violations.some(v => v.source);
|
|
158
|
+
|
|
159
|
+
const tableData = hasSourceInfo
|
|
160
|
+
? [['File', 'Line', 'Severity', 'Source', 'Rule', 'Message']]
|
|
161
|
+
: [['File', 'Line', 'Severity', 'Rule', 'Message']];
|
|
162
|
+
|
|
163
|
+
violations.forEach(violation => {
|
|
164
|
+
const relativePath = path.relative(process.cwd(), violation.file || '');
|
|
165
|
+
const row = [
|
|
166
|
+
relativePath,
|
|
167
|
+
(violation.line || 1).toString(),
|
|
168
|
+
violation.severity,
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
if (hasSourceInfo) {
|
|
172
|
+
// Add source information with color coding
|
|
173
|
+
const sourceDisplay = violation.source === 'sunlint'
|
|
174
|
+
? chalk.yellow('SunLint')
|
|
175
|
+
: chalk.cyan('ESLint');
|
|
176
|
+
row.push(sourceDisplay);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
row.push(
|
|
180
|
+
violation.ruleId || 'unknown',
|
|
181
|
+
violation.message.substring(0, 50) + (violation.message.length > 50 ? '...' : '')
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// Add conflict info if available
|
|
185
|
+
if (violation.additionalInfo) {
|
|
186
|
+
row[row.length - 1] += chalk.gray(` (ESLint: ${violation.additionalInfo.eslintRule})`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
tableData.push(row);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const config = {
|
|
193
|
+
border: {
|
|
194
|
+
topBody: '─',
|
|
195
|
+
topJoin: '┬',
|
|
196
|
+
topLeft: '┌',
|
|
197
|
+
topRight: '┐',
|
|
198
|
+
bottomBody: '─',
|
|
199
|
+
bottomJoin: '┴',
|
|
200
|
+
bottomLeft: '└',
|
|
201
|
+
bottomRight: '┘',
|
|
202
|
+
bodyLeft: '│',
|
|
203
|
+
bodyRight: '│',
|
|
204
|
+
bodyJoin: '│',
|
|
205
|
+
joinBody: '─',
|
|
206
|
+
joinLeft: '├',
|
|
207
|
+
joinRight: '┤',
|
|
208
|
+
joinJoin: '┼'
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
return table(tableData, config);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
generateSummary(results, metadata) {
|
|
216
|
+
const violations = this.flattenViolations(results);
|
|
217
|
+
const errorCount = violations.filter(v => v.severity === 'error').length;
|
|
218
|
+
const warningCount = violations.filter(v => v.severity === 'warning').length;
|
|
219
|
+
const infoCount = violations.filter(v => v.severity === 'info').length;
|
|
220
|
+
|
|
221
|
+
let summary = '';
|
|
222
|
+
summary += `Analysis completed in ${metadata.duration}ms\n`;
|
|
223
|
+
summary += `Files: ${results.filesAnalyzed || 0} | Rules: ${metadata.rulesRun} | Total: ${violations.length}\n`;
|
|
224
|
+
|
|
225
|
+
if (errorCount > 0) {
|
|
226
|
+
summary += chalk.red(`Errors: ${errorCount} `);
|
|
227
|
+
}
|
|
228
|
+
if (warningCount > 0) {
|
|
229
|
+
summary += chalk.yellow(`Warnings: ${warningCount} `);
|
|
230
|
+
}
|
|
231
|
+
if (infoCount > 0) {
|
|
232
|
+
summary += chalk.blue(`Info: ${infoCount} `);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return summary.trim();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
flattenViolations(results) {
|
|
239
|
+
const violations = [];
|
|
240
|
+
|
|
241
|
+
if (results.results) {
|
|
242
|
+
results.results.forEach(result => {
|
|
243
|
+
// Handle SunLint format (violations array)
|
|
244
|
+
if (result.violations) {
|
|
245
|
+
result.violations.forEach(violation => {
|
|
246
|
+
violations.push({
|
|
247
|
+
...violation,
|
|
248
|
+
ruleId: violation.ruleId || result.ruleId,
|
|
249
|
+
severity: violation.severity || result.severity || 'warning'
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Handle ESLint format (messages array)
|
|
255
|
+
if (result.messages) {
|
|
256
|
+
result.messages.forEach(message => {
|
|
257
|
+
violations.push({
|
|
258
|
+
file: result.filePath || message.file,
|
|
259
|
+
ruleId: message.ruleId,
|
|
260
|
+
severity: message.severity === 2 ? 'error' : 'warning',
|
|
261
|
+
message: message.message,
|
|
262
|
+
line: message.line,
|
|
263
|
+
column: message.column,
|
|
264
|
+
source: message.source || 'eslint'
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return violations;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
groupViolationsByFile(violations) {
|
|
275
|
+
const grouped = {};
|
|
276
|
+
|
|
277
|
+
violations.forEach(violation => {
|
|
278
|
+
const file = violation.file || violation.filePath || 'unknown';
|
|
279
|
+
if (!grouped[file]) {
|
|
280
|
+
grouped[file] = [];
|
|
281
|
+
}
|
|
282
|
+
grouped[file].push(violation);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Sort violations within each file by line number
|
|
286
|
+
Object.keys(grouped).forEach(file => {
|
|
287
|
+
grouped[file].sort((a, b) => (a.line || 1) - (b.line || 1));
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return grouped;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
getSeverityColor(severity) {
|
|
294
|
+
switch (severity) {
|
|
295
|
+
case 'error':
|
|
296
|
+
return chalk.red;
|
|
297
|
+
case 'warning':
|
|
298
|
+
return chalk.yellow;
|
|
299
|
+
case 'info':
|
|
300
|
+
return chalk.blue;
|
|
301
|
+
default:
|
|
302
|
+
return chalk.gray;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
getSeveritySymbol(severity) {
|
|
307
|
+
switch (severity) {
|
|
308
|
+
case 'error':
|
|
309
|
+
return '✖';
|
|
310
|
+
case 'warning':
|
|
311
|
+
return '⚠';
|
|
312
|
+
case 'info':
|
|
313
|
+
return 'ℹ';
|
|
314
|
+
default:
|
|
315
|
+
return '•';
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
module.exports = ReportGenerator;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule Mapping Service
|
|
3
|
+
* Following Rule C005: Single responsibility - handle rule mapping logic
|
|
4
|
+
* Following Rule C015: Use domain language - clear naming for rule mappings
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class RuleMappingService {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.eslintToSunlintMapping = this.createEslintToSunlintMapping();
|
|
10
|
+
this.sunlintToEslintMapping = this.createSunlintToEslintMapping();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create ESLint to SunLint rule mapping
|
|
15
|
+
* Following Rule C012: Query - pure function
|
|
16
|
+
*/
|
|
17
|
+
createEslintToSunlintMapping() {
|
|
18
|
+
return {
|
|
19
|
+
// Custom rules mapping (using actual rule IDs from eslint-plugin-custom)
|
|
20
|
+
'custom/c002': 'C002',
|
|
21
|
+
'custom/c003': 'C003',
|
|
22
|
+
'custom/c006': 'C006',
|
|
23
|
+
'custom/c010': 'C010',
|
|
24
|
+
'custom/c013': 'C013',
|
|
25
|
+
'custom/c014': 'C014',
|
|
26
|
+
'custom/c017': 'C017',
|
|
27
|
+
'custom/c018': 'C018',
|
|
28
|
+
'custom/c023': 'C023',
|
|
29
|
+
'custom/c027': 'C027',
|
|
30
|
+
'custom/c029': 'C029',
|
|
31
|
+
'custom/c030': 'C030',
|
|
32
|
+
'custom/c034': 'C034',
|
|
33
|
+
'custom/c035': 'C035',
|
|
34
|
+
'custom/c041': 'C041',
|
|
35
|
+
'custom/c042': 'C042',
|
|
36
|
+
'custom/c043': 'C043',
|
|
37
|
+
'custom/c047': 'C047',
|
|
38
|
+
'custom/c048': 'C048',
|
|
39
|
+
'custom/c076': 'C076',
|
|
40
|
+
'custom/t002': 'T002',
|
|
41
|
+
'custom/t003': 'T003',
|
|
42
|
+
'custom/t004': 'T004',
|
|
43
|
+
'custom/t007': 'T007',
|
|
44
|
+
'custom/t011': 'T011',
|
|
45
|
+
'custom/t019': 'T019',
|
|
46
|
+
'custom/t025': 'T025',
|
|
47
|
+
'custom/t026': 'T026',
|
|
48
|
+
|
|
49
|
+
// Additional mappings for semantic rule names
|
|
50
|
+
'custom/no-console-error': 'C019',
|
|
51
|
+
|
|
52
|
+
// Security rules mapping
|
|
53
|
+
'custom/typescript_s003': 'S003',
|
|
54
|
+
'custom/typescript_s005': 'S005',
|
|
55
|
+
'custom/typescript_s006': 'S006',
|
|
56
|
+
'custom/typescript_s008': 'S008',
|
|
57
|
+
'custom/typescript_s009': 'S009',
|
|
58
|
+
'custom/typescript_s010': 'S010',
|
|
59
|
+
'custom/typescript_s011': 'S011',
|
|
60
|
+
'custom/typescript_s012': 'S012',
|
|
61
|
+
'custom/typescript_s014': 'S014',
|
|
62
|
+
'custom/typescript_s015': 'S015',
|
|
63
|
+
'custom/typescript_s016': 'S016',
|
|
64
|
+
'custom/typescript_s017': 'S017',
|
|
65
|
+
'custom/typescript_s018': 'S018',
|
|
66
|
+
'custom/typescript_s019': 'S019',
|
|
67
|
+
'custom/typescript_s020': 'S020',
|
|
68
|
+
'custom/typescript_s022': 'S022',
|
|
69
|
+
'custom/typescript_s023': 'S023',
|
|
70
|
+
'custom/typescript_s025': 'S025',
|
|
71
|
+
'custom/typescript_s026': 'S026',
|
|
72
|
+
'custom/typescript_s027': 'S027',
|
|
73
|
+
'custom/typescript_s029': 'S029',
|
|
74
|
+
'custom/typescript_s030': 'S030',
|
|
75
|
+
'custom/typescript_s033': 'S033',
|
|
76
|
+
'custom/typescript_s034': 'S034',
|
|
77
|
+
'custom/typescript_s035': 'S035',
|
|
78
|
+
'custom/typescript_s036': 'S036',
|
|
79
|
+
'custom/typescript_s037': 'S037',
|
|
80
|
+
'custom/typescript_s038': 'S038',
|
|
81
|
+
'custom/typescript_s039': 'S039',
|
|
82
|
+
'custom/typescript_s041': 'S041',
|
|
83
|
+
'custom/typescript_s042': 'S042',
|
|
84
|
+
'custom/typescript_s043': 'S043',
|
|
85
|
+
'custom/typescript_s044': 'S044',
|
|
86
|
+
'custom/typescript_s045': 'S045',
|
|
87
|
+
'custom/typescript_s046': 'S046',
|
|
88
|
+
'custom/typescript_s047': 'S047',
|
|
89
|
+
'custom/typescript_s048': 'S048',
|
|
90
|
+
'custom/typescript_s050': 'S050',
|
|
91
|
+
'custom/typescript_s052': 'S052',
|
|
92
|
+
'custom/typescript_s054': 'S054',
|
|
93
|
+
'custom/typescript_s055': 'S055',
|
|
94
|
+
'custom/typescript_s057': 'S057',
|
|
95
|
+
'custom/typescript_s058': 'S058',
|
|
96
|
+
'custom/single-responsibility': 'C005',
|
|
97
|
+
'custom/verb-noun-naming': 'C006',
|
|
98
|
+
'custom/no-direct-new': 'C014',
|
|
99
|
+
'custom/domain-language': 'C015',
|
|
100
|
+
'custom/separate-validation': 'C031',
|
|
101
|
+
'custom/no-constructor-api': 'C032',
|
|
102
|
+
'custom/separate-logic-data': 'C033',
|
|
103
|
+
'custom/no-global-state': 'C034',
|
|
104
|
+
'custom/full-error-logging': 'C035',
|
|
105
|
+
'custom/standard-response': 'C037',
|
|
106
|
+
'custom/no-order-dependency': 'C038',
|
|
107
|
+
'custom/centralized-validation': 'C040',
|
|
108
|
+
|
|
109
|
+
// Standard ESLint rules that map to SunLint rules
|
|
110
|
+
'prefer-const': 'C_PREFER_CONST',
|
|
111
|
+
'no-unused-vars': 'C_NO_UNUSED_VARS',
|
|
112
|
+
'no-console': 'C019', // Maps to logging rule
|
|
113
|
+
'no-undef': 'C_NO_UNDEF', // Undefined variables
|
|
114
|
+
'consistent-return': 'C_CONSISTENT_RETURN',
|
|
115
|
+
'no-var': 'C_NO_VAR',
|
|
116
|
+
'eqeqeq': 'C_STRICT_EQUALITY',
|
|
117
|
+
'no-eval': 'S_NO_EVAL',
|
|
118
|
+
'no-implied-eval': 'S_NO_IMPLIED_EVAL',
|
|
119
|
+
'no-new-func': 'S_NO_NEW_FUNC',
|
|
120
|
+
'max-lines-per-function': 'C_MAX_LINES_PER_FUNCTION',
|
|
121
|
+
'complexity': 'C_COMPLEXITY',
|
|
122
|
+
'no-new': 'C_NO_NEW',
|
|
123
|
+
'curly': 'C_CURLY_BRACES',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create SunLint to ESLint rule mapping
|
|
129
|
+
* Following Rule C012: Query - pure function
|
|
130
|
+
*/
|
|
131
|
+
createSunlintToEslintMapping() {
|
|
132
|
+
const mapping = {};
|
|
133
|
+
|
|
134
|
+
// Reverse the ESLint to SunLint mapping
|
|
135
|
+
for (const [eslintRule, sunlintRule] of Object.entries(this.eslintToSunlintMapping)) {
|
|
136
|
+
if (!mapping[sunlintRule]) {
|
|
137
|
+
mapping[sunlintRule] = [];
|
|
138
|
+
}
|
|
139
|
+
mapping[sunlintRule].push(eslintRule);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Add additional direct mappings
|
|
143
|
+
mapping['C005'] = ['custom/single-responsibility']; // C005 doesn't have direct ESLint rule, fallback to basic
|
|
144
|
+
mapping['C006'] = ['custom/c006']; // Verb-noun naming
|
|
145
|
+
mapping['C014'] = ['custom/c014']; // Dependency injection
|
|
146
|
+
mapping['C015'] = ['custom/domain-language']; // Domain language - no direct ESLint rule
|
|
147
|
+
mapping['C019'] = ['custom/c043', 'no-console']; // Console/logging
|
|
148
|
+
mapping['C031'] = ['custom/separate-validation']; // Validation - no direct ESLint rule
|
|
149
|
+
mapping['C032'] = ['custom/no-constructor-api']; // Constructor API - no direct ESLint rule
|
|
150
|
+
mapping['C033'] = ['custom/separate-logic-data']; // Logic separation - no direct ESLint rule
|
|
151
|
+
mapping['C034'] = ['custom/c034']; // Implicit return
|
|
152
|
+
mapping['C035'] = ['custom/c035']; // Empty catch
|
|
153
|
+
mapping['C037'] = ['custom/standard-response']; // Standard response - no direct ESLint rule
|
|
154
|
+
mapping['C038'] = ['custom/no-order-dependency']; // Order dependency - no direct ESLint rule
|
|
155
|
+
mapping['C040'] = ['custom/centralized-validation']; // Centralized validation - no direct ESLint rule
|
|
156
|
+
|
|
157
|
+
// Additional mappings for available custom rules
|
|
158
|
+
mapping['C002'] = ['custom/c002']; // Duplicate code
|
|
159
|
+
mapping['C003'] = ['custom/c003']; // Vague abbreviations
|
|
160
|
+
mapping['C010'] = ['custom/c010']; // Block nesting
|
|
161
|
+
mapping['C013'] = ['custom/c013']; // Dead code
|
|
162
|
+
mapping['C017'] = ['custom/c017']; // Constructor logic
|
|
163
|
+
mapping['C018'] = ['custom/c018']; // Generic throw
|
|
164
|
+
mapping['C023'] = ['custom/c023']; // Duplicate variable name
|
|
165
|
+
mapping['C027'] = ['custom/c027']; // Function nesting
|
|
166
|
+
mapping['C029'] = ['custom/c029']; // Catch block logging
|
|
167
|
+
mapping['C030'] = ['custom/c030']; // Custom error classes
|
|
168
|
+
mapping['C041'] = ['custom/c041']; // Config inline
|
|
169
|
+
mapping['C042'] = ['custom/c042']; // Boolean naming
|
|
170
|
+
mapping['C043'] = ['custom/c043']; // Console/print
|
|
171
|
+
mapping['C047'] = ['custom/c047']; // Duplicate retry logic
|
|
172
|
+
mapping['C048'] = ['custom/c048']; // Var declaration
|
|
173
|
+
mapping['C076'] = ['custom/c076']; // One assert per test
|
|
174
|
+
|
|
175
|
+
// Security rules mapping
|
|
176
|
+
mapping['S005'] = ['custom/typescript_s005']; // No Origin header auth
|
|
177
|
+
mapping['S006'] = ['custom/typescript_s006']; // Activation recovery secret
|
|
178
|
+
mapping['S008'] = ['custom/typescript_s008']; // Crypto agility
|
|
179
|
+
mapping['S009'] = ['custom/typescript_s009']; // No insecure crypto
|
|
180
|
+
mapping['S010'] = ['custom/typescript_s010']; // No insecure random
|
|
181
|
+
mapping['S011'] = ['custom/typescript_s011']; // No insecure UUID
|
|
182
|
+
mapping['S012'] = ['custom/typescript_s012']; // No hardcoded secrets
|
|
183
|
+
mapping['S014'] = ['custom/typescript_s014']; // Insecure TLS version
|
|
184
|
+
mapping['S015'] = ['custom/typescript_s015']; // Insecure TLS certificate
|
|
185
|
+
mapping['S016'] = ['custom/typescript_s016']; // Sensitive query parameter
|
|
186
|
+
mapping['S017'] = ['custom/typescript_s017']; // No SQL injection
|
|
187
|
+
mapping['S018'] = ['custom/typescript_s018']; // Positive input validation
|
|
188
|
+
mapping['S019'] = ['custom/typescript_s019']; // No raw user input in email
|
|
189
|
+
mapping['S020'] = ['custom/typescript_s020']; // No eval dynamic execution
|
|
190
|
+
mapping['S022'] = ['custom/typescript_s022']; // Output encoding required
|
|
191
|
+
mapping['S023'] = ['custom/typescript_s023']; // No JSON injection
|
|
192
|
+
mapping['S025'] = ['custom/typescript_s025']; // Server side input validation
|
|
193
|
+
mapping['S026'] = ['custom/typescript_s026']; // JSON schema validation
|
|
194
|
+
mapping['S027'] = ['custom/typescript_s027']; // No hardcoded secrets advanced
|
|
195
|
+
mapping['S029'] = ['custom/typescript_s029']; // Require CSRF protection
|
|
196
|
+
mapping['S030'] = ['custom/typescript_s030']; // No directory browsing
|
|
197
|
+
mapping['S033'] = ['custom/typescript_s033']; // Require SameSite cookie
|
|
198
|
+
mapping['S034'] = ['custom/typescript_s034']; // Require Host cookie prefix
|
|
199
|
+
mapping['S035'] = ['custom/typescript_s035']; // Cookie specific path
|
|
200
|
+
mapping['S036'] = ['custom/typescript_s036']; // No unsafe file include
|
|
201
|
+
mapping['S037'] = ['custom/typescript_s037']; // Require anti cache headers
|
|
202
|
+
mapping['S038'] = ['custom/typescript_s038']; // No version disclosure
|
|
203
|
+
mapping['S039'] = ['custom/typescript_s039']; // No session token in URL
|
|
204
|
+
mapping['S041'] = ['custom/typescript_s041']; // Require session invalidate on logout
|
|
205
|
+
mapping['S042'] = ['custom/typescript_s042']; // Require periodic reauthentication
|
|
206
|
+
mapping['S043'] = ['custom/typescript_s043']; // Terminate sessions on password change
|
|
207
|
+
mapping['S044'] = ['custom/typescript_s044']; // Require full session for sensitive ops
|
|
208
|
+
mapping['S045'] = ['custom/typescript_s045']; // Anti automation controls
|
|
209
|
+
mapping['S046'] = ['custom/typescript_s046']; // Secure notification on auth change
|
|
210
|
+
mapping['S048'] = ['custom/typescript_s048']; // Password credential recovery
|
|
211
|
+
mapping['S050'] = ['custom/typescript_s050']; // Session token weak hash
|
|
212
|
+
mapping['S052'] = ['custom/typescript_s052']; // Secure random authentication code
|
|
213
|
+
mapping['S054'] = ['custom/typescript_s054']; // Verification default account
|
|
214
|
+
mapping['S057'] = ['custom/typescript_s057']; // UTC logging
|
|
215
|
+
mapping['S058'] = ['custom/typescript_s058']; // No SSRF
|
|
216
|
+
|
|
217
|
+
return mapping;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get ESLint rules for SunLint rule ID
|
|
222
|
+
* Following Rule C006: Verb-noun naming
|
|
223
|
+
*/
|
|
224
|
+
getEslintRulesForSunLintRule(sunlintRuleId) {
|
|
225
|
+
return this.sunlintToEslintMapping[sunlintRuleId] || [];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get SunLint rule for ESLint rule ID
|
|
230
|
+
* Following Rule C006: Verb-noun naming
|
|
231
|
+
*/
|
|
232
|
+
getSunLintRuleForEslintRule(eslintRuleId) {
|
|
233
|
+
return this.eslintToSunlintMapping[eslintRuleId] || eslintRuleId;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get all supported SunLint rules
|
|
238
|
+
* Following Rule C006: Verb-noun naming
|
|
239
|
+
*/
|
|
240
|
+
getSupportedSunLintRules() {
|
|
241
|
+
return Object.keys(this.sunlintToEslintMapping);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get all supported ESLint rules
|
|
246
|
+
* Following Rule C006: Verb-noun naming
|
|
247
|
+
*/
|
|
248
|
+
getSupportedEslintRules() {
|
|
249
|
+
return Object.keys(this.eslintToSunlintMapping);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check if SunLint rule is supported by ESLint
|
|
254
|
+
* Following Rule C006: Verb-noun naming
|
|
255
|
+
*/
|
|
256
|
+
isSunLintRuleSupportedByEslint(sunlintRuleId) {
|
|
257
|
+
return this.sunlintToEslintMapping.hasOwnProperty(sunlintRuleId);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get rule description for SunLint rule
|
|
262
|
+
* Following Rule C015: Use domain language
|
|
263
|
+
*/
|
|
264
|
+
getSunLintRuleDescription(sunlintRuleId) {
|
|
265
|
+
const descriptions = {
|
|
266
|
+
'C005': 'Each function should do only one thing',
|
|
267
|
+
'C006': 'Function names should be verb-noun',
|
|
268
|
+
'C014': 'Use Dependency Injection instead of direct new',
|
|
269
|
+
'C015': 'Use domain language in class/function names',
|
|
270
|
+
'C019': 'Do not use error level logging for non-critical errors',
|
|
271
|
+
'C031': 'Data validation logic should be separate',
|
|
272
|
+
'C032': 'No external API calls in constructor or static block',
|
|
273
|
+
'C033': 'Separate processing logic and data query in service layer',
|
|
274
|
+
'C034': 'Limit direct access to global state in domain logic',
|
|
275
|
+
'C035': 'When handling errors, log full relevant information',
|
|
276
|
+
'C037': 'API handlers should return standard response objects',
|
|
277
|
+
'C038': 'Avoid logic dependent on file/module loading order',
|
|
278
|
+
'C040': 'Do not scatter validation logic across multiple classes',
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
return descriptions[sunlintRuleId] || 'No description available';
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get rule category for SunLint rule
|
|
286
|
+
* Following Rule C015: Use domain language
|
|
287
|
+
*/
|
|
288
|
+
getSunLintRuleCategory(sunlintRuleId) {
|
|
289
|
+
const categories = {
|
|
290
|
+
'C005': 'quality',
|
|
291
|
+
'C006': 'naming',
|
|
292
|
+
'C014': 'architecture',
|
|
293
|
+
'C015': 'naming',
|
|
294
|
+
'C019': 'logging',
|
|
295
|
+
'C031': 'validation',
|
|
296
|
+
'C032': 'architecture',
|
|
297
|
+
'C033': 'architecture',
|
|
298
|
+
'C034': 'architecture',
|
|
299
|
+
'C035': 'logging',
|
|
300
|
+
'C037': 'api',
|
|
301
|
+
'C038': 'architecture',
|
|
302
|
+
'C040': 'validation',
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
return categories[sunlintRuleId] || 'other';
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = RuleMappingService;
|