helpers.js (3494B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import * as t from "@babel/types"; 6 7 export function isFunction(node) { 8 return ( 9 t.isFunction(node) || 10 t.isArrowFunctionExpression(node) || 11 t.isObjectMethod(node) || 12 t.isClassMethod(node) 13 ); 14 } 15 16 export function isAwaitExpression(path) { 17 const { node, parent } = path; 18 return ( 19 t.isAwaitExpression(node) || 20 t.isAwaitExpression(parent.init) || 21 t.isAwaitExpression(parent) 22 ); 23 } 24 25 export function isYieldExpression(path) { 26 const { node, parent } = path; 27 return ( 28 t.isYieldExpression(node) || 29 t.isYieldExpression(parent.init) || 30 t.isYieldExpression(parent) 31 ); 32 } 33 34 export function getMemberExpression(root) { 35 function _getMemberExpression(node, expr) { 36 if (t.isMemberExpression(node)) { 37 expr = [node.property.name].concat(expr); 38 return _getMemberExpression(node.object, expr); 39 } 40 41 if (t.isCallExpression(node)) { 42 return []; 43 } 44 45 if (t.isThisExpression(node)) { 46 return ["this"].concat(expr); 47 } 48 49 return [node.name].concat(expr); 50 } 51 52 const expr = _getMemberExpression(root, []); 53 return expr.join("."); 54 } 55 56 export function getVariables(dec) { 57 if (!dec.id) { 58 return []; 59 } 60 61 if (t.isArrayPattern(dec.id)) { 62 if (!dec.id.elements) { 63 return []; 64 } 65 66 // NOTE: it's possible that an element is empty or has several variables 67 // e.g. const [, a] = arr 68 // e.g. const [{a, b }] = 2 69 return dec.id.elements 70 .filter(Boolean) 71 .map(element => ({ 72 name: t.isAssignmentPattern(element) 73 ? element.left.name 74 : element.name || element.argument?.name, 75 location: element.loc, 76 })) 77 .filter(({ name }) => name); 78 } 79 80 return [ 81 { 82 name: dec.id.name, 83 location: dec.loc, 84 }, 85 ]; 86 } 87 88 /** 89 * Add the identifiers for a given object pattern. 90 * 91 * @param {Array.<object>} identifiers 92 * the current list of identifiers where to push the new identifiers 93 * related to this path. 94 * @param {Set<string>} identifiersKeys 95 * List of currently registered identifier location key. 96 * @param {object} pattern 97 */ 98 export function addPatternIdentifiers(identifiers, identifiersKeys, pattern) { 99 let items; 100 if (t.isObjectPattern(pattern)) { 101 items = pattern.properties.map(({ value }) => value); 102 } 103 104 if (t.isArrayPattern(pattern)) { 105 items = pattern.elements; 106 } 107 108 if (items) { 109 addIdentifiers(identifiers, identifiersKeys, items); 110 } 111 } 112 113 function addIdentifiers(identifiers, identifiersKeys, items) { 114 for (const item of items) { 115 if (t.isObjectPattern(item) || t.isArrayPattern(item)) { 116 addPatternIdentifiers(identifiers, identifiersKeys, item); 117 } else if (t.isIdentifier(item)) { 118 if (!identifiersKeys.has(nodeLocationKey(item.loc))) { 119 identifiers.push({ 120 name: item.name, 121 expression: item.name, 122 location: item.loc, 123 }); 124 } 125 } 126 } 127 } 128 129 // Top Level checks the number of "body" nodes in the ancestor chain 130 // if the node is top-level, then it shoul only have one body. 131 export function isTopLevel(ancestors) { 132 return ancestors.filter(ancestor => ancestor.key == "body").length == 1; 133 } 134 135 export function nodeLocationKey({ start, end }) { 136 return `${start.line}:${start.column}:${end.line}:${end.column}`; 137 }