UNPKG

@suchipi/traverse

Version:
72 lines (71 loc) 2.33 kB
"use strict"; const stop = Symbol("stop"); function isNonPrimitive(value) { return ((typeof value === "object" && value != null) || typeof value === "function"); } function doTraverse(obj, descriptor, filter, beforeCallback, afterCallback, path, seens) { if (seens.has(obj)) { return; } if (isNonPrimitive(obj)) { seens.add(obj); } if (beforeCallback) { const result = beforeCallback(obj, path, descriptor); if (result === stop) { return; } } if (Array.isArray(obj)) { const children = Array.from(obj); for (let i = 0; i < children.length; i++) { const childPath = path.concat(i); const childDescriptor = Object.getOwnPropertyDescriptor(obj, i); if (filter(childDescriptor, childPath)) { const child = children[i]; doTraverse(child, childDescriptor, filter, beforeCallback, afterCallback, childPath, seens); } } } else if (isNonPrimitive(obj)) { const descriptors = Object.getOwnPropertyDescriptors(obj); const keys = Object.keys(descriptors); for (const key of keys) { const childPath = path.concat(key); const childDescriptor = descriptors[key]; if (filter(childDescriptor, childPath)) { const value = obj[key]; doTraverse(value, childDescriptor, filter, beforeCallback, afterCallback, childPath, seens); } } } if (afterCallback) { afterCallback(obj, path, descriptor); } } const defaultFilter = (descriptor, _path) => !descriptor.get; function traverse( /** * The tree structure to traverse. */ tree, /** * Callbacks to call during traversal */ callbacks) { const { before, after, filter = defaultFilter } = callbacks ?? {}; const syntheticRootDescriptor = { value: tree, writable: true, enumerable: true, configurable: true, }; if (!filter(syntheticRootDescriptor, [])) { return; } const setConstructor = typeof WeakSet === "undefined" ? Set : WeakSet; doTraverse(tree, syntheticRootDescriptor, filter, before, after, [], new setConstructor()); } traverse.stop = stop; traverse.default = traverse; module.exports = traverse;