@yusufkandemir/eslint-plugin-lodash-template
Version:
ESLint plugin for John Resig-style micro template, Lodash's template, Underscore's template and EJS.
132 lines (120 loc) • 3.45 kB
JavaScript
// @ts-check
;
/**
* @typedef {import('estree').Expression} Expression
*/
const { Condition } = require("./condition");
module.exports = { Condition, getConditionsForTruthy, getConditionsForFalsy };
const cacheConditions = new WeakMap();
/**
* @param {Expression} node
* @param {string} scriptText
* @returns {Condition[]}
*/
function getConditionsForTruthy(node, scriptText) {
let cache = cacheConditions.get(node);
if (!cache) {
cache = {};
cacheConditions.set(node, cache);
}
if (cache.truthy) {
return cache.truthy;
}
const tokens = [...getConditionsForTruthyWithoutCache(node, scriptText)];
cache.truthy = tokens;
return tokens;
}
/**
* @param {Expression} node
* @param {string} scriptText
* @returns {Condition[]}
*/
function getConditionsForFalsy(node, scriptText) {
let cache = cacheConditions.get(node);
if (!cache) {
cache = {};
cacheConditions.set(node, cache);
}
if (cache.falsy) {
return cache.falsy;
}
const tokens = [...getConditionsForFalsyWithoutCache(node, scriptText)];
cache.falsy = tokens;
return tokens;
}
/**
* @param {Expression} node
* @param {string} scriptText
* @returns {Iterable<Condition>}
*/
function getConditionsForTruthyWithoutCache(node, scriptText) {
return getConditions0(node, {
scriptText,
logicalOperator: "&&",
getConditionsFromNode: (n) => getConditionsForTruthy(n, scriptText),
getConditionsFromNodeForNot: (n) =>
getConditionsForFalsy(n, scriptText),
});
}
/**
* @param {Expression} node
* @param {string} scriptText
* @returns {Iterable<Condition>}
*/
function getConditionsForFalsyWithoutCache(node, scriptText) {
return getConditions0(node, {
scriptText,
logicalOperator: "||",
getConditionsFromNode: (n) => getConditionsForFalsy(n, scriptText),
getConditionsFromNodeForNot: (n) =>
getConditionsForTruthy(n, scriptText),
});
}
/**
* @param {Expression} node
* @param {object} o
* @param {string} o.scriptText
* @param {'&&' | '||'} o.logicalOperator
* @param {(e: Expression) => Condition} o.getConditionsFromNode
* @param {(e: Expression) => Condition} o.getConditionsFromNodeForNot
* @returns {Iterable<Condition>}
*/
function* getConditions0(
node,
{
scriptText,
logicalOperator,
getConditionsFromNode,
getConditionsFromNodeForNot,
},
) {
if (node.type === "LogicalExpression") {
if (node.operator === logicalOperator) {
yield* getConditionsFromNode(node.left);
yield* getConditionsFromNode(node.right);
return;
}
} else if (node.type === "UnaryExpression") {
if (node.operator === "!") {
// Normalize
for (const condition of getConditionsFromNodeForNot(
node.argument,
)) {
yield condition.not;
}
return;
}
} else if (node.type === "CallExpression") {
if (
node.callee.type === "Identifier" &&
node.callee.name === "Boolean" &&
node.arguments.length === 1 &&
node.arguments[0]
) {
// Normalize
yield* getConditionsFromNode(node.arguments[0]);
return;
}
}
yield Condition.create(node, scriptText);
}