Add flat-ast-path-call rule (#10354)
This commit is contained in:
1 parent
64a3906571
commit
95c8086c2c
6 files changed
+159
-7
No files matched your search
+1
-1
@@ -49,7 +49,7 @@ module.exports = {
|
||||
type: "suggestion",
|
||||
docs: {
|
||||
url:
|
||||
"https://github.com/prettier/prettier/blob/main/scripts/eslint-plugin-prettier-internal-rules/better-parent-property-check-in-needs-parens.js",
|
||||
"https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/better-parent-property-check-in-needs-parens.js",
|
||||
},
|
||||
messages: {
|
||||
[MESSAGE_ID_PREFER_NAME_CHECK]:
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
"use strict";
|
||||
|
||||
// This rule only work for nested `AstPath#call()` for now
|
||||
|
||||
function astPathCallSelector(path) {
|
||||
const prefix = path ? `${path}.` : "";
|
||||
return [
|
||||
`[${prefix}type="CallExpression"]`,
|
||||
`[${prefix}callee.type="MemberExpression"]`,
|
||||
`[${prefix}callee.property.type="Identifier"]`,
|
||||
`[${prefix}callee.property.name="call"]`,
|
||||
`[${prefix}arguments.length>1]`,
|
||||
`[${prefix}arguments.0.type!="SpreadElement"]`,
|
||||
].join("");
|
||||
}
|
||||
|
||||
// Matches:
|
||||
// ```
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ```
|
||||
const selector = [
|
||||
astPathCallSelector(),
|
||||
'[arguments.0.type="ArrowFunctionExpression"]',
|
||||
"[arguments.0.params.length=1]",
|
||||
'[arguments.0.params.0.type="Identifier"]',
|
||||
astPathCallSelector("arguments.0.body"),
|
||||
'[arguments.0.body.callee.object.type="Identifier"]',
|
||||
].join("");
|
||||
|
||||
const MESSAGE_ID = "flat-ast-path-call";
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
docs: {
|
||||
url:
|
||||
"https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/flat-ast-path-call.js",
|
||||
},
|
||||
messages: {
|
||||
[MESSAGE_ID]: "Do not use nested `AstPath#{{method}}(…)`.",
|
||||
},
|
||||
fixable: "code",
|
||||
},
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode();
|
||||
|
||||
return {
|
||||
[selector](outerCall) {
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const outerCallback = outerCall.arguments[0];
|
||||
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^^^^^^^^^
|
||||
const outerCallbackParameterName = outerCallback.params[0].name;
|
||||
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const innerCall = outerCallback.body;
|
||||
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^^^^^^^^^
|
||||
const innerCallCalleeObjectName = innerCall.callee.object.name;
|
||||
|
||||
if (outerCallbackParameterName !== innerCallCalleeObjectName) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: innerCall,
|
||||
messageId: MESSAGE_ID,
|
||||
data: { method: "call" },
|
||||
*fix(fixer) {
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^^^^^
|
||||
const innerCallback = innerCall.arguments[0];
|
||||
|
||||
yield fixer.replaceTextRange(
|
||||
[
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^
|
||||
outerCallback.range[0],
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^
|
||||
innerCallback.range[0],
|
||||
],
|
||||
""
|
||||
);
|
||||
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^
|
||||
const innerNamesStart = innerCallback.range[1];
|
||||
|
||||
// path.call((childPath) => childPath.call(print, "b"), "a")
|
||||
// ^
|
||||
const innerNamesEnd = innerCall.range[1] - 1;
|
||||
|
||||
let innerNamesText = sourceCode.text.slice(
|
||||
innerNamesStart,
|
||||
innerNamesEnd
|
||||
);
|
||||
|
||||
yield fixer.replaceTextRange(
|
||||
[innerNamesStart, innerNamesEnd + 1],
|
||||
""
|
||||
);
|
||||
|
||||
const [penultimateToken, lastToken] = sourceCode.getLastTokens(
|
||||
outerCall,
|
||||
2
|
||||
);
|
||||
|
||||
// `outer` call has `trailing comma`
|
||||
if (
|
||||
penultimateToken &&
|
||||
penultimateToken.type === "Punctuator" &&
|
||||
penultimateToken.value === ","
|
||||
) {
|
||||
innerNamesText = innerNamesText.slice(1);
|
||||
}
|
||||
|
||||
yield fixer.insertTextBefore(lastToken, innerNamesText);
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -4,6 +4,7 @@ module.exports = {
|
||||
rules: {
|
||||
"better-parent-property-check-in-needs-parens": require("./better-parent-property-check-in-needs-parens"),
|
||||
"directly-loc-start-end": require("./directly-loc-start-end"),
|
||||
"flat-ast-path-call": require("./flat-ast-path-call"),
|
||||
"jsx-identifier-case": require("./jsx-identifier-case"),
|
||||
"no-doc-builder-concat": require("./no-doc-builder-concat"),
|
||||
"no-empty-flat-contents-for-if-break": require("./no-empty-flat-contents-for-if-break"),
|
||||
|
||||
@@ -73,6 +73,33 @@ test("directly-loc-start-end", {
|
||||
],
|
||||
});
|
||||
|
||||
test("flat-ast-path-call", {
|
||||
valid: [
|
||||
'path.call((childPath) => childPath.notCall(print, "b"), "a")',
|
||||
'path.notCall((childPath) => childPath.call(print, "b"), "a")',
|
||||
'path.call((childPath) => childPath.call(print, "b"))',
|
||||
'path.call((childPath) => childPath.call(print), "a")',
|
||||
'path.call((childPath) => notChildPath.call(print), "a")',
|
||||
'path.call(functionReference, "a")',
|
||||
// Only check `arrow function`
|
||||
'path.call((childPath) => {return childPath.call(print, "b")}, "a")',
|
||||
'path.call(function(childPath) {return childPath.call(print, "b")}, "a")',
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: 'path.call((childPath) => childPath.call(print, "b"), "a")',
|
||||
output: 'path.call(print, "a", "b")',
|
||||
errors: [{ message: "Do not use nested `AstPath#call(…)`." }],
|
||||
},
|
||||
{
|
||||
// Trailing comma
|
||||
code: 'path.call((childPath) => childPath.call(print, "b"), "a",)',
|
||||
output: 'path.call(print, "a", "b")',
|
||||
errors: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
test("jsx-identifier-case", {
|
||||
valid: [
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user