Skip to content

Commit c51cc4e

Browse files
committed
fix: improve handling of errors in overrides config blocks
1 parent d5bbcbe commit c51cc4e

File tree

2 files changed

+158
-17
lines changed

2 files changed

+158
-17
lines changed

src/rules/utils.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ interface ESLintFailedToLoadModuleError {
137137
type: ESLintErrorType.FailedToLoadModule;
138138
kind: 'parser' | 'plugin' | string;
139139
name: string;
140+
path: string;
140141
}
141142

142143
interface ESLintInvalidRuleConfigError {
@@ -149,16 +150,19 @@ interface ESLintInvalidRuleConfigError {
149150
interface ESLintProcessorNotFoundError {
150151
type: ESLintErrorType.ProcessorNotFound;
151152
name: string;
153+
path?: never;
152154
}
153155

154156
interface ESLintFailedToExtendError {
155157
type: ESLintErrorType.FailedToExtend;
156158
name: string;
159+
path: string;
157160
}
158161

159162
interface ESLintInvalidConfigError {
160163
type: ESLintErrorType.InvalidConfig;
161164
reason: string;
165+
path?: never;
162166
}
163167

164168
export type ESLintError =
@@ -174,13 +178,13 @@ const tryParseAsFailedToLoadModuleError = (
174178
error: Error
175179
): ESLintFailedToLoadModuleError | null => {
176180
// noinspection RegExpRedundantEscape
177-
const [, kind, name] =
181+
const [, kind, name, path] =
178182
/Failed to load (.+) '(.*)' declared in 'BaseConfig((?:#overrides\[\d*?\])*)': Cannot find module '/isu.exec(
179183
error.message.trim()
180184
) ?? [];
181185

182186
return kind //
183-
? { type: ESLintErrorType.FailedToLoadModule, kind, name }
187+
? { type: ESLintErrorType.FailedToLoadModule, kind, name, path }
184188
: null;
185189
};
186190

@@ -201,13 +205,14 @@ const tryParseAsInvalidRuleConfigError = (
201205
const tryParseAsFailedToExtendError = (
202206
error: Error
203207
): ESLintFailedToExtendError | null => {
204-
const [, name] =
205-
/Failed to load config "(.+)" to extend from./isu.exec(
208+
// noinspection RegExpRedundantEscape
209+
const [, name, path] =
210+
/Failed to load config "(.+)" to extend from\.\nReferenced from: BaseConfig((?:#overrides\[\d*?\])*)/isu.exec(
206211
error.message.trim()
207212
) ?? [];
208213

209214
return name //
210-
? { type: ESLintErrorType.FailedToExtend, name }
215+
? { type: ESLintErrorType.FailedToExtend, name, path }
211216
: null;
212217
};
213218

@@ -261,7 +266,7 @@ const parseESLintError = (error: Error): ESLintError => {
261266

262267
const followErrorPathToConfig = (
263268
config: ESLint.Linter.Config,
264-
error: ESLintInvalidRuleConfigError
269+
error: ESLintError
265270
): ESLint.Linter.Config => {
266271
if (!error.path || !config.overrides) {
267272
return config;
@@ -280,14 +285,16 @@ const tryRemoveErrorPointFromConfig = (
280285
config: ESLint.Linter.Config,
281286
error: ESLintError
282287
): boolean => {
288+
const configToDeleteFrom = followErrorPathToConfig(config, error);
289+
283290
if (error.type === ESLintErrorType.FailedToExtend) {
284-
if (typeof config.extends === 'string') {
285-
delete config.extends;
291+
if (typeof configToDeleteFrom.extends === 'string') {
292+
delete configToDeleteFrom.extends;
286293

287294
return true;
288295
}
289296

290-
config.extends = ensureArray(config.extends).filter(
297+
configToDeleteFrom.extends = ensureArray(configToDeleteFrom.extends).filter(
291298
extend => extend !== error.name
292299
);
293300

@@ -297,14 +304,14 @@ const tryRemoveErrorPointFromConfig = (
297304
if (error.type === ESLintErrorType.FailedToLoadModule) {
298305
switch (error.kind) {
299306
case 'plugin':
300-
config.plugins = config.plugins?.filter(
307+
configToDeleteFrom.plugins = configToDeleteFrom.plugins?.filter(
301308
plugin => plugin !== error.name
302309
);
303310

304311
return true;
305312
case 'parser':
306313
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
307-
delete config[error.kind];
314+
delete configToDeleteFrom[error.kind];
308315

309316
return true;
310317

@@ -315,13 +322,8 @@ const tryRemoveErrorPointFromConfig = (
315322
if (error.type === ESLintErrorType.InvalidRuleConfig) {
316323
const { ruleId } = error;
317324

318-
const configToDeleteFrom = {
319-
rules: {},
320-
...followErrorPathToConfig(config, error)
321-
};
322-
323325
/* istanbul ignore if */
324-
if (!(ruleId in configToDeleteFrom.rules)) {
326+
if (!(configToDeleteFrom.rules && ruleId in configToDeleteFrom.rules)) {
325327
throw new Error('Cannot delete InvalidRuleConfig error - please report');
326328
}
327329

test/src/rules/no-invalid-config.spec.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ ruleTester.run('FailedToLoadModule', rule, {
112112
type: ESLintErrorType.FailedToLoadModule,
113113
name: '@typescript-eslint/eslint-parser',
114114
kind: 'parser',
115+
path: '',
115116
line: 1,
116117
column: 28
117118
})
@@ -124,6 +125,7 @@ ruleTester.run('FailedToLoadModule', rule, {
124125
type: ESLintErrorType.FailedToLoadModule,
125126
name: '',
126127
kind: 'plugin',
128+
path: '',
127129
line: 1,
128130
column: 30
129131
})
@@ -136,10 +138,77 @@ ruleTester.run('FailedToLoadModule', rule, {
136138
type: ESLintErrorType.FailedToLoadModule,
137139
name: 'not-react',
138140
kind: 'plugin',
141+
path: '',
139142
line: 1,
140143
column: 30
141144
})
142145
]
146+
},
147+
{
148+
code: dedent`
149+
module.exports = {
150+
overrides: [
151+
{
152+
files: ['*.js'],
153+
plugins: ['not-react']
154+
}
155+
]
156+
};
157+
`,
158+
errors: [
159+
expectedError({
160+
type: ESLintErrorType.FailedToLoadModule,
161+
name: 'not-react',
162+
kind: 'plugin',
163+
path: '#overrides[0]',
164+
line: 5,
165+
column: 17
166+
})
167+
]
168+
},
169+
{
170+
code: dedent`
171+
module.exports = {
172+
overrides: [
173+
{
174+
files: ['*.js'],
175+
parser: '@typescript-eslint/eslint-parser'
176+
}
177+
]
178+
};
179+
`,
180+
errors: [
181+
expectedError({
182+
type: ESLintErrorType.FailedToLoadModule,
183+
name: '@typescript-eslint/eslint-parser',
184+
kind: 'parser',
185+
path: '#overrides[0]',
186+
line: 5,
187+
column: 15
188+
})
189+
]
190+
},
191+
{
192+
code: dedent`
193+
module.exports = {
194+
overrides: [
195+
{
196+
files: ['*'],
197+
parser: '@typescript-eslint/eslint-parser'
198+
}
199+
]
200+
};
201+
`,
202+
errors: [
203+
expectedError({
204+
type: ESLintErrorType.FailedToLoadModule,
205+
name: '@typescript-eslint/eslint-parser',
206+
kind: 'parser',
207+
path: '#overrides[0]',
208+
line: 5,
209+
column: 15
210+
})
211+
]
143212
}
144213
]
145214
});
@@ -391,6 +460,26 @@ ruleTester.run('ProcessorNotFound', rule, {
391460
column: 31
392461
})
393462
]
463+
},
464+
{
465+
code: dedent`
466+
module.exports = {
467+
overrides: [
468+
{
469+
files: ['*'],
470+
processor: '@typescript-eslint/processor'
471+
}
472+
]
473+
};
474+
`,
475+
errors: [
476+
expectedError({
477+
type: ESLintErrorType.ProcessorNotFound,
478+
name: '@typescript-eslint/processor',
479+
line: 5,
480+
column: 18
481+
})
482+
]
394483
}
395484
]
396485
});
@@ -408,6 +497,7 @@ ruleTester.run('FailedToExtend', rule, {
408497
expectedError({
409498
type: ESLintErrorType.FailedToExtend,
410499
name: 'hello-world',
500+
path: '',
411501
line: 1,
412502
column: 29
413503
})
@@ -419,6 +509,7 @@ ruleTester.run('FailedToExtend', rule, {
419509
expectedError({
420510
type: ESLintErrorType.FailedToExtend,
421511
name: 'hello-world',
512+
path: '',
422513
line: 1,
423514
column: 30
424515
})
@@ -431,6 +522,7 @@ ruleTester.run('FailedToExtend', rule, {
431522
expectedError({
432523
type: ESLintErrorType.FailedToExtend,
433524
name: 'hello-world',
525+
path: '',
434526
line: 1,
435527
column: 52
436528
})
@@ -453,6 +545,7 @@ ruleTester.run('FailedToExtend', rule, {
453545
expectedError({
454546
type: ESLintErrorType.FailedToExtend,
455547
name: 'hello-world',
548+
path: '',
456549
line: 2,
457550
column: 26
458551
})
@@ -475,11 +568,28 @@ ruleTester.run('FailedToExtend', rule, {
475568
expectedError({
476569
type: ESLintErrorType.FailedToExtend,
477570
name: 'hello-world',
571+
path: '#overrides[0]',
478572
line: 2,
479573
column: 27
480574
})
481575
]
482576
},
577+
{
578+
code: dedent`
579+
module.exports = {
580+
overrides: [{ files: ['*.ts'], extends: ['hello-world'] }]
581+
}
582+
`,
583+
errors: [
584+
expectedError({
585+
type: ESLintErrorType.FailedToExtend,
586+
name: 'hello-world',
587+
path: '#overrides[0]',
588+
line: 2,
589+
column: 44
590+
})
591+
]
592+
},
483593
{
484594
code: dedent`
485595
module.exports = {
@@ -498,6 +608,7 @@ ruleTester.run('FailedToExtend', rule, {
498608
expectedError({
499609
type: ESLintErrorType.FailedToExtend,
500610
name: 'hello-world',
611+
path: '#overrides[0]',
501612
line: 3,
502613
column: 27
503614
})
@@ -521,12 +632,14 @@ ruleTester.run('FailedToExtend', rule, {
521632
expectedError({
522633
type: ESLintErrorType.FailedToExtend,
523634
name: 'hello-world',
635+
path: '#overrides[0]',
524636
line: 3,
525637
column: 27
526638
}),
527639
expectedError({
528640
type: ESLintErrorType.FailedToExtend,
529641
name: 'hello-sunshine',
642+
path: '#overrides[0]',
530643
line: 3,
531644
column: 42
532645
})
@@ -550,16 +663,42 @@ ruleTester.run('FailedToExtend', rule, {
550663
expectedError({
551664
type: ESLintErrorType.FailedToExtend,
552665
name: 'hello-world',
666+
path: '',
553667
line: 2,
554668
column: 13
555669
}),
556670
expectedError({
557671
type: ESLintErrorType.FailedToExtend,
558672
name: 'hello-sunshine',
673+
path: '',
559674
line: 2,
560675
column: 28
561676
})
562677
]
678+
},
679+
{
680+
code: dedent`
681+
module.exports = {
682+
extends: ["hello-world"],
683+
overrides: [{ files: ["*"], extends: ["hello-sunshine"] }]
684+
}
685+
`,
686+
errors: [
687+
expectedError({
688+
type: ESLintErrorType.FailedToExtend,
689+
name: 'hello-world',
690+
path: '',
691+
line: 2,
692+
column: 13
693+
}),
694+
expectedError({
695+
type: ESLintErrorType.FailedToExtend,
696+
name: 'hello-sunshine',
697+
path: '#overrides[0]',
698+
line: 3,
699+
column: 41
700+
})
701+
]
563702
}
564703
]
565704
});

0 commit comments

Comments
 (0)