malinajs 0.7.2-a5 → 0.7.2-a7
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.js +333 -217
- package/package.json +1 -1
- package/runtime.js +39 -1
package/CHANGELOG.md
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,107 @@
|
|
|
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
|
+
if(r.probe('{*')) {
|
|
1355
|
+
const {raw} = parseBinding(r);
|
|
1356
|
+
result.push({name: raw, content: raw});
|
|
1357
|
+
} else if(r.probe('*{')) {
|
|
1358
|
+
r.read();
|
|
1359
|
+
let {raw} = parseBinding(r);
|
|
1360
|
+
raw = '*' + raw;
|
|
1361
|
+
result.push({name: raw, content: raw});
|
|
1362
|
+
} else if(r.probe('{...')) {
|
|
1363
|
+
let {raw} = parseBinding(r);
|
|
1364
|
+
result.push({name: raw, content: raw});
|
|
1365
|
+
} else {
|
|
1366
|
+
let name = r.readAttribute();
|
|
1367
|
+
assert(name, 'Wrong syntax');
|
|
1368
|
+
if(r.readIf('=')) {
|
|
1369
|
+
if(r.probe('{')) {
|
|
1370
|
+
const {raw} = parseBinding(r);
|
|
1371
|
+
result.push({name, value: raw, raw, content: r.sub(start)});
|
|
1372
|
+
} else if(r.probeQuote()) {
|
|
1373
|
+
const raw = r.readString();
|
|
1374
|
+
const value = raw.substring(1, raw.length - 1);
|
|
1375
|
+
result.push({name, value, raw, content: r.sub(start)});
|
|
1376
|
+
} else {
|
|
1377
|
+
const value = r.readIf(/^\S+/);
|
|
1378
|
+
result.push({name, value, raw: value, content: r.sub(start)});
|
|
1379
|
+
}
|
|
1380
|
+
} else {
|
|
1381
|
+
let value;
|
|
1382
|
+
if(name[0] == '{' && last(name) == '}' && !name.startsWith('{...')) {
|
|
1383
|
+
value = name;
|
|
1384
|
+
name = unwrapExp(name);
|
|
1385
|
+
}
|
|
1386
|
+
result.push({name, value, raw: value, content: r.sub(start)});
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
return result;
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
function parse() {
|
|
1340
1395
|
let source = this.scriptNodes.length ? this.scriptNodes[0].content : null;
|
|
1341
1396
|
this.script = {
|
|
1342
1397
|
source,
|
|
@@ -1820,6 +1875,12 @@
|
|
|
1820
1875
|
}
|
|
1821
1876
|
}));
|
|
1822
1877
|
|
|
1878
|
+
this.module.head.push(this.glob.keepAliveStore = xNode('$$keepAliveStore', {
|
|
1879
|
+
value: false
|
|
1880
|
+
}, (ctx, n) => {
|
|
1881
|
+
if(n.value) ctx.write(true, `const $$keepAliveStore = new Map();`);
|
|
1882
|
+
}));
|
|
1883
|
+
|
|
1823
1884
|
this.module.top.push(xNode(this.glob.$onMount, {
|
|
1824
1885
|
}, (ctx, n) => {
|
|
1825
1886
|
if(n.value) ctx.write(true, `import { $onMount } from 'malinajs/runtime.js';`);
|
|
@@ -2257,6 +2318,20 @@
|
|
|
2257
2318
|
if(!n.closedTag) {
|
|
2258
2319
|
go(n, false, el);
|
|
2259
2320
|
}
|
|
2321
|
+
} else if(n.type === 'block') {
|
|
2322
|
+
if(n.name == 'keep') {
|
|
2323
|
+
if(isRoot) requireFragment = true;
|
|
2324
|
+
binds.push(xNode('attach-fragment', {
|
|
2325
|
+
label: requireLabel(),
|
|
2326
|
+
block: this.makeKeepAlive(n)
|
|
2327
|
+
}, (ctx, n) => {
|
|
2328
|
+
if(n.label.node) ctx.write(true, `$runtime.insertBlock(${n.label.name}, `);
|
|
2329
|
+
else ctx.write(true, `$runtime.addBlock(${n.label.name}, `);
|
|
2330
|
+
ctx.add(n.block);
|
|
2331
|
+
ctx.write(')');
|
|
2332
|
+
}));
|
|
2333
|
+
return;
|
|
2334
|
+
} else wrapException(`wrong block: "${n.name}"`, n);
|
|
2260
2335
|
} else if(n.type === 'each') {
|
|
2261
2336
|
if(data.type == 'node' && data.body.length == 1) {
|
|
2262
2337
|
let eachBlock = this.makeEachBlock(n, {
|
|
@@ -2563,7 +2638,7 @@
|
|
|
2563
2638
|
console.log('Node: ', n);
|
|
2564
2639
|
if(n.type == 'text') e.details = n.value.trim();
|
|
2565
2640
|
else if(n.type == 'node') e.details = n.openTag.trim();
|
|
2566
|
-
else if(n.type == 'each') e.details = n.value.trim();
|
|
2641
|
+
else if(n.type == 'each' || n.type == 'block') e.details = n.value.trim();
|
|
2567
2642
|
else if(n.type == 'if') e.details = n.parts?.[0]?.value.trim() || 'if-block';
|
|
2568
2643
|
}
|
|
2569
2644
|
throw e;
|
|
@@ -4690,7 +4765,7 @@
|
|
|
4690
4765
|
function makeDom(data) {
|
|
4691
4766
|
function build(parent, list) {
|
|
4692
4767
|
list.forEach(e => {
|
|
4693
|
-
if(e.type == 'fragment' || e.type == 'slot') {
|
|
4768
|
+
if(e.type == 'fragment' || e.type == 'slot' || e.type == 'block') {
|
|
4694
4769
|
if(e.body && e.body.length) build(parent, e.body);
|
|
4695
4770
|
return;
|
|
4696
4771
|
} else if(e.type == 'each') {
|
|
@@ -6109,7 +6184,7 @@
|
|
|
6109
6184
|
}
|
|
6110
6185
|
|
|
6111
6186
|
|
|
6112
|
-
function parseAttibutes(attributes) {
|
|
6187
|
+
function parseAttibutes$1(attributes) {
|
|
6113
6188
|
let props = [];
|
|
6114
6189
|
let events = [];
|
|
6115
6190
|
let forwardAllEvents;
|
|
@@ -6154,7 +6229,7 @@
|
|
|
6154
6229
|
let slot = null;
|
|
6155
6230
|
if(node.body?.length) slot = this.buildBlock({ body: trimEmptyNodes(node.body) }, { inline: true });
|
|
6156
6231
|
|
|
6157
|
-
let { props, events, forwardAllEvents, staticProps } = parseAttibutes.call(this, node.attributes);
|
|
6232
|
+
let { props, events, forwardAllEvents, staticProps } = parseAttibutes$1.call(this, node.attributes);
|
|
6158
6233
|
|
|
6159
6234
|
return xNode('call-fragment', {
|
|
6160
6235
|
$compile: [slot?.source],
|
|
@@ -6254,7 +6329,7 @@
|
|
|
6254
6329
|
// assert(!data.slot.template.svg, 'SVG is not supported for exported fragment');
|
|
6255
6330
|
}
|
|
6256
6331
|
|
|
6257
|
-
let pa = parseAttibutes.call(this, node.attributes);
|
|
6332
|
+
let pa = parseAttibutes$1.call(this, node.attributes);
|
|
6258
6333
|
data = { ...pa, ...data };
|
|
6259
6334
|
|
|
6260
6335
|
return xNode('attach-exported-fragment', data, (ctx, n) => {
|
|
@@ -6638,7 +6713,44 @@
|
|
|
6638
6713
|
return { event, fn, rootModifier };
|
|
6639
6714
|
}
|
|
6640
6715
|
|
|
6641
|
-
|
|
6716
|
+
function makeKeepAlive(node) {
|
|
6717
|
+
let block;
|
|
6718
|
+
if(node.body && node.body.length) {
|
|
6719
|
+
block = this.buildBlock({ body: trimEmptyNodes(node.body) }, { }).block;
|
|
6720
|
+
} else {
|
|
6721
|
+
this.warning(`Empty block: '${node.value}'`);
|
|
6722
|
+
return xNode('empty-block', (ctx, n) => {
|
|
6723
|
+
ctx.writeLine(`function $block() {};`);
|
|
6724
|
+
});
|
|
6725
|
+
}
|
|
6726
|
+
|
|
6727
|
+
let key = null;
|
|
6728
|
+
let args = node.value.substr(6);
|
|
6729
|
+
if(args) {
|
|
6730
|
+
args = parseAttibutes(args);
|
|
6731
|
+
const a = args.find(a => a.name == 'key');
|
|
6732
|
+
if(a) {
|
|
6733
|
+
let value = a.value;
|
|
6734
|
+
if(value[0] == '{') value = unwrapExp(value);
|
|
6735
|
+
key = `() => (${value})`;
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
|
|
6739
|
+
if(!key) key = `() => '$$${this.uniqIndex++}'`;
|
|
6740
|
+
|
|
6741
|
+
this.glob.keepAliveStore.$value();
|
|
6742
|
+
|
|
6743
|
+
return xNode('keep-alive', {
|
|
6744
|
+
block,
|
|
6745
|
+
key
|
|
6746
|
+
}, (ctx, n) => {
|
|
6747
|
+
ctx.write(`$runtime.keepAlive($$keepAliveStore, ${n.key}, `);
|
|
6748
|
+
ctx.add(n.block);
|
|
6749
|
+
ctx.write(')');
|
|
6750
|
+
});
|
|
6751
|
+
}
|
|
6752
|
+
|
|
6753
|
+
const version = '0.7.2-a7';
|
|
6642
6754
|
|
|
6643
6755
|
|
|
6644
6756
|
async function compile(source, config = {}) {
|
|
@@ -6684,6 +6796,7 @@
|
|
|
6684
6796
|
inspectProp,
|
|
6685
6797
|
attachPortal,
|
|
6686
6798
|
makeEventProp,
|
|
6799
|
+
makeKeepAlive,
|
|
6687
6800
|
checkRootName: checkRootName,
|
|
6688
6801
|
|
|
6689
6802
|
inuse: {},
|
|
@@ -6713,12 +6826,14 @@
|
|
|
6713
6826
|
detectDependency,
|
|
6714
6827
|
|
|
6715
6828
|
DOM: null,
|
|
6716
|
-
parseHTML:
|
|
6829
|
+
parseHTML: function() {
|
|
6830
|
+
this.DOM = parseHTML(this.source);
|
|
6831
|
+
},
|
|
6717
6832
|
compactDOM,
|
|
6718
6833
|
|
|
6719
6834
|
script: null,
|
|
6720
6835
|
scriptNodes: null,
|
|
6721
|
-
js_parse: parse
|
|
6836
|
+
js_parse: parse,
|
|
6722
6837
|
js_transform: transform,
|
|
6723
6838
|
|
|
6724
6839
|
styleNodes: null,
|
|
@@ -6878,6 +6993,7 @@
|
|
|
6878
6993
|
}
|
|
6879
6994
|
|
|
6880
6995
|
exports.compile = compile;
|
|
6996
|
+
exports.parseHTML = parseHTML;
|
|
6881
6997
|
exports.version = version;
|
|
6882
6998
|
|
|
6883
6999
|
Object.defineProperty(exports, '__esModule', { value: true });
|
package/package.json
CHANGED
package/runtime.js
CHANGED
|
@@ -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 };
|