eslint-plugin-code-style 1.11.3 → 1.11.4
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 +16 -0
- package/index.js +159 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.11.4] - 2026-02-04
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **`opening-brackets-same-line`**
|
|
15
|
+
- Collapse JSX elements with simple children to single line (e.g., `<span>{strings.label}</span>`)
|
|
16
|
+
- Handle simple LogicalExpression children (e.g., `<p>{user?.email || fallback}</p>`)
|
|
17
|
+
|
|
18
|
+
- **`jsx-children-on-new-line`** / **`jsx-element-child-new-line`**
|
|
19
|
+
- Recognize simple LogicalExpression (≤2 operands) as simple children
|
|
20
|
+
- Recognize ChainExpression (optional chaining like `user?.name`) as simple expression
|
|
21
|
+
- Prevent circular fix conflicts with `opening-brackets-same-line`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
10
25
|
## [1.11.3] - 2026-02-04
|
|
11
26
|
|
|
12
27
|
### Fixed
|
|
@@ -1489,6 +1504,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1489
1504
|
|
|
1490
1505
|
---
|
|
1491
1506
|
|
|
1507
|
+
[1.11.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.3...v1.11.4
|
|
1492
1508
|
[1.11.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.2...v1.11.3
|
|
1493
1509
|
[1.11.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.1...v1.11.2
|
|
1494
1510
|
[1.11.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.0...v1.11.1
|
package/index.js
CHANGED
|
@@ -7683,6 +7683,12 @@ const jsxChildrenOnNewLine = {
|
|
|
7683
7683
|
|
|
7684
7684
|
if (expr.type === "Identifier") return true;
|
|
7685
7685
|
if (expr.type === "Literal") return true;
|
|
7686
|
+
|
|
7687
|
+
// Handle ChainExpression (optional chaining like user?.name)
|
|
7688
|
+
if (expr.type === "ChainExpression") {
|
|
7689
|
+
return isSimpleExpressionHandler(expr.expression);
|
|
7690
|
+
}
|
|
7691
|
+
|
|
7686
7692
|
if (expr.type === "MemberExpression") {
|
|
7687
7693
|
// Allow nested member expressions like row.original.currency or row[field]
|
|
7688
7694
|
let current = expr;
|
|
@@ -7700,6 +7706,11 @@ const jsxChildrenOnNewLine = {
|
|
|
7700
7706
|
current = current.object;
|
|
7701
7707
|
}
|
|
7702
7708
|
|
|
7709
|
+
// Handle ChainExpression at the end of the chain
|
|
7710
|
+
if (current.type === "ChainExpression") {
|
|
7711
|
+
return isSimpleExpressionHandler(current.expression);
|
|
7712
|
+
}
|
|
7713
|
+
|
|
7703
7714
|
return current.type === "Identifier";
|
|
7704
7715
|
}
|
|
7705
7716
|
|
|
@@ -7719,6 +7730,32 @@ const jsxChildrenOnNewLine = {
|
|
|
7719
7730
|
return false;
|
|
7720
7731
|
}
|
|
7721
7732
|
|
|
7733
|
+
// Allow simple LogicalExpression (2 operands with simple left/right)
|
|
7734
|
+
if (expr.type === "LogicalExpression") {
|
|
7735
|
+
// Count operands - if more than 2, not simple
|
|
7736
|
+
const countOperands = (n) => {
|
|
7737
|
+
if (n.type === "LogicalExpression") {
|
|
7738
|
+
return countOperands(n.left) + countOperands(n.right);
|
|
7739
|
+
}
|
|
7740
|
+
|
|
7741
|
+
return 1;
|
|
7742
|
+
};
|
|
7743
|
+
|
|
7744
|
+
if (countOperands(expr) > 2) return false;
|
|
7745
|
+
|
|
7746
|
+
// Check if left and right are simple
|
|
7747
|
+
const isSimpleSide = (n) => {
|
|
7748
|
+
if (n.type === "Identifier") return true;
|
|
7749
|
+
if (n.type === "Literal") return true;
|
|
7750
|
+
if (n.type === "MemberExpression") return isSimpleExpressionHandler(n);
|
|
7751
|
+
if (n.type === "ChainExpression" && n.expression) return isSimpleSide(n.expression);
|
|
7752
|
+
|
|
7753
|
+
return false;
|
|
7754
|
+
};
|
|
7755
|
+
|
|
7756
|
+
return isSimpleSide(expr.left) && isSimpleSide(expr.right);
|
|
7757
|
+
}
|
|
7758
|
+
|
|
7722
7759
|
return false;
|
|
7723
7760
|
};
|
|
7724
7761
|
|
|
@@ -7944,6 +7981,12 @@ const jsxElementChildNewLine = {
|
|
|
7944
7981
|
|
|
7945
7982
|
if (expr.type === "Identifier") return true;
|
|
7946
7983
|
if (expr.type === "Literal") return true;
|
|
7984
|
+
|
|
7985
|
+
// Handle ChainExpression (optional chaining like user?.name)
|
|
7986
|
+
if (expr.type === "ChainExpression") {
|
|
7987
|
+
return isSimpleExpressionHandler(expr.expression);
|
|
7988
|
+
}
|
|
7989
|
+
|
|
7947
7990
|
if (expr.type === "MemberExpression") {
|
|
7948
7991
|
// Allow nested member expressions like row.original.currency or row[field]
|
|
7949
7992
|
let current = expr;
|
|
@@ -7961,6 +8004,11 @@ const jsxElementChildNewLine = {
|
|
|
7961
8004
|
current = current.object;
|
|
7962
8005
|
}
|
|
7963
8006
|
|
|
8007
|
+
// Handle ChainExpression at the end of the chain
|
|
8008
|
+
if (current.type === "ChainExpression") {
|
|
8009
|
+
return isSimpleExpressionHandler(current.expression);
|
|
8010
|
+
}
|
|
8011
|
+
|
|
7964
8012
|
return current.type === "Identifier";
|
|
7965
8013
|
}
|
|
7966
8014
|
|
|
@@ -7980,6 +8028,32 @@ const jsxElementChildNewLine = {
|
|
|
7980
8028
|
return false;
|
|
7981
8029
|
}
|
|
7982
8030
|
|
|
8031
|
+
// Allow simple LogicalExpression (2 operands with simple left/right)
|
|
8032
|
+
if (expr.type === "LogicalExpression") {
|
|
8033
|
+
// Count operands - if more than 2, not simple
|
|
8034
|
+
const countOperands = (n) => {
|
|
8035
|
+
if (n.type === "LogicalExpression") {
|
|
8036
|
+
return countOperands(n.left) + countOperands(n.right);
|
|
8037
|
+
}
|
|
8038
|
+
|
|
8039
|
+
return 1;
|
|
8040
|
+
};
|
|
8041
|
+
|
|
8042
|
+
if (countOperands(expr) > 2) return false;
|
|
8043
|
+
|
|
8044
|
+
// Check if left and right are simple
|
|
8045
|
+
const isSimpleSide = (n) => {
|
|
8046
|
+
if (n.type === "Identifier") return true;
|
|
8047
|
+
if (n.type === "Literal") return true;
|
|
8048
|
+
if (n.type === "MemberExpression") return isSimpleExpressionHandler(n);
|
|
8049
|
+
if (n.type === "ChainExpression" && n.expression) return isSimpleSide(n.expression);
|
|
8050
|
+
|
|
8051
|
+
return false;
|
|
8052
|
+
};
|
|
8053
|
+
|
|
8054
|
+
return isSimpleSide(expr.left) && isSimpleSide(expr.right);
|
|
8055
|
+
}
|
|
8056
|
+
|
|
7983
8057
|
return false;
|
|
7984
8058
|
};
|
|
7985
8059
|
|
|
@@ -13117,6 +13191,49 @@ const openingBracketsSameLine = {
|
|
|
13117
13191
|
message: "Simple expression should be on single line in JSX attribute",
|
|
13118
13192
|
node: expression,
|
|
13119
13193
|
});
|
|
13194
|
+
|
|
13195
|
+
return;
|
|
13196
|
+
}
|
|
13197
|
+
|
|
13198
|
+
// Check if parent JSX element should be collapsed to single line
|
|
13199
|
+
// e.g., <span>\n {strings.label}\n</span> → <span>{strings.label}</span>
|
|
13200
|
+
const parent = node.parent;
|
|
13201
|
+
|
|
13202
|
+
if (parent && parent.type === "JSXElement") {
|
|
13203
|
+
const children = parent.children.filter(
|
|
13204
|
+
(child) => !(child.type === "JSXText" && /^\s*$/.test(child.value)),
|
|
13205
|
+
);
|
|
13206
|
+
|
|
13207
|
+
// Only collapse if this expression is the only meaningful child
|
|
13208
|
+
if (children.length === 1 && children[0] === node) {
|
|
13209
|
+
const openingTag = parent.openingElement;
|
|
13210
|
+
const closingTag = parent.closingElement;
|
|
13211
|
+
|
|
13212
|
+
if (closingTag) {
|
|
13213
|
+
const openTagEnd = openingTag.loc.end.line;
|
|
13214
|
+
const closeTagStart = closingTag.loc.start.line;
|
|
13215
|
+
|
|
13216
|
+
// Check if element spans multiple lines but content is simple
|
|
13217
|
+
if (openTagEnd !== closeTagStart) {
|
|
13218
|
+
const openTagText = sourceCode.getText(openingTag);
|
|
13219
|
+
const closeTagText = sourceCode.getText(closingTag);
|
|
13220
|
+
const expressionText = sourceCode.getText(node);
|
|
13221
|
+
const collapsedLength = openTagText.length + expressionText.length + closeTagText.length;
|
|
13222
|
+
|
|
13223
|
+
// Only collapse if total length is reasonable
|
|
13224
|
+
if (collapsedLength <= 120) {
|
|
13225
|
+
context.report({
|
|
13226
|
+
fix: (fixer) => fixer.replaceTextRange(
|
|
13227
|
+
[openingTag.range[1], closingTag.range[0]],
|
|
13228
|
+
expressionText,
|
|
13229
|
+
),
|
|
13230
|
+
message: "JSX element with simple expression should be on single line",
|
|
13231
|
+
node: parent,
|
|
13232
|
+
});
|
|
13233
|
+
}
|
|
13234
|
+
}
|
|
13235
|
+
}
|
|
13236
|
+
}
|
|
13120
13237
|
}
|
|
13121
13238
|
|
|
13122
13239
|
return;
|
|
@@ -13280,6 +13397,48 @@ const openingBracketsSameLine = {
|
|
|
13280
13397
|
message: "Simple logical expression should be on a single line",
|
|
13281
13398
|
node: expression,
|
|
13282
13399
|
});
|
|
13400
|
+
|
|
13401
|
+
return;
|
|
13402
|
+
}
|
|
13403
|
+
|
|
13404
|
+
// Check if parent JSX element should be collapsed to single line
|
|
13405
|
+
const parent = node.parent;
|
|
13406
|
+
|
|
13407
|
+
if (parent && parent.type === "JSXElement") {
|
|
13408
|
+
const children = parent.children.filter(
|
|
13409
|
+
(child) => !(child.type === "JSXText" && /^\s*$/.test(child.value)),
|
|
13410
|
+
);
|
|
13411
|
+
|
|
13412
|
+
// Only collapse if this expression is the only meaningful child
|
|
13413
|
+
if (children.length === 1 && children[0] === node) {
|
|
13414
|
+
const openingTag = parent.openingElement;
|
|
13415
|
+
const closingTag = parent.closingElement;
|
|
13416
|
+
|
|
13417
|
+
if (closingTag) {
|
|
13418
|
+
const openTagEnd = openingTag.loc.end.line;
|
|
13419
|
+
const closeTagStart = closingTag.loc.start.line;
|
|
13420
|
+
|
|
13421
|
+
// Check if element spans multiple lines but content is simple
|
|
13422
|
+
if (openTagEnd !== closeTagStart) {
|
|
13423
|
+
const openTagText = sourceCode.getText(openingTag);
|
|
13424
|
+
const closeTagText = sourceCode.getText(closingTag);
|
|
13425
|
+
const collapsedExpr = "{" + collapsedText + "}";
|
|
13426
|
+
const collapsedLength = openTagText.length + collapsedExpr.length + closeTagText.length;
|
|
13427
|
+
|
|
13428
|
+
// Only collapse if total length is reasonable
|
|
13429
|
+
if (collapsedLength <= 120) {
|
|
13430
|
+
context.report({
|
|
13431
|
+
fix: (fixer) => fixer.replaceTextRange(
|
|
13432
|
+
[openingTag.range[1], closingTag.range[0]],
|
|
13433
|
+
collapsedExpr,
|
|
13434
|
+
),
|
|
13435
|
+
message: "JSX element with simple logical expression should be on single line",
|
|
13436
|
+
node: parent,
|
|
13437
|
+
});
|
|
13438
|
+
}
|
|
13439
|
+
}
|
|
13440
|
+
}
|
|
13441
|
+
}
|
|
13283
13442
|
}
|
|
13284
13443
|
|
|
13285
13444
|
return;
|
package/package.json
CHANGED