olova 2.0.67 → 2.0.68
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.
- package/CHANGELOG.md +5 -5
- package/README.md +42 -42
- package/dist/compiler.d.ts +76 -1
- package/dist/compiler.js +13204 -630
- package/dist/compiler.js.map +1 -1
- package/dist/core.d.ts +2 -2
- package/dist/core.js +400 -38
- package/dist/core.js.map +1 -1
- package/dist/global.d.ts +1 -1
- package/dist/global.js +54 -8
- package/dist/global.js.map +1 -1
- package/dist/index.js +13178 -640
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +8 -3
- package/dist/runtime.js +512 -32
- package/dist/runtime.js.map +1 -1
- package/dist/{signals-core-BdfWh1Yt.d.ts → signals-core-BWZ5zXK5.d.ts} +6 -5
- package/dist/vite.js +13178 -640
- package/dist/vite.js.map +1 -1
- package/package.json +83 -83
package/dist/runtime.js
CHANGED
|
@@ -1,9 +1,180 @@
|
|
|
1
|
-
import { effect as effect$1 } from '@preact/signals-core';
|
|
1
|
+
import { signal, effect as effect$1 } from '@preact/signals-core';
|
|
2
2
|
|
|
3
3
|
// core/signals-core.ts
|
|
4
|
+
var rawToProxyByOwner = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
var proxyToRaw = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
var proxyOwner = /* @__PURE__ */ new WeakMap();
|
|
4
7
|
var hmrCaptureStack = [];
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
var runtimeErrorHandlerStack = [];
|
|
9
|
+
function isObject(value) {
|
|
10
|
+
return typeof value === "object" && value !== null;
|
|
11
|
+
}
|
|
12
|
+
function unwrapValue(value) {
|
|
13
|
+
if (!isObject(value)) {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
return proxyToRaw.get(value) ?? value;
|
|
17
|
+
}
|
|
18
|
+
var Signal = class {
|
|
19
|
+
source;
|
|
20
|
+
version;
|
|
21
|
+
proxy = null;
|
|
22
|
+
constructor(initial, source, version) {
|
|
23
|
+
this.source = source ?? signal(initial);
|
|
24
|
+
this.version = version ?? signal(0);
|
|
25
|
+
}
|
|
26
|
+
get value() {
|
|
27
|
+
this.version.value;
|
|
28
|
+
return this.getReactiveValue(this.source.value);
|
|
29
|
+
}
|
|
30
|
+
set value(next) {
|
|
31
|
+
const resolvedNext = unwrapValue(next);
|
|
32
|
+
if (Object.is(this.source.peek(), resolvedNext)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.proxy = null;
|
|
36
|
+
this.source.value = resolvedNext;
|
|
37
|
+
}
|
|
38
|
+
peek() {
|
|
39
|
+
return this.source.peek();
|
|
40
|
+
}
|
|
41
|
+
notify() {
|
|
42
|
+
this.version.value = this.version.peek() + 1;
|
|
43
|
+
}
|
|
44
|
+
peekVersion() {
|
|
45
|
+
return this.version.peek();
|
|
46
|
+
}
|
|
47
|
+
subscribe(fn) {
|
|
48
|
+
return this.source.subscribe(fn);
|
|
49
|
+
}
|
|
50
|
+
valueOf() {
|
|
51
|
+
return this.value;
|
|
52
|
+
}
|
|
53
|
+
toString() {
|
|
54
|
+
return String(this.value);
|
|
55
|
+
}
|
|
56
|
+
toJSON() {
|
|
57
|
+
return this.peek();
|
|
58
|
+
}
|
|
59
|
+
getReactiveValue(value) {
|
|
60
|
+
if (!isObject(value)) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
if (this.proxy && proxyToRaw.get(this.proxy) === value) {
|
|
64
|
+
return this.proxy;
|
|
65
|
+
}
|
|
66
|
+
this.proxy = this.wrapObject(value);
|
|
67
|
+
return this.proxy;
|
|
68
|
+
}
|
|
69
|
+
wrapObject(value) {
|
|
70
|
+
const ownedProxyMap = rawToProxyByOwner.get(value);
|
|
71
|
+
const existing = ownedProxyMap?.get(this);
|
|
72
|
+
if (existing) {
|
|
73
|
+
return existing;
|
|
74
|
+
}
|
|
75
|
+
const proxy = new Proxy(value, {
|
|
76
|
+
get: (target, key, receiver) => {
|
|
77
|
+
const result = Reflect.get(target, key, receiver);
|
|
78
|
+
return isObject(result) ? this.wrapNested(result) : result;
|
|
79
|
+
},
|
|
80
|
+
set: (target, key, next, receiver) => {
|
|
81
|
+
const resolvedNext = unwrapValue(next);
|
|
82
|
+
const previous = Reflect.get(target, key, receiver);
|
|
83
|
+
const changed = Reflect.set(target, key, resolvedNext, receiver);
|
|
84
|
+
if (changed && !Object.is(previous, resolvedNext)) {
|
|
85
|
+
this.notify();
|
|
86
|
+
}
|
|
87
|
+
return changed;
|
|
88
|
+
},
|
|
89
|
+
deleteProperty: (target, key) => {
|
|
90
|
+
const hadKey = Reflect.has(target, key);
|
|
91
|
+
const changed = Reflect.deleteProperty(target, key);
|
|
92
|
+
if (hadKey && changed) {
|
|
93
|
+
this.notify();
|
|
94
|
+
}
|
|
95
|
+
return changed;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const nextOwnedProxyMap = ownedProxyMap ?? /* @__PURE__ */ new WeakMap();
|
|
99
|
+
nextOwnedProxyMap.set(this, proxy);
|
|
100
|
+
if (!ownedProxyMap) {
|
|
101
|
+
rawToProxyByOwner.set(value, nextOwnedProxyMap);
|
|
102
|
+
}
|
|
103
|
+
proxyToRaw.set(proxy, value);
|
|
104
|
+
proxyOwner.set(proxy, this);
|
|
105
|
+
return proxy;
|
|
106
|
+
}
|
|
107
|
+
wrapNested(value) {
|
|
108
|
+
const owner = proxyOwner.get(value);
|
|
109
|
+
if (owner === this) {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
return this.wrapObject(value);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
function state(initial, hmrKey) {
|
|
116
|
+
const frame = hmrCaptureStack[hmrCaptureStack.length - 1];
|
|
117
|
+
let nextInitial = initial;
|
|
118
|
+
if (frame) {
|
|
119
|
+
if (frame.cursor < frame.restoredUnkeyed.length) {
|
|
120
|
+
nextInitial = frame.restoredUnkeyed[frame.cursor];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const signal = new Signal(nextInitial);
|
|
124
|
+
if (frame) {
|
|
125
|
+
frame.created.push({ key: hmrKey, signal });
|
|
126
|
+
{
|
|
127
|
+
frame.cursor += 1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return signal;
|
|
131
|
+
}
|
|
132
|
+
function getReactiveProxyVersion(value) {
|
|
133
|
+
if (!isObject(value)) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const owner = proxyOwner.get(value);
|
|
137
|
+
return owner ? owner.peekVersion() : null;
|
|
138
|
+
}
|
|
139
|
+
function reportRuntimeError(error, handler) {
|
|
140
|
+
if (handler) {
|
|
141
|
+
handler(error);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
function withRuntimeErrorHandler(handler, fn) {
|
|
147
|
+
if (!handler) {
|
|
148
|
+
return fn();
|
|
149
|
+
}
|
|
150
|
+
runtimeErrorHandlerStack.push(handler);
|
|
151
|
+
try {
|
|
152
|
+
return fn();
|
|
153
|
+
} finally {
|
|
154
|
+
runtimeErrorHandlerStack.pop();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function effect(fn) {
|
|
158
|
+
const handler = runtimeErrorHandlerStack[runtimeErrorHandlerStack.length - 1] ?? null;
|
|
159
|
+
const stop = effect$1(
|
|
160
|
+
() => withRuntimeErrorHandler(handler, () => {
|
|
161
|
+
try {
|
|
162
|
+
const cleanup = fn();
|
|
163
|
+
if (typeof cleanup !== "function") {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
return () => withRuntimeErrorHandler(handler, () => {
|
|
167
|
+
try {
|
|
168
|
+
cleanup();
|
|
169
|
+
} catch (error) {
|
|
170
|
+
reportRuntimeError(error, handler);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
reportRuntimeError(error, handler);
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
);
|
|
7
178
|
return () => stop();
|
|
8
179
|
}
|
|
9
180
|
function beginHmrStateCapture(restoredValues) {
|
|
@@ -32,6 +203,40 @@ function endHmrStateCapture() {
|
|
|
32
203
|
// runtime/component.ts
|
|
33
204
|
var EMPTY_SLOTS = Object.freeze({});
|
|
34
205
|
var currentSetupContext = null;
|
|
206
|
+
var currentLifecycleHooks = null;
|
|
207
|
+
var ERROR_BOUNDARY = /* @__PURE__ */ Symbol("olova.error-boundary");
|
|
208
|
+
var SUSPENSE_BOUNDARY = /* @__PURE__ */ Symbol("olova.suspense-boundary");
|
|
209
|
+
function isPromiseLike(value) {
|
|
210
|
+
return !!value && typeof value === "object" && "then" in value;
|
|
211
|
+
}
|
|
212
|
+
function toOlovaError(error, context) {
|
|
213
|
+
if (error instanceof Error && error.message.startsWith("[olova]")) {
|
|
214
|
+
return error;
|
|
215
|
+
}
|
|
216
|
+
const original = error instanceof Error ? error : new Error(String(error));
|
|
217
|
+
const wrapped = new Error(`[olova] ${context}: ${original.message}`);
|
|
218
|
+
wrapped.cause = error;
|
|
219
|
+
return wrapped;
|
|
220
|
+
}
|
|
221
|
+
function getBoundaryHandler(context) {
|
|
222
|
+
return context?.get(ERROR_BOUNDARY) ?? null;
|
|
223
|
+
}
|
|
224
|
+
function handleRuntimeError(error, contextMessage, context) {
|
|
225
|
+
const normalized = toOlovaError(error, contextMessage);
|
|
226
|
+
const boundaryHandler = getBoundaryHandler(context);
|
|
227
|
+
if (boundaryHandler) {
|
|
228
|
+
boundaryHandler(normalized);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
throw normalized;
|
|
232
|
+
}
|
|
233
|
+
function runWithRuntimeErrorHandler(context, action, fn) {
|
|
234
|
+
try {
|
|
235
|
+
return withRuntimeErrorHandler(getBoundaryHandler(context), fn);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return handleRuntimeError(error, action, context);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
35
240
|
function requireSetupContext(apiName) {
|
|
36
241
|
if (!currentSetupContext) {
|
|
37
242
|
throw new Error(
|
|
@@ -90,12 +295,12 @@ function sanitizeHtml(html) {
|
|
|
90
295
|
}
|
|
91
296
|
for (const attr of Array.from(element.attributes)) {
|
|
92
297
|
const attrName = attr.name.toLowerCase();
|
|
93
|
-
const attrValue = attr.value.trim()
|
|
298
|
+
const attrValue = attr.value.trim();
|
|
94
299
|
if (attrName.startsWith("on")) {
|
|
95
300
|
element.removeAttribute(attr.name);
|
|
96
301
|
continue;
|
|
97
302
|
}
|
|
98
|
-
if ((attrName === "href" || attrName === "src" || attrName === "xlink:href") && attrValue
|
|
303
|
+
if ((attrName === "href" || attrName === "src" || attrName === "xlink:href") && !isSafeUrl(attrName, attrValue)) {
|
|
99
304
|
element.removeAttribute(attr.name);
|
|
100
305
|
}
|
|
101
306
|
}
|
|
@@ -114,7 +319,27 @@ function toHtml(value) {
|
|
|
114
319
|
}
|
|
115
320
|
return sanitizeHtml(String(value));
|
|
116
321
|
}
|
|
117
|
-
|
|
322
|
+
var SAFE_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
|
|
323
|
+
var SAFE_IMAGE_DATA_URL_RE = /^data:image\/(?:png|gif|jpe?g|webp|avif|bmp);(?:charset=[^;,]+;)?base64,[a-z0-9+/=\s]+$/i;
|
|
324
|
+
function isSafeUrl(attrName, value) {
|
|
325
|
+
const normalized = value.replace(/[\u0000-\u001F\u007F\s]+/g, "");
|
|
326
|
+
if (!normalized) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (normalized.startsWith("#") || normalized.startsWith("/") || normalized.startsWith("./") || normalized.startsWith("../") || normalized.startsWith("?")) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
const match = normalized.match(/^([a-z0-9+.-]+):/i);
|
|
333
|
+
if (!match) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
const protocol = match[1].toLowerCase();
|
|
337
|
+
if (SAFE_URL_PROTOCOLS.has(protocol)) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
return protocol === "data" && attrName === "src" && SAFE_IMAGE_DATA_URL_RE.test(normalized);
|
|
341
|
+
}
|
|
342
|
+
function shallowEqualSlots(a, b) {
|
|
118
343
|
if (a === b) {
|
|
119
344
|
return true;
|
|
120
345
|
}
|
|
@@ -133,20 +358,39 @@ function shallowEqual(a, b) {
|
|
|
133
358
|
}
|
|
134
359
|
return true;
|
|
135
360
|
}
|
|
136
|
-
function
|
|
137
|
-
|
|
361
|
+
function createComparablePropsSnapshot(props) {
|
|
362
|
+
return Object.fromEntries(
|
|
363
|
+
Object.entries(props).map(([key, value]) => [
|
|
364
|
+
key,
|
|
365
|
+
{
|
|
366
|
+
value,
|
|
367
|
+
reactiveVersion: getReactiveProxyVersion(value)
|
|
368
|
+
}
|
|
369
|
+
])
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
function shallowComparablePropsEqual(snapshot, props) {
|
|
373
|
+
if (!snapshot && !props) {
|
|
138
374
|
return true;
|
|
139
375
|
}
|
|
140
|
-
if (!
|
|
376
|
+
if (!snapshot || !props) {
|
|
141
377
|
return false;
|
|
142
378
|
}
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
379
|
+
const keys = Object.keys(snapshot);
|
|
380
|
+
const propKeys = Object.keys(props);
|
|
381
|
+
if (keys.length !== propKeys.length) {
|
|
146
382
|
return false;
|
|
147
383
|
}
|
|
148
|
-
for (const key of
|
|
149
|
-
if (!
|
|
384
|
+
for (const key of keys) {
|
|
385
|
+
if (!(key in props)) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
const entry = snapshot[key];
|
|
389
|
+
const nextValue = props[key];
|
|
390
|
+
if (!Object.is(entry.value, nextValue)) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
if (entry.reactiveVersion !== getReactiveProxyVersion(nextValue)) {
|
|
150
394
|
return false;
|
|
151
395
|
}
|
|
152
396
|
}
|
|
@@ -179,7 +423,7 @@ function bindJsxEventsInRange(range) {
|
|
|
179
423
|
const listeners = [];
|
|
180
424
|
const handlerIds = /* @__PURE__ */ new Set();
|
|
181
425
|
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
182
|
-
let current = walker.
|
|
426
|
+
let current = walker.nextNode();
|
|
183
427
|
while (current) {
|
|
184
428
|
let intersects = false;
|
|
185
429
|
try {
|
|
@@ -299,6 +543,42 @@ function createRangeAtTokenWithinRange(hostRange, token) {
|
|
|
299
543
|
function resolveTokenRange(target, token) {
|
|
300
544
|
return target instanceof HTMLElement ? createRangeAtToken(target, token) : createRangeAtTokenWithinRange(target, token);
|
|
301
545
|
}
|
|
546
|
+
function createLifecycleHooks() {
|
|
547
|
+
return {
|
|
548
|
+
mount: [],
|
|
549
|
+
cleanup: []
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function flushLifecycleHooks(hooks, context) {
|
|
553
|
+
for (const mountHook of hooks.mount) {
|
|
554
|
+
const cleanup = runWithRuntimeErrorHandler(
|
|
555
|
+
context,
|
|
556
|
+
"Failed to run onMount() callback",
|
|
557
|
+
mountHook
|
|
558
|
+
);
|
|
559
|
+
if (typeof cleanup === "function") {
|
|
560
|
+
hooks.cleanup.push(cleanup);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return () => {
|
|
564
|
+
for (let index = hooks.cleanup.length - 1; index >= 0; index -= 1) {
|
|
565
|
+
runWithRuntimeErrorHandler(
|
|
566
|
+
context,
|
|
567
|
+
"Failed to run cleanup callback",
|
|
568
|
+
hooks.cleanup[index]
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
function createDescriptorEffect(context, fn) {
|
|
574
|
+
const stop = runWithRuntimeErrorHandler(
|
|
575
|
+
context,
|
|
576
|
+
"Failed to create reactive binding",
|
|
577
|
+
() => effect(fn)
|
|
578
|
+
);
|
|
579
|
+
return typeof stop === "function" ? stop : () => {
|
|
580
|
+
};
|
|
581
|
+
}
|
|
302
582
|
function mountDescriptor(descriptor, target, slots, context) {
|
|
303
583
|
let fragment;
|
|
304
584
|
let nodes = null;
|
|
@@ -318,7 +598,7 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
318
598
|
if (!textNode) {
|
|
319
599
|
continue;
|
|
320
600
|
}
|
|
321
|
-
const stop =
|
|
601
|
+
const stop = createDescriptorEffect(context, () => {
|
|
322
602
|
textNode.data = toText(binding.get());
|
|
323
603
|
});
|
|
324
604
|
cleanups.push(stop);
|
|
@@ -329,7 +609,7 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
329
609
|
(element) => element.getAttribute(binding.attr) === token
|
|
330
610
|
);
|
|
331
611
|
for (const element of elements) {
|
|
332
|
-
const stop =
|
|
612
|
+
const stop = createDescriptorEffect(context, () => {
|
|
333
613
|
const next = binding.attr === "class" ? normalizeClassValue(binding.get()) : toAttr(binding.get());
|
|
334
614
|
if (next === null) {
|
|
335
615
|
element.removeAttribute(binding.attr);
|
|
@@ -348,7 +628,7 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
348
628
|
}
|
|
349
629
|
if (!nodes) element.removeAttribute(`data-o-on-${binding.event}`);
|
|
350
630
|
let currentHandler;
|
|
351
|
-
const stop =
|
|
631
|
+
const stop = createDescriptorEffect(context, () => {
|
|
352
632
|
currentHandler = binding.get();
|
|
353
633
|
});
|
|
354
634
|
const listener = (event) => {
|
|
@@ -384,7 +664,7 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
384
664
|
let lastHtml = "__OLOVA_INIT__";
|
|
385
665
|
let cleanupJsxEvents = () => {
|
|
386
666
|
};
|
|
387
|
-
const stop =
|
|
667
|
+
const stop = createDescriptorEffect(context, () => {
|
|
388
668
|
const nextHtml = toHtml(binding.get());
|
|
389
669
|
if (nextHtml === lastHtml) {
|
|
390
670
|
return;
|
|
@@ -420,7 +700,15 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
420
700
|
range.deleteContents();
|
|
421
701
|
continue;
|
|
422
702
|
}
|
|
423
|
-
const slotDescriptor =
|
|
703
|
+
const slotDescriptor = runWithRuntimeErrorHandler(
|
|
704
|
+
context,
|
|
705
|
+
`Failed to render slot "${binding.name}"`,
|
|
706
|
+
slotFactory
|
|
707
|
+
);
|
|
708
|
+
if (!slotDescriptor) {
|
|
709
|
+
range.deleteContents();
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
424
712
|
const disposeSlot = mountDescriptor(slotDescriptor, range, slots, context);
|
|
425
713
|
cleanups.push(disposeSlot);
|
|
426
714
|
}
|
|
@@ -443,17 +731,17 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
443
731
|
let lastComponent = null;
|
|
444
732
|
let lastProps;
|
|
445
733
|
let lastSlots;
|
|
446
|
-
const stop =
|
|
734
|
+
const stop = createDescriptorEffect(context, () => {
|
|
447
735
|
const nextComponent = binding.getComponent();
|
|
448
736
|
const nextProps = binding.getProps();
|
|
449
737
|
const nextSlots = binding.getSlots ? binding.getSlots() : EMPTY_SLOTS;
|
|
450
|
-
if (lastComponent === nextComponent &&
|
|
738
|
+
if (lastComponent === nextComponent && shallowComparablePropsEqual(lastProps, nextProps) && shallowEqualSlots(lastSlots, nextSlots)) {
|
|
451
739
|
return;
|
|
452
740
|
}
|
|
453
741
|
disposeChild();
|
|
454
742
|
disposeChild = mount(nextComponent, range, nextProps, nextSlots, context);
|
|
455
743
|
lastComponent = nextComponent;
|
|
456
|
-
lastProps =
|
|
744
|
+
lastProps = createComparablePropsSnapshot(nextProps);
|
|
457
745
|
lastSlots = nextSlots;
|
|
458
746
|
});
|
|
459
747
|
cleanups.push(() => {
|
|
@@ -479,17 +767,39 @@ function mountDescriptor(descriptor, target, slots, context) {
|
|
|
479
767
|
let disposeBranch = () => {
|
|
480
768
|
};
|
|
481
769
|
let lastCondition = void 0;
|
|
482
|
-
const stop =
|
|
770
|
+
const stop = createDescriptorEffect(context, () => {
|
|
483
771
|
const condition = !!binding.get();
|
|
484
772
|
if (condition === lastCondition) {
|
|
485
773
|
return;
|
|
486
774
|
}
|
|
487
775
|
disposeBranch();
|
|
488
776
|
if (condition) {
|
|
489
|
-
const branchDescriptor =
|
|
777
|
+
const branchDescriptor = runWithRuntimeErrorHandler(
|
|
778
|
+
context,
|
|
779
|
+
"Failed to render conditional branch",
|
|
780
|
+
binding.trueBranch
|
|
781
|
+
);
|
|
782
|
+
if (!branchDescriptor) {
|
|
783
|
+
range.deleteContents();
|
|
784
|
+
disposeBranch = () => {
|
|
785
|
+
};
|
|
786
|
+
lastCondition = condition;
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
490
789
|
disposeBranch = mountDescriptor(branchDescriptor, range, slots, context);
|
|
491
790
|
} else if (binding.falseBranch) {
|
|
492
|
-
const branchDescriptor =
|
|
791
|
+
const branchDescriptor = runWithRuntimeErrorHandler(
|
|
792
|
+
context,
|
|
793
|
+
"Failed to render conditional fallback branch",
|
|
794
|
+
binding.falseBranch
|
|
795
|
+
);
|
|
796
|
+
if (!branchDescriptor) {
|
|
797
|
+
range.deleteContents();
|
|
798
|
+
disposeBranch = () => {
|
|
799
|
+
};
|
|
800
|
+
lastCondition = condition;
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
493
803
|
disposeBranch = mountDescriptor(branchDescriptor, range, slots, context);
|
|
494
804
|
} else {
|
|
495
805
|
range.deleteContents();
|
|
@@ -525,22 +835,69 @@ function unregisterMountedInstance(instance) {
|
|
|
525
835
|
function renderMountedInstance(instance, restoredValues) {
|
|
526
836
|
const context = new Map(instance.parentContext ?? []);
|
|
527
837
|
const previousContext = currentSetupContext;
|
|
838
|
+
const previousLifecycleHooks = currentLifecycleHooks;
|
|
839
|
+
const lifecycleHooks = createLifecycleHooks();
|
|
528
840
|
currentSetupContext = context;
|
|
841
|
+
currentLifecycleHooks = lifecycleHooks;
|
|
529
842
|
beginHmrStateCapture(restoredValues);
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
instance.disposeDescriptor = mountDescriptor(
|
|
843
|
+
const finalizeRender = (descriptor) => {
|
|
844
|
+
const disposeDescriptor = mountDescriptor(
|
|
533
845
|
descriptor,
|
|
534
846
|
instance.target,
|
|
535
847
|
instance.slots,
|
|
536
848
|
context
|
|
537
849
|
);
|
|
850
|
+
const disposeLifecycle = flushLifecycleHooks(lifecycleHooks, context);
|
|
851
|
+
instance.disposeDescriptor = () => {
|
|
852
|
+
disposeLifecycle();
|
|
853
|
+
disposeDescriptor();
|
|
854
|
+
};
|
|
855
|
+
};
|
|
856
|
+
try {
|
|
857
|
+
const descriptor = runWithRuntimeErrorHandler(
|
|
858
|
+
context,
|
|
859
|
+
"Failed to render component setup",
|
|
860
|
+
() => instance.component.setup(instance.props, instance.slots)
|
|
861
|
+
);
|
|
862
|
+
if (!descriptor) {
|
|
863
|
+
instance.disposeDescriptor = () => {
|
|
864
|
+
};
|
|
865
|
+
instance.hmrSignals = endHmrStateCapture();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (isPromiseLike(descriptor)) {
|
|
869
|
+
const suspenseBoundary = context.get(SUSPENSE_BOUNDARY);
|
|
870
|
+
const settleSuspense = suspenseBoundary?.begin() ?? (() => {
|
|
871
|
+
});
|
|
872
|
+
let disposed = false;
|
|
873
|
+
instance.disposeDescriptor = () => {
|
|
874
|
+
disposed = true;
|
|
875
|
+
settleSuspense();
|
|
876
|
+
};
|
|
877
|
+
instance.hmrSignals = endHmrStateCapture();
|
|
878
|
+
descriptor.then((resolvedDescriptor) => {
|
|
879
|
+
if (disposed) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
settleSuspense();
|
|
883
|
+
finalizeRender(resolvedDescriptor);
|
|
884
|
+
}).catch((error) => {
|
|
885
|
+
settleSuspense();
|
|
886
|
+
if (disposed) {
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
handleRuntimeError(error, "Failed to resolve async component", context);
|
|
890
|
+
});
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
finalizeRender(descriptor);
|
|
538
894
|
instance.hmrSignals = endHmrStateCapture();
|
|
539
895
|
} catch (error) {
|
|
540
896
|
endHmrStateCapture();
|
|
541
897
|
throw error;
|
|
542
898
|
} finally {
|
|
543
899
|
currentSetupContext = previousContext;
|
|
900
|
+
currentLifecycleHooks = previousLifecycleHooks;
|
|
544
901
|
}
|
|
545
902
|
}
|
|
546
903
|
function collectHmrSignalValues(instance) {
|
|
@@ -584,6 +941,124 @@ function replaceComponent(current, next) {
|
|
|
584
941
|
function defineComponent(setup, hmrId) {
|
|
585
942
|
return { setup, __hmrId: hmrId };
|
|
586
943
|
}
|
|
944
|
+
function isOlovaComponent(value) {
|
|
945
|
+
return typeof value === "object" && value !== null && "setup" in value;
|
|
946
|
+
}
|
|
947
|
+
function onMount(fn) {
|
|
948
|
+
if (!currentLifecycleHooks) {
|
|
949
|
+
throw new Error("[olova] onMount() can only be used during component setup.");
|
|
950
|
+
}
|
|
951
|
+
currentLifecycleHooks.mount.push(fn);
|
|
952
|
+
}
|
|
953
|
+
function onCleanup(fn) {
|
|
954
|
+
if (!currentLifecycleHooks) {
|
|
955
|
+
throw new Error("[olova] onCleanup() can only be used during component setup.");
|
|
956
|
+
}
|
|
957
|
+
currentLifecycleHooks.cleanup.push(fn);
|
|
958
|
+
}
|
|
959
|
+
function createErrorBoundary(component, fallback) {
|
|
960
|
+
return defineComponent((props, slots) => {
|
|
961
|
+
const errorState = state(null);
|
|
962
|
+
setContext(ERROR_BOUNDARY, (error) => {
|
|
963
|
+
errorState.value = error;
|
|
964
|
+
});
|
|
965
|
+
const renderFallback = () => {
|
|
966
|
+
const error = errorState.value ?? new Error("[olova] Unknown boundary error.");
|
|
967
|
+
if (isOlovaComponent(fallback)) {
|
|
968
|
+
return {
|
|
969
|
+
template: "__O_COMP_boundary_fallback__",
|
|
970
|
+
textBindings: [],
|
|
971
|
+
htmlBindings: [],
|
|
972
|
+
attrBindings: [],
|
|
973
|
+
eventBindings: [],
|
|
974
|
+
slotBindings: [],
|
|
975
|
+
componentBindings: [
|
|
976
|
+
{
|
|
977
|
+
id: "boundary_fallback",
|
|
978
|
+
getComponent: () => fallback,
|
|
979
|
+
getProps: () => ({ error })
|
|
980
|
+
}
|
|
981
|
+
],
|
|
982
|
+
ifBindings: []
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
return fallback(error);
|
|
986
|
+
};
|
|
987
|
+
return {
|
|
988
|
+
template: "__O_IF_boundary__",
|
|
989
|
+
textBindings: [],
|
|
990
|
+
htmlBindings: [],
|
|
991
|
+
attrBindings: [],
|
|
992
|
+
eventBindings: [],
|
|
993
|
+
slotBindings: [],
|
|
994
|
+
componentBindings: [],
|
|
995
|
+
ifBindings: [
|
|
996
|
+
{
|
|
997
|
+
id: "boundary",
|
|
998
|
+
get: () => errorState.value === null,
|
|
999
|
+
trueBranch: () => ({
|
|
1000
|
+
template: "__O_COMP_boundary_child__",
|
|
1001
|
+
textBindings: [],
|
|
1002
|
+
htmlBindings: [],
|
|
1003
|
+
attrBindings: [],
|
|
1004
|
+
eventBindings: [],
|
|
1005
|
+
slotBindings: [],
|
|
1006
|
+
componentBindings: [
|
|
1007
|
+
{
|
|
1008
|
+
id: "boundary_child",
|
|
1009
|
+
getComponent: () => component,
|
|
1010
|
+
getProps: () => props,
|
|
1011
|
+
getSlots: () => slots
|
|
1012
|
+
}
|
|
1013
|
+
],
|
|
1014
|
+
ifBindings: []
|
|
1015
|
+
}),
|
|
1016
|
+
falseBranch: renderFallback
|
|
1017
|
+
}
|
|
1018
|
+
]
|
|
1019
|
+
};
|
|
1020
|
+
}, component.__hmrId ? `${component.__hmrId}:boundary` : void 0);
|
|
1021
|
+
}
|
|
1022
|
+
var Suspense = defineComponent((_props, slots) => {
|
|
1023
|
+
const pending = state(0);
|
|
1024
|
+
setContext(SUSPENSE_BOUNDARY, {
|
|
1025
|
+
begin() {
|
|
1026
|
+
pending.value += 1;
|
|
1027
|
+
let settled = false;
|
|
1028
|
+
return () => {
|
|
1029
|
+
if (settled) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
settled = true;
|
|
1033
|
+
pending.value = Math.max(0, pending.value - 1);
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
return {
|
|
1038
|
+
template: `<div style="__O_ATTR_default_style__">__O_SLOT_default__</div><div style="__O_ATTR_fallback_style__">__O_SLOT_fallback__</div>`,
|
|
1039
|
+
textBindings: [],
|
|
1040
|
+
htmlBindings: [],
|
|
1041
|
+
attrBindings: [
|
|
1042
|
+
{
|
|
1043
|
+
id: "default_style",
|
|
1044
|
+
attr: "style",
|
|
1045
|
+
get: () => pending.value === 0 ? null : "display:none"
|
|
1046
|
+
},
|
|
1047
|
+
{
|
|
1048
|
+
id: "fallback_style",
|
|
1049
|
+
attr: "style",
|
|
1050
|
+
get: () => pending.value > 0 ? null : "display:none"
|
|
1051
|
+
}
|
|
1052
|
+
],
|
|
1053
|
+
eventBindings: [],
|
|
1054
|
+
slotBindings: [
|
|
1055
|
+
{ id: "default", name: "default" },
|
|
1056
|
+
{ id: "fallback", name: "fallback" }
|
|
1057
|
+
],
|
|
1058
|
+
componentBindings: [],
|
|
1059
|
+
ifBindings: []
|
|
1060
|
+
};
|
|
1061
|
+
});
|
|
587
1062
|
function dangerouslySetHtml(value) {
|
|
588
1063
|
return {
|
|
589
1064
|
__dangerousHtml: true,
|
|
@@ -615,7 +1090,12 @@ function mount(component, target, props = {}, slots = EMPTY_SLOTS, parentContext
|
|
|
615
1090
|
hmrSignals: []
|
|
616
1091
|
};
|
|
617
1092
|
registerMountedInstance(instance);
|
|
618
|
-
|
|
1093
|
+
try {
|
|
1094
|
+
renderMountedInstance(instance);
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
unregisterMountedInstance(instance);
|
|
1097
|
+
throw toOlovaError(error, "Failed to mount component");
|
|
1098
|
+
}
|
|
619
1099
|
return () => {
|
|
620
1100
|
unregisterMountedInstance(instance);
|
|
621
1101
|
instance.disposeDescriptor();
|
|
@@ -626,13 +1106,13 @@ function createApp(root) {
|
|
|
626
1106
|
mount(target) {
|
|
627
1107
|
const element = typeof target === "string" ? document.querySelector(target) : target;
|
|
628
1108
|
if (!element) {
|
|
629
|
-
throw new Error(`Target not found: ${String(target)}`);
|
|
1109
|
+
throw new Error(`[olova] Target not found: ${String(target)}`);
|
|
630
1110
|
}
|
|
631
1111
|
return mount(root, element);
|
|
632
1112
|
}
|
|
633
1113
|
};
|
|
634
1114
|
}
|
|
635
1115
|
|
|
636
|
-
export { createApp, dangerouslySetHtml, defineComponent, getContext, hasContext, mount, replaceComponent, setContext };
|
|
1116
|
+
export { Suspense, createApp, createErrorBoundary, dangerouslySetHtml, defineComponent, getContext, hasContext, mount, onCleanup, onMount, replaceComponent, setContext };
|
|
637
1117
|
//# sourceMappingURL=runtime.js.map
|
|
638
1118
|
//# sourceMappingURL=runtime.js.map
|