@b9g/crank 0.5.0-beta.2 → 0.5.0-beta.4
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/crank.cjs +506 -349
- package/crank.cjs.map +1 -1
- package/crank.d.ts +29 -54
- package/crank.js +506 -349
- package/crank.js.map +1 -1
- package/mod.cjs +2 -2
- package/mod.d.ts +1 -1
- package/mod.js +1 -1
- package/package.json +8 -8
- package/{xm.cjs → tags.cjs} +8 -8
- package/tags.cjs.map +1 -0
- package/tags.d.ts +2 -0
- package/{xm.js → tags.js} +9 -9
- package/tags.js.map +1 -0
- package/umd.js +506 -349
- package/umd.js.map +1 -1
- package/xm.cjs.map +0 -1
- package/xm.d.ts +0 -2
- package/xm.js.map +0 -1
package/crank.cjs
CHANGED
|
@@ -161,22 +161,6 @@ function createElement(tag, props, ...children) {
|
|
|
161
161
|
else if (children.length === 1) {
|
|
162
162
|
props1.children = children[0];
|
|
163
163
|
}
|
|
164
|
-
// string aliases for the special tags
|
|
165
|
-
// TODO: Does this logic belong here, or in the Element constructor
|
|
166
|
-
switch (tag) {
|
|
167
|
-
case "$FRAGMENT":
|
|
168
|
-
tag = Fragment;
|
|
169
|
-
break;
|
|
170
|
-
case "$PORTAL":
|
|
171
|
-
tag = Portal;
|
|
172
|
-
break;
|
|
173
|
-
case "$COPY":
|
|
174
|
-
tag = Copy;
|
|
175
|
-
break;
|
|
176
|
-
case "$RAW":
|
|
177
|
-
tag = Raw;
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
164
|
return new Element(tag, props1, key, ref, static_);
|
|
181
165
|
}
|
|
182
166
|
/** Clones a given element, shallowly copying the props object. */
|
|
@@ -255,13 +239,13 @@ function normalize(values) {
|
|
|
255
239
|
class Retainer {
|
|
256
240
|
constructor(el) {
|
|
257
241
|
this.el = el;
|
|
258
|
-
this.value = undefined;
|
|
259
242
|
this.ctx = undefined;
|
|
260
243
|
this.children = undefined;
|
|
261
|
-
this.
|
|
262
|
-
this.
|
|
263
|
-
this.
|
|
264
|
-
this.
|
|
244
|
+
this.value = undefined;
|
|
245
|
+
this.cachedChildValues = undefined;
|
|
246
|
+
this.fallbackValue = undefined;
|
|
247
|
+
this.inflightValue = undefined;
|
|
248
|
+
this.onNextValues = undefined;
|
|
265
249
|
}
|
|
266
250
|
}
|
|
267
251
|
/**
|
|
@@ -270,10 +254,10 @@ class Retainer {
|
|
|
270
254
|
* @returns The value of the element.
|
|
271
255
|
*/
|
|
272
256
|
function getValue(ret) {
|
|
273
|
-
if (typeof ret.
|
|
274
|
-
return typeof ret.
|
|
275
|
-
? getValue(ret.
|
|
276
|
-
: ret.
|
|
257
|
+
if (typeof ret.fallbackValue !== "undefined") {
|
|
258
|
+
return typeof ret.fallbackValue === "object"
|
|
259
|
+
? getValue(ret.fallbackValue)
|
|
260
|
+
: ret.fallbackValue;
|
|
277
261
|
}
|
|
278
262
|
else if (ret.el.tag === Portal) {
|
|
279
263
|
return;
|
|
@@ -289,8 +273,8 @@ function getValue(ret) {
|
|
|
289
273
|
* @returns A normalized array of nodes and strings.
|
|
290
274
|
*/
|
|
291
275
|
function getChildValues(ret) {
|
|
292
|
-
if (ret.
|
|
293
|
-
return wrap(ret.
|
|
276
|
+
if (ret.cachedChildValues) {
|
|
277
|
+
return wrap(ret.cachedChildValues);
|
|
294
278
|
}
|
|
295
279
|
const values = [];
|
|
296
280
|
const children = wrap(ret.children);
|
|
@@ -303,7 +287,7 @@ function getChildValues(ret) {
|
|
|
303
287
|
const values1 = normalize(values);
|
|
304
288
|
const tag = ret.el.tag;
|
|
305
289
|
if (typeof tag === "function" || (tag !== Fragment && tag !== Raw)) {
|
|
306
|
-
ret.
|
|
290
|
+
ret.cachedChildValues = unwrap(values1);
|
|
307
291
|
}
|
|
308
292
|
return values1;
|
|
309
293
|
}
|
|
@@ -320,7 +304,7 @@ const defaultRendererImpl = {
|
|
|
320
304
|
dispose: NOOP,
|
|
321
305
|
flush: NOOP,
|
|
322
306
|
};
|
|
323
|
-
const
|
|
307
|
+
const _RendererImpl = Symbol.for("crank.RendererImpl");
|
|
324
308
|
/**
|
|
325
309
|
* An abstract class which is subclassed to render to different target
|
|
326
310
|
* environments. This class is responsible for kicking off the rendering
|
|
@@ -334,7 +318,7 @@ const $RendererImpl = Symbol.for("crank.RendererImpl");
|
|
|
334
318
|
class Renderer {
|
|
335
319
|
constructor(impl) {
|
|
336
320
|
this.cache = new WeakMap();
|
|
337
|
-
this[
|
|
321
|
+
this[_RendererImpl] = {
|
|
338
322
|
...defaultRendererImpl,
|
|
339
323
|
...impl,
|
|
340
324
|
};
|
|
@@ -346,7 +330,7 @@ class Renderer {
|
|
|
346
330
|
* used root to delete the previously rendered element tree from the cache.
|
|
347
331
|
* @param root - The node to be rendered into. The renderer will cache
|
|
348
332
|
* element trees per root.
|
|
349
|
-
* @param
|
|
333
|
+
* @param bridge - An optional context that will be the ancestor context of all
|
|
350
334
|
* elements in the tree. Useful for connecting different renderers so that
|
|
351
335
|
* events/provisions properly propagate. The context for a given root must be
|
|
352
336
|
* the same or an error will be thrown.
|
|
@@ -356,7 +340,7 @@ class Renderer {
|
|
|
356
340
|
*/
|
|
357
341
|
render(children, root, bridge) {
|
|
358
342
|
let ret;
|
|
359
|
-
const ctx = bridge && bridge[
|
|
343
|
+
const ctx = bridge && bridge[_ContextImpl];
|
|
360
344
|
if (typeof root === "object" && root !== null) {
|
|
361
345
|
ret = this.cache.get(root);
|
|
362
346
|
}
|
|
@@ -379,7 +363,7 @@ class Renderer {
|
|
|
379
363
|
this.cache.delete(root);
|
|
380
364
|
}
|
|
381
365
|
}
|
|
382
|
-
const impl = this[
|
|
366
|
+
const impl = this[_RendererImpl];
|
|
383
367
|
const childValues = diffChildren(impl, root, ret, ctx, impl.scope(undefined, Portal, ret.el.props), ret, children);
|
|
384
368
|
// We return the child values of the portal because portal elements
|
|
385
369
|
// themselves have no readable value.
|
|
@@ -392,15 +376,15 @@ class Renderer {
|
|
|
392
376
|
/*** PRIVATE RENDERER FUNCTIONS ***/
|
|
393
377
|
function commitRootRender(renderer, root, ctx, ret, childValues, oldProps) {
|
|
394
378
|
// element is a host or portal element
|
|
395
|
-
if (root
|
|
396
|
-
renderer.arrange(Portal, root, ret.el.props, childValues, oldProps, wrap(ret.
|
|
379
|
+
if (root != null) {
|
|
380
|
+
renderer.arrange(Portal, root, ret.el.props, childValues, oldProps, wrap(ret.cachedChildValues));
|
|
397
381
|
flush(renderer, root);
|
|
398
382
|
}
|
|
399
|
-
ret.
|
|
383
|
+
ret.cachedChildValues = unwrap(childValues);
|
|
400
384
|
if (root == null) {
|
|
401
385
|
unmount(renderer, ret, ctx, ret);
|
|
402
386
|
}
|
|
403
|
-
return renderer.read(ret.
|
|
387
|
+
return renderer.read(ret.cachedChildValues);
|
|
404
388
|
}
|
|
405
389
|
function diffChildren(renderer, root, host, ctx, scope, parent, children) {
|
|
406
390
|
const oldRetained = wrap(parent.children);
|
|
@@ -472,7 +456,7 @@ function diffChildren(renderer, root, host, ctx, scope, parent, children) {
|
|
|
472
456
|
}
|
|
473
457
|
const fallback = ret;
|
|
474
458
|
ret = new Retainer(child);
|
|
475
|
-
ret.
|
|
459
|
+
ret.fallbackValue = fallback;
|
|
476
460
|
}
|
|
477
461
|
if (child.tag === Raw) {
|
|
478
462
|
value = updateRaw(renderer, ret, scope, oldProps);
|
|
@@ -540,27 +524,29 @@ function diffChildren(renderer, root, host, ctx, scope, parent, children) {
|
|
|
540
524
|
childValues1,
|
|
541
525
|
new Promise((resolve) => (onChildValues = resolve)),
|
|
542
526
|
]);
|
|
543
|
-
if (parent.
|
|
544
|
-
parent.
|
|
527
|
+
if (parent.onNextValues) {
|
|
528
|
+
parent.onNextValues(childValues1);
|
|
545
529
|
}
|
|
546
|
-
parent.
|
|
530
|
+
parent.onNextValues = onChildValues;
|
|
547
531
|
return childValues1.then((childValues) => {
|
|
548
|
-
parent.
|
|
532
|
+
parent.inflightValue = parent.fallbackValue = undefined;
|
|
549
533
|
return normalize(childValues);
|
|
550
534
|
});
|
|
551
535
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
536
|
+
else {
|
|
537
|
+
if (graveyard) {
|
|
538
|
+
for (let i = 0; i < graveyard.length; i++) {
|
|
539
|
+
unmount(renderer, host, ctx, graveyard[i]);
|
|
540
|
+
}
|
|
555
541
|
}
|
|
542
|
+
if (parent.onNextValues) {
|
|
543
|
+
parent.onNextValues(values);
|
|
544
|
+
parent.onNextValues = undefined;
|
|
545
|
+
}
|
|
546
|
+
parent.inflightValue = parent.fallbackValue = undefined;
|
|
547
|
+
// We can assert there are no promises in the array because isAsync is false
|
|
548
|
+
return normalize(values);
|
|
556
549
|
}
|
|
557
|
-
if (parent.onCommit) {
|
|
558
|
-
parent.onCommit(values);
|
|
559
|
-
parent.onCommit = undefined;
|
|
560
|
-
}
|
|
561
|
-
parent.inflight = parent.fallback = undefined;
|
|
562
|
-
// We can assert there are no promises in the array because isAsync is false
|
|
563
|
-
return normalize(values);
|
|
564
550
|
}
|
|
565
551
|
function createChildrenByKey(children, offset) {
|
|
566
552
|
const childrenByKey = new Map();
|
|
@@ -580,8 +566,8 @@ function getInflightValue(child) {
|
|
|
580
566
|
if (ctx && ctx.f & IsUpdating && ctx.inflightValue) {
|
|
581
567
|
return ctx.inflightValue;
|
|
582
568
|
}
|
|
583
|
-
else if (child.
|
|
584
|
-
return child.
|
|
569
|
+
else if (child.inflightValue) {
|
|
570
|
+
return child.inflightValue;
|
|
585
571
|
}
|
|
586
572
|
return getValue(child);
|
|
587
573
|
}
|
|
@@ -600,8 +586,8 @@ function updateRaw(renderer, ret, scope, oldProps) {
|
|
|
600
586
|
function updateFragment(renderer, root, host, ctx, scope, ret) {
|
|
601
587
|
const childValues = diffChildren(renderer, root, host, ctx, scope, ret, ret.el.props.children);
|
|
602
588
|
if (isPromiseLike(childValues)) {
|
|
603
|
-
ret.
|
|
604
|
-
return ret.
|
|
589
|
+
ret.inflightValue = childValues.then((childValues) => unwrap(childValues));
|
|
590
|
+
return ret.inflightValue;
|
|
605
591
|
}
|
|
606
592
|
return unwrap(childValues);
|
|
607
593
|
}
|
|
@@ -618,8 +604,8 @@ function updateHost(renderer, root, ctx, scope, ret, oldProps) {
|
|
|
618
604
|
scope = renderer.scope(scope, tag, el.props);
|
|
619
605
|
const childValues = diffChildren(renderer, root, ret, ctx, scope, ret, ret.el.props.children);
|
|
620
606
|
if (isPromiseLike(childValues)) {
|
|
621
|
-
ret.
|
|
622
|
-
return ret.
|
|
607
|
+
ret.inflightValue = childValues.then((childValues) => commitHost(renderer, scope, ret, childValues, oldProps));
|
|
608
|
+
return ret.inflightValue;
|
|
623
609
|
}
|
|
624
610
|
return commitHost(renderer, scope, ret, childValues, oldProps);
|
|
625
611
|
}
|
|
@@ -646,8 +632,8 @@ function commitHost(renderer, scope, ret, childValues, oldProps) {
|
|
|
646
632
|
}
|
|
647
633
|
ret.el = new Element(tag, props, ret.el.key, ret.el.ref);
|
|
648
634
|
}
|
|
649
|
-
renderer.arrange(tag, value, props, childValues, oldProps, wrap(ret.
|
|
650
|
-
ret.
|
|
635
|
+
renderer.arrange(tag, value, props, childValues, oldProps, wrap(ret.cachedChildValues));
|
|
636
|
+
ret.cachedChildValues = unwrap(childValues);
|
|
651
637
|
if (tag === Portal) {
|
|
652
638
|
flush(renderer, ret.value);
|
|
653
639
|
return;
|
|
@@ -694,7 +680,7 @@ function unmount(renderer, host, ctx, ret) {
|
|
|
694
680
|
}
|
|
695
681
|
else if (ret.el.tag === Portal) {
|
|
696
682
|
host = ret;
|
|
697
|
-
renderer.arrange(Portal, host.value, host.el.props, [], host.el.props, wrap(host.
|
|
683
|
+
renderer.arrange(Portal, host.value, host.el.props, [], host.el.props, wrap(host.cachedChildValues));
|
|
698
684
|
flush(renderer, host.value);
|
|
699
685
|
}
|
|
700
686
|
else if (ret.el.tag !== Fragment) {
|
|
@@ -718,38 +704,39 @@ function unmount(renderer, host, ctx, ret) {
|
|
|
718
704
|
}
|
|
719
705
|
/*** CONTEXT FLAGS ***/
|
|
720
706
|
/**
|
|
721
|
-
* A flag which is
|
|
722
|
-
*
|
|
723
|
-
*
|
|
707
|
+
* A flag which is true when the component is initialized or updated by an
|
|
708
|
+
* ancestor component or the root render call.
|
|
709
|
+
*
|
|
710
|
+
* Used to determine things like whether the nearest host ancestor needs to be
|
|
711
|
+
* rearranged.
|
|
724
712
|
*/
|
|
725
713
|
const IsUpdating = 1 << 0;
|
|
726
714
|
/**
|
|
727
|
-
* A flag which is
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
* overflow or a generator error.
|
|
715
|
+
* A flag which is true when the component is synchronously executing.
|
|
716
|
+
*
|
|
717
|
+
* Used to guard against components triggering stack overflow or generator error.
|
|
731
718
|
*/
|
|
732
|
-
const
|
|
719
|
+
const IsSyncExecuting = 1 << 1;
|
|
733
720
|
/**
|
|
734
|
-
* A flag
|
|
735
|
-
* iterators without a yield.
|
|
721
|
+
* A flag which is true when the component is in the render loop.
|
|
736
722
|
*/
|
|
737
|
-
const
|
|
723
|
+
const IsInRenderLoop = 1 << 2;
|
|
738
724
|
/**
|
|
739
|
-
* A flag
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
725
|
+
* A flag which is true when the component starts the render loop but has not
|
|
726
|
+
* yielded yet.
|
|
727
|
+
*
|
|
728
|
+
* Used to make sure that components yield at least once per loop.
|
|
743
729
|
*/
|
|
744
|
-
const
|
|
730
|
+
const NeedsToYield = 1 << 3;
|
|
745
731
|
/**
|
|
746
|
-
* A flag
|
|
747
|
-
*
|
|
748
|
-
*
|
|
732
|
+
* A flag used by async generator components in conjunction with the
|
|
733
|
+
* onAvailable callback to mark whether new props can be pulled via the context
|
|
734
|
+
* async iterator. See the Symbol.asyncIterator method and the
|
|
735
|
+
* resumeCtxIterator function.
|
|
749
736
|
*/
|
|
750
|
-
const
|
|
737
|
+
const PropsAvailable = 1 << 4;
|
|
751
738
|
/**
|
|
752
|
-
* A flag which is set when a
|
|
739
|
+
* A flag which is set when a component errors.
|
|
753
740
|
*
|
|
754
741
|
* NOTE: This is mainly used to prevent some false positives in component
|
|
755
742
|
* yields or returns undefined warnings. The reason we’re using this versus
|
|
@@ -757,28 +744,28 @@ const IsDone = 1 << 4;
|
|
|
757
744
|
* sync generator child) where synchronous code causes a stack overflow error
|
|
758
745
|
* in a non-deterministic way. Deeply disturbing stuff.
|
|
759
746
|
*/
|
|
760
|
-
const IsErrored = 1 <<
|
|
747
|
+
const IsErrored = 1 << 6;
|
|
761
748
|
/**
|
|
762
749
|
* A flag which is set when the component is unmounted. Unmounted components
|
|
763
750
|
* are no longer in the element tree and cannot refresh or rerender.
|
|
764
751
|
*/
|
|
765
|
-
const IsUnmounted = 1 <<
|
|
752
|
+
const IsUnmounted = 1 << 7;
|
|
766
753
|
/**
|
|
767
754
|
* A flag which indicates that the component is a sync generator component.
|
|
768
755
|
*/
|
|
769
|
-
const IsSyncGen = 1 <<
|
|
756
|
+
const IsSyncGen = 1 << 8;
|
|
770
757
|
/**
|
|
771
758
|
* A flag which indicates that the component is an async generator component.
|
|
772
759
|
*/
|
|
773
|
-
const IsAsyncGen = 1 <<
|
|
760
|
+
const IsAsyncGen = 1 << 9;
|
|
774
761
|
/**
|
|
775
762
|
* A flag which is set while schedule callbacks are called.
|
|
776
763
|
*/
|
|
777
|
-
const IsScheduling = 1 <<
|
|
764
|
+
const IsScheduling = 1 << 10;
|
|
778
765
|
/**
|
|
779
766
|
* A flag which is set when a schedule callback calls refresh.
|
|
780
767
|
*/
|
|
781
|
-
const IsSchedulingRefresh = 1 <<
|
|
768
|
+
const IsSchedulingRefresh = 1 << 11;
|
|
782
769
|
const provisionMaps = new WeakMap();
|
|
783
770
|
const scheduleMap = new WeakMap();
|
|
784
771
|
const cleanupMap = new WeakMap();
|
|
@@ -786,12 +773,12 @@ const cleanupMap = new WeakMap();
|
|
|
786
773
|
const flushMaps = new WeakMap();
|
|
787
774
|
/**
|
|
788
775
|
* @internal
|
|
789
|
-
* The internal class which holds
|
|
776
|
+
* The internal class which holds context data.
|
|
790
777
|
*/
|
|
791
778
|
class ContextImpl {
|
|
792
779
|
constructor(renderer, root, host, parent, scope, ret) {
|
|
793
780
|
this.f = 0;
|
|
794
|
-
this.
|
|
781
|
+
this.owner = new Context(this);
|
|
795
782
|
this.renderer = renderer;
|
|
796
783
|
this.root = root;
|
|
797
784
|
this.host = host;
|
|
@@ -803,10 +790,11 @@ class ContextImpl {
|
|
|
803
790
|
this.inflightValue = undefined;
|
|
804
791
|
this.enqueuedBlock = undefined;
|
|
805
792
|
this.enqueuedValue = undefined;
|
|
806
|
-
this.
|
|
793
|
+
this.onProps = undefined;
|
|
794
|
+
this.onPropsRequested = undefined;
|
|
807
795
|
}
|
|
808
796
|
}
|
|
809
|
-
const
|
|
797
|
+
const _ContextImpl = Symbol.for("crank.ContextImpl");
|
|
810
798
|
/**
|
|
811
799
|
* A class which is instantiated and passed to every component as its this
|
|
812
800
|
* value. Contexts form a tree just like elements and all components in the
|
|
@@ -820,8 +808,10 @@ const $ContextImpl = Symbol.for("crank.ContextImpl");
|
|
|
820
808
|
* schedule and cleanup callbacks.
|
|
821
809
|
*/
|
|
822
810
|
class Context {
|
|
811
|
+
// TODO: If we could make the constructor function take a nicer value, it
|
|
812
|
+
// would be useful for testing purposes.
|
|
823
813
|
constructor(impl) {
|
|
824
|
-
this[
|
|
814
|
+
this[_ContextImpl] = impl;
|
|
825
815
|
}
|
|
826
816
|
/**
|
|
827
817
|
* The current props of the associated element.
|
|
@@ -831,7 +821,7 @@ class Context {
|
|
|
831
821
|
* plugins or utilities which wrap contexts.
|
|
832
822
|
*/
|
|
833
823
|
get props() {
|
|
834
|
-
return this[
|
|
824
|
+
return this[_ContextImpl].ret.el.props;
|
|
835
825
|
}
|
|
836
826
|
// TODO: Should we rename this???
|
|
837
827
|
/**
|
|
@@ -842,45 +832,70 @@ class Context {
|
|
|
842
832
|
* mainly for plugins or utilities which wrap contexts.
|
|
843
833
|
*/
|
|
844
834
|
get value() {
|
|
845
|
-
return this[
|
|
835
|
+
return this[_ContextImpl].renderer.read(getValue(this[_ContextImpl].ret));
|
|
846
836
|
}
|
|
847
837
|
*[Symbol.iterator]() {
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
838
|
+
const ctx = this[_ContextImpl];
|
|
839
|
+
if (ctx.f & IsAsyncGen) {
|
|
840
|
+
throw new Error("Use for await…of in async generator components");
|
|
841
|
+
}
|
|
842
|
+
try {
|
|
843
|
+
ctx.f |= IsInRenderLoop;
|
|
844
|
+
while (!(ctx.f & IsUnmounted)) {
|
|
845
|
+
if (ctx.f & NeedsToYield) {
|
|
846
|
+
throw new Error("Context iterated twice without a yield");
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
ctx.f |= NeedsToYield;
|
|
850
|
+
}
|
|
851
|
+
yield ctx.ret.el.props;
|
|
855
852
|
}
|
|
856
|
-
|
|
857
|
-
|
|
853
|
+
}
|
|
854
|
+
finally {
|
|
855
|
+
ctx.f &= ~IsInRenderLoop;
|
|
858
856
|
}
|
|
859
857
|
}
|
|
860
858
|
async *[Symbol.asyncIterator]() {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
859
|
+
const ctx = this[_ContextImpl];
|
|
860
|
+
if (ctx.f & IsSyncGen) {
|
|
861
|
+
throw new Error("Use for…of in sync generator components");
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
// await an empty promise to prevent the IsInRenderLoop flag from
|
|
865
|
+
// returning false positives in the case of async generator components
|
|
866
|
+
// which immediately enter the loop
|
|
867
|
+
ctx.f |= IsInRenderLoop;
|
|
868
|
+
while (!(ctx.f & IsUnmounted)) {
|
|
869
|
+
if (ctx.f & NeedsToYield) {
|
|
870
|
+
throw new Error("Context iterated twice without a yield");
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
ctx.f |= NeedsToYield;
|
|
874
|
+
}
|
|
875
|
+
if (ctx.f & PropsAvailable) {
|
|
876
|
+
ctx.f &= ~PropsAvailable;
|
|
877
|
+
yield ctx.ret.el.props;
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
const props = await new Promise((resolve) => (ctx.onProps = resolve));
|
|
881
|
+
if (ctx.f & IsUnmounted) {
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
yield props;
|
|
885
|
+
}
|
|
886
|
+
if (ctx.onPropsRequested) {
|
|
887
|
+
ctx.onPropsRequested();
|
|
888
|
+
ctx.onPropsRequested = undefined;
|
|
880
889
|
}
|
|
881
890
|
}
|
|
882
|
-
|
|
883
|
-
|
|
891
|
+
}
|
|
892
|
+
finally {
|
|
893
|
+
ctx.f &= ~IsInRenderLoop;
|
|
894
|
+
if (ctx.onPropsRequested) {
|
|
895
|
+
ctx.onPropsRequested();
|
|
896
|
+
ctx.onPropsRequested = undefined;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
884
899
|
}
|
|
885
900
|
/**
|
|
886
901
|
* Re-executes a component.
|
|
@@ -895,32 +910,31 @@ class Context {
|
|
|
895
910
|
* async iterator to suspend.
|
|
896
911
|
*/
|
|
897
912
|
refresh() {
|
|
898
|
-
const
|
|
899
|
-
if (
|
|
913
|
+
const ctx = this[_ContextImpl];
|
|
914
|
+
if (ctx.f & IsUnmounted) {
|
|
900
915
|
console.error("Component is unmounted");
|
|
901
|
-
return
|
|
916
|
+
return ctx.renderer.read(undefined);
|
|
902
917
|
}
|
|
903
|
-
else if (
|
|
918
|
+
else if (ctx.f & IsSyncExecuting) {
|
|
904
919
|
console.error("Component is already executing");
|
|
905
920
|
return this.value;
|
|
906
921
|
}
|
|
907
|
-
|
|
908
|
-
const value = runComponent(impl);
|
|
922
|
+
const value = enqueueComponentRun(ctx);
|
|
909
923
|
if (isPromiseLike(value)) {
|
|
910
|
-
return value.then((value) =>
|
|
924
|
+
return value.then((value) => ctx.renderer.read(value));
|
|
911
925
|
}
|
|
912
|
-
return
|
|
926
|
+
return ctx.renderer.read(value);
|
|
913
927
|
}
|
|
914
928
|
/**
|
|
915
929
|
* Registers a callback which fires when the component commits. Will only
|
|
916
930
|
* fire once per callback and update.
|
|
917
931
|
*/
|
|
918
932
|
schedule(callback) {
|
|
919
|
-
const
|
|
920
|
-
let callbacks = scheduleMap.get(
|
|
933
|
+
const ctx = this[_ContextImpl];
|
|
934
|
+
let callbacks = scheduleMap.get(ctx);
|
|
921
935
|
if (!callbacks) {
|
|
922
936
|
callbacks = new Set();
|
|
923
|
-
scheduleMap.set(
|
|
937
|
+
scheduleMap.set(ctx, callbacks);
|
|
924
938
|
}
|
|
925
939
|
callbacks.add(callback);
|
|
926
940
|
}
|
|
@@ -929,19 +943,19 @@ class Context {
|
|
|
929
943
|
* rendered into the root. Will only fire once per callback and render.
|
|
930
944
|
*/
|
|
931
945
|
flush(callback) {
|
|
932
|
-
const
|
|
933
|
-
if (typeof
|
|
946
|
+
const ctx = this[_ContextImpl];
|
|
947
|
+
if (typeof ctx.root !== "object" || ctx.root === null) {
|
|
934
948
|
return;
|
|
935
949
|
}
|
|
936
|
-
let flushMap = flushMaps.get(
|
|
950
|
+
let flushMap = flushMaps.get(ctx.root);
|
|
937
951
|
if (!flushMap) {
|
|
938
952
|
flushMap = new Map();
|
|
939
|
-
flushMaps.set(
|
|
953
|
+
flushMaps.set(ctx.root, flushMap);
|
|
940
954
|
}
|
|
941
|
-
let callbacks = flushMap.get(
|
|
955
|
+
let callbacks = flushMap.get(ctx);
|
|
942
956
|
if (!callbacks) {
|
|
943
957
|
callbacks = new Set();
|
|
944
|
-
flushMap.set(
|
|
958
|
+
flushMap.set(ctx, callbacks);
|
|
945
959
|
}
|
|
946
960
|
callbacks.add(callback);
|
|
947
961
|
}
|
|
@@ -950,45 +964,45 @@ class Context {
|
|
|
950
964
|
* fire once per callback.
|
|
951
965
|
*/
|
|
952
966
|
cleanup(callback) {
|
|
953
|
-
const
|
|
954
|
-
let callbacks = cleanupMap.get(
|
|
967
|
+
const ctx = this[_ContextImpl];
|
|
968
|
+
let callbacks = cleanupMap.get(ctx);
|
|
955
969
|
if (!callbacks) {
|
|
956
970
|
callbacks = new Set();
|
|
957
|
-
cleanupMap.set(
|
|
971
|
+
cleanupMap.set(ctx, callbacks);
|
|
958
972
|
}
|
|
959
973
|
callbacks.add(callback);
|
|
960
974
|
}
|
|
961
975
|
consume(key) {
|
|
962
|
-
for (let
|
|
963
|
-
const provisions = provisionMaps.get(
|
|
976
|
+
for (let ctx = this[_ContextImpl].parent; ctx !== undefined; ctx = ctx.parent) {
|
|
977
|
+
const provisions = provisionMaps.get(ctx);
|
|
964
978
|
if (provisions && provisions.has(key)) {
|
|
965
979
|
return provisions.get(key);
|
|
966
980
|
}
|
|
967
981
|
}
|
|
968
982
|
}
|
|
969
983
|
provide(key, value) {
|
|
970
|
-
const
|
|
971
|
-
let provisions = provisionMaps.get(
|
|
984
|
+
const ctx = this[_ContextImpl];
|
|
985
|
+
let provisions = provisionMaps.get(ctx);
|
|
972
986
|
if (!provisions) {
|
|
973
987
|
provisions = new Map();
|
|
974
|
-
provisionMaps.set(
|
|
988
|
+
provisionMaps.set(ctx, provisions);
|
|
975
989
|
}
|
|
976
990
|
provisions.set(key, value);
|
|
977
991
|
}
|
|
978
992
|
addEventListener(type, listener, options) {
|
|
979
|
-
const
|
|
993
|
+
const ctx = this[_ContextImpl];
|
|
980
994
|
let listeners;
|
|
981
995
|
if (!isListenerOrListenerObject(listener)) {
|
|
982
996
|
return;
|
|
983
997
|
}
|
|
984
998
|
else {
|
|
985
|
-
const listeners1 = listenersMap.get(
|
|
999
|
+
const listeners1 = listenersMap.get(ctx);
|
|
986
1000
|
if (listeners1) {
|
|
987
1001
|
listeners = listeners1;
|
|
988
1002
|
}
|
|
989
1003
|
else {
|
|
990
1004
|
listeners = [];
|
|
991
|
-
listenersMap.set(
|
|
1005
|
+
listenersMap.set(ctx, listeners);
|
|
992
1006
|
}
|
|
993
1007
|
}
|
|
994
1008
|
options = normalizeListenerOptions(options);
|
|
@@ -999,7 +1013,7 @@ class Context {
|
|
|
999
1013
|
else {
|
|
1000
1014
|
callback = listener;
|
|
1001
1015
|
}
|
|
1002
|
-
const record = { type,
|
|
1016
|
+
const record = { type, listener, callback, options };
|
|
1003
1017
|
if (options.once) {
|
|
1004
1018
|
record.callback = function () {
|
|
1005
1019
|
const i = listeners.indexOf(record);
|
|
@@ -1016,15 +1030,15 @@ class Context {
|
|
|
1016
1030
|
}
|
|
1017
1031
|
listeners.push(record);
|
|
1018
1032
|
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1019
|
-
for (const value of getChildValues(
|
|
1033
|
+
for (const value of getChildValues(ctx.ret)) {
|
|
1020
1034
|
if (isEventTarget(value)) {
|
|
1021
1035
|
value.addEventListener(record.type, record.callback, record.options);
|
|
1022
1036
|
}
|
|
1023
1037
|
}
|
|
1024
1038
|
}
|
|
1025
1039
|
removeEventListener(type, listener, options) {
|
|
1026
|
-
const
|
|
1027
|
-
const listeners = listenersMap.get(
|
|
1040
|
+
const ctx = this[_ContextImpl];
|
|
1041
|
+
const listeners = listenersMap.get(ctx);
|
|
1028
1042
|
if (listeners == null || !isListenerOrListenerObject(listener)) {
|
|
1029
1043
|
return;
|
|
1030
1044
|
}
|
|
@@ -1038,16 +1052,16 @@ class Context {
|
|
|
1038
1052
|
const record = listeners[i];
|
|
1039
1053
|
listeners.splice(i, 1);
|
|
1040
1054
|
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1041
|
-
for (const value of getChildValues(
|
|
1055
|
+
for (const value of getChildValues(ctx.ret)) {
|
|
1042
1056
|
if (isEventTarget(value)) {
|
|
1043
1057
|
value.removeEventListener(record.type, record.callback, record.options);
|
|
1044
1058
|
}
|
|
1045
1059
|
}
|
|
1046
1060
|
}
|
|
1047
1061
|
dispatchEvent(ev) {
|
|
1048
|
-
const
|
|
1062
|
+
const ctx = this[_ContextImpl];
|
|
1049
1063
|
const path = [];
|
|
1050
|
-
for (let parent =
|
|
1064
|
+
for (let parent = ctx.parent; parent !== undefined; parent = parent.parent) {
|
|
1051
1065
|
path.push(parent);
|
|
1052
1066
|
}
|
|
1053
1067
|
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
@@ -1059,7 +1073,7 @@ class Context {
|
|
|
1059
1073
|
immediateCancelBubble = true;
|
|
1060
1074
|
return stopImmediatePropagation.call(ev);
|
|
1061
1075
|
});
|
|
1062
|
-
setEventProperty(ev, "target",
|
|
1076
|
+
setEventProperty(ev, "target", ctx.owner);
|
|
1063
1077
|
// The only possible errors in this block are errors thrown by callbacks,
|
|
1064
1078
|
// and dispatchEvent will only log these errors rather than throwing
|
|
1065
1079
|
// them. Therefore, we place all code in a try block, log errors in the
|
|
@@ -1068,18 +1082,21 @@ class Context {
|
|
|
1068
1082
|
// Each early return within the try block returns true because while the
|
|
1069
1083
|
// return value is overridden in the finally block, TypeScript
|
|
1070
1084
|
// (justifiably) does not recognize the unsafe return statement.
|
|
1071
|
-
//
|
|
1072
|
-
// TODO: Run all callbacks even if one of them errors
|
|
1073
1085
|
try {
|
|
1074
1086
|
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1075
1087
|
for (let i = path.length - 1; i >= 0; i--) {
|
|
1076
1088
|
const target = path[i];
|
|
1077
1089
|
const listeners = listenersMap.get(target);
|
|
1078
1090
|
if (listeners) {
|
|
1079
|
-
setEventProperty(ev, "currentTarget", target.
|
|
1091
|
+
setEventProperty(ev, "currentTarget", target.owner);
|
|
1080
1092
|
for (const record of listeners) {
|
|
1081
1093
|
if (record.type === ev.type && record.options.capture) {
|
|
1082
|
-
|
|
1094
|
+
try {
|
|
1095
|
+
record.callback.call(target.owner, ev);
|
|
1096
|
+
}
|
|
1097
|
+
catch (err) {
|
|
1098
|
+
console.error(err);
|
|
1099
|
+
}
|
|
1083
1100
|
if (immediateCancelBubble) {
|
|
1084
1101
|
return true;
|
|
1085
1102
|
}
|
|
@@ -1091,13 +1108,25 @@ class Context {
|
|
|
1091
1108
|
}
|
|
1092
1109
|
}
|
|
1093
1110
|
{
|
|
1094
|
-
|
|
1111
|
+
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1112
|
+
setEventProperty(ev, "currentTarget", ctx.owner);
|
|
1113
|
+
const propCallback = ctx.ret.el.props["on" + ev.type];
|
|
1114
|
+
if (propCallback != null) {
|
|
1115
|
+
propCallback(ev);
|
|
1116
|
+
if (immediateCancelBubble || ev.cancelBubble) {
|
|
1117
|
+
return true;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
const listeners = listenersMap.get(ctx);
|
|
1095
1121
|
if (listeners) {
|
|
1096
|
-
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1097
|
-
setEventProperty(ev, "currentTarget", impl.ctx);
|
|
1098
1122
|
for (const record of listeners) {
|
|
1099
1123
|
if (record.type === ev.type) {
|
|
1100
|
-
|
|
1124
|
+
try {
|
|
1125
|
+
record.callback.call(ctx.owner, ev);
|
|
1126
|
+
}
|
|
1127
|
+
catch (err) {
|
|
1128
|
+
console.error(err);
|
|
1129
|
+
}
|
|
1101
1130
|
if (immediateCancelBubble) {
|
|
1102
1131
|
return true;
|
|
1103
1132
|
}
|
|
@@ -1114,10 +1143,15 @@ class Context {
|
|
|
1114
1143
|
const target = path[i];
|
|
1115
1144
|
const listeners = listenersMap.get(target);
|
|
1116
1145
|
if (listeners) {
|
|
1117
|
-
setEventProperty(ev, "currentTarget", target.
|
|
1146
|
+
setEventProperty(ev, "currentTarget", target.owner);
|
|
1118
1147
|
for (const record of listeners) {
|
|
1119
1148
|
if (record.type === ev.type && !record.options.capture) {
|
|
1120
|
-
|
|
1149
|
+
try {
|
|
1150
|
+
record.callback.call(target.owner, ev);
|
|
1151
|
+
}
|
|
1152
|
+
catch (err) {
|
|
1153
|
+
console.error(err);
|
|
1154
|
+
}
|
|
1121
1155
|
if (immediateCancelBubble) {
|
|
1122
1156
|
return true;
|
|
1123
1157
|
}
|
|
@@ -1130,10 +1164,6 @@ class Context {
|
|
|
1130
1164
|
}
|
|
1131
1165
|
}
|
|
1132
1166
|
}
|
|
1133
|
-
catch (err) {
|
|
1134
|
-
// TODO: Use setTimeout to rethrow the error.
|
|
1135
|
-
console.error(err);
|
|
1136
|
-
}
|
|
1137
1167
|
finally {
|
|
1138
1168
|
setEventProperty(ev, "eventPhase", NONE);
|
|
1139
1169
|
setEventProperty(ev, "currentTarget", null);
|
|
@@ -1155,38 +1185,43 @@ function updateComponent(renderer, root, host, parent, scope, ret, oldProps) {
|
|
|
1155
1185
|
let ctx;
|
|
1156
1186
|
if (oldProps) {
|
|
1157
1187
|
ctx = ret.ctx;
|
|
1158
|
-
if (ctx.f &
|
|
1188
|
+
if (ctx.f & IsSyncExecuting) {
|
|
1159
1189
|
console.error("Component is already executing");
|
|
1160
|
-
return ret.
|
|
1190
|
+
return ret.cachedChildValues;
|
|
1161
1191
|
}
|
|
1162
1192
|
}
|
|
1163
1193
|
else {
|
|
1164
1194
|
ctx = ret.ctx = new ContextImpl(renderer, root, host, parent, scope, ret);
|
|
1165
1195
|
}
|
|
1166
1196
|
ctx.f |= IsUpdating;
|
|
1167
|
-
|
|
1168
|
-
return runComponent(ctx);
|
|
1197
|
+
return enqueueComponentRun(ctx);
|
|
1169
1198
|
}
|
|
1170
1199
|
function updateComponentChildren(ctx, children) {
|
|
1171
|
-
if (ctx.f & IsUnmounted
|
|
1200
|
+
if (ctx.f & IsUnmounted) {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
else if (ctx.f & IsErrored) {
|
|
1204
|
+
// This branch is necessary for some race conditions where this function is
|
|
1205
|
+
// called after iterator.throw() in async generator components.
|
|
1172
1206
|
return;
|
|
1173
1207
|
}
|
|
1174
1208
|
else if (children === undefined) {
|
|
1175
1209
|
console.error("A component has returned or yielded undefined. If this was intentional, return or yield null instead.");
|
|
1176
1210
|
}
|
|
1177
1211
|
let childValues;
|
|
1178
|
-
// We set the isExecuting flag in case a child component dispatches an event
|
|
1179
|
-
// which bubbles to this component and causes a synchronous refresh().
|
|
1180
|
-
ctx.f |= IsExecuting;
|
|
1181
1212
|
try {
|
|
1213
|
+
// TODO: WAT
|
|
1214
|
+
// We set the isExecuting flag in case a child component dispatches an event
|
|
1215
|
+
// which bubbles to this component and causes a synchronous refresh().
|
|
1216
|
+
ctx.f |= IsSyncExecuting;
|
|
1182
1217
|
childValues = diffChildren(ctx.renderer, ctx.root, ctx.host, ctx, ctx.scope, ctx.ret, narrow(children));
|
|
1183
1218
|
}
|
|
1184
1219
|
finally {
|
|
1185
|
-
ctx.f &= ~
|
|
1220
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1186
1221
|
}
|
|
1187
1222
|
if (isPromiseLike(childValues)) {
|
|
1188
|
-
ctx.ret.
|
|
1189
|
-
return ctx.ret.
|
|
1223
|
+
ctx.ret.inflightValue = childValues.then((childValues) => commitComponent(ctx, childValues));
|
|
1224
|
+
return ctx.ret.inflightValue;
|
|
1190
1225
|
}
|
|
1191
1226
|
return commitComponent(ctx, childValues);
|
|
1192
1227
|
}
|
|
@@ -1206,8 +1241,8 @@ function commitComponent(ctx, values) {
|
|
|
1206
1241
|
}
|
|
1207
1242
|
}
|
|
1208
1243
|
}
|
|
1209
|
-
const oldValues = wrap(ctx.ret.
|
|
1210
|
-
let value = (ctx.ret.
|
|
1244
|
+
const oldValues = wrap(ctx.ret.cachedChildValues);
|
|
1245
|
+
let value = (ctx.ret.cachedChildValues = unwrap(values));
|
|
1211
1246
|
if (ctx.f & IsScheduling) {
|
|
1212
1247
|
ctx.f |= IsSchedulingRefresh;
|
|
1213
1248
|
}
|
|
@@ -1215,7 +1250,7 @@ function commitComponent(ctx, values) {
|
|
|
1215
1250
|
// If we’re not updating the component, which happens when components are
|
|
1216
1251
|
// refreshed, or when async generator components iterate, we have to do a
|
|
1217
1252
|
// little bit housekeeping when a component’s child values have changed.
|
|
1218
|
-
if (!
|
|
1253
|
+
if (!arrayEqual(oldValues, values)) {
|
|
1219
1254
|
const records = getListenerRecords(ctx.parent, ctx.host);
|
|
1220
1255
|
if (records.length) {
|
|
1221
1256
|
for (let i = 0; i < values.length; i++) {
|
|
@@ -1230,7 +1265,7 @@ function commitComponent(ctx, values) {
|
|
|
1230
1265
|
}
|
|
1231
1266
|
// rearranging the nearest ancestor host element
|
|
1232
1267
|
const host = ctx.host;
|
|
1233
|
-
const oldHostValues = wrap(host.
|
|
1268
|
+
const oldHostValues = wrap(host.cachedChildValues);
|
|
1234
1269
|
invalidate(ctx, host);
|
|
1235
1270
|
const hostValues = getChildValues(host);
|
|
1236
1271
|
ctx.renderer.arrange(host.el.tag, host.value, host.el.props, hostValues,
|
|
@@ -1259,50 +1294,75 @@ function commitComponent(ctx, values) {
|
|
|
1259
1294
|
}
|
|
1260
1295
|
function invalidate(ctx, host) {
|
|
1261
1296
|
for (let parent = ctx.parent; parent !== undefined && parent.host === host; parent = parent.parent) {
|
|
1262
|
-
parent.ret.
|
|
1297
|
+
parent.ret.cachedChildValues = undefined;
|
|
1263
1298
|
}
|
|
1264
|
-
host.
|
|
1299
|
+
host.cachedChildValues = undefined;
|
|
1265
1300
|
}
|
|
1266
|
-
function
|
|
1267
|
-
if (
|
|
1301
|
+
function arrayEqual(arr1, arr2) {
|
|
1302
|
+
if (arr1.length !== arr2.length) {
|
|
1268
1303
|
return false;
|
|
1269
1304
|
}
|
|
1270
|
-
for (let i = 0; i <
|
|
1271
|
-
const value1 =
|
|
1272
|
-
const value2 =
|
|
1305
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
1306
|
+
const value1 = arr1[i];
|
|
1307
|
+
const value2 = arr2[i];
|
|
1273
1308
|
if (value1 !== value2) {
|
|
1274
1309
|
return false;
|
|
1275
1310
|
}
|
|
1276
1311
|
}
|
|
1277
1312
|
return true;
|
|
1278
1313
|
}
|
|
1279
|
-
/**
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1314
|
+
/** Enqueues and executes the component associated with the context. */
|
|
1315
|
+
function enqueueComponentRun(ctx) {
|
|
1316
|
+
if (ctx.f & IsAsyncGen) {
|
|
1317
|
+
// This branch will only run for async generator components after the
|
|
1318
|
+
// initial render.
|
|
1319
|
+
//
|
|
1320
|
+
// Async generator components which are in the props loop can be in one of
|
|
1321
|
+
// three states:
|
|
1322
|
+
//
|
|
1323
|
+
// 1. propsAvailable flag is true: "available"
|
|
1324
|
+
//
|
|
1325
|
+
// The component is paused somewhere in the loop. When the component
|
|
1326
|
+
// reaches the bottom of the loop, it will run again with the next props.
|
|
1327
|
+
//
|
|
1328
|
+
// 2. onAvailable callback is defined: "suspended"
|
|
1329
|
+
//
|
|
1330
|
+
// The component has reached the bottom of the loop and is waiting for
|
|
1331
|
+
// new props.
|
|
1332
|
+
//
|
|
1333
|
+
// 3. neither 1 or 2: "Running"
|
|
1334
|
+
//
|
|
1335
|
+
// The component is paused somewhere in the loop. When the component
|
|
1336
|
+
// reaches the bottom of the loop, it will suspend.
|
|
1337
|
+
//
|
|
1338
|
+
// By definition, components will never be both available and suspended at
|
|
1339
|
+
// the same time.
|
|
1340
|
+
//
|
|
1341
|
+
// If the component is at the loop bottom, this means that the next value
|
|
1342
|
+
// produced by the component will have the most up to date props, so we can
|
|
1343
|
+
// simply return the current inflight value. Otherwise, we have to wait for
|
|
1344
|
+
// the bottom of the loop before returning the inflight value.
|
|
1345
|
+
const isAtLoopbottom = ctx.f & IsInRenderLoop && !ctx.onProps;
|
|
1346
|
+
resumePropsIterator(ctx);
|
|
1347
|
+
if (isAtLoopbottom) {
|
|
1348
|
+
if (ctx.inflightBlock == null) {
|
|
1349
|
+
ctx.inflightBlock = new Promise((resolve) => (ctx.onPropsRequested = resolve));
|
|
1350
|
+
}
|
|
1351
|
+
return ctx.inflightBlock.then(() => {
|
|
1352
|
+
ctx.inflightBlock = undefined;
|
|
1353
|
+
return ctx.inflightValue;
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
return ctx.inflightValue;
|
|
1357
|
+
}
|
|
1358
|
+
else if (!ctx.inflightBlock) {
|
|
1297
1359
|
try {
|
|
1298
|
-
const [block, value] =
|
|
1360
|
+
const [block, value] = runComponent(ctx);
|
|
1299
1361
|
if (block) {
|
|
1300
1362
|
ctx.inflightBlock = block
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
}
|
|
1305
|
-
})
|
|
1363
|
+
// TODO: there is some fuckery going on here related to async
|
|
1364
|
+
// generator components resuming when they’re meant to be returned.
|
|
1365
|
+
.then((v) => v)
|
|
1306
1366
|
.finally(() => advanceComponent(ctx));
|
|
1307
1367
|
// stepComponent will only return a block if the value is asynchronous
|
|
1308
1368
|
ctx.inflightValue = value;
|
|
@@ -1316,38 +1376,43 @@ function runComponent(ctx) {
|
|
|
1316
1376
|
throw err;
|
|
1317
1377
|
}
|
|
1318
1378
|
}
|
|
1319
|
-
else if (ctx.f & IsAsyncGen) {
|
|
1320
|
-
return ctx.inflightValue;
|
|
1321
|
-
}
|
|
1322
1379
|
else if (!ctx.enqueuedBlock) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1380
|
+
// We need to assign enqueuedBlock and enqueuedValue synchronously, hence
|
|
1381
|
+
// the Promise constructor call.
|
|
1382
|
+
let resolveEnqueuedBlock;
|
|
1383
|
+
ctx.enqueuedBlock = new Promise((resolve) => (resolveEnqueuedBlock = resolve));
|
|
1384
|
+
ctx.enqueuedValue = ctx.inflightBlock.then(() => {
|
|
1326
1385
|
try {
|
|
1327
|
-
const [block, value] =
|
|
1328
|
-
resolve(value);
|
|
1386
|
+
const [block, value] = runComponent(ctx);
|
|
1329
1387
|
if (block) {
|
|
1330
|
-
|
|
1331
|
-
if (!(ctx.f & IsUpdating)) {
|
|
1332
|
-
return propagateError(ctx.parent, err);
|
|
1333
|
-
}
|
|
1334
|
-
});
|
|
1388
|
+
resolveEnqueuedBlock(block.finally(() => advanceComponent(ctx)));
|
|
1335
1389
|
}
|
|
1390
|
+
return value;
|
|
1336
1391
|
}
|
|
1337
1392
|
catch (err) {
|
|
1338
1393
|
if (!(ctx.f & IsUpdating)) {
|
|
1339
1394
|
return propagateError(ctx.parent, err);
|
|
1340
1395
|
}
|
|
1396
|
+
throw err;
|
|
1341
1397
|
}
|
|
1342
|
-
})
|
|
1343
|
-
.finally(() => advanceComponent(ctx));
|
|
1344
|
-
ctx.enqueuedValue = new Promise((resolve1) => (resolve = resolve1));
|
|
1398
|
+
});
|
|
1345
1399
|
}
|
|
1346
1400
|
return ctx.enqueuedValue;
|
|
1347
1401
|
}
|
|
1402
|
+
/** Called when the inflight block promise settles. */
|
|
1403
|
+
function advanceComponent(ctx) {
|
|
1404
|
+
if (ctx.f & IsAsyncGen) {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
ctx.inflightBlock = ctx.enqueuedBlock;
|
|
1408
|
+
ctx.inflightValue = ctx.enqueuedValue;
|
|
1409
|
+
ctx.enqueuedBlock = undefined;
|
|
1410
|
+
ctx.enqueuedValue = undefined;
|
|
1411
|
+
}
|
|
1348
1412
|
/**
|
|
1349
1413
|
* This function is responsible for executing the component and handling all
|
|
1350
|
-
* the different component types.
|
|
1414
|
+
* the different component types. We cannot identify whether a component is a
|
|
1415
|
+
* generator or async without calling it and inspecting the return value.
|
|
1351
1416
|
*
|
|
1352
1417
|
* @returns {[block, value]} A tuple where
|
|
1353
1418
|
* block - A possible promise which represents the duration during which the
|
|
@@ -1362,25 +1427,23 @@ function runComponent(ctx) {
|
|
|
1362
1427
|
* - Sync generator components block while any children are executing, because
|
|
1363
1428
|
* they are expected to only resume when they’ve actually rendered.
|
|
1364
1429
|
*/
|
|
1365
|
-
function
|
|
1430
|
+
function runComponent(ctx) {
|
|
1366
1431
|
const ret = ctx.ret;
|
|
1367
|
-
if (ctx.f & IsDone) {
|
|
1368
|
-
return [undefined, getValue(ret)];
|
|
1369
|
-
}
|
|
1370
1432
|
const initial = !ctx.iterator;
|
|
1371
1433
|
if (initial) {
|
|
1372
|
-
ctx
|
|
1434
|
+
resumePropsIterator(ctx);
|
|
1435
|
+
ctx.f |= IsSyncExecuting;
|
|
1373
1436
|
clearEventListeners(ctx);
|
|
1374
1437
|
let result;
|
|
1375
1438
|
try {
|
|
1376
|
-
result = ret.el.tag.call(ctx.
|
|
1439
|
+
result = ret.el.tag.call(ctx.owner, ret.el.props);
|
|
1377
1440
|
}
|
|
1378
1441
|
catch (err) {
|
|
1379
1442
|
ctx.f |= IsErrored;
|
|
1380
1443
|
throw err;
|
|
1381
1444
|
}
|
|
1382
1445
|
finally {
|
|
1383
|
-
ctx.f &= ~
|
|
1446
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1384
1447
|
}
|
|
1385
1448
|
if (isIteratorLike(result)) {
|
|
1386
1449
|
ctx.iterator = result;
|
|
@@ -1392,120 +1455,182 @@ function stepComponent(ctx) {
|
|
|
1392
1455
|
ctx.f |= IsErrored;
|
|
1393
1456
|
throw err;
|
|
1394
1457
|
});
|
|
1395
|
-
return [result1, value];
|
|
1458
|
+
return [result1.catch(NOOP), value];
|
|
1396
1459
|
}
|
|
1397
1460
|
else {
|
|
1398
1461
|
// sync function component
|
|
1399
1462
|
return [undefined, updateComponentChildren(ctx, result)];
|
|
1400
1463
|
}
|
|
1401
1464
|
}
|
|
1402
|
-
let
|
|
1465
|
+
let iteration;
|
|
1403
1466
|
if (initial) {
|
|
1404
|
-
|
|
1405
|
-
|
|
1467
|
+
try {
|
|
1468
|
+
ctx.f |= IsSyncExecuting;
|
|
1469
|
+
iteration = ctx.iterator.next();
|
|
1470
|
+
}
|
|
1471
|
+
catch (err) {
|
|
1472
|
+
ctx.f |= IsErrored;
|
|
1473
|
+
throw err;
|
|
1474
|
+
}
|
|
1475
|
+
finally {
|
|
1476
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1477
|
+
}
|
|
1478
|
+
if (isPromiseLike(iteration)) {
|
|
1479
|
+
ctx.f |= IsAsyncGen;
|
|
1480
|
+
runAsyncGenComponent(ctx, iteration);
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
ctx.f |= IsSyncGen;
|
|
1484
|
+
}
|
|
1406
1485
|
}
|
|
1407
|
-
|
|
1408
|
-
//
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1486
|
+
if (ctx.f & IsSyncGen) {
|
|
1487
|
+
// sync generator component
|
|
1488
|
+
ctx.f &= ~NeedsToYield;
|
|
1489
|
+
if (!initial) {
|
|
1490
|
+
try {
|
|
1491
|
+
ctx.f |= IsSyncExecuting;
|
|
1492
|
+
iteration = ctx.iterator.next(ctx.renderer.read(getValue(ret)));
|
|
1493
|
+
}
|
|
1494
|
+
catch (err) {
|
|
1495
|
+
ctx.f |= IsErrored;
|
|
1496
|
+
throw err;
|
|
1497
|
+
}
|
|
1498
|
+
finally {
|
|
1499
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (isPromiseLike(iteration)) {
|
|
1503
|
+
throw new Error("Sync generator component returned an async iteration");
|
|
1504
|
+
}
|
|
1505
|
+
if (iteration.done) {
|
|
1506
|
+
ctx.f &= ~IsSyncGen;
|
|
1507
|
+
ctx.iterator = undefined;
|
|
1508
|
+
}
|
|
1509
|
+
let value;
|
|
1510
|
+
try {
|
|
1511
|
+
value = updateComponentChildren(ctx,
|
|
1512
|
+
// Children can be void so we eliminate that here
|
|
1513
|
+
iteration.value);
|
|
1514
|
+
if (isPromiseLike(value)) {
|
|
1515
|
+
value = value.catch((err) => handleChildError(ctx, err));
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
catch (err) {
|
|
1519
|
+
value = handleChildError(ctx, err);
|
|
1520
|
+
}
|
|
1521
|
+
const block = isPromiseLike(value) ? value.catch(NOOP) : undefined;
|
|
1522
|
+
return [block, value];
|
|
1413
1523
|
}
|
|
1414
1524
|
else {
|
|
1415
|
-
|
|
1525
|
+
// async generator component
|
|
1526
|
+
return [undefined, ctx.inflightValue];
|
|
1416
1527
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1528
|
+
}
|
|
1529
|
+
async function runAsyncGenComponent(ctx, iterationP) {
|
|
1530
|
+
let done = false;
|
|
1419
1531
|
try {
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
if (isPromiseLike(iteration)) {
|
|
1430
|
-
// async generator component
|
|
1431
|
-
if (initial) {
|
|
1432
|
-
ctx.f |= IsAsyncGen;
|
|
1433
|
-
}
|
|
1434
|
-
const value = iteration.then((iteration) => {
|
|
1435
|
-
if (!(ctx.f & IsIterating)) {
|
|
1436
|
-
ctx.f &= ~IsAvailable;
|
|
1532
|
+
while (!done) {
|
|
1533
|
+
// inflightValue must be set synchronously.
|
|
1534
|
+
let onValue;
|
|
1535
|
+
ctx.inflightValue = new Promise((resolve) => (onValue = resolve));
|
|
1536
|
+
if (ctx.f & IsUpdating) {
|
|
1537
|
+
// We should not swallow unhandled promise rejections if the component is
|
|
1538
|
+
// updating independently.
|
|
1539
|
+
// TODO: Does this handle this.refresh() calls?
|
|
1540
|
+
ctx.inflightValue.catch(NOOP);
|
|
1437
1541
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1542
|
+
let iteration;
|
|
1543
|
+
try {
|
|
1544
|
+
iteration = await iterationP;
|
|
1441
1545
|
}
|
|
1546
|
+
catch (err) {
|
|
1547
|
+
done = true;
|
|
1548
|
+
ctx.f |= IsErrored;
|
|
1549
|
+
onValue(Promise.reject(err));
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1552
|
+
finally {
|
|
1553
|
+
ctx.f &= ~NeedsToYield;
|
|
1554
|
+
if (!(ctx.f & IsInRenderLoop)) {
|
|
1555
|
+
ctx.f &= ~PropsAvailable;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
done = !!iteration.done;
|
|
1559
|
+
let value;
|
|
1442
1560
|
try {
|
|
1443
|
-
|
|
1561
|
+
value = updateComponentChildren(ctx, iteration.value);
|
|
1444
1562
|
if (isPromiseLike(value)) {
|
|
1445
|
-
|
|
1563
|
+
value = value.catch((err) => handleChildError(ctx, err));
|
|
1446
1564
|
}
|
|
1447
|
-
return value;
|
|
1448
1565
|
}
|
|
1449
1566
|
catch (err) {
|
|
1450
|
-
|
|
1567
|
+
done = true;
|
|
1568
|
+
// Do we need to catch potential errors here in the case of unhandled
|
|
1569
|
+
// promise rejections?
|
|
1570
|
+
value = handleChildError(ctx, err);
|
|
1571
|
+
}
|
|
1572
|
+
finally {
|
|
1573
|
+
onValue(value);
|
|
1574
|
+
}
|
|
1575
|
+
// TODO: this can be done more elegantly
|
|
1576
|
+
let oldValue;
|
|
1577
|
+
if (ctx.ret.inflightValue) {
|
|
1578
|
+
// The value passed back into the generator as the argument to the next
|
|
1579
|
+
// method is a promise if an async generator component has async
|
|
1580
|
+
// children. Sync generator components only resume when their children
|
|
1581
|
+
// have fulfilled so the element’s inflight child values will never be
|
|
1582
|
+
// defined.
|
|
1583
|
+
oldValue = ctx.ret.inflightValue.then((value) => ctx.renderer.read(value), () => ctx.renderer.read(undefined));
|
|
1584
|
+
}
|
|
1585
|
+
else {
|
|
1586
|
+
oldValue = ctx.renderer.read(getValue(ctx.ret));
|
|
1587
|
+
}
|
|
1588
|
+
if (ctx.f & IsUnmounted) {
|
|
1589
|
+
if (ctx.f & IsInRenderLoop) {
|
|
1590
|
+
try {
|
|
1591
|
+
ctx.f |= IsSyncExecuting;
|
|
1592
|
+
iterationP = ctx.iterator.next(oldValue);
|
|
1593
|
+
}
|
|
1594
|
+
finally {
|
|
1595
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
else {
|
|
1599
|
+
returnComponent(ctx);
|
|
1600
|
+
break;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
else if (!done) {
|
|
1604
|
+
try {
|
|
1605
|
+
ctx.f |= IsSyncExecuting;
|
|
1606
|
+
iterationP = ctx.iterator.next(oldValue);
|
|
1607
|
+
}
|
|
1608
|
+
finally {
|
|
1609
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1610
|
+
}
|
|
1451
1611
|
}
|
|
1452
|
-
}, (err) => {
|
|
1453
|
-
ctx.f |= IsDone | IsErrored;
|
|
1454
|
-
throw err;
|
|
1455
|
-
});
|
|
1456
|
-
return [iteration, value];
|
|
1457
|
-
}
|
|
1458
|
-
// sync generator component
|
|
1459
|
-
if (initial) {
|
|
1460
|
-
ctx.f |= IsSyncGen;
|
|
1461
|
-
}
|
|
1462
|
-
ctx.f &= ~IsIterating;
|
|
1463
|
-
if (iteration.done) {
|
|
1464
|
-
ctx.f |= IsDone;
|
|
1465
|
-
}
|
|
1466
|
-
let value;
|
|
1467
|
-
try {
|
|
1468
|
-
value = updateComponentChildren(ctx, iteration.value);
|
|
1469
|
-
if (isPromiseLike(value)) {
|
|
1470
|
-
value = value.catch((err) => handleChildError(ctx, err));
|
|
1471
1612
|
}
|
|
1472
1613
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
if (isPromiseLike(value)) {
|
|
1477
|
-
return [value.catch(NOOP), value];
|
|
1478
|
-
}
|
|
1479
|
-
return [undefined, value];
|
|
1480
|
-
}
|
|
1481
|
-
/**
|
|
1482
|
-
* Called when the inflight block promise settles.
|
|
1483
|
-
*/
|
|
1484
|
-
function advanceComponent(ctx) {
|
|
1485
|
-
ctx.inflightBlock = ctx.enqueuedBlock;
|
|
1486
|
-
ctx.inflightValue = ctx.enqueuedValue;
|
|
1487
|
-
ctx.enqueuedBlock = undefined;
|
|
1488
|
-
ctx.enqueuedValue = undefined;
|
|
1489
|
-
if (ctx.f & IsAsyncGen && !(ctx.f & IsDone) && !(ctx.f & IsUnmounted)) {
|
|
1490
|
-
runComponent(ctx);
|
|
1614
|
+
finally {
|
|
1615
|
+
ctx.f &= ~IsAsyncGen;
|
|
1616
|
+
ctx.iterator = undefined;
|
|
1491
1617
|
}
|
|
1492
1618
|
}
|
|
1493
1619
|
/**
|
|
1494
|
-
* Called to
|
|
1495
|
-
* generator components.
|
|
1620
|
+
* Called to resume the props async iterator for async generator components.
|
|
1496
1621
|
*/
|
|
1497
|
-
function
|
|
1498
|
-
if (ctx.
|
|
1499
|
-
ctx.
|
|
1500
|
-
ctx.
|
|
1622
|
+
function resumePropsIterator(ctx) {
|
|
1623
|
+
if (ctx.onProps) {
|
|
1624
|
+
ctx.onProps(ctx.ret.el.props);
|
|
1625
|
+
ctx.onProps = undefined;
|
|
1626
|
+
ctx.f &= ~PropsAvailable;
|
|
1501
1627
|
}
|
|
1502
1628
|
else {
|
|
1503
|
-
ctx.f |=
|
|
1629
|
+
ctx.f |= PropsAvailable;
|
|
1504
1630
|
}
|
|
1505
1631
|
}
|
|
1506
1632
|
// TODO: async unmounting
|
|
1507
1633
|
function unmountComponent(ctx) {
|
|
1508
|
-
ctx.f |= IsUnmounted;
|
|
1509
1634
|
clearEventListeners(ctx);
|
|
1510
1635
|
const callbacks = cleanupMap.get(ctx);
|
|
1511
1636
|
if (callbacks) {
|
|
@@ -1515,21 +1640,54 @@ function unmountComponent(ctx) {
|
|
|
1515
1640
|
callback(value);
|
|
1516
1641
|
}
|
|
1517
1642
|
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
ctx.f
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1643
|
+
ctx.f |= IsUnmounted;
|
|
1644
|
+
if (ctx.iterator) {
|
|
1645
|
+
if (ctx.f & IsSyncGen) {
|
|
1646
|
+
let value;
|
|
1647
|
+
if (ctx.f & IsInRenderLoop) {
|
|
1648
|
+
value = enqueueComponentRun(ctx);
|
|
1649
|
+
}
|
|
1650
|
+
if (isPromiseLike(value)) {
|
|
1651
|
+
value.then(() => {
|
|
1652
|
+
if (ctx.f & IsInRenderLoop) {
|
|
1653
|
+
unmountComponent(ctx);
|
|
1654
|
+
}
|
|
1655
|
+
else {
|
|
1656
|
+
returnComponent(ctx);
|
|
1657
|
+
}
|
|
1658
|
+
}, (err) => {
|
|
1659
|
+
propagateError(ctx.parent, err);
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
else {
|
|
1663
|
+
if (ctx.f & IsInRenderLoop) {
|
|
1664
|
+
unmountComponent(ctx);
|
|
1665
|
+
}
|
|
1666
|
+
else {
|
|
1667
|
+
returnComponent(ctx);
|
|
1527
1668
|
}
|
|
1528
1669
|
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1670
|
+
}
|
|
1671
|
+
else if (ctx.f & IsAsyncGen) {
|
|
1672
|
+
// The logic for unmounting async generator components is in the
|
|
1673
|
+
// runAsyncGenComponent function.
|
|
1674
|
+
resumePropsIterator(ctx);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
function returnComponent(ctx) {
|
|
1679
|
+
resumePropsIterator(ctx);
|
|
1680
|
+
if (ctx.iterator && typeof ctx.iterator.return === "function") {
|
|
1681
|
+
try {
|
|
1682
|
+
ctx.f |= IsSyncExecuting;
|
|
1683
|
+
const iteration = ctx.iterator.return();
|
|
1684
|
+
if (isPromiseLike(iteration)) {
|
|
1685
|
+
iteration.catch((err) => propagateError(ctx.parent, err));
|
|
1531
1686
|
}
|
|
1532
1687
|
}
|
|
1688
|
+
finally {
|
|
1689
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1690
|
+
}
|
|
1533
1691
|
}
|
|
1534
1692
|
}
|
|
1535
1693
|
/*** EVENT TARGET UTILITIES ***/
|
|
@@ -1600,39 +1758,38 @@ function clearEventListeners(ctx) {
|
|
|
1600
1758
|
}
|
|
1601
1759
|
}
|
|
1602
1760
|
/*** ERROR HANDLING UTILITIES ***/
|
|
1603
|
-
// TODO: generator components which throw errors should be recoverable
|
|
1604
1761
|
function handleChildError(ctx, err) {
|
|
1605
|
-
if (ctx.
|
|
1606
|
-
!ctx.iterator ||
|
|
1607
|
-
typeof ctx.iterator.throw !== "function") {
|
|
1762
|
+
if (!ctx.iterator || typeof ctx.iterator.throw !== "function") {
|
|
1608
1763
|
throw err;
|
|
1609
1764
|
}
|
|
1610
|
-
|
|
1765
|
+
resumePropsIterator(ctx);
|
|
1611
1766
|
let iteration;
|
|
1612
1767
|
try {
|
|
1613
|
-
ctx.f |=
|
|
1768
|
+
ctx.f |= IsSyncExecuting;
|
|
1614
1769
|
iteration = ctx.iterator.throw(err);
|
|
1615
1770
|
}
|
|
1616
1771
|
catch (err) {
|
|
1617
|
-
ctx.f |=
|
|
1772
|
+
ctx.f |= IsErrored;
|
|
1618
1773
|
throw err;
|
|
1619
1774
|
}
|
|
1620
1775
|
finally {
|
|
1621
|
-
ctx.f &= ~
|
|
1776
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1622
1777
|
}
|
|
1623
1778
|
if (isPromiseLike(iteration)) {
|
|
1624
1779
|
return iteration.then((iteration) => {
|
|
1625
1780
|
if (iteration.done) {
|
|
1626
|
-
ctx.f
|
|
1781
|
+
ctx.f &= ~IsAsyncGen;
|
|
1782
|
+
ctx.iterator = undefined;
|
|
1627
1783
|
}
|
|
1628
1784
|
return updateComponentChildren(ctx, iteration.value);
|
|
1629
1785
|
}, (err) => {
|
|
1630
|
-
ctx.f |=
|
|
1786
|
+
ctx.f |= IsErrored;
|
|
1631
1787
|
throw err;
|
|
1632
1788
|
});
|
|
1633
1789
|
}
|
|
1634
1790
|
if (iteration.done) {
|
|
1635
|
-
ctx.f
|
|
1791
|
+
ctx.f &= ~IsSyncGen;
|
|
1792
|
+
ctx.iterator = undefined;
|
|
1636
1793
|
}
|
|
1637
1794
|
return updateComponentChildren(ctx, iteration.value);
|
|
1638
1795
|
}
|