@sun-asterisk/sunlint 1.1.5 → 1.1.6

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.
@@ -745,7 +745,7 @@
745
745
  }
746
746
  },
747
747
  "metadata": {
748
- "version": "1.1.5",
748
+ "version": "1.1.6",
749
749
  "lastUpdated": "2025-07-24",
750
750
  "totalRules": 44,
751
751
  "qualityRules": 33,
@@ -66,22 +66,14 @@ class ESLintEngine extends AnalysisEngineInterface {
66
66
  // Check for ESLint dependencies first
67
67
  dependencyChecker.checkAndNotify('eslint');
68
68
 
69
- // Dynamically import ESLint
70
- const { ESLint } = await this.loadESLint();
69
+ // Store config for later use in analyze()
70
+ this.config = config;
71
+ this.eslint = null; // Initialize later in analyze() with project path
71
72
 
72
- // Initialize ESLint with base configuration (v9+ compatible)
73
- this.eslint = new ESLint({
74
- overrideConfigFile: null, // ESLint 9.x requires null instead of true
75
- overrideConfig: this.createBaseConfig(),
76
- fix: config?.fix || false,
77
- cache: config?.cache || false,
78
- cwd: process.cwd()
79
- });
80
-
81
73
  // Rule mapping already loaded in constructor
82
74
  if (this.verbose) {
83
75
  console.log(`🔧 [ESLintEngine] Initialize: Rule mapping size = ${this.ruleMapping.size}`);
84
- console.log(`🔧 ESLint engine initialized`);
76
+ console.log(`🔧 ESLint engine initialized (ESLint instance will be created per-project)`);
85
77
  }
86
78
 
87
79
  this.initialized = true;
@@ -116,6 +108,126 @@ class ESLintEngine extends AnalysisEngineInterface {
116
108
  }
117
109
  }
118
110
 
111
+ /**
112
+ * Check for ESLint config files in project
113
+ * Following Rule C006: Verb-noun naming
114
+ * @param {string} projectPath - Path to the project being analyzed
115
+ * @returns {Object} Config file detection results
116
+ */
117
+ detectESLintConfig(projectPath) {
118
+ const fs = require('fs');
119
+ const path = require('path');
120
+
121
+ const configFiles = {
122
+ flat: ['eslint.config.js', 'eslint.config.mjs'],
123
+ legacy: ['.eslintrc.js', '.eslintrc.json', '.eslintrc.yml', '.eslintrc.yaml', '.eslintrc'],
124
+ packageJson: 'package.json'
125
+ };
126
+
127
+ const results = {
128
+ hasFlatConfig: false,
129
+ hasLegacyConfig: false,
130
+ hasPackageConfig: false,
131
+ foundFiles: []
132
+ };
133
+
134
+ // Check for flat config files
135
+ for (const file of configFiles.flat) {
136
+ const filePath = path.join(projectPath, file);
137
+ if (fs.existsSync(filePath)) {
138
+ results.hasFlatConfig = true;
139
+ results.foundFiles.push(file);
140
+ }
141
+ }
142
+
143
+ // Check for legacy config files
144
+ for (const file of configFiles.legacy) {
145
+ const filePath = path.join(projectPath, file);
146
+ if (fs.existsSync(filePath)) {
147
+ results.hasLegacyConfig = true;
148
+ results.foundFiles.push(file);
149
+ }
150
+ }
151
+
152
+ // Check for package.json eslintConfig
153
+ const packagePath = path.join(projectPath, configFiles.packageJson);
154
+ if (fs.existsSync(packagePath)) {
155
+ try {
156
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
157
+ if (packageJson.eslintConfig) {
158
+ results.hasPackageConfig = true;
159
+ results.foundFiles.push('package.json (eslintConfig)');
160
+ }
161
+ } catch (error) {
162
+ // Ignore package.json parsing errors
163
+ }
164
+ }
165
+
166
+ return results;
167
+ }
168
+
169
+ /**
170
+ * Create ESLint instance with proper configuration
171
+ * Following Rule C006: Verb-noun naming
172
+ * @param {string} projectPath - Path to the project being analyzed
173
+ * @returns {Promise<Object>} Configured ESLint instance
174
+ */
175
+ async createESLintInstance(projectPath) {
176
+ try {
177
+ const { ESLint } = await this.loadESLint();
178
+
179
+ // Detect existing config
180
+ const configDetection = this.detectESLintConfig(projectPath);
181
+ console.log(`🔍 [ESLintEngine] Config detection for ${projectPath}:`, configDetection);
182
+
183
+ let eslintOptions;
184
+
185
+ if (configDetection.hasFlatConfig) {
186
+ // Use flat config (ESLint v9+ preferred)
187
+ eslintOptions = {
188
+ overrideConfigFile: null, // Let ESLint find flat config automatically
189
+ overrideConfig: this.createBaseConfig(),
190
+ fix: this.config?.fix || false,
191
+ cache: this.config?.cache || false,
192
+ cwd: projectPath
193
+ };
194
+ console.log(`✅ [ESLintEngine] Using flat config (modern ESLint v9+)`);
195
+ } else if (configDetection.hasLegacyConfig || configDetection.hasPackageConfig) {
196
+ // Use legacy config for compatibility - but ESLint v9+ only supports flat config
197
+ // We'll convert legacy to flat config on-the-fly
198
+ eslintOptions = {
199
+ overrideConfigFile: null, // Force flat config mode
200
+ overrideConfig: this.createBaseConfig(),
201
+ fix: this.config?.fix || false,
202
+ cache: this.config?.cache || false,
203
+ cwd: projectPath
204
+ };
205
+ console.log(`✅ [ESLintEngine] Legacy config detected, but using flat config mode (ESLint v9+ requirement)`);
206
+ } else {
207
+ // No config found - use SunLint's base config only, create empty config file
208
+ eslintOptions = {
209
+ overrideConfig: this.createBaseConfig(),
210
+ fix: this.config?.fix || false,
211
+ cache: this.config?.cache || false,
212
+ cwd: projectPath
213
+ };
214
+ console.log(`⚠️ [ESLintEngine] No ESLint config found, using SunLint base config only`);
215
+ }
216
+
217
+ if (this.verbose) {
218
+ console.log(`📋 [ESLintEngine] ESLint options:`, JSON.stringify(eslintOptions, null, 2));
219
+ }
220
+
221
+ const eslint = new ESLint(eslintOptions);
222
+ console.log(`✅ [ESLintEngine] ESLint instance created successfully`);
223
+
224
+ return eslint;
225
+ } catch (error) {
226
+ console.error('Failed to create ESLint instance:', error.message);
227
+ throw error;
228
+ }
229
+ }
230
+
119
231
  /**
120
232
  * Create base ESLint configuration
121
233
  * Following Rule C006: Verb-noun naming
@@ -336,19 +448,41 @@ class ESLintEngine extends AnalysisEngineInterface {
336
448
  return results;
337
449
  }
338
450
 
339
- // Reconfigure ESLint with analysis-specific rules (v9+ compatible)
451
+ // Reconfigure ESLint with analysis-specific rules and detect project config
452
+ const path = require('path');
453
+ const projectPath = path.dirname(jstsFiles[0]) || process.cwd();
454
+
455
+ const eslintInstance = await this.createESLintInstance(projectPath);
456
+
457
+ // Override config for analysis-specific rules
458
+ const analysisConfig = {
459
+ ...this.createBaseConfig(),
460
+ ...eslintConfig
461
+ };
462
+
463
+ // Re-create instance with analysis config
340
464
  const { ESLint } = await this.loadESLint();
341
- const eslintInstance = new ESLint({
342
- overrideConfigFile: null,
343
- overrideConfig: {
344
- ...this.createBaseConfig(),
345
- ...eslintConfig
346
- },
347
- cwd: process.cwd()
348
- });
465
+ const configDetection = this.detectESLintConfig(projectPath);
466
+
467
+ let finalESLintOptions;
468
+ if (configDetection.hasFlatConfig) {
469
+ finalESLintOptions = {
470
+ overrideConfigFile: null,
471
+ overrideConfig: analysisConfig,
472
+ cwd: projectPath
473
+ };
474
+ } else {
475
+ // For legacy config or no config, omit overrideConfigFile to use default behavior
476
+ finalESLintOptions = {
477
+ overrideConfig: analysisConfig,
478
+ cwd: projectPath
479
+ };
480
+ }
481
+
482
+ const finalESLintInstance = new ESLint(finalESLintOptions);
349
483
 
350
484
  // Run ESLint analysis
351
- const eslintResults = await eslintInstance.lintFiles(jstsFiles);
485
+ const eslintResults = await finalESLintInstance.lintFiles(jstsFiles);
352
486
 
353
487
  // Convert ESLint results to SunLint format
354
488
  results.results = this.convertESLintResults(eslintResults, rules);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
5
5
  "main": "cli.js",
6
6
  "bin": {