@askrjs/askr 0.0.35 → 0.0.37
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 +17 -9
- package/dist/bench/components/benchmark-row.js.map +1 -1
- package/dist/bench/components/benchmark-table.js +1 -1
- package/dist/bench/components/benchmark-table.js.map +1 -1
- package/dist/benchmark.js +3 -3
- package/dist/benchmark.js.map +1 -1
- package/dist/bin/askr-ssg.js.map +1 -1
- package/dist/boot/index.d.ts +1 -7
- package/dist/boot/index.d.ts.map +1 -1
- package/dist/boot/index.js +31 -42
- package/dist/boot/index.js.map +1 -1
- package/dist/common/control.js.map +1 -1
- package/dist/common/env.js.map +1 -1
- package/dist/common/ssr-errors.js.map +1 -1
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/components/link.d.ts +4 -5
- package/dist/components/link.d.ts.map +1 -1
- package/dist/components/link.js +2 -1
- package/dist/components/link.js.map +1 -1
- package/dist/control/case.js.map +1 -1
- package/dist/control/for.js.map +1 -1
- package/dist/control/shared.js.map +1 -1
- package/dist/control/show.js.map +1 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +165 -23
- package/dist/data/index.js.map +1 -1
- package/dist/dev/invariant.js.map +1 -1
- package/dist/dev/logger.js.map +1 -1
- package/dist/foundations/icon/icon.d.ts.map +1 -1
- package/dist/foundations/icon/icon.js.map +1 -1
- package/dist/foundations/icon/icon.types.d.ts +2 -1
- package/dist/foundations/icon/icon.types.d.ts.map +1 -1
- package/dist/foundations/icon/index.d.ts +3 -0
- package/dist/foundations/icon/index.js +2 -0
- package/dist/foundations/index.d.ts +1 -18
- package/dist/foundations/index.js +2 -18
- package/dist/foundations/interactions/dismissable.js.map +1 -1
- package/dist/foundations/interactions/focusable.js.map +1 -1
- package/dist/foundations/interactions/hoverable.js.map +1 -1
- package/dist/foundations/interactions/index.d.ts +7 -0
- package/dist/foundations/interactions/index.js +7 -0
- package/dist/foundations/interactions/interaction-policy.js +2 -2
- package/dist/foundations/interactions/interaction-policy.js.map +1 -1
- package/dist/foundations/interactions/pressable.js.map +1 -1
- package/dist/foundations/interactions/roving-focus.js.map +1 -1
- package/dist/foundations/state/controllable.js.map +1 -1
- package/dist/foundations/state/index.d.ts +2 -0
- package/dist/foundations/state/index.js +2 -0
- package/dist/foundations/structures/collection.js.map +1 -1
- package/dist/foundations/structures/index.d.ts +8 -0
- package/dist/foundations/structures/index.js +7 -0
- package/dist/foundations/structures/layer.js.map +1 -1
- package/dist/foundations/structures/layout.js.map +1 -1
- package/dist/foundations/structures/portal.js.map +1 -1
- package/dist/foundations/structures/presence.js.map +1 -1
- package/dist/foundations/structures/slot.js.map +1 -1
- package/dist/foundations/utilities/aria.js.map +1 -1
- package/dist/foundations/utilities/compose-handlers.js.map +1 -1
- package/dist/foundations/utilities/compose-ref.js.map +1 -1
- package/dist/foundations/utilities/index.d.ts +7 -0
- package/dist/foundations/utilities/index.js +6 -0
- package/dist/foundations/utilities/merge-props.js.map +1 -1
- package/dist/foundations/utilities/use-id.js.map +1 -1
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/timing.js.map +1 -1
- package/dist/index.d.ts +2 -16
- package/dist/index.js +1 -17
- package/dist/index.js.map +1 -1
- package/dist/jsx/utils.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/dom.js +92 -357
- package/dist/renderer/dom.js.map +1 -1
- package/dist/renderer/evaluate.js +7 -0
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js +20 -18
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/for-commit.js +486 -0
- package/dist/renderer/for-commit.js.map +1 -0
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyed.js +84 -23
- package/dist/renderer/keyed.js.map +1 -1
- package/dist/renderer/reconcile.js +11 -18
- package/dist/renderer/reconcile.js.map +1 -1
- package/dist/renderer/utils.js +5 -1
- package/dist/renderer/utils.js.map +1 -1
- package/dist/resources/index.d.ts +1 -2
- package/dist/resources/index.js +1 -2
- package/dist/router/index.d.ts +2 -2
- package/dist/router/index.js +2 -2
- package/dist/router/match.js.map +1 -1
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +4 -2
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/policy.js.map +1 -1
- package/dist/router/route-context.js.map +1 -1
- package/dist/router/route.d.ts +1 -1
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/route.js +2 -33
- package/dist/router/route.js.map +1 -1
- package/dist/runtime/child-scope.d.ts +1 -0
- package/dist/runtime/child-scope.d.ts.map +1 -1
- package/dist/runtime/child-scope.js +2 -0
- package/dist/runtime/child-scope.js.map +1 -1
- package/dist/runtime/component.js +1 -1
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/derive.d.ts +2 -1
- package/dist/runtime/derive.d.ts.map +1 -1
- package/dist/runtime/derive.js +15 -10
- package/dist/runtime/derive.js.map +1 -1
- package/dist/runtime/dev-namespace.js.map +1 -1
- package/dist/runtime/effect.d.ts.map +1 -1
- package/dist/runtime/effect.js +34 -9
- package/dist/runtime/effect.js.map +1 -1
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/execution-model.js.map +1 -1
- package/dist/runtime/fastlane.js.map +1 -1
- package/dist/runtime/for-bench.d.ts +1 -1
- package/dist/runtime/for-bench.d.ts.map +1 -1
- package/dist/runtime/for-bench.js +15 -14
- package/dist/runtime/for-bench.js.map +1 -1
- package/dist/runtime/for.d.ts +1 -0
- package/dist/runtime/for.d.ts.map +1 -1
- package/dist/runtime/for.js +90 -31
- package/dist/runtime/for.js.map +1 -1
- package/dist/runtime/operations.d.ts.map +1 -1
- package/dist/runtime/operations.js +10 -8
- package/dist/runtime/operations.js.map +1 -1
- package/dist/runtime/perf-metrics.js +8 -2
- package/dist/runtime/perf-metrics.js.map +1 -1
- package/dist/runtime/readable.js.map +1 -1
- package/dist/runtime/resource-cell.js +3 -2
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/scheduler.d.ts +0 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +6 -19
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector.d.ts.map +1 -1
- package/dist/runtime/selector.js +182 -103
- package/dist/runtime/selector.js.map +1 -1
- package/dist/runtime/snapshot-source.d.ts +10 -0
- package/dist/runtime/snapshot-source.d.ts.map +1 -0
- package/dist/runtime/snapshot-source.js +17 -0
- package/dist/runtime/snapshot-source.js.map +1 -0
- package/dist/runtime/ssr-bridge.js.map +1 -1
- package/dist/runtime/state.d.ts.map +1 -1
- package/dist/runtime/state.js +1 -5
- package/dist/runtime/state.js.map +1 -1
- package/dist/ssg/batch-render.js.map +1 -1
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/generate-metadata.js.map +1 -1
- package/dist/ssg/incremental-manifest.js.map +1 -1
- package/dist/ssg/index.d.ts +1 -6
- package/dist/ssg/index.js +1 -6
- package/dist/ssg/resolve-ssg-data.js.map +1 -1
- package/dist/ssg/route-utils.js.map +1 -1
- package/dist/ssg/write-static-files.js.map +1 -1
- package/dist/ssr/attrs.js.map +1 -1
- package/dist/ssr/context.d.ts +3 -1
- package/dist/ssr/context.d.ts.map +1 -1
- package/dist/ssr/context.js +31 -11
- package/dist/ssr/context.js.map +1 -1
- package/dist/ssr/escape.js +56 -16
- package/dist/ssr/escape.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -31
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +19 -49
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/render-keys.js +1 -12
- package/dist/ssr/render-keys.js.map +1 -1
- package/dist/ssr/sink.js.map +1 -1
- package/dist/ssr/verify-hydration.js +25 -0
- package/dist/ssr/verify-hydration.js.map +1 -0
- package/package.json +44 -19
- package/dist/_virtual/_rolldown/runtime.js +0 -7
- package/dist/foundations/core.d.ts +0 -15
- package/dist/foundations/core.js +0 -13
- package/dist/foundations/structures.d.ts +0 -7
- package/dist/foundations/structures.js +0 -6
- package/dist/ssg/batch-render.d.ts +0 -16
- package/dist/ssg/batch-render.d.ts.map +0 -1
- package/dist/ssg/generate-metadata.d.ts +0 -24
- package/dist/ssg/generate-metadata.d.ts.map +0 -1
- package/dist/ssg/resolve-ssg-data.d.ts +0 -23
- package/dist/ssg/resolve-ssg-data.d.ts.map +0 -1
- package/dist/ssg/route-utils.d.ts +0 -16
- package/dist/ssg/route-utils.d.ts.map +0 -1
- package/dist/ssg/write-static-files.d.ts +0 -15
- package/dist/ssg/write-static-files.d.ts.map +0 -1
- package/dist/ssr/render-keys.d.ts +0 -37
- package/dist/ssr/render-keys.d.ts.map +0 -1
- package/dist/ssr/stream-render.js +0 -76
- package/dist/ssr/stream-render.js.map +0 -1
package/dist/runtime/effect.js
CHANGED
|
@@ -15,7 +15,19 @@ const hasPendingLaneFlush = {
|
|
|
15
15
|
reactive: false,
|
|
16
16
|
post: false
|
|
17
17
|
};
|
|
18
|
+
const dirtyLaneState = {
|
|
19
|
+
derived: false,
|
|
20
|
+
component: false,
|
|
21
|
+
reactive: false,
|
|
22
|
+
post: false
|
|
23
|
+
};
|
|
18
24
|
const _evalSourceBuffer = /* @__PURE__ */ new Set();
|
|
25
|
+
const LANE_FLUSH_TASKS = {
|
|
26
|
+
derived: () => flushLaneEffects("derived"),
|
|
27
|
+
component: () => flushLaneEffects("component"),
|
|
28
|
+
reactive: () => flushLaneEffects("reactive"),
|
|
29
|
+
post: () => flushLaneEffects("post")
|
|
30
|
+
};
|
|
19
31
|
function registerEffectSource(source, effect) {
|
|
20
32
|
let effects = effectSources.get(source);
|
|
21
33
|
if (!effects) {
|
|
@@ -72,24 +84,28 @@ function flushLaneEffects(lane) {
|
|
|
72
84
|
hasPendingLaneFlush[lane] = false;
|
|
73
85
|
const effects = dirtyEffectsByLane[lane];
|
|
74
86
|
if (effects.size === 0) return;
|
|
75
|
-
const pending =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
const pending = effects.values();
|
|
88
|
+
let next = pending.next();
|
|
89
|
+
while (!next.done) {
|
|
90
|
+
const effect = next.value;
|
|
91
|
+
effects.delete(effect);
|
|
92
|
+
if (!effect.isActive) {
|
|
93
|
+
next = pending.next();
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
79
96
|
try {
|
|
80
97
|
const { value, nextSources } = evaluateEffect(effect);
|
|
81
98
|
commitEffectResult(effect, value, nextSources);
|
|
82
99
|
} catch (error) {
|
|
83
100
|
effect.onError?.(error);
|
|
84
101
|
}
|
|
102
|
+
next = pending.next();
|
|
85
103
|
}
|
|
86
104
|
}
|
|
87
105
|
function scheduleLaneFlush(lane) {
|
|
88
106
|
if (hasPendingLaneFlush[lane]) return;
|
|
89
107
|
hasPendingLaneFlush[lane] = true;
|
|
90
|
-
globalScheduler.enqueueInLane(lane,
|
|
91
|
-
flushLaneEffects(lane);
|
|
92
|
-
});
|
|
108
|
+
globalScheduler.enqueueInLane(lane, LANE_FLUSH_TASKS[lane]);
|
|
93
109
|
}
|
|
94
110
|
function unscheduleEffect(effect) {
|
|
95
111
|
dirtyEffectsByLane[effect.lane].delete(effect);
|
|
@@ -101,11 +117,20 @@ function recomputeEffectNow(effect) {
|
|
|
101
117
|
function markFineGrainedEffectsDirtySource(source) {
|
|
102
118
|
const effects = effectSources.get(source);
|
|
103
119
|
if (!effects || effects.size === 0) return;
|
|
120
|
+
dirtyLaneState.derived = false;
|
|
121
|
+
dirtyLaneState.component = false;
|
|
122
|
+
dirtyLaneState.reactive = false;
|
|
123
|
+
dirtyLaneState.post = false;
|
|
104
124
|
for (const effect of effects) {
|
|
105
125
|
if (!effect.isActive) continue;
|
|
106
|
-
|
|
126
|
+
const lane = effect.lane;
|
|
127
|
+
dirtyEffectsByLane[lane].add(effect);
|
|
128
|
+
dirtyLaneState[lane] = true;
|
|
107
129
|
}
|
|
108
|
-
|
|
130
|
+
if (dirtyLaneState.derived) scheduleLaneFlush("derived");
|
|
131
|
+
if (dirtyLaneState.component) scheduleLaneFlush("component");
|
|
132
|
+
if (dirtyLaneState.reactive) scheduleLaneFlush("reactive");
|
|
133
|
+
if (dirtyLaneState.post) scheduleLaneFlush("post");
|
|
109
134
|
}
|
|
110
135
|
function createFineGrainedEffect(options) {
|
|
111
136
|
const effect = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","names":[],"sources":["../../src/runtime/effect.ts"],"sourcesContent":["import { incDevCounter } from './dev-namespace';\nimport { type ReadableSource, withFineGrainedReadTracking } from './readable';\nimport { globalScheduler, type SchedulerLane } from './scheduler';\n\ntype EffectRegistry = WeakMap<\n ReadableSource<unknown>,\n Set<FineGrainedEffect<unknown>>\n>;\n\ntype EffectFlushSets = Record<SchedulerLane, Set<FineGrainedEffect<unknown>>>;\n\ntype EffectPendingFlushState = Record<SchedulerLane, boolean>;\n\nconst effectSources: EffectRegistry = new WeakMap();\nconst dirtyEffectsByLane: EffectFlushSets = {\n derived: new Set(),\n component: new Set(),\n reactive: new Set(),\n post: new Set(),\n};\nconst hasPendingLaneFlush: EffectPendingFlushState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst _evalSourceBuffer = new Set<ReadableSource<unknown>>();\n\nexport interface FineGrainedEffect<T> {\n lane: SchedulerLane;\n compute(): T;\n commit(value: T, previousValue: T | undefined): void;\n equals(previousValue: T, nextValue: T): boolean;\n readSources: Set<ReadableSource<unknown>>;\n isActive: boolean;\n hasValue: boolean;\n lastValue: T | undefined;\n onError?(error: unknown): void;\n}\n\nexport interface FineGrainedEffectHandle<T> {\n cleanup(): void;\n updateCompute(nextCompute: () => T): void;\n flush(): void;\n}\n\nexport interface CreateFineGrainedEffectOptions<T> {\n lane: SchedulerLane;\n compute: () => T;\n commit: (value: T, previousValue: T | undefined) => void;\n equals?: (previousValue: T, nextValue: T) => boolean;\n onError?: (error: unknown) => void;\n}\n\nfunction registerEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n let effects = effectSources.get(source);\n if (!effects) {\n effects = new Set();\n effectSources.set(source, effects);\n }\n effects.add(effect);\n}\n\nfunction unregisterEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n effectSources.get(source)?.delete(effect);\n}\n\nfunction clearEffectSubscriptions(effect: FineGrainedEffect<unknown>): void {\n for (const source of effect.readSources) {\n unregisterEffectSource(source, effect);\n }\n effect.readSources.clear();\n}\n\nfunction normalizeNextSources(\n previousSources: Set<ReadableSource<unknown>>,\n pendingSources: Set<ReadableSource<unknown>>\n): Set<ReadableSource<unknown>> {\n if (previousSources.size === pendingSources.size) {\n let same = true;\n for (const source of previousSources) {\n if (!pendingSources.has(source)) {\n same = false;\n break;\n }\n }\n\n if (same) {\n return previousSources;\n }\n }\n\n return new Set(pendingSources);\n}\n\nfunction evaluateEffect<T>(effect: FineGrainedEffect<T>): {\n value: T;\n nextSources: Set<ReadableSource<unknown>>;\n} {\n _evalSourceBuffer.clear();\n\n try {\n incDevCounter('effectRuns');\n const value = withFineGrainedReadTracking(_evalSourceBuffer, () =>\n effect.compute()\n );\n const nextSources = normalizeNextSources(\n effect.readSources,\n _evalSourceBuffer\n );\n return { value, nextSources };\n } finally {\n _evalSourceBuffer.clear();\n }\n}\n\nfunction commitEffectSubscriptions(\n effect: FineGrainedEffect<unknown>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousSources = effect.readSources;\n\n if (previousSources === nextSources) {\n return;\n }\n\n for (const source of previousSources) {\n if (!nextSources.has(source)) {\n unregisterEffectSource(source, effect);\n }\n }\n\n for (const source of nextSources) {\n if (!previousSources.has(source)) {\n registerEffectSource(source, effect);\n }\n }\n\n effect.readSources = nextSources;\n}\n\nfunction commitEffectResult<T>(\n effect: FineGrainedEffect<T>,\n value: T,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousValue = effect.lastValue;\n const shouldCommit =\n !effect.hasValue || !effect.equals(previousValue as T, value);\n\n if (shouldCommit) {\n effect.commit(value, effect.hasValue ? previousValue : undefined);\n }\n\n commitEffectSubscriptions(effect, nextSources);\n effect.lastValue = value;\n effect.hasValue = true;\n}\n\nfunction flushLaneEffects(lane: SchedulerLane): void {\n hasPendingLaneFlush[lane] = false;\n\n const effects = dirtyEffectsByLane[lane];\n if (effects.size === 0) {\n return;\n }\n\n const pending = Array.from(effects);\n effects.clear();\n\n for (const effect of pending) {\n if (!effect.isActive) {\n continue;\n }\n\n try {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n } catch (error) {\n effect.onError?.(error);\n }\n }\n}\n\nfunction scheduleLaneFlush(lane: SchedulerLane): void {\n if (hasPendingLaneFlush[lane]) {\n return;\n }\n\n hasPendingLaneFlush[lane] = true;\n globalScheduler.enqueueInLane(lane, () => {\n flushLaneEffects(lane);\n });\n}\n\nfunction unscheduleEffect(effect: FineGrainedEffect<unknown>): void {\n dirtyEffectsByLane[effect.lane].delete(effect);\n}\n\nfunction recomputeEffectNow<T>(effect: FineGrainedEffect<T>): void {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n}\n\nexport function markFineGrainedEffectsDirtySource(\n source: ReadableSource<unknown>\n): void {\n const effects = effectSources.get(source);\n if (!effects || effects.size === 0) {\n return;\n }\n\n for (const effect of effects) {\n if (!effect.isActive) {\n continue;\n }\n dirtyEffectsByLane[effect.lane].add(effect);\n }\n\n for (const lane of Object.keys(hasPendingLaneFlush) as SchedulerLane[]) {\n if (dirtyEffectsByLane[lane].size > 0) {\n scheduleLaneFlush(lane);\n }\n }\n}\n\nexport function createFineGrainedEffect<T>(\n options: CreateFineGrainedEffectOptions<T>\n): FineGrainedEffectHandle<T> {\n const effect: FineGrainedEffect<T> = {\n lane: options.lane,\n compute: options.compute,\n commit: options.commit,\n equals: options.equals ?? Object.is,\n readSources: new Set(),\n isActive: true,\n hasValue: false,\n lastValue: undefined,\n onError: options.onError,\n };\n\n recomputeEffectNow(effect);\n\n return {\n cleanup(): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.isActive = false;\n unscheduleEffect(effect);\n clearEffectSubscriptions(effect);\n },\n\n updateCompute(nextCompute: () => T): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.compute = nextCompute;\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n\n flush(): void {\n if (!effect.isActive) {\n return;\n }\n\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"effect.js","names":[],"sources":["../../src/runtime/effect.ts"],"sourcesContent":["import { incDevCounter } from './dev-namespace';\nimport { type ReadableSource, withFineGrainedReadTracking } from './readable';\nimport { globalScheduler, type SchedulerLane } from './scheduler';\n\ntype EffectRegistry = WeakMap<\n ReadableSource<unknown>,\n Set<FineGrainedEffect<unknown>>\n>;\n\ntype EffectFlushSets = Record<SchedulerLane, Set<FineGrainedEffect<unknown>>>;\n\ntype EffectPendingFlushState = Record<SchedulerLane, boolean>;\ntype EffectLaneDirtyState = Record<SchedulerLane, boolean>;\n\nconst effectSources: EffectRegistry = new WeakMap();\nconst dirtyEffectsByLane: EffectFlushSets = {\n derived: new Set(),\n component: new Set(),\n reactive: new Set(),\n post: new Set(),\n};\nconst hasPendingLaneFlush: EffectPendingFlushState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst dirtyLaneState: EffectLaneDirtyState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst _evalSourceBuffer = new Set<ReadableSource<unknown>>();\nconst LANE_FLUSH_TASKS: Record<SchedulerLane, () => void> = {\n derived: () => flushLaneEffects('derived'),\n component: () => flushLaneEffects('component'),\n reactive: () => flushLaneEffects('reactive'),\n post: () => flushLaneEffects('post'),\n};\n\nexport interface FineGrainedEffect<T> {\n lane: SchedulerLane;\n compute(): T;\n commit(value: T, previousValue: T | undefined): void;\n equals(previousValue: T, nextValue: T): boolean;\n readSources: Set<ReadableSource<unknown>>;\n isActive: boolean;\n hasValue: boolean;\n lastValue: T | undefined;\n onError?(error: unknown): void;\n}\n\nexport interface FineGrainedEffectHandle<T> {\n cleanup(): void;\n updateCompute(nextCompute: () => T): void;\n flush(): void;\n}\n\nexport interface CreateFineGrainedEffectOptions<T> {\n lane: SchedulerLane;\n compute: () => T;\n commit: (value: T, previousValue: T | undefined) => void;\n equals?: (previousValue: T, nextValue: T) => boolean;\n onError?: (error: unknown) => void;\n}\n\nfunction registerEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n let effects = effectSources.get(source);\n if (!effects) {\n effects = new Set();\n effectSources.set(source, effects);\n }\n effects.add(effect);\n}\n\nfunction unregisterEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n effectSources.get(source)?.delete(effect);\n}\n\nfunction clearEffectSubscriptions(effect: FineGrainedEffect<unknown>): void {\n for (const source of effect.readSources) {\n unregisterEffectSource(source, effect);\n }\n effect.readSources.clear();\n}\n\nfunction normalizeNextSources(\n previousSources: Set<ReadableSource<unknown>>,\n pendingSources: Set<ReadableSource<unknown>>\n): Set<ReadableSource<unknown>> {\n if (previousSources.size === pendingSources.size) {\n let same = true;\n for (const source of previousSources) {\n if (!pendingSources.has(source)) {\n same = false;\n break;\n }\n }\n\n if (same) {\n return previousSources;\n }\n }\n\n return new Set(pendingSources);\n}\n\nfunction evaluateEffect<T>(effect: FineGrainedEffect<T>): {\n value: T;\n nextSources: Set<ReadableSource<unknown>>;\n} {\n _evalSourceBuffer.clear();\n\n try {\n incDevCounter('effectRuns');\n const value = withFineGrainedReadTracking(_evalSourceBuffer, () =>\n effect.compute()\n );\n const nextSources = normalizeNextSources(\n effect.readSources,\n _evalSourceBuffer\n );\n return { value, nextSources };\n } finally {\n _evalSourceBuffer.clear();\n }\n}\n\nfunction commitEffectSubscriptions(\n effect: FineGrainedEffect<unknown>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousSources = effect.readSources;\n\n if (previousSources === nextSources) {\n return;\n }\n\n for (const source of previousSources) {\n if (!nextSources.has(source)) {\n unregisterEffectSource(source, effect);\n }\n }\n\n for (const source of nextSources) {\n if (!previousSources.has(source)) {\n registerEffectSource(source, effect);\n }\n }\n\n effect.readSources = nextSources;\n}\n\nfunction commitEffectResult<T>(\n effect: FineGrainedEffect<T>,\n value: T,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousValue = effect.lastValue;\n const shouldCommit =\n !effect.hasValue || !effect.equals(previousValue as T, value);\n\n if (shouldCommit) {\n effect.commit(value, effect.hasValue ? previousValue : undefined);\n }\n\n commitEffectSubscriptions(effect, nextSources);\n effect.lastValue = value;\n effect.hasValue = true;\n}\n\nfunction flushLaneEffects(lane: SchedulerLane): void {\n hasPendingLaneFlush[lane] = false;\n\n const effects = dirtyEffectsByLane[lane];\n if (effects.size === 0) {\n return;\n }\n\n const pending = effects.values();\n let next = pending.next();\n\n while (!next.done) {\n const effect = next.value as FineGrainedEffect<unknown>;\n effects.delete(effect);\n if (!effect.isActive) {\n next = pending.next();\n continue;\n }\n\n try {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n } catch (error) {\n effect.onError?.(error);\n }\n\n next = pending.next();\n }\n}\n\nfunction scheduleLaneFlush(lane: SchedulerLane): void {\n if (hasPendingLaneFlush[lane]) {\n return;\n }\n\n hasPendingLaneFlush[lane] = true;\n globalScheduler.enqueueInLane(lane, LANE_FLUSH_TASKS[lane]);\n}\n\nfunction unscheduleEffect(effect: FineGrainedEffect<unknown>): void {\n dirtyEffectsByLane[effect.lane].delete(effect);\n}\n\nfunction recomputeEffectNow<T>(effect: FineGrainedEffect<T>): void {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n}\n\nexport function markFineGrainedEffectsDirtySource(\n source: ReadableSource<unknown>\n): void {\n const effects = effectSources.get(source);\n if (!effects || effects.size === 0) {\n return;\n }\n\n dirtyLaneState.derived = false;\n dirtyLaneState.component = false;\n dirtyLaneState.reactive = false;\n dirtyLaneState.post = false;\n\n for (const effect of effects) {\n if (!effect.isActive) {\n continue;\n }\n const lane = effect.lane;\n dirtyEffectsByLane[lane].add(effect);\n dirtyLaneState[lane] = true;\n }\n\n if (dirtyLaneState.derived) {\n scheduleLaneFlush('derived');\n }\n if (dirtyLaneState.component) {\n scheduleLaneFlush('component');\n }\n if (dirtyLaneState.reactive) {\n scheduleLaneFlush('reactive');\n }\n if (dirtyLaneState.post) {\n scheduleLaneFlush('post');\n }\n}\n\nexport function createFineGrainedEffect<T>(\n options: CreateFineGrainedEffectOptions<T>\n): FineGrainedEffectHandle<T> {\n const effect: FineGrainedEffect<T> = {\n lane: options.lane,\n compute: options.compute,\n commit: options.commit,\n equals: options.equals ?? Object.is,\n readSources: new Set(),\n isActive: true,\n hasValue: false,\n lastValue: undefined,\n onError: options.onError,\n };\n\n recomputeEffectNow(effect);\n\n return {\n cleanup(): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.isActive = false;\n unscheduleEffect(effect);\n clearEffectSubscriptions(effect);\n },\n\n updateCompute(nextCompute: () => T): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.compute = nextCompute;\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n\n flush(): void {\n if (!effect.isActive) {\n return;\n }\n\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":[],"sources":["../../src/runtime/events.ts"],"sourcesContent":["/**\n * Event delegation system for Askr\n *\n * Provides efficient event handling by attaching listeners to a container\n * instead of individual elements. This significantly reduces memory usage\n * and improves performance when many elements have the same event type.\n *\n * Delegated handling is enabled by default. Tests and internal runtime code\n * can still disable or re-enable it when they need to exercise both modes.\n */\n\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport { incrementPerfMetric } from './perf-metrics';\nimport { incDevCounter } from './dev-namespace';\n\nexport interface DelegatedEventMap {\n click: MouseEvent;\n dblclick: MouseEvent;\n mousedown: MouseEvent;\n mouseup: MouseEvent;\n mouseover: MouseEvent;\n mouseout: MouseEvent;\n mousemove: MouseEvent;\n focus: FocusEvent;\n blur: FocusEvent;\n input: InputEvent;\n change: Event;\n keydown: KeyboardEvent;\n keyup: KeyboardEvent;\n keypress: KeyboardEvent;\n submit: Event;\n scroll: Event;\n wheel: WheelEvent;\n touchstart: TouchEvent;\n touchend: TouchEvent;\n touchmove: TouchEvent;\n touchcancel: TouchEvent;\n}\n\nconst DELEGATED_EVENTS: (keyof DelegatedEventMap)[] = [\n 'click',\n 'dblclick',\n 'mousedown',\n 'mouseup',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'focus',\n 'blur',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'keypress',\n 'submit',\n 'scroll',\n 'wheel',\n 'touchstart',\n 'touchend',\n 'touchmove',\n 'touchcancel',\n];\n\ninterface DelegatedHandler {\n handler: EventListener;\n original: EventListener;\n element: Element;\n eventName: string;\n options?: AddEventListenerOptions;\n}\n\ntype DelegatedHandlerStore = DelegatedHandler | Map<string, DelegatedHandler>;\n\nconst delegatedHandlers = new WeakMap<Element, DelegatedHandlerStore>();\n\nlet eventDelegationEnabled = true;\nlet defaultContainer: Element | null = null;\nlet globalDelegationContainer: Element | null = null;\nconst containerDelegatedListeners = new Map<\n Element,\n Map<string, EventListener>\n>();\n\nexport function isEventDelegationEnabled(): boolean {\n return eventDelegationEnabled;\n}\n\nexport function disableEventDelegation(): void {\n eventDelegationEnabled = false;\n cleanupAllDelegatedListeners();\n}\n\nexport function enableEventDelegation(container?: Element): void {\n eventDelegationEnabled = true;\n if (container) {\n defaultContainer = container;\n }\n}\n\nexport function setGlobalDelegationContainer(container: Element): void {\n globalDelegationContainer = container;\n}\n\nfunction cleanupAllDelegatedListeners(): void {\n for (const [container, listeners] of containerDelegatedListeners) {\n for (const [eventName, handler] of listeners) {\n container.removeEventListener(eventName, handler);\n }\n }\n containerDelegatedListeners.clear();\n}\n\nfunction getDelegationContainer(): Element | null {\n if (globalDelegationContainer) return globalDelegationContainer;\n if (defaultContainer) return defaultContainer;\n if (typeof document !== 'undefined') return document.body;\n return null;\n}\n\nfunction attachDelegatedListener(\n container: Element,\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!containerDelegatedListeners.has(container)) {\n containerDelegatedListeners.set(container, new Map());\n }\n const containerListeners = containerDelegatedListeners.get(container)!;\n\n if (!containerListeners.has(eventName)) {\n const delegatedHandler = (e: Event) => {\n const target = e.target as Element;\n if (!target) return;\n\n globalScheduler.runInHandlerScope(() => {\n let current: Element | null = target;\n while (current && current !== container) {\n incrementPerfMetric('delegatedAncestorHops');\n const store = delegatedHandlers.get(current);\n const entry = !store\n ? undefined\n : store instanceof Map\n ? store.get(eventName)\n : store.eventName === eventName\n ? store\n : undefined;\n if (entry) {\n try {\n entry.handler(e);\n } catch (error) {\n logger.error('[Askr] Delegated event error:', error);\n }\n }\n\n if (e.cancelBubble) {\n break;\n }\n\n current = current.parentElement;\n }\n }, 'sync');\n };\n\n const passiveOptions = getPassiveOptions(eventName);\n const listenerOptions = passiveOptions ?? options;\n\n container.addEventListener(eventName, delegatedHandler, listenerOptions);\n containerListeners.set(eventName, delegatedHandler);\n }\n\n setDelegatedHandlerForElement(element, {\n handler,\n original: originalHandler,\n element,\n eventName,\n options,\n });\n}\n\nfunction setDelegatedHandlerForElement(\n element: Element,\n entry: DelegatedHandler\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n if (existing instanceof Map) {\n existing.set(entry.eventName, entry);\n return;\n }\n\n if (existing.eventName === entry.eventName) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n const next = new Map<string, DelegatedHandler>();\n next.set(existing.eventName, existing);\n next.set(entry.eventName, entry);\n delegatedHandlers.set(element, next);\n}\n\nfunction getPassiveOptions(\n eventName: string\n): AddEventListenerOptions | undefined {\n if (\n eventName === 'wheel' ||\n eventName === 'scroll' ||\n eventName.startsWith('touch')\n ) {\n return { passive: true };\n }\n return undefined;\n}\n\nexport function addDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!eventDelegationEnabled) return;\n\n const container = getDelegationContainer();\n if (!container) return;\n\n incDevCounter('listenerAdds');\n\n attachDelegatedListener(\n container,\n element,\n eventName,\n handler,\n originalHandler,\n options\n );\n}\n\nexport function updateDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): boolean {\n const existing = getDelegatedHandlerForElement(element, eventName);\n if (!existing) {\n return false;\n }\n\n existing.handler = handler;\n existing.original = originalHandler;\n existing.options = options;\n return true;\n}\n\nexport function removeDelegatedListener(\n element: Element,\n eventName: string\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n return;\n }\n\n if (existing instanceof Map) {\n if (existing.has(eventName)) {\n incDevCounter('listenerRemoves');\n }\n existing.delete(eventName);\n if (existing.size === 0) {\n delegatedHandlers.delete(element);\n return;\n }\n if (existing.size === 1) {\n const only = existing.values().next().value as DelegatedHandler;\n delegatedHandlers.set(element, only);\n }\n return;\n }\n\n if (existing.eventName === eventName) {\n incDevCounter('listenerRemoves');\n delegatedHandlers.delete(element);\n }\n}\n\nexport function getDelegatedHandlerForElement(\n element: Element,\n eventName: string\n): DelegatedHandler | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store.get(eventName);\n return store.eventName === eventName ? store : undefined;\n}\n\nexport function getDelegatedHandlersForElement(\n element: Element\n): Map<string, DelegatedHandler> | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store;\n return new Map([[store.eventName, store]]);\n}\n\nexport function hasDelegatedHandler(\n element: Element,\n eventName: string\n): boolean {\n return getDelegatedHandlerForElement(element, eventName) !== undefined;\n}\n\nexport function clearDelegatedHandlersForElement(element: Element): void {\n delegatedHandlers.delete(element);\n}\n\nexport function getDelegatedEventNames(): readonly (keyof DelegatedEventMap)[] {\n return DELEGATED_EVENTS;\n}\n\nexport function isDelegatedEvent(eventName: string): boolean {\n return DELEGATED_EVENTS.includes(eventName as keyof DelegatedEventMap);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../src/runtime/events.ts"],"sourcesContent":["/**\n * Event delegation system for Askr\n *\n * Provides efficient event handling by attaching listeners to a container\n * instead of individual elements. This significantly reduces memory usage\n * and improves performance when many elements have the same event type.\n *\n * Delegated handling is enabled by default. Tests and internal runtime code\n * can still disable or re-enable it when they need to exercise both modes.\n */\n\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport { incrementPerfMetric } from './perf-metrics';\nimport { incDevCounter } from './dev-namespace';\n\nexport interface DelegatedEventMap {\n click: MouseEvent;\n dblclick: MouseEvent;\n mousedown: MouseEvent;\n mouseup: MouseEvent;\n mouseover: MouseEvent;\n mouseout: MouseEvent;\n mousemove: MouseEvent;\n focus: FocusEvent;\n blur: FocusEvent;\n input: InputEvent;\n change: Event;\n keydown: KeyboardEvent;\n keyup: KeyboardEvent;\n keypress: KeyboardEvent;\n submit: Event;\n scroll: Event;\n wheel: WheelEvent;\n touchstart: TouchEvent;\n touchend: TouchEvent;\n touchmove: TouchEvent;\n touchcancel: TouchEvent;\n}\n\nconst DELEGATED_EVENTS: (keyof DelegatedEventMap)[] = [\n 'click',\n 'dblclick',\n 'mousedown',\n 'mouseup',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'focus',\n 'blur',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'keypress',\n 'submit',\n 'scroll',\n 'wheel',\n 'touchstart',\n 'touchend',\n 'touchmove',\n 'touchcancel',\n];\n\ninterface DelegatedHandler {\n handler: EventListener;\n original: EventListener;\n element: Element;\n eventName: string;\n options?: AddEventListenerOptions;\n}\n\ntype DelegatedHandlerStore = DelegatedHandler | Map<string, DelegatedHandler>;\n\nconst delegatedHandlers = new WeakMap<Element, DelegatedHandlerStore>();\n\nlet eventDelegationEnabled = true;\nlet defaultContainer: Element | null = null;\nlet globalDelegationContainer: Element | null = null;\nconst containerDelegatedListeners = new Map<\n Element,\n Map<string, EventListener>\n>();\n\nexport function isEventDelegationEnabled(): boolean {\n return eventDelegationEnabled;\n}\n\nexport function disableEventDelegation(): void {\n eventDelegationEnabled = false;\n cleanupAllDelegatedListeners();\n}\n\nexport function enableEventDelegation(container?: Element): void {\n eventDelegationEnabled = true;\n if (container) {\n defaultContainer = container;\n }\n}\n\nexport function setGlobalDelegationContainer(container: Element): void {\n globalDelegationContainer = container;\n}\n\nfunction cleanupAllDelegatedListeners(): void {\n for (const [container, listeners] of containerDelegatedListeners) {\n for (const [eventName, handler] of listeners) {\n container.removeEventListener(eventName, handler);\n }\n }\n containerDelegatedListeners.clear();\n}\n\nfunction getDelegationContainer(): Element | null {\n if (globalDelegationContainer) return globalDelegationContainer;\n if (defaultContainer) return defaultContainer;\n if (typeof document !== 'undefined') return document.body;\n return null;\n}\n\nfunction attachDelegatedListener(\n container: Element,\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!containerDelegatedListeners.has(container)) {\n containerDelegatedListeners.set(container, new Map());\n }\n const containerListeners = containerDelegatedListeners.get(container)!;\n\n if (!containerListeners.has(eventName)) {\n const delegatedHandler = (e: Event) => {\n const target = e.target as Element;\n if (!target) return;\n\n globalScheduler.runInHandlerScope(() => {\n let current: Element | null = target;\n while (current && current !== container) {\n incrementPerfMetric('delegatedAncestorHops');\n const store = delegatedHandlers.get(current);\n const entry = !store\n ? undefined\n : store instanceof Map\n ? store.get(eventName)\n : store.eventName === eventName\n ? store\n : undefined;\n if (entry) {\n try {\n entry.handler(e);\n } catch (error) {\n logger.error('[Askr] Delegated event error:', error);\n }\n }\n\n if (e.cancelBubble) {\n break;\n }\n\n current = current.parentElement;\n }\n }, 'sync');\n };\n\n const passiveOptions = getPassiveOptions(eventName);\n const listenerOptions = passiveOptions ?? options;\n\n container.addEventListener(eventName, delegatedHandler, listenerOptions);\n containerListeners.set(eventName, delegatedHandler);\n }\n\n setDelegatedHandlerForElement(element, {\n handler,\n original: originalHandler,\n element,\n eventName,\n options,\n });\n}\n\nfunction setDelegatedHandlerForElement(\n element: Element,\n entry: DelegatedHandler\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n if (existing instanceof Map) {\n existing.set(entry.eventName, entry);\n return;\n }\n\n if (existing.eventName === entry.eventName) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n const next = new Map<string, DelegatedHandler>();\n next.set(existing.eventName, existing);\n next.set(entry.eventName, entry);\n delegatedHandlers.set(element, next);\n}\n\nfunction getPassiveOptions(\n eventName: string\n): AddEventListenerOptions | undefined {\n if (\n eventName === 'wheel' ||\n eventName === 'scroll' ||\n eventName.startsWith('touch')\n ) {\n return { passive: true };\n }\n return undefined;\n}\n\nexport function addDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!eventDelegationEnabled) return;\n\n const container = getDelegationContainer();\n if (!container) return;\n\n incDevCounter('listenerAdds');\n\n attachDelegatedListener(\n container,\n element,\n eventName,\n handler,\n originalHandler,\n options\n );\n}\n\nexport function updateDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): boolean {\n const existing = getDelegatedHandlerForElement(element, eventName);\n if (!existing) {\n return false;\n }\n\n existing.handler = handler;\n existing.original = originalHandler;\n existing.options = options;\n return true;\n}\n\nexport function removeDelegatedListener(\n element: Element,\n eventName: string\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n return;\n }\n\n if (existing instanceof Map) {\n if (existing.has(eventName)) {\n incDevCounter('listenerRemoves');\n }\n existing.delete(eventName);\n if (existing.size === 0) {\n delegatedHandlers.delete(element);\n return;\n }\n if (existing.size === 1) {\n const only = existing.values().next().value as DelegatedHandler;\n delegatedHandlers.set(element, only);\n }\n return;\n }\n\n if (existing.eventName === eventName) {\n incDevCounter('listenerRemoves');\n delegatedHandlers.delete(element);\n }\n}\n\nexport function getDelegatedHandlerForElement(\n element: Element,\n eventName: string\n): DelegatedHandler | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store.get(eventName);\n return store.eventName === eventName ? store : undefined;\n}\n\nexport function getDelegatedHandlersForElement(\n element: Element\n): Map<string, DelegatedHandler> | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store;\n return new Map([[store.eventName, store]]);\n}\n\nexport function hasDelegatedHandler(\n element: Element,\n eventName: string\n): boolean {\n return getDelegatedHandlerForElement(element, eventName) !== undefined;\n}\n\nexport function clearDelegatedHandlersForElement(element: Element): void {\n delegatedHandlers.delete(element);\n}\n\nexport function getDelegatedEventNames(): readonly (keyof DelegatedEventMap)[] {\n return DELEGATED_EVENTS;\n}\n\nexport function isDelegatedEvent(eventName: string): boolean {\n return DELEGATED_EVENTS.includes(eventName as keyof DelegatedEventMap);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-model.js","names":[],"sources":["../../src/runtime/execution-model.ts"],"sourcesContent":["export type ExecutionModel = 'spa' | 'islands' | 'ssr';\n\nconst EXECUTION_MODEL_KEY = Symbol.for('__ASKR_EXECUTION_MODEL__');\n\nexport function getExecutionModel(): ExecutionModel | undefined {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n return g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n}\n\nexport function assertExecutionModel(model: ExecutionModel): void {\n // Mixing execution models is forbidden: once an app starts in one model,\n // attempting to start another is an invariant violation.\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n const cur = g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n if (cur && cur !== model) {\n throw new Error(\n `[Askr] mixing execution models is not allowed (current: ${cur}, attempted: ${model}). ` +\n `Choose exactly one: createSPA, createSSR, or createIslands.`\n );\n }\n if (!cur) g[EXECUTION_MODEL_KEY] = model;\n}\n"],"mappings":";AAEA,MAAM,sBAAsB,OAAO,IAAI,2BAA2B;AAElE,SAAgB,oBAAgD;
|
|
1
|
+
{"version":3,"file":"execution-model.js","names":[],"sources":["../../src/runtime/execution-model.ts"],"sourcesContent":["export type ExecutionModel = 'spa' | 'islands' | 'ssr';\n\nconst EXECUTION_MODEL_KEY = Symbol.for('__ASKR_EXECUTION_MODEL__');\n\nexport function getExecutionModel(): ExecutionModel | undefined {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n return g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n}\n\nexport function assertExecutionModel(model: ExecutionModel): void {\n // Mixing execution models is forbidden: once an app starts in one model,\n // attempting to start another is an invariant violation.\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n const cur = g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n if (cur && cur !== model) {\n throw new Error(\n `[Askr] mixing execution models is not allowed (current: ${cur}, attempted: ${model}). ` +\n `Choose exactly one: createSPA, createSSR, or createIslands.`\n );\n }\n if (!cur) g[EXECUTION_MODEL_KEY] = model;\n}\n"],"mappings":";AAEA,MAAM,sBAAsB,OAAO,IAAI,2BAA2B;AAElE,SAAgB,oBAAgD;CAE9D,OAAO,WAAE;;AAGX,SAAgB,qBAAqB,OAA6B;CAGhE,MAAM,IAAI;CACV,MAAM,MAAM,EAAE;CACd,IAAI,OAAO,QAAQ,OACjB,MAAM,IAAI,MACR,2DAA2D,IAAI,eAAe,MAAM,gEAErF;CAEH,IAAI,CAAC,KAAK,EAAE,uBAAuB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastlane.js","names":[],"sources":["../../src/runtime/fastlane.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport type { ComponentInstance } from './component';\nimport { finalizeReadableSubscriptions } from './readable';\nimport {\n getKeyMapForElement,\n isKeyedReorderFastPathEligible,\n populateKeyMapForElement,\n} from '../renderer/keyed';\nimport { Fragment } from '../common/jsx';\nimport { setDevValue, getDevValue, getDevNamespace } from './dev-namespace';\n\nlet _bulkCommitActive = false;\nlet _appliedParents: WeakSet<Element> | null = null;\n\nexport function enterBulkCommit(): void {\n _bulkCommitActive = true;\n // Initialize registry of parents that had fast-path applied during this bulk commit\n _appliedParents = new WeakSet<Element>();\n\n // Clear any previously scheduled synchronous scheduler tasks so they don't\n // retrigger evaluations during the committed fast-path.\n try {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__ASKR_FASTLANE_CLEARED_TASKS', cleared);\n } catch (err) {\n if (isDevelopmentEnvironment()) throw err;\n }\n}\n\nexport function exitBulkCommit(): void {\n _bulkCommitActive = false;\n // Clear registry to avoid leaking across commits\n _appliedParents = null;\n}\n\nexport function isBulkCommitActive(): boolean {\n return _bulkCommitActive;\n}\n\n// Mark that a fast-path was applied on a parent element during the active\n// bulk commit. No-op if there is no active bulk commit.\nexport function markFastPathApplied(parent: Element): void {\n if (!_appliedParents) return;\n try {\n _appliedParents.add(parent);\n } catch (e) {\n void e;\n }\n}\n\nexport function isFastPathApplied(parent: Element): boolean {\n return !!(_appliedParents && _appliedParents.has(parent));\n}\n\nfunction finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Attempt to execute a runtime fast-lane for a single component's synchronous\n * render result. Returns true if the fast-lane was used and commit was done.\n *\n * Preconditions (checked conservatively):\n * - The render result is an intrinsic element root with keyed children\n * - The renderer's fast-path heuristics indicate to use the fast-path\n * - No mount operations are pending on the component instance\n * - No child vnodes are component functions (avoid async/component mounts)\n */\n\n// Helper to unwrap Fragment vnodes to get the first intrinsic element child\nfunction unwrapFragmentForFastPath(vnode: unknown): unknown {\n if (!vnode || typeof vnode !== 'object' || !('type' in vnode)) return vnode;\n const v = vnode as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n // Check if it's a Fragment\n if (\n typeof v.type === 'symbol' &&\n (v.type === Fragment || String(v.type) === 'Symbol(askr.fragment)')\n ) {\n const children = v.props?.children ?? v.children;\n if (Array.isArray(children) && children.length > 0) {\n // Return the first child that's an intrinsic element\n for (const child of children) {\n if (child && typeof child === 'object' && 'type' in child) {\n const c = child as { type: unknown };\n if (typeof c.type === 'string') {\n return child;\n }\n }\n }\n }\n }\n return vnode;\n}\n\nexport function classifyUpdate(instance: ComponentInstance, result: unknown) {\n // Returns a classification describing whether this update is eligible for\n // the reorder-only fast-lane. The classifier mirrors renderer-level\n // heuristics and performs runtime-level checks (mounts, effects, component\n // children) that the renderer cannot reason about.\n\n // Unwrap Fragment to get the actual element vnode for classification\n const unwrappedResult = unwrapFragmentForFastPath(result);\n\n if (\n !unwrappedResult ||\n typeof unwrappedResult !== 'object' ||\n !('type' in unwrappedResult)\n )\n return { useFastPath: false, reason: 'not-vnode' };\n\n const vnode = unwrappedResult as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n if (vnode == null || typeof vnode.type !== 'string')\n return { useFastPath: false, reason: 'not-intrinsic' };\n\n const parent = instance.target;\n if (!parent) return { useFastPath: false, reason: 'no-root' };\n\n const firstChild = parent.children[0] as Element | undefined;\n if (!firstChild) return { useFastPath: false, reason: 'no-first-child' };\n if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())\n return { useFastPath: false, reason: 'root-tag-mismatch' };\n\n const children = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(children))\n return { useFastPath: false, reason: 'no-children-array' };\n\n // Avoid component child vnodes (they may mount/unmount or trigger async)\n for (const c of children) {\n if (\n typeof c === 'object' &&\n c !== null &&\n 'type' in c &&\n typeof (c as { type?: unknown }).type === 'function'\n ) {\n return { useFastPath: false, reason: 'component-child-present' };\n }\n }\n\n if ((instance.mountOperations?.length ?? 0) > 0)\n return { useFastPath: false, reason: 'pending-mounts' };\n\n // Ask renderer for keyed reorder eligibility (prop differences & heuristics)\n // Ensure a keyed map is available for the first child by populating it proactively.\n try {\n populateKeyMapForElement(firstChild);\n } catch {\n // ignore\n }\n\n const oldKeyMap = getKeyMapForElement(firstChild);\n const decision = isKeyedReorderFastPathEligible(\n firstChild,\n children,\n oldKeyMap\n );\n\n if (!decision.useFastPath || decision.totalKeyed < 128)\n return { ...decision, useFastPath: false, reason: 'renderer-declined' };\n\n return { ...decision, useFastPath: true } as const;\n}\n\nexport function commitReorderOnly(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n // Performs the minimal, synchronous reorder-only commit.\n const evaluate = (\n globalThis as {\n __ASKR_RENDERER?: {\n evaluate?: (node: unknown, target: Element | null) => void;\n };\n }\n ).__ASKR_RENDERER?.evaluate;\n\n if (typeof evaluate !== 'function') {\n logger.warn(\n '[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane'\n );\n return false;\n }\n\n const schedBefore = isDevelopmentEnvironment()\n ? globalScheduler.getState()\n : null;\n\n enterBulkCommit();\n\n try {\n globalScheduler.runWithSyncProgress(() => {\n evaluate(result, instance.target);\n\n // Finalize runtime bookkeeping (read subscriptions / tokens)\n try {\n finalizeReadSubscriptions(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) throw e;\n }\n });\n\n // Clear any synchronous tasks scheduled during the commit\n const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__FASTLANE_CLEARED_AFTER', clearedAfter);\n\n // Dev-only invariant checks\n if (isDevelopmentEnvironment()) {\n validateFastLaneInvariants(instance, schedBefore);\n }\n\n return true;\n } finally {\n // Clear bulk commit flag first\n exitBulkCommit();\n }\n // Note: The original code had a check here that was dead code because\n // exitBulkCommit() already ran in the finally block. This comment serves\n // as documentation that we've intentionally removed that unreachable code.\n}\n\n/**\n * Validates fast-lane invariants in dev mode.\n * Extracted to reduce complexity in commitReorderOnly.\n */\nfunction validateFastLaneInvariants(\n instance: ComponentInstance,\n schedBefore: ReturnType<typeof globalScheduler.getState> | null\n): void {\n const commitCount = getDevValue<number>('__LAST_FASTPATH_COMMIT_COUNT') ?? 0;\n const invariants = {\n commitCount,\n mountOps: instance.mountOperations?.length ?? 0,\n cleanupFns: instance.cleanupFns?.length ?? 0,\n };\n setDevValue('__LAST_FASTLANE_INVARIANTS', invariants);\n\n if (commitCount !== 1) {\n console.error(\n '[FASTLANE][INV] commitCount',\n commitCount,\n 'diag',\n getDevNamespace()\n );\n throw new Error(\n 'Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit'\n );\n }\n\n if (invariants.mountOps > 0) {\n throw new Error(\n 'Fast-lane invariant violated: mount operations were registered during bulk commit'\n );\n }\n\n if (invariants.cleanupFns > 0) {\n throw new Error(\n 'Fast-lane invariant violated: cleanup functions were added during bulk commit'\n );\n }\n\n const schedAfter = globalScheduler.getState();\n if (\n schedBefore &&\n schedAfter &&\n schedAfter.taskCount > schedBefore.taskCount\n ) {\n console.error(\n '[FASTLANE] schedBefore, schedAfter',\n schedBefore,\n schedAfter\n );\n console.error('[FASTLANE] enqueue logs', getDevValue('__ENQUEUE_LOGS'));\n throw new Error(\n 'Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit'\n );\n }\n\n // Final quiescence assertion\n let finalState = globalScheduler.getState();\n const executing = globalScheduler.isExecuting();\n let outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (executing ? 1 : 0)\n );\n\n if (outstandingAfter !== 0) {\n // Attempt to clear newly enqueued synchronous tasks\n let attempts = 0;\n while (attempts < 5) {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n if (cleared === 0) break;\n attempts++;\n }\n finalState = globalScheduler.getState();\n outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)\n );\n if (outstandingAfter !== 0) {\n console.error(\n '[FASTLANE] Post-commit enqueue logs:',\n getDevValue('__ENQUEUE_LOGS')\n );\n console.error(\n '[FASTLANE] Cleared counts:',\n getDevValue('__FASTLANE_CLEARED_TASKS'),\n getDevValue('__FASTLANE_CLEARED_AFTER')\n );\n throw new Error(\n `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`\n );\n }\n }\n}\n\nexport function tryRuntimeFastLaneSync(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n const cls = classifyUpdate(instance, result);\n if (!cls.useFastPath) {\n // Clear stale fast-path diagnostics\n setDevValue('__LAST_FASTPATH_STATS', undefined);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 0);\n return false;\n }\n\n try {\n return commitReorderOnly(instance, result);\n } catch (err) {\n // Surface dev-only invariant failures, otherwise decline silently\n if (isDevelopmentEnvironment()) throw err;\n return false;\n }\n}\n\n// Expose fastlane bridge on globalThis for environments/tests\nif (typeof globalThis !== 'undefined') {\n (globalThis as Record<string, unknown>).__ASKR_FASTLANE = {\n isBulkCommitActive,\n enterBulkCommit,\n exitBulkCommit,\n tryRuntimeFastLaneSync,\n markFastPathApplied,\n isFastPathApplied,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fastlane.js","names":[],"sources":["../../src/runtime/fastlane.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport type { ComponentInstance } from './component';\nimport { finalizeReadableSubscriptions } from './readable';\nimport {\n getKeyMapForElement,\n isKeyedReorderFastPathEligible,\n populateKeyMapForElement,\n} from '../renderer/keyed';\nimport { Fragment } from '../common/jsx';\nimport { setDevValue, getDevValue, getDevNamespace } from './dev-namespace';\n\nlet _bulkCommitActive = false;\nlet _appliedParents: WeakSet<Element> | null = null;\n\nexport function enterBulkCommit(): void {\n _bulkCommitActive = true;\n // Initialize registry of parents that had fast-path applied during this bulk commit\n _appliedParents = new WeakSet<Element>();\n\n // Clear any previously scheduled synchronous scheduler tasks so they don't\n // retrigger evaluations during the committed fast-path.\n try {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__ASKR_FASTLANE_CLEARED_TASKS', cleared);\n } catch (err) {\n if (isDevelopmentEnvironment()) throw err;\n }\n}\n\nexport function exitBulkCommit(): void {\n _bulkCommitActive = false;\n // Clear registry to avoid leaking across commits\n _appliedParents = null;\n}\n\nexport function isBulkCommitActive(): boolean {\n return _bulkCommitActive;\n}\n\n// Mark that a fast-path was applied on a parent element during the active\n// bulk commit. No-op if there is no active bulk commit.\nexport function markFastPathApplied(parent: Element): void {\n if (!_appliedParents) return;\n try {\n _appliedParents.add(parent);\n } catch (e) {\n void e;\n }\n}\n\nexport function isFastPathApplied(parent: Element): boolean {\n return !!(_appliedParents && _appliedParents.has(parent));\n}\n\nfunction finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Attempt to execute a runtime fast-lane for a single component's synchronous\n * render result. Returns true if the fast-lane was used and commit was done.\n *\n * Preconditions (checked conservatively):\n * - The render result is an intrinsic element root with keyed children\n * - The renderer's fast-path heuristics indicate to use the fast-path\n * - No mount operations are pending on the component instance\n * - No child vnodes are component functions (avoid async/component mounts)\n */\n\n// Helper to unwrap Fragment vnodes to get the first intrinsic element child\nfunction unwrapFragmentForFastPath(vnode: unknown): unknown {\n if (!vnode || typeof vnode !== 'object' || !('type' in vnode)) return vnode;\n const v = vnode as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n // Check if it's a Fragment\n if (\n typeof v.type === 'symbol' &&\n (v.type === Fragment || String(v.type) === 'Symbol(askr.fragment)')\n ) {\n const children = v.props?.children ?? v.children;\n if (Array.isArray(children) && children.length > 0) {\n // Return the first child that's an intrinsic element\n for (const child of children) {\n if (child && typeof child === 'object' && 'type' in child) {\n const c = child as { type: unknown };\n if (typeof c.type === 'string') {\n return child;\n }\n }\n }\n }\n }\n return vnode;\n}\n\nexport function classifyUpdate(instance: ComponentInstance, result: unknown) {\n // Returns a classification describing whether this update is eligible for\n // the reorder-only fast-lane. The classifier mirrors renderer-level\n // heuristics and performs runtime-level checks (mounts, effects, component\n // children) that the renderer cannot reason about.\n\n // Unwrap Fragment to get the actual element vnode for classification\n const unwrappedResult = unwrapFragmentForFastPath(result);\n\n if (\n !unwrappedResult ||\n typeof unwrappedResult !== 'object' ||\n !('type' in unwrappedResult)\n )\n return { useFastPath: false, reason: 'not-vnode' };\n\n const vnode = unwrappedResult as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n if (vnode == null || typeof vnode.type !== 'string')\n return { useFastPath: false, reason: 'not-intrinsic' };\n\n const parent = instance.target;\n if (!parent) return { useFastPath: false, reason: 'no-root' };\n\n const firstChild = parent.children[0] as Element | undefined;\n if (!firstChild) return { useFastPath: false, reason: 'no-first-child' };\n if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())\n return { useFastPath: false, reason: 'root-tag-mismatch' };\n\n const children = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(children))\n return { useFastPath: false, reason: 'no-children-array' };\n\n // Avoid component child vnodes (they may mount/unmount or trigger async)\n for (const c of children) {\n if (\n typeof c === 'object' &&\n c !== null &&\n 'type' in c &&\n typeof (c as { type?: unknown }).type === 'function'\n ) {\n return { useFastPath: false, reason: 'component-child-present' };\n }\n }\n\n if ((instance.mountOperations?.length ?? 0) > 0)\n return { useFastPath: false, reason: 'pending-mounts' };\n\n // Ask renderer for keyed reorder eligibility (prop differences & heuristics)\n // Ensure a keyed map is available for the first child by populating it proactively.\n try {\n populateKeyMapForElement(firstChild);\n } catch {\n // ignore\n }\n\n const oldKeyMap = getKeyMapForElement(firstChild);\n const decision = isKeyedReorderFastPathEligible(\n firstChild,\n children,\n oldKeyMap\n );\n\n if (!decision.useFastPath || decision.totalKeyed < 128)\n return { ...decision, useFastPath: false, reason: 'renderer-declined' };\n\n return { ...decision, useFastPath: true } as const;\n}\n\nexport function commitReorderOnly(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n // Performs the minimal, synchronous reorder-only commit.\n const evaluate = (\n globalThis as {\n __ASKR_RENDERER?: {\n evaluate?: (node: unknown, target: Element | null) => void;\n };\n }\n ).__ASKR_RENDERER?.evaluate;\n\n if (typeof evaluate !== 'function') {\n logger.warn(\n '[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane'\n );\n return false;\n }\n\n const schedBefore = isDevelopmentEnvironment()\n ? globalScheduler.getState()\n : null;\n\n enterBulkCommit();\n\n try {\n globalScheduler.runWithSyncProgress(() => {\n evaluate(result, instance.target);\n\n // Finalize runtime bookkeeping (read subscriptions / tokens)\n try {\n finalizeReadSubscriptions(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) throw e;\n }\n });\n\n // Clear any synchronous tasks scheduled during the commit\n const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__FASTLANE_CLEARED_AFTER', clearedAfter);\n\n // Dev-only invariant checks\n if (isDevelopmentEnvironment()) {\n validateFastLaneInvariants(instance, schedBefore);\n }\n\n return true;\n } finally {\n // Clear bulk commit flag first\n exitBulkCommit();\n }\n // Note: The original code had a check here that was dead code because\n // exitBulkCommit() already ran in the finally block. This comment serves\n // as documentation that we've intentionally removed that unreachable code.\n}\n\n/**\n * Validates fast-lane invariants in dev mode.\n * Extracted to reduce complexity in commitReorderOnly.\n */\nfunction validateFastLaneInvariants(\n instance: ComponentInstance,\n schedBefore: ReturnType<typeof globalScheduler.getState> | null\n): void {\n const commitCount = getDevValue<number>('__LAST_FASTPATH_COMMIT_COUNT') ?? 0;\n const invariants = {\n commitCount,\n mountOps: instance.mountOperations?.length ?? 0,\n cleanupFns: instance.cleanupFns?.length ?? 0,\n };\n setDevValue('__LAST_FASTLANE_INVARIANTS', invariants);\n\n if (commitCount !== 1) {\n console.error(\n '[FASTLANE][INV] commitCount',\n commitCount,\n 'diag',\n getDevNamespace()\n );\n throw new Error(\n 'Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit'\n );\n }\n\n if (invariants.mountOps > 0) {\n throw new Error(\n 'Fast-lane invariant violated: mount operations were registered during bulk commit'\n );\n }\n\n if (invariants.cleanupFns > 0) {\n throw new Error(\n 'Fast-lane invariant violated: cleanup functions were added during bulk commit'\n );\n }\n\n const schedAfter = globalScheduler.getState();\n if (\n schedBefore &&\n schedAfter &&\n schedAfter.taskCount > schedBefore.taskCount\n ) {\n console.error(\n '[FASTLANE] schedBefore, schedAfter',\n schedBefore,\n schedAfter\n );\n console.error('[FASTLANE] enqueue logs', getDevValue('__ENQUEUE_LOGS'));\n throw new Error(\n 'Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit'\n );\n }\n\n // Final quiescence assertion\n let finalState = globalScheduler.getState();\n const executing = globalScheduler.isExecuting();\n let outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (executing ? 1 : 0)\n );\n\n if (outstandingAfter !== 0) {\n // Attempt to clear newly enqueued synchronous tasks\n let attempts = 0;\n while (attempts < 5) {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n if (cleared === 0) break;\n attempts++;\n }\n finalState = globalScheduler.getState();\n outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)\n );\n if (outstandingAfter !== 0) {\n console.error(\n '[FASTLANE] Post-commit enqueue logs:',\n getDevValue('__ENQUEUE_LOGS')\n );\n console.error(\n '[FASTLANE] Cleared counts:',\n getDevValue('__FASTLANE_CLEARED_TASKS'),\n getDevValue('__FASTLANE_CLEARED_AFTER')\n );\n throw new Error(\n `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`\n );\n }\n }\n}\n\nexport function tryRuntimeFastLaneSync(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n const cls = classifyUpdate(instance, result);\n if (!cls.useFastPath) {\n // Clear stale fast-path diagnostics\n setDevValue('__LAST_FASTPATH_STATS', undefined);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 0);\n return false;\n }\n\n try {\n return commitReorderOnly(instance, result);\n } catch (err) {\n // Surface dev-only invariant failures, otherwise decline silently\n if (isDevelopmentEnvironment()) throw err;\n return false;\n }\n}\n\n// Expose fastlane bridge on globalThis for environments/tests\nif (typeof globalThis !== 'undefined') {\n (globalThis as Record<string, unknown>).__ASKR_FASTLANE = {\n isBulkCommitActive,\n enterBulkCommit,\n exitBulkCommit,\n tryRuntimeFastLaneSync,\n markFastPathApplied,\n isFastPathApplied,\n };\n}\n"],"mappings":"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"}
|
|
@@ -27,7 +27,7 @@ type BenchMetricScope = 'coldCreate' | 'fullClear';
|
|
|
27
27
|
type BenchCounter = 'domNodesCreated' | 'listenerBindings' | 'reactivePropsMounted' | 'replaceChildrenCommits' | 'bulkClearCommits';
|
|
28
28
|
declare function withBenchMetricScopeLive<T>(scope: BenchMetricScope, run: () => T): T;
|
|
29
29
|
declare const resetBenchMetrics: () => void;
|
|
30
|
-
declare const recordBenchEvent: (event: BenchEvent) => void;
|
|
30
|
+
declare const recordBenchEvent: (event: BenchEvent, delta?: number) => void;
|
|
31
31
|
declare const recordBenchFastLane: (name: string) => void;
|
|
32
32
|
declare const recordBenchTiming: (phase: "reconcile" | "domCommit", ms: number) => void;
|
|
33
33
|
declare const recordBenchCounter: (counter: BenchCounter, delta?: number) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for-bench.d.ts","names":[],"sources":["../../src/runtime/for-bench.ts"],"mappings":";UASiB,YAAA;EACf,YAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,qBAAA;EACA,UAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,sBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,KAGU,UAAA;AAAA,KA0CP,gBAAA;AAAA,KACA,YAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"for-bench.d.ts","names":[],"sources":["../../src/runtime/for-bench.ts"],"mappings":";UASiB,YAAA;EACf,YAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,qBAAA;EACA,UAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,sBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,KAGU,UAAA;AAAA,KA0CP,gBAAA;AAAA,KACA,YAAA;AAAA,iBAmJI,wBAAA,GAAA,CAA4B,KAAA,EAAO,gBAAA,EAAkB,GAAA,QAAW,CAAA,GAAI,CAAA;AAAA,cAoChE,iBAAA;AAAA,cAUA,gBAAA,GAAgB,KAAA,EAlIQ,UAAA,EAAU,KAAA;AAAA,cAsIlC,mBAAA,GAAmB,IAAA;AAAA,cAInB,iBAAA,GAAiB,KAAA,6BAnCI,EAAA;AAAA,cAuCrB,kBAAA,GAAkB,OAAA,EAlFU,YAAA,EAAY,KAAA;AAAA,cAsFxC,oBAAA,SAAoB,wBAAA;AAAA,cAIpB,wBAAA,GAAwB,KAAA,EAnDQ,gBAAA;AAAA,cAuDhC,eAAA,QArCmB,YAAA;AAAA,cAyCnB,iBAAA;AAAA,cAIA,mBAAA"}
|
|
@@ -69,47 +69,48 @@ function resetBenchMetricsLive(metrics) {
|
|
|
69
69
|
publishBenchMetrics(metrics);
|
|
70
70
|
}
|
|
71
71
|
const benchMetrics = BENCH_BUILD_ENABLED ? createInitialBenchMetrics() : null;
|
|
72
|
-
const recordBenchEventLive = (event) => {
|
|
72
|
+
const recordBenchEventLive = (event, delta = 1) => {
|
|
73
73
|
if (!isBenchRuntimeEnabled() || !benchMetrics) return;
|
|
74
|
+
if (delta === 0) return;
|
|
74
75
|
switch (event) {
|
|
75
76
|
case "itemCreated":
|
|
76
|
-
benchMetrics.itemsCreated
|
|
77
|
+
benchMetrics.itemsCreated += delta;
|
|
77
78
|
break;
|
|
78
79
|
case "itemReused":
|
|
79
|
-
benchMetrics.itemsReused
|
|
80
|
+
benchMetrics.itemsReused += delta;
|
|
80
81
|
break;
|
|
81
82
|
case "itemRemoved":
|
|
82
|
-
benchMetrics.itemsRemoved
|
|
83
|
+
benchMetrics.itemsRemoved += delta;
|
|
83
84
|
break;
|
|
84
85
|
case "itemMoved":
|
|
85
|
-
benchMetrics.itemsMoved
|
|
86
|
+
benchMetrics.itemsMoved += delta;
|
|
86
87
|
break;
|
|
87
88
|
case "rowFactory":
|
|
88
|
-
benchMetrics.rowFactoryInvocations
|
|
89
|
+
benchMetrics.rowFactoryInvocations += delta;
|
|
89
90
|
break;
|
|
90
91
|
case "keyLookup":
|
|
91
|
-
benchMetrics.keyLookups
|
|
92
|
+
benchMetrics.keyLookups += delta;
|
|
92
93
|
break;
|
|
93
94
|
case "keyHit":
|
|
94
|
-
benchMetrics.keyHits
|
|
95
|
+
benchMetrics.keyHits += delta;
|
|
95
96
|
break;
|
|
96
97
|
case "keyMiss":
|
|
97
|
-
benchMetrics.keyMisses
|
|
98
|
+
benchMetrics.keyMisses += delta;
|
|
98
99
|
break;
|
|
99
100
|
case "domInsert":
|
|
100
|
-
benchMetrics.domInserts
|
|
101
|
+
benchMetrics.domInserts += delta;
|
|
101
102
|
break;
|
|
102
103
|
case "domRemove":
|
|
103
|
-
benchMetrics.domRemoves
|
|
104
|
+
benchMetrics.domRemoves += delta;
|
|
104
105
|
break;
|
|
105
106
|
case "domMove":
|
|
106
|
-
benchMetrics.domMoves
|
|
107
|
+
benchMetrics.domMoves += delta;
|
|
107
108
|
break;
|
|
108
109
|
case "domAttrSet":
|
|
109
|
-
benchMetrics.domAttrSets
|
|
110
|
+
benchMetrics.domAttrSets += delta;
|
|
110
111
|
break;
|
|
111
112
|
case "domTextSet":
|
|
112
|
-
benchMetrics.domTextSets
|
|
113
|
+
benchMetrics.domTextSets += delta;
|
|
113
114
|
break;
|
|
114
115
|
}
|
|
115
116
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for-bench.js","names":[],"sources":["../../src/runtime/for-bench.ts"],"sourcesContent":["import { isRuntimeEnvFlagEnabled } from '../common/env';\n\nconst BENCH_BUILD_ENABLED = isRuntimeEnvFlagEnabled('ASKR_BENCH');\n\ntype BenchGlobal = typeof globalThis & {\n __ASKR_BENCH__?: boolean;\n __ASKR_FOR_BENCH__?: BenchMetrics;\n};\n\nexport interface BenchMetrics {\n itemsCreated: number;\n itemsReused: number;\n itemsRemoved: number;\n itemsMoved: number;\n rowFactoryInvocations: number;\n keyLookups: number;\n keyHits: number;\n keyMisses: number;\n domInserts: number;\n domRemoves: number;\n domMoves: number;\n domAttrSets: number;\n domTextSets: number;\n domNodesCreated: number;\n listenerBindings: number;\n reactivePropsMounted: number;\n replaceChildrenCommits: number;\n bulkClearCommits: number;\n reconcilePhaseMs: number;\n domCommitPhaseMs: number;\n fastLaneName: string | null;\n}\n\nexport type BenchEvent =\n | 'itemCreated'\n | 'itemReused'\n | 'itemRemoved'\n | 'itemMoved'\n | 'rowFactory'\n | 'keyLookup'\n | 'keyHit'\n | 'keyMiss'\n | 'domInsert'\n | 'domRemove'\n | 'domMove'\n | 'domAttrSet'\n | 'domTextSet';\n\nfunction createInitialBenchMetrics(): BenchMetrics {\n return {\n itemsCreated: 0,\n itemsReused: 0,\n itemsRemoved: 0,\n itemsMoved: 0,\n rowFactoryInvocations: 0,\n keyLookups: 0,\n keyHits: 0,\n keyMisses: 0,\n domInserts: 0,\n domRemoves: 0,\n domMoves: 0,\n domAttrSets: 0,\n domTextSets: 0,\n domNodesCreated: 0,\n listenerBindings: 0,\n reactivePropsMounted: 0,\n replaceChildrenCommits: 0,\n bulkClearCommits: 0,\n reconcilePhaseMs: 0,\n domCommitPhaseMs: 0,\n fastLaneName: null,\n };\n}\n\nconst emptyBenchMetrics = createInitialBenchMetrics();\ntype BenchMetricScope = 'coldCreate' | 'fullClear';\ntype BenchCounter =\n | 'domNodesCreated'\n | 'listenerBindings'\n | 'reactivePropsMounted'\n | 'replaceChildrenCommits'\n | 'bulkClearCommits';\nlet activeBenchMetricScope: BenchMetricScope | null = null;\n\nfunction isBenchRuntimeEnabled(): boolean {\n if (!BENCH_BUILD_ENABLED) {\n return false;\n }\n\n try {\n return !!(globalThis as BenchGlobal).__ASKR_BENCH__;\n } catch {\n return false;\n }\n}\n\nfunction publishBenchMetrics(metrics: BenchMetrics): void {\n if (!isBenchRuntimeEnabled()) {\n return;\n }\n\n (globalThis as BenchGlobal).__ASKR_FOR_BENCH__ = { ...metrics };\n}\n\nconst flushBenchMetricsLive = (): void => {\n if (!benchMetrics) {\n return;\n }\n\n publishBenchMetrics(benchMetrics);\n};\n\nfunction resetBenchMetricsLive(metrics: BenchMetrics): void {\n metrics.itemsCreated = 0;\n metrics.itemsReused = 0;\n metrics.itemsRemoved = 0;\n metrics.itemsMoved = 0;\n metrics.rowFactoryInvocations = 0;\n metrics.keyLookups = 0;\n metrics.keyHits = 0;\n metrics.keyMisses = 0;\n metrics.domInserts = 0;\n metrics.domRemoves = 0;\n metrics.domMoves = 0;\n metrics.domAttrSets = 0;\n metrics.domTextSets = 0;\n metrics.domNodesCreated = 0;\n metrics.listenerBindings = 0;\n metrics.reactivePropsMounted = 0;\n metrics.replaceChildrenCommits = 0;\n metrics.bulkClearCommits = 0;\n metrics.reconcilePhaseMs = 0;\n metrics.domCommitPhaseMs = 0;\n metrics.fastLaneName = null;\n publishBenchMetrics(metrics);\n}\n\nconst benchMetrics = BENCH_BUILD_ENABLED ? createInitialBenchMetrics() : null;\n\nconst recordBenchEventLive = (event: BenchEvent): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n switch (event) {\n case 'itemCreated':\n benchMetrics.itemsCreated++;\n break;\n case 'itemReused':\n benchMetrics.itemsReused++;\n break;\n case 'itemRemoved':\n benchMetrics.itemsRemoved++;\n break;\n case 'itemMoved':\n benchMetrics.itemsMoved++;\n break;\n case 'rowFactory':\n benchMetrics.rowFactoryInvocations++;\n break;\n case 'keyLookup':\n benchMetrics.keyLookups++;\n break;\n case 'keyHit':\n benchMetrics.keyHits++;\n break;\n case 'keyMiss':\n benchMetrics.keyMisses++;\n break;\n case 'domInsert':\n benchMetrics.domInserts++;\n break;\n case 'domRemove':\n benchMetrics.domRemoves++;\n break;\n case 'domMove':\n benchMetrics.domMoves++;\n break;\n case 'domAttrSet':\n benchMetrics.domAttrSets++;\n break;\n case 'domTextSet':\n benchMetrics.domTextSets++;\n break;\n }\n};\n\nconst recordBenchFastLaneLive = (name: string): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n benchMetrics.fastLaneName = name;\n};\n\nconst recordBenchCounterLive = (counter: BenchCounter, delta = 1): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics || delta === 0) {\n return;\n }\n\n switch (counter) {\n case 'domNodesCreated':\n benchMetrics.domNodesCreated += delta;\n break;\n case 'listenerBindings':\n benchMetrics.listenerBindings += delta;\n break;\n case 'reactivePropsMounted':\n benchMetrics.reactivePropsMounted += delta;\n break;\n case 'replaceChildrenCommits':\n benchMetrics.replaceChildrenCommits += delta;\n break;\n case 'bulkClearCommits':\n benchMetrics.bulkClearCommits += delta;\n break;\n }\n};\n\nfunction withBenchMetricScopeLive<T>(scope: BenchMetricScope, run: () => T): T {\n if (!isBenchRuntimeEnabled()) {\n return run();\n }\n\n const previousScope = activeBenchMetricScope;\n activeBenchMetricScope = scope;\n\n try {\n return run();\n } finally {\n activeBenchMetricScope = previousScope;\n }\n}\n\nconst isBenchMetricScopeActiveLive = (scope: BenchMetricScope): boolean =>\n isBenchRuntimeEnabled() && activeBenchMetricScope === scope;\n\nconst recordBenchTimingLive = (\n phase: 'reconcile' | 'domCommit',\n ms: number\n): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n if (phase === 'reconcile') {\n benchMetrics.reconcilePhaseMs = ms;\n } else {\n benchMetrics.domCommitPhaseMs = ms;\n }\n};\n\nconst getBenchMetricsLive = (): BenchMetrics =>\n benchMetrics ? { ...benchMetrics } : { ...emptyBenchMetrics };\n\nexport const resetBenchMetrics = BENCH_BUILD_ENABLED\n ? (): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n resetBenchMetricsLive(benchMetrics);\n }\n : (): void => {};\n\nexport const recordBenchEvent = BENCH_BUILD_ENABLED\n ? recordBenchEventLive\n : (_event: BenchEvent): void => {};\n\nexport const recordBenchFastLane = BENCH_BUILD_ENABLED\n ? recordBenchFastLaneLive\n : (_name: string): void => {};\n\nexport const recordBenchTiming = BENCH_BUILD_ENABLED\n ? recordBenchTimingLive\n : (_phase: 'reconcile' | 'domCommit', _ms: number): void => {};\n\nexport const recordBenchCounter = BENCH_BUILD_ENABLED\n ? recordBenchCounterLive\n : (_counter: BenchCounter, _delta = 1): void => {};\n\nexport const withBenchMetricScope = BENCH_BUILD_ENABLED\n ? withBenchMetricScopeLive\n : <T>(_scope: BenchMetricScope, run: () => T): T => run();\n\nexport const isBenchMetricScopeActive = BENCH_BUILD_ENABLED\n ? isBenchMetricScopeActiveLive\n : (_scope: BenchMetricScope): boolean => false;\n\nexport const getBenchMetrics = BENCH_BUILD_ENABLED\n ? getBenchMetricsLive\n : (): BenchMetrics => ({ ...emptyBenchMetrics });\n\nexport const flushBenchMetrics = BENCH_BUILD_ENABLED\n ? flushBenchMetricsLive\n : (): void => {};\n\nexport const isBenchBuildEnabled = (): boolean => BENCH_BUILD_ENABLED;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"for-bench.js","names":[],"sources":["../../src/runtime/for-bench.ts"],"sourcesContent":["import { isRuntimeEnvFlagEnabled } from '../common/env';\n\nconst BENCH_BUILD_ENABLED = isRuntimeEnvFlagEnabled('ASKR_BENCH');\n\ntype BenchGlobal = typeof globalThis & {\n __ASKR_BENCH__?: boolean;\n __ASKR_FOR_BENCH__?: BenchMetrics;\n};\n\nexport interface BenchMetrics {\n itemsCreated: number;\n itemsReused: number;\n itemsRemoved: number;\n itemsMoved: number;\n rowFactoryInvocations: number;\n keyLookups: number;\n keyHits: number;\n keyMisses: number;\n domInserts: number;\n domRemoves: number;\n domMoves: number;\n domAttrSets: number;\n domTextSets: number;\n domNodesCreated: number;\n listenerBindings: number;\n reactivePropsMounted: number;\n replaceChildrenCommits: number;\n bulkClearCommits: number;\n reconcilePhaseMs: number;\n domCommitPhaseMs: number;\n fastLaneName: string | null;\n}\n\nexport type BenchEvent =\n | 'itemCreated'\n | 'itemReused'\n | 'itemRemoved'\n | 'itemMoved'\n | 'rowFactory'\n | 'keyLookup'\n | 'keyHit'\n | 'keyMiss'\n | 'domInsert'\n | 'domRemove'\n | 'domMove'\n | 'domAttrSet'\n | 'domTextSet';\n\nfunction createInitialBenchMetrics(): BenchMetrics {\n return {\n itemsCreated: 0,\n itemsReused: 0,\n itemsRemoved: 0,\n itemsMoved: 0,\n rowFactoryInvocations: 0,\n keyLookups: 0,\n keyHits: 0,\n keyMisses: 0,\n domInserts: 0,\n domRemoves: 0,\n domMoves: 0,\n domAttrSets: 0,\n domTextSets: 0,\n domNodesCreated: 0,\n listenerBindings: 0,\n reactivePropsMounted: 0,\n replaceChildrenCommits: 0,\n bulkClearCommits: 0,\n reconcilePhaseMs: 0,\n domCommitPhaseMs: 0,\n fastLaneName: null,\n };\n}\n\nconst emptyBenchMetrics = createInitialBenchMetrics();\ntype BenchMetricScope = 'coldCreate' | 'fullClear';\ntype BenchCounter =\n | 'domNodesCreated'\n | 'listenerBindings'\n | 'reactivePropsMounted'\n | 'replaceChildrenCommits'\n | 'bulkClearCommits';\nlet activeBenchMetricScope: BenchMetricScope | null = null;\n\nfunction isBenchRuntimeEnabled(): boolean {\n if (!BENCH_BUILD_ENABLED) {\n return false;\n }\n\n try {\n return !!(globalThis as BenchGlobal).__ASKR_BENCH__;\n } catch {\n return false;\n }\n}\n\nfunction publishBenchMetrics(metrics: BenchMetrics): void {\n if (!isBenchRuntimeEnabled()) {\n return;\n }\n\n (globalThis as BenchGlobal).__ASKR_FOR_BENCH__ = { ...metrics };\n}\n\nconst flushBenchMetricsLive = (): void => {\n if (!benchMetrics) {\n return;\n }\n\n publishBenchMetrics(benchMetrics);\n};\n\nfunction resetBenchMetricsLive(metrics: BenchMetrics): void {\n metrics.itemsCreated = 0;\n metrics.itemsReused = 0;\n metrics.itemsRemoved = 0;\n metrics.itemsMoved = 0;\n metrics.rowFactoryInvocations = 0;\n metrics.keyLookups = 0;\n metrics.keyHits = 0;\n metrics.keyMisses = 0;\n metrics.domInserts = 0;\n metrics.domRemoves = 0;\n metrics.domMoves = 0;\n metrics.domAttrSets = 0;\n metrics.domTextSets = 0;\n metrics.domNodesCreated = 0;\n metrics.listenerBindings = 0;\n metrics.reactivePropsMounted = 0;\n metrics.replaceChildrenCommits = 0;\n metrics.bulkClearCommits = 0;\n metrics.reconcilePhaseMs = 0;\n metrics.domCommitPhaseMs = 0;\n metrics.fastLaneName = null;\n publishBenchMetrics(metrics);\n}\n\nconst benchMetrics = BENCH_BUILD_ENABLED ? createInitialBenchMetrics() : null;\n\nconst recordBenchEventLive = (event: BenchEvent, delta = 1): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n if (delta === 0) {\n return;\n }\n\n switch (event) {\n case 'itemCreated':\n benchMetrics.itemsCreated += delta;\n break;\n case 'itemReused':\n benchMetrics.itemsReused += delta;\n break;\n case 'itemRemoved':\n benchMetrics.itemsRemoved += delta;\n break;\n case 'itemMoved':\n benchMetrics.itemsMoved += delta;\n break;\n case 'rowFactory':\n benchMetrics.rowFactoryInvocations += delta;\n break;\n case 'keyLookup':\n benchMetrics.keyLookups += delta;\n break;\n case 'keyHit':\n benchMetrics.keyHits += delta;\n break;\n case 'keyMiss':\n benchMetrics.keyMisses += delta;\n break;\n case 'domInsert':\n benchMetrics.domInserts += delta;\n break;\n case 'domRemove':\n benchMetrics.domRemoves += delta;\n break;\n case 'domMove':\n benchMetrics.domMoves += delta;\n break;\n case 'domAttrSet':\n benchMetrics.domAttrSets += delta;\n break;\n case 'domTextSet':\n benchMetrics.domTextSets += delta;\n break;\n }\n};\n\nconst recordBenchFastLaneLive = (name: string): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n benchMetrics.fastLaneName = name;\n};\n\nconst recordBenchCounterLive = (counter: BenchCounter, delta = 1): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics || delta === 0) {\n return;\n }\n\n switch (counter) {\n case 'domNodesCreated':\n benchMetrics.domNodesCreated += delta;\n break;\n case 'listenerBindings':\n benchMetrics.listenerBindings += delta;\n break;\n case 'reactivePropsMounted':\n benchMetrics.reactivePropsMounted += delta;\n break;\n case 'replaceChildrenCommits':\n benchMetrics.replaceChildrenCommits += delta;\n break;\n case 'bulkClearCommits':\n benchMetrics.bulkClearCommits += delta;\n break;\n }\n};\n\nfunction withBenchMetricScopeLive<T>(scope: BenchMetricScope, run: () => T): T {\n if (!isBenchRuntimeEnabled()) {\n return run();\n }\n\n const previousScope = activeBenchMetricScope;\n activeBenchMetricScope = scope;\n\n try {\n return run();\n } finally {\n activeBenchMetricScope = previousScope;\n }\n}\n\nconst isBenchMetricScopeActiveLive = (scope: BenchMetricScope): boolean =>\n isBenchRuntimeEnabled() && activeBenchMetricScope === scope;\n\nconst recordBenchTimingLive = (\n phase: 'reconcile' | 'domCommit',\n ms: number\n): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n if (phase === 'reconcile') {\n benchMetrics.reconcilePhaseMs = ms;\n } else {\n benchMetrics.domCommitPhaseMs = ms;\n }\n};\n\nconst getBenchMetricsLive = (): BenchMetrics =>\n benchMetrics ? { ...benchMetrics } : { ...emptyBenchMetrics };\n\nexport const resetBenchMetrics = BENCH_BUILD_ENABLED\n ? (): void => {\n if (!isBenchRuntimeEnabled() || !benchMetrics) {\n return;\n }\n\n resetBenchMetricsLive(benchMetrics);\n }\n : (): void => {};\n\nexport const recordBenchEvent = BENCH_BUILD_ENABLED\n ? recordBenchEventLive\n : (_event: BenchEvent): void => {};\n\nexport const recordBenchFastLane = BENCH_BUILD_ENABLED\n ? recordBenchFastLaneLive\n : (_name: string): void => {};\n\nexport const recordBenchTiming = BENCH_BUILD_ENABLED\n ? recordBenchTimingLive\n : (_phase: 'reconcile' | 'domCommit', _ms: number): void => {};\n\nexport const recordBenchCounter = BENCH_BUILD_ENABLED\n ? recordBenchCounterLive\n : (_counter: BenchCounter, _delta = 1): void => {};\n\nexport const withBenchMetricScope = BENCH_BUILD_ENABLED\n ? withBenchMetricScopeLive\n : <T>(_scope: BenchMetricScope, run: () => T): T => run();\n\nexport const isBenchMetricScopeActive = BENCH_BUILD_ENABLED\n ? isBenchMetricScopeActiveLive\n : (_scope: BenchMetricScope): boolean => false;\n\nexport const getBenchMetrics = BENCH_BUILD_ENABLED\n ? getBenchMetricsLive\n : (): BenchMetrics => ({ ...emptyBenchMetrics });\n\nexport const flushBenchMetrics = BENCH_BUILD_ENABLED\n ? flushBenchMetricsLive\n : (): void => {};\n\nexport const isBenchBuildEnabled = (): boolean => BENCH_BUILD_ENABLED;\n"],"mappings":"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"}
|
package/dist/runtime/for.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ interface ForState<T> {
|
|
|
37
37
|
fallbackScope: ChildScope | null;
|
|
38
38
|
items: Map<string | number, ForItemInstance<T>>;
|
|
39
39
|
orderedKeys: Array<string | number>;
|
|
40
|
+
orderedItems: ForItemInstance<T>[];
|
|
40
41
|
orderedVNodes: VNode[];
|
|
41
42
|
byFn: NonNullable<ForProps<T>['by']> | ((item: T, index: number) => number);
|
|
42
43
|
renderFn: (item: T, index: () => number) => VNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for.d.ts","names":[],"sources":["../../src/runtime/for.ts"],"mappings":";;;;;;;;;UAoDiB,eAAA;EACf,GAAA;EACA,IAAA,EAAM,CAAA;EACN,YAAA,EAAc,CAAA;EACd,UAAA,EAAY,aAAA,CAAc,CAAA;EAC1B,mBAAA,EAAqB,GAAA,CAAI,WAAA,EAAa,qBAAA;EACtC,WAAA,EAAa,cAAA;EACb,KAAA,EAAO,UAAA;AAAA;AAAA,KAGJ,aAAA,MAAmB,cAAA,CAAe,CAAA,WAC9B,CAAA;EACL,IAAA,IAAQ,CAAA;EACR,GAAA,CAAI,QAAA,EAAU,CAAA,EAAG,aAAA;AAAA;AAAA,KAGhB,qBAAA,GAAwB,cAAA;EAEzB,IAAA;EACA,GAAA,CAAI,QAAA,WAAmB,aAAA;AAAA;AAAA,KAGtB,cAAA,GAAiB,cAAA;EAElB,IAAA;EACA,GAAA,CAAI,QAAA,aAAqB,IAAA;AAAA;AAAA,KAGjB,iBAAA;AAAA,UAOK,QAAA;EACf,IAAA;EACA,YAAA,EAAc,CAAA;EACd,UAAA,EAAY,aAAA,CAAc,CAAA;EAC1B,QAAA,EAAU,KAAA;EACV,aAAA,EAAe,UAAA;EACf,KAAA,EAAO,GAAA,kBAAqB,eAAA,CAAgB,CAAA;EAC5C,WAAA,EAAa,KAAA;EACb,aAAA,EAAe,KAAA;EACf,IAAA,EAAM,WAAA,CAAY,QAAA,CAAS,CAAA,aAAc,IAAA,EAAM,CAAA,EAAG,KAAA;EAClD,QAAA,GAAW,IAAA,EAAM,CAAA,EAAG,KAAA,mBAAwB,KAAA;EAC5C,cAAA,EAAgB,iBAAA;EAChB,kBAAA,EAAoB,iBAAA;EACpB,gBAAA,EAAkB,IAAA;EAClB,mBAAA;EACA,kBAAA;EACA,eAAA;EACA,mBAAA;EACA,qBAAA;EACA,aAAA,EAAe,uBAAA,CAAwB,CAAA;EACvC,oBAAA;EACA,sBAAA;EACA,yBAAA;EACA,WAAA,GAAc,GAAA;AAAA;AAAA,iBAmBA,cAAA,GAAA,CACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,IAAA,EAAM,QAAA,CAAS,CAAA,WACf,QAAA,GAAW,IAAA,EAAM,CAAA,EAAG,KAAA,mBAAwB,KAAA,EAC5C,QAAA,EAAU,KAAA,UACT,QAAA,CAAS,CAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"for.d.ts","names":[],"sources":["../../src/runtime/for.ts"],"mappings":";;;;;;;;;UAoDiB,eAAA;EACf,GAAA;EACA,IAAA,EAAM,CAAA;EACN,YAAA,EAAc,CAAA;EACd,UAAA,EAAY,aAAA,CAAc,CAAA;EAC1B,mBAAA,EAAqB,GAAA,CAAI,WAAA,EAAa,qBAAA;EACtC,WAAA,EAAa,cAAA;EACb,KAAA,EAAO,UAAA;AAAA;AAAA,KAGJ,aAAA,MAAmB,cAAA,CAAe,CAAA,WAC9B,CAAA;EACL,IAAA,IAAQ,CAAA;EACR,GAAA,CAAI,QAAA,EAAU,CAAA,EAAG,aAAA;AAAA;AAAA,KAGhB,qBAAA,GAAwB,cAAA;EAEzB,IAAA;EACA,GAAA,CAAI,QAAA,WAAmB,aAAA;AAAA;AAAA,KAGtB,cAAA,GAAiB,cAAA;EAElB,IAAA;EACA,GAAA,CAAI,QAAA,aAAqB,IAAA;AAAA;AAAA,KAGjB,iBAAA;AAAA,UAOK,QAAA;EACf,IAAA;EACA,YAAA,EAAc,CAAA;EACd,UAAA,EAAY,aAAA,CAAc,CAAA;EAC1B,QAAA,EAAU,KAAA;EACV,aAAA,EAAe,UAAA;EACf,KAAA,EAAO,GAAA,kBAAqB,eAAA,CAAgB,CAAA;EAC5C,WAAA,EAAa,KAAA;EACb,YAAA,EAAc,eAAA,CAAgB,CAAA;EAC9B,aAAA,EAAe,KAAA;EACf,IAAA,EAAM,WAAA,CAAY,QAAA,CAAS,CAAA,aAAc,IAAA,EAAM,CAAA,EAAG,KAAA;EAClD,QAAA,GAAW,IAAA,EAAM,CAAA,EAAG,KAAA,mBAAwB,KAAA;EAC5C,cAAA,EAAgB,iBAAA;EAChB,kBAAA,EAAoB,iBAAA;EACpB,gBAAA,EAAkB,IAAA;EAClB,mBAAA;EACA,kBAAA;EACA,eAAA;EACA,mBAAA;EACA,qBAAA;EACA,aAAA,EAAe,uBAAA,CAAwB,CAAA;EACvC,oBAAA;EACA,sBAAA;EACA,yBAAA;EACA,WAAA,GAAc,GAAA;AAAA;AAAA,iBAmBA,cAAA,GAAA,CACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,IAAA,EAAM,QAAA,CAAS,CAAA,WACf,QAAA,GAAW,IAAA,EAAM,CAAA,EAAG,KAAA,mBAAwB,KAAA,EAC5C,QAAA,EAAU,KAAA,UACT,QAAA,CAAS,CAAA;AAAA,iBA8BI,WAAA,GAAA,CACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,IAAA,EAAM,QAAA,CAAS,CAAA,WACf,QAAA,GAAW,IAAA,EAAM,CAAA,EAAG,KAAA,mBAAwB,KAAA,EAC5C,QAAA,EAAU,KAAA,UACT,QAAA,CAAS,CAAA;AAAA,iBAuUI,kBAAA,GAAA,CACd,GAAA,mBACA,IAAA,EAAM,CAAA,EACN,KAAA,UACA,QAAA,EAAU,QAAA,CAAS,CAAA,IAClB,eAAA,CAAgB,CAAA;AAAA,iBAiMH,iBAAA,GAAA,CACd,QAAA,EAAU,QAAA,CAAS,CAAA,GACnB,QAAA,EAAU,CAAA,KACT,KAAA;AAAA,iBAmiBa,gBAAA,GAAA,CAAoB,QAAA,EAAU,QAAA,CAAS,CAAA,IAAK,KAAA;AAAA,iBAS5C,sBAAA,GAAA,CAA0B,QAAA,EAAU,QAAA,CAAS,CAAA"}
|