malinajs 0.7.2-a4 → 0.7.2-a6
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/CHANGELOG.md +1 -0
- package/malina-esbuild.js +0 -1
- package/malina.js +325 -218
- package/package.json +1 -1
- package/runtime.js +45 -7
package/CHANGELOG.md
CHANGED
package/malina-esbuild.js
CHANGED
package/malina.js
CHANGED
|
@@ -713,6 +713,7 @@
|
|
|
713
713
|
switch(node.type) {
|
|
714
714
|
case 'node':
|
|
715
715
|
case 'slot':
|
|
716
|
+
case 'block':
|
|
716
717
|
case 'fragment':
|
|
717
718
|
if(node.body) go(node.body, node);
|
|
718
719
|
break
|
|
@@ -835,121 +836,103 @@
|
|
|
835
836
|
go(data.body);
|
|
836
837
|
}
|
|
837
838
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
839
|
+
class Reader {
|
|
840
|
+
constructor(source) {
|
|
841
|
+
if(source instanceof Reader) return source;
|
|
842
|
+
this.index = 0;
|
|
843
|
+
this.source = source;
|
|
844
|
+
}
|
|
841
845
|
|
|
842
|
-
|
|
843
|
-
assert(
|
|
844
|
-
|
|
845
|
-
|
|
846
|
+
read(pattern) {
|
|
847
|
+
assert(!this.end(), 'EOF');
|
|
848
|
+
if(pattern == null) {
|
|
849
|
+
return this.source[this.index++];
|
|
850
|
+
} else if(pattern instanceof RegExp) {
|
|
851
|
+
assert(pattern.source[0] == '^');
|
|
852
|
+
const rx = this.source.substring(this.index).match(pattern);
|
|
853
|
+
assert(rx && rx.index == 0, 'Wrong syntax');
|
|
854
|
+
let r = rx[1] || rx[0];
|
|
855
|
+
this.index += rx[0].length;
|
|
856
|
+
return r;
|
|
857
|
+
} else throw 'Not implemented';
|
|
858
|
+
}
|
|
846
859
|
|
|
847
|
-
|
|
860
|
+
probe(pattern) {
|
|
861
|
+
if(pattern instanceof RegExp) {
|
|
862
|
+
assert(pattern.source[0] == '^');
|
|
863
|
+
const r = this.source.substring(this.index).match(pattern);
|
|
864
|
+
if(r) return r[0];
|
|
865
|
+
} else {
|
|
866
|
+
if(this.source[this.index] == pattern[0] && this.source.substr(this.index, pattern.length) == pattern) return pattern;
|
|
867
|
+
}
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
848
870
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
let attributes = [];
|
|
854
|
-
let begin = true;
|
|
855
|
-
let name = '';
|
|
856
|
-
let eq, attr_start;
|
|
857
|
-
let elArg = null;
|
|
871
|
+
probeQuote() {
|
|
872
|
+
const a = this.source[this.index];
|
|
873
|
+
return a == '"' || a == "'" || a == '`';
|
|
874
|
+
}
|
|
858
875
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
876
|
+
readIf(pattern) {
|
|
877
|
+
const r = this.probe(pattern);
|
|
878
|
+
if(r != null) this.index += r.length;
|
|
879
|
+
return r;
|
|
880
|
+
}
|
|
864
881
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
let a = {
|
|
876
|
-
content: source.substring(attr_start, end)
|
|
877
|
-
};
|
|
878
|
-
if(eq) {
|
|
879
|
-
a.name = source.substring(attr_start, eq);
|
|
880
|
-
a.value = source.substring(eq + 1, end);
|
|
881
|
-
if(a.value[0] == '"' || a.value[0] == '\'') a.value = a.value.substring(1);
|
|
882
|
-
let i = a.value.length - 1;
|
|
883
|
-
if(a.value[i] == '"' || a.value[i] == '\'') a.value = a.value.substring(0, i);
|
|
884
|
-
} else a.name = a.content;
|
|
885
|
-
attributes.push(a);
|
|
886
|
-
attr_start = null;
|
|
887
|
-
eq = null;
|
|
882
|
+
end() {
|
|
883
|
+
return this.index >= this.source.length;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
skip() {
|
|
887
|
+
while(!this.end()) {
|
|
888
|
+
if(!this.source[this.index].match(/\s/)) break;
|
|
889
|
+
this.index++;
|
|
888
890
|
}
|
|
891
|
+
}
|
|
889
892
|
|
|
893
|
+
readString() {
|
|
894
|
+
let q = this.read();
|
|
895
|
+
assert(q == '"' || q == '`' || q == `'`, 'Wrong syntax');
|
|
896
|
+
let a = null, p, result = q;
|
|
890
897
|
while(true) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
continue;
|
|
896
|
-
}
|
|
897
|
-
if(a == '{') {
|
|
898
|
-
index--;
|
|
899
|
-
readBinding();
|
|
900
|
-
flush(1);
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
if(a == '}') error('Wrong attr');
|
|
904
|
-
if(a == '<') error('Wrong tag');
|
|
905
|
-
if(a == '/') {
|
|
906
|
-
a = readNext();
|
|
907
|
-
assert(a == '>');
|
|
908
|
-
flush(-1);
|
|
909
|
-
}
|
|
910
|
-
if(a == '>') {
|
|
911
|
-
flush();
|
|
912
|
-
const voidTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
913
|
-
let voidTag = voidTags.indexOf(name) >= 0;
|
|
914
|
-
let closedTag = voidTag || source[index - 2] == '/';
|
|
915
|
-
return {
|
|
916
|
-
type: 'node',
|
|
917
|
-
name,
|
|
918
|
-
elArg,
|
|
919
|
-
openTag: source.substring(start, index),
|
|
920
|
-
start: start,
|
|
921
|
-
end: index,
|
|
922
|
-
closedTag,
|
|
923
|
-
voidTag,
|
|
924
|
-
attributes
|
|
925
|
-
};
|
|
926
|
-
}
|
|
927
|
-
if(begin) {
|
|
928
|
-
if(a.match(/[\da-zA-Z^\-]/)) {
|
|
929
|
-
name += a;
|
|
930
|
-
continue;
|
|
931
|
-
} else {
|
|
932
|
-
begin = false;
|
|
933
|
-
if(a == ':') {
|
|
934
|
-
elArg = true;
|
|
935
|
-
attr_start = index;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
} else if(attr_start) {
|
|
939
|
-
if(a == '=' && !eq) eq = index - 1;
|
|
940
|
-
else if(a.match(/\s/)) flush();
|
|
941
|
-
}
|
|
898
|
+
p = a;
|
|
899
|
+
a = this.read();
|
|
900
|
+
result += a;
|
|
901
|
+
if(a == q && p != '\\') break;
|
|
942
902
|
}
|
|
943
|
-
|
|
903
|
+
return result;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
readAttribute() {
|
|
907
|
+
let name = '';
|
|
908
|
+
while(true) {
|
|
909
|
+
if(this.end()) break;
|
|
910
|
+
let a = this.source[this.index];
|
|
911
|
+
if(a == '=' || a == '/' || a == '>' || a == '\t' || a == '\n' || a == '\v' || a == '\f' || a == '\r' || a == ' ' || a == ' ') break;
|
|
912
|
+
name += a;
|
|
913
|
+
this.index++;
|
|
914
|
+
}
|
|
915
|
+
assert(name, 'Syntax error');
|
|
916
|
+
return name;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
sub(start, end) {
|
|
920
|
+
return this.source.substring(start, end || this.index);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function parseHTML(source) {
|
|
925
|
+
const reader = new Reader(source);
|
|
944
926
|
|
|
945
|
-
const readScript = (
|
|
946
|
-
|
|
947
|
-
let q, a, p, start = index;
|
|
927
|
+
const readScript = (reader) => {
|
|
928
|
+
const start = reader.index;
|
|
948
929
|
|
|
949
930
|
const readRegExp = () => {
|
|
931
|
+
assert(reader.read() == '/');
|
|
932
|
+
let a, p, q;
|
|
950
933
|
while(true) {
|
|
951
934
|
p = a;
|
|
952
|
-
a =
|
|
935
|
+
a = reader.read();
|
|
953
936
|
if(q) {
|
|
954
937
|
if(a != q) continue;
|
|
955
938
|
if(p == '\\') continue;
|
|
@@ -962,108 +945,40 @@
|
|
|
962
945
|
};
|
|
963
946
|
|
|
964
947
|
while(true) {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
if(q) {
|
|
968
|
-
if(a != q) continue;
|
|
969
|
-
if(p == '\\') continue;
|
|
970
|
-
q = null;
|
|
948
|
+
if(reader.probeQuote()) {
|
|
949
|
+
reader.readString();
|
|
971
950
|
continue;
|
|
972
951
|
}
|
|
973
|
-
if(
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if(a == '/') {
|
|
978
|
-
let n = probeNext();
|
|
979
|
-
if(n == '/') { // inline comment
|
|
980
|
-
while(readNext() != '\n');
|
|
981
|
-
a = null;
|
|
982
|
-
continue
|
|
952
|
+
if(reader.probe('/')) {
|
|
953
|
+
if(reader.readIf('//')) {
|
|
954
|
+
while(reader.read() != '\n');
|
|
955
|
+
continue;
|
|
983
956
|
}
|
|
984
|
-
if(
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
if(readNext() == '*' && probeNext() == '/') break;
|
|
957
|
+
if(reader.readIf('/*')) {
|
|
958
|
+
while(true) {
|
|
959
|
+
if(reader.read() == '*' && reader.readIf('/')) break;
|
|
988
960
|
}
|
|
989
|
-
readNext();
|
|
990
|
-
a = null;
|
|
991
961
|
continue;
|
|
992
962
|
}
|
|
993
963
|
readRegExp();
|
|
994
964
|
continue;
|
|
995
965
|
}
|
|
996
|
-
if(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
index += endTag.length - 1;
|
|
1000
|
-
return source.substring(start, end);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
966
|
+
if(reader.readIf('</script>')) {
|
|
967
|
+
return reader.sub(start, reader.index - 9);
|
|
968
|
+
} else reader.read();
|
|
1003
969
|
}
|
|
1004
970
|
};
|
|
1005
971
|
|
|
1006
972
|
const readStyle = () => {
|
|
1007
|
-
|
|
1008
|
-
let end = source.substring(start).indexOf('</style>') + start;
|
|
1009
|
-
assert(end >= 0, '<style> is not closed');
|
|
1010
|
-
index = end + 9;
|
|
1011
|
-
return source.substring(start, end);
|
|
973
|
+
return reader.read(/^(.*?)<\/style>/s);
|
|
1012
974
|
};
|
|
1013
975
|
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
assert(readNext() === '{', 'Bind error');
|
|
1017
|
-
let a = null, p, q;
|
|
1018
|
-
let bkt = 1;
|
|
1019
|
-
|
|
1020
|
-
while(true) {
|
|
1021
|
-
p = a;
|
|
1022
|
-
a = readNext();
|
|
1023
|
-
|
|
1024
|
-
if(q) {
|
|
1025
|
-
if(a != q) continue;
|
|
1026
|
-
if(p == '\\') continue;
|
|
1027
|
-
q = null;
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
if(a == '"' || a == "'" || a == '`') {
|
|
1031
|
-
q = a;
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
if(a == '*' && p == '/') {
|
|
1035
|
-
// comment block
|
|
1036
|
-
while(true) {
|
|
1037
|
-
p = a;
|
|
1038
|
-
a = readNext();
|
|
1039
|
-
if(a == '/' && p == '*') break;
|
|
1040
|
-
}
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
if(a == '{') {
|
|
1045
|
-
bkt++;
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if(a == '}') {
|
|
1049
|
-
bkt--;
|
|
1050
|
-
if(bkt > 0) continue;
|
|
1051
|
-
} else continue;
|
|
1052
|
-
|
|
1053
|
-
return {
|
|
1054
|
-
value: source.substring(start + 1, index - 1),
|
|
1055
|
-
raw: source.substring(start, index)
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
976
|
+
const readComment = () => {
|
|
977
|
+
return reader.read(/^<!--.*?-->/s);
|
|
1058
978
|
};
|
|
1059
979
|
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
let end = source.indexOf('-->', start);
|
|
1063
|
-
assert(end >= 0, 'Comment is not closed');
|
|
1064
|
-
end += 3;
|
|
1065
|
-
index = end;
|
|
1066
|
-
return source.substring(start, end);
|
|
980
|
+
const readTemplate = () => {
|
|
981
|
+
return reader.read(/^(.*?)<\/template>/s);
|
|
1067
982
|
};
|
|
1068
983
|
|
|
1069
984
|
const go = (parent, push) => {
|
|
@@ -1086,12 +1001,11 @@
|
|
|
1086
1001
|
textNode = null;
|
|
1087
1002
|
};
|
|
1088
1003
|
|
|
1089
|
-
while(
|
|
1090
|
-
|
|
1091
|
-
if(a === '<' && source[index + 1].match(/\S/)) {
|
|
1004
|
+
while(!reader.end()) {
|
|
1005
|
+
if(reader.probe('<') && reader.probe(/^<\S/)) {
|
|
1092
1006
|
flushText();
|
|
1093
1007
|
|
|
1094
|
-
if(
|
|
1008
|
+
if(reader.probe('<!--')) {
|
|
1095
1009
|
push({
|
|
1096
1010
|
type: 'comment',
|
|
1097
1011
|
content: readComment()
|
|
@@ -1099,14 +1013,8 @@
|
|
|
1099
1013
|
continue;
|
|
1100
1014
|
}
|
|
1101
1015
|
|
|
1102
|
-
if(
|
|
1103
|
-
let name =
|
|
1104
|
-
index += 2;
|
|
1105
|
-
while(true) {
|
|
1106
|
-
a = readNext();
|
|
1107
|
-
if(a === '>') break;
|
|
1108
|
-
name += a;
|
|
1109
|
-
}
|
|
1016
|
+
if(reader.readIf('</')) { // close tag
|
|
1017
|
+
let name = reader.read(/^([^>]*)>/);
|
|
1110
1018
|
name = name.trim();
|
|
1111
1019
|
if(name) {
|
|
1112
1020
|
name = name.split(':')[0];
|
|
@@ -1115,15 +1023,15 @@
|
|
|
1115
1023
|
return;
|
|
1116
1024
|
}
|
|
1117
1025
|
|
|
1118
|
-
let tag = readTag();
|
|
1026
|
+
let tag = readTag(reader);
|
|
1119
1027
|
push(tag);
|
|
1120
1028
|
if(tag.name === 'script') {
|
|
1121
1029
|
tag.type = 'script';
|
|
1122
|
-
tag.content = readScript(
|
|
1030
|
+
tag.content = readScript(reader);
|
|
1123
1031
|
continue;
|
|
1124
1032
|
} else if(tag.name === 'template') {
|
|
1125
1033
|
tag.type = 'template';
|
|
1126
|
-
tag.content =
|
|
1034
|
+
tag.content = readTemplate();
|
|
1127
1035
|
continue;
|
|
1128
1036
|
} else if(tag.name === 'style') {
|
|
1129
1037
|
tag.type = 'style';
|
|
@@ -1144,9 +1052,9 @@
|
|
|
1144
1052
|
throw e;
|
|
1145
1053
|
}
|
|
1146
1054
|
continue;
|
|
1147
|
-
} else if(
|
|
1148
|
-
if(
|
|
1149
|
-
let bind =
|
|
1055
|
+
} else if(reader.probe('{')) {
|
|
1056
|
+
if(reader.probe(/^\{[#/:@*]/)) {
|
|
1057
|
+
let bind = parseBinding(reader);
|
|
1150
1058
|
if(bind.value[0] != '*') flushText();
|
|
1151
1059
|
if(bind.value[0] == '*') {
|
|
1152
1060
|
addText(bind.raw);
|
|
@@ -1245,14 +1153,29 @@
|
|
|
1245
1153
|
} else if(bind.value == '/fragment') {
|
|
1246
1154
|
assert(parent.type === 'fragment', 'Fragment error: /fragment');
|
|
1247
1155
|
return;
|
|
1156
|
+
} else if(bind.value.match(/^#([\w\-]+)/)) {
|
|
1157
|
+
const name = bind.value.match(/^#([\w\-]+)/)[1];
|
|
1158
|
+
let tag = {
|
|
1159
|
+
type: 'block',
|
|
1160
|
+
value: bind.value,
|
|
1161
|
+
name,
|
|
1162
|
+
body: []
|
|
1163
|
+
};
|
|
1164
|
+
push(tag);
|
|
1165
|
+
go(tag);
|
|
1166
|
+
continue;
|
|
1167
|
+
} else if(bind.value.match(/^\/([\w\-]+)/)) {
|
|
1168
|
+
const name = bind.value.match(/^\/([\w\-]+)/)[1];
|
|
1169
|
+
assert(parent.type === 'block' && parent.name == name, `Fragment error: ${parent.name} - ${name}`);
|
|
1170
|
+
return;
|
|
1248
1171
|
} else throw 'Error binding: ' + bind.value;
|
|
1249
1172
|
} else {
|
|
1250
|
-
|
|
1251
|
-
|
|
1173
|
+
addText(parseBinding(reader).raw);
|
|
1174
|
+
continue;
|
|
1252
1175
|
}
|
|
1253
1176
|
}
|
|
1254
1177
|
|
|
1255
|
-
addText(
|
|
1178
|
+
addText(reader.read());
|
|
1256
1179
|
}
|
|
1257
1180
|
flushText();
|
|
1258
1181
|
assert(parent.type === 'root', 'File ends to early');
|
|
@@ -1264,9 +1187,41 @@
|
|
|
1264
1187
|
};
|
|
1265
1188
|
go(root);
|
|
1266
1189
|
|
|
1267
|
-
|
|
1190
|
+
return root;
|
|
1268
1191
|
}
|
|
1269
1192
|
|
|
1193
|
+
function readTag(reader) {
|
|
1194
|
+
const start = reader.index;
|
|
1195
|
+
assert(reader.read() === '<', 'Tag error');
|
|
1196
|
+
|
|
1197
|
+
let name = reader.read(/^[\da-zA-Z^\-]+/);
|
|
1198
|
+
let elArg = null;
|
|
1199
|
+
|
|
1200
|
+
if(reader.readIf(':')) {
|
|
1201
|
+
elArg = reader.read(/^[^\s>/]+/);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
let attributes = parseAttibutes(reader, {closedByTag: true});
|
|
1205
|
+
|
|
1206
|
+
let closedTag = false;
|
|
1207
|
+
if(reader.readIf('/>')) closedTag = true;
|
|
1208
|
+
else assert(reader.readIf('>'));
|
|
1209
|
+
|
|
1210
|
+
const voidTags = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
1211
|
+
let voidTag = voidTags.indexOf(name) >= 0;
|
|
1212
|
+
if(voidTag) closedTag = true;
|
|
1213
|
+
return {
|
|
1214
|
+
type: 'node',
|
|
1215
|
+
name,
|
|
1216
|
+
elArg,
|
|
1217
|
+
openTag: reader.sub(start),
|
|
1218
|
+
start: start,
|
|
1219
|
+
end: reader.index,
|
|
1220
|
+
closedTag,
|
|
1221
|
+
voidTag,
|
|
1222
|
+
attributes
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1270
1225
|
|
|
1271
1226
|
function parseText(source) {
|
|
1272
1227
|
let i = 0;
|
|
@@ -1336,7 +1291,94 @@
|
|
|
1336
1291
|
return { result, parts, staticText };
|
|
1337
1292
|
}
|
|
1338
1293
|
|
|
1339
|
-
|
|
1294
|
+
|
|
1295
|
+
const parseBinding = (reader) => {
|
|
1296
|
+
let start = reader.index;
|
|
1297
|
+
|
|
1298
|
+
assert(reader.read() === '{', 'Bind error');
|
|
1299
|
+
let a = null, p, q;
|
|
1300
|
+
let bkt = 1;
|
|
1301
|
+
|
|
1302
|
+
while(true) {
|
|
1303
|
+
p = a;
|
|
1304
|
+
a = reader.read();
|
|
1305
|
+
|
|
1306
|
+
if(q) {
|
|
1307
|
+
if(a != q) continue;
|
|
1308
|
+
if(p == '\\') continue;
|
|
1309
|
+
q = null;
|
|
1310
|
+
continue;
|
|
1311
|
+
}
|
|
1312
|
+
if(a == '"' || a == "'" || a == '`') {
|
|
1313
|
+
q = a;
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if(a == '*' && p == '/') {
|
|
1317
|
+
// comment block
|
|
1318
|
+
while(true) {
|
|
1319
|
+
p = a;
|
|
1320
|
+
a = reader.read();
|
|
1321
|
+
if(a == '/' && p == '*') break;
|
|
1322
|
+
}
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
if(a == '{') {
|
|
1327
|
+
bkt++;
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
if(a == '}') {
|
|
1331
|
+
bkt--;
|
|
1332
|
+
if(bkt > 0) continue;
|
|
1333
|
+
} else continue;
|
|
1334
|
+
|
|
1335
|
+
const raw = reader.sub(start);
|
|
1336
|
+
return {
|
|
1337
|
+
raw,
|
|
1338
|
+
value: raw.substring(1, raw.length - 1),
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
const parseAttibutes = (source, option={}) => {
|
|
1345
|
+
const r = new Reader(source);
|
|
1346
|
+
let result = [];
|
|
1347
|
+
|
|
1348
|
+
while(!r.end()) {
|
|
1349
|
+
r.skip();
|
|
1350
|
+
if(option.closedByTag) {
|
|
1351
|
+
if(r.probe('/>') || r.probe('>')) break;
|
|
1352
|
+
} else if(r.end()) break;
|
|
1353
|
+
let start = r.index;
|
|
1354
|
+
let name = r.readAttribute();
|
|
1355
|
+
assert(name, 'Wrong syntax');
|
|
1356
|
+
if(r.readIf('=')) {
|
|
1357
|
+
if(r.probe('{')) {
|
|
1358
|
+
const {raw} = parseBinding(r);
|
|
1359
|
+
result.push({name, value: raw, raw, content: r.sub(start)});
|
|
1360
|
+
} else if(r.probeQuote()) {
|
|
1361
|
+
const raw = r.readString();
|
|
1362
|
+
const value = raw.substring(1, raw.length - 1);
|
|
1363
|
+
result.push({name, value, raw, content: r.sub(start)});
|
|
1364
|
+
} else {
|
|
1365
|
+
const value = r.readIf(/^\S+/);
|
|
1366
|
+
result.push({name, value, raw: value, content: r.sub(start)});
|
|
1367
|
+
}
|
|
1368
|
+
} else {
|
|
1369
|
+
let value;
|
|
1370
|
+
if(name[0] == '{' && last(name) == '}' && !name.startsWith('{...')) {
|
|
1371
|
+
value = name;
|
|
1372
|
+
name = unwrapExp(name);
|
|
1373
|
+
}
|
|
1374
|
+
result.push({name, value, raw: value, content: r.sub(start)});
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
return result;
|
|
1379
|
+
};
|
|
1380
|
+
|
|
1381
|
+
function parse() {
|
|
1340
1382
|
let source = this.scriptNodes.length ? this.scriptNodes[0].content : null;
|
|
1341
1383
|
this.script = {
|
|
1342
1384
|
source,
|
|
@@ -1820,6 +1862,12 @@
|
|
|
1820
1862
|
}
|
|
1821
1863
|
}));
|
|
1822
1864
|
|
|
1865
|
+
this.module.head.push(this.glob.keepAliveStore = xNode('$$keepAliveStore', {
|
|
1866
|
+
value: false
|
|
1867
|
+
}, (ctx, n) => {
|
|
1868
|
+
if(n.value) ctx.write(true, `const $$keepAliveStore = new Map();`);
|
|
1869
|
+
}));
|
|
1870
|
+
|
|
1823
1871
|
this.module.top.push(xNode(this.glob.$onMount, {
|
|
1824
1872
|
}, (ctx, n) => {
|
|
1825
1873
|
if(n.value) ctx.write(true, `import { $onMount } from 'malinajs/runtime.js';`);
|
|
@@ -2137,7 +2185,11 @@
|
|
|
2137
2185
|
|
|
2138
2186
|
if(n.name == 'component') {
|
|
2139
2187
|
// dyn-component
|
|
2140
|
-
|
|
2188
|
+
if(isRoot) {
|
|
2189
|
+
requireFragment = true;
|
|
2190
|
+
if(!tpl.getLast()) tpl.push(xNode('node:comment', { label: true }));
|
|
2191
|
+
}
|
|
2192
|
+
const label = requireLabel(true, isRoot);
|
|
2141
2193
|
binds.push(this.makeComponentDyn(n, label));
|
|
2142
2194
|
} else {
|
|
2143
2195
|
const label = requireLabel();
|
|
@@ -2253,6 +2305,20 @@
|
|
|
2253
2305
|
if(!n.closedTag) {
|
|
2254
2306
|
go(n, false, el);
|
|
2255
2307
|
}
|
|
2308
|
+
} else if(n.type === 'block') {
|
|
2309
|
+
if(n.name == 'keep-alive') {
|
|
2310
|
+
if(isRoot) requireFragment = true;
|
|
2311
|
+
binds.push(xNode('attach-fragment', {
|
|
2312
|
+
label: requireLabel(),
|
|
2313
|
+
block: this.makeKeepAlive(n)
|
|
2314
|
+
}, (ctx, n) => {
|
|
2315
|
+
if(n.label.node) ctx.write(true, `$runtime.insertBlock(${n.label.name}, `);
|
|
2316
|
+
else ctx.write(true, `$runtime.addBlock(${n.label.name}, `);
|
|
2317
|
+
ctx.add(n.block);
|
|
2318
|
+
ctx.write(')');
|
|
2319
|
+
}));
|
|
2320
|
+
return;
|
|
2321
|
+
} else wrapException(`wrong block: "${n.name}"`, n);
|
|
2256
2322
|
} else if(n.type === 'each') {
|
|
2257
2323
|
if(data.type == 'node' && data.body.length == 1) {
|
|
2258
2324
|
let eachBlock = this.makeEachBlock(n, {
|
|
@@ -2559,7 +2625,7 @@
|
|
|
2559
2625
|
console.log('Node: ', n);
|
|
2560
2626
|
if(n.type == 'text') e.details = n.value.trim();
|
|
2561
2627
|
else if(n.type == 'node') e.details = n.openTag.trim();
|
|
2562
|
-
else if(n.type == 'each') e.details = n.value.trim();
|
|
2628
|
+
else if(n.type == 'each' || n.type == 'block') e.details = n.value.trim();
|
|
2563
2629
|
else if(n.type == 'if') e.details = n.parts?.[0]?.value.trim() || 'if-block';
|
|
2564
2630
|
}
|
|
2565
2631
|
throw e;
|
|
@@ -4686,7 +4752,7 @@
|
|
|
4686
4752
|
function makeDom(data) {
|
|
4687
4753
|
function build(parent, list) {
|
|
4688
4754
|
list.forEach(e => {
|
|
4689
|
-
if(e.type == 'fragment' || e.type == 'slot') {
|
|
4755
|
+
if(e.type == 'fragment' || e.type == 'slot' || e.type == 'block') {
|
|
4690
4756
|
if(e.body && e.body.length) build(parent, e.body);
|
|
4691
4757
|
return;
|
|
4692
4758
|
} else if(e.type == 'each') {
|
|
@@ -6105,7 +6171,7 @@
|
|
|
6105
6171
|
}
|
|
6106
6172
|
|
|
6107
6173
|
|
|
6108
|
-
function parseAttibutes(attributes) {
|
|
6174
|
+
function parseAttibutes$1(attributes) {
|
|
6109
6175
|
let props = [];
|
|
6110
6176
|
let events = [];
|
|
6111
6177
|
let forwardAllEvents;
|
|
@@ -6150,7 +6216,7 @@
|
|
|
6150
6216
|
let slot = null;
|
|
6151
6217
|
if(node.body?.length) slot = this.buildBlock({ body: trimEmptyNodes(node.body) }, { inline: true });
|
|
6152
6218
|
|
|
6153
|
-
let { props, events, forwardAllEvents, staticProps } = parseAttibutes.call(this, node.attributes);
|
|
6219
|
+
let { props, events, forwardAllEvents, staticProps } = parseAttibutes$1.call(this, node.attributes);
|
|
6154
6220
|
|
|
6155
6221
|
return xNode('call-fragment', {
|
|
6156
6222
|
$compile: [slot?.source],
|
|
@@ -6250,7 +6316,7 @@
|
|
|
6250
6316
|
// assert(!data.slot.template.svg, 'SVG is not supported for exported fragment');
|
|
6251
6317
|
}
|
|
6252
6318
|
|
|
6253
|
-
let pa = parseAttibutes.call(this, node.attributes);
|
|
6319
|
+
let pa = parseAttibutes$1.call(this, node.attributes);
|
|
6254
6320
|
data = { ...pa, ...data };
|
|
6255
6321
|
|
|
6256
6322
|
return xNode('attach-exported-fragment', data, (ctx, n) => {
|
|
@@ -6634,7 +6700,44 @@
|
|
|
6634
6700
|
return { event, fn, rootModifier };
|
|
6635
6701
|
}
|
|
6636
6702
|
|
|
6637
|
-
|
|
6703
|
+
function makeKeepAlive(node) {
|
|
6704
|
+
let block;
|
|
6705
|
+
if(node.body && node.body.length) {
|
|
6706
|
+
block = this.buildBlock({ body: trimEmptyNodes(node.body) }, { }).block;
|
|
6707
|
+
} else {
|
|
6708
|
+
this.warning(`Empty block: '${node.value}'`);
|
|
6709
|
+
return xNode('empty-block', (ctx, n) => {
|
|
6710
|
+
ctx.writeLine(`function $block() {};`);
|
|
6711
|
+
});
|
|
6712
|
+
}
|
|
6713
|
+
|
|
6714
|
+
let key = null;
|
|
6715
|
+
let args = node.value.substr(12);
|
|
6716
|
+
if(args) {
|
|
6717
|
+
args = parseAttibutes(args);
|
|
6718
|
+
const a = args.find(a => a.name == 'key');
|
|
6719
|
+
if(a) {
|
|
6720
|
+
let value = a.value;
|
|
6721
|
+
if(value[0] == '{') value = unwrapExp(value);
|
|
6722
|
+
key = `() => (${value})`;
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
|
|
6726
|
+
if(!key) key = `() => '$$${this.uniqIndex++}'`;
|
|
6727
|
+
|
|
6728
|
+
this.glob.keepAliveStore.$value();
|
|
6729
|
+
|
|
6730
|
+
return xNode('keep-alive', {
|
|
6731
|
+
block,
|
|
6732
|
+
key
|
|
6733
|
+
}, (ctx, n) => {
|
|
6734
|
+
ctx.write(`$runtime.keepAlive($$keepAliveStore, ${n.key}, `);
|
|
6735
|
+
ctx.add(n.block);
|
|
6736
|
+
ctx.write(')');
|
|
6737
|
+
});
|
|
6738
|
+
}
|
|
6739
|
+
|
|
6740
|
+
const version = '0.7.2-a6';
|
|
6638
6741
|
|
|
6639
6742
|
|
|
6640
6743
|
async function compile(source, config = {}) {
|
|
@@ -6680,6 +6783,7 @@
|
|
|
6680
6783
|
inspectProp,
|
|
6681
6784
|
attachPortal,
|
|
6682
6785
|
makeEventProp,
|
|
6786
|
+
makeKeepAlive,
|
|
6683
6787
|
checkRootName: checkRootName,
|
|
6684
6788
|
|
|
6685
6789
|
inuse: {},
|
|
@@ -6709,12 +6813,14 @@
|
|
|
6709
6813
|
detectDependency,
|
|
6710
6814
|
|
|
6711
6815
|
DOM: null,
|
|
6712
|
-
parseHTML:
|
|
6816
|
+
parseHTML: function() {
|
|
6817
|
+
this.DOM = parseHTML(this.source);
|
|
6818
|
+
},
|
|
6713
6819
|
compactDOM,
|
|
6714
6820
|
|
|
6715
6821
|
script: null,
|
|
6716
6822
|
scriptNodes: null,
|
|
6717
|
-
js_parse: parse
|
|
6823
|
+
js_parse: parse,
|
|
6718
6824
|
js_transform: transform,
|
|
6719
6825
|
|
|
6720
6826
|
styleNodes: null,
|
|
@@ -6874,6 +6980,7 @@
|
|
|
6874
6980
|
}
|
|
6875
6981
|
|
|
6876
6982
|
exports.compile = compile;
|
|
6983
|
+
exports.parseHTML = parseHTML;
|
|
6877
6984
|
exports.version = version;
|
|
6878
6985
|
|
|
6879
6986
|
Object.defineProperty(exports, '__esModule', { value: true });
|
package/package.json
CHANGED
package/runtime.js
CHANGED
|
@@ -75,7 +75,7 @@ const cd_component = cd => {
|
|
|
75
75
|
return cd.component;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
const cd_new = () => new $ChangeDetector();
|
|
78
|
+
const cd_new = (parent) => new $ChangeDetector(parent);
|
|
79
79
|
|
|
80
80
|
const cd_attach = (parent, cd) => {
|
|
81
81
|
if(cd) {
|
|
@@ -414,7 +414,7 @@ const attachDynComponent = (label, exp, bind, parentLabel) => {
|
|
|
414
414
|
if(component) {
|
|
415
415
|
destroyList = current_destroyList = [];
|
|
416
416
|
current_mountList = [];
|
|
417
|
-
$cd = current_cd = cd_new();
|
|
417
|
+
$cd = current_cd = cd_new(parentCD);
|
|
418
418
|
try {
|
|
419
419
|
const $dom = bind(component).$dom;
|
|
420
420
|
cd_attach(parentCD, $cd);
|
|
@@ -882,7 +882,7 @@ function ifBlock(label, fn, parts, parentLabel) {
|
|
|
882
882
|
let $dom;
|
|
883
883
|
destroyList = current_destroyList = [];
|
|
884
884
|
let mountList = current_mountList = [];
|
|
885
|
-
$cd = current_cd = cd_new();
|
|
885
|
+
$cd = current_cd = cd_new(parentCD);
|
|
886
886
|
try {
|
|
887
887
|
$dom = builder();
|
|
888
888
|
} finally {
|
|
@@ -955,7 +955,7 @@ function awaitBlock(label, parentLabel, relation, fn, build_main, build_then, bu
|
|
|
955
955
|
|
|
956
956
|
if(!builder) return;
|
|
957
957
|
destroyList = current_destroyList = [];
|
|
958
|
-
$cd = current_cd = cd_new();
|
|
958
|
+
$cd = current_cd = cd_new(parentCD);
|
|
959
959
|
let $dom, mountList = current_mountList = [];
|
|
960
960
|
try {
|
|
961
961
|
$dom = builder(value);
|
|
@@ -1015,7 +1015,7 @@ const makeEachElseBlock = (fn) => {
|
|
|
1015
1015
|
return (label, mode, parentCD) => {
|
|
1016
1016
|
let first, last;
|
|
1017
1017
|
let destroyList = current_destroyList = [];
|
|
1018
|
-
let $cd = current_cd = cd_new();
|
|
1018
|
+
let $cd = current_cd = cd_new(parentCD);
|
|
1019
1019
|
current_mountList = [];
|
|
1020
1020
|
const parentNode = mode ? label : label.parentNode;
|
|
1021
1021
|
try {
|
|
@@ -1173,7 +1173,7 @@ function $$eachBlock(label, mode, fn, getKey, bind, buildElseBlock) {
|
|
|
1173
1173
|
let $dom, rebind,
|
|
1174
1174
|
d = current_destroyList = [],
|
|
1175
1175
|
m = current_mountList = [],
|
|
1176
|
-
$cd = current_cd = cd_new();
|
|
1176
|
+
$cd = current_cd = cd_new(eachCD);
|
|
1177
1177
|
try {
|
|
1178
1178
|
([$dom, rebind] = bind(item, i));
|
|
1179
1179
|
} finally {
|
|
@@ -1247,4 +1247,42 @@ const makeSlot = (fr, fn) => {
|
|
|
1247
1247
|
};
|
|
1248
1248
|
};
|
|
1249
1249
|
|
|
1250
|
-
|
|
1250
|
+
const keepAlive = (store, keyFn, builder) => {
|
|
1251
|
+
if(!store.$$d) store.$$d = [];
|
|
1252
|
+
const key = keyFn();
|
|
1253
|
+
let block = store.get(key);
|
|
1254
|
+
const parentCD = current_cd;
|
|
1255
|
+
|
|
1256
|
+
$onDestroy(() => {
|
|
1257
|
+
if(!block.fr) block.fr = new DocumentFragment();
|
|
1258
|
+
iterNodes(block.first, block.last, n => block.fr.appendChild(n));
|
|
1259
|
+
cd_detach(block.$cd);
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
if(block) {
|
|
1263
|
+
cd_attach(parentCD, block.$cd);
|
|
1264
|
+
return block.fr;
|
|
1265
|
+
} else {
|
|
1266
|
+
let $dom, first, last, prev_destroyList = current_destroyList;
|
|
1267
|
+
let destroyList = current_destroyList = [];
|
|
1268
|
+
let $cd = current_cd = cd_new(parentCD);
|
|
1269
|
+
try {
|
|
1270
|
+
$dom = builder();
|
|
1271
|
+
} finally {
|
|
1272
|
+
current_destroyList = prev_destroyList;
|
|
1273
|
+
current_cd = parentCD;
|
|
1274
|
+
}
|
|
1275
|
+
cd_attach(parentCD, $cd);
|
|
1276
|
+
if($dom.nodeType == 11) {
|
|
1277
|
+
first = $dom.firstChild;
|
|
1278
|
+
last = $dom.lastChild;
|
|
1279
|
+
} else first = last = $dom;
|
|
1280
|
+
|
|
1281
|
+
store.$$d.push(() => safeGroupCall(destroyList));
|
|
1282
|
+
store.set(key, block = {first, last, $cd});
|
|
1283
|
+
|
|
1284
|
+
return $dom;
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
export { $$eachBlock, $context, $digest, $onDestroy, $onMount, $tick, $watch, WatchObject, __app_onerror, __bindActionSubscribe, addBlock, addClass, addEvent, addStyles, attachAnchor, attachBlock, attachDynComponent, autoSubscribe, awaitBlock, bindAction, bindAttribute, bindAttributeBase, bindClass, bindClassExp, bindInput, bindStyle, bindText, callComponent, callComponentDyn, callExportedFragment, cd_attach, cd_component, cd_detach, cd_new, cloneDeep, compareArray, compareDeep, configure, createTextNode, current_cd, current_component, current_destroyList, current_mountList, deepComparator, destroyResults, eachDefaultKey, exportFragment, fire, htmlBlock, htmlBlockStatic, htmlToFragment, htmlToFragmentClean, ifBlock, ifBlockReadOnly, insertAfter, insertBlock, invokeSlot, invokeSlotBase, isArray, isFunction, iterNodes, keepAlive, keyComparator, makeAnchor, makeApply, makeBlock, makeBlockBound, makeClassResolver, makeComponent, makeEachBlock, makeEachElseBlock, makeEachSingleBlock, makeEmitter, makeExternalProperty, makeRootEvent, makeSlot, mergeAllEvents, mergeEvents, mount, mountStatic, noop, prefixPush, refer, removeElements, removeItem, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };
|