@b9g/crank 0.5.0-beta.3 → 0.5.0-beta.5
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/core.cjs +1827 -0
- package/core.cjs.map +1 -0
- package/core.d.ts +481 -0
- package/core.js +1814 -0
- package/core.js.map +1 -0
- package/crank.cjs +15 -1807
- package/crank.cjs.map +1 -1
- package/crank.d.ts +2 -495
- package/crank.js +2 -1798
- package/crank.js.map +1 -1
- package/dom.cjs +4 -4
- package/dom.cjs.map +1 -1
- package/dom.d.ts +1 -1
- package/dom.js +1 -1
- package/dom.js.map +1 -1
- package/html.cjs +3 -3
- package/html.cjs.map +1 -1
- package/html.d.ts +2 -1
- package/html.js +1 -1
- package/html.js.map +1 -1
- package/package.json +19 -19
- package/tags.cjs +2 -2
- package/tags.cjs.map +1 -1
- package/tags.d.ts +1 -1
- package/tags.js +1 -1
- package/tags.js.map +1 -1
- package/umd.js +621 -183
- package/umd.js.map +1 -1
- package/mod.cjs +0 -21
- package/mod.cjs.map +0 -1
- package/mod.d.ts +0 -2
- package/mod.js +0 -4
- package/mod.js.map +0 -1
package/umd.js
CHANGED
|
@@ -737,12 +737,6 @@
|
|
|
737
737
|
* resumeCtxIterator function.
|
|
738
738
|
*/
|
|
739
739
|
const PropsAvailable = 1 << 4;
|
|
740
|
-
/**
|
|
741
|
-
* A flag which is set when a generator components returns, i.e. the done
|
|
742
|
-
* property on the iteration is true. Generator components will stick to their
|
|
743
|
-
* last rendered value and ignore further updates.
|
|
744
|
-
*/
|
|
745
|
-
const IsDone = 1 << 5;
|
|
746
740
|
/**
|
|
747
741
|
* A flag which is set when a component errors.
|
|
748
742
|
*
|
|
@@ -786,7 +780,7 @@
|
|
|
786
780
|
class ContextImpl {
|
|
787
781
|
constructor(renderer, root, host, parent, scope, ret) {
|
|
788
782
|
this.f = 0;
|
|
789
|
-
this.
|
|
783
|
+
this.owner = new Context(this);
|
|
790
784
|
this.renderer = renderer;
|
|
791
785
|
this.root = root;
|
|
792
786
|
this.host = host;
|
|
@@ -843,65 +837,65 @@
|
|
|
843
837
|
return this[_ContextImpl].renderer.read(getValue(this[_ContextImpl].ret));
|
|
844
838
|
}
|
|
845
839
|
*[Symbol.iterator]() {
|
|
846
|
-
const
|
|
847
|
-
if (
|
|
840
|
+
const ctx = this[_ContextImpl];
|
|
841
|
+
if (ctx.f & IsAsyncGen) {
|
|
848
842
|
throw new Error("Use for await…of in async generator components");
|
|
849
843
|
}
|
|
850
844
|
try {
|
|
851
|
-
|
|
852
|
-
while (!(
|
|
853
|
-
if (
|
|
845
|
+
ctx.f |= IsInRenderLoop;
|
|
846
|
+
while (!(ctx.f & IsUnmounted)) {
|
|
847
|
+
if (ctx.f & NeedsToYield) {
|
|
854
848
|
throw new Error("Context iterated twice without a yield");
|
|
855
849
|
}
|
|
856
850
|
else {
|
|
857
|
-
|
|
851
|
+
ctx.f |= NeedsToYield;
|
|
858
852
|
}
|
|
859
|
-
yield
|
|
853
|
+
yield ctx.ret.el.props;
|
|
860
854
|
}
|
|
861
855
|
}
|
|
862
856
|
finally {
|
|
863
|
-
|
|
857
|
+
ctx.f &= ~IsInRenderLoop;
|
|
864
858
|
}
|
|
865
859
|
}
|
|
866
860
|
async *[Symbol.asyncIterator]() {
|
|
867
|
-
const
|
|
868
|
-
if (
|
|
861
|
+
const ctx = this[_ContextImpl];
|
|
862
|
+
if (ctx.f & IsSyncGen) {
|
|
869
863
|
throw new Error("Use for…of in sync generator components");
|
|
870
864
|
}
|
|
871
865
|
try {
|
|
872
866
|
// await an empty promise to prevent the IsInRenderLoop flag from
|
|
873
867
|
// returning false positives in the case of async generator components
|
|
874
868
|
// which immediately enter the loop
|
|
875
|
-
|
|
876
|
-
while (!(
|
|
877
|
-
if (
|
|
869
|
+
ctx.f |= IsInRenderLoop;
|
|
870
|
+
while (!(ctx.f & IsUnmounted)) {
|
|
871
|
+
if (ctx.f & NeedsToYield) {
|
|
878
872
|
throw new Error("Context iterated twice without a yield");
|
|
879
873
|
}
|
|
880
874
|
else {
|
|
881
|
-
|
|
875
|
+
ctx.f |= NeedsToYield;
|
|
882
876
|
}
|
|
883
|
-
if (
|
|
884
|
-
|
|
885
|
-
yield
|
|
877
|
+
if (ctx.f & PropsAvailable) {
|
|
878
|
+
ctx.f &= ~PropsAvailable;
|
|
879
|
+
yield ctx.ret.el.props;
|
|
886
880
|
}
|
|
887
881
|
else {
|
|
888
|
-
const props = await new Promise((resolve) => (
|
|
889
|
-
if (
|
|
882
|
+
const props = await new Promise((resolve) => (ctx.onProps = resolve));
|
|
883
|
+
if (ctx.f & IsUnmounted) {
|
|
890
884
|
break;
|
|
891
885
|
}
|
|
892
886
|
yield props;
|
|
893
887
|
}
|
|
894
|
-
if (
|
|
895
|
-
|
|
896
|
-
|
|
888
|
+
if (ctx.onPropsRequested) {
|
|
889
|
+
ctx.onPropsRequested();
|
|
890
|
+
ctx.onPropsRequested = undefined;
|
|
897
891
|
}
|
|
898
892
|
}
|
|
899
893
|
}
|
|
900
894
|
finally {
|
|
901
|
-
|
|
902
|
-
if (
|
|
903
|
-
|
|
904
|
-
|
|
895
|
+
ctx.f &= ~IsInRenderLoop;
|
|
896
|
+
if (ctx.onPropsRequested) {
|
|
897
|
+
ctx.onPropsRequested();
|
|
898
|
+
ctx.onPropsRequested = undefined;
|
|
905
899
|
}
|
|
906
900
|
}
|
|
907
901
|
}
|
|
@@ -918,31 +912,31 @@
|
|
|
918
912
|
* async iterator to suspend.
|
|
919
913
|
*/
|
|
920
914
|
refresh() {
|
|
921
|
-
const
|
|
922
|
-
if (
|
|
915
|
+
const ctx = this[_ContextImpl];
|
|
916
|
+
if (ctx.f & IsUnmounted) {
|
|
923
917
|
console.error("Component is unmounted");
|
|
924
|
-
return
|
|
918
|
+
return ctx.renderer.read(undefined);
|
|
925
919
|
}
|
|
926
|
-
else if (
|
|
920
|
+
else if (ctx.f & IsSyncExecuting) {
|
|
927
921
|
console.error("Component is already executing");
|
|
928
922
|
return this.value;
|
|
929
923
|
}
|
|
930
|
-
const value = enqueueComponentRun(
|
|
924
|
+
const value = enqueueComponentRun(ctx);
|
|
931
925
|
if (isPromiseLike(value)) {
|
|
932
|
-
return value.then((value) =>
|
|
926
|
+
return value.then((value) => ctx.renderer.read(value));
|
|
933
927
|
}
|
|
934
|
-
return
|
|
928
|
+
return ctx.renderer.read(value);
|
|
935
929
|
}
|
|
936
930
|
/**
|
|
937
931
|
* Registers a callback which fires when the component commits. Will only
|
|
938
932
|
* fire once per callback and update.
|
|
939
933
|
*/
|
|
940
934
|
schedule(callback) {
|
|
941
|
-
const
|
|
942
|
-
let callbacks = scheduleMap.get(
|
|
935
|
+
const ctx = this[_ContextImpl];
|
|
936
|
+
let callbacks = scheduleMap.get(ctx);
|
|
943
937
|
if (!callbacks) {
|
|
944
938
|
callbacks = new Set();
|
|
945
|
-
scheduleMap.set(
|
|
939
|
+
scheduleMap.set(ctx, callbacks);
|
|
946
940
|
}
|
|
947
941
|
callbacks.add(callback);
|
|
948
942
|
}
|
|
@@ -951,19 +945,19 @@
|
|
|
951
945
|
* rendered into the root. Will only fire once per callback and render.
|
|
952
946
|
*/
|
|
953
947
|
flush(callback) {
|
|
954
|
-
const
|
|
955
|
-
if (typeof
|
|
948
|
+
const ctx = this[_ContextImpl];
|
|
949
|
+
if (typeof ctx.root !== "object" || ctx.root === null) {
|
|
956
950
|
return;
|
|
957
951
|
}
|
|
958
|
-
let flushMap = flushMaps.get(
|
|
952
|
+
let flushMap = flushMaps.get(ctx.root);
|
|
959
953
|
if (!flushMap) {
|
|
960
954
|
flushMap = new Map();
|
|
961
|
-
flushMaps.set(
|
|
955
|
+
flushMaps.set(ctx.root, flushMap);
|
|
962
956
|
}
|
|
963
|
-
let callbacks = flushMap.get(
|
|
957
|
+
let callbacks = flushMap.get(ctx);
|
|
964
958
|
if (!callbacks) {
|
|
965
959
|
callbacks = new Set();
|
|
966
|
-
flushMap.set(
|
|
960
|
+
flushMap.set(ctx, callbacks);
|
|
967
961
|
}
|
|
968
962
|
callbacks.add(callback);
|
|
969
963
|
}
|
|
@@ -972,45 +966,45 @@
|
|
|
972
966
|
* fire once per callback.
|
|
973
967
|
*/
|
|
974
968
|
cleanup(callback) {
|
|
975
|
-
const
|
|
976
|
-
let callbacks = cleanupMap.get(
|
|
969
|
+
const ctx = this[_ContextImpl];
|
|
970
|
+
let callbacks = cleanupMap.get(ctx);
|
|
977
971
|
if (!callbacks) {
|
|
978
972
|
callbacks = new Set();
|
|
979
|
-
cleanupMap.set(
|
|
973
|
+
cleanupMap.set(ctx, callbacks);
|
|
980
974
|
}
|
|
981
975
|
callbacks.add(callback);
|
|
982
976
|
}
|
|
983
977
|
consume(key) {
|
|
984
|
-
for (let
|
|
985
|
-
const provisions = provisionMaps.get(
|
|
978
|
+
for (let ctx = this[_ContextImpl].parent; ctx !== undefined; ctx = ctx.parent) {
|
|
979
|
+
const provisions = provisionMaps.get(ctx);
|
|
986
980
|
if (provisions && provisions.has(key)) {
|
|
987
981
|
return provisions.get(key);
|
|
988
982
|
}
|
|
989
983
|
}
|
|
990
984
|
}
|
|
991
985
|
provide(key, value) {
|
|
992
|
-
const
|
|
993
|
-
let provisions = provisionMaps.get(
|
|
986
|
+
const ctx = this[_ContextImpl];
|
|
987
|
+
let provisions = provisionMaps.get(ctx);
|
|
994
988
|
if (!provisions) {
|
|
995
989
|
provisions = new Map();
|
|
996
|
-
provisionMaps.set(
|
|
990
|
+
provisionMaps.set(ctx, provisions);
|
|
997
991
|
}
|
|
998
992
|
provisions.set(key, value);
|
|
999
993
|
}
|
|
1000
994
|
addEventListener(type, listener, options) {
|
|
1001
|
-
const
|
|
995
|
+
const ctx = this[_ContextImpl];
|
|
1002
996
|
let listeners;
|
|
1003
997
|
if (!isListenerOrListenerObject(listener)) {
|
|
1004
998
|
return;
|
|
1005
999
|
}
|
|
1006
1000
|
else {
|
|
1007
|
-
const listeners1 = listenersMap.get(
|
|
1001
|
+
const listeners1 = listenersMap.get(ctx);
|
|
1008
1002
|
if (listeners1) {
|
|
1009
1003
|
listeners = listeners1;
|
|
1010
1004
|
}
|
|
1011
1005
|
else {
|
|
1012
1006
|
listeners = [];
|
|
1013
|
-
listenersMap.set(
|
|
1007
|
+
listenersMap.set(ctx, listeners);
|
|
1014
1008
|
}
|
|
1015
1009
|
}
|
|
1016
1010
|
options = normalizeListenerOptions(options);
|
|
@@ -1021,7 +1015,7 @@
|
|
|
1021
1015
|
else {
|
|
1022
1016
|
callback = listener;
|
|
1023
1017
|
}
|
|
1024
|
-
const record = { type,
|
|
1018
|
+
const record = { type, listener, callback, options };
|
|
1025
1019
|
if (options.once) {
|
|
1026
1020
|
record.callback = function () {
|
|
1027
1021
|
const i = listeners.indexOf(record);
|
|
@@ -1038,15 +1032,15 @@
|
|
|
1038
1032
|
}
|
|
1039
1033
|
listeners.push(record);
|
|
1040
1034
|
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1041
|
-
for (const value of getChildValues(
|
|
1035
|
+
for (const value of getChildValues(ctx.ret)) {
|
|
1042
1036
|
if (isEventTarget(value)) {
|
|
1043
1037
|
value.addEventListener(record.type, record.callback, record.options);
|
|
1044
1038
|
}
|
|
1045
1039
|
}
|
|
1046
1040
|
}
|
|
1047
1041
|
removeEventListener(type, listener, options) {
|
|
1048
|
-
const
|
|
1049
|
-
const listeners = listenersMap.get(
|
|
1042
|
+
const ctx = this[_ContextImpl];
|
|
1043
|
+
const listeners = listenersMap.get(ctx);
|
|
1050
1044
|
if (listeners == null || !isListenerOrListenerObject(listener)) {
|
|
1051
1045
|
return;
|
|
1052
1046
|
}
|
|
@@ -1060,16 +1054,16 @@
|
|
|
1060
1054
|
const record = listeners[i];
|
|
1061
1055
|
listeners.splice(i, 1);
|
|
1062
1056
|
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1063
|
-
for (const value of getChildValues(
|
|
1057
|
+
for (const value of getChildValues(ctx.ret)) {
|
|
1064
1058
|
if (isEventTarget(value)) {
|
|
1065
1059
|
value.removeEventListener(record.type, record.callback, record.options);
|
|
1066
1060
|
}
|
|
1067
1061
|
}
|
|
1068
1062
|
}
|
|
1069
1063
|
dispatchEvent(ev) {
|
|
1070
|
-
const
|
|
1064
|
+
const ctx = this[_ContextImpl];
|
|
1071
1065
|
const path = [];
|
|
1072
|
-
for (let parent =
|
|
1066
|
+
for (let parent = ctx.parent; parent !== undefined; parent = parent.parent) {
|
|
1073
1067
|
path.push(parent);
|
|
1074
1068
|
}
|
|
1075
1069
|
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
@@ -1081,7 +1075,7 @@
|
|
|
1081
1075
|
immediateCancelBubble = true;
|
|
1082
1076
|
return stopImmediatePropagation.call(ev);
|
|
1083
1077
|
});
|
|
1084
|
-
setEventProperty(ev, "target",
|
|
1078
|
+
setEventProperty(ev, "target", ctx.owner);
|
|
1085
1079
|
// The only possible errors in this block are errors thrown by callbacks,
|
|
1086
1080
|
// and dispatchEvent will only log these errors rather than throwing
|
|
1087
1081
|
// them. Therefore, we place all code in a try block, log errors in the
|
|
@@ -1090,18 +1084,21 @@
|
|
|
1090
1084
|
// Each early return within the try block returns true because while the
|
|
1091
1085
|
// return value is overridden in the finally block, TypeScript
|
|
1092
1086
|
// (justifiably) does not recognize the unsafe return statement.
|
|
1093
|
-
//
|
|
1094
|
-
// TODO: Run all callbacks even if one of them errors
|
|
1095
1087
|
try {
|
|
1096
1088
|
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1097
1089
|
for (let i = path.length - 1; i >= 0; i--) {
|
|
1098
1090
|
const target = path[i];
|
|
1099
1091
|
const listeners = listenersMap.get(target);
|
|
1100
1092
|
if (listeners) {
|
|
1101
|
-
setEventProperty(ev, "currentTarget", target.
|
|
1093
|
+
setEventProperty(ev, "currentTarget", target.owner);
|
|
1102
1094
|
for (const record of listeners) {
|
|
1103
1095
|
if (record.type === ev.type && record.options.capture) {
|
|
1104
|
-
|
|
1096
|
+
try {
|
|
1097
|
+
record.callback.call(target.owner, ev);
|
|
1098
|
+
}
|
|
1099
|
+
catch (err) {
|
|
1100
|
+
console.error(err);
|
|
1101
|
+
}
|
|
1105
1102
|
if (immediateCancelBubble) {
|
|
1106
1103
|
return true;
|
|
1107
1104
|
}
|
|
@@ -1113,13 +1110,25 @@
|
|
|
1113
1110
|
}
|
|
1114
1111
|
}
|
|
1115
1112
|
{
|
|
1116
|
-
|
|
1113
|
+
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1114
|
+
setEventProperty(ev, "currentTarget", ctx.owner);
|
|
1115
|
+
const propCallback = ctx.ret.el.props["on" + ev.type];
|
|
1116
|
+
if (propCallback != null) {
|
|
1117
|
+
propCallback(ev);
|
|
1118
|
+
if (immediateCancelBubble || ev.cancelBubble) {
|
|
1119
|
+
return true;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
const listeners = listenersMap.get(ctx);
|
|
1117
1123
|
if (listeners) {
|
|
1118
|
-
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1119
|
-
setEventProperty(ev, "currentTarget", impl.ctx);
|
|
1120
1124
|
for (const record of listeners) {
|
|
1121
1125
|
if (record.type === ev.type) {
|
|
1122
|
-
|
|
1126
|
+
try {
|
|
1127
|
+
record.callback.call(ctx.owner, ev);
|
|
1128
|
+
}
|
|
1129
|
+
catch (err) {
|
|
1130
|
+
console.error(err);
|
|
1131
|
+
}
|
|
1123
1132
|
if (immediateCancelBubble) {
|
|
1124
1133
|
return true;
|
|
1125
1134
|
}
|
|
@@ -1136,10 +1145,15 @@
|
|
|
1136
1145
|
const target = path[i];
|
|
1137
1146
|
const listeners = listenersMap.get(target);
|
|
1138
1147
|
if (listeners) {
|
|
1139
|
-
setEventProperty(ev, "currentTarget", target.
|
|
1148
|
+
setEventProperty(ev, "currentTarget", target.owner);
|
|
1140
1149
|
for (const record of listeners) {
|
|
1141
1150
|
if (record.type === ev.type && !record.options.capture) {
|
|
1142
|
-
|
|
1151
|
+
try {
|
|
1152
|
+
record.callback.call(target.owner, ev);
|
|
1153
|
+
}
|
|
1154
|
+
catch (err) {
|
|
1155
|
+
console.error(err);
|
|
1156
|
+
}
|
|
1143
1157
|
if (immediateCancelBubble) {
|
|
1144
1158
|
return true;
|
|
1145
1159
|
}
|
|
@@ -1152,10 +1166,6 @@
|
|
|
1152
1166
|
}
|
|
1153
1167
|
}
|
|
1154
1168
|
}
|
|
1155
|
-
catch (err) {
|
|
1156
|
-
// TODO: Use setTimeout to rethrow the error.
|
|
1157
|
-
console.error(err);
|
|
1158
|
-
}
|
|
1159
1169
|
finally {
|
|
1160
1170
|
setEventProperty(ev, "eventPhase", NONE);
|
|
1161
1171
|
setEventProperty(ev, "currentTarget", null);
|
|
@@ -1189,7 +1199,12 @@
|
|
|
1189
1199
|
return enqueueComponentRun(ctx);
|
|
1190
1200
|
}
|
|
1191
1201
|
function updateComponentChildren(ctx, children) {
|
|
1192
|
-
if (ctx.f & IsUnmounted
|
|
1202
|
+
if (ctx.f & IsUnmounted) {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
else if (ctx.f & IsErrored) {
|
|
1206
|
+
// This branch is necessary for some race conditions where this function is
|
|
1207
|
+
// called after iterator.throw() in async generator components.
|
|
1193
1208
|
return;
|
|
1194
1209
|
}
|
|
1195
1210
|
else if (children === undefined) {
|
|
@@ -1416,9 +1431,6 @@
|
|
|
1416
1431
|
*/
|
|
1417
1432
|
function runComponent(ctx) {
|
|
1418
1433
|
const ret = ctx.ret;
|
|
1419
|
-
if (ctx.f & IsDone) {
|
|
1420
|
-
return [undefined, getValue(ret)];
|
|
1421
|
-
}
|
|
1422
1434
|
const initial = !ctx.iterator;
|
|
1423
1435
|
if (initial) {
|
|
1424
1436
|
resumePropsIterator(ctx);
|
|
@@ -1426,7 +1438,7 @@
|
|
|
1426
1438
|
clearEventListeners(ctx);
|
|
1427
1439
|
let result;
|
|
1428
1440
|
try {
|
|
1429
|
-
result = ret.el.tag.call(ctx.
|
|
1441
|
+
result = ret.el.tag.call(ctx.owner, ret.el.props);
|
|
1430
1442
|
}
|
|
1431
1443
|
catch (err) {
|
|
1432
1444
|
ctx.f |= IsErrored;
|
|
@@ -1459,7 +1471,7 @@
|
|
|
1459
1471
|
iteration = ctx.iterator.next();
|
|
1460
1472
|
}
|
|
1461
1473
|
catch (err) {
|
|
1462
|
-
ctx.f |=
|
|
1474
|
+
ctx.f |= IsErrored;
|
|
1463
1475
|
throw err;
|
|
1464
1476
|
}
|
|
1465
1477
|
finally {
|
|
@@ -1479,11 +1491,10 @@
|
|
|
1479
1491
|
if (!initial) {
|
|
1480
1492
|
try {
|
|
1481
1493
|
ctx.f |= IsSyncExecuting;
|
|
1482
|
-
|
|
1483
|
-
iteration = ctx.iterator.next(oldValue);
|
|
1494
|
+
iteration = ctx.iterator.next(ctx.renderer.read(getValue(ret)));
|
|
1484
1495
|
}
|
|
1485
1496
|
catch (err) {
|
|
1486
|
-
ctx.f |=
|
|
1497
|
+
ctx.f |= IsErrored;
|
|
1487
1498
|
throw err;
|
|
1488
1499
|
}
|
|
1489
1500
|
finally {
|
|
@@ -1494,7 +1505,8 @@
|
|
|
1494
1505
|
throw new Error("Sync generator component returned an async iteration");
|
|
1495
1506
|
}
|
|
1496
1507
|
if (iteration.done) {
|
|
1497
|
-
ctx.f
|
|
1508
|
+
ctx.f &= ~IsSyncGen;
|
|
1509
|
+
ctx.iterator = undefined;
|
|
1498
1510
|
}
|
|
1499
1511
|
let value;
|
|
1500
1512
|
try {
|
|
@@ -1508,10 +1520,8 @@
|
|
|
1508
1520
|
catch (err) {
|
|
1509
1521
|
value = handleChildError(ctx, err);
|
|
1510
1522
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
}
|
|
1514
|
-
return [undefined, value];
|
|
1523
|
+
const block = isPromiseLike(value) ? value.catch(NOOP) : undefined;
|
|
1524
|
+
return [block, value];
|
|
1515
1525
|
}
|
|
1516
1526
|
else {
|
|
1517
1527
|
// async generator component
|
|
@@ -1519,65 +1529,80 @@
|
|
|
1519
1529
|
}
|
|
1520
1530
|
}
|
|
1521
1531
|
async function runAsyncGenComponent(ctx, iterationP) {
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
iteration
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
ctx.f |= IsDone;
|
|
1538
|
-
ctx.f |= IsErrored;
|
|
1539
|
-
onValue(Promise.reject(err));
|
|
1540
|
-
break;
|
|
1541
|
-
}
|
|
1542
|
-
finally {
|
|
1543
|
-
if (!(ctx.f & IsInRenderLoop)) {
|
|
1544
|
-
ctx.f &= ~PropsAvailable;
|
|
1532
|
+
let done = false;
|
|
1533
|
+
try {
|
|
1534
|
+
while (!done) {
|
|
1535
|
+
// inflightValue must be set synchronously.
|
|
1536
|
+
let onValue;
|
|
1537
|
+
ctx.inflightValue = new Promise((resolve) => (onValue = resolve));
|
|
1538
|
+
if (ctx.f & IsUpdating) {
|
|
1539
|
+
// We should not swallow unhandled promise rejections if the component is
|
|
1540
|
+
// updating independently.
|
|
1541
|
+
// TODO: Does this handle this.refresh() calls?
|
|
1542
|
+
ctx.inflightValue.catch(NOOP);
|
|
1543
|
+
}
|
|
1544
|
+
let iteration;
|
|
1545
|
+
try {
|
|
1546
|
+
iteration = await iterationP;
|
|
1545
1547
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
ctx.f |= IsDone;
|
|
1552
|
-
}
|
|
1553
|
-
let value;
|
|
1554
|
-
try {
|
|
1555
|
-
value = updateComponentChildren(ctx, iteration.value);
|
|
1556
|
-
if (isPromiseLike(value)) {
|
|
1557
|
-
value = value.catch((err) => handleChildError(ctx, err));
|
|
1548
|
+
catch (err) {
|
|
1549
|
+
done = true;
|
|
1550
|
+
ctx.f |= IsErrored;
|
|
1551
|
+
onValue(Promise.reject(err));
|
|
1552
|
+
break;
|
|
1558
1553
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1554
|
+
finally {
|
|
1555
|
+
ctx.f &= ~NeedsToYield;
|
|
1556
|
+
if (!(ctx.f & IsInRenderLoop)) {
|
|
1557
|
+
ctx.f &= ~PropsAvailable;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
done = !!iteration.done;
|
|
1561
|
+
let value;
|
|
1562
|
+
try {
|
|
1563
|
+
value = updateComponentChildren(ctx, iteration.value);
|
|
1564
|
+
if (isPromiseLike(value)) {
|
|
1565
|
+
value = value.catch((err) => handleChildError(ctx, err));
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
catch (err) {
|
|
1569
|
+
done = true;
|
|
1570
|
+
// Do we need to catch potential errors here in the case of unhandled
|
|
1571
|
+
// promise rejections?
|
|
1572
|
+
value = handleChildError(ctx, err);
|
|
1573
|
+
}
|
|
1574
|
+
finally {
|
|
1575
|
+
onValue(value);
|
|
1576
|
+
}
|
|
1577
|
+
// TODO: this can be done more elegantly
|
|
1578
|
+
let oldValue;
|
|
1579
|
+
if (ctx.ret.inflightValue) {
|
|
1580
|
+
// The value passed back into the generator as the argument to the next
|
|
1581
|
+
// method is a promise if an async generator component has async
|
|
1582
|
+
// children. Sync generator components only resume when their children
|
|
1583
|
+
// have fulfilled so the element’s inflight child values will never be
|
|
1584
|
+
// defined.
|
|
1585
|
+
oldValue = ctx.ret.inflightValue.then((value) => ctx.renderer.read(value), () => ctx.renderer.read(undefined));
|
|
1586
|
+
}
|
|
1587
|
+
else {
|
|
1588
|
+
oldValue = ctx.renderer.read(getValue(ctx.ret));
|
|
1589
|
+
}
|
|
1590
|
+
if (ctx.f & IsUnmounted) {
|
|
1591
|
+
if (ctx.f & IsInRenderLoop) {
|
|
1592
|
+
try {
|
|
1593
|
+
ctx.f |= IsSyncExecuting;
|
|
1594
|
+
iterationP = ctx.iterator.next(oldValue);
|
|
1595
|
+
}
|
|
1596
|
+
finally {
|
|
1597
|
+
ctx.f &= ~IsSyncExecuting;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
returnComponent(ctx);
|
|
1602
|
+
break;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
else if (!done) {
|
|
1581
1606
|
try {
|
|
1582
1607
|
ctx.f |= IsSyncExecuting;
|
|
1583
1608
|
iterationP = ctx.iterator.next(oldValue);
|
|
@@ -1586,25 +1611,15 @@
|
|
|
1586
1611
|
ctx.f &= ~IsSyncExecuting;
|
|
1587
1612
|
}
|
|
1588
1613
|
}
|
|
1589
|
-
else {
|
|
1590
|
-
returnComponent(ctx);
|
|
1591
|
-
break;
|
|
1592
|
-
}
|
|
1593
1614
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
finally {
|
|
1600
|
-
ctx.f &= ~IsSyncExecuting;
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
} while (!(ctx.f & IsDone));
|
|
1615
|
+
}
|
|
1616
|
+
finally {
|
|
1617
|
+
ctx.f &= ~IsAsyncGen;
|
|
1618
|
+
ctx.iterator = undefined;
|
|
1619
|
+
}
|
|
1604
1620
|
}
|
|
1605
1621
|
/**
|
|
1606
|
-
* Called to
|
|
1607
|
-
* generator components.
|
|
1622
|
+
* Called to resume the props async iterator for async generator components.
|
|
1608
1623
|
*/
|
|
1609
1624
|
function resumePropsIterator(ctx) {
|
|
1610
1625
|
if (ctx.onProps) {
|
|
@@ -1628,7 +1643,7 @@
|
|
|
1628
1643
|
}
|
|
1629
1644
|
}
|
|
1630
1645
|
ctx.f |= IsUnmounted;
|
|
1631
|
-
if (ctx.iterator
|
|
1646
|
+
if (ctx.iterator) {
|
|
1632
1647
|
if (ctx.f & IsSyncGen) {
|
|
1633
1648
|
let value;
|
|
1634
1649
|
if (ctx.f & IsInRenderLoop) {
|
|
@@ -1655,17 +1670,18 @@
|
|
|
1655
1670
|
}
|
|
1656
1671
|
}
|
|
1657
1672
|
}
|
|
1658
|
-
else {
|
|
1659
|
-
// async generator
|
|
1673
|
+
else if (ctx.f & IsAsyncGen) {
|
|
1674
|
+
// The logic for unmounting async generator components is in the
|
|
1675
|
+
// runAsyncGenComponent function.
|
|
1660
1676
|
resumePropsIterator(ctx);
|
|
1661
1677
|
}
|
|
1662
1678
|
}
|
|
1663
1679
|
}
|
|
1664
1680
|
function returnComponent(ctx) {
|
|
1665
1681
|
resumePropsIterator(ctx);
|
|
1666
|
-
if (
|
|
1667
|
-
ctx.f |= IsSyncExecuting;
|
|
1682
|
+
if (ctx.iterator && typeof ctx.iterator.return === "function") {
|
|
1668
1683
|
try {
|
|
1684
|
+
ctx.f |= IsSyncExecuting;
|
|
1669
1685
|
const iteration = ctx.iterator.return();
|
|
1670
1686
|
if (isPromiseLike(iteration)) {
|
|
1671
1687
|
iteration.catch((err) => propagateError(ctx.parent, err));
|
|
@@ -1675,7 +1691,6 @@
|
|
|
1675
1691
|
ctx.f &= ~IsSyncExecuting;
|
|
1676
1692
|
}
|
|
1677
1693
|
}
|
|
1678
|
-
ctx.f |= IsDone;
|
|
1679
1694
|
}
|
|
1680
1695
|
/*** EVENT TARGET UTILITIES ***/
|
|
1681
1696
|
// EVENT PHASE CONSTANTS
|
|
@@ -1745,11 +1760,8 @@
|
|
|
1745
1760
|
}
|
|
1746
1761
|
}
|
|
1747
1762
|
/*** ERROR HANDLING UTILITIES ***/
|
|
1748
|
-
// TODO: generator components which throw errors should be recoverable
|
|
1749
1763
|
function handleChildError(ctx, err) {
|
|
1750
|
-
if (ctx.
|
|
1751
|
-
!ctx.iterator ||
|
|
1752
|
-
typeof ctx.iterator.throw !== "function") {
|
|
1764
|
+
if (!ctx.iterator || typeof ctx.iterator.throw !== "function") {
|
|
1753
1765
|
throw err;
|
|
1754
1766
|
}
|
|
1755
1767
|
resumePropsIterator(ctx);
|
|
@@ -1759,7 +1771,7 @@
|
|
|
1759
1771
|
iteration = ctx.iterator.throw(err);
|
|
1760
1772
|
}
|
|
1761
1773
|
catch (err) {
|
|
1762
|
-
ctx.f |=
|
|
1774
|
+
ctx.f |= IsErrored;
|
|
1763
1775
|
throw err;
|
|
1764
1776
|
}
|
|
1765
1777
|
finally {
|
|
@@ -1768,16 +1780,18 @@
|
|
|
1768
1780
|
if (isPromiseLike(iteration)) {
|
|
1769
1781
|
return iteration.then((iteration) => {
|
|
1770
1782
|
if (iteration.done) {
|
|
1771
|
-
ctx.f
|
|
1783
|
+
ctx.f &= ~IsAsyncGen;
|
|
1784
|
+
ctx.iterator = undefined;
|
|
1772
1785
|
}
|
|
1773
1786
|
return updateComponentChildren(ctx, iteration.value);
|
|
1774
1787
|
}, (err) => {
|
|
1775
|
-
ctx.f |=
|
|
1788
|
+
ctx.f |= IsErrored;
|
|
1776
1789
|
throw err;
|
|
1777
1790
|
});
|
|
1778
1791
|
}
|
|
1779
1792
|
if (iteration.done) {
|
|
1780
|
-
ctx.f
|
|
1793
|
+
ctx.f &= ~IsSyncGen;
|
|
1794
|
+
ctx.iterator = undefined;
|
|
1781
1795
|
}
|
|
1782
1796
|
return updateComponentChildren(ctx, iteration.value);
|
|
1783
1797
|
}
|
|
@@ -1798,6 +1812,429 @@
|
|
|
1798
1812
|
return result;
|
|
1799
1813
|
}
|
|
1800
1814
|
|
|
1815
|
+
const cache = new Map();
|
|
1816
|
+
function jsx(spans, ...expressions) {
|
|
1817
|
+
const key = JSON.stringify(spans.raw);
|
|
1818
|
+
let parseResult = cache.get(key);
|
|
1819
|
+
if (parseResult == null) {
|
|
1820
|
+
parseResult = parse(spans.raw);
|
|
1821
|
+
cache.set(key, parseResult);
|
|
1822
|
+
}
|
|
1823
|
+
const { element, targets } = parseResult;
|
|
1824
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
1825
|
+
const exp = expressions[i];
|
|
1826
|
+
const target = targets[i];
|
|
1827
|
+
if (target) {
|
|
1828
|
+
if (target.type === "error") {
|
|
1829
|
+
throw new SyntaxError(target.message.replace("${}", formatTagForError(exp)));
|
|
1830
|
+
}
|
|
1831
|
+
target.value = exp;
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
return build(element);
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Matches first significant character in children mode.
|
|
1838
|
+
*
|
|
1839
|
+
* Group 1: newline
|
|
1840
|
+
* Group 2: comment
|
|
1841
|
+
* Group 3: tag
|
|
1842
|
+
* Group 4: closing slash
|
|
1843
|
+
* Group 5: tag name
|
|
1844
|
+
*
|
|
1845
|
+
* The comment group must appear first because the tag group can potentially
|
|
1846
|
+
* match a comment, so that we can handle tag expressions where we’ve reached
|
|
1847
|
+
* the end of a span.
|
|
1848
|
+
*/
|
|
1849
|
+
const CHILDREN_RE = /((?:\r|\n|\r\n)\s*)|(<!--[\S\s]*?(?:-->|$))|(<\s*(\/{0,2})\s*([-_$\w]*))/g;
|
|
1850
|
+
/**
|
|
1851
|
+
* Matches props after element tags.
|
|
1852
|
+
*
|
|
1853
|
+
* Group 1: tag end
|
|
1854
|
+
* Group 2: spread props
|
|
1855
|
+
* Group 3: prop name
|
|
1856
|
+
* Group 4: equals
|
|
1857
|
+
* Group 5: prop value string
|
|
1858
|
+
*/
|
|
1859
|
+
const PROPS_RE = /\s*(?:(\/?\s*>)|(\.\.\.\s*)|(?:([-_$\w]+)\s*(=)?\s*(?:("(\\"|[\S\s])*?(?:"|$)|'(?:\\'|[\S\s])*?(?:'|$)))?))/g;
|
|
1860
|
+
const CLOSING_BRACKET_RE = />/g;
|
|
1861
|
+
const CLOSING_SINGLE_QUOTE_RE = /[^\\]?'/g;
|
|
1862
|
+
const CLOSING_DOUBLE_QUOTE_RE = /[^\\]?"/g;
|
|
1863
|
+
const CLOSING_COMMENT_RE = /-->/g;
|
|
1864
|
+
function parse(spans) {
|
|
1865
|
+
let matcher = CHILDREN_RE;
|
|
1866
|
+
const stack = [];
|
|
1867
|
+
let element = {
|
|
1868
|
+
type: "element",
|
|
1869
|
+
open: { type: "tag", slash: "", value: "" },
|
|
1870
|
+
close: null,
|
|
1871
|
+
props: [],
|
|
1872
|
+
children: [],
|
|
1873
|
+
};
|
|
1874
|
+
const targets = [];
|
|
1875
|
+
let lineStart = true;
|
|
1876
|
+
for (let s = 0; s < spans.length; s++) {
|
|
1877
|
+
const span = spans[s];
|
|
1878
|
+
// Whether or not an expression is upcoming. Used to provide better errors.
|
|
1879
|
+
const expressing = s < spans.length - 1;
|
|
1880
|
+
let expressionTarget = null;
|
|
1881
|
+
for (let i = 0, end = i; i < span.length; i = end) {
|
|
1882
|
+
matcher.lastIndex = i;
|
|
1883
|
+
const match = matcher.exec(span);
|
|
1884
|
+
end = match ? match.index + match[0].length : span.length;
|
|
1885
|
+
switch (matcher) {
|
|
1886
|
+
case CHILDREN_RE: {
|
|
1887
|
+
if (match) {
|
|
1888
|
+
const [, newline, comment, tag, closingSlash, tagName] = match;
|
|
1889
|
+
if (i < match.index) {
|
|
1890
|
+
let before = span.slice(i, match.index);
|
|
1891
|
+
if (lineStart) {
|
|
1892
|
+
before = before.replace(/^\s*/, "");
|
|
1893
|
+
}
|
|
1894
|
+
if (newline) {
|
|
1895
|
+
if (span[Math.max(0, match.index - 1)] === "\\") {
|
|
1896
|
+
// We preserve whitespace before escaped newlines and have to
|
|
1897
|
+
// remove the backslash.
|
|
1898
|
+
// jsx` \
|
|
1899
|
+
// `
|
|
1900
|
+
before = before.slice(0, -1);
|
|
1901
|
+
}
|
|
1902
|
+
else {
|
|
1903
|
+
before = before.replace(/\s*$/, "");
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
if (before) {
|
|
1907
|
+
element.children.push({ type: "value", value: before });
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
lineStart = !!newline;
|
|
1911
|
+
if (comment) {
|
|
1912
|
+
if (end === span.length) {
|
|
1913
|
+
// Expression in a comment:
|
|
1914
|
+
// jsx`<!-- ${exp} -->`
|
|
1915
|
+
matcher = CLOSING_COMMENT_RE;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
else if (tag) {
|
|
1919
|
+
if (closingSlash) {
|
|
1920
|
+
element.close = {
|
|
1921
|
+
type: "tag",
|
|
1922
|
+
slash: closingSlash,
|
|
1923
|
+
value: tagName,
|
|
1924
|
+
};
|
|
1925
|
+
if (!stack.length) {
|
|
1926
|
+
if (end !== span.length) {
|
|
1927
|
+
throw new SyntaxError(`Unmatched closing tag "${tagName}"`);
|
|
1928
|
+
}
|
|
1929
|
+
// ERROR EXPRESSION
|
|
1930
|
+
expressionTarget = {
|
|
1931
|
+
type: "error",
|
|
1932
|
+
message: "Unmatched closing tag ${}",
|
|
1933
|
+
value: null,
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
if (end === span.length) {
|
|
1938
|
+
// TAG EXPRESSION
|
|
1939
|
+
expressionTarget = element.close;
|
|
1940
|
+
}
|
|
1941
|
+
element = stack.pop();
|
|
1942
|
+
matcher = CLOSING_BRACKET_RE;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
else {
|
|
1946
|
+
const next = {
|
|
1947
|
+
type: "element",
|
|
1948
|
+
open: {
|
|
1949
|
+
type: "tag",
|
|
1950
|
+
slash: "",
|
|
1951
|
+
value: tagName,
|
|
1952
|
+
},
|
|
1953
|
+
close: null,
|
|
1954
|
+
props: [],
|
|
1955
|
+
children: [],
|
|
1956
|
+
};
|
|
1957
|
+
element.children.push(next);
|
|
1958
|
+
stack.push(element);
|
|
1959
|
+
element = next;
|
|
1960
|
+
matcher = PROPS_RE;
|
|
1961
|
+
if (end === span.length) {
|
|
1962
|
+
// TAG EXPRESSION
|
|
1963
|
+
expressionTarget = element.open;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
else {
|
|
1969
|
+
if (i < span.length) {
|
|
1970
|
+
let after = span.slice(i);
|
|
1971
|
+
if (!expressing) {
|
|
1972
|
+
// trim trailing whitespace
|
|
1973
|
+
after = after.replace(/\s*$/, "");
|
|
1974
|
+
}
|
|
1975
|
+
if (after) {
|
|
1976
|
+
element.children.push({ type: "value", value: after });
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
break;
|
|
1981
|
+
}
|
|
1982
|
+
case PROPS_RE: {
|
|
1983
|
+
if (match) {
|
|
1984
|
+
const [, tagEnd, spread, name, equals, string] = match;
|
|
1985
|
+
if (i < match.index) {
|
|
1986
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, match.index).trim()}\``);
|
|
1987
|
+
}
|
|
1988
|
+
if (tagEnd) {
|
|
1989
|
+
if (tagEnd[0] === "/") {
|
|
1990
|
+
// This is a self-closing element, so there will always be a
|
|
1991
|
+
// result on the stack.
|
|
1992
|
+
element = stack.pop();
|
|
1993
|
+
}
|
|
1994
|
+
matcher = CHILDREN_RE;
|
|
1995
|
+
}
|
|
1996
|
+
else if (spread) {
|
|
1997
|
+
const value = {
|
|
1998
|
+
type: "value",
|
|
1999
|
+
value: null,
|
|
2000
|
+
};
|
|
2001
|
+
element.props.push(value);
|
|
2002
|
+
// SPREAD PROP EXPRESSION
|
|
2003
|
+
expressionTarget = value;
|
|
2004
|
+
if (!(expressing && end === span.length)) {
|
|
2005
|
+
throw new SyntaxError('Expression expected after "..."');
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
else if (name) {
|
|
2009
|
+
let value;
|
|
2010
|
+
if (string == null) {
|
|
2011
|
+
if (!equals) {
|
|
2012
|
+
value = { type: "value", value: true };
|
|
2013
|
+
}
|
|
2014
|
+
else if (end < span.length) {
|
|
2015
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(end, end + 20)}\``);
|
|
2016
|
+
}
|
|
2017
|
+
else {
|
|
2018
|
+
value = { type: "value", value: null };
|
|
2019
|
+
// PROP EXPRESSION
|
|
2020
|
+
expressionTarget = value;
|
|
2021
|
+
if (!(expressing && end === span.length)) {
|
|
2022
|
+
throw new SyntaxError(`Expression expected for prop "${name}"`);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
else {
|
|
2027
|
+
const quote = string[0];
|
|
2028
|
+
value = { type: "propString", parts: [] };
|
|
2029
|
+
value.parts.push(string);
|
|
2030
|
+
if (end === span.length) {
|
|
2031
|
+
matcher =
|
|
2032
|
+
quote === "'"
|
|
2033
|
+
? CLOSING_SINGLE_QUOTE_RE
|
|
2034
|
+
: CLOSING_DOUBLE_QUOTE_RE;
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
const prop = {
|
|
2038
|
+
type: "prop",
|
|
2039
|
+
name,
|
|
2040
|
+
value,
|
|
2041
|
+
};
|
|
2042
|
+
element.props.push(prop);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
else {
|
|
2046
|
+
if (!expressing) {
|
|
2047
|
+
if (i === span.length) {
|
|
2048
|
+
throw new SyntaxError(`Expected props but reached end of document`);
|
|
2049
|
+
}
|
|
2050
|
+
else {
|
|
2051
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, i + 20).trim()}\``);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
// Unexpected expression errors are handled in the outer loop.
|
|
2055
|
+
//
|
|
2056
|
+
// This would most likely be the starting point for the logic of
|
|
2057
|
+
// prop name expressions.
|
|
2058
|
+
// jsx`<p ${name}=${value}>`
|
|
2059
|
+
}
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
case CLOSING_BRACKET_RE: {
|
|
2063
|
+
// We’re in a closing tag and looking for the >.
|
|
2064
|
+
if (match) {
|
|
2065
|
+
if (i < match.index) {
|
|
2066
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, match.index).trim()}\``);
|
|
2067
|
+
}
|
|
2068
|
+
matcher = CHILDREN_RE;
|
|
2069
|
+
}
|
|
2070
|
+
else {
|
|
2071
|
+
if (!expressing) {
|
|
2072
|
+
throw new SyntaxError(`Unexpected text \`${span.slice(i, i + 20).trim()}\``);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
break;
|
|
2076
|
+
}
|
|
2077
|
+
case CLOSING_SINGLE_QUOTE_RE:
|
|
2078
|
+
case CLOSING_DOUBLE_QUOTE_RE: {
|
|
2079
|
+
const string = span.slice(i, end);
|
|
2080
|
+
const prop = element.props[element.props.length - 1];
|
|
2081
|
+
const propString = prop.value;
|
|
2082
|
+
propString.parts.push(string);
|
|
2083
|
+
if (match) {
|
|
2084
|
+
matcher = PROPS_RE;
|
|
2085
|
+
}
|
|
2086
|
+
else {
|
|
2087
|
+
if (!expressing) {
|
|
2088
|
+
throw new SyntaxError(`Missing \`${matcher === CLOSING_SINGLE_QUOTE_RE ? "'" : '"'}\``);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
break;
|
|
2092
|
+
}
|
|
2093
|
+
case CLOSING_COMMENT_RE: {
|
|
2094
|
+
if (match) {
|
|
2095
|
+
matcher = CHILDREN_RE;
|
|
2096
|
+
}
|
|
2097
|
+
else {
|
|
2098
|
+
if (!expressing) {
|
|
2099
|
+
throw new SyntaxError("Expected `-->` but reached end of template");
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
break;
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
if (expressing) {
|
|
2107
|
+
if (expressionTarget) {
|
|
2108
|
+
targets.push(expressionTarget);
|
|
2109
|
+
if (expressionTarget.type === "error") {
|
|
2110
|
+
break;
|
|
2111
|
+
}
|
|
2112
|
+
continue;
|
|
2113
|
+
}
|
|
2114
|
+
switch (matcher) {
|
|
2115
|
+
case CHILDREN_RE: {
|
|
2116
|
+
const target = { type: "value", value: null };
|
|
2117
|
+
element.children.push(target);
|
|
2118
|
+
targets.push(target);
|
|
2119
|
+
break;
|
|
2120
|
+
}
|
|
2121
|
+
case CLOSING_SINGLE_QUOTE_RE:
|
|
2122
|
+
case CLOSING_DOUBLE_QUOTE_RE: {
|
|
2123
|
+
const prop = element.props[element.props.length - 1];
|
|
2124
|
+
const target = { type: "value", value: null };
|
|
2125
|
+
prop.value.parts.push(target);
|
|
2126
|
+
targets.push(target);
|
|
2127
|
+
break;
|
|
2128
|
+
}
|
|
2129
|
+
case CLOSING_COMMENT_RE:
|
|
2130
|
+
targets.push(null);
|
|
2131
|
+
break;
|
|
2132
|
+
default:
|
|
2133
|
+
throw new SyntaxError("Unexpected expression");
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
else if (expressionTarget) {
|
|
2137
|
+
throw new SyntaxError("Expression expected");
|
|
2138
|
+
}
|
|
2139
|
+
lineStart = false;
|
|
2140
|
+
}
|
|
2141
|
+
if (stack.length) {
|
|
2142
|
+
const ti = targets.indexOf(element.open);
|
|
2143
|
+
if (ti === -1) {
|
|
2144
|
+
throw new SyntaxError(`Unmatched opening tag "${element.open.value}"`);
|
|
2145
|
+
}
|
|
2146
|
+
targets[ti] = {
|
|
2147
|
+
type: "error",
|
|
2148
|
+
message: "Unmatched opening tag ${}",
|
|
2149
|
+
value: null,
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
if (element.children.length === 1 && element.children[0].type === "element") {
|
|
2153
|
+
element = element.children[0];
|
|
2154
|
+
}
|
|
2155
|
+
return { element, targets };
|
|
2156
|
+
}
|
|
2157
|
+
function build(parsed) {
|
|
2158
|
+
if (parsed.close !== null &&
|
|
2159
|
+
parsed.close.slash !== "//" &&
|
|
2160
|
+
parsed.open.value !== parsed.close.value) {
|
|
2161
|
+
throw new SyntaxError(`Unmatched closing tag ${formatTagForError(parsed.close.value)}, expected ${formatTagForError(parsed.open.value)}`);
|
|
2162
|
+
}
|
|
2163
|
+
const children = [];
|
|
2164
|
+
for (let i = 0; i < parsed.children.length; i++) {
|
|
2165
|
+
const child = parsed.children[i];
|
|
2166
|
+
children.push(child.type === "element" ? build(child) : child.value);
|
|
2167
|
+
}
|
|
2168
|
+
let props = parsed.props.length ? {} : null;
|
|
2169
|
+
for (let i = 0; i < parsed.props.length; i++) {
|
|
2170
|
+
const prop = parsed.props[i];
|
|
2171
|
+
if (prop.type === "prop") {
|
|
2172
|
+
let value;
|
|
2173
|
+
if (prop.value.type === "value") {
|
|
2174
|
+
value = prop.value.value;
|
|
2175
|
+
}
|
|
2176
|
+
else {
|
|
2177
|
+
let string = "";
|
|
2178
|
+
for (let i = 0; i < prop.value.parts.length; i++) {
|
|
2179
|
+
const part = prop.value.parts[i];
|
|
2180
|
+
if (typeof part === "string") {
|
|
2181
|
+
string += part;
|
|
2182
|
+
}
|
|
2183
|
+
else if (typeof part.value !== "boolean" && part.value != null) {
|
|
2184
|
+
string +=
|
|
2185
|
+
typeof part.value === "string" ? part.value : String(part.value);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
value = string
|
|
2189
|
+
// remove quotes
|
|
2190
|
+
.slice(1, -1)
|
|
2191
|
+
// unescape things
|
|
2192
|
+
// adapted from https://stackoverflow.com/a/57330383/1825413
|
|
2193
|
+
.replace(/\\x[0-9a-f]{2}|\\u[0-9a-f]{4}|\\u\{[0-9a-f]+\}|\\./gi, (match) => {
|
|
2194
|
+
switch (match[1]) {
|
|
2195
|
+
case "b":
|
|
2196
|
+
return "\b";
|
|
2197
|
+
case "f":
|
|
2198
|
+
return "\f";
|
|
2199
|
+
case "n":
|
|
2200
|
+
return "\n";
|
|
2201
|
+
case "r":
|
|
2202
|
+
return "\r";
|
|
2203
|
+
case "t":
|
|
2204
|
+
return "\t";
|
|
2205
|
+
case "v":
|
|
2206
|
+
return "\v";
|
|
2207
|
+
case "x":
|
|
2208
|
+
return String.fromCharCode(parseInt(match.slice(2), 16));
|
|
2209
|
+
case "u":
|
|
2210
|
+
if (match[2] === "{") {
|
|
2211
|
+
return String.fromCodePoint(parseInt(match.slice(3, -1), 16));
|
|
2212
|
+
}
|
|
2213
|
+
return String.fromCharCode(parseInt(match.slice(2), 16));
|
|
2214
|
+
case "0":
|
|
2215
|
+
return "\0";
|
|
2216
|
+
default:
|
|
2217
|
+
return match.slice(1);
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
2220
|
+
}
|
|
2221
|
+
props[prop.name] = value;
|
|
2222
|
+
}
|
|
2223
|
+
else {
|
|
2224
|
+
// spread prop
|
|
2225
|
+
props = { ...props, ...prop.value };
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
return createElement(parsed.open.value, props, ...children);
|
|
2229
|
+
}
|
|
2230
|
+
function formatTagForError(tag) {
|
|
2231
|
+
return typeof tag === "function"
|
|
2232
|
+
? tag.name + "()"
|
|
2233
|
+
: typeof tag === "string"
|
|
2234
|
+
? `"${tag}"`
|
|
2235
|
+
: JSON.stringify(tag);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
1801
2238
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
1802
2239
|
const impl$1 = {
|
|
1803
2240
|
parse(text) {
|
|
@@ -2178,6 +2615,7 @@
|
|
|
2178
2615
|
exports.dom = dom;
|
|
2179
2616
|
exports.html = html;
|
|
2180
2617
|
exports.isElement = isElement;
|
|
2618
|
+
exports.jsx = jsx;
|
|
2181
2619
|
|
|
2182
2620
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2183
2621
|
|