@sun-asterisk/sunlint 1.2.1 → 1.2.2

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.
Files changed (77) hide show
  1. package/config/rule-analysis-strategies.js +18 -2
  2. package/engines/eslint-engine.js +9 -11
  3. package/engines/heuristic-engine.js +55 -31
  4. package/package.json +2 -1
  5. package/rules/README.md +252 -0
  6. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  7. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  8. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  9. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  10. package/rules/common/C006_function_naming/analyzer.js +504 -0
  11. package/rules/common/C006_function_naming/config.json +86 -0
  12. package/rules/common/C006_function_naming/smart-analyzer.js +503 -0
  13. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  14. package/rules/common/C012_command_query_separation/analyzer.js +481 -0
  15. package/rules/common/C012_command_query_separation/ast-analyzer.js +495 -0
  16. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  17. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  18. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  19. package/rules/common/C019_log_level_usage/analyzer.js +362 -0
  20. package/rules/common/C019_log_level_usage/config.json +121 -0
  21. package/rules/common/C029_catch_block_logging/analyzer-backup.js +426 -0
  22. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +130 -0
  23. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +487 -0
  24. package/rules/common/C029_catch_block_logging/analyzer-simple.js +110 -0
  25. package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +755 -0
  26. package/rules/common/C029_catch_block_logging/analyzer.js +129 -0
  27. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +441 -0
  28. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +127 -0
  29. package/rules/common/C029_catch_block_logging/ast-analyzer.js +133 -0
  30. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +408 -0
  31. package/rules/common/C029_catch_block_logging/config.json +59 -0
  32. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +454 -0
  33. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +700 -0
  34. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +568 -0
  35. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +459 -0
  36. package/rules/common/C031_validation_separation/analyzer.js +186 -0
  37. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  38. package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +296 -0
  39. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  40. package/rules/common/C043_no_console_or_print/analyzer.js +431 -0
  41. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +590 -0
  42. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  43. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  44. package/rules/docs/C002_no_duplicate_code.md +57 -0
  45. package/rules/docs/C031_validation_separation.md +72 -0
  46. package/rules/index.js +155 -0
  47. package/rules/migration/converter.js +385 -0
  48. package/rules/migration/mapping.json +164 -0
  49. package/rules/parser/constants.js +31 -0
  50. package/rules/parser/file-config.js +80 -0
  51. package/rules/parser/rule-parser-simple.js +305 -0
  52. package/rules/parser/rule-parser.js +527 -0
  53. package/rules/security/S015_insecure_tls_certificate/analyzer.js +150 -0
  54. package/rules/security/S015_insecure_tls_certificate/ast-analyzer.js +237 -0
  55. package/rules/security/S023_no_json_injection/analyzer.js +278 -0
  56. package/rules/security/S023_no_json_injection/ast-analyzer.js +359 -0
  57. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  58. package/rules/security/S026_json_schema_validation/config.json +27 -0
  59. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +436 -0
  60. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  61. package/rules/security/S029_csrf_protection/analyzer.js +330 -0
  62. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  63. package/rules/universal/C010/generic.js +0 -0
  64. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  65. package/rules/utils/ast-utils.js +191 -0
  66. package/rules/utils/base-analyzer.js +98 -0
  67. package/rules/utils/pattern-matchers.js +239 -0
  68. package/rules/utils/rule-helpers.js +264 -0
  69. package/rules/utils/severity-constants.js +93 -0
  70. package/scripts/generate_insights.js +188 -0
  71. package/scripts/merge-reports.js +0 -424
  72. package/scripts/test-scripts/README.md +0 -22
  73. package/scripts/test-scripts/test-c041-comparison.js +0 -114
  74. package/scripts/test-scripts/test-c041-eslint.js +0 -67
  75. package/scripts/test-scripts/test-eslint-rules.js +0 -146
  76. package/scripts/test-scripts/test-real-world.js +0 -44
  77. package/scripts/test-scripts/test-rules-on-real-projects.js +0 -86
@@ -0,0 +1,305 @@
1
+ const { RuleParser } = require("./rule-parser")
2
+ const fs = require("fs")
3
+ const path = require("path")
4
+
5
+ /**
6
+ * Simple Rule Parser - Lightweight wrapper around RuleParser
7
+ * Provides simplified interface for basic rule information extraction
8
+ * Focused on English rules (*-en.md) with filtering capabilities
9
+ */
10
+ class SimpleRuleParser {
11
+ constructor() {
12
+ // Use existing RuleParser as core engine, but disable migrate mode
13
+ this.coreParser = new RuleParser(false)
14
+ this.rulesCache = new Map() // Cache parsed rules by file
15
+ }
16
+
17
+ /**
18
+ * Parse a specific markdown file and extract basic rule information
19
+ * @param {string} filePath - Path to the markdown file
20
+ * @returns {Array} Array of simplified rule objects
21
+ */
22
+ parseRuleFile(filePath) {
23
+ try {
24
+ // Check cache first
25
+ if (this.rulesCache.has(filePath)) {
26
+ return this.rulesCache.get(filePath)
27
+ }
28
+
29
+ // Use default config for parsing
30
+ const defaultConfig = {
31
+ category: "Common",
32
+ language: "All languages",
33
+ framework: "All"
34
+ }
35
+
36
+ // Parse using core parser
37
+ const fullRules = this.coreParser.parseMarkdownFile(filePath, defaultConfig)
38
+
39
+ // Convert to simplified format
40
+ const simplifiedRules = fullRules.map(rule => this.simplifyRule(rule))
41
+
42
+ // Cache the result
43
+ this.rulesCache.set(filePath, simplifiedRules)
44
+
45
+ return simplifiedRules
46
+ } catch (error) {
47
+ console.error(`Error parsing file ${filePath}:`, error.message)
48
+ return []
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Parse all English rule files from rules directory
54
+ * @param {string} rulesDir - Path to rules directory (default: relative to this script)
55
+ * @returns {Array} Array of all simplified rule objects
56
+ */
57
+ parseAllRules(rulesDir = null) {
58
+ try {
59
+ if (!rulesDir) {
60
+ rulesDir = path.join(__dirname, "..", "..", "origin-rules")
61
+ }
62
+
63
+ if (!fs.existsSync(rulesDir)) {
64
+ throw new Error(`Rules directory not found: ${rulesDir}`)
65
+ }
66
+
67
+ const allRules = []
68
+ const files = fs.readdirSync(rulesDir)
69
+
70
+ // Find all English rule files (*-en.md)
71
+ const englishRuleFiles = files.filter(file =>
72
+ file.endsWith('-en.md') && file !== 'README-en.md'
73
+ )
74
+
75
+ console.log(`Found ${englishRuleFiles.length} English rule files: ${englishRuleFiles.join(', ')}`)
76
+
77
+ for (const file of englishRuleFiles) {
78
+ const filePath = path.join(rulesDir, file)
79
+ const rules = this.parseRuleFile(filePath)
80
+ allRules.push(...rules)
81
+ }
82
+
83
+ return allRules
84
+ } catch (error) {
85
+ console.error("Error parsing all rules:", error.message)
86
+ return []
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Filter rules by various criteria
92
+ * @param {Array} rules - Array of rules to filter
93
+ * @param {Object} filters - Filter criteria
94
+ * @param {string} filters.ruleId - Specific rule ID (e.g., "C001")
95
+ * @param {string|Array} filters.principles - Principle(s) to match (e.g., "Quality", ["Security", "Performance"])
96
+ * @param {string} filters.framework - Framework to match (e.g., "Android")
97
+ * @param {string} filters.language - Language to match (e.g., "Java")
98
+ * @param {string} filters.minVersion - Minimum version (e.g., "1.0")
99
+ * @param {string} filters.status - Status to match (default: "activated")
100
+ * @returns {Array} Filtered rules
101
+ */
102
+ filterRules(rules, filters = {}) {
103
+ try {
104
+ let filteredRules = [...rules]
105
+
106
+ // Default filters: version >= 1.0 and status = activated
107
+ const {
108
+ ruleId,
109
+ principles,
110
+ framework,
111
+ language,
112
+ minVersion = "1.0",
113
+ status // No default for status when looking for specific ruleId
114
+ } = filters
115
+
116
+ // Filter by specific rule ID first (no status filter needed)
117
+ if (ruleId) {
118
+ filteredRules = filteredRules.filter(rule =>
119
+ rule.id && rule.id.toLowerCase() === ruleId.toLowerCase()
120
+ )
121
+ // If searching by ID, return early (no other filters needed)
122
+ return filteredRules
123
+ }
124
+
125
+ // Filter by status (default: activated) only when not searching by ID
126
+ const defaultStatus = status || "activated"
127
+ filteredRules = filteredRules.filter(rule =>
128
+ rule.status && rule.status.toLowerCase() === defaultStatus.toLowerCase()
129
+ )
130
+
131
+ // Filter by minimum version
132
+ if (minVersion) {
133
+ filteredRules = filteredRules.filter(rule =>
134
+ this.compareVersions(rule.version || "1.0", minVersion) >= 0
135
+ )
136
+ }
137
+
138
+ // Filter by principles
139
+ if (principles) {
140
+ const principlesArray = Array.isArray(principles) ? principles : [principles]
141
+ filteredRules = filteredRules.filter(rule => {
142
+ if (!rule.principles || rule.principles.length === 0) return false
143
+ return principlesArray.some(principle =>
144
+ rule.principles.some(rulePrinciple =>
145
+ rulePrinciple.toLowerCase().includes(principle.toLowerCase())
146
+ )
147
+ )
148
+ })
149
+ }
150
+
151
+ // Filter by framework
152
+ if (framework) {
153
+ filteredRules = filteredRules.filter(rule =>
154
+ rule.framework && rule.framework.toLowerCase().includes(framework.toLowerCase())
155
+ )
156
+ }
157
+
158
+ // Filter by language
159
+ if (language) {
160
+ filteredRules = filteredRules.filter(rule =>
161
+ rule.language && (
162
+ rule.language.toLowerCase().includes(language.toLowerCase()) ||
163
+ rule.language.toLowerCase().includes('all')
164
+ )
165
+ )
166
+ }
167
+
168
+ return filteredRules
169
+ } catch (error) {
170
+ console.error("Error filtering rules:", error.message)
171
+ return rules
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Get rules by principles (common use case)
177
+ * @param {string|Array} principles - Principle(s) to search for
178
+ * @param {string} rulesDir - Rules directory path
179
+ * @returns {Array} Rules matching the principles
180
+ */
181
+ getRulesByPrinciples(principles, rulesDir = null) {
182
+ const allRules = this.parseAllRules(rulesDir)
183
+ return this.filterRules(allRules, { principles })
184
+ }
185
+
186
+ /**
187
+ * Get rules for specific framework
188
+ * @param {string} framework - Framework name (e.g., "Android", "React")
189
+ * @param {string} rulesDir - Rules directory path
190
+ * @returns {Array} Rules for the framework
191
+ */
192
+ getRulesByFramework(framework, rulesDir = null) {
193
+ const allRules = this.parseAllRules(rulesDir)
194
+ return this.filterRules(allRules, { framework })
195
+ }
196
+
197
+ /**
198
+ * Get single rule by ID
199
+ * @param {string} ruleId - Rule ID (e.g., "C001")
200
+ * @param {string} rulesDir - Rules directory path
201
+ * @returns {Object|null} Rule object or null if not found
202
+ */
203
+ getRuleById(ruleId, rulesDir = null) {
204
+ try {
205
+ const allRules = this.parseAllRules(rulesDir)
206
+ const filtered = this.filterRules(allRules, { ruleId })
207
+ return filtered.length > 0 ? filtered[0] : null
208
+ } catch (error) {
209
+ console.error("Error in getRuleById:", error.message)
210
+ return null
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Compare version strings (supports x.y format)
216
+ * @param {string} version1 - First version
217
+ * @param {string} version2 - Second version
218
+ * @returns {number} -1 if version1 < version2, 0 if equal, 1 if version1 > version2
219
+ */
220
+ compareVersions(version1, version2) {
221
+ try {
222
+ const v1Parts = version1.split('.').map(Number)
223
+ const v2Parts = version2.split('.').map(Number)
224
+
225
+ const maxLength = Math.max(v1Parts.length, v2Parts.length)
226
+
227
+ for (let i = 0; i < maxLength; i++) {
228
+ const v1Part = v1Parts[i] || 0
229
+ const v2Part = v2Parts[i] || 0
230
+
231
+ if (v1Part < v2Part) return -1
232
+ if (v1Part > v2Part) return 1
233
+ }
234
+
235
+ return 0
236
+ } catch (error) {
237
+ console.warn(`Error comparing versions ${version1} and ${version2}:`, error.message)
238
+ return 0
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Convert full rule object to simplified format
244
+ * @param {Object} fullRule - Full rule object from RuleParser
245
+ * @returns {Object} Simplified rule object
246
+ */
247
+ simplifyRule(fullRule) {
248
+ return {
249
+ id: fullRule.id,
250
+ title: fullRule.title,
251
+ description: fullRule.description,
252
+ details: fullRule.details || [],
253
+ tools: fullRule.tools || [],
254
+ principles: fullRule.principles || [],
255
+ version: fullRule.version,
256
+ status: fullRule.status,
257
+ severity: fullRule.severity,
258
+ language: fullRule.language,
259
+ framework: fullRule.framework,
260
+ category: fullRule.category
261
+ // Exclude examples and configs for lightweight usage
262
+ }
263
+ }
264
+ }
265
+
266
+ // Factory functions for easy use (maintaining backward compatibility)
267
+ function parseRuleFile(filePath) {
268
+ const parser = new SimpleRuleParser()
269
+ return parser.parseRuleFile(filePath)
270
+ }
271
+
272
+ function parseAllRules(rulesDir = null) {
273
+ const parser = new SimpleRuleParser()
274
+ return parser.parseAllRules(rulesDir)
275
+ }
276
+
277
+ function filterRules(rules, filters = {}) {
278
+ const parser = new SimpleRuleParser()
279
+ return parser.filterRules(rules, filters)
280
+ }
281
+
282
+ function getRulesByPrinciples(principles, rulesDir = null) {
283
+ const parser = new SimpleRuleParser()
284
+ return parser.getRulesByPrinciples(principles, rulesDir)
285
+ }
286
+
287
+ function getRulesByFramework(framework, rulesDir = null) {
288
+ const parser = new SimpleRuleParser()
289
+ return parser.getRulesByFramework(framework, rulesDir)
290
+ }
291
+
292
+ function getRuleById(ruleId, rulesDir = null) {
293
+ const parser = new SimpleRuleParser()
294
+ return parser.getRuleById(ruleId, rulesDir)
295
+ }
296
+
297
+ module.exports = {
298
+ SimpleRuleParser,
299
+ parseRuleFile,
300
+ parseAllRules,
301
+ filterRules,
302
+ getRulesByPrinciples,
303
+ getRulesByFramework,
304
+ getRuleById
305
+ }