@qwik.dev/core 2.0.0-alpha.6 → 2.0.0-alpha.7
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/bindings/qwik.darwin-arm64.node +0 -0
- package/bindings/qwik.darwin-x64.node +0 -0
- package/bindings/qwik.linux-x64-gnu.node +0 -0
- package/bindings/qwik.win32-x64-msvc.node +0 -0
- package/bindings/qwik_wasm_bg.wasm +0 -0
- package/dist/build/package.json +1 -1
- package/dist/cli.cjs +65 -42
- package/dist/core-internal.d.ts +77 -76
- package/dist/core.cjs +1498 -1323
- package/dist/core.cjs.map +1 -1
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +1496 -1323
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.cjs +884 -782
- package/dist/core.prod.mjs +1006 -867
- package/dist/insights/index.qwik.cjs +3652 -154
- package/dist/insights/index.qwik.mjs +3652 -154
- package/dist/loader/index.cjs +2 -2
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.cjs +210 -5714
- package/dist/optimizer.mjs +191 -6037
- package/dist/prefetch/package.json +1 -1
- package/dist/qwikloader.debug.js +12 -15
- package/dist/qwikloader.js +2 -2
- package/dist/server.cjs +762 -7127
- package/dist/server.mjs +778 -7121
- package/dist/starters/adapters/fastify/src/plugins/fastify-qwik.ts +2 -0
- package/dist/starters/features/cypress/package.json +1 -1
- package/dist/starters/features/drizzle/drizzle/schema.ts +6 -18
- package/dist/starters/features/drizzle/drizzle.config.ts +5 -4
- package/dist/starters/features/drizzle/package.json +14 -11
- package/dist/starters/features/pandacss/package.json +1 -1
- package/dist/starters/features/partytown/package.json +1 -1
- package/dist/starters/features/postcss/package.json +1 -1
- package/dist/starters/features/prisma/package.json +1 -1
- package/dist/starters/features/react/package.json +1 -1
- package/dist/starters/features/storybook/package.json +1 -1
- package/dist/starters/features/styled-vanilla-extract/package.json +2 -1
- package/dist/starters/features/tailwind/package.json +15 -9
- package/dist/starters/features/tailwind/src/global.css +1 -7
- package/dist/starters/features/turso/package.json +1 -1
- package/dist/starters/features/vitest/package.json +1 -1
- package/dist/testing/index.cjs +1265 -1124
- package/dist/testing/index.mjs +1271 -1124
- package/dist/testing/package.json +1 -1
- package/handlers.mjs +9 -0
- package/package.json +6 -4
- package/public.d.ts +2 -0
- package/dist/starters/features/tailwind/.vscode/settings.json +0 -3
- package/dist/starters/features/tailwind/postcss.config.cjs +0 -6
- package/dist/starters/features/tailwind/tailwind.config.js +0 -8
package/dist/core.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* @qwik.dev/core 2.0.0-alpha.
|
|
3
|
+
* @qwik.dev/core 2.0.0-alpha.7-dev+a26598a
|
|
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
|
|
@@ -121,8 +121,8 @@
|
|
|
121
121
|
// Keep one error, one line to make it easier to search for the error message.
|
|
122
122
|
const MAP = [
|
|
123
123
|
'Error while serializing class or style attributes', // 0
|
|
124
|
-
'', // 1
|
|
125
|
-
'', // 2
|
|
124
|
+
'Scheduler not found', // 1
|
|
125
|
+
'track() received object, without prop to track', // 2
|
|
126
126
|
'Only primitive and object literals can be serialized. {{0}}', // 3
|
|
127
127
|
'', // 4 unused
|
|
128
128
|
'You can render over a existing q:container. Skipping render().', // 5
|
|
@@ -165,12 +165,11 @@
|
|
|
165
165
|
"Element must have 'q:container' attribute.", // 42
|
|
166
166
|
'Unknown vnode type {{0}}.', // 43
|
|
167
167
|
'Materialize error: missing element: {{0}} {{1}} {{2}}', // 44
|
|
168
|
-
'Cannot coerce a Signal, use `.value` instead', //
|
|
169
|
-
'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', //
|
|
170
|
-
'ComputedSignal is read-only', //
|
|
171
|
-
'WrappedSignal is read-only', //
|
|
172
|
-
'
|
|
173
|
-
'Attribute value is unsafe for SSR', // 51
|
|
168
|
+
'Cannot coerce a Signal, use `.value` instead', // 45
|
|
169
|
+
'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', // 46
|
|
170
|
+
'ComputedSignal is read-only', // 47
|
|
171
|
+
'WrappedSignal is read-only', // 48
|
|
172
|
+
'Attribute value is unsafe for SSR', // 49
|
|
174
173
|
];
|
|
175
174
|
let text = MAP[code] ?? '';
|
|
176
175
|
if (parts.length) {
|
|
@@ -192,8 +191,8 @@
|
|
|
192
191
|
var QError;
|
|
193
192
|
(function (QError) {
|
|
194
193
|
QError[QError["stringifyClassOrStyle"] = 0] = "stringifyClassOrStyle";
|
|
195
|
-
QError[QError["
|
|
196
|
-
QError[QError["
|
|
194
|
+
QError[QError["schedulerNotFound"] = 1] = "schedulerNotFound";
|
|
195
|
+
QError[QError["trackObjectWithoutProp"] = 2] = "trackObjectWithoutProp";
|
|
197
196
|
QError[QError["verifySerializable"] = 3] = "verifySerializable";
|
|
198
197
|
QError[QError["UNUSED_4"] = 4] = "UNUSED_4";
|
|
199
198
|
QError[QError["cannotRenderOverExistingContainer"] = 5] = "cannotRenderOverExistingContainer";
|
|
@@ -240,14 +239,37 @@
|
|
|
240
239
|
QError[QError["computedNotSync"] = 46] = "computedNotSync";
|
|
241
240
|
QError[QError["computedReadOnly"] = 47] = "computedReadOnly";
|
|
242
241
|
QError[QError["wrappedReadOnly"] = 48] = "wrappedReadOnly";
|
|
243
|
-
QError[QError["
|
|
244
|
-
QError[QError["unsafeAttr"] = 50] = "unsafeAttr";
|
|
242
|
+
QError[QError["unsafeAttr"] = 49] = "unsafeAttr";
|
|
245
243
|
})(QError || (QError = {}));
|
|
246
244
|
const qError = (code, errorMessageArgs = []) => {
|
|
247
245
|
const text = codeToText(code, ...errorMessageArgs);
|
|
248
246
|
return logErrorAndStop(text, ...errorMessageArgs);
|
|
249
247
|
};
|
|
250
248
|
|
|
249
|
+
/** QRL related utilities that you can import without importing all of Qwik. */
|
|
250
|
+
const SYNC_QRL = '<sync>';
|
|
251
|
+
/** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */
|
|
252
|
+
const isSyncQrl = (value) => {
|
|
253
|
+
return isQrl$1(value) && value.$symbol$ == SYNC_QRL;
|
|
254
|
+
};
|
|
255
|
+
const isQrl$1 = (value) => {
|
|
256
|
+
return typeof value === 'function' && typeof value.getSymbol === 'function';
|
|
257
|
+
};
|
|
258
|
+
function assertQrl(qrl) {
|
|
259
|
+
if (build.isDev) {
|
|
260
|
+
if (!isQrl$1(qrl)) {
|
|
261
|
+
throw new Error('Not a QRL');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const getSymbolHash = (symbolName) => {
|
|
266
|
+
const index = symbolName.lastIndexOf('_');
|
|
267
|
+
if (index > -1) {
|
|
268
|
+
return symbolName.slice(index + 1);
|
|
269
|
+
}
|
|
270
|
+
return symbolName;
|
|
271
|
+
};
|
|
272
|
+
|
|
251
273
|
/**
|
|
252
274
|
* A friendly name tag for a VirtualVNode.
|
|
253
275
|
*
|
|
@@ -291,7 +313,7 @@
|
|
|
291
313
|
/** State factory of the component. */
|
|
292
314
|
const OnRenderProp = 'q:renderFn';
|
|
293
315
|
/** Component style content prefix */
|
|
294
|
-
const ComponentStylesPrefixContent = '
|
|
316
|
+
const ComponentStylesPrefixContent = '⚡️';
|
|
295
317
|
/** `<some-element q:slot="...">` */
|
|
296
318
|
const QSlot = 'q:slot';
|
|
297
319
|
const QSlotParent = ':';
|
|
@@ -303,7 +325,7 @@
|
|
|
303
325
|
const QStylesAllSelector = QStyleSelector + ',' + QStyleSSelector;
|
|
304
326
|
const QScopedStyle = 'q:sstyle';
|
|
305
327
|
const QCtxAttr = 'q:ctx';
|
|
306
|
-
const
|
|
328
|
+
const QBackRefs = 'q:brefs';
|
|
307
329
|
const QFuncsPrefix = 'qFuncs_';
|
|
308
330
|
const getQFuncs = (document, hash) => {
|
|
309
331
|
return document[QFuncsPrefix + hash] || [];
|
|
@@ -499,11 +521,6 @@
|
|
|
499
521
|
? valueOrPromise.then(thenFn, shouldNotError)
|
|
500
522
|
: thenFn(valueOrPromise);
|
|
501
523
|
};
|
|
502
|
-
const maybeThenPassError = (valueOrPromise, thenFn) => {
|
|
503
|
-
return isPromise(valueOrPromise)
|
|
504
|
-
? valueOrPromise.then(thenFn)
|
|
505
|
-
: thenFn(valueOrPromise);
|
|
506
|
-
};
|
|
507
524
|
const shouldNotError = (reason) => {
|
|
508
525
|
throwErrorAndStop(reason);
|
|
509
526
|
};
|
|
@@ -621,7 +638,7 @@
|
|
|
621
638
|
_locale = locale;
|
|
622
639
|
}
|
|
623
640
|
|
|
624
|
-
const isQrl
|
|
641
|
+
const isQrl = (value) => {
|
|
625
642
|
return typeof value === 'function' && typeof value.getSymbol === 'function';
|
|
626
643
|
};
|
|
627
644
|
|
|
@@ -693,21 +710,21 @@
|
|
|
693
710
|
// Emit event
|
|
694
711
|
announcedQRL.add(symbol);
|
|
695
712
|
emitEvent('qprefetch', {
|
|
696
|
-
symbols: [
|
|
713
|
+
symbols: [symbol],
|
|
697
714
|
bundles: chunk && [chunk],
|
|
698
715
|
});
|
|
699
716
|
}
|
|
700
717
|
// Unwrap subscribers
|
|
701
|
-
return createQRL(chunk, symbol, null, symbolFn, null, lexicalScopeCapture
|
|
718
|
+
return createQRL(chunk, symbol, null, symbolFn, null, lexicalScopeCapture);
|
|
702
719
|
};
|
|
703
720
|
/** @internal */
|
|
704
721
|
const inlinedQrl = (symbol, symbolName, lexicalScopeCapture = EMPTY_ARRAY) => {
|
|
705
722
|
// Unwrap subscribers
|
|
706
|
-
return createQRL(null, symbolName, symbol, null, null, lexicalScopeCapture
|
|
723
|
+
return createQRL(null, symbolName, symbol, null, null, lexicalScopeCapture);
|
|
707
724
|
};
|
|
708
725
|
/** @internal */
|
|
709
726
|
const _noopQrl = (symbolName, lexicalScopeCapture = EMPTY_ARRAY) => {
|
|
710
|
-
return createQRL(null, symbolName, null, null, null, lexicalScopeCapture
|
|
727
|
+
return createQRL(null, symbolName, null, null, null, lexicalScopeCapture);
|
|
711
728
|
};
|
|
712
729
|
/** @internal */
|
|
713
730
|
const _noopQrlDEV = (symbolName, opts, lexicalScopeCapture = EMPTY_ARRAY) => {
|
|
@@ -736,6 +753,80 @@
|
|
|
736
753
|
return symbol;
|
|
737
754
|
};
|
|
738
755
|
|
|
756
|
+
var ChoreType;
|
|
757
|
+
(function (ChoreType) {
|
|
758
|
+
/// MASKS defining three levels of sorting
|
|
759
|
+
ChoreType[ChoreType["MACRO"] = 240] = "MACRO";
|
|
760
|
+
/* order of elements (not encoded here) */
|
|
761
|
+
ChoreType[ChoreType["MICRO"] = 15] = "MICRO";
|
|
762
|
+
/** Ensure that the QRL promise is resolved before processing next chores in the queue */
|
|
763
|
+
ChoreType[ChoreType["QRL_RESOLVE"] = 1] = "QRL_RESOLVE";
|
|
764
|
+
ChoreType[ChoreType["RUN_QRL"] = 2] = "RUN_QRL";
|
|
765
|
+
ChoreType[ChoreType["TASK"] = 3] = "TASK";
|
|
766
|
+
ChoreType[ChoreType["NODE_DIFF"] = 4] = "NODE_DIFF";
|
|
767
|
+
ChoreType[ChoreType["NODE_PROP"] = 5] = "NODE_PROP";
|
|
768
|
+
ChoreType[ChoreType["COMPONENT"] = 6] = "COMPONENT";
|
|
769
|
+
ChoreType[ChoreType["RECOMPUTE_AND_SCHEDULE_EFFECTS"] = 7] = "RECOMPUTE_AND_SCHEDULE_EFFECTS";
|
|
770
|
+
// Next macro level
|
|
771
|
+
ChoreType[ChoreType["JOURNAL_FLUSH"] = 16] = "JOURNAL_FLUSH";
|
|
772
|
+
// Next macro level
|
|
773
|
+
ChoreType[ChoreType["VISIBLE"] = 32] = "VISIBLE";
|
|
774
|
+
// Next macro level
|
|
775
|
+
ChoreType[ChoreType["CLEANUP_VISIBLE"] = 48] = "CLEANUP_VISIBLE";
|
|
776
|
+
// Next macro level
|
|
777
|
+
ChoreType[ChoreType["WAIT_FOR_ALL"] = 255] = "WAIT_FOR_ALL";
|
|
778
|
+
})(ChoreType || (ChoreType = {}));
|
|
779
|
+
|
|
780
|
+
// <docs markdown="../readme.md#useLexicalScope">
|
|
781
|
+
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
782
|
+
// (edit ../readme.md#useLexicalScope instead and run `pnpm docs.sync`)
|
|
783
|
+
/**
|
|
784
|
+
* Used by the Qwik Optimizer to restore the lexically scoped variables.
|
|
785
|
+
*
|
|
786
|
+
* This method should not be present in the application source code.
|
|
787
|
+
*
|
|
788
|
+
* NOTE: `useLexicalScope` method can only be used in the synchronous portion of the callback
|
|
789
|
+
* (before any `await` statements.)
|
|
790
|
+
*
|
|
791
|
+
* @internal
|
|
792
|
+
*/
|
|
793
|
+
// </docs>
|
|
794
|
+
const useLexicalScope = () => {
|
|
795
|
+
const context = getInvokeContext();
|
|
796
|
+
let qrl = context.$qrl$;
|
|
797
|
+
if (!qrl) {
|
|
798
|
+
const el = context.$element$;
|
|
799
|
+
assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
800
|
+
const containerElement = _getQContainerElement(el);
|
|
801
|
+
assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
802
|
+
const container = getDomContainer(containerElement);
|
|
803
|
+
qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
assertQrl(qrl);
|
|
807
|
+
assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
|
|
808
|
+
}
|
|
809
|
+
return qrl.$captureRef$;
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* This is called by qwik-loader to schedule a QRL. It has to be synchronous.
|
|
814
|
+
*
|
|
815
|
+
* @internal
|
|
816
|
+
*/
|
|
817
|
+
const queueQRL = (...args) => {
|
|
818
|
+
// This will already check container
|
|
819
|
+
const [runQrl] = useLexicalScope();
|
|
820
|
+
const context = getInvokeContext();
|
|
821
|
+
const hostElement = context.$hostElement$;
|
|
822
|
+
const container = getDomContainer(hostElement);
|
|
823
|
+
const scheduler = container.$scheduler$;
|
|
824
|
+
if (!scheduler) {
|
|
825
|
+
throw qError(QError.schedulerNotFound);
|
|
826
|
+
}
|
|
827
|
+
return scheduler(ChoreType.RUN_QRL, hostElement, runQrl, args);
|
|
828
|
+
};
|
|
829
|
+
|
|
739
830
|
/**
|
|
740
831
|
* Allows to project the children of the current component. <Slot/> can only be used within the
|
|
741
832
|
* context of a component defined with `component$`.
|
|
@@ -860,6 +951,47 @@
|
|
|
860
951
|
return key.startsWith('preventdefault:');
|
|
861
952
|
}
|
|
862
953
|
|
|
954
|
+
function getFileLocationFromJsx(jsxDev) {
|
|
955
|
+
if (!jsxDev) {
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
const sanitizedFileName = jsxDev.fileName?.replace(/\\/g, '/');
|
|
959
|
+
if (sanitizedFileName) {
|
|
960
|
+
return `${sanitizedFileName}:${jsxDev.lineNumber}:${jsxDev.columnNumber}`;
|
|
961
|
+
}
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const styleContent = (styleId) => {
|
|
966
|
+
return ComponentStylesPrefixContent + styleId;
|
|
967
|
+
};
|
|
968
|
+
function hasClassAttr(props) {
|
|
969
|
+
for (const key in props) {
|
|
970
|
+
if (Object.prototype.hasOwnProperty.call(props, key) && isClassAttr(key)) {
|
|
971
|
+
return true;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
function isClassAttr(key) {
|
|
977
|
+
return key === 'class' || key === 'className';
|
|
978
|
+
}
|
|
979
|
+
function convertScopedStyleIdsToArray(scopedStyleIds) {
|
|
980
|
+
return scopedStyleIds?.split(' ') ?? null;
|
|
981
|
+
}
|
|
982
|
+
function convertStyleIdsToString(scopedStyleIds) {
|
|
983
|
+
return Array.from(scopedStyleIds).join(' ');
|
|
984
|
+
}
|
|
985
|
+
const addComponentStylePrefix = (styleId) => {
|
|
986
|
+
if (styleId) {
|
|
987
|
+
let idx = 0;
|
|
988
|
+
do {
|
|
989
|
+
styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
|
|
990
|
+
} while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
|
|
991
|
+
}
|
|
992
|
+
return styleId || null;
|
|
993
|
+
};
|
|
994
|
+
|
|
863
995
|
/** CSS properties which accept numbers but are not in units of "px". */
|
|
864
996
|
const unitlessNumbers = new Set([
|
|
865
997
|
'animationIterationCount',
|
|
@@ -1018,36 +1150,6 @@
|
|
|
1018
1150
|
assertQrl(qStyles);
|
|
1019
1151
|
return `${hashCode(qStyles.$hash$)}-${index}`;
|
|
1020
1152
|
};
|
|
1021
|
-
const styleContent = (styleId) => {
|
|
1022
|
-
return ComponentStylesPrefixContent + styleId;
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
function hasClassAttr(props) {
|
|
1026
|
-
for (const key in props) {
|
|
1027
|
-
if (Object.prototype.hasOwnProperty.call(props, key) && isClassAttr(key)) {
|
|
1028
|
-
return true;
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
return false;
|
|
1032
|
-
}
|
|
1033
|
-
function isClassAttr(key) {
|
|
1034
|
-
return key === 'class' || key === 'className';
|
|
1035
|
-
}
|
|
1036
|
-
function convertScopedStyleIdsToArray(scopedStyleIds) {
|
|
1037
|
-
return scopedStyleIds?.split(' ') ?? null;
|
|
1038
|
-
}
|
|
1039
|
-
function convertStyleIdsToString(scopedStyleIds) {
|
|
1040
|
-
return Array.from(scopedStyleIds).join(' ');
|
|
1041
|
-
}
|
|
1042
|
-
const addComponentStylePrefix = (styleId) => {
|
|
1043
|
-
if (styleId) {
|
|
1044
|
-
let idx = 0;
|
|
1045
|
-
do {
|
|
1046
|
-
styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
|
|
1047
|
-
} while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
|
|
1048
|
-
}
|
|
1049
|
-
return styleId || null;
|
|
1050
|
-
};
|
|
1051
1153
|
|
|
1052
1154
|
const STORE_TARGET = Symbol('store.target');
|
|
1053
1155
|
const STORE_HANDLER = Symbol('store.handler');
|
|
@@ -1192,8 +1294,12 @@
|
|
|
1192
1294
|
return Reflect.ownKeys(target);
|
|
1193
1295
|
}
|
|
1194
1296
|
getOwnPropertyDescriptor(target, prop) {
|
|
1297
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
1195
1298
|
if (Array.isArray(target) || typeof prop === 'symbol') {
|
|
1196
|
-
return
|
|
1299
|
+
return descriptor;
|
|
1300
|
+
}
|
|
1301
|
+
if (descriptor && !descriptor.configurable) {
|
|
1302
|
+
return descriptor;
|
|
1197
1303
|
}
|
|
1198
1304
|
return {
|
|
1199
1305
|
enumerable: true,
|
|
@@ -1201,355 +1307,280 @@
|
|
|
1201
1307
|
};
|
|
1202
1308
|
}
|
|
1203
1309
|
}
|
|
1204
|
-
function addEffect(target, prop, store,
|
|
1205
|
-
const effectsMap = (store.$effects$ ||=
|
|
1206
|
-
|
|
1207
|
-
|
|
1310
|
+
function addEffect(target, prop, store, effectSubscription) {
|
|
1311
|
+
const effectsMap = (store.$effects$ ||= new Map());
|
|
1312
|
+
let effects = effectsMap.get(prop);
|
|
1313
|
+
if (!effects) {
|
|
1314
|
+
effects = new Set();
|
|
1315
|
+
effectsMap.set(prop, effects);
|
|
1316
|
+
}
|
|
1208
1317
|
// Let's make sure that we have a reference to this effect.
|
|
1209
1318
|
// Adding reference is essentially adding a subscription, so if the signal
|
|
1210
1319
|
// changes we know who to notify.
|
|
1211
|
-
|
|
1320
|
+
ensureContainsSubscription(effects, effectSubscription);
|
|
1212
1321
|
// But when effect is scheduled in needs to be able to know which signals
|
|
1213
1322
|
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1214
1323
|
// to this signal.
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
ensureEffectContainsSubscriber(effectSubscriber[EffectSubscriptionsProp.EFFECT], target, store.$container$);
|
|
1324
|
+
ensureContainsBackRef(effectSubscription, target);
|
|
1325
|
+
addQrlToSerializationCtx(effectSubscription, store.$container$);
|
|
1218
1326
|
}
|
|
1219
1327
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
1220
1328
|
target[prop] = value;
|
|
1221
1329
|
triggerEffects(currentStore.$container$, currentStore, getEffects(target, prop, currentStore.$effects$));
|
|
1222
1330
|
}
|
|
1223
1331
|
function getEffects(target, prop, storeEffects) {
|
|
1224
|
-
let effectsToTrigger
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1332
|
+
let effectsToTrigger;
|
|
1333
|
+
if (storeEffects) {
|
|
1334
|
+
if (Array.isArray(target)) {
|
|
1335
|
+
for (const effects of storeEffects.values()) {
|
|
1336
|
+
effectsToTrigger ||= new Set();
|
|
1337
|
+
for (const effect of effects) {
|
|
1338
|
+
effectsToTrigger.add(effect);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
effectsToTrigger = storeEffects.get(prop);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
const storeArrayValue = storeEffects?.get(STORE_ARRAY_PROP);
|
|
1230
1347
|
if (storeArrayValue) {
|
|
1231
|
-
effectsToTrigger ||=
|
|
1232
|
-
|
|
1348
|
+
effectsToTrigger ||= new Set();
|
|
1349
|
+
for (const effect of storeArrayValue) {
|
|
1350
|
+
effectsToTrigger.add(effect);
|
|
1351
|
+
}
|
|
1233
1352
|
}
|
|
1234
|
-
return effectsToTrigger;
|
|
1353
|
+
return effectsToTrigger || null;
|
|
1235
1354
|
}
|
|
1236
1355
|
|
|
1237
1356
|
/**
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1357
|
+
* Special value used to mark that a given signal needs to be computed. This is essentially a
|
|
1358
|
+
* "marked as dirty" flag.
|
|
1240
1359
|
*/
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
const host = hostElement;
|
|
1245
|
-
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
1246
|
-
if (seq === null) {
|
|
1247
|
-
seq = [];
|
|
1248
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
1249
|
-
}
|
|
1250
|
-
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
1251
|
-
if (seqIdx === null) {
|
|
1252
|
-
seqIdx = 0;
|
|
1253
|
-
}
|
|
1254
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
1255
|
-
while (seq.length <= seqIdx) {
|
|
1256
|
-
seq.push(undefined);
|
|
1257
|
-
}
|
|
1258
|
-
const set = (value) => {
|
|
1259
|
-
if (qDev && qSerialize) {
|
|
1260
|
-
verifySerializable(value);
|
|
1261
|
-
}
|
|
1262
|
-
return (seq[seqIdx] = value);
|
|
1263
|
-
};
|
|
1264
|
-
return {
|
|
1265
|
-
val: seq[seqIdx],
|
|
1266
|
-
set,
|
|
1267
|
-
i: seqIdx,
|
|
1268
|
-
iCtx,
|
|
1269
|
-
};
|
|
1270
|
-
};
|
|
1360
|
+
const NEEDS_COMPUTATION = Symbol('invalid');
|
|
1361
|
+
/** @internal */
|
|
1362
|
+
const _EFFECT_BACK_REF = Symbol('backRef');
|
|
1271
1363
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1364
|
+
/** Class for back reference to the EffectSubscription */
|
|
1365
|
+
class BackRef {
|
|
1366
|
+
[_EFFECT_BACK_REF] = null;
|
|
1274
1367
|
}
|
|
1275
|
-
function
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
function clearVNodeEffectDependencies(container, value) {
|
|
1279
|
-
if (vnode_isElementVNode(value)) {
|
|
1280
|
-
ensureMaterialized(value);
|
|
1368
|
+
function clearAllEffects(container, consumer) {
|
|
1369
|
+
if (vnode_isVNode(consumer) && vnode_isElementVNode(consumer)) {
|
|
1370
|
+
ensureMaterialized(consumer);
|
|
1281
1371
|
}
|
|
1282
|
-
const effects =
|
|
1372
|
+
const effects = consumer[_EFFECT_BACK_REF];
|
|
1283
1373
|
if (!effects) {
|
|
1284
1374
|
return;
|
|
1285
1375
|
}
|
|
1286
|
-
for (
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (effects.length === 0) {
|
|
1291
|
-
vnode_setProp(value, QSubscribers, null);
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
function clearSubscriberEffectDependencies(container, value) {
|
|
1295
|
-
if (value.$effectDependencies$) {
|
|
1296
|
-
for (let i = value.$effectDependencies$.length - 1; i >= 0; i--) {
|
|
1297
|
-
const subscriber = value.$effectDependencies$[i];
|
|
1298
|
-
clearEffects(subscriber, value, value.$effectDependencies$, i, container);
|
|
1299
|
-
}
|
|
1300
|
-
if (value.$effectDependencies$.length === 0) {
|
|
1301
|
-
value.$effectDependencies$ = null;
|
|
1376
|
+
for (const [, effect] of effects) {
|
|
1377
|
+
const backRefs = effect[EffectSubscriptionProp.BACK_REF];
|
|
1378
|
+
if (!backRefs) {
|
|
1379
|
+
return;
|
|
1302
1380
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
let subscriptionRemoved = false;
|
|
1307
|
-
const seenSet = new Set();
|
|
1308
|
-
if (subscriber instanceof WrappedSignal) {
|
|
1309
|
-
subscriptionRemoved = clearSignalEffects(subscriber, value, seenSet);
|
|
1310
|
-
}
|
|
1311
|
-
else if (container.$storeProxyMap$.has(subscriber)) {
|
|
1312
|
-
const store = container.$storeProxyMap$.get(subscriber);
|
|
1313
|
-
const handler = getStoreHandler(store);
|
|
1314
|
-
subscriptionRemoved = clearStoreEffects(handler, value);
|
|
1315
|
-
}
|
|
1316
|
-
if (subscriptionRemoved) {
|
|
1317
|
-
effectArray.splice(indexToRemove, 1);
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
function clearSignalEffects(subscriber, value, seenSet) {
|
|
1321
|
-
const effectSubscriptions = subscriber.$effects$;
|
|
1322
|
-
let subscriptionRemoved = false;
|
|
1323
|
-
if (effectSubscriptions) {
|
|
1324
|
-
for (let i = effectSubscriptions.length - 1; i >= 0; i--) {
|
|
1325
|
-
const effect = effectSubscriptions[i];
|
|
1326
|
-
if (effect[EffectSubscriptionsProp.EFFECT] === value) {
|
|
1327
|
-
effectSubscriptions.splice(i, 1);
|
|
1328
|
-
subscriptionRemoved = true;
|
|
1381
|
+
for (const producer of backRefs) {
|
|
1382
|
+
if (producer instanceof Signal) {
|
|
1383
|
+
clearSignal(container, producer, effect);
|
|
1329
1384
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
if (hostElement && hostElement === value) {
|
|
1335
|
-
subscriber.$hostElement$ = null;
|
|
1336
|
-
}
|
|
1337
|
-
// clear the effects of the arguments
|
|
1338
|
-
const args = subscriber.$args$;
|
|
1339
|
-
if (args) {
|
|
1340
|
-
clearArgsEffects(args, subscriber, seenSet);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
return subscriptionRemoved;
|
|
1344
|
-
}
|
|
1345
|
-
function clearStoreEffects(storeHandler, value) {
|
|
1346
|
-
const effectSubscriptions = storeHandler.$effects$;
|
|
1347
|
-
if (!effectSubscriptions) {
|
|
1348
|
-
return false;
|
|
1349
|
-
}
|
|
1350
|
-
let subscriptionRemoved = false;
|
|
1351
|
-
for (const key in effectSubscriptions) {
|
|
1352
|
-
const effects = effectSubscriptions[key];
|
|
1353
|
-
for (let i = effects.length - 1; i >= 0; i--) {
|
|
1354
|
-
const effect = effects[i];
|
|
1355
|
-
if (effect[EffectSubscriptionsProp.EFFECT] === value) {
|
|
1356
|
-
effects.splice(i, 1);
|
|
1357
|
-
subscriptionRemoved = true;
|
|
1385
|
+
else if (container.$storeProxyMap$.has(producer)) {
|
|
1386
|
+
const target = container.$storeProxyMap$.get(producer);
|
|
1387
|
+
const storeHandler = getStoreHandler(target);
|
|
1388
|
+
clearStore(storeHandler, effect);
|
|
1358
1389
|
}
|
|
1359
1390
|
}
|
|
1360
|
-
if (effects.length === 0) {
|
|
1361
|
-
delete effectSubscriptions[key];
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
return subscriptionRemoved;
|
|
1365
|
-
}
|
|
1366
|
-
function clearArgsEffects(args, subscriber, seenSet) {
|
|
1367
|
-
for (let i = args.length - 1; i >= 0; i--) {
|
|
1368
|
-
const arg = args[i];
|
|
1369
|
-
clearArgEffect(arg, subscriber, seenSet);
|
|
1370
1391
|
}
|
|
1371
1392
|
}
|
|
1372
|
-
function
|
|
1373
|
-
|
|
1374
|
-
|
|
1393
|
+
function clearSignal(container, producer, effect) {
|
|
1394
|
+
const effects = producer.$effects$;
|
|
1395
|
+
if (effects) {
|
|
1396
|
+
effects.delete(effect);
|
|
1375
1397
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1398
|
+
if (producer instanceof WrappedSignal) {
|
|
1399
|
+
producer.$hostElement$ = null;
|
|
1400
|
+
clearAllEffects(container, producer);
|
|
1379
1401
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
// To avoid that we need to get the constProps and varProps directly
|
|
1387
|
-
// from the props proxy object and loop over them.
|
|
1388
|
-
const constProps = arg[_CONST_PROPS];
|
|
1389
|
-
const varProps = arg[_VAR_PROPS];
|
|
1390
|
-
if (constProps) {
|
|
1391
|
-
for (const key in constProps) {
|
|
1392
|
-
clearArgEffect(constProps[key], subscriber, seenSet);
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
for (const key in varProps) {
|
|
1396
|
-
clearArgEffect(varProps[key], subscriber, seenSet);
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
else {
|
|
1400
|
-
for (const key in arg) {
|
|
1401
|
-
clearArgEffect(arg[key], subscriber, seenSet);
|
|
1402
|
-
}
|
|
1402
|
+
}
|
|
1403
|
+
function clearStore(producer, effect) {
|
|
1404
|
+
const effects = producer?.$effects$;
|
|
1405
|
+
if (effects) {
|
|
1406
|
+
for (const propEffects of effects.values()) {
|
|
1407
|
+
propEffects.delete(effect);
|
|
1403
1408
|
}
|
|
1404
1409
|
}
|
|
1405
|
-
else if (Array.isArray(arg)) {
|
|
1406
|
-
clearArgsEffects(arg, subscriber, seenSet);
|
|
1407
|
-
}
|
|
1408
|
-
else ;
|
|
1409
1410
|
}
|
|
1410
1411
|
|
|
1411
|
-
|
|
1412
|
-
const useResourceQrl = (qrl, opts) => {
|
|
1413
|
-
const { val, set, i, iCtx } = useSequentialScope();
|
|
1414
|
-
if (val != null) {
|
|
1415
|
-
return val;
|
|
1416
|
-
}
|
|
1417
|
-
assertQrl(qrl);
|
|
1418
|
-
const container = iCtx.$container$;
|
|
1419
|
-
const resource = createResourceReturn(container, opts);
|
|
1420
|
-
const el = iCtx.$hostElement$;
|
|
1421
|
-
const task = new Task(TaskFlags.DIRTY | TaskFlags.RESOURCE, i, el, qrl, resource, null);
|
|
1422
|
-
runResource(task, container, iCtx.$hostElement$);
|
|
1423
|
-
set(resource);
|
|
1424
|
-
return resource;
|
|
1425
|
-
};
|
|
1426
|
-
// <docs markdown="../readme.md#useResource">
|
|
1412
|
+
// <docs markdown="../../readme.md#implicit$FirstArg">
|
|
1427
1413
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
1428
|
-
// (edit
|
|
1414
|
+
// (edit ../../readme.md#implicit$FirstArg instead and run `pnpm docs.sync`)
|
|
1429
1415
|
/**
|
|
1430
|
-
*
|
|
1431
|
-
* and returns some data.
|
|
1416
|
+
* Create a `____$(...)` convenience method from `___(...)`.
|
|
1432
1417
|
*
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1418
|
+
* It is very common for functions to take a lazy-loadable resource as a first argument. For this
|
|
1419
|
+
* reason, the Qwik Optimizer automatically extracts the first argument from any function which ends
|
|
1420
|
+
* in `$`.
|
|
1435
1421
|
*
|
|
1436
|
-
*
|
|
1422
|
+
* This means that `foo$(arg0)` and `foo($(arg0))` are equivalent with respect to Qwik Optimizer.
|
|
1423
|
+
* The former is just a shorthand for the latter.
|
|
1437
1424
|
*
|
|
1438
|
-
*
|
|
1439
|
-
* - `resolved` - the data is available.
|
|
1440
|
-
* - `rejected` - the data is not available due to an error or timeout.
|
|
1425
|
+
* For example, these function calls are equivalent:
|
|
1441
1426
|
*
|
|
1442
|
-
*
|
|
1443
|
-
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
1427
|
+
* - `component$(() => {...})` is same as `component($(() => {...}))`
|
|
1444
1428
|
*
|
|
1445
|
-
*
|
|
1429
|
+
* ```tsx
|
|
1430
|
+
* export function myApi(callback: QRL<() => void>): void {
|
|
1431
|
+
* // ...
|
|
1432
|
+
* }
|
|
1446
1433
|
*
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
1434
|
+
* export const myApi$ = implicit$FirstArg(myApi);
|
|
1435
|
+
* // type of myApi$: (callback: () => void): void
|
|
1449
1436
|
*
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1452
|
-
* const cityS = useSignal('');
|
|
1437
|
+
* // can be used as:
|
|
1438
|
+
* myApi$(() => console.log('callback'));
|
|
1453
1439
|
*
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1456
|
-
*
|
|
1457
|
-
* cleanup(() => abortController.abort('cleanup'));
|
|
1458
|
-
* const res = await fetch(`http://weatherdata.com?city=${cityName}`, {
|
|
1459
|
-
* signal: abortController.signal,
|
|
1460
|
-
* });
|
|
1461
|
-
* const data = await res.json();
|
|
1462
|
-
* return data as { temp: number };
|
|
1463
|
-
* });
|
|
1440
|
+
* // will be transpiled to:
|
|
1441
|
+
* // FILE: <current file>
|
|
1442
|
+
* myApi(qrl('./chunk-abc.js', 'callback'));
|
|
1464
1443
|
*
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
* <input name="city" bind:value={cityS} />
|
|
1468
|
-
* <Resource
|
|
1469
|
-
* value={weatherResource}
|
|
1470
|
-
* onResolved={(weather) => {
|
|
1471
|
-
* return <div>Temperature: {weather.temp}</div>;
|
|
1472
|
-
* }}
|
|
1473
|
-
* />
|
|
1474
|
-
* </div>
|
|
1475
|
-
* );
|
|
1476
|
-
* });
|
|
1444
|
+
* // FILE: chunk-abc.js
|
|
1445
|
+
* export const callback = () => console.log('callback');
|
|
1477
1446
|
* ```
|
|
1478
1447
|
*
|
|
1448
|
+
* @param fn - A function that should have its first argument automatically `$`.
|
|
1479
1449
|
* @public
|
|
1480
|
-
* @see Resource
|
|
1481
|
-
* @see ResourceReturn
|
|
1482
1450
|
*/
|
|
1483
1451
|
// </docs>
|
|
1484
|
-
const
|
|
1485
|
-
|
|
1486
|
-
|
|
1452
|
+
const implicit$FirstArg = (fn) => {
|
|
1453
|
+
return function (first, ...rest) {
|
|
1454
|
+
return fn.call(null, dollar(first), ...rest);
|
|
1455
|
+
};
|
|
1487
1456
|
};
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1457
|
+
|
|
1458
|
+
const createSignal$1 = (value) => {
|
|
1459
|
+
return new Signal(null, value);
|
|
1460
|
+
};
|
|
1461
|
+
const createComputedSignal = (qrl) => {
|
|
1462
|
+
throwIfQRLNotResolved(qrl);
|
|
1463
|
+
return new ComputedSignal(null, qrl);
|
|
1464
|
+
};
|
|
1465
|
+
|
|
1466
|
+
/**
|
|
1467
|
+
* Creates a Signal with the given value. If no value is given, the signal is created with
|
|
1468
|
+
* `undefined`.
|
|
1469
|
+
*
|
|
1470
|
+
* @public
|
|
1471
|
+
*/
|
|
1472
|
+
const createSignal = createSignal$1;
|
|
1473
|
+
/** @internal */
|
|
1474
|
+
const createComputedQrl = createComputedSignal;
|
|
1475
|
+
/**
|
|
1476
|
+
* Create a computed signal which is calculated from the given QRL. A computed signal is a signal
|
|
1477
|
+
* which is calculated from other signals. When the signals change, the computed signal is
|
|
1478
|
+
* recalculated.
|
|
1479
|
+
*
|
|
1480
|
+
* The QRL must be a function which returns the value of the signal. The function must not have side
|
|
1481
|
+
* effects, and it mus be synchronous.
|
|
1482
|
+
*
|
|
1483
|
+
* If you need the function to be async, use `useSignal` and `useTask$` instead.
|
|
1484
|
+
*
|
|
1485
|
+
* @public
|
|
1486
|
+
*/
|
|
1487
|
+
const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedQrl);
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* @internal
|
|
1491
|
+
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
1492
|
+
*/
|
|
1493
|
+
const useSequentialScope = () => {
|
|
1494
|
+
const iCtx = useInvokeContext();
|
|
1495
|
+
const hostElement = iCtx.$hostElement$;
|
|
1496
|
+
const host = hostElement;
|
|
1497
|
+
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
1498
|
+
if (seq === null) {
|
|
1499
|
+
seq = [];
|
|
1500
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
1513
1501
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1502
|
+
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
1503
|
+
if (seqIdx === null) {
|
|
1504
|
+
seqIdx = 0;
|
|
1516
1505
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1506
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
1507
|
+
while (seq.length <= seqIdx) {
|
|
1508
|
+
seq.push(undefined);
|
|
1519
1509
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
value
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1510
|
+
const set = (value) => {
|
|
1511
|
+
if (qDev && qSerialize) {
|
|
1512
|
+
verifySerializable(value);
|
|
1513
|
+
}
|
|
1514
|
+
return (seq[seqIdx] = value);
|
|
1515
|
+
};
|
|
1516
|
+
return {
|
|
1517
|
+
val: seq[seqIdx],
|
|
1518
|
+
set,
|
|
1519
|
+
i: seqIdx,
|
|
1520
|
+
iCtx,
|
|
1531
1521
|
};
|
|
1532
|
-
return resource;
|
|
1533
|
-
};
|
|
1534
|
-
const createResourceReturn = (container, opts, initialPromise) => {
|
|
1535
|
-
const result = _createResourceReturn(opts);
|
|
1536
|
-
result.value = initialPromise;
|
|
1537
|
-
return createStore(container, result, StoreFlags.RECURSIVE);
|
|
1538
1522
|
};
|
|
1539
|
-
|
|
1540
|
-
|
|
1523
|
+
|
|
1524
|
+
function getSubscriber(effect, prop, data) {
|
|
1525
|
+
if (!effect[_EFFECT_BACK_REF]) {
|
|
1526
|
+
if (build.isServer && isSsrNode(effect)) {
|
|
1527
|
+
effect.setProp(QBackRefs, new Map());
|
|
1528
|
+
}
|
|
1529
|
+
else {
|
|
1530
|
+
effect[_EFFECT_BACK_REF] = new Map();
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const subMap = effect[_EFFECT_BACK_REF];
|
|
1534
|
+
let sub = subMap.get(prop);
|
|
1535
|
+
if (!sub) {
|
|
1536
|
+
sub = [effect, prop];
|
|
1537
|
+
subMap.set(prop, sub);
|
|
1538
|
+
}
|
|
1539
|
+
if (data) {
|
|
1540
|
+
sub[EffectSubscriptionProp.DATA] = data;
|
|
1541
|
+
}
|
|
1542
|
+
return sub;
|
|
1543
|
+
}
|
|
1544
|
+
function isSsrNode(value) {
|
|
1545
|
+
return '__brand__' in value && 'currentComponentNode' in value;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
var TaskFlags;
|
|
1549
|
+
(function (TaskFlags) {
|
|
1550
|
+
TaskFlags[TaskFlags["VISIBLE_TASK"] = 1] = "VISIBLE_TASK";
|
|
1551
|
+
TaskFlags[TaskFlags["TASK"] = 2] = "TASK";
|
|
1552
|
+
TaskFlags[TaskFlags["RESOURCE"] = 4] = "RESOURCE";
|
|
1553
|
+
TaskFlags[TaskFlags["DIRTY"] = 8] = "DIRTY";
|
|
1554
|
+
})(TaskFlags || (TaskFlags = {}));
|
|
1555
|
+
/** @internal */
|
|
1556
|
+
const useTaskQrl = (qrl) => {
|
|
1557
|
+
const { val, set, iCtx, i } = useSequentialScope();
|
|
1558
|
+
if (val) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
assertQrl(qrl);
|
|
1562
|
+
set(1);
|
|
1563
|
+
const task = new Task(TaskFlags.DIRTY | TaskFlags.TASK, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
1564
|
+
// In V2 we add the task to the sequential scope. We need to do this
|
|
1565
|
+
// in order to be able to retrieve it later when the parent element is
|
|
1566
|
+
// deleted and we need to be able to release the task subscriptions.
|
|
1567
|
+
set(task);
|
|
1568
|
+
const container = iCtx.$container$;
|
|
1569
|
+
const promise = container.$scheduler$(ChoreType.TASK, task);
|
|
1570
|
+
if (isPromise(promise)) {
|
|
1571
|
+
// TODO: should we handle this differently?
|
|
1572
|
+
promise.catch(() => { });
|
|
1573
|
+
}
|
|
1541
1574
|
};
|
|
1542
|
-
const
|
|
1575
|
+
const runTask = (task, container, host) => {
|
|
1543
1576
|
task.$flags$ &= ~TaskFlags.DIRTY;
|
|
1544
1577
|
cleanupTask(task);
|
|
1545
|
-
const iCtx = newInvokeContext(container.$locale$, host, undefined,
|
|
1578
|
+
const iCtx = newInvokeContext(container.$locale$, host, undefined, TaskEvent);
|
|
1546
1579
|
iCtx.$container$ = container;
|
|
1547
|
-
const taskFn = task.$qrl$.getFn(iCtx, () =>
|
|
1548
|
-
const resource = task.$state$;
|
|
1549
|
-
assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
|
|
1580
|
+
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
1550
1581
|
const track = (obj, prop) => {
|
|
1551
1582
|
const ctx = newInvokeContext();
|
|
1552
|
-
ctx.$effectSubscriber$ =
|
|
1583
|
+
ctx.$effectSubscriber$ = getSubscriber(task, EffectProperty.COMPONENT);
|
|
1553
1584
|
ctx.$container$ = container;
|
|
1554
1585
|
return invoke(ctx, () => {
|
|
1555
1586
|
if (isFunction(obj)) {
|
|
@@ -1562,115 +1593,85 @@
|
|
|
1562
1593
|
return obj.value;
|
|
1563
1594
|
}
|
|
1564
1595
|
else {
|
|
1565
|
-
|
|
1596
|
+
throw qError(QError.trackObjectWithoutProp);
|
|
1566
1597
|
}
|
|
1567
1598
|
});
|
|
1568
1599
|
};
|
|
1569
1600
|
const handleError = (reason) => container.handleError(reason, host);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1601
|
+
let cleanupFns = null;
|
|
1602
|
+
const cleanup = (fn) => {
|
|
1603
|
+
if (typeof fn == 'function') {
|
|
1604
|
+
if (!cleanupFns) {
|
|
1605
|
+
cleanupFns = [];
|
|
1606
|
+
task.$destroy$ = noSerialize(() => {
|
|
1607
|
+
task.$destroy$ = null;
|
|
1608
|
+
cleanupFns.forEach((fn) => {
|
|
1609
|
+
try {
|
|
1610
|
+
fn();
|
|
1611
|
+
}
|
|
1612
|
+
catch (err) {
|
|
1613
|
+
handleError(err);
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
});
|
|
1578
1617
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1618
|
+
cleanupFns.push(fn);
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
const taskApi = { track, cleanup };
|
|
1622
|
+
const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
1623
|
+
// If a Promise is thrown, that means we need to re-run the task.
|
|
1624
|
+
if (isPromise(err)) {
|
|
1625
|
+
return err.then(() => runTask(task, container, host));
|
|
1626
|
+
}
|
|
1627
|
+
else {
|
|
1628
|
+
throw err;
|
|
1629
|
+
}
|
|
1581
1630
|
});
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
cache(policy) {
|
|
1591
|
-
let milliseconds = 0;
|
|
1592
|
-
if (policy === 'immutable') {
|
|
1593
|
-
milliseconds = Infinity;
|
|
1594
|
-
}
|
|
1595
|
-
else {
|
|
1596
|
-
milliseconds = policy;
|
|
1597
|
-
}
|
|
1598
|
-
resource._cache = milliseconds;
|
|
1599
|
-
},
|
|
1600
|
-
previous: resourceTarget._resolved,
|
|
1601
|
-
};
|
|
1602
|
-
let resolve;
|
|
1603
|
-
let reject;
|
|
1604
|
-
let done = false;
|
|
1605
|
-
const setState = (resolved, value) => {
|
|
1606
|
-
if (!done) {
|
|
1607
|
-
done = true;
|
|
1608
|
-
if (resolved) {
|
|
1609
|
-
done = true;
|
|
1610
|
-
resource.loading = false;
|
|
1611
|
-
resource._state = 'resolved';
|
|
1612
|
-
resource._resolved = value;
|
|
1613
|
-
resource._error = undefined;
|
|
1614
|
-
resolve(value);
|
|
1615
|
-
}
|
|
1616
|
-
else {
|
|
1617
|
-
done = true;
|
|
1618
|
-
resource.loading = false;
|
|
1619
|
-
resource._state = 'rejected';
|
|
1620
|
-
resource._error = value;
|
|
1621
|
-
reject(value);
|
|
1622
|
-
}
|
|
1623
|
-
return true;
|
|
1624
|
-
}
|
|
1625
|
-
return false;
|
|
1626
|
-
};
|
|
1627
|
-
/**
|
|
1628
|
-
* Add cleanup to resolve the resource if we are trying to run the same resource again while the
|
|
1629
|
-
* previous one is not resolved yet. The next `runResource` run will call this cleanup
|
|
1630
|
-
*/
|
|
1631
|
-
cleanups.push(() => {
|
|
1632
|
-
if (untrack(() => resource.loading) === true) {
|
|
1633
|
-
const value = untrack(() => resource._resolved);
|
|
1634
|
-
setState(true, value);
|
|
1635
|
-
}
|
|
1636
|
-
});
|
|
1637
|
-
// Execute mutation inside empty invocation
|
|
1638
|
-
invoke(iCtx, () => {
|
|
1639
|
-
// console.log('RESOURCE.pending: ');
|
|
1640
|
-
resource._state = 'pending';
|
|
1641
|
-
resource.loading = !isServerPlatform();
|
|
1642
|
-
const promise = (resource.value = new Promise((r, re) => {
|
|
1643
|
-
resolve = r;
|
|
1644
|
-
reject = re;
|
|
1645
|
-
}));
|
|
1646
|
-
promise.catch(ignoreErrorToPreventNodeFromCrashing);
|
|
1647
|
-
});
|
|
1648
|
-
const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
|
|
1649
|
-
setState(true, value);
|
|
1650
|
-
}, (err) => {
|
|
1651
|
-
if (isPromise(err)) {
|
|
1652
|
-
return err.then(() => runResource(task, container, host));
|
|
1631
|
+
return result;
|
|
1632
|
+
};
|
|
1633
|
+
const cleanupTask = (task) => {
|
|
1634
|
+
const destroy = task.$destroy$;
|
|
1635
|
+
if (destroy) {
|
|
1636
|
+
task.$destroy$ = null;
|
|
1637
|
+
try {
|
|
1638
|
+
destroy();
|
|
1653
1639
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1640
|
+
catch (err) {
|
|
1641
|
+
logError(err);
|
|
1656
1642
|
}
|
|
1657
|
-
});
|
|
1658
|
-
const timeout = resourceTarget._timeout;
|
|
1659
|
-
if (timeout > 0) {
|
|
1660
|
-
return Promise.race([
|
|
1661
|
-
promise,
|
|
1662
|
-
delay(timeout).then(() => {
|
|
1663
|
-
if (setState(false, new Error('timeout'))) {
|
|
1664
|
-
cleanupTask(task);
|
|
1665
|
-
}
|
|
1666
|
-
}),
|
|
1667
|
-
]);
|
|
1668
1643
|
}
|
|
1669
|
-
return promise;
|
|
1670
1644
|
};
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1645
|
+
class Task extends BackRef {
|
|
1646
|
+
$flags$;
|
|
1647
|
+
$index$;
|
|
1648
|
+
$el$;
|
|
1649
|
+
$qrl$;
|
|
1650
|
+
$state$;
|
|
1651
|
+
$destroy$;
|
|
1652
|
+
constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
|
|
1653
|
+
super();
|
|
1654
|
+
this.$flags$ = $flags$;
|
|
1655
|
+
this.$index$ = $index$;
|
|
1656
|
+
this.$el$ = $el$;
|
|
1657
|
+
this.$qrl$ = $qrl$;
|
|
1658
|
+
this.$state$ = $state$;
|
|
1659
|
+
this.$destroy$ = $destroy$;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
const isTask = (value) => {
|
|
1663
|
+
return value instanceof Task;
|
|
1664
|
+
};
|
|
1665
|
+
/**
|
|
1666
|
+
* Used internally as a qrl event handler to schedule a task.
|
|
1667
|
+
*
|
|
1668
|
+
* @internal
|
|
1669
|
+
*/
|
|
1670
|
+
const scheduleTask = (_event, element) => {
|
|
1671
|
+
const [task] = useLexicalScope();
|
|
1672
|
+
const type = task.$flags$ & TaskFlags.VISIBLE_TASK ? ChoreType.VISIBLE : ChoreType.TASK;
|
|
1673
|
+
const container = getDomContainer(element);
|
|
1674
|
+
container.$scheduler$(type, task);
|
|
1674
1675
|
};
|
|
1675
1676
|
|
|
1676
1677
|
/** @file Public types for the client deserialization */
|
|
@@ -1748,22 +1749,67 @@
|
|
|
1748
1749
|
VirtualVNodeProps[VirtualVNodeProps["PROPS_OFFSET"] = 6] = "PROPS_OFFSET";
|
|
1749
1750
|
})(VirtualVNodeProps || (VirtualVNodeProps = {}));
|
|
1750
1751
|
|
|
1751
|
-
const
|
|
1752
|
+
const mapApp_findIndx = (elementVNode, key, start) => {
|
|
1753
|
+
assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
1754
|
+
let bottom = start >> 1;
|
|
1755
|
+
let top = (elementVNode.length - 2) >> 1;
|
|
1756
|
+
while (bottom <= top) {
|
|
1757
|
+
const mid = bottom + ((top - bottom) >> 1);
|
|
1758
|
+
const midKey = elementVNode[mid << 1];
|
|
1759
|
+
if (midKey === key) {
|
|
1760
|
+
return mid << 1;
|
|
1761
|
+
}
|
|
1762
|
+
if (midKey < key) {
|
|
1763
|
+
bottom = mid + 1;
|
|
1764
|
+
}
|
|
1765
|
+
else {
|
|
1766
|
+
top = mid - 1;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return (bottom << 1) ^ -1;
|
|
1770
|
+
};
|
|
1771
|
+
const mapArray_set = (elementVNode, key, value, start) => {
|
|
1772
|
+
const indx = mapApp_findIndx(elementVNode, key, start);
|
|
1773
|
+
if (indx >= 0) {
|
|
1774
|
+
if (value == null) {
|
|
1775
|
+
elementVNode.splice(indx, 2);
|
|
1776
|
+
}
|
|
1777
|
+
else {
|
|
1778
|
+
elementVNode[indx + 1] = value;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
else if (value != null) {
|
|
1782
|
+
elementVNode.splice(indx ^ -1, 0, key, value);
|
|
1783
|
+
}
|
|
1784
|
+
};
|
|
1785
|
+
const mapArray_get = (elementVNode, key, start) => {
|
|
1786
|
+
const indx = mapApp_findIndx(elementVNode, key, start);
|
|
1787
|
+
if (indx >= 0) {
|
|
1788
|
+
return elementVNode[indx + 1];
|
|
1789
|
+
}
|
|
1790
|
+
else {
|
|
1791
|
+
return null;
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
|
|
1795
|
+
const isForeignObjectElement = (elementName) => {
|
|
1796
|
+
return build.isDev ? elementName.toLowerCase() === 'foreignobject' : elementName === 'foreignObject';
|
|
1797
|
+
};
|
|
1752
1798
|
const isSvgElement = (elementName) => elementName === 'svg' || isForeignObjectElement(elementName);
|
|
1753
1799
|
const isMathElement = (elementName) => elementName === 'math';
|
|
1754
1800
|
const vnode_isDefaultNamespace = (vnode) => {
|
|
1755
1801
|
const flags = vnode[VNodeProps.flags];
|
|
1756
1802
|
return (flags & VNodeFlags.NAMESPACE_MASK) === 0;
|
|
1757
1803
|
};
|
|
1758
|
-
const vnode_getElementNamespaceFlags = (
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1804
|
+
const vnode_getElementNamespaceFlags = (element) => {
|
|
1805
|
+
const namespace = fastNamespaceURI(element);
|
|
1806
|
+
switch (namespace) {
|
|
1807
|
+
case SVG_NS:
|
|
1808
|
+
return VNodeFlags.NS_svg;
|
|
1809
|
+
case MATH_NS:
|
|
1810
|
+
return VNodeFlags.NS_math;
|
|
1811
|
+
default:
|
|
1812
|
+
return VNodeFlags.NS_html;
|
|
1767
1813
|
}
|
|
1768
1814
|
};
|
|
1769
1815
|
function vnode_getDomChildrenWithCorrectNamespacesToInsert(journal, domParentVNode, newChild) {
|
|
@@ -2117,19 +2163,21 @@
|
|
|
2117
2163
|
* @returns
|
|
2118
2164
|
*/
|
|
2119
2165
|
const executeComponent = (container, renderHost, subscriptionHost, componentQRL, props) => {
|
|
2120
|
-
const iCtx = newInvokeContext(container.$locale$, subscriptionHost, undefined, RenderEvent);
|
|
2121
|
-
|
|
2122
|
-
|
|
2166
|
+
const iCtx = newInvokeContext(container.$locale$, subscriptionHost || undefined, undefined, RenderEvent);
|
|
2167
|
+
if (subscriptionHost) {
|
|
2168
|
+
iCtx.$effectSubscriber$ = getSubscriber(subscriptionHost, EffectProperty.COMPONENT);
|
|
2169
|
+
iCtx.$container$ = container;
|
|
2170
|
+
}
|
|
2123
2171
|
let componentFn;
|
|
2124
2172
|
container.ensureProjectionResolved(renderHost);
|
|
2125
2173
|
let isInlineComponent = false;
|
|
2126
2174
|
if (componentQRL === null) {
|
|
2127
|
-
componentQRL =
|
|
2175
|
+
componentQRL = container.getHostProp(renderHost, OnRenderProp);
|
|
2128
2176
|
assertDefined(componentQRL, 'No Component found at this location');
|
|
2129
2177
|
}
|
|
2130
|
-
if (isQrl(componentQRL)) {
|
|
2178
|
+
if (isQrl$1(componentQRL)) {
|
|
2131
2179
|
props = props || container.getHostProp(renderHost, ELEMENT_PROPS) || EMPTY_OBJ;
|
|
2132
|
-
if (props
|
|
2180
|
+
if (props.children) {
|
|
2133
2181
|
delete props.children;
|
|
2134
2182
|
}
|
|
2135
2183
|
componentFn = componentQRL.getFn(iCtx);
|
|
@@ -2147,18 +2195,16 @@
|
|
|
2147
2195
|
if (!isInlineComponent) {
|
|
2148
2196
|
container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
|
|
2149
2197
|
container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
|
|
2150
|
-
|
|
2151
|
-
container.setHostProp(renderHost, ELEMENT_PROPS, props);
|
|
2152
|
-
}
|
|
2198
|
+
container.setHostProp(renderHost, ELEMENT_PROPS, props);
|
|
2153
2199
|
}
|
|
2154
2200
|
if (vnode_isVNode(renderHost)) {
|
|
2155
|
-
|
|
2201
|
+
clearAllEffects(container, renderHost);
|
|
2156
2202
|
}
|
|
2157
2203
|
return componentFn(props);
|
|
2158
2204
|
}, (jsx) => {
|
|
2159
2205
|
const useOnEvents = container.getHostProp(renderHost, USE_ON_LOCAL);
|
|
2160
2206
|
if (useOnEvents) {
|
|
2161
|
-
return
|
|
2207
|
+
return addUseOnEvents(jsx, useOnEvents);
|
|
2162
2208
|
}
|
|
2163
2209
|
return jsx;
|
|
2164
2210
|
}, (err) => {
|
|
@@ -2184,6 +2230,7 @@
|
|
|
2184
2230
|
*/
|
|
2185
2231
|
function addUseOnEvents(jsx, useOnEvents) {
|
|
2186
2232
|
const jsxElement = findFirstStringJSX(jsx);
|
|
2233
|
+
let jsxResult = jsx;
|
|
2187
2234
|
return maybeThen(jsxElement, (jsxElement) => {
|
|
2188
2235
|
let isInvisibleComponent = false;
|
|
2189
2236
|
if (!jsxElement) {
|
|
@@ -2202,13 +2249,15 @@
|
|
|
2202
2249
|
if (Object.prototype.hasOwnProperty.call(useOnEvents, key)) {
|
|
2203
2250
|
if (isInvisibleComponent) {
|
|
2204
2251
|
if (key === 'onQvisible$') {
|
|
2205
|
-
jsxElement = addScriptNodeForInvisibleComponents(
|
|
2252
|
+
const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
|
|
2253
|
+
jsxResult = jsx;
|
|
2206
2254
|
if (jsxElement) {
|
|
2207
2255
|
addUseOnEvent(jsxElement, 'document:onQinit$', useOnEvents[key]);
|
|
2208
2256
|
}
|
|
2209
2257
|
}
|
|
2210
2258
|
else if (key.startsWith('document:') || key.startsWith('window:')) {
|
|
2211
|
-
jsxElement = addScriptNodeForInvisibleComponents(
|
|
2259
|
+
const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
|
|
2260
|
+
jsxResult = jsx;
|
|
2212
2261
|
if (jsxElement) {
|
|
2213
2262
|
addUseOnEvent(jsxElement, key, useOnEvents[key]);
|
|
2214
2263
|
}
|
|
@@ -2226,7 +2275,7 @@
|
|
|
2226
2275
|
}
|
|
2227
2276
|
}
|
|
2228
2277
|
}
|
|
2229
|
-
return
|
|
2278
|
+
return jsxResult;
|
|
2230
2279
|
});
|
|
2231
2280
|
}
|
|
2232
2281
|
function addUseOnEvent(jsxElement, key, value) {
|
|
@@ -2272,6 +2321,9 @@
|
|
|
2272
2321
|
type: 'placeholder',
|
|
2273
2322
|
hidden: '',
|
|
2274
2323
|
}, null, 3);
|
|
2324
|
+
if (jsx.type === Slot) {
|
|
2325
|
+
return [jsxElement, _jsxSorted(Fragment, null, null, [jsx, jsxElement], 0, null)];
|
|
2326
|
+
}
|
|
2275
2327
|
if (jsx.children == null) {
|
|
2276
2328
|
jsx.children = jsxElement;
|
|
2277
2329
|
}
|
|
@@ -2281,15 +2333,23 @@
|
|
|
2281
2333
|
else {
|
|
2282
2334
|
jsx.children = [jsx.children, jsxElement];
|
|
2283
2335
|
}
|
|
2284
|
-
return jsxElement;
|
|
2336
|
+
return [jsxElement, jsx];
|
|
2285
2337
|
}
|
|
2286
2338
|
else if (Array.isArray(jsx) && jsx.length) {
|
|
2287
2339
|
// get first element
|
|
2288
|
-
|
|
2340
|
+
const [jsxElement, _] = addScriptNodeForInvisibleComponents(jsx[0]);
|
|
2341
|
+
return [jsxElement, jsx];
|
|
2289
2342
|
}
|
|
2290
|
-
return null;
|
|
2343
|
+
return [null, null];
|
|
2291
2344
|
}
|
|
2292
2345
|
|
|
2346
|
+
/** @internal */
|
|
2347
|
+
const _CONST_PROPS = Symbol('CONST');
|
|
2348
|
+
/** @internal */
|
|
2349
|
+
const _VAR_PROPS = Symbol('VAR');
|
|
2350
|
+
/** @internal @deprecated v1 compat */
|
|
2351
|
+
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
2352
|
+
|
|
2293
2353
|
function isSlotProp(prop) {
|
|
2294
2354
|
return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
|
|
2295
2355
|
}
|
|
@@ -2298,12 +2358,24 @@
|
|
|
2298
2358
|
}
|
|
2299
2359
|
/** @internal */
|
|
2300
2360
|
const _restProps = (props, omit, target = {}) => {
|
|
2301
|
-
|
|
2361
|
+
let constPropsTarget = null;
|
|
2362
|
+
const constProps = props[_CONST_PROPS];
|
|
2363
|
+
if (constProps) {
|
|
2364
|
+
for (const key in constProps) {
|
|
2365
|
+
if (!omit.includes(key)) {
|
|
2366
|
+
constPropsTarget ||= {};
|
|
2367
|
+
constPropsTarget[key] = constProps[key];
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
const varPropsTarget = target;
|
|
2372
|
+
const varProps = props[_VAR_PROPS];
|
|
2373
|
+
for (const key in varProps) {
|
|
2302
2374
|
if (!omit.includes(key)) {
|
|
2303
|
-
|
|
2375
|
+
varPropsTarget[key] = varProps[key];
|
|
2304
2376
|
}
|
|
2305
2377
|
}
|
|
2306
|
-
return
|
|
2378
|
+
return createPropsProxy(varPropsTarget, constPropsTarget);
|
|
2307
2379
|
};
|
|
2308
2380
|
|
|
2309
2381
|
function escapeHTML(html) {
|
|
@@ -2345,17 +2417,6 @@
|
|
|
2345
2417
|
}
|
|
2346
2418
|
}
|
|
2347
2419
|
|
|
2348
|
-
function getFileLocationFromJsx(jsxDev) {
|
|
2349
|
-
if (!jsxDev) {
|
|
2350
|
-
return null;
|
|
2351
|
-
}
|
|
2352
|
-
const sanitizedFileName = jsxDev.fileName?.replace(/\\/g, '/');
|
|
2353
|
-
if (sanitizedFileName) {
|
|
2354
|
-
return `${sanitizedFileName}:${jsxDev.lineNumber}:${jsxDev.columnNumber}`;
|
|
2355
|
-
}
|
|
2356
|
-
return null;
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
2420
|
const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
2360
2421
|
let journal = container.$journal$;
|
|
2361
2422
|
/**
|
|
@@ -2374,9 +2435,9 @@
|
|
|
2374
2435
|
/// (Node can be null, if we are at the end of the list.)
|
|
2375
2436
|
let vCurrent = null;
|
|
2376
2437
|
/// When we insert new node we start it here so that we can descend into it.
|
|
2377
|
-
/// NOTE: it can't be stored in `vCurrent` because `
|
|
2438
|
+
/// NOTE: it can't be stored in `vCurrent` because `vNewNode` is in journal
|
|
2378
2439
|
/// and is not connected to the tree.
|
|
2379
|
-
let vNewNode = null;
|
|
2440
|
+
let vNewNode = null;
|
|
2380
2441
|
/// When elements have keys they can be consumed out of order and therefore we can't use nextSibling.
|
|
2381
2442
|
/// In such a case this array will contain the elements after the current location.
|
|
2382
2443
|
/// The array even indices will contains keys and odd indices the vNode.
|
|
@@ -2429,7 +2490,7 @@
|
|
|
2429
2490
|
}
|
|
2430
2491
|
else if (isSignal(jsxValue)) {
|
|
2431
2492
|
if (vCurrent) {
|
|
2432
|
-
|
|
2493
|
+
clearAllEffects(container, vCurrent);
|
|
2433
2494
|
}
|
|
2434
2495
|
expectVirtual(VirtualType.WrappedSignal, null);
|
|
2435
2496
|
descend(trackSignalAndAssignHost(jsxValue, (vNewNode || vCurrent), EffectProperty.VNODE, container), true);
|
|
@@ -2644,9 +2705,10 @@
|
|
|
2644
2705
|
};
|
|
2645
2706
|
const projections = [];
|
|
2646
2707
|
if (host) {
|
|
2708
|
+
const props = vnode_getProps(host);
|
|
2647
2709
|
// we need to create empty projections for all the slots to remove unused slots content
|
|
2648
|
-
for (let i =
|
|
2649
|
-
const prop =
|
|
2710
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
2711
|
+
const prop = props[i];
|
|
2650
2712
|
if (isSlotProp(prop)) {
|
|
2651
2713
|
const slotName = prop;
|
|
2652
2714
|
projections.push(slotName);
|
|
@@ -2814,10 +2876,19 @@
|
|
|
2814
2876
|
// But we need to mark them so that they don't get pulled into the diff.
|
|
2815
2877
|
const eventName = getEventNameFromJsxProp(key);
|
|
2816
2878
|
const scope = getEventNameScopeFromJsxProp(key);
|
|
2817
|
-
vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
|
|
2818
2879
|
if (eventName) {
|
|
2880
|
+
vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
|
|
2819
2881
|
registerQwikLoaderEvent(eventName);
|
|
2820
2882
|
}
|
|
2883
|
+
if (scope) {
|
|
2884
|
+
// add an event attr with empty value for qwikloader element selector.
|
|
2885
|
+
// We don't need value here. For ssr this value is a QRL,
|
|
2886
|
+
// but for CSR value should be just empty
|
|
2887
|
+
const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
|
|
2888
|
+
if (htmlEvent) {
|
|
2889
|
+
vnode_setAttr(journal, vNewNode, htmlEvent, '');
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2821
2892
|
needsQDispatchEventPatch = true;
|
|
2822
2893
|
continue;
|
|
2823
2894
|
}
|
|
@@ -2830,12 +2901,15 @@
|
|
|
2830
2901
|
value(element);
|
|
2831
2902
|
continue;
|
|
2832
2903
|
}
|
|
2904
|
+
else if (value == null) {
|
|
2905
|
+
continue;
|
|
2906
|
+
}
|
|
2833
2907
|
else {
|
|
2834
2908
|
throw qError(QError.invalidRefValue, [currentFile]);
|
|
2835
2909
|
}
|
|
2836
2910
|
}
|
|
2837
2911
|
if (isSignal(value)) {
|
|
2838
|
-
const signalData = new
|
|
2912
|
+
const signalData = new SubscriptionData({
|
|
2839
2913
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
2840
2914
|
$isConst$: true,
|
|
2841
2915
|
});
|
|
@@ -2939,7 +3013,7 @@
|
|
|
2939
3013
|
let returnValue = false;
|
|
2940
3014
|
qrls.flat(2).forEach((qrl) => {
|
|
2941
3015
|
if (qrl) {
|
|
2942
|
-
const value = qrl
|
|
3016
|
+
const value = container.$scheduler$(ChoreType.RUN_QRL, vNode, qrl, [event, element]);
|
|
2943
3017
|
returnValue = returnValue || value === true;
|
|
2944
3018
|
}
|
|
2945
3019
|
});
|
|
@@ -2951,10 +3025,10 @@
|
|
|
2951
3025
|
/** @param tag Returns true if `qDispatchEvent` needs patching */
|
|
2952
3026
|
function setBulkProps(vnode, srcAttrs, currentFile) {
|
|
2953
3027
|
vnode_ensureElementInflated(vnode);
|
|
2954
|
-
const dstAttrs = vnode;
|
|
3028
|
+
const dstAttrs = vnode_getProps(vnode);
|
|
2955
3029
|
let srcIdx = 0;
|
|
2956
3030
|
const srcLength = srcAttrs.length;
|
|
2957
|
-
let dstIdx =
|
|
3031
|
+
let dstIdx = 0;
|
|
2958
3032
|
let dstLength = dstAttrs.length;
|
|
2959
3033
|
let srcKey = srcIdx < srcLength ? srcAttrs[srcIdx++] : null;
|
|
2960
3034
|
let dstKey = dstIdx < dstLength ? dstAttrs[dstIdx++] : null;
|
|
@@ -2974,12 +3048,15 @@
|
|
|
2974
3048
|
value(element);
|
|
2975
3049
|
return;
|
|
2976
3050
|
}
|
|
3051
|
+
else if (value == null) {
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
2977
3054
|
else {
|
|
2978
3055
|
throw qError(QError.invalidRefValue, [currentFile]);
|
|
2979
3056
|
}
|
|
2980
3057
|
}
|
|
2981
3058
|
if (isSignal(value)) {
|
|
2982
|
-
const signalData = new
|
|
3059
|
+
const signalData = new SubscriptionData({
|
|
2983
3060
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
2984
3061
|
$isConst$: false,
|
|
2985
3062
|
});
|
|
@@ -2993,21 +3070,21 @@
|
|
|
2993
3070
|
};
|
|
2994
3071
|
const recordJsxEvent = (key, value) => {
|
|
2995
3072
|
const eventName = getEventNameFromJsxProp(key);
|
|
3073
|
+
const scope = getEventNameScopeFromJsxProp(key);
|
|
2996
3074
|
if (eventName) {
|
|
2997
|
-
const scope = getEventNameScopeFromJsxProp(key);
|
|
2998
3075
|
record(':' + scope + ':' + eventName, value);
|
|
2999
|
-
|
|
3000
|
-
// add an event attr with empty value for qwikloader element selector.
|
|
3001
|
-
// We don't need value here. For ssr this value is a QRL,
|
|
3002
|
-
// but for CSR value should be just empty
|
|
3003
|
-
const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
|
|
3004
|
-
if (htmlEvent) {
|
|
3005
|
-
record(htmlEvent, '');
|
|
3006
|
-
}
|
|
3007
|
-
// register an event for qwik loader
|
|
3008
|
-
if (eventName) {
|
|
3076
|
+
// register an event for qwik loader
|
|
3009
3077
|
registerQwikLoaderEvent(eventName);
|
|
3010
3078
|
}
|
|
3079
|
+
if (scope) {
|
|
3080
|
+
// add an event attr with empty value for qwikloader element selector.
|
|
3081
|
+
// We don't need value here. For ssr this value is a QRL,
|
|
3082
|
+
// but for CSR value should be just empty
|
|
3083
|
+
const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
|
|
3084
|
+
if (htmlEvent) {
|
|
3085
|
+
record(htmlEvent, '');
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3011
3088
|
};
|
|
3012
3089
|
while (srcKey !== null || dstKey !== null) {
|
|
3013
3090
|
if (dstKey?.startsWith(HANDLER_PREFIX) || dstKey?.startsWith(Q_PREFIX)) {
|
|
@@ -3203,10 +3280,6 @@
|
|
|
3203
3280
|
else if (!hashesAreEqual) {
|
|
3204
3281
|
insertNewComponent(host, componentQRL, jsxProps);
|
|
3205
3282
|
if (vNewNode) {
|
|
3206
|
-
if (host) {
|
|
3207
|
-
// TODO(varixo): not sure why we need to copy flags here.
|
|
3208
|
-
vNewNode[VNodeProps.flags] = host[VNodeProps.flags];
|
|
3209
|
-
}
|
|
3210
3283
|
host = vNewNode;
|
|
3211
3284
|
shouldRender = true;
|
|
3212
3285
|
}
|
|
@@ -3259,7 +3332,7 @@
|
|
|
3259
3332
|
}
|
|
3260
3333
|
function insertNewComponent(host, componentQRL, jsxProps) {
|
|
3261
3334
|
if (host) {
|
|
3262
|
-
|
|
3335
|
+
clearAllEffects(container, host);
|
|
3263
3336
|
}
|
|
3264
3337
|
vnode_insertBefore(journal, vParent, (vNewNode = vnode_newVirtual()), vCurrent && getInsertBefore());
|
|
3265
3338
|
const jsxNode = jsxValue;
|
|
@@ -3347,8 +3420,8 @@
|
|
|
3347
3420
|
if (!src || !dst) {
|
|
3348
3421
|
return true;
|
|
3349
3422
|
}
|
|
3350
|
-
let srcKeys = removePropsKeys(Object.keys(src), ['children',
|
|
3351
|
-
let dstKeys = removePropsKeys(Object.keys(dst), ['children',
|
|
3423
|
+
let srcKeys = removePropsKeys(Object.keys(src), ['children', QBackRefs]);
|
|
3424
|
+
let dstKeys = removePropsKeys(Object.keys(dst), ['children', QBackRefs]);
|
|
3352
3425
|
if (srcKeys.length !== dstKeys.length) {
|
|
3353
3426
|
return true;
|
|
3354
3427
|
}
|
|
@@ -3394,7 +3467,7 @@
|
|
|
3394
3467
|
do {
|
|
3395
3468
|
const type = vCursor[VNodeProps.flags];
|
|
3396
3469
|
if (type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) {
|
|
3397
|
-
|
|
3470
|
+
clearAllEffects(container, vCursor);
|
|
3398
3471
|
markVNodeAsDeleted(vCursor);
|
|
3399
3472
|
// Only elements and virtual nodes need to be traversed for children
|
|
3400
3473
|
if (type & VNodeFlags.Virtual) {
|
|
@@ -3404,7 +3477,7 @@
|
|
|
3404
3477
|
const obj = seq[i];
|
|
3405
3478
|
if (isTask(obj)) {
|
|
3406
3479
|
const task = obj;
|
|
3407
|
-
|
|
3480
|
+
clearAllEffects(container, task);
|
|
3408
3481
|
if (task.$flags$ & TaskFlags.VISIBLE_TASK) {
|
|
3409
3482
|
container.$scheduler$(ChoreType.CLEANUP_VISIBLE, task);
|
|
3410
3483
|
}
|
|
@@ -3419,8 +3492,8 @@
|
|
|
3419
3492
|
vnode_getProp(vCursor, OnRenderProp, null) !== null;
|
|
3420
3493
|
if (isComponent) {
|
|
3421
3494
|
// SPECIAL CASE: If we are a component, we need to descend into the projected content and release the content.
|
|
3422
|
-
const attrs = vCursor;
|
|
3423
|
-
for (let i =
|
|
3495
|
+
const attrs = vnode_getProps(vCursor);
|
|
3496
|
+
for (let i = 0; i < attrs.length; i = i + 2) {
|
|
3424
3497
|
const key = attrs[i];
|
|
3425
3498
|
if (!isParentSlotProp(key) && isSlotProp(key)) {
|
|
3426
3499
|
const value = attrs[i + 1];
|
|
@@ -3528,82 +3601,270 @@
|
|
|
3528
3601
|
SiblingsArray[SiblingsArray["NextVNode"] = 5] = "NextVNode";
|
|
3529
3602
|
})(SiblingsArray || (SiblingsArray = {}));
|
|
3530
3603
|
|
|
3531
|
-
|
|
3604
|
+
/** @internal */
|
|
3605
|
+
const useResourceQrl = (qrl, opts) => {
|
|
3606
|
+
const { val, set, i, iCtx } = useSequentialScope();
|
|
3607
|
+
if (val != null) {
|
|
3608
|
+
return val;
|
|
3609
|
+
}
|
|
3610
|
+
assertQrl(qrl);
|
|
3611
|
+
const container = iCtx.$container$;
|
|
3612
|
+
const resource = createResourceReturn(container, opts);
|
|
3613
|
+
const el = iCtx.$hostElement$;
|
|
3614
|
+
const task = new Task(TaskFlags.DIRTY | TaskFlags.RESOURCE, i, el, qrl, resource, null);
|
|
3615
|
+
container.$scheduler$(ChoreType.TASK, task);
|
|
3616
|
+
set(resource);
|
|
3617
|
+
return resource;
|
|
3618
|
+
};
|
|
3619
|
+
// <docs markdown="../readme.md#useResource">
|
|
3532
3620
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
3533
|
-
// (edit
|
|
3621
|
+
// (edit ../readme.md#useResource instead and run `pnpm docs.sync`)
|
|
3534
3622
|
/**
|
|
3535
|
-
*
|
|
3623
|
+
* This method works like an async memoized function that runs whenever some tracked value changes
|
|
3624
|
+
* and returns some data.
|
|
3536
3625
|
*
|
|
3537
|
-
*
|
|
3538
|
-
*
|
|
3539
|
-
* in `$`.
|
|
3626
|
+
* `useResource` however returns immediate a `ResourceReturn` object that contains the data and a
|
|
3627
|
+
* state that indicates if the data is available or not.
|
|
3540
3628
|
*
|
|
3541
|
-
*
|
|
3542
|
-
* The former is just a shorthand for the latter.
|
|
3629
|
+
* The status can be one of the following:
|
|
3543
3630
|
*
|
|
3544
|
-
*
|
|
3631
|
+
* - `pending` - the data is not yet available.
|
|
3632
|
+
* - `resolved` - the data is available.
|
|
3633
|
+
* - `rejected` - the data is not available due to an error or timeout.
|
|
3545
3634
|
*
|
|
3546
|
-
*
|
|
3635
|
+
* Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
|
|
3636
|
+
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
3547
3637
|
*
|
|
3548
|
-
*
|
|
3549
|
-
* export function myApi(callback: QRL<() => void>): void {
|
|
3550
|
-
* // ...
|
|
3551
|
-
* }
|
|
3638
|
+
* ### Example
|
|
3552
3639
|
*
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
3640
|
+
* Example showing how `useResource` to perform a fetch to request the weather, whenever the input
|
|
3641
|
+
* city name changes.
|
|
3555
3642
|
*
|
|
3556
|
-
*
|
|
3557
|
-
*
|
|
3643
|
+
* ```tsx
|
|
3644
|
+
* const Cmp = component$(() => {
|
|
3645
|
+
* const cityS = useSignal('');
|
|
3558
3646
|
*
|
|
3559
|
-
*
|
|
3560
|
-
*
|
|
3561
|
-
*
|
|
3647
|
+
* const weatherResource = useResource$(async ({ track, cleanup }) => {
|
|
3648
|
+
* const cityName = track(cityS);
|
|
3649
|
+
* const abortController = new AbortController();
|
|
3650
|
+
* cleanup(() => abortController.abort('cleanup'));
|
|
3651
|
+
* const res = await fetch(`http://weatherdata.com?city=${cityName}`, {
|
|
3652
|
+
* signal: abortController.signal,
|
|
3653
|
+
* });
|
|
3654
|
+
* const data = await res.json();
|
|
3655
|
+
* return data as { temp: number };
|
|
3656
|
+
* });
|
|
3562
3657
|
*
|
|
3563
|
-
*
|
|
3564
|
-
*
|
|
3658
|
+
* return (
|
|
3659
|
+
* <div>
|
|
3660
|
+
* <input name="city" bind:value={cityS} />
|
|
3661
|
+
* <Resource
|
|
3662
|
+
* value={weatherResource}
|
|
3663
|
+
* onResolved={(weather) => {
|
|
3664
|
+
* return <div>Temperature: {weather.temp}</div>;
|
|
3665
|
+
* }}
|
|
3666
|
+
* />
|
|
3667
|
+
* </div>
|
|
3668
|
+
* );
|
|
3669
|
+
* });
|
|
3565
3670
|
* ```
|
|
3566
3671
|
*
|
|
3567
|
-
* @param fn - A function that should have its first argument automatically `$`.
|
|
3568
3672
|
* @public
|
|
3673
|
+
* @see Resource
|
|
3674
|
+
* @see ResourceReturn
|
|
3569
3675
|
*/
|
|
3570
3676
|
// </docs>
|
|
3571
|
-
const
|
|
3572
|
-
|
|
3573
|
-
|
|
3677
|
+
const Resource = (props) => {
|
|
3678
|
+
// Resource path
|
|
3679
|
+
return _jsxSorted(Fragment, null, null, getResourceValueAsPromise(props), 0, null);
|
|
3680
|
+
};
|
|
3681
|
+
function getResourceValueAsPromise(props) {
|
|
3682
|
+
const resource = props.value;
|
|
3683
|
+
if (isResourceReturn(resource) && resource.value) {
|
|
3684
|
+
const isBrowser = !isServerPlatform();
|
|
3685
|
+
if (isBrowser) {
|
|
3686
|
+
// create a subscription for the resource._state changes
|
|
3687
|
+
const state = resource._state;
|
|
3688
|
+
if (state === 'pending' && props.onPending) {
|
|
3689
|
+
return Promise.resolve().then(useBindInvokeContext(props.onPending));
|
|
3690
|
+
}
|
|
3691
|
+
else if (state === 'rejected' && props.onRejected) {
|
|
3692
|
+
return Promise.resolve(resource._error).then(useBindInvokeContext(props.onRejected));
|
|
3693
|
+
}
|
|
3694
|
+
else {
|
|
3695
|
+
const resolvedValue = untrack(() => resource._resolved);
|
|
3696
|
+
if (resolvedValue !== undefined) {
|
|
3697
|
+
// resolved, pending without onPending prop or rejected without onRejected prop
|
|
3698
|
+
return Promise.resolve(resolvedValue).then(useBindInvokeContext(props.onResolved));
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
return resource.value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3703
|
+
}
|
|
3704
|
+
else if (isPromise(resource)) {
|
|
3705
|
+
return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3706
|
+
}
|
|
3707
|
+
else if (isSignal(resource)) {
|
|
3708
|
+
return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3709
|
+
}
|
|
3710
|
+
else {
|
|
3711
|
+
return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
const _createResourceReturn = (opts) => {
|
|
3715
|
+
const resource = {
|
|
3716
|
+
__brand: 'resource',
|
|
3717
|
+
value: undefined,
|
|
3718
|
+
loading: isServerPlatform() ? false : true,
|
|
3719
|
+
_resolved: undefined,
|
|
3720
|
+
_error: undefined,
|
|
3721
|
+
_state: 'pending',
|
|
3722
|
+
_timeout: opts?.timeout ?? -1,
|
|
3723
|
+
_cache: 0,
|
|
3574
3724
|
};
|
|
3725
|
+
return resource;
|
|
3575
3726
|
};
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3727
|
+
const createResourceReturn = (container, opts, initialPromise) => {
|
|
3728
|
+
const result = _createResourceReturn(opts);
|
|
3729
|
+
result.value = initialPromise;
|
|
3730
|
+
return createStore(container, result, StoreFlags.RECURSIVE);
|
|
3579
3731
|
};
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
|
|
3732
|
+
const isResourceReturn = (obj) => {
|
|
3733
|
+
return isObject(obj) && (getStoreTarget(obj) || obj).__brand === 'resource';
|
|
3734
|
+
};
|
|
3735
|
+
const runResource = (task, container, host) => {
|
|
3736
|
+
task.$flags$ &= ~TaskFlags.DIRTY;
|
|
3737
|
+
cleanupTask(task);
|
|
3738
|
+
const iCtx = newInvokeContext(container.$locale$, host, undefined, ResourceEvent);
|
|
3739
|
+
iCtx.$container$ = container;
|
|
3740
|
+
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
3741
|
+
const resource = task.$state$;
|
|
3742
|
+
assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
|
|
3743
|
+
const track = (obj, prop) => {
|
|
3744
|
+
const ctx = newInvokeContext();
|
|
3745
|
+
ctx.$effectSubscriber$ = getSubscriber(task, EffectProperty.COMPONENT);
|
|
3746
|
+
ctx.$container$ = container;
|
|
3747
|
+
return invoke(ctx, () => {
|
|
3748
|
+
if (isFunction(obj)) {
|
|
3749
|
+
return obj();
|
|
3750
|
+
}
|
|
3751
|
+
if (prop) {
|
|
3752
|
+
return obj[prop];
|
|
3753
|
+
}
|
|
3754
|
+
else if (isSignal(obj)) {
|
|
3755
|
+
return obj.value;
|
|
3756
|
+
}
|
|
3757
|
+
else {
|
|
3758
|
+
return obj;
|
|
3759
|
+
}
|
|
3760
|
+
});
|
|
3761
|
+
};
|
|
3762
|
+
const handleError = (reason) => container.handleError(reason, host);
|
|
3763
|
+
const cleanups = [];
|
|
3764
|
+
task.$destroy$ = noSerialize(() => {
|
|
3765
|
+
cleanups.forEach((fn) => {
|
|
3766
|
+
try {
|
|
3767
|
+
fn();
|
|
3768
|
+
}
|
|
3769
|
+
catch (err) {
|
|
3770
|
+
handleError(err);
|
|
3771
|
+
}
|
|
3772
|
+
});
|
|
3773
|
+
done = true;
|
|
3774
|
+
});
|
|
3775
|
+
const resourceTarget = unwrapStore(resource);
|
|
3776
|
+
const opts = {
|
|
3777
|
+
track,
|
|
3778
|
+
cleanup(fn) {
|
|
3779
|
+
if (typeof fn === 'function') {
|
|
3780
|
+
cleanups.push(fn);
|
|
3781
|
+
}
|
|
3782
|
+
},
|
|
3783
|
+
cache(policy) {
|
|
3784
|
+
let milliseconds = 0;
|
|
3785
|
+
if (policy === 'immutable') {
|
|
3786
|
+
milliseconds = Infinity;
|
|
3787
|
+
}
|
|
3788
|
+
else {
|
|
3789
|
+
milliseconds = policy;
|
|
3790
|
+
}
|
|
3791
|
+
resource._cache = milliseconds;
|
|
3792
|
+
},
|
|
3793
|
+
previous: resourceTarget._resolved,
|
|
3794
|
+
};
|
|
3795
|
+
let resolve;
|
|
3796
|
+
let reject;
|
|
3797
|
+
let done = false;
|
|
3798
|
+
const setState = (resolved, value) => {
|
|
3799
|
+
if (!done) {
|
|
3800
|
+
done = true;
|
|
3801
|
+
if (resolved) {
|
|
3802
|
+
done = true;
|
|
3803
|
+
resource.loading = false;
|
|
3804
|
+
resource._state = 'resolved';
|
|
3805
|
+
resource._resolved = value;
|
|
3806
|
+
resource._error = undefined;
|
|
3807
|
+
resolve(value);
|
|
3808
|
+
}
|
|
3809
|
+
else {
|
|
3810
|
+
done = true;
|
|
3811
|
+
resource.loading = false;
|
|
3812
|
+
resource._state = 'rejected';
|
|
3813
|
+
resource._error = value;
|
|
3814
|
+
reject(value);
|
|
3815
|
+
}
|
|
3816
|
+
return true;
|
|
3817
|
+
}
|
|
3818
|
+
return false;
|
|
3819
|
+
};
|
|
3820
|
+
/**
|
|
3821
|
+
* Add cleanup to resolve the resource if we are trying to run the same resource again while the
|
|
3822
|
+
* previous one is not resolved yet. The next `runResource` run will call this cleanup
|
|
3823
|
+
*/
|
|
3824
|
+
cleanups.push(() => {
|
|
3825
|
+
if (untrack(() => resource.loading) === true) {
|
|
3826
|
+
const value = untrack(() => resource._resolved);
|
|
3827
|
+
setState(true, value);
|
|
3828
|
+
}
|
|
3829
|
+
});
|
|
3830
|
+
// Execute mutation inside empty invocation
|
|
3831
|
+
invoke(iCtx, () => {
|
|
3832
|
+
// console.log('RESOURCE.pending: ');
|
|
3833
|
+
resource._state = 'pending';
|
|
3834
|
+
resource.loading = !isServerPlatform();
|
|
3835
|
+
const promise = (resource.value = new Promise((r, re) => {
|
|
3836
|
+
resolve = r;
|
|
3837
|
+
reject = re;
|
|
3838
|
+
}));
|
|
3839
|
+
promise.catch(ignoreErrorToPreventNodeFromCrashing);
|
|
3840
|
+
});
|
|
3841
|
+
const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
|
|
3842
|
+
setState(true, value);
|
|
3843
|
+
}, (err) => {
|
|
3844
|
+
if (isPromise(err)) {
|
|
3845
|
+
return err.then(() => runResource(task, container, host));
|
|
3846
|
+
}
|
|
3847
|
+
else {
|
|
3848
|
+
setState(false, err);
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
const timeout = resourceTarget._timeout;
|
|
3852
|
+
if (timeout > 0) {
|
|
3853
|
+
return Promise.race([
|
|
3854
|
+
promise,
|
|
3855
|
+
delay(timeout).then(() => {
|
|
3856
|
+
if (setState(false, new Error('timeout'))) {
|
|
3857
|
+
cleanupTask(task);
|
|
3858
|
+
}
|
|
3859
|
+
}),
|
|
3860
|
+
]);
|
|
3861
|
+
}
|
|
3862
|
+
return promise;
|
|
3863
|
+
};
|
|
3864
|
+
const ignoreErrorToPreventNodeFromCrashing = (err) => {
|
|
3865
|
+
// ignore error to prevent node from crashing
|
|
3866
|
+
// node will crash in promise is rejected and no one is listening to the rejection.
|
|
3583
3867
|
};
|
|
3584
|
-
|
|
3585
|
-
/**
|
|
3586
|
-
* Creates a Signal with the given value. If no value is given, the signal is created with
|
|
3587
|
-
* `undefined`.
|
|
3588
|
-
*
|
|
3589
|
-
* @public
|
|
3590
|
-
*/
|
|
3591
|
-
const createSignal = createSignal$1;
|
|
3592
|
-
/** @internal */
|
|
3593
|
-
const createComputedQrl = createComputedSignal;
|
|
3594
|
-
/**
|
|
3595
|
-
* Create a computed signal which is calculated from the given QRL. A computed signal is a signal
|
|
3596
|
-
* which is calculated from other signals. When the signals change, the computed signal is
|
|
3597
|
-
* recalculated.
|
|
3598
|
-
*
|
|
3599
|
-
* The QRL must be a function which returns the value of the signal. The function must not have side
|
|
3600
|
-
* effects, and it mus be synchronous.
|
|
3601
|
-
*
|
|
3602
|
-
* If you need the function to be async, use `useSignal` and `useTask$` instead.
|
|
3603
|
-
*
|
|
3604
|
-
* @public
|
|
3605
|
-
*/
|
|
3606
|
-
const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedQrl);
|
|
3607
3868
|
|
|
3608
3869
|
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
|
|
3609
3870
|
const aVNodePath = [];
|
|
@@ -3788,38 +4049,29 @@
|
|
|
3788
4049
|
* - Visible Tasks are sorted afterJournalFlush, than depth first on component and finally in
|
|
3789
4050
|
* declaration order within component.
|
|
3790
4051
|
*/
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
ChoreType[ChoreType["MICRO"] = 15] = "MICRO";
|
|
3797
|
-
/** Ensure tha the QRL promise is resolved before processing next chores in the queue */
|
|
3798
|
-
ChoreType[ChoreType["QRL_RESOLVE"] = 1] = "QRL_RESOLVE";
|
|
3799
|
-
ChoreType[ChoreType["RESOURCE"] = 2] = "RESOURCE";
|
|
3800
|
-
ChoreType[ChoreType["TASK"] = 3] = "TASK";
|
|
3801
|
-
ChoreType[ChoreType["NODE_DIFF"] = 4] = "NODE_DIFF";
|
|
3802
|
-
ChoreType[ChoreType["NODE_PROP"] = 5] = "NODE_PROP";
|
|
3803
|
-
ChoreType[ChoreType["COMPONENT_SSR"] = 6] = "COMPONENT_SSR";
|
|
3804
|
-
ChoreType[ChoreType["COMPONENT"] = 7] = "COMPONENT";
|
|
3805
|
-
ChoreType[ChoreType["RECOMPUTE_AND_SCHEDULE_EFFECTS"] = 8] = "RECOMPUTE_AND_SCHEDULE_EFFECTS";
|
|
3806
|
-
ChoreType[ChoreType["JOURNAL_FLUSH"] = 16] = "JOURNAL_FLUSH";
|
|
3807
|
-
ChoreType[ChoreType["VISIBLE"] = 32] = "VISIBLE";
|
|
3808
|
-
ChoreType[ChoreType["CLEANUP_VISIBLE"] = 48] = "CLEANUP_VISIBLE";
|
|
3809
|
-
ChoreType[ChoreType["WAIT_FOR_ALL"] = 255] = "WAIT_FOR_ALL";
|
|
3810
|
-
})(ChoreType || (ChoreType = {}));
|
|
4052
|
+
// Turn this on to get debug output of what the scheduler is doing.
|
|
4053
|
+
const DEBUG$1 = false;
|
|
4054
|
+
const getPromise = (chore) => (chore.$promise$ ||= new Promise((resolve) => {
|
|
4055
|
+
chore.$resolve$ = resolve;
|
|
4056
|
+
}));
|
|
3811
4057
|
const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
3812
4058
|
const choreQueue = [];
|
|
4059
|
+
const qrlRuns = [];
|
|
3813
4060
|
let currentChore = null;
|
|
3814
|
-
let
|
|
4061
|
+
let drainScheduled = false;
|
|
3815
4062
|
return schedule;
|
|
3816
4063
|
///// IMPLEMENTATION /////
|
|
3817
4064
|
function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
|
|
3818
|
-
const
|
|
3819
|
-
const
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
4065
|
+
const isServer = !isDomContainer(container);
|
|
4066
|
+
const isComponentSsr = isServer && type === ChoreType.COMPONENT;
|
|
4067
|
+
const runLater = type !== ChoreType.WAIT_FOR_ALL && !isComponentSsr && type !== ChoreType.RUN_QRL;
|
|
4068
|
+
const isTask = type === ChoreType.TASK || type === ChoreType.VISIBLE || type === ChoreType.CLEANUP_VISIBLE;
|
|
4069
|
+
const isClientOnly = type === ChoreType.JOURNAL_FLUSH ||
|
|
4070
|
+
type === ChoreType.NODE_DIFF ||
|
|
4071
|
+
type === ChoreType.NODE_PROP;
|
|
4072
|
+
if (isServer && isClientOnly) {
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
3823
4075
|
if (isTask) {
|
|
3824
4076
|
hostOrTask.$flags$ |= TaskFlags.DIRTY;
|
|
3825
4077
|
}
|
|
@@ -3838,192 +4090,234 @@
|
|
|
3838
4090
|
$returnValue$: null,
|
|
3839
4091
|
$executed$: false,
|
|
3840
4092
|
};
|
|
3841
|
-
chore.$promise$ = new Promise((resolve) => (chore.$resolve$ = resolve));
|
|
3842
4093
|
chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
|
|
3843
|
-
if (!
|
|
4094
|
+
if (!drainScheduled && runLater) {
|
|
3844
4095
|
// If we are not currently draining, we need to schedule a drain.
|
|
3845
|
-
|
|
4096
|
+
drainScheduled = true;
|
|
3846
4097
|
schedule(ChoreType.JOURNAL_FLUSH);
|
|
3847
|
-
|
|
4098
|
+
// Catch here to avoid unhandled promise rejection
|
|
4099
|
+
scheduleDrain()?.catch?.(() => { });
|
|
3848
4100
|
}
|
|
4101
|
+
// TODO figure out what to do with chore errors
|
|
3849
4102
|
if (runLater) {
|
|
3850
|
-
return chore
|
|
4103
|
+
return getPromise(chore);
|
|
3851
4104
|
}
|
|
3852
4105
|
else {
|
|
3853
|
-
return drainUpTo(chore,
|
|
4106
|
+
return drainUpTo(chore, isServer);
|
|
3854
4107
|
}
|
|
3855
4108
|
}
|
|
3856
|
-
/**
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
* @param runUptoChore
|
|
3860
|
-
*/
|
|
3861
|
-
function drainUpTo(runUptoChore, rootVNode) {
|
|
3862
|
-
// If it already ran, it's not in the queue
|
|
3863
|
-
if (runUptoChore.$executed$) {
|
|
3864
|
-
return runUptoChore.$returnValue$;
|
|
3865
|
-
}
|
|
3866
|
-
if (currentChore) {
|
|
3867
|
-
// Already running chore, which means we're waiting for async completion
|
|
3868
|
-
return runUptoChore.$promise$;
|
|
3869
|
-
}
|
|
4109
|
+
/** Execute all of the chores up to and including the given chore. */
|
|
4110
|
+
function drainUpTo(runUptoChore, isServer) {
|
|
4111
|
+
let maxRetries = 5000;
|
|
3870
4112
|
while (choreQueue.length) {
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
if (order === null) {
|
|
3874
|
-
continue;
|
|
4113
|
+
if (maxRetries-- < 0) {
|
|
4114
|
+
throw new Error('drainUpTo: max retries reached');
|
|
3875
4115
|
}
|
|
3876
|
-
if (
|
|
3877
|
-
//
|
|
3878
|
-
|
|
4116
|
+
if (currentChore) {
|
|
4117
|
+
// Already running chore, which means we're waiting for async completion
|
|
4118
|
+
return getPromise(currentChore)
|
|
4119
|
+
.then(() => drainUpTo(runUptoChore, isServer))
|
|
4120
|
+
.catch((e) => {
|
|
4121
|
+
container.handleError(e, currentChore?.$host$);
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
const nextChore = choreQueue[0];
|
|
4125
|
+
if (nextChore.$executed$) {
|
|
4126
|
+
choreQueue.shift();
|
|
4127
|
+
if (nextChore === runUptoChore) {
|
|
4128
|
+
break;
|
|
4129
|
+
}
|
|
4130
|
+
continue;
|
|
3879
4131
|
}
|
|
3880
|
-
|
|
3881
|
-
if (isDeletedVNode &&
|
|
4132
|
+
if (vNodeAlreadyDeleted(nextChore) &&
|
|
3882
4133
|
// we need to process cleanup tasks for deleted nodes
|
|
3883
4134
|
nextChore.$type$ !== ChoreType.CLEANUP_VISIBLE) {
|
|
4135
|
+
choreQueue.shift();
|
|
3884
4136
|
continue;
|
|
3885
4137
|
}
|
|
3886
|
-
|
|
3887
|
-
if (isPromise(returnValue)) {
|
|
3888
|
-
const promise = returnValue.then(() => drainUpTo(runUptoChore, rootVNode));
|
|
3889
|
-
return promise;
|
|
3890
|
-
}
|
|
4138
|
+
executeChore(nextChore, isServer);
|
|
3891
4139
|
}
|
|
3892
4140
|
return runUptoChore.$returnValue$;
|
|
3893
4141
|
}
|
|
3894
|
-
function executeChore(chore) {
|
|
4142
|
+
function executeChore(chore, isServer) {
|
|
3895
4143
|
const host = chore.$host$;
|
|
3896
4144
|
assertEqual(currentChore, null, 'Chore already running.');
|
|
3897
4145
|
currentChore = chore;
|
|
3898
4146
|
let returnValue = null;
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
|
|
3907
|
-
if (chore.$type$ === ChoreType.COMPONENT) {
|
|
3908
|
-
const styleScopedId = container.getHostProp(host, QScopedStyle);
|
|
3909
|
-
return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
|
|
4147
|
+
try {
|
|
4148
|
+
switch (chore.$type$) {
|
|
4149
|
+
case ChoreType.WAIT_FOR_ALL:
|
|
4150
|
+
{
|
|
4151
|
+
if (isServer) {
|
|
4152
|
+
drainScheduled = false;
|
|
4153
|
+
}
|
|
3910
4154
|
}
|
|
3911
|
-
|
|
3912
|
-
|
|
4155
|
+
break;
|
|
4156
|
+
case ChoreType.JOURNAL_FLUSH:
|
|
4157
|
+
{
|
|
4158
|
+
returnValue = journalFlush();
|
|
4159
|
+
drainScheduled = false;
|
|
4160
|
+
}
|
|
4161
|
+
break;
|
|
4162
|
+
case ChoreType.COMPONENT:
|
|
4163
|
+
{
|
|
4164
|
+
returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
|
|
4165
|
+
if (isServer) {
|
|
4166
|
+
return jsx;
|
|
4167
|
+
}
|
|
4168
|
+
else {
|
|
4169
|
+
const styleScopedId = container.getHostProp(host, QScopedStyle);
|
|
4170
|
+
return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
|
|
4171
|
+
}
|
|
4172
|
+
}, (err) => container.handleError(err, host));
|
|
4173
|
+
}
|
|
4174
|
+
break;
|
|
4175
|
+
case ChoreType.RUN_QRL:
|
|
4176
|
+
{
|
|
4177
|
+
const fn = chore.$target$.getFn();
|
|
4178
|
+
const result = retryOnPromise(() => fn(...chore.$payload$));
|
|
4179
|
+
if (isPromise(result)) {
|
|
4180
|
+
const handled = result
|
|
4181
|
+
.finally(() => {
|
|
4182
|
+
qrlRuns.splice(qrlRuns.indexOf(handled), 1);
|
|
4183
|
+
})
|
|
4184
|
+
.catch((error) => {
|
|
4185
|
+
container.handleError(error, chore.$host$);
|
|
4186
|
+
});
|
|
4187
|
+
// Don't wait for the promise to resolve
|
|
4188
|
+
// TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
|
|
4189
|
+
qrlRuns.push(handled);
|
|
4190
|
+
DEBUG$1 &&
|
|
4191
|
+
debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
|
|
4192
|
+
chore.$returnValue$ = handled;
|
|
4193
|
+
chore.$resolve$?.(handled);
|
|
4194
|
+
currentChore = null;
|
|
4195
|
+
chore.$executed$ = true;
|
|
4196
|
+
// early out so we don't call after()
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
returnValue = null;
|
|
4200
|
+
}
|
|
4201
|
+
break;
|
|
4202
|
+
case ChoreType.TASK:
|
|
4203
|
+
case ChoreType.VISIBLE:
|
|
4204
|
+
{
|
|
4205
|
+
const payload = chore.$payload$;
|
|
4206
|
+
if (payload.$flags$ & TaskFlags.RESOURCE) {
|
|
4207
|
+
const result = runResource(payload, container, host);
|
|
4208
|
+
// Don't await the return value of the resource, because async resources should not be awaited.
|
|
4209
|
+
// The reason for this is that we should be able to update for example a node with loading
|
|
4210
|
+
// text. If we await the resource, the loading text will not be displayed until the resource
|
|
4211
|
+
// is loaded.
|
|
4212
|
+
// Awaiting on the client also causes a deadlock.
|
|
4213
|
+
// In any case, the resource will never throw.
|
|
4214
|
+
returnValue = isServer ? result : null;
|
|
4215
|
+
}
|
|
4216
|
+
else {
|
|
4217
|
+
returnValue = runTask(payload, container, host);
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
break;
|
|
4221
|
+
case ChoreType.CLEANUP_VISIBLE:
|
|
4222
|
+
{
|
|
4223
|
+
const task = chore.$payload$;
|
|
4224
|
+
cleanupTask(task);
|
|
4225
|
+
}
|
|
4226
|
+
break;
|
|
4227
|
+
case ChoreType.NODE_DIFF:
|
|
4228
|
+
{
|
|
4229
|
+
const parentVirtualNode = chore.$target$;
|
|
4230
|
+
let jsx = chore.$payload$;
|
|
4231
|
+
if (isSignal(jsx)) {
|
|
4232
|
+
jsx = jsx.value;
|
|
4233
|
+
}
|
|
4234
|
+
returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
|
|
4235
|
+
}
|
|
4236
|
+
break;
|
|
4237
|
+
case ChoreType.NODE_PROP:
|
|
4238
|
+
{
|
|
4239
|
+
const virtualNode = chore.$host$;
|
|
4240
|
+
const payload = chore.$payload$;
|
|
4241
|
+
let value = payload.$value$;
|
|
4242
|
+
if (isSignal(value)) {
|
|
4243
|
+
value = value.value;
|
|
4244
|
+
}
|
|
4245
|
+
const isConst = payload.$isConst$;
|
|
4246
|
+
const journal = container.$journal$;
|
|
4247
|
+
const property = chore.$idx$;
|
|
4248
|
+
const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
|
|
4249
|
+
if (isConst) {
|
|
4250
|
+
const element = virtualNode[ElementVNodeProps.element];
|
|
4251
|
+
journal.push(VNodeJournalOpCode.SetAttribute, element, property, serializedValue);
|
|
4252
|
+
}
|
|
4253
|
+
else {
|
|
4254
|
+
vnode_setAttr(journal, virtualNode, property, serializedValue);
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
break;
|
|
4258
|
+
case ChoreType.QRL_RESOLVE: {
|
|
4259
|
+
{
|
|
4260
|
+
const target = chore.$target$;
|
|
4261
|
+
returnValue = !target.resolved ? target.resolve() : null;
|
|
3913
4262
|
}
|
|
3914
|
-
}, (err) => container.handleError(err, host));
|
|
3915
|
-
break;
|
|
3916
|
-
case ChoreType.RESOURCE:
|
|
3917
|
-
// Don't await the return value of the resource, because async resources should not be awaited.
|
|
3918
|
-
// The reason for this is that we should be able to update for example a node with loading
|
|
3919
|
-
// text. If we await the resource, the loading text will not be displayed until the resource
|
|
3920
|
-
// is loaded.
|
|
3921
|
-
const result = runResource(chore.$payload$, container, host);
|
|
3922
|
-
returnValue = isDomContainer(container) ? null : result;
|
|
3923
|
-
break;
|
|
3924
|
-
case ChoreType.TASK:
|
|
3925
|
-
returnValue = runTask(chore.$payload$, container, host);
|
|
3926
|
-
break;
|
|
3927
|
-
case ChoreType.VISIBLE:
|
|
3928
|
-
returnValue = runTask(chore.$payload$, container, host);
|
|
3929
|
-
break;
|
|
3930
|
-
case ChoreType.CLEANUP_VISIBLE:
|
|
3931
|
-
const task = chore.$payload$;
|
|
3932
|
-
cleanupTask(task);
|
|
3933
|
-
break;
|
|
3934
|
-
case ChoreType.NODE_DIFF:
|
|
3935
|
-
const parentVirtualNode = chore.$target$;
|
|
3936
|
-
let jsx = chore.$payload$;
|
|
3937
|
-
if (isSignal(jsx)) {
|
|
3938
|
-
jsx = jsx.value;
|
|
3939
|
-
}
|
|
3940
|
-
returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
|
|
3941
|
-
break;
|
|
3942
|
-
case ChoreType.NODE_PROP:
|
|
3943
|
-
const virtualNode = chore.$host$;
|
|
3944
|
-
const payload = chore.$payload$;
|
|
3945
|
-
let value = payload.$value$;
|
|
3946
|
-
if (isSignal(value)) {
|
|
3947
|
-
value = value.value;
|
|
3948
|
-
}
|
|
3949
|
-
const isConst = payload.$isConst$;
|
|
3950
|
-
const journal = container.$journal$;
|
|
3951
|
-
const property = chore.$idx$;
|
|
3952
|
-
const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
|
|
3953
|
-
if (isConst) {
|
|
3954
|
-
const element = virtualNode[ElementVNodeProps.element];
|
|
3955
|
-
journal.push(VNodeJournalOpCode.SetAttribute, element, property, serializedValue);
|
|
3956
|
-
}
|
|
3957
|
-
else {
|
|
3958
|
-
vnode_setAttr(journal, virtualNode, property, serializedValue);
|
|
3959
|
-
}
|
|
3960
|
-
break;
|
|
3961
|
-
case ChoreType.QRL_RESOLVE: {
|
|
3962
|
-
const target = chore.$target$;
|
|
3963
|
-
returnValue = !target.resolved ? target.resolve() : null;
|
|
3964
|
-
break;
|
|
3965
|
-
}
|
|
3966
|
-
case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
|
|
3967
|
-
const target = chore.$target$;
|
|
3968
|
-
const forceRunEffects = target.$forceRunEffects$;
|
|
3969
|
-
target.$forceRunEffects$ = false;
|
|
3970
|
-
if (!target.$effects$?.length) {
|
|
3971
4263
|
break;
|
|
3972
4264
|
}
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
4265
|
+
case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
|
|
4266
|
+
{
|
|
4267
|
+
const target = chore.$target$;
|
|
4268
|
+
const forceRunEffects = target.$forceRunEffects$;
|
|
4269
|
+
target.$forceRunEffects$ = false;
|
|
4270
|
+
if (!target.$effects$?.size) {
|
|
4271
|
+
break;
|
|
4272
|
+
}
|
|
4273
|
+
returnValue = retryOnPromise(() => {
|
|
4274
|
+
if (target.$computeIfNeeded$() || forceRunEffects) {
|
|
4275
|
+
triggerEffects(container, target, target.$effects$);
|
|
4276
|
+
}
|
|
4277
|
+
});
|
|
3976
4278
|
}
|
|
3977
|
-
|
|
3978
|
-
|
|
4279
|
+
break;
|
|
4280
|
+
}
|
|
3979
4281
|
}
|
|
3980
4282
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
}
|
|
4283
|
+
catch (e) {
|
|
4284
|
+
returnValue = Promise.reject(e);
|
|
4285
|
+
}
|
|
4286
|
+
const after = (value, error) => {
|
|
3986
4287
|
currentChore = null;
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
function vNodeAlreadyDeleted(chore) {
|
|
4005
|
-
return !!(chore.$host$ &&
|
|
4006
|
-
vnode_isVNode(chore.$host$) &&
|
|
4007
|
-
chore.$host$[VNodeProps.flags] & VNodeFlags.Deleted);
|
|
4008
|
-
}
|
|
4009
|
-
/**
|
|
4010
|
-
* Compares two chores to determine their execution order in the scheduler's queue.
|
|
4011
|
-
*
|
|
4012
|
-
* @param a - The first chore to compare
|
|
4013
|
-
* @param b - The second chore to compare
|
|
4014
|
-
* @returns A number indicating the relative order of the chores. A negative number means `a` runs
|
|
4015
|
-
* before `b`.
|
|
4016
|
-
*/
|
|
4017
|
-
function choreComparator(a, b, rootVNode) {
|
|
4018
|
-
const macroTypeDiff = (a.$type$ & ChoreType.MACRO) - (b.$type$ & ChoreType.MACRO);
|
|
4019
|
-
if (macroTypeDiff !== 0) {
|
|
4020
|
-
return macroTypeDiff;
|
|
4288
|
+
chore.$executed$ = true;
|
|
4289
|
+
if (error) {
|
|
4290
|
+
container.handleError(error, host);
|
|
4291
|
+
}
|
|
4292
|
+
else {
|
|
4293
|
+
chore.$returnValue$ = value;
|
|
4294
|
+
chore.$resolve$?.(value);
|
|
4295
|
+
}
|
|
4296
|
+
};
|
|
4297
|
+
if (isPromise(returnValue)) {
|
|
4298
|
+
chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
|
|
4299
|
+
chore.$resolve$?.(chore.$promise$);
|
|
4300
|
+
chore.$resolve$ = undefined;
|
|
4301
|
+
}
|
|
4302
|
+
else {
|
|
4303
|
+
after(returnValue);
|
|
4304
|
+
}
|
|
4021
4305
|
}
|
|
4022
|
-
|
|
4023
|
-
|
|
4306
|
+
/**
|
|
4307
|
+
* Compares two chores to determine their execution order in the scheduler's queue.
|
|
4308
|
+
*
|
|
4309
|
+
* @param a - The first chore to compare
|
|
4310
|
+
* @param b - The second chore to compare
|
|
4311
|
+
* @returns A number indicating the relative order of the chores. A negative number means `a` runs
|
|
4312
|
+
* before `b`.
|
|
4313
|
+
*/
|
|
4314
|
+
function choreComparator(a, b, rootVNode) {
|
|
4315
|
+
const macroTypeDiff = (a.$type$ & ChoreType.MACRO) - (b.$type$ & ChoreType.MACRO);
|
|
4316
|
+
if (macroTypeDiff !== 0) {
|
|
4317
|
+
return macroTypeDiff;
|
|
4318
|
+
}
|
|
4024
4319
|
const aHost = a.$host$;
|
|
4025
4320
|
const bHost = b.$host$;
|
|
4026
|
-
// QRL_RESOLVE does not have a host.
|
|
4027
4321
|
if (aHost !== bHost && aHost !== null && bHost !== null) {
|
|
4028
4322
|
if (vnode_isVNode(aHost) && vnode_isVNode(bHost)) {
|
|
4029
4323
|
// we are running on the client.
|
|
@@ -4033,6 +4327,8 @@
|
|
|
4033
4327
|
}
|
|
4034
4328
|
}
|
|
4035
4329
|
else {
|
|
4330
|
+
assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
|
|
4331
|
+
assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
|
|
4036
4332
|
// we are running on the server.
|
|
4037
4333
|
// On server we can't schedule task for a different host!
|
|
4038
4334
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -4052,247 +4348,114 @@
|
|
|
4052
4348
|
if (microTypeDiff !== 0) {
|
|
4053
4349
|
return microTypeDiff;
|
|
4054
4350
|
}
|
|
4351
|
+
// types are the same
|
|
4055
4352
|
const idxDiff = toNumber(a.$idx$) - toNumber(b.$idx$);
|
|
4056
|
-
if (idxDiff !== 0) {
|
|
4057
|
-
return idxDiff;
|
|
4058
|
-
}
|
|
4059
|
-
// If the host is the same, we need to compare the target.
|
|
4060
|
-
if (a.$target$ !== b.$target$ &&
|
|
4061
|
-
((a.$type$ === ChoreType.QRL_RESOLVE && b.$type$ === ChoreType.QRL_RESOLVE) ||
|
|
4062
|
-
(a.$type$ === ChoreType.NODE_PROP && b.$type$ === ChoreType.NODE_PROP) ||
|
|
4063
|
-
(a.$type$ === ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS &&
|
|
4064
|
-
b.$type$ === ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS))) {
|
|
4065
|
-
// 1 means that we are going to process chores as FIFO
|
|
4066
|
-
return 1;
|
|
4067
|
-
}
|
|
4068
|
-
}
|
|
4069
|
-
return 0;
|
|
4070
|
-
}
|
|
4071
|
-
function sortedFindIndex(sortedArray, value, rootVNode) {
|
|
4072
|
-
/// We need to ensure that the `queue` is sorted by priority.
|
|
4073
|
-
/// 1. Find a place where to insert into.
|
|
4074
|
-
let bottom = 0;
|
|
4075
|
-
let top = sortedArray.length;
|
|
4076
|
-
while (bottom < top) {
|
|
4077
|
-
const middle = bottom + ((top - bottom) >> 1);
|
|
4078
|
-
const midChore = sortedArray[middle];
|
|
4079
|
-
const comp = choreComparator(value, midChore, rootVNode);
|
|
4080
|
-
if (comp < 0) {
|
|
4081
|
-
top = middle;
|
|
4082
|
-
}
|
|
4083
|
-
else if (comp > 0) {
|
|
4084
|
-
bottom = middle + 1;
|
|
4085
|
-
}
|
|
4086
|
-
else {
|
|
4087
|
-
// We already have the host in the queue.
|
|
4088
|
-
return middle;
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
return ~bottom;
|
|
4092
|
-
}
|
|
4093
|
-
function sortedInsert(sortedArray, value, rootVNode) {
|
|
4094
|
-
/// We need to ensure that the `queue` is sorted by priority.
|
|
4095
|
-
/// 1. Find a place where to insert into.
|
|
4096
|
-
const idx = sortedFindIndex(sortedArray, value, rootVNode);
|
|
4097
|
-
if (idx < 0) {
|
|
4098
|
-
/// 2. Insert the chore into the queue.
|
|
4099
|
-
sortedArray.splice(~idx, 0, value);
|
|
4100
|
-
return value;
|
|
4101
|
-
}
|
|
4102
|
-
const existing = sortedArray[idx];
|
|
4103
|
-
choreUpdate(existing, value);
|
|
4104
|
-
return existing;
|
|
4105
|
-
}
|
|
4106
|
-
|
|
4107
|
-
// <docs markdown="../readme.md#useLexicalScope">
|
|
4108
|
-
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
4109
|
-
// (edit ../readme.md#useLexicalScope instead and run `pnpm docs.sync`)
|
|
4110
|
-
/**
|
|
4111
|
-
* Used by the Qwik Optimizer to restore the lexically scoped variables.
|
|
4112
|
-
*
|
|
4113
|
-
* This method should not be present in the application source code.
|
|
4114
|
-
*
|
|
4115
|
-
* NOTE: `useLexicalScope` method can only be used in the synchronous portion of the callback
|
|
4116
|
-
* (before any `await` statements.)
|
|
4117
|
-
*
|
|
4118
|
-
* @internal
|
|
4119
|
-
*/
|
|
4120
|
-
// </docs>
|
|
4121
|
-
const useLexicalScope = () => {
|
|
4122
|
-
const context = getInvokeContext();
|
|
4123
|
-
let qrl = context.$qrl$;
|
|
4124
|
-
if (!qrl) {
|
|
4125
|
-
const el = context.$element$;
|
|
4126
|
-
assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
4127
|
-
const containerElement = _getQContainerElement(el);
|
|
4128
|
-
assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
4129
|
-
const container = getDomContainer(containerElement);
|
|
4130
|
-
qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
|
|
4131
|
-
}
|
|
4132
|
-
else {
|
|
4133
|
-
assertQrl(qrl);
|
|
4134
|
-
assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
|
|
4135
|
-
}
|
|
4136
|
-
return qrl.$captureRef$;
|
|
4137
|
-
};
|
|
4138
|
-
|
|
4139
|
-
var TaskFlags;
|
|
4140
|
-
(function (TaskFlags) {
|
|
4141
|
-
TaskFlags[TaskFlags["VISIBLE_TASK"] = 1] = "VISIBLE_TASK";
|
|
4142
|
-
TaskFlags[TaskFlags["TASK"] = 2] = "TASK";
|
|
4143
|
-
TaskFlags[TaskFlags["RESOURCE"] = 4] = "RESOURCE";
|
|
4144
|
-
TaskFlags[TaskFlags["DIRTY"] = 8] = "DIRTY";
|
|
4145
|
-
})(TaskFlags || (TaskFlags = {}));
|
|
4146
|
-
/** @internal */
|
|
4147
|
-
const useTaskQrl = (qrl, opts) => {
|
|
4148
|
-
const { val, set, iCtx, i } = useSequentialScope();
|
|
4149
|
-
if (val) {
|
|
4150
|
-
return;
|
|
4151
|
-
}
|
|
4152
|
-
assertQrl(qrl);
|
|
4153
|
-
set(1);
|
|
4154
|
-
const host = iCtx.$hostElement$;
|
|
4155
|
-
const task = new Task(TaskFlags.DIRTY | TaskFlags.TASK, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
4156
|
-
// In V2 we add the task to the sequential scope. We need to do this
|
|
4157
|
-
// in order to be able to retrieve it later when the parent element is
|
|
4158
|
-
// deleted and we need to be able to release the task subscriptions.
|
|
4159
|
-
set(task);
|
|
4160
|
-
const result = runTask(task, iCtx.$container$, host);
|
|
4161
|
-
if (isPromise(result)) {
|
|
4162
|
-
throw result;
|
|
4163
|
-
}
|
|
4164
|
-
qrl.$resolveLazy$(iCtx.$element$);
|
|
4165
|
-
if (isServerPlatform()) {
|
|
4166
|
-
useRunTask(task, opts?.eagerness);
|
|
4167
|
-
}
|
|
4168
|
-
};
|
|
4169
|
-
const runTask = (task, container, host) => {
|
|
4170
|
-
task.$flags$ &= ~TaskFlags.DIRTY;
|
|
4171
|
-
cleanupTask(task);
|
|
4172
|
-
const iCtx = newInvokeContext(container.$locale$, host, undefined, TaskEvent);
|
|
4173
|
-
iCtx.$container$ = container;
|
|
4174
|
-
const taskFn = task.$qrl$.getFn(iCtx, () => clearSubscriberEffectDependencies(container, task));
|
|
4175
|
-
const track = (obj, prop) => {
|
|
4176
|
-
const ctx = newInvokeContext();
|
|
4177
|
-
ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT];
|
|
4178
|
-
ctx.$container$ = container;
|
|
4179
|
-
return invoke(ctx, () => {
|
|
4180
|
-
if (isFunction(obj)) {
|
|
4181
|
-
return obj();
|
|
4182
|
-
}
|
|
4183
|
-
if (prop) {
|
|
4184
|
-
return obj[prop];
|
|
4185
|
-
}
|
|
4186
|
-
else if (isSignal(obj)) {
|
|
4187
|
-
return obj.value;
|
|
4188
|
-
}
|
|
4189
|
-
else {
|
|
4190
|
-
return obj;
|
|
4191
|
-
}
|
|
4192
|
-
});
|
|
4193
|
-
};
|
|
4194
|
-
const handleError = (reason) => container.handleError(reason, host);
|
|
4195
|
-
let cleanupFns = null;
|
|
4196
|
-
const cleanup = (fn) => {
|
|
4197
|
-
if (typeof fn == 'function') {
|
|
4198
|
-
if (!cleanupFns) {
|
|
4199
|
-
cleanupFns = [];
|
|
4200
|
-
task.$destroy$ = noSerialize(() => {
|
|
4201
|
-
task.$destroy$ = null;
|
|
4202
|
-
cleanupFns.forEach((fn) => {
|
|
4203
|
-
try {
|
|
4204
|
-
fn();
|
|
4205
|
-
}
|
|
4206
|
-
catch (err) {
|
|
4207
|
-
handleError(err);
|
|
4208
|
-
}
|
|
4209
|
-
});
|
|
4210
|
-
});
|
|
4211
|
-
}
|
|
4212
|
-
cleanupFns.push(fn);
|
|
4213
|
-
}
|
|
4214
|
-
};
|
|
4215
|
-
const taskApi = { track, cleanup };
|
|
4216
|
-
const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
4217
|
-
if (isPromise(err)) {
|
|
4218
|
-
return err.then(() => runTask(task, container, host));
|
|
4219
|
-
}
|
|
4220
|
-
else {
|
|
4221
|
-
return handleError(err);
|
|
4353
|
+
if (idxDiff !== 0) {
|
|
4354
|
+
return idxDiff;
|
|
4222
4355
|
}
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
const destroy = task.$destroy$;
|
|
4228
|
-
if (destroy) {
|
|
4229
|
-
task.$destroy$ = null;
|
|
4230
|
-
try {
|
|
4231
|
-
destroy();
|
|
4356
|
+
// If the host is the same (or missing), and the type is the same, we need to compare the target.
|
|
4357
|
+
if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
|
|
4358
|
+
// 1 means that we are going to process chores as FIFO
|
|
4359
|
+
return 1;
|
|
4232
4360
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4361
|
+
// If the chore is the same as the current chore, we will run it again
|
|
4362
|
+
if (b === currentChore) {
|
|
4363
|
+
return 1;
|
|
4235
4364
|
}
|
|
4365
|
+
// The chores are the same and will run only once
|
|
4366
|
+
return 0;
|
|
4236
4367
|
}
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4368
|
+
function sortedFindIndex(sortedArray, value, rootVNode) {
|
|
4369
|
+
/// We need to ensure that the `queue` is sorted by priority.
|
|
4370
|
+
/// 1. Find a place where to insert into.
|
|
4371
|
+
let bottom = 0;
|
|
4372
|
+
let top = sortedArray.length;
|
|
4373
|
+
while (bottom < top) {
|
|
4374
|
+
const middle = bottom + ((top - bottom) >> 1);
|
|
4375
|
+
const midChore = sortedArray[middle];
|
|
4376
|
+
const comp = choreComparator(value, midChore, rootVNode);
|
|
4377
|
+
if (comp < 0) {
|
|
4378
|
+
top = middle;
|
|
4379
|
+
}
|
|
4380
|
+
else if (comp > 0) {
|
|
4381
|
+
bottom = middle + 1;
|
|
4382
|
+
}
|
|
4383
|
+
else {
|
|
4384
|
+
// We already have the host in the queue.
|
|
4385
|
+
return middle;
|
|
4386
|
+
}
|
|
4387
|
+
}
|
|
4388
|
+
return ~bottom;
|
|
4244
4389
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4390
|
+
function sortedInsert(sortedArray, value, rootVNode) {
|
|
4391
|
+
/// We need to ensure that the `queue` is sorted by priority.
|
|
4392
|
+
/// 1. Find a place where to insert into.
|
|
4393
|
+
const idx = sortedFindIndex(sortedArray, value, rootVNode);
|
|
4394
|
+
if (idx < 0) {
|
|
4395
|
+
/// 2. Insert the chore into the queue.
|
|
4396
|
+
sortedArray.splice(~idx, 0, value);
|
|
4397
|
+
return value;
|
|
4398
|
+
}
|
|
4399
|
+
const existing = sortedArray[idx];
|
|
4400
|
+
/**
|
|
4401
|
+
* When a derived signal is updated we need to run vnode_diff. However the signal can update
|
|
4402
|
+
* multiple times during component execution. For this reason it is necessary for us to update
|
|
4403
|
+
* the chore with the latest result of the signal.
|
|
4404
|
+
*/
|
|
4405
|
+
if (existing.$type$ === ChoreType.NODE_DIFF) {
|
|
4406
|
+
existing.$payload$ = value.$payload$;
|
|
4407
|
+
}
|
|
4408
|
+
if (existing.$executed$) {
|
|
4409
|
+
existing.$executed$ = false;
|
|
4410
|
+
}
|
|
4411
|
+
return existing;
|
|
4247
4412
|
}
|
|
4248
4413
|
};
|
|
4249
|
-
const
|
|
4250
|
-
|
|
4251
|
-
const taskHandler = createQRL(taskQrl.$chunk$, '_hW', _hW, null, null, [task], taskQrl.$symbol$);
|
|
4252
|
-
// Needed for chunk lookup in dev mode
|
|
4253
|
-
if (taskQrl.dev) {
|
|
4254
|
-
taskHandler.dev = taskQrl.dev;
|
|
4255
|
-
}
|
|
4256
|
-
return taskHandler;
|
|
4414
|
+
const toNumber = (value) => {
|
|
4415
|
+
return typeof value === 'number' ? value : -1;
|
|
4257
4416
|
};
|
|
4258
|
-
|
|
4259
|
-
$
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4417
|
+
function vNodeAlreadyDeleted(chore) {
|
|
4418
|
+
return !!(chore.$host$ &&
|
|
4419
|
+
vnode_isVNode(chore.$host$) &&
|
|
4420
|
+
chore.$host$[VNodeProps.flags] & VNodeFlags.Deleted);
|
|
4421
|
+
}
|
|
4422
|
+
function debugChoreTypeToString(type) {
|
|
4423
|
+
return ({
|
|
4424
|
+
[ChoreType.QRL_RESOLVE]: 'QRL_RESOLVE',
|
|
4425
|
+
[ChoreType.RUN_QRL]: 'RUN_QRL',
|
|
4426
|
+
[ChoreType.TASK]: 'TASK',
|
|
4427
|
+
[ChoreType.NODE_DIFF]: 'NODE_DIFF',
|
|
4428
|
+
[ChoreType.NODE_PROP]: 'NODE_PROP',
|
|
4429
|
+
[ChoreType.COMPONENT]: 'COMPONENT',
|
|
4430
|
+
[ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS]: 'RECOMPUTE_SIGNAL',
|
|
4431
|
+
[ChoreType.JOURNAL_FLUSH]: 'JOURNAL_FLUSH',
|
|
4432
|
+
[ChoreType.VISIBLE]: 'VISIBLE',
|
|
4433
|
+
[ChoreType.CLEANUP_VISIBLE]: 'CLEANUP_VISIBLE',
|
|
4434
|
+
[ChoreType.WAIT_FOR_ALL]: 'WAIT_FOR_ALL',
|
|
4435
|
+
}[type] || 'UNKNOWN: ' + type);
|
|
4436
|
+
}
|
|
4437
|
+
function debugChoreToString(chore) {
|
|
4438
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
4439
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
4440
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
4441
|
+
return `Chore(${type} ${chore.$type$ === ChoreType.QRL_RESOLVE || chore.$type$ === ChoreType.RUN_QRL ? qrlTarget : host} ${chore.$idx$})`;
|
|
4442
|
+
}
|
|
4443
|
+
function debugTrace(action, arg, currentChore, queue) {
|
|
4444
|
+
const lines = ['===========================\nScheduler: ' + action];
|
|
4445
|
+
if (arg && !('$type$' in arg)) {
|
|
4446
|
+
lines.push(' arg: ' + String(arg).replaceAll(/\n.*/gim, ''));
|
|
4447
|
+
}
|
|
4448
|
+
if (queue) {
|
|
4449
|
+
queue.forEach((chore) => {
|
|
4450
|
+
const active = chore === arg ? '>>>' : ' ';
|
|
4451
|
+
lines.push(` ${active} > ` +
|
|
4452
|
+
(chore === currentChore ? '[running] ' : '') +
|
|
4453
|
+
debugChoreToString(chore));
|
|
4454
|
+
});
|
|
4273
4455
|
}
|
|
4456
|
+
// eslint-disable-next-line no-console
|
|
4457
|
+
console.log(lines.join('\n') + '\n');
|
|
4274
4458
|
}
|
|
4275
|
-
const isTask = (value) => {
|
|
4276
|
-
return value instanceof Task;
|
|
4277
|
-
};
|
|
4278
|
-
/**
|
|
4279
|
-
* Low-level API used by the Optimizer to process `useTask$()` API. This method is not intended to
|
|
4280
|
-
* be used by developers.
|
|
4281
|
-
*
|
|
4282
|
-
* @internal
|
|
4283
|
-
*/
|
|
4284
|
-
const _hW = () => {
|
|
4285
|
-
const [task] = useLexicalScope();
|
|
4286
|
-
const container = getDomContainer(task.$el$);
|
|
4287
|
-
const type = task.$flags$ & TaskFlags.VISIBLE_TASK ? ChoreType.VISIBLE : ChoreType.TASK;
|
|
4288
|
-
container.$scheduler$(type, task);
|
|
4289
|
-
};
|
|
4290
|
-
|
|
4291
|
-
/**
|
|
4292
|
-
* Special value used to mark that a given signal needs to be computed. This is essentially a
|
|
4293
|
-
* "marked as dirty" flag.
|
|
4294
|
-
*/
|
|
4295
|
-
const NEEDS_COMPUTATION = Symbol('invalid');
|
|
4296
4459
|
|
|
4297
4460
|
/**
|
|
4298
4461
|
* @file
|
|
@@ -4326,18 +4489,19 @@
|
|
|
4326
4489
|
return value instanceof Signal;
|
|
4327
4490
|
};
|
|
4328
4491
|
/** @internal */
|
|
4329
|
-
class
|
|
4492
|
+
class SubscriptionData {
|
|
4330
4493
|
data;
|
|
4331
4494
|
constructor(data) {
|
|
4332
4495
|
this.data = data;
|
|
4333
4496
|
}
|
|
4334
4497
|
}
|
|
4335
|
-
var
|
|
4336
|
-
(function (
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4498
|
+
var EffectSubscriptionProp;
|
|
4499
|
+
(function (EffectSubscriptionProp) {
|
|
4500
|
+
EffectSubscriptionProp[EffectSubscriptionProp["CONSUMER"] = 0] = "CONSUMER";
|
|
4501
|
+
EffectSubscriptionProp[EffectSubscriptionProp["PROPERTY"] = 1] = "PROPERTY";
|
|
4502
|
+
EffectSubscriptionProp[EffectSubscriptionProp["BACK_REF"] = 2] = "BACK_REF";
|
|
4503
|
+
EffectSubscriptionProp[EffectSubscriptionProp["DATA"] = 3] = "DATA";
|
|
4504
|
+
})(EffectSubscriptionProp || (EffectSubscriptionProp = {}));
|
|
4341
4505
|
var EffectProperty;
|
|
4342
4506
|
(function (EffectProperty) {
|
|
4343
4507
|
EffectProperty["COMPONENT"] = ":";
|
|
@@ -4374,19 +4538,16 @@
|
|
|
4374
4538
|
}
|
|
4375
4539
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
4376
4540
|
if (effectSubscriber) {
|
|
4377
|
-
const effects = (this.$effects$ ||=
|
|
4541
|
+
const effects = (this.$effects$ ||= new Set());
|
|
4378
4542
|
// Let's make sure that we have a reference to this effect.
|
|
4379
4543
|
// Adding reference is essentially adding a subscription, so if the signal
|
|
4380
4544
|
// changes we know who to notify.
|
|
4381
|
-
|
|
4545
|
+
ensureContainsSubscription(effects, effectSubscriber);
|
|
4382
4546
|
// But when effect is scheduled in needs to be able to know which signals
|
|
4383
4547
|
// to unsubscribe from. So we need to store the reference from the effect back
|
|
4384
4548
|
// to this signal.
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
// We need to add the subscriber to the effect so that we can clean it up later
|
|
4388
|
-
ensureEffectContainsSubscriber(effectSubscriber[EffectSubscriptionsProp.EFFECT], this, this.$container$);
|
|
4389
|
-
}
|
|
4549
|
+
ensureContainsBackRef(effectSubscriber, this);
|
|
4550
|
+
addQrlToSerializationCtx(effectSubscriber, this.$container$);
|
|
4390
4551
|
}
|
|
4391
4552
|
}
|
|
4392
4553
|
return this.untrackedValue;
|
|
@@ -4405,122 +4566,97 @@
|
|
|
4405
4566
|
}
|
|
4406
4567
|
toString() {
|
|
4407
4568
|
return (`[${this.constructor.name}${this.$invalid$ ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
|
|
4408
|
-
(this.$effects
|
|
4569
|
+
(Array.from(this.$effects$ || [])
|
|
4570
|
+
.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' '))
|
|
4571
|
+
.join('\n') || ''));
|
|
4409
4572
|
}
|
|
4410
4573
|
toJSON() {
|
|
4411
4574
|
return { value: this.$untrackedValue$ };
|
|
4412
4575
|
}
|
|
4413
4576
|
}
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
const isMissing = array.indexOf(value) === -1;
|
|
4417
|
-
if (isMissing) {
|
|
4418
|
-
array.push(value);
|
|
4419
|
-
}
|
|
4420
|
-
};
|
|
4421
|
-
const ensureContainsEffect = (array, effectSubscriptions) => {
|
|
4422
|
-
for (let i = 0; i < array.length; i++) {
|
|
4423
|
-
const existingEffect = array[i];
|
|
4424
|
-
if (existingEffect[0] === effectSubscriptions[0] &&
|
|
4425
|
-
existingEffect[1] === effectSubscriptions[1]) {
|
|
4426
|
-
return;
|
|
4427
|
-
}
|
|
4428
|
-
}
|
|
4429
|
-
array.push(effectSubscriptions);
|
|
4577
|
+
const ensureContainsSubscription = (array, effectSubscription) => {
|
|
4578
|
+
array.add(effectSubscription);
|
|
4430
4579
|
};
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4580
|
+
/** Ensure the item is in back refs set */
|
|
4581
|
+
const ensureContainsBackRef = (array, value) => {
|
|
4582
|
+
array[EffectSubscriptionProp.BACK_REF] ||= new Set();
|
|
4583
|
+
array[EffectSubscriptionProp.BACK_REF].add(value);
|
|
4584
|
+
};
|
|
4585
|
+
const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
4586
|
+
if (!!container && !isDomContainer(container)) {
|
|
4587
|
+
const effect = effectSubscriber[EffectSubscriptionProp.CONSUMER];
|
|
4588
|
+
const property = effectSubscriber[EffectSubscriptionProp.PROPERTY];
|
|
4589
|
+
let qrl = null;
|
|
4590
|
+
if (isTask(effect)) {
|
|
4591
|
+
qrl = effect.$qrl$;
|
|
4436
4592
|
}
|
|
4437
|
-
effect
|
|
4438
|
-
|
|
4439
|
-
else if (vnode_isVNode(effect) && !vnode_isTextVNode(effect)) {
|
|
4440
|
-
let subscribers = vnode_getProp(effect, QSubscribers, container ? container.$getObjectById$ : null);
|
|
4441
|
-
subscribers ||= [];
|
|
4442
|
-
if (subscriberExistInSubscribers(subscribers, subscriber)) {
|
|
4443
|
-
return;
|
|
4593
|
+
else if (effect instanceof ComputedSignal) {
|
|
4594
|
+
qrl = effect.$computeQrl$;
|
|
4444
4595
|
}
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
}
|
|
4448
|
-
else if (isSSRNode(effect)) {
|
|
4449
|
-
let subscribers = effect.getProp(QSubscribers);
|
|
4450
|
-
subscribers ||= [];
|
|
4451
|
-
if (subscriberExistInSubscribers(subscribers, subscriber)) {
|
|
4452
|
-
return;
|
|
4596
|
+
else if (property === EffectProperty.COMPONENT) {
|
|
4597
|
+
qrl = container.getHostProp(effect, OnRenderProp);
|
|
4453
4598
|
}
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
}
|
|
4457
|
-
};
|
|
4458
|
-
const isSSRNode = (effect) => {
|
|
4459
|
-
return 'setProp' in effect && 'getProp' in effect && 'removeProp' in effect && 'id' in effect;
|
|
4460
|
-
};
|
|
4461
|
-
const subscriberExistInSubscribers = (subscribers, subscriber) => {
|
|
4462
|
-
for (let i = 0; i < subscribers.length; i++) {
|
|
4463
|
-
if (subscribers[i] === subscriber) {
|
|
4464
|
-
return true;
|
|
4599
|
+
if (qrl) {
|
|
4600
|
+
container.serializationCtx.$eventQrls$.add(qrl);
|
|
4465
4601
|
}
|
|
4466
4602
|
}
|
|
4467
|
-
return false;
|
|
4468
4603
|
};
|
|
4469
4604
|
const triggerEffects = (container, signal, effects) => {
|
|
4605
|
+
const isBrowser = isDomContainer(container);
|
|
4470
4606
|
if (effects) {
|
|
4471
|
-
const scheduleEffect = (
|
|
4472
|
-
const
|
|
4473
|
-
const property =
|
|
4607
|
+
const scheduleEffect = (effectSubscription) => {
|
|
4608
|
+
const consumer = effectSubscription[EffectSubscriptionProp.CONSUMER];
|
|
4609
|
+
const property = effectSubscription[EffectSubscriptionProp.PROPERTY];
|
|
4474
4610
|
assertDefined(container, 'Container must be defined.');
|
|
4475
|
-
if (isTask(
|
|
4476
|
-
|
|
4611
|
+
if (isTask(consumer)) {
|
|
4612
|
+
consumer.$flags$ |= TaskFlags.DIRTY;
|
|
4477
4613
|
let choreType = ChoreType.TASK;
|
|
4478
|
-
if (
|
|
4614
|
+
if (consumer.$flags$ & TaskFlags.VISIBLE_TASK) {
|
|
4479
4615
|
choreType = ChoreType.VISIBLE;
|
|
4480
4616
|
}
|
|
4481
|
-
|
|
4482
|
-
choreType = ChoreType.RESOURCE;
|
|
4483
|
-
}
|
|
4484
|
-
container.$scheduler$(choreType, effect);
|
|
4617
|
+
container.$scheduler$(choreType, consumer);
|
|
4485
4618
|
}
|
|
4486
|
-
else if (
|
|
4619
|
+
else if (consumer instanceof Signal) {
|
|
4487
4620
|
// we don't schedule ComputedSignal/DerivedSignal directly, instead we invalidate it and
|
|
4488
4621
|
// and schedule the signals effects (recursively)
|
|
4489
|
-
if (
|
|
4622
|
+
if (consumer instanceof ComputedSignal) {
|
|
4490
4623
|
// Ensure that the computed signal's QRL is resolved.
|
|
4491
4624
|
// If not resolved schedule it to be resolved.
|
|
4492
|
-
if (!
|
|
4493
|
-
container.$scheduler$(ChoreType.QRL_RESOLVE, null,
|
|
4625
|
+
if (!consumer.$computeQrl$.resolved) {
|
|
4626
|
+
container.$scheduler$(ChoreType.QRL_RESOLVE, null, consumer.$computeQrl$);
|
|
4494
4627
|
}
|
|
4495
4628
|
}
|
|
4496
|
-
|
|
4629
|
+
consumer.$invalidate$();
|
|
4497
4630
|
}
|
|
4498
4631
|
else if (property === EffectProperty.COMPONENT) {
|
|
4499
|
-
const host =
|
|
4632
|
+
const host = consumer;
|
|
4500
4633
|
const qrl = container.getHostProp(host, OnRenderProp);
|
|
4501
4634
|
assertDefined(qrl, 'Component must have QRL');
|
|
4502
4635
|
const props = container.getHostProp(host, ELEMENT_PROPS);
|
|
4503
4636
|
container.$scheduler$(ChoreType.COMPONENT, host, qrl, props);
|
|
4504
4637
|
}
|
|
4505
|
-
else if (
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4638
|
+
else if (isBrowser) {
|
|
4639
|
+
if (property === EffectProperty.VNODE) {
|
|
4640
|
+
const host = consumer;
|
|
4641
|
+
container.$scheduler$(ChoreType.NODE_DIFF, host, host, signal);
|
|
4642
|
+
}
|
|
4643
|
+
else {
|
|
4644
|
+
const host = consumer;
|
|
4645
|
+
const effectData = effectSubscription[EffectSubscriptionProp.DATA];
|
|
4646
|
+
if (effectData instanceof SubscriptionData) {
|
|
4647
|
+
const data = effectData.data;
|
|
4648
|
+
const payload = {
|
|
4649
|
+
...data,
|
|
4650
|
+
$value$: signal,
|
|
4651
|
+
};
|
|
4652
|
+
container.$scheduler$(ChoreType.NODE_PROP, host, property, payload);
|
|
4653
|
+
}
|
|
4520
4654
|
}
|
|
4521
4655
|
}
|
|
4522
4656
|
};
|
|
4523
|
-
effects
|
|
4657
|
+
for (const effect of effects) {
|
|
4658
|
+
scheduleEffect(effect);
|
|
4659
|
+
}
|
|
4524
4660
|
}
|
|
4525
4661
|
};
|
|
4526
4662
|
/**
|
|
@@ -4578,7 +4714,7 @@
|
|
|
4578
4714
|
throwIfQRLNotResolved(computeQrl);
|
|
4579
4715
|
const ctx = tryGetInvokeContext();
|
|
4580
4716
|
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
4581
|
-
ctx && (ctx.$effectSubscriber$ =
|
|
4717
|
+
ctx && (ctx.$effectSubscriber$ = getSubscriber(this, EffectProperty.VNODE));
|
|
4582
4718
|
try {
|
|
4583
4719
|
const untrackedValue = computeQrl.getFn(ctx)();
|
|
4584
4720
|
if (isPromise(untrackedValue)) {
|
|
@@ -4616,9 +4752,9 @@
|
|
|
4616
4752
|
// We need a separate flag to know when the computation needs running because
|
|
4617
4753
|
// we need the old value to know if effects need running after computation
|
|
4618
4754
|
$invalid$ = true;
|
|
4619
|
-
$effectDependencies$ = null;
|
|
4620
4755
|
$hostElement$ = null;
|
|
4621
4756
|
$forceRunEffects$ = false;
|
|
4757
|
+
[_EFFECT_BACK_REF] = null;
|
|
4622
4758
|
constructor(container, fn, args, fnStr) {
|
|
4623
4759
|
super(container, NEEDS_COMPUTATION);
|
|
4624
4760
|
this.$args$ = args;
|
|
@@ -4686,7 +4822,7 @@
|
|
|
4686
4822
|
if (jsx.key !== null) {
|
|
4687
4823
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
4688
4824
|
}
|
|
4689
|
-
return scheduler(ChoreType.
|
|
4825
|
+
return scheduler(ChoreType.COMPONENT, host, componentQrl, srcProps);
|
|
4690
4826
|
};
|
|
4691
4827
|
|
|
4692
4828
|
class ParentComponentData {
|
|
@@ -4698,21 +4834,10 @@
|
|
|
4698
4834
|
}
|
|
4699
4835
|
}
|
|
4700
4836
|
/** @internal */
|
|
4701
|
-
function _walkJSX(ssr, value, options) {
|
|
4837
|
+
async function _walkJSX(ssr, value, options) {
|
|
4702
4838
|
const stack = [value];
|
|
4703
|
-
let resolveDrain;
|
|
4704
|
-
let rejectDrain;
|
|
4705
|
-
const drained = options.allowPromises &&
|
|
4706
|
-
new Promise((res, rej) => {
|
|
4707
|
-
resolveDrain = res;
|
|
4708
|
-
rejectDrain = rej;
|
|
4709
|
-
});
|
|
4710
4839
|
const enqueue = (value) => stack.push(value);
|
|
4711
|
-
const
|
|
4712
|
-
stack.push(value);
|
|
4713
|
-
drain();
|
|
4714
|
-
};
|
|
4715
|
-
const drain = () => {
|
|
4840
|
+
const drain = async () => {
|
|
4716
4841
|
while (stack.length) {
|
|
4717
4842
|
const value = stack.pop();
|
|
4718
4843
|
if (value instanceof ParentComponentData) {
|
|
@@ -4722,20 +4847,10 @@
|
|
|
4722
4847
|
}
|
|
4723
4848
|
else if (typeof value === 'function') {
|
|
4724
4849
|
if (value === Promise) {
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
}
|
|
4728
|
-
stack.pop().then(resolveValue, rejectDrain);
|
|
4729
|
-
return;
|
|
4730
|
-
}
|
|
4731
|
-
const waitOn = value.apply(ssr);
|
|
4732
|
-
if (waitOn) {
|
|
4733
|
-
if (!options.allowPromises) {
|
|
4734
|
-
throw qError(QError.promisesNotExpected);
|
|
4735
|
-
}
|
|
4736
|
-
waitOn.then(drain, rejectDrain);
|
|
4737
|
-
return;
|
|
4850
|
+
stack.push(await stack.pop());
|
|
4851
|
+
continue;
|
|
4738
4852
|
}
|
|
4853
|
+
await value.apply(ssr);
|
|
4739
4854
|
continue;
|
|
4740
4855
|
}
|
|
4741
4856
|
processJSXNode(ssr, enqueue, value, {
|
|
@@ -4743,12 +4858,8 @@
|
|
|
4743
4858
|
parentComponentFrame: options.parentComponentFrame,
|
|
4744
4859
|
});
|
|
4745
4860
|
}
|
|
4746
|
-
if (stack.length === 0 && options.allowPromises) {
|
|
4747
|
-
resolveDrain();
|
|
4748
|
-
}
|
|
4749
4861
|
};
|
|
4750
|
-
drain();
|
|
4751
|
-
return drained;
|
|
4862
|
+
await drain();
|
|
4752
4863
|
}
|
|
4753
4864
|
function processJSXNode(ssr, enqueue, value, options) {
|
|
4754
4865
|
// console.log('processJSXNode', value);
|
|
@@ -4787,7 +4898,6 @@
|
|
|
4787
4898
|
enqueue(async () => {
|
|
4788
4899
|
for await (const chunk of value) {
|
|
4789
4900
|
await _walkJSX(ssr, chunk, {
|
|
4790
|
-
allowPromises: true,
|
|
4791
4901
|
currentStyleScoped: options.styleScoped,
|
|
4792
4902
|
parentComponentFrame: options.parentComponentFrame,
|
|
4793
4903
|
});
|
|
@@ -4874,7 +4984,6 @@
|
|
|
4874
4984
|
value = generator({
|
|
4875
4985
|
async write(chunk) {
|
|
4876
4986
|
await _walkJSX(ssr, chunk, {
|
|
4877
|
-
allowPromises: true,
|
|
4878
4987
|
currentStyleScoped: options.styleScoped,
|
|
4879
4988
|
parentComponentFrame: options.parentComponentFrame,
|
|
4880
4989
|
});
|
|
@@ -5031,11 +5140,23 @@
|
|
|
5031
5140
|
const appendToValue = (valueToAppend) => {
|
|
5032
5141
|
value = (value == null ? '' : value + '\n') + valueToAppend;
|
|
5033
5142
|
};
|
|
5143
|
+
const getQrlString = (qrl) => {
|
|
5144
|
+
/**
|
|
5145
|
+
* If there are captures we need to schedule so everything is executed in the right order + qrls
|
|
5146
|
+
* are resolved.
|
|
5147
|
+
*
|
|
5148
|
+
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
5149
|
+
*/
|
|
5150
|
+
if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
|
|
5151
|
+
qrl = createQRL(null, '_run', queueQRL, null, null, [qrl]);
|
|
5152
|
+
}
|
|
5153
|
+
return qrlToString(serializationCtx, qrl);
|
|
5154
|
+
};
|
|
5034
5155
|
if (Array.isArray(qrls)) {
|
|
5035
5156
|
for (let i = 0; i <= qrls.length; i++) {
|
|
5036
5157
|
const qrl = qrls[i];
|
|
5037
|
-
if (isQrl(qrl)) {
|
|
5038
|
-
appendToValue(
|
|
5158
|
+
if (isQrl$1(qrl)) {
|
|
5159
|
+
appendToValue(getQrlString(qrl));
|
|
5039
5160
|
addQwikEventToSerializationContext(serializationCtx, key, qrl);
|
|
5040
5161
|
}
|
|
5041
5162
|
else if (qrl != null) {
|
|
@@ -5047,8 +5168,8 @@
|
|
|
5047
5168
|
}
|
|
5048
5169
|
}
|
|
5049
5170
|
}
|
|
5050
|
-
else if (isQrl(qrls)) {
|
|
5051
|
-
value =
|
|
5171
|
+
else if (isQrl$1(qrls)) {
|
|
5172
|
+
value = getQrlString(qrls);
|
|
5052
5173
|
addQwikEventToSerializationContext(serializationCtx, key, qrls);
|
|
5053
5174
|
}
|
|
5054
5175
|
return value;
|
|
@@ -5098,7 +5219,7 @@
|
|
|
5098
5219
|
*
|
|
5099
5220
|
* @public
|
|
5100
5221
|
*/
|
|
5101
|
-
const version = "2.0.0-alpha.
|
|
5222
|
+
const version = "2.0.0-alpha.7-dev+a26598a";
|
|
5102
5223
|
|
|
5103
5224
|
/** @internal */
|
|
5104
5225
|
class _SharedContainer {
|
|
@@ -5130,13 +5251,6 @@
|
|
|
5130
5251
|
}
|
|
5131
5252
|
}
|
|
5132
5253
|
|
|
5133
|
-
/** @internal */
|
|
5134
|
-
const _CONST_PROPS = Symbol('CONST');
|
|
5135
|
-
/** @internal */
|
|
5136
|
-
const _VAR_PROPS = Symbol('VAR');
|
|
5137
|
-
/** @internal @deprecated v1 compat */
|
|
5138
|
-
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
5139
|
-
|
|
5140
5254
|
// Keep these properties named like this so they're the same as from wrapSignal
|
|
5141
5255
|
const getValueProp = (p0) => p0.value;
|
|
5142
5256
|
const getProp = (p0, p1) => p0[p1];
|
|
@@ -5548,7 +5662,7 @@
|
|
|
5548
5662
|
else if (isTask(value)) {
|
|
5549
5663
|
return `Task(${qwikDebugToString(value.$qrl$)})`;
|
|
5550
5664
|
}
|
|
5551
|
-
else if (isQrl
|
|
5665
|
+
else if (isQrl(value)) {
|
|
5552
5666
|
return `Qrl(${value.$symbol$})`;
|
|
5553
5667
|
}
|
|
5554
5668
|
else if (typeof value === 'object' || typeof value === 'function') {
|
|
@@ -5702,14 +5816,21 @@
|
|
|
5702
5816
|
CONTEXT_CHAR: /* **** */ ']',
|
|
5703
5817
|
SEQ_IDX: /* ************ */ 94, // `^` - `q:seqIdx' - Sequential scope id
|
|
5704
5818
|
SEQ_IDX_CHAR: /* **** */ '^',
|
|
5705
|
-
|
|
5706
|
-
|
|
5819
|
+
BACK_REFS: /* ********** */ 96, // '`' - `q:brefs' - Effect dependencies/subscriptions
|
|
5820
|
+
BACK_REFS_CHAR: /* ** */ '`',
|
|
5707
5821
|
SEPARATOR: /* ********* */ 124, // `|` - Separator char to encode any key/value pairs.
|
|
5708
5822
|
SEPARATOR_CHAR: /* ** */ '|',
|
|
5709
5823
|
SLOT: /* ************** */ 126, // `~` - `q:slot' - Slot name
|
|
5710
5824
|
SLOT_CHAR: /* ******* */ '~',
|
|
5711
5825
|
};
|
|
5712
5826
|
|
|
5827
|
+
const mergeMaps = (map1, map2) => {
|
|
5828
|
+
for (const [k, v] of map2) {
|
|
5829
|
+
map1.set(k, v);
|
|
5830
|
+
}
|
|
5831
|
+
return map1;
|
|
5832
|
+
};
|
|
5833
|
+
|
|
5713
5834
|
/**
|
|
5714
5835
|
* @file
|
|
5715
5836
|
*
|
|
@@ -5965,6 +6086,7 @@
|
|
|
5965
6086
|
elementVNode[VNodeProps.flags] ^= VNodeFlags.Inflated;
|
|
5966
6087
|
const element = elementVNode[ElementVNodeProps.element];
|
|
5967
6088
|
const attributes = element.attributes;
|
|
6089
|
+
const props = vnode_getProps(elementVNode);
|
|
5968
6090
|
for (let idx = 0; idx < attributes.length; idx++) {
|
|
5969
6091
|
const attr = attributes[idx];
|
|
5970
6092
|
const key = attr.name;
|
|
@@ -5975,15 +6097,15 @@
|
|
|
5975
6097
|
}
|
|
5976
6098
|
else if (key.startsWith(QContainerAttr)) {
|
|
5977
6099
|
if (attr.value === QContainerValue.HTML) {
|
|
5978
|
-
mapArray_set(
|
|
6100
|
+
mapArray_set(props, dangerouslySetInnerHTML, element.innerHTML, 0);
|
|
5979
6101
|
}
|
|
5980
6102
|
else if (attr.value === QContainerValue.TEXT && 'value' in element) {
|
|
5981
|
-
mapArray_set(
|
|
6103
|
+
mapArray_set(props, 'value', element.value, 0);
|
|
5982
6104
|
}
|
|
5983
6105
|
}
|
|
5984
6106
|
else if (!key.startsWith('on:')) {
|
|
5985
6107
|
const value = attr.value;
|
|
5986
|
-
mapArray_set(
|
|
6108
|
+
mapArray_set(props, key, value, 0);
|
|
5987
6109
|
}
|
|
5988
6110
|
}
|
|
5989
6111
|
}
|
|
@@ -6419,54 +6541,16 @@
|
|
|
6419
6541
|
journal.length = 0;
|
|
6420
6542
|
};
|
|
6421
6543
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
6422
|
-
const mapApp_findIndx = (elementVNode, key, start) => {
|
|
6423
|
-
assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
6424
|
-
let bottom = start >> 1;
|
|
6425
|
-
let top = (elementVNode.length - 2) >> 1;
|
|
6426
|
-
while (bottom <= top) {
|
|
6427
|
-
const mid = bottom + ((top - bottom) >> 1);
|
|
6428
|
-
const midKey = elementVNode[mid << 1];
|
|
6429
|
-
if (midKey === key) {
|
|
6430
|
-
return mid << 1;
|
|
6431
|
-
}
|
|
6432
|
-
if (midKey < key) {
|
|
6433
|
-
bottom = mid + 1;
|
|
6434
|
-
}
|
|
6435
|
-
else {
|
|
6436
|
-
top = mid - 1;
|
|
6437
|
-
}
|
|
6438
|
-
}
|
|
6439
|
-
return (bottom << 1) ^ -1;
|
|
6440
|
-
};
|
|
6441
|
-
const mapArray_set = (elementVNode, key, value, start) => {
|
|
6442
|
-
const indx = mapApp_findIndx(elementVNode, key, start);
|
|
6443
|
-
if (indx >= 0) {
|
|
6444
|
-
if (value == null) {
|
|
6445
|
-
elementVNode.splice(indx, 2);
|
|
6446
|
-
}
|
|
6447
|
-
else {
|
|
6448
|
-
elementVNode[indx + 1] = value;
|
|
6449
|
-
}
|
|
6450
|
-
}
|
|
6451
|
-
else if (value != null) {
|
|
6452
|
-
elementVNode.splice(indx ^ -1, 0, key, value);
|
|
6453
|
-
}
|
|
6454
|
-
};
|
|
6455
|
-
const mapArray_get = (elementVNode, key, start) => {
|
|
6456
|
-
const indx = mapApp_findIndx(elementVNode, key, start);
|
|
6457
|
-
if (indx >= 0) {
|
|
6458
|
-
return elementVNode[indx + 1];
|
|
6459
|
-
}
|
|
6460
|
-
else {
|
|
6461
|
-
return null;
|
|
6462
|
-
}
|
|
6463
|
-
};
|
|
6464
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
6465
6544
|
const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
6466
6545
|
ensureElementOrVirtualVNode(parent);
|
|
6467
6546
|
if (vnode_isElementVNode(parent)) {
|
|
6468
6547
|
ensureMaterialized(parent);
|
|
6469
6548
|
}
|
|
6549
|
+
if (newChild === insertBefore) {
|
|
6550
|
+
// invalid insertBefore. We can't insert before self reference
|
|
6551
|
+
// prevent infinity loop and putting self reference to next sibling
|
|
6552
|
+
insertBefore = null;
|
|
6553
|
+
}
|
|
6470
6554
|
let adjustedInsertBefore = null;
|
|
6471
6555
|
if (insertBefore == null) {
|
|
6472
6556
|
if (vnode_isVirtualVNode(parent)) {
|
|
@@ -6590,9 +6674,10 @@
|
|
|
6590
6674
|
const elementVNode = ensureElementVNode(vnode);
|
|
6591
6675
|
let elementName = elementVNode[ElementVNodeProps.elementName];
|
|
6592
6676
|
if (elementName === undefined) {
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
elementVNode[
|
|
6677
|
+
const element = elementVNode[ElementVNodeProps.element];
|
|
6678
|
+
const nodeName = build.isDev ? fastNodeName(element).toLowerCase() : fastNodeName(element);
|
|
6679
|
+
elementName = elementVNode[ElementVNodeProps.elementName] = nodeName;
|
|
6680
|
+
elementVNode[VNodeProps.flags] |= vnode_getElementNamespaceFlags(element);
|
|
6596
6681
|
}
|
|
6597
6682
|
return elementName;
|
|
6598
6683
|
};
|
|
@@ -6774,6 +6859,20 @@
|
|
|
6774
6859
|
}
|
|
6775
6860
|
return node;
|
|
6776
6861
|
};
|
|
6862
|
+
let _fastNamespaceURI = null;
|
|
6863
|
+
const fastNamespaceURI = (element) => {
|
|
6864
|
+
if (!_fastNamespaceURI) {
|
|
6865
|
+
_fastNamespaceURI = fastGetter(element, 'namespaceURI');
|
|
6866
|
+
}
|
|
6867
|
+
return _fastNamespaceURI.call(element);
|
|
6868
|
+
};
|
|
6869
|
+
let _fastNodeName = null;
|
|
6870
|
+
const fastNodeName = (element) => {
|
|
6871
|
+
if (!_fastNodeName) {
|
|
6872
|
+
_fastNodeName = fastGetter(element, 'nodeName');
|
|
6873
|
+
}
|
|
6874
|
+
return _fastNodeName.call(element);
|
|
6875
|
+
};
|
|
6777
6876
|
const fastGetter = (prototype, name) => {
|
|
6778
6877
|
let getter;
|
|
6779
6878
|
while (prototype && !(getter = Object.getOwnPropertyDescriptor(prototype, name)?.get)) {
|
|
@@ -6840,8 +6939,11 @@
|
|
|
6840
6939
|
container.$setRawState$(parseInt(id), vParent);
|
|
6841
6940
|
build.isDev && vnode_setAttr(null, vParent, ELEMENT_ID, id);
|
|
6842
6941
|
}
|
|
6843
|
-
else if (peek() === VNodeDataChar.
|
|
6844
|
-
|
|
6942
|
+
else if (peek() === VNodeDataChar.BACK_REFS) {
|
|
6943
|
+
if (!container) {
|
|
6944
|
+
container = getDomContainer(vParent[ElementVNodeProps.element]);
|
|
6945
|
+
}
|
|
6946
|
+
setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
|
|
6845
6947
|
}
|
|
6846
6948
|
else {
|
|
6847
6949
|
// prevent infinity loop if there are some characters outside the range
|
|
@@ -6851,6 +6953,18 @@
|
|
|
6851
6953
|
}
|
|
6852
6954
|
return vFirstChild;
|
|
6853
6955
|
};
|
|
6956
|
+
function setEffectBackRefFromVNodeData(vParent, value, container) {
|
|
6957
|
+
const deserializedSubMap = container.$getObjectById$(value);
|
|
6958
|
+
if (!vParent[_EFFECT_BACK_REF]) {
|
|
6959
|
+
Object.defineProperty(vParent, _EFFECT_BACK_REF, {
|
|
6960
|
+
value: deserializedSubMap,
|
|
6961
|
+
});
|
|
6962
|
+
}
|
|
6963
|
+
else {
|
|
6964
|
+
const subMap = vParent[_EFFECT_BACK_REF];
|
|
6965
|
+
mergeMaps(subMap, deserializedSubMap);
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6854
6968
|
const processVNodeData$1 = (vData, callback) => {
|
|
6855
6969
|
let nextToConsumeIdx = 0;
|
|
6856
6970
|
let ch = 0;
|
|
@@ -6895,8 +7009,9 @@
|
|
|
6895
7009
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6896
7010
|
vnode_ensureElementInflated(vnode);
|
|
6897
7011
|
const keys = [];
|
|
6898
|
-
|
|
6899
|
-
|
|
7012
|
+
const props = vnode_getProps(vnode);
|
|
7013
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
7014
|
+
const key = props[i];
|
|
6900
7015
|
if (!key.startsWith(Q_PROPS_SEPARATOR)) {
|
|
6901
7016
|
keys.push(key);
|
|
6902
7017
|
}
|
|
@@ -6909,22 +7024,23 @@
|
|
|
6909
7024
|
const type = vnode[VNodeProps.flags];
|
|
6910
7025
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6911
7026
|
vnode_ensureElementInflated(vnode);
|
|
6912
|
-
const
|
|
7027
|
+
const props = vnode_getProps(vnode);
|
|
7028
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6913
7029
|
if (idx >= 0) {
|
|
6914
|
-
if (
|
|
7030
|
+
if (props[idx + 1] != value && (type & VNodeFlags.Element) !== 0) {
|
|
6915
7031
|
// Values are different, update DOM
|
|
6916
7032
|
const element = vnode[ElementVNodeProps.element];
|
|
6917
7033
|
journal && journal.push(VNodeJournalOpCode.SetAttribute, element, key, value);
|
|
6918
7034
|
}
|
|
6919
7035
|
if (value == null) {
|
|
6920
|
-
|
|
7036
|
+
props.splice(idx, 2);
|
|
6921
7037
|
}
|
|
6922
7038
|
else {
|
|
6923
|
-
|
|
7039
|
+
props[idx + 1] = value;
|
|
6924
7040
|
}
|
|
6925
7041
|
}
|
|
6926
7042
|
else if (value != null) {
|
|
6927
|
-
|
|
7043
|
+
props.splice(idx ^ -1, 0, key, value);
|
|
6928
7044
|
if ((type & VNodeFlags.Element) !== 0) {
|
|
6929
7045
|
// New value, update DOM
|
|
6930
7046
|
const element = vnode[ElementVNodeProps.element];
|
|
@@ -6937,7 +7053,8 @@
|
|
|
6937
7053
|
const type = vnode[VNodeProps.flags];
|
|
6938
7054
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6939
7055
|
vnode_ensureElementInflated(vnode);
|
|
6940
|
-
|
|
7056
|
+
const props = vnode_getProps(vnode);
|
|
7057
|
+
return mapArray_get(props, key, 0);
|
|
6941
7058
|
}
|
|
6942
7059
|
return null;
|
|
6943
7060
|
};
|
|
@@ -6945,11 +7062,12 @@
|
|
|
6945
7062
|
const type = vnode[VNodeProps.flags];
|
|
6946
7063
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6947
7064
|
type & VNodeFlags.Element && vnode_ensureElementInflated(vnode);
|
|
6948
|
-
const
|
|
7065
|
+
const props = vnode_getProps(vnode);
|
|
7066
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6949
7067
|
if (idx >= 0) {
|
|
6950
|
-
let value =
|
|
7068
|
+
let value = props[idx + 1];
|
|
6951
7069
|
if (typeof value === 'string' && getObject) {
|
|
6952
|
-
|
|
7070
|
+
props[idx + 1] = value = getObject(value);
|
|
6953
7071
|
}
|
|
6954
7072
|
return value;
|
|
6955
7073
|
}
|
|
@@ -6958,12 +7076,13 @@
|
|
|
6958
7076
|
};
|
|
6959
7077
|
const vnode_setProp = (vnode, key, value) => {
|
|
6960
7078
|
ensureElementOrVirtualVNode(vnode);
|
|
6961
|
-
const
|
|
7079
|
+
const props = vnode_getProps(vnode);
|
|
7080
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6962
7081
|
if (idx >= 0) {
|
|
6963
|
-
|
|
7082
|
+
props[idx + 1] = value;
|
|
6964
7083
|
}
|
|
6965
7084
|
else if (value != null) {
|
|
6966
|
-
|
|
7085
|
+
props.splice(idx ^ -1, 0, key, value);
|
|
6967
7086
|
}
|
|
6968
7087
|
};
|
|
6969
7088
|
const vnode_getPropStartIndex = (vnode) => {
|
|
@@ -6976,6 +7095,9 @@
|
|
|
6976
7095
|
}
|
|
6977
7096
|
throw qError(QError.invalidVNodeType, [type]);
|
|
6978
7097
|
};
|
|
7098
|
+
const vnode_getProps = (vnode) => {
|
|
7099
|
+
return vnode[vnode_getPropStartIndex(vnode)];
|
|
7100
|
+
};
|
|
6979
7101
|
const vnode_getParent = (vnode) => {
|
|
6980
7102
|
return vnode[VNodeProps.parent] || null;
|
|
6981
7103
|
};
|
|
@@ -7139,8 +7261,11 @@
|
|
|
7139
7261
|
else if (peek() === VNodeDataChar.SEQ_IDX) {
|
|
7140
7262
|
vnode_setAttr(null, vParent, ELEMENT_SEQ_IDX, consumeValue());
|
|
7141
7263
|
}
|
|
7142
|
-
else if (peek() === VNodeDataChar.
|
|
7143
|
-
|
|
7264
|
+
else if (peek() === VNodeDataChar.BACK_REFS) {
|
|
7265
|
+
if (!container) {
|
|
7266
|
+
container = getDomContainer(element);
|
|
7267
|
+
}
|
|
7268
|
+
setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
|
|
7144
7269
|
}
|
|
7145
7270
|
else if (peek() === VNodeDataChar.CONTEXT) {
|
|
7146
7271
|
vnode_setAttr(null, vParent, QCtxAttr, consumeValue());
|
|
@@ -7248,23 +7373,20 @@
|
|
|
7248
7373
|
};
|
|
7249
7374
|
const VNodeArray = class VNode extends Array {
|
|
7250
7375
|
static createElement(flags, parent, previousSibling, nextSibling, firstChild, lastChild, element, elementName) {
|
|
7251
|
-
const vnode = new VNode(flags, parent, previousSibling, nextSibling);
|
|
7252
|
-
vnode.push(firstChild, lastChild, element, elementName);
|
|
7376
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, element, elementName, []);
|
|
7253
7377
|
return vnode;
|
|
7254
7378
|
}
|
|
7255
7379
|
static createText(flags, parent, previousSibling, nextSibling, textNode, text) {
|
|
7256
|
-
const vnode = new VNode(flags, parent, previousSibling, nextSibling);
|
|
7257
|
-
vnode.push(textNode, text);
|
|
7380
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, textNode, text);
|
|
7258
7381
|
return vnode;
|
|
7259
7382
|
}
|
|
7260
7383
|
static createVirtual(flags, parent, previousSibling, nextSibling, firstChild, lastChild) {
|
|
7261
|
-
const vnode = new VNode(flags, parent, previousSibling, nextSibling);
|
|
7262
|
-
vnode.push(firstChild, lastChild);
|
|
7384
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, []);
|
|
7263
7385
|
return vnode;
|
|
7264
7386
|
}
|
|
7265
|
-
constructor(flags, parent, previousSibling, nextSibling) {
|
|
7266
|
-
|
|
7267
|
-
|
|
7387
|
+
constructor(flags, parent, previousSibling, nextSibling, ...rest) {
|
|
7388
|
+
// @ts-expect-error
|
|
7389
|
+
super(flags, parent, previousSibling, nextSibling, ...rest);
|
|
7268
7390
|
if (build.isDev) {
|
|
7269
7391
|
this.toString = vnode_toString;
|
|
7270
7392
|
}
|
|
@@ -7329,10 +7451,12 @@
|
|
|
7329
7451
|
return returnValue;
|
|
7330
7452
|
}
|
|
7331
7453
|
const newInvokeContextFromTuple = ([element, event, url]) => {
|
|
7332
|
-
const
|
|
7454
|
+
const domContainer = getDomContainer(element);
|
|
7455
|
+
const container = domContainer.element;
|
|
7456
|
+
const vNode = container ? vnode_locate(domContainer.rootVNode, element) : undefined;
|
|
7333
7457
|
const locale = container?.getAttribute(QLocaleAttr) || undefined;
|
|
7334
7458
|
locale && setLocale(locale);
|
|
7335
|
-
return newInvokeContext(locale,
|
|
7459
|
+
return newInvokeContext(locale, vNode, element, event, url);
|
|
7336
7460
|
};
|
|
7337
7461
|
// TODO how about putting url and locale (and event/custom?) in to a "static" object
|
|
7338
7462
|
const newInvokeContext = (locale, hostElement, element, event, url) => {
|
|
@@ -7367,16 +7491,14 @@
|
|
|
7367
7491
|
* @param property `true` - subscriber is component `false` - subscriber is VNode `string` -
|
|
7368
7492
|
* subscriber is property
|
|
7369
7493
|
* @param container
|
|
7494
|
+
* @param data - Additional subscription data
|
|
7370
7495
|
* @returns
|
|
7371
7496
|
*/
|
|
7372
7497
|
const trackSignal = (fn, subscriber, property, container, data) => {
|
|
7373
7498
|
const previousSubscriber = trackInvocation.$effectSubscriber$;
|
|
7374
7499
|
const previousContainer = trackInvocation.$container$;
|
|
7375
7500
|
try {
|
|
7376
|
-
trackInvocation.$effectSubscriber$ =
|
|
7377
|
-
if (data) {
|
|
7378
|
-
trackInvocation.$effectSubscriber$.push(data);
|
|
7379
|
-
}
|
|
7501
|
+
trackInvocation.$effectSubscriber$ = getSubscriber(subscriber, property, data);
|
|
7380
7502
|
trackInvocation.$container$ = container;
|
|
7381
7503
|
return invoke(trackInvocation, fn);
|
|
7382
7504
|
}
|
|
@@ -7397,8 +7519,16 @@
|
|
|
7397
7519
|
if (iCtx) {
|
|
7398
7520
|
const hostElement = iCtx.$hostElement$;
|
|
7399
7521
|
let element = null;
|
|
7400
|
-
if (
|
|
7401
|
-
|
|
7522
|
+
if (hostElement != null) {
|
|
7523
|
+
if (vnode_isVNode(hostElement)) {
|
|
7524
|
+
if (vnode_isElementVNode(hostElement)) {
|
|
7525
|
+
element = vnode_getNode(hostElement);
|
|
7526
|
+
}
|
|
7527
|
+
}
|
|
7528
|
+
else {
|
|
7529
|
+
// isSSRnode
|
|
7530
|
+
element = hostElement;
|
|
7531
|
+
}
|
|
7402
7532
|
}
|
|
7403
7533
|
return element ?? iCtx.$qrl$?.$setContainer$(undefined);
|
|
7404
7534
|
}
|
|
@@ -8034,9 +8164,9 @@
|
|
|
8034
8164
|
$storeProxyMap$ = new WeakMap();
|
|
8035
8165
|
$qFuncs$;
|
|
8036
8166
|
$instanceHash$;
|
|
8037
|
-
|
|
8167
|
+
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
8168
|
+
$stateData$;
|
|
8038
8169
|
$styleIds$ = null;
|
|
8039
|
-
$vnodeLocate$ = (id) => vnode_locate(this.rootVNode, id);
|
|
8040
8170
|
$renderCount$ = 0;
|
|
8041
8171
|
constructor(element) {
|
|
8042
8172
|
super(() => this.scheduleRender(), () => vnode_applyJournal(this.$journal$), {}, element.getAttribute('q:locale'));
|
|
@@ -8062,29 +8192,29 @@
|
|
|
8062
8192
|
this.rootVNode = vnode_newUnMaterializedElement(this.element);
|
|
8063
8193
|
// These are here to initialize all properties at once for single class transition
|
|
8064
8194
|
this.$rawStateData$ = null;
|
|
8065
|
-
this
|
|
8195
|
+
this.$stateData$ = null;
|
|
8066
8196
|
const document = this.element.ownerDocument;
|
|
8067
8197
|
if (!document.qVNodeData) {
|
|
8068
8198
|
processVNodeData(document);
|
|
8069
8199
|
}
|
|
8070
8200
|
this.$rawStateData$ = [];
|
|
8071
|
-
this
|
|
8201
|
+
this.$stateData$ = [];
|
|
8072
8202
|
const qwikStates = element.querySelectorAll('script[type="qwik/state"]');
|
|
8073
8203
|
if (qwikStates.length !== 0) {
|
|
8074
8204
|
const lastState = qwikStates[qwikStates.length - 1];
|
|
8075
8205
|
this.$rawStateData$ = JSON.parse(lastState.textContent);
|
|
8076
|
-
this
|
|
8206
|
+
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
8077
8207
|
}
|
|
8078
8208
|
this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
|
|
8079
8209
|
}
|
|
8080
8210
|
$setRawState$(id, vParent) {
|
|
8081
|
-
this
|
|
8211
|
+
this.$stateData$[id] = vParent;
|
|
8082
8212
|
}
|
|
8083
8213
|
parseQRL(qrl) {
|
|
8084
8214
|
return inflateQRL(this, parseQRL(qrl));
|
|
8085
8215
|
}
|
|
8086
8216
|
handleError(err, host) {
|
|
8087
|
-
if (qDev) {
|
|
8217
|
+
if (qDev && host) {
|
|
8088
8218
|
// Clean vdom
|
|
8089
8219
|
if (typeof document !== 'undefined') {
|
|
8090
8220
|
const vHost = host;
|
|
@@ -8108,7 +8238,7 @@
|
|
|
8108
8238
|
throw err;
|
|
8109
8239
|
}
|
|
8110
8240
|
}
|
|
8111
|
-
const errorStore = this.resolveContext(host, ERROR_CONTEXT);
|
|
8241
|
+
const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
|
|
8112
8242
|
if (!errorStore) {
|
|
8113
8243
|
throw err;
|
|
8114
8244
|
}
|
|
@@ -8144,7 +8274,7 @@
|
|
|
8144
8274
|
vNode =
|
|
8145
8275
|
vnode_getParent(vNode) ||
|
|
8146
8276
|
// If virtual node, than it could be a slot so we need to read its parent.
|
|
8147
|
-
vnode_getProp(vNode, QSlotParent, this
|
|
8277
|
+
vnode_getProp(vNode, QSlotParent, this.vNodeLocate);
|
|
8148
8278
|
}
|
|
8149
8279
|
else {
|
|
8150
8280
|
vNode = vnode_getParent(vNode);
|
|
@@ -8164,7 +8294,7 @@
|
|
|
8164
8294
|
case ELEMENT_PROPS:
|
|
8165
8295
|
case OnRenderProp:
|
|
8166
8296
|
case QCtxAttr:
|
|
8167
|
-
case
|
|
8297
|
+
case QBackRefs:
|
|
8168
8298
|
getObjectById = this.$getObjectById$;
|
|
8169
8299
|
break;
|
|
8170
8300
|
case ELEMENT_SEQ_IDX:
|
|
@@ -8177,7 +8307,7 @@
|
|
|
8177
8307
|
scheduleRender() {
|
|
8178
8308
|
this.$renderCount$++;
|
|
8179
8309
|
this.renderDone ||= getPlatform().nextTick(() => this.processChores());
|
|
8180
|
-
return this.renderDone;
|
|
8310
|
+
return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
|
|
8181
8311
|
}
|
|
8182
8312
|
processChores() {
|
|
8183
8313
|
let renderCount = this.$renderCount$;
|
|
@@ -8200,12 +8330,13 @@
|
|
|
8200
8330
|
ensureProjectionResolved(vNode) {
|
|
8201
8331
|
if ((vNode[VNodeProps.flags] & VNodeFlags.Resolved) === 0) {
|
|
8202
8332
|
vNode[VNodeProps.flags] |= VNodeFlags.Resolved;
|
|
8203
|
-
|
|
8204
|
-
|
|
8333
|
+
const props = vnode_getProps(vNode);
|
|
8334
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
8335
|
+
const prop = props[i];
|
|
8205
8336
|
if (isSlotProp(prop)) {
|
|
8206
|
-
const value =
|
|
8337
|
+
const value = props[i + 1];
|
|
8207
8338
|
if (typeof value == 'string') {
|
|
8208
|
-
|
|
8339
|
+
props[i + 1] = this.vNodeLocate(value);
|
|
8209
8340
|
}
|
|
8210
8341
|
}
|
|
8211
8342
|
}
|
|
@@ -8216,7 +8347,7 @@
|
|
|
8216
8347
|
id = parseFloat(id);
|
|
8217
8348
|
}
|
|
8218
8349
|
assertTrue(id < this.$rawStateData$.length / 2, `Invalid reference: ${id} >= ${this.$rawStateData$.length / 2}`);
|
|
8219
|
-
return this
|
|
8350
|
+
return this.$stateData$[id];
|
|
8220
8351
|
};
|
|
8221
8352
|
getSyncFn(id) {
|
|
8222
8353
|
const fn = this.$qFuncs$[id];
|
|
@@ -8288,8 +8419,7 @@
|
|
|
8288
8419
|
? parseInt(property, 10)
|
|
8289
8420
|
: NaN;
|
|
8290
8421
|
if (Number.isNaN(i) || i < 0 || i >= this.$length$) {
|
|
8291
|
-
|
|
8292
|
-
return out;
|
|
8422
|
+
return Reflect.get(target, property, receiver);
|
|
8293
8423
|
}
|
|
8294
8424
|
// The serialized data is an array with 2 values for each item
|
|
8295
8425
|
const idx = i * 2;
|
|
@@ -8355,6 +8485,7 @@
|
|
|
8355
8485
|
switch (typeId) {
|
|
8356
8486
|
case TypeIds.Object:
|
|
8357
8487
|
// We use getters for making complex values lazy
|
|
8488
|
+
// TODO scan the data for computeQRLs and schedule resolve chores
|
|
8358
8489
|
for (let i = 0; i < data.length; i += 4) {
|
|
8359
8490
|
const key = deserializeData(container, data[i], data[i + 1]);
|
|
8360
8491
|
const valType = data[i + 2];
|
|
@@ -8394,7 +8525,7 @@
|
|
|
8394
8525
|
task.$flags$ = v[1];
|
|
8395
8526
|
task.$index$ = v[2];
|
|
8396
8527
|
task.$el$ = v[3];
|
|
8397
|
-
task
|
|
8528
|
+
task[_EFFECT_BACK_REF] = v[4];
|
|
8398
8529
|
task.$state$ = v[5];
|
|
8399
8530
|
break;
|
|
8400
8531
|
case TypeIds.Resource:
|
|
@@ -8417,12 +8548,9 @@
|
|
|
8417
8548
|
break;
|
|
8418
8549
|
case TypeIds.Store:
|
|
8419
8550
|
case TypeIds.StoreArray: {
|
|
8420
|
-
const [value, flags, effects
|
|
8551
|
+
const [value, flags, effects] = data;
|
|
8421
8552
|
const store = getOrCreateStore(value, flags, container);
|
|
8422
8553
|
const storeHandler = getStoreHandler(store);
|
|
8423
|
-
if (storeEffect) {
|
|
8424
|
-
effects[STORE_ARRAY_PROP] = storeEffect;
|
|
8425
|
-
}
|
|
8426
8554
|
storeHandler.$effects$ = effects;
|
|
8427
8555
|
target = store;
|
|
8428
8556
|
break;
|
|
@@ -8431,7 +8559,7 @@
|
|
|
8431
8559
|
const signal = target;
|
|
8432
8560
|
const d = data;
|
|
8433
8561
|
signal.$untrackedValue$ = d[0];
|
|
8434
|
-
signal.$effects$ = d.slice(1);
|
|
8562
|
+
signal.$effects$ = new Set(d.slice(1));
|
|
8435
8563
|
break;
|
|
8436
8564
|
}
|
|
8437
8565
|
case TypeIds.WrappedSignal: {
|
|
@@ -8439,10 +8567,10 @@
|
|
|
8439
8567
|
const d = data;
|
|
8440
8568
|
signal.$func$ = container.getSyncFn(d[0]);
|
|
8441
8569
|
signal.$args$ = d[1];
|
|
8442
|
-
signal
|
|
8570
|
+
signal[_EFFECT_BACK_REF] = d[2];
|
|
8443
8571
|
signal.$untrackedValue$ = d[3];
|
|
8444
8572
|
signal.$hostElement$ = d[4];
|
|
8445
|
-
signal.$effects$ = d.slice(5);
|
|
8573
|
+
signal.$effects$ = new Set(d.slice(5));
|
|
8446
8574
|
break;
|
|
8447
8575
|
}
|
|
8448
8576
|
case TypeIds.ComputedSignal: {
|
|
@@ -8562,6 +8690,7 @@
|
|
|
8562
8690
|
EMPTY_ARRAY,
|
|
8563
8691
|
EMPTY_OBJ,
|
|
8564
8692
|
NEEDS_COMPUTATION,
|
|
8693
|
+
STORE_ARRAY_PROP,
|
|
8565
8694
|
Slot,
|
|
8566
8695
|
Fragment,
|
|
8567
8696
|
NaN,
|
|
@@ -8642,6 +8771,8 @@
|
|
|
8642
8771
|
reject = rej;
|
|
8643
8772
|
});
|
|
8644
8773
|
resolvers.set(promise, [resolve, reject]);
|
|
8774
|
+
// Don't leave unhandled promise rejections
|
|
8775
|
+
promise.catch(() => { });
|
|
8645
8776
|
return promise;
|
|
8646
8777
|
case TypeIds.Uint8Array:
|
|
8647
8778
|
const encodedLength = value.length;
|
|
@@ -8651,12 +8782,9 @@
|
|
|
8651
8782
|
return new Uint8Array(decodedLength);
|
|
8652
8783
|
case TypeIds.PropsProxy:
|
|
8653
8784
|
return createPropsProxy(null, null);
|
|
8654
|
-
case TypeIds.RefVNode:
|
|
8655
8785
|
case TypeIds.VNode:
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
return vnodeOrDocument;
|
|
8659
|
-
}
|
|
8786
|
+
return retrieveVNodeOrDocument(container, value);
|
|
8787
|
+
case TypeIds.RefVNode:
|
|
8660
8788
|
const vNode = retrieveVNodeOrDocument(container, value);
|
|
8661
8789
|
if (vnode_isVNode(vNode)) {
|
|
8662
8790
|
return vnode_getNode(vNode);
|
|
@@ -8665,7 +8793,7 @@
|
|
|
8665
8793
|
throw qError(QError.serializeErrorExpectedVNode, [typeof vNode]);
|
|
8666
8794
|
}
|
|
8667
8795
|
case TypeIds.EffectData:
|
|
8668
|
-
return new
|
|
8796
|
+
return new SubscriptionData({});
|
|
8669
8797
|
default:
|
|
8670
8798
|
throw qError(QError.serializeErrorCannotAllocate, [typeId]);
|
|
8671
8799
|
}
|
|
@@ -8697,7 +8825,7 @@
|
|
|
8697
8825
|
assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
8698
8826
|
qrlRef = backChannel.get(symbol);
|
|
8699
8827
|
}
|
|
8700
|
-
return createQRL(chunk, symbol, qrlRef, null, captureIds, null
|
|
8828
|
+
return createQRL(chunk, symbol, qrlRef, null, captureIds, null);
|
|
8701
8829
|
}
|
|
8702
8830
|
function inflateQRL(container, qrl) {
|
|
8703
8831
|
const captureIds = qrl.$capture$;
|
|
@@ -8815,7 +8943,7 @@
|
|
|
8815
8943
|
/** Visit an object, adding anything that will be serialized as to scan */
|
|
8816
8944
|
const visit = (obj) => {
|
|
8817
8945
|
if (typeof obj === 'function') {
|
|
8818
|
-
if (isQrl(obj)) {
|
|
8946
|
+
if (isQrl$1(obj)) {
|
|
8819
8947
|
if (obj.$captureRef$) {
|
|
8820
8948
|
discoveredValues.push(...obj.$captureRef$);
|
|
8821
8949
|
}
|
|
@@ -8834,6 +8962,7 @@
|
|
|
8834
8962
|
obj instanceof RegExp ||
|
|
8835
8963
|
obj instanceof Uint8Array ||
|
|
8836
8964
|
obj instanceof URLSearchParams ||
|
|
8965
|
+
vnode_isVNode(obj) ||
|
|
8837
8966
|
(typeof FormData !== 'undefined' && obj instanceof FormData) ||
|
|
8838
8967
|
// Ignore the no serialize objects
|
|
8839
8968
|
fastSkipSerialize(obj)) ;
|
|
@@ -8843,8 +8972,7 @@
|
|
|
8843
8972
|
else if (isStore(obj)) {
|
|
8844
8973
|
const target = getStoreTarget(obj);
|
|
8845
8974
|
const effects = getStoreHandler(obj).$effects$;
|
|
8846
|
-
|
|
8847
|
-
discoveredValues.push(target, effects, storeEffect);
|
|
8975
|
+
discoveredValues.push(target, effects);
|
|
8848
8976
|
for (const prop in target) {
|
|
8849
8977
|
const propValue = target[prop];
|
|
8850
8978
|
if (storeProxyMap.has(propValue)) {
|
|
@@ -8878,9 +9006,7 @@
|
|
|
8878
9006
|
}
|
|
8879
9007
|
// WrappedSignal uses syncQrl which has no captured refs
|
|
8880
9008
|
if (obj instanceof WrappedSignal) {
|
|
8881
|
-
|
|
8882
|
-
discoveredValues.push(...obj.$effectDependencies$);
|
|
8883
|
-
}
|
|
9009
|
+
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
|
|
8884
9010
|
if (obj.$args$) {
|
|
8885
9011
|
discoveredValues.push(...obj.$args$);
|
|
8886
9012
|
}
|
|
@@ -8893,7 +9019,8 @@
|
|
|
8893
9019
|
}
|
|
8894
9020
|
}
|
|
8895
9021
|
else if (obj instanceof Task) {
|
|
8896
|
-
discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state
|
|
9022
|
+
discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state$);
|
|
9023
|
+
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
|
|
8897
9024
|
}
|
|
8898
9025
|
else if (isSsrNode(obj)) {
|
|
8899
9026
|
discoverValuesForVNodeData(obj.vnodeData, discoveredValues);
|
|
@@ -8912,7 +9039,7 @@
|
|
|
8912
9039
|
else if (Array.isArray(obj)) {
|
|
8913
9040
|
discoveredValues.push(...obj);
|
|
8914
9041
|
}
|
|
8915
|
-
else if (isQrl(obj)) {
|
|
9042
|
+
else if (isQrl$1(obj)) {
|
|
8916
9043
|
obj.$captureRef$ && obj.$captureRef$.length && discoveredValues.push(...obj.$captureRef$);
|
|
8917
9044
|
}
|
|
8918
9045
|
else if (isPropsProxy(obj)) {
|
|
@@ -8928,7 +9055,7 @@
|
|
|
8928
9055
|
});
|
|
8929
9056
|
promises.push(obj);
|
|
8930
9057
|
}
|
|
8931
|
-
else if (obj instanceof
|
|
9058
|
+
else if (obj instanceof SubscriptionData) {
|
|
8932
9059
|
discoveredValues.push(obj.data);
|
|
8933
9060
|
}
|
|
8934
9061
|
else if (isObjectLiteral(obj)) {
|
|
@@ -8973,15 +9100,31 @@
|
|
|
8973
9100
|
for (const value of vnodeData) {
|
|
8974
9101
|
if (isSsrAttrs(value)) {
|
|
8975
9102
|
for (let i = 1; i < value.length; i += 2) {
|
|
8976
|
-
|
|
9103
|
+
const attrValue = value[i];
|
|
9104
|
+
if (typeof attrValue === 'string') {
|
|
8977
9105
|
continue;
|
|
8978
9106
|
}
|
|
8979
|
-
const attrValue = value[i];
|
|
8980
9107
|
discoveredValues.push(attrValue);
|
|
8981
9108
|
}
|
|
8982
9109
|
}
|
|
8983
9110
|
}
|
|
8984
9111
|
};
|
|
9112
|
+
const discoverEffectBackRefs = (effectsBackRefs, discoveredValues) => {
|
|
9113
|
+
if (effectsBackRefs) {
|
|
9114
|
+
// We need serialize effect subscriptions with back refs
|
|
9115
|
+
let hasBackRefs = false;
|
|
9116
|
+
for (const [, effect] of effectsBackRefs) {
|
|
9117
|
+
const backRefs = effect[EffectSubscriptionProp.BACK_REF];
|
|
9118
|
+
if (backRefs) {
|
|
9119
|
+
hasBackRefs = true;
|
|
9120
|
+
break;
|
|
9121
|
+
}
|
|
9122
|
+
}
|
|
9123
|
+
if (hasBackRefs) {
|
|
9124
|
+
discoveredValues.push(effectsBackRefs);
|
|
9125
|
+
}
|
|
9126
|
+
}
|
|
9127
|
+
};
|
|
8985
9128
|
const promiseResults = new WeakMap();
|
|
8986
9129
|
/**
|
|
8987
9130
|
* Format:
|
|
@@ -9053,7 +9196,7 @@
|
|
|
9053
9196
|
else if (value === Fragment) {
|
|
9054
9197
|
output(TypeIds.Constant, Constants.Fragment);
|
|
9055
9198
|
}
|
|
9056
|
-
else if (isQrl(value)) {
|
|
9199
|
+
else if (isQrl$1(value)) {
|
|
9057
9200
|
const qrl = qrlToString(serializationContext, value);
|
|
9058
9201
|
const id = serializationContext.$addRoot$(qrl);
|
|
9059
9202
|
output(TypeIds.QRL, id);
|
|
@@ -9128,6 +9271,9 @@
|
|
|
9128
9271
|
else if (value === NEEDS_COMPUTATION) {
|
|
9129
9272
|
output(TypeIds.Constant, Constants.NEEDS_COMPUTATION);
|
|
9130
9273
|
}
|
|
9274
|
+
else if (value === STORE_ARRAY_PROP) {
|
|
9275
|
+
output(TypeIds.Constant, Constants.STORE_ARRAY_PROP);
|
|
9276
|
+
}
|
|
9131
9277
|
else {
|
|
9132
9278
|
throw qError(QError.serializeErrorUnknownType, [typeof value]);
|
|
9133
9279
|
}
|
|
@@ -9164,7 +9310,7 @@
|
|
|
9164
9310
|
: 0;
|
|
9165
9311
|
output(TypeIds.PropsProxy, out);
|
|
9166
9312
|
}
|
|
9167
|
-
else if (value instanceof
|
|
9313
|
+
else if (value instanceof SubscriptionData) {
|
|
9168
9314
|
output(TypeIds.EffectData, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
|
|
9169
9315
|
}
|
|
9170
9316
|
else if (isStore(value)) {
|
|
@@ -9175,6 +9321,7 @@
|
|
|
9175
9321
|
if (!res) {
|
|
9176
9322
|
throw qError(QError.serializeErrorUnvisited, ['resource']);
|
|
9177
9323
|
}
|
|
9324
|
+
// TODO the effects include the resourcereturn which has duplicate data
|
|
9178
9325
|
output(TypeIds.Resource, [...res, getStoreHandler(value).$effects$]);
|
|
9179
9326
|
}
|
|
9180
9327
|
else {
|
|
@@ -9182,7 +9329,6 @@
|
|
|
9182
9329
|
const storeTarget = getStoreTarget(value);
|
|
9183
9330
|
const flags = storeHandler.$flags$;
|
|
9184
9331
|
const effects = storeHandler.$effects$;
|
|
9185
|
-
const storeEffect = effects?.[STORE_ARRAY_PROP] ?? null;
|
|
9186
9332
|
const innerStores = [];
|
|
9187
9333
|
for (const prop in storeTarget) {
|
|
9188
9334
|
const propValue = storeTarget[prop];
|
|
@@ -9192,7 +9338,7 @@
|
|
|
9192
9338
|
serializationContext.$addRoot$(innerStore);
|
|
9193
9339
|
}
|
|
9194
9340
|
}
|
|
9195
|
-
const out = [storeTarget, flags, effects,
|
|
9341
|
+
const out = [storeTarget, flags, effects, ...innerStores];
|
|
9196
9342
|
while (out[out.length - 1] == null) {
|
|
9197
9343
|
out.pop();
|
|
9198
9344
|
}
|
|
@@ -9231,7 +9377,7 @@
|
|
|
9231
9377
|
if (value instanceof WrappedSignal) {
|
|
9232
9378
|
output(TypeIds.WrappedSignal, [
|
|
9233
9379
|
...serializeWrappingFn(serializationContext, value),
|
|
9234
|
-
value
|
|
9380
|
+
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
|
|
9235
9381
|
v,
|
|
9236
9382
|
value.$hostElement$,
|
|
9237
9383
|
...(value.$effects$ || []),
|
|
@@ -9338,7 +9484,7 @@
|
|
|
9338
9484
|
value.$flags$,
|
|
9339
9485
|
value.$index$,
|
|
9340
9486
|
value.$el$,
|
|
9341
|
-
value
|
|
9487
|
+
value[_EFFECT_BACK_REF],
|
|
9342
9488
|
value.$state$,
|
|
9343
9489
|
];
|
|
9344
9490
|
while (out[out.length - 1] == null) {
|
|
@@ -9361,12 +9507,27 @@
|
|
|
9361
9507
|
const out = btoa(buf).replace(/=+$/, '');
|
|
9362
9508
|
output(TypeIds.Uint8Array, out);
|
|
9363
9509
|
}
|
|
9510
|
+
else if (vnode_isVNode(value)) {
|
|
9511
|
+
output(TypeIds.Constant, Constants.Undefined);
|
|
9512
|
+
}
|
|
9364
9513
|
else {
|
|
9365
9514
|
throw qError(QError.serializeErrorUnknownType, [typeof value]);
|
|
9366
9515
|
}
|
|
9367
9516
|
};
|
|
9368
9517
|
writeValue(serializationContext.$roots$, -1);
|
|
9369
9518
|
}
|
|
9519
|
+
function filterEffectBackRefs(effectBackRef) {
|
|
9520
|
+
let effectBackRefToSerialize = null;
|
|
9521
|
+
if (effectBackRef) {
|
|
9522
|
+
for (const [effectProp, effect] of effectBackRef) {
|
|
9523
|
+
if (effect[EffectSubscriptionProp.BACK_REF]) {
|
|
9524
|
+
effectBackRefToSerialize ||= new Map();
|
|
9525
|
+
effectBackRefToSerialize.set(effectProp, effect);
|
|
9526
|
+
}
|
|
9527
|
+
}
|
|
9528
|
+
}
|
|
9529
|
+
return effectBackRefToSerialize;
|
|
9530
|
+
}
|
|
9370
9531
|
function serializeWrappingFn(serializationContext, value) {
|
|
9371
9532
|
// if value is an object then we need to wrap this in ()
|
|
9372
9533
|
if (value.$funcStr$ && value.$funcStr$[0] === '{') {
|
|
@@ -9379,15 +9540,12 @@
|
|
|
9379
9540
|
function qrlToString(serializationContext, value) {
|
|
9380
9541
|
let symbol = value.$symbol$;
|
|
9381
9542
|
let chunk = value.$chunk$;
|
|
9382
|
-
const refSymbol = value.$refSymbol$ ?? symbol;
|
|
9383
9543
|
const platform = getPlatform();
|
|
9384
9544
|
if (platform) {
|
|
9385
|
-
const result = platform.chunkForSymbol(
|
|
9545
|
+
const result = platform.chunkForSymbol(symbol, chunk, value.dev?.file);
|
|
9386
9546
|
if (result) {
|
|
9387
9547
|
chunk = result[1];
|
|
9388
|
-
|
|
9389
|
-
symbol = result[0];
|
|
9390
|
-
}
|
|
9548
|
+
symbol = result[0];
|
|
9391
9549
|
}
|
|
9392
9550
|
}
|
|
9393
9551
|
const isSync = isSyncQrl(value);
|
|
@@ -9564,9 +9722,9 @@
|
|
|
9564
9722
|
return ((typeof obj === 'object' &&
|
|
9565
9723
|
obj !== null &&
|
|
9566
9724
|
(obj instanceof Signal || obj instanceof Task || isJSXNode(obj))) ||
|
|
9567
|
-
isQrl(obj));
|
|
9725
|
+
isQrl$1(obj));
|
|
9568
9726
|
};
|
|
9569
|
-
const canSerialize = (value) => {
|
|
9727
|
+
const canSerialize = (value, seen = new WeakSet()) => {
|
|
9570
9728
|
if (value == null ||
|
|
9571
9729
|
typeof value === 'string' ||
|
|
9572
9730
|
typeof value === 'number' ||
|
|
@@ -9575,6 +9733,10 @@
|
|
|
9575
9733
|
return true;
|
|
9576
9734
|
}
|
|
9577
9735
|
else if (typeof value === 'object') {
|
|
9736
|
+
if (seen.has(value)) {
|
|
9737
|
+
return true;
|
|
9738
|
+
}
|
|
9739
|
+
seen.add(value);
|
|
9578
9740
|
const proto = Object.getPrototypeOf(value);
|
|
9579
9741
|
if (isStore(value)) {
|
|
9580
9742
|
value = getStoreTarget(value);
|
|
@@ -9583,7 +9745,7 @@
|
|
|
9583
9745
|
for (const key in value) {
|
|
9584
9746
|
// if the value is a props proxy, then sometimes we could create a component-level subscription,
|
|
9585
9747
|
// so we should call untrack here to avoid tracking the value
|
|
9586
|
-
if (!canSerialize(untrack(() => value[key]))) {
|
|
9748
|
+
if (!canSerialize(untrack(() => value[key]), seen)) {
|
|
9587
9749
|
return false;
|
|
9588
9750
|
}
|
|
9589
9751
|
}
|
|
@@ -9591,7 +9753,7 @@
|
|
|
9591
9753
|
}
|
|
9592
9754
|
else if (proto == Array.prototype) {
|
|
9593
9755
|
for (let i = 0; i < value.length; i++) {
|
|
9594
|
-
if (!canSerialize(value[i])) {
|
|
9756
|
+
if (!canSerialize(value[i], seen)) {
|
|
9595
9757
|
return false;
|
|
9596
9758
|
}
|
|
9597
9759
|
}
|
|
@@ -9641,7 +9803,7 @@
|
|
|
9641
9803
|
}
|
|
9642
9804
|
}
|
|
9643
9805
|
else if (typeof value === 'function') {
|
|
9644
|
-
if (isQrl(value) || isQwikComponent(value)) {
|
|
9806
|
+
if (isQrl$1(value) || isQwikComponent(value)) {
|
|
9645
9807
|
return true;
|
|
9646
9808
|
}
|
|
9647
9809
|
}
|
|
@@ -9694,20 +9856,21 @@
|
|
|
9694
9856
|
Constants[Constants["EMPTY_ARRAY"] = 5] = "EMPTY_ARRAY";
|
|
9695
9857
|
Constants[Constants["EMPTY_OBJ"] = 6] = "EMPTY_OBJ";
|
|
9696
9858
|
Constants[Constants["NEEDS_COMPUTATION"] = 7] = "NEEDS_COMPUTATION";
|
|
9697
|
-
Constants[Constants["
|
|
9698
|
-
Constants[Constants["
|
|
9699
|
-
Constants[Constants["
|
|
9700
|
-
Constants[Constants["
|
|
9701
|
-
Constants[Constants["
|
|
9702
|
-
Constants[Constants["
|
|
9859
|
+
Constants[Constants["STORE_ARRAY_PROP"] = 8] = "STORE_ARRAY_PROP";
|
|
9860
|
+
Constants[Constants["Slot"] = 9] = "Slot";
|
|
9861
|
+
Constants[Constants["Fragment"] = 10] = "Fragment";
|
|
9862
|
+
Constants[Constants["NaN"] = 11] = "NaN";
|
|
9863
|
+
Constants[Constants["PositiveInfinity"] = 12] = "PositiveInfinity";
|
|
9864
|
+
Constants[Constants["NegativeInfinity"] = 13] = "NegativeInfinity";
|
|
9865
|
+
Constants[Constants["MaxSafeInt"] = 14] = "MaxSafeInt";
|
|
9703
9866
|
// used for close fragment
|
|
9704
|
-
Constants[Constants["AlmostMaxSafeInt"] =
|
|
9705
|
-
Constants[Constants["MinSafeInt"] =
|
|
9867
|
+
Constants[Constants["AlmostMaxSafeInt"] = 15] = "AlmostMaxSafeInt";
|
|
9868
|
+
Constants[Constants["MinSafeInt"] = 16] = "MinSafeInt";
|
|
9706
9869
|
})(Constants || (Constants = {}));
|
|
9707
9870
|
|
|
9708
9871
|
/** @internal */
|
|
9709
9872
|
const verifySerializable = (value, preMessage) => {
|
|
9710
|
-
const seen = new
|
|
9873
|
+
const seen = new WeakSet();
|
|
9711
9874
|
return _verifySerializable(value, seen, '_', preMessage);
|
|
9712
9875
|
};
|
|
9713
9876
|
const _verifySerializable = (value, seen, ctx, preMessage) => {
|
|
@@ -9716,10 +9879,12 @@
|
|
|
9716
9879
|
return value;
|
|
9717
9880
|
}
|
|
9718
9881
|
if (shouldSerialize(unwrapped)) {
|
|
9719
|
-
if (
|
|
9720
|
-
|
|
9882
|
+
if (typeof unwrapped === 'object') {
|
|
9883
|
+
if (seen.has(unwrapped)) {
|
|
9884
|
+
return value;
|
|
9885
|
+
}
|
|
9886
|
+
seen.add(unwrapped);
|
|
9721
9887
|
}
|
|
9722
|
-
seen.add(unwrapped);
|
|
9723
9888
|
if (isSignal(unwrapped)) {
|
|
9724
9889
|
return value;
|
|
9725
9890
|
}
|
|
@@ -9823,16 +9988,7 @@
|
|
|
9823
9988
|
return input;
|
|
9824
9989
|
};
|
|
9825
9990
|
|
|
9826
|
-
const
|
|
9827
|
-
return typeof value === 'function' && typeof value.getSymbol === 'function';
|
|
9828
|
-
};
|
|
9829
|
-
// Make sure this value is same as value in `platform.ts`
|
|
9830
|
-
const SYNC_QRL = '<sync>';
|
|
9831
|
-
/** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */
|
|
9832
|
-
const isSyncQrl = (value) => {
|
|
9833
|
-
return isQrl(value) && value.$symbol$ == SYNC_QRL;
|
|
9834
|
-
};
|
|
9835
|
-
const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef, refSymbol) => {
|
|
9991
|
+
const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
|
|
9836
9992
|
if (qDev && qSerialize) {
|
|
9837
9993
|
if (captureRef) {
|
|
9838
9994
|
for (const item of captureRef) {
|
|
@@ -9854,9 +10010,14 @@
|
|
|
9854
10010
|
};
|
|
9855
10011
|
function bindFnToContext(currentCtx, beforeFn) {
|
|
9856
10012
|
// Note that we bind the current `this`
|
|
9857
|
-
|
|
9858
|
-
if (!
|
|
9859
|
-
|
|
10013
|
+
const bound = (...args) => {
|
|
10014
|
+
if (!qrl.resolved) {
|
|
10015
|
+
return qrl.resolve().then((fn) => {
|
|
10016
|
+
if (!isFunction(fn)) {
|
|
10017
|
+
throw qError(QError.qrlIsNotFunction);
|
|
10018
|
+
}
|
|
10019
|
+
return bound(...args);
|
|
10020
|
+
});
|
|
9860
10021
|
}
|
|
9861
10022
|
if (beforeFn && beforeFn() === false) {
|
|
9862
10023
|
return;
|
|
@@ -9869,13 +10030,14 @@
|
|
|
9869
10030
|
context.$qrl$ = qrl;
|
|
9870
10031
|
context.$event$ ||= this;
|
|
9871
10032
|
try {
|
|
9872
|
-
return invoke.call(this, context,
|
|
10033
|
+
return invoke.call(this, context, symbolRef, ...args);
|
|
9873
10034
|
}
|
|
9874
10035
|
finally {
|
|
9875
10036
|
context.$qrl$ = prevQrl;
|
|
9876
10037
|
context.$event$ = prevEvent;
|
|
9877
10038
|
}
|
|
9878
|
-
}
|
|
10039
|
+
};
|
|
10040
|
+
return bound;
|
|
9879
10041
|
}
|
|
9880
10042
|
const resolveLazy = (containerEl) => {
|
|
9881
10043
|
return symbolRef !== null ? symbolRef : resolve(containerEl);
|
|
@@ -9887,8 +10049,20 @@
|
|
|
9887
10049
|
}
|
|
9888
10050
|
return function (...args) {
|
|
9889
10051
|
let context = tryGetInvokeContext();
|
|
10052
|
+
// use the given qrl if it is the right one
|
|
9890
10053
|
if (context) {
|
|
9891
|
-
|
|
10054
|
+
// TODO check if this is necessary in production
|
|
10055
|
+
if (context.$qrl$?.$symbol$ === qrl.$symbol$) {
|
|
10056
|
+
return fn.apply(this, args);
|
|
10057
|
+
}
|
|
10058
|
+
const prevQrl = context.$qrl$;
|
|
10059
|
+
context.$qrl$ = qrl;
|
|
10060
|
+
try {
|
|
10061
|
+
return fn.apply(this, args);
|
|
10062
|
+
}
|
|
10063
|
+
finally {
|
|
10064
|
+
context.$qrl$ = prevQrl;
|
|
10065
|
+
}
|
|
9892
10066
|
}
|
|
9893
10067
|
context = newInvokeContext();
|
|
9894
10068
|
context.$qrl$ = qrl;
|
|
@@ -9916,11 +10090,11 @@
|
|
|
9916
10090
|
const start = now();
|
|
9917
10091
|
const ctx = tryGetInvokeContext();
|
|
9918
10092
|
if (symbolFn !== null) {
|
|
9919
|
-
symbolRef = symbolFn().then((module) => (qrl.resolved = symbolRef =
|
|
10093
|
+
symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
|
|
9920
10094
|
}
|
|
9921
10095
|
else {
|
|
9922
10096
|
const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
|
|
9923
|
-
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = symbolRef =
|
|
10097
|
+
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
|
|
9924
10098
|
}
|
|
9925
10099
|
if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
|
|
9926
10100
|
symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
|
|
@@ -9943,10 +10117,9 @@
|
|
|
9943
10117
|
return invoke;
|
|
9944
10118
|
}
|
|
9945
10119
|
};
|
|
9946
|
-
const
|
|
9947
|
-
const hash = getSymbolHash(resolvedSymbol);
|
|
10120
|
+
const hash = getSymbolHash(symbol);
|
|
9948
10121
|
Object.assign(qrl, {
|
|
9949
|
-
getSymbol: () =>
|
|
10122
|
+
getSymbol: () => symbol,
|
|
9950
10123
|
getHash: () => hash,
|
|
9951
10124
|
getCaptured: () => captureRef,
|
|
9952
10125
|
resolve,
|
|
@@ -9954,7 +10127,6 @@
|
|
|
9954
10127
|
$setContainer$: setContainer,
|
|
9955
10128
|
$chunk$: chunk,
|
|
9956
10129
|
$symbol$: symbol,
|
|
9957
|
-
$refSymbol$: refSymbol,
|
|
9958
10130
|
$hash$: hash,
|
|
9959
10131
|
getFn: bindFnToContext,
|
|
9960
10132
|
$capture$: capture,
|
|
@@ -9963,8 +10135,8 @@
|
|
|
9963
10135
|
resolved: undefined,
|
|
9964
10136
|
});
|
|
9965
10137
|
if (symbolRef) {
|
|
9966
|
-
//
|
|
9967
|
-
symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = symbolRef =
|
|
10138
|
+
// Unwrap any promises
|
|
10139
|
+
symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = wrapFn((symbolRef = resolved))));
|
|
9968
10140
|
}
|
|
9969
10141
|
if (build.isDev) {
|
|
9970
10142
|
Object.defineProperty(qrl, '_devOnlySymbolRef', {
|
|
@@ -9978,20 +10150,6 @@
|
|
|
9978
10150
|
}
|
|
9979
10151
|
return qrl;
|
|
9980
10152
|
};
|
|
9981
|
-
const getSymbolHash = (symbolName) => {
|
|
9982
|
-
const index = symbolName.lastIndexOf('_');
|
|
9983
|
-
if (index > -1) {
|
|
9984
|
-
return symbolName.slice(index + 1);
|
|
9985
|
-
}
|
|
9986
|
-
return symbolName;
|
|
9987
|
-
};
|
|
9988
|
-
function assertQrl(qrl) {
|
|
9989
|
-
if (qDev) {
|
|
9990
|
-
if (!isQrl(qrl)) {
|
|
9991
|
-
throw new Error('Not a QRL');
|
|
9992
|
-
}
|
|
9993
|
-
}
|
|
9994
|
-
}
|
|
9995
10153
|
const EMITTED = /*#__PURE__*/ new Set();
|
|
9996
10154
|
const emitUsedSymbol = (symbol, element, reqTime) => {
|
|
9997
10155
|
if (!EMITTED.has(symbol)) {
|
|
@@ -10104,7 +10262,7 @@
|
|
|
10104
10262
|
if (!qRuntimeQrl && qDev) {
|
|
10105
10263
|
throw new Error('Optimizer should replace all usages of $() with some special syntax. If you need to create a QRL manually, use inlinedQrl() instead.');
|
|
10106
10264
|
}
|
|
10107
|
-
return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null
|
|
10265
|
+
return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null);
|
|
10108
10266
|
};
|
|
10109
10267
|
/** @private Use To avoid optimizer replacement */
|
|
10110
10268
|
const dollar = $;
|
|
@@ -10130,7 +10288,7 @@
|
|
|
10130
10288
|
// eslint-disable-next-line no-new-func
|
|
10131
10289
|
fn = new Function('return ' + fn.toString())();
|
|
10132
10290
|
}
|
|
10133
|
-
return createQRL('', SYNC_QRL, fn, null, null, null
|
|
10291
|
+
return createQRL('', SYNC_QRL, fn, null, null, null);
|
|
10134
10292
|
};
|
|
10135
10293
|
/**
|
|
10136
10294
|
* Extract function into a synchronously loadable QRL.
|
|
@@ -10147,7 +10305,7 @@
|
|
|
10147
10305
|
serializedFn = fn.toString();
|
|
10148
10306
|
}
|
|
10149
10307
|
fn.serialized = serializedFn;
|
|
10150
|
-
return createQRL('', SYNC_QRL, fn, null, null, null
|
|
10308
|
+
return createQRL('', SYNC_QRL, fn, null, null, null);
|
|
10151
10309
|
};
|
|
10152
10310
|
|
|
10153
10311
|
/** @internal */
|
|
@@ -10866,6 +11024,21 @@
|
|
|
10866
11024
|
iCtx.$container$.$scheduler$(ChoreType.VISIBLE, task);
|
|
10867
11025
|
}
|
|
10868
11026
|
};
|
|
11027
|
+
const useRunTask = (task, eagerness) => {
|
|
11028
|
+
if (eagerness === 'intersection-observer') {
|
|
11029
|
+
useOn('qvisible', getTaskHandlerQrl(task));
|
|
11030
|
+
}
|
|
11031
|
+
else if (eagerness === 'document-ready') {
|
|
11032
|
+
useOnDocument('qinit', getTaskHandlerQrl(task));
|
|
11033
|
+
}
|
|
11034
|
+
else if (eagerness === 'document-idle') {
|
|
11035
|
+
useOnDocument('qidle', getTaskHandlerQrl(task));
|
|
11036
|
+
}
|
|
11037
|
+
};
|
|
11038
|
+
const getTaskHandlerQrl = (task) => {
|
|
11039
|
+
const taskHandler = createQRL(null, '_task', scheduleTask, null, null, [task]);
|
|
11040
|
+
return taskHandler;
|
|
11041
|
+
};
|
|
10869
11042
|
|
|
10870
11043
|
// <docs markdown="../readme.md#useResource">
|
|
10871
11044
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
@@ -11202,8 +11375,9 @@
|
|
|
11202
11375
|
exports.Slot = Slot;
|
|
11203
11376
|
exports._CONST_PROPS = _CONST_PROPS;
|
|
11204
11377
|
exports._DomContainer = DomContainer;
|
|
11378
|
+
exports._EFFECT_BACK_REF = _EFFECT_BACK_REF;
|
|
11205
11379
|
exports._EMPTY_ARRAY = EMPTY_ARRAY;
|
|
11206
|
-
exports._EffectData =
|
|
11380
|
+
exports._EffectData = SubscriptionData;
|
|
11207
11381
|
exports._IMMUTABLE = _IMMUTABLE;
|
|
11208
11382
|
exports._SharedContainer = _SharedContainer;
|
|
11209
11383
|
exports._VAR_PROPS = _VAR_PROPS;
|
|
@@ -11213,7 +11387,6 @@
|
|
|
11213
11387
|
exports._getContextEvent = _getContextEvent;
|
|
11214
11388
|
exports._getDomContainer = getDomContainer;
|
|
11215
11389
|
exports._getQContainerElement = _getQContainerElement;
|
|
11216
|
-
exports._hW = _hW;
|
|
11217
11390
|
exports._isJSXNode = isJSXNode;
|
|
11218
11391
|
exports._isStringifiable = isStringifiable;
|
|
11219
11392
|
exports._jsxBranch = _jsxBranch;
|
|
@@ -11227,7 +11400,9 @@
|
|
|
11227
11400
|
exports._qrlSync = _qrlSync;
|
|
11228
11401
|
exports._regSymbol = _regSymbol;
|
|
11229
11402
|
exports._restProps = _restProps;
|
|
11403
|
+
exports._run = queueQRL;
|
|
11230
11404
|
exports._serialize = _serialize;
|
|
11405
|
+
exports._task = scheduleTask;
|
|
11231
11406
|
exports._verifySerializable = verifySerializable;
|
|
11232
11407
|
exports._waitUntilRendered = _waitUntilRendered;
|
|
11233
11408
|
exports._walkJSX = _walkJSX;
|