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 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
+ }
944
905
 
945
- const readScript = (tag) => {
946
- let endTag = `</${tag}>`;
947
- let q, a, p, start = index;
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 = 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,94 @@
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
+ 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
- const version = '0.7.2-a5';
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: parse,
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$1,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "malinajs",
3
- "version": "0.7.2-a5",
3
+ "version": "0.7.2-a6",
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 };