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