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 CHANGED
@@ -15,6 +15,7 @@
15
15
  * else-if
16
16
  * refactoring $onMount
17
17
  * optional deep checking for passed props: prop={value} prop|deep={value}
18
+ * keep-alive
18
19
 
19
20
  ## 0.6.x
20
21
 
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
- function parse() {
839
- let source = this.source;
840
- let index = 0;
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
- const readNext = () => {
843
- assert(index < source.length, 'EOF');
844
- return source[index++];
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
- const probeNext = () => source[index];
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
- const readTag = () => {
850
- let start = index;
851
- let a = readNext();
852
- assert(a === '<', 'Tag error');
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
- const error = (name) => {
860
- let e = new Error(name);
861
- e.details = source.substring(start, index);
862
- throw e;
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
- function flush(shift) {
866
- if(!attr_start) return;
867
- shift = shift || 0;
868
- let end = index - 1 + shift;
869
- if(elArg === true) {
870
- elArg = source.substring(attr_start, end);
871
- attr_start = null;
872
- eq = null;
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
- a = readNext();
892
- if(!begin && !attr_start && a.match(/\S/) && a != '/' && a != '>') attr_start = index - 1;
893
- if(a == '"' || a == "'" || a == '`') {
894
- while(a != readNext());
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 = (tag) => {
946
- let endTag = `</${tag}>`;
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 = readNext();
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
- p = a;
966
- a = readNext();
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(a == '"' || a == '\'' || a == '`') {
974
- q = a;
975
- continue;
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(n == '*') {
985
- readNext();
986
- while(true) { // multiline comment
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(a == '<') {
997
- if(source.substring(index - 1, index + endTag.length - 1) == endTag) {
998
- let end = index - 1;
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
- let start = index;
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 readBinding = () => {
1015
- let start = index;
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 readComment = () => {
1061
- let start = index;
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(index < source.length) {
1090
- let a = source[index];
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(source.substring(index, index + 4) === '<!--') {
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(source[index + 1] === '/') { // close tag
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('script');
1030
+ tag.content = readScript(reader);
1123
1031
  continue;
1124
1032
  } else if(tag.name === 'template') {
1125
1033
  tag.type = 'template';
1126
- tag.content = readScript('template');
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(a === '{') {
1148
- if(['#', '/', ':', '@', '*'].indexOf(source[index + 1]) >= 0) {
1149
- let bind = readBinding();
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
- addText(readBinding().raw);
1251
- continue;
1173
+ addText(parseBinding(reader).raw);
1174
+ continue;
1252
1175
  }
1253
1176
  }
1254
1177
 
1255
- addText(readNext());
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
- this.DOM = root;
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
- function parse$1() {
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
- const version = '0.7.2-a5';
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: parse,
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$1,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "malinajs",
3
- "version": "0.7.2-a5",
3
+ "version": "0.7.2-a7",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "prepare": "npm run build",
package/runtime.js CHANGED
@@ -1247,4 +1247,42 @@ const makeSlot = (fr, fn) => {
1247
1247
  };
1248
1248
  };
1249
1249
 
1250
- 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, 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 };
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 };