lint-rules-alvin 2.2.1 → 2.2.4
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/eslint/configs/custom.ts +0 -3
- package/eslint/configs/importX.ts +5 -5
- package/eslint/configs/perfectionist.ts +23 -1
- package/eslint/configs/typescript.ts +1 -1
- package/eslint/presets/sveltekitPreset.ts +1 -6
- package/package.json +1 -1
- package/eslint/custom_rules/unnamed-imports-last.ts +0 -105
- package/test/eslint/unnamed-imports-last.test.ts +0 -25
package/eslint/configs/custom.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
2
|
import { newlineBetweenImportsRule } from '../custom_rules/newline-between-imports';
|
|
3
|
-
import { unnamedImportsLastRule } from '../custom_rules/unnamed-imports-last';
|
|
4
3
|
import { jsxMultilinePropNewlineRule } from '../custom_rules/jsx-multiline-prop-newline';
|
|
5
4
|
import { maxChainPerLineRule } from '../custom_rules/max-chain-per-line';
|
|
6
5
|
import { multilineParenNewlineRule } from '../custom_rules/multiline-paren-newline';
|
|
@@ -15,7 +14,6 @@ export const custom: TSESLint.FlatConfig.Config = {
|
|
|
15
14
|
custom: {
|
|
16
15
|
rules: {
|
|
17
16
|
'newline-between-imports': newlineBetweenImportsRule,
|
|
18
|
-
'unnamed-imports-last': unnamedImportsLastRule,
|
|
19
17
|
'jsx-multiline-prop-newline': jsxMultilinePropNewlineRule,
|
|
20
18
|
'max-chain-per-line': maxChainPerLineRule,
|
|
21
19
|
'multiline-paren-newline': multilineParenNewlineRule,
|
|
@@ -29,7 +27,6 @@ export const custom: TSESLint.FlatConfig.Config = {
|
|
|
29
27
|
'error',
|
|
30
28
|
{ minItems: 2 }
|
|
31
29
|
],
|
|
32
|
-
'custom/unnamed-imports-last': 'error',
|
|
33
30
|
'custom/jsx-multiline-prop-newline': [
|
|
34
31
|
'error',
|
|
35
32
|
{
|
|
@@ -7,8 +7,8 @@ import { importX as eslintPluginImportX } from 'eslint-plugin-import-x';
|
|
|
7
7
|
export const importX: TSESLint.FlatConfig.Config = {
|
|
8
8
|
name: 'eslint-plugin-import-x',
|
|
9
9
|
plugins: { 'import-x': eslintPluginImportX },
|
|
10
|
-
...eslintPluginImportX.flatConfigs.typescript,
|
|
11
10
|
files: [ '**/*.{js,ts}' ],
|
|
11
|
+
...eslintPluginImportX.flatConfigs.typescript,
|
|
12
12
|
settings: {
|
|
13
13
|
'import-x/resolver': {
|
|
14
14
|
typescript: true,
|
|
@@ -50,7 +50,7 @@ export const importX: TSESLint.FlatConfig.Config = {
|
|
|
50
50
|
'import-x/no-relative-parent-imports': 'off',
|
|
51
51
|
'import-x/no-restricted-paths': 'off', // Allow the user to override
|
|
52
52
|
'import-x/no-self-import': 'error',
|
|
53
|
-
'import-x/no-unresolved': '
|
|
53
|
+
'import-x/no-unresolved': 'off', // Messes with some things, so make user override
|
|
54
54
|
'import-x/no-useless-path-segments': 'error',
|
|
55
55
|
'import-x/no-webpack-loader-syntax': 'error',
|
|
56
56
|
|
|
@@ -63,7 +63,7 @@ export const importX: TSESLint.FlatConfig.Config = {
|
|
|
63
63
|
'import-x/extensions': 'off',
|
|
64
64
|
'import-x/first': 'error',
|
|
65
65
|
'import-x/group-exports': 'off',
|
|
66
|
-
'import-x/imports-first': 'off', // Replaced by 'import/first'
|
|
66
|
+
'import-x/imports-first': 'off', // Replaced by 'import-x/first'
|
|
67
67
|
'import-x/max-dependencies': 'off',
|
|
68
68
|
'import-x/newline-after-import': [
|
|
69
69
|
'error',
|
|
@@ -72,14 +72,14 @@ export const importX: TSESLint.FlatConfig.Config = {
|
|
|
72
72
|
'import-x/no-anonymous-default-export': 'off', // See next rule
|
|
73
73
|
'import-x/no-default-export': 'error',
|
|
74
74
|
'import-x/no-duplicates': 'error',
|
|
75
|
-
'import-x/no-named-default': 'off', // In favor of 'import/no-default-export'
|
|
75
|
+
'import-x/no-named-default': 'off', // In favor of 'import-x/no-default-export'
|
|
76
76
|
'import-x/no-named-export': 'off',
|
|
77
77
|
'import-x/no-namespace': 'off',
|
|
78
78
|
'import-x/no-unassigned-import': [
|
|
79
79
|
'error',
|
|
80
80
|
{ allow: [ '**/*.css' ] }
|
|
81
81
|
],
|
|
82
|
-
'import-x/order': '
|
|
82
|
+
'import-x/order': 'off',
|
|
83
83
|
'import-x/prefer-default-export': 'off',
|
|
84
84
|
'import-x/prefer-namespace-import': 'off'
|
|
85
85
|
}
|
|
@@ -4,5 +4,27 @@ import eslintPluginPerfectionist from 'eslint-plugin-perfectionist';
|
|
|
4
4
|
export const perfectionist: TSESLint.FlatConfig.Config = {
|
|
5
5
|
name: 'eslint-plugin-perfectionist',
|
|
6
6
|
plugins: { eslintPluginPerfectionist },
|
|
7
|
-
...eslintPluginPerfectionist.configs['recommended-natural']
|
|
7
|
+
...eslintPluginPerfectionist.configs['recommended-natural'],
|
|
8
|
+
rules: {
|
|
9
|
+
|
|
10
|
+
'perfectionist/sort-imports': [
|
|
11
|
+
'error',
|
|
12
|
+
{
|
|
13
|
+
type: 'natural',
|
|
14
|
+
order: 'asc',
|
|
15
|
+
fallbackSort: { type: 'unsorted' },
|
|
16
|
+
ignoreCase: true,
|
|
17
|
+
specialCharacters: 'keep',
|
|
18
|
+
locales: 'en-US',
|
|
19
|
+
sortBy: 'path',
|
|
20
|
+
sortSideEffects: true,
|
|
21
|
+
partitionByComment: false,
|
|
22
|
+
partitionByNewLine: true,
|
|
23
|
+
newlinesBetween: 'ignore',
|
|
24
|
+
newlinesInside: 'ignore'
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
}
|
|
8
30
|
};
|
|
@@ -466,7 +466,7 @@ export const typescript: TSESLint.FlatConfig.Config = {
|
|
|
466
466
|
'error',
|
|
467
467
|
'always'
|
|
468
468
|
],
|
|
469
|
-
'@typescript-eslint/sort-type-constituents': 'off', // Deprecated in favor of sort-intersection-types, etc.
|
|
469
|
+
'@typescript-eslint/sort-type-constituents': 'off', // Deprecated in favor of perfectionist/sort-intersection-types, etc.
|
|
470
470
|
'@typescript-eslint/strict-boolean-expressions': [
|
|
471
471
|
'error',
|
|
472
472
|
{
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
3
|
import { defineConfig } from 'eslint/config';
|
|
4
|
-
import { importX as eslintPluginImportX } from 'eslint-plugin-import-x';
|
|
5
4
|
import { Linter } from 'eslint/universal';
|
|
6
5
|
import { base } from '../configs/base';
|
|
7
6
|
import { importX } from '../configs/importX';
|
|
@@ -18,11 +17,7 @@ export const sveltekitPreset = defineConfig(
|
|
|
18
17
|
base as any,
|
|
19
18
|
typescript as Linter.Config,
|
|
20
19
|
sveltekit as Linter.Config[],
|
|
21
|
-
|
|
22
|
-
...eslintPluginImportX.configs['flat/typescript'],
|
|
23
|
-
...importX
|
|
24
|
-
|
|
25
|
-
} as Linter.Config,
|
|
20
|
+
importX as Linter.Config,
|
|
26
21
|
stylistic as Linter.Config,
|
|
27
22
|
perfectionist as Linter.Config,
|
|
28
23
|
custom as Linter.Config,
|
package/package.json
CHANGED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
AST_NODE_TYPES,
|
|
4
|
-
ESLintUtils
|
|
5
|
-
} from '@typescript-eslint/utils';
|
|
6
|
-
|
|
7
|
-
export const unnamedImportsLastRule = ESLintUtils.RuleCreator.withoutDocs({
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'layout',
|
|
10
|
-
docs: { description: 'Enforce that unnamed imports (side-effect imports) are last' },
|
|
11
|
-
fixable: 'code',
|
|
12
|
-
schema: [],
|
|
13
|
-
messages: { error: 'Unnamed (side-effect) imports should be at the bottom of the import block.' }
|
|
14
|
-
},
|
|
15
|
-
defaultOptions: [],
|
|
16
|
-
create(context) {
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
20
|
-
'Program:exit'(program) {
|
|
21
|
-
|
|
22
|
-
const sourceCode = context.sourceCode;
|
|
23
|
-
const allImports = program.body.filter((node)=> node.type === AST_NODE_TYPES.ImportDeclaration);
|
|
24
|
-
|
|
25
|
-
if (allImports.length < 2) {
|
|
26
|
-
|
|
27
|
-
return;
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const regularImports = allImports.filter((node)=> node.specifiers.length > 0);
|
|
32
|
-
const sideEffectImports = allImports.filter((node)=> node.specifiers.length === 0);
|
|
33
|
-
|
|
34
|
-
if (regularImports.length === 0 || sideEffectImports.length === 0) {
|
|
35
|
-
|
|
36
|
-
return;
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const lastRegularImport = regularImports[regularImports.length - 1];
|
|
41
|
-
|
|
42
|
-
const misplacedImports = sideEffectImports.filter((node)=> node.range[0] < lastRegularImport.range[0]);
|
|
43
|
-
|
|
44
|
-
if (misplacedImports.length === 0) {
|
|
45
|
-
|
|
46
|
-
return;
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Report on the first misplaced import
|
|
51
|
-
const firstMisplaced = misplacedImports[0];
|
|
52
|
-
|
|
53
|
-
context.report({
|
|
54
|
-
node: firstMisplaced,
|
|
55
|
-
messageId: 'error',
|
|
56
|
-
fix(fixer) {
|
|
57
|
-
|
|
58
|
-
// Move the first misplaced side-effect import to after the last regular import
|
|
59
|
-
const moveNode = firstMisplaced;
|
|
60
|
-
const moveStart = moveNode.range[0];
|
|
61
|
-
let moveEnd = moveNode.range[1];
|
|
62
|
-
const text = sourceCode.text;
|
|
63
|
-
const endsWithSemicolon = text[moveEnd - 1] === ';';
|
|
64
|
-
|
|
65
|
-
if (!endsWithSemicolon) {
|
|
66
|
-
|
|
67
|
-
const ch = text[moveEnd] ?? '';
|
|
68
|
-
if (ch === '\n') {
|
|
69
|
-
|
|
70
|
-
moveEnd += 1;
|
|
71
|
-
|
|
72
|
-
} else if (ch === '\r') {
|
|
73
|
-
|
|
74
|
-
moveEnd += text[moveEnd + 1] === '\n'
|
|
75
|
-
? 2
|
|
76
|
-
: 1;
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const chunk = text.slice(
|
|
83
|
-
moveStart,
|
|
84
|
-
moveEnd
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
return [
|
|
88
|
-
fixer.removeRange([
|
|
89
|
-
moveStart,
|
|
90
|
-
moveEnd
|
|
91
|
-
]),
|
|
92
|
-
fixer.insertTextAfter(
|
|
93
|
-
lastRegularImport,
|
|
94
|
-
chunk
|
|
95
|
-
)
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { RuleTester } from '@typescript-eslint/rule-tester';
|
|
2
|
-
import { unnamedImportsLastRule } from '../../eslint/custom_rules/unnamed-imports-last.js';
|
|
3
|
-
|
|
4
|
-
new RuleTester().run(
|
|
5
|
-
'unnamed-imports-last',
|
|
6
|
-
unnamedImportsLastRule,
|
|
7
|
-
{
|
|
8
|
-
valid: [
|
|
9
|
-
'import { a } from \'./a\';import b from \'./b\';\nimport \'./side-effect\';',
|
|
10
|
-
'import a from \'./a\'\nimport { b } from \'./b\';\nimport \'./side-effect\';'
|
|
11
|
-
],
|
|
12
|
-
invalid: [
|
|
13
|
-
{
|
|
14
|
-
code: 'import \'./side-effect\';\nimport a from \'./a\';',
|
|
15
|
-
errors: [ { messageId: 'error' } ],
|
|
16
|
-
output: '\nimport a from \'./a\';import \'./side-effect\';'
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
code: '\nimport { a } from \'./a\';\nimport \'./side-effect\';import b from \'./b\';',
|
|
20
|
-
errors: [ { messageId: 'error' } ],
|
|
21
|
-
output: '\nimport { a } from \'./a\';\nimport b from \'./b\';import \'./side-effect\';'
|
|
22
|
-
}
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
);
|