Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 6074x 6074x 6074x 6074x 6074x 6074x 6074x 6074x 6074x 6074x 1x 1x 6074x 6074x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 509x 509x 509x 509x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 428x 44x 44x 44x 44x 44x 44x 44x 44x 36x 36x 42x 8x 8x 8x 44x 44x 44x | /**
* @file reactive.js
* @description Trace hooks for the reactive system.
*
* Two things are recorded here, and the split matters:
*
* - A **write** is a logical mutation: one property, at one path, changing
* from one value to another. It is recorded in the proxy traps, where the
* mutation actually happens, rather than in `trigger()` — `trigger` walks up
* the `parentMap` re-firing itself for every ancestor, so recording there
* would log one write per level of nesting for a single assignment.
*
* - A **watcher wake** is a consequence of a write. It is recorded in
* `trigger()`, inside the write's causal scope, which is what produces
* "cart.items.2.qty changed, and that woke CartItem#3's render".
*
* Placing this in its own module rather than inlining it in `proxyHandler.js`
* keeps `capture` and `recorder` out of the reactive system's import graph
* from the reactive side, so the dependency runs one way only.
* @module lib/core/trace/reactive
*/
import { getPropertyPath } from '../reactive/watcher.js';
import { tracer } from './tracer.js';
import { TraceNodeType } from './schema.js';
/**
* Opens a write node and makes it the causal parent of the reactive work the
* caller is about to trigger.
*
* Callers must guard with `tracer.on` and must pass the returned token to
* `tracer.leave()` in a `finally`.
* @param {object} target - The raw object that was mutated.
* @param {string|symbol} key - The mutated key.
* @param {any} oldValue - The value before the mutation.
* @param {any} newValue - The value after the mutation.
* @param {string} [op] - What kind of mutation this was, when it was not a plain assignment.
* @returns {number} A restore token for `tracer.leave`, or -1 when tracing is off.
*/
export function traceWrite(target, key, oldValue, newValue, op) {
const recorder = tracer.sink;
if (!recorder) {
return -1;
}
const path = getPropertyPath(target, key);
const node = {
path,
from: recorder.capture(oldValue, path),
to: recorder.capture(newValue, path),
};
if (op) {
node.op = op;
}
return tracer.enter(TraceNodeType.WRITE, node);
}
/**
* Opens a write node for a mutation whose before/after values are not a single
* pair — an array method, a `Map.clear()`, a `Set.add()`.
*
* The collection's size is recorded instead of its contents: capturing a whole
* array on every `push` would make tracing a list quadratic.
* @param {object} target - The raw collection.
* @param {string|symbol} key - The method or key that changed.
* @param {string} op - The operation name, e.g. `push` or `clear`.
* @param {number} [size] - The collection's size after the mutation.
* @returns {number} A restore token for `tracer.leave`, or -1 when tracing is off.
*/
export function traceCollectionWrite(target, key, op, size) {
if (!tracer.sink) {
return -1;
}
const path = getPropertyPath(target, typeof key === 'symbol' ? undefined : key);
return tracer.enter(TraceNodeType.WRITE, { path, op, size });
}
/**
* Opens a watcher node for a watcher about to re-run because of a write.
*
* Named watchers carry their own identity (`CartItem#render`, `Resource#users`,
* a computed key); anonymous ones are still worth recording, because the shape
* of the propagation is the answer to "why did this update".
* @param {object} watcher - The `AvenxWatcher` about to run.
* @returns {number} A restore token for `tracer.leave`, or -1 when tracing is off.
*/
export function traceWatcher(watcher) {
if (!tracer.sink) {
return -1;
}
const name = (watcher && watcher.name) || 'anonymous';
const node = { name };
// `Component#render` is the single most common watcher and the one a reader
// most wants to see attributed, so its component is lifted out of the name.
const renderMatch = /^(.+)#render$/.exec(name);
if (renderMatch) {
node.kind = 'render';
node.component = renderMatch[1];
} else if (watcher && watcher.options && watcher.options.isComputed) {
node.kind = 'computed';
} else {
node.kind = watcher && watcher.isEffect ? 'effect' : 'watch';
}
return tracer.enter(TraceNodeType.WATCHER, node);
}
|