sibujs 3.4.0 → 4.0.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.
- package/LICENSE +21 -21
- package/README.md +118 -15
- package/dist/browser.cjs +410 -101
- package/dist/browser.d.cts +50 -5
- package/dist/browser.d.ts +50 -5
- package/dist/browser.js +8 -6
- package/dist/build.cjs +777 -385
- package/dist/build.js +15 -15
- package/dist/cdn.global.js +11 -7
- package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
- package/dist/chunk-4MFZMLUU.js +147 -0
- package/dist/chunk-52XFPGSN.js +123 -0
- package/dist/chunk-5INI7D2L.js +194 -0
- package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
- package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
- package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
- package/dist/chunk-DHDZ7IVN.js +109 -0
- package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
- package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
- package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
- package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
- package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
- package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
- package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
- package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
- package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
- package/dist/chunk-O3QQ3XOL.js +61 -0
- package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
- package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
- package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
- package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
- package/dist/chunk-VPP2FONR.js +142 -0
- package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
- package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
- package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
- package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
- package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
- package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
- package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
- package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
- package/dist/data.cjs +483 -205
- package/dist/data.d.cts +139 -7
- package/dist/data.d.ts +139 -7
- package/dist/data.js +9 -9
- package/dist/devtools.cjs +222 -87
- package/dist/devtools.js +8 -8
- package/dist/dispose-4FZ6OFXR.js +19 -0
- package/dist/ecosystem.cjs +419 -175
- package/dist/ecosystem.js +11 -11
- package/dist/extras.cjs +1981 -765
- package/dist/extras.d.cts +7 -7
- package/dist/extras.d.ts +7 -7
- package/dist/extras.js +29 -26
- package/dist/index.cjs +784 -385
- package/dist/index.d.cts +299 -28
- package/dist/index.d.ts +299 -28
- package/dist/index.js +33 -18
- package/dist/motion.cjs +180 -50
- package/dist/motion.d.cts +26 -0
- package/dist/motion.d.ts +26 -0
- package/dist/motion.js +5 -5
- package/dist/patterns.cjs +437 -170
- package/dist/patterns.d.cts +60 -13
- package/dist/patterns.d.ts +60 -13
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +333 -148
- package/dist/performance.d.cts +55 -7
- package/dist/performance.d.ts +55 -7
- package/dist/performance.js +9 -9
- package/dist/plugins.cjs +1374 -576
- package/dist/plugins.d.cts +227 -9
- package/dist/plugins.d.ts +227 -9
- package/dist/plugins.js +613 -321
- package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
- package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
- package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
- package/dist/ssr.cjs +1104 -443
- package/dist/ssr.d.cts +230 -20
- package/dist/ssr.d.ts +230 -20
- package/dist/ssr.js +15 -12
- package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
- package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
- package/dist/testing.cjs +205 -63
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +8 -10
- package/dist/ui.cjs +640 -199
- package/dist/ui.d.cts +2 -2
- package/dist/ui.d.ts +2 -2
- package/dist/ui.js +10 -10
- package/dist/widgets.cjs +207 -82
- package/dist/widgets.js +9 -9
- package/package.json +12 -7
- package/dist/chunk-5VGSK6D2.js +0 -80
- package/dist/chunk-COY6PUD2.js +0 -34
- package/dist/chunk-K35BAR4P.js +0 -96
- package/dist/chunk-L3GAGWCC.js +0 -111
- package/dist/chunk-RT3IYFN2.js +0 -38
package/dist/ecosystem.cjs
CHANGED
|
@@ -53,8 +53,95 @@ function devWarn(message) {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// src/core/errors.ts
|
|
57
|
+
var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
|
|
58
|
+
function state() {
|
|
59
|
+
const g = globalThis;
|
|
60
|
+
const existing = g[ERROR_STATE_KEY];
|
|
61
|
+
if (existing) return existing;
|
|
62
|
+
const created = { handler: null, handlerDepth: 0 };
|
|
63
|
+
g[ERROR_STATE_KEY] = created;
|
|
64
|
+
return created;
|
|
65
|
+
}
|
|
66
|
+
function normalizeError(value) {
|
|
67
|
+
if (value instanceof Error) return value;
|
|
68
|
+
const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
|
|
69
|
+
return new Error(message, { cause: value });
|
|
70
|
+
}
|
|
71
|
+
function safeStringify(value) {
|
|
72
|
+
if (typeof value === "symbol") return value.toString();
|
|
73
|
+
try {
|
|
74
|
+
return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
|
|
75
|
+
} catch {
|
|
76
|
+
return Object.prototype.toString.call(value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function describe(context) {
|
|
80
|
+
return context.name ? `${context.phase} "${context.name}"` : context.phase;
|
|
81
|
+
}
|
|
82
|
+
var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
83
|
+
function untrackedRun(fn) {
|
|
84
|
+
const api = globalThis[REACTIVE_REGISTRY_KEY];
|
|
85
|
+
return api?.untracked ? api.untracked(fn) : fn();
|
|
86
|
+
}
|
|
87
|
+
var PROPAGATE_EVENT = "sibu:error-propagate";
|
|
88
|
+
function claimedByBoundary(error, context) {
|
|
89
|
+
const raw = context.node;
|
|
90
|
+
if (!raw || typeof CustomEvent === "undefined") return false;
|
|
91
|
+
const target = resolveEventTarget(raw);
|
|
92
|
+
if (!target) return false;
|
|
93
|
+
try {
|
|
94
|
+
const event = new CustomEvent(PROPAGATE_EVENT, {
|
|
95
|
+
bubbles: true,
|
|
96
|
+
cancelable: true,
|
|
97
|
+
detail: { error, context }
|
|
98
|
+
});
|
|
99
|
+
return target.dispatchEvent(event) === false;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function resolveEventTarget(node) {
|
|
105
|
+
const ELEMENT_NODE = 1;
|
|
106
|
+
let current = node;
|
|
107
|
+
while (current) {
|
|
108
|
+
if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
|
|
109
|
+
return current;
|
|
110
|
+
}
|
|
111
|
+
current = current.parentNode;
|
|
112
|
+
}
|
|
113
|
+
const self = node;
|
|
114
|
+
return typeof self.dispatchEvent === "function" ? self : null;
|
|
115
|
+
}
|
|
116
|
+
function defaultReport(error, context) {
|
|
117
|
+
if (typeof console === "undefined") return;
|
|
118
|
+
console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
|
|
119
|
+
}
|
|
120
|
+
function reportError(error, context) {
|
|
121
|
+
const err = normalizeError(error);
|
|
122
|
+
untrackedRun(() => {
|
|
123
|
+
if (claimedByBoundary(err, context)) return;
|
|
124
|
+
const s = state();
|
|
125
|
+
const handler = s.handler;
|
|
126
|
+
if (handler && s.handlerDepth === 0) {
|
|
127
|
+
s.handlerDepth++;
|
|
128
|
+
try {
|
|
129
|
+
handler(error instanceof Error ? error : err, context);
|
|
130
|
+
return;
|
|
131
|
+
} catch (handlerError) {
|
|
132
|
+
if (typeof console !== "undefined") {
|
|
133
|
+
const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
|
|
134
|
+
console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
|
|
135
|
+
}
|
|
136
|
+
} finally {
|
|
137
|
+
s.handlerDepth--;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
defaultReport(err, context);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
56
144
|
// src/reactivity/track-core.ts
|
|
57
|
-
var _isDev2 = isDev();
|
|
58
145
|
var POOL_MAX = 4096;
|
|
59
146
|
var nodePool = [];
|
|
60
147
|
function createNode() {
|
|
@@ -62,6 +149,7 @@ function createNode() {
|
|
|
62
149
|
sig: null,
|
|
63
150
|
sub: null,
|
|
64
151
|
epoch: 0,
|
|
152
|
+
depVersion: 0,
|
|
65
153
|
sigPrev: null,
|
|
66
154
|
sigNext: null,
|
|
67
155
|
subPrev: null,
|
|
@@ -146,8 +234,27 @@ function safeInvoke(sub) {
|
|
|
146
234
|
try {
|
|
147
235
|
sub();
|
|
148
236
|
} catch (err) {
|
|
149
|
-
|
|
237
|
+
const s = sub;
|
|
238
|
+
reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function depsChanged(sub) {
|
|
242
|
+
let node = sub.depsHead ?? null;
|
|
243
|
+
if (node === null) return true;
|
|
244
|
+
while (node !== null) {
|
|
245
|
+
const sig = node.sig;
|
|
246
|
+
if (sig === null) return true;
|
|
247
|
+
if (sig._d === true && sig._validate !== void 0) {
|
|
248
|
+
try {
|
|
249
|
+
sig._validate();
|
|
250
|
+
} catch {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (node.depVersion !== sig.__v) return true;
|
|
255
|
+
node = node.subNext;
|
|
150
256
|
}
|
|
257
|
+
return false;
|
|
151
258
|
}
|
|
152
259
|
var suspendDepth = 0;
|
|
153
260
|
var trackingSuspended = false;
|
|
@@ -229,7 +336,7 @@ function track(effectFn, subscriber) {
|
|
|
229
336
|
const sub = subscriber;
|
|
230
337
|
return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
|
|
231
338
|
}
|
|
232
|
-
function reactiveBinding(commit) {
|
|
339
|
+
function reactiveBinding(commit, ownerNode) {
|
|
233
340
|
const run = () => {
|
|
234
341
|
const s = subscriber;
|
|
235
342
|
if (s._disposed || s._reentrant) return;
|
|
@@ -245,13 +352,17 @@ function reactiveBinding(commit) {
|
|
|
245
352
|
subscriber.depsTail = null;
|
|
246
353
|
subscriber._epoch = 0;
|
|
247
354
|
subscriber._structDirty = false;
|
|
355
|
+
subscriber._hasComputedDep = false;
|
|
248
356
|
subscriber._runEpoch = 0;
|
|
249
357
|
subscriber._runs = 0;
|
|
250
358
|
subscriber._reentrant = false;
|
|
251
359
|
subscriber._disposed = false;
|
|
360
|
+
subscriber._errorPhase = "binding";
|
|
361
|
+
subscriber._errorNode = ownerNode;
|
|
252
362
|
run();
|
|
253
363
|
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
254
364
|
subscriber._disposed = true;
|
|
365
|
+
subscriber._errorNode = void 0;
|
|
255
366
|
cleanup(subscriber);
|
|
256
367
|
});
|
|
257
368
|
}
|
|
@@ -263,9 +374,12 @@ function recordDependency(signal2) {
|
|
|
263
374
|
const active = sig.__activeNode ?? null;
|
|
264
375
|
if (active !== null && active.sub === sub) {
|
|
265
376
|
active.epoch = epoch;
|
|
377
|
+
active.depVersion = sig.__v ?? Number.NaN;
|
|
266
378
|
return;
|
|
267
379
|
}
|
|
380
|
+
if (sig._validate !== void 0) sub._hasComputedDep = true;
|
|
268
381
|
const node = allocNode(signal2, sub, epoch);
|
|
382
|
+
node.depVersion = sig.__v ?? Number.NaN;
|
|
269
383
|
node.prevActive = active;
|
|
270
384
|
sig.__activeNode = node;
|
|
271
385
|
linkSub(sub, node);
|
|
@@ -284,9 +398,10 @@ function cleanup(subscriber) {
|
|
|
284
398
|
node = next;
|
|
285
399
|
}
|
|
286
400
|
}
|
|
287
|
-
var maxSubscriberRepeats =
|
|
401
|
+
var maxSubscriberRepeats = 1e3;
|
|
288
402
|
var maxDrainIterations = 1e6;
|
|
289
403
|
var drainEpoch = 0;
|
|
404
|
+
var quarantined = /* @__PURE__ */ new Set();
|
|
290
405
|
function setMaxSubscriberRepeats(n) {
|
|
291
406
|
const prev = maxSubscriberRepeats;
|
|
292
407
|
if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
|
|
@@ -308,19 +423,21 @@ function tickRepeat(sub) {
|
|
|
308
423
|
return s._runs > maxSubscriberRepeats;
|
|
309
424
|
}
|
|
310
425
|
function cycleError(sub) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
`
|
|
315
|
-
)
|
|
316
|
-
|
|
426
|
+
const name = sub.__name ?? "<unnamed>";
|
|
427
|
+
reportError(
|
|
428
|
+
new Error(
|
|
429
|
+
`subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. This subscriber is quarantined for the rest of this update; other pending work still runs.`
|
|
430
|
+
),
|
|
431
|
+
{ phase: "scheduler", name }
|
|
432
|
+
);
|
|
317
433
|
}
|
|
318
434
|
function absoluteDrainError() {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
`
|
|
322
|
-
)
|
|
323
|
-
|
|
435
|
+
reportError(
|
|
436
|
+
new Error(
|
|
437
|
+
`Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
|
|
438
|
+
),
|
|
439
|
+
{ phase: "scheduler" }
|
|
440
|
+
);
|
|
324
441
|
}
|
|
325
442
|
function drainQueue() {
|
|
326
443
|
let i = 0;
|
|
@@ -330,11 +447,14 @@ function drainQueue() {
|
|
|
330
447
|
break;
|
|
331
448
|
}
|
|
332
449
|
const sub = pendingQueue[i++];
|
|
450
|
+
pendingSet.delete(sub);
|
|
451
|
+
if (quarantined.size > 0 && quarantined.has(sub)) continue;
|
|
452
|
+
if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
|
|
333
453
|
if (tickRepeat(sub)) {
|
|
334
454
|
cycleError(sub);
|
|
335
|
-
|
|
455
|
+
quarantined.add(sub);
|
|
456
|
+
continue;
|
|
336
457
|
}
|
|
337
|
-
pendingSet.delete(sub);
|
|
338
458
|
safeInvoke(sub);
|
|
339
459
|
}
|
|
340
460
|
}
|
|
@@ -349,6 +469,7 @@ function drainNotificationQueue() {
|
|
|
349
469
|
if (notifyDepth === 0) {
|
|
350
470
|
pendingQueue.length = 0;
|
|
351
471
|
pendingSet.clear();
|
|
472
|
+
if (quarantined.size > 0) quarantined.clear();
|
|
352
473
|
}
|
|
353
474
|
}
|
|
354
475
|
}
|
|
@@ -442,6 +563,7 @@ function notifySubscribers(signal2) {
|
|
|
442
563
|
if (notifyDepth === 0) {
|
|
443
564
|
pendingQueue.length = 0;
|
|
444
565
|
pendingSet.clear();
|
|
566
|
+
if (quarantined.size > 0) quarantined.clear();
|
|
445
567
|
}
|
|
446
568
|
}
|
|
447
569
|
}
|
|
@@ -468,14 +590,14 @@ function forEachSubscriber(signal2, visit) {
|
|
|
468
590
|
}
|
|
469
591
|
|
|
470
592
|
// src/reactivity/track.ts
|
|
471
|
-
var
|
|
472
|
-
var _runtimeVersion = true ? "
|
|
593
|
+
var _isDev2 = isDev();
|
|
594
|
+
var _runtimeVersion = true ? "4.0.0" : "dev";
|
|
473
595
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
474
596
|
function resolveReactiveApi() {
|
|
475
597
|
const g = globalThis;
|
|
476
598
|
const existing = g[REGISTRY_KEY];
|
|
477
599
|
if (existing) {
|
|
478
|
-
if (
|
|
600
|
+
if (_isDev2 && !existing.__dupWarned) {
|
|
479
601
|
existing.__dupWarned = true;
|
|
480
602
|
devWarn(
|
|
481
603
|
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
|
|
@@ -535,20 +657,24 @@ function detectSSRShared() {
|
|
|
535
657
|
const getBuiltin = process.getBuiltinModule;
|
|
536
658
|
if (typeof getBuiltin === "function") {
|
|
537
659
|
mod = getBuiltin("node:async_hooks");
|
|
538
|
-
} else {
|
|
539
|
-
|
|
540
|
-
if (req) mod = req("node:async_hooks");
|
|
660
|
+
} else if (typeof require === "function") {
|
|
661
|
+
mod = require("async_hooks");
|
|
541
662
|
}
|
|
542
663
|
if (mod) detected = new mod.AsyncLocalStorage();
|
|
543
664
|
}
|
|
544
665
|
} catch {
|
|
545
666
|
detected = null;
|
|
546
667
|
}
|
|
547
|
-
return {
|
|
668
|
+
return {
|
|
669
|
+
als: detected,
|
|
670
|
+
fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
|
|
671
|
+
fallbackDepth: 0
|
|
672
|
+
};
|
|
548
673
|
}
|
|
549
674
|
var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
|
|
550
675
|
var als = _shared.als;
|
|
551
676
|
var fallbackStore = _shared.fallbackStore;
|
|
677
|
+
_shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
|
|
552
678
|
function getSSRStore() {
|
|
553
679
|
if (als) {
|
|
554
680
|
const s = als.getStore();
|
|
@@ -571,7 +697,7 @@ function flushUserCleanups(ctx) {
|
|
|
571
697
|
try {
|
|
572
698
|
list[i]();
|
|
573
699
|
} catch (err) {
|
|
574
|
-
|
|
700
|
+
reportError(err, { phase: "cleanup" });
|
|
575
701
|
}
|
|
576
702
|
}
|
|
577
703
|
}
|
|
@@ -584,11 +710,12 @@ function drainReruns(ctx) {
|
|
|
584
710
|
} while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
|
|
585
711
|
if (ctx.rerunPending) {
|
|
586
712
|
ctx.rerunPending = false;
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
`
|
|
590
|
-
)
|
|
591
|
-
|
|
713
|
+
reportError(
|
|
714
|
+
new Error(
|
|
715
|
+
`effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
716
|
+
),
|
|
717
|
+
{ phase: "effect" }
|
|
718
|
+
);
|
|
592
719
|
}
|
|
593
720
|
}
|
|
594
721
|
function disposeEffect(ctx) {
|
|
@@ -665,6 +792,8 @@ function effect(effectFn, options) {
|
|
|
665
792
|
sub.depsTail = null;
|
|
666
793
|
sub._epoch = 0;
|
|
667
794
|
sub._structDirty = false;
|
|
795
|
+
sub._hasComputedDep = false;
|
|
796
|
+
sub._errorPhase = "effect";
|
|
668
797
|
sub._runEpoch = 0;
|
|
669
798
|
sub._runs = 0;
|
|
670
799
|
ctx.subscriber = sub;
|
|
@@ -733,70 +862,72 @@ var isBatching = API2.isBatching;
|
|
|
733
862
|
|
|
734
863
|
// src/core/signals/signal.ts
|
|
735
864
|
var _g2 = globalThis;
|
|
736
|
-
var
|
|
865
|
+
var _isDev3 = isDev();
|
|
737
866
|
function signal(initial, options) {
|
|
738
|
-
const
|
|
867
|
+
const state2 = {
|
|
739
868
|
value: initial,
|
|
740
869
|
__v: 0,
|
|
741
870
|
__sc: 0,
|
|
742
871
|
subsHead: null,
|
|
743
872
|
subsTail: null,
|
|
744
873
|
__activeNode: null,
|
|
745
|
-
__name: void 0
|
|
874
|
+
__name: void 0,
|
|
875
|
+
_d: false,
|
|
876
|
+
_validate: void 0
|
|
746
877
|
};
|
|
747
|
-
const debugName =
|
|
878
|
+
const debugName = _isDev3 ? options?.name : void 0;
|
|
748
879
|
const equalsFn = options?.equals;
|
|
749
|
-
if (debugName)
|
|
880
|
+
if (debugName) state2.__name = debugName;
|
|
750
881
|
function get() {
|
|
751
|
-
recordDependency2(
|
|
752
|
-
return
|
|
882
|
+
recordDependency2(state2);
|
|
883
|
+
return state2.value;
|
|
753
884
|
}
|
|
754
|
-
get.__signal =
|
|
885
|
+
get.__signal = state2;
|
|
755
886
|
if (debugName) get.__name = debugName;
|
|
756
887
|
let set;
|
|
757
888
|
if (equalsFn) {
|
|
758
889
|
set = (next) => {
|
|
759
|
-
const prev =
|
|
890
|
+
const prev = state2.value;
|
|
760
891
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
761
892
|
if (equalsFn(prev, newValue)) return;
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
if (
|
|
893
|
+
state2.value = newValue;
|
|
894
|
+
state2.__v++;
|
|
895
|
+
if (_isDev3) {
|
|
765
896
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
766
|
-
if (hook) hook.emit("signal:update", { signal:
|
|
897
|
+
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
767
898
|
}
|
|
768
|
-
if (!enqueueBatchedSignal(
|
|
769
|
-
notifySubscribers2(
|
|
899
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
900
|
+
notifySubscribers2(state2);
|
|
770
901
|
}
|
|
771
902
|
};
|
|
772
|
-
} else if (
|
|
903
|
+
} else if (_isDev3) {
|
|
773
904
|
set = (next) => {
|
|
774
|
-
const prev =
|
|
905
|
+
const prev = state2.value;
|
|
775
906
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
776
907
|
if (Object.is(newValue, prev)) return;
|
|
777
|
-
|
|
778
|
-
|
|
908
|
+
state2.value = newValue;
|
|
909
|
+
state2.__v++;
|
|
779
910
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
780
|
-
if (hook) hook.emit("signal:update", { signal:
|
|
781
|
-
if (!enqueueBatchedSignal(
|
|
782
|
-
notifySubscribers2(
|
|
911
|
+
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
912
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
913
|
+
notifySubscribers2(state2);
|
|
783
914
|
}
|
|
784
915
|
};
|
|
785
916
|
} else {
|
|
786
917
|
set = (next) => {
|
|
787
|
-
const prev =
|
|
918
|
+
const prev = state2.value;
|
|
788
919
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
789
920
|
if (Object.is(newValue, prev)) return;
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (!enqueueBatchedSignal(
|
|
793
|
-
notifySubscribers2(
|
|
921
|
+
state2.value = newValue;
|
|
922
|
+
state2.__v++;
|
|
923
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
924
|
+
notifySubscribers2(state2);
|
|
794
925
|
}
|
|
795
926
|
};
|
|
796
927
|
}
|
|
797
|
-
if (
|
|
928
|
+
if (_isDev3) {
|
|
798
929
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
799
|
-
if (hook) hook.emit("signal:create", { signal:
|
|
930
|
+
if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
800
931
|
}
|
|
801
932
|
return [get, set];
|
|
802
933
|
}
|
|
@@ -975,6 +1106,21 @@ function derived(getter, options) {
|
|
|
975
1106
|
}, markDirty);
|
|
976
1107
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
977
1108
|
let evaluating = false;
|
|
1109
|
+
const validate = () => {
|
|
1110
|
+
if (!cs._d) return;
|
|
1111
|
+
const oldValue = cs._v;
|
|
1112
|
+
evaluating = true;
|
|
1113
|
+
try {
|
|
1114
|
+
retrack2(recompute, markDirty);
|
|
1115
|
+
if (!Object.is(oldValue, cs._v)) cs.__v++;
|
|
1116
|
+
} finally {
|
|
1117
|
+
evaluating = false;
|
|
1118
|
+
}
|
|
1119
|
+
if (hook && !Object.is(oldValue, cs._v)) {
|
|
1120
|
+
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
cs._validate = validate;
|
|
978
1124
|
function computedGetter() {
|
|
979
1125
|
if (evaluating) {
|
|
980
1126
|
throw new Error(
|
|
@@ -982,32 +1128,11 @@ function derived(getter, options) {
|
|
|
982
1128
|
);
|
|
983
1129
|
}
|
|
984
1130
|
if (isTrackingSuspended2()) {
|
|
985
|
-
if (cs._d)
|
|
986
|
-
const prev = cs._v;
|
|
987
|
-
evaluating = true;
|
|
988
|
-
try {
|
|
989
|
-
retrack2(recompute, markDirty);
|
|
990
|
-
if (!Object.is(prev, cs._v)) cs.__v++;
|
|
991
|
-
} finally {
|
|
992
|
-
evaluating = false;
|
|
993
|
-
}
|
|
994
|
-
}
|
|
1131
|
+
if (cs._d) validate();
|
|
995
1132
|
return cs._v;
|
|
996
1133
|
}
|
|
1134
|
+
if (cs._d) validate();
|
|
997
1135
|
recordDependency2(cs);
|
|
998
|
-
if (cs._d) {
|
|
999
|
-
const oldValue = cs._v;
|
|
1000
|
-
evaluating = true;
|
|
1001
|
-
try {
|
|
1002
|
-
retrack2(recompute, markDirty);
|
|
1003
|
-
if (!Object.is(oldValue, cs._v)) cs.__v++;
|
|
1004
|
-
} finally {
|
|
1005
|
-
evaluating = false;
|
|
1006
|
-
}
|
|
1007
|
-
if (hook && oldValue !== cs._v) {
|
|
1008
|
-
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
1136
|
return cs._v;
|
|
1012
1137
|
}
|
|
1013
1138
|
if (debugName) {
|
|
@@ -1047,9 +1172,9 @@ function zustandAdapter(options) {
|
|
|
1047
1172
|
return createPlugin("sibu-zustand", (ctx) => {
|
|
1048
1173
|
const { store } = options;
|
|
1049
1174
|
const [getState, setSibuState] = signal(store.getState());
|
|
1050
|
-
const unsubscribe = store.subscribe((
|
|
1175
|
+
const unsubscribe = store.subscribe((state2) => {
|
|
1051
1176
|
batch(() => {
|
|
1052
|
-
setSibuState(
|
|
1177
|
+
setSibuState(state2);
|
|
1053
1178
|
});
|
|
1054
1179
|
});
|
|
1055
1180
|
function select(selector) {
|
|
@@ -1078,10 +1203,12 @@ function isEventHandlerAttr(name) {
|
|
|
1078
1203
|
return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
|
|
1079
1204
|
}
|
|
1080
1205
|
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1206
|
+
var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
|
|
1081
1207
|
function sanitizeUrl(url) {
|
|
1082
|
-
const
|
|
1083
|
-
if (!
|
|
1084
|
-
const
|
|
1208
|
+
const probe = stripControlChars(url).trim();
|
|
1209
|
+
if (!probe) return "";
|
|
1210
|
+
const output = url.replace(OUTER_TRIM, "");
|
|
1211
|
+
const lower = probe.toLowerCase();
|
|
1085
1212
|
let schemeEnd = -1;
|
|
1086
1213
|
for (let i = 0; i < lower.length; i++) {
|
|
1087
1214
|
const ch = lower.charCodeAt(i);
|
|
@@ -1091,12 +1218,13 @@ function sanitizeUrl(url) {
|
|
|
1091
1218
|
}
|
|
1092
1219
|
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
1093
1220
|
}
|
|
1094
|
-
if (schemeEnd === -1) return
|
|
1221
|
+
if (schemeEnd === -1) return output;
|
|
1095
1222
|
const scheme = lower.slice(0, schemeEnd + 1);
|
|
1096
|
-
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return
|
|
1223
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output;
|
|
1097
1224
|
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
1098
|
-
return
|
|
1225
|
+
return output;
|
|
1099
1226
|
}
|
|
1227
|
+
var SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
|
|
1100
1228
|
function sanitizeSrcset(value) {
|
|
1101
1229
|
const parts = value.split(",");
|
|
1102
1230
|
const out = [];
|
|
@@ -1105,6 +1233,7 @@ function sanitizeSrcset(value) {
|
|
|
1105
1233
|
if (!part) continue;
|
|
1106
1234
|
const m = part.match(/^(\S+)(\s+.+)?$/);
|
|
1107
1235
|
if (!m) continue;
|
|
1236
|
+
if (m[2] !== void 0 && !SRCSET_DESCRIPTOR.test(m[2])) continue;
|
|
1108
1237
|
const safe = sanitizeUrl(m[1]);
|
|
1109
1238
|
if (!safe) continue;
|
|
1110
1239
|
out.push(m[2] ? `${safe}${m[2]}` : safe);
|
|
@@ -1112,23 +1241,83 @@ function sanitizeSrcset(value) {
|
|
|
1112
1241
|
return out.join(", ");
|
|
1113
1242
|
}
|
|
1114
1243
|
var CSS_DANGER_GATE = /[(:@\\]/;
|
|
1244
|
+
function isCssWhitespace(ch) {
|
|
1245
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
1246
|
+
}
|
|
1247
|
+
function isHexDigit(ch) {
|
|
1248
|
+
return ch >= "0" && ch <= "9" || ch >= "a" && ch <= "f" || ch >= "A" && ch <= "F";
|
|
1249
|
+
}
|
|
1250
|
+
function decodeCssEscapes(value) {
|
|
1251
|
+
let out = "";
|
|
1252
|
+
for (let i = 0; i < value.length; i++) {
|
|
1253
|
+
const ch = value[i];
|
|
1254
|
+
if (ch !== "\\") {
|
|
1255
|
+
out += ch;
|
|
1256
|
+
continue;
|
|
1257
|
+
}
|
|
1258
|
+
if (i + 1 >= value.length) break;
|
|
1259
|
+
const next = value[i + 1];
|
|
1260
|
+
if (next === "\n" || next === "\f") {
|
|
1261
|
+
i += 1;
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
if (next === "\r") {
|
|
1265
|
+
i += value[i + 2] === "\n" ? 2 : 1;
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (isHexDigit(next)) {
|
|
1269
|
+
let hex = "";
|
|
1270
|
+
let j = i + 1;
|
|
1271
|
+
while (j < value.length && hex.length < 6 && isHexDigit(value[j])) {
|
|
1272
|
+
hex += value[j];
|
|
1273
|
+
j++;
|
|
1274
|
+
}
|
|
1275
|
+
if (j < value.length && isCssWhitespace(value[j])) {
|
|
1276
|
+
j += value[j] === "\r" && value[j + 1] === "\n" ? 2 : 1;
|
|
1277
|
+
}
|
|
1278
|
+
const code = Number.parseInt(hex, 16);
|
|
1279
|
+
const invalid = code === 0 || code > 1114111 || code >= 55296 && code <= 57343;
|
|
1280
|
+
out += invalid ? "\uFFFD" : String.fromCodePoint(code);
|
|
1281
|
+
i = j - 1;
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
out += next;
|
|
1285
|
+
i += 1;
|
|
1286
|
+
}
|
|
1287
|
+
return out;
|
|
1288
|
+
}
|
|
1115
1289
|
function sanitizeCSSValue(value) {
|
|
1116
1290
|
if (!CSS_DANGER_GATE.test(value)) return value;
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1119
|
-
if (!Number.isFinite(code) || code < 0 || code > 1114111) return "";
|
|
1120
|
-
try {
|
|
1121
|
-
return String.fromCodePoint(code);
|
|
1122
|
-
} catch {
|
|
1123
|
-
return "";
|
|
1124
|
-
}
|
|
1125
|
-
});
|
|
1126
|
-
const lower = decoded.toLowerCase().replace(/\s+/g, "");
|
|
1291
|
+
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
1292
|
+
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
1127
1293
|
if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
|
|
1128
1294
|
return "";
|
|
1129
1295
|
}
|
|
1130
1296
|
return value;
|
|
1131
1297
|
}
|
|
1298
|
+
function sanitizeStyleAttribute(cssText) {
|
|
1299
|
+
const input = String(cssText);
|
|
1300
|
+
if (input.trim() === "") return "";
|
|
1301
|
+
if (typeof document === "undefined") {
|
|
1302
|
+
return sanitizeCSSValue(input) === "" ? "" : input;
|
|
1303
|
+
}
|
|
1304
|
+
const probe = document.createElement("div");
|
|
1305
|
+
try {
|
|
1306
|
+
probe.style.cssText = input;
|
|
1307
|
+
} catch {
|
|
1308
|
+
return "";
|
|
1309
|
+
}
|
|
1310
|
+
const declarations = [];
|
|
1311
|
+
for (let i = 0; i < probe.style.length; i++) {
|
|
1312
|
+
const property = probe.style[i];
|
|
1313
|
+
const value = probe.style.getPropertyValue(property);
|
|
1314
|
+
if (sanitizeCSSValue(value) === "") continue;
|
|
1315
|
+
if (sanitizeCSSValue(`${property}:${value}`) === "") continue;
|
|
1316
|
+
const priority = probe.style.getPropertyPriority(property);
|
|
1317
|
+
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
1318
|
+
}
|
|
1319
|
+
return declarations.join("; ");
|
|
1320
|
+
}
|
|
1132
1321
|
var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
1133
1322
|
"href",
|
|
1134
1323
|
"xlink:href",
|
|
@@ -1141,26 +1330,104 @@ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
|
1141
1330
|
"background",
|
|
1142
1331
|
"srcset",
|
|
1143
1332
|
"ping",
|
|
1144
|
-
"data"
|
|
1333
|
+
"data",
|
|
1334
|
+
// `<html manifest>` is a URL sink too. It was carried only by the SSR
|
|
1335
|
+
// serializers' private copy of this set; folding that copy into this one would
|
|
1336
|
+
// otherwise have silently dropped its coverage.
|
|
1337
|
+
"manifest"
|
|
1145
1338
|
]);
|
|
1339
|
+
var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
1340
|
+
function isHtmlContentAttribute(name) {
|
|
1341
|
+
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
1342
|
+
}
|
|
1146
1343
|
function sanitizeAttributeString(attr, value) {
|
|
1147
1344
|
const lower = attr.toLowerCase();
|
|
1148
1345
|
if (lower === "srcset") return sanitizeSrcset(value);
|
|
1149
1346
|
if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
|
|
1347
|
+
if (lower === "style") return sanitizeStyleAttribute(value);
|
|
1150
1348
|
return value;
|
|
1151
1349
|
}
|
|
1152
1350
|
|
|
1153
|
-
// src/
|
|
1154
|
-
var
|
|
1351
|
+
// src/utils/setSafeAttribute.ts
|
|
1352
|
+
var _isDev4 = isDev();
|
|
1353
|
+
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
1354
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1355
|
+
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
1356
|
+
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
1357
|
+
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
1358
|
+
function isHtmlElement(el) {
|
|
1359
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS;
|
|
1360
|
+
}
|
|
1155
1361
|
function setProp(el, key, val) {
|
|
1156
1362
|
el[key] = val;
|
|
1157
1363
|
}
|
|
1158
|
-
function
|
|
1159
|
-
if (
|
|
1160
|
-
|
|
1364
|
+
function namespaceFor(el, name) {
|
|
1365
|
+
if (el.namespaceURI !== SVG_NS) return null;
|
|
1366
|
+
const lower = name.toLowerCase();
|
|
1367
|
+
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
1368
|
+
if (lower.startsWith("xml:")) return XML_NS;
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
function setSafeAttribute(el, name, value, options = {}) {
|
|
1372
|
+
const ns = namespaceFor(el, name);
|
|
1373
|
+
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
1374
|
+
if (isEventHandlerAttr(name)) {
|
|
1375
|
+
if (_isDev4) {
|
|
1376
|
+
devWarn(
|
|
1377
|
+
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
1381
|
+
else el.removeAttribute(name);
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
if (value == null) {
|
|
1385
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
1386
|
+
else el.removeAttribute(name);
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
if (isHtmlContentAttribute(name)) {
|
|
1390
|
+
if (_isDev4) {
|
|
1161
1391
|
devWarn(
|
|
1162
|
-
|
|
1392
|
+
`${options.label ?? "setSafeAttribute"}: refusing to set "${name}". The browser parses this attribute as a nested HTML document, so a generic string value cannot be made safe \u2014 attribute escaping is undone before the parse. Build the frame's content another way.`
|
|
1163
1393
|
);
|
|
1394
|
+
}
|
|
1395
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
1396
|
+
else el.removeAttribute(name);
|
|
1397
|
+
return false;
|
|
1398
|
+
}
|
|
1399
|
+
const html = isHtmlElement(el);
|
|
1400
|
+
const idlName = html ? name.toLowerCase() : name;
|
|
1401
|
+
if (typeof value === "boolean") {
|
|
1402
|
+
if (html && BOOLEAN_IDL_ATTRS.has(idlName) && idlName in el) {
|
|
1403
|
+
setProp(el, idlName, value);
|
|
1404
|
+
} else if (value) {
|
|
1405
|
+
if (ns) el.setAttributeNS(ns, name, "");
|
|
1406
|
+
else el.setAttribute(name, "");
|
|
1407
|
+
} else if (ns) {
|
|
1408
|
+
el.removeAttributeNS(ns, localName);
|
|
1409
|
+
} else {
|
|
1410
|
+
el.removeAttribute(name);
|
|
1411
|
+
}
|
|
1412
|
+
return true;
|
|
1413
|
+
}
|
|
1414
|
+
const str = String(value);
|
|
1415
|
+
if (options.syncValueProperty !== false && html && (idlName === "value" || idlName === "checked") && idlName in el) {
|
|
1416
|
+
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
1417
|
+
return true;
|
|
1418
|
+
}
|
|
1419
|
+
const safe = sanitizeAttributeString(name, str);
|
|
1420
|
+
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1421
|
+
if (current === safe) return true;
|
|
1422
|
+
if (ns) el.setAttributeNS(ns, name, safe);
|
|
1423
|
+
else el.setAttribute(name, safe);
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// src/reactivity/bindAttribute.ts
|
|
1428
|
+
function bindAttribute(el, attr, getter) {
|
|
1429
|
+
if (isEventHandlerAttr(attr)) {
|
|
1430
|
+
setSafeAttribute(el, attr, "", { label: `bindAttribute("${attr}")` });
|
|
1164
1431
|
return () => {
|
|
1165
1432
|
};
|
|
1166
1433
|
}
|
|
@@ -1169,33 +1436,25 @@ function bindAttribute(el, attr, getter) {
|
|
|
1169
1436
|
try {
|
|
1170
1437
|
value = getter();
|
|
1171
1438
|
} catch (err) {
|
|
1172
|
-
|
|
1173
|
-
devWarn(`bindAttribute: getter for "${attr}" threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
if (typeof value === "boolean") {
|
|
1177
|
-
if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
|
|
1178
|
-
setProp(el, attr, value);
|
|
1179
|
-
} else if (value) {
|
|
1180
|
-
el.setAttribute(attr, "");
|
|
1181
|
-
} else {
|
|
1182
|
-
el.removeAttribute(attr);
|
|
1183
|
-
}
|
|
1439
|
+
reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
|
|
1184
1440
|
return;
|
|
1185
1441
|
}
|
|
1186
|
-
|
|
1187
|
-
if ((attr === "value" || attr === "checked") && attr in el) {
|
|
1188
|
-
setProp(el, attr, attr === "checked" ? Boolean(value) : str);
|
|
1189
|
-
} else {
|
|
1190
|
-
el.setAttribute(attr, sanitizeAttributeString(attr, str));
|
|
1191
|
-
}
|
|
1442
|
+
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")` });
|
|
1192
1443
|
}
|
|
1193
|
-
return reactiveBinding2(commit);
|
|
1444
|
+
return reactiveBinding2(commit, el);
|
|
1194
1445
|
}
|
|
1195
1446
|
|
|
1196
1447
|
// src/core/rendering/dispose.ts
|
|
1197
1448
|
var elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
1198
|
-
var
|
|
1449
|
+
var MAX_DRAIN_TEARDOWNS = 1e4;
|
|
1450
|
+
function reportDrainRunaway(label, executed, remaining) {
|
|
1451
|
+
if (typeof console === "undefined") return;
|
|
1452
|
+
console.error(
|
|
1453
|
+
`[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
|
|
1454
|
+
{ executed, remaining }
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
var _isDev5 = isDev();
|
|
1199
1458
|
var activeBindingCount = 0;
|
|
1200
1459
|
function registerDisposer(node, teardown) {
|
|
1201
1460
|
let disposers = elementDisposers.get(node);
|
|
@@ -1204,7 +1463,7 @@ function registerDisposer(node, teardown) {
|
|
|
1204
1463
|
elementDisposers.set(node, disposers);
|
|
1205
1464
|
}
|
|
1206
1465
|
disposers.push(teardown);
|
|
1207
|
-
if (
|
|
1466
|
+
if (_isDev5) activeBindingCount++;
|
|
1208
1467
|
}
|
|
1209
1468
|
function dispose(node) {
|
|
1210
1469
|
const stack = [node];
|
|
@@ -1219,34 +1478,30 @@ function dispose(node) {
|
|
|
1219
1478
|
}
|
|
1220
1479
|
for (let i = order.length - 1; i >= 0; i--) {
|
|
1221
1480
|
const current = order[i];
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
d();
|
|
1230
|
-
} catch (err) {
|
|
1231
|
-
if (_isDev6 && typeof console !== "undefined") {
|
|
1232
|
-
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
let extraPasses = 0;
|
|
1237
|
-
while (extraPasses++ < 8) {
|
|
1238
|
-
const added = elementDisposers.get(current);
|
|
1239
|
-
if (!added || added.length === 0) break;
|
|
1240
|
-
const moreSnapshot = added.slice();
|
|
1481
|
+
if (elementDisposers.has(current)) {
|
|
1482
|
+
let executed = 0;
|
|
1483
|
+
let runaway = false;
|
|
1484
|
+
while (!runaway) {
|
|
1485
|
+
const pending = elementDisposers.get(current);
|
|
1486
|
+
if (!pending || pending.length === 0) break;
|
|
1487
|
+
const snapshot = pending.slice();
|
|
1241
1488
|
elementDisposers.delete(current);
|
|
1242
|
-
if (
|
|
1243
|
-
for (
|
|
1489
|
+
if (_isDev5) activeBindingCount -= snapshot.length;
|
|
1490
|
+
for (let i2 = 0; i2 < snapshot.length; i2++) {
|
|
1491
|
+
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
1492
|
+
const rest = snapshot.slice(i2);
|
|
1493
|
+
const added = elementDisposers.get(current);
|
|
1494
|
+
elementDisposers.set(current, added ? rest.concat(added) : rest);
|
|
1495
|
+
if (_isDev5) activeBindingCount += rest.length;
|
|
1496
|
+
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
1497
|
+
runaway = true;
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1500
|
+
executed++;
|
|
1244
1501
|
try {
|
|
1245
|
-
|
|
1502
|
+
snapshot[i2]();
|
|
1246
1503
|
} catch (err) {
|
|
1247
|
-
|
|
1248
|
-
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1249
|
-
}
|
|
1504
|
+
reportError(err, { phase: "cleanup", name: "disposer" });
|
|
1250
1505
|
}
|
|
1251
1506
|
}
|
|
1252
1507
|
}
|
|
@@ -1255,7 +1510,7 @@ function dispose(node) {
|
|
|
1255
1510
|
}
|
|
1256
1511
|
|
|
1257
1512
|
// src/reactivity/bindChildNode.ts
|
|
1258
|
-
var
|
|
1513
|
+
var _isDev6 = isDev();
|
|
1259
1514
|
function bindChildNode(placeholder, getter) {
|
|
1260
1515
|
let lastNodes = [];
|
|
1261
1516
|
function commit() {
|
|
@@ -1263,7 +1518,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1263
1518
|
try {
|
|
1264
1519
|
result = getter();
|
|
1265
1520
|
} catch (err) {
|
|
1266
|
-
|
|
1521
|
+
reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
|
|
1267
1522
|
return;
|
|
1268
1523
|
}
|
|
1269
1524
|
if (result == null || typeof result === "boolean") {
|
|
@@ -1289,7 +1544,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
1289
1544
|
if (item == null || typeof item === "boolean") continue;
|
|
1290
1545
|
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1291
1546
|
if (seen.has(node)) {
|
|
1292
|
-
if (
|
|
1547
|
+
if (_isDev6)
|
|
1293
1548
|
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1294
1549
|
continue;
|
|
1295
1550
|
}
|
|
@@ -1324,11 +1579,11 @@ function bindChildNode(placeholder, getter) {
|
|
|
1324
1579
|
}
|
|
1325
1580
|
lastNodes = newNodes;
|
|
1326
1581
|
}
|
|
1327
|
-
return reactiveBinding2(commit);
|
|
1582
|
+
return reactiveBinding2(commit, placeholder);
|
|
1328
1583
|
}
|
|
1329
1584
|
|
|
1330
1585
|
// src/core/rendering/tagFactory.ts
|
|
1331
|
-
var
|
|
1586
|
+
var _isDev7 = isDev();
|
|
1332
1587
|
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1333
1588
|
function isBlockedTag(tag) {
|
|
1334
1589
|
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
@@ -1346,9 +1601,6 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
|
1346
1601
|
"self",
|
|
1347
1602
|
"frames"
|
|
1348
1603
|
]);
|
|
1349
|
-
function setProp2(el, key, val) {
|
|
1350
|
-
el[key] = val;
|
|
1351
|
-
}
|
|
1352
1604
|
function looksLikeClassList(s) {
|
|
1353
1605
|
const t = s.trim();
|
|
1354
1606
|
if (!t) return false;
|
|
@@ -1372,13 +1624,13 @@ function toKebab(prop) {
|
|
|
1372
1624
|
function applyStyle(el, style) {
|
|
1373
1625
|
if (typeof style === "function") {
|
|
1374
1626
|
const teardown = track2(() => {
|
|
1375
|
-
el.setAttribute("style", style());
|
|
1627
|
+
el.setAttribute("style", sanitizeStyleAttribute(String(style())));
|
|
1376
1628
|
});
|
|
1377
1629
|
registerDisposer(el, teardown);
|
|
1378
1630
|
return;
|
|
1379
1631
|
}
|
|
1380
1632
|
if (typeof style === "string") {
|
|
1381
|
-
el.setAttribute("style", style);
|
|
1633
|
+
el.setAttribute("style", sanitizeStyleAttribute(style));
|
|
1382
1634
|
return;
|
|
1383
1635
|
}
|
|
1384
1636
|
const htmlEl = el;
|
|
@@ -1499,7 +1751,7 @@ var tagFactory = (tag, ns) => {
|
|
|
1499
1751
|
appendChildren(el, second);
|
|
1500
1752
|
return el;
|
|
1501
1753
|
}
|
|
1502
|
-
if (
|
|
1754
|
+
if (_isDev7 && looksLikeClassList(first)) {
|
|
1503
1755
|
devWarn(
|
|
1504
1756
|
`tagFactory: lone string "${first}" looks like a class list but is being rendered as TEXT. For a class, use ${tag}({ class: "${first}" }) \u2014 or ${tag}("${first}", children) to set the class AND add children.`
|
|
1505
1757
|
);
|
|
@@ -1520,7 +1772,7 @@ var tagFactory = (tag, ns) => {
|
|
|
1520
1772
|
if (pClass != null) applyClass(el, pClass);
|
|
1521
1773
|
const pId = props.id;
|
|
1522
1774
|
if (pId != null) {
|
|
1523
|
-
if (
|
|
1775
|
+
if (_isDev7 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
1524
1776
|
devWarn(
|
|
1525
1777
|
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
1526
1778
|
);
|
|
@@ -1535,7 +1787,7 @@ var tagFactory = (tag, ns) => {
|
|
|
1535
1787
|
const handler = pOn[ev];
|
|
1536
1788
|
if (typeof handler === "function") {
|
|
1537
1789
|
el.addEventListener(ev, handler);
|
|
1538
|
-
} else if (
|
|
1790
|
+
} else if (_isDev7) {
|
|
1539
1791
|
devWarn(
|
|
1540
1792
|
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
1541
1793
|
);
|
|
@@ -1563,16 +1815,8 @@ var tagFactory = (tag, ns) => {
|
|
|
1563
1815
|
if (isEventHandlerAttr(key)) continue;
|
|
1564
1816
|
if (typeof value === "function") {
|
|
1565
1817
|
registerDisposer(el, bindAttribute(el, key, value));
|
|
1566
|
-
} else if (typeof value === "boolean") {
|
|
1567
|
-
if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
|
|
1568
|
-
setProp2(el, key, value);
|
|
1569
|
-
} else if (value) {
|
|
1570
|
-
el.setAttribute(key, "");
|
|
1571
|
-
} else {
|
|
1572
|
-
el.removeAttribute(key);
|
|
1573
|
-
}
|
|
1574
1818
|
} else {
|
|
1575
|
-
el
|
|
1819
|
+
setSafeAttribute(el, key, value, { syncValueProperty: false, label: "tagFactory" });
|
|
1576
1820
|
}
|
|
1577
1821
|
}
|
|
1578
1822
|
}
|