@kikiutils/eslint-config 9.3.1 → 10.0.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 +8 -0
- package/dist/{internals → _internals}/plugins.d.ts.map +1 -1
- package/dist/{internals → _internals}/plugins.js +1 -1
- package/dist/_internals/plugins.js.map +1 -0
- package/dist/_internals/rules/compact-iteration-layout.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/compact-iteration-layout.js +1 -1
- package/dist/_internals/rules/compact-iteration-layout.js.map +1 -0
- package/dist/_internals/rules/consistent-condition-layout.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/consistent-condition-layout.js +1 -1
- package/dist/_internals/rules/consistent-condition-layout.js.map +1 -0
- package/dist/_internals/rules/consistent-parameter-layout.d.ts.map +1 -0
- package/dist/_internals/rules/consistent-parameter-layout.js +137 -0
- package/dist/_internals/rules/consistent-parameter-layout.js.map +1 -0
- package/dist/_internals/rules/statement-padding.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/statement-padding.js +22 -12
- package/dist/_internals/rules/statement-padding.js.map +1 -0
- package/dist/_internals/type-aware.d.ts +3 -0
- package/dist/_internals/type-aware.d.ts.map +1 -0
- package/dist/_internals/type-aware.js +25 -0
- package/dist/_internals/type-aware.js.map +1 -0
- package/dist/_internals/utils.d.ts.map +1 -0
- package/dist/{internals → _internals}/utils.js +1 -1
- package/dist/_internals/utils.js.map +1 -0
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +44 -17
- package/dist/base.js.map +1 -1
- package/dist/style.js +1 -5
- package/dist/style.js.map +1 -1
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +8 -4
- package/dist/vue.js.map +1 -1
- package/package.json +19 -70
- package/src/_internals/rules/consistent-parameter-layout.ts +244 -0
- package/src/{internals → _internals}/rules/statement-padding.ts +33 -22
- package/src/_internals/type-aware.ts +28 -0
- package/src/base.ts +67 -24
- package/src/style.ts +1 -2
- package/src/vue.ts +11 -4
- package/dist/internals/plugins.js.map +0 -1
- package/dist/internals/rules/compact-iteration-layout.d.ts.map +0 -1
- package/dist/internals/rules/compact-iteration-layout.js.map +0 -1
- package/dist/internals/rules/consistent-condition-layout.d.ts.map +0 -1
- package/dist/internals/rules/consistent-condition-layout.js.map +0 -1
- package/dist/internals/rules/consistent-parameter-layout.d.ts.map +0 -1
- package/dist/internals/rules/consistent-parameter-layout.js +0 -90
- package/dist/internals/rules/consistent-parameter-layout.js.map +0 -1
- package/dist/internals/rules/statement-padding.d.ts.map +0 -1
- package/dist/internals/rules/statement-padding.js.map +0 -1
- package/dist/internals/utils.d.ts.map +0 -1
- package/dist/internals/utils.js.map +0 -1
- package/src/internals/rules/consistent-parameter-layout.ts +0 -163
- /package/dist/{internals → _internals}/plugins.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/compact-iteration-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/consistent-condition-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/consistent-parameter-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/statement-padding.d.ts +0 -0
- /package/dist/{internals → _internals}/utils.d.ts +0 -0
- /package/src/{internals → _internals}/plugins.ts +0 -0
- /package/src/{internals → _internals}/rules/compact-iteration-layout.ts +0 -0
- /package/src/{internals → _internals}/rules/consistent-condition-layout.ts +0 -0
- /package/src/{internals → _internals}/utils.ts +0 -0
package/src/base.ts
CHANGED
|
@@ -2,10 +2,18 @@ import type {
|
|
|
2
2
|
Rules,
|
|
3
3
|
TypedFlatConfigItem,
|
|
4
4
|
} from '@antfu/eslint-config';
|
|
5
|
+
import {
|
|
6
|
+
GLOB_JS,
|
|
7
|
+
GLOB_JSX,
|
|
8
|
+
GLOB_TESTS,
|
|
9
|
+
GLOB_TS,
|
|
10
|
+
GLOB_TSX,
|
|
11
|
+
} from '@antfu/eslint-config';
|
|
5
12
|
// @ts-expect-error No declare file.
|
|
6
13
|
import promise from 'eslint-plugin-promise';
|
|
7
14
|
|
|
8
|
-
import { customPlugins } from './
|
|
15
|
+
import { customPlugins } from './_internals/plugins';
|
|
16
|
+
import { createTypeAwareConfig } from './_internals/type-aware';
|
|
9
17
|
|
|
10
18
|
// Constants/Variables
|
|
11
19
|
const basePerfectionistSortOptions = {
|
|
@@ -13,6 +21,18 @@ const basePerfectionistSortOptions = {
|
|
|
13
21
|
type: 'natural',
|
|
14
22
|
} as const;
|
|
15
23
|
|
|
24
|
+
const vscodeOrderSensitiveArrayProperties = [
|
|
25
|
+
'args',
|
|
26
|
+
'autoAttachSmartPattern',
|
|
27
|
+
'dependsOn',
|
|
28
|
+
'options',
|
|
29
|
+
'outFiles',
|
|
30
|
+
'problemMatcher',
|
|
31
|
+
'resolveSourceMapLocations',
|
|
32
|
+
'runtimeArgs',
|
|
33
|
+
'skipFiles',
|
|
34
|
+
].join('|');
|
|
35
|
+
|
|
16
36
|
// Functions
|
|
17
37
|
export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem[] {
|
|
18
38
|
return [
|
|
@@ -21,19 +41,19 @@ export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFl
|
|
|
21
41
|
rules: {
|
|
22
42
|
'e18e/ban-dependencies': [
|
|
23
43
|
'error',
|
|
24
|
-
{
|
|
25
|
-
allowed: [
|
|
26
|
-
'axios',
|
|
27
|
-
'rimraf',
|
|
28
|
-
],
|
|
29
|
-
},
|
|
44
|
+
{ allowed: ['axios'] },
|
|
30
45
|
],
|
|
31
|
-
'e18e/prefer-static-regex':
|
|
46
|
+
'e18e/prefer-static-regex': 'off',
|
|
32
47
|
},
|
|
33
48
|
},
|
|
34
|
-
// JavaScript
|
|
49
|
+
// JavaScript and TypeScript
|
|
35
50
|
{
|
|
36
|
-
files: [
|
|
51
|
+
files: [
|
|
52
|
+
GLOB_JS,
|
|
53
|
+
GLOB_JSX,
|
|
54
|
+
GLOB_TS,
|
|
55
|
+
GLOB_TSX,
|
|
56
|
+
],
|
|
37
57
|
plugins: {
|
|
38
58
|
kikiutils: customPlugins,
|
|
39
59
|
promise,
|
|
@@ -48,16 +68,14 @@ export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFl
|
|
|
48
68
|
},
|
|
49
69
|
// TypeScript
|
|
50
70
|
{
|
|
51
|
-
files: [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
},
|
|
71
|
+
files: [
|
|
72
|
+
GLOB_TS,
|
|
73
|
+
GLOB_TSX,
|
|
74
|
+
],
|
|
56
75
|
rules: {
|
|
57
|
-
|
|
58
|
-
'node/prefer-global/process': [
|
|
76
|
+
'ts/array-type': [
|
|
59
77
|
'error',
|
|
60
|
-
'
|
|
78
|
+
{ default: 'array-simple' },
|
|
61
79
|
],
|
|
62
80
|
'ts/consistent-generic-constructors': [
|
|
63
81
|
'error',
|
|
@@ -66,7 +84,28 @@ export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFl
|
|
|
66
84
|
'ts/no-redeclare': 'off',
|
|
67
85
|
},
|
|
68
86
|
},
|
|
69
|
-
//
|
|
87
|
+
// Type-aware TypeScript
|
|
88
|
+
{
|
|
89
|
+
...createTypeAwareConfig(),
|
|
90
|
+
files: [
|
|
91
|
+
GLOB_TS,
|
|
92
|
+
GLOB_TSX,
|
|
93
|
+
],
|
|
94
|
+
ignores: ['**/*.config.?([cm])ts'],
|
|
95
|
+
},
|
|
96
|
+
// Tests
|
|
97
|
+
{
|
|
98
|
+
files: GLOB_TESTS,
|
|
99
|
+
rules: {
|
|
100
|
+
'kikiutils/consistent-parameter-layout': [
|
|
101
|
+
'error',
|
|
102
|
+
{ compactTestCalls: true },
|
|
103
|
+
],
|
|
104
|
+
'test/valid-expect': 'error',
|
|
105
|
+
'test/valid-expect-in-promise': 'error',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
// VS Code JSONC
|
|
70
109
|
{
|
|
71
110
|
files: ['**/.vscode/*.json'],
|
|
72
111
|
rules: {
|
|
@@ -77,7 +116,9 @@ export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFl
|
|
|
77
116
|
natural: true,
|
|
78
117
|
type: 'asc',
|
|
79
118
|
},
|
|
80
|
-
|
|
119
|
+
// Preserve ordered fields and any argument or option arrays nested inside them.
|
|
120
|
+
// eslint-disable-next-line style/max-len
|
|
121
|
+
pathPattern: String.raw`^(?!.*(?:^|\.|\[")(?:${vscodeOrderSensitiveArrayProperties})(?:$|\.|\[|"\])).*`,
|
|
81
122
|
},
|
|
82
123
|
],
|
|
83
124
|
'jsonc/sort-keys': [
|
|
@@ -90,6 +131,8 @@ export function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFl
|
|
|
90
131
|
],
|
|
91
132
|
},
|
|
92
133
|
},
|
|
134
|
+
// Ignore all extracted Markdown code blocks, but keep linting Markdown itself.
|
|
135
|
+
{ ignores: ['**/*.md/**'] },
|
|
93
136
|
];
|
|
94
137
|
}
|
|
95
138
|
|
|
@@ -122,10 +165,12 @@ export function createBaseRules(environment: 'bun' | 'node' = 'node'): Rules {
|
|
|
122
165
|
'error',
|
|
123
166
|
1,
|
|
124
167
|
],
|
|
168
|
+
'no-constant-binary-expression': 'error',
|
|
125
169
|
'no-promise-executor-return': [
|
|
126
170
|
'error',
|
|
127
171
|
{ allowVoid: true },
|
|
128
172
|
],
|
|
173
|
+
'no-useless-assignment': 'error',
|
|
129
174
|
'perfectionist/sort-array-includes': [
|
|
130
175
|
'error',
|
|
131
176
|
basePerfectionistSortOptions,
|
|
@@ -139,10 +184,7 @@ export function createBaseRules(environment: 'bun' | 'node' = 'node'): Rules {
|
|
|
139
184
|
],
|
|
140
185
|
'perfectionist/sort-heritage-clauses': [
|
|
141
186
|
'error',
|
|
142
|
-
|
|
143
|
-
ignoreCase: false,
|
|
144
|
-
type: 'natural',
|
|
145
|
-
},
|
|
187
|
+
basePerfectionistSortOptions,
|
|
146
188
|
],
|
|
147
189
|
'perfectionist/sort-imports': [
|
|
148
190
|
'error',
|
|
@@ -259,6 +301,7 @@ export function createBaseRules(environment: 'bun' | 'node' = 'node'): Rules {
|
|
|
259
301
|
'error',
|
|
260
302
|
basePerfectionistSortOptions,
|
|
261
303
|
],
|
|
304
|
+
'preserve-caught-error': 'error',
|
|
262
305
|
'promise/no-multiple-resolved': 'error',
|
|
263
306
|
'promise/no-return-in-finally': 'error',
|
|
264
307
|
'promise/no-return-wrap': 'error',
|
package/src/style.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
2
2
|
import format from 'eslint-plugin-format';
|
|
3
3
|
|
|
4
|
-
function createPrettierCssConfig(parser: 'css' | '
|
|
4
|
+
function createPrettierCssConfig(parser: 'css' | 'scss'): TypedFlatConfigItem {
|
|
5
5
|
return {
|
|
6
6
|
files: [`**/*.${parser}`],
|
|
7
7
|
languageOptions: { parser: format.parserPlain },
|
|
@@ -23,7 +23,6 @@ function createPrettierCssConfig(parser: 'css' | 'sass' | 'scss'): TypedFlatConf
|
|
|
23
23
|
export function createStyleFilesConfigs(): TypedFlatConfigItem[] {
|
|
24
24
|
return [
|
|
25
25
|
createPrettierCssConfig('css'),
|
|
26
|
-
createPrettierCssConfig('sass'),
|
|
27
26
|
createPrettierCssConfig('scss'),
|
|
28
27
|
];
|
|
29
28
|
}
|
package/src/vue.ts
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import type { TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
2
2
|
import kikiutilsEslintPluginVue from '@kikiutils/eslint-plugin-vue';
|
|
3
|
-
import
|
|
3
|
+
import betterTailwindcss from 'eslint-plugin-better-tailwindcss';
|
|
4
4
|
// @ts-expect-error No declare file.
|
|
5
5
|
import promise from 'eslint-plugin-promise';
|
|
6
6
|
|
|
7
|
+
import { customPlugins } from './_internals/plugins';
|
|
8
|
+
import { createTypeAwareConfig } from './_internals/type-aware';
|
|
7
9
|
import { createBaseRules } from './base';
|
|
8
|
-
import { customPlugins } from './internals/plugins';
|
|
9
10
|
|
|
10
11
|
export function createVueConfig(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem {
|
|
12
|
+
const typeAwareConfig = createTypeAwareConfig();
|
|
11
13
|
return {
|
|
12
14
|
files: ['**/*.vue'],
|
|
15
|
+
languageOptions: typeAwareConfig.languageOptions,
|
|
13
16
|
plugins: {
|
|
14
17
|
'@kikiutils/vue': kikiutilsEslintPluginVue,
|
|
15
|
-
'better-tailwindcss':
|
|
18
|
+
'better-tailwindcss': betterTailwindcss,
|
|
16
19
|
'kikiutils': customPlugins,
|
|
17
20
|
promise,
|
|
18
21
|
},
|
|
19
22
|
rules: {
|
|
20
23
|
...createBaseRules(environment),
|
|
24
|
+
...typeAwareConfig.rules,
|
|
21
25
|
'@kikiutils/vue/attributes-order': [
|
|
22
26
|
'error',
|
|
23
27
|
{
|
|
@@ -35,6 +39,10 @@ export function createVueConfig(environment: 'bun' | 'node' = 'node'): TypedFlat
|
|
|
35
39
|
'better-tailwindcss/no-duplicate-classes': 'error',
|
|
36
40
|
'better-tailwindcss/no-unnecessary-whitespace': 'error',
|
|
37
41
|
'style/max-len': 'off',
|
|
42
|
+
'ts/array-type': [
|
|
43
|
+
'error',
|
|
44
|
+
{ default: 'array-simple' },
|
|
45
|
+
],
|
|
38
46
|
'vue/attribute-hyphenation': 'error',
|
|
39
47
|
'vue/attributes-order': 'off',
|
|
40
48
|
'vue/block-order': [
|
|
@@ -80,7 +88,6 @@ export function createVueConfig(environment: 'bun' | 'node' = 'node'): TypedFlat
|
|
|
80
88
|
'vue/no-template-target-blank': 'error',
|
|
81
89
|
'vue/no-v-html': 'error',
|
|
82
90
|
'vue/prefer-define-options': 'error',
|
|
83
|
-
'vue/prefer-separate-static-class': 'error',
|
|
84
91
|
'vue/require-explicit-emits': 'error',
|
|
85
92
|
'vue/require-typed-ref': 'error',
|
|
86
93
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","names":[],"sources":["../../src/internals/plugins.ts"],"sourcesContent":["import { compactIterationLayout } from './rules/compact-iteration-layout';\nimport { consistentConditionLayout } from './rules/consistent-condition-layout';\nimport { consistentParameterLayout } from './rules/consistent-parameter-layout';\nimport { statementPadding } from './rules/statement-padding';\n\nexport const customPlugins = {\n rules: {\n 'compact-iteration-layout': compactIterationLayout,\n 'consistent-condition-layout': consistentConditionLayout,\n 'consistent-parameter-layout': consistentParameterLayout,\n 'statement-padding': statementPadding,\n },\n};\n"],"mappings":";;;;;AAKA,MAAa,gBAAgB,EACzB,OAAO;CACH,4BAA4B;CAC5B,+BAA+B;CAC/B,+BAA+B;CAC/B,qBAAqB;AACzB,EACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compact-iteration-layout.d.ts","names":[],"sources":["../../../src/internals/rules/compact-iteration-layout.ts"],"mappings":";qBAIa,wBAAwB,KAAK"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compact-iteration-layout.js","names":[],"sources":["../../../src/internals/rules/compact-iteration-layout.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\ntype IterationNode = Extract<Rule.Node, { type: 'ForInStatement' | 'ForOfStatement' }>;\n\nexport const compactIterationLayout: Rule.RuleModule = {\n create(context) {\n const { sourceCode } = context;\n\n function checkParentheses(node: IterationNode): void {\n const openingParen = sourceCode.getFirstToken(node, (token) => token.value === '(')!;\n const closingParen = sourceCode.getTokenBefore(node.body)!;\n const next = sourceCode.getTokenAfter(openingParen)!;\n const previous = sourceCode.getTokenBefore(closingParen)!;\n const ranges: Array<[number, number]> = [];\n\n if (\n openingParen.loc.end.line !== next.loc.start.line\n && !sourceCode.commentsExistBetween(openingParen, next)\n ) {\n ranges.push([\n openingParen.range[1],\n next.range[0],\n ]);\n }\n\n if (\n previous.loc.end.line !== closingParen.loc.start.line\n && !sourceCode.commentsExistBetween(previous, closingParen)\n ) {\n ranges.push([\n previous.range[1],\n closingParen.range[0],\n ]);\n }\n\n if (ranges.length) {\n context.report({\n fix: (fixer) => ranges.map((range) => fixer.replaceTextRange(range, '')),\n messageId: 'compact',\n node,\n });\n }\n }\n\n return {\n ForInStatement: checkParentheses,\n ForOfStatement: checkParentheses,\n };\n },\n meta: {\n docs: { description: 'Keep for-in and for-of parentheses beside their header contents.' },\n fixable: 'whitespace',\n messages: { compact: 'Keep iteration parentheses on the same lines as their adjacent header contents.' },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":";AAIA,MAAa,yBAA0C;CACnD,OAAO,SAAS;EACZ,MAAM,EAAE,eAAe;EAEvB,SAAS,iBAAiB,MAA2B;GACjD,MAAM,eAAe,WAAW,cAAc,OAAO,UAAU,MAAM,UAAU,GAAG;GAClF,MAAM,eAAe,WAAW,eAAe,KAAK,IAAI;GACxD,MAAM,OAAO,WAAW,cAAc,YAAY;GAClD,MAAM,WAAW,WAAW,eAAe,YAAY;GACvD,MAAM,SAAkC,CAAC;GAEzC,IACI,aAAa,IAAI,IAAI,SAAS,KAAK,IAAI,MAAM,QAC1C,CAAC,WAAW,qBAAqB,cAAc,IAAI,GAEtD,OAAO,KAAK,CACR,aAAa,MAAM,IACnB,KAAK,MAAM,EACf,CAAC;GAGL,IACI,SAAS,IAAI,IAAI,SAAS,aAAa,IAAI,MAAM,QAC9C,CAAC,WAAW,qBAAqB,UAAU,YAAY,GAE1D,OAAO,KAAK,CACR,SAAS,MAAM,IACf,aAAa,MAAM,EACvB,CAAC;GAGL,IAAI,OAAO,QACP,QAAQ,OAAO;IACX,MAAM,UAAU,OAAO,KAAK,UAAU,MAAM,iBAAiB,OAAO,EAAE,CAAC;IACvE,WAAW;IACX;GACJ,CAAC;EAET;EAEA,OAAO;GACH,gBAAgB;GAChB,gBAAgB;EACpB;CACJ;CACA,MAAM;EACF,MAAM,EAAE,aAAa,mEAAmE;EACxF,SAAS;EACT,UAAU,EAAE,SAAS,kFAAkF;EACvG,QAAQ,CAAC;EACT,MAAM;CACV;AACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consistent-condition-layout.d.ts","names":[],"sources":["../../../src/internals/rules/consistent-condition-layout.ts"],"mappings":";qBAUa,2BAA2B,KAAK"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consistent-condition-layout.js","names":[],"sources":["../../../src/internals/rules/consistent-condition-layout.ts"],"sourcesContent":["import type {\n AST,\n Rule,\n} from 'eslint';\n\nimport type { TokenStore } from '../utils';\nimport { defineScriptAndTemplateVisitors } from '../utils';\n\ntype LogicalNode = Extract<Rule.Node, { type: 'LogicalExpression' }>;\n\nexport const consistentConditionLayout: Rule.RuleModule = {\n create(context) {\n function createVisitor(tokenStore: TokenStore): Rule.RuleListener {\n const checkedOpeningOffsets = new Set<number>();\n\n function collectOperators(node: LogicalNode['left'], operators: AST.Token[]): void {\n if (node.type !== 'LogicalExpression' || (node.operator !== '&&' && node.operator !== '||')) return;\n const operator = tokenStore.getTokensBetween(node.left, node.right)\n .find((token) => token.type === 'Punctuator' && token.value === node.operator)!;\n\n function collectChild(child: LogicalNode['left']): void {\n const before = tokenStore.getTokenBefore(child);\n const after = tokenStore.getTokenAfter(child);\n if (\n before?.value === '('\n && after?.value === ')'\n && before.range[0] >= node.range![0]\n && after.range[1] <= node.range![1]\n ) return;\n\n collectOperators(child, operators);\n }\n\n collectChild(node.left);\n operators.push(operator);\n collectChild(node.right);\n }\n\n function checkParentheses(node: LogicalNode['left']): void {\n let openingParen = tokenStore.getTokenBefore(node);\n let closingParen = tokenStore.getTokenAfter(node);\n let operators: AST.Token[] | undefined;\n const newlineOffsets: number[] = [];\n while (openingParen?.value === '(' && closingParen?.value === ')') {\n if (\n !checkedOpeningOffsets.has(openingParen.range[0])\n && openingParen.loc.start.line !== closingParen.loc.end.line\n ) {\n checkedOpeningOffsets.add(openingParen.range[0]);\n if (!operators) {\n operators = [];\n collectOperators(node, operators);\n }\n\n const next = tokenStore.getTokenAfter(openingParen)!;\n if (openingParen.loc.end.line === next.loc.start.line) {\n newlineOffsets.push(openingParen.range[1]);\n }\n\n for (const operator of operators) {\n if (tokenStore.getTokenBefore(operator)!.loc.end.line === operator.loc.start.line) {\n newlineOffsets.push(operator.range[0]);\n }\n }\n\n if (tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line) {\n newlineOffsets.push(closingParen.range[0]);\n }\n }\n\n openingParen = tokenStore.getTokenBefore(openingParen);\n closingParen = tokenStore.getTokenAfter(closingParen);\n // An outer pair contains one grouped item, not the inner logical chain.\n operators = [];\n }\n\n if (newlineOffsets.length) {\n context.report({\n fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextBeforeRange(\n [\n offset,\n offset,\n ],\n '\\n',\n )),\n messageId: 'newline',\n node,\n });\n }\n }\n\n return {\n BinaryExpression: (node) => {\n if (\n [\n '!=',\n '!==',\n '<',\n '<=',\n '==',\n '===',\n '>',\n '>=',\n 'in',\n 'instanceof',\n ].includes(node.operator)\n ) checkParentheses(node);\n },\n DoWhileStatement: (node) => checkParentheses(node.test),\n IfStatement: (node) => checkParentheses(node.test),\n LogicalExpression: (node) => {\n if (node.operator === '&&' || node.operator === '||') checkParentheses(node);\n },\n UnaryExpression: (node) => {\n if (node.operator === '!') checkParentheses(node);\n },\n WhileStatement: (node) => checkParentheses(node.test),\n };\n }\n\n return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);\n },\n meta: {\n docs: { description: 'Expand multiline parenthesized conditions one logical item per line.' },\n fixable: 'whitespace',\n messages: { newline: 'Put each logical item and both parentheses on separate lines in a multiline condition.' },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":";;AAUA,MAAa,4BAA6C;CACtD,OAAO,SAAS;EACZ,SAAS,cAAc,YAA2C;GAC9D,MAAM,wCAAwB,IAAI,IAAY;GAE9C,SAAS,iBAAiB,MAA2B,WAA8B;IAC/E,IAAI,KAAK,SAAS,uBAAwB,KAAK,aAAa,QAAQ,KAAK,aAAa,MAAO;IAC7F,MAAM,WAAW,WAAW,iBAAiB,KAAK,MAAM,KAAK,KAAK,CAAC,CAC9D,MAAM,UAAU,MAAM,SAAS,gBAAgB,MAAM,UAAU,KAAK,QAAQ;IAEjF,SAAS,aAAa,OAAkC;KACpD,MAAM,SAAS,WAAW,eAAe,KAAK;KAC9C,MAAM,QAAQ,WAAW,cAAc,KAAK;KAC5C,IACI,QAAQ,UAAU,OACf,OAAO,UAAU,OACjB,OAAO,MAAM,MAAM,KAAK,MAAO,MAC/B,MAAM,MAAM,MAAM,KAAK,MAAO,IACnC;KAEF,iBAAiB,OAAO,SAAS;IACrC;IAEA,aAAa,KAAK,IAAI;IACtB,UAAU,KAAK,QAAQ;IACvB,aAAa,KAAK,KAAK;GAC3B;GAEA,SAAS,iBAAiB,MAAiC;IACvD,IAAI,eAAe,WAAW,eAAe,IAAI;IACjD,IAAI,eAAe,WAAW,cAAc,IAAI;IAChD,IAAI;IACJ,MAAM,iBAA2B,CAAC;IAClC,OAAO,cAAc,UAAU,OAAO,cAAc,UAAU,KAAK;KAC/D,IACI,CAAC,sBAAsB,IAAI,aAAa,MAAM,EAAE,KAC7C,aAAa,IAAI,MAAM,SAAS,aAAa,IAAI,IAAI,MAC1D;MACE,sBAAsB,IAAI,aAAa,MAAM,EAAE;MAC/C,IAAI,CAAC,WAAW;OACZ,YAAY,CAAC;OACb,iBAAiB,MAAM,SAAS;MACpC;MAEA,MAAM,OAAO,WAAW,cAAc,YAAY;MAClD,IAAI,aAAa,IAAI,IAAI,SAAS,KAAK,IAAI,MAAM,MAC7C,eAAe,KAAK,aAAa,MAAM,EAAE;MAG7C,KAAK,MAAM,YAAY,WACnB,IAAI,WAAW,eAAe,QAAQ,CAAC,CAAE,IAAI,IAAI,SAAS,SAAS,IAAI,MAAM,MACzE,eAAe,KAAK,SAAS,MAAM,EAAE;MAI7C,IAAI,WAAW,eAAe,YAAY,CAAC,CAAE,IAAI,IAAI,SAAS,aAAa,IAAI,MAAM,MACjF,eAAe,KAAK,aAAa,MAAM,EAAE;KAEjD;KAEA,eAAe,WAAW,eAAe,YAAY;KACrD,eAAe,WAAW,cAAc,YAAY;KAEpD,YAAY,CAAC;IACjB;IAEA,IAAI,eAAe,QACf,QAAQ,OAAO;KACX,MAAM,UAAU,eAAe,KAAK,WAAW,MAAM,sBACjD,CACI,QACA,MACJ,GACA,IACJ,CAAC;KACD,WAAW;KACX;IACJ,CAAC;GAET;GAEA,OAAO;IACH,mBAAmB,SAAS;KACxB,IACI;MACI;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;KACJ,CAAC,CAAC,SAAS,KAAK,QAAQ,GAC1B,iBAAiB,IAAI;IAC3B;IACA,mBAAmB,SAAS,iBAAiB,KAAK,IAAI;IACtD,cAAc,SAAS,iBAAiB,KAAK,IAAI;IACjD,oBAAoB,SAAS;KACzB,IAAI,KAAK,aAAa,QAAQ,KAAK,aAAa,MAAM,iBAAiB,IAAI;IAC/E;IACA,kBAAkB,SAAS;KACvB,IAAI,KAAK,aAAa,KAAK,iBAAiB,IAAI;IACpD;IACA,iBAAiB,SAAS,iBAAiB,KAAK,IAAI;GACxD;EACJ;EAEA,OAAO,gCAAgC,QAAQ,YAAY,aAAa;CAC5E;CACA,MAAM;EACF,MAAM,EAAE,aAAa,uEAAuE;EAC5F,SAAS;EACT,UAAU,EAAE,SAAS,yFAAyF;EAC9G,QAAQ,CAAC;EACT,MAAM;CACV;AACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consistent-parameter-layout.d.ts","names":[],"sources":["../../../src/internals/rules/consistent-parameter-layout.ts"],"mappings":";qBAaa,2BAA2B,KAAK"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { defineScriptAndTemplateVisitors } from "../utils.js";
|
|
2
|
-
// src/internals/rules/consistent-parameter-layout.ts
|
|
3
|
-
const consistentParameterLayout = {
|
|
4
|
-
create(context) {
|
|
5
|
-
const isTestFile = /\.test\.[jt]sx?$/.test(context.filename);
|
|
6
|
-
function checkParameterLayout(node, items, tokenStore, isTemplate) {
|
|
7
|
-
const first = items[0];
|
|
8
|
-
if (!first) return;
|
|
9
|
-
const isSingleParameter = items.length === 1;
|
|
10
|
-
const firstType = first.type;
|
|
11
|
-
if (isSingleParameter && (firstType === "JSXElement" || firstType === "JSXFragment")) return;
|
|
12
|
-
let openingParen;
|
|
13
|
-
if (node.type === "CallExpression" || node.type === "NewExpression") {
|
|
14
|
-
const call = node;
|
|
15
|
-
openingParen = tokenStore.getTokenAfter(call.typeArguments ?? call.callee, (token) => token.type === "Punctuator" && token.value === "(");
|
|
16
|
-
} else openingParen = tokenStore.getTokenBefore(first);
|
|
17
|
-
if (!openingParen || openingParen.value !== "(") return;
|
|
18
|
-
if (openingParen.range[0] < node.range[0]) return;
|
|
19
|
-
const closingParen = node.type === "CallExpression" || node.type === "NewExpression" ? tokenStore.getLastToken(node) : tokenStore.getTokenAfter(items.at(-1), (token) => token.value === ")");
|
|
20
|
-
const next = tokenStore.getTokenAfter(openingParen);
|
|
21
|
-
if (isSingleParameter) {
|
|
22
|
-
if (!closingParen || closingParen.value !== ")") return;
|
|
23
|
-
let previous = tokenStore.getTokenBefore(closingParen);
|
|
24
|
-
if (previous.value === ",") previous = tokenStore.getTokenBefore(previous);
|
|
25
|
-
if (tokenStore.commentsExistBetween(openingParen, next) || tokenStore.commentsExistBetween(previous, closingParen)) return;
|
|
26
|
-
const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;
|
|
27
|
-
if (hasOpeningNewline === (tokenStore.getTokenBefore(closingParen).loc.end.line !== closingParen.loc.start.line)) return;
|
|
28
|
-
context.report({
|
|
29
|
-
fix: (fixer) => hasOpeningNewline ? fixer.insertTextBefore(closingParen, "\n") : fixer.insertTextAfter(openingParen, "\n"),
|
|
30
|
-
messageId: "singleBoundary",
|
|
31
|
-
node
|
|
32
|
-
});
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;
|
|
36
|
-
if (isTemplate) {
|
|
37
|
-
const newlineOffsets = [];
|
|
38
|
-
if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);
|
|
39
|
-
for (let index = 1; index < items.length; index++) {
|
|
40
|
-
const item = items[index];
|
|
41
|
-
const comma = tokenStore.getTokensBetween(items[index - 1], item).find((token) => token.value === ",");
|
|
42
|
-
if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma).loc.start.line) newlineOffsets.push(comma.range[1]);
|
|
43
|
-
}
|
|
44
|
-
if (closingParen.value === ")" && tokenStore.getTokenBefore(closingParen).loc.end.line === closingParen.loc.start.line) newlineOffsets.push(closingParen.range[0]);
|
|
45
|
-
if (newlineOffsets.length) context.report({
|
|
46
|
-
fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextAfterRange([offset, offset], "\n")),
|
|
47
|
-
messageId: "newline",
|
|
48
|
-
node: first
|
|
49
|
-
});
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (openingParen.loc.end.line !== next.loc.start.line) return;
|
|
53
|
-
context.report({
|
|
54
|
-
fix: (fixer) => fixer.insertTextAfter(openingParen, "\n"),
|
|
55
|
-
messageId: "newline",
|
|
56
|
-
node: first
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
function createVisitor(tokenStore, isTemplate) {
|
|
60
|
-
return {
|
|
61
|
-
ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
62
|
-
CallExpression: (node) => {
|
|
63
|
-
const { callee } = node;
|
|
64
|
-
if (isTestFile) {
|
|
65
|
-
const target = callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && callee.property.name === "concurrent" ? callee.object : callee;
|
|
66
|
-
if (target.type === "Identifier" && (target.name === "describe" || target.name === "it")) return;
|
|
67
|
-
}
|
|
68
|
-
checkParameterLayout(node, node.arguments, tokenStore, isTemplate);
|
|
69
|
-
},
|
|
70
|
-
FunctionDeclaration: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
71
|
-
FunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
72
|
-
NewExpression: (node) => checkParameterLayout(node, node.arguments, tokenStore, isTemplate)
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);
|
|
76
|
-
},
|
|
77
|
-
meta: {
|
|
78
|
-
docs: { description: "Preserve consistent single-parameter boundaries and expand multiline parameter lists." },
|
|
79
|
-
fixable: "whitespace",
|
|
80
|
-
messages: {
|
|
81
|
-
newline: "Start a multiline parameter list on a new line.",
|
|
82
|
-
singleBoundary: "Use matching newline boundaries around a single parameter."
|
|
83
|
-
},
|
|
84
|
-
schema: [],
|
|
85
|
-
type: "layout"
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
export { consistentParameterLayout };
|
|
89
|
-
|
|
90
|
-
//# sourceMappingURL=consistent-parameter-layout.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consistent-parameter-layout.js","names":[],"sources":["../../../src/internals/rules/consistent-parameter-layout.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\nimport type { TokenStore } from '../utils';\nimport { defineScriptAndTemplateVisitors } from '../utils';\n\ntype CallNode = Extract<Rule.Node, { type: 'CallExpression' | 'NewExpression' }> & { typeArguments?: Rule.Node };\ntype FunctionNode = Extract<\n Rule.Node,\n { type: 'ArrowFunctionExpression' | 'FunctionDeclaration' | 'FunctionExpression' }\n>;\n\ntype ListItem = CallNode['arguments'][number] | FunctionNode['params'][number];\n\nexport const consistentParameterLayout: Rule.RuleModule = {\n create(context) {\n const isTestFile = /\\.test\\.[jt]sx?$/.test(context.filename);\n\n function checkParameterLayout(\n node: Rule.Node,\n items: readonly ListItem[],\n tokenStore: TokenStore,\n isTemplate: boolean,\n ): void {\n const first = items[0];\n if (!first) return;\n const isSingleParameter = items.length === 1;\n\n // JSX argument layout belongs to the JSX formatting rules.\n const firstType: string = first.type;\n if (isSingleParameter && (firstType === 'JSXElement' || firstType === 'JSXFragment')) return;\n let openingParen;\n if (node.type === 'CallExpression' || node.type === 'NewExpression') {\n const call = node as CallNode;\n openingParen = tokenStore.getTokenAfter(\n call.typeArguments ?? call.callee,\n (token) => token.type === 'Punctuator' && token.value === '(',\n );\n } else {\n openingParen = tokenStore.getTokenBefore(first);\n }\n\n if (!openingParen || openingParen.value !== '(') return;\n // An unparenthesized arrow must not borrow its parent's delimiters.\n if (openingParen.range[0] < node.range![0]) return;\n const closingParen = node.type === 'CallExpression' || node.type === 'NewExpression'\n ? tokenStore.getLastToken(node)\n : tokenStore.getTokenAfter(items.at(-1)!, (token) => token.value === ')');\n\n const next = tokenStore.getTokenAfter(openingParen)!;\n\n if (isSingleParameter) {\n if (!closingParen || closingParen.value !== ')') return;\n let previous = tokenStore.getTokenBefore(closingParen)!;\n if (previous.value === ',') previous = tokenStore.getTokenBefore(previous)!;\n if (\n tokenStore.commentsExistBetween(openingParen, next)\n || tokenStore.commentsExistBetween(previous, closingParen)\n ) return;\n\n const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;\n const hasClosingNewline = tokenStore.getTokenBefore(closingParen)!.loc.end.line\n !== closingParen.loc.start.line;\n\n if (hasOpeningNewline === hasClosingNewline) return;\n\n context.report({\n fix: (fixer) => hasOpeningNewline\n ? fixer.insertTextBefore(closingParen, '\\n')\n : fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'singleBoundary',\n node,\n });\n\n return;\n }\n\n if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;\n\n if (isTemplate) {\n // Script list formatters do not traverse Vue template expressions.\n const newlineOffsets: number[] = [];\n if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);\n for (let index = 1; index < items.length; index++) {\n const item = items[index]!;\n const comma = tokenStore.getTokensBetween(items[index - 1]!, item)\n .find((token) => token.value === ',');\n\n if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma)!.loc.start.line) {\n newlineOffsets.push(comma.range[1]);\n }\n }\n\n if (\n closingParen.value === ')'\n && tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line\n ) newlineOffsets.push(closingParen.range[0]);\n\n if (newlineOffsets.length) {\n context.report({\n fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextAfterRange(\n [\n offset,\n offset,\n ],\n '\\n',\n )),\n messageId: 'newline',\n node: first,\n });\n }\n\n return;\n }\n\n if (openingParen.loc.end.line !== next.loc.start.line) return;\n\n context.report({\n fix: (fixer) => fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'newline',\n node: first,\n });\n }\n\n function createVisitor(tokenStore: TokenStore, isTemplate: boolean): Rule.RuleListener {\n return {\n ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n CallExpression: (node) => {\n const { callee } = node;\n if (isTestFile) {\n const target = callee.type === 'MemberExpression'\n && !callee.computed\n && callee.property.type === 'Identifier'\n && callee.property.name === 'concurrent'\n ? callee.object\n : callee;\n\n if (\n target.type === 'Identifier'\n && (target.name === 'describe' || target.name === 'it')\n ) return;\n }\n\n checkParameterLayout(node, node.arguments, tokenStore, isTemplate);\n },\n FunctionDeclaration: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n FunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n NewExpression: (node) => checkParameterLayout(node, node.arguments, tokenStore, isTemplate),\n };\n }\n\n return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);\n },\n meta: {\n docs: { description: 'Preserve consistent single-parameter boundaries and expand multiline parameter lists.' },\n fixable: 'whitespace',\n messages: {\n newline: 'Start a multiline parameter list on a new line.',\n singleBoundary: 'Use matching newline boundaries around a single parameter.',\n },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"statement-padding.d.ts","names":[],"sources":["../../../src/internals/rules/statement-padding.ts"],"mappings":";qBAIa,kBAAkB,KAAK"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"statement-padding.js","names":[],"sources":["../../../src/internals/rules/statement-padding.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\ntype StatementNode = Extract<Rule.Node, { type: 'Program' }>['body'][number];\n\nexport const statementPadding: Rule.RuleModule = {\n create(context) {\n const { sourceCode } = context;\n\n function checkStatements(statements: readonly StatementNode[]): void {\n for (let index = 1; index < statements.length; index++) {\n const previous = statements[index - 1]!;\n const next = statements[index]!;\n const lastToken = sourceCode.getLastToken(previous)!;\n const firstToken = sourceCode.getFirstToken(next)!;\n const closingLine = sourceCode.lines[lastToken.loc.end.line - 1]!;\n const openingLine = sourceCode.lines[firstToken.loc.start.line - 1]!;\n const hasDifferentIndent = /^\\s*/.exec(closingLine)![0] !== /^\\s*/.exec(openingLine)![0];\n const hasStandaloneClosing = /^[)\\]}]+;?$/.test(closingLine.slice(0, lastToken.loc.end.column).trim());\n const blockNode = previous.type === 'ExportDefaultDeclaration'\n || previous.type === 'ExportNamedDeclaration'\n ? previous.declaration\n : previous;\n\n const hasBlockClosing = lastToken.value === '}' && blockNode && [\n 'BlockStatement',\n 'ClassDeclaration',\n 'ForInStatement',\n 'ForOfStatement',\n 'ForStatement',\n 'FunctionDeclaration',\n 'IfStatement',\n 'LabeledStatement',\n 'SwitchStatement',\n 'TryStatement',\n 'WhileStatement',\n 'WithStatement',\n ].includes(blockNode.type);\n\n if (!hasDifferentIndent && !hasStandaloneClosing && !hasBlockClosing) continue;\n const comments = sourceCode.getCommentsBefore(next);\n if (\n sourceCode\n .lines\n .slice(lastToken.loc.end.line, firstToken.loc.start.line - 1)\n .some((line, index) => !line.trim() && !comments.some((comment) =>\n comment.loc!.start.line <= lastToken.loc.end.line + index + 1\n && comment.loc!.end.line >= lastToken.loc.end.line + index + 1))\n ) continue;\n\n // Keep leading comments attached to the next statement and trailing comments in place.\n const boundary = comments\n .find((comment) => comment.loc!.start.line > lastToken.loc.end.line) ?? firstToken;\n\n const offset = boundary.loc!.start.line > lastToken.loc.end.line\n ? boundary.range![0] - boundary.loc!.start.column\n : boundary.range![0];\n\n context.report({\n fix: (fixer) => fixer.insertTextBeforeRange(\n [\n offset,\n offset,\n ],\n boundary.loc!.start.line === lastToken.loc.end.line ? '\\n\\n' : '\\n',\n ),\n messageId: 'blankLine',\n node: next,\n });\n }\n }\n\n return {\n BlockStatement: (node) => checkStatements(node.body),\n Program: (node) => checkStatements(node.body),\n StaticBlock: (node) => checkStatements(node.body),\n SwitchCase: (node) => checkStatements(node.consequent),\n };\n },\n meta: {\n docs: { description: 'Separate statements after closing lines, blocks, or indentation changes.' },\n fixable: 'whitespace',\n messages: { blankLine: 'Add a blank line between these complete statements.' },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":";AAIA,MAAa,mBAAoC;CAC7C,OAAO,SAAS;EACZ,MAAM,EAAE,eAAe;EAEvB,SAAS,gBAAgB,YAA4C;GACjE,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;IACpD,MAAM,WAAW,WAAW,QAAQ;IACpC,MAAM,OAAO,WAAW;IACxB,MAAM,YAAY,WAAW,aAAa,QAAQ;IAClD,MAAM,aAAa,WAAW,cAAc,IAAI;IAChD,MAAM,cAAc,WAAW,MAAM,UAAU,IAAI,IAAI,OAAO;IAC9D,MAAM,cAAc,WAAW,MAAM,WAAW,IAAI,MAAM,OAAO;IACjE,MAAM,qBAAqB,OAAO,KAAK,WAAW,CAAC,CAAE,OAAO,OAAO,KAAK,WAAW,CAAC,CAAE;IACtF,MAAM,uBAAuB,cAAc,KAAK,YAAY,MAAM,GAAG,UAAU,IAAI,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC;IACrG,MAAM,YAAY,SAAS,SAAS,8BAC/B,SAAS,SAAS,2BACjB,SAAS,cACT;IAEN,MAAM,kBAAkB,UAAU,UAAU,OAAO,aAAa;KAC5D;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACJ,CAAC,CAAC,SAAS,UAAU,IAAI;IAEzB,IAAI,CAAC,sBAAsB,CAAC,wBAAwB,CAAC,iBAAiB;IACtE,MAAM,WAAW,WAAW,kBAAkB,IAAI;IAClD,IACI,WACK,MACA,MAAM,UAAU,IAAI,IAAI,MAAM,WAAW,IAAI,MAAM,OAAO,CAAC,CAAC,CAC5D,MAAM,MAAM,UAAU,CAAC,KAAK,KAAK,KAAK,CAAC,SAAS,MAAM,YACnD,QAAQ,IAAK,MAAM,QAAQ,UAAU,IAAI,IAAI,OAAO,QAAQ,KACzD,QAAQ,IAAK,IAAI,QAAQ,UAAU,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC,GACzE;IAGF,MAAM,WAAW,SACZ,MAAM,YAAY,QAAQ,IAAK,MAAM,OAAO,UAAU,IAAI,IAAI,IAAI,KAAK;IAE5E,MAAM,SAAS,SAAS,IAAK,MAAM,OAAO,UAAU,IAAI,IAAI,OACtD,SAAS,MAAO,KAAK,SAAS,IAAK,MAAM,SACzC,SAAS,MAAO;IAEtB,QAAQ,OAAO;KACX,MAAM,UAAU,MAAM,sBAClB,CACI,QACA,MACJ,GACA,SAAS,IAAK,MAAM,SAAS,UAAU,IAAI,IAAI,OAAO,SAAS,IACnE;KACA,WAAW;KACX,MAAM;IACV,CAAC;GACL;EACJ;EAEA,OAAO;GACH,iBAAiB,SAAS,gBAAgB,KAAK,IAAI;GACnD,UAAU,SAAS,gBAAgB,KAAK,IAAI;GAC5C,cAAc,SAAS,gBAAgB,KAAK,IAAI;GAChD,aAAa,SAAS,gBAAgB,KAAK,UAAU;EACzD;CACJ;CACA,MAAM;EACF,MAAM,EAAE,aAAa,2EAA2E;EAChG,SAAS;EACT,UAAU,EAAE,WAAW,sDAAsD;EAC7E,QAAQ,CAAC;EACT,MAAM;CACV;AACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/internals/utils.ts"],"mappings":";YAKY,aAAa,KACrB;wBAaY,gCACZ,YAAY,YACZ,gBAAgB,YAAY,YAAY,wBAAwB,KAAK,eACtE,KAAK"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/internals/utils.ts"],"sourcesContent":["import type {\n Rule,\n SourceCode,\n} from 'eslint';\n\nexport type TokenStore = Pick<\n SourceCode,\n 'commentsExistBetween' | 'getLastToken' | 'getTokenAfter' | 'getTokenBefore' | 'getTokensBetween'\n>;\n\ninterface TemplateParserServices {\n defineTemplateBodyVisitor?: (\n templateVisitor: Rule.RuleListener,\n scriptVisitor: Rule.RuleListener,\n ) => Rule.RuleListener;\n\n getTemplateBodyTokenStore?: () => TokenStore;\n}\n\nexport function defineScriptAndTemplateVisitors(\n sourceCode: SourceCode,\n createVisitor: (tokenStore: TokenStore, isTemplate: boolean) => Rule.RuleListener,\n): Rule.RuleListener {\n const scriptVisitor = createVisitor(sourceCode, false);\n const parserServices = sourceCode.parserServices as TemplateParserServices;\n if (!parserServices.defineTemplateBodyVisitor || !parserServices.getTemplateBodyTokenStore) return scriptVisitor;\n\n return parserServices.defineTemplateBodyVisitor(\n createVisitor(parserServices.getTemplateBodyTokenStore(), true),\n scriptVisitor,\n );\n}\n"],"mappings":";AAmBA,SAAgB,gCACZ,YACA,eACiB;CACjB,MAAM,gBAAgB,cAAc,YAAY,KAAK;CACrD,MAAM,iBAAiB,WAAW;CAClC,IAAI,CAAC,eAAe,6BAA6B,CAAC,eAAe,2BAA2B,OAAO;CAEnG,OAAO,eAAe,0BAClB,cAAc,eAAe,0BAA0B,GAAG,IAAI,GAC9D,aACJ;AACJ"}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import type { Rule } from 'eslint';
|
|
2
|
-
|
|
3
|
-
import type { TokenStore } from '../utils';
|
|
4
|
-
import { defineScriptAndTemplateVisitors } from '../utils';
|
|
5
|
-
|
|
6
|
-
type CallNode = Extract<Rule.Node, { type: 'CallExpression' | 'NewExpression' }> & { typeArguments?: Rule.Node };
|
|
7
|
-
type FunctionNode = Extract<
|
|
8
|
-
Rule.Node,
|
|
9
|
-
{ type: 'ArrowFunctionExpression' | 'FunctionDeclaration' | 'FunctionExpression' }
|
|
10
|
-
>;
|
|
11
|
-
|
|
12
|
-
type ListItem = CallNode['arguments'][number] | FunctionNode['params'][number];
|
|
13
|
-
|
|
14
|
-
export const consistentParameterLayout: Rule.RuleModule = {
|
|
15
|
-
create(context) {
|
|
16
|
-
const isTestFile = /\.test\.[jt]sx?$/.test(context.filename);
|
|
17
|
-
|
|
18
|
-
function checkParameterLayout(
|
|
19
|
-
node: Rule.Node,
|
|
20
|
-
items: readonly ListItem[],
|
|
21
|
-
tokenStore: TokenStore,
|
|
22
|
-
isTemplate: boolean,
|
|
23
|
-
): void {
|
|
24
|
-
const first = items[0];
|
|
25
|
-
if (!first) return;
|
|
26
|
-
const isSingleParameter = items.length === 1;
|
|
27
|
-
|
|
28
|
-
// JSX argument layout belongs to the JSX formatting rules.
|
|
29
|
-
const firstType: string = first.type;
|
|
30
|
-
if (isSingleParameter && (firstType === 'JSXElement' || firstType === 'JSXFragment')) return;
|
|
31
|
-
let openingParen;
|
|
32
|
-
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
|
33
|
-
const call = node as CallNode;
|
|
34
|
-
openingParen = tokenStore.getTokenAfter(
|
|
35
|
-
call.typeArguments ?? call.callee,
|
|
36
|
-
(token) => token.type === 'Punctuator' && token.value === '(',
|
|
37
|
-
);
|
|
38
|
-
} else {
|
|
39
|
-
openingParen = tokenStore.getTokenBefore(first);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!openingParen || openingParen.value !== '(') return;
|
|
43
|
-
// An unparenthesized arrow must not borrow its parent's delimiters.
|
|
44
|
-
if (openingParen.range[0] < node.range![0]) return;
|
|
45
|
-
const closingParen = node.type === 'CallExpression' || node.type === 'NewExpression'
|
|
46
|
-
? tokenStore.getLastToken(node)
|
|
47
|
-
: tokenStore.getTokenAfter(items.at(-1)!, (token) => token.value === ')');
|
|
48
|
-
|
|
49
|
-
const next = tokenStore.getTokenAfter(openingParen)!;
|
|
50
|
-
|
|
51
|
-
if (isSingleParameter) {
|
|
52
|
-
if (!closingParen || closingParen.value !== ')') return;
|
|
53
|
-
let previous = tokenStore.getTokenBefore(closingParen)!;
|
|
54
|
-
if (previous.value === ',') previous = tokenStore.getTokenBefore(previous)!;
|
|
55
|
-
if (
|
|
56
|
-
tokenStore.commentsExistBetween(openingParen, next)
|
|
57
|
-
|| tokenStore.commentsExistBetween(previous, closingParen)
|
|
58
|
-
) return;
|
|
59
|
-
|
|
60
|
-
const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;
|
|
61
|
-
const hasClosingNewline = tokenStore.getTokenBefore(closingParen)!.loc.end.line
|
|
62
|
-
!== closingParen.loc.start.line;
|
|
63
|
-
|
|
64
|
-
if (hasOpeningNewline === hasClosingNewline) return;
|
|
65
|
-
|
|
66
|
-
context.report({
|
|
67
|
-
fix: (fixer) => hasOpeningNewline
|
|
68
|
-
? fixer.insertTextBefore(closingParen, '\n')
|
|
69
|
-
: fixer.insertTextAfter(openingParen, '\n'),
|
|
70
|
-
messageId: 'singleBoundary',
|
|
71
|
-
node,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;
|
|
78
|
-
|
|
79
|
-
if (isTemplate) {
|
|
80
|
-
// Script list formatters do not traverse Vue template expressions.
|
|
81
|
-
const newlineOffsets: number[] = [];
|
|
82
|
-
if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);
|
|
83
|
-
for (let index = 1; index < items.length; index++) {
|
|
84
|
-
const item = items[index]!;
|
|
85
|
-
const comma = tokenStore.getTokensBetween(items[index - 1]!, item)
|
|
86
|
-
.find((token) => token.value === ',');
|
|
87
|
-
|
|
88
|
-
if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma)!.loc.start.line) {
|
|
89
|
-
newlineOffsets.push(comma.range[1]);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
closingParen.value === ')'
|
|
95
|
-
&& tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line
|
|
96
|
-
) newlineOffsets.push(closingParen.range[0]);
|
|
97
|
-
|
|
98
|
-
if (newlineOffsets.length) {
|
|
99
|
-
context.report({
|
|
100
|
-
fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextAfterRange(
|
|
101
|
-
[
|
|
102
|
-
offset,
|
|
103
|
-
offset,
|
|
104
|
-
],
|
|
105
|
-
'\n',
|
|
106
|
-
)),
|
|
107
|
-
messageId: 'newline',
|
|
108
|
-
node: first,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (openingParen.loc.end.line !== next.loc.start.line) return;
|
|
116
|
-
|
|
117
|
-
context.report({
|
|
118
|
-
fix: (fixer) => fixer.insertTextAfter(openingParen, '\n'),
|
|
119
|
-
messageId: 'newline',
|
|
120
|
-
node: first,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function createVisitor(tokenStore: TokenStore, isTemplate: boolean): Rule.RuleListener {
|
|
125
|
-
return {
|
|
126
|
-
ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
127
|
-
CallExpression: (node) => {
|
|
128
|
-
const { callee } = node;
|
|
129
|
-
if (isTestFile) {
|
|
130
|
-
const target = callee.type === 'MemberExpression'
|
|
131
|
-
&& !callee.computed
|
|
132
|
-
&& callee.property.type === 'Identifier'
|
|
133
|
-
&& callee.property.name === 'concurrent'
|
|
134
|
-
? callee.object
|
|
135
|
-
: callee;
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
target.type === 'Identifier'
|
|
139
|
-
&& (target.name === 'describe' || target.name === 'it')
|
|
140
|
-
) return;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
checkParameterLayout(node, node.arguments, tokenStore, isTemplate);
|
|
144
|
-
},
|
|
145
|
-
FunctionDeclaration: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
146
|
-
FunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
|
|
147
|
-
NewExpression: (node) => checkParameterLayout(node, node.arguments, tokenStore, isTemplate),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);
|
|
152
|
-
},
|
|
153
|
-
meta: {
|
|
154
|
-
docs: { description: 'Preserve consistent single-parameter boundaries and expand multiline parameter lists.' },
|
|
155
|
-
fixable: 'whitespace',
|
|
156
|
-
messages: {
|
|
157
|
-
newline: 'Start a multiline parameter list on a new line.',
|
|
158
|
-
singleBoundary: 'Use matching newline boundaries around a single parameter.',
|
|
159
|
-
},
|
|
160
|
-
schema: [],
|
|
161
|
-
type: 'layout',
|
|
162
|
-
},
|
|
163
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|