Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: fisker Cheung <lionkay@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
123 lines
3.8 KiB
JavaScript
123 lines
3.8 KiB
JavaScript
// 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";
|
|
|
|
export default {
|
|
meta: {
|
|
type: "suggestion",
|
|
messages: {
|
|
[MESSAGE_ID]: "Do not use nested `AstPath#{{method}}(…)`.",
|
|
},
|
|
fixable: "code",
|
|
},
|
|
create(context) {
|
|
const { sourceCode } = context;
|
|
|
|
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);
|
|
},
|
|
});
|
|
},
|
|
};
|
|
},
|
|
};
|