@croct/eslint-plugin 0.8.2 → 0.9.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 +65 -29
- package/index.cjs +380324 -0
- package/index.d.cts +45 -0
- package/package.json +69 -50
- package/configs/cypress.js +0 -29
- package/configs/index.js +0 -12
- package/configs/javascript.js +0 -867
- package/configs/react.js +0 -355
- package/configs/typescript.js +0 -117
- package/index.js +0 -30
- package/rules/argument-spacing/index.js +0 -70
- package/rules/complex-expression-spacing/index.js +0 -66
- package/rules/createRule.js +0 -5
- package/rules/index.js +0 -17
- package/rules/jsx-attribute-spacing/index.js +0 -60
- package/rules/min-chained-call-depth/index.js +0 -158
- package/rules/newline-per-chained-call/index.js +0 -119
- package/rules/parameter-destructuring/index.js +0 -60
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.jsxAttributeSpacing = void 0;
|
|
4
|
-
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
const createRule_1 = require("../createRule");
|
|
6
|
-
exports.jsxAttributeSpacing = (0, createRule_1.createRule)({
|
|
7
|
-
name: 'jsx-attribute-spacing',
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'suggestion',
|
|
10
|
-
docs: {
|
|
11
|
-
description: 'Enforces a surrounding line break in multiline JSX attributes.',
|
|
12
|
-
},
|
|
13
|
-
fixable: 'whitespace',
|
|
14
|
-
schema: [],
|
|
15
|
-
messages: {
|
|
16
|
-
missing: 'Missing new line.',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
defaultOptions: [],
|
|
20
|
-
create: context => {
|
|
21
|
-
const sourceCode = context.getSourceCode();
|
|
22
|
-
function check(node) {
|
|
23
|
-
const { value } = node;
|
|
24
|
-
if (value?.type !== utils_1.TSESTree.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const firstToken = sourceCode.getFirstToken(value.expression);
|
|
28
|
-
const lastToken = sourceCode.getLastToken(value.expression);
|
|
29
|
-
if ((firstToken.type === utils_1.TSESTree.AST_TOKEN_TYPES.Punctuator
|
|
30
|
-
&& lastToken.type === utils_1.TSESTree.AST_TOKEN_TYPES.Punctuator)
|
|
31
|
-
|| (firstToken.loc.start.line === lastToken.loc.end.line)) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const leftBrace = sourceCode.getFirstToken(value);
|
|
35
|
-
const rightBrace = sourceCode.getLastToken(value);
|
|
36
|
-
const tokens = [
|
|
37
|
-
[leftBrace, firstToken],
|
|
38
|
-
[lastToken, rightBrace],
|
|
39
|
-
];
|
|
40
|
-
for (const [previousToken, currentToken] of tokens) {
|
|
41
|
-
if (previousToken.loc.end.line !== currentToken.loc.start.line) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const tokenBefore = sourceCode.getTokenBefore(currentToken, { includeComments: true });
|
|
45
|
-
context.report({
|
|
46
|
-
node: node,
|
|
47
|
-
loc: {
|
|
48
|
-
start: tokenBefore.loc.end,
|
|
49
|
-
end: currentToken.loc.start,
|
|
50
|
-
},
|
|
51
|
-
messageId: 'missing',
|
|
52
|
-
fix: fixer => fixer.replaceTextRange([tokenBefore.range[1], currentToken.range[0]], '\n'),
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
JSXAttribute: check,
|
|
58
|
-
};
|
|
59
|
-
},
|
|
60
|
-
});
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.minChainedCallDepth = void 0;
|
|
4
|
-
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
const ast_utils_1 = require("@typescript-eslint/utils/ast-utils");
|
|
6
|
-
const createRule_1 = require("../createRule");
|
|
7
|
-
exports.minChainedCallDepth = (0, createRule_1.createRule)({
|
|
8
|
-
name: 'min-chained-call-depth',
|
|
9
|
-
meta: {
|
|
10
|
-
type: 'layout',
|
|
11
|
-
docs: {
|
|
12
|
-
description: 'Enforces a minimum depth for multiline chained calls.',
|
|
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
|
-
ignoreChainDeeperThan: {
|
|
25
|
-
type: 'integer',
|
|
26
|
-
minimum: 1,
|
|
27
|
-
maximum: 10,
|
|
28
|
-
default: 2,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
additionalProperties: false,
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
messages: {
|
|
35
|
-
unexpectedLineBreak: 'Unexpected line break.',
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
defaultOptions: [
|
|
39
|
-
{
|
|
40
|
-
maxLineLength: 100,
|
|
41
|
-
ignoreChainDeeperThan: 2,
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
create: context => {
|
|
45
|
-
const sourceCode = context.getSourceCode();
|
|
46
|
-
let maxDepth = 0;
|
|
47
|
-
function getDepth(node) {
|
|
48
|
-
let depth = 0;
|
|
49
|
-
let currentNode = node;
|
|
50
|
-
while (currentNode.type === utils_1.AST_NODE_TYPES.CallExpression
|
|
51
|
-
|| currentNode.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
52
|
-
if (currentNode.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
53
|
-
currentNode = currentNode.object;
|
|
54
|
-
depth += 1;
|
|
55
|
-
}
|
|
56
|
-
else if (currentNode.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
57
|
-
currentNode = currentNode.callee;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return depth;
|
|
61
|
-
}
|
|
62
|
-
function check(node) {
|
|
63
|
-
// If the node is a member expression inside a call/new expression skip,
|
|
64
|
-
// this is to ensure that we consider the correct line length of the result.
|
|
65
|
-
//
|
|
66
|
-
// Example:
|
|
67
|
-
// ```ts
|
|
68
|
-
// foo
|
|
69
|
-
// .bar();
|
|
70
|
-
// ```
|
|
71
|
-
// The replacement of this input should be `foo.bar();`, which has 10 character.
|
|
72
|
-
// Without this check it would consider the length up to `r`, which is 7.
|
|
73
|
-
if (node.type === utils_1.AST_NODE_TYPES.MemberExpression
|
|
74
|
-
&& node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
// If the node is a call/new expression we need to validate it's callee as a member
|
|
78
|
-
// expression.
|
|
79
|
-
// If the node itself is already a member expression, like the
|
|
80
|
-
// `property` in `this.property.function()`, we validate the node directly.
|
|
81
|
-
const callee = node.type === utils_1.AST_NODE_TYPES.CallExpression
|
|
82
|
-
? node.callee
|
|
83
|
-
: node;
|
|
84
|
-
if (
|
|
85
|
-
// If the callee is not a member expression, skip.
|
|
86
|
-
// For example, root level calls like `foo();`.
|
|
87
|
-
callee.type !== utils_1.AST_NODE_TYPES.MemberExpression
|
|
88
|
-
// If the callee is a computed member expression, like `foo[bar]()`, skip.
|
|
89
|
-
|| callee.computed
|
|
90
|
-
|| callee.object.type === utils_1.AST_NODE_TYPES.NewExpression
|
|
91
|
-
// If the callee is already in the same line as it's object, skip.
|
|
92
|
-
|| callee.object.loc.end.line === callee.property.loc.start.line) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const currentDepth = getDepth(callee);
|
|
96
|
-
maxDepth = Math.max(maxDepth, currentDepth);
|
|
97
|
-
// Only affect the root level as the total depth is must be known.
|
|
98
|
-
// If the current call is nested inside another call, skip.
|
|
99
|
-
if (currentDepth > 1) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const { maxLineLength = 100, ignoreChainDeeperThan = 2 } = context.options[0] ?? {};
|
|
103
|
-
// If the max depth is greater than ignore threshold, skip
|
|
104
|
-
//
|
|
105
|
-
// Example:
|
|
106
|
-
// ```ts
|
|
107
|
-
// Array(10)
|
|
108
|
-
// .fill(0)
|
|
109
|
-
// .map(x => x + 1)
|
|
110
|
-
// .slice(0, 5);
|
|
111
|
-
// ```
|
|
112
|
-
// In this case the depth is 3, and the default value of ignoreChainDeeperThan is 2.
|
|
113
|
-
// So the check can be skipped.
|
|
114
|
-
if (maxDepth > ignoreChainDeeperThan) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const { property } = callee;
|
|
118
|
-
const lastToken = sourceCode.getLastToken(node, {
|
|
119
|
-
filter: token => token.loc.end.line === property.loc.start.line,
|
|
120
|
-
});
|
|
121
|
-
const semicolon = sourceCode.getLastToken(node.parent, {
|
|
122
|
-
filter: token => (token.loc.start.line === property.loc.start.line
|
|
123
|
-
&& token.type === utils_1.AST_TOKEN_TYPES.Punctuator
|
|
124
|
-
&& token.value === ';'),
|
|
125
|
-
});
|
|
126
|
-
const lineLength = callee.object.loc.end.column
|
|
127
|
-
+ lastToken.loc.end.column - property.loc.start.column
|
|
128
|
-
+ 1
|
|
129
|
-
+ (semicolon !== null ? 1 : 0);
|
|
130
|
-
if (maxLineLength !== null && lineLength > maxLineLength) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
const punctuator = sourceCode.getTokenBefore(callee.property);
|
|
134
|
-
const previousToken = sourceCode.getTokenBefore(punctuator, { includeComments: true });
|
|
135
|
-
const nextToken = sourceCode.getTokenAfter(punctuator, { includeComments: true });
|
|
136
|
-
if ((0, ast_utils_1.isCommentToken)(previousToken) || (0, ast_utils_1.isCommentToken)(nextToken)) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
context.report({
|
|
140
|
-
node: node,
|
|
141
|
-
loc: {
|
|
142
|
-
start: callee.object.loc.end,
|
|
143
|
-
end: callee.property.loc.start,
|
|
144
|
-
},
|
|
145
|
-
messageId: 'unexpectedLineBreak',
|
|
146
|
-
fix: fixer => fixer.replaceTextRange([previousToken.range[1], nextToken.range[0]], punctuator.value),
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
return {
|
|
150
|
-
CallExpression: (node) => {
|
|
151
|
-
check(node);
|
|
152
|
-
},
|
|
153
|
-
MemberExpression: (node) => {
|
|
154
|
-
check(node);
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
},
|
|
158
|
-
});
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.newlinePerChainedCall = void 0;
|
|
4
|
-
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
const createRule_1 = require("../createRule");
|
|
6
|
-
const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/u;
|
|
7
|
-
exports.newlinePerChainedCall = (0, createRule_1.createRule)({
|
|
8
|
-
name: 'newline-per-chained-call',
|
|
9
|
-
meta: {
|
|
10
|
-
type: 'layout',
|
|
11
|
-
docs: {
|
|
12
|
-
description: 'Require a newline after each call in a method chain',
|
|
13
|
-
},
|
|
14
|
-
fixable: 'whitespace',
|
|
15
|
-
schema: [
|
|
16
|
-
{
|
|
17
|
-
type: 'object',
|
|
18
|
-
properties: {
|
|
19
|
-
ignoreChainDeeperThan: {
|
|
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
|
-
ignoreChainDeeperThan: 2,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
create: context => {
|
|
39
|
-
const options = context.options[0] ?? {};
|
|
40
|
-
const ignoreChainWithDepth = options.ignoreChainDeeperThan ?? 2;
|
|
41
|
-
const sourceCode = context.getSourceCode();
|
|
42
|
-
function getPropertyText(node) {
|
|
43
|
-
const prefix = '.';
|
|
44
|
-
const lines = sourceCode.getText(node.property).split(LINEBREAK_MATCHER);
|
|
45
|
-
return prefix + lines[0];
|
|
46
|
-
}
|
|
47
|
-
function hasObjectAndPropertyOnSameLine(node) {
|
|
48
|
-
return node.object.loc.end.line === node.property.loc.start.line;
|
|
49
|
-
}
|
|
50
|
-
function isNotClosingParenToken(token) {
|
|
51
|
-
return token.value !== ')' || token.type !== utils_1.TSESTree.AST_TOKEN_TYPES.Punctuator;
|
|
52
|
-
}
|
|
53
|
-
function validateCallExpressionIgnoreDepth(node) {
|
|
54
|
-
let hasCallExpression = false;
|
|
55
|
-
if (node.type === utils_1.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
56
|
-
hasCallExpression = true;
|
|
57
|
-
}
|
|
58
|
-
if (node.parent != null
|
|
59
|
-
&& node.parent.type !== utils_1.TSESTree.AST_NODE_TYPES.CallExpression
|
|
60
|
-
&& node.parent.type !== utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
61
|
-
const memberExpressions = [];
|
|
62
|
-
let currentNode = ('callee' in node
|
|
63
|
-
? node.callee
|
|
64
|
-
: node);
|
|
65
|
-
while (currentNode.type === utils_1.TSESTree.AST_NODE_TYPES.CallExpression
|
|
66
|
-
|| currentNode.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
67
|
-
if (currentNode.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
68
|
-
if (currentNode.property.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier
|
|
69
|
-
&& !currentNode.computed) {
|
|
70
|
-
memberExpressions.push(currentNode);
|
|
71
|
-
}
|
|
72
|
-
currentNode = currentNode.object;
|
|
73
|
-
}
|
|
74
|
-
else if (currentNode.type === utils_1.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
75
|
-
currentNode = currentNode.callee;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (memberExpressions.length > ignoreChainWithDepth
|
|
79
|
-
&& hasCallExpression
|
|
80
|
-
&& memberExpressions.some(hasObjectAndPropertyOnSameLine)) {
|
|
81
|
-
const expressionsOnSameLine = memberExpressions
|
|
82
|
-
.filter(hasObjectAndPropertyOnSameLine);
|
|
83
|
-
const rootNode = expressionsOnSameLine[expressionsOnSameLine.length - 1];
|
|
84
|
-
if (rootNode.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression
|
|
85
|
-
&& (rootNode.parent != null && (rootNode.parent.type === utils_1.TSESTree.AST_NODE_TYPES.CallExpression
|
|
86
|
-
|| rootNode.parent.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression))
|
|
87
|
-
&& (rootNode.object.type === utils_1.TSESTree.AST_NODE_TYPES.ThisExpression
|
|
88
|
-
|| rootNode.object.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier)) {
|
|
89
|
-
expressionsOnSameLine.pop();
|
|
90
|
-
}
|
|
91
|
-
expressionsOnSameLine.forEach(memberExpression => {
|
|
92
|
-
context.report({
|
|
93
|
-
node: memberExpression.property,
|
|
94
|
-
loc: memberExpression.property.loc.start,
|
|
95
|
-
messageId: 'expectedLineBreak',
|
|
96
|
-
data: {
|
|
97
|
-
propertyName: getPropertyText(memberExpression),
|
|
98
|
-
},
|
|
99
|
-
fix: fixer => {
|
|
100
|
-
const firstTokenAfterObject = sourceCode.getTokenAfter(memberExpression.object, isNotClosingParenToken);
|
|
101
|
-
return fixer.insertTextBefore(firstTokenAfterObject, '\n');
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
CallExpression: (node) => {
|
|
110
|
-
if (node.callee?.type === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) {
|
|
111
|
-
validateCallExpressionIgnoreDepth(node);
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
MemberExpression: (node) => {
|
|
115
|
-
validateCallExpressionIgnoreDepth(node);
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
},
|
|
119
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parameterDestructuring = void 0;
|
|
4
|
-
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
-
const createRule_1 = require("../createRule");
|
|
6
|
-
exports.parameterDestructuring = (0, createRule_1.createRule)({
|
|
7
|
-
name: 'parameter-destructuring',
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'layout',
|
|
10
|
-
docs: {
|
|
11
|
-
description: 'Prevent noisy destructuring on parameters',
|
|
12
|
-
},
|
|
13
|
-
hasSuggestions: true,
|
|
14
|
-
schema: [],
|
|
15
|
-
messages: {
|
|
16
|
-
unexpectedDestructuring: ('Destructuring should not be done in the parameters. '
|
|
17
|
-
+ 'Bind to a variable and destructure inside the function.'),
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
defaultOptions: [],
|
|
21
|
-
create: context => {
|
|
22
|
-
const sourceCode = context.getSourceCode();
|
|
23
|
-
return {
|
|
24
|
-
ObjectPattern: function checkObjectPattern(node) {
|
|
25
|
-
const { parent } = node;
|
|
26
|
-
// Skip for destructuring in contexts unrelated to function parameters
|
|
27
|
-
if (parent?.type !== utils_1.AST_NODE_TYPES.FunctionExpression
|
|
28
|
-
&& parent?.type !== utils_1.AST_NODE_TYPES.FunctionDeclaration
|
|
29
|
-
&& parent?.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
// Allow one-line destructuring
|
|
33
|
-
if (node.loc.start.line === node.loc.end.line) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const { body } = parent;
|
|
37
|
-
context.report({
|
|
38
|
-
node: node,
|
|
39
|
-
messageId: 'unexpectedDestructuring',
|
|
40
|
-
suggest: body.type === utils_1.AST_NODE_TYPES.BlockStatement
|
|
41
|
-
? [
|
|
42
|
-
{
|
|
43
|
-
messageId: 'unexpectedDestructuring',
|
|
44
|
-
fix: (fixer) => [
|
|
45
|
-
// Replace the destructuring with a variable declaration
|
|
46
|
-
fixer.replaceText(node, 'value'),
|
|
47
|
-
// Add the destructuring inside the body
|
|
48
|
-
fixer.insertTextAfter(
|
|
49
|
-
// Null safety: a block expression always have the `{` token
|
|
50
|
-
// opening the body of the function.
|
|
51
|
-
sourceCode.getFirstToken(body), `\nconst ${sourceCode.getText(node)} = value;\n`),
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
]
|
|
55
|
-
: null,
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
},
|
|
60
|
-
});
|