@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
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { enqueueRuntimeLane } from "./access.js";
|
|
2
|
+
//#region src/runtime/selector-store.ts
|
|
3
|
+
const dirtySelectorRecords = /* @__PURE__ */ new Set();
|
|
4
|
+
let hasPendingSelectorFlush = false;
|
|
5
|
+
function markDirtySelectorRecord(record, flush) {
|
|
6
|
+
record._dirty = true;
|
|
7
|
+
if (record._scheduled) return;
|
|
8
|
+
record._scheduled = true;
|
|
9
|
+
dirtySelectorRecords.add(record);
|
|
10
|
+
if (hasPendingSelectorFlush) return;
|
|
11
|
+
hasPendingSelectorFlush = true;
|
|
12
|
+
enqueueRuntimeLane("derived", flush);
|
|
13
|
+
}
|
|
14
|
+
function takeDirtySelectorRecords() {
|
|
15
|
+
hasPendingSelectorFlush = false;
|
|
16
|
+
if (dirtySelectorRecords.size === 0) return [];
|
|
17
|
+
const pending = Array.from(dirtySelectorRecords);
|
|
18
|
+
dirtySelectorRecords.clear();
|
|
19
|
+
return pending;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { markDirtySelectorRecord, takeDirtySelectorRecords };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=selector-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-store.js","names":[],"sources":["../../src/runtime/selector-store.ts"],"sourcesContent":["import { enqueueRuntimeLane } from './access';\n\ntype DirtySelectorRecord = {\n _dirty: boolean;\n _scheduled: boolean;\n};\n\nconst dirtySelectorRecords = new Set<DirtySelectorRecord>();\nlet hasPendingSelectorFlush = false;\n\nexport function markDirtySelectorRecord<T extends DirtySelectorRecord>(\n record: T,\n flush: () => void\n): void {\n record._dirty = true;\n if (record._scheduled) {\n return;\n }\n\n record._scheduled = true;\n dirtySelectorRecords.add(record);\n\n if (hasPendingSelectorFlush) {\n return;\n }\n\n hasPendingSelectorFlush = true;\n enqueueRuntimeLane('derived', flush);\n}\n\nexport function takeDirtySelectorRecords<T extends DirtySelectorRecord>(): T[] {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorRecords.size === 0) {\n return [];\n }\n\n const pending = Array.from(dirtySelectorRecords);\n dirtySelectorRecords.clear();\n return pending as T[];\n}\n"],"mappings":";;AAOA,MAAM,uCAAuB,IAAI,IAAyB;AAC1D,IAAI,0BAA0B;AAE9B,SAAgB,wBACd,QACA,OACM;CACN,OAAO,SAAS;CAChB,IAAI,OAAO,YACT;CAGF,OAAO,aAAa;CACpB,qBAAqB,IAAI,MAAM;CAE/B,IAAI,yBACF;CAGF,0BAA0B;CAC1B,mBAAmB,WAAW,KAAK;AACrC;AAEA,SAAgB,2BAA+D;CAC7E,0BAA0B;CAE1B,IAAI,qBAAqB,SAAS,GAChC,OAAO,CAAC;CAGV,MAAM,UAAU,MAAM,KAAK,oBAAoB;CAC/C,qBAAqB,MAAM;CAC3B,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector.d.ts","names":[],"sources":["../../src/runtime/selector.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"selector.d.ts","names":[],"sources":["../../src/runtime/selector.ts"],"mappings":";UAgCiB,QAAA;EAAA,CACd,SAAA,EAAW,CAAC;AAAA;AAAA,KAOV,cAAA;EACH,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;AAAA;AAAA,iBAicX,QAAA,IACd,MAAA,QAAc,CAAA,EACd,MAAA,GAAQ,cAAA,CAAe,CAAA,IACtB,QAAA,CAAS,CAAA"}
|
package/dist/runtime/selector.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { getPerfMetricsStore, incrementPerfMetric } from "./perf-metrics.js";
|
|
2
|
-
import { enqueueRuntimeLane } from "./access.js";
|
|
3
2
|
import { clearDerivedDependencySubscriptions, markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, markReadableUsage, notifyReadableReaders, recordReadableRead, syncDerivedDependencySubscriptions, withDerivedReadTracking } from "./readable.js";
|
|
4
3
|
import { claimHookIndex, getCurrentInstance } from "./component-scope.js";
|
|
5
4
|
import "./component.js";
|
|
5
|
+
import { markDirtySelectorRecord, takeDirtySelectorRecords } from "./selector-store.js";
|
|
6
6
|
//#region src/runtime/selector.ts
|
|
7
7
|
const selectorCells = /* @__PURE__ */ new WeakMap();
|
|
8
8
|
const selectorRecords = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
const dirtySelectorRecords = /* @__PURE__ */ new Set();
|
|
10
|
-
let hasPendingSelectorFlush = false;
|
|
11
9
|
function getSelectorStore(instance) {
|
|
12
10
|
let store = selectorCells.get(instance);
|
|
13
11
|
if (!store) {
|
|
@@ -16,24 +14,11 @@ function getSelectorStore(instance) {
|
|
|
16
14
|
}
|
|
17
15
|
return store;
|
|
18
16
|
}
|
|
19
|
-
function scheduleSelectorFlush() {
|
|
20
|
-
if (hasPendingSelectorFlush) return;
|
|
21
|
-
hasPendingSelectorFlush = true;
|
|
22
|
-
enqueueRuntimeLane("derived", flushDirtySelectorRecords);
|
|
23
|
-
}
|
|
24
17
|
function markSelectorRecordDirty(record) {
|
|
25
|
-
record
|
|
26
|
-
if (record._scheduled) return;
|
|
27
|
-
record._scheduled = true;
|
|
28
|
-
dirtySelectorRecords.add(record);
|
|
29
|
-
scheduleSelectorFlush();
|
|
18
|
+
markDirtySelectorRecord(record, flushDirtySelectorRecords);
|
|
30
19
|
}
|
|
31
20
|
function flushDirtySelectorRecords() {
|
|
32
|
-
|
|
33
|
-
if (dirtySelectorRecords.size === 0) return;
|
|
34
|
-
const pending = Array.from(dirtySelectorRecords);
|
|
35
|
-
dirtySelectorRecords.clear();
|
|
36
|
-
for (const record of pending) {
|
|
21
|
+
for (const record of takeDirtySelectorRecords()) {
|
|
37
22
|
record._scheduled = false;
|
|
38
23
|
if (!record._dirty) continue;
|
|
39
24
|
recomputeSelectorSourceRecord(record, true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { enqueueRuntimeLane } from './access';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { getPerfMetricsStore, incrementPerfMetric } from './perf-metrics';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorLane<T> {\n _record: SelectorSourceRecord<T>;\n _equals: SelectorEquals<T>;\n _bindingCount: number;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorSourceRecord<T> extends DerivedSubscriber {\n _source: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _lanes: Map<SelectorEquals<T>, SelectorLane<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorHook<T> extends Selector<T> {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _record: SelectorSourceRecord<T> | null;\n _lane: SelectorLane<T> | null;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorHook<unknown>>\n>();\nconst selectorRecords = new WeakMap<\n ReadableSource<unknown>,\n SelectorSourceRecord<unknown>\n>();\nconst dirtySelectorRecords = new Set<SelectorSourceRecord<unknown>>();\nlet hasPendingSelectorFlush = false;\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorHook<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction scheduleSelectorFlush(): void {\n if (hasPendingSelectorFlush) {\n return;\n }\n\n hasPendingSelectorFlush = true;\n enqueueRuntimeLane('derived', flushDirtySelectorRecords);\n}\n\nfunction markSelectorRecordDirty(record: SelectorSourceRecord<unknown>): void {\n record._dirty = true;\n if (record._scheduled) {\n return;\n }\n\n record._scheduled = true;\n dirtySelectorRecords.add(record);\n scheduleSelectorFlush();\n}\n\nfunction flushDirtySelectorRecords(): void {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorRecords.size === 0) {\n return;\n }\n\n const pending = Array.from(dirtySelectorRecords);\n dirtySelectorRecords.clear();\n\n for (const record of pending) {\n record._scheduled = false;\n if (!record._dirty) {\n continue;\n }\n recomputeSelectorSourceRecord(record, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = lane._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._objectCandidates.set(candidate, created);\n lane._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = lane._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction peekCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> | undefined {\n if (isObjectCandidate(candidate)) {\n return lane._objectCandidates.get(candidate);\n }\n return lane._primitiveCandidates.get(candidate as PrimitiveKey);\n}\n\nfunction getSelectorSourceRecord<T>(source: () => T): SelectorSourceRecord<T> {\n const cached = selectorRecords.get(source);\n if (cached) {\n return cached as SelectorSourceRecord<T>;\n }\n\n const record = createSelectorSourceRecord(source);\n selectorRecords.set(source, record as SelectorSourceRecord<unknown>);\n return record;\n}\n\nfunction createSelectorSourceRecord<T>(\n source: () => T\n): SelectorSourceRecord<T> {\n let record!: SelectorSourceRecord<T>;\n\n record = {\n _source: source,\n _value: undefined as T,\n _hasValue: false,\n _dirty: true,\n _scheduled: false,\n _evaluating: false,\n _sources: new Set(),\n _lanes: new Map(),\n _markDirty: () => {\n markSelectorRecordDirty(record as SelectorSourceRecord<unknown>);\n },\n _cleanup: () => {\n record._scheduled = false;\n record._dirty = false;\n record._hasValue = false;\n record._evaluating = false;\n record._pendingDependencySources = undefined;\n clearDerivedDependencySubscriptions(record, record._sources);\n record._lanes.clear();\n selectorRecords.delete(source as ReadableSource<unknown>);\n },\n };\n\n return record;\n}\n\nfunction getSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const cached = record._lanes.get(equals);\n if (cached) {\n return cached;\n }\n\n const lane = createSelectorLane(record, equals);\n record._lanes.set(equals, lane);\n return lane;\n}\n\nfunction createSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const lane: SelectorLane<T> = {\n _record: record,\n _equals: equals,\n _bindingCount: 0,\n _primitiveCandidates: new Map(),\n _objectCandidates: new WeakMap(),\n _objectCandidateSources: new Set(),\n _cleanup: () => {\n for (const sourceRef of lane._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of lane._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n lane._primitiveCandidates.clear();\n lane._objectCandidates = new WeakMap();\n lane._objectCandidateSources.clear();\n },\n };\n\n return lane;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(lane: SelectorLane<T>): void {\n for (const source of lane._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of lane._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorLaneValueChange<T>(\n lane: SelectorLane<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!lane._bindingCount) {\n return;\n }\n\n if (!isDefaultSelectorEquals(lane._equals)) {\n if (lane._equals(prevValue, nextValue)) {\n return;\n }\n notifyAllSelectorSources(lane);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n // Only notify candidate sources that were actually materialized by a read.\n // Using getCandidateSource here would create-on-miss and leak a candidate\n // source for every distinct value the source ever passed through, even\n // those no component reads. Peek instead so the candidate cache stays\n // bounded to values that components actually compare against.\n const prevSource = peekCandidateSource(lane, prevValue);\n if (prevSource) {\n notifySelectorSource(prevSource);\n }\n const nextSource = peekCandidateSource(lane, nextValue);\n if (nextSource) {\n notifySelectorSource(nextSource);\n }\n }\n}\n\nfunction recomputeSelectorSourceRecord<T>(\n record: SelectorSourceRecord<T>,\n notifyDownstream: boolean\n): T {\n if (!record._dirty && record._hasValue) {\n return record._value;\n }\n\n if (record._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n record._evaluating = true;\n record._dirty = false;\n record._pendingDependencySources = new Set();\n\n const prevSources = record._sources;\n const hadValue = record._hasValue;\n const prevValue = record._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(record, record._source);\n } catch (error) {\n record._dirty = true;\n record._pendingDependencySources = undefined;\n throw error;\n } finally {\n record._evaluating = false;\n }\n\n const nextSources = record._pendingDependencySources ?? new Set();\n record._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(record, prevSources, nextSources);\n record._sources = nextSources;\n\n const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);\n record._hasValue = true;\n record._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n for (const lane of Array.from(record._lanes.values())) {\n notifySelectorLaneValueChange(lane, prevValue, nextValue);\n }\n }\n\n return record._value;\n}\n\nfunction attachSelectorHookBinding<T>(\n hook: SelectorHook<T>,\n source: () => T,\n equals: SelectorEquals<T>\n): void {\n const record = getSelectorSourceRecord(source);\n const lane = getSelectorLane(record, equals);\n\n hook._source = source;\n hook._equals = equals;\n hook._record = record;\n hook._lane = lane;\n lane._bindingCount += 1;\n}\n\nfunction detachSelectorHookBinding<T>(hook: SelectorHook<T>): void {\n const record = hook._record;\n const lane = hook._lane;\n\n hook._record = null;\n hook._lane = null;\n\n if (!record || !lane) {\n return;\n }\n\n if (lane._bindingCount > 0) {\n lane._bindingCount -= 1;\n }\n\n if (lane._bindingCount > 0) {\n return;\n }\n\n lane._cleanup();\n record._lanes.delete(lane._equals);\n\n if (record._lanes.size === 0) {\n record._cleanup();\n }\n}\n\nfunction ensureSelectorHookBinding<T>(\n hook: SelectorHook<T>\n): SelectorSourceRecord<T> {\n const record = hook._record;\n const lane = hook._lane;\n\n if (\n record &&\n lane &&\n lane._bindingCount > 0 &&\n record._lanes.get(hook._equals) === lane &&\n record._source === hook._source\n ) {\n return record;\n }\n\n if (hook._record || hook._lane) {\n detachSelectorHookBinding(hook);\n }\n\n attachSelectorHookBinding(hook, hook._source, hook._equals);\n return hook._record!;\n}\n\nfunction createSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const hook = function selectorPredicate(candidate: T): boolean {\n const selectorHook = hook as SelectorHook<T>;\n const record = ensureSelectorHookBinding(selectorHook);\n const lane = selectorHook._lane;\n if (!lane) {\n throw new Error('selector() binding could not be established.');\n }\n\n const sourceRef = getCandidateSource(lane, candidate);\n recordReadableRead(sourceRef);\n\n const perfMetricsStore = getPerfMetricsStore();\n if (perfMetricsStore) {\n perfMetricsStore.selectorCandidateReads += 1;\n }\n\n const current =\n record._dirty || !record._hasValue\n ? recomputeSelectorSourceRecord(record, record._scheduled)\n : record._value;\n\n return lane._equals(current, candidate);\n } as SelectorHook<T>;\n\n hook._owner = instance;\n hook._hookIndex = hookIndex;\n hook._source = source;\n hook._equals = equals;\n hook._record = null;\n hook._lane = null;\n hook._cleanup = () => {\n detachSelectorHookBinding(hook);\n };\n\n attachSelectorHookBinding(hook, source, equals);\n\n (instance.cleanupFns ??= []).push(() => {\n hook._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return hook;\n}\n\nfunction getOrCreateSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorHook<T> | undefined;\n if (existing) {\n if (existing._source !== source || existing._equals !== equals) {\n detachSelectorHookBinding(existing);\n attachSelectorHookBinding(existing, source, equals);\n } else {\n ensureSelectorHookBinding(existing);\n }\n return existing;\n }\n\n const created = createSelectorHook(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorHook<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const hook = getOrCreateSelectorHook(instance, hookIndex, source, equals);\n if (!hook._record) {\n throw new Error('selector() record binding was not established.');\n }\n\n if (!hook._record._hasValue) {\n // Initialize the shared source once so downstream selectors can subscribe,\n // but do not consume a pending dirty state on later renders.\n recomputeSelectorSourceRecord(hook._record, false);\n }\n return hook;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { getPerfMetricsStore, incrementPerfMetric } from './perf-metrics';\nimport {\n markDirtySelectorRecord,\n takeDirtySelectorRecords,\n} from './selector-store';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorLane<T> {\n _record: SelectorSourceRecord<T>;\n _equals: SelectorEquals<T>;\n _bindingCount: number;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorSourceRecord<T> extends DerivedSubscriber {\n _source: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _lanes: Map<SelectorEquals<T>, SelectorLane<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorHook<T> extends Selector<T> {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _record: SelectorSourceRecord<T> | null;\n _lane: SelectorLane<T> | null;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorHook<unknown>>\n>();\nconst selectorRecords = new WeakMap<\n ReadableSource<unknown>,\n SelectorSourceRecord<unknown>\n>();\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorHook<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction markSelectorRecordDirty(record: SelectorSourceRecord<unknown>): void {\n markDirtySelectorRecord(record, flushDirtySelectorRecords);\n}\n\nfunction flushDirtySelectorRecords(): void {\n for (const record of takeDirtySelectorRecords<\n SelectorSourceRecord<unknown>\n >()) {\n record._scheduled = false;\n if (!record._dirty) {\n continue;\n }\n recomputeSelectorSourceRecord(record, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = lane._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._objectCandidates.set(candidate, created);\n lane._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = lane._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction peekCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> | undefined {\n if (isObjectCandidate(candidate)) {\n return lane._objectCandidates.get(candidate);\n }\n return lane._primitiveCandidates.get(candidate as PrimitiveKey);\n}\n\nfunction getSelectorSourceRecord<T>(source: () => T): SelectorSourceRecord<T> {\n const cached = selectorRecords.get(source);\n if (cached) {\n return cached as SelectorSourceRecord<T>;\n }\n\n const record = createSelectorSourceRecord(source);\n selectorRecords.set(source, record as SelectorSourceRecord<unknown>);\n return record;\n}\n\nfunction createSelectorSourceRecord<T>(\n source: () => T\n): SelectorSourceRecord<T> {\n let record!: SelectorSourceRecord<T>;\n\n record = {\n _source: source,\n _value: undefined as T,\n _hasValue: false,\n _dirty: true,\n _scheduled: false,\n _evaluating: false,\n _sources: new Set(),\n _lanes: new Map(),\n _markDirty: () => {\n markSelectorRecordDirty(record as SelectorSourceRecord<unknown>);\n },\n _cleanup: () => {\n record._scheduled = false;\n record._dirty = false;\n record._hasValue = false;\n record._evaluating = false;\n record._pendingDependencySources = undefined;\n clearDerivedDependencySubscriptions(record, record._sources);\n record._lanes.clear();\n selectorRecords.delete(source as ReadableSource<unknown>);\n },\n };\n\n return record;\n}\n\nfunction getSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const cached = record._lanes.get(equals);\n if (cached) {\n return cached;\n }\n\n const lane = createSelectorLane(record, equals);\n record._lanes.set(equals, lane);\n return lane;\n}\n\nfunction createSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const lane: SelectorLane<T> = {\n _record: record,\n _equals: equals,\n _bindingCount: 0,\n _primitiveCandidates: new Map(),\n _objectCandidates: new WeakMap(),\n _objectCandidateSources: new Set(),\n _cleanup: () => {\n for (const sourceRef of lane._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of lane._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n lane._primitiveCandidates.clear();\n lane._objectCandidates = new WeakMap();\n lane._objectCandidateSources.clear();\n },\n };\n\n return lane;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(lane: SelectorLane<T>): void {\n for (const source of lane._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of lane._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorLaneValueChange<T>(\n lane: SelectorLane<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!lane._bindingCount) {\n return;\n }\n\n if (!isDefaultSelectorEquals(lane._equals)) {\n if (lane._equals(prevValue, nextValue)) {\n return;\n }\n notifyAllSelectorSources(lane);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n // Only notify candidate sources that were actually materialized by a read.\n // Using getCandidateSource here would create-on-miss and leak a candidate\n // source for every distinct value the source ever passed through, even\n // those no component reads. Peek instead so the candidate cache stays\n // bounded to values that components actually compare against.\n const prevSource = peekCandidateSource(lane, prevValue);\n if (prevSource) {\n notifySelectorSource(prevSource);\n }\n const nextSource = peekCandidateSource(lane, nextValue);\n if (nextSource) {\n notifySelectorSource(nextSource);\n }\n }\n}\n\nfunction recomputeSelectorSourceRecord<T>(\n record: SelectorSourceRecord<T>,\n notifyDownstream: boolean\n): T {\n if (!record._dirty && record._hasValue) {\n return record._value;\n }\n\n if (record._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n record._evaluating = true;\n record._dirty = false;\n record._pendingDependencySources = new Set();\n\n const prevSources = record._sources;\n const hadValue = record._hasValue;\n const prevValue = record._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(record, record._source);\n } catch (error) {\n record._dirty = true;\n record._pendingDependencySources = undefined;\n throw error;\n } finally {\n record._evaluating = false;\n }\n\n const nextSources = record._pendingDependencySources ?? new Set();\n record._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(record, prevSources, nextSources);\n record._sources = nextSources;\n\n const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);\n record._hasValue = true;\n record._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n for (const lane of Array.from(record._lanes.values())) {\n notifySelectorLaneValueChange(lane, prevValue, nextValue);\n }\n }\n\n return record._value;\n}\n\nfunction attachSelectorHookBinding<T>(\n hook: SelectorHook<T>,\n source: () => T,\n equals: SelectorEquals<T>\n): void {\n const record = getSelectorSourceRecord(source);\n const lane = getSelectorLane(record, equals);\n\n hook._source = source;\n hook._equals = equals;\n hook._record = record;\n hook._lane = lane;\n lane._bindingCount += 1;\n}\n\nfunction detachSelectorHookBinding<T>(hook: SelectorHook<T>): void {\n const record = hook._record;\n const lane = hook._lane;\n\n hook._record = null;\n hook._lane = null;\n\n if (!record || !lane) {\n return;\n }\n\n if (lane._bindingCount > 0) {\n lane._bindingCount -= 1;\n }\n\n if (lane._bindingCount > 0) {\n return;\n }\n\n lane._cleanup();\n record._lanes.delete(lane._equals);\n\n if (record._lanes.size === 0) {\n record._cleanup();\n }\n}\n\nfunction ensureSelectorHookBinding<T>(\n hook: SelectorHook<T>\n): SelectorSourceRecord<T> {\n const record = hook._record;\n const lane = hook._lane;\n\n if (\n record &&\n lane &&\n lane._bindingCount > 0 &&\n record._lanes.get(hook._equals) === lane &&\n record._source === hook._source\n ) {\n return record;\n }\n\n if (hook._record || hook._lane) {\n detachSelectorHookBinding(hook);\n }\n\n attachSelectorHookBinding(hook, hook._source, hook._equals);\n return hook._record!;\n}\n\nfunction createSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const hook = function selectorPredicate(candidate: T): boolean {\n const selectorHook = hook as SelectorHook<T>;\n const record = ensureSelectorHookBinding(selectorHook);\n const lane = selectorHook._lane;\n if (!lane) {\n throw new Error('selector() binding could not be established.');\n }\n\n const sourceRef = getCandidateSource(lane, candidate);\n recordReadableRead(sourceRef);\n\n const perfMetricsStore = getPerfMetricsStore();\n if (perfMetricsStore) {\n perfMetricsStore.selectorCandidateReads += 1;\n }\n\n const current =\n record._dirty || !record._hasValue\n ? recomputeSelectorSourceRecord(record, record._scheduled)\n : record._value;\n\n return lane._equals(current, candidate);\n } as SelectorHook<T>;\n\n hook._owner = instance;\n hook._hookIndex = hookIndex;\n hook._source = source;\n hook._equals = equals;\n hook._record = null;\n hook._lane = null;\n hook._cleanup = () => {\n detachSelectorHookBinding(hook);\n };\n\n attachSelectorHookBinding(hook, source, equals);\n\n (instance.cleanupFns ??= []).push(() => {\n hook._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return hook;\n}\n\nfunction getOrCreateSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorHook<T> | undefined;\n if (existing) {\n if (existing._source !== source || existing._equals !== equals) {\n detachSelectorHookBinding(existing);\n attachSelectorHookBinding(existing, source, equals);\n } else {\n ensureSelectorHookBinding(existing);\n }\n return existing;\n }\n\n const created = createSelectorHook(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorHook<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const hook = getOrCreateSelectorHook(instance, hookIndex, source, equals);\n if (!hook._record) {\n throw new Error('selector() record binding was not established.');\n }\n\n if (!hook._record._hasValue) {\n // Initialize the shared source once so downstream selectors can subscribe,\n // but do not consume a pending dirty state on later renders.\n recomputeSelectorSourceRecord(hook._record, false);\n }\n return hook;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { addPerfDuration, incrementPerfMetric } from "../runtime/perf-metrics.js";
|
|
2
|
+
import "../runtime/index.js";
|
|
2
3
|
import { resolveRouteDescriptor } from "./route-utils.js";
|
|
3
4
|
import { resolveSsgData, resolveSsgRouteData, validateRoutes } from "./resolve-ssg-data.js";
|
|
4
5
|
import { batchRenderRoutes } from "./batch-render.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport type { RouteRegistry } from '../common/router';\nimport {\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport { resolveRouteDescriptor } from './route-utils';\nimport {\n collectRemovedRouteResults,\n dedupeStrings,\n getRoutesToRender,\n selectRouteForGeneration,\n type SelectedRoute,\n} from './generation-plan';\nimport { normalizeStaticRoutes, splitStaticRoutes } from './static-routes';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime/perf-metrics';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ntype StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> =\n | {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n registry?: never;\n }\n | {\n registry: RouteRegistry;\n routes?: never;\n };\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> &\n StaticGenRouteSource<TRoutes>\n) {\n let result: SSGResult | null = null;\n const configuredRoutes = normalizeStaticRoutes(options);\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (configuredRoutes.length === 0) {\n throw new Error('routes array or route registry is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const splitRoutes = await splitStaticRoutes(configuredRoutes);\n const routes = splitRoutes.routes;\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n for (const runtimeRoute of splitRoutes.runtimeOnly) {\n routeResultsById.set(runtimeRoute.routeId, runtimeRoute.result);\n }\n const eligibleDescriptors = descriptors;\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (const routeId of splitRoutes.outputRouteIds) {\n const routeResult = routeResultsById.get(routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: configuredRoutes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAyEA,SAAS,mBAAmB,WAAgD;CAC1E,IAAI,cAAc,QAChB,OAAO,KAAK,IAAI,GAAG,aAAa,CAAC;CAGnC,MAAM,iBAAiB;CAKvB,MAAM,aAAa,OACjB,eAAe,SAAS,KAAK,oBAC3B,eAAe,SAAS,KAAK,wBAC7B,eAAe,SAAS,KAAK,kBACjC;CACA,IAAI,OAAO,SAAS,UAAU,KAAK,aAAa,GAC9C,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,CAAC;CAG3C,IAAI,OAAO,eAAe,WAAW,wBAAwB,UAC3D,OAAO,KAAK,IAAI,GAAG,eAAe,UAAU,mBAAmB;CAGjE,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,gBAGd,SAEA;CACA,IAAI,SAA2B;CAC/B,MAAM,mBAAmB,sBAAsB,OAAO;CACtD,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,sBAAsB,mBAAmB,QAAQ,WAAW;CAClE,MAAM,sBAAsB,KAAK,IAC/B,GACA,QAAQ,eAAe,mBACzB;CAEA,IAAI,iBAAiB,WAAW,GAC9B,MAAM,IAAI,MAAM,4CAA4C;CAG9D,IAAI,CAAC,QAAQ,aAAa,QAAQ,UAAU,KAAK,CAAC,CAAC,WAAW,GAC5D,MAAM,IAAI,MAAM,uBAAuB;CAGzC,OAAO;;;;;;EAML,MAAM,SACJ,kBAAsC,CAAC,GACnB;GACpB,MAAM,cAAc,MAAM,kBAAkB,gBAAgB;GAC5D,MAAM,SAAS,YAAY;GAC3B,eAAe,MAAM;GAErB,MAAM,cAAc,cAAc,gBAAgB,WAAW;GAC7D,MAAM,gBAAgB,cAAc,gBAAgB,aAAa;GACjE,MAAM,gBAAgB,gBAAgB,QAAQ;GAC9C,MAAM,mBACJ,CAAC,gBAAgB,aAAa,kBAAkB,gBAC5C,wBAAwB,QAAQ,WAAW,IAAI,IAC/C;GACN,MAAM,gBACJ,gBAAgB,aAChB,kBAAkB,iBAClB,qBAAqB,OACjB,SACA;GAGN,MAAM,UAAU,eAAe,QAAQ,EACrC,eAAe,QAAQ,cACzB,CAAC;GAED,MAAM,cAAc,OAAO,IAAI,sBAAsB;GACrD,MAAM,mCAAmB,IAAI,IAA+B;GAC5D,KAAK,MAAM,gBAAgB,YAAY,aACrC,iBAAiB,IAAI,aAAa,SAAS,aAAa,MAAM;GAEhE,MAAM,sBAAsB;GAE5B,MAAM,kBAAkB,IAAI,KACzB,kBAAkB,UAAU,CAAC,EAAA,CAAG,KAAK,UAAU,CAAC,MAAM,SAAS,KAAK,CAAC,CACxE;GACA,MAAM,kBAAkB,IAAI,IAC1B,oBAAoB,KAAK,eAAe,WAAW,OAAO,CAC5D;GAEA,MAAM,WAA4B,CAAC;GACnC,MAAM,iBAAkC,CAAC;GACzC,KAAK,IAAI,QAAQ,GAAG,QAAQ,oBAAoB,QAAQ,SAAS,GAAG;IAClE,MAAM,aAAa,oBAAoB;IACvC,MAAM,QAAQ,yBACZ,YACA,gBAAgB,IAAI,WAAW,OAAO,KAAK,MAC3C,eACA,aACA,aACF;IACA,SAAS,KAAK,KAAK;IACnB,IAAI,MAAM,WAAW,aACnB,eAAe,KAAK,KAAK;GAE7B;GACA,MAAM,kBAAkB,YAAY,IAAI;GACxC,oBAAoB,kBAAkB,mBAAmB;GACzD,MAAM,kBACJ,eAAe,SAAS,IACpB,MAAM,kBAAkB,kBAAkB,cAAc,GAAG;IACzD;IACA;IACA,aAAa;IACb,UAAU,QAAQ;GACpB,CAAC,IACD,CAAC;GACP,gBAAgB,mBAAmB,YAAY,IAAI,IAAI,eAAe;GACtE,MAAM,oCAAoB,IAAI,IAA+B;GAC7D,KAAK,IAAI,QAAQ,GAAG,QAAQ,gBAAgB,QAAQ,SAAS,GAC3D,kBAAkB,IAChB,eAAe,MAAM,CAAC,WAAW,SACjC,gBAAgB,MAClB;GAGF,IAAI,YAAY;GAChB,MAAM,qBAAsD,CAAC;GAE7D,KAAK,MAAM,SAAS,UAAU;IAC5B,MAAM,EAAE,YAAY,UAAU,WAAW;IACzC,MAAM,eAAe,oBACnB,SACA,WAAW,MAAM,MACjB,WAAW,IACb;IACA,MAAM,WAAW,aAAa,UAAU,aAAa,OAAO;IAC5D,MAAM,gBACJ,aAAa,WAAW,WAAW,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS;IAEpE,IAAI,WAAW,aAAa;KAC1B,iBAAiB,IAAI,WAAW,SAAS;MACvC,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,MAAM;MACN,UACE,UAAU,aAAa,QAAQ,aAAa,OACxC,0BACE,QAAQ,WACR,WAAW,QACb,IACA;MACN,gBAAgB;MAChB;MACA,QAAQ;MACR,QAAQ;MACR,SAAS;KACX,CAAC;KAED,IAAI,UACF,mBAAmB,KAAK;MACtB,GAAG;MACH,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,kBAAkB,WAAW,iBAAiB,MAAM;KACtD,CAAC;KAEH;IACF;IAEA,MAAM,WAAW,kBAAkB,IAAI,WAAW,OAAO;IACzD,IAAI,CAAC,UACH,MAAM,IAAI,MACR,sCAAsC,WAAW,KAAK,EACxD;IAGF,MAAM,aAAgC;KACpC,GAAG;KACH,MAAM,WAAW;KACjB,UAAU,WAAW;KACrB;KACA;KACA,SAAS;IACX;IAEA,IAAI,WAAW,WAAW,WAAW;KACnC,MAAM,aAAa,SAAS,WAAW,IAAI;KAC3C,MAAM,cACJ,kBAAkB,UAClB,CAAC,YACD,SAAS,aAAa,cACtB,CAAC,iBAAiB,QAAQ,WAAW,WAAW,QAAQ;KAE1D,WAAW,UAAU;KACrB,IAAI,CAAC,aACH,aAAa;KAGf,mBAAmB,KAAK;MACtB,SAAS,WAAW;MACpB,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,kBAAkB,WAAW,iBAAiB,MAAM;MACpD,UAAU;MACV,YAAY;KACd,CAAC;IACH,OACE,mBAAmB,KAAK;KACtB,SAAS,WAAW;KACpB,MAAM,WAAW;KACjB,UAAU,WAAW;KACrB,kBAAkB,WAAW,iBAAiB,MAAM;KACpD,UAAU,UAAU,YAAY;KAChC,YAAY;IACd,CAAC;IAGH,iBAAiB,IAAI,WAAW,SAAS,UAAU;GACrD;GAEA,MAAM,iBAAiB,2BACrB,kBACA,eACF;GACA,MAAM,eAAoC,CAAC;GAC3C,KAAK,MAAM,WAAW,YAAY,gBAAgB;IAChD,MAAM,cAAc,iBAAiB,IAAI,OAAO;IAChD,IAAI,aACF,aAAa,KAAK,WAAW;GAEjC;GACA,aAAa,KAAK,GAAG,cAAc;GAGnC,MAAM,iBAAiB,YAAY,IAAI;GACvC,MAAM,iBAAiB,cAAc,QAAQ,WAAW,EACtD,aAAa,oBACf,CAAC;GACD,gBAAgB,kBAAkB,YAAY,IAAI,IAAI,cAAc;GAGpE,SAAS,kBAAkB,cAAc;IACvC,MAAM;IACN;IACA,iBAAiB;IACjB,mBAAmB;GACrB,CAAC;GAID,MAAM,cADW,iBAAiB,MACd,GAAU,QAAQ,SAAS;GAE/C,MAAM,yBACJ;IACE,eAAA;IACA;IACA,MAAM;IACN,QAAQ;GACV,GACA,QAAQ,SACV;GAEA,OAAO;EACT;;;;EAKA,YAAY;GACV,OAAO;IACL,YAAY,iBAAiB;IAC7B,WAAW,QAAQ;IACnB;IACA,aAAa;IACb,aAAa;IACb,kBAAkB,CAAC,CAAC,QAAQ;GAC9B;EACF;;;;;EAMA,YAA8B;GAC5B,OAAO;EACT;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport type { RouteRegistry } from '../common/router';\nimport {\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport { resolveRouteDescriptor } from './route-utils';\nimport {\n collectRemovedRouteResults,\n dedupeStrings,\n getRoutesToRender,\n selectRouteForGeneration,\n type SelectedRoute,\n} from './generation-plan';\nimport { normalizeStaticRoutes, splitStaticRoutes } from './static-routes';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ntype StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> =\n | {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n registry?: never;\n }\n | {\n registry: RouteRegistry;\n routes?: never;\n };\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> &\n StaticGenRouteSource<TRoutes>\n) {\n let result: SSGResult | null = null;\n const configuredRoutes = normalizeStaticRoutes(options);\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (configuredRoutes.length === 0) {\n throw new Error('routes array or route registry is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const splitRoutes = await splitStaticRoutes(configuredRoutes);\n const routes = splitRoutes.routes;\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n for (const runtimeRoute of splitRoutes.runtimeOnly) {\n routeResultsById.set(runtimeRoute.routeId, runtimeRoute.result);\n }\n const eligibleDescriptors = descriptors;\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (const routeId of splitRoutes.outputRouteIds) {\n const routeResult = routeResultsById.get(routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: configuredRoutes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { _getBuiltInRoutePolicy } from "../router/policy.js";
|
|
2
|
+
import "../router/route.js";
|
|
2
3
|
import { getOutputFilePath, interpolateRoutePath, resolveRouteDescriptor } from "./route-utils.js";
|
|
3
4
|
import { expandRoutes } from "./resolve-ssg-data.js";
|
|
4
5
|
//#region src/ssg/static-routes.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-routes.js","names":[],"sources":["../../src/ssg/static-routes.ts"],"sourcesContent":["/**\n * SSG route source normalization and runtime-only filtering.\n */\n\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RoutePolicy, RouteRegistry } from '../common/router';\nimport { _getBuiltInRoutePolicy } from '../router/
|
|
1
|
+
{"version":3,"file":"static-routes.js","names":[],"sources":["../../src/ssg/static-routes.ts"],"sourcesContent":["/**\n * SSG route source normalization and runtime-only filtering.\n */\n\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RoutePolicy, RouteRegistry } from '../common/router';\nimport { _getBuiltInRoutePolicy } from '../router/route';\nimport { expandRoutes } from './resolve-ssg-data';\nimport {\n getOutputFilePath,\n interpolateRoutePath,\n resolveRouteDescriptor,\n} from './route-utils';\n\ntype StaticRouteSource = {\n registry?: RouteRegistry;\n routes?: readonly RouteConfig[];\n};\n\nexport type RuntimeOnlyRoute = {\n routeId: string;\n result: RouteRenderResult;\n};\n\nexport interface SplitStaticRoutesResult {\n routes: RouteConfig[];\n runtimeOnly: RuntimeOnlyRoute[];\n outputRouteIds: string[];\n}\n\nfunction getRuntimeOnlyDiagnostic(\n route: RouteConfig,\n path: string\n): string | null {\n const policies = route.policies ?? [];\n\n if (route.auth === true) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (route.role) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (route.permission) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n if (policies.length > 0) {\n let hasAuthPolicy = false;\n let hasRolePolicy = false;\n let hasPermissionPolicy = false;\n\n for (const policy of policies) {\n const metadata = _getBuiltInRoutePolicy(policy);\n if (!metadata) {\n return `Skipped prerender for \"${path}\": routes with custom policies are runtime-only by default.`;\n }\n\n if (metadata.kind === 'auth') {\n hasAuthPolicy = true;\n } else if (metadata.kind === 'role') {\n hasRolePolicy = true;\n } else if (metadata.kind === 'permission') {\n hasPermissionPolicy = true;\n }\n }\n\n if (hasAuthPolicy) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (hasRolePolicy) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (hasPermissionPolicy) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n return null;\n }\n\n return null;\n}\n\nfunction getRouteResultPath(route: RouteConfig): string {\n return route.params\n ? interpolateRoutePath(route.path, route.params)\n : route.path;\n}\n\nfunction createRuntimeOnlyRoute(\n route: RouteConfig,\n diagnostic: string\n): RuntimeOnlyRoute {\n const path = getRouteResultPath(route);\n const filePath = getOutputFilePath(path);\n\n return {\n routeId: `${path}::${filePath}`,\n result: {\n path,\n filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'skipped',\n reason: 'runtime-only',\n written: false,\n error: diagnostic,\n },\n };\n}\n\nexport async function splitStaticRoutes(\n routes: readonly RouteConfig[]\n): Promise<SplitStaticRoutesResult> {\n const prerenderableRoutes: RouteConfig[] = [];\n const runtimeOnly: RuntimeOnlyRoute[] = [];\n const outputRouteIds: string[] = [];\n\n for (const route of routes) {\n const routePath = getRouteResultPath(route);\n const diagnostic = getRuntimeOnlyDiagnostic(route, routePath);\n if (diagnostic) {\n const runtimeRoute = createRuntimeOnlyRoute(route, diagnostic);\n runtimeOnly.push(runtimeRoute);\n outputRouteIds.push(runtimeRoute.routeId);\n continue;\n }\n\n const expanded = await expandRoutes([route]);\n prerenderableRoutes.push(...expanded);\n for (const expandedRoute of expanded) {\n outputRouteIds.push(resolveRouteDescriptor(expandedRoute).routeId);\n }\n }\n\n return {\n routes: prerenderableRoutes,\n runtimeOnly,\n outputRouteIds,\n };\n}\n\nexport function normalizeStaticRoutes(\n options: StaticRouteSource\n): RouteConfig[] {\n if (options.registry) {\n return routeRegistryToRouteConfigs(options.registry);\n }\n\n return [...(options.routes ?? [])];\n}\n\nfunction routeRegistryToRouteConfigs(registry: RouteRegistry): RouteConfig[] {\n const routeConfigs: RouteConfig[] = [];\n\n for (const record of registry.manifest.records) {\n if (record.isFallback) {\n continue;\n }\n\n routeConfigs.push({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n auth: record.options.auth,\n role: record.options.role,\n permission: record.options.permission,\n policies: stripRegistryGuestPolicies(record.options.policies),\n entries: record.options.entries,\n });\n }\n\n return routeConfigs;\n}\n\nfunction stripRegistryGuestPolicies(\n policies: readonly RoutePolicy[] | undefined\n): readonly RoutePolicy[] | undefined {\n if (!policies || policies.length === 0) {\n return undefined;\n }\n\n const filtered = policies.filter(\n (policy) => _getBuiltInRoutePolicy(policy)?.kind !== 'guest'\n );\n\n return filtered.length > 0 ? filtered : undefined;\n}\n"],"mappings":";;;;;AA8BA,SAAS,yBACP,OACA,MACe;CACf,MAAM,WAAW,MAAM,YAAY,CAAC;CAEpC,IAAI,MAAM,SAAS,MACjB,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,MACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,YACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,SAAS,SAAS,GAAG;EACvB,IAAI,gBAAgB;EACpB,IAAI,gBAAgB;EACpB,IAAI,sBAAsB;EAE1B,KAAK,MAAM,UAAU,UAAU;GAC7B,MAAM,WAAW,uBAAuB,MAAM;GAC9C,IAAI,CAAC,UACH,OAAO,0BAA0B,KAAK;GAGxC,IAAI,SAAS,SAAS,QACpB,gBAAgB;QACX,IAAI,SAAS,SAAS,QAC3B,gBAAgB;QACX,IAAI,SAAS,SAAS,cAC3B,sBAAsB;EAE1B;EAEA,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,qBACF,OAAO,0BAA0B,KAAK;EAGxC,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAA4B;CACtD,OAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,MAAM,MAAM,IAC7C,MAAM;AACZ;AAEA,SAAS,uBACP,OACA,YACkB;CAClB,MAAM,OAAO,mBAAmB,KAAK;CACrC,MAAM,WAAW,kBAAkB,IAAI;CAEvC,OAAO;EACL,SAAS,GAAG,KAAK,IAAI;EACrB,QAAQ;GACN;GACA;GACA,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,eAAe;GACf,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,OAAO;EACT;CACF;AACF;AAEA,eAAsB,kBACpB,QACkC;CAClC,MAAM,sBAAqC,CAAC;CAC5C,MAAM,cAAkC,CAAC;CACzC,MAAM,iBAA2B,CAAC;CAElC,KAAK,MAAM,SAAS,QAAQ;EAE1B,MAAM,aAAa,yBAAyB,OAD1B,mBAAmB,KACc,CAAS;EAC5D,IAAI,YAAY;GACd,MAAM,eAAe,uBAAuB,OAAO,UAAU;GAC7D,YAAY,KAAK,YAAY;GAC7B,eAAe,KAAK,aAAa,OAAO;GACxC;EACF;EAEA,MAAM,WAAW,MAAM,aAAa,CAAC,KAAK,CAAC;EAC3C,oBAAoB,KAAK,GAAG,QAAQ;EACpC,KAAK,MAAM,iBAAiB,UAC1B,eAAe,KAAK,uBAAuB,aAAa,CAAC,CAAC,OAAO;CAErE;CAEA,OAAO;EACL,QAAQ;EACR;EACA;CACF;AACF;AAEA,SAAgB,sBACd,SACe;CACf,IAAI,QAAQ,UACV,OAAO,4BAA4B,QAAQ,QAAQ;CAGrD,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,CAAE;AACnC;AAEA,SAAS,4BAA4B,UAAwC;CAC3E,MAAM,eAA8B,CAAC;CAErC,KAAK,MAAM,UAAU,SAAS,SAAS,SAAS;EAC9C,IAAI,OAAO,YACT;EAGF,aAAa,KAAK;GAChB,MAAM,OAAO;GACb,SAAS,OAAO;GAChB,WAAW,OAAO,QAAQ;GAC1B,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,YAAY,OAAO,QAAQ;GAC3B,UAAU,2BAA2B,OAAO,QAAQ,QAAQ;GAC5D,SAAS,OAAO,QAAQ;EAC1B,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,2BACP,UACoC;CACpC,IAAI,CAAC,YAAY,SAAS,WAAW,GACnC;CAGF,MAAM,WAAW,SAAS,QACvB,WAAW,uBAAuB,MAAM,CAAC,EAAE,SAAS,OACvD;CAEA,OAAO,SAAS,SAAS,IAAI,WAAW;AAC1C"}
|
package/dist/ssr/boundaries.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __CONTROL_BOUNDARY__ } from "../common/control.js";
|
|
2
2
|
import { ELEMENT_TYPE } from "../common/jsx.js";
|
|
3
|
-
import { evaluateForState } from "../runtime/for-internal.js";
|
|
4
|
-
import "../runtime/for.js";
|
|
5
3
|
import { evaluateCaseState, evaluateShowState } from "../runtime/control.js";
|
|
4
|
+
import { evaluateForState } from "../runtime/for-internal.js";
|
|
5
|
+
import "../runtime/index.js";
|
|
6
6
|
import "../jsx/index.js";
|
|
7
7
|
//#region src/ssr/boundaries.ts
|
|
8
8
|
function normalizeRenderableChildren(value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boundaries.js","names":[],"sources":["../../src/ssr/boundaries.ts"],"sourcesContent":["/**\n * Shared SSR boundary state and renderable child helpers.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { ELEMENT_TYPE } from '../jsx';\nimport type { ComponentInstance } from '../runtime
|
|
1
|
+
{"version":3,"file":"boundaries.js","names":[],"sources":["../../src/ssr/boundaries.ts"],"sourcesContent":["/**\n * Shared SSR boundary state and renderable child helpers.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { ELEMENT_TYPE } from '../jsx';\nimport type { ComponentInstance } from '../runtime';\nimport {\n type ControlBoundaryState,\n evaluateCaseState,\n evaluateShowState,\n} from '../runtime';\nimport { evaluateForState } from '../runtime';\nimport type { VNode } from './types';\n\ntype ErrorBoundaryState = NonNullable<ComponentInstance['errorBoundaryState']>;\n\nexport function normalizeRenderableChildren(value: unknown): unknown[] {\n if (value === null || value === undefined || value === false) {\n return [];\n }\n\n return Array.isArray(value) ? value : [value];\n}\n\nexport function getRenderableChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (Array.isArray((node as VNode).children)) {\n return (node as VNode).children;\n }\n if (Array.isArray(node.props?.children)) {\n return node.props.children as unknown[];\n }\n if (\n node.props?.children !== undefined &&\n node.props.children !== null &&\n node.props.children !== false\n ) {\n return [node.props.children];\n }\n return undefined;\n}\n\nexport function getErrorBoundaryState(\n node: VNode | JSXElement\n): ErrorBoundaryState | null {\n return (\n (node as DOMElement & { __instance?: ComponentInstance }).__instance\n ?.errorBoundaryState ?? null\n );\n}\n\nexport function resetErrorBoundaryState(node: VNode | JSXElement): void {\n const instance = (node as DOMElement & { __instance?: ComponentInstance })\n .__instance;\n const state = instance?.errorBoundaryState;\n if (state) {\n state.error = null;\n state.notified = false;\n }\n}\n\nexport function createErrorBoundaryReset(node: VNode | JSXElement): () => void {\n return () => resetErrorBoundaryState(node);\n}\n\nfunction createDefaultErrorBoundaryFallbackVNode(error: unknown): JSXElement {\n const message =\n error instanceof Error\n ? error.stack || error.message || error.name\n : typeof error === 'string'\n ? error\n : (() => {\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n })();\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: 'div',\n props: {\n role: 'alert',\n 'data-askr-error-boundary': 'true',\n style: {\n boxSizing: 'border-box',\n padding: '1rem',\n border: '1px solid currentColor',\n borderRadius: '0.75rem',\n display: 'grid',\n gap: '0.75rem',\n maxWidth: '100%',\n },\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'strong',\n props: {\n children: ['Something went wrong while rendering this view.'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'p',\n props: {\n style: { margin: '0' },\n children: [\n 'The app recovered into a visible fallback so the error is not hidden in the console.',\n ],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'details',\n props: {\n open: process.env.NODE_ENV !== 'production',\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'summary',\n props: {\n children: ['Error details'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'pre',\n props: {\n style: {\n margin: '0',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n },\n children: [message],\n },\n },\n ],\n },\n },\n ],\n },\n key: null,\n } as JSXElement;\n}\n\nexport function resolveErrorBoundaryFallbackNode(\n fallback: unknown,\n error: unknown,\n reset: () => void\n): unknown {\n return typeof fallback === 'function'\n ? (fallback as (error: unknown, reset: () => void) => unknown)(error, reset)\n : fallback !== undefined\n ? fallback\n : createDefaultErrorBoundaryFallbackVNode(error);\n}\n\nexport function getControlBoundaryState(\n node: VNode | JSXElement\n): ControlBoundaryState | null {\n const boundaryNode = node as DOMElement;\n\n return (\n boundaryNode._controlState ??\n (boundaryNode._forState as ControlBoundaryState | undefined) ??\n null\n );\n}\n\nexport function evaluateControlBoundaryChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (node.type !== __CONTROL_BOUNDARY__) {\n return undefined;\n }\n\n const controlState = getControlBoundaryState(node);\n if (!controlState) {\n return [];\n }\n\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n return evaluateCaseState(controlState);\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,4BAA4B,OAA2B;CACrE,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,OACrD,OAAO,CAAC;CAGV,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,SAAgB,sBACd,MACuB;CACvB,IAAI,MAAM,QAAS,KAAe,QAAQ,GACxC,OAAQ,KAAe;CAEzB,IAAI,MAAM,QAAQ,KAAK,OAAO,QAAQ,GACpC,OAAO,KAAK,MAAM;CAEpB,IACE,KAAK,OAAO,aAAa,UACzB,KAAK,MAAM,aAAa,QACxB,KAAK,MAAM,aAAa,OAExB,OAAO,CAAC,KAAK,MAAM,QAAQ;AAG/B;AAEA,SAAgB,sBACd,MAC2B;CAC3B,OACG,KAAyD,YACtD,sBAAsB;AAE9B;AAEA,SAAgB,wBAAwB,MAAgC;CAGtE,MAAM,QAFY,KACf,YACqB;CACxB,IAAI,OAAO;EACT,MAAM,QAAQ;EACd,MAAM,WAAW;CACnB;AACF;AAEA,SAAgB,yBAAyB,MAAsC;CAC7E,aAAa,wBAAwB,IAAI;AAC3C;AAEA,SAAS,wCAAwC,OAA4B;CAC3E,MAAM,UACJ,iBAAiB,QACb,MAAM,SAAS,MAAM,WAAW,MAAM,OACtC,OAAO,UAAU,WACf,eACO;EACL,IAAI;GACF,OAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;GACN,OAAO,OAAO,KAAK;EACrB;CACF,EAAA,CAAG;CAEX,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO;GACL,MAAM;GACN,4BAA4B;GAC5B,OAAO;IACL,WAAW;IACX,SAAS;IACT,QAAQ;IACR,cAAc;IACd,SAAS;IACT,KAAK;IACL,UAAU;GACZ;GACA,UAAU;IACR;KACE,UAAU;KACV,MAAM;KACN,OAAO,EACL,UAAU,CAAC,iDAAiD,EAC9D;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,OAAO,EAAE,QAAQ,IAAI;MACrB,UAAU,CACR,sFACF;KACF;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,MAAA;MACA,UAAU,CACR;OACE,UAAU;OACV,MAAM;OACN,OAAO,EACL,UAAU,CAAC,eAAe,EAC5B;MACF,GACA;OACE,UAAU;OACV,MAAM;OACN,OAAO;QACL,OAAO;SACL,QAAQ;SACR,YAAY;SACZ,WAAW;QACb;QACA,UAAU,CAAC,OAAO;OACpB;MACF,CACF;KACF;IACF;GACF;EACF;EACA,KAAK;CACP;AACF;AAEA,SAAgB,iCACd,UACA,OACA,OACS;CACT,OAAO,OAAO,aAAa,aACtB,SAA4D,OAAO,KAAK,IACzE,aAAa,SACX,WACA,wCAAwC,KAAK;AACrD;AAEA,SAAgB,wBACd,MAC6B;CAC7B,MAAM,eAAe;CAErB,OACE,aAAa,iBACZ,aAAa,aACd;AAEJ;AAEA,SAAgB,gCACd,MACuB;CACvB,IAAI,KAAK,SAAS,sBAChB;CAGF,MAAM,eAAe,wBAAwB,IAAI;CACjD,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,IAAI,aAAa,SAAS,OACxB,OAAO,iBAAiB,YAAY;CAEtC,IAAI,aAAa,SAAS,QACxB,OAAO,kBAAkB,YAAY;CAEvC,OAAO,kBAAkB,YAAY;AACvC"}
|
|
@@ -3,8 +3,8 @@ import { getCurrentComponentInstance, setCurrentComponentInstance } from "../run
|
|
|
3
3
|
import { cleanupComponent } from "../runtime/component-cleanup.js";
|
|
4
4
|
import { isPromiseLike } from "../common/promise.js";
|
|
5
5
|
import { createComponentInstance } from "../runtime/component-internal.js";
|
|
6
|
-
import "../runtime/
|
|
7
|
-
import
|
|
6
|
+
import { DefaultPortal, disposeDefaultPortalScope } from "../runtime/portal.js";
|
|
7
|
+
import "../runtime/index.js";
|
|
8
8
|
import "../jsx/index.js";
|
|
9
9
|
import { throwSSRDataMissing } from "./context.js";
|
|
10
10
|
//#region src/ssr/component-runtime.ts
|
|
@@ -87,7 +87,7 @@ function wrapWithDefaultPortal(out) {
|
|
|
87
87
|
const portalVNode = {
|
|
88
88
|
$$typeof: ELEMENT_TYPE,
|
|
89
89
|
type: DefaultPortal,
|
|
90
|
-
props: {},
|
|
90
|
+
props: { __askrAutoDefaultPortal: true },
|
|
91
91
|
key: "__default_portal"
|
|
92
92
|
};
|
|
93
93
|
if (out == null) return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-runtime.js","names":[],"sources":["../../src/ssr/component-runtime.ts"],"sourcesContent":["/**\n * SSR component execution and temporary owner lifecycle.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport { isPromiseLike } from '../common/promise';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport {
|
|
1
|
+
{"version":3,"file":"component-runtime.js","names":[],"sources":["../../src/ssr/component-runtime.ts"],"sourcesContent":["/**\n * SSR component execution and temporary owner lifecycle.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport { isPromiseLike } from '../common/promise';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport {\n cleanupComponent,\n createComponentInstance,\n DefaultPortal,\n disposeDefaultPortalScope,\n getCurrentComponentInstance,\n setCurrentComponentInstance,\n} from '../runtime';\nimport { throwSSRDataMissing, type RenderContext } from './context';\nimport type { SSRComponent, VNode } from './types';\n\nexport type Component = SSRComponent;\n\nconst __ssrGuardStack: Array<{ random: () => number; now: () => number }> = [];\n\nfunction pushSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n __ssrGuardStack.push({\n random: Reflect.get(Math, 'random') as () => number,\n now: Reflect.get(Date, 'now') as () => number,\n });\n Reflect.set(Math, 'random', () => {\n throw new Error(\n 'SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.'\n );\n });\n Reflect.set(Date, 'now', () => {\n throw new Error(\n 'SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.'\n );\n });\n}\n\nfunction popSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n const prev = __ssrGuardStack.pop();\n if (prev) {\n Reflect.set(Math, 'random', prev.random);\n Reflect.set(Date, 'now', prev.now);\n }\n}\n\nexport function executeComponentSync(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n try {\n if (process.env.NODE_ENV !== 'production') {\n pushSSRStrictPurityGuard();\n }\n const prev = getCurrentComponentInstance();\n const temp = createComponentInstance(\n 'ssr-temp',\n component as ComponentFunction,\n (props || {}) as Props,\n null\n );\n temp.ssr = true;\n temp.portalScope = temp;\n ctx.ssrCleanupFns.push(() => {\n let cleanupError: unknown = null;\n\n try {\n cleanupComponent(temp);\n } catch (error) {\n cleanupError = error;\n }\n\n try {\n disposeDefaultPortalScope(temp);\n } catch (error) {\n if (cleanupError) {\n throw new AggregateError(\n [cleanupError, error],\n 'SSR temporary owner cleanup failed'\n );\n }\n throw error;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n });\n setCurrentComponentInstance(temp);\n try {\n const result = component((props || {}) as Props, { ssr: ctx });\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n if (\n typeof result === 'string' ||\n typeof result === 'number' ||\n typeof result === 'boolean' ||\n result === null ||\n result === undefined\n ) {\n const inner =\n result === null || result === undefined || result === false\n ? ''\n : String(result);\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: inner ? [inner] : [] },\n } as unknown as VNode | JSXElement;\n }\n return result as VNode | JSXElement;\n } finally {\n setCurrentComponentInstance(prev);\n }\n } finally {\n if (process.env.NODE_ENV !== 'production') popSSRStrictPurityGuard();\n }\n}\n\nexport function disposeSSRTemporaryOwners(ctx: RenderContext): void {\n const cleanupFns = ctx.ssrCleanupFns;\n ctx.ssrCleanupFns = [];\n const cleanupErrors: unknown[] = [];\n\n for (let index = cleanupFns.length - 1; index >= 0; index -= 1) {\n try {\n cleanupFns[index]();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(\n cleanupErrors,\n 'SSR temporary owner cleanup failed'\n );\n }\n}\n\nfunction wrapWithDefaultPortal(out: unknown): VNode | JSXElement {\n if (isPromiseLike(out)) {\n throwSSRDataMissing();\n }\n\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: { __askrAutoDefaultPortal: true },\n key: '__default_portal',\n } as unknown;\n\n if (out == null) {\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [portalVNode] },\n } as unknown as VNode | JSXElement;\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [out as unknown, portalVNode] },\n } as unknown as VNode | JSXElement;\n}\n\nexport function renderSyncComponentRoot(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n const wrapped: Component = (\n p?: Record<string, unknown>,\n c?: { signal?: AbortSignal; ssr?: RenderContext }\n ) => wrapWithDefaultPortal(component(p ?? {}, c));\n\n return executeComponentSync(wrapped, props || {}, ctx);\n}\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,kBAAsE,CAAC;AAE7E,SAAS,2BAA2B;CAGlC,gBAAgB,KAAK;EACnB,QAAQ,QAAQ,IAAI,MAAM,QAAQ;EAClC,KAAK,QAAQ,IAAI,MAAM,KAAK;CAC9B,CAAC;CACD,QAAQ,IAAI,MAAM,gBAAgB;EAChC,MAAM,IAAI,MACR,mHACF;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,aAAa;EAC7B,MAAM,IAAI,MACR,6HACF;CACF,CAAC;AACH;AAEA,SAAS,0BAA0B;CAGjC,MAAM,OAAO,gBAAgB,IAAI;CACjC,IAAI,MAAM;EACR,QAAQ,IAAI,MAAM,UAAU,KAAK,MAAM;EACvC,QAAQ,IAAI,MAAM,OAAO,KAAK,GAAG;CACnC;AACF;AAEA,SAAgB,qBACd,WACA,OACA,KACoB;CACpB,IAAI;EAEA,yBAAyB;EAE3B,MAAM,OAAO,4BAA4B;EACzC,MAAM,OAAO,wBACX,YACA,WACC,SAAS,CAAC,GACX,IACF;EACA,KAAK,MAAM;EACX,KAAK,cAAc;EACnB,IAAI,cAAc,WAAW;GAC3B,IAAI,eAAwB;GAE5B,IAAI;IACF,iBAAiB,IAAI;GACvB,SAAS,OAAO;IACd,eAAe;GACjB;GAEA,IAAI;IACF,0BAA0B,IAAI;GAChC,SAAS,OAAO;IACd,IAAI,cACF,MAAM,IAAI,eACR,CAAC,cAAc,KAAK,GACpB,oCACF;IAEF,MAAM;GACR;GAEA,IAAI,cACF,MAAM;EAEV,CAAC;EACD,4BAA4B,IAAI;EAChC,IAAI;GACF,MAAM,SAAS,UAAW,SAAS,CAAC,GAAa,EAAE,KAAK,IAAI,CAAC;GAC7D,IAAI,cAAc,MAAM,GACtB,oBAAoB;GAEtB,IACE,OAAO,WAAW,YAClB,OAAO,WAAW,YAClB,OAAO,WAAW,aAClB,WAAW,QACX,WAAW,QACX;IACA,MAAM,QACJ,WAAW,QAAQ,WAAW,UAAa,WAAW,QAClD,KACA,OAAO,MAAM;IACnB,OAAO;KACL,UAAU;KACV,MAAM;KACN,OAAO,EAAE,UAAU,QAAQ,CAAC,KAAK,IAAI,CAAC,EAAE;IAC1C;GACF;GACA,OAAO;EACT,UAAU;GACR,4BAA4B,IAAI;EAClC;CACF,UAAU;EACmC,wBAAwB;CACrE;AACF;AAEA,SAAgB,0BAA0B,KAA0B;CAClE,MAAM,aAAa,IAAI;CACvB,IAAI,gBAAgB,CAAC;CACrB,MAAM,gBAA2B,CAAC;CAElC,KAAK,IAAI,QAAQ,WAAW,SAAS,GAAG,SAAS,GAAG,SAAS,GAC3D,IAAI;EACF,WAAW,MAAM,CAAC;CACpB,SAAS,OAAO;EACd,cAAc,KAAK,KAAK;CAC1B;CAGF,IAAI,cAAc,WAAW,GAC3B,MAAM,cAAc;CAGtB,IAAI,cAAc,SAAS,GACzB,MAAM,IAAI,eACR,eACA,oCACF;AAEJ;AAEA,SAAS,sBAAsB,KAAkC;CAC/D,IAAI,cAAc,GAAG,GACnB,oBAAoB;CAGtB,MAAM,cAAc;EAClB,UAAU;EACV,MAAM;EACN,OAAO,EAAE,yBAAyB,KAAK;EACvC,KAAK;CACP;CAEA,IAAI,OAAO,MACT,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,WAAW,EAAE;CACnC;CAGF,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,KAAgB,WAAW,EAAE;CACnD;AACF;AAEA,SAAgB,wBACd,WACA,OACA,KACoB;CACpB,MAAM,WACJ,GACA,MACG,sBAAsB,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC;CAEhD,OAAO,qBAAqB,SAAS,SAAS,CAAC,GAAG,GAAG;AACvD"}
|
package/dist/ssr/render-sync.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __CONTROL_BOUNDARY__ } from "../common/control.js";
|
|
2
2
|
import { __ERROR_BOUNDARY__ } from "../common/vnode.js";
|
|
3
|
-
import { logger } from "../
|
|
3
|
+
import { logger } from "../common/logger.js";
|
|
4
4
|
import { Fragment } from "../common/jsx.js";
|
|
5
5
|
import "../jsx/index.js";
|
|
6
6
|
import { VOID_ELEMENTS, escapeText } from "./escape.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-sync.js","names":[],"sources":["../../src/ssr/render-sync.ts"],"sourcesContent":["import type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { __ERROR_BOUNDARY__ } from '../common/vnode';\nimport { Fragment } from '../jsx';\nimport { logger } from '../dev/logger';\nimport {\n createRenderContext,\n withRenderContext,\n type RenderContext,\n type SSRData,\n} from './context';\nimport {\n disposeSSRTemporaryOwners,\n executeComponentSync,\n renderSyncComponentRoot,\n type Component,\n} from './component-runtime';\nimport {\n createErrorBoundaryReset,\n evaluateControlBoundaryChildren,\n getErrorBoundaryState,\n getRenderableChildren,\n normalizeRenderableChildren,\n resolveErrorBoundaryFallbackNode,\n} from './boundaries';\nimport { renderAttrs, renderAttrsDirect } from './attrs';\nimport { VOID_ELEMENTS, escapeText } from './escape';\nimport { serializeHydrationRenderData } from './hydration-data';\nimport { startRenderPhase, stopRenderPhase } from './render-keys';\nimport type { RouteAppRenderInput } from './route-render';\nimport { StringSink } from './sink';\nimport type { VNode } from './types';\n\nconst __SSR_DEBUG =\n process.env.NODE_ENV !== 'production' &&\n (process.env.ASKR_SSR_DEBUG === '1' || process.env.ASKR_SSR_DEBUG === 'true');\n\nexport function inheritRenderableKey(\n source: VNode | JSXElement,\n result: VNode | JSXElement\n): VNode | JSXElement {\n const inheritedKey = (source as DOMElement).key;\n if (inheritedKey === undefined || inheritedKey === null) {\n return result;\n }\n\n if (!result || typeof result !== 'object' || !('type' in result)) {\n return result;\n }\n\n const resultVNode = result as DOMElement;\n if (resultVNode.key === undefined || resultVNode.key === null) {\n resultVNode.key = inheritedKey;\n }\n\n if (typeof resultVNode.type === 'string') {\n if (!resultVNode.props) {\n resultVNode.props = {};\n }\n\n if (resultVNode.props['data-key'] === undefined) {\n resultVNode.props['data-key'] = String(inheritedKey);\n }\n }\n\n return result;\n}\n\nfunction renderRenderableSync(value: unknown, ctx: RenderContext): string {\n if (typeof value === 'string') return escapeText(value);\n if (typeof value === 'number') return escapeText(String(value));\n if (value === null || value === undefined || value === false) return '';\n if (Array.isArray(value)) return renderChildrenSync(value, ctx);\n if (value && typeof value === 'object' && 'type' in value) {\n return renderNodeSync(value as VNode, ctx);\n }\n return '';\n}\n\nfunction renderChildSync(child: unknown, ctx: RenderContext): string {\n return renderRenderableSync(child, ctx);\n}\n\nexport function renderRenderableSyncToSink(\n value: unknown,\n sink: {\n write(html: string): void;\n write2?: (a: string, b: string) => void;\n write3?: (a: string, b: string, c: string) => void;\n },\n ctx: RenderContext\n): void {\n if (value === null || value === undefined || value === false) return;\n if (typeof value === 'string') {\n sink.write(escapeText(value));\n return;\n }\n if (typeof value === 'number') {\n sink.write(escapeText(String(value)));\n return;\n }\n if (Array.isArray(value)) {\n renderChildrenSyncToSink(value, sink, ctx);\n return;\n }\n if (value && typeof value === 'object' && 'type' in value) {\n renderNodeSyncToSink(value as VNode, sink, ctx);\n }\n}\n\nfunction renderChildSyncToSink(\n child: unknown,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n renderRenderableSyncToSink(child, sink, ctx);\n}\n\nfunction renderChildrenSync(\n children: unknown[] | undefined,\n ctx: RenderContext\n): string {\n if (!children || !Array.isArray(children) || children.length === 0) return '';\n if (children.length === 1) return renderChildSync(children[0], ctx);\n\n if (children.length <= 8) {\n let result = '';\n for (const child of children) result += renderChildSync(child, ctx);\n return result;\n }\n\n const parts = Array.from({ length: children.length }, (_, index) =>\n renderChildSync(children[index], ctx)\n );\n return parts.join('');\n}\n\nfunction renderErrorBoundaryFallbackValue(\n fallback: unknown,\n error: unknown,\n reset: () => void,\n ctx: RenderContext\n): string {\n const nextValue = resolveErrorBoundaryFallbackNode(fallback, error, reset);\n\n return Array.isArray(nextValue)\n ? renderChildrenSync(normalizeRenderableChildren(nextValue), ctx)\n : renderChildSync(nextValue, ctx);\n}\n\nfunction renderErrorBoundaryFallbackValueToSink(\n fallback: unknown,\n error: unknown,\n reset: () => void,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n sink.write(renderErrorBoundaryFallbackValue(fallback, error, reset, ctx));\n}\n\nfunction renderChildrenSyncToSink(\n children: unknown[] | undefined,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n if (!children || !Array.isArray(children) || children.length === 0) return;\n if (children.length >= 32) {\n for (let i = 0; i < children.length; i++) {\n renderRenderableSyncToSink(children[i], sink, ctx);\n }\n return;\n }\n for (let i = 0; i < children.length; i++) {\n renderChildSyncToSink(children[i], sink, ctx);\n }\n}\n\nfunction sinkWrite2(\n sink: { write(html: string): void; write2?: (a: string, b: string) => void },\n a: string,\n b: string\n): void {\n if (typeof sink.write2 === 'function') {\n sink.write2(a, b);\n return;\n }\n sink.write(a);\n sink.write(b);\n}\n\nfunction sinkWrite3(\n sink: {\n write(html: string): void;\n write3?: (a: string, b: string, c: string) => void;\n },\n a: string,\n b: string,\n c: string\n): void {\n if (typeof sink.write3 === 'function') {\n sink.write3(a, b, c);\n return;\n }\n sink.write(a);\n sink.write(b);\n sink.write(c);\n}\n\nfunction renderNodeSync(node: VNode | JSXElement, ctx: RenderContext): string {\n const { type, props } = node;\n\n /* istanbul ignore if - dev-only debug */\n if (__SSR_DEBUG) {\n try {\n logger.warn('[SSR] renderNodeSync type:', typeof type, type);\n } catch {}\n }\n\n if (typeof type === 'function') {\n const result = executeComponentSync(type as Component, props, ctx);\n return renderRenderableSync(inheritRenderableKey(node, result), ctx);\n }\n\n if (typeof type === 'symbol') {\n if (type === Fragment) {\n const childrenArr = getRenderableChildren(node);\n /* istanbul ignore if - dev-only debug */\n if (__SSR_DEBUG) {\n try {\n logger.warn('[SSR] fragment children length:', childrenArr?.length);\n } catch {\n // Ignore\n }\n }\n return renderChildrenSync(childrenArr, ctx);\n }\n if (type === __CONTROL_BOUNDARY__) {\n return renderChildrenSync(evaluateControlBoundaryChildren(node), ctx);\n }\n if (type === __ERROR_BOUNDARY__) {\n const boundaryState = getErrorBoundaryState(node);\n const fallback = props?.fallback;\n const reset = createErrorBoundaryReset(node);\n\n if (boundaryState?.error != null) {\n return renderErrorBoundaryFallbackValue(\n fallback,\n boundaryState.error,\n reset,\n ctx\n );\n }\n\n try {\n return renderChildrenSync(\n normalizeRenderableChildren(props?.children),\n ctx\n );\n } catch (error) {\n if (boundaryState) {\n boundaryState.error = error;\n boundaryState.notified = true;\n }\n logger.error('[Askr] ErrorBoundary caught render error:', error);\n return renderErrorBoundaryFallbackValue(fallback, error, reset, ctx);\n }\n }\n throw new Error(\n `renderNodeSync: unsupported VNode symbol type: ${String(type)}`\n );\n }\n\n const typeStr = type as string;\n if (VOID_ELEMENTS.has(typeStr)) {\n const attrs = renderAttrs(props);\n return `<${typeStr}${attrs} />`;\n }\n\n const maybeDangerous = (\n props as unknown as { dangerouslySetInnerHTML?: unknown }\n )?.dangerouslySetInnerHTML;\n if (maybeDangerous !== undefined && maybeDangerous !== null) {\n const { attrs, dangerousHtml } = renderAttrs(props, {\n returnDangerousHtml: true,\n });\n if (dangerousHtml !== undefined) {\n return `<${typeStr}${attrs}>${dangerousHtml}</${typeStr}>`;\n }\n const childrenHtml = renderChildrenSync(getRenderableChildren(node), ctx);\n return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;\n }\n\n const attrs = renderAttrs(props);\n const childrenHtml = renderChildrenSync(getRenderableChildren(node), ctx);\n return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;\n}\n\nfunction renderNodeSyncToSink(\n node: VNode | JSXElement,\n sink: {\n write(html: string): void;\n write2?: (a: string, b: string) => void;\n write3?: (a: string, b: string, c: string) => void;\n },\n ctx: RenderContext\n): void {\n const { type, props } = node;\n\n if (typeof type === 'function') {\n const result = executeComponentSync(type as Component, props, ctx);\n renderRenderableSyncToSink(inheritRenderableKey(node, result), sink, ctx);\n return;\n }\n\n if (typeof type === 'symbol') {\n if (type === Fragment) {\n const childrenArr = getRenderableChildren(node);\n renderChildrenSyncToSink(childrenArr, sink, ctx);\n return;\n }\n if (type === __CONTROL_BOUNDARY__) {\n renderChildrenSyncToSink(\n evaluateControlBoundaryChildren(node),\n sink,\n ctx\n );\n return;\n }\n if (type === __ERROR_BOUNDARY__) {\n const boundaryState = getErrorBoundaryState(node);\n const fallback = props?.fallback;\n const reset = createErrorBoundaryReset(node);\n\n if (boundaryState?.error != null) {\n renderErrorBoundaryFallbackValueToSink(\n fallback,\n boundaryState.error,\n reset,\n sink,\n ctx\n );\n return;\n }\n\n try {\n renderChildrenSyncToSink(\n normalizeRenderableChildren(props?.children),\n sink,\n ctx\n );\n } catch (error) {\n if (boundaryState) {\n boundaryState.error = error;\n boundaryState.notified = true;\n }\n logger.error('[Askr] ErrorBoundary caught render error:', error);\n renderErrorBoundaryFallbackValueToSink(\n fallback,\n error,\n reset,\n sink,\n ctx\n );\n }\n return;\n }\n throw new Error(\n `renderNodeSyncToSink: unsupported VNode symbol type: ${String(type)}`\n );\n }\n\n const typeStr = type as string;\n if (VOID_ELEMENTS.has(typeStr)) {\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write(' />');\n return;\n }\n\n const maybeDangerous = props\n ? (props as unknown as { dangerouslySetInnerHTML?: unknown })\n ?.dangerouslySetInnerHTML\n : undefined;\n\n if (maybeDangerous !== undefined && maybeDangerous !== null) {\n const dangerousHtml =\n typeof maybeDangerous === 'object' && '__html' in maybeDangerous\n ? String((maybeDangerous as { __html: unknown }).__html)\n : undefined;\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n if (dangerousHtml !== undefined) {\n sink.write(dangerousHtml);\n } else {\n renderChildrenSyncToSink(getRenderableChildren(node), sink, ctx);\n }\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n\n const children = getRenderableChildren(node);\n\n if (!children || (Array.isArray(children) && children.length === 0)) {\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n\n if (Array.isArray(children) && children.length === 1) {\n const only = children[0];\n if (typeof only === 'string') {\n const content = escapeText(only);\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sink.write(content);\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n if (typeof only === 'number') {\n const content = escapeText(String(only));\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sink.write(content);\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n }\n\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n renderChildrenSyncToSink(children, sink, ctx);\n sinkWrite3(sink, '</', typeStr, '>');\n}\n\nexport function renderToStringSync(\n component: (\n props?: Record<string, unknown>\n ) => VNode | JSXElement | string | number | boolean | null | undefined,\n props?: Record<string, unknown>,\n options?: { seed?: number; data?: SSRData }\n): string {\n const seed = options?.seed ?? 12345;\n const ctx = createRenderContext(seed, { data: options?.data });\n\n return withRenderContext(ctx, () => {\n startRenderPhase(options?.data ?? null);\n try {\n const node = renderSyncComponentRoot(\n component as unknown as Component,\n props || {},\n ctx\n );\n if (!node) {\n throw new Error('renderToStringSync: wrapped component returned empty');\n }\n const sink = new StringSink();\n renderNodeSyncToSink(node, sink, ctx);\n sink.write(serializeHydrationRenderData(options?.data));\n sink.end();\n return sink.toString();\n } finally {\n try {\n stopRenderPhase();\n } finally {\n disposeSSRTemporaryOwners(ctx);\n }\n }\n });\n}\n\nexport function renderSSRRouteAppToSink(input: RouteAppRenderInput): void {\n const { ctx, data, route, params, sink } = input;\n\n withRenderContext(ctx, () => {\n startRenderPhase(data || null);\n try {\n const app = executeComponentSync(\n route.handler as unknown as Component,\n params,\n ctx\n );\n renderRenderableSyncToSink(app, sink, ctx);\n sink.write(serializeHydrationRenderData(data));\n } finally {\n try {\n stopRenderPhase();\n } finally {\n disposeSSRTemporaryOwners(ctx);\n }\n }\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"render-sync.js","names":[],"sources":["../../src/ssr/render-sync.ts"],"sourcesContent":["import type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { __ERROR_BOUNDARY__ } from '../common/vnode';\nimport { Fragment } from '../jsx';\nimport { logger } from '../common/logger';\nimport {\n createRenderContext,\n withRenderContext,\n type RenderContext,\n type SSRData,\n} from './context';\nimport {\n disposeSSRTemporaryOwners,\n executeComponentSync,\n renderSyncComponentRoot,\n type Component,\n} from './component-runtime';\nimport {\n createErrorBoundaryReset,\n evaluateControlBoundaryChildren,\n getErrorBoundaryState,\n getRenderableChildren,\n normalizeRenderableChildren,\n resolveErrorBoundaryFallbackNode,\n} from './boundaries';\nimport { renderAttrs, renderAttrsDirect } from './attrs';\nimport { VOID_ELEMENTS, escapeText } from './escape';\nimport { serializeHydrationRenderData } from './hydration-data';\nimport { startRenderPhase, stopRenderPhase } from './render-keys';\nimport type { RouteAppRenderInput } from './route-render';\nimport { StringSink } from './sink';\nimport type { VNode } from './types';\n\nconst __SSR_DEBUG =\n process.env.NODE_ENV !== 'production' &&\n (process.env.ASKR_SSR_DEBUG === '1' || process.env.ASKR_SSR_DEBUG === 'true');\n\nexport function inheritRenderableKey(\n source: VNode | JSXElement,\n result: VNode | JSXElement\n): VNode | JSXElement {\n const inheritedKey = (source as DOMElement).key;\n if (inheritedKey === undefined || inheritedKey === null) {\n return result;\n }\n\n if (!result || typeof result !== 'object' || !('type' in result)) {\n return result;\n }\n\n const resultVNode = result as DOMElement;\n if (resultVNode.key === undefined || resultVNode.key === null) {\n resultVNode.key = inheritedKey;\n }\n\n if (typeof resultVNode.type === 'string') {\n if (!resultVNode.props) {\n resultVNode.props = {};\n }\n\n if (resultVNode.props['data-key'] === undefined) {\n resultVNode.props['data-key'] = String(inheritedKey);\n }\n }\n\n return result;\n}\n\nfunction renderRenderableSync(value: unknown, ctx: RenderContext): string {\n if (typeof value === 'string') return escapeText(value);\n if (typeof value === 'number') return escapeText(String(value));\n if (value === null || value === undefined || value === false) return '';\n if (Array.isArray(value)) return renderChildrenSync(value, ctx);\n if (value && typeof value === 'object' && 'type' in value) {\n return renderNodeSync(value as VNode, ctx);\n }\n return '';\n}\n\nfunction renderChildSync(child: unknown, ctx: RenderContext): string {\n return renderRenderableSync(child, ctx);\n}\n\nexport function renderRenderableSyncToSink(\n value: unknown,\n sink: {\n write(html: string): void;\n write2?: (a: string, b: string) => void;\n write3?: (a: string, b: string, c: string) => void;\n },\n ctx: RenderContext\n): void {\n if (value === null || value === undefined || value === false) return;\n if (typeof value === 'string') {\n sink.write(escapeText(value));\n return;\n }\n if (typeof value === 'number') {\n sink.write(escapeText(String(value)));\n return;\n }\n if (Array.isArray(value)) {\n renderChildrenSyncToSink(value, sink, ctx);\n return;\n }\n if (value && typeof value === 'object' && 'type' in value) {\n renderNodeSyncToSink(value as VNode, sink, ctx);\n }\n}\n\nfunction renderChildSyncToSink(\n child: unknown,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n renderRenderableSyncToSink(child, sink, ctx);\n}\n\nfunction renderChildrenSync(\n children: unknown[] | undefined,\n ctx: RenderContext\n): string {\n if (!children || !Array.isArray(children) || children.length === 0) return '';\n if (children.length === 1) return renderChildSync(children[0], ctx);\n\n if (children.length <= 8) {\n let result = '';\n for (const child of children) result += renderChildSync(child, ctx);\n return result;\n }\n\n const parts = Array.from({ length: children.length }, (_, index) =>\n renderChildSync(children[index], ctx)\n );\n return parts.join('');\n}\n\nfunction renderErrorBoundaryFallbackValue(\n fallback: unknown,\n error: unknown,\n reset: () => void,\n ctx: RenderContext\n): string {\n const nextValue = resolveErrorBoundaryFallbackNode(fallback, error, reset);\n\n return Array.isArray(nextValue)\n ? renderChildrenSync(normalizeRenderableChildren(nextValue), ctx)\n : renderChildSync(nextValue, ctx);\n}\n\nfunction renderErrorBoundaryFallbackValueToSink(\n fallback: unknown,\n error: unknown,\n reset: () => void,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n sink.write(renderErrorBoundaryFallbackValue(fallback, error, reset, ctx));\n}\n\nfunction renderChildrenSyncToSink(\n children: unknown[] | undefined,\n sink: { write(html: string): void },\n ctx: RenderContext\n): void {\n if (!children || !Array.isArray(children) || children.length === 0) return;\n if (children.length >= 32) {\n for (let i = 0; i < children.length; i++) {\n renderRenderableSyncToSink(children[i], sink, ctx);\n }\n return;\n }\n for (let i = 0; i < children.length; i++) {\n renderChildSyncToSink(children[i], sink, ctx);\n }\n}\n\nfunction sinkWrite2(\n sink: { write(html: string): void; write2?: (a: string, b: string) => void },\n a: string,\n b: string\n): void {\n if (typeof sink.write2 === 'function') {\n sink.write2(a, b);\n return;\n }\n sink.write(a);\n sink.write(b);\n}\n\nfunction sinkWrite3(\n sink: {\n write(html: string): void;\n write3?: (a: string, b: string, c: string) => void;\n },\n a: string,\n b: string,\n c: string\n): void {\n if (typeof sink.write3 === 'function') {\n sink.write3(a, b, c);\n return;\n }\n sink.write(a);\n sink.write(b);\n sink.write(c);\n}\n\nfunction renderNodeSync(node: VNode | JSXElement, ctx: RenderContext): string {\n const { type, props } = node;\n\n /* istanbul ignore if - dev-only debug */\n if (__SSR_DEBUG) {\n try {\n logger.warn('[SSR] renderNodeSync type:', typeof type, type);\n } catch {}\n }\n\n if (typeof type === 'function') {\n const result = executeComponentSync(type as Component, props, ctx);\n return renderRenderableSync(inheritRenderableKey(node, result), ctx);\n }\n\n if (typeof type === 'symbol') {\n if (type === Fragment) {\n const childrenArr = getRenderableChildren(node);\n /* istanbul ignore if - dev-only debug */\n if (__SSR_DEBUG) {\n try {\n logger.warn('[SSR] fragment children length:', childrenArr?.length);\n } catch {\n // Ignore\n }\n }\n return renderChildrenSync(childrenArr, ctx);\n }\n if (type === __CONTROL_BOUNDARY__) {\n return renderChildrenSync(evaluateControlBoundaryChildren(node), ctx);\n }\n if (type === __ERROR_BOUNDARY__) {\n const boundaryState = getErrorBoundaryState(node);\n const fallback = props?.fallback;\n const reset = createErrorBoundaryReset(node);\n\n if (boundaryState?.error != null) {\n return renderErrorBoundaryFallbackValue(\n fallback,\n boundaryState.error,\n reset,\n ctx\n );\n }\n\n try {\n return renderChildrenSync(\n normalizeRenderableChildren(props?.children),\n ctx\n );\n } catch (error) {\n if (boundaryState) {\n boundaryState.error = error;\n boundaryState.notified = true;\n }\n logger.error('[Askr] ErrorBoundary caught render error:', error);\n return renderErrorBoundaryFallbackValue(fallback, error, reset, ctx);\n }\n }\n throw new Error(\n `renderNodeSync: unsupported VNode symbol type: ${String(type)}`\n );\n }\n\n const typeStr = type as string;\n if (VOID_ELEMENTS.has(typeStr)) {\n const attrs = renderAttrs(props);\n return `<${typeStr}${attrs} />`;\n }\n\n const maybeDangerous = (\n props as unknown as { dangerouslySetInnerHTML?: unknown }\n )?.dangerouslySetInnerHTML;\n if (maybeDangerous !== undefined && maybeDangerous !== null) {\n const { attrs, dangerousHtml } = renderAttrs(props, {\n returnDangerousHtml: true,\n });\n if (dangerousHtml !== undefined) {\n return `<${typeStr}${attrs}>${dangerousHtml}</${typeStr}>`;\n }\n const childrenHtml = renderChildrenSync(getRenderableChildren(node), ctx);\n return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;\n }\n\n const attrs = renderAttrs(props);\n const childrenHtml = renderChildrenSync(getRenderableChildren(node), ctx);\n return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;\n}\n\nfunction renderNodeSyncToSink(\n node: VNode | JSXElement,\n sink: {\n write(html: string): void;\n write2?: (a: string, b: string) => void;\n write3?: (a: string, b: string, c: string) => void;\n },\n ctx: RenderContext\n): void {\n const { type, props } = node;\n\n if (typeof type === 'function') {\n const result = executeComponentSync(type as Component, props, ctx);\n renderRenderableSyncToSink(inheritRenderableKey(node, result), sink, ctx);\n return;\n }\n\n if (typeof type === 'symbol') {\n if (type === Fragment) {\n const childrenArr = getRenderableChildren(node);\n renderChildrenSyncToSink(childrenArr, sink, ctx);\n return;\n }\n if (type === __CONTROL_BOUNDARY__) {\n renderChildrenSyncToSink(\n evaluateControlBoundaryChildren(node),\n sink,\n ctx\n );\n return;\n }\n if (type === __ERROR_BOUNDARY__) {\n const boundaryState = getErrorBoundaryState(node);\n const fallback = props?.fallback;\n const reset = createErrorBoundaryReset(node);\n\n if (boundaryState?.error != null) {\n renderErrorBoundaryFallbackValueToSink(\n fallback,\n boundaryState.error,\n reset,\n sink,\n ctx\n );\n return;\n }\n\n try {\n renderChildrenSyncToSink(\n normalizeRenderableChildren(props?.children),\n sink,\n ctx\n );\n } catch (error) {\n if (boundaryState) {\n boundaryState.error = error;\n boundaryState.notified = true;\n }\n logger.error('[Askr] ErrorBoundary caught render error:', error);\n renderErrorBoundaryFallbackValueToSink(\n fallback,\n error,\n reset,\n sink,\n ctx\n );\n }\n return;\n }\n throw new Error(\n `renderNodeSyncToSink: unsupported VNode symbol type: ${String(type)}`\n );\n }\n\n const typeStr = type as string;\n if (VOID_ELEMENTS.has(typeStr)) {\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write(' />');\n return;\n }\n\n const maybeDangerous = props\n ? (props as unknown as { dangerouslySetInnerHTML?: unknown })\n ?.dangerouslySetInnerHTML\n : undefined;\n\n if (maybeDangerous !== undefined && maybeDangerous !== null) {\n const dangerousHtml =\n typeof maybeDangerous === 'object' && '__html' in maybeDangerous\n ? String((maybeDangerous as { __html: unknown }).__html)\n : undefined;\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n if (dangerousHtml !== undefined) {\n sink.write(dangerousHtml);\n } else {\n renderChildrenSyncToSink(getRenderableChildren(node), sink, ctx);\n }\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n\n const children = getRenderableChildren(node);\n\n if (!children || (Array.isArray(children) && children.length === 0)) {\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n\n if (Array.isArray(children) && children.length === 1) {\n const only = children[0];\n if (typeof only === 'string') {\n const content = escapeText(only);\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sink.write(content);\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n if (typeof only === 'number') {\n const content = escapeText(String(only));\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n sink.write(content);\n sinkWrite3(sink, '</', typeStr, '>');\n return;\n }\n }\n\n sinkWrite2(sink, '<', typeStr);\n renderAttrsDirect(props, sink);\n sink.write('>');\n renderChildrenSyncToSink(children, sink, ctx);\n sinkWrite3(sink, '</', typeStr, '>');\n}\n\nexport function renderToStringSync(\n component: (\n props?: Record<string, unknown>\n ) => VNode | JSXElement | string | number | boolean | null | undefined,\n props?: Record<string, unknown>,\n options?: { seed?: number; data?: SSRData }\n): string {\n const seed = options?.seed ?? 12345;\n const ctx = createRenderContext(seed, { data: options?.data });\n\n return withRenderContext(ctx, () => {\n startRenderPhase(options?.data ?? null);\n try {\n const node = renderSyncComponentRoot(\n component as unknown as Component,\n props || {},\n ctx\n );\n if (!node) {\n throw new Error('renderToStringSync: wrapped component returned empty');\n }\n const sink = new StringSink();\n renderNodeSyncToSink(node, sink, ctx);\n sink.write(serializeHydrationRenderData(options?.data));\n sink.end();\n return sink.toString();\n } finally {\n try {\n stopRenderPhase();\n } finally {\n disposeSSRTemporaryOwners(ctx);\n }\n }\n });\n}\n\nexport function renderSSRRouteAppToSink(input: RouteAppRenderInput): void {\n const { ctx, data, route, params, sink } = input;\n\n withRenderContext(ctx, () => {\n startRenderPhase(data || null);\n try {\n const app = executeComponentSync(\n route.handler as unknown as Component,\n params,\n ctx\n );\n renderRenderableSyncToSink(app, sink, ctx);\n sink.write(serializeHydrationRenderData(data));\n } finally {\n try {\n stopRenderPhase();\n } finally {\n disposeSSRTemporaryOwners(ctx);\n }\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isPromiseLike } from "../common/promise.js";
|
|
2
|
-
import { _resolveRouteMatchFromRoutes
|
|
2
|
+
import { _resolveRouteMatchFromRoutes } from "../router/route-matching.js";
|
|
3
|
+
import { resolveRouteRequest } from "../router/resolution.js";
|
|
3
4
|
import "../router/route.js";
|
|
4
5
|
import { throwSSRDataMissing } from "./context.js";
|
|
5
6
|
//#region src/ssr/route-policy-resolution.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-policy-resolution.js","names":["RouteModule._resolveRouteMatchFromRoutes","RouteModule.resolveRouteRequest"],"sources":["../../src/ssr/route-policy-resolution.ts"],"sourcesContent":["import { isPromiseLike } from '../common/promise';\nimport type {\n AccessDenyStatus,\n RouteManifest,\n RouteRequestResult,\n} from '../common/router';\nimport * as RouteModule from '../router/route';\nimport { throwSSRDataMissing } from './context';\nimport type { RouteRenderOptions, SSRRoute } from './route-render';\n\nconst MAX_SSR_REDIRECTS = 20;\n\ntype ResolvedPolicyAwareSSRRoute = {\n url: string;\n route: SSRRoute;\n params: Record<string, string>;\n};\n\nfunction getRouteRequestResultSync(\n result: RouteRequestResult | Promise<RouteRequestResult>\n): RouteRequestResult {\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n\n return result;\n}\n\nfunction buildDeniedRoute(route: SSRRoute, status: AccessDenyStatus): SSRRoute {\n return {\n ...route,\n handler: () => ({\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n }),\n };\n}\n\nfunction routeHasSSRLoader(manifest: RouteManifest, route: SSRRoute): boolean {\n const routeFallbackPrefix = (route as { fallbackPrefix?: string })\n .fallbackPrefix;\n\n return manifest.records.some((record) => {\n const recordFallbackPrefix = (record as { fallbackPrefix?: string })\n .fallbackPrefix;\n\n return (\n record.path === route.path &&\n recordFallbackPrefix === routeFallbackPrefix &&\n typeof record.options?.loader === 'function'\n );\n });\n}\n\nexport function resolvePolicyAwareSSRRoute(\n opts: RouteRenderOptions,\n routeTable: SSRRoute[]\n): ResolvedPolicyAwareSSRRoute {\n const manifest = opts.registry?.manifest;\n\n if (!manifest) {\n const requestUrl = new URL(opts.url, 'http://localhost');\n const matched = RouteModule._resolveRouteMatchFromRoutes(\n requestUrl.pathname,\n routeTable\n );\n if (!matched) {\n throw new Error(`SSR: no route found for url: ${opts.url}`);\n }\n\n return {\n url: opts.url,\n route: matched.route,\n params: matched.params,\n };\n }\n\n let href = opts.url;\n const visited = new Set<string>();\n\n for (let redirects = 0; redirects <= MAX_SSR_REDIRECTS; redirects += 1) {\n const requestUrl = new URL(href, 'http://localhost');\n const matched = RouteModule._resolveRouteMatchFromRoutes(\n requestUrl.pathname,\n routeTable\n );\n\n if (!matched) {\n throw new Error(`SSR: no route found for url: ${href}`);\n }\n\n const resolved = getRouteRequestResultSync(\n RouteModule.resolveRouteRequest(href, {\n manifest,\n mode: 'ssr',\n })\n );\n\n if (resolved === null) {\n throw new Error(`SSR: no route found for url: ${href}`);\n }\n\n if (resolved.kind === 'redirect') {\n const redirectTarget = new URL(resolved.to, 'http://localhost');\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n\n if (redirectHref === href || visited.has(redirectHref)) {\n throw new Error(\n `[Askr] SSR redirect cycle detected at ${redirectHref}.`\n );\n }\n\n if (redirects >= MAX_SSR_REDIRECTS) {\n throw new Error(\n `[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`\n );\n }\n\n visited.add(redirectHref);\n href = redirectHref;\n continue;\n }\n\n if (resolved.kind === 'deny') {\n return {\n url: href,\n route: buildDeniedRoute(matched.route, resolved.status),\n params: matched.params,\n };\n }\n\n return {\n url: href,\n route: {\n ...matched.route,\n handler: routeHasSSRLoader(manifest, matched.route)\n ? resolved.handler\n : matched.route.handler,\n },\n params: matched.params,\n };\n }\n\n throw new Error(`[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"route-policy-resolution.js","names":["RouteModule._resolveRouteMatchFromRoutes","RouteModule.resolveRouteRequest"],"sources":["../../src/ssr/route-policy-resolution.ts"],"sourcesContent":["import { isPromiseLike } from '../common/promise';\nimport type {\n AccessDenyStatus,\n RouteManifest,\n RouteRequestResult,\n} from '../common/router';\nimport * as RouteModule from '../router/route';\nimport { throwSSRDataMissing } from './context';\nimport type { RouteRenderOptions, SSRRoute } from './route-render';\n\nconst MAX_SSR_REDIRECTS = 20;\n\ntype ResolvedPolicyAwareSSRRoute = {\n url: string;\n route: SSRRoute;\n params: Record<string, string>;\n};\n\nfunction getRouteRequestResultSync(\n result: RouteRequestResult | Promise<RouteRequestResult>\n): RouteRequestResult {\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n\n return result;\n}\n\nfunction buildDeniedRoute(route: SSRRoute, status: AccessDenyStatus): SSRRoute {\n return {\n ...route,\n handler: () => ({\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n }),\n };\n}\n\nfunction routeHasSSRLoader(manifest: RouteManifest, route: SSRRoute): boolean {\n const routeFallbackPrefix = (route as { fallbackPrefix?: string })\n .fallbackPrefix;\n\n return manifest.records.some((record) => {\n const recordFallbackPrefix = (record as { fallbackPrefix?: string })\n .fallbackPrefix;\n\n return (\n record.path === route.path &&\n recordFallbackPrefix === routeFallbackPrefix &&\n typeof record.options?.loader === 'function'\n );\n });\n}\n\nexport function resolvePolicyAwareSSRRoute(\n opts: RouteRenderOptions,\n routeTable: SSRRoute[]\n): ResolvedPolicyAwareSSRRoute {\n const manifest = opts.registry?.manifest;\n\n if (!manifest) {\n const requestUrl = new URL(opts.url, 'http://localhost');\n const matched = RouteModule._resolveRouteMatchFromRoutes(\n requestUrl.pathname,\n routeTable\n );\n if (!matched) {\n throw new Error(`SSR: no route found for url: ${opts.url}`);\n }\n\n return {\n url: opts.url,\n route: matched.route,\n params: matched.params,\n };\n }\n\n let href = opts.url;\n const visited = new Set<string>();\n\n for (let redirects = 0; redirects <= MAX_SSR_REDIRECTS; redirects += 1) {\n const requestUrl = new URL(href, 'http://localhost');\n const matched = RouteModule._resolveRouteMatchFromRoutes(\n requestUrl.pathname,\n routeTable\n );\n\n if (!matched) {\n throw new Error(`SSR: no route found for url: ${href}`);\n }\n\n const resolved = getRouteRequestResultSync(\n RouteModule.resolveRouteRequest(href, {\n manifest,\n mode: 'ssr',\n })\n );\n\n if (resolved === null) {\n throw new Error(`SSR: no route found for url: ${href}`);\n }\n\n if (resolved.kind === 'redirect') {\n const redirectTarget = new URL(resolved.to, 'http://localhost');\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n\n if (redirectHref === href || visited.has(redirectHref)) {\n throw new Error(\n `[Askr] SSR redirect cycle detected at ${redirectHref}.`\n );\n }\n\n if (redirects >= MAX_SSR_REDIRECTS) {\n throw new Error(\n `[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`\n );\n }\n\n visited.add(redirectHref);\n href = redirectHref;\n continue;\n }\n\n if (resolved.kind === 'deny') {\n return {\n url: href,\n route: buildDeniedRoute(matched.route, resolved.status),\n params: matched.params,\n };\n }\n\n return {\n url: href,\n route: {\n ...matched.route,\n handler: routeHasSSRLoader(manifest, matched.route)\n ? resolved.handler\n : matched.route.handler,\n },\n params: matched.params,\n };\n }\n\n throw new Error(`[Askr] SSR redirect limit exceeded (${MAX_SSR_REDIRECTS}).`);\n}\n"],"mappings":";;;;;;AAUA,MAAM,oBAAoB;AAQ1B,SAAS,0BACP,QACoB;CACpB,IAAI,cAAc,MAAM,GACtB,oBAAoB;CAGtB,OAAO;AACT;AAEA,SAAS,iBAAiB,OAAiB,QAAoC;CAC7E,OAAO;EACL,GAAG;EACH,gBAAgB;GACd,MAAM;GACN,OAAO,EACL,qBAAqB,OAAO,MAAM,EACpC;GACA,UAAU,CAAC,OAAO,MAAM,CAAC;EAC3B;CACF;AACF;AAEA,SAAS,kBAAkB,UAAyB,OAA0B;CAC5E,MAAM,sBAAuB,MAC1B;CAEH,OAAO,SAAS,QAAQ,MAAM,WAAW;EACvC,MAAM,uBAAwB,OAC3B;EAEH,OACE,OAAO,SAAS,MAAM,QACtB,yBAAyB,uBACzB,OAAO,OAAO,SAAS,WAAW;CAEtC,CAAC;AACH;AAEA,SAAgB,2BACd,MACA,YAC6B;CAC7B,MAAM,WAAW,KAAK,UAAU;CAEhC,IAAI,CAAC,UAAU;EAEb,MAAM,UAAUA,6BACd,IAFqB,IAAI,KAAK,KAAK,kBAEnC,CAAA,CAAW,UACX,UACF;EACA,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,gCAAgC,KAAK,KAAK;EAG5D,OAAO;GACL,KAAK,KAAK;GACV,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB;CACF;CAEA,IAAI,OAAO,KAAK;CAChB,MAAM,0BAAU,IAAI,IAAY;CAEhC,KAAK,IAAI,YAAY,GAAG,aAAa,mBAAmB,aAAa,GAAG;EAEtE,MAAM,UAAUA,6BACd,IAFqB,IAAI,MAAM,kBAE/B,CAAA,CAAW,UACX,UACF;EAEA,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,gCAAgC,MAAM;EAGxD,MAAM,WAAW,0BACfC,oBAAgC,MAAM;GACpC;GACA,MAAM;EACR,CAAC,CACH;EAEA,IAAI,aAAa,MACf,MAAM,IAAI,MAAM,gCAAgC,MAAM;EAGxD,IAAI,SAAS,SAAS,YAAY;GAChC,MAAM,iBAAiB,IAAI,IAAI,SAAS,IAAI,kBAAkB;GAC9D,MAAM,eAAe,GAAG,eAAe,WAAW,eAAe,SAAS,eAAe;GAEzF,IAAI,iBAAiB,QAAQ,QAAQ,IAAI,YAAY,GACnD,MAAM,IAAI,MACR,yCAAyC,aAAa,EACxD;GAGF,IAAI,aAAa,mBACf,MAAM,IAAI,MACR,uCAAuC,kBAAkB,GAC3D;GAGF,QAAQ,IAAI,YAAY;GACxB,OAAO;GACP;EACF;EAEA,IAAI,SAAS,SAAS,QACpB,OAAO;GACL,KAAK;GACL,OAAO,iBAAiB,QAAQ,OAAO,SAAS,MAAM;GACtD,QAAQ,QAAQ;EAClB;EAGF,OAAO;GACL,KAAK;GACL,OAAO;IACL,GAAG,QAAQ;IACX,SAAS,kBAAkB,UAAU,QAAQ,KAAK,IAC9C,SAAS,UACT,QAAQ,MAAM;GACpB;GACA,QAAQ,QAAQ;EAClB;CACF;CAEA,MAAM,IAAI,MAAM,uCAAuC,kBAAkB,GAAG;AAC9E"}
|
package/dist/ssr/route-render.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { resolveRouteFromRoutes
|
|
1
|
+
import { resolveRouteFromRoutes } from "../router/route-matching.js";
|
|
2
|
+
import { resolveRouteRequest } from "../router/resolution.js";
|
|
2
3
|
import "../router/route.js";
|
|
3
4
|
import { renderDocument } from "../common/ssr.js";
|
|
4
5
|
import { createRenderContext } from "./context.js";
|