@vobs/runtime 1.2.1 → 1.3.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.
Files changed (74) hide show
  1. package/dist/async-boundary.cjs +73 -374
  2. package/dist/async-boundary.cjs.map +1 -1
  3. package/dist/async-boundary.js +44 -367
  4. package/dist/async-boundary.js.map +1 -1
  5. package/dist/bind.cjs +101 -234
  6. package/dist/bind.cjs.map +1 -1
  7. package/dist/bind.js +72 -227
  8. package/dist/bind.js.map +1 -1
  9. package/dist/boundary.cjs +67 -369
  10. package/dist/boundary.cjs.map +1 -1
  11. package/dist/boundary.js +42 -366
  12. package/dist/boundary.js.map +1 -1
  13. package/dist/debug.cjs +41 -12
  14. package/dist/debug.cjs.map +1 -1
  15. package/dist/debug.js +10 -3
  16. package/dist/debug.js.map +1 -1
  17. package/dist/dynamic.cjs +76 -378
  18. package/dist/dynamic.cjs.map +1 -1
  19. package/dist/dynamic.js +43 -367
  20. package/dist/dynamic.js.map +1 -1
  21. package/dist/error-boundary.cjs +77 -372
  22. package/dist/error-boundary.cjs.map +1 -1
  23. package/dist/error-boundary.d.cts +7 -3
  24. package/dist/error-boundary.d.ts +7 -3
  25. package/dist/error-boundary.js +48 -367
  26. package/dist/error-boundary.js.map +1 -1
  27. package/dist/error.cjs +35 -9
  28. package/dist/error.cjs.map +1 -1
  29. package/dist/error.js +7 -3
  30. package/dist/error.js.map +1 -1
  31. package/dist/fragment.cjs +44 -133
  32. package/dist/fragment.cjs.map +1 -1
  33. package/dist/fragment.js +19 -130
  34. package/dist/fragment.js.map +1 -1
  35. package/dist/hmr.cjs +61 -22
  36. package/dist/hmr.cjs.map +1 -1
  37. package/dist/hmr.d.cts +7 -1
  38. package/dist/hmr.d.ts +7 -1
  39. package/dist/hmr.js +19 -3
  40. package/dist/hmr.js.map +1 -1
  41. package/dist/index.cjs +230 -465
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.d.cts +1 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.js +128 -388
  46. package/dist/index.js.map +1 -1
  47. package/dist/ops.cjs +147 -244
  48. package/dist/ops.cjs.map +1 -1
  49. package/dist/ops.js +97 -216
  50. package/dist/ops.js.map +1 -1
  51. package/dist/profiler.cjs +69 -320
  52. package/dist/profiler.cjs.map +1 -1
  53. package/dist/profiler.js +40 -315
  54. package/dist/profiler.js.map +1 -1
  55. package/dist/ref.cjs +33 -131
  56. package/dist/ref.cjs.map +1 -1
  57. package/dist/ref.js +10 -130
  58. package/dist/ref.js.map +1 -1
  59. package/dist/renderer.cjs +18 -2
  60. package/dist/renderer.cjs.map +1 -1
  61. package/dist/renderer.js +0 -2
  62. package/dist/renderer.js.map +1 -1
  63. package/dist/template.cjs +29 -6
  64. package/dist/template.cjs.map +1 -1
  65. package/dist/template.js +4 -3
  66. package/dist/template.js.map +1 -1
  67. package/package.json +2 -2
  68. package/src/dynamic.test.ts +65 -1
  69. package/src/error-boundary.ts +13 -3
  70. package/src/hmr.test.ts +17 -0
  71. package/src/hmr.ts +14 -0
  72. package/src/index.ts +1 -0
  73. package/src/ops.ts +38 -3
  74. package/src/props.test.ts +32 -1
package/dist/fragment.cjs CHANGED
@@ -1,143 +1,51 @@
1
- 'use strict';
2
-
1
+ var __VOBS_CJS_FILE_URL = require("url").pathToFileURL(__filename).href;
2
+ "use strict";
3
3
  var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
-
6
- // packages/reactivity/src/debug.ts
7
- var activeDebugHooks = null;
8
- function hasDebugHooks() {
9
- return activeDebugHooks !== null;
10
- }
11
- __name(hasDebugHooks, "hasDebugHooks");
12
- function invokeDebug(name, ...args) {
13
- return;
14
- }
15
- __name(invokeDebug, "invokeDebug");
16
-
17
- // packages/reactivity/src/owner.ts
18
- var currentOwner = null;
19
- function getCurrentOwner() {
20
- return currentOwner;
21
- }
22
- __name(getCurrentOwner, "getCurrentOwner");
23
-
24
- // packages/reactivity/src/scheduler.ts
25
- var _Scheduler = class _Scheduler {
26
- constructor() {
27
- this.dirtyEffects = /* @__PURE__ */ new Set();
28
- this.lowPriorityEffects = /* @__PURE__ */ new Set();
29
- // flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。
30
- this.normalBuffer = [];
31
- this.lowBuffer = [];
32
- this.flushing = false;
33
- this.scheduled = false;
34
- this.batchDepth = 0;
35
- }
36
- schedule(effect2) {
37
- if (effect2.disposed) return;
38
- this.dirtyEffects.add(effect2);
39
- this.lowPriorityEffects.delete(effect2);
40
- this.ensureScheduled();
41
- }
42
- /** Queue an effect behind normal updates while preserving deterministic order. */
43
- scheduleLow(effect2) {
44
- if (effect2.disposed) return;
45
- if (!this.dirtyEffects.has(effect2)) this.lowPriorityEffects.add(effect2);
46
- this.ensureScheduled();
47
- }
48
- ensureScheduled() {
49
- if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {
50
- this.scheduled = true;
51
- queueMicrotask(() => {
52
- this.scheduled = false;
53
- this.flush();
54
- });
55
- }
56
- }
57
- remove(effect2) {
58
- this.dirtyEffects.delete(effect2);
59
- this.lowPriorityEffects.delete(effect2);
60
- }
61
- batch(fn) {
62
- this.batchDepth++;
63
- try {
64
- return fn();
65
- } finally {
66
- this.batchDepth--;
67
- if (this.batchDepth === 0) this.flush();
68
- }
69
- }
70
- flush() {
71
- if (this.flushing || this.batchDepth > 0) return;
72
- this.flushing = true;
73
- let rounds = 0;
74
- let firstError;
75
- let hasError = false;
76
- try {
77
- while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {
78
- if (++rounds > 100) {
79
- this.dirtyEffects.clear();
80
- this.lowPriorityEffects.clear();
81
- throw new Error("Vobs: \u54CD\u5E94\u5F0F\u66F4\u65B0\u8D85\u8FC7 100 \u8F6E\uFF0C\u53EF\u80FD\u5B58\u5728\u5FAA\u73AF\u4F9D\u8D56");
82
- }
83
- this.collectRunnable(this.dirtyEffects, this.normalBuffer);
84
- this.collectRunnable(this.lowPriorityEffects, this.lowBuffer);
85
- sortEffects(this.normalBuffer);
86
- sortEffects(this.lowBuffer);
87
- for (const effect2 of this.normalBuffer) {
88
- try {
89
- effect2.run();
90
- } catch (error) {
91
- if (!hasError) {
92
- firstError = error;
93
- hasError = true;
94
- }
95
- }
96
- }
97
- for (const effect2 of this.lowBuffer) {
98
- try {
99
- effect2.run();
100
- } catch (error) {
101
- if (!hasError) {
102
- firstError = error;
103
- hasError = true;
104
- }
105
- }
106
- }
107
- this.normalBuffer.length = 0;
108
- this.lowBuffer.length = 0;
109
- }
110
- } finally {
111
- this.normalBuffer.length = 0;
112
- this.lowBuffer.length = 0;
113
- this.flushing = false;
114
- }
115
- if (hasError) throw firstError;
116
- }
117
- /** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */
118
- collectRunnable(source, target) {
119
- for (const effect2 of source) {
120
- if (!effect2.disposed) target.push(effect2);
121
- }
122
- source.clear();
123
- }
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
124
11
  };
125
- __name(_Scheduler, "Scheduler");
126
- function sortEffects(effects) {
127
- if (effects.length > 1) {
128
- effects.sort((a, b) => b.depth - a.depth || a.order - b.order);
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
129
17
  }
130
- }
131
- __name(sortEffects, "sortEffects");
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // packages/runtime/src/fragment.ts
23
+ var fragment_exports = {};
24
+ __export(fragment_exports, {
25
+ createFragment: () => createFragment,
26
+ isVobsFragment: () => isVobsFragment
27
+ });
28
+ module.exports = __toCommonJS(fragment_exports);
29
+ var import_reactivity3 = require("@vobs/reactivity");
30
+
31
+ // packages/runtime/src/ops.ts
32
+ var import_reactivity2 = require("@vobs/reactivity");
132
33
 
133
34
  // packages/runtime/src/hmr.ts
134
35
  var globalTarget = globalThis;
135
36
  var hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: /* @__PURE__ */ new Map() };
136
37
  globalTarget.__VOBS_HMR__ = hmrGlobal;
38
+
39
+ // packages/runtime/src/ref.ts
40
+ var import_reactivity = require("@vobs/reactivity");
41
+
42
+ // packages/runtime/src/ops.ts
43
+ var currentRenderer = null;
137
44
  function getRenderer() {
138
- {
45
+ if (!currentRenderer) {
139
46
  throw new Error("\u6E32\u67D3\u5668\u672A\u521D\u59CB\u5316");
140
47
  }
48
+ return currentRenderer;
141
49
  }
142
50
  __name(getRenderer, "getRenderer");
143
51
  function createComment(content) {
@@ -151,6 +59,7 @@ function createFragment(factory) {
151
59
  const end = createComment("vobs:fragment:end");
152
60
  let parent = null;
153
61
  let initialized = false;
62
+ const owner = (0, import_reactivity3.getCurrentOwner)();
154
63
  const fragment = {
155
64
  kind: "vobs-fragment",
156
65
  start,
@@ -168,7 +77,8 @@ function createFragment(factory) {
168
77
  renderer.insertBefore(nextParent, end, anchor);
169
78
  parent = nextParent;
170
79
  initialized = true;
171
- factory(nextParent, end);
80
+ if (owner) owner.run(() => factory(nextParent, end));
81
+ else factory(nextParent, end);
172
82
  },
173
83
  unmount(nextParent) {
174
84
  if (!initialized || parent !== nextParent) {
@@ -209,8 +119,9 @@ function moveRange(parent, start, end, anchor) {
209
119
  for (const node of nodes) renderer.insertBefore(parent, node, anchor);
210
120
  }
211
121
  __name(moveRange, "moveRange");
212
-
213
- exports.createFragment = createFragment;
214
- exports.isVobsFragment = isVobsFragment;
215
- //# sourceMappingURL=fragment.cjs.map
122
+ // Annotate the CommonJS export names for ESM import in node:
123
+ 0 && (module.exports = {
124
+ createFragment,
125
+ isVobsFragment
126
+ });
216
127
  //# sourceMappingURL=fragment.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../reactivity/src/debug.ts","../../reactivity/src/owner.ts","../../reactivity/src/scheduler.ts","../src/hmr.ts","../src/ops.ts","../src/fragment.ts"],"names":["effect"],"mappings":"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","file":"fragment.cjs","sourcesContent":["import type { Effect } from './effect'\nimport type { Owner } from './owner'\nimport type { Dependency, ReadableSignal, Subscriber } from './signal'\n\nexport interface ReactivityDebugHooks {\n ownerCreated?(owner: Owner): void\n ownerNamed?(owner: Owner, name: string): void\n ownerDisposed?(owner: Owner): void\n signalCreated?(signal: ReadableSignal<unknown>, owner: Owner | null): void\n signalNamed?(signal: ReadableSignal<unknown>, name: string): void\n signalRead?(signal: ReadableSignal<unknown>, subscriber: Subscriber): void\n signalChanged?(signal: ReadableSignal<unknown>, previousValue: unknown, nextValue: unknown): void\n signalDisposed?(signal: ReadableSignal<unknown>): void\n dependencyTracked?(dependency: Dependency, subscriber: Subscriber): void\n dependencyUntracked?(dependency: Dependency, subscriber: Subscriber): void\n effectCreated?(effect: Effect, owner: Owner | null): void\n effectInvalidated?(effect: Effect): void\n effectRunStart?(effect: Effect): void\n effectRunEnd?(effect: Effect, error?: unknown, handled?: boolean): void\n effectDisposed?(effect: Effect): void\n memoCreated?(signal: ReadableSignal<unknown>, subscriber: Subscriber, owner: Owner | null): void\n memoInvalidated?(signal: ReadableSignal<unknown>): void\n flushStart?(): void\n flushEnd?(): void\n}\n\nlet activeDebugHooks: ReactivityDebugHooks | null = null\nconst signalNames = new WeakMap<object, string>()\n\nexport function setDebugHooks(hooks: ReactivityDebugHooks | null): ReactivityDebugHooks | null {\n const previous = activeDebugHooks\n activeDebugHooks = hooks\n return previous\n}\n\nexport function getDebugHooks(): ReactivityDebugHooks | null {\n return activeDebugHooks\n}\n\n/** 热路径守卫:无 hooks 时跳过 invokeDebug 调用,避免 rest 参数数组分配。 */\nexport function hasDebugHooks(): boolean {\n return activeDebugHooks !== null\n}\n\nexport function setSignalDebugName(signal: ReadableSignal<unknown>, name: string): void {\n signalNames.set(signal, name)\n invokeDebug('signalNamed', signal, name)\n}\n\nexport function getSignalDebugName(signal: ReadableSignal<unknown>): string | undefined {\n return signalNames.get(signal)\n}\n\nexport function invokeDebug<K extends keyof ReactivityDebugHooks>(\n name: K,\n ...args: Parameters<NonNullable<ReactivityDebugHooks[K]>>\n): void {\n const callback = activeDebugHooks?.[name] as ((...values: unknown[]) => void) | undefined\n if (!callback) return\n try {\n callback(...args)\n } catch {\n // Debug tooling must never change application behavior.\n }\n}\n","import { invokeDebug, hasDebugHooks } from './debug'\n\nexport interface Owner {\n readonly id: string\n readonly parent: Owner | null\n readonly children: readonly Owner[]\n readonly depth: number\n readonly disposed: boolean\n run<T>(fn: () => T): T\n addCleanup(cleanup: () => void): void\n onDispose(cleanup: () => void): void\n onError(handler: (error: unknown) => void): () => void\n handleError(error: unknown): boolean\n dispose(): void\n}\n\nlet currentOwner: Owner | null = null\nlet nextOwnerId = 1\nconst ownerNames = new WeakMap<Owner, string>()\n\nexport function createOwner(): Owner {\n const parent = currentOwner\n let disposed = parent?.disposed ?? false\n const children: Owner[] = []\n const cleanups: Array<() => void> = []\n const errorHandlers = new Set<(error: unknown) => void>()\n\n const owner: Owner = {\n id: `owner-${nextOwnerId++}`,\n parent,\n children,\n depth: (parent?.depth ?? -1) + 1,\n\n get disposed(): boolean {\n return disposed\n },\n\n run<T>(fn: () => T): T {\n if (disposed) throw new Error('Vobs: 已销毁的 Owner 不能继续运行')\n const previous = currentOwner\n currentOwner = owner\n try {\n return fn()\n } finally {\n currentOwner = previous\n }\n },\n\n addCleanup(cleanup: () => void): void {\n if (disposed) {\n cleanup()\n return\n }\n cleanups.push(cleanup)\n },\n\n onDispose(cleanup: () => void): void {\n owner.addCleanup(cleanup)\n },\n\n onError(handler: (error: unknown) => void): () => void {\n errorHandlers.add(handler)\n const remove = () => errorHandlers.delete(handler)\n owner.addCleanup(remove)\n return remove\n },\n\n handleError(error: unknown): boolean {\n for (const handler of [...errorHandlers].reverse()) {\n try {\n handler(error)\n return true\n } catch (handlerError) {\n return parent?.handleError(handlerError) ?? false\n }\n }\n return parent?.handleError(error) ?? false\n },\n\n dispose(): void {\n if (disposed) return\n disposed = true\n for (const child of [...children]) child.dispose()\n children.length = 0\n\n let firstError: unknown\n for (let index = cleanups.length - 1; index >= 0; index--) {\n try {\n cleanups[index]()\n } catch (error) {\n firstError ??= error\n }\n }\n cleanups.length = 0\n\n if (parent) {\n const index = parent.children.indexOf(owner)\n if (index >= 0) (parent.children as Owner[]).splice(index, 1)\n }\n if (hasDebugHooks()) invokeDebug('ownerDisposed', owner)\n if (firstError) throw firstError\n }\n }\n\n if (parent && !parent.disposed) (parent.children as Owner[]).push(owner)\n if (hasDebugHooks()) invokeDebug('ownerCreated', owner)\n return owner\n}\n\nexport function setOwnerDebugName(owner: Owner, name: string): void {\n ownerNames.set(owner, name)\n if (hasDebugHooks()) invokeDebug('ownerNamed', owner, name)\n}\n\nexport function getOwnerDebugName(owner: Owner): string | undefined {\n return ownerNames.get(owner)\n}\n\nexport function getCurrentOwner(): Owner | null {\n return currentOwner\n}\n\n/** Re-enter an Owner for an explicitly captured asynchronous continuation. */\nexport function runWithOwner<T>(owner: Owner, fn: () => T): T {\n return owner.run(fn)\n}\n\nexport function onDispose(cleanup: () => void): void {\n const owner = getCurrentOwner()\n if (!owner) throw new Error('Vobs: onDispose 必须在 Owner 作用域内调用')\n owner.onDispose(cleanup)\n}\n","import type { Effect } from './effect'\nimport { hasDebugHooks, invokeDebug } from './debug'\n\nexport class Scheduler {\n private readonly dirtyEffects = new Set<Effect>()\n private readonly lowPriorityEffects = new Set<Effect>()\n // flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。\n private readonly normalBuffer: Effect[] = []\n private readonly lowBuffer: Effect[] = []\n private flushing = false\n private scheduled = false\n private batchDepth = 0\n\n schedule(effect: Effect): void {\n if (effect.disposed) return\n this.dirtyEffects.add(effect)\n this.lowPriorityEffects.delete(effect)\n this.ensureScheduled()\n }\n\n /** Queue an effect behind normal updates while preserving deterministic order. */\n scheduleLow(effect: Effect): void {\n if (effect.disposed) return\n if (!this.dirtyEffects.has(effect)) this.lowPriorityEffects.add(effect)\n this.ensureScheduled()\n }\n\n private ensureScheduled(): void {\n if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {\n this.scheduled = true\n queueMicrotask(() => {\n this.scheduled = false\n this.flush()\n })\n }\n }\n\n remove(effect: Effect): void {\n this.dirtyEffects.delete(effect)\n this.lowPriorityEffects.delete(effect)\n }\n\n batch<T>(fn: () => T): T {\n this.batchDepth++\n try {\n return fn()\n } finally {\n this.batchDepth--\n if (this.batchDepth === 0) this.flush()\n }\n }\n\n flush(): void {\n if (this.flushing || this.batchDepth > 0) return\n this.flushing = true\n const debugEnabled = hasDebugHooks()\n if (debugEnabled) invokeDebug('flushStart')\n let rounds = 0\n let firstError: unknown\n let hasError = false\n try {\n while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {\n if (++rounds > 100) {\n this.dirtyEffects.clear()\n this.lowPriorityEffects.clear()\n throw new Error('Vobs: 响应式更新超过 100 轮,可能存在循环依赖')\n }\n\n // normal 先、low 后,两组分别排序:与旧的合并排序语义一致\n // (旧比较器里 low 优先级本就高于 depth),但消除了比较器内的 Set 查找。\n this.collectRunnable(this.dirtyEffects, this.normalBuffer)\n this.collectRunnable(this.lowPriorityEffects, this.lowBuffer)\n sortEffects(this.normalBuffer)\n sortEffects(this.lowBuffer)\n for (const effect of this.normalBuffer) {\n try {\n effect.run()\n } catch (error) {\n // Isolate one failed effect from the rest of the flush. Re-throw\n // the first error after all runnable effects have had a chance.\n if (!hasError) {\n firstError = error\n hasError = true\n }\n }\n }\n for (const effect of this.lowBuffer) {\n try {\n effect.run()\n } catch (error) {\n if (!hasError) {\n firstError = error\n hasError = true\n }\n }\n }\n this.normalBuffer.length = 0\n this.lowBuffer.length = 0\n }\n } finally {\n this.normalBuffer.length = 0\n this.lowBuffer.length = 0\n this.flushing = false\n if (debugEnabled) invokeDebug('flushEnd')\n }\n if (hasError) throw firstError\n }\n\n /** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */\n private collectRunnable(source: Set<Effect>, target: Effect[]): void {\n for (const effect of source) {\n if (!effect.disposed) target.push(effect)\n }\n source.clear()\n }\n}\n\n/** depth 深的先跑(子 effect 先于父),同深度按创建顺序。 */\nfunction sortEffects(effects: Effect[]): void {\n if (effects.length > 1) {\n effects.sort((a, b) => b.depth - a.depth || a.order - b.order)\n }\n}\n\nexport const scheduler = new Scheduler()\n\nexport function batch<T>(fn: () => T): T {\n return scheduler.batch(fn)\n}\n\n/** Schedule a low-priority effect explicitly. */\nexport function scheduleLow(effect: Effect): void {\n effect.scheduleLow()\n}\n","import type { VobsNode } from './fragment'\n\nexport type HmrComponent<Props extends object = Record<string, unknown>> =\n (props: Props) => VobsNode\n\nexport interface HmrStateStore {\n get<T>(key: string, initial: T | (() => T)): T\n set<T>(key: string, value: T): void\n has(key: string): boolean\n delete(key: string): void\n clear(): void\n}\n\nexport interface HmrInstance {\n node: VobsNode\n parent: Node | null\n refresh(): void\n}\n\ninterface HmrModuleState {\n readonly components: Map<string, HmrComponent>\n readonly state: Map<string, unknown>\n readonly instances: Set<HmrInstance>\n}\n\ninterface HmrGlobal {\n modules: Map<string, HmrModuleState>\n}\n\nconst globalTarget = globalThis as typeof globalThis & { __VOBS_HMR__?: HmrGlobal }\nconst hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: new Map<string, HmrModuleState>() }\nglobalTarget.__VOBS_HMR__ = hmrGlobal\n\nexport function resolveComponent<Props extends object>(\n component: HmrComponent<Props>,\n moduleId: string,\n exportName: string\n): HmrComponent<Props> {\n const module = getModule(moduleId)\n const existing = module.components.get(exportName)\n if (existing) return existing as HmrComponent<Props>\n\n const proxy = ((props: Props) => {\n const current = (proxy as HmrComponent<Props> & { current: HmrComponent<Props> }).current\n return current(props)\n }) as HmrComponent<Props> & { current: HmrComponent<Props> }\n proxy.current = component\n Object.defineProperties(proxy, {\n displayName: { configurable: true, value: component.name || exportName },\n hmrKey: { configurable: false, value: `${moduleId}:${exportName}` }\n })\n module.components.set(exportName, proxy as HmrComponent)\n return proxy\n}\n\nexport function updateHmrModule(_moduleId: string, nextModule: Record<string, unknown>): void {\n const modules = [...hmrGlobal.modules.values()]\n for (const module of modules) {\n let changed = false\n for (const [name, proxy] of module.components) {\n const next = nextModule[name]\n if (typeof next !== 'function') continue\n const hmrProxy = proxy as HmrComponent & { current: HmrComponent; displayName?: string }\n hmrProxy.current = next as HmrComponent\n Object.defineProperty(hmrProxy, 'displayName', { configurable: true, value: next.name || name })\n changed = true\n }\n if (!changed) continue\n for (const instance of module.instances) {\n try {\n instance.refresh()\n } catch {\n // HMR failures remain application errors on the next normal render.\n }\n }\n }\n}\n\nexport function disposeHmrModule(_moduleId: string): void {\n // State and component proxies intentionally survive module disposal.\n}\n\nexport function createHmrStateStore(moduleId: string): HmrStateStore {\n const state = getModule(moduleId).state\n return {\n get<T>(key: string, initial: T | (() => T)): T {\n if (!state.has(key)) state.set(key, typeof initial === 'function' ? (initial as () => T)() : initial)\n return state.get(key) as T\n },\n set<T>(key: string, value: T): void {\n state.set(key, value)\n },\n has: key => state.has(key),\n delete: key => { state.delete(key) },\n clear: () => { state.clear() }\n }\n}\n\nexport function registerHmrInstance(moduleId: string, instance: HmrInstance): () => void {\n const instances = getModule(moduleId).instances\n instances.add(instance)\n return () => instances.delete(instance)\n}\n\nexport function markHmrInstanceMounted(node: VobsNode, parent: Node): void {\n const instance = hmrInstances.get(node as object)\n if (instance) instance.parent = parent\n}\n\nfunction getModule(moduleId: string): HmrModuleState {\n let module = hmrGlobal.modules.get(moduleId)\n if (!module) {\n module = { components: new Map(), state: new Map(), instances: new Set() }\n hmrGlobal.modules.set(moduleId, module)\n }\n return module\n}\n\nconst hmrInstances = new WeakMap<object, HmrInstance>()\n\nexport function associateHmrInstance(node: VobsNode, instance: HmrInstance): void {\n hmrInstances.set(node as object, instance)\n}\n","// 编译产物调用的基础操作\n\nimport { createOwner, getCurrentOwner, setOwnerDebugName, type Owner } from '@vobs/reactivity'\nimport { isVobsFragment, type VobsNode } from './fragment'\nimport { describeDebugNode, getRuntimeDebugHooks, invokeRuntimeDebug, readDebugValue } from './debug'\nimport {\n associateHmrInstance,\n markHmrInstanceMounted,\n registerHmrInstance,\n type HmrInstance\n} from './hmr'\nimport type { VobsRenderer } from './renderer'\nimport { setRef } from './ref'\n\ntype RuntimeRenderer = VobsRenderer<Node, Text, Element, Comment>\n\nlet currentRenderer: RuntimeRenderer | null = null\nconst nodeOwners = new WeakMap<object, Owner>()\ninterface EventBinding {\n readonly handler: EventListener\n readonly owner: Owner | null\n readonly original: EventListener\n}\nconst eventBindings = new WeakMap<object, Map<string, EventBinding>>()\n\nexport function setRenderer<\n NodeType,\n TextNode extends NodeType,\n ElementNode extends NodeType,\n CommentNode extends NodeType\n>(renderer: VobsRenderer<NodeType, TextNode, ElementNode, CommentNode>): void {\n // 编译产物仍使用 DOM 节点声明;实际宿主类型由应用提供的渲染器决定。\n currentRenderer = renderer as unknown as RuntimeRenderer\n}\n\nexport function getRenderer(): RuntimeRenderer {\n if (!currentRenderer) {\n throw new Error('渲染器未初始化')\n }\n return currentRenderer\n}\n\nexport function createText(content: string): Text {\n return getRenderer().createText(content)\n}\n\nexport function createElement(tag: string): Element {\n return getRenderer().createElement(tag)\n}\n\nexport function createComment(content: string): Comment {\n return getRenderer().createComment(content)\n}\n\nexport function insertBefore(\n parent: Node,\n child: VobsNode,\n anchor: VobsNode | null\n): void {\n if (isVobsFragment(child)) {\n child.mount(parent, isVobsFragment(anchor) ? anchor.start : anchor)\n return\n }\n getRenderer().insertBefore(parent, child, isVobsFragment(anchor) ? anchor.start : anchor)\n markHmrInstanceMounted(child, parent)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'insert',\n target: describeDebugNode(child),\n parent: describeDebugNode(parent)\n })\n }\n}\n\nexport function removeChild(\n parent: Node,\n child: VobsNode\n): void {\n disposeNodeOwner(child)\n if (isVobsFragment(child)) {\n child.unmount(parent)\n return\n }\n getRenderer().removeChild(parent, child)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'remove',\n target: describeDebugNode(child),\n parent: describeDebugNode(parent)\n })\n }\n}\n\nexport function setTextContent(\n node: Text,\n content: string\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => node.textContent)\n : undefined\n getRenderer().setTextContent(node, content)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'text',\n target: describeDebugNode(node),\n previousValue,\n nextValue: content\n })\n }\n}\n\nexport function setProperty(\n node: Element,\n key: string,\n value: unknown\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => Reflect.get(node, key))\n : undefined\n getRenderer().setProperty(node, key, value)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'property',\n target: describeDebugNode(node),\n key,\n previousValue,\n nextValue: value\n })\n }\n}\n\nexport function setAttribute(\n node: Element,\n key: string,\n value: string\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => typeof node.getAttribute === 'function' ? node.getAttribute(key) : undefined)\n : undefined\n getRenderer().setAttribute(node, key, value)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'attribute',\n target: describeDebugNode(node),\n key,\n previousValue,\n nextValue: value\n })\n }\n}\n\nexport function spreadProps(node: Element, props: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(props)) {\n if (key === 'key' || value === null || value === undefined) continue\n if (key === 'ref') {\n setRef(node, value)\n continue\n }\n if (key.startsWith('on') && typeof value === 'function') addEventListener(node, key.slice(2).toLowerCase(), value as EventListener)\n // property 键的 false 有语义(如 disabled={false} 必须清除),不能跳过;\n // attribute 键的 false 表示“不设置”,与 HTML 语义一致。\n else if (isPropertyKey(key)) setProperty(node, key, value)\n else if (value === false) continue\n else setAttribute(node, key === 'className' ? 'class' : key, key === 'style' && isStyleObject(value) ? formatStyle(value) : String(value))\n }\n}\n\n/** Apply compile-time host properties in one renderer pass. */\nexport function setStaticProps(node: Element, props: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(props)) {\n if (key === 'key' || key === 'ref' || key.startsWith('on')) continue\n if (value === null || value === undefined) continue\n if (isPropertyKey(key)) setProperty(node, key, value)\n else if (value === false) continue\n else setAttribute(node, key === 'className' ? 'class' : key, key === 'style' && isStyleObject(value) ? formatStyle(value) : String(value))\n }\n}\n\nfunction isPropertyKey(key: string): boolean {\n return key === 'value' || key === 'checked' || key === 'selected' || key === 'disabled'\n || key === 'multiple' || key === 'readOnly' || key === 'required'\n || key === 'autofocus' || key === 'hidden' || key === 'tabIndex'\n}\n\nfunction isStyleObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction formatStyle(value: Record<string, unknown>): string {\n return Object.entries(value).filter(([, entry]) => entry !== null && entry !== undefined && entry !== false)\n .map(([key, entry]) => `${key.replace(/[A-Z]/gu, match => `-${match.toLowerCase()}`)}:${String(entry)}`).join(';')\n}\n\nexport function addEventListener(\n node: Element,\n event: string,\n handler: EventListener\n): void {\n const renderer = getRenderer()\n const owner = getCurrentOwner()\n let bindings = eventBindings.get(node)\n if (!bindings) {\n bindings = new Map()\n eventBindings.set(node, bindings)\n }\n const previous = bindings.get(event)\n if (previous && previous.original === handler && previous.owner === owner) return\n if (previous) renderer.removeEventListener(node, event, previous.handler)\n const listener = owner ? (reason: Event) => {\n try {\n owner.run(() => handler(reason))\n } catch (error) {\n const handled = owner.handleError(error)\n invokeRuntimeDebug('error', {\n error,\n owner,\n phase: 'event',\n handled,\n recovery: handled ? 'handled' : 'propagated'\n })\n if (!handled) throw error\n }\n } : handler\n const binding: EventBinding = { handler: listener, owner, original: handler }\n bindings.set(event, binding)\n renderer.addEventListener(node, event, listener)\n owner?.onDispose(() => {\n if (bindings?.get(event) !== binding) return\n bindings.delete(event)\n renderer.removeEventListener(node, event, listener)\n })\n}\n\nexport function removeEventListener(\n node: Element,\n event: string,\n handler: EventListener\n): void {\n const renderer = getRenderer()\n const binding = eventBindings.get(node)?.get(event)\n renderer.removeEventListener(node, event, binding?.handler ?? handler)\n eventBindings.get(node)?.delete(event)\n}\n\nexport function clear(container: Node): void {\n getRenderer().clear(container)\n}\n\ntype VobsComponent = (...args: any[]) => VobsNode\n\ntype ComponentProps<Component extends VobsComponent> = Component extends (\n props: infer Props\n) => VobsNode\n ? NonNullable<Props> extends object ? NonNullable<Props> : Record<string, never>\n : Record<string, never>\n\nexport function createComponent<Component extends VobsComponent>(\n component: Component,\n props: ComponentProps<Component>,\n source?: VobsSourceLocation\n): VobsNode {\n const owner = createOwner()\n const componentName = (component as typeof component & { displayName?: string }).displayName\n || component.name\n || 'anonymous'\n setOwnerDebugName(owner, source\n ? `${componentName} (${source.file}:${source.line}:${source.column})`\n : componentName)\n owner.onError(reason => {\n attachSourceLocation(reason, source)\n attachComponentContext(reason, componentName, owner.id)\n throw reason\n })\n let node: VobsNode\n try {\n node = owner.run(() => component(props))\n } catch (error) {\n owner.dispose()\n attachSourceLocation(error, source)\n attachComponentContext(error, componentName, owner.id)\n throw error\n }\n associateNodeOwner(node, owner)\n const hmrKey = (component as typeof component & { hmrKey?: string }).hmrKey\n if (hmrKey) {\n const instance: HmrInstance = {\n node,\n parent: null,\n refresh(): void {\n const previous = instance.node\n const next = owner.run(() => component(props))\n if (instance.parent && !isVobsFragment(previous) && !isVobsFragment(next)) {\n getRenderer().insertBefore(instance.parent, next, previous)\n getRenderer().removeChild(instance.parent, previous)\n }\n nodeOwners.delete(previous as object)\n nodeOwners.set(next as object, owner)\n associateHmrInstance(next, instance)\n instance.node = next\n }\n }\n associateHmrInstance(node, instance)\n const separator = hmrKey.lastIndexOf(':')\n const moduleId = separator < 0 ? hmrKey : hmrKey.slice(0, separator)\n const cleanup = registerHmrInstance(moduleId, instance)\n owner.onDispose(cleanup)\n }\n return node\n}\n\nexport interface VobsSourceLocation {\n readonly file: string\n readonly line: number\n readonly column: number\n}\n\nexport interface VobsLocatedError extends Error {\n readonly vobsSource?: VobsSourceLocation\n readonly vobsComponent?: string\n readonly vobsOwnerId?: string\n}\n\nfunction attachSourceLocation(reason: unknown, source: VobsSourceLocation | undefined): void {\n if (!source || (!reason || (typeof reason !== 'object' && typeof reason !== 'function'))) return\n const error = reason as VobsLocatedError\n if (error.vobsSource) return\n try {\n Object.defineProperty(error, 'vobsSource', {\n configurable: true,\n enumerable: false,\n value: source,\n writable: false\n })\n } catch {\n // Frozen third-party errors still propagate with their original details.\n }\n}\n\nfunction attachComponentContext(reason: unknown, component: string, ownerId: string): void {\n if (!reason || (typeof reason !== 'object' && typeof reason !== 'function')) return\n const error = reason as VobsLocatedError\n try {\n if (!error.vobsComponent) Object.defineProperty(error, 'vobsComponent', { configurable: true, enumerable: false, value: component, writable: false })\n if (!error.vobsOwnerId) Object.defineProperty(error, 'vobsOwnerId', { configurable: true, enumerable: false, value: ownerId, writable: false })\n } catch {\n // Frozen third-party errors still propagate with their original details.\n }\n}\n\nexport function createBlock(factory: () => VobsNode | null | undefined | false): VobsNode | null {\n const owner = createOwner()\n setOwnerDebugName(owner, 'dynamic')\n let node: VobsNode | null | undefined | false\n try {\n node = owner.run(factory)\n } catch (error) {\n owner.dispose()\n throw error\n }\n if (!node) {\n owner.dispose()\n return null\n }\n associateNodeOwner(node, owner)\n return node\n}\n\nexport function associateNodeOwner(node: VobsNode, owner: Owner): void {\n nodeOwners.set(node, owner)\n}\n\nexport function disposeNodeOwner(node: VobsNode): void {\n const owner = nodeOwners.get(node)\n if (!owner) return\n nodeOwners.delete(node)\n owner.dispose()\n}\n","import { getCurrentOwner } from '@vobs/reactivity'\nimport { createComment, getRenderer } from './ops'\n\nexport interface VobsFragment {\n readonly kind: 'vobs-fragment'\n readonly start: Node\n readonly end: Node\n readonly mount: (parent: Node, anchor: Node | null) => void\n readonly unmount: (parent: Node) => void\n}\n\nexport type VobsNode = Node | VobsFragment\nexport type FragmentFactory = (parent: Node, anchor: Node) => void\n\nexport function createFragment(factory: FragmentFactory): VobsFragment {\n const start = createComment('vobs:fragment:start')\n const end = createComment('vobs:fragment:end')\n let parent: Node | null = null\n let initialized = false\n const owner = getCurrentOwner()\n\n const fragment: VobsFragment = {\n kind: 'vobs-fragment',\n start,\n end,\n mount(nextParent, anchor): void {\n if (parent && parent !== nextParent) {\n throw new Error('Vobs Fragment: 不能跨父节点移动 Fragment')\n }\n\n if (initialized) {\n moveRange(nextParent, start, end, anchor)\n return\n }\n\n const renderer = getRenderer()\n renderer.insertBefore(nextParent, start, anchor)\n renderer.insertBefore(nextParent, end, anchor)\n parent = nextParent\n initialized = true\n if (owner) owner.run(() => factory(nextParent, end))\n else factory(nextParent, end)\n },\n unmount(nextParent): void {\n if (!initialized || parent !== nextParent) {\n throw new Error('Vobs Fragment: Fragment 不属于指定父节点')\n }\n const renderer = getRenderer()\n let current = renderer.nextSibling(start)\n while (current && current !== end) {\n const next = renderer.nextSibling(current)\n renderer.removeChild(nextParent, current)\n current = next\n }\n renderer.removeChild(nextParent, start)\n renderer.removeChild(nextParent, end)\n parent = null\n initialized = false\n }\n }\n return fragment\n}\n\nexport function isVobsFragment(value: unknown): value is VobsFragment {\n return Boolean(value) && typeof value === 'object' && (value as VobsFragment).kind === 'vobs-fragment'\n}\n\nfunction moveRange(parent: Node, start: Node, end: Node, anchor: Node | null): void {\n const renderer = getRenderer()\n const nodes: Node[] = [start]\n let current = renderer.nextSibling(start)\n while (current) {\n nodes.push(current)\n if (current === end) break\n current = renderer.nextSibling(current)\n }\n if (nodes[nodes.length - 1] !== end) {\n throw new Error('Vobs Fragment: 找不到结束锚点')\n }\n for (const node of nodes) renderer.insertBefore(parent, node, anchor)\n}\n"]}
1
+ {"version":3,"sources":["../src/fragment.ts","../src/ops.ts","../src/hmr.ts","../src/ref.ts"],"sourcesContent":["import { getCurrentOwner } from '@vobs/reactivity'\nimport { createComment, getRenderer } from './ops'\n\nexport interface VobsFragment {\n readonly kind: 'vobs-fragment'\n readonly start: Node\n readonly end: Node\n readonly mount: (parent: Node, anchor: Node | null) => void\n readonly unmount: (parent: Node) => void\n}\n\nexport type VobsNode = Node | VobsFragment\nexport type FragmentFactory = (parent: Node, anchor: Node) => void\n\nexport function createFragment(factory: FragmentFactory): VobsFragment {\n const start = createComment('vobs:fragment:start')\n const end = createComment('vobs:fragment:end')\n let parent: Node | null = null\n let initialized = false\n const owner = getCurrentOwner()\n\n const fragment: VobsFragment = {\n kind: 'vobs-fragment',\n start,\n end,\n mount(nextParent, anchor): void {\n if (parent && parent !== nextParent) {\n throw new Error('Vobs Fragment: 不能跨父节点移动 Fragment')\n }\n\n if (initialized) {\n moveRange(nextParent, start, end, anchor)\n return\n }\n\n const renderer = getRenderer()\n renderer.insertBefore(nextParent, start, anchor)\n renderer.insertBefore(nextParent, end, anchor)\n parent = nextParent\n initialized = true\n if (owner) owner.run(() => factory(nextParent, end))\n else factory(nextParent, end)\n },\n unmount(nextParent): void {\n if (!initialized || parent !== nextParent) {\n throw new Error('Vobs Fragment: Fragment 不属于指定父节点')\n }\n const renderer = getRenderer()\n let current = renderer.nextSibling(start)\n while (current && current !== end) {\n const next = renderer.nextSibling(current)\n renderer.removeChild(nextParent, current)\n current = next\n }\n renderer.removeChild(nextParent, start)\n renderer.removeChild(nextParent, end)\n parent = null\n initialized = false\n }\n }\n return fragment\n}\n\nexport function isVobsFragment(value: unknown): value is VobsFragment {\n return Boolean(value) && typeof value === 'object' && (value as VobsFragment).kind === 'vobs-fragment'\n}\n\nfunction moveRange(parent: Node, start: Node, end: Node, anchor: Node | null): void {\n const renderer = getRenderer()\n const nodes: Node[] = [start]\n let current = renderer.nextSibling(start)\n while (current) {\n nodes.push(current)\n if (current === end) break\n current = renderer.nextSibling(current)\n }\n if (nodes[nodes.length - 1] !== end) {\n throw new Error('Vobs Fragment: 找不到结束锚点')\n }\n for (const node of nodes) renderer.insertBefore(parent, node, anchor)\n}\n","// 编译产物调用的基础操作\n\nimport { createOwner, getCurrentOwner, setOwnerDebugName, untrack, type Owner } from '@vobs/reactivity'\nimport { isVobsFragment, type VobsNode } from './fragment'\nimport { describeDebugNode, getRuntimeDebugHooks, invokeRuntimeDebug, readDebugValue } from './debug'\nimport {\n associateHmrInstance,\n markHmrInstanceMounted,\n registerHmrInstance,\n type HmrInstance\n} from './hmr'\nimport type { VobsRenderer } from './renderer'\nimport { setRef } from './ref'\n\ntype RuntimeRenderer = VobsRenderer<Node, Text, Element, Comment>\n\nlet currentRenderer: RuntimeRenderer | null = null\nconst nodeOwners = new WeakMap<object, Owner>()\ninterface EventBinding {\n readonly handler: EventListener\n readonly owner: Owner | null\n readonly original: EventListener\n}\nconst eventBindings = new WeakMap<object, Map<string, EventBinding>>()\n\nexport function setRenderer<\n NodeType,\n TextNode extends NodeType,\n ElementNode extends NodeType,\n CommentNode extends NodeType\n>(renderer: VobsRenderer<NodeType, TextNode, ElementNode, CommentNode>): void {\n // 编译产物仍使用 DOM 节点声明;实际宿主类型由应用提供的渲染器决定。\n currentRenderer = renderer as unknown as RuntimeRenderer\n}\n\nexport function getRenderer(): RuntimeRenderer {\n if (!currentRenderer) {\n throw new Error('渲染器未初始化')\n }\n return currentRenderer\n}\n\nexport function createText(content: string): Text {\n return getRenderer().createText(content)\n}\n\nexport function createElement(tag: string): Element {\n return getRenderer().createElement(tag)\n}\n\nexport function createComment(content: string): Comment {\n return getRenderer().createComment(content)\n}\n\nexport function insertBefore(\n parent: Node,\n child: VobsNode,\n anchor: VobsNode | null\n): void {\n if (isVobsFragment(child)) {\n child.mount(parent, isVobsFragment(anchor) ? anchor.start : anchor)\n return\n }\n getRenderer().insertBefore(parent, child, isVobsFragment(anchor) ? anchor.start : anchor)\n markHmrInstanceMounted(child, parent)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'insert',\n target: describeDebugNode(child),\n parent: describeDebugNode(parent)\n })\n }\n}\n\nexport function removeChild(\n parent: Node,\n child: VobsNode\n): void {\n disposeNodeOwner(child)\n if (isVobsFragment(child)) {\n child.unmount(parent)\n return\n }\n getRenderer().removeChild(parent, child)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'remove',\n target: describeDebugNode(child),\n parent: describeDebugNode(parent)\n })\n }\n}\n\nexport function setTextContent(\n node: Text,\n content: string\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => node.textContent)\n : undefined\n getRenderer().setTextContent(node, content)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'text',\n target: describeDebugNode(node),\n previousValue,\n nextValue: content\n })\n }\n}\n\nexport function setProperty(\n node: Element,\n key: string,\n value: unknown\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => Reflect.get(node, key))\n : undefined\n getRenderer().setProperty(node, key, value)\n if (key === 'value' && (node as { tagName?: unknown }).tagName === 'SELECT') {\n scheduleSelectValueSync(node, value)\n }\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'property',\n target: describeDebugNode(node),\n key,\n previousValue,\n nextValue: value\n })\n }\n}\n\nconst pendingSelectValues = new WeakMap<Element, unknown>()\nconst selectSyncScheduled = new WeakSet<Element>()\n\n/**\n * `<select value>` 在 option 子节点存在前赋值不生效(HTML 规范:select 的 value\n * 由已存在的 option 决定)。编译产物先设置属性、后插入子节点,静态写法必然丢初始值\n * (消费方此前只能用 ref + queueMicrotask 规避)。\n * 这里对 select 的 value 赋值统一延迟到微任务重放一次:静态子节点在同一同步任务内\n * 插入完毕,重放即命中。动态(insertList/insertDynamic)插入的 option 晚于该微任务时,\n * 由 value 的绑定 effect 在后续信号更新中正常覆盖。\n */\nfunction scheduleSelectValueSync(node: Element, value: unknown): void {\n pendingSelectValues.set(node, value)\n if (selectSyncScheduled.has(node)) return\n selectSyncScheduled.add(node)\n queueMicrotask(() => {\n selectSyncScheduled.delete(node)\n if (!pendingSelectValues.has(node)) return\n const pending = pendingSelectValues.get(node)\n pendingSelectValues.delete(node)\n getRenderer().setProperty(node, 'value', pending)\n })\n}\n\nexport function setAttribute(\n node: Element,\n key: string,\n value: string\n): void {\n const previousValue = getRuntimeDebugHooks()\n ? readDebugValue(() => typeof node.getAttribute === 'function' ? node.getAttribute(key) : undefined)\n : undefined\n getRenderer().setAttribute(node, key, value)\n if (getRuntimeDebugHooks()) {\n invokeRuntimeDebug('domMutation', {\n operation: 'attribute',\n target: describeDebugNode(node),\n key,\n previousValue,\n nextValue: value\n })\n }\n}\n\nexport function spreadProps(node: Element, props: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(props)) {\n if (key === 'key' || value === null || value === undefined) continue\n if (key === 'ref') {\n setRef(node, value)\n continue\n }\n if (key.startsWith('on') && typeof value === 'function') addEventListener(node, key.slice(2).toLowerCase(), value as EventListener)\n // property 键的 false 有语义(如 disabled={false} 必须清除),不能跳过;\n // attribute 键的 false 表示“不设置”,与 HTML 语义一致。\n else if (isPropertyKey(key)) setProperty(node, key, value)\n else if (value === false) continue\n else setAttribute(node, key === 'className' ? 'class' : key, key === 'style' && isStyleObject(value) ? formatStyle(value) : String(value))\n }\n}\n\n/** Apply compile-time host properties in one renderer pass. */\nexport function setStaticProps(node: Element, props: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(props)) {\n if (key === 'key' || key === 'ref' || key.startsWith('on')) continue\n if (value === null || value === undefined) continue\n if (isPropertyKey(key)) setProperty(node, key, value)\n else if (value === false) continue\n else setAttribute(node, key === 'className' ? 'class' : key, key === 'style' && isStyleObject(value) ? formatStyle(value) : String(value))\n }\n}\n\nfunction isPropertyKey(key: string): boolean {\n return key === 'value' || key === 'checked' || key === 'selected' || key === 'disabled'\n || key === 'multiple' || key === 'readOnly' || key === 'required'\n || key === 'autofocus' || key === 'hidden' || key === 'tabIndex'\n}\n\nfunction isStyleObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction formatStyle(value: Record<string, unknown>): string {\n return Object.entries(value).filter(([, entry]) => entry !== null && entry !== undefined && entry !== false)\n .map(([key, entry]) => `${key.replace(/[A-Z]/gu, match => `-${match.toLowerCase()}`)}:${String(entry)}`).join(';')\n}\n\nexport function addEventListener(\n node: Element,\n event: string,\n handler: EventListener\n): void {\n const renderer = getRenderer()\n const owner = getCurrentOwner()\n let bindings = eventBindings.get(node)\n if (!bindings) {\n bindings = new Map()\n eventBindings.set(node, bindings)\n }\n const previous = bindings.get(event)\n if (previous && previous.original === handler && previous.owner === owner) return\n if (previous) renderer.removeEventListener(node, event, previous.handler)\n const listener = owner ? (reason: Event) => {\n // Owner 已销毁说明节点所属子树已被卸载/替换,事件来自游离 DOM,直接忽略。\n // 否则 owner.run 会抛\"已销毁的 Owner\",在事件流里制造无意义的错误噪音。\n if (owner.disposed) return\n try {\n owner.run(() => handler(reason))\n } catch (error) {\n const handled = owner.handleError(error)\n invokeRuntimeDebug('error', {\n error,\n owner,\n phase: 'event',\n handled,\n recovery: handled ? 'handled' : 'propagated'\n })\n if (!handled) throw error\n }\n } : handler\n const binding: EventBinding = { handler: listener, owner, original: handler }\n bindings.set(event, binding)\n renderer.addEventListener(node, event, listener)\n owner?.onDispose(() => {\n if (bindings?.get(event) !== binding) return\n bindings.delete(event)\n renderer.removeEventListener(node, event, listener)\n })\n}\n\nexport function removeEventListener(\n node: Element,\n event: string,\n handler: EventListener\n): void {\n const renderer = getRenderer()\n const binding = eventBindings.get(node)?.get(event)\n renderer.removeEventListener(node, event, binding?.handler ?? handler)\n eventBindings.get(node)?.delete(event)\n}\n\nexport function clear(container: Node): void {\n getRenderer().clear(container)\n}\n\ntype VobsComponent = (...args: any[]) => VobsNode\n\ntype ComponentProps<Component extends VobsComponent> = Component extends (\n props: infer Props\n) => VobsNode\n ? NonNullable<Props> extends object ? NonNullable<Props> : Record<string, never>\n : Record<string, never>\n\nexport function createComponent<Component extends VobsComponent>(\n component: Component,\n props: ComponentProps<Component>,\n source?: VobsSourceLocation\n): VobsNode {\n const owner = createOwner()\n const componentName = (component as typeof component & { displayName?: string }).displayName\n || component.name\n || 'anonymous'\n setOwnerDebugName(owner, source\n ? `${componentName} (${source.file}:${source.line}:${source.column})`\n : componentName)\n owner.onError(reason => {\n attachSourceLocation(reason, source)\n attachComponentContext(reason, componentName, owner.id)\n throw reason\n })\n let node: VobsNode\n try {\n // 组件渲染必须 untrack:组件是 run-once 的,其渲染发生在某次 effect 求值\n // (insertDynamic/insertBoundary 的渲染工厂、路由挂载)内时,若不切断追踪,\n // 组件体内读取的信号会被收集为祖先 effect 的依赖——一次无关编辑就会触发\n // 整棵子树销毁重建(输入框被换掉、焦点丢失、事件监听随旧树一起被清理)。\n // 结构性响应只属于条件工厂与绑定 effect,组件本体渲染一次即止。\n node = owner.run(() => untrack(() => component(props)))\n } catch (error) {\n owner.dispose()\n attachSourceLocation(error, source)\n attachComponentContext(error, componentName, owner.id)\n throw error\n }\n associateNodeOwner(node, owner)\n const hmrKey = (component as typeof component & { hmrKey?: string }).hmrKey\n if (hmrKey) {\n const instance: HmrInstance = {\n node,\n parent: null,\n refresh(): void {\n const previous = instance.node\n const next = owner.run(() => untrack(() => component(props)))\n if (instance.parent && !isVobsFragment(previous) && !isVobsFragment(next)) {\n getRenderer().insertBefore(instance.parent, next, previous)\n getRenderer().removeChild(instance.parent, previous)\n }\n nodeOwners.delete(previous as object)\n nodeOwners.set(next as object, owner)\n associateHmrInstance(next, instance)\n instance.node = next\n }\n }\n associateHmrInstance(node, instance)\n const separator = hmrKey.lastIndexOf(':')\n const moduleId = separator < 0 ? hmrKey : hmrKey.slice(0, separator)\n const cleanup = registerHmrInstance(moduleId, instance)\n owner.onDispose(cleanup)\n }\n return node\n}\n\nexport interface VobsSourceLocation {\n readonly file: string\n readonly line: number\n readonly column: number\n}\n\nexport interface VobsLocatedError extends Error {\n readonly vobsSource?: VobsSourceLocation\n readonly vobsComponent?: string\n readonly vobsOwnerId?: string\n}\n\nfunction attachSourceLocation(reason: unknown, source: VobsSourceLocation | undefined): void {\n if (!source || (!reason || (typeof reason !== 'object' && typeof reason !== 'function'))) return\n const error = reason as VobsLocatedError\n if (error.vobsSource) return\n try {\n Object.defineProperty(error, 'vobsSource', {\n configurable: true,\n enumerable: false,\n value: source,\n writable: false\n })\n } catch {\n // Frozen third-party errors still propagate with their original details.\n }\n}\n\nfunction attachComponentContext(reason: unknown, component: string, ownerId: string): void {\n if (!reason || (typeof reason !== 'object' && typeof reason !== 'function')) return\n const error = reason as VobsLocatedError\n try {\n if (!error.vobsComponent) Object.defineProperty(error, 'vobsComponent', { configurable: true, enumerable: false, value: component, writable: false })\n if (!error.vobsOwnerId) Object.defineProperty(error, 'vobsOwnerId', { configurable: true, enumerable: false, value: ownerId, writable: false })\n } catch {\n // Frozen third-party errors still propagate with their original details.\n }\n}\n\nexport function createBlock(factory: () => VobsNode | null | undefined | false): VobsNode | null {\n const owner = createOwner()\n setOwnerDebugName(owner, 'dynamic')\n let node: VobsNode | null | undefined | false\n try {\n node = owner.run(factory)\n } catch (error) {\n owner.dispose()\n throw error\n }\n if (!node) {\n owner.dispose()\n return null\n }\n associateNodeOwner(node, owner)\n return node\n}\n\nexport function associateNodeOwner(node: VobsNode, owner: Owner): void {\n nodeOwners.set(node, owner)\n}\n\nexport function disposeNodeOwner(node: VobsNode): void {\n const owner = nodeOwners.get(node)\n if (!owner) return\n nodeOwners.delete(node)\n owner.dispose()\n}\n","import type { VobsNode } from './fragment'\n\nexport type HmrComponent<Props extends object = Record<string, unknown>> =\n (props: Props) => VobsNode\n\nexport interface HmrStateStore {\n get<T>(key: string, initial: T | (() => T)): T\n set<T>(key: string, value: T): void\n has(key: string): boolean\n delete(key: string): void\n clear(): void\n}\n\nexport interface HmrInstance {\n node: VobsNode\n parent: Node | null\n refresh(): void\n}\n\ninterface HmrModuleState {\n readonly components: Map<string, HmrComponent>\n readonly state: Map<string, unknown>\n readonly instances: Set<HmrInstance>\n}\n\ninterface HmrGlobal {\n modules: Map<string, HmrModuleState>\n}\n\nconst globalTarget = globalThis as typeof globalThis & { __VOBS_HMR__?: HmrGlobal }\nconst hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: new Map<string, HmrModuleState>() }\nglobalTarget.__VOBS_HMR__ = hmrGlobal\n\nexport function resolveComponent<Props extends object>(\n component: HmrComponent<Props>,\n moduleId: string,\n exportName: string\n): HmrComponent<Props> {\n const module = getModule(moduleId)\n const existing = module.components.get(exportName)\n if (existing) return existing as HmrComponent<Props>\n\n const proxy = ((props: Props) => {\n const current = (proxy as HmrComponent<Props> & { current: HmrComponent<Props> }).current\n return current(props)\n }) as HmrComponent<Props> & { current: HmrComponent<Props> }\n proxy.current = component\n Object.defineProperties(proxy, {\n displayName: { configurable: true, value: component.name || exportName },\n hmrKey: { configurable: false, value: `${moduleId}:${exportName}` }\n })\n module.components.set(exportName, proxy as HmrComponent)\n return proxy\n}\n\nexport function updateHmrModule(_moduleId: string, nextModule: Record<string, unknown>): void {\n const modules = [...hmrGlobal.modules.values()]\n for (const module of modules) {\n let changed = false\n for (const [name, proxy] of module.components) {\n const next = nextModule[name]\n if (typeof next !== 'function') continue\n const hmrProxy = proxy as HmrComponent & { current: HmrComponent; displayName?: string }\n hmrProxy.current = next as HmrComponent\n Object.defineProperty(hmrProxy, 'displayName', { configurable: true, value: next.name || name })\n changed = true\n }\n if (!changed) continue\n for (const instance of module.instances) {\n try {\n instance.refresh()\n } catch {\n // HMR failures remain application errors on the next normal render.\n }\n }\n }\n}\n\nexport function disposeHmrModule(_moduleId: string): void {\n // State and component proxies intentionally survive module disposal.\n}\n\nexport function createHmrStateStore(moduleId: string): HmrStateStore {\n const state = getModule(moduleId).state\n return {\n get<T>(key: string, initial: T | (() => T)): T {\n if (!state.has(key)) state.set(key, typeof initial === 'function' ? (initial as () => T)() : initial)\n return state.get(key) as T\n },\n set<T>(key: string, value: T): void {\n state.set(key, value)\n },\n has: key => state.has(key),\n delete: key => { state.delete(key) },\n clear: () => { state.clear() }\n }\n}\n\n/**\n * 编译器为模块顶层 state() 声明生成的取值入口(`#state:` 前缀与手动 store 键隔离)。\n * 模块热更新重执行时复用既有信号实例:旧导入方持有的实例与新模块实例共享同一份状态,\n * 消除\"两份模块、两份状态\"导致的编辑不生效/页面半边失灵。\n */\nexport function hmrStateRef<T>(moduleId: string, key: string, create: () => T): T {\n const state = getModule(moduleId).state\n const registryKey = `#state:${key}`\n if (state.has(registryKey)) return state.get(registryKey) as T\n const value = create()\n state.set(registryKey, value)\n return value\n}\n\nexport function registerHmrInstance(moduleId: string, instance: HmrInstance): () => void {\n const instances = getModule(moduleId).instances\n instances.add(instance)\n return () => instances.delete(instance)\n}\n\nexport function markHmrInstanceMounted(node: VobsNode, parent: Node): void {\n const instance = hmrInstances.get(node as object)\n if (instance) instance.parent = parent\n}\n\nfunction getModule(moduleId: string): HmrModuleState {\n let module = hmrGlobal.modules.get(moduleId)\n if (!module) {\n module = { components: new Map(), state: new Map(), instances: new Set() }\n hmrGlobal.modules.set(moduleId, module)\n }\n return module\n}\n\nconst hmrInstances = new WeakMap<object, HmrInstance>()\n\nexport function associateHmrInstance(node: VobsNode, instance: HmrInstance): void {\n hmrInstances.set(node as object, instance)\n}\n","import { getCurrentOwner } from '@vobs/reactivity'\n\n/** A mutable reference populated when a host node is mounted. */\nexport interface Ref<T extends object = Node> {\n current: T | null\n}\n\nexport type RefTarget<T extends object = Node> = Ref<T> | ((value: T | null) => void)\n\nexport function ref<T extends object = Node>(initialValue: T | null = null): Ref<T> {\n return { current: initialValue }\n}\n\n/** Bind a host node to an object or callback ref and clear it with its Owner. */\nexport function setRef<T extends object>(node: T, target: unknown): void {\n if (!isRefTarget<T>(target)) return\n // SSR's serializable nodes are never exposed as live refs. Custom renderers\n // may use arbitrary host objects, so only exclude the known SSR shape.\n if (isSSRNode(node)) return\n const owner = getCurrentOwner()\n assignRef(target, node)\n owner?.onDispose(() => {\n // Do not clear a ref that has since been reassigned to another node.\n if (isObjectRef(target) && target.current !== node) return\n assignRef(target, null)\n })\n}\n\nfunction isSSRNode(value: object): boolean {\n const type = (value as { type?: unknown }).type\n return (type === 'element' || type === 'text' || type === 'comment')\n && !('nodeType' in value)\n}\n\nfunction isObjectRef<T extends object>(value: unknown): value is Ref<T> {\n return Boolean(value && typeof value === 'object' && 'current' in value)\n}\n\nfunction isRefTarget<T extends object>(value: unknown): value is RefTarget<T> {\n return isObjectRef<T>(value) || typeof value === 'function'\n}\n\nfunction assignRef<T extends object>(target: RefTarget<T>, value: T | null): void {\n try {\n if (typeof target === 'function') target(value)\n else target.current = value\n } catch {\n // Ref callbacks are user code; never make mounting fail because of them.\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,qBAAgC;;;ACEhC,IAAAC,qBAAqF;;;AC2BrF,IAAM,eAAe;AACrB,IAAM,YAAY,aAAa,gBAAgB,EAAE,SAAS,oBAAI,IAA4B,EAAE;AAC5F,aAAa,eAAe;;;AC/B5B,wBAAgC;;;AFgBhC,IAAI,kBAA0C;AAmBvC,SAAS,cAA+B;AAC7C,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI,MAAM,4CAAS;AAAA,EAC3B;AACA,SAAO;AACT;AALgB;AAeT,SAAS,cAAc,SAA0B;AACtD,SAAO,YAAY,EAAE,cAAc,OAAO;AAC5C;AAFgB;;;ADpCT,SAAS,eAAe,SAAwC;AACrE,QAAM,QAAQ,cAAc,qBAAqB;AACjD,QAAM,MAAM,cAAc,mBAAmB;AAC7C,MAAI,SAAsB;AAC1B,MAAI,cAAc;AAClB,QAAM,YAAQ,oCAAgB;AAE9B,QAAM,WAAyB;AAAA,IAC7B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,MAAM,YAAY,QAAc;AAC9B,UAAI,UAAU,WAAW,YAAY;AACnC,cAAM,IAAI,MAAM,0EAAkC;AAAA,MACpD;AAEA,UAAI,aAAa;AACf,kBAAU,YAAY,OAAO,KAAK,MAAM;AACxC;AAAA,MACF;AAEA,YAAM,WAAW,YAAY;AAC7B,eAAS,aAAa,YAAY,OAAO,MAAM;AAC/C,eAAS,aAAa,YAAY,KAAK,MAAM;AAC7C,eAAS;AACT,oBAAc;AACd,UAAI,MAAO,OAAM,IAAI,MAAM,QAAQ,YAAY,GAAG,CAAC;AAAA,UAC9C,SAAQ,YAAY,GAAG;AAAA,IAC9B;AAAA,IACA,QAAQ,YAAkB;AACxB,UAAI,CAAC,eAAe,WAAW,YAAY;AACzC,cAAM,IAAI,MAAM,0EAAkC;AAAA,MACpD;AACA,YAAM,WAAW,YAAY;AAC7B,UAAI,UAAU,SAAS,YAAY,KAAK;AACxC,aAAO,WAAW,YAAY,KAAK;AACjC,cAAM,OAAO,SAAS,YAAY,OAAO;AACzC,iBAAS,YAAY,YAAY,OAAO;AACxC,kBAAU;AAAA,MACZ;AACA,eAAS,YAAY,YAAY,KAAK;AACtC,eAAS,YAAY,YAAY,GAAG;AACpC,eAAS;AACT,oBAAc;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AA/CgB;AAiDT,SAAS,eAAe,OAAuC;AACpE,SAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAa,MAAuB,SAAS;AACzF;AAFgB;AAIhB,SAAS,UAAU,QAAc,OAAa,KAAW,QAA2B;AAClF,QAAM,WAAW,YAAY;AAC7B,QAAM,QAAgB,CAAC,KAAK;AAC5B,MAAI,UAAU,SAAS,YAAY,KAAK;AACxC,SAAO,SAAS;AACd,UAAM,KAAK,OAAO;AAClB,QAAI,YAAY,IAAK;AACrB,cAAU,SAAS,YAAY,OAAO;AAAA,EACxC;AACA,MAAI,MAAM,MAAM,SAAS,CAAC,MAAM,KAAK;AACnC,UAAM,IAAI,MAAM,2DAAwB;AAAA,EAC1C;AACA,aAAW,QAAQ,MAAO,UAAS,aAAa,QAAQ,MAAM,MAAM;AACtE;AAbS;","names":["import_reactivity","import_reactivity"]}
package/dist/fragment.js CHANGED
@@ -1,141 +1,27 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
- // packages/reactivity/src/debug.ts
5
- var activeDebugHooks = null;
6
- function hasDebugHooks() {
7
- return activeDebugHooks !== null;
8
- }
9
- __name(hasDebugHooks, "hasDebugHooks");
10
- function invokeDebug(name, ...args) {
11
- return;
12
- }
13
- __name(invokeDebug, "invokeDebug");
4
+ // packages/runtime/src/fragment.ts
5
+ import { getCurrentOwner as getCurrentOwner3 } from "@vobs/reactivity";
14
6
 
15
- // packages/reactivity/src/owner.ts
16
- var currentOwner = null;
17
- function getCurrentOwner() {
18
- return currentOwner;
19
- }
20
- __name(getCurrentOwner, "getCurrentOwner");
21
-
22
- // packages/reactivity/src/scheduler.ts
23
- var _Scheduler = class _Scheduler {
24
- constructor() {
25
- this.dirtyEffects = /* @__PURE__ */ new Set();
26
- this.lowPriorityEffects = /* @__PURE__ */ new Set();
27
- // flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。
28
- this.normalBuffer = [];
29
- this.lowBuffer = [];
30
- this.flushing = false;
31
- this.scheduled = false;
32
- this.batchDepth = 0;
33
- }
34
- schedule(effect2) {
35
- if (effect2.disposed) return;
36
- this.dirtyEffects.add(effect2);
37
- this.lowPriorityEffects.delete(effect2);
38
- this.ensureScheduled();
39
- }
40
- /** Queue an effect behind normal updates while preserving deterministic order. */
41
- scheduleLow(effect2) {
42
- if (effect2.disposed) return;
43
- if (!this.dirtyEffects.has(effect2)) this.lowPriorityEffects.add(effect2);
44
- this.ensureScheduled();
45
- }
46
- ensureScheduled() {
47
- if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {
48
- this.scheduled = true;
49
- queueMicrotask(() => {
50
- this.scheduled = false;
51
- this.flush();
52
- });
53
- }
54
- }
55
- remove(effect2) {
56
- this.dirtyEffects.delete(effect2);
57
- this.lowPriorityEffects.delete(effect2);
58
- }
59
- batch(fn) {
60
- this.batchDepth++;
61
- try {
62
- return fn();
63
- } finally {
64
- this.batchDepth--;
65
- if (this.batchDepth === 0) this.flush();
66
- }
67
- }
68
- flush() {
69
- if (this.flushing || this.batchDepth > 0) return;
70
- this.flushing = true;
71
- let rounds = 0;
72
- let firstError;
73
- let hasError = false;
74
- try {
75
- while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {
76
- if (++rounds > 100) {
77
- this.dirtyEffects.clear();
78
- this.lowPriorityEffects.clear();
79
- throw new Error("Vobs: \u54CD\u5E94\u5F0F\u66F4\u65B0\u8D85\u8FC7 100 \u8F6E\uFF0C\u53EF\u80FD\u5B58\u5728\u5FAA\u73AF\u4F9D\u8D56");
80
- }
81
- this.collectRunnable(this.dirtyEffects, this.normalBuffer);
82
- this.collectRunnable(this.lowPriorityEffects, this.lowBuffer);
83
- sortEffects(this.normalBuffer);
84
- sortEffects(this.lowBuffer);
85
- for (const effect2 of this.normalBuffer) {
86
- try {
87
- effect2.run();
88
- } catch (error) {
89
- if (!hasError) {
90
- firstError = error;
91
- hasError = true;
92
- }
93
- }
94
- }
95
- for (const effect2 of this.lowBuffer) {
96
- try {
97
- effect2.run();
98
- } catch (error) {
99
- if (!hasError) {
100
- firstError = error;
101
- hasError = true;
102
- }
103
- }
104
- }
105
- this.normalBuffer.length = 0;
106
- this.lowBuffer.length = 0;
107
- }
108
- } finally {
109
- this.normalBuffer.length = 0;
110
- this.lowBuffer.length = 0;
111
- this.flushing = false;
112
- }
113
- if (hasError) throw firstError;
114
- }
115
- /** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */
116
- collectRunnable(source, target) {
117
- for (const effect2 of source) {
118
- if (!effect2.disposed) target.push(effect2);
119
- }
120
- source.clear();
121
- }
122
- };
123
- __name(_Scheduler, "Scheduler");
124
- function sortEffects(effects) {
125
- if (effects.length > 1) {
126
- effects.sort((a, b) => b.depth - a.depth || a.order - b.order);
127
- }
128
- }
129
- __name(sortEffects, "sortEffects");
7
+ // packages/runtime/src/ops.ts
8
+ import { createOwner, getCurrentOwner as getCurrentOwner2, setOwnerDebugName, untrack } from "@vobs/reactivity";
130
9
 
131
10
  // packages/runtime/src/hmr.ts
132
11
  var globalTarget = globalThis;
133
12
  var hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: /* @__PURE__ */ new Map() };
134
13
  globalTarget.__VOBS_HMR__ = hmrGlobal;
14
+
15
+ // packages/runtime/src/ref.ts
16
+ import { getCurrentOwner } from "@vobs/reactivity";
17
+
18
+ // packages/runtime/src/ops.ts
19
+ var currentRenderer = null;
135
20
  function getRenderer() {
136
- {
21
+ if (!currentRenderer) {
137
22
  throw new Error("\u6E32\u67D3\u5668\u672A\u521D\u59CB\u5316");
138
23
  }
24
+ return currentRenderer;
139
25
  }
140
26
  __name(getRenderer, "getRenderer");
141
27
  function createComment(content) {
@@ -149,6 +35,7 @@ function createFragment(factory) {
149
35
  const end = createComment("vobs:fragment:end");
150
36
  let parent = null;
151
37
  let initialized = false;
38
+ const owner = getCurrentOwner3();
152
39
  const fragment = {
153
40
  kind: "vobs-fragment",
154
41
  start,
@@ -166,7 +53,8 @@ function createFragment(factory) {
166
53
  renderer.insertBefore(nextParent, end, anchor);
167
54
  parent = nextParent;
168
55
  initialized = true;
169
- factory(nextParent, end);
56
+ if (owner) owner.run(() => factory(nextParent, end));
57
+ else factory(nextParent, end);
170
58
  },
171
59
  unmount(nextParent) {
172
60
  if (!initialized || parent !== nextParent) {
@@ -207,7 +95,8 @@ function moveRange(parent, start, end, anchor) {
207
95
  for (const node of nodes) renderer.insertBefore(parent, node, anchor);
208
96
  }
209
97
  __name(moveRange, "moveRange");
210
-
211
- export { createFragment, isVobsFragment };
212
- //# sourceMappingURL=fragment.js.map
98
+ export {
99
+ createFragment,
100
+ isVobsFragment
101
+ };
213
102
  //# sourceMappingURL=fragment.js.map