@askrjs/askr 0.0.50 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bench/components/benchmark-table.js.map +1 -1
- package/dist/benchmark.js +5 -4
- package/dist/benchmark.js.map +1 -1
- package/dist/bin/askr-ssg.d.ts.map +1 -1
- package/dist/bin/askr-ssg.js.map +1 -1
- package/dist/boot/hydration.js.map +1 -1
- package/dist/boot/index.js +2 -1
- package/dist/boot/index.js.map +1 -1
- package/dist/boot/root-lifecycle.d.ts.map +1 -1
- package/dist/boot/root-lifecycle.js +4 -4
- package/dist/boot/root-lifecycle.js.map +1 -1
- package/dist/boot/route-startup.js.map +1 -1
- package/dist/common/error-boundary.d.ts +16 -0
- package/dist/common/error-boundary.d.ts.map +1 -0
- package/dist/common/invariant.js +17 -0
- package/dist/common/invariant.js.map +1 -0
- package/dist/{dev → common}/logger.js +5 -6
- package/dist/common/logger.js.map +1 -0
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.d.ts +2 -15
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary.js +2 -74
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/link.js +2 -0
- package/dist/components/link.js.map +1 -1
- package/dist/control/case.d.ts.map +1 -1
- package/dist/control/case.js +1 -0
- package/dist/control/case.js.map +1 -1
- package/dist/control/for.d.ts +3 -3
- package/dist/control/for.d.ts.map +1 -1
- package/dist/control/for.js +2 -2
- package/dist/control/for.js.map +1 -1
- package/dist/control/show.js +1 -0
- package/dist/control/show.js.map +1 -1
- package/dist/data/data-runtime.js.map +1 -1
- package/dist/data/invalidation.js +2 -2
- package/dist/data/invalidation.js.map +1 -1
- package/dist/data/mutation-cell.d.ts.map +1 -1
- package/dist/data/mutation-cell.js +1 -1
- package/dist/data/mutation-cell.js.map +1 -1
- package/dist/data/query-cell.js +2 -2
- package/dist/data/query-cell.js.map +1 -1
- package/dist/data/shared.js +1 -0
- package/dist/data/shared.js.map +1 -1
- package/dist/data/testing.js +2 -0
- package/dist/foundations/index.d.ts +1 -1
- package/dist/foundations/index.js +1 -1
- package/dist/foundations/state/controllable.d.ts +0 -1
- package/dist/foundations/state/controllable.d.ts.map +1 -1
- package/dist/foundations/state/controllable.js +1 -0
- package/dist/foundations/state/controllable.js.map +1 -1
- package/dist/foundations/structures/index.d.ts +1 -1
- package/dist/foundations/structures/index.js +2 -1
- package/dist/foundations/structures/portal.d.ts +2 -24
- package/dist/foundations/structures/portal.js +3 -187
- package/dist/fx/fx.js +2 -2
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/index.js +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/jsx/types.d.ts.map +1 -1
- package/dist/jsx-dev-runtime.js +1 -0
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.js +1 -0
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/renderer/attributes.js +1 -0
- package/dist/renderer/attributes.js.map +1 -1
- package/dist/renderer/boundaries.js +5 -5
- package/dist/renderer/boundaries.js.map +1 -1
- package/dist/renderer/child-shape.js +2 -2
- package/dist/renderer/child-shape.js.map +1 -1
- package/dist/renderer/children-fastpath.js +149 -0
- package/dist/renderer/children-fastpath.js.map +1 -0
- package/dist/renderer/children.js +3 -138
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js +2 -2
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/component-host-cleanup.js +1 -1
- package/dist/renderer/component-host-cleanup.js.map +1 -1
- package/dist/renderer/component-host-instances.js +1 -1
- package/dist/renderer/component-host-instances.js.map +1 -1
- package/dist/renderer/component-host.js +1 -1
- package/dist/renderer/component-host.js.map +1 -1
- package/dist/renderer/dom-host.js.map +1 -1
- package/dist/renderer/dom-internal.js +5 -4
- package/dist/renderer/dom-internal.js.map +1 -1
- package/dist/renderer/dom.js +2 -1
- package/dist/renderer/element-children.js.map +1 -1
- package/dist/renderer/error-boundary-dom.js +51 -2
- package/dist/renderer/error-boundary-dom.js.map +1 -1
- package/dist/renderer/evaluate-reconcile.js +6 -5
- package/dist/renderer/evaluate-reconcile.js.map +1 -1
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js +3 -2
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/for-commit-dom-map.js.map +1 -1
- package/dist/renderer/for-commit-removal.js +2 -2
- package/dist/renderer/for-commit-removal.js.map +1 -1
- package/dist/renderer/for-commit-reorder.js +2 -2
- package/dist/renderer/for-commit-reorder.js.map +1 -1
- package/dist/renderer/for-commit.js +3 -3
- package/dist/renderer/for-commit.js.map +1 -1
- package/dist/renderer/index.js +3 -1
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/prop-bindings.js +4 -4
- package/dist/renderer/prop-bindings.js.map +1 -1
- package/dist/renderer/reactive-child-dom.js.map +1 -1
- package/dist/renderer/reactive-children.js +4 -4
- package/dist/renderer/reactive-children.js.map +1 -1
- package/dist/renderer/reconcile-fastpaths.js +2 -1
- package/dist/renderer/reconcile-fastpaths.js.map +1 -1
- package/dist/renderer/reconcile-resolution.js +3 -3
- package/dist/renderer/reconcile-resolution.js.map +1 -1
- package/dist/renderer/retained-element-rollback.js +2 -1
- package/dist/renderer/retained-element-rollback.js.map +1 -1
- package/dist/renderer/stable-patch.js +2 -3
- package/dist/renderer/stable-patch.js.map +1 -1
- package/dist/renderer/utils.js +2 -1
- package/dist/renderer/utils.js.map +1 -1
- package/dist/resources/index.js +1 -2
- package/dist/router/activity.d.ts.map +1 -1
- package/dist/router/activity.js +20 -22
- package/dist/router/activity.js.map +1 -1
- package/dist/router/authoring.js +1 -1
- package/dist/router/authoring.js.map +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/navigate.js +1 -1
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/navigation-registry.js +1 -1
- package/dist/router/navigation-registry.js.map +1 -1
- package/dist/router/navigation-targets.d.ts.map +1 -1
- package/dist/router/navigation-targets.js +7 -5
- package/dist/router/navigation-targets.js.map +1 -1
- package/dist/router/rendering.js +1 -0
- package/dist/router/rendering.js.map +1 -1
- package/dist/router/resolution.d.ts +1 -14
- package/dist/router/resolution.d.ts.map +1 -1
- package/dist/router/resolution.js +6 -173
- package/dist/router/resolution.js.map +1 -1
- package/dist/router/route-matching.d.ts +20 -0
- package/dist/router/route-matching.d.ts.map +1 -0
- package/dist/router/route-matching.js +175 -0
- package/dist/router/route-matching.js.map +1 -0
- package/dist/router/route.js +4 -2
- package/dist/router/testing.js +4 -0
- package/dist/runtime/access.d.ts +20 -0
- package/dist/runtime/access.d.ts.map +1 -0
- package/dist/runtime/component-cleanup.js +1 -1
- package/dist/runtime/component-cleanup.js.map +1 -1
- package/dist/runtime/component-commit.js +1 -1
- package/dist/runtime/component-commit.js.map +1 -1
- package/dist/runtime/component-internal.d.ts +1 -1
- package/dist/runtime/component-internal.js +1 -1
- package/dist/runtime/component-internal.js.map +1 -1
- package/dist/runtime/component-lifecycle.d.ts +1 -1
- package/dist/runtime/component-lifecycle.js +1 -1
- package/dist/runtime/component-lifecycle.js.map +1 -1
- package/dist/runtime/component-scope.d.ts +1 -1
- package/dist/runtime/dev-namespace.d.ts +31 -0
- package/dist/runtime/dev-namespace.d.ts.map +1 -0
- package/dist/runtime/error-boundary.d.ts +5 -0
- package/dist/runtime/error-boundary.d.ts.map +1 -0
- package/dist/runtime/error-boundary.js +31 -0
- package/dist/runtime/error-boundary.js.map +1 -0
- package/dist/runtime/events.d.ts +58 -0
- package/dist/runtime/events.d.ts.map +1 -0
- package/dist/runtime/events.js +1 -1
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/execution-model.d.ts +7 -0
- package/dist/runtime/execution-model.d.ts.map +1 -0
- package/dist/runtime/fastlane.d.ts +34 -0
- package/dist/runtime/fastlane.d.ts.map +1 -0
- package/dist/runtime/for-internal.d.ts +5 -5
- package/dist/runtime/for-internal.d.ts.map +1 -1
- package/dist/runtime/for-internal.js.map +1 -1
- package/dist/runtime/for-signals.d.ts +1 -1
- package/dist/runtime/for-signals.d.ts.map +1 -1
- package/dist/runtime/for-signals.js +1 -1
- package/dist/runtime/for-signals.js.map +1 -1
- package/dist/runtime/for-types.d.ts +9 -0
- package/dist/runtime/for-types.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +24 -0
- package/dist/runtime/index.js +31 -0
- package/dist/runtime/perf-metrics.d.ts +26 -0
- package/dist/runtime/perf-metrics.d.ts.map +1 -0
- package/dist/runtime/portal.d.ts +22 -0
- package/dist/runtime/portal.d.ts.map +1 -0
- package/dist/runtime/portal.js +213 -0
- package/dist/runtime/portal.js.map +1 -0
- package/dist/runtime/resource-cell.js +1 -1
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/resource-operation.js +1 -1
- package/dist/runtime/runtime.d.ts +1 -1
- package/dist/runtime/scheduler.js +2 -2
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector-store.js +24 -0
- package/dist/runtime/selector-store.js.map +1 -0
- package/dist/runtime/selector.d.ts.map +1 -1
- package/dist/runtime/selector.js +3 -18
- package/dist/runtime/selector.js.map +1 -1
- package/dist/ssg/create-static-gen.js +1 -0
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/static-routes.js +1 -0
- package/dist/ssg/static-routes.js.map +1 -1
- package/dist/ssr/boundaries.js +2 -2
- package/dist/ssr/boundaries.js.map +1 -1
- package/dist/ssr/component-runtime.js +3 -3
- package/dist/ssr/component-runtime.js.map +1 -1
- package/dist/ssr/render-resolved.js +1 -1
- package/dist/ssr/render-sync.js +1 -1
- package/dist/ssr/render-sync.js.map +1 -1
- package/dist/ssr/route-policy-resolution.js +2 -1
- package/dist/ssr/route-policy-resolution.js.map +1 -1
- package/dist/ssr/route-render.js +2 -1
- package/dist/ssr/route-render.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +3 -2
- package/dist/testing/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/dev/invariant.js +0 -29
- package/dist/dev/invariant.js.map +0 -1
- package/dist/dev/logger.js.map +0 -1
- package/dist/foundations/structures/portal.d.ts.map +0 -1
- package/dist/foundations/structures/portal.js.map +0 -1
- package/dist/runtime/component-contracts.js +0 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Props } from "../common/props.js";
|
|
2
|
-
import { ReadableSource } from "./readable.js";
|
|
3
2
|
import { State } from "./state.js";
|
|
4
3
|
import { ContextFrame } from "./context.js";
|
|
5
4
|
import { OwnedChildScope, cleanupComponent, registerOwnedChildScope, unregisterOwnedChildScope } from "./component-cleanup.js";
|
|
6
5
|
import { LifecycleOperation } from "./component-lifecycle.js";
|
|
6
|
+
import { ReadableSource } from "./readable.js";
|
|
7
7
|
import { ComponentFunction } from "../common/component.js";
|
|
8
8
|
|
|
9
9
|
//#region src/runtime/component-internal.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isDevelopmentEnvironment, isProductionEnvironment } from "../common/env.js";
|
|
2
|
-
import { logger } from "../
|
|
2
|
+
import { logger } from "../common/logger.js";
|
|
3
3
|
import { enqueueRuntimeTask } from "./access.js";
|
|
4
4
|
import { withContext } from "./context.js";
|
|
5
5
|
import { finalizeReadableSubscriptions } from "./readable.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-internal.js","names":[],"sources":["../../src/runtime/component-internal.ts"],"sourcesContent":["/**\n * Component instance lifecycle management\n * Internal only — users never see this\n */\n\nimport { type State } from './state';\nimport { enqueueRuntimeTask } from './access';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport {\n // withContext is the sole primitive for context restoration\n withContext,\n type ContextFrame,\n} from './context';\nimport { type ReadableSource, finalizeReadableSubscriptions } from './readable';\nimport {\n isDevelopmentEnvironment,\n isProductionEnvironment,\n} from '../common/env';\nimport { logger } from '../dev/logger';\nimport { incDevCounter } from './dev-namespace';\nimport {\n cleanupComponent,\n registerOwnedChildScope,\n unregisterOwnedChildScope,\n type OwnedChildScope,\n} from './component-cleanup';\nimport { runScheduledComponent } from './component-commit';\nimport {\n captureInlineRenderSnapshot as captureLifecycleInlineRenderSnapshot,\n commitLifecycleForInstance,\n commitRenderedComponent as commitRenderedLifecycleComponent,\n discardCommitOperations,\n finalizeInlineReadSubscriptions,\n registerCommitOperationForInstance,\n registerMountOperationForInstance,\n type LifecycleOperation,\n} from './component-lifecycle';\nimport {\n beginRenderTracking,\n captureInlineComponentScope,\n captureInlineRenderTracking,\n clearRenderTracking,\n enterComponentExecutionScope,\n enterRenderScopedComponent,\n exitComponentExecutionScope,\n getCurrentComponentInstance,\n getCurrentInstance,\n getCurrentPortalScope,\n getSignalForInstance,\n resetRenderState,\n restoreInlineComponentScope,\n restoreInlineRenderTracking,\n restoreRenderScopedComponent,\n} from './component-scope';\n\nexport type { ComponentFunction } from '../common/component';\nexport { cleanupComponent, registerOwnedChildScope, unregisterOwnedChildScope };\n\nexport interface ComponentInstance {\n id: string;\n fn: ComponentFunction;\n props: Props;\n target: Element | null;\n parentInstance: ComponentInstance | null;\n portalScope: object | null;\n mounted: boolean;\n abortController: AbortController | null; // Lazily created per-component abort lifecycle\n ssr?: boolean; // Set to true for SSR temporary instances\n // Opt-in strict cleanup mode: when true cleanup errors are aggregated and re-thrown\n cleanupStrict?: boolean;\n stateValues: State<unknown>[]; // Persistent state storage across renders\n evaluationGeneration: number; // Prevents stale async evaluation completions\n notifyUpdate: (() => void) | null; // Callback for state updates (persisted on instance)\n // Internal: prebound helpers to avoid per-update closures (allocation hot-path)\n _pendingFlushTask?: () => void; // Clears hasPendingUpdate and triggers notifyUpdate\n _pendingRunTask?: () => void; // Clears hasPendingUpdate and runs component\n _enqueueRun?: () => void; // Batches run requests and enqueues _pendingRunTask\n stateIndexCheck: number; // Track state indices to catch conditional calls\n expectedStateIndices: number[]; // Expected sequence of render-scoped hook indices (frozen after first render)\n firstRenderComplete: boolean; // Flag to detect transition from first to subsequent renders\n mountOperations: Array<\n () => void | (() => void) | PromiseLike<void | (() => void)>\n >; // Operations to run when component mounts\n commitOperations: Array<\n () => void | (() => void) | PromiseLike<void | (() => void)>\n >; // Operations to run after a successful committed render\n cleanupFns: Array<() => void>; // Cleanup functions to run on unmount\n lifecycleSlots: unknown[]; // Render-scoped lifecycle primitive storage\n lifecycleGeneration: number; // Invalidates async mount-operation settlement after disposal\n hasPendingUpdate: boolean; // Flag to batch state updates (coalescing)\n ownerFrame: ContextFrame | null; // Provider chain for this component (set by Scope, never overwritten)\n isRoot?: boolean;\n\n // Render-tracking for precise subscriptions (internal)\n _currentRenderToken?: number; // Token for the in-progress render (set before render)\n lastRenderToken?: number; // Token of the last *committed* render\n _pendingReadSources?: Set<ReadableSource<unknown>>; // Readables read during the in-progress render\n _pendingReadSourceVersions?: Map<ReadableSource<unknown>, number>; // Source versions captured during the in-progress render\n _lastReadSources?: Set<ReadableSource<unknown>>; // Readables read during the last committed render\n devWarningsEmitted?: Set<string>; // Dev-only warning dedupe for this instance\n\n // Placeholder for null-returning components. When a component initially returns\n // null, we create a comment placeholder so updates can replace it with content.\n _placeholder?: Comment;\n _ownedChildScopes?: Set<OwnedChildScope>;\n errorBoundaryState?: {\n error: unknown | null;\n resetKey: unknown;\n notified: boolean;\n };\n}\n\nexport function createComponentInstance(\n id: string,\n fn: ComponentFunction,\n props: Props,\n target: Element | null\n): ComponentInstance {\n const parentInstance = getCurrentInstance();\n const portalScope = parentInstance?.portalScope ?? getCurrentPortalScope();\n const instance: ComponentInstance = {\n id,\n fn,\n props,\n target,\n parentInstance,\n portalScope: portalScope ?? null,\n mounted: false,\n abortController: null,\n stateValues: [],\n evaluationGeneration: 0,\n notifyUpdate: null,\n // Prebound helpers (initialized below) to avoid per-update allocations\n _pendingFlushTask: undefined,\n _pendingRunTask: undefined,\n _enqueueRun: undefined,\n stateIndexCheck: -1,\n expectedStateIndices: [],\n firstRenderComplete: false,\n mountOperations: [],\n commitOperations: [],\n cleanupFns: [],\n lifecycleSlots: [],\n lifecycleGeneration: 0,\n hasPendingUpdate: false,\n ownerFrame: null, // Will be set by renderer when vnode is marked\n ssr: false,\n cleanupStrict: false,\n isRoot: false,\n\n // Render-tracking (for precise state subscriptions)\n _currentRenderToken: undefined,\n lastRenderToken: 0,\n _pendingReadSources: undefined,\n _pendingReadSourceVersions: undefined,\n _lastReadSources: undefined,\n devWarningsEmitted: undefined,\n };\n\n // Initialize prebound helper tasks once per instance to avoid allocations\n instance._pendingRunTask = () => {\n // Clear pending flag when the run task executes\n instance.hasPendingUpdate = false;\n if (instance.notifyUpdate === null) {\n return;\n }\n // Execute component run (will set up notifyUpdate before render)\n runScheduledComponent(instance, {\n execute: executeComponentSync,\n finalizeReadSubscriptions,\n warnUnusedStateReads,\n commitRenderedComponent,\n });\n };\n\n instance._enqueueRun = () => {\n if (!instance.hasPendingUpdate) {\n instance.hasPendingUpdate = true;\n // Enqueue single run task (coalesces multiple writes)\n enqueueRuntimeTask(instance._pendingRunTask!);\n }\n };\n\n // Default state-driven updates enqueue the run task directly. Specialized\n // runtimes (for example `For` item instances) can still override this hook.\n instance._pendingFlushTask = instance._pendingRunTask;\n\n return instance;\n}\n\n/**\n * Register a mount operation that will run after the component is mounted\n * Used by operations (task, on, timer, etc) to execute after render completes\n */\nexport function captureInlineRenderSnapshot(instance: ComponentInstance): void {\n captureLifecycleInlineRenderSnapshot(instance);\n}\n\nexport function registerMountOperation(operation: LifecycleOperation): void {\n registerMountOperationForInstance(getCurrentComponentInstance(), operation);\n}\n\nexport function registerCommitOperation(operation: LifecycleOperation): void {\n registerCommitOperationForInstance(getCurrentComponentInstance(), operation);\n}\n\nexport function commitRenderedComponent(instance: ComponentInstance): void {\n commitRenderedLifecycleComponent(instance);\n}\n\nexport function mountInstanceInline(\n instance: ComponentInstance,\n target: Element | null\n): void {\n instance.target = target;\n // Record backref on host element so renderer can clean up when the\n // node is removed. Avoids leaks if the node is detached or replaced.\n try {\n if (target instanceof Element) {\n const host = target as Element & {\n __ASKR_INSTANCE?: ComponentInstance;\n __ASKR_INSTANCES?: ComponentInstance[];\n };\n const instances = host.__ASKR_INSTANCES ?? [];\n const nextInstances = instances.filter((entry) => entry !== instance);\n nextInstances.push(instance);\n host.__ASKR_INSTANCES = nextInstances;\n host.__ASKR_INSTANCE = nextInstances[0] ?? instance;\n }\n } catch (err) {\n void err;\n }\n\n // Ensure notifyUpdate is available for async resource completions that may\n // try to trigger re-render. This mirrors the setup in executeComponent().\n // Use prebound enqueue helper to avoid allocating a new closure\n instance.notifyUpdate = instance._enqueueRun!;\n\n const wasFirstMount = !instance.mounted;\n instance.mounted = true;\n commitLifecycleForInstance(instance, wasFirstMount);\n}\n\n/**\n * Run a component synchronously: execute function, handle result\n * This is the internal workhorse that manages async continuations and generation tracking.\n * Must always be called through the scheduler.\n *\n * ACTOR INVARIANT: This function is enqueued as a task, never called directly.\n */\n\nexport function renderScopedComponent<T>(\n instance: ComponentInstance,\n startStateIndex: number,\n render: () => T\n): T {\n instance.notifyUpdate = instance._enqueueRun!;\n resetRenderState(instance);\n beginRenderTracking(instance);\n const savedScope = enterRenderScopedComponent(instance, startStateIndex);\n\n let didComplete = false;\n\n try {\n const executionFrame: ContextFrame = {\n parent: instance.ownerFrame,\n values: null,\n };\n const result = withContext(executionFrame, render);\n didComplete = true;\n return result;\n } finally {\n if (!didComplete) {\n clearRenderTracking(instance);\n }\n restoreRenderScopedComponent(savedScope);\n }\n}\n\n/**\n * Execute a component's render function synchronously.\n * Returns either a vnode/promise immediately (does NOT render).\n * Rendering happens separately through the scheduled commit helper.\n */\nexport function renderComponentInline(\n instance: ComponentInstance\n): unknown | Promise<unknown> {\n // Reused inline instances can cross renderer cleanup boundaries while their\n // host node is retained. Make sure state writes still enqueue this instance.\n instance.notifyUpdate = instance._enqueueRun!;\n\n // Ensure inline executions (rendered during parent's evaluate) still\n // receive a render token and have their state reads finalized so\n // subscriptions are correctly recorded. If this function is called\n // as part of a scheduled run, the token will already be set by\n // runComponent and we should not overwrite it.\n const trackingSnapshot = captureInlineRenderTracking(instance);\n const scopeSnapshot = captureInlineComponentScope();\n const hadToken = trackingSnapshot.currentRenderToken !== undefined;\n\n if (!hadToken) {\n beginRenderTracking(instance);\n }\n\n try {\n const result = executeComponentSync(instance);\n // If we set the token for inline execution, finalize subscriptions now\n // unless the parent DOM commit is still provisional. Renderer commit\n // batches flush these reads only after DOM evaluation succeeds.\n if (!hadToken) {\n finalizeInlineReadSubscriptions(\n instance,\n instance._currentRenderToken!,\n instance._pendingReadSources,\n instance._pendingReadSourceVersions\n );\n }\n commitRenderedComponent(instance);\n return result;\n } finally {\n // Restore previous token/read states for nested inline render scenarios\n restoreInlineRenderTracking(instance, trackingSnapshot);\n restoreInlineComponentScope(scopeSnapshot);\n }\n}\n\nexport function warnUnusedStateReads(instance: ComponentInstance): void {\n for (let i = 0; i < instance.stateValues.length; i++) {\n const state = instance.stateValues[i];\n const hasCommittedUsage =\n (state?._readers?.size ?? 0) > 0 ||\n ((state as { _derivedSubscribers?: Set<unknown> } | undefined)\n ?._derivedSubscribers?.size ?? 0) > 0;\n\n if (\n state &&\n !state._hasBeenRead &&\n !state._hasEverBeenRead &&\n !hasCommittedUsage\n ) {\n try {\n const name = instance.fn?.name || '<anonymous>';\n warnInstanceOnce(\n instance,\n `unused-state:${i}`,\n `[askr] Unused state variable detected in ${name} at index ${i}. State should be read during render or removed.`\n );\n } catch {\n warnInstanceOnce(\n instance,\n `unused-state:${i}`,\n `[askr] Unused state variable detected. State should be read during render or removed.`\n );\n }\n }\n }\n}\n\nfunction executeComponentSync(\n instance: ComponentInstance\n): unknown | Promise<unknown> {\n resetRenderState(instance);\n incDevCounter('componentRuns');\n incDevCounter('componentReruns');\n\n const savedPortalScope = enterComponentExecutionScope(instance);\n\n let didComplete = false;\n\n try {\n // Track render time in dev mode\n const renderStartTime = isDevelopmentEnvironment() ? Date.now() : 0;\n\n // Create context object with abort signal\n const context = {\n get signal(): AbortSignal {\n return getSignalForInstance(instance);\n },\n };\n\n // Execute component within its owner frame (provider chain).\n // This ensures all context reads see the correct provider values.\n // We create a new execution frame whose parent is the ownerFrame. The\n // `values` map is lazily allocated to avoid per-render Map allocations\n // for components that do not use context.\n const executionFrame: ContextFrame = {\n parent: instance.ownerFrame,\n values: null,\n };\n const result = withContext(executionFrame, () =>\n instance.fn(instance.props, context)\n );\n\n // Check render time\n const renderTime = Date.now() - renderStartTime;\n if (renderTime > 5) {\n warnInstanceOnce(\n instance,\n 'slow-render',\n `[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`\n );\n }\n\n // Mark first render complete after successful execution\n // This enables hook order validation on subsequent renders\n if (!instance.firstRenderComplete) {\n instance.firstRenderComplete = true;\n }\n\n didComplete = true;\n return result;\n } finally {\n if (!didComplete) {\n discardCommitOperations(instance);\n }\n // Synchronous path: we did not push a fresh frame, so nothing to pop here.\n exitComponentExecutionScope(savedPortalScope);\n }\n}\n\n/**\n * Public entry point: Execute component with full lifecycle (execute + render)\n * Handles both initial mount and re-execution. Always enqueues through scheduler.\n * Single entry point to avoid lifecycle divergence.\n */\nexport function executeComponent(instance: ComponentInstance): void {\n // Lazily recreate abort controller only when signal is actually requested.\n instance.abortController = null;\n\n // Setup notifyUpdate callback using prebound helper to avoid per-call closures\n instance.notifyUpdate = instance._enqueueRun!;\n\n // Enqueue the initial component run\n enqueueRuntimeTask(instance._pendingRunTask!);\n}\n\n/**\n * Finalize read subscriptions for an instance after a successful commit.\n * - Update per-state readers map to point to this instance's last committed token\n * - Remove this instance from states it no longer reads\n * This is deterministic and runs synchronously with commit to ensure\n * subscribers are only notified when they actually read a state in their\n * last committed render.\n */\nexport function finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Mount a component instance.\n * This is just an alias to executeComponent() to maintain API compatibility.\n * All lifecycle logic is unified in executeComponent().\n */\nexport function mountComponent(instance: ComponentInstance): void {\n executeComponent(instance);\n}\n\nfunction warnInstanceOnce(\n instance: ComponentInstance,\n key: string,\n message: string\n): void {\n if (isProductionEnvironment()) return;\n const warnings = (instance.devWarningsEmitted ??= new Set());\n if (warnings.has(key)) return;\n warnings.add(key);\n logger.warn(message);\n}\n"],"mappings":";;;;;;;;;;;AAiHA,SAAgB,wBACd,IACA,IACA,OACA,QACmB;CACnB,MAAM,iBAAiB,mBAAmB;CAE1C,MAAM,WAA8B;EAClC;EACA;EACA;EACA;EACA;EACA,aAPkB,gBAAgB,eAAe,sBAAsB,KAO3C;EAC5B,SAAS;EACT,iBAAiB;EACjB,aAAa,CAAC;EACd,sBAAsB;EACtB,cAAc;EAEd,mBAAmB;EACnB,iBAAiB;EACjB,aAAa;EACb,iBAAiB;EACjB,sBAAsB,CAAC;EACvB,qBAAqB;EACrB,iBAAiB,CAAC;EAClB,kBAAkB,CAAC;EACnB,YAAY,CAAC;EACb,gBAAgB,CAAC;EACjB,qBAAqB;EACrB,kBAAkB;EAClB,YAAY;EACZ,KAAK;EACL,eAAe;EACf,QAAQ;EAGR,qBAAqB;EACrB,iBAAiB;EACjB,qBAAqB;EACrB,4BAA4B;EAC5B,kBAAkB;EAClB,oBAAoB;CACtB;CAGA,SAAS,wBAAwB;EAE/B,SAAS,mBAAmB;EAC5B,IAAI,SAAS,iBAAiB,MAC5B;EAGF,sBAAsB,UAAU;GAC9B,SAAS;GACT;GACA;GACA;EACF,CAAC;CACH;CAEA,SAAS,oBAAoB;EAC3B,IAAI,CAAC,SAAS,kBAAkB;GAC9B,SAAS,mBAAmB;GAE5B,mBAAmB,SAAS,eAAgB;EAC9C;CACF;CAIA,SAAS,oBAAoB,SAAS;CAEtC,OAAO;AACT;;;;;AAMA,SAAgB,4BAA4B,UAAmC;CAC7E,8BAAqC,QAAQ;AAC/C;AAMA,SAAgB,wBAAwB,WAAqC;CAC3E,mCAAmC,4BAA4B,GAAG,SAAS;AAC7E;AAEA,SAAgB,wBAAwB,UAAmC;CACzE,0BAAiC,QAAQ;AAC3C;AAEA,SAAgB,oBACd,UACA,QACM;CACN,SAAS,SAAS;CAGlB,IAAI;EACF,IAAI,kBAAkB,SAAS;GAC7B,MAAM,OAAO;GAKb,MAAM,iBADY,KAAK,oBAAoB,CAAC,EACtB,CAAU,QAAQ,UAAU,UAAU,QAAQ;GACpE,cAAc,KAAK,QAAQ;GAC3B,KAAK,mBAAmB;GACxB,KAAK,kBAAkB,cAAc,MAAM;EAC7C;CACF,SAAS,KAAK,CAEd;CAKA,SAAS,eAAe,SAAS;CAEjC,MAAM,gBAAgB,CAAC,SAAS;CAChC,SAAS,UAAU;CACnB,2BAA2B,UAAU,aAAa;AACpD;;;;;;;;AAUA,SAAgB,sBACd,UACA,iBACA,QACG;CACH,SAAS,eAAe,SAAS;CACjC,iBAAiB,QAAQ;CACzB,oBAAoB,QAAQ;CAC5B,MAAM,aAAa,2BAA2B,UAAU,eAAe;CAEvE,IAAI,cAAc;CAElB,IAAI;EAKF,MAAM,SAAS,YAAY;GAHzB,QAAQ,SAAS;GACjB,QAAQ;EAEiB,GAAgB,MAAM;EACjD,cAAc;EACd,OAAO;CACT,UAAU;EACR,IAAI,CAAC,aACH,oBAAoB,QAAQ;EAE9B,6BAA6B,UAAU;CACzC;AACF;;;;;;AAOA,SAAgB,sBACd,UAC4B;CAG5B,SAAS,eAAe,SAAS;CAOjC,MAAM,mBAAmB,4BAA4B,QAAQ;CAC7D,MAAM,gBAAgB,4BAA4B;CAClD,MAAM,WAAW,iBAAiB,uBAAuB;CAEzD,IAAI,CAAC,UACH,oBAAoB,QAAQ;CAG9B,IAAI;EACF,MAAM,SAAS,qBAAqB,QAAQ;EAI5C,IAAI,CAAC,UACH,gCACE,UACA,SAAS,qBACT,SAAS,qBACT,SAAS,0BACX;EAEF,wBAAwB,QAAQ;EAChC,OAAO;CACT,UAAU;EAER,4BAA4B,UAAU,gBAAgB;EACtD,4BAA4B,aAAa;CAC3C;AACF;AAEA,SAAgB,qBAAqB,UAAmC;CACtE,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;EACpD,MAAM,QAAQ,SAAS,YAAY;EACnC,MAAM,qBACH,OAAO,UAAU,QAAQ,KAAK,MAC7B,OACE,qBAAqB,QAAQ,KAAK;EAExC,IACE,SACA,CAAC,MAAM,gBACP,CAAC,MAAM,oBACP,CAAC,mBAED,IAAI;GACF,MAAM,OAAO,SAAS,IAAI,QAAQ;GAClC,iBACE,UACA,gBAAgB,KAChB,4CAA4C,KAAK,YAAY,EAAE,iDACjE;EACF,QAAQ;GACN,iBACE,UACA,gBAAgB,KAChB,uFACF;EACF;CAEJ;AACF;AAEA,SAAS,qBACP,UAC4B;CAC5B,iBAAiB,QAAQ;CACzB,cAAc,eAAe;CAC7B,cAAc,iBAAiB;CAE/B,MAAM,mBAAmB,6BAA6B,QAAQ;CAE9D,IAAI,cAAc;CAElB,IAAI;EAEF,MAAM,kBAAkB,yBAAyB,IAAI,KAAK,IAAI,IAAI;EAGlE,MAAM,UAAU,EACd,IAAI,SAAsB;GACxB,OAAO,qBAAqB,QAAQ;EACtC,EACF;EAWA,MAAM,SAAS,YAAY;GAHzB,QAAQ,SAAS;GACjB,QAAQ;EAEiB,SACzB,SAAS,GAAG,SAAS,OAAO,OAAO,CACrC;EAGA,MAAM,aAAa,KAAK,IAAI,IAAI;EAChC,IAAI,aAAa,GACf,iBACE,UACA,eACA,gCAAgC,WAAW,+CAC7C;EAKF,IAAI,CAAC,SAAS,qBACZ,SAAS,sBAAsB;EAGjC,cAAc;EACd,OAAO;CACT,UAAU;EACR,IAAI,CAAC,aACH,wBAAwB,QAAQ;EAGlC,4BAA4B,gBAAgB;CAC9C;AACF;;;;;;AAOA,SAAgB,iBAAiB,UAAmC;CAElE,SAAS,kBAAkB;CAG3B,SAAS,eAAe,SAAS;CAGjC,mBAAmB,SAAS,eAAgB;AAC9C;;;;;;;;;AAUA,SAAgB,0BAA0B,UAAmC;CAC3E,8BAA8B,QAAQ;AACxC;;;;;;AAOA,SAAgB,eAAe,UAAmC;CAChE,iBAAiB,QAAQ;AAC3B;AAEA,SAAS,iBACP,UACA,KACA,SACM;CACN,IAAI,wBAAwB,GAAG;CAC/B,MAAM,WAAY,SAAS,uCAAuB,IAAI,IAAI;CAC1D,IAAI,SAAS,IAAI,GAAG,GAAG;CACvB,SAAS,IAAI,GAAG;CAChB,OAAO,KAAK,OAAO;AACrB"}
|
|
1
|
+
{"version":3,"file":"component-internal.js","names":[],"sources":["../../src/runtime/component-internal.ts"],"sourcesContent":["/**\n * Component instance lifecycle management\n * Internal only — users never see this\n */\n\nimport { type State } from './state';\nimport { enqueueRuntimeTask } from './access';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport {\n // withContext is the sole primitive for context restoration\n withContext,\n type ContextFrame,\n} from './context';\nimport { type ReadableSource, finalizeReadableSubscriptions } from './readable';\nimport {\n isDevelopmentEnvironment,\n isProductionEnvironment,\n} from '../common/env';\nimport { logger } from '../common/logger';\nimport { incDevCounter } from './dev-namespace';\nimport {\n cleanupComponent,\n registerOwnedChildScope,\n unregisterOwnedChildScope,\n type OwnedChildScope,\n} from './component-cleanup';\nimport { runScheduledComponent } from './component-commit';\nimport {\n captureInlineRenderSnapshot as captureLifecycleInlineRenderSnapshot,\n commitLifecycleForInstance,\n commitRenderedComponent as commitRenderedLifecycleComponent,\n discardCommitOperations,\n finalizeInlineReadSubscriptions,\n registerCommitOperationForInstance,\n registerMountOperationForInstance,\n type LifecycleOperation,\n} from './component-lifecycle';\nimport {\n beginRenderTracking,\n captureInlineComponentScope,\n captureInlineRenderTracking,\n clearRenderTracking,\n enterComponentExecutionScope,\n enterRenderScopedComponent,\n exitComponentExecutionScope,\n getCurrentComponentInstance,\n getCurrentInstance,\n getCurrentPortalScope,\n getSignalForInstance,\n resetRenderState,\n restoreInlineComponentScope,\n restoreInlineRenderTracking,\n restoreRenderScopedComponent,\n} from './component-scope';\n\nexport type { ComponentFunction } from '../common/component';\nexport { cleanupComponent, registerOwnedChildScope, unregisterOwnedChildScope };\n\nexport interface ComponentInstance {\n id: string;\n fn: ComponentFunction;\n props: Props;\n target: Element | null;\n parentInstance: ComponentInstance | null;\n portalScope: object | null;\n mounted: boolean;\n abortController: AbortController | null; // Lazily created per-component abort lifecycle\n ssr?: boolean; // Set to true for SSR temporary instances\n // Opt-in strict cleanup mode: when true cleanup errors are aggregated and re-thrown\n cleanupStrict?: boolean;\n stateValues: State<unknown>[]; // Persistent state storage across renders\n evaluationGeneration: number; // Prevents stale async evaluation completions\n notifyUpdate: (() => void) | null; // Callback for state updates (persisted on instance)\n // Internal: prebound helpers to avoid per-update closures (allocation hot-path)\n _pendingFlushTask?: () => void; // Clears hasPendingUpdate and triggers notifyUpdate\n _pendingRunTask?: () => void; // Clears hasPendingUpdate and runs component\n _enqueueRun?: () => void; // Batches run requests and enqueues _pendingRunTask\n stateIndexCheck: number; // Track state indices to catch conditional calls\n expectedStateIndices: number[]; // Expected sequence of render-scoped hook indices (frozen after first render)\n firstRenderComplete: boolean; // Flag to detect transition from first to subsequent renders\n mountOperations: Array<\n () => void | (() => void) | PromiseLike<void | (() => void)>\n >; // Operations to run when component mounts\n commitOperations: Array<\n () => void | (() => void) | PromiseLike<void | (() => void)>\n >; // Operations to run after a successful committed render\n cleanupFns: Array<() => void>; // Cleanup functions to run on unmount\n lifecycleSlots: unknown[]; // Render-scoped lifecycle primitive storage\n lifecycleGeneration: number; // Invalidates async mount-operation settlement after disposal\n hasPendingUpdate: boolean; // Flag to batch state updates (coalescing)\n ownerFrame: ContextFrame | null; // Provider chain for this component (set by Scope, never overwritten)\n isRoot?: boolean;\n\n // Render-tracking for precise subscriptions (internal)\n _currentRenderToken?: number; // Token for the in-progress render (set before render)\n lastRenderToken?: number; // Token of the last *committed* render\n _pendingReadSources?: Set<ReadableSource<unknown>>; // Readables read during the in-progress render\n _pendingReadSourceVersions?: Map<ReadableSource<unknown>, number>; // Source versions captured during the in-progress render\n _lastReadSources?: Set<ReadableSource<unknown>>; // Readables read during the last committed render\n devWarningsEmitted?: Set<string>; // Dev-only warning dedupe for this instance\n\n // Placeholder for null-returning components. When a component initially returns\n // null, we create a comment placeholder so updates can replace it with content.\n _placeholder?: Comment;\n _ownedChildScopes?: Set<OwnedChildScope>;\n errorBoundaryState?: {\n error: unknown | null;\n resetKey: unknown;\n notified: boolean;\n };\n}\n\nexport function createComponentInstance(\n id: string,\n fn: ComponentFunction,\n props: Props,\n target: Element | null\n): ComponentInstance {\n const parentInstance = getCurrentInstance();\n const portalScope = parentInstance?.portalScope ?? getCurrentPortalScope();\n const instance: ComponentInstance = {\n id,\n fn,\n props,\n target,\n parentInstance,\n portalScope: portalScope ?? null,\n mounted: false,\n abortController: null,\n stateValues: [],\n evaluationGeneration: 0,\n notifyUpdate: null,\n // Prebound helpers (initialized below) to avoid per-update allocations\n _pendingFlushTask: undefined,\n _pendingRunTask: undefined,\n _enqueueRun: undefined,\n stateIndexCheck: -1,\n expectedStateIndices: [],\n firstRenderComplete: false,\n mountOperations: [],\n commitOperations: [],\n cleanupFns: [],\n lifecycleSlots: [],\n lifecycleGeneration: 0,\n hasPendingUpdate: false,\n ownerFrame: null, // Will be set by renderer when vnode is marked\n ssr: false,\n cleanupStrict: false,\n isRoot: false,\n\n // Render-tracking (for precise state subscriptions)\n _currentRenderToken: undefined,\n lastRenderToken: 0,\n _pendingReadSources: undefined,\n _pendingReadSourceVersions: undefined,\n _lastReadSources: undefined,\n devWarningsEmitted: undefined,\n };\n\n // Initialize prebound helper tasks once per instance to avoid allocations\n instance._pendingRunTask = () => {\n // Clear pending flag when the run task executes\n instance.hasPendingUpdate = false;\n if (instance.notifyUpdate === null) {\n return;\n }\n // Execute component run (will set up notifyUpdate before render)\n runScheduledComponent(instance, {\n execute: executeComponentSync,\n finalizeReadSubscriptions,\n warnUnusedStateReads,\n commitRenderedComponent,\n });\n };\n\n instance._enqueueRun = () => {\n if (!instance.hasPendingUpdate) {\n instance.hasPendingUpdate = true;\n // Enqueue single run task (coalesces multiple writes)\n enqueueRuntimeTask(instance._pendingRunTask!);\n }\n };\n\n // Default state-driven updates enqueue the run task directly. Specialized\n // runtimes (for example `For` item instances) can still override this hook.\n instance._pendingFlushTask = instance._pendingRunTask;\n\n return instance;\n}\n\n/**\n * Register a mount operation that will run after the component is mounted\n * Used by operations (task, on, timer, etc) to execute after render completes\n */\nexport function captureInlineRenderSnapshot(instance: ComponentInstance): void {\n captureLifecycleInlineRenderSnapshot(instance);\n}\n\nexport function registerMountOperation(operation: LifecycleOperation): void {\n registerMountOperationForInstance(getCurrentComponentInstance(), operation);\n}\n\nexport function registerCommitOperation(operation: LifecycleOperation): void {\n registerCommitOperationForInstance(getCurrentComponentInstance(), operation);\n}\n\nexport function commitRenderedComponent(instance: ComponentInstance): void {\n commitRenderedLifecycleComponent(instance);\n}\n\nexport function mountInstanceInline(\n instance: ComponentInstance,\n target: Element | null\n): void {\n instance.target = target;\n // Record backref on host element so renderer can clean up when the\n // node is removed. Avoids leaks if the node is detached or replaced.\n try {\n if (target instanceof Element) {\n const host = target as Element & {\n __ASKR_INSTANCE?: ComponentInstance;\n __ASKR_INSTANCES?: ComponentInstance[];\n };\n const instances = host.__ASKR_INSTANCES ?? [];\n const nextInstances = instances.filter((entry) => entry !== instance);\n nextInstances.push(instance);\n host.__ASKR_INSTANCES = nextInstances;\n host.__ASKR_INSTANCE = nextInstances[0] ?? instance;\n }\n } catch (err) {\n void err;\n }\n\n // Ensure notifyUpdate is available for async resource completions that may\n // try to trigger re-render. This mirrors the setup in executeComponent().\n // Use prebound enqueue helper to avoid allocating a new closure\n instance.notifyUpdate = instance._enqueueRun!;\n\n const wasFirstMount = !instance.mounted;\n instance.mounted = true;\n commitLifecycleForInstance(instance, wasFirstMount);\n}\n\n/**\n * Run a component synchronously: execute function, handle result\n * This is the internal workhorse that manages async continuations and generation tracking.\n * Must always be called through the scheduler.\n *\n * ACTOR INVARIANT: This function is enqueued as a task, never called directly.\n */\n\nexport function renderScopedComponent<T>(\n instance: ComponentInstance,\n startStateIndex: number,\n render: () => T\n): T {\n instance.notifyUpdate = instance._enqueueRun!;\n resetRenderState(instance);\n beginRenderTracking(instance);\n const savedScope = enterRenderScopedComponent(instance, startStateIndex);\n\n let didComplete = false;\n\n try {\n const executionFrame: ContextFrame = {\n parent: instance.ownerFrame,\n values: null,\n };\n const result = withContext(executionFrame, render);\n didComplete = true;\n return result;\n } finally {\n if (!didComplete) {\n clearRenderTracking(instance);\n }\n restoreRenderScopedComponent(savedScope);\n }\n}\n\n/**\n * Execute a component's render function synchronously.\n * Returns either a vnode/promise immediately (does NOT render).\n * Rendering happens separately through the scheduled commit helper.\n */\nexport function renderComponentInline(\n instance: ComponentInstance\n): unknown | Promise<unknown> {\n // Reused inline instances can cross renderer cleanup boundaries while their\n // host node is retained. Make sure state writes still enqueue this instance.\n instance.notifyUpdate = instance._enqueueRun!;\n\n // Ensure inline executions (rendered during parent's evaluate) still\n // receive a render token and have their state reads finalized so\n // subscriptions are correctly recorded. If this function is called\n // as part of a scheduled run, the token will already be set by\n // runComponent and we should not overwrite it.\n const trackingSnapshot = captureInlineRenderTracking(instance);\n const scopeSnapshot = captureInlineComponentScope();\n const hadToken = trackingSnapshot.currentRenderToken !== undefined;\n\n if (!hadToken) {\n beginRenderTracking(instance);\n }\n\n try {\n const result = executeComponentSync(instance);\n // If we set the token for inline execution, finalize subscriptions now\n // unless the parent DOM commit is still provisional. Renderer commit\n // batches flush these reads only after DOM evaluation succeeds.\n if (!hadToken) {\n finalizeInlineReadSubscriptions(\n instance,\n instance._currentRenderToken!,\n instance._pendingReadSources,\n instance._pendingReadSourceVersions\n );\n }\n commitRenderedComponent(instance);\n return result;\n } finally {\n // Restore previous token/read states for nested inline render scenarios\n restoreInlineRenderTracking(instance, trackingSnapshot);\n restoreInlineComponentScope(scopeSnapshot);\n }\n}\n\nexport function warnUnusedStateReads(instance: ComponentInstance): void {\n for (let i = 0; i < instance.stateValues.length; i++) {\n const state = instance.stateValues[i];\n const hasCommittedUsage =\n (state?._readers?.size ?? 0) > 0 ||\n ((state as { _derivedSubscribers?: Set<unknown> } | undefined)\n ?._derivedSubscribers?.size ?? 0) > 0;\n\n if (\n state &&\n !state._hasBeenRead &&\n !state._hasEverBeenRead &&\n !hasCommittedUsage\n ) {\n try {\n const name = instance.fn?.name || '<anonymous>';\n warnInstanceOnce(\n instance,\n `unused-state:${i}`,\n `[askr] Unused state variable detected in ${name} at index ${i}. State should be read during render or removed.`\n );\n } catch {\n warnInstanceOnce(\n instance,\n `unused-state:${i}`,\n `[askr] Unused state variable detected. State should be read during render or removed.`\n );\n }\n }\n }\n}\n\nfunction executeComponentSync(\n instance: ComponentInstance\n): unknown | Promise<unknown> {\n resetRenderState(instance);\n incDevCounter('componentRuns');\n incDevCounter('componentReruns');\n\n const savedPortalScope = enterComponentExecutionScope(instance);\n\n let didComplete = false;\n\n try {\n // Track render time in dev mode\n const renderStartTime = isDevelopmentEnvironment() ? Date.now() : 0;\n\n // Create context object with abort signal\n const context = {\n get signal(): AbortSignal {\n return getSignalForInstance(instance);\n },\n };\n\n // Execute component within its owner frame (provider chain).\n // This ensures all context reads see the correct provider values.\n // We create a new execution frame whose parent is the ownerFrame. The\n // `values` map is lazily allocated to avoid per-render Map allocations\n // for components that do not use context.\n const executionFrame: ContextFrame = {\n parent: instance.ownerFrame,\n values: null,\n };\n const result = withContext(executionFrame, () =>\n instance.fn(instance.props, context)\n );\n\n // Check render time\n const renderTime = Date.now() - renderStartTime;\n if (renderTime > 5) {\n warnInstanceOnce(\n instance,\n 'slow-render',\n `[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`\n );\n }\n\n // Mark first render complete after successful execution\n // This enables hook order validation on subsequent renders\n if (!instance.firstRenderComplete) {\n instance.firstRenderComplete = true;\n }\n\n didComplete = true;\n return result;\n } finally {\n if (!didComplete) {\n discardCommitOperations(instance);\n }\n // Synchronous path: we did not push a fresh frame, so nothing to pop here.\n exitComponentExecutionScope(savedPortalScope);\n }\n}\n\n/**\n * Public entry point: Execute component with full lifecycle (execute + render)\n * Handles both initial mount and re-execution. Always enqueues through scheduler.\n * Single entry point to avoid lifecycle divergence.\n */\nexport function executeComponent(instance: ComponentInstance): void {\n // Lazily recreate abort controller only when signal is actually requested.\n instance.abortController = null;\n\n // Setup notifyUpdate callback using prebound helper to avoid per-call closures\n instance.notifyUpdate = instance._enqueueRun!;\n\n // Enqueue the initial component run\n enqueueRuntimeTask(instance._pendingRunTask!);\n}\n\n/**\n * Finalize read subscriptions for an instance after a successful commit.\n * - Update per-state readers map to point to this instance's last committed token\n * - Remove this instance from states it no longer reads\n * This is deterministic and runs synchronously with commit to ensure\n * subscribers are only notified when they actually read a state in their\n * last committed render.\n */\nexport function finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Mount a component instance.\n * This is just an alias to executeComponent() to maintain API compatibility.\n * All lifecycle logic is unified in executeComponent().\n */\nexport function mountComponent(instance: ComponentInstance): void {\n executeComponent(instance);\n}\n\nfunction warnInstanceOnce(\n instance: ComponentInstance,\n key: string,\n message: string\n): void {\n if (isProductionEnvironment()) return;\n const warnings = (instance.devWarningsEmitted ??= new Set());\n if (warnings.has(key)) return;\n warnings.add(key);\n logger.warn(message);\n}\n"],"mappings":";;;;;;;;;;;AAiHA,SAAgB,wBACd,IACA,IACA,OACA,QACmB;CACnB,MAAM,iBAAiB,mBAAmB;CAE1C,MAAM,WAA8B;EAClC;EACA;EACA;EACA;EACA;EACA,aAPkB,gBAAgB,eAAe,sBAAsB,KAO3C;EAC5B,SAAS;EACT,iBAAiB;EACjB,aAAa,CAAC;EACd,sBAAsB;EACtB,cAAc;EAEd,mBAAmB;EACnB,iBAAiB;EACjB,aAAa;EACb,iBAAiB;EACjB,sBAAsB,CAAC;EACvB,qBAAqB;EACrB,iBAAiB,CAAC;EAClB,kBAAkB,CAAC;EACnB,YAAY,CAAC;EACb,gBAAgB,CAAC;EACjB,qBAAqB;EACrB,kBAAkB;EAClB,YAAY;EACZ,KAAK;EACL,eAAe;EACf,QAAQ;EAGR,qBAAqB;EACrB,iBAAiB;EACjB,qBAAqB;EACrB,4BAA4B;EAC5B,kBAAkB;EAClB,oBAAoB;CACtB;CAGA,SAAS,wBAAwB;EAE/B,SAAS,mBAAmB;EAC5B,IAAI,SAAS,iBAAiB,MAC5B;EAGF,sBAAsB,UAAU;GAC9B,SAAS;GACT;GACA;GACA;EACF,CAAC;CACH;CAEA,SAAS,oBAAoB;EAC3B,IAAI,CAAC,SAAS,kBAAkB;GAC9B,SAAS,mBAAmB;GAE5B,mBAAmB,SAAS,eAAgB;EAC9C;CACF;CAIA,SAAS,oBAAoB,SAAS;CAEtC,OAAO;AACT;;;;;AAMA,SAAgB,4BAA4B,UAAmC;CAC7E,8BAAqC,QAAQ;AAC/C;AAMA,SAAgB,wBAAwB,WAAqC;CAC3E,mCAAmC,4BAA4B,GAAG,SAAS;AAC7E;AAEA,SAAgB,wBAAwB,UAAmC;CACzE,0BAAiC,QAAQ;AAC3C;AAEA,SAAgB,oBACd,UACA,QACM;CACN,SAAS,SAAS;CAGlB,IAAI;EACF,IAAI,kBAAkB,SAAS;GAC7B,MAAM,OAAO;GAKb,MAAM,iBADY,KAAK,oBAAoB,CAAC,EACtB,CAAU,QAAQ,UAAU,UAAU,QAAQ;GACpE,cAAc,KAAK,QAAQ;GAC3B,KAAK,mBAAmB;GACxB,KAAK,kBAAkB,cAAc,MAAM;EAC7C;CACF,SAAS,KAAK,CAEd;CAKA,SAAS,eAAe,SAAS;CAEjC,MAAM,gBAAgB,CAAC,SAAS;CAChC,SAAS,UAAU;CACnB,2BAA2B,UAAU,aAAa;AACpD;;;;;;;;AAUA,SAAgB,sBACd,UACA,iBACA,QACG;CACH,SAAS,eAAe,SAAS;CACjC,iBAAiB,QAAQ;CACzB,oBAAoB,QAAQ;CAC5B,MAAM,aAAa,2BAA2B,UAAU,eAAe;CAEvE,IAAI,cAAc;CAElB,IAAI;EAKF,MAAM,SAAS,YAAY;GAHzB,QAAQ,SAAS;GACjB,QAAQ;EAEiB,GAAgB,MAAM;EACjD,cAAc;EACd,OAAO;CACT,UAAU;EACR,IAAI,CAAC,aACH,oBAAoB,QAAQ;EAE9B,6BAA6B,UAAU;CACzC;AACF;;;;;;AAOA,SAAgB,sBACd,UAC4B;CAG5B,SAAS,eAAe,SAAS;CAOjC,MAAM,mBAAmB,4BAA4B,QAAQ;CAC7D,MAAM,gBAAgB,4BAA4B;CAClD,MAAM,WAAW,iBAAiB,uBAAuB;CAEzD,IAAI,CAAC,UACH,oBAAoB,QAAQ;CAG9B,IAAI;EACF,MAAM,SAAS,qBAAqB,QAAQ;EAI5C,IAAI,CAAC,UACH,gCACE,UACA,SAAS,qBACT,SAAS,qBACT,SAAS,0BACX;EAEF,wBAAwB,QAAQ;EAChC,OAAO;CACT,UAAU;EAER,4BAA4B,UAAU,gBAAgB;EACtD,4BAA4B,aAAa;CAC3C;AACF;AAEA,SAAgB,qBAAqB,UAAmC;CACtE,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;EACpD,MAAM,QAAQ,SAAS,YAAY;EACnC,MAAM,qBACH,OAAO,UAAU,QAAQ,KAAK,MAC7B,OACE,qBAAqB,QAAQ,KAAK;EAExC,IACE,SACA,CAAC,MAAM,gBACP,CAAC,MAAM,oBACP,CAAC,mBAED,IAAI;GACF,MAAM,OAAO,SAAS,IAAI,QAAQ;GAClC,iBACE,UACA,gBAAgB,KAChB,4CAA4C,KAAK,YAAY,EAAE,iDACjE;EACF,QAAQ;GACN,iBACE,UACA,gBAAgB,KAChB,uFACF;EACF;CAEJ;AACF;AAEA,SAAS,qBACP,UAC4B;CAC5B,iBAAiB,QAAQ;CACzB,cAAc,eAAe;CAC7B,cAAc,iBAAiB;CAE/B,MAAM,mBAAmB,6BAA6B,QAAQ;CAE9D,IAAI,cAAc;CAElB,IAAI;EAEF,MAAM,kBAAkB,yBAAyB,IAAI,KAAK,IAAI,IAAI;EAGlE,MAAM,UAAU,EACd,IAAI,SAAsB;GACxB,OAAO,qBAAqB,QAAQ;EACtC,EACF;EAWA,MAAM,SAAS,YAAY;GAHzB,QAAQ,SAAS;GACjB,QAAQ;EAEiB,SACzB,SAAS,GAAG,SAAS,OAAO,OAAO,CACrC;EAGA,MAAM,aAAa,KAAK,IAAI,IAAI;EAChC,IAAI,aAAa,GACf,iBACE,UACA,eACA,gCAAgC,WAAW,+CAC7C;EAKF,IAAI,CAAC,SAAS,qBACZ,SAAS,sBAAsB;EAGjC,cAAc;EACd,OAAO;CACT,UAAU;EACR,IAAI,CAAC,aACH,wBAAwB,QAAQ;EAGlC,4BAA4B,gBAAgB;CAC9C;AACF;;;;;;AAOA,SAAgB,iBAAiB,UAAmC;CAElE,SAAS,kBAAkB;CAG3B,SAAS,eAAe,SAAS;CAGjC,mBAAmB,SAAS,eAAgB;AAC9C;;;;;;;;;AAUA,SAAgB,0BAA0B,UAAmC;CAC3E,8BAA8B,QAAQ;AACxC;;;;;;AAOA,SAAgB,eAAe,UAAmC;CAChE,iBAAiB,QAAQ;AAC3B;AAEA,SAAS,iBACP,UACA,KACA,SACM;CACN,IAAI,wBAAwB,GAAG;CAC/B,MAAM,WAAY,SAAS,uCAAuB,IAAI,IAAI;CAC1D,IAAI,SAAS,IAAI,GAAG,GAAG;CACvB,SAAS,IAAI,GAAG;CAChB,OAAO,KAAK,OAAO;AACrB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Props } from "../common/props.js";
|
|
2
|
-
import { ReadableSource } from "./readable.js";
|
|
3
2
|
import { ContextFrame } from "./context.js";
|
|
4
3
|
import { ComponentInstance } from "./component-internal.js";
|
|
4
|
+
import { ReadableSource } from "./readable.js";
|
|
5
5
|
|
|
6
6
|
//#region src/runtime/component-lifecycle.d.ts
|
|
7
7
|
type LifecycleOperation = () => void | (() => void) | PromiseLike<void | (() => void)>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isDevelopmentEnvironment } from "../common/env.js";
|
|
2
|
-
import { logger } from "../
|
|
2
|
+
import { logger } from "../common/logger.js";
|
|
3
3
|
import { finalizeReadableSubscriptionsFromSnapshot } from "./readable.js";
|
|
4
4
|
import { isPromiseLike } from "../common/promise.js";
|
|
5
5
|
import { isBulkCommitActive } from "./fastlane.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-lifecycle.js","names":[],"sources":["../../src/runtime/component-lifecycle.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { isPromiseLike } from '../common/promise';\nimport type { Props } from '../common/props';\nimport { logger } from '../dev/logger';\nimport type { ContextFrame } from './context';\nimport type { ComponentInstance } from './component-internal';\nimport { isBulkCommitActive } from './fastlane';\nimport {\n type ReadableSource,\n finalizeReadableSubscriptionsFromSnapshot,\n} from './readable';\n\nexport type LifecycleOperation = () =>\n | void\n | (() => void)\n | PromiseLike<void | (() => void)>;\n\ntype LifecycleCommitBatchEntry = {\n instance: ComponentInstance;\n wasFirstMount: boolean;\n};\n\ntype ReadSubscriptionCommit = {\n instance: ComponentInstance;\n token: number;\n pendingReadSources: Set<ReadableSource<unknown>> | undefined;\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined;\n};\n\ntype InlineRenderSnapshot = {\n instance: ComponentInstance;\n props: Props;\n ownerFrame: ContextFrame | null;\n portalScope: object | null;\n parentInstance: ComponentInstance | null;\n isRoot: boolean | undefined;\n};\n\nexport type LifecycleCommitBatch = {\n parent: LifecycleCommitBatch | null;\n entries: LifecycleCommitBatchEntry[];\n entriesByInstance: Map<ComponentInstance, LifecycleCommitBatchEntry>;\n readCommits: ReadSubscriptionCommit[];\n readCommitsByInstance: Map<ComponentInstance, ReadSubscriptionCommit>;\n renderSnapshots: InlineRenderSnapshot[];\n renderSnapshotsByInstance: Map<ComponentInstance, InlineRenderSnapshot>;\n active: boolean;\n};\n\nlet currentLifecycleCommitBatch: LifecycleCommitBatch | null = null;\n\nexport function beginLifecycleCommitBatch(): LifecycleCommitBatch {\n const batch: LifecycleCommitBatch = {\n parent: currentLifecycleCommitBatch,\n entries: [],\n entriesByInstance: new Map(),\n readCommits: [],\n readCommitsByInstance: new Map(),\n renderSnapshots: [],\n renderSnapshotsByInstance: new Map(),\n active: true,\n };\n currentLifecycleCommitBatch = batch;\n return batch;\n}\n\nfunction closeLifecycleCommitBatch(batch: LifecycleCommitBatch): boolean {\n if (!batch.active) {\n return false;\n }\n\n batch.active = false;\n currentLifecycleCommitBatch = batch.parent;\n return true;\n}\n\nfunction enqueueLifecycleCommit(\n batch: LifecycleCommitBatch,\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n const existing = batch.entriesByInstance.get(instance);\n if (existing) {\n existing.wasFirstMount = existing.wasFirstMount || wasFirstMount;\n return;\n }\n\n const entry = { instance, wasFirstMount };\n batch.entriesByInstance.set(instance, entry);\n batch.entries.push(entry);\n}\n\nfunction enqueueReadSubscriptionCommit(\n batch: LifecycleCommitBatch,\n instance: ComponentInstance,\n token: number,\n pendingReadSources: Set<ReadableSource<unknown>> | undefined,\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined\n): void {\n const existing = batch.readCommitsByInstance.get(instance);\n const commit = existing ?? {\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions,\n };\n\n commit.token = token;\n commit.pendingReadSources = pendingReadSources\n ? new Set(pendingReadSources)\n : undefined;\n commit.pendingReadSourceVersions = pendingReadSourceVersions\n ? new Map(pendingReadSourceVersions)\n : undefined;\n\n if (!existing) {\n batch.readCommitsByInstance.set(instance, commit);\n batch.readCommits.push(commit);\n }\n}\n\nfunction enqueueInlineRenderSnapshot(\n batch: LifecycleCommitBatch,\n snapshot: InlineRenderSnapshot\n): void {\n if (batch.renderSnapshotsByInstance.has(snapshot.instance)) {\n return;\n }\n\n batch.renderSnapshotsByInstance.set(snapshot.instance, snapshot);\n batch.renderSnapshots.push(snapshot);\n}\n\nexport function captureInlineRenderSnapshot(instance: ComponentInstance): void {\n if (!currentLifecycleCommitBatch?.active) {\n return;\n }\n\n enqueueInlineRenderSnapshot(currentLifecycleCommitBatch, {\n instance,\n props: instance.props,\n ownerFrame: instance.ownerFrame,\n portalScope: instance.portalScope,\n parentInstance: instance.parentInstance,\n isRoot: instance.isRoot,\n });\n}\n\nexport function finalizeInlineReadSubscriptions(\n instance: ComponentInstance,\n token: number,\n pendingReadSources: Set<ReadableSource<unknown>> | undefined,\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined\n): void {\n if (currentLifecycleCommitBatch?.active) {\n enqueueReadSubscriptionCommit(\n currentLifecycleCommitBatch,\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions\n );\n return;\n }\n\n finalizeReadableSubscriptionsFromSnapshot(\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions\n );\n}\n\nexport function flushLifecycleCommitBatch(batch: LifecycleCommitBatch): void {\n if (!closeLifecycleCommitBatch(batch)) {\n return;\n }\n\n if (batch.parent?.active) {\n for (const snapshot of batch.renderSnapshots) {\n enqueueInlineRenderSnapshot(batch.parent, snapshot);\n }\n for (const commit of batch.readCommits) {\n enqueueReadSubscriptionCommit(\n batch.parent,\n commit.instance,\n commit.token,\n commit.pendingReadSources,\n commit.pendingReadSourceVersions\n );\n }\n for (const entry of batch.entries) {\n enqueueLifecycleCommit(batch.parent, entry.instance, entry.wasFirstMount);\n }\n return;\n }\n\n for (const commit of batch.readCommits) {\n finalizeReadableSubscriptionsFromSnapshot(\n commit.instance,\n commit.token,\n commit.pendingReadSources,\n commit.pendingReadSourceVersions\n );\n }\n\n for (const entry of batch.entries) {\n executeCommittedLifecycleOperations(entry.instance, entry.wasFirstMount);\n }\n}\n\nexport function discardLifecycleCommitBatch(batch: LifecycleCommitBatch): void {\n if (!closeLifecycleCommitBatch(batch)) {\n return;\n }\n\n for (let index = batch.renderSnapshots.length - 1; index >= 0; index -= 1) {\n const snapshot = batch.renderSnapshots[index]!;\n snapshot.instance.props = snapshot.props;\n snapshot.instance.ownerFrame = snapshot.ownerFrame;\n snapshot.instance.portalScope = snapshot.portalScope;\n snapshot.instance.parentInstance = snapshot.parentInstance;\n snapshot.instance.isRoot = snapshot.isRoot;\n }\n\n for (const entry of batch.entries) {\n if (entry.wasFirstMount) {\n entry.instance.mountOperations = [];\n }\n discardCommitOperations(entry.instance);\n }\n}\n\nexport function registerMountOperationForInstance(\n instance: ComponentInstance | null,\n operation: LifecycleOperation\n): void {\n if (instance) {\n // If we're in bulk-commit fast lane, registering mount operations is a\n // violation of the fast-lane preconditions. Throw in dev, otherwise ignore\n // silently in production (we must avoid scheduling work during bulk commit).\n if (isBulkCommitActive()) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n 'registerMountOperation called during bulk commit fast-lane'\n );\n }\n return;\n }\n instance.mountOperations.push(operation);\n }\n}\n\nexport function registerCommitOperationForInstance(\n instance: ComponentInstance | null,\n operation: LifecycleOperation\n): void {\n if (instance) {\n if (isBulkCommitActive()) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n 'registerCommitOperation called during bulk commit fast-lane'\n );\n }\n return;\n }\n instance.commitOperations.push(operation);\n }\n}\n\nfunction settleLifecycleOperationResult(\n instance: ComponentInstance,\n lifecycleGeneration: number,\n result: void | (() => void) | PromiseLike<void | (() => void)>\n): void {\n if (isPromiseLike(result)) {\n Promise.resolve(result).then(\n (cleanup) => {\n if (typeof cleanup === 'function') {\n if (\n instance.lifecycleGeneration === lifecycleGeneration &&\n instance.mounted\n ) {\n instance.cleanupFns.push(cleanup);\n return;\n }\n\n try {\n cleanup();\n } catch (err) {\n logger.error('[Askr] async mount cleanup failed:', err);\n }\n }\n },\n (err) => {\n logger.error('[Askr] async mount operation failed:', err);\n }\n );\n } else if (typeof result === 'function') {\n instance.cleanupFns.push(result);\n }\n}\n\nfunction executeMountOperations(instance: ComponentInstance): void {\n const mountOperations = instance.mountOperations;\n if (mountOperations.length === 0) {\n return;\n }\n\n const lifecycleGeneration = instance.lifecycleGeneration;\n\n for (const operation of mountOperations) {\n settleLifecycleOperationResult(instance, lifecycleGeneration, operation());\n }\n // Clear the operations array so they don't run again on subsequent renders\n instance.mountOperations = [];\n}\n\nfunction executeCommitOperations(instance: ComponentInstance): void {\n const commitOperations = instance.commitOperations;\n if (commitOperations.length === 0) {\n return;\n }\n\n instance.commitOperations = [];\n const lifecycleGeneration = instance.lifecycleGeneration;\n\n for (const operation of commitOperations) {\n settleLifecycleOperationResult(instance, lifecycleGeneration, operation());\n }\n}\n\nexport function discardCommitOperations(instance: ComponentInstance): void {\n instance.commitOperations = [];\n}\n\nexport function executeCommittedLifecycleOperations(\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n if (wasFirstMount && instance.mountOperations.length > 0) {\n executeMountOperations(instance);\n }\n if (instance.commitOperations.length > 0) {\n executeCommitOperations(instance);\n }\n}\n\nexport function commitLifecycleForInstance(\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n if (currentLifecycleCommitBatch) {\n enqueueLifecycleCommit(\n currentLifecycleCommitBatch,\n instance,\n wasFirstMount\n );\n return;\n }\n\n executeCommittedLifecycleOperations(instance, wasFirstMount);\n}\n\nexport function commitRenderedComponent(instance: ComponentInstance): void {\n if (instance.mounted && instance.commitOperations.length > 0) {\n commitLifecycleForInstance(instance, false);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"component-lifecycle.js","names":[],"sources":["../../src/runtime/component-lifecycle.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { isPromiseLike } from '../common/promise';\nimport type { Props } from '../common/props';\nimport { logger } from '../common/logger';\nimport type { ContextFrame } from './context';\nimport type { ComponentInstance } from './component-internal';\nimport { isBulkCommitActive } from './fastlane';\nimport {\n type ReadableSource,\n finalizeReadableSubscriptionsFromSnapshot,\n} from './readable';\n\nexport type LifecycleOperation = () =>\n | void\n | (() => void)\n | PromiseLike<void | (() => void)>;\n\ntype LifecycleCommitBatchEntry = {\n instance: ComponentInstance;\n wasFirstMount: boolean;\n};\n\ntype ReadSubscriptionCommit = {\n instance: ComponentInstance;\n token: number;\n pendingReadSources: Set<ReadableSource<unknown>> | undefined;\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined;\n};\n\ntype InlineRenderSnapshot = {\n instance: ComponentInstance;\n props: Props;\n ownerFrame: ContextFrame | null;\n portalScope: object | null;\n parentInstance: ComponentInstance | null;\n isRoot: boolean | undefined;\n};\n\nexport type LifecycleCommitBatch = {\n parent: LifecycleCommitBatch | null;\n entries: LifecycleCommitBatchEntry[];\n entriesByInstance: Map<ComponentInstance, LifecycleCommitBatchEntry>;\n readCommits: ReadSubscriptionCommit[];\n readCommitsByInstance: Map<ComponentInstance, ReadSubscriptionCommit>;\n renderSnapshots: InlineRenderSnapshot[];\n renderSnapshotsByInstance: Map<ComponentInstance, InlineRenderSnapshot>;\n active: boolean;\n};\n\nlet currentLifecycleCommitBatch: LifecycleCommitBatch | null = null;\n\nexport function beginLifecycleCommitBatch(): LifecycleCommitBatch {\n const batch: LifecycleCommitBatch = {\n parent: currentLifecycleCommitBatch,\n entries: [],\n entriesByInstance: new Map(),\n readCommits: [],\n readCommitsByInstance: new Map(),\n renderSnapshots: [],\n renderSnapshotsByInstance: new Map(),\n active: true,\n };\n currentLifecycleCommitBatch = batch;\n return batch;\n}\n\nfunction closeLifecycleCommitBatch(batch: LifecycleCommitBatch): boolean {\n if (!batch.active) {\n return false;\n }\n\n batch.active = false;\n currentLifecycleCommitBatch = batch.parent;\n return true;\n}\n\nfunction enqueueLifecycleCommit(\n batch: LifecycleCommitBatch,\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n const existing = batch.entriesByInstance.get(instance);\n if (existing) {\n existing.wasFirstMount = existing.wasFirstMount || wasFirstMount;\n return;\n }\n\n const entry = { instance, wasFirstMount };\n batch.entriesByInstance.set(instance, entry);\n batch.entries.push(entry);\n}\n\nfunction enqueueReadSubscriptionCommit(\n batch: LifecycleCommitBatch,\n instance: ComponentInstance,\n token: number,\n pendingReadSources: Set<ReadableSource<unknown>> | undefined,\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined\n): void {\n const existing = batch.readCommitsByInstance.get(instance);\n const commit = existing ?? {\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions,\n };\n\n commit.token = token;\n commit.pendingReadSources = pendingReadSources\n ? new Set(pendingReadSources)\n : undefined;\n commit.pendingReadSourceVersions = pendingReadSourceVersions\n ? new Map(pendingReadSourceVersions)\n : undefined;\n\n if (!existing) {\n batch.readCommitsByInstance.set(instance, commit);\n batch.readCommits.push(commit);\n }\n}\n\nfunction enqueueInlineRenderSnapshot(\n batch: LifecycleCommitBatch,\n snapshot: InlineRenderSnapshot\n): void {\n if (batch.renderSnapshotsByInstance.has(snapshot.instance)) {\n return;\n }\n\n batch.renderSnapshotsByInstance.set(snapshot.instance, snapshot);\n batch.renderSnapshots.push(snapshot);\n}\n\nexport function captureInlineRenderSnapshot(instance: ComponentInstance): void {\n if (!currentLifecycleCommitBatch?.active) {\n return;\n }\n\n enqueueInlineRenderSnapshot(currentLifecycleCommitBatch, {\n instance,\n props: instance.props,\n ownerFrame: instance.ownerFrame,\n portalScope: instance.portalScope,\n parentInstance: instance.parentInstance,\n isRoot: instance.isRoot,\n });\n}\n\nexport function finalizeInlineReadSubscriptions(\n instance: ComponentInstance,\n token: number,\n pendingReadSources: Set<ReadableSource<unknown>> | undefined,\n pendingReadSourceVersions: Map<ReadableSource<unknown>, number> | undefined\n): void {\n if (currentLifecycleCommitBatch?.active) {\n enqueueReadSubscriptionCommit(\n currentLifecycleCommitBatch,\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions\n );\n return;\n }\n\n finalizeReadableSubscriptionsFromSnapshot(\n instance,\n token,\n pendingReadSources,\n pendingReadSourceVersions\n );\n}\n\nexport function flushLifecycleCommitBatch(batch: LifecycleCommitBatch): void {\n if (!closeLifecycleCommitBatch(batch)) {\n return;\n }\n\n if (batch.parent?.active) {\n for (const snapshot of batch.renderSnapshots) {\n enqueueInlineRenderSnapshot(batch.parent, snapshot);\n }\n for (const commit of batch.readCommits) {\n enqueueReadSubscriptionCommit(\n batch.parent,\n commit.instance,\n commit.token,\n commit.pendingReadSources,\n commit.pendingReadSourceVersions\n );\n }\n for (const entry of batch.entries) {\n enqueueLifecycleCommit(batch.parent, entry.instance, entry.wasFirstMount);\n }\n return;\n }\n\n for (const commit of batch.readCommits) {\n finalizeReadableSubscriptionsFromSnapshot(\n commit.instance,\n commit.token,\n commit.pendingReadSources,\n commit.pendingReadSourceVersions\n );\n }\n\n for (const entry of batch.entries) {\n executeCommittedLifecycleOperations(entry.instance, entry.wasFirstMount);\n }\n}\n\nexport function discardLifecycleCommitBatch(batch: LifecycleCommitBatch): void {\n if (!closeLifecycleCommitBatch(batch)) {\n return;\n }\n\n for (let index = batch.renderSnapshots.length - 1; index >= 0; index -= 1) {\n const snapshot = batch.renderSnapshots[index]!;\n snapshot.instance.props = snapshot.props;\n snapshot.instance.ownerFrame = snapshot.ownerFrame;\n snapshot.instance.portalScope = snapshot.portalScope;\n snapshot.instance.parentInstance = snapshot.parentInstance;\n snapshot.instance.isRoot = snapshot.isRoot;\n }\n\n for (const entry of batch.entries) {\n if (entry.wasFirstMount) {\n entry.instance.mountOperations = [];\n }\n discardCommitOperations(entry.instance);\n }\n}\n\nexport function registerMountOperationForInstance(\n instance: ComponentInstance | null,\n operation: LifecycleOperation\n): void {\n if (instance) {\n // If we're in bulk-commit fast lane, registering mount operations is a\n // violation of the fast-lane preconditions. Throw in dev, otherwise ignore\n // silently in production (we must avoid scheduling work during bulk commit).\n if (isBulkCommitActive()) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n 'registerMountOperation called during bulk commit fast-lane'\n );\n }\n return;\n }\n instance.mountOperations.push(operation);\n }\n}\n\nexport function registerCommitOperationForInstance(\n instance: ComponentInstance | null,\n operation: LifecycleOperation\n): void {\n if (instance) {\n if (isBulkCommitActive()) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n 'registerCommitOperation called during bulk commit fast-lane'\n );\n }\n return;\n }\n instance.commitOperations.push(operation);\n }\n}\n\nfunction settleLifecycleOperationResult(\n instance: ComponentInstance,\n lifecycleGeneration: number,\n result: void | (() => void) | PromiseLike<void | (() => void)>\n): void {\n if (isPromiseLike(result)) {\n Promise.resolve(result).then(\n (cleanup) => {\n if (typeof cleanup === 'function') {\n if (\n instance.lifecycleGeneration === lifecycleGeneration &&\n instance.mounted\n ) {\n instance.cleanupFns.push(cleanup);\n return;\n }\n\n try {\n cleanup();\n } catch (err) {\n logger.error('[Askr] async mount cleanup failed:', err);\n }\n }\n },\n (err) => {\n logger.error('[Askr] async mount operation failed:', err);\n }\n );\n } else if (typeof result === 'function') {\n instance.cleanupFns.push(result);\n }\n}\n\nfunction executeMountOperations(instance: ComponentInstance): void {\n const mountOperations = instance.mountOperations;\n if (mountOperations.length === 0) {\n return;\n }\n\n const lifecycleGeneration = instance.lifecycleGeneration;\n\n for (const operation of mountOperations) {\n settleLifecycleOperationResult(instance, lifecycleGeneration, operation());\n }\n // Clear the operations array so they don't run again on subsequent renders\n instance.mountOperations = [];\n}\n\nfunction executeCommitOperations(instance: ComponentInstance): void {\n const commitOperations = instance.commitOperations;\n if (commitOperations.length === 0) {\n return;\n }\n\n instance.commitOperations = [];\n const lifecycleGeneration = instance.lifecycleGeneration;\n\n for (const operation of commitOperations) {\n settleLifecycleOperationResult(instance, lifecycleGeneration, operation());\n }\n}\n\nexport function discardCommitOperations(instance: ComponentInstance): void {\n instance.commitOperations = [];\n}\n\nexport function executeCommittedLifecycleOperations(\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n if (wasFirstMount && instance.mountOperations.length > 0) {\n executeMountOperations(instance);\n }\n if (instance.commitOperations.length > 0) {\n executeCommitOperations(instance);\n }\n}\n\nexport function commitLifecycleForInstance(\n instance: ComponentInstance,\n wasFirstMount: boolean\n): void {\n if (currentLifecycleCommitBatch) {\n enqueueLifecycleCommit(\n currentLifecycleCommitBatch,\n instance,\n wasFirstMount\n );\n return;\n }\n\n executeCommittedLifecycleOperations(instance, wasFirstMount);\n}\n\nexport function commitRenderedComponent(instance: ComponentInstance): void {\n if (instance.mounted && instance.commitOperations.length > 0) {\n commitLifecycleForInstance(instance, false);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/runtime/dev-namespace.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Dev-only namespace helpers for diagnostics
|
|
4
|
+
*
|
|
5
|
+
* Centralizes the repetitive globalThis.__ASKR__ access pattern
|
|
6
|
+
* used throughout runtime for dev-mode diagnostics.
|
|
7
|
+
*/
|
|
8
|
+
type DevNamespace = Record<string, unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Get or create the __ASKR__ dev namespace on globalThis.
|
|
11
|
+
* Returns empty object in production to avoid allocations.
|
|
12
|
+
*/
|
|
13
|
+
declare function getDevNamespace(): DevNamespace;
|
|
14
|
+
/**
|
|
15
|
+
* Set a value in the dev namespace (no-op in production).
|
|
16
|
+
*/
|
|
17
|
+
declare function setDevValue(key: string, value: unknown): void;
|
|
18
|
+
/**
|
|
19
|
+
* Get a value from the dev namespace (returns undefined in production).
|
|
20
|
+
*/
|
|
21
|
+
declare function getDevValue<T>(key: string): T | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Delete a value from the dev namespace (no-op in production).
|
|
24
|
+
*/
|
|
25
|
+
declare function deleteDevValue(key: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Increment a counter in the dev namespace (no-op in production).
|
|
28
|
+
* Safely handles non-number values by resetting to 1.
|
|
29
|
+
*/
|
|
30
|
+
declare function incDevCounter(key: string): void;
|
|
31
|
+
//# sourceMappingURL=dev-namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-namespace.d.ts","names":[],"sources":["../../src/runtime/dev-namespace.ts"],"mappings":";;;;;;AAS0B;KAArB,YAAA,GAAe,MAAM;;;;AAMqB;iBAA/B,eAAA,IAAmB,YAAY;;;;iBAc/B,WAAA,CAAY,GAAA,UAAa,KAAc;AAYvD;;;AAAA,iBAAgB,WAAA,IAAe,GAAA,WAAc,CAAC;;;;iBAY9B,cAAA,CAAe,GAAW;AAZI;AAY9C;;;AAZ8C,iBAyB9B,aAAA,CAAc,GAAW"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ComponentInstance } from "./component-internal.js";
|
|
2
|
+
//#region src/runtime/error-boundary.d.ts
|
|
3
|
+
declare function createBoundaryReset(instance: ComponentInstance): () => void;
|
|
4
|
+
declare function reportBoundaryError(instance: ComponentInstance, error: unknown, onError?: (error: unknown) => void): void;
|
|
5
|
+
//# sourceMappingURL=error-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-boundary.d.ts","names":[],"sources":["../../src/runtime/error-boundary.ts"],"mappings":";;iBAGgB,mBAAA,CAAoB,QAA2B,EAAjB,iBAAiB;AAAA,iBAc/C,mBAAA,CACd,QAAA,EAAU,iBAAiB,EAC3B,KAAA,WACA,OAAA,IAAW,KAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { logger } from "../common/logger.js";
|
|
2
|
+
//#region src/runtime/error-boundary.ts
|
|
3
|
+
function createBoundaryReset(instance) {
|
|
4
|
+
return () => {
|
|
5
|
+
const boundaryState = instance.errorBoundaryState;
|
|
6
|
+
if (!boundaryState) return;
|
|
7
|
+
boundaryState.error = null;
|
|
8
|
+
boundaryState.notified = false;
|
|
9
|
+
queueMicrotask(() => {
|
|
10
|
+
instance._enqueueRun?.();
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function reportBoundaryError(instance, error, onError) {
|
|
15
|
+
const boundaryState = instance.errorBoundaryState;
|
|
16
|
+
if (boundaryState && Object.is(boundaryState.error, error) && boundaryState.notified) return;
|
|
17
|
+
if (boundaryState) {
|
|
18
|
+
boundaryState.error = error;
|
|
19
|
+
boundaryState.notified = true;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
onError?.(error);
|
|
23
|
+
} catch (hookError) {
|
|
24
|
+
logger.error("[Askr] ErrorBoundary onError handler threw:", hookError);
|
|
25
|
+
}
|
|
26
|
+
logger.error("[Askr] ErrorBoundary caught render error:", error);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { createBoundaryReset, reportBoundaryError };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=error-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-boundary.js","names":[],"sources":["../../src/runtime/error-boundary.ts"],"sourcesContent":["import { logger } from '../common/logger';\nimport type { ComponentInstance } from './component';\n\nexport function createBoundaryReset(instance: ComponentInstance): () => void {\n return () => {\n const boundaryState = instance.errorBoundaryState;\n if (!boundaryState) {\n return;\n }\n boundaryState.error = null;\n boundaryState.notified = false;\n queueMicrotask(() => {\n instance._enqueueRun?.();\n });\n };\n}\n\nexport function reportBoundaryError(\n instance: ComponentInstance,\n error: unknown,\n onError?: (error: unknown) => void\n): void {\n const boundaryState = instance.errorBoundaryState;\n if (\n boundaryState &&\n Object.is(boundaryState.error, error) &&\n boundaryState.notified\n ) {\n return;\n }\n\n if (boundaryState) {\n boundaryState.error = error;\n boundaryState.notified = true;\n }\n\n try {\n onError?.(error);\n } catch (hookError) {\n logger.error('[Askr] ErrorBoundary onError handler threw:', hookError);\n }\n\n logger.error('[Askr] ErrorBoundary caught render error:', error);\n}\n"],"mappings":";;AAGA,SAAgB,oBAAoB,UAAyC;CAC3E,aAAa;EACX,MAAM,gBAAgB,SAAS;EAC/B,IAAI,CAAC,eACH;EAEF,cAAc,QAAQ;EACtB,cAAc,WAAW;EACzB,qBAAqB;GACnB,SAAS,cAAc;EACzB,CAAC;CACH;AACF;AAEA,SAAgB,oBACd,UACA,OACA,SACM;CACN,MAAM,gBAAgB,SAAS;CAC/B,IACE,iBACA,OAAO,GAAG,cAAc,OAAO,KAAK,KACpC,cAAc,UAEd;CAGF,IAAI,eAAe;EACjB,cAAc,QAAQ;EACtB,cAAc,WAAW;CAC3B;CAEA,IAAI;EACF,UAAU,KAAK;CACjB,SAAS,WAAW;EAClB,OAAO,MAAM,+CAA+C,SAAS;CACvE;CAEA,OAAO,MAAM,6CAA6C,KAAK;AACjE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/runtime/events.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Event delegation system for Askr
|
|
4
|
+
*
|
|
5
|
+
* Provides efficient event handling by attaching listeners to a container
|
|
6
|
+
* instead of individual elements. This significantly reduces memory usage
|
|
7
|
+
* and improves performance when many elements have the same event type.
|
|
8
|
+
*
|
|
9
|
+
* Delegated handling is enabled by default. Tests and internal runtime code
|
|
10
|
+
* can still disable or re-enable it when they need to exercise both modes.
|
|
11
|
+
*/
|
|
12
|
+
interface DelegatedEventMap {
|
|
13
|
+
click: MouseEvent;
|
|
14
|
+
dblclick: MouseEvent;
|
|
15
|
+
mousedown: MouseEvent;
|
|
16
|
+
mouseup: MouseEvent;
|
|
17
|
+
mouseover: MouseEvent;
|
|
18
|
+
mouseout: MouseEvent;
|
|
19
|
+
mousemove: MouseEvent;
|
|
20
|
+
focus: FocusEvent;
|
|
21
|
+
blur: FocusEvent;
|
|
22
|
+
input: InputEvent;
|
|
23
|
+
change: Event;
|
|
24
|
+
keydown: KeyboardEvent;
|
|
25
|
+
keyup: KeyboardEvent;
|
|
26
|
+
keypress: KeyboardEvent;
|
|
27
|
+
submit: Event;
|
|
28
|
+
scroll: Event;
|
|
29
|
+
wheel: WheelEvent;
|
|
30
|
+
touchstart: TouchEvent;
|
|
31
|
+
touchend: TouchEvent;
|
|
32
|
+
touchmove: TouchEvent;
|
|
33
|
+
touchcancel: TouchEvent;
|
|
34
|
+
}
|
|
35
|
+
interface DelegatedHandler {
|
|
36
|
+
handler: EventListener;
|
|
37
|
+
original: EventListener;
|
|
38
|
+
element: Element;
|
|
39
|
+
container: Element;
|
|
40
|
+
eventName: string;
|
|
41
|
+
options?: AddEventListenerOptions;
|
|
42
|
+
}
|
|
43
|
+
declare function isEventDelegationEnabled(): boolean;
|
|
44
|
+
declare function disableEventDelegation(): void;
|
|
45
|
+
declare function enableEventDelegation(container?: Element): void;
|
|
46
|
+
declare function setGlobalDelegationContainer(container: Element): void;
|
|
47
|
+
declare function addDelegatedListener(element: Element, eventName: string, handler: EventListener, originalHandler: EventListener, options?: AddEventListenerOptions): void;
|
|
48
|
+
declare function updateDelegatedListener(element: Element, eventName: string, handler: EventListener, originalHandler: EventListener, options?: AddEventListenerOptions): boolean;
|
|
49
|
+
declare function removeDelegatedListener(element: Element, eventName: string): void;
|
|
50
|
+
declare function getDelegatedHandlerForElement(element: Element, eventName: string): DelegatedHandler | undefined;
|
|
51
|
+
declare function getDelegatedHandlersForElement(element: Element): Map<string, DelegatedHandler> | undefined;
|
|
52
|
+
declare function hasDelegatedHandler(element: Element, eventName: string): boolean;
|
|
53
|
+
declare function clearDelegatedHandlersForElement(element: Element): void;
|
|
54
|
+
declare function getDelegatedEventNames(): readonly (keyof DelegatedEventMap)[];
|
|
55
|
+
declare function isDelegatedEvent(eventName: string): boolean;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { DelegatedEventMap };
|
|
58
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","names":[],"sources":["../../src/runtime/events.ts"],"mappings":";;AAgBA;;;;;;;;;UAAiB,iBAAA;EACf,KAAA,EAAO,UAAA;EACP,QAAA,EAAU,UAAA;EACV,SAAA,EAAW,UAAA;EACX,OAAA,EAAS,UAAA;EACT,SAAA,EAAW,UAAA;EACX,QAAA,EAAU,UAAA;EACV,SAAA,EAAW,UAAA;EACX,KAAA,EAAO,UAAA;EACP,IAAA,EAAM,UAAA;EACN,KAAA,EAAO,UAAA;EACP,MAAA,EAAQ,KAAA;EACR,OAAA,EAAS,aAAA;EACT,KAAA,EAAO,aAAA;EACP,QAAA,EAAU,aAAA;EACV,MAAA,EAAQ,KAAA;EACR,MAAA,EAAQ,KAAA;EACR,KAAA,EAAO,UAAA;EACP,UAAA,EAAY,UAAA;EACZ,QAAA,EAAU,UAAA;EACV,SAAA,EAAW,UAAA;EACX,WAAA,EAAa,UAAA;AAAA;AAAA,UA2BL,gBAAA;EACR,OAAA,EAAS,aAAA;EACT,QAAA,EAAU,aAAA;EACV,OAAA,EAAS,OAAA;EACT,SAAA,EAAW,OAAA;EACX,SAAA;EACA,OAAA,GAAU,uBAAA;AAAA;AAAA,iBAgBI,wBAAA;AAAA,iBAIA,sBAAA;AAAA,iBAKA,qBAAA,CAAsB,SAAmB,GAAP,OAAO;AAAA,iBAOzC,4BAAA,CAA6B,SAAkB,EAAP,OAAO;AAAA,iBAyK/C,oBAAA,CACd,OAAA,EAAS,OAAA,EACT,SAAA,UACA,OAAA,EAAS,aAAA,EACT,eAAA,EAAiB,aAAA,EACjB,OAAA,GAAU,uBAAA;AAAA,iBAmBI,uBAAA,CACd,OAAA,EAAS,OAAA,EACT,SAAA,UACA,OAAA,EAAS,aAAA,EACT,eAAA,EAAiB,aAAA,EACjB,OAAA,GAAU,uBAAA;AAAA,iBAuBI,uBAAA,CACd,OAAA,EAAS,OAAO,EAChB,SAAA;AAAA,iBA+Bc,6BAAA,CACd,OAAA,EAAS,OAAA,EACT,SAAA,WACC,gBAAgB;AAAA,iBAOH,8BAAA,CACd,OAAA,EAAS,OAAA,GACR,GAAA,SAAY,gBAAA;AAAA,iBAOC,mBAAA,CACd,OAAA,EAAS,OAAO,EAChB,SAAA;AAAA,iBAKc,gCAAA,CAAiC,OAAgB,EAAP,OAAO;AAAA,iBAYjD,sBAAA,oBAA0C,iBAAiB;AAAA,iBAI3D,gBAAA,CAAiB,SAAiB"}
|
package/dist/runtime/events.js
CHANGED
|
@@ -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 { runRuntimeHandlerScope } from './access';\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 container: 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>();\nconst containerDelegatedListenerUsage = new Map<Element, Map<string, number>>();\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 containerDelegatedListenerUsage.clear();\n}\n\nfunction incrementContainerListenerUsage(\n container: Element,\n eventName: string\n): void {\n let usage = containerDelegatedListenerUsage.get(container);\n if (!usage) {\n usage = new Map();\n containerDelegatedListenerUsage.set(container, usage);\n }\n usage.set(eventName, (usage.get(eventName) ?? 0) + 1);\n}\n\nfunction decrementContainerListenerUsage(entry: DelegatedHandler): void {\n const usage = containerDelegatedListenerUsage.get(entry.container);\n if (!usage) {\n return;\n }\n\n const nextCount = (usage.get(entry.eventName) ?? 0) - 1;\n if (nextCount > 0) {\n usage.set(entry.eventName, nextCount);\n return;\n }\n\n usage.delete(entry.eventName);\n const listeners = containerDelegatedListeners.get(entry.container);\n const listener = listeners?.get(entry.eventName);\n if (listener) {\n entry.container.removeEventListener(entry.eventName, listener);\n listeners?.delete(entry.eventName);\n }\n\n if (listeners?.size === 0) {\n containerDelegatedListeners.delete(entry.container);\n }\n if (usage.size === 0) {\n containerDelegatedListenerUsage.delete(entry.container);\n }\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 const hadHandler = !!getDelegatedHandlerForElement(element, eventName);\n\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 runRuntimeHandlerScope(() => {\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 container,\n eventName,\n options,\n });\n if (!hadHandler) {\n incrementContainerListenerUsage(container, eventName);\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 const container = getDelegationContainer();\n if (\n !container ||\n existing.container !== container ||\n !containerDelegatedListeners.get(existing.container)?.has(eventName)\n ) {\n removeDelegatedListener(element, eventName);\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 decrementContainerListenerUsage(existing.get(eventName)!);\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 decrementContainerListenerUsage(existing);\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 const existing = delegatedHandlers.get(element);\n if (existing instanceof Map) {\n for (const entry of existing.values()) {\n decrementContainerListenerUsage(entry);\n }\n } else if (existing) {\n decrementContainerListenerUsage(existing);\n }\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 { runRuntimeHandlerScope } from './access';\nimport { logger } from '../common/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 container: 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>();\nconst containerDelegatedListenerUsage = new Map<Element, Map<string, number>>();\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 containerDelegatedListenerUsage.clear();\n}\n\nfunction incrementContainerListenerUsage(\n container: Element,\n eventName: string\n): void {\n let usage = containerDelegatedListenerUsage.get(container);\n if (!usage) {\n usage = new Map();\n containerDelegatedListenerUsage.set(container, usage);\n }\n usage.set(eventName, (usage.get(eventName) ?? 0) + 1);\n}\n\nfunction decrementContainerListenerUsage(entry: DelegatedHandler): void {\n const usage = containerDelegatedListenerUsage.get(entry.container);\n if (!usage) {\n return;\n }\n\n const nextCount = (usage.get(entry.eventName) ?? 0) - 1;\n if (nextCount > 0) {\n usage.set(entry.eventName, nextCount);\n return;\n }\n\n usage.delete(entry.eventName);\n const listeners = containerDelegatedListeners.get(entry.container);\n const listener = listeners?.get(entry.eventName);\n if (listener) {\n entry.container.removeEventListener(entry.eventName, listener);\n listeners?.delete(entry.eventName);\n }\n\n if (listeners?.size === 0) {\n containerDelegatedListeners.delete(entry.container);\n }\n if (usage.size === 0) {\n containerDelegatedListenerUsage.delete(entry.container);\n }\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 const hadHandler = !!getDelegatedHandlerForElement(element, eventName);\n\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 runRuntimeHandlerScope(() => {\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 container,\n eventName,\n options,\n });\n if (!hadHandler) {\n incrementContainerListenerUsage(container, eventName);\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 const container = getDelegationContainer();\n if (\n !container ||\n existing.container !== container ||\n !containerDelegatedListeners.get(existing.container)?.has(eventName)\n ) {\n removeDelegatedListener(element, eventName);\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 decrementContainerListenerUsage(existing.get(eventName)!);\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 decrementContainerListenerUsage(existing);\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 const existing = delegatedHandlers.get(element);\n if (existing instanceof Map) {\n for (const entry of existing.values()) {\n decrementContainerListenerUsage(entry);\n }\n } else if (existing) {\n decrementContainerListenerUsage(existing);\n }\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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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/runtime/execution-model.d.ts
|
|
2
|
+
type ExecutionModel = 'spa' | 'islands' | 'ssr';
|
|
3
|
+
declare function getExecutionModel(): ExecutionModel | undefined;
|
|
4
|
+
declare function assertExecutionModel(model: ExecutionModel): void;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { ExecutionModel };
|
|
7
|
+
//# sourceMappingURL=execution-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-model.d.ts","names":[],"sources":["../../src/runtime/execution-model.ts"],"mappings":";KAAY,cAAA;AAAA,iBAII,iBAAA,IAAqB,cAAc;AAAA,iBAKnC,oBAAA,CAAqB,KAAqB,EAAd,cAAc"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ComponentInstance } from "./component-internal.js";
|
|
2
|
+
//#region src/runtime/fastlane.d.ts
|
|
3
|
+
declare function enterBulkCommit(): void;
|
|
4
|
+
declare function exitBulkCommit(): void;
|
|
5
|
+
declare function isBulkCommitActive(): boolean;
|
|
6
|
+
declare function markFastPathApplied(parent: Element): void;
|
|
7
|
+
declare function isFastPathApplied(parent: Element): boolean;
|
|
8
|
+
declare function classifyUpdate(instance: ComponentInstance, result: unknown): {
|
|
9
|
+
useFastPath: boolean;
|
|
10
|
+
reason: string;
|
|
11
|
+
} | {
|
|
12
|
+
useFastPath: boolean;
|
|
13
|
+
reason: string;
|
|
14
|
+
totalKeyed: number;
|
|
15
|
+
totalChildren: number;
|
|
16
|
+
currentKeyCount: number;
|
|
17
|
+
moveCount: number;
|
|
18
|
+
lisLen: number;
|
|
19
|
+
hasPropChanges: boolean;
|
|
20
|
+
isWholeKeyedList: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
readonly useFastPath: true;
|
|
23
|
+
readonly totalKeyed: number;
|
|
24
|
+
readonly totalChildren: number;
|
|
25
|
+
readonly currentKeyCount: number;
|
|
26
|
+
readonly moveCount: number;
|
|
27
|
+
readonly lisLen: number;
|
|
28
|
+
readonly hasPropChanges: boolean;
|
|
29
|
+
readonly isWholeKeyedList: boolean;
|
|
30
|
+
reason?: undefined;
|
|
31
|
+
};
|
|
32
|
+
declare function commitReorderOnly(instance: ComponentInstance, result: unknown): boolean;
|
|
33
|
+
declare function tryRuntimeFastLaneSync(instance: ComponentInstance, result: unknown): boolean;
|
|
34
|
+
//# sourceMappingURL=fastlane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastlane.d.ts","names":[],"sources":["../../src/runtime/fastlane.ts"],"mappings":";;iBAegB,eAAA;AAAA,iBAOA,cAAA;AAAA,iBAMA,kBAAA;AAAA,iBAMA,mBAAA,CAAoB,MAAe,EAAP,OAAO;AAAA,iBASnC,iBAAA,CAAkB,MAAe,EAAP,OAAO;AAAA,iBAgDjC,cAAA,CAAe,QAAA,EAAU,iBAAiB,EAAE,MAAA;;;;;;;;;;;;;;;;;;;;;;;;iBA2E5C,iBAAA,CACd,QAAA,EAAU,iBAAiB,EAC3B,MAAA;AAAA,iBAyGc,sBAAA,CACd,QAAA,EAAU,iBAAiB,EAC3B,MAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ComponentInstance } from "./component-internal.js";
|
|
2
2
|
import { ChildScope } from "./child-scope.js";
|
|
3
3
|
import { ForItemInstance } from "./for-scopes.js";
|
|
4
|
-
import { ForEachSource, ForProps } from "../control/for.js";
|
|
5
4
|
import { FineGrainedEffectHandle } from "./effect.js";
|
|
5
|
+
import { ForEachSource, ForKeySelector, ForRenderItem } from "./for-types.js";
|
|
6
6
|
import { reconcileForItems } from "./for-reconcile.js";
|
|
7
7
|
import { VNode } from "../common/vnode.js";
|
|
8
8
|
|
|
@@ -18,8 +18,8 @@ interface ForState<T> {
|
|
|
18
18
|
orderedKeys: Array<string | number>;
|
|
19
19
|
orderedItems: ForItemInstance<T>[];
|
|
20
20
|
orderedVNodes: VNode[];
|
|
21
|
-
byFn:
|
|
22
|
-
renderFn:
|
|
21
|
+
byFn: ForKeySelector<T>;
|
|
22
|
+
renderFn: ForRenderItem<T>;
|
|
23
23
|
parentInstance: ComponentInstance | null;
|
|
24
24
|
lastCommitStrategy: ForCommitStrategy;
|
|
25
25
|
lastRemovedNodes: Node[];
|
|
@@ -34,8 +34,8 @@ interface ForState<T> {
|
|
|
34
34
|
_hasPendingBoundaryCommit?: boolean;
|
|
35
35
|
devKeyKinds?: Map<string, 'number' | 'string'>;
|
|
36
36
|
}
|
|
37
|
-
declare function createForState<T>(eachSource: ForEachSource<T>, byFn: ForState<T>['byFn'], renderFn:
|
|
38
|
-
declare function useForState<T>(eachSource: ForEachSource<T>, byFn: ForState<T>['byFn'], renderFn:
|
|
37
|
+
declare function createForState<T>(eachSource: ForEachSource<T>, byFn: ForState<T>['byFn'], renderFn: ForRenderItem<T>, fallback: VNode | null): ForState<T>;
|
|
38
|
+
declare function useForState<T>(eachSource: ForEachSource<T>, byFn: ForState<T>['byFn'], renderFn: ForRenderItem<T>, fallback: VNode | null): ForState<T>;
|
|
39
39
|
declare function evaluateForState<T>(forState: ForState<T>): VNode[];
|
|
40
40
|
declare function clearForDomUpdateState<T>(forState: ForState<T>): void;
|
|
41
41
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for-internal.d.ts","names":[],"sources":["../../src/runtime/for-internal.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"for-internal.d.ts","names":[],"sources":["../../src/runtime/for-internal.ts"],"mappings":";;;;;;;;;KA4BY,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,cAAA,CAAe,CAAA;EACrB,QAAA,EAAU,aAAA,CAAc,CAAA;EACxB,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,IACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,IAAA,EAAM,QAAA,CAAS,CAAA,WACf,QAAA,EAAU,aAAA,CAAc,CAAA,GACxB,QAAA,EAAU,KAAA,UACT,QAAA,CAAS,CAAA;AAAA,iBA8BI,WAAA,IACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,IAAA,EAAM,QAAA,CAAS,CAAA,WACf,QAAA,EAAU,aAAA,CAAc,CAAA,GACxB,QAAA,EAAU,KAAA,UACT,QAAA,CAAS,CAAA;AAAA,iBAgCI,gBAAA,IAAoB,QAAA,EAAU,QAAA,CAAS,CAAA,IAAK,KAAA;AAAA,iBAS5C,sBAAA,IAA0B,QAAA,EAAU,QAAQ,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for-internal.js","names":[],"sources":["../../src/runtime/for-internal.ts"],"sourcesContent":["/**\n * For primitive runtime\n *\n * Manages For state storage, hook binding, source evaluation,\n * and DOM update state cleanup.\n */\n\nimport { type ComponentInstance, getCurrentInstance } from './component';\nimport { claimHookIndex } from './component';\nimport type { VNode } from '../common/vnode';\nimport type { ChildScope } from './child-scope';\nimport type { ForItemInstance } from './for-scopes';\nimport type {
|
|
1
|
+
{"version":3,"file":"for-internal.js","names":[],"sources":["../../src/runtime/for-internal.ts"],"sourcesContent":["/**\n * For primitive runtime\n *\n * Manages For state storage, hook binding, source evaluation,\n * and DOM update state cleanup.\n */\n\nimport { type ComponentInstance, getCurrentInstance } from './component';\nimport { claimHookIndex } from './component';\nimport type { VNode } from '../common/vnode';\nimport type { ChildScope } from './child-scope';\nimport type { ForItemInstance } from './for-scopes';\nimport type { FineGrainedEffectHandle } from './effect';\nimport type { ForEachSource, ForKeySelector, ForRenderItem } from './for-types';\nimport { reconcileForItems } from './for-reconcile';\n\nexport {\n getBenchMetrics,\n isBenchMetricScopeActive,\n recordBenchEvent,\n recordBenchCounter,\n recordBenchTiming,\n resetBenchMetrics,\n withBenchMetricScope,\n} from './for-bench';\n\nexport { reconcileForItems };\n\nexport type ForCommitStrategy =\n | 'APPEND'\n | 'TRUNCATE'\n | 'NO_REORDER'\n | 'SWAP'\n | 'FULL_KEYED';\n\nexport interface ForState<T> {\n kind: 'for';\n currentItems: T[];\n eachSource: ForEachSource<T>;\n fallback: VNode | null;\n fallbackScope: ChildScope | null;\n items: Map<string | number, ForItemInstance<T>>;\n orderedKeys: Array<string | number>;\n orderedItems: ForItemInstance<T>[];\n orderedVNodes: VNode[];\n byFn: ForKeySelector<T>;\n renderFn: ForRenderItem<T>;\n parentInstance: ComponentInstance | null;\n lastCommitStrategy: ForCommitStrategy;\n lastRemovedNodes: Node[];\n pendingDirtyIndices: number[] | null;\n pendingSwapIndices: [number, number] | null;\n pendingMoveOnly: boolean;\n _hasResolvedItemDom: boolean;\n _needsSourceReconcile: boolean;\n _sourceEffect: FineGrainedEffectHandle<T[]> | null;\n _suspendSourceCommit: boolean;\n _enqueueBoundaryCommit?: (() => void) | null;\n _hasPendingBoundaryCommit?: boolean;\n devKeyKinds?: Map<string, 'number' | 'string'>;\n}\n\nconst forStates = new WeakMap<\n ComponentInstance,\n Map<number, ForState<unknown>>\n>();\n\nfunction getForStore(\n instance: ComponentInstance\n): Map<number, ForState<unknown>> {\n let store = forStates.get(instance);\n if (!store) {\n store = new Map();\n forStates.set(instance, store);\n }\n return store;\n}\n\nexport function createForState<T>(\n eachSource: ForEachSource<T>,\n byFn: ForState<T>['byFn'],\n renderFn: ForRenderItem<T>,\n fallback: VNode | null\n): ForState<T> {\n const parentInstance = getCurrentInstance();\n\n return {\n kind: 'for',\n currentItems: [],\n eachSource,\n fallback,\n fallbackScope: null,\n items: new Map(),\n orderedKeys: [],\n orderedItems: [],\n orderedVNodes: [],\n byFn,\n renderFn,\n parentInstance,\n lastCommitStrategy: 'NO_REORDER',\n lastRemovedNodes: [],\n pendingDirtyIndices: null,\n pendingSwapIndices: null,\n pendingMoveOnly: false,\n _hasResolvedItemDom: false,\n _needsSourceReconcile: false,\n _sourceEffect: null,\n _suspendSourceCommit: false,\n _enqueueBoundaryCommit: null,\n _hasPendingBoundaryCommit: false,\n };\n}\n\nexport function useForState<T>(\n eachSource: ForEachSource<T>,\n byFn: ForState<T>['byFn'],\n renderFn: ForRenderItem<T>,\n fallback: VNode | null\n): ForState<T> {\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'For can only be created during component render execution.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'For');\n const store = getForStore(instance);\n const existing = store.get(hookIndex) as ForState<T> | undefined;\n\n if (existing) {\n existing.eachSource = eachSource;\n existing.byFn = byFn;\n existing.renderFn = renderFn;\n existing.fallback = fallback;\n return existing;\n }\n\n const created = createForState(eachSource, byFn, renderFn, fallback);\n store.set(hookIndex, created as ForState<unknown>);\n\n (instance.cleanupFns ??= []).push(() => {\n created._sourceEffect?.cleanup();\n created._sourceEffect = null;\n store.delete(hookIndex);\n });\n\n return created;\n}\n\nexport function evaluateForState<T>(forState: ForState<T>): VNode[] {\n if (!Array.isArray(forState.currentItems)) {\n throw new Error('For source must evaluate to an array');\n }\n\n forState._needsSourceReconcile = false;\n return reconcileForItems(forState, forState.currentItems);\n}\n\nexport function clearForDomUpdateState<T>(forState: ForState<T>): void {\n const dirtyIndices = forState.pendingDirtyIndices;\n if (dirtyIndices && dirtyIndices.length > 0) {\n for (let i = 0; i < dirtyIndices.length; i++) {\n const itemInstance = forState.orderedItems[dirtyIndices[i]];\n if (itemInstance) {\n itemInstance.scope.needsDomUpdate = false;\n }\n }\n } else {\n for (let i = 0; i < forState.orderedKeys.length; i++) {\n const key = forState.orderedKeys[i];\n const itemInstance = forState.items.get(key);\n if (itemInstance) {\n itemInstance.scope.needsDomUpdate = false;\n }\n }\n }\n\n if (forState.fallbackScope) {\n forState.fallbackScope.needsDomUpdate = false;\n }\n forState.lastRemovedNodes = [];\n forState.pendingDirtyIndices = null;\n forState.pendingSwapIndices = null;\n forState.pendingMoveOnly = false;\n forState._needsSourceReconcile = false;\n forState._hasResolvedItemDom = forState.orderedKeys.length > 0;\n}\n"],"mappings":";;;;;;;;;;;AA8DA,MAAM,4BAAY,IAAI,QAGpB;AAEF,SAAS,YACP,UACgC;CAChC,IAAI,QAAQ,UAAU,IAAI,QAAQ;CAClC,IAAI,CAAC,OAAO;EACV,wBAAQ,IAAI,IAAI;EAChB,UAAU,IAAI,UAAU,KAAK;CAC/B;CACA,OAAO;AACT;AAEA,SAAgB,eACd,YACA,MACA,UACA,UACa;CACb,MAAM,iBAAiB,mBAAmB;CAE1C,OAAO;EACL,MAAM;EACN,cAAc,CAAC;EACf;EACA;EACA,eAAe;EACf,uBAAO,IAAI,IAAI;EACf,aAAa,CAAC;EACd,cAAc,CAAC;EACf,eAAe,CAAC;EAChB;EACA;EACA;EACA,oBAAoB;EACpB,kBAAkB,CAAC;EACnB,qBAAqB;EACrB,oBAAoB;EACpB,iBAAiB;EACjB,qBAAqB;EACrB,uBAAuB;EACvB,eAAe;EACf,sBAAsB;EACtB,wBAAwB;EACxB,2BAA2B;CAC7B;AACF;AAEA,SAAgB,YACd,YACA,MACA,UACA,UACa;CACb,MAAM,WAAW,mBAAmB;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,4DACF;CAGF,MAAM,YAAY,eAAe,UAAU,KAAK;CAChD,MAAM,QAAQ,YAAY,QAAQ;CAClC,MAAM,WAAW,MAAM,IAAI,SAAS;CAEpC,IAAI,UAAU;EACZ,SAAS,aAAa;EACtB,SAAS,OAAO;EAChB,SAAS,WAAW;EACpB,SAAS,WAAW;EACpB,OAAO;CACT;CAEA,MAAM,UAAU,eAAe,YAAY,MAAM,UAAU,QAAQ;CACnE,MAAM,IAAI,WAAW,OAA4B;CAEjD,CAAC,SAAS,eAAe,CAAC,EAAA,CAAG,WAAW;EACtC,QAAQ,eAAe,QAAQ;EAC/B,QAAQ,gBAAgB;EACxB,MAAM,OAAO,SAAS;CACxB,CAAC;CAED,OAAO;AACT;AAEA,SAAgB,iBAAoB,UAAgC;CAClE,IAAI,CAAC,MAAM,QAAQ,SAAS,YAAY,GACtC,MAAM,IAAI,MAAM,sCAAsC;CAGxD,SAAS,wBAAwB;CACjC,OAAO,kBAAkB,UAAU,SAAS,YAAY;AAC1D;AAEA,SAAgB,uBAA0B,UAA6B;CACrE,MAAM,eAAe,SAAS;CAC9B,IAAI,gBAAgB,aAAa,SAAS,GACxC,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EAC5C,MAAM,eAAe,SAAS,aAAa,aAAa;EACxD,IAAI,cACF,aAAa,MAAM,iBAAiB;CAExC;MAEA,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;EACpD,MAAM,MAAM,SAAS,YAAY;EACjC,MAAM,eAAe,SAAS,MAAM,IAAI,GAAG;EAC3C,IAAI,cACF,aAAa,MAAM,iBAAiB;CAExC;CAGF,IAAI,SAAS,eACX,SAAS,cAAc,iBAAiB;CAE1C,SAAS,mBAAmB,CAAC;CAC7B,SAAS,sBAAsB;CAC/B,SAAS,qBAAqB;CAC9B,SAAS,kBAAkB;CAC3B,SAAS,wBAAwB;CACjC,SAAS,sBAAsB,SAAS,YAAY,SAAS;AAC/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"for-signals.d.ts","names":[],"sources":["../../src/runtime/for-signals.ts"],"mappings":";;;;;KAUY,aAAA,MAAmB,cAAA,CAAe,CAAA,WACrC,CAAA;EACL,IAAA,IAAQ,CAAA;EACR,GAAA,CAAI,QAAA,EAAU,CAAA,EAAG,aAAA;AAAA;AAAA,KAGT,qBAAA,GAAwB,cAAc;EAE9C,IAAA;EACA,GAAA,CAAI,QAAA,WAAmB,aAAA;AAAA;AAAA,KAGf,cAAA,GAAiB,cAAc;EAEvC,IAAA;EACA,GAAA,CACE,QAAA,aAAqB,IAAA,sBACrB,aAAA;AAAA;AAAA,iBAIU,sBAAA,CACd,MAAA,EAAQ,cAAA,WACR,YAAA,GAAe,iBAAiB;AAAA,iBAOlB,oBAAA,CAAqB,YAAA,WAAuB,cAAc;AAAA,iBA6B1D,kBAAA,CACd,WAAA,EAAa,cAAc,EAC3B,SAAA;AAAA,iBAUc,mBAAA,IAAuB,WAAA,EAAa,CAAA,GAAI,aAAA,CAAc,CAAA;AAAA,iBAwDtD,mBAAA,CAAoB,IAAA,WAAe,IAAA,EAAM,WAAW;AAAA,iBAIpD,eAAA,CACd,YAAA,WACA,QAAiB;AAAA,iBAkBH,gBAAA,CACd,KAAA,EAAO,UAAA,EACP,MAAA,EAAQ,cAAc;AAAA,iBAqBR,sBAAA,CACd,cAAA,EAAgB,iBAAA,SAChB,MAAA,EAAQ,cAAc;AAAA,iBA+BR,eAAA,CAAgB,IAAA,YAAgB,IAAI;AAAA,
|
|
1
|
+
{"version":3,"file":"for-signals.d.ts","names":[],"sources":["../../src/runtime/for-signals.ts"],"mappings":";;;;;KAUY,aAAA,MAAmB,cAAA,CAAe,CAAA,WACrC,CAAA;EACL,IAAA,IAAQ,CAAA;EACR,GAAA,CAAI,QAAA,EAAU,CAAA,EAAG,aAAA;AAAA;AAAA,KAGT,qBAAA,GAAwB,cAAc;EAE9C,IAAA;EACA,GAAA,CAAI,QAAA,WAAmB,aAAA;AAAA;AAAA,KAGf,cAAA,GAAiB,cAAc;EAEvC,IAAA;EACA,GAAA,CACE,QAAA,aAAqB,IAAA,sBACrB,aAAA;AAAA;AAAA,iBAIU,sBAAA,CACd,MAAA,EAAQ,cAAA,WACR,YAAA,GAAe,iBAAiB;AAAA,iBAOlB,oBAAA,CAAqB,YAAA,WAAuB,cAAc;AAAA,iBA6B1D,kBAAA,CACd,WAAA,EAAa,cAAc,EAC3B,SAAA;AAAA,iBAUc,mBAAA,IAAuB,WAAA,EAAa,CAAA,GAAI,aAAA,CAAc,CAAA;AAAA,iBAwDtD,mBAAA,CAAoB,IAAA,WAAe,IAAA,EAAM,WAAW;AAAA,iBAIpD,eAAA,CACd,YAAA,WACA,QAAiB;AAAA,iBAkBH,gBAAA,CACd,KAAA,EAAO,UAAA,EACP,MAAA,EAAQ,cAAc;AAAA,iBAqBR,sBAAA,CACd,cAAA,EAAgB,iBAAA,SAChB,MAAA,EAAQ,cAAc;AAAA,iBA+BR,eAAA,CAAgB,IAAA,YAAgB,IAAI;AAAA,iBAOpC,qBAAA,IACd,UAAA,EAAY,aAAA,CAAc,CAAA,GAC1B,eAAA,EAAiB,GAAA,CAAI,WAAA,EAAa,qBAAA,IACjC,CAAA"}
|