@borela-tech/eslint-config 2.2.2 → 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 -7
- 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 -22
|
@@ -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
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {areSpecifiersSorted} from '../areSpecifiersSorted'
|
|
2
|
-
import {getNamedSpecifiers} from '../getNamedSpecifiers'
|
|
3
|
-
import {sortSpecifiersText} from '../sortSpecifiersText'
|
|
4
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
5
|
-
import type {TSESTree} from '@typescript-eslint/utils'
|
|
6
|
-
|
|
7
|
-
export function formatNamedImport(
|
|
8
|
-
declaration: TSESTree.ImportDeclaration,
|
|
9
|
-
sourceCode: TSESLint.SourceCode,
|
|
10
|
-
): string {
|
|
11
|
-
const specifiers = getNamedSpecifiers(declaration)
|
|
12
|
-
|
|
13
|
-
if (specifiers.length > 1 && !areSpecifiersSorted(specifiers)) {
|
|
14
|
-
const sortedSpecifiers = sortSpecifiersText(specifiers, sourceCode)
|
|
15
|
-
const source = declaration.source.value
|
|
16
|
-
const prefix = declaration.importKind === 'type' ? 'import type ' : 'import '
|
|
17
|
-
return `${prefix}{${sortedSpecifiers}} from '${source}'`
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return sourceCode.getText(declaration)
|
|
21
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {findLastImportIndex} from './findLastImportIndex'
|
|
2
|
-
import type {ReplacementRange} from '@lib/ReplacementRange'
|
|
3
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
4
|
-
|
|
5
|
-
export function getReplacementRange(
|
|
6
|
-
programBody: TSESTree.ProgramStatement[],
|
|
7
|
-
): ReplacementRange {
|
|
8
|
-
const lastIndex = findLastImportIndex(programBody)
|
|
9
|
-
const firstImport = programBody[0]
|
|
10
|
-
const lastImport = programBody[lastIndex]
|
|
11
|
-
const start = firstImport.range![0]
|
|
12
|
-
const end = lastImport.range![1]
|
|
13
|
-
return {start, end}
|
|
14
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type {CategorizedImport} from '../CategorizedImport'
|
|
2
|
-
import type {ImportGroup} from '../ImportGroup'
|
|
3
|
-
|
|
4
|
-
export function groupImportsByType(
|
|
5
|
-
categorized: CategorizedImport[],
|
|
6
|
-
): Record<ImportGroup, CategorizedImport[]> {
|
|
7
|
-
const grouped: Record<ImportGroup, CategorizedImport[]> = {
|
|
8
|
-
'side-effect': [],
|
|
9
|
-
namespace: [],
|
|
10
|
-
default: [],
|
|
11
|
-
named: [],
|
|
12
|
-
type: [],
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
for (const item of categorized)
|
|
16
|
-
grouped[item.group].push(item)
|
|
17
|
-
|
|
18
|
-
return grouped
|
|
19
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import {buildSortedCode} from './buildSortedCode'
|
|
2
|
-
import {categorizeImports} from '../categorizeImports'
|
|
3
|
-
import {groupImportsByType} from './groupImportsByType'
|
|
4
|
-
import {sortImportGroups} from './sortImportGroups'
|
|
5
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
6
|
-
import type {TSESTree} from '@typescript-eslint/utils'
|
|
7
|
-
|
|
8
|
-
function createFixForGroup(
|
|
9
|
-
fixer: TSESLint.RuleFixer,
|
|
10
|
-
importDeclarations: TSESTree.ImportDeclaration[],
|
|
11
|
-
sourceCode: TSESLint.SourceCode,
|
|
12
|
-
) {
|
|
13
|
-
if (importDeclarations.length === 0)
|
|
14
|
-
return null
|
|
15
|
-
|
|
16
|
-
const categorized = categorizeImports(importDeclarations)
|
|
17
|
-
const grouped = groupImportsByType(categorized)
|
|
18
|
-
|
|
19
|
-
sortImportGroups(grouped)
|
|
20
|
-
|
|
21
|
-
const sortedCode = buildSortedCode(grouped, sourceCode)
|
|
22
|
-
.join('\n')
|
|
23
|
-
|
|
24
|
-
const firstImport = importDeclarations[0]
|
|
25
|
-
const lastImport = importDeclarations[importDeclarations.length - 1]
|
|
26
|
-
|
|
27
|
-
return fixer.replaceTextRange(
|
|
28
|
-
[firstImport.range![0], lastImport.range![1]],
|
|
29
|
-
sortedCode,
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function createFix(
|
|
34
|
-
fixer: TSESLint.RuleFixer,
|
|
35
|
-
importGroups: TSESTree.ImportDeclaration[][],
|
|
36
|
-
sourceCode: TSESLint.SourceCode,
|
|
37
|
-
): TSESLint.RuleFix[] {
|
|
38
|
-
const fixes: TSESLint.RuleFix[] = []
|
|
39
|
-
|
|
40
|
-
for (const group of importGroups) {
|
|
41
|
-
const fix = createFixForGroup(fixer, group, sourceCode)
|
|
42
|
-
if (fix)
|
|
43
|
-
fixes.push(fix)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return fixes
|
|
47
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {compare} from '@lib/compare'
|
|
2
|
-
import type {CategorizedImport} from '../CategorizedImport'
|
|
3
|
-
import type {ImportGroup} from '../ImportGroup'
|
|
4
|
-
|
|
5
|
-
export function sortImportGroups(
|
|
6
|
-
grouped: Record<ImportGroup, CategorizedImport[]>,
|
|
7
|
-
): void {
|
|
8
|
-
grouped['side-effect'].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
9
|
-
grouped['namespace'].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
10
|
-
grouped['default'].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
11
|
-
grouped['named'].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
12
|
-
grouped['type'].sort((a, b) => compare(a.sortKey, b.sortKey))
|
|
13
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
-
|
|
3
|
-
export function getImportGroups(programBody: TSESTree.ProgramStatement[]): TSESTree.ImportDeclaration[][] {
|
|
4
|
-
const groups: TSESTree.ImportDeclaration[][] = []
|
|
5
|
-
let currentGroup: TSESTree.ImportDeclaration[] = []
|
|
6
|
-
|
|
7
|
-
for (const statement of programBody) {
|
|
8
|
-
if (statement.type === 'ImportDeclaration') {
|
|
9
|
-
currentGroup.push(statement)
|
|
10
|
-
continue
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (currentGroup.length > 0) {
|
|
14
|
-
groups.push(currentGroup)
|
|
15
|
-
currentGroup = []
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (currentGroup.length > 0)
|
|
20
|
-
groups.push(currentGroup)
|
|
21
|
-
|
|
22
|
-
return groups
|
|
23
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
-
|
|
3
|
-
export function getNamedSpecifiers(declaration: TSESTree.ImportDeclaration): TSESTree.ImportSpecifier[] {
|
|
4
|
-
return declaration.specifiers.filter(
|
|
5
|
-
(s): s is TSESTree.ImportSpecifier => s.type === 'ImportSpecifier',
|
|
6
|
-
)
|
|
7
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import {categorizeImport} from './categorizeImport'
|
|
2
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
3
|
-
|
|
4
|
-
export function getSortKey(declaration: TSESTree.ImportDeclaration): string {
|
|
5
|
-
const group = categorizeImport(declaration)
|
|
6
|
-
|
|
7
|
-
if (group === 'side-effect')
|
|
8
|
-
return declaration.source.value
|
|
9
|
-
|
|
10
|
-
if (group === 'namespace') {
|
|
11
|
-
const namespaceSpecifier = declaration.specifiers.find(
|
|
12
|
-
s => s.type === 'ImportNamespaceSpecifier',
|
|
13
|
-
)
|
|
14
|
-
return `*${namespaceSpecifier?.local.name ?? ''}`
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (group === 'default') {
|
|
18
|
-
const defaultSpecifier = declaration.specifiers.find(
|
|
19
|
-
s => s.type === 'ImportDefaultSpecifier',
|
|
20
|
-
)
|
|
21
|
-
return defaultSpecifier?.local.name ?? ''
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const specifier = declaration.specifiers[0]
|
|
25
|
-
return specifier.local.name
|
|
26
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import {categorizeImports} from './categorizeImports'
|
|
2
|
-
import {checkAlphabeticalSorting} from './checkAlphabeticalSorting'
|
|
3
|
-
import {checkGroupOrdering} from './checkGroupOrdering'
|
|
4
|
-
import {checkSpecifiersSorting} from './checkSpecifiersSorting'
|
|
5
|
-
import {createFix} from './createFix'
|
|
6
|
-
import {getImportGroups} from './getImportGroups'
|
|
7
|
-
import type {ImportError} from './ImportError'
|
|
8
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
9
|
-
|
|
10
|
-
type MessageIds =
|
|
11
|
-
| 'sortedImports'
|
|
12
|
-
| 'sortedNames'
|
|
13
|
-
| 'wrongGroup'
|
|
14
|
-
|
|
15
|
-
export const sortedImports: TSESLint.RuleModule<MessageIds, []> = {
|
|
16
|
-
meta: {
|
|
17
|
-
docs: {
|
|
18
|
-
description: 'Enforce sorted imports alphabetically',
|
|
19
|
-
},
|
|
20
|
-
fixable: 'code',
|
|
21
|
-
messages: {
|
|
22
|
-
sortedImports: 'Imports should be sorted alphabetically',
|
|
23
|
-
sortedNames: 'Named imports should be sorted alphabetically',
|
|
24
|
-
wrongGroup: 'Import is in wrong group',
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
type: 'suggestion',
|
|
28
|
-
},
|
|
29
|
-
create(context) {
|
|
30
|
-
return {
|
|
31
|
-
Program(node) {
|
|
32
|
-
const body = node.body
|
|
33
|
-
const importGroups = getImportGroups(body)
|
|
34
|
-
if (importGroups.length === 0)
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
const allErrors: ImportError[] = []
|
|
38
|
-
|
|
39
|
-
// Check each import group independently
|
|
40
|
-
for (const group of importGroups) {
|
|
41
|
-
const categorized = categorizeImports(group)
|
|
42
|
-
const errors: ImportError[] = [
|
|
43
|
-
...checkGroupOrdering(categorized),
|
|
44
|
-
...checkAlphabeticalSorting(categorized),
|
|
45
|
-
...checkSpecifiersSorting(categorized),
|
|
46
|
-
]
|
|
47
|
-
allErrors.push(...errors)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (const error of allErrors) {
|
|
51
|
-
context.report({
|
|
52
|
-
node: error.node,
|
|
53
|
-
messageId: error.messageId,
|
|
54
|
-
fix(fixer) {
|
|
55
|
-
const sourceCode = context.sourceCode
|
|
56
|
-
return createFix(fixer, importGroups, sourceCode)
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {compare} from '@lib/compare'
|
|
2
|
-
import {getSpecifierName} from './getSpecifierName'
|
|
3
|
-
import type {TSESLint} from '@typescript-eslint/utils'
|
|
4
|
-
import type {TSESTree} from '@typescript-eslint/utils'
|
|
5
|
-
|
|
6
|
-
export function sortSpecifiersText(
|
|
7
|
-
specifiers: TSESTree.ImportSpecifier[],
|
|
8
|
-
sourceCode: TSESLint.SourceCode,
|
|
9
|
-
): string {
|
|
10
|
-
const sorted = [...specifiers].sort((a, b) => {
|
|
11
|
-
const nameA = getSpecifierName(a)
|
|
12
|
-
const nameB = getSpecifierName(b)
|
|
13
|
-
return compare(nameA, nameB)
|
|
14
|
-
})
|
|
15
|
-
return sorted.map(s => sourceCode.getText(s)).join(', ')
|
|
16
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type {TSESTree} from '@typescript-eslint/types'
|
|
2
|
-
|
|
3
|
-
interface NamedReExport {
|
|
4
|
-
declaration: TSESTree.ExportNamedDeclaration
|
|
5
|
-
group:
|
|
6
|
-
| 're-export-named'
|
|
7
|
-
| 're-export-type'
|
|
8
|
-
sortKey: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface ReExportAll {
|
|
12
|
-
declaration: TSESTree.ExportAllDeclaration
|
|
13
|
-
group: 're-export-all'
|
|
14
|
-
sortKey: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface ReExportNamespace {
|
|
18
|
-
declaration: TSESTree.ExportAllDeclaration
|
|
19
|
-
group: 're-export-namespace'
|
|
20
|
-
sortKey: string
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export type CategorizedReExport =
|
|
24
|
-
| NamedReExport
|
|
25
|
-
| ReExportAll
|
|
26
|
-
| ReExportNamespace
|