@askrjs/askr 0.0.9 → 0.0.10
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/chunk-37RC6ZT3.js +1 -0
- package/dist/chunk-4RTKQ7SC.js +1 -0
- package/dist/chunk-534P7OMI.js +2 -0
- package/dist/chunk-62D2TNHX.js +1 -0
- package/dist/chunk-CI6AOGB5.js +1 -0
- package/dist/chunk-D2JSJKCW.js +1 -0
- package/dist/chunk-DPHQ4JD6.js +1 -0
- package/dist/chunk-FFSNBDHN.js +1 -0
- package/dist/chunk-JJDSOK6C.js +1 -0
- package/dist/chunk-LOSY3JCR.js +1 -0
- package/dist/chunk-OQMK7H2R.js +1 -0
- package/dist/chunk-Q7GRUZHR.js +1 -0
- package/dist/chunk-XKFPM4SY.js +2 -0
- package/dist/chunk-Y3Q3LOFT.js +1 -0
- package/dist/chunk-YRY4OLQF.js +1 -0
- package/dist/{component-DHAn9JxU.d.ts → component-mtwBWhUr.d.ts} +1 -1
- package/dist/for/index.d.ts +61 -0
- package/dist/for/index.js +1 -0
- package/dist/foundations/core.d.ts +449 -0
- package/dist/foundations/core.js +1 -0
- package/dist/foundations/index.d.ts +4 -722
- package/dist/foundations/index.js +1 -1274
- package/dist/foundations/structures.d.ts +223 -0
- package/dist/foundations/structures.js +1 -0
- package/dist/fx/index.js +1 -636
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -3955
- package/dist/jsx-dev-runtime.js +1 -17
- package/dist/jsx-runtime.js +1 -23
- package/dist/logger-MPMIVXAP.js +1 -0
- package/dist/main-EPE35NMW.js +65 -0
- package/dist/navigate-6CC6IXXF.js +1 -0
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.js +1 -792
- package/dist/route-4QZ3RYN5.js +1 -0
- package/dist/router/index.d.ts +5 -0
- package/dist/router/index.js +1 -3194
- package/dist/ssr/index.js +1 -3935
- package/dist/vite/index.js +1 -2306
- package/package.json +19 -5
- package/dist/foundations/index.js.map +0 -1
- package/dist/fx/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jsx-dev-runtime.js.map +0 -1
- package/dist/jsx-runtime.js.map +0 -1
- package/dist/resources/index.js.map +0 -1
- package/dist/router/index.js.map +0 -1
- package/dist/ssr/index.js.map +0 -1
- package/dist/vite/index.js.map +0 -1
package/dist/ssr/index.js
CHANGED
|
@@ -1,3935 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
var __export = (target, all) => {
|
|
3
|
-
for (var name in all)
|
|
4
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
// src/router/route.ts
|
|
8
|
-
var route_exports = {};
|
|
9
|
-
__export(route_exports, {
|
|
10
|
-
_lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
|
|
11
|
-
_unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
|
|
12
|
-
clearRoutes: () => clearRoutes,
|
|
13
|
-
getLoadedNamespaces: () => getLoadedNamespaces,
|
|
14
|
-
getNamespaceRoutes: () => getNamespaceRoutes,
|
|
15
|
-
getRoutes: () => getRoutes,
|
|
16
|
-
lockRouteRegistration: () => lockRouteRegistration,
|
|
17
|
-
registerRoute: () => registerRoute,
|
|
18
|
-
resolveRoute: () => resolveRoute,
|
|
19
|
-
route: () => route,
|
|
20
|
-
setServerLocation: () => setServerLocation,
|
|
21
|
-
unloadNamespace: () => unloadNamespace
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// src/router/match.ts
|
|
25
|
-
function match(path, pattern) {
|
|
26
|
-
const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
27
|
-
const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
|
|
28
|
-
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
29
|
-
const patternSegments = normalizedPattern.split("/").filter(Boolean);
|
|
30
|
-
if (patternSegments.length === 1 && patternSegments[0] === "*") {
|
|
31
|
-
return {
|
|
32
|
-
matched: true,
|
|
33
|
-
params: {
|
|
34
|
-
"*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
if (pathSegments.length !== patternSegments.length) {
|
|
39
|
-
return { matched: false, params: {} };
|
|
40
|
-
}
|
|
41
|
-
const params = {};
|
|
42
|
-
for (let i = 0; i < patternSegments.length; i++) {
|
|
43
|
-
const patternSegment = patternSegments[i];
|
|
44
|
-
const pathSegment = pathSegments[i];
|
|
45
|
-
if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
|
|
46
|
-
const paramName = patternSegment.slice(1, -1);
|
|
47
|
-
params[paramName] = decodeURIComponent(pathSegment);
|
|
48
|
-
} else if (patternSegment === "*") {
|
|
49
|
-
params["*"] = pathSegment;
|
|
50
|
-
} else if (patternSegment !== pathSegment) {
|
|
51
|
-
return { matched: false, params: {} };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return { matched: true, params };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// src/dev/invariant.ts
|
|
58
|
-
function invariant(condition, message, context) {
|
|
59
|
-
if (!condition) {
|
|
60
|
-
const contextStr = "";
|
|
61
|
-
throw new Error(`[Askr Invariant] ${message}${contextStr}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function assertSchedulingPrecondition(condition, violationMessage) {
|
|
65
|
-
invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/dev/logger.ts
|
|
69
|
-
function callConsole(method, args) {
|
|
70
|
-
const c = typeof console !== "undefined" ? console : void 0;
|
|
71
|
-
if (!c) return;
|
|
72
|
-
const fn = c[method];
|
|
73
|
-
if (typeof fn === "function") {
|
|
74
|
-
try {
|
|
75
|
-
fn.apply(console, args);
|
|
76
|
-
} catch {
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
var logger = {
|
|
81
|
-
debug: (...args) => {
|
|
82
|
-
if (process.env.NODE_ENV === "production") return;
|
|
83
|
-
callConsole("debug", args);
|
|
84
|
-
},
|
|
85
|
-
info: (...args) => {
|
|
86
|
-
if (process.env.NODE_ENV === "production") return;
|
|
87
|
-
callConsole("info", args);
|
|
88
|
-
},
|
|
89
|
-
warn: (...args) => {
|
|
90
|
-
if (process.env.NODE_ENV === "production") return;
|
|
91
|
-
callConsole("warn", args);
|
|
92
|
-
},
|
|
93
|
-
error: (...args) => {
|
|
94
|
-
callConsole("error", args);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// src/runtime/scheduler.ts
|
|
99
|
-
var MAX_FLUSH_DEPTH = 50;
|
|
100
|
-
function isBulkCommitActive() {
|
|
101
|
-
try {
|
|
102
|
-
const fb = globalThis.__ASKR_FASTLANE;
|
|
103
|
-
return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
|
|
104
|
-
} catch (e) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
var Scheduler = class {
|
|
109
|
-
constructor() {
|
|
110
|
-
this.q = [];
|
|
111
|
-
this.head = 0;
|
|
112
|
-
this.running = false;
|
|
113
|
-
this.inHandler = false;
|
|
114
|
-
this.depth = 0;
|
|
115
|
-
this.executionDepth = 0;
|
|
116
|
-
// for compat with existing diagnostics
|
|
117
|
-
// Monotonic flush version increments at end of each flush
|
|
118
|
-
this.flushVersion = 0;
|
|
119
|
-
// Best-effort microtask kick scheduling
|
|
120
|
-
this.kickScheduled = false;
|
|
121
|
-
// Escape hatch flag for runWithSyncProgress
|
|
122
|
-
this.allowSyncProgress = false;
|
|
123
|
-
// Waiters waiting for flushVersion >= target
|
|
124
|
-
this.waiters = [];
|
|
125
|
-
// Keep a lightweight taskCount for compatibility/diagnostics
|
|
126
|
-
this.taskCount = 0;
|
|
127
|
-
}
|
|
128
|
-
enqueue(task) {
|
|
129
|
-
assertSchedulingPrecondition(
|
|
130
|
-
typeof task === "function",
|
|
131
|
-
"enqueue() requires a function"
|
|
132
|
-
);
|
|
133
|
-
if (isBulkCommitActive() && !this.allowSyncProgress) {
|
|
134
|
-
if (process.env.NODE_ENV !== "production") {
|
|
135
|
-
throw new Error(
|
|
136
|
-
"[Scheduler] enqueue() during bulk commit (not allowed)"
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
this.q.push(task);
|
|
142
|
-
this.taskCount++;
|
|
143
|
-
if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
|
|
144
|
-
this.kickScheduled = true;
|
|
145
|
-
queueMicrotask(() => {
|
|
146
|
-
this.kickScheduled = false;
|
|
147
|
-
if (this.running) return;
|
|
148
|
-
if (isBulkCommitActive()) return;
|
|
149
|
-
try {
|
|
150
|
-
this.flush();
|
|
151
|
-
} catch (err) {
|
|
152
|
-
setTimeout(() => {
|
|
153
|
-
throw err;
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
flush() {
|
|
160
|
-
invariant(
|
|
161
|
-
!this.running,
|
|
162
|
-
"[Scheduler] flush() called while already running"
|
|
163
|
-
);
|
|
164
|
-
if (process.env.NODE_ENV !== "production") {
|
|
165
|
-
if (isBulkCommitActive() && !this.allowSyncProgress) {
|
|
166
|
-
throw new Error(
|
|
167
|
-
"[Scheduler] flush() started during bulk commit (not allowed)"
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
this.running = true;
|
|
172
|
-
this.depth = 0;
|
|
173
|
-
let fatal = null;
|
|
174
|
-
try {
|
|
175
|
-
while (this.head < this.q.length) {
|
|
176
|
-
this.depth++;
|
|
177
|
-
if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
|
|
178
|
-
throw new Error(
|
|
179
|
-
`[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
const task = this.q[this.head++];
|
|
183
|
-
try {
|
|
184
|
-
this.executionDepth++;
|
|
185
|
-
task();
|
|
186
|
-
this.executionDepth--;
|
|
187
|
-
} catch (err) {
|
|
188
|
-
if (this.executionDepth > 0) this.executionDepth = 0;
|
|
189
|
-
fatal = err;
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
if (this.taskCount > 0) this.taskCount--;
|
|
193
|
-
}
|
|
194
|
-
} finally {
|
|
195
|
-
this.running = false;
|
|
196
|
-
this.depth = 0;
|
|
197
|
-
this.executionDepth = 0;
|
|
198
|
-
if (this.head >= this.q.length) {
|
|
199
|
-
this.q.length = 0;
|
|
200
|
-
this.head = 0;
|
|
201
|
-
} else if (this.head > 0) {
|
|
202
|
-
const remaining = this.q.length - this.head;
|
|
203
|
-
for (let i = 0; i < remaining; i++) {
|
|
204
|
-
this.q[i] = this.q[this.head + i];
|
|
205
|
-
}
|
|
206
|
-
this.q.length = remaining;
|
|
207
|
-
this.head = 0;
|
|
208
|
-
}
|
|
209
|
-
this.flushVersion++;
|
|
210
|
-
this.resolveWaiters();
|
|
211
|
-
}
|
|
212
|
-
if (fatal) throw fatal;
|
|
213
|
-
}
|
|
214
|
-
runWithSyncProgress(fn) {
|
|
215
|
-
const prev = this.allowSyncProgress;
|
|
216
|
-
this.allowSyncProgress = true;
|
|
217
|
-
const g = globalThis;
|
|
218
|
-
const origQueueMicrotask = g.queueMicrotask;
|
|
219
|
-
const origSetTimeout = g.setTimeout;
|
|
220
|
-
if (process.env.NODE_ENV !== "production") {
|
|
221
|
-
g.queueMicrotask = () => {
|
|
222
|
-
throw new Error(
|
|
223
|
-
"[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
|
|
224
|
-
);
|
|
225
|
-
};
|
|
226
|
-
g.setTimeout = () => {
|
|
227
|
-
throw new Error(
|
|
228
|
-
"[Scheduler] setTimeout not allowed during runWithSyncProgress"
|
|
229
|
-
);
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
const startVersion = this.flushVersion;
|
|
233
|
-
try {
|
|
234
|
-
const res = fn();
|
|
235
|
-
if (!this.running && this.q.length - this.head > 0) {
|
|
236
|
-
this.flush();
|
|
237
|
-
}
|
|
238
|
-
if (process.env.NODE_ENV !== "production") {
|
|
239
|
-
if (this.q.length - this.head > 0) {
|
|
240
|
-
throw new Error(
|
|
241
|
-
"[Scheduler] tasks remain after runWithSyncProgress flush"
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return res;
|
|
246
|
-
} finally {
|
|
247
|
-
if (process.env.NODE_ENV !== "production") {
|
|
248
|
-
g.queueMicrotask = origQueueMicrotask;
|
|
249
|
-
g.setTimeout = origSetTimeout;
|
|
250
|
-
}
|
|
251
|
-
try {
|
|
252
|
-
if (this.flushVersion === startVersion) {
|
|
253
|
-
this.flushVersion++;
|
|
254
|
-
this.resolveWaiters();
|
|
255
|
-
}
|
|
256
|
-
} catch (e) {
|
|
257
|
-
}
|
|
258
|
-
this.allowSyncProgress = prev;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
waitForFlush(targetVersion, timeoutMs = 2e3) {
|
|
262
|
-
const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
|
|
263
|
-
if (this.flushVersion >= target) return Promise.resolve();
|
|
264
|
-
return new Promise((resolve, reject) => {
|
|
265
|
-
const timer = setTimeout(() => {
|
|
266
|
-
const ns = globalThis.__ASKR__ || {};
|
|
267
|
-
const diag = {
|
|
268
|
-
flushVersion: this.flushVersion,
|
|
269
|
-
queueLen: this.q.length - this.head,
|
|
270
|
-
running: this.running,
|
|
271
|
-
inHandler: this.inHandler,
|
|
272
|
-
bulk: isBulkCommitActive(),
|
|
273
|
-
namespace: ns
|
|
274
|
-
};
|
|
275
|
-
reject(
|
|
276
|
-
new Error(
|
|
277
|
-
`waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
|
|
278
|
-
)
|
|
279
|
-
);
|
|
280
|
-
}, timeoutMs);
|
|
281
|
-
this.waiters.push({ target, resolve, reject, timer });
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
getState() {
|
|
285
|
-
return {
|
|
286
|
-
queueLength: this.q.length - this.head,
|
|
287
|
-
running: this.running,
|
|
288
|
-
depth: this.depth,
|
|
289
|
-
executionDepth: this.executionDepth,
|
|
290
|
-
taskCount: this.taskCount,
|
|
291
|
-
flushVersion: this.flushVersion,
|
|
292
|
-
// New fields for optional inspection
|
|
293
|
-
inHandler: this.inHandler,
|
|
294
|
-
allowSyncProgress: this.allowSyncProgress
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
setInHandler(v) {
|
|
298
|
-
this.inHandler = v;
|
|
299
|
-
}
|
|
300
|
-
isInHandler() {
|
|
301
|
-
return this.inHandler;
|
|
302
|
-
}
|
|
303
|
-
isExecuting() {
|
|
304
|
-
return this.running || this.executionDepth > 0;
|
|
305
|
-
}
|
|
306
|
-
// Clear pending synchronous tasks (used by fastlane enter/exit)
|
|
307
|
-
clearPendingSyncTasks() {
|
|
308
|
-
const remaining = this.q.length - this.head;
|
|
309
|
-
if (remaining <= 0) return 0;
|
|
310
|
-
if (this.running) {
|
|
311
|
-
this.q.length = this.head;
|
|
312
|
-
this.taskCount = Math.max(0, this.taskCount - remaining);
|
|
313
|
-
queueMicrotask(() => {
|
|
314
|
-
try {
|
|
315
|
-
this.flushVersion++;
|
|
316
|
-
this.resolveWaiters();
|
|
317
|
-
} catch (e) {
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
return remaining;
|
|
321
|
-
}
|
|
322
|
-
this.q.length = 0;
|
|
323
|
-
this.head = 0;
|
|
324
|
-
this.taskCount = Math.max(0, this.taskCount - remaining);
|
|
325
|
-
this.flushVersion++;
|
|
326
|
-
this.resolveWaiters();
|
|
327
|
-
return remaining;
|
|
328
|
-
}
|
|
329
|
-
resolveWaiters() {
|
|
330
|
-
if (this.waiters.length === 0) return;
|
|
331
|
-
const ready = [];
|
|
332
|
-
const remaining = [];
|
|
333
|
-
for (const w of this.waiters) {
|
|
334
|
-
if (this.flushVersion >= w.target) {
|
|
335
|
-
if (w.timer) clearTimeout(w.timer);
|
|
336
|
-
ready.push(w.resolve);
|
|
337
|
-
} else {
|
|
338
|
-
remaining.push(w);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
this.waiters = remaining;
|
|
342
|
-
for (const r of ready) r();
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
var globalScheduler = new Scheduler();
|
|
346
|
-
function isSchedulerExecuting() {
|
|
347
|
-
return globalScheduler.isExecuting();
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// src/common/jsx.ts
|
|
351
|
-
var ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
|
|
352
|
-
var Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
|
|
353
|
-
|
|
354
|
-
// src/runtime/context.ts
|
|
355
|
-
var CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
|
|
356
|
-
var currentContextFrame = null;
|
|
357
|
-
function withContext(frame, fn) {
|
|
358
|
-
const oldFrame = currentContextFrame;
|
|
359
|
-
currentContextFrame = frame;
|
|
360
|
-
try {
|
|
361
|
-
return fn();
|
|
362
|
-
} finally {
|
|
363
|
-
currentContextFrame = oldFrame;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
function getCurrentContextFrame() {
|
|
367
|
-
return currentContextFrame;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// src/renderer/diag.ts
|
|
371
|
-
function getDiagMap() {
|
|
372
|
-
try {
|
|
373
|
-
const root = globalThis;
|
|
374
|
-
if (!root.__ASKR_DIAG) root.__ASKR_DIAG = {};
|
|
375
|
-
return root.__ASKR_DIAG;
|
|
376
|
-
} catch (e) {
|
|
377
|
-
return {};
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
function __ASKR_set(key, value) {
|
|
381
|
-
try {
|
|
382
|
-
const g = getDiagMap();
|
|
383
|
-
g[key] = value;
|
|
384
|
-
try {
|
|
385
|
-
const root = globalThis;
|
|
386
|
-
try {
|
|
387
|
-
const ns = root.__ASKR__ || (root.__ASKR__ = {});
|
|
388
|
-
try {
|
|
389
|
-
ns[key] = value;
|
|
390
|
-
} catch (e) {
|
|
391
|
-
void e;
|
|
392
|
-
}
|
|
393
|
-
} catch (e) {
|
|
394
|
-
void e;
|
|
395
|
-
}
|
|
396
|
-
} catch (e) {
|
|
397
|
-
void e;
|
|
398
|
-
}
|
|
399
|
-
} catch (e) {
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
function __ASKR_incCounter(key) {
|
|
403
|
-
try {
|
|
404
|
-
const g = getDiagMap();
|
|
405
|
-
const prev = typeof g[key] === "number" ? g[key] : 0;
|
|
406
|
-
const next = prev + 1;
|
|
407
|
-
g[key] = next;
|
|
408
|
-
try {
|
|
409
|
-
const root = globalThis;
|
|
410
|
-
const ns = root.__ASKR__ || (root.__ASKR__ = {});
|
|
411
|
-
try {
|
|
412
|
-
const nsPrev = typeof ns[key] === "number" ? ns[key] : 0;
|
|
413
|
-
ns[key] = nsPrev + 1;
|
|
414
|
-
} catch (e) {
|
|
415
|
-
void e;
|
|
416
|
-
}
|
|
417
|
-
} catch (e) {
|
|
418
|
-
void e;
|
|
419
|
-
}
|
|
420
|
-
} catch (e) {
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// src/renderer/utils.ts
|
|
425
|
-
function parseEventName(propName) {
|
|
426
|
-
if (!propName.startsWith("on") || propName.length <= 2) return null;
|
|
427
|
-
return propName.slice(2).charAt(0).toLowerCase() + propName.slice(3).toLowerCase();
|
|
428
|
-
}
|
|
429
|
-
function getPassiveOptions(eventName) {
|
|
430
|
-
if (eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch")) {
|
|
431
|
-
return { passive: true };
|
|
432
|
-
}
|
|
433
|
-
return void 0;
|
|
434
|
-
}
|
|
435
|
-
function createWrappedHandler(handler, flushAfter = false) {
|
|
436
|
-
return (event) => {
|
|
437
|
-
globalScheduler.setInHandler(true);
|
|
438
|
-
try {
|
|
439
|
-
handler(event);
|
|
440
|
-
} catch (error) {
|
|
441
|
-
logger.error("[Askr] Event handler error:", error);
|
|
442
|
-
} finally {
|
|
443
|
-
globalScheduler.setInHandler(false);
|
|
444
|
-
if (flushAfter) {
|
|
445
|
-
const state = globalScheduler.getState();
|
|
446
|
-
if ((state.queueLength ?? 0) > 0 && !state.running) {
|
|
447
|
-
queueMicrotask(() => {
|
|
448
|
-
try {
|
|
449
|
-
if (!globalScheduler.isExecuting()) globalScheduler.flush();
|
|
450
|
-
} catch (err) {
|
|
451
|
-
queueMicrotask(() => {
|
|
452
|
-
throw err;
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
function isSkippedProp(key) {
|
|
462
|
-
return key === "children" || key === "key" || key === "ref";
|
|
463
|
-
}
|
|
464
|
-
function isIgnoredForPropChanges(key) {
|
|
465
|
-
if (key === "children" || key === "key") return true;
|
|
466
|
-
if (key.startsWith("on") && key.length > 2) return true;
|
|
467
|
-
if (key.startsWith("data-")) return true;
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
function hasPropChanged(el, key, value) {
|
|
471
|
-
try {
|
|
472
|
-
if (key === "class" || key === "className") {
|
|
473
|
-
return el.className !== String(value);
|
|
474
|
-
}
|
|
475
|
-
if (key === "value" || key === "checked") {
|
|
476
|
-
return el[key] !== value;
|
|
477
|
-
}
|
|
478
|
-
const attr = el.getAttribute(key);
|
|
479
|
-
if (value === void 0 || value === null || value === false) {
|
|
480
|
-
return attr !== null;
|
|
481
|
-
}
|
|
482
|
-
return String(value) !== attr;
|
|
483
|
-
} catch {
|
|
484
|
-
return true;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
function hasNonTrivialProps(props) {
|
|
488
|
-
for (const k of Object.keys(props)) {
|
|
489
|
-
if (isIgnoredForPropChanges(k)) continue;
|
|
490
|
-
return true;
|
|
491
|
-
}
|
|
492
|
-
return false;
|
|
493
|
-
}
|
|
494
|
-
function checkPropChanges(el, props) {
|
|
495
|
-
for (const k of Object.keys(props)) {
|
|
496
|
-
if (isIgnoredForPropChanges(k)) continue;
|
|
497
|
-
if (hasPropChanged(el, k, props[k])) {
|
|
498
|
-
return true;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
function extractKey(vnode) {
|
|
504
|
-
if (typeof vnode !== "object" || vnode === null) return void 0;
|
|
505
|
-
const obj = vnode;
|
|
506
|
-
const rawKey = obj.key ?? obj.props?.key;
|
|
507
|
-
if (rawKey === void 0) return void 0;
|
|
508
|
-
return typeof rawKey === "symbol" ? String(rawKey) : rawKey;
|
|
509
|
-
}
|
|
510
|
-
function buildKeyMapFromChildren(parent) {
|
|
511
|
-
const map = /* @__PURE__ */ new Map();
|
|
512
|
-
for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
|
|
513
|
-
const k = ch.getAttribute("data-key");
|
|
514
|
-
if (k !== null) {
|
|
515
|
-
map.set(k, ch);
|
|
516
|
-
const n = Number(k);
|
|
517
|
-
if (!Number.isNaN(n)) map.set(n, ch);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return map;
|
|
521
|
-
}
|
|
522
|
-
function recordDOMReplace(source) {
|
|
523
|
-
try {
|
|
524
|
-
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
525
|
-
__ASKR_set(`__LAST_DOM_REPLACE_STACK_${source}`, new Error().stack);
|
|
526
|
-
} catch {
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
function recordFastPathStats(stats, counterName) {
|
|
530
|
-
try {
|
|
531
|
-
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
532
|
-
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
533
|
-
if (counterName) {
|
|
534
|
-
__ASKR_incCounter(counterName);
|
|
535
|
-
}
|
|
536
|
-
} catch {
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function logFastPathDebug(message, indexOrData, data) {
|
|
540
|
-
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
541
|
-
if (data !== void 0) {
|
|
542
|
-
logger.warn(`[Askr][FASTPATH] ${message}`, indexOrData, data);
|
|
543
|
-
} else if (indexOrData !== void 0) {
|
|
544
|
-
logger.warn(`[Askr][FASTPATH] ${message}`, indexOrData);
|
|
545
|
-
} else {
|
|
546
|
-
logger.warn(`[Askr][FASTPATH] ${message}`);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
function now() {
|
|
551
|
-
return typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// src/renderer/keyed.ts
|
|
555
|
-
var keyedElements = /* @__PURE__ */ new WeakMap();
|
|
556
|
-
function getKeyMapForElement(el) {
|
|
557
|
-
return keyedElements.get(el);
|
|
558
|
-
}
|
|
559
|
-
function populateKeyMapForElement(parent) {
|
|
560
|
-
try {
|
|
561
|
-
if (keyedElements.has(parent)) return;
|
|
562
|
-
let domMap = buildKeyMapFromChildren(parent);
|
|
563
|
-
if (domMap.size === 0) {
|
|
564
|
-
domMap = /* @__PURE__ */ new Map();
|
|
565
|
-
const children = Array.from(parent.children);
|
|
566
|
-
for (const ch of children) {
|
|
567
|
-
const text = (ch.textContent || "").trim();
|
|
568
|
-
if (text) {
|
|
569
|
-
domMap.set(text, ch);
|
|
570
|
-
const n = Number(text);
|
|
571
|
-
if (!Number.isNaN(n)) domMap.set(n, ch);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
if (domMap.size > 0) keyedElements.set(parent, domMap);
|
|
576
|
-
} catch {
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
var _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
|
|
580
|
-
function extractKeyedVnodes(newChildren) {
|
|
581
|
-
const result = [];
|
|
582
|
-
for (const child of newChildren) {
|
|
583
|
-
const key = extractKey(child);
|
|
584
|
-
if (key !== void 0) {
|
|
585
|
-
result.push({ key, vnode: child });
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
return result;
|
|
589
|
-
}
|
|
590
|
-
function computeLISLength(positions) {
|
|
591
|
-
const tails = [];
|
|
592
|
-
for (const pos of positions) {
|
|
593
|
-
if (pos === -1) continue;
|
|
594
|
-
let lo = 0;
|
|
595
|
-
let hi = tails.length;
|
|
596
|
-
while (lo < hi) {
|
|
597
|
-
const mid = lo + hi >> 1;
|
|
598
|
-
if (tails[mid] < pos) lo = mid + 1;
|
|
599
|
-
else hi = mid;
|
|
600
|
-
}
|
|
601
|
-
if (lo === tails.length) tails.push(pos);
|
|
602
|
-
else tails[lo] = pos;
|
|
603
|
-
}
|
|
604
|
-
return tails.length;
|
|
605
|
-
}
|
|
606
|
-
function checkVnodesHaveProps(keyedVnodes) {
|
|
607
|
-
for (const { vnode } of keyedVnodes) {
|
|
608
|
-
if (typeof vnode !== "object" || vnode === null) continue;
|
|
609
|
-
const vnodeObj = vnode;
|
|
610
|
-
if (vnodeObj.props && hasNonTrivialProps(vnodeObj.props)) {
|
|
611
|
-
return true;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return false;
|
|
615
|
-
}
|
|
616
|
-
function checkVnodePropChanges(keyedVnodes, oldKeyMap) {
|
|
617
|
-
for (const { key, vnode } of keyedVnodes) {
|
|
618
|
-
const el = oldKeyMap?.get(key);
|
|
619
|
-
if (!el || typeof vnode !== "object" || vnode === null) continue;
|
|
620
|
-
const vnodeObj = vnode;
|
|
621
|
-
const props = vnodeObj.props || {};
|
|
622
|
-
for (const k of Object.keys(props)) {
|
|
623
|
-
if (isIgnoredForPropChanges(k)) continue;
|
|
624
|
-
if (hasPropChanged(el, k, props[k])) {
|
|
625
|
-
return true;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
return false;
|
|
630
|
-
}
|
|
631
|
-
function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
632
|
-
const keyedVnodes = extractKeyedVnodes(newChildren);
|
|
633
|
-
const totalKeyed = keyedVnodes.length;
|
|
634
|
-
const newKeyOrder = keyedVnodes.map((kv) => kv.key);
|
|
635
|
-
const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
|
|
636
|
-
let moveCount = 0;
|
|
637
|
-
for (let i = 0; i < newKeyOrder.length; i++) {
|
|
638
|
-
const k = newKeyOrder[i];
|
|
639
|
-
if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k || !oldKeyMap?.has(k)) {
|
|
640
|
-
moveCount++;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
const FAST_MOVE_THRESHOLD_ABS = 64;
|
|
644
|
-
const FAST_MOVE_THRESHOLD_REL = 0.1;
|
|
645
|
-
const cheapMoveTrigger = totalKeyed >= 128 && oldKeyOrder.length > 0 && moveCount > Math.max(
|
|
646
|
-
FAST_MOVE_THRESHOLD_ABS,
|
|
647
|
-
Math.floor(totalKeyed * FAST_MOVE_THRESHOLD_REL)
|
|
648
|
-
);
|
|
649
|
-
let lisTrigger = false;
|
|
650
|
-
let lisLen = 0;
|
|
651
|
-
if (totalKeyed >= 128) {
|
|
652
|
-
const parentChildren = Array.from(parent.children);
|
|
653
|
-
const positions = keyedVnodes.map(({ key }) => {
|
|
654
|
-
const el = oldKeyMap?.get(key);
|
|
655
|
-
return el?.parentElement === parent ? parentChildren.indexOf(el) : -1;
|
|
656
|
-
});
|
|
657
|
-
lisLen = computeLISLength(positions);
|
|
658
|
-
lisTrigger = lisLen < Math.floor(totalKeyed * 0.5);
|
|
659
|
-
}
|
|
660
|
-
const hasPropsPresent = checkVnodesHaveProps(keyedVnodes);
|
|
661
|
-
const hasPropChanges = checkVnodePropChanges(keyedVnodes, oldKeyMap);
|
|
662
|
-
const useFastPath = (cheapMoveTrigger || lisTrigger) && !hasPropChanges && !hasPropsPresent;
|
|
663
|
-
return {
|
|
664
|
-
useFastPath,
|
|
665
|
-
totalKeyed,
|
|
666
|
-
moveCount,
|
|
667
|
-
lisLen,
|
|
668
|
-
hasPropChanges
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// src/runtime/dev-namespace.ts
|
|
673
|
-
function getDevNamespace() {
|
|
674
|
-
if (process.env.NODE_ENV === "production") return {};
|
|
675
|
-
try {
|
|
676
|
-
const g = globalThis;
|
|
677
|
-
if (!g.__ASKR__) g.__ASKR__ = {};
|
|
678
|
-
return g.__ASKR__;
|
|
679
|
-
} catch {
|
|
680
|
-
return {};
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
function setDevValue(key, value) {
|
|
684
|
-
if (process.env.NODE_ENV === "production") return;
|
|
685
|
-
try {
|
|
686
|
-
getDevNamespace()[key] = value;
|
|
687
|
-
} catch {
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
function getDevValue(key) {
|
|
691
|
-
if (process.env.NODE_ENV === "production") return void 0;
|
|
692
|
-
try {
|
|
693
|
-
return getDevNamespace()[key];
|
|
694
|
-
} catch {
|
|
695
|
-
return void 0;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// src/runtime/fastlane.ts
|
|
700
|
-
var _bulkCommitActive = false;
|
|
701
|
-
var _appliedParents = null;
|
|
702
|
-
function enterBulkCommit() {
|
|
703
|
-
_bulkCommitActive = true;
|
|
704
|
-
_appliedParents = /* @__PURE__ */ new WeakSet();
|
|
705
|
-
try {
|
|
706
|
-
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
707
|
-
setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", cleared);
|
|
708
|
-
} catch (err) {
|
|
709
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
function exitBulkCommit() {
|
|
713
|
-
_bulkCommitActive = false;
|
|
714
|
-
_appliedParents = null;
|
|
715
|
-
}
|
|
716
|
-
function isBulkCommitActive2() {
|
|
717
|
-
return _bulkCommitActive;
|
|
718
|
-
}
|
|
719
|
-
function markFastPathApplied(parent) {
|
|
720
|
-
if (!_appliedParents) return;
|
|
721
|
-
try {
|
|
722
|
-
_appliedParents.add(parent);
|
|
723
|
-
} catch (e) {
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
function isFastPathApplied(parent) {
|
|
727
|
-
return !!(_appliedParents && _appliedParents.has(parent));
|
|
728
|
-
}
|
|
729
|
-
function finalizeReadSubscriptions(instance) {
|
|
730
|
-
const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
|
|
731
|
-
const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
|
|
732
|
-
const token = instance._currentRenderToken;
|
|
733
|
-
if (token === void 0) return;
|
|
734
|
-
for (const s of oldSet) {
|
|
735
|
-
if (!newSet.has(s)) {
|
|
736
|
-
const readers = s._readers;
|
|
737
|
-
if (readers) readers.delete(instance);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
instance.lastRenderToken = token;
|
|
741
|
-
for (const s of newSet) {
|
|
742
|
-
let readers = s._readers;
|
|
743
|
-
if (!readers) {
|
|
744
|
-
readers = /* @__PURE__ */ new Map();
|
|
745
|
-
s._readers = readers;
|
|
746
|
-
}
|
|
747
|
-
readers.set(instance, instance.lastRenderToken ?? 0);
|
|
748
|
-
}
|
|
749
|
-
instance._lastReadStates = newSet;
|
|
750
|
-
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
751
|
-
instance._currentRenderToken = void 0;
|
|
752
|
-
}
|
|
753
|
-
function unwrapFragmentForFastPath(vnode) {
|
|
754
|
-
if (!vnode || typeof vnode !== "object" || !("type" in vnode)) return vnode;
|
|
755
|
-
const v = vnode;
|
|
756
|
-
if (typeof v.type === "symbol" && (v.type === Fragment || String(v.type) === "Symbol(askr.fragment)")) {
|
|
757
|
-
const children = v.children || v.props?.children;
|
|
758
|
-
if (Array.isArray(children) && children.length > 0) {
|
|
759
|
-
for (const child of children) {
|
|
760
|
-
if (child && typeof child === "object" && "type" in child) {
|
|
761
|
-
const c = child;
|
|
762
|
-
if (typeof c.type === "string") {
|
|
763
|
-
return child;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
return vnode;
|
|
770
|
-
}
|
|
771
|
-
function classifyUpdate(instance, result) {
|
|
772
|
-
const unwrappedResult = unwrapFragmentForFastPath(result);
|
|
773
|
-
if (!unwrappedResult || typeof unwrappedResult !== "object" || !("type" in unwrappedResult))
|
|
774
|
-
return { useFastPath: false, reason: "not-vnode" };
|
|
775
|
-
const vnode = unwrappedResult;
|
|
776
|
-
if (vnode == null || typeof vnode.type !== "string")
|
|
777
|
-
return { useFastPath: false, reason: "not-intrinsic" };
|
|
778
|
-
const parent = instance.target;
|
|
779
|
-
if (!parent) return { useFastPath: false, reason: "no-root" };
|
|
780
|
-
const firstChild = parent.children[0];
|
|
781
|
-
if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
|
|
782
|
-
if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
|
|
783
|
-
return { useFastPath: false, reason: "root-tag-mismatch" };
|
|
784
|
-
const children = vnode.children || vnode.props?.children;
|
|
785
|
-
if (!Array.isArray(children))
|
|
786
|
-
return { useFastPath: false, reason: "no-children-array" };
|
|
787
|
-
for (const c of children) {
|
|
788
|
-
if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
|
|
789
|
-
return { useFastPath: false, reason: "component-child-present" };
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
if (instance.mountOperations.length > 0)
|
|
793
|
-
return { useFastPath: false, reason: "pending-mounts" };
|
|
794
|
-
try {
|
|
795
|
-
populateKeyMapForElement(firstChild);
|
|
796
|
-
} catch {
|
|
797
|
-
}
|
|
798
|
-
const oldKeyMap = getKeyMapForElement(firstChild);
|
|
799
|
-
const decision = isKeyedReorderFastPathEligible(
|
|
800
|
-
firstChild,
|
|
801
|
-
children,
|
|
802
|
-
oldKeyMap
|
|
803
|
-
);
|
|
804
|
-
if (!decision.useFastPath || decision.totalKeyed < 128)
|
|
805
|
-
return { ...decision, useFastPath: false, reason: "renderer-declined" };
|
|
806
|
-
return { ...decision, useFastPath: true };
|
|
807
|
-
}
|
|
808
|
-
function commitReorderOnly(instance, result) {
|
|
809
|
-
const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
|
|
810
|
-
if (typeof evaluate2 !== "function") {
|
|
811
|
-
logger.warn(
|
|
812
|
-
"[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
|
|
813
|
-
);
|
|
814
|
-
return false;
|
|
815
|
-
}
|
|
816
|
-
const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
|
|
817
|
-
enterBulkCommit();
|
|
818
|
-
try {
|
|
819
|
-
globalScheduler.runWithSyncProgress(() => {
|
|
820
|
-
evaluate2(result, instance.target);
|
|
821
|
-
try {
|
|
822
|
-
finalizeReadSubscriptions(instance);
|
|
823
|
-
} catch (e) {
|
|
824
|
-
if (process.env.NODE_ENV !== "production") throw e;
|
|
825
|
-
}
|
|
826
|
-
});
|
|
827
|
-
const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
828
|
-
setDevValue("__FASTLANE_CLEARED_AFTER", clearedAfter);
|
|
829
|
-
if (process.env.NODE_ENV !== "production") {
|
|
830
|
-
validateFastLaneInvariants(instance, schedBefore);
|
|
831
|
-
}
|
|
832
|
-
return true;
|
|
833
|
-
} finally {
|
|
834
|
-
exitBulkCommit();
|
|
835
|
-
}
|
|
836
|
-
if (process.env.NODE_ENV !== "production") {
|
|
837
|
-
if (isBulkCommitActive2()) {
|
|
838
|
-
throw new Error(
|
|
839
|
-
"Fast-lane invariant violated: bulk commit flag still set after commit"
|
|
840
|
-
);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
function validateFastLaneInvariants(instance, schedBefore) {
|
|
845
|
-
const commitCount = getDevValue("__LAST_FASTPATH_COMMIT_COUNT") ?? 0;
|
|
846
|
-
const invariants = {
|
|
847
|
-
commitCount,
|
|
848
|
-
mountOps: instance.mountOperations.length,
|
|
849
|
-
cleanupFns: instance.cleanupFns.length
|
|
850
|
-
};
|
|
851
|
-
setDevValue("__LAST_FASTLANE_INVARIANTS", invariants);
|
|
852
|
-
if (commitCount !== 1) {
|
|
853
|
-
console.error(
|
|
854
|
-
"[FASTLANE][INV] commitCount",
|
|
855
|
-
commitCount,
|
|
856
|
-
"diag",
|
|
857
|
-
globalThis.__ASKR_DIAG
|
|
858
|
-
);
|
|
859
|
-
throw new Error(
|
|
860
|
-
"Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
|
|
861
|
-
);
|
|
862
|
-
}
|
|
863
|
-
if (invariants.mountOps > 0) {
|
|
864
|
-
throw new Error(
|
|
865
|
-
"Fast-lane invariant violated: mount operations were registered during bulk commit"
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
if (invariants.cleanupFns > 0) {
|
|
869
|
-
throw new Error(
|
|
870
|
-
"Fast-lane invariant violated: cleanup functions were added during bulk commit"
|
|
871
|
-
);
|
|
872
|
-
}
|
|
873
|
-
const schedAfter = globalScheduler.getState();
|
|
874
|
-
if (schedBefore && schedAfter && schedAfter.taskCount > schedBefore.taskCount) {
|
|
875
|
-
console.error(
|
|
876
|
-
"[FASTLANE] schedBefore, schedAfter",
|
|
877
|
-
schedBefore,
|
|
878
|
-
schedAfter
|
|
879
|
-
);
|
|
880
|
-
console.error("[FASTLANE] enqueue logs", getDevValue("__ENQUEUE_LOGS"));
|
|
881
|
-
throw new Error(
|
|
882
|
-
"Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
let finalState = globalScheduler.getState();
|
|
886
|
-
const executing = globalScheduler.isExecuting();
|
|
887
|
-
let outstandingAfter = Math.max(
|
|
888
|
-
0,
|
|
889
|
-
finalState.taskCount - (executing ? 1 : 0)
|
|
890
|
-
);
|
|
891
|
-
if (outstandingAfter !== 0) {
|
|
892
|
-
let attempts = 0;
|
|
893
|
-
while (attempts < 5) {
|
|
894
|
-
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
895
|
-
if (cleared === 0) break;
|
|
896
|
-
attempts++;
|
|
897
|
-
}
|
|
898
|
-
finalState = globalScheduler.getState();
|
|
899
|
-
outstandingAfter = Math.max(
|
|
900
|
-
0,
|
|
901
|
-
finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
|
|
902
|
-
);
|
|
903
|
-
if (outstandingAfter !== 0) {
|
|
904
|
-
console.error(
|
|
905
|
-
"[FASTLANE] Post-commit enqueue logs:",
|
|
906
|
-
getDevValue("__ENQUEUE_LOGS")
|
|
907
|
-
);
|
|
908
|
-
console.error(
|
|
909
|
-
"[FASTLANE] Cleared counts:",
|
|
910
|
-
getDevValue("__FASTLANE_CLEARED_TASKS"),
|
|
911
|
-
getDevValue("__FASTLANE_CLEARED_AFTER")
|
|
912
|
-
);
|
|
913
|
-
throw new Error(
|
|
914
|
-
`Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
|
|
915
|
-
);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
function tryRuntimeFastLaneSync(instance, result) {
|
|
920
|
-
const cls = classifyUpdate(instance, result);
|
|
921
|
-
if (!cls.useFastPath) {
|
|
922
|
-
setDevValue("__LAST_FASTPATH_STATS", void 0);
|
|
923
|
-
setDevValue("__LAST_FASTPATH_COMMIT_COUNT", 0);
|
|
924
|
-
return false;
|
|
925
|
-
}
|
|
926
|
-
try {
|
|
927
|
-
return commitReorderOnly(instance, result);
|
|
928
|
-
} catch (err) {
|
|
929
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
930
|
-
return false;
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
if (typeof globalThis !== "undefined") {
|
|
934
|
-
globalThis.__ASKR_FASTLANE = {
|
|
935
|
-
isBulkCommitActive: isBulkCommitActive2,
|
|
936
|
-
enterBulkCommit,
|
|
937
|
-
exitBulkCommit,
|
|
938
|
-
tryRuntimeFastLaneSync,
|
|
939
|
-
markFastPathApplied,
|
|
940
|
-
isFastPathApplied
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// src/common/vnode.ts
|
|
945
|
-
function _isDOMElement(node) {
|
|
946
|
-
return typeof node === "object" && node !== null && "type" in node;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// src/renderer/cleanup.ts
|
|
950
|
-
function cleanupSingleInstance(node, errors, strict) {
|
|
951
|
-
const inst = node.__ASKR_INSTANCE;
|
|
952
|
-
if (!inst) return;
|
|
953
|
-
try {
|
|
954
|
-
cleanupComponent(inst);
|
|
955
|
-
} catch (err) {
|
|
956
|
-
logger.warn("[Askr] cleanupComponent failed:", err);
|
|
957
|
-
}
|
|
958
|
-
try {
|
|
959
|
-
delete node.__ASKR_INSTANCE;
|
|
960
|
-
} catch (e) {
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
function forEachDescendantElement(root, visit) {
|
|
964
|
-
try {
|
|
965
|
-
const doc = root.ownerDocument;
|
|
966
|
-
const createTreeWalker = doc?.createTreeWalker;
|
|
967
|
-
if (typeof createTreeWalker === "function") {
|
|
968
|
-
const walker = createTreeWalker.call(doc, root, 1);
|
|
969
|
-
let n = walker.firstChild();
|
|
970
|
-
while (n) {
|
|
971
|
-
visit(n);
|
|
972
|
-
n = walker.nextNode();
|
|
973
|
-
}
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
} catch {
|
|
977
|
-
}
|
|
978
|
-
const descendants = root.querySelectorAll("*");
|
|
979
|
-
for (let i = 0; i < descendants.length; i++) {
|
|
980
|
-
visit(descendants[i]);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
function cleanupInstanceIfPresent(node, opts) {
|
|
984
|
-
if (!node || !(node instanceof Element)) return;
|
|
985
|
-
const strict = false;
|
|
986
|
-
const errors = null;
|
|
987
|
-
try {
|
|
988
|
-
cleanupSingleInstance(node, errors, strict);
|
|
989
|
-
} catch (err) {
|
|
990
|
-
logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
|
|
991
|
-
}
|
|
992
|
-
try {
|
|
993
|
-
forEachDescendantElement(node, (d) => {
|
|
994
|
-
try {
|
|
995
|
-
cleanupSingleInstance(d, errors, strict);
|
|
996
|
-
} catch (err) {
|
|
997
|
-
if (strict) ;
|
|
998
|
-
else
|
|
999
|
-
logger.warn(
|
|
1000
|
-
"[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
|
|
1001
|
-
err
|
|
1002
|
-
);
|
|
1003
|
-
}
|
|
1004
|
-
});
|
|
1005
|
-
} catch (err) {
|
|
1006
|
-
logger.warn(
|
|
1007
|
-
"[Askr] cleanupInstanceIfPresent descendant query failed:",
|
|
1008
|
-
err
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
function cleanupInstancesUnder(node, opts) {
|
|
1013
|
-
cleanupInstanceIfPresent(node);
|
|
1014
|
-
}
|
|
1015
|
-
var elementListeners = /* @__PURE__ */ new WeakMap();
|
|
1016
|
-
function removeElementListeners(element) {
|
|
1017
|
-
const map = elementListeners.get(element);
|
|
1018
|
-
if (map) {
|
|
1019
|
-
for (const [eventName, entry] of map) {
|
|
1020
|
-
if (entry.options !== void 0)
|
|
1021
|
-
element.removeEventListener(eventName, entry.handler, entry.options);
|
|
1022
|
-
else element.removeEventListener(eventName, entry.handler);
|
|
1023
|
-
}
|
|
1024
|
-
elementListeners.delete(element);
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
function removeAllListeners(root) {
|
|
1028
|
-
if (!root) return;
|
|
1029
|
-
removeElementListeners(root);
|
|
1030
|
-
forEachDescendantElement(root, removeElementListeners);
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
// src/renderer/dom.ts
|
|
1034
|
-
var IS_DOM_AVAILABLE = typeof document !== "undefined";
|
|
1035
|
-
var fallbackComponentInstanceId = 0;
|
|
1036
|
-
function nextComponentInstanceId() {
|
|
1037
|
-
const key = "__COMPONENT_INSTANCE_ID";
|
|
1038
|
-
try {
|
|
1039
|
-
__ASKR_incCounter(key);
|
|
1040
|
-
const root = globalThis;
|
|
1041
|
-
const diag = root.__ASKR_DIAG;
|
|
1042
|
-
const n = diag ? diag[key] : void 0;
|
|
1043
|
-
if (typeof n === "number" && Number.isFinite(n)) return `comp-${n}`;
|
|
1044
|
-
} catch {
|
|
1045
|
-
}
|
|
1046
|
-
fallbackComponentInstanceId++;
|
|
1047
|
-
return `comp-${fallbackComponentInstanceId}`;
|
|
1048
|
-
}
|
|
1049
|
-
function addTrackedListener(el, eventName, handler) {
|
|
1050
|
-
const wrappedHandler = createWrappedHandler(handler, true);
|
|
1051
|
-
const options = getPassiveOptions(eventName);
|
|
1052
|
-
if (options !== void 0) {
|
|
1053
|
-
el.addEventListener(eventName, wrappedHandler, options);
|
|
1054
|
-
} else {
|
|
1055
|
-
el.addEventListener(eventName, wrappedHandler);
|
|
1056
|
-
}
|
|
1057
|
-
if (!elementListeners.has(el)) {
|
|
1058
|
-
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
1059
|
-
}
|
|
1060
|
-
elementListeners.get(el).set(eventName, {
|
|
1061
|
-
handler: wrappedHandler,
|
|
1062
|
-
original: handler,
|
|
1063
|
-
options
|
|
1064
|
-
});
|
|
1065
|
-
}
|
|
1066
|
-
function applyPropsToElement(el, props, tagName) {
|
|
1067
|
-
for (const key in props) {
|
|
1068
|
-
const value = props[key];
|
|
1069
|
-
if (isSkippedProp(key)) continue;
|
|
1070
|
-
if (value === void 0 || value === null || value === false) continue;
|
|
1071
|
-
if (key === "ref") {
|
|
1072
|
-
applyRef(el, value);
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
|
-
const eventName = parseEventName(key);
|
|
1076
|
-
if (eventName) {
|
|
1077
|
-
addTrackedListener(el, eventName, value);
|
|
1078
|
-
continue;
|
|
1079
|
-
}
|
|
1080
|
-
if (key === "class" || key === "className") {
|
|
1081
|
-
el.className = String(value);
|
|
1082
|
-
} else if (key === "value" || key === "checked") {
|
|
1083
|
-
applyFormControlProp(el, key, value, tagName);
|
|
1084
|
-
} else {
|
|
1085
|
-
el.setAttribute(key, String(value));
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
function applyRef(el, ref) {
|
|
1090
|
-
const r = ref;
|
|
1091
|
-
if (!r) return;
|
|
1092
|
-
if (typeof r === "function") {
|
|
1093
|
-
r(el);
|
|
1094
|
-
return;
|
|
1095
|
-
}
|
|
1096
|
-
try {
|
|
1097
|
-
r.current = el;
|
|
1098
|
-
} catch {
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
function applyFormControlProp(el, key, value, tagName) {
|
|
1102
|
-
if (key === "value") {
|
|
1103
|
-
if (tagNamesEqualIgnoreCase(tagName, "input") || tagNamesEqualIgnoreCase(tagName, "textarea") || tagNamesEqualIgnoreCase(tagName, "select")) {
|
|
1104
|
-
el.value = String(value);
|
|
1105
|
-
el.setAttribute("value", String(value));
|
|
1106
|
-
} else {
|
|
1107
|
-
el.setAttribute("value", String(value));
|
|
1108
|
-
}
|
|
1109
|
-
} else if (key === "checked") {
|
|
1110
|
-
if (tagNamesEqualIgnoreCase(tagName, "input")) {
|
|
1111
|
-
el.checked = Boolean(value);
|
|
1112
|
-
el.setAttribute("checked", String(Boolean(value)));
|
|
1113
|
-
} else {
|
|
1114
|
-
el.setAttribute("checked", String(Boolean(value)));
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
function materializeKey(el, vnode, props) {
|
|
1119
|
-
const vnodeKey = vnode.key ?? props?.key;
|
|
1120
|
-
if (vnodeKey !== void 0) {
|
|
1121
|
-
el.setAttribute("data-key", String(vnodeKey));
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
function warnMissingKeys(children) {
|
|
1125
|
-
if (process.env.NODE_ENV === "production") return;
|
|
1126
|
-
let hasElements = false;
|
|
1127
|
-
let hasKeys = false;
|
|
1128
|
-
for (const item of children) {
|
|
1129
|
-
if (typeof item === "object" && item !== null && "type" in item) {
|
|
1130
|
-
hasElements = true;
|
|
1131
|
-
const rawKey = item.key ?? item.props?.key;
|
|
1132
|
-
if (rawKey !== void 0) {
|
|
1133
|
-
hasKeys = true;
|
|
1134
|
-
break;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
if (hasElements && !hasKeys) {
|
|
1139
|
-
try {
|
|
1140
|
-
const inst = getCurrentInstance();
|
|
1141
|
-
const name = inst?.fn?.name || "<anonymous>";
|
|
1142
|
-
logger.warn(
|
|
1143
|
-
`Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`
|
|
1144
|
-
);
|
|
1145
|
-
} catch {
|
|
1146
|
-
logger.warn(
|
|
1147
|
-
'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
|
|
1148
|
-
);
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
function createDOMNode(node) {
|
|
1153
|
-
if (!IS_DOM_AVAILABLE) {
|
|
1154
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1155
|
-
try {
|
|
1156
|
-
logger.warn("[Askr] createDOMNode called in non-DOM environment");
|
|
1157
|
-
} catch {
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
return null;
|
|
1161
|
-
}
|
|
1162
|
-
if (typeof node === "string") {
|
|
1163
|
-
return document.createTextNode(node);
|
|
1164
|
-
}
|
|
1165
|
-
if (typeof node === "number") {
|
|
1166
|
-
return document.createTextNode(String(node));
|
|
1167
|
-
}
|
|
1168
|
-
if (!node) {
|
|
1169
|
-
return null;
|
|
1170
|
-
}
|
|
1171
|
-
if (Array.isArray(node)) {
|
|
1172
|
-
const fragment = document.createDocumentFragment();
|
|
1173
|
-
for (const child of node) {
|
|
1174
|
-
const dom = createDOMNode(child);
|
|
1175
|
-
if (dom) fragment.appendChild(dom);
|
|
1176
|
-
}
|
|
1177
|
-
return fragment;
|
|
1178
|
-
}
|
|
1179
|
-
if (typeof node === "object" && node !== null && "type" in node) {
|
|
1180
|
-
const type = node.type;
|
|
1181
|
-
const props = node.props || {};
|
|
1182
|
-
if (typeof type === "string") {
|
|
1183
|
-
return createIntrinsicElement(node, type, props);
|
|
1184
|
-
}
|
|
1185
|
-
if (typeof type === "function") {
|
|
1186
|
-
return createComponentElement(node, type, props);
|
|
1187
|
-
}
|
|
1188
|
-
if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
|
|
1189
|
-
return createFragmentElement(node, props);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
return null;
|
|
1193
|
-
}
|
|
1194
|
-
function createIntrinsicElement(node, type, props) {
|
|
1195
|
-
const el = document.createElement(type);
|
|
1196
|
-
materializeKey(el, node, props);
|
|
1197
|
-
applyPropsToElement(el, props, type);
|
|
1198
|
-
const children = props.children || node.children;
|
|
1199
|
-
if (children) {
|
|
1200
|
-
if (Array.isArray(children)) {
|
|
1201
|
-
warnMissingKeys(children);
|
|
1202
|
-
for (const child of children) {
|
|
1203
|
-
const dom = createDOMNode(child);
|
|
1204
|
-
if (dom) el.appendChild(dom);
|
|
1205
|
-
}
|
|
1206
|
-
} else {
|
|
1207
|
-
const dom = createDOMNode(children);
|
|
1208
|
-
if (dom) el.appendChild(dom);
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
return el;
|
|
1212
|
-
}
|
|
1213
|
-
function createComponentElement(node, type, props) {
|
|
1214
|
-
const frame = node[CONTEXT_FRAME_SYMBOL];
|
|
1215
|
-
const snapshot = frame || getCurrentContextFrame();
|
|
1216
|
-
const componentFn = type;
|
|
1217
|
-
const isAsync = componentFn.constructor.name === "AsyncFunction";
|
|
1218
|
-
if (isAsync) {
|
|
1219
|
-
throw new Error(
|
|
1220
|
-
"Async components are not supported. Use resource() for async work."
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
let childInstance = node.__instance;
|
|
1224
|
-
if (!childInstance) {
|
|
1225
|
-
childInstance = createComponentInstance(
|
|
1226
|
-
nextComponentInstanceId(),
|
|
1227
|
-
componentFn,
|
|
1228
|
-
props || {},
|
|
1229
|
-
null
|
|
1230
|
-
);
|
|
1231
|
-
node.__instance = childInstance;
|
|
1232
|
-
}
|
|
1233
|
-
if (snapshot) {
|
|
1234
|
-
childInstance.ownerFrame = snapshot;
|
|
1235
|
-
}
|
|
1236
|
-
const result = withContext(
|
|
1237
|
-
snapshot,
|
|
1238
|
-
() => renderComponentInline(childInstance)
|
|
1239
|
-
);
|
|
1240
|
-
if (result instanceof Promise) {
|
|
1241
|
-
throw new Error(
|
|
1242
|
-
"Async components are not supported. Components must return synchronously."
|
|
1243
|
-
);
|
|
1244
|
-
}
|
|
1245
|
-
const dom = withContext(snapshot, () => createDOMNode(result));
|
|
1246
|
-
if (dom instanceof Element) {
|
|
1247
|
-
mountInstanceInline(childInstance, dom);
|
|
1248
|
-
return dom;
|
|
1249
|
-
}
|
|
1250
|
-
if (!dom) {
|
|
1251
|
-
const placeholder = document.createComment("");
|
|
1252
|
-
childInstance._placeholder = placeholder;
|
|
1253
|
-
childInstance.mounted = true;
|
|
1254
|
-
childInstance.notifyUpdate = childInstance._enqueueRun;
|
|
1255
|
-
return placeholder;
|
|
1256
|
-
}
|
|
1257
|
-
const host = document.createElement("div");
|
|
1258
|
-
host.appendChild(dom);
|
|
1259
|
-
mountInstanceInline(childInstance, host);
|
|
1260
|
-
return host;
|
|
1261
|
-
}
|
|
1262
|
-
function createFragmentElement(node, props) {
|
|
1263
|
-
const fragment = document.createDocumentFragment();
|
|
1264
|
-
const children = props.children || node.children;
|
|
1265
|
-
if (children) {
|
|
1266
|
-
if (Array.isArray(children)) {
|
|
1267
|
-
for (const child of children) {
|
|
1268
|
-
const dom = createDOMNode(child);
|
|
1269
|
-
if (dom) fragment.appendChild(dom);
|
|
1270
|
-
}
|
|
1271
|
-
} else {
|
|
1272
|
-
const dom = createDOMNode(children);
|
|
1273
|
-
if (dom) fragment.appendChild(dom);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
return fragment;
|
|
1277
|
-
}
|
|
1278
|
-
function updateElementFromVnode(el, vnode, updateChildren = true) {
|
|
1279
|
-
if (!_isDOMElement(vnode)) {
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
|
-
const props = vnode.props || {};
|
|
1283
|
-
materializeKey(el, vnode, props);
|
|
1284
|
-
const existingListeners = elementListeners.get(el);
|
|
1285
|
-
let desiredEventNames = null;
|
|
1286
|
-
for (const key in props) {
|
|
1287
|
-
const value = props[key];
|
|
1288
|
-
if (isSkippedProp(key)) continue;
|
|
1289
|
-
const eventName = parseEventName(key);
|
|
1290
|
-
if (value === void 0 || value === null || value === false) {
|
|
1291
|
-
if (key === "class" || key === "className") {
|
|
1292
|
-
el.className = "";
|
|
1293
|
-
} else if (eventName && existingListeners?.has(eventName)) {
|
|
1294
|
-
const entry = existingListeners.get(eventName);
|
|
1295
|
-
if (entry.options !== void 0) {
|
|
1296
|
-
el.removeEventListener(eventName, entry.handler, entry.options);
|
|
1297
|
-
} else {
|
|
1298
|
-
el.removeEventListener(eventName, entry.handler);
|
|
1299
|
-
}
|
|
1300
|
-
existingListeners.delete(eventName);
|
|
1301
|
-
} else {
|
|
1302
|
-
el.removeAttribute(key);
|
|
1303
|
-
}
|
|
1304
|
-
continue;
|
|
1305
|
-
}
|
|
1306
|
-
if (key === "class" || key === "className") {
|
|
1307
|
-
el.className = String(value);
|
|
1308
|
-
} else if (key === "value" || key === "checked") {
|
|
1309
|
-
el[key] = value;
|
|
1310
|
-
} else if (eventName) {
|
|
1311
|
-
if (existingListeners && existingListeners.size > 0) {
|
|
1312
|
-
(desiredEventNames ??= /* @__PURE__ */ new Set()).add(eventName);
|
|
1313
|
-
}
|
|
1314
|
-
const existing = existingListeners?.get(eventName);
|
|
1315
|
-
if (existing && existing.original === value) {
|
|
1316
|
-
continue;
|
|
1317
|
-
}
|
|
1318
|
-
if (existing) {
|
|
1319
|
-
if (existing.options !== void 0) {
|
|
1320
|
-
el.removeEventListener(eventName, existing.handler, existing.options);
|
|
1321
|
-
} else {
|
|
1322
|
-
el.removeEventListener(eventName, existing.handler);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
const wrappedHandler = createWrappedHandler(
|
|
1326
|
-
value,
|
|
1327
|
-
false
|
|
1328
|
-
);
|
|
1329
|
-
const options = getPassiveOptions(eventName);
|
|
1330
|
-
if (options !== void 0) {
|
|
1331
|
-
el.addEventListener(eventName, wrappedHandler, options);
|
|
1332
|
-
} else {
|
|
1333
|
-
el.addEventListener(eventName, wrappedHandler);
|
|
1334
|
-
}
|
|
1335
|
-
if (!elementListeners.has(el)) {
|
|
1336
|
-
elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
1337
|
-
}
|
|
1338
|
-
elementListeners.get(el).set(eventName, {
|
|
1339
|
-
handler: wrappedHandler,
|
|
1340
|
-
original: value,
|
|
1341
|
-
options
|
|
1342
|
-
});
|
|
1343
|
-
} else {
|
|
1344
|
-
el.setAttribute(key, String(value));
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
if (existingListeners && existingListeners.size > 0) {
|
|
1348
|
-
if (desiredEventNames === null) {
|
|
1349
|
-
for (const [eventName, entry] of existingListeners) {
|
|
1350
|
-
if (entry.options !== void 0) {
|
|
1351
|
-
el.removeEventListener(eventName, entry.handler, entry.options);
|
|
1352
|
-
} else {
|
|
1353
|
-
el.removeEventListener(eventName, entry.handler);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
elementListeners.delete(el);
|
|
1357
|
-
} else {
|
|
1358
|
-
for (const [eventName, entry] of existingListeners) {
|
|
1359
|
-
if (!desiredEventNames.has(eventName)) {
|
|
1360
|
-
if (entry.options !== void 0) {
|
|
1361
|
-
el.removeEventListener(eventName, entry.handler, entry.options);
|
|
1362
|
-
} else {
|
|
1363
|
-
el.removeEventListener(eventName, entry.handler);
|
|
1364
|
-
}
|
|
1365
|
-
existingListeners.delete(eventName);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
if (existingListeners.size === 0) elementListeners.delete(el);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
if (updateChildren) {
|
|
1372
|
-
const children = vnode.children || props.children;
|
|
1373
|
-
updateElementChildren(el, children);
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
function updateElementChildren(el, children) {
|
|
1377
|
-
if (!children) {
|
|
1378
|
-
el.textContent = "";
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
|
|
1382
|
-
if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
|
|
1383
|
-
el.firstChild.data = String(children);
|
|
1384
|
-
} else {
|
|
1385
|
-
el.textContent = String(children);
|
|
1386
|
-
}
|
|
1387
|
-
return;
|
|
1388
|
-
}
|
|
1389
|
-
if (Array.isArray(children)) {
|
|
1390
|
-
updateUnkeyedChildren(el, children);
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
el.textContent = "";
|
|
1394
|
-
const dom = createDOMNode(children);
|
|
1395
|
-
if (dom) el.appendChild(dom);
|
|
1396
|
-
}
|
|
1397
|
-
function updateUnkeyedChildren(parent, newChildren) {
|
|
1398
|
-
const existing = Array.from(parent.children);
|
|
1399
|
-
if (newChildren.length === 1 && existing.length === 0 && parent.childNodes.length === 1) {
|
|
1400
|
-
const firstNewChild = newChildren[0];
|
|
1401
|
-
const firstExisting = parent.firstChild;
|
|
1402
|
-
if ((typeof firstNewChild === "string" || typeof firstNewChild === "number") && firstExisting?.nodeType === 3) {
|
|
1403
|
-
firstExisting.data = String(firstNewChild);
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
if (existing.length === 0 && parent.childNodes.length > 0) {
|
|
1408
|
-
parent.textContent = "";
|
|
1409
|
-
}
|
|
1410
|
-
const max = Math.max(existing.length, newChildren.length);
|
|
1411
|
-
for (let i = 0; i < max; i++) {
|
|
1412
|
-
const current2 = existing[i];
|
|
1413
|
-
const next = newChildren[i];
|
|
1414
|
-
if (next === void 0 && current2) {
|
|
1415
|
-
cleanupInstanceIfPresent(current2);
|
|
1416
|
-
current2.remove();
|
|
1417
|
-
continue;
|
|
1418
|
-
}
|
|
1419
|
-
if (!current2 && next !== void 0) {
|
|
1420
|
-
const dom = createDOMNode(next);
|
|
1421
|
-
if (dom) parent.appendChild(dom);
|
|
1422
|
-
continue;
|
|
1423
|
-
}
|
|
1424
|
-
if (!current2 || next === void 0) continue;
|
|
1425
|
-
if (typeof next === "string" || typeof next === "number") {
|
|
1426
|
-
current2.textContent = String(next);
|
|
1427
|
-
} else if (_isDOMElement(next)) {
|
|
1428
|
-
if (typeof next.type === "string") {
|
|
1429
|
-
if (tagsEqualIgnoreCase(current2.tagName, next.type)) {
|
|
1430
|
-
updateElementFromVnode(current2, next);
|
|
1431
|
-
} else {
|
|
1432
|
-
const dom = createDOMNode(next);
|
|
1433
|
-
if (dom) {
|
|
1434
|
-
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1435
|
-
cleanupInstanceIfPresent(current2);
|
|
1436
|
-
parent.replaceChild(dom, current2);
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
} else {
|
|
1440
|
-
const dom = createDOMNode(next);
|
|
1441
|
-
if (dom) {
|
|
1442
|
-
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1443
|
-
cleanupInstanceIfPresent(current2);
|
|
1444
|
-
parent.replaceChild(dom, current2);
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
} else {
|
|
1448
|
-
const dom = createDOMNode(next);
|
|
1449
|
-
if (dom) {
|
|
1450
|
-
if (current2 instanceof Element) removeAllListeners(current2);
|
|
1451
|
-
cleanupInstanceIfPresent(current2);
|
|
1452
|
-
parent.replaceChild(dom, current2);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
|
|
1458
|
-
const total = keyedVnodes.length;
|
|
1459
|
-
let reused = 0;
|
|
1460
|
-
let updatedKeys = 0;
|
|
1461
|
-
const t0 = now();
|
|
1462
|
-
const debugFastPath = process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true";
|
|
1463
|
-
for (let i = 0; i < total; i++) {
|
|
1464
|
-
const { key, vnode } = keyedVnodes[i];
|
|
1465
|
-
const ch = parent.children[i];
|
|
1466
|
-
if (ch && _isDOMElement(vnode) && typeof vnode.type === "string") {
|
|
1467
|
-
const vnodeType = vnode.type;
|
|
1468
|
-
if (tagsEqualIgnoreCase(ch.tagName, vnodeType)) {
|
|
1469
|
-
const children = vnode.children || vnode.props?.children;
|
|
1470
|
-
if (debugFastPath) {
|
|
1471
|
-
logFastPathDebug("positional idx", i, {
|
|
1472
|
-
chTag: ch.tagName,
|
|
1473
|
-
vnodeType,
|
|
1474
|
-
chChildNodes: ch.childNodes.length,
|
|
1475
|
-
childrenType: Array.isArray(children) ? "array" : typeof children
|
|
1476
|
-
});
|
|
1477
|
-
}
|
|
1478
|
-
updateTextContent(ch, children, vnode);
|
|
1479
|
-
setDataKey(ch, key, () => updatedKeys++);
|
|
1480
|
-
reused++;
|
|
1481
|
-
continue;
|
|
1482
|
-
} else {
|
|
1483
|
-
if (debugFastPath) {
|
|
1484
|
-
logFastPathDebug("positional tag mismatch", i, {
|
|
1485
|
-
chTag: ch.tagName,
|
|
1486
|
-
vnodeType
|
|
1487
|
-
});
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
} else {
|
|
1491
|
-
if (debugFastPath) {
|
|
1492
|
-
logFastPathDebug("positional missing or invalid", i, { ch: !!ch });
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
replaceNodeAtPosition(parent, i, vnode);
|
|
1496
|
-
}
|
|
1497
|
-
const t = now() - t0;
|
|
1498
|
-
updateKeyedElementsMap(parent, keyedVnodes);
|
|
1499
|
-
const stats = { n: total, reused, updatedKeys, t };
|
|
1500
|
-
recordFastPathStats(stats, "bulkKeyedPositionalHits");
|
|
1501
|
-
return stats;
|
|
1502
|
-
}
|
|
1503
|
-
function updateTextContent(el, children, vnode) {
|
|
1504
|
-
if (typeof children === "string" || typeof children === "number") {
|
|
1505
|
-
setTextNodeData(el, String(children));
|
|
1506
|
-
} else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
|
|
1507
|
-
setTextNodeData(el, String(children[0]));
|
|
1508
|
-
} else {
|
|
1509
|
-
if (!tryUpdateTwoChildTextPattern(el, vnode)) {
|
|
1510
|
-
updateElementFromVnode(el, vnode);
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
function tryUpdateTwoChildTextPattern(parentEl, vnode) {
|
|
1515
|
-
const vnodeChildren = vnode.children || vnode.props?.children;
|
|
1516
|
-
if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;
|
|
1517
|
-
const c0 = vnodeChildren[0];
|
|
1518
|
-
const c1 = vnodeChildren[1];
|
|
1519
|
-
if (!_isDOMElement(c0) || !_isDOMElement(c1)) return false;
|
|
1520
|
-
if (typeof c0.type !== "string" || typeof c1.type !== "string") return false;
|
|
1521
|
-
const el0 = parentEl.children[0];
|
|
1522
|
-
const el1 = parentEl.children[1];
|
|
1523
|
-
if (!el0 || !el1) return false;
|
|
1524
|
-
if (!tagsEqualIgnoreCase(el0.tagName, c0.type)) return false;
|
|
1525
|
-
if (!tagsEqualIgnoreCase(el1.tagName, c1.type)) return false;
|
|
1526
|
-
const t0 = c0.children || c0.props?.children;
|
|
1527
|
-
const t1 = c1.children || c1.props?.children;
|
|
1528
|
-
if (typeof t0 === "string" || typeof t0 === "number") {
|
|
1529
|
-
setTextNodeData(el0, String(t0));
|
|
1530
|
-
} else if (Array.isArray(t0) && t0.length === 1 && (typeof t0[0] === "string" || typeof t0[0] === "number")) {
|
|
1531
|
-
setTextNodeData(el0, String(t0[0]));
|
|
1532
|
-
} else {
|
|
1533
|
-
return false;
|
|
1534
|
-
}
|
|
1535
|
-
if (typeof t1 === "string" || typeof t1 === "number") {
|
|
1536
|
-
setTextNodeData(el1, String(t1));
|
|
1537
|
-
} else if (Array.isArray(t1) && t1.length === 1 && (typeof t1[0] === "string" || typeof t1[0] === "number")) {
|
|
1538
|
-
setTextNodeData(el1, String(t1[0]));
|
|
1539
|
-
} else {
|
|
1540
|
-
return false;
|
|
1541
|
-
}
|
|
1542
|
-
return true;
|
|
1543
|
-
}
|
|
1544
|
-
function setTextNodeData(el, text) {
|
|
1545
|
-
if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
|
|
1546
|
-
el.firstChild.data = text;
|
|
1547
|
-
} else {
|
|
1548
|
-
el.textContent = text;
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
function setDataKey(el, key, onSet) {
|
|
1552
|
-
try {
|
|
1553
|
-
const next = String(key);
|
|
1554
|
-
if (el.getAttribute("data-key") === next) return;
|
|
1555
|
-
el.setAttribute("data-key", next);
|
|
1556
|
-
onSet();
|
|
1557
|
-
} catch {
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
function upperCommonTagName(tag) {
|
|
1561
|
-
switch (tag) {
|
|
1562
|
-
case "div":
|
|
1563
|
-
return "DIV";
|
|
1564
|
-
case "span":
|
|
1565
|
-
return "SPAN";
|
|
1566
|
-
case "p":
|
|
1567
|
-
return "P";
|
|
1568
|
-
case "a":
|
|
1569
|
-
return "A";
|
|
1570
|
-
case "button":
|
|
1571
|
-
return "BUTTON";
|
|
1572
|
-
case "input":
|
|
1573
|
-
return "INPUT";
|
|
1574
|
-
case "ul":
|
|
1575
|
-
return "UL";
|
|
1576
|
-
case "ol":
|
|
1577
|
-
return "OL";
|
|
1578
|
-
case "li":
|
|
1579
|
-
return "LI";
|
|
1580
|
-
default:
|
|
1581
|
-
return null;
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
function tagNamesEqualIgnoreCase(a, b) {
|
|
1585
|
-
if (a === b) return true;
|
|
1586
|
-
const len = a.length;
|
|
1587
|
-
if (len !== b.length) return false;
|
|
1588
|
-
for (let i = 0; i < len; i++) {
|
|
1589
|
-
const ac = a.charCodeAt(i);
|
|
1590
|
-
const bc = b.charCodeAt(i);
|
|
1591
|
-
if (ac === bc) continue;
|
|
1592
|
-
const an = ac >= 65 && ac <= 90 ? ac + 32 : ac;
|
|
1593
|
-
const bn = bc >= 65 && bc <= 90 ? bc + 32 : bc;
|
|
1594
|
-
if (an !== bn) return false;
|
|
1595
|
-
}
|
|
1596
|
-
return true;
|
|
1597
|
-
}
|
|
1598
|
-
function tagsEqualIgnoreCase(elementTagName, vnodeType) {
|
|
1599
|
-
const upperCommon = upperCommonTagName(vnodeType);
|
|
1600
|
-
if (upperCommon !== null && elementTagName === upperCommon) return true;
|
|
1601
|
-
return tagNamesEqualIgnoreCase(elementTagName, vnodeType);
|
|
1602
|
-
}
|
|
1603
|
-
function replaceNodeAtPosition(parent, index, vnode) {
|
|
1604
|
-
const dom = createDOMNode(vnode);
|
|
1605
|
-
if (dom) {
|
|
1606
|
-
const existing = parent.children[index];
|
|
1607
|
-
if (existing) {
|
|
1608
|
-
cleanupInstanceIfPresent(existing);
|
|
1609
|
-
parent.replaceChild(dom, existing);
|
|
1610
|
-
} else {
|
|
1611
|
-
parent.appendChild(dom);
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
function updateKeyedElementsMap(parent, keyedVnodes) {
|
|
1616
|
-
try {
|
|
1617
|
-
const existing = keyedElements.get(parent);
|
|
1618
|
-
const newKeyMap = existing ? (existing.clear(), existing) : /* @__PURE__ */ new Map();
|
|
1619
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1620
|
-
const k = keyedVnodes[i].key;
|
|
1621
|
-
const ch = parent.children[i];
|
|
1622
|
-
if (ch) newKeyMap.set(k, ch);
|
|
1623
|
-
}
|
|
1624
|
-
keyedElements.set(parent, newKeyMap);
|
|
1625
|
-
} catch {
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
function performBulkTextReplace(parent, newChildren) {
|
|
1629
|
-
const t0 = now();
|
|
1630
|
-
const existing = Array.from(parent.childNodes);
|
|
1631
|
-
const finalNodes = [];
|
|
1632
|
-
let reused = 0;
|
|
1633
|
-
let created = 0;
|
|
1634
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
1635
|
-
const result = processChildNode(newChildren[i], existing[i], finalNodes);
|
|
1636
|
-
if (result === "reused") reused++;
|
|
1637
|
-
else if (result === "created") created++;
|
|
1638
|
-
}
|
|
1639
|
-
const tBuild = now() - t0;
|
|
1640
|
-
const tCommit = commitBulkReplace(parent, finalNodes);
|
|
1641
|
-
keyedElements.delete(parent);
|
|
1642
|
-
const stats = {
|
|
1643
|
-
n: newChildren.length,
|
|
1644
|
-
reused,
|
|
1645
|
-
created,
|
|
1646
|
-
tBuild,
|
|
1647
|
-
tCommit
|
|
1648
|
-
};
|
|
1649
|
-
recordBulkTextStats(stats);
|
|
1650
|
-
return stats;
|
|
1651
|
-
}
|
|
1652
|
-
function processChildNode(vnode, existingNode, finalNodes) {
|
|
1653
|
-
if (typeof vnode === "string" || typeof vnode === "number") {
|
|
1654
|
-
return processTextVnode(String(vnode), existingNode, finalNodes);
|
|
1655
|
-
}
|
|
1656
|
-
if (typeof vnode === "object" && vnode !== null && "type" in vnode) {
|
|
1657
|
-
return processElementVnode(vnode, existingNode, finalNodes);
|
|
1658
|
-
}
|
|
1659
|
-
return "skipped";
|
|
1660
|
-
}
|
|
1661
|
-
function processTextVnode(text, existingNode, finalNodes) {
|
|
1662
|
-
if (existingNode && existingNode.nodeType === 3) {
|
|
1663
|
-
existingNode.data = text;
|
|
1664
|
-
finalNodes.push(existingNode);
|
|
1665
|
-
return "reused";
|
|
1666
|
-
}
|
|
1667
|
-
finalNodes.push(document.createTextNode(text));
|
|
1668
|
-
return "created";
|
|
1669
|
-
}
|
|
1670
|
-
function processElementVnode(vnode, existingNode, finalNodes) {
|
|
1671
|
-
const vnodeObj = vnode;
|
|
1672
|
-
if (typeof vnodeObj.type === "string") {
|
|
1673
|
-
const tag = vnodeObj.type;
|
|
1674
|
-
if (existingNode && existingNode.nodeType === 1 && tagsEqualIgnoreCase(existingNode.tagName, tag)) {
|
|
1675
|
-
updateElementFromVnode(existingNode, vnode);
|
|
1676
|
-
finalNodes.push(existingNode);
|
|
1677
|
-
return "reused";
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
const dom = createDOMNode(vnode);
|
|
1681
|
-
if (dom) {
|
|
1682
|
-
finalNodes.push(dom);
|
|
1683
|
-
return "created";
|
|
1684
|
-
}
|
|
1685
|
-
return "skipped";
|
|
1686
|
-
}
|
|
1687
|
-
function commitBulkReplace(parent, nodes) {
|
|
1688
|
-
const fragStart = Date.now();
|
|
1689
|
-
const fragment = document.createDocumentFragment();
|
|
1690
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
1691
|
-
fragment.appendChild(nodes[i]);
|
|
1692
|
-
}
|
|
1693
|
-
try {
|
|
1694
|
-
for (let n = parent.firstChild; n; ) {
|
|
1695
|
-
const next = n.nextSibling;
|
|
1696
|
-
if (n instanceof Element) removeAllListeners(n);
|
|
1697
|
-
cleanupInstanceIfPresent(n);
|
|
1698
|
-
n = next;
|
|
1699
|
-
}
|
|
1700
|
-
} catch {
|
|
1701
|
-
}
|
|
1702
|
-
recordDOMReplace("bulk-text-replace");
|
|
1703
|
-
parent.replaceChildren(fragment);
|
|
1704
|
-
return Date.now() - fragStart;
|
|
1705
|
-
}
|
|
1706
|
-
function recordBulkTextStats(stats) {
|
|
1707
|
-
try {
|
|
1708
|
-
__ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
|
|
1709
|
-
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1710
|
-
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1711
|
-
__ASKR_incCounter("bulkTextFastpathHits");
|
|
1712
|
-
} catch {
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
function isBulkTextFastPathEligible(parent, newChildren) {
|
|
1716
|
-
const threshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
|
|
1717
|
-
const requiredFraction = 0.8;
|
|
1718
|
-
const total = Array.isArray(newChildren) ? newChildren.length : 0;
|
|
1719
|
-
if (total < threshold) {
|
|
1720
|
-
recordBulkDiag({
|
|
1721
|
-
phase: "bulk-unkeyed-eligible",
|
|
1722
|
-
reason: "too-small",
|
|
1723
|
-
total,
|
|
1724
|
-
threshold
|
|
1725
|
-
});
|
|
1726
|
-
return false;
|
|
1727
|
-
}
|
|
1728
|
-
const result = countSimpleChildren(newChildren);
|
|
1729
|
-
if (result.componentFound !== void 0) {
|
|
1730
|
-
recordBulkDiag({
|
|
1731
|
-
phase: "bulk-unkeyed-eligible",
|
|
1732
|
-
reason: "component-child",
|
|
1733
|
-
index: result.componentFound
|
|
1734
|
-
});
|
|
1735
|
-
return false;
|
|
1736
|
-
}
|
|
1737
|
-
const fraction = result.simple / total;
|
|
1738
|
-
const eligible = fraction >= requiredFraction && parent.childNodes.length >= total;
|
|
1739
|
-
recordBulkDiag({
|
|
1740
|
-
phase: "bulk-unkeyed-eligible",
|
|
1741
|
-
total,
|
|
1742
|
-
simple: result.simple,
|
|
1743
|
-
fraction,
|
|
1744
|
-
requiredFraction,
|
|
1745
|
-
eligible
|
|
1746
|
-
});
|
|
1747
|
-
return eligible;
|
|
1748
|
-
}
|
|
1749
|
-
function countSimpleChildren(children) {
|
|
1750
|
-
let simple = 0;
|
|
1751
|
-
for (let i = 0; i < children.length; i++) {
|
|
1752
|
-
const c = children[i];
|
|
1753
|
-
if (typeof c === "string" || typeof c === "number") {
|
|
1754
|
-
simple++;
|
|
1755
|
-
continue;
|
|
1756
|
-
}
|
|
1757
|
-
if (typeof c === "object" && c !== null && "type" in c) {
|
|
1758
|
-
const dv = c;
|
|
1759
|
-
if (typeof dv.type === "function") {
|
|
1760
|
-
return { simple, componentFound: i };
|
|
1761
|
-
}
|
|
1762
|
-
if (typeof dv.type === "string" && isSimpleElement(dv)) {
|
|
1763
|
-
simple++;
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
return { simple };
|
|
1768
|
-
}
|
|
1769
|
-
function isSimpleElement(dv) {
|
|
1770
|
-
const children = dv.children || dv.props?.children;
|
|
1771
|
-
if (!children) return true;
|
|
1772
|
-
if (typeof children === "string" || typeof children === "number") {
|
|
1773
|
-
return true;
|
|
1774
|
-
}
|
|
1775
|
-
if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
|
|
1776
|
-
return true;
|
|
1777
|
-
}
|
|
1778
|
-
return false;
|
|
1779
|
-
}
|
|
1780
|
-
function recordBulkDiag(data) {
|
|
1781
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
1782
|
-
try {
|
|
1783
|
-
__ASKR_set("__BULK_DIAG", data);
|
|
1784
|
-
} catch {
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
// src/renderer/fastpath.ts
|
|
1790
|
-
function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
|
|
1791
|
-
if (typeof document === "undefined") return null;
|
|
1792
|
-
const totalKeyed = keyedVnodes.length;
|
|
1793
|
-
if (totalKeyed === 0 && (!unkeyedVnodes || unkeyedVnodes.length === 0))
|
|
1794
|
-
return null;
|
|
1795
|
-
if (!isSchedulerExecuting()) {
|
|
1796
|
-
logger.warn(
|
|
1797
|
-
"[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
|
|
1798
|
-
);
|
|
1799
|
-
}
|
|
1800
|
-
let parentChildrenArr;
|
|
1801
|
-
let localOldKeyMap;
|
|
1802
|
-
if (totalKeyed <= 20) {
|
|
1803
|
-
try {
|
|
1804
|
-
const pc = parent.children;
|
|
1805
|
-
parentChildrenArr = new Array(pc.length);
|
|
1806
|
-
for (let i = 0; i < pc.length; i++)
|
|
1807
|
-
parentChildrenArr[i] = pc[i];
|
|
1808
|
-
} catch (e) {
|
|
1809
|
-
parentChildrenArr = void 0;
|
|
1810
|
-
}
|
|
1811
|
-
} else {
|
|
1812
|
-
localOldKeyMap = /* @__PURE__ */ new Map();
|
|
1813
|
-
try {
|
|
1814
|
-
for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
|
|
1815
|
-
const k = ch.getAttribute("data-key");
|
|
1816
|
-
if (k !== null) {
|
|
1817
|
-
localOldKeyMap.set(k, ch);
|
|
1818
|
-
const n = Number(k);
|
|
1819
|
-
if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1822
|
-
} catch (e) {
|
|
1823
|
-
localOldKeyMap = void 0;
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
const finalNodes = [];
|
|
1827
|
-
let mapLookups = 0;
|
|
1828
|
-
let createdNodes = 0;
|
|
1829
|
-
let reusedCount = 0;
|
|
1830
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1831
|
-
const { key, vnode } = keyedVnodes[i];
|
|
1832
|
-
mapLookups++;
|
|
1833
|
-
let el;
|
|
1834
|
-
if (totalKeyed <= 20 && parentChildrenArr) {
|
|
1835
|
-
const ks = String(key);
|
|
1836
|
-
for (let j = 0; j < parentChildrenArr.length; j++) {
|
|
1837
|
-
const ch = parentChildrenArr[j];
|
|
1838
|
-
const k = ch.getAttribute("data-key");
|
|
1839
|
-
if (k !== null && (k === ks || Number(k) === key)) {
|
|
1840
|
-
el = ch;
|
|
1841
|
-
break;
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
if (!el) el = oldKeyMap?.get(key);
|
|
1845
|
-
} else {
|
|
1846
|
-
el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
|
|
1847
|
-
}
|
|
1848
|
-
if (el) {
|
|
1849
|
-
finalNodes.push(el);
|
|
1850
|
-
reusedCount++;
|
|
1851
|
-
} else {
|
|
1852
|
-
const newEl = createDOMNode(vnode);
|
|
1853
|
-
if (newEl) {
|
|
1854
|
-
finalNodes.push(newEl);
|
|
1855
|
-
createdNodes++;
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
if (unkeyedVnodes && unkeyedVnodes.length) {
|
|
1860
|
-
for (const vnode of unkeyedVnodes) {
|
|
1861
|
-
const newEl = createDOMNode(vnode);
|
|
1862
|
-
if (newEl) {
|
|
1863
|
-
finalNodes.push(newEl);
|
|
1864
|
-
createdNodes++;
|
|
1865
|
-
}
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
try {
|
|
1869
|
-
const tFragmentStart = Date.now();
|
|
1870
|
-
const fragment = document.createDocumentFragment();
|
|
1871
|
-
let fragmentAppendCount = 0;
|
|
1872
|
-
for (let i = 0; i < finalNodes.length; i++) {
|
|
1873
|
-
fragment.appendChild(finalNodes[i]);
|
|
1874
|
-
fragmentAppendCount++;
|
|
1875
|
-
}
|
|
1876
|
-
try {
|
|
1877
|
-
for (let n = parent.firstChild; n; ) {
|
|
1878
|
-
const next = n.nextSibling;
|
|
1879
|
-
if (n instanceof Element) removeAllListeners(n);
|
|
1880
|
-
cleanupInstanceIfPresent(n);
|
|
1881
|
-
n = next;
|
|
1882
|
-
}
|
|
1883
|
-
} catch (e) {
|
|
1884
|
-
void e;
|
|
1885
|
-
}
|
|
1886
|
-
try {
|
|
1887
|
-
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
1888
|
-
__ASKR_set("__LAST_DOM_REPLACE_STACK_FASTPATH", new Error().stack);
|
|
1889
|
-
} catch (e) {
|
|
1890
|
-
void e;
|
|
1891
|
-
}
|
|
1892
|
-
parent.replaceChildren(fragment);
|
|
1893
|
-
try {
|
|
1894
|
-
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
1895
|
-
} catch (e) {
|
|
1896
|
-
void e;
|
|
1897
|
-
}
|
|
1898
|
-
try {
|
|
1899
|
-
if (isBulkCommitActive2()) markFastPathApplied(parent);
|
|
1900
|
-
} catch (e) {
|
|
1901
|
-
void e;
|
|
1902
|
-
}
|
|
1903
|
-
const newKeyMap = /* @__PURE__ */ new Map();
|
|
1904
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
1905
|
-
const key = keyedVnodes[i].key;
|
|
1906
|
-
const node = finalNodes[i];
|
|
1907
|
-
if (node instanceof Element) newKeyMap.set(key, node);
|
|
1908
|
-
}
|
|
1909
|
-
try {
|
|
1910
|
-
const stats = {
|
|
1911
|
-
n: totalKeyed,
|
|
1912
|
-
moves: 0,
|
|
1913
|
-
lisLen: 0,
|
|
1914
|
-
t_lookup: 0,
|
|
1915
|
-
t_fragment: Date.now() - tFragmentStart,
|
|
1916
|
-
t_commit: 0,
|
|
1917
|
-
t_bookkeeping: 0,
|
|
1918
|
-
fragmentAppendCount,
|
|
1919
|
-
mapLookups,
|
|
1920
|
-
createdNodes,
|
|
1921
|
-
reusedCount
|
|
1922
|
-
};
|
|
1923
|
-
if (typeof globalThis !== "undefined") {
|
|
1924
|
-
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
1925
|
-
__ASKR_set("__LAST_FASTPATH_REUSED", reusedCount > 0);
|
|
1926
|
-
__ASKR_incCounter("fastpathHistoryPush");
|
|
1927
|
-
}
|
|
1928
|
-
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
1929
|
-
logger.warn(
|
|
1930
|
-
"[Askr][FASTPATH]",
|
|
1931
|
-
JSON.stringify({ n: totalKeyed, createdNodes, reusedCount })
|
|
1932
|
-
);
|
|
1933
|
-
}
|
|
1934
|
-
} catch (e) {
|
|
1935
|
-
void e;
|
|
1936
|
-
}
|
|
1937
|
-
try {
|
|
1938
|
-
_reconcilerRecordedParents.add(parent);
|
|
1939
|
-
} catch (e) {
|
|
1940
|
-
void e;
|
|
1941
|
-
}
|
|
1942
|
-
return newKeyMap;
|
|
1943
|
-
} catch (e) {
|
|
1944
|
-
return null;
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
|
-
// src/renderer/reconcile.ts
|
|
1949
|
-
function tagNamesEqualIgnoreCase2(a, b) {
|
|
1950
|
-
if (a === b) return true;
|
|
1951
|
-
if (a.length !== b.length) return false;
|
|
1952
|
-
for (let i = 0; i < a.length; i++) {
|
|
1953
|
-
const ca = a.charCodeAt(i);
|
|
1954
|
-
const cb = b.charCodeAt(i);
|
|
1955
|
-
if (ca === cb) continue;
|
|
1956
|
-
const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
|
|
1957
|
-
const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
|
|
1958
|
-
if (fa !== fb) return false;
|
|
1959
|
-
}
|
|
1960
|
-
return true;
|
|
1961
|
-
}
|
|
1962
|
-
function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
|
|
1963
|
-
const { keyedVnodes, unkeyedVnodes } = partitionChildren(newChildren);
|
|
1964
|
-
const fastPathResult = tryFastPaths(
|
|
1965
|
-
parent,
|
|
1966
|
-
newChildren,
|
|
1967
|
-
keyedVnodes,
|
|
1968
|
-
unkeyedVnodes,
|
|
1969
|
-
oldKeyMap
|
|
1970
|
-
);
|
|
1971
|
-
if (fastPathResult) return fastPathResult;
|
|
1972
|
-
return performFullReconciliation(parent, newChildren, keyedVnodes, oldKeyMap);
|
|
1973
|
-
}
|
|
1974
|
-
function partitionChildren(newChildren) {
|
|
1975
|
-
const keyedVnodes = [];
|
|
1976
|
-
const unkeyedVnodes = [];
|
|
1977
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
1978
|
-
const child = newChildren[i];
|
|
1979
|
-
const key = extractKey(child);
|
|
1980
|
-
if (key !== void 0) {
|
|
1981
|
-
keyedVnodes.push({ key, vnode: child });
|
|
1982
|
-
} else {
|
|
1983
|
-
unkeyedVnodes.push(child);
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
return { keyedVnodes, unkeyedVnodes };
|
|
1987
|
-
}
|
|
1988
|
-
function tryFastPaths(parent, newChildren, keyedVnodes, unkeyedVnodes, oldKeyMap) {
|
|
1989
|
-
try {
|
|
1990
|
-
const rendererResult = tryRendererFastPath(
|
|
1991
|
-
parent,
|
|
1992
|
-
newChildren,
|
|
1993
|
-
keyedVnodes,
|
|
1994
|
-
unkeyedVnodes,
|
|
1995
|
-
oldKeyMap
|
|
1996
|
-
);
|
|
1997
|
-
if (rendererResult) return rendererResult;
|
|
1998
|
-
const positionalResult = tryPositionalBulkUpdate(parent, keyedVnodes);
|
|
1999
|
-
if (positionalResult) return positionalResult;
|
|
2000
|
-
} catch {
|
|
2001
|
-
}
|
|
2002
|
-
return null;
|
|
2003
|
-
}
|
|
2004
|
-
function tryRendererFastPath(parent, newChildren, keyedVnodes, unkeyedVnodes, oldKeyMap) {
|
|
2005
|
-
const decision = isKeyedReorderFastPathEligible(
|
|
2006
|
-
parent,
|
|
2007
|
-
newChildren,
|
|
2008
|
-
oldKeyMap
|
|
2009
|
-
);
|
|
2010
|
-
if (decision.useFastPath && keyedVnodes.length >= 128 || isBulkCommitActive2()) {
|
|
2011
|
-
try {
|
|
2012
|
-
const map = applyRendererFastPath(
|
|
2013
|
-
parent,
|
|
2014
|
-
keyedVnodes,
|
|
2015
|
-
oldKeyMap,
|
|
2016
|
-
unkeyedVnodes
|
|
2017
|
-
);
|
|
2018
|
-
if (map) {
|
|
2019
|
-
keyedElements.set(parent, map);
|
|
2020
|
-
return map;
|
|
2021
|
-
}
|
|
2022
|
-
} catch {
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
return null;
|
|
2026
|
-
}
|
|
2027
|
-
function tryPositionalBulkUpdate(parent, keyedVnodes) {
|
|
2028
|
-
const total = keyedVnodes.length;
|
|
2029
|
-
if (total < 10) return null;
|
|
2030
|
-
const matchCount = countPositionalMatches(parent, keyedVnodes);
|
|
2031
|
-
if (matchCount / total < 0.9) return null;
|
|
2032
|
-
if (hasPositionalPropChanges(parent, keyedVnodes)) return null;
|
|
2033
|
-
try {
|
|
2034
|
-
const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
|
|
2035
|
-
recordFastPathStats(stats, "bulkKeyedPositionalHits");
|
|
2036
|
-
rebuildKeyedMap(parent);
|
|
2037
|
-
return keyedElements.get(parent);
|
|
2038
|
-
} catch {
|
|
2039
|
-
return null;
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
function countPositionalMatches(parent, keyedVnodes) {
|
|
2043
|
-
let matchCount = 0;
|
|
2044
|
-
try {
|
|
2045
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
2046
|
-
const vnode = keyedVnodes[i].vnode;
|
|
2047
|
-
if (!vnode || typeof vnode !== "object" || typeof vnode.type !== "string")
|
|
2048
|
-
continue;
|
|
2049
|
-
const el = parent.children[i];
|
|
2050
|
-
if (!el) continue;
|
|
2051
|
-
if (tagNamesEqualIgnoreCase2(el.tagName, vnode.type)) {
|
|
2052
|
-
matchCount++;
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
} catch {
|
|
2056
|
-
}
|
|
2057
|
-
return matchCount;
|
|
2058
|
-
}
|
|
2059
|
-
function hasPositionalPropChanges(parent, keyedVnodes) {
|
|
2060
|
-
try {
|
|
2061
|
-
for (let i = 0; i < keyedVnodes.length; i++) {
|
|
2062
|
-
const vnode = keyedVnodes[i].vnode;
|
|
2063
|
-
const el = parent.children[i];
|
|
2064
|
-
if (!el || !vnode || typeof vnode !== "object") continue;
|
|
2065
|
-
if (checkPropChanges(el, vnode.props || {})) {
|
|
2066
|
-
return true;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
} catch {
|
|
2070
|
-
return true;
|
|
2071
|
-
}
|
|
2072
|
-
return false;
|
|
2073
|
-
}
|
|
2074
|
-
function rebuildKeyedMap(parent) {
|
|
2075
|
-
try {
|
|
2076
|
-
const map = /* @__PURE__ */ new Map();
|
|
2077
|
-
for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {
|
|
2078
|
-
const k = el.getAttribute("data-key");
|
|
2079
|
-
if (k !== null) {
|
|
2080
|
-
map.set(k, el);
|
|
2081
|
-
const n = Number(k);
|
|
2082
|
-
if (!Number.isNaN(n)) map.set(n, el);
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
keyedElements.set(parent, map);
|
|
2086
|
-
} catch {
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2089
|
-
function performFullReconciliation(parent, newChildren, keyedVnodes, oldKeyMap) {
|
|
2090
|
-
const newKeyMap = /* @__PURE__ */ new Map();
|
|
2091
|
-
const finalNodes = [];
|
|
2092
|
-
const usedOldEls = /* @__PURE__ */ new WeakSet();
|
|
2093
|
-
const resolveOldElOnce = createOldElResolver(parent, oldKeyMap, usedOldEls);
|
|
2094
|
-
for (let i = 0; i < newChildren.length; i++) {
|
|
2095
|
-
const child = newChildren[i];
|
|
2096
|
-
const node = reconcileSingleChild(
|
|
2097
|
-
child,
|
|
2098
|
-
i,
|
|
2099
|
-
parent,
|
|
2100
|
-
resolveOldElOnce,
|
|
2101
|
-
usedOldEls,
|
|
2102
|
-
newKeyMap
|
|
2103
|
-
);
|
|
2104
|
-
if (node) finalNodes.push(node);
|
|
2105
|
-
}
|
|
2106
|
-
if (typeof document === "undefined") return newKeyMap;
|
|
2107
|
-
commitReconciliation(parent, finalNodes);
|
|
2108
|
-
keyedElements.delete(parent);
|
|
2109
|
-
return newKeyMap;
|
|
2110
|
-
}
|
|
2111
|
-
function createOldElResolver(parent, oldKeyMap, usedOldEls) {
|
|
2112
|
-
return (k) => {
|
|
2113
|
-
if (!oldKeyMap) return void 0;
|
|
2114
|
-
const direct = oldKeyMap.get(k);
|
|
2115
|
-
if (direct && !usedOldEls.has(direct)) {
|
|
2116
|
-
usedOldEls.add(direct);
|
|
2117
|
-
return direct;
|
|
2118
|
-
}
|
|
2119
|
-
const s = String(k);
|
|
2120
|
-
const byString = oldKeyMap.get(s);
|
|
2121
|
-
if (byString && !usedOldEls.has(byString)) {
|
|
2122
|
-
usedOldEls.add(byString);
|
|
2123
|
-
return byString;
|
|
2124
|
-
}
|
|
2125
|
-
const n = Number(s);
|
|
2126
|
-
if (!Number.isNaN(n)) {
|
|
2127
|
-
const byNum = oldKeyMap.get(n);
|
|
2128
|
-
if (byNum && !usedOldEls.has(byNum)) {
|
|
2129
|
-
usedOldEls.add(byNum);
|
|
2130
|
-
return byNum;
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
return scanForElementByKey(parent, k, s, usedOldEls);
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
function scanForElementByKey(parent, k, keyStr, usedOldEls) {
|
|
2137
|
-
try {
|
|
2138
|
-
for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
|
|
2139
|
-
if (usedOldEls.has(ch)) continue;
|
|
2140
|
-
const attr = ch.getAttribute("data-key");
|
|
2141
|
-
if (attr === keyStr) {
|
|
2142
|
-
usedOldEls.add(ch);
|
|
2143
|
-
return ch;
|
|
2144
|
-
}
|
|
2145
|
-
if (attr !== null) {
|
|
2146
|
-
const numAttr = Number(attr);
|
|
2147
|
-
if (!Number.isNaN(numAttr) && numAttr === k) {
|
|
2148
|
-
usedOldEls.add(ch);
|
|
2149
|
-
return ch;
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
}
|
|
2153
|
-
} catch {
|
|
2154
|
-
}
|
|
2155
|
-
return void 0;
|
|
2156
|
-
}
|
|
2157
|
-
function reconcileSingleChild(child, index, parent, resolveOldElOnce, usedOldEls, newKeyMap) {
|
|
2158
|
-
const key = extractKey(child);
|
|
2159
|
-
if (key !== void 0) {
|
|
2160
|
-
return reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap);
|
|
2161
|
-
}
|
|
2162
|
-
return reconcileUnkeyedChild(child, index, parent, usedOldEls);
|
|
2163
|
-
}
|
|
2164
|
-
function reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap) {
|
|
2165
|
-
const el = resolveOldElOnce(key);
|
|
2166
|
-
if (el && el.parentElement === parent) {
|
|
2167
|
-
try {
|
|
2168
|
-
const childObj = child;
|
|
2169
|
-
if (childObj && typeof childObj === "object" && typeof childObj.type === "string") {
|
|
2170
|
-
if (tagNamesEqualIgnoreCase2(el.tagName, childObj.type)) {
|
|
2171
|
-
updateElementFromVnode(el, child);
|
|
2172
|
-
newKeyMap.set(key, el);
|
|
2173
|
-
return el;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
} catch {
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
const dom = createDOMNode(child);
|
|
2180
|
-
if (dom) {
|
|
2181
|
-
if (dom instanceof Element) newKeyMap.set(key, dom);
|
|
2182
|
-
return dom;
|
|
2183
|
-
}
|
|
2184
|
-
return null;
|
|
2185
|
-
}
|
|
2186
|
-
function reconcileUnkeyedChild(child, index, parent, usedOldEls) {
|
|
2187
|
-
try {
|
|
2188
|
-
const existing = parent.children[index];
|
|
2189
|
-
if (existing && (typeof child === "string" || typeof child === "number") && existing.nodeType === 1) {
|
|
2190
|
-
existing.textContent = String(child);
|
|
2191
|
-
usedOldEls.add(existing);
|
|
2192
|
-
return existing;
|
|
2193
|
-
}
|
|
2194
|
-
if (canReuseElement(existing, child)) {
|
|
2195
|
-
updateElementFromVnode(existing, child);
|
|
2196
|
-
usedOldEls.add(existing);
|
|
2197
|
-
return existing;
|
|
2198
|
-
}
|
|
2199
|
-
const avail = findAvailableUnkeyedElement(parent, usedOldEls);
|
|
2200
|
-
if (avail) {
|
|
2201
|
-
const reuseResult = tryReuseElement(avail, child, usedOldEls);
|
|
2202
|
-
if (reuseResult) return reuseResult;
|
|
2203
|
-
}
|
|
2204
|
-
} catch {
|
|
2205
|
-
}
|
|
2206
|
-
const dom = createDOMNode(child);
|
|
2207
|
-
return dom;
|
|
2208
|
-
}
|
|
2209
|
-
function canReuseElement(existing, child) {
|
|
2210
|
-
if (!existing) return false;
|
|
2211
|
-
if (typeof child !== "object" || child === null || !("type" in child))
|
|
2212
|
-
return false;
|
|
2213
|
-
const childObj = child;
|
|
2214
|
-
const existingKey = existing.getAttribute("data-key");
|
|
2215
|
-
const hasNoKey = existingKey === null || existingKey === void 0;
|
|
2216
|
-
return hasNoKey && typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(existing.tagName, childObj.type);
|
|
2217
|
-
}
|
|
2218
|
-
function findAvailableUnkeyedElement(parent, usedOldEls) {
|
|
2219
|
-
for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
|
|
2220
|
-
if (usedOldEls.has(ch)) continue;
|
|
2221
|
-
if (ch.getAttribute("data-key") === null) return ch;
|
|
2222
|
-
}
|
|
2223
|
-
return void 0;
|
|
2224
|
-
}
|
|
2225
|
-
function tryReuseElement(avail, child, usedOldEls) {
|
|
2226
|
-
if (typeof child === "string" || typeof child === "number") {
|
|
2227
|
-
avail.textContent = String(child);
|
|
2228
|
-
usedOldEls.add(avail);
|
|
2229
|
-
return avail;
|
|
2230
|
-
}
|
|
2231
|
-
if (typeof child === "object" && child !== null && "type" in child) {
|
|
2232
|
-
const childObj = child;
|
|
2233
|
-
if (typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(avail.tagName, childObj.type)) {
|
|
2234
|
-
updateElementFromVnode(avail, child);
|
|
2235
|
-
usedOldEls.add(avail);
|
|
2236
|
-
return avail;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
return null;
|
|
2240
|
-
}
|
|
2241
|
-
function commitReconciliation(parent, finalNodes) {
|
|
2242
|
-
const fragment = document.createDocumentFragment();
|
|
2243
|
-
for (let i = 0; i < finalNodes.length; i++) {
|
|
2244
|
-
fragment.appendChild(finalNodes[i]);
|
|
2245
|
-
}
|
|
2246
|
-
try {
|
|
2247
|
-
for (let n = parent.firstChild; n; ) {
|
|
2248
|
-
const next = n.nextSibling;
|
|
2249
|
-
if (n instanceof Element) removeAllListeners(n);
|
|
2250
|
-
cleanupInstanceIfPresent(n);
|
|
2251
|
-
n = next;
|
|
2252
|
-
}
|
|
2253
|
-
} catch {
|
|
2254
|
-
}
|
|
2255
|
-
recordDOMReplace("reconcile");
|
|
2256
|
-
parent.replaceChildren(fragment);
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
// src/renderer/evaluate.ts
|
|
2260
|
-
var domRanges = /* @__PURE__ */ new WeakMap();
|
|
2261
|
-
function tagNamesEqualIgnoreCase3(a, b) {
|
|
2262
|
-
if (a === b) return true;
|
|
2263
|
-
if (a.length !== b.length) return false;
|
|
2264
|
-
for (let i = 0; i < a.length; i++) {
|
|
2265
|
-
const ca = a.charCodeAt(i);
|
|
2266
|
-
const cb = b.charCodeAt(i);
|
|
2267
|
-
if (ca === cb) continue;
|
|
2268
|
-
const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
|
|
2269
|
-
const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
|
|
2270
|
-
if (fa !== fb) return false;
|
|
2271
|
-
}
|
|
2272
|
-
return true;
|
|
2273
|
-
}
|
|
2274
|
-
function checkSimpleText(vnodeChildren) {
|
|
2275
|
-
if (!Array.isArray(vnodeChildren)) {
|
|
2276
|
-
if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
|
|
2277
|
-
return { isSimple: true, text: String(vnodeChildren) };
|
|
2278
|
-
}
|
|
2279
|
-
} else if (vnodeChildren.length === 1) {
|
|
2280
|
-
const child = vnodeChildren[0];
|
|
2281
|
-
if (typeof child === "string" || typeof child === "number") {
|
|
2282
|
-
return { isSimple: true, text: String(child) };
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
return { isSimple: false };
|
|
2286
|
-
}
|
|
2287
|
-
function tryUpdateTextInPlace(element, text) {
|
|
2288
|
-
if (element.childNodes.length === 1 && element.firstChild?.nodeType === 3) {
|
|
2289
|
-
element.firstChild.data = text;
|
|
2290
|
-
return true;
|
|
2291
|
-
}
|
|
2292
|
-
return false;
|
|
2293
|
-
}
|
|
2294
|
-
function buildKeyMapFromDOM(parent) {
|
|
2295
|
-
const keyMap = /* @__PURE__ */ new Map();
|
|
2296
|
-
for (let child = parent.firstElementChild; child; child = child.nextElementSibling) {
|
|
2297
|
-
const k = child.getAttribute("data-key");
|
|
2298
|
-
if (k !== null) {
|
|
2299
|
-
keyMap.set(k, child);
|
|
2300
|
-
const n = Number(k);
|
|
2301
|
-
if (!Number.isNaN(n)) keyMap.set(n, child);
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
return keyMap;
|
|
2305
|
-
}
|
|
2306
|
-
function getOrBuildKeyMap(parent) {
|
|
2307
|
-
let keyMap = keyedElements.get(parent);
|
|
2308
|
-
if (!keyMap) {
|
|
2309
|
-
keyMap = buildKeyMapFromDOM(parent);
|
|
2310
|
-
if (keyMap.size > 0) {
|
|
2311
|
-
keyedElements.set(parent, keyMap);
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
return keyMap.size > 0 ? keyMap : void 0;
|
|
2315
|
-
}
|
|
2316
|
-
function hasKeyedChildren(children) {
|
|
2317
|
-
for (let i = 0; i < children.length; i++) {
|
|
2318
|
-
if (extractKey(children[i]) !== void 0) return true;
|
|
2319
|
-
}
|
|
2320
|
-
return false;
|
|
2321
|
-
}
|
|
2322
|
-
function trackBulkTextStats(stats) {
|
|
2323
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2324
|
-
try {
|
|
2325
|
-
__ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
|
|
2326
|
-
__ASKR_incCounter("bulkTextHits");
|
|
2327
|
-
} catch {
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
function trackBulkTextMiss() {
|
|
2332
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2333
|
-
try {
|
|
2334
|
-
__ASKR_incCounter("bulkTextMisses");
|
|
2335
|
-
} catch {
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
function reconcileKeyed(parent, children, oldKeyMap) {
|
|
2340
|
-
if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
|
|
2341
|
-
const result = tryForcedBulkKeyedPath(parent, children);
|
|
2342
|
-
if (result) return;
|
|
2343
|
-
}
|
|
2344
|
-
const newKeyMap = reconcileKeyedChildren(parent, children, oldKeyMap);
|
|
2345
|
-
keyedElements.set(parent, newKeyMap);
|
|
2346
|
-
}
|
|
2347
|
-
function tryForcedBulkKeyedPath(parent, children) {
|
|
2348
|
-
try {
|
|
2349
|
-
const keyedVnodes = [];
|
|
2350
|
-
for (const child of children) {
|
|
2351
|
-
if (_isDOMElement(child) && child.key !== void 0) {
|
|
2352
|
-
keyedVnodes.push({
|
|
2353
|
-
key: child.key,
|
|
2354
|
-
vnode: child
|
|
2355
|
-
});
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
if (keyedVnodes.length === 0 || keyedVnodes.length !== children.length) {
|
|
2359
|
-
return false;
|
|
2360
|
-
}
|
|
2361
|
-
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
2362
|
-
logger.warn(
|
|
2363
|
-
"[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
|
|
2364
|
-
);
|
|
2365
|
-
}
|
|
2366
|
-
const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
|
|
2367
|
-
if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
|
|
2368
|
-
try {
|
|
2369
|
-
__ASKR_set("__LAST_FASTPATH_STATS", stats);
|
|
2370
|
-
__ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
|
|
2371
|
-
__ASKR_incCounter("bulkKeyedPositionalForced");
|
|
2372
|
-
} catch {
|
|
2373
|
-
}
|
|
2374
|
-
}
|
|
2375
|
-
const newMap = buildKeyMapFromDOM(parent);
|
|
2376
|
-
keyedElements.set(parent, newMap);
|
|
2377
|
-
return true;
|
|
2378
|
-
} catch (err) {
|
|
2379
|
-
if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
|
|
2380
|
-
logger.warn(
|
|
2381
|
-
"[Askr][FASTPATH] forced bulk path failed, falling back",
|
|
2382
|
-
err
|
|
2383
|
-
);
|
|
2384
|
-
}
|
|
2385
|
-
return false;
|
|
2386
|
-
}
|
|
2387
|
-
}
|
|
2388
|
-
function reconcileUnkeyed(parent, children) {
|
|
2389
|
-
if (isBulkTextFastPathEligible(parent, children)) {
|
|
2390
|
-
const stats = performBulkTextReplace(parent, children);
|
|
2391
|
-
trackBulkTextStats(stats);
|
|
2392
|
-
} else {
|
|
2393
|
-
trackBulkTextMiss();
|
|
2394
|
-
updateUnkeyedChildren(parent, children);
|
|
2395
|
-
}
|
|
2396
|
-
keyedElements.delete(parent);
|
|
2397
|
-
}
|
|
2398
|
-
function updateElementChildren2(element, vnodeChildren) {
|
|
2399
|
-
if (!vnodeChildren) {
|
|
2400
|
-
element.textContent = "";
|
|
2401
|
-
keyedElements.delete(element);
|
|
2402
|
-
return;
|
|
2403
|
-
}
|
|
2404
|
-
if (!Array.isArray(vnodeChildren)) {
|
|
2405
|
-
element.textContent = "";
|
|
2406
|
-
const dom = createDOMNode(vnodeChildren);
|
|
2407
|
-
if (dom) element.appendChild(dom);
|
|
2408
|
-
keyedElements.delete(element);
|
|
2409
|
-
return;
|
|
2410
|
-
}
|
|
2411
|
-
if (hasKeyedChildren(vnodeChildren)) {
|
|
2412
|
-
const oldKeyMap = getOrBuildKeyMap(element);
|
|
2413
|
-
try {
|
|
2414
|
-
reconcileKeyed(element, vnodeChildren, oldKeyMap);
|
|
2415
|
-
} catch {
|
|
2416
|
-
const newKeyMap = reconcileKeyedChildren(
|
|
2417
|
-
element,
|
|
2418
|
-
vnodeChildren,
|
|
2419
|
-
oldKeyMap
|
|
2420
|
-
);
|
|
2421
|
-
keyedElements.set(element, newKeyMap);
|
|
2422
|
-
}
|
|
2423
|
-
} else {
|
|
2424
|
-
reconcileUnkeyed(element, vnodeChildren);
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
function smartUpdateElement(element, vnode) {
|
|
2428
|
-
const vnodeChildren = vnode.children || vnode.props?.children;
|
|
2429
|
-
const textCheck = checkSimpleText(vnodeChildren);
|
|
2430
|
-
if (textCheck.isSimple && tryUpdateTextInPlace(element, textCheck.text)) ; else {
|
|
2431
|
-
updateElementChildren2(element, vnodeChildren);
|
|
2432
|
-
}
|
|
2433
|
-
updateElementFromVnode(element, vnode, false);
|
|
2434
|
-
}
|
|
2435
|
-
function processFragmentChildren(target, childArray) {
|
|
2436
|
-
let existingNode = target.firstElementChild;
|
|
2437
|
-
for (let i = 0; i < childArray.length; i++) {
|
|
2438
|
-
const childVnode = childArray[i];
|
|
2439
|
-
const nextExisting = existingNode ? existingNode.nextElementSibling : null;
|
|
2440
|
-
if (existingNode && _isDOMElement(childVnode) && typeof childVnode.type === "string" && tagNamesEqualIgnoreCase3(
|
|
2441
|
-
existingNode.tagName,
|
|
2442
|
-
childVnode.type
|
|
2443
|
-
)) {
|
|
2444
|
-
smartUpdateElement(existingNode, childVnode);
|
|
2445
|
-
existingNode = nextExisting;
|
|
2446
|
-
continue;
|
|
2447
|
-
}
|
|
2448
|
-
const newDom = createDOMNode(childVnode);
|
|
2449
|
-
if (newDom) {
|
|
2450
|
-
if (existingNode) {
|
|
2451
|
-
target.replaceChild(newDom, existingNode);
|
|
2452
|
-
} else {
|
|
2453
|
-
target.appendChild(newDom);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
|
-
existingNode = nextExisting;
|
|
2457
|
-
}
|
|
2458
|
-
while (existingNode) {
|
|
2459
|
-
const next = existingNode.nextElementSibling;
|
|
2460
|
-
target.removeChild(existingNode);
|
|
2461
|
-
existingNode = next;
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
function applyPropsToElement2(el, props) {
|
|
2465
|
-
for (const [key, value] of Object.entries(props)) {
|
|
2466
|
-
if (key === "children" || key === "key") continue;
|
|
2467
|
-
if (value === void 0 || value === null || value === false) continue;
|
|
2468
|
-
if (key === "ref") {
|
|
2469
|
-
applyRef2(el, value);
|
|
2470
|
-
continue;
|
|
2471
|
-
}
|
|
2472
|
-
const eventName = parseEventName(key);
|
|
2473
|
-
if (eventName) {
|
|
2474
|
-
const wrappedHandler = createWrappedHandler(
|
|
2475
|
-
value,
|
|
2476
|
-
false
|
|
2477
|
-
);
|
|
2478
|
-
const options = getPassiveOptions(eventName);
|
|
2479
|
-
if (options !== void 0)
|
|
2480
|
-
el.addEventListener(eventName, wrappedHandler, options);
|
|
2481
|
-
else el.addEventListener(eventName, wrappedHandler);
|
|
2482
|
-
if (!elementListeners.has(el)) elementListeners.set(el, /* @__PURE__ */ new Map());
|
|
2483
|
-
elementListeners.get(el).set(eventName, {
|
|
2484
|
-
handler: wrappedHandler,
|
|
2485
|
-
original: value,
|
|
2486
|
-
options
|
|
2487
|
-
});
|
|
2488
|
-
continue;
|
|
2489
|
-
}
|
|
2490
|
-
if (key === "class" || key === "className") {
|
|
2491
|
-
el.className = String(value);
|
|
2492
|
-
} else if (key === "value" || key === "checked") {
|
|
2493
|
-
el[key] = value;
|
|
2494
|
-
} else {
|
|
2495
|
-
el.setAttribute(key, String(value));
|
|
2496
|
-
}
|
|
2497
|
-
}
|
|
2498
|
-
}
|
|
2499
|
-
function applyRef2(el, ref) {
|
|
2500
|
-
const r = ref;
|
|
2501
|
-
if (!r) return;
|
|
2502
|
-
if (typeof r === "function") {
|
|
2503
|
-
r(el);
|
|
2504
|
-
return;
|
|
2505
|
-
}
|
|
2506
|
-
try {
|
|
2507
|
-
r.current = el;
|
|
2508
|
-
} catch {
|
|
2509
|
-
}
|
|
2510
|
-
}
|
|
2511
|
-
function tryFirstRenderKeyedChildren(target, vnode) {
|
|
2512
|
-
const children = vnode.children;
|
|
2513
|
-
if (!Array.isArray(children) || !hasKeyedChildren(children)) {
|
|
2514
|
-
return false;
|
|
2515
|
-
}
|
|
2516
|
-
const el = document.createElement(vnode.type);
|
|
2517
|
-
target.appendChild(el);
|
|
2518
|
-
applyPropsToElement2(el, vnode.props || {});
|
|
2519
|
-
const newKeyMap = reconcileKeyedChildren(el, children, void 0);
|
|
2520
|
-
keyedElements.set(el, newKeyMap);
|
|
2521
|
-
return true;
|
|
2522
|
-
}
|
|
2523
|
-
function isFragment(vnode) {
|
|
2524
|
-
return _isDOMElement(vnode) && typeof vnode.type === "symbol" && (vnode.type === Fragment || String(vnode.type) === "Symbol(askr.fragment)");
|
|
2525
|
-
}
|
|
2526
|
-
function getFragmentChildren(vnode) {
|
|
2527
|
-
const fragmentChildren = vnode.props?.children || vnode.children || [];
|
|
2528
|
-
return Array.isArray(fragmentChildren) ? fragmentChildren : [fragmentChildren];
|
|
2529
|
-
}
|
|
2530
|
-
function evaluate(node, target, context) {
|
|
2531
|
-
if (!target) return;
|
|
2532
|
-
if (typeof document === "undefined") {
|
|
2533
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2534
|
-
try {
|
|
2535
|
-
console.warn("[Askr] evaluate() called in non-DOM environment; no-op.");
|
|
2536
|
-
} catch (e) {
|
|
2537
|
-
}
|
|
2538
|
-
}
|
|
2539
|
-
return;
|
|
2540
|
-
}
|
|
2541
|
-
if (context && domRanges.has(context)) {
|
|
2542
|
-
const range = domRanges.get(context);
|
|
2543
|
-
let current2 = range.start.nextSibling;
|
|
2544
|
-
while (current2 && current2 !== range.end) {
|
|
2545
|
-
const next = current2.nextSibling;
|
|
2546
|
-
current2.remove();
|
|
2547
|
-
current2 = next;
|
|
2548
|
-
}
|
|
2549
|
-
const dom = createDOMNode(node);
|
|
2550
|
-
if (dom) {
|
|
2551
|
-
target.insertBefore(dom, range.end);
|
|
2552
|
-
}
|
|
2553
|
-
} else if (context) {
|
|
2554
|
-
const start = document.createComment("component-start");
|
|
2555
|
-
const end = document.createComment("component-end");
|
|
2556
|
-
target.appendChild(start);
|
|
2557
|
-
target.appendChild(end);
|
|
2558
|
-
domRanges.set(context, { start, end });
|
|
2559
|
-
const dom = createDOMNode(node);
|
|
2560
|
-
if (dom) {
|
|
2561
|
-
target.insertBefore(dom, end);
|
|
2562
|
-
}
|
|
2563
|
-
} else {
|
|
2564
|
-
let vnode = node;
|
|
2565
|
-
if (isFragment(vnode)) {
|
|
2566
|
-
const childArray = getFragmentChildren(vnode);
|
|
2567
|
-
if (childArray.length === 1 && _isDOMElement(childArray[0]) && typeof childArray[0].type === "string") {
|
|
2568
|
-
vnode = childArray[0];
|
|
2569
|
-
} else {
|
|
2570
|
-
processFragmentChildren(target, childArray);
|
|
2571
|
-
return;
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
const firstChild = target.children[0];
|
|
2575
|
-
if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && tagNamesEqualIgnoreCase3(firstChild.tagName, vnode.type)) {
|
|
2576
|
-
smartUpdateElement(firstChild, vnode);
|
|
2577
|
-
} else {
|
|
2578
|
-
target.textContent = "";
|
|
2579
|
-
if (_isDOMElement(vnode) && typeof vnode.type === "string" && tryFirstRenderKeyedChildren(target, vnode)) {
|
|
2580
|
-
return;
|
|
2581
|
-
}
|
|
2582
|
-
const dom = createDOMNode(vnode);
|
|
2583
|
-
if (dom) {
|
|
2584
|
-
target.appendChild(dom);
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
|
|
2590
|
-
// src/renderer/index.ts
|
|
2591
|
-
if (typeof globalThis !== "undefined") {
|
|
2592
|
-
const _g = globalThis;
|
|
2593
|
-
_g.__ASKR_RENDERER = {
|
|
2594
|
-
evaluate,
|
|
2595
|
-
isKeyedReorderFastPathEligible,
|
|
2596
|
-
getKeyMapForElement
|
|
2597
|
-
};
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2600
|
-
// src/runtime/component.ts
|
|
2601
|
-
function createComponentInstance(id, fn, props, target) {
|
|
2602
|
-
const instance = {
|
|
2603
|
-
id,
|
|
2604
|
-
fn,
|
|
2605
|
-
props,
|
|
2606
|
-
target,
|
|
2607
|
-
mounted: false,
|
|
2608
|
-
abortController: new AbortController(),
|
|
2609
|
-
// Create per-component
|
|
2610
|
-
stateValues: [],
|
|
2611
|
-
evaluationGeneration: 0,
|
|
2612
|
-
notifyUpdate: null,
|
|
2613
|
-
// Prebound helpers (initialized below) to avoid per-update allocations
|
|
2614
|
-
_pendingFlushTask: void 0,
|
|
2615
|
-
_pendingRunTask: void 0,
|
|
2616
|
-
_enqueueRun: void 0,
|
|
2617
|
-
stateIndexCheck: -1,
|
|
2618
|
-
expectedStateIndices: [],
|
|
2619
|
-
firstRenderComplete: false,
|
|
2620
|
-
mountOperations: [],
|
|
2621
|
-
cleanupFns: [],
|
|
2622
|
-
hasPendingUpdate: false,
|
|
2623
|
-
ownerFrame: null,
|
|
2624
|
-
// Will be set by renderer when vnode is marked
|
|
2625
|
-
ssr: false,
|
|
2626
|
-
cleanupStrict: false,
|
|
2627
|
-
isRoot: false,
|
|
2628
|
-
// Render-tracking (for precise state subscriptions)
|
|
2629
|
-
_currentRenderToken: void 0,
|
|
2630
|
-
lastRenderToken: 0,
|
|
2631
|
-
_pendingReadStates: /* @__PURE__ */ new Set(),
|
|
2632
|
-
_lastReadStates: /* @__PURE__ */ new Set()
|
|
2633
|
-
};
|
|
2634
|
-
instance._pendingRunTask = () => {
|
|
2635
|
-
instance.hasPendingUpdate = false;
|
|
2636
|
-
runComponent(instance);
|
|
2637
|
-
};
|
|
2638
|
-
instance._enqueueRun = () => {
|
|
2639
|
-
if (!instance.hasPendingUpdate) {
|
|
2640
|
-
instance.hasPendingUpdate = true;
|
|
2641
|
-
globalScheduler.enqueue(instance._pendingRunTask);
|
|
2642
|
-
}
|
|
2643
|
-
};
|
|
2644
|
-
instance._pendingFlushTask = () => {
|
|
2645
|
-
instance.hasPendingUpdate = false;
|
|
2646
|
-
instance._enqueueRun?.();
|
|
2647
|
-
};
|
|
2648
|
-
return instance;
|
|
2649
|
-
}
|
|
2650
|
-
var currentInstance = null;
|
|
2651
|
-
function getCurrentComponentInstance() {
|
|
2652
|
-
return currentInstance;
|
|
2653
|
-
}
|
|
2654
|
-
function setCurrentComponentInstance(instance) {
|
|
2655
|
-
currentInstance = instance;
|
|
2656
|
-
}
|
|
2657
|
-
function executeMountOperations(instance) {
|
|
2658
|
-
if (!instance.isRoot) return;
|
|
2659
|
-
for (const operation of instance.mountOperations) {
|
|
2660
|
-
const result = operation();
|
|
2661
|
-
if (result instanceof Promise) {
|
|
2662
|
-
result.then((cleanup) => {
|
|
2663
|
-
if (typeof cleanup === "function") {
|
|
2664
|
-
instance.cleanupFns.push(cleanup);
|
|
2665
|
-
}
|
|
2666
|
-
});
|
|
2667
|
-
} else if (typeof result === "function") {
|
|
2668
|
-
instance.cleanupFns.push(result);
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
instance.mountOperations = [];
|
|
2672
|
-
}
|
|
2673
|
-
function mountInstanceInline(instance, target) {
|
|
2674
|
-
instance.target = target;
|
|
2675
|
-
try {
|
|
2676
|
-
if (target instanceof Element)
|
|
2677
|
-
target.__ASKR_INSTANCE = instance;
|
|
2678
|
-
} catch (err) {
|
|
2679
|
-
}
|
|
2680
|
-
instance.notifyUpdate = instance._enqueueRun;
|
|
2681
|
-
const wasFirstMount = !instance.mounted;
|
|
2682
|
-
instance.mounted = true;
|
|
2683
|
-
if (wasFirstMount && instance.mountOperations.length > 0) {
|
|
2684
|
-
executeMountOperations(instance);
|
|
2685
|
-
}
|
|
2686
|
-
}
|
|
2687
|
-
var _globalRenderCounter = 0;
|
|
2688
|
-
function runComponent(instance) {
|
|
2689
|
-
instance.notifyUpdate = instance._enqueueRun;
|
|
2690
|
-
instance._currentRenderToken = ++_globalRenderCounter;
|
|
2691
|
-
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
2692
|
-
const domSnapshot = instance.target ? instance.target.innerHTML : "";
|
|
2693
|
-
const result = executeComponentSync(instance);
|
|
2694
|
-
if (result instanceof Promise) {
|
|
2695
|
-
throw new Error(
|
|
2696
|
-
"Async components are not supported. Components must be synchronous."
|
|
2697
|
-
);
|
|
2698
|
-
} else {
|
|
2699
|
-
const fastlaneBridge = globalThis.__ASKR_FASTLANE;
|
|
2700
|
-
try {
|
|
2701
|
-
const used = fastlaneBridge?.tryRuntimeFastLaneSync?.(instance, result);
|
|
2702
|
-
if (used) return;
|
|
2703
|
-
} catch (err) {
|
|
2704
|
-
if (process.env.NODE_ENV !== "production") throw err;
|
|
2705
|
-
}
|
|
2706
|
-
globalScheduler.enqueue(() => {
|
|
2707
|
-
if (!instance.target && instance._placeholder) {
|
|
2708
|
-
if (result === null || result === void 0) {
|
|
2709
|
-
finalizeReadSubscriptions2(instance);
|
|
2710
|
-
return;
|
|
2711
|
-
}
|
|
2712
|
-
const placeholder = instance._placeholder;
|
|
2713
|
-
const parent = placeholder.parentNode;
|
|
2714
|
-
if (!parent) {
|
|
2715
|
-
logger.warn(
|
|
2716
|
-
"[Askr] placeholder no longer in DOM, cannot render component"
|
|
2717
|
-
);
|
|
2718
|
-
return;
|
|
2719
|
-
}
|
|
2720
|
-
const host = document.createElement("div");
|
|
2721
|
-
const oldInstance = currentInstance;
|
|
2722
|
-
currentInstance = instance;
|
|
2723
|
-
try {
|
|
2724
|
-
evaluate(result, host);
|
|
2725
|
-
parent.replaceChild(host, placeholder);
|
|
2726
|
-
instance.target = host;
|
|
2727
|
-
instance._placeholder = void 0;
|
|
2728
|
-
host.__ASKR_INSTANCE = instance;
|
|
2729
|
-
finalizeReadSubscriptions2(instance);
|
|
2730
|
-
} finally {
|
|
2731
|
-
currentInstance = oldInstance;
|
|
2732
|
-
}
|
|
2733
|
-
return;
|
|
2734
|
-
}
|
|
2735
|
-
if (instance.target) {
|
|
2736
|
-
let oldChildren = [];
|
|
2737
|
-
try {
|
|
2738
|
-
const wasFirstMount = !instance.mounted;
|
|
2739
|
-
const oldInstance = currentInstance;
|
|
2740
|
-
currentInstance = instance;
|
|
2741
|
-
oldChildren = Array.from(instance.target.childNodes);
|
|
2742
|
-
try {
|
|
2743
|
-
evaluate(result, instance.target);
|
|
2744
|
-
} catch (e) {
|
|
2745
|
-
try {
|
|
2746
|
-
const newChildren = Array.from(instance.target.childNodes);
|
|
2747
|
-
for (const n of newChildren) {
|
|
2748
|
-
try {
|
|
2749
|
-
cleanupInstancesUnder(n);
|
|
2750
|
-
} catch (err) {
|
|
2751
|
-
logger.warn(
|
|
2752
|
-
"[Askr] error cleaning up failed commit children:",
|
|
2753
|
-
err
|
|
2754
|
-
);
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
} catch (_err) {
|
|
2758
|
-
void _err;
|
|
2759
|
-
}
|
|
2760
|
-
try {
|
|
2761
|
-
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
2762
|
-
__ASKR_set(
|
|
2763
|
-
"__LAST_DOM_REPLACE_STACK_COMPONENT_RESTORE",
|
|
2764
|
-
new Error().stack
|
|
2765
|
-
);
|
|
2766
|
-
} catch (e2) {
|
|
2767
|
-
void e2;
|
|
2768
|
-
}
|
|
2769
|
-
instance.target.replaceChildren(...oldChildren);
|
|
2770
|
-
throw e;
|
|
2771
|
-
} finally {
|
|
2772
|
-
currentInstance = oldInstance;
|
|
2773
|
-
}
|
|
2774
|
-
finalizeReadSubscriptions2(instance);
|
|
2775
|
-
instance.mounted = true;
|
|
2776
|
-
if (wasFirstMount && instance.mountOperations.length > 0) {
|
|
2777
|
-
executeMountOperations(instance);
|
|
2778
|
-
}
|
|
2779
|
-
} catch (renderError) {
|
|
2780
|
-
try {
|
|
2781
|
-
const currentChildren = Array.from(instance.target.childNodes);
|
|
2782
|
-
for (const n of currentChildren) {
|
|
2783
|
-
try {
|
|
2784
|
-
cleanupInstancesUnder(n);
|
|
2785
|
-
} catch (err) {
|
|
2786
|
-
logger.warn(
|
|
2787
|
-
"[Askr] error cleaning up partial children during rollback:",
|
|
2788
|
-
err
|
|
2789
|
-
);
|
|
2790
|
-
}
|
|
2791
|
-
}
|
|
2792
|
-
} catch (_err) {
|
|
2793
|
-
}
|
|
2794
|
-
try {
|
|
2795
|
-
try {
|
|
2796
|
-
__ASKR_incCounter("__DOM_REPLACE_COUNT");
|
|
2797
|
-
__ASKR_set(
|
|
2798
|
-
"__LAST_DOM_REPLACE_STACK_COMPONENT_ROLLBACK",
|
|
2799
|
-
new Error().stack
|
|
2800
|
-
);
|
|
2801
|
-
} catch (e) {
|
|
2802
|
-
void e;
|
|
2803
|
-
}
|
|
2804
|
-
instance.target.replaceChildren(...oldChildren);
|
|
2805
|
-
} catch {
|
|
2806
|
-
instance.target.innerHTML = domSnapshot;
|
|
2807
|
-
}
|
|
2808
|
-
throw renderError;
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
});
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
function renderComponentInline(instance) {
|
|
2815
|
-
const hadToken = instance._currentRenderToken !== void 0;
|
|
2816
|
-
const prevToken = instance._currentRenderToken;
|
|
2817
|
-
const prevPendingReads = instance._pendingReadStates;
|
|
2818
|
-
if (!hadToken) {
|
|
2819
|
-
instance._currentRenderToken = ++_globalRenderCounter;
|
|
2820
|
-
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
2821
|
-
}
|
|
2822
|
-
try {
|
|
2823
|
-
const result = executeComponentSync(instance);
|
|
2824
|
-
if (!hadToken) {
|
|
2825
|
-
finalizeReadSubscriptions2(instance);
|
|
2826
|
-
}
|
|
2827
|
-
return result;
|
|
2828
|
-
} finally {
|
|
2829
|
-
instance._currentRenderToken = prevToken;
|
|
2830
|
-
instance._pendingReadStates = prevPendingReads ?? /* @__PURE__ */ new Set();
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
function executeComponentSync(instance) {
|
|
2834
|
-
instance.stateIndexCheck = -1;
|
|
2835
|
-
for (const state of instance.stateValues) {
|
|
2836
|
-
if (state) {
|
|
2837
|
-
state._hasBeenRead = false;
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
2841
|
-
currentInstance = instance;
|
|
2842
|
-
try {
|
|
2843
|
-
const renderStartTime = process.env.NODE_ENV !== "production" ? Date.now() : 0;
|
|
2844
|
-
const context = {
|
|
2845
|
-
signal: instance.abortController.signal
|
|
2846
|
-
};
|
|
2847
|
-
const executionFrame = {
|
|
2848
|
-
parent: instance.ownerFrame,
|
|
2849
|
-
values: null
|
|
2850
|
-
};
|
|
2851
|
-
const result = withContext(
|
|
2852
|
-
executionFrame,
|
|
2853
|
-
() => instance.fn(instance.props, context)
|
|
2854
|
-
);
|
|
2855
|
-
const renderTime = Date.now() - renderStartTime;
|
|
2856
|
-
if (renderTime > 5) {
|
|
2857
|
-
logger.warn(
|
|
2858
|
-
`[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`
|
|
2859
|
-
);
|
|
2860
|
-
}
|
|
2861
|
-
if (!instance.firstRenderComplete) {
|
|
2862
|
-
instance.firstRenderComplete = true;
|
|
2863
|
-
}
|
|
2864
|
-
for (let i = 0; i < instance.stateValues.length; i++) {
|
|
2865
|
-
const state = instance.stateValues[i];
|
|
2866
|
-
if (state && !state._hasBeenRead) {
|
|
2867
|
-
try {
|
|
2868
|
-
const name = instance.fn?.name || "<anonymous>";
|
|
2869
|
-
logger.warn(
|
|
2870
|
-
`[askr] Unused state variable detected in ${name} at index ${i}. State should be read during render or removed.`
|
|
2871
|
-
);
|
|
2872
|
-
} catch {
|
|
2873
|
-
logger.warn(
|
|
2874
|
-
`[askr] Unused state variable detected. State should be read during render or removed.`
|
|
2875
|
-
);
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
return result;
|
|
2880
|
-
} finally {
|
|
2881
|
-
currentInstance = null;
|
|
2882
|
-
}
|
|
2883
|
-
}
|
|
2884
|
-
function getCurrentInstance() {
|
|
2885
|
-
return currentInstance;
|
|
2886
|
-
}
|
|
2887
|
-
function finalizeReadSubscriptions2(instance) {
|
|
2888
|
-
const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
|
|
2889
|
-
const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
|
|
2890
|
-
const token = instance._currentRenderToken;
|
|
2891
|
-
if (token === void 0) return;
|
|
2892
|
-
for (const s of oldSet) {
|
|
2893
|
-
if (!newSet.has(s)) {
|
|
2894
|
-
const readers = s._readers;
|
|
2895
|
-
if (readers) readers.delete(instance);
|
|
2896
|
-
}
|
|
2897
|
-
}
|
|
2898
|
-
instance.lastRenderToken = token;
|
|
2899
|
-
for (const s of newSet) {
|
|
2900
|
-
let readers = s._readers;
|
|
2901
|
-
if (!readers) {
|
|
2902
|
-
readers = /* @__PURE__ */ new Map();
|
|
2903
|
-
s._readers = readers;
|
|
2904
|
-
}
|
|
2905
|
-
readers.set(instance, instance.lastRenderToken ?? 0);
|
|
2906
|
-
}
|
|
2907
|
-
instance._lastReadStates = newSet;
|
|
2908
|
-
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
2909
|
-
instance._currentRenderToken = void 0;
|
|
2910
|
-
}
|
|
2911
|
-
function cleanupComponent(instance) {
|
|
2912
|
-
const cleanupErrors = [];
|
|
2913
|
-
for (const cleanup of instance.cleanupFns) {
|
|
2914
|
-
try {
|
|
2915
|
-
cleanup();
|
|
2916
|
-
} catch (err) {
|
|
2917
|
-
if (instance.cleanupStrict) {
|
|
2918
|
-
cleanupErrors.push(err);
|
|
2919
|
-
} else {
|
|
2920
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2921
|
-
logger.warn("[Askr] cleanup function threw:", err);
|
|
2922
|
-
}
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
instance.cleanupFns = [];
|
|
2927
|
-
if (cleanupErrors.length > 0) {
|
|
2928
|
-
throw new AggregateError(
|
|
2929
|
-
cleanupErrors,
|
|
2930
|
-
`Cleanup failed for component ${instance.id}`
|
|
2931
|
-
);
|
|
2932
|
-
}
|
|
2933
|
-
if (instance._lastReadStates) {
|
|
2934
|
-
for (const s of instance._lastReadStates) {
|
|
2935
|
-
const readers = s._readers;
|
|
2936
|
-
if (readers) readers.delete(instance);
|
|
2937
|
-
}
|
|
2938
|
-
instance._lastReadStates = /* @__PURE__ */ new Set();
|
|
2939
|
-
}
|
|
2940
|
-
instance.abortController.abort();
|
|
2941
|
-
instance.notifyUpdate = null;
|
|
2942
|
-
instance.mounted = false;
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
// src/runtime/execution-model.ts
|
|
2946
|
-
var EXECUTION_MODEL_KEY = /* @__PURE__ */ Symbol.for("__ASKR_EXECUTION_MODEL__");
|
|
2947
|
-
function getExecutionModel() {
|
|
2948
|
-
const g = globalThis;
|
|
2949
|
-
return g[EXECUTION_MODEL_KEY];
|
|
2950
|
-
}
|
|
2951
|
-
|
|
2952
|
-
// src/router/route.ts
|
|
2953
|
-
var routes = [];
|
|
2954
|
-
var namespaces = /* @__PURE__ */ new Set();
|
|
2955
|
-
var HAS_ROUTES_KEY = /* @__PURE__ */ Symbol.for("__ASKR_HAS_ROUTES__");
|
|
2956
|
-
function setHasRoutes(value) {
|
|
2957
|
-
try {
|
|
2958
|
-
const g = globalThis;
|
|
2959
|
-
g[HAS_ROUTES_KEY] = value;
|
|
2960
|
-
} catch {
|
|
2961
|
-
}
|
|
2962
|
-
}
|
|
2963
|
-
setHasRoutes(false);
|
|
2964
|
-
var routesByDepth = /* @__PURE__ */ new Map();
|
|
2965
|
-
function getDepth(path) {
|
|
2966
|
-
const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
2967
|
-
return normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
|
|
2968
|
-
}
|
|
2969
|
-
function getSpecificity(path) {
|
|
2970
|
-
const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
2971
|
-
if (normalized === "/*") {
|
|
2972
|
-
return 0;
|
|
2973
|
-
}
|
|
2974
|
-
const segments = normalized.split("/").filter(Boolean);
|
|
2975
|
-
let score = 0;
|
|
2976
|
-
for (const segment of segments) {
|
|
2977
|
-
if (segment.startsWith("{") && segment.endsWith("}")) {
|
|
2978
|
-
score += 2;
|
|
2979
|
-
} else if (segment === "*") {
|
|
2980
|
-
score += 1;
|
|
2981
|
-
} else {
|
|
2982
|
-
score += 3;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
return score;
|
|
2986
|
-
}
|
|
2987
|
-
var serverLocation = null;
|
|
2988
|
-
function setServerLocation(url) {
|
|
2989
|
-
serverLocation = url;
|
|
2990
|
-
}
|
|
2991
|
-
function parseLocation(url) {
|
|
2992
|
-
try {
|
|
2993
|
-
const u = new URL(url, "http://localhost");
|
|
2994
|
-
return { pathname: u.pathname, search: u.search, hash: u.hash };
|
|
2995
|
-
} catch {
|
|
2996
|
-
return { pathname: "/", search: "", hash: "" };
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
function deepFreeze(obj) {
|
|
3000
|
-
if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
|
|
3001
|
-
Object.freeze(obj);
|
|
3002
|
-
for (const key of Object.keys(obj)) {
|
|
3003
|
-
const value = obj[key];
|
|
3004
|
-
if (value && typeof value === "object") deepFreeze(value);
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
return obj;
|
|
3008
|
-
}
|
|
3009
|
-
function makeQuery(search) {
|
|
3010
|
-
const usp = new URLSearchParams(search || "");
|
|
3011
|
-
const mapping = /* @__PURE__ */ new Map();
|
|
3012
|
-
for (const [k, v] of usp.entries()) {
|
|
3013
|
-
const existing = mapping.get(k);
|
|
3014
|
-
if (existing) existing.push(v);
|
|
3015
|
-
else mapping.set(k, [v]);
|
|
3016
|
-
}
|
|
3017
|
-
const obj = {
|
|
3018
|
-
get(key) {
|
|
3019
|
-
const arr = mapping.get(key);
|
|
3020
|
-
return arr ? arr[0] : null;
|
|
3021
|
-
},
|
|
3022
|
-
getAll(key) {
|
|
3023
|
-
const arr = mapping.get(key);
|
|
3024
|
-
return arr ? [...arr] : [];
|
|
3025
|
-
},
|
|
3026
|
-
has(key) {
|
|
3027
|
-
return mapping.has(key);
|
|
3028
|
-
},
|
|
3029
|
-
toJSON() {
|
|
3030
|
-
const out = {};
|
|
3031
|
-
for (const [k, arr] of mapping.entries()) {
|
|
3032
|
-
out[k] = arr.length > 1 ? [...arr] : arr[0];
|
|
3033
|
-
}
|
|
3034
|
-
return out;
|
|
3035
|
-
}
|
|
3036
|
-
};
|
|
3037
|
-
return deepFreeze(obj);
|
|
3038
|
-
}
|
|
3039
|
-
function computeMatches(pathname) {
|
|
3040
|
-
const routesList = getRoutes();
|
|
3041
|
-
const matches = [];
|
|
3042
|
-
function getSpecificity2(path) {
|
|
3043
|
-
const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
3044
|
-
if (normalized === "/*") return 0;
|
|
3045
|
-
const segments = normalized.split("/").filter(Boolean);
|
|
3046
|
-
let score = 0;
|
|
3047
|
-
for (const segment of segments) {
|
|
3048
|
-
if (segment.startsWith("{") && segment.endsWith("}")) score += 2;
|
|
3049
|
-
else if (segment === "*") score += 1;
|
|
3050
|
-
else score += 3;
|
|
3051
|
-
}
|
|
3052
|
-
return score;
|
|
3053
|
-
}
|
|
3054
|
-
for (const r of routesList) {
|
|
3055
|
-
const result = match(pathname, r.path);
|
|
3056
|
-
if (result.matched) {
|
|
3057
|
-
matches.push({
|
|
3058
|
-
pattern: r.path,
|
|
3059
|
-
params: result.params,
|
|
3060
|
-
name: r.name,
|
|
3061
|
-
namespace: r.namespace,
|
|
3062
|
-
specificity: getSpecificity2(r.path)
|
|
3063
|
-
});
|
|
3064
|
-
}
|
|
3065
|
-
}
|
|
3066
|
-
matches.sort((a, b) => b.specificity - a.specificity);
|
|
3067
|
-
return matches.map((m) => ({
|
|
3068
|
-
path: m.pattern,
|
|
3069
|
-
params: deepFreeze({ ...m.params }),
|
|
3070
|
-
name: m.name,
|
|
3071
|
-
namespace: m.namespace
|
|
3072
|
-
}));
|
|
3073
|
-
}
|
|
3074
|
-
var registrationLocked = false;
|
|
3075
|
-
function lockRouteRegistration() {
|
|
3076
|
-
registrationLocked = true;
|
|
3077
|
-
}
|
|
3078
|
-
function _lockRouteRegistrationForTests() {
|
|
3079
|
-
registrationLocked = true;
|
|
3080
|
-
}
|
|
3081
|
-
function _unlockRouteRegistrationForTests() {
|
|
3082
|
-
registrationLocked = false;
|
|
3083
|
-
}
|
|
3084
|
-
function route(path, handler, namespace) {
|
|
3085
|
-
if (getExecutionModel() === "islands") {
|
|
3086
|
-
throw new Error(
|
|
3087
|
-
"Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead."
|
|
3088
|
-
);
|
|
3089
|
-
}
|
|
3090
|
-
if (typeof path === "undefined") {
|
|
3091
|
-
const instance = getCurrentComponentInstance();
|
|
3092
|
-
if (!instance) {
|
|
3093
|
-
throw new Error(
|
|
3094
|
-
"route() can only be called during component render execution. Call route() from inside your component function."
|
|
3095
|
-
);
|
|
3096
|
-
}
|
|
3097
|
-
let pathname = "/";
|
|
3098
|
-
let search = "";
|
|
3099
|
-
let hash = "";
|
|
3100
|
-
if (typeof window !== "undefined" && window.location) {
|
|
3101
|
-
pathname = window.location.pathname || "/";
|
|
3102
|
-
search = window.location.search || "";
|
|
3103
|
-
hash = window.location.hash || "";
|
|
3104
|
-
} else if (serverLocation) {
|
|
3105
|
-
const parsed = parseLocation(serverLocation);
|
|
3106
|
-
pathname = parsed.pathname;
|
|
3107
|
-
search = parsed.search;
|
|
3108
|
-
hash = parsed.hash;
|
|
3109
|
-
}
|
|
3110
|
-
const params = deepFreeze({
|
|
3111
|
-
...instance.props || {}
|
|
3112
|
-
});
|
|
3113
|
-
const query = makeQuery(search);
|
|
3114
|
-
const matches = computeMatches(pathname);
|
|
3115
|
-
const snapshot = Object.freeze({
|
|
3116
|
-
path: pathname,
|
|
3117
|
-
params,
|
|
3118
|
-
query,
|
|
3119
|
-
hash: hash || null,
|
|
3120
|
-
matches: Object.freeze(matches)
|
|
3121
|
-
});
|
|
3122
|
-
return snapshot;
|
|
3123
|
-
}
|
|
3124
|
-
const currentInst = getCurrentComponentInstance();
|
|
3125
|
-
if (currentInst && currentInst.ssr) {
|
|
3126
|
-
throw new Error(
|
|
3127
|
-
"route() cannot be called during SSR rendering. Register routes at module load time instead."
|
|
3128
|
-
);
|
|
3129
|
-
}
|
|
3130
|
-
if (registrationLocked) {
|
|
3131
|
-
throw new Error(
|
|
3132
|
-
"Route registration is locked after app startup. Register routes at module load time before calling createSPA or createSSR."
|
|
3133
|
-
);
|
|
3134
|
-
}
|
|
3135
|
-
if (typeof handler !== "function") {
|
|
3136
|
-
throw new Error(
|
|
3137
|
-
"route(path, handler) requires a function handler that returns a VNode (e.g. () => <Page />). Passing JSX elements or VNodes directly is not supported."
|
|
3138
|
-
);
|
|
3139
|
-
}
|
|
3140
|
-
const routeObj = { path, handler, namespace };
|
|
3141
|
-
routes.push(routeObj);
|
|
3142
|
-
setHasRoutes(true);
|
|
3143
|
-
const depth = getDepth(path);
|
|
3144
|
-
let depthRoutes = routesByDepth.get(depth);
|
|
3145
|
-
if (!depthRoutes) {
|
|
3146
|
-
depthRoutes = [];
|
|
3147
|
-
routesByDepth.set(depth, depthRoutes);
|
|
3148
|
-
}
|
|
3149
|
-
depthRoutes.push(routeObj);
|
|
3150
|
-
if (namespace) {
|
|
3151
|
-
namespaces.add(namespace);
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
function getRoutes() {
|
|
3155
|
-
return [...routes];
|
|
3156
|
-
}
|
|
3157
|
-
function getNamespaceRoutes(namespace) {
|
|
3158
|
-
return routes.filter((r) => r.namespace === namespace);
|
|
3159
|
-
}
|
|
3160
|
-
function unloadNamespace(namespace) {
|
|
3161
|
-
const before = routes.length;
|
|
3162
|
-
for (let i = routes.length - 1; i >= 0; i--) {
|
|
3163
|
-
if (routes[i].namespace === namespace) {
|
|
3164
|
-
const removed = routes[i];
|
|
3165
|
-
routes.splice(i, 1);
|
|
3166
|
-
const depth = getDepth(removed.path);
|
|
3167
|
-
const depthRoutes = routesByDepth.get(depth);
|
|
3168
|
-
if (depthRoutes) {
|
|
3169
|
-
const idx = depthRoutes.indexOf(removed);
|
|
3170
|
-
if (idx >= 0) {
|
|
3171
|
-
depthRoutes.splice(idx, 1);
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
namespaces.delete(namespace);
|
|
3177
|
-
return before - routes.length;
|
|
3178
|
-
}
|
|
3179
|
-
function clearRoutes() {
|
|
3180
|
-
routes.length = 0;
|
|
3181
|
-
namespaces.clear();
|
|
3182
|
-
routesByDepth.clear();
|
|
3183
|
-
registrationLocked = false;
|
|
3184
|
-
setHasRoutes(false);
|
|
3185
|
-
}
|
|
3186
|
-
function normalizeHandler(handler) {
|
|
3187
|
-
if (handler == null) return void 0;
|
|
3188
|
-
if (typeof handler === "function") {
|
|
3189
|
-
return (params, ctx) => {
|
|
3190
|
-
try {
|
|
3191
|
-
return handler(params, ctx);
|
|
3192
|
-
} catch {
|
|
3193
|
-
return handler(params);
|
|
3194
|
-
}
|
|
3195
|
-
};
|
|
3196
|
-
}
|
|
3197
|
-
return void 0;
|
|
3198
|
-
}
|
|
3199
|
-
function registerRoute(path, handler, ...children) {
|
|
3200
|
-
const isRelative = !path.startsWith("/");
|
|
3201
|
-
const descriptor = {
|
|
3202
|
-
path,
|
|
3203
|
-
handler,
|
|
3204
|
-
children: children.filter(Boolean),
|
|
3205
|
-
_isDescriptor: true
|
|
3206
|
-
};
|
|
3207
|
-
if (!isRelative) {
|
|
3208
|
-
const normalized = normalizeHandler(handler);
|
|
3209
|
-
if (handler != null && !normalized) {
|
|
3210
|
-
throw new Error(
|
|
3211
|
-
"registerRoute(path, handler) requires a function handler. Passing JSX elements or VNodes directly is not supported."
|
|
3212
|
-
);
|
|
3213
|
-
}
|
|
3214
|
-
if (normalized) route(path, normalized);
|
|
3215
|
-
for (const child of descriptor.children || []) {
|
|
3216
|
-
const base = path === "/" ? "" : path.replace(/\/$/, "");
|
|
3217
|
-
const childPath = `${base}/${child.path.replace(/^\//, "")}`.replace(
|
|
3218
|
-
/\/\//g,
|
|
3219
|
-
"/"
|
|
3220
|
-
);
|
|
3221
|
-
if (child.handler) {
|
|
3222
|
-
const childNormalized = normalizeHandler(child.handler);
|
|
3223
|
-
if (!childNormalized) {
|
|
3224
|
-
throw new Error(
|
|
3225
|
-
"registerRoute child handler must be a function. Passing JSX elements directly is not supported."
|
|
3226
|
-
);
|
|
3227
|
-
}
|
|
3228
|
-
if (childNormalized) route(childPath, childNormalized);
|
|
3229
|
-
}
|
|
3230
|
-
if (child.children && child.children.length) {
|
|
3231
|
-
registerRoute(
|
|
3232
|
-
childPath,
|
|
3233
|
-
null,
|
|
3234
|
-
...child.children
|
|
3235
|
-
);
|
|
3236
|
-
}
|
|
3237
|
-
}
|
|
3238
|
-
return descriptor;
|
|
3239
|
-
}
|
|
3240
|
-
return descriptor;
|
|
3241
|
-
}
|
|
3242
|
-
function getLoadedNamespaces() {
|
|
3243
|
-
return Array.from(namespaces);
|
|
3244
|
-
}
|
|
3245
|
-
function resolveRoute(pathname) {
|
|
3246
|
-
const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
3247
|
-
const depth = normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
|
|
3248
|
-
const candidates = [];
|
|
3249
|
-
const depthRoutes = routesByDepth.get(depth);
|
|
3250
|
-
if (depthRoutes) {
|
|
3251
|
-
for (const r of depthRoutes) {
|
|
3252
|
-
const result = match(pathname, r.path);
|
|
3253
|
-
if (result.matched) {
|
|
3254
|
-
candidates.push({
|
|
3255
|
-
route: r,
|
|
3256
|
-
specificity: getSpecificity(r.path),
|
|
3257
|
-
params: result.params
|
|
3258
|
-
});
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
for (const r of routes) {
|
|
3263
|
-
if (depthRoutes?.includes(r)) continue;
|
|
3264
|
-
const result = match(pathname, r.path);
|
|
3265
|
-
if (result.matched) {
|
|
3266
|
-
candidates.push({
|
|
3267
|
-
route: r,
|
|
3268
|
-
specificity: getSpecificity(r.path),
|
|
3269
|
-
params: result.params
|
|
3270
|
-
});
|
|
3271
|
-
}
|
|
3272
|
-
}
|
|
3273
|
-
candidates.sort((a, b) => b.specificity - a.specificity);
|
|
3274
|
-
if (candidates.length > 0) {
|
|
3275
|
-
const best = candidates[0];
|
|
3276
|
-
return { handler: best.route.handler, params: best.params };
|
|
3277
|
-
}
|
|
3278
|
-
return null;
|
|
3279
|
-
}
|
|
3280
|
-
|
|
3281
|
-
// src/foundations/structures/portal.tsx
|
|
3282
|
-
function definePortal() {
|
|
3283
|
-
if (typeof createPortalSlot === "function") {
|
|
3284
|
-
let PortalHost2 = function() {
|
|
3285
|
-
return slot.read();
|
|
3286
|
-
};
|
|
3287
|
-
const slot = createPortalSlot();
|
|
3288
|
-
PortalHost2.render = function PortalRender(props) {
|
|
3289
|
-
slot.write(props.children);
|
|
3290
|
-
return null;
|
|
3291
|
-
};
|
|
3292
|
-
return PortalHost2;
|
|
3293
|
-
}
|
|
3294
|
-
let mounted = false;
|
|
3295
|
-
let value;
|
|
3296
|
-
function PortalHostFallback() {
|
|
3297
|
-
mounted = true;
|
|
3298
|
-
return value;
|
|
3299
|
-
}
|
|
3300
|
-
PortalHostFallback.render = function PortalRenderFallback(props) {
|
|
3301
|
-
if (!mounted) return null;
|
|
3302
|
-
value = props.children;
|
|
3303
|
-
return null;
|
|
3304
|
-
};
|
|
3305
|
-
return PortalHostFallback;
|
|
3306
|
-
}
|
|
3307
|
-
var _defaultPortal;
|
|
3308
|
-
function ensureDefaultPortal() {
|
|
3309
|
-
if (!_defaultPortal) _defaultPortal = definePortal();
|
|
3310
|
-
return _defaultPortal;
|
|
3311
|
-
}
|
|
3312
|
-
var DefaultPortal = (() => {
|
|
3313
|
-
function Host() {
|
|
3314
|
-
const v = ensureDefaultPortal()();
|
|
3315
|
-
return v === void 0 ? null : v;
|
|
3316
|
-
}
|
|
3317
|
-
Host.render = function Render(props) {
|
|
3318
|
-
ensureDefaultPortal().render(props);
|
|
3319
|
-
return null;
|
|
3320
|
-
};
|
|
3321
|
-
return Host;
|
|
3322
|
-
})();
|
|
3323
|
-
|
|
3324
|
-
// src/common/ssr-errors.ts
|
|
3325
|
-
var SSRDataMissingError = class _SSRDataMissingError extends Error {
|
|
3326
|
-
constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
|
|
3327
|
-
super(message);
|
|
3328
|
-
this.code = "SSR_DATA_MISSING";
|
|
3329
|
-
this.name = "SSRDataMissingError";
|
|
3330
|
-
Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
|
|
3331
|
-
}
|
|
3332
|
-
};
|
|
3333
|
-
function withSSRContext(ctx, fn) {
|
|
3334
|
-
try {
|
|
3335
|
-
return fn();
|
|
3336
|
-
} finally {
|
|
3337
|
-
}
|
|
3338
|
-
}
|
|
3339
|
-
function createRenderContext(seed = 12345) {
|
|
3340
|
-
return { seed };
|
|
3341
|
-
}
|
|
3342
|
-
function runWithSSRContext(ctx, fn) {
|
|
3343
|
-
try {
|
|
3344
|
-
return fn();
|
|
3345
|
-
} finally {
|
|
3346
|
-
}
|
|
3347
|
-
}
|
|
3348
|
-
function throwSSRDataMissing() {
|
|
3349
|
-
throw new SSRDataMissingError();
|
|
3350
|
-
}
|
|
3351
|
-
function startRenderPhase(data) {
|
|
3352
|
-
}
|
|
3353
|
-
var PREPASS_REMOVED_MSG = "SSR collection/prepass is removed: SSR is strictly synchronous";
|
|
3354
|
-
async function resolvePlan(_plan) {
|
|
3355
|
-
throw new Error(
|
|
3356
|
-
`${PREPASS_REMOVED_MSG}; async resource plans are not supported`
|
|
3357
|
-
);
|
|
3358
|
-
}
|
|
3359
|
-
function collectResources(_opts) {
|
|
3360
|
-
throw new Error(`${PREPASS_REMOVED_MSG}; collectResources is disabled`);
|
|
3361
|
-
}
|
|
3362
|
-
var resolveResources = resolvePlan;
|
|
3363
|
-
|
|
3364
|
-
// src/ssr/escape.ts
|
|
3365
|
-
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
3366
|
-
"area",
|
|
3367
|
-
"base",
|
|
3368
|
-
"br",
|
|
3369
|
-
"col",
|
|
3370
|
-
"embed",
|
|
3371
|
-
"hr",
|
|
3372
|
-
"img",
|
|
3373
|
-
"input",
|
|
3374
|
-
"link",
|
|
3375
|
-
"meta",
|
|
3376
|
-
"param",
|
|
3377
|
-
"source",
|
|
3378
|
-
"track",
|
|
3379
|
-
"wbr"
|
|
3380
|
-
]);
|
|
3381
|
-
var escapeCache = /* @__PURE__ */ new Map();
|
|
3382
|
-
var MAX_CACHE_SIZE = 256;
|
|
3383
|
-
var TEXT_ESCAPE_TEST_RE = /[&<>]/;
|
|
3384
|
-
var TEXT_ESCAPE_RE = /[&<>]/g;
|
|
3385
|
-
var ATTR_ESCAPE_TEST_RE = /[&"'<>]/;
|
|
3386
|
-
var ATTR_ESCAPE_RE = /[&"'<>]/g;
|
|
3387
|
-
var CSS_UNSAFE_TEST_RE = /[{}<>\\]/;
|
|
3388
|
-
var CSS_UNSAFE_RE = /[{}<>\\]/g;
|
|
3389
|
-
var CSS_DANGEROUS_FN_RE = /(?:url|expression|javascript)\s*\(/i;
|
|
3390
|
-
var STYLE_PROP_CACHE = /* @__PURE__ */ new Map();
|
|
3391
|
-
var MAX_STYLE_PROP_CACHE_SIZE = 512;
|
|
3392
|
-
function toKebabCached(prop) {
|
|
3393
|
-
const cached = STYLE_PROP_CACHE.get(prop);
|
|
3394
|
-
if (cached !== void 0) return cached;
|
|
3395
|
-
const kebab = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
3396
|
-
if (STYLE_PROP_CACHE.size < MAX_STYLE_PROP_CACHE_SIZE) {
|
|
3397
|
-
STYLE_PROP_CACHE.set(prop, kebab);
|
|
3398
|
-
}
|
|
3399
|
-
return kebab;
|
|
3400
|
-
}
|
|
3401
|
-
function mapTextEscape(ch) {
|
|
3402
|
-
switch (ch) {
|
|
3403
|
-
case "&":
|
|
3404
|
-
return "&";
|
|
3405
|
-
case "<":
|
|
3406
|
-
return "<";
|
|
3407
|
-
default:
|
|
3408
|
-
return ">";
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
function mapAttrEscape(ch) {
|
|
3412
|
-
switch (ch) {
|
|
3413
|
-
case "&":
|
|
3414
|
-
return "&";
|
|
3415
|
-
case '"':
|
|
3416
|
-
return """;
|
|
3417
|
-
case "'":
|
|
3418
|
-
return "'";
|
|
3419
|
-
case "<":
|
|
3420
|
-
return "<";
|
|
3421
|
-
default:
|
|
3422
|
-
return ">";
|
|
3423
|
-
}
|
|
3424
|
-
}
|
|
3425
|
-
function escapeText(text) {
|
|
3426
|
-
const useCache = text.length <= 64;
|
|
3427
|
-
if (useCache) {
|
|
3428
|
-
const cached = escapeCache.get(text);
|
|
3429
|
-
if (cached !== void 0) return cached;
|
|
3430
|
-
}
|
|
3431
|
-
const str = String(text);
|
|
3432
|
-
if (!TEXT_ESCAPE_TEST_RE.test(str)) {
|
|
3433
|
-
if (useCache && escapeCache.size < MAX_CACHE_SIZE) {
|
|
3434
|
-
escapeCache.set(text, str);
|
|
3435
|
-
}
|
|
3436
|
-
return str;
|
|
3437
|
-
}
|
|
3438
|
-
const result = str.replace(TEXT_ESCAPE_RE, mapTextEscape);
|
|
3439
|
-
if (useCache && escapeCache.size < MAX_CACHE_SIZE) {
|
|
3440
|
-
escapeCache.set(text, result);
|
|
3441
|
-
}
|
|
3442
|
-
return result;
|
|
3443
|
-
}
|
|
3444
|
-
function escapeAttr(value) {
|
|
3445
|
-
const str = String(value);
|
|
3446
|
-
if (!ATTR_ESCAPE_TEST_RE.test(str)) {
|
|
3447
|
-
return str;
|
|
3448
|
-
}
|
|
3449
|
-
return str.replace(ATTR_ESCAPE_RE, mapAttrEscape);
|
|
3450
|
-
}
|
|
3451
|
-
function escapeCssValue(value) {
|
|
3452
|
-
const str = String(value);
|
|
3453
|
-
const hasUnsafeChars = CSS_UNSAFE_TEST_RE.test(str);
|
|
3454
|
-
const openParen = str.indexOf("(");
|
|
3455
|
-
if (!hasUnsafeChars && openParen === -1) return str;
|
|
3456
|
-
if (openParen !== -1 && CSS_DANGEROUS_FN_RE.test(str)) {
|
|
3457
|
-
return "";
|
|
3458
|
-
}
|
|
3459
|
-
return hasUnsafeChars ? str.replace(CSS_UNSAFE_RE, "") : str;
|
|
3460
|
-
}
|
|
3461
|
-
function styleObjToCss(value) {
|
|
3462
|
-
if (!value || typeof value !== "object") return null;
|
|
3463
|
-
const entries = Object.entries(value);
|
|
3464
|
-
if (entries.length === 0) return "";
|
|
3465
|
-
let out = "";
|
|
3466
|
-
for (const [k, v] of entries) {
|
|
3467
|
-
if (v === null || v === void 0 || v === false) continue;
|
|
3468
|
-
const prop = toKebabCached(k);
|
|
3469
|
-
const safeValue = escapeCssValue(String(v));
|
|
3470
|
-
if (safeValue) {
|
|
3471
|
-
out += `${prop}:${safeValue};`;
|
|
3472
|
-
}
|
|
3473
|
-
}
|
|
3474
|
-
return out;
|
|
3475
|
-
}
|
|
3476
|
-
|
|
3477
|
-
// src/ssr/attrs.ts
|
|
3478
|
-
function renderAttrs(props, opts) {
|
|
3479
|
-
if (!props || typeof props !== "object") {
|
|
3480
|
-
return opts?.returnDangerousHtml ? { attrs: "" } : "";
|
|
3481
|
-
}
|
|
3482
|
-
let result = "";
|
|
3483
|
-
let dangerousHtml;
|
|
3484
|
-
for (const key in props) {
|
|
3485
|
-
if (!Object.prototype.hasOwnProperty.call(props, key)) continue;
|
|
3486
|
-
const value = props[key];
|
|
3487
|
-
if (key === "children") continue;
|
|
3488
|
-
if (key === "key" || key === "ref") continue;
|
|
3489
|
-
if (key === "dangerouslySetInnerHTML") {
|
|
3490
|
-
if (value && typeof value === "object" && "__html" in value) {
|
|
3491
|
-
dangerousHtml = String(value.__html);
|
|
3492
|
-
}
|
|
3493
|
-
continue;
|
|
3494
|
-
}
|
|
3495
|
-
if (key.length >= 3 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z") {
|
|
3496
|
-
continue;
|
|
3497
|
-
}
|
|
3498
|
-
if (key.startsWith("_")) continue;
|
|
3499
|
-
const attrName = key === "class" || key === "className" ? "class" : key;
|
|
3500
|
-
if (attrName === "style") {
|
|
3501
|
-
const css = typeof value === "string" ? value : styleObjToCss(value);
|
|
3502
|
-
if (css === null || css === "") continue;
|
|
3503
|
-
result += ` style="${escapeAttr(css)}"`;
|
|
3504
|
-
continue;
|
|
3505
|
-
}
|
|
3506
|
-
if (value === true) {
|
|
3507
|
-
result += ` ${attrName}`;
|
|
3508
|
-
} else if (value === false || value === null || value === void 0) {
|
|
3509
|
-
continue;
|
|
3510
|
-
} else {
|
|
3511
|
-
result += ` ${attrName}="${escapeAttr(String(value))}"`;
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
if (opts?.returnDangerousHtml) {
|
|
3515
|
-
return { attrs: result, dangerousHtml };
|
|
3516
|
-
}
|
|
3517
|
-
return result;
|
|
3518
|
-
}
|
|
3519
|
-
|
|
3520
|
-
// src/ssr/sink.ts
|
|
3521
|
-
var _StringSink = class _StringSink {
|
|
3522
|
-
constructor() {
|
|
3523
|
-
this.chunks = [];
|
|
3524
|
-
this.bufferChunks = [];
|
|
3525
|
-
this.bufferLen = 0;
|
|
3526
|
-
}
|
|
3527
|
-
write(html) {
|
|
3528
|
-
if (!html) return;
|
|
3529
|
-
this.bufferChunks.push(html);
|
|
3530
|
-
this.bufferLen += html.length;
|
|
3531
|
-
if (this.bufferLen >= _StringSink.FLUSH_THRESHOLD) {
|
|
3532
|
-
this.chunks.push(this.bufferChunks.join(""));
|
|
3533
|
-
this.bufferChunks.length = 0;
|
|
3534
|
-
this.bufferLen = 0;
|
|
3535
|
-
}
|
|
3536
|
-
}
|
|
3537
|
-
end() {
|
|
3538
|
-
if (this.bufferLen) {
|
|
3539
|
-
this.chunks.push(this.bufferChunks.join(""));
|
|
3540
|
-
this.bufferChunks.length = 0;
|
|
3541
|
-
this.bufferLen = 0;
|
|
3542
|
-
}
|
|
3543
|
-
}
|
|
3544
|
-
toString() {
|
|
3545
|
-
if (this.bufferLen) {
|
|
3546
|
-
this.chunks.push(this.bufferChunks.join(""));
|
|
3547
|
-
this.bufferChunks.length = 0;
|
|
3548
|
-
this.bufferLen = 0;
|
|
3549
|
-
}
|
|
3550
|
-
return this.chunks.join("");
|
|
3551
|
-
}
|
|
3552
|
-
};
|
|
3553
|
-
// Reduce array churn by batching many small writes into a larger buffer.
|
|
3554
|
-
// This is especially important for large SSR trees where we may write
|
|
3555
|
-
// hundreds of thousands of small fragments.
|
|
3556
|
-
_StringSink.FLUSH_THRESHOLD = 32 * 1024;
|
|
3557
|
-
var StringSink = _StringSink;
|
|
3558
|
-
var StreamSink = class {
|
|
3559
|
-
constructor(onChunk, onComplete) {
|
|
3560
|
-
this.onChunk = onChunk;
|
|
3561
|
-
this.onComplete = onComplete;
|
|
3562
|
-
}
|
|
3563
|
-
write(html) {
|
|
3564
|
-
if (html) this.onChunk(html);
|
|
3565
|
-
}
|
|
3566
|
-
end() {
|
|
3567
|
-
this.onComplete();
|
|
3568
|
-
}
|
|
3569
|
-
};
|
|
3570
|
-
|
|
3571
|
-
// src/ssr/stream-render.ts
|
|
3572
|
-
function isVNodeLike(x) {
|
|
3573
|
-
return !!x && typeof x === "object" && "type" in x;
|
|
3574
|
-
}
|
|
3575
|
-
function normalizeChildren(node) {
|
|
3576
|
-
const n = node;
|
|
3577
|
-
const direct = Array.isArray(n?.children) ? n?.children : null;
|
|
3578
|
-
const fromProps = n?.props?.children;
|
|
3579
|
-
const raw = direct ?? fromProps;
|
|
3580
|
-
if (raw === null || raw === void 0 || raw === false) return [];
|
|
3581
|
-
if (Array.isArray(raw)) return raw;
|
|
3582
|
-
return [raw];
|
|
3583
|
-
}
|
|
3584
|
-
function renderChildrenToSink(children, sink, ctx) {
|
|
3585
|
-
for (const c of children)
|
|
3586
|
-
renderNodeToSink(
|
|
3587
|
-
c,
|
|
3588
|
-
sink,
|
|
3589
|
-
ctx
|
|
3590
|
-
);
|
|
3591
|
-
}
|
|
3592
|
-
function isPromiseLike(x) {
|
|
3593
|
-
if (!x || typeof x !== "object") return false;
|
|
3594
|
-
const then = x.then;
|
|
3595
|
-
return typeof then === "function";
|
|
3596
|
-
}
|
|
3597
|
-
function executeComponent(type, props, ctx) {
|
|
3598
|
-
const res = type(props ?? {}, { signal: ctx.signal });
|
|
3599
|
-
if (isPromiseLike(res)) {
|
|
3600
|
-
throwSSRDataMissing();
|
|
3601
|
-
}
|
|
3602
|
-
return res;
|
|
3603
|
-
}
|
|
3604
|
-
function renderNodeToSink(node, sink, ctx) {
|
|
3605
|
-
if (node === null || node === void 0) return;
|
|
3606
|
-
if (typeof node === "string") {
|
|
3607
|
-
sink.write(escapeText(node));
|
|
3608
|
-
return;
|
|
3609
|
-
}
|
|
3610
|
-
if (typeof node === "number") {
|
|
3611
|
-
sink.write(escapeText(String(node)));
|
|
3612
|
-
return;
|
|
3613
|
-
}
|
|
3614
|
-
if (!isVNodeLike(node)) return;
|
|
3615
|
-
const { type, props } = node;
|
|
3616
|
-
if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
|
|
3617
|
-
const children = normalizeChildren(node);
|
|
3618
|
-
renderChildrenToSink(children, sink, ctx);
|
|
3619
|
-
return;
|
|
3620
|
-
}
|
|
3621
|
-
if (typeof type === "function") {
|
|
3622
|
-
const out = withSSRContext(
|
|
3623
|
-
ctx,
|
|
3624
|
-
() => executeComponent(type, props, ctx)
|
|
3625
|
-
);
|
|
3626
|
-
renderNodeToSink(
|
|
3627
|
-
out,
|
|
3628
|
-
sink,
|
|
3629
|
-
ctx
|
|
3630
|
-
);
|
|
3631
|
-
return;
|
|
3632
|
-
}
|
|
3633
|
-
const tag = String(type);
|
|
3634
|
-
const { attrs, dangerousHtml } = renderAttrs(props, {
|
|
3635
|
-
returnDangerousHtml: true
|
|
3636
|
-
});
|
|
3637
|
-
if (VOID_ELEMENTS.has(tag)) {
|
|
3638
|
-
sink.write(`<${tag}${attrs} />`);
|
|
3639
|
-
return;
|
|
3640
|
-
}
|
|
3641
|
-
sink.write(`<${tag}${attrs}>`);
|
|
3642
|
-
if (dangerousHtml !== void 0) {
|
|
3643
|
-
sink.write(dangerousHtml);
|
|
3644
|
-
} else {
|
|
3645
|
-
const children = normalizeChildren(node);
|
|
3646
|
-
renderChildrenToSink(children, sink, ctx);
|
|
3647
|
-
}
|
|
3648
|
-
sink.write(`</${tag}>`);
|
|
3649
|
-
}
|
|
3650
|
-
|
|
3651
|
-
// src/ssr/index.ts
|
|
3652
|
-
process.env.NODE_ENV !== "production" && (process.env.ASKR_SSR_DEBUG === "1" || process.env.ASKR_SSR_DEBUG === "true");
|
|
3653
|
-
var __ssrGuardStack = [];
|
|
3654
|
-
function pushSSRStrictPurityGuard() {
|
|
3655
|
-
if (process.env.NODE_ENV === "production") return;
|
|
3656
|
-
__ssrGuardStack.push({
|
|
3657
|
-
random: Reflect.get(Math, "random"),
|
|
3658
|
-
now: Reflect.get(Date, "now")
|
|
3659
|
-
});
|
|
3660
|
-
Reflect.set(Math, "random", () => {
|
|
3661
|
-
throw new Error(
|
|
3662
|
-
"SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
|
|
3663
|
-
);
|
|
3664
|
-
});
|
|
3665
|
-
Reflect.set(Date, "now", () => {
|
|
3666
|
-
throw new Error(
|
|
3667
|
-
"SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
|
|
3668
|
-
);
|
|
3669
|
-
});
|
|
3670
|
-
}
|
|
3671
|
-
function popSSRStrictPurityGuard() {
|
|
3672
|
-
if (process.env.NODE_ENV === "production") return;
|
|
3673
|
-
const prev = __ssrGuardStack.pop();
|
|
3674
|
-
if (prev) {
|
|
3675
|
-
Reflect.set(Math, "random", prev.random);
|
|
3676
|
-
Reflect.set(Date, "now", prev.now);
|
|
3677
|
-
}
|
|
3678
|
-
}
|
|
3679
|
-
function renderChildSyncToSink(child, sink, ctx) {
|
|
3680
|
-
if (child === null || child === void 0 || child === false) return;
|
|
3681
|
-
if (typeof child === "string") {
|
|
3682
|
-
sink.write(escapeText(child));
|
|
3683
|
-
return;
|
|
3684
|
-
}
|
|
3685
|
-
if (typeof child === "number") {
|
|
3686
|
-
sink.write(escapeText(String(child)));
|
|
3687
|
-
return;
|
|
3688
|
-
}
|
|
3689
|
-
if (child && typeof child === "object" && "type" in child) {
|
|
3690
|
-
renderNodeSyncToSink(child, sink, ctx);
|
|
3691
|
-
}
|
|
3692
|
-
}
|
|
3693
|
-
function renderChildrenSyncToSink(children, sink, ctx) {
|
|
3694
|
-
if (!children || !Array.isArray(children) || children.length === 0) return;
|
|
3695
|
-
for (let i = 0; i < children.length; i++) {
|
|
3696
|
-
renderChildSyncToSink(children[i], sink, ctx);
|
|
3697
|
-
}
|
|
3698
|
-
}
|
|
3699
|
-
function renderNodeSyncToSink(node, sink, ctx) {
|
|
3700
|
-
const { type, props } = node;
|
|
3701
|
-
if (typeof type === "function") {
|
|
3702
|
-
const result = executeComponentSync2(type, props, ctx);
|
|
3703
|
-
renderNodeSyncToSink(result, sink, ctx);
|
|
3704
|
-
return;
|
|
3705
|
-
}
|
|
3706
|
-
if (typeof type === "symbol") {
|
|
3707
|
-
if (type === Fragment) {
|
|
3708
|
-
const childrenArr = Array.isArray(node.children) ? node.children : Array.isArray(props?.children) ? props?.children : void 0;
|
|
3709
|
-
renderChildrenSyncToSink(childrenArr, sink, ctx);
|
|
3710
|
-
return;
|
|
3711
|
-
}
|
|
3712
|
-
throw new Error(
|
|
3713
|
-
`renderNodeSyncToSink: unsupported VNode symbol type: ${String(type)}`
|
|
3714
|
-
);
|
|
3715
|
-
}
|
|
3716
|
-
const typeStr = type;
|
|
3717
|
-
if (VOID_ELEMENTS.has(typeStr)) {
|
|
3718
|
-
const attrs2 = props ? renderAttrs(props) : "";
|
|
3719
|
-
sink.write(`<${typeStr}${attrs2} />`);
|
|
3720
|
-
return;
|
|
3721
|
-
}
|
|
3722
|
-
const maybeDangerous = props ? props?.dangerouslySetInnerHTML : void 0;
|
|
3723
|
-
if (maybeDangerous !== void 0 && maybeDangerous !== null) {
|
|
3724
|
-
const { attrs: attrs2, dangerousHtml } = renderAttrs(props, {
|
|
3725
|
-
returnDangerousHtml: true
|
|
3726
|
-
});
|
|
3727
|
-
sink.write(`<${typeStr}${attrs2}>`);
|
|
3728
|
-
if (dangerousHtml !== void 0) {
|
|
3729
|
-
sink.write(dangerousHtml);
|
|
3730
|
-
} else {
|
|
3731
|
-
renderChildrenSyncToSink(node.children, sink, ctx);
|
|
3732
|
-
}
|
|
3733
|
-
sink.write(`</${typeStr}>`);
|
|
3734
|
-
return;
|
|
3735
|
-
}
|
|
3736
|
-
const attrs = props ? renderAttrs(props) : "";
|
|
3737
|
-
let children = node.children;
|
|
3738
|
-
if (children === void 0 && props?.children !== void 0) {
|
|
3739
|
-
const propsChildren = props.children;
|
|
3740
|
-
if (Array.isArray(propsChildren)) {
|
|
3741
|
-
children = propsChildren;
|
|
3742
|
-
} else if (propsChildren !== null && propsChildren !== false) {
|
|
3743
|
-
children = [propsChildren];
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
if (Array.isArray(children) && children.length === 1) {
|
|
3747
|
-
const only = children[0];
|
|
3748
|
-
if (typeof only === "string") {
|
|
3749
|
-
sink.write(`<${typeStr}${attrs}>${escapeText(only)}</${typeStr}>`);
|
|
3750
|
-
return;
|
|
3751
|
-
}
|
|
3752
|
-
if (typeof only === "number") {
|
|
3753
|
-
const escaped = escapeText(String(only));
|
|
3754
|
-
sink.write(`<${typeStr}${attrs}>${escaped}</${typeStr}>`);
|
|
3755
|
-
return;
|
|
3756
|
-
}
|
|
3757
|
-
}
|
|
3758
|
-
sink.write(`<${typeStr}${attrs}>`);
|
|
3759
|
-
renderChildrenSyncToSink(children, sink, ctx);
|
|
3760
|
-
sink.write(`</${typeStr}>`);
|
|
3761
|
-
}
|
|
3762
|
-
function executeComponentSync2(component, props, ctx) {
|
|
3763
|
-
try {
|
|
3764
|
-
if (process.env.NODE_ENV !== "production") {
|
|
3765
|
-
pushSSRStrictPurityGuard();
|
|
3766
|
-
}
|
|
3767
|
-
const prev = getCurrentComponentInstance();
|
|
3768
|
-
const temp = createComponentInstance(
|
|
3769
|
-
"ssr-temp",
|
|
3770
|
-
component,
|
|
3771
|
-
props || {},
|
|
3772
|
-
null
|
|
3773
|
-
);
|
|
3774
|
-
temp.ssr = true;
|
|
3775
|
-
setCurrentComponentInstance(temp);
|
|
3776
|
-
try {
|
|
3777
|
-
return runWithSSRContext(ctx, () => {
|
|
3778
|
-
const result = component(props || {}, { ssr: ctx });
|
|
3779
|
-
if (result instanceof Promise) {
|
|
3780
|
-
throwSSRDataMissing();
|
|
3781
|
-
}
|
|
3782
|
-
if (typeof result === "string" || typeof result === "number" || typeof result === "boolean" || result === null || result === void 0) {
|
|
3783
|
-
const inner = result === null || result === void 0 || result === false ? "" : String(result);
|
|
3784
|
-
return {
|
|
3785
|
-
$$typeof: ELEMENT_TYPE,
|
|
3786
|
-
type: Fragment,
|
|
3787
|
-
props: { children: inner ? [inner] : [] }
|
|
3788
|
-
};
|
|
3789
|
-
}
|
|
3790
|
-
return result;
|
|
3791
|
-
});
|
|
3792
|
-
} finally {
|
|
3793
|
-
setCurrentComponentInstance(prev);
|
|
3794
|
-
}
|
|
3795
|
-
} finally {
|
|
3796
|
-
if (process.env.NODE_ENV !== "production") popSSRStrictPurityGuard();
|
|
3797
|
-
}
|
|
3798
|
-
}
|
|
3799
|
-
function renderToStringSync(component, props, options) {
|
|
3800
|
-
const seed = options?.seed ?? 12345;
|
|
3801
|
-
const ctx = createRenderContext(seed);
|
|
3802
|
-
startRenderPhase(options?.data ?? null);
|
|
3803
|
-
try {
|
|
3804
|
-
const wrapped = (p, c) => {
|
|
3805
|
-
const out = component(p ?? {}, c);
|
|
3806
|
-
const portalVNode = {
|
|
3807
|
-
$$typeof: ELEMENT_TYPE,
|
|
3808
|
-
type: DefaultPortal,
|
|
3809
|
-
props: {},
|
|
3810
|
-
key: "__default_portal"
|
|
3811
|
-
};
|
|
3812
|
-
if (out == null) {
|
|
3813
|
-
return {
|
|
3814
|
-
$$typeof: ELEMENT_TYPE,
|
|
3815
|
-
type: Fragment,
|
|
3816
|
-
props: { children: [portalVNode] }
|
|
3817
|
-
};
|
|
3818
|
-
}
|
|
3819
|
-
return {
|
|
3820
|
-
$$typeof: ELEMENT_TYPE,
|
|
3821
|
-
type: Fragment,
|
|
3822
|
-
props: { children: [out, portalVNode] }
|
|
3823
|
-
};
|
|
3824
|
-
};
|
|
3825
|
-
const node = executeComponentSync2(wrapped, props || {}, ctx);
|
|
3826
|
-
if (!node) {
|
|
3827
|
-
throw new Error("renderToStringSync: wrapped component returned empty");
|
|
3828
|
-
}
|
|
3829
|
-
const sink = new StringSink();
|
|
3830
|
-
renderNodeSyncToSink(node, sink, ctx);
|
|
3831
|
-
sink.end();
|
|
3832
|
-
return sink.toString();
|
|
3833
|
-
} finally {
|
|
3834
|
-
}
|
|
3835
|
-
}
|
|
3836
|
-
function renderToStringSyncForUrl(opts) {
|
|
3837
|
-
const { url, routes: routes2, options } = opts;
|
|
3838
|
-
const {
|
|
3839
|
-
clearRoutes: clearRoutes2,
|
|
3840
|
-
route: route2,
|
|
3841
|
-
setServerLocation: setServerLocation2,
|
|
3842
|
-
lockRouteRegistration: lockRouteRegistration2,
|
|
3843
|
-
resolveRoute: resolveRoute2
|
|
3844
|
-
} = route_exports;
|
|
3845
|
-
clearRoutes2();
|
|
3846
|
-
for (const r of routes2) {
|
|
3847
|
-
route2(r.path, r.handler, r.namespace);
|
|
3848
|
-
}
|
|
3849
|
-
setServerLocation2(url);
|
|
3850
|
-
if (process.env.NODE_ENV === "production") lockRouteRegistration2();
|
|
3851
|
-
const resolved = resolveRoute2(url);
|
|
3852
|
-
if (!resolved)
|
|
3853
|
-
throw new Error(`renderToStringSync: no route found for url: ${url}`);
|
|
3854
|
-
const seed = options?.seed ?? 12345;
|
|
3855
|
-
const ctx = createRenderContext(seed);
|
|
3856
|
-
startRenderPhase(options?.data ?? null);
|
|
3857
|
-
try {
|
|
3858
|
-
const wrapped = (p, c) => {
|
|
3859
|
-
const out = resolved.handler(p ?? {}, c);
|
|
3860
|
-
const portalVNode = {
|
|
3861
|
-
$$typeof: ELEMENT_TYPE,
|
|
3862
|
-
type: DefaultPortal,
|
|
3863
|
-
props: {},
|
|
3864
|
-
key: "__default_portal"
|
|
3865
|
-
};
|
|
3866
|
-
if (out == null) {
|
|
3867
|
-
return {
|
|
3868
|
-
$$typeof: ELEMENT_TYPE,
|
|
3869
|
-
type: Fragment,
|
|
3870
|
-
props: { children: [portalVNode] }
|
|
3871
|
-
};
|
|
3872
|
-
}
|
|
3873
|
-
return {
|
|
3874
|
-
$$typeof: ELEMENT_TYPE,
|
|
3875
|
-
type: Fragment,
|
|
3876
|
-
props: { children: [out, portalVNode] }
|
|
3877
|
-
};
|
|
3878
|
-
};
|
|
3879
|
-
const node = executeComponentSync2(wrapped, resolved.params || {}, ctx);
|
|
3880
|
-
const sink = new StringSink();
|
|
3881
|
-
renderNodeSyncToSink(node, sink, ctx);
|
|
3882
|
-
sink.end();
|
|
3883
|
-
return sink.toString();
|
|
3884
|
-
} finally {
|
|
3885
|
-
}
|
|
3886
|
-
}
|
|
3887
|
-
function renderToString(arg) {
|
|
3888
|
-
if (typeof arg === "function") {
|
|
3889
|
-
return renderToStringSync(
|
|
3890
|
-
arg
|
|
3891
|
-
);
|
|
3892
|
-
}
|
|
3893
|
-
const opts = arg;
|
|
3894
|
-
const sink = new StringSink();
|
|
3895
|
-
renderToSinkInternal({ ...opts, sink });
|
|
3896
|
-
sink.end();
|
|
3897
|
-
return sink.toString();
|
|
3898
|
-
}
|
|
3899
|
-
function renderToStream(opts) {
|
|
3900
|
-
const sink = new StreamSink(opts.onChunk, opts.onComplete);
|
|
3901
|
-
renderToSinkInternal({ ...opts, sink });
|
|
3902
|
-
sink.end();
|
|
3903
|
-
}
|
|
3904
|
-
function renderToSinkInternal(opts) {
|
|
3905
|
-
const { url, routes: routes2, seed = 12345, data, sink } = opts;
|
|
3906
|
-
const {
|
|
3907
|
-
clearRoutes: clearRoutes2,
|
|
3908
|
-
route: route2,
|
|
3909
|
-
setServerLocation: setServerLocation2,
|
|
3910
|
-
lockRouteRegistration: lockRouteRegistration2,
|
|
3911
|
-
resolveRoute: resolveRoute2
|
|
3912
|
-
} = route_exports;
|
|
3913
|
-
clearRoutes2();
|
|
3914
|
-
for (const r of routes2) route2(r.path, r.handler, r.namespace);
|
|
3915
|
-
setServerLocation2(url);
|
|
3916
|
-
if (process.env.NODE_ENV === "production") lockRouteRegistration2();
|
|
3917
|
-
const resolved = resolveRoute2(url);
|
|
3918
|
-
if (!resolved) throw new Error(`SSR: no route found for url: ${url}`);
|
|
3919
|
-
const ctx = {
|
|
3920
|
-
url,
|
|
3921
|
-
seed,
|
|
3922
|
-
data,
|
|
3923
|
-
params: resolved.params,
|
|
3924
|
-
signal: void 0
|
|
3925
|
-
};
|
|
3926
|
-
const node = resolved.handler(resolved.params);
|
|
3927
|
-
try {
|
|
3928
|
-
renderNodeToSink(node, sink, ctx);
|
|
3929
|
-
} finally {
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
|
|
3933
|
-
export { SSRDataMissingError, collectResources, popSSRStrictPurityGuard, pushSSRStrictPurityGuard, renderToStream, renderToString, renderToStringSync, renderToStringSyncForUrl, resolvePlan, resolveResources };
|
|
3934
|
-
//# sourceMappingURL=index.js.map
|
|
3935
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import {d}from'../chunk-4RTKQ7SC.js';import {b as b$1,a}from'../chunk-YRY4OLQF.js';export{a as SSRDataMissingError}from'../chunk-YRY4OLQF.js';import {m}from'../chunk-XKFPM4SY.js';import'../chunk-D2JSJKCW.js';import {j as j$1,i,k as k$1}from'../chunk-534P7OMI.js';import'../chunk-JJDSOK6C.js';import'../chunk-OQMK7H2R.js';import {a as a$1,b as b$2}from'../chunk-37RC6ZT3.js';import'../chunk-62D2TNHX.js';function K(n,e){try{return e()}finally{}}function H(n=12345){return {seed:n}}var E=null;function z(){return E}function B(n,e){let t=E;E=n;try{return e()}finally{E=t;}}function h(){throw new a}var Z=0,L=null;function W(){return L}function Y(){Z=0;}function q(){return `r:${Z++}`}function k(n){L=n??null,Y();}function x(){L=null,Y();}var Q="SSR collection/prepass is removed: SSR is strictly synchronous";async function nn(n){throw new Error(`${Q}; async resource plans are not supported`)}function pn(n){throw new Error(`${Q}; collectResources is disabled`)}var ln=nn;var b=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),w=new Map,en=256,fn=/[&<>]/,dn=/[&<>]/g,Sn=/[&"'<>]/,mn=/[&"'<>]/g,gn=/[{}<>\\]/,yn=/[{}<>\\]/g,Rn=/(?:url|expression|javascript)\s*\(/i,M=new Map,hn=512;function wn(n){let e=M.get(n);if(e!==void 0)return e;let t=n.replace(/[A-Z]/g,s=>`-${s.toLowerCase()}`);return M.size<hn&&M.set(n,t),t}function Cn(n){switch(n){case "&":return "&";case "<":return "<";default:return ">"}}function En(n){switch(n){case "&":return "&";case '"':return """;case "'":return "'";case "<":return "<";default:return ">"}}function S(n){let e=n.length<=64;if(e){let r=w.get(n);if(r!==void 0)return r}let t=String(n);if(!fn.test(t))return e&&w.size<en&&w.set(n,t),t;let s=t.replace(dn,Cn);return e&&w.size<en&&w.set(n,s),s}function O(n){let e=String(n);return Sn.test(e)?e.replace(mn,En):e}function kn(n){let e=String(n),t=gn.test(e),s=e.indexOf("(");return !t&&s===-1?e:s!==-1&&Rn.test(e)?"":t?e.replace(yn,""):e}function tn(n){if(!n||typeof n!="object")return null;let e=Object.entries(n);if(e.length===0)return "";let t="";for(let[s,r]of e){if(r==null||r===false)continue;let o=wn(s),u=kn(String(r));u&&(t+=`${o}:${u};`);}return t}function y(n,e){if(!n||typeof n!="object")return e?.returnDangerousHtml?{attrs:""}:"";let t="",s;for(let r in n){if(!Object.prototype.hasOwnProperty.call(n,r))continue;let o=n[r];if(r==="children"||r==="key"||r==="ref")continue;if(r==="dangerouslySetInnerHTML"){o&&typeof o=="object"&&"__html"in o&&(s=String(o.__html));continue}if(r.length>=3&&r[0]==="o"&&r[1]==="n"&&r[2]>="A"&&r[2]<="Z"||r.startsWith("_"))continue;let u=r==="class"||r==="className"?"class":r;if(u==="style"){let c=typeof o=="string"?o:tn(o);if(c===null||c==="")continue;t+=` style="${O(c)}"`;continue}if(o===true)t+=` ${u}`;else {if(o===false||o===null||o===void 0)continue;t+=` ${u}="${O(String(o))}"`;}}return e?.returnDangerousHtml?{attrs:t,dangerousHtml:s}:t}var _=class _{constructor(){this.chunks=[];this.bufferChunks=[];this.bufferLen=0;}write(e){e&&(this.bufferChunks.push(e),this.bufferLen+=e.length,this.bufferLen>=_.FLUSH_THRESHOLD&&(this.chunks.push(this.bufferChunks.join("")),this.bufferChunks.length=0,this.bufferLen=0));}end(){this.bufferLen&&(this.chunks.push(this.bufferChunks.join("")),this.bufferChunks.length=0,this.bufferLen=0);}toString(){return this.bufferLen&&(this.chunks.push(this.bufferChunks.join("")),this.bufferChunks.length=0,this.bufferLen=0),this.chunks.join("")}};_.FLUSH_THRESHOLD=32*1024;var R=_,N=class{constructor(e,t){this.onChunk=e;this.onComplete=t;}write(e){e&&this.onChunk(e);}end(){this.onComplete();}};function xn(n){return !!n&&typeof n=="object"&&"type"in n}function rn(n){let e=n,t=Array.isArray(e?.children)?e?.children:null,s=e?.props?.children,r=t??s;return r==null||r===false?[]:Array.isArray(r)?r:[r]}function on(n,e,t){for(let s of n)$(s,e,t);}function bn(n){return !n||typeof n!="object"?false:typeof n.then=="function"}function Nn(n,e,t){let s=n(e??{},{signal:t.signal});return bn(s)&&h(),s}function $(n,e,t){if(n==null)return;if(typeof n=="string"){e.write(S(n));return}if(typeof n=="number"){e.write(S(String(n)));return}if(!xn(n))return;let{type:s,props:r}=n;if(typeof s=="symbol"&&(s===b$2||String(s)==="Symbol(Fragment)")){let a=rn(n);on(a,e,t);return}if(typeof s=="function"){let a=K(t,()=>Nn(s,r,t));$(a,e,t);return}let o=String(s),{attrs:u,dangerousHtml:c}=y(r,{returnDangerousHtml:true});if(b.has(o)){e.write(`<${o}${u} />`);return}if(e.write(`<${o}${u}>`),c!==void 0)e.write(c);else {let a=rn(n);on(a,e,t);}e.write(`</${o}>`);}process.env.NODE_ENV!=="production"&&(process.env.ASKR_SSR_DEBUG==="1"||process.env.ASKR_SSR_DEBUG==="true");b$1({getCurrentSSRContext:z,throwSSRDataMissing:h,getCurrentRenderData:W,getNextKey:q});var sn=[];function _n(){process.env.NODE_ENV!=="production"&&(sn.push({random:Reflect.get(Math,"random"),now:Reflect.get(Date,"now")}),Reflect.set(Math,"random",()=>{throw new Error("SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.")}),Reflect.set(Date,"now",()=>{throw new Error("SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.")}));}function $n(){if(process.env.NODE_ENV==="production")return;let n=sn.pop();n&&(Reflect.set(Math,"random",n.random),Reflect.set(Date,"now",n.now));}function An(n,e,t){if(!(n==null||n===false)){if(typeof n=="string"){e.write(S(n));return}if(typeof n=="number"){e.write(S(String(n)));return}n&&typeof n=="object"&&"type"in n&&A(n,e,t);}}function X(n,e,t){if(!(!n||!Array.isArray(n)||n.length===0))for(let s=0;s<n.length;s++)An(n[s],e,t);}function A(n,e,t){let{type:s,props:r}=n;if(typeof s=="function"){let i=j(s,r,t);A(i,e,t);return}if(typeof s=="symbol"){if(s===b$2){let i=Array.isArray(n.children)?n.children:Array.isArray(r?.children)?r?.children:void 0;X(i,e,t);return}throw new Error(`renderNodeSyncToSink: unsupported VNode symbol type: ${String(s)}`)}let o=s;if(b.has(o)){let i=r?y(r):"";e.write(`<${o}${i} />`);return}let u=r?r?.dangerouslySetInnerHTML:void 0;if(u!=null){let{attrs:i,dangerousHtml:p}=y(r,{returnDangerousHtml:true});e.write(`<${o}${i}>`),p!==void 0?e.write(p):X(n.children,e,t),e.write(`</${o}>`);return}let c=r?y(r):"",a=n.children;if(a===void 0&&r?.children!==void 0){let i=r.children;Array.isArray(i)?a=i:i!==null&&i!==false&&(a=[i]);}if(Array.isArray(a)&&a.length===1){let i=a[0];if(typeof i=="string"){e.write(`<${o}${c}>${S(i)}</${o}>`);return}if(typeof i=="number"){let p=S(String(i));e.write(`<${o}${c}>${p}</${o}>`);return}}e.write(`<${o}${c}>`),X(a,e,t),e.write(`</${o}>`);}function j(n,e,t){try{process.env.NODE_ENV!=="production"&&_n();let s=j$1(),r=i("ssr-temp",n,e||{},null);r.ssr=!0,k$1(r);try{return B(t,()=>{let o=n(e||{},{ssr:t});if(o instanceof Promise&&h(),typeof o=="string"||typeof o=="number"||typeof o=="boolean"||o===null||o===void 0){let u=o==null||o===!1?"":String(o);return {$$typeof:a$1,type:b$2,props:{children:u?[u]:[]}}}return o})}finally{k$1(s);}}finally{process.env.NODE_ENV!=="production"&&$n();}}function Tn(n,e,t){let s=t?.seed??12345,r=H(s);k(t?.data??null);try{let u=j((a,i)=>{let p=n(a??{},i),l={$$typeof:a$1,type:d,props:{},key:"__default_portal"};return p==null?{$$typeof:a$1,type:b$2,props:{children:[l]}}:{$$typeof:a$1,type:b$2,props:{children:[p,l]}}},e||{},r);if(!u)throw new Error("renderToStringSync: wrapped component returned empty");let c=new R;return A(u,c,r),c.end(),c.toString()}finally{x();}}function ne(n){let{url:e,routes:t,options:s}=n,{clearRoutes:r,route:o,setServerLocation:u,lockRouteRegistration:c,resolveRoute:a}=m;r();for(let g of t)o(g.path,g.handler,g.namespace);u(e),process.env.NODE_ENV==="production"&&c();let i=a(e);if(!i)throw new Error(`renderToStringSync: no route found for url: ${e}`);let p=s?.seed??12345,l=H(p);k(s?.data??null);try{let T=j((an,cn)=>{let I=i.handler(an??{},cn),J={$$typeof:a$1,type:d,props:{},key:"__default_portal"};return I==null?{$$typeof:a$1,type:b$2,props:{children:[J]}}:{$$typeof:a$1,type:b$2,props:{children:[I,J]}}},i.params||{},l),m=new R;return A(T,m,l),m.end(),m.toString()}finally{x();}}function oe(n){if(typeof n=="function")return Tn(n);let e=n,t=new R;return un({...e,sink:t}),t.end(),t.toString()}function se(n){let e=new N(n.onChunk,n.onComplete);un({...n,sink:e}),e.end();}function un(n){let{url:e,routes:t,seed:s=12345,data:r,sink:o}=n,{clearRoutes:u,route:c,setServerLocation:a,lockRouteRegistration:i,resolveRoute:p}=m;u();for(let m of t)c(m.path,m.handler,m.namespace);a(e),process.env.NODE_ENV==="production"&&i();let l=p(e);if(!l)throw new Error(`SSR: no route found for url: ${e}`);let g={url:e,seed:s,data:r,params:l.params,signal:void 0},T=l.handler(l.params);k(r||null);try{$(T,o,g);}finally{x();}}export{pn as collectResources,$n as popSSRStrictPurityGuard,_n as pushSSRStrictPurityGuard,se as renderToStream,oe as renderToString,Tn as renderToStringSync,ne as renderToStringSyncForUrl,nn as resolvePlan,ln as resolveResources};
|