Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/tests/src/rules/named.js
829 views
1
import { test, SYNTAX_CASES, getTSParsers, testFilePath, testVersion } from '../utils';
2
import { RuleTester } from 'eslint';
3
4
import { CASE_SENSITIVE_FS } from 'eslint-module-utils/resolve';
5
6
7
const ruleTester = new RuleTester();
8
const rule = require('rules/named');
9
10
function error(name, module) {
11
return { message: name + ' not found in \'' + module + '\'',
12
type: 'Identifier' };
13
}
14
15
ruleTester.run('named', rule, {
16
valid: [
17
test({ code: 'import "./malformed.js"' }),
18
19
test({ code: 'import { foo } from "./bar"' }),
20
test({ code: 'import { foo } from "./empty-module"' }),
21
test({ code: 'import bar from "./bar.js"' }),
22
test({ code: 'import bar, { foo } from "./bar.js"' }),
23
test({ code: 'import {a, b, d} from "./named-exports"' }),
24
test({ code: 'import {ExportedClass} from "./named-exports"' }),
25
test({ code: 'import { destructingAssign } from "./named-exports"' }),
26
test({ code: 'import { destructingRenamedAssign } from "./named-exports"' }),
27
test({ code: 'import { ActionTypes } from "./qc"' }),
28
test({ code: 'import {a, b, c, d} from "./re-export"' }),
29
test({ code: 'import {a, b, c} from "./re-export-common-star"' }),
30
test({ code: 'import {RuleTester} from "./re-export-node_modules"' }),
31
32
test({ code: 'import { jsxFoo } from "./jsx/AnotherComponent"',
33
settings: { 'import/resolve': { 'extensions': ['.js', '.jsx'] } } }),
34
35
// validate that eslint-disable-line silences this properly
36
test({ code: 'import {a, b, d} from "./common"; ' +
37
'// eslint-disable-line named' }),
38
39
test({ code: 'import { foo, bar } from "./re-export-names"' }),
40
41
test({ code: 'import { foo, bar } from "./common"',
42
settings: { 'import/ignore': ['common'] } }),
43
44
// ignore core modules by default
45
test({ code: 'import { foo } from "crypto"' }),
46
test({ code: 'import { zoob } from "a"' }),
47
48
test({ code: 'import { someThing } from "./test-module"' }),
49
50
// export tests
51
test({ code: 'export { foo } from "./bar"' }),
52
test({ code: 'export { foo as bar } from "./bar"' }),
53
test({ code: 'export { foo } from "./does-not-exist"' }),
54
55
// es7
56
test({
57
code: 'export bar, { foo } from "./bar"',
58
parser: require.resolve('babel-eslint'),
59
}),
60
test({
61
code: 'import { foo, bar } from "./named-trampoline"',
62
parser: require.resolve('babel-eslint'),
63
}),
64
65
// regression tests
66
test({ code: 'let foo; export { foo as bar }' }),
67
68
// destructured exports
69
test({ code: 'import { destructuredProp } from "./named-exports"' }),
70
test({ code: 'import { arrayKeyProp } from "./named-exports"' }),
71
test({ code: 'import { deepProp } from "./named-exports"' }),
72
test({ code: 'import { deepSparseElement } from "./named-exports"' }),
73
74
// should ignore imported/exported flow types, even if they don’t exist
75
test({
76
code: 'import type { MissingType } from "./flowtypes"',
77
parser: require.resolve('babel-eslint'),
78
}),
79
test({
80
code: 'import typeof { MissingType } from "./flowtypes"',
81
parser: require.resolve('babel-eslint'),
82
}),
83
test({
84
code: 'import type { MyOpaqueType } from "./flowtypes"',
85
parser: require.resolve('babel-eslint'),
86
}),
87
test({
88
code: 'import typeof { MyOpaqueType } from "./flowtypes"',
89
parser: require.resolve('babel-eslint'),
90
}),
91
test({
92
code: 'import { type MyOpaqueType, MyClass } from "./flowtypes"',
93
parser: require.resolve('babel-eslint'),
94
}),
95
test({
96
code: 'import { typeof MyOpaqueType, MyClass } from "./flowtypes"',
97
parser: require.resolve('babel-eslint'),
98
}),
99
test({
100
code: 'import typeof MissingType from "./flowtypes"',
101
parser: require.resolve('babel-eslint'),
102
}),
103
test({
104
code: 'import typeof * as MissingType from "./flowtypes"',
105
parser: require.resolve('babel-eslint'),
106
}),
107
test({
108
code: 'export type { MissingType } from "./flowtypes"',
109
parser: require.resolve('babel-eslint'),
110
}),
111
test({
112
code: 'export type { MyOpaqueType } from "./flowtypes"',
113
parser: require.resolve('babel-eslint'),
114
}),
115
116
// jsnext
117
test({
118
code: '/*jsnext*/ import { createStore } from "redux"',
119
settings: { 'import/ignore': [] },
120
}),
121
// should work without ignore
122
test({
123
code: '/*jsnext*/ import { createStore } from "redux"',
124
}),
125
126
// ignore is ignored if exports are found
127
test({ code: 'import { foo } from "es6-module"' }),
128
129
// issue #210: shameless self-reference
130
test({ code: 'import { me, soGreat } from "./narcissist"' }),
131
132
// issue #251: re-export default as named
133
test({ code: 'import { foo, bar, baz } from "./re-export-default"' }),
134
test({
135
code: 'import { common } from "./re-export-default"',
136
settings: { 'import/ignore': ['common'] },
137
}),
138
139
// ignore CJS by default. always ignore ignore list
140
test({ code: 'import {a, b, d} from "./common"' }),
141
test({
142
code: 'import { baz } from "./bar"',
143
settings: { 'import/ignore': ['bar'] },
144
}),
145
test({
146
code: 'import { common } from "./re-export-default"',
147
}),
148
149
// destructured requires with commonjs option
150
test({
151
code: 'const { destructuredProp } = require("./named-exports")',
152
options: [{ commonjs: true }],
153
}),
154
test({
155
code: 'let { arrayKeyProp } = require("./named-exports")',
156
options: [{ commonjs: true }],
157
}),
158
test({
159
code: 'const { deepProp } = require("./named-exports")',
160
options: [{ commonjs: true }],
161
}),
162
163
test({
164
code: 'const { foo, bar } = require("./re-export-names")',
165
options: [{ commonjs: true }],
166
}),
167
168
test({
169
code: 'const { baz } = require("./bar")',
170
errors: [error('baz', './bar')],
171
}),
172
173
test({
174
code: 'const { baz } = require("./bar")',
175
errors: [error('baz', './bar')],
176
options: [{ commonjs: false }],
177
}),
178
179
test({
180
code: 'const { default: defExport } = require("./bar")',
181
options: [{ commonjs: true }],
182
}),
183
184
...SYNTAX_CASES,
185
186
...[].concat(testVersion('>= 6', () => ({
187
code: `import { ExtfieldModel, Extfield2Model } from './models';`,
188
filename: testFilePath('./export-star/downstream.js'),
189
parserOptions: {
190
sourceType: 'module',
191
ecmaVersion: 2020,
192
},
193
})) || []),
194
],
195
196
invalid: [
197
test({ code: 'import { somethingElse } from "./test-module"',
198
errors: [ error('somethingElse', './test-module') ] }),
199
200
test({ code: 'import { baz } from "./bar"',
201
errors: [error('baz', './bar')] }),
202
203
// test multiple
204
test({ code: 'import { baz, bop } from "./bar"',
205
errors: [error('baz', './bar'), error('bop', './bar')] }),
206
207
test({ code: 'import {a, b, c} from "./named-exports"',
208
errors: [error('c', './named-exports')] }),
209
210
test({ code: 'import { a } from "./default-export"',
211
errors: [error('a', './default-export')] }),
212
213
test({ code: 'import { ActionTypess } from "./qc"',
214
errors: [error('ActionTypess', './qc')] }),
215
216
test({ code: 'import {a, b, c, d, e} from "./re-export"',
217
errors: [error('e', './re-export')] }),
218
219
test({
220
code: 'import { a } from "./re-export-names"',
221
errors: [error('a', './re-export-names')],
222
}),
223
224
// export tests
225
test({
226
code: 'export { bar } from "./bar"',
227
errors: ["bar not found in './bar'"],
228
}),
229
230
// es7
231
test({
232
code: 'export bar2, { bar } from "./bar"',
233
parser: require.resolve('babel-eslint'),
234
errors: ["bar not found in './bar'"],
235
}),
236
test({
237
code: 'import { foo, bar, baz } from "./named-trampoline"',
238
parser: require.resolve('babel-eslint'),
239
errors: ["baz not found in './named-trampoline'"],
240
}),
241
test({
242
code: 'import { baz } from "./broken-trampoline"',
243
parser: require.resolve('babel-eslint'),
244
errors: ['baz not found via broken-trampoline.js -> named-exports.js'],
245
}),
246
247
test({
248
code: 'const { baz } = require("./bar")',
249
errors: [error('baz', './bar')],
250
options: [{ commonjs: true }],
251
}),
252
253
test({
254
code: 'let { baz } = require("./bar")',
255
errors: [error('baz', './bar')],
256
options: [{ commonjs: true }],
257
}),
258
259
test({
260
code: 'const { baz: bar, bop } = require("./bar"), { a } = require("./re-export-names")',
261
errors: [error('baz', './bar'), error('bop', './bar'), error('a', './re-export-names')],
262
options: [{ commonjs: true }],
263
}),
264
265
test({
266
code: 'const { default: defExport } = require("./named-exports")',
267
errors: [error('default', './named-exports')],
268
options: [{ commonjs: true }],
269
}),
270
271
// parse errors
272
// test({
273
// code: "import { a } from './test.coffee';",
274
// settings: { 'import/extensions': ['.js', '.coffee'] },
275
// errors: [{
276
// message: "Parse errors in imported module './test.coffee': Unexpected token > (1:20)",
277
// type: 'Literal',
278
// }],
279
// }),
280
281
test({
282
code: 'import { type MyOpaqueType, MyMissingClass } from "./flowtypes"',
283
parser: require.resolve('babel-eslint'),
284
errors: ["MyMissingClass not found in './flowtypes'"],
285
}),
286
287
// jsnext
288
test({
289
code: '/*jsnext*/ import { createSnorlax } from "redux"',
290
settings: { 'import/ignore': [] },
291
errors: ["createSnorlax not found in 'redux'"],
292
}),
293
// should work without ignore
294
test({
295
code: '/*jsnext*/ import { createSnorlax } from "redux"',
296
errors: ["createSnorlax not found in 'redux'"],
297
}),
298
299
// ignore is ignored if exports are found
300
test({
301
code: 'import { baz } from "es6-module"',
302
errors: ["baz not found in 'es6-module'"],
303
}),
304
305
// issue #251
306
test({
307
code: 'import { foo, bar, bap } from "./re-export-default"',
308
errors: ["bap not found in './re-export-default'"],
309
}),
310
311
312
// #328: * exports do not include default
313
test({
314
code: 'import { default as barDefault } from "./re-export"',
315
errors: [`default not found in './re-export'`],
316
}),
317
],
318
});
319
320
// #311: import of mismatched case
321
if (!CASE_SENSITIVE_FS) {
322
ruleTester.run('named (path case-insensitivity)', rule, {
323
valid: [
324
test({
325
code: 'import { b } from "./Named-Exports"',
326
}),
327
],
328
invalid: [
329
test({
330
code: 'import { foo } from "./Named-Exports"',
331
errors: [`foo not found in './Named-Exports'`],
332
}),
333
],
334
});
335
}
336
337
// export-all
338
ruleTester.run('named (export *)', rule, {
339
valid: [
340
test({
341
code: 'import { foo } from "./export-all"',
342
}),
343
],
344
invalid: [
345
test({
346
code: 'import { bar } from "./export-all"',
347
errors: [`bar not found in './export-all'`],
348
}),
349
],
350
});
351
352
353
context('TypeScript', function () {
354
getTSParsers().forEach((parser) => {
355
const settings = {
356
'import/parsers': { [parser]: ['.ts'] },
357
'import/resolver': { 'eslint-import-resolver-typescript': true },
358
};
359
360
const valid = [];
361
const invalid = [
362
test({
363
code: `import {a} from './export-star-3/b';`,
364
filename: testFilePath('./export-star-3/a.js'),
365
parser,
366
settings,
367
}),
368
];
369
370
[
371
'typescript',
372
'typescript-declare',
373
'typescript-export-assign-namespace',
374
'typescript-export-assign-namespace-merged',
375
].forEach((source) => {
376
valid.push(
377
test({
378
code: `import { MyType } from "./${source}"`,
379
parser,
380
settings,
381
}),
382
test({
383
code: `import { Foo } from "./${source}"`,
384
parser,
385
settings,
386
}),
387
test({
388
code: `import { Bar } from "./${source}"`,
389
parser,
390
settings,
391
}),
392
test({
393
code: `import { getFoo } from "./${source}"`,
394
parser,
395
settings,
396
}),
397
test({
398
code: `import { MyEnum } from "./${source}"`,
399
parser,
400
settings,
401
}),
402
test({
403
code: `
404
import { MyModule } from "./${source}"
405
MyModule.ModuleFunction()
406
`,
407
parser,
408
settings,
409
}),
410
test({
411
code: `
412
import { MyNamespace } from "./${source}"
413
MyNamespace.NSModule.NSModuleFunction()
414
`,
415
parser,
416
settings,
417
}),
418
);
419
420
invalid.push(
421
test({
422
code: `import { MissingType } from "./${source}"`,
423
parser,
424
settings,
425
errors: [{
426
message: `MissingType not found in './${source}'`,
427
type: 'Identifier',
428
}],
429
}),
430
test({
431
code: `import { NotExported } from "./${source}"`,
432
parser,
433
settings,
434
errors: [{
435
message: `NotExported not found in './${source}'`,
436
type: 'Identifier',
437
}],
438
}),
439
);
440
});
441
});
442
});
443
444