malinajs 0.7.2-a5 → 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.js +320 -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
|
+
}
|
|
944
905
|
|
|
945
|
-
|
|
946
|
-
let
|
|
947
|
-
|
|
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);
|
|
926
|
+
|
|
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';`);
|
|
@@ -2257,6 +2305,20 @@
|
|
|
2257
2305
|
if(!n.closedTag) {
|
|
2258
2306
|
go(n, false, el);
|
|
2259
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);
|
|
2260
2322
|
} else if(n.type === 'each') {
|
|
2261
2323
|
if(data.type == 'node' && data.body.length == 1) {
|
|
2262
2324
|
let eachBlock = this.makeEachBlock(n, {
|
|
@@ -2563,7 +2625,7 @@
|
|
|
2563
2625
|
console.log('Node: ', n);
|
|
2564
2626
|
if(n.type == 'text') e.details = n.value.trim();
|
|
2565
2627
|
else if(n.type == 'node') e.details = n.openTag.trim();
|
|
2566
|
-
else if(n.type == 'each') e.details = n.value.trim();
|
|
2628
|
+
else if(n.type == 'each' || n.type == 'block') e.details = n.value.trim();
|
|
2567
2629
|
else if(n.type == 'if') e.details = n.parts?.[0]?.value.trim() || 'if-block';
|
|
2568
2630
|
}
|
|
2569
2631
|
throw e;
|
|
@@ -4690,7 +4752,7 @@
|
|
|
4690
4752
|
function makeDom(data) {
|
|
4691
4753
|
function build(parent, list) {
|
|
4692
4754
|
list.forEach(e => {
|
|
4693
|
-
if(e.type == 'fragment' || e.type == 'slot') {
|
|
4755
|
+
if(e.type == 'fragment' || e.type == 'slot' || e.type == 'block') {
|
|
4694
4756
|
if(e.body && e.body.length) build(parent, e.body);
|
|
4695
4757
|
return;
|
|
4696
4758
|
} else if(e.type == 'each') {
|
|
@@ -6109,7 +6171,7 @@
|
|
|
6109
6171
|
}
|
|
6110
6172
|
|
|
6111
6173
|
|
|
6112
|
-
function parseAttibutes(attributes) {
|
|
6174
|
+
function parseAttibutes$1(attributes) {
|
|
6113
6175
|
let props = [];
|
|
6114
6176
|
let events = [];
|
|
6115
6177
|
let forwardAllEvents;
|
|
@@ -6154,7 +6216,7 @@
|
|
|
6154
6216
|
let slot = null;
|
|
6155
6217
|
if(node.body?.length) slot = this.buildBlock({ body: trimEmptyNodes(node.body) }, { inline: true });
|
|
6156
6218
|
|
|
6157
|
-
let { props, events, forwardAllEvents, staticProps } = parseAttibutes.call(this, node.attributes);
|
|
6219
|
+
let { props, events, forwardAllEvents, staticProps } = parseAttibutes$1.call(this, node.attributes);
|
|
6158
6220
|
|
|
6159
6221
|
return xNode('call-fragment', {
|
|
6160
6222
|
$compile: [slot?.source],
|
|
@@ -6254,7 +6316,7 @@
|
|
|
6254
6316
|
// assert(!data.slot.template.svg, 'SVG is not supported for exported fragment');
|
|
6255
6317
|
}
|
|
6256
6318
|
|
|
6257
|
-
let pa = parseAttibutes.call(this, node.attributes);
|
|
6319
|
+
let pa = parseAttibutes$1.call(this, node.attributes);
|
|
6258
6320
|
data = { ...pa, ...data };
|
|
6259
6321
|
|
|
6260
6322
|
return xNode('attach-exported-fragment', data, (ctx, n) => {
|
|
@@ -6638,7 +6700,44 @@
|
|
|
6638
6700
|
return { event, fn, rootModifier };
|
|
6639
6701
|
}
|
|
6640
6702
|
|
|
6641
|
-
|
|
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';
|
|
6642
6741
|
|
|
6643
6742
|
|
|
6644
6743
|
async function compile(source, config = {}) {
|
|
@@ -6684,6 +6783,7 @@
|
|
|
6684
6783
|
inspectProp,
|
|
6685
6784
|
attachPortal,
|
|
6686
6785
|
makeEventProp,
|
|
6786
|
+
makeKeepAlive,
|
|
6687
6787
|
checkRootName: checkRootName,
|
|
6688
6788
|
|
|
6689
6789
|
inuse: {},
|
|
@@ -6713,12 +6813,14 @@
|
|
|
6713
6813
|
detectDependency,
|
|
6714
6814
|
|
|
6715
6815
|
DOM: null,
|
|
6716
|
-
parseHTML:
|
|
6816
|
+
parseHTML: function() {
|
|
6817
|
+
this.DOM = parseHTML(this.source);
|
|
6818
|
+
},
|
|
6717
6819
|
compactDOM,
|
|
6718
6820
|
|
|
6719
6821
|
script: null,
|
|
6720
6822
|
scriptNodes: null,
|
|
6721
|
-
js_parse: parse
|
|
6823
|
+
js_parse: parse,
|
|
6722
6824
|
js_transform: transform,
|
|
6723
6825
|
|
|
6724
6826
|
styleNodes: null,
|
|
@@ -6878,6 +6980,7 @@
|
|
|
6878
6980
|
}
|
|
6879
6981
|
|
|
6880
6982
|
exports.compile = compile;
|
|
6983
|
+
exports.parseHTML = parseHTML;
|
|
6881
6984
|
exports.version = version;
|
|
6882
6985
|
|
|
6883
6986
|
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 };
|