@askrjs/askr 0.0.1 → 0.0.2
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/README.md +18 -10
- package/dist/chunk-KR6HG7HF.js +38 -0
- package/dist/chunk-KR6HG7HF.js.map +1 -0
- package/dist/{chunk-L7RL4LYV.js → chunk-MIPES65F.js} +1486 -1905
- package/dist/chunk-MIPES65F.js.map +1 -0
- package/dist/{chunk-HIWJVOS4.js → chunk-PFOLLB6A.js} +38 -17
- package/dist/chunk-PFOLLB6A.js.map +1 -0
- package/dist/chunk-QECQ2TF6.js +28 -0
- package/dist/chunk-QECQ2TF6.js.map +1 -0
- package/dist/{chunk-UUM5W2RM.js → chunk-RJWOOUYV.js} +2 -2
- package/dist/chunk-RJWOOUYV.js.map +1 -0
- package/dist/index.cjs +1760 -1972
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -40
- package/dist/index.d.ts +52 -40
- package/dist/index.js +226 -52
- package/dist/index.js.map +1 -1
- package/dist/jsx/jsx-dev-runtime.cjs +9 -3
- package/dist/jsx/jsx-dev-runtime.cjs.map +1 -1
- package/dist/jsx/jsx-dev-runtime.d.cts +4 -9
- package/dist/jsx/jsx-dev-runtime.d.ts +4 -9
- package/dist/jsx/jsx-dev-runtime.js +10 -4
- package/dist/jsx/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx/jsx-runtime.cjs +14 -5
- package/dist/jsx/jsx-runtime.cjs.map +1 -1
- package/dist/jsx/jsx-runtime.d.cts +9 -6
- package/dist/jsx/jsx-runtime.d.ts +9 -6
- package/dist/jsx/jsx-runtime.js +6 -2
- package/dist/{navigate-NLQOZQGM.js → navigate-SDZNA2ZE.js} +5 -5
- package/dist/{route-TVYWYCEJ.js → route-P5YQBT4T.js} +4 -4
- package/dist/{ssr-4ELUFK65.js → ssr-65K3IJ6B.js} +9 -5
- package/dist/{types-DUDmnzD8.d.cts → types-DLTViI21.d.cts} +15 -3
- package/dist/{types-DUDmnzD8.d.ts → types-DLTViI21.d.ts} +15 -3
- package/package.json +5 -3
- package/src/jsx/index.ts +4 -0
- package/src/jsx/jsx-dev-runtime.ts +7 -10
- package/src/jsx/jsx-runtime.ts +23 -11
- package/src/jsx/types.ts +22 -3
- package/src/jsx/utils.ts +19 -0
- package/dist/chunk-4CV4JOE5.js +0 -27
- package/dist/chunk-HIWJVOS4.js.map +0 -1
- package/dist/chunk-L7RL4LYV.js.map +0 -1
- package/dist/chunk-UUM5W2RM.js.map +0 -1
- package/dist/chunk-YNH3D4KW.js +0 -29
- package/dist/chunk-YNH3D4KW.js.map +0 -1
- package/dist/ssr-4ELUFK65.js.map +0 -1
- package/src/jsx/react-jsx-runtime.d.ts +0 -0
- /package/dist/{chunk-4CV4JOE5.js.map → navigate-SDZNA2ZE.js.map} +0 -0
- /package/dist/{navigate-NLQOZQGM.js.map → route-P5YQBT4T.js.map} +0 -0
- /package/dist/{route-TVYWYCEJ.js.map → ssr-65K3IJ6B.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -136,9 +136,9 @@ var init_scheduler = __esm({
|
|
|
136
136
|
// Keep a lightweight taskCount for compatibility/diagnostics
|
|
137
137
|
this.taskCount = 0;
|
|
138
138
|
}
|
|
139
|
-
enqueue(
|
|
139
|
+
enqueue(task2) {
|
|
140
140
|
assertSchedulingPrecondition(
|
|
141
|
-
typeof
|
|
141
|
+
typeof task2 === "function",
|
|
142
142
|
"enqueue() requires a function"
|
|
143
143
|
);
|
|
144
144
|
if (isBulkCommitActive() && !this.allowSyncProgress) {
|
|
@@ -149,7 +149,7 @@ var init_scheduler = __esm({
|
|
|
149
149
|
}
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
|
-
this.q.push(
|
|
152
|
+
this.q.push(task2);
|
|
153
153
|
this.taskCount++;
|
|
154
154
|
if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
|
|
155
155
|
this.kickScheduled = true;
|
|
@@ -190,10 +190,10 @@ var init_scheduler = __esm({
|
|
|
190
190
|
`[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
|
|
191
191
|
);
|
|
192
192
|
}
|
|
193
|
-
const
|
|
193
|
+
const task2 = this.q[this.head++];
|
|
194
194
|
try {
|
|
195
195
|
this.executionDepth++;
|
|
196
|
-
|
|
196
|
+
task2();
|
|
197
197
|
this.executionDepth--;
|
|
198
198
|
} catch (err) {
|
|
199
199
|
if (this.executionDepth > 0) this.executionDepth = 0;
|
|
@@ -279,17 +279,14 @@ var init_scheduler = __esm({
|
|
|
279
279
|
if (this.flushVersion >= target) return Promise.resolve();
|
|
280
280
|
return new Promise((resolve, reject) => {
|
|
281
281
|
const timer = setTimeout(() => {
|
|
282
|
+
const ns = globalThis.__ASKR__ || {};
|
|
282
283
|
const diag = {
|
|
283
284
|
flushVersion: this.flushVersion,
|
|
284
285
|
queueLen: this.q.length - this.head,
|
|
285
286
|
running: this.running,
|
|
286
287
|
inHandler: this.inHandler,
|
|
287
288
|
bulk: isBulkCommitActive(),
|
|
288
|
-
|
|
289
|
-
__ASKR_LAST_FASTPATH_STATS: globalThis.__ASKR_LAST_FASTPATH_STATS,
|
|
290
|
-
__ASKR_LAST_BULK_TEXT_FASTPATH_STATS: globalThis.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS,
|
|
291
|
-
__ASKR_FASTPATH_COUNTERS: globalThis.__ASKR_FASTPATH_COUNTERS
|
|
292
|
-
}
|
|
289
|
+
namespace: ns
|
|
293
290
|
};
|
|
294
291
|
reject(
|
|
295
292
|
new Error(
|
|
@@ -366,267 +363,6 @@ var init_scheduler = __esm({
|
|
|
366
363
|
}
|
|
367
364
|
});
|
|
368
365
|
|
|
369
|
-
// src/runtime/fastlane.ts
|
|
370
|
-
function enterBulkCommit() {
|
|
371
|
-
_bulkCommitActive = true;
|
|
372
|
-
_appliedParents = /* @__PURE__ */ new WeakSet();
|
|
373
|
-
try {
|
|
374
|
-
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
375
|
-
if (process.env.NODE_ENV !== "production") {
|
|
376
|
-
const _g = globalThis;
|
|
377
|
-
_g.__ASKR_FASTLANE_CLEARED_TASKS = cleared;
|
|
378
|
-
}
|
|
379
|
-
} catch (err) {
|
|
380
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
function exitBulkCommit() {
|
|
384
|
-
_bulkCommitActive = false;
|
|
385
|
-
_appliedParents = null;
|
|
386
|
-
}
|
|
387
|
-
function isBulkCommitActive2() {
|
|
388
|
-
return _bulkCommitActive;
|
|
389
|
-
}
|
|
390
|
-
function markFastPathApplied(parent) {
|
|
391
|
-
if (!_appliedParents) return;
|
|
392
|
-
try {
|
|
393
|
-
_appliedParents.add(parent);
|
|
394
|
-
} catch (e) {
|
|
395
|
-
void e;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
function isFastPathApplied(parent) {
|
|
399
|
-
return !!(_appliedParents && _appliedParents.has(parent));
|
|
400
|
-
}
|
|
401
|
-
function classifyUpdate(instance, result) {
|
|
402
|
-
if (!result || typeof result !== "object" || !("type" in result))
|
|
403
|
-
return { useFastPath: false, reason: "not-vnode" };
|
|
404
|
-
const vnode = result;
|
|
405
|
-
if (vnode == null || typeof vnode.type !== "string")
|
|
406
|
-
return { useFastPath: false, reason: "not-intrinsic" };
|
|
407
|
-
const parent = instance.target;
|
|
408
|
-
if (!parent) return { useFastPath: false, reason: "no-root" };
|
|
409
|
-
const firstChild = parent.children[0];
|
|
410
|
-
if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
|
|
411
|
-
if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
|
|
412
|
-
return { useFastPath: false, reason: "root-tag-mismatch" };
|
|
413
|
-
const children = vnode.children || vnode.props?.children;
|
|
414
|
-
if (!Array.isArray(children))
|
|
415
|
-
return { useFastPath: false, reason: "no-children-array" };
|
|
416
|
-
for (let i = 0; i < children.length; i++) {
|
|
417
|
-
const c = children[i];
|
|
418
|
-
if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
|
|
419
|
-
return { useFastPath: false, reason: "component-child-present" };
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
if (instance.mountOperations.length > 0)
|
|
423
|
-
return { useFastPath: false, reason: "pending-mounts" };
|
|
424
|
-
const oldKeyMap = getKeyMapForElement(firstChild);
|
|
425
|
-
const decision = isKeyedReorderFastPathEligible(
|
|
426
|
-
firstChild,
|
|
427
|
-
children,
|
|
428
|
-
oldKeyMap
|
|
429
|
-
);
|
|
430
|
-
if (!decision.useFastPath || decision.totalKeyed < 128)
|
|
431
|
-
return { ...decision, useFastPath: false, reason: "renderer-declined" };
|
|
432
|
-
return { ...decision, useFastPath: true };
|
|
433
|
-
}
|
|
434
|
-
function commitReorderOnly(instance, result) {
|
|
435
|
-
const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
|
|
436
|
-
if (typeof evaluate2 !== "function") {
|
|
437
|
-
logger.warn(
|
|
438
|
-
"[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
|
|
439
|
-
);
|
|
440
|
-
return false;
|
|
441
|
-
}
|
|
442
|
-
const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
|
|
443
|
-
enterBulkCommit();
|
|
444
|
-
try {
|
|
445
|
-
globalScheduler.runWithSyncProgress(() => {
|
|
446
|
-
evaluate2(result, instance.target);
|
|
447
|
-
try {
|
|
448
|
-
const comp = (init_component(), __toCommonJS(component_exports));
|
|
449
|
-
if (typeof comp?.finalizeReadSubscriptions === "function") {
|
|
450
|
-
try {
|
|
451
|
-
comp.finalizeReadSubscriptions(instance);
|
|
452
|
-
} catch (e) {
|
|
453
|
-
if (process.env.NODE_ENV !== "production") throw e;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
} catch (e) {
|
|
457
|
-
void e;
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
try {
|
|
461
|
-
const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
462
|
-
if (process.env.NODE_ENV !== "production") {
|
|
463
|
-
const _g = globalThis;
|
|
464
|
-
_g.__ASKR_FASTLANE_CLEARED_AFTER = clearedAfter;
|
|
465
|
-
}
|
|
466
|
-
} catch (err) {
|
|
467
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
468
|
-
}
|
|
469
|
-
if (process.env.NODE_ENV !== "production") {
|
|
470
|
-
const _g = globalThis;
|
|
471
|
-
const commitCount = _g.__ASKR_LAST_FASTPATH_COMMIT_COUNT ?? 0;
|
|
472
|
-
const invariants = {
|
|
473
|
-
commitCount,
|
|
474
|
-
mountOps: instance.mountOperations.length,
|
|
475
|
-
cleanupFns: instance.cleanupFns.length
|
|
476
|
-
};
|
|
477
|
-
_g.__ASKR_LAST_FASTLANE_INVARIANTS = invariants;
|
|
478
|
-
if (commitCount !== 1) {
|
|
479
|
-
throw new Error(
|
|
480
|
-
"Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
if (invariants.mountOps > 0) {
|
|
484
|
-
throw new Error(
|
|
485
|
-
"Fast-lane invariant violated: mount operations were registered during bulk commit"
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
if (invariants.cleanupFns > 0) {
|
|
489
|
-
throw new Error(
|
|
490
|
-
"Fast-lane invariant violated: cleanup functions were added during bulk commit"
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
const schedAfter = globalScheduler.getState();
|
|
494
|
-
if (schedBefore && schedAfter && // Only fail if outstanding tasks increased — consuming existing tasks is allowed
|
|
495
|
-
schedAfter.taskCount > schedBefore.taskCount) {
|
|
496
|
-
try {
|
|
497
|
-
console.error(
|
|
498
|
-
"[FASTLANE] schedBefore, schedAfter",
|
|
499
|
-
schedBefore,
|
|
500
|
-
schedAfter
|
|
501
|
-
);
|
|
502
|
-
console.error(
|
|
503
|
-
"[FASTLANE] enqueue logs",
|
|
504
|
-
globalThis.__ASKR_ENQUEUE_LOGS
|
|
505
|
-
);
|
|
506
|
-
} catch (e) {
|
|
507
|
-
void e;
|
|
508
|
-
}
|
|
509
|
-
throw new Error(
|
|
510
|
-
"Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
|
|
511
|
-
);
|
|
512
|
-
}
|
|
513
|
-
let finalState = globalScheduler.getState();
|
|
514
|
-
const executing = globalScheduler.isExecuting();
|
|
515
|
-
const outstandingAfter = Math.max(
|
|
516
|
-
0,
|
|
517
|
-
finalState.taskCount - (executing ? 1 : 0)
|
|
518
|
-
);
|
|
519
|
-
if (outstandingAfter !== 0) {
|
|
520
|
-
if (process.env.NODE_ENV !== "production") {
|
|
521
|
-
let attempts = 0;
|
|
522
|
-
while (attempts < 5) {
|
|
523
|
-
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
524
|
-
if (cleared === 0) break;
|
|
525
|
-
attempts++;
|
|
526
|
-
}
|
|
527
|
-
finalState = globalScheduler.getState();
|
|
528
|
-
const outstandingAfter2 = Math.max(
|
|
529
|
-
0,
|
|
530
|
-
finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
|
|
531
|
-
);
|
|
532
|
-
if (outstandingAfter2 !== 0) {
|
|
533
|
-
try {
|
|
534
|
-
const _g2 = globalThis;
|
|
535
|
-
console.error(
|
|
536
|
-
"[FASTLANE] Post-commit enqueue logs:",
|
|
537
|
-
_g2.__ASKR_ENQUEUE_LOGS
|
|
538
|
-
);
|
|
539
|
-
console.error(
|
|
540
|
-
"[FASTLANE] Cleared counts:",
|
|
541
|
-
_g2.__ASKR_FASTLANE_CLEARED_TASKS,
|
|
542
|
-
_g2.__ASKR_FASTLANE_CLEARED_AFTER
|
|
543
|
-
);
|
|
544
|
-
} catch (err) {
|
|
545
|
-
void err;
|
|
546
|
-
}
|
|
547
|
-
throw new Error(
|
|
548
|
-
`Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
} else {
|
|
552
|
-
globalScheduler.clearPendingSyncTasks?.();
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
return true;
|
|
557
|
-
} finally {
|
|
558
|
-
exitBulkCommit();
|
|
559
|
-
if (process.env.NODE_ENV !== "production") {
|
|
560
|
-
try {
|
|
561
|
-
const _g = globalThis;
|
|
562
|
-
_g.__ASKR_FASTLANE_BULK_FLAG_CHECK = isBulkCommitActive2();
|
|
563
|
-
} catch (e) {
|
|
564
|
-
void e;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
if (process.env.NODE_ENV !== "production") {
|
|
569
|
-
const _g = globalThis;
|
|
570
|
-
if (_g.__ASKR_FASTLANE_BULK_FLAG_CHECK) {
|
|
571
|
-
delete _g.__ASKR_FASTLANE_BULK_FLAG_CHECK;
|
|
572
|
-
throw new Error(
|
|
573
|
-
"Fast-lane invariant violated: bulk commit flag still set after commit"
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
function tryRuntimeFastLaneSync(instance, result) {
|
|
579
|
-
const cls = classifyUpdate(instance, result);
|
|
580
|
-
if (!cls.useFastPath) return false;
|
|
581
|
-
try {
|
|
582
|
-
return commitReorderOnly(instance, result);
|
|
583
|
-
} catch (err) {
|
|
584
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
var _bulkCommitActive, _appliedParents;
|
|
589
|
-
var init_fastlane = __esm({
|
|
590
|
-
"src/runtime/fastlane.ts"() {
|
|
591
|
-
"use strict";
|
|
592
|
-
init_scheduler();
|
|
593
|
-
init_logger();
|
|
594
|
-
init_dom();
|
|
595
|
-
_bulkCommitActive = false;
|
|
596
|
-
_appliedParents = null;
|
|
597
|
-
if (typeof globalThis !== "undefined") {
|
|
598
|
-
const _g = globalThis;
|
|
599
|
-
_g.__ASKR_FASTLANE = {
|
|
600
|
-
isBulkCommitActive: isBulkCommitActive2,
|
|
601
|
-
enterBulkCommit,
|
|
602
|
-
exitBulkCommit,
|
|
603
|
-
tryRuntimeFastLaneSync,
|
|
604
|
-
markFastPathApplied,
|
|
605
|
-
isFastPathApplied
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
// src/jsx/jsx-runtime.ts
|
|
612
|
-
function jsx(type, props, key) {
|
|
613
|
-
return {
|
|
614
|
-
type,
|
|
615
|
-
props: props || {},
|
|
616
|
-
key
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
function jsxs(type, props, key) {
|
|
620
|
-
return jsx(type, props, key);
|
|
621
|
-
}
|
|
622
|
-
var Fragment;
|
|
623
|
-
var init_jsx_runtime = __esm({
|
|
624
|
-
"src/jsx/jsx-runtime.ts"() {
|
|
625
|
-
"use strict";
|
|
626
|
-
Fragment = /* @__PURE__ */ Symbol.for("@askrjs/askr.Fragment");
|
|
627
|
-
}
|
|
628
|
-
});
|
|
629
|
-
|
|
630
366
|
// src/runtime/context.ts
|
|
631
367
|
function withContext(frame, fn) {
|
|
632
368
|
const oldFrame = currentContextFrame;
|
|
@@ -652,9 +388,10 @@ function defineContext(defaultValue) {
|
|
|
652
388
|
key,
|
|
653
389
|
defaultValue,
|
|
654
390
|
Scope: (props) => {
|
|
391
|
+
const value = props.value;
|
|
655
392
|
return {
|
|
656
393
|
type: ContextScopeComponent,
|
|
657
|
-
props: { key, value
|
|
394
|
+
props: { key, value, children: props.children }
|
|
658
395
|
};
|
|
659
396
|
}
|
|
660
397
|
};
|
|
@@ -690,29 +427,29 @@ function ContextScopeComponent(props) {
|
|
|
690
427
|
parent: parentFrame,
|
|
691
428
|
values: /* @__PURE__ */ new Map([[key, value]])
|
|
692
429
|
};
|
|
430
|
+
function createFunctionChildInvoker(fn, frame, owner) {
|
|
431
|
+
return {
|
|
432
|
+
type: ContextFunctionChildInvoker,
|
|
433
|
+
props: { fn, __frame: frame, __owner: owner }
|
|
434
|
+
};
|
|
435
|
+
}
|
|
693
436
|
if (Array.isArray(children)) {
|
|
694
437
|
return children.map((child) => {
|
|
695
438
|
if (typeof child === "function") {
|
|
696
|
-
return
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
__owner: getCurrentComponentInstance()
|
|
702
|
-
}
|
|
703
|
-
};
|
|
439
|
+
return createFunctionChildInvoker(
|
|
440
|
+
child,
|
|
441
|
+
newFrame,
|
|
442
|
+
getCurrentComponentInstance()
|
|
443
|
+
);
|
|
704
444
|
}
|
|
705
445
|
return markWithFrame(child, newFrame);
|
|
706
446
|
});
|
|
707
447
|
} else if (typeof children === "function") {
|
|
708
|
-
return
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
__owner: getCurrentComponentInstance()
|
|
714
|
-
}
|
|
715
|
-
};
|
|
448
|
+
return createFunctionChildInvoker(
|
|
449
|
+
children,
|
|
450
|
+
newFrame,
|
|
451
|
+
getCurrentComponentInstance()
|
|
452
|
+
);
|
|
716
453
|
} else if (children) {
|
|
717
454
|
return markWithFrame(children, newFrame);
|
|
718
455
|
}
|
|
@@ -756,22 +493,126 @@ var init_context = __esm({
|
|
|
756
493
|
}
|
|
757
494
|
});
|
|
758
495
|
|
|
759
|
-
// src/renderer/
|
|
760
|
-
function
|
|
496
|
+
// src/renderer/diag/index.ts
|
|
497
|
+
function getDiagMap() {
|
|
498
|
+
try {
|
|
499
|
+
const root = globalThis;
|
|
500
|
+
if (!root.__ASKR_DIAG) root.__ASKR_DIAG = {};
|
|
501
|
+
return root.__ASKR_DIAG;
|
|
502
|
+
} catch (e) {
|
|
503
|
+
void e;
|
|
504
|
+
return {};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function __ASKR_set(key, value) {
|
|
508
|
+
try {
|
|
509
|
+
const g = getDiagMap();
|
|
510
|
+
g[key] = value;
|
|
511
|
+
try {
|
|
512
|
+
const root = globalThis;
|
|
513
|
+
try {
|
|
514
|
+
const ns = root.__ASKR__ || (root.__ASKR__ = {});
|
|
515
|
+
try {
|
|
516
|
+
ns[key] = value;
|
|
517
|
+
} catch (e) {
|
|
518
|
+
void e;
|
|
519
|
+
}
|
|
520
|
+
} catch (e) {
|
|
521
|
+
void e;
|
|
522
|
+
}
|
|
523
|
+
} catch (e) {
|
|
524
|
+
void e;
|
|
525
|
+
}
|
|
526
|
+
} catch (e) {
|
|
527
|
+
void e;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function __ASKR_incCounter(key) {
|
|
531
|
+
try {
|
|
532
|
+
const g = getDiagMap();
|
|
533
|
+
const prev = typeof g[key] === "number" ? g[key] : 0;
|
|
534
|
+
const next = prev + 1;
|
|
535
|
+
g[key] = next;
|
|
536
|
+
try {
|
|
537
|
+
const root = globalThis;
|
|
538
|
+
const ns = root.__ASKR__ || (root.__ASKR__ = {});
|
|
539
|
+
try {
|
|
540
|
+
const nsPrev = typeof ns[key] === "number" ? ns[key] : 0;
|
|
541
|
+
ns[key] = nsPrev + 1;
|
|
542
|
+
} catch (e) {
|
|
543
|
+
void e;
|
|
544
|
+
}
|
|
545
|
+
} catch (e) {
|
|
546
|
+
void e;
|
|
547
|
+
}
|
|
548
|
+
} catch (e) {
|
|
549
|
+
void e;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
var init_diag = __esm({
|
|
553
|
+
"src/renderer/diag/index.ts"() {
|
|
554
|
+
"use strict";
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// src/runtime/fastlane-shared.ts
|
|
559
|
+
function isBulkCommitActive2() {
|
|
560
|
+
return _bulkCommitActive;
|
|
561
|
+
}
|
|
562
|
+
function markFastPathApplied(parent) {
|
|
563
|
+
if (!_appliedParents) return;
|
|
564
|
+
try {
|
|
565
|
+
_appliedParents.add(parent);
|
|
566
|
+
} catch (e) {
|
|
567
|
+
void e;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
var _bulkCommitActive, _appliedParents;
|
|
571
|
+
var init_fastlane_shared = __esm({
|
|
572
|
+
"src/runtime/fastlane-shared.ts"() {
|
|
573
|
+
"use strict";
|
|
574
|
+
_bulkCommitActive = false;
|
|
575
|
+
_appliedParents = null;
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// src/renderer/types.ts
|
|
580
|
+
function _isDOMElement(node) {
|
|
581
|
+
return typeof node === "object" && node !== null && "type" in node;
|
|
582
|
+
}
|
|
583
|
+
var init_types = __esm({
|
|
584
|
+
"src/renderer/types.ts"() {
|
|
585
|
+
"use strict";
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// src/renderer/cleanup.ts
|
|
590
|
+
function cleanupInstanceIfPresent(node, opts) {
|
|
761
591
|
if (!node) return;
|
|
762
592
|
if (!(node instanceof Element)) return;
|
|
593
|
+
const errors = [];
|
|
763
594
|
try {
|
|
764
595
|
const inst = node.__ASKR_INSTANCE;
|
|
765
596
|
if (inst) {
|
|
766
|
-
|
|
597
|
+
try {
|
|
598
|
+
cleanupComponent(inst);
|
|
599
|
+
} catch (err) {
|
|
600
|
+
if (opts?.strict) errors.push(err);
|
|
601
|
+
else if (process.env.NODE_ENV !== "production")
|
|
602
|
+
logger.warn("[Askr] cleanupComponent failed:", err);
|
|
603
|
+
}
|
|
767
604
|
try {
|
|
768
605
|
delete node.__ASKR_INSTANCE;
|
|
769
606
|
} catch (e) {
|
|
770
|
-
|
|
607
|
+
if (opts?.strict) errors.push(e);
|
|
608
|
+
else void e;
|
|
771
609
|
}
|
|
772
610
|
}
|
|
773
611
|
} catch (err) {
|
|
774
|
-
|
|
612
|
+
if (opts?.strict) errors.push(err);
|
|
613
|
+
else if (process.env.NODE_ENV !== "production") {
|
|
614
|
+
logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
|
|
615
|
+
}
|
|
775
616
|
}
|
|
776
617
|
try {
|
|
777
618
|
const descendants = node.querySelectorAll("*");
|
|
@@ -779,32 +620,57 @@ function cleanupInstanceIfPresent(node) {
|
|
|
779
620
|
try {
|
|
780
621
|
const inst = d.__ASKR_INSTANCE;
|
|
781
622
|
if (inst) {
|
|
782
|
-
|
|
623
|
+
try {
|
|
624
|
+
cleanupComponent(inst);
|
|
625
|
+
} catch (err) {
|
|
626
|
+
if (opts?.strict) errors.push(err);
|
|
627
|
+
else if (process.env.NODE_ENV !== "production") {
|
|
628
|
+
logger.warn(
|
|
629
|
+
"[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
|
|
630
|
+
err
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
783
634
|
try {
|
|
784
635
|
delete d.__ASKR_INSTANCE;
|
|
785
636
|
} catch (e) {
|
|
786
|
-
|
|
637
|
+
if (opts?.strict) errors.push(e);
|
|
638
|
+
else void e;
|
|
787
639
|
}
|
|
788
640
|
}
|
|
789
641
|
} catch (err) {
|
|
790
|
-
|
|
642
|
+
if (opts?.strict) errors.push(err);
|
|
643
|
+
else if (process.env.NODE_ENV !== "production") {
|
|
644
|
+
logger.warn(
|
|
645
|
+
"[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
|
|
646
|
+
err
|
|
647
|
+
);
|
|
648
|
+
}
|
|
791
649
|
}
|
|
792
650
|
}
|
|
793
651
|
} catch (err) {
|
|
794
|
-
|
|
652
|
+
if (opts?.strict) errors.push(err);
|
|
653
|
+
else if (process.env.NODE_ENV !== "production") {
|
|
654
|
+
logger.warn(
|
|
655
|
+
"[Askr] cleanupInstanceIfPresent descendant query failed:",
|
|
656
|
+
err
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (errors.length > 0) {
|
|
661
|
+
throw new AggregateError(errors, "cleanupInstanceIfPresent failed");
|
|
795
662
|
}
|
|
796
663
|
}
|
|
797
|
-
function
|
|
798
|
-
|
|
799
|
-
}
|
|
800
|
-
function getKeyMapForElement(el) {
|
|
801
|
-
return keyedElements.get(el);
|
|
664
|
+
function cleanupInstancesUnder(node, opts) {
|
|
665
|
+
cleanupInstanceIfPresent(node, opts);
|
|
802
666
|
}
|
|
803
667
|
function removeElementListeners(element) {
|
|
804
668
|
const map = elementListeners.get(element);
|
|
805
669
|
if (map) {
|
|
806
670
|
for (const [eventName, entry] of map) {
|
|
807
|
-
|
|
671
|
+
if (entry.options !== void 0)
|
|
672
|
+
element.removeEventListener(eventName, entry.handler, entry.options);
|
|
673
|
+
else element.removeEventListener(eventName, entry.handler);
|
|
808
674
|
}
|
|
809
675
|
elementListeners.delete(element);
|
|
810
676
|
}
|
|
@@ -817,252 +683,32 @@ function removeAllListeners(root) {
|
|
|
817
683
|
removeElementListeners(children[i]);
|
|
818
684
|
}
|
|
819
685
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const firstChild = target.children[0];
|
|
847
|
-
if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && firstChild.tagName.toLowerCase() === vnode.type.toLowerCase()) {
|
|
848
|
-
const vnodeChildren = vnode.children || vnode.props?.children;
|
|
849
|
-
let isSimpleTextVNode = false;
|
|
850
|
-
let textContent;
|
|
851
|
-
if (!Array.isArray(vnodeChildren)) {
|
|
852
|
-
if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
|
|
853
|
-
isSimpleTextVNode = true;
|
|
854
|
-
textContent = String(vnodeChildren);
|
|
855
|
-
}
|
|
856
|
-
} else if (vnodeChildren.length === 1) {
|
|
857
|
-
const child = vnodeChildren[0];
|
|
858
|
-
if (typeof child === "string" || typeof child === "number") {
|
|
859
|
-
isSimpleTextVNode = true;
|
|
860
|
-
textContent = String(child);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
if (isSimpleTextVNode && firstChild.childNodes.length === 1 && firstChild.firstChild?.nodeType === 3) {
|
|
864
|
-
firstChild.firstChild.data = textContent;
|
|
865
|
-
} else {
|
|
866
|
-
if (vnodeChildren) {
|
|
867
|
-
if (Array.isArray(vnodeChildren)) {
|
|
868
|
-
const hasKeys = vnodeChildren.some(
|
|
869
|
-
(child) => typeof child === "object" && child !== null && "key" in child
|
|
870
|
-
);
|
|
871
|
-
if (hasKeys) {
|
|
872
|
-
let oldKeyMap = keyedElements.get(firstChild);
|
|
873
|
-
if (!oldKeyMap) {
|
|
874
|
-
oldKeyMap = /* @__PURE__ */ new Map();
|
|
875
|
-
}
|
|
876
|
-
try {
|
|
877
|
-
if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
|
|
878
|
-
try {
|
|
879
|
-
const keyedVnodes = [];
|
|
880
|
-
for (let i = 0; i < vnodeChildren.length; i++) {
|
|
881
|
-
const c = vnodeChildren[i];
|
|
882
|
-
if (_isDOMElement(c) && c.key !== void 0) {
|
|
883
|
-
keyedVnodes.push({
|
|
884
|
-
key: c.key,
|
|
885
|
-
vnode: c
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
if (keyedVnodes.length > 0 && keyedVnodes.length === vnodeChildren.length) {
|
|
890
|
-
logger.warn(
|
|
891
|
-
"[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
|
|
892
|
-
);
|
|
893
|
-
const stats = performBulkPositionalKeyedTextUpdate(
|
|
894
|
-
firstChild,
|
|
895
|
-
keyedVnodes
|
|
896
|
-
);
|
|
897
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
898
|
-
try {
|
|
899
|
-
const gl = globalThis;
|
|
900
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
901
|
-
gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
|
|
902
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
903
|
-
counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
|
|
904
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
905
|
-
} catch (e) {
|
|
906
|
-
void e;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
try {
|
|
910
|
-
const map = /* @__PURE__ */ new Map();
|
|
911
|
-
const children = Array.from(firstChild.children);
|
|
912
|
-
for (let i = 0; i < children.length; i++) {
|
|
913
|
-
const el = children[i];
|
|
914
|
-
const k = el.getAttribute("data-key");
|
|
915
|
-
if (k !== null) {
|
|
916
|
-
map.set(k, el);
|
|
917
|
-
const n = Number(k);
|
|
918
|
-
if (!Number.isNaN(n)) map.set(n, el);
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
keyedElements.set(firstChild, map);
|
|
922
|
-
} catch (e) {
|
|
923
|
-
void e;
|
|
924
|
-
}
|
|
925
|
-
} else {
|
|
926
|
-
const newKeyMap = reconcileKeyedChildren(
|
|
927
|
-
firstChild,
|
|
928
|
-
vnodeChildren,
|
|
929
|
-
oldKeyMap
|
|
930
|
-
);
|
|
931
|
-
keyedElements.set(firstChild, newKeyMap);
|
|
932
|
-
}
|
|
933
|
-
} catch (err) {
|
|
934
|
-
logger.warn(
|
|
935
|
-
"[Askr][FASTPATH] forced bulk path failed, falling back",
|
|
936
|
-
err
|
|
937
|
-
);
|
|
938
|
-
const newKeyMap = reconcileKeyedChildren(
|
|
939
|
-
firstChild,
|
|
940
|
-
vnodeChildren,
|
|
941
|
-
oldKeyMap
|
|
942
|
-
);
|
|
943
|
-
keyedElements.set(firstChild, newKeyMap);
|
|
944
|
-
}
|
|
945
|
-
} else {
|
|
946
|
-
const newKeyMap = reconcileKeyedChildren(
|
|
947
|
-
firstChild,
|
|
948
|
-
vnodeChildren,
|
|
949
|
-
oldKeyMap
|
|
950
|
-
);
|
|
951
|
-
keyedElements.set(firstChild, newKeyMap);
|
|
952
|
-
}
|
|
953
|
-
} catch (e) {
|
|
954
|
-
void e;
|
|
955
|
-
const newKeyMap = reconcileKeyedChildren(
|
|
956
|
-
firstChild,
|
|
957
|
-
vnodeChildren,
|
|
958
|
-
oldKeyMap
|
|
959
|
-
);
|
|
960
|
-
keyedElements.set(firstChild, newKeyMap);
|
|
961
|
-
}
|
|
962
|
-
} else {
|
|
963
|
-
if (isBulkTextFastPathEligible(firstChild, vnodeChildren)) {
|
|
964
|
-
const stats = performBulkTextReplace(firstChild, vnodeChildren);
|
|
965
|
-
if (process.env.NODE_ENV !== "production") {
|
|
966
|
-
try {
|
|
967
|
-
const gl = globalThis;
|
|
968
|
-
gl.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS = stats;
|
|
969
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
970
|
-
counters.bulkTextHits = (counters.bulkTextHits || 0) + 1;
|
|
971
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
972
|
-
} catch (e) {
|
|
973
|
-
void e;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
} else {
|
|
977
|
-
if (process.env.NODE_ENV !== "production") {
|
|
978
|
-
try {
|
|
979
|
-
const gl = globalThis;
|
|
980
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
981
|
-
counters.bulkTextMisses = (counters.bulkTextMisses || 0) + 1;
|
|
982
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
983
|
-
} catch (e) {
|
|
984
|
-
void e;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
updateUnkeyedChildren(firstChild, vnodeChildren);
|
|
988
|
-
keyedElements.delete(firstChild);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
} else {
|
|
992
|
-
firstChild.textContent = "";
|
|
993
|
-
const dom = createDOMNode(vnodeChildren);
|
|
994
|
-
if (dom) firstChild.appendChild(dom);
|
|
995
|
-
keyedElements.delete(firstChild);
|
|
996
|
-
}
|
|
997
|
-
} else {
|
|
998
|
-
firstChild.textContent = "";
|
|
999
|
-
keyedElements.delete(firstChild);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
updateElementFromVnode(firstChild, vnode, false);
|
|
1003
|
-
} else {
|
|
1004
|
-
target.textContent = "";
|
|
1005
|
-
if (_isDOMElement(vnode) && typeof vnode.type === "string") {
|
|
1006
|
-
const children = vnode.children;
|
|
1007
|
-
if (Array.isArray(children) && children.some(
|
|
1008
|
-
(child) => typeof child === "object" && child !== null && "key" in child
|
|
1009
|
-
)) {
|
|
1010
|
-
const el = document.createElement(vnode.type);
|
|
1011
|
-
target.appendChild(el);
|
|
1012
|
-
const props = vnode.props || {};
|
|
1013
|
-
for (const [key, value] of Object.entries(props)) {
|
|
1014
|
-
if (key === "children" || key === "key") continue;
|
|
1015
|
-
if (value === void 0 || value === null || value === false)
|
|
1016
|
-
continue;
|
|
1017
|
-
if (key.startsWith("on") && key.length > 2) {
|
|
1018
|
-
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
1019
|
-
const wrappedHandler = (event) => {
|
|
1020
|
-
globalScheduler.setInHandler(true);
|
|
1021
|
-
try {
|
|
1022
|
-
value(event);
|
|
1023
|
-
} catch (error) {
|
|
1024
|
-
logger.error("[Askr] Event handler error:", error);
|
|
1025
|
-
} finally {
|
|
1026
|
-
globalScheduler.setInHandler(false);
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
el.addEventListener(eventName, wrappedHandler);
|
|
1030
|
-
if (!elementListeners.has(el)) {
|
|
1031
|
-
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
1032
|
-
}
|
|
1033
|
-
elementListeners.get(el).set(eventName, {
|
|
1034
|
-
handler: wrappedHandler,
|
|
1035
|
-
original: value
|
|
1036
|
-
});
|
|
1037
|
-
continue;
|
|
1038
|
-
}
|
|
1039
|
-
if (key === "class" || key === "className") {
|
|
1040
|
-
el.className = String(value);
|
|
1041
|
-
} else if (key === "value" || key === "checked") {
|
|
1042
|
-
el[key] = value;
|
|
1043
|
-
} else {
|
|
1044
|
-
el.setAttribute(key, String(value));
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
const newKeyMap = reconcileKeyedChildren(el, children, void 0);
|
|
1048
|
-
keyedElements.set(el, newKeyMap);
|
|
1049
|
-
return;
|
|
1050
|
-
return;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
const dom = createDOMNode(vnode);
|
|
1054
|
-
if (dom) {
|
|
1055
|
-
target.appendChild(dom);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
1061
|
-
const keyedVnodes = [];
|
|
1062
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
1063
|
-
const child = newChildren[i];
|
|
1064
|
-
if (_isDOMElement(child) && child.key !== void 0) {
|
|
1065
|
-
keyedVnodes.push({ key: child.key, vnode: child });
|
|
686
|
+
var elementListeners;
|
|
687
|
+
var init_cleanup = __esm({
|
|
688
|
+
"src/renderer/cleanup.ts"() {
|
|
689
|
+
"use strict";
|
|
690
|
+
init_component();
|
|
691
|
+
init_logger();
|
|
692
|
+
elementListeners = /* @__PURE__ */ new WeakMap();
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
// src/renderer/keyed.ts
|
|
697
|
+
function getKeyMapForElement(el) {
|
|
698
|
+
return keyedElements.get(el);
|
|
699
|
+
}
|
|
700
|
+
function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
701
|
+
const keyedVnodes = [];
|
|
702
|
+
for (let i = 0; i < newChildren.length; i++) {
|
|
703
|
+
const child = newChildren[i];
|
|
704
|
+
if (typeof child === "object" && child !== null && "type" in child) {
|
|
705
|
+
const childObj = child;
|
|
706
|
+
if (childObj.key !== void 0) {
|
|
707
|
+
keyedVnodes.push({
|
|
708
|
+
key: childObj.key,
|
|
709
|
+
vnode: child
|
|
710
|
+
});
|
|
711
|
+
}
|
|
1066
712
|
}
|
|
1067
713
|
}
|
|
1068
714
|
const totalKeyed = keyedVnodes.length;
|
|
@@ -1113,8 +759,9 @@ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
|
1113
759
|
let hasPropsPresent = false;
|
|
1114
760
|
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1115
761
|
const vnode = keyedVnodes[i].vnode;
|
|
1116
|
-
if (
|
|
1117
|
-
const
|
|
762
|
+
if (typeof vnode !== "object" || vnode === null) continue;
|
|
763
|
+
const vnodeObj = vnode;
|
|
764
|
+
const props = vnodeObj.props || {};
|
|
1118
765
|
for (const k of Object.keys(props)) {
|
|
1119
766
|
if (k === "children" || k === "key") continue;
|
|
1120
767
|
if (k.startsWith("on") && k.length > 2) continue;
|
|
@@ -1128,8 +775,9 @@ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
|
1128
775
|
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1129
776
|
const { key, vnode } = keyedVnodes[i];
|
|
1130
777
|
const el = oldKeyMap?.get(key);
|
|
1131
|
-
if (!el ||
|
|
1132
|
-
const
|
|
778
|
+
if (!el || typeof vnode !== "object" || vnode === null) continue;
|
|
779
|
+
const vnodeObj = vnode;
|
|
780
|
+
const props = vnodeObj.props || {};
|
|
1133
781
|
for (const k of Object.keys(props)) {
|
|
1134
782
|
if (k === "children" || k === "key") continue;
|
|
1135
783
|
if (k.startsWith("on") && k.length > 2) continue;
|
|
@@ -1158,8 +806,9 @@ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
|
1158
806
|
break;
|
|
1159
807
|
}
|
|
1160
808
|
}
|
|
1161
|
-
} catch {
|
|
809
|
+
} catch (e) {
|
|
1162
810
|
hasPropChanges = true;
|
|
811
|
+
void e;
|
|
1163
812
|
break;
|
|
1164
813
|
}
|
|
1165
814
|
}
|
|
@@ -1174,1024 +823,421 @@ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
|
1174
823
|
hasPropChanges
|
|
1175
824
|
};
|
|
1176
825
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
if (_isDOMElement(child) && child.key !== void 0) {
|
|
1184
|
-
keyedVnodes.push({ key: child.key, vnode: child });
|
|
1185
|
-
} else {
|
|
1186
|
-
unkeyedVnodes.push(child);
|
|
1187
|
-
}
|
|
826
|
+
var keyedElements, _reconcilerRecordedParents;
|
|
827
|
+
var init_keyed = __esm({
|
|
828
|
+
"src/renderer/keyed.ts"() {
|
|
829
|
+
"use strict";
|
|
830
|
+
keyedElements = /* @__PURE__ */ new WeakMap();
|
|
831
|
+
_reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
|
|
1188
832
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
// src/jsx/types.ts
|
|
836
|
+
var ELEMENT_TYPE, Fragment;
|
|
837
|
+
var init_types2 = __esm({
|
|
838
|
+
"src/jsx/types.ts"() {
|
|
839
|
+
"use strict";
|
|
840
|
+
ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
|
|
841
|
+
Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
|
|
1198
842
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
} else if (k2 === "value" || k2 === "checked") {
|
|
1224
|
-
if (el[k2] !== v) {
|
|
1225
|
-
logger.warn("[Askr][FASTPATH][DEV] prop mismatch", {
|
|
1226
|
-
key,
|
|
1227
|
-
prop: k2,
|
|
1228
|
-
expected: v,
|
|
1229
|
-
actual: el[k2]
|
|
1230
|
-
});
|
|
1231
|
-
hasPropChanges = true;
|
|
1232
|
-
break;
|
|
1233
|
-
}
|
|
1234
|
-
} else {
|
|
1235
|
-
const attr = el.getAttribute(k2);
|
|
1236
|
-
if (v === void 0 || v === null || v === false) {
|
|
1237
|
-
if (attr !== null) {
|
|
1238
|
-
logger.warn(
|
|
1239
|
-
"[Askr][FASTPATH][DEV] prop mismatch (missing attr)",
|
|
1240
|
-
{
|
|
1241
|
-
key,
|
|
1242
|
-
prop: k2,
|
|
1243
|
-
expected: v,
|
|
1244
|
-
actual: attr
|
|
1245
|
-
}
|
|
1246
|
-
);
|
|
1247
|
-
hasPropChanges = true;
|
|
1248
|
-
break;
|
|
1249
|
-
}
|
|
1250
|
-
} else if (String(v) !== attr) {
|
|
1251
|
-
logger.warn("[Askr][FASTPATH][DEV] prop mismatch (attr diff)", {
|
|
1252
|
-
key,
|
|
1253
|
-
prop: k2,
|
|
1254
|
-
expected: String(v),
|
|
1255
|
-
actual: attr
|
|
1256
|
-
});
|
|
1257
|
-
hasPropChanges = true;
|
|
1258
|
-
break;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
} catch {
|
|
1262
|
-
hasPropChanges = true;
|
|
1263
|
-
break;
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
if (hasPropChanges) break;
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// src/jsx/jsx-runtime.ts
|
|
846
|
+
function jsxDEV(type, props, key) {
|
|
847
|
+
return {
|
|
848
|
+
$$typeof: ELEMENT_TYPE2,
|
|
849
|
+
type,
|
|
850
|
+
props: props ?? {},
|
|
851
|
+
key: key ?? null
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function jsx(type, props, key) {
|
|
855
|
+
return jsxDEV(type, props, key);
|
|
856
|
+
}
|
|
857
|
+
function jsxs(type, props, key) {
|
|
858
|
+
return jsxDEV(type, props, key);
|
|
859
|
+
}
|
|
860
|
+
var ELEMENT_TYPE2, Fragment2;
|
|
861
|
+
var init_jsx_runtime = __esm({
|
|
862
|
+
"src/jsx/jsx-runtime.ts"() {
|
|
863
|
+
"use strict";
|
|
864
|
+
init_types2();
|
|
865
|
+
ELEMENT_TYPE2 = /* @__PURE__ */ Symbol.for("askr.element");
|
|
866
|
+
Fragment2 = /* @__PURE__ */ Symbol.for("askr.fragment");
|
|
1267
867
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
)
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
let allSimple = true;
|
|
1279
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1280
|
-
const vnode = keyedVnodes[i].vnode;
|
|
1281
|
-
if (!_isDOMElement(vnode)) {
|
|
1282
|
-
allSimple = false;
|
|
1283
|
-
break;
|
|
1284
|
-
}
|
|
1285
|
-
const dv = vnode;
|
|
1286
|
-
if (typeof dv.type !== "string") {
|
|
1287
|
-
allSimple = false;
|
|
1288
|
-
break;
|
|
1289
|
-
}
|
|
1290
|
-
const ch = dv.children || dv.props?.children;
|
|
1291
|
-
if (ch === void 0) continue;
|
|
1292
|
-
if (Array.isArray(ch)) {
|
|
1293
|
-
if (ch.length !== 1 || typeof ch[0] !== "string" && typeof ch[0] !== "number") {
|
|
1294
|
-
allSimple = false;
|
|
1295
|
-
break;
|
|
1296
|
-
}
|
|
1297
|
-
} else if (typeof ch !== "string" && typeof ch !== "number") {
|
|
1298
|
-
allSimple = false;
|
|
1299
|
-
break;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
if (allSimple) {
|
|
1303
|
-
logger.warn("[Askr][FASTPATH] applying huge-list positional fallback");
|
|
1304
|
-
try {
|
|
1305
|
-
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1306
|
-
} catch (e) {
|
|
1307
|
-
void e;
|
|
1308
|
-
}
|
|
1309
|
-
const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
|
|
1310
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1311
|
-
try {
|
|
1312
|
-
const gl = globalThis;
|
|
1313
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
1314
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1315
|
-
counters.bulkKeyedHugeFallback = (counters.bulkKeyedHugeFallback || 0) + 1;
|
|
1316
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1317
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1318
|
-
phase: "bulk-keyed-huge-fallback",
|
|
1319
|
-
stats
|
|
1320
|
-
};
|
|
1321
|
-
} catch (e) {
|
|
1322
|
-
void e;
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
return newKeyMap;
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
// src/renderer/dom.ts
|
|
871
|
+
function createDOMNode(node) {
|
|
872
|
+
if (!IS_DOM_AVAILABLE) {
|
|
873
|
+
if (process.env.NODE_ENV !== "production") {
|
|
874
|
+
try {
|
|
875
|
+
logger.warn("[Askr] createDOMNode called in non-DOM environment");
|
|
876
|
+
} catch (e) {
|
|
877
|
+
void e;
|
|
1326
878
|
}
|
|
1327
879
|
}
|
|
1328
|
-
|
|
1329
|
-
void e;
|
|
880
|
+
return null;
|
|
1330
881
|
}
|
|
1331
|
-
if (
|
|
1332
|
-
|
|
1333
|
-
const gl = globalThis;
|
|
1334
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1335
|
-
phase: "keyed-decision",
|
|
1336
|
-
decision,
|
|
1337
|
-
totalKeyed,
|
|
1338
|
-
oldKeyMapSize: oldKeyMap?.size ?? 0
|
|
1339
|
-
};
|
|
1340
|
-
} catch (e) {
|
|
1341
|
-
void e;
|
|
1342
|
-
}
|
|
882
|
+
if (typeof node === "string") {
|
|
883
|
+
return document.createTextNode(node);
|
|
1343
884
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
if (keyedVnodes.length >= (Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024)) {
|
|
1347
|
-
let missing = 0;
|
|
1348
|
-
try {
|
|
1349
|
-
const present = /* @__PURE__ */ new Set();
|
|
1350
|
-
const parentChildren2 = Array.from(parent.children);
|
|
1351
|
-
for (let i = 0; i < parentChildren2.length; i++) {
|
|
1352
|
-
const attr = parentChildren2[i].getAttribute("data-key");
|
|
1353
|
-
if (attr !== null) {
|
|
1354
|
-
present.add(attr);
|
|
1355
|
-
const n = Number(attr);
|
|
1356
|
-
if (!Number.isNaN(n)) present.add(n);
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1360
|
-
const k2 = keyedVnodes[i].key;
|
|
1361
|
-
if (!present.has(k2)) missing++;
|
|
1362
|
-
}
|
|
1363
|
-
} catch {
|
|
1364
|
-
missing = 0;
|
|
1365
|
-
}
|
|
1366
|
-
allSimpleText = keyedVnodes.length > 0 && keyedVnodes.every(({ vnode }) => {
|
|
1367
|
-
if (!_isDOMElement(vnode)) return false;
|
|
1368
|
-
const dv = vnode;
|
|
1369
|
-
if (typeof dv.type !== "string") return false;
|
|
1370
|
-
const ch = dv.children || dv.props?.children;
|
|
1371
|
-
if (ch === void 0) return true;
|
|
1372
|
-
if (Array.isArray(ch)) {
|
|
1373
|
-
return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
|
|
1374
|
-
}
|
|
1375
|
-
return typeof ch === "string" || typeof ch === "number";
|
|
1376
|
-
});
|
|
1377
|
-
let hasPropsPresent = false;
|
|
1378
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1379
|
-
const vnode = keyedVnodes[i].vnode;
|
|
1380
|
-
if (!_isDOMElement(vnode)) continue;
|
|
1381
|
-
const props = vnode.props || {};
|
|
1382
|
-
for (const k2 of Object.keys(props)) {
|
|
1383
|
-
if (k2 === "children" || k2 === "key") continue;
|
|
1384
|
-
if (k2.startsWith("on") && k2.length > 2) continue;
|
|
1385
|
-
if (k2.startsWith("data-")) continue;
|
|
1386
|
-
hasPropsPresent = true;
|
|
1387
|
-
break;
|
|
1388
|
-
}
|
|
1389
|
-
if (hasPropsPresent) break;
|
|
1390
|
-
}
|
|
1391
|
-
const missingRatio = missing / Math.max(1, keyedVnodes.length);
|
|
1392
|
-
if (missingRatio > 0.5 && allSimpleText && !hasPropsPresent) {
|
|
1393
|
-
logger.warn(
|
|
1394
|
-
"[Askr][FASTPATH] switching to positional bulk keyed fast-path due to missing keys ratio",
|
|
1395
|
-
missingRatio
|
|
1396
|
-
);
|
|
1397
|
-
try {
|
|
1398
|
-
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1399
|
-
} catch (e) {
|
|
1400
|
-
void e;
|
|
1401
|
-
}
|
|
1402
|
-
const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
|
|
1403
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1404
|
-
try {
|
|
1405
|
-
const gl = globalThis;
|
|
1406
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
1407
|
-
try {
|
|
1408
|
-
_reconcilerRecordedParents.add(parent);
|
|
1409
|
-
} catch (e) {
|
|
1410
|
-
void e;
|
|
1411
|
-
}
|
|
1412
|
-
gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
|
|
1413
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1414
|
-
counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
|
|
1415
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1416
|
-
} catch (e) {
|
|
1417
|
-
void e;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
return newKeyMap;
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
} catch (e) {
|
|
1424
|
-
void e;
|
|
885
|
+
if (typeof node === "number") {
|
|
886
|
+
return document.createTextNode(String(node));
|
|
1425
887
|
}
|
|
1426
|
-
if (!
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
if (!parentFastpathApplied) {
|
|
1435
|
-
const gl = globalThis;
|
|
1436
|
-
try {
|
|
1437
|
-
if (_reconcilerRecordedParents.has(parent)) {
|
|
1438
|
-
_reconcilerRecordedParents.delete(parent);
|
|
1439
|
-
} else {
|
|
1440
|
-
delete gl.__ASKR_LAST_FASTPATH_STATS;
|
|
1441
|
-
delete gl.__ASKR_LAST_FASTPATH_REUSED;
|
|
1442
|
-
}
|
|
1443
|
-
} catch {
|
|
1444
|
-
delete gl.__ASKR_LAST_FASTPATH_STATS;
|
|
1445
|
-
delete gl.__ASKR_LAST_FASTPATH_REUSED;
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
} catch (e) {
|
|
1449
|
-
void e;
|
|
888
|
+
if (!node) {
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
if (Array.isArray(node)) {
|
|
892
|
+
const fragment = document.createDocumentFragment();
|
|
893
|
+
for (let i = 0; i < node.length; i++) {
|
|
894
|
+
const dom = createDOMNode(node[i]);
|
|
895
|
+
if (dom) fragment.appendChild(dom);
|
|
1450
896
|
}
|
|
897
|
+
return fragment;
|
|
1451
898
|
}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const
|
|
1455
|
-
if (
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
}
|
|
1466
|
-
let stable = true;
|
|
1467
|
-
try {
|
|
1468
|
-
const parentChildren2 = Array.from(parent.children);
|
|
1469
|
-
if (parentChildren2.length === keyedVnodes.length) {
|
|
1470
|
-
const allSimple = keyedVnodes.every(({ vnode }) => {
|
|
1471
|
-
if (!_isDOMElement(vnode)) return false;
|
|
1472
|
-
const dv = vnode;
|
|
1473
|
-
if (typeof dv.type !== "string") return false;
|
|
1474
|
-
const ch = dv.children || dv.props?.children;
|
|
1475
|
-
if (ch === void 0) return true;
|
|
1476
|
-
if (Array.isArray(ch)) {
|
|
1477
|
-
return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
|
|
1478
|
-
}
|
|
1479
|
-
return typeof ch === "string" || typeof ch === "number";
|
|
1480
|
-
});
|
|
1481
|
-
if (allSimple || process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
|
|
1482
|
-
logger.warn(
|
|
1483
|
-
"[Askr][FASTPATH] len-match heuristic triggered (positional bulk)"
|
|
1484
|
-
);
|
|
1485
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1486
|
-
try {
|
|
1487
|
-
const gl = globalThis;
|
|
1488
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1489
|
-
phase: "bulk-keyed-positional-trigger-lenmatch-early",
|
|
1490
|
-
totalKeyed: keyedVnodes.length,
|
|
1491
|
-
allSimple,
|
|
1492
|
-
forced: process.env.ASKR_FORCE_BULK_POSREUSE === "1"
|
|
1493
|
-
};
|
|
1494
|
-
} catch (e) {
|
|
1495
|
-
void e;
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
899
|
+
if (typeof node === "object" && node !== null && "type" in node) {
|
|
900
|
+
const type = node.type;
|
|
901
|
+
const props = node.props || {};
|
|
902
|
+
if (typeof type === "string") {
|
|
903
|
+
const el = document.createElement(type);
|
|
904
|
+
for (const key in props) {
|
|
905
|
+
const value = props[key];
|
|
906
|
+
if (key === "children" || key === "key") continue;
|
|
907
|
+
if (value === void 0 || value === null || value === false) continue;
|
|
908
|
+
if (key.startsWith("on") && key.length > 2) {
|
|
909
|
+
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
910
|
+
const wrappedHandler = (event) => {
|
|
911
|
+
globalScheduler.setInHandler(true);
|
|
1498
912
|
try {
|
|
1499
|
-
|
|
1500
|
-
} catch (
|
|
1501
|
-
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
};
|
|
1515
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1516
|
-
counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
|
|
1517
|
-
if (process.env.ASKR_FORCE_BULK_POSREUSE === "1")
|
|
1518
|
-
counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
|
|
1519
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1520
|
-
} catch (e) {
|
|
1521
|
-
void e;
|
|
913
|
+
value(event);
|
|
914
|
+
} catch (error) {
|
|
915
|
+
logger.error("[Askr] Event handler error:", error);
|
|
916
|
+
} finally {
|
|
917
|
+
globalScheduler.setInHandler(false);
|
|
918
|
+
const state2 = globalScheduler.getState();
|
|
919
|
+
if ((state2.queueLength ?? 0) > 0 && !state2.running) {
|
|
920
|
+
queueMicrotask(() => {
|
|
921
|
+
try {
|
|
922
|
+
if (!globalScheduler.isExecuting()) globalScheduler.flush();
|
|
923
|
+
} catch (err) {
|
|
924
|
+
queueMicrotask(() => {
|
|
925
|
+
throw err;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
});
|
|
1522
929
|
}
|
|
1523
930
|
}
|
|
1524
|
-
|
|
931
|
+
};
|
|
932
|
+
const options = eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch") ? { passive: true } : void 0;
|
|
933
|
+
if (options !== void 0)
|
|
934
|
+
el.addEventListener(eventName, wrappedHandler, options);
|
|
935
|
+
else el.addEventListener(eventName, wrappedHandler);
|
|
936
|
+
if (!elementListeners.has(el)) {
|
|
937
|
+
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
1525
938
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
939
|
+
elementListeners.get(el).set(eventName, {
|
|
940
|
+
handler: wrappedHandler,
|
|
941
|
+
original: value,
|
|
942
|
+
options
|
|
943
|
+
});
|
|
944
|
+
} else if (key === "class" || key === "className") {
|
|
945
|
+
el.className = String(value);
|
|
946
|
+
} else if (key === "value" || key === "checked") {
|
|
947
|
+
const tag = type.toLowerCase();
|
|
948
|
+
if (key === "value") {
|
|
949
|
+
if (tag === "input" || tag === "textarea" || tag === "select") {
|
|
950
|
+
el.value = String(value);
|
|
951
|
+
el.setAttribute("value", String(value));
|
|
952
|
+
} else {
|
|
953
|
+
el.setAttribute("value", String(value));
|
|
1541
954
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
955
|
+
} else {
|
|
956
|
+
if (tag === "input") {
|
|
957
|
+
el.checked = Boolean(value);
|
|
958
|
+
el.setAttribute("checked", String(Boolean(value)));
|
|
959
|
+
} else {
|
|
960
|
+
el.setAttribute("checked", String(Boolean(value)));
|
|
1544
961
|
}
|
|
1545
962
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
const stats = performBulkKeyedTextReplace(
|
|
1569
|
-
parent,
|
|
1570
|
-
keyedVnodes,
|
|
1571
|
-
oldKeyMap
|
|
1572
|
-
);
|
|
1573
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1574
|
-
try {
|
|
1575
|
-
const gl = globalThis;
|
|
1576
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
1577
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1578
|
-
phase: "bulk-keyed-applied",
|
|
1579
|
-
stats
|
|
1580
|
-
};
|
|
1581
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1582
|
-
counters.bulkKeyedTextHits = (counters.bulkKeyedTextHits || 0) + 1;
|
|
1583
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1584
|
-
} catch (e) {
|
|
1585
|
-
void e;
|
|
963
|
+
} else {
|
|
964
|
+
el.setAttribute(key, String(value));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const vnodeKey = node.key ?? props?.key;
|
|
968
|
+
if (vnodeKey !== void 0) {
|
|
969
|
+
el.setAttribute("data-key", String(vnodeKey));
|
|
970
|
+
}
|
|
971
|
+
const children = props.children || node.children;
|
|
972
|
+
if (children) {
|
|
973
|
+
if (Array.isArray(children)) {
|
|
974
|
+
if (process.env.NODE_ENV !== "production") {
|
|
975
|
+
let hasElements = false;
|
|
976
|
+
let hasKeys = false;
|
|
977
|
+
for (let i = 0; i < children.length; i++) {
|
|
978
|
+
const item = children[i];
|
|
979
|
+
if (typeof item === "object" && item !== null && "type" in item) {
|
|
980
|
+
hasElements = true;
|
|
981
|
+
const itemProps = item.props || {};
|
|
982
|
+
if ("key" in itemProps) {
|
|
983
|
+
hasKeys = true;
|
|
984
|
+
break;
|
|
1586
985
|
}
|
|
1587
986
|
}
|
|
1588
|
-
return newKeyMap;
|
|
1589
987
|
}
|
|
1590
|
-
if (
|
|
1591
|
-
|
|
1592
|
-
"[Askr][FASTPATH] applying bulk keyed positional text fast-path (len-match)"
|
|
1593
|
-
);
|
|
1594
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
988
|
+
if (hasElements && !hasKeys) {
|
|
989
|
+
if (typeof console !== "undefined") {
|
|
1595
990
|
try {
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
};
|
|
991
|
+
const inst = getCurrentInstance();
|
|
992
|
+
const name = inst?.fn?.name || "<anonymous>";
|
|
993
|
+
logger.warn(
|
|
994
|
+
`Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`
|
|
995
|
+
);
|
|
1602
996
|
} catch (e) {
|
|
997
|
+
logger.warn(
|
|
998
|
+
'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
|
|
999
|
+
);
|
|
1603
1000
|
void e;
|
|
1604
1001
|
}
|
|
1605
1002
|
}
|
|
1606
|
-
try {
|
|
1607
|
-
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1608
|
-
} catch (e) {
|
|
1609
|
-
void e;
|
|
1610
|
-
}
|
|
1611
|
-
const stats = performBulkPositionalKeyedTextUpdate(
|
|
1612
|
-
parent,
|
|
1613
|
-
keyedVnodes
|
|
1614
|
-
);
|
|
1615
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1616
|
-
try {
|
|
1617
|
-
const gl = globalThis;
|
|
1618
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
1619
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1620
|
-
phase: "bulk-keyed-positional-applied",
|
|
1621
|
-
stats
|
|
1622
|
-
};
|
|
1623
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1624
|
-
counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
|
|
1625
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1626
|
-
} catch (e) {
|
|
1627
|
-
void e;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
return newKeyMap;
|
|
1631
|
-
}
|
|
1632
|
-
const mismatchRatio = keyMismatches / keyedVnodes.length;
|
|
1633
|
-
const POSITIONAL_THRESHOLD = 0.5;
|
|
1634
|
-
if (mismatchRatio > POSITIONAL_THRESHOLD) {
|
|
1635
|
-
logger.warn(
|
|
1636
|
-
"[Askr][FASTPATH] applying bulk keyed positional text fast-path"
|
|
1637
|
-
);
|
|
1638
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1639
|
-
try {
|
|
1640
|
-
globalThis.__ASKR_BULK_DIAG = {
|
|
1641
|
-
phase: "bulk-keyed-positional-trigger",
|
|
1642
|
-
totalKeyed: keyedVnodes.length,
|
|
1643
|
-
keyMismatches
|
|
1644
|
-
};
|
|
1645
|
-
} catch (e) {
|
|
1646
|
-
void e;
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
try {
|
|
1650
|
-
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1651
|
-
} catch (e) {
|
|
1652
|
-
void e;
|
|
1653
|
-
}
|
|
1654
|
-
const stats = performBulkPositionalKeyedTextUpdate(
|
|
1655
|
-
parent,
|
|
1656
|
-
keyedVnodes
|
|
1657
|
-
);
|
|
1658
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1659
|
-
try {
|
|
1660
|
-
const gl = globalThis;
|
|
1661
|
-
gl.__ASKR_LAST_FASTPATH_STATS = stats;
|
|
1662
|
-
gl.__ASKR_BULK_DIAG = {
|
|
1663
|
-
phase: "bulk-keyed-positional-applied",
|
|
1664
|
-
stats
|
|
1665
|
-
};
|
|
1666
|
-
const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
|
|
1667
|
-
counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
|
|
1668
|
-
gl.__ASKR_FASTPATH_COUNTERS = counters;
|
|
1669
|
-
} catch (e) {
|
|
1670
|
-
void e;
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
return newKeyMap;
|
|
1674
|
-
}
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
} catch {
|
|
1678
|
-
stable = false;
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
} catch (e) {
|
|
1682
|
-
void e;
|
|
1683
|
-
}
|
|
1684
|
-
if (!useFastPath) {
|
|
1685
|
-
const totalKeyed2 = keyedVnodes.length;
|
|
1686
|
-
const candidates = newChildren.filter(
|
|
1687
|
-
(c) => _isDOMElement(c) && typeof c.type === "string"
|
|
1688
|
-
);
|
|
1689
|
-
const smallListPositionalReuseEligible = candidates.length > 0 && candidates.length <= 64 && parent.children.length === candidates.length && candidates.every((vnode) => {
|
|
1690
|
-
const children = vnode.children || vnode.props?.children;
|
|
1691
|
-
if (Array.isArray(children)) {
|
|
1692
|
-
return children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number");
|
|
1693
|
-
}
|
|
1694
|
-
return children === void 0 || typeof children === "string" || typeof children === "number";
|
|
1695
|
-
});
|
|
1696
|
-
try {
|
|
1697
|
-
if (smallListPositionalReuseEligible) {
|
|
1698
|
-
let eligible = true;
|
|
1699
|
-
for (let i = 0; i < totalKeyed2; i++) {
|
|
1700
|
-
const vnode = keyedVnodes[i].vnode;
|
|
1701
|
-
if (!_isDOMElement(vnode) || typeof vnode.type !== "string") {
|
|
1702
|
-
eligible = false;
|
|
1703
|
-
break;
|
|
1704
|
-
}
|
|
1705
|
-
const children = vnode.children || vnode.props?.children;
|
|
1706
|
-
if (Array.isArray(children)) {
|
|
1707
|
-
if (children.length !== 1) {
|
|
1708
|
-
eligible = false;
|
|
1709
|
-
break;
|
|
1710
|
-
}
|
|
1711
|
-
const c = children[0];
|
|
1712
|
-
if (typeof c !== "string" && typeof c !== "number") {
|
|
1713
|
-
eligible = false;
|
|
1714
|
-
break;
|
|
1715
|
-
}
|
|
1716
|
-
} else if (children !== void 0 && typeof children !== "string" && typeof children !== "number") {
|
|
1717
|
-
eligible = false;
|
|
1718
|
-
break;
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
const anyKeyMatches = !!oldKeyMap && keyedVnodes.some((kv) => oldKeyMap.has(kv.key));
|
|
1722
|
-
if (anyKeyMatches) {
|
|
1723
|
-
eligible = false;
|
|
1724
|
-
}
|
|
1725
|
-
if (eligible || process.env.ASKR_FORCE_POSREUSE === "1") {
|
|
1726
|
-
_triedPositionalReuse = true;
|
|
1727
|
-
if (process.env.ASKR_FORCE_POSREUSE === "1") {
|
|
1728
|
-
logger.warn(
|
|
1729
|
-
"[Askr][POSREUSE][FORCED] forcing positional reuse path for testing"
|
|
1730
|
-
);
|
|
1731
|
-
} else {
|
|
1732
|
-
logger.warn("[Askr][POSREUSE] positional reuse heuristic applied");
|
|
1733
|
-
}
|
|
1734
|
-
const existingChildren = parent.children;
|
|
1735
|
-
for (let i = 0; i < totalKeyed2; i++) {
|
|
1736
|
-
const { key, vnode } = keyedVnodes[i];
|
|
1737
|
-
const current2 = existingChildren[i];
|
|
1738
|
-
if (current2 && _isDOMElement(vnode)) {
|
|
1739
|
-
const vnodeType = vnode.type;
|
|
1740
|
-
if (current2.tagName.toLowerCase() === vnodeType.toLowerCase()) {
|
|
1741
|
-
updateElementFromVnode(current2, vnode);
|
|
1742
|
-
newKeyMap.set(key, current2);
|
|
1743
|
-
continue;
|
|
1744
|
-
}
|
|
1745
1003
|
}
|
|
1746
|
-
const newEl = createDOMNode(vnode);
|
|
1747
|
-
if (newEl instanceof Element) {
|
|
1748
|
-
if (current2) {
|
|
1749
|
-
cleanupInstanceIfPresent(current2);
|
|
1750
|
-
parent.replaceChild(newEl, current2);
|
|
1751
|
-
} else parent.appendChild(newEl);
|
|
1752
|
-
newKeyMap.set(key, newEl);
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
for (const vnode of unkeyedVnodes) {
|
|
1756
|
-
const newEl = createDOMNode(vnode);
|
|
1757
|
-
if (newEl) parent.appendChild(newEl);
|
|
1758
|
-
}
|
|
1759
|
-
return newKeyMap;
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
} catch {
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
if (useFastPath) {
|
|
1766
|
-
if (!isSchedulerExecuting()) {
|
|
1767
|
-
logger.warn(
|
|
1768
|
-
"[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
|
|
1769
|
-
);
|
|
1770
|
-
}
|
|
1771
|
-
let parentChildrenArr;
|
|
1772
|
-
let localOldKeyMap;
|
|
1773
|
-
if (totalKeyed <= 20) {
|
|
1774
|
-
try {
|
|
1775
|
-
const pc = parent.children;
|
|
1776
|
-
parentChildrenArr = new Array(pc.length);
|
|
1777
|
-
for (let i = 0; i < pc.length; i++)
|
|
1778
|
-
parentChildrenArr[i] = pc[i];
|
|
1779
|
-
} catch {
|
|
1780
|
-
parentChildrenArr = void 0;
|
|
1781
|
-
}
|
|
1782
|
-
} else {
|
|
1783
|
-
localOldKeyMap = /* @__PURE__ */ new Map();
|
|
1784
|
-
try {
|
|
1785
|
-
const parentChildren2 = Array.from(parent.children);
|
|
1786
|
-
for (let i = 0; i < parentChildren2.length; i++) {
|
|
1787
|
-
const ch = parentChildren2[i];
|
|
1788
|
-
const k2 = ch.getAttribute("data-key");
|
|
1789
|
-
if (k2 !== null) {
|
|
1790
|
-
localOldKeyMap.set(k2, ch);
|
|
1791
|
-
const n = Number(k2);
|
|
1792
|
-
if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
|
|
1793
1004
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
logger.warn(
|
|
1800
|
-
"[Askr][FASTPATH] oldKeyMap size:",
|
|
1801
|
-
oldKeyMap?.size ?? 0,
|
|
1802
|
-
"localOldKeyMap size:",
|
|
1803
|
-
localOldKeyMap?.size
|
|
1804
|
-
);
|
|
1805
|
-
const tLookupStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
1806
|
-
const finalNodes = [];
|
|
1807
|
-
let mapLookups = 0;
|
|
1808
|
-
let createdNodes = 0;
|
|
1809
|
-
let reusedCount = 0;
|
|
1810
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1811
|
-
const { key, vnode } = keyedVnodes[i];
|
|
1812
|
-
mapLookups++;
|
|
1813
|
-
let el;
|
|
1814
|
-
if (totalKeyed <= 20 && parentChildrenArr) {
|
|
1815
|
-
const ks = String(key);
|
|
1816
|
-
for (let j = 0; j < parentChildrenArr.length; j++) {
|
|
1817
|
-
const ch = parentChildrenArr[j];
|
|
1818
|
-
const k2 = ch.getAttribute("data-key");
|
|
1819
|
-
if (k2 !== null && (k2 === ks || Number(k2) === key)) {
|
|
1820
|
-
el = ch;
|
|
1821
|
-
break;
|
|
1005
|
+
for (let i = 0; i < children.length; i++) {
|
|
1006
|
+
const dom = createDOMNode(children[i]);
|
|
1007
|
+
if (dom) el.appendChild(dom);
|
|
1822
1008
|
}
|
|
1009
|
+
} else {
|
|
1010
|
+
const dom = createDOMNode(children);
|
|
1011
|
+
if (dom) el.appendChild(dom);
|
|
1823
1012
|
}
|
|
1824
|
-
if (!el) el = oldKeyMap?.get(key);
|
|
1825
|
-
} else {
|
|
1826
|
-
el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
|
|
1827
|
-
}
|
|
1828
|
-
if (el) {
|
|
1829
|
-
finalNodes.push(el);
|
|
1830
|
-
reusedCount++;
|
|
1831
|
-
} else {
|
|
1832
|
-
const newEl = createDOMNode(vnode);
|
|
1833
|
-
if (newEl) {
|
|
1834
|
-
finalNodes.push(newEl);
|
|
1835
|
-
createdNodes++;
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
for (const vnode of unkeyedVnodes) {
|
|
1840
|
-
const newEl = createDOMNode(vnode);
|
|
1841
|
-
if (newEl) {
|
|
1842
|
-
finalNodes.push(newEl);
|
|
1843
|
-
createdNodes++;
|
|
1844
1013
|
}
|
|
1014
|
+
return el;
|
|
1845
1015
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
const
|
|
1849
|
-
const
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1852
|
-
const nodeProto = Node.prototype;
|
|
1853
|
-
const removeFn = (() => {
|
|
1854
|
-
if (typeof document === "undefined" || typeof document.createElement !== "function")
|
|
1855
|
-
return void 0;
|
|
1856
|
-
try {
|
|
1857
|
-
const el = document.createElement("div");
|
|
1858
|
-
return typeof el.remove === "function" ? el.remove : void 0;
|
|
1859
|
-
} catch {
|
|
1860
|
-
return void 0;
|
|
1861
|
-
}
|
|
1862
|
-
})();
|
|
1863
|
-
if (elProto.replaceChildren)
|
|
1864
|
-
orig.replaceChildren = elProto.replaceChildren;
|
|
1865
|
-
if (nodeProto.appendChild) orig.appendChild = nodeProto.appendChild;
|
|
1866
|
-
if (nodeProto.insertBefore) orig.insertBefore = nodeProto.insertBefore;
|
|
1867
|
-
if (nodeProto.removeChild) orig.removeChild = nodeProto.removeChild;
|
|
1868
|
-
if (nodeProto.replaceChild) orig.replaceChild = nodeProto.replaceChild;
|
|
1869
|
-
if (removeFn) orig.remove = removeFn;
|
|
1870
|
-
let violation = false;
|
|
1871
|
-
try {
|
|
1872
|
-
const fragment = document.createDocumentFragment();
|
|
1873
|
-
for (let i = 0; i < finalNodes.length; i++)
|
|
1874
|
-
fragment.appendChild(finalNodes[i]);
|
|
1875
|
-
let commitCount = 0;
|
|
1876
|
-
commitCount++;
|
|
1877
|
-
parent.replaceChildren(fragment);
|
|
1878
|
-
if (typeof globalThis !== "undefined") {
|
|
1879
|
-
globalThis["__ASKR_LAST_FASTPATH_COMMIT_COUNT"] = commitCount;
|
|
1880
|
-
}
|
|
1881
|
-
} finally {
|
|
1882
|
-
violation = otherMutationCount !== 0 || replaceChildrenCount < 1;
|
|
1883
|
-
}
|
|
1884
|
-
if (violation) {
|
|
1885
|
-
logger.error(
|
|
1886
|
-
"[Askr][DEV] Fast-path structural mutation invariant violated:",
|
|
1887
|
-
{
|
|
1888
|
-
replaceChildrenCount,
|
|
1889
|
-
otherMutationCount
|
|
1890
|
-
}
|
|
1891
|
-
);
|
|
1016
|
+
if (typeof type === "function") {
|
|
1017
|
+
const frame = node[CONTEXT_FRAME_SYMBOL];
|
|
1018
|
+
const snapshot = frame || getCurrentContextFrame();
|
|
1019
|
+
const componentFn = type;
|
|
1020
|
+
const isAsync = componentFn.constructor.name === "AsyncFunction";
|
|
1021
|
+
if (isAsync) {
|
|
1892
1022
|
throw new Error(
|
|
1893
|
-
"
|
|
1023
|
+
"Async components are not supported. Use resource() for async work."
|
|
1894
1024
|
);
|
|
1895
1025
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
const wasExecuting = process.env.NODE_ENV !== "production" ? isSchedulerExecuting() : false;
|
|
1907
|
-
const tCommitStart = Date.now();
|
|
1908
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1909
|
-
}
|
|
1910
|
-
let commitCount = 0;
|
|
1911
|
-
commitCount++;
|
|
1912
|
-
try {
|
|
1913
|
-
const existing = Array.from(parent.childNodes);
|
|
1914
|
-
for (const n of existing) cleanupInstanceIfPresent(n);
|
|
1915
|
-
} catch (e) {
|
|
1916
|
-
void e;
|
|
1026
|
+
const vnodeAny = node;
|
|
1027
|
+
let childInstance = vnodeAny.__instance;
|
|
1028
|
+
if (!childInstance) {
|
|
1029
|
+
childInstance = createComponentInstance(
|
|
1030
|
+
`comp-${Math.random().toString(36).slice(2, 7)}`,
|
|
1031
|
+
componentFn,
|
|
1032
|
+
props || {},
|
|
1033
|
+
null
|
|
1034
|
+
);
|
|
1035
|
+
vnodeAny.__instance = childInstance;
|
|
1917
1036
|
}
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
for (const n of existing) cleanupInstanceIfPresent(n);
|
|
1921
|
-
} catch (e) {
|
|
1922
|
-
void e;
|
|
1037
|
+
if (snapshot) {
|
|
1038
|
+
childInstance.ownerFrame = snapshot;
|
|
1923
1039
|
}
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1040
|
+
const result = withContext(
|
|
1041
|
+
snapshot,
|
|
1042
|
+
() => renderComponentInline(childInstance)
|
|
1043
|
+
);
|
|
1044
|
+
if (result instanceof Promise) {
|
|
1045
|
+
throw new Error(
|
|
1046
|
+
"Async components are not supported. Components must return synchronously."
|
|
1047
|
+
);
|
|
1927
1048
|
}
|
|
1928
|
-
const
|
|
1929
|
-
if (
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
logger.warn(
|
|
1933
|
-
"[Askr][FASTPATH][DEV] Fast-path commit invoked outside scheduler execution"
|
|
1934
|
-
);
|
|
1935
|
-
}
|
|
1936
|
-
if (schedBefore && schedAfter) {
|
|
1937
|
-
if (schedBefore.taskCount !== schedAfter.taskCount) {
|
|
1938
|
-
logger.error(
|
|
1939
|
-
"[Askr][FASTPATH][DEV] Scheduler tasks were enqueued during fast-path commit",
|
|
1940
|
-
{
|
|
1941
|
-
before: schedBefore,
|
|
1942
|
-
after: schedAfter
|
|
1943
|
-
}
|
|
1944
|
-
);
|
|
1945
|
-
throw new Error("Fast-path must not enqueue scheduler tasks");
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
const parentNodes = Array.from(parent.childNodes);
|
|
1949
|
-
if (parentNodes.length !== finalNodes.length) {
|
|
1950
|
-
logger.error("[Askr][FASTPATH][DEV] Parent child count mismatch", {
|
|
1951
|
-
parentCount: parentNodes.length,
|
|
1952
|
-
expected: finalNodes.length
|
|
1953
|
-
});
|
|
1954
|
-
throw new Error(
|
|
1955
|
-
"Fast-path must perform a single structural replacement"
|
|
1956
|
-
);
|
|
1957
|
-
}
|
|
1958
|
-
for (let i = 0; i < finalNodes.length; i++) {
|
|
1959
|
-
if (parentNodes[i] !== finalNodes[i]) {
|
|
1960
|
-
logger.error(
|
|
1961
|
-
"[Askr][FASTPATH][DEV] Final DOM order mismatch at index",
|
|
1962
|
-
i,
|
|
1963
|
-
{
|
|
1964
|
-
expected: finalNodes[i],
|
|
1965
|
-
found: parentNodes[i]
|
|
1966
|
-
}
|
|
1967
|
-
);
|
|
1968
|
-
throw new Error(
|
|
1969
|
-
"Fast-path final DOM order does not match expected nodes"
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1049
|
+
const dom = withContext(snapshot, () => createDOMNode(result));
|
|
1050
|
+
if (dom instanceof Element) {
|
|
1051
|
+
mountInstanceInline(childInstance, dom);
|
|
1052
|
+
return dom;
|
|
1973
1053
|
}
|
|
1974
|
-
const
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1054
|
+
const host = document.createElement("div");
|
|
1055
|
+
if (dom instanceof DocumentFragment) {
|
|
1056
|
+
host.appendChild(dom);
|
|
1057
|
+
} else if (dom) {
|
|
1058
|
+
host.appendChild(dom);
|
|
1979
1059
|
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
mapLookups,
|
|
1992
|
-
createdNodes,
|
|
1993
|
-
reusedCount
|
|
1994
|
-
};
|
|
1995
|
-
if (typeof globalThis !== "undefined") {
|
|
1996
|
-
const _g = globalThis;
|
|
1997
|
-
_g["__ASKR_LAST_FASTPATH_STATS"] = stats;
|
|
1998
|
-
_g["__ASKR_LAST_FASTPATH_REUSED"] = reusedCount > 0;
|
|
1999
|
-
const historyKey = "__ASKR_LAST_FASTPATH_HISTORY";
|
|
2000
|
-
let hist = _g[historyKey];
|
|
2001
|
-
if (!hist) {
|
|
2002
|
-
hist = [];
|
|
2003
|
-
_g[historyKey] = hist;
|
|
1060
|
+
mountInstanceInline(childInstance, host);
|
|
1061
|
+
return host;
|
|
1062
|
+
}
|
|
1063
|
+
if (typeof type === "symbol" && (type === Fragment2 || String(type) === "Symbol(Fragment)")) {
|
|
1064
|
+
const fragment = document.createDocumentFragment();
|
|
1065
|
+
const children = props.children || node.children;
|
|
1066
|
+
if (children) {
|
|
1067
|
+
if (Array.isArray(children)) {
|
|
1068
|
+
for (let i = 0; i < children.length; i++) {
|
|
1069
|
+
const dom = createDOMNode(children[i]);
|
|
1070
|
+
if (dom) fragment.appendChild(dom);
|
|
2004
1071
|
}
|
|
2005
|
-
|
|
1072
|
+
} else {
|
|
1073
|
+
const dom = createDOMNode(children);
|
|
1074
|
+
if (dom) fragment.appendChild(dom);
|
|
2006
1075
|
}
|
|
2007
|
-
logger.warn("[Askr][FASTPATH]", JSON.stringify(stats));
|
|
2008
1076
|
}
|
|
1077
|
+
return fragment;
|
|
2009
1078
|
}
|
|
2010
|
-
return newKeyMap;
|
|
2011
|
-
}
|
|
2012
|
-
const parentChildren = Array.from(parent.children);
|
|
2013
|
-
const positions = new Array(keyedVnodes.length).fill(-1);
|
|
2014
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
2015
|
-
const key = keyedVnodes[i].key;
|
|
2016
|
-
const el = oldKeyMap?.get(key);
|
|
2017
|
-
if (el && el.parentElement === parent) {
|
|
2018
|
-
positions[i] = parentChildren.indexOf(el);
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
const tailsStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
2022
|
-
const keepSet = /* @__PURE__ */ new Set();
|
|
2023
|
-
const tails = [];
|
|
2024
|
-
const tailsIdx = [];
|
|
2025
|
-
const prev = new Array(positions.length).fill(-1);
|
|
2026
|
-
for (let i = 0; i < positions.length; i++) {
|
|
2027
|
-
const pos = positions[i];
|
|
2028
|
-
if (pos === -1) continue;
|
|
2029
|
-
let lo = 0;
|
|
2030
|
-
let hi = tails.length;
|
|
2031
|
-
while (lo < hi) {
|
|
2032
|
-
const mid = lo + hi >> 1;
|
|
2033
|
-
if (tails[mid] < pos) lo = mid + 1;
|
|
2034
|
-
else hi = mid;
|
|
2035
|
-
}
|
|
2036
|
-
if (lo === tails.length) {
|
|
2037
|
-
tails.push(pos);
|
|
2038
|
-
tailsIdx.push(i);
|
|
2039
|
-
} else {
|
|
2040
|
-
tails[lo] = pos;
|
|
2041
|
-
tailsIdx[lo] = i;
|
|
2042
|
-
}
|
|
2043
|
-
prev[i] = lo > 0 ? tailsIdx[lo - 1] : -1;
|
|
2044
1079
|
}
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
function updateElementFromVnode(el, vnode, updateChildren = true) {
|
|
1083
|
+
if (!_isDOMElement(vnode)) {
|
|
1084
|
+
return;
|
|
2049
1085
|
}
|
|
2050
|
-
const
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
globalThis.__ASKR_BULK_DIAG = {
|
|
2055
|
-
phase: "keyed-fallback-lis",
|
|
2056
|
-
positionsFound: positions.filter((p) => p !== -1).length,
|
|
2057
|
-
keepCount: keepSet.size,
|
|
2058
|
-
tLIS,
|
|
2059
|
-
previousDecision: prev2?.decision
|
|
2060
|
-
};
|
|
2061
|
-
} catch (e) {
|
|
2062
|
-
void e;
|
|
2063
|
-
}
|
|
1086
|
+
const props = vnode.props || {};
|
|
1087
|
+
const vnodeKey = vnode.key ?? vnode.props?.key;
|
|
1088
|
+
if (vnodeKey !== void 0) {
|
|
1089
|
+
el.setAttribute("data-key", String(vnodeKey));
|
|
2064
1090
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
const
|
|
2069
|
-
if (
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
1091
|
+
const existingListeners = elementListeners.get(el);
|
|
1092
|
+
const desiredEventNames = /* @__PURE__ */ new Set();
|
|
1093
|
+
for (const key in props) {
|
|
1094
|
+
const value = props[key];
|
|
1095
|
+
if (key === "children" || key === "key") continue;
|
|
1096
|
+
if (value === void 0 || value === null || value === false) {
|
|
1097
|
+
if (key === "class" || key === "className") {
|
|
1098
|
+
el.className = "";
|
|
1099
|
+
} else if (key.startsWith("on") && key.length > 2) {
|
|
1100
|
+
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
1101
|
+
if (existingListeners && existingListeners.has(eventName)) {
|
|
1102
|
+
const entry = existingListeners.get(eventName);
|
|
1103
|
+
if (entry.options !== void 0)
|
|
1104
|
+
el.removeEventListener(eventName, entry.handler, entry.options);
|
|
1105
|
+
else el.removeEventListener(eventName, entry.handler);
|
|
1106
|
+
existingListeners.delete(eventName);
|
|
2073
1107
|
}
|
|
2074
|
-
|
|
2075
|
-
newKeyMap.set(key, el);
|
|
1108
|
+
continue;
|
|
2076
1109
|
} else {
|
|
2077
|
-
|
|
2078
|
-
updateElementFromVnode(el, vnode);
|
|
2079
|
-
newKeyMap.set(key, el);
|
|
2080
|
-
anchor = el.nextSibling;
|
|
1110
|
+
el.removeAttribute(key);
|
|
2081
1111
|
}
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
if (key === "class" || key === "className") {
|
|
1115
|
+
el.className = String(value);
|
|
1116
|
+
} else if (key === "value" || key === "checked") {
|
|
1117
|
+
el[key] = value;
|
|
1118
|
+
} else if (key.startsWith("on") && key.length > 2) {
|
|
1119
|
+
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
1120
|
+
desiredEventNames.add(eventName);
|
|
1121
|
+
const existing = existingListeners?.get(eventName);
|
|
1122
|
+
if (existing && existing.original === value) {
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
if (existing) {
|
|
1126
|
+
el.removeEventListener(eventName, existing.handler);
|
|
1127
|
+
}
|
|
1128
|
+
const wrappedHandler = (event) => {
|
|
1129
|
+
globalScheduler.setInHandler(true);
|
|
1130
|
+
try {
|
|
1131
|
+
value(event);
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
logger.error("[Askr] Event handler error:", error);
|
|
1134
|
+
} finally {
|
|
1135
|
+
globalScheduler.setInHandler(false);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
const options = eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch") ? { passive: true } : void 0;
|
|
1139
|
+
if (options !== void 0)
|
|
1140
|
+
el.addEventListener(eventName, wrappedHandler, options);
|
|
1141
|
+
else el.addEventListener(eventName, wrappedHandler);
|
|
1142
|
+
if (!elementListeners.has(el)) {
|
|
1143
|
+
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
2088
1144
|
}
|
|
1145
|
+
elementListeners.get(el).set(eventName, {
|
|
1146
|
+
handler: wrappedHandler,
|
|
1147
|
+
original: value,
|
|
1148
|
+
options
|
|
1149
|
+
});
|
|
1150
|
+
} else {
|
|
1151
|
+
el.setAttribute(key, String(value));
|
|
2089
1152
|
}
|
|
2090
1153
|
}
|
|
2091
|
-
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2094
|
-
|
|
1154
|
+
if (existingListeners) {
|
|
1155
|
+
for (const eventName of existingListeners.keys()) {
|
|
1156
|
+
const entry = existingListeners.get(eventName);
|
|
1157
|
+
if (!desiredEventNames.has(eventName)) {
|
|
1158
|
+
el.removeEventListener(eventName, entry.handler);
|
|
1159
|
+
existingListeners.delete(eventName);
|
|
1160
|
+
}
|
|
2095
1161
|
}
|
|
1162
|
+
if (existingListeners.size === 0) elementListeners.delete(el);
|
|
2096
1163
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
if (el
|
|
2109
|
-
|
|
2110
|
-
if (typeof children === "string" || typeof children === "number") {
|
|
2111
|
-
if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
|
|
2112
|
-
el.firstChild.data = String(children);
|
|
2113
|
-
} else {
|
|
2114
|
-
el.textContent = String(children);
|
|
2115
|
-
}
|
|
2116
|
-
} else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
|
|
2117
|
-
if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
|
|
2118
|
-
el.firstChild.data = String(children[0]);
|
|
2119
|
-
} else {
|
|
2120
|
-
el.textContent = String(children[0]);
|
|
2121
|
-
}
|
|
2122
|
-
} else {
|
|
2123
|
-
updateElementFromVnode(el, vnode);
|
|
2124
|
-
}
|
|
2125
|
-
finalNodes.push(el);
|
|
2126
|
-
reused++;
|
|
1164
|
+
if (updateChildren) {
|
|
1165
|
+
const children = vnode.children || props.children;
|
|
1166
|
+
updateElementChildren(el, children);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
function updateElementChildren(el, children) {
|
|
1170
|
+
if (!children) {
|
|
1171
|
+
el.textContent = "";
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
|
|
1175
|
+
if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
|
|
1176
|
+
el.firstChild.data = String(children);
|
|
2127
1177
|
} else {
|
|
2128
|
-
|
|
2129
|
-
if (dom) {
|
|
2130
|
-
finalNodes.push(dom);
|
|
2131
|
-
created++;
|
|
2132
|
-
}
|
|
1178
|
+
el.textContent = String(children);
|
|
2133
1179
|
}
|
|
1180
|
+
return;
|
|
2134
1181
|
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
);
|
|
2139
|
-
for (const n of toRemove) cleanupInstanceIfPresent(n);
|
|
2140
|
-
} catch (e) {
|
|
2141
|
-
void e;
|
|
1182
|
+
if (Array.isArray(children)) {
|
|
1183
|
+
updateUnkeyedChildren(el, children);
|
|
1184
|
+
return;
|
|
2142
1185
|
}
|
|
2143
|
-
|
|
2144
|
-
const
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
const clone = /* @__PURE__ */ new Map();
|
|
2152
|
-
for (const [k, v] of map) clone.set(k, v);
|
|
2153
|
-
listenerSnapshots[i] = clone;
|
|
2154
|
-
}
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
} catch (e) {
|
|
2158
|
-
void e;
|
|
1186
|
+
el.textContent = "";
|
|
1187
|
+
const dom = createDOMNode(children);
|
|
1188
|
+
if (dom) el.appendChild(dom);
|
|
1189
|
+
}
|
|
1190
|
+
function updateUnkeyedChildren(parent, newChildren) {
|
|
1191
|
+
const existing = Array.from(parent.children);
|
|
1192
|
+
if (existing.length === 0 && parent.childNodes.length > 0) {
|
|
1193
|
+
parent.textContent = "";
|
|
2159
1194
|
}
|
|
2160
|
-
const
|
|
2161
|
-
for (let i = 0; i <
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
1195
|
+
const max = Math.max(existing.length, newChildren.length);
|
|
1196
|
+
for (let i = 0; i < max; i++) {
|
|
1197
|
+
const current2 = existing[i];
|
|
1198
|
+
const next = newChildren[i];
|
|
1199
|
+
if (next === void 0 && current2) {
|
|
1200
|
+
cleanupInstanceIfPresent(current2);
|
|
1201
|
+
current2.remove();
|
|
1202
|
+
continue;
|
|
1203
|
+
}
|
|
1204
|
+
if (!current2 && next !== void 0) {
|
|
1205
|
+
const dom = createDOMNode(next);
|
|
1206
|
+
if (dom) parent.appendChild(dom);
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
if (!current2 || next === void 0) continue;
|
|
1210
|
+
if (typeof next === "string" || typeof next === "number") {
|
|
1211
|
+
current2.textContent = String(next);
|
|
1212
|
+
} else if (_isDOMElement(next)) {
|
|
1213
|
+
if (typeof next.type === "string") {
|
|
1214
|
+
if (current2.tagName.toLowerCase() === next.type.toLowerCase()) {
|
|
1215
|
+
updateElementFromVnode(current2, next);
|
|
1216
|
+
} else {
|
|
1217
|
+
const dom = createDOMNode(next);
|
|
1218
|
+
if (dom) {
|
|
1219
|
+
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1220
|
+
cleanupInstanceIfPresent(current2);
|
|
1221
|
+
parent.replaceChild(dom, current2);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
} else {
|
|
1225
|
+
const dom = createDOMNode(next);
|
|
1226
|
+
if (dom) {
|
|
1227
|
+
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1228
|
+
cleanupInstanceIfPresent(current2);
|
|
1229
|
+
parent.replaceChild(dom, current2);
|
|
2176
1230
|
}
|
|
2177
1231
|
}
|
|
1232
|
+
} else {
|
|
1233
|
+
const dom = createDOMNode(next);
|
|
1234
|
+
if (dom) {
|
|
1235
|
+
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1236
|
+
cleanupInstanceIfPresent(current2);
|
|
1237
|
+
parent.replaceChild(dom, current2);
|
|
1238
|
+
}
|
|
2178
1239
|
}
|
|
2179
|
-
} catch (e) {
|
|
2180
|
-
void e;
|
|
2181
|
-
}
|
|
2182
|
-
try {
|
|
2183
|
-
keyedElements.delete(parent);
|
|
2184
|
-
} catch (e) {
|
|
2185
|
-
void e;
|
|
2186
1240
|
}
|
|
2187
|
-
const t = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
|
|
2188
|
-
const stats = {
|
|
2189
|
-
n: total,
|
|
2190
|
-
reused,
|
|
2191
|
-
created,
|
|
2192
|
-
t
|
|
2193
|
-
};
|
|
2194
|
-
return stats;
|
|
2195
1241
|
}
|
|
2196
1242
|
function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
|
|
2197
1243
|
const total = keyedVnodes.length;
|
|
@@ -2205,6 +1251,18 @@ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
|
|
|
2205
1251
|
const vnodeType = vnode.type;
|
|
2206
1252
|
if (ch.tagName.toLowerCase() === vnodeType.toLowerCase()) {
|
|
2207
1253
|
const children = vnode.children || vnode.props?.children;
|
|
1254
|
+
try {
|
|
1255
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1256
|
+
logger.warn("[Askr][FASTPATH] positional idx", i, {
|
|
1257
|
+
chTag: ch.tagName.toLowerCase(),
|
|
1258
|
+
vnodeType,
|
|
1259
|
+
chChildNodes: ch.childNodes.length,
|
|
1260
|
+
childrenType: Array.isArray(children) ? "array" : typeof children
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
} catch (e) {
|
|
1264
|
+
void e;
|
|
1265
|
+
}
|
|
2208
1266
|
if (typeof children === "string" || typeof children === "number") {
|
|
2209
1267
|
if (ch.childNodes.length === 1 && ch.firstChild?.nodeType === 3) {
|
|
2210
1268
|
ch.firstChild.data = String(children);
|
|
@@ -2228,6 +1286,27 @@ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
|
|
|
2228
1286
|
}
|
|
2229
1287
|
reused++;
|
|
2230
1288
|
continue;
|
|
1289
|
+
} else {
|
|
1290
|
+
try {
|
|
1291
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1292
|
+
logger.warn("[Askr][FASTPATH] positional tag mismatch", i, {
|
|
1293
|
+
chTag: ch.tagName.toLowerCase(),
|
|
1294
|
+
vnodeType
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
} catch (e) {
|
|
1298
|
+
void e;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
} else {
|
|
1302
|
+
try {
|
|
1303
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1304
|
+
logger.warn("[Askr][FASTPATH] positional missing or invalid", i, {
|
|
1305
|
+
ch: !!ch
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
} catch (e) {
|
|
1309
|
+
void e;
|
|
2231
1310
|
}
|
|
2232
1311
|
}
|
|
2233
1312
|
const dom = createDOMNode(vnode);
|
|
@@ -2251,12 +1330,99 @@ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
|
|
|
2251
1330
|
} catch (e) {
|
|
2252
1331
|
void e;
|
|
2253
1332
|
}
|
|
1333
|
+
const stats = { n: total, reused, updatedKeys, t };
|
|
1334
|
+
try {
|
|
1335
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1336
|
+
logger.warn("[Askr][FASTPATH] bulk positional stats", stats);
|
|
1337
|
+
}
|
|
1338
|
+
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1339
|
+
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1340
|
+
__ASKR_incCounter("bulkKeyedPositionalHits");
|
|
1341
|
+
} catch (e) {
|
|
1342
|
+
void e;
|
|
1343
|
+
}
|
|
1344
|
+
return stats;
|
|
1345
|
+
}
|
|
1346
|
+
function performBulkTextReplace(parent, newChildren) {
|
|
1347
|
+
const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
1348
|
+
const existing = Array.from(parent.childNodes);
|
|
1349
|
+
const finalNodes = [];
|
|
1350
|
+
let reused = 0;
|
|
1351
|
+
let created = 0;
|
|
1352
|
+
for (let i = 0; i < newChildren.length; i++) {
|
|
1353
|
+
const vnode = newChildren[i];
|
|
1354
|
+
const existingNode = existing[i];
|
|
1355
|
+
if (typeof vnode === "string" || typeof vnode === "number") {
|
|
1356
|
+
const text = String(vnode);
|
|
1357
|
+
if (existingNode && existingNode.nodeType === 3) {
|
|
1358
|
+
existingNode.data = text;
|
|
1359
|
+
finalNodes.push(existingNode);
|
|
1360
|
+
reused++;
|
|
1361
|
+
} else {
|
|
1362
|
+
finalNodes.push(document.createTextNode(text));
|
|
1363
|
+
created++;
|
|
1364
|
+
}
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (typeof vnode === "object" && vnode !== null && "type" in vnode) {
|
|
1368
|
+
const vnodeObj = vnode;
|
|
1369
|
+
if (typeof vnodeObj.type === "string") {
|
|
1370
|
+
const tag = vnodeObj.type;
|
|
1371
|
+
if (existingNode && existingNode.nodeType === 1 && existingNode.tagName.toLowerCase() === tag.toLowerCase()) {
|
|
1372
|
+
updateElementFromVnode(existingNode, vnode);
|
|
1373
|
+
finalNodes.push(existingNode);
|
|
1374
|
+
reused++;
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const dom = createDOMNode(vnode);
|
|
1379
|
+
if (dom) {
|
|
1380
|
+
finalNodes.push(dom);
|
|
1381
|
+
created++;
|
|
1382
|
+
continue;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
const tBuild = (typeof performance !== "undefined" && performance.now ? performance.now() : Date.now()) - t0;
|
|
1387
|
+
try {
|
|
1388
|
+
const toRemove = Array.from(parent.childNodes).filter(
|
|
1389
|
+
(n) => !finalNodes.includes(n)
|
|
1390
|
+
);
|
|
1391
|
+
for (const n of toRemove) {
|
|
1392
|
+
if (n instanceof Element) removeAllListeners(n);
|
|
1393
|
+
cleanupInstanceIfPresent(n);
|
|
1394
|
+
}
|
|
1395
|
+
} catch (e) {
|
|
1396
|
+
void e;
|
|
1397
|
+
}
|
|
1398
|
+
const fragStart = Date.now();
|
|
1399
|
+
const fragment = document.createDocumentFragment();
|
|
1400
|
+
for (let i = 0; i < finalNodes.length; i++)
|
|
1401
|
+
fragment.appendChild(finalNodes[i]);
|
|
1402
|
+
try {
|
|
1403
|
+
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
1404
|
+
__ASKR_set("__LAST_DOM_REPLACE_STACK_DOM", new Error().stack);
|
|
1405
|
+
} catch (e) {
|
|
1406
|
+
void e;
|
|
1407
|
+
}
|
|
1408
|
+
parent.replaceChildren(fragment);
|
|
1409
|
+
const tCommit = Date.now() - fragStart;
|
|
1410
|
+
keyedElements.delete(parent);
|
|
2254
1411
|
const stats = {
|
|
2255
|
-
n:
|
|
1412
|
+
n: newChildren.length,
|
|
2256
1413
|
reused,
|
|
2257
|
-
|
|
2258
|
-
|
|
1414
|
+
created,
|
|
1415
|
+
tBuild,
|
|
1416
|
+
tCommit
|
|
2259
1417
|
};
|
|
1418
|
+
try {
|
|
1419
|
+
__ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
|
|
1420
|
+
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1421
|
+
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1422
|
+
__ASKR_incCounter("bulkTextFastpathHits");
|
|
1423
|
+
} catch (e) {
|
|
1424
|
+
void e;
|
|
1425
|
+
}
|
|
2260
1426
|
return stats;
|
|
2261
1427
|
}
|
|
2262
1428
|
function isBulkTextFastPathEligible(parent, newChildren) {
|
|
@@ -2266,12 +1432,12 @@ function isBulkTextFastPathEligible(parent, newChildren) {
|
|
|
2266
1432
|
if (total < threshold) {
|
|
2267
1433
|
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
2268
1434
|
try {
|
|
2269
|
-
|
|
1435
|
+
__ASKR_set("__BULK_DIAG", {
|
|
2270
1436
|
phase: "bulk-unkeyed-eligible",
|
|
2271
1437
|
reason: "too-small",
|
|
2272
1438
|
total,
|
|
2273
1439
|
threshold
|
|
2274
|
-
};
|
|
1440
|
+
});
|
|
2275
1441
|
} catch (e) {
|
|
2276
1442
|
void e;
|
|
2277
1443
|
}
|
|
@@ -2290,11 +1456,11 @@ function isBulkTextFastPathEligible(parent, newChildren) {
|
|
|
2290
1456
|
if (typeof dv.type === "function") {
|
|
2291
1457
|
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
2292
1458
|
try {
|
|
2293
|
-
|
|
1459
|
+
__ASKR_set("__BULK_DIAG", {
|
|
2294
1460
|
phase: "bulk-unkeyed-eligible",
|
|
2295
1461
|
reason: "component-child",
|
|
2296
1462
|
index: i
|
|
2297
|
-
};
|
|
1463
|
+
});
|
|
2298
1464
|
} catch (e) {
|
|
2299
1465
|
void e;
|
|
2300
1466
|
}
|
|
@@ -2323,438 +1489,806 @@ function isBulkTextFastPathEligible(parent, newChildren) {
|
|
|
2323
1489
|
const eligible = fraction >= requiredFraction && parent.childNodes.length >= total;
|
|
2324
1490
|
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
2325
1491
|
try {
|
|
2326
|
-
|
|
1492
|
+
__ASKR_set("__BULK_DIAG", {
|
|
2327
1493
|
phase: "bulk-unkeyed-eligible",
|
|
2328
1494
|
total,
|
|
2329
1495
|
simple,
|
|
2330
1496
|
fraction,
|
|
2331
1497
|
requiredFraction,
|
|
2332
1498
|
eligible
|
|
2333
|
-
};
|
|
1499
|
+
});
|
|
2334
1500
|
} catch (e) {
|
|
2335
1501
|
void e;
|
|
2336
1502
|
}
|
|
2337
1503
|
}
|
|
2338
1504
|
return eligible;
|
|
2339
1505
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
1506
|
+
var IS_DOM_AVAILABLE;
|
|
1507
|
+
var init_dom = __esm({
|
|
1508
|
+
"src/renderer/dom.ts"() {
|
|
1509
|
+
"use strict";
|
|
1510
|
+
init_scheduler();
|
|
1511
|
+
init_logger();
|
|
1512
|
+
init_jsx_runtime();
|
|
1513
|
+
init_context();
|
|
1514
|
+
init_component();
|
|
1515
|
+
init_cleanup();
|
|
1516
|
+
init_diag();
|
|
1517
|
+
init_types();
|
|
1518
|
+
init_keyed();
|
|
1519
|
+
IS_DOM_AVAILABLE = typeof document !== "undefined";
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
|
|
1523
|
+
// src/renderer/fastpath.ts
|
|
1524
|
+
function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
|
|
1525
|
+
if (typeof document === "undefined") return null;
|
|
1526
|
+
const totalKeyed = keyedVnodes.length;
|
|
1527
|
+
if (totalKeyed === 0 && (!unkeyedVnodes || unkeyedVnodes.length === 0))
|
|
1528
|
+
return null;
|
|
1529
|
+
if (!isSchedulerExecuting()) {
|
|
1530
|
+
logger.warn(
|
|
1531
|
+
"[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
let parentChildrenArr;
|
|
1535
|
+
let localOldKeyMap;
|
|
1536
|
+
if (totalKeyed <= 20) {
|
|
1537
|
+
try {
|
|
1538
|
+
const pc = parent.children;
|
|
1539
|
+
parentChildrenArr = new Array(pc.length);
|
|
1540
|
+
for (let i = 0; i < pc.length; i++)
|
|
1541
|
+
parentChildrenArr[i] = pc[i];
|
|
1542
|
+
} catch (e) {
|
|
1543
|
+
parentChildrenArr = void 0;
|
|
1544
|
+
void e;
|
|
1545
|
+
}
|
|
1546
|
+
} else {
|
|
1547
|
+
localOldKeyMap = /* @__PURE__ */ new Map();
|
|
1548
|
+
try {
|
|
1549
|
+
const parentChildren = Array.from(parent.children);
|
|
1550
|
+
for (let i = 0; i < parentChildren.length; i++) {
|
|
1551
|
+
const ch = parentChildren[i];
|
|
1552
|
+
const k = ch.getAttribute("data-key");
|
|
1553
|
+
if (k !== null) {
|
|
1554
|
+
localOldKeyMap.set(k, ch);
|
|
1555
|
+
const n = Number(k);
|
|
1556
|
+
if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
|
|
1557
|
+
}
|
|
2358
1558
|
}
|
|
2359
|
-
|
|
1559
|
+
} catch (e) {
|
|
1560
|
+
localOldKeyMap = void 0;
|
|
1561
|
+
void e;
|
|
2360
1562
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
1563
|
+
}
|
|
1564
|
+
const finalNodes = [];
|
|
1565
|
+
let mapLookups = 0;
|
|
1566
|
+
let createdNodes = 0;
|
|
1567
|
+
let reusedCount = 0;
|
|
1568
|
+
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1569
|
+
const { key, vnode } = keyedVnodes[i];
|
|
1570
|
+
mapLookups++;
|
|
1571
|
+
let el;
|
|
1572
|
+
if (totalKeyed <= 20 && parentChildrenArr) {
|
|
1573
|
+
const ks = String(key);
|
|
1574
|
+
for (let j = 0; j < parentChildrenArr.length; j++) {
|
|
1575
|
+
const ch = parentChildrenArr[j];
|
|
1576
|
+
const k = ch.getAttribute("data-key");
|
|
1577
|
+
if (k !== null && (k === ks || Number(k) === key)) {
|
|
1578
|
+
el = ch;
|
|
1579
|
+
break;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
if (!el) el = oldKeyMap?.get(key);
|
|
1583
|
+
} else {
|
|
1584
|
+
el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
|
|
1585
|
+
}
|
|
1586
|
+
if (el) {
|
|
1587
|
+
finalNodes.push(el);
|
|
1588
|
+
reusedCount++;
|
|
1589
|
+
} else {
|
|
1590
|
+
const newEl = createDOMNode(vnode);
|
|
1591
|
+
if (newEl) {
|
|
1592
|
+
finalNodes.push(newEl);
|
|
1593
|
+
createdNodes++;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
if (unkeyedVnodes && unkeyedVnodes.length) {
|
|
1598
|
+
for (const vnode of unkeyedVnodes) {
|
|
1599
|
+
const newEl = createDOMNode(vnode);
|
|
1600
|
+
if (newEl) {
|
|
1601
|
+
finalNodes.push(newEl);
|
|
1602
|
+
createdNodes++;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
try {
|
|
1607
|
+
const tFragmentStart = Date.now();
|
|
1608
|
+
const fragment = document.createDocumentFragment();
|
|
1609
|
+
let fragmentAppendCount = 0;
|
|
1610
|
+
for (let i = 0; i < finalNodes.length; i++) {
|
|
1611
|
+
fragment.appendChild(finalNodes[i]);
|
|
1612
|
+
fragmentAppendCount++;
|
|
1613
|
+
}
|
|
1614
|
+
try {
|
|
1615
|
+
const existing = Array.from(parent.childNodes);
|
|
1616
|
+
const toRemove = existing.filter((n) => !finalNodes.includes(n));
|
|
1617
|
+
for (const n of toRemove) {
|
|
1618
|
+
if (n instanceof Element) removeAllListeners(n);
|
|
1619
|
+
cleanupInstanceIfPresent(n);
|
|
1620
|
+
}
|
|
1621
|
+
} catch (e) {
|
|
1622
|
+
void e;
|
|
1623
|
+
}
|
|
1624
|
+
try {
|
|
1625
|
+
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
1626
|
+
__ASKR_set("__LAST_DOM_REPLACE_STACK_FASTPATH", new Error().stack);
|
|
1627
|
+
} catch (e) {
|
|
1628
|
+
void e;
|
|
1629
|
+
}
|
|
1630
|
+
parent.replaceChildren(fragment);
|
|
1631
|
+
try {
|
|
1632
|
+
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1633
|
+
} catch (e) {
|
|
1634
|
+
void e;
|
|
1635
|
+
}
|
|
1636
|
+
try {
|
|
1637
|
+
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1638
|
+
} catch (e) {
|
|
1639
|
+
void e;
|
|
1640
|
+
}
|
|
1641
|
+
const newKeyMap = /* @__PURE__ */ new Map();
|
|
1642
|
+
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1643
|
+
const key = keyedVnodes[i].key;
|
|
1644
|
+
const node = finalNodes[i];
|
|
1645
|
+
if (node instanceof Element) newKeyMap.set(key, node);
|
|
1646
|
+
}
|
|
1647
|
+
try {
|
|
1648
|
+
const stats = {
|
|
1649
|
+
n: totalKeyed,
|
|
1650
|
+
moves: 0,
|
|
1651
|
+
lisLen: 0,
|
|
1652
|
+
t_lookup: 0,
|
|
1653
|
+
t_fragment: Date.now() - tFragmentStart,
|
|
1654
|
+
t_commit: 0,
|
|
1655
|
+
t_bookkeeping: 0,
|
|
1656
|
+
fragmentAppendCount,
|
|
1657
|
+
mapLookups,
|
|
1658
|
+
createdNodes,
|
|
1659
|
+
reusedCount
|
|
1660
|
+
};
|
|
1661
|
+
if (typeof globalThis !== "undefined") {
|
|
1662
|
+
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1663
|
+
__ASKR_set("__LAST_FASTPATH_REUSED", reusedCount > 0);
|
|
1664
|
+
__ASKR_incCounter("fastpathHistoryPush");
|
|
1665
|
+
}
|
|
1666
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1667
|
+
logger.warn(
|
|
1668
|
+
"[Askr][FASTPATH]",
|
|
1669
|
+
JSON.stringify({ n: totalKeyed, createdNodes, reusedCount })
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
} catch (e) {
|
|
1673
|
+
void e;
|
|
1674
|
+
}
|
|
1675
|
+
try {
|
|
1676
|
+
_reconcilerRecordedParents.add(parent);
|
|
1677
|
+
} catch (e) {
|
|
1678
|
+
void e;
|
|
1679
|
+
}
|
|
1680
|
+
return newKeyMap;
|
|
1681
|
+
} catch (e) {
|
|
1682
|
+
void e;
|
|
1683
|
+
return null;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
var init_fastpath = __esm({
|
|
1687
|
+
"src/renderer/fastpath.ts"() {
|
|
1688
|
+
"use strict";
|
|
1689
|
+
init_dom();
|
|
1690
|
+
init_keyed();
|
|
1691
|
+
init_logger();
|
|
1692
|
+
init_cleanup();
|
|
1693
|
+
init_diag();
|
|
1694
|
+
init_scheduler();
|
|
1695
|
+
init_fastlane_shared();
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
// src/renderer/reconcile.ts
|
|
1700
|
+
function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
|
|
1701
|
+
const newKeyMap = /* @__PURE__ */ new Map();
|
|
1702
|
+
const keyedVnodes = [];
|
|
1703
|
+
const unkeyedVnodes = [];
|
|
1704
|
+
for (let i = 0; i < newChildren.length; i++) {
|
|
1705
|
+
const child = newChildren[i];
|
|
1706
|
+
if (typeof child === "object" && child !== null && "type" in child) {
|
|
1707
|
+
const childObj = child;
|
|
1708
|
+
const rawKey = childObj.key ?? childObj.props?.key;
|
|
1709
|
+
if (rawKey !== void 0) {
|
|
1710
|
+
const key = typeof rawKey === "symbol" ? String(rawKey) : rawKey;
|
|
1711
|
+
keyedVnodes.push({ key, vnode: child });
|
|
1712
|
+
} else {
|
|
1713
|
+
unkeyedVnodes.push(child);
|
|
1714
|
+
}
|
|
1715
|
+
} else {
|
|
1716
|
+
unkeyedVnodes.push(child);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
try {
|
|
1720
|
+
const decision = isKeyedReorderFastPathEligible(
|
|
1721
|
+
parent,
|
|
1722
|
+
newChildren,
|
|
1723
|
+
oldKeyMap
|
|
1724
|
+
);
|
|
1725
|
+
if (decision.useFastPath && keyedVnodes.length >= 128 || // If we're executing inside a runtime bulk commit (fastlane), prefer the
|
|
1726
|
+
// renderer fast-path to ensure the single-commit invariant is preserved.
|
|
1727
|
+
isBulkCommitActive2()) {
|
|
1728
|
+
try {
|
|
1729
|
+
const map = applyRendererFastPath(
|
|
1730
|
+
parent,
|
|
1731
|
+
keyedVnodes,
|
|
1732
|
+
oldKeyMap,
|
|
1733
|
+
unkeyedVnodes
|
|
1734
|
+
);
|
|
1735
|
+
if (map) {
|
|
1736
|
+
try {
|
|
1737
|
+
keyedElements.set(parent, map);
|
|
1738
|
+
} catch (e) {
|
|
1739
|
+
void e;
|
|
1740
|
+
}
|
|
1741
|
+
return map;
|
|
1742
|
+
}
|
|
1743
|
+
} catch (e) {
|
|
1744
|
+
void e;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
try {
|
|
1748
|
+
const total = keyedVnodes.length;
|
|
1749
|
+
if (total >= 10) {
|
|
1750
|
+
let matchCount = 0;
|
|
1751
|
+
try {
|
|
1752
|
+
for (let i = 0; i < total; i++) {
|
|
1753
|
+
const vnode = keyedVnodes[i].vnode;
|
|
1754
|
+
if (!vnode || typeof vnode !== "object" || typeof vnode.type !== "string")
|
|
1755
|
+
continue;
|
|
1756
|
+
const el = parent.children[i];
|
|
1757
|
+
if (!el) continue;
|
|
1758
|
+
if (el.tagName.toLowerCase() === String(vnode.type).toLowerCase())
|
|
1759
|
+
matchCount++;
|
|
1760
|
+
}
|
|
1761
|
+
} catch (e) {
|
|
1762
|
+
void e;
|
|
1763
|
+
}
|
|
1764
|
+
if (matchCount / total >= 0.9) {
|
|
1765
|
+
let hasPropChanges = false;
|
|
1766
|
+
try {
|
|
1767
|
+
for (let i = 0; i < total; i++) {
|
|
1768
|
+
const vnode = keyedVnodes[i].vnode;
|
|
1769
|
+
const el = parent.children[i];
|
|
1770
|
+
if (!el || !vnode || typeof vnode !== "object") continue;
|
|
1771
|
+
const props = vnode.props || {};
|
|
1772
|
+
for (const k of Object.keys(props)) {
|
|
1773
|
+
if (k === "children" || k === "key") continue;
|
|
1774
|
+
if (k.startsWith("on") && k.length > 2) continue;
|
|
1775
|
+
if (k.startsWith("data-")) continue;
|
|
1776
|
+
const v = props[k];
|
|
1777
|
+
try {
|
|
1778
|
+
if (k === "class" || k === "className") {
|
|
1779
|
+
if (el.className !== String(v)) {
|
|
1780
|
+
hasPropChanges = true;
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
} else if (k === "value" || k === "checked") {
|
|
1784
|
+
if (el[k] !== v) {
|
|
1785
|
+
hasPropChanges = true;
|
|
1786
|
+
break;
|
|
1787
|
+
}
|
|
1788
|
+
} else {
|
|
1789
|
+
const attr = el.getAttribute(k);
|
|
1790
|
+
if (v === void 0 || v === null || v === false) {
|
|
1791
|
+
if (attr !== null) {
|
|
1792
|
+
hasPropChanges = true;
|
|
1793
|
+
break;
|
|
1794
|
+
}
|
|
1795
|
+
} else if (String(v) !== attr) {
|
|
1796
|
+
hasPropChanges = true;
|
|
1797
|
+
break;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
} catch (e) {
|
|
1801
|
+
hasPropChanges = true;
|
|
1802
|
+
void e;
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
if (hasPropChanges) break;
|
|
2378
1807
|
}
|
|
1808
|
+
} catch (e) {
|
|
1809
|
+
void e;
|
|
1810
|
+
}
|
|
1811
|
+
if (hasPropChanges) {
|
|
2379
1812
|
} else {
|
|
2380
|
-
|
|
1813
|
+
try {
|
|
1814
|
+
const stats = performBulkPositionalKeyedTextUpdate(
|
|
1815
|
+
parent,
|
|
1816
|
+
keyedVnodes
|
|
1817
|
+
);
|
|
1818
|
+
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1819
|
+
try {
|
|
1820
|
+
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1821
|
+
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1822
|
+
__ASKR_incCounter("bulkKeyedPositionalHits");
|
|
1823
|
+
} catch (e) {
|
|
1824
|
+
void e;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
try {
|
|
1828
|
+
const map = /* @__PURE__ */ new Map();
|
|
1829
|
+
const children = Array.from(parent.children);
|
|
1830
|
+
for (let i = 0; i < children.length; i++) {
|
|
1831
|
+
const el = children[i];
|
|
1832
|
+
const k = el.getAttribute("data-key");
|
|
1833
|
+
if (k !== null) {
|
|
1834
|
+
map.set(k, el);
|
|
1835
|
+
const n = Number(k);
|
|
1836
|
+
if (!Number.isNaN(n)) map.set(n, el);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
keyedElements.set(parent, map);
|
|
1840
|
+
} catch (e) {
|
|
1841
|
+
void e;
|
|
1842
|
+
}
|
|
1843
|
+
return keyedElements.get(parent);
|
|
1844
|
+
} catch (e) {
|
|
1845
|
+
void e;
|
|
1846
|
+
}
|
|
2381
1847
|
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
} catch (e) {
|
|
1851
|
+
void e;
|
|
1852
|
+
}
|
|
1853
|
+
} catch (e) {
|
|
1854
|
+
void e;
|
|
1855
|
+
}
|
|
1856
|
+
const finalNodes = [];
|
|
1857
|
+
const usedOldEls = /* @__PURE__ */ new WeakSet();
|
|
1858
|
+
const resolveOldElOnce = (k) => {
|
|
1859
|
+
if (!oldKeyMap) return void 0;
|
|
1860
|
+
const direct = oldKeyMap.get(k);
|
|
1861
|
+
if (direct && !usedOldEls.has(direct)) {
|
|
1862
|
+
usedOldEls.add(direct);
|
|
1863
|
+
return direct;
|
|
1864
|
+
}
|
|
1865
|
+
const s = String(k);
|
|
1866
|
+
const byString = oldKeyMap.get(s);
|
|
1867
|
+
if (byString && !usedOldEls.has(byString)) {
|
|
1868
|
+
usedOldEls.add(byString);
|
|
1869
|
+
return byString;
|
|
1870
|
+
}
|
|
1871
|
+
const n = Number(String(k));
|
|
1872
|
+
if (!Number.isNaN(n)) {
|
|
1873
|
+
const byNum = oldKeyMap.get(n);
|
|
1874
|
+
if (byNum && !usedOldEls.has(byNum)) {
|
|
1875
|
+
usedOldEls.add(byNum);
|
|
1876
|
+
return byNum;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
try {
|
|
1880
|
+
const children = Array.from(parent.children);
|
|
1881
|
+
for (const ch of children) {
|
|
1882
|
+
if (usedOldEls.has(ch)) continue;
|
|
1883
|
+
const attr = ch.getAttribute("data-key");
|
|
1884
|
+
if (attr === s) {
|
|
1885
|
+
usedOldEls.add(ch);
|
|
1886
|
+
return ch;
|
|
1887
|
+
}
|
|
1888
|
+
const numAttr = Number(attr);
|
|
1889
|
+
if (!Number.isNaN(numAttr) && numAttr === k) {
|
|
1890
|
+
usedOldEls.add(ch);
|
|
1891
|
+
return ch;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
} catch (e) {
|
|
1895
|
+
void e;
|
|
1896
|
+
}
|
|
1897
|
+
return void 0;
|
|
1898
|
+
};
|
|
1899
|
+
for (let i = 0; i < newChildren.length; i++) {
|
|
1900
|
+
const child = newChildren[i];
|
|
1901
|
+
if (typeof child === "object" && child !== null && "type" in child) {
|
|
1902
|
+
const childObj = child;
|
|
1903
|
+
const rawKey = childObj.key ?? childObj.props?.key;
|
|
1904
|
+
if (rawKey !== void 0) {
|
|
1905
|
+
const key = typeof rawKey === "symbol" ? String(rawKey) : rawKey;
|
|
1906
|
+
const el = resolveOldElOnce(key);
|
|
1907
|
+
if (el && el.parentElement === parent) {
|
|
1908
|
+
updateElementFromVnode(el, child);
|
|
2382
1909
|
finalNodes.push(el);
|
|
2383
|
-
|
|
1910
|
+
newKeyMap.set(key, el);
|
|
2384
1911
|
continue;
|
|
2385
1912
|
}
|
|
2386
|
-
const dom2 = createDOMNode(
|
|
1913
|
+
const dom2 = createDOMNode(child);
|
|
2387
1914
|
if (dom2) {
|
|
2388
1915
|
finalNodes.push(dom2);
|
|
2389
|
-
|
|
1916
|
+
if (dom2 instanceof Element) newKeyMap.set(key, dom2);
|
|
2390
1917
|
}
|
|
2391
1918
|
continue;
|
|
2392
1919
|
}
|
|
2393
1920
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
1921
|
+
try {
|
|
1922
|
+
const existing = parent.children[i];
|
|
1923
|
+
if (existing && (typeof child === "string" || typeof child === "number") && existing.nodeType === 1) {
|
|
1924
|
+
existing.textContent = String(child);
|
|
1925
|
+
finalNodes.push(existing);
|
|
1926
|
+
usedOldEls.add(existing);
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
if (existing && typeof child === "object" && child !== null && "type" in child && (existing.getAttribute("data-key") === null || existing.getAttribute("data-key") === void 0) && typeof child.type === "string" && existing.tagName.toLowerCase() === String(child.type).toLowerCase()) {
|
|
1930
|
+
updateElementFromVnode(existing, child);
|
|
1931
|
+
finalNodes.push(existing);
|
|
1932
|
+
usedOldEls.add(existing);
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
try {
|
|
1936
|
+
const avail = Array.from(parent.children).find(
|
|
1937
|
+
(ch) => !usedOldEls.has(ch) && ch.getAttribute("data-key") === null
|
|
1938
|
+
);
|
|
1939
|
+
if (avail) {
|
|
1940
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
1941
|
+
avail.textContent = String(child);
|
|
1942
|
+
} else if (typeof child === "object" && child !== null && "type" in child && typeof child.type === "string" && avail.tagName.toLowerCase() === String(child.type).toLowerCase()) {
|
|
1943
|
+
updateElementFromVnode(avail, child);
|
|
1944
|
+
} else {
|
|
1945
|
+
const dom2 = createDOMNode(child);
|
|
1946
|
+
if (dom2) {
|
|
1947
|
+
finalNodes.push(dom2);
|
|
1948
|
+
continue;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
usedOldEls.add(avail);
|
|
1952
|
+
finalNodes.push(avail);
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
} catch (e) {
|
|
1956
|
+
void e;
|
|
1957
|
+
}
|
|
1958
|
+
} catch (e) {
|
|
1959
|
+
void e;
|
|
1960
|
+
}
|
|
1961
|
+
const dom = createDOMNode(child);
|
|
1962
|
+
if (dom) finalNodes.push(dom);
|
|
1963
|
+
}
|
|
1964
|
+
if (typeof document === "undefined") return newKeyMap;
|
|
1965
|
+
const fragment = document.createDocumentFragment();
|
|
1966
|
+
for (let i = 0; i < finalNodes.length; i++)
|
|
1967
|
+
fragment.appendChild(finalNodes[i]);
|
|
1968
|
+
try {
|
|
1969
|
+
const existing = Array.from(parent.childNodes);
|
|
1970
|
+
for (const n of existing) {
|
|
1971
|
+
if (n instanceof Element) removeAllListeners(n);
|
|
1972
|
+
cleanupInstanceIfPresent(n);
|
|
2398
1973
|
}
|
|
1974
|
+
} catch (e) {
|
|
1975
|
+
void e;
|
|
2399
1976
|
}
|
|
2400
|
-
const tBuild = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
|
|
2401
1977
|
try {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
);
|
|
2405
|
-
for (const n of toRemove) cleanupInstanceIfPresent(n);
|
|
1978
|
+
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
1979
|
+
__ASKR_set("__LAST_DOM_REPLACE_STACK_RECONCILE", new Error().stack);
|
|
2406
1980
|
} catch (e) {
|
|
2407
1981
|
void e;
|
|
2408
1982
|
}
|
|
2409
|
-
const fragStart = Date.now();
|
|
2410
|
-
const fragment = document.createDocumentFragment();
|
|
2411
|
-
for (let i = 0; i < finalNodes.length; i++)
|
|
2412
|
-
fragment.appendChild(finalNodes[i]);
|
|
2413
1983
|
parent.replaceChildren(fragment);
|
|
2414
|
-
const tCommit = Date.now() - fragStart;
|
|
2415
1984
|
keyedElements.delete(parent);
|
|
2416
|
-
|
|
2417
|
-
n: newChildren.length,
|
|
2418
|
-
reused,
|
|
2419
|
-
created,
|
|
2420
|
-
tBuild,
|
|
2421
|
-
tCommit
|
|
2422
|
-
};
|
|
2423
|
-
return stats;
|
|
1985
|
+
return newKeyMap;
|
|
2424
1986
|
}
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
1987
|
+
var init_reconcile = __esm({
|
|
1988
|
+
"src/renderer/reconcile.ts"() {
|
|
1989
|
+
"use strict";
|
|
1990
|
+
init_dom();
|
|
1991
|
+
init_keyed();
|
|
1992
|
+
init_cleanup();
|
|
1993
|
+
init_fastlane_shared();
|
|
1994
|
+
init_diag();
|
|
1995
|
+
init_fastpath();
|
|
2432
1996
|
}
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
const entry = existingListeners.get(eventName);
|
|
2445
|
-
el.removeEventListener(eventName, entry.handler);
|
|
2446
|
-
existingListeners.delete(eventName);
|
|
2447
|
-
}
|
|
2448
|
-
continue;
|
|
2449
|
-
} else {
|
|
2450
|
-
el.removeAttribute(key);
|
|
1997
|
+
});
|
|
1998
|
+
|
|
1999
|
+
// src/renderer/evaluate.ts
|
|
2000
|
+
function evaluate(node, target, context) {
|
|
2001
|
+
if (!target) return;
|
|
2002
|
+
if (typeof document === "undefined") {
|
|
2003
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2004
|
+
try {
|
|
2005
|
+
console.warn("[Askr] evaluate() called in non-DOM environment; no-op.");
|
|
2006
|
+
} catch (e) {
|
|
2007
|
+
void e;
|
|
2451
2008
|
}
|
|
2452
|
-
continue;
|
|
2453
2009
|
}
|
|
2454
|
-
if (key === "class" || key === "className") {
|
|
2455
|
-
el.className = String(value);
|
|
2456
|
-
} else if (key === "value" || key === "checked") {
|
|
2457
|
-
el[key] = value;
|
|
2458
|
-
} else if (key.startsWith("on") && key.length > 2) {
|
|
2459
|
-
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
2460
|
-
desiredEventNames.add(eventName);
|
|
2461
|
-
const existing = existingListeners?.get(eventName);
|
|
2462
|
-
if (existing && existing.original === value) {
|
|
2463
|
-
continue;
|
|
2464
|
-
}
|
|
2465
|
-
if (existing) {
|
|
2466
|
-
el.removeEventListener(eventName, existing.handler);
|
|
2467
|
-
}
|
|
2468
|
-
const wrappedHandler = (event) => {
|
|
2469
|
-
globalScheduler.setInHandler(true);
|
|
2470
|
-
try {
|
|
2471
|
-
value(event);
|
|
2472
|
-
} catch (error) {
|
|
2473
|
-
logger.error("[Askr] Event handler error:", error);
|
|
2474
|
-
} finally {
|
|
2475
|
-
globalScheduler.setInHandler(false);
|
|
2476
|
-
}
|
|
2477
|
-
};
|
|
2478
|
-
el.addEventListener(eventName, wrappedHandler);
|
|
2479
|
-
if (!elementListeners.has(el)) {
|
|
2480
|
-
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
2481
|
-
}
|
|
2482
|
-
elementListeners.get(el).set(eventName, {
|
|
2483
|
-
handler: wrappedHandler,
|
|
2484
|
-
original: value
|
|
2485
|
-
});
|
|
2486
|
-
} else {
|
|
2487
|
-
el.setAttribute(key, String(value));
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
if (existingListeners) {
|
|
2491
|
-
for (const eventName of existingListeners.keys()) {
|
|
2492
|
-
const entry = existingListeners.get(eventName);
|
|
2493
|
-
if (!desiredEventNames.has(eventName)) {
|
|
2494
|
-
el.removeEventListener(eventName, entry.handler);
|
|
2495
|
-
existingListeners.delete(eventName);
|
|
2496
|
-
}
|
|
2497
|
-
}
|
|
2498
|
-
if (existingListeners.size === 0) elementListeners.delete(el);
|
|
2499
|
-
}
|
|
2500
|
-
if (updateChildren) {
|
|
2501
|
-
const children = vnode.children || props.children;
|
|
2502
|
-
updateElementChildren(el, children);
|
|
2503
|
-
}
|
|
2504
|
-
}
|
|
2505
|
-
function updateElementChildren(el, children) {
|
|
2506
|
-
if (!children) {
|
|
2507
|
-
el.textContent = "";
|
|
2508
2010
|
return;
|
|
2509
2011
|
}
|
|
2510
|
-
if (
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
}
|
|
2516
|
-
return;
|
|
2517
|
-
}
|
|
2518
|
-
if (Array.isArray(children)) {
|
|
2519
|
-
updateUnkeyedChildren(el, children);
|
|
2520
|
-
return;
|
|
2521
|
-
}
|
|
2522
|
-
el.textContent = "";
|
|
2523
|
-
const dom = createDOMNode(children);
|
|
2524
|
-
if (dom) el.appendChild(dom);
|
|
2525
|
-
}
|
|
2526
|
-
function updateUnkeyedChildren(parent, newChildren) {
|
|
2527
|
-
const existing = Array.from(parent.children);
|
|
2528
|
-
if (existing.length === 0 && parent.childNodes.length > 0) {
|
|
2529
|
-
parent.textContent = "";
|
|
2530
|
-
}
|
|
2531
|
-
const max = Math.max(existing.length, newChildren.length);
|
|
2532
|
-
for (let i = 0; i < max; i++) {
|
|
2533
|
-
const current2 = existing[i];
|
|
2534
|
-
const next = newChildren[i];
|
|
2535
|
-
if (next === void 0 && current2) {
|
|
2536
|
-
cleanupInstanceIfPresent(current2);
|
|
2012
|
+
if (context && domRanges.has(context)) {
|
|
2013
|
+
const range = domRanges.get(context);
|
|
2014
|
+
let current2 = range.start.nextSibling;
|
|
2015
|
+
while (current2 && current2 !== range.end) {
|
|
2016
|
+
const next = current2.nextSibling;
|
|
2537
2017
|
current2.remove();
|
|
2538
|
-
|
|
2018
|
+
current2 = next;
|
|
2539
2019
|
}
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
continue;
|
|
2020
|
+
const dom = createDOMNode(node);
|
|
2021
|
+
if (dom) {
|
|
2022
|
+
target.insertBefore(dom, range.end);
|
|
2544
2023
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2024
|
+
} else if (context) {
|
|
2025
|
+
const start = document.createComment("component-start");
|
|
2026
|
+
const end = document.createComment("component-end");
|
|
2027
|
+
target.appendChild(start);
|
|
2028
|
+
target.appendChild(end);
|
|
2029
|
+
domRanges.set(context, { start, end });
|
|
2030
|
+
const dom = createDOMNode(node);
|
|
2031
|
+
if (dom) {
|
|
2032
|
+
target.insertBefore(dom, end);
|
|
2033
|
+
}
|
|
2034
|
+
} else {
|
|
2035
|
+
const vnode = node;
|
|
2036
|
+
const firstChild = target.children[0];
|
|
2037
|
+
if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && firstChild.tagName.toLowerCase() === vnode.type.toLowerCase()) {
|
|
2038
|
+
const vnodeChildren = vnode.children || vnode.props?.children;
|
|
2039
|
+
let isSimpleTextVNode = false;
|
|
2040
|
+
let textContent;
|
|
2041
|
+
if (!Array.isArray(vnodeChildren)) {
|
|
2042
|
+
if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
|
|
2043
|
+
isSimpleTextVNode = true;
|
|
2044
|
+
textContent = String(vnodeChildren);
|
|
2558
2045
|
}
|
|
2559
|
-
} else {
|
|
2560
|
-
const
|
|
2561
|
-
if (
|
|
2562
|
-
|
|
2563
|
-
|
|
2046
|
+
} else if (vnodeChildren.length === 1) {
|
|
2047
|
+
const child = vnodeChildren[0];
|
|
2048
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
2049
|
+
isSimpleTextVNode = true;
|
|
2050
|
+
textContent = String(child);
|
|
2564
2051
|
}
|
|
2565
2052
|
}
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
const el = document.createElement(type);
|
|
2598
|
-
for (const key in props) {
|
|
2599
|
-
const value = props[key];
|
|
2600
|
-
if (key === "children" || key === "key") continue;
|
|
2601
|
-
if (value === void 0 || value === null || value === false) continue;
|
|
2602
|
-
if (key.startsWith("on") && key.length > 2) {
|
|
2603
|
-
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
2604
|
-
const wrappedHandler = (event) => {
|
|
2605
|
-
globalScheduler.setInHandler(true);
|
|
2606
|
-
try {
|
|
2607
|
-
value(event);
|
|
2608
|
-
} catch (error) {
|
|
2609
|
-
logger.error("[Askr] Event handler error:", error);
|
|
2610
|
-
} finally {
|
|
2611
|
-
globalScheduler.setInHandler(false);
|
|
2612
|
-
const state2 = globalScheduler.getState();
|
|
2613
|
-
if ((state2.queueLength ?? 0) > 0 && !state2.running) {
|
|
2614
|
-
queueMicrotask(() => {
|
|
2053
|
+
if (isSimpleTextVNode && firstChild.childNodes.length === 1 && firstChild.firstChild?.nodeType === 3) {
|
|
2054
|
+
firstChild.firstChild.data = textContent;
|
|
2055
|
+
} else {
|
|
2056
|
+
if (vnodeChildren) {
|
|
2057
|
+
if (Array.isArray(vnodeChildren)) {
|
|
2058
|
+
const hasKeys = vnodeChildren.some(
|
|
2059
|
+
(child) => typeof child === "object" && child !== null && "key" in child
|
|
2060
|
+
);
|
|
2061
|
+
if (hasKeys) {
|
|
2062
|
+
let oldKeyMap = keyedElements.get(firstChild);
|
|
2063
|
+
if (!oldKeyMap) {
|
|
2064
|
+
oldKeyMap = /* @__PURE__ */ new Map();
|
|
2065
|
+
try {
|
|
2066
|
+
const children = Array.from(firstChild.children);
|
|
2067
|
+
for (let i = 0; i < children.length; i++) {
|
|
2068
|
+
const ch = children[i];
|
|
2069
|
+
const k = ch.getAttribute("data-key");
|
|
2070
|
+
if (k !== null) {
|
|
2071
|
+
oldKeyMap.set(k, ch);
|
|
2072
|
+
const n = Number(k);
|
|
2073
|
+
if (!Number.isNaN(n)) oldKeyMap.set(n, ch);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
if (oldKeyMap.size > 0)
|
|
2077
|
+
keyedElements.set(firstChild, oldKeyMap);
|
|
2078
|
+
} catch (e) {
|
|
2079
|
+
void e;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
try {
|
|
2083
|
+
if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
|
|
2615
2084
|
try {
|
|
2616
|
-
|
|
2085
|
+
const keyedVnodes = [];
|
|
2086
|
+
for (let i = 0; i < vnodeChildren.length; i++) {
|
|
2087
|
+
const c = vnodeChildren[i];
|
|
2088
|
+
if (_isDOMElement(c) && c.key !== void 0) {
|
|
2089
|
+
keyedVnodes.push({
|
|
2090
|
+
key: c.key,
|
|
2091
|
+
vnode: c
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
if (keyedVnodes.length > 0 && keyedVnodes.length === vnodeChildren.length) {
|
|
2096
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
2097
|
+
logger.warn(
|
|
2098
|
+
"[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
const stats = performBulkPositionalKeyedTextUpdate(
|
|
2102
|
+
firstChild,
|
|
2103
|
+
keyedVnodes
|
|
2104
|
+
);
|
|
2105
|
+
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
2106
|
+
try {
|
|
2107
|
+
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
2108
|
+
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
2109
|
+
__ASKR_incCounter("bulkKeyedPositionalForced");
|
|
2110
|
+
} catch (e) {
|
|
2111
|
+
void e;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
try {
|
|
2115
|
+
const map = /* @__PURE__ */ new Map();
|
|
2116
|
+
const children = Array.from(firstChild.children);
|
|
2117
|
+
for (let i = 0; i < children.length; i++) {
|
|
2118
|
+
const el = children[i];
|
|
2119
|
+
const k = el.getAttribute("data-key");
|
|
2120
|
+
if (k !== null) {
|
|
2121
|
+
map.set(k, el);
|
|
2122
|
+
const n = Number(k);
|
|
2123
|
+
if (!Number.isNaN(n)) map.set(n, el);
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
keyedElements.set(firstChild, map);
|
|
2127
|
+
} catch (e) {
|
|
2128
|
+
void e;
|
|
2129
|
+
}
|
|
2130
|
+
} else {
|
|
2131
|
+
const newKeyMap = reconcileKeyedChildren(
|
|
2132
|
+
firstChild,
|
|
2133
|
+
vnodeChildren,
|
|
2134
|
+
oldKeyMap
|
|
2135
|
+
);
|
|
2136
|
+
keyedElements.set(firstChild, newKeyMap);
|
|
2137
|
+
}
|
|
2617
2138
|
} catch (err) {
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2139
|
+
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
2140
|
+
logger.warn(
|
|
2141
|
+
"[Askr][FASTPATH] forced bulk path failed, falling back",
|
|
2142
|
+
err
|
|
2143
|
+
);
|
|
2144
|
+
}
|
|
2145
|
+
const newKeyMap = reconcileKeyedChildren(
|
|
2146
|
+
firstChild,
|
|
2147
|
+
vnodeChildren,
|
|
2148
|
+
oldKeyMap
|
|
2149
|
+
);
|
|
2150
|
+
keyedElements.set(firstChild, newKeyMap);
|
|
2621
2151
|
}
|
|
2622
|
-
}
|
|
2152
|
+
} else {
|
|
2153
|
+
const newKeyMap = reconcileKeyedChildren(
|
|
2154
|
+
firstChild,
|
|
2155
|
+
vnodeChildren,
|
|
2156
|
+
oldKeyMap
|
|
2157
|
+
);
|
|
2158
|
+
keyedElements.set(firstChild, newKeyMap);
|
|
2159
|
+
}
|
|
2160
|
+
} catch (e) {
|
|
2161
|
+
void e;
|
|
2162
|
+
const newKeyMap = reconcileKeyedChildren(
|
|
2163
|
+
firstChild,
|
|
2164
|
+
vnodeChildren,
|
|
2165
|
+
oldKeyMap
|
|
2166
|
+
);
|
|
2167
|
+
keyedElements.set(firstChild, newKeyMap);
|
|
2168
|
+
}
|
|
2169
|
+
} else {
|
|
2170
|
+
if (isBulkTextFastPathEligible(firstChild, vnodeChildren)) {
|
|
2171
|
+
const stats = performBulkTextReplace(firstChild, vnodeChildren);
|
|
2172
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2173
|
+
try {
|
|
2174
|
+
__ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
|
|
2175
|
+
__ASKR_incCounter("bulkTextHits");
|
|
2176
|
+
} catch (e) {
|
|
2177
|
+
void e;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
} else {
|
|
2181
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2182
|
+
try {
|
|
2183
|
+
__ASKR_incCounter("bulkTextMisses");
|
|
2184
|
+
} catch (e) {
|
|
2185
|
+
void e;
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
updateUnkeyedChildren(firstChild, vnodeChildren);
|
|
2189
|
+
keyedElements.delete(firstChild);
|
|
2623
2190
|
}
|
|
2624
2191
|
}
|
|
2625
|
-
}
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2192
|
+
} else {
|
|
2193
|
+
firstChild.textContent = "";
|
|
2194
|
+
const dom = createDOMNode(vnodeChildren);
|
|
2195
|
+
if (dom) firstChild.appendChild(dom);
|
|
2196
|
+
keyedElements.delete(firstChild);
|
|
2629
2197
|
}
|
|
2630
|
-
elementListeners.get(el).set(eventName, {
|
|
2631
|
-
handler: wrappedHandler,
|
|
2632
|
-
original: value
|
|
2633
|
-
});
|
|
2634
|
-
} else if (key === "class" || key === "className") {
|
|
2635
|
-
el.className = String(value);
|
|
2636
|
-
} else if (key === "value" || key === "checked") {
|
|
2637
|
-
el[key] = value;
|
|
2638
|
-
el.setAttribute(key, String(value));
|
|
2639
2198
|
} else {
|
|
2640
|
-
|
|
2199
|
+
firstChild.textContent = "";
|
|
2200
|
+
keyedElements.delete(firstChild);
|
|
2641
2201
|
}
|
|
2642
2202
|
}
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2203
|
+
updateElementFromVnode(firstChild, vnode, false);
|
|
2204
|
+
} else {
|
|
2205
|
+
target.textContent = "";
|
|
2206
|
+
if (_isDOMElement(vnode) && typeof vnode.type === "string") {
|
|
2207
|
+
const children = vnode.children;
|
|
2208
|
+
if (Array.isArray(children) && children.some(
|
|
2209
|
+
(child) => typeof child === "object" && child !== null && "key" in child
|
|
2210
|
+
)) {
|
|
2211
|
+
const el = document.createElement(vnode.type);
|
|
2212
|
+
target.appendChild(el);
|
|
2213
|
+
const props = vnode.props || {};
|
|
2214
|
+
for (const [key, value] of Object.entries(props)) {
|
|
2215
|
+
if (key === "children" || key === "key") continue;
|
|
2216
|
+
if (value === void 0 || value === null || value === false)
|
|
2217
|
+
continue;
|
|
2218
|
+
if (key.startsWith("on") && key.length > 2) {
|
|
2219
|
+
const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
|
|
2220
|
+
const wrappedHandler = (event) => {
|
|
2221
|
+
globalScheduler.setInHandler(true);
|
|
2222
|
+
try {
|
|
2223
|
+
value(event);
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
logger.error("[Askr] Event handler error:", error);
|
|
2226
|
+
} finally {
|
|
2227
|
+
globalScheduler.setInHandler(false);
|
|
2661
2228
|
}
|
|
2229
|
+
};
|
|
2230
|
+
const options = eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch") ? { passive: true } : void 0;
|
|
2231
|
+
if (options !== void 0)
|
|
2232
|
+
el.addEventListener(eventName, wrappedHandler, options);
|
|
2233
|
+
else el.addEventListener(eventName, wrappedHandler);
|
|
2234
|
+
if (!elementListeners.has(el)) {
|
|
2235
|
+
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
2662
2236
|
}
|
|
2237
|
+
elementListeners.get(el).set(eventName, {
|
|
2238
|
+
handler: wrappedHandler,
|
|
2239
|
+
original: value,
|
|
2240
|
+
options
|
|
2241
|
+
});
|
|
2242
|
+
continue;
|
|
2663
2243
|
}
|
|
2664
|
-
if (
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2244
|
+
if (key === "class" || key === "className") {
|
|
2245
|
+
el.className = String(value);
|
|
2246
|
+
} else if (key === "value" || key === "checked") {
|
|
2247
|
+
el[key] = value;
|
|
2248
|
+
} else {
|
|
2249
|
+
el.setAttribute(key, String(value));
|
|
2670
2250
|
}
|
|
2671
2251
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
} else {
|
|
2677
|
-
const dom = createDOMNode(children);
|
|
2678
|
-
if (dom) el.appendChild(dom);
|
|
2252
|
+
const newKeyMap = reconcileKeyedChildren(el, children, void 0);
|
|
2253
|
+
keyedElements.set(el, newKeyMap);
|
|
2254
|
+
return;
|
|
2255
|
+
return;
|
|
2679
2256
|
}
|
|
2680
2257
|
}
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
const frame = node[CONTEXT_FRAME_SYMBOL];
|
|
2685
|
-
const snapshot = frame || getCurrentContextFrame();
|
|
2686
|
-
const componentFn = type;
|
|
2687
|
-
const isAsync = componentFn.constructor.name === "AsyncFunction";
|
|
2688
|
-
if (isAsync) {
|
|
2689
|
-
throw new Error(
|
|
2690
|
-
"Async components are not supported. Use resource() for async work."
|
|
2691
|
-
);
|
|
2692
|
-
}
|
|
2693
|
-
const vnodeAny = node;
|
|
2694
|
-
let childInstance = vnodeAny.__instance;
|
|
2695
|
-
if (!childInstance) {
|
|
2696
|
-
childInstance = createComponentInstance(
|
|
2697
|
-
`comp-${Math.random().toString(36).slice(2, 7)}`,
|
|
2698
|
-
componentFn,
|
|
2699
|
-
props || {},
|
|
2700
|
-
null
|
|
2701
|
-
);
|
|
2702
|
-
vnodeAny.__instance = childInstance;
|
|
2703
|
-
}
|
|
2704
|
-
if (snapshot) {
|
|
2705
|
-
childInstance.ownerFrame = snapshot;
|
|
2706
|
-
}
|
|
2707
|
-
const result = withContext(
|
|
2708
|
-
snapshot,
|
|
2709
|
-
() => renderComponentInline(childInstance)
|
|
2710
|
-
);
|
|
2711
|
-
if (result instanceof Promise) {
|
|
2712
|
-
throw new Error(
|
|
2713
|
-
"Async components are not supported. Components must return synchronously."
|
|
2714
|
-
);
|
|
2715
|
-
}
|
|
2716
|
-
const dom = withContext(snapshot, () => createDOMNode(result));
|
|
2717
|
-
if (dom instanceof Element) {
|
|
2718
|
-
mountInstanceInline(childInstance, dom);
|
|
2719
|
-
} else {
|
|
2720
|
-
const host = document.createElement("div");
|
|
2721
|
-
mountInstanceInline(childInstance, host);
|
|
2722
|
-
}
|
|
2723
|
-
return dom;
|
|
2724
|
-
}
|
|
2725
|
-
if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
|
|
2726
|
-
const fragment = document.createDocumentFragment();
|
|
2727
|
-
const children = props.children || node.children;
|
|
2728
|
-
if (children) {
|
|
2729
|
-
if (Array.isArray(children)) {
|
|
2730
|
-
for (let i = 0; i < children.length; i++) {
|
|
2731
|
-
const dom = createDOMNode(children[i]);
|
|
2732
|
-
if (dom) fragment.appendChild(dom);
|
|
2733
|
-
}
|
|
2734
|
-
} else {
|
|
2735
|
-
const dom = createDOMNode(children);
|
|
2736
|
-
if (dom) fragment.appendChild(dom);
|
|
2737
|
-
}
|
|
2258
|
+
const dom = createDOMNode(vnode);
|
|
2259
|
+
if (dom) {
|
|
2260
|
+
target.appendChild(dom);
|
|
2738
2261
|
}
|
|
2739
|
-
return fragment;
|
|
2740
2262
|
}
|
|
2741
2263
|
}
|
|
2742
|
-
return null;
|
|
2743
2264
|
}
|
|
2744
|
-
var domRanges
|
|
2745
|
-
var
|
|
2746
|
-
"src/renderer/
|
|
2265
|
+
var domRanges;
|
|
2266
|
+
var init_evaluate = __esm({
|
|
2267
|
+
"src/renderer/evaluate.ts"() {
|
|
2747
2268
|
"use strict";
|
|
2748
2269
|
init_scheduler();
|
|
2749
|
-
init_fastlane();
|
|
2750
2270
|
init_logger();
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2271
|
+
init_cleanup();
|
|
2272
|
+
init_keyed();
|
|
2273
|
+
init_reconcile();
|
|
2274
|
+
init_types();
|
|
2275
|
+
init_dom();
|
|
2276
|
+
init_diag();
|
|
2754
2277
|
domRanges = /* @__PURE__ */ new WeakMap();
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2278
|
+
}
|
|
2279
|
+
});
|
|
2280
|
+
|
|
2281
|
+
// src/renderer/index.ts
|
|
2282
|
+
var init_renderer = __esm({
|
|
2283
|
+
"src/renderer/index.ts"() {
|
|
2284
|
+
"use strict";
|
|
2285
|
+
init_types();
|
|
2286
|
+
init_cleanup();
|
|
2287
|
+
init_keyed();
|
|
2288
|
+
init_dom();
|
|
2289
|
+
init_evaluate();
|
|
2290
|
+
init_evaluate();
|
|
2291
|
+
init_keyed();
|
|
2758
2292
|
if (typeof globalThis !== "undefined") {
|
|
2759
2293
|
const _g = globalThis;
|
|
2760
2294
|
_g.__ASKR_RENDERER = {
|
|
@@ -2767,22 +2301,6 @@ var init_dom = __esm({
|
|
|
2767
2301
|
});
|
|
2768
2302
|
|
|
2769
2303
|
// src/runtime/component.ts
|
|
2770
|
-
var component_exports = {};
|
|
2771
|
-
__export(component_exports, {
|
|
2772
|
-
cleanupComponent: () => cleanupComponent,
|
|
2773
|
-
createComponentInstance: () => createComponentInstance,
|
|
2774
|
-
executeComponent: () => executeComponent,
|
|
2775
|
-
finalizeReadSubscriptions: () => finalizeReadSubscriptions,
|
|
2776
|
-
getCurrentComponentInstance: () => getCurrentComponentInstance,
|
|
2777
|
-
getCurrentInstance: () => getCurrentInstance,
|
|
2778
|
-
getNextStateIndex: () => getNextStateIndex,
|
|
2779
|
-
getSignal: () => getSignal,
|
|
2780
|
-
mountComponent: () => mountComponent,
|
|
2781
|
-
mountInstanceInline: () => mountInstanceInline,
|
|
2782
|
-
registerMountOperation: () => registerMountOperation,
|
|
2783
|
-
renderComponentInline: () => renderComponentInline,
|
|
2784
|
-
setCurrentComponentInstance: () => setCurrentComponentInstance
|
|
2785
|
-
});
|
|
2786
2304
|
function createComponentInstance(id, fn, props, target) {
|
|
2787
2305
|
const instance = {
|
|
2788
2306
|
id,
|
|
@@ -2808,6 +2326,7 @@ function createComponentInstance(id, fn, props, target) {
|
|
|
2808
2326
|
ownerFrame: null,
|
|
2809
2327
|
// Will be set by renderer when vnode is marked
|
|
2810
2328
|
ssr: false,
|
|
2329
|
+
cleanupStrict: false,
|
|
2811
2330
|
isRoot: false,
|
|
2812
2331
|
// Render-tracking (for precise state subscriptions)
|
|
2813
2332
|
_currentRenderToken: void 0,
|
|
@@ -2902,12 +2421,41 @@ function runComponent(instance) {
|
|
|
2902
2421
|
}
|
|
2903
2422
|
globalScheduler.enqueue(() => {
|
|
2904
2423
|
if (instance.target) {
|
|
2424
|
+
let oldChildren = [];
|
|
2905
2425
|
try {
|
|
2906
2426
|
const wasFirstMount = !instance.mounted;
|
|
2907
2427
|
const oldInstance = currentInstance;
|
|
2908
2428
|
currentInstance = instance;
|
|
2429
|
+
oldChildren = Array.from(instance.target.childNodes);
|
|
2909
2430
|
try {
|
|
2910
2431
|
evaluate(result, instance.target);
|
|
2432
|
+
} catch (e) {
|
|
2433
|
+
try {
|
|
2434
|
+
const newChildren = Array.from(instance.target.childNodes);
|
|
2435
|
+
for (const n of newChildren) {
|
|
2436
|
+
try {
|
|
2437
|
+
cleanupInstancesUnder(n);
|
|
2438
|
+
} catch (err) {
|
|
2439
|
+
logger.warn(
|
|
2440
|
+
"[Askr] error cleaning up failed commit children:",
|
|
2441
|
+
err
|
|
2442
|
+
);
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
} catch (_err) {
|
|
2446
|
+
void _err;
|
|
2447
|
+
}
|
|
2448
|
+
try {
|
|
2449
|
+
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
2450
|
+
__ASKR_set(
|
|
2451
|
+
"__LAST_DOM_REPLACE_STACK_COMPONENT_RESTORE",
|
|
2452
|
+
new Error().stack
|
|
2453
|
+
);
|
|
2454
|
+
} catch (e2) {
|
|
2455
|
+
void e2;
|
|
2456
|
+
}
|
|
2457
|
+
instance.target.replaceChildren(...oldChildren);
|
|
2458
|
+
throw e;
|
|
2911
2459
|
} finally {
|
|
2912
2460
|
currentInstance = oldInstance;
|
|
2913
2461
|
}
|
|
@@ -2917,7 +2465,35 @@ function runComponent(instance) {
|
|
|
2917
2465
|
executeMountOperations(instance);
|
|
2918
2466
|
}
|
|
2919
2467
|
} catch (renderError) {
|
|
2920
|
-
|
|
2468
|
+
try {
|
|
2469
|
+
const currentChildren = Array.from(instance.target.childNodes);
|
|
2470
|
+
for (const n of currentChildren) {
|
|
2471
|
+
try {
|
|
2472
|
+
cleanupInstancesUnder(n);
|
|
2473
|
+
} catch (err) {
|
|
2474
|
+
logger.warn(
|
|
2475
|
+
"[Askr] error cleaning up partial children during rollback:",
|
|
2476
|
+
err
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
} catch (_err) {
|
|
2481
|
+
void _err;
|
|
2482
|
+
}
|
|
2483
|
+
try {
|
|
2484
|
+
try {
|
|
2485
|
+
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
2486
|
+
__ASKR_set(
|
|
2487
|
+
"__LAST_DOM_REPLACE_STACK_COMPONENT_ROLLBACK",
|
|
2488
|
+
new Error().stack
|
|
2489
|
+
);
|
|
2490
|
+
} catch (e) {
|
|
2491
|
+
void e;
|
|
2492
|
+
}
|
|
2493
|
+
instance.target.replaceChildren(...oldChildren);
|
|
2494
|
+
} catch {
|
|
2495
|
+
instance.target.innerHTML = domSnapshot;
|
|
2496
|
+
}
|
|
2921
2497
|
throw renderError;
|
|
2922
2498
|
}
|
|
2923
2499
|
}
|
|
@@ -2966,21 +2542,24 @@ function executeComponentSync(instance) {
|
|
|
2966
2542
|
executionFrame,
|
|
2967
2543
|
() => instance.fn(instance.props, context)
|
|
2968
2544
|
);
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
);
|
|
2975
|
-
}
|
|
2545
|
+
const renderTime = Date.now() - renderStartTime;
|
|
2546
|
+
if (renderTime > 5) {
|
|
2547
|
+
logger.warn(
|
|
2548
|
+
`[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`
|
|
2549
|
+
);
|
|
2976
2550
|
}
|
|
2977
2551
|
if (!instance.firstRenderComplete) {
|
|
2978
2552
|
instance.firstRenderComplete = true;
|
|
2979
2553
|
}
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2554
|
+
for (let i = 0; i < instance.stateValues.length; i++) {
|
|
2555
|
+
const state2 = instance.stateValues[i];
|
|
2556
|
+
if (state2 && !state2._hasBeenRead) {
|
|
2557
|
+
try {
|
|
2558
|
+
const name = instance.fn?.name || "<anonymous>";
|
|
2559
|
+
logger.warn(
|
|
2560
|
+
`[askr] Unused state variable detected in ${name} at index ${i}. State should be read during render or removed.`
|
|
2561
|
+
);
|
|
2562
|
+
} catch {
|
|
2984
2563
|
logger.warn(
|
|
2985
2564
|
`[askr] Unused state variable detected. State should be read during render or removed.`
|
|
2986
2565
|
);
|
|
@@ -3015,13 +2594,13 @@ function finalizeReadSubscriptions(instance) {
|
|
|
3015
2594
|
if (token === void 0) return;
|
|
3016
2595
|
for (const s of oldSet) {
|
|
3017
2596
|
if (!newSet.has(s)) {
|
|
3018
|
-
const readers = s
|
|
2597
|
+
const readers = s._readers;
|
|
3019
2598
|
if (readers) readers.delete(instance);
|
|
3020
2599
|
}
|
|
3021
2600
|
}
|
|
3022
2601
|
instance.lastRenderToken = token;
|
|
3023
2602
|
for (const s of newSet) {
|
|
3024
|
-
let readers = s
|
|
2603
|
+
let readers = s._readers;
|
|
3025
2604
|
if (!readers) {
|
|
3026
2605
|
readers = /* @__PURE__ */ new Map();
|
|
3027
2606
|
s._readers = readers;
|
|
@@ -3039,13 +2618,30 @@ function mountComponent(instance) {
|
|
|
3039
2618
|
executeComponent(instance);
|
|
3040
2619
|
}
|
|
3041
2620
|
function cleanupComponent(instance) {
|
|
2621
|
+
const cleanupErrors = [];
|
|
3042
2622
|
for (const cleanup of instance.cleanupFns) {
|
|
3043
|
-
|
|
2623
|
+
try {
|
|
2624
|
+
cleanup();
|
|
2625
|
+
} catch (err) {
|
|
2626
|
+
if (instance.cleanupStrict) {
|
|
2627
|
+
cleanupErrors.push(err);
|
|
2628
|
+
} else {
|
|
2629
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2630
|
+
logger.warn("[Askr] cleanup function threw:", err);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
3044
2634
|
}
|
|
3045
2635
|
instance.cleanupFns = [];
|
|
2636
|
+
if (cleanupErrors.length > 0) {
|
|
2637
|
+
throw new AggregateError(
|
|
2638
|
+
cleanupErrors,
|
|
2639
|
+
`Cleanup failed for component ${instance.id}`
|
|
2640
|
+
);
|
|
2641
|
+
}
|
|
3046
2642
|
if (instance._lastReadStates) {
|
|
3047
2643
|
for (const s of instance._lastReadStates) {
|
|
3048
|
-
const readers = s
|
|
2644
|
+
const readers = s._readers;
|
|
3049
2645
|
if (readers) readers.delete(instance);
|
|
3050
2646
|
}
|
|
3051
2647
|
instance._lastReadStates = /* @__PURE__ */ new Set();
|
|
@@ -3056,11 +2652,12 @@ var currentInstance, stateIndex, _globalRenderCounter;
|
|
|
3056
2652
|
var init_component = __esm({
|
|
3057
2653
|
"src/runtime/component.ts"() {
|
|
3058
2654
|
"use strict";
|
|
3059
|
-
init_dom();
|
|
3060
2655
|
init_scheduler();
|
|
3061
2656
|
init_context();
|
|
3062
2657
|
init_logger();
|
|
3063
|
-
|
|
2658
|
+
init_diag();
|
|
2659
|
+
init_fastlane_shared();
|
|
2660
|
+
init_renderer();
|
|
3064
2661
|
currentInstance = null;
|
|
3065
2662
|
stateIndex = 0;
|
|
3066
2663
|
_globalRenderCounter = 0;
|
|
@@ -3387,7 +2984,7 @@ function route(path, handler, namespace) {
|
|
|
3387
2984
|
}
|
|
3388
2985
|
if (registrationLocked) {
|
|
3389
2986
|
throw new Error(
|
|
3390
|
-
"Route registration is locked after app startup. Register routes at module load time before calling
|
|
2987
|
+
"Route registration is locked after app startup. Register routes at module load time before calling createIsland()."
|
|
3391
2988
|
);
|
|
3392
2989
|
}
|
|
3393
2990
|
if (typeof handler !== "function") {
|
|
@@ -3737,9 +3334,14 @@ function renderChildrenToSink(children, sink, ctx) {
|
|
|
3737
3334
|
ctx
|
|
3738
3335
|
);
|
|
3739
3336
|
}
|
|
3337
|
+
function isPromiseLike(x) {
|
|
3338
|
+
if (!x || typeof x !== "object") return false;
|
|
3339
|
+
const then = x.then;
|
|
3340
|
+
return typeof then === "function";
|
|
3341
|
+
}
|
|
3740
3342
|
function executeComponent2(type, props, ctx) {
|
|
3741
3343
|
const res = type(props ?? {}, { signal: ctx.signal });
|
|
3742
|
-
if (res
|
|
3344
|
+
if (isPromiseLike(res)) {
|
|
3743
3345
|
throwSSRDataMissing();
|
|
3744
3346
|
}
|
|
3745
3347
|
return res;
|
|
@@ -3809,6 +3411,8 @@ var ssr_exports = {};
|
|
|
3809
3411
|
__export(ssr_exports, {
|
|
3810
3412
|
SSRDataMissingError: () => SSRDataMissingError,
|
|
3811
3413
|
collectResources: () => collectResources,
|
|
3414
|
+
popSSRStrictPurityGuard: () => popSSRStrictPurityGuard,
|
|
3415
|
+
pushSSRStrictPurityGuard: () => pushSSRStrictPurityGuard,
|
|
3812
3416
|
renderToStream: () => renderToStream,
|
|
3813
3417
|
renderToString: () => renderToString,
|
|
3814
3418
|
renderToStringSync: () => renderToStringSync,
|
|
@@ -3816,6 +3420,31 @@ __export(ssr_exports, {
|
|
|
3816
3420
|
resolvePlan: () => resolvePlan,
|
|
3817
3421
|
resolveResources: () => resolveResources
|
|
3818
3422
|
});
|
|
3423
|
+
function pushSSRStrictPurityGuard() {
|
|
3424
|
+
if (process.env.NODE_ENV === "production") return;
|
|
3425
|
+
__ssrGuardStack.push({
|
|
3426
|
+
random: Reflect.get(Math, "random"),
|
|
3427
|
+
now: Reflect.get(Date, "now")
|
|
3428
|
+
});
|
|
3429
|
+
Reflect.set(Math, "random", () => {
|
|
3430
|
+
throw new Error(
|
|
3431
|
+
"SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
|
|
3432
|
+
);
|
|
3433
|
+
});
|
|
3434
|
+
Reflect.set(Date, "now", () => {
|
|
3435
|
+
throw new Error(
|
|
3436
|
+
"SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
|
|
3437
|
+
);
|
|
3438
|
+
});
|
|
3439
|
+
}
|
|
3440
|
+
function popSSRStrictPurityGuard() {
|
|
3441
|
+
if (process.env.NODE_ENV === "production") return;
|
|
3442
|
+
const prev = __ssrGuardStack.pop();
|
|
3443
|
+
if (prev) {
|
|
3444
|
+
Reflect.set(Math, "random", prev.random);
|
|
3445
|
+
Reflect.set(Date, "now", prev.now);
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3819
3448
|
function escapeText2(text) {
|
|
3820
3449
|
const cached = escapeCache2.get(text);
|
|
3821
3450
|
if (cached) return cached;
|
|
@@ -3893,20 +3522,9 @@ function renderNodeSync(node, ctx) {
|
|
|
3893
3522
|
return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;
|
|
3894
3523
|
}
|
|
3895
3524
|
function executeComponentSync2(component, props, ctx) {
|
|
3896
|
-
const originalRandom = Math.random;
|
|
3897
|
-
const originalDateNow = Date.now;
|
|
3898
3525
|
try {
|
|
3899
3526
|
if (process.env.NODE_ENV !== "production") {
|
|
3900
|
-
|
|
3901
|
-
throw new Error(
|
|
3902
|
-
"SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
|
|
3903
|
-
);
|
|
3904
|
-
};
|
|
3905
|
-
Date.now = () => {
|
|
3906
|
-
throw new Error(
|
|
3907
|
-
"SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
|
|
3908
|
-
);
|
|
3909
|
-
};
|
|
3527
|
+
pushSSRStrictPurityGuard();
|
|
3910
3528
|
}
|
|
3911
3529
|
const prev = getCurrentComponentInstance();
|
|
3912
3530
|
const temp = createComponentInstance(
|
|
@@ -3929,8 +3547,7 @@ function executeComponentSync2(component, props, ctx) {
|
|
|
3929
3547
|
setCurrentComponentInstance(prev);
|
|
3930
3548
|
}
|
|
3931
3549
|
} finally {
|
|
3932
|
-
|
|
3933
|
-
Date.now = originalDateNow;
|
|
3550
|
+
if (process.env.NODE_ENV !== "production") popSSRStrictPurityGuard();
|
|
3934
3551
|
}
|
|
3935
3552
|
}
|
|
3936
3553
|
function renderToStringSync(component, props, options) {
|
|
@@ -4023,7 +3640,7 @@ function renderToSinkInternal(opts) {
|
|
|
4023
3640
|
stopRenderPhase();
|
|
4024
3641
|
}
|
|
4025
3642
|
}
|
|
4026
|
-
var VOID_ELEMENTS2, escapeCache2;
|
|
3643
|
+
var VOID_ELEMENTS2, escapeCache2, __ssrGuardStack;
|
|
4027
3644
|
var init_ssr = __esm({
|
|
4028
3645
|
"src/ssr/index.ts"() {
|
|
4029
3646
|
"use strict";
|
|
@@ -4051,21 +3668,24 @@ var init_ssr = __esm({
|
|
|
4051
3668
|
"wbr"
|
|
4052
3669
|
]);
|
|
4053
3670
|
escapeCache2 = /* @__PURE__ */ new Map();
|
|
3671
|
+
__ssrGuardStack = [];
|
|
4054
3672
|
}
|
|
4055
3673
|
});
|
|
4056
3674
|
|
|
4057
3675
|
// src/index.ts
|
|
4058
3676
|
var index_exports = {};
|
|
4059
3677
|
__export(index_exports, {
|
|
4060
|
-
Fragment: () =>
|
|
3678
|
+
Fragment: () => Fragment2,
|
|
4061
3679
|
Link: () => Link,
|
|
3680
|
+
Slot: () => Slot,
|
|
4062
3681
|
cleanupApp: () => cleanupApp,
|
|
4063
3682
|
clearRoutes: () => clearRoutes,
|
|
4064
3683
|
collectResources: () => collectResources,
|
|
4065
|
-
createApp: () => createApp,
|
|
4066
3684
|
createIsland: () => createIsland,
|
|
4067
3685
|
createSPA: () => createSPA,
|
|
4068
3686
|
defineContext: () => defineContext,
|
|
3687
|
+
definePortal: () => definePortal,
|
|
3688
|
+
derive: () => derive,
|
|
4069
3689
|
getLoadedNamespaces: () => getLoadedNamespaces,
|
|
4070
3690
|
getNamespaceRoutes: () => getNamespaceRoutes,
|
|
4071
3691
|
getRoutes: () => getRoutes,
|
|
@@ -4087,6 +3707,7 @@ __export(index_exports, {
|
|
|
4087
3707
|
scheduleEventHandler: () => scheduleEventHandler,
|
|
4088
3708
|
setServerLocation: () => setServerLocation,
|
|
4089
3709
|
state: () => state,
|
|
3710
|
+
task: () => task,
|
|
4090
3711
|
unloadNamespace: () => unloadNamespace
|
|
4091
3712
|
});
|
|
4092
3713
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -4095,7 +3716,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
4095
3716
|
init_scheduler();
|
|
4096
3717
|
init_component();
|
|
4097
3718
|
init_invariant();
|
|
4098
|
-
|
|
3719
|
+
init_fastlane_shared();
|
|
4099
3720
|
function state(initialValue) {
|
|
4100
3721
|
const instance = getCurrentInstance();
|
|
4101
3722
|
if (!instance) {
|
|
@@ -4151,7 +3772,7 @@ function createStateCell(initialValue, instance) {
|
|
|
4151
3772
|
}
|
|
4152
3773
|
read._readers = readers;
|
|
4153
3774
|
read._owner = instance;
|
|
4154
|
-
read.set = (
|
|
3775
|
+
read.set = (newValueOrUpdater) => {
|
|
4155
3776
|
const currentInst = getCurrentInstance();
|
|
4156
3777
|
if (currentInst !== null && process.env.NODE_ENV !== "production") {
|
|
4157
3778
|
throw new Error(
|
|
@@ -4161,6 +3782,13 @@ function createStateCell(initialValue, instance) {
|
|
|
4161
3782
|
if (currentInst !== null && process.env.NODE_ENV === "production") {
|
|
4162
3783
|
return;
|
|
4163
3784
|
}
|
|
3785
|
+
let newValue;
|
|
3786
|
+
if (typeof newValueOrUpdater === "function") {
|
|
3787
|
+
const updater = newValueOrUpdater;
|
|
3788
|
+
newValue = updater(value);
|
|
3789
|
+
} else {
|
|
3790
|
+
newValue = newValueOrUpdater;
|
|
3791
|
+
}
|
|
4164
3792
|
if (Object.is(value, newValue)) return;
|
|
4165
3793
|
if (isBulkCommitActive2()) {
|
|
4166
3794
|
value = newValue;
|
|
@@ -4191,8 +3819,8 @@ function createStateCell(initialValue, instance) {
|
|
|
4191
3819
|
);
|
|
4192
3820
|
if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
|
|
4193
3821
|
instance.hasPendingUpdate = true;
|
|
4194
|
-
const
|
|
4195
|
-
if (
|
|
3822
|
+
const task2 = instance._pendingFlushTask;
|
|
3823
|
+
if (task2) globalScheduler.enqueue(task2);
|
|
4196
3824
|
else
|
|
4197
3825
|
globalScheduler.enqueue(() => {
|
|
4198
3826
|
instance.hasPendingUpdate = false;
|
|
@@ -4288,7 +3916,14 @@ var ResourceCell = class {
|
|
|
4288
3916
|
this.pending = false;
|
|
4289
3917
|
this.error = err;
|
|
4290
3918
|
try {
|
|
4291
|
-
|
|
3919
|
+
if (this.ownerName) {
|
|
3920
|
+
logger.error(
|
|
3921
|
+
`[Askr] Async resource error in ${this.ownerName}:`,
|
|
3922
|
+
err
|
|
3923
|
+
);
|
|
3924
|
+
} else {
|
|
3925
|
+
logger.error("[Askr] Async resource error:", err);
|
|
3926
|
+
}
|
|
4292
3927
|
} catch {
|
|
4293
3928
|
}
|
|
4294
3929
|
this.notifySubscribers();
|
|
@@ -4304,6 +3939,17 @@ var ResourceCell = class {
|
|
|
4304
3939
|
}
|
|
4305
3940
|
};
|
|
4306
3941
|
|
|
3942
|
+
// src/shared/derive_cache.ts
|
|
3943
|
+
var deriveCacheMap = /* @__PURE__ */ new WeakMap();
|
|
3944
|
+
function getDeriveCache(instance) {
|
|
3945
|
+
let cache = deriveCacheMap.get(instance);
|
|
3946
|
+
if (!cache) {
|
|
3947
|
+
cache = /* @__PURE__ */ new Map();
|
|
3948
|
+
deriveCacheMap.set(instance, cache);
|
|
3949
|
+
}
|
|
3950
|
+
return cache;
|
|
3951
|
+
}
|
|
3952
|
+
|
|
4307
3953
|
// src/runtime/operations.ts
|
|
4308
3954
|
init_context2();
|
|
4309
3955
|
init_data();
|
|
@@ -4376,6 +4022,7 @@ function resource(fn, deps = []) {
|
|
|
4376
4022
|
if (!h.cell) {
|
|
4377
4023
|
const frame = getCurrentContextFrame();
|
|
4378
4024
|
const cell2 = new ResourceCell(fn, deps, frame);
|
|
4025
|
+
cell2.ownerName = inst.fn?.name || "<anonymous>";
|
|
4379
4026
|
h.cell = cell2;
|
|
4380
4027
|
h.snapshot = cell2.snapshot;
|
|
4381
4028
|
const unsubscribe = cell2.subscribe(() => {
|
|
@@ -4438,35 +4085,101 @@ function resource(fn, deps = []) {
|
|
|
4438
4085
|
}
|
|
4439
4086
|
return h.snapshot;
|
|
4440
4087
|
}
|
|
4088
|
+
function derive(source, map) {
|
|
4089
|
+
if (map === void 0 && typeof source === "function") {
|
|
4090
|
+
const value2 = source();
|
|
4091
|
+
if (value2 == null) return null;
|
|
4092
|
+
const instance2 = getCurrentComponentInstance();
|
|
4093
|
+
if (!instance2) {
|
|
4094
|
+
return value2;
|
|
4095
|
+
}
|
|
4096
|
+
const cache2 = getDeriveCache(instance2);
|
|
4097
|
+
if (cache2.has(value2)) return cache2.get(value2);
|
|
4098
|
+
cache2.set(value2, value2);
|
|
4099
|
+
return value2;
|
|
4100
|
+
}
|
|
4101
|
+
let value;
|
|
4102
|
+
if (typeof source === "function" && !("value" in source)) {
|
|
4103
|
+
value = source();
|
|
4104
|
+
} else {
|
|
4105
|
+
value = source?.value ?? source;
|
|
4106
|
+
}
|
|
4107
|
+
if (value == null) return null;
|
|
4108
|
+
const instance = getCurrentComponentInstance();
|
|
4109
|
+
if (!instance) {
|
|
4110
|
+
return map(value);
|
|
4111
|
+
}
|
|
4112
|
+
const cache = getDeriveCache(instance);
|
|
4113
|
+
if (cache.has(value)) {
|
|
4114
|
+
return cache.get(value);
|
|
4115
|
+
}
|
|
4116
|
+
const result = map(value);
|
|
4117
|
+
cache.set(value, result);
|
|
4118
|
+
return result;
|
|
4119
|
+
}
|
|
4120
|
+
function task(fn) {
|
|
4121
|
+
const ownerIsRoot = getCurrentComponentInstance()?.isRoot ?? false;
|
|
4122
|
+
registerMountOperation(async () => {
|
|
4123
|
+
if (!ownerIsRoot) {
|
|
4124
|
+
throw new Error("[Askr] task() may only be used in root components");
|
|
4125
|
+
}
|
|
4126
|
+
return await fn();
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4441
4129
|
|
|
4442
|
-
// src/
|
|
4130
|
+
// src/boot/index.ts
|
|
4443
4131
|
init_component();
|
|
4444
4132
|
init_scheduler();
|
|
4445
4133
|
init_logger();
|
|
4446
|
-
init_dom();
|
|
4447
4134
|
init_navigate();
|
|
4135
|
+
init_renderer();
|
|
4448
4136
|
var componentIdCounter = 0;
|
|
4449
4137
|
var instancesByRoot = /* @__PURE__ */ new WeakMap();
|
|
4450
4138
|
var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
|
|
4451
|
-
function createApp(config) {
|
|
4452
|
-
if (!config || typeof config !== "object") {
|
|
4453
|
-
throw new Error("createApp requires a config object");
|
|
4454
|
-
}
|
|
4455
|
-
if ("routes" in config) {
|
|
4456
|
-
throw new Error(
|
|
4457
|
-
"The `createApp` API is removed. Use `createSPA({ root, routes })` for routed apps, or `hydrateSPA({ root, routes })` for SSR hydration."
|
|
4458
|
-
);
|
|
4459
|
-
}
|
|
4460
|
-
const appCfg = config;
|
|
4461
|
-
createIsland({
|
|
4462
|
-
root: appCfg.root,
|
|
4463
|
-
component: appCfg.component
|
|
4464
|
-
});
|
|
4465
|
-
}
|
|
4466
4139
|
function attachCleanupForRoot(rootElement, instance) {
|
|
4467
4140
|
rootElement[CLEANUP_SYMBOL] = () => {
|
|
4468
|
-
|
|
4469
|
-
|
|
4141
|
+
const errors = [];
|
|
4142
|
+
try {
|
|
4143
|
+
removeAllListeners(rootElement);
|
|
4144
|
+
} catch (e) {
|
|
4145
|
+
errors.push(e);
|
|
4146
|
+
}
|
|
4147
|
+
try {
|
|
4148
|
+
const descendants = rootElement.querySelectorAll("*");
|
|
4149
|
+
for (const d of Array.from(descendants)) {
|
|
4150
|
+
try {
|
|
4151
|
+
const inst = d.__ASKR_INSTANCE;
|
|
4152
|
+
if (inst) {
|
|
4153
|
+
try {
|
|
4154
|
+
cleanupComponent(inst);
|
|
4155
|
+
} catch (err) {
|
|
4156
|
+
errors.push(err);
|
|
4157
|
+
}
|
|
4158
|
+
try {
|
|
4159
|
+
delete d.__ASKR_INSTANCE;
|
|
4160
|
+
} catch (err) {
|
|
4161
|
+
errors.push(err);
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
} catch (err) {
|
|
4165
|
+
errors.push(err);
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
} catch (e) {
|
|
4169
|
+
errors.push(e);
|
|
4170
|
+
}
|
|
4171
|
+
try {
|
|
4172
|
+
cleanupComponent(instance);
|
|
4173
|
+
} catch (e) {
|
|
4174
|
+
errors.push(e);
|
|
4175
|
+
}
|
|
4176
|
+
if (errors.length > 0) {
|
|
4177
|
+
if (instance.cleanupStrict) {
|
|
4178
|
+
throw new AggregateError(errors, `cleanup failed for app root`);
|
|
4179
|
+
} else if (process.env.NODE_ENV !== "production") {
|
|
4180
|
+
for (const err of errors) logger.warn("[Askr] cleanup error:", err);
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4470
4183
|
};
|
|
4471
4184
|
try {
|
|
4472
4185
|
const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
|
|
@@ -4480,8 +4193,20 @@ function attachCleanupForRoot(rootElement, instance) {
|
|
|
4480
4193
|
} : void 0,
|
|
4481
4194
|
set: function(value) {
|
|
4482
4195
|
if (value === "" && instancesByRoot.get(this) === instance) {
|
|
4483
|
-
|
|
4484
|
-
|
|
4196
|
+
try {
|
|
4197
|
+
removeAllListeners(rootElement);
|
|
4198
|
+
} catch (e) {
|
|
4199
|
+
if (instance.cleanupStrict) throw e;
|
|
4200
|
+
if (process.env.NODE_ENV !== "production")
|
|
4201
|
+
logger.warn("[Askr] cleanup error:", e);
|
|
4202
|
+
}
|
|
4203
|
+
try {
|
|
4204
|
+
cleanupComponent(instance);
|
|
4205
|
+
} catch (e) {
|
|
4206
|
+
if (instance.cleanupStrict) throw e;
|
|
4207
|
+
if (process.env.NODE_ENV !== "production")
|
|
4208
|
+
logger.warn("[Askr] cleanup error:", e);
|
|
4209
|
+
}
|
|
4485
4210
|
}
|
|
4486
4211
|
if (descriptor.set) {
|
|
4487
4212
|
return descriptor.set.call(this, value);
|
|
@@ -4493,19 +4218,27 @@ function attachCleanupForRoot(rootElement, instance) {
|
|
|
4493
4218
|
} catch {
|
|
4494
4219
|
}
|
|
4495
4220
|
}
|
|
4496
|
-
function mountOrUpdate(rootElement, componentFn) {
|
|
4221
|
+
function mountOrUpdate(rootElement, componentFn, options) {
|
|
4497
4222
|
const existingCleanup = rootElement[CLEANUP_SYMBOL];
|
|
4498
4223
|
if (existingCleanup) existingCleanup();
|
|
4499
4224
|
let instance = instancesByRoot.get(rootElement);
|
|
4500
4225
|
if (instance) {
|
|
4501
4226
|
removeAllListeners(rootElement);
|
|
4502
|
-
|
|
4227
|
+
try {
|
|
4228
|
+
cleanupComponent(instance);
|
|
4229
|
+
} catch (e) {
|
|
4230
|
+
if (process.env.NODE_ENV !== "production")
|
|
4231
|
+
logger.warn("[Askr] prior cleanup threw:", e);
|
|
4232
|
+
}
|
|
4503
4233
|
instance.fn = componentFn;
|
|
4504
4234
|
instance.evaluationGeneration++;
|
|
4505
4235
|
instance.mounted = false;
|
|
4506
4236
|
instance.expectedStateIndices = [];
|
|
4507
4237
|
instance.firstRenderComplete = false;
|
|
4508
4238
|
instance.isRoot = true;
|
|
4239
|
+
if (options && typeof options.cleanupStrict === "boolean") {
|
|
4240
|
+
instance.cleanupStrict = options.cleanupStrict;
|
|
4241
|
+
}
|
|
4509
4242
|
} else {
|
|
4510
4243
|
const componentId = String(++componentIdCounter);
|
|
4511
4244
|
instance = createComponentInstance(
|
|
@@ -4516,6 +4249,9 @@ function mountOrUpdate(rootElement, componentFn) {
|
|
|
4516
4249
|
);
|
|
4517
4250
|
instancesByRoot.set(rootElement, instance);
|
|
4518
4251
|
instance.isRoot = true;
|
|
4252
|
+
if (options && typeof options.cleanupStrict === "boolean") {
|
|
4253
|
+
instance.cleanupStrict = options.cleanupStrict;
|
|
4254
|
+
}
|
|
4519
4255
|
}
|
|
4520
4256
|
attachCleanupForRoot(rootElement, instance);
|
|
4521
4257
|
mountComponent(instance);
|
|
@@ -4535,7 +4271,9 @@ function createIsland(config) {
|
|
|
4535
4271
|
"createIsland does not accept routes; use createSPA for routed apps"
|
|
4536
4272
|
);
|
|
4537
4273
|
}
|
|
4538
|
-
mountOrUpdate(rootElement, config.component
|
|
4274
|
+
mountOrUpdate(rootElement, config.component, {
|
|
4275
|
+
cleanupStrict: config.cleanupStrict
|
|
4276
|
+
});
|
|
4539
4277
|
}
|
|
4540
4278
|
async function createSPA(config) {
|
|
4541
4279
|
if (!config || typeof config !== "object") {
|
|
@@ -4562,14 +4300,18 @@ async function createSPA(config) {
|
|
|
4562
4300
|
`createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
|
|
4563
4301
|
);
|
|
4564
4302
|
}
|
|
4565
|
-
mountOrUpdate(rootElement, () => ({ type: "div", children: [] })
|
|
4303
|
+
mountOrUpdate(rootElement, () => ({ type: "div", children: [] }), {
|
|
4304
|
+
cleanupStrict: false
|
|
4305
|
+
});
|
|
4566
4306
|
const instance2 = instancesByRoot.get(rootElement);
|
|
4567
4307
|
if (!instance2) throw new Error("Internal error: app instance missing");
|
|
4568
4308
|
registerAppInstance(instance2, path);
|
|
4569
4309
|
initializeNavigation();
|
|
4570
4310
|
return;
|
|
4571
4311
|
}
|
|
4572
|
-
mountOrUpdate(rootElement, resolved.handler
|
|
4312
|
+
mountOrUpdate(rootElement, resolved.handler, {
|
|
4313
|
+
cleanupStrict: false
|
|
4314
|
+
});
|
|
4573
4315
|
const instance = instancesByRoot.get(rootElement);
|
|
4574
4316
|
if (!instance) throw new Error("Internal error: app instance missing");
|
|
4575
4317
|
registerAppInstance(instance, path);
|
|
@@ -4622,7 +4364,9 @@ async function hydrateSPA(config) {
|
|
|
4622
4364
|
"[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output."
|
|
4623
4365
|
);
|
|
4624
4366
|
}
|
|
4625
|
-
mountOrUpdate(rootElement, resolved.handler
|
|
4367
|
+
mountOrUpdate(rootElement, resolved.handler, {
|
|
4368
|
+
cleanupStrict: false
|
|
4369
|
+
});
|
|
4626
4370
|
const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await Promise.resolve().then(() => (init_navigate(), navigate_exports));
|
|
4627
4371
|
const instance = instancesByRoot.get(rootElement);
|
|
4628
4372
|
if (!instance) throw new Error("Internal error: app instance missing");
|
|
@@ -4646,13 +4390,6 @@ function hasApp(root) {
|
|
|
4646
4390
|
|
|
4647
4391
|
// src/index.ts
|
|
4648
4392
|
init_route();
|
|
4649
|
-
|
|
4650
|
-
// src/router/layouts.ts
|
|
4651
|
-
function layout(Layout) {
|
|
4652
|
-
return (children) => Layout({ children });
|
|
4653
|
-
}
|
|
4654
|
-
|
|
4655
|
-
// src/index.ts
|
|
4656
4393
|
init_route();
|
|
4657
4394
|
init_navigate();
|
|
4658
4395
|
|
|
@@ -4681,6 +4418,55 @@ function Link({ href, children }) {
|
|
|
4681
4418
|
};
|
|
4682
4419
|
}
|
|
4683
4420
|
|
|
4421
|
+
// src/foundations/layout.ts
|
|
4422
|
+
function layout(Layout) {
|
|
4423
|
+
return (children, props) => Layout({ ...props, children });
|
|
4424
|
+
}
|
|
4425
|
+
|
|
4426
|
+
// src/foundations/slot.ts
|
|
4427
|
+
init_logger();
|
|
4428
|
+
|
|
4429
|
+
// src/jsx/index.ts
|
|
4430
|
+
init_types2();
|
|
4431
|
+
|
|
4432
|
+
// src/jsx/utils.ts
|
|
4433
|
+
init_types2();
|
|
4434
|
+
function isElement(value) {
|
|
4435
|
+
return typeof value === "object" && value !== null && value.$$typeof === ELEMENT_TYPE;
|
|
4436
|
+
}
|
|
4437
|
+
function cloneElement(element, props) {
|
|
4438
|
+
return {
|
|
4439
|
+
...element,
|
|
4440
|
+
props: { ...element.props, ...props }
|
|
4441
|
+
};
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
// src/foundations/slot.ts
|
|
4445
|
+
function Slot(props) {
|
|
4446
|
+
if (props.asChild) {
|
|
4447
|
+
const { children, ...rest } = props;
|
|
4448
|
+
if (isElement(children)) {
|
|
4449
|
+
return cloneElement(children, rest);
|
|
4450
|
+
}
|
|
4451
|
+
logger.warn("<Slot asChild> expects a single JSX element child.");
|
|
4452
|
+
return null;
|
|
4453
|
+
}
|
|
4454
|
+
return { type: Fragment, props: { children: props.children } };
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
// src/foundations/portal.ts
|
|
4458
|
+
function definePortal() {
|
|
4459
|
+
const slot = createPortalSlot();
|
|
4460
|
+
function PortalHost() {
|
|
4461
|
+
return slot.read();
|
|
4462
|
+
}
|
|
4463
|
+
PortalHost.render = function PortalRender(props) {
|
|
4464
|
+
slot.write(props.children);
|
|
4465
|
+
return null;
|
|
4466
|
+
};
|
|
4467
|
+
return PortalHost;
|
|
4468
|
+
}
|
|
4469
|
+
|
|
4684
4470
|
// src/index.ts
|
|
4685
4471
|
init_ssr();
|
|
4686
4472
|
init_jsx_runtime();
|
|
@@ -4688,7 +4474,6 @@ init_route();
|
|
|
4688
4474
|
init_navigate();
|
|
4689
4475
|
if (typeof globalThis !== "undefined") {
|
|
4690
4476
|
const g = globalThis;
|
|
4691
|
-
if (!g.createApp) g.createApp = createApp;
|
|
4692
4477
|
if (!g.createIsland) g.createIsland = createIsland;
|
|
4693
4478
|
if (!g.createSPA) g.createSPA = createSPA;
|
|
4694
4479
|
if (!g.hydrateSPA) g.hydrateSPA = hydrateSPA;
|
|
@@ -4700,13 +4485,15 @@ if (typeof globalThis !== "undefined") {
|
|
|
4700
4485
|
0 && (module.exports = {
|
|
4701
4486
|
Fragment,
|
|
4702
4487
|
Link,
|
|
4488
|
+
Slot,
|
|
4703
4489
|
cleanupApp,
|
|
4704
4490
|
clearRoutes,
|
|
4705
4491
|
collectResources,
|
|
4706
|
-
createApp,
|
|
4707
4492
|
createIsland,
|
|
4708
4493
|
createSPA,
|
|
4709
4494
|
defineContext,
|
|
4495
|
+
definePortal,
|
|
4496
|
+
derive,
|
|
4710
4497
|
getLoadedNamespaces,
|
|
4711
4498
|
getNamespaceRoutes,
|
|
4712
4499
|
getRoutes,
|
|
@@ -4728,6 +4515,7 @@ if (typeof globalThis !== "undefined") {
|
|
|
4728
4515
|
scheduleEventHandler,
|
|
4729
4516
|
setServerLocation,
|
|
4730
4517
|
state,
|
|
4518
|
+
task,
|
|
4731
4519
|
unloadNamespace
|
|
4732
4520
|
});
|
|
4733
4521
|
//# sourceMappingURL=index.cjs.map
|