@nx/eslint 20.8.2 → 20.8.4
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/eslint",
|
|
3
|
-
"version": "20.8.
|
|
3
|
+
"version": "20.8.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The ESLint plugin for Nx contains executors, generators and utilities used for linting JavaScript/TypeScript projects within an Nx workspace.",
|
|
6
6
|
"repository": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"eslint": "^8.0.0 || ^9.0.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@nx/devkit": "20.8.
|
|
39
|
-
"@nx/js": "20.8.
|
|
38
|
+
"@nx/devkit": "20.8.4",
|
|
39
|
+
"@nx/js": "20.8.4",
|
|
40
40
|
"semver": "^7.5.3",
|
|
41
41
|
"tslib": "^2.3.0",
|
|
42
42
|
"typescript": "~5.7.2"
|
|
@@ -8,7 +8,8 @@ export declare function addPatternsToFlatConfigIgnoresBlock(content: string, ign
|
|
|
8
8
|
export declare function hasFlatConfigIgnoresBlock(content: string): boolean;
|
|
9
9
|
export declare function hasOverride(content: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean): boolean;
|
|
10
10
|
/**
|
|
11
|
-
* Finds an override matching the lookup function and applies the update function to it
|
|
11
|
+
* Finds an override matching the lookup function and applies the update function to it.
|
|
12
|
+
* Uses property-level AST updates to preserve properties with variable references.
|
|
12
13
|
*/
|
|
13
14
|
export declare function replaceOverride(content: string, root: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, update?: (override: Partial<Linter.ConfigOverride<Linter.RulesRecord>>) => Partial<Linter.ConfigOverride<Linter.RulesRecord>>): string;
|
|
14
15
|
/**
|
|
@@ -143,18 +143,20 @@ function hasOverride(content, lookup) {
|
|
|
143
143
|
}
|
|
144
144
|
for (const node of exportsArray) {
|
|
145
145
|
if (isOverride(node)) {
|
|
146
|
-
let
|
|
146
|
+
let data;
|
|
147
147
|
if (ts.isObjectLiteralExpression(node)) {
|
|
148
|
-
|
|
149
|
-
// strip any spread elements
|
|
150
|
-
objSource = objSource.replace(SPREAD_ELEMENTS_REGEXP, '');
|
|
148
|
+
data = extractPropertiesFromObjectLiteral(node);
|
|
151
149
|
}
|
|
152
150
|
else {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
// Handle compat.config(...).map(...) pattern
|
|
152
|
+
const arrowBody = node['expression'].arguments[0].body.expression;
|
|
153
|
+
if (ts.isObjectLiteralExpression(arrowBody)) {
|
|
154
|
+
data = extractPropertiesFromObjectLiteral(arrowBody);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
156
159
|
}
|
|
157
|
-
const data = parseTextToJson(objSource);
|
|
158
160
|
if (lookup(data)) {
|
|
159
161
|
return true;
|
|
160
162
|
}
|
|
@@ -172,7 +174,123 @@ function parseTextToJson(text) {
|
|
|
172
174
|
.replace(/\(?await import\(['"]([^'"]+)['"]\)\)?/g, '"$1"'));
|
|
173
175
|
}
|
|
174
176
|
/**
|
|
175
|
-
*
|
|
177
|
+
* Extracts literal values from AST nodes.
|
|
178
|
+
* Returns undefined for complex expressions that can't be statically evaluated.
|
|
179
|
+
*/
|
|
180
|
+
function extractLiteralValue(node) {
|
|
181
|
+
if (ts.isStringLiteral(node)) {
|
|
182
|
+
return node.text;
|
|
183
|
+
}
|
|
184
|
+
if (ts.isNumericLiteral(node)) {
|
|
185
|
+
return Number(node.text);
|
|
186
|
+
}
|
|
187
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword)
|
|
188
|
+
return true;
|
|
189
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword)
|
|
190
|
+
return false;
|
|
191
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
192
|
+
return null;
|
|
193
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
194
|
+
const arr = [];
|
|
195
|
+
for (const element of node.elements) {
|
|
196
|
+
const value = extractLiteralValue(element);
|
|
197
|
+
if (value === undefined)
|
|
198
|
+
return undefined;
|
|
199
|
+
arr.push(value);
|
|
200
|
+
}
|
|
201
|
+
return arr;
|
|
202
|
+
}
|
|
203
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
204
|
+
const obj = {};
|
|
205
|
+
for (const prop of node.properties) {
|
|
206
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
207
|
+
const name = prop.name.getText().replace(/['"]/g, '');
|
|
208
|
+
const value = extractLiteralValue(prop.initializer);
|
|
209
|
+
if (value === undefined) {
|
|
210
|
+
// Skip properties with non-extractable values (like variable references)
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
obj[name] = value;
|
|
214
|
+
}
|
|
215
|
+
else if (ts.isSpreadAssignment(prop)) {
|
|
216
|
+
// Cannot extract spread assignments statically, skip them
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Skip other property types (shorthand, method, etc.)
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return obj;
|
|
225
|
+
}
|
|
226
|
+
// For complex expressions (identifiers, function calls, etc.), return undefined
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Extracts property values from an ObjectLiteralExpression using AST.
|
|
231
|
+
* Only extracts properties that have simple literal values.
|
|
232
|
+
* Returns a partial object suitable for the lookup function.
|
|
233
|
+
*/
|
|
234
|
+
function extractPropertiesFromObjectLiteral(node) {
|
|
235
|
+
const result = {};
|
|
236
|
+
for (const prop of node.properties) {
|
|
237
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
238
|
+
const name = prop.name.getText().replace(/['"]/g, '');
|
|
239
|
+
const value = extractLiteralValue(prop.initializer);
|
|
240
|
+
if (value !== undefined) {
|
|
241
|
+
result[name] = value;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Find a property assignment node by name in an object literal.
|
|
249
|
+
*/
|
|
250
|
+
function findPropertyNode(node, propertyName) {
|
|
251
|
+
for (const prop of node.properties) {
|
|
252
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
253
|
+
const name = prop.name.getText().replace(/['"]/g, '');
|
|
254
|
+
if (name === propertyName) {
|
|
255
|
+
return prop;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Find properties that are added, changed, or removed.
|
|
263
|
+
*/
|
|
264
|
+
function findChangedProperties(original, updated) {
|
|
265
|
+
const changed = [];
|
|
266
|
+
// Check modified/added properties
|
|
267
|
+
for (const key of Object.keys(updated)) {
|
|
268
|
+
if (JSON.stringify(original[key]) !== JSON.stringify(updated[key])) {
|
|
269
|
+
changed.push(key);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Check removed properties
|
|
273
|
+
for (const key of Object.keys(original)) {
|
|
274
|
+
if (!(key in updated)) {
|
|
275
|
+
changed.push(key);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return changed;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Serialize a value to JavaScript source code. Handles converting eslintrc parser format to flat config format.
|
|
282
|
+
*/
|
|
283
|
+
function serializeValue(value, format) {
|
|
284
|
+
const parserReplacement = format === 'mjs'
|
|
285
|
+
? (parser) => `(await import('${parser}'))`
|
|
286
|
+
: (parser) => `require('${parser}')`;
|
|
287
|
+
return JSON.stringify(value, null, 2)
|
|
288
|
+
.replace(/"parser": "([^"]+)"/g, (_, parser) => `"parser": ${parserReplacement(parser)}`)
|
|
289
|
+
.replaceAll(/\n/g, '\n '); // Maintain indentation
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Finds an override matching the lookup function and applies the update function to it.
|
|
293
|
+
* Uses property-level AST updates to preserve properties with variable references.
|
|
176
294
|
*/
|
|
177
295
|
function replaceOverride(content, root, lookup, update) {
|
|
178
296
|
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
@@ -183,45 +301,78 @@ function replaceOverride(content, root, lookup, update) {
|
|
|
183
301
|
}
|
|
184
302
|
const changes = [];
|
|
185
303
|
exportsArray.forEach((node) => {
|
|
186
|
-
if (isOverride(node)) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
304
|
+
if (!isOverride(node)) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
let objectLiteralNode;
|
|
308
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
309
|
+
objectLiteralNode = node;
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// Handle compat.config(...).map(...) pattern
|
|
313
|
+
const arrowBody = node['expression'].arguments[0].body.expression;
|
|
314
|
+
if (ts.isObjectLiteralExpression(arrowBody)) {
|
|
315
|
+
objectLiteralNode = arrowBody;
|
|
193
316
|
}
|
|
194
317
|
else {
|
|
195
|
-
|
|
196
|
-
// strip any spread elements
|
|
197
|
-
objSource = fullNodeText.replace(SPREAD_ELEMENTS_REGEXP, '');
|
|
198
|
-
start =
|
|
199
|
-
node['expression'].arguments[0].body.expression.properties.pos +
|
|
200
|
-
(fullNodeText.length - objSource.length);
|
|
201
|
-
end = node['expression'].arguments[0].body.expression.properties.end;
|
|
318
|
+
return;
|
|
202
319
|
}
|
|
203
|
-
|
|
204
|
-
|
|
320
|
+
}
|
|
321
|
+
// Use AST-based extraction to handle variable references (e.g., plugins: { 'abc': abc })
|
|
322
|
+
const data = extractPropertiesFromObjectLiteral(objectLiteralNode);
|
|
323
|
+
if (lookup(data)) {
|
|
324
|
+
// Deep clone before update (update functions may mutate nested objects)
|
|
325
|
+
const originalData = structuredClone(data);
|
|
326
|
+
const updatedData = update?.(data);
|
|
327
|
+
// If update function was provided and returns undefined, delete the entire override block
|
|
328
|
+
if (update && updatedData === undefined) {
|
|
205
329
|
changes.push({
|
|
206
330
|
type: devkit_1.ChangeType.Delete,
|
|
207
|
-
start,
|
|
208
|
-
length: end -
|
|
331
|
+
start: node.pos,
|
|
332
|
+
length: node.end - node.pos + 1, // +1 for trailing comma
|
|
209
333
|
});
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
334
|
+
}
|
|
335
|
+
else if (updatedData) {
|
|
336
|
+
const mappedData = mapFilePaths(updatedData);
|
|
337
|
+
const changedProps = findChangedProperties(originalData, mappedData);
|
|
338
|
+
for (const propName of changedProps) {
|
|
339
|
+
const originalNode = findPropertyNode(objectLiteralNode, propName);
|
|
340
|
+
const updatedValue = mappedData[propName];
|
|
341
|
+
if (originalNode && !(propName in mappedData)) {
|
|
342
|
+
// Delete property that was removed
|
|
343
|
+
changes.push({
|
|
344
|
+
type: devkit_1.ChangeType.Delete,
|
|
345
|
+
start: originalNode.pos,
|
|
346
|
+
length: originalNode.end - originalNode.pos,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
else if (originalNode) {
|
|
350
|
+
// Replace existing property value
|
|
351
|
+
const valueNode = originalNode.initializer;
|
|
352
|
+
changes.push({
|
|
353
|
+
type: devkit_1.ChangeType.Delete,
|
|
354
|
+
start: valueNode.pos,
|
|
355
|
+
length: valueNode.end - valueNode.pos,
|
|
356
|
+
});
|
|
357
|
+
changes.push({
|
|
358
|
+
type: devkit_1.ChangeType.Insert,
|
|
359
|
+
index: valueNode.pos,
|
|
360
|
+
text: ' ' + serializeValue(updatedValue, format),
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
// Add new property at the end of the object
|
|
365
|
+
const lastProp = objectLiteralNode.properties[objectLiteralNode.properties.length - 1];
|
|
366
|
+
const insertPos = lastProp
|
|
367
|
+
? lastProp.end
|
|
368
|
+
: objectLiteralNode.pos + 1;
|
|
369
|
+
const needsComma = lastProp ? ',' : '';
|
|
370
|
+
changes.push({
|
|
371
|
+
type: devkit_1.ChangeType.Insert,
|
|
372
|
+
index: insertPos,
|
|
373
|
+
text: `${needsComma}\n "${propName}": ${serializeValue(updatedValue, format)}`,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
225
376
|
}
|
|
226
377
|
}
|
|
227
378
|
}
|