Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/eslint-plugin-import
Path: blob/main/tests/src/rules/order.js
829 views
1
import { test, getTSParsers, getNonDefaultParsers } from '../utils';
2
3
import { RuleTester } from 'eslint';
4
import eslintPkg from 'eslint/package.json';
5
import semver from 'semver';
6
import flatMap from 'array.prototype.flatmap';
7
8
const ruleTester = new RuleTester();
9
const rule = require('rules/order');
10
11
function withoutAutofixOutput(test) {
12
return Object.assign({}, test, { output: test.code });
13
}
14
15
ruleTester.run('order', rule, {
16
valid: [
17
// Default order using require
18
test({
19
code: `
20
var fs = require('fs');
21
var async = require('async');
22
var relParent1 = require('../foo');
23
var relParent2 = require('../foo/bar');
24
var relParent3 = require('../');
25
var relParent4 = require('..');
26
var sibling = require('./foo');
27
var index = require('./');`,
28
}),
29
// Default order using import
30
test({
31
code: `
32
import fs from 'fs';
33
import async, {foo1} from 'async';
34
import relParent1 from '../foo';
35
import relParent2, {foo2} from '../foo/bar';
36
import relParent3 from '../';
37
import sibling, {foo3} from './foo';
38
import index from './';`,
39
}),
40
// Multiple module of the same rank next to each other
41
test({
42
code: `
43
var fs = require('fs');
44
var fs = require('fs');
45
var path = require('path');
46
var _ = require('lodash');
47
var async = require('async');`,
48
}),
49
// Overriding order to be the reverse of the default order
50
test({
51
code: `
52
var index = require('./');
53
var sibling = require('./foo');
54
var relParent3 = require('../');
55
var relParent2 = require('../foo/bar');
56
var relParent1 = require('../foo');
57
var async = require('async');
58
var fs = require('fs');
59
`,
60
options: [{ groups: ['index', 'sibling', 'parent', 'external', 'builtin'] }],
61
}),
62
// Ignore dynamic requires
63
test({
64
code: `
65
var path = require('path');
66
var _ = require('lodash');
67
var async = require('async');
68
var fs = require('f' + 's');`,
69
}),
70
// Ignore non-require call expressions
71
test({
72
code: `
73
var path = require('path');
74
var result = add(1, 2);
75
var _ = require('lodash');`,
76
}),
77
// Ignore requires that are not at the top-level #1
78
test({
79
code: `
80
var index = require('./');
81
function foo() {
82
var fs = require('fs');
83
}
84
() => require('fs');
85
if (a) {
86
require('fs');
87
}`,
88
}),
89
// Ignore requires that are not at the top-level #2
90
test({
91
code: `
92
const foo = [
93
require('./foo'),
94
require('fs'),
95
]`,
96
}),
97
// Ignore requires in template literal (#1936)
98
test({
99
code: "const foo = `${require('./a')} ${require('fs')}`",
100
}),
101
// Ignore unknown/invalid cases
102
test({
103
code: `
104
var unknown1 = require('/unknown1');
105
var fs = require('fs');
106
var unknown2 = require('/unknown2');
107
var async = require('async');
108
var unknown3 = require('/unknown3');
109
var foo = require('../foo');
110
var unknown4 = require('/unknown4');
111
var bar = require('../foo/bar');
112
var unknown5 = require('/unknown5');
113
var parent = require('../');
114
var unknown6 = require('/unknown6');
115
var foo = require('./foo');
116
var unknown7 = require('/unknown7');
117
var index = require('./');
118
var unknown8 = require('/unknown8');
119
` }),
120
// Ignoring unassigned values by default (require)
121
test({
122
code: `
123
require('./foo');
124
require('fs');
125
var path = require('path');
126
` }),
127
// Ignoring unassigned values by default (import)
128
test({
129
code: `
130
import './foo';
131
import 'fs';
132
import path from 'path';
133
` }),
134
// No imports
135
test({
136
code: `
137
function add(a, b) {
138
return a + b;
139
}
140
var foo;
141
` }),
142
// Grouping import types
143
test({
144
code: `
145
var fs = require('fs');
146
var index = require('./');
147
var path = require('path');
148
149
var sibling = require('./foo');
150
var relParent3 = require('../');
151
var async = require('async');
152
var relParent1 = require('../foo');
153
`,
154
options: [{ groups: [
155
['builtin', 'index'],
156
['sibling', 'parent', 'external'],
157
] }],
158
}),
159
// Omitted types should implicitly be considered as the last type
160
test({
161
code: `
162
var index = require('./');
163
var path = require('path');
164
`,
165
options: [{ groups: [
166
'index',
167
['sibling', 'parent', 'external'],
168
// missing 'builtin'
169
] }],
170
}),
171
// Mixing require and import should have import up top
172
test({
173
code: `
174
import async, {foo1} from 'async';
175
import relParent2, {foo2} from '../foo/bar';
176
import sibling, {foo3} from './foo';
177
var fs = require('fs');
178
var relParent1 = require('../foo');
179
var relParent3 = require('../');
180
var index = require('./');
181
`,
182
}),
183
...flatMap(getTSParsers(), parser => [
184
// Export equals expressions should be on top alongside with ordinary import-statements.
185
test({
186
code: `
187
import async, {foo1} from 'async';
188
import relParent2, {foo2} from '../foo/bar';
189
import sibling, {foo3} from './foo';
190
var fs = require('fs');
191
var util = require("util");
192
var relParent1 = require('../foo');
193
var relParent3 = require('../');
194
var index = require('./');
195
`,
196
parser,
197
}),
198
199
test({
200
code: `
201
export import CreateSomething = _CreateSomething;
202
`,
203
parser,
204
}),
205
]),
206
// Adding unknown import types (e.g. using a resolver alias via babel) to the groups.
207
test({
208
code: `
209
import fs from 'fs';
210
import { Input } from '-/components/Input';
211
import { Button } from '-/components/Button';
212
import { add } from './helper';`,
213
options: [{
214
groups: ['builtin', 'external', 'unknown', 'parent', 'sibling', 'index'],
215
}],
216
}),
217
// Using unknown import types (e.g. using a resolver alias via babel) with
218
// an alternative custom group list.
219
test({
220
code: `
221
import { Input } from '-/components/Input';
222
import { Button } from '-/components/Button';
223
import fs from 'fs';
224
import { add } from './helper';`,
225
options: [{
226
groups: [ 'unknown', 'builtin', 'external', 'parent', 'sibling', 'index' ],
227
}],
228
}),
229
// Using unknown import types (e.g. using a resolver alias via babel)
230
// Option: newlines-between: 'always'
231
test({
232
code: `
233
import fs from 'fs';
234
235
import { Input } from '-/components/Input';
236
import { Button } from '-/components/Button';
237
238
import p from '..';
239
import q from '../';
240
241
import { add } from './helper';
242
243
import i from '.';
244
import j from './';`,
245
options: [
246
{
247
'newlines-between': 'always',
248
groups: ['builtin', 'external', 'unknown', 'parent', 'sibling', 'index'],
249
},
250
],
251
}),
252
253
// Using pathGroups to customize ordering, position 'after'
254
test({
255
code: `
256
import fs from 'fs';
257
import _ from 'lodash';
258
import { Input } from '~/components/Input';
259
import { Button } from '#/components/Button';
260
import { add } from './helper';`,
261
options: [{
262
pathGroups: [
263
{ pattern: '~/**', group: 'external', position: 'after' },
264
{ pattern: '#/**', group: 'external', position: 'after' },
265
],
266
}],
267
}),
268
// pathGroup without position means "equal" with group
269
test({
270
code: `
271
import fs from 'fs';
272
import { Input } from '~/components/Input';
273
import async from 'async';
274
import { Button } from '#/components/Button';
275
import _ from 'lodash';
276
import { add } from './helper';`,
277
options: [{
278
pathGroups: [
279
{ pattern: '~/**', group: 'external' },
280
{ pattern: '#/**', group: 'external' },
281
],
282
}],
283
}),
284
// Using pathGroups to customize ordering, position 'before'
285
test({
286
code: `
287
import fs from 'fs';
288
289
import { Input } from '~/components/Input';
290
291
import { Button } from '#/components/Button';
292
293
import _ from 'lodash';
294
295
import { add } from './helper';`,
296
options: [{
297
'newlines-between': 'always',
298
pathGroups: [
299
{ pattern: '~/**', group: 'external', position: 'before' },
300
{ pattern: '#/**', group: 'external', position: 'before' },
301
],
302
}],
303
}),
304
// Using pathGroups to customize ordering, with patternOptions
305
test({
306
code: `
307
import fs from 'fs';
308
309
import _ from 'lodash';
310
311
import { Input } from '~/components/Input';
312
313
import { Button } from '!/components/Button';
314
315
import { add } from './helper';`,
316
options: [{
317
'newlines-between': 'always',
318
pathGroups: [
319
{ pattern: '~/**', group: 'external', position: 'after' },
320
{ pattern: '!/**', patternOptions: { nonegate: true }, group: 'external', position: 'after' },
321
],
322
}],
323
}),
324
// Using pathGroups to customize ordering for imports that are recognized as 'external'
325
// by setting pathGroupsExcludedImportTypes without 'external'
326
test({
327
code: `
328
import fs from 'fs';
329
330
import { Input } from '@app/components/Input';
331
332
import { Button } from '@app2/components/Button';
333
334
import _ from 'lodash';
335
336
import { add } from './helper';`,
337
options: [{
338
'newlines-between': 'always',
339
pathGroupsExcludedImportTypes: ['builtin'],
340
pathGroups: [
341
{ pattern: '@app/**', group: 'external', position: 'before' },
342
{ pattern: '@app2/**', group: 'external', position: 'before' },
343
],
344
}],
345
}),
346
// Using pathGroups (a test case for https://github.com/import-js/eslint-plugin-import/pull/1724)
347
test({
348
code: `
349
import fs from 'fs';
350
import external from 'external';
351
import externalTooPlease from './make-me-external';
352
353
import sibling from './sibling';`,
354
options: [{
355
'newlines-between': 'always',
356
pathGroupsExcludedImportTypes: [],
357
pathGroups: [
358
{ pattern: './make-me-external', group: 'external' },
359
],
360
groups: [['builtin', 'external'], 'internal', 'parent', 'sibling', 'index'],
361
}],
362
}),
363
// Monorepo setup, using Webpack resolver, workspace folder name in external-module-folders
364
test({
365
code: `
366
import _ from 'lodash';
367
import m from '@test-scope/some-module';
368
369
import bar from './bar';
370
`,
371
options: [{
372
'newlines-between': 'always',
373
}],
374
settings: {
375
'import/resolver': 'webpack',
376
'import/external-module-folders': ['node_modules', 'symlinked-module'],
377
},
378
}),
379
// Monorepo setup, using Node resolver (doesn't resolve symlinks)
380
test({
381
code: `
382
import _ from 'lodash';
383
import m from '@test-scope/some-module';
384
385
import bar from './bar';
386
`,
387
options: [{
388
'newlines-between': 'always',
389
}],
390
settings: {
391
'import/resolver': 'node',
392
'import/external-module-folders': ['node_modules', 'symlinked-module'],
393
},
394
}),
395
// Option: newlines-between: 'always'
396
test({
397
code: `
398
var fs = require('fs');
399
var index = require('./');
400
var path = require('path');
401
402
403
404
var sibling = require('./foo');
405
406
407
var relParent1 = require('../foo');
408
var relParent3 = require('../');
409
var async = require('async');
410
`,
411
options: [
412
{
413
groups: [
414
['builtin', 'index'],
415
['sibling'],
416
['parent', 'external'],
417
],
418
'newlines-between': 'always',
419
},
420
],
421
}),
422
// Option: newlines-between: 'never'
423
test({
424
code: `
425
var fs = require('fs');
426
var index = require('./');
427
var path = require('path');
428
var sibling = require('./foo');
429
var relParent1 = require('../foo');
430
var relParent3 = require('../');
431
var async = require('async');
432
`,
433
options: [
434
{
435
groups: [
436
['builtin', 'index'],
437
['sibling'],
438
['parent', 'external'],
439
],
440
'newlines-between': 'never',
441
},
442
],
443
}),
444
// Option: newlines-between: 'ignore'
445
test({
446
code: `
447
var fs = require('fs');
448
449
var index = require('./');
450
var path = require('path');
451
var sibling = require('./foo');
452
453
454
var relParent1 = require('../foo');
455
456
var relParent3 = require('../');
457
var async = require('async');
458
`,
459
options: [
460
{
461
groups: [
462
['builtin', 'index'],
463
['sibling'],
464
['parent', 'external'],
465
],
466
'newlines-between': 'ignore',
467
},
468
],
469
}),
470
// 'ignore' should be the default value for `newlines-between`
471
test({
472
code: `
473
var fs = require('fs');
474
475
var index = require('./');
476
var path = require('path');
477
var sibling = require('./foo');
478
479
480
var relParent1 = require('../foo');
481
482
var relParent3 = require('../');
483
484
var async = require('async');
485
`,
486
options: [
487
{
488
groups: [
489
['builtin', 'index'],
490
['sibling'],
491
['parent', 'external'],
492
],
493
},
494
],
495
}),
496
// Option newlines-between: 'always' with multiline imports #1
497
test({
498
code: `
499
import path from 'path';
500
501
import {
502
I,
503
Want,
504
Couple,
505
Imports,
506
Here
507
} from 'bar';
508
import external from 'external'
509
`,
510
options: [{ 'newlines-between': 'always' }],
511
}),
512
// Option newlines-between: 'always' with multiline imports #2
513
test({
514
code: `
515
import path from 'path';
516
import net
517
from 'net';
518
519
import external from 'external'
520
`,
521
options: [{ 'newlines-between': 'always' }],
522
}),
523
// Option newlines-between: 'always' with multiline imports #3
524
test({
525
code: `
526
import foo
527
from '../../../../this/will/be/very/long/path/and/therefore/this/import/has/to/be/in/two/lines';
528
529
import bar
530
from './sibling';
531
`,
532
options: [{ 'newlines-between': 'always' }],
533
}),
534
// Option newlines-between: 'always' with not assigned import #1
535
test({
536
code: `
537
import path from 'path';
538
539
import 'loud-rejection';
540
import 'something-else';
541
542
import _ from 'lodash';
543
`,
544
options: [{ 'newlines-between': 'always' }],
545
}),
546
// Option newlines-between: 'never' with not assigned import #2
547
test({
548
code: `
549
import path from 'path';
550
import 'loud-rejection';
551
import 'something-else';
552
import _ from 'lodash';
553
`,
554
options: [{ 'newlines-between': 'never' }],
555
}),
556
// Option newlines-between: 'always' with not assigned require #1
557
test({
558
code: `
559
var path = require('path');
560
561
require('loud-rejection');
562
require('something-else');
563
564
var _ = require('lodash');
565
`,
566
options: [{ 'newlines-between': 'always' }],
567
}),
568
// Option newlines-between: 'never' with not assigned require #2
569
test({
570
code: `
571
var path = require('path');
572
require('loud-rejection');
573
require('something-else');
574
var _ = require('lodash');
575
`,
576
options: [{ 'newlines-between': 'never' }],
577
}),
578
// Option newlines-between: 'never' should ignore nested require statement's #1
579
test({
580
code: `
581
var some = require('asdas');
582
var config = {
583
port: 4444,
584
runner: {
585
server_path: require('runner-binary').path,
586
587
cli_args: {
588
'webdriver.chrome.driver': require('browser-binary').path
589
}
590
}
591
}
592
`,
593
options: [{ 'newlines-between': 'never' }],
594
}),
595
// Option newlines-between: 'always' should ignore nested require statement's #2
596
test({
597
code: `
598
var some = require('asdas');
599
var config = {
600
port: 4444,
601
runner: {
602
server_path: require('runner-binary').path,
603
cli_args: {
604
'webdriver.chrome.driver': require('browser-binary').path
605
}
606
}
607
}
608
`,
609
options: [{ 'newlines-between': 'always' }],
610
}),
611
// Option: newlines-between: 'always-and-inside-groups'
612
test({
613
code: `
614
var fs = require('fs');
615
var path = require('path');
616
617
var util = require('util');
618
619
var async = require('async');
620
621
var relParent1 = require('../foo');
622
var relParent2 = require('../');
623
624
var relParent3 = require('../bar');
625
626
var sibling = require('./foo');
627
var sibling2 = require('./bar');
628
629
var sibling3 = require('./foobar');
630
`,
631
options: [
632
{
633
'newlines-between': 'always-and-inside-groups',
634
},
635
],
636
}),
637
// Option alphabetize: {order: 'ignore'}
638
test({
639
code: `
640
import a from 'foo';
641
import b from 'bar';
642
643
import index from './';
644
`,
645
options: [{
646
groups: ['external', 'index'],
647
alphabetize: { order: 'ignore' },
648
}],
649
}),
650
// Option alphabetize: {order: 'asc'}
651
test({
652
code: `
653
import c from 'Bar';
654
import b from 'bar';
655
import a from 'foo';
656
657
import index from './';
658
`,
659
options: [{
660
groups: ['external', 'index'],
661
alphabetize: { order: 'asc' },
662
}],
663
}),
664
// Option alphabetize: {order: 'desc'}
665
test({
666
code: `
667
import a from 'foo';
668
import b from 'bar';
669
import c from 'Bar';
670
671
import index from './';
672
`,
673
options: [{
674
groups: ['external', 'index'],
675
alphabetize: { order: 'desc' },
676
}],
677
}),
678
// Option alphabetize with newlines-between: {order: 'asc', newlines-between: 'always'}
679
test({
680
code: `
681
import b from 'Bar';
682
import c from 'bar';
683
import a from 'foo';
684
685
import index from './';
686
`,
687
options: [{
688
groups: ['external', 'index'],
689
alphabetize: { order: 'asc' },
690
'newlines-between': 'always',
691
}],
692
}),
693
// Alphabetize with require
694
test({
695
code: `
696
import { hello } from './hello';
697
import { int } from './int';
698
const blah = require('./blah');
699
const { cello } = require('./cello');
700
`,
701
options: [
702
{
703
alphabetize: {
704
order: 'asc',
705
},
706
},
707
],
708
}),
709
// Order of imports with similar names
710
test({
711
code: `
712
import React from 'react';
713
import { BrowserRouter } from 'react-router-dom';
714
`,
715
options: [
716
{
717
alphabetize: {
718
order: 'asc',
719
},
720
},
721
],
722
}),
723
test({
724
code: `
725
import { UserInputError } from 'apollo-server-express';
726
727
import { new as assertNewEmail } from '~/Assertions/Email';
728
`,
729
options: [{
730
alphabetize: {
731
caseInsensitive: true,
732
order: 'asc',
733
},
734
pathGroups: [
735
{ pattern: '~/*', group: 'internal' },
736
],
737
groups: [
738
'builtin',
739
'external',
740
'internal',
741
'parent',
742
'sibling',
743
'index',
744
],
745
'newlines-between': 'always',
746
}],
747
}),
748
test({
749
code: `
750
import { ReactElement, ReactNode } from 'react';
751
752
import { util } from 'Internal/lib';
753
754
import { parent } from '../parent';
755
756
import { sibling } from './sibling';
757
`,
758
options: [{
759
alphabetize: {
760
caseInsensitive: true,
761
order: 'asc',
762
},
763
pathGroups: [
764
{ pattern: 'Internal/**/*', group: 'internal' },
765
],
766
groups: [
767
'builtin',
768
'external',
769
'internal',
770
'parent',
771
'sibling',
772
'index',
773
],
774
'newlines-between': 'always',
775
pathGroupsExcludedImportTypes: [],
776
}],
777
}),
778
...flatMap(getTSParsers, parser => [
779
// Order of the `import ... = require(...)` syntax
780
test({
781
code: `
782
import blah = require('./blah');
783
import { hello } from './hello';`,
784
parser,
785
options: [
786
{
787
alphabetize: {
788
order: 'asc',
789
},
790
},
791
],
792
}),
793
// Order of object-imports
794
test({
795
code: `
796
import blah = require('./blah');
797
import log = console.log;`,
798
parser,
799
options: [
800
{
801
alphabetize: {
802
order: 'asc',
803
},
804
},
805
],
806
}),
807
// Object-imports should not be forced to be alphabetized
808
test({
809
code: `
810
import debug = console.debug;
811
import log = console.log;`,
812
parser,
813
options: [
814
{
815
alphabetize: {
816
order: 'asc',
817
},
818
},
819
],
820
}),
821
test({
822
code: `
823
import log = console.log;
824
import debug = console.debug;`,
825
parser,
826
options: [
827
{
828
alphabetize: {
829
order: 'asc',
830
},
831
},
832
],
833
}),
834
test({
835
code: `
836
import { a } from "./a";
837
export namespace SomeNamespace {
838
export import a2 = a;
839
}
840
`,
841
parser,
842
options: [
843
{
844
groups: ['external', 'index'],
845
alphabetize: { order: 'asc' },
846
},
847
],
848
}),
849
]),
850
],
851
invalid: [
852
// builtin before external module (require)
853
test({
854
code: `
855
var async = require('async');
856
var fs = require('fs');
857
`,
858
output: `
859
var fs = require('fs');
860
var async = require('async');
861
`,
862
errors: [{
863
message: '`fs` import should occur before import of `async`',
864
}],
865
}),
866
// fix order with spaces on the end of line
867
test({
868
code: `
869
var async = require('async');
870
var fs = require('fs');${' '}
871
`,
872
output: `
873
var fs = require('fs');${' '}
874
var async = require('async');
875
`,
876
errors: [{
877
message: '`fs` import should occur before import of `async`',
878
}],
879
}),
880
// fix order with comment on the end of line
881
test({
882
code: `
883
var async = require('async');
884
var fs = require('fs'); /* comment */
885
`,
886
output: `
887
var fs = require('fs'); /* comment */
888
var async = require('async');
889
`,
890
errors: [{
891
message: '`fs` import should occur before import of `async`',
892
}],
893
}),
894
// fix order with comments at the end and start of line
895
test({
896
code: `
897
/* comment1 */ var async = require('async'); /* comment2 */
898
/* comment3 */ var fs = require('fs'); /* comment4 */
899
`,
900
output: `
901
/* comment3 */ var fs = require('fs'); /* comment4 */
902
/* comment1 */ var async = require('async'); /* comment2 */
903
`,
904
errors: [{
905
message: '`fs` import should occur before import of `async`',
906
}],
907
}),
908
// fix order with few comments at the end and start of line
909
test({
910
code: `
911
/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */
912
/* comment3 */ var fs = require('fs'); /* comment4 */
913
`,
914
output: `
915
/* comment3 */ var fs = require('fs'); /* comment4 */
916
/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */
917
`,
918
errors: [{
919
message: '`fs` import should occur before import of `async`',
920
}],
921
}),
922
// fix order with windows end of lines
923
test({
924
code:
925
`/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */` + `\r\n` +
926
`/* comment3 */ var fs = require('fs'); /* comment4 */` + `\r\n`,
927
output:
928
`/* comment3 */ var fs = require('fs'); /* comment4 */` + `\r\n` +
929
`/* comment0 */ /* comment1 */ var async = require('async'); /* comment2 */` + `\r\n`,
930
errors: [{
931
message: '`fs` import should occur before import of `async`',
932
}],
933
}),
934
// fix order with multilines comments at the end and start of line
935
test({
936
code: `
937
/* multiline1
938
comment1 */ var async = require('async'); /* multiline2
939
comment2 */ var fs = require('fs'); /* multiline3
940
comment3 */
941
`,
942
output: `
943
/* multiline1
944
comment1 */ var fs = require('fs');` + ' ' + `
945
var async = require('async'); /* multiline2
946
comment2 *//* multiline3
947
comment3 */
948
`,
949
errors: [{
950
message: '`fs` import should occur before import of `async`',
951
}],
952
}),
953
// fix destructured commonjs import
954
test({
955
code: `
956
var {b} = require('async');
957
var {a} = require('fs');
958
`,
959
output: `
960
var {a} = require('fs');
961
var {b} = require('async');
962
`,
963
errors: [{
964
message: '`fs` import should occur before import of `async`',
965
}],
966
}),
967
// fix order of multiline import
968
test({
969
code: `
970
var async = require('async');
971
var fs =
972
require('fs');
973
`,
974
output: `
975
var fs =
976
require('fs');
977
var async = require('async');
978
`,
979
errors: [{
980
message: '`fs` import should occur before import of `async`',
981
}],
982
}),
983
// fix order at the end of file
984
test({
985
code: `
986
var async = require('async');
987
var fs = require('fs');`,
988
output: `
989
var fs = require('fs');
990
var async = require('async');` + '\n',
991
errors: [{
992
message: '`fs` import should occur before import of `async`',
993
}],
994
}),
995
// builtin before external module (import)
996
test({
997
code: `
998
import async from 'async';
999
import fs from 'fs';
1000
`,
1001
output: `
1002
import fs from 'fs';
1003
import async from 'async';
1004
`,
1005
errors: [{
1006
message: '`fs` import should occur before import of `async`',
1007
}],
1008
}),
1009
// builtin before external module (mixed import and require)
1010
test({
1011
code: `
1012
var async = require('async');
1013
import fs from 'fs';
1014
`,
1015
output: `
1016
import fs from 'fs';
1017
var async = require('async');
1018
`,
1019
errors: [{
1020
message: '`fs` import should occur before import of `async`',
1021
}],
1022
}),
1023
// external before parent
1024
test({
1025
code: `
1026
var parent = require('../parent');
1027
var async = require('async');
1028
`,
1029
output: `
1030
var async = require('async');
1031
var parent = require('../parent');
1032
`,
1033
errors: [{
1034
message: '`async` import should occur before import of `../parent`',
1035
}],
1036
}),
1037
// parent before sibling
1038
test({
1039
code: `
1040
var sibling = require('./sibling');
1041
var parent = require('../parent');
1042
`,
1043
output: `
1044
var parent = require('../parent');
1045
var sibling = require('./sibling');
1046
`,
1047
errors: [{
1048
message: '`../parent` import should occur before import of `./sibling`',
1049
}],
1050
}),
1051
// sibling before index
1052
test({
1053
code: `
1054
var index = require('./');
1055
var sibling = require('./sibling');
1056
`,
1057
output: `
1058
var sibling = require('./sibling');
1059
var index = require('./');
1060
`,
1061
errors: [{
1062
message: '`./sibling` import should occur before import of `./`',
1063
}],
1064
}),
1065
// Multiple errors
1066
...semver.satisfies(eslintPkg.version, '< 3.0.0') ? [] : [
1067
test({
1068
code: `
1069
var sibling = require('./sibling');
1070
var async = require('async');
1071
var fs = require('fs');
1072
`,
1073
output: `
1074
var async = require('async');
1075
var sibling = require('./sibling');
1076
var fs = require('fs');
1077
`,
1078
errors: [{
1079
message: '`async` import should occur before import of `./sibling`',
1080
}, {
1081
message: '`fs` import should occur before import of `./sibling`',
1082
}],
1083
}),
1084
],
1085
// Uses 'after' wording if it creates less errors
1086
test({
1087
code: `
1088
var index = require('./');
1089
var fs = require('fs');
1090
var path = require('path');
1091
var _ = require('lodash');
1092
var foo = require('foo');
1093
var bar = require('bar');
1094
`,
1095
output: `
1096
var fs = require('fs');
1097
var path = require('path');
1098
var _ = require('lodash');
1099
var foo = require('foo');
1100
var bar = require('bar');
1101
var index = require('./');
1102
`,
1103
errors: [{
1104
message: '`./` import should occur after import of `bar`',
1105
}],
1106
}),
1107
// Overriding order to be the reverse of the default order
1108
test({
1109
code: `
1110
var fs = require('fs');
1111
var index = require('./');
1112
`,
1113
output: `
1114
var index = require('./');
1115
var fs = require('fs');
1116
`,
1117
options: [{ groups: ['index', 'sibling', 'parent', 'external', 'builtin'] }],
1118
errors: [{
1119
message: '`./` import should occur before import of `fs`',
1120
}],
1121
}),
1122
// member expression of require
1123
test(withoutAutofixOutput({
1124
code: `
1125
var foo = require('./foo').bar;
1126
var fs = require('fs');
1127
`,
1128
errors: [{
1129
message: '`fs` import should occur before import of `./foo`',
1130
}],
1131
})),
1132
// nested member expression of require
1133
test(withoutAutofixOutput({
1134
code: `
1135
var foo = require('./foo').bar.bar.bar;
1136
var fs = require('fs');
1137
`,
1138
errors: [{
1139
message: '`fs` import should occur before import of `./foo`',
1140
}],
1141
})),
1142
// fix near nested member expression of require with newlines
1143
test(withoutAutofixOutput({
1144
code: `
1145
var foo = require('./foo').bar
1146
.bar
1147
.bar;
1148
var fs = require('fs');
1149
`,
1150
errors: [{
1151
message: '`fs` import should occur before import of `./foo`',
1152
}],
1153
})),
1154
// fix nested member expression of require with newlines
1155
test(withoutAutofixOutput({
1156
code: `
1157
var foo = require('./foo');
1158
var fs = require('fs').bar
1159
.bar
1160
.bar;
1161
`,
1162
errors: [{
1163
message: '`fs` import should occur before import of `./foo`',
1164
}],
1165
})),
1166
// Grouping import types
1167
test({
1168
code: `
1169
var fs = require('fs');
1170
var index = require('./');
1171
var sibling = require('./foo');
1172
var path = require('path');
1173
`,
1174
output: `
1175
var fs = require('fs');
1176
var index = require('./');
1177
var path = require('path');
1178
var sibling = require('./foo');
1179
`,
1180
options: [{ groups: [
1181
['builtin', 'index'],
1182
['sibling', 'parent', 'external'],
1183
] }],
1184
errors: [{
1185
message: '`path` import should occur before import of `./foo`',
1186
}],
1187
}),
1188
// Omitted types should implicitly be considered as the last type
1189
test({
1190
code: `
1191
var path = require('path');
1192
var async = require('async');
1193
`,
1194
output: `
1195
var async = require('async');
1196
var path = require('path');
1197
`,
1198
options: [{ groups: [
1199
'index',
1200
['sibling', 'parent', 'external', 'internal'],
1201
// missing 'builtin'
1202
] }],
1203
errors: [{
1204
message: '`async` import should occur before import of `path`',
1205
}],
1206
}),
1207
// Setting the order for an unknown type
1208
// should make the rule trigger an error and do nothing else
1209
test({
1210
code: `
1211
var async = require('async');
1212
var index = require('./');
1213
`,
1214
options: [{ groups: [
1215
'index',
1216
['sibling', 'parent', 'UNKNOWN', 'internal'],
1217
] }],
1218
errors: [{
1219
message: 'Incorrect configuration of the rule: Unknown type `"UNKNOWN"`',
1220
}],
1221
}),
1222
// Type in an array can't be another array, too much nesting
1223
test({
1224
code: `
1225
var async = require('async');
1226
var index = require('./');
1227
`,
1228
options: [{ groups: [
1229
'index',
1230
['sibling', 'parent', ['builtin'], 'internal'],
1231
] }],
1232
errors: [{
1233
message: 'Incorrect configuration of the rule: Unknown type `["builtin"]`',
1234
}],
1235
}),
1236
// No numbers
1237
test({
1238
code: `
1239
var async = require('async');
1240
var index = require('./');
1241
`,
1242
options: [{ groups: [
1243
'index',
1244
['sibling', 'parent', 2, 'internal'],
1245
] }],
1246
errors: [{
1247
message: 'Incorrect configuration of the rule: Unknown type `2`',
1248
}],
1249
}),
1250
// Duplicate
1251
test({
1252
code: `
1253
var async = require('async');
1254
var index = require('./');
1255
`,
1256
options: [{ groups: [
1257
'index',
1258
['sibling', 'parent', 'parent', 'internal'],
1259
] }],
1260
errors: [{
1261
message: 'Incorrect configuration of the rule: `parent` is duplicated',
1262
}],
1263
}),
1264
// Mixing require and import should have import up top
1265
test({
1266
code: `
1267
import async, {foo1} from 'async';
1268
import relParent2, {foo2} from '../foo/bar';
1269
var fs = require('fs');
1270
var relParent1 = require('../foo');
1271
var relParent3 = require('../');
1272
import sibling, {foo3} from './foo';
1273
var index = require('./');
1274
`,
1275
output: `
1276
import async, {foo1} from 'async';
1277
import relParent2, {foo2} from '../foo/bar';
1278
import sibling, {foo3} from './foo';
1279
var fs = require('fs');
1280
var relParent1 = require('../foo');
1281
var relParent3 = require('../');
1282
var index = require('./');
1283
`,
1284
errors: [{
1285
message: '`./foo` import should occur before import of `fs`',
1286
}],
1287
}),
1288
test({
1289
code: `
1290
var fs = require('fs');
1291
import async, {foo1} from 'async';
1292
import relParent2, {foo2} from '../foo/bar';
1293
`,
1294
output: `
1295
import async, {foo1} from 'async';
1296
import relParent2, {foo2} from '../foo/bar';
1297
var fs = require('fs');
1298
`,
1299
errors: [{
1300
message: '`fs` import should occur after import of `../foo/bar`',
1301
}],
1302
}),
1303
...flatMap(getTSParsers(), parser => [
1304
// Order of the `import ... = require(...)` syntax
1305
test({
1306
code: `
1307
var fs = require('fs');
1308
import async, {foo1} from 'async';
1309
import bar = require("../foo/bar");
1310
`,
1311
output: `
1312
import async, {foo1} from 'async';
1313
import bar = require("../foo/bar");
1314
var fs = require('fs');
1315
`,
1316
parser,
1317
errors: [{
1318
message: '`fs` import should occur after import of `../foo/bar`',
1319
}],
1320
}),
1321
test({
1322
code: `
1323
var async = require('async');
1324
var fs = require('fs');
1325
`,
1326
output: `
1327
var fs = require('fs');
1328
var async = require('async');
1329
`,
1330
parser,
1331
errors: [{
1332
message: '`fs` import should occur before import of `async`',
1333
}],
1334
}),
1335
test({
1336
code: `
1337
import sync = require('sync');
1338
import async, {foo1} from 'async';
1339
1340
import index from './';
1341
`,
1342
output: `
1343
import async, {foo1} from 'async';
1344
import sync = require('sync');
1345
1346
import index from './';
1347
`,
1348
options: [{
1349
groups: ['external', 'index'],
1350
alphabetize: { order: 'asc' },
1351
}],
1352
parser,
1353
errors: [{
1354
message: '`async` import should occur before import of `sync`',
1355
}],
1356
}),
1357
// Order of object-imports
1358
test({
1359
code: `
1360
import log = console.log;
1361
import blah = require('./blah');`,
1362
parser,
1363
errors: [{
1364
message: '`./blah` import should occur before import of `console.log`',
1365
}],
1366
}),
1367
]),
1368
// Default order using import with custom import alias
1369
test({
1370
code: `
1371
import { Button } from '-/components/Button';
1372
import { add } from './helper';
1373
import fs from 'fs';
1374
`,
1375
output: `
1376
import fs from 'fs';
1377
import { Button } from '-/components/Button';
1378
import { add } from './helper';
1379
`,
1380
options: [
1381
{
1382
groups: ['builtin', 'external', 'unknown', 'parent', 'sibling', 'index'],
1383
},
1384
],
1385
errors: [
1386
{
1387
line: 4,
1388
message: '`fs` import should occur before import of `-/components/Button`',
1389
},
1390
],
1391
}),
1392
// Default order using import with custom import alias
1393
test({
1394
code: `
1395
import fs from 'fs';
1396
import { Button } from '-/components/Button';
1397
import { LinkButton } from '-/components/Link';
1398
import { add } from './helper';
1399
`,
1400
output: `
1401
import fs from 'fs';
1402
1403
import { Button } from '-/components/Button';
1404
import { LinkButton } from '-/components/Link';
1405
1406
import { add } from './helper';
1407
`,
1408
options: [
1409
{
1410
groups: ['builtin', 'external', 'unknown', 'parent', 'sibling', 'index'],
1411
'newlines-between': 'always',
1412
},
1413
],
1414
errors: [
1415
{
1416
line: 2,
1417
message: 'There should be at least one empty line between import groups',
1418
},
1419
{
1420
line: 4,
1421
message: 'There should be at least one empty line between import groups',
1422
},
1423
],
1424
}),
1425
// Option newlines-between: 'never' - should report unnecessary line between groups
1426
test({
1427
code: `
1428
var fs = require('fs');
1429
var index = require('./');
1430
var path = require('path');
1431
1432
var sibling = require('./foo');
1433
1434
var relParent1 = require('../foo');
1435
var relParent3 = require('../');
1436
var async = require('async');
1437
`,
1438
output: `
1439
var fs = require('fs');
1440
var index = require('./');
1441
var path = require('path');
1442
var sibling = require('./foo');
1443
var relParent1 = require('../foo');
1444
var relParent3 = require('../');
1445
var async = require('async');
1446
`,
1447
options: [
1448
{
1449
groups: [
1450
['builtin', 'index'],
1451
['sibling'],
1452
['parent', 'external'],
1453
],
1454
'newlines-between': 'never',
1455
},
1456
],
1457
errors: [
1458
{
1459
line: 4,
1460
message: 'There should be no empty line between import groups',
1461
},
1462
{
1463
line: 6,
1464
message: 'There should be no empty line between import groups',
1465
},
1466
],
1467
}),
1468
// Fix newlines-between with comments after
1469
test({
1470
code: `
1471
var fs = require('fs'); /* comment */
1472
1473
var index = require('./');
1474
`,
1475
output: `
1476
var fs = require('fs'); /* comment */
1477
var index = require('./');
1478
`,
1479
options: [
1480
{
1481
groups: [['builtin'], ['index']],
1482
'newlines-between': 'never',
1483
},
1484
],
1485
errors: [
1486
{
1487
line: 2,
1488
message: 'There should be no empty line between import groups',
1489
},
1490
],
1491
}),
1492
// Cannot fix newlines-between with multiline comment after
1493
test({
1494
code: `
1495
var fs = require('fs'); /* multiline
1496
comment */
1497
1498
var index = require('./');
1499
`,
1500
output: `
1501
var fs = require('fs'); /* multiline
1502
comment */
1503
1504
var index = require('./');
1505
`,
1506
options: [
1507
{
1508
groups: [['builtin'], ['index']],
1509
'newlines-between': 'never',
1510
},
1511
],
1512
errors: [
1513
{
1514
line: 2,
1515
message: 'There should be no empty line between import groups',
1516
},
1517
],
1518
}),
1519
// Option newlines-between: 'always' - should report lack of newline between groups
1520
test({
1521
code: `
1522
var fs = require('fs');
1523
var index = require('./');
1524
var path = require('path');
1525
var sibling = require('./foo');
1526
var relParent1 = require('../foo');
1527
var relParent3 = require('../');
1528
var async = require('async');
1529
`,
1530
output: `
1531
var fs = require('fs');
1532
var index = require('./');
1533
var path = require('path');
1534
1535
var sibling = require('./foo');
1536
1537
var relParent1 = require('../foo');
1538
var relParent3 = require('../');
1539
var async = require('async');
1540
`,
1541
options: [
1542
{
1543
groups: [
1544
['builtin', 'index'],
1545
['sibling'],
1546
['parent', 'external'],
1547
],
1548
'newlines-between': 'always',
1549
},
1550
],
1551
errors: [
1552
{
1553
line: 4,
1554
message: 'There should be at least one empty line between import groups',
1555
},
1556
{
1557
line: 5,
1558
message: 'There should be at least one empty line between import groups',
1559
},
1560
],
1561
}),
1562
// Option newlines-between: 'always' should report unnecessary empty lines space between import groups
1563
test({
1564
code: `
1565
var fs = require('fs');
1566
1567
var path = require('path');
1568
var index = require('./');
1569
1570
var sibling = require('./foo');
1571
1572
var async = require('async');
1573
`,
1574
output: `
1575
var fs = require('fs');
1576
var path = require('path');
1577
var index = require('./');
1578
1579
var sibling = require('./foo');
1580
var async = require('async');
1581
`,
1582
options: [
1583
{
1584
groups: [
1585
['builtin', 'index'],
1586
['sibling', 'parent', 'external'],
1587
],
1588
'newlines-between': 'always',
1589
},
1590
],
1591
errors: [
1592
{
1593
line: 2,
1594
message: 'There should be no empty line within import group',
1595
},
1596
{
1597
line: 7,
1598
message: 'There should be no empty line within import group',
1599
},
1600
],
1601
}),
1602
// Option newlines-between: 'never' with unassigned imports and warnOnUnassignedImports disabled
1603
// newline is preserved to match existing behavior
1604
test({
1605
code: `
1606
import path from 'path';
1607
import 'loud-rejection';
1608
1609
import 'something-else';
1610
import _ from 'lodash';
1611
`,
1612
output: `
1613
import path from 'path';
1614
import 'loud-rejection';
1615
1616
import 'something-else';
1617
import _ from 'lodash';
1618
`,
1619
options: [{ 'newlines-between': 'never', warnOnUnassignedImports: false }],
1620
errors: [
1621
{
1622
line: 2,
1623
message: 'There should be no empty line between import groups',
1624
},
1625
],
1626
}),
1627
// Option newlines-between: 'never' with unassigned imports and warnOnUnassignedImports enabled
1628
test({
1629
code: `
1630
import path from 'path';
1631
import 'loud-rejection';
1632
1633
import 'something-else';
1634
import _ from 'lodash';
1635
`,
1636
output: `
1637
import path from 'path';
1638
import 'loud-rejection';
1639
import 'something-else';
1640
import _ from 'lodash';
1641
`,
1642
options: [{ 'newlines-between': 'never', warnOnUnassignedImports: true }],
1643
errors: [
1644
{
1645
line: 3,
1646
message: 'There should be no empty line between import groups',
1647
},
1648
],
1649
}),
1650
// Option newlines-between: 'never' cannot fix if there are other statements between imports
1651
test({
1652
code: `
1653
import path from 'path';
1654
export const abc = 123;
1655
1656
import 'something-else';
1657
import _ from 'lodash';
1658
`,
1659
output: `
1660
import path from 'path';
1661
export const abc = 123;
1662
1663
import 'something-else';
1664
import _ from 'lodash';
1665
`,
1666
options: [{ 'newlines-between': 'never' }],
1667
errors: [
1668
{
1669
line: 2,
1670
message: 'There should be no empty line between import groups',
1671
},
1672
],
1673
}),
1674
// Option newlines-between: 'always' should report missing empty lines when using not assigned imports
1675
test({
1676
code: `
1677
import path from 'path';
1678
import 'loud-rejection';
1679
import 'something-else';
1680
import _ from 'lodash';
1681
`,
1682
output: `
1683
import path from 'path';
1684
1685
import 'loud-rejection';
1686
import 'something-else';
1687
import _ from 'lodash';
1688
`,
1689
options: [{ 'newlines-between': 'always' }],
1690
errors: [
1691
{
1692
line: 2,
1693
message: 'There should be at least one empty line between import groups',
1694
},
1695
],
1696
}),
1697
// fix missing empty lines with single line comment after
1698
test({
1699
code: `
1700
import path from 'path'; // comment
1701
import _ from 'lodash';
1702
`,
1703
output: `
1704
import path from 'path'; // comment
1705
1706
import _ from 'lodash';
1707
`,
1708
options: [{ 'newlines-between': 'always' }],
1709
errors: [
1710
{
1711
line: 2,
1712
message: 'There should be at least one empty line between import groups',
1713
},
1714
],
1715
}),
1716
// fix missing empty lines with few line block comment after
1717
test({
1718
code: `
1719
import path from 'path'; /* comment */ /* comment */
1720
import _ from 'lodash';
1721
`,
1722
output: `
1723
import path from 'path'; /* comment */ /* comment */
1724
1725
import _ from 'lodash';
1726
`,
1727
options: [{ 'newlines-between': 'always' }],
1728
errors: [
1729
{
1730
line: 2,
1731
message: 'There should be at least one empty line between import groups',
1732
},
1733
],
1734
}),
1735
// fix missing empty lines with single line block comment after
1736
test({
1737
code: `
1738
import path from 'path'; /* 1
1739
2 */
1740
import _ from 'lodash';
1741
`,
1742
output: `
1743
import path from 'path';
1744
/* 1
1745
2 */
1746
import _ from 'lodash';
1747
`,
1748
options: [{ 'newlines-between': 'always' }],
1749
errors: [
1750
{
1751
line: 2,
1752
message: 'There should be at least one empty line between import groups',
1753
},
1754
],
1755
}),
1756
// reorder fix cannot cross function call on moving below #1
1757
test({
1758
code: `
1759
const local = require('./local');
1760
1761
fn_call();
1762
1763
const global1 = require('global1');
1764
const global2 = require('global2');
1765
1766
fn_call();
1767
`,
1768
output: `
1769
const local = require('./local');
1770
1771
fn_call();
1772
1773
const global1 = require('global1');
1774
const global2 = require('global2');
1775
1776
fn_call();
1777
`,
1778
errors: [{
1779
message: '`./local` import should occur after import of `global2`',
1780
}],
1781
}),
1782
// reorder fix cannot cross function call on moving below #2
1783
test({
1784
code: `
1785
const local = require('./local');
1786
fn_call();
1787
const global1 = require('global1');
1788
const global2 = require('global2');
1789
1790
fn_call();
1791
`,
1792
output: `
1793
const local = require('./local');
1794
fn_call();
1795
const global1 = require('global1');
1796
const global2 = require('global2');
1797
1798
fn_call();
1799
`,
1800
errors: [{
1801
message: '`./local` import should occur after import of `global2`',
1802
}],
1803
}),
1804
// reorder fix cannot cross function call on moving below #3
1805
test({
1806
code: `
1807
const local1 = require('./local1');
1808
const local2 = require('./local2');
1809
const local3 = require('./local3');
1810
const local4 = require('./local4');
1811
fn_call();
1812
const global1 = require('global1');
1813
const global2 = require('global2');
1814
const global3 = require('global3');
1815
const global4 = require('global4');
1816
const global5 = require('global5');
1817
fn_call();
1818
`,
1819
output: `
1820
const local1 = require('./local1');
1821
const local2 = require('./local2');
1822
const local3 = require('./local3');
1823
const local4 = require('./local4');
1824
fn_call();
1825
const global1 = require('global1');
1826
const global2 = require('global2');
1827
const global3 = require('global3');
1828
const global4 = require('global4');
1829
const global5 = require('global5');
1830
fn_call();
1831
`,
1832
errors: [
1833
'`./local1` import should occur after import of `global5`',
1834
'`./local2` import should occur after import of `global5`',
1835
'`./local3` import should occur after import of `global5`',
1836
'`./local4` import should occur after import of `global5`',
1837
],
1838
}),
1839
// reorder fix cannot cross function call on moving below
1840
test(withoutAutofixOutput({
1841
code: `
1842
const local = require('./local');
1843
const global1 = require('global1');
1844
const global2 = require('global2');
1845
fn_call();
1846
const global3 = require('global3');
1847
1848
fn_call();
1849
`,
1850
errors: [{
1851
message: '`./local` import should occur after import of `global3`',
1852
}],
1853
})),
1854
// reorder fix cannot cross function call on moving below
1855
// fix imports that not crosses function call only
1856
test({
1857
code: `
1858
const local1 = require('./local1');
1859
const global1 = require('global1');
1860
const global2 = require('global2');
1861
fn_call();
1862
const local2 = require('./local2');
1863
const global3 = require('global3');
1864
const global4 = require('global4');
1865
1866
fn_call();
1867
`,
1868
output: `
1869
const local1 = require('./local1');
1870
const global1 = require('global1');
1871
const global2 = require('global2');
1872
fn_call();
1873
const global3 = require('global3');
1874
const global4 = require('global4');
1875
const local2 = require('./local2');
1876
1877
fn_call();
1878
`,
1879
errors: [
1880
'`./local1` import should occur after import of `global4`',
1881
'`./local2` import should occur after import of `global4`',
1882
],
1883
}),
1884
// pathGroup with position 'after'
1885
test({
1886
code: `
1887
import fs from 'fs';
1888
import _ from 'lodash';
1889
import { add } from './helper';
1890
import { Input } from '~/components/Input';
1891
`,
1892
output: `
1893
import fs from 'fs';
1894
import _ from 'lodash';
1895
import { Input } from '~/components/Input';
1896
import { add } from './helper';
1897
`,
1898
options: [{
1899
pathGroups: [
1900
{ pattern: '~/**', group: 'external', position: 'after' },
1901
],
1902
}],
1903
errors: [{
1904
message: '`~/components/Input` import should occur before import of `./helper`',
1905
}],
1906
}),
1907
// pathGroup without position
1908
test({
1909
code: `
1910
import fs from 'fs';
1911
import _ from 'lodash';
1912
import { add } from './helper';
1913
import { Input } from '~/components/Input';
1914
import async from 'async';
1915
`,
1916
output: `
1917
import fs from 'fs';
1918
import _ from 'lodash';
1919
import { Input } from '~/components/Input';
1920
import async from 'async';
1921
import { add } from './helper';
1922
`,
1923
options: [{
1924
pathGroups: [
1925
{ pattern: '~/**', group: 'external' },
1926
],
1927
}],
1928
errors: [{
1929
message: '`./helper` import should occur after import of `async`',
1930
}],
1931
}),
1932
// pathGroup with position 'before'
1933
test({
1934
code: `
1935
import fs from 'fs';
1936
import _ from 'lodash';
1937
import { add } from './helper';
1938
import { Input } from '~/components/Input';
1939
`,
1940
output: `
1941
import fs from 'fs';
1942
import { Input } from '~/components/Input';
1943
import _ from 'lodash';
1944
import { add } from './helper';
1945
`,
1946
options: [{
1947
pathGroups: [
1948
{ pattern: '~/**', group: 'external', position: 'before' },
1949
],
1950
}],
1951
errors: [{
1952
message: '`~/components/Input` import should occur before import of `lodash`',
1953
}],
1954
}),
1955
// multiple pathGroup with different positions for same group, fix for 'after'
1956
test({
1957
code: `
1958
import fs from 'fs';
1959
import { Import } from '$/components/Import';
1960
import _ from 'lodash';
1961
import { Output } from '~/components/Output';
1962
import { Input } from '#/components/Input';
1963
import { add } from './helper';
1964
import { Export } from '-/components/Export';
1965
`,
1966
output: `
1967
import fs from 'fs';
1968
import { Export } from '-/components/Export';
1969
import { Import } from '$/components/Import';
1970
import _ from 'lodash';
1971
import { Output } from '~/components/Output';
1972
import { Input } from '#/components/Input';
1973
import { add } from './helper';
1974
`,
1975
options: [{
1976
pathGroups: [
1977
{ pattern: '~/**', group: 'external', position: 'after' },
1978
{ pattern: '#/**', group: 'external', position: 'after' },
1979
{ pattern: '-/**', group: 'external', position: 'before' },
1980
{ pattern: '$/**', group: 'external', position: 'before' },
1981
],
1982
}],
1983
errors: [
1984
{
1985
message: '`-/components/Export` import should occur before import of `$/components/Import`',
1986
},
1987
],
1988
}),
1989
1990
// multiple pathGroup with different positions for same group, fix for 'before'
1991
test({
1992
code: `
1993
import fs from 'fs';
1994
import { Export } from '-/components/Export';
1995
import { Import } from '$/components/Import';
1996
import _ from 'lodash';
1997
import { Input } from '#/components/Input';
1998
import { add } from './helper';
1999
import { Output } from '~/components/Output';
2000
`,
2001
output: `
2002
import fs from 'fs';
2003
import { Export } from '-/components/Export';
2004
import { Import } from '$/components/Import';
2005
import _ from 'lodash';
2006
import { Output } from '~/components/Output';
2007
import { Input } from '#/components/Input';
2008
import { add } from './helper';
2009
`,
2010
options: [{
2011
pathGroups: [
2012
{ pattern: '~/**', group: 'external', position: 'after' },
2013
{ pattern: '#/**', group: 'external', position: 'after' },
2014
{ pattern: '-/**', group: 'external', position: 'before' },
2015
{ pattern: '$/**', group: 'external', position: 'before' },
2016
],
2017
}],
2018
errors: [
2019
{
2020
message: '`~/components/Output` import should occur before import of `#/components/Input`',
2021
},
2022
],
2023
}),
2024
2025
// reorder fix cannot cross non import or require
2026
test(withoutAutofixOutput({
2027
code: `
2028
var async = require('async');
2029
fn_call();
2030
var fs = require('fs');
2031
`,
2032
errors: [{
2033
message: '`fs` import should occur before import of `async`',
2034
}],
2035
})),
2036
// reorder fix cannot cross function call on moving below (from #1252)
2037
test({
2038
code: `
2039
const env = require('./config');
2040
2041
Object.keys(env);
2042
2043
const http = require('http');
2044
const express = require('express');
2045
2046
http.createServer(express());
2047
`,
2048
output: `
2049
const env = require('./config');
2050
2051
Object.keys(env);
2052
2053
const http = require('http');
2054
const express = require('express');
2055
2056
http.createServer(express());
2057
`,
2058
errors: [{
2059
message: '`./config` import should occur after import of `express`',
2060
}],
2061
}),
2062
// reorder cannot cross non plain requires
2063
test(withoutAutofixOutput({
2064
code: `
2065
var async = require('async');
2066
var a = require('./value.js')(a);
2067
var fs = require('fs');
2068
`,
2069
errors: [{
2070
message: '`fs` import should occur before import of `async`',
2071
}],
2072
})),
2073
// reorder fixes cannot be applied to non plain requires #1
2074
test(withoutAutofixOutput({
2075
code: `
2076
var async = require('async');
2077
var fs = require('fs')(a);
2078
`,
2079
errors: [{
2080
message: '`fs` import should occur before import of `async`',
2081
}],
2082
})),
2083
// reorder fixes cannot be applied to non plain requires #2
2084
test(withoutAutofixOutput({
2085
code: `
2086
var async = require('async')(a);
2087
var fs = require('fs');
2088
`,
2089
errors: [{
2090
message: '`fs` import should occur before import of `async`',
2091
}],
2092
})),
2093
// cannot require in case of not assignment require
2094
test(withoutAutofixOutput({
2095
code: `
2096
var async = require('async');
2097
require('./aa');
2098
var fs = require('fs');
2099
`,
2100
errors: [{
2101
message: '`fs` import should occur before import of `async`',
2102
}],
2103
})),
2104
// reorder cannot cross function call (import statement)
2105
test(withoutAutofixOutput({
2106
code: `
2107
import async from 'async';
2108
fn_call();
2109
import fs from 'fs';
2110
`,
2111
errors: [{
2112
message: '`fs` import should occur before import of `async`',
2113
}],
2114
})),
2115
// reorder cannot cross variable assignment (import statement)
2116
test(withoutAutofixOutput({
2117
code: `
2118
import async from 'async';
2119
var a = 1;
2120
import fs from 'fs';
2121
`,
2122
errors: [{
2123
message: '`fs` import should occur before import of `async`',
2124
}],
2125
})),
2126
// reorder cannot cross non plain requires (import statement)
2127
test(withoutAutofixOutput({
2128
code: `
2129
import async from 'async';
2130
var a = require('./value.js')(a);
2131
import fs from 'fs';
2132
`,
2133
errors: [{
2134
message: '`fs` import should occur before import of `async`',
2135
}],
2136
})),
2137
// cannot reorder in case of not assignment import
2138
test(withoutAutofixOutput({
2139
code: `
2140
import async from 'async';
2141
import './aa';
2142
import fs from 'fs';
2143
`,
2144
errors: [{
2145
message: '`fs` import should occur before import of `async`',
2146
}],
2147
})),
2148
// Option alphabetize: {order: 'asc'}
2149
test({
2150
code: `
2151
import b from 'bar';
2152
import c from 'Bar';
2153
import a from 'foo';
2154
2155
import index from './';
2156
`,
2157
output: `
2158
import c from 'Bar';
2159
import b from 'bar';
2160
import a from 'foo';
2161
2162
import index from './';
2163
`,
2164
options: [{
2165
groups: ['external', 'index'],
2166
alphabetize: { order: 'asc' },
2167
}],
2168
errors: [{
2169
message: '`Bar` import should occur before import of `bar`',
2170
}],
2171
}),
2172
// Option alphabetize: {order: 'desc'}
2173
test({
2174
code: `
2175
import a from 'foo';
2176
import c from 'Bar';
2177
import b from 'bar';
2178
2179
import index from './';
2180
`,
2181
output: `
2182
import a from 'foo';
2183
import b from 'bar';
2184
import c from 'Bar';
2185
2186
import index from './';
2187
`,
2188
options: [{
2189
groups: ['external', 'index'],
2190
alphabetize: { order: 'desc' },
2191
}],
2192
errors: [{
2193
message: '`bar` import should occur before import of `Bar`',
2194
}],
2195
}),
2196
// Option alphabetize {order: 'asc': caseInsensitive: true}
2197
test({
2198
code: `
2199
import b from 'foo';
2200
import a from 'Bar';
2201
2202
import index from './';
2203
`,
2204
output: `
2205
import a from 'Bar';
2206
import b from 'foo';
2207
2208
import index from './';
2209
`,
2210
options: [{
2211
groups: ['external', 'index'],
2212
alphabetize: { order: 'asc', caseInsensitive: true },
2213
}],
2214
errors: [{
2215
message: '`Bar` import should occur before import of `foo`',
2216
}],
2217
}),
2218
// Option alphabetize {order: 'desc': caseInsensitive: true}
2219
test({
2220
code: `
2221
import a from 'Bar';
2222
import b from 'foo';
2223
2224
import index from './';
2225
`,
2226
output: `
2227
import b from 'foo';
2228
import a from 'Bar';
2229
2230
import index from './';
2231
`,
2232
options: [{
2233
groups: ['external', 'index'],
2234
alphabetize: { order: 'desc', caseInsensitive: true },
2235
}],
2236
errors: [{
2237
message: '`foo` import should occur before import of `Bar`',
2238
}],
2239
}),
2240
// Alphabetize with parent paths
2241
test({
2242
code: `
2243
import a from '../a';
2244
import p from '..';
2245
`,
2246
output: `
2247
import p from '..';
2248
import a from '../a';
2249
`,
2250
options: [{
2251
groups: ['external', 'index'],
2252
alphabetize: { order: 'asc' },
2253
}],
2254
errors: [{
2255
message: '`..` import should occur before import of `../a`',
2256
}],
2257
}),
2258
// Alphabetize with require
2259
...semver.satisfies(eslintPkg.version, '< 3.0.0') ? [] : [
2260
test({
2261
code: `
2262
const { cello } = require('./cello');
2263
import { int } from './int';
2264
const blah = require('./blah');
2265
import { hello } from './hello';
2266
`,
2267
output: `
2268
import { int } from './int';
2269
const { cello } = require('./cello');
2270
const blah = require('./blah');
2271
import { hello } from './hello';
2272
`,
2273
errors: [{
2274
message: '`./int` import should occur before import of `./cello`',
2275
}, {
2276
message: '`./hello` import should occur before import of `./cello`',
2277
}],
2278
}),
2279
],
2280
].filter((t) => !!t),
2281
});
2282
2283
2284
context('TypeScript', function () {
2285
getNonDefaultParsers()
2286
// Type-only imports were added in TypeScript ESTree 2.23.0
2287
.filter((parser) => parser !== require.resolve('typescript-eslint-parser'))
2288
.forEach((parser) => {
2289
const parserConfig = {
2290
parser,
2291
settings: {
2292
'import/parsers': { [parser]: ['.ts'] },
2293
'import/resolver': { 'eslint-import-resolver-typescript': true },
2294
},
2295
};
2296
2297
ruleTester.run('order', rule, {
2298
valid: [
2299
// #1667: typescript type import support
2300
2301
// Option alphabetize: {order: 'asc'}
2302
test({
2303
code: `
2304
import c from 'Bar';
2305
import type { C } from 'Bar';
2306
import b from 'bar';
2307
import a from 'foo';
2308
import type { A } from 'foo';
2309
2310
import index from './';
2311
`,
2312
...parserConfig,
2313
options: [
2314
{
2315
groups: ['external', 'index'],
2316
alphabetize: { order: 'asc' },
2317
},
2318
],
2319
}),
2320
// Option alphabetize: {order: 'desc'}
2321
test({
2322
code: `
2323
import a from 'foo';
2324
import type { A } from 'foo';
2325
import b from 'bar';
2326
import c from 'Bar';
2327
import type { C } from 'Bar';
2328
2329
import index from './';
2330
`,
2331
...parserConfig,
2332
options: [
2333
{
2334
groups: ['external', 'index'],
2335
alphabetize: { order: 'desc' },
2336
},
2337
],
2338
}),
2339
// Option alphabetize: {order: 'asc'} with type group
2340
test({
2341
code: `
2342
import c from 'Bar';
2343
import b from 'bar';
2344
import a from 'foo';
2345
2346
import index from './';
2347
2348
import type { C } from 'Bar';
2349
import type { A } from 'foo';
2350
`,
2351
...parserConfig,
2352
options: [
2353
{
2354
groups: ['external', 'index', 'type'],
2355
alphabetize: { order: 'asc' },
2356
},
2357
],
2358
}),
2359
// Option alphabetize: {order: 'asc'} with type group & path group
2360
test({
2361
// only: true,
2362
code: `
2363
import c from 'Bar';
2364
import a from 'foo';
2365
2366
import b from 'dirA/bar';
2367
2368
import index from './';
2369
2370
import type { C } from 'dirA/Bar';
2371
import type { A } from 'foo';
2372
`,
2373
...parserConfig,
2374
options: [
2375
{
2376
alphabetize: { order: 'asc' },
2377
groups: ['external', 'internal', 'index', 'type'],
2378
pathGroups: [
2379
{
2380
pattern: 'dirA/**',
2381
group: 'internal',
2382
},
2383
],
2384
'newlines-between': 'always',
2385
pathGroupsExcludedImportTypes: ['type'],
2386
},
2387
],
2388
}),
2389
// Option alphabetize: {order: 'asc'} with path group
2390
test({
2391
// only: true,
2392
code: `
2393
import c from 'Bar';
2394
import type { A } from 'foo';
2395
import a from 'foo';
2396
2397
import type { C } from 'dirA/Bar';
2398
import b from 'dirA/bar';
2399
2400
import index from './';
2401
`,
2402
...parserConfig,
2403
options: [
2404
{
2405
alphabetize: { order: 'asc' },
2406
groups: ['external', 'internal', 'index'],
2407
pathGroups: [
2408
{
2409
pattern: 'dirA/**',
2410
group: 'internal',
2411
},
2412
],
2413
'newlines-between': 'always',
2414
pathGroupsExcludedImportTypes: [],
2415
},
2416
],
2417
}),
2418
// Option alphabetize: {order: 'desc'} with type group
2419
test({
2420
code: `
2421
import a from 'foo';
2422
import b from 'bar';
2423
import c from 'Bar';
2424
2425
import index from './';
2426
2427
import type { A } from 'foo';
2428
import type { C } from 'Bar';
2429
`,
2430
...parserConfig,
2431
options: [
2432
{
2433
groups: ['external', 'index', 'type'],
2434
alphabetize: { order: 'desc' },
2435
},
2436
],
2437
}),
2438
test({
2439
code: `
2440
import { Partner } from '@models/partner/partner';
2441
import { PartnerId } from '@models/partner/partner-id';
2442
`,
2443
...parserConfig,
2444
options: [
2445
{
2446
alphabetize: { order: 'asc' },
2447
},
2448
],
2449
}),
2450
test({
2451
code: `
2452
import { serialize, parse, mapFieldErrors } from '@vtaits/form-schema';
2453
import type { GetFieldSchema } from '@vtaits/form-schema';
2454
import { useMemo, useCallback } from 'react';
2455
import type { ReactElement, ReactNode } from 'react';
2456
import { Form } from 'react-final-form';
2457
import type { FormProps as FinalFormProps } from 'react-final-form';
2458
`,
2459
...parserConfig,
2460
options: [
2461
{
2462
alphabetize: { order: 'asc' },
2463
},
2464
],
2465
}),
2466
// Imports inside module declaration
2467
test({
2468
code: `
2469
import type { CopyOptions } from 'fs';
2470
import type { ParsedPath } from 'path';
2471
2472
declare module 'my-module' {
2473
import type { CopyOptions } from 'fs';
2474
import type { ParsedPath } from 'path';
2475
}
2476
`,
2477
...parserConfig,
2478
options: [
2479
{
2480
alphabetize: { order: 'asc' },
2481
},
2482
],
2483
}),
2484
],
2485
invalid: [
2486
// Option alphabetize: {order: 'asc'}
2487
test({
2488
code: `
2489
import b from 'bar';
2490
import c from 'Bar';
2491
import type { C } from 'Bar';
2492
import a from 'foo';
2493
import type { A } from 'foo';
2494
2495
import index from './';
2496
`,
2497
output: `
2498
import c from 'Bar';
2499
import type { C } from 'Bar';
2500
import b from 'bar';
2501
import a from 'foo';
2502
import type { A } from 'foo';
2503
2504
import index from './';
2505
`,
2506
...parserConfig,
2507
options: [
2508
{
2509
groups: ['external', 'index'],
2510
alphabetize: { order: 'asc' },
2511
},
2512
],
2513
errors: [
2514
{
2515
message: semver.satisfies(eslintPkg.version, '< 3')
2516
? '`bar` import should occur after import of `Bar`'
2517
: /(`bar` import should occur after import of `Bar`)|(`Bar` import should occur before import of `bar`)/,
2518
},
2519
],
2520
}),
2521
// Option alphabetize: {order: 'desc'}
2522
test({
2523
code: `
2524
import a from 'foo';
2525
import type { A } from 'foo';
2526
import c from 'Bar';
2527
import type { C } from 'Bar';
2528
import b from 'bar';
2529
2530
import index from './';
2531
`,
2532
output: `
2533
import a from 'foo';
2534
import type { A } from 'foo';
2535
import b from 'bar';
2536
import c from 'Bar';
2537
import type { C } from 'Bar';
2538
2539
import index from './';
2540
`,
2541
...parserConfig,
2542
options: [
2543
{
2544
groups: ['external', 'index'],
2545
alphabetize: { order: 'desc' },
2546
},
2547
],
2548
errors: [
2549
{
2550
message: semver.satisfies(eslintPkg.version, '< 3')
2551
? '`bar` import should occur before import of `Bar`'
2552
: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/,
2553
},
2554
],
2555
}),
2556
// Option alphabetize: {order: 'asc'} with type group
2557
test({
2558
code: `
2559
import b from 'bar';
2560
import c from 'Bar';
2561
import a from 'foo';
2562
2563
import index from './';
2564
2565
import type { A } from 'foo';
2566
import type { C } from 'Bar';
2567
`,
2568
output: `
2569
import c from 'Bar';
2570
import b from 'bar';
2571
import a from 'foo';
2572
2573
import index from './';
2574
2575
import type { C } from 'Bar';
2576
import type { A } from 'foo';
2577
`,
2578
...parserConfig,
2579
options: [
2580
{
2581
groups: ['external', 'index', 'type'],
2582
alphabetize: { order: 'asc' },
2583
},
2584
],
2585
errors: semver.satisfies(eslintPkg.version, '< 3') ? [
2586
{ message: '`Bar` import should occur before import of `bar`' },
2587
{ message: '`Bar` import should occur before import of `foo`' },
2588
] : [
2589
{ message: /(`Bar` import should occur before import of `bar`)|(`bar` import should occur after import of `Bar`)/ },
2590
{ message: /(`Bar` import should occur before import of `foo`)|(`foo` import should occur after import of `Bar`)/ },
2591
],
2592
}),
2593
// Option alphabetize: {order: 'desc'} with type group
2594
test({
2595
code: `
2596
import a from 'foo';
2597
import c from 'Bar';
2598
import b from 'bar';
2599
2600
import index from './';
2601
2602
import type { C } from 'Bar';
2603
import type { A } from 'foo';
2604
`,
2605
output: `
2606
import a from 'foo';
2607
import b from 'bar';
2608
import c from 'Bar';
2609
2610
import index from './';
2611
2612
import type { A } from 'foo';
2613
import type { C } from 'Bar';
2614
`,
2615
...parserConfig,
2616
options: [
2617
{
2618
groups: ['external', 'index', 'type'],
2619
alphabetize: { order: 'desc' },
2620
},
2621
],
2622
errors: semver.satisfies(eslintPkg.version, '< 3') ? [
2623
{ message: '`bar` import should occur before import of `Bar`' },
2624
{ message: '`foo` import should occur before import of `Bar`' },
2625
] : [
2626
{ message: /(`bar` import should occur before import of `Bar`)|(`Bar` import should occur after import of `bar`)/ },
2627
{ message: /(`foo` import should occur before import of `Bar`)|(`Bar` import should occur after import of `foo`)/ },
2628
],
2629
}),
2630
// warns for out of order unassigned imports (warnOnUnassignedImports enabled)
2631
test({
2632
code: `
2633
import './local1';
2634
import global from 'global1';
2635
import local from './local2';
2636
import 'global2';
2637
`,
2638
output: `
2639
import './local1';
2640
import global from 'global1';
2641
import local from './local2';
2642
import 'global2';
2643
`,
2644
errors: [
2645
{
2646
message: '`global1` import should occur before import of `./local1`',
2647
},
2648
{
2649
message: '`global2` import should occur before import of `./local1`',
2650
},
2651
],
2652
options: [{ warnOnUnassignedImports: true }],
2653
}),
2654
// fix cannot move below unassigned import (warnOnUnassignedImports enabled)
2655
test({
2656
code: `
2657
import local from './local';
2658
2659
import 'global1';
2660
2661
import global2 from 'global2';
2662
import global3 from 'global3';
2663
`,
2664
output: `
2665
import local from './local';
2666
2667
import 'global1';
2668
2669
import global2 from 'global2';
2670
import global3 from 'global3';
2671
`,
2672
errors: [{
2673
message: '`./local` import should occur after import of `global3`',
2674
}],
2675
options: [{ warnOnUnassignedImports: true }],
2676
}),
2677
// Imports inside module declaration
2678
test({
2679
code: `
2680
import type { ParsedPath } from 'path';
2681
import type { CopyOptions } from 'fs';
2682
2683
declare module 'my-module' {
2684
import type { ParsedPath } from 'path';
2685
import type { CopyOptions } from 'fs';
2686
}
2687
`,
2688
output: `
2689
import type { CopyOptions } from 'fs';
2690
import type { ParsedPath } from 'path';
2691
2692
declare module 'my-module' {
2693
import type { CopyOptions } from 'fs';
2694
import type { ParsedPath } from 'path';
2695
}
2696
`,
2697
errors: [{
2698
message: '`fs` import should occur before import of `path`',
2699
},{
2700
message: '`fs` import should occur before import of `path`',
2701
}],
2702
...parserConfig,
2703
options: [
2704
{
2705
alphabetize: { order: 'asc' },
2706
},
2707
],
2708
}),
2709
],
2710
});
2711
});
2712
});
2713
2714