olova 2.0.61 → 2.0.63

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 (80) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +42 -61
  3. package/dist/compiler.d.ts +44 -0
  4. package/dist/compiler.js +2139 -0
  5. package/dist/compiler.js.map +1 -0
  6. package/dist/core.d.ts +4 -0
  7. package/dist/core.js +859 -0
  8. package/dist/core.js.map +1 -0
  9. package/dist/global.d.ts +15 -0
  10. package/dist/global.js +226 -0
  11. package/dist/global.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +2302 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/runtime.d.ts +89 -0
  16. package/dist/runtime.js +633 -0
  17. package/dist/runtime.js.map +1 -0
  18. package/dist/signals-core-BdfWh1Yt.d.ts +43 -0
  19. package/dist/vite.d.ts +5 -0
  20. package/dist/vite.js +2302 -0
  21. package/dist/vite.js.map +1 -0
  22. package/package.json +83 -65
  23. package/dist/chunk-D7SIC5TC.js +0 -367
  24. package/dist/chunk-D7SIC5TC.js.map +0 -1
  25. package/dist/entry-server.cjs +0 -120
  26. package/dist/entry-server.cjs.map +0 -1
  27. package/dist/entry-server.js +0 -115
  28. package/dist/entry-server.js.map +0 -1
  29. package/dist/entry-worker.cjs +0 -133
  30. package/dist/entry-worker.cjs.map +0 -1
  31. package/dist/entry-worker.js +0 -127
  32. package/dist/entry-worker.js.map +0 -1
  33. package/dist/main.cjs +0 -18
  34. package/dist/main.cjs.map +0 -1
  35. package/dist/main.js +0 -16
  36. package/dist/main.js.map +0 -1
  37. package/dist/olova.cjs +0 -1680
  38. package/dist/olova.cjs.map +0 -1
  39. package/dist/olova.d.cts +0 -72
  40. package/dist/olova.d.ts +0 -72
  41. package/dist/olova.js +0 -1321
  42. package/dist/olova.js.map +0 -1
  43. package/dist/performance.cjs +0 -386
  44. package/dist/performance.cjs.map +0 -1
  45. package/dist/performance.js +0 -3
  46. package/dist/performance.js.map +0 -1
  47. package/dist/router.cjs +0 -646
  48. package/dist/router.cjs.map +0 -1
  49. package/dist/router.d.cts +0 -113
  50. package/dist/router.d.ts +0 -113
  51. package/dist/router.js +0 -632
  52. package/dist/router.js.map +0 -1
  53. package/main.tsx +0 -76
  54. package/olova.ts +0 -619
  55. package/src/entry-server.tsx +0 -165
  56. package/src/entry-worker.tsx +0 -201
  57. package/src/generator/index.ts +0 -409
  58. package/src/hydration/flight.ts +0 -320
  59. package/src/hydration/index.ts +0 -12
  60. package/src/hydration/types.ts +0 -225
  61. package/src/logger.ts +0 -182
  62. package/src/main.tsx +0 -24
  63. package/src/performance.ts +0 -488
  64. package/src/plugin/index.ts +0 -204
  65. package/src/router/ErrorBoundary.tsx +0 -145
  66. package/src/router/Link.tsx +0 -117
  67. package/src/router/OlovaRouter.tsx +0 -354
  68. package/src/router/Outlet.tsx +0 -8
  69. package/src/router/context.ts +0 -117
  70. package/src/router/index.ts +0 -29
  71. package/src/router/matching.ts +0 -63
  72. package/src/router/router.tsx +0 -23
  73. package/src/router/search-params.ts +0 -29
  74. package/src/scanner/index.ts +0 -114
  75. package/src/types/index.ts +0 -190
  76. package/src/utils/export.ts +0 -85
  77. package/src/utils/index.ts +0 -4
  78. package/src/utils/naming.ts +0 -54
  79. package/src/utils/path.ts +0 -45
  80. package/tsup.config.ts +0 -35
package/dist/core.js ADDED
@@ -0,0 +1,859 @@
1
+ import { signal, effect as effect$1, computed as computed$1, untracked } from '@preact/signals-core';
2
+
3
+ // core/signals-core.ts
4
+ var rawToProxy = /* @__PURE__ */ new WeakMap();
5
+ var proxyToRaw = /* @__PURE__ */ new WeakMap();
6
+ var proxyOwner = /* @__PURE__ */ new WeakMap();
7
+ var hmrCaptureStack = [];
8
+ function isObject(value) {
9
+ return typeof value === "object" && value !== null;
10
+ }
11
+ function unwrapValue(value) {
12
+ if (!isObject(value)) {
13
+ return value;
14
+ }
15
+ return proxyToRaw.get(value) ?? value;
16
+ }
17
+ var Signal = class {
18
+ source;
19
+ version;
20
+ proxy = null;
21
+ constructor(initial, source, version) {
22
+ this.source = source ?? signal(initial);
23
+ this.version = version ?? signal(0);
24
+ }
25
+ get value() {
26
+ this.version.value;
27
+ return this.getReactiveValue(this.source.value);
28
+ }
29
+ set value(next) {
30
+ const resolvedNext = unwrapValue(next);
31
+ if (Object.is(this.source.peek(), resolvedNext)) {
32
+ return;
33
+ }
34
+ this.proxy = null;
35
+ this.source.value = resolvedNext;
36
+ }
37
+ peek() {
38
+ return this.source.peek();
39
+ }
40
+ notify() {
41
+ this.version.value = this.version.peek() + 1;
42
+ }
43
+ subscribe(fn) {
44
+ return this.source.subscribe(fn);
45
+ }
46
+ valueOf() {
47
+ return this.value;
48
+ }
49
+ toString() {
50
+ return String(this.value);
51
+ }
52
+ toJSON() {
53
+ return this.peek();
54
+ }
55
+ getReactiveValue(value) {
56
+ if (!isObject(value)) {
57
+ return value;
58
+ }
59
+ if (this.proxy && proxyToRaw.get(this.proxy) === value) {
60
+ return this.proxy;
61
+ }
62
+ this.proxy = this.wrapObject(value);
63
+ return this.proxy;
64
+ }
65
+ wrapObject(value) {
66
+ const existing = rawToProxy.get(value);
67
+ if (existing) {
68
+ return existing;
69
+ }
70
+ const proxy = new Proxy(value, {
71
+ get: (target, key, receiver) => {
72
+ const result = Reflect.get(target, key, receiver);
73
+ return isObject(result) ? this.wrapNested(result) : result;
74
+ },
75
+ set: (target, key, next, receiver) => {
76
+ const resolvedNext = unwrapValue(next);
77
+ const previous = Reflect.get(target, key, receiver);
78
+ const changed = Reflect.set(target, key, resolvedNext, receiver);
79
+ if (changed && !Object.is(previous, resolvedNext)) {
80
+ this.notify();
81
+ }
82
+ return changed;
83
+ },
84
+ deleteProperty: (target, key) => {
85
+ const hadKey = Reflect.has(target, key);
86
+ const changed = Reflect.deleteProperty(target, key);
87
+ if (hadKey && changed) {
88
+ this.notify();
89
+ }
90
+ return changed;
91
+ }
92
+ });
93
+ rawToProxy.set(value, proxy);
94
+ proxyToRaw.set(proxy, value);
95
+ proxyOwner.set(proxy, this);
96
+ return proxy;
97
+ }
98
+ wrapNested(value) {
99
+ const owner = proxyOwner.get(value);
100
+ if (owner === this) {
101
+ return value;
102
+ }
103
+ return this.wrapObject(value);
104
+ }
105
+ };
106
+ function state(initial, hmrKey) {
107
+ const frame = hmrCaptureStack[hmrCaptureStack.length - 1];
108
+ let nextInitial = initial;
109
+ if (frame) {
110
+ if (hmrKey && frame.restoredByKey?.has(hmrKey)) {
111
+ nextInitial = frame.restoredByKey.get(hmrKey);
112
+ } else if (frame.cursor < frame.restoredUnkeyed.length) {
113
+ nextInitial = frame.restoredUnkeyed[frame.cursor];
114
+ }
115
+ }
116
+ const signal = new Signal(nextInitial);
117
+ if (frame) {
118
+ frame.created.push({ key: hmrKey, signal });
119
+ if (!hmrKey || !frame.restoredByKey?.has(hmrKey)) {
120
+ frame.cursor += 1;
121
+ }
122
+ }
123
+ return signal;
124
+ }
125
+ function effect(fn, options) {
126
+ const stop = effect$1(() => fn());
127
+ return () => stop();
128
+ }
129
+ function computed(getter) {
130
+ const version = signal(0);
131
+ const source = computed$1(() => getter());
132
+ effect$1(() => {
133
+ getter();
134
+ version.value = version.peek() + 1;
135
+ });
136
+ return new Signal(untracked(() => source.value), source, version);
137
+ }
138
+ var derived = computed;
139
+ function beginHmrStateCapture(restoredValues) {
140
+ const restoredByKey = /* @__PURE__ */ new Map();
141
+ const restoredUnkeyed = [];
142
+ for (const entry of restoredValues ?? []) {
143
+ if (entry.key) {
144
+ restoredByKey.set(entry.key, entry.value);
145
+ continue;
146
+ }
147
+ restoredUnkeyed.push(entry.value);
148
+ }
149
+ hmrCaptureStack.push({
150
+ created: [],
151
+ restoredValues,
152
+ restoredByKey,
153
+ restoredUnkeyed,
154
+ cursor: 0
155
+ });
156
+ }
157
+ function endHmrStateCapture() {
158
+ const frame = hmrCaptureStack.pop();
159
+ return frame?.created ?? [];
160
+ }
161
+
162
+ // runtime/component.ts
163
+ var EMPTY_SLOTS = Object.freeze({});
164
+ var currentSetupContext = null;
165
+ function requireSetupContext(apiName) {
166
+ if (!currentSetupContext) {
167
+ throw new Error(
168
+ `[olova] ${apiName}() can only be used during component setup.`
169
+ );
170
+ }
171
+ return currentSetupContext;
172
+ }
173
+ function toText(value) {
174
+ if (value === null || value === void 0) {
175
+ return "";
176
+ }
177
+ if (Array.isArray(value)) {
178
+ return value.map(toText).join("");
179
+ }
180
+ return String(value);
181
+ }
182
+ function normalizeClassValue(value) {
183
+ if (value === false || value === null || value === void 0) {
184
+ return null;
185
+ }
186
+ if (Array.isArray(value)) {
187
+ const parts = value.map((item) => normalizeClassValue(item)).filter((item) => !!item);
188
+ return parts.length > 0 ? parts.join(" ") : null;
189
+ }
190
+ if (typeof value === "object") {
191
+ const parts = Object.entries(value).filter(([, enabled]) => !!enabled).map(([name]) => name);
192
+ return parts.length > 0 ? parts.join(" ") : null;
193
+ }
194
+ return String(value);
195
+ }
196
+ function toAttr(value) {
197
+ if (value === false || value === null || value === void 0) {
198
+ return null;
199
+ }
200
+ if (value === true) {
201
+ return "true";
202
+ }
203
+ return String(value);
204
+ }
205
+ function isDangerousHtml(value) {
206
+ return !!(value && typeof value === "object" && "__dangerousHtml" in value && value.__dangerousHtml === true);
207
+ }
208
+ function sanitizeHtml(html) {
209
+ const template = document.createElement("template");
210
+ template.innerHTML = html;
211
+ const blockedElements = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed"]);
212
+ const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);
213
+ let current = walker.nextNode();
214
+ while (current) {
215
+ const element = current;
216
+ current = walker.nextNode();
217
+ if (blockedElements.has(element.tagName.toLowerCase())) {
218
+ element.remove();
219
+ continue;
220
+ }
221
+ for (const attr of Array.from(element.attributes)) {
222
+ const attrName = attr.name.toLowerCase();
223
+ const attrValue = attr.value.trim().toLowerCase();
224
+ if (attrName.startsWith("on")) {
225
+ element.removeAttribute(attr.name);
226
+ continue;
227
+ }
228
+ if ((attrName === "href" || attrName === "src" || attrName === "xlink:href") && attrValue.startsWith("javascript:")) {
229
+ element.removeAttribute(attr.name);
230
+ }
231
+ }
232
+ }
233
+ return template.innerHTML;
234
+ }
235
+ function toHtml(value) {
236
+ if (value === null || value === void 0) {
237
+ return "";
238
+ }
239
+ if (Array.isArray(value)) {
240
+ return value.map(toHtml).join("");
241
+ }
242
+ if (isDangerousHtml(value)) {
243
+ return value.value;
244
+ }
245
+ return sanitizeHtml(String(value));
246
+ }
247
+ function shallowEqual(a, b) {
248
+ if (a === b) {
249
+ return true;
250
+ }
251
+ if (!a || !b) {
252
+ return false;
253
+ }
254
+ const aKeys = Object.keys(a);
255
+ const bKeys = Object.keys(b);
256
+ if (aKeys.length !== bKeys.length) {
257
+ return false;
258
+ }
259
+ for (const key of aKeys) {
260
+ if (!Object.is(a[key], b[key])) {
261
+ return false;
262
+ }
263
+ }
264
+ return true;
265
+ }
266
+ function shallowEqualSlots(a, b) {
267
+ if (a === b) {
268
+ return true;
269
+ }
270
+ if (!a || !b) {
271
+ return false;
272
+ }
273
+ const aKeys = Object.keys(a);
274
+ const bKeys = Object.keys(b);
275
+ if (aKeys.length !== bKeys.length) {
276
+ return false;
277
+ }
278
+ for (const key of aKeys) {
279
+ if (!Object.is(a[key], b[key])) {
280
+ return false;
281
+ }
282
+ }
283
+ return true;
284
+ }
285
+ function insertFragmentIntoRange(range, fragment) {
286
+ const nodes = Array.from(fragment.childNodes);
287
+ range.deleteContents();
288
+ if (nodes.length === 0) {
289
+ return;
290
+ }
291
+ range.insertNode(fragment);
292
+ const first = nodes[0];
293
+ const last = nodes[nodes.length - 1];
294
+ range.setStartBefore(first);
295
+ range.setEndAfter(last);
296
+ }
297
+ function bindJsxEventsInRange(range) {
298
+ const root = range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE ? range.commonAncestorContainer : range.commonAncestorContainer.parentNode;
299
+ if (!root) {
300
+ return () => {
301
+ };
302
+ }
303
+ const globalObj = globalThis;
304
+ const handlers = globalObj.__olovaJsxHandlers;
305
+ if (!handlers) {
306
+ return () => {
307
+ };
308
+ }
309
+ const listeners = [];
310
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
311
+ let current = walker.currentNode;
312
+ while (current) {
313
+ let intersects = false;
314
+ try {
315
+ intersects = range.intersectsNode(current);
316
+ } catch {
317
+ intersects = false;
318
+ }
319
+ if (intersects) {
320
+ const element = current;
321
+ for (const attr of Array.from(current.attributes)) {
322
+ if (!attr.name.startsWith("data-o-jsx-")) {
323
+ continue;
324
+ }
325
+ const eventName = attr.name.slice("data-o-jsx-".length);
326
+ const handlerId = attr.value;
327
+ const listener = (event) => {
328
+ const handler = handlers.get(handlerId);
329
+ if (typeof handler === "function") {
330
+ handler(event);
331
+ }
332
+ };
333
+ element.addEventListener(eventName, listener);
334
+ element.removeAttribute(`on${eventName}`);
335
+ listeners.push(() => element.removeEventListener(eventName, listener));
336
+ }
337
+ }
338
+ current = walker.nextNode();
339
+ }
340
+ return () => {
341
+ for (const cleanup of listeners) {
342
+ cleanup();
343
+ }
344
+ };
345
+ }
346
+ function replaceTokenWithTextNode(root, token) {
347
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
348
+ let current = walker.nextNode();
349
+ while (current) {
350
+ const textNode = current;
351
+ const index = textNode.data.indexOf(token);
352
+ if (index >= 0) {
353
+ const remainder = textNode.splitText(index);
354
+ const after = remainder.splitText(token.length);
355
+ const parent = remainder.parentNode;
356
+ if (!parent) {
357
+ return null;
358
+ }
359
+ const dynamic = document.createTextNode("");
360
+ parent.insertBefore(dynamic, after);
361
+ parent.removeChild(remainder);
362
+ return dynamic;
363
+ }
364
+ current = walker.nextNode();
365
+ }
366
+ return null;
367
+ }
368
+ function createRangeAtToken(root, token) {
369
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
370
+ let current = walker.nextNode();
371
+ while (current) {
372
+ const textNode = current;
373
+ const index = textNode.data.indexOf(token);
374
+ if (index >= 0) {
375
+ const marker = textNode.splitText(index);
376
+ const after = marker.splitText(token.length);
377
+ const range = document.createRange();
378
+ range.setStartBefore(marker);
379
+ range.setEndBefore(marker);
380
+ marker.parentNode?.removeChild(marker);
381
+ if (after.data.length === 0) {
382
+ after.parentNode?.removeChild(after);
383
+ }
384
+ return range;
385
+ }
386
+ current = walker.nextNode();
387
+ }
388
+ return null;
389
+ }
390
+ function createRangeAtTokenWithinRange(hostRange, token) {
391
+ const root = hostRange.commonAncestorContainer;
392
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
393
+ let current = walker.nextNode();
394
+ while (current) {
395
+ const textNode = current;
396
+ const index = textNode.data.indexOf(token);
397
+ if (index < 0) {
398
+ current = walker.nextNode();
399
+ continue;
400
+ }
401
+ let intersects = false;
402
+ try {
403
+ intersects = hostRange.intersectsNode(textNode);
404
+ } catch {
405
+ intersects = false;
406
+ }
407
+ if (!intersects) {
408
+ current = walker.nextNode();
409
+ continue;
410
+ }
411
+ const marker = textNode.splitText(index);
412
+ const after = marker.splitText(token.length);
413
+ const range = document.createRange();
414
+ range.setStartBefore(marker);
415
+ range.setEndBefore(marker);
416
+ marker.parentNode?.removeChild(marker);
417
+ if (after.data.length === 0) {
418
+ after.parentNode?.removeChild(after);
419
+ }
420
+ return range;
421
+ }
422
+ return null;
423
+ }
424
+ function resolveTokenRange(target, token) {
425
+ return target instanceof HTMLElement ? createRangeAtToken(target, token) : createRangeAtTokenWithinRange(target, token);
426
+ }
427
+ function mountDescriptor(descriptor, target, slots, context) {
428
+ let fragment;
429
+ let nodes = null;
430
+ if (descriptor.build) {
431
+ const buildResult = descriptor.build();
432
+ fragment = buildResult.fragment;
433
+ nodes = buildResult.nodes;
434
+ } else {
435
+ const template = document.createElement("template");
436
+ template.innerHTML = descriptor.template ? descriptor.template.trim() : "";
437
+ fragment = template.content;
438
+ }
439
+ const cleanups = [];
440
+ for (const binding of descriptor.textBindings) {
441
+ const token = `__O_TEXT_${binding.id}__`;
442
+ const textNode = nodes && nodes[binding.id] ? nodes[binding.id] : replaceTokenWithTextNode(fragment, token);
443
+ if (!textNode) {
444
+ continue;
445
+ }
446
+ const stop = effect(() => {
447
+ textNode.data = toText(binding.get());
448
+ });
449
+ cleanups.push(stop);
450
+ }
451
+ for (const binding of descriptor.attrBindings) {
452
+ const token = `__O_ATTR_${binding.id}__`;
453
+ const elements = nodes && nodes[binding.id] ? [nodes[binding.id]] : Array.from(fragment.querySelectorAll("*")).filter(
454
+ (element) => element.getAttribute(binding.attr) === token
455
+ );
456
+ for (const element of elements) {
457
+ const stop = effect(() => {
458
+ const next = binding.attr === "class" ? normalizeClassValue(binding.get()) : toAttr(binding.get());
459
+ if (next === null) {
460
+ element.removeAttribute(binding.attr);
461
+ return;
462
+ }
463
+ element.setAttribute(binding.attr, next);
464
+ });
465
+ cleanups.push(stop);
466
+ }
467
+ }
468
+ for (const binding of descriptor.eventBindings) {
469
+ const selector = `[data-o-on-${binding.event}="${binding.id}"]`;
470
+ const element = nodes && nodes[binding.id] ? nodes[binding.id] : fragment.querySelector(selector);
471
+ if (!element) {
472
+ continue;
473
+ }
474
+ if (!nodes) element.removeAttribute(`data-o-on-${binding.event}`);
475
+ let currentHandler;
476
+ const stop = effect(() => {
477
+ currentHandler = binding.get();
478
+ });
479
+ const listener = (event) => {
480
+ if (typeof currentHandler === "function") {
481
+ currentHandler(event);
482
+ }
483
+ };
484
+ element.addEventListener(binding.event, listener);
485
+ cleanups.push(() => {
486
+ stop();
487
+ element.removeEventListener(binding.event, listener);
488
+ });
489
+ }
490
+ if (target instanceof HTMLElement) {
491
+ target.replaceChildren(fragment);
492
+ } else {
493
+ insertFragmentIntoRange(target, fragment);
494
+ }
495
+ for (const binding of descriptor.htmlBindings) {
496
+ const token = `__O_HTML_${binding.id}__`;
497
+ let range = null;
498
+ if (nodes && nodes[binding.id]) {
499
+ range = document.createRange();
500
+ range.setStartBefore(nodes[binding.id]);
501
+ range.setEndBefore(nodes[binding.id]);
502
+ nodes[binding.id].parentNode?.removeChild(nodes[binding.id]);
503
+ } else {
504
+ range = resolveTokenRange(target, token);
505
+ }
506
+ if (!range) {
507
+ continue;
508
+ }
509
+ let lastHtml = "__OLOVA_INIT__";
510
+ let cleanupJsxEvents = () => {
511
+ };
512
+ const stop = effect(() => {
513
+ const nextHtml = toHtml(binding.get());
514
+ if (nextHtml === lastHtml) {
515
+ return;
516
+ }
517
+ lastHtml = nextHtml;
518
+ cleanupJsxEvents();
519
+ const htmlTemplate = document.createElement("template");
520
+ htmlTemplate.innerHTML = nextHtml;
521
+ insertFragmentIntoRange(range, htmlTemplate.content);
522
+ cleanupJsxEvents = bindJsxEventsInRange(range);
523
+ });
524
+ cleanups.push(() => {
525
+ cleanupJsxEvents();
526
+ stop();
527
+ });
528
+ }
529
+ for (const binding of descriptor.slotBindings) {
530
+ const token = `__O_SLOT_${binding.id}__`;
531
+ let range = null;
532
+ if (nodes && nodes[binding.id]) {
533
+ range = document.createRange();
534
+ range.setStartBefore(nodes[binding.id]);
535
+ range.setEndBefore(nodes[binding.id]);
536
+ nodes[binding.id].parentNode?.removeChild(nodes[binding.id]);
537
+ } else {
538
+ range = resolveTokenRange(target, token);
539
+ }
540
+ if (!range) {
541
+ continue;
542
+ }
543
+ const slotFactory = slots[binding.name];
544
+ if (!slotFactory) {
545
+ range.deleteContents();
546
+ continue;
547
+ }
548
+ const slotDescriptor = slotFactory();
549
+ const disposeSlot = mountDescriptor(slotDescriptor, range, slots, context);
550
+ cleanups.push(disposeSlot);
551
+ }
552
+ for (const binding of descriptor.componentBindings) {
553
+ const token = `__O_COMP_${binding.id}__`;
554
+ let range = null;
555
+ if (nodes && nodes[binding.id]) {
556
+ range = document.createRange();
557
+ range.setStartBefore(nodes[binding.id]);
558
+ range.setEndBefore(nodes[binding.id]);
559
+ nodes[binding.id].parentNode?.removeChild(nodes[binding.id]);
560
+ } else {
561
+ range = resolveTokenRange(target, token);
562
+ }
563
+ if (!range) {
564
+ continue;
565
+ }
566
+ let disposeChild = () => {
567
+ };
568
+ let lastComponent = null;
569
+ let lastProps;
570
+ let lastSlots;
571
+ const stop = effect(() => {
572
+ const nextComponent = binding.getComponent();
573
+ const nextProps = binding.getProps();
574
+ const nextSlots = binding.getSlots ? binding.getSlots() : EMPTY_SLOTS;
575
+ if (lastComponent === nextComponent && shallowEqual(lastProps, nextProps) && shallowEqualSlots(lastSlots, nextSlots)) {
576
+ return;
577
+ }
578
+ disposeChild();
579
+ disposeChild = mount(nextComponent, range, nextProps, nextSlots, context);
580
+ lastComponent = nextComponent;
581
+ lastProps = { ...nextProps };
582
+ lastSlots = nextSlots;
583
+ });
584
+ cleanups.push(() => {
585
+ stop();
586
+ disposeChild();
587
+ });
588
+ }
589
+ if (descriptor.ifBindings) {
590
+ for (const binding of descriptor.ifBindings) {
591
+ const token = `__O_IF_${binding.id}__`;
592
+ let range = null;
593
+ if (nodes && nodes[binding.id]) {
594
+ range = document.createRange();
595
+ range.setStartBefore(nodes[binding.id]);
596
+ range.setEndBefore(nodes[binding.id]);
597
+ nodes[binding.id].parentNode?.removeChild(nodes[binding.id]);
598
+ } else {
599
+ range = resolveTokenRange(target, token);
600
+ }
601
+ if (!range) {
602
+ continue;
603
+ }
604
+ let disposeBranch = () => {
605
+ };
606
+ let lastCondition = void 0;
607
+ const stop = effect(() => {
608
+ const condition = !!binding.get();
609
+ if (condition === lastCondition) {
610
+ return;
611
+ }
612
+ disposeBranch();
613
+ if (condition) {
614
+ const branchDescriptor = binding.trueBranch();
615
+ disposeBranch = mountDescriptor(branchDescriptor, range, slots, context);
616
+ } else if (binding.falseBranch) {
617
+ const branchDescriptor = binding.falseBranch();
618
+ disposeBranch = mountDescriptor(branchDescriptor, range, slots, context);
619
+ } else {
620
+ range.deleteContents();
621
+ disposeBranch = () => {
622
+ };
623
+ }
624
+ lastCondition = condition;
625
+ });
626
+ cleanups.push(() => {
627
+ stop();
628
+ disposeBranch();
629
+ });
630
+ }
631
+ }
632
+ return () => {
633
+ for (const cleanup of cleanups) {
634
+ cleanup();
635
+ }
636
+ if (target instanceof HTMLElement) {
637
+ target.replaceChildren();
638
+ return;
639
+ }
640
+ target.deleteContents();
641
+ };
642
+ }
643
+ function registerMountedInstance(instance) {
644
+ const instances = instance.component.__hmrInstances ?? (instance.component.__hmrInstances = /* @__PURE__ */ new Set());
645
+ instances.add(instance);
646
+ }
647
+ function unregisterMountedInstance(instance) {
648
+ instance.component.__hmrInstances?.delete(instance);
649
+ }
650
+ function renderMountedInstance(instance, restoredValues) {
651
+ const context = new Map(instance.parentContext ?? []);
652
+ const previousContext = currentSetupContext;
653
+ currentSetupContext = context;
654
+ beginHmrStateCapture(restoredValues);
655
+ try {
656
+ const descriptor = instance.component.setup(instance.props, instance.slots);
657
+ instance.disposeDescriptor = mountDescriptor(
658
+ descriptor,
659
+ instance.target,
660
+ instance.slots,
661
+ context
662
+ );
663
+ instance.hmrSignals = endHmrStateCapture();
664
+ } catch (error) {
665
+ endHmrStateCapture();
666
+ throw error;
667
+ } finally {
668
+ currentSetupContext = previousContext;
669
+ }
670
+ }
671
+ function collectHmrSignalValues(instance) {
672
+ return instance.hmrSignals.map(({ key, signal }) => ({
673
+ key,
674
+ value: signal.peek()
675
+ }));
676
+ }
677
+ function replaceComponent(current, next) {
678
+ const instances = current.__hmrInstances;
679
+ if (!instances || instances.size === 0) {
680
+ current.setup = next.setup;
681
+ next.__hmrInstances = instances;
682
+ current.__hmrInstances = void 0;
683
+ return;
684
+ }
685
+ const snapshots = Array.from(instances, (instance) => ({
686
+ instance,
687
+ restoredValues: collectHmrSignalValues(instance)
688
+ }));
689
+ next.__hmrInstances = instances;
690
+ current.__hmrInstances = void 0;
691
+ try {
692
+ for (const { instance, restoredValues } of snapshots) {
693
+ instance.component = next;
694
+ instance.disposeDescriptor();
695
+ renderMountedInstance(instance, restoredValues);
696
+ }
697
+ } catch (error) {
698
+ next.__hmrInstances = void 0;
699
+ current.__hmrInstances = instances;
700
+ for (const { instance, restoredValues } of snapshots) {
701
+ instance.component = current;
702
+ instance.disposeDescriptor();
703
+ renderMountedInstance(instance, restoredValues);
704
+ }
705
+ console.error("[olova] HMR update failed. Restored previous component.", error);
706
+ return;
707
+ }
708
+ }
709
+ function defineComponent(setup, hmrId) {
710
+ return { setup, __hmrId: hmrId };
711
+ }
712
+ function dangerouslySetHtml(value) {
713
+ return {
714
+ __dangerousHtml: true,
715
+ value: toText(value)
716
+ };
717
+ }
718
+ function setContext(key, value) {
719
+ const context = requireSetupContext("setContext");
720
+ context.set(key, value);
721
+ return value;
722
+ }
723
+ function getContext(key) {
724
+ const context = requireSetupContext("getContext");
725
+ return context.get(key);
726
+ }
727
+ function hasContext(key) {
728
+ const context = requireSetupContext("hasContext");
729
+ return context.has(key);
730
+ }
731
+ function mount(component, target, props = {}, slots = EMPTY_SLOTS, parentContext) {
732
+ const instance = {
733
+ component,
734
+ target,
735
+ props,
736
+ slots,
737
+ parentContext,
738
+ disposeDescriptor: () => {
739
+ },
740
+ hmrSignals: []
741
+ };
742
+ registerMountedInstance(instance);
743
+ renderMountedInstance(instance);
744
+ return () => {
745
+ unregisterMountedInstance(instance);
746
+ instance.disposeDescriptor();
747
+ };
748
+ }
749
+ function createApp(root) {
750
+ return {
751
+ mount(target) {
752
+ const element = typeof target === "string" ? document.querySelector(target) : target;
753
+ if (!element) {
754
+ throw new Error(`Target not found: ${String(target)}`);
755
+ }
756
+ return mount(root, element);
757
+ }
758
+ };
759
+ }
760
+
761
+ // runtime/global.ts
762
+ var globalStates = /* @__PURE__ */ new Map();
763
+ var persistCleanups = /* @__PURE__ */ new Map();
764
+ var persistTargets = /* @__PURE__ */ new Map();
765
+ function storageKey(name) {
766
+ return `olova:global:${name}`;
767
+ }
768
+ function getStorage(target) {
769
+ if (typeof window === "undefined") {
770
+ return null;
771
+ }
772
+ if (target === "localStorage") {
773
+ return window.localStorage;
774
+ }
775
+ return null;
776
+ }
777
+ function readPersisted(name, target) {
778
+ const storage = getStorage(target);
779
+ if (!storage) {
780
+ return void 0;
781
+ }
782
+ try {
783
+ const raw = storage.getItem(storageKey(name));
784
+ if (raw == null) {
785
+ return void 0;
786
+ }
787
+ return JSON.parse(raw);
788
+ } catch {
789
+ return void 0;
790
+ }
791
+ }
792
+ function setupPersistence(name, stateRef, target) {
793
+ const currentTarget = persistTargets.get(name);
794
+ if (currentTarget === target && persistCleanups.has(name)) {
795
+ return;
796
+ }
797
+ const previousCleanup = persistCleanups.get(name);
798
+ if (previousCleanup) {
799
+ previousCleanup();
800
+ }
801
+ persistTargets.set(name, target);
802
+ const stop = effect(() => {
803
+ const storage = getStorage(target);
804
+ if (!storage) {
805
+ return;
806
+ }
807
+ try {
808
+ storage.setItem(storageKey(name), JSON.stringify(stateRef.value));
809
+ } catch {
810
+ }
811
+ });
812
+ persistCleanups.set(name, stop);
813
+ }
814
+ function ensureState(name, initial, options) {
815
+ const existing = globalStates.get(name);
816
+ if (existing) {
817
+ if (existing.value === void 0 && initial !== void 0) {
818
+ existing.value = initial;
819
+ }
820
+ if (options?.persist) {
821
+ if (existing.value === void 0) {
822
+ const persisted = readPersisted(name, options.persist);
823
+ if (persisted !== void 0) {
824
+ existing.value = persisted;
825
+ }
826
+ }
827
+ setupPersistence(name, existing, options.persist);
828
+ }
829
+ return existing;
830
+ }
831
+ let resolvedInitial = initial;
832
+ if (options?.persist) {
833
+ const persisted = readPersisted(name, options.persist);
834
+ if (persisted !== void 0) {
835
+ resolvedInitial = persisted;
836
+ }
837
+ }
838
+ const created = state(resolvedInitial);
839
+ globalStates.set(name, created);
840
+ if (options?.persist) {
841
+ setupPersistence(name, created, options.persist);
842
+ }
843
+ return created;
844
+ }
845
+ var global = {
846
+ state(name, initial, options) {
847
+ return ensureState(name, initial, options);
848
+ },
849
+ get(name) {
850
+ return ensureState(name);
851
+ },
852
+ has(name) {
853
+ return globalStates.has(name);
854
+ }
855
+ };
856
+
857
+ export { Signal, beginHmrStateCapture, computed, createApp, dangerouslySetHtml, defineComponent, derived, effect, endHmrStateCapture, getContext, global, hasContext, mount, replaceComponent, setContext, state };
858
+ //# sourceMappingURL=core.js.map
859
+ //# sourceMappingURL=core.js.map