123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- // src/index.ts
- var to_string = (obj) => Object.prototype.toString.call(obj);
- var is_typed_array = (value) => ArrayBuffer.isView(value) && !(value instanceof DataView);
- var is_date = (obj) => to_string(obj) === "[object Date]";
- var is_regexp = (obj) => to_string(obj) === "[object RegExp]";
- var is_error = (obj) => to_string(obj) === "[object Error]";
- var is_boolean = (obj) => to_string(obj) === "[object Boolean]";
- var is_number = (obj) => to_string(obj) === "[object Number]";
- var is_string = (obj) => to_string(obj) === "[object String]";
- var is_array = Array.isArray;
- var gopd = Object.getOwnPropertyDescriptor;
- var is_property_enumerable = Object.prototype.propertyIsEnumerable;
- var get_own_property_symbols = Object.getOwnPropertySymbols;
- var has_own_property = Object.prototype.hasOwnProperty;
- function own_enumerable_keys(obj) {
- const res = Object.keys(obj);
- const symbols = get_own_property_symbols(obj);
- for (let i = 0; i < symbols.length; i++) {
- if (is_property_enumerable.call(obj, symbols[i])) {
- res.push(symbols[i]);
- }
- }
- return res;
- }
- function is_writable(object, key) {
- return !gopd(object, key)?.writable;
- }
- function copy(src, options) {
- if (typeof src === "object" && src !== null) {
- let dst;
- if (is_array(src)) {
- dst = [];
- } else if (is_date(src)) {
- dst = new Date(src.getTime ? src.getTime() : src);
- } else if (is_regexp(src)) {
- dst = new RegExp(src);
- } else if (is_error(src)) {
- dst = { message: src.message };
- } else if (is_boolean(src) || is_number(src) || is_string(src)) {
- dst = Object(src);
- } else if (is_typed_array(src)) {
- return src.slice();
- } else {
- dst = Object.create(Object.getPrototypeOf(src));
- }
- const iterator_function = options.includeSymbols ? own_enumerable_keys : Object.keys;
- for (const key of iterator_function(src)) {
- dst[key] = src[key];
- }
- return dst;
- }
- return src;
- }
- var empty_null = {
- includeSymbols: false,
- immutable: false
- };
- function walk(root, cb, options = empty_null) {
- const path = [];
- const parents = [];
- let alive = true;
- const iterator_function = options.includeSymbols ? own_enumerable_keys : Object.keys;
- const immutable = !!options.immutable;
- return function walker(node_) {
- const node = immutable ? copy(node_, options) : node_;
- const modifiers = {};
- let keep_going = true;
- const state = {
- node,
- node_,
- path: [].concat(path),
- parent: parents[parents.length - 1],
- parents,
- key: path[path.length - 1],
- isRoot: path.length === 0,
- level: path.length,
- circular: void 0,
- isLeaf: false,
- notLeaf: true,
- notRoot: true,
- isFirst: false,
- isLast: false,
- update: function(x, stopHere = false) {
- if (!state.isRoot) {
- state.parent.node[state.key] = x;
- }
- state.node = x;
- if (stopHere) {
- keep_going = false;
- }
- },
- delete: function(stopHere) {
- delete state.parent.node[state.key];
- if (stopHere) {
- keep_going = false;
- }
- },
- remove: function(stopHere) {
- if (is_array(state.parent.node)) {
- state.parent.node.splice(state.key, 1);
- } else {
- delete state.parent.node[state.key];
- }
- if (stopHere) {
- keep_going = false;
- }
- },
- keys: null,
- before: function(f) {
- modifiers.before = f;
- },
- after: function(f) {
- modifiers.after = f;
- },
- pre: function(f) {
- modifiers.pre = f;
- },
- post: function(f) {
- modifiers.post = f;
- },
- stop: function() {
- alive = false;
- },
- block: function() {
- keep_going = false;
- }
- };
- if (!alive) {
- return state;
- }
- function update_state() {
- if (typeof state.node === "object" && state.node !== null) {
- if (!state.keys || state.node_ !== state.node) {
- state.keys = iterator_function(state.node);
- }
- state.isLeaf = state.keys.length === 0;
- for (let i = 0; i < parents.length; i++) {
- if (parents[i].node_ === node_) {
- state.circular = parents[i];
- break;
- }
- }
- } else {
- state.isLeaf = true;
- state.keys = null;
- }
- state.notLeaf = !state.isLeaf;
- state.notRoot = !state.isRoot;
- }
- update_state();
- const ret = cb.call(state, state.node);
- if (ret !== void 0 && state.update) {
- state.update(ret);
- }
- if (modifiers.before) {
- modifiers.before.call(state, state.node);
- }
- if (!keep_going) {
- return state;
- }
- if (typeof state.node === "object" && state.node !== null && !state.circular) {
- parents.push(state);
- update_state();
- for (const [index, key] of Object.entries(state.keys ?? [])) {
- path.push(key);
- if (modifiers.pre) {
- modifiers.pre.call(state, state.node[key], key);
- }
- const child = walker(state.node[key]);
- if (immutable && has_own_property.call(state.node, key) && !is_writable(state.node, key)) {
- state.node[key] = child.node;
- }
- child.isLast = state.keys?.length ? +index === state.keys.length - 1 : false;
- child.isFirst = +index === 0;
- if (modifiers.post) {
- modifiers.post.call(state, child);
- }
- path.pop();
- }
- parents.pop();
- }
- if (modifiers.after) {
- modifiers.after.call(state, state.node);
- }
- return state;
- }(root).node;
- }
- var Traverse = class {
- // ! Have to keep these public as legacy mode requires them
- #value;
- #options;
- constructor(obj, options = empty_null) {
- this.#value = obj;
- this.#options = options;
- }
- /**
- * Get the element at the array `path`.
- */
- get(paths) {
- let node = this.#value;
- for (let i = 0; node && i < paths.length; i++) {
- const key = paths[i];
- if (!has_own_property.call(node, key) || !this.#options.includeSymbols && typeof key === "symbol") {
- return void 0;
- }
- node = node[key];
- }
- return node;
- }
- /**
- * Return whether the element at the array `path` exists.
- */
- has(paths) {
- let node = this.#value;
- for (let i = 0; node && i < paths.length; i++) {
- const key = paths[i];
- if (!has_own_property.call(node, key) || !this.#options.includeSymbols && typeof key === "symbol") {
- return false;
- }
- node = node[key];
- }
- return true;
- }
- /**
- * Set the element at the array `path` to `value`.
- */
- set(path, value) {
- let node = this.#value;
- let i = 0;
- for (i = 0; i < path.length - 1; i++) {
- const key = path[i];
- if (!has_own_property.call(node, key)) {
- node[key] = {};
- }
- node = node[key];
- }
- node[path[i]] = value;
- return value;
- }
- /**
- * Execute `fn` for each node in the object and return a new object with the results of the walk. To update nodes in the result use `this.update(value)`.
- */
- map(cb) {
- return walk(this.#value, cb, {
- immutable: true,
- includeSymbols: !!this.#options.includeSymbols
- });
- }
- /**
- * Execute `fn` for each node in the object but unlike `.map()`, when `this.update()` is called it updates the object in-place.
- */
- forEach(cb) {
- this.#value = walk(this.#value, cb, this.#options);
- return this.#value;
- }
- /**
- * For each node in the object, perform a [left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function)) with the return value of `fn(acc, node)`.
- *
- * If `init` isn't specified, `init` is set to the root object for the first step and the root element is skipped.
- */
- reduce(cb, init) {
- const skip = arguments.length === 1;
- let acc = skip ? this.#value : init;
- this.forEach(function(x) {
- if (!this.isRoot || !skip) {
- acc = cb.call(this, acc, x);
- }
- });
- return acc;
- }
- /**
- * Return an `Array` of every possible non-cyclic path in the object.
- * Paths are `Array`s of string keys.
- */
- paths() {
- const acc = [];
- this.forEach(function() {
- acc.push(this.path);
- });
- return acc;
- }
- /**
- * Return an `Array` of every node in the object.
- */
- nodes() {
- const acc = [];
- this.forEach(function() {
- acc.push(this.node);
- });
- return acc;
- }
- /**
- * Create a deep clone of the object.
- */
- clone() {
- const parents = [];
- const nodes = [];
- const options = this.#options;
- if (is_typed_array(this.#value)) {
- return this.#value.slice();
- }
- return function clone(src) {
- for (let i = 0; i < parents.length; i++) {
- if (parents[i] === src) {
- return nodes[i];
- }
- }
- if (typeof src === "object" && src !== null) {
- const dst = copy(src, options);
- parents.push(src);
- nodes.push(dst);
- const iteratorFunction = options.includeSymbols ? own_enumerable_keys : Object.keys;
- for (const key of iteratorFunction(src)) {
- dst[key] = clone(src[key]);
- }
- parents.pop();
- nodes.pop();
- return dst;
- }
- return src;
- }(this.#value);
- }
- };
- var traverse = (obj, options) => {
- return new Traverse(obj, options);
- };
- traverse.get = (obj, paths, options) => {
- return new Traverse(obj, options).get(paths);
- };
- traverse.set = (obj, path, value, options) => {
- return new Traverse(obj, options).set(path, value);
- };
- traverse.has = (obj, paths, options) => {
- return new Traverse(obj, options).has(paths);
- };
- traverse.map = (obj, cb, options) => {
- return new Traverse(obj, options).map(cb);
- };
- traverse.forEach = (obj, cb, options) => {
- return new Traverse(obj, options).forEach(cb);
- };
- traverse.reduce = (obj, cb, init, options) => {
- return new Traverse(obj, options).reduce(cb, init);
- };
- traverse.paths = (obj, options) => {
- return new Traverse(obj, options).paths();
- };
- traverse.nodes = (obj, options) => {
- return new Traverse(obj, options).nodes();
- };
- traverse.clone = (obj, options) => {
- return new Traverse(obj, options).clone();
- };
- var src_default = traverse;
- export {
- Traverse,
- src_default as default
- };
|