lint-rules-alvin 1.0.5 → 1.1.1
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/astro.js +2 -2
- package/eslint/configs/base.js +20 -2
- package/eslint/configs/custom.js +20 -9
- package/eslint/configs/importX.js +3 -1
- package/eslint/configs/importXTs.js +4 -2
- package/eslint/configs/json.js +7 -4
- package/eslint/configs/markdown.js +4 -1
- package/eslint/configs/reactHooks.js +9 -1
- package/eslint/configs/stylistic.js +7 -0
- package/eslint/configs/typescript.js +16 -5
- package/eslint/custom_rules/destructure-newline.js +88 -0
- package/eslint/custom_rules/jsx-multiline-prop-newline.js +23 -5
- package/eslint/custom_rules/jsx-no-single-object-curly-newline.js +23 -3
- package/eslint/custom_rules/max-chain-per-line.js +170 -77
- package/eslint/custom_rules/multiline-array-accessor-newline.js +193 -0
- package/eslint/custom_rules/multiline-paren-newline.js +192 -14
- package/eslint/custom_rules/newline-between-imports.js +10 -4
- package/eslint/custom_rules/unnamed-imports-last.js +1 -3
- package/eslint/presets/astroReactTs.js +1 -1
- package/package.json +42 -7
- package/eslint/custom_rules/chain-first-on-newline.js +0 -174
package/eslint/configs/astro.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import eslintPluginAstro from 'eslint-plugin-astro';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
4
|
+
* The ESLint Astro config. Extends `configs['flat/base']` and configures all rules.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* @type {import('eslint').Linter.Config}
|
|
7
7
|
*/
|
|
8
8
|
export const astro = [
|
|
9
9
|
...eslintPluginAstro.configs['flat/base'],
|
package/eslint/configs/base.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { includeIgnoreFile } from '@eslint/compat';
|
|
3
|
+
import eslintJs from '@eslint/js';
|
|
3
4
|
import { globalIgnores } from 'eslint/config';
|
|
5
|
+
import globals from 'globals';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* The
|
|
8
|
+
* The ESLint base config. Includes base rules, ignore files and directives,
|
|
9
|
+
* and the recommended eslintJs rules.
|
|
10
|
+
*
|
|
11
|
+
* @type {import('eslint').Linter.Config}
|
|
7
12
|
*/
|
|
8
13
|
export const base = [
|
|
9
14
|
includeIgnoreFile(
|
|
@@ -15,5 +20,18 @@ export const base = [
|
|
|
15
20
|
globalIgnores([
|
|
16
21
|
'eslint.config.js',
|
|
17
22
|
'eslint.config.ts'
|
|
18
|
-
])
|
|
23
|
+
]),
|
|
24
|
+
{
|
|
25
|
+
name: 'base/env',
|
|
26
|
+
languageOptions: {
|
|
27
|
+
ecmaVersion: 2020,
|
|
28
|
+
sourceType: 'module',
|
|
29
|
+
globals: {
|
|
30
|
+
...globals.browser,
|
|
31
|
+
...globals.nodeBuiltin,
|
|
32
|
+
...globals.serviceworker
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
eslintJs.configs.recommended
|
|
19
37
|
];
|
package/eslint/configs/custom.js
CHANGED
|
@@ -3,9 +3,15 @@ import { unnamedImportsLastRule } from '../custom_rules/unnamed-imports-last.js'
|
|
|
3
3
|
import { jsxMultilinePropNewlineRule } from '../custom_rules/jsx-multiline-prop-newline.js';
|
|
4
4
|
import { jsxNoSingleObjectCurlyNewlineRule } from '../custom_rules/jsx-no-single-object-curly-newline.js';
|
|
5
5
|
import { maxChainPerLineRule } from '../custom_rules/max-chain-per-line.js';
|
|
6
|
-
import { chainFirstOnNewlineRule } from '../custom_rules/chain-first-on-newline.js';
|
|
7
6
|
import { multilineParenNewlineRule } from '../custom_rules/multiline-paren-newline.js';
|
|
7
|
+
import { multilineArrayAccessorNewlineRule } from '../custom_rules/multiline-array-accessor-newline.js';
|
|
8
|
+
import { destructureNewlineRule } from '../custom_rules/destructure-newline.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Provides a config that creates a plugin and configures custom rules.
|
|
12
|
+
*
|
|
13
|
+
* @type {import('eslint').Linter.Config}
|
|
14
|
+
*/
|
|
9
15
|
export const custom = {
|
|
10
16
|
plugins: {
|
|
11
17
|
custom: {
|
|
@@ -15,8 +21,9 @@ export const custom = {
|
|
|
15
21
|
'jsx-multiline-prop-newline': jsxMultilinePropNewlineRule,
|
|
16
22
|
'jsx-no-single-object-curly-newline': jsxNoSingleObjectCurlyNewlineRule,
|
|
17
23
|
'max-chain-per-line': maxChainPerLineRule,
|
|
18
|
-
'
|
|
19
|
-
'multiline-
|
|
24
|
+
'multiline-paren-newline': multilineParenNewlineRule,
|
|
25
|
+
'multiline-array-accessor-newline': multilineArrayAccessorNewlineRule,
|
|
26
|
+
'destructure-newline': destructureNewlineRule
|
|
20
27
|
}
|
|
21
28
|
}
|
|
22
29
|
},
|
|
@@ -30,16 +37,20 @@ export const custom = {
|
|
|
30
37
|
'custom/jsx-no-single-object-curly-newline': 'error',
|
|
31
38
|
'custom/max-chain-per-line': [
|
|
32
39
|
'error',
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
{
|
|
41
|
+
maxChain: 2,
|
|
42
|
+
enforceSingleLine: true,
|
|
43
|
+
checkSingleLink: true
|
|
44
|
+
}
|
|
38
45
|
],
|
|
39
46
|
'custom/multiline-paren-newline': [
|
|
40
47
|
'error',
|
|
41
48
|
{ singleArgument: true }
|
|
49
|
+
],
|
|
50
|
+
'custom/multiline-array-accessor-newline': 'error',
|
|
51
|
+
'custom/destructure-newline': [
|
|
52
|
+
'error',
|
|
53
|
+
{ minItems: 2 }
|
|
42
54
|
]
|
|
43
55
|
}
|
|
44
56
|
};
|
|
45
|
-
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { importX as eslintPluginImportX } from 'eslint-plugin-import-x';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
4
|
+
* The ESLint import config. Configures all rules.
|
|
5
|
+
*
|
|
6
|
+
* @type {import('eslint').Linter.Config}
|
|
5
7
|
*/
|
|
6
8
|
export const importX = {
|
|
7
9
|
name: 'eslint-plugin-import-x',
|
|
@@ -2,9 +2,11 @@ import { importX as eslintPluginImportX } from 'eslint-plugin-import-x';
|
|
|
2
2
|
import { importX } from './index.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* The
|
|
5
|
+
* The ESLint import config with a TS resolver.
|
|
6
|
+
* Extends `../importX` and `flatConfigs.typescript` config.
|
|
7
|
+
*
|
|
8
|
+
* @type {import('eslint').Linter.Config}
|
|
6
9
|
*
|
|
7
|
-
* Extends `eslint-plugin-import-x`'s `typescript` flat config.
|
|
8
10
|
*/
|
|
9
11
|
export const importXTs = {
|
|
10
12
|
...importX,
|
package/eslint/configs/json.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import eslintPluginJsonc from 'eslint-plugin-jsonc';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
4
|
+
* The ESLint JSON config. Extends `flat/recommended-with-json`,
|
|
5
|
+
* `...with-jsonc` and `...with-json5` for the corresponding file types.
|
|
6
|
+
*
|
|
7
|
+
* @type {import('eslint').Linter.Config}
|
|
5
8
|
*/
|
|
6
9
|
export const json = [
|
|
7
|
-
{
|
|
10
|
+
{
|
|
8
11
|
name: 'eslint-plugin-json',
|
|
9
12
|
files: [ '**/*.{json}' ],
|
|
10
13
|
...eslintPluginJsonc.configs['flat/recommended-with-json']
|
|
11
14
|
},
|
|
12
|
-
{
|
|
15
|
+
{
|
|
13
16
|
name: 'eslint-plugin-jsonc',
|
|
14
17
|
files: [ '**/*.{jsonc}' ],
|
|
15
18
|
...eslintPluginJsonc.configs['flat/recommended-with-jsonc']
|
|
16
19
|
},
|
|
17
|
-
{
|
|
20
|
+
{
|
|
18
21
|
name: 'eslint-plugin-json5',
|
|
19
22
|
files: [ '**/*.{json5}' ],
|
|
20
23
|
...eslintPluginJsonc.configs['flat/recommended-with-json5']
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import eslintPluginMarkdown from 'eslint-plugin-markdown';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
4
|
+
* The ESLint markdown config. Extends `configs.recommended` only for `md` files.
|
|
5
|
+
*
|
|
6
|
+
* @type {import('eslint').Linter.Config}
|
|
7
|
+
*
|
|
5
8
|
*/
|
|
6
9
|
export const markdown = {
|
|
7
10
|
name: 'eslint-plugin-markdown',
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import eslintPluginReactHooks from 'eslint-plugin-react-hooks';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The ESLint `react-hooks` config. Extends `configs.flat.recommended` only for `jsx` and `tsx` files.
|
|
5
|
+
*
|
|
6
|
+
* @type {import('eslint').Linter.Config}
|
|
7
|
+
*/
|
|
3
8
|
export const reactHooks = {
|
|
4
9
|
name: 'eslint-plugin-react-hooks',
|
|
5
10
|
files: [ '**/*.{jsx,tsx}' ],
|
|
6
|
-
...eslintPluginReactHooks
|
|
11
|
+
...eslintPluginReactHooks
|
|
12
|
+
.configs
|
|
13
|
+
.flat
|
|
14
|
+
.recommended
|
|
7
15
|
};
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
// eslint-disable-next-line import-x/no-deprecated, import-x/namespace, import-x/default
|
|
1
2
|
import eslintPluginStylistic from '@stylistic/eslint-plugin';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The ESLint `stylistic` config. Extends `configs.recommended` and overrides all rules.
|
|
6
|
+
*
|
|
7
|
+
* @type {import('eslint').Linter.Config}
|
|
8
|
+
*/
|
|
3
9
|
export const stylistic = {
|
|
4
10
|
name: 'eslint-plugin-stylistic',
|
|
5
11
|
...eslintPluginStylistic.configs.recommended,
|
|
@@ -309,6 +315,7 @@ export const stylistic = {
|
|
|
309
315
|
'all',
|
|
310
316
|
{
|
|
311
317
|
ignoreJSX: 'multi-line',
|
|
318
|
+
nestedBinaryExpressions: false,
|
|
312
319
|
ignoredNodes: [
|
|
313
320
|
|
|
314
321
|
// Arrow function ternaries
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import eslintTs from 'typescript-eslint';
|
|
1
|
+
import eslintTs from '@typescript-eslint/eslint-plugin';
|
|
2
|
+
import eslintTsParser from '@typescript-eslint/parser';
|
|
2
3
|
|
|
3
4
|
/**
|
|
5
|
+
* The ESLint `typescript` config. Extends `configs.base`,
|
|
6
|
+
* enables `languageOptions.parserOptions.projectService` and configures all rules,
|
|
7
|
+
* only for `ts`, `tsx`, `mts` and `cts` files.
|
|
8
|
+
*
|
|
4
9
|
* @type {import('eslint').Linter.Config}
|
|
5
10
|
*/
|
|
6
11
|
export const typescript = {
|
|
@@ -11,8 +16,12 @@ export const typescript = {
|
|
|
11
16
|
'**/*.mts',
|
|
12
17
|
'**/*.cts'
|
|
13
18
|
],
|
|
14
|
-
...eslintTs.configs
|
|
15
|
-
languageOptions: {
|
|
19
|
+
...eslintTs.configs['flat/base'],
|
|
20
|
+
languageOptions: {
|
|
21
|
+
parser: eslintTsParser,
|
|
22
|
+
parserOptions: { projectService: true },
|
|
23
|
+
sourceType: 'module'
|
|
24
|
+
},
|
|
16
25
|
rules: {
|
|
17
26
|
'@typescript-eslint/array-type': [
|
|
18
27
|
'error',
|
|
@@ -458,7 +467,6 @@ export const typescript = {
|
|
|
458
467
|
'always'
|
|
459
468
|
],
|
|
460
469
|
'@typescript-eslint/sort-type-constituents': 'off', // Deprecated in favor of sort-intersection-types, etc.
|
|
461
|
-
'@typescript-eslint/strict-boolean-expressions': 'off',
|
|
462
470
|
'@typescript-eslint/strict-boolean-expressions': [
|
|
463
471
|
'error',
|
|
464
472
|
{
|
|
@@ -498,7 +506,10 @@ export const typescript = {
|
|
|
498
506
|
ignoreOverloadsWithDifferentJSDoc: true
|
|
499
507
|
}
|
|
500
508
|
],
|
|
501
|
-
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off'
|
|
509
|
+
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
|
|
510
|
+
|
|
511
|
+
// Other base ESLint overrides
|
|
512
|
+
'no-undef': 'off'
|
|
502
513
|
|
|
503
514
|
}
|
|
504
515
|
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @type {import('eslint').Rule.RuleModule}
|
|
3
|
+
*/
|
|
4
|
+
export const destructureNewlineRule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'layout',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Enforce newlines between properties in destructuring assignments',
|
|
9
|
+
category: 'Stylistic Issues',
|
|
10
|
+
recommended: false
|
|
11
|
+
},
|
|
12
|
+
fixable: 'whitespace',
|
|
13
|
+
schema: [
|
|
14
|
+
{
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
minItems: {
|
|
18
|
+
type: 'integer',
|
|
19
|
+
minimum: 2
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
additionalProperties: false
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
messages: { error: 'There should be a newline between destructuring properties.' }
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
create(context) {
|
|
29
|
+
|
|
30
|
+
const sourceCode = context.sourceCode;
|
|
31
|
+
const { minItems = 2 } = context.options[0] || {};
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
VariableDeclarator(node) {
|
|
35
|
+
|
|
36
|
+
if (node.id.type !== 'ObjectPattern') {
|
|
37
|
+
|
|
38
|
+
return;
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
const properties = node.id.properties;
|
|
42
|
+
|
|
43
|
+
if (properties.length < minItems) {
|
|
44
|
+
|
|
45
|
+
return;
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < properties.length - 1; i++) {
|
|
50
|
+
|
|
51
|
+
const currentProperty = properties[i];
|
|
52
|
+
const nextProperty = properties[i + 1];
|
|
53
|
+
|
|
54
|
+
const lastTokenOfCurrent = sourceCode.getLastToken(currentProperty);
|
|
55
|
+
const firstTokenOfNext = sourceCode.getFirstToken(nextProperty);
|
|
56
|
+
|
|
57
|
+
if (
|
|
58
|
+
lastTokenOfCurrent
|
|
59
|
+
.loc
|
|
60
|
+
.end
|
|
61
|
+
.line === firstTokenOfNext
|
|
62
|
+
.loc
|
|
63
|
+
.start
|
|
64
|
+
.line
|
|
65
|
+
) {
|
|
66
|
+
|
|
67
|
+
context.report({
|
|
68
|
+
node: nextProperty,
|
|
69
|
+
messageId: 'error',
|
|
70
|
+
fix(fixer) {
|
|
71
|
+
|
|
72
|
+
return fixer.insertTextBefore(
|
|
73
|
+
nextProperty,
|
|
74
|
+
'\n'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
};
|
|
@@ -20,7 +20,13 @@ export const jsxMultilinePropNewlineRule = {
|
|
|
20
20
|
|
|
21
21
|
function isMultiline(node) {
|
|
22
22
|
|
|
23
|
-
return node && node.loc && node
|
|
23
|
+
return node && node.loc && node
|
|
24
|
+
.loc
|
|
25
|
+
.start
|
|
26
|
+
.line < node
|
|
27
|
+
.loc
|
|
28
|
+
.end
|
|
29
|
+
.line;
|
|
24
30
|
|
|
25
31
|
}
|
|
26
32
|
|
|
@@ -63,7 +69,16 @@ export const jsxMultilinePropNewlineRule = {
|
|
|
63
69
|
const firstProp = node.attributes[0];
|
|
64
70
|
|
|
65
71
|
// Check if the tag name and the first prop are on the same line.
|
|
66
|
-
if (
|
|
72
|
+
if (
|
|
73
|
+
node
|
|
74
|
+
.name
|
|
75
|
+
.loc
|
|
76
|
+
.end
|
|
77
|
+
.line === firstProp
|
|
78
|
+
.loc
|
|
79
|
+
.start
|
|
80
|
+
.line
|
|
81
|
+
) {
|
|
67
82
|
|
|
68
83
|
context.report({
|
|
69
84
|
node: firstProp,
|
|
@@ -71,9 +86,12 @@ export const jsxMultilinePropNewlineRule = {
|
|
|
71
86
|
fix(fixer) {
|
|
72
87
|
|
|
73
88
|
// Get indentation of the line with the opening tag.
|
|
74
|
-
const line = sourceCode
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
const line = sourceCode.getLines()[
|
|
90
|
+
node
|
|
91
|
+
.loc
|
|
92
|
+
.start
|
|
93
|
+
.line - 1
|
|
94
|
+
];
|
|
77
95
|
const baseIndentMatch = line.match(/^\s*/);
|
|
78
96
|
const baseIndent = baseIndentMatch
|
|
79
97
|
? baseIndentMatch[0]
|
|
@@ -31,7 +31,15 @@ export const jsxNoSingleObjectCurlyNewlineRule = {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// If the expression itself isn't multiline, there are no newlines to collapse.
|
|
34
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
expression
|
|
36
|
+
.loc
|
|
37
|
+
.start
|
|
38
|
+
.line === expression
|
|
39
|
+
.loc
|
|
40
|
+
.end
|
|
41
|
+
.line
|
|
42
|
+
) {
|
|
35
43
|
|
|
36
44
|
return;
|
|
37
45
|
|
|
@@ -42,8 +50,20 @@ export const jsxNoSingleObjectCurlyNewlineRule = {
|
|
|
42
50
|
const firstTokenInExpression = sourceCode.getFirstToken(expression);
|
|
43
51
|
const lastTokenInExpression = sourceCode.getLastToken(expression);
|
|
44
52
|
|
|
45
|
-
const hasNewlineBefore = openingBrace
|
|
46
|
-
|
|
53
|
+
const hasNewlineBefore = openingBrace
|
|
54
|
+
.loc
|
|
55
|
+
.end
|
|
56
|
+
.line < firstTokenInExpression
|
|
57
|
+
.loc
|
|
58
|
+
.start
|
|
59
|
+
.line;
|
|
60
|
+
const hasNewlineAfter = lastTokenInExpression
|
|
61
|
+
.loc
|
|
62
|
+
.end
|
|
63
|
+
.line < closingBrace
|
|
64
|
+
.loc
|
|
65
|
+
.start
|
|
66
|
+
.line;
|
|
47
67
|
|
|
48
68
|
if (hasNewlineBefore || hasNewlineAfter) {
|
|
49
69
|
|