153 lines
4.2 KiB
JavaScript
153 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/master/scripts/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})`
|
|
);
|
|
},
|
|
});
|
|
},
|
|
};
|
|
},
|
|
};
|