@markless/bundler 0.4.0 → 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.
@@ -1,1168 +0,0 @@
1
- import { joinURL } from "ufo";
2
- import { ASYNC_PROTOCOL_VERSION } from "@markless/serializer";
3
- //#region src/build/preload-plan.ts
4
- const DEFAULT_MIN_PROBABILITY = 0;
5
- const JAVASCRIPT_MODULE_RE = /\.(?:mjs|js)(?:[?#].*)?$/;
6
- const PRIORITY_RANK = {
7
- high: 2,
8
- auto: 1,
9
- low: 0
10
- };
11
- function planModulePreloadUrls(input) {
12
- return planModulePreloads(input).map((preload) => preload.href);
13
- }
14
- function planModulePreloads(input) {
15
- const minProbability = input.minProbability ?? DEFAULT_MIN_PROBABILITY;
16
- const maxPreloads = input.maxPreloads ?? Number.POSITIVE_INFINITY;
17
- const graph = parseBundleGraph(input.bundleGraph);
18
- const planned = /* @__PURE__ */ new Map();
19
- const bestVisitByNode = /* @__PURE__ */ new Map();
20
- let order = 0;
21
- const addModule = (name, probability, priority, fetchPriority) => {
22
- if (!isPreloadableModuleName(name)) return;
23
- const href = preloadHref(input.base, name);
24
- const existing = planned.get(href);
25
- const nextRank = PRIORITY_RANK[priority];
26
- const existingRank = existing ? PRIORITY_RANK[existing.priority] : -1;
27
- if (existing && (existingRank > nextRank || existingRank === nextRank && existing.probability >= probability)) return;
28
- planned.set(href, {
29
- fetchPriority,
30
- href,
31
- name,
32
- order: existing?.order ?? order++,
33
- priority,
34
- probability
35
- });
36
- };
37
- const visit = (name, probability, priority, fetchPriority, seen, suppressed = false, suppressRootOnly = false) => {
38
- if (probability < minProbability || planned.size >= maxPreloads) return;
39
- if (!suppressed) {
40
- const priorityRank = PRIORITY_RANK[priority];
41
- const previousBest = bestVisitByNode.get(name);
42
- if (previousBest && (previousBest.priorityRank > priorityRank || previousBest.priorityRank === priorityRank && previousBest.probability >= probability)) return;
43
- bestVisitByNode.set(name, {
44
- priorityRank,
45
- probability
46
- });
47
- }
48
- if (seen.has(name)) return;
49
- const nextSeen = new Set(seen);
50
- nextSeen.add(name);
51
- const record = graph.get(name);
52
- if (!record) {
53
- if (!suppressed) addModule(name, probability, priority, fetchPriority);
54
- return;
55
- }
56
- for (const dep of record.deps.filter((item) => item.kind === "static")) visit(dep.name, probability * dep.probability, priority, fetchPriority, nextSeen, suppressed && !suppressRootOnly);
57
- if (!suppressed) addModule(name, probability, priority, fetchPriority);
58
- for (const dep of record.deps.filter((item) => item.kind === "dynamic")) {
59
- const edgeProbability = JAVASCRIPT_MODULE_RE.test(name) ? dep.probability : 1;
60
- visit(dep.name, probability * edgeProbability, priority, fetchPriority, nextSeen, false);
61
- }
62
- };
63
- for (const root of input.roots) {
64
- const normalized = normalizeRoot(root);
65
- visit(normalized.name, 1, normalized.priority, normalized.fetchPriority, /* @__PURE__ */ new Set(), normalized.edges === "dynamic-only" || normalized.edges === "dependencies-only", normalized.edges === "dependencies-only");
66
- }
67
- return [...planned.values()].sort((left, right) => {
68
- const priority = PRIORITY_RANK[right.priority] - PRIORITY_RANK[left.priority];
69
- if (priority !== 0) return priority;
70
- return left.order - right.order;
71
- }).slice(0, maxPreloads).map(({ order: _order, ...preload }) => preload);
72
- }
73
- function parseBundleGraph(graph) {
74
- const records = /* @__PURE__ */ new Map();
75
- if (!graph) return records;
76
- let index = 0;
77
- while (index < graph.length) {
78
- const name = graph[index++];
79
- if (typeof name !== "string") continue;
80
- const deps = [];
81
- let probability = 1;
82
- let kind = "static";
83
- while (typeof graph[index] === "number") {
84
- const marker = graph[index++];
85
- if (marker < 0) {
86
- probability = -marker / 10;
87
- kind = "dynamic";
88
- continue;
89
- }
90
- const dep = graph[marker];
91
- if (typeof dep === "string") deps.push({
92
- name: dep,
93
- kind,
94
- probability
95
- });
96
- }
97
- records.set(name, {
98
- name,
99
- deps
100
- });
101
- }
102
- return records;
103
- }
104
- function preloadHref(base, name) {
105
- if (!base || /^(?:[a-z]+:)?\/\//i.test(name)) return name;
106
- return joinURL(base, name);
107
- }
108
- function isPreloadableModuleName(name) {
109
- return JAVASCRIPT_MODULE_RE.test(name) || isViteDevModuleUrl(name);
110
- }
111
- function isViteDevModuleUrl(name) {
112
- return (name.startsWith("/") || name.startsWith("@id/")) && /(?:^|[?&])import(?:[&#]|$)/.test(name);
113
- }
114
- function normalizeRoot(root) {
115
- if (typeof root === "string") return {
116
- name: root,
117
- priority: "auto",
118
- fetchPriority: "auto"
119
- };
120
- const priority = root.priority ?? "auto";
121
- return {
122
- name: root.name,
123
- priority,
124
- edges: root.edges,
125
- fetchPriority: root.fetchPriority ?? priorityToFetchPriority(priority)
126
- };
127
- }
128
- function priorityToFetchPriority(priority) {
129
- if (priority === "auto") return "auto";
130
- return priority;
131
- }
132
- //#endregion
133
- //#region src/execution-log.ts
134
- const MARKLESS_EXECUTION_LOG_MODULE_ID = "virtual:markless:dev-log";
135
- const EXECUTION_LOG_DISPATCH_MODULE_IDS = ["web:render-csr", "web:resume-events"];
136
- const MARKLESS_EXECUTION_LEDGER_GLOBAL = "__marklessExecutionLedger";
137
- const MARKLESS_EXECUTION_LEDGER_INIT = "{ unit: 'chunk-raw-bytes', load: { app: 0, framework: 0, instrument: 0, inline: 0, modules: [] }, total: { app: 0, framework: 0, instrument: 0, inline: 0 }, turns: [], incomplete: null }";
138
- const EXECUTION_LOG_GESTURE_EVENTS = [
139
- "pointerdown",
140
- "touchstart",
141
- "keydown"
142
- ];
143
- const EXECUTION_LOG_FRAMEWORK_ID_PATTERN = "/^(?:web|runtime|serializer|router|core|analyzer):/";
144
- function normalizeExecutionLogMode(mode) {
145
- return mode ?? "auto";
146
- }
147
- function injectExecutionLogModuleHook(source, moduleId, mode) {
148
- if (normalizeExecutionLogMode(mode) === "never") return source;
149
- return `globalThis.__mxLog?.add(${JSON.stringify(moduleId)});\n${source}`;
150
- }
151
- const EXECUTION_LOG_HOOK_LINE = /^globalThis\.__mxLog\?\.add\("(?:[^"\\]|\\.)*"\);\n/;
152
- function hasExecutionLogModuleHook(source) {
153
- return EXECUTION_LOG_HOOK_LINE.test(source);
154
- }
155
- function requalifyExecutionLogModuleHook(source, moduleId) {
156
- if (!EXECUTION_LOG_HOOK_LINE.test(source)) return source;
157
- return source.replace(EXECUTION_LOG_HOOK_LINE, `globalThis.__mxLog?.add(${JSON.stringify(moduleId)});\n`);
158
- }
159
- function executionLogVirtualModuleSource(options = {}) {
160
- if (!options.moduleSizes) return executionLogVirtualModuleSourceWithOwnSize(options, null);
161
- return executionLogVirtualModuleSourceWithOwnSize(options, executionLogVirtualModuleSourceWithOwnSize(options, 0).length);
162
- }
163
- function executionLogVirtualModuleSourceWithOwnSize(options, ownRawSize) {
164
- const moduleSizes = options.moduleSizes ? Object.fromEntries([...[...options.moduleSizes].map(([id, raw]) => [id, {
165
- raw,
166
- estimated: true
167
- }]), [MARKLESS_EXECUTION_LOG_MODULE_ID, {
168
- raw: ownRawSize ?? 0,
169
- estimated: true,
170
- instrument: true
171
- }]]) : null;
172
- return `
173
- globalThis.__mxLog?.add(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)});
174
- const marklessDefaultModuleSizes = ${JSON.stringify(moduleSizes)};
175
- const marklessDefaultAttribution = ${JSON.stringify(options.attribution ?? null)};
176
- const marklessSizesUrl = ${JSON.stringify(options.sizesUrl ?? null)};
177
- let marklessSizesPromise;
178
- let marklessAttribution;
179
- let marklessInstallPromise;
180
- let marklessRenderSummaryTurn;
181
- function modules(log) { return log ? [...log] : []; }
182
- function sizeRecord(input) { return !input ? undefined : typeof input === 'number' ? { raw: input, estimated: true } : input; }
183
- function normalizeSizes(input) { if (!input) return undefined; const map = new Map(); for (const id of Object.keys(input)) if (id !== 'attribution' && id !== 'unshipped') map.set(id, sizeRecord(input[id])); return map; }
184
- async function loadModuleSizes(input) {
185
- if (input.moduleSizes) return normalizeSizes(input.moduleSizes);
186
- if (marklessDefaultModuleSizes) { marklessAttribution = marklessDefaultAttribution; return normalizeSizes(marklessDefaultModuleSizes); }
187
- if (!marklessSizesUrl) return undefined;
188
- marklessSizesPromise ||= fetch(marklessSizesUrl).then((response) => response.ok ? response.json() : undefined).then((payload) => { marklessAttribution = payload && payload.attribution; return normalizeSizes(payload); }).catch(() => undefined);
189
- return marklessSizesPromise;
190
- }
191
- function symbolParts(id) { const match = /^virtual:markless:symbol:([^:]+):([^:]+)$/.exec(id); if (!match) return null; try { return { source: decodeURIComponent(match[1]), symbolId: decodeURIComponent(match[2]) }; } catch { return null; } }
192
- function baseSymbolId(id) { if (!id.startsWith('bound:')) return null; const separator = id.indexOf(':', 'bound:'.length); if (separator < 0) return null; try { return decodeURIComponent(id.slice('bound:'.length, separator)); } catch { return null; } }
193
- function routeFile() { const text = document.querySelector?.('script[type="@markless/core/route"]')?.textContent; if (!text) return null; try { const value = JSON.parse(text).file; return typeof value === 'string' ? value : null; } catch { return null; } }
194
- // Attribution tables are keyed by the bare path this lookup can name: the
195
- // document's route file, or — for a routeless page — the build's single root,
196
- // which is the only page it can be.
197
- function attributionScopes(tables) { if (!tables) return undefined; const route = routeFile(); if (route) { if (route.includes('..') || route.includes('\\\\')) return undefined; const canonical = route.replace(/^\\/+/, ''); return Object.prototype.hasOwnProperty.call(tables, canonical) ? tables[canonical] : undefined; } const roots = Object.keys(tables); return roots.length === 1 ? tables[roots[0]] : undefined; }
198
- // A handler renders inside one component but is owned by whichever component
199
- // created the closure — a prop-passed onClick renders at the child's scope and
200
- // belongs to the parent. The owner is therefore somewhere on the host's render
201
- // ancestry, so once the host's OWN scope is one the table names, the chain is
202
- // walked outward and the first scope holding exactly one candidate wins. Never a
203
- // guess: a host in a scope the table does not name is refused outright, a scope
204
- // with zero or several candidates is skipped, and an id nobody owns uniquely
205
- // stays unmapped.
206
- function scopeChain(scope) { const chain = []; for (let current = scope; ; ) { chain.push(current); if (!current) return chain; const next = current.replace(/c\\d+:$/, ''); if (next === current) return chain; current = next; } }
207
- function qualifySymbolIds(ids, hostNodeId, sizes, tables) { const scopes = attributionScopes(tables); if (!scopes) return ids; const host = /^((?:c\\d+:)*)[^:]+$/.exec(hostNodeId); const hostScope = host && host[1]; return ids.map((id) => { const own = /^((?:c\\d+:)+)(.*)$/.exec(id); const scope = own ? own[1] : hostScope; if (scope === null || scope === undefined || !Object.prototype.hasOwnProperty.call(scopes, scope)) return id; const local = own ? own[2] : id; const base = baseSymbolId(local); const sizeSymbolId = base || local; if (!sizeSymbolId.startsWith('symbol:')) return id; for (const candidate of scopeChain(scope)) { if (!Object.prototype.hasOwnProperty.call(scopes, candidate)) continue; const matches = [...(sizes?.keys() || [])].filter((key) => { const match = /^virtual:markless:symbol:([^:]+):([^:]+)$/.exec(key); if (!match || match[1] !== scopes[candidate]) return false; try { return decodeURIComponent(match[2]) === sizeSymbolId; } catch { return false; } }); if (matches.length !== 1) continue; if (!base) return matches[0]; const match = /^virtual:markless:symbol:([^:]+):/.exec(matches[0]); return match ? 'virtual:markless:symbol:' + match[1] + ':' + encodeURIComponent(local) : id; } return id; }); }
208
- function canonicalId(id, sizes) {
209
- if (!sizes || sizes.has(id)) return id;
210
- const qualified = symbolParts(id); const local = qualified ? qualified.symbolId : id.replace(/^(?:c\\d+:)+/, ''); const sizeSymbolId = baseSymbolId(local) || local;
211
- if (!sizeSymbolId.startsWith('symbol:')) return id;
212
- const matches = [...sizes.keys()].filter((key) => { const parts = symbolParts(key); return !!parts && parts.symbolId === sizeSymbolId && (!qualified || parts.source === qualified.source); });
213
- return matches.length === 1 ? matches[0] : id;
214
- }
215
- function displayId(id) { const parts = symbolParts(id); return parts ? parts.symbolId + ' (' + (parts.source.split('/').pop() || parts.source) + ')' : id; }
216
- function displayObservedId(id, sizes) { const parts = symbolParts(id); return displayId(baseSymbolId(parts ? parts.symbolId : id) ? id : canonicalId(id, sizes)); }
217
- function accounting(items, sizes) {
218
- const ids = [...new Set(items.map((id) => canonicalId(id, sizes)))];
219
- if (!sizes) return { appBytes: ids.length ? null : 0, instrumentBytes: 0, appModules: ids.length, instrumentModules: 0, estimated: { app: false, instrument: false }, unmappedIds: [] };
220
- let appBytes = 0, instrumentBytes = 0, appModules = 0, instrumentModules = 0, appEstimated = false, instrumentEstimated = false; const unmappedIds = [];
221
- for (const id of ids) { const record = sizes.get(id); if (!record) { appModules++; unmappedIds.push(id); continue; } const bytes = record.raw; if (record.instrument) { instrumentModules++; instrumentBytes += bytes; instrumentEstimated ||= !!record.estimated; } else { appModules++; appBytes += bytes; appEstimated ||= !!record.estimated; } }
222
- return { appBytes: unmappedIds.length ? null : appBytes, instrumentBytes, appModules, instrumentModules, estimated: { app: appEstimated, instrument: instrumentEstimated }, unmappedIds };
223
- }
224
- function rowKb(items, sizes) { const a = accounting(items, sizes); if (a.unmappedIds.length) return 'bytes unknown'; const total = (a.appBytes || 0) + (a.instrumentBytes || 0); return (total / 1024).toFixed(1) + ' KB' + (a.estimated.app || a.estimated.instrument ? ' est. source' : ''); }
225
- // One cumulative ledger owns every number the console prints. A module's charge
226
- // is the whole raw byte length of the chunk that absorbed it (several modules in
227
- // one chunk are each charged the whole chunk), which is what unit says.
228
- function marklessLedger() { return (globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} ||= ${MARKLESS_EXECUTION_LEDGER_INIT}); }
229
- function ledgerCategory(id, record) { return record && record.instrument ? 'instrument' : ${EXECUTION_LOG_FRAMEWORK_ID_PATTERN}.test(id) ? 'framework' : 'app'; }
230
- function ledgerCharge(l, ids, sizes) {
231
- const seen = (l.chargedIds ||= new Set());
232
- const seenChunks = (l.chargedChunks ||= new Set());
233
- const delta = { app: 0, framework: 0, instrument: 0, gzip: 0, modules: [], unmapped: [] };
234
- for (const raw of ids) {
235
- const id = canonicalId(raw, sizes);
236
- const record = sizes && sizes.get(id);
237
- // The unit is the chunk, so the dedupe unit is the chunk: one chunk reached
238
- // under two names (a symbol id and the emitted specifier Rolldown rewrote
239
- // its hook to) is one charge, not two. Dev estimates carry no chunk, so
240
- // there the id is still the unit.
241
- const chunk = record && record.chunk;
242
- if (chunk ? seenChunks.has(chunk) : seen.has(id)) continue;
243
- if (chunk) seenChunks.add(chunk); else seen.add(id);
244
- if (!record) { delta.unmapped.push(id); continue; }
245
- if (record.estimated) l.unit = 'estimated-source-bytes';
246
- delta[ledgerCategory(id, record)] += record.raw; delta.gzip += record.gzip || 0; delta.modules.push(id);
247
- }
248
- if (delta.unmapped.length) l.incomplete = { reason: 'unmapped-id', ids: [...new Set([...(l.incomplete ? l.incomplete.ids : []), ...delta.unmapped])] };
249
- return delta;
250
- }
251
- // Load is everything charged before the FIRST USER GESTURE, which the activation
252
- // script latches on the gesture itself (loadClosed) rather than on the kind of
253
- // whichever turn reports first. On an SSR page nothing runs until the click, and
254
- // the instrument and the wake entry both arrive with it; their render/resume
255
- // turns are work that gesture caused, so their charge joins the gesture's turn —
256
- // merged into it if it already exists, carried until it does if it does not.
257
- function ledgerApply(l, kind, label, delta) {
258
- const gesture = kind !== 'render' && kind !== 'resume';
259
- if (gesture) l.loadClosed = true;
260
- for (const name of ['app', 'framework', 'instrument']) { l.total[name] += delta[name]; if (!l.loadClosed) l.load[name] += delta[name]; }
261
- l.totalGzip = (l.totalGzip || 0) + delta.gzip;
262
- if (!l.loadClosed) { l.loadGzip = (l.loadGzip || 0) + delta.gzip; for (const id of delta.modules) l.load.modules.push(id); }
263
- if (!gesture && l.loadClosed) {
264
- const open = l.open;
265
- if (open) { open.delta.app += delta.app; open.delta.framework += delta.framework; open.delta.instrument += delta.instrument; for (const id of delta.modules) open.modules.push(id); return open; }
266
- const held = (l.carry ||= { app: 0, framework: 0, instrument: 0, modules: [] });
267
- held.app += delta.app; held.framework += delta.framework; held.instrument += delta.instrument; for (const id of delta.modules) held.modules.push(id);
268
- delta = { app: 0, framework: 0, instrument: 0, modules: [] };
269
- }
270
- const carry = gesture ? l.carry : undefined;
271
- if (carry) l.carry = undefined;
272
- const turn = { kind, label, delta: { app: delta.app + (carry ? carry.app : 0), framework: delta.framework + (carry ? carry.framework : 0), instrument: delta.instrument + (carry ? carry.instrument : 0) }, modules: carry ? [...carry.modules, ...delta.modules] : delta.modules };
273
- l.turns.push(turn); if (gesture) l.open = turn;
274
- return turn;
275
- }
276
- function ledgerKb(bytes) { return (bytes / 1024).toFixed(1) + ' KB'; }
277
- // The instrument is dev-only weight, so it stays out of the headline totals and
278
- // keeps its own category, exactly as the pre-ledger lines did.
279
- function ledgerVisible(part) { return part.app + part.framework + part.inline; }
280
- function ledgerLine(l, turn) {
281
- let line = 'markless: ' + ledgerKb(ledgerVisible(l.load)) + ' executed at load';
282
- if (turn && turn.kind !== 'render' && turn.kind !== 'resume') line += ' · this ' + turn.kind + ' +' + ledgerKb(turn.delta.app + turn.delta.framework);
283
- line += ' · total ' + ledgerKb(ledgerVisible(l.total));
284
- if (l.totalGzip) line += ' (gzip ' + ledgerKb(l.totalGzip) + ')';
285
- if (l.incomplete) line += ' · ' + l.incomplete.ids.length + ' unmapped (excluded)';
286
- return line;
287
- }
288
- function ledgerMirror(l, turn, text, attribute) {
289
- const root = document.documentElement; if (!root) return;
290
- root.setAttribute(attribute, text);
291
- root.setAttribute('data-markless-log-unit', l.unit);
292
- root.setAttribute('data-markless-log-load-bytes', String(ledgerVisible(l.load)));
293
- root.setAttribute('data-markless-log-total-bytes', String(ledgerVisible(l.total)));
294
- root.setAttribute('data-markless-log-inline-bytes', String(l.total.inline));
295
- if (turn) {
296
- root.setAttribute('data-markless-log-app-bytes', String(turn.delta.app));
297
- root.setAttribute('data-markless-log-framework-bytes', String(turn.delta.framework));
298
- root.setAttribute('data-markless-log-instrument-bytes', String(turn.delta.instrument));
299
- root.setAttribute('data-markless-log-turn-bytes', String(turn.delta.app + turn.delta.framework));
300
- root.setAttribute('data-markless-log-turn-modules', turn.modules.join(' '));
301
- // The headline carries no selector, so the turn's identity lives here.
302
- root.setAttribute('data-markless-log-turn-label', turn.kind + (turn.label ? ' ' + turn.label : ''));
303
- }
304
- if (l.incomplete) root.setAttribute('data-markless-log-incomplete', String(l.incomplete.ids.length)); else root.removeAttribute('data-markless-log-incomplete');
305
- }
306
- function warmIds(event) { return [...new Set([event.dispatchModuleId, ...((event.eventRecord && event.eventRecord.symbolIds) || [])].filter(Boolean))]; }
307
- function causeRows(input) {
308
- const before = input.before || new Set(); const after = input.after || new Set(); const woken = [...after].filter((id) => !before.has(id)); const record = input.eventRecord;
309
- const cause = record ? input.eventName + ' matched event record ' + record.hostNodeId : input.eventName + ' matched runtime records';
310
- const label = (id) => displayObservedId(id, input.moduleSizes);
311
- const rows = woken.map((id) => 'woke ' + label(id) + (input.moduleSizes ? ' (' + rowKb([id], input.moduleSizes) + (input.moduleSizes.get(canonicalId(id, input.moduleSizes))?.instrument ? ' instrument' : '') + ')' : '') + ' <- ' + cause);
312
- if (record) for (const id of warmIds(input)) rows.push('ran warm ' + label(id) + (input.moduleSizes ? ' (' + rowKb([id], input.moduleSizes) + (input.moduleSizes.get(canonicalId(id, input.moduleSizes))?.instrument ? ' instrument' : '') + ')' : '') + ' <- ' + cause);
313
- if (record && !(input.view?.behaviors || []).some((b) => b.hostNodeId === record.hostNodeId)) rows.push('skip behavior — no matching record touched');
314
- return rows;
315
- }
316
- function mirrorInteraction(l, turn, text) {
317
- const root = document.documentElement; if (!root) return;
318
- root.setAttribute('data-markless-log-interactions', String(Number(root.getAttribute('data-markless-log-interactions') || '0') + 1));
319
- ledgerMirror(l, turn, text, 'data-markless-log-last');
320
- }
321
- export async function installMarklessExecutionLog(input = {}) {
322
- const log = globalThis.__mxLog; if (!log || globalThis.__mxLogInteraction) return;
323
- if (marklessInstallPromise) return marklessInstallPromise;
324
- marklessInstallPromise = (async () => {
325
- const moduleSizes = await loadModuleSizes(input); const current = modules(log);
326
- if (input.printResumeSummary !== false) {
327
- const l = marklessLedger(); const turn = ledgerApply(l, 'resume', undefined, ledgerCharge(l, current, moduleSizes)); const summary = ledgerLine(l, turn);
328
- // This summary publishes into the ledger and mirrors; it never prints. The
329
- // ledger's turn line is the one printed line, and a resume that lands
330
- // beside a render turn would otherwise print the same load figure twice.
331
- // A turn merged into an open gesture belongs to that gesture, so it mirrors
332
- // onto the interaction attribute instead of the load one.
333
- ledgerMirror(l, turn, summary, turn.kind === 'resume' ? 'data-markless-log-summary' : 'data-markless-log-last');
334
- }
335
- globalThis.__mxLogInteraction = (event) => {
336
- const capturedAfter = modules(event.after || log);
337
- const symbolIds = qualifySymbolIds((event.eventRecord && event.eventRecord.symbolIds) || [], event.eventRecord && event.eventRecord.hostNodeId, moduleSizes, marklessAttribution);
338
- if (event.eventRecord) event = { ...event, eventRecord: { ...event.eventRecord, symbolIds } };
339
- const after = capturedAfter; const before = event.before || new Set(); if (log.has(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)}) && !after.includes(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)})) after.push(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)}); const woken = after.filter((id) => !before.has(id)); const warm = warmIds(event);
340
- const l = marklessLedger(); const label = '[' + (event.selector || 'event target') + ']';
341
- if (event.noMatch) {
342
- const turn = ledgerApply(l, event.eventName, label, ledgerCharge(l, [], moduleSizes)); const line = ledgerLine(l, turn) + ' · no event record matched ' + label;
343
- console.info(line); mirrorInteraction(l, turn, line); return;
344
- }
345
- const turn = ledgerApply(l, event.eventName, label, ledgerCharge(l, [...woken, ...warm], moduleSizes)); const header = ledgerLine(l, turn);
346
- console.groupCollapsed(header);
347
- console.log(event.eventName + ' ' + label + ' · woke ' + woken.length + ' modules · ran warm ' + warm.length + ' modules');
348
- for (const row of causeRows({ ...event, after: new Set(after), moduleSizes })) console.log(row);
349
- console.groupEnd(); mirrorInteraction(l, turn, header);
350
- };
351
- log.__marklessInstalled = true;
352
- })();
353
- return marklessInstallPromise;
354
- }
355
- export async function logMarklessInteraction(event) { await installMarklessExecutionLog({ printResumeSummary: false }); globalThis.__mxLogInteraction?.(event); }
356
- export async function logMarklessSpecializedInteraction(input, before) {
357
- const target = input.element ?? input.event?.target;
358
- const tag = typeof target?.tagName === 'string' ? target.tagName.toLowerCase() : 'element';
359
- await logMarklessInteraction({ eventName: input.event?.type ?? 'event', eventRecord: input.eventRecord, before, selector: tag + (target?.id ? '#' + target.id : ''), after: new Set(globalThis.__mxLog) });
360
- }
361
- function marklessRenderSummaryTurnEnd() {
362
- // Each injected entry module calls in from its own dynamic-import
363
- // resolution, so a microtask window closes between callers of one render;
364
- // a frame holds them all. The timeout is the backstop for a document that
365
- // never paints, and whichever lands first ends the turn.
366
- if (typeof requestAnimationFrame !== 'function') return Promise.resolve();
367
- return new Promise((resolve) => { let ended; const end = () => { if (ended) return; ended = true; resolve(); }; requestAnimationFrame(end); setTimeout(end, 50); });
368
- }
369
- // Only the console line coalesces: the attribute mirror keeps its per-call
370
- // last-wins timing, which the interaction mirror interleaves with.
371
- function coalesceMarklessRenderSummaryLine(summary) {
372
- if (marklessRenderSummaryTurn) { marklessRenderSummaryTurn.summary = summary; return marklessRenderSummaryTurn.printed; }
373
- const turn = { summary };
374
- turn.printed = marklessRenderSummaryTurnEnd().then(() => { marklessRenderSummaryTurn = undefined; console.log(turn.summary); });
375
- marklessRenderSummaryTurn = turn;
376
- return turn.printed;
377
- }
378
- export async function logMarklessRenderSummary(input = {}) {
379
- const log = globalThis.__mxLog; if (!log) return;
380
- const moduleSizes = await loadModuleSizes(input); const l = marklessLedger();
381
- const turn = ledgerApply(l, 'render', undefined, ledgerCharge(l, modules(log), moduleSizes));
382
- const summary = ledgerLine(l, turn);
383
- if (turn.kind !== 'render') { ledgerMirror(l, turn, summary, 'data-markless-log-last'); return; }
384
- ledgerMirror(l, turn, summary, 'data-markless-log-summary');
385
- return coalesceMarklessRenderSummaryLine(summary);
386
- }
387
- `;
388
- }
389
- function executionLogActivationInjection(mode) {
390
- if (normalizeExecutionLogMode(mode) === "never") return null;
391
- return {
392
- tag: "script",
393
- location: "head",
394
- children: `(() => { const l = location; if (${mode === "always" ? "true" : "/^https?:\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\])(?::|$)/.test(l.origin) || new URLSearchParams(l.search).has('markless-log') || (() => { try { return localStorage.getItem('marklessLog') === '1'; } catch { return false; } })()"}) { globalThis.__mxLog = globalThis.__mxLog || new Set(); const g = globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} = globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} || ${MARKLESS_EXECUTION_LEDGER_INIT}; const s = document.currentScript && document.currentScript.textContent; if (s) { g.total.inline += s.length; if (!g.loadClosed) g.load.inline += s.length; } const c = (e) => { if (e.isTrusted) g.loadClosed = true; }; for (const t of ${JSON.stringify(EXECUTION_LOG_GESTURE_EVENTS)}) addEventListener(t, c, { capture: true, passive: true }); } })();`
395
- };
396
- }
397
- //#endregion
398
- //#region src/source-module.ts
399
- const MARKLESS_VIRTUAL_PREFIX = "virtual:markless:";
400
- const SMALL_SYMBOL_DIRECT_LOAD_LIMIT = 8;
401
- const MARKLESS_BOUND_SYMBOLS_EXPORT = "marklessBoundSymbols";
402
- const SYMBOL_VIRTUAL_PREFIX = `${MARKLESS_VIRTUAL_PREFIX}symbol:`;
403
- function symbolVirtualModuleId(filename, symbolId) {
404
- return `${SYMBOL_VIRTUAL_PREFIX}${encodeURIComponent(filename)}:${encodeURIComponent(symbolId)}`;
405
- }
406
- function encodedSymbolSource(filename) {
407
- return encodeURIComponent(filename);
408
- }
409
- function symbolVirtualModuleSourceFile(moduleId) {
410
- const bare = moduleId.startsWith("\0") ? moduleId.slice(1) : moduleId;
411
- if (!bare.startsWith(SYMBOL_VIRTUAL_PREFIX)) return null;
412
- const encoded = bare.slice(SYMBOL_VIRTUAL_PREFIX.length);
413
- const separator = encoded.indexOf(":");
414
- if (separator <= 0 || separator === encoded.length - 1) return null;
415
- if (encoded.includes(":", separator + 1)) return null;
416
- try {
417
- return decodeURIComponent(encoded.slice(0, separator));
418
- } catch {
419
- return null;
420
- }
421
- }
422
- function resumeVirtualModuleId(filename) {
423
- return `${MARKLESS_VIRTUAL_PREFIX}resume:${encodeURIComponent(filename)}`;
424
- }
425
- function prerenderWakeVirtualModuleId(filename) {
426
- return `${MARKLESS_VIRTUAL_PREFIX}prerender-wake:${encodeURIComponent(filename)}`;
427
- }
428
- function settleVirtualModuleId(filename) {
429
- return `${MARKLESS_VIRTUAL_PREFIX}settle:${encodeURIComponent(filename)}`;
430
- }
431
- /**
432
- * The settle module: import targets and data, no logic. It carries the DOM
433
- * filler, each boundary's async runner keyed by graph node, and each bound
434
- * symbol's compiled derive function keyed by the id the fill plan references.
435
- * Rolldown resolves the real chunk urls, so nothing here is a url the document
436
- * has to carry, and a page that never settles an arm never loads it.
437
- */
438
- function emitSettleModule(input) {
439
- const imports = [...input.runners, ...input.derives].map((entry) => entry.symbol);
440
- const seen = /* @__PURE__ */ new Map();
441
- const lines = ["export { marklessApplySettlePlan as f } from '@markless/web/fns/settle-plan';"];
442
- for (const symbol of imports) {
443
- if (seen.has(symbol.id)) continue;
444
- seen.set(symbol.id, symbol.exportName);
445
- lines.push(`import { ${symbol.exportName} } from ${JSON.stringify(symbol.chunk)};`);
446
- }
447
- const entries = (rows) => `{${rows.map((row) => `${JSON.stringify(row.key)}: ${seen.get(row.symbolId)}`).join(",")}}`;
448
- lines.push(`export const r = ${entries(input.runners.map((entry) => ({
449
- key: entry.node,
450
- symbolId: entry.symbol.id
451
- })))};`);
452
- lines.push(`export const d = ${entries(input.derives.map((entry) => ({
453
- key: entry.id,
454
- symbolId: entry.symbol.id
455
- })))};`);
456
- return `${lines.join("\n")}\n`;
457
- }
458
- function prerenderWakeVirtualModuleSourceFile(moduleId) {
459
- const bare = moduleId.startsWith("\0") ? moduleId.slice(1) : moduleId;
460
- const prefix = `${MARKLESS_VIRTUAL_PREFIX}prerender-wake:`;
461
- if (!bare.startsWith(prefix)) return null;
462
- try {
463
- return decodeURIComponent(bare.slice(prefix.length));
464
- } catch {
465
- return null;
466
- }
467
- }
468
- function scopedSymbolExportName(filename, exportName) {
469
- return `${exportName}_${stringHash(filename)}`;
470
- }
471
- function rewriteSymbolModuleExport(source, fromExportName, toExportName) {
472
- return source.replace(`export function ${fromExportName}`, `export function ${toExportName}`).replace(`export async function ${fromExportName}`, `export async function ${toExportName}`);
473
- }
474
- function payloadModule(payload) {
475
- return [
476
- `export const state = ${JSON.stringify(payload.state, null, " ")};`,
477
- `export const runtimeDemandMap = ${JSON.stringify(payload.runtimeDemandMap, null, " ")};`,
478
- `export const view = ${JSON.stringify(payload.view, null, " ")};`,
479
- ""
480
- ].join("\n");
481
- }
482
- /** The module-local name a direct-CSR module's root renders under. */
483
- function csrRootLocalName(rootExportName) {
484
- return `marklessCsr${rootExportName}`;
485
- }
486
- function emitPublicRenderModule(source, input) {
487
- if (!input.rootExportName) return source;
488
- const declaration = `export function ${input.rootExportName}()`;
489
- if (!source.includes(declaration)) throw new Error(`MARKLESS_CSR_ROOT_DECLARATION_MISSING: ${input.rootExportName}`);
490
- const localName = csrRootLocalName(input.rootExportName);
491
- if (!input.executionLogEnabled) return source.replace(declaration, `function ${localName}()`);
492
- const implementationName = `marklessRender${input.rootExportName}`;
493
- return [
494
- source.replace(declaration, `function ${implementationName}()`),
495
- `function ${localName}() {`,
496
- `\tconst output = ${implementationName}();`,
497
- " globalThis.__mxLoadLog().then(log => log.logMarklessRenderSummary());",
498
- " return output;",
499
- "}"
500
- ].join("\n");
501
- }
502
- function emitSourceModule(input) {
503
- if (input.directCsr && input.prerenderRecords) input = {
504
- ...input,
505
- prerenderRecords: false
506
- };
507
- const symbolsOnly = input.environment === "client" && input.clientOutput === "symbols-only";
508
- const routeSymbols = input.environment === "client" && input.symbolRoutes.length > 0;
509
- const canonicalRenderData = input.environment === "client" && !symbolsOnly && !input.prerenderRecords && input.canonicalRenderData === true && input.publicRenderRootExportName === null && !!input.publicSsrModuleSource && !!input.renderDataId;
510
- const emitsSsrBody = !!input.publicSsrModuleSource && !(input.environment === "client" && (symbolsOnly || !input.prerenderRecords && !input.dev));
511
- const csrRootName = input.environment !== "server" && !symbolsOnly && !input.prerenderRecords && input.publicRenderRootExportName ? csrRootLocalName(input.publicRenderRootExportName) : null;
512
- return [
513
- !input.publicSsrModuleSource && !input.publicRenderModuleSource || symbolsOnly || !input.renderDataId || input.environment === "client" && !input.publicRenderModuleSource && !input.prerenderRecords && !input.dev && !canonicalRenderData ? "" : canonicalRenderData ? emitsSsrBody ? `import { marklessPrerenderData, marklessRenderData } from '${input.renderDataId}';` : `import { marklessPrerenderData } from '${input.renderDataId}';` : `import { marklessRenderData } from '${input.renderDataId}';`,
514
- symbolsOnly ? "" : `import { state as payloadState, view as payloadView, runtimeDemandMap as payloadRuntimeDemandMap } from '${input.payloadId}';`,
515
- input.environment === "client" && input.directCsr === true && input.hasComputedState === true ? ["import { installMarklessDerivedReconcile } from '@markless/web/fns/reconcile-plane';", "installMarklessDerivedReconcile();"].join("\n") : null,
516
- input.environment === "client" && input.hasOverlayMarks === true ? emitOverlayLoaderInstall() : null,
517
- "",
518
- emitLoadSymbol(input),
519
- input.behaviorSymbols?.length ? emitDirectSourceSymbolLoader(input.behaviorSymbols, "readMarklessBehaviorSourceSymbol").replace("function loadSymbol(", "function loadBehaviorSymbol(") : "",
520
- input.environment === "client" && input.executionLog !== "never" ? emitExecutionLogLoader() : "",
521
- routeSymbols ? "const marklessLoadLocalSymbol = loadSymbol;" : "",
522
- (symbolsOnly || input.publicRenderRootExportName === null) && !routeSymbols ? "export { loadSymbol };" : "",
523
- symbolsOnly ? "" : "export { payloadView };",
524
- symbolsOnly ? "" : "export { payloadRuntimeDemandMap };",
525
- input.devResumeReexport && input.environment === "client" ? `export { resumeContainerEvent } from '${resumeVirtualModuleId(input.filename)}';` : "",
526
- "",
527
- input.environment === "server" || symbolsOnly || input.prerenderRecords ? "" : emitPublicRenderModule(input.publicRenderModuleSource, {
528
- executionLogEnabled: input.executionLog !== "never",
529
- rootExportName: input.publicRenderRootExportName
530
- }),
531
- emitsSsrBody ? input.publicSsrModuleSource : "",
532
- routeSymbols ? emitLazySymbolRouteFunction(input.symbolRoutes, "marklessSsrLoadSymbolRoute", "marklessLoadLocalSymbol") : "",
533
- routeSymbols && !symbolsOnly && input.directCsr === true ? emitComposedArmRecordsInstall() : null,
534
- symbolsOnly && routeSymbols ? "export { marklessSsrLoadSymbolRoute as loadSymbol };" : "",
535
- symbolsOnly ? "" : emitCompiledAppDefault({
536
- environment: input.environment,
537
- executionLog: input.executionLog,
538
- headInjections: input.headInjections,
539
- storageSeeds: input.storageSeeds,
540
- inlineResumerSources: input.inlineResumerSources,
541
- prerenderBoot: input.prerenderBoot,
542
- resumeModuleUrl: input.resumeModuleUrl,
543
- prerenderWakeModuleUrl: input.prerenderWakeModuleUrl,
544
- rootExportName: input.publicRenderRootExportName,
545
- csrRootName,
546
- symbolLoaderName: routeSymbols ? "marklessSsrLoadSymbolRoute" : "loadSymbol",
547
- ssrExportName: input.publicRenderSsrExportName,
548
- ssrComponents: input.publicRenderSsrComponentExports ?? [],
549
- canonicalRenderData,
550
- prerenderRecords: input.prerenderRecords,
551
- dev: input.dev
552
- }),
553
- ...emitSharedDefinitionExports(input.sharedDefinitionExports ?? [], input.publicRenderSsrComponentExports ?? []),
554
- ""
555
- ].filter((line) => line !== null).join("\n");
556
- }
557
- const MARKLESS_SHARED_CALL_UNCOMPILED = "MARKLESS_SHARED_CALL_UNCOMPILED";
558
- /**
559
- * One real ES named export per authored shared definition, bound to a callable
560
- * that only ever throws.
561
- *
562
- * The export exists for two reasons, and neither is "run the definition".
563
- * Linking first: a `.ts` barrel writing `export { nscShared as state } from
564
- * './family.tsrx'` is resolved before anything runs, and the emitted module
565
- * replacing the authored one wholesale made that a SyntaxError. Failing closed
566
- * second: a compiled consumer's `family.state()` is lowered by the compiler and
567
- * never reaches this binding, so anything that DOES reach it is an uncompiled
568
- * call site, which cannot be served correctly — a shared instance resolves
569
- * against the widget the caller renders under, and an uncompiled call has no
570
- * such caller. It throws by name rather than quietly becoming a second,
571
- * unratified runtime API.
572
- */
573
- function emitSharedDefinitionExports(sharedExports, ssrComponents) {
574
- if (sharedExports.length === 0) return [];
575
- const taken = new Set([...RESERVED_MODULE_BINDINGS, ...ssrComponents.map((component) => component.exportName)]);
576
- return sharedExports.map((name) => {
577
- if (taken.has(name)) throw new Error(`MARKLESS_SHARED_EXPORT_NAME_RESERVED: ${name}`);
578
- taken.add(name);
579
- const message = `${MARKLESS_SHARED_CALL_UNCOMPILED}: ${name} — a shared definition can only be called from a compiled module; this call site was not compiled.`;
580
- return `export const ${name} = () => { throw new Error(${JSON.stringify(message)}); };`;
581
- });
582
- }
583
- /**
584
- * Whether this app's serialized state defines any computed node. Computed
585
- * definitions are what `createRuntimeGraph` turns into derived graph nodes on
586
- * resume, so they are exactly the apps derived reconciliation can act on.
587
- */
588
- function payloadHasComputed(payloadState) {
589
- const computed = payloadState?.computed;
590
- return Array.isArray(computed) && computed.length > 0;
591
- }
592
- /**
593
- * The one line that makes elevation cost nothing until it is used.
594
- *
595
- * Writing the `import()` specifier HERE rather than in the runtime is the whole
596
- * mechanism: a module every app loads cannot name the behaviour without making
597
- * every app ship its chunk. The handoff is a global rather than a slot module
598
- * for the same reason - a slot module is bytes every app pays for a capability
599
- * most of them do not have. Nothing is fetched until the runtime calls it.
600
- */
601
- function emitOverlayLoaderInstall() {
602
- return [
603
- "globalThis.__marklessOverlay = (root) =>",
604
- " root.querySelector('[overlay]')",
605
- " ? import('@markless/web/fns/overlay').then((m) => m.installOverlayBehavior(root))",
606
- " : undefined;"
607
- ].join("\n");
608
- }
609
- /**
610
- * The same one line for the row mint, and for the same reason.
611
- *
612
- * `resume-keyed-repeats` is loaded by EVERY repeat, so it cannot name the
613
- * building half: doing so makes an app whose rows only reorder emit the mint
614
- * chunk anyway. Written here, the specifier exists only in a build the compiler
615
- * recorded a mintable repeat for; the repeat runtime reads the loader off the
616
- * global and refuses to build without one.
617
- */
618
- function emitRowMintLoaderInstall() {
619
- return "globalThis.__marklessRowMint = () => import('@markless/web/fns/row-mint');";
620
- }
621
- /**
622
- * True when the compiler folded the mint into a keyed-repeat record - which it
623
- * does exactly for a record carrying `rowTemplate` or `emptyArm`, the two fields
624
- * that make a repeat able to build nodes.
625
- */
626
- function demandsRowMint(runtimeDemandMap) {
627
- const records = runtimeDemandMap?.payloadRecords;
628
- return Array.isArray(records) && records.some((record) => record.kind === "keyed-repeat" && record.runtimeModuleIds?.includes(ROW_MINT_RUNTIME_MODULE_ID) === true);
629
- }
630
- const ROW_MINT_RUNTIME_MODULE_ID = "web/fns/row-mint";
631
- /** True when the compiler recorded an `overlay` mark for this module. */
632
- function demandsOverlay(runtimeDemandMap) {
633
- const records = runtimeDemandMap?.payloadRecords;
634
- return Array.isArray(records) && records.some((record) => record.kind === "overlay");
635
- }
636
- function emitResumeModule(input) {
637
- const routeSymbols = input.symbolRoutes.length > 0;
638
- const resumeSymbolLoader = routeSymbols ? "marklessSsrLoadSymbolRoute" : "loadSymbol";
639
- const scalarSpecializations = scalarDispatcherSpecializations(input);
640
- const stagedPrerender = (input.prerenderTriggerGroups?.length ?? 0) > 0;
641
- const resumeContainerEvent = emitQueuedResumeContainerEvent(emitResumeContainerEvent(resumeSymbolLoader, input.needsFullResume ?? false, input.payloadState?.version === ASYNC_PROTOCOL_VERSION, input.symbolRoutes.length > 0 ? "none" : leanResumeMode(input.runtimeDemandMap), scalarSpecializations, input.runtimeDemandMap, input.executionLog !== "never", input.prerenderDataId, stagedPrerender));
642
- return [
643
- input.boundSymbolDescriptors ? `export const ${MARKLESS_BOUND_SYMBOLS_EXPORT} = ${emitBoundSymbolDescriptors(input.boundSymbolDescriptors)};` : null,
644
- input.prerenderDataId && !stagedPrerender && resumeContainerEvent.includes("marklessPrerenderData") ? `import { marklessPrerenderData } from '${input.prerenderDataId}';` : null,
645
- stagedPrerender && input.prerenderDataId ? `async function marklessLoadPrerenderData() { const module = await import('${input.prerenderDataId}'); return module.marklessPrerenderData; }` : null,
646
- `import { runtimeDemandMap as payloadRuntimeDemandMap } from '${input.payloadId}';`,
647
- payloadHasComputed(input.payloadState) ? ["import { installMarklessDerivedReconcile } from '@markless/web/fns/reconcile-plane';", "installMarklessDerivedReconcile();"].join("\n") : null,
648
- demandsOverlay(input.runtimeDemandMap) ? emitOverlayLoaderInstall() : null,
649
- demandsRowMint(input.runtimeDemandMap) ? emitRowMintLoaderInstall() : null,
650
- scalarSpecializations.length > 0 ? [
651
- "import { marklessDecodeScalarCell, marklessReadScalarCell, marklessScalarSpecializedError } from '@markless/web/fns/scalar-specialized';",
652
- "import { marklessWriteScalar } from '@markless/web/fns/write-scalar';",
653
- "import { marklessUpdateText } from '@markless/web/fns/update-text';"
654
- ].join("\n") : "",
655
- scalarSpecializations.length > 0 || stagedPrerender ? "import { marklessFindElementAtDomOrderIndex } from '@markless/web/fns/dom-order';" : "",
656
- "",
657
- input.executionLog === "never" ? "" : emitExecutionLogLoader(),
658
- input.installResumeSummary && input.executionLog !== "never" ? "globalThis.__mxLoadLog().then(log => log.installMarklessExecutionLog());" : null,
659
- "",
660
- emitLoadSymbol(input, stagedPrerender ? "readMarklessWakeSourceSymbol" : void 0),
661
- routeSymbols ? "const marklessLoadLocalSymbol = loadSymbol;" : "",
662
- routeSymbols ? emitLazySymbolRouteFunction(input.symbolRoutes, "marklessSsrLoadSymbolRoute", "marklessLoadLocalSymbol") : "",
663
- routeSymbols ? "export { marklessSsrLoadSymbolRoute as loadSymbol };" : "",
664
- routeSymbols ? emitComposedArmRecordsInstall() : null,
665
- stagedPrerender ? emitPrerenderTriggerGroupLoader(input.prerenderTriggerGroups ?? []) : "",
666
- resumeContainerEvent,
667
- ""
668
- ].filter((line) => line !== null).join("\n");
669
- }
670
- function emitBoundSymbolDescriptors(descriptors) {
671
- return JSON.stringify(Object.fromEntries(Object.keys(descriptors).sort().map((boundaryId) => [boundaryId, descriptors[boundaryId]])));
672
- }
673
- function emitQueuedResumeContainerEvent(source) {
674
- const implementation = source.replace("export async function resumeContainerEvent", "async function marklessResumeContainerEvent");
675
- if (implementation === source) throw new Error("MARKLESS_RESUME_DISPATCH_EXPORT_MISSING");
676
- return [
677
- implementation,
678
- "export function resumeContainerEvent(input) {",
679
- " const root = input.root;",
680
- " if (!root.__marklessDispatch) {",
681
- " let handler = marklessResumeContainerEvent, tail = Promise.resolve(), lastEvent = null, lastEventTime = undefined;",
682
- " root.__marklessRegisterDispatch = next => {",
683
- " const fallback = handler;",
684
- " handler = input => next(input, fallback);",
685
- " };",
686
- " root.__marklessDispatch = next => {",
687
- " const event = next.event, eventTime = event?.timeStamp;",
688
- " if (event === lastEvent && eventTime === lastEventTime) return tail;",
689
- " lastEvent = event;",
690
- " lastEventTime = eventTime;",
691
- " const run = () => handler(next);",
692
- " return tail = tail.then(run, run);",
693
- " };",
694
- " }",
695
- " return root.__marklessDispatch(input);",
696
- "}"
697
- ].join("\n");
698
- }
699
- function emitComposedArmRecordsInstall() {
700
- return ["import { installMarklessComposedArmRecords } from '@markless/web/fns/instance-scope';", "installMarklessComposedArmRecords();"].join("\n");
701
- }
702
- function emitLazySymbolRouteFunction(routes, functionName, fallbackName = "loadSymbol") {
703
- if (routes.length === 0) return "";
704
- const ordered = [...routes].sort((left, right) => right.prefix.length - left.prefix.length);
705
- return [
706
- `function ${functionName}(symbolId) {`,
707
- ...ordered.flatMap((route) => [
708
- ` if (symbolId.startsWith(${JSON.stringify(route.prefix)})) {`,
709
- "importSource" in route ? ` return import(${JSON.stringify(symbolRouteImportSource(route.importSource))}).then((mod) => mod.loadSymbol ? mod.loadSymbol(symbolId.slice(${route.prefix.length})) : Promise.reject(new Error(\`Unknown child async symbol \${symbolId}\`)));` : ` return ${route.prefix.length > 0 ? functionName : fallbackName}(symbolId.slice(${route.prefix.length}));`,
710
- " }"
711
- ]),
712
- ` return ${fallbackName}(symbolId);`,
713
- "}"
714
- ].join("\n");
715
- }
716
- function symbolRouteImportSource(importSource) {
717
- return importSource.includes("?") ? `${importSource}&markless-symbols` : `${importSource}?markless-symbols`;
718
- }
719
- function emitCompiledAppDefault(input) {
720
- const renderCsrEntry = input.csrRootName ? [` renderCsr: ${input.csrRootName},`] : [];
721
- const symbolLoaderEntry = input.environment !== "server" && input.rootExportName === null ? [`\tloadSymbol: ${input.symbolLoaderName},`] : input.prerenderRecords === true ? [`\tloadSymbol: ${input.symbolLoaderName},`] : [];
722
- const renderDataEntry = input.canonicalRenderData ? [" renderData: marklessPrerenderData,"] : [];
723
- const servesSsr = !!input.ssrExportName && (input.environment !== "client" || input.prerenderRecords || input.dev);
724
- const renderSsrEntry = servesSsr ? [
725
- " renderSsr(props, marklessRenderContext) {",
726
- ` return ${input.ssrExportName}(props, marklessRenderContext);`,
727
- " },"
728
- ] : [];
729
- const renderSsrComponentsEntry = servesSsr && input.ssrComponents.length > 0 ? [` renderSsrComponents: { ${input.ssrComponents.map((component) => `${JSON.stringify(component.exportName)}: { renderSsr: ${component.ssrFunctionName} }`).join(", ")} },`] : [];
730
- const resumeModuleEntry = input.resumeModuleUrl && input.environment !== "client" ? [` resumeModuleUrl: ${JSON.stringify(input.resumeModuleUrl)},`] : [];
731
- const prerenderWakeModuleEntry = input.prerenderWakeModuleUrl && input.environment !== "client" ? [`\tprerenderWakeModuleUrl: ${JSON.stringify(input.prerenderWakeModuleUrl)},`] : [];
732
- const inlineResumerEntry = input.inlineResumerSources && input.environment !== "client" ? [`\tinlineResumerSources: ${JSON.stringify(input.inlineResumerSources)},`] : [];
733
- const prerenderBootEntry = input.prerenderBoot && input.environment !== "client" ? [`\tprerenderBoot: ${JSON.stringify(input.prerenderBoot)},`] : [];
734
- const headInjectionEntry = input.headInjections?.length && input.environment !== "client" ? [` headInjections: ${JSON.stringify(input.headInjections)},`] : [];
735
- const storageSeedEntry = input.storageSeeds?.length && input.environment !== "client" ? [`\tstorageSeeds: ${JSON.stringify(input.storageSeeds)},`] : [];
736
- const modulePreloadEntry = input.resumeModuleUrl && input.environment === "server" ? [` modulePreloads: [{ href: ${JSON.stringify(input.resumeModuleUrl)}, fetchPriority: "high" }],`] : [];
737
- const metadataEntries = input.environment === "client" ? [] : [
738
- ...headInjectionEntry,
739
- ...storageSeedEntry,
740
- ...resumeModuleEntry,
741
- ...prerenderWakeModuleEntry,
742
- ...inlineResumerEntry,
743
- ...prerenderBootEntry,
744
- ...modulePreloadEntry,
745
- input.executionLog && input.executionLog !== "never" ? ` executionLog: ${JSON.stringify(input.executionLog)},` : "",
746
- " payloadView,"
747
- ];
748
- return [
749
- "const marklessCompiledApp = {",
750
- ...renderCsrEntry,
751
- ...renderDataEntry,
752
- ...symbolLoaderEntry,
753
- ...renderSsrEntry,
754
- ...renderSsrComponentsEntry,
755
- ...metadataEntries,
756
- "};",
757
- "export default marklessCompiledApp;",
758
- ...emitComponentExports({
759
- ssrComponents: input.ssrComponents,
760
- rootExportName: input.ssrComponents.find((component) => component.ssrFunctionName === input.ssrExportName)?.exportName,
761
- servesSsr: !!servesSsr
762
- })
763
- ].join("\n");
764
- }
765
- const RESERVED_MODULE_BINDINGS = new Set([
766
- "loadBehaviorSymbol",
767
- "loadSymbol",
768
- "marklessCompiledApp",
769
- "marklessLoadLocalSymbol",
770
- "marklessPrerenderData",
771
- "marklessRenderData",
772
- "marklessRenderSsr",
773
- "marklessSsrLoadSymbolRoute",
774
- "payloadRuntimeDemandMap",
775
- "payloadState",
776
- "payloadView",
777
- "readMarklessBehaviorSourceSymbol",
778
- "resumeContainerEvent"
779
- ]);
780
- /**
781
- * One real ES named export per component the module serves, so plain ESM reaches
782
- * them: a `.ts` barrel writing `export { CheckboxRoot as root } from
783
- * './checkbox.tsrx'`, and an app writing `import { Gallery } from
784
- * './Gallery.tsrx'`, are both named reads the bundler resolves at LINK time.
785
- * Publishing components only on the default export's map answered neither
786
- * (MISSING_EXPORT at build, "does not provide an export named" in the browser).
787
- *
788
- * The root is published merged - the module surface plus its own part's
789
- * `renderSsr` - because both consumers reach it by that one name: `render(Gallery,
790
- * { target })` reads the surface (`renderCsr`/`renderData`/`loadSymbol`), while a
791
- * barrel re-export composed as a member tag reads the part. Every other component
792
- * is published as exactly the part `marklessSsrComponentPart` hands a composed
793
- * child, through the same access path, so a named import and a member tag reach
794
- * one object.
795
- */
796
- function emitComponentExports(input) {
797
- return input.ssrComponents.map((component) => {
798
- if (RESERVED_MODULE_BINDINGS.has(component.exportName)) throw new Error(`MARKLESS_COMPONENT_EXPORT_NAME_RESERVED: ${component.exportName}`);
799
- const part = `marklessCompiledApp.renderSsrComponents[${JSON.stringify(component.exportName)}]`;
800
- const isRoot = component.exportName === input.rootExportName;
801
- if (input.servesSsr) return `export const ${component.exportName} = ${isRoot ? `{ ...marklessCompiledApp, renderSsr: ${part}.renderSsr }` : part};`;
802
- return isRoot ? `export const ${component.exportName} = marklessCompiledApp;` : `export const ${component.exportName} = { marklessCsrOnlyPart: ${JSON.stringify(component.exportName)} };`;
803
- });
804
- }
805
- function emitResumeContainerEvent(loadSymbolName, needsFullResume, storageFreePayload, leanMode, scalarSpecializations, runtimeDemandMap, executionLogEnabled, prerenderDataId, stagedPrerender = false) {
806
- const fullResumeHandoff = stagedPrerender && prerenderDataId ? [
807
- "async function marklessFullResumeHandoff(handoff) {",
808
- " handoff.root.__asyncResumeRuntimeStarted = true;",
809
- " const group = await marklessLoadPrerenderTriggerGroup(handoff);",
810
- " const { mergePrerenderPayloadRecords, resumePrerenderTriggerGroup } = await import('@markless/web/fns/prerender-trigger-resume');",
811
- " if (!group) {",
812
- " const { derivePrerenderResumeRecords, renderPrerenderBoundary, resumeFromPrerenderRecords } = await import('@markless/web/fns/prerender-resume');",
813
- " handoff.root.__marklessFullResumeRuntime ??= (async () => {",
814
- " const marklessPrerenderData = await marklessLoadPrerenderData();",
815
- `\t\t\tconst fallbackRecords = mergePrerenderPayloadRecords(await derivePrerenderResumeRecords(marklessPrerenderData, ${loadSymbolName}), handoff.root);`,
816
- " return (await resumeFromPrerenderRecords({",
817
- " ...fallbackRecords,",
818
- " root: handoff.root,",
819
- `\t\t\t\tloadSymbol: ${loadSymbolName},`,
820
- `\t\t\t\trenderAsyncBoundary: (boundaryId, status, graph) => renderPrerenderBoundary(marklessPrerenderData, boundaryId, status, graph, ${loadSymbolName}),`,
821
- " })).runtime;",
822
- " })();",
823
- " const marklessFullRuntime = await handoff.root.__marklessFullResumeRuntime;",
824
- " await marklessFullRuntime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
825
- " return;",
826
- " }",
827
- " const records = mergePrerenderPayloadRecords({ state: group.state, view: group.view }, handoff.root);",
828
- " const { runtime } = await resumePrerenderTriggerGroup({",
829
- " ...records, groupId: group.groupId, graphNodeIds: group.graphNodeIds,",
830
- " root: handoff.root, loadSymbol: group.loadSymbol, prepareBoundaryArm: group.prepareBoundaryArm, renderBoundaryArm: group.renderBoundaryArm,",
831
- " });",
832
- " await runtime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
833
- "}"
834
- ].join("\n") : prerenderDataId ? [
835
- "async function marklessFullResumeHandoff(handoff) {",
836
- " handoff.root.__marklessLinkedRenderDataBoot = true;",
837
- " handoff.root.__asyncResumeRuntimeStarted = true;",
838
- " const { derivePrerenderResumeRecords, mergePrerenderPayloadRecords, renderPrerenderBoundary, resumeFromPrerenderRecords } = await import('@markless/web/fns/prerender-resume');",
839
- `\tconst records = await derivePrerenderResumeRecords(marklessPrerenderData, ${loadSymbolName});`,
840
- " const mergedRecords = mergePrerenderPayloadRecords(records, handoff.root);",
841
- " const { runtime } = await resumeFromPrerenderRecords({",
842
- " ...mergedRecords,",
843
- " root: handoff.root,",
844
- `\t\tloadSymbol: ${loadSymbolName},`,
845
- `\t\trenderAsyncBoundary: (boundaryId, status, graph) => renderPrerenderBoundary(marklessPrerenderData, boundaryId, status, graph, ${loadSymbolName}),`,
846
- " });",
847
- " await runtime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
848
- "}"
849
- ].join("\n") : [
850
- "async function marklessFullResumeHandoff(handoff) {",
851
- " handoff.root.__asyncResumeRuntimeStarted = true;",
852
- ` const { resumeFromPayloadDocument } = await import('${storageFreePayload ? "@markless/core/web/resume-storage-free" : "@markless/core/web/resume"}');`,
853
- " const { runtime } = await resumeFromPayloadDocument({",
854
- " document: handoff.document,",
855
- " root: handoff.root,",
856
- ` loadSymbol: ${loadSymbolName},`,
857
- " });",
858
- " await runtime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
859
- "}"
860
- ].join("\n");
861
- const scalarOnlySpecialized = leanMode === "scalar" && scalarSpecializations.length > 0 && allEventActionsHaveScalarPlan(runtimeDemandMap);
862
- const scalarDispatcher = scalarSpecializations.length > 0 ? emitSpecializedScalarDispatcher(scalarSpecializations, loadSymbolName, scalarOnlySpecialized ? "fail" : "full") : emitSpecializedScalarDispatcher([], loadSymbolName, "full");
863
- if (needsFullResume) return [
864
- fullResumeHandoff,
865
- "export async function resumeContainerEvent(input) {",
866
- " await marklessFullResumeHandoff({ ...input, document: input.root });",
867
- "}"
868
- ].join("\n");
869
- if (leanMode !== "none") {
870
- const row = [
871
- " const { resumeScalarRowEventFromPayloadDocument } = await import('@markless/web/event-only-lean/row');",
872
- " await resumeScalarRowEventFromPayloadDocument({",
873
- ...[
874
- " document: input.root,",
875
- " root: input.root,",
876
- " event: input.event,",
877
- " element: input.element,",
878
- " runtimeDemandMap: payloadRuntimeDemandMap,",
879
- " syncPolicyAlreadyApplied: input.syncPolicyAlreadyApplied === true,",
880
- ` loadSymbol: ${loadSymbolName},`,
881
- " });"
882
- ]
883
- ];
884
- if (leanMode === "scalar") return [
885
- scalarOnlySpecialized ? "" : fullResumeHandoff,
886
- scalarDispatcher,
887
- "export async function resumeContainerEvent(input) {",
888
- executionLogEnabled ? " const marklessLogBefore = globalThis.__mxLog && new Set(globalThis.__mxLog);" : "",
889
- " await marklessResumeSpecializedScalarEvent(input);",
890
- executionLogEnabled ? " if (marklessLogBefore) globalThis.__mxLoadLog().then(log => log.logMarklessSpecializedInteraction(input, marklessLogBefore));" : "",
891
- "}"
892
- ].join("\n");
893
- if (leanMode === "row") return [
894
- "export async function resumeContainerEvent(input) {",
895
- ...row,
896
- "}"
897
- ].join("\n");
898
- return [
899
- fullResumeHandoff,
900
- scalarDispatcher,
901
- "export async function resumeContainerEvent(input) {",
902
- " if (marklessScalarSpecializedAction(input)) {",
903
- " await marklessResumeSpecializedScalarEvent(input);",
904
- " return;",
905
- " }",
906
- ...row,
907
- "}"
908
- ].join("\n");
909
- }
910
- if (prerenderDataId) return "export async function resumeContainerEvent(_input) {}";
911
- return [
912
- fullResumeHandoff,
913
- "export async function resumeContainerEvent(input) {",
914
- " await marklessFullResumeHandoff({ ...input, document: input.root });",
915
- "}"
916
- ].join("\n");
917
- }
918
- function emitPrerenderTriggerGroupLoader(groups) {
919
- return [
920
- "function marklessPrerenderTriggerMatches(input, index, tagName, eventName) {",
921
- " if (input.event?.type !== eventName) return false;",
922
- " const host = marklessFindElementAtDomOrderIndex(input.root, index);",
923
- " if (!host || (tagName !== \"*\" && host.tagName.toLowerCase() !== tagName)) return false;",
924
- " const target = input.event?.target;",
925
- " return host === target || (!!target?.nodeType && typeof host.contains === \"function\" && host.contains(target));",
926
- "}",
927
- "function marklessPrerenderBranchTriggerMatches(input, startIndex, endIndex, hostPath, eventName) {",
928
- " if (input.event?.type !== eventName) return false;",
929
- " const comments = [];",
930
- " const collect = node => { for (const child of node.childNodes ?? []) { if (child.nodeType === 8) comments.push(child); collect(child); } };",
931
- " collect(input.root);",
932
- " const start = comments[startIndex], end = comments[endIndex], armNodes = [];",
933
- " let within = false, done = false;",
934
- " const between = node => { for (const child of node.childNodes ?? []) { if (child === start) { within = true; continue; } if (child === end) { done = true; return; } if (within) armNodes.push(child); else between(child); if (done) return; } };",
935
- " between(input.root);",
936
- " let host = armNodes[hostPath[0]];",
937
- " for (let index = 1; host && index < hostPath.length; index++) host = host.childNodes?.[hostPath[index]];",
938
- " const target = input.event?.target;",
939
- " return host?.nodeType === 1 && (host === target || (!!target?.nodeType && typeof host.contains === \"function\" && host.contains(target)));",
940
- "}",
941
- "function marklessLoadPrerenderTriggerGroup(input) {",
942
- ...groups.map((group) => {
943
- return `\tif (${group.eventName === "self-wake" ? "input.event === 0" : group.hostPath ? `marklessPrerenderBranchTriggerMatches(input, ${group.branchStartIndex}, ${group.branchEndIndex}, ${JSON.stringify(group.hostPath)}, ${JSON.stringify(group.eventName)})` : `marklessPrerenderTriggerMatches(input, ${group.hostIndex}, ${JSON.stringify(group.hostTagName.toLowerCase())}, ${JSON.stringify(group.eventName)})`}) return import(${JSON.stringify(group.moduleId)});`;
944
- }),
945
- " return Promise.resolve(null);",
946
- "}"
947
- ].join("\n");
948
- }
949
- function scalarDispatcherSpecializations(input) {
950
- const state = input.payloadState;
951
- const view = input.payloadView;
952
- const map = input.runtimeDemandMap;
953
- if ((input.symbolRoutes?.length ?? 0) > 0) return [];
954
- const cells = state?.cells ?? [];
955
- const locators = view?.locators ?? [];
956
- return (map?.actions ?? []).flatMap((action, index) => {
957
- const plan = action?.plan;
958
- if (action?.recordKind !== "event" || plan?.version !== 1 || plan?.kind !== "scalar") return [];
959
- const cellIndex = cells.findIndex((cell) => cell?.graphNodeId === plan.cell);
960
- const initialCell = cells[cellIndex];
961
- const host = locators.find((locator) => locator?.hostNodeId === action.hostNodeId);
962
- const event = view?.events?.find((candidate) => candidate?.hostNodeId === action.hostNodeId && candidate?.eventName === action.eventName);
963
- const symbolId = scalarActionSymbolId(plan.symbolId, event, input.symbolRoutes ?? []);
964
- if (!symbolId) return [];
965
- if (cellIndex < 0 || !initialCell || !host || typeof host.index !== "number") return [];
966
- if (event && syncPolicyGraphNodeIds(event.syncPolicy).some((graphNodeId) => graphNodeId !== plan.cell)) return [];
967
- const textUpdates = (plan.textUpdates ?? []).flatMap((update) => {
968
- const locator = locators.find((candidate) => candidate?.hostNodeId === update.hostNodeId);
969
- return locator && typeof locator.index === "number" ? [{
970
- hostNodeId: update.hostNodeId,
971
- index: locator.index,
972
- tagName: String(locator.tagName ?? "*"),
973
- ...update.prefix ? { prefix: update.prefix } : {}
974
- }] : [];
975
- });
976
- if (textUpdates.length !== (plan.textUpdates ?? []).length) return [];
977
- return [{
978
- name: `marklessRunScalar${index}`,
979
- hostNodeId: action.hostNodeId,
980
- eventName: action.eventName,
981
- symbolId,
982
- cell: plan.cell,
983
- cellIndex,
984
- initialCell,
985
- hostIndex: host.index,
986
- hostTagName: String(host.tagName ?? "*"),
987
- syncPolicy: event?.syncPolicy ?? null,
988
- write: plan.write,
989
- textUpdates
990
- }];
991
- });
992
- }
993
- function scalarActionSymbolId(plannedSymbolId, event, routes) {
994
- if (typeof plannedSymbolId !== "string") return null;
995
- const eventSymbolIds = Array.isArray(event?.symbolIds) ? event.symbolIds.filter((symbolId) => typeof symbolId === "string") : [];
996
- const routedSymbolId = eventSymbolIds.find((symbolId) => routes.some((route) => symbolId.startsWith(route.prefix)));
997
- if (routedSymbolId) return routedSymbolId;
998
- if (eventSymbolIds.some((symbolId) => /^[^:]+:symbol:/.test(symbolId))) return null;
999
- if (eventSymbolIds.length > 0 && !eventSymbolIds.includes(plannedSymbolId)) return null;
1000
- return plannedSymbolId;
1001
- }
1002
- function allEventActionsHaveScalarPlan(runtimeDemandMap) {
1003
- const eventActions = (runtimeDemandMap?.actions ?? []).filter((action) => action.recordKind === "event");
1004
- return eventActions.length > 0 && eventActions.every((action) => action.plan?.kind === "scalar");
1005
- }
1006
- function emitSpecializedScalarDispatcher(actions, loadSymbolName, fallback) {
1007
- const fallbackName = fallback === "fail" ? "marklessScalarSpecializedHostMiss" : "marklessScalarSpecializedFallback";
1008
- const fallbackBody = fallback === "full" ? [
1009
- "async function marklessScalarSpecializedFallback(input, site, syncPolicyAlreadyApplied = input.syncPolicyAlreadyApplied === true) {",
1010
- " if (import.meta.env?.DEV) console.warn(Object.assign(new Error(\"MARKLESS_SCALAR_SPECIALIZED_FALLBACK\"), { code: \"MARKLESS_SCALAR_SPECIALIZED_FALLBACK\", site }));",
1011
- " await marklessFullResumeHandoff({ ...input, document: input.root, syncPolicyAlreadyApplied });",
1012
- "}"
1013
- ] : [];
1014
- return [
1015
- "async function marklessResumeSpecializedScalarEvent(input) {",
1016
- " const action = marklessScalarSpecializedAction(input);",
1017
- " if (action) {",
1018
- " try {",
1019
- " return await action(input);",
1020
- " } catch (error) {",
1021
- ` if (error?.code === "MARKLESS_SCALAR_SPECIALIZED_ESCALATE") return ${fallbackName}(input, error.site ?? "escalate", error.syncPolicyAlreadyApplied === true);`,
1022
- " throw error;",
1023
- " }",
1024
- " }",
1025
- fallback === "fail" ? " return;" : ` return ${fallbackName}(input, "event-match");`,
1026
- "}",
1027
- fallback === "fail" ? "function marklessScalarSpecializedHostMiss(_input, site) { return marklessScalarSpecializedError(\"MARKLESS_SCALAR_SPECIALIZED_HOST_MISS\", site); }" : "function marklessScalarSpecializedHostMiss(input, site) { return marklessScalarSpecializedFallback(input, site); }",
1028
- "function marklessScalarSpecializedAction(input) {",
1029
- ...actions.map((action) => ` if (marklessScalarEventMatches(input, marklessFindElementAtDomOrderIndex(input.root, ${action.hostIndex}), ${JSON.stringify(action.hostTagName.toLowerCase())}, ${JSON.stringify(action.eventName)}, ${JSON.stringify(action.hostNodeId)})) return ${action.name};`),
1030
- "}",
1031
- "function marklessScalarEventMatches(input, host, tagName, eventName, hostNodeId) {",
1032
- " const eventTypeMatches = input.event?.type === eventName;",
1033
- " if (!eventTypeMatches) return false;",
1034
- " if (!host || (tagName !== \"*\" && host.tagName.toLowerCase() !== tagName)) return false;",
1035
- " const eventTarget = input.event?.target;",
1036
- " return host === eventTarget || (!!eventTarget?.nodeType && typeof host.contains === \"function\" && host.contains(eventTarget));",
1037
- "}",
1038
- ...actions.map((action) => emitScalarAction(action, loadSymbolName)),
1039
- ...fallbackBody
1040
- ].join("\n");
1041
- }
1042
- function emitScalarAction(action, loadSymbolName) {
1043
- return [
1044
- `async function ${action.name}(input) {`,
1045
- " let syncPolicyAlreadyApplied = input.syncPolicyAlreadyApplied === true;",
1046
- " const values = input.root.__marklessEventOnlyGraph || new Map();",
1047
- " input.root.__marklessEventOnlyGraph = values;",
1048
- ` if (!values.has(${JSON.stringify(action.cell)})) values.set(${JSON.stringify(action.cell)}, marklessDecodeScalarCell(marklessReadScalarCell(input.root, ${JSON.stringify(action.cell)}) ?? ${JSON.stringify(action.initialCell)}, ${JSON.stringify(action.cell)}, ${JSON.stringify(`markless/state cell ${action.cell}`)}));`,
1049
- ` const state = { value: values.get(${JSON.stringify(action.cell)}), dirty: false };`,
1050
- " try {",
1051
- ` const host = marklessFindElementAtDomOrderIndex(input.root, ${action.hostIndex});`,
1052
- ` if (!host || (${JSON.stringify(action.hostTagName.toLowerCase())} !== "*" && host.tagName.toLowerCase() !== ${JSON.stringify(action.hostTagName.toLowerCase())})) return marklessScalarSpecializedHostMiss(input, "host");`,
1053
- ...action.textUpdates.map((update, index) => ` const textTarget${index} = marklessFindElementAtDomOrderIndex(input.root, ${update.index});`),
1054
- ...action.textUpdates.map((update, index) => ` if (!textTarget${index} || (${JSON.stringify(update.tagName.toLowerCase())} !== "*" && textTarget${index}.tagName.toLowerCase() !== ${JSON.stringify(update.tagName.toLowerCase())})) return marklessScalarSpecializedHostMiss(input, "text-target");`),
1055
- " const graph = {",
1056
- ` hasCell(graphNodeId) { return graphNodeId === ${JSON.stringify(action.cell)}; },`,
1057
- ` read(graphNodeId, path = []) { if (graphNodeId !== ${JSON.stringify(action.cell)} || path.length) return marklessScalarSpecializedError("MARKLESS_SCALAR_SPECIALIZED_ESCALATE", "read"); return state.value; },`,
1058
- ` write(write) { if (write.graphNodeId !== ${JSON.stringify(action.cell)} || (write.path?.length ?? 0)) return marklessScalarSpecializedError("MARKLESS_SCALAR_SPECIALIZED_ESCALATE", "write"); if (!Object.is(state.value, write.value)) { state.value = write.value; values.set(${JSON.stringify(action.cell)}, state.value); state.dirty = true; } },`,
1059
- ` update(update) { if (update.graphNodeId !== ${JSON.stringify(action.cell)} || (update.path?.length ?? 0)) return marklessScalarSpecializedError("MARKLESS_SCALAR_SPECIALIZED_ESCALATE", "update"); const previous = state.value; const next = update.update(previous); if (!Object.is(previous, next)) { state.value = next; values.set(${JSON.stringify(action.cell)}, state.value); state.dirty = true; } return update.returnValue === "previous" ? previous : update.returnValue === "next" ? next : undefined; },`,
1060
- " call() { return marklessScalarSpecializedError(\"MARKLESS_SCALAR_SPECIALIZED_ESCALATE\", \"call\"); },",
1061
- " async flush() {},",
1062
- " };",
1063
- ...action.syncPolicy ? [
1064
- ` const syncPolicy = ${JSON.stringify(action.syncPolicy)};`,
1065
- " if (syncPolicy && !syncPolicyAlreadyApplied) {",
1066
- " const { runSyncPolicyActions } = await import('@markless/web/inline/sync-policy-core');",
1067
- " runSyncPolicyActions(syncPolicy, graph, input.event);",
1068
- " syncPolicyAlreadyApplied = true;",
1069
- " }"
1070
- ] : [],
1071
- ...emitScalarWrite(action),
1072
- ` const symbol = await Promise.resolve(${loadSymbolName}(${JSON.stringify(action.symbolId)}));`,
1073
- " await Promise.resolve(symbol({ graph: { ...graph, write() {}, update(update) { const value = graph.read(update.graphNodeId, update.path ?? []); return update.returnValue === \"previous\" || update.returnValue === \"next\" ? value : undefined; } }, event: input.event, element: host, getElementHandle: () => undefined }));",
1074
- " if (state.dirty) {",
1075
- " state.dirty = false;",
1076
- ...action.textUpdates.map((update, index) => ` textTarget${index}.textContent = marklessUpdateText({ domUpdate: { hostNodeId: ${JSON.stringify(update.hostNodeId)} }, value: ${JSON.stringify(update.prefix ?? "")} + (state.value == null ? '' : String(state.value)) }, ${JSON.stringify(update.hostNodeId)}).value;`),
1077
- " }",
1078
- " } catch (error) {",
1079
- " if (error?.code === \"MARKLESS_SCALAR_SPECIALIZED_ESCALATE\") error.syncPolicyAlreadyApplied = syncPolicyAlreadyApplied;",
1080
- " throw error;",
1081
- " }",
1082
- "}"
1083
- ].join("\n");
1084
- }
1085
- function emitScalarWrite(action) {
1086
- if (action.write.kind === "update") return [
1087
- " marklessWriteScalar({ graph }, {",
1088
- ` graphNodeId: ${JSON.stringify(action.cell)},`,
1089
- " returnValue: \"next\",",
1090
- " update(value) {",
1091
- ` return Number(value) ${action.write.updateOperator === "--" ? "-" : "+"} 1;`,
1092
- " },",
1093
- " });"
1094
- ];
1095
- return [
1096
- " marklessWriteScalar({ graph }, {",
1097
- ` graphNodeId: ${JSON.stringify(action.cell)},`,
1098
- ` value: ${action.write.valueKind === "undefined" ? "undefined" : JSON.stringify(action.write.value)},`,
1099
- " });"
1100
- ];
1101
- }
1102
- function syncPolicyGraphNodeIds(policy) {
1103
- if (!policy || typeof policy !== "object") return [];
1104
- const branches = Array.isArray(policy.branches) ? policy.branches : [policy];
1105
- return [...new Set(branches.flatMap((branch) => conditionGraphNodeIds(branch.when)))].sort();
1106
- }
1107
- function conditionGraphNodeIds(condition) {
1108
- if (!condition || typeof condition !== "object") return [];
1109
- const typed = condition;
1110
- if (typed.type === "graph-truthy" && typeof typed.graphNodeId === "string") return [typed.graphNodeId];
1111
- if (typed.type === "not") return conditionGraphNodeIds(typed.condition);
1112
- if ((typed.type === "and" || typed.type === "or") && Array.isArray(typed.conditions)) return typed.conditions.flatMap(conditionGraphNodeIds);
1113
- return [];
1114
- }
1115
- function leanResumeMode(runtimeDemandMap) {
1116
- const recordKinds = runtimeDemandMap?.recordKinds;
1117
- if (!recordKinds) return "none";
1118
- const replaced = new Map(recordKinds.map((record) => [record.kind, record.replaced]));
1119
- const scalar = replaced.get("event") === true && replaced.get("dom-update") === true;
1120
- const row = replaced.get("keyed-repeat") === true && replaced.get("dom-update") === true;
1121
- if (scalar && row) return "mixed";
1122
- if (scalar) return "scalar";
1123
- if (row) return "row";
1124
- return "none";
1125
- }
1126
- function emitExecutionLogLoader() {
1127
- return `globalThis.__mxLoadLog ||= () => import(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)});`;
1128
- }
1129
- function emitLoadSymbol(input, sourceReaderName) {
1130
- if (input.symbols.length > 0 && input.symbols.length <= SMALL_SYMBOL_DIRECT_LOAD_LIMIT) {
1131
- const direct = emitDirectSourceSymbolLoader(input.symbols, sourceReaderName);
1132
- if (!input.hasBoundSymbols) return direct;
1133
- return [`const marklessSymbolResolverModule = () => import('${input.resolverId}');`, direct.replace(" return Promise.reject(new Error(`Unknown async symbol ${symbolId}`));", " return marklessSymbolResolverModule().then((mod) => mod.loadSymbol(symbolId));")].join("\n");
1134
- }
1135
- return [
1136
- `const marklessSymbolResolverModule = () => import('${input.resolverId}');`,
1137
- "function loadSymbol(symbolId) {",
1138
- " return marklessSymbolResolverModule().then((mod) => mod.loadSymbol(symbolId));",
1139
- "}"
1140
- ].join("\n");
1141
- }
1142
- function emitDirectSourceSymbolLoader(symbols, readerName = "readMarklessSourceSymbol") {
1143
- return [
1144
- "function loadSymbol(symbolId) {",
1145
- ...symbols.flatMap((symbol) => [` if (symbolId === ${JSON.stringify(symbol.id)}) return import('${symbol.chunk}')`, ` .then((mod) => ${readerName}(mod, ${JSON.stringify(symbol.exportName)}));`]),
1146
- " return Promise.reject(new Error(`Unknown async symbol ${symbolId}`));",
1147
- "}",
1148
- emitSourceSymbolExportReader(readerName)
1149
- ].join("\n");
1150
- }
1151
- function emitSourceSymbolExportReader(name = "readMarklessSourceSymbol") {
1152
- return [
1153
- `function ${name}(mod, exportName) {`,
1154
- " mod.init__virtual_markless_symbol?.();",
1155
- " return mod[exportName];",
1156
- "}"
1157
- ].join("\n");
1158
- }
1159
- function stringHash(value) {
1160
- let hash = 2166136261;
1161
- for (let index = 0; index < value.length; index++) {
1162
- hash ^= value.charCodeAt(index);
1163
- hash = Math.imul(hash, 16777619);
1164
- }
1165
- return (hash >>> 0).toString(36);
1166
- }
1167
- //#endregion
1168
- export { planModulePreloadUrls as C, requalifyExecutionLogModuleHook as S, executionLogActivationInjection as _, encodedSymbolSource as a, injectExecutionLogModuleHook as b, prerenderWakeVirtualModuleSourceFile as c, scopedSymbolExportName as d, settleVirtualModuleId as f, MARKLESS_EXECUTION_LOG_MODULE_ID as g, EXECUTION_LOG_DISPATCH_MODULE_IDS as h, emitSourceModule as i, resumeVirtualModuleId as l, symbolVirtualModuleSourceFile as m, emitResumeModule as n, payloadModule as o, symbolVirtualModuleId as p, emitSettleModule as r, prerenderWakeVirtualModuleId as s, MARKLESS_VIRTUAL_PREFIX as t, rewriteSymbolModuleExport as u, executionLogVirtualModuleSource as v, planModulePreloads as w, normalizeExecutionLogMode as x, hasExecutionLogModuleHook as y };