|
|
@ -1,4 +1,4 @@
|
|
|
|
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */
|
|
|
|
/** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, Reaction, TemplateNode, TransitionManager } from '#client' */
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
check_dirtiness,
|
|
|
|
check_dirtiness,
|
|
|
|
active_effect,
|
|
|
|
active_effect,
|
|
|
@ -32,7 +32,10 @@ import {
|
|
|
|
HEAD_EFFECT,
|
|
|
|
HEAD_EFFECT,
|
|
|
|
MAYBE_DIRTY,
|
|
|
|
MAYBE_DIRTY,
|
|
|
|
EFFECT_HAS_DERIVED,
|
|
|
|
EFFECT_HAS_DERIVED,
|
|
|
|
BOUNDARY_EFFECT
|
|
|
|
BOUNDARY_EFFECT,
|
|
|
|
|
|
|
|
EFFECT_IS_UPDATING,
|
|
|
|
|
|
|
|
DISCONNECTED,
|
|
|
|
|
|
|
|
LEGACY_DERIVED_PROP
|
|
|
|
} from '#client/constants';
|
|
|
|
} from '#client/constants';
|
|
|
|
import { set } from './sources.js';
|
|
|
|
import { set } from './sources.js';
|
|
|
|
import * as e from '../errors.js';
|
|
|
|
import * as e from '../errors.js';
|
|
|
@ -41,6 +44,372 @@ import { define_property } from '../../shared/utils.js';
|
|
|
|
import { get_next_sibling } from '../dom/operations.js';
|
|
|
|
import { get_next_sibling } from '../dom/operations.js';
|
|
|
|
import { derived } from './deriveds.js';
|
|
|
|
import { derived } from './deriveds.js';
|
|
|
|
import { component_context, dev_current_component_function } from '../context.js';
|
|
|
|
import { component_context, dev_current_component_function } from '../context.js';
|
|
|
|
|
|
|
|
import { FILENAME } from '../../../constants.js';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Get human-readable information about an effect for debugging
|
|
|
|
|
|
|
|
* @param {Effect | null} effect
|
|
|
|
|
|
|
|
* @returns {{
|
|
|
|
|
|
|
|
* type: string,
|
|
|
|
|
|
|
|
* typeFlags: string,
|
|
|
|
|
|
|
|
* typeNumeric: number,
|
|
|
|
|
|
|
|
* typeBinary: string,
|
|
|
|
|
|
|
|
* status: string,
|
|
|
|
|
|
|
|
* parent: string,
|
|
|
|
|
|
|
|
* parentChain: string,
|
|
|
|
|
|
|
|
* component: string,
|
|
|
|
|
|
|
|
* hasChildren: boolean,
|
|
|
|
|
|
|
|
* hasDeps: number,
|
|
|
|
|
|
|
|
* hasNodes: boolean
|
|
|
|
|
|
|
|
* }}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function get_effect_debug_info(effect) {
|
|
|
|
|
|
|
|
if (!effect)
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
type: 'NO_EFFECT',
|
|
|
|
|
|
|
|
typeFlags: '0x0 (0)',
|
|
|
|
|
|
|
|
typeNumeric: 0,
|
|
|
|
|
|
|
|
typeBinary: '00000000',
|
|
|
|
|
|
|
|
status: 'NONE',
|
|
|
|
|
|
|
|
parent: 'NO_PARENT',
|
|
|
|
|
|
|
|
parentChain: 'NONE',
|
|
|
|
|
|
|
|
component: 'NO_COMPONENT',
|
|
|
|
|
|
|
|
hasChildren: false,
|
|
|
|
|
|
|
|
hasDeps: 0,
|
|
|
|
|
|
|
|
hasNodes: false
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const flags = effect.f;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Core effect types
|
|
|
|
|
|
|
|
const effectTypes = [];
|
|
|
|
|
|
|
|
const statusFlags = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Core effect types
|
|
|
|
|
|
|
|
if (flags & DERIVED) effectTypes.push('DERIVED');
|
|
|
|
|
|
|
|
if (flags & EFFECT) effectTypes.push('EFFECT');
|
|
|
|
|
|
|
|
if (flags & RENDER_EFFECT) effectTypes.push('RENDER_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BLOCK_EFFECT) effectTypes.push('BLOCK_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BRANCH_EFFECT) effectTypes.push('BRANCH_EFFECT');
|
|
|
|
|
|
|
|
if (flags & ROOT_EFFECT) effectTypes.push('ROOT_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BOUNDARY_EFFECT) effectTypes.push('BOUNDARY_EFFECT');
|
|
|
|
|
|
|
|
if (flags & INSPECT_EFFECT) effectTypes.push('INSPECT_EFFECT');
|
|
|
|
|
|
|
|
if (flags & HEAD_EFFECT) effectTypes.push('HEAD_EFFECT');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Status flags
|
|
|
|
|
|
|
|
if (flags & UNOWNED) statusFlags.push('UNOWNED');
|
|
|
|
|
|
|
|
if (flags & DISCONNECTED) statusFlags.push('DISCONNECTED');
|
|
|
|
|
|
|
|
if (flags & CLEAN) statusFlags.push('CLEAN');
|
|
|
|
|
|
|
|
if (flags & DIRTY) statusFlags.push('DIRTY');
|
|
|
|
|
|
|
|
if (flags & MAYBE_DIRTY) statusFlags.push('MAYBE_DIRTY');
|
|
|
|
|
|
|
|
if (flags & INERT) statusFlags.push('INERT');
|
|
|
|
|
|
|
|
if (flags & DESTROYED) statusFlags.push('DESTROYED');
|
|
|
|
|
|
|
|
if (flags & EFFECT_RAN) statusFlags.push('EFFECT_RAN');
|
|
|
|
|
|
|
|
if (flags & EFFECT_TRANSPARENT) statusFlags.push('EFFECT_TRANSPARENT');
|
|
|
|
|
|
|
|
if (flags & LEGACY_DERIVED_PROP) statusFlags.push('LEGACY_DERIVED_PROP');
|
|
|
|
|
|
|
|
if (flags & EFFECT_HAS_DERIVED) statusFlags.push('EFFECT_HAS_DERIVED');
|
|
|
|
|
|
|
|
if (flags & EFFECT_IS_UPDATING) statusFlags.push('EFFECT_IS_UPDATING');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Build parent chain
|
|
|
|
|
|
|
|
const parentChain = [];
|
|
|
|
|
|
|
|
let current = effect.parent;
|
|
|
|
|
|
|
|
let depth = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (current && depth < 5) {
|
|
|
|
|
|
|
|
// Limit depth to prevent infinite loops
|
|
|
|
|
|
|
|
const parentTypes = [];
|
|
|
|
|
|
|
|
const parentFlags = current.f;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parentFlags & DERIVED) parentTypes.push('DERIVED');
|
|
|
|
|
|
|
|
if (parentFlags & EFFECT) parentTypes.push('EFFECT');
|
|
|
|
|
|
|
|
if (parentFlags & RENDER_EFFECT) parentTypes.push('RENDER');
|
|
|
|
|
|
|
|
if (parentFlags & BLOCK_EFFECT) parentTypes.push('BLOCK');
|
|
|
|
|
|
|
|
if (parentFlags & BRANCH_EFFECT) parentTypes.push('BRANCH');
|
|
|
|
|
|
|
|
if (parentFlags & ROOT_EFFECT) parentTypes.push('ROOT');
|
|
|
|
|
|
|
|
if (parentFlags & BOUNDARY_EFFECT) parentTypes.push('BOUNDARY');
|
|
|
|
|
|
|
|
if (parentFlags & INSPECT_EFFECT) parentTypes.push('INSPECT');
|
|
|
|
|
|
|
|
if (parentFlags & HEAD_EFFECT) parentTypes.push('HEAD');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parentChain.push(parentTypes.length > 0 ? parentTypes.join('+') : 'UNKNOWN');
|
|
|
|
|
|
|
|
current = current.parent;
|
|
|
|
|
|
|
|
depth++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
type: effectTypes.length > 0 ? effectTypes.join(' + ') : 'UNKNOWN',
|
|
|
|
|
|
|
|
typeFlags: `0x${flags.toString(16)} (${flags})`,
|
|
|
|
|
|
|
|
typeNumeric: flags,
|
|
|
|
|
|
|
|
typeBinary: flags.toString(2).padStart(8, '0'),
|
|
|
|
|
|
|
|
status: statusFlags.join(' + ') || 'NONE',
|
|
|
|
|
|
|
|
parent: effect.parent ? 'HAS_PARENT' : 'NO_PARENT',
|
|
|
|
|
|
|
|
parentChain: parentChain.length > 0 ? parentChain.join(' → ') : 'NO_PARENTS',
|
|
|
|
|
|
|
|
component: effect.component_function?.name || 'NO_COMPONENT',
|
|
|
|
|
|
|
|
hasChildren: !!effect.first,
|
|
|
|
|
|
|
|
hasDeps: effect.deps ? effect.deps.length : 0,
|
|
|
|
|
|
|
|
hasNodes: !!effect.nodes_start
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Decode reaction/effect flags (the 'f' property) into human-readable format
|
|
|
|
|
|
|
|
* The 'f' property contains bitwise flags that represent:
|
|
|
|
|
|
|
|
* - Type of effect (RENDER_EFFECT, BRANCH_EFFECT, etc.)
|
|
|
|
|
|
|
|
* - Status flags (DIRTY, CLEAN, MAYBE_DIRTY, etc.)
|
|
|
|
|
|
|
|
* - Behavior flags (UNOWNED, INERT, etc.)
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param {number} flags - The flags value (reaction.f or effect.f)
|
|
|
|
|
|
|
|
* @returns {{
|
|
|
|
|
|
|
|
* numeric: number,
|
|
|
|
|
|
|
|
* hex: string,
|
|
|
|
|
|
|
|
* binary: string,
|
|
|
|
|
|
|
|
* types: string[],
|
|
|
|
|
|
|
|
* status: string[],
|
|
|
|
|
|
|
|
* behavior: string[],
|
|
|
|
|
|
|
|
* all: string[],
|
|
|
|
|
|
|
|
* summary: string
|
|
|
|
|
|
|
|
* }}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function decode_reaction_flags(flags) {
|
|
|
|
|
|
|
|
const types = [];
|
|
|
|
|
|
|
|
const status = [];
|
|
|
|
|
|
|
|
const behavior = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Core effect/reaction types
|
|
|
|
|
|
|
|
if (flags & DERIVED) types.push('DERIVED');
|
|
|
|
|
|
|
|
if (flags & EFFECT) types.push('EFFECT');
|
|
|
|
|
|
|
|
if (flags & RENDER_EFFECT) types.push('RENDER_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BLOCK_EFFECT) types.push('BLOCK_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BRANCH_EFFECT) types.push('BRANCH_EFFECT');
|
|
|
|
|
|
|
|
if (flags & ROOT_EFFECT) types.push('ROOT_EFFECT');
|
|
|
|
|
|
|
|
if (flags & BOUNDARY_EFFECT) types.push('BOUNDARY_EFFECT');
|
|
|
|
|
|
|
|
if (flags & INSPECT_EFFECT) types.push('INSPECT_EFFECT');
|
|
|
|
|
|
|
|
if (flags & HEAD_EFFECT) types.push('HEAD_EFFECT');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Status flags (mutually exclusive in some cases)
|
|
|
|
|
|
|
|
if (flags & CLEAN) status.push('CLEAN');
|
|
|
|
|
|
|
|
if (flags & DIRTY) status.push('DIRTY');
|
|
|
|
|
|
|
|
if (flags & MAYBE_DIRTY) status.push('MAYBE_DIRTY');
|
|
|
|
|
|
|
|
if (flags & DESTROYED) status.push('DESTROYED');
|
|
|
|
|
|
|
|
if (flags & EFFECT_RAN) status.push('EFFECT_RAN');
|
|
|
|
|
|
|
|
if (flags & EFFECT_IS_UPDATING) status.push('EFFECT_IS_UPDATING');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Behavior flags
|
|
|
|
|
|
|
|
if (flags & UNOWNED) behavior.push('UNOWNED');
|
|
|
|
|
|
|
|
if (flags & DISCONNECTED) behavior.push('DISCONNECTED');
|
|
|
|
|
|
|
|
if (flags & INERT) behavior.push('INERT');
|
|
|
|
|
|
|
|
if (flags & EFFECT_TRANSPARENT) behavior.push('EFFECT_TRANSPARENT');
|
|
|
|
|
|
|
|
if (flags & LEGACY_DERIVED_PROP) behavior.push('LEGACY_DERIVED_PROP');
|
|
|
|
|
|
|
|
if (flags & EFFECT_HAS_DERIVED) behavior.push('EFFECT_HAS_DERIVED');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const all = [...types, ...status, ...behavior];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
numeric: flags,
|
|
|
|
|
|
|
|
hex: `0x${flags.toString(16).toUpperCase()}`,
|
|
|
|
|
|
|
|
binary: flags.toString(2).padStart(24, '0'), // 24 bits for better readability
|
|
|
|
|
|
|
|
types,
|
|
|
|
|
|
|
|
status,
|
|
|
|
|
|
|
|
behavior,
|
|
|
|
|
|
|
|
all,
|
|
|
|
|
|
|
|
summary: all.length > 0 ? all.join(' + ') : 'NO_FLAGS'
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Log the operation being performed on reaction flags for debugging
|
|
|
|
|
|
|
|
* Usage: log_flag_operation(reaction, 'f ^= EFFECT_IS_UPDATING', EFFECT_IS_UPDATING)
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param {any} reaction - The reaction/effect object
|
|
|
|
|
|
|
|
* @param {string} operation - Description of the operation (e.g., 'f ^= EFFECT_IS_UPDATING')
|
|
|
|
|
|
|
|
* @param {number} flagValue - The flag value being operated on
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function log_flag_operation(reaction, operation, flagValue) {
|
|
|
|
|
|
|
|
if (!DEV) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const beforeFlags = decode_reaction_flags(reaction.f);
|
|
|
|
|
|
|
|
const operationFlag = decode_reaction_flags(flagValue);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create flags string with format "FLAG_NAME (number) + FLAG_NAME (number)"
|
|
|
|
|
|
|
|
const flagsString =
|
|
|
|
|
|
|
|
beforeFlags.all
|
|
|
|
|
|
|
|
.map((flag) => {
|
|
|
|
|
|
|
|
const flagNumeric = getFlagNumericValue(flag);
|
|
|
|
|
|
|
|
return `${flag} (${flagNumeric})`;
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.join(' + ') || 'NO_FLAGS (0)';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create operation description
|
|
|
|
|
|
|
|
const operationType = operation.includes('^=')
|
|
|
|
|
|
|
|
? 'toggle flag'
|
|
|
|
|
|
|
|
: operation.includes('|=')
|
|
|
|
|
|
|
|
? 'add flag'
|
|
|
|
|
|
|
|
: operation.includes('&=')
|
|
|
|
|
|
|
|
? 'remove flag'
|
|
|
|
|
|
|
|
: 'set flag';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.debug(`Flag operation: ${operation}`, {
|
|
|
|
|
|
|
|
flags: flagsString,
|
|
|
|
|
|
|
|
operation: `(${operation}) ${operationType}`,
|
|
|
|
|
|
|
|
operationFlag: `${operationFlag.summary} (${flagValue})`
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Helper to get numeric value for a flag name
|
|
|
|
|
|
|
|
* @param {string} flagName
|
|
|
|
|
|
|
|
* @returns {number}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
function getFlagNumericValue(flagName) {
|
|
|
|
|
|
|
|
const flagMap = /** @type {Record<string, number>} */ ({
|
|
|
|
|
|
|
|
DERIVED: DERIVED,
|
|
|
|
|
|
|
|
EFFECT: EFFECT,
|
|
|
|
|
|
|
|
RENDER_EFFECT: RENDER_EFFECT,
|
|
|
|
|
|
|
|
BLOCK_EFFECT: BLOCK_EFFECT,
|
|
|
|
|
|
|
|
BRANCH_EFFECT: BRANCH_EFFECT,
|
|
|
|
|
|
|
|
ROOT_EFFECT: ROOT_EFFECT,
|
|
|
|
|
|
|
|
BOUNDARY_EFFECT: BOUNDARY_EFFECT,
|
|
|
|
|
|
|
|
INSPECT_EFFECT: INSPECT_EFFECT,
|
|
|
|
|
|
|
|
HEAD_EFFECT: HEAD_EFFECT,
|
|
|
|
|
|
|
|
CLEAN: CLEAN,
|
|
|
|
|
|
|
|
DIRTY: DIRTY,
|
|
|
|
|
|
|
|
MAYBE_DIRTY: MAYBE_DIRTY,
|
|
|
|
|
|
|
|
DESTROYED: DESTROYED,
|
|
|
|
|
|
|
|
EFFECT_RAN: EFFECT_RAN,
|
|
|
|
|
|
|
|
EFFECT_IS_UPDATING: EFFECT_IS_UPDATING,
|
|
|
|
|
|
|
|
UNOWNED: UNOWNED,
|
|
|
|
|
|
|
|
DISCONNECTED: DISCONNECTED,
|
|
|
|
|
|
|
|
INERT: INERT,
|
|
|
|
|
|
|
|
EFFECT_TRANSPARENT: EFFECT_TRANSPARENT,
|
|
|
|
|
|
|
|
LEGACY_DERIVED_PROP: LEGACY_DERIVED_PROP,
|
|
|
|
|
|
|
|
EFFECT_HAS_DERIVED: EFFECT_HAS_DERIVED
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
return flagMap[flagName] || 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Log effect processing information in a simplified format
|
|
|
|
|
|
|
|
* @param {Effect} effect - The effect being processed
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function get_effect_info(effect) {
|
|
|
|
|
|
|
|
if (!DEV) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const flags = effect.f;
|
|
|
|
|
|
|
|
const effectInfo = decode_reaction_flags(flags);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
effectType: effectInfo.summary,
|
|
|
|
|
|
|
|
component: effect.component_function?.[FILENAME] || 'NO_COMPONENT',
|
|
|
|
|
|
|
|
effect: effect
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Build a tree representation of effects starting from a root effect
|
|
|
|
|
|
|
|
* @param {Effect} root - The root effect to start traversal from
|
|
|
|
|
|
|
|
* @returns {{effectType: string, component: string, effect: Effect, children: any[]} | null} Tree representation
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function get_effect_tree(root) {
|
|
|
|
|
|
|
|
if (!root) return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const map = new Map();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create root object
|
|
|
|
|
|
|
|
const rootObj = {
|
|
|
|
|
|
|
|
effectType: decode_reaction_flags(root.f).summary,
|
|
|
|
|
|
|
|
component: root.component_function?.[FILENAME] || 'NO_COMPONENT',
|
|
|
|
|
|
|
|
effect: root,
|
|
|
|
|
|
|
|
children: []
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
map.set(root, rootObj);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start traversal from root's first child
|
|
|
|
|
|
|
|
let effect = root.first;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (effect != null) {
|
|
|
|
|
|
|
|
// Create object for current effect
|
|
|
|
|
|
|
|
const effectObj = {
|
|
|
|
|
|
|
|
effectType: decode_reaction_flags(effect.f).summary,
|
|
|
|
|
|
|
|
component: effect.component_function?.[FILENAME] || 'NO_COMPONENT',
|
|
|
|
|
|
|
|
effect: effect,
|
|
|
|
|
|
|
|
children: []
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
map.set(effect, effectObj);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add to parent's children array
|
|
|
|
|
|
|
|
if (effect.parent && map.has(effect.parent)) {
|
|
|
|
|
|
|
|
const parentObj = map.get(effect.parent);
|
|
|
|
|
|
|
|
parentObj.children.push(effectObj);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Navigate to children first (depth-first traversal)
|
|
|
|
|
|
|
|
const child = effect.first;
|
|
|
|
|
|
|
|
if (child !== null) {
|
|
|
|
|
|
|
|
effect = child;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Then navigate to siblings
|
|
|
|
|
|
|
|
let parent = effect.parent;
|
|
|
|
|
|
|
|
effect = effect.next;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If no sibling, go up to parent and try its sibling
|
|
|
|
|
|
|
|
while (effect === null && parent !== null) {
|
|
|
|
|
|
|
|
effect = parent.next;
|
|
|
|
|
|
|
|
parent = parent.parent;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return rootObj;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Get all parent effects of a given effect in an array
|
|
|
|
|
|
|
|
* @param {Effect} effect - The effect to get parents for
|
|
|
|
|
|
|
|
* @returns {Array<{effectType: string, component: string, effect: Effect}>} Array of parent effects
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function get_effect_parents(effect) {
|
|
|
|
|
|
|
|
if (!effect) return [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const parents = [];
|
|
|
|
|
|
|
|
let current = effect.parent;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (current != null) {
|
|
|
|
|
|
|
|
const parentObj = {
|
|
|
|
|
|
|
|
effectType: decode_reaction_flags(current.f).summary,
|
|
|
|
|
|
|
|
component: current.component_function?.[FILENAME] || 'NO_COMPONENT',
|
|
|
|
|
|
|
|
effect: current
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
parents.push(parentObj);
|
|
|
|
|
|
|
|
current = current.parent;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return parents;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Comprehensive effect debugging information combining all logging utilities
|
|
|
|
|
|
|
|
* @param {Effect} effect - The effect to get debugging info for
|
|
|
|
|
|
|
|
* @returns {{
|
|
|
|
|
|
|
|
* info: {effectType: string, component: string, effect: Effect} | null,
|
|
|
|
|
|
|
|
* tree: {effectType: string, component: string, effect: Effect, children: any[]} | null,
|
|
|
|
|
|
|
|
* parents: Array<{effectType: string, component: string, effect: Effect}>
|
|
|
|
|
|
|
|
* }} Combined debugging information
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function get_comprehensive_effect_info(effect) {
|
|
|
|
|
|
|
|
if (!DEV || !effect) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
info: null,
|
|
|
|
|
|
|
|
tree: null,
|
|
|
|
|
|
|
|
parents: []
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
info: get_effect_info(effect) || null,
|
|
|
|
|
|
|
|
tree: get_effect_tree(effect),
|
|
|
|
|
|
|
|
parents: get_effect_parents(effect)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
|
|
|
|
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
|
|
|
@ -109,6 +478,12 @@ function create_effect(type, fn, sync, push = true) {
|
|
|
|
wv: 0
|
|
|
|
wv: 0
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (DEV) {
|
|
|
|
|
|
|
|
// if (effect.component_function?.[FILENAME].includes('NestedComponent')) {
|
|
|
|
|
|
|
|
// console.debug('create_effect', get_comprehensive_effect_info(effect));
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (DEV) {
|
|
|
|
if (DEV) {
|
|
|
|
effect.component_function = dev_current_component_function;
|
|
|
|
effect.component_function = dev_current_component_function;
|
|
|
|
}
|
|
|
|
}
|
|
|
|