Files
test-repo/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-is-non-empty-array.js
T

152 lines
4.2 KiB
JavaScript

"use strict";
const getLengthSelector = (path) =>
`[${path}.type="MemberExpression"][${path}.property.type="Identifier"][${path}.property.name="length"]`;
const selector = [
"LogicalExpression",
':not(FunctionDeclaration[id.name="isNonEmptyArray"] *)',
'[operator="&&"]',
`:matches(${[
// `&& foo.length`
getLengthSelector("right"),
// `&& foo.length !== 0`
// `&& foo.length > 0`
[
'[right.type="BinaryExpression"]',
':matches([right.operator="!=="], [right.operator=">"])',
getLengthSelector("right.left"),
'[right.right.type="Literal"]',
'[right.right.raw="0"]',
].join(""),
].join(", ")})`,
].join("");
const negativeSelector = [
"LogicalExpression",
'[operator="||"]',
`:matches(${[
// `|| !foo.length`
[
'[right.type="UnaryExpression"]',
'[right.operator="!"]',
getLengthSelector("right.argument"),
].join(""),
// `|| foo.length === 0`
[
'[right.type="BinaryExpression"]',
'[right.operator="==="]',
getLengthSelector("right.left"),
'[right.right.type="Literal"]',
'[right.right.raw="0"]',
].join(""),
].join(", ")})`,
].join("");
const isArrayIsArrayCall = (node) =>
node.type === "CallExpression" &&
node.callee.type === "MemberExpression" &&
node.callee.object.type === "Identifier" &&
node.callee.object.name === "Array" &&
node.callee.property.type === "Identifier" &&
node.callee.property.name === "isArray";
const MESSAGE_ID = "prefer-is-non-empty-array";
module.exports = {
meta: {
type: "suggestion",
docs: {
url: "https://github.com/prettier/prettier/blob/main/scripts/tools/eslint-plugin-prettier-internal-rules/prefer-is-non-empty-array.js",
},
messages: {
[MESSAGE_ID]: "Please use `isNonEmptyArray()`.",
},
fixable: "code",
},
create(context) {
const sourceCode = context.getSourceCode();
return {
[selector](node) {
let { left, right } = node;
while (left.type === "LogicalExpression" && left.operator === "&&") {
left = left.right;
}
let leftObject = left;
// `Array.isArray(foo)`
if (isArrayIsArrayCall(leftObject)) {
leftObject = leftObject.arguments[0];
}
const rightObject =
right.type === "BinaryExpression" ? right.left.object : right.object;
const objectText = sourceCode.getText(rightObject);
// Simple compare with code
if (sourceCode.getText(leftObject) !== objectText) {
return;
}
const [start] = left.range;
const [, end] = node.range;
context.report({
loc: {
start: sourceCode.getLocFromIndex(start),
end: sourceCode.getLocFromIndex(end),
},
messageId: MESSAGE_ID,
fix(fixer) {
return fixer.replaceTextRange(
[start, end],
`isNonEmptyArray(${objectText})`,
);
},
});
},
[negativeSelector](node) {
let { left, right } = node;
while (left.type === "LogicalExpression" && left.operator === "||") {
left = left.right;
}
if (left.type !== "UnaryExpression" || left.operator !== "!") {
return;
}
const rightObject =
right.type === "UnaryExpression"
? right.argument.object
: right.left.object;
let leftObject = left.argument;
if (isArrayIsArrayCall(leftObject)) {
leftObject = leftObject.arguments[0];
}
const objectText = sourceCode.getText(rightObject);
// Simple compare with code
if (sourceCode.getText(leftObject) !== objectText) {
return;
}
const [start] = left.range;
const [, end] = node.range;
context.report({
loc: {
start: sourceCode.getLocFromIndex(start),
end: sourceCode.getLocFromIndex(end),
},
messageId: MESSAGE_ID,
fix(fixer) {
return fixer.replaceTextRange(
[start, end],
`!isNonEmptyArray(${objectText})`,
);
},
});
},
};
},
};