@qwik.dev/core 2.0.0-beta.23 → 2.0.0-beta.24

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/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.23-dev+03de42d
3
+ * @qwik.dev/core 2.0.0-beta.24-dev+314726b
4
4
  * Copyright QwikDev. All Rights Reserved.
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
@@ -9,13 +9,6 @@ import { isDev, isServer, isBrowser } from '@qwik.dev/core/build';
9
9
  export { isBrowser, isDev, isServer } from '@qwik.dev/core/build';
10
10
  import { p } from '@qwik.dev/core/preloader';
11
11
 
12
- /**
13
- * QWIK_VERSION
14
- *
15
- * @public
16
- */
17
- const version = "2.0.0-beta.23-dev+03de42d";
18
-
19
12
  // same as isDev but separate so we can test
20
13
  const qDev = globalThis.qDev !== false;
21
14
  const qInspector = globalThis.qInspector === true;
@@ -79,6 +72,102 @@ const createAndLogError = (asyncThrow, message, ...optionalParams) => {
79
72
  return err;
80
73
  };
81
74
 
75
+ const ASSERT_DISCLAIMER = 'Internal assert, this is likely caused by a bug in Qwik: ';
76
+ /*@__INLINE__*/
77
+ function assertDefined(value, text, ...parts) {
78
+ if (isDev) {
79
+ if (value != null) {
80
+ return;
81
+ }
82
+ throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
83
+ }
84
+ }
85
+ /*@__INLINE__*/
86
+ function assertEqual(value1, value2, text, ...parts) {
87
+ if (isDev) {
88
+ if (value1 === value2) {
89
+ return;
90
+ }
91
+ throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
92
+ }
93
+ }
94
+ /*@__INLINE__*/
95
+ function assertTrue(value1, text, ...parts) {
96
+ if (isDev) {
97
+ if (value1 === true) {
98
+ return;
99
+ }
100
+ throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
101
+ }
102
+ }
103
+ /*@__INLINE__*/
104
+ function assertFalse(value1, text, ...parts) {
105
+ if (isDev) {
106
+ if (value1 === false) {
107
+ return;
108
+ }
109
+ throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
110
+ }
111
+ }
112
+ /*@__INLINE__*/
113
+ function assertNumber(value1, text, ...parts) {
114
+ if (isDev) {
115
+ if (typeof value1 === 'number') {
116
+ return;
117
+ }
118
+ throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
119
+ }
120
+ }
121
+
122
+ /** @internal */
123
+ const mapApp_findIndx = (array, key, start) => {
124
+ isDev && assertTrue(start % 2 === 0, 'Expecting even number.');
125
+ let bottom = start >> 1;
126
+ let top = (array.length - 2) >> 1;
127
+ while (bottom <= top) {
128
+ const mid = bottom + ((top - bottom) >> 1);
129
+ const midKey = array[mid << 1];
130
+ if (midKey === key) {
131
+ return mid << 1;
132
+ }
133
+ if (midKey < key) {
134
+ bottom = mid + 1;
135
+ }
136
+ else {
137
+ top = mid - 1;
138
+ }
139
+ }
140
+ return (bottom << 1) ^ -1;
141
+ };
142
+ /** @internal */
143
+ const mapArray_set = (array, key, value, start, allowNullValue = false) => {
144
+ const indx = mapApp_findIndx(array, key, start);
145
+ if (indx >= 0) {
146
+ if (value == null && !allowNullValue) {
147
+ array.splice(indx, 2);
148
+ }
149
+ else {
150
+ array[indx + 1] = value;
151
+ }
152
+ }
153
+ else if (value != null || allowNullValue) {
154
+ array.splice(indx ^ -1, 0, key, value);
155
+ }
156
+ };
157
+ /** @internal */
158
+ const mapArray_get = (array, key, start) => {
159
+ const indx = mapApp_findIndx(array, key, start);
160
+ if (indx >= 0) {
161
+ return array[indx + 1];
162
+ }
163
+ else {
164
+ return null;
165
+ }
166
+ };
167
+ const mapArray_has = (array, key, start) => {
168
+ return mapApp_findIndx(array, key, start) >= 0;
169
+ };
170
+
82
171
  /** @private */
83
172
  const isSerializableObject = (v) => {
84
173
  const proto = Object.getPrototypeOf(v);
@@ -134,7 +223,7 @@ const codeToText = (code, ...parts) => {
134
223
  'Materialize error: missing element: {{0}} {{1}} {{2}}', // 27
135
224
  'Cannot coerce a Signal, use `.value` instead', // 28
136
225
  'useComputed$ QRL {{0}} {{1}} cannot return a Promise', // 29
137
- 'ComputedSignal is read-only', // 30
226
+ '===\nQwik version {{0}} already imported while importing {{1}}.\nThis can lead to issues due to duplicated shared structures.\nVerify that the Qwik libraries you\'re using are in "resolve.noExternal[]" and in "optimizeDeps.exclude".\n===\n', // 30
138
227
  'WrappedSignal is read-only', // 31
139
228
  'Attribute value is unsafe for SSR {{0}}', // 32
140
229
  'SerializerSymbol function returned rejected promise', // 33
@@ -154,7 +243,8 @@ const codeToText = (code, ...parts) => {
154
243
  }
155
244
  else {
156
245
  // cute little hack to give roughly the correct line number. Update the line number if it shifts.
157
- return `Code(Q${code}) https://github.com/QwikDev/qwik/blob/main/packages/qwik/src/core/error/error.ts#L${8 + code}`;
246
+ // TODO change the URL after merging into main
247
+ return `Code(Q${code}) https://github.com/QwikDev/qwik/blob/build/v2/packages/qwik/src/core/shared/error/error.ts#${parts.join()}L${9 + code}`;
158
248
  }
159
249
  };
160
250
  const qError = (code, errorMessageArgs = []) => {
@@ -186,6 +276,112 @@ const getSymbolHash = (symbolName) => {
186
276
  return symbolName;
187
277
  };
188
278
 
279
+ /**
280
+ * A friendly name tag for a VirtualVNode.
281
+ *
282
+ * Theses are used to give a name to a VirtualVNode. This is useful for debugging and testing.
283
+ *
284
+ * The name is only added in development mode and is not included in production builds.
285
+ */
286
+ const DEBUG_TYPE = 'q:type';
287
+ const VirtualTypeName = {
288
+ ["V" /* VirtualType.Virtual */]: /* ********* */ 'Virtual', //
289
+ ["F" /* VirtualType.Fragment */]: /* ******** */ 'Fragment', //
290
+ ["S" /* VirtualType.WrappedSignal */]: /* *** */ 'Signal', //
291
+ ["A" /* VirtualType.Awaited */]: /* ********* */ 'Awaited', //
292
+ ["C" /* VirtualType.Component */]: /* ******* */ 'Component', //
293
+ ["I" /* VirtualType.InlineComponent */]: /* * */ 'InlineComponent', //
294
+ ["P" /* VirtualType.Projection */]: /* ****** */ 'Projection', //
295
+ };
296
+
297
+ /**
298
+ * @file
299
+ *
300
+ * VNodeData is additional information which allows the `vnode` to recover virtual VNode information
301
+ * from the HTML.
302
+ */
303
+ /**
304
+ * VNodeDataSeparator contains information about splitting up the VNodeData and attaching it to the
305
+ * HTML.
306
+ */
307
+ const VNodeDataSeparator = {
308
+ REFERENCE: /* ******** */ 126, // `~` is a reference to the node. Save it.
309
+ ADVANCE_1: /* ********* */ 33, // `!` is vNodeData separator skipping 0. (ie next vNode)
310
+ ADVANCE_8192: /* ****** */ 46, // `.` is vNodeData separator skipping 4096.
311
+ };
312
+ /**
313
+ * VNodeDataChar contains information about the VNodeData used for encoding props.
314
+ *
315
+ * Available character ranges: 59 - 64, 91 - 94, 96, 123 - 126
316
+ */
317
+ const VNodeDataChar = {
318
+ OPEN: /* ************** */ 123, // `{` is the start of the VNodeData for a virtual element.
319
+ CLOSE: /* ************* */ 125, // `}` is the end of the VNodeData for a virtual element.
320
+ SCOPED_STYLE: /* ******* */ 59, // `;` - `q:sstyle` - Style attribute.
321
+ RENDER_FN: /* ********** */ 60, // `<` - `q:renderFn' - Component QRL render function (body)
322
+ ID: /* ***************** */ 61, // `=` - `q:id` - ID of the element.
323
+ PROPS: /* ************** */ 62, // `>` - `q:props' - Component Props
324
+ SLOT_PARENT: /* ******** */ 63, // `?` - `q:sparent` - Slot parent.
325
+ KEY: /* **************** */ 64, // `@` - `q:key` - Element key.
326
+ SEQ: /* **************** */ 91, // `[` - `q:seq' - Seq value from `useSequentialScope()`
327
+ CONTEXT: /* ************ */ 93, // `]` - `q:ctx' - Component context/props
328
+ SEQ_IDX: /* ************ */ 94, // `^` - `q:seqIdx' - Sequential scope id
329
+ BACK_REFS: /* ********** */ 96, // '`' - `q:brefs' - Effect dependencies/subscriptions
330
+ SEPARATOR: /* ********* */ 124, // `|` - Separator char to encode any key/value pairs.
331
+ SLOT: /* ************** */ 126};
332
+
333
+ function escapeHTML(html) {
334
+ let escapedHTML = '';
335
+ const length = html.length;
336
+ let idx = 0;
337
+ let lastIdx = idx;
338
+ for (; idx < length; idx++) {
339
+ // We get the charCode NOT string. String would allocate memory.
340
+ const ch = html.charCodeAt(idx);
341
+ // Every time we concat a string we allocate memory. We want to minimize that.
342
+ if (ch === 60 /* < */) {
343
+ escapedHTML += html.substring(lastIdx, idx) + '&lt;';
344
+ }
345
+ else if (ch === 62 /* > */) {
346
+ escapedHTML += html.substring(lastIdx, idx) + '&gt;';
347
+ }
348
+ else if (ch === 38 /* & */) {
349
+ escapedHTML += html.substring(lastIdx, idx) + '&amp;';
350
+ }
351
+ else if (ch === 34 /* " */) {
352
+ escapedHTML += html.substring(lastIdx, idx) + '&quot;';
353
+ }
354
+ else if (ch === 39 /* ' */) {
355
+ escapedHTML += html.substring(lastIdx, idx) + '&#39;';
356
+ }
357
+ else {
358
+ continue;
359
+ }
360
+ lastIdx = idx + 1;
361
+ }
362
+ if (lastIdx === 0) {
363
+ // This is most common case, just return previous string no memory allocation.
364
+ return html;
365
+ }
366
+ else {
367
+ // Add the tail of replacement.
368
+ return escapedHTML + html.substring(lastIdx);
369
+ }
370
+ }
371
+ function decodeVNodeDataString(str) {
372
+ let result = '';
373
+ for (let i = 0; i < str.length; i++) {
374
+ if (str.charAt(i) === '\\' && i + 1 < str.length) {
375
+ result += str.charAt(i + 1);
376
+ i++;
377
+ }
378
+ else {
379
+ result += str.charAt(i);
380
+ }
381
+ }
382
+ return result;
383
+ }
384
+
189
385
  /** State factory of the component. */
190
386
  const OnRenderProp = 'q:renderFn';
191
387
  /** Component style content prefix */
@@ -254,127 +450,15 @@ const NON_SERIALIZABLE_MARKER_PREFIX = ':';
254
450
  const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
255
451
  const USE_ON_LOCAL_SEQ_IDX = NON_SERIALIZABLE_MARKER_PREFIX + 'onIdx';
256
452
  const USE_ON_LOCAL_FLAGS = NON_SERIALIZABLE_MARKER_PREFIX + 'onFlags';
257
- // comment nodes
258
- const FLUSH_COMMENT = 'qkssr-f';
259
- const STREAM_BLOCK_START_COMMENT = 'qkssr-pu';
260
- const STREAM_BLOCK_END_COMMENT = 'qkssr-po';
261
453
  const Q_PROPS_SEPARATOR = ':';
262
454
  const dangerouslySetInnerHTML = 'dangerouslySetInnerHTML';
263
455
  const qwikInspectorAttr = 'data-qwik-inspector';
264
456
  const debugStyleScopeIdPrefixAttr = '__scopedStyleIdPrefix__';
265
457
 
266
- // keep this import from core/build so the cjs build works
267
- const createPlatform = () => {
268
- return {
269
- isServer,
270
- importSymbol(containerEl, url, symbolName) {
271
- if (isServer) {
272
- const hash = getSymbolHash(symbolName);
273
- const regSym = globalThis.__qwik_reg_symbols?.get(hash);
274
- if (regSym) {
275
- return regSym;
276
- }
277
- }
278
- if (!url) {
279
- throw qError(14 /* QError.qrlMissingChunk */, [symbolName]);
280
- }
281
- if (!containerEl) {
282
- throw qError(13 /* QError.qrlMissingContainer */, [url, symbolName]);
283
- }
284
- const urlDoc = toUrl(containerEl.ownerDocument, containerEl, url).toString();
285
- const urlCopy = new URL(urlDoc);
286
- urlCopy.hash = '';
287
- const importURL = urlCopy.href;
288
- return import(/* @vite-ignore */ importURL).then((mod) => {
289
- return mod[symbolName];
290
- });
291
- },
292
- raf: (fn) => {
293
- return new Promise((resolve) => {
294
- requestAnimationFrame(() => {
295
- resolve(fn());
296
- });
297
- });
298
- },
299
- chunkForSymbol(symbolName, chunk) {
300
- return [symbolName, chunk ?? '_'];
301
- },
302
- };
303
- };
304
- /**
305
- * Convert relative base URI and relative URL into a fully qualified URL.
306
- *
307
- * @param base -`QRL`s are relative, and therefore they need a base for resolution.
308
- *
309
- * - `Element` use `base.ownerDocument.baseURI`
310
- * - `Document` use `base.baseURI`
311
- * - `string` use `base` as is
312
- * - `QConfig` use `base.baseURI`
313
- *
314
- * @param url - Relative URL
315
- * @returns Fully qualified URL.
316
- */
317
- const toUrl = (doc, containerEl, url) => {
318
- const baseURI = doc.baseURI;
319
- const base = new URL(containerEl.getAttribute(QBaseAttr) ?? baseURI, baseURI);
320
- return new URL(url, base);
321
- };
322
- let _platform = /*#__PURE__ */ createPlatform();
323
- // <docs markdown="./readme.md#setPlatform">
324
- // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
325
- // (edit ./readme.md#setPlatform instead and run `pnpm docs.sync`)
326
- /**
327
- * Sets the `CorePlatform`.
328
- *
329
- * This is useful to override the platform in tests to change the behavior of,
330
- * `requestAnimationFrame`, and import resolution.
331
- *
332
- * @param doc - The document of the application for which the platform is needed.
333
- * @param platform - The platform to use.
334
- * @public
335
- */
336
- // </docs>
337
- const setPlatform = (plt) => (_platform = plt);
338
- // <docs markdown="./readme.md#getPlatform">
339
- // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
340
- // (edit ./readme.md#getPlatform instead and run `pnpm docs.sync`)
341
- /**
342
- * Retrieve the `CorePlatform`.
343
- *
344
- * The `CorePlatform` is also responsible for retrieving the Manifest, that contains mappings from
345
- * symbols to javascript import chunks. For this reason, `CorePlatform` can't be global, but is
346
- * specific to the application currently running. On server it is possible that many different
347
- * applications are running in a single server instance, and for this reason the `CorePlatform` is
348
- * associated with the application document.
349
- *
350
- * @param docOrNode - The document (or node) of the application for which the platform is needed.
351
- * @public
352
- */
353
- // </docs>
354
- const getPlatform = () => {
355
- return _platform;
356
- };
357
- const isServerPlatform = () => {
358
- if (qDynamicPlatform) {
359
- return _platform.isServer;
360
- }
361
- return false;
362
- };
363
-
364
- const isNode = (value) => {
365
- return value && typeof value.nodeType === 'number';
366
- };
367
- const isDocument = (value) => {
368
- return value.nodeType === 9;
369
- };
370
- const isElement$1 = (value) => {
371
- return value.nodeType === 1;
372
- };
373
-
374
- const MAX_RETRY_ON_PROMISE_COUNT = 100;
375
- const isPromise = (value) => {
376
- // not using "value instanceof Promise" to have zone.js support
377
- return !!value && typeof value == 'object' && typeof value.then === 'function';
458
+ const MAX_RETRY_ON_PROMISE_COUNT = 100;
459
+ const isPromise = (value) => {
460
+ // not using "value instanceof Promise" to have zone.js support
461
+ return !!value && typeof value == 'object' && typeof value.then === 'function';
378
462
  };
379
463
  const safeCall = (call, thenFn, rejectFn) => {
380
464
  try {
@@ -455,101 +539,583 @@ function retryOnPromise(fn, onError = justThrow) {
455
539
  return ok ? result.catch(retry) : retry(result);
456
540
  }
457
541
 
458
- const ASSERT_DISCLAIMER = 'Internal assert, this is likely caused by a bug in Qwik: ';
459
- function assertDefined(value, text, ...parts) {
460
- if (qDev) {
461
- if (value != null) {
462
- return;
542
+ const styleContent = (styleId) => {
543
+ return ComponentStylesPrefixContent + styleId;
544
+ };
545
+ function isClassAttr(key) {
546
+ return key === 'class';
547
+ }
548
+ function convertScopedStyleIdsToArray(scopedStyleIds) {
549
+ return scopedStyleIds?.split(' ') ?? null;
550
+ }
551
+ function convertStyleIdsToString(scopedStyleIds) {
552
+ return Array.from(scopedStyleIds).join(' ');
553
+ }
554
+ const addComponentStylePrefix = (styleId) => {
555
+ if (styleId) {
556
+ let idx = 0;
557
+ do {
558
+ styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
559
+ } while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
560
+ }
561
+ return styleId || null;
562
+ };
563
+
564
+ /**
565
+ * Think of `-` as an escape character which makes the next character uppercase. `--` is just `-`.
566
+ *
567
+ * Rules for JSX property event names starting with `on`:
568
+ *
569
+ * - Are case insensitive: `onClick$` is same `onclick$`
570
+ * - A `--` is `-`: `dbl--click` => `dbl-click`
571
+ * - Become case sensitive if prefixed by `-`: `-Click` is `Click`
572
+ * - A `-` (not at the beginning) makes next character uppercase: `dbl-click` => `dblClick`
573
+ */
574
+ const EVENT_SUFFIX = '$';
575
+ const isHtmlAttributeAnEventName = (name) => {
576
+ return (name.charCodeAt(0) === 113 /* q */ &&
577
+ name.charCodeAt(1) === 45 /* - */ &&
578
+ name.charCodeAt(3) === 58 /* : */);
579
+ };
580
+ function jsxEventToHtmlAttribute(jsxEvent) {
581
+ if (jsxEvent.endsWith(EVENT_SUFFIX)) {
582
+ const [prefix, idx] = getEventScopeDataFromJsxEvent(jsxEvent);
583
+ if (idx !== -1) {
584
+ const name = jsxEvent.slice(idx, -1);
585
+ return name === 'DOMContentLoaded'
586
+ ? // The only DOM event that is not all lowercase
587
+ prefix + '-d-o-m-content-loaded'
588
+ : createEventName(name.charAt(0) === '-'
589
+ ? // marker for case sensitive event name
590
+ name.slice(1)
591
+ : name.toLowerCase(), prefix);
463
592
  }
464
- throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
465
593
  }
594
+ return null; // Return null if not matching expected format
466
595
  }
467
- function assertEqual(value1, value2, text, ...parts) {
468
- if (qDev) {
469
- if (value1 === value2) {
470
- return;
471
- }
472
- throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
596
+ function createEventName(event, prefix) {
597
+ const eventName = fromCamelToKebabCase(event);
598
+ return prefix + eventName;
599
+ }
600
+ function getEventScopeDataFromJsxEvent(eventName) {
601
+ let prefix;
602
+ let idx = -1;
603
+ // set prefix and idx based on the scope
604
+ if (eventName.startsWith("on" /* EventNameJSXScope.on */)) {
605
+ prefix = "q-e:" /* EventNameHtmlScope.on */;
606
+ idx = 2;
473
607
  }
608
+ else if (eventName.startsWith("window:on" /* EventNameJSXScope.window */)) {
609
+ prefix = "q-w:" /* EventNameHtmlScope.window */;
610
+ idx = 9;
611
+ }
612
+ else if (eventName.startsWith("document:on" /* EventNameJSXScope.document */)) {
613
+ prefix = "q-d:" /* EventNameHtmlScope.document */;
614
+ idx = 11;
615
+ }
616
+ return [prefix, idx];
474
617
  }
475
- function assertTrue(value1, text, ...parts) {
476
- if (qDev) {
477
- if (value1 === true) {
478
- return;
618
+ function isPreventDefault(key) {
619
+ return key.startsWith('preventdefault:');
620
+ }
621
+ /** Converts a camelCase string to kebab-case. This is used for event names. */
622
+ const fromCamelToKebabCase = (text) => {
623
+ return text.replace(/([A-Z-])/g, (a) => '-' + a.toLowerCase());
624
+ };
625
+ /** E.g. `"q-e:click"` => `['e', 'click']` */
626
+ const getEventDataFromHtmlAttribute = (htmlKey) => [
627
+ htmlKey.charAt(2),
628
+ htmlKey.substring(4),
629
+ ];
630
+ /** E.g. `"e:click"`, `"w:load"` */
631
+ const getScopedEventName = (scope, eventName) => scope + ':' + eventName;
632
+
633
+ /** CSS properties which accept numbers but are not in units of "px". */
634
+ const unitlessNumbers = new Set([
635
+ 'animationIterationCount',
636
+ 'aspectRatio',
637
+ 'borderImageOutset',
638
+ 'borderImageSlice',
639
+ 'borderImageWidth',
640
+ 'boxFlex',
641
+ 'boxFlexGroup',
642
+ 'boxOrdinalGroup',
643
+ 'columnCount',
644
+ 'columns',
645
+ 'flex',
646
+ 'flexGrow',
647
+ 'flexShrink',
648
+ 'gridArea',
649
+ 'gridRow',
650
+ 'gridRowEnd',
651
+ 'gridRowStart',
652
+ 'gridColumn',
653
+ 'gridColumnEnd',
654
+ 'gridColumnStart',
655
+ 'fontWeight',
656
+ 'lineClamp',
657
+ 'lineHeight',
658
+ 'opacity',
659
+ 'order',
660
+ 'orphans',
661
+ 'scale',
662
+ 'tabSize',
663
+ 'widows',
664
+ 'zIndex',
665
+ 'zoom',
666
+ 'MozAnimationIterationCount', // Known Prefixed Properties
667
+ 'MozBoxFlex', // TODO: Remove these since they shouldn't be used in modern code
668
+ 'msFlex',
669
+ 'msFlexPositive',
670
+ 'WebkitAnimationIterationCount',
671
+ 'WebkitBoxFlex',
672
+ 'WebkitBoxOrdinalGroup',
673
+ 'WebkitColumnCount',
674
+ 'WebkitColumns',
675
+ 'WebkitFlex',
676
+ 'WebkitFlexGrow',
677
+ 'WebkitFlexShrink',
678
+ 'WebkitLineClamp',
679
+ ]);
680
+ const isUnitlessNumber = (name) => {
681
+ return unitlessNumbers.has(name);
682
+ };
683
+
684
+ const hashCode = (text, hash = 0) => {
685
+ for (let i = 0; i < text.length; i++) {
686
+ const chr = text.charCodeAt(i);
687
+ hash = (hash << 5) - hash + chr;
688
+ hash |= 0; // Convert to 32bit integer
689
+ }
690
+ return Number(Math.abs(hash)).toString(36);
691
+ };
692
+
693
+ const serializeClass = (obj) => {
694
+ if (!obj) {
695
+ return '';
696
+ }
697
+ if (isString(obj)) {
698
+ return obj.trim();
699
+ }
700
+ const classes = [];
701
+ if (isArray(obj)) {
702
+ for (const o of obj) {
703
+ const classList = serializeClass(o);
704
+ if (classList) {
705
+ classes.push(classList);
706
+ }
479
707
  }
480
- throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
481
708
  }
482
- }
483
- function assertFalse(value1, text, ...parts) {
484
- if (qDev) {
485
- if (value1 === false) {
486
- return;
709
+ else {
710
+ for (const [key, value] of Object.entries(obj)) {
711
+ if (value) {
712
+ classes.push(key.trim());
713
+ }
487
714
  }
488
- throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
489
715
  }
716
+ return classes.join(' ');
717
+ };
718
+ // Unlike fromCamelToKebabCase, this leaves `-` so that `background-color` stays `background-color`
719
+ const fromCamelToKebabCaseWithDash = (text) => {
720
+ return text.replace(/([A-Z])/g, '-$1').toLowerCase();
721
+ };
722
+ const stringifyStyle = (obj) => {
723
+ if (obj == null) {
724
+ return '';
725
+ }
726
+ if (typeof obj == 'object') {
727
+ if (isArray(obj)) {
728
+ throw qError(0 /* QError.stringifyClassOrStyle */, [obj, 'style']);
729
+ }
730
+ else {
731
+ const chunks = [];
732
+ for (const key in obj) {
733
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
734
+ const value = obj[key];
735
+ if (value != null && typeof value !== 'function') {
736
+ if (key.startsWith('--')) {
737
+ chunks.push(key + ':' + value);
738
+ }
739
+ else {
740
+ chunks.push(fromCamelToKebabCaseWithDash(key) + ':' + setValueForStyle(key, value));
741
+ }
742
+ }
743
+ }
744
+ }
745
+ return chunks.join(';');
746
+ }
747
+ }
748
+ return String(obj);
749
+ };
750
+ const serializeBooleanOrNumberAttribute = (value) => {
751
+ return value != null ? String(value) : null;
752
+ };
753
+ function serializeAttribute(key, value, styleScopedId) {
754
+ if (isClassAttr(key)) {
755
+ const serializedClass = serializeClass(value);
756
+ value = styleScopedId
757
+ ? styleScopedId + (serializedClass.length ? ' ' + serializedClass : serializedClass)
758
+ : serializedClass;
759
+ }
760
+ else if (key === 'style') {
761
+ value = stringifyStyle(value);
762
+ }
763
+ else if (isEnumeratedBooleanAttribute(key) || typeof value === 'number') {
764
+ // aria attrs, tabindex etc.
765
+ value = serializeBooleanOrNumberAttribute(value);
766
+ }
767
+ else if (value === false || value == null) {
768
+ value = null;
769
+ }
770
+ else if (value === true && isPreventDefault(key)) {
771
+ value = '';
772
+ }
773
+ return value;
490
774
  }
491
- function assertNumber(value1, text, ...parts) {
492
- if (qDev) {
493
- if (typeof value1 === 'number') {
494
- return;
775
+ function isEnumeratedBooleanAttribute(key) {
776
+ return isAriaAttribute(key) || ['spellcheck', 'draggable', 'contenteditable'].includes(key);
777
+ }
778
+ const setValueForStyle = (styleName, value) => {
779
+ if (typeof value === 'number' && value !== 0 && !isUnitlessNumber(styleName)) {
780
+ return value + 'px';
781
+ }
782
+ return value;
783
+ };
784
+ function isAriaAttribute(prop) {
785
+ return prop.startsWith('aria-');
786
+ }
787
+ const styleKey = (qStyles, index) => {
788
+ assertQrl(qStyles);
789
+ return `${hashCode(qStyles.$hash$)}-${index}`;
790
+ };
791
+
792
+ // Browser-specific setup
793
+ const doc = isBrowser ? document : undefined;
794
+ // Determine which rel attribute to use based on browser support
795
+ const rel = isBrowser && doc.createElement('link').relList.supports('modulepreload')
796
+ ? 'modulePreload'
797
+ : 'preload';
798
+ const isJSRegex = /\.[mc]?js$/;
799
+
800
+ const BundleImportState_None = 0;
801
+ const BundleImportState_Preload = 2;
802
+ const BundleImportState_Alias = 3;
803
+ const BundleImportState_Loaded = 4;
804
+
805
+ let base;
806
+ const makeBundle = (name, deps) => {
807
+ return {
808
+ $name$: name,
809
+ $state$: isJSRegex.test(name) ? BundleImportState_None : BundleImportState_Alias,
810
+ $deps$: deps,
811
+ $inverseProbability$: 1,
812
+ $createdTs$: Date.now(),
813
+ $waitedMs$: 0,
814
+ $loadedMs$: 0,
815
+ };
816
+ };
817
+ const getBundle = (name) => {
818
+ let bundle = bundles.get(name);
819
+ if (!bundle) {
820
+ let deps;
821
+ bundle = makeBundle(name, deps);
822
+ bundles.set(name, bundle);
823
+ }
824
+ return bundle;
825
+ };
826
+
827
+ const bundles = new Map();
828
+ let preloadCount = 0;
829
+ const queue = [];
830
+ /**
831
+ * This is called when a bundle is queued, or finished loading.
832
+ *
833
+ * Because Chrome doesn't treat new modulepreloads as higher priority, we only make
834
+ * maxSimultaneousPreloads links available at a time, so that when a new high priority bundle comes
835
+ * in, it is soon preloaded.
836
+ *
837
+ * We make sure to first preload the high priority items.
838
+ */
839
+ const trigger = () => {
840
+ if (!queue.length) {
841
+ return;
842
+ }
843
+ while (queue.length) {
844
+ const bundle = queue[0];
845
+ const inverseProbability = bundle.$inverseProbability$;
846
+ const probability = 1 - inverseProbability;
847
+ const allowedPreloads = // While the graph is not available, we limit to 5 preloads
848
+ 5;
849
+ // When we're 99% sure, everything needs to be queued
850
+ if (probability >= 0.99 || preloadCount < allowedPreloads) {
851
+ queue.shift();
852
+ preloadOne(bundle);
495
853
  }
496
- throwErrorAndStop(ASSERT_DISCLAIMER + text, ...parts);
854
+ else {
855
+ break;
856
+ }
857
+ }
858
+ };
859
+ const preloadOne = (bundle) => {
860
+ if (bundle.$state$ >= BundleImportState_Preload) {
861
+ return;
862
+ }
863
+ preloadCount++;
864
+ const start = Date.now();
865
+ bundle.$waitedMs$ = start - bundle.$createdTs$;
866
+ bundle.$state$ = BundleImportState_Preload;
867
+ const link = doc.createElement('link');
868
+ // Only bundles with state none are js bundles
869
+ link.href = new URL(`${base}${bundle.$name$}`, doc.baseURI).toString();
870
+ link.rel = rel;
871
+ // Needed when rel is 'preload'
872
+ link.as = 'script';
873
+ // Handle completion of the preload
874
+ link.onload = link.onerror = () => {
875
+ preloadCount--;
876
+ const end = Date.now();
877
+ bundle.$loadedMs$ = end - start;
878
+ bundle.$state$ = BundleImportState_Loaded;
879
+ // Keep the <head> clean
880
+ link.remove();
881
+ // More bundles may be ready to preload
882
+ trigger();
883
+ };
884
+ doc.head.appendChild(link);
885
+ };
886
+ /**
887
+ * Adjust the probability of a bundle based on the probability of its dependent bundles, and queue
888
+ * it if it's likely enough to be preloaded.
889
+ *
890
+ * Note that if the probability is 100%, we treat the dynamic imports as 99% sure, and both will be
891
+ * preloaded without limit.
892
+ *
893
+ * We also limit "organic" probability to 98% so they don't get unlimited preloads.
894
+ */
895
+ const adjustProbabilities = (bundle, newInverseProbability, seen) => {
896
+ if (seen?.has(bundle)) {
897
+ return;
898
+ }
899
+ const previousInverseProbability = bundle.$inverseProbability$;
900
+ bundle.$inverseProbability$ = newInverseProbability;
901
+ // Don't propagate tiny changes
902
+ if (previousInverseProbability - bundle.$inverseProbability$ < 0.01) {
903
+ return;
904
+ }
905
+ if (bundle.$deps$) {
906
+ seen ||= new Set();
907
+ seen.add(bundle);
908
+ const probability = 1 - bundle.$inverseProbability$;
909
+ for (const dep of bundle.$deps$) {
910
+ const depBundle = getBundle(dep.$name$);
911
+ if (depBundle.$inverseProbability$ === 0) {
912
+ // it's already at max probability
913
+ continue;
914
+ }
915
+ /**
916
+ * The chance that a dep won't be loaded is 1-(the chance that the dep will be loaded)*(the
917
+ * chance that the current bundle will be loaded).
918
+ *
919
+ * We can multiply this chance together with all other bundle adjustments to get the chance
920
+ * that a dep will be loaded given all the chances of the other bundles.
921
+ *
922
+ * But when we're very likely to load the current bundle, make the dynamic imports very likely
923
+ * too.
924
+ */
925
+ let newInverseProbability;
926
+ if (probability === 1 || (probability >= 0.99 && depsCount < 100)) {
927
+ depsCount++;
928
+ // we're loaded at max probability, so elevate dynamic imports to 99% sure
929
+ newInverseProbability = Math.min(0.01, 1 - dep.$importProbability$);
930
+ }
931
+ else {
932
+ const newInverseImportProbability = 1 - dep.$importProbability$ * probability;
933
+ /** We need to undo the previous adjustment */
934
+ const prevAdjust = dep.$factor$;
935
+ const factor = newInverseImportProbability / prevAdjust;
936
+ // limit organic probability to 98%
937
+ newInverseProbability = Math.max(0.02, depBundle.$inverseProbability$ * factor);
938
+ dep.$factor$ = factor;
939
+ }
940
+ adjustProbabilities(depBundle, newInverseProbability, seen);
941
+ }
942
+ }
943
+ };
944
+ const handleBundle = (name, inverseProbability) => {
945
+ const bundle = getBundle(name);
946
+ if (bundle && bundle.$inverseProbability$ > inverseProbability) {
947
+ adjustProbabilities(bundle, inverseProbability);
948
+ }
949
+ };
950
+ let depsCount;
951
+ const preload = (name, probability) => {
952
+ if (!name?.length) {
953
+ return;
497
954
  }
955
+ depsCount = 0;
956
+ let inverseProbability = 1 - probability ;
957
+ if (Array.isArray(name)) {
958
+ // We must process in reverse order to ensure first bundles are handled first
959
+ for (let i = name.length - 1; i >= 0; i--) {
960
+ const item = name[i];
961
+ if (typeof item === 'number') {
962
+ inverseProbability = 1 - item / 10;
963
+ }
964
+ else {
965
+ handleBundle(item, inverseProbability);
966
+ }
967
+ }
968
+ }
969
+ else {
970
+ handleBundle(name, inverseProbability);
971
+ }
972
+ if (isBrowser) {
973
+ trigger();
974
+ }
975
+ };
976
+ if (isBrowser) {
977
+ // Get early hints from qwikloader
978
+ document.addEventListener('qsymbol', (ev) => {
979
+ const { symbol, href } = ev.detail;
980
+ // the qrl class doesn't emit href, we don't need to preload
981
+ if (href) {
982
+ const hash = symbol.slice(symbol.lastIndexOf('_') + 1);
983
+ preload(hash, 1);
984
+ }
985
+ });
498
986
  }
499
987
 
988
+ const isObjectEmpty = (obj) => {
989
+ for (const key in obj) {
990
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
991
+ return false;
992
+ }
993
+ }
994
+ return true;
995
+ };
996
+
997
+ // Pre-allocated common strings to reduce allocation overhead
998
+ const CLOSE_TAG = '</';
999
+ const ESCAPED_CLOSE_TAG = '<\\/';
1000
+ const QUOTE = '"';
1001
+ const BRACKET_OPEN = '[';
1002
+ const BRACKET_CLOSE = ']';
1003
+ const COMMA = ',';
1004
+
500
1005
  /**
501
- * A friendly name tag for a VirtualVNode.
1006
+ * QWIK_VERSION
502
1007
  *
503
- * Theses are used to give a name to a VirtualVNode. This is useful for debugging and testing.
1008
+ * @public
1009
+ */
1010
+ const version = "2.0.0-beta.24-dev+314726b";
1011
+
1012
+ // keep this import from core/build so the cjs build works
1013
+ const createPlatform = () => {
1014
+ return {
1015
+ isServer,
1016
+ importSymbol(containerEl, url, symbolName) {
1017
+ if (isServer) {
1018
+ const hash = getSymbolHash(symbolName);
1019
+ const regSym = globalThis.__qwik_reg_symbols?.get(hash);
1020
+ if (regSym) {
1021
+ return regSym;
1022
+ }
1023
+ }
1024
+ if (!url) {
1025
+ throw qError(14 /* QError.qrlMissingChunk */, [symbolName]);
1026
+ }
1027
+ if (!containerEl) {
1028
+ throw qError(13 /* QError.qrlMissingContainer */, [url, symbolName]);
1029
+ }
1030
+ const urlDoc = toUrl(containerEl.ownerDocument, containerEl, url).toString();
1031
+ const urlCopy = new URL(urlDoc);
1032
+ urlCopy.hash = '';
1033
+ const importURL = urlCopy.href;
1034
+ return import(/* @vite-ignore */ importURL).then((mod) => {
1035
+ return mod[symbolName];
1036
+ });
1037
+ },
1038
+ raf: (fn) => {
1039
+ return new Promise((resolve) => {
1040
+ requestAnimationFrame(() => {
1041
+ resolve(fn());
1042
+ });
1043
+ });
1044
+ },
1045
+ chunkForSymbol(symbolName, chunk) {
1046
+ return [symbolName, chunk ?? '_'];
1047
+ },
1048
+ };
1049
+ };
1050
+ /**
1051
+ * Convert relative base URI and relative URL into a fully qualified URL.
1052
+ *
1053
+ * @param base -`QRL`s are relative, and therefore they need a base for resolution.
1054
+ *
1055
+ * - `Element` use `base.ownerDocument.baseURI`
1056
+ * - `Document` use `base.baseURI`
1057
+ * - `string` use `base` as is
1058
+ * - `QConfig` use `base.baseURI`
1059
+ *
1060
+ * @param url - Relative URL
1061
+ * @returns Fully qualified URL.
1062
+ */
1063
+ const toUrl = (doc, containerEl, url) => {
1064
+ const baseURI = doc.baseURI;
1065
+ const base = new URL(containerEl.getAttribute(QBaseAttr) ?? baseURI, baseURI);
1066
+ return new URL(url, base);
1067
+ };
1068
+ let _platform = /*#__PURE__ */ createPlatform();
1069
+ // <docs markdown="./readme.md#setPlatform">
1070
+ // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
1071
+ // (edit ./readme.md#setPlatform instead and run `pnpm docs.sync`)
1072
+ /**
1073
+ * Sets the `CorePlatform`.
1074
+ *
1075
+ * This is useful to override the platform in tests to change the behavior of,
1076
+ * `requestAnimationFrame`, and import resolution.
1077
+ *
1078
+ * @param doc - The document of the application for which the platform is needed.
1079
+ * @param platform - The platform to use.
1080
+ * @public
1081
+ */
1082
+ // </docs>
1083
+ const setPlatform = (plt) => (_platform = plt);
1084
+ // <docs markdown="./readme.md#getPlatform">
1085
+ // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
1086
+ // (edit ./readme.md#getPlatform instead and run `pnpm docs.sync`)
1087
+ /**
1088
+ * Retrieve the `CorePlatform`.
1089
+ *
1090
+ * The `CorePlatform` is also responsible for retrieving the Manifest, that contains mappings from
1091
+ * symbols to javascript import chunks. For this reason, `CorePlatform` can't be global, but is
1092
+ * specific to the application currently running. On server it is possible that many different
1093
+ * applications are running in a single server instance, and for this reason the `CorePlatform` is
1094
+ * associated with the application document.
504
1095
  *
505
- * The name is only added in development mode and is not included in production builds.
1096
+ * @param docOrNode - The document (or node) of the application for which the platform is needed.
1097
+ * @public
506
1098
  */
507
- const DEBUG_TYPE = 'q:type';
508
- const VirtualTypeName = {
509
- ["V" /* VirtualType.Virtual */]: /* ********* */ 'Virtual', //
510
- ["F" /* VirtualType.Fragment */]: /* ******** */ 'Fragment', //
511
- ["S" /* VirtualType.WrappedSignal */]: /* *** */ 'Signal', //
512
- ["A" /* VirtualType.Awaited */]: /* ********* */ 'Awaited', //
513
- ["C" /* VirtualType.Component */]: /* ******* */ 'Component', //
514
- ["I" /* VirtualType.InlineComponent */]: /* * */ 'InlineComponent', //
515
- ["P" /* VirtualType.Projection */]: /* ****** */ 'Projection', //
1099
+ // </docs>
1100
+ const getPlatform = () => {
1101
+ return _platform;
1102
+ };
1103
+ const isServerPlatform = () => {
1104
+ if (qDynamicPlatform) {
1105
+ return _platform.isServer;
1106
+ }
1107
+ return false;
516
1108
  };
517
1109
 
518
- /**
519
- * @file
520
- *
521
- * VNodeData is additional information which allows the `vnode` to recover virtual VNode information
522
- * from the HTML.
523
- */
524
- /**
525
- * VNodeDataSeparator contains information about splitting up the VNodeData and attaching it to the
526
- * HTML.
527
- */
528
- const VNodeDataSeparator = {
529
- REFERENCE: /* ******** */ 126, // `~` is a reference to the node. Save it.
530
- ADVANCE_1: /* ********* */ 33, // `!` is vNodeData separator skipping 0. (ie next vNode)
531
- ADVANCE_8192: /* ****** */ 46, // `.` is vNodeData separator skipping 4096.
1110
+ const isNode = (value) => {
1111
+ return value && typeof value.nodeType === 'number';
1112
+ };
1113
+ const isDocument = (value) => {
1114
+ return value.nodeType === 9;
1115
+ };
1116
+ const isElement$1 = (value) => {
1117
+ return value.nodeType === 1;
532
1118
  };
533
- /**
534
- * VNodeDataChar contains information about the VNodeData used for encoding props.
535
- *
536
- * Available character ranges: 59 - 64, 91 - 94, 96, 123 - 126
537
- */
538
- const VNodeDataChar = {
539
- OPEN: /* ************** */ 123, // `{` is the start of the VNodeData for a virtual element.
540
- CLOSE: /* ************* */ 125, // `}` is the end of the VNodeData for a virtual element.
541
- SCOPED_STYLE: /* ******* */ 59, // `;` - `q:sstyle` - Style attribute.
542
- RENDER_FN: /* ********** */ 60, // `<` - `q:renderFn' - Component QRL render function (body)
543
- ID: /* ***************** */ 61, // `=` - `q:id` - ID of the element.
544
- PROPS: /* ************** */ 62, // `>` - `q:props' - Component Props
545
- SLOT_PARENT: /* ******** */ 63, // `?` - `q:sparent` - Slot parent.
546
- KEY: /* **************** */ 64, // `@` - `q:key` - Element key.
547
- SEQ: /* **************** */ 91, // `[` - `q:seq' - Seq value from `useSequentialScope()`
548
- CONTEXT: /* ************ */ 93, // `]` - `q:ctx' - Component context/props
549
- SEQ_IDX: /* ************ */ 94, // `^` - `q:seqIdx' - Sequential scope id
550
- BACK_REFS: /* ********** */ 96, // '`' - `q:brefs' - Effect dependencies/subscriptions
551
- SEPARATOR: /* ********* */ 124, // `|` - Separator char to encode any key/value pairs.
552
- SLOT: /* ************** */ 126};
553
1119
 
554
1120
  const isForeignObjectElement = (elementName) => {
555
1121
  return isDev ? elementName.toLowerCase() === 'foreignobject' : elementName === 'foreignObject';
@@ -773,75 +1339,6 @@ const mergeMaps = (map1, map2) => {
773
1339
  return map1;
774
1340
  };
775
1341
 
776
- /**
777
- * Think of `-` as an escape character which makes the next character uppercase. `--` is just `-`.
778
- *
779
- * Rules for JSX property event names starting with `on`:
780
- *
781
- * - Are case insensitive: `onClick$` is same `onclick$`
782
- * - A `--` is `-`: `dbl--click` => `dbl-click`
783
- * - Become case sensitive if prefixed by `-`: `-Click` is `Click`
784
- * - A `-` (not at the beginning) makes next character uppercase: `dbl-click` => `dblClick`
785
- */
786
- const EVENT_SUFFIX = '$';
787
- const isHtmlAttributeAnEventName = (name) => {
788
- return (name.charCodeAt(0) === 113 /* q */ &&
789
- name.charCodeAt(1) === 45 /* - */ &&
790
- name.charCodeAt(3) === 58 /* : */);
791
- };
792
- function jsxEventToHtmlAttribute(jsxEvent) {
793
- if (jsxEvent.endsWith(EVENT_SUFFIX)) {
794
- const [prefix, idx] = getEventScopeDataFromJsxEvent(jsxEvent);
795
- if (idx !== -1) {
796
- const name = jsxEvent.slice(idx, -1);
797
- return name === 'DOMContentLoaded'
798
- ? // The only DOM event that is not all lowercase
799
- prefix + '-d-o-m-content-loaded'
800
- : createEventName(name.charAt(0) === '-'
801
- ? // marker for case sensitive event name
802
- name.slice(1)
803
- : name.toLowerCase(), prefix);
804
- }
805
- }
806
- return null; // Return null if not matching expected format
807
- }
808
- function createEventName(event, prefix) {
809
- const eventName = fromCamelToKebabCase(event);
810
- return prefix + eventName;
811
- }
812
- function getEventScopeDataFromJsxEvent(eventName) {
813
- let prefix;
814
- let idx = -1;
815
- // set prefix and idx based on the scope
816
- if (eventName.startsWith("on" /* EventNameJSXScope.on */)) {
817
- prefix = "q-e:" /* EventNameHtmlScope.on */;
818
- idx = 2;
819
- }
820
- else if (eventName.startsWith("window:on" /* EventNameJSXScope.window */)) {
821
- prefix = "q-w:" /* EventNameHtmlScope.window */;
822
- idx = 9;
823
- }
824
- else if (eventName.startsWith("document:on" /* EventNameJSXScope.document */)) {
825
- prefix = "q-d:" /* EventNameHtmlScope.document */;
826
- idx = 11;
827
- }
828
- return [prefix, idx];
829
- }
830
- function isPreventDefault(key) {
831
- return key.startsWith('preventdefault:');
832
- }
833
- /** Converts a camelCase string to kebab-case. This is used for event names. */
834
- const fromCamelToKebabCase = (text) => {
835
- return text.replace(/([A-Z-])/g, (a) => '-' + a.toLowerCase());
836
- };
837
- /** E.g. `"q-e:click"` => `['e', 'click']` */
838
- const getEventDataFromHtmlAttribute = (htmlKey) => [
839
- htmlKey.charAt(2),
840
- htmlKey.substring(4),
841
- ];
842
- /** E.g. `"e:click"`, `"w:load"` */
843
- const getScopedEventName = (scope, eventName) => scope + ':' + eventName;
844
-
845
1342
  /** @internal */
846
1343
  const _EFFECT_BACK_REF = Symbol('backRef');
847
1344
  /** Class for back reference to the EffectSubscription */
@@ -1092,16 +1589,20 @@ class SignalImpl {
1092
1589
  this.$untrackedValue$ = value;
1093
1590
  }
1094
1591
  /**
1095
- * Use this to force running subscribers, for example when the calculated value has mutated but
1592
+ * Use this to trigger running subscribers, for example when the calculated value has mutated but
1096
1593
  * remained the same object
1097
1594
  */
1595
+ trigger() {
1596
+ scheduleEffects(this.$container$, this, this.$effects$);
1597
+ }
1598
+ /** @deprecated Use `trigger()` instead */
1098
1599
  force() {
1099
1600
  scheduleEffects(this.$container$, this, this.$effects$);
1100
1601
  }
1602
+ // We need this to be getter/setter so subclasses can override them
1101
1603
  get untrackedValue() {
1102
1604
  return this.$untrackedValue$;
1103
1605
  }
1104
- // TODO: should we disallow setting the value directly?
1105
1606
  set untrackedValue(value) {
1106
1607
  this.$untrackedValue$ = value;
1107
1608
  }
@@ -1205,6 +1706,7 @@ const _UNINITIALIZED = Symbol('UNINITIALIZED');
1205
1706
 
1206
1707
  /** @internal */
1207
1708
  const EMPTY_ARRAY = [];
1709
+ /** @internal */
1208
1710
  const EMPTY_OBJ = {};
1209
1711
  Object.freeze(EMPTY_ARRAY);
1210
1712
  Object.freeze(EMPTY_OBJ);
@@ -1616,6 +2118,9 @@ class ComputedSignalImpl extends SignalImpl {
1616
2118
  isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
1617
2119
  return this.$untrackedValue$;
1618
2120
  }
2121
+ set untrackedValue(value) {
2122
+ this.$untrackedValue$ = value;
2123
+ }
1619
2124
  $computeIfNeeded$() {
1620
2125
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1621
2126
  return;
@@ -1711,18 +2216,17 @@ class AsyncSignalImpl extends ComputedSignalImpl {
1711
2216
  $jobs$ = [];
1712
2217
  $concurrency$ = 1;
1713
2218
  $interval$ = 0;
1714
- $pollTimeoutId$ = undefined;
1715
2219
  $timeoutMs$;
1716
- $computationTimeoutId$;
1717
2220
  [_EFFECT_BACK_REF] = undefined;
1718
2221
  constructor(container, fn, flags = 1 /* SignalFlags.INVALID */ |
1719
2222
  16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
1720
2223
  super(container, fn, flags);
1721
- const interval = options?.interval || 0;
2224
+ const interval = options?.interval;
1722
2225
  const concurrency = options?.concurrency ?? 1;
1723
2226
  const initial = options?.initial;
1724
2227
  const timeout = options?.timeout;
1725
2228
  const eagerCleanup = options?.eagerCleanup;
2229
+ const clientOnly = options?.clientOnly;
1726
2230
  // Handle initial value - eagerly evaluate if function, set $untrackedValue$ and $promiseValue$
1727
2231
  // Do NOT call setValue() which would clear the INVALID flag and prevent async computation
1728
2232
  if (initial !== undefined) {
@@ -1730,11 +2234,42 @@ class AsyncSignalImpl extends ComputedSignalImpl {
1730
2234
  this.$untrackedValue$ = initialValue;
1731
2235
  }
1732
2236
  this.$concurrency$ = concurrency;
1733
- this.$timeoutMs$ = timeout;
2237
+ if (timeout) {
2238
+ this.$timeoutMs$ = timeout;
2239
+ }
1734
2240
  if (eagerCleanup) {
1735
2241
  this.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
1736
2242
  }
1737
- this.interval = interval;
2243
+ if (clientOnly) {
2244
+ this.$flags$ |= 64 /* AsyncSignalFlags.CLIENT_ONLY */;
2245
+ }
2246
+ if (interval) {
2247
+ this.interval = interval;
2248
+ }
2249
+ }
2250
+ get untrackedValue() {
2251
+ this.$computeIfNeeded$();
2252
+ if (this.$current$?.$promise$) {
2253
+ if (this.$untrackedValue$ === NEEDS_COMPUTATION ||
2254
+ (import.meta.env.TEST ? isServerPlatform() : isServer)) {
2255
+ throw this.$current$?.$promise$;
2256
+ }
2257
+ return this.$untrackedValue$;
2258
+ }
2259
+ if (this.$untrackedError$) {
2260
+ throw this.$untrackedError$;
2261
+ }
2262
+ // For clientOnly signals without initial value during SSR, throw if trying to read value
2263
+ // During SSR, clientOnly signals are skipped, so there's no computed value available
2264
+ if ((import.meta.env.TEST ? isServerPlatform() : isServer) &&
2265
+ this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */ &&
2266
+ this.$untrackedValue$ === NEEDS_COMPUTATION) {
2267
+ throw new Error('During SSR, cannot read .value from clientOnly async signal without an initial value. Use .loading or provide an initial value.');
2268
+ }
2269
+ return this.$untrackedValue$;
2270
+ }
2271
+ set untrackedValue(value) {
2272
+ this.$untrackedValue$ = value;
1738
2273
  }
1739
2274
  /**
1740
2275
  * Loading is true if the signal is still waiting for the promise to resolve, false if the promise
@@ -1827,6 +2362,14 @@ class AsyncSignalImpl extends ComputedSignalImpl {
1827
2362
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1828
2363
  return;
1829
2364
  }
2365
+ // Skip computation on SSR for clientOnly signals
2366
+ if ((import.meta.env.TEST ? isServerPlatform() : isServer) &&
2367
+ this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
2368
+ // We must pretend to load, and register as a listener for the captures
2369
+ this.$untrackedLoading$ = true;
2370
+ this.$container$?.serializationCtx.$eagerResume$.add(this);
2371
+ return;
2372
+ }
1830
2373
  this.$clearNextPoll$();
1831
2374
  if (this.$current$) {
1832
2375
  this.$requestCleanups$(this.$current$);
@@ -1901,20 +2444,6 @@ class AsyncSignalImpl extends ComputedSignalImpl {
1901
2444
  }
1902
2445
  await Promise.all(this.$jobs$.map((job) => job.$promise$));
1903
2446
  }
1904
- get untrackedValue() {
1905
- this.$computeIfNeeded$();
1906
- if (this.$current$?.$promise$) {
1907
- if (this.$untrackedValue$ === NEEDS_COMPUTATION ||
1908
- (import.meta.env.TEST ? isServerPlatform() : isServer)) {
1909
- throw this.$current$?.$promise$;
1910
- }
1911
- return this.$untrackedValue$;
1912
- }
1913
- if (this.$untrackedError$) {
1914
- throw this.$untrackedError$;
1915
- }
1916
- return this.$untrackedValue$;
1917
- }
1918
2447
  $clearNextPoll$() {
1919
2448
  if (this.$pollTimeoutId$ !== undefined) {
1920
2449
  clearTimeout(this.$pollTimeoutId$);
@@ -2198,6 +2727,8 @@ class WrappedSignalImpl extends SignalImpl {
2198
2727
  $funcStr$;
2199
2728
  $flags$;
2200
2729
  $hostElement$ = undefined;
2730
+ // important: don't use implemnets BackRef here
2731
+ // it causes v8 optimizations eager bailouts, because of not consistent class shape
2201
2732
  [_EFFECT_BACK_REF] = undefined;
2202
2733
  constructor(container, fn, args, fnStr,
2203
2734
  // We need a separate flag to know when the computation needs running because
@@ -2393,17 +2924,16 @@ function _chk(_, element) {
2393
2924
  */
2394
2925
  function _res(_, element) {
2395
2926
  maybeScopeFromQL(this, element);
2396
- // Captures are deserialized, signals are now resumed
2397
- }
2398
-
2399
- const isObjectEmpty = (obj) => {
2400
- for (const key in obj) {
2401
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
2402
- return false;
2927
+ // Captures are deserialized, now trigger computation on AsyncSignals
2928
+ if (_captures) {
2929
+ for (const capture of _captures) {
2930
+ if (capture instanceof AsyncSignalImpl && capture.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
2931
+ capture.$computeIfNeeded$();
2932
+ }
2933
+ // note that polling async signals will automatically schedule themselves so no action needed
2403
2934
  }
2404
2935
  }
2405
- return true;
2406
- };
2936
+ }
2407
2937
 
2408
2938
  const _hasOwnProperty$2 = Object.prototype.hasOwnProperty;
2409
2939
  // TODO store props as the arrays the vnodes also use?
@@ -2462,6 +2992,9 @@ const isJSXNode = (n) => {
2462
2992
  _hasOwnProperty$2.call(n, 'key') &&
2463
2993
  _hasOwnProperty$2.call(n, 'props') &&
2464
2994
  _hasOwnProperty$2.call(n, 'type')) {
2995
+ if (isPropsProxy(n)) {
2996
+ return false;
2997
+ }
2465
2998
  logWarn(`Duplicate implementations of "JSXNode" found`);
2466
2999
  return true;
2467
3000
  }
@@ -2914,7 +3447,6 @@ function addUseOnEvent(jsxElement, key, value) {
2914
3447
  props[key] = undefined;
2915
3448
  }
2916
3449
  }
2917
- const getValue = (o) => o.value;
2918
3450
  /**
2919
3451
  * Finds the first element node in the JSX output.
2920
3452
  *
@@ -2938,7 +3470,7 @@ function findFirstElementNode(jsx) {
2938
3470
  return maybeThen(jsx, (jsx) => findFirstElementNode(jsx));
2939
3471
  }
2940
3472
  else if (isSignal(jsx)) {
2941
- return findFirstElementNode(untrack(getValue, jsx));
3473
+ return findFirstElementNode(jsx.untrackedValue);
2942
3474
  }
2943
3475
  }
2944
3476
  return null;
@@ -3007,11 +3539,7 @@ const SSRRaw = () => null;
3007
3539
  const SSRComment = () => null;
3008
3540
  /** @public */
3009
3541
  const SSRStreamBlock = (props) => {
3010
- return [
3011
- jsx(SSRComment, { data: STREAM_BLOCK_START_COMMENT }),
3012
- props.children,
3013
- jsx(SSRComment, { data: STREAM_BLOCK_END_COMMENT }),
3014
- ];
3542
+ return props.children;
3015
3543
  };
3016
3544
  /** @public */
3017
3545
  const SSRStream = (props, key) => jsx(RenderOnce, { children: jsx(InternalSSRStream, props) }, key);
@@ -3022,79 +3550,27 @@ const fastSetAttribute = (target, name, value) => {
3022
3550
  if (!_setAttribute) {
3023
3551
  _setAttribute = target.setAttribute;
3024
3552
  }
3025
- _setAttribute.call(target, name, value);
3026
- };
3027
- let _setAttributeNS = null;
3028
- const fastSetAttributeNS = (target, namespace, name, value) => {
3029
- if (!_setAttributeNS) {
3030
- _setAttributeNS = target.setAttributeNS;
3031
- }
3032
- _setAttributeNS.call(target, namespace, name, value);
3033
- };
3034
- function directSetAttribute(element, attrName, attrValue, isSvg) {
3035
- if (attrValue != null) {
3036
- if (isSvg) {
3037
- // only svg elements can have namespace attributes
3038
- const namespace = getAttributeNamespace(attrName);
3039
- if (namespace) {
3040
- fastSetAttributeNS(element, namespace, attrName, attrValue);
3041
- return;
3042
- }
3043
- }
3044
- fastSetAttribute(element, attrName, attrValue);
3045
- }
3046
- }
3047
-
3048
- function escapeHTML(html) {
3049
- let escapedHTML = '';
3050
- const length = html.length;
3051
- let idx = 0;
3052
- let lastIdx = idx;
3053
- for (; idx < length; idx++) {
3054
- // We get the charCode NOT string. String would allocate memory.
3055
- const ch = html.charCodeAt(idx);
3056
- // Every time we concat a string we allocate memory. We want to minimize that.
3057
- if (ch === 60 /* < */) {
3058
- escapedHTML += html.substring(lastIdx, idx) + '&lt;';
3059
- }
3060
- else if (ch === 62 /* > */) {
3061
- escapedHTML += html.substring(lastIdx, idx) + '&gt;';
3062
- }
3063
- else if (ch === 38 /* & */) {
3064
- escapedHTML += html.substring(lastIdx, idx) + '&amp;';
3065
- }
3066
- else if (ch === 34 /* " */) {
3067
- escapedHTML += html.substring(lastIdx, idx) + '&quot;';
3068
- }
3069
- else if (ch === 39 /* ' */) {
3070
- escapedHTML += html.substring(lastIdx, idx) + '&#39;';
3071
- }
3072
- else {
3073
- continue;
3074
- }
3075
- lastIdx = idx + 1;
3076
- }
3077
- if (lastIdx === 0) {
3078
- // This is most common case, just return previous string no memory allocation.
3079
- return html;
3080
- }
3081
- else {
3082
- // Add the tail of replacement.
3083
- return escapedHTML + html.substring(lastIdx);
3084
- }
3085
- }
3086
- function decodeVNodeDataString(str) {
3087
- let result = '';
3088
- for (let i = 0; i < str.length; i++) {
3089
- if (str.charAt(i) === '\\' && i + 1 < str.length) {
3090
- result += str.charAt(i + 1);
3091
- i++;
3092
- }
3093
- else {
3094
- result += str.charAt(i);
3553
+ _setAttribute.call(target, name, value);
3554
+ };
3555
+ let _setAttributeNS = null;
3556
+ const fastSetAttributeNS = (target, namespace, name, value) => {
3557
+ if (!_setAttributeNS) {
3558
+ _setAttributeNS = target.setAttributeNS;
3559
+ }
3560
+ _setAttributeNS.call(target, namespace, name, value);
3561
+ };
3562
+ function directSetAttribute(element, attrName, attrValue, isSvg) {
3563
+ if (attrValue != null) {
3564
+ if (isSvg) {
3565
+ // only svg elements can have namespace attributes
3566
+ const namespace = getAttributeNamespace(attrName);
3567
+ if (namespace) {
3568
+ fastSetAttributeNS(element, namespace, attrName, attrValue);
3569
+ return;
3570
+ }
3095
3571
  }
3572
+ fastSetAttribute(element, attrName, attrValue);
3096
3573
  }
3097
- return result;
3098
3574
  }
3099
3575
 
3100
3576
  function getFileLocationFromJsx(jsxDev) {
@@ -3133,187 +3609,6 @@ const _restProps = (props, omit = [], target = {}) => {
3133
3609
  return createPropsProxy(new JSXNodeImpl(null, varPropsTarget, constPropsTarget, null, null));
3134
3610
  };
3135
3611
 
3136
- const styleContent = (styleId) => {
3137
- return ComponentStylesPrefixContent + styleId;
3138
- };
3139
- function isClassAttr(key) {
3140
- return key === 'class';
3141
- }
3142
- function convertScopedStyleIdsToArray(scopedStyleIds) {
3143
- return scopedStyleIds?.split(' ') ?? null;
3144
- }
3145
- function convertStyleIdsToString(scopedStyleIds) {
3146
- return Array.from(scopedStyleIds).join(' ');
3147
- }
3148
- const addComponentStylePrefix = (styleId) => {
3149
- if (styleId) {
3150
- let idx = 0;
3151
- do {
3152
- styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
3153
- } while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
3154
- }
3155
- return styleId || null;
3156
- };
3157
-
3158
- /** CSS properties which accept numbers but are not in units of "px". */
3159
- const unitlessNumbers = new Set([
3160
- 'animationIterationCount',
3161
- 'aspectRatio',
3162
- 'borderImageOutset',
3163
- 'borderImageSlice',
3164
- 'borderImageWidth',
3165
- 'boxFlex',
3166
- 'boxFlexGroup',
3167
- 'boxOrdinalGroup',
3168
- 'columnCount',
3169
- 'columns',
3170
- 'flex',
3171
- 'flexGrow',
3172
- 'flexShrink',
3173
- 'gridArea',
3174
- 'gridRow',
3175
- 'gridRowEnd',
3176
- 'gridRowStart',
3177
- 'gridColumn',
3178
- 'gridColumnEnd',
3179
- 'gridColumnStart',
3180
- 'fontWeight',
3181
- 'lineClamp',
3182
- 'lineHeight',
3183
- 'opacity',
3184
- 'order',
3185
- 'orphans',
3186
- 'scale',
3187
- 'tabSize',
3188
- 'widows',
3189
- 'zIndex',
3190
- 'zoom',
3191
- 'MozAnimationIterationCount', // Known Prefixed Properties
3192
- 'MozBoxFlex', // TODO: Remove these since they shouldn't be used in modern code
3193
- 'msFlex',
3194
- 'msFlexPositive',
3195
- 'WebkitAnimationIterationCount',
3196
- 'WebkitBoxFlex',
3197
- 'WebkitBoxOrdinalGroup',
3198
- 'WebkitColumnCount',
3199
- 'WebkitColumns',
3200
- 'WebkitFlex',
3201
- 'WebkitFlexGrow',
3202
- 'WebkitFlexShrink',
3203
- 'WebkitLineClamp',
3204
- ]);
3205
- const isUnitlessNumber = (name) => {
3206
- return unitlessNumbers.has(name);
3207
- };
3208
-
3209
- const hashCode = (text, hash = 0) => {
3210
- for (let i = 0; i < text.length; i++) {
3211
- const chr = text.charCodeAt(i);
3212
- hash = (hash << 5) - hash + chr;
3213
- hash |= 0; // Convert to 32bit integer
3214
- }
3215
- return Number(Math.abs(hash)).toString(36);
3216
- };
3217
-
3218
- const serializeClass = (obj) => {
3219
- if (!obj) {
3220
- return '';
3221
- }
3222
- if (isString(obj)) {
3223
- return obj.trim();
3224
- }
3225
- const classes = [];
3226
- if (isArray(obj)) {
3227
- for (const o of obj) {
3228
- const classList = serializeClass(o);
3229
- if (classList) {
3230
- classes.push(classList);
3231
- }
3232
- }
3233
- }
3234
- else {
3235
- for (const [key, value] of Object.entries(obj)) {
3236
- if (value) {
3237
- classes.push(key.trim());
3238
- }
3239
- }
3240
- }
3241
- return classes.join(' ');
3242
- };
3243
- // Unlike fromCamelToKebabCase, this leaves `-` so that `background-color` stays `background-color`
3244
- const fromCamelToKebabCaseWithDash = (text) => {
3245
- return text.replace(/([A-Z])/g, '-$1').toLowerCase();
3246
- };
3247
- const stringifyStyle = (obj) => {
3248
- if (obj == null) {
3249
- return '';
3250
- }
3251
- if (typeof obj == 'object') {
3252
- if (isArray(obj)) {
3253
- throw qError(0 /* QError.stringifyClassOrStyle */, [obj, 'style']);
3254
- }
3255
- else {
3256
- const chunks = [];
3257
- for (const key in obj) {
3258
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
3259
- const value = obj[key];
3260
- if (value != null && typeof value !== 'function') {
3261
- if (key.startsWith('--')) {
3262
- chunks.push(key + ':' + value);
3263
- }
3264
- else {
3265
- chunks.push(fromCamelToKebabCaseWithDash(key) + ':' + setValueForStyle(key, value));
3266
- }
3267
- }
3268
- }
3269
- }
3270
- return chunks.join(';');
3271
- }
3272
- }
3273
- return String(obj);
3274
- };
3275
- const serializeBooleanOrNumberAttribute = (value) => {
3276
- return value != null ? String(value) : null;
3277
- };
3278
- function serializeAttribute(key, value, styleScopedId) {
3279
- if (isClassAttr(key)) {
3280
- const serializedClass = serializeClass(value);
3281
- value = styleScopedId
3282
- ? styleScopedId + (serializedClass.length ? ' ' + serializedClass : serializedClass)
3283
- : serializedClass;
3284
- }
3285
- else if (key === 'style') {
3286
- value = stringifyStyle(value);
3287
- }
3288
- else if (isEnumeratedBooleanAttribute(key) || typeof value === 'number') {
3289
- // aria attrs, tabindex etc.
3290
- value = serializeBooleanOrNumberAttribute(value);
3291
- }
3292
- else if (value === false || value == null) {
3293
- value = null;
3294
- }
3295
- else if (value === true && isPreventDefault(key)) {
3296
- value = '';
3297
- }
3298
- return value;
3299
- }
3300
- function isEnumeratedBooleanAttribute(key) {
3301
- return isAriaAttribute(key) || ['spellcheck', 'draggable', 'contenteditable'].includes(key);
3302
- }
3303
- const setValueForStyle = (styleName, value) => {
3304
- if (typeof value === 'number' && value !== 0 && !isUnitlessNumber(styleName)) {
3305
- return value + 'px';
3306
- }
3307
- return value;
3308
- };
3309
- function isAriaAttribute(prop) {
3310
- return prop.startsWith('aria-');
3311
- }
3312
- const styleKey = (qStyles, index) => {
3313
- assertQrl(qStyles);
3314
- return `${hashCode(qStyles.$hash$)}-${index}`;
3315
- };
3316
-
3317
3612
  class DeleteOperation {
3318
3613
  target;
3319
3614
  constructor(target) {
@@ -3329,7 +3624,6 @@ class RemoveAllChildrenOperation {
3329
3624
  class SetTextOperation {
3330
3625
  target;
3331
3626
  text;
3332
- operationType = 16 /* VNodeOperationType.SetText */;
3333
3627
  constructor(target, text) {
3334
3628
  this.target = target;
3335
3629
  this.text = text;
@@ -3415,66 +3709,17 @@ function runEventHandlerQRL(handler, event, element, ctx = newInvokeContextFromD
3415
3709
  /**
3416
3710
  * This is called by qwik-loader to run a QRL. It has to be synchronous when possible.
3417
3711
  *
3418
- * @internal
3419
- */
3420
- function _run(event, element) {
3421
- const ctx = newInvokeContextFromDOM(event, element);
3422
- if (typeof this === 'string') {
3423
- setCaptures(deserializeCaptures(ctx.$container$, this));
3424
- }
3425
- const qrlToRun = _captures[0];
3426
- isDev && assertQrl(qrlToRun);
3427
- return runEventHandlerQRL(qrlToRun, event, element, ctx);
3428
- }
3429
-
3430
- /** @internal */
3431
- const mapApp_findIndx = (array, key, start) => {
3432
- isDev && assertTrue(start % 2 === 0, 'Expecting even number.');
3433
- let bottom = start >> 1;
3434
- let top = (array.length - 2) >> 1;
3435
- while (bottom <= top) {
3436
- const mid = bottom + ((top - bottom) >> 1);
3437
- const midKey = array[mid << 1];
3438
- if (midKey === key) {
3439
- return mid << 1;
3440
- }
3441
- if (midKey < key) {
3442
- bottom = mid + 1;
3443
- }
3444
- else {
3445
- top = mid - 1;
3446
- }
3447
- }
3448
- return (bottom << 1) ^ -1;
3449
- };
3450
- /** @internal */
3451
- const mapArray_set = (array, key, value, start, allowNullValue = false) => {
3452
- const indx = mapApp_findIndx(array, key, start);
3453
- if (indx >= 0) {
3454
- if (value == null && !allowNullValue) {
3455
- array.splice(indx, 2);
3456
- }
3457
- else {
3458
- array[indx + 1] = value;
3459
- }
3460
- }
3461
- else if (value != null || allowNullValue) {
3462
- array.splice(indx ^ -1, 0, key, value);
3463
- }
3464
- };
3465
- /** @internal */
3466
- const mapArray_get = (array, key, start) => {
3467
- const indx = mapApp_findIndx(array, key, start);
3468
- if (indx >= 0) {
3469
- return array[indx + 1];
3470
- }
3471
- else {
3472
- return null;
3712
+ * @internal
3713
+ */
3714
+ function _run(event, element) {
3715
+ const ctx = newInvokeContextFromDOM(event, element);
3716
+ if (typeof this === 'string') {
3717
+ setCaptures(deserializeCaptures(ctx.$container$, this));
3473
3718
  }
3474
- };
3475
- const mapArray_has = (array, key, start) => {
3476
- return mapApp_findIndx(array, key, start) >= 0;
3477
- };
3719
+ const qrlToRun = _captures[0];
3720
+ isDev && assertQrl(qrlToRun);
3721
+ return runEventHandlerQRL(qrlToRun, event, element, ctx);
3722
+ }
3478
3723
 
3479
3724
  /**
3480
3725
  * Helper to get the next sibling of a VNode. Extracted to module scope to help V8 inline it
@@ -3565,7 +3810,7 @@ function diff(diffContext, jsxNode, vStartNode) {
3565
3810
  if (isJSXNode(diffContext.jsxValue)) {
3566
3811
  const type = diffContext.jsxValue.type;
3567
3812
  if (typeof type === 'string') {
3568
- expectNoMoreTextNodes(diffContext);
3813
+ expectNoTextNode(diffContext);
3569
3814
  expectElement(diffContext, diffContext.jsxValue, type);
3570
3815
  const hasDangerousInnerHTML = (diffContext.jsxValue.constProps &&
3571
3816
  _hasOwnProperty.call(diffContext.jsxValue.constProps, dangerouslySetInnerHTML)) ||
@@ -3579,12 +3824,12 @@ function diff(diffContext, jsxNode, vStartNode) {
3579
3824
  }
3580
3825
  else if (typeof type === 'function') {
3581
3826
  if (type === Fragment) {
3582
- expectNoMoreTextNodes(diffContext);
3827
+ expectNoTextNode(diffContext);
3583
3828
  expectVirtual(diffContext, "F" /* VirtualType.Fragment */, diffContext.jsxValue.key);
3584
3829
  descend(diffContext, diffContext.jsxValue.children, true);
3585
3830
  }
3586
3831
  else if (type === Slot) {
3587
- expectNoMoreTextNodes(diffContext);
3832
+ expectNoTextNode(diffContext);
3588
3833
  if (!expectSlot(diffContext)) {
3589
3834
  // nothing to project, so try to render the Slot default content.
3590
3835
  descend(diffContext, diffContext.jsxValue.children, true);
@@ -3605,7 +3850,7 @@ function diff(diffContext, jsxNode, vStartNode) {
3605
3850
  }
3606
3851
  else {
3607
3852
  // Must be a component
3608
- expectNoMoreTextNodes(diffContext);
3853
+ expectNoTextNode(diffContext);
3609
3854
  expectComponent(diffContext, type);
3610
3855
  }
3611
3856
  }
@@ -3790,11 +4035,10 @@ function descendContentToProject(diffContext, children, host) {
3790
4035
  const props = host.props;
3791
4036
  if (props) {
3792
4037
  // we need to create empty projections for all the slots to remove unused slots content
3793
- for (const prop of Object.keys(props)) {
4038
+ for (const prop in props) {
3794
4039
  if (isSlotProp(prop)) {
3795
4040
  const slotName = prop;
3796
- projections.push(slotName);
3797
- projections.push(createProjectionJSXNode(slotName));
4041
+ mapArray_set(projections, slotName, createProjectionJSXNode(slotName), 0);
3798
4042
  }
3799
4043
  }
3800
4044
  }
@@ -3976,9 +4220,8 @@ function expectNoMore(diffContext) {
3976
4220
  }
3977
4221
  }
3978
4222
  }
3979
- function expectNoMoreTextNodes(diffContext) {
3980
- while (diffContext.vCurrent !== null && vnode_isTextVNode(diffContext.vCurrent)) {
3981
- cleanup(diffContext.container, diffContext.journal, diffContext.vCurrent, diffContext.cursor);
4223
+ function expectNoTextNode(diffContext) {
4224
+ if (diffContext.vCurrent !== null && vnode_isTextVNode(diffContext.vCurrent)) {
3982
4225
  const toRemove = diffContext.vCurrent;
3983
4226
  diffContext.vCurrent = peekNextSibling(diffContext.vCurrent);
3984
4227
  vnode_remove(diffContext.journal, diffContext.vParent, toRemove, true);
@@ -4077,7 +4320,9 @@ function registerEventHandlers(key, value, element, vnode, diffContext) {
4077
4320
  handlers.push(runEventHandlerQRL.bind(null, item));
4078
4321
  }
4079
4322
  }
4080
- (element._qDispatch ||= {})[scopedKebabName] = handlers;
4323
+ if (handlers.length > 0) {
4324
+ (element._qDispatch ||= {})[scopedKebabName] = handlers;
4325
+ }
4081
4326
  }
4082
4327
  else if (value) {
4083
4328
  (element._qDispatch ||= {})[scopedKebabName] = [
@@ -4491,7 +4736,7 @@ function expectComponent(diffContext, component) {
4491
4736
  (vnode_isVirtualVNode(componentHost)
4492
4737
  ? vnode_getProp(componentHost, OnRenderProp, null) === null
4493
4738
  : true)) {
4494
- componentHost = componentHost.parent;
4739
+ componentHost = componentHost.parent || vnode_getProjectionParentComponent(componentHost);
4495
4740
  }
4496
4741
  const jsxOutput = executeComponent(diffContext.container, host, (componentHost || diffContext.container.rootVNode), component, jsxNode.props);
4497
4742
  diffContext.asyncQueue.push(jsxOutput, host);
@@ -5402,6 +5647,13 @@ function walkCursor(cursor, options) {
5402
5647
  if (currentVNode.dirty & 64 /* ChoreBits.CLEANUP */) {
5403
5648
  executeCleanup(currentVNode, container);
5404
5649
  }
5650
+ else if (currentVNode.dirty & 32 /* ChoreBits.CHILDREN */) {
5651
+ const next = tryDescendDirtyChildren(container, cursorData, currentVNode, cursor);
5652
+ if (next !== null) {
5653
+ currentVNode = next;
5654
+ continue;
5655
+ }
5656
+ }
5405
5657
  // Clear dirty bits and move to next node
5406
5658
  currentVNode.dirty &= -128 /* ChoreBits.DIRTY_MASK */;
5407
5659
  setCursorPosition(container, cursorData, getNextVNode(currentVNode, cursor));
@@ -5426,17 +5678,9 @@ function walkCursor(cursor, options) {
5426
5678
  result = executeCompute(currentVNode, container);
5427
5679
  }
5428
5680
  else if (currentVNode.dirty & 32 /* ChoreBits.CHILDREN */) {
5429
- const dirtyChildren = currentVNode.dirtyChildren;
5430
- if (!dirtyChildren || dirtyChildren.length === 0) {
5431
- // No dirty children
5432
- currentVNode.dirty &= ~32 /* ChoreBits.CHILDREN */;
5433
- }
5434
- else {
5435
- partitionDirtyChildren(dirtyChildren, currentVNode);
5436
- currentVNode.nextDirtyChildIndex = 0;
5437
- // descend
5438
- currentVNode = getNextVNode(dirtyChildren[0], cursor);
5439
- setCursorPosition(container, cursorData, currentVNode);
5681
+ const next = tryDescendDirtyChildren(container, cursorData, currentVNode, cursor);
5682
+ if (next !== null) {
5683
+ currentVNode = next;
5440
5684
  continue;
5441
5685
  }
5442
5686
  }
@@ -5493,6 +5737,22 @@ function finishWalk(container, cursor, cursorData, isServer) {
5493
5737
  function resolveCursor(container) {
5494
5738
  container.$checkPendingCount$();
5495
5739
  }
5740
+ /**
5741
+ * If the vNode has dirty children, partitions them, sets cursor to first dirty child, and returns
5742
+ * that child. Otherwise clears CHILDREN bit and returns null.
5743
+ */
5744
+ function tryDescendDirtyChildren(container, cursorData, currentVNode, cursor) {
5745
+ const dirtyChildren = currentVNode.dirtyChildren;
5746
+ if (!dirtyChildren || dirtyChildren.length === 0) {
5747
+ currentVNode.dirty &= -33 /* ChoreBits.CHILDREN */;
5748
+ return null;
5749
+ }
5750
+ partitionDirtyChildren(dirtyChildren, currentVNode);
5751
+ currentVNode.nextDirtyChildIndex = 0;
5752
+ const next = getNextVNode(dirtyChildren[0], cursor);
5753
+ setCursorPosition(container, cursorData, next);
5754
+ return next;
5755
+ }
5496
5756
  /**
5497
5757
  * Partitions dirtyChildren array so non-projections come first, projections last. Uses in-place
5498
5758
  * swapping to avoid allocations.
@@ -8481,18 +8741,26 @@ const _fnSignal = (fn, args, fnStr) => {
8481
8741
  * - Odd values are numbers, strings (JSON stringified with `</` escaping) or arrays (same format).
8482
8742
  * - Therefore root indexes need to be doubled to get the actual index.
8483
8743
  */
8484
- async function serialize(serializationContext) {
8485
- const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $promoteToRoot$, getSeenRef, $markSeen$, } = serializationContext;
8486
- let rootIdx = 0;
8487
- const forwardRefs = [];
8488
- let forwardRefsId = 0;
8489
- const promises = new Set();
8490
- const s11nWeakRefs = new Map();
8491
- let parent;
8492
- const qrlMap = new Map();
8744
+ class Serializer {
8745
+ $serializationContext$;
8746
+ rootIdx = 0;
8747
+ forwardRefs = [];
8748
+ forwardRefsId = 0;
8749
+ promises = new Set();
8750
+ s11nWeakRefs = new Map();
8751
+ parent;
8752
+ qrlMap = new Map();
8753
+ $writer$;
8754
+ constructor($serializationContext$) {
8755
+ this.$serializationContext$ = $serializationContext$;
8756
+ this.$writer$ = $serializationContext$.$writer$;
8757
+ }
8758
+ async serialize() {
8759
+ await this.outputRoots();
8760
+ }
8493
8761
  /** Helper to output an array */
8494
- const outputArray = (value, keepUndefined, writeFn) => {
8495
- $writer$.write('[');
8762
+ outputArray(value, keepUndefined, writeFn) {
8763
+ this.$writer$.write(BRACKET_OPEN);
8496
8764
  let separator = false;
8497
8765
  let length;
8498
8766
  if (keepUndefined) {
@@ -8507,41 +8775,52 @@ async function serialize(serializationContext) {
8507
8775
  }
8508
8776
  for (let i = 0; i < length; i++) {
8509
8777
  if (separator) {
8510
- $writer$.write(',');
8778
+ this.$writer$.write(COMMA);
8511
8779
  }
8512
8780
  else {
8513
8781
  separator = true;
8514
8782
  }
8515
8783
  writeFn(value[i], i);
8516
8784
  }
8517
- $writer$.write(']');
8518
- };
8785
+ this.$writer$.write(BRACKET_CLOSE);
8786
+ }
8787
+ /** Whether a string needs JSON escaping (quote, backslash, or control chars). */
8788
+ stringNeedsJsonEscape$(str) {
8789
+ for (let i = 0; i < str.length; i++) {
8790
+ const c = str.charCodeAt(i);
8791
+ if (c < 32 || c === 34 || c === 92) {
8792
+ return true;
8793
+ }
8794
+ }
8795
+ return false;
8796
+ }
8519
8797
  /** Output a type,value pair. If the value is an array, it calls writeValue on each item. */
8520
- const output = (type, value, keepUndefined) => {
8521
- $writer$.write(`${type},`);
8798
+ output(type, value, keepUndefined) {
8522
8799
  if (typeof value === 'number') {
8523
- $writer$.write(value.toString());
8800
+ this.$writer$.write(type + COMMA + value);
8524
8801
  }
8525
8802
  else if (typeof value === 'string') {
8526
- const s = JSON.stringify(value);
8803
+ const s = this.stringNeedsJsonEscape$(value) ? JSON.stringify(value) : QUOTE + value + QUOTE;
8804
+ this.$writer$.write(type + COMMA);
8527
8805
  let angleBracketIdx = -1;
8528
8806
  let lastIdx = 0;
8529
- while ((angleBracketIdx = s.indexOf('</', lastIdx)) !== -1) {
8530
- $writer$.write(s.slice(lastIdx, angleBracketIdx));
8531
- $writer$.write('<\\/');
8807
+ while ((angleBracketIdx = s.indexOf(CLOSE_TAG, lastIdx)) !== -1) {
8808
+ this.$writer$.write(s.slice(lastIdx, angleBracketIdx));
8809
+ this.$writer$.write(ESCAPED_CLOSE_TAG);
8532
8810
  lastIdx = angleBracketIdx + 2;
8533
8811
  }
8534
- $writer$.write(lastIdx === 0 ? s : s.slice(lastIdx));
8812
+ this.$writer$.write(lastIdx === 0 ? s : s.slice(lastIdx));
8535
8813
  }
8536
8814
  else {
8537
- outputArray(value, !!keepUndefined, (valueItem, idx) => {
8538
- writeValue(valueItem, idx);
8815
+ this.$writer$.write(type + COMMA);
8816
+ this.outputArray(value, !!keepUndefined, (valueItem, idx) => {
8817
+ this.writeValue(valueItem, idx);
8539
8818
  });
8540
8819
  }
8541
- };
8542
- const getSeenRefOrOutput = (value, index, keepWeak) => {
8543
- let seen = getSeenRef(value);
8544
- const forwardRefIdx = !keepWeak && s11nWeakRefs.get(value);
8820
+ }
8821
+ getSeenRefOrOutput(value, index, keepWeak) {
8822
+ let seen = this.$serializationContext$.getSeenRef(value);
8823
+ const forwardRefIdx = !keepWeak && this.s11nWeakRefs.get(value);
8545
8824
  if (!seen) {
8546
8825
  if (keepWeak) {
8547
8826
  // we're testing a weakref, so don't mark it as seen yet
@@ -8550,136 +8829,136 @@ async function serialize(serializationContext) {
8550
8829
  // Maybe it's a weakref and that should count as seen
8551
8830
  if (typeof forwardRefIdx === 'number') {
8552
8831
  // Yes, no longer a weakref
8553
- seen = $addRoot$(value, true);
8832
+ seen = this.$serializationContext$.$addRoot$(value, true);
8554
8833
  }
8555
8834
  else {
8556
- return $markSeen$(value, parent, index);
8835
+ return this.$serializationContext$.$markSeen$(value, this.parent, index);
8557
8836
  }
8558
8837
  }
8559
8838
  // Now that we saw it a second time, make sure it's a root
8560
8839
  if (seen.$parent$) {
8561
8840
  // Note, this means it was output before so we always need a backref
8562
8841
  // Special case: we're a root so instead of adding a backref, we replace ourself
8563
- if (!parent) {
8564
- $promoteToRoot$(seen, index);
8565
- value = serializationContext.$roots$[index];
8842
+ if (!this.parent) {
8843
+ this.$serializationContext$.$promoteToRoot$(seen, index);
8844
+ value = this.$serializationContext$.$roots$[index];
8566
8845
  }
8567
8846
  else {
8568
- $promoteToRoot$(seen);
8847
+ this.$serializationContext$.$promoteToRoot$(seen);
8569
8848
  }
8570
8849
  }
8571
8850
  // Check if there was a weakref to us
8572
8851
  if (typeof forwardRefIdx === 'number') {
8573
- forwardRefs[forwardRefIdx] = seen.$index$;
8574
- s11nWeakRefs.delete(value);
8852
+ this.forwardRefs[forwardRefIdx] = seen.$index$;
8853
+ this.s11nWeakRefs.delete(value);
8575
8854
  }
8576
8855
  // Now we know it's a root and we should output a RootRef
8577
8856
  const rootIdx = value instanceof SerializationBackRef ? value.$path$ : seen.$index$;
8578
8857
  // But make sure we do output ourselves
8579
- if (!parent && rootIdx === index) {
8858
+ if (!this.parent && rootIdx === index) {
8580
8859
  return seen;
8581
8860
  }
8582
- output(1 /* TypeIds.RootRef */, rootIdx);
8583
- };
8861
+ this.output(1 /* TypeIds.RootRef */, rootIdx);
8862
+ }
8584
8863
  // First check for scalars, then do objects with seen checks
8585
8864
  // Make sure to only get the SeenRef once, it's expensive
8586
- const writeValue = (value, index) => {
8865
+ writeValue(value, index) {
8587
8866
  if (fastSkipSerialize(value)) {
8588
- output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
8867
+ this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
8589
8868
  }
8590
8869
  else {
8591
8870
  switch (typeof value) {
8592
8871
  case 'undefined':
8593
- output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
8872
+ this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
8594
8873
  break;
8595
8874
  case 'boolean':
8596
- output(3 /* TypeIds.Constant */, value ? 2 /* Constants.True */ : 3 /* Constants.False */);
8875
+ this.output(3 /* TypeIds.Constant */, value ? 2 /* Constants.True */ : 3 /* Constants.False */);
8597
8876
  break;
8598
8877
  case 'number':
8599
8878
  if (Number.isNaN(value)) {
8600
- output(3 /* TypeIds.Constant */, 12 /* Constants.NaN */);
8879
+ this.output(3 /* TypeIds.Constant */, 12 /* Constants.NaN */);
8601
8880
  }
8602
8881
  else if (!Number.isFinite(value)) {
8603
- output(3 /* TypeIds.Constant */, value < 0 ? 14 /* Constants.NegativeInfinity */ : 13 /* Constants.PositiveInfinity */);
8882
+ this.output(3 /* TypeIds.Constant */, value < 0 ? 14 /* Constants.NegativeInfinity */ : 13 /* Constants.PositiveInfinity */);
8604
8883
  }
8605
8884
  else if (value === Number.MAX_SAFE_INTEGER) {
8606
- output(3 /* TypeIds.Constant */, 15 /* Constants.MaxSafeInt */);
8885
+ this.output(3 /* TypeIds.Constant */, 15 /* Constants.MaxSafeInt */);
8607
8886
  }
8608
8887
  else if (value === Number.MAX_SAFE_INTEGER - 1) {
8609
- output(3 /* TypeIds.Constant */, 16 /* Constants.AlmostMaxSafeInt */);
8888
+ this.output(3 /* TypeIds.Constant */, 16 /* Constants.AlmostMaxSafeInt */);
8610
8889
  }
8611
8890
  else if (value === Number.MIN_SAFE_INTEGER) {
8612
- output(3 /* TypeIds.Constant */, 17 /* Constants.MinSafeInt */);
8891
+ this.output(3 /* TypeIds.Constant */, 17 /* Constants.MinSafeInt */);
8613
8892
  }
8614
8893
  else {
8615
- output(0 /* TypeIds.Plain */, value);
8894
+ this.output(0 /* TypeIds.Plain */, value);
8616
8895
  }
8617
8896
  break;
8618
8897
  case 'string':
8619
8898
  if (value.length === 0) {
8620
- output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
8899
+ this.output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
8621
8900
  }
8622
8901
  else {
8623
8902
  // If the string is short, we output directly
8624
8903
  // Very short strings add overhead to tracking
8625
- if (value.length < 4 || getSeenRefOrOutput(value, index)) {
8626
- output(0 /* TypeIds.Plain */, value);
8904
+ if (value.length < 4 || this.getSeenRefOrOutput(value, index)) {
8905
+ this.output(0 /* TypeIds.Plain */, value);
8627
8906
  }
8628
8907
  }
8629
8908
  break;
8630
8909
  case 'bigint':
8631
- if ((value < 10000 && value > -1e3) || getSeenRefOrOutput(value, index)) {
8632
- output(12 /* TypeIds.BigInt */, value.toString());
8910
+ if ((value < 10000 && value > -1e3) || this.getSeenRefOrOutput(value, index)) {
8911
+ this.output(12 /* TypeIds.BigInt */, value.toString());
8633
8912
  }
8634
8913
  break;
8635
8914
  case 'symbol':
8636
8915
  if (value === NEEDS_COMPUTATION) {
8637
- output(3 /* TypeIds.Constant */, 7 /* Constants.NEEDS_COMPUTATION */);
8916
+ this.output(3 /* TypeIds.Constant */, 7 /* Constants.NEEDS_COMPUTATION */);
8638
8917
  }
8639
8918
  else if (value === STORE_ALL_PROPS) {
8640
- output(3 /* TypeIds.Constant */, 8 /* Constants.STORE_ALL_PROPS */);
8919
+ this.output(3 /* TypeIds.Constant */, 8 /* Constants.STORE_ALL_PROPS */);
8641
8920
  }
8642
8921
  else if (value === _UNINITIALIZED) {
8643
- output(3 /* TypeIds.Constant */, 9 /* Constants.UNINITIALIZED */);
8922
+ this.output(3 /* TypeIds.Constant */, 9 /* Constants.UNINITIALIZED */);
8644
8923
  }
8645
8924
  break;
8646
8925
  case 'function':
8647
8926
  if (value === Slot) {
8648
- output(3 /* TypeIds.Constant */, 10 /* Constants.Slot */);
8927
+ this.output(3 /* TypeIds.Constant */, 10 /* Constants.Slot */);
8649
8928
  }
8650
8929
  else if (value === Fragment) {
8651
- output(3 /* TypeIds.Constant */, 11 /* Constants.Fragment */);
8930
+ this.output(3 /* TypeIds.Constant */, 11 /* Constants.Fragment */);
8652
8931
  }
8653
8932
  else if (isQrl(value)) {
8654
- if (getSeenRefOrOutput(value, index)) {
8655
- const [chunk, symbol, captures] = qrlToString(serializationContext, value, true);
8933
+ if (this.getSeenRefOrOutput(value, index)) {
8934
+ const [chunk, symbol, captures] = qrlToString(this.$serializationContext$, value, true);
8656
8935
  let data;
8657
8936
  if (chunk !== '') {
8658
8937
  // not a sync QRL, replace all parts with string references
8659
- data = `${$addRoot$(chunk)}#${$addRoot$(symbol)}${captures ? '#' + captures : ''}`;
8938
+ data = `${this.$serializationContext$.$addRoot$(chunk)}#${this.$serializationContext$.$addRoot$(symbol)}${captures ? '#' + captures : ''}`;
8660
8939
  // Since we map QRLs to strings, we need to keep track of this secondary mapping
8661
- const existing = qrlMap.get(data);
8940
+ const existing = this.qrlMap.get(data);
8662
8941
  if (existing) {
8663
8942
  // We encountered the same QRL again, make it a root
8664
- const ref = $addRoot$(existing);
8665
- output(1 /* TypeIds.RootRef */, ref);
8943
+ const ref = this.$serializationContext$.$addRoot$(existing);
8944
+ this.output(1 /* TypeIds.RootRef */, ref);
8666
8945
  return;
8667
8946
  }
8668
8947
  else {
8669
- qrlMap.set(data, value);
8948
+ this.qrlMap.set(data, value);
8670
8949
  }
8671
8950
  }
8672
8951
  else {
8673
8952
  // sync QRL
8674
8953
  data = Number(symbol);
8675
8954
  }
8676
- output(9 /* TypeIds.QRL */, data);
8955
+ this.output(9 /* TypeIds.QRL */, data);
8677
8956
  }
8678
8957
  }
8679
8958
  else if (isQwikComponent(value)) {
8680
8959
  const [qrl] = value[SERIALIZABLE_STATE];
8681
- serializationContext.$renderSymbols$.add(qrl.$symbol$);
8682
- output(21 /* TypeIds.Component */, [qrl]);
8960
+ this.$serializationContext$.$renderSymbols$.add(qrl.$symbol$);
8961
+ this.output(21 /* TypeIds.Component */, [qrl]);
8683
8962
  }
8684
8963
  else {
8685
8964
  throw qError(34 /* QError.serializeErrorCannotSerializeFunction */, [value.toString()]);
@@ -8687,25 +8966,25 @@ async function serialize(serializationContext) {
8687
8966
  break;
8688
8967
  case 'object':
8689
8968
  if (value === EMPTY_ARRAY) {
8690
- output(3 /* TypeIds.Constant */, 5 /* Constants.EMPTY_ARRAY */);
8969
+ this.output(3 /* TypeIds.Constant */, 5 /* Constants.EMPTY_ARRAY */);
8691
8970
  }
8692
8971
  else if (value === EMPTY_OBJ) {
8693
- output(3 /* TypeIds.Constant */, 6 /* Constants.EMPTY_OBJ */);
8972
+ this.output(3 /* TypeIds.Constant */, 6 /* Constants.EMPTY_OBJ */);
8694
8973
  }
8695
8974
  else if (value === null) {
8696
- output(3 /* TypeIds.Constant */, 1 /* Constants.Null */);
8975
+ this.output(3 /* TypeIds.Constant */, 1 /* Constants.Null */);
8697
8976
  }
8698
8977
  else if (value instanceof SerializationBackRef) {
8699
- output(1 /* TypeIds.RootRef */, value.$path$);
8978
+ this.output(1 /* TypeIds.RootRef */, value.$path$);
8700
8979
  }
8701
8980
  else {
8702
- const newSeenRef = getSeenRefOrOutput(value, index);
8981
+ const newSeenRef = this.getSeenRefOrOutput(value, index);
8703
8982
  if (newSeenRef) {
8704
- const oldParent = parent;
8705
- parent = newSeenRef;
8983
+ const oldParent = this.parent;
8984
+ this.parent = newSeenRef;
8706
8985
  // separate function for readability
8707
- writeObjectValue(value);
8708
- parent = oldParent;
8986
+ this.writeObjectValue(value);
8987
+ this.parent = oldParent;
8709
8988
  }
8710
8989
  }
8711
8990
  break;
@@ -8713,11 +8992,11 @@ async function serialize(serializationContext) {
8713
8992
  throw qError(20 /* QError.serializeErrorUnknownType */, [typeof value]);
8714
8993
  }
8715
8994
  }
8716
- };
8717
- const writeObjectValue = (value) => {
8995
+ }
8996
+ writeObjectValue(value) {
8718
8997
  if (isPropsProxy(value)) {
8719
8998
  const owner = value[_OWNER];
8720
- output(30 /* TypeIds.PropsProxy */, [
8999
+ this.output(30 /* TypeIds.PropsProxy */, [
8721
9000
  _serializationWeakRef(owner),
8722
9001
  owner.varProps,
8723
9002
  owner.constProps,
@@ -8725,10 +9004,13 @@ async function serialize(serializationContext) {
8725
9004
  ]);
8726
9005
  }
8727
9006
  else if (value instanceof SubscriptionData) {
8728
- output(31 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9007
+ this.output(31 /* TypeIds.SubscriptionData */, [
9008
+ value.data.$scopedStyleIdPrefix$,
9009
+ value.data.$isConst$,
9010
+ ]);
8729
9011
  }
8730
9012
  else if (value instanceof EffectSubscription) {
8731
- output(32 /* TypeIds.EffectSubscription */, [
9013
+ this.output(32 /* TypeIds.EffectSubscription */, [
8732
9014
  value.consumer,
8733
9015
  value.property,
8734
9016
  value.backRef,
@@ -8744,7 +9026,7 @@ async function serialize(serializationContext) {
8744
9026
  const innerStores = [];
8745
9027
  for (const prop in storeTarget) {
8746
9028
  const propValue = storeTarget[prop];
8747
- const innerStore = $storeProxyMap$.get(propValue);
9029
+ const innerStore = this.$serializationContext$.$storeProxyMap$.get(propValue);
8748
9030
  if (innerStore) {
8749
9031
  innerStores.push(innerStore);
8750
9032
  }
@@ -8753,26 +9035,26 @@ async function serialize(serializationContext) {
8753
9035
  while (out[out.length - 1] === undefined) {
8754
9036
  out.pop();
8755
9037
  }
8756
- output(27 /* TypeIds.Store */, out);
9038
+ this.output(27 /* TypeIds.Store */, out);
8757
9039
  }
8758
9040
  else if (isSerializerObj(value)) {
8759
9041
  const result = value[SerializerSymbol](value);
8760
9042
  if (isPromise(result)) {
8761
- const forwardRef = resolvePromise(result, $addRoot$, (resolved, resolvedValue) => {
9043
+ const forwardRef = this.resolvePromise(result, (resolved, resolvedValue) => {
8762
9044
  return new PromiseResult(26 /* TypeIds.SerializerSignal */, resolved, resolvedValue, undefined, undefined);
8763
9045
  });
8764
- output(2 /* TypeIds.ForwardRef */, forwardRef);
9046
+ this.output(2 /* TypeIds.ForwardRef */, forwardRef);
8765
9047
  }
8766
9048
  else {
8767
9049
  // We replace ourselves with this value
8768
- const index = parent.$index$;
8769
- parent = parent.$parent$;
8770
- writeValue(result, index);
9050
+ const index = this.parent.$index$;
9051
+ this.parent = this.parent.$parent$;
9052
+ this.writeValue(result, index);
8771
9053
  }
8772
9054
  }
8773
9055
  else if (isObjectLiteral(value)) {
8774
9056
  if (Array.isArray(value)) {
8775
- output(4 /* TypeIds.Array */, value);
9057
+ this.output(4 /* TypeIds.Array */, value);
8776
9058
  }
8777
9059
  else {
8778
9060
  const out = [];
@@ -8784,24 +9066,24 @@ async function serialize(serializationContext) {
8784
9066
  }
8785
9067
  }
8786
9068
  }
8787
- output(5 /* TypeIds.Object */, out.length ? out : 0);
9069
+ this.output(5 /* TypeIds.Object */, out.length ? out : 0);
8788
9070
  }
8789
9071
  }
8790
- else if ($isDomRef$(value)) {
9072
+ else if (this.$serializationContext$.$isDomRef$(value)) {
8791
9073
  value.$ssrNode$.vnodeData[0] |= 16 /* VNodeDataFlag.SERIALIZE */;
8792
- output(11 /* TypeIds.RefVNode */, value.$ssrNode$.id);
9074
+ this.output(11 /* TypeIds.RefVNode */, value.$ssrNode$.id);
8793
9075
  }
8794
9076
  else if (value instanceof SignalImpl) {
8795
9077
  if (value instanceof SerializerSignalImpl) {
8796
9078
  const maybeValue = getCustomSerializerPromise(value, value.$untrackedValue$);
8797
9079
  if (isPromise(maybeValue)) {
8798
- const forwardRefId = resolvePromise(maybeValue, $addRoot$, (resolved, resolvedValue) => {
9080
+ const forwardRefId = this.resolvePromise(maybeValue, (resolved, resolvedValue) => {
8799
9081
  return new PromiseResult(26 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
8800
9082
  });
8801
- output(2 /* TypeIds.ForwardRef */, forwardRefId);
9083
+ this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
8802
9084
  }
8803
9085
  else {
8804
- output(26 /* TypeIds.SerializerSignal */, [
9086
+ this.output(26 /* TypeIds.SerializerSignal */, [
8805
9087
  value.$computeQrl$,
8806
9088
  filterEffectBackRefs(value[_EFFECT_BACK_REF]),
8807
9089
  value.$effects$,
@@ -8811,8 +9093,8 @@ async function serialize(serializationContext) {
8811
9093
  return;
8812
9094
  }
8813
9095
  if (value instanceof WrappedSignalImpl) {
8814
- output(23 /* TypeIds.WrappedSignal */, [
8815
- ...serializeWrappingFn(serializationContext, value),
9096
+ this.output(23 /* TypeIds.WrappedSignal */, [
9097
+ ...serializeWrappingFn(this.$serializationContext$, value),
8816
9098
  filterEffectBackRefs(value[_EFFECT_BACK_REF]),
8817
9099
  value.$flags$,
8818
9100
  value.$hostElement$,
@@ -8829,7 +9111,9 @@ async function serialize(serializationContext) {
8829
9111
  const interval = isAsync && value.$interval$ > 0 ? value.$interval$ : undefined;
8830
9112
  const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
8831
9113
  const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
8832
- const eagerCleanup = isAsync && value.$flags$ & 32 /* AsyncSignalFlags.EAGER_CLEANUP */ ? true : undefined;
9114
+ // Send the flags but remove the serialization bits and default to 0 when undefined
9115
+ const asyncFlags = (isAsync && value.$flags$ & -25 /* SerializationSignalFlags.SERIALIZATION_ALL_STRATEGIES */) ||
9116
+ undefined;
8833
9117
  if (isInvalid || isSkippable) {
8834
9118
  v = NEEDS_COMPUTATION;
8835
9119
  }
@@ -8847,6 +9131,7 @@ async function serialize(serializationContext) {
8847
9131
  if (isAsync) {
8848
9132
  // After SSR, the signal is never loading, so no need to send it
8849
9133
  out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
9134
+ out.push(asyncFlags || undefined);
8850
9135
  }
8851
9136
  let keepUndefined = false;
8852
9137
  if (v !== NEEDS_COMPUTATION ||
@@ -8867,9 +9152,8 @@ async function serialize(serializationContext) {
8867
9152
  out.push(interval);
8868
9153
  out.push(concurrency);
8869
9154
  out.push(timeout);
8870
- out.push(eagerCleanup);
8871
9155
  }
8872
- output(isAsync ? 25 /* TypeIds.AsyncSignal */ : 24 /* TypeIds.ComputedSignal */, out, keepUndefined);
9156
+ this.output(isAsync ? 25 /* TypeIds.AsyncSignal */ : 24 /* TypeIds.ComputedSignal */, out, keepUndefined);
8873
9157
  }
8874
9158
  else {
8875
9159
  const v = value.$untrackedValue$;
@@ -8878,17 +9162,17 @@ async function serialize(serializationContext) {
8878
9162
  if (value.$effects$) {
8879
9163
  out.push(...value.$effects$);
8880
9164
  }
8881
- output(22 /* TypeIds.Signal */, out, keepUndefined);
9165
+ this.output(22 /* TypeIds.Signal */, out, keepUndefined);
8882
9166
  }
8883
9167
  }
8884
9168
  else if (value instanceof URL) {
8885
- output(6 /* TypeIds.URL */, value.href);
9169
+ this.output(6 /* TypeIds.URL */, value.href);
8886
9170
  }
8887
9171
  else if (value instanceof Date) {
8888
- output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
9172
+ this.output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
8889
9173
  }
8890
9174
  else if (value instanceof RegExp) {
8891
- output(8 /* TypeIds.Regex */, value.toString());
9175
+ this.output(8 /* TypeIds.Regex */, value.toString());
8892
9176
  }
8893
9177
  else if (value instanceof Error) {
8894
9178
  const out = [value.message];
@@ -8898,29 +9182,32 @@ async function serialize(serializationContext) {
8898
9182
  if (isDev) {
8899
9183
  out.push('stack', value.stack);
8900
9184
  }
8901
- output(15 /* TypeIds.Error */, out);
9185
+ this.output(15 /* TypeIds.Error */, out);
8902
9186
  }
8903
- else if ($isSsrNode$(value)) {
8904
- const rootIndex = $addRoot$(value);
8905
- serializationContext.$setProp$(value, ELEMENT_ID, String(rootIndex));
9187
+ else if (this.$serializationContext$.$isSsrNode$(value)) {
9188
+ const rootIndex = this.$serializationContext$.$addRoot$(value);
9189
+ this.$serializationContext$.$setProp$(value, ELEMENT_ID, String(rootIndex));
8906
9190
  // we need to output before the vnode overwrites its values
8907
- output(10 /* TypeIds.VNode */, value.id);
9191
+ this.output(10 /* TypeIds.VNode */, value.id);
8908
9192
  const vNodeData = value.vnodeData;
8909
9193
  if (vNodeData) {
8910
- discoverValuesForVNodeData(vNodeData, (vNodeDataValue) => $addRoot$(vNodeDataValue));
9194
+ discoverValuesForVNodeData(vNodeData, (vNodeDataValue) => this.$serializationContext$.$addRoot$(vNodeDataValue));
8911
9195
  vNodeData[0] |= 16 /* VNodeDataFlag.SERIALIZE */;
8912
9196
  }
8913
9197
  if (value.children) {
8914
9198
  // can be static, but we need to save vnode data structure + discover the back refs
8915
- for (const child of value.children) {
9199
+ const childrenLength = value.children.length;
9200
+ for (let i = 0; i < childrenLength; i++) {
9201
+ const child = value.children[i];
8916
9202
  const childVNodeData = child.vnodeData;
8917
9203
  if (childVNodeData) {
8918
9204
  // add all back refs to the roots
8919
- for (const value of childVNodeData) {
9205
+ for (let i = 0; i < childVNodeData.length; i++) {
9206
+ const value = childVNodeData[i];
8920
9207
  if (isSsrAttrs(value)) {
8921
- const backRefKeyIndex = value.findIndex((v) => v === QBackRefs);
8922
- if (backRefKeyIndex !== -1) {
8923
- $addRoot$(value[backRefKeyIndex + 1]);
9208
+ const backRefs = tryGetBackRefs(value);
9209
+ if (backRefs) {
9210
+ this.$serializationContext$.$addRoot$(backRefs);
8924
9211
  }
8925
9212
  }
8926
9213
  }
@@ -8932,28 +9219,25 @@ async function serialize(serializationContext) {
8932
9219
  else if (typeof FormData !== 'undefined' && value instanceof FormData) {
8933
9220
  // FormData is generally used only once so don't bother with references
8934
9221
  const array = [];
8935
- value.forEach((value, key) => {
8936
- if (typeof value === 'string') {
8937
- array.push(key, value);
8938
- }
8939
- else {
8940
- array.push(key, value.name);
9222
+ for (const [k, v] of value.entries()) {
9223
+ if (typeof v === 'string') {
9224
+ array.push(k, v);
8941
9225
  }
8942
- });
8943
- output(28 /* TypeIds.FormData */, array);
9226
+ }
9227
+ this.output(28 /* TypeIds.FormData */, array);
8944
9228
  }
8945
9229
  else if (value instanceof URLSearchParams) {
8946
- output(13 /* TypeIds.URLSearchParams */, value.toString());
9230
+ this.output(13 /* TypeIds.URLSearchParams */, value.toString());
8947
9231
  }
8948
9232
  else if (value instanceof Set) {
8949
- output(17 /* TypeIds.Set */, [...value.values()]);
9233
+ this.output(17 /* TypeIds.Set */, [...value.values()]);
8950
9234
  }
8951
9235
  else if (value instanceof Map) {
8952
9236
  const combined = [];
8953
9237
  for (const [k, v] of value.entries()) {
8954
9238
  combined.push(k, v);
8955
9239
  }
8956
- output(18 /* TypeIds.Map */, combined);
9240
+ this.output(18 /* TypeIds.Map */, combined);
8957
9241
  }
8958
9242
  else if (isJSXNode(value)) {
8959
9243
  const out = [
@@ -8967,7 +9251,7 @@ async function serialize(serializationContext) {
8967
9251
  while (out[out.length - 1] === undefined) {
8968
9252
  out.pop();
8969
9253
  }
8970
- output(29 /* TypeIds.JSXNode */, out);
9254
+ this.output(29 /* TypeIds.JSXNode */, out);
8971
9255
  }
8972
9256
  else if (value instanceof Task) {
8973
9257
  const out = [
@@ -8981,24 +9265,24 @@ async function serialize(serializationContext) {
8981
9265
  while (out[out.length - 1] === undefined) {
8982
9266
  out.pop();
8983
9267
  }
8984
- output(20 /* TypeIds.Task */, out);
9268
+ this.output(20 /* TypeIds.Task */, out);
8985
9269
  }
8986
9270
  else if (isPromise(value)) {
8987
- const forwardRefId = resolvePromise(value, $addRoot$, (resolved, resolvedValue) => {
9271
+ const forwardRefId = this.resolvePromise(value, (resolved, resolvedValue) => {
8988
9272
  return new PromiseResult(16 /* TypeIds.Promise */, resolved, resolvedValue);
8989
9273
  });
8990
- output(2 /* TypeIds.ForwardRef */, forwardRefId);
9274
+ this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
8991
9275
  }
8992
9276
  else if (value instanceof PromiseResult) {
8993
9277
  if (value.$type$ === 26 /* TypeIds.SerializerSignal */) {
8994
9278
  if (value.$qrl$) {
8995
- output(26 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
9279
+ this.output(26 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
8996
9280
  }
8997
9281
  else if (value.$resolved$) {
8998
9282
  // We replace ourselves with this value
8999
- const index = parent.$index$;
9000
- parent = parent.$parent$;
9001
- writeValue(value.$value$, index);
9283
+ const index = this.parent.$index$;
9284
+ this.parent = this.parent.$parent$;
9285
+ this.writeValue(value.$value$, index);
9002
9286
  }
9003
9287
  else {
9004
9288
  console.error(value.$value$);
@@ -9006,95 +9290,97 @@ async function serialize(serializationContext) {
9006
9290
  }
9007
9291
  }
9008
9292
  else {
9009
- output(16 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
9293
+ this.output(16 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
9010
9294
  }
9011
9295
  }
9012
9296
  else if (value instanceof Uint8Array) {
9013
9297
  let buf = '';
9014
- for (const c of value) {
9015
- buf += String.fromCharCode(c);
9298
+ const length = value.length;
9299
+ for (let i = 0; i < length; i++) {
9300
+ buf += String.fromCharCode(value[i]);
9016
9301
  }
9017
9302
  const out = btoa(buf).replace(/=+$/, '');
9018
- output(19 /* TypeIds.Uint8Array */, out);
9303
+ this.output(19 /* TypeIds.Uint8Array */, out);
9019
9304
  }
9020
9305
  else if (value instanceof SerializationWeakRef) {
9021
9306
  const obj = value.$obj$;
9022
9307
  // This will return a fake SeenRef if it's not been seen before
9023
- if (getSeenRefOrOutput(obj, parent.$index$, true)) {
9024
- let forwardRefId = s11nWeakRefs.get(obj);
9308
+ if (this.getSeenRefOrOutput(obj, this.parent.$index$, true)) {
9309
+ let forwardRefId = this.s11nWeakRefs.get(obj);
9025
9310
  if (forwardRefId === undefined) {
9026
- forwardRefId = forwardRefsId++;
9027
- s11nWeakRefs.set(obj, forwardRefId);
9028
- forwardRefs[forwardRefId] = -1;
9311
+ forwardRefId = this.forwardRefsId++;
9312
+ this.s11nWeakRefs.set(obj, forwardRefId);
9313
+ this.forwardRefs[forwardRefId] = -1;
9029
9314
  }
9030
- output(2 /* TypeIds.ForwardRef */, forwardRefId);
9315
+ this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
9031
9316
  }
9032
9317
  }
9033
9318
  else if (vnode_isVNode(value)) {
9034
- output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
9319
+ this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
9035
9320
  }
9036
9321
  else {
9037
9322
  throw qError(20 /* QError.serializeErrorUnknownType */, [typeof value]);
9038
9323
  }
9039
- };
9040
- function resolvePromise(promise, $addRoot$, classCreator) {
9041
- const forwardRefId = forwardRefsId++;
9324
+ }
9325
+ resolvePromise(promise, classCreator) {
9326
+ const forwardRefId = this.forwardRefsId++;
9042
9327
  promise
9043
9328
  .then((resolvedValue) => {
9044
- promises.delete(promise);
9045
- forwardRefs[forwardRefId] = $addRoot$(classCreator(true, resolvedValue));
9329
+ this.promises.delete(promise);
9330
+ this.forwardRefs[forwardRefId] = this.$serializationContext$.$addRoot$(classCreator(true, resolvedValue));
9046
9331
  })
9047
9332
  .catch((err) => {
9048
- promises.delete(promise);
9049
- forwardRefs[forwardRefId] = $addRoot$(classCreator(false, err));
9333
+ this.promises.delete(promise);
9334
+ this.forwardRefs[forwardRefId] = this.$serializationContext$.$addRoot$(classCreator(false, err));
9050
9335
  });
9051
- promises.add(promise);
9336
+ this.promises.add(promise);
9052
9337
  return forwardRefId;
9053
9338
  }
9054
- const outputRoots = async () => {
9055
- $writer$.write('[');
9056
- const { $roots$ } = serializationContext;
9057
- while (rootIdx < $roots$.length || promises.size) {
9058
- if (rootIdx !== 0) {
9059
- $writer$.write(',');
9339
+ async outputRoots() {
9340
+ this.$writer$.write(BRACKET_OPEN);
9341
+ const { $roots$ } = this.$serializationContext$;
9342
+ while (this.rootIdx < $roots$.length || this.promises.size) {
9343
+ if (this.rootIdx !== 0) {
9344
+ this.$writer$.write(COMMA);
9060
9345
  }
9061
9346
  let separator = false;
9062
- for (; rootIdx < $roots$.length; rootIdx++) {
9347
+ for (; this.rootIdx < $roots$.length; this.rootIdx++) {
9063
9348
  if (separator) {
9064
- $writer$.write(',');
9349
+ this.$writer$.write(COMMA);
9065
9350
  }
9066
9351
  else {
9067
9352
  separator = true;
9068
9353
  }
9069
- writeValue($roots$[rootIdx], rootIdx);
9354
+ this.writeValue($roots$[this.rootIdx], this.rootIdx);
9070
9355
  }
9071
- if (promises.size) {
9356
+ if (this.promises.size) {
9072
9357
  try {
9073
- await Promise.race(promises);
9358
+ await Promise.race(this.promises);
9074
9359
  }
9075
9360
  catch {
9076
9361
  // ignore rejections, they will be serialized as rejected promises
9077
9362
  }
9078
9363
  }
9079
9364
  }
9080
- if (forwardRefs.length) {
9081
- let lastIdx = forwardRefs.length - 1;
9082
- while (lastIdx >= 0 && forwardRefs[lastIdx] === -1) {
9365
+ if (this.forwardRefs.length) {
9366
+ let lastIdx = this.forwardRefs.length - 1;
9367
+ while (lastIdx >= 0 && this.forwardRefs[lastIdx] === -1) {
9083
9368
  lastIdx--;
9084
9369
  }
9085
9370
  if (lastIdx >= 0) {
9086
- $writer$.write(',');
9087
- $writer$.write(14 /* TypeIds.ForwardRefs */ + ',');
9088
- const out = lastIdx === forwardRefs.length - 1 ? forwardRefs : forwardRefs.slice(0, lastIdx + 1);
9371
+ this.$writer$.write(COMMA);
9372
+ this.$writer$.write(14 /* TypeIds.ForwardRefs */ + COMMA);
9373
+ const out = lastIdx === this.forwardRefs.length - 1
9374
+ ? this.forwardRefs
9375
+ : this.forwardRefs.slice(0, lastIdx + 1);
9089
9376
  // We could also implement RLE of -1 values
9090
- outputArray(out, true, (value) => {
9091
- $writer$.write(String(value));
9377
+ this.outputArray(out, true, (value) => {
9378
+ this.$writer$.write(String(value));
9092
9379
  });
9093
9380
  }
9094
9381
  }
9095
- $writer$.write(']');
9096
- };
9097
- await outputRoots();
9382
+ this.$writer$.write(BRACKET_CLOSE);
9383
+ }
9098
9384
  }
9099
9385
  class PromiseResult {
9100
9386
  $type$;
@@ -9132,16 +9418,15 @@ function getCustomSerializerPromise(signal, value) {
9132
9418
  });
9133
9419
  }
9134
9420
  const discoverValuesForVNodeData = (vnodeData, callback) => {
9135
- for (const value of vnodeData) {
9421
+ const length = vnodeData.length;
9422
+ for (let i = 0; i < length; i++) {
9423
+ const value = vnodeData[i];
9136
9424
  if (isSsrAttrs(value)) {
9137
- for (let i = 1; i < value.length; i += 2) {
9138
- const keyValue = value[i - 1];
9139
- const attrValue = value[i];
9425
+ for (const key in value) {
9426
+ const attrValue = value[key];
9140
9427
  if (attrValue == null ||
9141
9428
  typeof attrValue === 'string' ||
9142
- // skip empty props
9143
- (keyValue === ELEMENT_PROPS &&
9144
- Object.keys(attrValue).length === 0)) {
9429
+ (key === ELEMENT_PROPS && isObjectEmpty(attrValue))) {
9145
9430
  continue;
9146
9431
  }
9147
9432
  callback(attrValue);
@@ -9149,7 +9434,7 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
9149
9434
  }
9150
9435
  }
9151
9436
  };
9152
- const isSsrAttrs = (value) => Array.isArray(value) && value.length > 0;
9437
+ const isSsrAttrs = (value) => typeof value === 'object' && value !== null && !isObjectEmpty(value);
9153
9438
  /**
9154
9439
  * When serializing the object we need check if it is URL, RegExp, Map, Set, etc. This is time
9155
9440
  * consuming. So if we could know that this is a basic object literal we could skip the check, and
@@ -9187,6 +9472,11 @@ function filterEffectBackRefs(effectBackRef) {
9187
9472
  }
9188
9473
  return effectBackRefToSerialize;
9189
9474
  }
9475
+ function tryGetBackRefs(props) {
9476
+ return Object.prototype.hasOwnProperty.call(props, QBackRefs)
9477
+ ? props[QBackRefs]
9478
+ : undefined;
9479
+ }
9190
9480
  class SerializationWeakRef {
9191
9481
  $obj$;
9192
9482
  constructor($obj$) {
@@ -9209,39 +9499,56 @@ class SerializationBackRef {
9209
9499
  this.$path$ = $path$;
9210
9500
  }
9211
9501
  }
9212
- const createSerializationContext = (
9213
- /**
9214
- * Node constructor, for instanceof checks.
9215
- *
9216
- * A node constructor can be null. For example on the client we can't serialize DOM nodes as
9217
- * server will not know what to do with them.
9218
- */
9219
- NodeConstructor,
9220
- /** DomRef constructor, for instanceof checks. */
9221
- DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, writer) => {
9222
- if (!writer) {
9223
- const buffer = [];
9224
- writer = {
9225
- write: (text) => buffer.push(text),
9226
- toString: () => buffer.join(''),
9227
- };
9228
- }
9229
- const seenObjsMap = new Map();
9230
- const syncFnMap = new Map();
9231
- const syncFns = [];
9232
- const roots = [];
9233
- const eagerResume = new Set();
9234
- const getSeenRef = (obj) => seenObjsMap.get(obj);
9235
- const $markSeen$ = (obj, parent, index) => {
9502
+ class SerializationContextImpl {
9503
+ NodeConstructor;
9504
+ DomRefConstructor;
9505
+ $symbolToChunkResolver$;
9506
+ $setProp$;
9507
+ $storeProxyMap$;
9508
+ $writer$;
9509
+ $seenObjsMap$ = new Map();
9510
+ $syncFnMap$ = new Map();
9511
+ $syncFns$ = [];
9512
+ $roots$ = [];
9513
+ $eagerResume$ = new Set();
9514
+ $eventQrls$ = new Set();
9515
+ $eventNames$ = new Set();
9516
+ $renderSymbols$ = new Set();
9517
+ $serializer$;
9518
+ constructor(
9519
+ /**
9520
+ * Node constructor, for instanceof checks.
9521
+ *
9522
+ * A node constructor can be null. For example on the client we can't serialize DOM nodes as
9523
+ * server will not know what to do with them.
9524
+ */
9525
+ NodeConstructor,
9526
+ /** DomRef constructor, for instanceof checks. */
9527
+ DomRefConstructor, $symbolToChunkResolver$, $setProp$, $storeProxyMap$, $writer$) {
9528
+ this.NodeConstructor = NodeConstructor;
9529
+ this.DomRefConstructor = DomRefConstructor;
9530
+ this.$symbolToChunkResolver$ = $symbolToChunkResolver$;
9531
+ this.$setProp$ = $setProp$;
9532
+ this.$storeProxyMap$ = $storeProxyMap$;
9533
+ this.$writer$ = $writer$;
9534
+ this.$serializer$ = new Serializer(this);
9535
+ }
9536
+ async $serialize$() {
9537
+ return await this.$serializer$.serialize();
9538
+ }
9539
+ getSeenRef(obj) {
9540
+ return this.$seenObjsMap$.get(obj);
9541
+ }
9542
+ $markSeen$(obj, parent, index) {
9236
9543
  const ref = { $index$: index, $parent$: parent };
9237
- seenObjsMap.set(obj, ref);
9544
+ this.$seenObjsMap$.set(obj, ref);
9238
9545
  return ref;
9239
- };
9546
+ }
9240
9547
  /**
9241
9548
  * Returns a path string representing the path from roots through all parents to the object.
9242
9549
  * Format: "3 2 0" where each number is the index within its parent, from root to leaf.
9243
9550
  */
9244
- const $getObjectPath$ = (ref) => {
9551
+ $getObjectPath$(ref) {
9245
9552
  // Traverse up through parent references to build a path
9246
9553
  const path = [];
9247
9554
  while (ref.$parent$) {
@@ -9251,88 +9558,89 @@ DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, write
9251
9558
  // Now we are at root, but it could be a backref
9252
9559
  path.unshift(ref.$index$);
9253
9560
  return path.join(' ');
9254
- };
9255
- const $promoteToRoot$ = (ref, index) => {
9256
- const path = $getObjectPath$(ref);
9561
+ }
9562
+ $promoteToRoot$(ref, index) {
9563
+ const path = this.$getObjectPath$(ref);
9257
9564
  if (index === undefined) {
9258
- index = roots.length;
9565
+ index = this.$roots$.length;
9259
9566
  }
9260
- roots[index] = new SerializationBackRef(path);
9567
+ this.$roots$[index] = new SerializationBackRef(path);
9261
9568
  ref.$parent$ = null;
9262
9569
  ref.$index$ = index;
9263
- };
9264
- const $addRoot$ = ((obj, returnRef) => {
9265
- let seen = seenObjsMap.get(obj);
9570
+ }
9571
+ $addRoot$(obj, returnRef = false) {
9572
+ let seen = this.$seenObjsMap$.get(obj);
9266
9573
  let index;
9267
9574
  if (!seen) {
9268
- index = roots.length;
9575
+ index = this.$roots$.length;
9269
9576
  seen = {
9270
9577
  $index$: index,
9271
9578
  // TODO benchmark with and without $parent$
9272
9579
  // $parent$: undefined
9273
9580
  };
9274
- seenObjsMap.set(obj, seen);
9275
- roots.push(obj);
9581
+ this.$seenObjsMap$.set(obj, seen);
9582
+ this.$roots$.push(obj);
9276
9583
  }
9277
9584
  else {
9278
9585
  if (seen.$parent$) {
9279
- $promoteToRoot$(seen);
9586
+ this.$promoteToRoot$(seen);
9280
9587
  }
9281
9588
  index = seen.$index$;
9282
9589
  }
9283
9590
  return returnRef ? seen : index;
9284
- });
9285
- const isSsrNode = (NodeConstructor ? (obj) => obj instanceof NodeConstructor : (() => false));
9286
- isDomRef = (DomRefConstructor ? (obj) => obj instanceof DomRefConstructor : (() => false));
9287
- return {
9288
- async $serialize$() {
9289
- return await serialize(this);
9290
- },
9291
- $isSsrNode$: isSsrNode,
9292
- $isDomRef$: isDomRef,
9293
- $symbolToChunkResolver$: symbolToChunkResolver,
9294
- getSeenRef,
9295
- $roots$: roots,
9296
- $markSeen$,
9297
- $hasRootId$: (obj) => {
9298
- const id = seenObjsMap.get(obj);
9299
- return id && (id.$parent$ ? undefined : id.$index$);
9300
- },
9301
- $promoteToRoot$,
9302
- $addRoot$,
9303
- $syncFns$: syncFns,
9304
- $addSyncFn$: (funcStr, argCount, fn) => {
9305
- const isFullFn = funcStr == null;
9591
+ }
9592
+ $isSsrNode$(obj) {
9593
+ return this.NodeConstructor ? obj instanceof this.NodeConstructor : false;
9594
+ }
9595
+ $isDomRef$(obj) {
9596
+ return this.DomRefConstructor ? obj instanceof this.DomRefConstructor : false;
9597
+ }
9598
+ $hasRootId$(obj) {
9599
+ const id = this.$seenObjsMap$.get(obj);
9600
+ return id && (id.$parent$ ? undefined : id.$index$);
9601
+ }
9602
+ $addSyncFn$(funcStr, argCount, fn) {
9603
+ const isFullFn = funcStr == null;
9604
+ if (isFullFn) {
9605
+ funcStr = fn.serialized || fn.toString();
9606
+ }
9607
+ let id = this.$syncFnMap$.get(funcStr);
9608
+ if (id === undefined) {
9609
+ id = this.$syncFns$.length;
9610
+ this.$syncFnMap$.set(funcStr, id);
9306
9611
  if (isFullFn) {
9307
- funcStr = fn.serialized || fn.toString();
9612
+ this.$syncFns$.push(funcStr);
9308
9613
  }
9309
- let id = syncFnMap.get(funcStr);
9310
- if (id === undefined) {
9311
- id = syncFns.length;
9312
- syncFnMap.set(funcStr, id);
9313
- if (isFullFn) {
9314
- syncFns.push(funcStr);
9315
- }
9316
- else {
9317
- let code = '(';
9318
- for (let i = 0; i < argCount; i++) {
9319
- code += (i == 0 ? 'p' : ',p') + i;
9320
- }
9321
- syncFns.push((code += ')=>' + funcStr));
9614
+ else {
9615
+ let code = '(';
9616
+ for (let i = 0; i < argCount; i++) {
9617
+ code += (i == 0 ? 'p' : ',p') + i;
9322
9618
  }
9619
+ this.$syncFns$.push((code += ')=>' + funcStr));
9323
9620
  }
9324
- return id;
9325
- },
9326
- $writer$: writer,
9327
- $eventQrls$: new Set(),
9328
- $eventNames$: new Set(),
9329
- $renderSymbols$: new Set(),
9330
- $storeProxyMap$: storeProxyMap,
9331
- $eagerResume$: eagerResume,
9332
- $resources$: new Set(),
9333
- $getProp$: getProp,
9334
- $setProp$: setProp,
9335
- };
9621
+ }
9622
+ return id;
9623
+ }
9624
+ }
9625
+ const createSerializationContext = (
9626
+ /**
9627
+ * Node constructor, for instanceof checks.
9628
+ *
9629
+ * A node constructor can be null. For example on the client we can't serialize DOM nodes as
9630
+ * server will not know what to do with them.
9631
+ */
9632
+ NodeConstructor,
9633
+ /** DomRef constructor, for instanceof checks. */
9634
+ DomRefConstructor, symbolToChunkResolver, setProp, storeProxyMap, writer) => {
9635
+ if (!writer) {
9636
+ const buffer = [];
9637
+ writer = {
9638
+ write: (text) => buffer.push(text),
9639
+ toString: () => buffer.join(''),
9640
+ };
9641
+ }
9642
+ isDomRef = (DomRefConstructor ? (obj) => obj instanceof DomRefConstructor : (() => false));
9643
+ return new SerializationContextImpl(NodeConstructor, DomRefConstructor, symbolToChunkResolver, setProp, storeProxyMap, writer);
9336
9644
  };
9337
9645
 
9338
9646
  /** @internal */
@@ -9363,7 +9671,7 @@ class _SharedContainer {
9363
9671
  return trackSignalAndAssignHost(signal, subscriber, property, this, data);
9364
9672
  }
9365
9673
  serializationCtxFactory(NodeConstructor, DomRefConstructor, symbolToChunkResolver, writer) {
9366
- return createSerializationContext(NodeConstructor, DomRefConstructor, symbolToChunkResolver, this.getHostProp.bind(this), this.setHostProp.bind(this), this.$storeProxyMap$, writer);
9674
+ return createSerializationContext(NodeConstructor, DomRefConstructor, symbolToChunkResolver, this.setHostProp.bind(this), this.$storeProxyMap$, writer);
9367
9675
  }
9368
9676
  $checkPendingCount$() {
9369
9677
  if (this.$pendingCount$ === 0) {
@@ -9396,16 +9704,14 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
9396
9704
  return executeComponent(ssr, host, host, componentQrl, srcProps);
9397
9705
  };
9398
9706
 
9399
- class ParentComponentData {
9400
- $scopedStyle$;
9401
- $componentFrame$;
9402
- constructor($scopedStyle$, $componentFrame$) {
9403
- this.$scopedStyle$ = $scopedStyle$;
9404
- this.$componentFrame$ = $componentFrame$;
9405
- }
9406
- }
9407
9707
  class MaybeAsyncSignal {
9408
9708
  }
9709
+ function setParentOptions(mutable, styleScoped, parentComponentFrame) {
9710
+ return () => {
9711
+ mutable.currentStyleScoped = styleScoped;
9712
+ mutable.parentComponentFrame = parentComponentFrame;
9713
+ };
9714
+ }
9409
9715
  /** @internal */
9410
9716
  async function _walkJSX(ssr, value, options) {
9411
9717
  const stack = [value];
@@ -9413,32 +9719,22 @@ async function _walkJSX(ssr, value, options) {
9413
9719
  const drain = async () => {
9414
9720
  while (stack.length) {
9415
9721
  const value = stack.pop();
9416
- if (value instanceof ParentComponentData) {
9417
- options.currentStyleScoped = value.$scopedStyle$;
9418
- options.parentComponentFrame = value.$componentFrame$;
9419
- continue;
9420
- }
9421
- else if (value === MaybeAsyncSignal) {
9422
- // It could be an async signal, but it is not resolved yet, we need to wait for it.
9423
- // We could do that in the processJSXNode,
9424
- // but it will mean that we need to await it there, and it will return a promise.
9425
- // We probably want to avoid creating a promise for all jsx nodes.
9722
+ // Reference equality first (no prototype walk), then typeof
9723
+ if (value === MaybeAsyncSignal) {
9426
9724
  const trackFn = stack.pop();
9427
9725
  await retryOnPromise(() => stack.push(trackFn()));
9428
9726
  continue;
9429
9727
  }
9430
- else if (typeof value === 'function') {
9728
+ if (typeof value === 'function') {
9431
9729
  if (value === Promise) {
9432
9730
  stack.push(await stack.pop());
9433
- continue;
9434
9731
  }
9435
- await value.apply(ssr);
9732
+ else {
9733
+ await value.apply(ssr);
9734
+ }
9436
9735
  continue;
9437
9736
  }
9438
- processJSXNode(ssr, enqueue, value, {
9439
- styleScoped: options.currentStyleScoped,
9440
- parentComponentFrame: options.parentComponentFrame,
9441
- });
9737
+ processJSXNode(ssr, enqueue, value, options);
9442
9738
  }
9443
9739
  };
9444
9740
  await drain();
@@ -9465,7 +9761,7 @@ function processJSXNode(ssr, enqueue, value, options) {
9465
9761
  }
9466
9762
  else if (isSignal(value)) {
9467
9763
  maybeAddPollingAsyncSignalToEagerResume(ssr.serializationCtx, value);
9468
- ssr.openFragment(isDev ? [DEBUG_TYPE, "S" /* VirtualType.WrappedSignal */] : EMPTY_ARRAY);
9764
+ ssr.openFragment(isDev ? { [DEBUG_TYPE]: "S" /* VirtualType.WrappedSignal */ } : EMPTY_OBJ);
9469
9765
  const signalNode = ssr.getOrCreateLastNode();
9470
9766
  const unwrappedSignal = value instanceof WrappedSignalImpl ? value.$unwrapIfSignal$() : value;
9471
9767
  enqueue(ssr.closeFragment);
@@ -9473,20 +9769,20 @@ function processJSXNode(ssr, enqueue, value, options) {
9473
9769
  enqueue(MaybeAsyncSignal);
9474
9770
  }
9475
9771
  else if (isPromise(value)) {
9476
- ssr.openFragment(isDev ? [DEBUG_TYPE, "A" /* VirtualType.Awaited */] : EMPTY_ARRAY);
9772
+ ssr.openFragment(isDev ? { [DEBUG_TYPE]: "A" /* VirtualType.Awaited */ } : EMPTY_OBJ);
9477
9773
  enqueue(ssr.closeFragment);
9478
9774
  enqueue(value);
9479
9775
  enqueue(Promise);
9480
- enqueue(() => ssr.commentNode(FLUSH_COMMENT));
9776
+ enqueue(() => ssr.streamHandler.flush());
9481
9777
  }
9482
9778
  else if (isAsyncGenerator(value)) {
9483
9779
  enqueue(async () => {
9484
9780
  for await (const chunk of value) {
9485
9781
  await _walkJSX(ssr, chunk, {
9486
- currentStyleScoped: options.styleScoped,
9782
+ currentStyleScoped: options.currentStyleScoped,
9487
9783
  parentComponentFrame: options.parentComponentFrame,
9488
9784
  });
9489
- ssr.commentNode(FLUSH_COMMENT);
9785
+ ssr.streamHandler.flush();
9490
9786
  }
9491
9787
  });
9492
9788
  }
@@ -9495,7 +9791,7 @@ function processJSXNode(ssr, enqueue, value, options) {
9495
9791
  const type = jsx.type;
9496
9792
  // Below, JSXChildren allows functions and regexes, but we assume the dev only uses those as appropriate.
9497
9793
  if (typeof type === 'string') {
9498
- appendClassIfScopedStyleExists(jsx, options.styleScoped);
9794
+ appendClassIfScopedStyleExists(jsx, options.currentStyleScoped);
9499
9795
  let qwikInspectorAttrValue = null;
9500
9796
  if (isDev && jsx.dev && jsx.type !== 'head') {
9501
9797
  qwikInspectorAttrValue = getFileLocationFromJsx(jsx.dev);
@@ -9503,14 +9799,7 @@ function processJSXNode(ssr, enqueue, value, options) {
9503
9799
  appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue);
9504
9800
  }
9505
9801
  }
9506
- const innerHTML = ssr.openElement(type, jsx.key, toSsrAttrs(jsx.varProps, {
9507
- serializationCtx: ssr.serializationCtx,
9508
- styleScopedId: options.styleScoped,
9509
- toSort: jsx.toSort,
9510
- }), toSsrAttrs(jsx.constProps, {
9511
- serializationCtx: ssr.serializationCtx,
9512
- styleScopedId: options.styleScoped,
9513
- }), qwikInspectorAttrValue);
9802
+ const innerHTML = ssr.openElement(type, jsx.key, jsx.varProps, jsx.constProps, options.currentStyleScoped, qwikInspectorAttrValue);
9514
9803
  if (innerHTML) {
9515
9804
  ssr.htmlNode(innerHTML);
9516
9805
  }
@@ -9533,9 +9822,9 @@ function processJSXNode(ssr, enqueue, value, options) {
9533
9822
  }
9534
9823
  else if (isFunction(type)) {
9535
9824
  if (type === Fragment) {
9536
- let attrs = jsx.key != null ? [ELEMENT_KEY, jsx.key] : EMPTY_ARRAY;
9825
+ const attrs = jsx.key != null ? { [ELEMENT_KEY]: jsx.key } : {};
9537
9826
  if (isDev) {
9538
- attrs = [DEBUG_TYPE, "F" /* VirtualType.Fragment */, ...attrs]; // Add debug info.
9827
+ attrs[DEBUG_TYPE] = "F" /* VirtualType.Fragment */; // Add debug info.
9539
9828
  }
9540
9829
  ssr.openFragment(attrs);
9541
9830
  enqueue(ssr.closeFragment);
@@ -9547,14 +9836,16 @@ function processJSXNode(ssr, enqueue, value, options) {
9547
9836
  const componentFrame = options.parentComponentFrame;
9548
9837
  if (componentFrame) {
9549
9838
  const compId = componentFrame.componentNode.id || '';
9550
- const projectionAttrs = isDev ? [DEBUG_TYPE, "P" /* VirtualType.Projection */] : [];
9551
- projectionAttrs.push(QSlotParent, compId);
9839
+ const projectionAttrs = isDev
9840
+ ? { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ }
9841
+ : {};
9842
+ projectionAttrs[QSlotParent] = compId;
9552
9843
  ssr.openProjection(projectionAttrs);
9553
9844
  const host = componentFrame.componentNode;
9554
9845
  const node = ssr.getOrCreateLastNode();
9555
9846
  const slotName = getSlotName(host, jsx, ssr);
9556
- projectionAttrs.push(QSlot, slotName);
9557
- enqueue(new ParentComponentData(options.styleScoped, options.parentComponentFrame));
9847
+ projectionAttrs[QSlot] = slotName;
9848
+ enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
9558
9849
  enqueue(ssr.closeProjection);
9559
9850
  const slotDefaultChildren = jsx.children || null;
9560
9851
  const slotChildren = componentFrame.consumeChildrenForSlot(node, slotName) || slotDefaultChildren;
@@ -9562,11 +9853,15 @@ function processJSXNode(ssr, enqueue, value, options) {
9562
9853
  ssr.addUnclaimedProjection(componentFrame, QDefaultSlot, slotDefaultChildren);
9563
9854
  }
9564
9855
  enqueue(slotChildren);
9565
- enqueue(new ParentComponentData(componentFrame.projectionScopedStyle, componentFrame.projectionComponentFrame));
9856
+ enqueue(setParentOptions(options, componentFrame.projectionScopedStyle, componentFrame.projectionComponentFrame));
9566
9857
  }
9567
9858
  else {
9568
9859
  // Even thought we are not projecting we still need to leave a marker for the slot.
9569
- ssr.openFragment(isDev ? [DEBUG_TYPE, "P" /* VirtualType.Projection */] : EMPTY_ARRAY);
9860
+ let projectionAttrs = EMPTY_OBJ;
9861
+ if (isDev) {
9862
+ projectionAttrs = { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ };
9863
+ }
9864
+ ssr.openFragment(projectionAttrs);
9570
9865
  ssr.closeFragment();
9571
9866
  }
9572
9867
  }
@@ -9574,17 +9869,17 @@ function processJSXNode(ssr, enqueue, value, options) {
9574
9869
  ssr.commentNode(directGetPropsProxyProp(jsx, 'data') || '');
9575
9870
  }
9576
9871
  else if (type === SSRStream) {
9577
- ssr.commentNode(FLUSH_COMMENT);
9872
+ ssr.streamHandler.flush();
9578
9873
  const generator = jsx.children;
9579
9874
  let value;
9580
9875
  if (isFunction(generator)) {
9581
9876
  value = generator({
9582
9877
  async write(chunk) {
9583
9878
  await _walkJSX(ssr, chunk, {
9584
- currentStyleScoped: options.styleScoped,
9879
+ currentStyleScoped: options.currentStyleScoped,
9585
9880
  parentComponentFrame: options.parentComponentFrame,
9586
9881
  });
9587
- ssr.commentNode(FLUSH_COMMENT);
9882
+ ssr.streamHandler.flush();
9588
9883
  },
9589
9884
  });
9590
9885
  }
@@ -9597,14 +9892,23 @@ function processJSXNode(ssr, enqueue, value, options) {
9597
9892
  else if (type === SSRRaw) {
9598
9893
  ssr.htmlNode(directGetPropsProxyProp(jsx, 'data'));
9599
9894
  }
9895
+ else if (type === SSRStreamBlock) {
9896
+ ssr.streamHandler.streamBlockStart();
9897
+ enqueue(() => ssr.streamHandler.streamBlockEnd());
9898
+ enqueue(jsx.children);
9899
+ }
9600
9900
  else if (isQwikComponent(type)) {
9601
- // prod: use new instance of an array for props, we always modify props for a component
9602
- ssr.openComponent(isDev ? [DEBUG_TYPE, "C" /* VirtualType.Component */] : []);
9901
+ // prod: use new instance of an object for props, we always modify props for a component
9902
+ const componentAttrs = {};
9903
+ if (isDev) {
9904
+ componentAttrs[DEBUG_TYPE] = "C" /* VirtualType.Component */;
9905
+ }
9906
+ ssr.openComponent(componentAttrs);
9603
9907
  const host = ssr.getOrCreateLastNode();
9604
9908
  const componentFrame = ssr.getParentComponentFrame();
9605
- componentFrame.distributeChildrenIntoSlots(jsx.children, options.styleScoped, options.parentComponentFrame);
9909
+ componentFrame.distributeChildrenIntoSlots(jsx.children, options.currentStyleScoped, options.parentComponentFrame);
9606
9910
  const jsxOutput = applyQwikComponentBody(ssr, jsx, type);
9607
- enqueue(new ParentComponentData(options.styleScoped, options.parentComponentFrame));
9911
+ enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
9608
9912
  enqueue(ssr.closeComponent);
9609
9913
  if (isPromise(jsxOutput)) {
9610
9914
  // Defer reading QScopedStyle until after the promise resolves
@@ -9612,22 +9916,23 @@ function processJSXNode(ssr, enqueue, value, options) {
9612
9916
  const resolvedOutput = await jsxOutput;
9613
9917
  const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
9614
9918
  enqueue(resolvedOutput);
9615
- enqueue(new ParentComponentData(compStyleComponentId, componentFrame));
9919
+ enqueue(setParentOptions(options, compStyleComponentId, componentFrame));
9616
9920
  });
9617
9921
  }
9618
9922
  else {
9619
9923
  enqueue(jsxOutput);
9620
9924
  const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
9621
- enqueue(new ParentComponentData(compStyleComponentId, componentFrame));
9925
+ enqueue(setParentOptions(options, compStyleComponentId, componentFrame));
9622
9926
  }
9623
9927
  }
9624
9928
  else {
9625
- const inlineComponentProps = [ELEMENT_KEY, jsx.key];
9626
- ssr.openFragment(isDev
9627
- ? [DEBUG_TYPE, "I" /* VirtualType.InlineComponent */, ...inlineComponentProps]
9628
- : inlineComponentProps);
9929
+ const inlineComponentProps = { [ELEMENT_KEY]: jsx.key };
9930
+ if (isDev) {
9931
+ inlineComponentProps[DEBUG_TYPE] = "I" /* VirtualType.InlineComponent */;
9932
+ }
9933
+ ssr.openFragment(inlineComponentProps);
9629
9934
  enqueue(ssr.closeFragment);
9630
- const component = ssr.getComponentFrame(0);
9935
+ const component = ssr.getParentComponentFrame();
9631
9936
  const jsxOutput = applyInlineComponent(ssr, component && component.componentNode, type, jsx);
9632
9937
  enqueue(jsxOutput);
9633
9938
  isPromise(jsxOutput) && enqueue(Promise);
@@ -9636,112 +9941,6 @@ function processJSXNode(ssr, enqueue, value, options) {
9636
9941
  }
9637
9942
  }
9638
9943
  }
9639
- function toSsrAttrs(record, options) {
9640
- if (record == null) {
9641
- return null;
9642
- }
9643
- const ssrAttrs = [];
9644
- const handleProp = (key, value) => {
9645
- if (value == null) {
9646
- return;
9647
- }
9648
- if (isHtmlAttributeAnEventName(key)) {
9649
- const eventValue = setEvent(options.serializationCtx, key, value);
9650
- if (eventValue) {
9651
- ssrAttrs.push(key, eventValue);
9652
- }
9653
- return;
9654
- }
9655
- if (isSignal(value)) {
9656
- maybeAddPollingAsyncSignalToEagerResume(options.serializationCtx, value);
9657
- // write signal as is. We will track this signal inside `writeAttrs`
9658
- if (isClassAttr(key)) {
9659
- // additionally append styleScopedId for class attr
9660
- ssrAttrs.push(key, [value, options.styleScopedId]);
9661
- }
9662
- else {
9663
- ssrAttrs.push(key, value);
9664
- }
9665
- return;
9666
- }
9667
- if (isPreventDefault(key)) {
9668
- addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
9669
- }
9670
- else if (key === ITERATION_ITEM_SINGLE || key === ITERATION_ITEM_MULTI) {
9671
- value = options.serializationCtx.$addRoot$(value);
9672
- }
9673
- value = serializeAttribute(key, value, options.styleScopedId);
9674
- ssrAttrs.push(key, value);
9675
- };
9676
- if (options.toSort) {
9677
- const keys = Object.keys(record).sort();
9678
- for (const key of keys) {
9679
- handleProp(key, record[key]);
9680
- }
9681
- }
9682
- else {
9683
- for (const key in record) {
9684
- handleProp(key, record[key]);
9685
- }
9686
- }
9687
- return ssrAttrs;
9688
- }
9689
- function setEvent(serializationCtx, key, rawValue) {
9690
- let value = null;
9691
- const qrls = rawValue;
9692
- const appendToValue = (valueToAppend) => {
9693
- value = (value == null ? '' : value + '|') + valueToAppend;
9694
- };
9695
- const getQrlString = (qrl) => {
9696
- /**
9697
- * If there are captures we need to schedule so everything is executed in the right order + qrls
9698
- * are resolved.
9699
- *
9700
- * For internal qrls (starting with `_`) we assume that they do the right thing.
9701
- */
9702
- if (!qrl.$symbol$.startsWith('_') && qrl.$captures$?.length) {
9703
- qrl = createQRL(null, '_run', _run, null, [qrl]);
9704
- }
9705
- return qrlToString(serializationCtx, qrl);
9706
- };
9707
- if (Array.isArray(qrls)) {
9708
- for (let i = 0; i <= qrls.length; i++) {
9709
- const qrl = qrls[i];
9710
- if (isQrl(qrl)) {
9711
- appendToValue(getQrlString(qrl));
9712
- addQwikEventToSerializationContext(serializationCtx, key, qrl);
9713
- }
9714
- else if (qrl != null) {
9715
- // nested arrays etc.
9716
- const nestedValue = setEvent(serializationCtx, key, qrl);
9717
- if (nestedValue) {
9718
- appendToValue(nestedValue);
9719
- }
9720
- }
9721
- }
9722
- }
9723
- else if (isQrl(qrls)) {
9724
- value = getQrlString(qrls);
9725
- addQwikEventToSerializationContext(serializationCtx, key, qrls);
9726
- }
9727
- return value;
9728
- }
9729
- function addQwikEventToSerializationContext(serializationCtx, key, qrl) {
9730
- const data = getEventDataFromHtmlAttribute(key);
9731
- if (data) {
9732
- const [scope, eventName] = data;
9733
- const scopedEvent = getScopedEventName(scope, eventName);
9734
- serializationCtx.$eventNames$.add(scopedEvent);
9735
- serializationCtx.$eventQrls$.add(qrl);
9736
- }
9737
- }
9738
- function addPreventDefaultEventToSerializationContext(serializationCtx, key) {
9739
- // skip the `preventdefault`, leave the ':'
9740
- const eventName = 'e' + key.substring(14);
9741
- if (eventName) {
9742
- serializationCtx.$eventNames$.add(eventName);
9743
- }
9744
- }
9745
9944
  function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
9746
9945
  // Unwrap if it's a WrappedSignalImpl
9747
9946
  const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
@@ -9912,6 +10111,57 @@ const isResourceReturn = (obj) => {
9912
10111
  return obj && obj.__brand === 'resource';
9913
10112
  };
9914
10113
 
10114
+ /** @internal */
10115
+ function setEvent(serializationCtx, key, rawValue, isLoopElement) {
10116
+ let value = null;
10117
+ const qrls = rawValue;
10118
+ const appendToValue = (valueToAppend) => {
10119
+ value = (value == null ? '' : value + '|') + valueToAppend;
10120
+ };
10121
+ const getQrlString = (qrl) => {
10122
+ /**
10123
+ * If there are captures we need to schedule so everything is executed in the right order + qrls
10124
+ * are resolved.
10125
+ *
10126
+ * For internal qrls (starting with `_`) we assume that they do the right thing.
10127
+ */
10128
+ if (!qrl.$symbol$.startsWith('_') && (qrl.$captures$?.length || isLoopElement)) {
10129
+ qrl = createQRL(null, '_run', _run, null, [qrl]);
10130
+ }
10131
+ return qrlToString(serializationCtx, qrl);
10132
+ };
10133
+ if (Array.isArray(qrls)) {
10134
+ for (let i = 0; i < qrls.length; i++) {
10135
+ const qrl = qrls[i];
10136
+ if (isQrl(qrl)) {
10137
+ appendToValue(getQrlString(qrl));
10138
+ addQwikEventToSerializationContext(serializationCtx, key, qrl);
10139
+ }
10140
+ else if (qrl != null) {
10141
+ // nested arrays etc.
10142
+ const nestedValue = setEvent(serializationCtx, key, qrl, isLoopElement);
10143
+ if (nestedValue) {
10144
+ appendToValue(nestedValue);
10145
+ }
10146
+ }
10147
+ }
10148
+ }
10149
+ else if (isQrl(qrls)) {
10150
+ value = getQrlString(qrls);
10151
+ addQwikEventToSerializationContext(serializationCtx, key, qrls);
10152
+ }
10153
+ return value;
10154
+ }
10155
+ function addQwikEventToSerializationContext(serializationCtx, key, qrl) {
10156
+ const data = getEventDataFromHtmlAttribute(key);
10157
+ if (data) {
10158
+ const [scope, eventName] = data;
10159
+ const scopedEvent = getScopedEventName(scope, eventName);
10160
+ serializationCtx.$eventNames$.add(scopedEvent);
10161
+ serializationCtx.$eventQrls$.add(qrl);
10162
+ }
10163
+ }
10164
+
9915
10165
  let loading = Promise.resolve();
9916
10166
  const inflate = (container, target, typeId, data) => {
9917
10167
  if (typeId === 0 /* TypeIds.Plain */) {
@@ -9999,21 +10249,23 @@ const inflate = (container, target, typeId, data) => {
9999
10249
  asyncSignal.$loadingEffects$ = new Set(d[3]);
10000
10250
  asyncSignal.$errorEffects$ = new Set(d[4]);
10001
10251
  asyncSignal.$untrackedError$ = d[5];
10002
- const hasValue = d.length > 6;
10252
+ asyncSignal.$flags$ = d[6] ?? 0;
10253
+ if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
10254
+ // If it's client only, it was serialized because it pretended to be loading
10255
+ asyncSignal.$untrackedLoading$ = true;
10256
+ }
10257
+ const hasValue = d.length > 7;
10003
10258
  if (hasValue) {
10004
- asyncSignal.$untrackedValue$ = d[6];
10259
+ asyncSignal.$untrackedValue$ = d[7];
10005
10260
  }
10006
- if (asyncSignal.$untrackedValue$ !== NEEDS_COMPUTATION) {
10007
- // If we have a value after SSR, it will always be mean the signal was not invalid
10008
- asyncSignal.$flags$ &= -2 /* SignalFlags.INVALID */;
10261
+ // can happen when never serialize etc
10262
+ if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
10263
+ asyncSignal.$flags$ |= 1 /* SignalFlags.INVALID */;
10009
10264
  }
10010
10265
  // Note, we use the setter so that it schedules polling if needed
10011
- asyncSignal.interval = d[7] ?? 0;
10012
- asyncSignal.$concurrency$ = d[8] ?? 1;
10013
- asyncSignal.$timeoutMs$ = d[9] ?? 0;
10014
- if (d[10]) {
10015
- asyncSignal.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
10016
- }
10266
+ asyncSignal.interval = (d[8] ?? 0);
10267
+ asyncSignal.$concurrency$ = (d[9] ?? 1);
10268
+ asyncSignal.$timeoutMs$ = (d[10] ?? 0);
10017
10269
  break;
10018
10270
  }
10019
10271
  // Inflating a SerializerSignal is the same as inflating a ComputedSignal
@@ -10356,7 +10608,6 @@ function processVNodeData(document) {
10356
10608
  // Process all of the `qwik/vnode` script tags by attaching them to the corresponding containers.
10357
10609
  const attachVnodeDataAndRefs = (element) => {
10358
10610
  Array.from(element.querySelectorAll('script[type="qwik/vnode"]')).forEach((script) => {
10359
- script.setAttribute('type', 'x-qwik/vnode');
10360
10611
  const qContainerElement = script.closest('[q\\:container]');
10361
10612
  qContainerElement.qVnodeData = script.textContent;
10362
10613
  qContainerElement.qVNodeRefs = new Map();
@@ -10673,9 +10924,14 @@ class DomContainer extends _SharedContainer {
10673
10924
  $hoistStyles$() {
10674
10925
  const document = this.element.ownerDocument;
10675
10926
  const head = document.head;
10676
- const styles = document.querySelectorAll(QStylesAllSelector);
10677
- for (let i = 0; i < styles.length; i++) {
10678
- head.appendChild(styles[i]);
10927
+ const styles = document.body.querySelectorAll(QStylesAllSelector);
10928
+ const styleTagCount = styles.length;
10929
+ if (styleTagCount) {
10930
+ const fragment = document.createDocumentFragment();
10931
+ for (let i = 0; i < styleTagCount; i++) {
10932
+ fragment.appendChild(styles[i]);
10933
+ }
10934
+ head.appendChild(fragment);
10679
10935
  }
10680
10936
  }
10681
10937
  $setRawState$(id, vParent) {
@@ -11649,7 +11905,7 @@ function preprocessState(data, container) {
11649
11905
  * @internal
11650
11906
  */
11651
11907
  async function _serialize(data) {
11652
- const serializationContext = createSerializationContext(null, null, () => '', () => '', () => { }, new WeakMap());
11908
+ const serializationContext = createSerializationContext(null, null, () => '', () => { }, new WeakMap());
11653
11909
  serializationContext.$addRoot$(data);
11654
11910
  await serializationContext.$serialize$();
11655
11911
  return serializationContext.$writer$.toString();
@@ -11786,7 +12042,7 @@ const shouldSerialize = (obj) => {
11786
12042
  const fastSkipSerialize = (obj) => {
11787
12043
  return (!!obj &&
11788
12044
  (isObject(obj) || typeof obj === 'function') &&
11789
- (NoSerializeSymbol in obj || noSerializeSet.has(obj)));
12045
+ (noSerializeSet.has(obj) || NoSerializeSymbol in obj));
11790
12046
  };
11791
12047
  // <docs markdown="../../readme.md#noSerialize">
11792
12048
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -12037,12 +12293,9 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, captures) => {
12037
12293
  return symbolRef;
12038
12294
  }));
12039
12295
  }
12040
- if (isBrowser && symbol) {
12041
- /**
12042
- * Preloading the symbol instead of the chunk allows us to get probabilities for the bundle
12043
- * based on its contents.
12044
- */
12045
- p(symbol, 0.8);
12296
+ if (isBrowser && chunk) {
12297
+ /** Preloading the chunk when we create the QRL. */
12298
+ p(chunk, 0.8);
12046
12299
  }
12047
12300
  return qrl;
12048
12301
  };
@@ -12672,12 +12925,12 @@ const a = 97; // `a`.charCodeAt(0);
12672
12925
  const z = 122; // `z`.charCodeAt(0);
12673
12926
  const OPEN_BRACE = 123; // `{`.charCodeAt(0);
12674
12927
  const CLOSE_BRACE = 125; // `}`.charCodeAt(0);
12675
- const STRINGS_COMMENTS = /*__PURE__*/ (() => [
12928
+ const STRINGS_COMMENTS = /*@__PURE__*/ (() => [
12676
12929
  [ANY, SINGLE_QUOTE, stringSingle],
12677
12930
  [ANY, DOUBLE_QUOTE, stringDouble],
12678
12931
  [ANY, FORWARD_SLASH, commentMultiline, '*'],
12679
12932
  ])();
12680
- const STATE_MACHINE = /*__PURE__*/ (() => [
12933
+ const STATE_MACHINE = /*@__PURE__*/ (() => [
12681
12934
  [
12682
12935
  /// rule
12683
12936
  [ANY, STAR, starSelector],
@@ -13105,6 +13358,7 @@ const useConstant = (value, ...args) => {
13105
13358
  if (val != null) {
13106
13359
  return val;
13107
13360
  }
13361
+ // We don't want to create a subscription since we only run this once
13108
13362
  // Note: We are not using `invoke` here because we don't want to clear the context
13109
13363
  value = isFunction(value) && !isQwikComponent(value) ? untrack(value, ...args) : value;
13110
13364
  return set(value);
@@ -13488,11 +13742,7 @@ const PrefetchGraph = (_opts = {}) => null;
13488
13742
  // Protect against duplicate imports
13489
13743
  //////////////////////////////////////////////////////////////////////////////////////////
13490
13744
  if (globalThis.__qwik) {
13491
- console.error(`==============================================\n` +
13492
- `Qwik version ${globalThis.__qwik} already imported while importing ${version}.\n` +
13493
- `This can lead to issues due to duplicated shared structures.\n` +
13494
- `Verify that the Qwik libraries you're using are in "resolve.noExternal[]" and in "optimizeDeps.exclude".\n` +
13495
- `==============================================\n`);
13745
+ qError(30 /* QError.duplicateQwik */, [globalThis.__qwik, version]);
13496
13746
  }
13497
13747
  globalThis.__qwik = version;
13498
13748
  if (import.meta.hot) {
@@ -13501,5 +13751,5 @@ if (import.meta.hot) {
13501
13751
  });
13502
13752
  }
13503
13753
 
13504
- export { $, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _captures, _chk, createQRL as _createQRL, _deserialize, _dumpState, _executeSsrChores, _fnSignal, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _regSymbol, _res, _resolveContextWithoutSequentialScope, _restProps, _rsc, _run, _serialize, scheduleTask as _task, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getFirstChild as _vnode_getFirstChild, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsync$, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsync$, useAsyncQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
13754
+ export { $, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _captures, _chk, createQRL as _createQRL, _deserialize, _dumpState, _executeSsrChores, _fnSignal, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _regSymbol, _res, _resolveContextWithoutSequentialScope, _restProps, _rsc, _run, _serialize, setEvent as _setEvent, scheduleTask as _task, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getFirstChild as _vnode_getFirstChild, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsync$, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsync$, useAsyncQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
13505
13755
  //# sourceMappingURL=core.mjs.map