@wcstack/state 1.21.1 → 1.21.3
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/dist/index.esm.js +106 -54
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -3332,6 +3332,38 @@ let nextRecordId = 0;
|
|
|
3332
3332
|
let nextGeneration = 0;
|
|
3333
3333
|
const recordByBinding = new WeakMap();
|
|
3334
3334
|
const sessionByRoot = new WeakMap();
|
|
3335
|
+
// node → その node に関心を持つ session(anchor として binding を覚えている、
|
|
3336
|
+
// または定義待ちタスクを抱えている)。BindingOwner は mutation で増減した
|
|
3337
|
+
// サブツリーを1回だけ走査し、ここに登録された session だけへ per-node 配送する。
|
|
3338
|
+
// 全 session ブロードキャストだと、リスト行の逐次 append などで
|
|
3339
|
+
// 「session 数 × 変異ノード数」の O(n²) ファンアウトになるため、その正本台帳。
|
|
3340
|
+
// 大多数の node は関心 session が1つなので単一値で持ち、2つ目から Set に昇格する。
|
|
3341
|
+
const interestedSessionsByNode = new WeakMap();
|
|
3342
|
+
function addInterestedSession(node, session) {
|
|
3343
|
+
const current = interestedSessionsByNode.get(node);
|
|
3344
|
+
if (typeof current === "undefined") {
|
|
3345
|
+
interestedSessionsByNode.set(node, session);
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
if (current === session)
|
|
3349
|
+
return;
|
|
3350
|
+
if (current instanceof Set) {
|
|
3351
|
+
current.add(session);
|
|
3352
|
+
return;
|
|
3353
|
+
}
|
|
3354
|
+
interestedSessionsByNode.set(node, new Set([current, session]));
|
|
3355
|
+
}
|
|
3356
|
+
function forEachInterestedSession(node, callback) {
|
|
3357
|
+
const current = interestedSessionsByNode.get(node);
|
|
3358
|
+
if (typeof current === "undefined")
|
|
3359
|
+
return;
|
|
3360
|
+
if (current instanceof Set) {
|
|
3361
|
+
for (const session of Array.from(current))
|
|
3362
|
+
callback(session);
|
|
3363
|
+
return;
|
|
3364
|
+
}
|
|
3365
|
+
callback(current);
|
|
3366
|
+
}
|
|
3335
3367
|
function forEachInclusive(root, callback) {
|
|
3336
3368
|
callback(root);
|
|
3337
3369
|
for (const child of Array.from(root.childNodes)) {
|
|
@@ -3350,8 +3382,6 @@ function observableRootFor(node) {
|
|
|
3350
3382
|
}
|
|
3351
3383
|
class BindingOwner {
|
|
3352
3384
|
root;
|
|
3353
|
-
sessionRefs = new Set();
|
|
3354
|
-
knownSessions = new WeakSet();
|
|
3355
3385
|
observer;
|
|
3356
3386
|
constructor(root) {
|
|
3357
3387
|
this.root = root;
|
|
@@ -3361,12 +3391,6 @@ class BindingOwner {
|
|
|
3361
3391
|
: null;
|
|
3362
3392
|
this.observer?.observe(root, { childList: true, subtree: true });
|
|
3363
3393
|
}
|
|
3364
|
-
add(session) {
|
|
3365
|
-
if (this.knownSessions.has(session))
|
|
3366
|
-
return;
|
|
3367
|
-
this.knownSessions.add(session);
|
|
3368
|
-
this.sessionRefs.add(new WeakRef(session));
|
|
3369
|
-
}
|
|
3370
3394
|
handleMutations(mutations) {
|
|
3371
3395
|
const removed = [];
|
|
3372
3396
|
const added = [];
|
|
@@ -3374,14 +3398,29 @@ class BindingOwner {
|
|
|
3374
3398
|
removed.push(...Array.from(mutation.removedNodes));
|
|
3375
3399
|
added.push(...Array.from(mutation.addedNodes));
|
|
3376
3400
|
}
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3401
|
+
// 走査は owner が1回だけ行い、関心 session が居る node だけを配送・contains
|
|
3402
|
+
// 検査へ進める。contains は O(木の深さ) なので、関心の無い node で呼ばない。
|
|
3403
|
+
const reconnected = [];
|
|
3404
|
+
for (const subtree of removed) {
|
|
3405
|
+
forEachInclusive(subtree, (node) => {
|
|
3406
|
+
forEachInterestedSession(node, (session) => {
|
|
3407
|
+
if (this.root.contains(node))
|
|
3408
|
+
return;
|
|
3409
|
+
session.handleRemovedNode(node);
|
|
3410
|
+
});
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
for (const subtree of added) {
|
|
3414
|
+
forEachInclusive(subtree, (node) => {
|
|
3415
|
+
forEachInterestedSession(node, (session) => {
|
|
3416
|
+
if (!this.root.contains(node))
|
|
3417
|
+
return;
|
|
3418
|
+
session.handleAddedNode(node, reconnected);
|
|
3419
|
+
});
|
|
3420
|
+
});
|
|
3384
3421
|
}
|
|
3422
|
+
if (reconnected.length > 0)
|
|
3423
|
+
applyChangeFromBindings(reconnected);
|
|
3385
3424
|
}
|
|
3386
3425
|
}
|
|
3387
3426
|
const ownerByRoot = new WeakMap();
|
|
@@ -3477,6 +3516,7 @@ class BindingSession {
|
|
|
3477
3516
|
raiseError(`CustomElementRegistry is unavailable for <${tagName}>.`);
|
|
3478
3517
|
}
|
|
3479
3518
|
this.observe(node);
|
|
3519
|
+
addInterestedSession(node, this);
|
|
3480
3520
|
const task = { node, active: true, cancel: null };
|
|
3481
3521
|
let tasks = this.deferredByNode.get(node);
|
|
3482
3522
|
if (typeof tasks === "undefined") {
|
|
@@ -3534,27 +3574,17 @@ class BindingSession {
|
|
|
3534
3574
|
const root = observableRootFor(node);
|
|
3535
3575
|
if (root === null)
|
|
3536
3576
|
return;
|
|
3537
|
-
|
|
3577
|
+
// owner(root ごとの MutationObserver)の存在だけ保証する。session の配送先
|
|
3578
|
+
// 登録は node 単位(interestedSessionsByNode)で行い、owner は session を
|
|
3579
|
+
// 直接は保持しない。
|
|
3580
|
+
getBindingOwner(root);
|
|
3538
3581
|
}
|
|
3539
3582
|
handleMutations(root, removed, added) {
|
|
3540
3583
|
for (const subtree of removed) {
|
|
3541
3584
|
forEachInclusive(subtree, (node) => {
|
|
3542
3585
|
if (root.contains(node))
|
|
3543
3586
|
return;
|
|
3544
|
-
|
|
3545
|
-
if (typeof known !== "undefined") {
|
|
3546
|
-
for (const binding of known.values())
|
|
3547
|
-
this.disposeBinding(binding);
|
|
3548
|
-
}
|
|
3549
|
-
const tasks = this.deferredByNode.get(node);
|
|
3550
|
-
if (typeof tasks !== "undefined") {
|
|
3551
|
-
for (const task of Array.from(tasks)) {
|
|
3552
|
-
task.active = false;
|
|
3553
|
-
task.cancel?.();
|
|
3554
|
-
tasks.delete(task);
|
|
3555
|
-
this.deferred.delete(task);
|
|
3556
|
-
}
|
|
3557
|
-
}
|
|
3587
|
+
this.handleRemovedNode(node);
|
|
3558
3588
|
});
|
|
3559
3589
|
}
|
|
3560
3590
|
const reconnected = [];
|
|
@@ -3562,36 +3592,58 @@ class BindingSession {
|
|
|
3562
3592
|
forEachInclusive(subtree, (node) => {
|
|
3563
3593
|
if (!root.contains(node))
|
|
3564
3594
|
return;
|
|
3565
|
-
|
|
3566
|
-
if (typeof known === "undefined")
|
|
3567
|
-
return;
|
|
3568
|
-
for (const binding of known.values()) {
|
|
3569
|
-
const record = recordByBinding.get(binding);
|
|
3570
|
-
if (record?.phase === "active") {
|
|
3571
|
-
this.settleConnectedSnapshot(record);
|
|
3572
|
-
continue;
|
|
3573
|
-
}
|
|
3574
|
-
if (record?.phase !== "disposed")
|
|
3575
|
-
continue;
|
|
3576
|
-
const options = this.optionsByBinding.get(binding);
|
|
3577
|
-
if (typeof options === "undefined")
|
|
3578
|
-
continue;
|
|
3579
|
-
try {
|
|
3580
|
-
this.start(binding, options);
|
|
3581
|
-
if (options.applyOnReconnect && this.shouldApplyState(binding))
|
|
3582
|
-
reconnected.push(binding);
|
|
3583
|
-
}
|
|
3584
|
-
catch {
|
|
3585
|
-
// Mutation delivery cannot surface initialization errors to a caller.
|
|
3586
|
-
}
|
|
3587
|
-
}
|
|
3595
|
+
this.handleAddedNode(node, reconnected);
|
|
3588
3596
|
});
|
|
3589
3597
|
}
|
|
3590
3598
|
if (reconnected.length > 0)
|
|
3591
3599
|
applyChangeFromBindings(reconnected);
|
|
3592
3600
|
}
|
|
3601
|
+
handleRemovedNode(node) {
|
|
3602
|
+
const known = this.knownBindingsByNode.get(node);
|
|
3603
|
+
if (typeof known !== "undefined") {
|
|
3604
|
+
for (const binding of known.values())
|
|
3605
|
+
this.disposeBinding(binding);
|
|
3606
|
+
}
|
|
3607
|
+
const tasks = this.deferredByNode.get(node);
|
|
3608
|
+
if (typeof tasks !== "undefined") {
|
|
3609
|
+
for (const task of Array.from(tasks)) {
|
|
3610
|
+
task.active = false;
|
|
3611
|
+
task.cancel?.();
|
|
3612
|
+
tasks.delete(task);
|
|
3613
|
+
this.deferred.delete(task);
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
handleAddedNode(node, reconnected) {
|
|
3618
|
+
const known = this.knownBindingsByNode.get(node);
|
|
3619
|
+
if (typeof known === "undefined")
|
|
3620
|
+
return;
|
|
3621
|
+
for (const binding of known.values()) {
|
|
3622
|
+
const record = recordByBinding.get(binding);
|
|
3623
|
+
if (record?.phase === "active") {
|
|
3624
|
+
this.settleConnectedSnapshot(record);
|
|
3625
|
+
continue;
|
|
3626
|
+
}
|
|
3627
|
+
if (record?.phase !== "disposed")
|
|
3628
|
+
continue;
|
|
3629
|
+
const options = this.optionsByBinding.get(binding);
|
|
3630
|
+
if (typeof options === "undefined")
|
|
3631
|
+
continue;
|
|
3632
|
+
try {
|
|
3633
|
+
this.start(binding, options);
|
|
3634
|
+
if (options.applyOnReconnect && this.shouldApplyState(binding))
|
|
3635
|
+
reconnected.push(binding);
|
|
3636
|
+
}
|
|
3637
|
+
catch {
|
|
3638
|
+
// Mutation delivery cannot surface initialization errors to a caller.
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3593
3642
|
remember(binding, options) {
|
|
3594
3643
|
const anchor = binding.replaceNode;
|
|
3644
|
+
// detached fragment 上でも登録しておく(node 単位の台帳なので root 非依存)。
|
|
3645
|
+
// fragment 一括マウントで後から接続された行にも mutation 配送が届くようにする。
|
|
3646
|
+
addInterestedSession(anchor, this);
|
|
3595
3647
|
let known = this.knownBindingsByNode.get(anchor);
|
|
3596
3648
|
if (typeof known === "undefined") {
|
|
3597
3649
|
known = new Map();
|
|
@@ -6058,7 +6110,7 @@ async function buildBindings(root) {
|
|
|
6058
6110
|
}
|
|
6059
6111
|
}
|
|
6060
6112
|
|
|
6061
|
-
var version = "1.21.
|
|
6113
|
+
var version = "1.21.3";
|
|
6062
6114
|
var pkg = {
|
|
6063
6115
|
version: version};
|
|
6064
6116
|
|