(u: unknown, isLeaf: (u: unknown) => boolean)
| 4191 | } |
| 4192 | |
| 4193 | function isTree(u: unknown, isLeaf: (u: unknown) => boolean): boolean { |
| 4194 | const cache = new WeakMap<object, boolean>() |
| 4195 | const stack: Array<TreeFrame> = [] |
| 4196 | outer: while (true) { |
| 4197 | if (typeof u !== "object" || u === null) { |
| 4198 | if (!isLeaf(u)) { |
| 4199 | return false |
| 4200 | } |
| 4201 | } else { |
| 4202 | const value = u |
| 4203 | const cached = cache.get(value) |
| 4204 | // `false` marks a node on the current path, while `true` marks a fully |
| 4205 | // validated node that can be safely reused by a DAG. |
| 4206 | if (cached === false) { |
| 4207 | return false |
| 4208 | } |
| 4209 | if (cached === undefined) { |
| 4210 | const isArray = Array.isArray(value) |
| 4211 | if (!isArray) { |
| 4212 | const prototype = Object.getPrototypeOf(value) |
| 4213 | // A plain object from another realm has a different Object.prototype, |
| 4214 | // but that prototype still has a null prototype. |
| 4215 | if ( |
| 4216 | prototype !== null && |
| 4217 | prototype !== Object.prototype && |
| 4218 | Object.getPrototypeOf(prototype) !== null |
| 4219 | ) { |
| 4220 | return false |
| 4221 | } |
| 4222 | } |
| 4223 | cache.set(value, false) |
| 4224 | stack.push({ |
| 4225 | value, |
| 4226 | keys: isArray ? value.length : Object.keys(value), |
| 4227 | index: 0 |
| 4228 | }) |
| 4229 | } |
| 4230 | } |
| 4231 | |
| 4232 | while (stack.length > 0) { |
| 4233 | const frame = stack[stack.length - 1] |
| 4234 | const keys = frame.keys |
| 4235 | if (typeof keys === "number") { |
| 4236 | if (frame.index < keys) { |
| 4237 | // A sparse slot is read as `undefined`; the leaf predicate determines |
| 4238 | // whether that is valid for the current tree. |
| 4239 | u = (frame.value as ReadonlyArray<unknown>)[frame.index++] |
| 4240 | continue outer |
| 4241 | } |
| 4242 | } else if (frame.index < keys.length) { |
| 4243 | u = (frame.value as Record<string, unknown>)[keys[frame.index++]] |
| 4244 | continue outer |
| 4245 | } |
| 4246 | cache.set(frame.value, true) |
| 4247 | stack.pop() |
| 4248 | } |
| 4249 | return true |
| 4250 | } |
no test coverage detected