UNPKG

@usehall/bot-gate

Version:

React/Vue/Svelte components for conditionally rendering content based on bot detection with IP validation

2,000 lines (1,669 loc) 91.6 kB
'use strict'; var svelte = require('svelte'); var fs = require('fs'); var path = require('path'); var url = require('url'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; // generated during release, do not modify const PUBLIC_VERSION = '5'; if (typeof window !== 'undefined') { // @ts-expect-error ((window.__svelte ??= {}).v ??= new Set()).add(PUBLIC_VERSION); } let legacy_mode_flag = false; let tracing_mode_flag = false; function enable_legacy_mode_flag() { legacy_mode_flag = true; } enable_legacy_mode_flag(); const PROPS_IS_RUNES = 1 << 1; const PROPS_IS_UPDATED = 1 << 2; const PROPS_IS_BINDABLE = 1 << 3; const UNINITIALIZED = Symbol(); // Dev-time component properties const FILENAME = Symbol('filename'); const node_env = globalThis.process?.env?.NODE_ENV; var DEV = node_env && !node_env.toLowerCase().startsWith('prod'); // Store the references to globals in case someone tries to monkey patch these, causing the below // to de-opt (this occurs often when using popular extensions). var is_array = Array.isArray; var index_of = Array.prototype.indexOf; var define_property = Object.defineProperty; var get_descriptor = Object.getOwnPropertyDescriptor; var get_descriptors = Object.getOwnPropertyDescriptors; var object_prototype = Object.prototype; var array_prototype = Array.prototype; var get_prototype_of = Object.getPrototypeOf; /** @param {Function} fn */ function run(fn) { return fn(); } /** @param {Array<() => void>} arr */ function run_all(arr) { for (var i = 0; i < arr.length; i++) { arr[i](); } } const DERIVED = 1 << 1; const EFFECT = 1 << 2; const RENDER_EFFECT = 1 << 3; const BLOCK_EFFECT = 1 << 4; const BRANCH_EFFECT = 1 << 5; const ROOT_EFFECT = 1 << 6; const BOUNDARY_EFFECT = 1 << 7; const UNOWNED = 1 << 8; const DISCONNECTED = 1 << 9; const CLEAN = 1 << 10; const DIRTY = 1 << 11; const MAYBE_DIRTY = 1 << 12; const INERT = 1 << 13; const DESTROYED = 1 << 14; const EFFECT_RAN = 1 << 15; /** 'Transparent' effects do not create a transition boundary */ const EFFECT_TRANSPARENT = 1 << 16; const INSPECT_EFFECT = 1 << 17; const HEAD_EFFECT = 1 << 18; const EFFECT_PRESERVED = 1 << 19; const EFFECT_IS_UPDATING = 1 << 20; const STATE_SYMBOL = Symbol('$state'); const LEGACY_PROPS = Symbol('legacy props'); const PROXY_PATH_SYMBOL = Symbol('proxy path'); /** allow users to ignore aborted signal errors if `reason.name === 'StaleReactionError` */ const STALE_REACTION = new (class StaleReactionError extends Error { name = 'StaleReactionError'; message = 'The reaction that called `getAbortSignal()` was re-run or destroyed'; })(); /** @import { Equals } from '#client' */ /** @type {Equals} */ function equals(value) { return value === this.v; } /** * @param {unknown} a * @param {unknown} b * @returns {boolean} */ function safe_not_equal(a, b) { return a != a ? b == b : a !== b || (a !== null && typeof a === 'object') || typeof a === 'function'; } /** @type {Equals} */ function safe_equals(value) { return !safe_not_equal(value, this.v); } /* This file is generated by scripts/process-messages/index.js. Do not edit! */ /** * A derived value cannot reference itself recursively * @returns {never} */ function derived_references_self() { if (DEV) { const error = new Error(`derived_references_self\nA derived value cannot reference itself recursively\nhttps://svelte.dev/e/derived_references_self`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/derived_references_self`); } } /** * `%rune%` cannot be used inside an effect cleanup function * @param {string} rune * @returns {never} */ function effect_in_teardown(rune) { if (DEV) { const error = new Error(`effect_in_teardown\n\`${rune}\` cannot be used inside an effect cleanup function\nhttps://svelte.dev/e/effect_in_teardown`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/effect_in_teardown`); } } /** * Effect cannot be created inside a `$derived` value that was not itself created inside an effect * @returns {never} */ function effect_in_unowned_derived() { if (DEV) { const error = new Error(`effect_in_unowned_derived\nEffect cannot be created inside a \`$derived\` value that was not itself created inside an effect\nhttps://svelte.dev/e/effect_in_unowned_derived`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`); } } /** * `%rune%` can only be used inside an effect (e.g. during component initialisation) * @param {string} rune * @returns {never} */ function effect_orphan(rune) { if (DEV) { const error = new Error(`effect_orphan\n\`${rune}\` can only be used inside an effect (e.g. during component initialisation)\nhttps://svelte.dev/e/effect_orphan`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/effect_orphan`); } } /** * Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops * @returns {never} */ function effect_update_depth_exceeded() { if (DEV) { const error = new Error(`effect_update_depth_exceeded\nMaximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops\nhttps://svelte.dev/e/effect_update_depth_exceeded`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`); } } /** * Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value * @param {string} key * @returns {never} */ function props_invalid_value(key) { if (DEV) { const error = new Error(`props_invalid_value\nCannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value\nhttps://svelte.dev/e/props_invalid_value`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/props_invalid_value`); } } /** * The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files * @param {string} rune * @returns {never} */ function rune_outside_svelte(rune) { if (DEV) { const error = new Error(`rune_outside_svelte\nThe \`${rune}\` rune is only available inside \`.svelte\` and \`.svelte.js/ts\` files\nhttps://svelte.dev/e/rune_outside_svelte`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/rune_outside_svelte`); } } /** * Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`. * @returns {never} */ function state_descriptors_fixed() { if (DEV) { const error = new Error(`state_descriptors_fixed\nProperty descriptors defined on \`$state\` objects must contain \`value\` and always be \`enumerable\`, \`configurable\` and \`writable\`.\nhttps://svelte.dev/e/state_descriptors_fixed`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/state_descriptors_fixed`); } } /** * Cannot set prototype of `$state` object * @returns {never} */ function state_prototype_fixed() { if (DEV) { const error = new Error(`state_prototype_fixed\nCannot set prototype of \`$state\` object\nhttps://svelte.dev/e/state_prototype_fixed`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/state_prototype_fixed`); } } /** * Updating state inside `$derived(...)`, `$inspect(...)` or a template expression is forbidden. If the value should not be reactive, declare it without `$state` * @returns {never} */ function state_unsafe_mutation() { if (DEV) { const error = new Error(`state_unsafe_mutation\nUpdating state inside \`$derived(...)\`, \`$inspect(...)\` or a template expression is forbidden. If the value should not be reactive, declare it without \`$state\`\nhttps://svelte.dev/e/state_unsafe_mutation`); error.name = 'Svelte error'; throw error; } else { throw new Error(`https://svelte.dev/e/state_unsafe_mutation`); } } /** @import { Derived, Reaction, Value } from '#client' */ /** * @param {Value} source * @param {string} label */ function tag(source, label) { source.label = label; tag_proxy(source.v, label); return source; } /** * @param {unknown} value * @param {string} label */ function tag_proxy(value, label) { // @ts-expect-error value?.[PROXY_PATH_SYMBOL]?.(label); return value; } /** @import { ComponentContext, DevStackEntry } from '#client' */ /** @type {ComponentContext | null} */ let component_context = null; /** @param {ComponentContext | null} context */ function set_component_context(context) { component_context = context; } /** @type {DevStackEntry | null} */ let dev_stack = null; /** @param {DevStackEntry | null} stack */ function set_dev_stack(stack) { dev_stack = stack; } /** * The current component function. Different from current component context: * ```html * <!-- App.svelte --> * <Foo> * <Bar /> <!-- context == Foo.svelte, function == App.svelte --> * </Foo> * ``` * @type {ComponentContext['function']} */ let dev_current_component_function = null; /** @param {ComponentContext['function']} fn */ function set_dev_current_component_function(fn) { dev_current_component_function = fn; } /** * @param {Record<string, unknown>} props * @param {any} runes * @param {Function} [fn] * @returns {void} */ function push(props, runes = false, fn) { var ctx = (component_context = { p: component_context, c: null, d: false, e: null, m: false, s: props, x: null, l: null }); if (legacy_mode_flag && !runes) { component_context.l = { s: null, u: null, r1: [], r2: source(false) }; } teardown(() => { /** @type {ComponentContext} */ (ctx).d = true; }); if (DEV) { // component function component_context.function = fn; dev_current_component_function = fn; } } /** * @template {Record<string, any>} T * @param {T} [component] * @returns {T} */ function pop(component) { const context_stack_item = component_context; if (context_stack_item !== null) { const component_effects = context_stack_item.e; if (component_effects !== null) { var previous_effect = active_effect; var previous_reaction = active_reaction; context_stack_item.e = null; try { for (var i = 0; i < component_effects.length; i++) { var component_effect = component_effects[i]; set_active_effect(component_effect.effect); set_active_reaction(component_effect.reaction); effect(component_effect.fn); } } finally { set_active_effect(previous_effect); set_active_reaction(previous_reaction); } } component_context = context_stack_item.p; if (DEV) { dev_current_component_function = context_stack_item.p?.function ?? null; } context_stack_item.m = true; } // Micro-optimization: Don't set .a above to the empty object // so it can be garbage-collected when the return here is unused return /** @type {T} */ ({}); } /** @returns {boolean} */ function is_runes() { return !legacy_mode_flag || (component_context !== null && component_context.l === null); } /** @import { Source } from '#client' */ // TODO move all regexes into shared module? const regex_is_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/; /** * @template T * @param {T} value * @returns {T} */ function proxy(value) { // if non-proxyable, or is already a proxy, return `value` if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { return value; } const prototype = get_prototype_of(value); if (prototype !== object_prototype && prototype !== array_prototype) { return value; } /** @type {Map<any, Source<any>>} */ var sources = new Map(); var is_proxied_array = is_array(value); var version = state(0); var reaction = active_reaction; /** * Executes the proxy in the context of the reaction it was originally created in, if any * @template T * @param {() => T} fn */ var with_parent = (fn) => { var previous_reaction = active_reaction; set_active_reaction(reaction); /** @type {T} */ var result = fn(); set_active_reaction(previous_reaction); return result; }; if (is_proxied_array) { // We need to create the length source eagerly to ensure that // mutations to the array are properly synced with our proxy sources.set('length', state(/** @type {any[]} */ (value).length)); } /** Used in dev for $inspect.trace() */ var path = ''; /** @param {string} new_path */ function update_path(new_path) { path = new_path; tag(version, `${path} version`); // rename all child sources and child proxies for (const [prop, source] of sources) { tag(source, get_label(path, prop)); } } return new Proxy(/** @type {any} */ (value), { defineProperty(_, prop, descriptor) { if ( !('value' in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false ) { // we disallow non-basic descriptors, because unless they are applied to the // target object — which we avoid, so that state can be forked — we will run // afoul of the various invariants // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/getOwnPropertyDescriptor#invariants state_descriptors_fixed(); } var s = sources.get(prop); if (s === undefined) { s = with_parent(() => { var s = state(descriptor.value); sources.set(prop, s); if (DEV && typeof prop === 'string') { tag(s, get_label(path, prop)); } return s; }); } else { set(s, descriptor.value, true); } return true; }, deleteProperty(target, prop) { var s = sources.get(prop); if (s === undefined) { if (prop in target) { const s = with_parent(() => state(UNINITIALIZED)); sources.set(prop, s); update_version(version); if (DEV) { tag(s, get_label(path, prop)); } } } else { // When working with arrays, we need to also ensure we update the length when removing // an indexed property if (is_proxied_array && typeof prop === 'string') { var ls = /** @type {Source<number>} */ (sources.get('length')); var n = Number(prop); if (Number.isInteger(n) && n < ls.v) { set(ls, n); } } set(s, UNINITIALIZED); update_version(version); } return true; }, get(target, prop, receiver) { if (prop === STATE_SYMBOL) { return value; } if (DEV && prop === PROXY_PATH_SYMBOL) { return update_path; } var s = sources.get(prop); var exists = prop in target; // create a source, but only if it's an own property and not a prototype property if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) { s = with_parent(() => { var p = proxy(exists ? target[prop] : UNINITIALIZED); var s = state(p); if (DEV) { tag(s, get_label(path, prop)); } return s; }); sources.set(prop, s); } if (s !== undefined) { var v = get(s); return v === UNINITIALIZED ? undefined : v; } return Reflect.get(target, prop, receiver); }, getOwnPropertyDescriptor(target, prop) { var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); if (descriptor && 'value' in descriptor) { var s = sources.get(prop); if (s) descriptor.value = get(s); } else if (descriptor === undefined) { var source = sources.get(prop); var value = source?.v; if (source !== undefined && value !== UNINITIALIZED) { return { enumerable: true, configurable: true, value, writable: true }; } } return descriptor; }, has(target, prop) { if (prop === STATE_SYMBOL) { return true; } var s = sources.get(prop); var has = (s !== undefined && s.v !== UNINITIALIZED) || Reflect.has(target, prop); if ( s !== undefined || (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { s = with_parent(() => { var p = has ? proxy(target[prop]) : UNINITIALIZED; var s = state(p); if (DEV) { tag(s, get_label(path, prop)); } return s; }); sources.set(prop, s); } var value = get(s); if (value === UNINITIALIZED) { return false; } } return has; }, set(target, prop, value, receiver) { var s = sources.get(prop); var has = prop in target; // variable.length = value -> clear all signals with index >= value if (is_proxied_array && prop === 'length') { for (var i = value; i < /** @type {Source<number>} */ (s).v; i += 1) { var other_s = sources.get(i + ''); if (other_s !== undefined) { set(other_s, UNINITIALIZED); } else if (i in target) { // If the item exists in the original, we need to create a uninitialized source, // else a later read of the property would result in a source being created with // the value of the original item at that index. other_s = with_parent(() => state(UNINITIALIZED)); sources.set(i + '', other_s); if (DEV) { tag(other_s, get_label(path, i)); } } } } // If we haven't yet created a source for this property, we need to ensure // we do so otherwise if we read it later, then the write won't be tracked and // the heuristics of effects will be different vs if we had read the proxied // object property before writing to that property. if (s === undefined) { if (!has || get_descriptor(target, prop)?.writable) { s = with_parent(() => state(undefined)); set(s, proxy(value)); sources.set(prop, s); if (DEV) { tag(s, get_label(path, prop)); } } } else { has = s.v !== UNINITIALIZED; var p = with_parent(() => proxy(value)); set(s, p); } var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); // Set the new value before updating any signals so that any listeners get the new value if (descriptor?.set) { descriptor.set.call(receiver, value); } if (!has) { // If we have mutated an array directly, we might need to // signal that length has also changed. Do it before updating metadata // to ensure that iterating over the array as a result of a metadata update // will not cause the length to be out of sync. if (is_proxied_array && typeof prop === 'string') { var ls = /** @type {Source<number>} */ (sources.get('length')); var n = Number(prop); if (Number.isInteger(n) && n >= ls.v) { set(ls, n + 1); } } update_version(version); } return true; }, ownKeys(target) { get(version); var own_keys = Reflect.ownKeys(target).filter((key) => { var source = sources.get(key); return source === undefined || source.v !== UNINITIALIZED; }); for (var [key, source] of sources) { if (source.v !== UNINITIALIZED && !(key in target)) { own_keys.push(key); } } return own_keys; }, setPrototypeOf() { state_prototype_fixed(); } }); } /** * @param {string} path * @param {string | symbol} prop */ function get_label(path, prop) { if (typeof prop === 'symbol') return `${path}[Symbol(${prop.description ?? ''})]`; if (regex_is_valid_identifier.test(prop)) return `${path}.${prop}`; return /^\d+$/.test(prop) ? `${path}[${prop}]` : `${path}['${prop}']`; } /** * @param {Source<number>} signal * @param {1 | -1} [d] */ function update_version(signal, d = 1) { set(signal, signal.v + d); } /** @import { Derived, Effect } from '#client' */ /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function derived(fn) { var flags = DERIVED | DIRTY; var parent_derived = active_reaction !== null && (active_reaction.f & DERIVED) !== 0 ? /** @type {Derived} */ (active_reaction) : null; if (active_effect === null || (parent_derived !== null && (parent_derived.f & UNOWNED) !== 0)) { flags |= UNOWNED; } else { // Since deriveds are evaluated lazily, any effects created inside them are // created too late to ensure that the parent effect is added to the tree active_effect.f |= EFFECT_PRESERVED; } /** @type {Derived<V>} */ const signal = { ctx: component_context, deps: null, effects: null, equals, f: flags, fn, reactions: null, rv: 0, v: /** @type {V} */ (null), wv: 0, parent: parent_derived ?? active_effect, ac: null }; return signal; } /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function derived_safe_equal(fn) { const signal = derived(fn); signal.equals = safe_equals; return signal; } /** * @param {Derived} derived * @returns {void} */ function destroy_derived_effects(derived) { var effects = derived.effects; if (effects !== null) { derived.effects = null; for (var i = 0; i < effects.length; i += 1) { destroy_effect(/** @type {Effect} */ (effects[i])); } } } /** * The currently updating deriveds, used to detect infinite recursion * in dev mode and provide a nicer error than 'too much recursion' * @type {Derived[]} */ let stack = []; /** * @param {Derived} derived * @returns {Effect | null} */ function get_derived_parent_effect(derived) { var parent = derived.parent; while (parent !== null) { if ((parent.f & DERIVED) === 0) { return /** @type {Effect} */ (parent); } parent = parent.parent; } return null; } /** * @template T * @param {Derived} derived * @returns {T} */ function execute_derived(derived) { var value; var prev_active_effect = active_effect; set_active_effect(get_derived_parent_effect(derived)); if (DEV) { let prev_inspect_effects = inspect_effects; set_inspect_effects(new Set()); try { if (stack.includes(derived)) { derived_references_self(); } stack.push(derived); destroy_derived_effects(derived); value = update_reaction(derived); } finally { set_active_effect(prev_active_effect); set_inspect_effects(prev_inspect_effects); stack.pop(); } } else { try { destroy_derived_effects(derived); value = update_reaction(derived); } finally { set_active_effect(prev_active_effect); } } return value; } /** * @param {Derived} derived * @returns {void} */ function update_derived(derived) { var value = execute_derived(derived); if (!derived.equals(value)) { derived.v = value; derived.wv = increment_write_version(); } // don't mark derived clean if we're reading it inside a // cleanup function, or it will cache a stale value if (is_destroying_effect) return; var status = (skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN; set_signal_status(derived, status); } /** @import { Derived, Effect, Source, Value } from '#client' */ let inspect_effects = new Set(); /** @type {Map<Source, any>} */ const old_values = new Map(); /** * @param {Set<any>} v */ function set_inspect_effects(v) { inspect_effects = v; } /** * @template V * @param {V} v * @param {Error | null} [stack] * @returns {Source<V>} */ // TODO rename this to `state` throughout the codebase function source(v, stack) { /** @type {Value} */ var signal = { f: 0, // TODO ideally we could skip this altogether, but it causes type errors v, reactions: null, equals, rv: 0, wv: 0 }; return signal; } /** * @template V * @param {V} v * @param {Error | null} [stack] */ /*#__NO_SIDE_EFFECTS__*/ function state(v, stack) { const s = source(v); push_reaction_value(s); return s; } /** * @template V * @param {V} initial_value * @param {boolean} [immutable] * @returns {Source<V>} */ /*#__NO_SIDE_EFFECTS__*/ function mutable_source(initial_value, immutable = false, trackable = true) { const s = source(initial_value); if (!immutable) { s.equals = safe_equals; } // bind the signal to the component context, in case we need to // track updates to trigger beforeUpdate/afterUpdate callbacks if (legacy_mode_flag && trackable && component_context !== null && component_context.l !== null) { (component_context.l.s ??= []).push(s); } return s; } /** * @template V * @param {Source<V>} source * @param {V} value * @param {boolean} [should_proxy] * @returns {V} */ function set(source, value, should_proxy = false) { if ( active_reaction !== null && // since we are untracking the function inside `$inspect.with` we need to add this check // to ensure we error if state is set inside an inspect effect (!untracking || (active_reaction.f & INSPECT_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | INSPECT_EFFECT)) !== 0 && !(reaction_sources?.[1].includes(source) && reaction_sources[0] === active_reaction) ) { state_unsafe_mutation(); } let new_value = should_proxy ? proxy(value) : value; if (DEV) { tag_proxy(new_value, /** @type {string} */ (source.label)); } return internal_set(source, new_value); } /** * @template V * @param {Source<V>} source * @param {V} value * @returns {V} */ function internal_set(source, value) { if (!source.equals(value)) { var old_value = source.v; if (is_destroying_effect) { old_values.set(source, value); } else { old_values.set(source, old_value); } source.v = value; if ((source.f & DERIVED) !== 0) { // if we are assigning to a dirty derived we set it to clean/maybe dirty but we also eagerly execute it to track the dependencies if ((source.f & DIRTY) !== 0) { execute_derived(/** @type {Derived} */ (source)); } set_signal_status(source, (source.f & UNOWNED) === 0 ? CLEAN : MAYBE_DIRTY); } source.wv = increment_write_version(); mark_reactions(source, DIRTY); // It's possible that the current reaction might not have up-to-date dependencies // whilst it's actively running. So in the case of ensuring it registers the reaction // properly for itself, we need to ensure the current effect actually gets // scheduled. i.e: `$effect(() => x++)` if ( is_runes() && active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ) { if (untracked_writes === null) { set_untracked_writes([source]); } else { untracked_writes.push(source); } } if (DEV && inspect_effects.size > 0) { const inspects = Array.from(inspect_effects); for (const effect of inspects) { // Mark clean inspect-effects as maybe dirty and then check their dirtiness // instead of just updating the effects - this way we avoid overfiring. if ((effect.f & CLEAN) !== 0) { set_signal_status(effect, MAYBE_DIRTY); } if (check_dirtiness(effect)) { update_effect(effect); } } inspect_effects.clear(); } } return value; } /** * @param {Value} signal * @param {number} status should be DIRTY or MAYBE_DIRTY * @returns {void} */ function mark_reactions(signal, status) { var reactions = signal.reactions; if (reactions === null) return; var runes = is_runes(); var length = reactions.length; for (var i = 0; i < length; i++) { var reaction = reactions[i]; var flags = reaction.f; // Skip any effects that are already dirty if ((flags & DIRTY) !== 0) continue; // In legacy mode, skip the current effect to prevent infinite loops if (!runes && reaction === active_effect) continue; // Inspect effects need to run immediately, so that the stack trace makes sense if (DEV && (flags & INSPECT_EFFECT) !== 0) { inspect_effects.add(reaction); continue; } set_signal_status(reaction, status); // If the signal a) was previously clean or b) is an unowned derived, then mark it if ((flags & (CLEAN | UNOWNED)) !== 0) { if ((flags & DERIVED) !== 0) { mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY); } else { schedule_effect(/** @type {Effect} */ (reaction)); } } } } /** @import { TemplateNode } from '#client' */ /** @type {() => Node | null} */ var first_child_getter; /** @type {() => Node | null} */ var next_sibling_getter; /** * @param {string} value * @returns {Text} */ function create_text(value = '') { return document.createTextNode(value); } /** * @template {Node} N * @param {N} node * @returns {Node | null} */ /*@__NO_SIDE_EFFECTS__*/ function get_first_child(node) { return first_child_getter.call(node); } /** * @template {Node} N * @param {N} node * @returns {Node | null} */ /*@__NO_SIDE_EFFECTS__*/ function get_next_sibling(node) { return next_sibling_getter.call(node); } /** * Don't mark this as side-effect-free, hydration needs to walk all nodes * @param {DocumentFragment | TemplateNode[]} fragment * @param {boolean} is_text * @returns {Node | null} */ function first_child(fragment, is_text) { { // when not hydrating, `fragment` is a `DocumentFragment` (the result of calling `open_frag`) var first = /** @type {DocumentFragment} */ (get_first_child(/** @type {Node} */ (fragment))); // TODO prevent user comments with the empty string when preserveComments is true if (first instanceof Comment && first.data === '') return get_next_sibling(first); return first; } } /** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */ /** * @param {'$effect' | '$effect.pre' | '$inspect'} rune */ function validate_effect(rune) { if (active_effect === null && active_reaction === null) { effect_orphan(rune); } if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0 && active_effect === null) { effect_in_unowned_derived(); } if (is_destroying_effect) { effect_in_teardown(rune); } } /** * @param {Effect} effect * @param {Effect} parent_effect */ function push_effect(effect, parent_effect) { var parent_last = parent_effect.last; if (parent_last === null) { parent_effect.last = parent_effect.first = effect; } else { parent_last.next = effect; effect.prev = parent_last; parent_effect.last = effect; } } /** * @param {number} type * @param {null | (() => void | (() => void))} fn * @param {boolean} sync * @param {boolean} push * @returns {Effect} */ function create_effect(type, fn, sync, push = true) { var parent = active_effect; if (DEV) { // Ensure the parent is never an inspect effect while (parent !== null && (parent.f & INSPECT_EFFECT) !== 0) { parent = parent.parent; } } /** @type {Effect} */ var effect = { ctx: component_context, deps: null, nodes_start: null, nodes_end: null, f: type | DIRTY, first: null, fn, last: null, next: null, parent, b: parent && parent.b, prev: null, teardown: null, transitions: null, wv: 0, ac: null }; if (DEV) { effect.component_function = dev_current_component_function; } if (sync) { try { update_effect(effect); effect.f |= EFFECT_RAN; } catch (e) { destroy_effect(effect); throw e; } } else if (fn !== null) { schedule_effect(effect); } // if an effect has no dependencies, no DOM and no teardown function, // don't bother adding it to the effect tree var inert = sync && effect.deps === null && effect.first === null && effect.nodes_start === null && effect.teardown === null && (effect.f & (EFFECT_PRESERVED | BOUNDARY_EFFECT)) === 0; if (!inert && push) { if (parent !== null) { push_effect(effect, parent); } // if we're in a derived, add the effect there too if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0) { var derived = /** @type {Derived} */ (active_reaction); (derived.effects ??= []).push(effect); } } return effect; } /** * @param {() => void} fn */ function teardown(fn) { const effect = create_effect(RENDER_EFFECT, null, false); set_signal_status(effect, CLEAN); effect.teardown = fn; return effect; } /** * Internal representation of `$effect(...)` * @param {() => void | (() => void)} fn */ function user_effect(fn) { validate_effect('$effect'); // Non-nested `$effect(...)` in a component should be deferred // until the component is mounted var defer = active_effect !== null && (active_effect.f & BRANCH_EFFECT) !== 0 && component_context !== null && !component_context.m; if (DEV) { define_property(fn, 'name', { value: '$effect' }); } if (defer) { var context = /** @type {ComponentContext} */ (component_context); (context.e ??= []).push({ fn, effect: active_effect, reaction: active_reaction }); } else { var signal = effect(fn); return signal; } } /** * Internal representation of `$effect.pre(...)` * @param {() => void | (() => void)} fn * @returns {Effect} */ function user_pre_effect(fn) { validate_effect('$effect.pre'); if (DEV) { define_property(fn, 'name', { value: '$effect.pre' }); } return render_effect(fn); } /** * @param {() => void | (() => void)} fn * @returns {Effect} */ function effect(fn) { return create_effect(EFFECT, fn, false); } /** * Internal representation of `$: ..` * @param {() => any} deps * @param {() => void | (() => void)} fn */ function legacy_pre_effect(deps, fn) { var context = /** @type {ComponentContextLegacy} */ (component_context); /** @type {{ effect: null | Effect, ran: boolean }} */ var token = { effect: null, ran: false }; context.l.r1.push(token); token.effect = render_effect(() => { deps(); // If this legacy pre effect has already run before the end of the reset, then // bail out to emulate the same behavior. if (token.ran) return; token.ran = true; set(context.l.r2, true); untrack(fn); }); } function legacy_pre_effect_reset() { var context = /** @type {ComponentContextLegacy} */ (component_context); render_effect(() => { if (!get(context.l.r2)) return; // Run dirty `$:` statements for (var token of context.l.r1) { var effect = token.effect; // If the effect is CLEAN, then make it MAYBE_DIRTY. This ensures we traverse through // the effects dependencies and correctly ensure each dependency is up-to-date. if ((effect.f & CLEAN) !== 0) { set_signal_status(effect, MAYBE_DIRTY); } if (check_dirtiness(effect)) { update_effect(effect); } token.ran = false; } context.l.r2.v = false; // set directly to avoid rerunning this effect }); } /** * @param {() => void | (() => void)} fn * @returns {Effect} */ function render_effect(fn) { return create_effect(RENDER_EFFECT, fn, true); } /** * @param {(() => void)} fn * @param {number} flags */ function block(fn, flags = 0) { var effect = create_effect(RENDER_EFFECT | BLOCK_EFFECT | flags, fn, true); if (DEV) { effect.dev_stack = dev_stack; } return effect; } /** * @param {(() => void)} fn * @param {boolean} [push] */ function branch(fn, push = true) { return create_effect(RENDER_EFFECT | BRANCH_EFFECT, fn, true, push); } /** * @param {Effect} effect */ function execute_effect_teardown(effect) { var teardown = effect.teardown; if (teardown !== null) { const previously_destroying_effect = is_destroying_effect; const previous_reaction = active_reaction; set_is_destroying_effect(true); set_active_reaction(null); try { teardown.call(null); } finally { set_is_destroying_effect(previously_destroying_effect); set_active_reaction(previous_reaction); } } } /** * @param {Effect} signal * @param {boolean} remove_dom * @returns {void} */ function destroy_effect_children(signal, remove_dom = false) { var effect = signal.first; signal.first = signal.last = null; while (effect !== null) { effect.ac?.abort(STALE_REACTION); var next = effect.next; if ((effect.f & ROOT_EFFECT) !== 0) { // this is now an independent root effect.parent = null; } else { destroy_effect(effect, remove_dom); } effect = next; } } /** * @param {Effect} signal * @returns {void} */ function destroy_block_effect_children(signal) { var effect = signal.first; while (effect !== null) { var next = effect.next; if ((effect.f & BRANCH_EFFECT) === 0) { destroy_effect(effect); } effect = next; } } /** * @param {Effect} effect * @param {boolean} [remove_dom] * @returns {void} */ function destroy_effect(effect, remove_dom = true) { var removed = false; if ( (remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes_start !== null && effect.nodes_end !== null ) { remove_effect_dom(effect.nodes_start, /** @type {TemplateNode} */ (effect.nodes_end)); removed = true; } destroy_effect_children(effect, remove_dom && !removed); remove_reactions(effect, 0); set_signal_status(effect, DESTROYED); var transitions = effect.transitions; if (transitions !== null) { for (const transition of transitions) { transition.stop(); } } execute_effect_teardown(effect); var parent = effect.parent; // If the parent doesn't have any children, then skip this work altogether if (parent !== null && parent.first !== null) { unlink_effect(effect); } if (DEV) { effect.component_function = null; } // `first` and `child` are nulled out in destroy_effect_children // we don't null out `parent` so that error propagation can work correctly effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.fn = effect.nodes_start = effect.nodes_end = effect.ac = null; } /** * * @param {TemplateNode | null} node * @param {TemplateNode} end */ function remove_effect_dom(node, end) { while (node !== null) { /** @type {TemplateNode | null} */ var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node)); node.remove(); node = next; } } /** * Detach an effect from the effect tree, freeing up memory and * reducing the amount of work that happens on subsequent traversals * @param {Effect} effect */ function unlink_effect(effect) { var parent = effect.parent; var prev = effect.prev; var next = effect.next; if (prev !== null) prev.next = next; if (next !== null) next.prev = prev; if (parent !== null) { if (parent.first === effect) parent.first = next; if (parent.last === effect) parent.last = prev; } } /** * When a block effect is removed, we don't immediately destroy it or yank it * out of the DOM, because it might have transitions. Instead, we 'pause' it. * It stays around (in memory, and in the DOM) until outro transitions have * completed, and if the state change is reversed then we _resume_ it. * A paused effect does not update, and the DOM subtree becomes inert. * @param {Effect} effect * @param {() => void} [callback] */ function pause_effect(effect, callback) { /** @type {TransitionManager[]} */ var transitions = []; pause_children(effect, transitions, true); run_out_transitions(transitions, () => { destroy_effect(effect); if (callback) callback(); }); } /** * @param {TransitionManager[]} transitions * @param {() => void} fn */ function run_out_transitions(transitions, fn) { var remaining = transitions.length; if (remaining > 0) { var check = () => --remaining || fn(); for (var transition of transitions) { transition.out(check); } } else { fn(); } } /** * @param {Effect} effect * @param {TransitionManager[]} transitions * @param {boolean} local */ function pause_children(effect, transitions, local) { if ((effect.f & INERT) !== 0) return; effect.f ^= INERT; if (effect.transitions !== null) { for (const transition of effect.transitions) { if (transition.is_global || local) { transitions.push(transition); } } } var child = effect.first; while (child !== null) { var sibling = child.next; var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; // TODO we don't need to call pause_children recursively with a linked list in place // it's slightly more involved though as we have to account for `transparent` changing // through the tree. pause_children(child, transitions, transparent ? local : false); child = sibling; } } /** * The opposite of `pause_effect`. We call this if (for example) * `x` becomes falsy then truthy: `{#if x}...{/if}` * @param {Effect} effect */ function resume_effect(effect) { resume_children(effect, true); } /** * @param {Effect} effect * @param {boolean} local */ function resume_children(effect, local) { if ((effect.f & INERT) === 0) return; effect.f ^= INERT; var child = effect.first; while (child !== null) { var sibling = child.next; var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; // TODO we don't need to call resume_children recursively with a linked list in place // it's slightly more involved though as we have to account for `transparent` changing // through the tree. resume_children(child, transparent ? local : false); child = sibling; } if (effect.transitions !== null) { for (const transition of effect.transitions) { if (transition.is_global || local) { transition.in(); } } } } /** @import { Effect } from '#client' */ /** @import { Boundary } from './dom/blocks/boundary.js' */ /** * @param {unknown} error */ function handle_error(error) { var effect = /** @type {Effect} */ (active_effect); if (DEV && error instanceof Error) { adjust_error(error, effect); } if ((effect.f & EFFECT_RAN) === 0) { // if the error occurred while creating this subtree, we let it // bubble up until it hits a boundary that can handle it if ((effect.f & BOUNDARY_EFFECT) === 0) { throw error; } // @ts-expect-error effect.fn(error); } else { // otherwise we bubble up the effect tree ourselves invoke_error_boundary(error, effect); } } /** * @param {unknown} error * @param {Effect | null} effect */ function invoke_error_boundary(error, effect) { while (effect !== null) { if ((effect.f & BOUNDARY_EFFECT) !== 0) { try { /** @type {Boundary} */ (effect.b).error(error); return; } catch {} } effect = effect.parent; } throw error; } /** @type {WeakSet<Error>} */ const adjusted_errors = new WeakSet(); /** * Add useful information to the error message/stack in development * @param {Error} error * @param {Effect} effect */ function adjust_error(error, effect) { if (adjusted_errors.has(error)) return; adjusted_errors.add(error); const message_descriptor = get_descriptor(error, 'message'); // if the message was already changed and it's not configurable we can't change it // or it will throw a different error swallowing the original error if (message_descriptor && !message_descriptor.configurable) return; var indent = '\t'; var component_stack = `\n${indent}in ${effect.fn?.name || '<unknown>'}`; var context = effect.ctx; while (context !== null) { component_stack += `\n${indent}in ${context.function?.[FILENAME].split('/').pop()}`; context = context.p; } define_property(error, 'message', { value: error.message + `\n${component_stack}\n` }); if (error.stack) { // Filter out internal modules define_property(error, 'stack', { value: error.stack .split('\n') .filter((line) => !line.includes('svelte/src/internal')) .join('\n') }); } } /** @import { Derived, Effect, Reaction, Signal, Source, Value } from '#client' */ let is_flushing = false; /** @type {Effect | null} */ let last_scheduled_effect = null; let is_updating_effect = false; let is_destroying_effect = false; /** @param {boolean} value */ function set_is_destroying_effect(value) { is_destroying_effect = value; } // Handle effect queues /** @type {Effect[]} */ let queued_root_effects = []; /** @type {Effect[]} Stack of effects, dev only */ let dev_effect_stack = []; // Handle signal reactivity tree dependencies and reactions /** @type {null | Reaction} */ let active_reaction = null; let untracking = false; /** @param {null | Reaction} reaction */ function set_active_reaction(reaction) { active_reaction = reaction; } /** @type {null | Effect} */ let active_effect = null; /** @param {null | Effect} effect */ function set_active_effect(effect) { active_effect = effect; } /** * When sources are created within a reaction, reading and writing * them within that reaction should not cause a re-run * @type {null | [active_reaction: Reaction, sources: Source[]]} */ let reaction_sources = null; /** @param {Value} value */ function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { if (reaction_sources === null) { reaction_sources = [active_reaction, [value]]; } else { reaction_sources[1].push(value); } } } /** * The dependencies of the reaction that is currently being executed. In many cases, * the dependencies are unchanged between runs, and so this will be `null` unless * and until a new dependency is accessed — we track this via `skipped_deps` * @type {null | Value[]} */ let new_deps = null; let skipped_deps = 0; /** * Tracks writes that the effect it's executed in doesn't listen to yet, * so that the dependency can be added to the effect later on if it then reads it * @type {null | Source[]} */ let untracked_writes = null; /** @param {null | Source[]} value */ function set_untracked_writes(value) { untracked_writes = value; } /** * @type {number} Used by sources and deriveds for handling updates. * Version starts from 1 so that unowned deriveds differentiate between a created effect and a run one for tracing **/ let write_version = 1; /** @type {number} Used to version each read of a source of derived to avoid duplicating depedencies inside a reaction */ let read_version = 0; // If we are working with a get() chain that has no active container, // to prevent memory leaks, we skip adding the reaction. let skip_reaction = false; function increment_write_version() { return ++write_version; } /** * Determines whether a derived or effect is dirty. * If it is MAYBE_DIRTY, will set the status to CLEAN * @param {Reaction} reaction * @returns {boolean} */ function check_dirtiness(reaction) { var flags = reaction.f; if ((flags & DIRTY) !== 0) { return true; } if ((flags & MAYBE_DIRTY) !== 0) { var dependencies = reaction.deps; var is_unowned = (flags & UNOWNED) !== 0; if (dependencies !== null) { var i; var dependency; var is_disconnected = (flags & DISCONNECTED) !== 0; var is_unowned_connected = is_unowned && active_effect !== null && !skip_reaction; var length = dependencies.length; // If we are working with a disconnected or an unowned signal that is now connected (due to an active effect) // then we need to re-connect the reaction to the dependency if (is_disconnected || is_unowned_connected) { var derived = /** @type {Derived} */ (reaction); var parent = derived.parent; for (i = 0; i < length; i++) { dependency = dependencies[i]; // We always re-add all reactions (even duplicates) if the derived was // previously disconnected, however we don't if it was unowned as we // de-duplicate dependencies in that case if (is_disconnected || !dependency?.reactions?.includes(derived)) { (dependency.reactions ??= []).push(derived); } } if (is_disconnected) { derived.f ^= DISCONNECTED; } // If the unowned derived is now fully connected to the graph again (it's unowned and reconnected, has a parent // and the parent is not unowned), then we can mark it as connected again, removing the need for the unowned // flag if (is_unowned_connected && parent !== null && (parent.f & UNOWNED) === 0) { derived.f ^= UNOWNED; } } for (i = 0; i < length; i++) { dependency = dependencies[i]; if (check_dirtiness(/** @type {Derived} */ (dependency))) { update_derived(/** @type {Derived} */ (dependency)); } if (dependency.wv > reaction.wv) { return true; } } } // Unowned signals should never be marked as clean unless they // are used within an active_effect without skip_reaction if (!is_unowned || (active_effect !== null && !skip_reaction)) { set_signal_status(reaction, CLEAN); } } return false; } /** * @param {Value} signal * @param {Effect} effect * @param {boolean} [root] */ function schedule_possible_effect_self_invalidation(signal, effect, root = true) { var reactions = signal.reactions; if (reactions === null) return; for (var i = 0; i < reactions.length; i++) { var reaction = reactions[i]; if (reaction_sources?.[1].includes(signal) && reaction_sources[0] === active_reaction) continue; if ((reaction.f & DERIVED) !== 0) { schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false); } else if (effect === reaction) { if (root) { set_signal_status(reaction, DIRTY); } else if ((reaction.f & CLEAN) !== 0) { set_signal_status(reaction, MAYBE_DIRTY); } schedule_effect(/** @type {Effect} */ (reaction)); } } } /** @param {Reaction} reaction */ function update_reaction(reaction) { var previous_deps = new_deps; var previous_skipped_deps = skipped_deps; var previous_untracked_writes = untracked_writes; var previous_reaction = active_reaction; var previous_skip_reaction = skip_reaction; var previous_reaction_sources = reaction_sources; var previous_component_context = component_context; var previous_untracking = untracking; var flags = reaction.f; new_deps = /** @type {null | Value[]} */ (null); skipped_deps = 0; untracked_writes = null; skip_reaction = (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; reaction_sources = null; set_componen