Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/tests/src/rules/no-duplicates.js
829 views
1
import * as path from 'path';
2
import { test as testUtil, getNonDefaultParsers } from '../utils';
3
4
import { RuleTester } from 'eslint';
5
import eslintPkg from 'eslint/package.json';
6
import semver from 'semver';
7
8
const ruleTester = new RuleTester();
9
const rule = require('rules/no-duplicates');
10
11
// autofix only possible with eslint 4+
12
const test = semver.satisfies(eslintPkg.version, '< 4')
13
? t => testUtil(Object.assign({}, t, { output: t.code }))
14
: testUtil;
15
16
ruleTester.run('no-duplicates', rule, {
17
valid: [
18
test({ code: 'import "./malformed.js"' }),
19
20
test({ code: "import { x } from './foo'; import { y } from './bar'" }),
21
22
// #86: every unresolved module should not show up as 'null' and duplicate
23
test({ code: 'import foo from "234artaf";' +
24
'import { shoop } from "234q25ad"' }),
25
26
// #225: ignore duplicate if is a flow type import
27
test({
28
code: "import { x } from './foo'; import type { y } from './foo'",
29
parser: require.resolve('babel-eslint'),
30
}),
31
32
// #1107: Using different query strings that trigger different webpack loaders.
33
test({
34
code: "import x from './bar?optionX'; import y from './bar?optionY';",
35
options: [{ 'considerQueryString': true }],
36
settings: { 'import/resolver': 'webpack' },
37
}),
38
test({
39
code: "import x from './foo'; import y from './bar';",
40
options: [{ 'considerQueryString': true }],
41
settings: { 'import/resolver': 'webpack' },
42
}),
43
44
// #1538: It is impossible to import namespace and other in one line, so allow this.
45
test({
46
code: "import * as ns from './foo'; import {y} from './foo'",
47
}),
48
test({
49
code: "import {y} from './foo'; import * as ns from './foo'",
50
}),
51
],
52
invalid: [
53
test({
54
code: "import { x } from './foo'; import { y } from './foo'",
55
output: "import { x , y } from './foo'; ",
56
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
57
}),
58
59
test({
60
code: "import {x} from './foo'; import {y} from './foo'; import { z } from './foo'",
61
output: "import {x,y, z } from './foo'; ",
62
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
63
}),
64
65
// ensure resolved path results in warnings
66
test({
67
code: "import { x } from './bar'; import { y } from 'bar';",
68
output: "import { x , y } from './bar'; ",
69
settings: { 'import/resolve': {
70
paths: [path.join( process.cwd()
71
, 'tests', 'files',
72
)] } },
73
errors: 2, // path ends up hardcoded
74
}),
75
76
// #1107: Using different query strings that trigger different webpack loaders.
77
test({
78
code: "import x from './bar.js?optionX'; import y from './bar?optionX';",
79
settings: { 'import/resolver': 'webpack' },
80
errors: 2, // path ends up hardcoded
81
}),
82
test({
83
code: "import x from './bar?optionX'; import y from './bar?optionY';",
84
settings: { 'import/resolver': 'webpack' },
85
errors: 2, // path ends up hardcoded
86
}),
87
88
// #1107: Using same query strings that trigger the same loader.
89
test({
90
code: "import x from './bar?optionX'; import y from './bar.js?optionX';",
91
options: [{ 'considerQueryString': true }],
92
settings: { 'import/resolver': 'webpack' },
93
errors: 2, // path ends up hardcoded
94
}),
95
96
// #86: duplicate unresolved modules should be flagged
97
test({
98
code: "import foo from 'non-existent'; import bar from 'non-existent';",
99
// Autofix bail because of different default import names.
100
output: "import foo from 'non-existent'; import bar from 'non-existent';",
101
errors: [
102
"'non-existent' imported multiple times.",
103
"'non-existent' imported multiple times.",
104
],
105
}),
106
107
test({
108
code: "import type { x } from './foo'; import type { y } from './foo'",
109
output: "import type { x , y } from './foo'; ",
110
parser: require.resolve('babel-eslint'),
111
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
112
}),
113
114
test({
115
code: "import './foo'; import './foo'",
116
output: "import './foo'; ",
117
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
118
}),
119
120
test({
121
code: "import { x, /* x */ } from './foo'; import {//y\ny//y2\n} from './foo'",
122
output: "import { x, /* x */ //y\ny//y2\n} from './foo'; ",
123
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
124
}),
125
126
test({
127
code: "import {x} from './foo'; import {} from './foo'",
128
output: "import {x} from './foo'; ",
129
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
130
}),
131
132
test({
133
code: "import {x} from './foo'; import {} from './foo'; import {/*c*/} from './foo'; import {y} from './foo'",
134
output: "import {x/*c*/,y} from './foo'; ",
135
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
136
}),
137
138
test({
139
code: "import { } from './foo'; import {x} from './foo'",
140
output: "import { x} from './foo'; ",
141
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
142
}),
143
144
test({
145
code: "import './foo'; import {x} from './foo'",
146
output: "import {x} from './foo'; ",
147
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
148
}),
149
150
test({
151
code: "import'./foo'; import {x} from './foo'",
152
output: "import {x} from'./foo'; ",
153
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
154
}),
155
156
test({
157
code: "import './foo'; import { /*x*/} from './foo'; import {//y\n} from './foo'; import {z} from './foo'",
158
output: "import { /*x*///y\nz} from './foo'; ",
159
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
160
}),
161
162
test({
163
code: "import './foo'; import def, {x} from './foo'",
164
output: "import def, {x} from './foo'; ",
165
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
166
}),
167
168
test({
169
code: "import './foo'; import def from './foo'",
170
output: "import def from './foo'; ",
171
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
172
}),
173
174
test({
175
code: "import def from './foo'; import {x} from './foo'",
176
output: "import def, {x} from './foo'; ",
177
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
178
}),
179
180
test({
181
code: "import {x} from './foo'; import def from './foo'",
182
output: "import def, {x} from './foo'; ",
183
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
184
}),
185
186
test({
187
code: "import{x} from './foo'; import def from './foo'",
188
output: "import def,{x} from './foo'; ",
189
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
190
}),
191
192
test({
193
code: "import {x} from './foo'; import def, {y} from './foo'",
194
output: "import def, {x,y} from './foo'; ",
195
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
196
}),
197
198
test({
199
code: "import * as ns1 from './foo'; import * as ns2 from './foo'",
200
// Autofix bail because cannot merge namespace imports.
201
output: "import * as ns1 from './foo'; import * as ns2 from './foo'",
202
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
203
}),
204
205
test({
206
code: "import * as ns from './foo'; import {x} from './foo'; import {y} from './foo'",
207
// Autofix could merge some imports, but not the namespace import.
208
output: "import * as ns from './foo'; import {x,y} from './foo'; ",
209
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
210
}),
211
212
test({
213
code: "import {x} from './foo'; import * as ns from './foo'; import {y} from './foo'; import './foo'",
214
// Autofix could merge some imports, but not the namespace import.
215
output: "import {x,y} from './foo'; import * as ns from './foo'; ",
216
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
217
}),
218
219
test({
220
code: `
221
// some-tool-disable-next-line
222
import {x} from './foo'
223
import {//y\ny} from './foo'
224
`,
225
// Autofix bail because of comment.
226
output: `
227
// some-tool-disable-next-line
228
import {x} from './foo'
229
import {//y\ny} from './foo'
230
`,
231
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
232
}),
233
234
test({
235
code: `
236
import {x} from './foo'
237
// some-tool-disable-next-line
238
import {y} from './foo'
239
`,
240
// Autofix bail because of comment.
241
output: `
242
import {x} from './foo'
243
// some-tool-disable-next-line
244
import {y} from './foo'
245
`,
246
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
247
}),
248
249
test({
250
code: `
251
import {x} from './foo' // some-tool-disable-line
252
import {y} from './foo'
253
`,
254
// Autofix bail because of comment.
255
output: `
256
import {x} from './foo' // some-tool-disable-line
257
import {y} from './foo'
258
`,
259
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
260
}),
261
262
test({
263
code: `
264
import {x} from './foo'
265
import {y} from './foo' // some-tool-disable-line
266
`,
267
// Autofix bail because of comment.
268
output: `
269
import {x} from './foo'
270
import {y} from './foo' // some-tool-disable-line
271
`,
272
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
273
}),
274
275
test({
276
code: `
277
import {x} from './foo'
278
/* comment */ import {y} from './foo'
279
`,
280
// Autofix bail because of comment.
281
output: `
282
import {x} from './foo'
283
/* comment */ import {y} from './foo'
284
`,
285
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
286
}),
287
288
test({
289
code: `
290
import {x} from './foo'
291
import {y} from './foo' /* comment
292
multiline */
293
`,
294
// Autofix bail because of comment.
295
output: `
296
import {x} from './foo'
297
import {y} from './foo' /* comment
298
multiline */
299
`,
300
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
301
}),
302
303
test({
304
code: `
305
import {x} from './foo'
306
import {y} from './foo'
307
// some-tool-disable-next-line
308
`,
309
// Not autofix bail.
310
output: `
311
import {x,y} from './foo'
312
// some-tool-disable-next-line
313
`,
314
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
315
}),
316
317
test({
318
code: `
319
import {x} from './foo'
320
// comment
321
322
import {y} from './foo'
323
`,
324
// Not autofix bail.
325
output: `
326
import {x,y} from './foo'
327
// comment
328
329
`,
330
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
331
}),
332
333
test({
334
code: `
335
import {x} from './foo'
336
import/* comment */{y} from './foo'
337
`,
338
// Autofix bail because of comment.
339
output: `
340
import {x} from './foo'
341
import/* comment */{y} from './foo'
342
`,
343
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
344
}),
345
346
test({
347
code: `
348
import {x} from './foo'
349
import/* comment */'./foo'
350
`,
351
// Autofix bail because of comment.
352
output: `
353
import {x} from './foo'
354
import/* comment */'./foo'
355
`,
356
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
357
}),
358
359
test({
360
code: `
361
import {x} from './foo'
362
import{y}/* comment */from './foo'
363
`,
364
// Autofix bail because of comment.
365
output: `
366
import {x} from './foo'
367
import{y}/* comment */from './foo'
368
`,
369
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
370
}),
371
372
test({
373
code: `
374
import {x} from './foo'
375
import{y}from/* comment */'./foo'
376
`,
377
// Autofix bail because of comment.
378
output: `
379
import {x} from './foo'
380
import{y}from/* comment */'./foo'
381
`,
382
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
383
}),
384
385
test({
386
code: `
387
import {x} from
388
// some-tool-disable-next-line
389
'./foo'
390
import {y} from './foo'
391
`,
392
// Autofix bail because of comment.
393
output: `
394
import {x} from
395
// some-tool-disable-next-line
396
'./foo'
397
import {y} from './foo'
398
`,
399
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
400
}),
401
402
// #2027 long import list generate empty lines
403
test({
404
code: "import { Foo } from './foo';\nimport { Bar } from './foo';\nexport const value = {}",
405
output: "import { Foo , Bar } from './foo';\nexport const value = {}",
406
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
407
}),
408
409
// #2027 long import list generate empty lines
410
test({
411
code: "import { Foo } from './foo';\nimport Bar from './foo';\nexport const value = {}",
412
output: "import Bar, { Foo } from './foo';\nexport const value = {}",
413
errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'],
414
}),
415
],
416
});
417
418
context('TypeScript', function () {
419
getNonDefaultParsers()
420
// Type-only imports were added in TypeScript ESTree 2.23.0
421
.filter((parser) => parser !== require.resolve('typescript-eslint-parser'))
422
.forEach((parser) => {
423
const parserConfig = {
424
parser,
425
settings: {
426
'import/parsers': { [parser]: ['.ts'] },
427
'import/resolver': { 'eslint-import-resolver-typescript': true },
428
},
429
};
430
431
ruleTester.run('no-duplicates', rule, {
432
valid: [
433
// #1667: ignore duplicate if is a typescript type import
434
test({
435
code: "import type { x } from './foo'; import y from './foo'",
436
...parserConfig,
437
}),
438
test({
439
code: "import type x from './foo'; import type y from './bar'",
440
...parserConfig,
441
}),
442
test({
443
code: "import type {x} from './foo'; import type {y} from './bar'",
444
...parserConfig,
445
}),
446
test({
447
code: "import type x from './foo'; import type {y} from './foo'",
448
...parserConfig,
449
}),
450
test({
451
code: `
452
import type {} from './module';
453
import {} from './module2';
454
`,
455
...parserConfig,
456
}),
457
],
458
invalid: [
459
test({
460
code: "import type x from './foo'; import type y from './foo'",
461
...parserConfig,
462
errors: [
463
{
464
line: 1,
465
column: 20,
466
message: "'./foo' imported multiple times.",
467
},
468
{
469
line: 1,
470
column: 48,
471
message: "'./foo' imported multiple times.",
472
},
473
],
474
}),
475
test({
476
code: "import type x from './foo'; import type x from './foo'",
477
output: "import type x from './foo'; ",
478
...parserConfig,
479
errors: [
480
{
481
line: 1,
482
column: 20,
483
message: "'./foo' imported multiple times.",
484
},
485
{
486
line: 1,
487
column: 48,
488
message: "'./foo' imported multiple times.",
489
},
490
],
491
}),
492
test({
493
code: "import type {x} from './foo'; import type {y} from './foo'",
494
...parserConfig,
495
output: `import type {x,y} from './foo'; `,
496
errors: [
497
{
498
line: 1,
499
column: 22,
500
message: "'./foo' imported multiple times.",
501
},
502
{
503
line: 1,
504
column: 52,
505
message: "'./foo' imported multiple times.",
506
},
507
],
508
}),
509
],
510
});
511
});
512
});
513
514