"use strict";
const Syntax = require("estraverse").Syntax;
const esrecurse = require("esrecurse");
function getLast(xs) {
return xs[xs.length - 1] || null;
}
class PatternVisitor extends esrecurse.Visitor {
static isPattern(node) {
const nodeType = node.type;
return (
nodeType === Syntax.Identifier ||
nodeType === Syntax.ObjectPattern ||
nodeType === Syntax.ArrayPattern ||
nodeType === Syntax.SpreadElement ||
nodeType === Syntax.RestElement ||
nodeType === Syntax.AssignmentPattern
);
}
constructor(options, rootPattern, callback) {
super(null, options);
this.rootPattern = rootPattern;
this.callback = callback;
this.assignments = [];
this.rightHandNodes = [];
this.restElements = [];
}
Identifier(pattern) {
const lastRestElement = getLast(this.restElements);
this.callback(pattern, {
topLevel: pattern === this.rootPattern,
rest: lastRestElement !== null && lastRestElement !== undefined && lastRestElement.argument === pattern,
assignments: this.assignments
});
}
Property(property) {
if (property.computed) {
this.rightHandNodes.push(property.key);
}
this.visit(property.value);
}
ArrayPattern(pattern) {
for (let i = 0, iz = pattern.elements.length; i < iz; ++i) {
const element = pattern.elements[i];
this.visit(element);
}
}
AssignmentPattern(pattern) {
this.assignments.push(pattern);
this.visit(pattern.left);
this.rightHandNodes.push(pattern.right);
this.assignments.pop();
}
RestElement(pattern) {
this.restElements.push(pattern);
this.visit(pattern.argument);
this.restElements.pop();
}
MemberExpression(node) {
if (node.computed) {
this.rightHandNodes.push(node.property);
}
this.rightHandNodes.push(node.object);
}
SpreadElement(node) {
this.visit(node.argument);
}
ArrayExpression(node) {
node.elements.forEach(this.visit, this);
}
AssignmentExpression(node) {
this.assignments.push(node);
this.visit(node.left);
this.rightHandNodes.push(node.right);
this.assignments.pop();
}
CallExpression(node) {
node.arguments.forEach(a => {
this.rightHandNodes.push(a);
});
this.visit(node.callee);
}
}
module.exports = PatternVisitor;