@markless/bundler 0.4.0 → 0.6.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.
@@ -1,8 +1,10 @@
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-BuooJg32.js";
2
- import { i as resumeVirtualModuleId, n as prerenderWakeVirtualModuleId, t as MARKLESS_VIRTUAL_PREFIX } from "./source-module-XFgOFX1c.js";
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-iOUoceJ-.js";
2
+ import { a as resumeVirtualModuleId, n as MARKLESS_VIRTUAL_PREFIX, r as prerenderWakeVirtualModuleId } from "./execution-log-BL-7a77M.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;
@@ -13,9 +15,11 @@ type BuiltPrerenderRecords = {
13
15
  type Environment = MarklessEnvironment | ((context: unknown) => MarklessEnvironment);
14
16
  //#endregion
15
17
  //#region src/build/chunking.d.ts
16
- declare const MARKLESS_BUILD_PREFIX = "build/";
17
- declare const MARKLESS_BUNDLE_GRAPH = "build/bundle-graph.json";
18
- declare function outputDefaults(output: OutputOptions, environment: MarklessEnvironment): OutputOptions;
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 const MARKLESS_PUBLIC_BUILD_METADATA_FILES: readonly ["build/execution-sizes.json"];
22
+ export declare function outputDefaults(output: OutputOptions, environment: MarklessEnvironment): OutputOptions;
19
23
  //#endregion
20
24
  //#region src/build/build-metadata.d.ts
21
25
  type MarklessBuildMetadataBundle = Record<string, MarklessBuildMetadataBundleItem>;
@@ -41,7 +45,7 @@ interface MarklessBuildMetadataChunk {
41
45
  importedCss?: ReadonlySet<string> | readonly string[];
42
46
  };
43
47
  }
44
- declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transformManifests: Iterable<MarklessTransformManifest>, root: string | undefined, options?: {
48
+ export declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transformManifests: Iterable<MarklessTransformManifest>, root: string | undefined, options?: {
45
49
  bundleGraphAsset?: string;
46
50
  bundleGraphAdders?: Set<BundleGraphAdder>;
47
51
  canonPath?: (fileName: string) => string;
@@ -50,8 +54,8 @@ declare function createBuildMetadata(bundle: MarklessBuildMetadataBundle, transf
50
54
  }): MarklessBuildMetadata;
51
55
  //#endregion
52
56
  //#region src/build/bundle-graph.d.ts
53
- declare function convertManifestToBundleGraph(manifest: MarklessBuildMetadata, bundleGraphAdders?: Set<BundleGraphAdder>): MarklessBundleGraph;
54
- declare function createPreloadGraphAdder(addEntries: PreloadGraphEntriesAdder): BundleGraphAdder;
57
+ export declare function convertManifestToBundleGraph(manifest: MarklessBuildMetadata, bundleGraphAdders?: Set<BundleGraphAdder>): MarklessBundleGraph;
58
+ export declare function createPreloadGraphAdder(addEntries: PreloadGraphEntriesAdder): BundleGraphAdder;
55
59
  //#endregion
56
60
  //#region src/build/head-links.d.ts
57
61
  type HeadLinkBundle = Record<string, HeadLinkBundleItem>;
@@ -66,24 +70,40 @@ interface HeadLinkChunk {
66
70
  importedCss?: ReadonlySet<string> | readonly string[];
67
71
  };
68
72
  }
69
- declare function collectHeadLinkInjections(bundle: HeadLinkBundle, options?: {
73
+ export declare function collectHeadLinkInjections(bundle: HeadLinkBundle, options?: {
70
74
  publicPath?: (fileName: string) => string;
71
75
  }): GlobalInjections[];
72
76
  //#endregion
77
+ //#region src/build/build-manifests.d.ts
78
+ /** Where build-time hand-off files for a client output live: beside it, never inside the directory a host serves. */
79
+ export declare function marklessBuildManifestDir(clientOutDir: string): string;
80
+ /** Where a build metadata file such as `build/bundle-graph.json` lands for a client output. */
81
+ export declare function marklessBuildManifestPath(clientOutDir: string, metadataFile: string): string;
82
+ /** The chunk import map a packed client build hands to the server that renders its documents. */
83
+ export declare function marklessImportMapPath(clientOutDir: string): string;
84
+ //#endregion
85
+ //#region src/build/content-hash-names.d.ts
86
+ export declare const MARKLESS_IMPORT_MAP_ASSET = ".vite/markless-import-map.json";
87
+ export declare const MARKLESS_CHUNK_SPECIFIER_PREFIX = "@markless/c/";
88
+ export declare function importMapScript(importMap: {
89
+ readonly imports: Record<string, string>;
90
+ }): string;
91
+ export declare function insertImportMapScript(html: string, script: string): string;
92
+ //#endregion
73
93
  //#region src/transform.d.ts
74
- declare function transformTsrxModule(input: TransformTsrxModuleInput): Promise<TransformTsrxModuleResult>;
94
+ export declare function transformTsrxModule(input: TransformTsrxModuleInput): Promise<TransformTsrxModuleResult>;
75
95
  //#endregion
76
96
  //#region src/rolldown.d.ts
77
- type MarklessRolldownPlugin = Plugin & {
97
+ export type MarklessRolldownPlugin = Plugin & {
78
98
  api: MarklessRolldownPluginApi;
79
99
  };
80
- declare const marklessClient: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
81
- declare const marklessServer: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
82
- declare const marklessLib: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
83
- declare function createMarklessRolldownPlugin(input: {
100
+ export declare const marklessClient: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
101
+ export declare const marklessServer: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
102
+ export declare const marklessLib: (options?: MarklessRolldownOptions) => MarklessRolldownPlugin;
103
+ export declare function createMarklessRolldownPlugin(input: {
84
104
  environment: Environment;
85
105
  options?: MarklessRolldownOptions;
86
106
  prerenderRecordsBySource?: ReadonlyMap<string, BuiltPrerenderRecords>;
87
107
  }): MarklessRolldownPlugin;
88
108
  //#endregion
89
- export { type BundleGraphAdder, type GlobalInjections, MARKLESS_BUILD_PREFIX, MARKLESS_BUNDLE_GRAPH, MARKLESS_VIRTUAL_PREFIX, type MarklessAsset, type MarklessBuildMetadata, type MarklessBundle, type MarklessBundleGraph, type MarklessDevServer, type MarklessEnvironment, type MarklessManifest, type MarklessRolldownOptions, MarklessRolldownPlugin, type MarklessRolldownPluginApi, type MarklessTransformManifest, type MarklessVirtualModule, type PreloadGraphContext, type PreloadGraphEntries, type PreloadGraphEntriesAdder, type TransformTsrxModuleInput, type TransformTsrxModuleResult, collectHeadLinkInjections, convertManifestToBundleGraph, createBuildMetadata, createMarklessRolldownPlugin, createPreloadGraphAdder, marklessClient, marklessLib, marklessServer, outputDefaults, prerenderWakeVirtualModuleId, resumeVirtualModuleId, transformTsrxModule };
109
+ 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 { l as resumeVirtualModuleId, s as prerenderWakeVirtualModuleId, t as MARKLESS_VIRTUAL_PREFIX } from "./source-module-DI20i0ZG.js";
2
- import { a as createBuildMetadata, c as createPreloadGraphAdder, d as MARKLESS_BUILD_PREFIX, f as MARKLESS_BUNDLE_GRAPH, i as marklessServer, n as marklessClient, o as collectHeadLinkInjections, p as outputDefaults, r as marklessLib, s as convertManifestToBundleGraph, t as createMarklessRolldownPlugin, u as transformTsrxModule } from "./rolldown-CB2Xpf-E.js";
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 { $ as MARKLESS_BUNDLE_GRAPH, Q as MARKLESS_BUILD_PREFIX, Z as MARKLESS_BUILD_METADATA_FILES, at as outputDefaults, gt as prerenderWakeVirtualModuleId, it as MARKLESS_PUBLIC_BUILD_METADATA_FILES, ot as MARKLESS_VIRTUAL_PREFIX, vt as resumeVirtualModuleId } from "./route-pack-groups-BXc755qH.js";
2
+ import { C as MARKLESS_IMPORT_MAP_ASSET, O as transformTsrxModule, S as MARKLESS_CHUNK_SPECIFIER_PREFIX, T as insertImportMapScript, _ as createPreloadGraphAdder, b as marklessBuildManifestPath, c as collectHeadLinkInjections, g as convertManifestToBundleGraph, i as marklessServer, n as marklessClient, r as marklessLib, s as createBuildMetadata, t as createMarklessRolldownPlugin, w as importMapScript, x as marklessImportMapPath, y as marklessBuildManifestDir } from "./rolldown-DHkCX7vL.js";
3
+ export { MARKLESS_BUILD_METADATA_FILES, MARKLESS_BUILD_PREFIX, MARKLESS_BUNDLE_GRAPH, MARKLESS_CHUNK_SPECIFIER_PREFIX, MARKLESS_IMPORT_MAP_ASSET, MARKLESS_PUBLIC_BUILD_METADATA_FILES, MARKLESS_VIRTUAL_PREFIX, collectHeadLinkInjections, convertManifestToBundleGraph, createBuildMetadata, createMarklessRolldownPlugin, createPreloadGraphAdder, importMapScript, insertImportMapScript, marklessBuildManifestDir, marklessBuildManifestPath, 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("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
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 };