UNPKG

svelte

Version:

Cybernetically enhanced web apps

180 lines (151 loc) 4.45 kB
/** @import { Derived, Reaction, Signal, Value } from '#client' */ import { UNINITIALIZED } from '../../../constants.js'; import { snapshot } from '../../shared/clone.js'; import { define_property } from '../../shared/utils.js'; import { DERIVED, STATE_SYMBOL } from '../constants.js'; import { effect_tracking } from '../reactivity/effects.js'; import { active_reaction, captured_signals, set_captured_signals, untrack } from '../runtime.js'; /** @type { any } */ export let tracing_expressions = null; /** * @param { Value } signal * @param { { read: Error[] } } [entry] */ function log_entry(signal, entry) { const debug = signal.debug; const value = signal.trace_need_increase ? signal.trace_v : signal.v; if (value === UNINITIALIZED) { return; } if (debug) { var previous_captured_signals = captured_signals; var captured = new Set(); set_captured_signals(captured); try { untrack(() => { debug(); }); } finally { set_captured_signals(previous_captured_signals); } if (captured.size > 0) { for (const dep of captured) { log_entry(dep); } return; } } const type = (signal.f & DERIVED) !== 0 ? '$derived' : '$state'; const current_reaction = /** @type {Reaction} */ (active_reaction); const dirty = signal.wv > current_reaction.wv || current_reaction.wv === 0; // eslint-disable-next-line no-console console.groupCollapsed( `%c${type}`, dirty ? 'color: CornflowerBlue; font-weight: bold' : 'color: grey; font-weight: bold', typeof value === 'object' && value !== null && STATE_SYMBOL in value ? snapshot(value, true) : value ); if (type === '$derived') { const deps = new Set(/** @type {Derived} */ (signal).deps); for (const dep of deps) { log_entry(dep); } } if (signal.created) { // eslint-disable-next-line no-console console.log(signal.created); } if (signal.updated) { // eslint-disable-next-line no-console console.log(signal.updated); } const read = entry?.read; if (read && read.length > 0) { for (var stack of read) { // eslint-disable-next-line no-console console.log(stack); } } // eslint-disable-next-line no-console console.groupEnd(); } /** * @template T * @param {() => string} label * @param {() => T} fn */ export function trace(label, fn) { var previously_tracing_expressions = tracing_expressions; try { tracing_expressions = { entries: new Map(), reaction: active_reaction }; var start = performance.now(); var value = fn(); var time = (performance.now() - start).toFixed(2); if (!effect_tracking()) { // eslint-disable-next-line no-console console.log(`${label()} %cran outside of an effect (${time}ms)`, 'color: grey'); } else if (tracing_expressions.entries.size === 0) { // eslint-disable-next-line no-console console.log(`${label()} %cno reactive dependencies (${time}ms)`, 'color: grey'); } else { // eslint-disable-next-line no-console console.group(`${label()} %c(${time}ms)`, 'color: grey'); var entries = tracing_expressions.entries; tracing_expressions = null; for (const [signal, entry] of entries) { log_entry(signal, entry); } // eslint-disable-next-line no-console console.groupEnd(); } if (previously_tracing_expressions !== null && tracing_expressions !== null) { for (const [signal, entry] of tracing_expressions.entries) { var prev_entry = previously_tracing_expressions.get(signal); if (prev_entry === undefined) { previously_tracing_expressions.set(signal, entry); } else { prev_entry.read.push(...entry.read); } } } return value; } finally { tracing_expressions = previously_tracing_expressions; } } /** * @param {string} label */ export function get_stack(label) { let error = Error(); const stack = error.stack; if (stack) { const lines = stack.split('\n'); const new_lines = ['\n']; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line === 'Error') { continue; } if (line.includes('validate_each_keys')) { return null; } if (line.includes('svelte/src/internal')) { continue; } new_lines.push(line); } if (new_lines.length === 1) { return null; } define_property(error, 'stack', { value: new_lines.join('\n') }); define_property(error, 'name', { // 'Error' suffix is required for stack traces to be rendered properly value: `${label}Error` }); } return error; }