@qwik.dev/core 2.0.0-alpha.6 → 2.0.0-alpha.8
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 +92 -78
- package/dist/core.cjs +1603 -1374
- package/dist/core.cjs.map +1 -1
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +1600 -1374
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.cjs +963 -834
- package/dist/core.prod.mjs +1093 -927
- package/dist/insights/index.qwik.cjs +3679 -167
- package/dist/insights/index.qwik.mjs +3679 -167
- 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 +228 -5715
- package/dist/optimizer.mjs +208 -6038
- package/dist/prefetch/package.json +1 -1
- package/dist/qwikloader.debug.js +12 -15
- package/dist/qwikloader.js +2 -2
- package/dist/server.cjs +787 -7152
- package/dist/server.mjs +805 -7148
- 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 +1341 -1180
- package/dist/testing/index.mjs +1354 -1186
- 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.8-dev+66037b5
|
|
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,11 +313,10 @@
|
|
|
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
|
-
const QSlotParent = ':';
|
|
298
|
-
const QSlotRef = 'q:sref';
|
|
319
|
+
const QSlotParent = 'q:sparent';
|
|
299
320
|
const QSlotS = 'q:s';
|
|
300
321
|
const QStyle = 'q:style';
|
|
301
322
|
const QStyleSelector = 'style[q\\:style]';
|
|
@@ -303,7 +324,7 @@
|
|
|
303
324
|
const QStylesAllSelector = QStyleSelector + ',' + QStyleSSelector;
|
|
304
325
|
const QScopedStyle = 'q:sstyle';
|
|
305
326
|
const QCtxAttr = 'q:ctx';
|
|
306
|
-
const
|
|
327
|
+
const QBackRefs = 'q:brefs';
|
|
307
328
|
const QFuncsPrefix = 'qFuncs_';
|
|
308
329
|
const getQFuncs = (document, hash) => {
|
|
309
330
|
return document[QFuncsPrefix + hash] || [];
|
|
@@ -332,6 +353,7 @@
|
|
|
332
353
|
const ResourceEvent = 'qResource';
|
|
333
354
|
const RenderEvent = 'qRender';
|
|
334
355
|
const TaskEvent = 'qTask';
|
|
356
|
+
/** `<q:slot name="...">` */
|
|
335
357
|
const QDefaultSlot = '';
|
|
336
358
|
/**
|
|
337
359
|
* Attribute to mark that this VNode has a pointer to itself from the `qwik/json` state.
|
|
@@ -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,40 +1150,10 @@
|
|
|
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');
|
|
1054
|
-
const
|
|
1156
|
+
const STORE_ALL_PROPS = Symbol('store.all');
|
|
1055
1157
|
var StoreFlags;
|
|
1056
1158
|
(function (StoreFlags) {
|
|
1057
1159
|
StoreFlags[StoreFlags["NONE"] = 0] = "NONE";
|
|
@@ -1126,7 +1228,7 @@
|
|
|
1126
1228
|
}
|
|
1127
1229
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1128
1230
|
if (effectSubscriber) {
|
|
1129
|
-
|
|
1231
|
+
addStoreEffect(target, Array.isArray(target) ? STORE_ALL_PROPS : prop, this, effectSubscriber);
|
|
1130
1232
|
}
|
|
1131
1233
|
}
|
|
1132
1234
|
if (prop === 'toString' && value === Object.prototype.toString) {
|
|
@@ -1177,7 +1279,7 @@
|
|
|
1177
1279
|
if (ctx) {
|
|
1178
1280
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1179
1281
|
if (effectSubscriber) {
|
|
1180
|
-
|
|
1282
|
+
addStoreEffect(target, Array.isArray(target) ? STORE_ALL_PROPS : prop, this, effectSubscriber);
|
|
1181
1283
|
}
|
|
1182
1284
|
}
|
|
1183
1285
|
}
|
|
@@ -1187,13 +1289,17 @@
|
|
|
1187
1289
|
const ctx = tryGetInvokeContext();
|
|
1188
1290
|
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
1189
1291
|
if (effectSubscriber) {
|
|
1190
|
-
|
|
1292
|
+
addStoreEffect(target, STORE_ALL_PROPS, this, effectSubscriber);
|
|
1191
1293
|
}
|
|
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
|
|
1205
|
-
const effectsMap = (store.$effects$ ||=
|
|
1206
|
-
|
|
1207
|
-
|
|
1310
|
+
function addStoreEffect(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_ALL_PROPS);
|
|
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)) {
|
|
@@ -1561,116 +1592,91 @@
|
|
|
1561
1592
|
else if (isSignal(obj)) {
|
|
1562
1593
|
return obj.value;
|
|
1563
1594
|
}
|
|
1564
|
-
else {
|
|
1595
|
+
else if (isStore(obj)) {
|
|
1596
|
+
// track whole store
|
|
1597
|
+
addStoreEffect(getStoreTarget(obj), STORE_ALL_PROPS, getStoreHandler(obj), ctx.$effectSubscriber$);
|
|
1565
1598
|
return obj;
|
|
1566
1599
|
}
|
|
1600
|
+
else {
|
|
1601
|
+
throw qError(QError.trackObjectWithoutProp);
|
|
1602
|
+
}
|
|
1567
1603
|
});
|
|
1568
1604
|
};
|
|
1569
1605
|
const handleError = (reason) => container.handleError(reason, host);
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1606
|
+
let cleanupFns = null;
|
|
1607
|
+
const cleanup = (fn) => {
|
|
1608
|
+
if (typeof fn == 'function') {
|
|
1609
|
+
if (!cleanupFns) {
|
|
1610
|
+
cleanupFns = [];
|
|
1611
|
+
task.$destroy$ = noSerialize(() => {
|
|
1612
|
+
task.$destroy$ = null;
|
|
1613
|
+
cleanupFns.forEach((fn) => {
|
|
1614
|
+
try {
|
|
1615
|
+
fn();
|
|
1616
|
+
}
|
|
1617
|
+
catch (err) {
|
|
1618
|
+
handleError(err);
|
|
1619
|
+
}
|
|
1620
|
+
});
|
|
1621
|
+
});
|
|
1578
1622
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1623
|
+
cleanupFns.push(fn);
|
|
1624
|
+
}
|
|
1625
|
+
};
|
|
1626
|
+
const taskApi = { track, cleanup };
|
|
1627
|
+
const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
1628
|
+
// If a Promise is thrown, that means we need to re-run the task.
|
|
1629
|
+
if (isPromise(err)) {
|
|
1630
|
+
return err.then(() => runTask(task, container, host));
|
|
1631
|
+
}
|
|
1632
|
+
else {
|
|
1633
|
+
throw err;
|
|
1634
|
+
}
|
|
1581
1635
|
});
|
|
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));
|
|
1636
|
+
return result;
|
|
1637
|
+
};
|
|
1638
|
+
const cleanupTask = (task) => {
|
|
1639
|
+
const destroy = task.$destroy$;
|
|
1640
|
+
if (destroy) {
|
|
1641
|
+
task.$destroy$ = null;
|
|
1642
|
+
try {
|
|
1643
|
+
destroy();
|
|
1653
1644
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1645
|
+
catch (err) {
|
|
1646
|
+
logError(err);
|
|
1656
1647
|
}
|
|
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
1648
|
}
|
|
1669
|
-
return promise;
|
|
1670
1649
|
};
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1650
|
+
class Task extends BackRef {
|
|
1651
|
+
$flags$;
|
|
1652
|
+
$index$;
|
|
1653
|
+
$el$;
|
|
1654
|
+
$qrl$;
|
|
1655
|
+
$state$;
|
|
1656
|
+
$destroy$;
|
|
1657
|
+
constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
|
|
1658
|
+
super();
|
|
1659
|
+
this.$flags$ = $flags$;
|
|
1660
|
+
this.$index$ = $index$;
|
|
1661
|
+
this.$el$ = $el$;
|
|
1662
|
+
this.$qrl$ = $qrl$;
|
|
1663
|
+
this.$state$ = $state$;
|
|
1664
|
+
this.$destroy$ = $destroy$;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
const isTask = (value) => {
|
|
1668
|
+
return value instanceof Task;
|
|
1669
|
+
};
|
|
1670
|
+
/**
|
|
1671
|
+
* Used internally as a qrl event handler to schedule a task.
|
|
1672
|
+
*
|
|
1673
|
+
* @internal
|
|
1674
|
+
*/
|
|
1675
|
+
const scheduleTask = (_event, element) => {
|
|
1676
|
+
const [task] = useLexicalScope();
|
|
1677
|
+
const type = task.$flags$ & TaskFlags.VISIBLE_TASK ? ChoreType.VISIBLE : ChoreType.TASK;
|
|
1678
|
+
const container = getDomContainer(element);
|
|
1679
|
+
container.$scheduler$(type, task);
|
|
1674
1680
|
};
|
|
1675
1681
|
|
|
1676
1682
|
/** @file Public types for the client deserialization */
|
|
@@ -1748,22 +1754,67 @@
|
|
|
1748
1754
|
VirtualVNodeProps[VirtualVNodeProps["PROPS_OFFSET"] = 6] = "PROPS_OFFSET";
|
|
1749
1755
|
})(VirtualVNodeProps || (VirtualVNodeProps = {}));
|
|
1750
1756
|
|
|
1751
|
-
const
|
|
1757
|
+
const mapApp_findIndx = (array, key, start) => {
|
|
1758
|
+
assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
1759
|
+
let bottom = start >> 1;
|
|
1760
|
+
let top = (array.length - 2) >> 1;
|
|
1761
|
+
while (bottom <= top) {
|
|
1762
|
+
const mid = bottom + ((top - bottom) >> 1);
|
|
1763
|
+
const midKey = array[mid << 1];
|
|
1764
|
+
if (midKey === key) {
|
|
1765
|
+
return mid << 1;
|
|
1766
|
+
}
|
|
1767
|
+
if (midKey < key) {
|
|
1768
|
+
bottom = mid + 1;
|
|
1769
|
+
}
|
|
1770
|
+
else {
|
|
1771
|
+
top = mid - 1;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
return (bottom << 1) ^ -1;
|
|
1775
|
+
};
|
|
1776
|
+
const mapArray_set = (array, key, value, start) => {
|
|
1777
|
+
const indx = mapApp_findIndx(array, key, start);
|
|
1778
|
+
if (indx >= 0) {
|
|
1779
|
+
if (value == null) {
|
|
1780
|
+
array.splice(indx, 2);
|
|
1781
|
+
}
|
|
1782
|
+
else {
|
|
1783
|
+
array[indx + 1] = value;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
else if (value != null) {
|
|
1787
|
+
array.splice(indx ^ -1, 0, key, value);
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
const mapArray_get = (array, key, start) => {
|
|
1791
|
+
const indx = mapApp_findIndx(array, key, start);
|
|
1792
|
+
if (indx >= 0) {
|
|
1793
|
+
return array[indx + 1];
|
|
1794
|
+
}
|
|
1795
|
+
else {
|
|
1796
|
+
return null;
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
const isForeignObjectElement = (elementName) => {
|
|
1801
|
+
return build.isDev ? elementName.toLowerCase() === 'foreignobject' : elementName === 'foreignObject';
|
|
1802
|
+
};
|
|
1752
1803
|
const isSvgElement = (elementName) => elementName === 'svg' || isForeignObjectElement(elementName);
|
|
1753
1804
|
const isMathElement = (elementName) => elementName === 'math';
|
|
1754
1805
|
const vnode_isDefaultNamespace = (vnode) => {
|
|
1755
1806
|
const flags = vnode[VNodeProps.flags];
|
|
1756
1807
|
return (flags & VNodeFlags.NAMESPACE_MASK) === 0;
|
|
1757
1808
|
};
|
|
1758
|
-
const vnode_getElementNamespaceFlags = (
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1809
|
+
const vnode_getElementNamespaceFlags = (element) => {
|
|
1810
|
+
const namespace = fastNamespaceURI(element);
|
|
1811
|
+
switch (namespace) {
|
|
1812
|
+
case SVG_NS:
|
|
1813
|
+
return VNodeFlags.NS_svg;
|
|
1814
|
+
case MATH_NS:
|
|
1815
|
+
return VNodeFlags.NS_math;
|
|
1816
|
+
default:
|
|
1817
|
+
return VNodeFlags.NS_html;
|
|
1767
1818
|
}
|
|
1768
1819
|
};
|
|
1769
1820
|
function vnode_getDomChildrenWithCorrectNamespacesToInsert(journal, domParentVNode, newChild) {
|
|
@@ -2117,19 +2168,21 @@
|
|
|
2117
2168
|
* @returns
|
|
2118
2169
|
*/
|
|
2119
2170
|
const executeComponent = (container, renderHost, subscriptionHost, componentQRL, props) => {
|
|
2120
|
-
const iCtx = newInvokeContext(container.$locale$, subscriptionHost, undefined, RenderEvent);
|
|
2121
|
-
|
|
2122
|
-
|
|
2171
|
+
const iCtx = newInvokeContext(container.$locale$, subscriptionHost || undefined, undefined, RenderEvent);
|
|
2172
|
+
if (subscriptionHost) {
|
|
2173
|
+
iCtx.$effectSubscriber$ = getSubscriber(subscriptionHost, EffectProperty.COMPONENT);
|
|
2174
|
+
iCtx.$container$ = container;
|
|
2175
|
+
}
|
|
2123
2176
|
let componentFn;
|
|
2124
2177
|
container.ensureProjectionResolved(renderHost);
|
|
2125
2178
|
let isInlineComponent = false;
|
|
2126
2179
|
if (componentQRL === null) {
|
|
2127
|
-
componentQRL =
|
|
2180
|
+
componentQRL = container.getHostProp(renderHost, OnRenderProp);
|
|
2128
2181
|
assertDefined(componentQRL, 'No Component found at this location');
|
|
2129
2182
|
}
|
|
2130
|
-
if (isQrl(componentQRL)) {
|
|
2183
|
+
if (isQrl$1(componentQRL)) {
|
|
2131
2184
|
props = props || container.getHostProp(renderHost, ELEMENT_PROPS) || EMPTY_OBJ;
|
|
2132
|
-
if (props
|
|
2185
|
+
if (props.children) {
|
|
2133
2186
|
delete props.children;
|
|
2134
2187
|
}
|
|
2135
2188
|
componentFn = componentQRL.getFn(iCtx);
|
|
@@ -2147,18 +2200,16 @@
|
|
|
2147
2200
|
if (!isInlineComponent) {
|
|
2148
2201
|
container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
|
|
2149
2202
|
container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
|
|
2150
|
-
|
|
2151
|
-
container.setHostProp(renderHost, ELEMENT_PROPS, props);
|
|
2152
|
-
}
|
|
2203
|
+
container.setHostProp(renderHost, ELEMENT_PROPS, props);
|
|
2153
2204
|
}
|
|
2154
2205
|
if (vnode_isVNode(renderHost)) {
|
|
2155
|
-
|
|
2206
|
+
clearAllEffects(container, renderHost);
|
|
2156
2207
|
}
|
|
2157
2208
|
return componentFn(props);
|
|
2158
2209
|
}, (jsx) => {
|
|
2159
2210
|
const useOnEvents = container.getHostProp(renderHost, USE_ON_LOCAL);
|
|
2160
2211
|
if (useOnEvents) {
|
|
2161
|
-
return
|
|
2212
|
+
return addUseOnEvents(jsx, useOnEvents);
|
|
2162
2213
|
}
|
|
2163
2214
|
return jsx;
|
|
2164
2215
|
}, (err) => {
|
|
@@ -2184,6 +2235,7 @@
|
|
|
2184
2235
|
*/
|
|
2185
2236
|
function addUseOnEvents(jsx, useOnEvents) {
|
|
2186
2237
|
const jsxElement = findFirstStringJSX(jsx);
|
|
2238
|
+
let jsxResult = jsx;
|
|
2187
2239
|
return maybeThen(jsxElement, (jsxElement) => {
|
|
2188
2240
|
let isInvisibleComponent = false;
|
|
2189
2241
|
if (!jsxElement) {
|
|
@@ -2202,13 +2254,15 @@
|
|
|
2202
2254
|
if (Object.prototype.hasOwnProperty.call(useOnEvents, key)) {
|
|
2203
2255
|
if (isInvisibleComponent) {
|
|
2204
2256
|
if (key === 'onQvisible$') {
|
|
2205
|
-
jsxElement = addScriptNodeForInvisibleComponents(
|
|
2257
|
+
const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
|
|
2258
|
+
jsxResult = jsx;
|
|
2206
2259
|
if (jsxElement) {
|
|
2207
2260
|
addUseOnEvent(jsxElement, 'document:onQinit$', useOnEvents[key]);
|
|
2208
2261
|
}
|
|
2209
2262
|
}
|
|
2210
2263
|
else if (key.startsWith('document:') || key.startsWith('window:')) {
|
|
2211
|
-
jsxElement = addScriptNodeForInvisibleComponents(
|
|
2264
|
+
const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
|
|
2265
|
+
jsxResult = jsx;
|
|
2212
2266
|
if (jsxElement) {
|
|
2213
2267
|
addUseOnEvent(jsxElement, key, useOnEvents[key]);
|
|
2214
2268
|
}
|
|
@@ -2226,7 +2280,7 @@
|
|
|
2226
2280
|
}
|
|
2227
2281
|
}
|
|
2228
2282
|
}
|
|
2229
|
-
return
|
|
2283
|
+
return jsxResult;
|
|
2230
2284
|
});
|
|
2231
2285
|
}
|
|
2232
2286
|
function addUseOnEvent(jsxElement, key, value) {
|
|
@@ -2272,6 +2326,9 @@
|
|
|
2272
2326
|
type: 'placeholder',
|
|
2273
2327
|
hidden: '',
|
|
2274
2328
|
}, null, 3);
|
|
2329
|
+
if (jsx.type === Slot) {
|
|
2330
|
+
return [jsxElement, _jsxSorted(Fragment, null, null, [jsx, jsxElement], 0, null)];
|
|
2331
|
+
}
|
|
2275
2332
|
if (jsx.children == null) {
|
|
2276
2333
|
jsx.children = jsxElement;
|
|
2277
2334
|
}
|
|
@@ -2281,29 +2338,46 @@
|
|
|
2281
2338
|
else {
|
|
2282
2339
|
jsx.children = [jsx.children, jsxElement];
|
|
2283
2340
|
}
|
|
2284
|
-
return jsxElement;
|
|
2341
|
+
return [jsxElement, jsx];
|
|
2285
2342
|
}
|
|
2286
2343
|
else if (Array.isArray(jsx) && jsx.length) {
|
|
2287
2344
|
// get first element
|
|
2288
|
-
|
|
2345
|
+
const [jsxElement, _] = addScriptNodeForInvisibleComponents(jsx[0]);
|
|
2346
|
+
return [jsxElement, jsx];
|
|
2289
2347
|
}
|
|
2290
|
-
return null;
|
|
2348
|
+
return [null, null];
|
|
2291
2349
|
}
|
|
2292
2350
|
|
|
2351
|
+
/** @internal */
|
|
2352
|
+
const _CONST_PROPS = Symbol('CONST');
|
|
2353
|
+
/** @internal */
|
|
2354
|
+
const _VAR_PROPS = Symbol('VAR');
|
|
2355
|
+
/** @internal @deprecated v1 compat */
|
|
2356
|
+
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
2357
|
+
|
|
2293
2358
|
function isSlotProp(prop) {
|
|
2294
2359
|
return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
|
|
2295
2360
|
}
|
|
2296
|
-
function isParentSlotProp(prop) {
|
|
2297
|
-
return prop.startsWith(QSlotParent);
|
|
2298
|
-
}
|
|
2299
2361
|
/** @internal */
|
|
2300
2362
|
const _restProps = (props, omit, target = {}) => {
|
|
2301
|
-
|
|
2363
|
+
let constPropsTarget = null;
|
|
2364
|
+
const constProps = props[_CONST_PROPS];
|
|
2365
|
+
if (constProps) {
|
|
2366
|
+
for (const key in constProps) {
|
|
2367
|
+
if (!omit.includes(key)) {
|
|
2368
|
+
constPropsTarget ||= {};
|
|
2369
|
+
constPropsTarget[key] = constProps[key];
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
const varPropsTarget = target;
|
|
2374
|
+
const varProps = props[_VAR_PROPS];
|
|
2375
|
+
for (const key in varProps) {
|
|
2302
2376
|
if (!omit.includes(key)) {
|
|
2303
|
-
|
|
2377
|
+
varPropsTarget[key] = varProps[key];
|
|
2304
2378
|
}
|
|
2305
2379
|
}
|
|
2306
|
-
return
|
|
2380
|
+
return createPropsProxy(varPropsTarget, constPropsTarget);
|
|
2307
2381
|
};
|
|
2308
2382
|
|
|
2309
2383
|
function escapeHTML(html) {
|
|
@@ -2345,17 +2419,6 @@
|
|
|
2345
2419
|
}
|
|
2346
2420
|
}
|
|
2347
2421
|
|
|
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
2422
|
const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
2360
2423
|
let journal = container.$journal$;
|
|
2361
2424
|
/**
|
|
@@ -2374,9 +2437,9 @@
|
|
|
2374
2437
|
/// (Node can be null, if we are at the end of the list.)
|
|
2375
2438
|
let vCurrent = null;
|
|
2376
2439
|
/// 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 `
|
|
2440
|
+
/// NOTE: it can't be stored in `vCurrent` because `vNewNode` is in journal
|
|
2378
2441
|
/// and is not connected to the tree.
|
|
2379
|
-
let vNewNode = null;
|
|
2442
|
+
let vNewNode = null;
|
|
2380
2443
|
/// When elements have keys they can be consumed out of order and therefore we can't use nextSibling.
|
|
2381
2444
|
/// In such a case this array will contain the elements after the current location.
|
|
2382
2445
|
/// The array even indices will contains keys and odd indices the vNode.
|
|
@@ -2429,7 +2492,7 @@
|
|
|
2429
2492
|
}
|
|
2430
2493
|
else if (isSignal(jsxValue)) {
|
|
2431
2494
|
if (vCurrent) {
|
|
2432
|
-
|
|
2495
|
+
clearAllEffects(container, vCurrent);
|
|
2433
2496
|
}
|
|
2434
2497
|
expectVirtual(VirtualType.WrappedSignal, null);
|
|
2435
2498
|
descend(trackSignalAndAssignHost(jsxValue, (vNewNode || vCurrent), EffectProperty.VNODE, container), true);
|
|
@@ -2644,9 +2707,10 @@
|
|
|
2644
2707
|
};
|
|
2645
2708
|
const projections = [];
|
|
2646
2709
|
if (host) {
|
|
2710
|
+
const props = vnode_getProps(host);
|
|
2647
2711
|
// we need to create empty projections for all the slots to remove unused slots content
|
|
2648
|
-
for (let i =
|
|
2649
|
-
const prop =
|
|
2712
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
2713
|
+
const prop = props[i];
|
|
2650
2714
|
if (isSlotProp(prop)) {
|
|
2651
2715
|
const slotName = prop;
|
|
2652
2716
|
projections.push(slotName);
|
|
@@ -2687,6 +2751,8 @@
|
|
|
2687
2751
|
// console.log('expectProjection', JSON.stringify(slotName));
|
|
2688
2752
|
vCurrent = vnode_getProp(vParent, // The parent is the component and it should have our portal.
|
|
2689
2753
|
slotName, (id) => vnode_locate(container.rootVNode, id));
|
|
2754
|
+
// if projection is marked as deleted then we need to create a new one
|
|
2755
|
+
vCurrent = vCurrent && vCurrent[VNodeProps.flags] & VNodeFlags.Deleted ? null : vCurrent;
|
|
2690
2756
|
if (vCurrent == null) {
|
|
2691
2757
|
vNewNode = vnode_newVirtual();
|
|
2692
2758
|
// you may be tempted to add the projection into the current parent, but
|
|
@@ -2723,6 +2789,19 @@
|
|
|
2723
2789
|
}
|
|
2724
2790
|
else if (vProjectedNode === vCurrent) ;
|
|
2725
2791
|
else {
|
|
2792
|
+
const parent = vnode_getParent(vProjectedNode);
|
|
2793
|
+
const isAlreadyProjected = !!parent && !(vnode_isElementVNode(parent) && vnode_getElementName(parent) === QTemplate);
|
|
2794
|
+
if (isAlreadyProjected && vParent !== parent) {
|
|
2795
|
+
/**
|
|
2796
|
+
* The node is already projected, but structure has been changed. In next steps we will
|
|
2797
|
+
* insert the vProjectedNode at the end. However we will find existing projection elements
|
|
2798
|
+
* (from already projected THE SAME projection as vProjectedNode!) during
|
|
2799
|
+
* vnode_insertBefore. We need to remove vnode from the vnode tree to avoid referencing it
|
|
2800
|
+
* to self and cause infinite loop. Don't remove it from DOM to avoid additional operations
|
|
2801
|
+
* and flickering.
|
|
2802
|
+
*/
|
|
2803
|
+
vnode_remove(journal, parent, vProjectedNode, false);
|
|
2804
|
+
}
|
|
2726
2805
|
// move from q:template to the target node
|
|
2727
2806
|
vnode_insertBefore(journal, vParent, (vNewNode = vProjectedNode), vCurrent && getInsertBefore());
|
|
2728
2807
|
vnode_setProp(vNewNode, QSlot, slotNameKey);
|
|
@@ -2776,8 +2855,8 @@
|
|
|
2776
2855
|
while (vCurrent) {
|
|
2777
2856
|
const toRemove = vCurrent;
|
|
2778
2857
|
advanceToNextSibling();
|
|
2779
|
-
cleanup(container, toRemove);
|
|
2780
2858
|
if (vParent === vnode_getParent(toRemove)) {
|
|
2859
|
+
cleanup(container, toRemove);
|
|
2781
2860
|
// If we are diffing projection than the parent is not the parent of the node.
|
|
2782
2861
|
// If that is the case we don't want to remove the node from the parent.
|
|
2783
2862
|
vnode_remove(journal, vParent, toRemove, true);
|
|
@@ -2814,10 +2893,19 @@
|
|
|
2814
2893
|
// But we need to mark them so that they don't get pulled into the diff.
|
|
2815
2894
|
const eventName = getEventNameFromJsxProp(key);
|
|
2816
2895
|
const scope = getEventNameScopeFromJsxProp(key);
|
|
2817
|
-
vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
|
|
2818
2896
|
if (eventName) {
|
|
2897
|
+
vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
|
|
2819
2898
|
registerQwikLoaderEvent(eventName);
|
|
2820
2899
|
}
|
|
2900
|
+
if (scope) {
|
|
2901
|
+
// add an event attr with empty value for qwikloader element selector.
|
|
2902
|
+
// We don't need value here. For ssr this value is a QRL,
|
|
2903
|
+
// but for CSR value should be just empty
|
|
2904
|
+
const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
|
|
2905
|
+
if (htmlEvent) {
|
|
2906
|
+
vnode_setAttr(journal, vNewNode, htmlEvent, '');
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2821
2909
|
needsQDispatchEventPatch = true;
|
|
2822
2910
|
continue;
|
|
2823
2911
|
}
|
|
@@ -2830,12 +2918,15 @@
|
|
|
2830
2918
|
value(element);
|
|
2831
2919
|
continue;
|
|
2832
2920
|
}
|
|
2921
|
+
else if (value == null) {
|
|
2922
|
+
continue;
|
|
2923
|
+
}
|
|
2833
2924
|
else {
|
|
2834
2925
|
throw qError(QError.invalidRefValue, [currentFile]);
|
|
2835
2926
|
}
|
|
2836
2927
|
}
|
|
2837
2928
|
if (isSignal(value)) {
|
|
2838
|
-
const signalData = new
|
|
2929
|
+
const signalData = new SubscriptionData({
|
|
2839
2930
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
2840
2931
|
$isConst$: true,
|
|
2841
2932
|
});
|
|
@@ -2939,7 +3030,7 @@
|
|
|
2939
3030
|
let returnValue = false;
|
|
2940
3031
|
qrls.flat(2).forEach((qrl) => {
|
|
2941
3032
|
if (qrl) {
|
|
2942
|
-
const value = qrl
|
|
3033
|
+
const value = container.$scheduler$(ChoreType.RUN_QRL, vNode, qrl, [event, element]);
|
|
2943
3034
|
returnValue = returnValue || value === true;
|
|
2944
3035
|
}
|
|
2945
3036
|
});
|
|
@@ -2951,10 +3042,10 @@
|
|
|
2951
3042
|
/** @param tag Returns true if `qDispatchEvent` needs patching */
|
|
2952
3043
|
function setBulkProps(vnode, srcAttrs, currentFile) {
|
|
2953
3044
|
vnode_ensureElementInflated(vnode);
|
|
2954
|
-
const dstAttrs = vnode;
|
|
3045
|
+
const dstAttrs = vnode_getProps(vnode);
|
|
2955
3046
|
let srcIdx = 0;
|
|
2956
3047
|
const srcLength = srcAttrs.length;
|
|
2957
|
-
let dstIdx =
|
|
3048
|
+
let dstIdx = 0;
|
|
2958
3049
|
let dstLength = dstAttrs.length;
|
|
2959
3050
|
let srcKey = srcIdx < srcLength ? srcAttrs[srcIdx++] : null;
|
|
2960
3051
|
let dstKey = dstIdx < dstLength ? dstAttrs[dstIdx++] : null;
|
|
@@ -2974,12 +3065,15 @@
|
|
|
2974
3065
|
value(element);
|
|
2975
3066
|
return;
|
|
2976
3067
|
}
|
|
3068
|
+
else if (value == null) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
2977
3071
|
else {
|
|
2978
3072
|
throw qError(QError.invalidRefValue, [currentFile]);
|
|
2979
3073
|
}
|
|
2980
3074
|
}
|
|
2981
3075
|
if (isSignal(value)) {
|
|
2982
|
-
const signalData = new
|
|
3076
|
+
const signalData = new SubscriptionData({
|
|
2983
3077
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
2984
3078
|
$isConst$: false,
|
|
2985
3079
|
});
|
|
@@ -2993,21 +3087,21 @@
|
|
|
2993
3087
|
};
|
|
2994
3088
|
const recordJsxEvent = (key, value) => {
|
|
2995
3089
|
const eventName = getEventNameFromJsxProp(key);
|
|
3090
|
+
const scope = getEventNameScopeFromJsxProp(key);
|
|
2996
3091
|
if (eventName) {
|
|
2997
|
-
const scope = getEventNameScopeFromJsxProp(key);
|
|
2998
3092
|
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) {
|
|
3093
|
+
// register an event for qwik loader
|
|
3009
3094
|
registerQwikLoaderEvent(eventName);
|
|
3010
3095
|
}
|
|
3096
|
+
if (scope) {
|
|
3097
|
+
// add an event attr with empty value for qwikloader element selector.
|
|
3098
|
+
// We don't need value here. For ssr this value is a QRL,
|
|
3099
|
+
// but for CSR value should be just empty
|
|
3100
|
+
const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
|
|
3101
|
+
if (htmlEvent) {
|
|
3102
|
+
record(htmlEvent, '');
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3011
3105
|
};
|
|
3012
3106
|
while (srcKey !== null || dstKey !== null) {
|
|
3013
3107
|
if (dstKey?.startsWith(HANDLER_PREFIX) || dstKey?.startsWith(Q_PREFIX)) {
|
|
@@ -3202,14 +3296,8 @@
|
|
|
3202
3296
|
}
|
|
3203
3297
|
else if (!hashesAreEqual) {
|
|
3204
3298
|
insertNewComponent(host, componentQRL, jsxProps);
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
// TODO(varixo): not sure why we need to copy flags here.
|
|
3208
|
-
vNewNode[VNodeProps.flags] = host[VNodeProps.flags];
|
|
3209
|
-
}
|
|
3210
|
-
host = vNewNode;
|
|
3211
|
-
shouldRender = true;
|
|
3212
|
-
}
|
|
3299
|
+
host = vNewNode;
|
|
3300
|
+
shouldRender = true;
|
|
3213
3301
|
}
|
|
3214
3302
|
if (host) {
|
|
3215
3303
|
const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
|
|
@@ -3230,6 +3318,7 @@
|
|
|
3230
3318
|
const lookupKey = jsxNode.key;
|
|
3231
3319
|
const vNodeLookupKey = getKey(host);
|
|
3232
3320
|
const lookupKeysAreEqual = lookupKey === vNodeLookupKey;
|
|
3321
|
+
const vNodeComponentHash = getComponentHash(host, container.$getObjectById$);
|
|
3233
3322
|
if (!lookupKeysAreEqual) {
|
|
3234
3323
|
// See if we already have this inline component later on.
|
|
3235
3324
|
vNewNode = retrieveChildWithKey(null, lookupKey);
|
|
@@ -3243,6 +3332,11 @@
|
|
|
3243
3332
|
}
|
|
3244
3333
|
host = vNewNode;
|
|
3245
3334
|
}
|
|
3335
|
+
// inline components don't have component hash - q:renderFn prop, so it should be null
|
|
3336
|
+
else if (vNodeComponentHash != null) {
|
|
3337
|
+
insertNewInlineComponent();
|
|
3338
|
+
host = vNewNode;
|
|
3339
|
+
}
|
|
3246
3340
|
if (host) {
|
|
3247
3341
|
let componentHost = host;
|
|
3248
3342
|
// Find the closest component host which has `OnRender` prop. This is need for subscriptions context.
|
|
@@ -3259,7 +3353,7 @@
|
|
|
3259
3353
|
}
|
|
3260
3354
|
function insertNewComponent(host, componentQRL, jsxProps) {
|
|
3261
3355
|
if (host) {
|
|
3262
|
-
|
|
3356
|
+
clearAllEffects(container, host);
|
|
3263
3357
|
}
|
|
3264
3358
|
vnode_insertBefore(journal, vParent, (vNewNode = vnode_newVirtual()), vCurrent && getInsertBefore());
|
|
3265
3359
|
const jsxNode = jsxValue;
|
|
@@ -3347,8 +3441,8 @@
|
|
|
3347
3441
|
if (!src || !dst) {
|
|
3348
3442
|
return true;
|
|
3349
3443
|
}
|
|
3350
|
-
let srcKeys = removePropsKeys(Object.keys(src), ['children',
|
|
3351
|
-
let dstKeys = removePropsKeys(Object.keys(dst), ['children',
|
|
3444
|
+
let srcKeys = removePropsKeys(Object.keys(src), ['children', QBackRefs]);
|
|
3445
|
+
let dstKeys = removePropsKeys(Object.keys(dst), ['children', QBackRefs]);
|
|
3352
3446
|
if (srcKeys.length !== dstKeys.length) {
|
|
3353
3447
|
return true;
|
|
3354
3448
|
}
|
|
@@ -3387,6 +3481,7 @@
|
|
|
3387
3481
|
let vCursor = vNode;
|
|
3388
3482
|
// Depth first traversal
|
|
3389
3483
|
if (vnode_isTextVNode(vNode)) {
|
|
3484
|
+
markVNodeAsDeleted(vCursor);
|
|
3390
3485
|
// Text nodes don't have subscriptions or children;
|
|
3391
3486
|
return;
|
|
3392
3487
|
}
|
|
@@ -3394,7 +3489,7 @@
|
|
|
3394
3489
|
do {
|
|
3395
3490
|
const type = vCursor[VNodeProps.flags];
|
|
3396
3491
|
if (type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) {
|
|
3397
|
-
|
|
3492
|
+
clearAllEffects(container, vCursor);
|
|
3398
3493
|
markVNodeAsDeleted(vCursor);
|
|
3399
3494
|
// Only elements and virtual nodes need to be traversed for children
|
|
3400
3495
|
if (type & VNodeFlags.Virtual) {
|
|
@@ -3404,7 +3499,7 @@
|
|
|
3404
3499
|
const obj = seq[i];
|
|
3405
3500
|
if (isTask(obj)) {
|
|
3406
3501
|
const task = obj;
|
|
3407
|
-
|
|
3502
|
+
clearAllEffects(container, task);
|
|
3408
3503
|
if (task.$flags$ & TaskFlags.VISIBLE_TASK) {
|
|
3409
3504
|
container.$scheduler$(ChoreType.CLEANUP_VISIBLE, task);
|
|
3410
3505
|
}
|
|
@@ -3419,10 +3514,10 @@
|
|
|
3419
3514
|
vnode_getProp(vCursor, OnRenderProp, null) !== null;
|
|
3420
3515
|
if (isComponent) {
|
|
3421
3516
|
// 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 =
|
|
3517
|
+
const attrs = vnode_getProps(vCursor);
|
|
3518
|
+
for (let i = 0; i < attrs.length; i = i + 2) {
|
|
3424
3519
|
const key = attrs[i];
|
|
3425
|
-
if (
|
|
3520
|
+
if (isSlotProp(key)) {
|
|
3426
3521
|
const value = attrs[i + 1];
|
|
3427
3522
|
if (value) {
|
|
3428
3523
|
attrs[i + 1] = null; // prevent infinite loop
|
|
@@ -3439,7 +3534,7 @@
|
|
|
3439
3534
|
}
|
|
3440
3535
|
}
|
|
3441
3536
|
}
|
|
3442
|
-
const isProjection =
|
|
3537
|
+
const isProjection = vnode_isProjection(vCursor);
|
|
3443
3538
|
// Descend into children
|
|
3444
3539
|
if (!isProjection) {
|
|
3445
3540
|
// Only if it is not a projection
|
|
@@ -3462,6 +3557,9 @@
|
|
|
3462
3557
|
}
|
|
3463
3558
|
}
|
|
3464
3559
|
}
|
|
3560
|
+
else if (type & VNodeFlags.Text) {
|
|
3561
|
+
markVNodeAsDeleted(vCursor);
|
|
3562
|
+
}
|
|
3465
3563
|
// Out of children
|
|
3466
3564
|
if (vCursor === vNode) {
|
|
3467
3565
|
// we are where we started, this means that vNode has no children, so we are done.
|
|
@@ -3528,82 +3626,270 @@
|
|
|
3528
3626
|
SiblingsArray[SiblingsArray["NextVNode"] = 5] = "NextVNode";
|
|
3529
3627
|
})(SiblingsArray || (SiblingsArray = {}));
|
|
3530
3628
|
|
|
3531
|
-
|
|
3629
|
+
/** @internal */
|
|
3630
|
+
const useResourceQrl = (qrl, opts) => {
|
|
3631
|
+
const { val, set, i, iCtx } = useSequentialScope();
|
|
3632
|
+
if (val != null) {
|
|
3633
|
+
return val;
|
|
3634
|
+
}
|
|
3635
|
+
assertQrl(qrl);
|
|
3636
|
+
const container = iCtx.$container$;
|
|
3637
|
+
const resource = createResourceReturn(container, opts);
|
|
3638
|
+
const el = iCtx.$hostElement$;
|
|
3639
|
+
const task = new Task(TaskFlags.DIRTY | TaskFlags.RESOURCE, i, el, qrl, resource, null);
|
|
3640
|
+
container.$scheduler$(ChoreType.TASK, task);
|
|
3641
|
+
set(resource);
|
|
3642
|
+
return resource;
|
|
3643
|
+
};
|
|
3644
|
+
// <docs markdown="../readme.md#useResource">
|
|
3532
3645
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
3533
|
-
// (edit
|
|
3646
|
+
// (edit ../readme.md#useResource instead and run `pnpm docs.sync`)
|
|
3534
3647
|
/**
|
|
3535
|
-
*
|
|
3648
|
+
* This method works like an async memoized function that runs whenever some tracked value changes
|
|
3649
|
+
* and returns some data.
|
|
3536
3650
|
*
|
|
3537
|
-
*
|
|
3538
|
-
*
|
|
3539
|
-
* in `$`.
|
|
3651
|
+
* `useResource` however returns immediate a `ResourceReturn` object that contains the data and a
|
|
3652
|
+
* state that indicates if the data is available or not.
|
|
3540
3653
|
*
|
|
3541
|
-
*
|
|
3542
|
-
* The former is just a shorthand for the latter.
|
|
3654
|
+
* The status can be one of the following:
|
|
3543
3655
|
*
|
|
3544
|
-
*
|
|
3656
|
+
* - `pending` - the data is not yet available.
|
|
3657
|
+
* - `resolved` - the data is available.
|
|
3658
|
+
* - `rejected` - the data is not available due to an error or timeout.
|
|
3545
3659
|
*
|
|
3546
|
-
*
|
|
3660
|
+
* Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
|
|
3661
|
+
* re-throw it (or a new Error), the resource status will never be `rejected`.
|
|
3547
3662
|
*
|
|
3548
|
-
*
|
|
3549
|
-
* export function myApi(callback: QRL<() => void>): void {
|
|
3550
|
-
* // ...
|
|
3551
|
-
* }
|
|
3663
|
+
* ### Example
|
|
3552
3664
|
*
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
3665
|
+
* Example showing how `useResource` to perform a fetch to request the weather, whenever the input
|
|
3666
|
+
* city name changes.
|
|
3555
3667
|
*
|
|
3556
|
-
*
|
|
3557
|
-
*
|
|
3668
|
+
* ```tsx
|
|
3669
|
+
* const Cmp = component$(() => {
|
|
3670
|
+
* const cityS = useSignal('');
|
|
3558
3671
|
*
|
|
3559
|
-
*
|
|
3560
|
-
*
|
|
3561
|
-
*
|
|
3672
|
+
* const weatherResource = useResource$(async ({ track, cleanup }) => {
|
|
3673
|
+
* const cityName = track(cityS);
|
|
3674
|
+
* const abortController = new AbortController();
|
|
3675
|
+
* cleanup(() => abortController.abort('cleanup'));
|
|
3676
|
+
* const res = await fetch(`http://weatherdata.com?city=${cityName}`, {
|
|
3677
|
+
* signal: abortController.signal,
|
|
3678
|
+
* });
|
|
3679
|
+
* const data = await res.json();
|
|
3680
|
+
* return data as { temp: number };
|
|
3681
|
+
* });
|
|
3562
3682
|
*
|
|
3563
|
-
*
|
|
3564
|
-
*
|
|
3683
|
+
* return (
|
|
3684
|
+
* <div>
|
|
3685
|
+
* <input name="city" bind:value={cityS} />
|
|
3686
|
+
* <Resource
|
|
3687
|
+
* value={weatherResource}
|
|
3688
|
+
* onResolved={(weather) => {
|
|
3689
|
+
* return <div>Temperature: {weather.temp}</div>;
|
|
3690
|
+
* }}
|
|
3691
|
+
* />
|
|
3692
|
+
* </div>
|
|
3693
|
+
* );
|
|
3694
|
+
* });
|
|
3565
3695
|
* ```
|
|
3566
3696
|
*
|
|
3567
|
-
* @param fn - A function that should have its first argument automatically `$`.
|
|
3568
3697
|
* @public
|
|
3698
|
+
* @see Resource
|
|
3699
|
+
* @see ResourceReturn
|
|
3569
3700
|
*/
|
|
3570
3701
|
// </docs>
|
|
3571
|
-
const
|
|
3572
|
-
|
|
3573
|
-
|
|
3702
|
+
const Resource = (props) => {
|
|
3703
|
+
// Resource path
|
|
3704
|
+
return _jsxSorted(Fragment, null, null, getResourceValueAsPromise(props), 0, null);
|
|
3705
|
+
};
|
|
3706
|
+
function getResourceValueAsPromise(props) {
|
|
3707
|
+
const resource = props.value;
|
|
3708
|
+
if (isResourceReturn(resource) && resource.value) {
|
|
3709
|
+
const isBrowser = !isServerPlatform();
|
|
3710
|
+
if (isBrowser) {
|
|
3711
|
+
// create a subscription for the resource._state changes
|
|
3712
|
+
const state = resource._state;
|
|
3713
|
+
if (state === 'pending' && props.onPending) {
|
|
3714
|
+
return Promise.resolve().then(useBindInvokeContext(props.onPending));
|
|
3715
|
+
}
|
|
3716
|
+
else if (state === 'rejected' && props.onRejected) {
|
|
3717
|
+
return Promise.resolve(resource._error).then(useBindInvokeContext(props.onRejected));
|
|
3718
|
+
}
|
|
3719
|
+
else {
|
|
3720
|
+
const resolvedValue = untrack(() => resource._resolved);
|
|
3721
|
+
if (resolvedValue !== undefined) {
|
|
3722
|
+
// resolved, pending without onPending prop or rejected without onRejected prop
|
|
3723
|
+
return Promise.resolve(resolvedValue).then(useBindInvokeContext(props.onResolved));
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
return resource.value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3728
|
+
}
|
|
3729
|
+
else if (isPromise(resource)) {
|
|
3730
|
+
return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3731
|
+
}
|
|
3732
|
+
else if (isSignal(resource)) {
|
|
3733
|
+
return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3734
|
+
}
|
|
3735
|
+
else {
|
|
3736
|
+
return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
const _createResourceReturn = (opts) => {
|
|
3740
|
+
const resource = {
|
|
3741
|
+
__brand: 'resource',
|
|
3742
|
+
value: undefined,
|
|
3743
|
+
loading: isServerPlatform() ? false : true,
|
|
3744
|
+
_resolved: undefined,
|
|
3745
|
+
_error: undefined,
|
|
3746
|
+
_state: 'pending',
|
|
3747
|
+
_timeout: opts?.timeout ?? -1,
|
|
3748
|
+
_cache: 0,
|
|
3574
3749
|
};
|
|
3750
|
+
return resource;
|
|
3575
3751
|
};
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3752
|
+
const createResourceReturn = (container, opts, initialPromise) => {
|
|
3753
|
+
const result = _createResourceReturn(opts);
|
|
3754
|
+
result.value = initialPromise;
|
|
3755
|
+
return createStore(container, result, StoreFlags.RECURSIVE);
|
|
3579
3756
|
};
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
|
|
3757
|
+
const isResourceReturn = (obj) => {
|
|
3758
|
+
return isObject(obj) && (getStoreTarget(obj) || obj).__brand === 'resource';
|
|
3759
|
+
};
|
|
3760
|
+
const runResource = (task, container, host) => {
|
|
3761
|
+
task.$flags$ &= ~TaskFlags.DIRTY;
|
|
3762
|
+
cleanupTask(task);
|
|
3763
|
+
const iCtx = newInvokeContext(container.$locale$, host, undefined, ResourceEvent);
|
|
3764
|
+
iCtx.$container$ = container;
|
|
3765
|
+
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
3766
|
+
const resource = task.$state$;
|
|
3767
|
+
assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
|
|
3768
|
+
const track = (obj, prop) => {
|
|
3769
|
+
const ctx = newInvokeContext();
|
|
3770
|
+
ctx.$effectSubscriber$ = getSubscriber(task, EffectProperty.COMPONENT);
|
|
3771
|
+
ctx.$container$ = container;
|
|
3772
|
+
return invoke(ctx, () => {
|
|
3773
|
+
if (isFunction(obj)) {
|
|
3774
|
+
return obj();
|
|
3775
|
+
}
|
|
3776
|
+
if (prop) {
|
|
3777
|
+
return obj[prop];
|
|
3778
|
+
}
|
|
3779
|
+
else if (isSignal(obj)) {
|
|
3780
|
+
return obj.value;
|
|
3781
|
+
}
|
|
3782
|
+
else {
|
|
3783
|
+
return obj;
|
|
3784
|
+
}
|
|
3785
|
+
});
|
|
3786
|
+
};
|
|
3787
|
+
const handleError = (reason) => container.handleError(reason, host);
|
|
3788
|
+
const cleanups = [];
|
|
3789
|
+
task.$destroy$ = noSerialize(() => {
|
|
3790
|
+
cleanups.forEach((fn) => {
|
|
3791
|
+
try {
|
|
3792
|
+
fn();
|
|
3793
|
+
}
|
|
3794
|
+
catch (err) {
|
|
3795
|
+
handleError(err);
|
|
3796
|
+
}
|
|
3797
|
+
});
|
|
3798
|
+
done = true;
|
|
3799
|
+
});
|
|
3800
|
+
const resourceTarget = unwrapStore(resource);
|
|
3801
|
+
const opts = {
|
|
3802
|
+
track,
|
|
3803
|
+
cleanup(fn) {
|
|
3804
|
+
if (typeof fn === 'function') {
|
|
3805
|
+
cleanups.push(fn);
|
|
3806
|
+
}
|
|
3807
|
+
},
|
|
3808
|
+
cache(policy) {
|
|
3809
|
+
let milliseconds = 0;
|
|
3810
|
+
if (policy === 'immutable') {
|
|
3811
|
+
milliseconds = Infinity;
|
|
3812
|
+
}
|
|
3813
|
+
else {
|
|
3814
|
+
milliseconds = policy;
|
|
3815
|
+
}
|
|
3816
|
+
resource._cache = milliseconds;
|
|
3817
|
+
},
|
|
3818
|
+
previous: resourceTarget._resolved,
|
|
3819
|
+
};
|
|
3820
|
+
let resolve;
|
|
3821
|
+
let reject;
|
|
3822
|
+
let done = false;
|
|
3823
|
+
const setState = (resolved, value) => {
|
|
3824
|
+
if (!done) {
|
|
3825
|
+
done = true;
|
|
3826
|
+
if (resolved) {
|
|
3827
|
+
done = true;
|
|
3828
|
+
resource.loading = false;
|
|
3829
|
+
resource._state = 'resolved';
|
|
3830
|
+
resource._resolved = value;
|
|
3831
|
+
resource._error = undefined;
|
|
3832
|
+
resolve(value);
|
|
3833
|
+
}
|
|
3834
|
+
else {
|
|
3835
|
+
done = true;
|
|
3836
|
+
resource.loading = false;
|
|
3837
|
+
resource._state = 'rejected';
|
|
3838
|
+
resource._error = value;
|
|
3839
|
+
reject(value);
|
|
3840
|
+
}
|
|
3841
|
+
return true;
|
|
3842
|
+
}
|
|
3843
|
+
return false;
|
|
3844
|
+
};
|
|
3845
|
+
/**
|
|
3846
|
+
* Add cleanup to resolve the resource if we are trying to run the same resource again while the
|
|
3847
|
+
* previous one is not resolved yet. The next `runResource` run will call this cleanup
|
|
3848
|
+
*/
|
|
3849
|
+
cleanups.push(() => {
|
|
3850
|
+
if (untrack(() => resource.loading) === true) {
|
|
3851
|
+
const value = untrack(() => resource._resolved);
|
|
3852
|
+
setState(true, value);
|
|
3853
|
+
}
|
|
3854
|
+
});
|
|
3855
|
+
// Execute mutation inside empty invocation
|
|
3856
|
+
invoke(iCtx, () => {
|
|
3857
|
+
// console.log('RESOURCE.pending: ');
|
|
3858
|
+
resource._state = 'pending';
|
|
3859
|
+
resource.loading = !isServerPlatform();
|
|
3860
|
+
const promise = (resource.value = new Promise((r, re) => {
|
|
3861
|
+
resolve = r;
|
|
3862
|
+
reject = re;
|
|
3863
|
+
}));
|
|
3864
|
+
promise.catch(ignoreErrorToPreventNodeFromCrashing);
|
|
3865
|
+
});
|
|
3866
|
+
const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
|
|
3867
|
+
setState(true, value);
|
|
3868
|
+
}, (err) => {
|
|
3869
|
+
if (isPromise(err)) {
|
|
3870
|
+
return err.then(() => runResource(task, container, host));
|
|
3871
|
+
}
|
|
3872
|
+
else {
|
|
3873
|
+
setState(false, err);
|
|
3874
|
+
}
|
|
3875
|
+
});
|
|
3876
|
+
const timeout = resourceTarget._timeout;
|
|
3877
|
+
if (timeout > 0) {
|
|
3878
|
+
return Promise.race([
|
|
3879
|
+
promise,
|
|
3880
|
+
delay(timeout).then(() => {
|
|
3881
|
+
if (setState(false, new Error('timeout'))) {
|
|
3882
|
+
cleanupTask(task);
|
|
3883
|
+
}
|
|
3884
|
+
}),
|
|
3885
|
+
]);
|
|
3886
|
+
}
|
|
3887
|
+
return promise;
|
|
3888
|
+
};
|
|
3889
|
+
const ignoreErrorToPreventNodeFromCrashing = (err) => {
|
|
3890
|
+
// ignore error to prevent node from crashing
|
|
3891
|
+
// node will crash in promise is rejected and no one is listening to the rejection.
|
|
3583
3892
|
};
|
|
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
3893
|
|
|
3608
3894
|
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
|
|
3609
3895
|
const aVNodePath = [];
|
|
@@ -3788,38 +4074,29 @@
|
|
|
3788
4074
|
* - Visible Tasks are sorted afterJournalFlush, than depth first on component and finally in
|
|
3789
4075
|
* declaration order within component.
|
|
3790
4076
|
*/
|
|
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 = {}));
|
|
4077
|
+
// Turn this on to get debug output of what the scheduler is doing.
|
|
4078
|
+
const DEBUG$1 = false;
|
|
4079
|
+
const getPromise = (chore) => (chore.$promise$ ||= new Promise((resolve) => {
|
|
4080
|
+
chore.$resolve$ = resolve;
|
|
4081
|
+
}));
|
|
3811
4082
|
const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
3812
4083
|
const choreQueue = [];
|
|
4084
|
+
const qrlRuns = [];
|
|
3813
4085
|
let currentChore = null;
|
|
3814
|
-
let
|
|
4086
|
+
let drainScheduled = false;
|
|
3815
4087
|
return schedule;
|
|
3816
4088
|
///// IMPLEMENTATION /////
|
|
3817
4089
|
function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
|
|
3818
|
-
const
|
|
3819
|
-
const
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
4090
|
+
const isServer = !isDomContainer(container);
|
|
4091
|
+
const isComponentSsr = isServer && type === ChoreType.COMPONENT;
|
|
4092
|
+
const runLater = type !== ChoreType.WAIT_FOR_ALL && !isComponentSsr && type !== ChoreType.RUN_QRL;
|
|
4093
|
+
const isTask = type === ChoreType.TASK || type === ChoreType.VISIBLE || type === ChoreType.CLEANUP_VISIBLE;
|
|
4094
|
+
const isClientOnly = type === ChoreType.JOURNAL_FLUSH ||
|
|
4095
|
+
type === ChoreType.NODE_DIFF ||
|
|
4096
|
+
type === ChoreType.NODE_PROP;
|
|
4097
|
+
if (isServer && isClientOnly) {
|
|
4098
|
+
return;
|
|
4099
|
+
}
|
|
3823
4100
|
if (isTask) {
|
|
3824
4101
|
hostOrTask.$flags$ |= TaskFlags.DIRTY;
|
|
3825
4102
|
}
|
|
@@ -3838,192 +4115,234 @@
|
|
|
3838
4115
|
$returnValue$: null,
|
|
3839
4116
|
$executed$: false,
|
|
3840
4117
|
};
|
|
3841
|
-
chore.$promise$ = new Promise((resolve) => (chore.$resolve$ = resolve));
|
|
3842
4118
|
chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
|
|
3843
|
-
if (!
|
|
4119
|
+
if (!drainScheduled && runLater) {
|
|
3844
4120
|
// If we are not currently draining, we need to schedule a drain.
|
|
3845
|
-
|
|
4121
|
+
drainScheduled = true;
|
|
3846
4122
|
schedule(ChoreType.JOURNAL_FLUSH);
|
|
3847
|
-
|
|
4123
|
+
// Catch here to avoid unhandled promise rejection
|
|
4124
|
+
scheduleDrain()?.catch?.(() => { });
|
|
3848
4125
|
}
|
|
4126
|
+
// TODO figure out what to do with chore errors
|
|
3849
4127
|
if (runLater) {
|
|
3850
|
-
return chore
|
|
4128
|
+
return getPromise(chore);
|
|
3851
4129
|
}
|
|
3852
4130
|
else {
|
|
3853
|
-
return drainUpTo(chore,
|
|
4131
|
+
return drainUpTo(chore, isServer);
|
|
3854
4132
|
}
|
|
3855
4133
|
}
|
|
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
|
-
}
|
|
4134
|
+
/** Execute all of the chores up to and including the given chore. */
|
|
4135
|
+
function drainUpTo(runUptoChore, isServer) {
|
|
4136
|
+
let maxRetries = 5000;
|
|
3870
4137
|
while (choreQueue.length) {
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
if (order === null) {
|
|
3874
|
-
continue;
|
|
4138
|
+
if (maxRetries-- < 0) {
|
|
4139
|
+
throw new Error('drainUpTo: max retries reached');
|
|
3875
4140
|
}
|
|
3876
|
-
if (
|
|
3877
|
-
//
|
|
3878
|
-
|
|
4141
|
+
if (currentChore) {
|
|
4142
|
+
// Already running chore, which means we're waiting for async completion
|
|
4143
|
+
return getPromise(currentChore)
|
|
4144
|
+
.then(() => drainUpTo(runUptoChore, isServer))
|
|
4145
|
+
.catch((e) => {
|
|
4146
|
+
container.handleError(e, currentChore?.$host$);
|
|
4147
|
+
});
|
|
4148
|
+
}
|
|
4149
|
+
const nextChore = choreQueue[0];
|
|
4150
|
+
if (nextChore.$executed$) {
|
|
4151
|
+
choreQueue.shift();
|
|
4152
|
+
if (nextChore === runUptoChore) {
|
|
4153
|
+
break;
|
|
4154
|
+
}
|
|
4155
|
+
continue;
|
|
3879
4156
|
}
|
|
3880
|
-
|
|
3881
|
-
if (isDeletedVNode &&
|
|
4157
|
+
if (vNodeAlreadyDeleted(nextChore) &&
|
|
3882
4158
|
// we need to process cleanup tasks for deleted nodes
|
|
3883
4159
|
nextChore.$type$ !== ChoreType.CLEANUP_VISIBLE) {
|
|
4160
|
+
choreQueue.shift();
|
|
3884
4161
|
continue;
|
|
3885
4162
|
}
|
|
3886
|
-
|
|
3887
|
-
if (isPromise(returnValue)) {
|
|
3888
|
-
const promise = returnValue.then(() => drainUpTo(runUptoChore, rootVNode));
|
|
3889
|
-
return promise;
|
|
3890
|
-
}
|
|
4163
|
+
executeChore(nextChore, isServer);
|
|
3891
4164
|
}
|
|
3892
4165
|
return runUptoChore.$returnValue$;
|
|
3893
4166
|
}
|
|
3894
|
-
function executeChore(chore) {
|
|
4167
|
+
function executeChore(chore, isServer) {
|
|
3895
4168
|
const host = chore.$host$;
|
|
3896
4169
|
assertEqual(currentChore, null, 'Chore already running.');
|
|
3897
4170
|
currentChore = chore;
|
|
3898
4171
|
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)));
|
|
4172
|
+
try {
|
|
4173
|
+
switch (chore.$type$) {
|
|
4174
|
+
case ChoreType.WAIT_FOR_ALL:
|
|
4175
|
+
{
|
|
4176
|
+
if (isServer) {
|
|
4177
|
+
drainScheduled = false;
|
|
4178
|
+
}
|
|
3910
4179
|
}
|
|
3911
|
-
|
|
3912
|
-
|
|
4180
|
+
break;
|
|
4181
|
+
case ChoreType.JOURNAL_FLUSH:
|
|
4182
|
+
{
|
|
4183
|
+
returnValue = journalFlush();
|
|
4184
|
+
drainScheduled = false;
|
|
4185
|
+
}
|
|
4186
|
+
break;
|
|
4187
|
+
case ChoreType.COMPONENT:
|
|
4188
|
+
{
|
|
4189
|
+
returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
|
|
4190
|
+
if (isServer) {
|
|
4191
|
+
return jsx;
|
|
4192
|
+
}
|
|
4193
|
+
else {
|
|
4194
|
+
const styleScopedId = container.getHostProp(host, QScopedStyle);
|
|
4195
|
+
return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
|
|
4196
|
+
}
|
|
4197
|
+
}, (err) => container.handleError(err, host));
|
|
4198
|
+
}
|
|
4199
|
+
break;
|
|
4200
|
+
case ChoreType.RUN_QRL:
|
|
4201
|
+
{
|
|
4202
|
+
const fn = chore.$target$.getFn();
|
|
4203
|
+
const result = retryOnPromise(() => fn(...chore.$payload$));
|
|
4204
|
+
if (isPromise(result)) {
|
|
4205
|
+
const handled = result
|
|
4206
|
+
.finally(() => {
|
|
4207
|
+
qrlRuns.splice(qrlRuns.indexOf(handled), 1);
|
|
4208
|
+
})
|
|
4209
|
+
.catch((error) => {
|
|
4210
|
+
container.handleError(error, chore.$host$);
|
|
4211
|
+
});
|
|
4212
|
+
// Don't wait for the promise to resolve
|
|
4213
|
+
// TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
|
|
4214
|
+
qrlRuns.push(handled);
|
|
4215
|
+
DEBUG$1 &&
|
|
4216
|
+
debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
|
|
4217
|
+
chore.$returnValue$ = handled;
|
|
4218
|
+
chore.$resolve$?.(handled);
|
|
4219
|
+
currentChore = null;
|
|
4220
|
+
chore.$executed$ = true;
|
|
4221
|
+
// early out so we don't call after()
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
returnValue = null;
|
|
4225
|
+
}
|
|
4226
|
+
break;
|
|
4227
|
+
case ChoreType.TASK:
|
|
4228
|
+
case ChoreType.VISIBLE:
|
|
4229
|
+
{
|
|
4230
|
+
const payload = chore.$payload$;
|
|
4231
|
+
if (payload.$flags$ & TaskFlags.RESOURCE) {
|
|
4232
|
+
const result = runResource(payload, container, host);
|
|
4233
|
+
// Don't await the return value of the resource, because async resources should not be awaited.
|
|
4234
|
+
// The reason for this is that we should be able to update for example a node with loading
|
|
4235
|
+
// text. If we await the resource, the loading text will not be displayed until the resource
|
|
4236
|
+
// is loaded.
|
|
4237
|
+
// Awaiting on the client also causes a deadlock.
|
|
4238
|
+
// In any case, the resource will never throw.
|
|
4239
|
+
returnValue = isServer ? result : null;
|
|
4240
|
+
}
|
|
4241
|
+
else {
|
|
4242
|
+
returnValue = runTask(payload, container, host);
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
break;
|
|
4246
|
+
case ChoreType.CLEANUP_VISIBLE:
|
|
4247
|
+
{
|
|
4248
|
+
const task = chore.$payload$;
|
|
4249
|
+
cleanupTask(task);
|
|
4250
|
+
}
|
|
4251
|
+
break;
|
|
4252
|
+
case ChoreType.NODE_DIFF:
|
|
4253
|
+
{
|
|
4254
|
+
const parentVirtualNode = chore.$target$;
|
|
4255
|
+
let jsx = chore.$payload$;
|
|
4256
|
+
if (isSignal(jsx)) {
|
|
4257
|
+
jsx = jsx.value;
|
|
4258
|
+
}
|
|
4259
|
+
returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
|
|
4260
|
+
}
|
|
4261
|
+
break;
|
|
4262
|
+
case ChoreType.NODE_PROP:
|
|
4263
|
+
{
|
|
4264
|
+
const virtualNode = chore.$host$;
|
|
4265
|
+
const payload = chore.$payload$;
|
|
4266
|
+
let value = payload.$value$;
|
|
4267
|
+
if (isSignal(value)) {
|
|
4268
|
+
value = value.value;
|
|
4269
|
+
}
|
|
4270
|
+
const isConst = payload.$isConst$;
|
|
4271
|
+
const journal = container.$journal$;
|
|
4272
|
+
const property = chore.$idx$;
|
|
4273
|
+
const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
|
|
4274
|
+
if (isConst) {
|
|
4275
|
+
const element = virtualNode[ElementVNodeProps.element];
|
|
4276
|
+
journal.push(VNodeJournalOpCode.SetAttribute, element, property, serializedValue);
|
|
4277
|
+
}
|
|
4278
|
+
else {
|
|
4279
|
+
vnode_setAttr(journal, virtualNode, property, serializedValue);
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
break;
|
|
4283
|
+
case ChoreType.QRL_RESOLVE: {
|
|
4284
|
+
{
|
|
4285
|
+
const target = chore.$target$;
|
|
4286
|
+
returnValue = !target.resolved ? target.resolve() : null;
|
|
3913
4287
|
}
|
|
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
4288
|
break;
|
|
3972
4289
|
}
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
4290
|
+
case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
|
|
4291
|
+
{
|
|
4292
|
+
const target = chore.$target$;
|
|
4293
|
+
const forceRunEffects = target.$forceRunEffects$;
|
|
4294
|
+
target.$forceRunEffects$ = false;
|
|
4295
|
+
if (!target.$effects$?.size) {
|
|
4296
|
+
break;
|
|
4297
|
+
}
|
|
4298
|
+
returnValue = retryOnPromise(() => {
|
|
4299
|
+
if (target.$computeIfNeeded$() || forceRunEffects) {
|
|
4300
|
+
triggerEffects(container, target, target.$effects$);
|
|
4301
|
+
}
|
|
4302
|
+
});
|
|
3976
4303
|
}
|
|
3977
|
-
|
|
3978
|
-
|
|
4304
|
+
break;
|
|
4305
|
+
}
|
|
3979
4306
|
}
|
|
3980
4307
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
}
|
|
4308
|
+
catch (e) {
|
|
4309
|
+
returnValue = Promise.reject(e);
|
|
4310
|
+
}
|
|
4311
|
+
const after = (value, error) => {
|
|
3986
4312
|
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;
|
|
4313
|
+
chore.$executed$ = true;
|
|
4314
|
+
if (error) {
|
|
4315
|
+
container.handleError(error, host);
|
|
4316
|
+
}
|
|
4317
|
+
else {
|
|
4318
|
+
chore.$returnValue$ = value;
|
|
4319
|
+
chore.$resolve$?.(value);
|
|
4320
|
+
}
|
|
4321
|
+
};
|
|
4322
|
+
if (isPromise(returnValue)) {
|
|
4323
|
+
chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
|
|
4324
|
+
chore.$resolve$?.(chore.$promise$);
|
|
4325
|
+
chore.$resolve$ = undefined;
|
|
4326
|
+
}
|
|
4327
|
+
else {
|
|
4328
|
+
after(returnValue);
|
|
4329
|
+
}
|
|
4021
4330
|
}
|
|
4022
|
-
|
|
4023
|
-
|
|
4331
|
+
/**
|
|
4332
|
+
* Compares two chores to determine their execution order in the scheduler's queue.
|
|
4333
|
+
*
|
|
4334
|
+
* @param a - The first chore to compare
|
|
4335
|
+
* @param b - The second chore to compare
|
|
4336
|
+
* @returns A number indicating the relative order of the chores. A negative number means `a` runs
|
|
4337
|
+
* before `b`.
|
|
4338
|
+
*/
|
|
4339
|
+
function choreComparator(a, b, rootVNode) {
|
|
4340
|
+
const macroTypeDiff = (a.$type$ & ChoreType.MACRO) - (b.$type$ & ChoreType.MACRO);
|
|
4341
|
+
if (macroTypeDiff !== 0) {
|
|
4342
|
+
return macroTypeDiff;
|
|
4343
|
+
}
|
|
4024
4344
|
const aHost = a.$host$;
|
|
4025
4345
|
const bHost = b.$host$;
|
|
4026
|
-
// QRL_RESOLVE does not have a host.
|
|
4027
4346
|
if (aHost !== bHost && aHost !== null && bHost !== null) {
|
|
4028
4347
|
if (vnode_isVNode(aHost) && vnode_isVNode(bHost)) {
|
|
4029
4348
|
// we are running on the client.
|
|
@@ -4033,6 +4352,8 @@
|
|
|
4033
4352
|
}
|
|
4034
4353
|
}
|
|
4035
4354
|
else {
|
|
4355
|
+
assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
|
|
4356
|
+
assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
|
|
4036
4357
|
// we are running on the server.
|
|
4037
4358
|
// On server we can't schedule task for a different host!
|
|
4038
4359
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -4049,250 +4370,117 @@
|
|
|
4049
4370
|
}
|
|
4050
4371
|
}
|
|
4051
4372
|
const microTypeDiff = (a.$type$ & ChoreType.MICRO) - (b.$type$ & ChoreType.MICRO);
|
|
4052
|
-
if (microTypeDiff !== 0) {
|
|
4053
|
-
return microTypeDiff;
|
|
4054
|
-
}
|
|
4055
|
-
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);
|
|
4222
|
-
}
|
|
4223
|
-
});
|
|
4224
|
-
return result;
|
|
4225
|
-
};
|
|
4226
|
-
const cleanupTask = (task) => {
|
|
4227
|
-
const destroy = task.$destroy$;
|
|
4228
|
-
if (destroy) {
|
|
4229
|
-
task.$destroy$ = null;
|
|
4230
|
-
try {
|
|
4231
|
-
destroy();
|
|
4373
|
+
if (microTypeDiff !== 0) {
|
|
4374
|
+
return microTypeDiff;
|
|
4232
4375
|
}
|
|
4233
|
-
|
|
4234
|
-
|
|
4376
|
+
// types are the same
|
|
4377
|
+
const idxDiff = toNumber(a.$idx$) - toNumber(b.$idx$);
|
|
4378
|
+
if (idxDiff !== 0) {
|
|
4379
|
+
return idxDiff;
|
|
4235
4380
|
}
|
|
4381
|
+
// If the host is the same (or missing), and the type is the same, we need to compare the target.
|
|
4382
|
+
if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
|
|
4383
|
+
// 1 means that we are going to process chores as FIFO
|
|
4384
|
+
return 1;
|
|
4385
|
+
}
|
|
4386
|
+
// If the chore is the same as the current chore, we will run it again
|
|
4387
|
+
if (b === currentChore) {
|
|
4388
|
+
return 1;
|
|
4389
|
+
}
|
|
4390
|
+
// The chores are the same and will run only once
|
|
4391
|
+
return 0;
|
|
4236
4392
|
}
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4393
|
+
function sortedFindIndex(sortedArray, value, rootVNode) {
|
|
4394
|
+
/// We need to ensure that the `queue` is sorted by priority.
|
|
4395
|
+
/// 1. Find a place where to insert into.
|
|
4396
|
+
let bottom = 0;
|
|
4397
|
+
let top = sortedArray.length;
|
|
4398
|
+
while (bottom < top) {
|
|
4399
|
+
const middle = bottom + ((top - bottom) >> 1);
|
|
4400
|
+
const midChore = sortedArray[middle];
|
|
4401
|
+
const comp = choreComparator(value, midChore, rootVNode);
|
|
4402
|
+
if (comp < 0) {
|
|
4403
|
+
top = middle;
|
|
4404
|
+
}
|
|
4405
|
+
else if (comp > 0) {
|
|
4406
|
+
bottom = middle + 1;
|
|
4407
|
+
}
|
|
4408
|
+
else {
|
|
4409
|
+
// We already have the host in the queue.
|
|
4410
|
+
return middle;
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
return ~bottom;
|
|
4244
4414
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4415
|
+
function sortedInsert(sortedArray, value, rootVNode) {
|
|
4416
|
+
/// We need to ensure that the `queue` is sorted by priority.
|
|
4417
|
+
/// 1. Find a place where to insert into.
|
|
4418
|
+
const idx = sortedFindIndex(sortedArray, value, rootVNode);
|
|
4419
|
+
if (idx < 0) {
|
|
4420
|
+
/// 2. Insert the chore into the queue.
|
|
4421
|
+
sortedArray.splice(~idx, 0, value);
|
|
4422
|
+
return value;
|
|
4423
|
+
}
|
|
4424
|
+
const existing = sortedArray[idx];
|
|
4425
|
+
/**
|
|
4426
|
+
* When a derived signal is updated we need to run vnode_diff. However the signal can update
|
|
4427
|
+
* multiple times during component execution. For this reason it is necessary for us to update
|
|
4428
|
+
* the chore with the latest result of the signal.
|
|
4429
|
+
*/
|
|
4430
|
+
if (existing.$type$ === ChoreType.NODE_DIFF) {
|
|
4431
|
+
existing.$payload$ = value.$payload$;
|
|
4432
|
+
}
|
|
4433
|
+
if (existing.$executed$) {
|
|
4434
|
+
existing.$executed$ = false;
|
|
4435
|
+
}
|
|
4436
|
+
return existing;
|
|
4247
4437
|
}
|
|
4248
4438
|
};
|
|
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;
|
|
4439
|
+
const toNumber = (value) => {
|
|
4440
|
+
return typeof value === 'number' ? value : -1;
|
|
4257
4441
|
};
|
|
4258
|
-
|
|
4259
|
-
$
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4442
|
+
function vNodeAlreadyDeleted(chore) {
|
|
4443
|
+
return !!(chore.$host$ &&
|
|
4444
|
+
vnode_isVNode(chore.$host$) &&
|
|
4445
|
+
chore.$host$[VNodeProps.flags] & VNodeFlags.Deleted);
|
|
4446
|
+
}
|
|
4447
|
+
function debugChoreTypeToString(type) {
|
|
4448
|
+
return ({
|
|
4449
|
+
[ChoreType.QRL_RESOLVE]: 'QRL_RESOLVE',
|
|
4450
|
+
[ChoreType.RUN_QRL]: 'RUN_QRL',
|
|
4451
|
+
[ChoreType.TASK]: 'TASK',
|
|
4452
|
+
[ChoreType.NODE_DIFF]: 'NODE_DIFF',
|
|
4453
|
+
[ChoreType.NODE_PROP]: 'NODE_PROP',
|
|
4454
|
+
[ChoreType.COMPONENT]: 'COMPONENT',
|
|
4455
|
+
[ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS]: 'RECOMPUTE_SIGNAL',
|
|
4456
|
+
[ChoreType.JOURNAL_FLUSH]: 'JOURNAL_FLUSH',
|
|
4457
|
+
[ChoreType.VISIBLE]: 'VISIBLE',
|
|
4458
|
+
[ChoreType.CLEANUP_VISIBLE]: 'CLEANUP_VISIBLE',
|
|
4459
|
+
[ChoreType.WAIT_FOR_ALL]: 'WAIT_FOR_ALL',
|
|
4460
|
+
}[type] || 'UNKNOWN: ' + type);
|
|
4461
|
+
}
|
|
4462
|
+
function debugChoreToString(chore) {
|
|
4463
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
4464
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
4465
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
4466
|
+
return `Chore(${type} ${chore.$type$ === ChoreType.QRL_RESOLVE || chore.$type$ === ChoreType.RUN_QRL ? qrlTarget : host} ${chore.$idx$})`;
|
|
4467
|
+
}
|
|
4468
|
+
function debugTrace(action, arg, currentChore, queue) {
|
|
4469
|
+
const lines = ['===========================\nScheduler: ' + action];
|
|
4470
|
+
if (arg && !('$type$' in arg)) {
|
|
4471
|
+
lines.push(' arg: ' + String(arg).replaceAll(/\n.*/gim, ''));
|
|
4472
|
+
}
|
|
4473
|
+
if (queue) {
|
|
4474
|
+
queue.forEach((chore) => {
|
|
4475
|
+
const active = chore === arg ? '>>>' : ' ';
|
|
4476
|
+
lines.push(` ${active} > ` +
|
|
4477
|
+
(chore === currentChore ? '[running] ' : '') +
|
|
4478
|
+
debugChoreToString(chore));
|
|
4479
|
+
});
|
|
4273
4480
|
}
|
|
4481
|
+
// eslint-disable-next-line no-console
|
|
4482
|
+
console.log(lines.join('\n') + '\n');
|
|
4274
4483
|
}
|
|
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
4484
|
|
|
4297
4485
|
/**
|
|
4298
4486
|
* @file
|
|
@@ -4310,6 +4498,15 @@
|
|
|
4310
4498
|
const DEBUG = false;
|
|
4311
4499
|
// eslint-disable-next-line no-console
|
|
4312
4500
|
const log = (...args) => console.log('SIGNAL', ...args.map(qwikDebugToString));
|
|
4501
|
+
var SignalFlags;
|
|
4502
|
+
(function (SignalFlags) {
|
|
4503
|
+
SignalFlags[SignalFlags["INVALID"] = 1] = "INVALID";
|
|
4504
|
+
})(SignalFlags || (SignalFlags = {}));
|
|
4505
|
+
var WrappedSignalFlags;
|
|
4506
|
+
(function (WrappedSignalFlags) {
|
|
4507
|
+
// should subscribe to value and be unwrapped for PropsProxy
|
|
4508
|
+
WrappedSignalFlags[WrappedSignalFlags["UNWRAP"] = 2] = "UNWRAP";
|
|
4509
|
+
})(WrappedSignalFlags || (WrappedSignalFlags = {}));
|
|
4313
4510
|
const throwIfQRLNotResolved = (qrl) => {
|
|
4314
4511
|
const resolved = qrl.resolved;
|
|
4315
4512
|
if (!resolved) {
|
|
@@ -4326,18 +4523,19 @@
|
|
|
4326
4523
|
return value instanceof Signal;
|
|
4327
4524
|
};
|
|
4328
4525
|
/** @internal */
|
|
4329
|
-
class
|
|
4526
|
+
class SubscriptionData {
|
|
4330
4527
|
data;
|
|
4331
4528
|
constructor(data) {
|
|
4332
4529
|
this.data = data;
|
|
4333
4530
|
}
|
|
4334
4531
|
}
|
|
4335
|
-
var
|
|
4336
|
-
(function (
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4532
|
+
var EffectSubscriptionProp;
|
|
4533
|
+
(function (EffectSubscriptionProp) {
|
|
4534
|
+
EffectSubscriptionProp[EffectSubscriptionProp["CONSUMER"] = 0] = "CONSUMER";
|
|
4535
|
+
EffectSubscriptionProp[EffectSubscriptionProp["PROPERTY"] = 1] = "PROPERTY";
|
|
4536
|
+
EffectSubscriptionProp[EffectSubscriptionProp["BACK_REF"] = 2] = "BACK_REF";
|
|
4537
|
+
EffectSubscriptionProp[EffectSubscriptionProp["DATA"] = 3] = "DATA";
|
|
4538
|
+
})(EffectSubscriptionProp || (EffectSubscriptionProp = {}));
|
|
4341
4539
|
var EffectProperty;
|
|
4342
4540
|
(function (EffectProperty) {
|
|
4343
4541
|
EffectProperty["COMPONENT"] = ":";
|
|
@@ -4374,19 +4572,16 @@
|
|
|
4374
4572
|
}
|
|
4375
4573
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
4376
4574
|
if (effectSubscriber) {
|
|
4377
|
-
const effects = (this.$effects$ ||=
|
|
4575
|
+
const effects = (this.$effects$ ||= new Set());
|
|
4378
4576
|
// Let's make sure that we have a reference to this effect.
|
|
4379
4577
|
// Adding reference is essentially adding a subscription, so if the signal
|
|
4380
4578
|
// changes we know who to notify.
|
|
4381
|
-
|
|
4579
|
+
ensureContainsSubscription(effects, effectSubscriber);
|
|
4382
4580
|
// But when effect is scheduled in needs to be able to know which signals
|
|
4383
4581
|
// to unsubscribe from. So we need to store the reference from the effect back
|
|
4384
4582
|
// 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
|
-
}
|
|
4583
|
+
ensureContainsBackRef(effectSubscriber, this);
|
|
4584
|
+
addQrlToSerializationCtx(effectSubscriber, this.$container$);
|
|
4390
4585
|
}
|
|
4391
4586
|
}
|
|
4392
4587
|
return this.untrackedValue;
|
|
@@ -4404,123 +4599,98 @@
|
|
|
4404
4599
|
}
|
|
4405
4600
|
}
|
|
4406
4601
|
toString() {
|
|
4407
|
-
return (`[${this.constructor.name}${this.$
|
|
4408
|
-
(this.$effects
|
|
4602
|
+
return (`[${this.constructor.name}${this.$flags$ & SignalFlags.INVALID ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
|
|
4603
|
+
(Array.from(this.$effects$ || [])
|
|
4604
|
+
.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' '))
|
|
4605
|
+
.join('\n') || ''));
|
|
4409
4606
|
}
|
|
4410
4607
|
toJSON() {
|
|
4411
4608
|
return { value: this.$untrackedValue$ };
|
|
4412
4609
|
}
|
|
4413
4610
|
}
|
|
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);
|
|
4611
|
+
const ensureContainsSubscription = (array, effectSubscription) => {
|
|
4612
|
+
array.add(effectSubscription);
|
|
4430
4613
|
};
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4614
|
+
/** Ensure the item is in back refs set */
|
|
4615
|
+
const ensureContainsBackRef = (array, value) => {
|
|
4616
|
+
array[EffectSubscriptionProp.BACK_REF] ||= new Set();
|
|
4617
|
+
array[EffectSubscriptionProp.BACK_REF].add(value);
|
|
4618
|
+
};
|
|
4619
|
+
const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
4620
|
+
if (!!container && !isDomContainer(container)) {
|
|
4621
|
+
const effect = effectSubscriber[EffectSubscriptionProp.CONSUMER];
|
|
4622
|
+
const property = effectSubscriber[EffectSubscriptionProp.PROPERTY];
|
|
4623
|
+
let qrl = null;
|
|
4624
|
+
if (isTask(effect)) {
|
|
4625
|
+
qrl = effect.$qrl$;
|
|
4436
4626
|
}
|
|
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;
|
|
4627
|
+
else if (effect instanceof ComputedSignal) {
|
|
4628
|
+
qrl = effect.$computeQrl$;
|
|
4444
4629
|
}
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
}
|
|
4448
|
-
else if (isSSRNode(effect)) {
|
|
4449
|
-
let subscribers = effect.getProp(QSubscribers);
|
|
4450
|
-
subscribers ||= [];
|
|
4451
|
-
if (subscriberExistInSubscribers(subscribers, subscriber)) {
|
|
4452
|
-
return;
|
|
4630
|
+
else if (property === EffectProperty.COMPONENT) {
|
|
4631
|
+
qrl = container.getHostProp(effect, OnRenderProp);
|
|
4453
4632
|
}
|
|
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;
|
|
4633
|
+
if (qrl) {
|
|
4634
|
+
container.serializationCtx.$eventQrls$.add(qrl);
|
|
4465
4635
|
}
|
|
4466
4636
|
}
|
|
4467
|
-
return false;
|
|
4468
4637
|
};
|
|
4469
4638
|
const triggerEffects = (container, signal, effects) => {
|
|
4639
|
+
const isBrowser = isDomContainer(container);
|
|
4470
4640
|
if (effects) {
|
|
4471
|
-
const scheduleEffect = (
|
|
4472
|
-
const
|
|
4473
|
-
const property =
|
|
4641
|
+
const scheduleEffect = (effectSubscription) => {
|
|
4642
|
+
const consumer = effectSubscription[EffectSubscriptionProp.CONSUMER];
|
|
4643
|
+
const property = effectSubscription[EffectSubscriptionProp.PROPERTY];
|
|
4474
4644
|
assertDefined(container, 'Container must be defined.');
|
|
4475
|
-
if (isTask(
|
|
4476
|
-
|
|
4645
|
+
if (isTask(consumer)) {
|
|
4646
|
+
consumer.$flags$ |= TaskFlags.DIRTY;
|
|
4477
4647
|
let choreType = ChoreType.TASK;
|
|
4478
|
-
if (
|
|
4648
|
+
if (consumer.$flags$ & TaskFlags.VISIBLE_TASK) {
|
|
4479
4649
|
choreType = ChoreType.VISIBLE;
|
|
4480
4650
|
}
|
|
4481
|
-
|
|
4482
|
-
choreType = ChoreType.RESOURCE;
|
|
4483
|
-
}
|
|
4484
|
-
container.$scheduler$(choreType, effect);
|
|
4651
|
+
container.$scheduler$(choreType, consumer);
|
|
4485
4652
|
}
|
|
4486
|
-
else if (
|
|
4653
|
+
else if (consumer instanceof Signal) {
|
|
4487
4654
|
// we don't schedule ComputedSignal/DerivedSignal directly, instead we invalidate it and
|
|
4488
4655
|
// and schedule the signals effects (recursively)
|
|
4489
|
-
if (
|
|
4656
|
+
if (consumer instanceof ComputedSignal) {
|
|
4490
4657
|
// Ensure that the computed signal's QRL is resolved.
|
|
4491
4658
|
// If not resolved schedule it to be resolved.
|
|
4492
|
-
if (!
|
|
4493
|
-
container.$scheduler$(ChoreType.QRL_RESOLVE, null,
|
|
4659
|
+
if (!consumer.$computeQrl$.resolved) {
|
|
4660
|
+
container.$scheduler$(ChoreType.QRL_RESOLVE, null, consumer.$computeQrl$);
|
|
4494
4661
|
}
|
|
4495
4662
|
}
|
|
4496
|
-
|
|
4663
|
+
consumer.$invalidate$();
|
|
4497
4664
|
}
|
|
4498
4665
|
else if (property === EffectProperty.COMPONENT) {
|
|
4499
|
-
const host =
|
|
4666
|
+
const host = consumer;
|
|
4500
4667
|
const qrl = container.getHostProp(host, OnRenderProp);
|
|
4501
4668
|
assertDefined(qrl, 'Component must have QRL');
|
|
4502
4669
|
const props = container.getHostProp(host, ELEMENT_PROPS);
|
|
4503
4670
|
container.$scheduler$(ChoreType.COMPONENT, host, qrl, props);
|
|
4504
4671
|
}
|
|
4505
|
-
else if (
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4672
|
+
else if (isBrowser) {
|
|
4673
|
+
if (property === EffectProperty.VNODE) {
|
|
4674
|
+
const host = consumer;
|
|
4675
|
+
container.$scheduler$(ChoreType.NODE_DIFF, host, host, signal);
|
|
4676
|
+
}
|
|
4677
|
+
else {
|
|
4678
|
+
const host = consumer;
|
|
4679
|
+
const effectData = effectSubscription[EffectSubscriptionProp.DATA];
|
|
4680
|
+
if (effectData instanceof SubscriptionData) {
|
|
4681
|
+
const data = effectData.data;
|
|
4682
|
+
const payload = {
|
|
4683
|
+
...data,
|
|
4684
|
+
$value$: signal,
|
|
4685
|
+
};
|
|
4686
|
+
container.$scheduler$(ChoreType.NODE_PROP, host, property, payload);
|
|
4687
|
+
}
|
|
4520
4688
|
}
|
|
4521
4689
|
}
|
|
4522
4690
|
};
|
|
4523
|
-
effects
|
|
4691
|
+
for (const effect of effects) {
|
|
4692
|
+
scheduleEffect(effect);
|
|
4693
|
+
}
|
|
4524
4694
|
}
|
|
4525
4695
|
};
|
|
4526
4696
|
/**
|
|
@@ -4536,18 +4706,21 @@
|
|
|
4536
4706
|
* resolve the QRL during the mark dirty phase so that any call to it will be synchronous). )
|
|
4537
4707
|
*/
|
|
4538
4708
|
$computeQrl$;
|
|
4709
|
+
$flags$;
|
|
4710
|
+
$forceRunEffects$ = false;
|
|
4711
|
+
[_EFFECT_BACK_REF] = null;
|
|
4712
|
+
constructor(container, fn,
|
|
4539
4713
|
// We need a separate flag to know when the computation needs running because
|
|
4540
4714
|
// we need the old value to know if effects need running after computation
|
|
4541
|
-
|
|
4542
|
-
$forceRunEffects$ = false;
|
|
4543
|
-
constructor(container, fn) {
|
|
4715
|
+
flags = SignalFlags.INVALID) {
|
|
4544
4716
|
// The value is used for comparison when signals trigger, which can only happen
|
|
4545
4717
|
// when it was calculated before. Therefore we can pass whatever we like.
|
|
4546
4718
|
super(container, NEEDS_COMPUTATION);
|
|
4547
4719
|
this.$computeQrl$ = fn;
|
|
4720
|
+
this.$flags$ = flags;
|
|
4548
4721
|
}
|
|
4549
4722
|
$invalidate$() {
|
|
4550
|
-
this.$
|
|
4723
|
+
this.$flags$ |= SignalFlags.INVALID;
|
|
4551
4724
|
this.$forceRunEffects$ = false;
|
|
4552
4725
|
// We should only call subscribers if the calculation actually changed.
|
|
4553
4726
|
// Therefore, we need to calculate the value now.
|
|
@@ -4558,7 +4731,7 @@
|
|
|
4558
4731
|
* remained the same object
|
|
4559
4732
|
*/
|
|
4560
4733
|
force() {
|
|
4561
|
-
this.$
|
|
4734
|
+
this.$flags$ |= SignalFlags.INVALID;
|
|
4562
4735
|
this.$forceRunEffects$ = false;
|
|
4563
4736
|
triggerEffects(this.$container$, this, this.$effects$);
|
|
4564
4737
|
}
|
|
@@ -4571,14 +4744,14 @@
|
|
|
4571
4744
|
return this.$untrackedValue$;
|
|
4572
4745
|
}
|
|
4573
4746
|
$computeIfNeeded$() {
|
|
4574
|
-
if (!this.$
|
|
4747
|
+
if (!(this.$flags$ & SignalFlags.INVALID)) {
|
|
4575
4748
|
return false;
|
|
4576
4749
|
}
|
|
4577
4750
|
const computeQrl = this.$computeQrl$;
|
|
4578
4751
|
throwIfQRLNotResolved(computeQrl);
|
|
4579
4752
|
const ctx = tryGetInvokeContext();
|
|
4580
4753
|
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
4581
|
-
ctx && (ctx.$effectSubscriber$ =
|
|
4754
|
+
ctx && (ctx.$effectSubscriber$ = getSubscriber(this, EffectProperty.VNODE));
|
|
4582
4755
|
try {
|
|
4583
4756
|
const untrackedValue = computeQrl.getFn(ctx)();
|
|
4584
4757
|
if (isPromise(untrackedValue)) {
|
|
@@ -4588,7 +4761,7 @@
|
|
|
4588
4761
|
]);
|
|
4589
4762
|
}
|
|
4590
4763
|
DEBUG && log('Signal.$compute$', untrackedValue);
|
|
4591
|
-
this.$
|
|
4764
|
+
this.$flags$ &= ~SignalFlags.INVALID;
|
|
4592
4765
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
4593
4766
|
if (didChange) {
|
|
4594
4767
|
this.$untrackedValue$ = untrackedValue;
|
|
@@ -4613,20 +4786,22 @@
|
|
|
4613
4786
|
$args$;
|
|
4614
4787
|
$func$;
|
|
4615
4788
|
$funcStr$;
|
|
4616
|
-
|
|
4617
|
-
// we need the old value to know if effects need running after computation
|
|
4618
|
-
$invalid$ = true;
|
|
4619
|
-
$effectDependencies$ = null;
|
|
4789
|
+
$flags$;
|
|
4620
4790
|
$hostElement$ = null;
|
|
4621
4791
|
$forceRunEffects$ = false;
|
|
4622
|
-
|
|
4792
|
+
[_EFFECT_BACK_REF] = null;
|
|
4793
|
+
constructor(container, fn, args, fnStr,
|
|
4794
|
+
// We need a separate flag to know when the computation needs running because
|
|
4795
|
+
// we need the old value to know if effects need running after computation
|
|
4796
|
+
flags = SignalFlags.INVALID | WrappedSignalFlags.UNWRAP) {
|
|
4623
4797
|
super(container, NEEDS_COMPUTATION);
|
|
4624
4798
|
this.$args$ = args;
|
|
4625
4799
|
this.$func$ = fn;
|
|
4626
4800
|
this.$funcStr$ = fnStr;
|
|
4801
|
+
this.$flags$ = flags;
|
|
4627
4802
|
}
|
|
4628
4803
|
$invalidate$() {
|
|
4629
|
-
this.$
|
|
4804
|
+
this.$flags$ |= SignalFlags.INVALID;
|
|
4630
4805
|
this.$forceRunEffects$ = false;
|
|
4631
4806
|
// We should only call subscribers if the calculation actually changed.
|
|
4632
4807
|
// Therefore, we need to calculate the value now.
|
|
@@ -4637,7 +4812,7 @@
|
|
|
4637
4812
|
* remained the same object
|
|
4638
4813
|
*/
|
|
4639
4814
|
force() {
|
|
4640
|
-
this.$
|
|
4815
|
+
this.$flags$ |= SignalFlags.INVALID;
|
|
4641
4816
|
this.$forceRunEffects$ = false;
|
|
4642
4817
|
triggerEffects(this.$container$, this, this.$effects$);
|
|
4643
4818
|
}
|
|
@@ -4650,10 +4825,12 @@
|
|
|
4650
4825
|
return this.$untrackedValue$;
|
|
4651
4826
|
}
|
|
4652
4827
|
$computeIfNeeded$() {
|
|
4653
|
-
if (!this.$
|
|
4828
|
+
if (!(this.$flags$ & SignalFlags.INVALID)) {
|
|
4654
4829
|
return false;
|
|
4655
4830
|
}
|
|
4656
4831
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, EffectProperty.VNODE, this.$container$);
|
|
4832
|
+
// TODO: we should remove invalid flag here
|
|
4833
|
+
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
4657
4834
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
4658
4835
|
if (didChange) {
|
|
4659
4836
|
this.$untrackedValue$ = untrackedValue;
|
|
@@ -4686,7 +4863,7 @@
|
|
|
4686
4863
|
if (jsx.key !== null) {
|
|
4687
4864
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
4688
4865
|
}
|
|
4689
|
-
return scheduler(ChoreType.
|
|
4866
|
+
return scheduler(ChoreType.COMPONENT, host, componentQrl, srcProps);
|
|
4690
4867
|
};
|
|
4691
4868
|
|
|
4692
4869
|
class ParentComponentData {
|
|
@@ -4698,21 +4875,10 @@
|
|
|
4698
4875
|
}
|
|
4699
4876
|
}
|
|
4700
4877
|
/** @internal */
|
|
4701
|
-
function _walkJSX(ssr, value, options) {
|
|
4878
|
+
async function _walkJSX(ssr, value, options) {
|
|
4702
4879
|
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
4880
|
const enqueue = (value) => stack.push(value);
|
|
4711
|
-
const
|
|
4712
|
-
stack.push(value);
|
|
4713
|
-
drain();
|
|
4714
|
-
};
|
|
4715
|
-
const drain = () => {
|
|
4881
|
+
const drain = async () => {
|
|
4716
4882
|
while (stack.length) {
|
|
4717
4883
|
const value = stack.pop();
|
|
4718
4884
|
if (value instanceof ParentComponentData) {
|
|
@@ -4722,20 +4888,10 @@
|
|
|
4722
4888
|
}
|
|
4723
4889
|
else if (typeof value === 'function') {
|
|
4724
4890
|
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;
|
|
4891
|
+
stack.push(await stack.pop());
|
|
4892
|
+
continue;
|
|
4738
4893
|
}
|
|
4894
|
+
await value.apply(ssr);
|
|
4739
4895
|
continue;
|
|
4740
4896
|
}
|
|
4741
4897
|
processJSXNode(ssr, enqueue, value, {
|
|
@@ -4743,12 +4899,8 @@
|
|
|
4743
4899
|
parentComponentFrame: options.parentComponentFrame,
|
|
4744
4900
|
});
|
|
4745
4901
|
}
|
|
4746
|
-
if (stack.length === 0 && options.allowPromises) {
|
|
4747
|
-
resolveDrain();
|
|
4748
|
-
}
|
|
4749
4902
|
};
|
|
4750
|
-
drain();
|
|
4751
|
-
return drained;
|
|
4903
|
+
await drain();
|
|
4752
4904
|
}
|
|
4753
4905
|
function processJSXNode(ssr, enqueue, value, options) {
|
|
4754
4906
|
// console.log('processJSXNode', value);
|
|
@@ -4787,7 +4939,6 @@
|
|
|
4787
4939
|
enqueue(async () => {
|
|
4788
4940
|
for await (const chunk of value) {
|
|
4789
4941
|
await _walkJSX(ssr, chunk, {
|
|
4790
|
-
allowPromises: true,
|
|
4791
4942
|
currentStyleScoped: options.styleScoped,
|
|
4792
4943
|
parentComponentFrame: options.parentComponentFrame,
|
|
4793
4944
|
});
|
|
@@ -4841,7 +4992,7 @@
|
|
|
4841
4992
|
if (componentFrame) {
|
|
4842
4993
|
const compId = componentFrame.componentNode.id || '';
|
|
4843
4994
|
const projectionAttrs = build.isDev ? [DEBUG_TYPE, VirtualType.Projection] : [];
|
|
4844
|
-
projectionAttrs.push(
|
|
4995
|
+
projectionAttrs.push(QSlotParent, compId);
|
|
4845
4996
|
ssr.openProjection(projectionAttrs);
|
|
4846
4997
|
const host = componentFrame.componentNode;
|
|
4847
4998
|
const node = ssr.getLastNode();
|
|
@@ -4874,7 +5025,6 @@
|
|
|
4874
5025
|
value = generator({
|
|
4875
5026
|
async write(chunk) {
|
|
4876
5027
|
await _walkJSX(ssr, chunk, {
|
|
4877
|
-
allowPromises: true,
|
|
4878
5028
|
currentStyleScoped: options.styleScoped,
|
|
4879
5029
|
parentComponentFrame: options.parentComponentFrame,
|
|
4880
5030
|
});
|
|
@@ -5031,11 +5181,23 @@
|
|
|
5031
5181
|
const appendToValue = (valueToAppend) => {
|
|
5032
5182
|
value = (value == null ? '' : value + '\n') + valueToAppend;
|
|
5033
5183
|
};
|
|
5184
|
+
const getQrlString = (qrl) => {
|
|
5185
|
+
/**
|
|
5186
|
+
* If there are captures we need to schedule so everything is executed in the right order + qrls
|
|
5187
|
+
* are resolved.
|
|
5188
|
+
*
|
|
5189
|
+
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
5190
|
+
*/
|
|
5191
|
+
if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
|
|
5192
|
+
qrl = createQRL(null, '_run', queueQRL, null, null, [qrl]);
|
|
5193
|
+
}
|
|
5194
|
+
return qrlToString(serializationCtx, qrl);
|
|
5195
|
+
};
|
|
5034
5196
|
if (Array.isArray(qrls)) {
|
|
5035
5197
|
for (let i = 0; i <= qrls.length; i++) {
|
|
5036
5198
|
const qrl = qrls[i];
|
|
5037
|
-
if (isQrl(qrl)) {
|
|
5038
|
-
appendToValue(
|
|
5199
|
+
if (isQrl$1(qrl)) {
|
|
5200
|
+
appendToValue(getQrlString(qrl));
|
|
5039
5201
|
addQwikEventToSerializationContext(serializationCtx, key, qrl);
|
|
5040
5202
|
}
|
|
5041
5203
|
else if (qrl != null) {
|
|
@@ -5047,8 +5209,8 @@
|
|
|
5047
5209
|
}
|
|
5048
5210
|
}
|
|
5049
5211
|
}
|
|
5050
|
-
else if (isQrl(qrls)) {
|
|
5051
|
-
value =
|
|
5212
|
+
else if (isQrl$1(qrls)) {
|
|
5213
|
+
value = getQrlString(qrls);
|
|
5052
5214
|
addQwikEventToSerializationContext(serializationCtx, key, qrls);
|
|
5053
5215
|
}
|
|
5054
5216
|
return value;
|
|
@@ -5098,7 +5260,7 @@
|
|
|
5098
5260
|
*
|
|
5099
5261
|
* @public
|
|
5100
5262
|
*/
|
|
5101
|
-
const version = "2.0.0-alpha.
|
|
5263
|
+
const version = "2.0.0-alpha.8-dev+66037b5";
|
|
5102
5264
|
|
|
5103
5265
|
/** @internal */
|
|
5104
5266
|
class _SharedContainer {
|
|
@@ -5130,13 +5292,6 @@
|
|
|
5130
5292
|
}
|
|
5131
5293
|
}
|
|
5132
5294
|
|
|
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
5295
|
// Keep these properties named like this so they're the same as from wrapSignal
|
|
5141
5296
|
const getValueProp = (p0) => p0.value;
|
|
5142
5297
|
const getProp = (p0, p1) => p0[p1];
|
|
@@ -5160,7 +5315,7 @@
|
|
|
5160
5315
|
}
|
|
5161
5316
|
if (isSignal(obj)) {
|
|
5162
5317
|
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
5163
|
-
if (obj instanceof WrappedSignal) {
|
|
5318
|
+
if (obj instanceof WrappedSignal && obj.flags & WrappedSignalFlags.UNWRAP) {
|
|
5164
5319
|
return obj;
|
|
5165
5320
|
}
|
|
5166
5321
|
return getWrapped(args);
|
|
@@ -5186,6 +5341,17 @@
|
|
|
5186
5341
|
// We need to forward the access to the original object
|
|
5187
5342
|
return getWrapped(args);
|
|
5188
5343
|
};
|
|
5344
|
+
/** @internal */
|
|
5345
|
+
const _wrapStore = (obj, prop) => {
|
|
5346
|
+
const target = getStoreTarget(obj);
|
|
5347
|
+
const value = target[prop];
|
|
5348
|
+
if (isSignal(value)) {
|
|
5349
|
+
return value;
|
|
5350
|
+
}
|
|
5351
|
+
else {
|
|
5352
|
+
return new WrappedSignal(null, getProp, [obj, prop], null, SignalFlags.INVALID);
|
|
5353
|
+
}
|
|
5354
|
+
};
|
|
5189
5355
|
/** @internal @deprecated v1 compat */
|
|
5190
5356
|
const _wrapSignal = (obj, prop) => {
|
|
5191
5357
|
const r = _wrapProp(obj, prop);
|
|
@@ -5456,7 +5622,9 @@
|
|
|
5456
5622
|
? this.$constProps$[prop]
|
|
5457
5623
|
: this.$varProps$[prop];
|
|
5458
5624
|
// a proxied value that the optimizer made
|
|
5459
|
-
return value instanceof WrappedSignal
|
|
5625
|
+
return value instanceof WrappedSignal && value.$flags$ & WrappedSignalFlags.UNWRAP
|
|
5626
|
+
? value.value
|
|
5627
|
+
: value;
|
|
5460
5628
|
}
|
|
5461
5629
|
set(_, prop, value) {
|
|
5462
5630
|
if (prop === _CONST_PROPS) {
|
|
@@ -5548,7 +5716,7 @@
|
|
|
5548
5716
|
else if (isTask(value)) {
|
|
5549
5717
|
return `Task(${qwikDebugToString(value.$qrl$)})`;
|
|
5550
5718
|
}
|
|
5551
|
-
else if (isQrl
|
|
5719
|
+
else if (isQrl(value)) {
|
|
5552
5720
|
return `Qrl(${value.$symbol$})`;
|
|
5553
5721
|
}
|
|
5554
5722
|
else if (typeof value === 'object' || typeof value === 'function') {
|
|
@@ -5690,8 +5858,8 @@
|
|
|
5690
5858
|
ID_CHAR: /* ********* */ '=',
|
|
5691
5859
|
PROPS: /* ************** */ 62, // `>` - `q:props' - Component Props
|
|
5692
5860
|
PROPS_CHAR: /* ****** */ '>',
|
|
5693
|
-
|
|
5694
|
-
|
|
5861
|
+
SLOT_PARENT: /* ******** */ 63, // `?` - `q:sparent` - Slot parent.
|
|
5862
|
+
SLOT_PARENT_CHAR: /* */ '?',
|
|
5695
5863
|
KEY: /* **************** */ 64, // `@` - `q:key` - Element key.
|
|
5696
5864
|
KEY_CHAR: /* ******** */ '@',
|
|
5697
5865
|
SEQ: /* **************** */ 91, // `[` - `q:seq' - Seq value from `useSequentialScope()`
|
|
@@ -5702,14 +5870,21 @@
|
|
|
5702
5870
|
CONTEXT_CHAR: /* **** */ ']',
|
|
5703
5871
|
SEQ_IDX: /* ************ */ 94, // `^` - `q:seqIdx' - Sequential scope id
|
|
5704
5872
|
SEQ_IDX_CHAR: /* **** */ '^',
|
|
5705
|
-
|
|
5706
|
-
|
|
5873
|
+
BACK_REFS: /* ********** */ 96, // '`' - `q:brefs' - Effect dependencies/subscriptions
|
|
5874
|
+
BACK_REFS_CHAR: /* ** */ '`',
|
|
5707
5875
|
SEPARATOR: /* ********* */ 124, // `|` - Separator char to encode any key/value pairs.
|
|
5708
5876
|
SEPARATOR_CHAR: /* ** */ '|',
|
|
5709
5877
|
SLOT: /* ************** */ 126, // `~` - `q:slot' - Slot name
|
|
5710
5878
|
SLOT_CHAR: /* ******* */ '~',
|
|
5711
5879
|
};
|
|
5712
5880
|
|
|
5881
|
+
const mergeMaps = (map1, map2) => {
|
|
5882
|
+
for (const [k, v] of map2) {
|
|
5883
|
+
map1.set(k, v);
|
|
5884
|
+
}
|
|
5885
|
+
return map1;
|
|
5886
|
+
};
|
|
5887
|
+
|
|
5713
5888
|
/**
|
|
5714
5889
|
* @file
|
|
5715
5890
|
*
|
|
@@ -5932,6 +6107,12 @@
|
|
|
5932
6107
|
const flag = vNode[VNodeProps.flags];
|
|
5933
6108
|
return (flag & VNodeFlags.Virtual) === VNodeFlags.Virtual;
|
|
5934
6109
|
};
|
|
6110
|
+
const vnode_isProjection = (vNode) => {
|
|
6111
|
+
assertDefined(vNode, 'Missing vNode');
|
|
6112
|
+
const flag = vNode[VNodeProps.flags];
|
|
6113
|
+
return ((flag & VNodeFlags.Virtual) === VNodeFlags.Virtual &&
|
|
6114
|
+
vnode_getProp(vNode, QSlot, null) !== null);
|
|
6115
|
+
};
|
|
5935
6116
|
const ensureTextVNode = (vNode) => {
|
|
5936
6117
|
assertTrue(vnode_isTextVNode(vNode), 'Expecting TextVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5937
6118
|
return vNode;
|
|
@@ -5965,6 +6146,7 @@
|
|
|
5965
6146
|
elementVNode[VNodeProps.flags] ^= VNodeFlags.Inflated;
|
|
5966
6147
|
const element = elementVNode[ElementVNodeProps.element];
|
|
5967
6148
|
const attributes = element.attributes;
|
|
6149
|
+
const props = vnode_getProps(elementVNode);
|
|
5968
6150
|
for (let idx = 0; idx < attributes.length; idx++) {
|
|
5969
6151
|
const attr = attributes[idx];
|
|
5970
6152
|
const key = attr.name;
|
|
@@ -5975,15 +6157,15 @@
|
|
|
5975
6157
|
}
|
|
5976
6158
|
else if (key.startsWith(QContainerAttr)) {
|
|
5977
6159
|
if (attr.value === QContainerValue.HTML) {
|
|
5978
|
-
mapArray_set(
|
|
6160
|
+
mapArray_set(props, dangerouslySetInnerHTML, element.innerHTML, 0);
|
|
5979
6161
|
}
|
|
5980
6162
|
else if (attr.value === QContainerValue.TEXT && 'value' in element) {
|
|
5981
|
-
mapArray_set(
|
|
6163
|
+
mapArray_set(props, 'value', element.value, 0);
|
|
5982
6164
|
}
|
|
5983
6165
|
}
|
|
5984
6166
|
else if (!key.startsWith('on:')) {
|
|
5985
6167
|
const value = attr.value;
|
|
5986
|
-
mapArray_set(
|
|
6168
|
+
mapArray_set(props, key, value, 0);
|
|
5987
6169
|
}
|
|
5988
6170
|
}
|
|
5989
6171
|
}
|
|
@@ -6375,7 +6557,7 @@
|
|
|
6375
6557
|
element[key] = parseBoolean(value);
|
|
6376
6558
|
}
|
|
6377
6559
|
else if (key === 'value' && key in element) {
|
|
6378
|
-
element.value =
|
|
6560
|
+
element.value = String(value);
|
|
6379
6561
|
}
|
|
6380
6562
|
else if (key === dangerouslySetInnerHTML) {
|
|
6381
6563
|
element.innerHTML = value;
|
|
@@ -6419,54 +6601,16 @@
|
|
|
6419
6601
|
journal.length = 0;
|
|
6420
6602
|
};
|
|
6421
6603
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
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
6604
|
const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
6466
6605
|
ensureElementOrVirtualVNode(parent);
|
|
6467
6606
|
if (vnode_isElementVNode(parent)) {
|
|
6468
6607
|
ensureMaterialized(parent);
|
|
6469
6608
|
}
|
|
6609
|
+
if (newChild === insertBefore) {
|
|
6610
|
+
// invalid insertBefore. We can't insert before self reference
|
|
6611
|
+
// prevent infinity loop and putting self reference to next sibling
|
|
6612
|
+
insertBefore = null;
|
|
6613
|
+
}
|
|
6470
6614
|
let adjustedInsertBefore = null;
|
|
6471
6615
|
if (insertBefore == null) {
|
|
6472
6616
|
if (vnode_isVirtualVNode(parent)) {
|
|
@@ -6590,9 +6734,10 @@
|
|
|
6590
6734
|
const elementVNode = ensureElementVNode(vnode);
|
|
6591
6735
|
let elementName = elementVNode[ElementVNodeProps.elementName];
|
|
6592
6736
|
if (elementName === undefined) {
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
elementVNode[
|
|
6737
|
+
const element = elementVNode[ElementVNodeProps.element];
|
|
6738
|
+
const nodeName = build.isDev ? fastNodeName(element).toLowerCase() : fastNodeName(element);
|
|
6739
|
+
elementName = elementVNode[ElementVNodeProps.elementName] = nodeName;
|
|
6740
|
+
elementVNode[VNodeProps.flags] |= vnode_getElementNamespaceFlags(element);
|
|
6596
6741
|
}
|
|
6597
6742
|
return elementName;
|
|
6598
6743
|
};
|
|
@@ -6774,6 +6919,20 @@
|
|
|
6774
6919
|
}
|
|
6775
6920
|
return node;
|
|
6776
6921
|
};
|
|
6922
|
+
let _fastNamespaceURI = null;
|
|
6923
|
+
const fastNamespaceURI = (element) => {
|
|
6924
|
+
if (!_fastNamespaceURI) {
|
|
6925
|
+
_fastNamespaceURI = fastGetter(element, 'namespaceURI');
|
|
6926
|
+
}
|
|
6927
|
+
return _fastNamespaceURI.call(element);
|
|
6928
|
+
};
|
|
6929
|
+
let _fastNodeName = null;
|
|
6930
|
+
const fastNodeName = (element) => {
|
|
6931
|
+
if (!_fastNodeName) {
|
|
6932
|
+
_fastNodeName = fastGetter(element, 'nodeName');
|
|
6933
|
+
}
|
|
6934
|
+
return _fastNodeName.call(element);
|
|
6935
|
+
};
|
|
6777
6936
|
const fastGetter = (prototype, name) => {
|
|
6778
6937
|
let getter;
|
|
6779
6938
|
while (prototype && !(getter = Object.getOwnPropertyDescriptor(prototype, name)?.get)) {
|
|
@@ -6840,8 +6999,11 @@
|
|
|
6840
6999
|
container.$setRawState$(parseInt(id), vParent);
|
|
6841
7000
|
build.isDev && vnode_setAttr(null, vParent, ELEMENT_ID, id);
|
|
6842
7001
|
}
|
|
6843
|
-
else if (peek() === VNodeDataChar.
|
|
6844
|
-
|
|
7002
|
+
else if (peek() === VNodeDataChar.BACK_REFS) {
|
|
7003
|
+
if (!container) {
|
|
7004
|
+
container = getDomContainer(vParent[ElementVNodeProps.element]);
|
|
7005
|
+
}
|
|
7006
|
+
setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
|
|
6845
7007
|
}
|
|
6846
7008
|
else {
|
|
6847
7009
|
// prevent infinity loop if there are some characters outside the range
|
|
@@ -6851,6 +7013,18 @@
|
|
|
6851
7013
|
}
|
|
6852
7014
|
return vFirstChild;
|
|
6853
7015
|
};
|
|
7016
|
+
function setEffectBackRefFromVNodeData(vParent, value, container) {
|
|
7017
|
+
const deserializedSubMap = container.$getObjectById$(value);
|
|
7018
|
+
if (!vParent[_EFFECT_BACK_REF]) {
|
|
7019
|
+
Object.defineProperty(vParent, _EFFECT_BACK_REF, {
|
|
7020
|
+
value: deserializedSubMap,
|
|
7021
|
+
});
|
|
7022
|
+
}
|
|
7023
|
+
else {
|
|
7024
|
+
const subMap = vParent[_EFFECT_BACK_REF];
|
|
7025
|
+
mergeMaps(subMap, deserializedSubMap);
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
6854
7028
|
const processVNodeData$1 = (vData, callback) => {
|
|
6855
7029
|
let nextToConsumeIdx = 0;
|
|
6856
7030
|
let ch = 0;
|
|
@@ -6895,8 +7069,9 @@
|
|
|
6895
7069
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6896
7070
|
vnode_ensureElementInflated(vnode);
|
|
6897
7071
|
const keys = [];
|
|
6898
|
-
|
|
6899
|
-
|
|
7072
|
+
const props = vnode_getProps(vnode);
|
|
7073
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
7074
|
+
const key = props[i];
|
|
6900
7075
|
if (!key.startsWith(Q_PROPS_SEPARATOR)) {
|
|
6901
7076
|
keys.push(key);
|
|
6902
7077
|
}
|
|
@@ -6909,22 +7084,23 @@
|
|
|
6909
7084
|
const type = vnode[VNodeProps.flags];
|
|
6910
7085
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6911
7086
|
vnode_ensureElementInflated(vnode);
|
|
6912
|
-
const
|
|
7087
|
+
const props = vnode_getProps(vnode);
|
|
7088
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6913
7089
|
if (idx >= 0) {
|
|
6914
|
-
if (
|
|
7090
|
+
if (props[idx + 1] != value && (type & VNodeFlags.Element) !== 0) {
|
|
6915
7091
|
// Values are different, update DOM
|
|
6916
7092
|
const element = vnode[ElementVNodeProps.element];
|
|
6917
7093
|
journal && journal.push(VNodeJournalOpCode.SetAttribute, element, key, value);
|
|
6918
7094
|
}
|
|
6919
7095
|
if (value == null) {
|
|
6920
|
-
|
|
7096
|
+
props.splice(idx, 2);
|
|
6921
7097
|
}
|
|
6922
7098
|
else {
|
|
6923
|
-
|
|
7099
|
+
props[idx + 1] = value;
|
|
6924
7100
|
}
|
|
6925
7101
|
}
|
|
6926
7102
|
else if (value != null) {
|
|
6927
|
-
|
|
7103
|
+
props.splice(idx ^ -1, 0, key, value);
|
|
6928
7104
|
if ((type & VNodeFlags.Element) !== 0) {
|
|
6929
7105
|
// New value, update DOM
|
|
6930
7106
|
const element = vnode[ElementVNodeProps.element];
|
|
@@ -6937,7 +7113,8 @@
|
|
|
6937
7113
|
const type = vnode[VNodeProps.flags];
|
|
6938
7114
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6939
7115
|
vnode_ensureElementInflated(vnode);
|
|
6940
|
-
|
|
7116
|
+
const props = vnode_getProps(vnode);
|
|
7117
|
+
return mapArray_get(props, key, 0);
|
|
6941
7118
|
}
|
|
6942
7119
|
return null;
|
|
6943
7120
|
};
|
|
@@ -6945,11 +7122,12 @@
|
|
|
6945
7122
|
const type = vnode[VNodeProps.flags];
|
|
6946
7123
|
if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
|
|
6947
7124
|
type & VNodeFlags.Element && vnode_ensureElementInflated(vnode);
|
|
6948
|
-
const
|
|
7125
|
+
const props = vnode_getProps(vnode);
|
|
7126
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6949
7127
|
if (idx >= 0) {
|
|
6950
|
-
let value =
|
|
7128
|
+
let value = props[idx + 1];
|
|
6951
7129
|
if (typeof value === 'string' && getObject) {
|
|
6952
|
-
|
|
7130
|
+
props[idx + 1] = value = getObject(value);
|
|
6953
7131
|
}
|
|
6954
7132
|
return value;
|
|
6955
7133
|
}
|
|
@@ -6958,12 +7136,13 @@
|
|
|
6958
7136
|
};
|
|
6959
7137
|
const vnode_setProp = (vnode, key, value) => {
|
|
6960
7138
|
ensureElementOrVirtualVNode(vnode);
|
|
6961
|
-
const
|
|
7139
|
+
const props = vnode_getProps(vnode);
|
|
7140
|
+
const idx = mapApp_findIndx(props, key, 0);
|
|
6962
7141
|
if (idx >= 0) {
|
|
6963
|
-
|
|
7142
|
+
props[idx + 1] = value;
|
|
6964
7143
|
}
|
|
6965
7144
|
else if (value != null) {
|
|
6966
|
-
|
|
7145
|
+
props.splice(idx ^ -1, 0, key, value);
|
|
6967
7146
|
}
|
|
6968
7147
|
};
|
|
6969
7148
|
const vnode_getPropStartIndex = (vnode) => {
|
|
@@ -6976,6 +7155,9 @@
|
|
|
6976
7155
|
}
|
|
6977
7156
|
throw qError(QError.invalidVNodeType, [type]);
|
|
6978
7157
|
};
|
|
7158
|
+
const vnode_getProps = (vnode) => {
|
|
7159
|
+
return vnode[vnode_getPropStartIndex(vnode)];
|
|
7160
|
+
};
|
|
6979
7161
|
const vnode_getParent = (vnode) => {
|
|
6980
7162
|
return vnode[VNodeProps.parent] || null;
|
|
6981
7163
|
};
|
|
@@ -7127,9 +7309,6 @@
|
|
|
7127
7309
|
else if (peek() === VNodeDataChar.PROPS) {
|
|
7128
7310
|
vnode_setAttr(null, vParent, ELEMENT_PROPS, consumeValue());
|
|
7129
7311
|
}
|
|
7130
|
-
else if (peek() === VNodeDataChar.SLOT_REF) {
|
|
7131
|
-
vnode_setAttr(null, vParent, QSlotRef, consumeValue());
|
|
7132
|
-
}
|
|
7133
7312
|
else if (peek() === VNodeDataChar.KEY) {
|
|
7134
7313
|
vnode_setAttr(null, vParent, ELEMENT_KEY, consumeValue());
|
|
7135
7314
|
}
|
|
@@ -7139,8 +7318,14 @@
|
|
|
7139
7318
|
else if (peek() === VNodeDataChar.SEQ_IDX) {
|
|
7140
7319
|
vnode_setAttr(null, vParent, ELEMENT_SEQ_IDX, consumeValue());
|
|
7141
7320
|
}
|
|
7142
|
-
else if (peek() === VNodeDataChar.
|
|
7143
|
-
|
|
7321
|
+
else if (peek() === VNodeDataChar.BACK_REFS) {
|
|
7322
|
+
if (!container) {
|
|
7323
|
+
container = getDomContainer(element);
|
|
7324
|
+
}
|
|
7325
|
+
setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
|
|
7326
|
+
}
|
|
7327
|
+
else if (peek() === VNodeDataChar.SLOT_PARENT) {
|
|
7328
|
+
vnode_setProp(vParent, QSlotParent, consumeValue());
|
|
7144
7329
|
}
|
|
7145
7330
|
else if (peek() === VNodeDataChar.CONTEXT) {
|
|
7146
7331
|
vnode_setAttr(null, vParent, QCtxAttr, consumeValue());
|
|
@@ -7248,23 +7433,20 @@
|
|
|
7248
7433
|
};
|
|
7249
7434
|
const VNodeArray = class VNode extends Array {
|
|
7250
7435
|
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);
|
|
7436
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, element, elementName, []);
|
|
7253
7437
|
return vnode;
|
|
7254
7438
|
}
|
|
7255
7439
|
static createText(flags, parent, previousSibling, nextSibling, textNode, text) {
|
|
7256
|
-
const vnode = new VNode(flags, parent, previousSibling, nextSibling);
|
|
7257
|
-
vnode.push(textNode, text);
|
|
7440
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, textNode, text);
|
|
7258
7441
|
return vnode;
|
|
7259
7442
|
}
|
|
7260
7443
|
static createVirtual(flags, parent, previousSibling, nextSibling, firstChild, lastChild) {
|
|
7261
|
-
const vnode = new VNode(flags, parent, previousSibling, nextSibling);
|
|
7262
|
-
vnode.push(firstChild, lastChild);
|
|
7444
|
+
const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, []);
|
|
7263
7445
|
return vnode;
|
|
7264
7446
|
}
|
|
7265
|
-
constructor(flags, parent, previousSibling, nextSibling) {
|
|
7266
|
-
|
|
7267
|
-
|
|
7447
|
+
constructor(flags, parent, previousSibling, nextSibling, ...rest) {
|
|
7448
|
+
// @ts-expect-error
|
|
7449
|
+
super(flags, parent, previousSibling, nextSibling, ...rest);
|
|
7268
7450
|
if (build.isDev) {
|
|
7269
7451
|
this.toString = vnode_toString;
|
|
7270
7452
|
}
|
|
@@ -7329,10 +7511,12 @@
|
|
|
7329
7511
|
return returnValue;
|
|
7330
7512
|
}
|
|
7331
7513
|
const newInvokeContextFromTuple = ([element, event, url]) => {
|
|
7332
|
-
const
|
|
7514
|
+
const domContainer = getDomContainer(element);
|
|
7515
|
+
const container = domContainer.element;
|
|
7516
|
+
const vNode = container ? vnode_locate(domContainer.rootVNode, element) : undefined;
|
|
7333
7517
|
const locale = container?.getAttribute(QLocaleAttr) || undefined;
|
|
7334
7518
|
locale && setLocale(locale);
|
|
7335
|
-
return newInvokeContext(locale,
|
|
7519
|
+
return newInvokeContext(locale, vNode, element, event, url);
|
|
7336
7520
|
};
|
|
7337
7521
|
// TODO how about putting url and locale (and event/custom?) in to a "static" object
|
|
7338
7522
|
const newInvokeContext = (locale, hostElement, element, event, url) => {
|
|
@@ -7367,16 +7551,14 @@
|
|
|
7367
7551
|
* @param property `true` - subscriber is component `false` - subscriber is VNode `string` -
|
|
7368
7552
|
* subscriber is property
|
|
7369
7553
|
* @param container
|
|
7554
|
+
* @param data - Additional subscription data
|
|
7370
7555
|
* @returns
|
|
7371
7556
|
*/
|
|
7372
7557
|
const trackSignal = (fn, subscriber, property, container, data) => {
|
|
7373
7558
|
const previousSubscriber = trackInvocation.$effectSubscriber$;
|
|
7374
7559
|
const previousContainer = trackInvocation.$container$;
|
|
7375
7560
|
try {
|
|
7376
|
-
trackInvocation.$effectSubscriber$ =
|
|
7377
|
-
if (data) {
|
|
7378
|
-
trackInvocation.$effectSubscriber$.push(data);
|
|
7379
|
-
}
|
|
7561
|
+
trackInvocation.$effectSubscriber$ = getSubscriber(subscriber, property, data);
|
|
7380
7562
|
trackInvocation.$container$ = container;
|
|
7381
7563
|
return invoke(trackInvocation, fn);
|
|
7382
7564
|
}
|
|
@@ -7397,8 +7579,16 @@
|
|
|
7397
7579
|
if (iCtx) {
|
|
7398
7580
|
const hostElement = iCtx.$hostElement$;
|
|
7399
7581
|
let element = null;
|
|
7400
|
-
if (
|
|
7401
|
-
|
|
7582
|
+
if (hostElement != null) {
|
|
7583
|
+
if (vnode_isVNode(hostElement)) {
|
|
7584
|
+
if (vnode_isElementVNode(hostElement)) {
|
|
7585
|
+
element = vnode_getNode(hostElement);
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7588
|
+
else {
|
|
7589
|
+
// isSSRnode
|
|
7590
|
+
element = hostElement;
|
|
7591
|
+
}
|
|
7402
7592
|
}
|
|
7403
7593
|
return element ?? iCtx.$qrl$?.$setContainer$(undefined);
|
|
7404
7594
|
}
|
|
@@ -8034,12 +8224,12 @@
|
|
|
8034
8224
|
$storeProxyMap$ = new WeakMap();
|
|
8035
8225
|
$qFuncs$;
|
|
8036
8226
|
$instanceHash$;
|
|
8037
|
-
|
|
8227
|
+
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
8228
|
+
$stateData$;
|
|
8038
8229
|
$styleIds$ = null;
|
|
8039
|
-
$vnodeLocate$ = (id) => vnode_locate(this.rootVNode, id);
|
|
8040
8230
|
$renderCount$ = 0;
|
|
8041
8231
|
constructor(element) {
|
|
8042
|
-
super(() => this.scheduleRender(), () => vnode_applyJournal(this.$journal$), {}, element.getAttribute(
|
|
8232
|
+
super(() => this.scheduleRender(), () => vnode_applyJournal(this.$journal$), {}, element.getAttribute(QLocaleAttr));
|
|
8043
8233
|
this.qContainer = element.getAttribute(QContainerAttr);
|
|
8044
8234
|
if (!this.qContainer) {
|
|
8045
8235
|
throw qError(QError.elementWithoutContainer);
|
|
@@ -8062,29 +8252,29 @@
|
|
|
8062
8252
|
this.rootVNode = vnode_newUnMaterializedElement(this.element);
|
|
8063
8253
|
// These are here to initialize all properties at once for single class transition
|
|
8064
8254
|
this.$rawStateData$ = null;
|
|
8065
|
-
this
|
|
8255
|
+
this.$stateData$ = null;
|
|
8066
8256
|
const document = this.element.ownerDocument;
|
|
8067
8257
|
if (!document.qVNodeData) {
|
|
8068
8258
|
processVNodeData(document);
|
|
8069
8259
|
}
|
|
8070
8260
|
this.$rawStateData$ = [];
|
|
8071
|
-
this
|
|
8261
|
+
this.$stateData$ = [];
|
|
8072
8262
|
const qwikStates = element.querySelectorAll('script[type="qwik/state"]');
|
|
8073
8263
|
if (qwikStates.length !== 0) {
|
|
8074
8264
|
const lastState = qwikStates[qwikStates.length - 1];
|
|
8075
8265
|
this.$rawStateData$ = JSON.parse(lastState.textContent);
|
|
8076
|
-
this
|
|
8266
|
+
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
8077
8267
|
}
|
|
8078
8268
|
this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
|
|
8079
8269
|
}
|
|
8080
8270
|
$setRawState$(id, vParent) {
|
|
8081
|
-
this
|
|
8271
|
+
this.$stateData$[id] = vParent;
|
|
8082
8272
|
}
|
|
8083
8273
|
parseQRL(qrl) {
|
|
8084
8274
|
return inflateQRL(this, parseQRL(qrl));
|
|
8085
8275
|
}
|
|
8086
8276
|
handleError(err, host) {
|
|
8087
|
-
if (qDev) {
|
|
8277
|
+
if (qDev && host) {
|
|
8088
8278
|
// Clean vdom
|
|
8089
8279
|
if (typeof document !== 'undefined') {
|
|
8090
8280
|
const vHost = host;
|
|
@@ -8108,7 +8298,7 @@
|
|
|
8108
8298
|
throw err;
|
|
8109
8299
|
}
|
|
8110
8300
|
}
|
|
8111
|
-
const errorStore = this.resolveContext(host, ERROR_CONTEXT);
|
|
8301
|
+
const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
|
|
8112
8302
|
if (!errorStore) {
|
|
8113
8303
|
throw err;
|
|
8114
8304
|
}
|
|
@@ -8144,7 +8334,7 @@
|
|
|
8144
8334
|
vNode =
|
|
8145
8335
|
vnode_getParent(vNode) ||
|
|
8146
8336
|
// If virtual node, than it could be a slot so we need to read its parent.
|
|
8147
|
-
vnode_getProp(vNode, QSlotParent, this
|
|
8337
|
+
vnode_getProp(vNode, QSlotParent, this.vNodeLocate);
|
|
8148
8338
|
}
|
|
8149
8339
|
else {
|
|
8150
8340
|
vNode = vnode_getParent(vNode);
|
|
@@ -8164,7 +8354,7 @@
|
|
|
8164
8354
|
case ELEMENT_PROPS:
|
|
8165
8355
|
case OnRenderProp:
|
|
8166
8356
|
case QCtxAttr:
|
|
8167
|
-
case
|
|
8357
|
+
case QBackRefs:
|
|
8168
8358
|
getObjectById = this.$getObjectById$;
|
|
8169
8359
|
break;
|
|
8170
8360
|
case ELEMENT_SEQ_IDX:
|
|
@@ -8177,7 +8367,7 @@
|
|
|
8177
8367
|
scheduleRender() {
|
|
8178
8368
|
this.$renderCount$++;
|
|
8179
8369
|
this.renderDone ||= getPlatform().nextTick(() => this.processChores());
|
|
8180
|
-
return this.renderDone;
|
|
8370
|
+
return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
|
|
8181
8371
|
}
|
|
8182
8372
|
processChores() {
|
|
8183
8373
|
let renderCount = this.$renderCount$;
|
|
@@ -8200,12 +8390,13 @@
|
|
|
8200
8390
|
ensureProjectionResolved(vNode) {
|
|
8201
8391
|
if ((vNode[VNodeProps.flags] & VNodeFlags.Resolved) === 0) {
|
|
8202
8392
|
vNode[VNodeProps.flags] |= VNodeFlags.Resolved;
|
|
8203
|
-
|
|
8204
|
-
|
|
8393
|
+
const props = vnode_getProps(vNode);
|
|
8394
|
+
for (let i = 0; i < props.length; i = i + 2) {
|
|
8395
|
+
const prop = props[i];
|
|
8205
8396
|
if (isSlotProp(prop)) {
|
|
8206
|
-
const value =
|
|
8397
|
+
const value = props[i + 1];
|
|
8207
8398
|
if (typeof value == 'string') {
|
|
8208
|
-
|
|
8399
|
+
props[i + 1] = this.vNodeLocate(value);
|
|
8209
8400
|
}
|
|
8210
8401
|
}
|
|
8211
8402
|
}
|
|
@@ -8216,7 +8407,7 @@
|
|
|
8216
8407
|
id = parseFloat(id);
|
|
8217
8408
|
}
|
|
8218
8409
|
assertTrue(id < this.$rawStateData$.length / 2, `Invalid reference: ${id} >= ${this.$rawStateData$.length / 2}`);
|
|
8219
|
-
return this
|
|
8410
|
+
return this.$stateData$[id];
|
|
8220
8411
|
};
|
|
8221
8412
|
getSyncFn(id) {
|
|
8222
8413
|
const fn = this.$qFuncs$[id];
|
|
@@ -8288,8 +8479,7 @@
|
|
|
8288
8479
|
? parseInt(property, 10)
|
|
8289
8480
|
: NaN;
|
|
8290
8481
|
if (Number.isNaN(i) || i < 0 || i >= this.$length$) {
|
|
8291
|
-
|
|
8292
|
-
return out;
|
|
8482
|
+
return Reflect.get(target, property, receiver);
|
|
8293
8483
|
}
|
|
8294
8484
|
// The serialized data is an array with 2 values for each item
|
|
8295
8485
|
const idx = i * 2;
|
|
@@ -8355,6 +8545,7 @@
|
|
|
8355
8545
|
switch (typeId) {
|
|
8356
8546
|
case TypeIds.Object:
|
|
8357
8547
|
// We use getters for making complex values lazy
|
|
8548
|
+
// TODO scan the data for computeQRLs and schedule resolve chores
|
|
8358
8549
|
for (let i = 0; i < data.length; i += 4) {
|
|
8359
8550
|
const key = deserializeData(container, data[i], data[i + 1]);
|
|
8360
8551
|
const valType = data[i + 2];
|
|
@@ -8394,7 +8585,7 @@
|
|
|
8394
8585
|
task.$flags$ = v[1];
|
|
8395
8586
|
task.$index$ = v[2];
|
|
8396
8587
|
task.$el$ = v[3];
|
|
8397
|
-
task
|
|
8588
|
+
task[_EFFECT_BACK_REF] = v[4];
|
|
8398
8589
|
task.$state$ = v[5];
|
|
8399
8590
|
break;
|
|
8400
8591
|
case TypeIds.Resource:
|
|
@@ -8417,12 +8608,9 @@
|
|
|
8417
8608
|
break;
|
|
8418
8609
|
case TypeIds.Store:
|
|
8419
8610
|
case TypeIds.StoreArray: {
|
|
8420
|
-
const [value, flags, effects
|
|
8611
|
+
const [value, flags, effects] = data;
|
|
8421
8612
|
const store = getOrCreateStore(value, flags, container);
|
|
8422
8613
|
const storeHandler = getStoreHandler(store);
|
|
8423
|
-
if (storeEffect) {
|
|
8424
|
-
effects[STORE_ARRAY_PROP] = storeEffect;
|
|
8425
|
-
}
|
|
8426
8614
|
storeHandler.$effects$ = effects;
|
|
8427
8615
|
target = store;
|
|
8428
8616
|
break;
|
|
@@ -8431,7 +8619,7 @@
|
|
|
8431
8619
|
const signal = target;
|
|
8432
8620
|
const d = data;
|
|
8433
8621
|
signal.$untrackedValue$ = d[0];
|
|
8434
|
-
signal.$effects$ = d.slice(1);
|
|
8622
|
+
signal.$effects$ = new Set(d.slice(1));
|
|
8435
8623
|
break;
|
|
8436
8624
|
}
|
|
8437
8625
|
case TypeIds.WrappedSignal: {
|
|
@@ -8439,10 +8627,11 @@
|
|
|
8439
8627
|
const d = data;
|
|
8440
8628
|
signal.$func$ = container.getSyncFn(d[0]);
|
|
8441
8629
|
signal.$args$ = d[1];
|
|
8442
|
-
signal
|
|
8630
|
+
signal[_EFFECT_BACK_REF] = d[2];
|
|
8443
8631
|
signal.$untrackedValue$ = d[3];
|
|
8444
|
-
signal.$
|
|
8445
|
-
signal.$
|
|
8632
|
+
signal.$flags$ = d[4];
|
|
8633
|
+
signal.$hostElement$ = d[5];
|
|
8634
|
+
signal.$effects$ = new Set(d.slice(6));
|
|
8446
8635
|
break;
|
|
8447
8636
|
}
|
|
8448
8637
|
case TypeIds.ComputedSignal: {
|
|
@@ -8454,7 +8643,7 @@
|
|
|
8454
8643
|
computed.$untrackedValue$ = d[2];
|
|
8455
8644
|
}
|
|
8456
8645
|
else {
|
|
8457
|
-
computed.$
|
|
8646
|
+
computed.$flags$ |= SignalFlags.INVALID;
|
|
8458
8647
|
/**
|
|
8459
8648
|
* If we try to compute value and the qrl is not resolved, then system throws an error with
|
|
8460
8649
|
* qrl promise. To prevent that we should early resolve computed qrl while computed
|
|
@@ -8562,6 +8751,7 @@
|
|
|
8562
8751
|
EMPTY_ARRAY,
|
|
8563
8752
|
EMPTY_OBJ,
|
|
8564
8753
|
NEEDS_COMPUTATION,
|
|
8754
|
+
STORE_ALL_PROPS,
|
|
8565
8755
|
Slot,
|
|
8566
8756
|
Fragment,
|
|
8567
8757
|
NaN,
|
|
@@ -8642,6 +8832,8 @@
|
|
|
8642
8832
|
reject = rej;
|
|
8643
8833
|
});
|
|
8644
8834
|
resolvers.set(promise, [resolve, reject]);
|
|
8835
|
+
// Don't leave unhandled promise rejections
|
|
8836
|
+
promise.catch(() => { });
|
|
8645
8837
|
return promise;
|
|
8646
8838
|
case TypeIds.Uint8Array:
|
|
8647
8839
|
const encodedLength = value.length;
|
|
@@ -8651,12 +8843,9 @@
|
|
|
8651
8843
|
return new Uint8Array(decodedLength);
|
|
8652
8844
|
case TypeIds.PropsProxy:
|
|
8653
8845
|
return createPropsProxy(null, null);
|
|
8654
|
-
case TypeIds.RefVNode:
|
|
8655
8846
|
case TypeIds.VNode:
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
return vnodeOrDocument;
|
|
8659
|
-
}
|
|
8847
|
+
return retrieveVNodeOrDocument(container, value);
|
|
8848
|
+
case TypeIds.RefVNode:
|
|
8660
8849
|
const vNode = retrieveVNodeOrDocument(container, value);
|
|
8661
8850
|
if (vnode_isVNode(vNode)) {
|
|
8662
8851
|
return vnode_getNode(vNode);
|
|
@@ -8665,7 +8854,7 @@
|
|
|
8665
8854
|
throw qError(QError.serializeErrorExpectedVNode, [typeof vNode]);
|
|
8666
8855
|
}
|
|
8667
8856
|
case TypeIds.EffectData:
|
|
8668
|
-
return new
|
|
8857
|
+
return new SubscriptionData({});
|
|
8669
8858
|
default:
|
|
8670
8859
|
throw qError(QError.serializeErrorCannotAllocate, [typeId]);
|
|
8671
8860
|
}
|
|
@@ -8697,7 +8886,7 @@
|
|
|
8697
8886
|
assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
8698
8887
|
qrlRef = backChannel.get(symbol);
|
|
8699
8888
|
}
|
|
8700
|
-
return createQRL(chunk, symbol, qrlRef, null, captureIds, null
|
|
8889
|
+
return createQRL(chunk, symbol, qrlRef, null, captureIds, null);
|
|
8701
8890
|
}
|
|
8702
8891
|
function inflateQRL(container, qrl) {
|
|
8703
8892
|
const captureIds = qrl.$capture$;
|
|
@@ -8815,7 +9004,7 @@
|
|
|
8815
9004
|
/** Visit an object, adding anything that will be serialized as to scan */
|
|
8816
9005
|
const visit = (obj) => {
|
|
8817
9006
|
if (typeof obj === 'function') {
|
|
8818
|
-
if (isQrl(obj)) {
|
|
9007
|
+
if (isQrl$1(obj)) {
|
|
8819
9008
|
if (obj.$captureRef$) {
|
|
8820
9009
|
discoveredValues.push(...obj.$captureRef$);
|
|
8821
9010
|
}
|
|
@@ -8834,6 +9023,7 @@
|
|
|
8834
9023
|
obj instanceof RegExp ||
|
|
8835
9024
|
obj instanceof Uint8Array ||
|
|
8836
9025
|
obj instanceof URLSearchParams ||
|
|
9026
|
+
vnode_isVNode(obj) ||
|
|
8837
9027
|
(typeof FormData !== 'undefined' && obj instanceof FormData) ||
|
|
8838
9028
|
// Ignore the no serialize objects
|
|
8839
9029
|
fastSkipSerialize(obj)) ;
|
|
@@ -8843,8 +9033,7 @@
|
|
|
8843
9033
|
else if (isStore(obj)) {
|
|
8844
9034
|
const target = getStoreTarget(obj);
|
|
8845
9035
|
const effects = getStoreHandler(obj).$effects$;
|
|
8846
|
-
|
|
8847
|
-
discoveredValues.push(target, effects, storeEffect);
|
|
9036
|
+
discoveredValues.push(target, effects);
|
|
8848
9037
|
for (const prop in target) {
|
|
8849
9038
|
const propValue = target[prop];
|
|
8850
9039
|
if (storeProxyMap.has(propValue)) {
|
|
@@ -8867,20 +9056,19 @@
|
|
|
8867
9056
|
*/
|
|
8868
9057
|
const v = obj instanceof WrappedSignal
|
|
8869
9058
|
? obj.untrackedValue
|
|
8870
|
-
: obj instanceof ComputedSignal &&
|
|
9059
|
+
: obj instanceof ComputedSignal &&
|
|
9060
|
+
(obj.$flags$ & SignalFlags.INVALID || fastSkipSerialize(obj))
|
|
8871
9061
|
? NEEDS_COMPUTATION
|
|
8872
9062
|
: obj.$untrackedValue$;
|
|
8873
9063
|
if (v !== NEEDS_COMPUTATION) {
|
|
8874
9064
|
discoveredValues.push(v);
|
|
8875
9065
|
}
|
|
8876
9066
|
if (obj.$effects$) {
|
|
8877
|
-
discoveredValues.push(
|
|
9067
|
+
discoveredValues.push(obj.$effects$);
|
|
8878
9068
|
}
|
|
8879
9069
|
// WrappedSignal uses syncQrl which has no captured refs
|
|
8880
9070
|
if (obj instanceof WrappedSignal) {
|
|
8881
|
-
|
|
8882
|
-
discoveredValues.push(...obj.$effectDependencies$);
|
|
8883
|
-
}
|
|
9071
|
+
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
|
|
8884
9072
|
if (obj.$args$) {
|
|
8885
9073
|
discoveredValues.push(...obj.$args$);
|
|
8886
9074
|
}
|
|
@@ -8889,11 +9077,13 @@
|
|
|
8889
9077
|
}
|
|
8890
9078
|
}
|
|
8891
9079
|
else if (obj instanceof ComputedSignal) {
|
|
9080
|
+
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
|
|
8892
9081
|
discoveredValues.push(obj.$computeQrl$);
|
|
8893
9082
|
}
|
|
8894
9083
|
}
|
|
8895
9084
|
else if (obj instanceof Task) {
|
|
8896
|
-
discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state
|
|
9085
|
+
discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state$);
|
|
9086
|
+
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
|
|
8897
9087
|
}
|
|
8898
9088
|
else if (isSsrNode(obj)) {
|
|
8899
9089
|
discoverValuesForVNodeData(obj.vnodeData, discoveredValues);
|
|
@@ -8912,7 +9102,7 @@
|
|
|
8912
9102
|
else if (Array.isArray(obj)) {
|
|
8913
9103
|
discoveredValues.push(...obj);
|
|
8914
9104
|
}
|
|
8915
|
-
else if (isQrl(obj)) {
|
|
9105
|
+
else if (isQrl$1(obj)) {
|
|
8916
9106
|
obj.$captureRef$ && obj.$captureRef$.length && discoveredValues.push(...obj.$captureRef$);
|
|
8917
9107
|
}
|
|
8918
9108
|
else if (isPropsProxy(obj)) {
|
|
@@ -8928,7 +9118,7 @@
|
|
|
8928
9118
|
});
|
|
8929
9119
|
promises.push(obj);
|
|
8930
9120
|
}
|
|
8931
|
-
else if (obj instanceof
|
|
9121
|
+
else if (obj instanceof SubscriptionData) {
|
|
8932
9122
|
discoveredValues.push(obj.data);
|
|
8933
9123
|
}
|
|
8934
9124
|
else if (isObjectLiteral(obj)) {
|
|
@@ -8973,15 +9163,20 @@
|
|
|
8973
9163
|
for (const value of vnodeData) {
|
|
8974
9164
|
if (isSsrAttrs(value)) {
|
|
8975
9165
|
for (let i = 1; i < value.length; i += 2) {
|
|
8976
|
-
|
|
9166
|
+
const attrValue = value[i];
|
|
9167
|
+
if (typeof attrValue === 'string') {
|
|
8977
9168
|
continue;
|
|
8978
9169
|
}
|
|
8979
|
-
const attrValue = value[i];
|
|
8980
9170
|
discoveredValues.push(attrValue);
|
|
8981
9171
|
}
|
|
8982
9172
|
}
|
|
8983
9173
|
}
|
|
8984
9174
|
};
|
|
9175
|
+
const discoverEffectBackRefs = (effectsBackRefs, discoveredValues) => {
|
|
9176
|
+
if (effectsBackRefs) {
|
|
9177
|
+
discoveredValues.push(effectsBackRefs);
|
|
9178
|
+
}
|
|
9179
|
+
};
|
|
8985
9180
|
const promiseResults = new WeakMap();
|
|
8986
9181
|
/**
|
|
8987
9182
|
* Format:
|
|
@@ -9053,7 +9248,7 @@
|
|
|
9053
9248
|
else if (value === Fragment) {
|
|
9054
9249
|
output(TypeIds.Constant, Constants.Fragment);
|
|
9055
9250
|
}
|
|
9056
|
-
else if (isQrl(value)) {
|
|
9251
|
+
else if (isQrl$1(value)) {
|
|
9057
9252
|
const qrl = qrlToString(serializationContext, value);
|
|
9058
9253
|
const id = serializationContext.$addRoot$(qrl);
|
|
9059
9254
|
output(TypeIds.QRL, id);
|
|
@@ -9128,6 +9323,9 @@
|
|
|
9128
9323
|
else if (value === NEEDS_COMPUTATION) {
|
|
9129
9324
|
output(TypeIds.Constant, Constants.NEEDS_COMPUTATION);
|
|
9130
9325
|
}
|
|
9326
|
+
else if (value === STORE_ALL_PROPS) {
|
|
9327
|
+
output(TypeIds.Constant, Constants.STORE_ALL_PROPS);
|
|
9328
|
+
}
|
|
9131
9329
|
else {
|
|
9132
9330
|
throw qError(QError.serializeErrorUnknownType, [typeof value]);
|
|
9133
9331
|
}
|
|
@@ -9164,7 +9362,7 @@
|
|
|
9164
9362
|
: 0;
|
|
9165
9363
|
output(TypeIds.PropsProxy, out);
|
|
9166
9364
|
}
|
|
9167
|
-
else if (value instanceof
|
|
9365
|
+
else if (value instanceof SubscriptionData) {
|
|
9168
9366
|
output(TypeIds.EffectData, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
|
|
9169
9367
|
}
|
|
9170
9368
|
else if (isStore(value)) {
|
|
@@ -9175,6 +9373,7 @@
|
|
|
9175
9373
|
if (!res) {
|
|
9176
9374
|
throw qError(QError.serializeErrorUnvisited, ['resource']);
|
|
9177
9375
|
}
|
|
9376
|
+
// TODO the effects include the resourcereturn which has duplicate data
|
|
9178
9377
|
output(TypeIds.Resource, [...res, getStoreHandler(value).$effects$]);
|
|
9179
9378
|
}
|
|
9180
9379
|
else {
|
|
@@ -9182,7 +9381,6 @@
|
|
|
9182
9381
|
const storeTarget = getStoreTarget(value);
|
|
9183
9382
|
const flags = storeHandler.$flags$;
|
|
9184
9383
|
const effects = storeHandler.$effects$;
|
|
9185
|
-
const storeEffect = effects?.[STORE_ARRAY_PROP] ?? null;
|
|
9186
9384
|
const innerStores = [];
|
|
9187
9385
|
for (const prop in storeTarget) {
|
|
9188
9386
|
const propValue = storeTarget[prop];
|
|
@@ -9192,7 +9390,7 @@
|
|
|
9192
9390
|
serializationContext.$addRoot$(innerStore);
|
|
9193
9391
|
}
|
|
9194
9392
|
}
|
|
9195
|
-
const out = [storeTarget, flags, effects,
|
|
9393
|
+
const out = [storeTarget, flags, effects, ...innerStores];
|
|
9196
9394
|
while (out[out.length - 1] == null) {
|
|
9197
9395
|
out.pop();
|
|
9198
9396
|
}
|
|
@@ -9225,14 +9423,15 @@
|
|
|
9225
9423
|
* It can never be meant to become a vNode, because vNodes are internal only.
|
|
9226
9424
|
*/
|
|
9227
9425
|
const v = value instanceof ComputedSignal &&
|
|
9228
|
-
(value.$
|
|
9426
|
+
(value.$flags$ & SignalFlags.INVALID || fastSkipSerialize(value.$untrackedValue$))
|
|
9229
9427
|
? NEEDS_COMPUTATION
|
|
9230
9428
|
: value.$untrackedValue$;
|
|
9231
9429
|
if (value instanceof WrappedSignal) {
|
|
9232
9430
|
output(TypeIds.WrappedSignal, [
|
|
9233
9431
|
...serializeWrappingFn(serializationContext, value),
|
|
9234
|
-
value
|
|
9432
|
+
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
|
|
9235
9433
|
v,
|
|
9434
|
+
value.$flags$,
|
|
9236
9435
|
value.$hostElement$,
|
|
9237
9436
|
...(value.$effects$ || []),
|
|
9238
9437
|
]);
|
|
@@ -9338,7 +9537,7 @@
|
|
|
9338
9537
|
value.$flags$,
|
|
9339
9538
|
value.$index$,
|
|
9340
9539
|
value.$el$,
|
|
9341
|
-
value
|
|
9540
|
+
value[_EFFECT_BACK_REF],
|
|
9342
9541
|
value.$state$,
|
|
9343
9542
|
];
|
|
9344
9543
|
while (out[out.length - 1] == null) {
|
|
@@ -9361,12 +9560,27 @@
|
|
|
9361
9560
|
const out = btoa(buf).replace(/=+$/, '');
|
|
9362
9561
|
output(TypeIds.Uint8Array, out);
|
|
9363
9562
|
}
|
|
9563
|
+
else if (vnode_isVNode(value)) {
|
|
9564
|
+
output(TypeIds.Constant, Constants.Undefined);
|
|
9565
|
+
}
|
|
9364
9566
|
else {
|
|
9365
9567
|
throw qError(QError.serializeErrorUnknownType, [typeof value]);
|
|
9366
9568
|
}
|
|
9367
9569
|
};
|
|
9368
9570
|
writeValue(serializationContext.$roots$, -1);
|
|
9369
9571
|
}
|
|
9572
|
+
function filterEffectBackRefs(effectBackRef) {
|
|
9573
|
+
let effectBackRefToSerialize = null;
|
|
9574
|
+
if (effectBackRef) {
|
|
9575
|
+
for (const [effectProp, effect] of effectBackRef) {
|
|
9576
|
+
if (effect[EffectSubscriptionProp.BACK_REF]) {
|
|
9577
|
+
effectBackRefToSerialize ||= new Map();
|
|
9578
|
+
effectBackRefToSerialize.set(effectProp, effect);
|
|
9579
|
+
}
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9582
|
+
return effectBackRefToSerialize;
|
|
9583
|
+
}
|
|
9370
9584
|
function serializeWrappingFn(serializationContext, value) {
|
|
9371
9585
|
// if value is an object then we need to wrap this in ()
|
|
9372
9586
|
if (value.$funcStr$ && value.$funcStr$[0] === '{') {
|
|
@@ -9379,15 +9593,12 @@
|
|
|
9379
9593
|
function qrlToString(serializationContext, value) {
|
|
9380
9594
|
let symbol = value.$symbol$;
|
|
9381
9595
|
let chunk = value.$chunk$;
|
|
9382
|
-
const refSymbol = value.$refSymbol$ ?? symbol;
|
|
9383
9596
|
const platform = getPlatform();
|
|
9384
9597
|
if (platform) {
|
|
9385
|
-
const result = platform.chunkForSymbol(
|
|
9598
|
+
const result = platform.chunkForSymbol(symbol, chunk, value.dev?.file);
|
|
9386
9599
|
if (result) {
|
|
9387
9600
|
chunk = result[1];
|
|
9388
|
-
|
|
9389
|
-
symbol = result[0];
|
|
9390
|
-
}
|
|
9601
|
+
symbol = result[0];
|
|
9391
9602
|
}
|
|
9392
9603
|
}
|
|
9393
9604
|
const isSync = isSyncQrl(value);
|
|
@@ -9564,9 +9775,9 @@
|
|
|
9564
9775
|
return ((typeof obj === 'object' &&
|
|
9565
9776
|
obj !== null &&
|
|
9566
9777
|
(obj instanceof Signal || obj instanceof Task || isJSXNode(obj))) ||
|
|
9567
|
-
isQrl(obj));
|
|
9778
|
+
isQrl$1(obj));
|
|
9568
9779
|
};
|
|
9569
|
-
const canSerialize = (value) => {
|
|
9780
|
+
const canSerialize = (value, seen = new WeakSet()) => {
|
|
9570
9781
|
if (value == null ||
|
|
9571
9782
|
typeof value === 'string' ||
|
|
9572
9783
|
typeof value === 'number' ||
|
|
@@ -9575,6 +9786,10 @@
|
|
|
9575
9786
|
return true;
|
|
9576
9787
|
}
|
|
9577
9788
|
else if (typeof value === 'object') {
|
|
9789
|
+
if (seen.has(value)) {
|
|
9790
|
+
return true;
|
|
9791
|
+
}
|
|
9792
|
+
seen.add(value);
|
|
9578
9793
|
const proto = Object.getPrototypeOf(value);
|
|
9579
9794
|
if (isStore(value)) {
|
|
9580
9795
|
value = getStoreTarget(value);
|
|
@@ -9583,7 +9798,7 @@
|
|
|
9583
9798
|
for (const key in value) {
|
|
9584
9799
|
// if the value is a props proxy, then sometimes we could create a component-level subscription,
|
|
9585
9800
|
// so we should call untrack here to avoid tracking the value
|
|
9586
|
-
if (!canSerialize(untrack(() => value[key]))) {
|
|
9801
|
+
if (!canSerialize(untrack(() => value[key]), seen)) {
|
|
9587
9802
|
return false;
|
|
9588
9803
|
}
|
|
9589
9804
|
}
|
|
@@ -9591,7 +9806,7 @@
|
|
|
9591
9806
|
}
|
|
9592
9807
|
else if (proto == Array.prototype) {
|
|
9593
9808
|
for (let i = 0; i < value.length; i++) {
|
|
9594
|
-
if (!canSerialize(value[i])) {
|
|
9809
|
+
if (!canSerialize(value[i], seen)) {
|
|
9595
9810
|
return false;
|
|
9596
9811
|
}
|
|
9597
9812
|
}
|
|
@@ -9641,7 +9856,7 @@
|
|
|
9641
9856
|
}
|
|
9642
9857
|
}
|
|
9643
9858
|
else if (typeof value === 'function') {
|
|
9644
|
-
if (isQrl(value) || isQwikComponent(value)) {
|
|
9859
|
+
if (isQrl$1(value) || isQwikComponent(value)) {
|
|
9645
9860
|
return true;
|
|
9646
9861
|
}
|
|
9647
9862
|
}
|
|
@@ -9694,20 +9909,21 @@
|
|
|
9694
9909
|
Constants[Constants["EMPTY_ARRAY"] = 5] = "EMPTY_ARRAY";
|
|
9695
9910
|
Constants[Constants["EMPTY_OBJ"] = 6] = "EMPTY_OBJ";
|
|
9696
9911
|
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["
|
|
9912
|
+
Constants[Constants["STORE_ALL_PROPS"] = 8] = "STORE_ALL_PROPS";
|
|
9913
|
+
Constants[Constants["Slot"] = 9] = "Slot";
|
|
9914
|
+
Constants[Constants["Fragment"] = 10] = "Fragment";
|
|
9915
|
+
Constants[Constants["NaN"] = 11] = "NaN";
|
|
9916
|
+
Constants[Constants["PositiveInfinity"] = 12] = "PositiveInfinity";
|
|
9917
|
+
Constants[Constants["NegativeInfinity"] = 13] = "NegativeInfinity";
|
|
9918
|
+
Constants[Constants["MaxSafeInt"] = 14] = "MaxSafeInt";
|
|
9703
9919
|
// used for close fragment
|
|
9704
|
-
Constants[Constants["AlmostMaxSafeInt"] =
|
|
9705
|
-
Constants[Constants["MinSafeInt"] =
|
|
9920
|
+
Constants[Constants["AlmostMaxSafeInt"] = 15] = "AlmostMaxSafeInt";
|
|
9921
|
+
Constants[Constants["MinSafeInt"] = 16] = "MinSafeInt";
|
|
9706
9922
|
})(Constants || (Constants = {}));
|
|
9707
9923
|
|
|
9708
9924
|
/** @internal */
|
|
9709
9925
|
const verifySerializable = (value, preMessage) => {
|
|
9710
|
-
const seen = new
|
|
9926
|
+
const seen = new WeakSet();
|
|
9711
9927
|
return _verifySerializable(value, seen, '_', preMessage);
|
|
9712
9928
|
};
|
|
9713
9929
|
const _verifySerializable = (value, seen, ctx, preMessage) => {
|
|
@@ -9716,10 +9932,12 @@
|
|
|
9716
9932
|
return value;
|
|
9717
9933
|
}
|
|
9718
9934
|
if (shouldSerialize(unwrapped)) {
|
|
9719
|
-
if (
|
|
9720
|
-
|
|
9935
|
+
if (typeof unwrapped === 'object') {
|
|
9936
|
+
if (seen.has(unwrapped)) {
|
|
9937
|
+
return value;
|
|
9938
|
+
}
|
|
9939
|
+
seen.add(unwrapped);
|
|
9721
9940
|
}
|
|
9722
|
-
seen.add(unwrapped);
|
|
9723
9941
|
if (isSignal(unwrapped)) {
|
|
9724
9942
|
return value;
|
|
9725
9943
|
}
|
|
@@ -9823,16 +10041,7 @@
|
|
|
9823
10041
|
return input;
|
|
9824
10042
|
};
|
|
9825
10043
|
|
|
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) => {
|
|
10044
|
+
const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
|
|
9836
10045
|
if (qDev && qSerialize) {
|
|
9837
10046
|
if (captureRef) {
|
|
9838
10047
|
for (const item of captureRef) {
|
|
@@ -9854,9 +10063,14 @@
|
|
|
9854
10063
|
};
|
|
9855
10064
|
function bindFnToContext(currentCtx, beforeFn) {
|
|
9856
10065
|
// Note that we bind the current `this`
|
|
9857
|
-
|
|
9858
|
-
if (!
|
|
9859
|
-
|
|
10066
|
+
const bound = (...args) => {
|
|
10067
|
+
if (!qrl.resolved) {
|
|
10068
|
+
return qrl.resolve().then((fn) => {
|
|
10069
|
+
if (!isFunction(fn)) {
|
|
10070
|
+
throw qError(QError.qrlIsNotFunction);
|
|
10071
|
+
}
|
|
10072
|
+
return bound(...args);
|
|
10073
|
+
});
|
|
9860
10074
|
}
|
|
9861
10075
|
if (beforeFn && beforeFn() === false) {
|
|
9862
10076
|
return;
|
|
@@ -9869,13 +10083,14 @@
|
|
|
9869
10083
|
context.$qrl$ = qrl;
|
|
9870
10084
|
context.$event$ ||= this;
|
|
9871
10085
|
try {
|
|
9872
|
-
return invoke.call(this, context,
|
|
10086
|
+
return invoke.call(this, context, symbolRef, ...args);
|
|
9873
10087
|
}
|
|
9874
10088
|
finally {
|
|
9875
10089
|
context.$qrl$ = prevQrl;
|
|
9876
10090
|
context.$event$ = prevEvent;
|
|
9877
10091
|
}
|
|
9878
|
-
}
|
|
10092
|
+
};
|
|
10093
|
+
return bound;
|
|
9879
10094
|
}
|
|
9880
10095
|
const resolveLazy = (containerEl) => {
|
|
9881
10096
|
return symbolRef !== null ? symbolRef : resolve(containerEl);
|
|
@@ -9887,8 +10102,20 @@
|
|
|
9887
10102
|
}
|
|
9888
10103
|
return function (...args) {
|
|
9889
10104
|
let context = tryGetInvokeContext();
|
|
10105
|
+
// use the given qrl if it is the right one
|
|
9890
10106
|
if (context) {
|
|
9891
|
-
|
|
10107
|
+
// TODO check if this is necessary in production
|
|
10108
|
+
if (context.$qrl$?.$symbol$ === qrl.$symbol$) {
|
|
10109
|
+
return fn.apply(this, args);
|
|
10110
|
+
}
|
|
10111
|
+
const prevQrl = context.$qrl$;
|
|
10112
|
+
context.$qrl$ = qrl;
|
|
10113
|
+
try {
|
|
10114
|
+
return fn.apply(this, args);
|
|
10115
|
+
}
|
|
10116
|
+
finally {
|
|
10117
|
+
context.$qrl$ = prevQrl;
|
|
10118
|
+
}
|
|
9892
10119
|
}
|
|
9893
10120
|
context = newInvokeContext();
|
|
9894
10121
|
context.$qrl$ = qrl;
|
|
@@ -9916,11 +10143,11 @@
|
|
|
9916
10143
|
const start = now();
|
|
9917
10144
|
const ctx = tryGetInvokeContext();
|
|
9918
10145
|
if (symbolFn !== null) {
|
|
9919
|
-
symbolRef = symbolFn().then((module) => (qrl.resolved = symbolRef =
|
|
10146
|
+
symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
|
|
9920
10147
|
}
|
|
9921
10148
|
else {
|
|
9922
10149
|
const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
|
|
9923
|
-
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = symbolRef =
|
|
10150
|
+
symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
|
|
9924
10151
|
}
|
|
9925
10152
|
if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
|
|
9926
10153
|
symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
|
|
@@ -9943,10 +10170,9 @@
|
|
|
9943
10170
|
return invoke;
|
|
9944
10171
|
}
|
|
9945
10172
|
};
|
|
9946
|
-
const
|
|
9947
|
-
const hash = getSymbolHash(resolvedSymbol);
|
|
10173
|
+
const hash = getSymbolHash(symbol);
|
|
9948
10174
|
Object.assign(qrl, {
|
|
9949
|
-
getSymbol: () =>
|
|
10175
|
+
getSymbol: () => symbol,
|
|
9950
10176
|
getHash: () => hash,
|
|
9951
10177
|
getCaptured: () => captureRef,
|
|
9952
10178
|
resolve,
|
|
@@ -9954,7 +10180,6 @@
|
|
|
9954
10180
|
$setContainer$: setContainer,
|
|
9955
10181
|
$chunk$: chunk,
|
|
9956
10182
|
$symbol$: symbol,
|
|
9957
|
-
$refSymbol$: refSymbol,
|
|
9958
10183
|
$hash$: hash,
|
|
9959
10184
|
getFn: bindFnToContext,
|
|
9960
10185
|
$capture$: capture,
|
|
@@ -9963,8 +10188,8 @@
|
|
|
9963
10188
|
resolved: undefined,
|
|
9964
10189
|
});
|
|
9965
10190
|
if (symbolRef) {
|
|
9966
|
-
//
|
|
9967
|
-
symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = symbolRef =
|
|
10191
|
+
// Unwrap any promises
|
|
10192
|
+
symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = wrapFn((symbolRef = resolved))));
|
|
9968
10193
|
}
|
|
9969
10194
|
if (build.isDev) {
|
|
9970
10195
|
Object.defineProperty(qrl, '_devOnlySymbolRef', {
|
|
@@ -9978,20 +10203,6 @@
|
|
|
9978
10203
|
}
|
|
9979
10204
|
return qrl;
|
|
9980
10205
|
};
|
|
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
10206
|
const EMITTED = /*#__PURE__*/ new Set();
|
|
9996
10207
|
const emitUsedSymbol = (symbol, element, reqTime) => {
|
|
9997
10208
|
if (!EMITTED.has(symbol)) {
|
|
@@ -10104,7 +10315,7 @@
|
|
|
10104
10315
|
if (!qRuntimeQrl && qDev) {
|
|
10105
10316
|
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
10317
|
}
|
|
10107
|
-
return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null
|
|
10318
|
+
return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null);
|
|
10108
10319
|
};
|
|
10109
10320
|
/** @private Use To avoid optimizer replacement */
|
|
10110
10321
|
const dollar = $;
|
|
@@ -10130,7 +10341,7 @@
|
|
|
10130
10341
|
// eslint-disable-next-line no-new-func
|
|
10131
10342
|
fn = new Function('return ' + fn.toString())();
|
|
10132
10343
|
}
|
|
10133
|
-
return createQRL('', SYNC_QRL, fn, null, null, null
|
|
10344
|
+
return createQRL('', SYNC_QRL, fn, null, null, null);
|
|
10134
10345
|
};
|
|
10135
10346
|
/**
|
|
10136
10347
|
* Extract function into a synchronously loadable QRL.
|
|
@@ -10147,7 +10358,7 @@
|
|
|
10147
10358
|
serializedFn = fn.toString();
|
|
10148
10359
|
}
|
|
10149
10360
|
fn.serialized = serializedFn;
|
|
10150
|
-
return createQRL('', SYNC_QRL, fn, null, null, null
|
|
10361
|
+
return createQRL('', SYNC_QRL, fn, null, null, null);
|
|
10151
10362
|
};
|
|
10152
10363
|
|
|
10153
10364
|
/** @internal */
|
|
@@ -10866,6 +11077,21 @@
|
|
|
10866
11077
|
iCtx.$container$.$scheduler$(ChoreType.VISIBLE, task);
|
|
10867
11078
|
}
|
|
10868
11079
|
};
|
|
11080
|
+
const useRunTask = (task, eagerness) => {
|
|
11081
|
+
if (eagerness === 'intersection-observer') {
|
|
11082
|
+
useOn('qvisible', getTaskHandlerQrl(task));
|
|
11083
|
+
}
|
|
11084
|
+
else if (eagerness === 'document-ready') {
|
|
11085
|
+
useOnDocument('qinit', getTaskHandlerQrl(task));
|
|
11086
|
+
}
|
|
11087
|
+
else if (eagerness === 'document-idle') {
|
|
11088
|
+
useOnDocument('qidle', getTaskHandlerQrl(task));
|
|
11089
|
+
}
|
|
11090
|
+
};
|
|
11091
|
+
const getTaskHandlerQrl = (task) => {
|
|
11092
|
+
const taskHandler = createQRL(null, '_task', scheduleTask, null, null, [task]);
|
|
11093
|
+
return taskHandler;
|
|
11094
|
+
};
|
|
10869
11095
|
|
|
10870
11096
|
// <docs markdown="../readme.md#useResource">
|
|
10871
11097
|
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
@@ -11202,8 +11428,9 @@
|
|
|
11202
11428
|
exports.Slot = Slot;
|
|
11203
11429
|
exports._CONST_PROPS = _CONST_PROPS;
|
|
11204
11430
|
exports._DomContainer = DomContainer;
|
|
11431
|
+
exports._EFFECT_BACK_REF = _EFFECT_BACK_REF;
|
|
11205
11432
|
exports._EMPTY_ARRAY = EMPTY_ARRAY;
|
|
11206
|
-
exports._EffectData =
|
|
11433
|
+
exports._EffectData = SubscriptionData;
|
|
11207
11434
|
exports._IMMUTABLE = _IMMUTABLE;
|
|
11208
11435
|
exports._SharedContainer = _SharedContainer;
|
|
11209
11436
|
exports._VAR_PROPS = _VAR_PROPS;
|
|
@@ -11213,7 +11440,6 @@
|
|
|
11213
11440
|
exports._getContextEvent = _getContextEvent;
|
|
11214
11441
|
exports._getDomContainer = getDomContainer;
|
|
11215
11442
|
exports._getQContainerElement = _getQContainerElement;
|
|
11216
|
-
exports._hW = _hW;
|
|
11217
11443
|
exports._isJSXNode = isJSXNode;
|
|
11218
11444
|
exports._isStringifiable = isStringifiable;
|
|
11219
11445
|
exports._jsxBranch = _jsxBranch;
|
|
@@ -11227,13 +11453,16 @@
|
|
|
11227
11453
|
exports._qrlSync = _qrlSync;
|
|
11228
11454
|
exports._regSymbol = _regSymbol;
|
|
11229
11455
|
exports._restProps = _restProps;
|
|
11456
|
+
exports._run = queueQRL;
|
|
11230
11457
|
exports._serialize = _serialize;
|
|
11458
|
+
exports._task = scheduleTask;
|
|
11231
11459
|
exports._verifySerializable = verifySerializable;
|
|
11232
11460
|
exports._waitUntilRendered = _waitUntilRendered;
|
|
11233
11461
|
exports._walkJSX = _walkJSX;
|
|
11234
11462
|
exports._weakSerialize = _weakSerialize;
|
|
11235
11463
|
exports._wrapProp = _wrapProp;
|
|
11236
11464
|
exports._wrapSignal = _wrapSignal;
|
|
11465
|
+
exports._wrapStore = _wrapStore;
|
|
11237
11466
|
exports.component$ = component$;
|
|
11238
11467
|
exports.componentQrl = componentQrl;
|
|
11239
11468
|
exports.createComputed$ = createComputed$;
|