@markless/bundler 0.3.3 → 0.5.0
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/dev-error-DRvO28Fd.js +174 -0
- package/dist/dev-error.d.ts +14 -16
- package/dist/dev-error.js +1 -173
- package/dist/execution-log-D9cex1i1.d.ts +17 -0
- package/dist/optimized-deps-BfzxSm6C.js +89 -0
- package/dist/preload.d.ts +39 -7
- package/dist/preload.js +3 -2
- package/dist/repeat-runtime-BDnaUYXM.js +71 -0
- package/dist/rolldown-BciZw5hZ.js +9116 -0
- package/dist/rolldown.d.ts +37 -18
- package/dist/rolldown.js +3 -3
- package/dist/roster-resume-CpphsFl_.js +427 -0
- package/dist/route-pack-groups-BpefyjrE.js +2707 -0
- package/dist/shared-seed-slot-ihIVCD2S.js +113 -0
- package/dist/{types-BuooJg32.d.ts → types-BqSoEVp6.d.ts} +46 -10
- package/dist/vite.d.ts +5 -6
- package/dist/vite.js +636 -137
- package/package.json +7 -7
- package/dist/rolldown-FRjFod14.js +0 -4516
- package/dist/source-module-CZFm1uWH.js +0 -1032
- package/dist/source-module-XFgOFX1c.d.ts +0 -8
package/dist/rolldown.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import { _ as TransformTsrxModuleInput, a as MarklessBundle, c as MarklessEnvironment, d as MarklessRolldownPluginApi, f as MarklessTransformManifest, g as PreloadGraphEntriesAdder, h as PreloadGraphEntries, i as MarklessBuildMetadata, l as MarklessManifest, m as PreloadGraphContext, n as GlobalInjections, o as MarklessBundleGraph, p as MarklessVirtualModule, r as MarklessAsset, s as MarklessDevServer, t as BundleGraphAdder, u as MarklessRolldownOptions, v as TransformTsrxModuleResult } from "./types-
|
|
2
|
-
import {
|
|
1
|
+
import { _ as TransformTsrxModuleInput, a as MarklessBundle, c as MarklessEnvironment, d as MarklessRolldownPluginApi, f as MarklessTransformManifest, g as PreloadGraphEntriesAdder, h as PreloadGraphEntries, i as MarklessBuildMetadata, l as MarklessManifest, m as PreloadGraphContext, n as GlobalInjections, o as MarklessBundleGraph, p as MarklessVirtualModule, r as MarklessAsset, s as MarklessDevServer, t as BundleGraphAdder, u as MarklessRolldownOptions, v as TransformTsrxModuleResult } from "./types-BqSoEVp6.js";
|
|
2
|
+
import { a as resumeVirtualModuleId, n as MARKLESS_VIRTUAL_PREFIX, r as prerenderWakeVirtualModuleId } from "./execution-log-D9cex1i1.js";
|
|
3
3
|
import { ProtocolStatePayload, ProtocolViewPayload } from "@markless/serializer";
|
|
4
|
+
import { ArtifactChildMaterialization, CompilerDiagnostic, ModuleGraphInterfaceArtifact, SemanticGraphInput } from "@markless/compiler";
|
|
5
|
+
import "@markless/web/inline/resumer";
|
|
4
6
|
import { OutputOptions, Plugin } from "rolldown";
|
|
5
|
-
|
|
7
|
+
import "@markless/serializer/protocol";
|
|
6
8
|
//#region src/build/prerender.d.ts
|
|
7
9
|
type BuiltPrerenderRecords = {
|
|
8
10
|
readonly state: ProtocolStatePayload;
|
|
9
11
|
readonly view: ProtocolViewPayload;
|
|
10
12
|
};
|
|
11
13
|
//#endregion
|
|
14
|
+
//#region src/hooks/hook-context.d.ts
|
|
15
|
+
type Environment = MarklessEnvironment | ((context: unknown) => MarklessEnvironment);
|
|
16
|
+
//#endregion
|
|
12
17
|
//#region src/build/chunking.d.ts
|
|
13
|
-
declare const MARKLESS_BUILD_PREFIX = "build/";
|
|
14
|
-
declare const MARKLESS_BUNDLE_GRAPH = "build/bundle-graph.json";
|
|
15
|
-
declare
|
|
18
|
+
export declare const MARKLESS_BUILD_PREFIX = "build/";
|
|
19
|
+
export declare const MARKLESS_BUNDLE_GRAPH = "build/bundle-graph.json";
|
|
20
|
+
export declare const MARKLESS_BUILD_METADATA_FILES: readonly ["build/bundle-graph.json", "build/execution-sizes.json", "build/execution-demand.json", "build/interaction-closures.json", "build/byte-attribution.json"];
|
|
21
|
+
export declare function outputDefaults(output: OutputOptions, environment: MarklessEnvironment): OutputOptions;
|
|
16
22
|
//#endregion
|
|
17
23
|
//#region src/build/build-metadata.d.ts
|
|
18
24
|
type MarklessBuildMetadataBundle = Record<string, MarklessBuildMetadataBundleItem>;
|
|
@@ -38,7 +44,7 @@ interface MarklessBuildMetadataChunk {
|
|
|
38
44
|
importedCss?: ReadonlySet<string> | readonly string[];
|
|
39
45
|
};
|
|
40
46
|
}
|
|
41
|
-
declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transformManifests: Iterable<MarklessTransformManifest>, root: string | undefined, options?: {
|
|
47
|
+
export declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transformManifests: Iterable<MarklessTransformManifest>, root: string | undefined, options?: {
|
|
42
48
|
bundleGraphAsset?: string;
|
|
43
49
|
bundleGraphAdders?: Set<BundleGraphAdder>;
|
|
44
50
|
canonPath?: (fileName: string) => string;
|
|
@@ -47,8 +53,8 @@ declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transf
|
|
|
47
53
|
}): MarklessBuildMetadata;
|
|
48
54
|
//#endregion
|
|
49
55
|
//#region src/build/bundle-graph.d.ts
|
|
50
|
-
declare function convertManifestToBundleGraph(manifest: MarklessBuildMetadata, bundleGraphAdders?: Set<BundleGraphAdder>): MarklessBundleGraph;
|
|
51
|
-
declare function createPreloadGraphAdder(addEntries: PreloadGraphEntriesAdder): BundleGraphAdder;
|
|
56
|
+
export declare function convertManifestToBundleGraph(manifest: MarklessBuildMetadata, bundleGraphAdders?: Set<BundleGraphAdder>): MarklessBundleGraph;
|
|
57
|
+
export declare function createPreloadGraphAdder(addEntries: PreloadGraphEntriesAdder): BundleGraphAdder;
|
|
52
58
|
//#endregion
|
|
53
59
|
//#region src/build/head-links.d.ts
|
|
54
60
|
type HeadLinkBundle = Record<string, HeadLinkBundleItem>;
|
|
@@ -63,25 +69,38 @@ interface HeadLinkChunk {
|
|
|
63
69
|
importedCss?: ReadonlySet<string> | readonly string[];
|
|
64
70
|
};
|
|
65
71
|
}
|
|
66
|
-
declare function collectHeadLinkInjections(bundle: HeadLinkBundle, options?: {
|
|
72
|
+
export declare function collectHeadLinkInjections(bundle: HeadLinkBundle, options?: {
|
|
67
73
|
publicPath?: (fileName: string) => string;
|
|
68
74
|
}): GlobalInjections[];
|
|
69
75
|
//#endregion
|
|
76
|
+
//#region src/build/build-manifests.d.ts
|
|
77
|
+
/** Where build-time hand-off files for a client output live: beside it, never inside the directory a host serves. */
|
|
78
|
+
export declare function marklessBuildManifestDir(clientOutDir: string): string;
|
|
79
|
+
/** The chunk import map a packed client build hands to the server that renders its documents. */
|
|
80
|
+
export declare function marklessImportMapPath(clientOutDir: string): string;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/build/content-hash-names.d.ts
|
|
83
|
+
export declare const MARKLESS_IMPORT_MAP_ASSET = ".vite/markless-import-map.json";
|
|
84
|
+
export declare const MARKLESS_CHUNK_SPECIFIER_PREFIX = "@markless/c/";
|
|
85
|
+
export declare function importMapScript(importMap: {
|
|
86
|
+
readonly imports: Record<string, string>;
|
|
87
|
+
}): string;
|
|
88
|
+
export declare function insertImportMapScript(html: string, script: string): string;
|
|
89
|
+
//#endregion
|
|
70
90
|
//#region src/transform.d.ts
|
|
71
|
-
declare function transformTsrxModule(input: TransformTsrxModuleInput): Promise<TransformTsrxModuleResult>;
|
|
91
|
+
export declare function transformTsrxModule(input: TransformTsrxModuleInput): Promise<TransformTsrxModuleResult>;
|
|
72
92
|
//#endregion
|
|
73
93
|
//#region src/rolldown.d.ts
|
|
74
|
-
type
|
|
75
|
-
type MarklessRolldownPlugin = Plugin & {
|
|
94
|
+
export type MarklessRolldownPlugin = Plugin & {
|
|
76
95
|
api: MarklessRolldownPluginApi;
|
|
77
96
|
};
|
|
78
|
-
declare const marklessClient: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
79
|
-
declare const marklessServer: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
80
|
-
declare const marklessLib: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
81
|
-
declare function createMarklessRolldownPlugin(input: {
|
|
97
|
+
export declare const marklessClient: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
98
|
+
export declare const marklessServer: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
99
|
+
export declare const marklessLib: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
|
|
100
|
+
export declare function createMarklessRolldownPlugin(input: {
|
|
82
101
|
environment: Environment;
|
|
83
102
|
options?: MarklessRolldownOptions;
|
|
84
103
|
prerenderRecordsBySource?: ReadonlyMap<string, BuiltPrerenderRecords>;
|
|
85
104
|
}): MarklessRolldownPlugin;
|
|
86
105
|
//#endregion
|
|
87
|
-
export { type BundleGraphAdder, type GlobalInjections,
|
|
106
|
+
export { type BundleGraphAdder, type GlobalInjections, MARKLESS_VIRTUAL_PREFIX, type MarklessAsset, type MarklessBuildMetadata, type MarklessBundle, type MarklessBundleGraph, type MarklessDevServer, type MarklessEnvironment, type MarklessManifest, type MarklessRolldownOptions, type MarklessRolldownPluginApi, type MarklessTransformManifest, type MarklessVirtualModule, type PreloadGraphContext, type PreloadGraphEntries, type PreloadGraphEntriesAdder, type TransformTsrxModuleInput, type TransformTsrxModuleResult, prerenderWakeVirtualModuleId, resumeVirtualModuleId };
|
package/dist/rolldown.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export { MARKLESS_BUILD_PREFIX, MARKLESS_BUNDLE_GRAPH, MARKLESS_VIRTUAL_PREFIX, collectHeadLinkInjections, convertManifestToBundleGraph, createBuildMetadata, createMarklessRolldownPlugin, createPreloadGraphAdder, marklessClient, marklessLib, marklessServer, outputDefaults, prerenderWakeVirtualModuleId, resumeVirtualModuleId, transformTsrxModule };
|
|
1
|
+
import { X as MARKLESS_BUILD_PREFIX, Y as MARKLESS_BUILD_METADATA_FILES, Z as MARKLESS_BUNDLE_GRAPH, ht as resumeVirtualModuleId, nt as outputDefaults, pt as prerenderWakeVirtualModuleId, rt as MARKLESS_VIRTUAL_PREFIX } from "./route-pack-groups-BpefyjrE.js";
|
|
2
|
+
import { C as importMapScript, D as transformTsrxModule, S as MARKLESS_IMPORT_MAP_ASSET, _ as createPreloadGraphAdder, b as marklessImportMapPath, c as collectHeadLinkInjections, g as convertManifestToBundleGraph, i as marklessServer, n as marklessClient, r as marklessLib, s as createBuildMetadata, t as createMarklessRolldownPlugin, w as insertImportMapScript, x as MARKLESS_CHUNK_SPECIFIER_PREFIX, y as marklessBuildManifestDir } from "./rolldown-BciZw5hZ.js";
|
|
3
|
+
export { MARKLESS_BUILD_METADATA_FILES, MARKLESS_BUILD_PREFIX, MARKLESS_BUNDLE_GRAPH, MARKLESS_CHUNK_SPECIFIER_PREFIX, MARKLESS_IMPORT_MAP_ASSET, MARKLESS_VIRTUAL_PREFIX, collectHeadLinkInjections, convertManifestToBundleGraph, createBuildMetadata, createMarklessRolldownPlugin, createPreloadGraphAdder, importMapScript, insertImportMapScript, marklessBuildManifestDir, marklessClient, marklessImportMapPath, marklessLib, marklessServer, outputDefaults, prerenderWakeVirtualModuleId, resumeVirtualModuleId, transformTsrxModule };
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
//#region ../web/src/dom-attribute.ts
|
|
2
|
+
function marklessAttributeValue(name, value) {
|
|
3
|
+
if (value == null || value === false) return null;
|
|
4
|
+
if (value !== true) return String(value);
|
|
5
|
+
return /^(aria|data)-/.test(name) ? "true" : "";
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region ../web/src/fns/instance-scope.ts
|
|
9
|
+
const INSTANCE_PATH = /^(?:[cpm]\d+:|r:[^:]*:)+/;
|
|
10
|
+
function marklessInstancePath(prefix) {
|
|
11
|
+
return prefix && INSTANCE_PATH.exec(prefix)?.[0] || "";
|
|
12
|
+
}
|
|
13
|
+
const ROW_SEGMENT = /r:[^:]*:/g;
|
|
14
|
+
/**
|
|
15
|
+
* A widget-scoped `element()` handle names one element PER RENDERED WIDGET, and
|
|
16
|
+
* its compiled id is one module-level string every instance of that widget
|
|
17
|
+
* spells. Qualifying it exactly as the widget's graph nodes are qualified is
|
|
18
|
+
* what turns it back into a key: the registration and the reading handler both
|
|
19
|
+
* land on the rendered widget's own root path, so a page carrying two instances
|
|
20
|
+
* answers each handler with its own element instead of the last registration.
|
|
21
|
+
*
|
|
22
|
+
* A handle that is not widget-scoped is returned untouched. A component-local
|
|
23
|
+
* handle is already one element per key, and a page-scoped `shared()` graph is
|
|
24
|
+
* page space by design.
|
|
25
|
+
*/
|
|
26
|
+
function marklessWidgetHandleId(handleId, instancePath, registry = marklessWidgetScope.active) {
|
|
27
|
+
if (!instancePath) return handleId;
|
|
28
|
+
const pageSpace = PAGE_SPACE_ID.exec(handleId);
|
|
29
|
+
if (!pageSpace || pageSpace[2] !== "shared") return handleId;
|
|
30
|
+
return marklessComposedGraphNodeId(handleId, instancePath, registry);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The reading half of the same key.
|
|
34
|
+
*
|
|
35
|
+
* The compiled symbol asks for the module-level id, so the instance it is
|
|
36
|
+
* running in is what has to be added here. Every registration a rendered widget
|
|
37
|
+
* makes is qualified the same way - the page-level ones at composition, the
|
|
38
|
+
* ones an `@if` arm files at resume - so a reader whose instance is named asks
|
|
39
|
+
* the qualified key and nothing else.
|
|
40
|
+
*/
|
|
41
|
+
function marklessInstanceScopedElementHandle(getElementHandle, instancePath, graph) {
|
|
42
|
+
if (typeof getElementHandle !== "function") return getElementHandle;
|
|
43
|
+
if (getElementHandle.marklessHandleScope === instancePath) return getElementHandle;
|
|
44
|
+
const scopedReader = (handleIdOrName) => {
|
|
45
|
+
const scoped = marklessWidgetHandleId(handleIdOrName, instancePath, graph ? marklessGraphWidgetRegistry(graph) : marklessWidgetScope.active);
|
|
46
|
+
return scoped === handleIdOrName ? getElementHandle(handleIdOrName) : getElementHandle(scoped);
|
|
47
|
+
};
|
|
48
|
+
scopedReader.marklessHandleScope = instancePath;
|
|
49
|
+
return scopedReader;
|
|
50
|
+
}
|
|
51
|
+
const PAGE_SPACE_ID = /^((?:[cpm]\d+:|r:[^:]*:)*)(shared|storage):/;
|
|
52
|
+
/**
|
|
53
|
+
* One registry per RUNTIME GRAPH, and a graph is one rendered page.
|
|
54
|
+
*
|
|
55
|
+
* A widget root path is only ever an answer about the container that rendered
|
|
56
|
+
* it, so a realm-wide map is a category error: two Markless roots on one page
|
|
57
|
+
* each render their own widgets, and a torn-down container's roots must not
|
|
58
|
+
* answer for the render that replaces it. Filing the registry against the graph
|
|
59
|
+
* makes both true by construction - the entries die with the graph, and a
|
|
60
|
+
* lookup can only reach the rendered widgets of the graph it was asked about.
|
|
61
|
+
*
|
|
62
|
+
* The key is the PAGE graph, recovered through `marklessPageGraph`, because
|
|
63
|
+
* every scope adapter below hands its symbol a fresh wrapper object over the
|
|
64
|
+
* same page graph and all of them must reach the same answer.
|
|
65
|
+
*/
|
|
66
|
+
const graphRegistries = /* @__PURE__ */ new WeakMap();
|
|
67
|
+
/**
|
|
68
|
+
* Which registry the lookups below read when the CALLER names no graph.
|
|
69
|
+
*
|
|
70
|
+
* Two readers cannot name one. Inside a compose there is no graph yet, so
|
|
71
|
+
* composition.ts swaps this to the render's own registry and swaps it back.
|
|
72
|
+
* And the generated symbol-resolver module's bound-symbol adapter holds the
|
|
73
|
+
* dispatching graph in a closure it never passes on, so it reaches this field
|
|
74
|
+
* instead - which is why every entry point that DOES hold a graph points this
|
|
75
|
+
* at that graph's registry before running anything (`marklessScopeWidgetsTo`).
|
|
76
|
+
*
|
|
77
|
+
* `composing` is what keeps a dispatch from stealing the field out from under a
|
|
78
|
+
* compose. Only a server ever composes and dispatches at once.
|
|
79
|
+
*/
|
|
80
|
+
const marklessWidgetScope = {
|
|
81
|
+
active: {
|
|
82
|
+
rootPaths: /* @__PURE__ */ new Map(),
|
|
83
|
+
rowRooted: /* @__PURE__ */ new Set()
|
|
84
|
+
},
|
|
85
|
+
composing: false
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Points the graph-less readers at the registry of the graph now being read.
|
|
89
|
+
*
|
|
90
|
+
* A dispatch is not synchronous, so this is a pointer re-aimed per entry rather
|
|
91
|
+
* than a scope that unwinds: the next entry re-aims it, and a torn-down
|
|
92
|
+
* container's registry is never re-aimed at again. Two containers dispatching
|
|
93
|
+
* async bodies that interleave their writes are the one case it cannot separate
|
|
94
|
+
* - the readers that hold a graph are exact regardless.
|
|
95
|
+
*/
|
|
96
|
+
function marklessScopeWidgetsTo(registry) {
|
|
97
|
+
if (!marklessWidgetScope.composing) marklessWidgetScope.active = registry;
|
|
98
|
+
return registry;
|
|
99
|
+
}
|
|
100
|
+
function marklessRegistryHolder(graph) {
|
|
101
|
+
const scoped = graph;
|
|
102
|
+
return scoped.marklessPageGraph ?? scoped.marklessWidgetHostGraph ?? graph;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* This graph's rendered widgets, minted on first ask and filled from the graph
|
|
106
|
+
* itself: the payload's widget-scoped definitions carry their qualified root ids
|
|
107
|
+
* and the projection sites composition registered them under, which is every
|
|
108
|
+
* answer a lookup needs and the only place resume has ever read them from.
|
|
109
|
+
*/
|
|
110
|
+
function marklessGraphWidgetRegistry(graph) {
|
|
111
|
+
if (!graph) return marklessWidgetScope.active;
|
|
112
|
+
const own = graph.marklessComposedWidgets ?? graphRegistries.get(graph);
|
|
113
|
+
if (own) return marklessScopeWidgetsTo(own);
|
|
114
|
+
const holder = marklessRegistryHolder(graph);
|
|
115
|
+
const held = graphRegistries.get(holder);
|
|
116
|
+
if (held) return marklessScopeWidgetsTo(held);
|
|
117
|
+
const registry = {
|
|
118
|
+
rootPaths: /* @__PURE__ */ new Map(),
|
|
119
|
+
rowRooted: /* @__PURE__ */ new Set()
|
|
120
|
+
};
|
|
121
|
+
graphRegistries.set(holder, registry);
|
|
122
|
+
marklessNoteGraphWidgetRoots(registry, graph);
|
|
123
|
+
return marklessScopeWidgetsTo(registry);
|
|
124
|
+
}
|
|
125
|
+
function marklessNoteGraphWidgetRoots(registry, graph) {
|
|
126
|
+
for (const definition of graph.listSharedDefinitions?.() ?? []) if (definition.scope === "widget") {
|
|
127
|
+
const rootPath = marklessInstancePath(definition.id);
|
|
128
|
+
marklessNoteWidgetRoot(registry, definition.id, rootPath);
|
|
129
|
+
for (const projectionId of definition.projectionIds ?? []) marklessNoteWidgetRoot(registry, projectionId, rootPath);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function marklessNoteWidgetRoot(registry, id, rootPath) {
|
|
133
|
+
registry.rootPaths.set(id, rootPath);
|
|
134
|
+
if (rootPath.includes("r:")) registry.rowRooted.add(id.slice(marklessInstancePath(id).length));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The rendered widgets a client-minted repeat row is standing INSIDE.
|
|
138
|
+
*
|
|
139
|
+
* A minted row composes alone, so the registry that render builds holds only the
|
|
140
|
+
* roots the row itself is. A part reading a widget rooted in an ancestor - the
|
|
141
|
+
* collection the repeat iterates, most of all - would find nothing and mint a
|
|
142
|
+
* second instance of it, whose writes no served node ever sees. The mint reads
|
|
143
|
+
* the live page's roots off its graph and installs them here for the row's
|
|
144
|
+
* render; the `rowSegment` guard is what keeps a render running beside it from
|
|
145
|
+
* reading the answer, the same separation `marklessWidgetScope` settles for.
|
|
146
|
+
*/
|
|
147
|
+
const enclosingWidgetScope = {
|
|
148
|
+
rowSegment: "",
|
|
149
|
+
roots: void 0
|
|
150
|
+
};
|
|
151
|
+
function enclosingRootPathFor(graphNodeId, roots) {
|
|
152
|
+
return byDefinition(graphNodeId, (key) => roots.get(key));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The same question asked of a path that may carry rows the ROOT does not.
|
|
156
|
+
*
|
|
157
|
+
* One root per rendered widget means a root inside a repeat is registered under
|
|
158
|
+
* its row and a root outside one is registered without any - but a part
|
|
159
|
+
* projected INTO an outside root from inside the repeat carries the row in its
|
|
160
|
+
* own path regardless. The walk below chops segments off the right, so a leading
|
|
161
|
+
* `r:<key>:` blocks it from ever reaching that root. Rows are asked first, so a
|
|
162
|
+
* per-row root always wins over the row-free reading; only a path no rendered
|
|
163
|
+
* row answers is asked again with its rows dropped.
|
|
164
|
+
*/
|
|
165
|
+
function marklessWidgetRootPathThroughRows(graphNodeId, instancePath, registry) {
|
|
166
|
+
const withRows = widgetRootPathFor(graphNodeId, instancePath, registry);
|
|
167
|
+
if (withRows !== void 0) return withRows;
|
|
168
|
+
const rowFree = instancePath.replace(ROW_SEGMENT, "");
|
|
169
|
+
if (rowFree === instancePath) return "";
|
|
170
|
+
return widgetRootPathFor(graphNodeId, rowFree, registry) ?? "";
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The two spellings of one containment, and the one that has to wait for a row.
|
|
174
|
+
*
|
|
175
|
+
* A widget root is filed under the path it RENDERED at, rows and all
|
|
176
|
+
* (`r:page%3A5:c0:p2:`). A dispatching bound symbol runs at the compose tree's
|
|
177
|
+
* path for that same containment, which names the component edges and no row
|
|
178
|
+
* (`c0:p2:p3:`) - a bound symbol is minted per edge, and a row key is a runtime
|
|
179
|
+
* value no symbol id can hold. Neither spelling is a prefix of the other, so the
|
|
180
|
+
* walk above can never get from one to the other on its own.
|
|
181
|
+
*
|
|
182
|
+
* Leaving the id in page space here is what breaks the projection bridge: the
|
|
183
|
+
* write lands on an id no rendered widget owns, the record matches, the symbol
|
|
184
|
+
* runs, and nothing moves. Keeping the reading path ON the id instead hands the
|
|
185
|
+
* question to `marklessRowWidgetGraphNodeId`, which is spelled for exactly this
|
|
186
|
+
* input - it holds the dispatched record's rows and re-asks the registry with
|
|
187
|
+
* them, reaching the ONE root this row rendered. An alias resolved at lookup,
|
|
188
|
+
* never a second registry entry, so one containment still yields one instance.
|
|
189
|
+
*
|
|
190
|
+
* Two guards keep that from minting a phantom instance instead. The path must
|
|
191
|
+
* carry no row of its own, because a path that already names its rows and STILL
|
|
192
|
+
* found no root is not waiting on one. And the definition must be one some row
|
|
193
|
+
* really did root: an id belonging to no widget at all - a page-scoped
|
|
194
|
+
* `shared()` graph, a storage slot - is page space and stays exactly as spelled.
|
|
195
|
+
*/
|
|
196
|
+
function marklessUnresolvedWidgetGraphNodeId(graphNodeId, instancePath, registry) {
|
|
197
|
+
const rowRooted = registry.rowRooted;
|
|
198
|
+
if (instancePath.includes("r:") || rowRooted.size === 0) return graphNodeId;
|
|
199
|
+
return byDefinition(graphNodeId, (key) => rowRooted.has(key) || void 0) ? instancePath + graphNodeId : graphNodeId;
|
|
200
|
+
}
|
|
201
|
+
function widgetRootPathFor(graphNodeId, instancePath, registry) {
|
|
202
|
+
const widgetRootPaths = registry.rootPaths;
|
|
203
|
+
if (widgetRootPaths.size === 0) return void 0;
|
|
204
|
+
for (let end = instancePath.length; end > 0; end--) {
|
|
205
|
+
if (instancePath[end - 1] !== ":") continue;
|
|
206
|
+
const prefix = instancePath.slice(0, end);
|
|
207
|
+
const rootPath = byDefinition(graphNodeId, (key) => widgetRootPaths.get(prefix + key));
|
|
208
|
+
if (rootPath !== void 0) return rootPath;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function byDefinition(id, lookup) {
|
|
212
|
+
const slash = id.lastIndexOf("/");
|
|
213
|
+
return lookup(id) ?? (slash > 0 ? lookup(id.slice(0, slash)) : void 0);
|
|
214
|
+
}
|
|
215
|
+
function marklessComposedGraphNodeId(graphNodeId, instancePath, registry = marklessWidgetScope.active) {
|
|
216
|
+
if (!instancePath) return graphNodeId;
|
|
217
|
+
const pageSpace = PAGE_SPACE_ID.exec(graphNodeId);
|
|
218
|
+
if (!pageSpace) return instancePath + graphNodeId;
|
|
219
|
+
if (pageSpace[2] === "storage") return graphNodeId;
|
|
220
|
+
if (pageSpace[1]) {
|
|
221
|
+
const sharedId = graphNodeId.slice(pageSpace[1].length);
|
|
222
|
+
return ((!pageSpace[1].includes("r:") && instancePath.includes("r:") ? widgetRootPathFor(sharedId, instancePath + pageSpace[1], registry) : void 0) ?? instancePath + pageSpace[1]) + sharedId;
|
|
223
|
+
}
|
|
224
|
+
const rootPath = marklessWidgetRootPathThroughRows(graphNodeId, instancePath, registry);
|
|
225
|
+
if (rootPath) return rootPath + graphNodeId;
|
|
226
|
+
const enclosing = enclosingWidgetScope.roots && instancePath.startsWith(enclosingWidgetScope.rowSegment) ? enclosingRootPathFor(graphNodeId, enclosingWidgetScope.roots) : void 0;
|
|
227
|
+
if (enclosing) return enclosing + graphNodeId;
|
|
228
|
+
return marklessUnresolvedWidgetGraphNodeId(graphNodeId, instancePath, registry);
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region ../web/src/fns/roster-resume.ts
|
|
232
|
+
/**
|
|
233
|
+
* The roster half that only a resumed page runs, in one module nothing eagerly
|
|
234
|
+
* loaded names. The `import()` specifier is written by the app's own resume
|
|
235
|
+
* module, not here, so a page whose payload carries no computed nodes - and so
|
|
236
|
+
* can hold no roster derivation - never emits this chunk. Both call sites read
|
|
237
|
+
* the loader off `__marklessRosterResume`; an absent loader is a page with
|
|
238
|
+
* nothing to derive.
|
|
239
|
+
*
|
|
240
|
+
* Reaching `instance-scope.ts` statically is what keeps the scoping free: the
|
|
241
|
+
* dispatch core already loads it, so this chunk imports a chunk the page has,
|
|
242
|
+
* instead of turning it into a dynamic entry with a re-export shim of its own.
|
|
243
|
+
*/
|
|
244
|
+
const ELEMENT_BINDING_SEGMENT = "/element:";
|
|
245
|
+
const INSTANCE_SEGMENT = /r:[^:]*:|[cpm]\d+:/g;
|
|
246
|
+
/**
|
|
247
|
+
* Where this part stands in its family's roster, now that there is a DOM: the
|
|
248
|
+
* roster answers its live members in document order and the part's own bound
|
|
249
|
+
* element is one of them.
|
|
250
|
+
*
|
|
251
|
+
* Built only for a derivation that depends on an element() binding, because
|
|
252
|
+
* scoping the roster to THIS rendered widget is what keeps a second collection
|
|
253
|
+
* on the page from answering.
|
|
254
|
+
*/
|
|
255
|
+
function createRosterPositionReader(input) {
|
|
256
|
+
if (!input.computed.dependencies?.some((dependency) => isElementBinding(dependency.graphNodeId))) return void 0;
|
|
257
|
+
const instancePath = marklessInstancePath(input.computed.graphNodeId);
|
|
258
|
+
const rosterOf = marklessInstanceScopedElementHandle(input.elementHandles.get, instancePath, input.graph);
|
|
259
|
+
const scope = hostScopePath(instancePath);
|
|
260
|
+
return (rosterGraphNodeId, handleGraphNodeId) => {
|
|
261
|
+
const roster = rosterOf?.(rosterGraphNodeId);
|
|
262
|
+
const member = oneElement(input.elementHandles.get, scope + handleGraphNodeId) ?? oneElement(input.elementHandles.get, handleGraphNodeId);
|
|
263
|
+
return Array.isArray(roster) && member ? roster.indexOf(member) : -1;
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* How many parts this family instance has in the roster, now that there is a
|
|
268
|
+
* DOM: the roster's own live members. No member handle is needed - a count does
|
|
269
|
+
* not depend on the asker being in the roster.
|
|
270
|
+
*/
|
|
271
|
+
function createRosterCountReader(input) {
|
|
272
|
+
if (!input.computed.dependencies?.some((dependency) => isElementBinding(dependency.graphNodeId))) return void 0;
|
|
273
|
+
const rosterOf = marklessInstanceScopedElementHandle(input.elementHandles.get, marklessInstancePath(input.computed.graphNodeId), input.graph);
|
|
274
|
+
return (rosterGraphNodeId) => {
|
|
275
|
+
const roster = rosterOf?.(rosterGraphNodeId);
|
|
276
|
+
return Array.isArray(roster) ? roster.length : 0;
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The host id space spelling of an instance path, which is the space element
|
|
281
|
+
* handles are registered in.
|
|
282
|
+
*
|
|
283
|
+
* Both spaces number one component edge the same, but only symbol space carries
|
|
284
|
+
* the edge a PROJECTED component was projected into: symbol `c0:p1:` and host
|
|
285
|
+
* `c1:` name one rendered component. So a segment another segment projects out
|
|
286
|
+
* of is dropped, and what is left is respelled as the host's own `c`.
|
|
287
|
+
*/
|
|
288
|
+
function hostScopePath(instancePath) {
|
|
289
|
+
const segments = instancePath.match(INSTANCE_SEGMENT) ?? [];
|
|
290
|
+
let scope = "";
|
|
291
|
+
for (let at = 0; at < segments.length; at++) {
|
|
292
|
+
const segment = segments[at];
|
|
293
|
+
if (!segment.startsWith("m") && segments[at + 1]?.startsWith("p")) continue;
|
|
294
|
+
scope += segment.startsWith("p") ? "c" + segment.slice(1) : segment;
|
|
295
|
+
}
|
|
296
|
+
return scope;
|
|
297
|
+
}
|
|
298
|
+
function oneElement(get, key) {
|
|
299
|
+
try {
|
|
300
|
+
const value = get(key);
|
|
301
|
+
return Array.isArray(value) ? void 0 : value;
|
|
302
|
+
} catch {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* After resume the roster is live, and a part's place in it changes when a row
|
|
308
|
+
* arrives, leaves or moves. Nothing else writes an element() binding node and
|
|
309
|
+
* every reader of one answers from the handle registry, so the binding's cell
|
|
310
|
+
* carries a revision: bumping it is how the parts deriving a place in that
|
|
311
|
+
* roster are told to derive it again.
|
|
312
|
+
*
|
|
313
|
+
* A keyed repeat's collection write is one channel; an `@if` arm adopting or
|
|
314
|
+
* dropping its host elements is the other, and it writes no collection at all,
|
|
315
|
+
* so the journal is the only thing that reports it.
|
|
316
|
+
*
|
|
317
|
+
* Resume is itself the first revision. A render answers a place from emission
|
|
318
|
+
* order and paints it, but the number never reaches the derivation's graph cell,
|
|
319
|
+
* so an expression that SPENDS the place - `code.slice(pos, pos + 1)` - reads
|
|
320
|
+
* `undefined` the first time it re-derives. Deriving once against the live
|
|
321
|
+
* roster puts the number in the cell before anything asks for it.
|
|
322
|
+
*/
|
|
323
|
+
function wireRosterRevisions(input) {
|
|
324
|
+
const rosters = /* @__PURE__ */ new Set();
|
|
325
|
+
for (const record of input.computed) for (const dependency of record.dependencies ?? []) if (isElementBinding(dependency.graphNodeId)) rosters.add(dependency.graphNodeId);
|
|
326
|
+
if (rosters.size === 0) return;
|
|
327
|
+
const bump = () => {
|
|
328
|
+
for (const roster of rosters) {
|
|
329
|
+
const revision = input.graph.read(roster, []);
|
|
330
|
+
input.graph.write({
|
|
331
|
+
graphNodeId: roster,
|
|
332
|
+
value: (typeof revision === "number" ? revision : 0) + 1
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
for (const repeat of input.keyedRepeats) {
|
|
337
|
+
const collection = repeat.collectionGraphNodeId;
|
|
338
|
+
if (!collection) continue;
|
|
339
|
+
input.storeContainerSubscription(input.graph.subscribe({
|
|
340
|
+
id: `roster-revision:${repeat.id}:${collection}`,
|
|
341
|
+
graphNodeId: collection,
|
|
342
|
+
path: repeat.collectionPath,
|
|
343
|
+
run: bump
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
input.storeContainerSubscription(input.graph.subscribeJournal((entries) => {
|
|
347
|
+
if (entries.some((entry) => entry.locator.startsWith("branch:"))) bump();
|
|
348
|
+
}));
|
|
349
|
+
bump();
|
|
350
|
+
}
|
|
351
|
+
function isElementBinding(graphNodeId) {
|
|
352
|
+
return graphNodeId.includes(ELEMENT_BINDING_SEGMENT);
|
|
353
|
+
}
|
|
354
|
+
const DEFERRED_COUNT = new RegExp(`(\\d+)(?:([^]*))?`, "g");
|
|
355
|
+
const ROSTER_COUNT_KEY = new RegExp(`^([^]*)$`);
|
|
356
|
+
const ROSTER_COUNT = new RegExp(`([^]*)`, "g");
|
|
357
|
+
/**
|
|
358
|
+
* Every placeholder count a render minted, answered from the page it produced:
|
|
359
|
+
* the roster's members are its element-handle registrations, and composition has
|
|
360
|
+
* already qualified each one with the rendered widget it belongs to.
|
|
361
|
+
*
|
|
362
|
+
* This is the render half, and it lives here because it is the same pay-per-use
|
|
363
|
+
* fact the resume half is: a page whose payload holds no computed node can hold
|
|
364
|
+
* no count, and never names this module.
|
|
365
|
+
*
|
|
366
|
+
* The payload is answered alongside the html because a computed a handler reads
|
|
367
|
+
* is SERVED with its rendered value, and a placeholder there would outlive paint.
|
|
368
|
+
*/
|
|
369
|
+
function marklessResolveRosterCounts(surface) {
|
|
370
|
+
const handles = surface.view?.elementHandles ?? [];
|
|
371
|
+
const answer = (text) => text.replace(ROSTER_COUNT, (_all, key) => String(handles.filter((handle) => handle.handleId === key).length));
|
|
372
|
+
return {
|
|
373
|
+
...surface,
|
|
374
|
+
html: answer(surface.html),
|
|
375
|
+
...surface.state === void 0 ? {} : { state: answered(surface.state, answer) }
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* The expressions this render handed over unevaluated, answered from the page it
|
|
380
|
+
* produced.
|
|
381
|
+
*
|
|
382
|
+
* A count is a placeholder while the render is still emitting the members it
|
|
383
|
+
* counts, so an expression that SPENDS one - `count - 1`, `step >= count - 1` -
|
|
384
|
+
* is registered as a thunk and printed as a token. Composition has since made
|
|
385
|
+
* the counts facts, so each thunk runs with a reader that turns the placeholder
|
|
386
|
+
* it captured into the number, and the answer is spliced over its token.
|
|
387
|
+
*
|
|
388
|
+
* A token standing for a whole ATTRIBUTE carries the name: for a boolean
|
|
389
|
+
* attribute presence is the value, so an expression answering false has to
|
|
390
|
+
* erase the name and the quotes, not write `disabled="false"`.
|
|
391
|
+
*
|
|
392
|
+
* Runs before the placeholder resolver, and off the same tally: both read the
|
|
393
|
+
* roster's members as its element-handle registrations.
|
|
394
|
+
*/
|
|
395
|
+
function marklessResolveDeferredCounts(surface, deferred) {
|
|
396
|
+
if (deferred.length === 0) return surface;
|
|
397
|
+
const handles = surface.view?.elementHandles ?? [];
|
|
398
|
+
const count = (placeholder) => {
|
|
399
|
+
const key = ROSTER_COUNT_KEY.exec(String(placeholder ?? ""))?.[1];
|
|
400
|
+
if (key === void 0) throw new Error("MARKLESS_ROSTER_COUNT_UNRESOLVED");
|
|
401
|
+
return handles.filter((handle) => handle.handleId === key).length;
|
|
402
|
+
};
|
|
403
|
+
const html = surface.html.replace(DEFERRED_COUNT, (all, index, name) => {
|
|
404
|
+
const thunk = deferred[Number(index)];
|
|
405
|
+
if (!thunk) return all;
|
|
406
|
+
const value = thunk(count);
|
|
407
|
+
if (name === void 0) return value == null ? "" : escapeHtml(String(value));
|
|
408
|
+
const text = marklessAttributeValue(name, value);
|
|
409
|
+
return text === null ? "" : ` ${name}="${escapeHtml(text)}"`;
|
|
410
|
+
});
|
|
411
|
+
return html === surface.html ? surface : {
|
|
412
|
+
...surface,
|
|
413
|
+
html
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function escapeHtml(value) {
|
|
417
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
418
|
+
}
|
|
419
|
+
function answered(value, answer) {
|
|
420
|
+
if (typeof value === "string") return answer(value);
|
|
421
|
+
if (!value || typeof value !== "object") return value;
|
|
422
|
+
const held = Object.entries(value).map(([key, one]) => [key, answered(one, answer)]);
|
|
423
|
+
if (!held.some(([key, one]) => one !== value[key])) return value;
|
|
424
|
+
return Array.isArray(value) ? held.map(([, one]) => one) : Object.fromEntries(held);
|
|
425
|
+
}
|
|
426
|
+
//#endregion
|
|
427
|
+
export { createRosterCountReader, createRosterPositionReader, marklessResolveDeferredCounts, marklessResolveRosterCounts, wireRosterRevisions };
|