This commit is contained in:
2022-07-21 03:28:35 +00:00
parent d7c883d6df
commit 51b34b0e1d
30103 changed files with 4152204 additions and 23 deletions
+123
View File
@@ -0,0 +1,123 @@
'use strict';
const zip = require('lodash.zip');
const toValue = value => ({value});
function computeTemplateLiteral(node) {
const expressions = node.expressions.map(computeStaticExpression);
if (expressions.some(expression => expression === undefined)) {
return undefined;
}
const quasi = node.quasis.map(quasis => quasis.value.cooked);
const value = zip(quasi, expressions.map(expr => expr.value))
.reduce((res, elts) => res.concat(elts))
.filter(Boolean)
.join('');
return toValue(value);
}
function computeBinaryExpression(operator, leftExpr, rightExpr) { // eslint-disable-line complexity
if (!leftExpr || !rightExpr) {
return undefined;
}
const left = leftExpr.value;
const right = rightExpr.value;
switch (operator) { // eslint-disable-line default-case
case '+': return toValue(left + right);
case '-': return toValue(left - right);
case '*': return toValue(left * right);
case '/': return toValue(left / right);
case '%': return toValue(left % right);
case '**': return toValue(Math.pow(left, right));
case '<<': return toValue(left << right);
case '>>': return toValue(left >> right);
case '>>>': return toValue(left >>> right);
case '&': return toValue(left & right);
case '|': return toValue(left | right);
case '^': return toValue(left | right);
case '&&': return toValue(left && right);
case '||': return toValue(left || right);
case '===': return toValue(left === right);
case '!==': return toValue(left !== right);
case '==': return toValue(left == right); // eslint-disable-line eqeqeq
case '!=': return toValue(left != right); // eslint-disable-line eqeqeq
case '<': return toValue(left < right);
case '>': return toValue(left > right);
case '<=': return toValue(left <= right);
case '>=': return toValue(left >= right);
}
}
function applyUnaryOperator(operator, expr) {
if (operator === 'void') {
return toValue(undefined);
}
if (!expr) {
return undefined;
}
const value = expr.value;
switch (operator) { // eslint-disable-line default-case
case '+': return toValue(+value); // eslint-disable-line no-implicit-coercion
case '-': return toValue(-value);
case '!': return toValue(!value);
case '~': return toValue(~value);
}
}
function computeConditionalExpression(test, consequent, alternate) {
if (!test) {
return undefined;
}
return test.value ? consequent : alternate;
}
function computeStaticExpression(node) {
if (!node) {
return undefined;
}
switch (node.type) {
case 'Identifier':
return node.name === 'undefined' ? toValue(undefined) : undefined;
case 'Literal':
return toValue(node.value);
case 'TemplateLiteral':
return computeTemplateLiteral(node);
case 'UnaryExpression':
return applyUnaryOperator(node.operator, computeStaticExpression(node.argument));
case 'BinaryExpression': {
return computeBinaryExpression(
node.operator,
computeStaticExpression(node.left),
computeStaticExpression(node.right)
);
}
case 'LogicalExpression': {
return computeBinaryExpression(
node.operator,
computeStaticExpression(node.left),
computeStaticExpression(node.right)
);
}
case 'ConditionalExpression':
return computeConditionalExpression(
computeStaticExpression(node.test),
computeStaticExpression(node.consequent),
computeStaticExpression(node.alternate)
);
default:
return undefined;
}
}
module.exports = computeStaticExpression;
+274
View File
@@ -0,0 +1,274 @@
'use strict';
function introduces(name, node) { // eslint-disable-line complexity
if (!node) {
return false;
}
switch (node.type) {
case 'Identifier':
return node.name === name;
case 'FunctionDeclaration':
return introduces(name, node.id) ||
someIntroduce(name, node.params);
case 'ArrowFunctionExpression':
return someIntroduce(name, node.params);
case 'FunctionExpression':
return someIntroduce(name, node.params);
case 'BlockStatement':
return someIntroduce(name, node.body);
case 'VariableDeclaration':
return someIntroduce(name, node.declarations);
case 'VariableDeclarator':
return introduces(name, node.id);
case 'ObjectPattern':
return someIntroduce(name, node.properties);
case 'ArrayPattern':
return someIntroduce(name, node.elements);
case 'Property':
return introduces(name, node.value);
case 'ExperimentalRestProperty':
return introduces(name, node.argument);
case 'ForStatement':
return introduces(name, node.init);
case 'ClassDeclaration':
return introduces(name, node.id);
case 'RestElement':
return introduces(name, node.argument);
case 'Program':
return someIntroduce(name, node.body);
case 'ImportDeclaration':
return someIntroduce(name, node.specifiers);
case 'ImportDefaultSpecifier':
return introduces(name, node.local);
case 'ImportSpecifier':
return introduces(name, node.local);
case 'ImportNamespaceSpecifier':
return introduces(name, node.local);
default:
return false;
}
}
function someIntroduce(name, array) {
return Array.isArray(array) && array.some(item => {
return introduces(name, item);
});
}
function containsIdentifier(name, node) { // eslint-disable-line complexity
if (!node) {
return false;
}
switch (node.type) {
// Primitives
case 'Identifier':
return node.name === name;
case 'Literal':
return false;
case 'ThisExpression':
return false;
// Objects / Arrays
case 'ArrayExpression':
return someContainIdentifier(name, node.elements);
case 'ObjectExpression':
return someContainIdentifier(name, node.properties);
case 'ExperimentalSpreadProperty':
return containsIdentifier(name, node.argument);
case 'Property':
return (node.computed && containsIdentifier(name, node.key)) ||
containsIdentifier(name, node.value);
// Expressions
case 'TemplateLiteral':
return someContainIdentifier(name, node.expressions);
case 'TaggedTemplateExpression':
return containsIdentifier(name, node.tag) || containsIdentifier(name, node.quasi);
case 'SequenceExpression':
return someContainIdentifier(name, node.expressions);
case 'CallExpression':
return containsIdentifier(name, node.callee) ||
someContainIdentifier(name, node.arguments);
case 'NewExpression':
return containsIdentifier(name, node.callee) ||
someContainIdentifier(name, node.arguments);
case 'MemberExpression':
if (node.computed === false) {
return containsIdentifier(name, node.object);
}
return containsIdentifier(name, node.property) ||
containsIdentifier(name, node.object);
case 'ConditionalExpression':
return containsIdentifier(name, node.test) ||
containsIdentifier(name, node.consequent) ||
containsIdentifier(name, node.alternate);
case 'BinaryExpression':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right);
case 'LogicalExpression':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right);
case 'AssignmentExpression':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right);
case 'UpdateExpression':
return containsIdentifier(name, node.argument);
case 'UnaryExpression':
return containsIdentifier(name, node.argument);
case 'YieldExpression':
return containsIdentifier(name, node.argument);
case 'AwaitExpression':
return containsIdentifier(name, node.argument);
case 'ArrowFunctionExpression':
if (node.params.some(param => param.type !== 'Identifier' && containsIdentifier(name, param))) {
return true;
}
return !introduces(name, node) && containsIdentifier(name, node.body);
case 'FunctionExpression':
if (node.params.some(param => param.type !== 'Identifier' && containsIdentifier(name, param))) {
return true;
}
return !introduces(name, node) && containsIdentifier(name, node.body);
case 'SpreadElement':
return containsIdentifier(name, node.argument);
// Statements / control flow
case 'ExpressionStatement':
return containsIdentifier(name, node.expression);
case 'ReturnStatement':
return containsIdentifier(name, node.argument);
case 'ThrowStatement':
return containsIdentifier(name, node.argument);
case 'IfStatement':
return containsIdentifier(name, node.test) ||
containsIdentifier(name, node.consequent) ||
containsIdentifier(name, node.alternate);
case 'BreakStatement':
return false;
case 'ContinueStatement':
return false;
case 'ForOfStatement':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right) ||
containsIdentifier(name, node.body);
case 'ForInStatement':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right) ||
containsIdentifier(name, node.body);
case 'ForStatement':
return !introduces(name, node) && (
containsIdentifier(name, node.init) ||
containsIdentifier(name, node.test) ||
containsIdentifier(name, node.update) ||
containsIdentifier(name, node.body)
);
case 'WhileStatement':
return containsIdentifier(name, node.test) ||
containsIdentifier(name, node.body);
case 'DoWhileStatement':
return containsIdentifier(name, node.test) ||
containsIdentifier(name, node.body);
case 'Program':
return !introduces(name, node) && someContainIdentifier(name, node.body);
case 'BlockStatement':
return !introduces(name, node) && someContainIdentifier(name, node.body);
case 'TryStatement':
return containsIdentifier(name, node.block) ||
containsIdentifier(name, node.handler) ||
containsIdentifier(name, node.finalizer);
case 'CatchClause':
return !introduces(name, node.param) && containsIdentifier(name, node.body);
case 'SwitchStatement':
return containsIdentifier(name, node.discriminant) || someContainIdentifier(name, node.cases);
case 'SwitchCase':
return containsIdentifier(name, node.test) || someContainIdentifier(name, node.consequent);
case 'LabeledStatement':
return containsIdentifier(name, node.body);
case 'DebuggerStatement':
return false;
case 'EmptyStatement':
return false;
// Assignment / Declaration
case 'AssignmentPattern':
return containsIdentifier(name, node.left) ||
containsIdentifier(name, node.right);
case 'VariableDeclarator':
if (node.id.type !== 'Identifier') {
return containsIdentifier(name, node.id) ||
containsIdentifier(name, node.init);
}
return containsIdentifier(name, node.init);
case 'ObjectPattern':
return node.properties.some(prop =>
prop.type === 'Property' && prop.value.type !== 'Identifier' && containsIdentifier(name, prop.value)
);
case 'FunctionDeclaration':
if (node.params.some(param => param.type !== 'Identifier' && containsIdentifier(name, param))) {
return true;
}
return !introduces(name, node) && containsIdentifier(name, node.body);
case 'ArrayPattern':
return node.elements.some(item => {
return item && item.type !== 'Identifier' && containsIdentifier(name, item);
});
case 'VariableDeclaration':
return someContainIdentifier(name, node.declarations);
case 'RestElement':
return false;
// Classes
case 'ClassDeclaration':
return !introduces(name, node) && (
containsIdentifier(name, node.superClass) ||
containsIdentifier(name, node.body)
);
case 'ClassExpression':
return containsIdentifier(name, node.superClass) ||
containsIdentifier(name, node.body);
case 'ClassBody':
return someContainIdentifier(name, node.body);
case 'MethodDefinition':
return containsIdentifier(name, node.value);
case 'Super':
return false;
// Import / export
case 'ImportDeclaration':
return false;
case 'ExportDefaultDeclaration':
return containsIdentifier(name, node.declaration);
case 'ExportNamedDeclaration':
return containsIdentifier(name, node.declaration);
// JSX
case 'JSXIdentifier':
return node.name === name;
case 'JSXElement':
return containsIdentifier(name, node.openingElement) ||
someContainIdentifier(name, node.children);
case 'JSXOpeningElement':
return containsIdentifier(name, node.name) ||
someContainIdentifier(name, node.attributes);
case 'JSXExpressionContainer':
return containsIdentifier(name, node.expression);
case 'JSXSpreadAttribute':
return containsIdentifier(name, node.argument);
case 'JSXAttribute':
return containsIdentifier(name, node.value);
default:
return false;
}
}
function someContainIdentifier(name, array) {
return Array.isArray(array) && array.some(item => {
return containsIdentifier(name, item);
});
}
module.exports = {
containsIdentifier,
someContainIdentifier
};
+18
View File
@@ -0,0 +1,18 @@
'use strict';
const computeStaticExpression = require('./compute-static-expression');
function getPropertyName(node) {
if (!node || node.type !== 'MemberExpression') {
return undefined;
}
if (node.property.type === 'Identifier' && node.computed === false) {
return node.property.name;
}
const expression = computeStaticExpression(node.property);
return expression && expression.value;
}
module.exports = getPropertyName;
+10
View File
@@ -0,0 +1,10 @@
'use strict';
const get = require('lodash.get');
const isStaticRequire = require('./is-static-require');
function getRequireSource(node) {
return isStaticRequire(node) ? get(node, 'arguments.0.value') : undefined;
}
module.exports = getRequireSource;
+13
View File
@@ -0,0 +1,13 @@
'use strict';
const functionExpressions = [
'FunctionExpression',
'ArrowFunctionExpression'
];
function isFunctionExpression(node) {
return Boolean(node) &&
functionExpressions.indexOf(node.type) !== -1;
}
module.exports = isFunctionExpression;
+37
View File
@@ -0,0 +1,37 @@
'use strict';
const getPropertyName = require('./get-property-name');
const prototypeMethods = ['then', 'catch'];
const knownNotMethods = ['promisify', 'promisifyAll', 'cancel', 'is'];
function containsThenOrCatch(node) {
return Boolean(node) &&
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
prototypeMethods.indexOf(getPropertyName(node.callee)) !== -1;
}
function isPromiseStaticMethod(node) {
return Boolean(node) &&
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'Promise' &&
knownNotMethods.indexOf(getPropertyName(node.callee)) === -1;
}
function isNewPromise(node) {
return Boolean(node) &&
node.type === 'NewExpression' &&
node.callee.type === 'Identifier' &&
node.callee.name === 'Promise';
}
function isPromise(node) {
return containsThenOrCatch(node) ||
isPromiseStaticMethod(node) ||
isNewPromise(node);
}
module.exports = isPromise;
+14
View File
@@ -0,0 +1,14 @@
'use strict';
function isStaticRequire(node) {
return Boolean(node &&
node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'require' &&
node.arguments.length === 1 &&
node.arguments[0].type === 'Literal' &&
typeof node.arguments[0].value === 'string'
);
}
module.exports = isStaticRequire;