@qwik.dev/core 2.0.0-beta.37 → 2.0.0-beta.39
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/backpatch/package.json +1 -1
- package/dist/build/package.json +1 -1
- package/dist/cli.mjs +14 -5
- package/dist/core-internal.d.ts +397 -323
- package/dist/core.min.mjs +9 -8
- package/dist/core.mjs +1886 -1161
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +4646 -4048
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.d.ts +5 -3
- package/dist/optimizer.mjs +1676 -1722
- package/dist/preloader.mjs +1 -1
- package/dist/qwikloader.debug.js +1 -1
- package/dist/qwikloader.js +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.mjs +75 -34
- package/dist/server.prod.mjs +392 -345
- package/dist/starters/adapters/bun/src/entry.bun.ts +35 -0
- package/dist/starters/adapters/cloud-run/src/entry.cloud-run.tsx +20 -0
- package/dist/starters/adapters/deno/src/entry.deno.ts +41 -0
- package/dist/starters/adapters/express/src/entry.express.tsx +20 -0
- package/dist/starters/adapters/fastify/package.json +2 -2
- package/dist/starters/adapters/fastify/src/entry.fastify.tsx +20 -0
- package/dist/starters/adapters/fastify/src/plugins/fastify-qwik.ts +10 -1
- package/dist/starters/adapters/node-server/src/entry.node-server.tsx +20 -0
- package/dist/starters/features/csr/package.json +1 -1
- package/dist/starters/features/drizzle/package.json +1 -1
- package/dist/starters/features/vitest/package.json +1 -1
- package/dist/testing/index.d.ts +40 -31
- package/dist/testing/index.mjs +1568 -942
- package/dist/testing/package.json +1 -1
- package/dist/worker/package.json +1 -1
- package/dist/worker/worker.shared.js +1 -1
- package/handlers.mjs +3 -0
- package/package.json +7 -7
- package/public.d.ts +3 -0
package/dist/core.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* @qwik.dev/core 2.0.0-beta.
|
|
3
|
+
* @qwik.dev/core 2.0.0-beta.39-dev+6fb620f
|
|
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
|
|
@@ -225,13 +225,16 @@ const codeToText = (code, ...parts) => {
|
|
|
225
225
|
'Unknown vnode type {{0}}.', // 26
|
|
226
226
|
'Materialize error: missing element: {{0}} {{1}} {{2}}', // 27
|
|
227
227
|
'Cannot coerce a Signal, use `.value` instead', // 28
|
|
228
|
-
'
|
|
228
|
+
'', // 29 (cleared: useComputed$ now supports async functions)
|
|
229
229
|
'===\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
|
|
230
230
|
'WrappedSignal is read-only', // 31
|
|
231
231
|
'Attribute value is unsafe for SSR {{0}}', // 32
|
|
232
232
|
'SerializerSymbol function returned rejected promise', // 33
|
|
233
233
|
'Serialization Error: Cannot serialize function: {{0}}', // 34
|
|
234
234
|
'Cannot read .value of a clientOnly async signal during SSR. Use .loading to check state, or provide an initial value.', // 35
|
|
235
|
+
'Invalid element name for SSR {{0}}', // 36
|
|
236
|
+
'Invalid serialized Promise dependency', // 37
|
|
237
|
+
'Invalid serialized Uint8Array payload', // 38
|
|
235
238
|
];
|
|
236
239
|
let text = MAP[code] ?? '';
|
|
237
240
|
if (parts.length) {
|
|
@@ -318,6 +321,7 @@ const VNodeDataChar = {
|
|
|
318
321
|
CLOSE: /* ************* */ 125, // `}` is the end of the VNodeData for a virtual element.
|
|
319
322
|
SCOPED_STYLE: /* ******* */ 59, // `;` - `q:sstyle` - Style attribute.
|
|
320
323
|
RENDER_FN: /* ********** */ 60, // `<` - `q:renderFn' - Component QRL render function (body)
|
|
324
|
+
RENDER_HASH_PREFIX: /* **/ 95, // `_` after `<` identifies a component hash.
|
|
321
325
|
ID: /* ***************** */ 61, // `=` - `q:id` - ID of the element.
|
|
322
326
|
PROPS: /* ************** */ 62, // `>` - `q:props' - Component Props
|
|
323
327
|
SLOT_PARENT: /* ******** */ 63, // `?` - `q:sparent` - Slot parent.
|
|
@@ -402,6 +406,7 @@ function decodeVNodeDataString(str) {
|
|
|
402
406
|
|
|
403
407
|
/** State factory of the component. */
|
|
404
408
|
const OnRenderProp = 'q:renderFn';
|
|
409
|
+
const QComponentHash = 'q:componentHash';
|
|
405
410
|
/** Target DOM element for external projection rendering. */
|
|
406
411
|
const QTargetElement = 'q:targetEl';
|
|
407
412
|
/** Component style content prefix */
|
|
@@ -428,13 +433,13 @@ const QBaseAttr = 'q:base';
|
|
|
428
433
|
const QLocaleAttr = 'q:locale';
|
|
429
434
|
const QManifestHashAttr = 'q:manifest-hash';
|
|
430
435
|
const QInstanceAttr = 'q:instance';
|
|
436
|
+
const QStatePrewarmAttr = 'q:prewarm';
|
|
431
437
|
const QContainerIsland = 'q:container-island';
|
|
432
438
|
const QContainerIslandEnd = '/' + QContainerIsland;
|
|
433
439
|
const QIgnore = 'q:ignore';
|
|
434
440
|
const QIgnoreEnd = '/' + QIgnore;
|
|
435
441
|
const QContainerAttr = 'q:container';
|
|
436
442
|
const QContainerAttrEnd = '/' + QContainerAttr;
|
|
437
|
-
const QCursorBoundary = 'q:cursorBoundary';
|
|
438
443
|
const QTemplate = 'q:template';
|
|
439
444
|
// the same selector should be inside the qwik loader
|
|
440
445
|
// and the same selector should be inside the qwik router spa-shim and spa-init
|
|
@@ -475,6 +480,7 @@ const NON_SERIALIZABLE_MARKER_PREFIX = ':';
|
|
|
475
480
|
const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
|
|
476
481
|
const USE_ON_LOCAL_SEQ_IDX = NON_SERIALIZABLE_MARKER_PREFIX + 'onIdx';
|
|
477
482
|
const USE_ON_LOCAL_FLAGS = NON_SERIALIZABLE_MARKER_PREFIX + 'onFlags';
|
|
483
|
+
const QCursorBoundary = NON_SERIALIZABLE_MARKER_PREFIX + 'cursorBoundary';
|
|
478
484
|
const NEAREST_CURSOR_BOUNDARY = NON_SERIALIZABLE_MARKER_PREFIX + 'nearestCursorBoundary';
|
|
479
485
|
const Q_PROPS_SEPARATOR = ':';
|
|
480
486
|
const dangerouslySetInnerHTML = 'dangerouslySetInnerHTML';
|
|
@@ -842,8 +848,21 @@ const createMacroTask = (fn) => {
|
|
|
842
848
|
let macroTask;
|
|
843
849
|
if (typeof MessageChannel !== 'undefined') {
|
|
844
850
|
const channel = new MessageChannel();
|
|
851
|
+
let active = true;
|
|
845
852
|
channel.port1.onmessage = () => fn();
|
|
846
|
-
macroTask = () =>
|
|
853
|
+
macroTask = () => {
|
|
854
|
+
if (active) {
|
|
855
|
+
channel.port2.postMessage(null);
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
macroTask.$destroy$ = () => {
|
|
859
|
+
if (active) {
|
|
860
|
+
active = false;
|
|
861
|
+
channel.port1.onmessage = null;
|
|
862
|
+
channel.port1.close();
|
|
863
|
+
channel.port2.close();
|
|
864
|
+
}
|
|
865
|
+
};
|
|
847
866
|
}
|
|
848
867
|
else {
|
|
849
868
|
macroTask = () => setTimeout(fn);
|
|
@@ -963,7 +982,7 @@ const rel = isBrowser && doc.createElement('link').relList?.supports?.('modulepr
|
|
|
963
982
|
? 'modulePreload'
|
|
964
983
|
: 'preload';
|
|
965
984
|
const isJSRegex = /\.[mc]?js$/;
|
|
966
|
-
const yieldInterval =
|
|
985
|
+
const yieldInterval = 10;
|
|
967
986
|
|
|
968
987
|
const BundleImportState_None = 0;
|
|
969
988
|
const BundleImportState_Preload = 2;
|
|
@@ -1219,6 +1238,8 @@ const writeStringRootRef = (writer, id) => writer.write(String(id));
|
|
|
1219
1238
|
/** @internal */
|
|
1220
1239
|
const writeStringRootRefPath = (writer, path) => writer.write(stringifyRootRefPath(path));
|
|
1221
1240
|
/** @internal */
|
|
1241
|
+
const writeStringRootRefDelta = (writer, id, base) => writer.write(String(id - base));
|
|
1242
|
+
/** @internal */
|
|
1222
1243
|
const createStringStreamWriter = (write) => ({
|
|
1223
1244
|
write,
|
|
1224
1245
|
writeRootRef(id) {
|
|
@@ -1227,6 +1248,9 @@ const createStringStreamWriter = (write) => ({
|
|
|
1227
1248
|
writeRootRefPath(path) {
|
|
1228
1249
|
return writeStringRootRefPath(this, path);
|
|
1229
1250
|
},
|
|
1251
|
+
writeRootRefDelta(id, base) {
|
|
1252
|
+
return writeStringRootRefDelta(this, id, base);
|
|
1253
|
+
},
|
|
1230
1254
|
});
|
|
1231
1255
|
|
|
1232
1256
|
// Pre-allocated common strings to reduce allocation overhead
|
|
@@ -1242,7 +1266,7 @@ const COMMA = ',';
|
|
|
1242
1266
|
*
|
|
1243
1267
|
* @public
|
|
1244
1268
|
*/
|
|
1245
|
-
const version = "2.0.0-beta.
|
|
1269
|
+
const version = "2.0.0-beta.39-dev+6fb620f";
|
|
1246
1270
|
|
|
1247
1271
|
const isNode = (value) => {
|
|
1248
1272
|
return value && typeof value.nodeType === 'number';
|
|
@@ -1698,9 +1722,12 @@ function setCursorPosition(container, cursorData, position) {
|
|
|
1698
1722
|
}
|
|
1699
1723
|
}
|
|
1700
1724
|
function mergeCursors(container, newCursorData, oldCursor) {
|
|
1725
|
+
const oldCursorData = getCursorData(oldCursor);
|
|
1726
|
+
if (!oldCursorData || oldCursorData === newCursorData) {
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1701
1729
|
// delete from global cursors queue
|
|
1702
1730
|
removeCursorFromQueue(oldCursor, container);
|
|
1703
|
-
const oldCursorData = getCursorData(oldCursor);
|
|
1704
1731
|
mergeCursorData(newCursorData, oldCursorData);
|
|
1705
1732
|
}
|
|
1706
1733
|
function mergeCursorData(newCursorData, oldCursorData) {
|
|
@@ -1778,6 +1805,234 @@ function setCursorData(vNode, cursorData) {
|
|
|
1778
1805
|
cursorDatas.set(vNode, cursorData);
|
|
1779
1806
|
}
|
|
1780
1807
|
|
|
1808
|
+
/** @internal */
|
|
1809
|
+
const _CONST_PROPS = Symbol('CONST');
|
|
1810
|
+
/** @internal */
|
|
1811
|
+
const _VAR_PROPS = Symbol('VAR');
|
|
1812
|
+
/** @internal */
|
|
1813
|
+
const _OWNER = Symbol('OWNER');
|
|
1814
|
+
/** @internal */
|
|
1815
|
+
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
1816
|
+
/** @internal @deprecated v1 compat */
|
|
1817
|
+
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
1818
|
+
/** @internal */
|
|
1819
|
+
const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
1820
|
+
|
|
1821
|
+
/** @internal */
|
|
1822
|
+
const EMPTY_ARRAY = [];
|
|
1823
|
+
/** @internal */
|
|
1824
|
+
const EMPTY_OBJ = {};
|
|
1825
|
+
Object.freeze(EMPTY_ARRAY);
|
|
1826
|
+
Object.freeze(EMPTY_OBJ);
|
|
1827
|
+
|
|
1828
|
+
function createPropsProxy(owner) {
|
|
1829
|
+
// TODO don't make a proxy but populate getters? benchmark
|
|
1830
|
+
return new Proxy({}, new PropsProxyHandler(owner));
|
|
1831
|
+
}
|
|
1832
|
+
class PropsProxyHandler {
|
|
1833
|
+
owner;
|
|
1834
|
+
$effects$ = undefined;
|
|
1835
|
+
$container$ = null;
|
|
1836
|
+
constructor(owner) {
|
|
1837
|
+
this.owner = owner;
|
|
1838
|
+
}
|
|
1839
|
+
get(_, prop) {
|
|
1840
|
+
// escape hatch to get the separated props from a component
|
|
1841
|
+
if (prop === _CONST_PROPS) {
|
|
1842
|
+
return this.owner.constProps;
|
|
1843
|
+
}
|
|
1844
|
+
else if (prop === _VAR_PROPS) {
|
|
1845
|
+
return this.owner.varProps;
|
|
1846
|
+
}
|
|
1847
|
+
else if (prop === _OWNER) {
|
|
1848
|
+
return this.owner;
|
|
1849
|
+
}
|
|
1850
|
+
else if (prop === _PROPS_HANDLER) {
|
|
1851
|
+
return this;
|
|
1852
|
+
}
|
|
1853
|
+
let value;
|
|
1854
|
+
if (prop === 'children') {
|
|
1855
|
+
value = this.owner.children;
|
|
1856
|
+
}
|
|
1857
|
+
else {
|
|
1858
|
+
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
1859
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1860
|
+
if (attr) {
|
|
1861
|
+
prop = attr;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
value = directGetPropsProxyProp(this.owner, prop);
|
|
1865
|
+
if (prop in this.owner.varProps) {
|
|
1866
|
+
addPropsProxyEffect(this, prop);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
// a proxied value that the optimizer made
|
|
1870
|
+
return value instanceof WrappedSignalImpl ? value.value : value;
|
|
1871
|
+
}
|
|
1872
|
+
set(_, prop, value) {
|
|
1873
|
+
if (prop === _OWNER) {
|
|
1874
|
+
// used for deserialization
|
|
1875
|
+
this.owner = value;
|
|
1876
|
+
}
|
|
1877
|
+
else if (prop === 'children') {
|
|
1878
|
+
this.owner.children = value;
|
|
1879
|
+
}
|
|
1880
|
+
else if (prop === _CONST_PROPS) {
|
|
1881
|
+
this.owner.constProps = value;
|
|
1882
|
+
}
|
|
1883
|
+
else if (prop === _VAR_PROPS) {
|
|
1884
|
+
this.owner.varProps = value;
|
|
1885
|
+
}
|
|
1886
|
+
else {
|
|
1887
|
+
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
1888
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1889
|
+
if (attr) {
|
|
1890
|
+
prop = attr;
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
1894
|
+
// delete the prop from the const props first
|
|
1895
|
+
delete this.owner.constProps[prop];
|
|
1896
|
+
}
|
|
1897
|
+
if (this.owner.varProps === EMPTY_OBJ) {
|
|
1898
|
+
this.owner.varProps = {};
|
|
1899
|
+
}
|
|
1900
|
+
else if (!(prop in this.owner.varProps)) {
|
|
1901
|
+
this.owner.toSort = true;
|
|
1902
|
+
}
|
|
1903
|
+
if (this.owner.varProps[prop] !== value) {
|
|
1904
|
+
this.owner.varProps[prop] = value;
|
|
1905
|
+
triggerPropsProxyEffect(this, prop);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
return true;
|
|
1909
|
+
}
|
|
1910
|
+
deleteProperty(_, prop) {
|
|
1911
|
+
let didDelete = delete this.owner.varProps[prop];
|
|
1912
|
+
if (didDelete) {
|
|
1913
|
+
triggerPropsProxyEffect(this, prop);
|
|
1914
|
+
}
|
|
1915
|
+
if (this.owner.constProps) {
|
|
1916
|
+
didDelete = delete this.owner.constProps[prop] || didDelete;
|
|
1917
|
+
}
|
|
1918
|
+
if (this.owner.children != null && prop === 'children') {
|
|
1919
|
+
this.owner.children = null;
|
|
1920
|
+
didDelete = true;
|
|
1921
|
+
}
|
|
1922
|
+
return didDelete;
|
|
1923
|
+
}
|
|
1924
|
+
has(_, prop) {
|
|
1925
|
+
if (prop === 'children') {
|
|
1926
|
+
return this.owner.children != null;
|
|
1927
|
+
}
|
|
1928
|
+
else if (prop === _CONST_PROPS || prop === _VAR_PROPS) {
|
|
1929
|
+
return true;
|
|
1930
|
+
}
|
|
1931
|
+
const inVarProps = prop in this.owner.varProps;
|
|
1932
|
+
if (typeof prop === 'string') {
|
|
1933
|
+
if (inVarProps) {
|
|
1934
|
+
addPropsProxyEffect(this, prop);
|
|
1935
|
+
}
|
|
1936
|
+
if (typeof this.owner.type === 'string') {
|
|
1937
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1938
|
+
if (attr) {
|
|
1939
|
+
prop = attr;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
1944
|
+
}
|
|
1945
|
+
getOwnPropertyDescriptor(_, p) {
|
|
1946
|
+
const value = p === 'children'
|
|
1947
|
+
? this.owner.children
|
|
1948
|
+
: this.owner.constProps && p in this.owner.constProps
|
|
1949
|
+
? this.owner.constProps[p]
|
|
1950
|
+
: this.owner.varProps[p];
|
|
1951
|
+
return {
|
|
1952
|
+
configurable: true,
|
|
1953
|
+
enumerable: true,
|
|
1954
|
+
value: value,
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
ownKeys() {
|
|
1958
|
+
const out = Object.keys(this.owner.varProps);
|
|
1959
|
+
if (this.owner.children != null) {
|
|
1960
|
+
out.push('children');
|
|
1961
|
+
}
|
|
1962
|
+
if (this.owner.constProps) {
|
|
1963
|
+
for (const key in this.owner.constProps) {
|
|
1964
|
+
if (out.indexOf(key) === -1) {
|
|
1965
|
+
out.push(key);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return out;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
const addPropsProxyEffect = (propsProxy, prop) => {
|
|
1973
|
+
// Lazily grab the container from the invoke context
|
|
1974
|
+
const ctx = tryGetInvokeContext();
|
|
1975
|
+
if (ctx) {
|
|
1976
|
+
if (propsProxy.$container$ === null) {
|
|
1977
|
+
if (ctx.$container$) {
|
|
1978
|
+
propsProxy.$container$ = ctx.$container$;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
else {
|
|
1982
|
+
isDev &&
|
|
1983
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
1987
|
+
if (effectSubscriber) {
|
|
1988
|
+
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
1989
|
+
}
|
|
1990
|
+
};
|
|
1991
|
+
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
1992
|
+
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
1993
|
+
if (effects) {
|
|
1994
|
+
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
1995
|
+
}
|
|
1996
|
+
return !!effects;
|
|
1997
|
+
};
|
|
1998
|
+
function getEffects$1(effects, prop) {
|
|
1999
|
+
// TODO: Handle STORE_ALL_PROPS
|
|
2000
|
+
return effects?.get(prop);
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
2004
|
+
* Use this function to get the props directly from a const or var props.
|
|
2005
|
+
*
|
|
2006
|
+
* This does not convert jsx event names.
|
|
2007
|
+
*/
|
|
2008
|
+
const directGetPropsProxyProp = (jsx, prop) => {
|
|
2009
|
+
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
2010
|
+
};
|
|
2011
|
+
const _getProps = (props, prop) => {
|
|
2012
|
+
return _getVarProps(props)?.[prop] || _getConstProps(props)?.[prop] || null;
|
|
2013
|
+
};
|
|
2014
|
+
/** Used by the optimizer for spread props operations @internal */
|
|
2015
|
+
const _getVarProps = (props) => {
|
|
2016
|
+
if (!props) {
|
|
2017
|
+
return null;
|
|
2018
|
+
}
|
|
2019
|
+
return _VAR_PROPS in props
|
|
2020
|
+
? 'children' in props
|
|
2021
|
+
? { ...props[_VAR_PROPS], children: props.children }
|
|
2022
|
+
: props[_VAR_PROPS]
|
|
2023
|
+
: props;
|
|
2024
|
+
};
|
|
2025
|
+
/** Used by the optimizer for spread props operations @internal */
|
|
2026
|
+
const _getConstProps = (props) => {
|
|
2027
|
+
if (!props) {
|
|
2028
|
+
return null;
|
|
2029
|
+
}
|
|
2030
|
+
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
2031
|
+
};
|
|
2032
|
+
const isPropsProxy = (obj) => {
|
|
2033
|
+
return obj && _VAR_PROPS in obj;
|
|
2034
|
+
};
|
|
2035
|
+
|
|
1781
2036
|
/**
|
|
1782
2037
|
* # ================================
|
|
1783
2038
|
*
|
|
@@ -2017,7 +2272,7 @@ class SignalImpl {
|
|
|
2017
2272
|
toString() {
|
|
2018
2273
|
if (isDev) {
|
|
2019
2274
|
try {
|
|
2020
|
-
return (`[${this.constructor.name}${this.$flags$ & 1 /*
|
|
2275
|
+
return (`[${this.constructor.name}${this.$flags$ & 1 /* ComputedSignalFlags.INVALID */ ? ' INVALID' : ''} ${this.$untrackedValue$}]` +
|
|
2021
2276
|
(Array.from(this.$effects$ || [])
|
|
2022
2277
|
.map((e) => '\n -> ' + pad(qwikDebugToString(e.consumer), ' '))
|
|
2023
2278
|
.join('\n') || ''));
|
|
@@ -2035,99 +2290,11 @@ class SignalImpl {
|
|
|
2035
2290
|
}
|
|
2036
2291
|
}
|
|
2037
2292
|
|
|
2038
|
-
const DEBUG
|
|
2293
|
+
const DEBUG = false;
|
|
2039
2294
|
// eslint-disable-next-line no-console
|
|
2040
|
-
const log
|
|
2041
|
-
/**
|
|
2042
|
-
|
|
2043
|
-
*
|
|
2044
|
-
* The value is available synchronously, but the computation is done lazily.
|
|
2045
|
-
*/
|
|
2046
|
-
class ComputedSignalImpl extends SignalImpl {
|
|
2047
|
-
/**
|
|
2048
|
-
* The compute function is stored here.
|
|
2049
|
-
*
|
|
2050
|
-
* The computed functions must be executed synchronously (because of this we need to eagerly
|
|
2051
|
-
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous). )
|
|
2052
|
-
*/
|
|
2053
|
-
$computeQrl$;
|
|
2054
|
-
$flags$;
|
|
2055
|
-
[_EFFECT_BACK_REF] = undefined;
|
|
2056
|
-
constructor(container, fn,
|
|
2057
|
-
// We need a separate flag to know when the computation needs running because
|
|
2058
|
-
// we need the old value to know if effects need running after computation
|
|
2059
|
-
flags = 1 /* SignalFlags.INVALID */ |
|
|
2060
|
-
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
|
|
2061
|
-
// The value is used for comparison when signals trigger, which can only happen
|
|
2062
|
-
// when it was calculated before. Therefore we can pass whatever we like.
|
|
2063
|
-
super(container || tryGetInvokeContext()?.$container$, NEEDS_COMPUTATION);
|
|
2064
|
-
this.$computeQrl$ = fn;
|
|
2065
|
-
this.$flags$ = flags;
|
|
2066
|
-
}
|
|
2067
|
-
invalidate() {
|
|
2068
|
-
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
2069
|
-
const ctx = newInvokeContext();
|
|
2070
|
-
ctx.$container$ = this.$container$ || undefined;
|
|
2071
|
-
// @ts-expect-error it's confused about args any[] vs []
|
|
2072
|
-
const running = retryOnPromise(invokeApply.bind(this, ctx, this.$computeIfNeeded$));
|
|
2073
|
-
if (running) {
|
|
2074
|
-
running.catch((err) => {
|
|
2075
|
-
if (this.$container$) {
|
|
2076
|
-
this.$container$.handleError(err, null);
|
|
2077
|
-
}
|
|
2078
|
-
else {
|
|
2079
|
-
console.error('Error during computation', err);
|
|
2080
|
-
}
|
|
2081
|
-
});
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
get untrackedValue() {
|
|
2085
|
-
this.$computeIfNeeded$();
|
|
2086
|
-
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2087
|
-
return this.$untrackedValue$;
|
|
2088
|
-
}
|
|
2089
|
-
set untrackedValue(value) {
|
|
2090
|
-
this.$untrackedValue$ = value;
|
|
2091
|
-
}
|
|
2092
|
-
$computeIfNeeded$() {
|
|
2093
|
-
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
const computeQrl = this.$computeQrl$;
|
|
2097
|
-
throwIfQRLNotResolved(computeQrl);
|
|
2098
|
-
const ctx = tryGetInvokeContext();
|
|
2099
|
-
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
2100
|
-
if (ctx) {
|
|
2101
|
-
const effectSubscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
2102
|
-
clearEffectSubscription(this.$container$, effectSubscriber);
|
|
2103
|
-
ctx.$effectSubscriber$ = effectSubscriber;
|
|
2104
|
-
}
|
|
2105
|
-
try {
|
|
2106
|
-
const untrackedValue = computeQrl.getFn(ctx)();
|
|
2107
|
-
if (isPromise(untrackedValue)) {
|
|
2108
|
-
throw qError(29 /* QError.computedNotSync */, [
|
|
2109
|
-
computeQrl.dev ? computeQrl.dev.file : '',
|
|
2110
|
-
computeQrl.$hash$,
|
|
2111
|
-
]);
|
|
2112
|
-
}
|
|
2113
|
-
DEBUG$1 && log$1('Signal.$compute$', untrackedValue);
|
|
2114
|
-
this.$flags$ &= ~1 /* SignalFlags.INVALID */;
|
|
2115
|
-
super.value = untrackedValue;
|
|
2116
|
-
}
|
|
2117
|
-
finally {
|
|
2118
|
-
if (ctx) {
|
|
2119
|
-
ctx.$effectSubscriber$ = previousEffectSubscription;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
|
|
2125
|
-
const DEBUG = false;
|
|
2126
|
-
const log = (...args) =>
|
|
2127
|
-
// eslint-disable-next-line no-console
|
|
2128
|
-
console.log('ASYNC COMPUTED SIGNAL', ...args.map(qwikDebugToString));
|
|
2129
|
-
/** Retains job metadata and also serves as the argument for the compute function */
|
|
2130
|
-
class AsyncJob {
|
|
2295
|
+
const log = (...args) => console.log('COMPUTED SIGNAL', ...args.map(qwikDebugToString));
|
|
2296
|
+
/** Retains job metadata and also serves as the argument for CTX_ARG compute functions */
|
|
2297
|
+
class Job {
|
|
2131
2298
|
$signal$;
|
|
2132
2299
|
/** First holds the compute promise and then the cleanup promise */
|
|
2133
2300
|
$promise$ = null;
|
|
@@ -2149,7 +2316,7 @@ class AsyncJob {
|
|
|
2149
2316
|
/** Backward compatible cache method for resource */
|
|
2150
2317
|
cache() {
|
|
2151
2318
|
isDev &&
|
|
2152
|
-
console.error('useResource cache() method does not do anything. Use `
|
|
2319
|
+
console.error('useResource cache() method does not do anything. Use `useComputed$` instead of `useResource$`; for polling use the `usePoll` hook from `@qwik.dev/utils`.');
|
|
2153
2320
|
}
|
|
2154
2321
|
get previous() {
|
|
2155
2322
|
const val = this.$signal$.$untrackedValue$;
|
|
@@ -2164,62 +2331,123 @@ class AsyncJob {
|
|
|
2164
2331
|
}
|
|
2165
2332
|
}
|
|
2166
2333
|
/**
|
|
2167
|
-
*
|
|
2168
|
-
*
|
|
2169
|
-
* AsyncSignalImpl
|
|
2170
|
-
*
|
|
2171
|
-
* # ================================
|
|
2334
|
+
* A signal which is computed from other signals.
|
|
2172
2335
|
*
|
|
2173
|
-
*
|
|
2336
|
+
* Sync compute functions resolve synchronously and every read they perform is auto-tracked. When
|
|
2337
|
+
* the compute function turns out to be async (it returned a promise), the signal lazily switches on
|
|
2338
|
+
* the async engine — jobs, `loading`, `error` — giving it the same API as an AsyncSignal.
|
|
2339
|
+
* Auto-tracking only covers reads before the first await point (the invoke context is lost after
|
|
2340
|
+
* it); later reads must use the ComputeCtx `track()`.
|
|
2174
2341
|
*/
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2342
|
+
// TODO when we make core lazy async, lazy load the async engine part of this class
|
|
2343
|
+
class ComputedSignalImpl extends SignalImpl {
|
|
2344
|
+
/**
|
|
2345
|
+
* The compute function is stored here.
|
|
2346
|
+
*
|
|
2347
|
+
* Sync computed functions must be executed synchronously (because of this we need to eagerly
|
|
2348
|
+
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous).
|
|
2349
|
+
*/
|
|
2350
|
+
$computeQrl$;
|
|
2351
|
+
$flags$;
|
|
2179
2352
|
[_EFFECT_BACK_REF] = undefined;
|
|
2180
|
-
constructor(container, fn,
|
|
2353
|
+
constructor(container, fn,
|
|
2354
|
+
// We need a separate flag to know when the computation needs running because
|
|
2355
|
+
// we need the old value to know if effects need running after computation
|
|
2356
|
+
flags = 1 /* ComputedSignalFlags.INVALID */ |
|
|
2181
2357
|
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
|
|
2182
|
-
|
|
2358
|
+
// The value is used for comparison when signals trigger, which can only happen
|
|
2359
|
+
// when it was calculated before. Therefore we can pass whatever we like.
|
|
2360
|
+
super(container || tryGetInvokeContext()?.$container$, NEEDS_COMPUTATION);
|
|
2361
|
+
this.$computeQrl$ = fn;
|
|
2362
|
+
this.$flags$ = flags;
|
|
2183
2363
|
if (!options) {
|
|
2184
2364
|
return;
|
|
2185
2365
|
}
|
|
2186
|
-
//
|
|
2187
|
-
// Do NOT call setValue() which would clear the INVALID flag and prevent async computation
|
|
2366
|
+
// Eagerly evaluate an initial value without clearing INVALID, so the compute still runs
|
|
2188
2367
|
const initial = options.initial;
|
|
2189
2368
|
if (initial !== undefined) {
|
|
2190
|
-
|
|
2191
|
-
this.$untrackedValue$ = initialValue;
|
|
2369
|
+
this.$untrackedValue$ = typeof initial === 'function' ? initial() : initial;
|
|
2192
2370
|
}
|
|
2193
2371
|
const concurrency = options.concurrency;
|
|
2194
2372
|
if (concurrency !== undefined && concurrency >= 0 && concurrency !== 1) {
|
|
2195
2373
|
this.$concurrency$ = concurrency;
|
|
2196
2374
|
this.$jobs$ = [];
|
|
2197
2375
|
}
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
this.$timeoutMs$ = timeout;
|
|
2376
|
+
if (options.timeout) {
|
|
2377
|
+
this.$timeoutMs$ = options.timeout;
|
|
2201
2378
|
}
|
|
2202
2379
|
if (options.eagerCleanup) {
|
|
2203
2380
|
this.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
|
|
2204
2381
|
}
|
|
2205
2382
|
if (options.clientOnly) {
|
|
2206
|
-
|
|
2383
|
+
// clientOnly can never resolve during SSR, so it must be async from the start
|
|
2384
|
+
this.$flags$ |= 64 /* AsyncSignalFlags.CLIENT_ONLY */ | 512 /* AsyncSignalFlags.ASYNC_MODE */;
|
|
2207
2385
|
}
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2386
|
+
}
|
|
2387
|
+
/** Clear the value so readers see the loading state, then recompute. */
|
|
2388
|
+
clear() {
|
|
2389
|
+
this.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
2390
|
+
this.invalidate();
|
|
2391
|
+
}
|
|
2392
|
+
invalidate(info) {
|
|
2393
|
+
if (arguments.length > 0) {
|
|
2394
|
+
this.$info$ = info;
|
|
2395
|
+
this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
|
|
2214
2396
|
}
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2397
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2398
|
+
this.$setInvalid$(true);
|
|
2399
|
+
return;
|
|
2218
2400
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2401
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2402
|
+
const ctx = newInvokeContext();
|
|
2403
|
+
ctx.$container$ = this.$container$ || undefined;
|
|
2404
|
+
// @ts-expect-error it's confused about args any[] vs []
|
|
2405
|
+
const running = retryOnPromise(invokeApply.bind(this, ctx, this.$computeIfNeeded$));
|
|
2406
|
+
if (isPromise(running)) {
|
|
2407
|
+
running.catch((err) => {
|
|
2408
|
+
if (this.$container$) {
|
|
2409
|
+
this.$container$.handleError(err, null);
|
|
2410
|
+
}
|
|
2411
|
+
else {
|
|
2412
|
+
console.error('Error during computation', err);
|
|
2413
|
+
}
|
|
2414
|
+
});
|
|
2221
2415
|
}
|
|
2222
2416
|
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Read the value, subscribing if in a tracking context. Triggers computation if needed.
|
|
2419
|
+
*
|
|
2420
|
+
* Setting the value will mark the signal as not loading and clear any error, and prevent any
|
|
2421
|
+
* pending computations from writing their results.
|
|
2422
|
+
*
|
|
2423
|
+
* If you want to set the value without affecting loading or error state, set `untrackedValue`
|
|
2424
|
+
* instead and make sure to trigger effects manually if needed.
|
|
2425
|
+
*
|
|
2426
|
+
* If you want to abort pending computations when setting, you have to call `abort()` manually.
|
|
2427
|
+
*/
|
|
2428
|
+
get value() {
|
|
2429
|
+
return super.value;
|
|
2430
|
+
}
|
|
2431
|
+
set value(value) {
|
|
2432
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2433
|
+
this.untrackedError = undefined;
|
|
2434
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2435
|
+
this.untrackedPending = false;
|
|
2436
|
+
this.$info$ = undefined;
|
|
2437
|
+
// Prevent pending computations from overwriting this value
|
|
2438
|
+
if (this.$jobs$) {
|
|
2439
|
+
for (let i = 0; i < this.$jobs$.length; i++) {
|
|
2440
|
+
this.$jobs$[i].$canWrite$ = false;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
else if (this.$current$) {
|
|
2444
|
+
this.$current$.$canWrite$ = false;
|
|
2445
|
+
}
|
|
2446
|
+
super.value = value;
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
super.value = value;
|
|
2450
|
+
}
|
|
2223
2451
|
get untrackedValue() {
|
|
2224
2452
|
this.$computeIfNeeded$();
|
|
2225
2453
|
if (this.$current$?.$promise$) {
|
|
@@ -2238,52 +2466,26 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2238
2466
|
this.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
2239
2467
|
throw qError(35 /* QError.asyncClientOnlyValueDuringSSR */);
|
|
2240
2468
|
}
|
|
2469
|
+
isDev &&
|
|
2470
|
+
!(this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) &&
|
|
2471
|
+
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2241
2472
|
return this.$untrackedValue$;
|
|
2242
2473
|
}
|
|
2243
2474
|
set untrackedValue(value) {
|
|
2244
2475
|
this.$untrackedValue$ = value;
|
|
2245
2476
|
}
|
|
2246
|
-
/**
|
|
2247
|
-
* Read the value, subscribing if in a tracking context. Triggers computation if needed.
|
|
2248
|
-
*
|
|
2249
|
-
* Setting the value will mark the signal as not loading and clear any error, and prevent any
|
|
2250
|
-
* pending computations from writing their results.
|
|
2251
|
-
*
|
|
2252
|
-
* If you want to set the value without affecting loading or error state, set `untrackedValue`
|
|
2253
|
-
* instead and make sure to trigger effects manually if needed.
|
|
2254
|
-
*
|
|
2255
|
-
* If you want to abort pending computations when setting, you have to call `abort()` manually.
|
|
2256
|
-
*/
|
|
2257
|
-
get value() {
|
|
2258
|
-
return super.value;
|
|
2259
|
-
}
|
|
2260
|
-
set value(value) {
|
|
2261
|
-
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
2262
|
-
this.untrackedLoading = false;
|
|
2263
|
-
this.untrackedError = undefined;
|
|
2264
|
-
this.$info$ = undefined;
|
|
2265
|
-
// Prevent pending computations from overwriting this value
|
|
2266
|
-
if (this.$jobs$) {
|
|
2267
|
-
for (let i = 0; i < this.$jobs$.length; i++) {
|
|
2268
|
-
this.$jobs$[i].$canWrite$ = false;
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
else if (this.$current$) {
|
|
2272
|
-
this.$current$.$canWrite$ = false;
|
|
2273
|
-
}
|
|
2274
|
-
this.$clearNextPoll$();
|
|
2275
|
-
super.value = value;
|
|
2276
|
-
this.$scheduleNextPoll$();
|
|
2277
|
-
}
|
|
2278
2477
|
/**
|
|
2279
2478
|
* Loading is true if the signal is still waiting for the promise to resolve, false if the promise
|
|
2280
|
-
* has resolved or rejected.
|
|
2479
|
+
* has resolved or rejected (or the compute function is synchronous).
|
|
2480
|
+
*
|
|
2481
|
+
* Accessing `.pending` will trigger computation if needed, since it's often used like
|
|
2281
2482
|
*
|
|
2282
|
-
*
|
|
2283
|
-
*
|
|
2483
|
+
* ```ts
|
|
2484
|
+
* signal.pending ? <Loading /> : signal.value
|
|
2485
|
+
* ```
|
|
2284
2486
|
*/
|
|
2285
|
-
get
|
|
2286
|
-
const val = this.
|
|
2487
|
+
get pending() {
|
|
2488
|
+
const val = this.untrackedPending;
|
|
2287
2489
|
const ctx = tryGetInvokeContext();
|
|
2288
2490
|
if (ctx && (this.$container$ ||= ctx.$container$ || null)) {
|
|
2289
2491
|
isDev &&
|
|
@@ -2297,22 +2499,41 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2297
2499
|
}
|
|
2298
2500
|
return val;
|
|
2299
2501
|
}
|
|
2300
|
-
set
|
|
2301
|
-
if (value !== this.$
|
|
2302
|
-
this.$
|
|
2502
|
+
set untrackedPending(value) {
|
|
2503
|
+
if (value !== !!this.$untrackedPending$) {
|
|
2504
|
+
this.$untrackedPending$ = value;
|
|
2303
2505
|
scheduleEffects(this.$container$, this, this.$loadingEffects$);
|
|
2304
2506
|
}
|
|
2305
2507
|
}
|
|
2306
|
-
get
|
|
2508
|
+
get untrackedPending() {
|
|
2307
2509
|
// reading `.loading` means someone is interested in the result, so we should trigger the computation. The alternative is eager computation or imperative calls to invalidate; this seems nicer.
|
|
2308
2510
|
this.$computeIfNeeded$();
|
|
2309
2511
|
// During SSR there's no such thing as loading state, we must render complete results
|
|
2310
2512
|
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2311
2513
|
throw this.$current$?.$promise$;
|
|
2312
2514
|
}
|
|
2313
|
-
return this.$
|
|
2515
|
+
return !!this.$untrackedPending$;
|
|
2314
2516
|
}
|
|
2315
|
-
/**
|
|
2517
|
+
/** @deprecated Use `pending` instead */
|
|
2518
|
+
get loading() {
|
|
2519
|
+
return this.pending;
|
|
2520
|
+
}
|
|
2521
|
+
/** @deprecated Use `untrackedPending` instead */
|
|
2522
|
+
get untrackedLoading() {
|
|
2523
|
+
return this.untrackedPending;
|
|
2524
|
+
}
|
|
2525
|
+
set untrackedLoading(value) {
|
|
2526
|
+
this.untrackedPending = value;
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* The error the compute function threw or rejected with.
|
|
2530
|
+
*
|
|
2531
|
+
* Accessing .error will trigger computation if needed, since it's often used like
|
|
2532
|
+
*
|
|
2533
|
+
* ```ts
|
|
2534
|
+
* signal.error ? <Failed /> : signal.value
|
|
2535
|
+
* ```
|
|
2536
|
+
*/
|
|
2316
2537
|
get error() {
|
|
2317
2538
|
const val = this.untrackedError;
|
|
2318
2539
|
const ctx = tryGetInvokeContext();
|
|
@@ -2335,62 +2556,15 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2335
2556
|
}
|
|
2336
2557
|
}
|
|
2337
2558
|
get untrackedError() {
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
}
|
|
2343
|
-
set expires(value) {
|
|
2344
|
-
this.$clearNextPoll$();
|
|
2345
|
-
this.$expires$ = value;
|
|
2346
|
-
if (this.$expires$ && this.$hasSubscribers$()) {
|
|
2347
|
-
this.$scheduleNextPoll$();
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
get poll() {
|
|
2351
|
-
return !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
|
|
2352
|
-
}
|
|
2353
|
-
set poll(value) {
|
|
2354
|
-
if (value) {
|
|
2355
|
-
this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
|
|
2356
|
-
}
|
|
2357
|
-
else {
|
|
2358
|
-
this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
|
|
2359
|
-
}
|
|
2360
|
-
// Reschedule since poll behavior changed
|
|
2361
|
-
if (this.$expires$ && this.$hasSubscribers$()) {
|
|
2362
|
-
this.$clearNextPoll$();
|
|
2363
|
-
this.$scheduleNextPoll$();
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
/** @deprecated Use `expires` and `poll` instead. */
|
|
2367
|
-
get interval() {
|
|
2368
|
-
const expires = this.$expires$ || 0;
|
|
2369
|
-
return this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */ ? -expires : expires;
|
|
2370
|
-
}
|
|
2371
|
-
set interval(value) {
|
|
2372
|
-
if (value < 0) {
|
|
2373
|
-
this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
|
|
2374
|
-
}
|
|
2375
|
-
else {
|
|
2376
|
-
this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
|
|
2377
|
-
}
|
|
2378
|
-
this.expires = Math.abs(value);
|
|
2379
|
-
}
|
|
2380
|
-
/** Invalidates the signal, causing it to re-compute its value. */
|
|
2381
|
-
async invalidate(info) {
|
|
2382
|
-
if (arguments.length > 0) {
|
|
2383
|
-
this.$info$ = info;
|
|
2384
|
-
this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
|
|
2559
|
+
this.$computeIfNeeded$();
|
|
2560
|
+
// During SSR we must render settled results
|
|
2561
|
+
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2562
|
+
throw this.$current$?.$promise$;
|
|
2385
2563
|
}
|
|
2386
|
-
|
|
2564
|
+
return this.$untrackedError$;
|
|
2387
2565
|
}
|
|
2388
|
-
$setInvalid$(allowRecalc
|
|
2389
|
-
this.$flags$ |= 1 /*
|
|
2390
|
-
this.$clearNextPoll$();
|
|
2391
|
-
if (mustClear) {
|
|
2392
|
-
this.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
2393
|
-
}
|
|
2566
|
+
$setInvalid$(allowRecalc) {
|
|
2567
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2394
2568
|
if (allowRecalc &&
|
|
2395
2569
|
(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size)) {
|
|
2396
2570
|
// compute in next microtask
|
|
@@ -2427,19 +2601,96 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2427
2601
|
}
|
|
2428
2602
|
/** Run the computation if needed */
|
|
2429
2603
|
$computeIfNeeded$() {
|
|
2430
|
-
if (!(this.$flags$ & 1 /*
|
|
2604
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
2431
2605
|
return;
|
|
2432
2606
|
}
|
|
2607
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2608
|
+
return this.$computeAsync$();
|
|
2609
|
+
}
|
|
2610
|
+
const computeQrl = this.$computeQrl$;
|
|
2611
|
+
throwIfQRLNotResolved(computeQrl);
|
|
2612
|
+
// The previous compute's cleanups run before the new compute, like the async engine
|
|
2613
|
+
const prevJob = this.$current$;
|
|
2614
|
+
if (prevJob && !prevJob.$cleanupRequested$) {
|
|
2615
|
+
prevJob.$cleanupRequested$ = true;
|
|
2616
|
+
prevJob.$abortController$?.abort();
|
|
2617
|
+
this.$runCleanupCallbacks$(prevJob);
|
|
2618
|
+
}
|
|
2619
|
+
const running = new Job(this, this.$info$, this.$infoVersion$);
|
|
2620
|
+
this.$current$ = running;
|
|
2621
|
+
let result;
|
|
2622
|
+
try {
|
|
2623
|
+
result = this.$invokeComputeFn$(computeQrl.resolved, running);
|
|
2624
|
+
}
|
|
2625
|
+
catch (err) {
|
|
2626
|
+
// A thrown promise is a retry request, not a failure
|
|
2627
|
+
if (isPromise(err)) {
|
|
2628
|
+
throw err;
|
|
2629
|
+
}
|
|
2630
|
+
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2631
|
+
this.$info$ = undefined;
|
|
2632
|
+
}
|
|
2633
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2634
|
+
this.$setError$(running, err);
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
if (isPromise(result)) {
|
|
2638
|
+
// The compute fn is async: hand the in-flight computation to the async engine
|
|
2639
|
+
this.$flags$ |= 512 /* AsyncSignalFlags.ASYNC_MODE */;
|
|
2640
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2641
|
+
// Consume the in-flight promise first; retries re-invoke the compute fn
|
|
2642
|
+
let first = result;
|
|
2643
|
+
const compute = () => {
|
|
2644
|
+
const r = first ?? this.$invokeComputeFn$(this.$computeQrl$.resolved, running);
|
|
2645
|
+
first = undefined;
|
|
2646
|
+
return r;
|
|
2647
|
+
};
|
|
2648
|
+
running.$promise$ = this.$settleComputation$(running, () => retryOnPromise(compute));
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2652
|
+
this.$info$ = undefined;
|
|
2653
|
+
}
|
|
2654
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2655
|
+
this.untrackedError = undefined;
|
|
2656
|
+
super.value = result;
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Invoke the compute fn with the ComputeCtx argument. CTX_ARG signals (useAsync$, useResource$)
|
|
2660
|
+
* only track via its explicit track(). Computeds auto-track every synchronous read instead; after
|
|
2661
|
+
* the first await they must use the explicit track() too.
|
|
2662
|
+
*/
|
|
2663
|
+
$invokeComputeFn$(fn, job) {
|
|
2664
|
+
const computeFn = fn;
|
|
2665
|
+
if (this.$flags$ & 1024 /* AsyncSignalFlags.CTX_ARG */) {
|
|
2666
|
+
// Strip the ambient effect subscriber: these compute fns track only via their track()
|
|
2667
|
+
let iCtx = tryGetInvokeContext();
|
|
2668
|
+
if (iCtx?.$effectSubscriber$) {
|
|
2669
|
+
iCtx = { ...iCtx, $effectSubscriber$: undefined };
|
|
2670
|
+
}
|
|
2671
|
+
return invokeApply(iCtx, computeFn, [job]);
|
|
2672
|
+
}
|
|
2673
|
+
const container = (this.$container$ ||= tryGetInvokeContext()?.$container$ || null);
|
|
2674
|
+
const subscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
2675
|
+
if (container) {
|
|
2676
|
+
clearEffectSubscription(container, subscriber);
|
|
2677
|
+
}
|
|
2678
|
+
const ctx = newInvokeContext();
|
|
2679
|
+
ctx.$container$ = container || undefined;
|
|
2680
|
+
ctx.$effectSubscriber$ = subscriber;
|
|
2681
|
+
return invokeApply(ctx, computeFn, [job]);
|
|
2682
|
+
}
|
|
2683
|
+
/** Start an async computation (the async engine; assumes the INVALID flag is set) */
|
|
2684
|
+
$computeAsync$() {
|
|
2433
2685
|
// Skip computation on SSR for clientOnly signals
|
|
2434
2686
|
if ((qTest ? isServerPlatform() : isServer) && this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
2435
2687
|
// We must pretend to load, and register as a listener for the captures
|
|
2436
|
-
this.$
|
|
2688
|
+
this.$untrackedPending$ = true;
|
|
2437
2689
|
this.$container$?.serializationCtx.$eagerResume$.add(this);
|
|
2438
2690
|
return;
|
|
2439
2691
|
}
|
|
2440
|
-
this.$clearNextPoll$();
|
|
2441
2692
|
// Clear flag here to make sure the cleanups don't start another compute
|
|
2442
|
-
this.$flags$ &= -2 /*
|
|
2693
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2443
2694
|
const current = this.$current$;
|
|
2444
2695
|
if (current) {
|
|
2445
2696
|
this.$requestCleanups$(current);
|
|
@@ -2449,12 +2700,12 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2449
2700
|
if (this.$jobs$ ? this.$jobs$.length >= limit : current?.$promise$) {
|
|
2450
2701
|
// We requested cleanups for all the previous jobs, once one finishes it will be removed from the jobs array and trigger computeIfNeeded
|
|
2451
2702
|
// Restore invalid state
|
|
2452
|
-
this.$flags$ |= 1 /*
|
|
2703
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2453
2704
|
return;
|
|
2454
2705
|
}
|
|
2455
2706
|
// We put the actual computation in a separate method so we can easily retain the promise
|
|
2456
2707
|
const infoVersion = this.$infoVersion$;
|
|
2457
|
-
const running = new
|
|
2708
|
+
const running = new Job(this, this.$info$, infoVersion);
|
|
2458
2709
|
this.$current$ = running;
|
|
2459
2710
|
if (this.$jobs$) {
|
|
2460
2711
|
this.$jobs$.push(running);
|
|
@@ -2462,35 +2713,39 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2462
2713
|
running.$promise$ = this.$runComputation$(running);
|
|
2463
2714
|
}
|
|
2464
2715
|
async $runComputation$(running) {
|
|
2465
|
-
const isCurrent = () => running === this.$current$;
|
|
2466
2716
|
let fn = this.$computeQrl$.resolved;
|
|
2467
2717
|
if (!fn) {
|
|
2468
2718
|
// QRL resolution is async — we have to publish loading=true before awaiting so
|
|
2469
2719
|
// subscribers know the value isn't ready yet.
|
|
2470
|
-
this.
|
|
2720
|
+
this.untrackedPending = true;
|
|
2471
2721
|
fn = await this.$computeQrl$.resolve();
|
|
2472
2722
|
if (running.$abortController$?.signal.aborted) {
|
|
2473
2723
|
running.$promise$ = null;
|
|
2474
2724
|
return;
|
|
2475
2725
|
}
|
|
2476
2726
|
}
|
|
2727
|
+
if (this.$timeoutMs$) {
|
|
2728
|
+
this.$computationTimeoutId$ = setTimeout(() => {
|
|
2729
|
+
const error = new Error(`timeout ${this.$timeoutMs$}ms`);
|
|
2730
|
+
this.$setError$(running, error);
|
|
2731
|
+
running.$abortController$?.abort(error);
|
|
2732
|
+
}, this.$timeoutMs$);
|
|
2733
|
+
}
|
|
2734
|
+
return this.$settleComputation$(running, () => retryOnPromise(() => this.$invokeComputeFn$(fn, running)));
|
|
2735
|
+
}
|
|
2736
|
+
/** Await the computation and publish its result, error, and loading transitions. */
|
|
2737
|
+
async $settleComputation$(running, compute) {
|
|
2738
|
+
const isCurrent = () => running === this.$current$;
|
|
2477
2739
|
try {
|
|
2478
|
-
if (this.$timeoutMs$) {
|
|
2479
|
-
this.$computationTimeoutId$ = setTimeout(() => {
|
|
2480
|
-
const error = new Error(`timeout ${this.$timeoutMs$}ms`);
|
|
2481
|
-
this.$setError$(running, error);
|
|
2482
|
-
running.$abortController$?.abort(error);
|
|
2483
|
-
}, this.$timeoutMs$);
|
|
2484
|
-
}
|
|
2485
2740
|
// Try to stay sync if possible. Only publish loading=true to subscribers when
|
|
2486
2741
|
// the compute is actually asynchronous — a synchronous resolve (e.g. pre-loaded
|
|
2487
2742
|
// values injected via _injectAsyncSignalValue) should never transition through a
|
|
2488
2743
|
// visible loading state, which on SSR would fire the loading-effect subscribers
|
|
2489
2744
|
// (tasks) while the value is still "loading" from their perspective.
|
|
2490
|
-
const valuePromise =
|
|
2745
|
+
const valuePromise = compute();
|
|
2491
2746
|
let value;
|
|
2492
2747
|
if (isPromise(valuePromise)) {
|
|
2493
|
-
this.
|
|
2748
|
+
this.untrackedPending = true;
|
|
2494
2749
|
value = await valuePromise;
|
|
2495
2750
|
}
|
|
2496
2751
|
else {
|
|
@@ -2515,7 +2770,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2515
2770
|
// Note that these assignments run setters
|
|
2516
2771
|
this.untrackedError = undefined;
|
|
2517
2772
|
/**
|
|
2518
|
-
* Use
|
|
2773
|
+
* Use SignalImpl.value instead of this.value to persist invalid state, so that invalidation
|
|
2519
2774
|
* during computation recomputes
|
|
2520
2775
|
*/
|
|
2521
2776
|
super.value = value;
|
|
@@ -2530,13 +2785,12 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2530
2785
|
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2531
2786
|
this.$info$ = undefined;
|
|
2532
2787
|
}
|
|
2533
|
-
if (this.$flags$ & 1 /*
|
|
2788
|
+
if (this.$flags$ & 1 /* ComputedSignalFlags.INVALID */) {
|
|
2534
2789
|
// we became invalid again while running, so we need to re-run the computation to get the new promise
|
|
2535
2790
|
this.$computeIfNeeded$();
|
|
2536
2791
|
}
|
|
2537
2792
|
else {
|
|
2538
|
-
this.
|
|
2539
|
-
this.$scheduleNextPoll$();
|
|
2793
|
+
this.untrackedPending = false;
|
|
2540
2794
|
}
|
|
2541
2795
|
}
|
|
2542
2796
|
}
|
|
@@ -2559,341 +2813,82 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2559
2813
|
}
|
|
2560
2814
|
/** Called after SSR/unmount */
|
|
2561
2815
|
async $destroy$() {
|
|
2562
|
-
this.$clearNextPoll$();
|
|
2563
2816
|
clearTimeout(this.$computationTimeoutId$);
|
|
2564
2817
|
const current = this.$current$;
|
|
2565
2818
|
if (current) {
|
|
2566
|
-
this.$requestCleanups$(current);
|
|
2567
|
-
}
|
|
2568
|
-
if (this.$jobs$) {
|
|
2569
|
-
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2570
|
-
}
|
|
2571
|
-
else {
|
|
2572
|
-
await current?.$promise$;
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
$clearNextPoll$() {
|
|
2576
|
-
if (this.$pollTimeoutId$ !== undefined) {
|
|
2577
|
-
clearTimeout(this.$pollTimeoutId$);
|
|
2578
|
-
this.$pollTimeoutId$ = undefined;
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
$scheduleNextPoll$() {
|
|
2582
|
-
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2583
|
-
return;
|
|
2584
|
-
}
|
|
2585
|
-
this.$clearNextPoll$();
|
|
2586
|
-
const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
|
|
2587
|
-
// Even when clear on invalidate, we don't clear if we're merely re-running due to polling
|
|
2588
|
-
// We expect to get the new value soon, so we can avoid showing a loading state
|
|
2589
|
-
const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
|
|
2590
|
-
this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
|
|
2591
|
-
this.$pollTimeoutId$?.unref?.();
|
|
2592
|
-
}
|
|
2593
|
-
$hasSubscribers$() {
|
|
2594
|
-
return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
|
|
2595
|
-
}
|
|
2596
|
-
$requestCleanups$(job, reason) {
|
|
2597
|
-
if (job.$cleanupRequested$) {
|
|
2598
|
-
return;
|
|
2599
|
-
}
|
|
2600
|
-
job.$cleanupRequested$ = true;
|
|
2601
|
-
job.$abortController$?.abort(reason);
|
|
2602
|
-
job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
|
|
2603
|
-
}
|
|
2604
|
-
/** Clean up and trigger signal compute once complete */
|
|
2605
|
-
$runCleanups$(job) {
|
|
2606
|
-
const cleanups = job.$cleanups$;
|
|
2607
|
-
const onError = (err) => {
|
|
2608
|
-
const handleError = this.$container$?.handleError;
|
|
2609
|
-
if (handleError) {
|
|
2610
|
-
handleError(err, null);
|
|
2611
|
-
}
|
|
2612
|
-
else {
|
|
2613
|
-
console.error('Error in async signal cleanup', err);
|
|
2614
|
-
}
|
|
2615
|
-
};
|
|
2616
|
-
const onDone = () => {
|
|
2617
|
-
job.$promise$ = null;
|
|
2618
|
-
if (cleanups) {
|
|
2619
|
-
cleanups.length = 0;
|
|
2620
|
-
}
|
|
2621
|
-
// Now trigger compute
|
|
2622
|
-
const jobs = this.$jobs$;
|
|
2623
|
-
if (jobs) {
|
|
2624
|
-
const idx = jobs.indexOf(job);
|
|
2625
|
-
if (idx !== -1) {
|
|
2626
|
-
jobs.splice(idx, 1);
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
this.$computeIfNeeded$();
|
|
2630
|
-
};
|
|
2631
|
-
let promiseChain = undefined;
|
|
2632
|
-
if (cleanups) {
|
|
2633
|
-
// Keep this sync-ish so sync functions run immediately.
|
|
2634
|
-
for (let i = 0; i < cleanups.length; i++) {
|
|
2635
|
-
try {
|
|
2636
|
-
const result = cleanups[i]();
|
|
2637
|
-
if (isPromise(result)) {
|
|
2638
|
-
promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
catch (err) {
|
|
2642
|
-
onError(err);
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
}
|
|
2646
|
-
if (promiseChain) {
|
|
2647
|
-
return promiseChain.then(onDone);
|
|
2648
|
-
}
|
|
2649
|
-
else {
|
|
2650
|
-
onDone();
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Inject a pre-loaded value into an AsyncSignal while preserving track() subscriptions. Calls
|
|
2656
|
-
* `invalidate({ __v })` so the compute function reads the value from `info`, then triggers an
|
|
2657
|
-
* immediate synchronous compute via the private $computeIfNeeded$() method (which is mangled in
|
|
2658
|
-
* core builds, so callers from other packages must go through this helper).
|
|
2659
|
-
*
|
|
2660
|
-
* @internal
|
|
2661
|
-
*/
|
|
2662
|
-
const _injectAsyncSignalValue = (signal, value) => {
|
|
2663
|
-
const impl = signal;
|
|
2664
|
-
impl.invalidate({ __v: value });
|
|
2665
|
-
impl.$computeIfNeeded$();
|
|
2666
|
-
};
|
|
2667
|
-
|
|
2668
|
-
/** @internal */
|
|
2669
|
-
const _CONST_PROPS = Symbol('CONST');
|
|
2670
|
-
/** @internal */
|
|
2671
|
-
const _VAR_PROPS = Symbol('VAR');
|
|
2672
|
-
/** @internal */
|
|
2673
|
-
const _OWNER = Symbol('OWNER');
|
|
2674
|
-
/** @internal */
|
|
2675
|
-
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
2676
|
-
/** @internal @deprecated v1 compat */
|
|
2677
|
-
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
2678
|
-
/** @internal */
|
|
2679
|
-
const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
2680
|
-
|
|
2681
|
-
/** @internal */
|
|
2682
|
-
const EMPTY_ARRAY = [];
|
|
2683
|
-
/** @internal */
|
|
2684
|
-
const EMPTY_OBJ = {};
|
|
2685
|
-
Object.freeze(EMPTY_ARRAY);
|
|
2686
|
-
Object.freeze(EMPTY_OBJ);
|
|
2687
|
-
|
|
2688
|
-
function createPropsProxy(owner) {
|
|
2689
|
-
// TODO don't make a proxy but populate getters? benchmark
|
|
2690
|
-
return new Proxy({}, new PropsProxyHandler(owner));
|
|
2691
|
-
}
|
|
2692
|
-
class PropsProxyHandler {
|
|
2693
|
-
owner;
|
|
2694
|
-
$effects$ = undefined;
|
|
2695
|
-
$container$ = null;
|
|
2696
|
-
constructor(owner) {
|
|
2697
|
-
this.owner = owner;
|
|
2698
|
-
}
|
|
2699
|
-
get(_, prop) {
|
|
2700
|
-
// escape hatch to get the separated props from a component
|
|
2701
|
-
if (prop === _CONST_PROPS) {
|
|
2702
|
-
return this.owner.constProps;
|
|
2703
|
-
}
|
|
2704
|
-
else if (prop === _VAR_PROPS) {
|
|
2705
|
-
return this.owner.varProps;
|
|
2706
|
-
}
|
|
2707
|
-
else if (prop === _OWNER) {
|
|
2708
|
-
return this.owner;
|
|
2709
|
-
}
|
|
2710
|
-
else if (prop === _PROPS_HANDLER) {
|
|
2711
|
-
return this;
|
|
2712
|
-
}
|
|
2713
|
-
let value;
|
|
2714
|
-
if (prop === 'children') {
|
|
2715
|
-
value = this.owner.children;
|
|
2716
|
-
}
|
|
2717
|
-
else {
|
|
2718
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2719
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2720
|
-
if (attr) {
|
|
2721
|
-
prop = attr;
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
value = directGetPropsProxyProp(this.owner, prop);
|
|
2725
|
-
if (prop in this.owner.varProps) {
|
|
2726
|
-
addPropsProxyEffect(this, prop);
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
// a proxied value that the optimizer made
|
|
2730
|
-
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
2731
|
-
? value.value
|
|
2732
|
-
: value;
|
|
2733
|
-
}
|
|
2734
|
-
set(_, prop, value) {
|
|
2735
|
-
if (prop === _OWNER) {
|
|
2736
|
-
// used for deserialization
|
|
2737
|
-
this.owner = value;
|
|
2738
|
-
}
|
|
2739
|
-
else if (prop === 'children') {
|
|
2740
|
-
this.owner.children = value;
|
|
2741
|
-
}
|
|
2742
|
-
else if (prop === _CONST_PROPS) {
|
|
2743
|
-
this.owner.constProps = value;
|
|
2744
|
-
}
|
|
2745
|
-
else if (prop === _VAR_PROPS) {
|
|
2746
|
-
this.owner.varProps = value;
|
|
2747
|
-
}
|
|
2748
|
-
else {
|
|
2749
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2750
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2751
|
-
if (attr) {
|
|
2752
|
-
prop = attr;
|
|
2753
|
-
}
|
|
2754
|
-
}
|
|
2755
|
-
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
2756
|
-
// delete the prop from the const props first
|
|
2757
|
-
delete this.owner.constProps[prop];
|
|
2758
|
-
}
|
|
2759
|
-
if (this.owner.varProps === EMPTY_OBJ) {
|
|
2760
|
-
this.owner.varProps = {};
|
|
2761
|
-
}
|
|
2762
|
-
else if (!(prop in this.owner.varProps)) {
|
|
2763
|
-
this.owner.toSort = true;
|
|
2764
|
-
}
|
|
2765
|
-
if (this.owner.varProps[prop] !== value) {
|
|
2766
|
-
this.owner.varProps[prop] = value;
|
|
2767
|
-
triggerPropsProxyEffect(this, prop);
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
return true;
|
|
2771
|
-
}
|
|
2772
|
-
deleteProperty(_, prop) {
|
|
2773
|
-
let didDelete = delete this.owner.varProps[prop];
|
|
2774
|
-
if (didDelete) {
|
|
2775
|
-
triggerPropsProxyEffect(this, prop);
|
|
2776
|
-
}
|
|
2777
|
-
if (this.owner.constProps) {
|
|
2778
|
-
didDelete = delete this.owner.constProps[prop] || didDelete;
|
|
2779
|
-
}
|
|
2780
|
-
if (this.owner.children != null && prop === 'children') {
|
|
2781
|
-
this.owner.children = null;
|
|
2782
|
-
didDelete = true;
|
|
2783
|
-
}
|
|
2784
|
-
return didDelete;
|
|
2785
|
-
}
|
|
2786
|
-
has(_, prop) {
|
|
2787
|
-
if (prop === 'children') {
|
|
2788
|
-
return this.owner.children != null;
|
|
2789
|
-
}
|
|
2790
|
-
else if (prop === _CONST_PROPS || prop === _VAR_PROPS) {
|
|
2791
|
-
return true;
|
|
2792
|
-
}
|
|
2793
|
-
const inVarProps = prop in this.owner.varProps;
|
|
2794
|
-
if (typeof prop === 'string') {
|
|
2795
|
-
if (inVarProps) {
|
|
2796
|
-
addPropsProxyEffect(this, prop);
|
|
2797
|
-
}
|
|
2798
|
-
if (typeof this.owner.type === 'string') {
|
|
2799
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2800
|
-
if (attr) {
|
|
2801
|
-
prop = attr;
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2819
|
+
this.$requestCleanups$(current);
|
|
2820
|
+
}
|
|
2821
|
+
if (this.$jobs$) {
|
|
2822
|
+
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2823
|
+
}
|
|
2824
|
+
else {
|
|
2825
|
+
await current?.$promise$;
|
|
2804
2826
|
}
|
|
2805
|
-
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
2806
2827
|
}
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
? this.owner.children
|
|
2810
|
-
: this.owner.constProps && p in this.owner.constProps
|
|
2811
|
-
? this.owner.constProps[p]
|
|
2812
|
-
: this.owner.varProps[p];
|
|
2813
|
-
return {
|
|
2814
|
-
configurable: true,
|
|
2815
|
-
enumerable: true,
|
|
2816
|
-
value: value,
|
|
2817
|
-
};
|
|
2828
|
+
$hasSubscribers$() {
|
|
2829
|
+
return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
|
|
2818
2830
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
out.push('children');
|
|
2831
|
+
$requestCleanups$(job, reason) {
|
|
2832
|
+
if (job.$cleanupRequested$) {
|
|
2833
|
+
return;
|
|
2823
2834
|
}
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2835
|
+
job.$cleanupRequested$ = true;
|
|
2836
|
+
job.$abortController$?.abort(reason);
|
|
2837
|
+
job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
|
|
2838
|
+
}
|
|
2839
|
+
/** Run a job's cleanup callbacks, returning a promise when any of them are async. */
|
|
2840
|
+
$runCleanupCallbacks$(job) {
|
|
2841
|
+
const cleanups = job.$cleanups$;
|
|
2842
|
+
const onError = (err) => {
|
|
2843
|
+
const handleError = this.$container$?.handleError;
|
|
2844
|
+
if (handleError) {
|
|
2845
|
+
handleError(err, null);
|
|
2846
|
+
}
|
|
2847
|
+
else {
|
|
2848
|
+
console.error('Error in async signal cleanup', err);
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
let promiseChain = undefined;
|
|
2852
|
+
if (cleanups) {
|
|
2853
|
+
// Keep this sync-ish so sync functions run immediately.
|
|
2854
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
2855
|
+
try {
|
|
2856
|
+
const result = cleanups[i]();
|
|
2857
|
+
if (isPromise(result)) {
|
|
2858
|
+
promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
catch (err) {
|
|
2862
|
+
onError(err);
|
|
2828
2863
|
}
|
|
2829
2864
|
}
|
|
2865
|
+
cleanups.length = 0;
|
|
2830
2866
|
}
|
|
2831
|
-
return
|
|
2867
|
+
return promiseChain;
|
|
2832
2868
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
if (
|
|
2840
|
-
|
|
2869
|
+
/** Clean up and trigger signal compute once complete */
|
|
2870
|
+
$runCleanups$(job) {
|
|
2871
|
+
const onDone = () => {
|
|
2872
|
+
job.$promise$ = null;
|
|
2873
|
+
// Now trigger compute
|
|
2874
|
+
const jobs = this.$jobs$;
|
|
2875
|
+
if (jobs) {
|
|
2876
|
+
const idx = jobs.indexOf(job);
|
|
2877
|
+
if (idx !== -1) {
|
|
2878
|
+
jobs.splice(idx, 1);
|
|
2879
|
+
}
|
|
2841
2880
|
}
|
|
2881
|
+
this.$computeIfNeeded$();
|
|
2882
|
+
};
|
|
2883
|
+
const promiseChain = this.$runCleanupCallbacks$(job);
|
|
2884
|
+
if (promiseChain) {
|
|
2885
|
+
return promiseChain.then(onDone);
|
|
2842
2886
|
}
|
|
2843
2887
|
else {
|
|
2844
|
-
|
|
2845
|
-
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
2888
|
+
onDone();
|
|
2846
2889
|
}
|
|
2847
2890
|
}
|
|
2848
|
-
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
2849
|
-
if (effectSubscriber) {
|
|
2850
|
-
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
2851
|
-
}
|
|
2852
|
-
};
|
|
2853
|
-
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
2854
|
-
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
2855
|
-
if (effects) {
|
|
2856
|
-
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
2857
|
-
}
|
|
2858
|
-
return !!effects;
|
|
2859
|
-
};
|
|
2860
|
-
function getEffects$1(effects, prop) {
|
|
2861
|
-
// TODO: Handle STORE_ALL_PROPS
|
|
2862
|
-
return effects?.get(prop);
|
|
2863
2891
|
}
|
|
2864
|
-
/**
|
|
2865
|
-
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
2866
|
-
* Use this function to get the props directly from a const or var props.
|
|
2867
|
-
*
|
|
2868
|
-
* This does not convert jsx event names.
|
|
2869
|
-
*/
|
|
2870
|
-
const directGetPropsProxyProp = (jsx, prop) => {
|
|
2871
|
-
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
2872
|
-
};
|
|
2873
|
-
const _getProps = (props, prop) => {
|
|
2874
|
-
return _getVarProps(props)?.[prop] || _getConstProps(props)?.[prop] || null;
|
|
2875
|
-
};
|
|
2876
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2877
|
-
const _getVarProps = (props) => {
|
|
2878
|
-
if (!props) {
|
|
2879
|
-
return null;
|
|
2880
|
-
}
|
|
2881
|
-
return _VAR_PROPS in props
|
|
2882
|
-
? 'children' in props
|
|
2883
|
-
? { ...props[_VAR_PROPS], children: props.children }
|
|
2884
|
-
: props[_VAR_PROPS]
|
|
2885
|
-
: props;
|
|
2886
|
-
};
|
|
2887
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2888
|
-
const _getConstProps = (props) => {
|
|
2889
|
-
if (!props) {
|
|
2890
|
-
return null;
|
|
2891
|
-
}
|
|
2892
|
-
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
2893
|
-
};
|
|
2894
|
-
const isPropsProxy = (obj) => {
|
|
2895
|
-
return obj && _VAR_PROPS in obj;
|
|
2896
|
-
};
|
|
2897
2892
|
|
|
2898
2893
|
// <docs markdown="../../readme.md#implicit$FirstArg">
|
|
2899
2894
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
@@ -2949,11 +2944,11 @@ const implicit$FirstArg = (fn) => {
|
|
|
2949
2944
|
*/
|
|
2950
2945
|
class SerializerSignalImpl extends ComputedSignalImpl {
|
|
2951
2946
|
constructor(container, argQrl) {
|
|
2952
|
-
super(container, argQrl, 1 /*
|
|
2947
|
+
super(container, argQrl, 1 /* ComputedSignalFlags.INVALID */ | 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
|
|
2953
2948
|
}
|
|
2954
2949
|
$didInitialize$ = false;
|
|
2955
2950
|
$computeIfNeeded$() {
|
|
2956
|
-
if (!(this.$flags$ & 1 /*
|
|
2951
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
2957
2952
|
return;
|
|
2958
2953
|
}
|
|
2959
2954
|
throwIfQRLNotResolved(this.$computeQrl$);
|
|
@@ -2966,7 +2961,7 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2966
2961
|
: deserialize(currentValue), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
2967
2962
|
this.$didInitialize$ = true;
|
|
2968
2963
|
// Needs to invalidate only after all possible Promise throws happened
|
|
2969
|
-
this.$flags$ &= -2 /*
|
|
2964
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2970
2965
|
// We allow forcing the update of the signal without changing the value, for example when the deserialized value is the same reference as the old value but its internals have changed. In that case we want to trigger effects that depend on this signal, even though the value is the same.
|
|
2971
2966
|
const didChange = (this.$didInitialize$ && untrackedValue !== 'undefined') ||
|
|
2972
2967
|
untrackedValue !== this.$untrackedValue$;
|
|
@@ -2977,13 +2972,46 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2977
2972
|
}
|
|
2978
2973
|
}
|
|
2979
2974
|
|
|
2975
|
+
/**
|
|
2976
|
+
* # ================================
|
|
2977
|
+
*
|
|
2978
|
+
* AsyncSignalImpl
|
|
2979
|
+
*
|
|
2980
|
+
* # ================================
|
|
2981
|
+
*
|
|
2982
|
+
* The async engine (jobs, loading, error) lives in ComputedSignalImpl; this subclass configures it
|
|
2983
|
+
* from options and switches the compute invocation to CTX_ARG mode: the compute fn receives the
|
|
2984
|
+
* ComputeCtx argument and tracks only via its explicit `track()` (no auto-tracking).
|
|
2985
|
+
*
|
|
2986
|
+
* @internal
|
|
2987
|
+
*/
|
|
2988
|
+
class AsyncSignalImpl extends ComputedSignalImpl {
|
|
2989
|
+
constructor(container, fn, flags = 1 /* ComputedSignalFlags.INVALID */ |
|
|
2990
|
+
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
|
|
2991
|
+
super(container, fn, flags | 512 /* AsyncSignalFlags.ASYNC_MODE */ | 1024 /* AsyncSignalFlags.CTX_ARG */, options);
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
/**
|
|
2995
|
+
* Inject a pre-loaded value into a signal while preserving subscriptions. Calls `invalidate({__v})`
|
|
2996
|
+
* so the compute function reads the value from `info`, then triggers an immediate synchronous
|
|
2997
|
+
* compute via the private `$computeIfNeeded$()` method (which is mangled in core builds, so callers
|
|
2998
|
+
* from other packages must go through this helper).
|
|
2999
|
+
*
|
|
3000
|
+
* @internal
|
|
3001
|
+
*/
|
|
3002
|
+
const _injectAsyncSignalValue = (signal, value) => {
|
|
3003
|
+
const impl = signal;
|
|
3004
|
+
impl.invalidate({ __v: value });
|
|
3005
|
+
impl.$computeIfNeeded$();
|
|
3006
|
+
};
|
|
3007
|
+
|
|
2980
3008
|
/** @internal */
|
|
2981
3009
|
const createSignal$1 = (value) => {
|
|
2982
3010
|
return new SignalImpl(null, value);
|
|
2983
3011
|
};
|
|
2984
3012
|
/** @internal */
|
|
2985
3013
|
const createComputedSignal = (qrl, options) => {
|
|
2986
|
-
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'));
|
|
3014
|
+
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'), options);
|
|
2987
3015
|
};
|
|
2988
3016
|
/** @internal */
|
|
2989
3017
|
const createAsyncSignal = (qrl, options) => {
|
|
@@ -3007,9 +3035,10 @@ const createSignal = createSignal$1;
|
|
|
3007
3035
|
* recalculated.
|
|
3008
3036
|
*
|
|
3009
3037
|
* The QRL must be a function which returns the value of the signal. The function must not have side
|
|
3010
|
-
* effects
|
|
3011
|
-
*
|
|
3012
|
-
*
|
|
3038
|
+
* effects. Every synchronous signal or store read is tracked automatically; reads after the first
|
|
3039
|
+
* `await` must use the `track()` provided on the context argument. When the function is async, the
|
|
3040
|
+
* returned signal exposes the async API (`.pending`, `.error`, `.promise()`), and reading an
|
|
3041
|
+
* unresolved `.value` throws the computation promise.
|
|
3013
3042
|
*
|
|
3014
3043
|
* @public
|
|
3015
3044
|
*/
|
|
@@ -3018,6 +3047,7 @@ const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedSignal);
|
|
|
3018
3047
|
* Create a signal holding a `.value` which is calculated from the given async function (QRL). The
|
|
3019
3048
|
* standalone version of `useAsync$`.
|
|
3020
3049
|
*
|
|
3050
|
+
* @deprecated Use `createComputed$` instead, it has async support now.
|
|
3021
3051
|
* @public
|
|
3022
3052
|
*/
|
|
3023
3053
|
const createAsync$ = /*#__PURE__*/ implicit$FirstArg(createAsyncSignal);
|
|
@@ -3064,10 +3094,10 @@ const _wrapProp = (...args) => {
|
|
|
3064
3094
|
return obj[prop];
|
|
3065
3095
|
}
|
|
3066
3096
|
if (isSignal(obj)) {
|
|
3067
|
-
if (!(obj instanceof
|
|
3097
|
+
if (!(obj instanceof ComputedSignalImpl)) {
|
|
3068
3098
|
isDev && assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
3069
3099
|
}
|
|
3070
|
-
if (obj instanceof WrappedSignalImpl
|
|
3100
|
+
if (obj instanceof WrappedSignalImpl) {
|
|
3071
3101
|
return obj;
|
|
3072
3102
|
}
|
|
3073
3103
|
return getWrapped(args);
|
|
@@ -3121,7 +3151,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3121
3151
|
constructor(container, fn, args, fnStr,
|
|
3122
3152
|
// We need a separate flag to know when the computation needs running because
|
|
3123
3153
|
// we need the old value to know if effects need running after computation
|
|
3124
|
-
flags = 1 /*
|
|
3154
|
+
flags = 1 /* ComputedSignalFlags.INVALID */) {
|
|
3125
3155
|
super(container, NEEDS_COMPUTATION);
|
|
3126
3156
|
this.$args$ = args;
|
|
3127
3157
|
this.$func$ = fn;
|
|
@@ -3129,7 +3159,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3129
3159
|
this.$flags$ = flags;
|
|
3130
3160
|
}
|
|
3131
3161
|
invalidate() {
|
|
3132
|
-
this.$flags$ |= 1 /*
|
|
3162
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
3133
3163
|
// we are trying to run computation without creating a chore, which can be expensive
|
|
3134
3164
|
// for many signals. If it fails, we schedule a chore to run the computation.
|
|
3135
3165
|
try {
|
|
@@ -3142,8 +3172,8 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3142
3172
|
}
|
|
3143
3173
|
}
|
|
3144
3174
|
// if the computation not failed, we can run the effects directly
|
|
3145
|
-
if (this.$flags$ & 2 /*
|
|
3146
|
-
this.$flags$ &= -3 /*
|
|
3175
|
+
if (this.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
3176
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3147
3177
|
scheduleEffects(this.$container$, this, this.$effects$);
|
|
3148
3178
|
}
|
|
3149
3179
|
}
|
|
@@ -3153,7 +3183,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3153
3183
|
return this.$untrackedValue$;
|
|
3154
3184
|
}
|
|
3155
3185
|
$computeIfNeeded$() {
|
|
3156
|
-
if (!(this.$flags$ & 1 /*
|
|
3186
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
3157
3187
|
return;
|
|
3158
3188
|
}
|
|
3159
3189
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
@@ -3164,10 +3194,10 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3164
3194
|
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
3165
3195
|
// reset flag in case we call computedIfNeeded twice and the value was changed only the first time
|
|
3166
3196
|
// TODO: change to version number?
|
|
3167
|
-
this.$flags$ &= -3 /*
|
|
3197
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3168
3198
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
3169
3199
|
if (didChange) {
|
|
3170
|
-
this.$flags$ |= 2 /*
|
|
3200
|
+
this.$flags$ |= 2 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3171
3201
|
this.$untrackedValue$ = untrackedValue;
|
|
3172
3202
|
}
|
|
3173
3203
|
}
|
|
@@ -3271,12 +3301,15 @@ const isJSXNode = (n) => {
|
|
|
3271
3301
|
* load the QRL captured scope ourselves. Otherwise, we are being called as a QRL and the captures
|
|
3272
3302
|
* are already set.
|
|
3273
3303
|
*/
|
|
3274
|
-
const
|
|
3275
|
-
if (typeof
|
|
3304
|
+
const withScopeFromQL = (captureDeltas, element, callback) => {
|
|
3305
|
+
if (typeof captureDeltas === 'string') {
|
|
3276
3306
|
const container = getDomContainer(element);
|
|
3277
|
-
|
|
3307
|
+
return whenContainerDataReady(container, () => {
|
|
3308
|
+
setCaptures(deserializeCaptureDeltas(container, captureDeltas));
|
|
3309
|
+
return callback();
|
|
3310
|
+
});
|
|
3278
3311
|
}
|
|
3279
|
-
return
|
|
3312
|
+
return callback();
|
|
3280
3313
|
};
|
|
3281
3314
|
/**
|
|
3282
3315
|
* Handles events for bind:value
|
|
@@ -3284,9 +3317,10 @@ const maybeScopeFromQL = (captureIds, element) => {
|
|
|
3284
3317
|
* @internal
|
|
3285
3318
|
*/
|
|
3286
3319
|
function _val(_, element) {
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3320
|
+
return withScopeFromQL(this, element, () => {
|
|
3321
|
+
const signal = _captures[0];
|
|
3322
|
+
signal.value = element.type === 'number' ? element.valueAsNumber : element.value;
|
|
3323
|
+
});
|
|
3290
3324
|
}
|
|
3291
3325
|
/**
|
|
3292
3326
|
* Handles events for bind:checked
|
|
@@ -3294,9 +3328,10 @@ function _val(_, element) {
|
|
|
3294
3328
|
* @internal
|
|
3295
3329
|
*/
|
|
3296
3330
|
function _chk(_, element) {
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3331
|
+
return withScopeFromQL(this, element, () => {
|
|
3332
|
+
const signal = _captures[0];
|
|
3333
|
+
signal.value = element.checked;
|
|
3334
|
+
});
|
|
3300
3335
|
}
|
|
3301
3336
|
/**
|
|
3302
3337
|
* Resumes selected state (e.g. polling AsyncSignals) by deserializing captures. Used for
|
|
@@ -3305,17 +3340,18 @@ function _chk(_, element) {
|
|
|
3305
3340
|
* @internal
|
|
3306
3341
|
*/
|
|
3307
3342
|
function _res(_, element) {
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3343
|
+
return withScopeFromQL(this, element, () => {
|
|
3344
|
+
// Captures are deserialized, now trigger computation on AsyncSignals
|
|
3345
|
+
if (_captures) {
|
|
3346
|
+
for (let i = 0; i < _captures.length; i++) {
|
|
3347
|
+
const capture = _captures[i];
|
|
3348
|
+
if (capture instanceof AsyncSignalImpl && capture.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
3349
|
+
capture.$computeIfNeeded$();
|
|
3350
|
+
}
|
|
3351
|
+
// note that polling async signals will automatically schedule themselves so no action needed
|
|
3315
3352
|
}
|
|
3316
|
-
// note that polling async signals will automatically schedule themselves so no action needed
|
|
3317
3353
|
}
|
|
3318
|
-
}
|
|
3354
|
+
});
|
|
3319
3355
|
}
|
|
3320
3356
|
|
|
3321
3357
|
const BIND_VALUE = 'bind:value';
|
|
@@ -3956,31 +3992,25 @@ const useConstant = (value, ...args) => {
|
|
|
3956
3992
|
return set(value);
|
|
3957
3993
|
};
|
|
3958
3994
|
|
|
3959
|
-
const createCursorBoundary = () => {
|
|
3960
|
-
return {
|
|
3961
|
-
pending: createSignal(0),
|
|
3962
|
-
version: createSignal(0),
|
|
3963
|
-
};
|
|
3964
|
-
};
|
|
3965
3995
|
/** @internal */
|
|
3966
3996
|
const useCursorBoundary = () => {
|
|
3967
3997
|
if (!__EXPERIMENTAL__.suspense) {
|
|
3968
3998
|
throw new Error('useCursorBoundary is experimental and must be enabled with `experimental: ["suspense"]` in the `qwikVite` plugin.');
|
|
3969
3999
|
}
|
|
3970
|
-
return
|
|
4000
|
+
return useSignal(0);
|
|
3971
4001
|
};
|
|
3972
4002
|
function addCursorBoundary(cursorData, vNode) {
|
|
3973
4003
|
if (!__EXPERIMENTAL__.suspense) {
|
|
3974
4004
|
return;
|
|
3975
4005
|
}
|
|
3976
|
-
const boundary = getNearestCursorBoundary(
|
|
4006
|
+
const boundary = getNearestCursorBoundary(vNode);
|
|
3977
4007
|
if (!boundary) {
|
|
3978
4008
|
return;
|
|
3979
4009
|
}
|
|
3980
4010
|
const boundaries = (cursorData.boundaries ||= []);
|
|
3981
4011
|
if (!boundaries.includes(boundary)) {
|
|
3982
4012
|
boundaries.push(boundary);
|
|
3983
|
-
boundary.
|
|
4013
|
+
boundary.value++;
|
|
3984
4014
|
}
|
|
3985
4015
|
}
|
|
3986
4016
|
function resolveCursorBoundaries(cursorData) {
|
|
@@ -3994,40 +4024,35 @@ function resolveCursorBoundaries(cursorData) {
|
|
|
3994
4024
|
cursorData.boundaries = null;
|
|
3995
4025
|
for (let i = 0; i < boundaries.length; i++) {
|
|
3996
4026
|
const boundary = boundaries[i];
|
|
3997
|
-
boundary.
|
|
3998
|
-
boundary.version.value++;
|
|
3999
|
-
}
|
|
4000
|
-
}
|
|
4001
|
-
function getOwnCursorBoundary(container, vNode) {
|
|
4002
|
-
if (!__EXPERIMENTAL__.suspense) {
|
|
4003
|
-
return null;
|
|
4027
|
+
boundary.value = Math.max(0, boundary.value - 1);
|
|
4004
4028
|
}
|
|
4005
|
-
return container.getHostProp(vNode, QCursorBoundary);
|
|
4006
4029
|
}
|
|
4007
|
-
function
|
|
4030
|
+
function getOwnCursorBoundary(vNode) {
|
|
4008
4031
|
if (!__EXPERIMENTAL__.suspense) {
|
|
4009
4032
|
return null;
|
|
4010
4033
|
}
|
|
4011
|
-
return
|
|
4012
|
-
null);
|
|
4034
|
+
return vnode_getProp(vNode, QCursorBoundary, null) || null;
|
|
4013
4035
|
}
|
|
4014
4036
|
function clearNearestCursorBoundary(vNode) {
|
|
4015
|
-
|
|
4016
|
-
return;
|
|
4017
|
-
}
|
|
4018
|
-
vnode_setProp(vNode, NEAREST_CURSOR_BOUNDARY, null);
|
|
4037
|
+
setNearestCursorBoundary(vNode, null);
|
|
4019
4038
|
}
|
|
4020
|
-
function getNearestCursorBoundary(
|
|
4039
|
+
function getNearestCursorBoundary(vNode) {
|
|
4021
4040
|
if (!__EXPERIMENTAL__.suspense) {
|
|
4022
4041
|
return null;
|
|
4023
4042
|
}
|
|
4024
|
-
return
|
|
4043
|
+
return (vnode_getProp(vNode, NEAREST_CURSOR_BOUNDARY, null) ||
|
|
4044
|
+
getOwnCursorBoundary(vNode));
|
|
4025
4045
|
}
|
|
4026
4046
|
function setNearestCursorBoundary(vNode, boundary) {
|
|
4027
4047
|
__EXPERIMENTAL__.suspense && vnode_setProp(vNode, NEAREST_CURSOR_BOUNDARY, boundary);
|
|
4028
4048
|
}
|
|
4049
|
+
function clearCursorBoundary(vNode) {
|
|
4050
|
+
if (__EXPERIMENTAL__.suspense && vNode.props && QCursorBoundary in vNode.props) {
|
|
4051
|
+
vnode_setProp(vNode, QCursorBoundary, null);
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4029
4054
|
/** Updates the nearest cursor boundary cache on a vnode and any already-dirty descendants. */
|
|
4030
|
-
function updateDirtySubtreeCursorBoundary(
|
|
4055
|
+
function updateDirtySubtreeCursorBoundary(vNode, boundary) {
|
|
4031
4056
|
if (!__EXPERIMENTAL__.suspense) {
|
|
4032
4057
|
return;
|
|
4033
4058
|
}
|
|
@@ -4038,7 +4063,7 @@ function updateDirtySubtreeCursorBoundary(container, vNode, boundary) {
|
|
|
4038
4063
|
}
|
|
4039
4064
|
for (let i = 0; i < dirtyChildren.length; i++) {
|
|
4040
4065
|
const child = dirtyChildren[i];
|
|
4041
|
-
updateDirtySubtreeCursorBoundary(
|
|
4066
|
+
updateDirtySubtreeCursorBoundary(child, getOwnCursorBoundary(child) || boundary);
|
|
4042
4067
|
}
|
|
4043
4068
|
}
|
|
4044
4069
|
|
|
@@ -4095,7 +4120,8 @@ function runEventHandlerQRL(handler, event, element, ctx) {
|
|
|
4095
4120
|
return;
|
|
4096
4121
|
}
|
|
4097
4122
|
if (!ctx) {
|
|
4098
|
-
|
|
4123
|
+
const container = getDomContainer(element);
|
|
4124
|
+
return whenContainerDataReady(container, () => runEventHandlerQRL(handler, event, element, newInvokeContextFromDOM(event, element, container)));
|
|
4099
4125
|
}
|
|
4100
4126
|
const container = ctx.$container$;
|
|
4101
4127
|
const hostElement = ctx.$hostElement$;
|
|
@@ -4136,13 +4162,16 @@ function _run(event, element) {
|
|
|
4136
4162
|
// ignore events on disconnected elements, this can happen when the event is triggered while the element is being removed
|
|
4137
4163
|
return;
|
|
4138
4164
|
}
|
|
4139
|
-
const
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4165
|
+
const container = getDomContainer(element);
|
|
4166
|
+
return whenContainerDataReady(container, () => {
|
|
4167
|
+
const ctx = newInvokeContextFromDOM(event, element, container);
|
|
4168
|
+
if (typeof this === 'string') {
|
|
4169
|
+
setCaptures(deserializeCaptureDeltas(ctx.$container$, this));
|
|
4170
|
+
}
|
|
4171
|
+
const qrlToRun = _captures[0];
|
|
4172
|
+
isDev && assertQrl(qrlToRun);
|
|
4173
|
+
return runEventHandlerQRL(qrlToRun, event, element, ctx);
|
|
4174
|
+
});
|
|
4146
4175
|
}
|
|
4147
4176
|
|
|
4148
4177
|
function peekNextSibling(vCurrent) {
|
|
@@ -4303,9 +4332,7 @@ function diff(diffContext, jsxNode, vStartNode, vCurrent = vnode_getFirstChild(v
|
|
|
4303
4332
|
else if (type === Projection) {
|
|
4304
4333
|
expectProjection(diffContext);
|
|
4305
4334
|
descend(diffContext, diffContext.$jsxValue$.children, true,
|
|
4306
|
-
|
|
4307
|
-
// because the projection's children are not removed
|
|
4308
|
-
false);
|
|
4335
|
+
/* isProjection */ true);
|
|
4309
4336
|
}
|
|
4310
4337
|
else if (type === SSRComment) {
|
|
4311
4338
|
expectNoMore(diffContext);
|
|
@@ -4418,9 +4445,11 @@ function advance(diffContext) {
|
|
|
4418
4445
|
*
|
|
4419
4446
|
* In the above example all nodes are on same level so we don't `descendVNode` even thought there is
|
|
4420
4447
|
* an array produced by the `map` function.
|
|
4448
|
+
* @param isProjection - True when descending into a Projection, whose children survive re-renders:
|
|
4449
|
+
* they are diffed against (never re-created) and kept when the new JSX has no children.
|
|
4421
4450
|
*/
|
|
4422
|
-
function descend(diffContext, children, descendVNode,
|
|
4423
|
-
if (
|
|
4451
|
+
function descend(diffContext, children, descendVNode, isProjection = false) {
|
|
4452
|
+
if (!isProjection &&
|
|
4424
4453
|
(children == null || (descendVNode && isArray(children) && children.length === 0))) {
|
|
4425
4454
|
expectNoChildren(diffContext);
|
|
4426
4455
|
return;
|
|
@@ -4429,7 +4458,10 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
4429
4458
|
if (descendVNode) {
|
|
4430
4459
|
isDev &&
|
|
4431
4460
|
assertDefined(diffContext.$vCurrent$ || diffContext.$vNewNode$, 'Expecting vCurrent to be defined.');
|
|
4432
|
-
const creationMode =
|
|
4461
|
+
const creationMode =
|
|
4462
|
+
// a projection keeps its children across re-renders, so it never inherits
|
|
4463
|
+
// creation mode from a not-yet-rendered host; create only if new or empty
|
|
4464
|
+
(!isProjection && diffContext.$isCreationMode$) ||
|
|
4433
4465
|
!!diffContext.$vNewNode$ ||
|
|
4434
4466
|
!vnode_getFirstChild(diffContext.$vCurrent$);
|
|
4435
4467
|
diffContext.$isCreationMode$ = creationMode;
|
|
@@ -4581,7 +4613,7 @@ function expectSlot(diffContext) {
|
|
|
4581
4613
|
diffContext.$vNewNode$ = vnode_newVirtual();
|
|
4582
4614
|
vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
|
|
4583
4615
|
vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
|
|
4584
|
-
updateDirtySubtreeCursorBoundary(diffContext.$
|
|
4616
|
+
updateDirtySubtreeCursorBoundary(diffContext.$vNewNode$, cursorBoundary);
|
|
4585
4617
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
|
|
4586
4618
|
isDev &&
|
|
4587
4619
|
vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */); // Nothing to project, so render content of the slot.
|
|
@@ -4595,7 +4627,7 @@ function expectSlot(diffContext) {
|
|
|
4595
4627
|
diffContext.$vNewNode$ = vProjectedNode;
|
|
4596
4628
|
vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
|
|
4597
4629
|
vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
|
|
4598
|
-
updateDirtySubtreeCursorBoundary(diffContext.$
|
|
4630
|
+
updateDirtySubtreeCursorBoundary(diffContext.$vNewNode$, cursorBoundary);
|
|
4599
4631
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
|
|
4600
4632
|
isDev &&
|
|
4601
4633
|
vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
@@ -4862,18 +4894,20 @@ function diffProps(diffContext, vnode, newAttrs, currentFile) {
|
|
|
4862
4894
|
vnode_ensureElementInflated(diffContext.$container$, vnode);
|
|
4863
4895
|
}
|
|
4864
4896
|
const oldAttrs = vnode.props;
|
|
4897
|
+
const isHtml = (vnode.flags & 1536 /* VNodeFlags.NAMESPACE_MASK */) === 0 /* VNodeFlags.NS_html */;
|
|
4865
4898
|
// Actual diffing logic
|
|
4866
4899
|
// Apply all new attributes
|
|
4867
4900
|
for (const key in newAttrs) {
|
|
4868
4901
|
const newValue = newAttrs[key];
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4902
|
+
// HTML parsers lowercase attribute names.
|
|
4903
|
+
const oldKey = oldAttrs && isHtml && !_hasOwnProperty.call(oldAttrs, key) ? key.toLowerCase() : key;
|
|
4904
|
+
if (oldAttrs && _hasOwnProperty.call(oldAttrs, oldKey)) {
|
|
4905
|
+
const oldValue = oldAttrs[oldKey];
|
|
4906
|
+
if (oldKey !== key) {
|
|
4907
|
+
vnode_setProp(vnode, oldKey, null);
|
|
4908
|
+
vnode_setProp(vnode, key, oldValue);
|
|
4909
|
+
}
|
|
4910
|
+
if (!areDiffValuesEqual(newValue, oldValue)) {
|
|
4877
4911
|
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
4878
4912
|
}
|
|
4879
4913
|
}
|
|
@@ -5285,7 +5319,9 @@ function getComponentHash(vNode, getObject) {
|
|
|
5285
5319
|
return null;
|
|
5286
5320
|
}
|
|
5287
5321
|
const qrl = vnode_getProp(vNode, OnRenderProp, getObject);
|
|
5288
|
-
return qrl
|
|
5322
|
+
return qrl
|
|
5323
|
+
? qrl.$hash$
|
|
5324
|
+
: vnode_getProp(vNode, QComponentHash, null);
|
|
5289
5325
|
}
|
|
5290
5326
|
/**
|
|
5291
5327
|
* Marker class for JSX projection.
|
|
@@ -5343,13 +5379,26 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
5343
5379
|
if (key === 'children' || key === QBackRefs) {
|
|
5344
5380
|
continue;
|
|
5345
5381
|
}
|
|
5346
|
-
|
|
5382
|
+
const newValue = src[key];
|
|
5383
|
+
const oldValue = dst?.[key];
|
|
5384
|
+
if (!dst ||
|
|
5385
|
+
!(areDiffValuesEqual(newValue, oldValue) || areSignalValuesEqual(newValue, oldValue))) {
|
|
5386
|
+
if (key === 'class') {
|
|
5387
|
+
if (areClassValuesEqual(newValue, oldValue)) {
|
|
5388
|
+
continue;
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
else if (key === 'style') {
|
|
5392
|
+
if (areStyleValuesEqual(newValue, oldValue)) {
|
|
5393
|
+
continue;
|
|
5394
|
+
}
|
|
5395
|
+
}
|
|
5347
5396
|
if (triggerEffects) {
|
|
5348
5397
|
if (dst) {
|
|
5349
5398
|
// Update the value in dst BEFORE triggering effects
|
|
5350
5399
|
// so effects see the new value
|
|
5351
5400
|
// Note: Value is not triggering effects, because we are modyfing direct VAR_PROPS object
|
|
5352
|
-
dst[key] =
|
|
5401
|
+
dst[key] = newValue;
|
|
5353
5402
|
}
|
|
5354
5403
|
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
5355
5404
|
if (!didTigger) {
|
|
@@ -5436,10 +5485,16 @@ function cleanup(container, journal, vNode, cursorRoot = null) {
|
|
|
5436
5485
|
// don't call cleanupDestroyable yet, do it by the scheduler
|
|
5437
5486
|
continue;
|
|
5438
5487
|
}
|
|
5439
|
-
|
|
5440
|
-
|
|
5488
|
+
// Stores and plain signals are only producers; their subscriptions are removed
|
|
5489
|
+
// when cleaning the consumers that read them. They don't own reactive backrefs.
|
|
5490
|
+
else if (obj instanceof ComputedSignalImpl || obj instanceof WrappedSignalImpl) {
|
|
5491
|
+
if (!(obj.$flags$ & 4 /* ComputedSignalFlags.PRESERVE_ON_SEQ_CLEANUP */)) {
|
|
5492
|
+
clearAllEffects(container, obj);
|
|
5493
|
+
}
|
|
5441
5494
|
}
|
|
5442
|
-
if (objIsTask ||
|
|
5495
|
+
if (objIsTask ||
|
|
5496
|
+
(obj instanceof ComputedSignalImpl &&
|
|
5497
|
+
(obj.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */ || obj.$current$))) {
|
|
5443
5498
|
cleanupDestroyable(obj);
|
|
5444
5499
|
}
|
|
5445
5500
|
}
|
|
@@ -5558,6 +5613,37 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
5558
5613
|
*/
|
|
5559
5614
|
vCursor.flags |= 32 /* VNodeFlags.Deleted */;
|
|
5560
5615
|
}
|
|
5616
|
+
function areDiffValuesEqual(newValue, oldValue) {
|
|
5617
|
+
if (newValue === oldValue) {
|
|
5618
|
+
return true;
|
|
5619
|
+
}
|
|
5620
|
+
return (newValue instanceof WrappedSignalImpl &&
|
|
5621
|
+
oldValue instanceof WrappedSignalImpl &&
|
|
5622
|
+
areWrappedSignalsEqual(oldValue, newValue));
|
|
5623
|
+
}
|
|
5624
|
+
function areSignalValuesEqual(newValue, oldValue) {
|
|
5625
|
+
if (newValue === oldValue) {
|
|
5626
|
+
return true;
|
|
5627
|
+
}
|
|
5628
|
+
if (isSignal(newValue) && isSignal(oldValue)) {
|
|
5629
|
+
const unwrappedNew = newValue instanceof WrappedSignalImpl ? newValue.$unwrapIfSignal$() : newValue;
|
|
5630
|
+
const unwrappedOld = oldValue instanceof WrappedSignalImpl ? oldValue.$unwrapIfSignal$() : oldValue;
|
|
5631
|
+
return untrack(() => unwrappedNew.value === unwrappedOld.value);
|
|
5632
|
+
}
|
|
5633
|
+
return false;
|
|
5634
|
+
}
|
|
5635
|
+
function areStyleValuesEqual(newValue, oldValue) {
|
|
5636
|
+
if (newValue === oldValue) {
|
|
5637
|
+
return true;
|
|
5638
|
+
}
|
|
5639
|
+
return stringifyStyle(newValue) === stringifyStyle(oldValue);
|
|
5640
|
+
}
|
|
5641
|
+
function areClassValuesEqual(newValue, oldValue) {
|
|
5642
|
+
if (newValue === oldValue) {
|
|
5643
|
+
return true;
|
|
5644
|
+
}
|
|
5645
|
+
return serializeClass(newValue) === serializeClass(oldValue);
|
|
5646
|
+
}
|
|
5561
5647
|
function areWrappedSignalsEqual(oldSignal, newSignal) {
|
|
5562
5648
|
if (oldSignal === newSignal) {
|
|
5563
5649
|
return true;
|
|
@@ -5860,8 +5946,8 @@ function findFirstElementNode(jsx) {
|
|
|
5860
5946
|
function injectPlaceholderElement(jsx, placeholder) {
|
|
5861
5947
|
// For regular JSX nodes, we can append the placeholder to its children.
|
|
5862
5948
|
if (isJSXNode(jsx)) {
|
|
5863
|
-
// Inline components
|
|
5864
|
-
if (jsx.type !== Fragment
|
|
5949
|
+
// Inline components may ignore children, while component$ children become projections.
|
|
5950
|
+
if (jsx.type !== Fragment) {
|
|
5865
5951
|
return _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null);
|
|
5866
5952
|
}
|
|
5867
5953
|
if (jsx.children == null) {
|
|
@@ -6406,8 +6492,8 @@ function executeCompute(vNode, container) {
|
|
|
6406
6492
|
ctx.$container$ = container;
|
|
6407
6493
|
// needed for computed signals and throwing QRLs
|
|
6408
6494
|
return maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
|
|
6409
|
-
if (target.$flags$ & 2 /*
|
|
6410
|
-
target.$flags$ &= -3 /*
|
|
6495
|
+
if (target.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
6496
|
+
target.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
6411
6497
|
return scheduleEffects(container, target, effects);
|
|
6412
6498
|
}
|
|
6413
6499
|
});
|
|
@@ -6825,6 +6911,7 @@ function finishWalk(container, cursor, cursorData, isServer) {
|
|
|
6825
6911
|
executeFlushPhase(cursor, container);
|
|
6826
6912
|
}
|
|
6827
6913
|
resolveCursorBoundaries(cursorData);
|
|
6914
|
+
clearCursorBoundary(cursor);
|
|
6828
6915
|
if (cursorData.extraPromises) {
|
|
6829
6916
|
Promise.all(cursorData.extraPromises).then(() => {
|
|
6830
6917
|
resolveCursor(container);
|
|
@@ -6925,12 +7012,7 @@ function getNextVNode(vNode, cursor, container) {
|
|
|
6925
7012
|
return getNextVNode(parent, cursor, container);
|
|
6926
7013
|
}
|
|
6927
7014
|
function splitCursorBoundary(container, vNode) {
|
|
6928
|
-
if (!
|
|
6929
|
-
return false;
|
|
6930
|
-
}
|
|
6931
|
-
if (!vNode.props ||
|
|
6932
|
-
!(QCursorBoundary in vNode.props) ||
|
|
6933
|
-
!container.getHostProp(vNode, QCursorBoundary)) {
|
|
7015
|
+
if (!getOwnCursorBoundary(vNode)) {
|
|
6934
7016
|
return false;
|
|
6935
7017
|
}
|
|
6936
7018
|
if (!isCursor(vNode)) {
|
|
@@ -6948,6 +7030,10 @@ function splitCursorBoundary(container, vNode) {
|
|
|
6948
7030
|
* @returns The vNode itself, now acting as a cursor
|
|
6949
7031
|
*/
|
|
6950
7032
|
function addCursor(container, root, priority) {
|
|
7033
|
+
if (isCursor(root)) {
|
|
7034
|
+
triggerCursors();
|
|
7035
|
+
return root;
|
|
7036
|
+
}
|
|
6951
7037
|
const cursorData = {
|
|
6952
7038
|
afterFlushTasks: null,
|
|
6953
7039
|
extraPromises: null,
|
|
@@ -7000,7 +7086,11 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
7000
7086
|
if (ssrNode.dirty & 32 /* ChoreBits.COMPUTE */) {
|
|
7001
7087
|
executeCompute(ssrNode, container);
|
|
7002
7088
|
}
|
|
7003
|
-
if (isDev &&
|
|
7089
|
+
if (isDev &&
|
|
7090
|
+
ssrNode.dirty & 1023 /* ChoreBits.DIRTY_MASK */ &&
|
|
7091
|
+
!(ssrNode.flags & 2 /* SsrNodeFlags.WarnedStreamedChore */)) {
|
|
7092
|
+
// Warn once per host; a re-dirtied streamed host would otherwise spam every tick.
|
|
7093
|
+
ssrNode.flags |= 2 /* SsrNodeFlags.WarnedStreamedChore */;
|
|
7004
7094
|
// We are running on the server.
|
|
7005
7095
|
// On server we can't schedule task for a different host!
|
|
7006
7096
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -7123,17 +7213,16 @@ function propagatePath(target) {
|
|
|
7123
7213
|
* Propagates dirty bits from vNode up to the specified cursorRoot. Used during diff when we know
|
|
7124
7214
|
* the cursor root to merge with. Also updates cursor position if we pass through any cursors.
|
|
7125
7215
|
*/
|
|
7126
|
-
function propagateToCursorRoot(
|
|
7216
|
+
function propagateToCursorRoot(vNode, cursorRoot) {
|
|
7127
7217
|
reusablePath.push(vNode);
|
|
7128
|
-
let cursorBoundary = getOwnCursorBoundary(
|
|
7218
|
+
let cursorBoundary = getOwnCursorBoundary(vNode);
|
|
7129
7219
|
let current = vNode.slotParent || vNode.parent;
|
|
7130
7220
|
while (current) {
|
|
7131
7221
|
const isDirty = current.dirty & 1023 /* ChoreBits.DIRTY_MASK */;
|
|
7132
7222
|
const currentIsCursor = isCursor(current);
|
|
7133
7223
|
if (__EXPERIMENTAL__.suspense) {
|
|
7134
7224
|
cursorBoundary ||=
|
|
7135
|
-
getOwnCursorBoundary(
|
|
7136
|
-
(isDirty ? getNearestCursorBoundary(container, current) : null);
|
|
7225
|
+
getOwnCursorBoundary(current) || (isDirty ? getNearestCursorBoundary(current) : null);
|
|
7137
7226
|
}
|
|
7138
7227
|
// Stop when we reach the cursor root or a dirty ancestor
|
|
7139
7228
|
if (current === cursorRoot || isDirty) {
|
|
@@ -7168,18 +7257,16 @@ function propagateToCursorRoot(container, vNode, cursorRoot) {
|
|
|
7168
7257
|
* Finds a blocking cursor or dirty ancestor and propagates dirty bits to it. Returns true if found
|
|
7169
7258
|
* and attached, false if a new cursor should be created.
|
|
7170
7259
|
*/
|
|
7171
|
-
function findAndPropagateToBlockingCursor(
|
|
7260
|
+
function findAndPropagateToBlockingCursor(vNode) {
|
|
7172
7261
|
reusablePath.push(vNode);
|
|
7173
|
-
let cursorBoundary =
|
|
7174
|
-
? getOwnCursorBoundary(container, vNode)
|
|
7175
|
-
: null;
|
|
7262
|
+
let cursorBoundary = getOwnCursorBoundary(vNode);
|
|
7176
7263
|
let current = vNode.slotParent || vNode.parent;
|
|
7177
7264
|
while (current) {
|
|
7178
7265
|
const currentIsCursor = isCursor(current);
|
|
7179
7266
|
if (__EXPERIMENTAL__.suspense) {
|
|
7180
7267
|
cursorBoundary ||=
|
|
7181
|
-
getOwnCursorBoundary(
|
|
7182
|
-
(currentIsCursor ? getNearestCursorBoundary(
|
|
7268
|
+
getOwnCursorBoundary(current) ||
|
|
7269
|
+
(currentIsCursor ? getNearestCursorBoundary(current) : null);
|
|
7183
7270
|
}
|
|
7184
7271
|
if (currentIsCursor) {
|
|
7185
7272
|
// Existing cursor case: attach this dirty vnode to the blocking cursor found above it and
|
|
@@ -7220,7 +7307,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
7220
7307
|
? container.$renderPromise$.then(() => result)
|
|
7221
7308
|
: result;
|
|
7222
7309
|
}
|
|
7223
|
-
return;
|
|
7310
|
+
return result;
|
|
7224
7311
|
}
|
|
7225
7312
|
const isRealDirty = bits & 1023 /* ChoreBits.DIRTY_MASK */;
|
|
7226
7313
|
// If already dirty, no need to propagate again
|
|
@@ -7230,14 +7317,14 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
7230
7317
|
const parent = vNode.slotParent || vNode.parent;
|
|
7231
7318
|
// If cursorRoot is provided, propagate up to it
|
|
7232
7319
|
if (cursorRoot && isRealDirty && parent && !parent.dirty) {
|
|
7233
|
-
propagateToCursorRoot(
|
|
7320
|
+
propagateToCursorRoot(vNode, cursorRoot);
|
|
7234
7321
|
return;
|
|
7235
7322
|
}
|
|
7236
7323
|
// We must attach to a cursor subtree if it exists
|
|
7237
7324
|
if (parent && parent.dirty & 1023 /* ChoreBits.DIRTY_MASK */) {
|
|
7238
7325
|
// Dirty parent case: this vnode joins an already scheduled subtree, so inherit the parent's
|
|
7239
7326
|
// nearest boundary unless this vnode owns a boundary itself.
|
|
7240
|
-
setNearestCursorBoundary(vNode, getOwnCursorBoundary(
|
|
7327
|
+
setNearestCursorBoundary(vNode, getOwnCursorBoundary(vNode) || getNearestCursorBoundary(parent));
|
|
7241
7328
|
if (isRealDirty) {
|
|
7242
7329
|
parent.dirty |= 64 /* ChoreBits.CHILDREN */;
|
|
7243
7330
|
}
|
|
@@ -7269,7 +7356,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
7269
7356
|
else if (!isCursor(vNode)) {
|
|
7270
7357
|
// Check if there's an existing cursor that is blocking (executing a render-blocking task)
|
|
7271
7358
|
// If so, merge with it instead of creating a new cursor (single-pass find + propagate)
|
|
7272
|
-
if (!findAndPropagateToBlockingCursor(
|
|
7359
|
+
if (!findAndPropagateToBlockingCursor(vNode)) {
|
|
7273
7360
|
// No blocking cursor found, create a new one
|
|
7274
7361
|
addCursor(container, vNode, 0);
|
|
7275
7362
|
}
|
|
@@ -7277,7 +7364,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
7277
7364
|
else {
|
|
7278
7365
|
// Existing cursor-root case: the vnode is already the scheduled cursor, so only its own
|
|
7279
7366
|
// boundary can be authoritative here.
|
|
7280
|
-
setNearestCursorBoundary(vNode, getOwnCursorBoundary(
|
|
7367
|
+
setNearestCursorBoundary(vNode, getOwnCursorBoundary(vNode));
|
|
7281
7368
|
}
|
|
7282
7369
|
}
|
|
7283
7370
|
function addVNodeOperation(journal, operation) {
|
|
@@ -8717,8 +8804,17 @@ const processVNodeData$1 = (vData, callback) => {
|
|
|
8717
8804
|
}
|
|
8718
8805
|
return vData.substring(start, nextToConsumeIdx);
|
|
8719
8806
|
};
|
|
8807
|
+
const consumeEncodedValue = () => {
|
|
8808
|
+
if (getChar(nextToConsumeIdx + 1) !== VNodeDataChar.SEPARATOR) {
|
|
8809
|
+
return consumeValue();
|
|
8810
|
+
}
|
|
8811
|
+
consume();
|
|
8812
|
+
const value = decodeURIComponent(decodeVNodeDataString(consumeValue()));
|
|
8813
|
+
consume();
|
|
8814
|
+
return value;
|
|
8815
|
+
};
|
|
8720
8816
|
while (peek() !== 0) {
|
|
8721
|
-
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
|
|
8817
|
+
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx, consumeEncodedValue);
|
|
8722
8818
|
}
|
|
8723
8819
|
};
|
|
8724
8820
|
/** @internal */
|
|
@@ -8909,13 +9005,13 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8909
9005
|
return !nodeIsElement || (nodeIsElement && shouldSkipElement(node));
|
|
8910
9006
|
};
|
|
8911
9007
|
let components = null;
|
|
8912
|
-
processVNodeData$1(vData, (peek, consumeValue, consume, getChar,
|
|
9008
|
+
processVNodeData$1(vData, (peek, consumeValue, consume, getChar, dataIdx, consumeEncodedValue) => {
|
|
8913
9009
|
if (isNumber(peek())) {
|
|
8914
9010
|
// Element counts get encoded as numbers.
|
|
8915
9011
|
while (shouldSkipNode(child)) {
|
|
8916
9012
|
child = fastNextSibling(child);
|
|
8917
9013
|
if (!child) {
|
|
8918
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9014
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8919
9015
|
}
|
|
8920
9016
|
}
|
|
8921
9017
|
combinedText = null;
|
|
@@ -8936,7 +9032,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8936
9032
|
shouldSkipElement(child)) {
|
|
8937
9033
|
child = fastNextSibling(child);
|
|
8938
9034
|
if (!child && value > 0) {
|
|
8939
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9035
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8940
9036
|
}
|
|
8941
9037
|
}
|
|
8942
9038
|
}
|
|
@@ -8946,8 +9042,14 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8946
9042
|
vnode_setProp(vParent, QScopedStyle, consumeValue());
|
|
8947
9043
|
}
|
|
8948
9044
|
else if (peek() === VNodeDataChar.RENDER_FN) {
|
|
8949
|
-
|
|
8950
|
-
|
|
9045
|
+
const renderRef = consumeValue();
|
|
9046
|
+
if (renderRef.charCodeAt(0) === VNodeDataChar.RENDER_HASH_PREFIX) {
|
|
9047
|
+
vnode_setProp(vParent, QComponentHash, decodeURIComponent(decodeVNodeDataString(renderRef.slice(1))));
|
|
9048
|
+
}
|
|
9049
|
+
else {
|
|
9050
|
+
(components ||= []).push(vParent);
|
|
9051
|
+
vnode_setProp(vParent, OnRenderProp, renderRef);
|
|
9052
|
+
}
|
|
8951
9053
|
}
|
|
8952
9054
|
else if (peek() === VNodeDataChar.ID) {
|
|
8953
9055
|
if (!container) {
|
|
@@ -8961,17 +9063,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8961
9063
|
vnode_setProp(vParent, ELEMENT_PROPS, consumeValue());
|
|
8962
9064
|
}
|
|
8963
9065
|
else if (peek() === VNodeDataChar.KEY) {
|
|
8964
|
-
|
|
8965
|
-
let value;
|
|
8966
|
-
if (isEscapedValue) {
|
|
8967
|
-
consume();
|
|
8968
|
-
value = decodeURIComponent(decodeVNodeDataString(consumeValue()));
|
|
8969
|
-
consume();
|
|
8970
|
-
}
|
|
8971
|
-
else {
|
|
8972
|
-
value = consumeValue();
|
|
8973
|
-
}
|
|
8974
|
-
vParent.key = value;
|
|
9066
|
+
vParent.key = consumeEncodedValue();
|
|
8975
9067
|
}
|
|
8976
9068
|
else if (peek() === VNodeDataChar.SEQ) {
|
|
8977
9069
|
vnode_setProp(vParent, ELEMENT_SEQ, consumeValue());
|
|
@@ -9005,8 +9097,8 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
9005
9097
|
else if (peek() === VNodeDataChar.SEPARATOR) {
|
|
9006
9098
|
// Custom attribute: |key|value
|
|
9007
9099
|
const keyValue = consumeValue();
|
|
9008
|
-
const key = decodeVNodeDataString(keyValue);
|
|
9009
|
-
const valueSeparatorIdx =
|
|
9100
|
+
const key = decodeURIComponent(decodeVNodeDataString(keyValue));
|
|
9101
|
+
const valueSeparatorIdx = dataIdx + keyValue.length + 1;
|
|
9010
9102
|
const isEscapedValue = getChar(valueSeparatorIdx + 1) === VNodeDataChar.SEPARATOR;
|
|
9011
9103
|
let value;
|
|
9012
9104
|
if (isEscapedValue) {
|
|
@@ -9029,8 +9121,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
9029
9121
|
vParent = stack.pop();
|
|
9030
9122
|
}
|
|
9031
9123
|
else if (peek() === VNodeDataChar.SLOT) {
|
|
9032
|
-
|
|
9033
|
-
vnode_setProp(vParent, QSlot, value);
|
|
9124
|
+
vnode_setProp(vParent, QSlot, consumeEncodedValue());
|
|
9034
9125
|
}
|
|
9035
9126
|
else {
|
|
9036
9127
|
// skip over style or non-qwik elements in front of text nodes, where text node is the first child (except the style node)
|
|
@@ -9141,12 +9232,12 @@ function clearEffectSubscription(container, effect) {
|
|
|
9141
9232
|
return;
|
|
9142
9233
|
}
|
|
9143
9234
|
for (const producer of backRefs) {
|
|
9144
|
-
|
|
9145
|
-
if (producer instanceof AsyncSignalImpl) {
|
|
9146
|
-
clearAsyncSignal(producer, effect);
|
|
9147
|
-
}
|
|
9148
|
-
else if (producer instanceof SignalImpl) {
|
|
9235
|
+
if (producer instanceof SignalImpl) {
|
|
9149
9236
|
clearSignal(container, producer, effect);
|
|
9237
|
+
if (producer instanceof ComputedSignalImpl) {
|
|
9238
|
+
// computeds can carry async engine state (loading/error subscribers)
|
|
9239
|
+
clearAsyncSignalEffects(producer, effect);
|
|
9240
|
+
}
|
|
9150
9241
|
}
|
|
9151
9242
|
else if (isPropsProxy(producer)) {
|
|
9152
9243
|
const propsHandler = producer[_PROPS_HANDLER];
|
|
@@ -9171,11 +9262,7 @@ function clearSignal(container, producer, effect) {
|
|
|
9171
9262
|
clearAllEffects(container, producer);
|
|
9172
9263
|
}
|
|
9173
9264
|
}
|
|
9174
|
-
function
|
|
9175
|
-
const effects = producer.$effects$;
|
|
9176
|
-
if (effects && effects.has(effect)) {
|
|
9177
|
-
effects.delete(effect);
|
|
9178
|
-
}
|
|
9265
|
+
function clearAsyncSignalEffects(producer, effect) {
|
|
9179
9266
|
const pendingEffects = producer.$loadingEffects$;
|
|
9180
9267
|
if (pendingEffects && pendingEffects.has(effect)) {
|
|
9181
9268
|
pendingEffects.delete(effect);
|
|
@@ -9211,7 +9298,7 @@ const useTaskQrl = (qrl, opts) => {
|
|
|
9211
9298
|
const taskFlags =
|
|
9212
9299
|
// enabled by default
|
|
9213
9300
|
opts?.deferUpdates === false ? 0 : 8 /* TaskFlags.RENDER_BLOCKING */;
|
|
9214
|
-
const task = new Task(4 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl,
|
|
9301
|
+
const task = new Task(4 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, null);
|
|
9215
9302
|
// In V2 we add the task to the sequential scope. We need to do this
|
|
9216
9303
|
// in order to be able to retrieve it later when the parent element is
|
|
9217
9304
|
// deleted and we need to be able to release the task subscriptions.
|
|
@@ -9270,17 +9357,15 @@ class Task extends BackRef {
|
|
|
9270
9357
|
$index$;
|
|
9271
9358
|
$el$;
|
|
9272
9359
|
$qrl$;
|
|
9273
|
-
$state$;
|
|
9274
9360
|
$destroy$;
|
|
9275
9361
|
$destroyPromise$;
|
|
9276
9362
|
$taskPromise$ = null;
|
|
9277
|
-
constructor($flags$, $index$, $el$, $qrl$, $
|
|
9363
|
+
constructor($flags$, $index$, $el$, $qrl$, $destroy$) {
|
|
9278
9364
|
super();
|
|
9279
9365
|
this.$flags$ = $flags$;
|
|
9280
9366
|
this.$index$ = $index$;
|
|
9281
9367
|
this.$el$ = $el$;
|
|
9282
9368
|
this.$qrl$ = $qrl$;
|
|
9283
|
-
this.$state$ = $state$;
|
|
9284
9369
|
this.$destroy$ = $destroy$;
|
|
9285
9370
|
}
|
|
9286
9371
|
}
|
|
@@ -9296,12 +9381,14 @@ const isTask = (value) => {
|
|
|
9296
9381
|
*/
|
|
9297
9382
|
function scheduleTask(_event, element) {
|
|
9298
9383
|
const container = getDomContainer(element);
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9384
|
+
return whenContainerDataReady(container, () => {
|
|
9385
|
+
if (typeof this === 'string') {
|
|
9386
|
+
setCaptures(deserializeCaptureDeltas(container, this));
|
|
9387
|
+
}
|
|
9388
|
+
const task = _captures[0];
|
|
9389
|
+
task.$flags$ |= 4 /* TaskFlags.DIRTY */;
|
|
9390
|
+
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
9391
|
+
});
|
|
9305
9392
|
}
|
|
9306
9393
|
|
|
9307
9394
|
const throwIfQRLNotResolved = (qrl) => {
|
|
@@ -9413,7 +9500,7 @@ const isSerializerObj = (obj) => {
|
|
|
9413
9500
|
return isObject(obj) && typeof obj[SerializerSymbol] === 'function';
|
|
9414
9501
|
};
|
|
9415
9502
|
const getComputedSignalFlags = (serializationStrategy) => {
|
|
9416
|
-
let flags = 1 /*
|
|
9503
|
+
let flags = 1 /* ComputedSignalFlags.INVALID */;
|
|
9417
9504
|
switch (serializationStrategy) {
|
|
9418
9505
|
// TODO: implement this in the future
|
|
9419
9506
|
// case 'auto':
|
|
@@ -9428,6 +9515,18 @@ const getComputedSignalFlags = (serializationStrategy) => {
|
|
|
9428
9515
|
}
|
|
9429
9516
|
return flags;
|
|
9430
9517
|
};
|
|
9518
|
+
/**
|
|
9519
|
+
* Mark this signal as owned outside of the component that read it.
|
|
9520
|
+
*
|
|
9521
|
+
* Externally owned signals are preserved when found in a component's sequential scope during
|
|
9522
|
+
* component cleanup.
|
|
9523
|
+
*
|
|
9524
|
+
* @internal
|
|
9525
|
+
*/
|
|
9526
|
+
const _markSignalAsExternallyOwned = (signal) => {
|
|
9527
|
+
signal.$flags$ |=
|
|
9528
|
+
4 /* ComputedSignalFlags.PRESERVE_ON_SEQ_CLEANUP */;
|
|
9529
|
+
};
|
|
9431
9530
|
|
|
9432
9531
|
const stringifyPath = [];
|
|
9433
9532
|
function qwikDebugToString(value) {
|
|
@@ -9787,6 +9886,7 @@ function getEffects(target, prop, storeEffects) {
|
|
|
9787
9886
|
|
|
9788
9887
|
/** Used to represent an undefined value that must be serialized */
|
|
9789
9888
|
const explicitUndefined = Symbol('undefined');
|
|
9889
|
+
const EMPTY_OBJECT_PAYLOAD = 0;
|
|
9790
9890
|
// Used for allocate, make sure they are in sync with Constants
|
|
9791
9891
|
const _constants = [
|
|
9792
9892
|
undefined,
|
|
@@ -9807,6 +9907,10 @@ const _constants = [
|
|
|
9807
9907
|
Number.MAX_SAFE_INTEGER,
|
|
9808
9908
|
Number.MAX_SAFE_INTEGER - 1,
|
|
9809
9909
|
Number.MIN_SAFE_INTEGER,
|
|
9910
|
+
':',
|
|
9911
|
+
'.',
|
|
9912
|
+
'id',
|
|
9913
|
+
'ref',
|
|
9810
9914
|
];
|
|
9811
9915
|
// Used for dumpState, make sure they are in sync with Constants
|
|
9812
9916
|
const _constantNames = [
|
|
@@ -9828,6 +9932,10 @@ const _constantNames = [
|
|
|
9828
9932
|
'MAX_SAFE_INTEGER',
|
|
9829
9933
|
'MAX_SAFE_INTEGER-1',
|
|
9830
9934
|
'MIN_SAFE_INTEGER',
|
|
9935
|
+
"':'",
|
|
9936
|
+
"'.'",
|
|
9937
|
+
"'id'",
|
|
9938
|
+
"'ref'",
|
|
9831
9939
|
];
|
|
9832
9940
|
// Used for dumpState, make sure they are in sync with TypeIds
|
|
9833
9941
|
const _typeIdNames = [
|
|
@@ -9873,6 +9981,9 @@ const _typeIdNames = [
|
|
|
9873
9981
|
'SubscriptionData',
|
|
9874
9982
|
'EffectSubscription',
|
|
9875
9983
|
'SubscriptionPatch',
|
|
9984
|
+
'SubscriptionDataConstTrue',
|
|
9985
|
+
'SubscriptionDataConstFalse',
|
|
9986
|
+
'EffectSubscriptionNoData',
|
|
9876
9987
|
];
|
|
9877
9988
|
|
|
9878
9989
|
function qrlToString(serializationContext, qrl, raw) {
|
|
@@ -9919,17 +10030,25 @@ function qrlToString(serializationContext, qrl, raw) {
|
|
|
9919
10030
|
symbol = String(serializationContext.$addSyncFn$(null, 0, fn));
|
|
9920
10031
|
}
|
|
9921
10032
|
const captures = qrl.getCaptured();
|
|
9922
|
-
let
|
|
10033
|
+
let captureDeltas = null;
|
|
9923
10034
|
if (captures && captures.length > 0) {
|
|
9924
10035
|
// We refer by id so every capture needs to be a root
|
|
9925
|
-
|
|
10036
|
+
let previous = 0;
|
|
10037
|
+
let output = '';
|
|
10038
|
+
for (let i = 0; i < captures.length; i++) {
|
|
10039
|
+
const captureId = serializationContext.$addRoot$(captures[i]);
|
|
10040
|
+
const delta = captureId - previous;
|
|
10041
|
+
previous = captureId;
|
|
10042
|
+
output += (i === 0 ? '' : ' ') + delta;
|
|
10043
|
+
}
|
|
10044
|
+
captureDeltas = output;
|
|
9926
10045
|
}
|
|
9927
10046
|
if (raw) {
|
|
9928
|
-
return [chunk, symbol,
|
|
10047
|
+
return [chunk, symbol, captureDeltas];
|
|
9929
10048
|
}
|
|
9930
10049
|
let qrlStringInline = `${chunk}#${symbol}`;
|
|
9931
|
-
if (
|
|
9932
|
-
qrlStringInline += `#${
|
|
10050
|
+
if (captureDeltas) {
|
|
10051
|
+
qrlStringInline += `#${captureDeltas}`;
|
|
9933
10052
|
}
|
|
9934
10053
|
return qrlStringInline;
|
|
9935
10054
|
}
|
|
@@ -9941,12 +10060,23 @@ function qrlToChunks(serializationContext, qrl) {
|
|
|
9941
10060
|
return prefix;
|
|
9942
10061
|
}
|
|
9943
10062
|
const chunks = [prefix, '#'];
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
10063
|
+
let previousCaptureId = 0;
|
|
10064
|
+
let start = 0;
|
|
10065
|
+
for (let i = 0; i <= captures.length; i++) {
|
|
10066
|
+
if (i === captures.length || captures[i] === ' ') {
|
|
10067
|
+
if (i > start) {
|
|
10068
|
+
const captureId = previousCaptureId + Number(captures.slice(start, i));
|
|
10069
|
+
if (start > 0) {
|
|
10070
|
+
chunks.push(' ');
|
|
10071
|
+
chunks.push({ id: captureId, base: previousCaptureId });
|
|
10072
|
+
}
|
|
10073
|
+
else {
|
|
10074
|
+
chunks.push(captureId);
|
|
10075
|
+
}
|
|
10076
|
+
previousCaptureId = captureId;
|
|
10077
|
+
}
|
|
10078
|
+
start = i + 1;
|
|
9948
10079
|
}
|
|
9949
|
-
chunks.push(Number(captureIds[i]));
|
|
9950
10080
|
}
|
|
9951
10081
|
return chunks;
|
|
9952
10082
|
}
|
|
@@ -9962,10 +10092,14 @@ function createQRLWithBackChannel(chunk, symbol, captures, container) {
|
|
|
9962
10092
|
}
|
|
9963
10093
|
return createQRL(chunk, symbol, null, qrlImporter, captures, container);
|
|
9964
10094
|
}
|
|
9965
|
-
/** Parses "chunk#hash#...
|
|
10095
|
+
/** Parses "chunk#hash#...captureDelta" */
|
|
9966
10096
|
function parseQRL(qrl, container) {
|
|
9967
|
-
const
|
|
9968
|
-
|
|
10097
|
+
const firstHash = qrl.indexOf('#');
|
|
10098
|
+
const secondHash = qrl.indexOf('#', firstHash + 1);
|
|
10099
|
+
const chunk = qrl.slice(0, firstHash);
|
|
10100
|
+
const symbol = secondHash === -1 ? qrl.slice(firstHash + 1) : qrl.slice(firstHash + 1, secondHash);
|
|
10101
|
+
const captures = secondHash !== -1 && secondHash + 1 < qrl.length ? qrl.slice(secondHash + 1) : null;
|
|
10102
|
+
return createQRLWithBackChannel(chunk, symbol, captures, container);
|
|
9969
10103
|
}
|
|
9970
10104
|
const QRL_RUNTIME_CHUNK = 'mock-chunk';
|
|
9971
10105
|
|
|
@@ -10117,7 +10251,37 @@ class Serializer {
|
|
|
10117
10251
|
return key;
|
|
10118
10252
|
}
|
|
10119
10253
|
}
|
|
10120
|
-
return Number(key);
|
|
10254
|
+
return Number(key);
|
|
10255
|
+
}
|
|
10256
|
+
rebaseQrlCaptureDeltas$(baseRootId, captureDeltas) {
|
|
10257
|
+
let previousCaptureId = 0;
|
|
10258
|
+
let previousOutputBase = baseRootId;
|
|
10259
|
+
const deltaList = captureDeltas.split(' ');
|
|
10260
|
+
for (let i = 0; i < deltaList.length; i++) {
|
|
10261
|
+
const captureId = previousCaptureId + Number(deltaList[i]);
|
|
10262
|
+
deltaList[i] = String(captureId - previousOutputBase);
|
|
10263
|
+
previousCaptureId = captureId;
|
|
10264
|
+
previousOutputBase = captureId;
|
|
10265
|
+
}
|
|
10266
|
+
return deltaList.join(' ');
|
|
10267
|
+
}
|
|
10268
|
+
outputShortStringConstant$(value) {
|
|
10269
|
+
switch (value) {
|
|
10270
|
+
case ':':
|
|
10271
|
+
this.output(3 /* TypeIds.Constant */, 18 /* Constants.Colon */);
|
|
10272
|
+
return true;
|
|
10273
|
+
case '.':
|
|
10274
|
+
this.output(3 /* TypeIds.Constant */, 19 /* Constants.Dot */);
|
|
10275
|
+
return true;
|
|
10276
|
+
case 'id':
|
|
10277
|
+
this.output(3 /* TypeIds.Constant */, 20 /* Constants.Id */);
|
|
10278
|
+
return true;
|
|
10279
|
+
case 'ref':
|
|
10280
|
+
this.output(3 /* TypeIds.Constant */, 21 /* Constants.Ref */);
|
|
10281
|
+
return true;
|
|
10282
|
+
default:
|
|
10283
|
+
return false;
|
|
10284
|
+
}
|
|
10121
10285
|
}
|
|
10122
10286
|
outputString(value) {
|
|
10123
10287
|
const s = this.stringNeedsJsonEscape$(value) ? JSON.stringify(value) : QUOTE + value + QUOTE;
|
|
@@ -10136,6 +10300,9 @@ class Serializer {
|
|
|
10136
10300
|
writeRootRefPath(path) {
|
|
10137
10301
|
this.$writer$.writeRootRefPath(path);
|
|
10138
10302
|
}
|
|
10303
|
+
writeRootRefDelta(id, base) {
|
|
10304
|
+
this.$writer$.writeRootRefDelta(id, base);
|
|
10305
|
+
}
|
|
10139
10306
|
outputStringChunks(chunks) {
|
|
10140
10307
|
this.$writer$.write(QUOTE);
|
|
10141
10308
|
for (let i = 0; i < chunks.length; i++) {
|
|
@@ -10146,6 +10313,9 @@ class Serializer {
|
|
|
10146
10313
|
else if (typeof chunk === 'number') {
|
|
10147
10314
|
this.writeRootRef(chunk);
|
|
10148
10315
|
}
|
|
10316
|
+
else if ('base' in chunk) {
|
|
10317
|
+
this.writeRootRefDelta(chunk.id, chunk.base);
|
|
10318
|
+
}
|
|
10149
10319
|
else {
|
|
10150
10320
|
this.writeRootRefPath(chunk.path);
|
|
10151
10321
|
}
|
|
@@ -10275,6 +10445,9 @@ class Serializer {
|
|
|
10275
10445
|
if (value.length === 0) {
|
|
10276
10446
|
this.output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
|
|
10277
10447
|
}
|
|
10448
|
+
else if (this.outputShortStringConstant$(value)) {
|
|
10449
|
+
break;
|
|
10450
|
+
}
|
|
10278
10451
|
else {
|
|
10279
10452
|
// If the string is short, we output directly
|
|
10280
10453
|
// Very short strings add overhead to tracking
|
|
@@ -10314,27 +10487,38 @@ class Serializer {
|
|
|
10314
10487
|
}
|
|
10315
10488
|
else if (isQrl(value)) {
|
|
10316
10489
|
if (this.getSeenRefOrOutput(value, index)) {
|
|
10317
|
-
const [chunk, symbol,
|
|
10490
|
+
const [chunk, symbol, captureDeltasFromZero] = qrlToString(this.$serializationContext$, value, true);
|
|
10318
10491
|
let data;
|
|
10319
10492
|
if (chunk !== '') {
|
|
10320
10493
|
// not a sync QRL, replace all parts with string references
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
this
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10494
|
+
const chunkRootId = this.$serializationContext$.$addRoot$(chunk);
|
|
10495
|
+
const symbolRootId = this.$serializationContext$.$addRoot$(symbol);
|
|
10496
|
+
const captureDeltas = captureDeltasFromZero
|
|
10497
|
+
? this.rebaseQrlCaptureDeltas$(symbolRootId, captureDeltasFromZero)
|
|
10498
|
+
: null;
|
|
10499
|
+
data = [chunkRootId, '#', { id: symbolRootId, base: chunkRootId }];
|
|
10500
|
+
if (captureDeltasFromZero) {
|
|
10501
|
+
let previousRootId = 0;
|
|
10502
|
+
let previousOutputBase = symbolRootId;
|
|
10503
|
+
let start = 0;
|
|
10328
10504
|
data.push('#');
|
|
10329
|
-
for (let i = 0; i
|
|
10330
|
-
if (i
|
|
10331
|
-
|
|
10505
|
+
for (let i = 0; i <= captureDeltasFromZero.length; i++) {
|
|
10506
|
+
if (i === captureDeltasFromZero.length || captureDeltasFromZero[i] === ' ') {
|
|
10507
|
+
if (i > start) {
|
|
10508
|
+
const captureId = previousRootId + Number(captureDeltasFromZero.slice(start, i));
|
|
10509
|
+
if (start > 0) {
|
|
10510
|
+
data.push(' ');
|
|
10511
|
+
}
|
|
10512
|
+
data.push({ id: captureId, base: previousOutputBase });
|
|
10513
|
+
previousRootId = captureId;
|
|
10514
|
+
previousOutputBase = captureId;
|
|
10515
|
+
}
|
|
10516
|
+
start = i + 1;
|
|
10332
10517
|
}
|
|
10333
|
-
data.push(Number(captureIds[i]));
|
|
10334
10518
|
}
|
|
10335
10519
|
}
|
|
10336
10520
|
// Since we map QRLs to strings, we need to keep track of this secondary mapping
|
|
10337
|
-
const qrlKey =
|
|
10521
|
+
const qrlKey = `${chunkRootId}#${symbolRootId - chunkRootId}${captureDeltas ? '#' + captureDeltas : ''}`;
|
|
10338
10522
|
const existing = this.$qrlMap$.get(qrlKey);
|
|
10339
10523
|
if (existing) {
|
|
10340
10524
|
// We encountered the same QRL again, make it a root
|
|
@@ -10402,15 +10586,21 @@ class Serializer {
|
|
|
10402
10586
|
]);
|
|
10403
10587
|
}
|
|
10404
10588
|
else if (value instanceof SubscriptionData) {
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10589
|
+
const { $scopedStyleIdPrefix$, $isConst$ } = value.data;
|
|
10590
|
+
if ($scopedStyleIdPrefix$ === null) {
|
|
10591
|
+
this.output($isConst$ ? 42 /* TypeIds.SubscriptionDataConstTrue */ : 43 /* TypeIds.SubscriptionDataConstFalse */, 0);
|
|
10592
|
+
}
|
|
10593
|
+
else {
|
|
10594
|
+
this.output(39 /* TypeIds.SubscriptionData */, [$scopedStyleIdPrefix$, $isConst$]);
|
|
10595
|
+
}
|
|
10410
10596
|
}
|
|
10411
10597
|
else if (value instanceof EffectSubscription) {
|
|
10412
|
-
|
|
10413
|
-
|
|
10598
|
+
if (value.data === null) {
|
|
10599
|
+
this.output(44 /* TypeIds.EffectSubscriptionNoData */, [value.consumer, value.property]);
|
|
10600
|
+
}
|
|
10601
|
+
else {
|
|
10602
|
+
this.output(40 /* TypeIds.EffectSubscription */, [value.consumer, value.property, value.data]);
|
|
10603
|
+
}
|
|
10414
10604
|
}
|
|
10415
10605
|
else if (value instanceof SubscriptionPatch) {
|
|
10416
10606
|
this.output(41 /* TypeIds.SubscriptionPatch */, [value.rootId, value.subscriptions]);
|
|
@@ -10464,7 +10654,7 @@ class Serializer {
|
|
|
10464
10654
|
}
|
|
10465
10655
|
}
|
|
10466
10656
|
}
|
|
10467
|
-
this.output(5 /* TypeIds.Object */, out.length ? out :
|
|
10657
|
+
this.output(5 /* TypeIds.Object */, out.length ? out : EMPTY_OBJECT_PAYLOAD);
|
|
10468
10658
|
}
|
|
10469
10659
|
}
|
|
10470
10660
|
else if (this.$serializationContext$.$isDomRef$(value)) {
|
|
@@ -10497,16 +10687,17 @@ class Serializer {
|
|
|
10497
10687
|
let v = value.$untrackedValue$;
|
|
10498
10688
|
const shouldAlwaysSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
10499
10689
|
const shouldNeverSerialize = value.$flags$ & 8 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
10500
|
-
const isInvalid = value.$flags$ & 1 /*
|
|
10690
|
+
const isInvalid = value.$flags$ & 1 /* ComputedSignalFlags.INVALID */;
|
|
10501
10691
|
const isSkippable = fastSkipSerialize(value.$untrackedValue$);
|
|
10502
|
-
|
|
10503
|
-
const
|
|
10692
|
+
// async-mode computeds carry the same engine state and must round-trip like AsyncSignals
|
|
10693
|
+
const isAsync = !!(value.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */);
|
|
10694
|
+
const isErrored = isAsync && !!value.$untrackedError$;
|
|
10504
10695
|
const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
|
|
10505
10696
|
const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
|
|
10506
10697
|
// Send the flags but remove the serialization bits and default to 0 when undefined
|
|
10507
10698
|
const asyncFlags = (isAsync && value.$flags$ & -25 /* SerializationSignalFlags.SERIALIZATION_ALL_STRATEGIES */) ||
|
|
10508
10699
|
undefined;
|
|
10509
|
-
if (isInvalid || isSkippable) {
|
|
10700
|
+
if (isInvalid || isSkippable || isErrored) {
|
|
10510
10701
|
v = NEEDS_COMPUTATION;
|
|
10511
10702
|
}
|
|
10512
10703
|
else if (shouldAlwaysSerialize) {
|
|
@@ -10521,10 +10712,7 @@ class Serializer {
|
|
|
10521
10712
|
out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
|
|
10522
10713
|
out.push(asyncFlags || undefined);
|
|
10523
10714
|
}
|
|
10524
|
-
if (v !== NEEDS_COMPUTATION ||
|
|
10525
|
-
expires !== undefined ||
|
|
10526
|
-
concurrency !== undefined ||
|
|
10527
|
-
timeout !== undefined) {
|
|
10715
|
+
if (v !== NEEDS_COMPUTATION || concurrency !== undefined || timeout !== undefined) {
|
|
10528
10716
|
/**
|
|
10529
10717
|
* If value is undefined, we need to keep it in the output. If we don't do that, later
|
|
10530
10718
|
* during resuming, the value will be set to symbol(invalid) with flag invalid, and thats
|
|
@@ -10533,7 +10721,6 @@ class Serializer {
|
|
|
10533
10721
|
out.push(v === undefined ? explicitUndefined : v);
|
|
10534
10722
|
}
|
|
10535
10723
|
if (isAsync) {
|
|
10536
|
-
out.push(expires);
|
|
10537
10724
|
out.push(concurrency);
|
|
10538
10725
|
out.push(timeout);
|
|
10539
10726
|
}
|
|
@@ -10554,30 +10741,6 @@ class Serializer {
|
|
|
10554
10741
|
else if (value instanceof Date) {
|
|
10555
10742
|
this.output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
|
|
10556
10743
|
}
|
|
10557
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
|
|
10558
|
-
this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
|
|
10559
|
-
}
|
|
10560
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
|
|
10561
|
-
this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
|
|
10562
|
-
}
|
|
10563
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
|
|
10564
|
-
this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
|
|
10565
|
-
}
|
|
10566
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
|
|
10567
|
-
this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
|
|
10568
|
-
}
|
|
10569
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
|
|
10570
|
-
this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
|
|
10571
|
-
}
|
|
10572
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
|
|
10573
|
-
this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
|
|
10574
|
-
}
|
|
10575
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
|
|
10576
|
-
this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
|
|
10577
|
-
}
|
|
10578
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
|
|
10579
|
-
this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
|
|
10580
|
-
}
|
|
10581
10744
|
else if (value instanceof RegExp) {
|
|
10582
10745
|
this.output(8 /* TypeIds.Regex */, value.toString());
|
|
10583
10746
|
}
|
|
@@ -10650,7 +10813,7 @@ class Serializer {
|
|
|
10650
10813
|
this.output(37 /* TypeIds.JSXNode */, out);
|
|
10651
10814
|
}
|
|
10652
10815
|
else if (value instanceof Task) {
|
|
10653
|
-
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el
|
|
10816
|
+
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el$];
|
|
10654
10817
|
while (out[out.length - 1] === undefined) {
|
|
10655
10818
|
out.pop();
|
|
10656
10819
|
}
|
|
@@ -10704,6 +10867,30 @@ class Serializer {
|
|
|
10704
10867
|
this.output(2 /* TypeIds.ForwardRef */, this.getForwardRefId(forwardRefId));
|
|
10705
10868
|
}
|
|
10706
10869
|
}
|
|
10870
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
|
|
10871
|
+
this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
|
|
10872
|
+
}
|
|
10873
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
|
|
10874
|
+
this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
|
|
10875
|
+
}
|
|
10876
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
|
|
10877
|
+
this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
|
|
10878
|
+
}
|
|
10879
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
|
|
10880
|
+
this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
|
|
10881
|
+
}
|
|
10882
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
|
|
10883
|
+
this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
|
|
10884
|
+
}
|
|
10885
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
|
|
10886
|
+
this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
|
|
10887
|
+
}
|
|
10888
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
|
|
10889
|
+
this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
|
|
10890
|
+
}
|
|
10891
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
|
|
10892
|
+
this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
|
|
10893
|
+
}
|
|
10707
10894
|
else if (vnode_isVNode(value)) {
|
|
10708
10895
|
this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
|
|
10709
10896
|
}
|
|
@@ -10870,7 +11057,9 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10870
11057
|
if (attrValue == null ||
|
|
10871
11058
|
typeof attrValue === 'string' ||
|
|
10872
11059
|
(typeof attrValue === 'number' && key === ELEMENT_ID) ||
|
|
10873
|
-
(key === ELEMENT_PROPS &&
|
|
11060
|
+
(key === ELEMENT_PROPS &&
|
|
11061
|
+
(isObjectEmpty(attrValue) ||
|
|
11062
|
+
shouldSkipComponentProps(value, attrValue)))) {
|
|
10874
11063
|
continue;
|
|
10875
11064
|
}
|
|
10876
11065
|
callback(attrValue);
|
|
@@ -10879,6 +11068,21 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10879
11068
|
}
|
|
10880
11069
|
};
|
|
10881
11070
|
const isSsrAttrs = (value) => typeof value === 'object' && value !== null && !isObjectEmpty(value);
|
|
11071
|
+
const shouldSkipComponentProps = (attrs, value, isDevMode = isDev) => {
|
|
11072
|
+
if (isDevMode || !Object.prototype.hasOwnProperty.call(attrs, OnRenderProp)) {
|
|
11073
|
+
return false;
|
|
11074
|
+
}
|
|
11075
|
+
const owner = value[_OWNER];
|
|
11076
|
+
return (isObjectEmpty(owner.varProps) &&
|
|
11077
|
+
!hasPropsEffects(value) &&
|
|
11078
|
+
!hasComponentBackRef(attrs[QBackRefs]));
|
|
11079
|
+
};
|
|
11080
|
+
const hasPropsEffects = (propsProxy) => {
|
|
11081
|
+
return !!propsProxy[_PROPS_HANDLER].$effects$?.size;
|
|
11082
|
+
};
|
|
11083
|
+
const hasComponentBackRef = (backRefs) => {
|
|
11084
|
+
return backRefs instanceof Map && backRefs.has(":" /* EffectProperty.COMPONENT */);
|
|
11085
|
+
};
|
|
10882
11086
|
/**
|
|
10883
11087
|
* When serializing the object we need check if it is URL, RegExp, Map, Set, etc. This is time
|
|
10884
11088
|
* consuming. So if we could know that this is a basic object literal we could skip the check, and
|
|
@@ -11377,6 +11581,12 @@ const constantToName = (code) => {
|
|
|
11377
11581
|
* @internal
|
|
11378
11582
|
*/
|
|
11379
11583
|
function preprocessState(data, container, segmentId, startIndex = 0) {
|
|
11584
|
+
const iterator = preprocessStateIterator(data, container, startIndex);
|
|
11585
|
+
while (!iterator.next().done) {
|
|
11586
|
+
// Run synchronously for non-browser and non-container deserialization paths.
|
|
11587
|
+
}
|
|
11588
|
+
}
|
|
11589
|
+
function* preprocessStateIterator(data, container, startIndex = 0) {
|
|
11380
11590
|
const isRootDeepRef = (type, value) => {
|
|
11381
11591
|
return type === 1 /* TypeIds.RootRef */ && typeof value === 'string' && value.indexOf(' ') !== -1;
|
|
11382
11592
|
};
|
|
@@ -11419,11 +11629,39 @@ function preprocessState(data, container, segmentId, startIndex = 0) {
|
|
|
11419
11629
|
else if (isForwardRefsMap(data[i])) {
|
|
11420
11630
|
container.$forwardRefs$ = data[i + 1];
|
|
11421
11631
|
}
|
|
11632
|
+
yield;
|
|
11422
11633
|
}
|
|
11423
11634
|
}
|
|
11424
11635
|
|
|
11425
11636
|
const resolvers = new WeakMap();
|
|
11426
|
-
const
|
|
11637
|
+
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
11638
|
+
const BASE64_REGEXP = /^[A-Za-z0-9+/]*$/;
|
|
11639
|
+
// Validate canonical unpadded base64 before its length controls allocation.
|
|
11640
|
+
const isCanonicalBase64 = (value) => {
|
|
11641
|
+
if (typeof value !== 'string' || !BASE64_REGEXP.test(value)) {
|
|
11642
|
+
return false;
|
|
11643
|
+
}
|
|
11644
|
+
const rest = value.length % 4;
|
|
11645
|
+
if (rest === 0) {
|
|
11646
|
+
return true;
|
|
11647
|
+
}
|
|
11648
|
+
if (rest === 1) {
|
|
11649
|
+
return false;
|
|
11650
|
+
}
|
|
11651
|
+
const lastValue = BASE64_ALPHABET.indexOf(value[value.length - 1]);
|
|
11652
|
+
return (lastValue & (rest === 2 ? 15 : 3)) === 0;
|
|
11653
|
+
};
|
|
11654
|
+
const beginDeserialization = (container) => {
|
|
11655
|
+
const ownsPendingStoreTargets = container.$pendingStoreTargets$ === undefined;
|
|
11656
|
+
container.$pendingStoreTargets$ ??= new Map();
|
|
11657
|
+
return ownsPendingStoreTargets;
|
|
11658
|
+
};
|
|
11659
|
+
const endDeserialization = (container, ownsPendingStoreTargets) => {
|
|
11660
|
+
if (ownsPendingStoreTargets) {
|
|
11661
|
+
container.$pendingStoreTargets$.clear();
|
|
11662
|
+
container.$pendingStoreTargets$ = undefined;
|
|
11663
|
+
}
|
|
11664
|
+
};
|
|
11427
11665
|
const allocate = (container, typeId, value) => {
|
|
11428
11666
|
switch (typeId) {
|
|
11429
11667
|
case 0 /* TypeIds.Plain */:
|
|
@@ -11449,10 +11687,17 @@ const allocate = (container, typeId, value) => {
|
|
|
11449
11687
|
case 9 /* TypeIds.QRL */: {
|
|
11450
11688
|
let qrl;
|
|
11451
11689
|
if (typeof value === 'string') {
|
|
11452
|
-
const
|
|
11453
|
-
const
|
|
11454
|
-
const
|
|
11455
|
-
|
|
11690
|
+
const serializedQrl = value;
|
|
11691
|
+
const firstHash = serializedQrl.indexOf('#');
|
|
11692
|
+
const secondHash = serializedQrl.indexOf('#', firstHash + 1);
|
|
11693
|
+
const chunkRootId = Number(serializedQrl.slice(0, firstHash));
|
|
11694
|
+
const symbolDelta = secondHash === -1
|
|
11695
|
+
? Number(serializedQrl.slice(firstHash + 1))
|
|
11696
|
+
: Number(serializedQrl.slice(firstHash + 1, secondHash));
|
|
11697
|
+
const symbolRootId = chunkRootId + symbolDelta;
|
|
11698
|
+
const chunk = container.$getObjectById$(chunkRootId);
|
|
11699
|
+
const symbol = container.$getObjectById$(symbolRootId);
|
|
11700
|
+
qrl = createQRLWithBackChannel(chunk, symbol, secondHash !== -1 ? serializedQrl : null, container);
|
|
11456
11701
|
}
|
|
11457
11702
|
else {
|
|
11458
11703
|
// Sync qrl
|
|
@@ -11461,7 +11706,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11461
11706
|
return qrl;
|
|
11462
11707
|
}
|
|
11463
11708
|
case 28 /* TypeIds.Task */:
|
|
11464
|
-
return new Task(-1, -1, null, null, null
|
|
11709
|
+
return new Task(-1, -1, null, null, null);
|
|
11465
11710
|
case 6 /* TypeIds.URL */:
|
|
11466
11711
|
return new URL(value);
|
|
11467
11712
|
case 7 /* TypeIds.Date */:
|
|
@@ -11509,7 +11754,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11509
11754
|
const storeValue = allocate(container, t, v);
|
|
11510
11755
|
const store = getOrCreateStore(storeValue, 0 /* StoreFlags.NONE */, container);
|
|
11511
11756
|
if (needsInflation(t)) {
|
|
11512
|
-
pendingStoreTargets
|
|
11757
|
+
container.$pendingStoreTargets$.set(storeValue, { t, v });
|
|
11513
11758
|
}
|
|
11514
11759
|
// We must store the reference so it doesn't get deserialized again in inflate()
|
|
11515
11760
|
data[0] = 0 /* TypeIds.Plain */;
|
|
@@ -11539,12 +11784,16 @@ const allocate = (container, typeId, value) => {
|
|
|
11539
11784
|
// Don't leave unhandled promise rejections
|
|
11540
11785
|
promise.catch(() => { });
|
|
11541
11786
|
return promise;
|
|
11542
|
-
case 27 /* TypeIds.Uint8Array */:
|
|
11787
|
+
case 27 /* TypeIds.Uint8Array */: {
|
|
11788
|
+
if (!isCanonicalBase64(value)) {
|
|
11789
|
+
throw qError(38 /* QError.invalidUint8ArrayPayload */);
|
|
11790
|
+
}
|
|
11543
11791
|
const encodedLength = value.length;
|
|
11544
|
-
const blocks = encodedLength
|
|
11545
|
-
const rest = encodedLength
|
|
11792
|
+
const blocks = Math.floor(encodedLength / 4);
|
|
11793
|
+
const rest = encodedLength % 4;
|
|
11546
11794
|
const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
|
|
11547
11795
|
return new Uint8Array(decodedLength);
|
|
11796
|
+
}
|
|
11548
11797
|
case 38 /* TypeIds.PropsProxy */:
|
|
11549
11798
|
return createPropsProxy(null);
|
|
11550
11799
|
case 10 /* TypeIds.VNode */:
|
|
@@ -11585,7 +11834,12 @@ const allocate = (container, typeId, value) => {
|
|
|
11585
11834
|
}
|
|
11586
11835
|
case 39 /* TypeIds.SubscriptionData */:
|
|
11587
11836
|
return new SubscriptionData({});
|
|
11837
|
+
case 42 /* TypeIds.SubscriptionDataConstTrue */:
|
|
11838
|
+
return new SubscriptionData({ $scopedStyleIdPrefix$: null, $isConst$: true });
|
|
11839
|
+
case 43 /* TypeIds.SubscriptionDataConstFalse */:
|
|
11840
|
+
return new SubscriptionData({ $scopedStyleIdPrefix$: null, $isConst$: false });
|
|
11588
11841
|
case 40 /* TypeIds.EffectSubscription */:
|
|
11842
|
+
case 44 /* TypeIds.EffectSubscriptionNoData */:
|
|
11589
11843
|
return new EffectSubscription(null, null, null, null);
|
|
11590
11844
|
case 41 /* TypeIds.SubscriptionPatch */:
|
|
11591
11845
|
return new SubscriptionPatch();
|
|
@@ -11794,6 +12048,16 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
|
|
|
11794
12048
|
|
|
11795
12049
|
class MaybeAsyncSignal {
|
|
11796
12050
|
}
|
|
12051
|
+
const markPromiseHandled = (ssr, promise, host = null) => {
|
|
12052
|
+
promise.catch((reason) => {
|
|
12053
|
+
try {
|
|
12054
|
+
ssr.handleError(reason, host);
|
|
12055
|
+
}
|
|
12056
|
+
catch {
|
|
12057
|
+
// Original promise remains awaited later.
|
|
12058
|
+
}
|
|
12059
|
+
});
|
|
12060
|
+
};
|
|
11797
12061
|
function setParentOptions(mutable, styleScoped, parentComponentFrame) {
|
|
11798
12062
|
return () => {
|
|
11799
12063
|
mutable.currentStyleScoped = styleScoped;
|
|
@@ -11804,6 +12068,11 @@ function setParentOptions(mutable, styleScoped, parentComponentFrame) {
|
|
|
11804
12068
|
async function _walkJSX(ssr, value, options) {
|
|
11805
12069
|
const stack = [value];
|
|
11806
12070
|
const enqueue = (value) => stack.push(value);
|
|
12071
|
+
const enqueuePromise = (promise) => {
|
|
12072
|
+
markPromiseHandled(ssr, promise);
|
|
12073
|
+
stack.push(promise);
|
|
12074
|
+
stack.push(Promise);
|
|
12075
|
+
};
|
|
11807
12076
|
const drain = async () => {
|
|
11808
12077
|
while (stack.length) {
|
|
11809
12078
|
try {
|
|
@@ -11826,7 +12095,7 @@ async function _walkJSX(ssr, value, options) {
|
|
|
11826
12095
|
}
|
|
11827
12096
|
continue;
|
|
11828
12097
|
}
|
|
11829
|
-
processJSXNode(ssr, enqueue, value, options);
|
|
12098
|
+
processJSXNode(ssr, enqueue, enqueuePromise, value, options);
|
|
11830
12099
|
}
|
|
11831
12100
|
finally {
|
|
11832
12101
|
const pendingFlush = ssr.streamHandler.waitForPendingFlush();
|
|
@@ -11838,7 +12107,7 @@ async function _walkJSX(ssr, value, options) {
|
|
|
11838
12107
|
};
|
|
11839
12108
|
await drain();
|
|
11840
12109
|
}
|
|
11841
|
-
function processJSXNode(ssr, enqueue, value, options) {
|
|
12110
|
+
function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
|
|
11842
12111
|
// console.log('processJSXNode', value);
|
|
11843
12112
|
if (value == null) {
|
|
11844
12113
|
ssr.textNode('');
|
|
@@ -11859,7 +12128,6 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11859
12128
|
}
|
|
11860
12129
|
}
|
|
11861
12130
|
else if (isSignal(value)) {
|
|
11862
|
-
maybeAddPollingAsyncSignalToEagerResume(ssr.serializationCtx, value);
|
|
11863
12131
|
ssr.openFragment(isDev ? { [DEBUG_TYPE]: "S" /* VirtualType.WrappedSignal */ } : EMPTY_OBJ);
|
|
11864
12132
|
const signalNode = ssr.getOrCreateLastNode();
|
|
11865
12133
|
const unwrappedSignal = value instanceof WrappedSignalImpl ? value.$unwrapIfSignal$() : value;
|
|
@@ -11870,8 +12138,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11870
12138
|
else if (isPromise(value)) {
|
|
11871
12139
|
ssr.openFragment(isDev ? { [DEBUG_TYPE]: "A" /* VirtualType.Awaited */ } : EMPTY_OBJ);
|
|
11872
12140
|
enqueue(ssr.closeFragment);
|
|
11873
|
-
|
|
11874
|
-
enqueue(Promise);
|
|
12141
|
+
enqueuePromise(value);
|
|
11875
12142
|
enqueue(() => ssr.streamHandler.flush());
|
|
11876
12143
|
}
|
|
11877
12144
|
else if (isAsyncGenerator(value)) {
|
|
@@ -11942,11 +12209,9 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11942
12209
|
const componentFrame = options.parentComponentFrame;
|
|
11943
12210
|
if (componentFrame) {
|
|
11944
12211
|
const compId = componentFrame.componentNode.id || '';
|
|
11945
|
-
const projectionAttrs = isDev
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
projectionAttrs[QCursorBoundary] = cursorBoundary;
|
|
11949
|
-
}
|
|
12212
|
+
const projectionAttrs = isDev
|
|
12213
|
+
? { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ }
|
|
12214
|
+
: {};
|
|
11950
12215
|
projectionAttrs[QSlotParent] = compId;
|
|
11951
12216
|
ssr.openProjection(projectionAttrs);
|
|
11952
12217
|
const host = componentFrame.componentNode;
|
|
@@ -11994,8 +12259,12 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11994
12259
|
else {
|
|
11995
12260
|
value = generator;
|
|
11996
12261
|
}
|
|
11997
|
-
|
|
11998
|
-
|
|
12262
|
+
if (isPromise(value)) {
|
|
12263
|
+
enqueuePromise(value);
|
|
12264
|
+
}
|
|
12265
|
+
else {
|
|
12266
|
+
enqueue(value);
|
|
12267
|
+
}
|
|
11999
12268
|
}
|
|
12000
12269
|
else if (type === SSRRaw) {
|
|
12001
12270
|
ssr.htmlNode(directGetPropsProxyProp(jsx, 'data'));
|
|
@@ -12019,8 +12288,10 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
12019
12288
|
enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
|
|
12020
12289
|
enqueue(() => ssr.closeComponent());
|
|
12021
12290
|
if (isPromise(jsxOutput)) {
|
|
12291
|
+
markPromiseHandled(ssr, jsxOutput, host);
|
|
12022
12292
|
// Defer reading QScopedStyle until after the promise resolves
|
|
12023
12293
|
enqueue(async () => {
|
|
12294
|
+
await ssr.streamHandler.flush();
|
|
12024
12295
|
const resolvedOutput = await jsxOutput;
|
|
12025
12296
|
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
12026
12297
|
enqueue(resolvedOutput);
|
|
@@ -12042,27 +12313,17 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
12042
12313
|
enqueue(ssr.closeFragment);
|
|
12043
12314
|
const component = ssr.getParentComponentFrame();
|
|
12044
12315
|
const jsxOutput = applyInlineComponent(ssr, component && component.componentNode, type, jsx);
|
|
12045
|
-
|
|
12046
|
-
|
|
12316
|
+
if (isPromise(jsxOutput)) {
|
|
12317
|
+
enqueuePromise(jsxOutput);
|
|
12318
|
+
}
|
|
12319
|
+
else {
|
|
12320
|
+
enqueue(jsxOutput);
|
|
12321
|
+
}
|
|
12047
12322
|
}
|
|
12048
12323
|
}
|
|
12049
12324
|
}
|
|
12050
12325
|
}
|
|
12051
12326
|
}
|
|
12052
|
-
function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
|
|
12053
|
-
// Unwrap if it's a WrappedSignalImpl
|
|
12054
|
-
const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
|
|
12055
|
-
if (unwrappedSignal instanceof AsyncSignalImpl) {
|
|
12056
|
-
const expires = unwrappedSignal.$expires$;
|
|
12057
|
-
// Don't check for $effects$ here - effects are added later during tracking.
|
|
12058
|
-
// The AsyncSignal's polling mechanism will check for effects before scheduling.
|
|
12059
|
-
// Only eager-resume for polling signals, not stale-only ones.
|
|
12060
|
-
if (expires && !(unwrappedSignal.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */)) {
|
|
12061
|
-
serializationCtx.$addRoot$(unwrappedSignal);
|
|
12062
|
-
serializationCtx.$eagerResume$.add(unwrappedSignal);
|
|
12063
|
-
}
|
|
12064
|
-
}
|
|
12065
|
-
}
|
|
12066
12327
|
function appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue) {
|
|
12067
12328
|
if (qwikInspectorAttrValue && (!jsx.constProps || !(qwikInspectorAttr in jsx.constProps))) {
|
|
12068
12329
|
(jsx.constProps ||= {})[qwikInspectorAttr] = qwikInspectorAttrValue;
|
|
@@ -12235,7 +12496,8 @@ function setEvent(serializationCtx, key, rawValue, hasMovedCaptures) {
|
|
|
12235
12496
|
*
|
|
12236
12497
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
12237
12498
|
*/
|
|
12238
|
-
if (!qrl.$symbol$.startsWith('_') &&
|
|
12499
|
+
if (!qrl.$symbol$.startsWith('_') &&
|
|
12500
|
+
(Array.isArray(qrl.$captures$) || (hasMovedCaptures && qrl.$hasMovedCaptures$))) {
|
|
12239
12501
|
qrl = createQRL(null, '_run', _run, null, [qrl]);
|
|
12240
12502
|
}
|
|
12241
12503
|
return qrlToChunks(serializationCtx, qrl);
|
|
@@ -12449,22 +12711,24 @@ const useOnEventsSequentialScope = () => {
|
|
|
12449
12711
|
const _hmr = function (event, element) {
|
|
12450
12712
|
// Deserialize captures from `this` when called via qwikloader/attribute dispatch
|
|
12451
12713
|
const container = getDomContainer(element);
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
12714
|
+
return whenContainerDataReady(container, () => {
|
|
12715
|
+
if (typeof this === 'string') {
|
|
12716
|
+
setCaptures(deserializeCaptureDeltas(container, this));
|
|
12717
|
+
}
|
|
12718
|
+
const devPath = _captures?.[1];
|
|
12719
|
+
const hmrPath = devPath ?? element.getAttribute('data-qwik-inspector');
|
|
12720
|
+
if (!hmrPath || !event.detail.files.some((file) => hmrPath.startsWith(file))) {
|
|
12721
|
+
return;
|
|
12722
|
+
}
|
|
12723
|
+
const host = _captures?.[0];
|
|
12724
|
+
if (!host || host.flags & 32 /* VNodeFlags.Deleted */) {
|
|
12725
|
+
return;
|
|
12726
|
+
}
|
|
12727
|
+
markVNodeDirty(container, host, 4 /* ChoreBits.COMPONENT */);
|
|
12728
|
+
// Mark HMR as handled
|
|
12729
|
+
const doc = element.ownerDocument;
|
|
12730
|
+
doc.__hmrDone = doc.__hmrT;
|
|
12731
|
+
});
|
|
12468
12732
|
};
|
|
12469
12733
|
let hmrQrl;
|
|
12470
12734
|
/**
|
|
@@ -12569,22 +12833,93 @@ const isSafeObjectKV = (key, value) => {
|
|
|
12569
12833
|
(typeof value !== 'function' || !dangerousObjectKeys.has(key)));
|
|
12570
12834
|
};
|
|
12571
12835
|
const inflate = (container, target, typeId, data) => {
|
|
12836
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
12837
|
+
try {
|
|
12838
|
+
const iterator = inflateIterator(container, target, typeId, data);
|
|
12839
|
+
while (!iterator.next().done) {
|
|
12840
|
+
// Run synchronously for lazy deserialization paths.
|
|
12841
|
+
}
|
|
12842
|
+
}
|
|
12843
|
+
finally {
|
|
12844
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12845
|
+
}
|
|
12846
|
+
};
|
|
12847
|
+
function* eagerDeserializeArrayIterator(container, data, output = Array(data.length / 2)) {
|
|
12848
|
+
for (let i = 0; i < data.length; i += 2) {
|
|
12849
|
+
output[i / 2] = yield* deserializeDataIterator(container, data[i], data[i + 1]);
|
|
12850
|
+
yield;
|
|
12851
|
+
}
|
|
12852
|
+
return output;
|
|
12853
|
+
}
|
|
12854
|
+
function* eagerDeserializeStateIterator(container, data, output = Array(data.length / 2)) {
|
|
12855
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
12856
|
+
const length = data.length / 2;
|
|
12857
|
+
const allocated = new Uint8Array(length);
|
|
12858
|
+
const previousGetObjectById = container.$getObjectById$;
|
|
12859
|
+
const allocateRoot = (index) => {
|
|
12860
|
+
if (!allocated[index]) {
|
|
12861
|
+
allocated[index] = 1;
|
|
12862
|
+
const typeIndex = index * 2;
|
|
12863
|
+
const typeId = data[typeIndex];
|
|
12864
|
+
const value = data[typeIndex + 1];
|
|
12865
|
+
output[index] = typeId === 0 /* TypeIds.Plain */ ? value : allocate(container, typeId, value);
|
|
12866
|
+
}
|
|
12867
|
+
return output[index];
|
|
12868
|
+
};
|
|
12869
|
+
container.$getObjectById$ = (id) => allocateRoot(typeof id === 'string' ? parseInt(id, 10) : id);
|
|
12870
|
+
try {
|
|
12871
|
+
for (let i = 0; i < length; i++) {
|
|
12872
|
+
allocateRoot(i);
|
|
12873
|
+
yield;
|
|
12874
|
+
}
|
|
12875
|
+
for (let i = 0; i < length; i++) {
|
|
12876
|
+
const typeIndex = i * 2;
|
|
12877
|
+
const typeId = data[typeIndex];
|
|
12878
|
+
const value = data[typeIndex + 1];
|
|
12879
|
+
const propValue = output[i];
|
|
12880
|
+
data[typeIndex] = 0 /* TypeIds.Plain */;
|
|
12881
|
+
data[typeIndex + 1] = propValue;
|
|
12882
|
+
if (needsInflation(typeId)) {
|
|
12883
|
+
yield* inflateIterator(container, propValue, typeId, value);
|
|
12884
|
+
}
|
|
12885
|
+
yield;
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12888
|
+
finally {
|
|
12889
|
+
container.$getObjectById$ = previousGetObjectById;
|
|
12890
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12891
|
+
}
|
|
12892
|
+
return output;
|
|
12893
|
+
}
|
|
12894
|
+
function* deserializeDataIterator(container, typeId, value) {
|
|
12895
|
+
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12896
|
+
return value;
|
|
12897
|
+
}
|
|
12898
|
+
const propValue = allocate(container, typeId, value);
|
|
12899
|
+
if (needsInflation(typeId)) {
|
|
12900
|
+
yield* inflateIterator(container, propValue, typeId, value);
|
|
12901
|
+
}
|
|
12902
|
+
return propValue;
|
|
12903
|
+
}
|
|
12904
|
+
function* inflateIterator(container, target, typeId, data) {
|
|
12572
12905
|
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12573
12906
|
// Already processed
|
|
12574
12907
|
return;
|
|
12575
12908
|
}
|
|
12909
|
+
if (typeId === 5 /* TypeIds.Object */ && data !== EMPTY_OBJECT_PAYLOAD && !Array.isArray(data)) {
|
|
12910
|
+
throw new Error('Invalid Object payload');
|
|
12911
|
+
}
|
|
12576
12912
|
// Restore the complex data, special case for Array
|
|
12577
12913
|
if (typeId !== 4 /* TypeIds.Array */ && Array.isArray(data)) {
|
|
12578
|
-
data =
|
|
12914
|
+
data = yield* eagerDeserializeArrayIterator(container, data);
|
|
12579
12915
|
}
|
|
12580
12916
|
switch (typeId) {
|
|
12581
12917
|
case 4 /* TypeIds.Array */:
|
|
12582
12918
|
// Arrays are special, we need to fill the array in place
|
|
12583
|
-
|
|
12919
|
+
yield* eagerDeserializeArrayIterator(container, data, target);
|
|
12584
12920
|
break;
|
|
12585
12921
|
case 5 /* TypeIds.Object */:
|
|
12586
|
-
if (data ===
|
|
12587
|
-
// Special case, was an empty object
|
|
12922
|
+
if (data === EMPTY_OBJECT_PAYLOAD) {
|
|
12588
12923
|
break;
|
|
12589
12924
|
}
|
|
12590
12925
|
for (let i = 0; i < data.length; i += 2) {
|
|
@@ -12596,37 +12931,65 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12596
12931
|
target[key] = value;
|
|
12597
12932
|
}
|
|
12598
12933
|
break;
|
|
12599
|
-
case
|
|
12934
|
+
case 25 /* TypeIds.Set */: {
|
|
12935
|
+
const set = target;
|
|
12936
|
+
const d = data;
|
|
12937
|
+
for (let i = 0; i < d.length; i++) {
|
|
12938
|
+
set.add(d[i]);
|
|
12939
|
+
yield;
|
|
12940
|
+
}
|
|
12941
|
+
break;
|
|
12942
|
+
}
|
|
12943
|
+
case 26 /* TypeIds.Map */: {
|
|
12944
|
+
const map = target;
|
|
12945
|
+
const d = data;
|
|
12946
|
+
for (let i = 0; i < d.length; i++) {
|
|
12947
|
+
map.set(d[i++], d[i]);
|
|
12948
|
+
yield;
|
|
12949
|
+
}
|
|
12950
|
+
break;
|
|
12951
|
+
}
|
|
12952
|
+
case 24 /* TypeIds.Promise */: {
|
|
12953
|
+
const promise = target;
|
|
12954
|
+
const [resolved, result] = data;
|
|
12955
|
+
const [resolve, reject] = resolvers.get(promise);
|
|
12956
|
+
if (resolved) {
|
|
12957
|
+
// Native Promises cannot fulfill with another Promise.
|
|
12958
|
+
if (resolvers.has(result)) {
|
|
12959
|
+
throw qError(37 /* QError.invalidPromiseDependency */);
|
|
12960
|
+
}
|
|
12961
|
+
resolve(result);
|
|
12962
|
+
}
|
|
12963
|
+
else {
|
|
12964
|
+
reject(result);
|
|
12965
|
+
}
|
|
12966
|
+
break;
|
|
12967
|
+
}
|
|
12968
|
+
case 23 /* TypeIds.Error */: {
|
|
12969
|
+
const d = data;
|
|
12970
|
+
target.message = d[0];
|
|
12971
|
+
for (let i = 1; i < d.length; i += 2) {
|
|
12972
|
+
const key = d[i];
|
|
12973
|
+
const value = d[i + 1];
|
|
12974
|
+
if (isSafeObjectKV(key, value)) {
|
|
12975
|
+
target[key] = value;
|
|
12976
|
+
}
|
|
12977
|
+
yield;
|
|
12978
|
+
}
|
|
12979
|
+
break;
|
|
12980
|
+
}
|
|
12981
|
+
case 28 /* TypeIds.Task */: {
|
|
12600
12982
|
const task = target;
|
|
12601
12983
|
const v = data;
|
|
12602
12984
|
task.$qrl$ = v[0];
|
|
12603
12985
|
task.$flags$ = v[1];
|
|
12604
12986
|
task.$index$ = v[2];
|
|
12605
12987
|
task.$el$ = v[3];
|
|
12606
|
-
task.$state$ = v[4];
|
|
12607
12988
|
break;
|
|
12989
|
+
}
|
|
12608
12990
|
case 29 /* TypeIds.Component */:
|
|
12609
12991
|
target[SERIALIZABLE_STATE][0] = data[0];
|
|
12610
12992
|
break;
|
|
12611
|
-
case 35 /* TypeIds.Store */: {
|
|
12612
|
-
// Inflate the store target
|
|
12613
|
-
const store = unwrapStore(target);
|
|
12614
|
-
const storeTarget = pendingStoreTargets.get(store);
|
|
12615
|
-
if (storeTarget) {
|
|
12616
|
-
pendingStoreTargets.delete(store);
|
|
12617
|
-
inflate(container, store, storeTarget.t, storeTarget.v);
|
|
12618
|
-
}
|
|
12619
|
-
/**
|
|
12620
|
-
* Note that we don't do anything with the innerstores we added during serialization, because
|
|
12621
|
-
* they are already inflated in the deserialize of the data, above.
|
|
12622
|
-
*/
|
|
12623
|
-
const [, flags, effects] = data;
|
|
12624
|
-
const storeHandler = getStoreHandler(target);
|
|
12625
|
-
storeHandler.$flags$ = flags;
|
|
12626
|
-
storeHandler.$effects$ = effects;
|
|
12627
|
-
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
12628
|
-
break;
|
|
12629
|
-
}
|
|
12630
12993
|
case 30 /* TypeIds.Signal */: {
|
|
12631
12994
|
const signal = target;
|
|
12632
12995
|
const d = data;
|
|
@@ -12642,7 +13005,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12642
13005
|
signal.$args$ = d[1];
|
|
12643
13006
|
signal.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
12644
13007
|
signal.$flags$ = d[2];
|
|
12645
|
-
signal.$flags$ |= 1 /*
|
|
13008
|
+
signal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12646
13009
|
signal.$hostElement$ = d[3];
|
|
12647
13010
|
signal.$effects$ = new Set(d.slice(4));
|
|
12648
13011
|
inflateWrappedSignalValue(signal);
|
|
@@ -12668,7 +13031,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12668
13031
|
asyncSignal.$flags$ = d[5] ?? 0;
|
|
12669
13032
|
if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
12670
13033
|
// If it's client only, it was serialized because it pretended to be loading
|
|
12671
|
-
asyncSignal.$
|
|
13034
|
+
asyncSignal.$untrackedPending$ = true;
|
|
12672
13035
|
}
|
|
12673
13036
|
const hasValue = d.length > 6;
|
|
12674
13037
|
if (hasValue) {
|
|
@@ -12676,19 +13039,13 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12676
13039
|
}
|
|
12677
13040
|
// can happen when never serialize etc
|
|
12678
13041
|
if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
12679
|
-
asyncSignal.$flags$ |= 1 /*
|
|
13042
|
+
asyncSignal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12680
13043
|
}
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
asyncSignal.expires = Math.abs(rawExpires);
|
|
12684
|
-
if (rawExpires < 0) {
|
|
12685
|
-
asyncSignal.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
|
|
12686
|
-
}
|
|
12687
|
-
if (d[8] !== undefined && d[8] !== 1) {
|
|
12688
|
-
asyncSignal.$concurrency$ = (d[8] ?? 1);
|
|
13044
|
+
if (d[7] !== undefined && d[7] !== 1) {
|
|
13045
|
+
asyncSignal.$concurrency$ = (d[7] ?? 1);
|
|
12689
13046
|
asyncSignal.$jobs$ = [];
|
|
12690
13047
|
}
|
|
12691
|
-
asyncSignal.$timeoutMs$ = (d[
|
|
13048
|
+
asyncSignal.$timeoutMs$ = (d[8] ?? 0);
|
|
12692
13049
|
restoreEffectBackRefForEffects(asyncSignal.$effects$, asyncSignal);
|
|
12693
13050
|
restoreEffectBackRefForEffects(asyncSignal.$loadingEffects$, asyncSignal);
|
|
12694
13051
|
restoreEffectBackRefForEffects(asyncSignal.$errorEffects$, asyncSignal);
|
|
@@ -12719,24 +13076,17 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12719
13076
|
if (typeId !== 34 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
12720
13077
|
// If we have a value after SSR, it will always be mean the signal was not invalid
|
|
12721
13078
|
// The serialized signal is always left invalid so it can recreate the custom object
|
|
12722
|
-
computed.$flags$ &= -2 /*
|
|
13079
|
+
computed.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
12723
13080
|
}
|
|
12724
13081
|
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
12725
13082
|
break;
|
|
12726
13083
|
}
|
|
12727
|
-
case 23 /* TypeIds.Error */: {
|
|
12728
|
-
const d = data;
|
|
12729
|
-
target.message = d[0];
|
|
12730
|
-
for (let i = 1; i < d.length; i += 2) {
|
|
12731
|
-
target[d[i]] = d[i + 1];
|
|
12732
|
-
}
|
|
12733
|
-
break;
|
|
12734
|
-
}
|
|
12735
13084
|
case 36 /* TypeIds.FormData */: {
|
|
12736
13085
|
const formData = target;
|
|
12737
13086
|
const d = data;
|
|
12738
13087
|
for (let i = 0; i < d.length; i++) {
|
|
12739
13088
|
formData.append(d[i++], d[i]);
|
|
13089
|
+
yield;
|
|
12740
13090
|
}
|
|
12741
13091
|
break;
|
|
12742
13092
|
}
|
|
@@ -12751,49 +13101,16 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12751
13101
|
jsx.toSort = !!toSort;
|
|
12752
13102
|
break;
|
|
12753
13103
|
}
|
|
12754
|
-
case
|
|
12755
|
-
const set = target;
|
|
12756
|
-
const d = data;
|
|
12757
|
-
for (let i = 0; i < d.length; i++) {
|
|
12758
|
-
set.add(d[i]);
|
|
12759
|
-
}
|
|
12760
|
-
break;
|
|
12761
|
-
}
|
|
12762
|
-
case 26 /* TypeIds.Map */: {
|
|
12763
|
-
const map = target;
|
|
12764
|
-
const d = data;
|
|
12765
|
-
for (let i = 0; i < d.length; i++) {
|
|
12766
|
-
map.set(d[i++], d[i]);
|
|
12767
|
-
}
|
|
12768
|
-
break;
|
|
12769
|
-
}
|
|
12770
|
-
case 24 /* TypeIds.Promise */: {
|
|
12771
|
-
const promise = target;
|
|
12772
|
-
const [resolved, result] = data;
|
|
12773
|
-
const [resolve, reject] = resolvers.get(promise);
|
|
12774
|
-
if (resolved) {
|
|
12775
|
-
resolve(result);
|
|
12776
|
-
}
|
|
12777
|
-
else {
|
|
12778
|
-
reject(result);
|
|
12779
|
-
}
|
|
12780
|
-
break;
|
|
12781
|
-
}
|
|
12782
|
-
case 27 /* TypeIds.Uint8Array */:
|
|
12783
|
-
const bytes = target;
|
|
12784
|
-
const buf = atob(data);
|
|
12785
|
-
let i = 0;
|
|
12786
|
-
for (let j = 0; j < buf.length; j++) {
|
|
12787
|
-
const s = buf[j];
|
|
12788
|
-
bytes[i++] = s.charCodeAt(0);
|
|
12789
|
-
}
|
|
12790
|
-
break;
|
|
12791
|
-
case 38 /* TypeIds.PropsProxy */:
|
|
13104
|
+
case 38 /* TypeIds.PropsProxy */: {
|
|
12792
13105
|
const propsProxy = target;
|
|
12793
13106
|
const d = data;
|
|
12794
13107
|
let owner = d[0];
|
|
12795
13108
|
if (owner === _UNINITIALIZED) {
|
|
12796
|
-
owner = new JSXNodeImpl(Fragment,
|
|
13109
|
+
owner = new JSXNodeImpl(Fragment, null, null, null, 0, null);
|
|
13110
|
+
// Important: var/const props can be eager-deserialization placeholders. (empty objects)
|
|
13111
|
+
// Do not let JSXNodeImpl constructor normalize {} to EMPTY_OBJ/null.
|
|
13112
|
+
owner.varProps = d[1];
|
|
13113
|
+
owner.constProps = d[2];
|
|
12797
13114
|
owner._proxy = propsProxy;
|
|
12798
13115
|
}
|
|
12799
13116
|
propsProxy[_OWNER] = owner;
|
|
@@ -12801,51 +13118,69 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12801
13118
|
propsHandler.$effects$ = d[3];
|
|
12802
13119
|
restoreEffectBackRefForEffectsMap(propsHandler.$effects$, propsProxy);
|
|
12803
13120
|
break;
|
|
13121
|
+
}
|
|
12804
13122
|
case 39 /* TypeIds.SubscriptionData */: {
|
|
12805
13123
|
const effectData = target;
|
|
12806
13124
|
effectData.data.$scopedStyleIdPrefix$ = data[0];
|
|
12807
13125
|
effectData.data.$isConst$ = data[1];
|
|
12808
13126
|
break;
|
|
12809
13127
|
}
|
|
12810
|
-
case
|
|
13128
|
+
case 42 /* TypeIds.SubscriptionDataConstTrue */:
|
|
13129
|
+
case 43 /* TypeIds.SubscriptionDataConstFalse */:
|
|
13130
|
+
break;
|
|
13131
|
+
case 40 /* TypeIds.EffectSubscription */: {
|
|
13132
|
+
const effectSub = target;
|
|
13133
|
+
const d = data;
|
|
13134
|
+
effectSub.consumer = d[0];
|
|
13135
|
+
effectSub.property = d[1];
|
|
13136
|
+
effectSub.data = d[2];
|
|
13137
|
+
restoreEffectBackRefForConsumer(effectSub);
|
|
13138
|
+
break;
|
|
13139
|
+
}
|
|
13140
|
+
case 41 /* TypeIds.SubscriptionPatch */: {
|
|
13141
|
+
const patch = target;
|
|
13142
|
+
const d = data;
|
|
13143
|
+
patch.rootId = d[0];
|
|
13144
|
+
patch.subscriptions = d[1];
|
|
13145
|
+
break;
|
|
13146
|
+
}
|
|
13147
|
+
case 44 /* TypeIds.EffectSubscriptionNoData */: {
|
|
12811
13148
|
const effectSub = target;
|
|
12812
13149
|
const d = data;
|
|
12813
13150
|
effectSub.consumer = d[0];
|
|
12814
13151
|
effectSub.property = d[1];
|
|
12815
|
-
effectSub.data =
|
|
13152
|
+
effectSub.data = null;
|
|
12816
13153
|
restoreEffectBackRefForConsumer(effectSub);
|
|
12817
13154
|
break;
|
|
12818
13155
|
}
|
|
12819
|
-
case
|
|
12820
|
-
const
|
|
12821
|
-
const
|
|
12822
|
-
|
|
12823
|
-
|
|
13156
|
+
case 27 /* TypeIds.Uint8Array */: {
|
|
13157
|
+
const bytes = target;
|
|
13158
|
+
const buf = atob(data);
|
|
13159
|
+
for (let j = 0; j < buf.length; j++) {
|
|
13160
|
+
bytes[j] = buf.charCodeAt(j);
|
|
13161
|
+
if ((j & 31) === 31) {
|
|
13162
|
+
yield;
|
|
13163
|
+
}
|
|
13164
|
+
}
|
|
13165
|
+
break;
|
|
13166
|
+
}
|
|
13167
|
+
case 35 /* TypeIds.Store */: {
|
|
13168
|
+
const store = unwrapStore(target);
|
|
13169
|
+
const storeTarget = container.$pendingStoreTargets$.get(store);
|
|
13170
|
+
if (storeTarget) {
|
|
13171
|
+
container.$pendingStoreTargets$.delete(store);
|
|
13172
|
+
yield* inflateIterator(container, store, storeTarget.t, storeTarget.v);
|
|
13173
|
+
}
|
|
13174
|
+
const [, flags, effects] = data;
|
|
13175
|
+
const storeHandler = getStoreHandler(target);
|
|
13176
|
+
storeHandler.$flags$ = flags;
|
|
13177
|
+
storeHandler.$effects$ = effects;
|
|
13178
|
+
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
12824
13179
|
break;
|
|
12825
13180
|
}
|
|
12826
13181
|
default:
|
|
12827
13182
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
12828
13183
|
}
|
|
12829
|
-
};
|
|
12830
|
-
/**
|
|
12831
|
-
* Restores an array eagerly. If you need it lazily, use `deserializeData(container, TypeIds.Array,
|
|
12832
|
-
* array)` instead
|
|
12833
|
-
*/
|
|
12834
|
-
const _eagerDeserializeArray = (container, data, output = Array(data.length / 2)) => {
|
|
12835
|
-
for (let i = 0; i < data.length; i += 2) {
|
|
12836
|
-
output[i / 2] = deserializeData(container, data[i], data[i + 1]);
|
|
12837
|
-
}
|
|
12838
|
-
return output;
|
|
12839
|
-
};
|
|
12840
|
-
function deserializeData(container, typeId, value) {
|
|
12841
|
-
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12842
|
-
return value;
|
|
12843
|
-
}
|
|
12844
|
-
const propValue = allocate(container, typeId, value);
|
|
12845
|
-
if (needsInflation(typeId)) {
|
|
12846
|
-
inflate(container, propValue, typeId, value);
|
|
12847
|
-
}
|
|
12848
|
-
return propValue;
|
|
12849
13184
|
}
|
|
12850
13185
|
function inflateWrappedSignalValue(signal) {
|
|
12851
13186
|
if (signal.$hostElement$ !== null && vnode_isVNode(signal.$hostElement$)) {
|
|
@@ -12956,15 +13291,21 @@ class DeserializationHandler {
|
|
|
12956
13291
|
return value;
|
|
12957
13292
|
}
|
|
12958
13293
|
const container = this.$container$;
|
|
12959
|
-
const
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
13294
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
13295
|
+
try {
|
|
13296
|
+
const propValue = allocate(container, typeId, value);
|
|
13297
|
+
Reflect.set(target, property, propValue);
|
|
13298
|
+
this.$data$[idx] = 0 /* TypeIds.Plain */;
|
|
13299
|
+
this.$data$[idx + 1] = propValue;
|
|
13300
|
+
/** We stored the reference, so now we can inflate, allowing cycles */
|
|
13301
|
+
if (needsInflation(typeId)) {
|
|
13302
|
+
inflate(container, propValue, typeId, value);
|
|
13303
|
+
}
|
|
13304
|
+
return propValue;
|
|
13305
|
+
}
|
|
13306
|
+
finally {
|
|
13307
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12966
13308
|
}
|
|
12967
|
-
return propValue;
|
|
12968
13309
|
}
|
|
12969
13310
|
has(target, property) {
|
|
12970
13311
|
if (property === SERIALIZER_PROXY_UNWRAP) {
|
|
@@ -12988,6 +13329,54 @@ class DeserializationHandler {
|
|
|
12988
13329
|
}
|
|
12989
13330
|
}
|
|
12990
13331
|
|
|
13332
|
+
const YIELD_INTERVAL = 10;
|
|
13333
|
+
const scheduleYieldingIterator = (state) => {
|
|
13334
|
+
if (!state.$scheduled$) {
|
|
13335
|
+
state.$scheduled$ = true;
|
|
13336
|
+
state.$schedule$();
|
|
13337
|
+
}
|
|
13338
|
+
};
|
|
13339
|
+
const runYieldingIterator = (state, onDone, onError) => {
|
|
13340
|
+
state.$scheduled$ = false;
|
|
13341
|
+
const deadline = performance.now() + YIELD_INTERVAL;
|
|
13342
|
+
let count = 0;
|
|
13343
|
+
try {
|
|
13344
|
+
while (true) {
|
|
13345
|
+
const result = state.$iterator$.next();
|
|
13346
|
+
if (result.done) {
|
|
13347
|
+
onDone(result.value);
|
|
13348
|
+
return;
|
|
13349
|
+
}
|
|
13350
|
+
// Sampling the clock every 32 steps keeps `performance.now()` out of the hottest path.
|
|
13351
|
+
if ((++count & 31) === 0 && performance.now() >= deadline) {
|
|
13352
|
+
scheduleYieldingIterator(state);
|
|
13353
|
+
return;
|
|
13354
|
+
}
|
|
13355
|
+
}
|
|
13356
|
+
}
|
|
13357
|
+
catch (error) {
|
|
13358
|
+
onError(error);
|
|
13359
|
+
}
|
|
13360
|
+
};
|
|
13361
|
+
const createYieldingIteratorState = (iterator, onDone, onError) => {
|
|
13362
|
+
const state = {
|
|
13363
|
+
$iterator$: iterator,
|
|
13364
|
+
$schedule$: undefined,
|
|
13365
|
+
$scheduled$: false,
|
|
13366
|
+
};
|
|
13367
|
+
const schedule = createMacroTask(() => {
|
|
13368
|
+
runYieldingIterator(state, (value) => {
|
|
13369
|
+
schedule.$destroy$?.();
|
|
13370
|
+
onDone(value);
|
|
13371
|
+
}, (error) => {
|
|
13372
|
+
schedule.$destroy$?.();
|
|
13373
|
+
onError(error);
|
|
13374
|
+
});
|
|
13375
|
+
});
|
|
13376
|
+
state.$schedule$ = schedule;
|
|
13377
|
+
return state;
|
|
13378
|
+
};
|
|
13379
|
+
|
|
12991
13380
|
/**
|
|
12992
13381
|
* Serialize data to string using SerializationContext.
|
|
12993
13382
|
*
|
|
@@ -13000,12 +13389,12 @@ async function _serialize(data) {
|
|
|
13000
13389
|
return serializationContext.$writer$.toString();
|
|
13001
13390
|
}
|
|
13002
13391
|
/**
|
|
13003
|
-
* Deserialize data from string
|
|
13392
|
+
* Deserialize data from string.
|
|
13004
13393
|
*
|
|
13005
13394
|
* @param rawStateData - Data to deserialize
|
|
13006
13395
|
* @internal
|
|
13007
13396
|
*/
|
|
13008
|
-
function _deserialize(rawStateData) {
|
|
13397
|
+
async function _deserialize(rawStateData) {
|
|
13009
13398
|
if (rawStateData == null) {
|
|
13010
13399
|
throw new Error('No state data to deserialize');
|
|
13011
13400
|
}
|
|
@@ -13013,9 +13402,18 @@ function _deserialize(rawStateData) {
|
|
|
13013
13402
|
if (!Array.isArray(stateData) || stateData.length < 2 || typeof stateData[0] !== 'number') {
|
|
13014
13403
|
throw new Error('Invalid state data');
|
|
13015
13404
|
}
|
|
13016
|
-
const
|
|
13017
|
-
|
|
13405
|
+
const state = Array(stateData.length / 2);
|
|
13406
|
+
const container = createBaseDeserializeContainer(stateData, () => state);
|
|
13407
|
+
container.$state$ = state;
|
|
13408
|
+
await runDeserializeIterator(eagerDeserializeStateIterator(container, stateData, state));
|
|
13409
|
+
return state[0];
|
|
13018
13410
|
}
|
|
13411
|
+
const runDeserializeIterator = (iterator) => {
|
|
13412
|
+
return new Promise((resolve, reject) => {
|
|
13413
|
+
const state = createYieldingIteratorState(iterator, resolve, reject);
|
|
13414
|
+
scheduleYieldingIterator(state);
|
|
13415
|
+
});
|
|
13416
|
+
};
|
|
13019
13417
|
function getObjectById(id, stateData) {
|
|
13020
13418
|
if (typeof id === 'string') {
|
|
13021
13419
|
id = parseInt(id, 10);
|
|
@@ -13029,8 +13427,14 @@ function getObjectById(id, stateData) {
|
|
|
13029
13427
|
function _createDeserializeContainer(stateData) {
|
|
13030
13428
|
// eslint-disable-next-line prefer-const
|
|
13031
13429
|
let state;
|
|
13430
|
+
const container = createBaseDeserializeContainer(stateData, () => state);
|
|
13431
|
+
state = wrapDeserializerProxy(container, stateData);
|
|
13432
|
+
container.$state$ = state;
|
|
13433
|
+
return container;
|
|
13434
|
+
}
|
|
13435
|
+
function createBaseDeserializeContainer(stateData, getState) {
|
|
13032
13436
|
const container = {
|
|
13033
|
-
$getObjectById$: (id) => getObjectById(id,
|
|
13437
|
+
$getObjectById$: (id) => getObjectById(id, getState()),
|
|
13034
13438
|
$getForwardRef$: (id) => container.$forwardRefs$?.[Number(id)],
|
|
13035
13439
|
getSyncFn: (_) => {
|
|
13036
13440
|
const fn = () => { };
|
|
@@ -13041,8 +13445,6 @@ function _createDeserializeContainer(stateData) {
|
|
|
13041
13445
|
$forwardRefs$: null,
|
|
13042
13446
|
};
|
|
13043
13447
|
preprocessState(stateData, container);
|
|
13044
|
-
state = wrapDeserializerProxy(container, stateData);
|
|
13045
|
-
container.$state$ = state;
|
|
13046
13448
|
return container;
|
|
13047
13449
|
}
|
|
13048
13450
|
|
|
@@ -13425,7 +13827,7 @@ const isRecoverable = (err) => {
|
|
|
13425
13827
|
};
|
|
13426
13828
|
|
|
13427
13829
|
/** @internal */
|
|
13428
|
-
const canRevealRegistration = (registration, isPending = (item) => item.boundary.
|
|
13830
|
+
const canRevealRegistration = (registration, isPending = (item) => item.boundary.untrackedValue > 0) => {
|
|
13429
13831
|
if (registration === null) {
|
|
13430
13832
|
return true;
|
|
13431
13833
|
}
|
|
@@ -13502,15 +13904,9 @@ class OutOfOrderRevealCoordinator {
|
|
|
13502
13904
|
}
|
|
13503
13905
|
/** @internal */
|
|
13504
13906
|
const createOutOfOrderRevealCoordinator = (order, collapsed) => {
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
const container = tryGetInvokeContext()?.$container$;
|
|
13509
|
-
let id = 0;
|
|
13510
|
-
if (container) {
|
|
13511
|
-
id = (outOfOrderRevealIds.get(container) || 0) + 1;
|
|
13512
|
-
outOfOrderRevealIds.set(container, id);
|
|
13513
|
-
}
|
|
13907
|
+
const container = tryGetInvokeContext().$container$;
|
|
13908
|
+
const id = (outOfOrderRevealIds.get(container) || 0) + 1;
|
|
13909
|
+
outOfOrderRevealIds.set(container, id);
|
|
13514
13910
|
return new OutOfOrderRevealCoordinator(id, order, collapsed);
|
|
13515
13911
|
};
|
|
13516
13912
|
const getOutOfOrderRevealOrderCode = (order) => {
|
|
@@ -13534,16 +13930,7 @@ const isOutOfOrderStreaming = () => {
|
|
|
13534
13930
|
return container?.outOfOrderStreaming === true && !isOutOfOrderSegmentContainer(container);
|
|
13535
13931
|
};
|
|
13536
13932
|
/** @internal */
|
|
13537
|
-
const nextOutOfOrderSuspenseId = () =>
|
|
13538
|
-
if (!__EXPERIMENTAL__.suspense) {
|
|
13539
|
-
return 0;
|
|
13540
|
-
}
|
|
13541
|
-
const container = tryGetInvokeContext()?.$container$;
|
|
13542
|
-
if (container?.outOfOrderStreaming !== true) {
|
|
13543
|
-
return 0;
|
|
13544
|
-
}
|
|
13545
|
-
return container?.nextOutOfOrderId?.() ?? 0;
|
|
13546
|
-
};
|
|
13933
|
+
const nextOutOfOrderSuspenseId = () => tryGetInvokeContext().$container$.nextOutOfOrderId();
|
|
13547
13934
|
/** @internal */
|
|
13548
13935
|
const applySubscriptionPatches = (container, patches) => {
|
|
13549
13936
|
if (!__EXPERIMENTAL__.suspense || !patches) {
|
|
@@ -13594,13 +13981,12 @@ const mergeSubscriptionSet = (container, producer, backRef, rootEffects, patchEf
|
|
|
13594
13981
|
};
|
|
13595
13982
|
|
|
13596
13983
|
const processedStatePatchScripts = new WeakMap();
|
|
13597
|
-
|
|
13598
|
-
const processSegmentStateScripts = (container, segmentId) => {
|
|
13984
|
+
function* processSegmentStateScriptsIterator(container, segmentId) {
|
|
13599
13985
|
if (!__EXPERIMENTAL__.suspense) {
|
|
13600
13986
|
return;
|
|
13601
13987
|
}
|
|
13602
13988
|
const stateContainer = container;
|
|
13603
|
-
const qwikStates = stateContainer.element.querySelectorAll(
|
|
13989
|
+
const qwikStates = stateContainer.element.querySelectorAll(`script[type="qwik/state"][q\\:instance="${stateContainer.$instanceHash$}"]${QStatePatchAttrSelector}`);
|
|
13604
13990
|
const processedScripts = getProcessedStatePatchScripts(container);
|
|
13605
13991
|
for (let i = 0; i < qwikStates.length; i++) {
|
|
13606
13992
|
const stateScript = qwikStates[i];
|
|
@@ -13611,9 +13997,10 @@ const processSegmentStateScripts = (container, segmentId) => {
|
|
|
13611
13997
|
continue;
|
|
13612
13998
|
}
|
|
13613
13999
|
processedScripts.add(stateScript);
|
|
13614
|
-
processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14000
|
+
yield* processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14001
|
+
yield;
|
|
13615
14002
|
}
|
|
13616
|
-
}
|
|
14003
|
+
}
|
|
13617
14004
|
const getProcessedStatePatchScripts = (container) => {
|
|
13618
14005
|
let processedScripts = processedStatePatchScripts.get(container);
|
|
13619
14006
|
if (!processedScripts) {
|
|
@@ -13622,20 +14009,18 @@ const getProcessedStatePatchScripts = (container) => {
|
|
|
13622
14009
|
}
|
|
13623
14010
|
return processedScripts;
|
|
13624
14011
|
};
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
const processStatePatch = (container, stateContainer, textContent) => {
|
|
13629
|
-
if (textContent) {
|
|
13630
|
-
const [rootStart, rawStateData, forwardRefs, subscriptionPatchRootId] = JSON.parse(textContent);
|
|
13631
|
-
appendStatePatchRoots(container, stateContainer, rootStart, rawStateData);
|
|
13632
|
-
mergeForwardRefs(stateContainer, forwardRefs || undefined);
|
|
13633
|
-
applySubscriptionPatches(container, subscriptionPatchRootId === undefined
|
|
13634
|
-
? undefined
|
|
13635
|
-
: stateContainer.$getObjectById$(subscriptionPatchRootId));
|
|
14012
|
+
function* processStatePatch(container, stateContainer, textContent) {
|
|
14013
|
+
if (!textContent) {
|
|
14014
|
+
return;
|
|
13636
14015
|
}
|
|
13637
|
-
|
|
13638
|
-
|
|
14016
|
+
const [rootStart, rawStateData, forwardRefs, subscriptionPatchRootId] = JSON.parse(textContent);
|
|
14017
|
+
yield* appendStatePatchRoots(container, stateContainer, rootStart, rawStateData);
|
|
14018
|
+
mergeForwardRefs(stateContainer, forwardRefs || undefined);
|
|
14019
|
+
applySubscriptionPatches(container, subscriptionPatchRootId === undefined
|
|
14020
|
+
? undefined
|
|
14021
|
+
: stateContainer.$getObjectById$(subscriptionPatchRootId));
|
|
14022
|
+
}
|
|
14023
|
+
function* appendStatePatchRoots(container, stateContainer, rootStart, rawStateData) {
|
|
13639
14024
|
const currentRootCount = stateContainer.$rawStateData$.length / 2;
|
|
13640
14025
|
if (rootStart !== currentRootCount) {
|
|
13641
14026
|
if (qDev) {
|
|
@@ -13645,12 +14030,13 @@ const appendStatePatchRoots = (container, stateContainer, rootStart, rawStateDat
|
|
|
13645
14030
|
}
|
|
13646
14031
|
for (let i = 0; i < rawStateData.length; i++) {
|
|
13647
14032
|
stateContainer.$rawStateData$[rootStart * 2 + i] = rawStateData[i];
|
|
14033
|
+
yield;
|
|
13648
14034
|
}
|
|
13649
|
-
|
|
14035
|
+
yield* preprocessStateIterator(stateContainer.$rawStateData$, container, rootStart * 2);
|
|
13650
14036
|
stateContainer.$stateData$ = wrapDeserializerProxy(container, stateContainer.$rawStateData$);
|
|
13651
14037
|
stateContainer.$stateData$.length = stateContainer.$rawStateData$.length / 2;
|
|
13652
14038
|
stateContainer.$rootForwardRefs$ = stateContainer.$forwardRefs$;
|
|
13653
|
-
}
|
|
14039
|
+
}
|
|
13654
14040
|
const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
13655
14041
|
if (!forwardRefs) {
|
|
13656
14042
|
return;
|
|
@@ -13665,24 +14051,172 @@ const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
|
13665
14051
|
stateContainer.$forwardRefs$ = rootForwardRefs;
|
|
13666
14052
|
};
|
|
13667
14053
|
|
|
13668
|
-
|
|
14054
|
+
const Q_SUSPENSE_RESOLVED = 'q:r';
|
|
14055
|
+
const Q_PATCH = 'q:patch';
|
|
14056
|
+
/**
|
|
14057
|
+
* Process the VNodeData script tags and store the VNodeData in the VNodeDataMap.
|
|
14058
|
+
*
|
|
14059
|
+
* The end result of this function is that each DOM element has the associated `VNodeData` attached
|
|
14060
|
+
* to it, to be used later `VNode` materialization. The "attachment" is done through the
|
|
14061
|
+
* `VNodeDataMap`.
|
|
14062
|
+
*
|
|
14063
|
+
* Run this function on startup to process the `<script type="qwik/vnode">` tags. The data in the
|
|
14064
|
+
* tags needs to be parsed and attached to the DOM elements. (We do this through `VNodeDataMap`)
|
|
14065
|
+
* `VNodeDataMap` is then used to lazily materialize the VNodes.
|
|
14066
|
+
*
|
|
14067
|
+
* Only one invocation of this function is needed per document/browser session.
|
|
14068
|
+
*
|
|
14069
|
+
* Below is an example of the kinds of constructs which need to be handled when dealing with
|
|
14070
|
+
* VNodeData deserialization.
|
|
14071
|
+
*
|
|
14072
|
+
* ```
|
|
14073
|
+
* <html q:container="paused">
|
|
14074
|
+
* <body>
|
|
14075
|
+
* <div q:container="paused">
|
|
14076
|
+
* <script type="qwik/vnode">...</script>
|
|
14077
|
+
* </div>
|
|
14078
|
+
* <div q:container="html">...</div>
|
|
14079
|
+
* before
|
|
14080
|
+
* <!--q:container=ABC-->
|
|
14081
|
+
* ...
|
|
14082
|
+
* <!--/q:container-->
|
|
14083
|
+
* after
|
|
14084
|
+
* <!--q:ignore=FOO-->
|
|
14085
|
+
* ...
|
|
14086
|
+
* <!--q:container-island=BAR-->
|
|
14087
|
+
* <div>some interactive island</div>
|
|
14088
|
+
* <!--/q:container-island-->
|
|
14089
|
+
* ...
|
|
14090
|
+
* <!--/q:ignore-->
|
|
14091
|
+
* <textarea q:container="text">...</textarea>
|
|
14092
|
+
* <script type="qwik/vnode">...</script>
|
|
14093
|
+
* </body>
|
|
14094
|
+
* </html>
|
|
14095
|
+
* ```
|
|
14096
|
+
*
|
|
14097
|
+
* Each `qwik/vnode` script assumes that the elements are numbered in depth first order. For this
|
|
14098
|
+
* reason, whenever the `processVNodeData` comes across a `q:container` it must ignore its
|
|
14099
|
+
* children.
|
|
14100
|
+
*
|
|
14101
|
+
* IMPLEMENTATION:
|
|
14102
|
+
*
|
|
14103
|
+
* - Stack to keep track of the current `q:container` being processed.
|
|
14104
|
+
* - Attach all `qwik/vnode` scripts (not the data contain within them) to the `q:container` element.
|
|
14105
|
+
* - Walk the tree and process each `q:container` element.
|
|
14106
|
+
*/
|
|
14107
|
+
function processVNodeData(document, containerElement) {
|
|
14108
|
+
const qDocument = document;
|
|
14109
|
+
// Per-container gate: a walk already populated this container's refs → done.
|
|
14110
|
+
if (containerElement?.qVNodeRefs) {
|
|
14111
|
+
return;
|
|
14112
|
+
}
|
|
14113
|
+
// A document-wide walk is in flight; it will pick up this newly-added container too.
|
|
14114
|
+
if (qDocument.qVNodeDataStarted && !qDocument.qVNodeDataProcessed) {
|
|
14115
|
+
return;
|
|
14116
|
+
}
|
|
14117
|
+
qDocument.qVNodeDataStarted = true;
|
|
14118
|
+
qDocument.qVNodeData ||= new WeakMap();
|
|
14119
|
+
enqueueProcessVNodeDataJob(qDocument, processRootVNodeData(document));
|
|
14120
|
+
}
|
|
13669
14121
|
function processOutOfOrderSegmentVNodeData(document, segmentId, contentNode) {
|
|
13670
14122
|
if (!__EXPERIMENTAL__.suspense || !contentNode) {
|
|
13671
14123
|
return;
|
|
13672
14124
|
}
|
|
13673
14125
|
const qContainerElement = contentNode.closest('[q\\:container]');
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
14126
|
+
if (!qContainerElement) {
|
|
14127
|
+
return;
|
|
14128
|
+
}
|
|
14129
|
+
const script = qContainerElement.querySelector(`script[type="qwik/vnode"][q\\:r="${segmentId}"]:not([q\\:patch])`);
|
|
14130
|
+
const patches = qContainerElement.querySelectorAll(`script[type="qwik/vnode"][q\\:r="${segmentId}"][q\\:patch]`);
|
|
14131
|
+
enqueueProcessVNodeDataJob(document, processOutOfOrderSegmentVNodeDataIterator(document, segmentId, qContainerElement, contentNode, script?.textContent || undefined, patches));
|
|
14132
|
+
}
|
|
14133
|
+
const onVNodeDataReady = (document, callback) => {
|
|
14134
|
+
const qDocument = document;
|
|
14135
|
+
if (qDocument.qVNodeDataReady) {
|
|
14136
|
+
callback();
|
|
14137
|
+
}
|
|
14138
|
+
else {
|
|
14139
|
+
(qDocument.qVNodeDataCallbacks ||= []).push(callback);
|
|
14140
|
+
}
|
|
14141
|
+
};
|
|
14142
|
+
function enqueueProcessVNodeDataJob(qDocument, iterator) {
|
|
14143
|
+
const state = (qDocument.qVNodeDataState ||= {
|
|
14144
|
+
$queue$: [],
|
|
14145
|
+
$active$: null,
|
|
14146
|
+
});
|
|
14147
|
+
qDocument.qProcessVNodeDataPatch ||= (script) => enqueueProcessVNodeDataJob(qDocument, processVNodeDataPatch(qDocument, script));
|
|
14148
|
+
qDocument.qVNodeDataReady = false;
|
|
14149
|
+
state.$queue$.push(iterator);
|
|
14150
|
+
scheduleProcessVNodeData(qDocument, state);
|
|
14151
|
+
}
|
|
14152
|
+
function scheduleProcessVNodeData(qDocument, state) {
|
|
14153
|
+
if (state.$active$) {
|
|
14154
|
+
return;
|
|
14155
|
+
}
|
|
14156
|
+
const iterator = state.$queue$.shift();
|
|
14157
|
+
if (!iterator) {
|
|
14158
|
+
markVNodeDataReady(qDocument);
|
|
14159
|
+
return;
|
|
14160
|
+
}
|
|
14161
|
+
state.$active$ = createYieldingIteratorState(runProcessVNodeData(qDocument, state, iterator), () => {
|
|
14162
|
+
if (qDocument.qVNodeDataState === state) {
|
|
14163
|
+
state.$active$ = null;
|
|
14164
|
+
scheduleProcessVNodeData(qDocument, state);
|
|
14165
|
+
}
|
|
14166
|
+
}, (error) => {
|
|
14167
|
+
state.$active$ = null;
|
|
14168
|
+
logError(error);
|
|
14169
|
+
markVNodeDataReady(qDocument);
|
|
14170
|
+
});
|
|
14171
|
+
scheduleYieldingIterator(state.$active$);
|
|
14172
|
+
}
|
|
14173
|
+
function* runProcessVNodeData(qDocument, state, iterator) {
|
|
14174
|
+
while (qDocument.qVNodeDataState === state) {
|
|
14175
|
+
if (iterator.next().done) {
|
|
14176
|
+
return;
|
|
14177
|
+
}
|
|
14178
|
+
yield;
|
|
13679
14179
|
}
|
|
13680
14180
|
}
|
|
13681
|
-
function
|
|
13682
|
-
|
|
13683
|
-
|
|
14181
|
+
function markVNodeDataReady(document) {
|
|
14182
|
+
if (document.qVNodeDataReady) {
|
|
14183
|
+
return;
|
|
14184
|
+
}
|
|
14185
|
+
document.qVNodeDataReady = true;
|
|
14186
|
+
document.qVNodeDataState = undefined;
|
|
14187
|
+
const callbacks = document.qVNodeDataCallbacks;
|
|
14188
|
+
document.qVNodeDataCallbacks = undefined;
|
|
14189
|
+
if (callbacks) {
|
|
14190
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
14191
|
+
callbacks[i]();
|
|
14192
|
+
}
|
|
14193
|
+
}
|
|
14194
|
+
}
|
|
14195
|
+
function* processRootVNodeData(document) {
|
|
14196
|
+
yield* processVNodeDataImpl(document);
|
|
14197
|
+
const qDocument = document;
|
|
14198
|
+
qDocument.qVNodeDataProcessed = true;
|
|
14199
|
+
// Re-open the gate so a container added after this drain re-runs a walk.
|
|
14200
|
+
qDocument.qVNodeDataStarted = false;
|
|
14201
|
+
}
|
|
14202
|
+
function* processOutOfOrderSegmentVNodeDataIterator(document, segmentId, segmentContainer, segmentContent, segmentVNodeData, patches) {
|
|
14203
|
+
yield* processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData);
|
|
14204
|
+
for (let i = 0; i < patches.length; i++) {
|
|
14205
|
+
yield* processVNodeDataPatch(document, patches[i]);
|
|
14206
|
+
}
|
|
14207
|
+
}
|
|
14208
|
+
function* processVNodeDataPatch(document, script) {
|
|
14209
|
+
const qContainerElement = script?.closest('[q\\:container]');
|
|
14210
|
+
const patchSegment = script?.getAttribute(Q_SUSPENSE_RESOLVED);
|
|
14211
|
+
const contentNode = qContainerElement &&
|
|
14212
|
+
(patchSegment
|
|
14213
|
+
? qContainerElement.querySelector(`[q\\:rp="${patchSegment}"]`)
|
|
14214
|
+
: qContainerElement);
|
|
14215
|
+
if (qContainerElement && contentNode) {
|
|
14216
|
+
yield* processVNodeDataImpl(document, patchSegment || undefined, qContainerElement, contentNode, script.textContent);
|
|
14217
|
+
}
|
|
13684
14218
|
}
|
|
13685
|
-
function processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData) {
|
|
14219
|
+
function* processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData) {
|
|
13686
14220
|
const Q_CONTAINER = 'q:container';
|
|
13687
14221
|
const Q_CONTAINER_END = '/' + Q_CONTAINER;
|
|
13688
14222
|
const Q_PROPS_SEPARATOR = ':';
|
|
@@ -13691,9 +14225,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13691
14225
|
const Q_IGNORE_END = '/' + Q_IGNORE;
|
|
13692
14226
|
const Q_CONTAINER_ISLAND = 'q:container-island';
|
|
13693
14227
|
const Q_CONTAINER_ISLAND_END = '/' + Q_CONTAINER_ISLAND;
|
|
13694
|
-
const Q_SUSPENSE_RESOLVED = 'q:r';
|
|
13695
14228
|
const Q_SUSPENSE_RESULT_PARENT = 'q:rp';
|
|
13696
|
-
const Q_PATCH = 'q:patch';
|
|
13697
14229
|
const qDocument = document;
|
|
13698
14230
|
const vNodeDataMap = (qDocument.qVNodeData ||= new WeakMap());
|
|
13699
14231
|
const prototype = document.body;
|
|
@@ -13711,7 +14243,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13711
14243
|
const hasAttribute = prototype.hasAttribute;
|
|
13712
14244
|
const getNodeType = getter(prototype, 'nodeType');
|
|
13713
14245
|
// Process all of the `qwik/vnode` script tags by attaching them to the corresponding containers.
|
|
13714
|
-
const attachVnodeDataAndRefs = (element)
|
|
14246
|
+
const attachVnodeDataAndRefs = function* (element) {
|
|
13715
14247
|
const scripts = element.querySelectorAll('script[type="qwik/vnode"]');
|
|
13716
14248
|
for (let i = 0; i < scripts.length; i++) {
|
|
13717
14249
|
const script = scripts[i];
|
|
@@ -13719,6 +14251,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13719
14251
|
qContainer.qVNodeRefs ||= new Map();
|
|
13720
14252
|
if (script.hasAttribute(Q_PATCH)) {
|
|
13721
14253
|
qDocument.qProcessVNodeDataPatch?.(script);
|
|
14254
|
+
yield;
|
|
13722
14255
|
continue;
|
|
13723
14256
|
}
|
|
13724
14257
|
const scriptContent = script.textContent;
|
|
@@ -13729,14 +14262,21 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13729
14262
|
else {
|
|
13730
14263
|
qContainer.qVnodeData = scriptContent;
|
|
13731
14264
|
}
|
|
14265
|
+
yield;
|
|
13732
14266
|
}
|
|
13733
14267
|
const shadowRoots = element.querySelectorAll('[q\\:shadowroot]');
|
|
13734
14268
|
for (let i = 0; i < shadowRoots.length; i++) {
|
|
13735
14269
|
const parent = shadowRoots[i];
|
|
13736
14270
|
const shadowRoot = parent.shadowRoot;
|
|
13737
|
-
|
|
14271
|
+
if (shadowRoot) {
|
|
14272
|
+
yield* attachVnodeDataAndRefs(shadowRoot);
|
|
14273
|
+
}
|
|
14274
|
+
yield;
|
|
13738
14275
|
}
|
|
13739
14276
|
};
|
|
14277
|
+
///////////////////////////////
|
|
14278
|
+
// Functions to consume the tree.
|
|
14279
|
+
///////////////////////////////
|
|
13740
14280
|
/**
|
|
13741
14281
|
* Looks up which type of node this is in a monomorphic way which should be faster.
|
|
13742
14282
|
*
|
|
@@ -13792,7 +14332,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13792
14332
|
* @param exitNode The node which represents the last node and we should exit.
|
|
13793
14333
|
* @param qVNodeRefs Place to store the VNodeRefs
|
|
13794
14334
|
*/
|
|
13795
|
-
const walkContainer = (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId)
|
|
14335
|
+
const walkContainer = function* (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId) {
|
|
13796
14336
|
const isSegment = __EXPERIMENTAL__.suspense && segmentId !== undefined;
|
|
13797
14337
|
const vData_length = vData.length;
|
|
13798
14338
|
/// Stores the current element index as the TreeWalker traverses the DOM.
|
|
@@ -13818,6 +14358,9 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13818
14358
|
}
|
|
13819
14359
|
return elementsToSkip;
|
|
13820
14360
|
};
|
|
14361
|
+
if (!node) {
|
|
14362
|
+
return;
|
|
14363
|
+
}
|
|
13821
14364
|
do {
|
|
13822
14365
|
if (node === exitNode) {
|
|
13823
14366
|
return;
|
|
@@ -13831,7 +14374,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13831
14374
|
while (cursor && !(nextNode = nextSibling(cursor))) {
|
|
13832
14375
|
cursor = cursor.parentNode;
|
|
13833
14376
|
}
|
|
13834
|
-
walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
14377
|
+
yield* walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
13835
14378
|
}
|
|
13836
14379
|
else if (nodeType === 16 /* NodeType.COMMENT_IGNORE_START */) {
|
|
13837
14380
|
let islandNode = node;
|
|
@@ -13866,7 +14409,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13866
14409
|
throw new Error(`<!--${node?.nodeValue}--> not closed!`);
|
|
13867
14410
|
}
|
|
13868
14411
|
} while (getFastNodeType(nextNode) !== 8 /* NodeType.COMMENT_SKIP_END */);
|
|
13869
|
-
walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
14412
|
+
yield* walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
13870
14413
|
}
|
|
13871
14414
|
else if (nodeType === 6 /* NodeType.ELEMENT_SHADOW_ROOT_WRAPPER */) {
|
|
13872
14415
|
// If we are in a shadow root, we need to get the shadow root element.
|
|
@@ -13874,7 +14417,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13874
14417
|
const shadowRootContainer = node;
|
|
13875
14418
|
const shadowRoot = shadowRootContainer?.shadowRoot;
|
|
13876
14419
|
if (shadowRoot) {
|
|
13877
|
-
walkContainer(
|
|
14420
|
+
yield* walkContainer(
|
|
13878
14421
|
// we need to create a new walker for the shadow root
|
|
13879
14422
|
document.createTreeWalker(shadowRoot, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, shadowRoot, null, '', null, null);
|
|
13880
14423
|
}
|
|
@@ -13937,51 +14480,42 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13937
14480
|
}
|
|
13938
14481
|
elementIdx++;
|
|
13939
14482
|
if (__EXPERIMENTAL__.suspense && contentBoundaryId !== null) {
|
|
13940
|
-
processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
14483
|
+
yield* processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
13941
14484
|
nextNode = nextSibling(node);
|
|
13942
14485
|
if (nextNode) {
|
|
13943
14486
|
walker.currentNode = nextNode;
|
|
13944
14487
|
}
|
|
13945
14488
|
}
|
|
13946
14489
|
}
|
|
14490
|
+
yield;
|
|
13947
14491
|
} while ((node = nextNode || walker.nextNode()));
|
|
13948
14492
|
};
|
|
13949
|
-
const processVNodeDataScope = (qContainerElement, contentNode, vData, scopeSegmentId)
|
|
14493
|
+
const processVNodeDataScope = function* (qContainerElement, contentNode, vData, scopeSegmentId) {
|
|
13950
14494
|
qContainerElement.qVNodeRefs ||= new Map();
|
|
13951
14495
|
const scopeWalker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13952
14496
|
scopeWalker.currentNode = contentNode;
|
|
13953
|
-
walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
14497
|
+
yield* walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
13954
14498
|
};
|
|
13955
|
-
const processSuspenseContentSegment =
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
processVNodeDataScope(qContainerElement, contentNode, vData, boundaryId);
|
|
13960
|
-
}
|
|
13961
|
-
}
|
|
13962
|
-
: null;
|
|
13963
|
-
qDocument.qProcessVNodeDataPatch = (script) => {
|
|
13964
|
-
const qContainerElement = script?.closest('[q\\:container]');
|
|
13965
|
-
const patchSegment = script?.getAttribute(Q_SUSPENSE_RESOLVED);
|
|
13966
|
-
const contentNode = qContainerElement &&
|
|
13967
|
-
(patchSegment
|
|
13968
|
-
? qContainerElement.querySelector(`[q\\:rp="${patchSegment}"]`)
|
|
13969
|
-
: qContainerElement);
|
|
13970
|
-
if (qContainerElement && contentNode) {
|
|
13971
|
-
processVNodeDataScope(qContainerElement, contentNode, script.textContent, patchSegment || undefined);
|
|
14499
|
+
const processSuspenseContentSegment = function* (qContainerElement, contentNode, boundaryId, vData) {
|
|
14500
|
+
vData ||= qContainerElement?.qSegmentVnodeData?.get(boundaryId);
|
|
14501
|
+
if (qContainerElement && vData) {
|
|
14502
|
+
yield* processVNodeDataScope(qContainerElement, contentNode, vData, boundaryId);
|
|
13972
14503
|
}
|
|
13973
14504
|
};
|
|
13974
|
-
if (
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
processSuspenseContentSegment(segmentContainer, segmentContent, segmentId, segmentVNodeData);
|
|
14505
|
+
if (segmentContainer && segmentContent && segmentVNodeData !== undefined) {
|
|
14506
|
+
segmentContainer.qVNodeRefs ||= new Map();
|
|
14507
|
+
if (__EXPERIMENTAL__.suspense && segmentId !== undefined) {
|
|
14508
|
+
yield* processSuspenseContentSegment(segmentContainer, segmentContent, segmentId, segmentVNodeData);
|
|
14509
|
+
}
|
|
14510
|
+
else {
|
|
14511
|
+
yield* processVNodeDataScope(segmentContainer, segmentContent, segmentVNodeData);
|
|
13978
14512
|
}
|
|
13979
14513
|
return;
|
|
13980
14514
|
}
|
|
13981
|
-
attachVnodeDataAndRefs(document);
|
|
14515
|
+
yield* attachVnodeDataAndRefs(document);
|
|
13982
14516
|
// Walk the tree and process each `q:container` element.
|
|
13983
14517
|
const walker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13984
|
-
walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
14518
|
+
yield* walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
13985
14519
|
}
|
|
13986
14520
|
const isSeparator = (ch) =>
|
|
13987
14521
|
/* `!` */ VNodeDataSeparator.ADVANCE_1 <= ch && ch <= VNodeDataSeparator.ADVANCE_8192; /* `.` */
|
|
@@ -14016,6 +14550,87 @@ const findVDataSectionEnd = (vData, start, end) => {
|
|
|
14016
14550
|
return start;
|
|
14017
14551
|
};
|
|
14018
14552
|
|
|
14553
|
+
function isContainerReady(container) {
|
|
14554
|
+
return container.$containerDataProcessState$ === 3 /* ContainerDataProcessState.ProcessingStateDone */;
|
|
14555
|
+
}
|
|
14556
|
+
function processContainerStateData(container, iterator) {
|
|
14557
|
+
const state = (container.$containerStateDataState$ ||= {
|
|
14558
|
+
$queue$: [],
|
|
14559
|
+
$active$: null,
|
|
14560
|
+
});
|
|
14561
|
+
container.$containerDataProcessState$ = 2 /* ContainerDataProcessState.ProcessingState */;
|
|
14562
|
+
state.$queue$.push(iterator);
|
|
14563
|
+
scheduleProcessContainerStateData(container, state);
|
|
14564
|
+
}
|
|
14565
|
+
const onContainerDataReady = (container, callback) => {
|
|
14566
|
+
const domContainer = container;
|
|
14567
|
+
const checkReady = () => {
|
|
14568
|
+
if (!isContainerReady(domContainer)) {
|
|
14569
|
+
(domContainer.$containerStateReadyCallbacks$ ||= []).push(checkReady);
|
|
14570
|
+
return;
|
|
14571
|
+
}
|
|
14572
|
+
onVNodeDataReady(domContainer.document, () => {
|
|
14573
|
+
if (isContainerReady(domContainer)) {
|
|
14574
|
+
callback();
|
|
14575
|
+
}
|
|
14576
|
+
else {
|
|
14577
|
+
checkReady();
|
|
14578
|
+
}
|
|
14579
|
+
});
|
|
14580
|
+
};
|
|
14581
|
+
checkReady();
|
|
14582
|
+
};
|
|
14583
|
+
const whenContainerDataReady = (container, callback) => {
|
|
14584
|
+
const domContainer = container;
|
|
14585
|
+
if (isContainerReady(domContainer) && domContainer.document.qVNodeDataReady) {
|
|
14586
|
+
return callback();
|
|
14587
|
+
}
|
|
14588
|
+
return new Promise((resolve, reject) => {
|
|
14589
|
+
onContainerDataReady(domContainer, () => {
|
|
14590
|
+
try {
|
|
14591
|
+
resolve(callback());
|
|
14592
|
+
}
|
|
14593
|
+
catch (error) {
|
|
14594
|
+
reject(error);
|
|
14595
|
+
}
|
|
14596
|
+
});
|
|
14597
|
+
});
|
|
14598
|
+
};
|
|
14599
|
+
function scheduleProcessContainerStateData(container, state) {
|
|
14600
|
+
if (state.$active$) {
|
|
14601
|
+
return;
|
|
14602
|
+
}
|
|
14603
|
+
const iterator = state.$queue$.shift();
|
|
14604
|
+
if (!iterator) {
|
|
14605
|
+
markContainerDataReady(container);
|
|
14606
|
+
return;
|
|
14607
|
+
}
|
|
14608
|
+
state.$active$ = createYieldingIteratorState(iterator, () => {
|
|
14609
|
+
state.$active$ = null;
|
|
14610
|
+
scheduleProcessContainerStateData(container, state);
|
|
14611
|
+
}, (error) => {
|
|
14612
|
+
state.$active$ = null;
|
|
14613
|
+
logError(error);
|
|
14614
|
+
markContainerDataReady(container);
|
|
14615
|
+
});
|
|
14616
|
+
scheduleYieldingIterator(state.$active$);
|
|
14617
|
+
}
|
|
14618
|
+
function markContainerDataReady(container) {
|
|
14619
|
+
const state = container.$containerDataProcessState$;
|
|
14620
|
+
if (state !== 2 /* ContainerDataProcessState.ProcessingState */) {
|
|
14621
|
+
return;
|
|
14622
|
+
}
|
|
14623
|
+
container.$containerDataProcessState$ = 3 /* ContainerDataProcessState.ProcessingStateDone */;
|
|
14624
|
+
container.$containerStateDataState$ = undefined;
|
|
14625
|
+
const callbacks = container.$containerStateReadyCallbacks$;
|
|
14626
|
+
container.$containerStateReadyCallbacks$ = undefined;
|
|
14627
|
+
if (callbacks) {
|
|
14628
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
14629
|
+
callbacks[i]();
|
|
14630
|
+
}
|
|
14631
|
+
}
|
|
14632
|
+
}
|
|
14633
|
+
|
|
14019
14634
|
/** @file Public APIs for the SSR */
|
|
14020
14635
|
/** @public */
|
|
14021
14636
|
function getDomContainer(element) {
|
|
@@ -14038,8 +14653,12 @@ function getOutOfOrderStreamingScript(boundaryId, content) {
|
|
|
14038
14653
|
const qContainerElement = content?.closest(QContainerSelector);
|
|
14039
14654
|
const qContainer = qContainerElement?.qContainer;
|
|
14040
14655
|
if (qContainer) {
|
|
14041
|
-
|
|
14042
|
-
|
|
14656
|
+
const document = qContainer.element.ownerDocument;
|
|
14657
|
+
processOutOfOrderSegmentVNodeData(document, segmentId, content);
|
|
14658
|
+
onVNodeDataReady(document, () => {
|
|
14659
|
+
qContainer.element.qContainer === qContainer &&
|
|
14660
|
+
processContainerStateData(qContainer, processSegmentStateScriptsIterator(qContainer, segmentId));
|
|
14661
|
+
});
|
|
14043
14662
|
}
|
|
14044
14663
|
}
|
|
14045
14664
|
/** @internal */
|
|
@@ -14054,6 +14673,9 @@ class DomContainer extends _SharedContainer {
|
|
|
14054
14673
|
$instanceHash$;
|
|
14055
14674
|
$forwardRefs$ = null;
|
|
14056
14675
|
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
14676
|
+
$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14677
|
+
$containerStateReadyCallbacks$ = undefined;
|
|
14678
|
+
$containerStateDataState$ = undefined;
|
|
14057
14679
|
$rawStateData$;
|
|
14058
14680
|
$stateData$;
|
|
14059
14681
|
$rootForwardRefs$ = null;
|
|
@@ -14064,7 +14686,8 @@ class DomContainer extends _SharedContainer {
|
|
|
14064
14686
|
if (!this.qContainer) {
|
|
14065
14687
|
throw qError(25 /* QError.elementWithoutContainer */);
|
|
14066
14688
|
}
|
|
14067
|
-
|
|
14689
|
+
const document = element.ownerDocument;
|
|
14690
|
+
this.document = document;
|
|
14068
14691
|
this.element = element;
|
|
14069
14692
|
this.$buildBase$ = element.getAttribute(QBaseAttr);
|
|
14070
14693
|
this.$instanceHash$ = element.getAttribute(QInstanceAttr);
|
|
@@ -14072,23 +14695,46 @@ class DomContainer extends _SharedContainer {
|
|
|
14072
14695
|
this.rootVNode = vnode_newUnMaterializedElement(this.element);
|
|
14073
14696
|
this.$rawStateData$ = [];
|
|
14074
14697
|
this.$stateData$ = [];
|
|
14075
|
-
const document = this.element.ownerDocument;
|
|
14076
|
-
if (!document.qVNodeDataProcessed) {
|
|
14077
|
-
processVNodeData(document);
|
|
14078
|
-
}
|
|
14079
14698
|
if (__EXPERIMENTAL__.suspense && document.querySelector('template[q\\:r]')) {
|
|
14080
14699
|
document.qProcessOOOS ||= getOutOfOrderStreamingScript;
|
|
14081
14700
|
}
|
|
14082
14701
|
this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
|
|
14083
14702
|
this.$setServerData$();
|
|
14084
|
-
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14085
14703
|
element.qContainer = this;
|
|
14086
14704
|
element.qDestroy = () => this.$destroy$();
|
|
14087
|
-
this.$
|
|
14705
|
+
this.$containerDataProcessState$ = 1 /* ContainerDataProcessState.ProcessingVNode */;
|
|
14706
|
+
processVNodeData(document, element);
|
|
14707
|
+
onVNodeDataReady(document, () => {
|
|
14708
|
+
if (this.$containerDataProcessState$ === 1 /* ContainerDataProcessState.ProcessingVNode */) {
|
|
14709
|
+
processContainerStateData(this, this.$processContainerData$());
|
|
14710
|
+
}
|
|
14711
|
+
});
|
|
14712
|
+
}
|
|
14713
|
+
*$processContainerData$() {
|
|
14714
|
+
const element = this.element;
|
|
14715
|
+
if (element.qContainer !== this) {
|
|
14716
|
+
return;
|
|
14717
|
+
}
|
|
14718
|
+
const rootState = element.querySelector(`script[type="qwik/state"][q\\:instance="${this.$instanceHash$}"]:not(${QStatePatchAttrSelector})`) ||
|
|
14719
|
+
element.querySelector(`script[type="qwik/state"]:not([q\\:instance]):not(${QStatePatchAttrSelector})`);
|
|
14720
|
+
if (rootState) {
|
|
14721
|
+
this.$rawStateData$ = JSON.parse(rootState.textContent);
|
|
14722
|
+
yield* preprocessStateIterator(this.$rawStateData$, this);
|
|
14723
|
+
this.$rootForwardRefs$ = this.$forwardRefs$;
|
|
14724
|
+
const rootCount = this.$rawStateData$.length / 2;
|
|
14725
|
+
const statePrewarm = element.getAttribute(QStatePrewarmAttr);
|
|
14726
|
+
if (statePrewarm !== null && rootCount > 0 && rootCount >= Number(statePrewarm)) {
|
|
14727
|
+
this.$stateData$ = yield* eagerDeserializeStateIterator(this, this.$rawStateData$);
|
|
14728
|
+
}
|
|
14729
|
+
else {
|
|
14730
|
+
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
14731
|
+
}
|
|
14732
|
+
}
|
|
14088
14733
|
if (__EXPERIMENTAL__.suspense) {
|
|
14089
|
-
|
|
14734
|
+
yield* processSegmentStateScriptsIterator(this);
|
|
14090
14735
|
}
|
|
14091
14736
|
this.$hoistStyles$();
|
|
14737
|
+
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14092
14738
|
if (!qTest && element.isConnected) {
|
|
14093
14739
|
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
|
|
14094
14740
|
}
|
|
@@ -14108,9 +14754,15 @@ class DomContainer extends _SharedContainer {
|
|
|
14108
14754
|
}
|
|
14109
14755
|
el.removeAttribute(QContainerAttr);
|
|
14110
14756
|
const document = el.ownerDocument;
|
|
14757
|
+
this.$containerStateDataState$ = undefined;
|
|
14758
|
+
this.$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14111
14759
|
const hasContainers = document.querySelector(QContainerSelector) !== null;
|
|
14112
14760
|
if (!hasContainers) {
|
|
14113
14761
|
document.qVNodeData = undefined;
|
|
14762
|
+
document.qVNodeDataStarted = undefined;
|
|
14763
|
+
document.qVNodeDataReady = undefined;
|
|
14764
|
+
document.qVNodeDataState = undefined;
|
|
14765
|
+
document.qVNodeDataCallbacks = undefined;
|
|
14114
14766
|
document.qVNodeDataProcessed = undefined;
|
|
14115
14767
|
document.qProcessVNodeDataPatch = undefined;
|
|
14116
14768
|
}
|
|
@@ -14120,18 +14772,6 @@ class DomContainer extends _SharedContainer {
|
|
|
14120
14772
|
}
|
|
14121
14773
|
}
|
|
14122
14774
|
}
|
|
14123
|
-
$processRootStateScript$() {
|
|
14124
|
-
const rootState = this.element.querySelector(`${this.$stateScriptSelector$()}:not(${QStatePatchAttrSelector})`);
|
|
14125
|
-
if (rootState) {
|
|
14126
|
-
this.$rawStateData$ = JSON.parse(rootState.textContent);
|
|
14127
|
-
preprocessState(this.$rawStateData$, this);
|
|
14128
|
-
this.$rootForwardRefs$ = this.$forwardRefs$;
|
|
14129
|
-
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
14130
|
-
}
|
|
14131
|
-
}
|
|
14132
|
-
$stateScriptSelector$() {
|
|
14133
|
-
return `script[type="qwik/state"][q\\:instance="${this.$instanceHash$}"]`;
|
|
14134
|
-
}
|
|
14135
14775
|
/**
|
|
14136
14776
|
* The first time we render we need to hoist the styles. (Meaning we need to move all styles from
|
|
14137
14777
|
* component inline to <head>)
|
|
@@ -14229,7 +14869,6 @@ class DomContainer extends _SharedContainer {
|
|
|
14229
14869
|
case OnRenderProp:
|
|
14230
14870
|
case QCtxAttr:
|
|
14231
14871
|
case QBackRefs:
|
|
14232
|
-
case QCursorBoundary:
|
|
14233
14872
|
getObjectById = this.$getObjectById$;
|
|
14234
14873
|
break;
|
|
14235
14874
|
case ELEMENT_SEQ_IDX:
|
|
@@ -14420,8 +15059,7 @@ function invokeApply(context, fn, args) {
|
|
|
14420
15059
|
_context = previousContext;
|
|
14421
15060
|
}
|
|
14422
15061
|
}
|
|
14423
|
-
const newInvokeContextFromDOM = (event, element) => {
|
|
14424
|
-
const domContainer = getDomContainer(element);
|
|
15062
|
+
const newInvokeContextFromDOM = (event, element, domContainer = getDomContainer(element)) => {
|
|
14425
15063
|
const hostElement = vnode_locate(domContainer.rootVNode, element);
|
|
14426
15064
|
const locale = domContainer.$locale$;
|
|
14427
15065
|
locale && setLocale(locale);
|
|
@@ -14563,7 +15201,7 @@ const initLazyRefDev = (lazy) => {
|
|
|
14563
15201
|
};
|
|
14564
15202
|
/** Validate captured scope and register WeakRef tracking on a QRLClass instance. */
|
|
14565
15203
|
const initQrlClassDev = (lazy, captures, qrl) => {
|
|
14566
|
-
if (captures
|
|
15204
|
+
if (Array.isArray(captures)) {
|
|
14567
15205
|
for (let i = 0; i < captures.length; i++) {
|
|
14568
15206
|
const item = captures[i];
|
|
14569
15207
|
verifySerializable(item, 'Captured variable in the closure can not be serialized');
|
|
@@ -14656,6 +15294,7 @@ const setupHmr = (LazyRefClass, setGetLazyRef) => {
|
|
|
14656
15294
|
};
|
|
14657
15295
|
|
|
14658
15296
|
// keep these imports above the rest to prevent circular dep issues
|
|
15297
|
+
let reportedChunkFailures;
|
|
14659
15298
|
let getLazyRef = (chunk, symbol, symbolFn, ref, container) => {
|
|
14660
15299
|
return new LazyRef(chunk, symbol, symbolFn, ref, container);
|
|
14661
15300
|
};
|
|
@@ -14696,7 +15335,25 @@ class LazyRef {
|
|
|
14696
15335
|
this.$ref$ = ref;
|
|
14697
15336
|
if (isPromise(ref)) {
|
|
14698
15337
|
ref.then((r) => (this.$ref$ = r), (err) => {
|
|
14699
|
-
|
|
15338
|
+
const errorMessage = `qrl ${this.$symbol$} failed to load`;
|
|
15339
|
+
if (qTest ? isServerPlatform() : isServer) {
|
|
15340
|
+
console.error(errorMessage, err);
|
|
15341
|
+
}
|
|
15342
|
+
else if (qTest ? !isServerPlatform() : isBrowser$1) {
|
|
15343
|
+
const failureKey = this.$chunk$ === null ? `symbol:${this.$symbol$}` : `chunk:${this.$chunk$}`;
|
|
15344
|
+
const container = this.$container$;
|
|
15345
|
+
let containerFailures = container && reportedChunkFailures?.get(container);
|
|
15346
|
+
if (!containerFailures?.has(failureKey)) {
|
|
15347
|
+
if (container) {
|
|
15348
|
+
if (!containerFailures) {
|
|
15349
|
+
containerFailures = new Set();
|
|
15350
|
+
(reportedChunkFailures ||= new WeakMap()).set(container, containerFailures);
|
|
15351
|
+
}
|
|
15352
|
+
containerFailures.add(failureKey);
|
|
15353
|
+
}
|
|
15354
|
+
console.error(errorMessage, err);
|
|
15355
|
+
}
|
|
15356
|
+
}
|
|
14700
15357
|
// We shouldn't cache rejections, we can try again later
|
|
14701
15358
|
this.$ref$ = null;
|
|
14702
15359
|
});
|
|
@@ -14765,7 +15422,9 @@ class QRLClass {
|
|
|
14765
15422
|
}
|
|
14766
15423
|
// If it is plain value with deserialized or missing captures, resolve it immediately
|
|
14767
15424
|
// Otherwise we keep using the async path so we can wait for qrls to load
|
|
14768
|
-
if ($lazy$.$ref$ != null &&
|
|
15425
|
+
if ($lazy$.$ref$ != null &&
|
|
15426
|
+
(!this.$captures$ || typeof this.$captures$ !== 'string') &&
|
|
15427
|
+
!isPromise($lazy$.$ref$)) {
|
|
14769
15428
|
this.resolved = bindCaptures(this, $lazy$.$ref$);
|
|
14770
15429
|
}
|
|
14771
15430
|
}
|
|
@@ -14787,6 +15446,10 @@ const qrlWithCaptures = function (captures) {
|
|
|
14787
15446
|
const newQrl = new QRLClass(qrl.$lazy$, captures, qrl.$captures$ ? qrl.$container$ : undefined);
|
|
14788
15447
|
return makeQrlFn(newQrl);
|
|
14789
15448
|
};
|
|
15449
|
+
const qrlWithMovedCaptures = function () {
|
|
15450
|
+
this[QRL_STATE].$lazy$.$hasMovedCaptures$ = true;
|
|
15451
|
+
return this;
|
|
15452
|
+
};
|
|
14790
15453
|
const qrlSetRef = function (ref) {
|
|
14791
15454
|
const qrl = getInstance(this);
|
|
14792
15455
|
qrl.$lazy$.$setRef$(ref);
|
|
@@ -14842,6 +15505,11 @@ const QRL_FUNCTION_PROTO = Object.create(Function.prototype, {
|
|
|
14842
15505
|
this[QRL_STATE].$captures$ = value;
|
|
14843
15506
|
},
|
|
14844
15507
|
},
|
|
15508
|
+
$hasMovedCaptures$: {
|
|
15509
|
+
get() {
|
|
15510
|
+
return this[QRL_STATE].$lazy$.$hasMovedCaptures$;
|
|
15511
|
+
},
|
|
15512
|
+
},
|
|
14845
15513
|
$container$: {
|
|
14846
15514
|
get() {
|
|
14847
15515
|
return this[QRL_STATE].$container$;
|
|
@@ -14890,6 +15558,9 @@ const QRL_FUNCTION_PROTO = Object.create(Function.prototype, {
|
|
|
14890
15558
|
w: {
|
|
14891
15559
|
value: qrlWithCaptures,
|
|
14892
15560
|
},
|
|
15561
|
+
m: {
|
|
15562
|
+
value: qrlWithMovedCaptures,
|
|
15563
|
+
},
|
|
14893
15564
|
s: {
|
|
14894
15565
|
value: qrlSetRef,
|
|
14895
15566
|
},
|
|
@@ -14920,31 +15591,50 @@ let _captures = null;
|
|
|
14920
15591
|
const setCaptures = (captures) => {
|
|
14921
15592
|
_captures = captures;
|
|
14922
15593
|
};
|
|
14923
|
-
const
|
|
15594
|
+
const deserializeCaptureDeltas = (container, deltaString, startIndex = 0, previousRootId) => {
|
|
14924
15595
|
const refs = [];
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
15596
|
+
let previous = previousRootId;
|
|
15597
|
+
let start = startIndex;
|
|
15598
|
+
for (let i = startIndex; i <= deltaString.length; i++) {
|
|
15599
|
+
if (i === deltaString.length || deltaString.charCodeAt(i) === 32) {
|
|
15600
|
+
if (i > start) {
|
|
15601
|
+
const delta = Number(deltaString.slice(start, i));
|
|
15602
|
+
previous = previous === undefined ? delta : previous + delta;
|
|
15603
|
+
refs.push(container.$getObjectById$(previous));
|
|
15604
|
+
}
|
|
15605
|
+
start = i + 1;
|
|
15606
|
+
}
|
|
14929
15607
|
}
|
|
14930
15608
|
return refs;
|
|
14931
15609
|
};
|
|
15610
|
+
const deserializeQrlCaptureDeltas = (container, qrlString) => {
|
|
15611
|
+
const firstHash = qrlString.indexOf('#');
|
|
15612
|
+
if (firstHash === -1) {
|
|
15613
|
+
return deserializeCaptureDeltas(container, qrlString);
|
|
15614
|
+
}
|
|
15615
|
+
const secondHash = qrlString.indexOf('#', firstHash + 1);
|
|
15616
|
+
const previousRootId = Number(qrlString.slice(0, firstHash)) + Number(qrlString.slice(firstHash + 1, secondHash));
|
|
15617
|
+
return deserializeCaptureDeltas(container, qrlString, secondHash + 1, previousRootId);
|
|
15618
|
+
};
|
|
14932
15619
|
/** Puts the qrl captures into `_captures`, and returns a Promise that should be awaited if possible */
|
|
14933
15620
|
const ensureQrlCaptures = (qrl) => {
|
|
14934
15621
|
// We read the captures once, synchronously, so no need to keep previous
|
|
14935
|
-
|
|
15622
|
+
const serializedCaptures = qrl.$captures$;
|
|
14936
15623
|
const container = qrl.$container$;
|
|
14937
|
-
if (typeof
|
|
15624
|
+
if (typeof serializedCaptures === 'string') {
|
|
14938
15625
|
if (!container) {
|
|
14939
15626
|
throw qError(13 /* QError.qrlMissingContainer */);
|
|
14940
15627
|
}
|
|
14941
15628
|
const prevLoading = loading;
|
|
14942
|
-
_captures = qrl.$captures$ =
|
|
15629
|
+
_captures = qrl.$captures$ = deserializeQrlCaptureDeltas(container, serializedCaptures);
|
|
14943
15630
|
if (loading !== prevLoading) {
|
|
14944
15631
|
// return the loading promise so callers can await it
|
|
14945
15632
|
return loading;
|
|
14946
15633
|
}
|
|
14947
15634
|
}
|
|
15635
|
+
else {
|
|
15636
|
+
_captures = serializedCaptures || null;
|
|
15637
|
+
}
|
|
14948
15638
|
};
|
|
14949
15639
|
// Wrap functions to provide their lexical scope
|
|
14950
15640
|
const bindCaptures = (qrl, ref) => {
|
|
@@ -15911,7 +16601,13 @@ const useComputedQrl = (qrl, options) => {
|
|
|
15911
16601
|
* recalculated, and if the result changed, all tasks which are tracking the signal will be re-run
|
|
15912
16602
|
* and all components that read the signal will be re-rendered.
|
|
15913
16603
|
*
|
|
15914
|
-
*
|
|
16604
|
+
* Every synchronous signal or store read is tracked automatically. Reads after an `await` are not:
|
|
16605
|
+
* the tracking context is lost, so track them explicitly with the `track()` provided on the context
|
|
16606
|
+
* argument. When the function is async, the returned signal exposes the async API: reading an
|
|
16607
|
+
* unresolved `.value` throws the computation promise, and `.pending` and `.error` expose the
|
|
16608
|
+
* computation state.
|
|
16609
|
+
*
|
|
16610
|
+
* The function must not have any side effects.
|
|
15915
16611
|
*
|
|
15916
16612
|
* @public
|
|
15917
16613
|
*/
|
|
@@ -16009,7 +16705,7 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
16009
16705
|
// In SSR we defer execution until triggered in DOM
|
|
16010
16706
|
flags = 1 /* TaskFlags.VISIBLE_TASK */;
|
|
16011
16707
|
}
|
|
16012
|
-
const task = new Task(flags, i, iCtx.$hostElement$, qrl,
|
|
16708
|
+
const task = new Task(flags, i, iCtx.$hostElement$, qrl, null);
|
|
16013
16709
|
set(task);
|
|
16014
16710
|
useRegisterTaskEvents(task, eagerness);
|
|
16015
16711
|
};
|
|
@@ -16047,11 +16743,11 @@ const getTaskHandlerQrl = (task) => {
|
|
|
16047
16743
|
* Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
|
|
16048
16744
|
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
16049
16745
|
*
|
|
16050
|
-
* @deprecated Use `
|
|
16051
|
-
* available for backward compatibility but it is recommended to migrate to `
|
|
16052
|
-
* code and when updating existing code.
|
|
16746
|
+
* @deprecated Use `useComputed$` instead, which is more powerful and flexible. `useResource$` is
|
|
16747
|
+
* still available for backward compatibility but it is recommended to migrate to `useComputed$`
|
|
16748
|
+
* for new code and when updating existing code.
|
|
16053
16749
|
* @public
|
|
16054
|
-
* @see
|
|
16750
|
+
* @see useComputed$
|
|
16055
16751
|
* @see Resource
|
|
16056
16752
|
* @see ResourceReturn
|
|
16057
16753
|
*/
|
|
@@ -16156,7 +16852,10 @@ const creator = (qrl, options) => {
|
|
|
16156
16852
|
qrl.resolve();
|
|
16157
16853
|
return createAsyncSignal(qrl, options);
|
|
16158
16854
|
};
|
|
16159
|
-
/**
|
|
16855
|
+
/**
|
|
16856
|
+
* @deprecated Use `useComputed$` instead, it has async support now.
|
|
16857
|
+
* @internal
|
|
16858
|
+
*/
|
|
16160
16859
|
const useAsyncQrl = (qrl, options) => {
|
|
16161
16860
|
return useConstant((creator), qrl, options);
|
|
16162
16861
|
};
|
|
@@ -16179,6 +16878,8 @@ const useAsyncQrl = (qrl, options) => {
|
|
|
16179
16878
|
* will subscribe to it and return the last resolved value until the new value is ready. As soon as
|
|
16180
16879
|
* the new value is ready, the subscribers will be updated.
|
|
16181
16880
|
*
|
|
16881
|
+
* @deprecated Use `useComputed$` instead, it has async support now. It auto-tracks synchronous
|
|
16882
|
+
* reads; after the first `await`, use the provided `track()` like before.
|
|
16182
16883
|
* @public
|
|
16183
16884
|
*/
|
|
16184
16885
|
const useAsync$ = implicit$FirstArg(useAsyncQrl);
|
|
@@ -16197,10 +16898,10 @@ const eachCmpTask = async ({ track }) => {
|
|
|
16197
16898
|
const context = tryGetInvokeContext();
|
|
16198
16899
|
const host = context.$hostElement$;
|
|
16199
16900
|
const container = context.$container$;
|
|
16200
|
-
markVNodeDirty(container, host, 256 /* ChoreBits.RECONCILE */);
|
|
16901
|
+
const renderPromise = markVNodeDirty(container, host, 256 /* ChoreBits.RECONCILE */);
|
|
16201
16902
|
const isSsr = qTest ? isServerPlatform() : isServer;
|
|
16202
16903
|
if (isSsr) {
|
|
16203
|
-
await
|
|
16904
|
+
await renderPromise;
|
|
16204
16905
|
}
|
|
16205
16906
|
};
|
|
16206
16907
|
/** @internal */
|
|
@@ -16215,6 +16916,46 @@ const eachCmp = (props) => {
|
|
|
16215
16916
|
const Each = /*#__PURE__*/ componentQrl(
|
|
16216
16917
|
/*#__PURE__*/ inlinedQrl(eachCmp, '_eaC'));
|
|
16217
16918
|
|
|
16919
|
+
const invokeShowFn = (fn, context, arg) => {
|
|
16920
|
+
return isQrl(fn) ? fn.getFn(context)(arg) : fn(arg);
|
|
16921
|
+
};
|
|
16922
|
+
/** @internal */
|
|
16923
|
+
const showCmpTask = ({ track }) => {
|
|
16924
|
+
const props = _captures[0];
|
|
16925
|
+
const context = tryGetInvokeContext();
|
|
16926
|
+
const host = context.$hostElement$;
|
|
16927
|
+
const container = context.$container$;
|
|
16928
|
+
const isSsr = qTest ? isServerPlatform() : isServer;
|
|
16929
|
+
return maybeThen(track(() => invokeShowFn(props.when$, tryGetInvokeContext(), undefined)), (condition) => {
|
|
16930
|
+
const branch = condition ? props.then$ : props.else$;
|
|
16931
|
+
return maybeThen(branch ? invokeShowFn(branch, context, condition) : null, (output) => {
|
|
16932
|
+
const jsx = branch ? [output] : [];
|
|
16933
|
+
if (isSsr) {
|
|
16934
|
+
const ssr = container;
|
|
16935
|
+
return ssr.renderJSX(jsx, {
|
|
16936
|
+
currentStyleScoped: null,
|
|
16937
|
+
parentComponentFrame: ssr.getComponentFrame(0),
|
|
16938
|
+
});
|
|
16939
|
+
}
|
|
16940
|
+
else {
|
|
16941
|
+
setNodeDiffPayload(host, jsx);
|
|
16942
|
+
markVNodeDirty(container, host, 2 /* ChoreBits.NODE_DIFF */);
|
|
16943
|
+
}
|
|
16944
|
+
});
|
|
16945
|
+
});
|
|
16946
|
+
};
|
|
16947
|
+
/** @internal */
|
|
16948
|
+
const showCmp = (props) => {
|
|
16949
|
+
if (!__EXPERIMENTAL__.show) {
|
|
16950
|
+
throw new Error('Show is experimental and must be enabled with `experimental: ["show"]` in the `qwikVite` plugin.');
|
|
16951
|
+
}
|
|
16952
|
+
useTaskQrl(/*#__PURE__*/ inlinedQrl(showCmpTask, '_shT', [props]));
|
|
16953
|
+
return SkipRender;
|
|
16954
|
+
};
|
|
16955
|
+
/** @public @experimental */
|
|
16956
|
+
const Show = /*#__PURE__*/ componentQrl(
|
|
16957
|
+
/*#__PURE__*/ inlinedQrl(showCmp, '_shC'));
|
|
16958
|
+
|
|
16218
16959
|
const RevealContext = /*#__PURE__*/ createContextId('qk-reveal');
|
|
16219
16960
|
const createRevealContext = (props) => {
|
|
16220
16961
|
return {
|
|
@@ -16319,19 +17060,19 @@ const _hf0 = (p0, p1, p2, p3) => ({
|
|
|
16319
17060
|
display: p1.value === 'fallback' &&
|
|
16320
17061
|
p0.fallback != null &&
|
|
16321
17062
|
p0.fallback !== false &&
|
|
16322
|
-
(p2
|
|
17063
|
+
(p2.value || !p3.reveal.collapsed)
|
|
16323
17064
|
? 'contents'
|
|
16324
17065
|
: 'none',
|
|
16325
17066
|
});
|
|
16326
|
-
const _hf0_str = '{display:p1.value==="fallback"&&p0.fallback!=null&&p0.fallback!==false&&(p2
|
|
16327
|
-
const _hf1 = (p0, p1
|
|
16328
|
-
display:
|
|
17067
|
+
const _hf0_str = '{display:p1.value==="fallback"&&p0.fallback!=null&&p0.fallback!==false&&(p2.value||!p3.reveal.collapsed)?"contents":"none"}';
|
|
17068
|
+
const _hf1 = (p0, p1) => ({
|
|
17069
|
+
display: p0.value === 'content' && p1.value ? 'contents' : 'none',
|
|
16329
17070
|
});
|
|
16330
|
-
const _hf1_str = '{display:
|
|
17071
|
+
const _hf1_str = '{display:p0.value==="content"&&p1.value?"contents":"none"}';
|
|
16331
17072
|
/** @internal */
|
|
16332
17073
|
const suspenseTask = ({ track, cleanup }) => {
|
|
16333
17074
|
const cursorBoundary = _captures[0], props = _captures[1], state = _captures[2], revealRegistration = _captures[3];
|
|
16334
|
-
const pendingCount = track(cursorBoundary
|
|
17075
|
+
const pendingCount = track(cursorBoundary);
|
|
16335
17076
|
const isBrowserEnv = qTest ? !isServerPlatform() : isBrowser$1;
|
|
16336
17077
|
if (revealRegistration !== null && isBrowserEnv) {
|
|
16337
17078
|
revealRegistration.reveal.version.value++;
|
|
@@ -16341,7 +17082,7 @@ const suspenseTask = ({ track, cleanup }) => {
|
|
|
16341
17082
|
return;
|
|
16342
17083
|
}
|
|
16343
17084
|
const delayTimer = setTimeout(() => {
|
|
16344
|
-
if (cursorBoundary.
|
|
17085
|
+
if (cursorBoundary.value > 0) {
|
|
16345
17086
|
state.value = 'fallback';
|
|
16346
17087
|
}
|
|
16347
17088
|
}, props.delay ?? 0);
|
|
@@ -16370,19 +17111,17 @@ const suspenseCmp = (props) => {
|
|
|
16370
17111
|
const outOfOrderRevealBoundary = isServerOutOfOrder
|
|
16371
17112
|
? (revealRegistration?.reveal.ooos?.register(revealRegistration) ?? null)
|
|
16372
17113
|
: null;
|
|
16373
|
-
const showOutOfOrderFallback = isServerOutOfOrder &&
|
|
17114
|
+
const showOutOfOrderFallback = isServerOutOfOrder &&
|
|
17115
|
+
untrack(() => props.fallback != null && props.fallback !== false) &&
|
|
17116
|
+
(outOfOrderRevealBoundary === null || outOfOrderRevealBoundary.showFallback);
|
|
16374
17117
|
const outOfOrderBoundaryState = showOutOfOrderFallback && isPositiveDelay(props.delay)
|
|
16375
|
-
? { contentResolved: false, delayTimer: null }
|
|
17118
|
+
? { contentResolved: false, delay: props.delay, delayTimer: null }
|
|
16376
17119
|
: null;
|
|
16377
|
-
const
|
|
16378
|
-
? /*#__PURE__*/ _fnSignal(_hf0, [props, state, canReveal, revealRegistration], _hf0_str)
|
|
16379
|
-
: null;
|
|
16380
|
-
const contentStyle = /*#__PURE__*/ _fnSignal(_hf1, [props, state, canReveal], _hf1_str);
|
|
17120
|
+
const contentStyle = /*#__PURE__*/ _fnSignal(_hf1, [state, canReveal], _hf1_str);
|
|
16381
17121
|
const fallbackHost = (isServerOutOfOrder
|
|
16382
17122
|
? /*#__PURE__*/ _jsxSorted(SSRFallback, {
|
|
16383
17123
|
boundary: outOfOrderBoundaryState,
|
|
16384
|
-
|
|
16385
|
-
fallbackStyle: outOfOrderFallbackStyle,
|
|
17124
|
+
fallbackStyle: _fnSignal(_hf0, [props, state, canReveal, revealRegistration], _hf0_str),
|
|
16386
17125
|
showFallback: showOutOfOrderFallback,
|
|
16387
17126
|
state,
|
|
16388
17127
|
}, null, _wrapProp(props, 'fallback'), 1, null)
|
|
@@ -16418,15 +17157,16 @@ const Suspense = /*#__PURE__*/ componentQrl(
|
|
|
16418
17157
|
const SSRFallback = __EXPERIMENTAL__.suspense
|
|
16419
17158
|
? /*#__PURE__*/ createInternalServerComponent((ssr, jsx, _options, enqueue) => {
|
|
16420
17159
|
const boundaryState = jsx.varProps.boundary;
|
|
16421
|
-
const delay = jsx.varProps.delay;
|
|
16422
17160
|
const fallbackStyle = jsx.varProps.fallbackStyle;
|
|
16423
17161
|
const showFallback = jsx.varProps.showFallback === true;
|
|
16424
17162
|
const state = jsx.varProps.state;
|
|
16425
|
-
if (showFallback
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
17163
|
+
if (showFallback) {
|
|
17164
|
+
if (boundaryState) {
|
|
17165
|
+
enqueue(() => scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state));
|
|
17166
|
+
}
|
|
17167
|
+
else {
|
|
17168
|
+
state.value = 'fallback';
|
|
17169
|
+
}
|
|
16430
17170
|
}
|
|
16431
17171
|
enqueue(
|
|
16432
17172
|
/*#__PURE__*/ _jsxSorted('div', {
|
|
@@ -16436,13 +17176,13 @@ const SSRFallback = __EXPERIMENTAL__.suspense
|
|
|
16436
17176
|
: null;
|
|
16437
17177
|
const SSRDeferredSlot = __EXPERIMENTAL__.suspense
|
|
16438
17178
|
? /*#__PURE__*/ createInternalServerComponent(async (ssr, jsx, options) => {
|
|
16439
|
-
const boundaryId = jsx.varProps.boundaryId
|
|
17179
|
+
const boundaryId = jsx.varProps.boundaryId;
|
|
16440
17180
|
const contentSegment = `${boundaryId}`;
|
|
16441
17181
|
const boundaryState = jsx.varProps.boundary;
|
|
16442
17182
|
const contentStyle = jsx.varProps.contentStyle;
|
|
16443
17183
|
const revealBoundary = jsx.varProps.reveal;
|
|
16444
17184
|
const content = ssr.segment(contentSegment, createClaimedDeferredSlot(ssr, jsx, options), options);
|
|
16445
|
-
|
|
17185
|
+
ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
|
|
16446
17186
|
ssr.emitOutOfOrderExecutorIfNeeded();
|
|
16447
17187
|
ssr.queueOutOfOrderSegment(content.then((rendered) => emitRenderedOutOfOrderSegment(ssr, boundaryId, contentSegment, rendered, contentStyle, revealBoundary, boundaryState)));
|
|
16448
17188
|
})
|
|
@@ -16461,29 +17201,27 @@ function createClaimedDeferredSlot(ssr, jsx, options) {
|
|
|
16461
17201
|
return /*#__PURE__*/ _jsxSorted(Slot, jsx.varProps, jsx.constProps, slotChildren, jsx.flags, jsx.key);
|
|
16462
17202
|
}
|
|
16463
17203
|
async function emitRenderedOutOfOrderSegment(ssr, boundaryId, segmentId, rendered, contentStyle, revealBoundary, boundaryState) {
|
|
16464
|
-
|
|
17204
|
+
if (boundaryState) {
|
|
17205
|
+
boundaryState.contentResolved = true;
|
|
17206
|
+
if (boundaryState.delayTimer) {
|
|
17207
|
+
clearTimeout(boundaryState.delayTimer);
|
|
17208
|
+
boundaryState.delayTimer = null;
|
|
17209
|
+
}
|
|
17210
|
+
}
|
|
16465
17211
|
revealBoundary?.resolve();
|
|
16466
17212
|
await ssr.$runQueuedRender$(async () => {
|
|
16467
17213
|
ssr.addRoot(contentStyle);
|
|
16468
17214
|
const result = await rendered.container.$finalizeOutOfOrderSegment$(segmentId, rendered);
|
|
16469
|
-
|
|
17215
|
+
ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
|
|
17216
|
+
ssr.write(result.html);
|
|
17217
|
+
ssr.write('</template>');
|
|
16470
17218
|
ssr.emitOutOfOrderSegmentScripts(result.scripts);
|
|
16471
17219
|
ssr.emitInlineScript(`qO(${boundaryId})`);
|
|
16472
17220
|
// qO() is the browser-visible handoff for this segment, so flush it immediately.
|
|
16473
17221
|
await ssr.streamHandler.flush();
|
|
16474
17222
|
});
|
|
16475
17223
|
}
|
|
16476
|
-
function
|
|
16477
|
-
if (!boundaryState) {
|
|
16478
|
-
return;
|
|
16479
|
-
}
|
|
16480
|
-
boundaryState.contentResolved = true;
|
|
16481
|
-
if (boundaryState.delayTimer) {
|
|
16482
|
-
clearTimeout(boundaryState.delayTimer);
|
|
16483
|
-
boundaryState.delayTimer = null;
|
|
16484
|
-
}
|
|
16485
|
-
}
|
|
16486
|
-
function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state, delay) {
|
|
17224
|
+
function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state) {
|
|
16487
17225
|
boundaryState.delayTimer = setTimeout(() => {
|
|
16488
17226
|
boundaryState.delayTimer = null;
|
|
16489
17227
|
void ssr.$runQueuedRender$(async () => {
|
|
@@ -16494,24 +17232,11 @@ function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state, delay) {
|
|
|
16494
17232
|
ssr.emitBackpatchDataAndExecutorIfNeeded();
|
|
16495
17233
|
await ssr.streamHandler.flush();
|
|
16496
17234
|
});
|
|
16497
|
-
}, delay);
|
|
17235
|
+
}, boundaryState.delay);
|
|
16498
17236
|
}
|
|
16499
17237
|
function isPositiveDelay(delay) {
|
|
16500
17238
|
return typeof delay === 'number' && Number.isFinite(delay) && delay > 0;
|
|
16501
17239
|
}
|
|
16502
|
-
function shouldRenderFallback(fallback, revealBoundary) {
|
|
16503
|
-
return (fallback != null &&
|
|
16504
|
-
fallback !== false &&
|
|
16505
|
-
(revealBoundary === null || revealBoundary.showFallback));
|
|
16506
|
-
}
|
|
16507
|
-
function writeOutOfOrderPlaceholder(ssr, boundaryId) {
|
|
16508
|
-
ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
|
|
16509
|
-
}
|
|
16510
|
-
function writeOutOfOrderResolvedTemplate(ssr, boundaryId, html, revealBoundary) {
|
|
16511
|
-
ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
|
|
16512
|
-
ssr.write(html);
|
|
16513
|
-
ssr.write('</template>');
|
|
16514
|
-
}
|
|
16515
17240
|
|
|
16516
17241
|
// keep this import from core/build so the cjs build works
|
|
16517
17242
|
/**
|
|
@@ -16608,5 +17333,5 @@ if (import.meta.hot) {
|
|
|
16608
17333
|
});
|
|
16609
17334
|
}
|
|
16610
17335
|
|
|
16611
|
-
export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, ELEMENT_SEQ as _ELEMENT_SEQ, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, Task as _Task, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, createStore as _createStore, delay as _delay, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, getSubscriber as _getSubscriber, _getVarProps, _hasStoreEffects, _hmr, _injectAsyncSignalValue, invoke as _invoke, 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, newInvokeContext as _newInvokeContext, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, retryOnPromise as _retryOnPromise, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, 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, getClientManifest, 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 };
|
|
17336
|
+
export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, Show, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, ELEMENT_SEQ as _ELEMENT_SEQ, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, Task as _Task, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, createStore as _createStore, delay as _delay, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, getSubscriber as _getSubscriber, _getVarProps, _hasStoreEffects, _hmr, _injectAsyncSignalValue, invoke as _invoke, 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, _markSignalAsExternallyOwned, newInvokeContext as _newInvokeContext, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, retryOnPromise as _retryOnPromise, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, showCmp as _shC, showCmpTask as _shT, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, 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, getClientManifest, 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 };
|
|
16612
17337
|
//# sourceMappingURL=core.mjs.map
|