| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.explode = explode; |
| exports.verify = verify; |
| exports.merge = merge; |
| |
| var virtualTypes = _interopRequireWildcard(require("./path/lib/virtual-types")); |
| |
| var t = _interopRequireWildcard(require("@babel/types")); |
| |
| var _clone = _interopRequireDefault(require("lodash/clone")); |
| |
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
| |
| function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } |
| |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } |
| |
| function explode(visitor) { |
| if (visitor._exploded) return visitor; |
| visitor._exploded = true; |
| |
| for (const nodeType of Object.keys(visitor)) { |
| if (shouldIgnoreKey(nodeType)) continue; |
| const parts = nodeType.split("|"); |
| if (parts.length === 1) continue; |
| const fns = visitor[nodeType]; |
| delete visitor[nodeType]; |
| |
| for (const part of parts) { |
| visitor[part] = fns; |
| } |
| } |
| |
| verify(visitor); |
| delete visitor.__esModule; |
| ensureEntranceObjects(visitor); |
| ensureCallbackArrays(visitor); |
| |
| for (const nodeType of Object.keys(visitor)) { |
| if (shouldIgnoreKey(nodeType)) continue; |
| const wrapper = virtualTypes[nodeType]; |
| if (!wrapper) continue; |
| const fns = visitor[nodeType]; |
| |
| for (const type of Object.keys(fns)) { |
| fns[type] = wrapCheck(wrapper, fns[type]); |
| } |
| |
| delete visitor[nodeType]; |
| |
| if (wrapper.types) { |
| for (const type of wrapper.types) { |
| if (visitor[type]) { |
| mergePair(visitor[type], fns); |
| } else { |
| visitor[type] = fns; |
| } |
| } |
| } else { |
| mergePair(visitor, fns); |
| } |
| } |
| |
| for (const nodeType of Object.keys(visitor)) { |
| if (shouldIgnoreKey(nodeType)) continue; |
| const fns = visitor[nodeType]; |
| let aliases = t.FLIPPED_ALIAS_KEYS[nodeType]; |
| const deprecratedKey = t.DEPRECATED_KEYS[nodeType]; |
| |
| if (deprecratedKey) { |
| console.trace(`Visitor defined for ${nodeType} but it has been renamed to ${deprecratedKey}`); |
| aliases = [deprecratedKey]; |
| } |
| |
| if (!aliases) continue; |
| delete visitor[nodeType]; |
| |
| for (const alias of aliases) { |
| const existing = visitor[alias]; |
| |
| if (existing) { |
| mergePair(existing, fns); |
| } else { |
| visitor[alias] = (0, _clone.default)(fns); |
| } |
| } |
| } |
| |
| for (const nodeType of Object.keys(visitor)) { |
| if (shouldIgnoreKey(nodeType)) continue; |
| ensureCallbackArrays(visitor[nodeType]); |
| } |
| |
| return visitor; |
| } |
| |
| function verify(visitor) { |
| if (visitor._verified) return; |
| |
| if (typeof visitor === "function") { |
| throw new Error("You passed `traverse()` a function when it expected a visitor object, " + "are you sure you didn't mean `{ enter: Function }`?"); |
| } |
| |
| for (const nodeType of Object.keys(visitor)) { |
| if (nodeType === "enter" || nodeType === "exit") { |
| validateVisitorMethods(nodeType, visitor[nodeType]); |
| } |
| |
| if (shouldIgnoreKey(nodeType)) continue; |
| |
| if (t.TYPES.indexOf(nodeType) < 0) { |
| throw new Error(`You gave us a visitor for the node type ${nodeType} but it's not a valid type`); |
| } |
| |
| const visitors = visitor[nodeType]; |
| |
| if (typeof visitors === "object") { |
| for (const visitorKey of Object.keys(visitors)) { |
| if (visitorKey === "enter" || visitorKey === "exit") { |
| validateVisitorMethods(`${nodeType}.${visitorKey}`, visitors[visitorKey]); |
| } else { |
| throw new Error("You passed `traverse()` a visitor object with the property " + `${nodeType} that has the invalid property ${visitorKey}`); |
| } |
| } |
| } |
| } |
| |
| visitor._verified = true; |
| } |
| |
| function validateVisitorMethods(path, val) { |
| const fns = [].concat(val); |
| |
| for (const fn of fns) { |
| if (typeof fn !== "function") { |
| throw new TypeError(`Non-function found defined in ${path} with type ${typeof fn}`); |
| } |
| } |
| } |
| |
| function merge(visitors, states = [], wrapper) { |
| const rootVisitor = {}; |
| |
| for (let i = 0; i < visitors.length; i++) { |
| const visitor = visitors[i]; |
| const state = states[i]; |
| explode(visitor); |
| |
| for (const type of Object.keys(visitor)) { |
| let visitorType = visitor[type]; |
| |
| if (state || wrapper) { |
| visitorType = wrapWithStateOrWrapper(visitorType, state, wrapper); |
| } |
| |
| const nodeVisitor = rootVisitor[type] = rootVisitor[type] || {}; |
| mergePair(nodeVisitor, visitorType); |
| } |
| } |
| |
| return rootVisitor; |
| } |
| |
| function wrapWithStateOrWrapper(oldVisitor, state, wrapper) { |
| const newVisitor = {}; |
| |
| for (const key of Object.keys(oldVisitor)) { |
| let fns = oldVisitor[key]; |
| if (!Array.isArray(fns)) continue; |
| fns = fns.map(function (fn) { |
| let newFn = fn; |
| |
| if (state) { |
| newFn = function (path) { |
| return fn.call(state, path, state); |
| }; |
| } |
| |
| if (wrapper) { |
| newFn = wrapper(state.key, key, newFn); |
| } |
| |
| return newFn; |
| }); |
| newVisitor[key] = fns; |
| } |
| |
| return newVisitor; |
| } |
| |
| function ensureEntranceObjects(obj) { |
| for (const key of Object.keys(obj)) { |
| if (shouldIgnoreKey(key)) continue; |
| const fns = obj[key]; |
| |
| if (typeof fns === "function") { |
| obj[key] = { |
| enter: fns |
| }; |
| } |
| } |
| } |
| |
| function ensureCallbackArrays(obj) { |
| if (obj.enter && !Array.isArray(obj.enter)) obj.enter = [obj.enter]; |
| if (obj.exit && !Array.isArray(obj.exit)) obj.exit = [obj.exit]; |
| } |
| |
| function wrapCheck(wrapper, fn) { |
| const newFn = function (path) { |
| if (wrapper.checkPath(path)) { |
| return fn.apply(this, arguments); |
| } |
| }; |
| |
| newFn.toString = () => fn.toString(); |
| |
| return newFn; |
| } |
| |
| function shouldIgnoreKey(key) { |
| if (key[0] === "_") return true; |
| if (key === "enter" || key === "exit" || key === "shouldSkip") return true; |
| |
| if (key === "blacklist" || key === "noScope" || key === "skipKeys") { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| function mergePair(dest, src) { |
| for (const key of Object.keys(src)) { |
| dest[key] = [].concat(dest[key] || [], src[key]); |
| } |
| } |