@lytjs/reactivity 6.5.0 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/effect.ts","../src/ref.ts","../src/async-computed.ts"],"names":["effect","REACTIVITY_MAX_TRIGGER_DEPTH","error","unsafeCast"],"mappings":"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","file":"async.cjs","sourcesContent":["// src/constants.ts\r\n// 内部符号常量\r\n\r\n// DEV 检测方式说明:\r\n// 统一使用 typeof 检测方式,兼容编译时 define/replace 替换和未配置构建替换的场景。\r\n// 当打包工具(如 rollup/esbuild)通过 define 插件将 __DEV__ 替换为字面量 true/false 时,\r\n// typeof 检测会被优化为直接的字面量判断,实现死代码消除(DCE)。\r\n// 当未配置构建替换时,typeof 检测也能安全降级为 false,避免 ReferenceError。\r\nconst DEV = typeof __DEV__ !== 'undefined' ? __DEV__ : false;\r\n\r\nexport const RefSymbol: unique symbol = Symbol(DEV ? 'ref' : undefined);\r\nexport const ShallowRefSymbol: unique symbol = Symbol(DEV ? 'shallow_ref' : undefined);\r\nexport const ComputedRefSymbol: unique symbol = Symbol(DEV ? 'computed_ref' : undefined);\r\nexport const ReactiveSymbol: unique symbol = Symbol(DEV ? 'reactive' : undefined);\r\nexport const ReadonlySymbol: unique symbol = Symbol(DEV ? 'readonly' : undefined);\r\nexport const SignalSymbol: unique symbol = Symbol(DEV ? 'signal' : undefined);\r\nexport const ComputedSignalSymbol: unique symbol = Symbol(DEV ? 'computed_signal' : undefined);\r\n\r\n// ReactiveFlags - 用于 Proxy handler 内部标记\r\nexport const ReactiveFlags = {\r\n IS_REACTIVE: '__v_isReactive',\r\n IS_READONLY: '__v_isReadonly',\r\n IS_SHALLOW: '__v_isShallow',\r\n IS_REF: '__v_isRef',\r\n RAW: '__v_raw',\r\n SKIP: '__v_skip',\r\n} as const;\r\n\r\n// Track/Trigger 操作类型\r\nexport const TrackOpTypes = {\r\n GET: 'get',\r\n HAS: 'has',\r\n ITERATE: 'iterate',\r\n} as const;\r\n\r\nexport const TriggerOpTypes = {\r\n SET: 'set',\r\n ADD: 'add',\r\n DELETE: 'delete',\r\n CLEAR: 'clear',\r\n} as const;\r\n\r\n// 内部共享常量\r\nexport const ITERATE_KEY = Symbol('iterate');\r\n","// src/effect.ts\r\n// 响应式副作用系统核心\r\n\r\nimport { ITERATE_KEY } from './constants';\r\nimport type { ReactiveEffectRunner } from './types';\r\nimport { warn } from '@lytjs/common-error';\r\nimport { _isSignalUntracked } from './signal';\r\nimport { getActiveEffectScope } from './effect-scope';\r\nimport { REACTIVITY_MAX_TRIGGER_DEPTH } from '@lytjs/common-constants';\r\n\r\n// ==================== 全局状态 ====================\r\n\r\nlet activeEffect: ReactiveEffect | undefined;\r\nlet _trackDepth = 0;\r\nconst targetMap = new WeakMap<object, Map<string | symbol, Dep>>();\r\nlet shouldTrack = true;\r\nconst trackStack: boolean[] = [];\r\n\r\n// ==================== 首次渲染优化 ====================\r\n\r\n/** 标记当前是否处于首次渲染优化期间 */\r\nlet isFirstRenderPass = false;\r\n\r\n/** 记录被跳过的追踪次数(用于调试和测试验证) */\r\nlet skippedTrackingCount = 0;\r\n\r\n/**\r\n * 包裹首次渲染过程,期间禁用响应式依赖收集。\r\n * 支持嵌套调用:如果外层已经处于首次渲染优化期间,\r\n * 内层调用不会提前重置标志位。\r\n */\r\nexport function withFirstRenderOptimization<T>(fn: () => T): T {\r\n const wasFirstRender = isFirstRenderPass;\r\n isFirstRenderPass = true;\r\n try {\r\n return fn();\r\n } finally {\r\n if (!wasFirstRender) {\r\n isFirstRenderPass = false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 检查当前是否应跳过响应式依赖收集。\r\n * 在 withFirstRenderOptimization 执行期间返回 true。\r\n */\r\nexport function shouldSkipTracking(): boolean {\r\n return isFirstRenderPass;\r\n}\r\n\r\n/**\r\n * 获取被跳过的追踪次数(用于调试和测试)。\r\n */\r\nexport function getSkippedTrackingCount(): number {\r\n return skippedTrackingCount;\r\n}\r\n\r\n/**\r\n * 重置被跳过的追踪计数(用于测试)。\r\n */\r\nexport function resetSkippedTrackingCount(): void {\r\n skippedTrackingCount = 0;\r\n}\r\n\r\n// 只读访问器,防止外部修改内部状态\r\n\r\n/**\r\n * 获取当前活跃的 ReactiveEffect 实例。\r\n * 在 effect 执行期间返回当前正在运行的 effect,否则返回 undefined。\r\n *\r\n * @returns 当前活跃的 effect,如果没有则返回 undefined\r\n */\r\nexport function getActiveEffect(): ReactiveEffect | undefined {\r\n return activeEffect;\r\n}\r\n\r\n/**\r\n * 获取当前是否应该进行依赖追踪。\r\n * 可通过 pauseTracking/enableTracking 控制。\r\n *\r\n * @returns 是否应该进行依赖追踪\r\n */\r\nexport function getShouldTrack(): boolean {\r\n return shouldTrack;\r\n}\r\n\r\n// ==================== Dep ====================\r\n\r\n/**\r\n * 依赖集合类型,存储订阅某个响应式属性的所有 ReactiveEffect。\r\n */\r\nexport type Dep = Set<ReactiveEffect>;\r\n\r\n/**\r\n * 创建一个新的 Dep(依赖集合)。\r\n *\r\n * @returns 新的空 Dep 实例\r\n */\r\nexport const createDep = (): Dep => {\r\n return new Set() as Dep;\r\n};\r\n\r\n// ==================== Track / Trigger ====================\r\n\r\n/**\r\n * Maximum depth for nested trigger() calls to prevent infinite reactivity loops.\r\n * When triggerDepth exceeds this limit, further triggers are silently dropped\r\n * and a warning is emitted in DEV mode.\r\n */\r\nlet triggerDepth = 0;\r\n\r\n/**\r\n * 追踪响应式属性的依赖关系。\r\n * 当响应式属性被读取时调用,将当前活跃的 effect 记录为该属性的依赖。\r\n *\r\n * @param target - 被追踪的响应式对象\r\n * @param _type - 追踪操作类型(如 'get'、'has'、'iterate')\r\n * @param key - 被追踪的属性键\r\n */\r\nexport function track(target: object, _type: string, key: string | symbol) {\r\n if (!shouldTrack || activeEffect === undefined) return;\r\n // signal untrack 桥接:signalUntrack 期间跳过 effect 系统的依赖收集\r\n if (_isSignalUntracked()) return;\r\n\r\n let depsMap = targetMap.get(target);\r\n if (!depsMap) {\r\n targetMap.set(target, (depsMap = new Map()));\r\n }\r\n\r\n let dep = depsMap.get(key);\r\n if (!dep) {\r\n depsMap.set(key, (dep = createDep()));\r\n }\r\n\r\n trackEffect(dep);\r\n\r\n // 调试:触发 onTrack\r\n if (__DEV__ && activeEffect.onTrack) {\r\n activeEffect.onTrack({\r\n effect: activeEffect,\r\n target,\r\n type: _type,\r\n key,\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * 将当前活跃的 effect 添加到指定的依赖集合中。\r\n * 在首次渲染优化期间会跳过依赖收集。\r\n *\r\n * @param dep - 目标依赖集合\r\n */\r\nexport function trackEffect(dep: Dep) {\r\n // 首次渲染优化:跳过依赖收集\r\n if (shouldSkipTracking()) {\r\n skippedTrackingCount++;\r\n return;\r\n }\r\n // FIX: P1-01 移除重复的 shouldTrack/activeEffect 检查,\r\n // 这些检查已在调用方 track() 中完成,此处只需关注 dep 操作\r\n // FIX: P0-5 添加防御性检查,避免非空断言在公共 API 调用时不安全\r\n if (activeEffect && !dep.has(activeEffect)) {\r\n dep.add(activeEffect);\r\n activeEffect.deps.push(dep);\r\n }\r\n}\r\n\r\n/**\r\n * 触发响应式属性的依赖更新。\r\n * 当响应式属性被修改时调用,通知所有依赖该属性的 effect 重新执行。\r\n *\r\n * 根据操作类型(add/delete/set/clear)会触发不同的依赖集合:\r\n * - `add`:触发属性本身 + ITERATE_KEY(或数组 length)\r\n * - `delete`:触发属性本身 + ITERATE_KEY\r\n * - `set`:触发属性本身 + 数组 length(如果是整数键)\r\n * - `clear`:触发所有属性的依赖\r\n *\r\n * @param target - 被修改的响应式对象\r\n * @param type - 触发操作类型('set' | 'add' | 'delete' | 'clear')\r\n * @param key - 被修改的属性键\r\n * @param _newValue - 新值(可选,用于调试)\r\n * @param _oldValue - 旧值(可选,用于调试)\r\n */\r\nexport function trigger(\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n const depsMap = targetMap.get(target);\r\n if (!depsMap) return;\r\n\r\n const deps: (Dep | undefined)[] = [];\r\n\r\n if (type === 'clear') {\r\n deps.push(...depsMap.values());\r\n } else {\r\n if (key !== undefined) {\r\n deps.push(depsMap.get(key));\r\n }\r\n\r\n if (type === 'add') {\r\n if (Array.isArray(target)) {\r\n deps.push(depsMap.get('length'));\r\n } else {\r\n deps.push(depsMap.get(ITERATE_KEY));\r\n }\r\n } else if (type === 'delete') {\r\n if (!Array.isArray(target)) {\r\n deps.push(depsMap.get(ITERATE_KEY));\r\n }\r\n } else if (type === 'set') {\r\n if (Array.isArray(target) && isIntegerKey(key)) {\r\n deps.push(depsMap.get('length'));\r\n }\r\n }\r\n }\r\n\r\n const effects: ReactiveEffect[] = [];\r\n for (const dep of deps) {\r\n if (dep) {\r\n for (const effect of dep) {\r\n effects.push(effect);\r\n }\r\n }\r\n }\r\n\r\n // 去重:同一个 effect 可能同时存在于多个 dep 中\r\n triggerEffects([...new Set(effects)], target, type, key, newValue, oldValue);\r\n}\r\n\r\n/**\r\n * 执行一组 effect 的触发。\r\n * 优先执行 computed effect,再执行普通 effect。\r\n * 内置递归深度限制,超过最大深度时静默丢弃并发出警告。\r\n *\r\n * @param effects - 需要触发的 ReactiveEffect 数组\r\n * @param target - 被修改的目标对象(用于调试回调)\r\n * @param type - 触发操作类型(用于调试回调)\r\n * @param key - 被修改的属性键(用于调试回调)\r\n * @param newValue - 新值(用于调试回调)\r\n * @param oldValue - 旧值(用于调试回调)\r\n */\r\nexport function triggerEffects(\r\n effects: ReactiveEffect[],\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n if (triggerDepth > REACTIVITY_MAX_TRIGGER_DEPTH) {\r\n // FIX: P2-1 triggerDepth 超限时改为 warn + 静默丢弃,与 Vue 3 行为一致。\r\n // 之前直接 throw Error 过于激进,会导致整个响应式链断裂。\r\n // 改为仅发出警告并丢弃后续 trigger,避免因单个无限循环导致整个应用崩溃。\r\n if (__DEV__) {\r\n warn(\r\n `[lytjs/reactivity] Maximum trigger depth (${REACTIVITY_MAX_TRIGGER_DEPTH}) exceeded. ` +\r\n `Possible infinite reactivity loop detected. Further triggers are silently dropped. ` +\r\n `triggerDepth=${triggerDepth}`,\r\n );\r\n }\r\n return;\r\n }\r\n triggerDepth++;\r\n try {\r\n for (const effect of effects) {\r\n if (effect.computed) {\r\n triggerEffect(effect, target, type, key, newValue, oldValue);\r\n }\r\n }\r\n for (const effect of effects) {\r\n if (!effect.computed) {\r\n triggerEffect(effect, target, type, key, newValue, oldValue);\r\n }\r\n }\r\n } finally {\r\n triggerDepth--;\r\n }\r\n}\r\n\r\nfunction triggerEffect(\r\n effect: ReactiveEffect,\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n if (effect !== activeEffect || effect.allowRecurse) {\r\n // 调用 onTrigger 回调(用于调试)\r\n if (__DEV__ && effect.onTrigger) {\r\n effect.onTrigger({\r\n effect,\r\n target,\r\n type,\r\n key,\r\n newValue,\r\n oldValue,\r\n });\r\n }\r\n if (effect.scheduler) {\r\n effect.scheduler();\r\n } else {\r\n effect.run();\r\n }\r\n }\r\n}\r\n\r\n// ==================== ReactiveEffect ====================\r\n\r\n/**\r\n * 响应式副作用类。\r\n * 封装一个副作用函数,支持依赖自动收集、调度执行和手动停止。\r\n *\r\n * 创建时会自动注册到当前活跃的 effectScope 中。\r\n *\r\n * @typeParam T - 副作用函数的返回值类型\r\n *\r\n * @example\r\n * ```ts\r\n * const eff = new ReactiveEffect(() => {\r\n * console.log(state.count);\r\n * });\r\n * eff.run(); // 执行副作用,同时收集依赖\r\n * eff.stop(); // 停止副作用,清理所有依赖\r\n * ```\r\n */\r\nexport class ReactiveEffect<T = unknown> {\r\n active = true;\r\n deps: Dep[] = [];\r\n parent: ReactiveEffect | undefined = undefined;\r\n computed?: boolean;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n onError?: (error: Error) => void;\r\n // 运行前清理(onEffectCleanup 注册的)\r\n _cleanups: Array<() => void> = [];\r\n\r\n constructor(\r\n public fn: () => T,\r\n public scheduler?: (...args: unknown[]) => unknown,\r\n ) {\r\n // 自动注册到当前活跃的 effectScope\r\n const scope = getActiveEffectScope();\r\n if (scope && scope.active) {\r\n scope.effects.push(this);\r\n }\r\n }\r\n\r\n run(): T | undefined {\r\n if (!this.active) {\r\n return undefined;\r\n }\r\n\r\n // 在重新执行前调用 cleanup\r\n if (this._cleanups.length > 0) {\r\n for (let i = 0; i < this._cleanups.length; i++) {\r\n this._cleanups[i]!();\r\n }\r\n this._cleanups.length = 0;\r\n }\r\n\r\n const prevShouldTrack = shouldTrack;\r\n try {\r\n this.parent = activeEffect;\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n activeEffect = this;\r\n shouldTrack = true;\r\n _trackDepth++;\r\n\r\n return this.fn();\r\n } catch (error) {\r\n if (this.onError) {\r\n this.onError(error as Error);\r\n return undefined;\r\n }\r\n throw error;\r\n } finally {\r\n _trackDepth--;\r\n activeEffect = this.parent;\r\n shouldTrack = prevShouldTrack;\r\n this.parent = undefined;\r\n }\r\n }\r\n\r\n stop(): void {\r\n if (this.active) {\r\n cleanupEffect(this);\r\n if (this._cleanups.length > 0) {\r\n for (let i = 0; i < this._cleanups.length; i++) {\r\n this._cleanups[i]!();\r\n }\r\n this._cleanups.length = 0;\r\n }\r\n if (this.onStop) {\r\n this.onStop();\r\n }\r\n this.active = false;\r\n this.scheduler = undefined;\r\n }\r\n }\r\n}\r\n\r\nfunction cleanupEffect(effect: ReactiveEffect) {\r\n const { deps } = effect;\r\n for (let i = 0; i < deps.length; i++) {\r\n deps[i]!.delete(effect);\r\n }\r\n deps.length = 0;\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\n// Function overloads for effect()\r\n// Non-lazy effect: fn returns void, preventing accidental return value usage\r\n\r\n/**\r\n * 创建一个响应式副作用并立即执行。\r\n *\r\n * 副作用函数会在执行期间自动追踪所使用的响应式属性,\r\n * 当这些属性发生变化时,副作用会重新执行。\r\n *\r\n * @param fn - 副作用函数,返回 void\r\n * @param options - 配置选项\r\n * @param options.lazy - 是否延迟执行(false 时立即执行)\r\n * @param options.scheduler - 自定义调度器,替代默认的立即执行行为\r\n * @param options.allowRecurse - 是否允许副作用递归触发自身\r\n * @param options.onStop - 副作用停止时的回调\r\n * @param options.onTrack - 依赖被追踪时的调试回调\r\n * @param options.onTrigger - 依赖被触发时的调试回调\r\n * @returns 副作用运行器,可调用 run() 手动执行或 stop() 停止\r\n */\r\nexport function effect(\r\n fn: () => void,\r\n options?: {\r\n lazy?: false;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n },\r\n): ReactiveEffectRunner<void>;\r\n\r\n// Lazy effect: preserves generic return value type (used by computed etc.)\r\nexport function effect<T>(\r\n fn: () => T,\r\n options: {\r\n lazy: true;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n },\r\n): ReactiveEffectRunner<T>;\r\n\r\n// 统一实现签名\r\nexport function effect<T = unknown>(\r\n fn: () => T,\r\n options?: {\r\n lazy?: boolean;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n onError?: (error: Error) => void;\r\n },\r\n): ReactiveEffectRunner<T> {\r\n const _effect = new ReactiveEffect(fn);\r\n if (options) {\r\n // 仅提取已知合法选项,防止覆盖内部属性(如 fn、active)\r\n _effect.scheduler = options.scheduler;\r\n _effect.allowRecurse = options.allowRecurse;\r\n _effect.onStop = options.onStop;\r\n _effect.onTrack = options.onTrack;\r\n _effect.onTrigger = options.onTrigger;\r\n _effect.onError = options.onError;\r\n }\r\n if (!options || !options.lazy) {\r\n _effect.run();\r\n }\r\n const runner = _effect.run.bind(_effect) as ReactiveEffectRunner<T>;\r\n runner.effect = _effect;\r\n return runner;\r\n}\r\n\r\n/**\r\n * 停止一个响应式副作用。\r\n * 清理所有依赖关系,并调用 onStop 回调。\r\n *\r\n * @param runner - 由 effect() 返回的副作用运行器\r\n */\r\nexport function stop(runner: ReactiveEffectRunner): void {\r\n runner.effect.stop();\r\n}\r\n\r\n/**\r\n * 暂停依赖追踪。\r\n * 调用后,响应式属性的读取不会建立依赖关系。\r\n * 可通过 resetTracking() 恢复。\r\n */\r\nexport function pauseTracking(): void {\r\n trackStack.push(shouldTrack);\r\n shouldTrack = false;\r\n}\r\n\r\n/**\r\n * 启用依赖追踪。\r\n * 将当前追踪状态压入栈中并设为 true。\r\n * 可通过 resetTracking() 恢复到之前的状态。\r\n */\r\nexport function enableTracking(): void {\r\n trackStack.push(shouldTrack);\r\n shouldTrack = true;\r\n}\r\n\r\n/**\r\n * 重置依赖追踪状态到上一次暂停/启用之前的状态。\r\n * 从追踪栈中弹出最近的状态并恢复。\r\n */\r\nexport function resetTracking(): void {\r\n const last = trackStack.pop();\r\n shouldTrack = last === undefined ? true : last;\r\n}\r\n\r\n/**\r\n * 批量执行函数,期间暂停依赖追踪。\r\n * 与 signalBatch 不同,batch 侧重于暂停追踪而非延迟通知。\r\n * 支持嵌套调用,内层 batch 不会提前恢复追踪状态。\r\n *\r\n * @param fn - 需要批量执行的函数\r\n *\r\n * @example\r\n * ```ts\r\n * batch(() => {\r\n * state.a = 1; // 不会触发依赖更新\r\n * state.b = 2; // 不会触发依赖更新\r\n * }); // 函数结束后恢复追踪\r\n * ```\r\n */\r\nexport function batch(fn: () => void): void {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n try {\r\n fn();\r\n } finally {\r\n // 恢复到 batch 调用前的 stack 长度,确保嵌套安全\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n }\r\n}\r\n\r\n/**\r\n * batchAsync - like batch but supports async functions.\r\n * Pauses tracking during fn execution (including after await),\r\n * and restores tracking state when fn completes (or throws).\r\n * Returns a Promise.\r\n */\r\nexport function batchAsync(fn: () => void | Promise<void>): Promise<void> {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n const restoreTracking = () => {\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n };\r\n try {\r\n const result = fn();\r\n if (result && typeof result === 'object' && 'then' in result) {\r\n return (result as Promise<void>).finally(restoreTracking);\r\n }\r\n // 同步路径:立即恢复 tracking 状态\r\n restoreTracking();\r\n return Promise.resolve();\r\n } catch (e) {\r\n restoreTracking();\r\n return Promise.reject(e);\r\n }\r\n}\r\n\r\n/**\r\n * untrack - execute fn without tracking dependencies.\r\n * Semantically different from batch: untrack means \"run but don't track\".\r\n * Returns the return value of fn.\r\n */\r\nexport function untrack<T>(fn: () => T): T {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n try {\r\n return fn();\r\n } finally {\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n }\r\n}\r\n\r\n/**\r\n * 在当前活跃的 effect 上注册一个清理回调。\r\n * 该回调会在 effect 重新执行前或停止时被调用,用于清理副作用资源。\r\n *\r\n * @param fn - 清理回调函数\r\n * @param failSilently - 当没有活跃 effect 时是否静默失败(默认 false,开发模式下会发出警告)\r\n *\r\n * @example\r\n * ```ts\r\n * effect(() => {\r\n * const timer = setInterval(() => console.log('tick'), 1000);\r\n * onEffectCleanup(() => clearInterval(timer));\r\n * });\r\n * ```\r\n */\r\nexport function onEffectCleanup(fn: () => void, failSilently = false): void {\r\n if (activeEffect === undefined) {\r\n if (!failSilently && __DEV__) {\r\n warn('onEffectCleanup() was called when there was no active effect to associate with.');\r\n }\r\n return;\r\n }\r\n activeEffect._cleanups.push(fn);\r\n}\r\n\r\n// ==================== 辅助 ====================\r\n\r\n/**\r\n * 检查给定的键是否为有效的整数键。\r\n * 用于判断数组索引是否为合法的整数值。\r\n *\r\n * @param key - 需要检查的键值\r\n * @returns 如果是有效的整数键返回 true,否则返回 false\r\n */\r\nexport function isIntegerKey(key: unknown): boolean {\r\n return (\r\n typeof key === 'string' &&\r\n key !== 'NaN' &&\r\n key[0] !== '-' &&\r\n '' + parseInt(key, 10) === key &&\r\n Number.isSafeInteger(Number(key))\r\n );\r\n}\r\n","// src/ref.ts\r\n// Ref 响应式引用\r\n// 复用 @lytjs/common-is: isObject, hasChanged\r\n\r\nimport { isObject, hasChanged } from '@lytjs/common-is';\r\nimport { warn } from '@lytjs/common-error';\r\nimport { unsafeCast } from '@lytjs/common-assertions';\r\nimport { track, trigger, getActiveEffect, getShouldTrack, createDep } from './effect';\r\nimport type { Dep } from './effect';\r\nimport { TrackOpTypes, TriggerOpTypes } from './constants';\r\nimport { toRaw, isRef } from './shared';\r\nimport { reactive } from './reactive';\r\n\r\n// ==================== Ref 类型 ====================\r\n\r\n/** track/trigger 中使用的类 ref 对象的内部接口 */\r\nexport interface RefLike<T = unknown> {\r\n dep: Dep;\r\n __v_isRef?: boolean;\r\n value: T;\r\n}\r\n\r\n/** trackRefValue/triggerRefValue 所需的最小接口 */\r\ninterface TrackableRef {\r\n dep: Dep;\r\n}\r\n\r\nexport interface Ref<T = unknown> {\r\n value: T;\r\n __v_isRef: true;\r\n}\r\n\r\nexport interface ShallowRef<T = unknown> extends Ref<T> {\r\n __v_isShallow: true;\r\n}\r\n\r\nexport interface ComputedRef<T = unknown> extends Ref<T> {\r\n __v_isComputed: true;\r\n}\r\n\r\n// ==================== Ref 类 ====================\r\n\r\nclass RefImpl<T> {\r\n private _value: T;\r\n private _rawValue: T;\r\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\r\n public dep: Dep = createDep();\r\n public readonly __v_isRef = true;\r\n public readonly __v_isShallow?: boolean;\r\n\r\n constructor(value: T, isShallow: boolean) {\r\n this.__v_isShallow = isShallow || undefined;\r\n this._rawValue = isShallow ? value : toRaw(value);\r\n // toReactive 仅对对象类型生效,非对象值直接赋值。\r\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\r\n this._value = isShallow ? value : (toReactive(value as object) as T);\r\n }\r\n\r\n get value(): T {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(newVal: T) {\r\n const useDirectValue = this.__v_isShallow;\r\n newVal = useDirectValue ? newVal : toRaw(newVal);\r\n if (hasChanged(newVal, this._rawValue)) {\r\n const oldVal = this._rawValue;\r\n this._rawValue = newVal;\r\n // toReactive 仅对对象类型生效,非对象值直接赋值。\r\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\r\n this._value = useDirectValue ? newVal : (toReactive(newVal as object) as T);\r\n triggerRefValue(this, newVal, oldVal);\r\n }\r\n }\r\n}\r\n\r\nclass ShallowRefImpl<T> {\r\n private _value: T;\r\n private _rawValue: T;\r\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\r\n public dep: Dep = createDep();\r\n public readonly __v_isRef = true;\r\n public readonly __v_isShallow = true as const;\r\n\r\n constructor(value: T) {\r\n this._rawValue = value;\r\n this._value = value;\r\n }\r\n\r\n get value(): T {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(newVal: T) {\r\n if (hasChanged(newVal, this._rawValue)) {\r\n const oldVal = this._rawValue;\r\n this._rawValue = newVal;\r\n this._value = newVal;\r\n triggerRefValue(this, newVal, oldVal);\r\n }\r\n }\r\n}\r\n\r\n// ==================== 追踪与触发 ====================\r\n\r\nexport function trackRefValue(ref: TrackableRef): void {\r\n if (getShouldTrack() && getActiveEffect()) {\r\n track(ref, TrackOpTypes.GET, 'value');\r\n }\r\n}\r\n\r\nexport function triggerRefValue(ref: TrackableRef, newVal?: unknown, oldVal?: unknown): void {\r\n trigger(ref, TriggerOpTypes.SET, 'value', newVal, oldVal);\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\nexport function ref<T extends object | string | number | boolean | null | undefined>(\r\n value: T,\r\n): Ref<T> {\r\n if (isRef(value)) {\r\n // FIX: P1-07 ref() 接受 ShallowRef 时添加 DEV 警告,\r\n // 提醒用户 ShallowRef 语义与 Ref 不同,直接返回可能导致意外行为\r\n // FIX: P2-34 使用类型守卫替代类型断言\r\n if (__DEV__ && isShallowRef(value)) {\r\n warn(\r\n 'ref() received a ShallowRef value. ' +\r\n 'ShallowRef and Ref have different reactivity semantics. ' +\r\n 'If this is intentional, use shallowRef() instead.',\r\n );\r\n }\r\n return value as Ref<T>;\r\n }\r\n // 双重断言是必要的:RefImpl 实现了 Ref 接口所需的 value/__v_isRef 属性,\r\n // 但 TypeScript 无法自动推断类实例满足接口(私有成员导致结构不兼容)。\r\n return unsafeCast<Ref<T>>(new RefImpl(value, false));\r\n}\r\n\r\nexport function shallowRef<T>(value: T): ShallowRef<T> {\r\n if (isRef(value)) return unsafeCast<ShallowRef<T>>(value);\r\n return unsafeCast<ShallowRef<T>>(new ShallowRefImpl(value));\r\n}\r\n\r\nexport function triggerRef<T>(ref: ShallowRef<T>): void {\r\n triggerRefValue(unsafeCast<TrackableRef>(ref), ref.value);\r\n}\r\n\r\nexport { isRef } from './shared';\r\n\r\n// FIX: P2-8 添加类型谓词:isShallowRef 和 isComputedRef\r\n/**\r\n * 检查值是否为 ShallowRef\r\n * 类型谓词:缩小类型到 ShallowRef<T>\r\n */\r\nexport function isShallowRef<T = unknown>(r: unknown): r is ShallowRef<T> {\r\n return isRef(r) && !!(r as ShallowRef<T>).__v_isShallow;\r\n}\r\n\r\n/**\r\n * 检查值是否为 ComputedRef\r\n * 类型谓词:缩小类型到 ComputedRef<T>\r\n */\r\nexport function isComputedRef<T = unknown>(r: unknown): r is ComputedRef<T> {\r\n return isRef(r) && !!(r as ComputedRef<T>).__v_isComputed;\r\n}\r\n\r\n// FIX: P2-06 unref 类型守卫增强:添加明确的返回类型注释\r\n// unref 如果参数是 Ref 则返回 .value,否则返回参数本身\r\nexport function unref<T>(r: T | Ref<T>): T {\r\n // FIX: P2-34 使用类型守卫替代类型断言,P2-38 移除不必要的 as\r\n // FIX: DTS build error - 使用类型断言确保类型正确\r\n return isRef(r) ? (r as Ref<T>).value : r;\r\n}\r\n\r\nexport function toRef<T extends object, K extends keyof T>(object: T, key: K): Ref<T[K]> {\r\n if (isRef(object[key])) return unsafeCast<Ref<T[K]>>(object[key]);\r\n return unsafeCast<Ref<T[K]>>(new ObjectRefImpl(object, key));\r\n}\r\n\r\nexport function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {\r\n const result = {} as { [K in keyof T]: Ref<T[K]> };\r\n for (const key in object) {\r\n result[key] = toRef(object, key);\r\n }\r\n return result;\r\n}\r\n\r\nexport function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {\r\n return unsafeCast<Ref<T>>(new CustomRefImpl(factory));\r\n}\r\n\r\n/**\r\n * 将值规范化为非 ref 值。\r\n * 如果是 Ref 则返回 .value,如果是函数则调用并返回结果,否则直接返回。\r\n * Vue 3.3+ 新增工具函数。\r\n */\r\nexport function toValue<T>(source: T | Ref<T> | (() => T)): T {\r\n // FIX: P2-34 使用类型守卫替代类型断言\r\n // FIX: DTS build error - 使用类型断言确保类型正确\r\n if (isRef(source)) return (source as Ref<T>).value;\r\n if (typeof source === 'function') {\r\n // FIX: P2-35 添加类型守卫确保 source 是函数后再调用\r\n return (source as () => T)();\r\n }\r\n return source as T;\r\n}\r\n\r\n// ==================== 内部实现类 ====================\r\n\r\nclass ObjectRefImpl<T extends object, K extends keyof T> {\r\n public readonly __v_isRef = true;\r\n\r\n constructor(\r\n private readonly _object: T,\r\n private readonly _key: K,\r\n ) {}\r\n\r\n get value(): T[K] {\r\n return this._object[this._key];\r\n }\r\n\r\n set value(newVal: T[K]) {\r\n this._object[this._key] = newVal;\r\n }\r\n}\r\n\r\nclass CustomRefImpl<T> {\r\n public readonly __v_isRef = true;\r\n public dep: Dep = createDep();\r\n private readonly _getter: () => T;\r\n private readonly _setter: (value: T) => void;\r\n\r\n constructor(factory: CustomRefFactory<T>) {\r\n const { get, set } = factory(\r\n () => trackRefValue(this),\r\n () => triggerRefValue(this),\r\n );\r\n this._getter = get;\r\n this._setter = set;\r\n }\r\n\r\n get value(): T {\r\n return this._getter();\r\n }\r\n\r\n set value(newVal: T) {\r\n this._setter(newVal);\r\n }\r\n}\r\n\r\n// ==================== 辅助函数 ====================\r\n\r\ntype CustomRefFactory<T> = (\r\n track: () => void,\r\n trigger: () => void,\r\n) => { get: () => T; set: (value: T) => void };\r\n\r\nfunction toReactive<T>(value: T): T {\r\n return isObject(value) ? (reactive(value as object) as T) : value;\r\n}\r\n","// src/async-computed.ts\r\n// @lytjs/reactivity - 异步 computed\r\n\r\ndeclare const __DEV__: boolean;\r\n\r\nimport { trackRefValue, triggerRefValue } from './ref';\r\nimport type { Ref } from './ref';\r\nimport { createDep } from './effect';\r\nimport type { Dep } from './effect';\r\nimport { effect, stop } from './effect';\r\nimport { unsafeCast } from '@lytjs/common-assertions';\r\nimport type { ReactiveEffectRunner } from './types';\r\nimport { warn } from '@lytjs/common-error';\r\n\r\n// ==================== AsyncComputedRef 类型 ====================\r\n\r\n/**\r\n * 异步计算属性引用\r\n * 扩展了标准 Ref,增加了 loading 和 error 状态\r\n */\r\nexport interface AsyncComputedRef<T = unknown> extends Ref<T | undefined> {\r\n /** 异步计算是否正在进行 */\r\n readonly loading: boolean;\r\n /** 上一次异步计算的错误(如果有) */\r\n readonly error: unknown;\r\n}\r\n\r\n// ==================== AsyncComputedRefImpl ====================\r\n\r\nclass AsyncComputedRefImpl<T> {\r\n private _value: T | undefined;\r\n private _loading: boolean = false;\r\n private _error: unknown = undefined;\r\n private _effect: ReactiveEffectRunner<void> | null = null;\r\n private _version = 0;\r\n\r\n public readonly __v_isRef = true;\r\n public dep: Dep = createDep();\r\n\r\n constructor(\r\n private readonly _getter: () => Promise<T>,\r\n initialValue?: T,\r\n lazy: boolean = false,\r\n ) {\r\n this._value = initialValue;\r\n\r\n if (!lazy) {\r\n // 非懒加载模式:使用 effect 追踪依赖,依赖变化时重新执行 getter\r\n this._effect = effect(() => {\r\n this._runGetter();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * 执行 getter 并处理 Promise 结果\r\n */\r\n private _runGetter(): void {\r\n // 标记为 loading\r\n this._loading = true;\r\n this._error = undefined;\r\n\r\n // FIX: P2-3 loading 状态变化同步触发通知。\r\n // 在设置 _loading = true 后立即调用 triggerRefValue,\r\n // 确保订阅者能感知到 loading 状态的变化(如显示 loading 指示器),\r\n // 而不是等到异步操作完成后才统一通知。\r\n triggerRefValue(this);\r\n\r\n // 递增版本号,用于竞态检测\r\n const currentVersion = ++this._version;\r\n\r\n // 调用 getter 获取 Promise\r\n const result = this._getter();\r\n // FIX: P1-06 getter 返回非 Promise 时包装为 Promise.resolve(),\r\n // 避免非 Promise 返回值导致 .then() 调用失败\r\n const promise = result instanceof Promise ? result : Promise.resolve(result);\r\n\r\n // 使用 Promise.then() 非阻塞处理\r\n promise.then(\r\n (value) => {\r\n if (currentVersion !== this._version) return; // 过期结果,忽略\r\n this._value = value;\r\n this._loading = false;\r\n this._error = undefined;\r\n // 触发 ref 更新\r\n triggerRefValue(this);\r\n },\r\n (err) => {\r\n if (currentVersion !== this._version) return; // 过期结果,忽略\r\n // FIX: P2-02 异步 computed 错误处理完善:在 DEV 模式下发出警告\r\n if (__DEV__) {\r\n console.warn('[lytjs/async-computed] Async computed error:', err);\r\n }\r\n this._error = err;\r\n this._loading = false;\r\n // 触发 ref 更新\r\n triggerRefValue(this);\r\n },\r\n );\r\n }\r\n\r\n /**\r\n * 手动触发执行(用于懒加载模式)\r\n */\r\n execute(): void {\r\n if (this._loading) return;\r\n this._runGetter();\r\n }\r\n\r\n get value(): T | undefined {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(_newVal: T | undefined) {\r\n if (__DEV__) {\r\n warn('Write operation failed: asyncComputed value is readonly');\r\n }\r\n }\r\n\r\n get loading(): boolean {\r\n return this._loading;\r\n }\r\n\r\n get error(): unknown {\r\n return this._error;\r\n }\r\n\r\n /**\r\n * 停止 effect 追踪\r\n */\r\n dispose(): void {\r\n this._version++; // 使所有 pending 的 promise 回调失效\r\n if (this._effect) {\r\n stop(this._effect);\r\n this._effect = null;\r\n }\r\n // FIX: P2-07 dispose 时清空错误和值,避免悬挂的异步回调更新已销毁的 computed\r\n this._error = null;\r\n this._value = undefined;\r\n // FIX: P1-2 REACTIVITY-NEW-03 - dispose 时通知订阅者,避免订阅者持有过期值\r\n triggerRefValue(this);\r\n }\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\n/**\r\n * 创建异步计算属性\r\n * 当 getter 中的响应式依赖变化时,自动重新执行 getter\r\n *\r\n * @param getter 返回 Promise 的函数\r\n * @param initialValue 初始值(Promise pending 时的值)\r\n * @returns AsyncComputedRef\r\n */\r\nexport function asyncComputed<T>(\r\n getter: () => Promise<T>,\r\n initialValue?: T,\r\n): AsyncComputedRef<T> {\r\n return unsafeCast<AsyncComputedRef<T>>(new AsyncComputedRefImpl<T>(getter, initialValue, false));\r\n}\r\n\r\n/**\r\n * 创建异步状态(懒加载模式)\r\n * factory 只执行一次,适合数据请求场景\r\n *\r\n * @param factory 返回 Promise 的函数\r\n * @param initialValue 初始值\r\n * @returns AsyncComputedRef\r\n */\r\nexport function useAsyncState<T>(\r\n factory: () => Promise<T>,\r\n initialValue?: T,\r\n): AsyncComputedRef<T> {\r\n const impl = new AsyncComputedRefImpl<T>(factory, initialValue, true);\r\n\r\n // 立即执行一次\r\n impl.execute();\r\n\r\n return unsafeCast<AsyncComputedRef<T>>(impl);\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/effect.ts","../src/ref.ts","../src/async-computed.ts"],"names":["effect","REACTIVITY_MAX_TRIGGER_DEPTH","error","unsafeCast"],"mappings":"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","file":"async.cjs","sourcesContent":["// src/constants.ts\n// 内部符号常量\n\n// DEV 检测方式说明:\n// 统一使用 typeof 检测方式,兼容编译时 define/replace 替换和未配置构建替换的场景。\n// 当打包工具(如 rollup/esbuild)通过 define 插件将 __DEV__ 替换为字面量 true/false 时,\n// typeof 检测会被优化为直接的字面量判断,实现死代码消除(DCE)。\n// 当未配置构建替换时,typeof 检测也能安全降级为 false,避免 ReferenceError。\nconst DEV = typeof __DEV__ !== 'undefined' ? __DEV__ : false;\n\nexport const RefSymbol: unique symbol = Symbol(DEV ? 'ref' : undefined);\nexport const ShallowRefSymbol: unique symbol = Symbol(DEV ? 'shallow_ref' : undefined);\nexport const ComputedRefSymbol: unique symbol = Symbol(DEV ? 'computed_ref' : undefined);\nexport const ReactiveSymbol: unique symbol = Symbol(DEV ? 'reactive' : undefined);\nexport const ReadonlySymbol: unique symbol = Symbol(DEV ? 'readonly' : undefined);\nexport const SignalSymbol: unique symbol = Symbol(DEV ? 'signal' : undefined);\nexport const ComputedSignalSymbol: unique symbol = Symbol(DEV ? 'computed_signal' : undefined);\n\n// ReactiveFlags - 用于 Proxy handler 内部标记\nexport const ReactiveFlags = {\n IS_REACTIVE: '__v_isReactive',\n IS_READONLY: '__v_isReadonly',\n IS_SHALLOW: '__v_isShallow',\n IS_REF: '__v_isRef',\n RAW: '__v_raw',\n SKIP: '__v_skip',\n} as const;\n\n// Track/Trigger 操作类型\nexport const TrackOpTypes = {\n GET: 'get',\n HAS: 'has',\n ITERATE: 'iterate',\n} as const;\n\nexport const TriggerOpTypes = {\n SET: 'set',\n ADD: 'add',\n DELETE: 'delete',\n CLEAR: 'clear',\n} as const;\n\n// 内部共享常量\nexport const ITERATE_KEY = Symbol('iterate');\n","// src/effect.ts\n// 响应式副作用系统核心\n\nimport { ITERATE_KEY } from './constants';\nimport type { ReactiveEffectRunner } from './types';\nimport { warn } from '@lytjs/common-error';\nimport { _isSignalUntracked } from './signal';\nimport { getActiveEffectScope } from './effect-scope';\nimport { REACTIVITY_MAX_TRIGGER_DEPTH } from '@lytjs/common-constants';\n\n// ==================== 全局状态 ====================\n\nlet activeEffect: ReactiveEffect | undefined;\nlet _trackDepth = 0;\nconst targetMap = new WeakMap<object, Map<string | symbol, Dep>>();\nlet shouldTrack = true;\nconst trackStack: boolean[] = [];\n\n// ==================== 首次渲染优化 ====================\n\n/** 标记当前是否处于首次渲染优化期间 */\nlet isFirstRenderPass = false;\n\n/** 记录被跳过的追踪次数(用于调试和测试验证) */\nlet skippedTrackingCount = 0;\n\n/**\n * 包裹首次渲染过程,期间禁用响应式依赖收集。\n * 支持嵌套调用:如果外层已经处于首次渲染优化期间,\n * 内层调用不会提前重置标志位。\n */\nexport function withFirstRenderOptimization<T>(fn: () => T): T {\n const wasFirstRender = isFirstRenderPass;\n isFirstRenderPass = true;\n try {\n return fn();\n } finally {\n if (!wasFirstRender) {\n isFirstRenderPass = false;\n }\n }\n}\n\n/**\n * 检查当前是否应跳过响应式依赖收集。\n * 在 withFirstRenderOptimization 执行期间返回 true。\n */\nexport function shouldSkipTracking(): boolean {\n return isFirstRenderPass;\n}\n\n/**\n * 获取被跳过的追踪次数(用于调试和测试)。\n */\nexport function getSkippedTrackingCount(): number {\n return skippedTrackingCount;\n}\n\n/**\n * 重置被跳过的追踪计数(用于测试)。\n */\nexport function resetSkippedTrackingCount(): void {\n skippedTrackingCount = 0;\n}\n\n// 只读访问器,防止外部修改内部状态\n\n/**\n * 获取当前活跃的 ReactiveEffect 实例。\n * 在 effect 执行期间返回当前正在运行的 effect,否则返回 undefined。\n *\n * @returns 当前活跃的 effect,如果没有则返回 undefined\n */\nexport function getActiveEffect(): ReactiveEffect | undefined {\n return activeEffect;\n}\n\n/**\n * 获取当前是否应该进行依赖追踪。\n * 可通过 pauseTracking/enableTracking 控制。\n *\n * @returns 是否应该进行依赖追踪\n */\nexport function getShouldTrack(): boolean {\n return shouldTrack;\n}\n\n// ==================== Dep ====================\n\n/**\n * 依赖集合类型,存储订阅某个响应式属性的所有 ReactiveEffect。\n */\nexport type Dep = Set<ReactiveEffect>;\n\n/**\n * 创建一个新的 Dep(依赖集合)。\n *\n * @returns 新的空 Dep 实例\n */\nexport const createDep = (): Dep => {\n return new Set() as Dep;\n};\n\n// ==================== Track / Trigger ====================\n\n/**\n * Maximum depth for nested trigger() calls to prevent infinite reactivity loops.\n * When triggerDepth exceeds this limit, further triggers are silently dropped\n * and a warning is emitted in DEV mode.\n */\nlet triggerDepth = 0;\n\n/**\n * 追踪响应式属性的依赖关系。\n * 当响应式属性被读取时调用,将当前活跃的 effect 记录为该属性的依赖。\n *\n * @param target - 被追踪的响应式对象\n * @param _type - 追踪操作类型(如 'get'、'has'、'iterate')\n * @param key - 被追踪的属性键\n */\nexport function track(target: object, _type: string, key: string | symbol) {\n if (!shouldTrack || activeEffect === undefined) return;\n // signal untrack 桥接:signalUntrack 期间跳过 effect 系统的依赖收集\n if (_isSignalUntracked()) return;\n\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, (depsMap = new Map()));\n }\n\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, (dep = createDep()));\n }\n\n trackEffect(dep);\n\n // 调试:触发 onTrack\n if (__DEV__ && activeEffect.onTrack) {\n activeEffect.onTrack({\n effect: activeEffect,\n target,\n type: _type,\n key,\n });\n }\n}\n\n/**\n * 将当前活跃的 effect 添加到指定的依赖集合中。\n * 在首次渲染优化期间会跳过依赖收集。\n *\n * @param dep - 目标依赖集合\n */\nexport function trackEffect(dep: Dep) {\n // 首次渲染优化:跳过依赖收集\n if (shouldSkipTracking()) {\n skippedTrackingCount++;\n return;\n }\n // FIX: P1-01 移除重复的 shouldTrack/activeEffect 检查,\n // 这些检查已在调用方 track() 中完成,此处只需关注 dep 操作\n // FIX: P0-5 添加防御性检查,避免非空断言在公共 API 调用时不安全\n if (activeEffect && !dep.has(activeEffect)) {\n dep.add(activeEffect);\n activeEffect.deps.push(dep);\n }\n}\n\n/**\n * 触发响应式属性的依赖更新。\n * 当响应式属性被修改时调用,通知所有依赖该属性的 effect 重新执行。\n *\n * 根据操作类型(add/delete/set/clear)会触发不同的依赖集合:\n * - `add`:触发属性本身 + ITERATE_KEY(或数组 length)\n * - `delete`:触发属性本身 + ITERATE_KEY\n * - `set`:触发属性本身 + 数组 length(如果是整数键)\n * - `clear`:触发所有属性的依赖\n *\n * @param target - 被修改的响应式对象\n * @param type - 触发操作类型('set' | 'add' | 'delete' | 'clear')\n * @param key - 被修改的属性键\n * @param _newValue - 新值(可选,用于调试)\n * @param _oldValue - 旧值(可选,用于调试)\n */\nexport function trigger(\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n const depsMap = targetMap.get(target);\n if (!depsMap) return;\n\n const deps: (Dep | undefined)[] = [];\n\n if (type === 'clear') {\n deps.push(...depsMap.values());\n } else {\n if (key !== undefined) {\n deps.push(depsMap.get(key));\n }\n\n if (type === 'add') {\n if (Array.isArray(target)) {\n deps.push(depsMap.get('length'));\n } else {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n } else if (type === 'delete') {\n if (!Array.isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n } else if (type === 'set') {\n if (Array.isArray(target) && isIntegerKey(key)) {\n deps.push(depsMap.get('length'));\n }\n }\n }\n\n const effects: ReactiveEffect[] = [];\n for (const dep of deps) {\n if (dep) {\n for (const effect of dep) {\n effects.push(effect);\n }\n }\n }\n\n // 去重:同一个 effect 可能同时存在于多个 dep 中\n triggerEffects([...new Set(effects)], target, type, key, newValue, oldValue);\n}\n\n/**\n * 执行一组 effect 的触发。\n * 优先执行 computed effect,再执行普通 effect。\n * 内置递归深度限制,超过最大深度时静默丢弃并发出警告。\n *\n * @param effects - 需要触发的 ReactiveEffect 数组\n * @param target - 被修改的目标对象(用于调试回调)\n * @param type - 触发操作类型(用于调试回调)\n * @param key - 被修改的属性键(用于调试回调)\n * @param newValue - 新值(用于调试回调)\n * @param oldValue - 旧值(用于调试回调)\n */\nexport function triggerEffects(\n effects: ReactiveEffect[],\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n if (triggerDepth > REACTIVITY_MAX_TRIGGER_DEPTH) {\n // FIX: P2-1 triggerDepth 超限时改为 warn + 静默丢弃,与 Vue 3 行为一致。\n // 之前直接 throw Error 过于激进,会导致整个响应式链断裂。\n // 改为仅发出警告并丢弃后续 trigger,避免因单个无限循环导致整个应用崩溃。\n if (__DEV__) {\n warn(\n `[lytjs/reactivity] Maximum trigger depth (${REACTIVITY_MAX_TRIGGER_DEPTH}) exceeded. ` +\n `Possible infinite reactivity loop detected. Further triggers are silently dropped. ` +\n `triggerDepth=${triggerDepth}`,\n );\n }\n return;\n }\n triggerDepth++;\n try {\n for (const effect of effects) {\n if (effect.computed) {\n triggerEffect(effect, target, type, key, newValue, oldValue);\n }\n }\n for (const effect of effects) {\n if (!effect.computed) {\n triggerEffect(effect, target, type, key, newValue, oldValue);\n }\n }\n } finally {\n triggerDepth--;\n }\n}\n\nfunction triggerEffect(\n effect: ReactiveEffect,\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n if (effect !== activeEffect || effect.allowRecurse) {\n // 调用 onTrigger 回调(用于调试)\n if (__DEV__ && effect.onTrigger) {\n effect.onTrigger({\n effect,\n target,\n type,\n key,\n newValue,\n oldValue,\n });\n }\n if (effect.scheduler) {\n effect.scheduler();\n } else {\n effect.run();\n }\n }\n}\n\n// ==================== ReactiveEffect ====================\n\n/**\n * 响应式副作用类。\n * 封装一个副作用函数,支持依赖自动收集、调度执行和手动停止。\n *\n * 创建时会自动注册到当前活跃的 effectScope 中。\n *\n * @typeParam T - 副作用函数的返回值类型\n *\n * @example\n * ```ts\n * const eff = new ReactiveEffect(() => {\n * console.log(state.count);\n * });\n * eff.run(); // 执行副作用,同时收集依赖\n * eff.stop(); // 停止副作用,清理所有依赖\n * ```\n */\nexport class ReactiveEffect<T = unknown> {\n active = true;\n deps: Dep[] = [];\n parent: ReactiveEffect | undefined = undefined;\n computed?: boolean;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n onError?: (error: Error) => void;\n // 运行前清理(onEffectCleanup 注册的)\n _cleanups: Array<() => void> = [];\n\n constructor(\n public fn: () => T,\n public scheduler?: (...args: unknown[]) => unknown,\n ) {\n // 自动注册到当前活跃的 effectScope\n const scope = getActiveEffectScope();\n if (scope && scope.active) {\n scope.effects.push(this);\n }\n }\n\n run(): T | undefined {\n if (!this.active) {\n return undefined;\n }\n\n // 在重新执行前调用 cleanup\n if (this._cleanups.length > 0) {\n for (let i = 0; i < this._cleanups.length; i++) {\n this._cleanups[i]!();\n }\n this._cleanups.length = 0;\n }\n\n const prevShouldTrack = shouldTrack;\n try {\n this.parent = activeEffect;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n activeEffect = this;\n shouldTrack = true;\n _trackDepth++;\n\n return this.fn();\n } catch (error) {\n if (this.onError) {\n this.onError(error as Error);\n return undefined;\n }\n throw error;\n } finally {\n _trackDepth--;\n activeEffect = this.parent;\n shouldTrack = prevShouldTrack;\n this.parent = undefined;\n }\n }\n\n stop(): void {\n if (this.active) {\n cleanupEffect(this);\n if (this._cleanups.length > 0) {\n for (let i = 0; i < this._cleanups.length; i++) {\n this._cleanups[i]!();\n }\n this._cleanups.length = 0;\n }\n if (this.onStop) {\n this.onStop();\n }\n this.active = false;\n this.scheduler = undefined;\n }\n }\n}\n\nfunction cleanupEffect(effect: ReactiveEffect) {\n const { deps } = effect;\n for (let i = 0; i < deps.length; i++) {\n deps[i]!.delete(effect);\n }\n deps.length = 0;\n}\n\n// ==================== 公共 API ====================\n\n// Function overloads for effect()\n// Non-lazy effect: fn returns void, preventing accidental return value usage\n\n/**\n * 创建一个响应式副作用并立即执行。\n *\n * 副作用函数会在执行期间自动追踪所使用的响应式属性,\n * 当这些属性发生变化时,副作用会重新执行。\n *\n * @param fn - 副作用函数,返回 void\n * @param options - 配置选项\n * @param options.lazy - 是否延迟执行(false 时立即执行)\n * @param options.scheduler - 自定义调度器,替代默认的立即执行行为\n * @param options.allowRecurse - 是否允许副作用递归触发自身\n * @param options.onStop - 副作用停止时的回调\n * @param options.onTrack - 依赖被追踪时的调试回调\n * @param options.onTrigger - 依赖被触发时的调试回调\n * @returns 副作用运行器,可调用 run() 手动执行或 stop() 停止\n */\nexport function effect(\n fn: () => void,\n options?: {\n lazy?: false;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n },\n): ReactiveEffectRunner<void>;\n\n// Lazy effect: preserves generic return value type (used by computed etc.)\nexport function effect<T>(\n fn: () => T,\n options: {\n lazy: true;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n },\n): ReactiveEffectRunner<T>;\n\n// 统一实现签名\nexport function effect<T = unknown>(\n fn: () => T,\n options?: {\n lazy?: boolean;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n onError?: (error: Error) => void;\n },\n): ReactiveEffectRunner<T> {\n const _effect = new ReactiveEffect(fn);\n if (options) {\n // 仅提取已知合法选项,防止覆盖内部属性(如 fn、active)\n _effect.scheduler = options.scheduler;\n _effect.allowRecurse = options.allowRecurse;\n _effect.onStop = options.onStop;\n _effect.onTrack = options.onTrack;\n _effect.onTrigger = options.onTrigger;\n _effect.onError = options.onError;\n }\n if (!options || !options.lazy) {\n _effect.run();\n }\n const runner = _effect.run.bind(_effect) as ReactiveEffectRunner<T>;\n runner.effect = _effect;\n return runner;\n}\n\n/**\n * 停止一个响应式副作用。\n * 清理所有依赖关系,并调用 onStop 回调。\n *\n * @param runner - 由 effect() 返回的副作用运行器\n */\nexport function stop(runner: ReactiveEffectRunner): void {\n runner.effect.stop();\n}\n\n/**\n * 暂停依赖追踪。\n * 调用后,响应式属性的读取不会建立依赖关系。\n * 可通过 resetTracking() 恢复。\n */\nexport function pauseTracking(): void {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\n\n/**\n * 启用依赖追踪。\n * 将当前追踪状态压入栈中并设为 true。\n * 可通过 resetTracking() 恢复到之前的状态。\n */\nexport function enableTracking(): void {\n trackStack.push(shouldTrack);\n shouldTrack = true;\n}\n\n/**\n * 重置依赖追踪状态到上一次暂停/启用之前的状态。\n * 从追踪栈中弹出最近的状态并恢复。\n */\nexport function resetTracking(): void {\n const last = trackStack.pop();\n shouldTrack = last === undefined ? true : last;\n}\n\n/**\n * 批量执行函数,期间暂停依赖追踪。\n * 与 signalBatch 不同,batch 侧重于暂停追踪而非延迟通知。\n * 支持嵌套调用,内层 batch 不会提前恢复追踪状态。\n *\n * @param fn - 需要批量执行的函数\n *\n * @example\n * ```ts\n * batch(() => {\n * state.a = 1; // 不会触发依赖更新\n * state.b = 2; // 不会触发依赖更新\n * }); // 函数结束后恢复追踪\n * ```\n */\nexport function batch(fn: () => void): void {\n const stackLength = trackStack.length;\n pauseTracking();\n try {\n fn();\n } finally {\n // 恢复到 batch 调用前的 stack 长度,确保嵌套安全\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n }\n}\n\n/**\n * batchAsync - like batch but supports async functions.\n * Pauses tracking during fn execution (including after await),\n * and restores tracking state when fn completes (or throws).\n * Returns a Promise.\n */\nexport function batchAsync(fn: () => void | Promise<void>): Promise<void> {\n const stackLength = trackStack.length;\n pauseTracking();\n const restoreTracking = () => {\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n };\n try {\n const result = fn();\n if (result && typeof result === 'object' && 'then' in result) {\n return (result as Promise<void>).finally(restoreTracking);\n }\n // 同步路径:立即恢复 tracking 状态\n restoreTracking();\n return Promise.resolve();\n } catch (e) {\n restoreTracking();\n return Promise.reject(e);\n }\n}\n\n/**\n * untrack - execute fn without tracking dependencies.\n * Semantically different from batch: untrack means \"run but don't track\".\n * Returns the return value of fn.\n */\nexport function untrack<T>(fn: () => T): T {\n const stackLength = trackStack.length;\n pauseTracking();\n try {\n return fn();\n } finally {\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n }\n}\n\n/**\n * 在当前活跃的 effect 上注册一个清理回调。\n * 该回调会在 effect 重新执行前或停止时被调用,用于清理副作用资源。\n *\n * @param fn - 清理回调函数\n * @param failSilently - 当没有活跃 effect 时是否静默失败(默认 false,开发模式下会发出警告)\n *\n * @example\n * ```ts\n * effect(() => {\n * const timer = setInterval(() => console.log('tick'), 1000);\n * onEffectCleanup(() => clearInterval(timer));\n * });\n * ```\n */\nexport function onEffectCleanup(fn: () => void, failSilently = false): void {\n if (activeEffect === undefined) {\n if (!failSilently && __DEV__) {\n warn('onEffectCleanup() was called when there was no active effect to associate with.');\n }\n return;\n }\n activeEffect._cleanups.push(fn);\n}\n\n// ==================== 辅助 ====================\n\n/**\n * 检查给定的键是否为有效的整数键。\n * 用于判断数组索引是否为合法的整数值。\n *\n * @param key - 需要检查的键值\n * @returns 如果是有效的整数键返回 true,否则返回 false\n */\nexport function isIntegerKey(key: unknown): boolean {\n return (\n typeof key === 'string' &&\n key !== 'NaN' &&\n key[0] !== '-' &&\n '' + parseInt(key, 10) === key &&\n Number.isSafeInteger(Number(key))\n );\n}\n","// src/ref.ts\n// Ref 响应式引用\n// 复用 @lytjs/common-is: isObject, hasChanged\n\nimport { isObject, hasChanged } from '@lytjs/common-is';\nimport { warn } from '@lytjs/common-error';\nimport { unsafeCast } from '@lytjs/common-assertions';\nimport { track, trigger, getActiveEffect, getShouldTrack, createDep } from './effect';\nimport type { Dep } from './effect';\nimport { TrackOpTypes, TriggerOpTypes } from './constants';\nimport { toRaw, isRef } from './shared';\nimport { reactive } from './reactive';\n\n// ==================== Ref 类型 ====================\n\n/** track/trigger 中使用的类 ref 对象的内部接口 */\nexport interface RefLike<T = unknown> {\n dep: Dep;\n __v_isRef?: boolean;\n value: T;\n}\n\n/** trackRefValue/triggerRefValue 所需的最小接口 */\ninterface TrackableRef {\n dep: Dep;\n}\n\nexport interface Ref<T = unknown> {\n value: T;\n __v_isRef: true;\n}\n\nexport interface ShallowRef<T = unknown> extends Ref<T> {\n __v_isShallow: true;\n}\n\nexport interface ComputedRef<T = unknown> extends Ref<T> {\n __v_isComputed: true;\n}\n\n// ==================== Ref 类 ====================\n\nclass RefImpl<T> {\n private _value: T;\n private _rawValue: T;\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\n public dep: Dep = createDep();\n public readonly __v_isRef = true;\n public readonly __v_isShallow?: boolean;\n\n constructor(value: T, isShallow: boolean) {\n this.__v_isShallow = isShallow || undefined;\n this._rawValue = isShallow ? value : toRaw(value);\n // toReactive 仅对对象类型生效,非对象值直接赋值。\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\n this._value = isShallow ? value : (toReactive(value as object) as T);\n }\n\n get value(): T {\n trackRefValue(this);\n return this._value;\n }\n\n set value(newVal: T) {\n const useDirectValue = this.__v_isShallow;\n newVal = useDirectValue ? newVal : toRaw(newVal);\n if (hasChanged(newVal, this._rawValue)) {\n const oldVal = this._rawValue;\n this._rawValue = newVal;\n // toReactive 仅对对象类型生效,非对象值直接赋值。\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\n this._value = useDirectValue ? newVal : (toReactive(newVal as object) as T);\n triggerRefValue(this, newVal, oldVal);\n }\n }\n}\n\nclass ShallowRefImpl<T> {\n private _value: T;\n private _rawValue: T;\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\n public dep: Dep = createDep();\n public readonly __v_isRef = true;\n public readonly __v_isShallow = true as const;\n\n constructor(value: T) {\n this._rawValue = value;\n this._value = value;\n }\n\n get value(): T {\n trackRefValue(this);\n return this._value;\n }\n\n set value(newVal: T) {\n if (hasChanged(newVal, this._rawValue)) {\n const oldVal = this._rawValue;\n this._rawValue = newVal;\n this._value = newVal;\n triggerRefValue(this, newVal, oldVal);\n }\n }\n}\n\n// ==================== 追踪与触发 ====================\n\nexport function trackRefValue(ref: TrackableRef): void {\n if (getShouldTrack() && getActiveEffect()) {\n track(ref, TrackOpTypes.GET, 'value');\n }\n}\n\nexport function triggerRefValue(ref: TrackableRef, newVal?: unknown, oldVal?: unknown): void {\n trigger(ref, TriggerOpTypes.SET, 'value', newVal, oldVal);\n}\n\n// ==================== 公共 API ====================\n\nexport function ref<T extends object | string | number | boolean | null | undefined>(\n value: T,\n): Ref<T> {\n if (isRef(value)) {\n // FIX: P1-07 ref() 接受 ShallowRef 时添加 DEV 警告,\n // 提醒用户 ShallowRef 语义与 Ref 不同,直接返回可能导致意外行为\n // FIX: P2-34 使用类型守卫替代类型断言\n if (__DEV__ && isShallowRef(value)) {\n warn(\n 'ref() received a ShallowRef value. ' +\n 'ShallowRef and Ref have different reactivity semantics. ' +\n 'If this is intentional, use shallowRef() instead.',\n );\n }\n return value as Ref<T>;\n }\n // 双重断言是必要的:RefImpl 实现了 Ref 接口所需的 value/__v_isRef 属性,\n // 但 TypeScript 无法自动推断类实例满足接口(私有成员导致结构不兼容)。\n return unsafeCast<Ref<T>>(new RefImpl(value, false));\n}\n\nexport function shallowRef<T>(value: T): ShallowRef<T> {\n if (isRef(value)) return unsafeCast<ShallowRef<T>>(value);\n return unsafeCast<ShallowRef<T>>(new ShallowRefImpl(value));\n}\n\nexport function triggerRef<T>(ref: ShallowRef<T>): void {\n triggerRefValue(unsafeCast<TrackableRef>(ref), ref.value);\n}\n\nexport { isRef } from './shared';\n\n// FIX: P2-8 添加类型谓词:isShallowRef 和 isComputedRef\n/**\n * 检查值是否为 ShallowRef\n * 类型谓词:缩小类型到 ShallowRef<T>\n */\nexport function isShallowRef<T = unknown>(r: unknown): r is ShallowRef<T> {\n return isRef(r) && !!(r as ShallowRef<T>).__v_isShallow;\n}\n\n/**\n * 检查值是否为 ComputedRef\n * 类型谓词:缩小类型到 ComputedRef<T>\n */\nexport function isComputedRef<T = unknown>(r: unknown): r is ComputedRef<T> {\n return isRef(r) && !!(r as ComputedRef<T>).__v_isComputed;\n}\n\n// FIX: P2-06 unref 类型守卫增强:添加明确的返回类型注释\n// unref 如果参数是 Ref 则返回 .value,否则返回参数本身\nexport function unref<T>(r: T | Ref<T>): T {\n // FIX: P2-34 使用类型守卫替代类型断言,P2-38 移除不必要的 as\n // FIX: DTS build error - 使用类型断言确保类型正确\n return isRef(r) ? (r as Ref<T>).value : r;\n}\n\nexport function toRef<T extends object, K extends keyof T>(object: T, key: K): Ref<T[K]> {\n if (isRef(object[key])) return unsafeCast<Ref<T[K]>>(object[key]);\n return unsafeCast<Ref<T[K]>>(new ObjectRefImpl(object, key));\n}\n\nexport function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {\n const result = {} as { [K in keyof T]: Ref<T[K]> };\n for (const key in object) {\n result[key] = toRef(object, key);\n }\n return result;\n}\n\nexport function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {\n return unsafeCast<Ref<T>>(new CustomRefImpl(factory));\n}\n\n/**\n * 将值规范化为非 ref 值。\n * 如果是 Ref 则返回 .value,如果是函数则调用并返回结果,否则直接返回。\n * Vue 3.3+ 新增工具函数。\n */\nexport function toValue<T>(source: T | Ref<T> | (() => T)): T {\n // FIX: P2-34 使用类型守卫替代类型断言\n // FIX: DTS build error - 使用类型断言确保类型正确\n if (isRef(source)) return (source as Ref<T>).value;\n if (typeof source === 'function') {\n // FIX: P2-35 添加类型守卫确保 source 是函数后再调用\n return (source as () => T)();\n }\n return source as T;\n}\n\n// ==================== 内部实现类 ====================\n\nclass ObjectRefImpl<T extends object, K extends keyof T> {\n public readonly __v_isRef = true;\n\n constructor(\n private readonly _object: T,\n private readonly _key: K,\n ) {}\n\n get value(): T[K] {\n return this._object[this._key];\n }\n\n set value(newVal: T[K]) {\n this._object[this._key] = newVal;\n }\n}\n\nclass CustomRefImpl<T> {\n public readonly __v_isRef = true;\n public dep: Dep = createDep();\n private readonly _getter: () => T;\n private readonly _setter: (value: T) => void;\n\n constructor(factory: CustomRefFactory<T>) {\n const { get, set } = factory(\n () => trackRefValue(this),\n () => triggerRefValue(this),\n );\n this._getter = get;\n this._setter = set;\n }\n\n get value(): T {\n return this._getter();\n }\n\n set value(newVal: T) {\n this._setter(newVal);\n }\n}\n\n// ==================== 辅助函数 ====================\n\ntype CustomRefFactory<T> = (\n track: () => void,\n trigger: () => void,\n) => { get: () => T; set: (value: T) => void };\n\nfunction toReactive<T>(value: T): T {\n return isObject(value) ? (reactive(value as object) as T) : value;\n}\n","// src/async-computed.ts\n// @lytjs/reactivity - 异步 computed\n\ndeclare const __DEV__: boolean;\n\nimport { trackRefValue, triggerRefValue } from './ref';\nimport type { Ref } from './ref';\nimport { createDep } from './effect';\nimport type { Dep } from './effect';\nimport { effect, stop } from './effect';\nimport { unsafeCast } from '@lytjs/common-assertions';\nimport type { ReactiveEffectRunner } from './types';\nimport { warn } from '@lytjs/common-error';\n\n// ==================== AsyncComputedRef 类型 ====================\n\n/**\n * 异步计算属性引用\n * 扩展了标准 Ref,增加了 loading 和 error 状态\n */\nexport interface AsyncComputedRef<T = unknown> extends Ref<T | undefined> {\n /** 异步计算是否正在进行 */\n readonly loading: boolean;\n /** 上一次异步计算的错误(如果有) */\n readonly error: unknown;\n}\n\n// ==================== AsyncComputedRefImpl ====================\n\nclass AsyncComputedRefImpl<T> {\n private _value: T | undefined;\n private _loading: boolean = false;\n private _error: unknown = undefined;\n private _effect: ReactiveEffectRunner<void> | null = null;\n private _version = 0;\n\n public readonly __v_isRef = true;\n public dep: Dep = createDep();\n\n constructor(\n private readonly _getter: () => Promise<T>,\n initialValue?: T,\n lazy: boolean = false,\n ) {\n this._value = initialValue;\n\n if (!lazy) {\n // 非懒加载模式:使用 effect 追踪依赖,依赖变化时重新执行 getter\n this._effect = effect(() => {\n this._runGetter();\n });\n }\n }\n\n /**\n * 执行 getter 并处理 Promise 结果\n */\n private _runGetter(): void {\n // 标记为 loading\n this._loading = true;\n this._error = undefined;\n\n // FIX: P2-3 loading 状态变化同步触发通知。\n // 在设置 _loading = true 后立即调用 triggerRefValue,\n // 确保订阅者能感知到 loading 状态的变化(如显示 loading 指示器),\n // 而不是等到异步操作完成后才统一通知。\n triggerRefValue(this);\n\n // 递增版本号,用于竞态检测\n const currentVersion = ++this._version;\n\n // 调用 getter 获取 Promise\n const result = this._getter();\n // FIX: P1-06 getter 返回非 Promise 时包装为 Promise.resolve(),\n // 避免非 Promise 返回值导致 .then() 调用失败\n const promise = result instanceof Promise ? result : Promise.resolve(result);\n\n // 使用 Promise.then() 非阻塞处理\n promise.then(\n (value) => {\n if (currentVersion !== this._version) return; // 过期结果,忽略\n this._value = value;\n this._loading = false;\n this._error = undefined;\n // 触发 ref 更新\n triggerRefValue(this);\n },\n (err) => {\n if (currentVersion !== this._version) return; // 过期结果,忽略\n // FIX: P2-02 异步 computed 错误处理完善:在 DEV 模式下发出警告\n if (__DEV__) {\n console.warn('[lytjs/async-computed] Async computed error:', err);\n }\n this._error = err;\n this._loading = false;\n // 触发 ref 更新\n triggerRefValue(this);\n },\n );\n }\n\n /**\n * 手动触发执行(用于懒加载模式)\n */\n execute(): void {\n if (this._loading) return;\n this._runGetter();\n }\n\n get value(): T | undefined {\n trackRefValue(this);\n return this._value;\n }\n\n set value(_newVal: T | undefined) {\n if (__DEV__) {\n warn('Write operation failed: asyncComputed value is readonly');\n }\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): unknown {\n return this._error;\n }\n\n /**\n * 停止 effect 追踪\n */\n dispose(): void {\n this._version++; // 使所有 pending 的 promise 回调失效\n if (this._effect) {\n stop(this._effect);\n this._effect = null;\n }\n // FIX: P2-07 dispose 时清空错误和值,避免悬挂的异步回调更新已销毁的 computed\n this._error = null;\n this._value = undefined;\n // FIX: P1-2 REACTIVITY-NEW-03 - dispose 时通知订阅者,避免订阅者持有过期值\n triggerRefValue(this);\n }\n}\n\n// ==================== 公共 API ====================\n\n/**\n * 创建异步计算属性\n * 当 getter 中的响应式依赖变化时,自动重新执行 getter\n *\n * @param getter 返回 Promise 的函数\n * @param initialValue 初始值(Promise pending 时的值)\n * @returns AsyncComputedRef\n */\nexport function asyncComputed<T>(getter: () => Promise<T>, initialValue?: T): AsyncComputedRef<T> {\n return unsafeCast<AsyncComputedRef<T>>(new AsyncComputedRefImpl<T>(getter, initialValue, false));\n}\n\n/**\n * 创建异步状态(懒加载模式)\n * factory 只执行一次,适合数据请求场景\n *\n * @param factory 返回 Promise 的函数\n * @param initialValue 初始值\n * @returns AsyncComputedRef\n */\nexport function useAsyncState<T>(factory: () => Promise<T>, initialValue?: T): AsyncComputedRef<T> {\n const impl = new AsyncComputedRefImpl<T>(factory, initialValue, true);\n\n // 立即执行一次\n impl.execute();\n\n return unsafeCast<AsyncComputedRef<T>>(impl);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/effect.ts","../src/ref.ts","../src/async-computed.ts"],"names":["effect","REACTIVITY_MAX_TRIGGER_DEPTH","error","unsafeCast"],"mappings":"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","file":"async.mjs","sourcesContent":["// src/constants.ts\r\n// 内部符号常量\r\n\r\n// DEV 检测方式说明:\r\n// 统一使用 typeof 检测方式,兼容编译时 define/replace 替换和未配置构建替换的场景。\r\n// 当打包工具(如 rollup/esbuild)通过 define 插件将 __DEV__ 替换为字面量 true/false 时,\r\n// typeof 检测会被优化为直接的字面量判断,实现死代码消除(DCE)。\r\n// 当未配置构建替换时,typeof 检测也能安全降级为 false,避免 ReferenceError。\r\nconst DEV = typeof __DEV__ !== 'undefined' ? __DEV__ : false;\r\n\r\nexport const RefSymbol: unique symbol = Symbol(DEV ? 'ref' : undefined);\r\nexport const ShallowRefSymbol: unique symbol = Symbol(DEV ? 'shallow_ref' : undefined);\r\nexport const ComputedRefSymbol: unique symbol = Symbol(DEV ? 'computed_ref' : undefined);\r\nexport const ReactiveSymbol: unique symbol = Symbol(DEV ? 'reactive' : undefined);\r\nexport const ReadonlySymbol: unique symbol = Symbol(DEV ? 'readonly' : undefined);\r\nexport const SignalSymbol: unique symbol = Symbol(DEV ? 'signal' : undefined);\r\nexport const ComputedSignalSymbol: unique symbol = Symbol(DEV ? 'computed_signal' : undefined);\r\n\r\n// ReactiveFlags - 用于 Proxy handler 内部标记\r\nexport const ReactiveFlags = {\r\n IS_REACTIVE: '__v_isReactive',\r\n IS_READONLY: '__v_isReadonly',\r\n IS_SHALLOW: '__v_isShallow',\r\n IS_REF: '__v_isRef',\r\n RAW: '__v_raw',\r\n SKIP: '__v_skip',\r\n} as const;\r\n\r\n// Track/Trigger 操作类型\r\nexport const TrackOpTypes = {\r\n GET: 'get',\r\n HAS: 'has',\r\n ITERATE: 'iterate',\r\n} as const;\r\n\r\nexport const TriggerOpTypes = {\r\n SET: 'set',\r\n ADD: 'add',\r\n DELETE: 'delete',\r\n CLEAR: 'clear',\r\n} as const;\r\n\r\n// 内部共享常量\r\nexport const ITERATE_KEY = Symbol('iterate');\r\n","// src/effect.ts\r\n// 响应式副作用系统核心\r\n\r\nimport { ITERATE_KEY } from './constants';\r\nimport type { ReactiveEffectRunner } from './types';\r\nimport { warn } from '@lytjs/common-error';\r\nimport { _isSignalUntracked } from './signal';\r\nimport { getActiveEffectScope } from './effect-scope';\r\nimport { REACTIVITY_MAX_TRIGGER_DEPTH } from '@lytjs/common-constants';\r\n\r\n// ==================== 全局状态 ====================\r\n\r\nlet activeEffect: ReactiveEffect | undefined;\r\nlet _trackDepth = 0;\r\nconst targetMap = new WeakMap<object, Map<string | symbol, Dep>>();\r\nlet shouldTrack = true;\r\nconst trackStack: boolean[] = [];\r\n\r\n// ==================== 首次渲染优化 ====================\r\n\r\n/** 标记当前是否处于首次渲染优化期间 */\r\nlet isFirstRenderPass = false;\r\n\r\n/** 记录被跳过的追踪次数(用于调试和测试验证) */\r\nlet skippedTrackingCount = 0;\r\n\r\n/**\r\n * 包裹首次渲染过程,期间禁用响应式依赖收集。\r\n * 支持嵌套调用:如果外层已经处于首次渲染优化期间,\r\n * 内层调用不会提前重置标志位。\r\n */\r\nexport function withFirstRenderOptimization<T>(fn: () => T): T {\r\n const wasFirstRender = isFirstRenderPass;\r\n isFirstRenderPass = true;\r\n try {\r\n return fn();\r\n } finally {\r\n if (!wasFirstRender) {\r\n isFirstRenderPass = false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 检查当前是否应跳过响应式依赖收集。\r\n * 在 withFirstRenderOptimization 执行期间返回 true。\r\n */\r\nexport function shouldSkipTracking(): boolean {\r\n return isFirstRenderPass;\r\n}\r\n\r\n/**\r\n * 获取被跳过的追踪次数(用于调试和测试)。\r\n */\r\nexport function getSkippedTrackingCount(): number {\r\n return skippedTrackingCount;\r\n}\r\n\r\n/**\r\n * 重置被跳过的追踪计数(用于测试)。\r\n */\r\nexport function resetSkippedTrackingCount(): void {\r\n skippedTrackingCount = 0;\r\n}\r\n\r\n// 只读访问器,防止外部修改内部状态\r\n\r\n/**\r\n * 获取当前活跃的 ReactiveEffect 实例。\r\n * 在 effect 执行期间返回当前正在运行的 effect,否则返回 undefined。\r\n *\r\n * @returns 当前活跃的 effect,如果没有则返回 undefined\r\n */\r\nexport function getActiveEffect(): ReactiveEffect | undefined {\r\n return activeEffect;\r\n}\r\n\r\n/**\r\n * 获取当前是否应该进行依赖追踪。\r\n * 可通过 pauseTracking/enableTracking 控制。\r\n *\r\n * @returns 是否应该进行依赖追踪\r\n */\r\nexport function getShouldTrack(): boolean {\r\n return shouldTrack;\r\n}\r\n\r\n// ==================== Dep ====================\r\n\r\n/**\r\n * 依赖集合类型,存储订阅某个响应式属性的所有 ReactiveEffect。\r\n */\r\nexport type Dep = Set<ReactiveEffect>;\r\n\r\n/**\r\n * 创建一个新的 Dep(依赖集合)。\r\n *\r\n * @returns 新的空 Dep 实例\r\n */\r\nexport const createDep = (): Dep => {\r\n return new Set() as Dep;\r\n};\r\n\r\n// ==================== Track / Trigger ====================\r\n\r\n/**\r\n * Maximum depth for nested trigger() calls to prevent infinite reactivity loops.\r\n * When triggerDepth exceeds this limit, further triggers are silently dropped\r\n * and a warning is emitted in DEV mode.\r\n */\r\nlet triggerDepth = 0;\r\n\r\n/**\r\n * 追踪响应式属性的依赖关系。\r\n * 当响应式属性被读取时调用,将当前活跃的 effect 记录为该属性的依赖。\r\n *\r\n * @param target - 被追踪的响应式对象\r\n * @param _type - 追踪操作类型(如 'get'、'has'、'iterate')\r\n * @param key - 被追踪的属性键\r\n */\r\nexport function track(target: object, _type: string, key: string | symbol) {\r\n if (!shouldTrack || activeEffect === undefined) return;\r\n // signal untrack 桥接:signalUntrack 期间跳过 effect 系统的依赖收集\r\n if (_isSignalUntracked()) return;\r\n\r\n let depsMap = targetMap.get(target);\r\n if (!depsMap) {\r\n targetMap.set(target, (depsMap = new Map()));\r\n }\r\n\r\n let dep = depsMap.get(key);\r\n if (!dep) {\r\n depsMap.set(key, (dep = createDep()));\r\n }\r\n\r\n trackEffect(dep);\r\n\r\n // 调试:触发 onTrack\r\n if (__DEV__ && activeEffect.onTrack) {\r\n activeEffect.onTrack({\r\n effect: activeEffect,\r\n target,\r\n type: _type,\r\n key,\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * 将当前活跃的 effect 添加到指定的依赖集合中。\r\n * 在首次渲染优化期间会跳过依赖收集。\r\n *\r\n * @param dep - 目标依赖集合\r\n */\r\nexport function trackEffect(dep: Dep) {\r\n // 首次渲染优化:跳过依赖收集\r\n if (shouldSkipTracking()) {\r\n skippedTrackingCount++;\r\n return;\r\n }\r\n // FIX: P1-01 移除重复的 shouldTrack/activeEffect 检查,\r\n // 这些检查已在调用方 track() 中完成,此处只需关注 dep 操作\r\n // FIX: P0-5 添加防御性检查,避免非空断言在公共 API 调用时不安全\r\n if (activeEffect && !dep.has(activeEffect)) {\r\n dep.add(activeEffect);\r\n activeEffect.deps.push(dep);\r\n }\r\n}\r\n\r\n/**\r\n * 触发响应式属性的依赖更新。\r\n * 当响应式属性被修改时调用,通知所有依赖该属性的 effect 重新执行。\r\n *\r\n * 根据操作类型(add/delete/set/clear)会触发不同的依赖集合:\r\n * - `add`:触发属性本身 + ITERATE_KEY(或数组 length)\r\n * - `delete`:触发属性本身 + ITERATE_KEY\r\n * - `set`:触发属性本身 + 数组 length(如果是整数键)\r\n * - `clear`:触发所有属性的依赖\r\n *\r\n * @param target - 被修改的响应式对象\r\n * @param type - 触发操作类型('set' | 'add' | 'delete' | 'clear')\r\n * @param key - 被修改的属性键\r\n * @param _newValue - 新值(可选,用于调试)\r\n * @param _oldValue - 旧值(可选,用于调试)\r\n */\r\nexport function trigger(\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n const depsMap = targetMap.get(target);\r\n if (!depsMap) return;\r\n\r\n const deps: (Dep | undefined)[] = [];\r\n\r\n if (type === 'clear') {\r\n deps.push(...depsMap.values());\r\n } else {\r\n if (key !== undefined) {\r\n deps.push(depsMap.get(key));\r\n }\r\n\r\n if (type === 'add') {\r\n if (Array.isArray(target)) {\r\n deps.push(depsMap.get('length'));\r\n } else {\r\n deps.push(depsMap.get(ITERATE_KEY));\r\n }\r\n } else if (type === 'delete') {\r\n if (!Array.isArray(target)) {\r\n deps.push(depsMap.get(ITERATE_KEY));\r\n }\r\n } else if (type === 'set') {\r\n if (Array.isArray(target) && isIntegerKey(key)) {\r\n deps.push(depsMap.get('length'));\r\n }\r\n }\r\n }\r\n\r\n const effects: ReactiveEffect[] = [];\r\n for (const dep of deps) {\r\n if (dep) {\r\n for (const effect of dep) {\r\n effects.push(effect);\r\n }\r\n }\r\n }\r\n\r\n // 去重:同一个 effect 可能同时存在于多个 dep 中\r\n triggerEffects([...new Set(effects)], target, type, key, newValue, oldValue);\r\n}\r\n\r\n/**\r\n * 执行一组 effect 的触发。\r\n * 优先执行 computed effect,再执行普通 effect。\r\n * 内置递归深度限制,超过最大深度时静默丢弃并发出警告。\r\n *\r\n * @param effects - 需要触发的 ReactiveEffect 数组\r\n * @param target - 被修改的目标对象(用于调试回调)\r\n * @param type - 触发操作类型(用于调试回调)\r\n * @param key - 被修改的属性键(用于调试回调)\r\n * @param newValue - 新值(用于调试回调)\r\n * @param oldValue - 旧值(用于调试回调)\r\n */\r\nexport function triggerEffects(\r\n effects: ReactiveEffect[],\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n if (triggerDepth > REACTIVITY_MAX_TRIGGER_DEPTH) {\r\n // FIX: P2-1 triggerDepth 超限时改为 warn + 静默丢弃,与 Vue 3 行为一致。\r\n // 之前直接 throw Error 过于激进,会导致整个响应式链断裂。\r\n // 改为仅发出警告并丢弃后续 trigger,避免因单个无限循环导致整个应用崩溃。\r\n if (__DEV__) {\r\n warn(\r\n `[lytjs/reactivity] Maximum trigger depth (${REACTIVITY_MAX_TRIGGER_DEPTH}) exceeded. ` +\r\n `Possible infinite reactivity loop detected. Further triggers are silently dropped. ` +\r\n `triggerDepth=${triggerDepth}`,\r\n );\r\n }\r\n return;\r\n }\r\n triggerDepth++;\r\n try {\r\n for (const effect of effects) {\r\n if (effect.computed) {\r\n triggerEffect(effect, target, type, key, newValue, oldValue);\r\n }\r\n }\r\n for (const effect of effects) {\r\n if (!effect.computed) {\r\n triggerEffect(effect, target, type, key, newValue, oldValue);\r\n }\r\n }\r\n } finally {\r\n triggerDepth--;\r\n }\r\n}\r\n\r\nfunction triggerEffect(\r\n effect: ReactiveEffect,\r\n target: object,\r\n type: string,\r\n key?: string | symbol,\r\n newValue?: unknown,\r\n oldValue?: unknown,\r\n) {\r\n if (effect !== activeEffect || effect.allowRecurse) {\r\n // 调用 onTrigger 回调(用于调试)\r\n if (__DEV__ && effect.onTrigger) {\r\n effect.onTrigger({\r\n effect,\r\n target,\r\n type,\r\n key,\r\n newValue,\r\n oldValue,\r\n });\r\n }\r\n if (effect.scheduler) {\r\n effect.scheduler();\r\n } else {\r\n effect.run();\r\n }\r\n }\r\n}\r\n\r\n// ==================== ReactiveEffect ====================\r\n\r\n/**\r\n * 响应式副作用类。\r\n * 封装一个副作用函数,支持依赖自动收集、调度执行和手动停止。\r\n *\r\n * 创建时会自动注册到当前活跃的 effectScope 中。\r\n *\r\n * @typeParam T - 副作用函数的返回值类型\r\n *\r\n * @example\r\n * ```ts\r\n * const eff = new ReactiveEffect(() => {\r\n * console.log(state.count);\r\n * });\r\n * eff.run(); // 执行副作用,同时收集依赖\r\n * eff.stop(); // 停止副作用,清理所有依赖\r\n * ```\r\n */\r\nexport class ReactiveEffect<T = unknown> {\r\n active = true;\r\n deps: Dep[] = [];\r\n parent: ReactiveEffect | undefined = undefined;\r\n computed?: boolean;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n onError?: (error: Error) => void;\r\n // 运行前清理(onEffectCleanup 注册的)\r\n _cleanups: Array<() => void> = [];\r\n\r\n constructor(\r\n public fn: () => T,\r\n public scheduler?: (...args: unknown[]) => unknown,\r\n ) {\r\n // 自动注册到当前活跃的 effectScope\r\n const scope = getActiveEffectScope();\r\n if (scope && scope.active) {\r\n scope.effects.push(this);\r\n }\r\n }\r\n\r\n run(): T | undefined {\r\n if (!this.active) {\r\n return undefined;\r\n }\r\n\r\n // 在重新执行前调用 cleanup\r\n if (this._cleanups.length > 0) {\r\n for (let i = 0; i < this._cleanups.length; i++) {\r\n this._cleanups[i]!();\r\n }\r\n this._cleanups.length = 0;\r\n }\r\n\r\n const prevShouldTrack = shouldTrack;\r\n try {\r\n this.parent = activeEffect;\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n activeEffect = this;\r\n shouldTrack = true;\r\n _trackDepth++;\r\n\r\n return this.fn();\r\n } catch (error) {\r\n if (this.onError) {\r\n this.onError(error as Error);\r\n return undefined;\r\n }\r\n throw error;\r\n } finally {\r\n _trackDepth--;\r\n activeEffect = this.parent;\r\n shouldTrack = prevShouldTrack;\r\n this.parent = undefined;\r\n }\r\n }\r\n\r\n stop(): void {\r\n if (this.active) {\r\n cleanupEffect(this);\r\n if (this._cleanups.length > 0) {\r\n for (let i = 0; i < this._cleanups.length; i++) {\r\n this._cleanups[i]!();\r\n }\r\n this._cleanups.length = 0;\r\n }\r\n if (this.onStop) {\r\n this.onStop();\r\n }\r\n this.active = false;\r\n this.scheduler = undefined;\r\n }\r\n }\r\n}\r\n\r\nfunction cleanupEffect(effect: ReactiveEffect) {\r\n const { deps } = effect;\r\n for (let i = 0; i < deps.length; i++) {\r\n deps[i]!.delete(effect);\r\n }\r\n deps.length = 0;\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\n// Function overloads for effect()\r\n// Non-lazy effect: fn returns void, preventing accidental return value usage\r\n\r\n/**\r\n * 创建一个响应式副作用并立即执行。\r\n *\r\n * 副作用函数会在执行期间自动追踪所使用的响应式属性,\r\n * 当这些属性发生变化时,副作用会重新执行。\r\n *\r\n * @param fn - 副作用函数,返回 void\r\n * @param options - 配置选项\r\n * @param options.lazy - 是否延迟执行(false 时立即执行)\r\n * @param options.scheduler - 自定义调度器,替代默认的立即执行行为\r\n * @param options.allowRecurse - 是否允许副作用递归触发自身\r\n * @param options.onStop - 副作用停止时的回调\r\n * @param options.onTrack - 依赖被追踪时的调试回调\r\n * @param options.onTrigger - 依赖被触发时的调试回调\r\n * @returns 副作用运行器,可调用 run() 手动执行或 stop() 停止\r\n */\r\nexport function effect(\r\n fn: () => void,\r\n options?: {\r\n lazy?: false;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n },\r\n): ReactiveEffectRunner<void>;\r\n\r\n// Lazy effect: preserves generic return value type (used by computed etc.)\r\nexport function effect<T>(\r\n fn: () => T,\r\n options: {\r\n lazy: true;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n },\r\n): ReactiveEffectRunner<T>;\r\n\r\n// 统一实现签名\r\nexport function effect<T = unknown>(\r\n fn: () => T,\r\n options?: {\r\n lazy?: boolean;\r\n scheduler?: (...args: unknown[]) => unknown;\r\n allowRecurse?: boolean;\r\n onStop?: () => void;\r\n onTrack?: (event: { effect: ReactiveEffect; target: object; key?: string | symbol; type: string }) => void;\r\n onTrigger?: (event: {\r\n effect: ReactiveEffect;\r\n target: object;\r\n key?: string | symbol;\r\n type: string;\r\n newValue?: unknown;\r\n oldValue?: unknown;\r\n }) => void;\r\n onError?: (error: Error) => void;\r\n },\r\n): ReactiveEffectRunner<T> {\r\n const _effect = new ReactiveEffect(fn);\r\n if (options) {\r\n // 仅提取已知合法选项,防止覆盖内部属性(如 fn、active)\r\n _effect.scheduler = options.scheduler;\r\n _effect.allowRecurse = options.allowRecurse;\r\n _effect.onStop = options.onStop;\r\n _effect.onTrack = options.onTrack;\r\n _effect.onTrigger = options.onTrigger;\r\n _effect.onError = options.onError;\r\n }\r\n if (!options || !options.lazy) {\r\n _effect.run();\r\n }\r\n const runner = _effect.run.bind(_effect) as ReactiveEffectRunner<T>;\r\n runner.effect = _effect;\r\n return runner;\r\n}\r\n\r\n/**\r\n * 停止一个响应式副作用。\r\n * 清理所有依赖关系,并调用 onStop 回调。\r\n *\r\n * @param runner - 由 effect() 返回的副作用运行器\r\n */\r\nexport function stop(runner: ReactiveEffectRunner): void {\r\n runner.effect.stop();\r\n}\r\n\r\n/**\r\n * 暂停依赖追踪。\r\n * 调用后,响应式属性的读取不会建立依赖关系。\r\n * 可通过 resetTracking() 恢复。\r\n */\r\nexport function pauseTracking(): void {\r\n trackStack.push(shouldTrack);\r\n shouldTrack = false;\r\n}\r\n\r\n/**\r\n * 启用依赖追踪。\r\n * 将当前追踪状态压入栈中并设为 true。\r\n * 可通过 resetTracking() 恢复到之前的状态。\r\n */\r\nexport function enableTracking(): void {\r\n trackStack.push(shouldTrack);\r\n shouldTrack = true;\r\n}\r\n\r\n/**\r\n * 重置依赖追踪状态到上一次暂停/启用之前的状态。\r\n * 从追踪栈中弹出最近的状态并恢复。\r\n */\r\nexport function resetTracking(): void {\r\n const last = trackStack.pop();\r\n shouldTrack = last === undefined ? true : last;\r\n}\r\n\r\n/**\r\n * 批量执行函数,期间暂停依赖追踪。\r\n * 与 signalBatch 不同,batch 侧重于暂停追踪而非延迟通知。\r\n * 支持嵌套调用,内层 batch 不会提前恢复追踪状态。\r\n *\r\n * @param fn - 需要批量执行的函数\r\n *\r\n * @example\r\n * ```ts\r\n * batch(() => {\r\n * state.a = 1; // 不会触发依赖更新\r\n * state.b = 2; // 不会触发依赖更新\r\n * }); // 函数结束后恢复追踪\r\n * ```\r\n */\r\nexport function batch(fn: () => void): void {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n try {\r\n fn();\r\n } finally {\r\n // 恢复到 batch 调用前的 stack 长度,确保嵌套安全\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n }\r\n}\r\n\r\n/**\r\n * batchAsync - like batch but supports async functions.\r\n * Pauses tracking during fn execution (including after await),\r\n * and restores tracking state when fn completes (or throws).\r\n * Returns a Promise.\r\n */\r\nexport function batchAsync(fn: () => void | Promise<void>): Promise<void> {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n const restoreTracking = () => {\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n };\r\n try {\r\n const result = fn();\r\n if (result && typeof result === 'object' && 'then' in result) {\r\n return (result as Promise<void>).finally(restoreTracking);\r\n }\r\n // 同步路径:立即恢复 tracking 状态\r\n restoreTracking();\r\n return Promise.resolve();\r\n } catch (e) {\r\n restoreTracking();\r\n return Promise.reject(e);\r\n }\r\n}\r\n\r\n/**\r\n * untrack - execute fn without tracking dependencies.\r\n * Semantically different from batch: untrack means \"run but don't track\".\r\n * Returns the return value of fn.\r\n */\r\nexport function untrack<T>(fn: () => T): T {\r\n const stackLength = trackStack.length;\r\n pauseTracking();\r\n try {\r\n return fn();\r\n } finally {\r\n while (trackStack.length > stackLength) {\r\n trackStack.pop();\r\n }\r\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\r\n }\r\n}\r\n\r\n/**\r\n * 在当前活跃的 effect 上注册一个清理回调。\r\n * 该回调会在 effect 重新执行前或停止时被调用,用于清理副作用资源。\r\n *\r\n * @param fn - 清理回调函数\r\n * @param failSilently - 当没有活跃 effect 时是否静默失败(默认 false,开发模式下会发出警告)\r\n *\r\n * @example\r\n * ```ts\r\n * effect(() => {\r\n * const timer = setInterval(() => console.log('tick'), 1000);\r\n * onEffectCleanup(() => clearInterval(timer));\r\n * });\r\n * ```\r\n */\r\nexport function onEffectCleanup(fn: () => void, failSilently = false): void {\r\n if (activeEffect === undefined) {\r\n if (!failSilently && __DEV__) {\r\n warn('onEffectCleanup() was called when there was no active effect to associate with.');\r\n }\r\n return;\r\n }\r\n activeEffect._cleanups.push(fn);\r\n}\r\n\r\n// ==================== 辅助 ====================\r\n\r\n/**\r\n * 检查给定的键是否为有效的整数键。\r\n * 用于判断数组索引是否为合法的整数值。\r\n *\r\n * @param key - 需要检查的键值\r\n * @returns 如果是有效的整数键返回 true,否则返回 false\r\n */\r\nexport function isIntegerKey(key: unknown): boolean {\r\n return (\r\n typeof key === 'string' &&\r\n key !== 'NaN' &&\r\n key[0] !== '-' &&\r\n '' + parseInt(key, 10) === key &&\r\n Number.isSafeInteger(Number(key))\r\n );\r\n}\r\n","// src/ref.ts\r\n// Ref 响应式引用\r\n// 复用 @lytjs/common-is: isObject, hasChanged\r\n\r\nimport { isObject, hasChanged } from '@lytjs/common-is';\r\nimport { warn } from '@lytjs/common-error';\r\nimport { unsafeCast } from '@lytjs/common-assertions';\r\nimport { track, trigger, getActiveEffect, getShouldTrack, createDep } from './effect';\r\nimport type { Dep } from './effect';\r\nimport { TrackOpTypes, TriggerOpTypes } from './constants';\r\nimport { toRaw, isRef } from './shared';\r\nimport { reactive } from './reactive';\r\n\r\n// ==================== Ref 类型 ====================\r\n\r\n/** track/trigger 中使用的类 ref 对象的内部接口 */\r\nexport interface RefLike<T = unknown> {\r\n dep: Dep;\r\n __v_isRef?: boolean;\r\n value: T;\r\n}\r\n\r\n/** trackRefValue/triggerRefValue 所需的最小接口 */\r\ninterface TrackableRef {\r\n dep: Dep;\r\n}\r\n\r\nexport interface Ref<T = unknown> {\r\n value: T;\r\n __v_isRef: true;\r\n}\r\n\r\nexport interface ShallowRef<T = unknown> extends Ref<T> {\r\n __v_isShallow: true;\r\n}\r\n\r\nexport interface ComputedRef<T = unknown> extends Ref<T> {\r\n __v_isComputed: true;\r\n}\r\n\r\n// ==================== Ref 类 ====================\r\n\r\nclass RefImpl<T> {\r\n private _value: T;\r\n private _rawValue: T;\r\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\r\n public dep: Dep = createDep();\r\n public readonly __v_isRef = true;\r\n public readonly __v_isShallow?: boolean;\r\n\r\n constructor(value: T, isShallow: boolean) {\r\n this.__v_isShallow = isShallow || undefined;\r\n this._rawValue = isShallow ? value : toRaw(value);\r\n // toReactive 仅对对象类型生效,非对象值直接赋值。\r\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\r\n this._value = isShallow ? value : (toReactive(value as object) as T);\r\n }\r\n\r\n get value(): T {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(newVal: T) {\r\n const useDirectValue = this.__v_isShallow;\r\n newVal = useDirectValue ? newVal : toRaw(newVal);\r\n if (hasChanged(newVal, this._rawValue)) {\r\n const oldVal = this._rawValue;\r\n this._rawValue = newVal;\r\n // toReactive 仅对对象类型生效,非对象值直接赋值。\r\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\r\n this._value = useDirectValue ? newVal : (toReactive(newVal as object) as T);\r\n triggerRefValue(this, newVal, oldVal);\r\n }\r\n }\r\n}\r\n\r\nclass ShallowRefImpl<T> {\r\n private _value: T;\r\n private _rawValue: T;\r\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\r\n public dep: Dep = createDep();\r\n public readonly __v_isRef = true;\r\n public readonly __v_isShallow = true as const;\r\n\r\n constructor(value: T) {\r\n this._rawValue = value;\r\n this._value = value;\r\n }\r\n\r\n get value(): T {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(newVal: T) {\r\n if (hasChanged(newVal, this._rawValue)) {\r\n const oldVal = this._rawValue;\r\n this._rawValue = newVal;\r\n this._value = newVal;\r\n triggerRefValue(this, newVal, oldVal);\r\n }\r\n }\r\n}\r\n\r\n// ==================== 追踪与触发 ====================\r\n\r\nexport function trackRefValue(ref: TrackableRef): void {\r\n if (getShouldTrack() && getActiveEffect()) {\r\n track(ref, TrackOpTypes.GET, 'value');\r\n }\r\n}\r\n\r\nexport function triggerRefValue(ref: TrackableRef, newVal?: unknown, oldVal?: unknown): void {\r\n trigger(ref, TriggerOpTypes.SET, 'value', newVal, oldVal);\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\nexport function ref<T extends object | string | number | boolean | null | undefined>(\r\n value: T,\r\n): Ref<T> {\r\n if (isRef(value)) {\r\n // FIX: P1-07 ref() 接受 ShallowRef 时添加 DEV 警告,\r\n // 提醒用户 ShallowRef 语义与 Ref 不同,直接返回可能导致意外行为\r\n // FIX: P2-34 使用类型守卫替代类型断言\r\n if (__DEV__ && isShallowRef(value)) {\r\n warn(\r\n 'ref() received a ShallowRef value. ' +\r\n 'ShallowRef and Ref have different reactivity semantics. ' +\r\n 'If this is intentional, use shallowRef() instead.',\r\n );\r\n }\r\n return value as Ref<T>;\r\n }\r\n // 双重断言是必要的:RefImpl 实现了 Ref 接口所需的 value/__v_isRef 属性,\r\n // 但 TypeScript 无法自动推断类实例满足接口(私有成员导致结构不兼容)。\r\n return unsafeCast<Ref<T>>(new RefImpl(value, false));\r\n}\r\n\r\nexport function shallowRef<T>(value: T): ShallowRef<T> {\r\n if (isRef(value)) return unsafeCast<ShallowRef<T>>(value);\r\n return unsafeCast<ShallowRef<T>>(new ShallowRefImpl(value));\r\n}\r\n\r\nexport function triggerRef<T>(ref: ShallowRef<T>): void {\r\n triggerRefValue(unsafeCast<TrackableRef>(ref), ref.value);\r\n}\r\n\r\nexport { isRef } from './shared';\r\n\r\n// FIX: P2-8 添加类型谓词:isShallowRef 和 isComputedRef\r\n/**\r\n * 检查值是否为 ShallowRef\r\n * 类型谓词:缩小类型到 ShallowRef<T>\r\n */\r\nexport function isShallowRef<T = unknown>(r: unknown): r is ShallowRef<T> {\r\n return isRef(r) && !!(r as ShallowRef<T>).__v_isShallow;\r\n}\r\n\r\n/**\r\n * 检查值是否为 ComputedRef\r\n * 类型谓词:缩小类型到 ComputedRef<T>\r\n */\r\nexport function isComputedRef<T = unknown>(r: unknown): r is ComputedRef<T> {\r\n return isRef(r) && !!(r as ComputedRef<T>).__v_isComputed;\r\n}\r\n\r\n// FIX: P2-06 unref 类型守卫增强:添加明确的返回类型注释\r\n// unref 如果参数是 Ref 则返回 .value,否则返回参数本身\r\nexport function unref<T>(r: T | Ref<T>): T {\r\n // FIX: P2-34 使用类型守卫替代类型断言,P2-38 移除不必要的 as\r\n // FIX: DTS build error - 使用类型断言确保类型正确\r\n return isRef(r) ? (r as Ref<T>).value : r;\r\n}\r\n\r\nexport function toRef<T extends object, K extends keyof T>(object: T, key: K): Ref<T[K]> {\r\n if (isRef(object[key])) return unsafeCast<Ref<T[K]>>(object[key]);\r\n return unsafeCast<Ref<T[K]>>(new ObjectRefImpl(object, key));\r\n}\r\n\r\nexport function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {\r\n const result = {} as { [K in keyof T]: Ref<T[K]> };\r\n for (const key in object) {\r\n result[key] = toRef(object, key);\r\n }\r\n return result;\r\n}\r\n\r\nexport function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {\r\n return unsafeCast<Ref<T>>(new CustomRefImpl(factory));\r\n}\r\n\r\n/**\r\n * 将值规范化为非 ref 值。\r\n * 如果是 Ref 则返回 .value,如果是函数则调用并返回结果,否则直接返回。\r\n * Vue 3.3+ 新增工具函数。\r\n */\r\nexport function toValue<T>(source: T | Ref<T> | (() => T)): T {\r\n // FIX: P2-34 使用类型守卫替代类型断言\r\n // FIX: DTS build error - 使用类型断言确保类型正确\r\n if (isRef(source)) return (source as Ref<T>).value;\r\n if (typeof source === 'function') {\r\n // FIX: P2-35 添加类型守卫确保 source 是函数后再调用\r\n return (source as () => T)();\r\n }\r\n return source as T;\r\n}\r\n\r\n// ==================== 内部实现类 ====================\r\n\r\nclass ObjectRefImpl<T extends object, K extends keyof T> {\r\n public readonly __v_isRef = true;\r\n\r\n constructor(\r\n private readonly _object: T,\r\n private readonly _key: K,\r\n ) {}\r\n\r\n get value(): T[K] {\r\n return this._object[this._key];\r\n }\r\n\r\n set value(newVal: T[K]) {\r\n this._object[this._key] = newVal;\r\n }\r\n}\r\n\r\nclass CustomRefImpl<T> {\r\n public readonly __v_isRef = true;\r\n public dep: Dep = createDep();\r\n private readonly _getter: () => T;\r\n private readonly _setter: (value: T) => void;\r\n\r\n constructor(factory: CustomRefFactory<T>) {\r\n const { get, set } = factory(\r\n () => trackRefValue(this),\r\n () => triggerRefValue(this),\r\n );\r\n this._getter = get;\r\n this._setter = set;\r\n }\r\n\r\n get value(): T {\r\n return this._getter();\r\n }\r\n\r\n set value(newVal: T) {\r\n this._setter(newVal);\r\n }\r\n}\r\n\r\n// ==================== 辅助函数 ====================\r\n\r\ntype CustomRefFactory<T> = (\r\n track: () => void,\r\n trigger: () => void,\r\n) => { get: () => T; set: (value: T) => void };\r\n\r\nfunction toReactive<T>(value: T): T {\r\n return isObject(value) ? (reactive(value as object) as T) : value;\r\n}\r\n","// src/async-computed.ts\r\n// @lytjs/reactivity - 异步 computed\r\n\r\ndeclare const __DEV__: boolean;\r\n\r\nimport { trackRefValue, triggerRefValue } from './ref';\r\nimport type { Ref } from './ref';\r\nimport { createDep } from './effect';\r\nimport type { Dep } from './effect';\r\nimport { effect, stop } from './effect';\r\nimport { unsafeCast } from '@lytjs/common-assertions';\r\nimport type { ReactiveEffectRunner } from './types';\r\nimport { warn } from '@lytjs/common-error';\r\n\r\n// ==================== AsyncComputedRef 类型 ====================\r\n\r\n/**\r\n * 异步计算属性引用\r\n * 扩展了标准 Ref,增加了 loading 和 error 状态\r\n */\r\nexport interface AsyncComputedRef<T = unknown> extends Ref<T | undefined> {\r\n /** 异步计算是否正在进行 */\r\n readonly loading: boolean;\r\n /** 上一次异步计算的错误(如果有) */\r\n readonly error: unknown;\r\n}\r\n\r\n// ==================== AsyncComputedRefImpl ====================\r\n\r\nclass AsyncComputedRefImpl<T> {\r\n private _value: T | undefined;\r\n private _loading: boolean = false;\r\n private _error: unknown = undefined;\r\n private _effect: ReactiveEffectRunner<void> | null = null;\r\n private _version = 0;\r\n\r\n public readonly __v_isRef = true;\r\n public dep: Dep = createDep();\r\n\r\n constructor(\r\n private readonly _getter: () => Promise<T>,\r\n initialValue?: T,\r\n lazy: boolean = false,\r\n ) {\r\n this._value = initialValue;\r\n\r\n if (!lazy) {\r\n // 非懒加载模式:使用 effect 追踪依赖,依赖变化时重新执行 getter\r\n this._effect = effect(() => {\r\n this._runGetter();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * 执行 getter 并处理 Promise 结果\r\n */\r\n private _runGetter(): void {\r\n // 标记为 loading\r\n this._loading = true;\r\n this._error = undefined;\r\n\r\n // FIX: P2-3 loading 状态变化同步触发通知。\r\n // 在设置 _loading = true 后立即调用 triggerRefValue,\r\n // 确保订阅者能感知到 loading 状态的变化(如显示 loading 指示器),\r\n // 而不是等到异步操作完成后才统一通知。\r\n triggerRefValue(this);\r\n\r\n // 递增版本号,用于竞态检测\r\n const currentVersion = ++this._version;\r\n\r\n // 调用 getter 获取 Promise\r\n const result = this._getter();\r\n // FIX: P1-06 getter 返回非 Promise 时包装为 Promise.resolve(),\r\n // 避免非 Promise 返回值导致 .then() 调用失败\r\n const promise = result instanceof Promise ? result : Promise.resolve(result);\r\n\r\n // 使用 Promise.then() 非阻塞处理\r\n promise.then(\r\n (value) => {\r\n if (currentVersion !== this._version) return; // 过期结果,忽略\r\n this._value = value;\r\n this._loading = false;\r\n this._error = undefined;\r\n // 触发 ref 更新\r\n triggerRefValue(this);\r\n },\r\n (err) => {\r\n if (currentVersion !== this._version) return; // 过期结果,忽略\r\n // FIX: P2-02 异步 computed 错误处理完善:在 DEV 模式下发出警告\r\n if (__DEV__) {\r\n console.warn('[lytjs/async-computed] Async computed error:', err);\r\n }\r\n this._error = err;\r\n this._loading = false;\r\n // 触发 ref 更新\r\n triggerRefValue(this);\r\n },\r\n );\r\n }\r\n\r\n /**\r\n * 手动触发执行(用于懒加载模式)\r\n */\r\n execute(): void {\r\n if (this._loading) return;\r\n this._runGetter();\r\n }\r\n\r\n get value(): T | undefined {\r\n trackRefValue(this);\r\n return this._value;\r\n }\r\n\r\n set value(_newVal: T | undefined) {\r\n if (__DEV__) {\r\n warn('Write operation failed: asyncComputed value is readonly');\r\n }\r\n }\r\n\r\n get loading(): boolean {\r\n return this._loading;\r\n }\r\n\r\n get error(): unknown {\r\n return this._error;\r\n }\r\n\r\n /**\r\n * 停止 effect 追踪\r\n */\r\n dispose(): void {\r\n this._version++; // 使所有 pending 的 promise 回调失效\r\n if (this._effect) {\r\n stop(this._effect);\r\n this._effect = null;\r\n }\r\n // FIX: P2-07 dispose 时清空错误和值,避免悬挂的异步回调更新已销毁的 computed\r\n this._error = null;\r\n this._value = undefined;\r\n // FIX: P1-2 REACTIVITY-NEW-03 - dispose 时通知订阅者,避免订阅者持有过期值\r\n triggerRefValue(this);\r\n }\r\n}\r\n\r\n// ==================== 公共 API ====================\r\n\r\n/**\r\n * 创建异步计算属性\r\n * 当 getter 中的响应式依赖变化时,自动重新执行 getter\r\n *\r\n * @param getter 返回 Promise 的函数\r\n * @param initialValue 初始值(Promise pending 时的值)\r\n * @returns AsyncComputedRef\r\n */\r\nexport function asyncComputed<T>(\r\n getter: () => Promise<T>,\r\n initialValue?: T,\r\n): AsyncComputedRef<T> {\r\n return unsafeCast<AsyncComputedRef<T>>(new AsyncComputedRefImpl<T>(getter, initialValue, false));\r\n}\r\n\r\n/**\r\n * 创建异步状态(懒加载模式)\r\n * factory 只执行一次,适合数据请求场景\r\n *\r\n * @param factory 返回 Promise 的函数\r\n * @param initialValue 初始值\r\n * @returns AsyncComputedRef\r\n */\r\nexport function useAsyncState<T>(\r\n factory: () => Promise<T>,\r\n initialValue?: T,\r\n): AsyncComputedRef<T> {\r\n const impl = new AsyncComputedRefImpl<T>(factory, initialValue, true);\r\n\r\n // 立即执行一次\r\n impl.execute();\r\n\r\n return unsafeCast<AsyncComputedRef<T>>(impl);\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/effect.ts","../src/ref.ts","../src/async-computed.ts"],"names":["effect","REACTIVITY_MAX_TRIGGER_DEPTH","error","unsafeCast"],"mappings":"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","file":"async.mjs","sourcesContent":["// src/constants.ts\n// 内部符号常量\n\n// DEV 检测方式说明:\n// 统一使用 typeof 检测方式,兼容编译时 define/replace 替换和未配置构建替换的场景。\n// 当打包工具(如 rollup/esbuild)通过 define 插件将 __DEV__ 替换为字面量 true/false 时,\n// typeof 检测会被优化为直接的字面量判断,实现死代码消除(DCE)。\n// 当未配置构建替换时,typeof 检测也能安全降级为 false,避免 ReferenceError。\nconst DEV = typeof __DEV__ !== 'undefined' ? __DEV__ : false;\n\nexport const RefSymbol: unique symbol = Symbol(DEV ? 'ref' : undefined);\nexport const ShallowRefSymbol: unique symbol = Symbol(DEV ? 'shallow_ref' : undefined);\nexport const ComputedRefSymbol: unique symbol = Symbol(DEV ? 'computed_ref' : undefined);\nexport const ReactiveSymbol: unique symbol = Symbol(DEV ? 'reactive' : undefined);\nexport const ReadonlySymbol: unique symbol = Symbol(DEV ? 'readonly' : undefined);\nexport const SignalSymbol: unique symbol = Symbol(DEV ? 'signal' : undefined);\nexport const ComputedSignalSymbol: unique symbol = Symbol(DEV ? 'computed_signal' : undefined);\n\n// ReactiveFlags - 用于 Proxy handler 内部标记\nexport const ReactiveFlags = {\n IS_REACTIVE: '__v_isReactive',\n IS_READONLY: '__v_isReadonly',\n IS_SHALLOW: '__v_isShallow',\n IS_REF: '__v_isRef',\n RAW: '__v_raw',\n SKIP: '__v_skip',\n} as const;\n\n// Track/Trigger 操作类型\nexport const TrackOpTypes = {\n GET: 'get',\n HAS: 'has',\n ITERATE: 'iterate',\n} as const;\n\nexport const TriggerOpTypes = {\n SET: 'set',\n ADD: 'add',\n DELETE: 'delete',\n CLEAR: 'clear',\n} as const;\n\n// 内部共享常量\nexport const ITERATE_KEY = Symbol('iterate');\n","// src/effect.ts\n// 响应式副作用系统核心\n\nimport { ITERATE_KEY } from './constants';\nimport type { ReactiveEffectRunner } from './types';\nimport { warn } from '@lytjs/common-error';\nimport { _isSignalUntracked } from './signal';\nimport { getActiveEffectScope } from './effect-scope';\nimport { REACTIVITY_MAX_TRIGGER_DEPTH } from '@lytjs/common-constants';\n\n// ==================== 全局状态 ====================\n\nlet activeEffect: ReactiveEffect | undefined;\nlet _trackDepth = 0;\nconst targetMap = new WeakMap<object, Map<string | symbol, Dep>>();\nlet shouldTrack = true;\nconst trackStack: boolean[] = [];\n\n// ==================== 首次渲染优化 ====================\n\n/** 标记当前是否处于首次渲染优化期间 */\nlet isFirstRenderPass = false;\n\n/** 记录被跳过的追踪次数(用于调试和测试验证) */\nlet skippedTrackingCount = 0;\n\n/**\n * 包裹首次渲染过程,期间禁用响应式依赖收集。\n * 支持嵌套调用:如果外层已经处于首次渲染优化期间,\n * 内层调用不会提前重置标志位。\n */\nexport function withFirstRenderOptimization<T>(fn: () => T): T {\n const wasFirstRender = isFirstRenderPass;\n isFirstRenderPass = true;\n try {\n return fn();\n } finally {\n if (!wasFirstRender) {\n isFirstRenderPass = false;\n }\n }\n}\n\n/**\n * 检查当前是否应跳过响应式依赖收集。\n * 在 withFirstRenderOptimization 执行期间返回 true。\n */\nexport function shouldSkipTracking(): boolean {\n return isFirstRenderPass;\n}\n\n/**\n * 获取被跳过的追踪次数(用于调试和测试)。\n */\nexport function getSkippedTrackingCount(): number {\n return skippedTrackingCount;\n}\n\n/**\n * 重置被跳过的追踪计数(用于测试)。\n */\nexport function resetSkippedTrackingCount(): void {\n skippedTrackingCount = 0;\n}\n\n// 只读访问器,防止外部修改内部状态\n\n/**\n * 获取当前活跃的 ReactiveEffect 实例。\n * 在 effect 执行期间返回当前正在运行的 effect,否则返回 undefined。\n *\n * @returns 当前活跃的 effect,如果没有则返回 undefined\n */\nexport function getActiveEffect(): ReactiveEffect | undefined {\n return activeEffect;\n}\n\n/**\n * 获取当前是否应该进行依赖追踪。\n * 可通过 pauseTracking/enableTracking 控制。\n *\n * @returns 是否应该进行依赖追踪\n */\nexport function getShouldTrack(): boolean {\n return shouldTrack;\n}\n\n// ==================== Dep ====================\n\n/**\n * 依赖集合类型,存储订阅某个响应式属性的所有 ReactiveEffect。\n */\nexport type Dep = Set<ReactiveEffect>;\n\n/**\n * 创建一个新的 Dep(依赖集合)。\n *\n * @returns 新的空 Dep 实例\n */\nexport const createDep = (): Dep => {\n return new Set() as Dep;\n};\n\n// ==================== Track / Trigger ====================\n\n/**\n * Maximum depth for nested trigger() calls to prevent infinite reactivity loops.\n * When triggerDepth exceeds this limit, further triggers are silently dropped\n * and a warning is emitted in DEV mode.\n */\nlet triggerDepth = 0;\n\n/**\n * 追踪响应式属性的依赖关系。\n * 当响应式属性被读取时调用,将当前活跃的 effect 记录为该属性的依赖。\n *\n * @param target - 被追踪的响应式对象\n * @param _type - 追踪操作类型(如 'get'、'has'、'iterate')\n * @param key - 被追踪的属性键\n */\nexport function track(target: object, _type: string, key: string | symbol) {\n if (!shouldTrack || activeEffect === undefined) return;\n // signal untrack 桥接:signalUntrack 期间跳过 effect 系统的依赖收集\n if (_isSignalUntracked()) return;\n\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, (depsMap = new Map()));\n }\n\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, (dep = createDep()));\n }\n\n trackEffect(dep);\n\n // 调试:触发 onTrack\n if (__DEV__ && activeEffect.onTrack) {\n activeEffect.onTrack({\n effect: activeEffect,\n target,\n type: _type,\n key,\n });\n }\n}\n\n/**\n * 将当前活跃的 effect 添加到指定的依赖集合中。\n * 在首次渲染优化期间会跳过依赖收集。\n *\n * @param dep - 目标依赖集合\n */\nexport function trackEffect(dep: Dep) {\n // 首次渲染优化:跳过依赖收集\n if (shouldSkipTracking()) {\n skippedTrackingCount++;\n return;\n }\n // FIX: P1-01 移除重复的 shouldTrack/activeEffect 检查,\n // 这些检查已在调用方 track() 中完成,此处只需关注 dep 操作\n // FIX: P0-5 添加防御性检查,避免非空断言在公共 API 调用时不安全\n if (activeEffect && !dep.has(activeEffect)) {\n dep.add(activeEffect);\n activeEffect.deps.push(dep);\n }\n}\n\n/**\n * 触发响应式属性的依赖更新。\n * 当响应式属性被修改时调用,通知所有依赖该属性的 effect 重新执行。\n *\n * 根据操作类型(add/delete/set/clear)会触发不同的依赖集合:\n * - `add`:触发属性本身 + ITERATE_KEY(或数组 length)\n * - `delete`:触发属性本身 + ITERATE_KEY\n * - `set`:触发属性本身 + 数组 length(如果是整数键)\n * - `clear`:触发所有属性的依赖\n *\n * @param target - 被修改的响应式对象\n * @param type - 触发操作类型('set' | 'add' | 'delete' | 'clear')\n * @param key - 被修改的属性键\n * @param _newValue - 新值(可选,用于调试)\n * @param _oldValue - 旧值(可选,用于调试)\n */\nexport function trigger(\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n const depsMap = targetMap.get(target);\n if (!depsMap) return;\n\n const deps: (Dep | undefined)[] = [];\n\n if (type === 'clear') {\n deps.push(...depsMap.values());\n } else {\n if (key !== undefined) {\n deps.push(depsMap.get(key));\n }\n\n if (type === 'add') {\n if (Array.isArray(target)) {\n deps.push(depsMap.get('length'));\n } else {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n } else if (type === 'delete') {\n if (!Array.isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n } else if (type === 'set') {\n if (Array.isArray(target) && isIntegerKey(key)) {\n deps.push(depsMap.get('length'));\n }\n }\n }\n\n const effects: ReactiveEffect[] = [];\n for (const dep of deps) {\n if (dep) {\n for (const effect of dep) {\n effects.push(effect);\n }\n }\n }\n\n // 去重:同一个 effect 可能同时存在于多个 dep 中\n triggerEffects([...new Set(effects)], target, type, key, newValue, oldValue);\n}\n\n/**\n * 执行一组 effect 的触发。\n * 优先执行 computed effect,再执行普通 effect。\n * 内置递归深度限制,超过最大深度时静默丢弃并发出警告。\n *\n * @param effects - 需要触发的 ReactiveEffect 数组\n * @param target - 被修改的目标对象(用于调试回调)\n * @param type - 触发操作类型(用于调试回调)\n * @param key - 被修改的属性键(用于调试回调)\n * @param newValue - 新值(用于调试回调)\n * @param oldValue - 旧值(用于调试回调)\n */\nexport function triggerEffects(\n effects: ReactiveEffect[],\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n if (triggerDepth > REACTIVITY_MAX_TRIGGER_DEPTH) {\n // FIX: P2-1 triggerDepth 超限时改为 warn + 静默丢弃,与 Vue 3 行为一致。\n // 之前直接 throw Error 过于激进,会导致整个响应式链断裂。\n // 改为仅发出警告并丢弃后续 trigger,避免因单个无限循环导致整个应用崩溃。\n if (__DEV__) {\n warn(\n `[lytjs/reactivity] Maximum trigger depth (${REACTIVITY_MAX_TRIGGER_DEPTH}) exceeded. ` +\n `Possible infinite reactivity loop detected. Further triggers are silently dropped. ` +\n `triggerDepth=${triggerDepth}`,\n );\n }\n return;\n }\n triggerDepth++;\n try {\n for (const effect of effects) {\n if (effect.computed) {\n triggerEffect(effect, target, type, key, newValue, oldValue);\n }\n }\n for (const effect of effects) {\n if (!effect.computed) {\n triggerEffect(effect, target, type, key, newValue, oldValue);\n }\n }\n } finally {\n triggerDepth--;\n }\n}\n\nfunction triggerEffect(\n effect: ReactiveEffect,\n target: object,\n type: string,\n key?: string | symbol,\n newValue?: unknown,\n oldValue?: unknown,\n) {\n if (effect !== activeEffect || effect.allowRecurse) {\n // 调用 onTrigger 回调(用于调试)\n if (__DEV__ && effect.onTrigger) {\n effect.onTrigger({\n effect,\n target,\n type,\n key,\n newValue,\n oldValue,\n });\n }\n if (effect.scheduler) {\n effect.scheduler();\n } else {\n effect.run();\n }\n }\n}\n\n// ==================== ReactiveEffect ====================\n\n/**\n * 响应式副作用类。\n * 封装一个副作用函数,支持依赖自动收集、调度执行和手动停止。\n *\n * 创建时会自动注册到当前活跃的 effectScope 中。\n *\n * @typeParam T - 副作用函数的返回值类型\n *\n * @example\n * ```ts\n * const eff = new ReactiveEffect(() => {\n * console.log(state.count);\n * });\n * eff.run(); // 执行副作用,同时收集依赖\n * eff.stop(); // 停止副作用,清理所有依赖\n * ```\n */\nexport class ReactiveEffect<T = unknown> {\n active = true;\n deps: Dep[] = [];\n parent: ReactiveEffect | undefined = undefined;\n computed?: boolean;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n onError?: (error: Error) => void;\n // 运行前清理(onEffectCleanup 注册的)\n _cleanups: Array<() => void> = [];\n\n constructor(\n public fn: () => T,\n public scheduler?: (...args: unknown[]) => unknown,\n ) {\n // 自动注册到当前活跃的 effectScope\n const scope = getActiveEffectScope();\n if (scope && scope.active) {\n scope.effects.push(this);\n }\n }\n\n run(): T | undefined {\n if (!this.active) {\n return undefined;\n }\n\n // 在重新执行前调用 cleanup\n if (this._cleanups.length > 0) {\n for (let i = 0; i < this._cleanups.length; i++) {\n this._cleanups[i]!();\n }\n this._cleanups.length = 0;\n }\n\n const prevShouldTrack = shouldTrack;\n try {\n this.parent = activeEffect;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n activeEffect = this;\n shouldTrack = true;\n _trackDepth++;\n\n return this.fn();\n } catch (error) {\n if (this.onError) {\n this.onError(error as Error);\n return undefined;\n }\n throw error;\n } finally {\n _trackDepth--;\n activeEffect = this.parent;\n shouldTrack = prevShouldTrack;\n this.parent = undefined;\n }\n }\n\n stop(): void {\n if (this.active) {\n cleanupEffect(this);\n if (this._cleanups.length > 0) {\n for (let i = 0; i < this._cleanups.length; i++) {\n this._cleanups[i]!();\n }\n this._cleanups.length = 0;\n }\n if (this.onStop) {\n this.onStop();\n }\n this.active = false;\n this.scheduler = undefined;\n }\n }\n}\n\nfunction cleanupEffect(effect: ReactiveEffect) {\n const { deps } = effect;\n for (let i = 0; i < deps.length; i++) {\n deps[i]!.delete(effect);\n }\n deps.length = 0;\n}\n\n// ==================== 公共 API ====================\n\n// Function overloads for effect()\n// Non-lazy effect: fn returns void, preventing accidental return value usage\n\n/**\n * 创建一个响应式副作用并立即执行。\n *\n * 副作用函数会在执行期间自动追踪所使用的响应式属性,\n * 当这些属性发生变化时,副作用会重新执行。\n *\n * @param fn - 副作用函数,返回 void\n * @param options - 配置选项\n * @param options.lazy - 是否延迟执行(false 时立即执行)\n * @param options.scheduler - 自定义调度器,替代默认的立即执行行为\n * @param options.allowRecurse - 是否允许副作用递归触发自身\n * @param options.onStop - 副作用停止时的回调\n * @param options.onTrack - 依赖被追踪时的调试回调\n * @param options.onTrigger - 依赖被触发时的调试回调\n * @returns 副作用运行器,可调用 run() 手动执行或 stop() 停止\n */\nexport function effect(\n fn: () => void,\n options?: {\n lazy?: false;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n },\n): ReactiveEffectRunner<void>;\n\n// Lazy effect: preserves generic return value type (used by computed etc.)\nexport function effect<T>(\n fn: () => T,\n options: {\n lazy: true;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n },\n): ReactiveEffectRunner<T>;\n\n// 统一实现签名\nexport function effect<T = unknown>(\n fn: () => T,\n options?: {\n lazy?: boolean;\n scheduler?: (...args: unknown[]) => unknown;\n allowRecurse?: boolean;\n onStop?: () => void;\n onTrack?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n }) => void;\n onTrigger?: (event: {\n effect: ReactiveEffect;\n target: object;\n key?: string | symbol;\n type: string;\n newValue?: unknown;\n oldValue?: unknown;\n }) => void;\n onError?: (error: Error) => void;\n },\n): ReactiveEffectRunner<T> {\n const _effect = new ReactiveEffect(fn);\n if (options) {\n // 仅提取已知合法选项,防止覆盖内部属性(如 fn、active)\n _effect.scheduler = options.scheduler;\n _effect.allowRecurse = options.allowRecurse;\n _effect.onStop = options.onStop;\n _effect.onTrack = options.onTrack;\n _effect.onTrigger = options.onTrigger;\n _effect.onError = options.onError;\n }\n if (!options || !options.lazy) {\n _effect.run();\n }\n const runner = _effect.run.bind(_effect) as ReactiveEffectRunner<T>;\n runner.effect = _effect;\n return runner;\n}\n\n/**\n * 停止一个响应式副作用。\n * 清理所有依赖关系,并调用 onStop 回调。\n *\n * @param runner - 由 effect() 返回的副作用运行器\n */\nexport function stop(runner: ReactiveEffectRunner): void {\n runner.effect.stop();\n}\n\n/**\n * 暂停依赖追踪。\n * 调用后,响应式属性的读取不会建立依赖关系。\n * 可通过 resetTracking() 恢复。\n */\nexport function pauseTracking(): void {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\n\n/**\n * 启用依赖追踪。\n * 将当前追踪状态压入栈中并设为 true。\n * 可通过 resetTracking() 恢复到之前的状态。\n */\nexport function enableTracking(): void {\n trackStack.push(shouldTrack);\n shouldTrack = true;\n}\n\n/**\n * 重置依赖追踪状态到上一次暂停/启用之前的状态。\n * 从追踪栈中弹出最近的状态并恢复。\n */\nexport function resetTracking(): void {\n const last = trackStack.pop();\n shouldTrack = last === undefined ? true : last;\n}\n\n/**\n * 批量执行函数,期间暂停依赖追踪。\n * 与 signalBatch 不同,batch 侧重于暂停追踪而非延迟通知。\n * 支持嵌套调用,内层 batch 不会提前恢复追踪状态。\n *\n * @param fn - 需要批量执行的函数\n *\n * @example\n * ```ts\n * batch(() => {\n * state.a = 1; // 不会触发依赖更新\n * state.b = 2; // 不会触发依赖更新\n * }); // 函数结束后恢复追踪\n * ```\n */\nexport function batch(fn: () => void): void {\n const stackLength = trackStack.length;\n pauseTracking();\n try {\n fn();\n } finally {\n // 恢复到 batch 调用前的 stack 长度,确保嵌套安全\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n }\n}\n\n/**\n * batchAsync - like batch but supports async functions.\n * Pauses tracking during fn execution (including after await),\n * and restores tracking state when fn completes (or throws).\n * Returns a Promise.\n */\nexport function batchAsync(fn: () => void | Promise<void>): Promise<void> {\n const stackLength = trackStack.length;\n pauseTracking();\n const restoreTracking = () => {\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n };\n try {\n const result = fn();\n if (result && typeof result === 'object' && 'then' in result) {\n return (result as Promise<void>).finally(restoreTracking);\n }\n // 同步路径:立即恢复 tracking 状态\n restoreTracking();\n return Promise.resolve();\n } catch (e) {\n restoreTracking();\n return Promise.reject(e);\n }\n}\n\n/**\n * untrack - execute fn without tracking dependencies.\n * Semantically different from batch: untrack means \"run but don't track\".\n * Returns the return value of fn.\n */\nexport function untrack<T>(fn: () => T): T {\n const stackLength = trackStack.length;\n pauseTracking();\n try {\n return fn();\n } finally {\n while (trackStack.length > stackLength) {\n trackStack.pop();\n }\n shouldTrack = trackStack.length > 0 ? trackStack[trackStack.length - 1]! : true;\n }\n}\n\n/**\n * 在当前活跃的 effect 上注册一个清理回调。\n * 该回调会在 effect 重新执行前或停止时被调用,用于清理副作用资源。\n *\n * @param fn - 清理回调函数\n * @param failSilently - 当没有活跃 effect 时是否静默失败(默认 false,开发模式下会发出警告)\n *\n * @example\n * ```ts\n * effect(() => {\n * const timer = setInterval(() => console.log('tick'), 1000);\n * onEffectCleanup(() => clearInterval(timer));\n * });\n * ```\n */\nexport function onEffectCleanup(fn: () => void, failSilently = false): void {\n if (activeEffect === undefined) {\n if (!failSilently && __DEV__) {\n warn('onEffectCleanup() was called when there was no active effect to associate with.');\n }\n return;\n }\n activeEffect._cleanups.push(fn);\n}\n\n// ==================== 辅助 ====================\n\n/**\n * 检查给定的键是否为有效的整数键。\n * 用于判断数组索引是否为合法的整数值。\n *\n * @param key - 需要检查的键值\n * @returns 如果是有效的整数键返回 true,否则返回 false\n */\nexport function isIntegerKey(key: unknown): boolean {\n return (\n typeof key === 'string' &&\n key !== 'NaN' &&\n key[0] !== '-' &&\n '' + parseInt(key, 10) === key &&\n Number.isSafeInteger(Number(key))\n );\n}\n","// src/ref.ts\n// Ref 响应式引用\n// 复用 @lytjs/common-is: isObject, hasChanged\n\nimport { isObject, hasChanged } from '@lytjs/common-is';\nimport { warn } from '@lytjs/common-error';\nimport { unsafeCast } from '@lytjs/common-assertions';\nimport { track, trigger, getActiveEffect, getShouldTrack, createDep } from './effect';\nimport type { Dep } from './effect';\nimport { TrackOpTypes, TriggerOpTypes } from './constants';\nimport { toRaw, isRef } from './shared';\nimport { reactive } from './reactive';\n\n// ==================== Ref 类型 ====================\n\n/** track/trigger 中使用的类 ref 对象的内部接口 */\nexport interface RefLike<T = unknown> {\n dep: Dep;\n __v_isRef?: boolean;\n value: T;\n}\n\n/** trackRefValue/triggerRefValue 所需的最小接口 */\ninterface TrackableRef {\n dep: Dep;\n}\n\nexport interface Ref<T = unknown> {\n value: T;\n __v_isRef: true;\n}\n\nexport interface ShallowRef<T = unknown> extends Ref<T> {\n __v_isShallow: true;\n}\n\nexport interface ComputedRef<T = unknown> extends Ref<T> {\n __v_isComputed: true;\n}\n\n// ==================== Ref 类 ====================\n\nclass RefImpl<T> {\n private _value: T;\n private _rawValue: T;\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\n public dep: Dep = createDep();\n public readonly __v_isRef = true;\n public readonly __v_isShallow?: boolean;\n\n constructor(value: T, isShallow: boolean) {\n this.__v_isShallow = isShallow || undefined;\n this._rawValue = isShallow ? value : toRaw(value);\n // toReactive 仅对对象类型生效,非对象值直接赋值。\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\n this._value = isShallow ? value : (toReactive(value as object) as T);\n }\n\n get value(): T {\n trackRefValue(this);\n return this._value;\n }\n\n set value(newVal: T) {\n const useDirectValue = this.__v_isShallow;\n newVal = useDirectValue ? newVal : toRaw(newVal);\n if (hasChanged(newVal, this._rawValue)) {\n const oldVal = this._rawValue;\n this._rawValue = newVal;\n // toReactive 仅对对象类型生效,非对象值直接赋值。\n // 此处的 as object 断言是安全的,因为 toReactive 内部会先做 isObject 检查。\n this._value = useDirectValue ? newVal : (toReactive(newVal as object) as T);\n triggerRefValue(this, newVal, oldVal);\n }\n }\n}\n\nclass ShallowRefImpl<T> {\n private _value: T;\n private _rawValue: T;\n // 使用 Dep 类型替代 Set<any>,提供更精确的类型约束\n public dep: Dep = createDep();\n public readonly __v_isRef = true;\n public readonly __v_isShallow = true as const;\n\n constructor(value: T) {\n this._rawValue = value;\n this._value = value;\n }\n\n get value(): T {\n trackRefValue(this);\n return this._value;\n }\n\n set value(newVal: T) {\n if (hasChanged(newVal, this._rawValue)) {\n const oldVal = this._rawValue;\n this._rawValue = newVal;\n this._value = newVal;\n triggerRefValue(this, newVal, oldVal);\n }\n }\n}\n\n// ==================== 追踪与触发 ====================\n\nexport function trackRefValue(ref: TrackableRef): void {\n if (getShouldTrack() && getActiveEffect()) {\n track(ref, TrackOpTypes.GET, 'value');\n }\n}\n\nexport function triggerRefValue(ref: TrackableRef, newVal?: unknown, oldVal?: unknown): void {\n trigger(ref, TriggerOpTypes.SET, 'value', newVal, oldVal);\n}\n\n// ==================== 公共 API ====================\n\nexport function ref<T extends object | string | number | boolean | null | undefined>(\n value: T,\n): Ref<T> {\n if (isRef(value)) {\n // FIX: P1-07 ref() 接受 ShallowRef 时添加 DEV 警告,\n // 提醒用户 ShallowRef 语义与 Ref 不同,直接返回可能导致意外行为\n // FIX: P2-34 使用类型守卫替代类型断言\n if (__DEV__ && isShallowRef(value)) {\n warn(\n 'ref() received a ShallowRef value. ' +\n 'ShallowRef and Ref have different reactivity semantics. ' +\n 'If this is intentional, use shallowRef() instead.',\n );\n }\n return value as Ref<T>;\n }\n // 双重断言是必要的:RefImpl 实现了 Ref 接口所需的 value/__v_isRef 属性,\n // 但 TypeScript 无法自动推断类实例满足接口(私有成员导致结构不兼容)。\n return unsafeCast<Ref<T>>(new RefImpl(value, false));\n}\n\nexport function shallowRef<T>(value: T): ShallowRef<T> {\n if (isRef(value)) return unsafeCast<ShallowRef<T>>(value);\n return unsafeCast<ShallowRef<T>>(new ShallowRefImpl(value));\n}\n\nexport function triggerRef<T>(ref: ShallowRef<T>): void {\n triggerRefValue(unsafeCast<TrackableRef>(ref), ref.value);\n}\n\nexport { isRef } from './shared';\n\n// FIX: P2-8 添加类型谓词:isShallowRef 和 isComputedRef\n/**\n * 检查值是否为 ShallowRef\n * 类型谓词:缩小类型到 ShallowRef<T>\n */\nexport function isShallowRef<T = unknown>(r: unknown): r is ShallowRef<T> {\n return isRef(r) && !!(r as ShallowRef<T>).__v_isShallow;\n}\n\n/**\n * 检查值是否为 ComputedRef\n * 类型谓词:缩小类型到 ComputedRef<T>\n */\nexport function isComputedRef<T = unknown>(r: unknown): r is ComputedRef<T> {\n return isRef(r) && !!(r as ComputedRef<T>).__v_isComputed;\n}\n\n// FIX: P2-06 unref 类型守卫增强:添加明确的返回类型注释\n// unref 如果参数是 Ref 则返回 .value,否则返回参数本身\nexport function unref<T>(r: T | Ref<T>): T {\n // FIX: P2-34 使用类型守卫替代类型断言,P2-38 移除不必要的 as\n // FIX: DTS build error - 使用类型断言确保类型正确\n return isRef(r) ? (r as Ref<T>).value : r;\n}\n\nexport function toRef<T extends object, K extends keyof T>(object: T, key: K): Ref<T[K]> {\n if (isRef(object[key])) return unsafeCast<Ref<T[K]>>(object[key]);\n return unsafeCast<Ref<T[K]>>(new ObjectRefImpl(object, key));\n}\n\nexport function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {\n const result = {} as { [K in keyof T]: Ref<T[K]> };\n for (const key in object) {\n result[key] = toRef(object, key);\n }\n return result;\n}\n\nexport function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {\n return unsafeCast<Ref<T>>(new CustomRefImpl(factory));\n}\n\n/**\n * 将值规范化为非 ref 值。\n * 如果是 Ref 则返回 .value,如果是函数则调用并返回结果,否则直接返回。\n * Vue 3.3+ 新增工具函数。\n */\nexport function toValue<T>(source: T | Ref<T> | (() => T)): T {\n // FIX: P2-34 使用类型守卫替代类型断言\n // FIX: DTS build error - 使用类型断言确保类型正确\n if (isRef(source)) return (source as Ref<T>).value;\n if (typeof source === 'function') {\n // FIX: P2-35 添加类型守卫确保 source 是函数后再调用\n return (source as () => T)();\n }\n return source as T;\n}\n\n// ==================== 内部实现类 ====================\n\nclass ObjectRefImpl<T extends object, K extends keyof T> {\n public readonly __v_isRef = true;\n\n constructor(\n private readonly _object: T,\n private readonly _key: K,\n ) {}\n\n get value(): T[K] {\n return this._object[this._key];\n }\n\n set value(newVal: T[K]) {\n this._object[this._key] = newVal;\n }\n}\n\nclass CustomRefImpl<T> {\n public readonly __v_isRef = true;\n public dep: Dep = createDep();\n private readonly _getter: () => T;\n private readonly _setter: (value: T) => void;\n\n constructor(factory: CustomRefFactory<T>) {\n const { get, set } = factory(\n () => trackRefValue(this),\n () => triggerRefValue(this),\n );\n this._getter = get;\n this._setter = set;\n }\n\n get value(): T {\n return this._getter();\n }\n\n set value(newVal: T) {\n this._setter(newVal);\n }\n}\n\n// ==================== 辅助函数 ====================\n\ntype CustomRefFactory<T> = (\n track: () => void,\n trigger: () => void,\n) => { get: () => T; set: (value: T) => void };\n\nfunction toReactive<T>(value: T): T {\n return isObject(value) ? (reactive(value as object) as T) : value;\n}\n","// src/async-computed.ts\n// @lytjs/reactivity - 异步 computed\n\ndeclare const __DEV__: boolean;\n\nimport { trackRefValue, triggerRefValue } from './ref';\nimport type { Ref } from './ref';\nimport { createDep } from './effect';\nimport type { Dep } from './effect';\nimport { effect, stop } from './effect';\nimport { unsafeCast } from '@lytjs/common-assertions';\nimport type { ReactiveEffectRunner } from './types';\nimport { warn } from '@lytjs/common-error';\n\n// ==================== AsyncComputedRef 类型 ====================\n\n/**\n * 异步计算属性引用\n * 扩展了标准 Ref,增加了 loading 和 error 状态\n */\nexport interface AsyncComputedRef<T = unknown> extends Ref<T | undefined> {\n /** 异步计算是否正在进行 */\n readonly loading: boolean;\n /** 上一次异步计算的错误(如果有) */\n readonly error: unknown;\n}\n\n// ==================== AsyncComputedRefImpl ====================\n\nclass AsyncComputedRefImpl<T> {\n private _value: T | undefined;\n private _loading: boolean = false;\n private _error: unknown = undefined;\n private _effect: ReactiveEffectRunner<void> | null = null;\n private _version = 0;\n\n public readonly __v_isRef = true;\n public dep: Dep = createDep();\n\n constructor(\n private readonly _getter: () => Promise<T>,\n initialValue?: T,\n lazy: boolean = false,\n ) {\n this._value = initialValue;\n\n if (!lazy) {\n // 非懒加载模式:使用 effect 追踪依赖,依赖变化时重新执行 getter\n this._effect = effect(() => {\n this._runGetter();\n });\n }\n }\n\n /**\n * 执行 getter 并处理 Promise 结果\n */\n private _runGetter(): void {\n // 标记为 loading\n this._loading = true;\n this._error = undefined;\n\n // FIX: P2-3 loading 状态变化同步触发通知。\n // 在设置 _loading = true 后立即调用 triggerRefValue,\n // 确保订阅者能感知到 loading 状态的变化(如显示 loading 指示器),\n // 而不是等到异步操作完成后才统一通知。\n triggerRefValue(this);\n\n // 递增版本号,用于竞态检测\n const currentVersion = ++this._version;\n\n // 调用 getter 获取 Promise\n const result = this._getter();\n // FIX: P1-06 getter 返回非 Promise 时包装为 Promise.resolve(),\n // 避免非 Promise 返回值导致 .then() 调用失败\n const promise = result instanceof Promise ? result : Promise.resolve(result);\n\n // 使用 Promise.then() 非阻塞处理\n promise.then(\n (value) => {\n if (currentVersion !== this._version) return; // 过期结果,忽略\n this._value = value;\n this._loading = false;\n this._error = undefined;\n // 触发 ref 更新\n triggerRefValue(this);\n },\n (err) => {\n if (currentVersion !== this._version) return; // 过期结果,忽略\n // FIX: P2-02 异步 computed 错误处理完善:在 DEV 模式下发出警告\n if (__DEV__) {\n console.warn('[lytjs/async-computed] Async computed error:', err);\n }\n this._error = err;\n this._loading = false;\n // 触发 ref 更新\n triggerRefValue(this);\n },\n );\n }\n\n /**\n * 手动触发执行(用于懒加载模式)\n */\n execute(): void {\n if (this._loading) return;\n this._runGetter();\n }\n\n get value(): T | undefined {\n trackRefValue(this);\n return this._value;\n }\n\n set value(_newVal: T | undefined) {\n if (__DEV__) {\n warn('Write operation failed: asyncComputed value is readonly');\n }\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): unknown {\n return this._error;\n }\n\n /**\n * 停止 effect 追踪\n */\n dispose(): void {\n this._version++; // 使所有 pending 的 promise 回调失效\n if (this._effect) {\n stop(this._effect);\n this._effect = null;\n }\n // FIX: P2-07 dispose 时清空错误和值,避免悬挂的异步回调更新已销毁的 computed\n this._error = null;\n this._value = undefined;\n // FIX: P1-2 REACTIVITY-NEW-03 - dispose 时通知订阅者,避免订阅者持有过期值\n triggerRefValue(this);\n }\n}\n\n// ==================== 公共 API ====================\n\n/**\n * 创建异步计算属性\n * 当 getter 中的响应式依赖变化时,自动重新执行 getter\n *\n * @param getter 返回 Promise 的函数\n * @param initialValue 初始值(Promise pending 时的值)\n * @returns AsyncComputedRef\n */\nexport function asyncComputed<T>(getter: () => Promise<T>, initialValue?: T): AsyncComputedRef<T> {\n return unsafeCast<AsyncComputedRef<T>>(new AsyncComputedRefImpl<T>(getter, initialValue, false));\n}\n\n/**\n * 创建异步状态(懒加载模式)\n * factory 只执行一次,适合数据请求场景\n *\n * @param factory 返回 Promise 的函数\n * @param initialValue 初始值\n * @returns AsyncComputedRef\n */\nexport function useAsyncState<T>(factory: () => Promise<T>, initialValue?: T): AsyncComputedRef<T> {\n const impl = new AsyncComputedRefImpl<T>(factory, initialValue, true);\n\n // 立即执行一次\n impl.execute();\n\n return unsafeCast<AsyncComputedRef<T>>(impl);\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1530,9 +1530,7 @@ function batchScope(callback, options = {}) {
1530
1530
  });
1531
1531
  ctx.committed = true;
1532
1532
  if (result === void 0) {
1533
- throw new Error(
1534
- "[lytjs/reactivity] batchScope sync mode: callback returned undefined."
1535
- );
1533
+ throw new Error("[lytjs/reactivity] batchScope sync mode: callback returned undefined.");
1536
1534
  }
1537
1535
  return result;
1538
1536
  }