@borela-tech/eslint-config 2.2.1 → 2.3.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/README.md +308 -19
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +3589 -811
- package/dist/index.mjs.map +1 -1
- package/jest.config.ts +19 -0
- package/package.json +17 -8
- package/vite.config.ts +41 -0
- package/bin/build +0 -9
- package/bin/lint +0 -14
- package/bin/publish +0 -12
- package/bin/test +0 -12
- package/bin/typecheck +0 -8
- package/dist/index.d.mts +0 -5226
- package/src/index.ts +0 -149
- package/src/lib/ReExportDeclaration.ts +0 -5
- package/src/lib/ReplacementRange.ts +0 -4
- package/src/lib/compare.ts +0 -3
- package/src/rules/__tests__/dedent/countLeadingSpaces.ts +0 -4
- package/src/rules/__tests__/dedent/findMinIndent.ts +0 -7
- package/src/rules/__tests__/dedent/index.ts +0 -17
- package/src/rules/__tests__/dedent/interpolate.ts +0 -11
- package/src/rules/__tests__/dedent/removeEmptyPrefix.ts +0 -6
- package/src/rules/__tests__/dedent/removeEmptySuffix.ts +0 -6
- package/src/rules/__tests__/dedent/removeIndent.ts +0 -3
- package/src/rules/__tests__/importsAndReExportsAtTop.test.ts +0 -88
- package/src/rules/__tests__/individualImports.test.ts +0 -44
- package/src/rules/__tests__/individualReExports.test.ts +0 -64
- package/src/rules/__tests__/multilineUnionTypes.test.ts +0 -75
- package/src/rules/__tests__/singleLineImports.test.ts +0 -129
- package/src/rules/__tests__/singleLineReExports.test.ts +0 -100
- package/src/rules/__tests__/sortedImports.test.ts +0 -227
- package/src/rules/__tests__/sortedReExports.test.ts +0 -220
- package/src/rules/importsAndReExportsAtTop/CategorizedStatements.ts +0 -8
- package/src/rules/importsAndReExportsAtTop/StatementIndices.ts +0 -5
- package/src/rules/importsAndReExportsAtTop/categorizeStatements.ts +0 -28
- package/src/rules/importsAndReExportsAtTop/findStatementIndices.ts +0 -25
- package/src/rules/importsAndReExportsAtTop/generateSortedText.ts +0 -16
- package/src/rules/importsAndReExportsAtTop/getStatementType.ts +0 -17
- package/src/rules/importsAndReExportsAtTop/hasViolation.ts +0 -25
- package/src/rules/importsAndReExportsAtTop/index.ts +0 -45
- package/src/rules/importsAndReExportsAtTop/isImportDeclaration.ts +0 -7
- package/src/rules/importsAndReExportsAtTop/isReExport.ts +0 -12
- package/src/rules/importsAndReExportsAtTop/statementType.ts +0 -4
- package/src/rules/individualImports.ts +0 -38
- package/src/rules/individualReExports.ts +0 -51
- package/src/rules/multilineUnionTypes/createFix.ts +0 -13
- package/src/rules/multilineUnionTypes/index.ts +0 -52
- package/src/rules/multilineUnionTypes/isMultiline.ts +0 -6
- package/src/rules/singleLineImports/createFix.ts +0 -23
- package/src/rules/singleLineImports/formatAttributes.ts +0 -20
- package/src/rules/singleLineImports/formatNamed.ts +0 -9
- package/src/rules/singleLineImports/formatSpecifiers.ts +0 -32
- package/src/rules/singleLineImports/index.ts +0 -34
- package/src/rules/singleLineImports/isMultiline.ts +0 -6
- package/src/rules/singleLineReExports/createFix.ts +0 -29
- package/src/rules/singleLineReExports/index.ts +0 -48
- package/src/rules/singleLineReExports/isMultiline.ts +0 -6
- package/src/rules/sortedImports/CategorizedImport.ts +0 -8
- package/src/rules/sortedImports/ImportError.ts +0 -9
- package/src/rules/sortedImports/ImportGroup.ts +0 -6
- package/src/rules/sortedImports/ImportGroupOrder.ts +0 -9
- package/src/rules/sortedImports/areSpecifiersSorted.ts +0 -9
- package/src/rules/sortedImports/categorizeImport.ts +0 -23
- package/src/rules/sortedImports/categorizeImports.ts +0 -12
- package/src/rules/sortedImports/checkAlphabeticalSorting.ts +0 -23
- package/src/rules/sortedImports/checkGroupOrdering.ts +0 -21
- package/src/rules/sortedImports/checkSpecifiersSorting.ts +0 -21
- package/src/rules/sortedImports/createFix/buildSortedCode.ts +0 -23
- package/src/rules/sortedImports/createFix/findLastImportIndex.ts +0 -12
- package/src/rules/sortedImports/createFix/formatNamedImport.ts +0 -21
- package/src/rules/sortedImports/createFix/getReplacementRange.ts +0 -14
- package/src/rules/sortedImports/createFix/groupImportsByType.ts +0 -19
- package/src/rules/sortedImports/createFix/index.ts +0 -47
- package/src/rules/sortedImports/createFix/sortImportGroups.ts +0 -13
- package/src/rules/sortedImports/getImportGroups.ts +0 -23
- package/src/rules/sortedImports/getNamedSpecifiers.ts +0 -7
- package/src/rules/sortedImports/getSortKey.ts +0 -26
- package/src/rules/sortedImports/getSpecifierName.ts +0 -7
- package/src/rules/sortedImports/index.ts +0 -63
- package/src/rules/sortedImports/sortSpecifiersText.ts +0 -16
- package/src/rules/sortedReExports/CategorizedNamedReExport.ts +0 -6
- package/src/rules/sortedReExports/CategorizedReExport.ts +0 -26
- package/src/rules/sortedReExports/ReExportError.ts +0 -9
- package/src/rules/sortedReExports/ReExportGroup.ts +0 -5
- package/src/rules/sortedReExports/ReExportGroupOrder.ts +0 -8
- package/src/rules/sortedReExports/areSpecifiersSorted.ts +0 -9
- package/src/rules/sortedReExports/categorizeReExport.ts +0 -21
- package/src/rules/sortedReExports/categorizeReExports.ts +0 -14
- package/src/rules/sortedReExports/checkAlphabeticalSorting.ts +0 -25
- package/src/rules/sortedReExports/checkGroupOrdering.ts +0 -21
- package/src/rules/sortedReExports/checkSpecifiersSorting.ts +0 -23
- package/src/rules/sortedReExports/createFix/buildSortedCode.ts +0 -29
- package/src/rules/sortedReExports/createFix/findFirstExportIndex.ts +0 -11
- package/src/rules/sortedReExports/createFix/findLastExportIndex.ts +0 -12
- package/src/rules/sortedReExports/createFix/formatNamedReExport.ts +0 -21
- package/src/rules/sortedReExports/createFix/getReplacementRange.ts +0 -22
- package/src/rules/sortedReExports/createFix/groupReExportsByType.ts +0 -18
- package/src/rules/sortedReExports/createFix/index.ts +0 -47
- package/src/rules/sortedReExports/createFix/sortExportGroups.ts +0 -12
- package/src/rules/sortedReExports/getNamedSpecifiers.ts +0 -9
- package/src/rules/sortedReExports/getReExportGroups.ts +0 -33
- package/src/rules/sortedReExports/getSortKey.ts +0 -22
- package/src/rules/sortedReExports/getSpecifierName.ts +0 -7
- package/src/rules/sortedReExports/index.ts +0 -63
- package/src/rules/sortedReExports/isNamedReExport.ts +0 -6
- package/src/rules/sortedReExports/sortSpecifiersText.ts +0 -16
- package/tsdown.config.ts +0 -19
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {categorizeStatements} from './categorizeStatements'
|
|
2
|
-
import {findStatementIndices} from './findStatementIndices'
|
|
3
|
-
import {generateSortedText} from './generateSortedText'
|
|
4
|
-
import {hasViolation} from './hasViolation'
|
|
5
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
6
|
-
|
|
7
|
-
type MessageIds = 'importsAndReExportsAtTop'
|
|
8
|
-
|
|
9
|
-
export const importsAndReExportsAtTop: TSESLint.RuleModule<MessageIds, []> = {
|
|
10
|
-
meta: {
|
|
11
|
-
type: 'suggestion',
|
|
12
|
-
docs: {
|
|
13
|
-
description: 'Enforce imports and re-exports at the top of the file',
|
|
14
|
-
},
|
|
15
|
-
fixable: 'code',
|
|
16
|
-
messages: {
|
|
17
|
-
importsAndReExportsAtTop:
|
|
18
|
-
'Imports and re-exports should be at the top of the file.',
|
|
19
|
-
},
|
|
20
|
-
schema: [],
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
create(context) {
|
|
24
|
-
return {
|
|
25
|
-
Program(node) {
|
|
26
|
-
const statements = node.body
|
|
27
|
-
const categories = categorizeStatements(statements)
|
|
28
|
-
const indices = findStatementIndices(statements)
|
|
29
|
-
|
|
30
|
-
if (!hasViolation(indices, categories))
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
context.report({
|
|
34
|
-
node,
|
|
35
|
-
messageId: 'importsAndReExportsAtTop',
|
|
36
|
-
|
|
37
|
-
fix(fixer) {
|
|
38
|
-
const sortedText = generateSortedText(context, categories)
|
|
39
|
-
return fixer.replaceText(node, sortedText)
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
},
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
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,38 +0,0 @@
|
|
|
1
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
2
|
-
|
|
3
|
-
type MessageIds = 'individualImports'
|
|
4
|
-
|
|
5
|
-
export const individualImports: TSESLint.RuleModule<MessageIds, []> = {
|
|
6
|
-
meta: {
|
|
7
|
-
docs: {
|
|
8
|
-
description: 'Enforce individual imports instead of grouped imports',
|
|
9
|
-
},
|
|
10
|
-
fixable: 'code',
|
|
11
|
-
messages: {
|
|
12
|
-
individualImports: 'Use individual imports instead of grouped imports.',
|
|
13
|
-
},
|
|
14
|
-
schema: [],
|
|
15
|
-
type: 'suggestion',
|
|
16
|
-
},
|
|
17
|
-
create(context) {
|
|
18
|
-
return {
|
|
19
|
-
ImportDeclaration(node) {
|
|
20
|
-
if (node.specifiers.length <= 1)
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
context.report({
|
|
24
|
-
node,
|
|
25
|
-
messageId: 'individualImports',
|
|
26
|
-
fix(fixer) {
|
|
27
|
-
const source = node.source.raw
|
|
28
|
-
const specifiers = node.specifiers
|
|
29
|
-
.filter(s => s.type === 'ImportSpecifier')
|
|
30
|
-
.map(s => `import {${s.local.name}} from ${source}`)
|
|
31
|
-
.join('\n')
|
|
32
|
-
return fixer.replaceText(node, specifiers)
|
|
33
|
-
},
|
|
34
|
-
})
|
|
35
|
-
},
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
2
|
-
|
|
3
|
-
type MessageIds = 'individualReExports'
|
|
4
|
-
|
|
5
|
-
export const individualReExports: TSESLint.RuleModule<MessageIds, []> = {
|
|
6
|
-
meta: {
|
|
7
|
-
docs: {
|
|
8
|
-
description: 'Enforce individual exports instead of grouped exports',
|
|
9
|
-
},
|
|
10
|
-
fixable: 'code',
|
|
11
|
-
messages: {
|
|
12
|
-
individualReExports: 'Use individual exports instead of grouped exports.',
|
|
13
|
-
},
|
|
14
|
-
schema: [],
|
|
15
|
-
type: 'suggestion',
|
|
16
|
-
},
|
|
17
|
-
create(context) {
|
|
18
|
-
return {
|
|
19
|
-
ExportNamedDeclaration(node) {
|
|
20
|
-
if (!node.source || node.specifiers.length <= 1)
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
context.report({
|
|
24
|
-
node,
|
|
25
|
-
messageId: 'individualReExports',
|
|
26
|
-
fix(fixer) {
|
|
27
|
-
const source = node.source.value
|
|
28
|
-
const typeKeyword = node.exportKind === 'type'
|
|
29
|
-
? 'type '
|
|
30
|
-
: ''
|
|
31
|
-
const specifiers = node.specifiers
|
|
32
|
-
.map(s => {
|
|
33
|
-
const localName = s.local.type === 'Identifier'
|
|
34
|
-
? s.local.name
|
|
35
|
-
: s.local.value
|
|
36
|
-
const exportedName = s.exported.type === 'Identifier'
|
|
37
|
-
? s.exported.name
|
|
38
|
-
: s.exported.value
|
|
39
|
-
const name = localName === exportedName
|
|
40
|
-
? localName
|
|
41
|
-
: `${localName} as ${exportedName}`
|
|
42
|
-
return `export ${typeKeyword}{${name}} from '${source}'`
|
|
43
|
-
})
|
|
44
|
-
.join('\n')
|
|
45
|
-
return fixer.replaceText(node, specifiers)
|
|
46
|
-
},
|
|
47
|
-
})
|
|
48
|
-
},
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {formatNamed} from './formatNamed'
|
|
2
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
3
|
-
import type {TSESTree} from '@typescript-eslint/utils'
|
|
4
|
-
|
|
5
|
-
export function formatSpecifiers(
|
|
6
|
-
declaration: TSESTree.ImportDeclaration,
|
|
7
|
-
sourceCode: TSESLint.SourceCode,
|
|
8
|
-
): string {
|
|
9
|
-
const defaultSpecifier = declaration.specifiers.find(
|
|
10
|
-
(s): s is TSESTree.ImportDefaultSpecifier => s.type === 'ImportDefaultSpecifier',
|
|
11
|
-
)
|
|
12
|
-
const namespaceSpecifier = declaration.specifiers.find(
|
|
13
|
-
(s): s is TSESTree.ImportNamespaceSpecifier => s.type === 'ImportNamespaceSpecifier',
|
|
14
|
-
)
|
|
15
|
-
const namedSpecifiers = declaration.specifiers.filter(
|
|
16
|
-
(s): s is TSESTree.ImportSpecifier => s.type === 'ImportSpecifier',
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
if (namespaceSpecifier)
|
|
20
|
-
return `* as ${namespaceSpecifier.local.name}`
|
|
21
|
-
|
|
22
|
-
if (defaultSpecifier && namedSpecifiers.length > 0)
|
|
23
|
-
return `${defaultSpecifier.local.name}, {${formatNamed(namedSpecifiers, sourceCode)}}`
|
|
24
|
-
|
|
25
|
-
if (defaultSpecifier)
|
|
26
|
-
return defaultSpecifier.local.name
|
|
27
|
-
|
|
28
|
-
if (namedSpecifiers.length === 0)
|
|
29
|
-
return ''
|
|
30
|
-
|
|
31
|
-
return `{${formatNamed(namedSpecifiers, sourceCode)}}`
|
|
32
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {createFix} from './createFix'
|
|
2
|
-
import {isMultiline} from './isMultiline'
|
|
3
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
4
|
-
|
|
5
|
-
type MessageIds = 'multiline'
|
|
6
|
-
|
|
7
|
-
export const singleLineImports: TSESLint.RuleModule<MessageIds, []> = {
|
|
8
|
-
meta: {
|
|
9
|
-
docs: {
|
|
10
|
-
description: 'Enforce imports to be on a single line',
|
|
11
|
-
},
|
|
12
|
-
fixable: 'code',
|
|
13
|
-
messages: {
|
|
14
|
-
multiline: 'Import should be on a single line',
|
|
15
|
-
},
|
|
16
|
-
schema: [],
|
|
17
|
-
type: 'layout',
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
create(context) {
|
|
21
|
-
return {
|
|
22
|
-
ImportDeclaration(node) {
|
|
23
|
-
if (!isMultiline(node))
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
context.report({
|
|
27
|
-
node,
|
|
28
|
-
messageId: 'multiline',
|
|
29
|
-
fix: fixer => createFix(fixer, node, context.sourceCode),
|
|
30
|
-
})
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {formatAttributes} from '../singleLineImports/formatAttributes'
|
|
2
|
-
import type {ReExportDeclaration} from '@lib/ReExportDeclaration'
|
|
3
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
4
|
-
|
|
5
|
-
export function createFix(
|
|
6
|
-
fixer: TSESLint.RuleFixer,
|
|
7
|
-
declaration: ReExportDeclaration,
|
|
8
|
-
sourceCode: TSESLint.SourceCode,
|
|
9
|
-
): TSESLint.RuleFix {
|
|
10
|
-
const source = declaration.source!.value
|
|
11
|
-
|
|
12
|
-
if (declaration.type === 'ExportAllDeclaration') {
|
|
13
|
-
const exported = declaration.exported
|
|
14
|
-
? `* as ${sourceCode.getText(declaration.exported)}`
|
|
15
|
-
: '*'
|
|
16
|
-
const attributes = formatAttributes(declaration.attributes)
|
|
17
|
-
const result = `export ${exported} from '${source}'${attributes}`
|
|
18
|
-
return fixer.replaceText(declaration, result)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const prefix = declaration.exportKind === 'type' ? 'export type ' : 'export '
|
|
22
|
-
const specifiers = declaration.specifiers.map(
|
|
23
|
-
s => sourceCode.getText(s),
|
|
24
|
-
).join(', ')
|
|
25
|
-
const attributes = formatAttributes(declaration.attributes)
|
|
26
|
-
const result = `${prefix}{${specifiers}} from '${source}'${attributes}`
|
|
27
|
-
|
|
28
|
-
return fixer.replaceText(declaration, result)
|
|
29
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {createFix} from './createFix'
|
|
2
|
-
import {isMultiline} from './isMultiline'
|
|
3
|
-
import type {ReExportDeclaration} from '@lib/ReExportDeclaration'
|
|
4
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
5
|
-
import type {TSESTree} from '@typescript-eslint/utils'
|
|
6
|
-
|
|
7
|
-
type MessageIds = 'multiline'
|
|
8
|
-
|
|
9
|
-
export const singleLineReExports: TSESLint.RuleModule<MessageIds, []> = {
|
|
10
|
-
meta: {
|
|
11
|
-
docs: {
|
|
12
|
-
description: 'Enforce re-exports to be on a single line',
|
|
13
|
-
},
|
|
14
|
-
fixable: 'code',
|
|
15
|
-
messages: {
|
|
16
|
-
multiline: 'Re-export should be on a single line',
|
|
17
|
-
},
|
|
18
|
-
schema: [],
|
|
19
|
-
type: 'layout',
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
create(context) {
|
|
23
|
-
const checkDeclaration = (
|
|
24
|
-
node: TSESTree.Node,
|
|
25
|
-
declaration: ReExportDeclaration,
|
|
26
|
-
) => {
|
|
27
|
-
// Skip local exports (only process re-exports with a source)
|
|
28
|
-
if (!declaration.source)
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
if (!isMultiline(declaration))
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
context.report({
|
|
35
|
-
node,
|
|
36
|
-
messageId: 'multiline',
|
|
37
|
-
fix: fixer => createFix(fixer, declaration, context.sourceCode),
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
ExportNamedDeclaration: node =>
|
|
43
|
-
checkDeclaration(node, node),
|
|
44
|
-
ExportAllDeclaration: node =>
|
|
45
|
-
checkDeclaration(node, node),
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import {compare} from '@lib/compare'
|
|
2
|
-
import {getSpecifierName} from './getSpecifierName'
|
|
3
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
4
|
-
|
|
5
|
-
export function areSpecifiersSorted(specifiers: TSESTree.ImportSpecifier[]): boolean {
|
|
6
|
-
const names = specifiers.map(s => getSpecifierName(s))
|
|
7
|
-
const sorted = [...names].sort((a, b) => compare(a, b))
|
|
8
|
-
return names.every((name, i) => name === sorted[i])
|
|
9
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type {ImportGroup} from './ImportGroup'
|
|
2
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
3
|
-
|
|
4
|
-
export function categorizeImport(declaration: TSESTree.ImportDeclaration): ImportGroup {
|
|
5
|
-
// Example: import type {Type} from 'module'
|
|
6
|
-
if (declaration.importKind === 'type')
|
|
7
|
-
return 'type'
|
|
8
|
-
|
|
9
|
-
// Example: import 'module'
|
|
10
|
-
if (declaration.specifiers.length === 0)
|
|
11
|
-
return 'side-effect'
|
|
12
|
-
|
|
13
|
-
// Example: import * as fs from 'module'
|
|
14
|
-
if (declaration.specifiers.some(s => s.type === 'ImportNamespaceSpecifier'))
|
|
15
|
-
return 'namespace'
|
|
16
|
-
|
|
17
|
-
// Example: import value from 'module'
|
|
18
|
-
if (declaration.specifiers.some(s => s.type === 'ImportDefaultSpecifier'))
|
|
19
|
-
return 'default'
|
|
20
|
-
|
|
21
|
-
// Example: import {value} from 'module'
|
|
22
|
-
return 'named'
|
|
23
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {categorizeImport} from './categorizeImport'
|
|
2
|
-
import {getSortKey} from './getSortKey'
|
|
3
|
-
import type {CategorizedImport} from './CategorizedImport'
|
|
4
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
5
|
-
|
|
6
|
-
export function categorizeImports(declarations: TSESTree.ImportDeclaration[]): CategorizedImport[] {
|
|
7
|
-
return declarations.map(declaration => ({
|
|
8
|
-
declaration,
|
|
9
|
-
group: categorizeImport(declaration),
|
|
10
|
-
sortKey: getSortKey(declaration),
|
|
11
|
-
}))
|
|
12
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {compare} from '@lib/compare'
|
|
2
|
-
import {importGroupOrder} from './ImportGroupOrder'
|
|
3
|
-
import type {CategorizedImport} from './CategorizedImport'
|
|
4
|
-
import type {ImportError} from './ImportError'
|
|
5
|
-
|
|
6
|
-
export function checkAlphabeticalSorting(categorized: CategorizedImport[]): ImportError[] {
|
|
7
|
-
const errors: ImportError[] = []
|
|
8
|
-
|
|
9
|
-
for (const group of importGroupOrder) {
|
|
10
|
-
const groupImports = categorized.filter(c => c.group === group)
|
|
11
|
-
const sorted = [...groupImports].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
12
|
-
for (let i = 0; i < groupImports.length; i++) {
|
|
13
|
-
if (groupImports[i] !== sorted[i]) {
|
|
14
|
-
errors.push({
|
|
15
|
-
node: groupImports[i].declaration,
|
|
16
|
-
messageId: 'sortedImports',
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return errors
|
|
23
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {importGroupOrder} from './ImportGroupOrder'
|
|
2
|
-
import type {CategorizedImport} from './CategorizedImport'
|
|
3
|
-
import type {ImportError} from './ImportError'
|
|
4
|
-
|
|
5
|
-
export function checkGroupOrdering(categorized: CategorizedImport[]): ImportError[] {
|
|
6
|
-
const errors: ImportError[] = []
|
|
7
|
-
|
|
8
|
-
let currentGroupIndex = -1
|
|
9
|
-
for (const {declaration, group} of categorized) {
|
|
10
|
-
const groupIndex = importGroupOrder.indexOf(group)
|
|
11
|
-
if (groupIndex < currentGroupIndex) {
|
|
12
|
-
errors.push({
|
|
13
|
-
node: declaration,
|
|
14
|
-
messageId: 'wrongGroup',
|
|
15
|
-
})
|
|
16
|
-
} else
|
|
17
|
-
currentGroupIndex = groupIndex
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return errors
|
|
21
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {areSpecifiersSorted} from './areSpecifiersSorted'
|
|
2
|
-
import {getNamedSpecifiers} from './getNamedSpecifiers'
|
|
3
|
-
import type {CategorizedImport} from './CategorizedImport'
|
|
4
|
-
import type {ImportError} from './ImportError'
|
|
5
|
-
|
|
6
|
-
export function checkSpecifiersSorting(categorized: CategorizedImport[]): ImportError[] {
|
|
7
|
-
const errors: ImportError[] = []
|
|
8
|
-
const namedImports = categorized.filter(c => c.group === 'named')
|
|
9
|
-
|
|
10
|
-
for (const {declaration} of namedImports) {
|
|
11
|
-
const specifiers = getNamedSpecifiers(declaration)
|
|
12
|
-
if (specifiers.length > 1 && !areSpecifiersSorted(specifiers)) {
|
|
13
|
-
errors.push({
|
|
14
|
-
node: declaration,
|
|
15
|
-
messageId: 'sortedNames',
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return errors
|
|
21
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {formatNamedImport} from './formatNamedImport'
|
|
2
|
-
import {importGroupOrder} from '../ImportGroupOrder'
|
|
3
|
-
import type {CategorizedImport} from '../CategorizedImport'
|
|
4
|
-
import type {ImportGroup} from '../ImportGroup'
|
|
5
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
6
|
-
|
|
7
|
-
export function buildSortedCode(
|
|
8
|
-
grouped: Record<ImportGroup, CategorizedImport[]>,
|
|
9
|
-
sourceCode: TSESLint.SourceCode,
|
|
10
|
-
): string[] {
|
|
11
|
-
const sortedCode: string[] = []
|
|
12
|
-
|
|
13
|
-
for (const group of importGroupOrder) {
|
|
14
|
-
for (const {declaration} of grouped[group]) {
|
|
15
|
-
if (group === 'named' || group === 'type')
|
|
16
|
-
sortedCode.push(formatNamedImport(declaration, sourceCode))
|
|
17
|
-
else
|
|
18
|
-
sortedCode.push(sourceCode.getText(declaration))
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return sortedCode
|
|
23
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
-
|
|
3
|
-
export function findLastImportIndex(programBody: TSESTree.ProgramStatement[]): number {
|
|
4
|
-
let lastIndex = 0
|
|
5
|
-
for (let i = 0; i < programBody.length; i++) {
|
|
6
|
-
if (programBody[i].type === 'ImportDeclaration')
|
|
7
|
-
lastIndex = i
|
|
8
|
-
else
|
|
9
|
-
break
|
|
10
|
-
}
|
|
11
|
-
return lastIndex
|
|
12
|
-
}
|