eslint-plugin-code-style 1.14.1 → 1.14.3
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/CHANGELOG.md +23 -0
- package/index.js +134 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.14.3] - 2026-02-05
|
|
11
|
+
|
|
12
|
+
### Enhanced
|
|
13
|
+
|
|
14
|
+
- **`type-annotation-spacing`** - Add auto-fix to collapse function types with 2 or fewer params to one line
|
|
15
|
+
- **`interface-format`** - Fix circular fix conflict by skipping collapse when property has multi-line function type
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [1.14.2] - 2026-02-05
|
|
20
|
+
|
|
21
|
+
### Enhanced
|
|
22
|
+
|
|
23
|
+
- **`type-annotation-spacing`** - Add spacing rules for async keyword and function types:
|
|
24
|
+
- Enforce space after `async` keyword: `async()` → `async ()`
|
|
25
|
+
- Enforce space after `=>` in function types: `() =>void` → `() => void`
|
|
26
|
+
- Format function types with 3+ params on multiple lines
|
|
27
|
+
- **`interface-format`** - Skip collapsing single-property interfaces when property has function type with 3+ params
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
10
31
|
## [1.14.1] - 2026-02-05
|
|
11
32
|
|
|
12
33
|
### Enhanced
|
|
@@ -1666,6 +1687,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1666
1687
|
|
|
1667
1688
|
---
|
|
1668
1689
|
|
|
1690
|
+
[1.14.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.2...v1.14.3
|
|
1691
|
+
[1.14.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.1...v1.14.2
|
|
1669
1692
|
[1.14.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.0...v1.14.1
|
|
1670
1693
|
[1.14.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.13.0...v1.14.0
|
|
1671
1694
|
[1.13.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.1...v1.13.0
|
package/index.js
CHANGED
|
@@ -19980,6 +19980,57 @@ const typeAnnotationSpacing = {
|
|
|
19980
19980
|
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
19981
19981
|
|
|
19982
19982
|
return {
|
|
19983
|
+
ArrowFunctionExpression(node) {
|
|
19984
|
+
// Check for space after async keyword: async() => -> async () =>
|
|
19985
|
+
if (node.async) {
|
|
19986
|
+
const asyncToken = sourceCode.getFirstToken(node, (t) => t.value === "async");
|
|
19987
|
+
const openParen = sourceCode.getTokenAfter(asyncToken, (t) => t.value === "(");
|
|
19988
|
+
|
|
19989
|
+
if (asyncToken && openParen) {
|
|
19990
|
+
const textBetween = sourceCode.text.slice(asyncToken.range[1], openParen.range[0]);
|
|
19991
|
+
|
|
19992
|
+
// Should have exactly one space after async
|
|
19993
|
+
if (textBetween === "") {
|
|
19994
|
+
context.report({
|
|
19995
|
+
fix: (fixer) => fixer.insertTextAfter(asyncToken, " "),
|
|
19996
|
+
message: "Missing space after async keyword",
|
|
19997
|
+
node: asyncToken,
|
|
19998
|
+
});
|
|
19999
|
+
} else if (textBetween !== " " && !textBetween.includes("\n")) {
|
|
20000
|
+
// Has extra spaces but not newline
|
|
20001
|
+
context.report({
|
|
20002
|
+
fix: (fixer) => fixer.replaceTextRange([asyncToken.range[1], openParen.range[0]], " "),
|
|
20003
|
+
message: "Should have exactly one space after async keyword",
|
|
20004
|
+
node: asyncToken,
|
|
20005
|
+
});
|
|
20006
|
+
}
|
|
20007
|
+
}
|
|
20008
|
+
}
|
|
20009
|
+
},
|
|
20010
|
+
FunctionExpression(node) {
|
|
20011
|
+
// Check for space after async keyword in function expressions: async function() -> async function ()
|
|
20012
|
+
if (node.async) {
|
|
20013
|
+
const asyncToken = sourceCode.getFirstToken(node, (t) => t.value === "async");
|
|
20014
|
+
const functionToken = sourceCode.getTokenAfter(asyncToken, (t) => t.value === "function");
|
|
20015
|
+
|
|
20016
|
+
if (functionToken) {
|
|
20017
|
+
const openParen = sourceCode.getTokenAfter(functionToken, (t) => t.value === "(");
|
|
20018
|
+
|
|
20019
|
+
if (openParen) {
|
|
20020
|
+
const textBetween = sourceCode.text.slice(functionToken.range[1], openParen.range[0]);
|
|
20021
|
+
|
|
20022
|
+
// Should have exactly one space after function keyword
|
|
20023
|
+
if (textBetween === "") {
|
|
20024
|
+
context.report({
|
|
20025
|
+
fix: (fixer) => fixer.insertTextAfter(functionToken, " "),
|
|
20026
|
+
message: "Missing space after function keyword",
|
|
20027
|
+
node: functionToken,
|
|
20028
|
+
});
|
|
20029
|
+
}
|
|
20030
|
+
}
|
|
20031
|
+
}
|
|
20032
|
+
}
|
|
20033
|
+
},
|
|
19983
20034
|
TSArrayType(node) {
|
|
19984
20035
|
// Check for space before [] like: Type []
|
|
19985
20036
|
const elementType = node.elementType;
|
|
@@ -20365,6 +20416,83 @@ const typeAnnotationSpacing = {
|
|
|
20365
20416
|
}
|
|
20366
20417
|
}
|
|
20367
20418
|
},
|
|
20419
|
+
TSFunctionType(node) {
|
|
20420
|
+
// Check for space after => in function types: () =>void -> () => void
|
|
20421
|
+
// Find the arrow token by searching all tokens in the node
|
|
20422
|
+
const tokens = sourceCode.getTokens(node);
|
|
20423
|
+
const arrowToken = tokens.find((t) => t.value === "=>");
|
|
20424
|
+
|
|
20425
|
+
if (arrowToken) {
|
|
20426
|
+
const nextToken = sourceCode.getTokenAfter(arrowToken);
|
|
20427
|
+
|
|
20428
|
+
if (nextToken) {
|
|
20429
|
+
const textAfterArrow = sourceCode.text.slice(arrowToken.range[1], nextToken.range[0]);
|
|
20430
|
+
|
|
20431
|
+
// Should have exactly one space after =>
|
|
20432
|
+
if (textAfterArrow === "") {
|
|
20433
|
+
context.report({
|
|
20434
|
+
fix: (fixer) => fixer.insertTextAfter(arrowToken, " "),
|
|
20435
|
+
message: "Missing space after => in function type",
|
|
20436
|
+
node: arrowToken,
|
|
20437
|
+
});
|
|
20438
|
+
} else if (textAfterArrow !== " " && !textAfterArrow.includes("\n")) {
|
|
20439
|
+
// Has extra spaces but not newline
|
|
20440
|
+
context.report({
|
|
20441
|
+
fix: (fixer) => fixer.replaceTextRange([arrowToken.range[1], nextToken.range[0]], " "),
|
|
20442
|
+
message: "Should have exactly one space after => in function type",
|
|
20443
|
+
node: arrowToken,
|
|
20444
|
+
});
|
|
20445
|
+
}
|
|
20446
|
+
}
|
|
20447
|
+
}
|
|
20448
|
+
|
|
20449
|
+
// Check function type params formatting
|
|
20450
|
+
// - 3+ params should be multiline
|
|
20451
|
+
// - 0-2 params should be on one line
|
|
20452
|
+
const params = node.params;
|
|
20453
|
+
const openParen = tokens.find((t) => t.value === "(");
|
|
20454
|
+
|
|
20455
|
+
if (openParen && arrowToken) {
|
|
20456
|
+
const closeParen = sourceCode.getTokenBefore(arrowToken, (t) => t.value === ")");
|
|
20457
|
+
|
|
20458
|
+
if (closeParen) {
|
|
20459
|
+
const isMultiLine = openParen.loc.start.line !== closeParen.loc.end.line;
|
|
20460
|
+
|
|
20461
|
+
if (params && params.length >= 3 && !isMultiLine) {
|
|
20462
|
+
// 3+ params on one line - expand to multiple lines
|
|
20463
|
+
const lineStart = sourceCode.text.lastIndexOf("\n", node.range[0]) + 1;
|
|
20464
|
+
const lineText = sourceCode.text.slice(lineStart, node.range[0]);
|
|
20465
|
+
const match = lineText.match(/^(\s*)/);
|
|
20466
|
+
const baseIndent = match ? match[1] : "";
|
|
20467
|
+
const paramIndent = baseIndent + " ";
|
|
20468
|
+
|
|
20469
|
+
const formattedParams = params.map((p) => {
|
|
20470
|
+
const paramText = sourceCode.getText(p);
|
|
20471
|
+
|
|
20472
|
+
return paramIndent + paramText;
|
|
20473
|
+
}).join(",\n");
|
|
20474
|
+
|
|
20475
|
+
const newParamsText = `(\n${formattedParams},\n${baseIndent})`;
|
|
20476
|
+
|
|
20477
|
+
context.report({
|
|
20478
|
+
fix: (fixer) => fixer.replaceTextRange([openParen.range[0], closeParen.range[1]], newParamsText),
|
|
20479
|
+
message: "Function type with 3+ parameters should have each parameter on its own line",
|
|
20480
|
+
node,
|
|
20481
|
+
});
|
|
20482
|
+
} else if (params && params.length <= 2 && isMultiLine) {
|
|
20483
|
+
// 0-2 params on multiple lines - collapse to one line
|
|
20484
|
+
const formattedParams = params.map((p) => sourceCode.getText(p).trim()).join(", ");
|
|
20485
|
+
const newParamsText = `(${formattedParams})`;
|
|
20486
|
+
|
|
20487
|
+
context.report({
|
|
20488
|
+
fix: (fixer) => fixer.replaceTextRange([openParen.range[0], closeParen.range[1]], newParamsText),
|
|
20489
|
+
message: "Function type with 2 or fewer parameters should be on one line",
|
|
20490
|
+
node,
|
|
20491
|
+
});
|
|
20492
|
+
}
|
|
20493
|
+
}
|
|
20494
|
+
}
|
|
20495
|
+
},
|
|
20368
20496
|
VariableDeclarator(node) {
|
|
20369
20497
|
// Check for space before generic like: ColumnDef <T>
|
|
20370
20498
|
if (node.id && node.id.typeAnnotation) {
|
|
@@ -21833,6 +21961,7 @@ const interfaceFormat = {
|
|
|
21833
21961
|
|
|
21834
21962
|
// For single member, should be on one line without trailing punctuation
|
|
21835
21963
|
// But skip if the property has a nested object type with 2+ members
|
|
21964
|
+
// Or if the property has a multi-line function type (let type-annotation-spacing handle it first)
|
|
21836
21965
|
if (members.length === 1) {
|
|
21837
21966
|
const member = members[0];
|
|
21838
21967
|
const isMultiLine = openBraceToken.loc.end.line !== closeBraceToken.loc.start.line;
|
|
@@ -21843,7 +21972,11 @@ const interfaceFormat = {
|
|
|
21843
21972
|
const hasMultiMemberNestedType = hasNestedType && nestedType.members?.length >= 2;
|
|
21844
21973
|
const hasSingleMemberNestedType = hasNestedType && nestedType.members?.length === 1;
|
|
21845
21974
|
|
|
21846
|
-
if
|
|
21975
|
+
// Check if property has function type that spans multiple lines
|
|
21976
|
+
const hasMultiLineFunctionType = nestedType?.type === "TSFunctionType" &&
|
|
21977
|
+
nestedType.loc.start.line !== nestedType.loc.end.line;
|
|
21978
|
+
|
|
21979
|
+
if (isMultiLine && !hasMultiMemberNestedType && !hasMultiLineFunctionType) {
|
|
21847
21980
|
// Build the collapsed text, handling nested types specially
|
|
21848
21981
|
let cleanText;
|
|
21849
21982
|
|
package/package.json
CHANGED