@borela-tech/eslint-config 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +273 -34
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +18 -5
- package/src/rules/__tests__/importsAndReExportsAtTop.test.ts +3 -1
- package/src/rules/__tests__/individualImports.test.ts +3 -1
- package/src/rules/__tests__/individualReExports.test.ts +3 -1
- package/src/rules/__tests__/multilineUnionTypes.test.ts +75 -0
- package/src/rules/__tests__/singleLineImports.test.ts +129 -0
- package/src/rules/__tests__/singleLineReExports.test.ts +100 -0
- package/src/rules/__tests__/sortedImports.test.ts +37 -1
- package/src/rules/__tests__/sortedReExports.test.ts +27 -1
- package/src/rules/importsAndReExportsAtTop/CategorizedStatements.ts +2 -2
- package/src/rules/importsAndReExportsAtTop/categorizeStatements.ts +7 -6
- package/src/rules/importsAndReExportsAtTop/generateSortedText.ts +4 -6
- package/src/rules/importsAndReExportsAtTop/getStatementType.ts +1 -1
- package/src/rules/importsAndReExportsAtTop/index.ts +5 -5
- package/src/rules/importsAndReExportsAtTop/isImportDeclaration.ts +7 -0
- package/src/rules/importsAndReExportsAtTop/isReExport.ts +12 -0
- package/src/rules/individualImports.ts +4 -3
- package/src/rules/individualReExports.ts +8 -9
- package/src/rules/multilineUnionTypes/createFix.ts +13 -0
- package/src/rules/multilineUnionTypes/index.ts +52 -0
- package/src/rules/multilineUnionTypes/isMultiline.ts +6 -0
- package/src/rules/singleLineImports/createFix.ts +23 -0
- package/src/rules/singleLineImports/formatAttributes.ts +20 -0
- package/src/rules/singleLineImports/formatNamed.ts +9 -0
- package/src/rules/singleLineImports/formatSpecifiers.ts +32 -0
- package/src/rules/singleLineImports/index.ts +34 -0
- package/src/rules/singleLineImports/isMultiline.ts +6 -0
- package/src/rules/singleLineReExports/createFix.ts +29 -0
- package/src/rules/singleLineReExports/index.ts +48 -0
- package/src/rules/singleLineReExports/isMultiline.ts +6 -0
- package/src/rules/sortedImports/ImportError.ts +4 -1
- package/src/rules/sortedImports/ImportGroup.ts +2 -1
- package/src/rules/sortedImports/ImportGroupOrder.ts +2 -1
- package/src/rules/sortedImports/areSpecifiersSorted.ts +1 -1
- package/src/rules/sortedImports/categorizeImport.ts +4 -0
- package/src/rules/sortedImports/checkAlphabeticalSorting.ts +1 -1
- package/src/rules/sortedImports/createFix/buildSortedCode.ts +2 -1
- package/src/rules/sortedImports/createFix/formatNamedImport.ts +3 -2
- package/src/rules/sortedImports/createFix/getReplacementRange.ts +3 -3
- package/src/rules/sortedImports/createFix/groupImportsByType.ts +1 -0
- package/src/rules/sortedImports/createFix/index.ts +10 -11
- package/src/rules/sortedImports/createFix/sortImportGroups.ts +2 -1
- package/src/rules/sortedImports/getSortKey.ts +8 -2
- package/src/rules/sortedImports/index.ts +8 -5
- package/src/rules/sortedImports/sortSpecifiersText.ts +4 -3
- package/src/rules/sortedReExports/CategorizedReExport.ts +14 -3
- package/src/rules/sortedReExports/ReExportError.ts +5 -2
- package/src/rules/sortedReExports/ReExportGroup.ts +1 -0
- package/src/rules/sortedReExports/ReExportGroupOrder.ts +2 -1
- package/src/rules/sortedReExports/areSpecifiersSorted.ts +1 -1
- package/src/rules/sortedReExports/categorizeReExport.ts +8 -4
- package/src/rules/sortedReExports/categorizeReExports.ts +1 -1
- package/src/rules/sortedReExports/checkAlphabeticalSorting.ts +1 -1
- package/src/rules/sortedReExports/createFix/buildSortedCode.ts +2 -1
- package/src/rules/sortedReExports/createFix/formatNamedReExport.ts +3 -2
- package/src/rules/sortedReExports/createFix/getReplacementRange.ts +1 -1
- package/src/rules/sortedReExports/createFix/groupReExportsByType.ts +1 -0
- package/src/rules/sortedReExports/createFix/index.ts +10 -11
- package/src/rules/sortedReExports/createFix/sortExportGroups.ts +2 -1
- package/src/rules/sortedReExports/getNamedSpecifiers.ts +1 -1
- package/src/rules/sortedReExports/getReExportGroups.ts +1 -1
- package/src/rules/sortedReExports/getSortKey.ts +11 -5
- package/src/rules/sortedReExports/index.ts +8 -5
- package/src/rules/sortedReExports/isNamedReExport.ts +2 -2
- package/src/rules/sortedReExports/sortSpecifiersText.ts +4 -3
- package/src/rules/importsAndReExportsAtTop/ReExport.ts +0 -5
- /package/src/{rules/sortedReExports → lib}/ReExportDeclaration.ts +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import typescript from 'typescript-eslint'
|
|
2
|
+
import {dedent} from './dedent'
|
|
3
|
+
import {RuleTester} from 'eslint'
|
|
4
|
+
import {singleLineImports} from '../singleLineImports'
|
|
5
|
+
import type {Rule} from 'eslint'
|
|
6
|
+
|
|
7
|
+
const rule = singleLineImports as unknown as Rule.RuleModule
|
|
8
|
+
const ruleTester = new RuleTester({
|
|
9
|
+
languageOptions: {
|
|
10
|
+
parser: typescript.parser,
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaVersion: 2020,
|
|
13
|
+
sourceType: 'module',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
ruleTester.run('single-line-imports', rule, {
|
|
19
|
+
valid: [{
|
|
20
|
+
code: "import {foo} from 'bar'",
|
|
21
|
+
}, {
|
|
22
|
+
code: "import foo from 'bar'",
|
|
23
|
+
}, {
|
|
24
|
+
code: "import * as foo from 'bar'",
|
|
25
|
+
}, {
|
|
26
|
+
code: "import 'bar'",
|
|
27
|
+
}, {
|
|
28
|
+
code: "import type {Foo} from 'bar'",
|
|
29
|
+
}, {
|
|
30
|
+
code: "import foo, {bar} from 'baz'",
|
|
31
|
+
}, {
|
|
32
|
+
code: "import {a, b, c} from 'bar'",
|
|
33
|
+
}, {
|
|
34
|
+
code: "import {foo} from 'bar' with {type: 'json'}",
|
|
35
|
+
}, {
|
|
36
|
+
code: "import type {Foo} from 'bar' with {type: 'json'}",
|
|
37
|
+
}],
|
|
38
|
+
invalid: [{
|
|
39
|
+
code: dedent`
|
|
40
|
+
import {
|
|
41
|
+
foo,
|
|
42
|
+
} from 'bar'
|
|
43
|
+
`,
|
|
44
|
+
errors: [{messageId: 'multiline'}],
|
|
45
|
+
output: dedent`
|
|
46
|
+
import {foo} from 'bar'
|
|
47
|
+
`,
|
|
48
|
+
}, {
|
|
49
|
+
code: dedent`
|
|
50
|
+
import type {
|
|
51
|
+
Foo,
|
|
52
|
+
} from 'bar'
|
|
53
|
+
`,
|
|
54
|
+
errors: [{messageId: 'multiline'}],
|
|
55
|
+
output: dedent`
|
|
56
|
+
import type {Foo} from 'bar'
|
|
57
|
+
`,
|
|
58
|
+
}, {
|
|
59
|
+
code: dedent`
|
|
60
|
+
import {
|
|
61
|
+
a,
|
|
62
|
+
b,
|
|
63
|
+
c,
|
|
64
|
+
} from 'bar'
|
|
65
|
+
`,
|
|
66
|
+
errors: [{messageId: 'multiline'}],
|
|
67
|
+
output: dedent`
|
|
68
|
+
import {a, b, c} from 'bar'
|
|
69
|
+
`,
|
|
70
|
+
}, {
|
|
71
|
+
code: dedent`
|
|
72
|
+
import foo, {
|
|
73
|
+
bar,
|
|
74
|
+
} from 'baz'
|
|
75
|
+
`,
|
|
76
|
+
errors: [{messageId: 'multiline'}],
|
|
77
|
+
output: dedent`
|
|
78
|
+
import foo, {bar} from 'baz'
|
|
79
|
+
`,
|
|
80
|
+
}, {
|
|
81
|
+
code: dedent`
|
|
82
|
+
import
|
|
83
|
+
foo
|
|
84
|
+
from 'bar'
|
|
85
|
+
`,
|
|
86
|
+
errors: [{messageId: 'multiline'}],
|
|
87
|
+
output: dedent`
|
|
88
|
+
import foo from 'bar'
|
|
89
|
+
`,
|
|
90
|
+
}, {
|
|
91
|
+
code: dedent`
|
|
92
|
+
import * as foo
|
|
93
|
+
from 'bar'
|
|
94
|
+
`,
|
|
95
|
+
errors: [{messageId: 'multiline'}],
|
|
96
|
+
output: dedent`
|
|
97
|
+
import * as foo from 'bar'
|
|
98
|
+
`,
|
|
99
|
+
}, {
|
|
100
|
+
code: dedent`
|
|
101
|
+
import
|
|
102
|
+
'bar'
|
|
103
|
+
`,
|
|
104
|
+
errors: [{messageId: 'multiline'}],
|
|
105
|
+
output: dedent`
|
|
106
|
+
import 'bar'
|
|
107
|
+
`,
|
|
108
|
+
}, {
|
|
109
|
+
code: dedent`
|
|
110
|
+
import {
|
|
111
|
+
foo,
|
|
112
|
+
} from 'bar' with {type: 'json'}
|
|
113
|
+
`,
|
|
114
|
+
errors: [{messageId: 'multiline'}],
|
|
115
|
+
output: dedent`
|
|
116
|
+
import {foo} from 'bar' with {type: 'json'}
|
|
117
|
+
`,
|
|
118
|
+
}, {
|
|
119
|
+
code: dedent`
|
|
120
|
+
import type {
|
|
121
|
+
Foo,
|
|
122
|
+
} from 'bar' with {type: 'json'}
|
|
123
|
+
`,
|
|
124
|
+
errors: [{messageId: 'multiline'}],
|
|
125
|
+
output: dedent`
|
|
126
|
+
import type {Foo} from 'bar' with {type: 'json'}
|
|
127
|
+
`,
|
|
128
|
+
}],
|
|
129
|
+
})
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import typescript from 'typescript-eslint'
|
|
2
|
+
import {dedent} from './dedent'
|
|
3
|
+
import {RuleTester} from 'eslint'
|
|
4
|
+
import {singleLineReExports} from '../singleLineReExports'
|
|
5
|
+
import type {Rule} from 'eslint'
|
|
6
|
+
|
|
7
|
+
const rule = singleLineReExports as unknown as Rule.RuleModule
|
|
8
|
+
const ruleTester = new RuleTester({
|
|
9
|
+
languageOptions: {
|
|
10
|
+
parser: typescript.parser,
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaVersion: 2020,
|
|
13
|
+
sourceType: 'module',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
ruleTester.run('single-line-re-exports', rule, {
|
|
19
|
+
valid: [{
|
|
20
|
+
code: "export {foo} from 'bar'",
|
|
21
|
+
}, {
|
|
22
|
+
code: "export * from 'bar'",
|
|
23
|
+
}, {
|
|
24
|
+
code: "export * as foo from 'bar'",
|
|
25
|
+
}, {
|
|
26
|
+
code: "export type {Foo} from 'bar'",
|
|
27
|
+
}, {
|
|
28
|
+
code: "export {a, b, c} from 'bar'",
|
|
29
|
+
}, {
|
|
30
|
+
// Local export, not a re-export
|
|
31
|
+
code: dedent`
|
|
32
|
+
export {
|
|
33
|
+
foo,
|
|
34
|
+
}
|
|
35
|
+
`,
|
|
36
|
+
}, {
|
|
37
|
+
code: "export {foo} from 'bar' with {type: 'json'}",
|
|
38
|
+
}],
|
|
39
|
+
invalid: [{
|
|
40
|
+
code: dedent`
|
|
41
|
+
export {
|
|
42
|
+
foo,
|
|
43
|
+
} from 'bar'
|
|
44
|
+
`,
|
|
45
|
+
errors: [{messageId: 'multiline'}],
|
|
46
|
+
output: dedent`
|
|
47
|
+
export {foo} from 'bar'
|
|
48
|
+
`,
|
|
49
|
+
}, {
|
|
50
|
+
code: dedent`
|
|
51
|
+
export type {
|
|
52
|
+
Foo,
|
|
53
|
+
} from 'bar'
|
|
54
|
+
`,
|
|
55
|
+
errors: [{messageId: 'multiline'}],
|
|
56
|
+
output: dedent`
|
|
57
|
+
export type {Foo} from 'bar'
|
|
58
|
+
`,
|
|
59
|
+
}, {
|
|
60
|
+
code: dedent`
|
|
61
|
+
export {
|
|
62
|
+
a,
|
|
63
|
+
b,
|
|
64
|
+
c,
|
|
65
|
+
} from 'bar'
|
|
66
|
+
`,
|
|
67
|
+
errors: [{messageId: 'multiline'}],
|
|
68
|
+
output: dedent`
|
|
69
|
+
export {a, b, c} from 'bar'
|
|
70
|
+
`,
|
|
71
|
+
}, {
|
|
72
|
+
code: `
|
|
73
|
+
export {
|
|
74
|
+
foo,
|
|
75
|
+
} from 'bar' with {type: 'json'}
|
|
76
|
+
`,
|
|
77
|
+
errors: [{messageId: 'multiline'}],
|
|
78
|
+
output: `
|
|
79
|
+
export {foo} from 'bar' with {type: 'json'}
|
|
80
|
+
`,
|
|
81
|
+
}, {
|
|
82
|
+
code: dedent`
|
|
83
|
+
export *
|
|
84
|
+
from 'bar'
|
|
85
|
+
`,
|
|
86
|
+
errors: [{messageId: 'multiline'}],
|
|
87
|
+
output: dedent`
|
|
88
|
+
export * from 'bar'
|
|
89
|
+
`,
|
|
90
|
+
}, {
|
|
91
|
+
code: dedent`
|
|
92
|
+
export * as foo
|
|
93
|
+
from 'bar'
|
|
94
|
+
`,
|
|
95
|
+
errors: [{messageId: 'multiline'}],
|
|
96
|
+
output: dedent`
|
|
97
|
+
export * as foo from 'bar'
|
|
98
|
+
`,
|
|
99
|
+
}],
|
|
100
|
+
})
|
|
@@ -2,7 +2,9 @@ import typescript from 'typescript-eslint'
|
|
|
2
2
|
import {dedent} from './dedent'
|
|
3
3
|
import {RuleTester} from 'eslint'
|
|
4
4
|
import {sortedImports} from '../sortedImports'
|
|
5
|
+
import type {Rule} from 'eslint'
|
|
5
6
|
|
|
7
|
+
const rule = sortedImports as unknown as Rule.RuleModule
|
|
6
8
|
const ruleTester = new RuleTester({
|
|
7
9
|
languageOptions: {
|
|
8
10
|
parser: typescript.parser,
|
|
@@ -13,7 +15,7 @@ const ruleTester = new RuleTester({
|
|
|
13
15
|
},
|
|
14
16
|
})
|
|
15
17
|
|
|
16
|
-
ruleTester.run('sorted-imports',
|
|
18
|
+
ruleTester.run('sorted-imports', rule, {
|
|
17
19
|
valid: [{
|
|
18
20
|
code: "import {foo} from 'bar'",
|
|
19
21
|
}, {
|
|
@@ -22,10 +24,14 @@ ruleTester.run('sorted-imports', sortedImports, {
|
|
|
22
24
|
code: "import 'bar'",
|
|
23
25
|
}, {
|
|
24
26
|
code: "import type {Foo} from 'bar'",
|
|
27
|
+
}, {
|
|
28
|
+
code: "import * as fs from 'fs'",
|
|
25
29
|
}, {
|
|
26
30
|
code: dedent`
|
|
27
31
|
import 'aaa'
|
|
28
32
|
import 'bbb'
|
|
33
|
+
import * as fs from 'fs'
|
|
34
|
+
import * as path from 'path'
|
|
29
35
|
import bar from 'bbb'
|
|
30
36
|
import foo from 'aaa'
|
|
31
37
|
import {a} from 'aaa'
|
|
@@ -187,5 +193,35 @@ ruleTester.run('sorted-imports', sortedImports, {
|
|
|
187
193
|
import {basename} from 'path'
|
|
188
194
|
import {existsSync} from 'fs'
|
|
189
195
|
`,
|
|
196
|
+
}, {
|
|
197
|
+
code: dedent`
|
|
198
|
+
import * as path from 'path'
|
|
199
|
+
import * as fs from 'fs'
|
|
200
|
+
`,
|
|
201
|
+
errors: [{messageId: 'sortedImports'}, {messageId: 'sortedImports'}],
|
|
202
|
+
output: dedent`
|
|
203
|
+
import * as fs from 'fs'
|
|
204
|
+
import * as path from 'path'
|
|
205
|
+
`,
|
|
206
|
+
}, {
|
|
207
|
+
code: dedent`
|
|
208
|
+
import {foo} from 'bar'
|
|
209
|
+
import * as fs from 'fs'
|
|
210
|
+
`,
|
|
211
|
+
errors: [{messageId: 'wrongGroup'}],
|
|
212
|
+
output: dedent`
|
|
213
|
+
import * as fs from 'fs'
|
|
214
|
+
import {foo} from 'bar'
|
|
215
|
+
`,
|
|
216
|
+
}, {
|
|
217
|
+
code: dedent`
|
|
218
|
+
import foo from 'bar'
|
|
219
|
+
import * as fs from 'fs'
|
|
220
|
+
`,
|
|
221
|
+
errors: [{messageId: 'wrongGroup'}],
|
|
222
|
+
output: dedent`
|
|
223
|
+
import * as fs from 'fs'
|
|
224
|
+
import foo from 'bar'
|
|
225
|
+
`,
|
|
190
226
|
}],
|
|
191
227
|
})
|
|
@@ -2,7 +2,9 @@ import typescript from 'typescript-eslint'
|
|
|
2
2
|
import {dedent} from './dedent'
|
|
3
3
|
import {RuleTester} from 'eslint'
|
|
4
4
|
import {sortedReExports} from '../sortedReExports'
|
|
5
|
+
import type {Rule} from 'eslint'
|
|
5
6
|
|
|
7
|
+
const rule = sortedReExports as unknown as Rule.RuleModule
|
|
6
8
|
const ruleTester = new RuleTester({
|
|
7
9
|
languageOptions: {
|
|
8
10
|
parser: typescript.parser,
|
|
@@ -13,7 +15,7 @@ const ruleTester = new RuleTester({
|
|
|
13
15
|
},
|
|
14
16
|
})
|
|
15
17
|
|
|
16
|
-
ruleTester.run('sorted-re-exports',
|
|
18
|
+
ruleTester.run('sorted-re-exports', rule, {
|
|
17
19
|
valid: [{
|
|
18
20
|
code: 'export const foo = 42',
|
|
19
21
|
}, {
|
|
@@ -26,9 +28,13 @@ ruleTester.run('sorted-re-exports', sortedReExports, {
|
|
|
26
28
|
code: "export * from 'bar'",
|
|
27
29
|
}, {
|
|
28
30
|
code: "export type {Foo} from 'bar'",
|
|
31
|
+
}, {
|
|
32
|
+
code: "export * as ns from 'bar'",
|
|
29
33
|
}, {
|
|
30
34
|
code: dedent`
|
|
31
35
|
export * from 'aaa'
|
|
36
|
+
export * as fs from 'fs'
|
|
37
|
+
export * as path from 'path'
|
|
32
38
|
export {a} from 'aaa'
|
|
33
39
|
export {b} from 'bbb'
|
|
34
40
|
export type {X} from 'xxx'
|
|
@@ -190,5 +196,25 @@ ruleTester.run('sorted-re-exports', sortedReExports, {
|
|
|
190
196
|
export {basename} from 'path'
|
|
191
197
|
export {existsSync} from 'fs'
|
|
192
198
|
`,
|
|
199
|
+
}, {
|
|
200
|
+
code: dedent`
|
|
201
|
+
export * as path from 'path'
|
|
202
|
+
export * as fs from 'fs'
|
|
203
|
+
`,
|
|
204
|
+
errors: [{messageId: 'sortedReExports'}, {messageId: 'sortedReExports'}],
|
|
205
|
+
output: dedent`
|
|
206
|
+
export * as fs from 'fs'
|
|
207
|
+
export * as path from 'path'
|
|
208
|
+
`,
|
|
209
|
+
}, {
|
|
210
|
+
code: dedent`
|
|
211
|
+
export {foo} from 'bar'
|
|
212
|
+
export * as fs from 'fs'
|
|
213
|
+
`,
|
|
214
|
+
errors: [{messageId: 'wrongGroup'}],
|
|
215
|
+
output: dedent`
|
|
216
|
+
export * as fs from 'fs'
|
|
217
|
+
export {foo} from 'bar'
|
|
218
|
+
`,
|
|
193
219
|
}],
|
|
194
220
|
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {ReExportDeclaration} from '@lib/ReExportDeclaration'
|
|
2
2
|
import type {TSESTree} from '@typescript-eslint/types'
|
|
3
3
|
|
|
4
4
|
export interface CategorizedStatements {
|
|
5
5
|
imports: TSESTree.ImportDeclaration[]
|
|
6
|
-
reExports:
|
|
6
|
+
reExports: ReExportDeclaration[]
|
|
7
7
|
other: TSESTree.Statement[]
|
|
8
8
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {getStatementType} from './getStatementType'
|
|
2
|
-
import {
|
|
2
|
+
import {isImportDeclaration} from './isImportDeclaration'
|
|
3
|
+
import {isReExport} from './isReExport'
|
|
3
4
|
import type {CategorizedStatements} from './CategorizedStatements'
|
|
4
5
|
import type {TSESTree} from '@typescript-eslint/types'
|
|
5
6
|
|
|
6
7
|
export function categorizeStatements(
|
|
7
|
-
statements: TSESTree.
|
|
8
|
+
statements: TSESTree.ProgramStatement[],
|
|
8
9
|
): CategorizedStatements {
|
|
9
10
|
const result: CategorizedStatements = {
|
|
10
11
|
imports: [],
|
|
@@ -15,10 +16,10 @@ export function categorizeStatements(
|
|
|
15
16
|
for (const statement of statements) {
|
|
16
17
|
const type = getStatementType(statement)
|
|
17
18
|
|
|
18
|
-
if (type === 'import')
|
|
19
|
-
result.imports.push(statement
|
|
20
|
-
else if (type === 're-export')
|
|
21
|
-
result.reExports.push(statement
|
|
19
|
+
if (type === 'import' && isImportDeclaration(statement))
|
|
20
|
+
result.imports.push(statement)
|
|
21
|
+
else if (type === 're-export' && isReExport(statement))
|
|
22
|
+
result.reExports.push(statement)
|
|
22
23
|
else
|
|
23
24
|
result.other.push(statement)
|
|
24
25
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import {Rule} from 'eslint'
|
|
2
1
|
import type {CategorizedStatements} from './CategorizedStatements'
|
|
3
|
-
import type {
|
|
4
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
5
3
|
|
|
6
4
|
export function generateSortedText(
|
|
7
|
-
context:
|
|
5
|
+
context: TSESLint.RuleContext<'importsAndReExportsAtTop', []>,
|
|
8
6
|
categories: CategorizedStatements,
|
|
9
7
|
): string {
|
|
10
|
-
const allStatements
|
|
8
|
+
const allStatements = [
|
|
11
9
|
...categories.imports,
|
|
12
10
|
...categories.reExports,
|
|
13
11
|
...categories.other,
|
|
14
12
|
]
|
|
15
13
|
return allStatements.map(
|
|
16
|
-
node => context.sourceCode.getText(node
|
|
14
|
+
node => context.sourceCode.getText(node),
|
|
17
15
|
).join('\n')
|
|
18
16
|
}
|
|
@@ -2,15 +2,15 @@ import {categorizeStatements} from './categorizeStatements'
|
|
|
2
2
|
import {findStatementIndices} from './findStatementIndices'
|
|
3
3
|
import {generateSortedText} from './generateSortedText'
|
|
4
4
|
import {hasViolation} from './hasViolation'
|
|
5
|
-
import type {
|
|
6
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
5
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
type MessageIds = 'importsAndReExportsAtTop'
|
|
8
|
+
|
|
9
|
+
export const importsAndReExportsAtTop: TSESLint.RuleModule<MessageIds, []> = {
|
|
9
10
|
meta: {
|
|
10
11
|
type: 'suggestion',
|
|
11
12
|
docs: {
|
|
12
13
|
description: 'Enforce imports and re-exports at the top of the file',
|
|
13
|
-
recommended: false,
|
|
14
14
|
},
|
|
15
15
|
fixable: 'code',
|
|
16
16
|
messages: {
|
|
@@ -23,7 +23,7 @@ export const importsAndReExportsAtTop: Rule.RuleModule = {
|
|
|
23
23
|
create(context) {
|
|
24
24
|
return {
|
|
25
25
|
Program(node) {
|
|
26
|
-
const statements = node.body
|
|
26
|
+
const statements = node.body
|
|
27
27
|
const categories = categorizeStatements(statements)
|
|
28
28
|
const indices = findStatementIndices(statements)
|
|
29
29
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type {ReExportDeclaration} from '@lib/ReExportDeclaration'
|
|
2
|
+
import type {TSESTree} from '@typescript-eslint/types'
|
|
3
|
+
|
|
4
|
+
export function isReExport(
|
|
5
|
+
statement: TSESTree.ProgramStatement,
|
|
6
|
+
): statement is ReExportDeclaration {
|
|
7
|
+
if (statement.type === 'ExportAllDeclaration')
|
|
8
|
+
return true
|
|
9
|
+
if (statement.type === 'ExportNamedDeclaration')
|
|
10
|
+
return statement.source !== null
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type MessageIds = 'individualImports'
|
|
4
|
+
|
|
5
|
+
export const individualImports: TSESLint.RuleModule<MessageIds, []> = {
|
|
4
6
|
meta: {
|
|
5
7
|
docs: {
|
|
6
8
|
description: 'Enforce individual imports instead of grouped imports',
|
|
7
|
-
recommended: true,
|
|
8
9
|
},
|
|
9
10
|
fixable: 'code',
|
|
10
11
|
messages: {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
1
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
type MessageIds = 'individualReExports'
|
|
4
|
+
|
|
5
|
+
export const individualReExports: TSESLint.RuleModule<MessageIds, []> = {
|
|
5
6
|
meta: {
|
|
6
7
|
docs: {
|
|
7
8
|
description: 'Enforce individual exports instead of grouped exports',
|
|
8
|
-
recommended: true,
|
|
9
9
|
},
|
|
10
10
|
fixable: 'code',
|
|
11
11
|
messages: {
|
|
@@ -17,19 +17,18 @@ export const individualReExports: Rule.RuleModule = {
|
|
|
17
17
|
create(context) {
|
|
18
18
|
return {
|
|
19
19
|
ExportNamedDeclaration(node) {
|
|
20
|
-
|
|
21
|
-
if (!exportNode.source || exportNode.specifiers.length <= 1)
|
|
20
|
+
if (!node.source || node.specifiers.length <= 1)
|
|
22
21
|
return
|
|
23
22
|
|
|
24
23
|
context.report({
|
|
25
24
|
node,
|
|
26
25
|
messageId: 'individualReExports',
|
|
27
26
|
fix(fixer) {
|
|
28
|
-
const source =
|
|
29
|
-
const typeKeyword =
|
|
27
|
+
const source = node.source.value
|
|
28
|
+
const typeKeyword = node.exportKind === 'type'
|
|
30
29
|
? 'type '
|
|
31
30
|
: ''
|
|
32
|
-
const specifiers =
|
|
31
|
+
const specifiers = node.specifiers
|
|
33
32
|
.map(s => {
|
|
34
33
|
const localName = s.local.type === 'Identifier'
|
|
35
34
|
? s.local.name
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
2
|
+
import type {TSESTree} from '@typescript-eslint/utils'
|
|
3
|
+
|
|
4
|
+
export function createFix(
|
|
5
|
+
fixer: TSESLint.RuleFixer,
|
|
6
|
+
node: TSESTree.TSUnionType,
|
|
7
|
+
sourceCode: TSESLint.SourceCode,
|
|
8
|
+
): TSESLint.RuleFix {
|
|
9
|
+
const types = node.types.map(t => sourceCode.getText(t))
|
|
10
|
+
const formattedTypes = types.map(t => ` | ${t}`).join('\n')
|
|
11
|
+
const result = `\n${formattedTypes}`
|
|
12
|
+
return fixer.replaceText(node, result)
|
|
13
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {createFix} from './createFix'
|
|
2
|
+
import {isMultiline} from './isMultiline'
|
|
3
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
4
|
+
|
|
5
|
+
type MessageIds =
|
|
6
|
+
| 'singleLine'
|
|
7
|
+
| 'missingPipes'
|
|
8
|
+
|
|
9
|
+
export const multilineUnionTypes: TSESLint.RuleModule<MessageIds, []> = {
|
|
10
|
+
meta: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Enforce union types with multiple members to be on multiple lines',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
messages: {
|
|
16
|
+
singleLine: 'Union types with multiple members should be on multiple lines',
|
|
17
|
+
missingPipes: 'Multiline union types should have leading pipes on each member',
|
|
18
|
+
},
|
|
19
|
+
schema: [],
|
|
20
|
+
type: 'layout',
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
create(context) {
|
|
24
|
+
return {
|
|
25
|
+
TSUnionType(node) {
|
|
26
|
+
if (node.types.length < 2)
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
const sourceCode = context.sourceCode
|
|
30
|
+
const text = sourceCode.getText(node)
|
|
31
|
+
|
|
32
|
+
if (text.trim().startsWith('|'))
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
if (!isMultiline(node)) {
|
|
36
|
+
context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: 'singleLine',
|
|
39
|
+
fix: fixer => createFix(fixer, node, sourceCode),
|
|
40
|
+
})
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: 'missingPipes',
|
|
47
|
+
fix: fixer => createFix(fixer, node, sourceCode),
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {formatAttributes} from './formatAttributes'
|
|
2
|
+
import {formatSpecifiers} from './formatSpecifiers'
|
|
3
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
4
|
+
import type {TSESTree} from '@typescript-eslint/utils'
|
|
5
|
+
|
|
6
|
+
export function createFix(
|
|
7
|
+
fixer: TSESLint.RuleFixer,
|
|
8
|
+
declaration: TSESTree.ImportDeclaration,
|
|
9
|
+
sourceCode: TSESLint.SourceCode,
|
|
10
|
+
): TSESLint.RuleFix {
|
|
11
|
+
const source = declaration.source.value
|
|
12
|
+
const prefix = declaration.importKind === 'type' ? 'import type ' : 'import '
|
|
13
|
+
const specifiers = formatSpecifiers(declaration, sourceCode)
|
|
14
|
+
const attributes = formatAttributes(declaration.attributes)
|
|
15
|
+
|
|
16
|
+
if (specifiers === '') {
|
|
17
|
+
const result = `${prefix}'${source}'${attributes}`
|
|
18
|
+
return fixer.replaceText(declaration, result)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const result = `${prefix}${specifiers} from '${source}'${attributes}`
|
|
22
|
+
return fixer.replaceText(declaration, result)
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
+
|
|
3
|
+
export function formatAttributes(
|
|
4
|
+
attributes: readonly TSESTree.ImportAttribute[],
|
|
5
|
+
): string {
|
|
6
|
+
if (attributes.length === 0)
|
|
7
|
+
return ''
|
|
8
|
+
|
|
9
|
+
const formatted = attributes.map(
|
|
10
|
+
attr => {
|
|
11
|
+
const key = attr.key.type === 'Identifier'
|
|
12
|
+
? attr.key.name
|
|
13
|
+
: attr.key.value
|
|
14
|
+
const value = attr.value.value
|
|
15
|
+
return `${key}: '${value}'`
|
|
16
|
+
},
|
|
17
|
+
).join(', ')
|
|
18
|
+
|
|
19
|
+
return ` with {${formatted}}`
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type {TSESLint} from '@typescript-eslint/utils'
|
|
2
|
+
import type {TSESTree} from '@typescript-eslint/utils'
|
|
3
|
+
|
|
4
|
+
export function formatNamed(
|
|
5
|
+
specifiers: TSESTree.ImportSpecifier[],
|
|
6
|
+
sourceCode: TSESLint.SourceCode,
|
|
7
|
+
): string {
|
|
8
|
+
return specifiers.map(s => sourceCode.getText(s)).join(', ')
|
|
9
|
+
}
|