@qwik.dev/core 2.0.0-beta.36 → 2.0.0-beta.38
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 +2 -2
- package/dist/core-internal.d.ts +526 -345
- package/dist/core.min.mjs +9 -8
- package/dist/core.mjs +1784 -925
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +4294 -3600
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.d.ts +11 -3
- package/dist/optimizer.mjs +1574 -1459
- package/dist/preloader.mjs +1 -1
- package/dist/qwikloader.debug.js +23 -21
- package/dist/qwikloader.js +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.mjs +63 -27
- package/dist/server.prod.mjs +424 -378
- 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/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/testing/index.d.ts +40 -30
- package/dist/testing/index.mjs +1451 -719
- 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 +4 -4
- 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.38-dev+0339f17
|
|
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) {
|
|
@@ -428,6 +431,7 @@ const QBaseAttr = 'q:base';
|
|
|
428
431
|
const QLocaleAttr = 'q:locale';
|
|
429
432
|
const QManifestHashAttr = 'q:manifest-hash';
|
|
430
433
|
const QInstanceAttr = 'q:instance';
|
|
434
|
+
const QStatePrewarmAttr = 'q:prewarm';
|
|
431
435
|
const QContainerIsland = 'q:container-island';
|
|
432
436
|
const QContainerIslandEnd = '/' + QContainerIsland;
|
|
433
437
|
const QIgnore = 'q:ignore';
|
|
@@ -465,6 +469,7 @@ const QDefaultSlot = '';
|
|
|
465
469
|
const ELEMENT_ID = 'q:id';
|
|
466
470
|
const ELEMENT_KEY = 'q:key';
|
|
467
471
|
const ELEMENT_PROPS = 'q:props';
|
|
472
|
+
/** @internal */
|
|
468
473
|
const ELEMENT_SEQ = 'q:seq';
|
|
469
474
|
const ELEMENT_SEQ_IDX = 'q:seqIdx';
|
|
470
475
|
const ITERATION_ITEM_SINGLE = 'q:p'; // Single iteration parameter (not an array)
|
|
@@ -504,6 +509,12 @@ const maybeThen = (valueOrPromise, thenFn) => {
|
|
|
504
509
|
? valueOrPromise.then(thenFn)
|
|
505
510
|
: thenFn(valueOrPromise);
|
|
506
511
|
};
|
|
512
|
+
/** @internal */
|
|
513
|
+
const delay = (timeout) => {
|
|
514
|
+
return new Promise((resolve) => {
|
|
515
|
+
setTimeout(resolve, timeout);
|
|
516
|
+
});
|
|
517
|
+
};
|
|
507
518
|
const checkError = (e) => {
|
|
508
519
|
if (isServer && e instanceof ReferenceError && e.message.includes('window')) {
|
|
509
520
|
e.message = 'It seems like you forgot to add "if (isBrowser) {...}" here:' + e.message;
|
|
@@ -515,6 +526,8 @@ const justThrow = (e) => {
|
|
|
515
526
|
/**
|
|
516
527
|
* Retries a function that throws a promise. If you pass `onError`, you're responsible for handling
|
|
517
528
|
* errors.
|
|
529
|
+
*
|
|
530
|
+
* @internal
|
|
518
531
|
*/
|
|
519
532
|
function retryOnPromise(fn, onError = justThrow) {
|
|
520
533
|
let ok = false;
|
|
@@ -833,8 +846,21 @@ const createMacroTask = (fn) => {
|
|
|
833
846
|
let macroTask;
|
|
834
847
|
if (typeof MessageChannel !== 'undefined') {
|
|
835
848
|
const channel = new MessageChannel();
|
|
849
|
+
let active = true;
|
|
836
850
|
channel.port1.onmessage = () => fn();
|
|
837
|
-
macroTask = () =>
|
|
851
|
+
macroTask = () => {
|
|
852
|
+
if (active) {
|
|
853
|
+
channel.port2.postMessage(null);
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
macroTask.$destroy$ = () => {
|
|
857
|
+
if (active) {
|
|
858
|
+
active = false;
|
|
859
|
+
channel.port1.onmessage = null;
|
|
860
|
+
channel.port1.close();
|
|
861
|
+
channel.port2.close();
|
|
862
|
+
}
|
|
863
|
+
};
|
|
838
864
|
}
|
|
839
865
|
else {
|
|
840
866
|
macroTask = () => setTimeout(fn);
|
|
@@ -954,7 +980,7 @@ const rel = isBrowser && doc.createElement('link').relList?.supports?.('modulepr
|
|
|
954
980
|
? 'modulePreload'
|
|
955
981
|
: 'preload';
|
|
956
982
|
const isJSRegex = /\.[mc]?js$/;
|
|
957
|
-
const yieldInterval =
|
|
983
|
+
const yieldInterval = 10;
|
|
958
984
|
|
|
959
985
|
const BundleImportState_None = 0;
|
|
960
986
|
const BundleImportState_Preload = 2;
|
|
@@ -1210,6 +1236,8 @@ const writeStringRootRef = (writer, id) => writer.write(String(id));
|
|
|
1210
1236
|
/** @internal */
|
|
1211
1237
|
const writeStringRootRefPath = (writer, path) => writer.write(stringifyRootRefPath(path));
|
|
1212
1238
|
/** @internal */
|
|
1239
|
+
const writeStringRootRefDelta = (writer, id, base) => writer.write(String(id - base));
|
|
1240
|
+
/** @internal */
|
|
1213
1241
|
const createStringStreamWriter = (write) => ({
|
|
1214
1242
|
write,
|
|
1215
1243
|
writeRootRef(id) {
|
|
@@ -1218,6 +1246,9 @@ const createStringStreamWriter = (write) => ({
|
|
|
1218
1246
|
writeRootRefPath(path) {
|
|
1219
1247
|
return writeStringRootRefPath(this, path);
|
|
1220
1248
|
},
|
|
1249
|
+
writeRootRefDelta(id, base) {
|
|
1250
|
+
return writeStringRootRefDelta(this, id, base);
|
|
1251
|
+
},
|
|
1221
1252
|
});
|
|
1222
1253
|
|
|
1223
1254
|
// Pre-allocated common strings to reduce allocation overhead
|
|
@@ -1233,7 +1264,7 @@ const COMMA = ',';
|
|
|
1233
1264
|
*
|
|
1234
1265
|
* @public
|
|
1235
1266
|
*/
|
|
1236
|
-
const version = "2.0.0-beta.
|
|
1267
|
+
const version = "2.0.0-beta.38-dev+0339f17";
|
|
1237
1268
|
|
|
1238
1269
|
const isNode = (value) => {
|
|
1239
1270
|
return value && typeof value.nodeType === 'number';
|
|
@@ -1689,9 +1720,12 @@ function setCursorPosition(container, cursorData, position) {
|
|
|
1689
1720
|
}
|
|
1690
1721
|
}
|
|
1691
1722
|
function mergeCursors(container, newCursorData, oldCursor) {
|
|
1723
|
+
const oldCursorData = getCursorData(oldCursor);
|
|
1724
|
+
if (!oldCursorData || oldCursorData === newCursorData) {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1692
1727
|
// delete from global cursors queue
|
|
1693
1728
|
removeCursorFromQueue(oldCursor, container);
|
|
1694
|
-
const oldCursorData = getCursorData(oldCursor);
|
|
1695
1729
|
mergeCursorData(newCursorData, oldCursorData);
|
|
1696
1730
|
}
|
|
1697
1731
|
function mergeCursorData(newCursorData, oldCursorData) {
|
|
@@ -1769,6 +1803,234 @@ function setCursorData(vNode, cursorData) {
|
|
|
1769
1803
|
cursorDatas.set(vNode, cursorData);
|
|
1770
1804
|
}
|
|
1771
1805
|
|
|
1806
|
+
/** @internal */
|
|
1807
|
+
const _CONST_PROPS = Symbol('CONST');
|
|
1808
|
+
/** @internal */
|
|
1809
|
+
const _VAR_PROPS = Symbol('VAR');
|
|
1810
|
+
/** @internal */
|
|
1811
|
+
const _OWNER = Symbol('OWNER');
|
|
1812
|
+
/** @internal */
|
|
1813
|
+
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
1814
|
+
/** @internal @deprecated v1 compat */
|
|
1815
|
+
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
1816
|
+
/** @internal */
|
|
1817
|
+
const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
1818
|
+
|
|
1819
|
+
/** @internal */
|
|
1820
|
+
const EMPTY_ARRAY = [];
|
|
1821
|
+
/** @internal */
|
|
1822
|
+
const EMPTY_OBJ = {};
|
|
1823
|
+
Object.freeze(EMPTY_ARRAY);
|
|
1824
|
+
Object.freeze(EMPTY_OBJ);
|
|
1825
|
+
|
|
1826
|
+
function createPropsProxy(owner) {
|
|
1827
|
+
// TODO don't make a proxy but populate getters? benchmark
|
|
1828
|
+
return new Proxy({}, new PropsProxyHandler(owner));
|
|
1829
|
+
}
|
|
1830
|
+
class PropsProxyHandler {
|
|
1831
|
+
owner;
|
|
1832
|
+
$effects$ = undefined;
|
|
1833
|
+
$container$ = null;
|
|
1834
|
+
constructor(owner) {
|
|
1835
|
+
this.owner = owner;
|
|
1836
|
+
}
|
|
1837
|
+
get(_, prop) {
|
|
1838
|
+
// escape hatch to get the separated props from a component
|
|
1839
|
+
if (prop === _CONST_PROPS) {
|
|
1840
|
+
return this.owner.constProps;
|
|
1841
|
+
}
|
|
1842
|
+
else if (prop === _VAR_PROPS) {
|
|
1843
|
+
return this.owner.varProps;
|
|
1844
|
+
}
|
|
1845
|
+
else if (prop === _OWNER) {
|
|
1846
|
+
return this.owner;
|
|
1847
|
+
}
|
|
1848
|
+
else if (prop === _PROPS_HANDLER) {
|
|
1849
|
+
return this;
|
|
1850
|
+
}
|
|
1851
|
+
let value;
|
|
1852
|
+
if (prop === 'children') {
|
|
1853
|
+
value = this.owner.children;
|
|
1854
|
+
}
|
|
1855
|
+
else {
|
|
1856
|
+
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
1857
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1858
|
+
if (attr) {
|
|
1859
|
+
prop = attr;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
value = directGetPropsProxyProp(this.owner, prop);
|
|
1863
|
+
if (prop in this.owner.varProps) {
|
|
1864
|
+
addPropsProxyEffect(this, prop);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
// a proxied value that the optimizer made
|
|
1868
|
+
return value instanceof WrappedSignalImpl ? value.value : value;
|
|
1869
|
+
}
|
|
1870
|
+
set(_, prop, value) {
|
|
1871
|
+
if (prop === _OWNER) {
|
|
1872
|
+
// used for deserialization
|
|
1873
|
+
this.owner = value;
|
|
1874
|
+
}
|
|
1875
|
+
else if (prop === 'children') {
|
|
1876
|
+
this.owner.children = value;
|
|
1877
|
+
}
|
|
1878
|
+
else if (prop === _CONST_PROPS) {
|
|
1879
|
+
this.owner.constProps = value;
|
|
1880
|
+
}
|
|
1881
|
+
else if (prop === _VAR_PROPS) {
|
|
1882
|
+
this.owner.varProps = value;
|
|
1883
|
+
}
|
|
1884
|
+
else {
|
|
1885
|
+
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
1886
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1887
|
+
if (attr) {
|
|
1888
|
+
prop = attr;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
1892
|
+
// delete the prop from the const props first
|
|
1893
|
+
delete this.owner.constProps[prop];
|
|
1894
|
+
}
|
|
1895
|
+
if (this.owner.varProps === EMPTY_OBJ) {
|
|
1896
|
+
this.owner.varProps = {};
|
|
1897
|
+
}
|
|
1898
|
+
else if (!(prop in this.owner.varProps)) {
|
|
1899
|
+
this.owner.toSort = true;
|
|
1900
|
+
}
|
|
1901
|
+
if (this.owner.varProps[prop] !== value) {
|
|
1902
|
+
this.owner.varProps[prop] = value;
|
|
1903
|
+
triggerPropsProxyEffect(this, prop);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
return true;
|
|
1907
|
+
}
|
|
1908
|
+
deleteProperty(_, prop) {
|
|
1909
|
+
let didDelete = delete this.owner.varProps[prop];
|
|
1910
|
+
if (didDelete) {
|
|
1911
|
+
triggerPropsProxyEffect(this, prop);
|
|
1912
|
+
}
|
|
1913
|
+
if (this.owner.constProps) {
|
|
1914
|
+
didDelete = delete this.owner.constProps[prop] || didDelete;
|
|
1915
|
+
}
|
|
1916
|
+
if (this.owner.children != null && prop === 'children') {
|
|
1917
|
+
this.owner.children = null;
|
|
1918
|
+
didDelete = true;
|
|
1919
|
+
}
|
|
1920
|
+
return didDelete;
|
|
1921
|
+
}
|
|
1922
|
+
has(_, prop) {
|
|
1923
|
+
if (prop === 'children') {
|
|
1924
|
+
return this.owner.children != null;
|
|
1925
|
+
}
|
|
1926
|
+
else if (prop === _CONST_PROPS || prop === _VAR_PROPS) {
|
|
1927
|
+
return true;
|
|
1928
|
+
}
|
|
1929
|
+
const inVarProps = prop in this.owner.varProps;
|
|
1930
|
+
if (typeof prop === 'string') {
|
|
1931
|
+
if (inVarProps) {
|
|
1932
|
+
addPropsProxyEffect(this, prop);
|
|
1933
|
+
}
|
|
1934
|
+
if (typeof this.owner.type === 'string') {
|
|
1935
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1936
|
+
if (attr) {
|
|
1937
|
+
prop = attr;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
1942
|
+
}
|
|
1943
|
+
getOwnPropertyDescriptor(_, p) {
|
|
1944
|
+
const value = p === 'children'
|
|
1945
|
+
? this.owner.children
|
|
1946
|
+
: this.owner.constProps && p in this.owner.constProps
|
|
1947
|
+
? this.owner.constProps[p]
|
|
1948
|
+
: this.owner.varProps[p];
|
|
1949
|
+
return {
|
|
1950
|
+
configurable: true,
|
|
1951
|
+
enumerable: true,
|
|
1952
|
+
value: value,
|
|
1953
|
+
};
|
|
1954
|
+
}
|
|
1955
|
+
ownKeys() {
|
|
1956
|
+
const out = Object.keys(this.owner.varProps);
|
|
1957
|
+
if (this.owner.children != null) {
|
|
1958
|
+
out.push('children');
|
|
1959
|
+
}
|
|
1960
|
+
if (this.owner.constProps) {
|
|
1961
|
+
for (const key in this.owner.constProps) {
|
|
1962
|
+
if (out.indexOf(key) === -1) {
|
|
1963
|
+
out.push(key);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
return out;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
const addPropsProxyEffect = (propsProxy, prop) => {
|
|
1971
|
+
// Lazily grab the container from the invoke context
|
|
1972
|
+
const ctx = tryGetInvokeContext();
|
|
1973
|
+
if (ctx) {
|
|
1974
|
+
if (propsProxy.$container$ === null) {
|
|
1975
|
+
if (ctx.$container$) {
|
|
1976
|
+
propsProxy.$container$ = ctx.$container$;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
else {
|
|
1980
|
+
isDev &&
|
|
1981
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
1985
|
+
if (effectSubscriber) {
|
|
1986
|
+
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
1990
|
+
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
1991
|
+
if (effects) {
|
|
1992
|
+
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
1993
|
+
}
|
|
1994
|
+
return !!effects;
|
|
1995
|
+
};
|
|
1996
|
+
function getEffects$1(effects, prop) {
|
|
1997
|
+
// TODO: Handle STORE_ALL_PROPS
|
|
1998
|
+
return effects?.get(prop);
|
|
1999
|
+
}
|
|
2000
|
+
/**
|
|
2001
|
+
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
2002
|
+
* Use this function to get the props directly from a const or var props.
|
|
2003
|
+
*
|
|
2004
|
+
* This does not convert jsx event names.
|
|
2005
|
+
*/
|
|
2006
|
+
const directGetPropsProxyProp = (jsx, prop) => {
|
|
2007
|
+
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
2008
|
+
};
|
|
2009
|
+
const _getProps = (props, prop) => {
|
|
2010
|
+
return _getVarProps(props)?.[prop] || _getConstProps(props)?.[prop] || null;
|
|
2011
|
+
};
|
|
2012
|
+
/** Used by the optimizer for spread props operations @internal */
|
|
2013
|
+
const _getVarProps = (props) => {
|
|
2014
|
+
if (!props) {
|
|
2015
|
+
return null;
|
|
2016
|
+
}
|
|
2017
|
+
return _VAR_PROPS in props
|
|
2018
|
+
? 'children' in props
|
|
2019
|
+
? { ...props[_VAR_PROPS], children: props.children }
|
|
2020
|
+
: props[_VAR_PROPS]
|
|
2021
|
+
: props;
|
|
2022
|
+
};
|
|
2023
|
+
/** Used by the optimizer for spread props operations @internal */
|
|
2024
|
+
const _getConstProps = (props) => {
|
|
2025
|
+
if (!props) {
|
|
2026
|
+
return null;
|
|
2027
|
+
}
|
|
2028
|
+
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
2029
|
+
};
|
|
2030
|
+
const isPropsProxy = (obj) => {
|
|
2031
|
+
return obj && _VAR_PROPS in obj;
|
|
2032
|
+
};
|
|
2033
|
+
|
|
1772
2034
|
/**
|
|
1773
2035
|
* # ================================
|
|
1774
2036
|
*
|
|
@@ -1840,6 +2102,7 @@ const STORE_TARGET = Symbol('store.target');
|
|
|
1840
2102
|
const STORE_HANDLER = Symbol('store.handler');
|
|
1841
2103
|
const STORE_ALL_PROPS = Symbol('store.all');
|
|
1842
2104
|
|
|
2105
|
+
/** @internal */
|
|
1843
2106
|
function getSubscriber(effect, prop, data) {
|
|
1844
2107
|
if (!effect[_EFFECT_BACK_REF]) {
|
|
1845
2108
|
if (isServer && isSsrNode(effect)) {
|
|
@@ -2007,7 +2270,7 @@ class SignalImpl {
|
|
|
2007
2270
|
toString() {
|
|
2008
2271
|
if (isDev) {
|
|
2009
2272
|
try {
|
|
2010
|
-
return (`[${this.constructor.name}${this.$flags$ & 1 /*
|
|
2273
|
+
return (`[${this.constructor.name}${this.$flags$ & 1 /* ComputedSignalFlags.INVALID */ ? ' INVALID' : ''} ${this.$untrackedValue$}]` +
|
|
2011
2274
|
(Array.from(this.$effects$ || [])
|
|
2012
2275
|
.map((e) => '\n -> ' + pad(qwikDebugToString(e.consumer), ' '))
|
|
2013
2276
|
.join('\n') || ''));
|
|
@@ -2025,99 +2288,11 @@ class SignalImpl {
|
|
|
2025
2288
|
}
|
|
2026
2289
|
}
|
|
2027
2290
|
|
|
2028
|
-
const DEBUG
|
|
2291
|
+
const DEBUG = false;
|
|
2029
2292
|
// eslint-disable-next-line no-console
|
|
2030
|
-
const log
|
|
2031
|
-
/**
|
|
2032
|
-
|
|
2033
|
-
*
|
|
2034
|
-
* The value is available synchronously, but the computation is done lazily.
|
|
2035
|
-
*/
|
|
2036
|
-
class ComputedSignalImpl extends SignalImpl {
|
|
2037
|
-
/**
|
|
2038
|
-
* The compute function is stored here.
|
|
2039
|
-
*
|
|
2040
|
-
* The computed functions must be executed synchronously (because of this we need to eagerly
|
|
2041
|
-
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous). )
|
|
2042
|
-
*/
|
|
2043
|
-
$computeQrl$;
|
|
2044
|
-
$flags$;
|
|
2045
|
-
[_EFFECT_BACK_REF] = undefined;
|
|
2046
|
-
constructor(container, fn,
|
|
2047
|
-
// We need a separate flag to know when the computation needs running because
|
|
2048
|
-
// we need the old value to know if effects need running after computation
|
|
2049
|
-
flags = 1 /* SignalFlags.INVALID */ |
|
|
2050
|
-
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
|
|
2051
|
-
// The value is used for comparison when signals trigger, which can only happen
|
|
2052
|
-
// when it was calculated before. Therefore we can pass whatever we like.
|
|
2053
|
-
super(container || tryGetInvokeContext()?.$container$, NEEDS_COMPUTATION);
|
|
2054
|
-
this.$computeQrl$ = fn;
|
|
2055
|
-
this.$flags$ = flags;
|
|
2056
|
-
}
|
|
2057
|
-
invalidate() {
|
|
2058
|
-
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
2059
|
-
const ctx = newInvokeContext();
|
|
2060
|
-
ctx.$container$ = this.$container$ || undefined;
|
|
2061
|
-
// @ts-expect-error it's confused about args any[] vs []
|
|
2062
|
-
const running = retryOnPromise(invokeApply.bind(this, ctx, this.$computeIfNeeded$));
|
|
2063
|
-
if (running) {
|
|
2064
|
-
running.catch((err) => {
|
|
2065
|
-
if (this.$container$) {
|
|
2066
|
-
this.$container$.handleError(err, null);
|
|
2067
|
-
}
|
|
2068
|
-
else {
|
|
2069
|
-
console.error('Error during computation', err);
|
|
2070
|
-
}
|
|
2071
|
-
});
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
get untrackedValue() {
|
|
2075
|
-
this.$computeIfNeeded$();
|
|
2076
|
-
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2077
|
-
return this.$untrackedValue$;
|
|
2078
|
-
}
|
|
2079
|
-
set untrackedValue(value) {
|
|
2080
|
-
this.$untrackedValue$ = value;
|
|
2081
|
-
}
|
|
2082
|
-
$computeIfNeeded$() {
|
|
2083
|
-
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
const computeQrl = this.$computeQrl$;
|
|
2087
|
-
throwIfQRLNotResolved(computeQrl);
|
|
2088
|
-
const ctx = tryGetInvokeContext();
|
|
2089
|
-
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
2090
|
-
if (ctx) {
|
|
2091
|
-
const effectSubscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
2092
|
-
clearEffectSubscription(this.$container$, effectSubscriber);
|
|
2093
|
-
ctx.$effectSubscriber$ = effectSubscriber;
|
|
2094
|
-
}
|
|
2095
|
-
try {
|
|
2096
|
-
const untrackedValue = computeQrl.getFn(ctx)();
|
|
2097
|
-
if (isPromise(untrackedValue)) {
|
|
2098
|
-
throw qError(29 /* QError.computedNotSync */, [
|
|
2099
|
-
computeQrl.dev ? computeQrl.dev.file : '',
|
|
2100
|
-
computeQrl.$hash$,
|
|
2101
|
-
]);
|
|
2102
|
-
}
|
|
2103
|
-
DEBUG$1 && log$1('Signal.$compute$', untrackedValue);
|
|
2104
|
-
this.$flags$ &= ~1 /* SignalFlags.INVALID */;
|
|
2105
|
-
super.value = untrackedValue;
|
|
2106
|
-
}
|
|
2107
|
-
finally {
|
|
2108
|
-
if (ctx) {
|
|
2109
|
-
ctx.$effectSubscriber$ = previousEffectSubscription;
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
|
|
2115
|
-
const DEBUG = false;
|
|
2116
|
-
const log = (...args) =>
|
|
2117
|
-
// eslint-disable-next-line no-console
|
|
2118
|
-
console.log('ASYNC COMPUTED SIGNAL', ...args.map(qwikDebugToString));
|
|
2119
|
-
/** Retains job metadata and also serves as the argument for the compute function */
|
|
2120
|
-
class AsyncJob {
|
|
2293
|
+
const log = (...args) => console.log('COMPUTED SIGNAL', ...args.map(qwikDebugToString));
|
|
2294
|
+
/** Retains job metadata and also serves as the argument for CTX_ARG compute functions */
|
|
2295
|
+
class Job {
|
|
2121
2296
|
$signal$;
|
|
2122
2297
|
/** First holds the compute promise and then the cleanup promise */
|
|
2123
2298
|
$promise$ = null;
|
|
@@ -2139,7 +2314,7 @@ class AsyncJob {
|
|
|
2139
2314
|
/** Backward compatible cache method for resource */
|
|
2140
2315
|
cache() {
|
|
2141
2316
|
isDev &&
|
|
2142
|
-
console.error('useResource cache() method does not do anything. Use `
|
|
2317
|
+
console.error('useResource cache() method does not do anything. Use `useComputed$` instead of `useResource$`, use the `expires` option for polling behavior.');
|
|
2143
2318
|
}
|
|
2144
2319
|
get previous() {
|
|
2145
2320
|
const val = this.$signal$.$untrackedValue$;
|
|
@@ -2154,46 +2329,57 @@ class AsyncJob {
|
|
|
2154
2329
|
}
|
|
2155
2330
|
}
|
|
2156
2331
|
/**
|
|
2157
|
-
*
|
|
2158
|
-
*
|
|
2159
|
-
* AsyncSignalImpl
|
|
2160
|
-
*
|
|
2161
|
-
* # ================================
|
|
2332
|
+
* A signal which is computed from other signals.
|
|
2162
2333
|
*
|
|
2163
|
-
*
|
|
2334
|
+
* Sync compute functions resolve synchronously and every read they perform is auto-tracked. When
|
|
2335
|
+
* the compute function turns out to be async (it returned a promise), the signal lazily switches on
|
|
2336
|
+
* the async engine — jobs, `loading`, `error`, polling — giving it the same API as an AsyncSignal.
|
|
2337
|
+
* Auto-tracking only covers reads before the first await point (the invoke context is lost after
|
|
2338
|
+
* it); later reads must use the ComputeCtx `track()`.
|
|
2164
2339
|
*/
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2340
|
+
// TODO when we make core lazy async, lazy load the async engine part of this class
|
|
2341
|
+
class ComputedSignalImpl extends SignalImpl {
|
|
2342
|
+
/**
|
|
2343
|
+
* The compute function is stored here.
|
|
2344
|
+
*
|
|
2345
|
+
* Sync computed functions must be executed synchronously (because of this we need to eagerly
|
|
2346
|
+
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous).
|
|
2347
|
+
*/
|
|
2348
|
+
$computeQrl$;
|
|
2349
|
+
$flags$;
|
|
2169
2350
|
[_EFFECT_BACK_REF] = undefined;
|
|
2170
|
-
constructor(container, fn,
|
|
2351
|
+
constructor(container, fn,
|
|
2352
|
+
// We need a separate flag to know when the computation needs running because
|
|
2353
|
+
// we need the old value to know if effects need running after computation
|
|
2354
|
+
flags = 1 /* ComputedSignalFlags.INVALID */ |
|
|
2171
2355
|
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
|
|
2172
|
-
|
|
2356
|
+
// The value is used for comparison when signals trigger, which can only happen
|
|
2357
|
+
// when it was calculated before. Therefore we can pass whatever we like.
|
|
2358
|
+
super(container || tryGetInvokeContext()?.$container$, NEEDS_COMPUTATION);
|
|
2359
|
+
this.$computeQrl$ = fn;
|
|
2360
|
+
this.$flags$ = flags;
|
|
2173
2361
|
if (!options) {
|
|
2174
2362
|
return;
|
|
2175
2363
|
}
|
|
2176
|
-
//
|
|
2177
|
-
// Do NOT call setValue() which would clear the INVALID flag and prevent async computation
|
|
2364
|
+
// Eagerly evaluate an initial value without clearing INVALID, so the compute still runs
|
|
2178
2365
|
const initial = options.initial;
|
|
2179
2366
|
if (initial !== undefined) {
|
|
2180
|
-
|
|
2181
|
-
this.$untrackedValue$ = initialValue;
|
|
2367
|
+
this.$untrackedValue$ = typeof initial === 'function' ? initial() : initial;
|
|
2182
2368
|
}
|
|
2183
2369
|
const concurrency = options.concurrency;
|
|
2184
2370
|
if (concurrency !== undefined && concurrency >= 0 && concurrency !== 1) {
|
|
2185
2371
|
this.$concurrency$ = concurrency;
|
|
2186
2372
|
this.$jobs$ = [];
|
|
2187
2373
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
this.$timeoutMs$ = timeout;
|
|
2374
|
+
if (options.timeout) {
|
|
2375
|
+
this.$timeoutMs$ = options.timeout;
|
|
2191
2376
|
}
|
|
2192
2377
|
if (options.eagerCleanup) {
|
|
2193
2378
|
this.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
|
|
2194
2379
|
}
|
|
2195
2380
|
if (options.clientOnly) {
|
|
2196
|
-
|
|
2381
|
+
// clientOnly can never resolve during SSR, so it must be async from the start
|
|
2382
|
+
this.$flags$ |= 64 /* AsyncSignalFlags.CLIENT_ONLY */ | 512 /* AsyncSignalFlags.ASYNC_MODE */;
|
|
2197
2383
|
}
|
|
2198
2384
|
if (options.allowStale === false) {
|
|
2199
2385
|
if (isDev && initial !== undefined) {
|
|
@@ -2210,28 +2396,30 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2210
2396
|
this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
|
|
2211
2397
|
}
|
|
2212
2398
|
}
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
throw this.$current$?.$promise$;
|
|
2218
|
-
}
|
|
2219
|
-
return this.$untrackedValue$;
|
|
2399
|
+
invalidate(info) {
|
|
2400
|
+
if (arguments.length > 0) {
|
|
2401
|
+
this.$info$ = info;
|
|
2402
|
+
this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
|
|
2220
2403
|
}
|
|
2221
|
-
if (this.$
|
|
2222
|
-
|
|
2404
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2405
|
+
this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
|
|
2406
|
+
return;
|
|
2223
2407
|
}
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2408
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2409
|
+
const ctx = newInvokeContext();
|
|
2410
|
+
ctx.$container$ = this.$container$ || undefined;
|
|
2411
|
+
// @ts-expect-error it's confused about args any[] vs []
|
|
2412
|
+
const running = retryOnPromise(invokeApply.bind(this, ctx, this.$computeIfNeeded$));
|
|
2413
|
+
if (isPromise(running)) {
|
|
2414
|
+
running.catch((err) => {
|
|
2415
|
+
if (this.$container$) {
|
|
2416
|
+
this.$container$.handleError(err, null);
|
|
2417
|
+
}
|
|
2418
|
+
else {
|
|
2419
|
+
console.error('Error during computation', err);
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2230
2422
|
}
|
|
2231
|
-
return this.$untrackedValue$;
|
|
2232
|
-
}
|
|
2233
|
-
set untrackedValue(value) {
|
|
2234
|
-
this.$untrackedValue$ = value;
|
|
2235
2423
|
}
|
|
2236
2424
|
/**
|
|
2237
2425
|
* Read the value, subscribing if in a tracking context. Triggers computation if needed.
|
|
@@ -2248,32 +2436,65 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2248
2436
|
return super.value;
|
|
2249
2437
|
}
|
|
2250
2438
|
set value(value) {
|
|
2251
|
-
this.$flags$ &= -2 /*
|
|
2252
|
-
this.untrackedLoading = false;
|
|
2439
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2253
2440
|
this.untrackedError = undefined;
|
|
2254
|
-
this.$
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2441
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2442
|
+
this.untrackedPending = false;
|
|
2443
|
+
this.$info$ = undefined;
|
|
2444
|
+
// Prevent pending computations from overwriting this value
|
|
2445
|
+
if (this.$jobs$) {
|
|
2446
|
+
for (let i = 0; i < this.$jobs$.length; i++) {
|
|
2447
|
+
this.$jobs$[i].$canWrite$ = false;
|
|
2448
|
+
}
|
|
2259
2449
|
}
|
|
2450
|
+
else if (this.$current$) {
|
|
2451
|
+
this.$current$.$canWrite$ = false;
|
|
2452
|
+
}
|
|
2453
|
+
this.$clearNextPoll$();
|
|
2454
|
+
super.value = value;
|
|
2455
|
+
this.$scheduleNextPoll$();
|
|
2456
|
+
return;
|
|
2260
2457
|
}
|
|
2261
|
-
else if (this.$current$) {
|
|
2262
|
-
this.$current$.$canWrite$ = false;
|
|
2263
|
-
}
|
|
2264
|
-
this.$clearNextPoll$();
|
|
2265
2458
|
super.value = value;
|
|
2266
|
-
|
|
2459
|
+
}
|
|
2460
|
+
get untrackedValue() {
|
|
2461
|
+
this.$computeIfNeeded$();
|
|
2462
|
+
if (this.$current$?.$promise$) {
|
|
2463
|
+
if (this.$untrackedValue$ === NEEDS_COMPUTATION || (qTest ? isServerPlatform() : isServer)) {
|
|
2464
|
+
throw this.$current$?.$promise$;
|
|
2465
|
+
}
|
|
2466
|
+
return this.$untrackedValue$;
|
|
2467
|
+
}
|
|
2468
|
+
if (this.$untrackedError$) {
|
|
2469
|
+
throw this.$untrackedError$;
|
|
2470
|
+
}
|
|
2471
|
+
// For clientOnly signals without initial value during SSR, throw if trying to read value
|
|
2472
|
+
// During SSR, clientOnly signals are skipped, so there's no computed value available
|
|
2473
|
+
if ((qTest ? isServerPlatform() : isServer) &&
|
|
2474
|
+
this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */ &&
|
|
2475
|
+
this.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
2476
|
+
throw qError(35 /* QError.asyncClientOnlyValueDuringSSR */);
|
|
2477
|
+
}
|
|
2478
|
+
isDev &&
|
|
2479
|
+
!(this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) &&
|
|
2480
|
+
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2481
|
+
return this.$untrackedValue$;
|
|
2482
|
+
}
|
|
2483
|
+
set untrackedValue(value) {
|
|
2484
|
+
this.$untrackedValue$ = value;
|
|
2267
2485
|
}
|
|
2268
2486
|
/**
|
|
2269
2487
|
* Loading is true if the signal is still waiting for the promise to resolve, false if the promise
|
|
2270
|
-
* has resolved or rejected.
|
|
2488
|
+
* has resolved or rejected (or the compute function is synchronous).
|
|
2271
2489
|
*
|
|
2272
|
-
* Accessing
|
|
2273
|
-
*
|
|
2490
|
+
* Accessing `.pending` will trigger computation if needed, since it's often used like
|
|
2491
|
+
*
|
|
2492
|
+
* ```ts
|
|
2493
|
+
* signal.pending ? <Loading /> : signal.value
|
|
2494
|
+
* ```
|
|
2274
2495
|
*/
|
|
2275
|
-
get
|
|
2276
|
-
const val = this.
|
|
2496
|
+
get pending() {
|
|
2497
|
+
const val = this.untrackedPending;
|
|
2277
2498
|
const ctx = tryGetInvokeContext();
|
|
2278
2499
|
if (ctx && (this.$container$ ||= ctx.$container$ || null)) {
|
|
2279
2500
|
isDev &&
|
|
@@ -2287,22 +2508,41 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2287
2508
|
}
|
|
2288
2509
|
return val;
|
|
2289
2510
|
}
|
|
2290
|
-
set
|
|
2291
|
-
if (value !== this.$
|
|
2292
|
-
this.$
|
|
2511
|
+
set untrackedPending(value) {
|
|
2512
|
+
if (value !== !!this.$untrackedPending$) {
|
|
2513
|
+
this.$untrackedPending$ = value;
|
|
2293
2514
|
scheduleEffects(this.$container$, this, this.$loadingEffects$);
|
|
2294
2515
|
}
|
|
2295
2516
|
}
|
|
2296
|
-
get
|
|
2517
|
+
get untrackedPending() {
|
|
2297
2518
|
// 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.
|
|
2298
2519
|
this.$computeIfNeeded$();
|
|
2299
2520
|
// During SSR there's no such thing as loading state, we must render complete results
|
|
2300
2521
|
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2301
2522
|
throw this.$current$?.$promise$;
|
|
2302
2523
|
}
|
|
2303
|
-
return this.$
|
|
2524
|
+
return !!this.$untrackedPending$;
|
|
2525
|
+
}
|
|
2526
|
+
/** @deprecated Use `pending` instead */
|
|
2527
|
+
get loading() {
|
|
2528
|
+
return this.pending;
|
|
2529
|
+
}
|
|
2530
|
+
/** @deprecated Use `untrackedPending` instead */
|
|
2531
|
+
get untrackedLoading() {
|
|
2532
|
+
return this.untrackedPending;
|
|
2304
2533
|
}
|
|
2305
|
-
|
|
2534
|
+
set untrackedLoading(value) {
|
|
2535
|
+
this.untrackedPending = value;
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* The error the compute function threw or rejected with.
|
|
2539
|
+
*
|
|
2540
|
+
* Accessing .error will trigger computation if needed, since it's often used like
|
|
2541
|
+
*
|
|
2542
|
+
* ```ts
|
|
2543
|
+
* signal.error ? <Failed /> : signal.value
|
|
2544
|
+
* ```
|
|
2545
|
+
*/
|
|
2306
2546
|
get error() {
|
|
2307
2547
|
const val = this.untrackedError;
|
|
2308
2548
|
const ctx = tryGetInvokeContext();
|
|
@@ -2325,6 +2565,11 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2325
2565
|
}
|
|
2326
2566
|
}
|
|
2327
2567
|
get untrackedError() {
|
|
2568
|
+
this.$computeIfNeeded$();
|
|
2569
|
+
// During SSR we must render settled results
|
|
2570
|
+
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2571
|
+
throw this.$current$?.$promise$;
|
|
2572
|
+
}
|
|
2328
2573
|
return this.$untrackedError$;
|
|
2329
2574
|
}
|
|
2330
2575
|
get expires() {
|
|
@@ -2367,16 +2612,8 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2367
2612
|
}
|
|
2368
2613
|
this.expires = Math.abs(value);
|
|
2369
2614
|
}
|
|
2370
|
-
/** Invalidates the signal, causing it to re-compute its value. */
|
|
2371
|
-
async invalidate(info) {
|
|
2372
|
-
if (arguments.length > 0) {
|
|
2373
|
-
this.$info$ = info;
|
|
2374
|
-
this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
|
|
2375
|
-
}
|
|
2376
|
-
this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
|
|
2377
|
-
}
|
|
2378
2615
|
$setInvalid$(allowRecalc, mustClear) {
|
|
2379
|
-
this.$flags$ |= 1 /*
|
|
2616
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2380
2617
|
this.$clearNextPoll$();
|
|
2381
2618
|
if (mustClear) {
|
|
2382
2619
|
this.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
@@ -2417,19 +2654,97 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2417
2654
|
}
|
|
2418
2655
|
/** Run the computation if needed */
|
|
2419
2656
|
$computeIfNeeded$() {
|
|
2420
|
-
if (!(this.$flags$ & 1 /*
|
|
2657
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
2660
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2661
|
+
return this.$computeAsync$();
|
|
2662
|
+
}
|
|
2663
|
+
const computeQrl = this.$computeQrl$;
|
|
2664
|
+
throwIfQRLNotResolved(computeQrl);
|
|
2665
|
+
// The previous compute's cleanups run before the new compute, like the async engine
|
|
2666
|
+
const prevJob = this.$current$;
|
|
2667
|
+
if (prevJob && !prevJob.$cleanupRequested$) {
|
|
2668
|
+
prevJob.$cleanupRequested$ = true;
|
|
2669
|
+
prevJob.$abortController$?.abort();
|
|
2670
|
+
this.$runCleanupCallbacks$(prevJob);
|
|
2671
|
+
}
|
|
2672
|
+
const running = new Job(this, this.$info$, this.$infoVersion$);
|
|
2673
|
+
this.$current$ = running;
|
|
2674
|
+
let result;
|
|
2675
|
+
try {
|
|
2676
|
+
result = this.$invokeComputeFn$(computeQrl.resolved, running);
|
|
2677
|
+
}
|
|
2678
|
+
catch (err) {
|
|
2679
|
+
// A thrown promise is a retry request, not a failure
|
|
2680
|
+
if (isPromise(err)) {
|
|
2681
|
+
throw err;
|
|
2682
|
+
}
|
|
2683
|
+
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2684
|
+
this.$info$ = undefined;
|
|
2685
|
+
}
|
|
2686
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2687
|
+
this.$setError$(running, err);
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
if (isPromise(result)) {
|
|
2691
|
+
// The compute fn is async: hand the in-flight computation to the async engine
|
|
2692
|
+
this.$flags$ |= 512 /* AsyncSignalFlags.ASYNC_MODE */;
|
|
2693
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2694
|
+
// Consume the in-flight promise first; retries re-invoke the compute fn
|
|
2695
|
+
let first = result;
|
|
2696
|
+
const compute = () => {
|
|
2697
|
+
const r = first ?? this.$invokeComputeFn$(this.$computeQrl$.resolved, running);
|
|
2698
|
+
first = undefined;
|
|
2699
|
+
return r;
|
|
2700
|
+
};
|
|
2701
|
+
running.$promise$ = this.$settleComputation$(running, () => retryOnPromise(compute));
|
|
2421
2702
|
return;
|
|
2422
2703
|
}
|
|
2704
|
+
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2705
|
+
this.$info$ = undefined;
|
|
2706
|
+
}
|
|
2707
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2708
|
+
this.untrackedError = undefined;
|
|
2709
|
+
super.value = result;
|
|
2710
|
+
}
|
|
2711
|
+
/**
|
|
2712
|
+
* Invoke the compute fn with the ComputeCtx argument. CTX_ARG signals (useAsync$, useResource$)
|
|
2713
|
+
* only track via its explicit track(). Computeds auto-track every synchronous read instead; after
|
|
2714
|
+
* the first await they must use the explicit track() too.
|
|
2715
|
+
*/
|
|
2716
|
+
$invokeComputeFn$(fn, job) {
|
|
2717
|
+
const computeFn = fn;
|
|
2718
|
+
if (this.$flags$ & 1024 /* AsyncSignalFlags.CTX_ARG */) {
|
|
2719
|
+
// Strip the ambient effect subscriber: these compute fns track only via their track()
|
|
2720
|
+
let iCtx = tryGetInvokeContext();
|
|
2721
|
+
if (iCtx?.$effectSubscriber$) {
|
|
2722
|
+
iCtx = { ...iCtx, $effectSubscriber$: undefined };
|
|
2723
|
+
}
|
|
2724
|
+
return invokeApply(iCtx, computeFn, [job]);
|
|
2725
|
+
}
|
|
2726
|
+
const container = (this.$container$ ||= tryGetInvokeContext()?.$container$ || null);
|
|
2727
|
+
const subscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
2728
|
+
if (container) {
|
|
2729
|
+
clearEffectSubscription(container, subscriber);
|
|
2730
|
+
}
|
|
2731
|
+
const ctx = newInvokeContext();
|
|
2732
|
+
ctx.$container$ = container || undefined;
|
|
2733
|
+
ctx.$effectSubscriber$ = subscriber;
|
|
2734
|
+
return invokeApply(ctx, computeFn, [job]);
|
|
2735
|
+
}
|
|
2736
|
+
/** Start an async computation (the async engine; assumes the INVALID flag is set) */
|
|
2737
|
+
$computeAsync$() {
|
|
2423
2738
|
// Skip computation on SSR for clientOnly signals
|
|
2424
2739
|
if ((qTest ? isServerPlatform() : isServer) && this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
2425
2740
|
// We must pretend to load, and register as a listener for the captures
|
|
2426
|
-
this.$
|
|
2741
|
+
this.$untrackedPending$ = true;
|
|
2427
2742
|
this.$container$?.serializationCtx.$eagerResume$.add(this);
|
|
2428
2743
|
return;
|
|
2429
2744
|
}
|
|
2430
2745
|
this.$clearNextPoll$();
|
|
2431
2746
|
// Clear flag here to make sure the cleanups don't start another compute
|
|
2432
|
-
this.$flags$ &= -2 /*
|
|
2747
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2433
2748
|
const current = this.$current$;
|
|
2434
2749
|
if (current) {
|
|
2435
2750
|
this.$requestCleanups$(current);
|
|
@@ -2439,12 +2754,12 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2439
2754
|
if (this.$jobs$ ? this.$jobs$.length >= limit : current?.$promise$) {
|
|
2440
2755
|
// We requested cleanups for all the previous jobs, once one finishes it will be removed from the jobs array and trigger computeIfNeeded
|
|
2441
2756
|
// Restore invalid state
|
|
2442
|
-
this.$flags$ |= 1 /*
|
|
2757
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2443
2758
|
return;
|
|
2444
2759
|
}
|
|
2445
2760
|
// We put the actual computation in a separate method so we can easily retain the promise
|
|
2446
2761
|
const infoVersion = this.$infoVersion$;
|
|
2447
|
-
const running = new
|
|
2762
|
+
const running = new Job(this, this.$info$, infoVersion);
|
|
2448
2763
|
this.$current$ = running;
|
|
2449
2764
|
if (this.$jobs$) {
|
|
2450
2765
|
this.$jobs$.push(running);
|
|
@@ -2452,35 +2767,39 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2452
2767
|
running.$promise$ = this.$runComputation$(running);
|
|
2453
2768
|
}
|
|
2454
2769
|
async $runComputation$(running) {
|
|
2455
|
-
const isCurrent = () => running === this.$current$;
|
|
2456
2770
|
let fn = this.$computeQrl$.resolved;
|
|
2457
2771
|
if (!fn) {
|
|
2458
2772
|
// QRL resolution is async — we have to publish loading=true before awaiting so
|
|
2459
2773
|
// subscribers know the value isn't ready yet.
|
|
2460
|
-
this.
|
|
2774
|
+
this.untrackedPending = true;
|
|
2461
2775
|
fn = await this.$computeQrl$.resolve();
|
|
2462
2776
|
if (running.$abortController$?.signal.aborted) {
|
|
2463
2777
|
running.$promise$ = null;
|
|
2464
2778
|
return;
|
|
2465
2779
|
}
|
|
2466
2780
|
}
|
|
2781
|
+
if (this.$timeoutMs$) {
|
|
2782
|
+
this.$computationTimeoutId$ = setTimeout(() => {
|
|
2783
|
+
const error = new Error(`timeout ${this.$timeoutMs$}ms`);
|
|
2784
|
+
this.$setError$(running, error);
|
|
2785
|
+
running.$abortController$?.abort(error);
|
|
2786
|
+
}, this.$timeoutMs$);
|
|
2787
|
+
}
|
|
2788
|
+
return this.$settleComputation$(running, () => retryOnPromise(() => this.$invokeComputeFn$(fn, running)));
|
|
2789
|
+
}
|
|
2790
|
+
/** Await the computation and publish its result, error, and loading transitions. */
|
|
2791
|
+
async $settleComputation$(running, compute) {
|
|
2792
|
+
const isCurrent = () => running === this.$current$;
|
|
2467
2793
|
try {
|
|
2468
|
-
if (this.$timeoutMs$) {
|
|
2469
|
-
this.$computationTimeoutId$ = setTimeout(() => {
|
|
2470
|
-
const error = new Error(`timeout ${this.$timeoutMs$}ms`);
|
|
2471
|
-
this.$setError$(running, error);
|
|
2472
|
-
running.$abortController$?.abort(error);
|
|
2473
|
-
}, this.$timeoutMs$);
|
|
2474
|
-
}
|
|
2475
2794
|
// Try to stay sync if possible. Only publish loading=true to subscribers when
|
|
2476
2795
|
// the compute is actually asynchronous — a synchronous resolve (e.g. pre-loaded
|
|
2477
2796
|
// values injected via _injectAsyncSignalValue) should never transition through a
|
|
2478
2797
|
// visible loading state, which on SSR would fire the loading-effect subscribers
|
|
2479
2798
|
// (tasks) while the value is still "loading" from their perspective.
|
|
2480
|
-
const valuePromise =
|
|
2799
|
+
const valuePromise = compute();
|
|
2481
2800
|
let value;
|
|
2482
2801
|
if (isPromise(valuePromise)) {
|
|
2483
|
-
this.
|
|
2802
|
+
this.untrackedPending = true;
|
|
2484
2803
|
value = await valuePromise;
|
|
2485
2804
|
}
|
|
2486
2805
|
else {
|
|
@@ -2505,7 +2824,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2505
2824
|
// Note that these assignments run setters
|
|
2506
2825
|
this.untrackedError = undefined;
|
|
2507
2826
|
/**
|
|
2508
|
-
* Use
|
|
2827
|
+
* Use SignalImpl.value instead of this.value to persist invalid state, so that invalidation
|
|
2509
2828
|
* during computation recomputes
|
|
2510
2829
|
*/
|
|
2511
2830
|
super.value = value;
|
|
@@ -2520,12 +2839,12 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2520
2839
|
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2521
2840
|
this.$info$ = undefined;
|
|
2522
2841
|
}
|
|
2523
|
-
if (this.$flags$ & 1 /*
|
|
2842
|
+
if (this.$flags$ & 1 /* ComputedSignalFlags.INVALID */) {
|
|
2524
2843
|
// we became invalid again while running, so we need to re-run the computation to get the new promise
|
|
2525
2844
|
this.$computeIfNeeded$();
|
|
2526
2845
|
}
|
|
2527
2846
|
else {
|
|
2528
|
-
this.
|
|
2847
|
+
this.untrackedPending = false;
|
|
2529
2848
|
this.$scheduleNextPoll$();
|
|
2530
2849
|
}
|
|
2531
2850
|
}
|
|
@@ -2552,325 +2871,98 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2552
2871
|
this.$clearNextPoll$();
|
|
2553
2872
|
clearTimeout(this.$computationTimeoutId$);
|
|
2554
2873
|
const current = this.$current$;
|
|
2555
|
-
if (current) {
|
|
2556
|
-
this.$requestCleanups$(current);
|
|
2557
|
-
}
|
|
2558
|
-
if (this.$jobs$) {
|
|
2559
|
-
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2560
|
-
}
|
|
2561
|
-
else {
|
|
2562
|
-
await current?.$promise$;
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
$clearNextPoll$() {
|
|
2566
|
-
if (this.$pollTimeoutId$ !== undefined) {
|
|
2567
|
-
clearTimeout(this.$pollTimeoutId$);
|
|
2568
|
-
this.$pollTimeoutId$ = undefined;
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
$scheduleNextPoll$() {
|
|
2572
|
-
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2573
|
-
return;
|
|
2574
|
-
}
|
|
2575
|
-
this.$clearNextPoll$();
|
|
2576
|
-
const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
|
|
2577
|
-
// Even when clear on invalidate, we don't clear if we're merely re-running due to polling
|
|
2578
|
-
// We expect to get the new value soon, so we can avoid showing a loading state
|
|
2579
|
-
const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
|
|
2580
|
-
this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
|
|
2581
|
-
this.$pollTimeoutId$?.unref?.();
|
|
2582
|
-
}
|
|
2583
|
-
$hasSubscribers$() {
|
|
2584
|
-
return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
|
|
2585
|
-
}
|
|
2586
|
-
$requestCleanups$(job, reason) {
|
|
2587
|
-
if (job.$cleanupRequested$) {
|
|
2588
|
-
return;
|
|
2589
|
-
}
|
|
2590
|
-
job.$cleanupRequested$ = true;
|
|
2591
|
-
job.$abortController$?.abort(reason);
|
|
2592
|
-
job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
|
|
2593
|
-
}
|
|
2594
|
-
/** Clean up and trigger signal compute once complete */
|
|
2595
|
-
$runCleanups$(job) {
|
|
2596
|
-
const cleanups = job.$cleanups$;
|
|
2597
|
-
const onError = (err) => {
|
|
2598
|
-
const handleError = this.$container$?.handleError;
|
|
2599
|
-
if (handleError) {
|
|
2600
|
-
handleError(err, null);
|
|
2601
|
-
}
|
|
2602
|
-
else {
|
|
2603
|
-
console.error('Error in async signal cleanup', err);
|
|
2604
|
-
}
|
|
2605
|
-
};
|
|
2606
|
-
const onDone = () => {
|
|
2607
|
-
job.$promise$ = null;
|
|
2608
|
-
if (cleanups) {
|
|
2609
|
-
cleanups.length = 0;
|
|
2610
|
-
}
|
|
2611
|
-
// Now trigger compute
|
|
2612
|
-
const jobs = this.$jobs$;
|
|
2613
|
-
if (jobs) {
|
|
2614
|
-
const idx = jobs.indexOf(job);
|
|
2615
|
-
if (idx !== -1) {
|
|
2616
|
-
jobs.splice(idx, 1);
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
this.$computeIfNeeded$();
|
|
2620
|
-
};
|
|
2621
|
-
let promiseChain = undefined;
|
|
2622
|
-
if (cleanups) {
|
|
2623
|
-
// Keep this sync-ish so sync functions run immediately.
|
|
2624
|
-
for (let i = 0; i < cleanups.length; i++) {
|
|
2625
|
-
try {
|
|
2626
|
-
const result = cleanups[i]();
|
|
2627
|
-
if (isPromise(result)) {
|
|
2628
|
-
promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2631
|
-
catch (err) {
|
|
2632
|
-
onError(err);
|
|
2633
|
-
}
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
if (promiseChain) {
|
|
2637
|
-
return promiseChain.then(onDone);
|
|
2638
|
-
}
|
|
2639
|
-
else {
|
|
2640
|
-
onDone();
|
|
2641
|
-
}
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
|
-
/** @internal */
|
|
2646
|
-
const _CONST_PROPS = Symbol('CONST');
|
|
2647
|
-
/** @internal */
|
|
2648
|
-
const _VAR_PROPS = Symbol('VAR');
|
|
2649
|
-
/** @internal */
|
|
2650
|
-
const _OWNER = Symbol('OWNER');
|
|
2651
|
-
/** @internal */
|
|
2652
|
-
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
2653
|
-
/** @internal @deprecated v1 compat */
|
|
2654
|
-
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
2655
|
-
/** @internal */
|
|
2656
|
-
const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
2657
|
-
|
|
2658
|
-
/** @internal */
|
|
2659
|
-
const EMPTY_ARRAY = [];
|
|
2660
|
-
/** @internal */
|
|
2661
|
-
const EMPTY_OBJ = {};
|
|
2662
|
-
Object.freeze(EMPTY_ARRAY);
|
|
2663
|
-
Object.freeze(EMPTY_OBJ);
|
|
2664
|
-
|
|
2665
|
-
function createPropsProxy(owner) {
|
|
2666
|
-
// TODO don't make a proxy but populate getters? benchmark
|
|
2667
|
-
return new Proxy({}, new PropsProxyHandler(owner));
|
|
2668
|
-
}
|
|
2669
|
-
class PropsProxyHandler {
|
|
2670
|
-
owner;
|
|
2671
|
-
$effects$ = undefined;
|
|
2672
|
-
$container$ = null;
|
|
2673
|
-
constructor(owner) {
|
|
2674
|
-
this.owner = owner;
|
|
2675
|
-
}
|
|
2676
|
-
get(_, prop) {
|
|
2677
|
-
// escape hatch to get the separated props from a component
|
|
2678
|
-
if (prop === _CONST_PROPS) {
|
|
2679
|
-
return this.owner.constProps;
|
|
2680
|
-
}
|
|
2681
|
-
else if (prop === _VAR_PROPS) {
|
|
2682
|
-
return this.owner.varProps;
|
|
2683
|
-
}
|
|
2684
|
-
else if (prop === _OWNER) {
|
|
2685
|
-
return this.owner;
|
|
2686
|
-
}
|
|
2687
|
-
else if (prop === _PROPS_HANDLER) {
|
|
2688
|
-
return this;
|
|
2689
|
-
}
|
|
2690
|
-
let value;
|
|
2691
|
-
if (prop === 'children') {
|
|
2692
|
-
value = this.owner.children;
|
|
2693
|
-
}
|
|
2694
|
-
else {
|
|
2695
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2696
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2697
|
-
if (attr) {
|
|
2698
|
-
prop = attr;
|
|
2699
|
-
}
|
|
2700
|
-
}
|
|
2701
|
-
value = directGetPropsProxyProp(this.owner, prop);
|
|
2702
|
-
if (prop in this.owner.varProps) {
|
|
2703
|
-
addPropsProxyEffect(this, prop);
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
// a proxied value that the optimizer made
|
|
2707
|
-
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
2708
|
-
? value.value
|
|
2709
|
-
: value;
|
|
2710
|
-
}
|
|
2711
|
-
set(_, prop, value) {
|
|
2712
|
-
if (prop === _OWNER) {
|
|
2713
|
-
// used for deserialization
|
|
2714
|
-
this.owner = value;
|
|
2715
|
-
}
|
|
2716
|
-
else if (prop === 'children') {
|
|
2717
|
-
this.owner.children = value;
|
|
2718
|
-
}
|
|
2719
|
-
else if (prop === _CONST_PROPS) {
|
|
2720
|
-
this.owner.constProps = value;
|
|
2721
|
-
}
|
|
2722
|
-
else if (prop === _VAR_PROPS) {
|
|
2723
|
-
this.owner.varProps = value;
|
|
2724
|
-
}
|
|
2725
|
-
else {
|
|
2726
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2727
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2728
|
-
if (attr) {
|
|
2729
|
-
prop = attr;
|
|
2730
|
-
}
|
|
2731
|
-
}
|
|
2732
|
-
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
2733
|
-
// delete the prop from the const props first
|
|
2734
|
-
delete this.owner.constProps[prop];
|
|
2735
|
-
}
|
|
2736
|
-
if (this.owner.varProps === EMPTY_OBJ) {
|
|
2737
|
-
this.owner.varProps = {};
|
|
2738
|
-
}
|
|
2739
|
-
else if (!(prop in this.owner.varProps)) {
|
|
2740
|
-
this.owner.toSort = true;
|
|
2741
|
-
}
|
|
2742
|
-
if (this.owner.varProps[prop] !== value) {
|
|
2743
|
-
this.owner.varProps[prop] = value;
|
|
2744
|
-
triggerPropsProxyEffect(this, prop);
|
|
2745
|
-
}
|
|
2874
|
+
if (current) {
|
|
2875
|
+
this.$requestCleanups$(current);
|
|
2746
2876
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
deleteProperty(_, prop) {
|
|
2750
|
-
let didDelete = delete this.owner.varProps[prop];
|
|
2751
|
-
if (didDelete) {
|
|
2752
|
-
triggerPropsProxyEffect(this, prop);
|
|
2877
|
+
if (this.$jobs$) {
|
|
2878
|
+
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2753
2879
|
}
|
|
2754
|
-
|
|
2755
|
-
|
|
2880
|
+
else {
|
|
2881
|
+
await current?.$promise$;
|
|
2756
2882
|
}
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2883
|
+
}
|
|
2884
|
+
$clearNextPoll$() {
|
|
2885
|
+
if (this.$pollTimeoutId$ !== undefined) {
|
|
2886
|
+
clearTimeout(this.$pollTimeoutId$);
|
|
2887
|
+
this.$pollTimeoutId$ = undefined;
|
|
2760
2888
|
}
|
|
2761
|
-
return didDelete;
|
|
2762
2889
|
}
|
|
2763
|
-
|
|
2764
|
-
if (
|
|
2765
|
-
return
|
|
2890
|
+
$scheduleNextPoll$() {
|
|
2891
|
+
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2892
|
+
return;
|
|
2766
2893
|
}
|
|
2767
|
-
|
|
2768
|
-
|
|
2894
|
+
this.$clearNextPoll$();
|
|
2895
|
+
const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
|
|
2896
|
+
// Even when clear on invalidate, we don't clear if we're merely re-running due to polling
|
|
2897
|
+
// We expect to get the new value soon, so we can avoid showing a loading state
|
|
2898
|
+
const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
|
|
2899
|
+
this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
|
|
2900
|
+
this.$pollTimeoutId$?.unref?.();
|
|
2901
|
+
}
|
|
2902
|
+
$hasSubscribers$() {
|
|
2903
|
+
return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
|
|
2904
|
+
}
|
|
2905
|
+
$requestCleanups$(job, reason) {
|
|
2906
|
+
if (job.$cleanupRequested$) {
|
|
2907
|
+
return;
|
|
2769
2908
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2909
|
+
job.$cleanupRequested$ = true;
|
|
2910
|
+
job.$abortController$?.abort(reason);
|
|
2911
|
+
job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
|
|
2912
|
+
}
|
|
2913
|
+
/** Run a job's cleanup callbacks, returning a promise when any of them are async. */
|
|
2914
|
+
$runCleanupCallbacks$(job) {
|
|
2915
|
+
const cleanups = job.$cleanups$;
|
|
2916
|
+
const onError = (err) => {
|
|
2917
|
+
const handleError = this.$container$?.handleError;
|
|
2918
|
+
if (handleError) {
|
|
2919
|
+
handleError(err, null);
|
|
2774
2920
|
}
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
if (attr) {
|
|
2778
|
-
prop = attr;
|
|
2779
|
-
}
|
|
2921
|
+
else {
|
|
2922
|
+
console.error('Error in async signal cleanup', err);
|
|
2780
2923
|
}
|
|
2781
|
-
}
|
|
2782
|
-
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
2783
|
-
}
|
|
2784
|
-
getOwnPropertyDescriptor(_, p) {
|
|
2785
|
-
const value = p === 'children'
|
|
2786
|
-
? this.owner.children
|
|
2787
|
-
: this.owner.constProps && p in this.owner.constProps
|
|
2788
|
-
? this.owner.constProps[p]
|
|
2789
|
-
: this.owner.varProps[p];
|
|
2790
|
-
return {
|
|
2791
|
-
configurable: true,
|
|
2792
|
-
enumerable: true,
|
|
2793
|
-
value: value,
|
|
2794
2924
|
};
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2925
|
+
let promiseChain = undefined;
|
|
2926
|
+
if (cleanups) {
|
|
2927
|
+
// Keep this sync-ish so sync functions run immediately.
|
|
2928
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
2929
|
+
try {
|
|
2930
|
+
const result = cleanups[i]();
|
|
2931
|
+
if (isPromise(result)) {
|
|
2932
|
+
promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
catch (err) {
|
|
2936
|
+
onError(err);
|
|
2805
2937
|
}
|
|
2806
2938
|
}
|
|
2939
|
+
cleanups.length = 0;
|
|
2807
2940
|
}
|
|
2808
|
-
return
|
|
2941
|
+
return promiseChain;
|
|
2809
2942
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
if (
|
|
2817
|
-
|
|
2943
|
+
/** Clean up and trigger signal compute once complete */
|
|
2944
|
+
$runCleanups$(job) {
|
|
2945
|
+
const onDone = () => {
|
|
2946
|
+
job.$promise$ = null;
|
|
2947
|
+
// Now trigger compute
|
|
2948
|
+
const jobs = this.$jobs$;
|
|
2949
|
+
if (jobs) {
|
|
2950
|
+
const idx = jobs.indexOf(job);
|
|
2951
|
+
if (idx !== -1) {
|
|
2952
|
+
jobs.splice(idx, 1);
|
|
2953
|
+
}
|
|
2818
2954
|
}
|
|
2955
|
+
this.$computeIfNeeded$();
|
|
2956
|
+
};
|
|
2957
|
+
const promiseChain = this.$runCleanupCallbacks$(job);
|
|
2958
|
+
if (promiseChain) {
|
|
2959
|
+
return promiseChain.then(onDone);
|
|
2819
2960
|
}
|
|
2820
2961
|
else {
|
|
2821
|
-
|
|
2822
|
-
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
2962
|
+
onDone();
|
|
2823
2963
|
}
|
|
2824
2964
|
}
|
|
2825
|
-
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
2826
|
-
if (effectSubscriber) {
|
|
2827
|
-
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
2828
|
-
}
|
|
2829
|
-
};
|
|
2830
|
-
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
2831
|
-
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
2832
|
-
if (effects) {
|
|
2833
|
-
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
2834
|
-
}
|
|
2835
|
-
return !!effects;
|
|
2836
|
-
};
|
|
2837
|
-
function getEffects$1(effects, prop) {
|
|
2838
|
-
// TODO: Handle STORE_ALL_PROPS
|
|
2839
|
-
return effects?.get(prop);
|
|
2840
2965
|
}
|
|
2841
|
-
/**
|
|
2842
|
-
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
2843
|
-
* Use this function to get the props directly from a const or var props.
|
|
2844
|
-
*
|
|
2845
|
-
* This does not convert jsx event names.
|
|
2846
|
-
*/
|
|
2847
|
-
const directGetPropsProxyProp = (jsx, prop) => {
|
|
2848
|
-
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
2849
|
-
};
|
|
2850
|
-
const _getProps = (props, prop) => {
|
|
2851
|
-
return _getVarProps(props)?.[prop] || _getConstProps(props)?.[prop] || null;
|
|
2852
|
-
};
|
|
2853
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2854
|
-
const _getVarProps = (props) => {
|
|
2855
|
-
if (!props) {
|
|
2856
|
-
return null;
|
|
2857
|
-
}
|
|
2858
|
-
return _VAR_PROPS in props
|
|
2859
|
-
? 'children' in props
|
|
2860
|
-
? { ...props[_VAR_PROPS], children: props.children }
|
|
2861
|
-
: props[_VAR_PROPS]
|
|
2862
|
-
: props;
|
|
2863
|
-
};
|
|
2864
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2865
|
-
const _getConstProps = (props) => {
|
|
2866
|
-
if (!props) {
|
|
2867
|
-
return null;
|
|
2868
|
-
}
|
|
2869
|
-
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
2870
|
-
};
|
|
2871
|
-
const isPropsProxy = (obj) => {
|
|
2872
|
-
return obj && _VAR_PROPS in obj;
|
|
2873
|
-
};
|
|
2874
2966
|
|
|
2875
2967
|
// <docs markdown="../../readme.md#implicit$FirstArg">
|
|
2876
2968
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
@@ -2926,11 +3018,11 @@ const implicit$FirstArg = (fn) => {
|
|
|
2926
3018
|
*/
|
|
2927
3019
|
class SerializerSignalImpl extends ComputedSignalImpl {
|
|
2928
3020
|
constructor(container, argQrl) {
|
|
2929
|
-
super(container, argQrl, 1 /*
|
|
3021
|
+
super(container, argQrl, 1 /* ComputedSignalFlags.INVALID */ | 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
|
|
2930
3022
|
}
|
|
2931
3023
|
$didInitialize$ = false;
|
|
2932
3024
|
$computeIfNeeded$() {
|
|
2933
|
-
if (!(this.$flags$ & 1 /*
|
|
3025
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
2934
3026
|
return;
|
|
2935
3027
|
}
|
|
2936
3028
|
throwIfQRLNotResolved(this.$computeQrl$);
|
|
@@ -2943,7 +3035,7 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2943
3035
|
: deserialize(currentValue), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
2944
3036
|
this.$didInitialize$ = true;
|
|
2945
3037
|
// Needs to invalidate only after all possible Promise throws happened
|
|
2946
|
-
this.$flags$ &= -2 /*
|
|
3038
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2947
3039
|
// 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.
|
|
2948
3040
|
const didChange = (this.$didInitialize$ && untrackedValue !== 'undefined') ||
|
|
2949
3041
|
untrackedValue !== this.$untrackedValue$;
|
|
@@ -2954,13 +3046,46 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2954
3046
|
}
|
|
2955
3047
|
}
|
|
2956
3048
|
|
|
3049
|
+
/**
|
|
3050
|
+
* # ================================
|
|
3051
|
+
*
|
|
3052
|
+
* AsyncSignalImpl
|
|
3053
|
+
*
|
|
3054
|
+
* # ================================
|
|
3055
|
+
*
|
|
3056
|
+
* The async engine (jobs, loading, error, polling) lives in ComputedSignalImpl; this subclass
|
|
3057
|
+
* configures it from options and switches the compute invocation to CTX_ARG mode: the compute fn
|
|
3058
|
+
* receives the ComputeCtx argument and tracks only via its explicit `track()` (no auto-tracking).
|
|
3059
|
+
*
|
|
3060
|
+
* @internal
|
|
3061
|
+
*/
|
|
3062
|
+
class AsyncSignalImpl extends ComputedSignalImpl {
|
|
3063
|
+
constructor(container, fn, flags = 1 /* ComputedSignalFlags.INVALID */ |
|
|
3064
|
+
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
|
|
3065
|
+
super(container, fn, flags | 512 /* AsyncSignalFlags.ASYNC_MODE */ | 1024 /* AsyncSignalFlags.CTX_ARG */, options);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
/**
|
|
3069
|
+
* Inject a pre-loaded value into a signal while preserving subscriptions. Calls `invalidate({__v})`
|
|
3070
|
+
* so the compute function reads the value from `info`, then triggers an immediate synchronous
|
|
3071
|
+
* compute via the private `$computeIfNeeded$()` method (which is mangled in core builds, so callers
|
|
3072
|
+
* from other packages must go through this helper).
|
|
3073
|
+
*
|
|
3074
|
+
* @internal
|
|
3075
|
+
*/
|
|
3076
|
+
const _injectAsyncSignalValue = (signal, value) => {
|
|
3077
|
+
const impl = signal;
|
|
3078
|
+
impl.invalidate({ __v: value });
|
|
3079
|
+
impl.$computeIfNeeded$();
|
|
3080
|
+
};
|
|
3081
|
+
|
|
2957
3082
|
/** @internal */
|
|
2958
3083
|
const createSignal$1 = (value) => {
|
|
2959
3084
|
return new SignalImpl(null, value);
|
|
2960
3085
|
};
|
|
2961
3086
|
/** @internal */
|
|
2962
3087
|
const createComputedSignal = (qrl, options) => {
|
|
2963
|
-
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'));
|
|
3088
|
+
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'), options);
|
|
2964
3089
|
};
|
|
2965
3090
|
/** @internal */
|
|
2966
3091
|
const createAsyncSignal = (qrl, options) => {
|
|
@@ -2984,9 +3109,10 @@ const createSignal = createSignal$1;
|
|
|
2984
3109
|
* recalculated.
|
|
2985
3110
|
*
|
|
2986
3111
|
* The QRL must be a function which returns the value of the signal. The function must not have side
|
|
2987
|
-
* effects
|
|
2988
|
-
*
|
|
2989
|
-
*
|
|
3112
|
+
* effects. Every synchronous signal or store read is tracked automatically; reads after the first
|
|
3113
|
+
* `await` must use the `track()` provided on the context argument. When the function is async, the
|
|
3114
|
+
* returned signal exposes the async API (`.pending`, `.error`, `.promise()`), and reading an
|
|
3115
|
+
* unresolved `.value` throws the computation promise.
|
|
2990
3116
|
*
|
|
2991
3117
|
* @public
|
|
2992
3118
|
*/
|
|
@@ -2995,6 +3121,7 @@ const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedSignal);
|
|
|
2995
3121
|
* Create a signal holding a `.value` which is calculated from the given async function (QRL). The
|
|
2996
3122
|
* standalone version of `useAsync$`.
|
|
2997
3123
|
*
|
|
3124
|
+
* @deprecated Use `createComputed$` instead, it has async support now.
|
|
2998
3125
|
* @public
|
|
2999
3126
|
*/
|
|
3000
3127
|
const createAsync$ = /*#__PURE__*/ implicit$FirstArg(createAsyncSignal);
|
|
@@ -3041,10 +3168,10 @@ const _wrapProp = (...args) => {
|
|
|
3041
3168
|
return obj[prop];
|
|
3042
3169
|
}
|
|
3043
3170
|
if (isSignal(obj)) {
|
|
3044
|
-
if (!(obj instanceof
|
|
3171
|
+
if (!(obj instanceof ComputedSignalImpl)) {
|
|
3045
3172
|
isDev && assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
3046
3173
|
}
|
|
3047
|
-
if (obj instanceof WrappedSignalImpl
|
|
3174
|
+
if (obj instanceof WrappedSignalImpl) {
|
|
3048
3175
|
return obj;
|
|
3049
3176
|
}
|
|
3050
3177
|
return getWrapped(args);
|
|
@@ -3098,7 +3225,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3098
3225
|
constructor(container, fn, args, fnStr,
|
|
3099
3226
|
// We need a separate flag to know when the computation needs running because
|
|
3100
3227
|
// we need the old value to know if effects need running after computation
|
|
3101
|
-
flags = 1 /*
|
|
3228
|
+
flags = 1 /* ComputedSignalFlags.INVALID */) {
|
|
3102
3229
|
super(container, NEEDS_COMPUTATION);
|
|
3103
3230
|
this.$args$ = args;
|
|
3104
3231
|
this.$func$ = fn;
|
|
@@ -3106,7 +3233,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3106
3233
|
this.$flags$ = flags;
|
|
3107
3234
|
}
|
|
3108
3235
|
invalidate() {
|
|
3109
|
-
this.$flags$ |= 1 /*
|
|
3236
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
3110
3237
|
// we are trying to run computation without creating a chore, which can be expensive
|
|
3111
3238
|
// for many signals. If it fails, we schedule a chore to run the computation.
|
|
3112
3239
|
try {
|
|
@@ -3119,8 +3246,8 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3119
3246
|
}
|
|
3120
3247
|
}
|
|
3121
3248
|
// if the computation not failed, we can run the effects directly
|
|
3122
|
-
if (this.$flags$ & 2 /*
|
|
3123
|
-
this.$flags$ &= -3 /*
|
|
3249
|
+
if (this.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
3250
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3124
3251
|
scheduleEffects(this.$container$, this, this.$effects$);
|
|
3125
3252
|
}
|
|
3126
3253
|
}
|
|
@@ -3130,7 +3257,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3130
3257
|
return this.$untrackedValue$;
|
|
3131
3258
|
}
|
|
3132
3259
|
$computeIfNeeded$() {
|
|
3133
|
-
if (!(this.$flags$ & 1 /*
|
|
3260
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
3134
3261
|
return;
|
|
3135
3262
|
}
|
|
3136
3263
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
@@ -3141,10 +3268,10 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3141
3268
|
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
3142
3269
|
// reset flag in case we call computedIfNeeded twice and the value was changed only the first time
|
|
3143
3270
|
// TODO: change to version number?
|
|
3144
|
-
this.$flags$ &= -3 /*
|
|
3271
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3145
3272
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
3146
3273
|
if (didChange) {
|
|
3147
|
-
this.$flags$ |= 2 /*
|
|
3274
|
+
this.$flags$ |= 2 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3148
3275
|
this.$untrackedValue$ = untrackedValue;
|
|
3149
3276
|
}
|
|
3150
3277
|
}
|
|
@@ -3248,12 +3375,15 @@ const isJSXNode = (n) => {
|
|
|
3248
3375
|
* load the QRL captured scope ourselves. Otherwise, we are being called as a QRL and the captures
|
|
3249
3376
|
* are already set.
|
|
3250
3377
|
*/
|
|
3251
|
-
const
|
|
3252
|
-
if (typeof
|
|
3378
|
+
const withScopeFromQL = (captureDeltas, element, callback) => {
|
|
3379
|
+
if (typeof captureDeltas === 'string') {
|
|
3253
3380
|
const container = getDomContainer(element);
|
|
3254
|
-
|
|
3381
|
+
return whenContainerDataReady(container, () => {
|
|
3382
|
+
setCaptures(deserializeCaptureDeltas(container, captureDeltas));
|
|
3383
|
+
return callback();
|
|
3384
|
+
});
|
|
3255
3385
|
}
|
|
3256
|
-
return
|
|
3386
|
+
return callback();
|
|
3257
3387
|
};
|
|
3258
3388
|
/**
|
|
3259
3389
|
* Handles events for bind:value
|
|
@@ -3261,9 +3391,10 @@ const maybeScopeFromQL = (captureIds, element) => {
|
|
|
3261
3391
|
* @internal
|
|
3262
3392
|
*/
|
|
3263
3393
|
function _val(_, element) {
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3394
|
+
return withScopeFromQL(this, element, () => {
|
|
3395
|
+
const signal = _captures[0];
|
|
3396
|
+
signal.value = element.type === 'number' ? element.valueAsNumber : element.value;
|
|
3397
|
+
});
|
|
3267
3398
|
}
|
|
3268
3399
|
/**
|
|
3269
3400
|
* Handles events for bind:checked
|
|
@@ -3271,9 +3402,10 @@ function _val(_, element) {
|
|
|
3271
3402
|
* @internal
|
|
3272
3403
|
*/
|
|
3273
3404
|
function _chk(_, element) {
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3405
|
+
return withScopeFromQL(this, element, () => {
|
|
3406
|
+
const signal = _captures[0];
|
|
3407
|
+
signal.value = element.checked;
|
|
3408
|
+
});
|
|
3277
3409
|
}
|
|
3278
3410
|
/**
|
|
3279
3411
|
* Resumes selected state (e.g. polling AsyncSignals) by deserializing captures. Used for
|
|
@@ -3282,17 +3414,18 @@ function _chk(_, element) {
|
|
|
3282
3414
|
* @internal
|
|
3283
3415
|
*/
|
|
3284
3416
|
function _res(_, element) {
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3417
|
+
return withScopeFromQL(this, element, () => {
|
|
3418
|
+
// Captures are deserialized, now trigger computation on AsyncSignals
|
|
3419
|
+
if (_captures) {
|
|
3420
|
+
for (let i = 0; i < _captures.length; i++) {
|
|
3421
|
+
const capture = _captures[i];
|
|
3422
|
+
if (capture instanceof AsyncSignalImpl && capture.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
3423
|
+
capture.$computeIfNeeded$();
|
|
3424
|
+
}
|
|
3425
|
+
// note that polling async signals will automatically schedule themselves so no action needed
|
|
3292
3426
|
}
|
|
3293
|
-
// note that polling async signals will automatically schedule themselves so no action needed
|
|
3294
3427
|
}
|
|
3295
|
-
}
|
|
3428
|
+
});
|
|
3296
3429
|
}
|
|
3297
3430
|
|
|
3298
3431
|
const BIND_VALUE = 'bind:value';
|
|
@@ -4072,7 +4205,8 @@ function runEventHandlerQRL(handler, event, element, ctx) {
|
|
|
4072
4205
|
return;
|
|
4073
4206
|
}
|
|
4074
4207
|
if (!ctx) {
|
|
4075
|
-
|
|
4208
|
+
const container = getDomContainer(element);
|
|
4209
|
+
return whenContainerDataReady(container, () => runEventHandlerQRL(handler, event, element, newInvokeContextFromDOM(event, element, container)));
|
|
4076
4210
|
}
|
|
4077
4211
|
const container = ctx.$container$;
|
|
4078
4212
|
const hostElement = ctx.$hostElement$;
|
|
@@ -4113,13 +4247,16 @@ function _run(event, element) {
|
|
|
4113
4247
|
// ignore events on disconnected elements, this can happen when the event is triggered while the element is being removed
|
|
4114
4248
|
return;
|
|
4115
4249
|
}
|
|
4116
|
-
const
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4250
|
+
const container = getDomContainer(element);
|
|
4251
|
+
return whenContainerDataReady(container, () => {
|
|
4252
|
+
const ctx = newInvokeContextFromDOM(event, element, container);
|
|
4253
|
+
if (typeof this === 'string') {
|
|
4254
|
+
setCaptures(deserializeCaptureDeltas(ctx.$container$, this));
|
|
4255
|
+
}
|
|
4256
|
+
const qrlToRun = _captures[0];
|
|
4257
|
+
isDev && assertQrl(qrlToRun);
|
|
4258
|
+
return runEventHandlerQRL(qrlToRun, event, element, ctx);
|
|
4259
|
+
});
|
|
4123
4260
|
}
|
|
4124
4261
|
|
|
4125
4262
|
function peekNextSibling(vCurrent) {
|
|
@@ -4280,9 +4417,7 @@ function diff(diffContext, jsxNode, vStartNode, vCurrent = vnode_getFirstChild(v
|
|
|
4280
4417
|
else if (type === Projection) {
|
|
4281
4418
|
expectProjection(diffContext);
|
|
4282
4419
|
descend(diffContext, diffContext.$jsxValue$.children, true,
|
|
4283
|
-
|
|
4284
|
-
// because the projection's children are not removed
|
|
4285
|
-
false);
|
|
4420
|
+
/* isProjection */ true);
|
|
4286
4421
|
}
|
|
4287
4422
|
else if (type === SSRComment) {
|
|
4288
4423
|
expectNoMore(diffContext);
|
|
@@ -4395,9 +4530,11 @@ function advance(diffContext) {
|
|
|
4395
4530
|
*
|
|
4396
4531
|
* In the above example all nodes are on same level so we don't `descendVNode` even thought there is
|
|
4397
4532
|
* an array produced by the `map` function.
|
|
4533
|
+
* @param isProjection - True when descending into a Projection, whose children survive re-renders:
|
|
4534
|
+
* they are diffed against (never re-created) and kept when the new JSX has no children.
|
|
4398
4535
|
*/
|
|
4399
|
-
function descend(diffContext, children, descendVNode,
|
|
4400
|
-
if (
|
|
4536
|
+
function descend(diffContext, children, descendVNode, isProjection = false) {
|
|
4537
|
+
if (!isProjection &&
|
|
4401
4538
|
(children == null || (descendVNode && isArray(children) && children.length === 0))) {
|
|
4402
4539
|
expectNoChildren(diffContext);
|
|
4403
4540
|
return;
|
|
@@ -4406,7 +4543,10 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
4406
4543
|
if (descendVNode) {
|
|
4407
4544
|
isDev &&
|
|
4408
4545
|
assertDefined(diffContext.$vCurrent$ || diffContext.$vNewNode$, 'Expecting vCurrent to be defined.');
|
|
4409
|
-
const creationMode =
|
|
4546
|
+
const creationMode =
|
|
4547
|
+
// a projection keeps its children across re-renders, so it never inherits
|
|
4548
|
+
// creation mode from a not-yet-rendered host; create only if new or empty
|
|
4549
|
+
(!isProjection && diffContext.$isCreationMode$) ||
|
|
4410
4550
|
!!diffContext.$vNewNode$ ||
|
|
4411
4551
|
!vnode_getFirstChild(diffContext.$vCurrent$);
|
|
4412
4552
|
diffContext.$isCreationMode$ = creationMode;
|
|
@@ -4839,18 +4979,20 @@ function diffProps(diffContext, vnode, newAttrs, currentFile) {
|
|
|
4839
4979
|
vnode_ensureElementInflated(diffContext.$container$, vnode);
|
|
4840
4980
|
}
|
|
4841
4981
|
const oldAttrs = vnode.props;
|
|
4982
|
+
const isHtml = (vnode.flags & 1536 /* VNodeFlags.NAMESPACE_MASK */) === 0 /* VNodeFlags.NS_html */;
|
|
4842
4983
|
// Actual diffing logic
|
|
4843
4984
|
// Apply all new attributes
|
|
4844
4985
|
for (const key in newAttrs) {
|
|
4845
4986
|
const newValue = newAttrs[key];
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4987
|
+
// HTML parsers lowercase attribute names.
|
|
4988
|
+
const oldKey = oldAttrs && isHtml && !_hasOwnProperty.call(oldAttrs, key) ? key.toLowerCase() : key;
|
|
4989
|
+
if (oldAttrs && _hasOwnProperty.call(oldAttrs, oldKey)) {
|
|
4990
|
+
const oldValue = oldAttrs[oldKey];
|
|
4991
|
+
if (oldKey !== key) {
|
|
4992
|
+
vnode_setProp(vnode, oldKey, null);
|
|
4993
|
+
vnode_setProp(vnode, key, oldValue);
|
|
4994
|
+
}
|
|
4995
|
+
if (!areDiffValuesEqual(newValue, oldValue)) {
|
|
4854
4996
|
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
4855
4997
|
}
|
|
4856
4998
|
}
|
|
@@ -5320,13 +5462,26 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
5320
5462
|
if (key === 'children' || key === QBackRefs) {
|
|
5321
5463
|
continue;
|
|
5322
5464
|
}
|
|
5323
|
-
|
|
5465
|
+
const newValue = src[key];
|
|
5466
|
+
const oldValue = dst?.[key];
|
|
5467
|
+
if (!dst ||
|
|
5468
|
+
!(areDiffValuesEqual(newValue, oldValue) || areSignalValuesEqual(newValue, oldValue))) {
|
|
5469
|
+
if (key === 'class') {
|
|
5470
|
+
if (areClassValuesEqual(newValue, oldValue)) {
|
|
5471
|
+
continue;
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
else if (key === 'style') {
|
|
5475
|
+
if (areStyleValuesEqual(newValue, oldValue)) {
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5324
5479
|
if (triggerEffects) {
|
|
5325
5480
|
if (dst) {
|
|
5326
5481
|
// Update the value in dst BEFORE triggering effects
|
|
5327
5482
|
// so effects see the new value
|
|
5328
5483
|
// Note: Value is not triggering effects, because we are modyfing direct VAR_PROPS object
|
|
5329
|
-
dst[key] =
|
|
5484
|
+
dst[key] = newValue;
|
|
5330
5485
|
}
|
|
5331
5486
|
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
5332
5487
|
if (!didTigger) {
|
|
@@ -5413,10 +5568,16 @@ function cleanup(container, journal, vNode, cursorRoot = null) {
|
|
|
5413
5568
|
// don't call cleanupDestroyable yet, do it by the scheduler
|
|
5414
5569
|
continue;
|
|
5415
5570
|
}
|
|
5416
|
-
|
|
5417
|
-
|
|
5571
|
+
// Stores and plain signals are only producers; their subscriptions are removed
|
|
5572
|
+
// when cleaning the consumers that read them. They don't own reactive backrefs.
|
|
5573
|
+
else if (obj instanceof ComputedSignalImpl || obj instanceof WrappedSignalImpl) {
|
|
5574
|
+
if (!(obj.$flags$ & 4 /* ComputedSignalFlags.PRESERVE_ON_SEQ_CLEANUP */)) {
|
|
5575
|
+
clearAllEffects(container, obj);
|
|
5576
|
+
}
|
|
5418
5577
|
}
|
|
5419
|
-
if (objIsTask ||
|
|
5578
|
+
if (objIsTask ||
|
|
5579
|
+
(obj instanceof ComputedSignalImpl &&
|
|
5580
|
+
(obj.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */ || obj.$current$))) {
|
|
5420
5581
|
cleanupDestroyable(obj);
|
|
5421
5582
|
}
|
|
5422
5583
|
}
|
|
@@ -5535,6 +5696,37 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
5535
5696
|
*/
|
|
5536
5697
|
vCursor.flags |= 32 /* VNodeFlags.Deleted */;
|
|
5537
5698
|
}
|
|
5699
|
+
function areDiffValuesEqual(newValue, oldValue) {
|
|
5700
|
+
if (newValue === oldValue) {
|
|
5701
|
+
return true;
|
|
5702
|
+
}
|
|
5703
|
+
return (newValue instanceof WrappedSignalImpl &&
|
|
5704
|
+
oldValue instanceof WrappedSignalImpl &&
|
|
5705
|
+
areWrappedSignalsEqual(oldValue, newValue));
|
|
5706
|
+
}
|
|
5707
|
+
function areSignalValuesEqual(newValue, oldValue) {
|
|
5708
|
+
if (newValue === oldValue) {
|
|
5709
|
+
return true;
|
|
5710
|
+
}
|
|
5711
|
+
if (isSignal(newValue) && isSignal(oldValue)) {
|
|
5712
|
+
const unwrappedNew = newValue instanceof WrappedSignalImpl ? newValue.$unwrapIfSignal$() : newValue;
|
|
5713
|
+
const unwrappedOld = oldValue instanceof WrappedSignalImpl ? oldValue.$unwrapIfSignal$() : oldValue;
|
|
5714
|
+
return untrack(() => unwrappedNew.value === unwrappedOld.value);
|
|
5715
|
+
}
|
|
5716
|
+
return false;
|
|
5717
|
+
}
|
|
5718
|
+
function areStyleValuesEqual(newValue, oldValue) {
|
|
5719
|
+
if (newValue === oldValue) {
|
|
5720
|
+
return true;
|
|
5721
|
+
}
|
|
5722
|
+
return stringifyStyle(newValue) === stringifyStyle(oldValue);
|
|
5723
|
+
}
|
|
5724
|
+
function areClassValuesEqual(newValue, oldValue) {
|
|
5725
|
+
if (newValue === oldValue) {
|
|
5726
|
+
return true;
|
|
5727
|
+
}
|
|
5728
|
+
return serializeClass(newValue) === serializeClass(oldValue);
|
|
5729
|
+
}
|
|
5538
5730
|
function areWrappedSignalsEqual(oldSignal, newSignal) {
|
|
5539
5731
|
if (oldSignal === newSignal) {
|
|
5540
5732
|
return true;
|
|
@@ -6222,9 +6414,17 @@ function executeNodeDiff(vNode, container, journal, cursor) {
|
|
|
6222
6414
|
* @returns Promise if component execution is async, void otherwise
|
|
6223
6415
|
*/
|
|
6224
6416
|
function executeComponentChore(vNode, container, journal, cursor) {
|
|
6225
|
-
vNode.dirty &= -5 /* ChoreBits.COMPONENT */;
|
|
6226
6417
|
const host = vNode;
|
|
6227
6418
|
const componentQRL = container.getHostProp(host, OnRenderProp);
|
|
6419
|
+
if (componentQRL && !componentQRL.resolved) {
|
|
6420
|
+
/**
|
|
6421
|
+
* If the component QRL is not resolved, we need to wait for it to resolve before we can execute
|
|
6422
|
+
* it. We just return the promise and we'll be called again, possibly with updated props, which
|
|
6423
|
+
* is why we don't clear the dirty bit yet.
|
|
6424
|
+
*/
|
|
6425
|
+
return componentQRL.resolve();
|
|
6426
|
+
}
|
|
6427
|
+
vNode.dirty &= -5 /* ChoreBits.COMPONENT */;
|
|
6228
6428
|
if (!componentQRL) {
|
|
6229
6429
|
return;
|
|
6230
6430
|
}
|
|
@@ -6375,8 +6575,8 @@ function executeCompute(vNode, container) {
|
|
|
6375
6575
|
ctx.$container$ = container;
|
|
6376
6576
|
// needed for computed signals and throwing QRLs
|
|
6377
6577
|
return maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
|
|
6378
|
-
if (target.$flags$ & 2 /*
|
|
6379
|
-
target.$flags$ &= -3 /*
|
|
6578
|
+
if (target.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
6579
|
+
target.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
6380
6580
|
return scheduleEffects(container, target, effects);
|
|
6381
6581
|
}
|
|
6382
6582
|
});
|
|
@@ -6917,6 +7117,10 @@ function splitCursorBoundary(container, vNode) {
|
|
|
6917
7117
|
* @returns The vNode itself, now acting as a cursor
|
|
6918
7118
|
*/
|
|
6919
7119
|
function addCursor(container, root, priority) {
|
|
7120
|
+
if (isCursor(root)) {
|
|
7121
|
+
triggerCursors();
|
|
7122
|
+
return root;
|
|
7123
|
+
}
|
|
6920
7124
|
const cursorData = {
|
|
6921
7125
|
afterFlushTasks: null,
|
|
6922
7126
|
extraPromises: null,
|
|
@@ -6969,7 +7173,11 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
6969
7173
|
if (ssrNode.dirty & 32 /* ChoreBits.COMPUTE */) {
|
|
6970
7174
|
executeCompute(ssrNode, container);
|
|
6971
7175
|
}
|
|
6972
|
-
if (isDev &&
|
|
7176
|
+
if (isDev &&
|
|
7177
|
+
ssrNode.dirty & 1023 /* ChoreBits.DIRTY_MASK */ &&
|
|
7178
|
+
!(ssrNode.flags & 2 /* SsrNodeFlags.WarnedStreamedChore */)) {
|
|
7179
|
+
// Warn once per host; a re-dirtied streamed host would otherwise spam every tick.
|
|
7180
|
+
ssrNode.flags |= 2 /* SsrNodeFlags.WarnedStreamedChore */;
|
|
6973
7181
|
// We are running on the server.
|
|
6974
7182
|
// On server we can't schedule task for a different host!
|
|
6975
7183
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -8686,8 +8894,17 @@ const processVNodeData$1 = (vData, callback) => {
|
|
|
8686
8894
|
}
|
|
8687
8895
|
return vData.substring(start, nextToConsumeIdx);
|
|
8688
8896
|
};
|
|
8897
|
+
const consumeEncodedValue = () => {
|
|
8898
|
+
if (getChar(nextToConsumeIdx + 1) !== VNodeDataChar.SEPARATOR) {
|
|
8899
|
+
return consumeValue();
|
|
8900
|
+
}
|
|
8901
|
+
consume();
|
|
8902
|
+
const value = decodeURIComponent(decodeVNodeDataString(consumeValue()));
|
|
8903
|
+
consume();
|
|
8904
|
+
return value;
|
|
8905
|
+
};
|
|
8689
8906
|
while (peek() !== 0) {
|
|
8690
|
-
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
|
|
8907
|
+
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx, consumeEncodedValue);
|
|
8691
8908
|
}
|
|
8692
8909
|
};
|
|
8693
8910
|
/** @internal */
|
|
@@ -8878,13 +9095,13 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8878
9095
|
return !nodeIsElement || (nodeIsElement && shouldSkipElement(node));
|
|
8879
9096
|
};
|
|
8880
9097
|
let components = null;
|
|
8881
|
-
processVNodeData$1(vData, (peek, consumeValue, consume, getChar,
|
|
9098
|
+
processVNodeData$1(vData, (peek, consumeValue, consume, getChar, dataIdx, consumeEncodedValue) => {
|
|
8882
9099
|
if (isNumber(peek())) {
|
|
8883
9100
|
// Element counts get encoded as numbers.
|
|
8884
9101
|
while (shouldSkipNode(child)) {
|
|
8885
9102
|
child = fastNextSibling(child);
|
|
8886
9103
|
if (!child) {
|
|
8887
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9104
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8888
9105
|
}
|
|
8889
9106
|
}
|
|
8890
9107
|
combinedText = null;
|
|
@@ -8905,7 +9122,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8905
9122
|
shouldSkipElement(child)) {
|
|
8906
9123
|
child = fastNextSibling(child);
|
|
8907
9124
|
if (!child && value > 0) {
|
|
8908
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9125
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8909
9126
|
}
|
|
8910
9127
|
}
|
|
8911
9128
|
}
|
|
@@ -8930,17 +9147,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8930
9147
|
vnode_setProp(vParent, ELEMENT_PROPS, consumeValue());
|
|
8931
9148
|
}
|
|
8932
9149
|
else if (peek() === VNodeDataChar.KEY) {
|
|
8933
|
-
|
|
8934
|
-
let value;
|
|
8935
|
-
if (isEscapedValue) {
|
|
8936
|
-
consume();
|
|
8937
|
-
value = decodeURIComponent(decodeVNodeDataString(consumeValue()));
|
|
8938
|
-
consume();
|
|
8939
|
-
}
|
|
8940
|
-
else {
|
|
8941
|
-
value = consumeValue();
|
|
8942
|
-
}
|
|
8943
|
-
vParent.key = value;
|
|
9150
|
+
vParent.key = consumeEncodedValue();
|
|
8944
9151
|
}
|
|
8945
9152
|
else if (peek() === VNodeDataChar.SEQ) {
|
|
8946
9153
|
vnode_setProp(vParent, ELEMENT_SEQ, consumeValue());
|
|
@@ -8975,7 +9182,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8975
9182
|
// Custom attribute: |key|value
|
|
8976
9183
|
const keyValue = consumeValue();
|
|
8977
9184
|
const key = decodeVNodeDataString(keyValue);
|
|
8978
|
-
const valueSeparatorIdx =
|
|
9185
|
+
const valueSeparatorIdx = dataIdx + keyValue.length + 1;
|
|
8979
9186
|
const isEscapedValue = getChar(valueSeparatorIdx + 1) === VNodeDataChar.SEPARATOR;
|
|
8980
9187
|
let value;
|
|
8981
9188
|
if (isEscapedValue) {
|
|
@@ -8998,8 +9205,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8998
9205
|
vParent = stack.pop();
|
|
8999
9206
|
}
|
|
9000
9207
|
else if (peek() === VNodeDataChar.SLOT) {
|
|
9001
|
-
|
|
9002
|
-
vnode_setProp(vParent, QSlot, value);
|
|
9208
|
+
vnode_setProp(vParent, QSlot, consumeEncodedValue());
|
|
9003
9209
|
}
|
|
9004
9210
|
else {
|
|
9005
9211
|
// skip over style or non-qwik elements in front of text nodes, where text node is the first child (except the style node)
|
|
@@ -9110,12 +9316,12 @@ function clearEffectSubscription(container, effect) {
|
|
|
9110
9316
|
return;
|
|
9111
9317
|
}
|
|
9112
9318
|
for (const producer of backRefs) {
|
|
9113
|
-
|
|
9114
|
-
if (producer instanceof AsyncSignalImpl) {
|
|
9115
|
-
clearAsyncSignal(producer, effect);
|
|
9116
|
-
}
|
|
9117
|
-
else if (producer instanceof SignalImpl) {
|
|
9319
|
+
if (producer instanceof SignalImpl) {
|
|
9118
9320
|
clearSignal(container, producer, effect);
|
|
9321
|
+
if (producer instanceof ComputedSignalImpl) {
|
|
9322
|
+
// computeds can carry async engine state (loading/error subscribers)
|
|
9323
|
+
clearAsyncSignalEffects(producer, effect);
|
|
9324
|
+
}
|
|
9119
9325
|
}
|
|
9120
9326
|
else if (isPropsProxy(producer)) {
|
|
9121
9327
|
const propsHandler = producer[_PROPS_HANDLER];
|
|
@@ -9140,11 +9346,7 @@ function clearSignal(container, producer, effect) {
|
|
|
9140
9346
|
clearAllEffects(container, producer);
|
|
9141
9347
|
}
|
|
9142
9348
|
}
|
|
9143
|
-
function
|
|
9144
|
-
const effects = producer.$effects$;
|
|
9145
|
-
if (effects && effects.has(effect)) {
|
|
9146
|
-
effects.delete(effect);
|
|
9147
|
-
}
|
|
9349
|
+
function clearAsyncSignalEffects(producer, effect) {
|
|
9148
9350
|
const pendingEffects = producer.$loadingEffects$;
|
|
9149
9351
|
if (pendingEffects && pendingEffects.has(effect)) {
|
|
9150
9352
|
pendingEffects.delete(effect);
|
|
@@ -9180,7 +9382,7 @@ const useTaskQrl = (qrl, opts) => {
|
|
|
9180
9382
|
const taskFlags =
|
|
9181
9383
|
// enabled by default
|
|
9182
9384
|
opts?.deferUpdates === false ? 0 : 8 /* TaskFlags.RENDER_BLOCKING */;
|
|
9183
|
-
const task = new Task(4 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl,
|
|
9385
|
+
const task = new Task(4 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, null);
|
|
9184
9386
|
// In V2 we add the task to the sequential scope. We need to do this
|
|
9185
9387
|
// in order to be able to retrieve it later when the parent element is
|
|
9186
9388
|
// deleted and we need to be able to release the task subscriptions.
|
|
@@ -9233,22 +9435,21 @@ const runTask = (task, container, host) => {
|
|
|
9233
9435
|
}
|
|
9234
9436
|
return result;
|
|
9235
9437
|
};
|
|
9438
|
+
/** @internal */
|
|
9236
9439
|
class Task extends BackRef {
|
|
9237
9440
|
$flags$;
|
|
9238
9441
|
$index$;
|
|
9239
9442
|
$el$;
|
|
9240
9443
|
$qrl$;
|
|
9241
|
-
$state$;
|
|
9242
9444
|
$destroy$;
|
|
9243
9445
|
$destroyPromise$;
|
|
9244
9446
|
$taskPromise$ = null;
|
|
9245
|
-
constructor($flags$, $index$, $el$, $qrl$, $
|
|
9447
|
+
constructor($flags$, $index$, $el$, $qrl$, $destroy$) {
|
|
9246
9448
|
super();
|
|
9247
9449
|
this.$flags$ = $flags$;
|
|
9248
9450
|
this.$index$ = $index$;
|
|
9249
9451
|
this.$el$ = $el$;
|
|
9250
9452
|
this.$qrl$ = $qrl$;
|
|
9251
|
-
this.$state$ = $state$;
|
|
9252
9453
|
this.$destroy$ = $destroy$;
|
|
9253
9454
|
}
|
|
9254
9455
|
}
|
|
@@ -9264,12 +9465,14 @@ const isTask = (value) => {
|
|
|
9264
9465
|
*/
|
|
9265
9466
|
function scheduleTask(_event, element) {
|
|
9266
9467
|
const container = getDomContainer(element);
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9468
|
+
return whenContainerDataReady(container, () => {
|
|
9469
|
+
if (typeof this === 'string') {
|
|
9470
|
+
setCaptures(deserializeCaptureDeltas(container, this));
|
|
9471
|
+
}
|
|
9472
|
+
const task = _captures[0];
|
|
9473
|
+
task.$flags$ |= 4 /* TaskFlags.DIRTY */;
|
|
9474
|
+
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
9475
|
+
});
|
|
9273
9476
|
}
|
|
9274
9477
|
|
|
9275
9478
|
const throwIfQRLNotResolved = (qrl) => {
|
|
@@ -9381,7 +9584,7 @@ const isSerializerObj = (obj) => {
|
|
|
9381
9584
|
return isObject(obj) && typeof obj[SerializerSymbol] === 'function';
|
|
9382
9585
|
};
|
|
9383
9586
|
const getComputedSignalFlags = (serializationStrategy) => {
|
|
9384
|
-
let flags = 1 /*
|
|
9587
|
+
let flags = 1 /* ComputedSignalFlags.INVALID */;
|
|
9385
9588
|
switch (serializationStrategy) {
|
|
9386
9589
|
// TODO: implement this in the future
|
|
9387
9590
|
// case 'auto':
|
|
@@ -9396,6 +9599,18 @@ const getComputedSignalFlags = (serializationStrategy) => {
|
|
|
9396
9599
|
}
|
|
9397
9600
|
return flags;
|
|
9398
9601
|
};
|
|
9602
|
+
/**
|
|
9603
|
+
* Mark this signal as owned outside of the component that read it.
|
|
9604
|
+
*
|
|
9605
|
+
* Externally owned signals are preserved when found in a component's sequential scope during
|
|
9606
|
+
* component cleanup.
|
|
9607
|
+
*
|
|
9608
|
+
* @internal
|
|
9609
|
+
*/
|
|
9610
|
+
const _markSignalAsExternallyOwned = (signal) => {
|
|
9611
|
+
signal.$flags$ |=
|
|
9612
|
+
4 /* ComputedSignalFlags.PRESERVE_ON_SEQ_CLEANUP */;
|
|
9613
|
+
};
|
|
9399
9614
|
|
|
9400
9615
|
const stringifyPath = [];
|
|
9401
9616
|
function qwikDebugToString(value) {
|
|
@@ -9556,6 +9771,7 @@ const unwrapStore = (value) => {
|
|
|
9556
9771
|
const isStore = (value) => {
|
|
9557
9772
|
return STORE_TARGET in value;
|
|
9558
9773
|
};
|
|
9774
|
+
/** @internal */
|
|
9559
9775
|
function createStore(container, obj, flags) {
|
|
9560
9776
|
return new Proxy(obj, new StoreHandler(flags, container || null));
|
|
9561
9777
|
}
|
|
@@ -9754,6 +9970,7 @@ function getEffects(target, prop, storeEffects) {
|
|
|
9754
9970
|
|
|
9755
9971
|
/** Used to represent an undefined value that must be serialized */
|
|
9756
9972
|
const explicitUndefined = Symbol('undefined');
|
|
9973
|
+
const EMPTY_OBJECT_PAYLOAD = 0;
|
|
9757
9974
|
// Used for allocate, make sure they are in sync with Constants
|
|
9758
9975
|
const _constants = [
|
|
9759
9976
|
undefined,
|
|
@@ -9774,6 +9991,10 @@ const _constants = [
|
|
|
9774
9991
|
Number.MAX_SAFE_INTEGER,
|
|
9775
9992
|
Number.MAX_SAFE_INTEGER - 1,
|
|
9776
9993
|
Number.MIN_SAFE_INTEGER,
|
|
9994
|
+
':',
|
|
9995
|
+
'.',
|
|
9996
|
+
'id',
|
|
9997
|
+
'ref',
|
|
9777
9998
|
];
|
|
9778
9999
|
// Used for dumpState, make sure they are in sync with Constants
|
|
9779
10000
|
const _constantNames = [
|
|
@@ -9795,6 +10016,10 @@ const _constantNames = [
|
|
|
9795
10016
|
'MAX_SAFE_INTEGER',
|
|
9796
10017
|
'MAX_SAFE_INTEGER-1',
|
|
9797
10018
|
'MIN_SAFE_INTEGER',
|
|
10019
|
+
"':'",
|
|
10020
|
+
"'.'",
|
|
10021
|
+
"'id'",
|
|
10022
|
+
"'ref'",
|
|
9798
10023
|
];
|
|
9799
10024
|
// Used for dumpState, make sure they are in sync with TypeIds
|
|
9800
10025
|
const _typeIdNames = [
|
|
@@ -9840,6 +10065,9 @@ const _typeIdNames = [
|
|
|
9840
10065
|
'SubscriptionData',
|
|
9841
10066
|
'EffectSubscription',
|
|
9842
10067
|
'SubscriptionPatch',
|
|
10068
|
+
'SubscriptionDataConstTrue',
|
|
10069
|
+
'SubscriptionDataConstFalse',
|
|
10070
|
+
'EffectSubscriptionNoData',
|
|
9843
10071
|
];
|
|
9844
10072
|
|
|
9845
10073
|
function qrlToString(serializationContext, qrl, raw) {
|
|
@@ -9886,17 +10114,25 @@ function qrlToString(serializationContext, qrl, raw) {
|
|
|
9886
10114
|
symbol = String(serializationContext.$addSyncFn$(null, 0, fn));
|
|
9887
10115
|
}
|
|
9888
10116
|
const captures = qrl.getCaptured();
|
|
9889
|
-
let
|
|
10117
|
+
let captureDeltas = null;
|
|
9890
10118
|
if (captures && captures.length > 0) {
|
|
9891
10119
|
// We refer by id so every capture needs to be a root
|
|
9892
|
-
|
|
10120
|
+
let previous = 0;
|
|
10121
|
+
let output = '';
|
|
10122
|
+
for (let i = 0; i < captures.length; i++) {
|
|
10123
|
+
const captureId = serializationContext.$addRoot$(captures[i]);
|
|
10124
|
+
const delta = captureId - previous;
|
|
10125
|
+
previous = captureId;
|
|
10126
|
+
output += (i === 0 ? '' : ' ') + delta;
|
|
10127
|
+
}
|
|
10128
|
+
captureDeltas = output;
|
|
9893
10129
|
}
|
|
9894
10130
|
if (raw) {
|
|
9895
|
-
return [chunk, symbol,
|
|
10131
|
+
return [chunk, symbol, captureDeltas];
|
|
9896
10132
|
}
|
|
9897
10133
|
let qrlStringInline = `${chunk}#${symbol}`;
|
|
9898
|
-
if (
|
|
9899
|
-
qrlStringInline += `#${
|
|
10134
|
+
if (captureDeltas) {
|
|
10135
|
+
qrlStringInline += `#${captureDeltas}`;
|
|
9900
10136
|
}
|
|
9901
10137
|
return qrlStringInline;
|
|
9902
10138
|
}
|
|
@@ -9908,12 +10144,23 @@ function qrlToChunks(serializationContext, qrl) {
|
|
|
9908
10144
|
return prefix;
|
|
9909
10145
|
}
|
|
9910
10146
|
const chunks = [prefix, '#'];
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
10147
|
+
let previousCaptureId = 0;
|
|
10148
|
+
let start = 0;
|
|
10149
|
+
for (let i = 0; i <= captures.length; i++) {
|
|
10150
|
+
if (i === captures.length || captures[i] === ' ') {
|
|
10151
|
+
if (i > start) {
|
|
10152
|
+
const captureId = previousCaptureId + Number(captures.slice(start, i));
|
|
10153
|
+
if (start > 0) {
|
|
10154
|
+
chunks.push(' ');
|
|
10155
|
+
chunks.push({ id: captureId, base: previousCaptureId });
|
|
10156
|
+
}
|
|
10157
|
+
else {
|
|
10158
|
+
chunks.push(captureId);
|
|
10159
|
+
}
|
|
10160
|
+
previousCaptureId = captureId;
|
|
10161
|
+
}
|
|
10162
|
+
start = i + 1;
|
|
9915
10163
|
}
|
|
9916
|
-
chunks.push(Number(captureIds[i]));
|
|
9917
10164
|
}
|
|
9918
10165
|
return chunks;
|
|
9919
10166
|
}
|
|
@@ -9929,10 +10176,14 @@ function createQRLWithBackChannel(chunk, symbol, captures, container) {
|
|
|
9929
10176
|
}
|
|
9930
10177
|
return createQRL(chunk, symbol, null, qrlImporter, captures, container);
|
|
9931
10178
|
}
|
|
9932
|
-
/** Parses "chunk#hash#...
|
|
10179
|
+
/** Parses "chunk#hash#...captureDelta" */
|
|
9933
10180
|
function parseQRL(qrl, container) {
|
|
9934
|
-
const
|
|
9935
|
-
|
|
10181
|
+
const firstHash = qrl.indexOf('#');
|
|
10182
|
+
const secondHash = qrl.indexOf('#', firstHash + 1);
|
|
10183
|
+
const chunk = qrl.slice(0, firstHash);
|
|
10184
|
+
const symbol = secondHash === -1 ? qrl.slice(firstHash + 1) : qrl.slice(firstHash + 1, secondHash);
|
|
10185
|
+
const captures = secondHash !== -1 && secondHash + 1 < qrl.length ? qrl.slice(secondHash + 1) : null;
|
|
10186
|
+
return createQRLWithBackChannel(chunk, symbol, captures, container);
|
|
9936
10187
|
}
|
|
9937
10188
|
const QRL_RUNTIME_CHUNK = 'mock-chunk';
|
|
9938
10189
|
|
|
@@ -10086,6 +10337,36 @@ class Serializer {
|
|
|
10086
10337
|
}
|
|
10087
10338
|
return Number(key);
|
|
10088
10339
|
}
|
|
10340
|
+
rebaseQrlCaptureDeltas$(baseRootId, captureDeltas) {
|
|
10341
|
+
let previousCaptureId = 0;
|
|
10342
|
+
let previousOutputBase = baseRootId;
|
|
10343
|
+
const deltaList = captureDeltas.split(' ');
|
|
10344
|
+
for (let i = 0; i < deltaList.length; i++) {
|
|
10345
|
+
const captureId = previousCaptureId + Number(deltaList[i]);
|
|
10346
|
+
deltaList[i] = String(captureId - previousOutputBase);
|
|
10347
|
+
previousCaptureId = captureId;
|
|
10348
|
+
previousOutputBase = captureId;
|
|
10349
|
+
}
|
|
10350
|
+
return deltaList.join(' ');
|
|
10351
|
+
}
|
|
10352
|
+
outputShortStringConstant$(value) {
|
|
10353
|
+
switch (value) {
|
|
10354
|
+
case ':':
|
|
10355
|
+
this.output(3 /* TypeIds.Constant */, 18 /* Constants.Colon */);
|
|
10356
|
+
return true;
|
|
10357
|
+
case '.':
|
|
10358
|
+
this.output(3 /* TypeIds.Constant */, 19 /* Constants.Dot */);
|
|
10359
|
+
return true;
|
|
10360
|
+
case 'id':
|
|
10361
|
+
this.output(3 /* TypeIds.Constant */, 20 /* Constants.Id */);
|
|
10362
|
+
return true;
|
|
10363
|
+
case 'ref':
|
|
10364
|
+
this.output(3 /* TypeIds.Constant */, 21 /* Constants.Ref */);
|
|
10365
|
+
return true;
|
|
10366
|
+
default:
|
|
10367
|
+
return false;
|
|
10368
|
+
}
|
|
10369
|
+
}
|
|
10089
10370
|
outputString(value) {
|
|
10090
10371
|
const s = this.stringNeedsJsonEscape$(value) ? JSON.stringify(value) : QUOTE + value + QUOTE;
|
|
10091
10372
|
let angleBracketIdx = -1;
|
|
@@ -10103,6 +10384,9 @@ class Serializer {
|
|
|
10103
10384
|
writeRootRefPath(path) {
|
|
10104
10385
|
this.$writer$.writeRootRefPath(path);
|
|
10105
10386
|
}
|
|
10387
|
+
writeRootRefDelta(id, base) {
|
|
10388
|
+
this.$writer$.writeRootRefDelta(id, base);
|
|
10389
|
+
}
|
|
10106
10390
|
outputStringChunks(chunks) {
|
|
10107
10391
|
this.$writer$.write(QUOTE);
|
|
10108
10392
|
for (let i = 0; i < chunks.length; i++) {
|
|
@@ -10113,6 +10397,9 @@ class Serializer {
|
|
|
10113
10397
|
else if (typeof chunk === 'number') {
|
|
10114
10398
|
this.writeRootRef(chunk);
|
|
10115
10399
|
}
|
|
10400
|
+
else if ('base' in chunk) {
|
|
10401
|
+
this.writeRootRefDelta(chunk.id, chunk.base);
|
|
10402
|
+
}
|
|
10116
10403
|
else {
|
|
10117
10404
|
this.writeRootRefPath(chunk.path);
|
|
10118
10405
|
}
|
|
@@ -10242,6 +10529,9 @@ class Serializer {
|
|
|
10242
10529
|
if (value.length === 0) {
|
|
10243
10530
|
this.output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
|
|
10244
10531
|
}
|
|
10532
|
+
else if (this.outputShortStringConstant$(value)) {
|
|
10533
|
+
break;
|
|
10534
|
+
}
|
|
10245
10535
|
else {
|
|
10246
10536
|
// If the string is short, we output directly
|
|
10247
10537
|
// Very short strings add overhead to tracking
|
|
@@ -10268,6 +10558,9 @@ class Serializer {
|
|
|
10268
10558
|
else if (value === explicitUndefined) {
|
|
10269
10559
|
this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
|
|
10270
10560
|
}
|
|
10561
|
+
else {
|
|
10562
|
+
throw qError(20 /* QError.serializeErrorUnknownType */, [typeof value]);
|
|
10563
|
+
}
|
|
10271
10564
|
break;
|
|
10272
10565
|
case 'function':
|
|
10273
10566
|
if (value === Slot) {
|
|
@@ -10278,27 +10571,38 @@ class Serializer {
|
|
|
10278
10571
|
}
|
|
10279
10572
|
else if (isQrl(value)) {
|
|
10280
10573
|
if (this.getSeenRefOrOutput(value, index)) {
|
|
10281
|
-
const [chunk, symbol,
|
|
10574
|
+
const [chunk, symbol, captureDeltasFromZero] = qrlToString(this.$serializationContext$, value, true);
|
|
10282
10575
|
let data;
|
|
10283
10576
|
if (chunk !== '') {
|
|
10284
10577
|
// not a sync QRL, replace all parts with string references
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
this
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10578
|
+
const chunkRootId = this.$serializationContext$.$addRoot$(chunk);
|
|
10579
|
+
const symbolRootId = this.$serializationContext$.$addRoot$(symbol);
|
|
10580
|
+
const captureDeltas = captureDeltasFromZero
|
|
10581
|
+
? this.rebaseQrlCaptureDeltas$(symbolRootId, captureDeltasFromZero)
|
|
10582
|
+
: null;
|
|
10583
|
+
data = [chunkRootId, '#', { id: symbolRootId, base: chunkRootId }];
|
|
10584
|
+
if (captureDeltasFromZero) {
|
|
10585
|
+
let previousRootId = 0;
|
|
10586
|
+
let previousOutputBase = symbolRootId;
|
|
10587
|
+
let start = 0;
|
|
10292
10588
|
data.push('#');
|
|
10293
|
-
for (let i = 0; i
|
|
10294
|
-
if (i
|
|
10295
|
-
|
|
10589
|
+
for (let i = 0; i <= captureDeltasFromZero.length; i++) {
|
|
10590
|
+
if (i === captureDeltasFromZero.length || captureDeltasFromZero[i] === ' ') {
|
|
10591
|
+
if (i > start) {
|
|
10592
|
+
const captureId = previousRootId + Number(captureDeltasFromZero.slice(start, i));
|
|
10593
|
+
if (start > 0) {
|
|
10594
|
+
data.push(' ');
|
|
10595
|
+
}
|
|
10596
|
+
data.push({ id: captureId, base: previousOutputBase });
|
|
10597
|
+
previousRootId = captureId;
|
|
10598
|
+
previousOutputBase = captureId;
|
|
10599
|
+
}
|
|
10600
|
+
start = i + 1;
|
|
10296
10601
|
}
|
|
10297
|
-
data.push(Number(captureIds[i]));
|
|
10298
10602
|
}
|
|
10299
10603
|
}
|
|
10300
10604
|
// Since we map QRLs to strings, we need to keep track of this secondary mapping
|
|
10301
|
-
const qrlKey =
|
|
10605
|
+
const qrlKey = `${chunkRootId}#${symbolRootId - chunkRootId}${captureDeltas ? '#' + captureDeltas : ''}`;
|
|
10302
10606
|
const existing = this.$qrlMap$.get(qrlKey);
|
|
10303
10607
|
if (existing) {
|
|
10304
10608
|
// We encountered the same QRL again, make it a root
|
|
@@ -10366,15 +10670,21 @@ class Serializer {
|
|
|
10366
10670
|
]);
|
|
10367
10671
|
}
|
|
10368
10672
|
else if (value instanceof SubscriptionData) {
|
|
10369
|
-
|
|
10370
|
-
|
|
10371
|
-
|
|
10372
|
-
|
|
10373
|
-
|
|
10673
|
+
const { $scopedStyleIdPrefix$, $isConst$ } = value.data;
|
|
10674
|
+
if ($scopedStyleIdPrefix$ === null) {
|
|
10675
|
+
this.output($isConst$ ? 42 /* TypeIds.SubscriptionDataConstTrue */ : 43 /* TypeIds.SubscriptionDataConstFalse */, 0);
|
|
10676
|
+
}
|
|
10677
|
+
else {
|
|
10678
|
+
this.output(39 /* TypeIds.SubscriptionData */, [$scopedStyleIdPrefix$, $isConst$]);
|
|
10679
|
+
}
|
|
10374
10680
|
}
|
|
10375
10681
|
else if (value instanceof EffectSubscription) {
|
|
10376
|
-
|
|
10377
|
-
|
|
10682
|
+
if (value.data === null) {
|
|
10683
|
+
this.output(44 /* TypeIds.EffectSubscriptionNoData */, [value.consumer, value.property]);
|
|
10684
|
+
}
|
|
10685
|
+
else {
|
|
10686
|
+
this.output(40 /* TypeIds.EffectSubscription */, [value.consumer, value.property, value.data]);
|
|
10687
|
+
}
|
|
10378
10688
|
}
|
|
10379
10689
|
else if (value instanceof SubscriptionPatch) {
|
|
10380
10690
|
this.output(41 /* TypeIds.SubscriptionPatch */, [value.rootId, value.subscriptions]);
|
|
@@ -10428,7 +10738,7 @@ class Serializer {
|
|
|
10428
10738
|
}
|
|
10429
10739
|
}
|
|
10430
10740
|
}
|
|
10431
|
-
this.output(5 /* TypeIds.Object */, out.length ? out :
|
|
10741
|
+
this.output(5 /* TypeIds.Object */, out.length ? out : EMPTY_OBJECT_PAYLOAD);
|
|
10432
10742
|
}
|
|
10433
10743
|
}
|
|
10434
10744
|
else if (this.$serializationContext$.$isDomRef$(value)) {
|
|
@@ -10461,16 +10771,18 @@ class Serializer {
|
|
|
10461
10771
|
let v = value.$untrackedValue$;
|
|
10462
10772
|
const shouldAlwaysSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
10463
10773
|
const shouldNeverSerialize = value.$flags$ & 8 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
10464
|
-
const isInvalid = value.$flags$ & 1 /*
|
|
10774
|
+
const isInvalid = value.$flags$ & 1 /* ComputedSignalFlags.INVALID */;
|
|
10465
10775
|
const isSkippable = fastSkipSerialize(value.$untrackedValue$);
|
|
10466
|
-
|
|
10776
|
+
// async-mode computeds carry the same engine state and must round-trip like AsyncSignals
|
|
10777
|
+
const isAsync = !!(value.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */);
|
|
10778
|
+
const isErrored = isAsync && !!value.$untrackedError$;
|
|
10467
10779
|
const expires = isAsync && value.$expires$ !== 0 ? value.$expires$ : undefined;
|
|
10468
10780
|
const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
|
|
10469
10781
|
const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
|
|
10470
10782
|
// Send the flags but remove the serialization bits and default to 0 when undefined
|
|
10471
10783
|
const asyncFlags = (isAsync && value.$flags$ & -25 /* SerializationSignalFlags.SERIALIZATION_ALL_STRATEGIES */) ||
|
|
10472
10784
|
undefined;
|
|
10473
|
-
if (isInvalid || isSkippable) {
|
|
10785
|
+
if (isInvalid || isSkippable || isErrored) {
|
|
10474
10786
|
v = NEEDS_COMPUTATION;
|
|
10475
10787
|
}
|
|
10476
10788
|
else if (shouldAlwaysSerialize) {
|
|
@@ -10518,30 +10830,6 @@ class Serializer {
|
|
|
10518
10830
|
else if (value instanceof Date) {
|
|
10519
10831
|
this.output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
|
|
10520
10832
|
}
|
|
10521
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
|
|
10522
|
-
this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
|
|
10523
|
-
}
|
|
10524
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
|
|
10525
|
-
this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
|
|
10526
|
-
}
|
|
10527
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
|
|
10528
|
-
this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
|
|
10529
|
-
}
|
|
10530
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
|
|
10531
|
-
this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
|
|
10532
|
-
}
|
|
10533
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
|
|
10534
|
-
this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
|
|
10535
|
-
}
|
|
10536
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
|
|
10537
|
-
this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
|
|
10538
|
-
}
|
|
10539
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
|
|
10540
|
-
this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
|
|
10541
|
-
}
|
|
10542
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
|
|
10543
|
-
this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
|
|
10544
|
-
}
|
|
10545
10833
|
else if (value instanceof RegExp) {
|
|
10546
10834
|
this.output(8 /* TypeIds.Regex */, value.toString());
|
|
10547
10835
|
}
|
|
@@ -10614,7 +10902,7 @@ class Serializer {
|
|
|
10614
10902
|
this.output(37 /* TypeIds.JSXNode */, out);
|
|
10615
10903
|
}
|
|
10616
10904
|
else if (value instanceof Task) {
|
|
10617
|
-
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el
|
|
10905
|
+
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el$];
|
|
10618
10906
|
while (out[out.length - 1] === undefined) {
|
|
10619
10907
|
out.pop();
|
|
10620
10908
|
}
|
|
@@ -10668,6 +10956,30 @@ class Serializer {
|
|
|
10668
10956
|
this.output(2 /* TypeIds.ForwardRef */, this.getForwardRefId(forwardRefId));
|
|
10669
10957
|
}
|
|
10670
10958
|
}
|
|
10959
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
|
|
10960
|
+
this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
|
|
10961
|
+
}
|
|
10962
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
|
|
10963
|
+
this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
|
|
10964
|
+
}
|
|
10965
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
|
|
10966
|
+
this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
|
|
10967
|
+
}
|
|
10968
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
|
|
10969
|
+
this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
|
|
10970
|
+
}
|
|
10971
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
|
|
10972
|
+
this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
|
|
10973
|
+
}
|
|
10974
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
|
|
10975
|
+
this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
|
|
10976
|
+
}
|
|
10977
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
|
|
10978
|
+
this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
|
|
10979
|
+
}
|
|
10980
|
+
else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
|
|
10981
|
+
this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
|
|
10982
|
+
}
|
|
10671
10983
|
else if (vnode_isVNode(value)) {
|
|
10672
10984
|
this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
|
|
10673
10985
|
}
|
|
@@ -10834,7 +11146,9 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10834
11146
|
if (attrValue == null ||
|
|
10835
11147
|
typeof attrValue === 'string' ||
|
|
10836
11148
|
(typeof attrValue === 'number' && key === ELEMENT_ID) ||
|
|
10837
|
-
(key === ELEMENT_PROPS &&
|
|
11149
|
+
(key === ELEMENT_PROPS &&
|
|
11150
|
+
(isObjectEmpty(attrValue) ||
|
|
11151
|
+
shouldSkipComponentProps(value, attrValue)))) {
|
|
10838
11152
|
continue;
|
|
10839
11153
|
}
|
|
10840
11154
|
callback(attrValue);
|
|
@@ -10843,6 +11157,21 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10843
11157
|
}
|
|
10844
11158
|
};
|
|
10845
11159
|
const isSsrAttrs = (value) => typeof value === 'object' && value !== null && !isObjectEmpty(value);
|
|
11160
|
+
const shouldSkipComponentProps = (attrs, value, isDevMode = isDev) => {
|
|
11161
|
+
if (isDevMode || !Object.prototype.hasOwnProperty.call(attrs, OnRenderProp)) {
|
|
11162
|
+
return false;
|
|
11163
|
+
}
|
|
11164
|
+
const owner = value[_OWNER];
|
|
11165
|
+
return (isObjectEmpty(owner.varProps) &&
|
|
11166
|
+
!hasPropsEffects(value) &&
|
|
11167
|
+
!hasComponentBackRef(attrs[QBackRefs]));
|
|
11168
|
+
};
|
|
11169
|
+
const hasPropsEffects = (propsProxy) => {
|
|
11170
|
+
return !!propsProxy[_PROPS_HANDLER].$effects$?.size;
|
|
11171
|
+
};
|
|
11172
|
+
const hasComponentBackRef = (backRefs) => {
|
|
11173
|
+
return backRefs instanceof Map && backRefs.has(":" /* EffectProperty.COMPONENT */);
|
|
11174
|
+
};
|
|
10846
11175
|
/**
|
|
10847
11176
|
* When serializing the object we need check if it is URL, RegExp, Map, Set, etc. This is time
|
|
10848
11177
|
* consuming. So if we could know that this is a basic object literal we could skip the check, and
|
|
@@ -11341,6 +11670,12 @@ const constantToName = (code) => {
|
|
|
11341
11670
|
* @internal
|
|
11342
11671
|
*/
|
|
11343
11672
|
function preprocessState(data, container, segmentId, startIndex = 0) {
|
|
11673
|
+
const iterator = preprocessStateIterator(data, container, startIndex);
|
|
11674
|
+
while (!iterator.next().done) {
|
|
11675
|
+
// Run synchronously for non-browser and non-container deserialization paths.
|
|
11676
|
+
}
|
|
11677
|
+
}
|
|
11678
|
+
function* preprocessStateIterator(data, container, startIndex = 0) {
|
|
11344
11679
|
const isRootDeepRef = (type, value) => {
|
|
11345
11680
|
return type === 1 /* TypeIds.RootRef */ && typeof value === 'string' && value.indexOf(' ') !== -1;
|
|
11346
11681
|
};
|
|
@@ -11383,11 +11718,39 @@ function preprocessState(data, container, segmentId, startIndex = 0) {
|
|
|
11383
11718
|
else if (isForwardRefsMap(data[i])) {
|
|
11384
11719
|
container.$forwardRefs$ = data[i + 1];
|
|
11385
11720
|
}
|
|
11721
|
+
yield;
|
|
11386
11722
|
}
|
|
11387
11723
|
}
|
|
11388
11724
|
|
|
11389
11725
|
const resolvers = new WeakMap();
|
|
11390
|
-
const
|
|
11726
|
+
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
11727
|
+
const BASE64_REGEXP = /^[A-Za-z0-9+/]*$/;
|
|
11728
|
+
// Validate canonical unpadded base64 before its length controls allocation.
|
|
11729
|
+
const isCanonicalBase64 = (value) => {
|
|
11730
|
+
if (typeof value !== 'string' || !BASE64_REGEXP.test(value)) {
|
|
11731
|
+
return false;
|
|
11732
|
+
}
|
|
11733
|
+
const rest = value.length % 4;
|
|
11734
|
+
if (rest === 0) {
|
|
11735
|
+
return true;
|
|
11736
|
+
}
|
|
11737
|
+
if (rest === 1) {
|
|
11738
|
+
return false;
|
|
11739
|
+
}
|
|
11740
|
+
const lastValue = BASE64_ALPHABET.indexOf(value[value.length - 1]);
|
|
11741
|
+
return (lastValue & (rest === 2 ? 15 : 3)) === 0;
|
|
11742
|
+
};
|
|
11743
|
+
const beginDeserialization = (container) => {
|
|
11744
|
+
const ownsPendingStoreTargets = container.$pendingStoreTargets$ === undefined;
|
|
11745
|
+
container.$pendingStoreTargets$ ??= new Map();
|
|
11746
|
+
return ownsPendingStoreTargets;
|
|
11747
|
+
};
|
|
11748
|
+
const endDeserialization = (container, ownsPendingStoreTargets) => {
|
|
11749
|
+
if (ownsPendingStoreTargets) {
|
|
11750
|
+
container.$pendingStoreTargets$.clear();
|
|
11751
|
+
container.$pendingStoreTargets$ = undefined;
|
|
11752
|
+
}
|
|
11753
|
+
};
|
|
11391
11754
|
const allocate = (container, typeId, value) => {
|
|
11392
11755
|
switch (typeId) {
|
|
11393
11756
|
case 0 /* TypeIds.Plain */:
|
|
@@ -11413,10 +11776,17 @@ const allocate = (container, typeId, value) => {
|
|
|
11413
11776
|
case 9 /* TypeIds.QRL */: {
|
|
11414
11777
|
let qrl;
|
|
11415
11778
|
if (typeof value === 'string') {
|
|
11416
|
-
const
|
|
11417
|
-
const
|
|
11418
|
-
const
|
|
11419
|
-
|
|
11779
|
+
const serializedQrl = value;
|
|
11780
|
+
const firstHash = serializedQrl.indexOf('#');
|
|
11781
|
+
const secondHash = serializedQrl.indexOf('#', firstHash + 1);
|
|
11782
|
+
const chunkRootId = Number(serializedQrl.slice(0, firstHash));
|
|
11783
|
+
const symbolDelta = secondHash === -1
|
|
11784
|
+
? Number(serializedQrl.slice(firstHash + 1))
|
|
11785
|
+
: Number(serializedQrl.slice(firstHash + 1, secondHash));
|
|
11786
|
+
const symbolRootId = chunkRootId + symbolDelta;
|
|
11787
|
+
const chunk = container.$getObjectById$(chunkRootId);
|
|
11788
|
+
const symbol = container.$getObjectById$(symbolRootId);
|
|
11789
|
+
qrl = createQRLWithBackChannel(chunk, symbol, secondHash !== -1 ? serializedQrl : null, container);
|
|
11420
11790
|
}
|
|
11421
11791
|
else {
|
|
11422
11792
|
// Sync qrl
|
|
@@ -11425,7 +11795,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11425
11795
|
return qrl;
|
|
11426
11796
|
}
|
|
11427
11797
|
case 28 /* TypeIds.Task */:
|
|
11428
|
-
return new Task(-1, -1, null, null, null
|
|
11798
|
+
return new Task(-1, -1, null, null, null);
|
|
11429
11799
|
case 6 /* TypeIds.URL */:
|
|
11430
11800
|
return new URL(value);
|
|
11431
11801
|
case 7 /* TypeIds.Date */:
|
|
@@ -11473,7 +11843,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11473
11843
|
const storeValue = allocate(container, t, v);
|
|
11474
11844
|
const store = getOrCreateStore(storeValue, 0 /* StoreFlags.NONE */, container);
|
|
11475
11845
|
if (needsInflation(t)) {
|
|
11476
|
-
pendingStoreTargets
|
|
11846
|
+
container.$pendingStoreTargets$.set(storeValue, { t, v });
|
|
11477
11847
|
}
|
|
11478
11848
|
// We must store the reference so it doesn't get deserialized again in inflate()
|
|
11479
11849
|
data[0] = 0 /* TypeIds.Plain */;
|
|
@@ -11503,12 +11873,16 @@ const allocate = (container, typeId, value) => {
|
|
|
11503
11873
|
// Don't leave unhandled promise rejections
|
|
11504
11874
|
promise.catch(() => { });
|
|
11505
11875
|
return promise;
|
|
11506
|
-
case 27 /* TypeIds.Uint8Array */:
|
|
11876
|
+
case 27 /* TypeIds.Uint8Array */: {
|
|
11877
|
+
if (!isCanonicalBase64(value)) {
|
|
11878
|
+
throw qError(38 /* QError.invalidUint8ArrayPayload */);
|
|
11879
|
+
}
|
|
11507
11880
|
const encodedLength = value.length;
|
|
11508
|
-
const blocks = encodedLength
|
|
11509
|
-
const rest = encodedLength
|
|
11881
|
+
const blocks = Math.floor(encodedLength / 4);
|
|
11882
|
+
const rest = encodedLength % 4;
|
|
11510
11883
|
const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
|
|
11511
11884
|
return new Uint8Array(decodedLength);
|
|
11885
|
+
}
|
|
11512
11886
|
case 38 /* TypeIds.PropsProxy */:
|
|
11513
11887
|
return createPropsProxy(null);
|
|
11514
11888
|
case 10 /* TypeIds.VNode */:
|
|
@@ -11549,7 +11923,12 @@ const allocate = (container, typeId, value) => {
|
|
|
11549
11923
|
}
|
|
11550
11924
|
case 39 /* TypeIds.SubscriptionData */:
|
|
11551
11925
|
return new SubscriptionData({});
|
|
11926
|
+
case 42 /* TypeIds.SubscriptionDataConstTrue */:
|
|
11927
|
+
return new SubscriptionData({ $scopedStyleIdPrefix$: null, $isConst$: true });
|
|
11928
|
+
case 43 /* TypeIds.SubscriptionDataConstFalse */:
|
|
11929
|
+
return new SubscriptionData({ $scopedStyleIdPrefix$: null, $isConst$: false });
|
|
11552
11930
|
case 40 /* TypeIds.EffectSubscription */:
|
|
11931
|
+
case 44 /* TypeIds.EffectSubscriptionNoData */:
|
|
11553
11932
|
return new EffectSubscription(null, null, null, null);
|
|
11554
11933
|
case 41 /* TypeIds.SubscriptionPatch */:
|
|
11555
11934
|
return new SubscriptionPatch();
|
|
@@ -11985,6 +12364,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11985
12364
|
if (isPromise(jsxOutput)) {
|
|
11986
12365
|
// Defer reading QScopedStyle until after the promise resolves
|
|
11987
12366
|
enqueue(async () => {
|
|
12367
|
+
await ssr.streamHandler.flush();
|
|
11988
12368
|
const resolvedOutput = await jsxOutput;
|
|
11989
12369
|
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
11990
12370
|
enqueue(resolvedOutput);
|
|
@@ -12016,7 +12396,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
12016
12396
|
function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
|
|
12017
12397
|
// Unwrap if it's a WrappedSignalImpl
|
|
12018
12398
|
const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
|
|
12019
|
-
if (unwrappedSignal instanceof
|
|
12399
|
+
if (unwrappedSignal instanceof ComputedSignalImpl) {
|
|
12020
12400
|
const expires = unwrappedSignal.$expires$;
|
|
12021
12401
|
// Don't check for $effects$ here - effects are added later during tracking.
|
|
12022
12402
|
// The AsyncSignal's polling mechanism will check for effects before scheduling.
|
|
@@ -12199,7 +12579,7 @@ function setEvent(serializationCtx, key, rawValue, hasMovedCaptures) {
|
|
|
12199
12579
|
*
|
|
12200
12580
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
12201
12581
|
*/
|
|
12202
|
-
if (!qrl.$symbol$.startsWith('_') && (qrl.$captures
|
|
12582
|
+
if (!qrl.$symbol$.startsWith('_') && (Array.isArray(qrl.$captures$) || hasMovedCaptures)) {
|
|
12203
12583
|
qrl = createQRL(null, '_run', _run, null, [qrl]);
|
|
12204
12584
|
}
|
|
12205
12585
|
return qrlToChunks(serializationCtx, qrl);
|
|
@@ -12411,20 +12791,26 @@ const useOnEventsSequentialScope = () => {
|
|
|
12411
12791
|
* @internal
|
|
12412
12792
|
*/
|
|
12413
12793
|
const _hmr = function (event, element) {
|
|
12414
|
-
if (!event.detail.files.some((file) => element.getAttribute('data-qwik-inspector')?.startsWith(file))) {
|
|
12415
|
-
return;
|
|
12416
|
-
}
|
|
12417
12794
|
// Deserialize captures from `this` when called via qwikloader/attribute dispatch
|
|
12418
|
-
if (typeof this === 'string') {
|
|
12419
|
-
const container = getDomContainer(element);
|
|
12420
|
-
setCaptures(deserializeCaptures(container, this));
|
|
12421
|
-
}
|
|
12422
|
-
const host = _captures[0];
|
|
12423
12795
|
const container = getDomContainer(element);
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12796
|
+
return whenContainerDataReady(container, () => {
|
|
12797
|
+
if (typeof this === 'string') {
|
|
12798
|
+
setCaptures(deserializeCaptureDeltas(container, this));
|
|
12799
|
+
}
|
|
12800
|
+
const devPath = _captures?.[1];
|
|
12801
|
+
const hmrPath = devPath ?? element.getAttribute('data-qwik-inspector');
|
|
12802
|
+
if (!hmrPath || !event.detail.files.some((file) => hmrPath.startsWith(file))) {
|
|
12803
|
+
return;
|
|
12804
|
+
}
|
|
12805
|
+
const host = _captures?.[0];
|
|
12806
|
+
if (!host || host.flags & 32 /* VNodeFlags.Deleted */) {
|
|
12807
|
+
return;
|
|
12808
|
+
}
|
|
12809
|
+
markVNodeDirty(container, host, 4 /* ChoreBits.COMPONENT */);
|
|
12810
|
+
// Mark HMR as handled
|
|
12811
|
+
const doc = element.ownerDocument;
|
|
12812
|
+
doc.__hmrDone = doc.__hmrT;
|
|
12813
|
+
});
|
|
12428
12814
|
};
|
|
12429
12815
|
let hmrQrl;
|
|
12430
12816
|
/**
|
|
@@ -12441,7 +12827,7 @@ function _useHmr(devPath) {
|
|
|
12441
12827
|
hmrQrl ||= inlinedQrl(_hmr, '_hmr');
|
|
12442
12828
|
const hostElement = iCtx.$hostElement$;
|
|
12443
12829
|
// We must capture the vnode to be able to re-render
|
|
12444
|
-
const qrl = hmrQrl.w([hostElement]);
|
|
12830
|
+
const qrl = hmrQrl.w([hostElement, devPath]);
|
|
12445
12831
|
useOnDocument('qHmr', qrl);
|
|
12446
12832
|
}
|
|
12447
12833
|
|
|
@@ -12529,22 +12915,93 @@ const isSafeObjectKV = (key, value) => {
|
|
|
12529
12915
|
(typeof value !== 'function' || !dangerousObjectKeys.has(key)));
|
|
12530
12916
|
};
|
|
12531
12917
|
const inflate = (container, target, typeId, data) => {
|
|
12918
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
12919
|
+
try {
|
|
12920
|
+
const iterator = inflateIterator(container, target, typeId, data);
|
|
12921
|
+
while (!iterator.next().done) {
|
|
12922
|
+
// Run synchronously for lazy deserialization paths.
|
|
12923
|
+
}
|
|
12924
|
+
}
|
|
12925
|
+
finally {
|
|
12926
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12927
|
+
}
|
|
12928
|
+
};
|
|
12929
|
+
function* eagerDeserializeArrayIterator(container, data, output = Array(data.length / 2)) {
|
|
12930
|
+
for (let i = 0; i < data.length; i += 2) {
|
|
12931
|
+
output[i / 2] = yield* deserializeDataIterator(container, data[i], data[i + 1]);
|
|
12932
|
+
yield;
|
|
12933
|
+
}
|
|
12934
|
+
return output;
|
|
12935
|
+
}
|
|
12936
|
+
function* eagerDeserializeStateIterator(container, data, output = Array(data.length / 2)) {
|
|
12937
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
12938
|
+
const length = data.length / 2;
|
|
12939
|
+
const allocated = new Uint8Array(length);
|
|
12940
|
+
const previousGetObjectById = container.$getObjectById$;
|
|
12941
|
+
const allocateRoot = (index) => {
|
|
12942
|
+
if (!allocated[index]) {
|
|
12943
|
+
allocated[index] = 1;
|
|
12944
|
+
const typeIndex = index * 2;
|
|
12945
|
+
const typeId = data[typeIndex];
|
|
12946
|
+
const value = data[typeIndex + 1];
|
|
12947
|
+
output[index] = typeId === 0 /* TypeIds.Plain */ ? value : allocate(container, typeId, value);
|
|
12948
|
+
}
|
|
12949
|
+
return output[index];
|
|
12950
|
+
};
|
|
12951
|
+
container.$getObjectById$ = (id) => allocateRoot(typeof id === 'string' ? parseInt(id, 10) : id);
|
|
12952
|
+
try {
|
|
12953
|
+
for (let i = 0; i < length; i++) {
|
|
12954
|
+
allocateRoot(i);
|
|
12955
|
+
yield;
|
|
12956
|
+
}
|
|
12957
|
+
for (let i = 0; i < length; i++) {
|
|
12958
|
+
const typeIndex = i * 2;
|
|
12959
|
+
const typeId = data[typeIndex];
|
|
12960
|
+
const value = data[typeIndex + 1];
|
|
12961
|
+
const propValue = output[i];
|
|
12962
|
+
data[typeIndex] = 0 /* TypeIds.Plain */;
|
|
12963
|
+
data[typeIndex + 1] = propValue;
|
|
12964
|
+
if (needsInflation(typeId)) {
|
|
12965
|
+
yield* inflateIterator(container, propValue, typeId, value);
|
|
12966
|
+
}
|
|
12967
|
+
yield;
|
|
12968
|
+
}
|
|
12969
|
+
}
|
|
12970
|
+
finally {
|
|
12971
|
+
container.$getObjectById$ = previousGetObjectById;
|
|
12972
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12973
|
+
}
|
|
12974
|
+
return output;
|
|
12975
|
+
}
|
|
12976
|
+
function* deserializeDataIterator(container, typeId, value) {
|
|
12977
|
+
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12978
|
+
return value;
|
|
12979
|
+
}
|
|
12980
|
+
const propValue = allocate(container, typeId, value);
|
|
12981
|
+
if (needsInflation(typeId)) {
|
|
12982
|
+
yield* inflateIterator(container, propValue, typeId, value);
|
|
12983
|
+
}
|
|
12984
|
+
return propValue;
|
|
12985
|
+
}
|
|
12986
|
+
function* inflateIterator(container, target, typeId, data) {
|
|
12532
12987
|
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12533
12988
|
// Already processed
|
|
12534
12989
|
return;
|
|
12535
12990
|
}
|
|
12991
|
+
if (typeId === 5 /* TypeIds.Object */ && data !== EMPTY_OBJECT_PAYLOAD && !Array.isArray(data)) {
|
|
12992
|
+
throw new Error('Invalid Object payload');
|
|
12993
|
+
}
|
|
12536
12994
|
// Restore the complex data, special case for Array
|
|
12537
12995
|
if (typeId !== 4 /* TypeIds.Array */ && Array.isArray(data)) {
|
|
12538
|
-
data =
|
|
12996
|
+
data = yield* eagerDeserializeArrayIterator(container, data);
|
|
12539
12997
|
}
|
|
12540
12998
|
switch (typeId) {
|
|
12541
12999
|
case 4 /* TypeIds.Array */:
|
|
12542
13000
|
// Arrays are special, we need to fill the array in place
|
|
12543
|
-
|
|
13001
|
+
yield* eagerDeserializeArrayIterator(container, data, target);
|
|
12544
13002
|
break;
|
|
12545
13003
|
case 5 /* TypeIds.Object */:
|
|
12546
|
-
if (data ===
|
|
12547
|
-
// Special case, was an empty object
|
|
13004
|
+
if (data === EMPTY_OBJECT_PAYLOAD) {
|
|
12548
13005
|
break;
|
|
12549
13006
|
}
|
|
12550
13007
|
for (let i = 0; i < data.length; i += 2) {
|
|
@@ -12556,37 +13013,65 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12556
13013
|
target[key] = value;
|
|
12557
13014
|
}
|
|
12558
13015
|
break;
|
|
12559
|
-
case
|
|
13016
|
+
case 25 /* TypeIds.Set */: {
|
|
13017
|
+
const set = target;
|
|
13018
|
+
const d = data;
|
|
13019
|
+
for (let i = 0; i < d.length; i++) {
|
|
13020
|
+
set.add(d[i]);
|
|
13021
|
+
yield;
|
|
13022
|
+
}
|
|
13023
|
+
break;
|
|
13024
|
+
}
|
|
13025
|
+
case 26 /* TypeIds.Map */: {
|
|
13026
|
+
const map = target;
|
|
13027
|
+
const d = data;
|
|
13028
|
+
for (let i = 0; i < d.length; i++) {
|
|
13029
|
+
map.set(d[i++], d[i]);
|
|
13030
|
+
yield;
|
|
13031
|
+
}
|
|
13032
|
+
break;
|
|
13033
|
+
}
|
|
13034
|
+
case 24 /* TypeIds.Promise */: {
|
|
13035
|
+
const promise = target;
|
|
13036
|
+
const [resolved, result] = data;
|
|
13037
|
+
const [resolve, reject] = resolvers.get(promise);
|
|
13038
|
+
if (resolved) {
|
|
13039
|
+
// Native Promises cannot fulfill with another Promise.
|
|
13040
|
+
if (resolvers.has(result)) {
|
|
13041
|
+
throw qError(37 /* QError.invalidPromiseDependency */);
|
|
13042
|
+
}
|
|
13043
|
+
resolve(result);
|
|
13044
|
+
}
|
|
13045
|
+
else {
|
|
13046
|
+
reject(result);
|
|
13047
|
+
}
|
|
13048
|
+
break;
|
|
13049
|
+
}
|
|
13050
|
+
case 23 /* TypeIds.Error */: {
|
|
13051
|
+
const d = data;
|
|
13052
|
+
target.message = d[0];
|
|
13053
|
+
for (let i = 1; i < d.length; i += 2) {
|
|
13054
|
+
const key = d[i];
|
|
13055
|
+
const value = d[i + 1];
|
|
13056
|
+
if (isSafeObjectKV(key, value)) {
|
|
13057
|
+
target[key] = value;
|
|
13058
|
+
}
|
|
13059
|
+
yield;
|
|
13060
|
+
}
|
|
13061
|
+
break;
|
|
13062
|
+
}
|
|
13063
|
+
case 28 /* TypeIds.Task */: {
|
|
12560
13064
|
const task = target;
|
|
12561
13065
|
const v = data;
|
|
12562
13066
|
task.$qrl$ = v[0];
|
|
12563
13067
|
task.$flags$ = v[1];
|
|
12564
13068
|
task.$index$ = v[2];
|
|
12565
13069
|
task.$el$ = v[3];
|
|
12566
|
-
task.$state$ = v[4];
|
|
12567
13070
|
break;
|
|
13071
|
+
}
|
|
12568
13072
|
case 29 /* TypeIds.Component */:
|
|
12569
13073
|
target[SERIALIZABLE_STATE][0] = data[0];
|
|
12570
13074
|
break;
|
|
12571
|
-
case 35 /* TypeIds.Store */: {
|
|
12572
|
-
// Inflate the store target
|
|
12573
|
-
const store = unwrapStore(target);
|
|
12574
|
-
const storeTarget = pendingStoreTargets.get(store);
|
|
12575
|
-
if (storeTarget) {
|
|
12576
|
-
pendingStoreTargets.delete(store);
|
|
12577
|
-
inflate(container, store, storeTarget.t, storeTarget.v);
|
|
12578
|
-
}
|
|
12579
|
-
/**
|
|
12580
|
-
* Note that we don't do anything with the innerstores we added during serialization, because
|
|
12581
|
-
* they are already inflated in the deserialize of the data, above.
|
|
12582
|
-
*/
|
|
12583
|
-
const [, flags, effects] = data;
|
|
12584
|
-
const storeHandler = getStoreHandler(target);
|
|
12585
|
-
storeHandler.$flags$ = flags;
|
|
12586
|
-
storeHandler.$effects$ = effects;
|
|
12587
|
-
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
12588
|
-
break;
|
|
12589
|
-
}
|
|
12590
13075
|
case 30 /* TypeIds.Signal */: {
|
|
12591
13076
|
const signal = target;
|
|
12592
13077
|
const d = data;
|
|
@@ -12602,7 +13087,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12602
13087
|
signal.$args$ = d[1];
|
|
12603
13088
|
signal.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
12604
13089
|
signal.$flags$ = d[2];
|
|
12605
|
-
signal.$flags$ |= 1 /*
|
|
13090
|
+
signal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12606
13091
|
signal.$hostElement$ = d[3];
|
|
12607
13092
|
signal.$effects$ = new Set(d.slice(4));
|
|
12608
13093
|
inflateWrappedSignalValue(signal);
|
|
@@ -12628,7 +13113,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12628
13113
|
asyncSignal.$flags$ = d[5] ?? 0;
|
|
12629
13114
|
if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
12630
13115
|
// If it's client only, it was serialized because it pretended to be loading
|
|
12631
|
-
asyncSignal.$
|
|
13116
|
+
asyncSignal.$untrackedPending$ = true;
|
|
12632
13117
|
}
|
|
12633
13118
|
const hasValue = d.length > 6;
|
|
12634
13119
|
if (hasValue) {
|
|
@@ -12636,7 +13121,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12636
13121
|
}
|
|
12637
13122
|
// can happen when never serialize etc
|
|
12638
13123
|
if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
12639
|
-
asyncSignal.$flags$ |= 1 /*
|
|
13124
|
+
asyncSignal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12640
13125
|
}
|
|
12641
13126
|
// Handle old format (negative = no poll) and new format (always positive, flag in d[5])
|
|
12642
13127
|
const rawExpires = (d[7] ?? 0);
|
|
@@ -12676,84 +13161,44 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12676
13161
|
if (hasValue) {
|
|
12677
13162
|
computed.$untrackedValue$ = d[2];
|
|
12678
13163
|
}
|
|
12679
|
-
if (typeId !== 34 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
12680
|
-
// If we have a value after SSR, it will always be mean the signal was not invalid
|
|
12681
|
-
// The serialized signal is always left invalid so it can recreate the custom object
|
|
12682
|
-
computed.$flags$ &= -2 /*
|
|
12683
|
-
}
|
|
12684
|
-
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
12685
|
-
break;
|
|
12686
|
-
}
|
|
12687
|
-
case 23 /* TypeIds.Error */: {
|
|
12688
|
-
const d = data;
|
|
12689
|
-
target.message = d[0];
|
|
12690
|
-
for (let i = 1; i < d.length; i += 2) {
|
|
12691
|
-
target[d[i]] = d[i + 1];
|
|
12692
|
-
}
|
|
12693
|
-
break;
|
|
12694
|
-
}
|
|
12695
|
-
case 36 /* TypeIds.FormData */: {
|
|
12696
|
-
const formData = target;
|
|
12697
|
-
const d = data;
|
|
12698
|
-
for (let i = 0; i < d.length; i++) {
|
|
12699
|
-
formData.append(d[i++], d[i]);
|
|
12700
|
-
}
|
|
12701
|
-
break;
|
|
12702
|
-
}
|
|
12703
|
-
case 37 /* TypeIds.JSXNode */: {
|
|
12704
|
-
const jsx = target;
|
|
12705
|
-
const [type, key, varProps, constProps, children, toSort] = data;
|
|
12706
|
-
jsx.type = type;
|
|
12707
|
-
jsx.key = key;
|
|
12708
|
-
jsx.varProps = varProps;
|
|
12709
|
-
jsx.constProps = constProps || null;
|
|
12710
|
-
jsx.children = children;
|
|
12711
|
-
jsx.toSort = !!toSort;
|
|
12712
|
-
break;
|
|
12713
|
-
}
|
|
12714
|
-
case 25 /* TypeIds.Set */: {
|
|
12715
|
-
const set = target;
|
|
12716
|
-
const d = data;
|
|
12717
|
-
for (let i = 0; i < d.length; i++) {
|
|
12718
|
-
set.add(d[i]);
|
|
12719
|
-
}
|
|
12720
|
-
break;
|
|
12721
|
-
}
|
|
12722
|
-
case 26 /* TypeIds.Map */: {
|
|
12723
|
-
const map = target;
|
|
12724
|
-
const d = data;
|
|
12725
|
-
for (let i = 0; i < d.length; i++) {
|
|
12726
|
-
map.set(d[i++], d[i]);
|
|
12727
|
-
}
|
|
12728
|
-
break;
|
|
12729
|
-
}
|
|
12730
|
-
case 24 /* TypeIds.Promise */: {
|
|
12731
|
-
const promise = target;
|
|
12732
|
-
const [resolved, result] = data;
|
|
12733
|
-
const [resolve, reject] = resolvers.get(promise);
|
|
12734
|
-
if (resolved) {
|
|
12735
|
-
resolve(result);
|
|
12736
|
-
}
|
|
12737
|
-
else {
|
|
12738
|
-
reject(result);
|
|
12739
|
-
}
|
|
13164
|
+
if (typeId !== 34 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
13165
|
+
// If we have a value after SSR, it will always be mean the signal was not invalid
|
|
13166
|
+
// The serialized signal is always left invalid so it can recreate the custom object
|
|
13167
|
+
computed.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
13168
|
+
}
|
|
13169
|
+
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
12740
13170
|
break;
|
|
12741
13171
|
}
|
|
12742
|
-
case
|
|
12743
|
-
const
|
|
12744
|
-
const
|
|
12745
|
-
let i = 0;
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
bytes[i++] = s.charCodeAt(0);
|
|
13172
|
+
case 36 /* TypeIds.FormData */: {
|
|
13173
|
+
const formData = target;
|
|
13174
|
+
const d = data;
|
|
13175
|
+
for (let i = 0; i < d.length; i++) {
|
|
13176
|
+
formData.append(d[i++], d[i]);
|
|
13177
|
+
yield;
|
|
12749
13178
|
}
|
|
12750
13179
|
break;
|
|
12751
|
-
|
|
13180
|
+
}
|
|
13181
|
+
case 37 /* TypeIds.JSXNode */: {
|
|
13182
|
+
const jsx = target;
|
|
13183
|
+
const [type, key, varProps, constProps, children, toSort] = data;
|
|
13184
|
+
jsx.type = type;
|
|
13185
|
+
jsx.key = key;
|
|
13186
|
+
jsx.varProps = varProps;
|
|
13187
|
+
jsx.constProps = constProps || null;
|
|
13188
|
+
jsx.children = children;
|
|
13189
|
+
jsx.toSort = !!toSort;
|
|
13190
|
+
break;
|
|
13191
|
+
}
|
|
13192
|
+
case 38 /* TypeIds.PropsProxy */: {
|
|
12752
13193
|
const propsProxy = target;
|
|
12753
13194
|
const d = data;
|
|
12754
13195
|
let owner = d[0];
|
|
12755
13196
|
if (owner === _UNINITIALIZED) {
|
|
12756
|
-
owner = new JSXNodeImpl(Fragment,
|
|
13197
|
+
owner = new JSXNodeImpl(Fragment, null, null, null, 0, null);
|
|
13198
|
+
// Important: var/const props can be eager-deserialization placeholders. (empty objects)
|
|
13199
|
+
// Do not let JSXNodeImpl constructor normalize {} to EMPTY_OBJ/null.
|
|
13200
|
+
owner.varProps = d[1];
|
|
13201
|
+
owner.constProps = d[2];
|
|
12757
13202
|
owner._proxy = propsProxy;
|
|
12758
13203
|
}
|
|
12759
13204
|
propsProxy[_OWNER] = owner;
|
|
@@ -12761,12 +13206,16 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12761
13206
|
propsHandler.$effects$ = d[3];
|
|
12762
13207
|
restoreEffectBackRefForEffectsMap(propsHandler.$effects$, propsProxy);
|
|
12763
13208
|
break;
|
|
13209
|
+
}
|
|
12764
13210
|
case 39 /* TypeIds.SubscriptionData */: {
|
|
12765
13211
|
const effectData = target;
|
|
12766
13212
|
effectData.data.$scopedStyleIdPrefix$ = data[0];
|
|
12767
13213
|
effectData.data.$isConst$ = data[1];
|
|
12768
13214
|
break;
|
|
12769
13215
|
}
|
|
13216
|
+
case 42 /* TypeIds.SubscriptionDataConstTrue */:
|
|
13217
|
+
case 43 /* TypeIds.SubscriptionDataConstFalse */:
|
|
13218
|
+
break;
|
|
12770
13219
|
case 40 /* TypeIds.EffectSubscription */: {
|
|
12771
13220
|
const effectSub = target;
|
|
12772
13221
|
const d = data;
|
|
@@ -12783,29 +13232,43 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12783
13232
|
patch.subscriptions = d[1];
|
|
12784
13233
|
break;
|
|
12785
13234
|
}
|
|
13235
|
+
case 44 /* TypeIds.EffectSubscriptionNoData */: {
|
|
13236
|
+
const effectSub = target;
|
|
13237
|
+
const d = data;
|
|
13238
|
+
effectSub.consumer = d[0];
|
|
13239
|
+
effectSub.property = d[1];
|
|
13240
|
+
effectSub.data = null;
|
|
13241
|
+
restoreEffectBackRefForConsumer(effectSub);
|
|
13242
|
+
break;
|
|
13243
|
+
}
|
|
13244
|
+
case 27 /* TypeIds.Uint8Array */: {
|
|
13245
|
+
const bytes = target;
|
|
13246
|
+
const buf = atob(data);
|
|
13247
|
+
for (let j = 0; j < buf.length; j++) {
|
|
13248
|
+
bytes[j] = buf.charCodeAt(j);
|
|
13249
|
+
if ((j & 31) === 31) {
|
|
13250
|
+
yield;
|
|
13251
|
+
}
|
|
13252
|
+
}
|
|
13253
|
+
break;
|
|
13254
|
+
}
|
|
13255
|
+
case 35 /* TypeIds.Store */: {
|
|
13256
|
+
const store = unwrapStore(target);
|
|
13257
|
+
const storeTarget = container.$pendingStoreTargets$.get(store);
|
|
13258
|
+
if (storeTarget) {
|
|
13259
|
+
container.$pendingStoreTargets$.delete(store);
|
|
13260
|
+
yield* inflateIterator(container, store, storeTarget.t, storeTarget.v);
|
|
13261
|
+
}
|
|
13262
|
+
const [, flags, effects] = data;
|
|
13263
|
+
const storeHandler = getStoreHandler(target);
|
|
13264
|
+
storeHandler.$flags$ = flags;
|
|
13265
|
+
storeHandler.$effects$ = effects;
|
|
13266
|
+
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
13267
|
+
break;
|
|
13268
|
+
}
|
|
12786
13269
|
default:
|
|
12787
13270
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
12788
13271
|
}
|
|
12789
|
-
};
|
|
12790
|
-
/**
|
|
12791
|
-
* Restores an array eagerly. If you need it lazily, use `deserializeData(container, TypeIds.Array,
|
|
12792
|
-
* array)` instead
|
|
12793
|
-
*/
|
|
12794
|
-
const _eagerDeserializeArray = (container, data, output = Array(data.length / 2)) => {
|
|
12795
|
-
for (let i = 0; i < data.length; i += 2) {
|
|
12796
|
-
output[i / 2] = deserializeData(container, data[i], data[i + 1]);
|
|
12797
|
-
}
|
|
12798
|
-
return output;
|
|
12799
|
-
};
|
|
12800
|
-
function deserializeData(container, typeId, value) {
|
|
12801
|
-
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12802
|
-
return value;
|
|
12803
|
-
}
|
|
12804
|
-
const propValue = allocate(container, typeId, value);
|
|
12805
|
-
if (needsInflation(typeId)) {
|
|
12806
|
-
inflate(container, propValue, typeId, value);
|
|
12807
|
-
}
|
|
12808
|
-
return propValue;
|
|
12809
13272
|
}
|
|
12810
13273
|
function inflateWrappedSignalValue(signal) {
|
|
12811
13274
|
if (signal.$hostElement$ !== null && vnode_isVNode(signal.$hostElement$)) {
|
|
@@ -12916,15 +13379,21 @@ class DeserializationHandler {
|
|
|
12916
13379
|
return value;
|
|
12917
13380
|
}
|
|
12918
13381
|
const container = this.$container$;
|
|
12919
|
-
const
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
13382
|
+
const ownsPendingStoreTargets = beginDeserialization(container);
|
|
13383
|
+
try {
|
|
13384
|
+
const propValue = allocate(container, typeId, value);
|
|
13385
|
+
Reflect.set(target, property, propValue);
|
|
13386
|
+
this.$data$[idx] = 0 /* TypeIds.Plain */;
|
|
13387
|
+
this.$data$[idx + 1] = propValue;
|
|
13388
|
+
/** We stored the reference, so now we can inflate, allowing cycles */
|
|
13389
|
+
if (needsInflation(typeId)) {
|
|
13390
|
+
inflate(container, propValue, typeId, value);
|
|
13391
|
+
}
|
|
13392
|
+
return propValue;
|
|
13393
|
+
}
|
|
13394
|
+
finally {
|
|
13395
|
+
endDeserialization(container, ownsPendingStoreTargets);
|
|
12926
13396
|
}
|
|
12927
|
-
return propValue;
|
|
12928
13397
|
}
|
|
12929
13398
|
has(target, property) {
|
|
12930
13399
|
if (property === SERIALIZER_PROXY_UNWRAP) {
|
|
@@ -12948,6 +13417,54 @@ class DeserializationHandler {
|
|
|
12948
13417
|
}
|
|
12949
13418
|
}
|
|
12950
13419
|
|
|
13420
|
+
const YIELD_INTERVAL = 10;
|
|
13421
|
+
const scheduleYieldingIterator = (state) => {
|
|
13422
|
+
if (!state.$scheduled$) {
|
|
13423
|
+
state.$scheduled$ = true;
|
|
13424
|
+
state.$schedule$();
|
|
13425
|
+
}
|
|
13426
|
+
};
|
|
13427
|
+
const runYieldingIterator = (state, onDone, onError) => {
|
|
13428
|
+
state.$scheduled$ = false;
|
|
13429
|
+
const deadline = performance.now() + YIELD_INTERVAL;
|
|
13430
|
+
let count = 0;
|
|
13431
|
+
try {
|
|
13432
|
+
while (true) {
|
|
13433
|
+
const result = state.$iterator$.next();
|
|
13434
|
+
if (result.done) {
|
|
13435
|
+
onDone(result.value);
|
|
13436
|
+
return;
|
|
13437
|
+
}
|
|
13438
|
+
// Sampling the clock every 32 steps keeps `performance.now()` out of the hottest path.
|
|
13439
|
+
if ((++count & 31) === 0 && performance.now() >= deadline) {
|
|
13440
|
+
scheduleYieldingIterator(state);
|
|
13441
|
+
return;
|
|
13442
|
+
}
|
|
13443
|
+
}
|
|
13444
|
+
}
|
|
13445
|
+
catch (error) {
|
|
13446
|
+
onError(error);
|
|
13447
|
+
}
|
|
13448
|
+
};
|
|
13449
|
+
const createYieldingIteratorState = (iterator, onDone, onError) => {
|
|
13450
|
+
const state = {
|
|
13451
|
+
$iterator$: iterator,
|
|
13452
|
+
$schedule$: undefined,
|
|
13453
|
+
$scheduled$: false,
|
|
13454
|
+
};
|
|
13455
|
+
const schedule = createMacroTask(() => {
|
|
13456
|
+
runYieldingIterator(state, (value) => {
|
|
13457
|
+
schedule.$destroy$?.();
|
|
13458
|
+
onDone(value);
|
|
13459
|
+
}, (error) => {
|
|
13460
|
+
schedule.$destroy$?.();
|
|
13461
|
+
onError(error);
|
|
13462
|
+
});
|
|
13463
|
+
});
|
|
13464
|
+
state.$schedule$ = schedule;
|
|
13465
|
+
return state;
|
|
13466
|
+
};
|
|
13467
|
+
|
|
12951
13468
|
/**
|
|
12952
13469
|
* Serialize data to string using SerializationContext.
|
|
12953
13470
|
*
|
|
@@ -12960,12 +13477,12 @@ async function _serialize(data) {
|
|
|
12960
13477
|
return serializationContext.$writer$.toString();
|
|
12961
13478
|
}
|
|
12962
13479
|
/**
|
|
12963
|
-
* Deserialize data from string
|
|
13480
|
+
* Deserialize data from string.
|
|
12964
13481
|
*
|
|
12965
13482
|
* @param rawStateData - Data to deserialize
|
|
12966
13483
|
* @internal
|
|
12967
13484
|
*/
|
|
12968
|
-
function _deserialize(rawStateData) {
|
|
13485
|
+
async function _deserialize(rawStateData) {
|
|
12969
13486
|
if (rawStateData == null) {
|
|
12970
13487
|
throw new Error('No state data to deserialize');
|
|
12971
13488
|
}
|
|
@@ -12973,9 +13490,18 @@ function _deserialize(rawStateData) {
|
|
|
12973
13490
|
if (!Array.isArray(stateData) || stateData.length < 2 || typeof stateData[0] !== 'number') {
|
|
12974
13491
|
throw new Error('Invalid state data');
|
|
12975
13492
|
}
|
|
12976
|
-
const
|
|
12977
|
-
|
|
13493
|
+
const state = Array(stateData.length / 2);
|
|
13494
|
+
const container = createBaseDeserializeContainer(stateData, () => state);
|
|
13495
|
+
container.$state$ = state;
|
|
13496
|
+
await runDeserializeIterator(eagerDeserializeStateIterator(container, stateData, state));
|
|
13497
|
+
return state[0];
|
|
12978
13498
|
}
|
|
13499
|
+
const runDeserializeIterator = (iterator) => {
|
|
13500
|
+
return new Promise((resolve, reject) => {
|
|
13501
|
+
const state = createYieldingIteratorState(iterator, resolve, reject);
|
|
13502
|
+
scheduleYieldingIterator(state);
|
|
13503
|
+
});
|
|
13504
|
+
};
|
|
12979
13505
|
function getObjectById(id, stateData) {
|
|
12980
13506
|
if (typeof id === 'string') {
|
|
12981
13507
|
id = parseInt(id, 10);
|
|
@@ -12989,8 +13515,14 @@ function getObjectById(id, stateData) {
|
|
|
12989
13515
|
function _createDeserializeContainer(stateData) {
|
|
12990
13516
|
// eslint-disable-next-line prefer-const
|
|
12991
13517
|
let state;
|
|
13518
|
+
const container = createBaseDeserializeContainer(stateData, () => state);
|
|
13519
|
+
state = wrapDeserializerProxy(container, stateData);
|
|
13520
|
+
container.$state$ = state;
|
|
13521
|
+
return container;
|
|
13522
|
+
}
|
|
13523
|
+
function createBaseDeserializeContainer(stateData, getState) {
|
|
12992
13524
|
const container = {
|
|
12993
|
-
$getObjectById$: (id) => getObjectById(id,
|
|
13525
|
+
$getObjectById$: (id) => getObjectById(id, getState()),
|
|
12994
13526
|
$getForwardRef$: (id) => container.$forwardRefs$?.[Number(id)],
|
|
12995
13527
|
getSyncFn: (_) => {
|
|
12996
13528
|
const fn = () => { };
|
|
@@ -13001,8 +13533,6 @@ function _createDeserializeContainer(stateData) {
|
|
|
13001
13533
|
$forwardRefs$: null,
|
|
13002
13534
|
};
|
|
13003
13535
|
preprocessState(stateData, container);
|
|
13004
|
-
state = wrapDeserializerProxy(container, stateData);
|
|
13005
|
-
container.$state$ = state;
|
|
13006
13536
|
return container;
|
|
13007
13537
|
}
|
|
13008
13538
|
|
|
@@ -13554,13 +14084,12 @@ const mergeSubscriptionSet = (container, producer, backRef, rootEffects, patchEf
|
|
|
13554
14084
|
};
|
|
13555
14085
|
|
|
13556
14086
|
const processedStatePatchScripts = new WeakMap();
|
|
13557
|
-
|
|
13558
|
-
const processSegmentStateScripts = (container, segmentId) => {
|
|
14087
|
+
function* processSegmentStateScriptsIterator(container, segmentId) {
|
|
13559
14088
|
if (!__EXPERIMENTAL__.suspense) {
|
|
13560
14089
|
return;
|
|
13561
14090
|
}
|
|
13562
14091
|
const stateContainer = container;
|
|
13563
|
-
const qwikStates = stateContainer.element.querySelectorAll(
|
|
14092
|
+
const qwikStates = stateContainer.element.querySelectorAll(`script[type="qwik/state"][q\\:instance="${stateContainer.$instanceHash$}"]${QStatePatchAttrSelector}`);
|
|
13564
14093
|
const processedScripts = getProcessedStatePatchScripts(container);
|
|
13565
14094
|
for (let i = 0; i < qwikStates.length; i++) {
|
|
13566
14095
|
const stateScript = qwikStates[i];
|
|
@@ -13571,9 +14100,10 @@ const processSegmentStateScripts = (container, segmentId) => {
|
|
|
13571
14100
|
continue;
|
|
13572
14101
|
}
|
|
13573
14102
|
processedScripts.add(stateScript);
|
|
13574
|
-
processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14103
|
+
yield* processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14104
|
+
yield;
|
|
13575
14105
|
}
|
|
13576
|
-
}
|
|
14106
|
+
}
|
|
13577
14107
|
const getProcessedStatePatchScripts = (container) => {
|
|
13578
14108
|
let processedScripts = processedStatePatchScripts.get(container);
|
|
13579
14109
|
if (!processedScripts) {
|
|
@@ -13582,20 +14112,18 @@ const getProcessedStatePatchScripts = (container) => {
|
|
|
13582
14112
|
}
|
|
13583
14113
|
return processedScripts;
|
|
13584
14114
|
};
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
const processStatePatch = (container, stateContainer, textContent) => {
|
|
13589
|
-
if (textContent) {
|
|
13590
|
-
const [rootStart, rawStateData, forwardRefs, subscriptionPatchRootId] = JSON.parse(textContent);
|
|
13591
|
-
appendStatePatchRoots(container, stateContainer, rootStart, rawStateData);
|
|
13592
|
-
mergeForwardRefs(stateContainer, forwardRefs || undefined);
|
|
13593
|
-
applySubscriptionPatches(container, subscriptionPatchRootId === undefined
|
|
13594
|
-
? undefined
|
|
13595
|
-
: stateContainer.$getObjectById$(subscriptionPatchRootId));
|
|
14115
|
+
function* processStatePatch(container, stateContainer, textContent) {
|
|
14116
|
+
if (!textContent) {
|
|
14117
|
+
return;
|
|
13596
14118
|
}
|
|
13597
|
-
|
|
13598
|
-
|
|
14119
|
+
const [rootStart, rawStateData, forwardRefs, subscriptionPatchRootId] = JSON.parse(textContent);
|
|
14120
|
+
yield* appendStatePatchRoots(container, stateContainer, rootStart, rawStateData);
|
|
14121
|
+
mergeForwardRefs(stateContainer, forwardRefs || undefined);
|
|
14122
|
+
applySubscriptionPatches(container, subscriptionPatchRootId === undefined
|
|
14123
|
+
? undefined
|
|
14124
|
+
: stateContainer.$getObjectById$(subscriptionPatchRootId));
|
|
14125
|
+
}
|
|
14126
|
+
function* appendStatePatchRoots(container, stateContainer, rootStart, rawStateData) {
|
|
13599
14127
|
const currentRootCount = stateContainer.$rawStateData$.length / 2;
|
|
13600
14128
|
if (rootStart !== currentRootCount) {
|
|
13601
14129
|
if (qDev) {
|
|
@@ -13605,12 +14133,13 @@ const appendStatePatchRoots = (container, stateContainer, rootStart, rawStateDat
|
|
|
13605
14133
|
}
|
|
13606
14134
|
for (let i = 0; i < rawStateData.length; i++) {
|
|
13607
14135
|
stateContainer.$rawStateData$[rootStart * 2 + i] = rawStateData[i];
|
|
14136
|
+
yield;
|
|
13608
14137
|
}
|
|
13609
|
-
|
|
14138
|
+
yield* preprocessStateIterator(stateContainer.$rawStateData$, container, rootStart * 2);
|
|
13610
14139
|
stateContainer.$stateData$ = wrapDeserializerProxy(container, stateContainer.$rawStateData$);
|
|
13611
14140
|
stateContainer.$stateData$.length = stateContainer.$rawStateData$.length / 2;
|
|
13612
14141
|
stateContainer.$rootForwardRefs$ = stateContainer.$forwardRefs$;
|
|
13613
|
-
}
|
|
14142
|
+
}
|
|
13614
14143
|
const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
13615
14144
|
if (!forwardRefs) {
|
|
13616
14145
|
return;
|
|
@@ -13625,24 +14154,172 @@ const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
|
13625
14154
|
stateContainer.$forwardRefs$ = rootForwardRefs;
|
|
13626
14155
|
};
|
|
13627
14156
|
|
|
13628
|
-
|
|
14157
|
+
const Q_SUSPENSE_RESOLVED = 'q:r';
|
|
14158
|
+
const Q_PATCH = 'q:patch';
|
|
14159
|
+
/**
|
|
14160
|
+
* Process the VNodeData script tags and store the VNodeData in the VNodeDataMap.
|
|
14161
|
+
*
|
|
14162
|
+
* The end result of this function is that each DOM element has the associated `VNodeData` attached
|
|
14163
|
+
* to it, to be used later `VNode` materialization. The "attachment" is done through the
|
|
14164
|
+
* `VNodeDataMap`.
|
|
14165
|
+
*
|
|
14166
|
+
* Run this function on startup to process the `<script type="qwik/vnode">` tags. The data in the
|
|
14167
|
+
* tags needs to be parsed and attached to the DOM elements. (We do this through `VNodeDataMap`)
|
|
14168
|
+
* `VNodeDataMap` is then used to lazily materialize the VNodes.
|
|
14169
|
+
*
|
|
14170
|
+
* Only one invocation of this function is needed per document/browser session.
|
|
14171
|
+
*
|
|
14172
|
+
* Below is an example of the kinds of constructs which need to be handled when dealing with
|
|
14173
|
+
* VNodeData deserialization.
|
|
14174
|
+
*
|
|
14175
|
+
* ```
|
|
14176
|
+
* <html q:container="paused">
|
|
14177
|
+
* <body>
|
|
14178
|
+
* <div q:container="paused">
|
|
14179
|
+
* <script type="qwik/vnode">...</script>
|
|
14180
|
+
* </div>
|
|
14181
|
+
* <div q:container="html">...</div>
|
|
14182
|
+
* before
|
|
14183
|
+
* <!--q:container=ABC-->
|
|
14184
|
+
* ...
|
|
14185
|
+
* <!--/q:container-->
|
|
14186
|
+
* after
|
|
14187
|
+
* <!--q:ignore=FOO-->
|
|
14188
|
+
* ...
|
|
14189
|
+
* <!--q:container-island=BAR-->
|
|
14190
|
+
* <div>some interactive island</div>
|
|
14191
|
+
* <!--/q:container-island-->
|
|
14192
|
+
* ...
|
|
14193
|
+
* <!--/q:ignore-->
|
|
14194
|
+
* <textarea q:container="text">...</textarea>
|
|
14195
|
+
* <script type="qwik/vnode">...</script>
|
|
14196
|
+
* </body>
|
|
14197
|
+
* </html>
|
|
14198
|
+
* ```
|
|
14199
|
+
*
|
|
14200
|
+
* Each `qwik/vnode` script assumes that the elements are numbered in depth first order. For this
|
|
14201
|
+
* reason, whenever the `processVNodeData` comes across a `q:container` it must ignore its
|
|
14202
|
+
* children.
|
|
14203
|
+
*
|
|
14204
|
+
* IMPLEMENTATION:
|
|
14205
|
+
*
|
|
14206
|
+
* - Stack to keep track of the current `q:container` being processed.
|
|
14207
|
+
* - Attach all `qwik/vnode` scripts (not the data contain within them) to the `q:container` element.
|
|
14208
|
+
* - Walk the tree and process each `q:container` element.
|
|
14209
|
+
*/
|
|
14210
|
+
function processVNodeData(document, containerElement) {
|
|
14211
|
+
const qDocument = document;
|
|
14212
|
+
// Per-container gate: a walk already populated this container's refs → done.
|
|
14213
|
+
if (containerElement?.qVNodeRefs) {
|
|
14214
|
+
return;
|
|
14215
|
+
}
|
|
14216
|
+
// A document-wide walk is in flight; it will pick up this newly-added container too.
|
|
14217
|
+
if (qDocument.qVNodeDataStarted && !qDocument.qVNodeDataProcessed) {
|
|
14218
|
+
return;
|
|
14219
|
+
}
|
|
14220
|
+
qDocument.qVNodeDataStarted = true;
|
|
14221
|
+
qDocument.qVNodeData ||= new WeakMap();
|
|
14222
|
+
enqueueProcessVNodeDataJob(qDocument, processRootVNodeData(document));
|
|
14223
|
+
}
|
|
13629
14224
|
function processOutOfOrderSegmentVNodeData(document, segmentId, contentNode) {
|
|
13630
14225
|
if (!__EXPERIMENTAL__.suspense || !contentNode) {
|
|
13631
14226
|
return;
|
|
13632
14227
|
}
|
|
13633
14228
|
const qContainerElement = contentNode.closest('[q\\:container]');
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
14229
|
+
if (!qContainerElement) {
|
|
14230
|
+
return;
|
|
14231
|
+
}
|
|
14232
|
+
const script = qContainerElement.querySelector(`script[type="qwik/vnode"][q\\:r="${segmentId}"]:not([q\\:patch])`);
|
|
14233
|
+
const patches = qContainerElement.querySelectorAll(`script[type="qwik/vnode"][q\\:r="${segmentId}"][q\\:patch]`);
|
|
14234
|
+
enqueueProcessVNodeDataJob(document, processOutOfOrderSegmentVNodeDataIterator(document, segmentId, qContainerElement, contentNode, script?.textContent || undefined, patches));
|
|
14235
|
+
}
|
|
14236
|
+
const onVNodeDataReady = (document, callback) => {
|
|
14237
|
+
const qDocument = document;
|
|
14238
|
+
if (qDocument.qVNodeDataReady) {
|
|
14239
|
+
callback();
|
|
14240
|
+
}
|
|
14241
|
+
else {
|
|
14242
|
+
(qDocument.qVNodeDataCallbacks ||= []).push(callback);
|
|
14243
|
+
}
|
|
14244
|
+
};
|
|
14245
|
+
function enqueueProcessVNodeDataJob(qDocument, iterator) {
|
|
14246
|
+
const state = (qDocument.qVNodeDataState ||= {
|
|
14247
|
+
$queue$: [],
|
|
14248
|
+
$active$: null,
|
|
14249
|
+
});
|
|
14250
|
+
qDocument.qProcessVNodeDataPatch ||= (script) => enqueueProcessVNodeDataJob(qDocument, processVNodeDataPatch(qDocument, script));
|
|
14251
|
+
qDocument.qVNodeDataReady = false;
|
|
14252
|
+
state.$queue$.push(iterator);
|
|
14253
|
+
scheduleProcessVNodeData(qDocument, state);
|
|
14254
|
+
}
|
|
14255
|
+
function scheduleProcessVNodeData(qDocument, state) {
|
|
14256
|
+
if (state.$active$) {
|
|
14257
|
+
return;
|
|
14258
|
+
}
|
|
14259
|
+
const iterator = state.$queue$.shift();
|
|
14260
|
+
if (!iterator) {
|
|
14261
|
+
markVNodeDataReady(qDocument);
|
|
14262
|
+
return;
|
|
14263
|
+
}
|
|
14264
|
+
state.$active$ = createYieldingIteratorState(runProcessVNodeData(qDocument, state, iterator), () => {
|
|
14265
|
+
if (qDocument.qVNodeDataState === state) {
|
|
14266
|
+
state.$active$ = null;
|
|
14267
|
+
scheduleProcessVNodeData(qDocument, state);
|
|
14268
|
+
}
|
|
14269
|
+
}, (error) => {
|
|
14270
|
+
state.$active$ = null;
|
|
14271
|
+
logError(error);
|
|
14272
|
+
markVNodeDataReady(qDocument);
|
|
14273
|
+
});
|
|
14274
|
+
scheduleYieldingIterator(state.$active$);
|
|
14275
|
+
}
|
|
14276
|
+
function* runProcessVNodeData(qDocument, state, iterator) {
|
|
14277
|
+
while (qDocument.qVNodeDataState === state) {
|
|
14278
|
+
if (iterator.next().done) {
|
|
14279
|
+
return;
|
|
14280
|
+
}
|
|
14281
|
+
yield;
|
|
14282
|
+
}
|
|
14283
|
+
}
|
|
14284
|
+
function markVNodeDataReady(document) {
|
|
14285
|
+
if (document.qVNodeDataReady) {
|
|
14286
|
+
return;
|
|
14287
|
+
}
|
|
14288
|
+
document.qVNodeDataReady = true;
|
|
14289
|
+
document.qVNodeDataState = undefined;
|
|
14290
|
+
const callbacks = document.qVNodeDataCallbacks;
|
|
14291
|
+
document.qVNodeDataCallbacks = undefined;
|
|
14292
|
+
if (callbacks) {
|
|
14293
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
14294
|
+
callbacks[i]();
|
|
14295
|
+
}
|
|
13639
14296
|
}
|
|
13640
14297
|
}
|
|
13641
|
-
function
|
|
13642
|
-
processVNodeDataImpl(document);
|
|
13643
|
-
|
|
14298
|
+
function* processRootVNodeData(document) {
|
|
14299
|
+
yield* processVNodeDataImpl(document);
|
|
14300
|
+
const qDocument = document;
|
|
14301
|
+
qDocument.qVNodeDataProcessed = true;
|
|
14302
|
+
// Re-open the gate so a container added after this drain re-runs a walk.
|
|
14303
|
+
qDocument.qVNodeDataStarted = false;
|
|
14304
|
+
}
|
|
14305
|
+
function* processOutOfOrderSegmentVNodeDataIterator(document, segmentId, segmentContainer, segmentContent, segmentVNodeData, patches) {
|
|
14306
|
+
yield* processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData);
|
|
14307
|
+
for (let i = 0; i < patches.length; i++) {
|
|
14308
|
+
yield* processVNodeDataPatch(document, patches[i]);
|
|
14309
|
+
}
|
|
13644
14310
|
}
|
|
13645
|
-
function
|
|
14311
|
+
function* processVNodeDataPatch(document, script) {
|
|
14312
|
+
const qContainerElement = script?.closest('[q\\:container]');
|
|
14313
|
+
const patchSegment = script?.getAttribute(Q_SUSPENSE_RESOLVED);
|
|
14314
|
+
const contentNode = qContainerElement &&
|
|
14315
|
+
(patchSegment
|
|
14316
|
+
? qContainerElement.querySelector(`[q\\:rp="${patchSegment}"]`)
|
|
14317
|
+
: qContainerElement);
|
|
14318
|
+
if (qContainerElement && contentNode) {
|
|
14319
|
+
yield* processVNodeDataImpl(document, patchSegment || undefined, qContainerElement, contentNode, script.textContent);
|
|
14320
|
+
}
|
|
14321
|
+
}
|
|
14322
|
+
function* processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData) {
|
|
13646
14323
|
const Q_CONTAINER = 'q:container';
|
|
13647
14324
|
const Q_CONTAINER_END = '/' + Q_CONTAINER;
|
|
13648
14325
|
const Q_PROPS_SEPARATOR = ':';
|
|
@@ -13651,9 +14328,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13651
14328
|
const Q_IGNORE_END = '/' + Q_IGNORE;
|
|
13652
14329
|
const Q_CONTAINER_ISLAND = 'q:container-island';
|
|
13653
14330
|
const Q_CONTAINER_ISLAND_END = '/' + Q_CONTAINER_ISLAND;
|
|
13654
|
-
const Q_SUSPENSE_RESOLVED = 'q:r';
|
|
13655
14331
|
const Q_SUSPENSE_RESULT_PARENT = 'q:rp';
|
|
13656
|
-
const Q_PATCH = 'q:patch';
|
|
13657
14332
|
const qDocument = document;
|
|
13658
14333
|
const vNodeDataMap = (qDocument.qVNodeData ||= new WeakMap());
|
|
13659
14334
|
const prototype = document.body;
|
|
@@ -13671,7 +14346,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13671
14346
|
const hasAttribute = prototype.hasAttribute;
|
|
13672
14347
|
const getNodeType = getter(prototype, 'nodeType');
|
|
13673
14348
|
// Process all of the `qwik/vnode` script tags by attaching them to the corresponding containers.
|
|
13674
|
-
const attachVnodeDataAndRefs = (element)
|
|
14349
|
+
const attachVnodeDataAndRefs = function* (element) {
|
|
13675
14350
|
const scripts = element.querySelectorAll('script[type="qwik/vnode"]');
|
|
13676
14351
|
for (let i = 0; i < scripts.length; i++) {
|
|
13677
14352
|
const script = scripts[i];
|
|
@@ -13679,6 +14354,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13679
14354
|
qContainer.qVNodeRefs ||= new Map();
|
|
13680
14355
|
if (script.hasAttribute(Q_PATCH)) {
|
|
13681
14356
|
qDocument.qProcessVNodeDataPatch?.(script);
|
|
14357
|
+
yield;
|
|
13682
14358
|
continue;
|
|
13683
14359
|
}
|
|
13684
14360
|
const scriptContent = script.textContent;
|
|
@@ -13689,14 +14365,21 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13689
14365
|
else {
|
|
13690
14366
|
qContainer.qVnodeData = scriptContent;
|
|
13691
14367
|
}
|
|
14368
|
+
yield;
|
|
13692
14369
|
}
|
|
13693
14370
|
const shadowRoots = element.querySelectorAll('[q\\:shadowroot]');
|
|
13694
14371
|
for (let i = 0; i < shadowRoots.length; i++) {
|
|
13695
14372
|
const parent = shadowRoots[i];
|
|
13696
14373
|
const shadowRoot = parent.shadowRoot;
|
|
13697
|
-
|
|
14374
|
+
if (shadowRoot) {
|
|
14375
|
+
yield* attachVnodeDataAndRefs(shadowRoot);
|
|
14376
|
+
}
|
|
14377
|
+
yield;
|
|
13698
14378
|
}
|
|
13699
14379
|
};
|
|
14380
|
+
///////////////////////////////
|
|
14381
|
+
// Functions to consume the tree.
|
|
14382
|
+
///////////////////////////////
|
|
13700
14383
|
/**
|
|
13701
14384
|
* Looks up which type of node this is in a monomorphic way which should be faster.
|
|
13702
14385
|
*
|
|
@@ -13752,7 +14435,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13752
14435
|
* @param exitNode The node which represents the last node and we should exit.
|
|
13753
14436
|
* @param qVNodeRefs Place to store the VNodeRefs
|
|
13754
14437
|
*/
|
|
13755
|
-
const walkContainer = (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId)
|
|
14438
|
+
const walkContainer = function* (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId) {
|
|
13756
14439
|
const isSegment = __EXPERIMENTAL__.suspense && segmentId !== undefined;
|
|
13757
14440
|
const vData_length = vData.length;
|
|
13758
14441
|
/// Stores the current element index as the TreeWalker traverses the DOM.
|
|
@@ -13778,6 +14461,9 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13778
14461
|
}
|
|
13779
14462
|
return elementsToSkip;
|
|
13780
14463
|
};
|
|
14464
|
+
if (!node) {
|
|
14465
|
+
return;
|
|
14466
|
+
}
|
|
13781
14467
|
do {
|
|
13782
14468
|
if (node === exitNode) {
|
|
13783
14469
|
return;
|
|
@@ -13791,7 +14477,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13791
14477
|
while (cursor && !(nextNode = nextSibling(cursor))) {
|
|
13792
14478
|
cursor = cursor.parentNode;
|
|
13793
14479
|
}
|
|
13794
|
-
walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
14480
|
+
yield* walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
13795
14481
|
}
|
|
13796
14482
|
else if (nodeType === 16 /* NodeType.COMMENT_IGNORE_START */) {
|
|
13797
14483
|
let islandNode = node;
|
|
@@ -13826,7 +14512,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13826
14512
|
throw new Error(`<!--${node?.nodeValue}--> not closed!`);
|
|
13827
14513
|
}
|
|
13828
14514
|
} while (getFastNodeType(nextNode) !== 8 /* NodeType.COMMENT_SKIP_END */);
|
|
13829
|
-
walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
14515
|
+
yield* walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
13830
14516
|
}
|
|
13831
14517
|
else if (nodeType === 6 /* NodeType.ELEMENT_SHADOW_ROOT_WRAPPER */) {
|
|
13832
14518
|
// If we are in a shadow root, we need to get the shadow root element.
|
|
@@ -13834,7 +14520,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13834
14520
|
const shadowRootContainer = node;
|
|
13835
14521
|
const shadowRoot = shadowRootContainer?.shadowRoot;
|
|
13836
14522
|
if (shadowRoot) {
|
|
13837
|
-
walkContainer(
|
|
14523
|
+
yield* walkContainer(
|
|
13838
14524
|
// we need to create a new walker for the shadow root
|
|
13839
14525
|
document.createTreeWalker(shadowRoot, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, shadowRoot, null, '', null, null);
|
|
13840
14526
|
}
|
|
@@ -13897,51 +14583,42 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13897
14583
|
}
|
|
13898
14584
|
elementIdx++;
|
|
13899
14585
|
if (__EXPERIMENTAL__.suspense && contentBoundaryId !== null) {
|
|
13900
|
-
processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
14586
|
+
yield* processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
13901
14587
|
nextNode = nextSibling(node);
|
|
13902
14588
|
if (nextNode) {
|
|
13903
14589
|
walker.currentNode = nextNode;
|
|
13904
14590
|
}
|
|
13905
14591
|
}
|
|
13906
14592
|
}
|
|
14593
|
+
yield;
|
|
13907
14594
|
} while ((node = nextNode || walker.nextNode()));
|
|
13908
14595
|
};
|
|
13909
|
-
const processVNodeDataScope = (qContainerElement, contentNode, vData, scopeSegmentId)
|
|
14596
|
+
const processVNodeDataScope = function* (qContainerElement, contentNode, vData, scopeSegmentId) {
|
|
13910
14597
|
qContainerElement.qVNodeRefs ||= new Map();
|
|
13911
14598
|
const scopeWalker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13912
14599
|
scopeWalker.currentNode = contentNode;
|
|
13913
|
-
walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
14600
|
+
yield* walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
13914
14601
|
};
|
|
13915
|
-
const processSuspenseContentSegment =
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
processVNodeDataScope(qContainerElement, contentNode, vData, boundaryId);
|
|
13920
|
-
}
|
|
13921
|
-
}
|
|
13922
|
-
: null;
|
|
13923
|
-
qDocument.qProcessVNodeDataPatch = (script) => {
|
|
13924
|
-
const qContainerElement = script?.closest('[q\\:container]');
|
|
13925
|
-
const patchSegment = script?.getAttribute(Q_SUSPENSE_RESOLVED);
|
|
13926
|
-
const contentNode = qContainerElement &&
|
|
13927
|
-
(patchSegment
|
|
13928
|
-
? qContainerElement.querySelector(`[q\\:rp="${patchSegment}"]`)
|
|
13929
|
-
: qContainerElement);
|
|
13930
|
-
if (qContainerElement && contentNode) {
|
|
13931
|
-
processVNodeDataScope(qContainerElement, contentNode, script.textContent, patchSegment || undefined);
|
|
14602
|
+
const processSuspenseContentSegment = function* (qContainerElement, contentNode, boundaryId, vData) {
|
|
14603
|
+
vData ||= qContainerElement?.qSegmentVnodeData?.get(boundaryId);
|
|
14604
|
+
if (qContainerElement && vData) {
|
|
14605
|
+
yield* processVNodeDataScope(qContainerElement, contentNode, vData, boundaryId);
|
|
13932
14606
|
}
|
|
13933
14607
|
};
|
|
13934
|
-
if (
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
processSuspenseContentSegment(segmentContainer, segmentContent, segmentId, segmentVNodeData);
|
|
14608
|
+
if (segmentContainer && segmentContent && segmentVNodeData !== undefined) {
|
|
14609
|
+
segmentContainer.qVNodeRefs ||= new Map();
|
|
14610
|
+
if (__EXPERIMENTAL__.suspense && segmentId !== undefined) {
|
|
14611
|
+
yield* processSuspenseContentSegment(segmentContainer, segmentContent, segmentId, segmentVNodeData);
|
|
14612
|
+
}
|
|
14613
|
+
else {
|
|
14614
|
+
yield* processVNodeDataScope(segmentContainer, segmentContent, segmentVNodeData);
|
|
13938
14615
|
}
|
|
13939
14616
|
return;
|
|
13940
14617
|
}
|
|
13941
|
-
attachVnodeDataAndRefs(document);
|
|
14618
|
+
yield* attachVnodeDataAndRefs(document);
|
|
13942
14619
|
// Walk the tree and process each `q:container` element.
|
|
13943
14620
|
const walker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13944
|
-
walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
14621
|
+
yield* walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
13945
14622
|
}
|
|
13946
14623
|
const isSeparator = (ch) =>
|
|
13947
14624
|
/* `!` */ VNodeDataSeparator.ADVANCE_1 <= ch && ch <= VNodeDataSeparator.ADVANCE_8192; /* `.` */
|
|
@@ -13976,6 +14653,87 @@ const findVDataSectionEnd = (vData, start, end) => {
|
|
|
13976
14653
|
return start;
|
|
13977
14654
|
};
|
|
13978
14655
|
|
|
14656
|
+
function isContainerReady(container) {
|
|
14657
|
+
return container.$containerDataProcessState$ === 3 /* ContainerDataProcessState.ProcessingStateDone */;
|
|
14658
|
+
}
|
|
14659
|
+
function processContainerStateData(container, iterator) {
|
|
14660
|
+
const state = (container.$containerStateDataState$ ||= {
|
|
14661
|
+
$queue$: [],
|
|
14662
|
+
$active$: null,
|
|
14663
|
+
});
|
|
14664
|
+
container.$containerDataProcessState$ = 2 /* ContainerDataProcessState.ProcessingState */;
|
|
14665
|
+
state.$queue$.push(iterator);
|
|
14666
|
+
scheduleProcessContainerStateData(container, state);
|
|
14667
|
+
}
|
|
14668
|
+
const onContainerDataReady = (container, callback) => {
|
|
14669
|
+
const domContainer = container;
|
|
14670
|
+
const checkReady = () => {
|
|
14671
|
+
if (!isContainerReady(domContainer)) {
|
|
14672
|
+
(domContainer.$containerStateReadyCallbacks$ ||= []).push(checkReady);
|
|
14673
|
+
return;
|
|
14674
|
+
}
|
|
14675
|
+
onVNodeDataReady(domContainer.document, () => {
|
|
14676
|
+
if (isContainerReady(domContainer)) {
|
|
14677
|
+
callback();
|
|
14678
|
+
}
|
|
14679
|
+
else {
|
|
14680
|
+
checkReady();
|
|
14681
|
+
}
|
|
14682
|
+
});
|
|
14683
|
+
};
|
|
14684
|
+
checkReady();
|
|
14685
|
+
};
|
|
14686
|
+
const whenContainerDataReady = (container, callback) => {
|
|
14687
|
+
const domContainer = container;
|
|
14688
|
+
if (isContainerReady(domContainer) && domContainer.document.qVNodeDataReady) {
|
|
14689
|
+
return callback();
|
|
14690
|
+
}
|
|
14691
|
+
return new Promise((resolve, reject) => {
|
|
14692
|
+
onContainerDataReady(domContainer, () => {
|
|
14693
|
+
try {
|
|
14694
|
+
resolve(callback());
|
|
14695
|
+
}
|
|
14696
|
+
catch (error) {
|
|
14697
|
+
reject(error);
|
|
14698
|
+
}
|
|
14699
|
+
});
|
|
14700
|
+
});
|
|
14701
|
+
};
|
|
14702
|
+
function scheduleProcessContainerStateData(container, state) {
|
|
14703
|
+
if (state.$active$) {
|
|
14704
|
+
return;
|
|
14705
|
+
}
|
|
14706
|
+
const iterator = state.$queue$.shift();
|
|
14707
|
+
if (!iterator) {
|
|
14708
|
+
markContainerDataReady(container);
|
|
14709
|
+
return;
|
|
14710
|
+
}
|
|
14711
|
+
state.$active$ = createYieldingIteratorState(iterator, () => {
|
|
14712
|
+
state.$active$ = null;
|
|
14713
|
+
scheduleProcessContainerStateData(container, state);
|
|
14714
|
+
}, (error) => {
|
|
14715
|
+
state.$active$ = null;
|
|
14716
|
+
logError(error);
|
|
14717
|
+
markContainerDataReady(container);
|
|
14718
|
+
});
|
|
14719
|
+
scheduleYieldingIterator(state.$active$);
|
|
14720
|
+
}
|
|
14721
|
+
function markContainerDataReady(container) {
|
|
14722
|
+
const state = container.$containerDataProcessState$;
|
|
14723
|
+
if (state !== 2 /* ContainerDataProcessState.ProcessingState */) {
|
|
14724
|
+
return;
|
|
14725
|
+
}
|
|
14726
|
+
container.$containerDataProcessState$ = 3 /* ContainerDataProcessState.ProcessingStateDone */;
|
|
14727
|
+
container.$containerStateDataState$ = undefined;
|
|
14728
|
+
const callbacks = container.$containerStateReadyCallbacks$;
|
|
14729
|
+
container.$containerStateReadyCallbacks$ = undefined;
|
|
14730
|
+
if (callbacks) {
|
|
14731
|
+
for (let i = 0; i < callbacks.length; i++) {
|
|
14732
|
+
callbacks[i]();
|
|
14733
|
+
}
|
|
14734
|
+
}
|
|
14735
|
+
}
|
|
14736
|
+
|
|
13979
14737
|
/** @file Public APIs for the SSR */
|
|
13980
14738
|
/** @public */
|
|
13981
14739
|
function getDomContainer(element) {
|
|
@@ -13998,8 +14756,12 @@ function getOutOfOrderStreamingScript(boundaryId, content) {
|
|
|
13998
14756
|
const qContainerElement = content?.closest(QContainerSelector);
|
|
13999
14757
|
const qContainer = qContainerElement?.qContainer;
|
|
14000
14758
|
if (qContainer) {
|
|
14001
|
-
|
|
14002
|
-
|
|
14759
|
+
const document = qContainer.element.ownerDocument;
|
|
14760
|
+
processOutOfOrderSegmentVNodeData(document, segmentId, content);
|
|
14761
|
+
onVNodeDataReady(document, () => {
|
|
14762
|
+
qContainer.element.qContainer === qContainer &&
|
|
14763
|
+
processContainerStateData(qContainer, processSegmentStateScriptsIterator(qContainer, segmentId));
|
|
14764
|
+
});
|
|
14003
14765
|
}
|
|
14004
14766
|
}
|
|
14005
14767
|
/** @internal */
|
|
@@ -14014,6 +14776,9 @@ class DomContainer extends _SharedContainer {
|
|
|
14014
14776
|
$instanceHash$;
|
|
14015
14777
|
$forwardRefs$ = null;
|
|
14016
14778
|
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
14779
|
+
$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14780
|
+
$containerStateReadyCallbacks$ = undefined;
|
|
14781
|
+
$containerStateDataState$ = undefined;
|
|
14017
14782
|
$rawStateData$;
|
|
14018
14783
|
$stateData$;
|
|
14019
14784
|
$rootForwardRefs$ = null;
|
|
@@ -14024,7 +14789,8 @@ class DomContainer extends _SharedContainer {
|
|
|
14024
14789
|
if (!this.qContainer) {
|
|
14025
14790
|
throw qError(25 /* QError.elementWithoutContainer */);
|
|
14026
14791
|
}
|
|
14027
|
-
|
|
14792
|
+
const document = element.ownerDocument;
|
|
14793
|
+
this.document = document;
|
|
14028
14794
|
this.element = element;
|
|
14029
14795
|
this.$buildBase$ = element.getAttribute(QBaseAttr);
|
|
14030
14796
|
this.$instanceHash$ = element.getAttribute(QInstanceAttr);
|
|
@@ -14032,23 +14798,46 @@ class DomContainer extends _SharedContainer {
|
|
|
14032
14798
|
this.rootVNode = vnode_newUnMaterializedElement(this.element);
|
|
14033
14799
|
this.$rawStateData$ = [];
|
|
14034
14800
|
this.$stateData$ = [];
|
|
14035
|
-
const document = this.element.ownerDocument;
|
|
14036
|
-
if (!document.qVNodeDataProcessed) {
|
|
14037
|
-
processVNodeData(document);
|
|
14038
|
-
}
|
|
14039
14801
|
if (__EXPERIMENTAL__.suspense && document.querySelector('template[q\\:r]')) {
|
|
14040
14802
|
document.qProcessOOOS ||= getOutOfOrderStreamingScript;
|
|
14041
14803
|
}
|
|
14042
14804
|
this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
|
|
14043
14805
|
this.$setServerData$();
|
|
14044
|
-
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14045
14806
|
element.qContainer = this;
|
|
14046
14807
|
element.qDestroy = () => this.$destroy$();
|
|
14047
|
-
this.$
|
|
14808
|
+
this.$containerDataProcessState$ = 1 /* ContainerDataProcessState.ProcessingVNode */;
|
|
14809
|
+
processVNodeData(document, element);
|
|
14810
|
+
onVNodeDataReady(document, () => {
|
|
14811
|
+
if (this.$containerDataProcessState$ === 1 /* ContainerDataProcessState.ProcessingVNode */) {
|
|
14812
|
+
processContainerStateData(this, this.$processContainerData$());
|
|
14813
|
+
}
|
|
14814
|
+
});
|
|
14815
|
+
}
|
|
14816
|
+
*$processContainerData$() {
|
|
14817
|
+
const element = this.element;
|
|
14818
|
+
if (element.qContainer !== this) {
|
|
14819
|
+
return;
|
|
14820
|
+
}
|
|
14821
|
+
const rootState = element.querySelector(`script[type="qwik/state"][q\\:instance="${this.$instanceHash$}"]:not(${QStatePatchAttrSelector})`) ||
|
|
14822
|
+
element.querySelector(`script[type="qwik/state"]:not([q\\:instance]):not(${QStatePatchAttrSelector})`);
|
|
14823
|
+
if (rootState) {
|
|
14824
|
+
this.$rawStateData$ = JSON.parse(rootState.textContent);
|
|
14825
|
+
yield* preprocessStateIterator(this.$rawStateData$, this);
|
|
14826
|
+
this.$rootForwardRefs$ = this.$forwardRefs$;
|
|
14827
|
+
const rootCount = this.$rawStateData$.length / 2;
|
|
14828
|
+
const statePrewarm = element.getAttribute(QStatePrewarmAttr);
|
|
14829
|
+
if (statePrewarm !== null && rootCount > 0 && rootCount >= Number(statePrewarm)) {
|
|
14830
|
+
this.$stateData$ = yield* eagerDeserializeStateIterator(this, this.$rawStateData$);
|
|
14831
|
+
}
|
|
14832
|
+
else {
|
|
14833
|
+
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
14834
|
+
}
|
|
14835
|
+
}
|
|
14048
14836
|
if (__EXPERIMENTAL__.suspense) {
|
|
14049
|
-
|
|
14837
|
+
yield* processSegmentStateScriptsIterator(this);
|
|
14050
14838
|
}
|
|
14051
14839
|
this.$hoistStyles$();
|
|
14840
|
+
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14052
14841
|
if (!qTest && element.isConnected) {
|
|
14053
14842
|
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
|
|
14054
14843
|
}
|
|
@@ -14068,9 +14857,15 @@ class DomContainer extends _SharedContainer {
|
|
|
14068
14857
|
}
|
|
14069
14858
|
el.removeAttribute(QContainerAttr);
|
|
14070
14859
|
const document = el.ownerDocument;
|
|
14860
|
+
this.$containerStateDataState$ = undefined;
|
|
14861
|
+
this.$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14071
14862
|
const hasContainers = document.querySelector(QContainerSelector) !== null;
|
|
14072
14863
|
if (!hasContainers) {
|
|
14073
14864
|
document.qVNodeData = undefined;
|
|
14865
|
+
document.qVNodeDataStarted = undefined;
|
|
14866
|
+
document.qVNodeDataReady = undefined;
|
|
14867
|
+
document.qVNodeDataState = undefined;
|
|
14868
|
+
document.qVNodeDataCallbacks = undefined;
|
|
14074
14869
|
document.qVNodeDataProcessed = undefined;
|
|
14075
14870
|
document.qProcessVNodeDataPatch = undefined;
|
|
14076
14871
|
}
|
|
@@ -14080,18 +14875,6 @@ class DomContainer extends _SharedContainer {
|
|
|
14080
14875
|
}
|
|
14081
14876
|
}
|
|
14082
14877
|
}
|
|
14083
|
-
$processRootStateScript$() {
|
|
14084
|
-
const rootState = this.element.querySelector(`${this.$stateScriptSelector$()}:not(${QStatePatchAttrSelector})`);
|
|
14085
|
-
if (rootState) {
|
|
14086
|
-
this.$rawStateData$ = JSON.parse(rootState.textContent);
|
|
14087
|
-
preprocessState(this.$rawStateData$, this);
|
|
14088
|
-
this.$rootForwardRefs$ = this.$forwardRefs$;
|
|
14089
|
-
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
14090
|
-
}
|
|
14091
|
-
}
|
|
14092
|
-
$stateScriptSelector$() {
|
|
14093
|
-
return `script[type="qwik/state"][q\\:instance="${this.$instanceHash$}"]`;
|
|
14094
|
-
}
|
|
14095
14878
|
/**
|
|
14096
14879
|
* The first time we render we need to hoist the styles. (Meaning we need to move all styles from
|
|
14097
14880
|
* component inline to <head>)
|
|
@@ -14361,7 +15144,11 @@ const useInvokeContext = () => {
|
|
|
14361
15144
|
isDev && assertDefined(ctx.$effectSubscriber$, `invoke: $effectSubscriber$ must be defined`, ctx);
|
|
14362
15145
|
return ctx;
|
|
14363
15146
|
};
|
|
14364
|
-
/**
|
|
15147
|
+
/**
|
|
15148
|
+
* Call a function with the given InvokeContext and given arguments.
|
|
15149
|
+
*
|
|
15150
|
+
* @internal
|
|
15151
|
+
*/
|
|
14365
15152
|
function invoke(context, fn, ...args) {
|
|
14366
15153
|
return invokeApply.call(this, context, fn, args);
|
|
14367
15154
|
}
|
|
@@ -14376,8 +15163,7 @@ function invokeApply(context, fn, args) {
|
|
|
14376
15163
|
_context = previousContext;
|
|
14377
15164
|
}
|
|
14378
15165
|
}
|
|
14379
|
-
const newInvokeContextFromDOM = (event, element) => {
|
|
14380
|
-
const domContainer = getDomContainer(element);
|
|
15166
|
+
const newInvokeContextFromDOM = (event, element, domContainer = getDomContainer(element)) => {
|
|
14381
15167
|
const hostElement = vnode_locate(domContainer.rootVNode, element);
|
|
14382
15168
|
const locale = domContainer.$locale$;
|
|
14383
15169
|
locale && setLocale(locale);
|
|
@@ -14397,6 +15183,7 @@ function newRenderInvokeContext(locale, hostElement, container) {
|
|
|
14397
15183
|
seal(ctx);
|
|
14398
15184
|
return ctx;
|
|
14399
15185
|
}
|
|
15186
|
+
/** @internal */
|
|
14400
15187
|
// TODO how about putting url and locale (and event/custom?) in to a "static" object
|
|
14401
15188
|
function newInvokeContext(locale, hostElement, event) {
|
|
14402
15189
|
// ServerRequestEvent has .locale, but it's not always defined.
|
|
@@ -14518,7 +15305,7 @@ const initLazyRefDev = (lazy) => {
|
|
|
14518
15305
|
};
|
|
14519
15306
|
/** Validate captured scope and register WeakRef tracking on a QRLClass instance. */
|
|
14520
15307
|
const initQrlClassDev = (lazy, captures, qrl) => {
|
|
14521
|
-
if (captures
|
|
15308
|
+
if (Array.isArray(captures)) {
|
|
14522
15309
|
for (let i = 0; i < captures.length; i++) {
|
|
14523
15310
|
const item = captures[i];
|
|
14524
15311
|
verifySerializable(item, 'Captured variable in the closure can not be serialized');
|
|
@@ -14555,7 +15342,7 @@ const setupHmr = (LazyRefClass, setGetLazyRef) => {
|
|
|
14555
15342
|
params.push(`t=${t}`);
|
|
14556
15343
|
return `${path}?${params.join('&')}`;
|
|
14557
15344
|
};
|
|
14558
|
-
|
|
15345
|
+
const hmrHandler = (ev) => {
|
|
14559
15346
|
const files = ev.detail.files;
|
|
14560
15347
|
const t = ev.detail.t || document.__hmrT || Date.now();
|
|
14561
15348
|
let didReload = false;
|
|
@@ -14591,7 +15378,6 @@ const setupHmr = (LazyRefClass, setGetLazyRef) => {
|
|
|
14591
15378
|
}
|
|
14592
15379
|
if (didReload) {
|
|
14593
15380
|
lazy.$ref$ = undefined;
|
|
14594
|
-
document.__hmrDone = document.__hmrT;
|
|
14595
15381
|
if (lazy.qrls) {
|
|
14596
15382
|
for (const qrlRef of lazy.qrls) {
|
|
14597
15383
|
const qrl = qrlRef.deref();
|
|
@@ -14607,7 +15393,8 @@ const setupHmr = (LazyRefClass, setGetLazyRef) => {
|
|
|
14607
15393
|
}
|
|
14608
15394
|
}
|
|
14609
15395
|
}
|
|
14610
|
-
}
|
|
15396
|
+
};
|
|
15397
|
+
document.addEventListener('qHmr', hmrHandler, true);
|
|
14611
15398
|
};
|
|
14612
15399
|
|
|
14613
15400
|
// keep these imports above the rest to prevent circular dep issues
|
|
@@ -14720,7 +15507,9 @@ class QRLClass {
|
|
|
14720
15507
|
}
|
|
14721
15508
|
// If it is plain value with deserialized or missing captures, resolve it immediately
|
|
14722
15509
|
// Otherwise we keep using the async path so we can wait for qrls to load
|
|
14723
|
-
if ($lazy$.$ref$ != null &&
|
|
15510
|
+
if ($lazy$.$ref$ != null &&
|
|
15511
|
+
(!this.$captures$ || typeof this.$captures$ !== 'string') &&
|
|
15512
|
+
!isPromise($lazy$.$ref$)) {
|
|
14724
15513
|
this.resolved = bindCaptures(this, $lazy$.$ref$);
|
|
14725
15514
|
}
|
|
14726
15515
|
}
|
|
@@ -14875,31 +15664,50 @@ let _captures = null;
|
|
|
14875
15664
|
const setCaptures = (captures) => {
|
|
14876
15665
|
_captures = captures;
|
|
14877
15666
|
};
|
|
14878
|
-
const
|
|
15667
|
+
const deserializeCaptureDeltas = (container, deltaString, startIndex = 0, previousRootId) => {
|
|
14879
15668
|
const refs = [];
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
15669
|
+
let previous = previousRootId;
|
|
15670
|
+
let start = startIndex;
|
|
15671
|
+
for (let i = startIndex; i <= deltaString.length; i++) {
|
|
15672
|
+
if (i === deltaString.length || deltaString.charCodeAt(i) === 32) {
|
|
15673
|
+
if (i > start) {
|
|
15674
|
+
const delta = Number(deltaString.slice(start, i));
|
|
15675
|
+
previous = previous === undefined ? delta : previous + delta;
|
|
15676
|
+
refs.push(container.$getObjectById$(previous));
|
|
15677
|
+
}
|
|
15678
|
+
start = i + 1;
|
|
15679
|
+
}
|
|
14884
15680
|
}
|
|
14885
15681
|
return refs;
|
|
14886
15682
|
};
|
|
15683
|
+
const deserializeQrlCaptureDeltas = (container, qrlString) => {
|
|
15684
|
+
const firstHash = qrlString.indexOf('#');
|
|
15685
|
+
if (firstHash === -1) {
|
|
15686
|
+
return deserializeCaptureDeltas(container, qrlString);
|
|
15687
|
+
}
|
|
15688
|
+
const secondHash = qrlString.indexOf('#', firstHash + 1);
|
|
15689
|
+
const previousRootId = Number(qrlString.slice(0, firstHash)) + Number(qrlString.slice(firstHash + 1, secondHash));
|
|
15690
|
+
return deserializeCaptureDeltas(container, qrlString, secondHash + 1, previousRootId);
|
|
15691
|
+
};
|
|
14887
15692
|
/** Puts the qrl captures into `_captures`, and returns a Promise that should be awaited if possible */
|
|
14888
15693
|
const ensureQrlCaptures = (qrl) => {
|
|
14889
15694
|
// We read the captures once, synchronously, so no need to keep previous
|
|
14890
|
-
|
|
15695
|
+
const serializedCaptures = qrl.$captures$;
|
|
14891
15696
|
const container = qrl.$container$;
|
|
14892
|
-
if (typeof
|
|
15697
|
+
if (typeof serializedCaptures === 'string') {
|
|
14893
15698
|
if (!container) {
|
|
14894
15699
|
throw qError(13 /* QError.qrlMissingContainer */);
|
|
14895
15700
|
}
|
|
14896
15701
|
const prevLoading = loading;
|
|
14897
|
-
_captures = qrl.$captures$ =
|
|
15702
|
+
_captures = qrl.$captures$ = deserializeQrlCaptureDeltas(container, serializedCaptures);
|
|
14898
15703
|
if (loading !== prevLoading) {
|
|
14899
15704
|
// return the loading promise so callers can await it
|
|
14900
15705
|
return loading;
|
|
14901
15706
|
}
|
|
14902
15707
|
}
|
|
15708
|
+
else {
|
|
15709
|
+
_captures = serializedCaptures || null;
|
|
15710
|
+
}
|
|
14903
15711
|
};
|
|
14904
15712
|
// Wrap functions to provide their lexical scope
|
|
14905
15713
|
const bindCaptures = (qrl, ref) => {
|
|
@@ -15866,7 +16674,13 @@ const useComputedQrl = (qrl, options) => {
|
|
|
15866
16674
|
* recalculated, and if the result changed, all tasks which are tracking the signal will be re-run
|
|
15867
16675
|
* and all components that read the signal will be re-rendered.
|
|
15868
16676
|
*
|
|
15869
|
-
*
|
|
16677
|
+
* Every synchronous signal or store read is tracked automatically. Reads after an `await` are not:
|
|
16678
|
+
* the tracking context is lost, so track them explicitly with the `track()` provided on the context
|
|
16679
|
+
* argument. When the function is async, the returned signal exposes the async API: reading an
|
|
16680
|
+
* unresolved `.value` throws the computation promise, and `.pending` and `.error` expose the
|
|
16681
|
+
* computation state.
|
|
16682
|
+
*
|
|
16683
|
+
* The function must not have any side effects.
|
|
15870
16684
|
*
|
|
15871
16685
|
* @public
|
|
15872
16686
|
*/
|
|
@@ -15964,7 +16778,7 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
15964
16778
|
// In SSR we defer execution until triggered in DOM
|
|
15965
16779
|
flags = 1 /* TaskFlags.VISIBLE_TASK */;
|
|
15966
16780
|
}
|
|
15967
|
-
const task = new Task(flags, i, iCtx.$hostElement$, qrl,
|
|
16781
|
+
const task = new Task(flags, i, iCtx.$hostElement$, qrl, null);
|
|
15968
16782
|
set(task);
|
|
15969
16783
|
useRegisterTaskEvents(task, eagerness);
|
|
15970
16784
|
};
|
|
@@ -16002,11 +16816,11 @@ const getTaskHandlerQrl = (task) => {
|
|
|
16002
16816
|
* Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
|
|
16003
16817
|
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
16004
16818
|
*
|
|
16005
|
-
* @deprecated Use `
|
|
16006
|
-
* available for backward compatibility but it is recommended to migrate to `
|
|
16007
|
-
* code and when updating existing code.
|
|
16819
|
+
* @deprecated Use `useComputed$` instead, which is more powerful and flexible. `useResource$` is
|
|
16820
|
+
* still available for backward compatibility but it is recommended to migrate to `useComputed$`
|
|
16821
|
+
* for new code and when updating existing code.
|
|
16008
16822
|
* @public
|
|
16009
|
-
* @see
|
|
16823
|
+
* @see useComputed$
|
|
16010
16824
|
* @see Resource
|
|
16011
16825
|
* @see ResourceReturn
|
|
16012
16826
|
*/
|
|
@@ -16111,7 +16925,10 @@ const creator = (qrl, options) => {
|
|
|
16111
16925
|
qrl.resolve();
|
|
16112
16926
|
return createAsyncSignal(qrl, options);
|
|
16113
16927
|
};
|
|
16114
|
-
/**
|
|
16928
|
+
/**
|
|
16929
|
+
* @deprecated Use `useComputed$` instead, it has async support now.
|
|
16930
|
+
* @internal
|
|
16931
|
+
*/
|
|
16115
16932
|
const useAsyncQrl = (qrl, options) => {
|
|
16116
16933
|
return useConstant((creator), qrl, options);
|
|
16117
16934
|
};
|
|
@@ -16134,6 +16951,8 @@ const useAsyncQrl = (qrl, options) => {
|
|
|
16134
16951
|
* will subscribe to it and return the last resolved value until the new value is ready. As soon as
|
|
16135
16952
|
* the new value is ready, the subscribers will be updated.
|
|
16136
16953
|
*
|
|
16954
|
+
* @deprecated Use `useComputed$` instead, it has async support now. It auto-tracks synchronous
|
|
16955
|
+
* reads; after the first `await`, use the provided `track()` like before.
|
|
16137
16956
|
* @public
|
|
16138
16957
|
*/
|
|
16139
16958
|
const useAsync$ = implicit$FirstArg(useAsyncQrl);
|
|
@@ -16170,6 +16989,46 @@ const eachCmp = (props) => {
|
|
|
16170
16989
|
const Each = /*#__PURE__*/ componentQrl(
|
|
16171
16990
|
/*#__PURE__*/ inlinedQrl(eachCmp, '_eaC'));
|
|
16172
16991
|
|
|
16992
|
+
const invokeShowFn = (fn, context, arg) => {
|
|
16993
|
+
return isQrl(fn) ? fn.getFn(context)(arg) : fn(arg);
|
|
16994
|
+
};
|
|
16995
|
+
/** @internal */
|
|
16996
|
+
const showCmpTask = ({ track }) => {
|
|
16997
|
+
const props = _captures[0];
|
|
16998
|
+
const context = tryGetInvokeContext();
|
|
16999
|
+
const host = context.$hostElement$;
|
|
17000
|
+
const container = context.$container$;
|
|
17001
|
+
const isSsr = qTest ? isServerPlatform() : isServer;
|
|
17002
|
+
return maybeThen(track(() => invokeShowFn(props.when$, tryGetInvokeContext(), undefined)), (condition) => {
|
|
17003
|
+
const branch = condition ? props.then$ : props.else$;
|
|
17004
|
+
return maybeThen(branch ? invokeShowFn(branch, context, condition) : null, (output) => {
|
|
17005
|
+
const jsx = branch ? [output] : [];
|
|
17006
|
+
if (isSsr) {
|
|
17007
|
+
const ssr = container;
|
|
17008
|
+
return ssr.renderJSX(jsx, {
|
|
17009
|
+
currentStyleScoped: null,
|
|
17010
|
+
parentComponentFrame: ssr.getComponentFrame(0),
|
|
17011
|
+
});
|
|
17012
|
+
}
|
|
17013
|
+
else {
|
|
17014
|
+
setNodeDiffPayload(host, jsx);
|
|
17015
|
+
markVNodeDirty(container, host, 2 /* ChoreBits.NODE_DIFF */);
|
|
17016
|
+
}
|
|
17017
|
+
});
|
|
17018
|
+
});
|
|
17019
|
+
};
|
|
17020
|
+
/** @internal */
|
|
17021
|
+
const showCmp = (props) => {
|
|
17022
|
+
if (!__EXPERIMENTAL__.show) {
|
|
17023
|
+
throw new Error('Show is experimental and must be enabled with `experimental: ["show"]` in the `qwikVite` plugin.');
|
|
17024
|
+
}
|
|
17025
|
+
useTaskQrl(/*#__PURE__*/ inlinedQrl(showCmpTask, '_shT', [props]));
|
|
17026
|
+
return SkipRender;
|
|
17027
|
+
};
|
|
17028
|
+
/** @public @experimental */
|
|
17029
|
+
const Show = /*#__PURE__*/ componentQrl(
|
|
17030
|
+
/*#__PURE__*/ inlinedQrl(showCmp, '_shC'));
|
|
17031
|
+
|
|
16173
17032
|
const RevealContext = /*#__PURE__*/ createContextId('qk-reveal');
|
|
16174
17033
|
const createRevealContext = (props) => {
|
|
16175
17034
|
return {
|
|
@@ -16563,5 +17422,5 @@ if (import.meta.hot) {
|
|
|
16563
17422
|
});
|
|
16564
17423
|
}
|
|
16565
17424
|
|
|
16566
|
-
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, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, _hmr, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, _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 };
|
|
17425
|
+
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 };
|
|
16567
17426
|
//# sourceMappingURL=core.mjs.map
|