@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.
- package/dist/dev-error-2hi-Icjn.js +176 -0
- package/dist/dev-error.d.ts +16 -16
- package/dist/dev-error.js +2 -174
- package/dist/execution-log-BL-7a77M.d.ts +17 -0
- package/dist/optimized-deps-BfzxSm6C.js +89 -0
- package/dist/preload.d.ts +44 -7
- package/dist/preload.js +3 -2
- package/dist/repeat-runtime-BDnaUYXM.js +71 -0
- package/dist/rolldown-DHkCX7vL.js +9267 -0
- package/dist/rolldown.d.ts +37 -17
- package/dist/rolldown.js +3 -3
- package/dist/roster-resume-CpphsFl_.js +427 -0
- package/dist/route-pack-groups-BXc755qH.js +2744 -0
- package/dist/shared-seed-slot-ihIVCD2S.js +113 -0
- package/dist/{types-BuooJg32.d.ts → types-iOUoceJ-.d.ts} +49 -10
- package/dist/vite.d.ts +5 -6
- package/dist/vite.js +673 -171
- package/package.json +7 -7
- package/dist/rolldown-CB2Xpf-E.js +0 -4828
- package/dist/source-module-DI20i0ZG.js +0 -1168
- package/dist/source-module-XFgOFX1c.d.ts +0 -8
|
@@ -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 };
|