@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,204 @@
|
|
|
1
|
+
# Rule Responsibility Matrix
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This document defines clear responsibilities between ESLint and SunLint to avoid duplication and maximize efficiency.
|
|
5
|
+
|
|
6
|
+
## Current Rule Distribution
|
|
7
|
+
|
|
8
|
+
### ESLint Custom Rules (29 rules)
|
|
9
|
+
**Primary Responsibilities:**
|
|
10
|
+
- ✅ Syntactic/structural checks
|
|
11
|
+
- ✅ IDE integration & fast feedback
|
|
12
|
+
- ✅ Standard coding conventions
|
|
13
|
+
- ✅ TypeScript-specific features
|
|
14
|
+
|
|
15
|
+
| Rule ID | Name | Type | Rationale |
|
|
16
|
+
|---------|------|------|-----------|
|
|
17
|
+
| C002 | no-duplicate-code | Structural | AST-based duplicate detection |
|
|
18
|
+
| C003 | no-vague-abbreviations | Naming | Simple naming convention |
|
|
19
|
+
| C006 | function-name-verb-noun | Naming | **ACTIVE** - Simple naming check |
|
|
20
|
+
| C008 | declare-variables-near-usage | Structural | Scope analysis |
|
|
21
|
+
| C010 | limit-block-nesting | Structural | Nesting depth check |
|
|
22
|
+
| C013 | no-dead-code | Structural | Dead code detection |
|
|
23
|
+
| C014 | abstract-dependency-preferred | Structural | DI pattern detection |
|
|
24
|
+
| C017 | limit-constructor-logic | Structural | Constructor complexity |
|
|
25
|
+
| C018 | no-generic-throw | Structural | Error handling pattern |
|
|
26
|
+
| C023 | no-duplicate-variable-name | Structural | Variable naming |
|
|
27
|
+
| C024 | no-hardcode-constants | Structural | Constant extraction |
|
|
28
|
+
| C027 | limit-function-nesting | Structural | Function nesting |
|
|
29
|
+
| C028 | no-silent-catch | Structural | **DEPRECATED** - Use SunLint C029 |
|
|
30
|
+
| C030 | use-custom-error-classes | Structural | Error class pattern |
|
|
31
|
+
| C034 | no-implicit-return | Structural | Return statement check |
|
|
32
|
+
| C035 | no-empty-catch | Structural | Empty catch detection |
|
|
33
|
+
| C037 | error-handler-log-input | Structural | Error logging pattern |
|
|
34
|
+
| C041 | no-config-inline | Structural | Configuration separation |
|
|
35
|
+
| C042 | boolean-name-prefix | Naming | Boolean naming convention |
|
|
36
|
+
| C043 | no-console-or-print | Structural | Console usage detection |
|
|
37
|
+
| C047 | no-duplicate-retry-logic | Structural | Retry pattern detection |
|
|
38
|
+
| C048 | no-var-declaration | Structural | Variable declaration |
|
|
39
|
+
| C076 | one-assert-per-test | Test | Test assertion pattern |
|
|
40
|
+
| T002 | interface-prefix-i | TypeScript | Interface naming |
|
|
41
|
+
| T003 | ts-ignore-reason | TypeScript | TypeScript ignore usage |
|
|
42
|
+
| T004 | interface-public-only | TypeScript | Interface structure |
|
|
43
|
+
| T007 | no-fn-in-constructor | TypeScript | Constructor pattern |
|
|
44
|
+
| T011 | no-real-time-dependency | Test | Test isolation |
|
|
45
|
+
| T019 | no-empty-type | TypeScript | Type definition |
|
|
46
|
+
| T025 | no-nested-union-tuple | TypeScript | Type complexity |
|
|
47
|
+
| T026 | limit-nested-generics | TypeScript | Generic complexity |
|
|
48
|
+
|
|
49
|
+
### SunLint Rules (4 rules)
|
|
50
|
+
**Primary Responsibilities:**
|
|
51
|
+
- ✅ Complex semantic analysis
|
|
52
|
+
- ✅ Cross-file/project analysis
|
|
53
|
+
- ✅ Performance-critical batch processing
|
|
54
|
+
- ✅ Business rule logic
|
|
55
|
+
|
|
56
|
+
| Rule ID | Name | Type | Rationale |
|
|
57
|
+
|---------|------|------|-----------|
|
|
58
|
+
| C006 | function_naming | Naming | **DISABLED** - Use ESLint version |
|
|
59
|
+
| C019 | log_level_usage | Semantic | **ACTIVE** - Complex log context analysis |
|
|
60
|
+
| C029 | catch_block_logging | Semantic | **ACTIVE** - Enhanced error context analysis |
|
|
61
|
+
| C031 | validation_separation | Architectural | **ACTIVE** - Cross-function validation pattern |
|
|
62
|
+
|
|
63
|
+
## Rule Overlap Resolution
|
|
64
|
+
|
|
65
|
+
### ✅ Resolved Overlaps
|
|
66
|
+
|
|
67
|
+
#### C006 - Function Naming
|
|
68
|
+
- **Decision**: Use ESLint version
|
|
69
|
+
- **Rationale**: Simple naming check, better IDE integration
|
|
70
|
+
- **Action**: SunLint C006 disabled in config
|
|
71
|
+
|
|
72
|
+
#### C028/C029 - Catch Block Logging
|
|
73
|
+
- **Decision**: Use SunLint C029
|
|
74
|
+
- **Rationale**: More sophisticated error context analysis
|
|
75
|
+
- **Action**: ESLint C028 should be deprecated in favor of SunLint C029
|
|
76
|
+
|
|
77
|
+
### 🔄 Planned Enhancements
|
|
78
|
+
|
|
79
|
+
#### C029 - Enhanced Catch Block Logging
|
|
80
|
+
Current SunLint C029 should be enhanced to fully replace ESLint C028:
|
|
81
|
+
|
|
82
|
+
**ESLint C028 capabilities:**
|
|
83
|
+
- Detects silent catch blocks
|
|
84
|
+
- Basic error logging requirements
|
|
85
|
+
|
|
86
|
+
**SunLint C029 enhancements needed:**
|
|
87
|
+
- All C028 functionality
|
|
88
|
+
- Context-aware error logging
|
|
89
|
+
- Stack trace preservation analysis
|
|
90
|
+
- Error correlation tracking
|
|
91
|
+
|
|
92
|
+
## Integration Strategy
|
|
93
|
+
|
|
94
|
+
### Phase 1: Current State (Implemented)
|
|
95
|
+
```json
|
|
96
|
+
// .eslintrc.cjs - ESLint handles most rules
|
|
97
|
+
{
|
|
98
|
+
"rules": {
|
|
99
|
+
"custom/c006": "warn", // Active in ESLint
|
|
100
|
+
"custom/c029": "warn", // Will be deprecated
|
|
101
|
+
// ... other ESLint rules
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// .sunlint.json - SunLint handles specialized rules
|
|
106
|
+
{
|
|
107
|
+
"rules": {
|
|
108
|
+
"C006": "off", // Disabled - use ESLint
|
|
109
|
+
"C019": true, // Active - unique to SunLint
|
|
110
|
+
"C029": "error", // Active - enhanced version
|
|
111
|
+
"C031": true // Active - unique to SunLint
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Phase 2: ESLint Adapter (Planned)
|
|
117
|
+
```json
|
|
118
|
+
// .sunlint.json - Unified configuration
|
|
119
|
+
{
|
|
120
|
+
"rules": {
|
|
121
|
+
"C019": true,
|
|
122
|
+
"C029": true,
|
|
123
|
+
"C031": true,
|
|
124
|
+
// ESLint rules via adapter
|
|
125
|
+
"eslint:custom/c003": true,
|
|
126
|
+
"eslint:custom/c006": true,
|
|
127
|
+
"eslint:custom/c042": true
|
|
128
|
+
},
|
|
129
|
+
"eslintAdapter": {
|
|
130
|
+
"configPath": ".eslintrc.cjs",
|
|
131
|
+
"rules": ["custom/c003", "custom/c006", "custom/c042"]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Migration Guidelines
|
|
137
|
+
|
|
138
|
+
### Rules to Keep in ESLint
|
|
139
|
+
**Criteria:**
|
|
140
|
+
- Simple syntactic checks
|
|
141
|
+
- IDE integration critical
|
|
142
|
+
- TypeScript-specific features
|
|
143
|
+
- Standard conventions
|
|
144
|
+
|
|
145
|
+
**Examples:**
|
|
146
|
+
- C003 (Variable naming)
|
|
147
|
+
- C042 (Boolean naming)
|
|
148
|
+
- T002 (Interface prefix)
|
|
149
|
+
- T003 (TypeScript ignore)
|
|
150
|
+
|
|
151
|
+
### Rules to Migrate to SunLint
|
|
152
|
+
**Criteria:**
|
|
153
|
+
- Complex semantic analysis
|
|
154
|
+
- Cross-file analysis needed
|
|
155
|
+
- Performance-critical
|
|
156
|
+
- Business rule logic
|
|
157
|
+
|
|
158
|
+
**Candidates:**
|
|
159
|
+
- C014 (Dependency Injection) - Cross-file analysis
|
|
160
|
+
- C034 (Data fetching separation) - Service layer analysis
|
|
161
|
+
- C040 (File execution order) - Project-level analysis
|
|
162
|
+
|
|
163
|
+
### Rules to Enhance in SunLint
|
|
164
|
+
**Current:**
|
|
165
|
+
- C029 (Catch block logging) - Enhance to replace C028
|
|
166
|
+
- C031 (Validation separation) - Add cross-file validation
|
|
167
|
+
|
|
168
|
+
## Testing Strategy
|
|
169
|
+
|
|
170
|
+
### Rule Compatibility Testing
|
|
171
|
+
1. **Overlap Testing**: Ensure no conflicting reports
|
|
172
|
+
2. **Performance Testing**: Compare combined vs individual execution
|
|
173
|
+
3. **Accuracy Testing**: Validate rule logic equivalence
|
|
174
|
+
|
|
175
|
+
### Integration Testing
|
|
176
|
+
1. **CI/CD Pipeline**: Test unified reporting
|
|
177
|
+
2. **IDE Integration**: Verify ESLint feedback still works
|
|
178
|
+
3. **Configuration**: Test rule enable/disable scenarios
|
|
179
|
+
|
|
180
|
+
## Monitoring & Maintenance
|
|
181
|
+
|
|
182
|
+
### Performance Metrics
|
|
183
|
+
- Combined analysis time
|
|
184
|
+
- Memory usage comparison
|
|
185
|
+
- CI/CD pipeline impact
|
|
186
|
+
|
|
187
|
+
### Quality Metrics
|
|
188
|
+
- Rule coverage completeness
|
|
189
|
+
- False positive rates
|
|
190
|
+
- Developer satisfaction
|
|
191
|
+
|
|
192
|
+
### Process Metrics
|
|
193
|
+
- Configuration complexity
|
|
194
|
+
- Maintenance overhead
|
|
195
|
+
- Team adoption rate
|
|
196
|
+
|
|
197
|
+
## Decision Log
|
|
198
|
+
|
|
199
|
+
| Date | Decision | Rationale |
|
|
200
|
+
|------|----------|-----------|
|
|
201
|
+
| 2024-01-XX | Disable SunLint C006 | ESLint version sufficient, better IDE integration |
|
|
202
|
+
| 2024-01-XX | Keep SunLint C019 | Unique semantic analysis capability |
|
|
203
|
+
| 2024-01-XX | Enhance SunLint C029 | Replace ESLint C028 with better analysis |
|
|
204
|
+
| 2024-01-XX | Keep SunLint C031 | Unique architectural analysis |
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// ESLint Legacy Configuration for SunLint (ESLint v8.x compatibility)
|
|
2
|
+
// Following Rule C005: Single responsibility - ESLint configuration
|
|
3
|
+
module.exports = {
|
|
4
|
+
env: {
|
|
5
|
+
es2022: true,
|
|
6
|
+
node: true,
|
|
7
|
+
browser: true
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
parser: '@typescript-eslint/parser',
|
|
11
|
+
|
|
12
|
+
parserOptions: {
|
|
13
|
+
ecmaVersion: 2022,
|
|
14
|
+
sourceType: 'module',
|
|
15
|
+
project: 'eslint-integration/tsconfig.json'
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
plugins: [
|
|
19
|
+
'custom',
|
|
20
|
+
'@typescript-eslint'
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
globals: {
|
|
24
|
+
console: 'readonly',
|
|
25
|
+
process: 'readonly',
|
|
26
|
+
eval: 'readonly'
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
rules: {
|
|
30
|
+
// Rule C019: No console.error for non-critical errors
|
|
31
|
+
'no-console': ['warn', { allow: ['warn', 'log'] }],
|
|
32
|
+
|
|
33
|
+
// Code quality rules
|
|
34
|
+
'no-unused-vars': 'warn',
|
|
35
|
+
'prefer-const': 'warn',
|
|
36
|
+
'no-var': 'error',
|
|
37
|
+
'no-undef': 'warn',
|
|
38
|
+
|
|
39
|
+
// Rule C005: Single responsibility principle
|
|
40
|
+
'max-lines-per-function': ['warn', { max: 50 }],
|
|
41
|
+
'complexity': ['warn', { max: 10 }],
|
|
42
|
+
|
|
43
|
+
// Rule C014: Avoid direct new instantiation patterns
|
|
44
|
+
'no-new': 'warn',
|
|
45
|
+
|
|
46
|
+
// Security and best practices
|
|
47
|
+
'no-eval': 'error',
|
|
48
|
+
'no-implied-eval': 'error',
|
|
49
|
+
'no-new-func': 'error',
|
|
50
|
+
'eqeqeq': 'error',
|
|
51
|
+
'curly': 'error',
|
|
52
|
+
|
|
53
|
+
// Security rules from custom plugin (dynamic loading based on category)
|
|
54
|
+
'custom/typescript_s003': 'off', // Will be enabled dynamically
|
|
55
|
+
'custom/typescript_s005': 'off', // Will be enabled dynamically
|
|
56
|
+
'custom/typescript_s006': 'off',
|
|
57
|
+
'custom/typescript_s008': 'off',
|
|
58
|
+
'custom/typescript_s009': 'off',
|
|
59
|
+
'custom/typescript_s010': 'off',
|
|
60
|
+
'custom/typescript_s011': 'off',
|
|
61
|
+
'custom/typescript_s012': 'off',
|
|
62
|
+
'custom/typescript_s014': 'off',
|
|
63
|
+
'custom/typescript_s015': 'off',
|
|
64
|
+
'custom/typescript_s016': 'off',
|
|
65
|
+
'custom/typescript_s017': 'off',
|
|
66
|
+
'custom/typescript_s018': 'off',
|
|
67
|
+
'custom/typescript_s019': 'off',
|
|
68
|
+
'custom/typescript_s020': 'off',
|
|
69
|
+
'custom/typescript_s022': 'off',
|
|
70
|
+
'custom/typescript_s023': 'off',
|
|
71
|
+
'custom/typescript_s025': 'off',
|
|
72
|
+
'custom/typescript_s026': 'off',
|
|
73
|
+
'custom/typescript_s027': 'off',
|
|
74
|
+
'custom/typescript_s029': 'off',
|
|
75
|
+
'custom/typescript_s030': 'off',
|
|
76
|
+
'custom/typescript_s033': 'off',
|
|
77
|
+
'custom/typescript_s034': 'off',
|
|
78
|
+
'custom/typescript_s035': 'off',
|
|
79
|
+
'custom/typescript_s036': 'off',
|
|
80
|
+
'custom/typescript_s037': 'off',
|
|
81
|
+
'custom/typescript_s038': 'off',
|
|
82
|
+
'custom/typescript_s039': 'off',
|
|
83
|
+
'custom/typescript_s041': 'off',
|
|
84
|
+
'custom/typescript_s042': 'off',
|
|
85
|
+
'custom/typescript_s043': 'off',
|
|
86
|
+
'custom/typescript_s044': 'off',
|
|
87
|
+
'custom/typescript_s045': 'off',
|
|
88
|
+
'custom/typescript_s046': 'off',
|
|
89
|
+
'custom/typescript_s047': 'off',
|
|
90
|
+
'custom/typescript_s048': 'off',
|
|
91
|
+
'custom/typescript_s050': 'off',
|
|
92
|
+
'custom/typescript_s052': 'off',
|
|
93
|
+
'custom/typescript_s054': 'off',
|
|
94
|
+
'custom/typescript_s055': 'off',
|
|
95
|
+
'custom/typescript_s057': 'off',
|
|
96
|
+
'custom/typescript_s058': 'off'
|
|
97
|
+
}
|
|
98
|
+
};
|
|
@@ -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,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom ESLint rule for: C002 – Không để trùng lặp code > 10 dòng
|
|
3
|
+
* Rule ID: custom/c002
|
|
4
|
+
* Purpose: Detect duplicate code blocks longer than 10 lines to maintain DRY principle
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "suggestion",
|
|
10
|
+
docs: {
|
|
11
|
+
description: "Detect duplicate code blocks longer than 10 lines",
|
|
12
|
+
recommended: false
|
|
13
|
+
},
|
|
14
|
+
schema: [
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
minLines: {
|
|
19
|
+
type: "number",
|
|
20
|
+
minimum: 1,
|
|
21
|
+
default: 10
|
|
22
|
+
},
|
|
23
|
+
ignoreComments: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
default: true
|
|
26
|
+
},
|
|
27
|
+
ignoreWhitespace: {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
default: true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
messages: {
|
|
36
|
+
duplicateCode: "Duplicate code block found ({{lines}} lines). Consider extracting into a shared function or module."
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
create(context) {
|
|
40
|
+
const options = context.options[0] || {};
|
|
41
|
+
const minLines = options.minLines || 10;
|
|
42
|
+
const ignoreComments = options.ignoreComments !== false;
|
|
43
|
+
const ignoreWhitespace = options.ignoreWhitespace !== false;
|
|
44
|
+
|
|
45
|
+
const sourceCode = context.getSourceCode();
|
|
46
|
+
const codeBlocks = new Map();
|
|
47
|
+
|
|
48
|
+
function normalizeCode(text) {
|
|
49
|
+
let normalized = text;
|
|
50
|
+
|
|
51
|
+
if (ignoreWhitespace) {
|
|
52
|
+
// Remove extra whitespace and normalize spacing
|
|
53
|
+
normalized = normalized
|
|
54
|
+
.replace(/\s+/g, ' ')
|
|
55
|
+
.trim();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (ignoreComments) {
|
|
59
|
+
// Remove single line comments
|
|
60
|
+
normalized = normalized.replace(/\/\/.*$/gm, '');
|
|
61
|
+
// Remove multi-line comments
|
|
62
|
+
normalized = normalized.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return normalized;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getCodeLines(node) {
|
|
69
|
+
const startLine = node.loc.start.line;
|
|
70
|
+
const endLine = node.loc.end.line;
|
|
71
|
+
const lines = [];
|
|
72
|
+
|
|
73
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
74
|
+
const line = sourceCode.lines[i - 1];
|
|
75
|
+
if (line !== undefined) {
|
|
76
|
+
lines.push(line);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function analyzeNode(node) {
|
|
84
|
+
const lines = getCodeLines(node);
|
|
85
|
+
|
|
86
|
+
if (lines.length < minLines) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const codeText = lines.join('\n');
|
|
91
|
+
const normalizedCode = normalizeCode(codeText);
|
|
92
|
+
|
|
93
|
+
// Skip if normalized code is too short after cleaning
|
|
94
|
+
if (normalizedCode.length < 20) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const codeHash = normalizedCode;
|
|
99
|
+
|
|
100
|
+
if (codeBlocks.has(codeHash)) {
|
|
101
|
+
const existingNodes = codeBlocks.get(codeHash);
|
|
102
|
+
|
|
103
|
+
// Report duplicate for current node
|
|
104
|
+
context.report({
|
|
105
|
+
node,
|
|
106
|
+
messageId: "duplicateCode",
|
|
107
|
+
data: {
|
|
108
|
+
lines: lines.length
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Also report the first occurrence if not already reported
|
|
113
|
+
existingNodes.forEach(existingNode => {
|
|
114
|
+
if (!existingNode.reported) {
|
|
115
|
+
context.report({
|
|
116
|
+
node: existingNode.node,
|
|
117
|
+
messageId: "duplicateCode",
|
|
118
|
+
data: {
|
|
119
|
+
lines: existingNode.lines
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
existingNode.reported = true;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
existingNodes.push({ node, lines: lines.length, reported: true });
|
|
127
|
+
} else {
|
|
128
|
+
codeBlocks.set(codeHash, [{ node, lines: lines.length, reported: false }]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
// Check function declarations
|
|
134
|
+
FunctionDeclaration(node) {
|
|
135
|
+
if (node.body) {
|
|
136
|
+
analyzeNode(node.body);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// Check function expressions
|
|
141
|
+
FunctionExpression(node) {
|
|
142
|
+
if (node.body) {
|
|
143
|
+
analyzeNode(node.body);
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
// Check arrow functions
|
|
148
|
+
ArrowFunctionExpression(node) {
|
|
149
|
+
if (node.body && node.body.type === 'BlockStatement') {
|
|
150
|
+
analyzeNode(node.body);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
// Check method definitions
|
|
155
|
+
MethodDefinition(node) {
|
|
156
|
+
if (node.value && node.value.body) {
|
|
157
|
+
analyzeNode(node.value.body);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
// Check block statements (general code blocks)
|
|
162
|
+
BlockStatement(node) {
|
|
163
|
+
// Only analyze block statements that are not function bodies
|
|
164
|
+
const parent = node.parent;
|
|
165
|
+
if (parent &&
|
|
166
|
+
parent.type !== 'FunctionDeclaration' &&
|
|
167
|
+
parent.type !== 'FunctionExpression' &&
|
|
168
|
+
parent.type !== 'ArrowFunctionExpression' &&
|
|
169
|
+
parent.type !== 'MethodDefinition') {
|
|
170
|
+
analyzeNode(node);
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// Check if/else statements
|
|
175
|
+
IfStatement(node) {
|
|
176
|
+
if (node.consequent && node.consequent.type === 'BlockStatement') {
|
|
177
|
+
analyzeNode(node.consequent);
|
|
178
|
+
}
|
|
179
|
+
if (node.alternate && node.alternate.type === 'BlockStatement') {
|
|
180
|
+
analyzeNode(node.alternate);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
// Check loop bodies
|
|
185
|
+
ForStatement(node) {
|
|
186
|
+
if (node.body && node.body.type === 'BlockStatement') {
|
|
187
|
+
analyzeNode(node.body);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
WhileStatement(node) {
|
|
192
|
+
if (node.body && node.body.type === 'BlockStatement') {
|
|
193
|
+
analyzeNode(node.body);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
DoWhileStatement(node) {
|
|
198
|
+
if (node.body && node.body.type === 'BlockStatement') {
|
|
199
|
+
analyzeNode(node.body);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
};
|