* "innerDeepFreeze()" acts like "Object.freeze()", except that: * * To deepFreeze an object is to freeze it and all objects transitively * reachable from it via transitive reflective property and prototype * traversal.
(node)
| 421 | * traversal. |
| 422 | */ |
| 423 | function innerDeepFreeze(node) { |
| 424 | // Objects that we have frozen in this round. |
| 425 | const freezingSet = new SafeSet(); |
| 426 | |
| 427 | // If val is something we should be freezing but aren't yet, |
| 428 | // add it to freezingSet. |
| 429 | function enqueue(val) { |
| 430 | if (Object(val) !== val) { |
| 431 | // ignore primitives |
| 432 | return; |
| 433 | } |
| 434 | const type = typeof val; |
| 435 | if (type !== 'object' && type !== 'function') { |
| 436 | // NB: handle for any new cases in future |
| 437 | } |
| 438 | if (frozenSet.has(val) || freezingSet.has(val)) { |
| 439 | // TODO: Use uncurried form |
| 440 | // Ignore if already frozen or freezing |
| 441 | return; |
| 442 | } |
| 443 | freezingSet.add(val); // TODO: Use uncurried form |
| 444 | } |
| 445 | |
| 446 | function doFreeze(obj) { |
| 447 | // Immediately freeze the object to ensure reactive |
| 448 | // objects such as proxies won't add properties |
| 449 | // during traversal, before they get frozen. |
| 450 | |
| 451 | // Object are verified before being enqueued, |
| 452 | // therefore this is a valid candidate. |
| 453 | // Throws if this fails (strict mode). |
| 454 | ObjectFreeze(obj); |
| 455 | |
| 456 | // We rely upon certain commitments of Object.freeze and proxies here |
| 457 | |
| 458 | // Get stable/immutable outbound links before a Proxy has a chance to do |
| 459 | // something sneaky. |
| 460 | const proto = ObjectGetPrototypeOf(obj); |
| 461 | const descs = ObjectGetOwnPropertyDescriptors(obj); |
| 462 | enqueue(proto); |
| 463 | ArrayPrototypeForEach(ReflectOwnKeys(descs), (name) => { |
| 464 | const desc = descs[name]; |
| 465 | if (ObjectPrototypeHasOwnProperty(desc, 'value')) { |
| 466 | // todo uncurried form |
| 467 | enqueue(desc.value); |
| 468 | } else { |
| 469 | enqueue(desc.get); |
| 470 | enqueue(desc.set); |
| 471 | } |
| 472 | }); |
| 473 | } |
| 474 | |
| 475 | function dequeue() { |
| 476 | // New values added before forEach() has finished will be visited. |
| 477 | freezingSet.forEach(doFreeze); // TODO: Curried forEach |
| 478 | } |
| 479 | |
| 480 | function commit() { |
no test coverage detected