@croct/eslint-plugin 0.1.3 → 0.2.2
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 +1 -1
- package/configs/index.d.ts +16 -7
- package/configs/javascript.d.ts +12 -4
- package/configs/javascript.js +13 -5
- package/configs/typescript.d.ts +4 -3
- package/configs/typescript.js +7 -2
- package/index.d.ts +27 -7
- package/package.json +1 -1
- package/rules/argument-spacing/index.js +4 -2
- package/rules/index.d.ts +11 -0
- package/rules/index.js +4 -0
- package/rules/min-chained-call-depth/index.d.ts +6 -0
- package/rules/min-chained-call-depth/index.js +105 -0
- package/rules/newline-per-chained-call/index.d.ts +7 -0
- package/rules/newline-per-chained-call/index.js +122 -0
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
|
-
The recommended way to install the
|
|
28
|
+
The recommended way to install the package is via [NPM](https://npmjs.com). It pairs nicely with module bundlers such as
|
|
29
29
|
Webpack or Browserify:
|
|
30
30
|
|
|
31
31
|
```sh
|
package/configs/index.d.ts
CHANGED
|
@@ -95,7 +95,6 @@ export declare const configs: {
|
|
|
95
95
|
allowNumber: boolean;
|
|
96
96
|
allowNullableObject: boolean;
|
|
97
97
|
})[];
|
|
98
|
-
'@typescript-eslint/prefer-regexp-exec': string;
|
|
99
98
|
'@typescript-eslint/prefer-optional-chain': string;
|
|
100
99
|
'no-shadow': string;
|
|
101
100
|
'@typescript-eslint/no-shadow': (string | {
|
|
@@ -114,7 +113,10 @@ export declare const configs: {
|
|
|
114
113
|
indent: (string | number | {
|
|
115
114
|
SwitchCase: number;
|
|
116
115
|
})[];
|
|
117
|
-
'@typescript-eslint/no-unused-vars': string
|
|
116
|
+
'@typescript-eslint/no-unused-vars': (string | {
|
|
117
|
+
args: string;
|
|
118
|
+
ignoreRestSiblings: boolean;
|
|
119
|
+
})[];
|
|
118
120
|
'no-unused-vars': string;
|
|
119
121
|
'@typescript-eslint/no-non-null-assertion': string;
|
|
120
122
|
'object-curly-spacing': string;
|
|
@@ -156,7 +158,6 @@ export declare const configs: {
|
|
|
156
158
|
'@typescript-eslint/type-annotation-spacing'?: undefined;
|
|
157
159
|
'@typescript-eslint/semi'?: undefined;
|
|
158
160
|
'@typescript-eslint/strict-boolean-expressions'?: undefined;
|
|
159
|
-
'@typescript-eslint/prefer-regexp-exec'?: undefined;
|
|
160
161
|
'@typescript-eslint/prefer-optional-chain'?: undefined;
|
|
161
162
|
'no-shadow'?: undefined;
|
|
162
163
|
'@typescript-eslint/no-shadow'?: undefined;
|
|
@@ -190,6 +191,10 @@ export declare const configs: {
|
|
|
190
191
|
rules: {
|
|
191
192
|
'@croct/argument-spacing': string;
|
|
192
193
|
'@croct/complex-expression-spacing': string;
|
|
194
|
+
'@croct/newline-per-chained-call': string;
|
|
195
|
+
'@croct/min-chained-call-depth': string;
|
|
196
|
+
'newline-per-chained-call': string;
|
|
197
|
+
'no-plusplus': string;
|
|
193
198
|
'array-bracket-newline': string[];
|
|
194
199
|
'multiline-ternary': string[];
|
|
195
200
|
'no-undef-init': string;
|
|
@@ -237,6 +242,10 @@ export declare const configs: {
|
|
|
237
242
|
'max-len': (string | {
|
|
238
243
|
code: number;
|
|
239
244
|
ignoreStrings: boolean;
|
|
245
|
+
ignoreComments: boolean;
|
|
246
|
+
ignoreTemplateLiterals: boolean;
|
|
247
|
+
ignoreTrailingComments: boolean;
|
|
248
|
+
ignoreUrls: boolean;
|
|
240
249
|
})[];
|
|
241
250
|
'no-await-in-loop': string;
|
|
242
251
|
'no-bitwise': string;
|
|
@@ -246,11 +255,11 @@ export declare const configs: {
|
|
|
246
255
|
maxEOF: number;
|
|
247
256
|
maxBOF: number;
|
|
248
257
|
})[];
|
|
249
|
-
'no-plusplus': (string | {
|
|
250
|
-
allowForLoopAfterthoughts: boolean;
|
|
251
|
-
})[];
|
|
252
258
|
'no-unused-expressions': string;
|
|
253
|
-
'no-unused-vars': string
|
|
259
|
+
'no-unused-vars': (string | {
|
|
260
|
+
args: string;
|
|
261
|
+
ignoreRestSiblings: boolean;
|
|
262
|
+
})[];
|
|
254
263
|
'no-restricted-syntax': string[];
|
|
255
264
|
'object-curly-newline': (string | {
|
|
256
265
|
multiline: boolean;
|
package/configs/javascript.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export declare const javascript: {
|
|
|
4
4
|
rules: {
|
|
5
5
|
'@croct/argument-spacing': string;
|
|
6
6
|
'@croct/complex-expression-spacing': string;
|
|
7
|
+
'@croct/newline-per-chained-call': string;
|
|
8
|
+
'@croct/min-chained-call-depth': string;
|
|
9
|
+
'newline-per-chained-call': string;
|
|
10
|
+
'no-plusplus': string;
|
|
7
11
|
'array-bracket-newline': string[];
|
|
8
12
|
'multiline-ternary': string[];
|
|
9
13
|
'no-undef-init': string;
|
|
@@ -51,6 +55,10 @@ export declare const javascript: {
|
|
|
51
55
|
'max-len': (string | {
|
|
52
56
|
code: number;
|
|
53
57
|
ignoreStrings: boolean;
|
|
58
|
+
ignoreComments: boolean;
|
|
59
|
+
ignoreTemplateLiterals: boolean;
|
|
60
|
+
ignoreTrailingComments: boolean;
|
|
61
|
+
ignoreUrls: boolean;
|
|
54
62
|
})[];
|
|
55
63
|
'no-await-in-loop': string;
|
|
56
64
|
'no-bitwise': string;
|
|
@@ -60,11 +68,11 @@ export declare const javascript: {
|
|
|
60
68
|
maxEOF: number;
|
|
61
69
|
maxBOF: number;
|
|
62
70
|
})[];
|
|
63
|
-
'no-plusplus': (string | {
|
|
64
|
-
allowForLoopAfterthoughts: boolean;
|
|
65
|
-
})[];
|
|
66
71
|
'no-unused-expressions': string;
|
|
67
|
-
'no-unused-vars': string
|
|
72
|
+
'no-unused-vars': (string | {
|
|
73
|
+
args: string;
|
|
74
|
+
ignoreRestSiblings: boolean;
|
|
75
|
+
})[];
|
|
68
76
|
'no-restricted-syntax': string[];
|
|
69
77
|
'object-curly-newline': (string | {
|
|
70
78
|
multiline: boolean;
|
package/configs/javascript.js
CHANGED
|
@@ -16,6 +16,10 @@ exports.javascript = {
|
|
|
16
16
|
rules: {
|
|
17
17
|
'@croct/argument-spacing': 'error',
|
|
18
18
|
'@croct/complex-expression-spacing': 'error',
|
|
19
|
+
'@croct/newline-per-chained-call': 'error',
|
|
20
|
+
'@croct/min-chained-call-depth': 'error',
|
|
21
|
+
'newline-per-chained-call': 'off',
|
|
22
|
+
'no-plusplus': 'off',
|
|
19
23
|
'array-bracket-newline': [
|
|
20
24
|
'error',
|
|
21
25
|
'consistent',
|
|
@@ -99,7 +103,11 @@ exports.javascript = {
|
|
|
99
103
|
'error',
|
|
100
104
|
{
|
|
101
105
|
code: 100,
|
|
102
|
-
ignoreStrings:
|
|
106
|
+
ignoreStrings: false,
|
|
107
|
+
ignoreComments: false,
|
|
108
|
+
ignoreTemplateLiterals: false,
|
|
109
|
+
ignoreTrailingComments: false,
|
|
110
|
+
ignoreUrls: false,
|
|
103
111
|
},
|
|
104
112
|
],
|
|
105
113
|
'no-await-in-loop': 'off',
|
|
@@ -113,14 +121,14 @@ exports.javascript = {
|
|
|
113
121
|
maxBOF: 0,
|
|
114
122
|
},
|
|
115
123
|
],
|
|
116
|
-
'no-
|
|
124
|
+
'no-unused-expressions': 'error',
|
|
125
|
+
'no-unused-vars': [
|
|
117
126
|
'error',
|
|
118
127
|
{
|
|
119
|
-
|
|
128
|
+
args: 'after-used',
|
|
129
|
+
ignoreRestSiblings: true,
|
|
120
130
|
},
|
|
121
131
|
],
|
|
122
|
-
'no-unused-expressions': 'error',
|
|
123
|
-
'no-unused-vars': 'error',
|
|
124
132
|
'no-restricted-syntax': [
|
|
125
133
|
'error',
|
|
126
134
|
'ForInStatement',
|
package/configs/typescript.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ export declare const typescript: {
|
|
|
18
18
|
allowNumber: boolean;
|
|
19
19
|
allowNullableObject: boolean;
|
|
20
20
|
})[];
|
|
21
|
-
'@typescript-eslint/prefer-regexp-exec': string;
|
|
22
21
|
'@typescript-eslint/prefer-optional-chain': string;
|
|
23
22
|
'no-shadow': string;
|
|
24
23
|
'@typescript-eslint/no-shadow': (string | {
|
|
@@ -37,7 +36,10 @@ export declare const typescript: {
|
|
|
37
36
|
indent: (string | number | {
|
|
38
37
|
SwitchCase: number;
|
|
39
38
|
})[];
|
|
40
|
-
'@typescript-eslint/no-unused-vars': string
|
|
39
|
+
'@typescript-eslint/no-unused-vars': (string | {
|
|
40
|
+
args: string;
|
|
41
|
+
ignoreRestSiblings: boolean;
|
|
42
|
+
})[];
|
|
41
43
|
'no-unused-vars': string;
|
|
42
44
|
'@typescript-eslint/no-non-null-assertion': string;
|
|
43
45
|
'object-curly-spacing': string;
|
|
@@ -79,7 +81,6 @@ export declare const typescript: {
|
|
|
79
81
|
'@typescript-eslint/type-annotation-spacing'?: undefined;
|
|
80
82
|
'@typescript-eslint/semi'?: undefined;
|
|
81
83
|
'@typescript-eslint/strict-boolean-expressions'?: undefined;
|
|
82
|
-
'@typescript-eslint/prefer-regexp-exec'?: undefined;
|
|
83
84
|
'@typescript-eslint/prefer-optional-chain'?: undefined;
|
|
84
85
|
'no-shadow'?: undefined;
|
|
85
86
|
'@typescript-eslint/no-shadow'?: undefined;
|
package/configs/typescript.js
CHANGED
|
@@ -25,7 +25,6 @@ exports.typescript = {
|
|
|
25
25
|
allowNumber: false,
|
|
26
26
|
allowNullableObject: false,
|
|
27
27
|
}],
|
|
28
|
-
'@typescript-eslint/prefer-regexp-exec': 'error',
|
|
29
28
|
'@typescript-eslint/prefer-optional-chain': 'error',
|
|
30
29
|
'no-shadow': 'off',
|
|
31
30
|
'@typescript-eslint/no-shadow': ['error', {
|
|
@@ -46,7 +45,13 @@ exports.typescript = {
|
|
|
46
45
|
indent: ['error', 4, {
|
|
47
46
|
SwitchCase: 1,
|
|
48
47
|
}],
|
|
49
|
-
'@typescript-eslint/no-unused-vars':
|
|
48
|
+
'@typescript-eslint/no-unused-vars': [
|
|
49
|
+
'error',
|
|
50
|
+
{
|
|
51
|
+
args: 'after-used',
|
|
52
|
+
ignoreRestSiblings: true,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
50
55
|
'no-unused-vars': 'off',
|
|
51
56
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
52
57
|
'object-curly-spacing': 'off',
|
package/index.d.ts
CHANGED
|
@@ -11,6 +11,17 @@ declare const configuration: {
|
|
|
11
11
|
ArrowFunctionExpression: (node: import("@typescript-eslint/types/dist/ast-spec").ArrowFunctionExpression) => void;
|
|
12
12
|
IfStatement: (node: import("@typescript-eslint/types/dist/ast-spec").IfStatement) => void;
|
|
13
13
|
}>;
|
|
14
|
+
'newline-per-chained-call': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"expectedLineBreak", {
|
|
15
|
+
ignoreChainWithDepth: number;
|
|
16
|
+
}[], {
|
|
17
|
+
CallExpression: (node: import("@typescript-eslint/types/dist/ast-spec").CallExpression) => void;
|
|
18
|
+
MemberExpression: (node: import("@typescript-eslint/types/dist/ast-spec").MemberExpression) => void;
|
|
19
|
+
}>;
|
|
20
|
+
'min-chained-call-depth': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"unexpectedLineBreak", {
|
|
21
|
+
maxLineLength: number;
|
|
22
|
+
}[], {
|
|
23
|
+
CallExpression: (node: import("@typescript-eslint/types/dist/ast-spec").CallExpression) => void;
|
|
24
|
+
}>;
|
|
14
25
|
};
|
|
15
26
|
configs: {
|
|
16
27
|
cypress: {
|
|
@@ -109,7 +120,6 @@ declare const configuration: {
|
|
|
109
120
|
allowNumber: boolean;
|
|
110
121
|
allowNullableObject: boolean;
|
|
111
122
|
})[];
|
|
112
|
-
'@typescript-eslint/prefer-regexp-exec': string;
|
|
113
123
|
'@typescript-eslint/prefer-optional-chain': string;
|
|
114
124
|
'no-shadow': string;
|
|
115
125
|
'@typescript-eslint/no-shadow': (string | {
|
|
@@ -128,7 +138,10 @@ declare const configuration: {
|
|
|
128
138
|
indent: (string | number | {
|
|
129
139
|
SwitchCase: number;
|
|
130
140
|
})[];
|
|
131
|
-
'@typescript-eslint/no-unused-vars': string
|
|
141
|
+
'@typescript-eslint/no-unused-vars': (string | {
|
|
142
|
+
args: string;
|
|
143
|
+
ignoreRestSiblings: boolean;
|
|
144
|
+
})[];
|
|
132
145
|
'no-unused-vars': string;
|
|
133
146
|
'@typescript-eslint/no-non-null-assertion': string;
|
|
134
147
|
'object-curly-spacing': string;
|
|
@@ -170,7 +183,6 @@ declare const configuration: {
|
|
|
170
183
|
'@typescript-eslint/type-annotation-spacing'?: undefined;
|
|
171
184
|
'@typescript-eslint/semi'?: undefined;
|
|
172
185
|
'@typescript-eslint/strict-boolean-expressions'?: undefined;
|
|
173
|
-
'@typescript-eslint/prefer-regexp-exec'?: undefined;
|
|
174
186
|
'@typescript-eslint/prefer-optional-chain'?: undefined;
|
|
175
187
|
'no-shadow'?: undefined;
|
|
176
188
|
'@typescript-eslint/no-shadow'?: undefined;
|
|
@@ -204,6 +216,10 @@ declare const configuration: {
|
|
|
204
216
|
rules: {
|
|
205
217
|
'@croct/argument-spacing': string;
|
|
206
218
|
'@croct/complex-expression-spacing': string;
|
|
219
|
+
'@croct/newline-per-chained-call': string;
|
|
220
|
+
'@croct/min-chained-call-depth': string;
|
|
221
|
+
'newline-per-chained-call': string;
|
|
222
|
+
'no-plusplus': string;
|
|
207
223
|
'array-bracket-newline': string[];
|
|
208
224
|
'multiline-ternary': string[];
|
|
209
225
|
'no-undef-init': string;
|
|
@@ -251,6 +267,10 @@ declare const configuration: {
|
|
|
251
267
|
'max-len': (string | {
|
|
252
268
|
code: number;
|
|
253
269
|
ignoreStrings: boolean;
|
|
270
|
+
ignoreComments: boolean;
|
|
271
|
+
ignoreTemplateLiterals: boolean;
|
|
272
|
+
ignoreTrailingComments: boolean;
|
|
273
|
+
ignoreUrls: boolean;
|
|
254
274
|
})[];
|
|
255
275
|
'no-await-in-loop': string;
|
|
256
276
|
'no-bitwise': string;
|
|
@@ -260,11 +280,11 @@ declare const configuration: {
|
|
|
260
280
|
maxEOF: number;
|
|
261
281
|
maxBOF: number;
|
|
262
282
|
})[];
|
|
263
|
-
'no-plusplus': (string | {
|
|
264
|
-
allowForLoopAfterthoughts: boolean;
|
|
265
|
-
})[];
|
|
266
283
|
'no-unused-expressions': string;
|
|
267
|
-
'no-unused-vars': string
|
|
284
|
+
'no-unused-vars': (string | {
|
|
285
|
+
args: string;
|
|
286
|
+
ignoreRestSiblings: boolean;
|
|
287
|
+
})[];
|
|
268
288
|
'no-restricted-syntax': string[];
|
|
269
289
|
'object-curly-newline': (string | {
|
|
270
290
|
multiline: boolean;
|
package/package.json
CHANGED
|
@@ -7,7 +7,8 @@ exports.argumentSpacing = (0, createRule_1.createRule)({
|
|
|
7
7
|
meta: {
|
|
8
8
|
type: 'suggestion',
|
|
9
9
|
docs: {
|
|
10
|
-
description: 'Enforces a surrounding line break before and after
|
|
10
|
+
description: 'Enforces a surrounding line break before and after '
|
|
11
|
+
+ 'the argument list in multiline functional calls.',
|
|
11
12
|
recommended: 'error',
|
|
12
13
|
},
|
|
13
14
|
fixable: 'whitespace',
|
|
@@ -34,7 +35,8 @@ exports.argumentSpacing = (0, createRule_1.createRule)({
|
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
36
37
|
const lastArgumentFirstToken = sourceCode.getFirstToken(lastArgument);
|
|
37
|
-
if ((lastArgument.type !== 'ArrowFunctionExpression'
|
|
38
|
+
if ((lastArgument.type !== 'ArrowFunctionExpression'
|
|
39
|
+
|| lastArgument.body.type === 'BlockStatement')
|
|
38
40
|
&& firstToken.loc.start.line === lastArgumentFirstToken.loc.start.line) {
|
|
39
41
|
return;
|
|
40
42
|
}
|
package/rules/index.d.ts
CHANGED
|
@@ -10,4 +10,15 @@ export declare const rules: {
|
|
|
10
10
|
ArrowFunctionExpression: (node: import("@typescript-eslint/types/dist/ast-spec").ArrowFunctionExpression) => void;
|
|
11
11
|
IfStatement: (node: import("@typescript-eslint/types/dist/ast-spec").IfStatement) => void;
|
|
12
12
|
}>;
|
|
13
|
+
'newline-per-chained-call': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"expectedLineBreak", {
|
|
14
|
+
ignoreChainWithDepth: number;
|
|
15
|
+
}[], {
|
|
16
|
+
CallExpression: (node: import("@typescript-eslint/types/dist/ast-spec").CallExpression) => void;
|
|
17
|
+
MemberExpression: (node: import("@typescript-eslint/types/dist/ast-spec").MemberExpression) => void;
|
|
18
|
+
}>;
|
|
19
|
+
'min-chained-call-depth': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"unexpectedLineBreak", {
|
|
20
|
+
maxLineLength: number;
|
|
21
|
+
}[], {
|
|
22
|
+
CallExpression: (node: import("@typescript-eslint/types/dist/ast-spec").CallExpression) => void;
|
|
23
|
+
}>;
|
|
13
24
|
};
|
package/rules/index.js
CHANGED
|
@@ -4,8 +4,12 @@ exports.rules = void 0;
|
|
|
4
4
|
const argument_spacing_1 = require("./argument-spacing");
|
|
5
5
|
const jsx_attribute_spacing_1 = require("./jsx-attribute-spacing");
|
|
6
6
|
const complex_expression_spacing_1 = require("./complex-expression-spacing");
|
|
7
|
+
const newline_per_chained_call_1 = require("./newline-per-chained-call");
|
|
8
|
+
const min_chained_call_depth_1 = require("./min-chained-call-depth");
|
|
7
9
|
exports.rules = {
|
|
8
10
|
'argument-spacing': argument_spacing_1.argumentSpacing,
|
|
9
11
|
'jsx-attribute-spacing': jsx_attribute_spacing_1.jsxAttributeSpacing,
|
|
10
12
|
'complex-expression-spacing': complex_expression_spacing_1.complexExpressionSpacing,
|
|
13
|
+
'newline-per-chained-call': newline_per_chained_call_1.newlinePerChainedCall,
|
|
14
|
+
'min-chained-call-depth': min_chained_call_depth_1.minChainedCallDepth,
|
|
11
15
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TSESTree } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
export declare const minChainedCallDepth: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"unexpectedLineBreak", {
|
|
3
|
+
maxLineLength: number;
|
|
4
|
+
}[], {
|
|
5
|
+
CallExpression: (node: TSESTree.CallExpression) => void;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.minChainedCallDepth = void 0;
|
|
4
|
+
const ast_utils_1 = require("@typescript-eslint/utils/dist/ast-utils");
|
|
5
|
+
const createRule_1 = require("../createRule");
|
|
6
|
+
exports.minChainedCallDepth = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'min-chained-call-depth',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'layout',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Enforces a minimum depth for multiline chained calls.',
|
|
12
|
+
recommended: 'error',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'whitespace',
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
maxLineLength: {
|
|
20
|
+
type: 'integer',
|
|
21
|
+
minimum: 1,
|
|
22
|
+
default: 100,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
messages: {
|
|
29
|
+
unexpectedLineBreak: 'Unexpected line break.',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [
|
|
33
|
+
{
|
|
34
|
+
maxLineLength: 100,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
create: context => {
|
|
38
|
+
const sourceCode = context.getSourceCode();
|
|
39
|
+
function getDepth(node) {
|
|
40
|
+
let depth = 0;
|
|
41
|
+
let currentNode = node;
|
|
42
|
+
while (currentNode.type === 'CallExpression'
|
|
43
|
+
|| currentNode.type === 'MemberExpression') {
|
|
44
|
+
if (currentNode.type === 'MemberExpression') {
|
|
45
|
+
currentNode = currentNode.object;
|
|
46
|
+
}
|
|
47
|
+
else if (currentNode.type === 'CallExpression') {
|
|
48
|
+
currentNode = currentNode.callee;
|
|
49
|
+
}
|
|
50
|
+
depth += 1;
|
|
51
|
+
}
|
|
52
|
+
return depth;
|
|
53
|
+
}
|
|
54
|
+
function check(node) {
|
|
55
|
+
var _a, _b, _c;
|
|
56
|
+
if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === 'MemberExpression'
|
|
57
|
+
|| ((_b = node.parent) === null || _b === void 0 ? void 0 : _b.type) === 'CallExpression'
|
|
58
|
+
|| node.callee.type !== 'MemberExpression'
|
|
59
|
+
|| node.callee.computed
|
|
60
|
+
|| node.callee.object.loc.end.line === node.callee.property.loc.start.line) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (getDepth(node) > 3) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const { maxLineLength = 100 } = (_c = context.options[0]) !== null && _c !== void 0 ? _c : {};
|
|
67
|
+
const { property } = node.callee;
|
|
68
|
+
const lastToken = sourceCode.getLastToken(node, {
|
|
69
|
+
filter: token => token.loc.end.line === property.loc.start.line,
|
|
70
|
+
});
|
|
71
|
+
const semicolon = sourceCode.getLastToken(node.parent, {
|
|
72
|
+
filter: token => (token.loc.start.line === property.loc.start.line
|
|
73
|
+
&& token.type === 'Punctuator'
|
|
74
|
+
&& token.value === ';'),
|
|
75
|
+
});
|
|
76
|
+
const lineLength = node.callee.object.loc.end.column
|
|
77
|
+
+ lastToken.loc.end.column - property.loc.start.column
|
|
78
|
+
+ 1
|
|
79
|
+
+ (semicolon !== null ? 1 : 0);
|
|
80
|
+
if (maxLineLength !== null && lineLength > maxLineLength) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const punctuator = sourceCode.getTokenBefore(node.callee.property);
|
|
84
|
+
const previousToken = sourceCode.getTokenBefore(punctuator, { includeComments: true });
|
|
85
|
+
const nextToken = sourceCode.getTokenAfter(punctuator, { includeComments: true });
|
|
86
|
+
if ((0, ast_utils_1.isCommentToken)(previousToken) || (0, ast_utils_1.isCommentToken)(nextToken)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
context.report({
|
|
90
|
+
node: node,
|
|
91
|
+
loc: {
|
|
92
|
+
start: node.callee.object.loc.end,
|
|
93
|
+
end: node.callee.property.loc.start,
|
|
94
|
+
},
|
|
95
|
+
messageId: 'unexpectedLineBreak',
|
|
96
|
+
fix: fixer => fixer.replaceTextRange([previousToken.range[1], nextToken.range[0]], punctuator.value),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
CallExpression: (node) => {
|
|
101
|
+
check(node);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TSESTree } from '@typescript-eslint/experimental-utils';
|
|
2
|
+
export declare const newlinePerChainedCall: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"expectedLineBreak", {
|
|
3
|
+
ignoreChainWithDepth: number;
|
|
4
|
+
}[], {
|
|
5
|
+
CallExpression: (node: TSESTree.CallExpression) => void;
|
|
6
|
+
MemberExpression: (node: TSESTree.MemberExpression) => void;
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.newlinePerChainedCall = void 0;
|
|
4
|
+
const createRule_1 = require("../createRule");
|
|
5
|
+
const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/u;
|
|
6
|
+
exports.newlinePerChainedCall = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'newline-per-chained-call',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'layout',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Require a newline after each call in a method chain',
|
|
12
|
+
recommended: 'error',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'whitespace',
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
ignoreChainWithDepth: {
|
|
20
|
+
type: 'integer',
|
|
21
|
+
minimum: 1,
|
|
22
|
+
maximum: 10,
|
|
23
|
+
default: 2,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
messages: {
|
|
30
|
+
expectedLineBreak: 'Expected line break before `{{propertyName}}`.',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultOptions: [
|
|
34
|
+
{
|
|
35
|
+
ignoreChainWithDepth: 2,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
create: context => {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
const options = (_a = context.options[0]) !== null && _a !== void 0 ? _a : {};
|
|
41
|
+
const ignoreChainWithDepth = (_b = options.ignoreChainWithDepth) !== null && _b !== void 0 ? _b : 2;
|
|
42
|
+
const sourceCode = context.getSourceCode();
|
|
43
|
+
function getPropertyText(node) {
|
|
44
|
+
const prefix = '.';
|
|
45
|
+
const lines = sourceCode.getText(node.property)
|
|
46
|
+
.split(LINEBREAK_MATCHER);
|
|
47
|
+
return prefix + lines[0];
|
|
48
|
+
}
|
|
49
|
+
function hasObjectAndPropertyOnSameLine(node) {
|
|
50
|
+
return node.object.loc.end.line === node.property.loc.start.line;
|
|
51
|
+
}
|
|
52
|
+
function isNotClosingParenToken(token) {
|
|
53
|
+
return token.value !== ')' || token.type !== 'Punctuator';
|
|
54
|
+
}
|
|
55
|
+
function validateCallExpressionIgnoreDepth(node) {
|
|
56
|
+
var _a;
|
|
57
|
+
let hasCallExpression = false;
|
|
58
|
+
if (node.type === 'CallExpression') {
|
|
59
|
+
hasCallExpression = true;
|
|
60
|
+
}
|
|
61
|
+
if ((node.parent !== undefined)
|
|
62
|
+
&& node.parent.type !== 'CallExpression'
|
|
63
|
+
&& node.parent.type !== 'MemberExpression') {
|
|
64
|
+
const memberExpressions = [];
|
|
65
|
+
let currentNode = (node.type === 'CallExpression'
|
|
66
|
+
? node.callee
|
|
67
|
+
: node);
|
|
68
|
+
while (currentNode.type === 'CallExpression'
|
|
69
|
+
|| currentNode.type === 'MemberExpression') {
|
|
70
|
+
if (currentNode.type === 'MemberExpression') {
|
|
71
|
+
if (currentNode.property.type === 'Identifier'
|
|
72
|
+
&& !currentNode.computed) {
|
|
73
|
+
memberExpressions.push(currentNode);
|
|
74
|
+
}
|
|
75
|
+
currentNode = currentNode.object;
|
|
76
|
+
}
|
|
77
|
+
else if (currentNode.type === 'CallExpression') {
|
|
78
|
+
currentNode = currentNode.callee;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (memberExpressions.length > ignoreChainWithDepth
|
|
82
|
+
&& hasCallExpression
|
|
83
|
+
&& memberExpressions.some(hasObjectAndPropertyOnSameLine)) {
|
|
84
|
+
const expressionsOnSameLine = memberExpressions
|
|
85
|
+
.filter(hasObjectAndPropertyOnSameLine);
|
|
86
|
+
const rootNode = expressionsOnSameLine[expressionsOnSameLine.length - 1];
|
|
87
|
+
if (rootNode.type === 'MemberExpression'
|
|
88
|
+
&& ((_a = rootNode.parent) === null || _a === void 0 ? void 0 : _a.type) === 'CallExpression'
|
|
89
|
+
&& (rootNode.object.type === 'ThisExpression'
|
|
90
|
+
|| rootNode.object.type === 'Identifier')) {
|
|
91
|
+
expressionsOnSameLine.pop();
|
|
92
|
+
}
|
|
93
|
+
expressionsOnSameLine.forEach(memberExpression => {
|
|
94
|
+
context.report({
|
|
95
|
+
node: memberExpression.property,
|
|
96
|
+
loc: memberExpression.property.loc.start,
|
|
97
|
+
messageId: 'expectedLineBreak',
|
|
98
|
+
data: {
|
|
99
|
+
propertyName: getPropertyText(memberExpression),
|
|
100
|
+
},
|
|
101
|
+
fix: fixer => {
|
|
102
|
+
const firstTokenAfterObject = sourceCode.getTokenAfter(memberExpression.object, isNotClosingParenToken);
|
|
103
|
+
return fixer.insertTextBefore(firstTokenAfterObject, '\n');
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
CallExpression: (node) => {
|
|
112
|
+
var _a;
|
|
113
|
+
if (((_a = node.callee) === null || _a === void 0 ? void 0 : _a.type) === 'MemberExpression') {
|
|
114
|
+
validateCallExpressionIgnoreDepth(node);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
MemberExpression: (node) => {
|
|
118
|
+
validateCallExpressionIgnoreDepth(node);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
});
|