neotraverse
Version:
traverse and transform objects by visiting every node on a recursive walk
1,653 lines • 55.5 kB
JavaScript
//#region packages/neotraverse/src/safe/kernel/keys.ts
const object_keys$2 = Object.keys;
const has_own = Object.prototype.hasOwnProperty;
const get_proto = Object.getPrototypeOf;
const object_proto = Object.prototype;
const is_array = Array.isArray;
const get_symbols$3 = Object.getOwnPropertySymbols;
const is_enumerable$3 = Object.prototype.propertyIsEnumerable;
const to_string$1 = (x) => Object.prototype.toString.call(x);
const same_value_zero = (x, y) => x === y || x !== x && y !== y;
const is_typed_array = (value) => ArrayBuffer.isView(value) && to_string$1(value) !== "[object DataView]";
function type_tag(value) {
if (value === null) return "null";
const t = typeof value;
if (t === "function") return "function";
if (t !== "object") return "primitive";
if (is_array(value)) return "array";
if (value instanceof Date) return "date";
if (value instanceof RegExp) return "regexp";
if (value instanceof Map) return "map";
if (value instanceof Set) return "set";
if (value instanceof WeakMap) return "weakmap";
if (value instanceof WeakSet) return "weakset";
if (is_typed_array(value)) return "typed-array";
if (value instanceof ArrayBuffer) return "arraybuffer";
if (value instanceof DataView) return "dataview";
if (value instanceof Error) return "error";
return "object";
}
const is_unsafe_key = (key) => {
const k = typeof key === "object" && key !== null ? String(key) : key;
return k === "__proto__" || k === "constructor" || k === "prototype";
};
/**
* Assign without ever triggering the `__proto__` setter or mutating
* [[Prototype]]. Injected data is neutralized as an inert own key, not dropped.
*/
function safe_set(dst, key, value) {
if (typeof key === "object" && key !== null) key = String(key);
if (key === "__proto__") Object.defineProperty(dst, key, {
value,
writable: true,
enumerable: true,
configurable: true
});
else dst[key] = value;
}
/** Depth bound: catchable RangeError, never a native stack overflow. */
function assert_depth(depth, max_depth) {
if (max_depth !== void 0 && depth > max_depth) throw new RangeError(`neotraverse: maximum depth (${max_depth}) exceeded`);
}
const INT_RE = /^\d+$/;
function coerce_key(segment) {
if (INT_RE.test(segment)) {
const n = Number(segment);
if (Number.isSafeInteger(n) && String(n) === segment) return n;
}
return segment;
}
function own_keys$3(node, symbols) {
const keys = object_keys$2(node);
if (symbols) {
const syms = get_symbols$3(node);
for (let i = 0; i < syms.length; i++) if (is_enumerable$3.call(node, syms[i])) keys.push(syms[i]);
}
return keys;
}
function array_keys(node, keys) {
const len = node.length;
if (keys.length === len) {
for (let i = 0; i < len; i++) keys[i] = i;
return keys;
}
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
if (typeof k === "string" && "" + +k === k) keys[i] = +k;
}
return keys;
}
/**
* Children of `node` under the one key model, or `null` for a leaf.
* Map children are its values keyed by their Map keys; Set children are its
* elements keyed by insertion index — recursively at every level when `mapSet`.
*/
function list_keys(node, symbols, mapSet) {
if (typeof node !== "object" || node === null) return null;
if (node instanceof Map) {
if (!mapSet) return null;
return [...node.keys()];
}
if (node instanceof Set) {
if (!mapSet) return null;
const keys = new Array(node.size);
for (let i = 0; i < node.size; i++) keys[i] = i;
return keys;
}
if (is_typed_array(node) || node instanceof ArrayBuffer || node instanceof DataView) return null;
if (node instanceof WeakMap || node instanceof WeakSet) return null;
const keys = own_keys$3(node, symbols);
return is_array(node) ? array_keys(node, keys) : keys;
}
/** Child value at `key` under the same model `list_keys` used. */
function child_at(node, key, mapSet) {
if (mapSet && node instanceof Map) return node.get(key);
if (mapSet && node instanceof Set) {
let i = 0;
for (const v of node) {
if (i === key) return v;
i++;
}
return;
}
return node[key];
}
/**
* A shallow copy of container `src`: same prototype, same exotic identity
* (Date/RegExp/Error/Map/Set), every own enumerable key/entry present with the
* ORIGINAL child references. The COW fold overwrites only changed children.
*/
function shallow_shell(src, symbols) {
if (is_array(src)) {
const dst = new Array(src.length);
const keys = own_keys$3(src, symbols);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
safe_set(dst, k, src[k]);
}
return dst;
}
if (src instanceof Map) return new Map(src);
if (src instanceof Set) return new Set(src);
const tag = to_string$1(src);
let dst;
if (tag === "[object Date]" && typeof src.getTime === "function") dst = new Date(src.getTime());
else if (tag === "[object RegExp]" && typeof src.source === "string") try {
dst = new RegExp(src.source, src.flags);
dst.lastIndex = src.lastIndex;
} catch {
dst = void 0;
}
else if (tag === "[object Error]") {
const Ctor = typeof src.constructor === "function" ? src.constructor : Error;
try {
dst = new Ctor(src.message);
} catch {
dst = new Error(src.message);
}
if (src.name !== dst.name) dst.name = src.name;
if (src.stack !== void 0) dst.stack = src.stack;
if ("cause" in src) dst.cause = src.cause;
}
if (dst === void 0) {
const proto = get_proto(src);
dst = proto === object_proto ? {} : Object.create(proto);
}
const keys = own_keys$3(src, symbols);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
safe_set(dst, k, src[k]);
}
return dst;
}
//#endregion
//#region packages/neotraverse/src/safe/kernel/pattern.ts
function unescape(raw) {
if (raw.indexOf("\\") === -1) return raw;
let out = "";
for (let i = 0; i < raw.length; i++) if (raw[i] === "\\" && i + 1 < raw.length) out += raw[++i];
else out += raw[i];
return out;
}
function split_escaped(src, delim) {
const parts = [];
let cur = "";
for (let i = 0; i < src.length; i++) {
const c = src[i];
if (c === "\\" && i + 1 < src.length) {
cur += c + src[++i];
continue;
}
if (c === delim) {
parts.push(cur);
cur = "";
continue;
}
cur += c;
}
parts.push(cur);
return parts;
}
function parse(pattern) {
if (pattern === "") return [];
return split_escaped(pattern, ".").map((raw) => {
if (raw === "*") return { kind: "any" };
if (raw === "**") return { kind: "deep" };
if (raw.startsWith("{") && raw.endsWith("}") && raw.length >= 2) {
const inner = raw.slice(1, -1);
return {
kind: "alt",
keys: new Set(split_escaped(inner, ",").map(unescape).filter((k) => k !== ""))
};
}
return {
kind: "lit",
key: unescape(raw)
};
});
}
function close_mask(mask, segs) {
for (let i = 0; i < segs.length; i++) if (segs[i].kind === "deep" && mask & 1 << i) mask |= 1 << i + 1;
return mask;
}
var MaskMatcher = class {
initial;
segs;
n;
constructor(segs) {
this.segs = segs;
this.n = segs.length;
this.initial = close_mask(1, segs);
}
step(states, key) {
const segs = this.segs;
const mask = states;
const is_symbol = typeof key === "symbol";
const s = is_symbol ? "" : String(key);
let next = 0;
for (let i = 0; i < this.n; i++) {
if (!(mask & 1 << i)) continue;
const seg = segs[i];
switch (seg.kind) {
case "deep":
next |= 1 << i;
break;
case "any":
next |= 1 << i + 1;
break;
case "lit":
if (!is_symbol && seg.key === s) next |= 1 << i + 1;
break;
case "alt":
if (!is_symbol && seg.keys.has(s)) next |= 1 << i + 1;
break;
}
}
return close_mask(next, segs);
}
accepts(states) {
return (states & 1 << this.n) !== 0;
}
viable(states) {
return (states & ~(1 << this.n)) !== 0;
}
};
var SetMatcher = class {
initial;
segs;
n;
constructor(segs) {
this.segs = segs;
this.n = segs.length;
this.initial = this.close(new Set([0]));
}
close(states) {
for (let i = 0; i < this.n; i++) if (this.segs[i].kind === "deep" && states.has(i)) states.add(i + 1);
return states;
}
step(states, key) {
const is_symbol = typeof key === "symbol";
const s = is_symbol ? "" : String(key);
const next = /* @__PURE__ */ new Set();
for (const i of states) {
if (i >= this.n) continue;
const seg = this.segs[i];
if (seg.kind === "deep") next.add(i);
else if (seg.kind === "any") next.add(i + 1);
else if (seg.kind === "lit") {
if (!is_symbol && seg.key === s) next.add(i + 1);
} else if (!is_symbol && seg.keys.has(s)) next.add(i + 1);
}
return this.close(next);
}
accepts(states) {
return states.has(this.n);
}
viable(states) {
for (const i of states) if (i < this.n) return true;
return false;
}
};
const CACHE_CAP = 64;
const cache = /* @__PURE__ */ new Map();
function compile_pattern(pattern) {
if (typeof pattern !== "string") throw new TypeError("neotraverse: pattern must be a string");
let m = cache.get(pattern);
if (m !== void 0) return m;
const segs = parse(pattern);
m = segs.length <= 30 ? new MaskMatcher(segs) : new SetMatcher(segs);
if (cache.size >= CACHE_CAP) cache.delete(cache.keys().next().value);
cache.set(pattern, m);
return m;
}
function reset_frame(f, node, key, parent, depth) {
f.node = node;
f.keys = null;
f.index = -1;
f.depth = depth;
f.key = key;
f.parent = parent;
f.view = void 0;
f.tx = void 0;
f.circular = void 0;
f.states = 0;
f.matched = true;
f.skipped = false;
f.isLeaf = true;
return f;
}
function ancestor_of(node, from) {
for (let p = from; p !== void 0; p = p.parent) if (p.node === node) return p;
}
function make_frame(node, key, parent, depth) {
return {
node,
keys: null,
index: -1,
depth,
key,
parent,
view: void 0,
tx: void 0,
circular: void 0,
states: 0,
matched: true,
skipped: false,
isLeaf: true
};
}
/**
* Depth-first ENTER/EXIT cursor. Pull one event at a time via {@link step};
* after it returns true, read {@link phase} and {@link frame}. ENTER fires when
* a node is first reached (parents before children); EXIT fires once all of a
* node's descendants have been processed (children before parents).
*/
var Cursor = class {
phase = 1;
frame;
stack;
ancestors = /* @__PURE__ */ new Set();
symbols;
mapSet;
maxDepth;
matcher;
emitExits;
pool = [];
recyclable = void 0;
constructor(root, options = {}) {
this.symbols = !!options.symbols;
this.mapSet = !!options.mapSet;
this.maxDepth = options.maxDepth;
this.matcher = options.match !== void 0 ? compile_pattern(options.match) : void 0;
this.emitExits = options.exits !== false;
const f = make_frame(root, void 0, void 0, 0);
if (this.matcher) f.states = this.matcher.initial;
this.stack = [f];
this.frame = f;
}
acquire(node, key, parent, depth) {
const pooled = this.pool.pop();
return pooled !== void 0 ? reset_frame(pooled, node, key, parent, depth) : make_frame(node, key, parent, depth);
}
/** Advance to the next ENTER/EXIT event. Returns false when traversal is done. */
step() {
const stack = this.stack;
if (this.recyclable !== void 0) {
this.pool.push(this.recyclable);
this.recyclable = void 0;
}
for (;;) {
const top = stack.length - 1;
if (top < 0) return false;
const f = stack[top];
if (f.index === -1) {
this.enter(f);
f.index = 0;
this.frame = f;
this.phase = 1;
return true;
}
const keys = f.keys;
if (keys !== null && !f.skipped && f.circular === void 0 && f.index < keys.length) {
const k = keys[f.index++];
const child = this.acquire(child_at(f.node, k, this.mapSet), k, f, f.depth + 1);
if (this.matcher !== void 0) child.states = this.matcher.step(f.states, k);
assert_depth(child.depth, this.maxDepth);
stack.push(child);
continue;
}
stack.pop();
const node = f.node;
if (f.circular === void 0 && typeof node === "object" && node !== null) this.ancestors.delete(node);
if (this.emitExits) {
this.frame = f;
this.phase = 2;
this.recyclable = f;
return true;
}
this.pool.push(f);
}
}
/** Mark the current node so its descendants are not visited. */
skip() {
this.frame.skipped = true;
}
/**
* Swap the current node for `value` and descend into the REPLACEMENT's
* children instead of the original's (transform's `replace(v, {descend:true})`).
* The replacement node itself is not re-entered. Must be called during the
* current frame's ENTER, before the next {@link step}.
*/
replaceCurrent(value) {
const f = this.frame;
const old = f.node;
if (f.circular === void 0 && typeof old === "object" && old !== null) this.ancestors.delete(old);
f.node = value;
f.circular = void 0;
if (typeof value === "object" && value !== null) if (this.ancestors.has(value)) {
f.circular = ancestor_of(value, f.parent);
f.keys = null;
} else {
this.ancestors.add(value);
f.keys = list_keys(value, this.symbols, this.mapSet);
}
else f.keys = null;
f.index = 0;
f.isLeaf = f.keys === null || f.keys.length === 0;
}
enter(f) {
const node = f.node;
if (typeof node === "object" && node !== null) if (this.ancestors.has(node)) f.circular = ancestor_of(node, f.parent);
else {
this.ancestors.add(node);
f.keys = list_keys(node, this.symbols, this.mapSet);
}
f.isLeaf = f.keys === null || f.keys.length === 0;
const m = this.matcher;
if (m !== void 0) {
f.matched = m.accepts(f.states);
if (!m.viable(f.states)) f.skipped = true;
}
}
get hasMatcher() {
return this.matcher !== void 0;
}
};
function* breadthFrames(root, options = {}) {
const symbols = !!options.symbols;
const mapSet = !!options.mapSet;
const maxDepth = options.maxDepth;
const matcher = options.match !== void 0 ? compile_pattern(options.match) : void 0;
const rootFrame = make_frame(root, void 0, void 0, 0);
if (matcher) rootFrame.states = matcher.initial;
const queue = [rootFrame];
let head = 0;
while (head < queue.length) {
const f = queue[head++];
assert_depth(f.depth, maxDepth);
const node = f.node;
if (typeof node === "object" && node !== null) {
for (let p = f.parent; p !== void 0; p = p.parent) if (p.node === node) {
f.circular = p;
break;
}
if (f.circular === void 0) f.keys = list_keys(node, symbols, mapSet);
}
f.isLeaf = f.keys === null || f.keys.length === 0;
if (matcher) {
f.matched = matcher.accepts(f.states);
if (!matcher.viable(f.states)) f.skipped = true;
}
yield f;
const keys = f.keys;
if (keys !== null && !f.skipped && f.circular === void 0) for (let i = 0; i < keys.length; i++) {
const k = keys[i];
const child = make_frame(child_at(node, k, mapSet), k, f, f.depth + 1);
if (matcher) child.states = matcher.step(f.states, k);
queue.push(child);
}
}
}
//#endregion
//#region packages/neotraverse/src/safe/visit.ts
/**
* One visited node. Created fresh per node and safe to retain. The control
* method {@link skip} is meaningful only during the current iteration step.
*/
var Visit = class {
/** The node's value. */
value;
/** The node's key in its parent (`undefined` at the root). Map keys appear as-is. */
key;
/** The parent node's Visit (`undefined` at the root). */
parent;
/** Depth from the root (`0` at the root). */
depth;
/** No traversable children under the current options. */
isLeaf;
/** The ancestor Visit this node points back to, if it is a back-edge. */
circular;
/** @internal owning session, for {@link skip}. */
s;
constructor(session, value, key, parent, depth, isLeaf, circular) {
this.s = session;
this.value = value;
this.key = key;
this.parent = parent;
this.depth = depth;
this.isLeaf = isLeaf;
this.circular = circular;
}
/** Key path from the root. Lazily rebuilt from the parent chain on each read. */
get path() {
const out = new Array(this.depth);
let v = this;
for (let i = this.depth - 1; i >= 0; i--) {
out[i] = v.key;
v = v.parent;
}
return out;
}
/** RFC 6901 JSON Pointer to this node (`/users/0/name`). Lazy. */
get pointer() {
const path = this.path;
let out = "";
for (let i = 0; i < path.length; i++) {
let s = String(path[i]);
if (s.indexOf("~") !== -1 || s.indexOf("/") !== -1) s = s.replace(/~/g, "~0").replace(/\//g, "~1");
out += "/" + s;
}
return out;
}
/**
* Do not descend into this node's children (pre/breadth order only).
* Throws in post-order, where children are already visited. A no-op when
* called on a stale (already-passed) record.
*/
skip() {
if (this.s.post) throw new TypeError("neotraverse: skip() is not available in order: 'post' (children are already visited)");
if (this.s.current === this && this.s.cursor) this.s.cursor.skip();
}
};
function makeVisit(session, f, value) {
const parent = f.parent !== void 0 ? f.parent.view : void 0;
const circular = f.circular !== void 0 ? f.circular.view : void 0;
const v = new Visit(session, value, f.key, parent, f.depth, f.isLeaf, circular);
f.view = v;
return v;
}
const IteratorBase = globalThis.Iterator ?? class {};
var VisitIterator = class extends IteratorBase {
cursor;
session;
post;
hasMatcher;
done = false;
result = {
value: void 0,
done: false
};
constructor(root, options) {
super();
this.post = options.order === "post";
this.cursor = new Cursor(root, {
...options,
exits: this.post
});
this.hasMatcher = options.match !== void 0;
this.session = {
cursor: this.cursor,
post: this.post,
current: void 0
};
}
yield(v) {
this.session.current = v;
this.result.value = v;
this.result.done = false;
return this.result;
}
finish() {
this.done = true;
this.session.current = void 0;
this.result.value = void 0;
this.result.done = true;
return this.result;
}
next() {
if (this.done) return this.finish();
const cursor = this.cursor;
while (cursor.step()) {
const f = cursor.frame;
if (cursor.phase === 1) {
const v = makeVisit(this.session, f, f.node);
if (!this.post && (!this.hasMatcher || f.matched)) return this.yield(v);
} else if (this.post && (!this.hasMatcher || f.matched)) return this.yield(f.view);
}
return this.finish();
}
return() {
return this.finish();
}
};
var BreadthIterator = class extends IteratorBase {
gen;
session;
hasMatcher;
result = {
value: void 0,
done: false
};
constructor(root, options) {
super();
this.gen = breadthFrames(root, options);
this.hasMatcher = options.match !== void 0;
this.session = {
cursor: void 0,
post: false,
current: void 0
};
}
next() {
for (;;) {
const r = this.gen.next();
if (r.done) {
this.result.value = void 0;
this.result.done = true;
return this.result;
}
const f = r.value;
const v = makeVisit(this.session, f, f.node);
if (!this.hasMatcher || f.matched) {
this.result.value = v;
this.result.done = false;
return this.result;
}
}
}
};
function visit(root, optionsOrPattern, maybeOptions) {
if (typeof optionsOrPattern === "function") throw new TypeError("neotraverse: visit(root, callback) is not the v1 walk(); use transform(root, visitor) for edits or `for (const v of visit(root))` for reads");
const options = typeof optionsOrPattern === "string" ? {
...maybeOptions,
match: optionsOrPattern
} : optionsOrPattern ?? {};
return options.order === "breadth" ? new BreadthIterator(root, options) : new VisitIterator(root, options);
}
//#endregion
//#region packages/neotraverse/src/safe/transform.ts
const COMMAND = Symbol("neotraverse.command");
const REMOVE = { [COMMAND]: "remove" };
const SKIP = { [COMMAND]: "skip" };
const STOP = { [COMMAND]: "stop" };
const edit = {
replace: (value, opts) => ({
[COMMAND]: "replace",
value,
descend: !!(opts && opts.descend)
}),
remove: () => REMOVE,
skip: () => SKIP,
stop: () => STOP
};
function as_command(ret) {
if (ret == null) return void 0;
if (typeof ret === "object" && COMMAND in ret) return ret;
throw new TypeError("neotraverse: visitor returned a non-command value; did you mean edit.replace(...)?");
}
const REMOVED = Symbol("removed");
function apply_edits(base, edits, mutate, symbols) {
const tag = type_tag(base);
if (tag === "array") {
const out = [];
const len = base.length;
for (let i = 0; i < len; i++) if (edits.has(i)) {
const e = edits.get(i);
if (e !== REMOVED) out.push(e);
} else out.push(base[i]);
if (mutate) {
base.length = 0;
for (let i = 0; i < out.length; i++) base.push(out[i]);
for (const [k, v] of edits) {
if (typeof k === "number") continue;
if (v === REMOVED) delete base[k];
else base[k] = v;
}
return base;
}
const xkeys = symbols ? Object.keys(base).concat(Object.getOwnPropertySymbols(base)) : Object.keys(base);
for (let j = 0; j < xkeys.length; j++) {
const k = xkeys[j];
if (typeof k === "string" && "" + +k === k && +k < len) continue;
if (edits.has(k)) {
const e = edits.get(k);
if (e !== REMOVED) out[k] = e;
} else out[k] = base[k];
}
return out;
}
if (tag === "map") {
const out = mutate ? base : new Map(base);
for (const [k, v] of edits) if (v === REMOVED) out.delete(k);
else out.set(k, v);
return out;
}
if (tag === "set") {
const arr = [...base];
const out = [];
for (let i = 0; i < arr.length; i++) if (edits.has(i)) {
const e = edits.get(i);
if (e !== REMOVED) out.push(e);
} else out.push(arr[i]);
if (mutate) {
base.clear();
for (let i = 0; i < out.length; i++) base.add(out[i]);
return base;
}
return new Set(out);
}
const out = mutate ? base : shallow_shell(base, symbols);
for (const [k, v] of edits) if (v === REMOVED) delete out[k];
else safe_set(out, k, v);
return out;
}
function compute_fold(tx, mutate, symbols) {
if (tx.final) return tx.result;
if (tx.edits === null) return tx.base;
return apply_edits(tx.base, tx.edits, mutate, symbols);
}
function dispatch$1(session, f, baseValue, fns, rules, matchScoped) {
let current = baseValue;
let replaced = false;
let descend = false;
const runOne = (fn) => {
const cmd = as_command(fn(makeVisit(session, f, current), edit));
if (cmd === void 0) return 0;
if (cmd[COMMAND] === "replace") {
current = cmd.value;
replaced = true;
descend = cmd.descend;
return 0;
}
return cmd;
};
if (rules !== null) {
const states = f.tx.states;
for (let i = 0; i < rules.length; i++) {
if (!rules[i].matcher.accepts(states[i])) continue;
const out = runOne(rules[i].fn);
if (out !== 0) return out;
}
} else if (!matchScoped || f.matched) for (let i = 0; i < fns.length; i++) {
const out = runOne(fns[i]);
if (out !== 0) return out;
}
if (replaced) return descend ? edit.replace(current, { descend: true }) : edit.replace(current);
}
function run(root, fns, rules, options) {
const symbols = !!options.symbols;
const mapSet = !!options.mapSet;
const mutate = !!options.mutate;
const post = options.order === "post";
const matchScoped = rules === null && options.match !== void 0;
const cursor = new Cursor(root, {
symbols,
mapSet,
maxDepth: options.maxDepth,
match: rules === null ? options.match : void 0
});
const session = {
cursor,
post,
current: void 0
};
let stopped = false;
let rootResult = root;
while (cursor.step()) {
const f = cursor.frame;
if (cursor.phase === 1) {
const tx = {
edits: null,
dirty: false,
removed: false,
final: false,
base: f.node,
result: f.node,
states: null
};
f.tx = tx;
if (rules !== null) {
const states = new Array(rules.length);
const parentStates = f.parent ? f.parent.tx.states : null;
let anyViable = false;
for (let i = 0; i < rules.length; i++) {
const m = rules[i].matcher;
states[i] = f.parent ? m.step(parentStates[i], f.key) : m.initial;
if (m.viable(states[i])) anyViable = true;
}
tx.states = states;
if (!anyViable) cursor.skip();
}
if (stopped) {
cursor.skip();
continue;
}
if (post) {
makeVisit(session, f, f.node);
continue;
}
const cmd = dispatch$1(session, f, f.node, fns, rules, matchScoped);
if (cmd !== void 0) {
const t = cmd[COMMAND];
if (t === "replace") {
const rc = cmd;
tx.dirty = true;
if (rc.descend) {
tx.base = rc.value;
cursor.replaceCurrent(rc.value);
} else {
tx.final = true;
tx.result = rc.value;
cursor.skip();
}
} else if (t === "remove") {
tx.removed = true;
tx.dirty = true;
cursor.skip();
} else if (t === "skip") cursor.skip();
else {
cursor.skip();
stopped = true;
}
}
} else {
const tx = f.tx;
let folded = compute_fold(tx, mutate, symbols);
if (post && !stopped && !tx.removed && !tx.final) {
const cmd = dispatch$1(session, f, folded, fns, rules, matchScoped);
if (cmd !== void 0) {
const t = cmd[COMMAND];
if (t === "replace") {
folded = cmd.value;
tx.dirty = true;
} else if (t === "remove") {
tx.removed = true;
tx.dirty = true;
} else if (t === "stop") stopped = true;
}
}
tx.result = tx.removed ? void 0 : folded;
if (f.parent) {
if (tx.dirty || tx.removed) {
const ptx = f.parent.tx;
(ptx.edits ??= /* @__PURE__ */ new Map()).set(f.key, tx.removed ? REMOVED : tx.result);
ptx.dirty = true;
}
} else rootResult = tx.removed ? void 0 : tx.result;
}
}
return rootResult;
}
function normalize(visitor) {
if (typeof visitor === "function") return {
fns: [visitor],
rules: null
};
if (is_array(visitor)) return {
fns: visitor,
rules: null
};
const rules = [];
for (const key of Object.keys(visitor)) rules.push({
matcher: compile_pattern(key),
fn: visitor[key]
});
return {
fns: null,
rules
};
}
function transform(root, visitor, options = {}) {
const { fns, rules } = normalize(visitor);
if (rules !== null && options.match !== void 0) throw new TypeError("neotraverse: the Rules form carries its own patterns; do not also pass options.match");
if (options.order === "breadth") throw new TypeError("neotraverse: transform supports order 'pre' | 'post' only (no breadth rewrites)");
return run(root, fns, rules, options);
}
//#endregion
//#region packages/neotraverse/src/safe/transform-async.ts
async function dispatch(ctx, value, key, parentVisit, depth, isLeaf, circular, states, matched) {
let current = value;
let replaced = false;
let descend = false;
let lastVisit = new Visit(ctx.session, current, key, parentVisit, depth, isLeaf, circular);
const runOne = async (fn) => {
lastVisit = new Visit(ctx.session, current, key, parentVisit, depth, isLeaf, circular);
const cmd = as_command(await fn(lastVisit, edit));
if (cmd === void 0) return 0;
if (cmd[COMMAND] === "replace") {
current = cmd.value;
replaced = true;
descend = cmd.descend;
return 0;
}
return cmd;
};
if (ctx.rules !== null) for (let i = 0; i < ctx.rules.length; i++) {
if (!ctx.rules[i].matcher.accepts(states[i])) continue;
const out = await runOne(ctx.rules[i].fn);
if (out !== 0) return {
cmd: out,
lastVisit
};
}
else if (ctx.matchMatcher === void 0 || matched) for (let i = 0; i < ctx.fns.length; i++) {
const out = await runOne(ctx.fns[i]);
if (out !== 0) return {
cmd: out,
lastVisit
};
}
if (replaced) return {
cmd: descend ? edit.replace(current, { descend: true }) : edit.replace(current),
lastVisit
};
return {
cmd: void 0,
lastVisit
};
}
async function fold(ctx, node, key, parentVisit, depth, ancestors, states, matchStates) {
ctx.signal?.throwIfAborted();
assert_depth(depth, ctx.maxDepth);
const isObj = typeof node === "object" && node !== null;
let circularHit = false;
let circularVisit = void 0;
if (isObj && ancestors.has(node)) {
circularHit = true;
for (let p = parentVisit; p !== void 0; p = p.parent) if (p.value === node) {
circularVisit = p;
break;
}
}
let keys = isObj && !circularHit ? list_keys(node, ctx.symbols, ctx.mapSet) : null;
const isLeaf = keys === null || keys.length === 0;
const matched = ctx.matchMatcher === void 0 ? true : ctx.matchMatcher.accepts(matchStates);
const viable = ctx.matchMatcher === void 0 ? true : ctx.matchMatcher.viable(matchStates);
let anyRuleViable = true;
if (ctx.rules !== null && states !== null) {
anyRuleViable = false;
for (let i = 0; i < ctx.rules.length; i++) if (ctx.rules[i].matcher.viable(states[i])) anyRuleViable = true;
}
let base = node;
let result = node;
let changed = false;
let removed = false;
let ownVisit = new Visit(ctx.session, node, key, parentVisit, depth, isLeaf, circularVisit);
if (!ctx.post && !ctx.stopped && (ctx.matchMatcher === void 0 || true)) {
const { cmd, lastVisit } = await dispatch(ctx, node, key, parentVisit, depth, isLeaf, circularVisit, states, matched);
ownVisit = lastVisit;
if (cmd !== void 0) {
const t = cmd[COMMAND];
if (t === "replace") {
changed = true;
if (cmd.descend) {
base = cmd.value;
keys = typeof base === "object" && base !== null ? list_keys(base, ctx.symbols, ctx.mapSet) : null;
} else return {
value: cmd.value,
changed: true,
removed: false
};
} else if (t === "remove") return {
value: void 0,
changed: true,
removed: true
};
else if (t === "skip") return {
value: node,
changed: false,
removed: false
};
else {
ctx.stopped = true;
return {
value: node,
changed: false,
removed: false
};
}
}
}
if (ctx.matchMatcher !== void 0 && !viable || ctx.rules !== null && !anyRuleViable) keys = null;
if (keys !== null && !ctx.stopped && !circularHit) {
const baseIsObj = typeof base === "object" && base !== null;
if (baseIsObj) ancestors.set(base, true);
const edits = /* @__PURE__ */ new Map();
const tag = ctx.mapSet && base instanceof Map ? "map" : ctx.mapSet && base instanceof Set ? "set" : "";
const childList = [];
if (tag === "map") for (const [k, val] of base) childList.push({
k,
child: val
});
else if (tag === "set") {
let i = 0;
for (const val of base) childList.push({
k: i++,
child: val
});
} else for (let i = 0; i < keys.length; i++) childList.push({
k: keys[i],
child: base[keys[i]]
});
const limit = ctx.concurrency;
for (let start = 0; start < childList.length; start += limit) {
if (ctx.stopped) break;
const batch = childList.slice(start, start + limit);
const results = await Promise.all(batch.map((c) => {
const childStates = ctx.rules !== null && states !== null ? states.map((s, i) => ctx.rules[i].matcher.step(s, c.k)) : null;
const childMatch = ctx.matchMatcher !== void 0 ? ctx.matchMatcher.step(matchStates, c.k) : 0;
return fold(ctx, c.child, c.k, ownVisit, depth + 1, ancestors, childStates, childMatch);
}));
for (let i = 0; i < results.length; i++) {
const r = results[i];
if (r.removed) {
edits.set(batch[i].k, REMOVED);
changed = true;
} else if (r.changed) {
edits.set(batch[i].k, r.value);
changed = true;
}
}
}
if (baseIsObj) ancestors.delete(base);
if (edits.size > 0) result = apply_edits(base, edits, ctx.mutate, ctx.symbols);
else result = base;
} else result = base;
if (ctx.post && !ctx.stopped) {
const { cmd } = await dispatch(ctx, result, key, parentVisit, depth, isLeaf, circularVisit, states, matched);
if (cmd !== void 0) {
const t = cmd[COMMAND];
if (t === "replace") {
result = cmd.value;
changed = true;
} else if (t === "remove") return {
value: void 0,
changed: true,
removed: true
};
else if (t === "stop") ctx.stopped = true;
}
}
return {
value: result,
changed,
removed
};
}
async function transformAsync(root, visitor, options = {}) {
const { fns, rules } = normalize(visitor);
if (rules !== null && options.match !== void 0) throw new TypeError("neotraverse: the Rules form carries its own patterns; do not also pass options.match");
const matchMatcher = rules === null && options.match !== void 0 ? compile_pattern(options.match) : void 0;
const ctx = {
symbols: !!options.symbols,
mapSet: !!options.mapSet,
maxDepth: options.maxDepth,
mutate: !!options.mutate,
post: options.order === "post",
signal: options.signal,
concurrency: typeof options.concurrency === "number" && options.concurrency >= 1 ? Math.floor(options.concurrency) : 1,
fns,
rules,
matchMatcher,
stopped: false,
session: {
cursor: void 0,
post: options.order === "post",
current: void 0
}
};
const states = rules !== null ? rules.map((r) => r.matcher.initial) : null;
const matchStates = matchMatcher !== void 0 ? matchMatcher.initial : 0;
const r = await fold(ctx, root, void 0, void 0, 0, /* @__PURE__ */ new Map(), states, matchStates);
return r.removed ? void 0 : r.value;
}
//#endregion
//#region packages/neotraverse/src/safe/path.ts
function parse_dot(path) {
const keys = [];
let cur = "";
for (let i = 0; i < path.length; i++) {
const c = path[i];
if (c === "\\" && i + 1 < path.length) {
cur += path[++i];
continue;
}
if (c === ".") {
if (cur.length) keys.push(coerce_key(cur));
cur = "";
continue;
}
cur += c;
}
if (cur.length) keys.push(coerce_key(cur));
return keys;
}
function parse_pointer(pointer) {
if (pointer === "") return [];
return pointer.slice(1).split("/").map((seg) => coerce_key(seg.replace(/~1/g, "/").replace(/~0/g, "~")));
}
/** Normalize any path spelling to an exact key array. Array form is taken as-is. */
function to_keys(path) {
if (typeof path !== "string") return path;
if (path === "") return [];
return path[0] === "/" ? parse_pointer(path) : parse_dot(path);
}
function step_read(node, key) {
if (node === null || node === void 0) return {
found: false,
value: void 0
};
if (is_unsafe_key(key)) return {
found: false,
value: void 0
};
if (node instanceof Map) return node.has(key) ? {
found: true,
value: node.get(key)
} : {
found: false,
value: void 0
};
if (node instanceof Set) {
if (typeof key === "number" && key >= 0 && key < node.size) {
let i = 0;
for (const v of node) {
if (i === key) return {
found: true,
value: v
};
i++;
}
}
return {
found: false,
value: void 0
};
}
if (typeof node === "object" || typeof node === "string") {
if (has_own.call(node, key)) return {
found: true,
value: node[key]
};
}
return {
found: false,
value: void 0
};
}
function get(obj, path, fallback) {
const keys = to_keys(path);
let node = obj;
for (let i = 0; i < keys.length; i++) {
const r = step_read(node, keys[i]);
if (!r.found) return fallback;
node = r.value;
}
return node;
}
function has(obj, path) {
const keys = to_keys(path);
let node = obj;
for (let i = 0; i < keys.length; i++) {
const r = step_read(node, keys[i]);
if (!r.found) return false;
node = r.value;
}
return true;
}
function write_child(node, key, value) {
if (node instanceof Map) node.set(key, value);
else safe_set(node, key, value);
}
function read_child(node, key) {
if (node instanceof Map) return node.get(key);
if (node === null || typeof node !== "object") return void 0;
return node[key];
}
function copy_container(node, keyForKind) {
if (node === null || typeof node !== "object") return typeof keyForKind === "number" ? [] : {};
if (node instanceof Map) return new Map(node);
return shallow_shell(node, true);
}
function set_cow(node, keys, i, value) {
if (i === keys.length) return value;
const key = keys[i];
const isLast = i === keys.length - 1;
let child = read_child(node, key);
if (!isLast && (child === null || typeof child !== "object")) child = typeof keys[i + 1] === "number" ? [] : {};
const newChild = set_cow(child, keys, i + 1, value);
if (newChild === child && read_child(node, key) === child) return node;
const copy = copy_container(node, key);
write_child(copy, key, newChild);
return copy;
}
function set_in_place(obj, keys, value) {
let node = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
let child = read_child(node, key);
if (child === null || typeof child !== "object") {
child = typeof keys[i + 1] === "number" ? [] : {};
write_child(node, key, child);
}
node = child;
}
write_child(node, keys[keys.length - 1], value);
}
function set(obj, path, value, options) {
const keys = to_keys(path);
if (keys.length === 0) return value;
for (let i = 0; i < keys.length; i++) if (is_unsafe_key(keys[i])) throw new TypeError(`neotraverse: unsafe path segment "${String(keys[i])}"`);
if (options?.mutate) {
set_in_place(obj, keys, value);
return obj;
}
return set_cow(obj, keys, 0, value);
}
//#endregion
//#region packages/neotraverse/src/safe/clone.ts
const get_symbols$2 = Object.getOwnPropertySymbols;
const is_enumerable$2 = Object.prototype.propertyIsEnumerable;
const object_keys$1 = Object.keys;
const to_string = (x) => Object.prototype.toString.call(x);
function own_keys$2(obj, symbols) {
const keys = object_keys$1(obj);
if (symbols) {
const syms = get_symbols$2(obj);
for (let i = 0; i < syms.length; i++) if (is_enumerable$2.call(obj, syms[i])) keys.push(syms[i]);
}
return keys;
}
function is_boxed_primitive(obj) {
const tag = to_string(obj);
if (tag !== "[object Boolean]" && tag !== "[object Number]" && tag !== "[object String]") return false;
try {
return typeof obj.valueOf() !== "object";
} catch {
return false;
}
}
let shell_keyed = false;
function make_shell(src) {
if (is_array(src)) {
shell_keyed = true;
return new Array(src.length);
}
shell_keyed = false;
if (src instanceof ArrayBuffer) return src.slice(0);
if (src instanceof DataView) return new DataView(src.buffer.slice(src.byteOffset, src.byteOffset + src.byteLength), 0, src.byteLength);
if (is_typed_array(src)) return src.slice();
if (is_boxed_primitive(src)) return Object(src);
const tag = to_string(src);
if (tag === "[object Date]" && typeof src.getTime === "function") {
shell_keyed = true;
return new Date(src.getTime());
}
if (tag === "[object RegExp]" && typeof src.source === "string") try {
const re = new RegExp(src.source, src.flags);
re.lastIndex = src.lastIndex;
shell_keyed = true;
return re;
} catch {}
if (tag === "[object Error]") {
const Ctor = typeof src.constructor === "function" ? src.constructor : Error;
let dst;
try {
dst = new Ctor(src.message);
} catch {
dst = new Error(src.message);
}
if (src.name !== dst.name) dst.name = src.name;
if (src.stack !== void 0) dst.stack = src.stack;
if ("cause" in src) dst.cause = src.cause;
shell_keyed = true;
return dst;
}
if (tag === "[object Map]") return new Map(src);
if (tag === "[object Set]") return new Set(src);
shell_keyed = true;
const proto = get_proto(src);
return proto === object_proto ? {} : Object.create(proto);
}
function clone_node(src, seen, symbols, maxDepth, depth) {
if (typeof src !== "object" || src === null) return src;
assert_depth(depth, maxDepth);
const existing = seen.get(src);
if (existing !== void 0) return existing;
if (src instanceof Map) {
const dst = /* @__PURE__ */ new Map();
seen.set(src, dst);
for (const [k, v] of src) dst.set(clone_node(k, seen, symbols, maxDepth, depth + 1), clone_node(v, seen, symbols, maxDepth, depth + 1));
seen.delete(src);
return dst;
}
if (src instanceof Set) {
const dst = /* @__PURE__ */ new Set();
seen.set(src, dst);
for (const v of src) dst.add(clone_node(v, seen, symbols, maxDepth, depth + 1));
seen.delete(src);
return dst;
}
if (src instanceof WeakMap || src instanceof WeakSet) {
seen.set(src, src);
return src;
}
const dst = make_shell(src);
if (!shell_keyed) {
seen.set(src, dst);
return dst;
}
seen.set(src, dst);
const keys = own_keys$2(src, symbols);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
safe_set(dst, key, clone_node(src[key], seen, symbols, maxDepth, depth + 1));
}
if (dst instanceof Error && "cause" in src) dst.cause = clone_node(src.cause, seen, symbols, maxDepth, depth + 1);
seen.delete(src);
return dst;
}
/**
* Deep clone `value`. Cycle- and prototype-preserving; shares nothing with the
* input.
*
* @example
* ```js
* const copy = clone({ nested: { n: 1 } });
* copy.nested.n = 2; // original unchanged
* ```
*/
function clone(value, options) {
if (typeof value !== "object" || value === null) return value;
return clone_node(value, /* @__PURE__ */ new Map(), !!options?.symbols, options?.maxDepth, 0);
}
//#endregion
//#region packages/neotraverse/src/safe/equal.ts
const get_symbols$1 = Object.getOwnPropertySymbols;
const is_enumerable$1 = Object.prototype.propertyIsEnumerable;
function is_boxed(obj) {
const tag = Object.prototype.toString.call(obj);
if (tag !== "[object Boolean]" && tag !== "[object Number]" && tag !== "[object String]") return false;
try {
return typeof obj.valueOf() !== "object";
} catch {
return false;
}
}
function own_keys$1(obj, symbols) {
const keys = Object.keys(obj);
if (symbols) {
const syms = get_symbols$1(obj);
for (let i = 0; i < syms.length; i++) if (is_enumerable$1.call(obj, syms[i])) keys.push(syms[i]);
}
return keys;
}
function equal_pair(a, b, compare, symbols, seen, maxDepth, depth) {
if (a === b) return true;
assert_depth(depth, maxDepth);
if (compare) {
const custom = compare(a, b);
if (custom !== void 0) return custom;
}
if (typeof a !== typeof b) return false;
if (a === null || b === null) return a === b;
if (is_boxed(a) || is_boxed(b)) {
if (!is_boxed(a) || !is_boxed(b)) return false;
return same_value_zero(Object(a).valueOf(), Object(b).valueOf());
}
const ta = type_tag(a);
if (ta !== type_tag(b)) return false;
if (ta === "primitive" || ta === "null") return same_value_zero(a, b);
if (typeof a === "object") {
let bs = seen.get(a);
if (bs?.has(b)) return true;
if (!bs) {
bs = /* @__PURE__ */ new Set();
seen.set(a, bs);
}
bs.add(b);
}
switch (ta) {
case "date": return a.getTime() === b.getTime();
case "regexp": return a.source === b.source && a.flags === b.flags;
case "error": return a.message === b.message && a.name === b.name;
case "arraybuffer": {
if (a.byteLength !== b.byteLength) return false;
const va = new Uint8Array(a);
const vb = new Uint8Array(b);
for (let i = 0; i < va.length; i++) if (va[i] !== vb[i]) return false;
return true;
}
case "dataview":
if (a.byteLength !== b.byteLength) return false;
for (let i = 0; i < a.byteLength; i++) if (a.getUint8(i) !== b.getUint8(i)) return false;
return true;
case "typed-array":
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) if (!same_value_zero(a[i], b[i])) return false;
return true;
case "map":
if (a.size !== b.size) return false;
for (const [k, v] of a) if (!b.has(k) || !equal_pair(v, b.get(k), compare, symbols, seen, maxDepth, depth + 1)) return false;
return true;
case "set": {
if (a.size !== b.size) return false;
let allPrimitive = true;
for (const v of a) if (v !== null && (typeof v === "object" || typeof v === "function")) {
allPrimitive = false;
break;
}
if (allPrimitive) {
for (const v of a) if (!b.has(v)) return false;
return true;
}
const used = /* @__PURE__ */ new Set();
for (const v of a) {
let matched = false;
let i = 0;
for (const w of b) {
if (!used.has(i) && equal_pair(v, w, compare, symbols, seen, maxDepth, depth + 1)) {
used.add(i);
matched = true;
break;
}
i++;
}
if (!matched) return false;
}
return true;
}
case "weakmap":
case "weakset":
case "function": return a === b;
case "array":
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) if (!equal_pair(a[i], b[i], compare, symbols, seen, maxDepth, depth + 1)) return false;
return true;
default: {
const ka = own_keys$1(a, symbols);
const kb = own_keys$1(b, symbols);
if (ka.length !== kb.length) return false;
for (let i = 0; i < ka.length; i++) {
const k = ka[i];
if (!has_own.call(b, k)) return false;
if (!equal_pair(a[k], b[k], compare, symbols, seen, maxDepth, depth + 1)) return false;
}
return true;
}
}
}
/**
* Structural equality.
*
* @example
* ```js
* equal({ a: [1] }, { a: [1] }); // true
* equal(new Date(0), new Date(0)); // true
* ```
*/
function equal(a, b, options) {
return equal_pair(a, b, options?.compare, !!options?.symbols, /* @__PURE__ */ new Map(), options?.maxDepth, 0);
}
//#endregion
//#region packages/neotraverse/src/safe/merge.ts
const object_keys = Object.keys;
const get_symbols = Object.getOwnPropertySymbols;
const is_enumerable = Object.prototype.propertyIsEnumerable;
function own_keys(obj, symbols) {
const keys = object_keys(obj);
if (symbols) {
const syms = get_symbols(obj);
for (let i = 0; i < syms.length; i++) if (is_enumerable.call(obj, syms[i])) keys.push(syms[i]);
}
return keys;
}
function mergeable(t) {
return t === "object" || t === "array" || t === "map";
}
function resolve_strategy(ctx, states) {
for (let i = 0; i < ctx.atEntries.length; i++) if (ctx.atEntries[i].matcher.accepts(states[i])) return ctx.atEntries[i].strategy;
return ctx.defaultArrays;
}
function merge_arrays(base, overlay, strat, path, ctx, states) {
if (typeof strat === "function") return strat(base, overlay, path);
if (strat === "replace") return overlay;
if (strat === "concat") return base.concat(overlay);
if (strat === "union") {
const out = base.slice();
for (const el of overlay) {
let dup = false;
for (let i = 0; i < out.length; i++) if (equal(out[i], el)) {
dup = true;
break;
}
if (!dup) out.push(el);
}
return out;
}
const by = strat.by;
const keyFn = typeof by === "function" ? by : (x) => x == null ? void 0 : x[by];
const out = base.slice();
const indexByKey = /* @__PURE__ */ new Map();
for (let i = 0; i < out.length; i++) indexByKey.set(keyFn(out[i]), i);
for (const el of overlay) {
const k = keyFn(el);
const at = indexByKey.get(k);
if (at !== void 0) out[at] = merge_pair(out[at], el, path.concat(out[at]?.length ?? at), ctx, states);
else {
indexByKey.set(k, out.length);
out.push(el);
}
}
return out;
}
function child_states(ctx, states, key) {
if (ctx.atEntries.length === 0) return states;
const next = new Array(ctx.atEntries.length);
for (let i = 0; i < ctx.atEntries.length; i++) next[i] = ctx.atEntries[i].matcher.step(states[i], key);
return next;
}
function merge_pair(base, overlay, path, ctx, states) {
if (overlay === void 0) return base;
const ot = type_tag(overlay);
const bt = type_tag(base);
if (!mergeable(ot) || !mergeable(bt) || ot !== bt) return overlay;
if (ctx.seen.has(overlay)) return overlay;
ctx.seen.add(overlay);
let result;
if (ot === "array") {
result = merge_arrays(base, overlay, resolve_strategy(ctx, states), path, ctx, child_states(ctx, states, 0));
if (ctx.mutate) {
base.length = 0;
for (let i = 0; i < result.length; i++) base.push(result[i]);
result = base;
}
} else if (ot === "map") {
const out = ctx.mutate ? base : new Map(base);
let changed = ctx.mutate;
for (const [k, ov] of overlay) {
const cs = child_states(ctx, states, k);
if (out.has(k)) {
const merged = merge_pair(out.get(k), ov, path.concat(k), ctx, cs);
if (merged !== out.get(k)) changed = true;
out.set(k, merged);
} else {
out.set(k, ov);
changed = true;
}
}
result = changed ? out : base;
} else {
const okeys = own_keys(overlay, ctx.symbols);
const out = ctx.mutate ? base : shallow_shell(base, ctx.symbols);
let changed = ctx.mutate;
for (let i = 0; i < okeys.length; i++) {
const k = okeys[i];
const ov = overlay[k];
const cs = child_states(ctx, states, k);
if (has_own.call(base, k)) {
const merged = merge_pair(base[k], ov, path.concat(k), ctx, cs);
if (merged !== base[k]) changed = true;
safe_set(out, k, merged);
} else {
safe_set(out, k, ov);
changed = true;
}
}
result = changed ? out : base;
}
ctx.seen.delete(overlay);
return result;
}
function merge(base, overlay, options = {}) {
const atEntries = options.at ? Object.keys(options.at).map((pat) => ({
matcher: compile_pattern(pat),
strategy: options.at[pat]
})) : [];
return merge_pair(base, overlay, [], {
defaultArrays: options.arrays ?? "replace",
atEntries,
symbols: !!options.symbols,
mutate: !!options.mutate,
seen: /* @__PURE__ */ new WeakSet()
}, atEntries.map((e) => e.matcher.initial));
}
//#endregion
//#region packages/neotraverse/src/safe/diff.ts
function pointer(path) {
let out = "";
for (let i = 0; i < path.length; i++) {
let s = String(path[i]);
if (s.indexOf("~") !== -1 || s.indexOf("/") !== -1) s = s.replace(/~/g, "~0").replace(/\//g, "~1");
out += "/" + s;
}
return out;
}
const ATOMIC = new Set([
"map",
"set",
"weakmap",
"weakset",
"date",
"regexp",
"error",
"typed-array",
"arraybuffer",
"dataview",
"function"
]);
function assert_acyclic(value, seen) {
if (typeof value !== "object" || value === null) return;
if (seen.has(value)) throw new TypeError("neotraverse: diff does not support cyclic inputs");
seen.add(value);
if (Array.isArray(value)) for (let i = 0; i < value.length; i++) assert_acyclic(value[i], seen);
else if (value instanceof Map) for (const v of value.values()) assert_acyclic(v, seen);
else if (value instanceof Set) for (const v of value) assert_acyclic(v, seen);
else for (const k of Object.keys(value)) assert_acyclic(value[k], seen);
seen.delete(value);
}
function diff_pair(a, b, path, ops, stack, maxDepth, depth) {
if (a === b) return;
assert_depth(depth, maxDepth);
const ta = type_tag(a);
if (ta !== type_tag(b) || ta === "primitive" || ta === "null") {
assert_acyclic(a, /* @__PURE__ */ new Set());
assert_acyclic(b, /* @__PURE__ */ new Set());
ops.push({
op: "replace",
path: pointer(path),
value: clone(b)
});
return;
}
const tracked = typeof a === "object" && a !=