@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.
- package/config/rules/rules-registry.json +1 -1
- package/engines/eslint-engine.js +156 -22
- package/package.json +1 -1
package/engines/eslint-engine.js
CHANGED
|
@@ -66,22 +66,14 @@ class ESLintEngine extends AnalysisEngineInterface {
|
|
|
66
66
|
// Check for ESLint dependencies first
|
|
67
67
|
dependencyChecker.checkAndNotify('eslint');
|
|
68
68
|
|
|
69
|
-
//
|
|
70
|
-
|
|
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
|
|
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
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
|
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