@qwik.dev/core 2.0.0-beta.37 → 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 +448 -317
- package/dist/core.min.mjs +9 -8
- package/dist/core.mjs +1767 -953
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +4280 -3613
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.d.ts +5 -3
- package/dist/optimizer.mjs +1254 -1227
- package/dist/preloader.mjs +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.mjs +49 -8
- package/dist/server.prod.mjs +360 -312
- 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 +37 -30
- package/dist/testing/index.mjs +1392 -697
- 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 +3 -3
- 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';
|
|
@@ -842,8 +846,21 @@ const createMacroTask = (fn) => {
|
|
|
842
846
|
let macroTask;
|
|
843
847
|
if (typeof MessageChannel !== 'undefined') {
|
|
844
848
|
const channel = new MessageChannel();
|
|
849
|
+
let active = true;
|
|
845
850
|
channel.port1.onmessage = () => fn();
|
|
846
|
-
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
|
+
};
|
|
847
864
|
}
|
|
848
865
|
else {
|
|
849
866
|
macroTask = () => setTimeout(fn);
|
|
@@ -963,7 +980,7 @@ const rel = isBrowser && doc.createElement('link').relList?.supports?.('modulepr
|
|
|
963
980
|
? 'modulePreload'
|
|
964
981
|
: 'preload';
|
|
965
982
|
const isJSRegex = /\.[mc]?js$/;
|
|
966
|
-
const yieldInterval =
|
|
983
|
+
const yieldInterval = 10;
|
|
967
984
|
|
|
968
985
|
const BundleImportState_None = 0;
|
|
969
986
|
const BundleImportState_Preload = 2;
|
|
@@ -1219,6 +1236,8 @@ const writeStringRootRef = (writer, id) => writer.write(String(id));
|
|
|
1219
1236
|
/** @internal */
|
|
1220
1237
|
const writeStringRootRefPath = (writer, path) => writer.write(stringifyRootRefPath(path));
|
|
1221
1238
|
/** @internal */
|
|
1239
|
+
const writeStringRootRefDelta = (writer, id, base) => writer.write(String(id - base));
|
|
1240
|
+
/** @internal */
|
|
1222
1241
|
const createStringStreamWriter = (write) => ({
|
|
1223
1242
|
write,
|
|
1224
1243
|
writeRootRef(id) {
|
|
@@ -1227,6 +1246,9 @@ const createStringStreamWriter = (write) => ({
|
|
|
1227
1246
|
writeRootRefPath(path) {
|
|
1228
1247
|
return writeStringRootRefPath(this, path);
|
|
1229
1248
|
},
|
|
1249
|
+
writeRootRefDelta(id, base) {
|
|
1250
|
+
return writeStringRootRefDelta(this, id, base);
|
|
1251
|
+
},
|
|
1230
1252
|
});
|
|
1231
1253
|
|
|
1232
1254
|
// Pre-allocated common strings to reduce allocation overhead
|
|
@@ -1242,7 +1264,7 @@ const COMMA = ',';
|
|
|
1242
1264
|
*
|
|
1243
1265
|
* @public
|
|
1244
1266
|
*/
|
|
1245
|
-
const version = "2.0.0-beta.
|
|
1267
|
+
const version = "2.0.0-beta.38-dev+0339f17";
|
|
1246
1268
|
|
|
1247
1269
|
const isNode = (value) => {
|
|
1248
1270
|
return value && typeof value.nodeType === 'number';
|
|
@@ -1698,9 +1720,12 @@ function setCursorPosition(container, cursorData, position) {
|
|
|
1698
1720
|
}
|
|
1699
1721
|
}
|
|
1700
1722
|
function mergeCursors(container, newCursorData, oldCursor) {
|
|
1723
|
+
const oldCursorData = getCursorData(oldCursor);
|
|
1724
|
+
if (!oldCursorData || oldCursorData === newCursorData) {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1701
1727
|
// delete from global cursors queue
|
|
1702
1728
|
removeCursorFromQueue(oldCursor, container);
|
|
1703
|
-
const oldCursorData = getCursorData(oldCursor);
|
|
1704
1729
|
mergeCursorData(newCursorData, oldCursorData);
|
|
1705
1730
|
}
|
|
1706
1731
|
function mergeCursorData(newCursorData, oldCursorData) {
|
|
@@ -1778,6 +1803,234 @@ function setCursorData(vNode, cursorData) {
|
|
|
1778
1803
|
cursorDatas.set(vNode, cursorData);
|
|
1779
1804
|
}
|
|
1780
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
|
+
|
|
1781
2034
|
/**
|
|
1782
2035
|
* # ================================
|
|
1783
2036
|
*
|
|
@@ -2017,7 +2270,7 @@ class SignalImpl {
|
|
|
2017
2270
|
toString() {
|
|
2018
2271
|
if (isDev) {
|
|
2019
2272
|
try {
|
|
2020
|
-
return (`[${this.constructor.name}${this.$flags$ & 1 /*
|
|
2273
|
+
return (`[${this.constructor.name}${this.$flags$ & 1 /* ComputedSignalFlags.INVALID */ ? ' INVALID' : ''} ${this.$untrackedValue$}]` +
|
|
2021
2274
|
(Array.from(this.$effects$ || [])
|
|
2022
2275
|
.map((e) => '\n -> ' + pad(qwikDebugToString(e.consumer), ' '))
|
|
2023
2276
|
.join('\n') || ''));
|
|
@@ -2035,99 +2288,11 @@ class SignalImpl {
|
|
|
2035
2288
|
}
|
|
2036
2289
|
}
|
|
2037
2290
|
|
|
2038
|
-
const DEBUG
|
|
2291
|
+
const DEBUG = false;
|
|
2039
2292
|
// eslint-disable-next-line no-console
|
|
2040
|
-
const log
|
|
2041
|
-
/**
|
|
2042
|
-
|
|
2043
|
-
*
|
|
2044
|
-
* The value is available synchronously, but the computation is done lazily.
|
|
2045
|
-
*/
|
|
2046
|
-
class ComputedSignalImpl extends SignalImpl {
|
|
2047
|
-
/**
|
|
2048
|
-
* The compute function is stored here.
|
|
2049
|
-
*
|
|
2050
|
-
* The computed functions must be executed synchronously (because of this we need to eagerly
|
|
2051
|
-
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous). )
|
|
2052
|
-
*/
|
|
2053
|
-
$computeQrl$;
|
|
2054
|
-
$flags$;
|
|
2055
|
-
[_EFFECT_BACK_REF] = undefined;
|
|
2056
|
-
constructor(container, fn,
|
|
2057
|
-
// We need a separate flag to know when the computation needs running because
|
|
2058
|
-
// we need the old value to know if effects need running after computation
|
|
2059
|
-
flags = 1 /* SignalFlags.INVALID */ |
|
|
2060
|
-
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
|
|
2061
|
-
// The value is used for comparison when signals trigger, which can only happen
|
|
2062
|
-
// when it was calculated before. Therefore we can pass whatever we like.
|
|
2063
|
-
super(container || tryGetInvokeContext()?.$container$, NEEDS_COMPUTATION);
|
|
2064
|
-
this.$computeQrl$ = fn;
|
|
2065
|
-
this.$flags$ = flags;
|
|
2066
|
-
}
|
|
2067
|
-
invalidate() {
|
|
2068
|
-
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
2069
|
-
const ctx = newInvokeContext();
|
|
2070
|
-
ctx.$container$ = this.$container$ || undefined;
|
|
2071
|
-
// @ts-expect-error it's confused about args any[] vs []
|
|
2072
|
-
const running = retryOnPromise(invokeApply.bind(this, ctx, this.$computeIfNeeded$));
|
|
2073
|
-
if (running) {
|
|
2074
|
-
running.catch((err) => {
|
|
2075
|
-
if (this.$container$) {
|
|
2076
|
-
this.$container$.handleError(err, null);
|
|
2077
|
-
}
|
|
2078
|
-
else {
|
|
2079
|
-
console.error('Error during computation', err);
|
|
2080
|
-
}
|
|
2081
|
-
});
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
get untrackedValue() {
|
|
2085
|
-
this.$computeIfNeeded$();
|
|
2086
|
-
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2087
|
-
return this.$untrackedValue$;
|
|
2088
|
-
}
|
|
2089
|
-
set untrackedValue(value) {
|
|
2090
|
-
this.$untrackedValue$ = value;
|
|
2091
|
-
}
|
|
2092
|
-
$computeIfNeeded$() {
|
|
2093
|
-
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
const computeQrl = this.$computeQrl$;
|
|
2097
|
-
throwIfQRLNotResolved(computeQrl);
|
|
2098
|
-
const ctx = tryGetInvokeContext();
|
|
2099
|
-
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
2100
|
-
if (ctx) {
|
|
2101
|
-
const effectSubscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
2102
|
-
clearEffectSubscription(this.$container$, effectSubscriber);
|
|
2103
|
-
ctx.$effectSubscriber$ = effectSubscriber;
|
|
2104
|
-
}
|
|
2105
|
-
try {
|
|
2106
|
-
const untrackedValue = computeQrl.getFn(ctx)();
|
|
2107
|
-
if (isPromise(untrackedValue)) {
|
|
2108
|
-
throw qError(29 /* QError.computedNotSync */, [
|
|
2109
|
-
computeQrl.dev ? computeQrl.dev.file : '',
|
|
2110
|
-
computeQrl.$hash$,
|
|
2111
|
-
]);
|
|
2112
|
-
}
|
|
2113
|
-
DEBUG$1 && log$1('Signal.$compute$', untrackedValue);
|
|
2114
|
-
this.$flags$ &= ~1 /* SignalFlags.INVALID */;
|
|
2115
|
-
super.value = untrackedValue;
|
|
2116
|
-
}
|
|
2117
|
-
finally {
|
|
2118
|
-
if (ctx) {
|
|
2119
|
-
ctx.$effectSubscriber$ = previousEffectSubscription;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
|
|
2125
|
-
const DEBUG = false;
|
|
2126
|
-
const log = (...args) =>
|
|
2127
|
-
// eslint-disable-next-line no-console
|
|
2128
|
-
console.log('ASYNC COMPUTED SIGNAL', ...args.map(qwikDebugToString));
|
|
2129
|
-
/** Retains job metadata and also serves as the argument for the compute function */
|
|
2130
|
-
class AsyncJob {
|
|
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 {
|
|
2131
2296
|
$signal$;
|
|
2132
2297
|
/** First holds the compute promise and then the cleanup promise */
|
|
2133
2298
|
$promise$ = null;
|
|
@@ -2149,7 +2314,7 @@ class AsyncJob {
|
|
|
2149
2314
|
/** Backward compatible cache method for resource */
|
|
2150
2315
|
cache() {
|
|
2151
2316
|
isDev &&
|
|
2152
|
-
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.');
|
|
2153
2318
|
}
|
|
2154
2319
|
get previous() {
|
|
2155
2320
|
const val = this.$signal$.$untrackedValue$;
|
|
@@ -2164,46 +2329,57 @@ class AsyncJob {
|
|
|
2164
2329
|
}
|
|
2165
2330
|
}
|
|
2166
2331
|
/**
|
|
2167
|
-
*
|
|
2168
|
-
*
|
|
2169
|
-
* AsyncSignalImpl
|
|
2170
|
-
*
|
|
2171
|
-
* # ================================
|
|
2332
|
+
* A signal which is computed from other signals.
|
|
2172
2333
|
*
|
|
2173
|
-
*
|
|
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()`.
|
|
2174
2339
|
*/
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
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$;
|
|
2179
2350
|
[_EFFECT_BACK_REF] = undefined;
|
|
2180
|
-
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 */ |
|
|
2181
2355
|
16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
|
|
2182
|
-
|
|
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;
|
|
2183
2361
|
if (!options) {
|
|
2184
2362
|
return;
|
|
2185
2363
|
}
|
|
2186
|
-
//
|
|
2187
|
-
// 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
|
|
2188
2365
|
const initial = options.initial;
|
|
2189
2366
|
if (initial !== undefined) {
|
|
2190
|
-
|
|
2191
|
-
this.$untrackedValue$ = initialValue;
|
|
2367
|
+
this.$untrackedValue$ = typeof initial === 'function' ? initial() : initial;
|
|
2192
2368
|
}
|
|
2193
2369
|
const concurrency = options.concurrency;
|
|
2194
2370
|
if (concurrency !== undefined && concurrency >= 0 && concurrency !== 1) {
|
|
2195
2371
|
this.$concurrency$ = concurrency;
|
|
2196
2372
|
this.$jobs$ = [];
|
|
2197
2373
|
}
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
this.$timeoutMs$ = timeout;
|
|
2374
|
+
if (options.timeout) {
|
|
2375
|
+
this.$timeoutMs$ = options.timeout;
|
|
2201
2376
|
}
|
|
2202
2377
|
if (options.eagerCleanup) {
|
|
2203
2378
|
this.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
|
|
2204
2379
|
}
|
|
2205
2380
|
if (options.clientOnly) {
|
|
2206
|
-
|
|
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 */;
|
|
2207
2383
|
}
|
|
2208
2384
|
if (options.allowStale === false) {
|
|
2209
2385
|
if (isDev && initial !== undefined) {
|
|
@@ -2220,28 +2396,30 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2220
2396
|
this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
|
|
2221
2397
|
}
|
|
2222
2398
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
throw this.$current$?.$promise$;
|
|
2228
|
-
}
|
|
2229
|
-
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;
|
|
2230
2403
|
}
|
|
2231
|
-
if (this.$
|
|
2232
|
-
|
|
2404
|
+
if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
|
|
2405
|
+
this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
|
|
2406
|
+
return;
|
|
2233
2407
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
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
|
+
});
|
|
2240
2422
|
}
|
|
2241
|
-
return this.$untrackedValue$;
|
|
2242
|
-
}
|
|
2243
|
-
set untrackedValue(value) {
|
|
2244
|
-
this.$untrackedValue$ = value;
|
|
2245
2423
|
}
|
|
2246
2424
|
/**
|
|
2247
2425
|
* Read the value, subscribing if in a tracking context. Triggers computation if needed.
|
|
@@ -2258,32 +2436,65 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2258
2436
|
return super.value;
|
|
2259
2437
|
}
|
|
2260
2438
|
set value(value) {
|
|
2261
|
-
this.$flags$ &= -2 /*
|
|
2262
|
-
this.untrackedLoading = false;
|
|
2439
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2263
2440
|
this.untrackedError = undefined;
|
|
2264
|
-
this.$
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
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
|
+
}
|
|
2269
2449
|
}
|
|
2450
|
+
else if (this.$current$) {
|
|
2451
|
+
this.$current$.$canWrite$ = false;
|
|
2452
|
+
}
|
|
2453
|
+
this.$clearNextPoll$();
|
|
2454
|
+
super.value = value;
|
|
2455
|
+
this.$scheduleNextPoll$();
|
|
2456
|
+
return;
|
|
2270
2457
|
}
|
|
2271
|
-
else if (this.$current$) {
|
|
2272
|
-
this.$current$.$canWrite$ = false;
|
|
2273
|
-
}
|
|
2274
|
-
this.$clearNextPoll$();
|
|
2275
2458
|
super.value = value;
|
|
2276
|
-
|
|
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;
|
|
2277
2485
|
}
|
|
2278
2486
|
/**
|
|
2279
2487
|
* Loading is true if the signal is still waiting for the promise to resolve, false if the promise
|
|
2280
|
-
* has resolved or rejected.
|
|
2488
|
+
* has resolved or rejected (or the compute function is synchronous).
|
|
2281
2489
|
*
|
|
2282
|
-
* Accessing
|
|
2283
|
-
*
|
|
2490
|
+
* Accessing `.pending` will trigger computation if needed, since it's often used like
|
|
2491
|
+
*
|
|
2492
|
+
* ```ts
|
|
2493
|
+
* signal.pending ? <Loading /> : signal.value
|
|
2494
|
+
* ```
|
|
2284
2495
|
*/
|
|
2285
|
-
get
|
|
2286
|
-
const val = this.
|
|
2496
|
+
get pending() {
|
|
2497
|
+
const val = this.untrackedPending;
|
|
2287
2498
|
const ctx = tryGetInvokeContext();
|
|
2288
2499
|
if (ctx && (this.$container$ ||= ctx.$container$ || null)) {
|
|
2289
2500
|
isDev &&
|
|
@@ -2297,22 +2508,41 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2297
2508
|
}
|
|
2298
2509
|
return val;
|
|
2299
2510
|
}
|
|
2300
|
-
set
|
|
2301
|
-
if (value !== this.$
|
|
2302
|
-
this.$
|
|
2511
|
+
set untrackedPending(value) {
|
|
2512
|
+
if (value !== !!this.$untrackedPending$) {
|
|
2513
|
+
this.$untrackedPending$ = value;
|
|
2303
2514
|
scheduleEffects(this.$container$, this, this.$loadingEffects$);
|
|
2304
2515
|
}
|
|
2305
2516
|
}
|
|
2306
|
-
get
|
|
2517
|
+
get untrackedPending() {
|
|
2307
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.
|
|
2308
2519
|
this.$computeIfNeeded$();
|
|
2309
2520
|
// During SSR there's no such thing as loading state, we must render complete results
|
|
2310
2521
|
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2311
2522
|
throw this.$current$?.$promise$;
|
|
2312
2523
|
}
|
|
2313
|
-
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;
|
|
2314
2533
|
}
|
|
2315
|
-
|
|
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
|
+
*/
|
|
2316
2546
|
get error() {
|
|
2317
2547
|
const val = this.untrackedError;
|
|
2318
2548
|
const ctx = tryGetInvokeContext();
|
|
@@ -2335,6 +2565,11 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2335
2565
|
}
|
|
2336
2566
|
}
|
|
2337
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
|
+
}
|
|
2338
2573
|
return this.$untrackedError$;
|
|
2339
2574
|
}
|
|
2340
2575
|
get expires() {
|
|
@@ -2377,16 +2612,8 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2377
2612
|
}
|
|
2378
2613
|
this.expires = Math.abs(value);
|
|
2379
2614
|
}
|
|
2380
|
-
/** Invalidates the signal, causing it to re-compute its value. */
|
|
2381
|
-
async invalidate(info) {
|
|
2382
|
-
if (arguments.length > 0) {
|
|
2383
|
-
this.$info$ = info;
|
|
2384
|
-
this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
|
|
2385
|
-
}
|
|
2386
|
-
this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
|
|
2387
|
-
}
|
|
2388
2615
|
$setInvalid$(allowRecalc, mustClear) {
|
|
2389
|
-
this.$flags$ |= 1 /*
|
|
2616
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2390
2617
|
this.$clearNextPoll$();
|
|
2391
2618
|
if (mustClear) {
|
|
2392
2619
|
this.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
@@ -2427,19 +2654,97 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2427
2654
|
}
|
|
2428
2655
|
/** Run the computation if needed */
|
|
2429
2656
|
$computeIfNeeded$() {
|
|
2430
|
-
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));
|
|
2431
2702
|
return;
|
|
2432
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$() {
|
|
2433
2738
|
// Skip computation on SSR for clientOnly signals
|
|
2434
2739
|
if ((qTest ? isServerPlatform() : isServer) && this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
2435
2740
|
// We must pretend to load, and register as a listener for the captures
|
|
2436
|
-
this.$
|
|
2741
|
+
this.$untrackedPending$ = true;
|
|
2437
2742
|
this.$container$?.serializationCtx.$eagerResume$.add(this);
|
|
2438
2743
|
return;
|
|
2439
2744
|
}
|
|
2440
2745
|
this.$clearNextPoll$();
|
|
2441
2746
|
// Clear flag here to make sure the cleanups don't start another compute
|
|
2442
|
-
this.$flags$ &= -2 /*
|
|
2747
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2443
2748
|
const current = this.$current$;
|
|
2444
2749
|
if (current) {
|
|
2445
2750
|
this.$requestCleanups$(current);
|
|
@@ -2449,12 +2754,12 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2449
2754
|
if (this.$jobs$ ? this.$jobs$.length >= limit : current?.$promise$) {
|
|
2450
2755
|
// We requested cleanups for all the previous jobs, once one finishes it will be removed from the jobs array and trigger computeIfNeeded
|
|
2451
2756
|
// Restore invalid state
|
|
2452
|
-
this.$flags$ |= 1 /*
|
|
2757
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
2453
2758
|
return;
|
|
2454
2759
|
}
|
|
2455
2760
|
// We put the actual computation in a separate method so we can easily retain the promise
|
|
2456
2761
|
const infoVersion = this.$infoVersion$;
|
|
2457
|
-
const running = new
|
|
2762
|
+
const running = new Job(this, this.$info$, infoVersion);
|
|
2458
2763
|
this.$current$ = running;
|
|
2459
2764
|
if (this.$jobs$) {
|
|
2460
2765
|
this.$jobs$.push(running);
|
|
@@ -2462,35 +2767,39 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2462
2767
|
running.$promise$ = this.$runComputation$(running);
|
|
2463
2768
|
}
|
|
2464
2769
|
async $runComputation$(running) {
|
|
2465
|
-
const isCurrent = () => running === this.$current$;
|
|
2466
2770
|
let fn = this.$computeQrl$.resolved;
|
|
2467
2771
|
if (!fn) {
|
|
2468
2772
|
// QRL resolution is async — we have to publish loading=true before awaiting so
|
|
2469
2773
|
// subscribers know the value isn't ready yet.
|
|
2470
|
-
this.
|
|
2774
|
+
this.untrackedPending = true;
|
|
2471
2775
|
fn = await this.$computeQrl$.resolve();
|
|
2472
2776
|
if (running.$abortController$?.signal.aborted) {
|
|
2473
2777
|
running.$promise$ = null;
|
|
2474
2778
|
return;
|
|
2475
2779
|
}
|
|
2476
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$;
|
|
2477
2793
|
try {
|
|
2478
|
-
if (this.$timeoutMs$) {
|
|
2479
|
-
this.$computationTimeoutId$ = setTimeout(() => {
|
|
2480
|
-
const error = new Error(`timeout ${this.$timeoutMs$}ms`);
|
|
2481
|
-
this.$setError$(running, error);
|
|
2482
|
-
running.$abortController$?.abort(error);
|
|
2483
|
-
}, this.$timeoutMs$);
|
|
2484
|
-
}
|
|
2485
2794
|
// Try to stay sync if possible. Only publish loading=true to subscribers when
|
|
2486
2795
|
// the compute is actually asynchronous — a synchronous resolve (e.g. pre-loaded
|
|
2487
2796
|
// values injected via _injectAsyncSignalValue) should never transition through a
|
|
2488
2797
|
// visible loading state, which on SSR would fire the loading-effect subscribers
|
|
2489
2798
|
// (tasks) while the value is still "loading" from their perspective.
|
|
2490
|
-
const valuePromise =
|
|
2799
|
+
const valuePromise = compute();
|
|
2491
2800
|
let value;
|
|
2492
2801
|
if (isPromise(valuePromise)) {
|
|
2493
|
-
this.
|
|
2802
|
+
this.untrackedPending = true;
|
|
2494
2803
|
value = await valuePromise;
|
|
2495
2804
|
}
|
|
2496
2805
|
else {
|
|
@@ -2515,7 +2824,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2515
2824
|
// Note that these assignments run setters
|
|
2516
2825
|
this.untrackedError = undefined;
|
|
2517
2826
|
/**
|
|
2518
|
-
* Use
|
|
2827
|
+
* Use SignalImpl.value instead of this.value to persist invalid state, so that invalidation
|
|
2519
2828
|
* during computation recomputes
|
|
2520
2829
|
*/
|
|
2521
2830
|
super.value = value;
|
|
@@ -2530,370 +2839,130 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2530
2839
|
if (running.$infoVersion$ === this.$infoVersion$) {
|
|
2531
2840
|
this.$info$ = undefined;
|
|
2532
2841
|
}
|
|
2533
|
-
if (this.$flags$ & 1 /*
|
|
2842
|
+
if (this.$flags$ & 1 /* ComputedSignalFlags.INVALID */) {
|
|
2534
2843
|
// we became invalid again while running, so we need to re-run the computation to get the new promise
|
|
2535
2844
|
this.$computeIfNeeded$();
|
|
2536
2845
|
}
|
|
2537
|
-
else {
|
|
2538
|
-
this.
|
|
2539
|
-
this.$scheduleNextPoll$();
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
/**
|
|
2544
|
-
* Sets the error from the given job. We only accept errors from the current job and we ignore
|
|
2545
|
-
* AbortErrors.
|
|
2546
|
-
*/
|
|
2547
|
-
$setError$(job, error) {
|
|
2548
|
-
if (job !== this.$current$ || !job.$canWrite$) {
|
|
2549
|
-
return;
|
|
2550
|
-
}
|
|
2551
|
-
job.$canWrite$ = false;
|
|
2552
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
2553
|
-
// AbortError from AbortSignal is a cancellation, not an actual error
|
|
2554
|
-
return;
|
|
2555
|
-
}
|
|
2556
|
-
this.untrackedError = error;
|
|
2557
|
-
// Job failures should be rare and require retrying
|
|
2558
|
-
this.untrackedValue = NEEDS_COMPUTATION;
|
|
2559
|
-
}
|
|
2560
|
-
/** Called after SSR/unmount */
|
|
2561
|
-
async $destroy$() {
|
|
2562
|
-
this.$clearNextPoll$();
|
|
2563
|
-
clearTimeout(this.$computationTimeoutId$);
|
|
2564
|
-
const current = this.$current$;
|
|
2565
|
-
if (current) {
|
|
2566
|
-
this.$requestCleanups$(current);
|
|
2567
|
-
}
|
|
2568
|
-
if (this.$jobs$) {
|
|
2569
|
-
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2570
|
-
}
|
|
2571
|
-
else {
|
|
2572
|
-
await current?.$promise$;
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
$clearNextPoll$() {
|
|
2576
|
-
if (this.$pollTimeoutId$ !== undefined) {
|
|
2577
|
-
clearTimeout(this.$pollTimeoutId$);
|
|
2578
|
-
this.$pollTimeoutId$ = undefined;
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
$scheduleNextPoll$() {
|
|
2582
|
-
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2583
|
-
return;
|
|
2584
|
-
}
|
|
2585
|
-
this.$clearNextPoll$();
|
|
2586
|
-
const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
|
|
2587
|
-
// Even when clear on invalidate, we don't clear if we're merely re-running due to polling
|
|
2588
|
-
// We expect to get the new value soon, so we can avoid showing a loading state
|
|
2589
|
-
const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
|
|
2590
|
-
this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
|
|
2591
|
-
this.$pollTimeoutId$?.unref?.();
|
|
2592
|
-
}
|
|
2593
|
-
$hasSubscribers$() {
|
|
2594
|
-
return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
|
|
2595
|
-
}
|
|
2596
|
-
$requestCleanups$(job, reason) {
|
|
2597
|
-
if (job.$cleanupRequested$) {
|
|
2598
|
-
return;
|
|
2599
|
-
}
|
|
2600
|
-
job.$cleanupRequested$ = true;
|
|
2601
|
-
job.$abortController$?.abort(reason);
|
|
2602
|
-
job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
|
|
2603
|
-
}
|
|
2604
|
-
/** Clean up and trigger signal compute once complete */
|
|
2605
|
-
$runCleanups$(job) {
|
|
2606
|
-
const cleanups = job.$cleanups$;
|
|
2607
|
-
const onError = (err) => {
|
|
2608
|
-
const handleError = this.$container$?.handleError;
|
|
2609
|
-
if (handleError) {
|
|
2610
|
-
handleError(err, null);
|
|
2611
|
-
}
|
|
2612
|
-
else {
|
|
2613
|
-
console.error('Error in async signal cleanup', err);
|
|
2614
|
-
}
|
|
2615
|
-
};
|
|
2616
|
-
const onDone = () => {
|
|
2617
|
-
job.$promise$ = null;
|
|
2618
|
-
if (cleanups) {
|
|
2619
|
-
cleanups.length = 0;
|
|
2620
|
-
}
|
|
2621
|
-
// Now trigger compute
|
|
2622
|
-
const jobs = this.$jobs$;
|
|
2623
|
-
if (jobs) {
|
|
2624
|
-
const idx = jobs.indexOf(job);
|
|
2625
|
-
if (idx !== -1) {
|
|
2626
|
-
jobs.splice(idx, 1);
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
this.$computeIfNeeded$();
|
|
2630
|
-
};
|
|
2631
|
-
let promiseChain = undefined;
|
|
2632
|
-
if (cleanups) {
|
|
2633
|
-
// Keep this sync-ish so sync functions run immediately.
|
|
2634
|
-
for (let i = 0; i < cleanups.length; i++) {
|
|
2635
|
-
try {
|
|
2636
|
-
const result = cleanups[i]();
|
|
2637
|
-
if (isPromise(result)) {
|
|
2638
|
-
promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
catch (err) {
|
|
2642
|
-
onError(err);
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
}
|
|
2646
|
-
if (promiseChain) {
|
|
2647
|
-
return promiseChain.then(onDone);
|
|
2648
|
-
}
|
|
2649
|
-
else {
|
|
2650
|
-
onDone();
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
/**
|
|
2655
|
-
* Inject a pre-loaded value into an AsyncSignal while preserving track() subscriptions. Calls
|
|
2656
|
-
* `invalidate({ __v })` so the compute function reads the value from `info`, then triggers an
|
|
2657
|
-
* immediate synchronous compute via the private $computeIfNeeded$() method (which is mangled in
|
|
2658
|
-
* core builds, so callers from other packages must go through this helper).
|
|
2659
|
-
*
|
|
2660
|
-
* @internal
|
|
2661
|
-
*/
|
|
2662
|
-
const _injectAsyncSignalValue = (signal, value) => {
|
|
2663
|
-
const impl = signal;
|
|
2664
|
-
impl.invalidate({ __v: value });
|
|
2665
|
-
impl.$computeIfNeeded$();
|
|
2666
|
-
};
|
|
2667
|
-
|
|
2668
|
-
/** @internal */
|
|
2669
|
-
const _CONST_PROPS = Symbol('CONST');
|
|
2670
|
-
/** @internal */
|
|
2671
|
-
const _VAR_PROPS = Symbol('VAR');
|
|
2672
|
-
/** @internal */
|
|
2673
|
-
const _OWNER = Symbol('OWNER');
|
|
2674
|
-
/** @internal */
|
|
2675
|
-
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
2676
|
-
/** @internal @deprecated v1 compat */
|
|
2677
|
-
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
2678
|
-
/** @internal */
|
|
2679
|
-
const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
2680
|
-
|
|
2681
|
-
/** @internal */
|
|
2682
|
-
const EMPTY_ARRAY = [];
|
|
2683
|
-
/** @internal */
|
|
2684
|
-
const EMPTY_OBJ = {};
|
|
2685
|
-
Object.freeze(EMPTY_ARRAY);
|
|
2686
|
-
Object.freeze(EMPTY_OBJ);
|
|
2687
|
-
|
|
2688
|
-
function createPropsProxy(owner) {
|
|
2689
|
-
// TODO don't make a proxy but populate getters? benchmark
|
|
2690
|
-
return new Proxy({}, new PropsProxyHandler(owner));
|
|
2691
|
-
}
|
|
2692
|
-
class PropsProxyHandler {
|
|
2693
|
-
owner;
|
|
2694
|
-
$effects$ = undefined;
|
|
2695
|
-
$container$ = null;
|
|
2696
|
-
constructor(owner) {
|
|
2697
|
-
this.owner = owner;
|
|
2698
|
-
}
|
|
2699
|
-
get(_, prop) {
|
|
2700
|
-
// escape hatch to get the separated props from a component
|
|
2701
|
-
if (prop === _CONST_PROPS) {
|
|
2702
|
-
return this.owner.constProps;
|
|
2703
|
-
}
|
|
2704
|
-
else if (prop === _VAR_PROPS) {
|
|
2705
|
-
return this.owner.varProps;
|
|
2706
|
-
}
|
|
2707
|
-
else if (prop === _OWNER) {
|
|
2708
|
-
return this.owner;
|
|
2709
|
-
}
|
|
2710
|
-
else if (prop === _PROPS_HANDLER) {
|
|
2711
|
-
return this;
|
|
2712
|
-
}
|
|
2713
|
-
let value;
|
|
2714
|
-
if (prop === 'children') {
|
|
2715
|
-
value = this.owner.children;
|
|
2716
|
-
}
|
|
2717
|
-
else {
|
|
2718
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2719
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2720
|
-
if (attr) {
|
|
2721
|
-
prop = attr;
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
value = directGetPropsProxyProp(this.owner, prop);
|
|
2725
|
-
if (prop in this.owner.varProps) {
|
|
2726
|
-
addPropsProxyEffect(this, prop);
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
// a proxied value that the optimizer made
|
|
2730
|
-
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
2731
|
-
? value.value
|
|
2732
|
-
: value;
|
|
2733
|
-
}
|
|
2734
|
-
set(_, prop, value) {
|
|
2735
|
-
if (prop === _OWNER) {
|
|
2736
|
-
// used for deserialization
|
|
2737
|
-
this.owner = value;
|
|
2738
|
-
}
|
|
2739
|
-
else if (prop === 'children') {
|
|
2740
|
-
this.owner.children = value;
|
|
2741
|
-
}
|
|
2742
|
-
else if (prop === _CONST_PROPS) {
|
|
2743
|
-
this.owner.constProps = value;
|
|
2744
|
-
}
|
|
2745
|
-
else if (prop === _VAR_PROPS) {
|
|
2746
|
-
this.owner.varProps = value;
|
|
2747
|
-
}
|
|
2748
|
-
else {
|
|
2749
|
-
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
2750
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2751
|
-
if (attr) {
|
|
2752
|
-
prop = attr;
|
|
2753
|
-
}
|
|
2754
|
-
}
|
|
2755
|
-
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
2756
|
-
// delete the prop from the const props first
|
|
2757
|
-
delete this.owner.constProps[prop];
|
|
2758
|
-
}
|
|
2759
|
-
if (this.owner.varProps === EMPTY_OBJ) {
|
|
2760
|
-
this.owner.varProps = {};
|
|
2761
|
-
}
|
|
2762
|
-
else if (!(prop in this.owner.varProps)) {
|
|
2763
|
-
this.owner.toSort = true;
|
|
2764
|
-
}
|
|
2765
|
-
if (this.owner.varProps[prop] !== value) {
|
|
2766
|
-
this.owner.varProps[prop] = value;
|
|
2767
|
-
triggerPropsProxyEffect(this, prop);
|
|
2846
|
+
else {
|
|
2847
|
+
this.untrackedPending = false;
|
|
2848
|
+
this.$scheduleNextPoll$();
|
|
2768
2849
|
}
|
|
2769
2850
|
}
|
|
2770
|
-
return true;
|
|
2771
2851
|
}
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
if (this
|
|
2778
|
-
|
|
2852
|
+
/**
|
|
2853
|
+
* Sets the error from the given job. We only accept errors from the current job and we ignore
|
|
2854
|
+
* AbortErrors.
|
|
2855
|
+
*/
|
|
2856
|
+
$setError$(job, error) {
|
|
2857
|
+
if (job !== this.$current$ || !job.$canWrite$) {
|
|
2858
|
+
return;
|
|
2779
2859
|
}
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2860
|
+
job.$canWrite$ = false;
|
|
2861
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
2862
|
+
// AbortError from AbortSignal is a cancellation, not an actual error
|
|
2863
|
+
return;
|
|
2783
2864
|
}
|
|
2784
|
-
|
|
2865
|
+
this.untrackedError = error;
|
|
2866
|
+
// Job failures should be rare and require retrying
|
|
2867
|
+
this.untrackedValue = NEEDS_COMPUTATION;
|
|
2785
2868
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2869
|
+
/** Called after SSR/unmount */
|
|
2870
|
+
async $destroy$() {
|
|
2871
|
+
this.$clearNextPoll$();
|
|
2872
|
+
clearTimeout(this.$computationTimeoutId$);
|
|
2873
|
+
const current = this.$current$;
|
|
2874
|
+
if (current) {
|
|
2875
|
+
this.$requestCleanups$(current);
|
|
2789
2876
|
}
|
|
2790
|
-
|
|
2791
|
-
|
|
2877
|
+
if (this.$jobs$) {
|
|
2878
|
+
await Promise.all(this.$jobs$.map((job) => job.$promise$));
|
|
2792
2879
|
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
if (inVarProps) {
|
|
2796
|
-
addPropsProxyEffect(this, prop);
|
|
2797
|
-
}
|
|
2798
|
-
if (typeof this.owner.type === 'string') {
|
|
2799
|
-
const attr = jsxEventToHtmlAttribute(prop);
|
|
2800
|
-
if (attr) {
|
|
2801
|
-
prop = attr;
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2880
|
+
else {
|
|
2881
|
+
await current?.$promise$;
|
|
2804
2882
|
}
|
|
2805
|
-
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
2806
2883
|
}
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
: this.owner.varProps[p];
|
|
2813
|
-
return {
|
|
2814
|
-
configurable: true,
|
|
2815
|
-
enumerable: true,
|
|
2816
|
-
value: value,
|
|
2817
|
-
};
|
|
2884
|
+
$clearNextPoll$() {
|
|
2885
|
+
if (this.$pollTimeoutId$ !== undefined) {
|
|
2886
|
+
clearTimeout(this.$pollTimeoutId$);
|
|
2887
|
+
this.$pollTimeoutId$ = undefined;
|
|
2888
|
+
}
|
|
2818
2889
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
out.push('children');
|
|
2890
|
+
$scheduleNextPoll$() {
|
|
2891
|
+
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2892
|
+
return;
|
|
2823
2893
|
}
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
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;
|
|
2908
|
+
}
|
|
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);
|
|
2920
|
+
}
|
|
2921
|
+
else {
|
|
2922
|
+
console.error('Error in async signal cleanup', err);
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
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);
|
|
2828
2937
|
}
|
|
2829
2938
|
}
|
|
2939
|
+
cleanups.length = 0;
|
|
2830
2940
|
}
|
|
2831
|
-
return
|
|
2941
|
+
return promiseChain;
|
|
2832
2942
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
if (
|
|
2840
|
-
|
|
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
|
+
}
|
|
2841
2954
|
}
|
|
2955
|
+
this.$computeIfNeeded$();
|
|
2956
|
+
};
|
|
2957
|
+
const promiseChain = this.$runCleanupCallbacks$(job);
|
|
2958
|
+
if (promiseChain) {
|
|
2959
|
+
return promiseChain.then(onDone);
|
|
2842
2960
|
}
|
|
2843
2961
|
else {
|
|
2844
|
-
|
|
2845
|
-
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
2962
|
+
onDone();
|
|
2846
2963
|
}
|
|
2847
2964
|
}
|
|
2848
|
-
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
2849
|
-
if (effectSubscriber) {
|
|
2850
|
-
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
2851
|
-
}
|
|
2852
|
-
};
|
|
2853
|
-
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
2854
|
-
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
2855
|
-
if (effects) {
|
|
2856
|
-
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
2857
|
-
}
|
|
2858
|
-
return !!effects;
|
|
2859
|
-
};
|
|
2860
|
-
function getEffects$1(effects, prop) {
|
|
2861
|
-
// TODO: Handle STORE_ALL_PROPS
|
|
2862
|
-
return effects?.get(prop);
|
|
2863
2965
|
}
|
|
2864
|
-
/**
|
|
2865
|
-
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
2866
|
-
* Use this function to get the props directly from a const or var props.
|
|
2867
|
-
*
|
|
2868
|
-
* This does not convert jsx event names.
|
|
2869
|
-
*/
|
|
2870
|
-
const directGetPropsProxyProp = (jsx, prop) => {
|
|
2871
|
-
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
2872
|
-
};
|
|
2873
|
-
const _getProps = (props, prop) => {
|
|
2874
|
-
return _getVarProps(props)?.[prop] || _getConstProps(props)?.[prop] || null;
|
|
2875
|
-
};
|
|
2876
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2877
|
-
const _getVarProps = (props) => {
|
|
2878
|
-
if (!props) {
|
|
2879
|
-
return null;
|
|
2880
|
-
}
|
|
2881
|
-
return _VAR_PROPS in props
|
|
2882
|
-
? 'children' in props
|
|
2883
|
-
? { ...props[_VAR_PROPS], children: props.children }
|
|
2884
|
-
: props[_VAR_PROPS]
|
|
2885
|
-
: props;
|
|
2886
|
-
};
|
|
2887
|
-
/** Used by the optimizer for spread props operations @internal */
|
|
2888
|
-
const _getConstProps = (props) => {
|
|
2889
|
-
if (!props) {
|
|
2890
|
-
return null;
|
|
2891
|
-
}
|
|
2892
|
-
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
2893
|
-
};
|
|
2894
|
-
const isPropsProxy = (obj) => {
|
|
2895
|
-
return obj && _VAR_PROPS in obj;
|
|
2896
|
-
};
|
|
2897
2966
|
|
|
2898
2967
|
// <docs markdown="../../readme.md#implicit$FirstArg">
|
|
2899
2968
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
@@ -2949,11 +3018,11 @@ const implicit$FirstArg = (fn) => {
|
|
|
2949
3018
|
*/
|
|
2950
3019
|
class SerializerSignalImpl extends ComputedSignalImpl {
|
|
2951
3020
|
constructor(container, argQrl) {
|
|
2952
|
-
super(container, argQrl, 1 /*
|
|
3021
|
+
super(container, argQrl, 1 /* ComputedSignalFlags.INVALID */ | 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
|
|
2953
3022
|
}
|
|
2954
3023
|
$didInitialize$ = false;
|
|
2955
3024
|
$computeIfNeeded$() {
|
|
2956
|
-
if (!(this.$flags$ & 1 /*
|
|
3025
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
2957
3026
|
return;
|
|
2958
3027
|
}
|
|
2959
3028
|
throwIfQRLNotResolved(this.$computeQrl$);
|
|
@@ -2966,7 +3035,7 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2966
3035
|
: deserialize(currentValue), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
2967
3036
|
this.$didInitialize$ = true;
|
|
2968
3037
|
// Needs to invalidate only after all possible Promise throws happened
|
|
2969
|
-
this.$flags$ &= -2 /*
|
|
3038
|
+
this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
2970
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.
|
|
2971
3040
|
const didChange = (this.$didInitialize$ && untrackedValue !== 'undefined') ||
|
|
2972
3041
|
untrackedValue !== this.$untrackedValue$;
|
|
@@ -2977,13 +3046,46 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
2977
3046
|
}
|
|
2978
3047
|
}
|
|
2979
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
|
+
|
|
2980
3082
|
/** @internal */
|
|
2981
3083
|
const createSignal$1 = (value) => {
|
|
2982
3084
|
return new SignalImpl(null, value);
|
|
2983
3085
|
};
|
|
2984
3086
|
/** @internal */
|
|
2985
3087
|
const createComputedSignal = (qrl, options) => {
|
|
2986
|
-
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'));
|
|
3088
|
+
return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'), options);
|
|
2987
3089
|
};
|
|
2988
3090
|
/** @internal */
|
|
2989
3091
|
const createAsyncSignal = (qrl, options) => {
|
|
@@ -3007,9 +3109,10 @@ const createSignal = createSignal$1;
|
|
|
3007
3109
|
* recalculated.
|
|
3008
3110
|
*
|
|
3009
3111
|
* The QRL must be a function which returns the value of the signal. The function must not have side
|
|
3010
|
-
* effects
|
|
3011
|
-
*
|
|
3012
|
-
*
|
|
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.
|
|
3013
3116
|
*
|
|
3014
3117
|
* @public
|
|
3015
3118
|
*/
|
|
@@ -3018,6 +3121,7 @@ const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedSignal);
|
|
|
3018
3121
|
* Create a signal holding a `.value` which is calculated from the given async function (QRL). The
|
|
3019
3122
|
* standalone version of `useAsync$`.
|
|
3020
3123
|
*
|
|
3124
|
+
* @deprecated Use `createComputed$` instead, it has async support now.
|
|
3021
3125
|
* @public
|
|
3022
3126
|
*/
|
|
3023
3127
|
const createAsync$ = /*#__PURE__*/ implicit$FirstArg(createAsyncSignal);
|
|
@@ -3064,10 +3168,10 @@ const _wrapProp = (...args) => {
|
|
|
3064
3168
|
return obj[prop];
|
|
3065
3169
|
}
|
|
3066
3170
|
if (isSignal(obj)) {
|
|
3067
|
-
if (!(obj instanceof
|
|
3171
|
+
if (!(obj instanceof ComputedSignalImpl)) {
|
|
3068
3172
|
isDev && assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
3069
3173
|
}
|
|
3070
|
-
if (obj instanceof WrappedSignalImpl
|
|
3174
|
+
if (obj instanceof WrappedSignalImpl) {
|
|
3071
3175
|
return obj;
|
|
3072
3176
|
}
|
|
3073
3177
|
return getWrapped(args);
|
|
@@ -3121,7 +3225,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3121
3225
|
constructor(container, fn, args, fnStr,
|
|
3122
3226
|
// We need a separate flag to know when the computation needs running because
|
|
3123
3227
|
// we need the old value to know if effects need running after computation
|
|
3124
|
-
flags = 1 /*
|
|
3228
|
+
flags = 1 /* ComputedSignalFlags.INVALID */) {
|
|
3125
3229
|
super(container, NEEDS_COMPUTATION);
|
|
3126
3230
|
this.$args$ = args;
|
|
3127
3231
|
this.$func$ = fn;
|
|
@@ -3129,7 +3233,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3129
3233
|
this.$flags$ = flags;
|
|
3130
3234
|
}
|
|
3131
3235
|
invalidate() {
|
|
3132
|
-
this.$flags$ |= 1 /*
|
|
3236
|
+
this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
3133
3237
|
// we are trying to run computation without creating a chore, which can be expensive
|
|
3134
3238
|
// for many signals. If it fails, we schedule a chore to run the computation.
|
|
3135
3239
|
try {
|
|
@@ -3142,8 +3246,8 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3142
3246
|
}
|
|
3143
3247
|
}
|
|
3144
3248
|
// if the computation not failed, we can run the effects directly
|
|
3145
|
-
if (this.$flags$ & 2 /*
|
|
3146
|
-
this.$flags$ &= -3 /*
|
|
3249
|
+
if (this.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
3250
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3147
3251
|
scheduleEffects(this.$container$, this, this.$effects$);
|
|
3148
3252
|
}
|
|
3149
3253
|
}
|
|
@@ -3153,7 +3257,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3153
3257
|
return this.$untrackedValue$;
|
|
3154
3258
|
}
|
|
3155
3259
|
$computeIfNeeded$() {
|
|
3156
|
-
if (!(this.$flags$ & 1 /*
|
|
3260
|
+
if (!(this.$flags$ & 1 /* ComputedSignalFlags.INVALID */)) {
|
|
3157
3261
|
return;
|
|
3158
3262
|
}
|
|
3159
3263
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
@@ -3164,10 +3268,10 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
3164
3268
|
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
3165
3269
|
// reset flag in case we call computedIfNeeded twice and the value was changed only the first time
|
|
3166
3270
|
// TODO: change to version number?
|
|
3167
|
-
this.$flags$ &= -3 /*
|
|
3271
|
+
this.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3168
3272
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
3169
3273
|
if (didChange) {
|
|
3170
|
-
this.$flags$ |= 2 /*
|
|
3274
|
+
this.$flags$ |= 2 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
3171
3275
|
this.$untrackedValue$ = untrackedValue;
|
|
3172
3276
|
}
|
|
3173
3277
|
}
|
|
@@ -3271,12 +3375,15 @@ const isJSXNode = (n) => {
|
|
|
3271
3375
|
* load the QRL captured scope ourselves. Otherwise, we are being called as a QRL and the captures
|
|
3272
3376
|
* are already set.
|
|
3273
3377
|
*/
|
|
3274
|
-
const
|
|
3275
|
-
if (typeof
|
|
3378
|
+
const withScopeFromQL = (captureDeltas, element, callback) => {
|
|
3379
|
+
if (typeof captureDeltas === 'string') {
|
|
3276
3380
|
const container = getDomContainer(element);
|
|
3277
|
-
|
|
3381
|
+
return whenContainerDataReady(container, () => {
|
|
3382
|
+
setCaptures(deserializeCaptureDeltas(container, captureDeltas));
|
|
3383
|
+
return callback();
|
|
3384
|
+
});
|
|
3278
3385
|
}
|
|
3279
|
-
return
|
|
3386
|
+
return callback();
|
|
3280
3387
|
};
|
|
3281
3388
|
/**
|
|
3282
3389
|
* Handles events for bind:value
|
|
@@ -3284,9 +3391,10 @@ const maybeScopeFromQL = (captureIds, element) => {
|
|
|
3284
3391
|
* @internal
|
|
3285
3392
|
*/
|
|
3286
3393
|
function _val(_, element) {
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3394
|
+
return withScopeFromQL(this, element, () => {
|
|
3395
|
+
const signal = _captures[0];
|
|
3396
|
+
signal.value = element.type === 'number' ? element.valueAsNumber : element.value;
|
|
3397
|
+
});
|
|
3290
3398
|
}
|
|
3291
3399
|
/**
|
|
3292
3400
|
* Handles events for bind:checked
|
|
@@ -3294,9 +3402,10 @@ function _val(_, element) {
|
|
|
3294
3402
|
* @internal
|
|
3295
3403
|
*/
|
|
3296
3404
|
function _chk(_, element) {
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3405
|
+
return withScopeFromQL(this, element, () => {
|
|
3406
|
+
const signal = _captures[0];
|
|
3407
|
+
signal.value = element.checked;
|
|
3408
|
+
});
|
|
3300
3409
|
}
|
|
3301
3410
|
/**
|
|
3302
3411
|
* Resumes selected state (e.g. polling AsyncSignals) by deserializing captures. Used for
|
|
@@ -3305,17 +3414,18 @@ function _chk(_, element) {
|
|
|
3305
3414
|
* @internal
|
|
3306
3415
|
*/
|
|
3307
3416
|
function _res(_, element) {
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
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
|
|
3315
3426
|
}
|
|
3316
|
-
// note that polling async signals will automatically schedule themselves so no action needed
|
|
3317
3427
|
}
|
|
3318
|
-
}
|
|
3428
|
+
});
|
|
3319
3429
|
}
|
|
3320
3430
|
|
|
3321
3431
|
const BIND_VALUE = 'bind:value';
|
|
@@ -4095,7 +4205,8 @@ function runEventHandlerQRL(handler, event, element, ctx) {
|
|
|
4095
4205
|
return;
|
|
4096
4206
|
}
|
|
4097
4207
|
if (!ctx) {
|
|
4098
|
-
|
|
4208
|
+
const container = getDomContainer(element);
|
|
4209
|
+
return whenContainerDataReady(container, () => runEventHandlerQRL(handler, event, element, newInvokeContextFromDOM(event, element, container)));
|
|
4099
4210
|
}
|
|
4100
4211
|
const container = ctx.$container$;
|
|
4101
4212
|
const hostElement = ctx.$hostElement$;
|
|
@@ -4136,13 +4247,16 @@ function _run(event, element) {
|
|
|
4136
4247
|
// ignore events on disconnected elements, this can happen when the event is triggered while the element is being removed
|
|
4137
4248
|
return;
|
|
4138
4249
|
}
|
|
4139
|
-
const
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
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
|
+
});
|
|
4146
4260
|
}
|
|
4147
4261
|
|
|
4148
4262
|
function peekNextSibling(vCurrent) {
|
|
@@ -4303,9 +4417,7 @@ function diff(diffContext, jsxNode, vStartNode, vCurrent = vnode_getFirstChild(v
|
|
|
4303
4417
|
else if (type === Projection) {
|
|
4304
4418
|
expectProjection(diffContext);
|
|
4305
4419
|
descend(diffContext, diffContext.$jsxValue$.children, true,
|
|
4306
|
-
|
|
4307
|
-
// because the projection's children are not removed
|
|
4308
|
-
false);
|
|
4420
|
+
/* isProjection */ true);
|
|
4309
4421
|
}
|
|
4310
4422
|
else if (type === SSRComment) {
|
|
4311
4423
|
expectNoMore(diffContext);
|
|
@@ -4418,9 +4530,11 @@ function advance(diffContext) {
|
|
|
4418
4530
|
*
|
|
4419
4531
|
* In the above example all nodes are on same level so we don't `descendVNode` even thought there is
|
|
4420
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.
|
|
4421
4535
|
*/
|
|
4422
|
-
function descend(diffContext, children, descendVNode,
|
|
4423
|
-
if (
|
|
4536
|
+
function descend(diffContext, children, descendVNode, isProjection = false) {
|
|
4537
|
+
if (!isProjection &&
|
|
4424
4538
|
(children == null || (descendVNode && isArray(children) && children.length === 0))) {
|
|
4425
4539
|
expectNoChildren(diffContext);
|
|
4426
4540
|
return;
|
|
@@ -4429,7 +4543,10 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
4429
4543
|
if (descendVNode) {
|
|
4430
4544
|
isDev &&
|
|
4431
4545
|
assertDefined(diffContext.$vCurrent$ || diffContext.$vNewNode$, 'Expecting vCurrent to be defined.');
|
|
4432
|
-
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$) ||
|
|
4433
4550
|
!!diffContext.$vNewNode$ ||
|
|
4434
4551
|
!vnode_getFirstChild(diffContext.$vCurrent$);
|
|
4435
4552
|
diffContext.$isCreationMode$ = creationMode;
|
|
@@ -4862,18 +4979,20 @@ function diffProps(diffContext, vnode, newAttrs, currentFile) {
|
|
|
4862
4979
|
vnode_ensureElementInflated(diffContext.$container$, vnode);
|
|
4863
4980
|
}
|
|
4864
4981
|
const oldAttrs = vnode.props;
|
|
4982
|
+
const isHtml = (vnode.flags & 1536 /* VNodeFlags.NAMESPACE_MASK */) === 0 /* VNodeFlags.NS_html */;
|
|
4865
4983
|
// Actual diffing logic
|
|
4866
4984
|
// Apply all new attributes
|
|
4867
4985
|
for (const key in newAttrs) {
|
|
4868
4986
|
const newValue = newAttrs[key];
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
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)) {
|
|
4877
4996
|
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
4878
4997
|
}
|
|
4879
4998
|
}
|
|
@@ -5343,13 +5462,26 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
5343
5462
|
if (key === 'children' || key === QBackRefs) {
|
|
5344
5463
|
continue;
|
|
5345
5464
|
}
|
|
5346
|
-
|
|
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
|
+
}
|
|
5347
5479
|
if (triggerEffects) {
|
|
5348
5480
|
if (dst) {
|
|
5349
5481
|
// Update the value in dst BEFORE triggering effects
|
|
5350
5482
|
// so effects see the new value
|
|
5351
5483
|
// Note: Value is not triggering effects, because we are modyfing direct VAR_PROPS object
|
|
5352
|
-
dst[key] =
|
|
5484
|
+
dst[key] = newValue;
|
|
5353
5485
|
}
|
|
5354
5486
|
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
5355
5487
|
if (!didTigger) {
|
|
@@ -5436,10 +5568,16 @@ function cleanup(container, journal, vNode, cursorRoot = null) {
|
|
|
5436
5568
|
// don't call cleanupDestroyable yet, do it by the scheduler
|
|
5437
5569
|
continue;
|
|
5438
5570
|
}
|
|
5439
|
-
|
|
5440
|
-
|
|
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
|
+
}
|
|
5441
5577
|
}
|
|
5442
|
-
if (objIsTask ||
|
|
5578
|
+
if (objIsTask ||
|
|
5579
|
+
(obj instanceof ComputedSignalImpl &&
|
|
5580
|
+
(obj.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */ || obj.$current$))) {
|
|
5443
5581
|
cleanupDestroyable(obj);
|
|
5444
5582
|
}
|
|
5445
5583
|
}
|
|
@@ -5558,6 +5696,37 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
5558
5696
|
*/
|
|
5559
5697
|
vCursor.flags |= 32 /* VNodeFlags.Deleted */;
|
|
5560
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
|
+
}
|
|
5561
5730
|
function areWrappedSignalsEqual(oldSignal, newSignal) {
|
|
5562
5731
|
if (oldSignal === newSignal) {
|
|
5563
5732
|
return true;
|
|
@@ -6406,8 +6575,8 @@ function executeCompute(vNode, container) {
|
|
|
6406
6575
|
ctx.$container$ = container;
|
|
6407
6576
|
// needed for computed signals and throwing QRLs
|
|
6408
6577
|
return maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
|
|
6409
|
-
if (target.$flags$ & 2 /*
|
|
6410
|
-
target.$flags$ &= -3 /*
|
|
6578
|
+
if (target.$flags$ & 2 /* ComputedSignalFlags.RUN_EFFECTS */) {
|
|
6579
|
+
target.$flags$ &= -3 /* ComputedSignalFlags.RUN_EFFECTS */;
|
|
6411
6580
|
return scheduleEffects(container, target, effects);
|
|
6412
6581
|
}
|
|
6413
6582
|
});
|
|
@@ -6948,6 +7117,10 @@ function splitCursorBoundary(container, vNode) {
|
|
|
6948
7117
|
* @returns The vNode itself, now acting as a cursor
|
|
6949
7118
|
*/
|
|
6950
7119
|
function addCursor(container, root, priority) {
|
|
7120
|
+
if (isCursor(root)) {
|
|
7121
|
+
triggerCursors();
|
|
7122
|
+
return root;
|
|
7123
|
+
}
|
|
6951
7124
|
const cursorData = {
|
|
6952
7125
|
afterFlushTasks: null,
|
|
6953
7126
|
extraPromises: null,
|
|
@@ -7000,7 +7173,11 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
7000
7173
|
if (ssrNode.dirty & 32 /* ChoreBits.COMPUTE */) {
|
|
7001
7174
|
executeCompute(ssrNode, container);
|
|
7002
7175
|
}
|
|
7003
|
-
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 */;
|
|
7004
7181
|
// We are running on the server.
|
|
7005
7182
|
// On server we can't schedule task for a different host!
|
|
7006
7183
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -8717,8 +8894,17 @@ const processVNodeData$1 = (vData, callback) => {
|
|
|
8717
8894
|
}
|
|
8718
8895
|
return vData.substring(start, nextToConsumeIdx);
|
|
8719
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
|
+
};
|
|
8720
8906
|
while (peek() !== 0) {
|
|
8721
|
-
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
|
|
8907
|
+
callback(peek, consumeValue, consume, getChar, nextToConsumeIdx, consumeEncodedValue);
|
|
8722
8908
|
}
|
|
8723
8909
|
};
|
|
8724
8910
|
/** @internal */
|
|
@@ -8909,13 +9095,13 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8909
9095
|
return !nodeIsElement || (nodeIsElement && shouldSkipElement(node));
|
|
8910
9096
|
};
|
|
8911
9097
|
let components = null;
|
|
8912
|
-
processVNodeData$1(vData, (peek, consumeValue, consume, getChar,
|
|
9098
|
+
processVNodeData$1(vData, (peek, consumeValue, consume, getChar, dataIdx, consumeEncodedValue) => {
|
|
8913
9099
|
if (isNumber(peek())) {
|
|
8914
9100
|
// Element counts get encoded as numbers.
|
|
8915
9101
|
while (shouldSkipNode(child)) {
|
|
8916
9102
|
child = fastNextSibling(child);
|
|
8917
9103
|
if (!child) {
|
|
8918
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9104
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8919
9105
|
}
|
|
8920
9106
|
}
|
|
8921
9107
|
combinedText = null;
|
|
@@ -8936,7 +9122,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8936
9122
|
shouldSkipElement(child)) {
|
|
8937
9123
|
child = fastNextSibling(child);
|
|
8938
9124
|
if (!child && value > 0) {
|
|
8939
|
-
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(),
|
|
9125
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), dataIdx]);
|
|
8940
9126
|
}
|
|
8941
9127
|
}
|
|
8942
9128
|
}
|
|
@@ -8961,17 +9147,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
8961
9147
|
vnode_setProp(vParent, ELEMENT_PROPS, consumeValue());
|
|
8962
9148
|
}
|
|
8963
9149
|
else if (peek() === VNodeDataChar.KEY) {
|
|
8964
|
-
|
|
8965
|
-
let value;
|
|
8966
|
-
if (isEscapedValue) {
|
|
8967
|
-
consume();
|
|
8968
|
-
value = decodeURIComponent(decodeVNodeDataString(consumeValue()));
|
|
8969
|
-
consume();
|
|
8970
|
-
}
|
|
8971
|
-
else {
|
|
8972
|
-
value = consumeValue();
|
|
8973
|
-
}
|
|
8974
|
-
vParent.key = value;
|
|
9150
|
+
vParent.key = consumeEncodedValue();
|
|
8975
9151
|
}
|
|
8976
9152
|
else if (peek() === VNodeDataChar.SEQ) {
|
|
8977
9153
|
vnode_setProp(vParent, ELEMENT_SEQ, consumeValue());
|
|
@@ -9006,7 +9182,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
9006
9182
|
// Custom attribute: |key|value
|
|
9007
9183
|
const keyValue = consumeValue();
|
|
9008
9184
|
const key = decodeVNodeDataString(keyValue);
|
|
9009
|
-
const valueSeparatorIdx =
|
|
9185
|
+
const valueSeparatorIdx = dataIdx + keyValue.length + 1;
|
|
9010
9186
|
const isEscapedValue = getChar(valueSeparatorIdx + 1) === VNodeDataChar.SEPARATOR;
|
|
9011
9187
|
let value;
|
|
9012
9188
|
if (isEscapedValue) {
|
|
@@ -9029,8 +9205,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
|
|
|
9029
9205
|
vParent = stack.pop();
|
|
9030
9206
|
}
|
|
9031
9207
|
else if (peek() === VNodeDataChar.SLOT) {
|
|
9032
|
-
|
|
9033
|
-
vnode_setProp(vParent, QSlot, value);
|
|
9208
|
+
vnode_setProp(vParent, QSlot, consumeEncodedValue());
|
|
9034
9209
|
}
|
|
9035
9210
|
else {
|
|
9036
9211
|
// skip over style or non-qwik elements in front of text nodes, where text node is the first child (except the style node)
|
|
@@ -9141,12 +9316,12 @@ function clearEffectSubscription(container, effect) {
|
|
|
9141
9316
|
return;
|
|
9142
9317
|
}
|
|
9143
9318
|
for (const producer of backRefs) {
|
|
9144
|
-
|
|
9145
|
-
if (producer instanceof AsyncSignalImpl) {
|
|
9146
|
-
clearAsyncSignal(producer, effect);
|
|
9147
|
-
}
|
|
9148
|
-
else if (producer instanceof SignalImpl) {
|
|
9319
|
+
if (producer instanceof SignalImpl) {
|
|
9149
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
|
+
}
|
|
9150
9325
|
}
|
|
9151
9326
|
else if (isPropsProxy(producer)) {
|
|
9152
9327
|
const propsHandler = producer[_PROPS_HANDLER];
|
|
@@ -9171,11 +9346,7 @@ function clearSignal(container, producer, effect) {
|
|
|
9171
9346
|
clearAllEffects(container, producer);
|
|
9172
9347
|
}
|
|
9173
9348
|
}
|
|
9174
|
-
function
|
|
9175
|
-
const effects = producer.$effects$;
|
|
9176
|
-
if (effects && effects.has(effect)) {
|
|
9177
|
-
effects.delete(effect);
|
|
9178
|
-
}
|
|
9349
|
+
function clearAsyncSignalEffects(producer, effect) {
|
|
9179
9350
|
const pendingEffects = producer.$loadingEffects$;
|
|
9180
9351
|
if (pendingEffects && pendingEffects.has(effect)) {
|
|
9181
9352
|
pendingEffects.delete(effect);
|
|
@@ -9211,7 +9382,7 @@ const useTaskQrl = (qrl, opts) => {
|
|
|
9211
9382
|
const taskFlags =
|
|
9212
9383
|
// enabled by default
|
|
9213
9384
|
opts?.deferUpdates === false ? 0 : 8 /* TaskFlags.RENDER_BLOCKING */;
|
|
9214
|
-
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);
|
|
9215
9386
|
// In V2 we add the task to the sequential scope. We need to do this
|
|
9216
9387
|
// in order to be able to retrieve it later when the parent element is
|
|
9217
9388
|
// deleted and we need to be able to release the task subscriptions.
|
|
@@ -9270,17 +9441,15 @@ class Task extends BackRef {
|
|
|
9270
9441
|
$index$;
|
|
9271
9442
|
$el$;
|
|
9272
9443
|
$qrl$;
|
|
9273
|
-
$state$;
|
|
9274
9444
|
$destroy$;
|
|
9275
9445
|
$destroyPromise$;
|
|
9276
9446
|
$taskPromise$ = null;
|
|
9277
|
-
constructor($flags$, $index$, $el$, $qrl$, $
|
|
9447
|
+
constructor($flags$, $index$, $el$, $qrl$, $destroy$) {
|
|
9278
9448
|
super();
|
|
9279
9449
|
this.$flags$ = $flags$;
|
|
9280
9450
|
this.$index$ = $index$;
|
|
9281
9451
|
this.$el$ = $el$;
|
|
9282
9452
|
this.$qrl$ = $qrl$;
|
|
9283
|
-
this.$state$ = $state$;
|
|
9284
9453
|
this.$destroy$ = $destroy$;
|
|
9285
9454
|
}
|
|
9286
9455
|
}
|
|
@@ -9296,12 +9465,14 @@ const isTask = (value) => {
|
|
|
9296
9465
|
*/
|
|
9297
9466
|
function scheduleTask(_event, element) {
|
|
9298
9467
|
const container = getDomContainer(element);
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
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
|
+
});
|
|
9305
9476
|
}
|
|
9306
9477
|
|
|
9307
9478
|
const throwIfQRLNotResolved = (qrl) => {
|
|
@@ -9413,7 +9584,7 @@ const isSerializerObj = (obj) => {
|
|
|
9413
9584
|
return isObject(obj) && typeof obj[SerializerSymbol] === 'function';
|
|
9414
9585
|
};
|
|
9415
9586
|
const getComputedSignalFlags = (serializationStrategy) => {
|
|
9416
|
-
let flags = 1 /*
|
|
9587
|
+
let flags = 1 /* ComputedSignalFlags.INVALID */;
|
|
9417
9588
|
switch (serializationStrategy) {
|
|
9418
9589
|
// TODO: implement this in the future
|
|
9419
9590
|
// case 'auto':
|
|
@@ -9428,6 +9599,18 @@ const getComputedSignalFlags = (serializationStrategy) => {
|
|
|
9428
9599
|
}
|
|
9429
9600
|
return flags;
|
|
9430
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
|
+
};
|
|
9431
9614
|
|
|
9432
9615
|
const stringifyPath = [];
|
|
9433
9616
|
function qwikDebugToString(value) {
|
|
@@ -9787,6 +9970,7 @@ function getEffects(target, prop, storeEffects) {
|
|
|
9787
9970
|
|
|
9788
9971
|
/** Used to represent an undefined value that must be serialized */
|
|
9789
9972
|
const explicitUndefined = Symbol('undefined');
|
|
9973
|
+
const EMPTY_OBJECT_PAYLOAD = 0;
|
|
9790
9974
|
// Used for allocate, make sure they are in sync with Constants
|
|
9791
9975
|
const _constants = [
|
|
9792
9976
|
undefined,
|
|
@@ -9807,6 +9991,10 @@ const _constants = [
|
|
|
9807
9991
|
Number.MAX_SAFE_INTEGER,
|
|
9808
9992
|
Number.MAX_SAFE_INTEGER - 1,
|
|
9809
9993
|
Number.MIN_SAFE_INTEGER,
|
|
9994
|
+
':',
|
|
9995
|
+
'.',
|
|
9996
|
+
'id',
|
|
9997
|
+
'ref',
|
|
9810
9998
|
];
|
|
9811
9999
|
// Used for dumpState, make sure they are in sync with Constants
|
|
9812
10000
|
const _constantNames = [
|
|
@@ -9828,6 +10016,10 @@ const _constantNames = [
|
|
|
9828
10016
|
'MAX_SAFE_INTEGER',
|
|
9829
10017
|
'MAX_SAFE_INTEGER-1',
|
|
9830
10018
|
'MIN_SAFE_INTEGER',
|
|
10019
|
+
"':'",
|
|
10020
|
+
"'.'",
|
|
10021
|
+
"'id'",
|
|
10022
|
+
"'ref'",
|
|
9831
10023
|
];
|
|
9832
10024
|
// Used for dumpState, make sure they are in sync with TypeIds
|
|
9833
10025
|
const _typeIdNames = [
|
|
@@ -9873,6 +10065,9 @@ const _typeIdNames = [
|
|
|
9873
10065
|
'SubscriptionData',
|
|
9874
10066
|
'EffectSubscription',
|
|
9875
10067
|
'SubscriptionPatch',
|
|
10068
|
+
'SubscriptionDataConstTrue',
|
|
10069
|
+
'SubscriptionDataConstFalse',
|
|
10070
|
+
'EffectSubscriptionNoData',
|
|
9876
10071
|
];
|
|
9877
10072
|
|
|
9878
10073
|
function qrlToString(serializationContext, qrl, raw) {
|
|
@@ -9919,17 +10114,25 @@ function qrlToString(serializationContext, qrl, raw) {
|
|
|
9919
10114
|
symbol = String(serializationContext.$addSyncFn$(null, 0, fn));
|
|
9920
10115
|
}
|
|
9921
10116
|
const captures = qrl.getCaptured();
|
|
9922
|
-
let
|
|
10117
|
+
let captureDeltas = null;
|
|
9923
10118
|
if (captures && captures.length > 0) {
|
|
9924
10119
|
// We refer by id so every capture needs to be a root
|
|
9925
|
-
|
|
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;
|
|
9926
10129
|
}
|
|
9927
10130
|
if (raw) {
|
|
9928
|
-
return [chunk, symbol,
|
|
10131
|
+
return [chunk, symbol, captureDeltas];
|
|
9929
10132
|
}
|
|
9930
10133
|
let qrlStringInline = `${chunk}#${symbol}`;
|
|
9931
|
-
if (
|
|
9932
|
-
qrlStringInline += `#${
|
|
10134
|
+
if (captureDeltas) {
|
|
10135
|
+
qrlStringInline += `#${captureDeltas}`;
|
|
9933
10136
|
}
|
|
9934
10137
|
return qrlStringInline;
|
|
9935
10138
|
}
|
|
@@ -9941,12 +10144,23 @@ function qrlToChunks(serializationContext, qrl) {
|
|
|
9941
10144
|
return prefix;
|
|
9942
10145
|
}
|
|
9943
10146
|
const chunks = [prefix, '#'];
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
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;
|
|
9948
10163
|
}
|
|
9949
|
-
chunks.push(Number(captureIds[i]));
|
|
9950
10164
|
}
|
|
9951
10165
|
return chunks;
|
|
9952
10166
|
}
|
|
@@ -9962,10 +10176,14 @@ function createQRLWithBackChannel(chunk, symbol, captures, container) {
|
|
|
9962
10176
|
}
|
|
9963
10177
|
return createQRL(chunk, symbol, null, qrlImporter, captures, container);
|
|
9964
10178
|
}
|
|
9965
|
-
/** Parses "chunk#hash#...
|
|
10179
|
+
/** Parses "chunk#hash#...captureDelta" */
|
|
9966
10180
|
function parseQRL(qrl, container) {
|
|
9967
|
-
const
|
|
9968
|
-
|
|
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);
|
|
9969
10187
|
}
|
|
9970
10188
|
const QRL_RUNTIME_CHUNK = 'mock-chunk';
|
|
9971
10189
|
|
|
@@ -10119,6 +10337,36 @@ class Serializer {
|
|
|
10119
10337
|
}
|
|
10120
10338
|
return Number(key);
|
|
10121
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
|
+
}
|
|
10122
10370
|
outputString(value) {
|
|
10123
10371
|
const s = this.stringNeedsJsonEscape$(value) ? JSON.stringify(value) : QUOTE + value + QUOTE;
|
|
10124
10372
|
let angleBracketIdx = -1;
|
|
@@ -10136,6 +10384,9 @@ class Serializer {
|
|
|
10136
10384
|
writeRootRefPath(path) {
|
|
10137
10385
|
this.$writer$.writeRootRefPath(path);
|
|
10138
10386
|
}
|
|
10387
|
+
writeRootRefDelta(id, base) {
|
|
10388
|
+
this.$writer$.writeRootRefDelta(id, base);
|
|
10389
|
+
}
|
|
10139
10390
|
outputStringChunks(chunks) {
|
|
10140
10391
|
this.$writer$.write(QUOTE);
|
|
10141
10392
|
for (let i = 0; i < chunks.length; i++) {
|
|
@@ -10146,6 +10397,9 @@ class Serializer {
|
|
|
10146
10397
|
else if (typeof chunk === 'number') {
|
|
10147
10398
|
this.writeRootRef(chunk);
|
|
10148
10399
|
}
|
|
10400
|
+
else if ('base' in chunk) {
|
|
10401
|
+
this.writeRootRefDelta(chunk.id, chunk.base);
|
|
10402
|
+
}
|
|
10149
10403
|
else {
|
|
10150
10404
|
this.writeRootRefPath(chunk.path);
|
|
10151
10405
|
}
|
|
@@ -10275,6 +10529,9 @@ class Serializer {
|
|
|
10275
10529
|
if (value.length === 0) {
|
|
10276
10530
|
this.output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
|
|
10277
10531
|
}
|
|
10532
|
+
else if (this.outputShortStringConstant$(value)) {
|
|
10533
|
+
break;
|
|
10534
|
+
}
|
|
10278
10535
|
else {
|
|
10279
10536
|
// If the string is short, we output directly
|
|
10280
10537
|
// Very short strings add overhead to tracking
|
|
@@ -10314,27 +10571,38 @@ class Serializer {
|
|
|
10314
10571
|
}
|
|
10315
10572
|
else if (isQrl(value)) {
|
|
10316
10573
|
if (this.getSeenRefOrOutput(value, index)) {
|
|
10317
|
-
const [chunk, symbol,
|
|
10574
|
+
const [chunk, symbol, captureDeltasFromZero] = qrlToString(this.$serializationContext$, value, true);
|
|
10318
10575
|
let data;
|
|
10319
10576
|
if (chunk !== '') {
|
|
10320
10577
|
// not a sync QRL, replace all parts with string references
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
this
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
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;
|
|
10328
10588
|
data.push('#');
|
|
10329
|
-
for (let i = 0; i
|
|
10330
|
-
if (i
|
|
10331
|
-
|
|
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;
|
|
10332
10601
|
}
|
|
10333
|
-
data.push(Number(captureIds[i]));
|
|
10334
10602
|
}
|
|
10335
10603
|
}
|
|
10336
10604
|
// Since we map QRLs to strings, we need to keep track of this secondary mapping
|
|
10337
|
-
const qrlKey =
|
|
10605
|
+
const qrlKey = `${chunkRootId}#${symbolRootId - chunkRootId}${captureDeltas ? '#' + captureDeltas : ''}`;
|
|
10338
10606
|
const existing = this.$qrlMap$.get(qrlKey);
|
|
10339
10607
|
if (existing) {
|
|
10340
10608
|
// We encountered the same QRL again, make it a root
|
|
@@ -10402,15 +10670,21 @@ class Serializer {
|
|
|
10402
10670
|
]);
|
|
10403
10671
|
}
|
|
10404
10672
|
else if (value instanceof SubscriptionData) {
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
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
|
+
}
|
|
10410
10680
|
}
|
|
10411
10681
|
else if (value instanceof EffectSubscription) {
|
|
10412
|
-
|
|
10413
|
-
|
|
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
|
+
}
|
|
10414
10688
|
}
|
|
10415
10689
|
else if (value instanceof SubscriptionPatch) {
|
|
10416
10690
|
this.output(41 /* TypeIds.SubscriptionPatch */, [value.rootId, value.subscriptions]);
|
|
@@ -10464,7 +10738,7 @@ class Serializer {
|
|
|
10464
10738
|
}
|
|
10465
10739
|
}
|
|
10466
10740
|
}
|
|
10467
|
-
this.output(5 /* TypeIds.Object */, out.length ? out :
|
|
10741
|
+
this.output(5 /* TypeIds.Object */, out.length ? out : EMPTY_OBJECT_PAYLOAD);
|
|
10468
10742
|
}
|
|
10469
10743
|
}
|
|
10470
10744
|
else if (this.$serializationContext$.$isDomRef$(value)) {
|
|
@@ -10497,16 +10771,18 @@ class Serializer {
|
|
|
10497
10771
|
let v = value.$untrackedValue$;
|
|
10498
10772
|
const shouldAlwaysSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
10499
10773
|
const shouldNeverSerialize = value.$flags$ & 8 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
10500
|
-
const isInvalid = value.$flags$ & 1 /*
|
|
10774
|
+
const isInvalid = value.$flags$ & 1 /* ComputedSignalFlags.INVALID */;
|
|
10501
10775
|
const isSkippable = fastSkipSerialize(value.$untrackedValue$);
|
|
10502
|
-
|
|
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$;
|
|
10503
10779
|
const expires = isAsync && value.$expires$ !== 0 ? value.$expires$ : undefined;
|
|
10504
10780
|
const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
|
|
10505
10781
|
const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
|
|
10506
10782
|
// Send the flags but remove the serialization bits and default to 0 when undefined
|
|
10507
10783
|
const asyncFlags = (isAsync && value.$flags$ & -25 /* SerializationSignalFlags.SERIALIZATION_ALL_STRATEGIES */) ||
|
|
10508
10784
|
undefined;
|
|
10509
|
-
if (isInvalid || isSkippable) {
|
|
10785
|
+
if (isInvalid || isSkippable || isErrored) {
|
|
10510
10786
|
v = NEEDS_COMPUTATION;
|
|
10511
10787
|
}
|
|
10512
10788
|
else if (shouldAlwaysSerialize) {
|
|
@@ -10554,30 +10830,6 @@ class Serializer {
|
|
|
10554
10830
|
else if (value instanceof Date) {
|
|
10555
10831
|
this.output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
|
|
10556
10832
|
}
|
|
10557
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
|
|
10558
|
-
this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
|
|
10559
|
-
}
|
|
10560
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
|
|
10561
|
-
this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
|
|
10562
|
-
}
|
|
10563
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
|
|
10564
|
-
this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
|
|
10565
|
-
}
|
|
10566
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
|
|
10567
|
-
this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
|
|
10568
|
-
}
|
|
10569
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
|
|
10570
|
-
this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
|
|
10571
|
-
}
|
|
10572
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
|
|
10573
|
-
this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
|
|
10574
|
-
}
|
|
10575
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
|
|
10576
|
-
this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
|
|
10577
|
-
}
|
|
10578
|
-
else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
|
|
10579
|
-
this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
|
|
10580
|
-
}
|
|
10581
10833
|
else if (value instanceof RegExp) {
|
|
10582
10834
|
this.output(8 /* TypeIds.Regex */, value.toString());
|
|
10583
10835
|
}
|
|
@@ -10650,7 +10902,7 @@ class Serializer {
|
|
|
10650
10902
|
this.output(37 /* TypeIds.JSXNode */, out);
|
|
10651
10903
|
}
|
|
10652
10904
|
else if (value instanceof Task) {
|
|
10653
|
-
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el
|
|
10905
|
+
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el$];
|
|
10654
10906
|
while (out[out.length - 1] === undefined) {
|
|
10655
10907
|
out.pop();
|
|
10656
10908
|
}
|
|
@@ -10704,6 +10956,30 @@ class Serializer {
|
|
|
10704
10956
|
this.output(2 /* TypeIds.ForwardRef */, this.getForwardRefId(forwardRefId));
|
|
10705
10957
|
}
|
|
10706
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
|
+
}
|
|
10707
10983
|
else if (vnode_isVNode(value)) {
|
|
10708
10984
|
this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
|
|
10709
10985
|
}
|
|
@@ -10870,7 +11146,9 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10870
11146
|
if (attrValue == null ||
|
|
10871
11147
|
typeof attrValue === 'string' ||
|
|
10872
11148
|
(typeof attrValue === 'number' && key === ELEMENT_ID) ||
|
|
10873
|
-
(key === ELEMENT_PROPS &&
|
|
11149
|
+
(key === ELEMENT_PROPS &&
|
|
11150
|
+
(isObjectEmpty(attrValue) ||
|
|
11151
|
+
shouldSkipComponentProps(value, attrValue)))) {
|
|
10874
11152
|
continue;
|
|
10875
11153
|
}
|
|
10876
11154
|
callback(attrValue);
|
|
@@ -10879,6 +11157,21 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
|
10879
11157
|
}
|
|
10880
11158
|
};
|
|
10881
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
|
+
};
|
|
10882
11175
|
/**
|
|
10883
11176
|
* When serializing the object we need check if it is URL, RegExp, Map, Set, etc. This is time
|
|
10884
11177
|
* consuming. So if we could know that this is a basic object literal we could skip the check, and
|
|
@@ -11377,6 +11670,12 @@ const constantToName = (code) => {
|
|
|
11377
11670
|
* @internal
|
|
11378
11671
|
*/
|
|
11379
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) {
|
|
11380
11679
|
const isRootDeepRef = (type, value) => {
|
|
11381
11680
|
return type === 1 /* TypeIds.RootRef */ && typeof value === 'string' && value.indexOf(' ') !== -1;
|
|
11382
11681
|
};
|
|
@@ -11419,11 +11718,39 @@ function preprocessState(data, container, segmentId, startIndex = 0) {
|
|
|
11419
11718
|
else if (isForwardRefsMap(data[i])) {
|
|
11420
11719
|
container.$forwardRefs$ = data[i + 1];
|
|
11421
11720
|
}
|
|
11721
|
+
yield;
|
|
11422
11722
|
}
|
|
11423
11723
|
}
|
|
11424
11724
|
|
|
11425
11725
|
const resolvers = new WeakMap();
|
|
11426
|
-
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
|
+
};
|
|
11427
11754
|
const allocate = (container, typeId, value) => {
|
|
11428
11755
|
switch (typeId) {
|
|
11429
11756
|
case 0 /* TypeIds.Plain */:
|
|
@@ -11449,10 +11776,17 @@ const allocate = (container, typeId, value) => {
|
|
|
11449
11776
|
case 9 /* TypeIds.QRL */: {
|
|
11450
11777
|
let qrl;
|
|
11451
11778
|
if (typeof value === 'string') {
|
|
11452
|
-
const
|
|
11453
|
-
const
|
|
11454
|
-
const
|
|
11455
|
-
|
|
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);
|
|
11456
11790
|
}
|
|
11457
11791
|
else {
|
|
11458
11792
|
// Sync qrl
|
|
@@ -11461,7 +11795,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11461
11795
|
return qrl;
|
|
11462
11796
|
}
|
|
11463
11797
|
case 28 /* TypeIds.Task */:
|
|
11464
|
-
return new Task(-1, -1, null, null, null
|
|
11798
|
+
return new Task(-1, -1, null, null, null);
|
|
11465
11799
|
case 6 /* TypeIds.URL */:
|
|
11466
11800
|
return new URL(value);
|
|
11467
11801
|
case 7 /* TypeIds.Date */:
|
|
@@ -11509,7 +11843,7 @@ const allocate = (container, typeId, value) => {
|
|
|
11509
11843
|
const storeValue = allocate(container, t, v);
|
|
11510
11844
|
const store = getOrCreateStore(storeValue, 0 /* StoreFlags.NONE */, container);
|
|
11511
11845
|
if (needsInflation(t)) {
|
|
11512
|
-
pendingStoreTargets
|
|
11846
|
+
container.$pendingStoreTargets$.set(storeValue, { t, v });
|
|
11513
11847
|
}
|
|
11514
11848
|
// We must store the reference so it doesn't get deserialized again in inflate()
|
|
11515
11849
|
data[0] = 0 /* TypeIds.Plain */;
|
|
@@ -11539,12 +11873,16 @@ const allocate = (container, typeId, value) => {
|
|
|
11539
11873
|
// Don't leave unhandled promise rejections
|
|
11540
11874
|
promise.catch(() => { });
|
|
11541
11875
|
return promise;
|
|
11542
|
-
case 27 /* TypeIds.Uint8Array */:
|
|
11876
|
+
case 27 /* TypeIds.Uint8Array */: {
|
|
11877
|
+
if (!isCanonicalBase64(value)) {
|
|
11878
|
+
throw qError(38 /* QError.invalidUint8ArrayPayload */);
|
|
11879
|
+
}
|
|
11543
11880
|
const encodedLength = value.length;
|
|
11544
|
-
const blocks = encodedLength
|
|
11545
|
-
const rest = encodedLength
|
|
11881
|
+
const blocks = Math.floor(encodedLength / 4);
|
|
11882
|
+
const rest = encodedLength % 4;
|
|
11546
11883
|
const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
|
|
11547
11884
|
return new Uint8Array(decodedLength);
|
|
11885
|
+
}
|
|
11548
11886
|
case 38 /* TypeIds.PropsProxy */:
|
|
11549
11887
|
return createPropsProxy(null);
|
|
11550
11888
|
case 10 /* TypeIds.VNode */:
|
|
@@ -11585,7 +11923,12 @@ const allocate = (container, typeId, value) => {
|
|
|
11585
11923
|
}
|
|
11586
11924
|
case 39 /* TypeIds.SubscriptionData */:
|
|
11587
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 });
|
|
11588
11930
|
case 40 /* TypeIds.EffectSubscription */:
|
|
11931
|
+
case 44 /* TypeIds.EffectSubscriptionNoData */:
|
|
11589
11932
|
return new EffectSubscription(null, null, null, null);
|
|
11590
11933
|
case 41 /* TypeIds.SubscriptionPatch */:
|
|
11591
11934
|
return new SubscriptionPatch();
|
|
@@ -12021,6 +12364,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
12021
12364
|
if (isPromise(jsxOutput)) {
|
|
12022
12365
|
// Defer reading QScopedStyle until after the promise resolves
|
|
12023
12366
|
enqueue(async () => {
|
|
12367
|
+
await ssr.streamHandler.flush();
|
|
12024
12368
|
const resolvedOutput = await jsxOutput;
|
|
12025
12369
|
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
12026
12370
|
enqueue(resolvedOutput);
|
|
@@ -12052,7 +12396,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
12052
12396
|
function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
|
|
12053
12397
|
// Unwrap if it's a WrappedSignalImpl
|
|
12054
12398
|
const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
|
|
12055
|
-
if (unwrappedSignal instanceof
|
|
12399
|
+
if (unwrappedSignal instanceof ComputedSignalImpl) {
|
|
12056
12400
|
const expires = unwrappedSignal.$expires$;
|
|
12057
12401
|
// Don't check for $effects$ here - effects are added later during tracking.
|
|
12058
12402
|
// The AsyncSignal's polling mechanism will check for effects before scheduling.
|
|
@@ -12235,7 +12579,7 @@ function setEvent(serializationCtx, key, rawValue, hasMovedCaptures) {
|
|
|
12235
12579
|
*
|
|
12236
12580
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
12237
12581
|
*/
|
|
12238
|
-
if (!qrl.$symbol$.startsWith('_') && (qrl.$captures
|
|
12582
|
+
if (!qrl.$symbol$.startsWith('_') && (Array.isArray(qrl.$captures$) || hasMovedCaptures)) {
|
|
12239
12583
|
qrl = createQRL(null, '_run', _run, null, [qrl]);
|
|
12240
12584
|
}
|
|
12241
12585
|
return qrlToChunks(serializationCtx, qrl);
|
|
@@ -12449,22 +12793,24 @@ const useOnEventsSequentialScope = () => {
|
|
|
12449
12793
|
const _hmr = function (event, element) {
|
|
12450
12794
|
// Deserialize captures from `this` when called via qwikloader/attribute dispatch
|
|
12451
12795
|
const container = getDomContainer(element);
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
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
|
+
});
|
|
12468
12814
|
};
|
|
12469
12815
|
let hmrQrl;
|
|
12470
12816
|
/**
|
|
@@ -12569,22 +12915,93 @@ const isSafeObjectKV = (key, value) => {
|
|
|
12569
12915
|
(typeof value !== 'function' || !dangerousObjectKeys.has(key)));
|
|
12570
12916
|
};
|
|
12571
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) {
|
|
12572
12987
|
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12573
12988
|
// Already processed
|
|
12574
12989
|
return;
|
|
12575
12990
|
}
|
|
12991
|
+
if (typeId === 5 /* TypeIds.Object */ && data !== EMPTY_OBJECT_PAYLOAD && !Array.isArray(data)) {
|
|
12992
|
+
throw new Error('Invalid Object payload');
|
|
12993
|
+
}
|
|
12576
12994
|
// Restore the complex data, special case for Array
|
|
12577
12995
|
if (typeId !== 4 /* TypeIds.Array */ && Array.isArray(data)) {
|
|
12578
|
-
data =
|
|
12996
|
+
data = yield* eagerDeserializeArrayIterator(container, data);
|
|
12579
12997
|
}
|
|
12580
12998
|
switch (typeId) {
|
|
12581
12999
|
case 4 /* TypeIds.Array */:
|
|
12582
13000
|
// Arrays are special, we need to fill the array in place
|
|
12583
|
-
|
|
13001
|
+
yield* eagerDeserializeArrayIterator(container, data, target);
|
|
12584
13002
|
break;
|
|
12585
13003
|
case 5 /* TypeIds.Object */:
|
|
12586
|
-
if (data ===
|
|
12587
|
-
// Special case, was an empty object
|
|
13004
|
+
if (data === EMPTY_OBJECT_PAYLOAD) {
|
|
12588
13005
|
break;
|
|
12589
13006
|
}
|
|
12590
13007
|
for (let i = 0; i < data.length; i += 2) {
|
|
@@ -12596,37 +13013,65 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12596
13013
|
target[key] = value;
|
|
12597
13014
|
}
|
|
12598
13015
|
break;
|
|
12599
|
-
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 */: {
|
|
12600
13064
|
const task = target;
|
|
12601
13065
|
const v = data;
|
|
12602
13066
|
task.$qrl$ = v[0];
|
|
12603
13067
|
task.$flags$ = v[1];
|
|
12604
13068
|
task.$index$ = v[2];
|
|
12605
13069
|
task.$el$ = v[3];
|
|
12606
|
-
task.$state$ = v[4];
|
|
12607
13070
|
break;
|
|
13071
|
+
}
|
|
12608
13072
|
case 29 /* TypeIds.Component */:
|
|
12609
13073
|
target[SERIALIZABLE_STATE][0] = data[0];
|
|
12610
13074
|
break;
|
|
12611
|
-
case 35 /* TypeIds.Store */: {
|
|
12612
|
-
// Inflate the store target
|
|
12613
|
-
const store = unwrapStore(target);
|
|
12614
|
-
const storeTarget = pendingStoreTargets.get(store);
|
|
12615
|
-
if (storeTarget) {
|
|
12616
|
-
pendingStoreTargets.delete(store);
|
|
12617
|
-
inflate(container, store, storeTarget.t, storeTarget.v);
|
|
12618
|
-
}
|
|
12619
|
-
/**
|
|
12620
|
-
* Note that we don't do anything with the innerstores we added during serialization, because
|
|
12621
|
-
* they are already inflated in the deserialize of the data, above.
|
|
12622
|
-
*/
|
|
12623
|
-
const [, flags, effects] = data;
|
|
12624
|
-
const storeHandler = getStoreHandler(target);
|
|
12625
|
-
storeHandler.$flags$ = flags;
|
|
12626
|
-
storeHandler.$effects$ = effects;
|
|
12627
|
-
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
12628
|
-
break;
|
|
12629
|
-
}
|
|
12630
13075
|
case 30 /* TypeIds.Signal */: {
|
|
12631
13076
|
const signal = target;
|
|
12632
13077
|
const d = data;
|
|
@@ -12642,7 +13087,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12642
13087
|
signal.$args$ = d[1];
|
|
12643
13088
|
signal.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
12644
13089
|
signal.$flags$ = d[2];
|
|
12645
|
-
signal.$flags$ |= 1 /*
|
|
13090
|
+
signal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12646
13091
|
signal.$hostElement$ = d[3];
|
|
12647
13092
|
signal.$effects$ = new Set(d.slice(4));
|
|
12648
13093
|
inflateWrappedSignalValue(signal);
|
|
@@ -12668,7 +13113,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12668
13113
|
asyncSignal.$flags$ = d[5] ?? 0;
|
|
12669
13114
|
if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
12670
13115
|
// If it's client only, it was serialized because it pretended to be loading
|
|
12671
|
-
asyncSignal.$
|
|
13116
|
+
asyncSignal.$untrackedPending$ = true;
|
|
12672
13117
|
}
|
|
12673
13118
|
const hasValue = d.length > 6;
|
|
12674
13119
|
if (hasValue) {
|
|
@@ -12676,7 +13121,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12676
13121
|
}
|
|
12677
13122
|
// can happen when never serialize etc
|
|
12678
13123
|
if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
12679
|
-
asyncSignal.$flags$ |= 1 /*
|
|
13124
|
+
asyncSignal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
|
|
12680
13125
|
}
|
|
12681
13126
|
// Handle old format (negative = no poll) and new format (always positive, flag in d[5])
|
|
12682
13127
|
const rawExpires = (d[7] ?? 0);
|
|
@@ -12718,82 +13163,42 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12718
13163
|
}
|
|
12719
13164
|
if (typeId !== 34 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
12720
13165
|
// If we have a value after SSR, it will always be mean the signal was not invalid
|
|
12721
|
-
// The serialized signal is always left invalid so it can recreate the custom object
|
|
12722
|
-
computed.$flags$ &= -2 /*
|
|
12723
|
-
}
|
|
12724
|
-
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
12725
|
-
break;
|
|
12726
|
-
}
|
|
12727
|
-
case 23 /* TypeIds.Error */: {
|
|
12728
|
-
const d = data;
|
|
12729
|
-
target.message = d[0];
|
|
12730
|
-
for (let i = 1; i < d.length; i += 2) {
|
|
12731
|
-
target[d[i]] = d[i + 1];
|
|
12732
|
-
}
|
|
12733
|
-
break;
|
|
12734
|
-
}
|
|
12735
|
-
case 36 /* TypeIds.FormData */: {
|
|
12736
|
-
const formData = target;
|
|
12737
|
-
const d = data;
|
|
12738
|
-
for (let i = 0; i < d.length; i++) {
|
|
12739
|
-
formData.append(d[i++], d[i]);
|
|
12740
|
-
}
|
|
12741
|
-
break;
|
|
12742
|
-
}
|
|
12743
|
-
case 37 /* TypeIds.JSXNode */: {
|
|
12744
|
-
const jsx = target;
|
|
12745
|
-
const [type, key, varProps, constProps, children, toSort] = data;
|
|
12746
|
-
jsx.type = type;
|
|
12747
|
-
jsx.key = key;
|
|
12748
|
-
jsx.varProps = varProps;
|
|
12749
|
-
jsx.constProps = constProps || null;
|
|
12750
|
-
jsx.children = children;
|
|
12751
|
-
jsx.toSort = !!toSort;
|
|
12752
|
-
break;
|
|
12753
|
-
}
|
|
12754
|
-
case 25 /* TypeIds.Set */: {
|
|
12755
|
-
const set = target;
|
|
12756
|
-
const d = data;
|
|
12757
|
-
for (let i = 0; i < d.length; i++) {
|
|
12758
|
-
set.add(d[i]);
|
|
13166
|
+
// The serialized signal is always left invalid so it can recreate the custom object
|
|
13167
|
+
computed.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
|
|
12759
13168
|
}
|
|
13169
|
+
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
12760
13170
|
break;
|
|
12761
13171
|
}
|
|
12762
|
-
case
|
|
12763
|
-
const
|
|
13172
|
+
case 36 /* TypeIds.FormData */: {
|
|
13173
|
+
const formData = target;
|
|
12764
13174
|
const d = data;
|
|
12765
13175
|
for (let i = 0; i < d.length; i++) {
|
|
12766
|
-
|
|
13176
|
+
formData.append(d[i++], d[i]);
|
|
13177
|
+
yield;
|
|
12767
13178
|
}
|
|
12768
13179
|
break;
|
|
12769
13180
|
}
|
|
12770
|
-
case
|
|
12771
|
-
const
|
|
12772
|
-
const [
|
|
12773
|
-
|
|
12774
|
-
|
|
12775
|
-
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
}
|
|
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;
|
|
12780
13190
|
break;
|
|
12781
13191
|
}
|
|
12782
|
-
case
|
|
12783
|
-
const bytes = target;
|
|
12784
|
-
const buf = atob(data);
|
|
12785
|
-
let i = 0;
|
|
12786
|
-
for (let j = 0; j < buf.length; j++) {
|
|
12787
|
-
const s = buf[j];
|
|
12788
|
-
bytes[i++] = s.charCodeAt(0);
|
|
12789
|
-
}
|
|
12790
|
-
break;
|
|
12791
|
-
case 38 /* TypeIds.PropsProxy */:
|
|
13192
|
+
case 38 /* TypeIds.PropsProxy */: {
|
|
12792
13193
|
const propsProxy = target;
|
|
12793
13194
|
const d = data;
|
|
12794
13195
|
let owner = d[0];
|
|
12795
13196
|
if (owner === _UNINITIALIZED) {
|
|
12796
|
-
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];
|
|
12797
13202
|
owner._proxy = propsProxy;
|
|
12798
13203
|
}
|
|
12799
13204
|
propsProxy[_OWNER] = owner;
|
|
@@ -12801,12 +13206,16 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12801
13206
|
propsHandler.$effects$ = d[3];
|
|
12802
13207
|
restoreEffectBackRefForEffectsMap(propsHandler.$effects$, propsProxy);
|
|
12803
13208
|
break;
|
|
13209
|
+
}
|
|
12804
13210
|
case 39 /* TypeIds.SubscriptionData */: {
|
|
12805
13211
|
const effectData = target;
|
|
12806
13212
|
effectData.data.$scopedStyleIdPrefix$ = data[0];
|
|
12807
13213
|
effectData.data.$isConst$ = data[1];
|
|
12808
13214
|
break;
|
|
12809
13215
|
}
|
|
13216
|
+
case 42 /* TypeIds.SubscriptionDataConstTrue */:
|
|
13217
|
+
case 43 /* TypeIds.SubscriptionDataConstFalse */:
|
|
13218
|
+
break;
|
|
12810
13219
|
case 40 /* TypeIds.EffectSubscription */: {
|
|
12811
13220
|
const effectSub = target;
|
|
12812
13221
|
const d = data;
|
|
@@ -12823,29 +13232,43 @@ const inflate = (container, target, typeId, data) => {
|
|
|
12823
13232
|
patch.subscriptions = d[1];
|
|
12824
13233
|
break;
|
|
12825
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
|
+
}
|
|
12826
13269
|
default:
|
|
12827
13270
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
12828
13271
|
}
|
|
12829
|
-
};
|
|
12830
|
-
/**
|
|
12831
|
-
* Restores an array eagerly. If you need it lazily, use `deserializeData(container, TypeIds.Array,
|
|
12832
|
-
* array)` instead
|
|
12833
|
-
*/
|
|
12834
|
-
const _eagerDeserializeArray = (container, data, output = Array(data.length / 2)) => {
|
|
12835
|
-
for (let i = 0; i < data.length; i += 2) {
|
|
12836
|
-
output[i / 2] = deserializeData(container, data[i], data[i + 1]);
|
|
12837
|
-
}
|
|
12838
|
-
return output;
|
|
12839
|
-
};
|
|
12840
|
-
function deserializeData(container, typeId, value) {
|
|
12841
|
-
if (typeId === 0 /* TypeIds.Plain */) {
|
|
12842
|
-
return value;
|
|
12843
|
-
}
|
|
12844
|
-
const propValue = allocate(container, typeId, value);
|
|
12845
|
-
if (needsInflation(typeId)) {
|
|
12846
|
-
inflate(container, propValue, typeId, value);
|
|
12847
|
-
}
|
|
12848
|
-
return propValue;
|
|
12849
13272
|
}
|
|
12850
13273
|
function inflateWrappedSignalValue(signal) {
|
|
12851
13274
|
if (signal.$hostElement$ !== null && vnode_isVNode(signal.$hostElement$)) {
|
|
@@ -12956,15 +13379,21 @@ class DeserializationHandler {
|
|
|
12956
13379
|
return value;
|
|
12957
13380
|
}
|
|
12958
13381
|
const container = this.$container$;
|
|
12959
|
-
const
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
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);
|
|
12966
13396
|
}
|
|
12967
|
-
return propValue;
|
|
12968
13397
|
}
|
|
12969
13398
|
has(target, property) {
|
|
12970
13399
|
if (property === SERIALIZER_PROXY_UNWRAP) {
|
|
@@ -12988,6 +13417,54 @@ class DeserializationHandler {
|
|
|
12988
13417
|
}
|
|
12989
13418
|
}
|
|
12990
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
|
+
|
|
12991
13468
|
/**
|
|
12992
13469
|
* Serialize data to string using SerializationContext.
|
|
12993
13470
|
*
|
|
@@ -13000,12 +13477,12 @@ async function _serialize(data) {
|
|
|
13000
13477
|
return serializationContext.$writer$.toString();
|
|
13001
13478
|
}
|
|
13002
13479
|
/**
|
|
13003
|
-
* Deserialize data from string
|
|
13480
|
+
* Deserialize data from string.
|
|
13004
13481
|
*
|
|
13005
13482
|
* @param rawStateData - Data to deserialize
|
|
13006
13483
|
* @internal
|
|
13007
13484
|
*/
|
|
13008
|
-
function _deserialize(rawStateData) {
|
|
13485
|
+
async function _deserialize(rawStateData) {
|
|
13009
13486
|
if (rawStateData == null) {
|
|
13010
13487
|
throw new Error('No state data to deserialize');
|
|
13011
13488
|
}
|
|
@@ -13013,9 +13490,18 @@ function _deserialize(rawStateData) {
|
|
|
13013
13490
|
if (!Array.isArray(stateData) || stateData.length < 2 || typeof stateData[0] !== 'number') {
|
|
13014
13491
|
throw new Error('Invalid state data');
|
|
13015
13492
|
}
|
|
13016
|
-
const
|
|
13017
|
-
|
|
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];
|
|
13018
13498
|
}
|
|
13499
|
+
const runDeserializeIterator = (iterator) => {
|
|
13500
|
+
return new Promise((resolve, reject) => {
|
|
13501
|
+
const state = createYieldingIteratorState(iterator, resolve, reject);
|
|
13502
|
+
scheduleYieldingIterator(state);
|
|
13503
|
+
});
|
|
13504
|
+
};
|
|
13019
13505
|
function getObjectById(id, stateData) {
|
|
13020
13506
|
if (typeof id === 'string') {
|
|
13021
13507
|
id = parseInt(id, 10);
|
|
@@ -13029,8 +13515,14 @@ function getObjectById(id, stateData) {
|
|
|
13029
13515
|
function _createDeserializeContainer(stateData) {
|
|
13030
13516
|
// eslint-disable-next-line prefer-const
|
|
13031
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) {
|
|
13032
13524
|
const container = {
|
|
13033
|
-
$getObjectById$: (id) => getObjectById(id,
|
|
13525
|
+
$getObjectById$: (id) => getObjectById(id, getState()),
|
|
13034
13526
|
$getForwardRef$: (id) => container.$forwardRefs$?.[Number(id)],
|
|
13035
13527
|
getSyncFn: (_) => {
|
|
13036
13528
|
const fn = () => { };
|
|
@@ -13041,8 +13533,6 @@ function _createDeserializeContainer(stateData) {
|
|
|
13041
13533
|
$forwardRefs$: null,
|
|
13042
13534
|
};
|
|
13043
13535
|
preprocessState(stateData, container);
|
|
13044
|
-
state = wrapDeserializerProxy(container, stateData);
|
|
13045
|
-
container.$state$ = state;
|
|
13046
13536
|
return container;
|
|
13047
13537
|
}
|
|
13048
13538
|
|
|
@@ -13594,13 +14084,12 @@ const mergeSubscriptionSet = (container, producer, backRef, rootEffects, patchEf
|
|
|
13594
14084
|
};
|
|
13595
14085
|
|
|
13596
14086
|
const processedStatePatchScripts = new WeakMap();
|
|
13597
|
-
|
|
13598
|
-
const processSegmentStateScripts = (container, segmentId) => {
|
|
14087
|
+
function* processSegmentStateScriptsIterator(container, segmentId) {
|
|
13599
14088
|
if (!__EXPERIMENTAL__.suspense) {
|
|
13600
14089
|
return;
|
|
13601
14090
|
}
|
|
13602
14091
|
const stateContainer = container;
|
|
13603
|
-
const qwikStates = stateContainer.element.querySelectorAll(
|
|
14092
|
+
const qwikStates = stateContainer.element.querySelectorAll(`script[type="qwik/state"][q\\:instance="${stateContainer.$instanceHash$}"]${QStatePatchAttrSelector}`);
|
|
13604
14093
|
const processedScripts = getProcessedStatePatchScripts(container);
|
|
13605
14094
|
for (let i = 0; i < qwikStates.length; i++) {
|
|
13606
14095
|
const stateScript = qwikStates[i];
|
|
@@ -13611,9 +14100,10 @@ const processSegmentStateScripts = (container, segmentId) => {
|
|
|
13611
14100
|
continue;
|
|
13612
14101
|
}
|
|
13613
14102
|
processedScripts.add(stateScript);
|
|
13614
|
-
processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14103
|
+
yield* processStatePatch(container, stateContainer, stateScript.textContent);
|
|
14104
|
+
yield;
|
|
13615
14105
|
}
|
|
13616
|
-
}
|
|
14106
|
+
}
|
|
13617
14107
|
const getProcessedStatePatchScripts = (container) => {
|
|
13618
14108
|
let processedScripts = processedStatePatchScripts.get(container);
|
|
13619
14109
|
if (!processedScripts) {
|
|
@@ -13622,20 +14112,18 @@ const getProcessedStatePatchScripts = (container) => {
|
|
|
13622
14112
|
}
|
|
13623
14113
|
return processedScripts;
|
|
13624
14114
|
};
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
const processStatePatch = (container, stateContainer, textContent) => {
|
|
13629
|
-
if (textContent) {
|
|
13630
|
-
const [rootStart, rawStateData, forwardRefs, subscriptionPatchRootId] = JSON.parse(textContent);
|
|
13631
|
-
appendStatePatchRoots(container, stateContainer, rootStart, rawStateData);
|
|
13632
|
-
mergeForwardRefs(stateContainer, forwardRefs || undefined);
|
|
13633
|
-
applySubscriptionPatches(container, subscriptionPatchRootId === undefined
|
|
13634
|
-
? undefined
|
|
13635
|
-
: stateContainer.$getObjectById$(subscriptionPatchRootId));
|
|
14115
|
+
function* processStatePatch(container, stateContainer, textContent) {
|
|
14116
|
+
if (!textContent) {
|
|
14117
|
+
return;
|
|
13636
14118
|
}
|
|
13637
|
-
|
|
13638
|
-
|
|
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) {
|
|
13639
14127
|
const currentRootCount = stateContainer.$rawStateData$.length / 2;
|
|
13640
14128
|
if (rootStart !== currentRootCount) {
|
|
13641
14129
|
if (qDev) {
|
|
@@ -13645,12 +14133,13 @@ const appendStatePatchRoots = (container, stateContainer, rootStart, rawStateDat
|
|
|
13645
14133
|
}
|
|
13646
14134
|
for (let i = 0; i < rawStateData.length; i++) {
|
|
13647
14135
|
stateContainer.$rawStateData$[rootStart * 2 + i] = rawStateData[i];
|
|
14136
|
+
yield;
|
|
13648
14137
|
}
|
|
13649
|
-
|
|
14138
|
+
yield* preprocessStateIterator(stateContainer.$rawStateData$, container, rootStart * 2);
|
|
13650
14139
|
stateContainer.$stateData$ = wrapDeserializerProxy(container, stateContainer.$rawStateData$);
|
|
13651
14140
|
stateContainer.$stateData$.length = stateContainer.$rawStateData$.length / 2;
|
|
13652
14141
|
stateContainer.$rootForwardRefs$ = stateContainer.$forwardRefs$;
|
|
13653
|
-
}
|
|
14142
|
+
}
|
|
13654
14143
|
const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
13655
14144
|
if (!forwardRefs) {
|
|
13656
14145
|
return;
|
|
@@ -13665,24 +14154,172 @@ const mergeForwardRefs = (stateContainer, forwardRefs) => {
|
|
|
13665
14154
|
stateContainer.$forwardRefs$ = rootForwardRefs;
|
|
13666
14155
|
};
|
|
13667
14156
|
|
|
13668
|
-
|
|
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
|
+
}
|
|
13669
14224
|
function processOutOfOrderSegmentVNodeData(document, segmentId, contentNode) {
|
|
13670
14225
|
if (!__EXPERIMENTAL__.suspense || !contentNode) {
|
|
13671
14226
|
return;
|
|
13672
14227
|
}
|
|
13673
14228
|
const qContainerElement = contentNode.closest('[q\\:container]');
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
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
|
+
}
|
|
14296
|
+
}
|
|
14297
|
+
}
|
|
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]);
|
|
13679
14309
|
}
|
|
13680
14310
|
}
|
|
13681
|
-
function
|
|
13682
|
-
|
|
13683
|
-
|
|
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
|
+
}
|
|
13684
14321
|
}
|
|
13685
|
-
function processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData) {
|
|
14322
|
+
function* processVNodeDataImpl(document, segmentId, segmentContainer, segmentContent, segmentVNodeData) {
|
|
13686
14323
|
const Q_CONTAINER = 'q:container';
|
|
13687
14324
|
const Q_CONTAINER_END = '/' + Q_CONTAINER;
|
|
13688
14325
|
const Q_PROPS_SEPARATOR = ':';
|
|
@@ -13691,9 +14328,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13691
14328
|
const Q_IGNORE_END = '/' + Q_IGNORE;
|
|
13692
14329
|
const Q_CONTAINER_ISLAND = 'q:container-island';
|
|
13693
14330
|
const Q_CONTAINER_ISLAND_END = '/' + Q_CONTAINER_ISLAND;
|
|
13694
|
-
const Q_SUSPENSE_RESOLVED = 'q:r';
|
|
13695
14331
|
const Q_SUSPENSE_RESULT_PARENT = 'q:rp';
|
|
13696
|
-
const Q_PATCH = 'q:patch';
|
|
13697
14332
|
const qDocument = document;
|
|
13698
14333
|
const vNodeDataMap = (qDocument.qVNodeData ||= new WeakMap());
|
|
13699
14334
|
const prototype = document.body;
|
|
@@ -13711,7 +14346,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13711
14346
|
const hasAttribute = prototype.hasAttribute;
|
|
13712
14347
|
const getNodeType = getter(prototype, 'nodeType');
|
|
13713
14348
|
// Process all of the `qwik/vnode` script tags by attaching them to the corresponding containers.
|
|
13714
|
-
const attachVnodeDataAndRefs = (element)
|
|
14349
|
+
const attachVnodeDataAndRefs = function* (element) {
|
|
13715
14350
|
const scripts = element.querySelectorAll('script[type="qwik/vnode"]');
|
|
13716
14351
|
for (let i = 0; i < scripts.length; i++) {
|
|
13717
14352
|
const script = scripts[i];
|
|
@@ -13719,6 +14354,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13719
14354
|
qContainer.qVNodeRefs ||= new Map();
|
|
13720
14355
|
if (script.hasAttribute(Q_PATCH)) {
|
|
13721
14356
|
qDocument.qProcessVNodeDataPatch?.(script);
|
|
14357
|
+
yield;
|
|
13722
14358
|
continue;
|
|
13723
14359
|
}
|
|
13724
14360
|
const scriptContent = script.textContent;
|
|
@@ -13729,14 +14365,21 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13729
14365
|
else {
|
|
13730
14366
|
qContainer.qVnodeData = scriptContent;
|
|
13731
14367
|
}
|
|
14368
|
+
yield;
|
|
13732
14369
|
}
|
|
13733
14370
|
const shadowRoots = element.querySelectorAll('[q\\:shadowroot]');
|
|
13734
14371
|
for (let i = 0; i < shadowRoots.length; i++) {
|
|
13735
14372
|
const parent = shadowRoots[i];
|
|
13736
14373
|
const shadowRoot = parent.shadowRoot;
|
|
13737
|
-
|
|
14374
|
+
if (shadowRoot) {
|
|
14375
|
+
yield* attachVnodeDataAndRefs(shadowRoot);
|
|
14376
|
+
}
|
|
14377
|
+
yield;
|
|
13738
14378
|
}
|
|
13739
14379
|
};
|
|
14380
|
+
///////////////////////////////
|
|
14381
|
+
// Functions to consume the tree.
|
|
14382
|
+
///////////////////////////////
|
|
13740
14383
|
/**
|
|
13741
14384
|
* Looks up which type of node this is in a monomorphic way which should be faster.
|
|
13742
14385
|
*
|
|
@@ -13792,7 +14435,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13792
14435
|
* @param exitNode The node which represents the last node and we should exit.
|
|
13793
14436
|
* @param qVNodeRefs Place to store the VNodeRefs
|
|
13794
14437
|
*/
|
|
13795
|
-
const walkContainer = (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId)
|
|
14438
|
+
const walkContainer = function* (walker, containerNode, node, exitNode, vData, qVNodeRefs, qContainerElement, segmentId) {
|
|
13796
14439
|
const isSegment = __EXPERIMENTAL__.suspense && segmentId !== undefined;
|
|
13797
14440
|
const vData_length = vData.length;
|
|
13798
14441
|
/// Stores the current element index as the TreeWalker traverses the DOM.
|
|
@@ -13818,6 +14461,9 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13818
14461
|
}
|
|
13819
14462
|
return elementsToSkip;
|
|
13820
14463
|
};
|
|
14464
|
+
if (!node) {
|
|
14465
|
+
return;
|
|
14466
|
+
}
|
|
13821
14467
|
do {
|
|
13822
14468
|
if (node === exitNode) {
|
|
13823
14469
|
return;
|
|
@@ -13831,7 +14477,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13831
14477
|
while (cursor && !(nextNode = nextSibling(cursor))) {
|
|
13832
14478
|
cursor = cursor.parentNode;
|
|
13833
14479
|
}
|
|
13834
|
-
walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
14480
|
+
yield* walkContainer(walker, container, node, nextNode, container.qVnodeData || '', container.qVNodeRefs, container);
|
|
13835
14481
|
}
|
|
13836
14482
|
else if (nodeType === 16 /* NodeType.COMMENT_IGNORE_START */) {
|
|
13837
14483
|
let islandNode = node;
|
|
@@ -13866,7 +14512,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13866
14512
|
throw new Error(`<!--${node?.nodeValue}--> not closed!`);
|
|
13867
14513
|
}
|
|
13868
14514
|
} while (getFastNodeType(nextNode) !== 8 /* NodeType.COMMENT_SKIP_END */);
|
|
13869
|
-
walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
14515
|
+
yield* walkContainer(walker, node, node, nextNode, '', null, qContainerElement);
|
|
13870
14516
|
}
|
|
13871
14517
|
else if (nodeType === 6 /* NodeType.ELEMENT_SHADOW_ROOT_WRAPPER */) {
|
|
13872
14518
|
// If we are in a shadow root, we need to get the shadow root element.
|
|
@@ -13874,7 +14520,7 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13874
14520
|
const shadowRootContainer = node;
|
|
13875
14521
|
const shadowRoot = shadowRootContainer?.shadowRoot;
|
|
13876
14522
|
if (shadowRoot) {
|
|
13877
|
-
walkContainer(
|
|
14523
|
+
yield* walkContainer(
|
|
13878
14524
|
// we need to create a new walker for the shadow root
|
|
13879
14525
|
document.createTreeWalker(shadowRoot, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, shadowRoot, null, '', null, null);
|
|
13880
14526
|
}
|
|
@@ -13937,51 +14583,42 @@ function processVNodeDataImpl(document, segmentId, segmentContainer, segmentCont
|
|
|
13937
14583
|
}
|
|
13938
14584
|
elementIdx++;
|
|
13939
14585
|
if (__EXPERIMENTAL__.suspense && contentBoundaryId !== null) {
|
|
13940
|
-
processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
14586
|
+
yield* processSuspenseContentSegment(qContainerElement, node, contentBoundaryId);
|
|
13941
14587
|
nextNode = nextSibling(node);
|
|
13942
14588
|
if (nextNode) {
|
|
13943
14589
|
walker.currentNode = nextNode;
|
|
13944
14590
|
}
|
|
13945
14591
|
}
|
|
13946
14592
|
}
|
|
14593
|
+
yield;
|
|
13947
14594
|
} while ((node = nextNode || walker.nextNode()));
|
|
13948
14595
|
};
|
|
13949
|
-
const processVNodeDataScope = (qContainerElement, contentNode, vData, scopeSegmentId)
|
|
14596
|
+
const processVNodeDataScope = function* (qContainerElement, contentNode, vData, scopeSegmentId) {
|
|
13950
14597
|
qContainerElement.qVNodeRefs ||= new Map();
|
|
13951
14598
|
const scopeWalker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13952
14599
|
scopeWalker.currentNode = contentNode;
|
|
13953
|
-
walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
14600
|
+
yield* walkContainer(scopeWalker, contentNode, contentNode, nextSibling(contentNode), vData, qContainerElement.qVNodeRefs, qContainerElement, scopeSegmentId);
|
|
13954
14601
|
};
|
|
13955
|
-
const processSuspenseContentSegment =
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
processVNodeDataScope(qContainerElement, contentNode, vData, boundaryId);
|
|
13960
|
-
}
|
|
13961
|
-
}
|
|
13962
|
-
: null;
|
|
13963
|
-
qDocument.qProcessVNodeDataPatch = (script) => {
|
|
13964
|
-
const qContainerElement = script?.closest('[q\\:container]');
|
|
13965
|
-
const patchSegment = script?.getAttribute(Q_SUSPENSE_RESOLVED);
|
|
13966
|
-
const contentNode = qContainerElement &&
|
|
13967
|
-
(patchSegment
|
|
13968
|
-
? qContainerElement.querySelector(`[q\\:rp="${patchSegment}"]`)
|
|
13969
|
-
: qContainerElement);
|
|
13970
|
-
if (qContainerElement && contentNode) {
|
|
13971
|
-
processVNodeDataScope(qContainerElement, contentNode, script.textContent, patchSegment || undefined);
|
|
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);
|
|
13972
14606
|
}
|
|
13973
14607
|
};
|
|
13974
|
-
if (
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
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);
|
|
13978
14615
|
}
|
|
13979
14616
|
return;
|
|
13980
14617
|
}
|
|
13981
|
-
attachVnodeDataAndRefs(document);
|
|
14618
|
+
yield* attachVnodeDataAndRefs(document);
|
|
13982
14619
|
// Walk the tree and process each `q:container` element.
|
|
13983
14620
|
const walker = document.createTreeWalker(document, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */);
|
|
13984
|
-
walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
14621
|
+
yield* walkContainer(walker, null, walker.firstChild(), null, '', null, null);
|
|
13985
14622
|
}
|
|
13986
14623
|
const isSeparator = (ch) =>
|
|
13987
14624
|
/* `!` */ VNodeDataSeparator.ADVANCE_1 <= ch && ch <= VNodeDataSeparator.ADVANCE_8192; /* `.` */
|
|
@@ -14016,6 +14653,87 @@ const findVDataSectionEnd = (vData, start, end) => {
|
|
|
14016
14653
|
return start;
|
|
14017
14654
|
};
|
|
14018
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
|
+
|
|
14019
14737
|
/** @file Public APIs for the SSR */
|
|
14020
14738
|
/** @public */
|
|
14021
14739
|
function getDomContainer(element) {
|
|
@@ -14038,8 +14756,12 @@ function getOutOfOrderStreamingScript(boundaryId, content) {
|
|
|
14038
14756
|
const qContainerElement = content?.closest(QContainerSelector);
|
|
14039
14757
|
const qContainer = qContainerElement?.qContainer;
|
|
14040
14758
|
if (qContainer) {
|
|
14041
|
-
|
|
14042
|
-
|
|
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
|
+
});
|
|
14043
14765
|
}
|
|
14044
14766
|
}
|
|
14045
14767
|
/** @internal */
|
|
@@ -14054,6 +14776,9 @@ class DomContainer extends _SharedContainer {
|
|
|
14054
14776
|
$instanceHash$;
|
|
14055
14777
|
$forwardRefs$ = null;
|
|
14056
14778
|
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
14779
|
+
$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14780
|
+
$containerStateReadyCallbacks$ = undefined;
|
|
14781
|
+
$containerStateDataState$ = undefined;
|
|
14057
14782
|
$rawStateData$;
|
|
14058
14783
|
$stateData$;
|
|
14059
14784
|
$rootForwardRefs$ = null;
|
|
@@ -14064,7 +14789,8 @@ class DomContainer extends _SharedContainer {
|
|
|
14064
14789
|
if (!this.qContainer) {
|
|
14065
14790
|
throw qError(25 /* QError.elementWithoutContainer */);
|
|
14066
14791
|
}
|
|
14067
|
-
|
|
14792
|
+
const document = element.ownerDocument;
|
|
14793
|
+
this.document = document;
|
|
14068
14794
|
this.element = element;
|
|
14069
14795
|
this.$buildBase$ = element.getAttribute(QBaseAttr);
|
|
14070
14796
|
this.$instanceHash$ = element.getAttribute(QInstanceAttr);
|
|
@@ -14072,23 +14798,46 @@ class DomContainer extends _SharedContainer {
|
|
|
14072
14798
|
this.rootVNode = vnode_newUnMaterializedElement(this.element);
|
|
14073
14799
|
this.$rawStateData$ = [];
|
|
14074
14800
|
this.$stateData$ = [];
|
|
14075
|
-
const document = this.element.ownerDocument;
|
|
14076
|
-
if (!document.qVNodeDataProcessed) {
|
|
14077
|
-
processVNodeData(document);
|
|
14078
|
-
}
|
|
14079
14801
|
if (__EXPERIMENTAL__.suspense && document.querySelector('template[q\\:r]')) {
|
|
14080
14802
|
document.qProcessOOOS ||= getOutOfOrderStreamingScript;
|
|
14081
14803
|
}
|
|
14082
14804
|
this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
|
|
14083
14805
|
this.$setServerData$();
|
|
14084
|
-
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14085
14806
|
element.qContainer = this;
|
|
14086
14807
|
element.qDestroy = () => this.$destroy$();
|
|
14087
|
-
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
|
+
}
|
|
14088
14836
|
if (__EXPERIMENTAL__.suspense) {
|
|
14089
|
-
|
|
14837
|
+
yield* processSegmentStateScriptsIterator(this);
|
|
14090
14838
|
}
|
|
14091
14839
|
this.$hoistStyles$();
|
|
14840
|
+
element.setAttribute(QContainerAttr, "resumed" /* QContainerValue.RESUMED */);
|
|
14092
14841
|
if (!qTest && element.isConnected) {
|
|
14093
14842
|
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
|
|
14094
14843
|
}
|
|
@@ -14108,9 +14857,15 @@ class DomContainer extends _SharedContainer {
|
|
|
14108
14857
|
}
|
|
14109
14858
|
el.removeAttribute(QContainerAttr);
|
|
14110
14859
|
const document = el.ownerDocument;
|
|
14860
|
+
this.$containerStateDataState$ = undefined;
|
|
14861
|
+
this.$containerDataProcessState$ = 0 /* ContainerDataProcessState.NotStarted */;
|
|
14111
14862
|
const hasContainers = document.querySelector(QContainerSelector) !== null;
|
|
14112
14863
|
if (!hasContainers) {
|
|
14113
14864
|
document.qVNodeData = undefined;
|
|
14865
|
+
document.qVNodeDataStarted = undefined;
|
|
14866
|
+
document.qVNodeDataReady = undefined;
|
|
14867
|
+
document.qVNodeDataState = undefined;
|
|
14868
|
+
document.qVNodeDataCallbacks = undefined;
|
|
14114
14869
|
document.qVNodeDataProcessed = undefined;
|
|
14115
14870
|
document.qProcessVNodeDataPatch = undefined;
|
|
14116
14871
|
}
|
|
@@ -14120,18 +14875,6 @@ class DomContainer extends _SharedContainer {
|
|
|
14120
14875
|
}
|
|
14121
14876
|
}
|
|
14122
14877
|
}
|
|
14123
|
-
$processRootStateScript$() {
|
|
14124
|
-
const rootState = this.element.querySelector(`${this.$stateScriptSelector$()}:not(${QStatePatchAttrSelector})`);
|
|
14125
|
-
if (rootState) {
|
|
14126
|
-
this.$rawStateData$ = JSON.parse(rootState.textContent);
|
|
14127
|
-
preprocessState(this.$rawStateData$, this);
|
|
14128
|
-
this.$rootForwardRefs$ = this.$forwardRefs$;
|
|
14129
|
-
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
14130
|
-
}
|
|
14131
|
-
}
|
|
14132
|
-
$stateScriptSelector$() {
|
|
14133
|
-
return `script[type="qwik/state"][q\\:instance="${this.$instanceHash$}"]`;
|
|
14134
|
-
}
|
|
14135
14878
|
/**
|
|
14136
14879
|
* The first time we render we need to hoist the styles. (Meaning we need to move all styles from
|
|
14137
14880
|
* component inline to <head>)
|
|
@@ -14420,8 +15163,7 @@ function invokeApply(context, fn, args) {
|
|
|
14420
15163
|
_context = previousContext;
|
|
14421
15164
|
}
|
|
14422
15165
|
}
|
|
14423
|
-
const newInvokeContextFromDOM = (event, element) => {
|
|
14424
|
-
const domContainer = getDomContainer(element);
|
|
15166
|
+
const newInvokeContextFromDOM = (event, element, domContainer = getDomContainer(element)) => {
|
|
14425
15167
|
const hostElement = vnode_locate(domContainer.rootVNode, element);
|
|
14426
15168
|
const locale = domContainer.$locale$;
|
|
14427
15169
|
locale && setLocale(locale);
|
|
@@ -14563,7 +15305,7 @@ const initLazyRefDev = (lazy) => {
|
|
|
14563
15305
|
};
|
|
14564
15306
|
/** Validate captured scope and register WeakRef tracking on a QRLClass instance. */
|
|
14565
15307
|
const initQrlClassDev = (lazy, captures, qrl) => {
|
|
14566
|
-
if (captures
|
|
15308
|
+
if (Array.isArray(captures)) {
|
|
14567
15309
|
for (let i = 0; i < captures.length; i++) {
|
|
14568
15310
|
const item = captures[i];
|
|
14569
15311
|
verifySerializable(item, 'Captured variable in the closure can not be serialized');
|
|
@@ -14765,7 +15507,9 @@ class QRLClass {
|
|
|
14765
15507
|
}
|
|
14766
15508
|
// If it is plain value with deserialized or missing captures, resolve it immediately
|
|
14767
15509
|
// Otherwise we keep using the async path so we can wait for qrls to load
|
|
14768
|
-
if ($lazy$.$ref$ != null &&
|
|
15510
|
+
if ($lazy$.$ref$ != null &&
|
|
15511
|
+
(!this.$captures$ || typeof this.$captures$ !== 'string') &&
|
|
15512
|
+
!isPromise($lazy$.$ref$)) {
|
|
14769
15513
|
this.resolved = bindCaptures(this, $lazy$.$ref$);
|
|
14770
15514
|
}
|
|
14771
15515
|
}
|
|
@@ -14920,31 +15664,50 @@ let _captures = null;
|
|
|
14920
15664
|
const setCaptures = (captures) => {
|
|
14921
15665
|
_captures = captures;
|
|
14922
15666
|
};
|
|
14923
|
-
const
|
|
15667
|
+
const deserializeCaptureDeltas = (container, deltaString, startIndex = 0, previousRootId) => {
|
|
14924
15668
|
const refs = [];
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
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
|
+
}
|
|
14929
15680
|
}
|
|
14930
15681
|
return refs;
|
|
14931
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
|
+
};
|
|
14932
15692
|
/** Puts the qrl captures into `_captures`, and returns a Promise that should be awaited if possible */
|
|
14933
15693
|
const ensureQrlCaptures = (qrl) => {
|
|
14934
15694
|
// We read the captures once, synchronously, so no need to keep previous
|
|
14935
|
-
|
|
15695
|
+
const serializedCaptures = qrl.$captures$;
|
|
14936
15696
|
const container = qrl.$container$;
|
|
14937
|
-
if (typeof
|
|
15697
|
+
if (typeof serializedCaptures === 'string') {
|
|
14938
15698
|
if (!container) {
|
|
14939
15699
|
throw qError(13 /* QError.qrlMissingContainer */);
|
|
14940
15700
|
}
|
|
14941
15701
|
const prevLoading = loading;
|
|
14942
|
-
_captures = qrl.$captures$ =
|
|
15702
|
+
_captures = qrl.$captures$ = deserializeQrlCaptureDeltas(container, serializedCaptures);
|
|
14943
15703
|
if (loading !== prevLoading) {
|
|
14944
15704
|
// return the loading promise so callers can await it
|
|
14945
15705
|
return loading;
|
|
14946
15706
|
}
|
|
14947
15707
|
}
|
|
15708
|
+
else {
|
|
15709
|
+
_captures = serializedCaptures || null;
|
|
15710
|
+
}
|
|
14948
15711
|
};
|
|
14949
15712
|
// Wrap functions to provide their lexical scope
|
|
14950
15713
|
const bindCaptures = (qrl, ref) => {
|
|
@@ -15911,7 +16674,13 @@ const useComputedQrl = (qrl, options) => {
|
|
|
15911
16674
|
* recalculated, and if the result changed, all tasks which are tracking the signal will be re-run
|
|
15912
16675
|
* and all components that read the signal will be re-rendered.
|
|
15913
16676
|
*
|
|
15914
|
-
*
|
|
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.
|
|
15915
16684
|
*
|
|
15916
16685
|
* @public
|
|
15917
16686
|
*/
|
|
@@ -16009,7 +16778,7 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
16009
16778
|
// In SSR we defer execution until triggered in DOM
|
|
16010
16779
|
flags = 1 /* TaskFlags.VISIBLE_TASK */;
|
|
16011
16780
|
}
|
|
16012
|
-
const task = new Task(flags, i, iCtx.$hostElement$, qrl,
|
|
16781
|
+
const task = new Task(flags, i, iCtx.$hostElement$, qrl, null);
|
|
16013
16782
|
set(task);
|
|
16014
16783
|
useRegisterTaskEvents(task, eagerness);
|
|
16015
16784
|
};
|
|
@@ -16047,11 +16816,11 @@ const getTaskHandlerQrl = (task) => {
|
|
|
16047
16816
|
* Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
|
|
16048
16817
|
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
16049
16818
|
*
|
|
16050
|
-
* @deprecated Use `
|
|
16051
|
-
* available for backward compatibility but it is recommended to migrate to `
|
|
16052
|
-
* 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.
|
|
16053
16822
|
* @public
|
|
16054
|
-
* @see
|
|
16823
|
+
* @see useComputed$
|
|
16055
16824
|
* @see Resource
|
|
16056
16825
|
* @see ResourceReturn
|
|
16057
16826
|
*/
|
|
@@ -16156,7 +16925,10 @@ const creator = (qrl, options) => {
|
|
|
16156
16925
|
qrl.resolve();
|
|
16157
16926
|
return createAsyncSignal(qrl, options);
|
|
16158
16927
|
};
|
|
16159
|
-
/**
|
|
16928
|
+
/**
|
|
16929
|
+
* @deprecated Use `useComputed$` instead, it has async support now.
|
|
16930
|
+
* @internal
|
|
16931
|
+
*/
|
|
16160
16932
|
const useAsyncQrl = (qrl, options) => {
|
|
16161
16933
|
return useConstant((creator), qrl, options);
|
|
16162
16934
|
};
|
|
@@ -16179,6 +16951,8 @@ const useAsyncQrl = (qrl, options) => {
|
|
|
16179
16951
|
* will subscribe to it and return the last resolved value until the new value is ready. As soon as
|
|
16180
16952
|
* the new value is ready, the subscribers will be updated.
|
|
16181
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.
|
|
16182
16956
|
* @public
|
|
16183
16957
|
*/
|
|
16184
16958
|
const useAsync$ = implicit$FirstArg(useAsyncQrl);
|
|
@@ -16215,6 +16989,46 @@ const eachCmp = (props) => {
|
|
|
16215
16989
|
const Each = /*#__PURE__*/ componentQrl(
|
|
16216
16990
|
/*#__PURE__*/ inlinedQrl(eachCmp, '_eaC'));
|
|
16217
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
|
+
|
|
16218
17032
|
const RevealContext = /*#__PURE__*/ createContextId('qk-reveal');
|
|
16219
17033
|
const createRevealContext = (props) => {
|
|
16220
17034
|
return {
|
|
@@ -16608,5 +17422,5 @@ if (import.meta.hot) {
|
|
|
16608
17422
|
});
|
|
16609
17423
|
}
|
|
16610
17424
|
|
|
16611
|
-
export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, ELEMENT_SEQ as _ELEMENT_SEQ, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, Task as _Task, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, createStore as _createStore, delay as _delay, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, getSubscriber as _getSubscriber, _getVarProps, _hasStoreEffects, _hmr, _injectAsyncSignalValue, invoke as _invoke, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, newInvokeContext as _newInvokeContext, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, retryOnPromise as _retryOnPromise, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsync$, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getClientManifest, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsync$, useAsyncQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
|
|
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 };
|
|
16612
17426
|
//# sourceMappingURL=core.mjs.map
|