export function YieldExpression(node: Object, parent: Object): boolean { return t.isBinary(parent) || t.isUnaryLike(parent) || t.isCallExpression(parent) || t.isMemberExpression(parent) || t.isNewExpression(parent); }
export function Binary(node: Object, parent: Object): boolean { if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node) { return true; } if (t.isUnaryLike(parent)) { return true; } if (t.isMemberExpression(parent) && parent.object === node) { return true; } if (t.isBinary(parent)) { let parentOp = parent.operator; let parentPos = PRECEDENCE[parentOp]; let nodeOp = node.operator; let nodePos = PRECEDENCE[nodeOp]; if (parentPos > nodePos) { return true; } // Logical expressions with the same precedence don't need parens. if (parentPos === nodePos && parent.right === node && !t.isLogicalExpression(parent)) { return true; } } return false; }
// Walk up the print stack to deterimine if our node can come first // in statement. function isFirstInStatement(printStack: Array<Object>): boolean { let i = printStack.length - 1; let node = printStack[i]; i--; let parent = printStack[i]; while (i > 0) { if (t.isExpressionStatement(parent, { expression: node })) { return true; } if ((t.isCallExpression(parent, { callee: node })) || (t.isSequenceExpression(parent) && parent.expressions[0] === node) || (t.isMemberExpression(parent, { object: node })) || (t.isConditional(parent, { test: node })) || (t.isBinary(parent, { left: node })) || (t.isAssignmentExpression(parent, { left: node }))) { node = parent; i--; parent = printStack[i]; } else { return false; } } return false; }
export function YieldExpression(node, parent) { return t.isBinary(parent) || t.isUnaryLike(parent) || t.isCallExpression(parent) || t.isMemberExpression(parent) || t.isNewExpression(parent); }
function isHelper(node) { if (t.isMemberExpression(node)) { return isHelper(node.object) || isHelper(node.property); } else if (t.isIdentifier(node)) { return node.name === "require" || node.name[0] === "_"; } else if (t.isCallExpression(node)) { return isHelper(node.callee); } else if (t.isBinary(node) || t.isAssignmentExpression(node)) { return (t.isIdentifier(node.left) && isHelper(node.left)) || isHelper(node.right); } else { return false; } }
export function ConditionalExpression(node: Object, parent: Object): boolean { if (t.isUnaryLike(parent)) { return true; } if (t.isBinary(parent)) { return true; } if (t.isConditionalExpression(parent, { test: node })) { return true; } return UnaryLike(node, parent); }
function crawl(node, state = {}) { if (t.isMemberExpression(node)) { crawl(node.object, state); if (node.computed) crawl(node.property, state); } else if (t.isBinary(node) || t.isAssignmentExpression(node)) { crawl(node.left, state); crawl(node.right, state); } else if (t.isCallExpression(node)) { state.hasCall = true; crawl(node.callee, state); } else if (t.isFunction(node)) { state.hasFunction = true; } else if (t.isIdentifier(node)) { state.hasHelper = state.hasHelper || isHelper(node.callee); } return state; }
isPure(node, constantsOnly?: boolean) { if (t.isIdentifier(node)) { let binding = this.getBinding(node.name); if (!binding) return false; if (constantsOnly) return binding.constant; return true; } else if (t.isClass(node)) { if (node.superClass && !this.isPure(node.superClass, constantsOnly)) return false; return this.isPure(node.body, constantsOnly); } else if (t.isClassBody(node)) { for (let method of node.body) { if (!this.isPure(method, constantsOnly)) return false; } return true; } else if (t.isBinary(node)) { return this.isPure(node.left, constantsOnly) && this.isPure(node.right, constantsOnly); } else if (t.isArrayExpression(node)) { for (let elem of (node.elements: Array<Object>)) { if (!this.isPure(elem, constantsOnly)) return false; } return true; } else if (t.isObjectExpression(node)) { for (let prop of (node.properties: Array<Object>)) { if (!this.isPure(prop, constantsOnly)) return false; } return true; } else if (t.isClassMethod(node)) { if (node.computed && !this.isPure(node.key, constantsOnly)) return false; if (node.kind === "get" || node.kind === "set") return false; return true; } else if (t.isClassProperty(node) || t.isObjectProperty(node)) { if (node.computed && !this.isPure(node.key, constantsOnly)) return false; return this.isPure(node.value, constantsOnly); } else if (t.isUnaryExpression(node)) { return this.isPure(node.argument, constantsOnly); } else { return t.isPureish(node); } }
// Walk up the print stack to deterimine if our node can come first // in statement. function isFirstInStatement(printStack: Array<Object>, { considerArrow = false, considerDefaultExports = false } = {}): boolean { let i = printStack.length - 1; let node = printStack[i]; i--; let parent = printStack[i]; while (i > 0) { if (t.isExpressionStatement(parent, { expression: node })) { return true; } if (considerDefaultExports && t.isExportDefaultDeclaration(parent, { declaration: node })) { return true; } if (considerArrow && t.isArrowFunctionExpression(parent, { body: node })) { return true; } if ((t.isCallExpression(parent, { callee: node })) || (t.isSequenceExpression(parent) && parent.expressions[0] === node) || (t.isMemberExpression(parent, { object: node })) || (t.isConditional(parent, { test: node })) || (t.isBinary(parent, { left: node })) || (t.isAssignmentExpression(parent, { left: node }))) { node = parent; i--; parent = printStack[i]; } else { return false; } } return false; }