eslint-plugin-code-style 1.3.8 → 1.3.9
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/index.js +100 -19
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -13846,6 +13846,7 @@ const reactCodeOrder = {
|
|
|
13846
13846
|
|
|
13847
13847
|
const checkCodeOrderHandler = (node, isHook) => {
|
|
13848
13848
|
const body = node.body;
|
|
13849
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
13849
13850
|
|
|
13850
13851
|
// Only check block statements (not implicit returns)
|
|
13851
13852
|
if (body.type !== "BlockStatement") return;
|
|
@@ -13902,36 +13903,115 @@ const reactCodeOrder = {
|
|
|
13902
13903
|
|
|
13903
13904
|
if (relevantStatements.length < 2) return;
|
|
13904
13905
|
|
|
13905
|
-
//
|
|
13906
|
+
// Collect all statements with their categories and original positions
|
|
13907
|
+
const statementsWithCategories = [];
|
|
13908
|
+
let hasOrderViolation = false;
|
|
13906
13909
|
let lastCategory = 0;
|
|
13907
|
-
let
|
|
13910
|
+
let violatingStatement = null;
|
|
13911
|
+
let violatingCategory = null;
|
|
13912
|
+
let previousCategory = null;
|
|
13908
13913
|
|
|
13909
|
-
for (
|
|
13914
|
+
for (let i = 0; i < relevantStatements.length; i++) {
|
|
13915
|
+
const statement = relevantStatements[i];
|
|
13910
13916
|
const category = getStatementCategoryHandler(statement, propNames);
|
|
13911
13917
|
|
|
13912
|
-
|
|
13918
|
+
statementsWithCategories.push({
|
|
13919
|
+
category,
|
|
13920
|
+
index: i,
|
|
13921
|
+
statement,
|
|
13922
|
+
});
|
|
13923
|
+
|
|
13924
|
+
// Skip unknown statements for order checking
|
|
13913
13925
|
if (category === ORDER.UNKNOWN) continue;
|
|
13914
13926
|
|
|
13915
13927
|
// Check if current category comes before the last one
|
|
13916
|
-
if (category < lastCategory) {
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
previous: ORDER_NAMES[lastCategory],
|
|
13922
|
-
type: isHook ? "hook" : "component",
|
|
13923
|
-
},
|
|
13924
|
-
message: "\"{{current}}\" should come before \"{{previous}}\" in {{type}}. Order: refs → state → redux → router → context → custom hooks → derived → useMemo → useCallback → handlers → useEffect → return",
|
|
13925
|
-
node: statement,
|
|
13926
|
-
});
|
|
13927
|
-
|
|
13928
|
-
// Only report first violation to avoid noise
|
|
13929
|
-
return;
|
|
13928
|
+
if (category < lastCategory && !hasOrderViolation) {
|
|
13929
|
+
hasOrderViolation = true;
|
|
13930
|
+
violatingStatement = statement;
|
|
13931
|
+
violatingCategory = category;
|
|
13932
|
+
previousCategory = lastCategory;
|
|
13930
13933
|
}
|
|
13931
13934
|
|
|
13932
13935
|
lastCategory = category;
|
|
13933
|
-
lastCategoryStatement = statement;
|
|
13934
13936
|
}
|
|
13937
|
+
|
|
13938
|
+
if (!hasOrderViolation) return;
|
|
13939
|
+
|
|
13940
|
+
// Sort statements by category (stable sort - maintains relative order within same category)
|
|
13941
|
+
const sortedStatements = [...statementsWithCategories].sort((a, b) => {
|
|
13942
|
+
if (a.category !== b.category) {
|
|
13943
|
+
return a.category - b.category;
|
|
13944
|
+
}
|
|
13945
|
+
|
|
13946
|
+
// Maintain original order within the same category
|
|
13947
|
+
return a.index - b.index;
|
|
13948
|
+
});
|
|
13949
|
+
|
|
13950
|
+
// Check if sorting actually changes the order
|
|
13951
|
+
const orderChanged = sortedStatements.some((s, i) => s.index !== statementsWithCategories[i].index);
|
|
13952
|
+
|
|
13953
|
+
if (!orderChanged) return;
|
|
13954
|
+
|
|
13955
|
+
// Build the fix
|
|
13956
|
+
const fixHandler = (fixer) => {
|
|
13957
|
+
// Get the base indentation from the first statement
|
|
13958
|
+
const firstStatementLine = sourceCode.lines[relevantStatements[0].loc.start.line - 1];
|
|
13959
|
+
const baseIndent = firstStatementLine.match(/^\s*/)[0];
|
|
13960
|
+
|
|
13961
|
+
// Get statement text with its leading comments
|
|
13962
|
+
const getStatementTextWithCommentsHandler = (stmt, stmtIndex) => {
|
|
13963
|
+
// Find the previous statement to determine comment boundaries
|
|
13964
|
+
const prevStmtIndex = relevantStatements.findIndex((s) => s === stmt) - 1;
|
|
13965
|
+
const prevStmt = prevStmtIndex >= 0 ? relevantStatements[prevStmtIndex] : null;
|
|
13966
|
+
const prevEnd = prevStmt ? prevStmt.range[1] : sourceCode.getFirstToken(body).range[1];
|
|
13967
|
+
|
|
13968
|
+
// Get text from after previous statement to end of current statement
|
|
13969
|
+
// This includes leading whitespace and comments
|
|
13970
|
+
const fullText = sourceCode.text.slice(prevEnd, stmt.range[1]);
|
|
13971
|
+
|
|
13972
|
+
// Trim leading newlines but keep indentation of the statement
|
|
13973
|
+
const trimmed = fullText.replace(/^\s*\n/, "");
|
|
13974
|
+
|
|
13975
|
+
return trimmed;
|
|
13976
|
+
};
|
|
13977
|
+
|
|
13978
|
+
// Build new body content
|
|
13979
|
+
let newBodyContent = "";
|
|
13980
|
+
let lastStatementCategory = null;
|
|
13981
|
+
|
|
13982
|
+
for (let i = 0; i < sortedStatements.length; i++) {
|
|
13983
|
+
const { category, statement, index } = sortedStatements[i];
|
|
13984
|
+
|
|
13985
|
+
// Add blank line between different categories (except UNKNOWN)
|
|
13986
|
+
if (lastStatementCategory !== null && category !== ORDER.UNKNOWN && lastStatementCategory !== ORDER.UNKNOWN && category !== lastStatementCategory) {
|
|
13987
|
+
newBodyContent += "\n";
|
|
13988
|
+
}
|
|
13989
|
+
|
|
13990
|
+
// Get the statement text with proper indentation
|
|
13991
|
+
const stmtText = sourceCode.getText(statement);
|
|
13992
|
+
|
|
13993
|
+
newBodyContent += baseIndent + stmtText.trim() + "\n";
|
|
13994
|
+
|
|
13995
|
+
lastStatementCategory = category;
|
|
13996
|
+
}
|
|
13997
|
+
|
|
13998
|
+
// Find the range to replace
|
|
13999
|
+
const firstStmt = relevantStatements[0];
|
|
14000
|
+
const lastStmt = relevantStatements[relevantStatements.length - 1];
|
|
14001
|
+
|
|
14002
|
+
return fixer.replaceTextRange([firstStmt.range[0], lastStmt.range[1]], newBodyContent.trimEnd());
|
|
14003
|
+
};
|
|
14004
|
+
|
|
14005
|
+
context.report({
|
|
14006
|
+
data: {
|
|
14007
|
+
current: ORDER_NAMES[violatingCategory],
|
|
14008
|
+
previous: ORDER_NAMES[previousCategory],
|
|
14009
|
+
type: isHook ? "hook" : "component",
|
|
14010
|
+
},
|
|
14011
|
+
fix: fixHandler,
|
|
14012
|
+
message: "\"{{current}}\" should come before \"{{previous}}\" in {{type}}. Order: refs → state → redux → router → context → custom hooks → derived → useMemo → useCallback → handlers → useEffect → return",
|
|
14013
|
+
node: violatingStatement,
|
|
14014
|
+
});
|
|
13935
14015
|
};
|
|
13936
14016
|
|
|
13937
14017
|
const checkFunctionHandler = (node) => {
|
|
@@ -13956,6 +14036,7 @@ const reactCodeOrder = {
|
|
|
13956
14036
|
},
|
|
13957
14037
|
meta: {
|
|
13958
14038
|
docs: { description: "Enforce consistent ordering of code blocks in React components and custom hooks" },
|
|
14039
|
+
fixable: "code",
|
|
13959
14040
|
schema: [],
|
|
13960
14041
|
type: "suggestion",
|
|
13961
14042
|
},
|
package/package.json
CHANGED