Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import * as t from "@babel/types";
import generate from "@babel/generator";
export function isFunction(node) {
return (
t.isFunction(node) ||
t.isArrowFunctionExpression(node) ||
t.isObjectMethod(node) ||
t.isClassMethod(node)
);
}
export function isAwaitExpression(path) {
const { node, parent } = path;
return (
t.isAwaitExpression(node) ||
t.isAwaitExpression(parent.init) ||
t.isAwaitExpression(parent)
);
}
export function isYieldExpression(path) {
const { node, parent } = path;
return (
t.isYieldExpression(node) ||
t.isYieldExpression(parent.init) ||
t.isYieldExpression(parent)
);
}
export function isObjectShorthand(parent) {
if (!t.isObjectProperty(parent)) {
return false;
}
if (parent.value && parent.value.left) {
return (
parent.value.type === "AssignmentPattern" &&
parent.value.left.type === "Identifier"
);
}
return (
parent.value &&
parent.key.start == parent.value.start &&
parent.key.loc.identifierName === parent.value.loc.identifierName
);
}
export function getObjectExpressionValue(node) {
const { value } = node;
if (t.isIdentifier(value)) {
return value.name;
}
if (t.isCallExpression(value) || t.isFunctionExpression(value)) {
return "";
}
const code = generate(value).code;
const shouldWrap = t.isObjectExpression(value);
return shouldWrap ? `(${code})` : code;
}
export function getCode(node) {
return generate(node).code;
}
export function getComments(ast) {
if (!ast || !ast.comments) {
return [];
}
return ast.comments.map(comment => ({
name: comment.location,
location: comment.loc,
}));
}
export function isComputedExpression(expression) {
return /^\[/m.test(expression);
}
export function getMemberExpression(root) {
function _getMemberExpression(node, expr) {
if (t.isMemberExpression(node)) {
expr = [node.property.name].concat(expr);
return _getMemberExpression(node.object, expr);
}
if (t.isCallExpression(node)) {
return [];
}
if (t.isThisExpression(node)) {
return ["this"].concat(expr);
}
return [node.name].concat(expr);
}
const expr = _getMemberExpression(root, []);
return expr.join(".");
}
export function getVariables(dec) {
if (!dec.id) {
return [];
}
if (t.isArrayPattern(dec.id)) {
if (!dec.id.elements) {
return [];
}
// NOTE: it's possible that an element is empty or has several variables
// e.g. const [, a] = arr
// e.g. const [{a, b }] = 2
return dec.id.elements
.filter(Boolean)
.map(element => ({
name: t.isAssignmentPattern(element)
? element.left.name
: element.name || element.argument?.name,
location: element.loc,
}))
.filter(({ name }) => name);
}
return [
{
name: dec.id.name,
location: dec.loc,
},
];
}
/**
* Add the identifiers for a given object pattern.
*
* @param {Array.<Object>} identifiers
* the current list of identifiers where to push the new identifiers
* related to this path.
* @param {Set<String>} identifiersKeys
* List of currently registered identifier location key.
* @param {Object} pattern
*/
export function addPatternIdentifiers(identifiers, identifiersKeys, pattern) {
let items;
if (t.isObjectPattern(pattern)) {
items = pattern.properties.map(({ value }) => value);
}
if (t.isArrayPattern(pattern)) {
items = pattern.elements;
}
if (items) {
addIdentifiers(identifiers, identifiersKeys, items);
}
}
function addIdentifiers(identifiers, identifiersKeys, items) {
for (const item of items) {
if (t.isObjectPattern(item) || t.isArrayPattern(item)) {
addPatternIdentifiers(identifiers, identifiersKeys, item);
} else if (t.isIdentifier(item)) {
if (!identifiersKeys.has(nodeLocationKey(item.loc))) {
identifiers.push({
name: item.name,
expression: item.name,
location: item.loc,
});
}
}
}
}
// Top Level checks the number of "body" nodes in the ancestor chain
// if the node is top-level, then it shoul only have one body.
export function isTopLevel(ancestors) {
return ancestors.filter(ancestor => ancestor.key == "body").length == 1;
}
export function nodeLocationKey({ start, end }) {
return `${start.line}:${start.column}:${end.line}:${end.column}`;
}
export function getFunctionParameterNames(path) {
if (path.node.params != null) {
return path.node.params.map(param => {
if (param.type !== "AssignmentPattern") {
return param.name;
}
// Parameter with default value
if (
param.left.type === "Identifier" &&
param.right.type === "Identifier"
) {
return `${param.left.name} = ${param.right.name}`;
} else if (
param.left.type === "Identifier" &&
param.right.type === "StringLiteral"
) {
return `${param.left.name} = ${param.right.value}`;
} else if (
param.left.type === "Identifier" &&
param.right.type === "ObjectExpression"
) {
return `${param.left.name} = {}`;
} else if (
param.left.type === "Identifier" &&
param.right.type === "ArrayExpression"
) {
return `${param.left.name} = []`;
} else if (
param.left.type === "Identifier" &&
param.right.type === "NullLiteral"
) {
return `${param.left.name} = null`;
}
return null;
});
}
return [];
}