malinajs 0.7.0-a2 → 0.7.0-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.
Files changed (3) hide show
  1. package/malina.js +599 -554
  2. package/package.json +2 -2
  3. package/runtime.js +310 -302
package/malina.js CHANGED
@@ -8,6 +8,23 @@
8
8
  astring = astring && Object.prototype.hasOwnProperty.call(astring, 'default') ? astring['default'] : astring;
9
9
  csstree = csstree && Object.prototype.hasOwnProperty.call(csstree, 'default') ? csstree['default'] : csstree;
10
10
 
11
+ let current_context;
12
+
13
+ const get_context = () => {
14
+ assert(current_context, 'Out of context');
15
+ return current_context;
16
+ };
17
+
18
+ const use_context = (context, fn) => {
19
+ let prev = current_context;
20
+ try {
21
+ current_context = context;
22
+ fn();
23
+ } finally {
24
+ current_context = prev;
25
+ }
26
+ };
27
+
11
28
  let _svgElements = 'animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,tspan,unknown,use,view';
12
29
  let svgElements = {};
13
30
  _svgElements.split(',').forEach(k => svgElements[k] = true);
@@ -20,19 +37,16 @@
20
37
 
21
38
  function toCamelCase(name) {
22
39
  assert(name[name.length - 1] !== '-', 'Wrong name');
23
- return name.replace(/(\-\w)/g, function(part) {
40
+ return name.replace(/(?<!-)(\-\w)/g, function(part) {
24
41
  return part[1].toUpperCase();
25
42
  });
26
43
  }
27
44
 
28
45
  function Q(s) {
46
+ if(get_context().config.inlineTemplate) return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\n/g, '\\n');
29
47
  return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`');
30
48
  }
31
49
 
32
- function Q2(s) {
33
- return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\n/g, '\\n');
34
- }
35
-
36
50
  function unwrapExp(e) {
37
51
  assert(e, 'Empty expression');
38
52
  let rx = e.match(/^\{(.*)\}$/);
@@ -60,19 +74,10 @@
60
74
  let ast = acorn.parse(name, { allowReturnOutsideFunction: true });
61
75
 
62
76
  function checkIdentificator(body) {
63
- if(body.length != 1) return;
64
- if(body[0].type != 'ExpressionStatement') return;
65
- if(body[0].expression.type != 'Identifier') return;
66
- return true;
67
- }
68
-
69
- function checkMemberIdentificator(body) {
70
77
  if(body.length != 1) return;
71
78
  if(body[0].type != 'ExpressionStatement') return;
72
79
  let obj = body[0].expression;
73
- if(obj.type != 'MemberExpression') return;
74
- if(obj.property.type != 'Identifier') return;
75
- return true;
80
+ return obj.type == 'Identifier' || obj.type == 'MemberExpression';
76
81
  }
77
82
 
78
83
  function checkFunction(body) {
@@ -92,7 +97,6 @@
92
97
  }
93
98
 
94
99
  if(checkIdentificator(ast.body)) return 'identifier';
95
- if(checkMemberIdentificator(ast.body)) return 'identifier';
96
100
  if(checkFunction(ast.body)) return 'function';
97
101
 
98
102
  let fn = checkFunctionCall(ast.body);
@@ -177,7 +181,7 @@
177
181
 
178
182
  const replaceElementKeyword = (exp, fn) => {
179
183
  let changed = false;
180
- let r = parseJS(exp, (n, pk) => {
184
+ let r = parseJS(exp).transform((n, pk) => {
181
185
  if(n.type != 'Identifier') return;
182
186
  if(pk == 'property' || pk == 'params') return;
183
187
  if(n.name != '$element') return;
@@ -188,38 +192,42 @@
188
192
  };
189
193
 
190
194
 
191
- const parseJS = (exp, fn) => {
192
- let result = {};
193
- let ast = result.ast = acorn.parse(exp, { sourceType: 'module', ecmaVersion: 12 });
194
-
195
- const rec = (n, pk) => {
196
- let self;
197
- if(n.type) {
198
- self = n;
199
- fn?.(n, pk);
200
- }
201
-
202
- for(let k in n) {
203
- if(k == '_parent') continue;
204
- let v = n[k];
205
- if(v == null || typeof (v) != 'object') continue;
206
- if(Array.isArray(v)) {
207
- v.forEach(i => {
208
- i._parent = self || n._parent;
209
- rec(i, k);
210
- });
211
- } else {
212
- v._parent = self || n._parent;
213
- rec(v, k);
195
+ const parseJS = (exp) => {
196
+ let self = {};
197
+ self.ast = acorn.parse(exp, { sourceType: 'module', ecmaVersion: 12 });
198
+
199
+ self.transform = function(fn) {
200
+ const rec = (n, pk) => {
201
+ let self;
202
+ if(n.type) {
203
+ self = n;
204
+ fn?.(n, pk);
205
+ }
206
+
207
+ for(let k in n) {
208
+ if(k == '_parent') continue;
209
+ let v = n[k];
210
+ if(v == null || typeof(v) != 'object') continue;
211
+ if(Array.isArray(v)) {
212
+ v.forEach(i => {
213
+ i._parent = self || n._parent;
214
+ rec(i, k);
215
+ });
216
+ } else {
217
+ v._parent = self || n._parent;
218
+ rec(v, k);
219
+ }
214
220
  }
215
- }
221
+ };
222
+ rec(self.ast, null);
223
+
224
+ return self;
216
225
  };
217
- rec(ast, null);
218
226
 
219
- result.build = (data) => {
220
- return astring.generate(data || ast);
227
+ self.build = function(data) {
228
+ return astring.generate(data || self.ast);
221
229
  };
222
- return result;
230
+ return self;
223
231
  };
224
232
 
225
233
 
@@ -233,7 +241,7 @@
233
241
  [/&#47;/g, '/'],
234
242
  [/&lt;/g, '<'],
235
243
  [/&gt;/g, '>'],
236
- [/&nbsp;/g, ' '],
244
+ [/&nbsp;/g, ' '],
237
245
  [/&quot;/g, '"']
238
246
  ];
239
247
  entities.forEach(([k, v]) => {
@@ -242,13 +250,15 @@
242
250
  return text;
243
251
  };
244
252
 
253
+ const isFunction = fn => typeof fn == 'function';
254
+
245
255
  function I(value = 0) {
246
256
  this.$indent = value;
247
257
  }
248
258
 
249
259
 
250
- function xWriter(ctx, node) {
251
- this._ctx = ctx;
260
+ function xWriter(node) {
261
+ const ctx = get_context();
252
262
  this.inuse = ctx.inuse;
253
263
 
254
264
  this.indent = 0;
@@ -290,22 +300,28 @@
290
300
  }
291
301
 
292
302
 
293
- function xBuild(ctx, node) {
294
- let pending = 0;
303
+ function xBuild(node) {
304
+ let pending, trace;
295
305
  const resolve = n => {
296
306
  n.$compile?.forEach(c => {
297
307
  c != null && resolve(c);
298
308
  });
299
309
  if(!n.$done) {
300
310
  let ready = true;
301
- if(n.$deps?.length) {
302
- if(n.$deps.some(i => i != null && !i.$done)) {
311
+ if(n.$wait?.length) {
312
+ const allDone = n.$wait.every(i => {
313
+ if(i == null) return true;
314
+ assert(i instanceof xNode, '$wait supports only xNode');
315
+ if(!i.$done) trace.push(`${n.$type} -> ${i.$type}`);
316
+ return i.$done;
317
+ });
318
+ if(!allDone) {
303
319
  pending++;
304
320
  ready = false;
305
321
  }
306
322
  }
307
323
  if(ready) {
308
- let w = new xWriter(ctx, n);
324
+ let w = new xWriter(n);
309
325
  n.$handler(w, n);
310
326
  n.$done = true;
311
327
  }
@@ -320,10 +336,14 @@
320
336
  let depth;
321
337
  for(depth = 10; depth > 0; depth--) {
322
338
  pending = 0;
339
+ trace = [];
323
340
  resolve(node);
324
341
  if(!pending) break;
325
342
  }
326
- if(!depth) throw new Error('xNode: Circular dependency');
343
+ if(!depth) {
344
+ trace.forEach(i => get_context().warning(` * ${i}`));
345
+ throw new Error('xNode: Circular dependency');
346
+ }
327
347
 
328
348
  let result = [];
329
349
 
@@ -374,11 +394,24 @@
374
394
 
375
395
  function xNode(_type, _data, _handler) {
376
396
  /*
377
- xNode(type, data, handler)
378
- xNode(type, handler)
379
- xNode(data, handler)
380
- xNode(handler)
381
- */
397
+ xNode(type, data, handler)
398
+ xNode(type, handler)
399
+ xNode(data, handler)
400
+ xNode(handler)
401
+ xNode(xNode, data, handler)
402
+ */
403
+ if(_type instanceof xNode) {
404
+ let n = _type;
405
+ if(isFunction(_handler)) {
406
+ Object.assign(n, _data);
407
+ n.$handler = _handler;
408
+ } else {
409
+ assert(!_handler && isFunction(_data), 'Wrong xNode usage');
410
+ n.$handler = _data;
411
+ }
412
+ resolveDependecies(n);
413
+ return n;
414
+ }
382
415
  if(!(this instanceof xNode)) return new xNode(_type, _data, _handler);
383
416
 
384
417
  let type, data, handler;
@@ -387,6 +420,9 @@
387
420
  if(_data === false && !_handler) {
388
421
  handler = noop;
389
422
  data = null;
423
+ } else if(_handler === false && typeof(_data) == 'object') {
424
+ handler = noop;
425
+ data = _data;
390
426
  } else if(typeof _data == 'function') {
391
427
  assert(!_handler);
392
428
  handler = _data;
@@ -418,18 +454,42 @@
418
454
  this.$done = false;
419
455
  this.$inserted = false;
420
456
  this.$result = [];
421
- this.$depends = function(n) {
422
- assert(!this.$done, 'Attempt to add dependecy, but node is already resolved');
423
- if(!this.$deps) this.$deps = [];
424
- this.$deps.push(n);
425
- };
457
+
426
458
  this.$value = function(value) {
427
459
  assert(!this.$done, 'Attempt to set active, depends node is already resolved');
428
460
  this.value = value === undefined ? true : value;
429
461
  };
462
+ resolveDependecies(this);
430
463
  return this;
431
464
  }
432
465
 
466
+ const resolveDependecies = node => {
467
+ if(node.$wait) {
468
+ node.$wait = node.$wait.map(n => {
469
+ if(typeof(n) == 'string') {
470
+ const context = get_context();
471
+ assert(context.glob[n], `Wrong dependency '${n}'`);
472
+ n = context.glob[n];
473
+ }
474
+ return n;
475
+ });
476
+ }
477
+
478
+ if(node.$hold) {
479
+ node.$hold.forEach(n => {
480
+ if(typeof(n) == 'string') {
481
+ const context = get_context();
482
+ assert(context.glob[n], `Wrong dependency '${n}'`);
483
+ n = context.glob[n];
484
+ }
485
+ assert(!n.$done, 'Attempt to add dependecy, but node is already resolved');
486
+ if(!n.$wait) n.$wait = [];
487
+ n.$wait.push(node);
488
+ });
489
+ delete node.$hold;
490
+ }
491
+ };
492
+
433
493
  xNode.init = {
434
494
  raw: (ctx, node) => {
435
495
  ctx.writeLine(node.value);
@@ -442,6 +502,11 @@
442
502
  if(typeof child == 'string') child = xNode('raw', { value: child });
443
503
  this.body.push(child);
444
504
  };
505
+ node.unshift = function(child) {
506
+ assert(arguments.length == 1, 'Wrong xNode');
507
+ if(typeof child == 'string') child = xNode('raw', { value: child });
508
+ this.body.unshift(child);
509
+ };
445
510
  },
446
511
  handler: (ctx, node) => {
447
512
  if(node.scope) {
@@ -504,7 +569,6 @@
504
569
  }
505
570
  assert(n instanceof xNode);
506
571
  this.children.push(n);
507
- n._ctx = this._ctx;
508
572
  return n;
509
573
  };
510
574
  },
@@ -529,7 +593,7 @@
529
593
 
530
594
  let className = {};
531
595
  node.class.forEach(sel => {
532
- if(sel.$selector) sel = ctx._ctx.css.resolve(sel);
596
+ if(sel.$selector) sel = get_context().css.resolve(sel);
533
597
  className[sel] = true;
534
598
  });
535
599
  className = Object.keys(className).join(' ');
@@ -546,7 +610,7 @@
546
610
  }
547
611
  },
548
612
  bindName: function() {
549
- if(!this._boundName) this._boundName = `el${this._ctx.uniqIndex++}`;
613
+ if(!this._boundName) this._boundName = `el${get_context().uniqIndex++}`;
550
614
  return this._boundName;
551
615
  }
552
616
  },
@@ -563,12 +627,13 @@
563
627
  node.bindName = xNode.init.node.bindName;
564
628
  },
565
629
  handler: (ctx, node) => {
566
- if(ctx._ctx.config.debug && ctx._ctx.config.debugLabel) ctx.write(`<!-- ${node.value} -->`);
630
+ const context = get_context();
631
+ if(context.config.debug && context.config.debugLabel) ctx.write(`<!-- ${node.value} -->`);
567
632
  else ctx.write('<!---->');
568
633
  }
569
634
  },
570
635
  template: (ctx, node) => {
571
- let template = ctx._ctx.xBuild(node.body);
636
+ let template = xBuild(node.body);
572
637
  let convert, cloneNode = node.cloneNode;
573
638
  if(node.svg) {
574
639
  convert = '$runtime.svgToFragment';
@@ -582,16 +647,16 @@
582
647
  template = template.replace(/<!---->/g, '<>');
583
648
  }
584
649
  if(node.raw) {
585
- ctx.write(ctx._ctx.Q(template));
650
+ ctx.write(Q(template));
586
651
  } else if(node.inline) {
587
- ctx.write(`${convert}(\`${ctx._ctx.Q(template)}\``);
652
+ ctx.write(`${convert}(\`${Q(template)}\``);
588
653
  if(cloneNode || node.requireFragment) {
589
654
  let opt = (cloneNode ? 1 : 0) + (node.requireFragment ? 2 : 0);
590
655
  ctx.write(`, ${opt})`);
591
656
  } else ctx.write(')');
592
657
  } else {
593
658
  assert(node.name);
594
- ctx.write(true, `const ${node.name} = ${convert}(\`${ctx._ctx.Q(template)}\``);
659
+ ctx.write(true, `const ${node.name} = ${convert}(\`${Q(template)}\``);
595
660
  if(cloneNode || node.requireFragment) {
596
661
  let opt = (cloneNode ? 1 : 0) + (node.requireFragment ? 2 : 0);
597
662
  ctx.write(`, ${opt});`);
@@ -934,7 +999,8 @@
934
999
  } else continue;
935
1000
 
936
1001
  return {
937
- value: source.substring(start + 1, index - 1)
1002
+ value: source.substring(start + 1, index - 1),
1003
+ raw: source.substring(start, index)
938
1004
  };
939
1005
  }
940
1006
  };
@@ -951,6 +1017,16 @@
951
1017
  const go = (parent) => {
952
1018
  let textNode = null;
953
1019
 
1020
+ const addText = v => {
1021
+ if(!textNode) {
1022
+ textNode = {
1023
+ type: 'text',
1024
+ value: ''
1025
+ };
1026
+ }
1027
+ textNode.value += v;
1028
+ };
1029
+
954
1030
  const flushText = () => {
955
1031
  if(!textNode) return;
956
1032
  parent.body.push(textNode);
@@ -1016,10 +1092,12 @@
1016
1092
  }
1017
1093
  continue;
1018
1094
  } else if(a === '{') {
1019
- if(['#', '/', ':', '@'].indexOf(source[index + 1]) >= 0) {
1020
- flushText();
1095
+ if(['#', '/', ':', '@', '*'].indexOf(source[index + 1]) >= 0) {
1021
1096
  let bind = readBinding();
1022
- if(bind.value.match(/^@\w+/)) {
1097
+ if(bind.value[0] != '*') flushText();
1098
+ if(bind.value[0] == '*') {
1099
+ addText(bind.raw);
1100
+ } else if(bind.value.match(/^@\w+/)) {
1023
1101
  let tag = {
1024
1102
  type: 'systag',
1025
1103
  value: bind.value
@@ -1111,13 +1189,7 @@
1111
1189
  }
1112
1190
  }
1113
1191
 
1114
- if(!textNode) {
1115
- textNode = {
1116
- type: 'text',
1117
- value: ''
1118
- };
1119
- }
1120
- textNode.value += readNext();
1192
+ addText(readNext());
1121
1193
  }
1122
1194
  flushText();
1123
1195
  assert(parent.type === 'root', 'File ends to early');
@@ -1197,7 +1269,7 @@
1197
1269
  else result.push({ ...p });
1198
1270
  }
1199
1271
  });
1200
- result = result.map(p => p.type == 'text' ? '`' + this.Q(p.value) + '`' : '(' + p.value + ')').join('+');
1272
+ result = result.map(p => p.type == 'text' ? '`' + Q(p.value) + '`' : '(' + p.value + ')').join('+');
1201
1273
  return { result, parts, staticText };
1202
1274
  }
1203
1275
 
@@ -1205,7 +1277,6 @@
1205
1277
  let source = this.scriptNodes.length ? this.scriptNodes[0].content : null;
1206
1278
  this.script = {
1207
1279
  source,
1208
- watchers: [],
1209
1280
  imports: [],
1210
1281
  importedNames: [],
1211
1282
  autosubscribeNames: [],
@@ -1357,7 +1428,7 @@
1357
1428
  function walk(node, parent, fn) {
1358
1429
  if(typeof node !== 'object') return;
1359
1430
 
1360
- if(node._apply) return;
1431
+ if(node._apply && node.type == 'ExpressionStatement') return;
1361
1432
  node._parent = parent;
1362
1433
  let forParent = parent;
1363
1434
  if(node.type) {
@@ -1395,6 +1466,8 @@
1395
1466
  };
1396
1467
  }
1397
1468
 
1469
+ let watchers = xNode('block');
1470
+
1398
1471
  const makeWatch = (n) => {
1399
1472
  function assertExpression(n) {
1400
1473
  if(['Identifier', 'TemplateLiteral', 'Literal'].includes(n.type)) return;
@@ -1411,15 +1484,22 @@
1411
1484
  target = ex.left.name;
1412
1485
  if(!(target in rootVariables)) resultBody.push(makeVariable(target));
1413
1486
  } else if(ex.left.type == 'MemberExpression') {
1414
- target = source.substring(ex.left.start, ex.left.end);
1487
+ target = astring.generate(ex.left);
1415
1488
  } else throw 'Error';
1416
1489
  assertExpression(ex.right);
1417
- const exp = source.substring(ex.right.start, ex.right.end);
1418
- result.watchers.push(`$runtime.prefixPush($cd, () => {${target} = ${exp};});`);
1490
+ const exp = astring.generate(ex.right);
1491
+ watchers.push(xNode('watch-assign', {
1492
+ $wait: ['apply'],
1493
+ target,
1494
+ exp
1495
+ }, (ctx, n) => {
1496
+ if(this.inuse.apply) ctx.write(true, `$runtime.prefixPush(() => {${n.target} = ${n.exp};});`);
1497
+ else ctx.write(true, `${n.target} = ${n.exp};`);
1498
+ }));
1419
1499
  } else if(n.body.expression.type == 'SequenceExpression') {
1420
1500
  const ex = n.body.expression.expressions;
1421
- const handler = ex[ex.length - 1];
1422
- let callback = source.substring(handler.start, handler.end);
1501
+ const handler = last(ex);
1502
+ let callback = astring.generate(handler);
1423
1503
  if(handler.type == 'ArrowFunctionExpression' || handler.type == 'FunctionExpression') ; else if(detectExpressionType(callback) == 'identifier') {
1424
1504
  callback = `(v) => { ${callback}(v); }`;
1425
1505
  } else {
@@ -1428,13 +1508,33 @@
1428
1508
 
1429
1509
  if(ex.length == 2) {
1430
1510
  assertExpression(ex[0]);
1431
- let exp = source.substring(ex[0].start, ex[0].end);
1432
- if(this.config.immutable) result.watchers.push(`$watch($cd, () => (${exp}), ${callback});`);
1433
- else result.watchers.push(`$watch($cd, () => (${exp}), ${callback}, {cmp: $runtime.$$deepComparator(0)});`);
1511
+ watchers.push(xNode('watch-expression', {
1512
+ $wait: ['apply'],
1513
+ exp: astring.generate(ex[0]),
1514
+ callback
1515
+ }, (ctx, n) => {
1516
+ if(this.inuse.apply) {
1517
+ if(this.config.immutable) ctx.write(true, `$watch(() => (${n.exp}), ${n.callback});`);
1518
+ else ctx.write(true, `$watch(() => (${n.exp}), ${n.callback}, {cmp: $runtime.$$deepComparator(0)});`);
1519
+ } else {
1520
+ ctx.write(true, `(${n.callback})(${n.exp});`);
1521
+ }
1522
+ }));
1434
1523
  } else if(ex.length > 2) {
1435
1524
  for(let i = 0; i < ex.length - 1; i++) assertExpression(ex[i]);
1436
- let exp = source.substring(ex[0].start, ex[ex.length - 2].end);
1437
- result.watchers.push(`$watch($cd, () => [${exp}], ($args) => { (${callback}).apply(null, $args); }, {cmp: $runtime.$$deepComparator(1)});`);
1525
+ let exp = {
1526
+ type: 'ArrayExpression',
1527
+ elements: ex.slice(0, ex.length - 1)
1528
+ };
1529
+
1530
+ watchers.push(xNode('watch-expression', {
1531
+ $wait: ['apply'],
1532
+ exp: astring.generate(exp),
1533
+ callback
1534
+ }, (ctx, n) => {
1535
+ if(this.inuse.apply) ctx.write(true, `$watch(() => ${n.exp}, ($args) => { (${n.callback}).apply(null, $args); }, {cmp: $runtime.$$deepComparator(1)});`);
1536
+ else ctx.write(true, `(${n.callback}).apply(null, ${n.exp})`);
1537
+ }));
1438
1538
  } else throw 'Error';
1439
1539
  } else throw 'Error';
1440
1540
  };
@@ -1501,140 +1601,83 @@
1501
1601
  resultBody.push(n);
1502
1602
  });
1503
1603
 
1504
- this.glob.component.$handler = (ctx, n) => {
1505
- if(this.inuse.$component || n.value) ctx.writeLine('const $component = $runtime.current_component;');
1506
- };
1507
- this.module.head.push(this.glob.component);
1508
-
1509
- let header = [];
1510
- header.push(rawNode(() => {
1511
- if(this.inuse.$events) return 'const $events = $option.events || {};';
1512
- }));
1513
-
1514
1604
  if(lastPropIndex != null) {
1515
- header.push(rawNode(() => {
1516
- if(this.inuse.$props) return 'let $props = $option.props || {};';
1605
+ this.module.head.push(xNode('$props', ctx => {
1606
+ if(this.inuse.$props) ctx.write(true, 'let $props = $option.props || {};');
1517
1607
  }));
1518
1608
 
1519
1609
  if(!constantProps && !this.script.readOnly) this.require('apply');
1520
1610
 
1521
- resultBody.splice(lastPropIndex, 0, rawNode(() => {
1522
- let code = [];
1611
+ this.module.code.push(xNode('ast', { body: resultBody.slice(0, lastPropIndex) }));
1612
+
1613
+ this.module.code.push(xNode('props', {
1614
+ props: this.script.props,
1615
+ constantProps
1616
+ }, (ctx, n) => {
1523
1617
  if(this.inuse.$attributes) {
1524
- let pa = result.props.map(p => {
1618
+ let pa = n.props.map(p => {
1525
1619
  if(p.value === void 0) return `${p.name}`;
1526
1620
  return `${p.name}=${p.value}`;
1527
1621
  }).join(', ');
1528
- code.push(`let {${pa}, ...$attributes} = $props;`);
1622
+ ctx.write(true, `let {${pa}, ...$attributes} = $props;`);
1529
1623
 
1530
- if(!this.script.readOnly && !constantProps) {
1531
- code.push(`$runtime.current_component.push = () => ({${result.props.map(p => p.name + '=' + p.name).join(', ')}, ...$attributes} = $props = $option.props || {});`);
1532
- code.push(`$runtime.current_component.exportedProps = () => ({${result.props.map(p => p.name).join(', ')}});`);
1624
+ if(!this.script.readOnly && !n.constantProps) {
1625
+ ctx.write(true, `$runtime.current_component.push = () => ({${n.props.map(p => p.name + '=' + p.name).join(', ')}, ...$attributes} = $props = $option.props || {});`);
1626
+ ctx.write(true, `$runtime.current_component.exportedProps = () => ({${n.props.map(p => p.name).join(', ')}});`);
1533
1627
  }
1534
1628
  } else if(this.inuse.$props) {
1535
- let pa = result.props.map(p => {
1629
+ let pa = n.props.map(p => {
1536
1630
  if(p.value === void 0) return `${p.name}`;
1537
1631
  return `${p.name}=${p.value}`;
1538
1632
  }).join(', ');
1539
- code.push(`let {${pa}} = $props;`);
1633
+ ctx.write(true, `let {${pa}} = $props;`);
1540
1634
 
1541
- if(!this.script.readOnly && !constantProps) {
1542
- code.push(`$runtime.current_component.push = () => ({${result.props.map(p => p.name + '=' + p.name).join(', ')}} = $props = $option.props || {});`);
1543
- code.push(`$runtime.current_component.exportedProps = () => ({${result.props.map(p => p.name).join(', ')}});`);
1635
+ if(!this.script.readOnly && !n.constantProps) {
1636
+ ctx.write(true, `$runtime.current_component.push = () => ({${n.props.map(p => p.name + '=' + p.name).join(', ')}} = $props = $option.props || {});`);
1637
+ ctx.write(true, `$runtime.current_component.exportedProps = () => ({${n.props.map(p => p.name).join(', ')}});`);
1544
1638
  }
1545
1639
  }
1546
- return code;
1547
1640
  }));
1641
+
1642
+ this.module.code.push(xNode('ast', { body: resultBody.slice(lastPropIndex) }));
1548
1643
  } else {
1549
- header.push(rawNode(() => {
1550
- let code = [];
1644
+ this.module.head.push(xNode('no-props', ctx => {
1551
1645
  if(this.inuse.$props && this.inuse.$attributes) {
1552
- code.push('let $props = $option.props || {}, $attributes = $props;');
1553
- if(!constantProps && !this.script.readOnly) code.push('$runtime.current_component.push = () => $props = $option.props || {}, $attributes = $props;');
1646
+ ctx.write(true, 'let $props = $option.props || {}, $attributes = $props;');
1647
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $props = $attributes = $option.props || {};');
1554
1648
  } else if(this.inuse.$props) {
1555
- code.push('let $props = $option.props || {};');
1556
- if(!constantProps && !this.script.readOnly) code.push('$runtime.current_component.push = () => $props = $option.props || {};');
1649
+ ctx.write(true, 'let $props = $option.props || {};');
1650
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $props = $option.props || {};');
1557
1651
  } else if(this.inuse.$attributes) {
1558
- code.push('let $attributes = $option.props || {};');
1559
- if(!constantProps && !this.script.readOnly) code.push('$runtime.current_component.push = () => $attributes = $option.props || {};');
1652
+ ctx.write(true, 'let $attributes = $option.props || {};');
1653
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $attributes = $option.props || {};');
1560
1654
  }
1561
- return code;
1562
1655
  }));
1563
- }
1564
-
1565
- header.push(rawNode(() => {
1566
- if(this.inuse.$context) return 'const $context = $runtime.$context;';
1567
- }));
1568
-
1569
-
1570
- imports.push(rawNode(() => {
1571
- if(this.inuse.$onMount) return 'import {$onMount} from \'malinajs/runtime.js\';';
1572
- }));
1573
-
1574
- header.push(rawNode(() => {
1575
- if(this.inuse.$onDestroy) return 'const $onDestroy = fn => $component._d.push(fn);';
1576
- }));
1577
1656
 
1578
- if(this.config.autoSubscribe && result.autosubscribeNames.length) {
1579
- if(!this.script.readOnly) this.require('$cd', 'apply');
1580
- header.push(rawNode(() => {
1581
- if(this.inuse.apply) return `$runtime.autoSubscribe(${result.autosubscribeNames.join(', ')});`;
1582
- }));
1583
- }
1584
-
1585
- if(!rootFunctions.$emit) {
1586
- header.push(rawNode(() => {
1587
- if(this.inuse.$emit) return 'const $emit = $runtime.$makeEmitter($option);';
1588
- }));
1589
- }
1590
-
1591
- if(this.scriptNodes[0] && this.scriptNodes[0].attributes.some(a => a.name == 'property')) {
1592
- result.props.forEach(p => {
1593
- this.require('$cd');
1594
- resultBody.push(rawNode(`$runtime.makeExternalProperty($component, '${p.name}', () => ${p.name}, _${p.name} => ${p.name} = _${p.name});`));
1595
- });
1657
+ this.module.code.push(xNode('ast', { body: resultBody }));
1596
1658
  }
1597
1659
 
1598
- this.script.rootLevel = resultBody;
1599
-
1600
1660
  this.module.top.push(xNode('autoimport', (ctx) => {
1601
1661
  Object.values(this.script.autoimport).forEach(l => ctx.writeLine(l));
1602
1662
  }));
1603
1663
 
1604
1664
  this.module.top.push(xNode('ast', { body: imports }));
1605
- this.module.head.push(xNode('ast', { body: header }));
1606
- this.module.code.push(xNode('ast', { body: resultBody }));
1607
- }
1608
-
1609
- function build() {
1610
- const generator = Object.assign({
1611
- ImportExpression: function(node, state) {
1612
- state.write('import(');
1613
- this[node.source.type](node.source, state);
1614
- state.write(')');
1615
- },
1616
- Raw: function(node, state) {
1617
- state.write(node.value);
1618
- }
1619
- }, astring.baseGenerator);
1620
- this.script.code = astring.generate(this.script.ast, { generator });
1621
- }
1665
+ this.module.code.push(watchers);
1622
1666
 
1623
-
1624
- function rawNode(exp, n) {
1625
- n = n || {};
1626
- n.type = 'Raw';
1627
- n.value = exp;
1628
- return n;
1667
+ if(this.scriptNodes[0] && this.scriptNodes[0].attributes.some(a => a.name == 'property') && this.script.props.length && !this.script.readOnly) {
1668
+ this.require('apply');
1669
+ this.module.code.push(xNode('external-property', {
1670
+ props: this.script.props
1671
+ }, (ctx, n) => {
1672
+ n.props.forEach(p => {
1673
+ ctx.write(true, `$runtime.makeExternalProperty('${p.name}', () => ${p.name}, _${p.name} => ${p.name} = _${p.name});`);
1674
+ });
1675
+ }));
1676
+ }
1629
1677
  }
1630
1678
 
1631
1679
 
1632
1680
  const generator = Object.assign({
1633
- ImportExpression: function(node, state) {
1634
- state.write('import(');
1635
- this[node.source.type](node.source, state);
1636
- state.write(')');
1637
- },
1638
1681
  Raw: function(node, state) {
1639
1682
  let value = typeof node.value == 'function' ? node.value() : node.value;
1640
1683
  if(value) {
@@ -1675,27 +1718,78 @@
1675
1718
  };
1676
1719
 
1677
1720
  function buildRuntime() {
1678
- let runtime = xNode('block', { scope: true, $compile: [] });
1721
+ this.module.head.push(xNode('$events', (ctx) => {
1722
+ if(this.inuse.$events) ctx.write(true, 'const $events = $option.events || {};');
1723
+ }));
1679
1724
 
1680
- let rootCD = this.glob.rootCD;
1681
- rootCD.$handler = (ctx, n) => {
1682
- n.$value(!!n.$deps[0].value);
1725
+ this.module.head.push(xNode(this.glob.$component, {
1726
+ $hold: ['componentFn']
1727
+ }, (ctx, n) => {
1683
1728
  if(n.value) {
1684
- ctx.writeLine('let $cd = $component.$cd;');
1685
- this.glob.component.$value(true);
1729
+ this.require('componentFn');
1730
+ ctx.write(true, 'const $component = $runtime.current_component;');
1686
1731
  }
1687
- };
1688
- runtime.push(rootCD);
1689
- this.glob.component.$depends(rootCD);
1732
+ }));
1733
+
1734
+ this.module.head.push(xNode('$context', {
1735
+ $hold: ['componentFn'],
1736
+ }, (ctx) => {
1737
+ if(this.inuse.$context) {
1738
+ this.require('componentFn');
1739
+ ctx.write(true, 'const $context = $runtime.$context;');
1740
+ }
1741
+ }));
1742
+
1743
+ this.module.top.push(xNode(this.glob.$onMount, {
1744
+ $hold: ['componentFn']
1745
+ }, (ctx, n) => {
1746
+ if(n.value) {
1747
+ this.require('componentFn');
1748
+ ctx.write(true, `import { $onMount } from 'malinajs/runtime.js';`);
1749
+ }
1750
+ }));
1751
+
1752
+ this.module.top.push(xNode('$onDestroy', (ctx) => {
1753
+ if(this.inuse.$onDestroy) ctx.write(true, `import { $onDestroy } from 'malinajs/runtime.js';`);
1754
+ }));
1755
+
1756
+ this.module.head.unshift(xNode(this.glob.apply, {
1757
+ $hold: ['componentFn'],
1758
+ $wait: ['rootCD']
1759
+ }, (ctx, n) => {
1760
+ if(n.value || this.inuse.rootCD) {
1761
+ this.require('componentFn');
1762
+ if(n.value == 'readOnly') ctx.writeLine('const $$apply = $runtime.noop;');
1763
+ else ctx.writeLine('const $$apply = $runtime.makeApply();');
1764
+ }
1765
+ }));
1766
+
1767
+ this.module.head.push(xNode('$emit', (ctx) => {
1768
+ if(this.inuse.$emit) ctx.write(true, 'const $emit = $runtime.$makeEmitter($option);');
1769
+ }));
1770
+
1771
+ if(this.config.autoSubscribe && !this.script.readOnly) {
1772
+ this.module.head.push(xNode('autoSubscribe', {
1773
+ $hold: ['apply'],
1774
+ names: this.script.autosubscribeNames
1775
+ }, (ctx, n) => {
1776
+ if(!n.names.length) return;
1777
+ this.require('apply');
1778
+ ctx.write(true, `$runtime.autoSubscribe(${n.names.join(', ')});`);
1779
+ }));
1780
+ }
1781
+
1782
+ let runtime = xNode('block', { scope: true, $compile: [] });
1783
+ this.module.body.push(runtime);
1690
1784
 
1691
1785
  let bb = this.buildBlock(this.DOM, {
1692
1786
  inline: true,
1787
+ protectLastTag: true,
1693
1788
  template: {
1694
1789
  name: '$parentElement',
1695
1790
  cloneNode: true
1696
1791
  }
1697
1792
  });
1698
- bb.requireCD && rootCD.$depends(bb.requireCD);
1699
1793
  runtime.push(bb.template);
1700
1794
  runtime.push(xNode('root-event', (ctx) => {
1701
1795
  if(!this.inuse.rootEvent) return;
@@ -1705,33 +1799,27 @@
1705
1799
 
1706
1800
  if(this.script.onMount) runtime.push('$runtime.$onMount(onMount);');
1707
1801
  if(this.script.onDestroy) runtime.push('$runtime.$onDestroy(onDestroy);');
1708
- if(this.script.watchers.length) {
1709
- this.script.watchers.forEach(n => runtime.push(n));
1710
- }
1711
1802
 
1712
1803
  runtime.push(xNode('addStyle', ctx => {
1713
1804
  if(!this.css.active()) return;
1714
1805
  let style = this.css.getContent();
1715
1806
  if(!style) return;
1716
- let config = ctx._ctx.config;
1717
- if(config.css) {
1718
- if(typeof config.css == 'function') config.css(style, config.path, ctx._ctx, ctx);
1719
- else ctx.writeLine(`$runtime.addStyles('${this.css.id}', \`${this.Q(style)}\`);`);
1807
+ if(this.config.css) {
1808
+ if(typeof this.config.css == 'function') this.config.css(style, this.config.path, this, ctx);
1809
+ else ctx.writeLine(`$runtime.addStyles('${this.css.id}', \`${Q(style)}\`);`);
1720
1810
  } else {
1721
- ctx._ctx.css.result = style;
1811
+ this.css.result = style;
1722
1812
  }
1723
1813
  }));
1724
1814
 
1725
1815
  runtime.push(xNode('bind-component-element', {
1726
- $deps: [this.glob.componentFn]
1816
+ $wait: ['componentFn']
1727
1817
  }, (ctx) => {
1728
- if(this.glob.componentFn.value == 'thin') ctx.writeLine('return {$dom: $parentElement};');
1729
- else ctx.writeLine('return $parentElement;');
1818
+ if(this.inuse.componentFn) ctx.writeLine('return $parentElement;');
1819
+ else ctx.writeLine('return {$dom: $parentElement};');
1730
1820
  }));
1731
1821
 
1732
- this.module.body.push(runtime);
1733
-
1734
- if(!this.script.readOnly && this.css.active() && this.css.containsExternal()) this.require('apply', '$cd');
1822
+ if(!this.script.readOnly && this.css.active() && this.css.containsExternal()) this.require('apply', 'rootCD');
1735
1823
 
1736
1824
  this.module.head.push(xNode('resolveClass', (ctx) => {
1737
1825
  if(!this.inuse.resolveClass) return;
@@ -1758,12 +1846,12 @@
1758
1846
 
1759
1847
 
1760
1848
  function buildBlock(data, option = {}) {
1761
- let rootTemplate = xNode('node', { inline: true, _ctx: this });
1849
+ let rootTemplate = xNode('node', { inline: true });
1762
1850
  let rootSVG = false, requireFragment = option.template?.requireFragment;
1763
1851
  let binds = xNode('block');
1764
1852
  let result = {};
1765
- let requireCD = result.requireCD = xNode('require-cd', false);
1766
1853
  let inuse = Object.assign({}, this.inuse);
1854
+ let lastTagDynamic = false;
1767
1855
 
1768
1856
  if(!option.parentElement) option.parentElement = '$parentElement';
1769
1857
 
@@ -1772,9 +1860,8 @@
1772
1860
  if(option.allowSingleBlock && data.body.length == 1) {
1773
1861
  let n = data.body[0];
1774
1862
  if(n.type == 'node' && n.name.match(/^[A-Z]/)) {
1775
- let component = this.makeComponent(n, requireCD);
1863
+ let component = this.makeComponent(n);
1776
1864
  return {
1777
- requireCD,
1778
1865
  singleBlock: component.bind
1779
1866
  };
1780
1867
  }
@@ -1786,7 +1873,7 @@
1786
1873
  if(n.type == 'comment' && !this.config.preserveComments) return false;
1787
1874
  if(n.type == 'fragment') {
1788
1875
  try {
1789
- let f = this.makeFragment(n, requireCD);
1876
+ let f = this.makeFragment(n);
1790
1877
  f && binds.push(f);
1791
1878
  } catch (e) {
1792
1879
  wrapException(e, n);
@@ -1849,8 +1936,9 @@
1849
1936
  return el;
1850
1937
  };
1851
1938
 
1852
- const bindNode = (n) => {
1939
+ const bindNode = (n, nodeIndex) => {
1853
1940
  if(n.type === 'text') {
1941
+ if(isRoot) lastTagDynamic = false;
1854
1942
  let prev = tpl.getLast();
1855
1943
  if(prev?.$type == 'node:text' && prev._boundName) tpl.push(xNode('node:comment', { label: true }));
1856
1944
 
@@ -1864,17 +1952,15 @@
1864
1952
  } else {
1865
1953
  textNode = tpl.push(' ');
1866
1954
  let bindText = xNode('bindText', {
1867
- $deps: [this.glob.apply],
1955
+ $wait: ['apply'],
1868
1956
  el: textNode.bindName(),
1869
1957
  exp: pe.result
1870
1958
  }, (ctx, n) => {
1871
- if(this.glob.apply.value) {
1872
- requireCD.$value(true);
1873
- ctx.writeLine(`$runtime.bindText($cd, ${n.el}, () => ${n.exp});`);
1959
+ if(this.inuse.apply) {
1960
+ ctx.writeLine(`$runtime.bindText(${n.el}, () => ${n.exp});`);
1874
1961
  } else ctx.writeLine(`${n.el}.textContent = ${n.exp};`);
1875
1962
  });
1876
1963
  binds.push(bindText);
1877
- requireCD.$depends(bindText);
1878
1964
  }
1879
1965
 
1880
1966
  pe.parts.forEach(p => {
@@ -1893,6 +1979,7 @@
1893
1979
  lastStatic = tpl.push(n.value);
1894
1980
  }
1895
1981
  } else if(n.type === 'template') {
1982
+ if(isRoot) lastTagDynamic = false;
1896
1983
  lastStatic = null;
1897
1984
  tpl.push(n.openTag);
1898
1985
  tpl.push(n.content);
@@ -1900,11 +1987,12 @@
1900
1987
  } else if(n.type === 'node') {
1901
1988
  if(n.name == 'malina' && !option.malinaElement) {
1902
1989
  let b;
1903
- if(n.elArg == 'portal') b = this.attachPortal(n, requireCD);
1904
- else b = this.attachHead(n, requireCD);
1990
+ if(n.elArg == 'portal') b = this.attachPortal(n);
1991
+ else b = this.attachHead(n);
1905
1992
  b && binds.push(b);
1906
1993
  return;
1907
1994
  }
1995
+ if(isRoot) lastTagDynamic = false;
1908
1996
  if(n.name == 'component' || n.name.match(/^[A-Z]/)) {
1909
1997
  if(n.name == 'component' || !n.elArg) {
1910
1998
  // component
@@ -1913,61 +2001,59 @@
1913
2001
 
1914
2002
  if(n.name == 'component') {
1915
2003
  // dyn-component
1916
- binds.push(this.makeComponentDyn(n, requireCD, el));
2004
+ binds.push(this.makeComponentDyn(n, el));
1917
2005
  } else {
1918
- let component = this.makeComponent(n, requireCD);
1919
- binds.push(xNode('attach-component', {
2006
+ let component = this.makeComponent(n);
2007
+ binds.push(xNode('insert-component', {
1920
2008
  component: component.bind,
1921
2009
  el: el.bindName()
1922
2010
  }, (ctx, n) => {
1923
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, `);
2011
+ ctx.write(true, `$runtime.insertAfter(${n.el}, `);
1924
2012
  ctx.add(n.component);
1925
- ctx.write(')');
2013
+ ctx.write('.$dom);');
1926
2014
  }));
1927
2015
  }
1928
2016
  } else {
2017
+ if(isRoot) requireFragment = true;
1929
2018
  let el = placeLabel(`exported ${n.elArg}`);
1930
- let b = this.attchExportedFragment(n, el, n.name, requireCD);
2019
+ let b = this.attchExportedFragment(n, el, n.name);
1931
2020
  b && binds.push(b);
1932
2021
  }
1933
2022
  return;
1934
2023
  }
1935
2024
  if(n.name == 'slot') {
2025
+ if(isRoot) requireFragment = true;
1936
2026
  let slotName = n.elArg;
1937
2027
  if(!slotName) {
1938
2028
  if(option.context == 'fragment') {
1939
2029
  let el = placeLabel('fragment-slot');
1940
- binds.push(this.attachFragmentSlot(el, requireCD));
2030
+ binds.push(this.attachFragmentSlot(el));
1941
2031
  return;
1942
2032
  } else slotName = 'default';
1943
2033
  }
1944
2034
 
1945
2035
  let el = placeLabel(slotName);
1946
- let slot = this.attachSlot(slotName, n, requireCD);
2036
+ let slot = this.attachSlot(slotName, n);
1947
2037
 
1948
2038
  binds.push(xNode('attach-slot', {
1949
- $deps: [requireCD],
1950
2039
  $compile: [slot],
1951
2040
  el: el.bindName(),
1952
- slot,
1953
- requireCD
2041
+ slot
1954
2042
  }, (ctx, n) => {
1955
- if(n.requireCD.value) ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, `);
1956
- else ctx.write(true, `$runtime.attachBlock($component, ${n.el}, `);
2043
+ ctx.write(true, `$runtime.attachBlock(${n.el}, `);
1957
2044
  ctx.add(n.slot);
1958
2045
  ctx.write(');', true);
1959
2046
  }));
1960
2047
  return;
1961
2048
  }
1962
2049
  if(n.name == 'fragment') {
1963
- requireCD.$value(true);
1964
2050
  assert(n.elArg, 'Fragment name is required');
1965
2051
  let el = placeLabel(`fragment ${n.elArg}`);
1966
2052
  binds.push(xNode('attach-fragment', {
1967
2053
  el: el.bindName(),
1968
2054
  fragment: this.attachFragment(n)
1969
2055
  }, (ctx, n) => {
1970
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, `);
2056
+ ctx.write(true, `$runtime.attachBlock(${n.el}, `);
1971
2057
  ctx.add(n.fragment);
1972
2058
  ctx.write(')');
1973
2059
  }));
@@ -1980,18 +2066,18 @@
1980
2066
  lastStatic = el;
1981
2067
 
1982
2068
  if(n.attributes.some(a => a.name.startsWith('{...'))) {
2069
+ this.require('rootCD');
1983
2070
  n.spreading = [];
1984
- requireCD.$value(true);
1985
2071
  binds.push(xNode('spread-to-element', {
1986
2072
  el: el.bindName(),
1987
2073
  props: n.spreading
1988
2074
  }, (ctx, n) => {
1989
- ctx.writeLine(`$runtime.spreadAttributes($cd, ${n.el}, () => ({${n.props.join(', ')}}));`);
2075
+ ctx.writeLine(`$runtime.spreadAttributes(${n.el}, () => ({${n.props.join(', ')}}));`);
1990
2076
  }));
1991
2077
  }
1992
2078
  let bindTail = [];
1993
2079
  n.attributes.forEach(p => {
1994
- let b = this.bindProp(p, n, el, requireCD);
2080
+ let b = this.bindProp(p, n, el);
1995
2081
  if(b) {
1996
2082
  if(b.bind) binds.push(b.bind);
1997
2083
  if(b.bindTail) bindTail.push(b.bindTail);
@@ -2004,7 +2090,7 @@
2004
2090
  binds.push(xNode('bindAttributes', { el }, (ctx, n) => {
2005
2091
  let elName = n.el.bindName();
2006
2092
  n.el.attributes.forEach(a => {
2007
- ctx.writeLine(`${elName}.setAttribute('${a.name}', \`${this.Q(a.value)}\`);`);
2093
+ ctx.writeLine(`${elName}.setAttribute('${a.name}', \`${Q(a.value)}\`);`);
2008
2094
  });
2009
2095
  }));
2010
2096
  binds.push(xNode('bindClasses', { el }, (ctx, n) => {
@@ -2023,7 +2109,6 @@
2023
2109
  go(n, false, el);
2024
2110
  }
2025
2111
  } else if(n.type === 'each') {
2026
- requireCD.$value(true);
2027
2112
  if(data.type == 'node' && data.body.length == 1) {
2028
2113
  lastStatic = null;
2029
2114
  let eachBlock = this.makeEachBlock(n, {
@@ -2033,15 +2118,22 @@
2033
2118
  binds.push(eachBlock.source);
2034
2119
  return;
2035
2120
  } else {
2036
- if(isRoot) requireFragment = true;
2121
+ if(isRoot) {
2122
+ requireFragment = true;
2123
+ lastTagDynamic = true;
2124
+ }
2037
2125
  let element = placeLabel(n.value);
2038
2126
  let eachBlock = this.makeEachBlock(n, { elName: element.bindName() });
2039
2127
  binds.push(eachBlock.source);
2040
2128
  return;
2041
2129
  }
2042
2130
  } else if(n.type === 'if') {
2043
- if(isRoot) requireFragment = true;
2044
- binds.push(this.makeifBlock(n, placeLabel(n.value), requireCD));
2131
+ if(isRoot) {
2132
+ requireFragment = true;
2133
+ lastTagDynamic = true;
2134
+ }
2135
+ if(nodeIndex == 0 && !isRoot) binds.push(this.makeifBlock(n, tpl, true));
2136
+ else binds.push(this.makeifBlock(n, placeLabel(n.value)));
2045
2137
  return;
2046
2138
  } else if(n.type === 'systag') {
2047
2139
  let r = n.value.match(/^@(\w+)\s+(.*)$/s);
@@ -2049,41 +2141,43 @@
2049
2141
  let exp = r[2];
2050
2142
 
2051
2143
  if(name == 'html') {
2052
- if(isRoot) requireFragment = true;
2144
+ if(isRoot) {
2145
+ requireFragment = true;
2146
+ lastTagDynamic = true;
2147
+ }
2053
2148
  let el = placeLabel('html');
2054
- binds.push(this.makeHtmlBlock(exp, el, requireCD));
2149
+ binds.push(this.makeHtmlBlock(exp, el));
2055
2150
  return;
2056
2151
  } else throw 'Wrong tag';
2057
2152
  } else if(n.type === 'await') {
2058
- if(isRoot) requireFragment = true;
2059
- requireCD.$value(true);
2153
+ if(isRoot) {
2154
+ requireFragment = true;
2155
+ lastTagDynamic = true;
2156
+ }
2060
2157
  let el = placeLabel(n.value);
2061
2158
  let r = this.makeAwaitBlock(n, el);
2062
2159
  r && binds.push(r);
2063
2160
  return;
2064
2161
  } else if(n.type === 'comment') {
2162
+ if(isRoot) lastTagDynamic = false;
2065
2163
  lastStatic = tpl.push(n.content);
2066
2164
  }
2067
2165
  };
2068
- body.forEach(node => {
2166
+ body.forEach((node, i) => {
2069
2167
  try {
2070
- bindNode(node);
2168
+ bindNode(node, i);
2071
2169
  } catch (e) {
2072
2170
  wrapException(e, node);
2073
2171
  }
2074
2172
  });
2075
2173
  };
2076
2174
  go(data, true, rootTemplate);
2077
- if(option.protectLastTag) {
2078
- let l = rootTemplate.getLast();
2079
- if(l?.label) {
2080
- rootTemplate.push(xNode('node:comment', { value: '' }));
2081
- }
2175
+ if(option.protectLastTag && lastTagDynamic) {
2176
+ rootTemplate.push(xNode('node:comment', { value: '' }));
2082
2177
  }
2083
2178
 
2084
2179
  let innerBlock = null;
2085
2180
  if(binds.body.length) {
2086
- binds.push(requireCD);
2087
2181
  innerBlock = xNode('block');
2088
2182
  if(!option.oneElement) {
2089
2183
  innerBlock.push(xNode('bindNodes', {
@@ -2120,7 +2214,6 @@
2120
2214
  result.source = innerBlock;
2121
2215
  }
2122
2216
  } else {
2123
- result.requireCD.$done = true;
2124
2217
  result.name = '$runtime.noop';
2125
2218
  result.source = null;
2126
2219
  }
@@ -2135,30 +2228,26 @@
2135
2228
  else template.inline = true;
2136
2229
 
2137
2230
  result.block = xNode('block', {
2138
- $compile: [innerBlock, requireCD],
2139
- $deps: [requireCD],
2140
- requireCD,
2231
+ $compile: [innerBlock],
2141
2232
  innerBlock,
2142
2233
  tpl: template,
2143
2234
  each: option.each,
2144
2235
  parentElement: option.parentElement
2145
2236
  }, (ctx, n) => {
2146
2237
  if(n.each && !ctx.isEmpty(n.innerBlock)) {
2147
- if(n.requireCD.value) ctx.write('$runtime.makeEachBlock(');
2148
- else ctx.write('$runtime.makeStaticEachBlock(');
2238
+ ctx.write('$runtime.makeEachBlock(');
2149
2239
  } else {
2150
- if(n.requireCD.value) ctx.write('$runtime.makeBlock(');
2151
- else ctx.write('$runtime.makeStaticBlock(');
2240
+ ctx.write('$runtime.makeBlock(');
2152
2241
  }
2153
2242
  ctx.add(n.tpl);
2154
2243
  if(!ctx.isEmpty(n.innerBlock)) {
2155
2244
  if(n.each) {
2156
- if(n.requireCD.value) ctx.write(`, ($cd, ${n.parentElement}, ${n.each.itemName}, ${n.each.indexName}) => {`, true);
2157
- else ctx.write(`, (${n.parentElement}, ${n.each.itemName}, ${n.each.indexName}) => {`, true);
2245
+ ctx.write(`, (${n.parentElement}, ${n.each.itemName}`);
2246
+ if(n.each.indexName) ctx.write(`, ${n.each.indexName}`);
2247
+ ctx.write(`) => {`, true);
2158
2248
  } else {
2159
2249
  let extra = option.extraArguments ? ', ' + option.extraArguments.join(', ') : '';
2160
- if(n.requireCD.value) ctx.write(`, ($cd, ${n.parentElement}${extra}) => {`, true);
2161
- else ctx.write(`, (${n.parentElement}${extra}) => {`, true);
2250
+ ctx.write(`, (${n.parentElement}${extra}) => {`, true);
2162
2251
  }
2163
2252
  ctx.indent++;
2164
2253
  ctx.add(n.innerBlock);
@@ -4427,13 +4516,12 @@
4427
4516
  return result;
4428
4517
  };
4429
4518
 
4430
- function makeComponent(node, requireCD) {
4519
+ function makeComponent(node) {
4431
4520
  this.require('apply');
4432
4521
 
4433
4522
  let propList = node.attributes;
4434
4523
 
4435
4524
  this.require('$context');
4436
- requireCD.$value(true); // FIX
4437
4525
 
4438
4526
  let reference = null;
4439
4527
  let propsFn = [], propsSetter = [], $class = [], staticProps = true;
@@ -4510,12 +4598,11 @@
4510
4598
  }
4511
4599
 
4512
4600
  if(props) this.require('apply');
4513
- requireCD.$value(true); // FIXME
4514
4601
 
4515
4602
  let block = this.buildBlock(slot, { inline: true });
4516
4603
 
4517
4604
  slotBlocks.push(xNode('slot', {
4518
- $deps: [this.glob.apply],
4605
+ $wait: ['apply'],
4519
4606
  name: slot.name,
4520
4607
  template: block.template,
4521
4608
  bind: block.source,
@@ -4523,20 +4610,20 @@
4523
4610
  props
4524
4611
  }, (ctx, n) => {
4525
4612
  if(n.bind) {
4526
- ctx.write(true, `${n.name}: $runtime.makeSlot($cd, `);
4613
+ ctx.write(true, `${n.name}: $runtime.makeSlot(`);
4527
4614
  ctx.add(n.template);
4528
- ctx.write(`, ($cd, $parentElement, $context, $instance_${n.componentName}`);
4615
+ ctx.write(`, ($parentElement, $context, $instance_${n.componentName}`);
4529
4616
  if(n.props) ctx.write(', $localProps');
4530
4617
  ctx.write(') => {', true);
4531
4618
  ctx.indent++;
4532
4619
  if(n.props) ctx.write(true, `let {${n.props.join(', ')}} = $localProps;`);
4533
4620
  ctx.add(n.bind);
4534
4621
 
4535
- if(n.props && this.glob.apply.value) ctx.write(true, `return ($localProps) => ({${n.props.join(', ')}} = $localProps, $$apply());`);
4622
+ if(n.props && this.inuse.apply) ctx.write(true, `return ($localProps) => ({${n.props.join(', ')}} = $localProps, $$apply());`);
4536
4623
  ctx.indent--;
4537
4624
  ctx.writeLine('})');
4538
4625
  } else {
4539
- ctx.write(true, `${n.name}: $runtime.makeStaticBlock(`);
4626
+ ctx.write(true, `${n.name}: $runtime.makeBlock(`);
4540
4627
  ctx.add(n.template);
4541
4628
  ctx.write(')');
4542
4629
  }
@@ -4551,18 +4638,14 @@
4551
4638
 
4552
4639
  anchorBlocks.push(xNode('anchor', {
4553
4640
  $compile: [block],
4554
- $deps: [bb.requireCD],
4555
4641
  name,
4556
4642
  block
4557
4643
  }, (ctx, n) => {
4558
- let useCD = n.$deps[0].value;
4559
- if(useCD) ctx.write(`${n.name}: {$: ($cd, el) => {`);
4560
- else ctx.write(`${n.name}: (el) => {`);
4644
+ ctx.write(`${n.name}: $runtime.makeAnchor((el) => {`);
4561
4645
  ctx.indent++;
4562
4646
  ctx.build(n.block);
4563
4647
  ctx.indent--;
4564
- if(useCD) ctx.write(true, '}}');
4565
- else ctx.write(true, '}');
4648
+ ctx.write(true, '})');
4566
4649
  }));
4567
4650
  });
4568
4651
  }
@@ -4780,7 +4863,7 @@
4780
4863
  return { bind: result };
4781
4864
  }
4782
4865
 
4783
- function makeComponentDyn(node, requireCD, element) {
4866
+ function makeComponentDyn(node, element) {
4784
4867
  let dynamicComponent;
4785
4868
 
4786
4869
  if(node.elArg) {
@@ -4796,9 +4879,8 @@
4796
4879
 
4797
4880
  assert(dynamicComponent);
4798
4881
  this.detectDependency(dynamicComponent);
4799
- requireCD.$value(true);
4800
4882
 
4801
- let component = this.makeComponent(node, requireCD).bind;
4883
+ let component = this.makeComponent(node).bind;
4802
4884
 
4803
4885
  component.componentName = '$ComponentConstructor';
4804
4886
  return xNode('dyn-component', {
@@ -4806,13 +4888,13 @@
4806
4888
  exp: dynamicComponent,
4807
4889
  component
4808
4890
  }, (ctx, n) => {
4809
- ctx.write(true, `$runtime.attachDynComponent($cd, ${n.el}, () => ${n.exp}, ($ComponentConstructor) => `);
4891
+ ctx.write(true, `$runtime.attachDynComponent(${n.el}, () => ${n.exp}, ($ComponentConstructor) => `);
4810
4892
  ctx.add(n.component);
4811
4893
  ctx.write(')');
4812
4894
  });
4813
4895
  }
4814
4896
 
4815
- function bindProp(prop, node, element, requireCD) {
4897
+ function bindProp(prop, node, element) {
4816
4898
  let name, arg;
4817
4899
 
4818
4900
  if(prop.content.startsWith('{*')) {
@@ -4876,13 +4958,17 @@
4876
4958
 
4877
4959
  if(name[0] == '#') {
4878
4960
  let target = name.substring(1);
4879
- assert(isSimpleName(target), target);
4880
- this.checkRootName(target);
4881
- return { bind: `${target}=${element.bindName()};` };
4961
+ assert(detectExpressionType(target) == 'identifier', name);
4962
+ return { bind: xNode('reference-to-element', {
4963
+ target,
4964
+ el: element.bindName()
4965
+ }, (ctx, n) => {
4966
+ ctx.write(true, `${n.target} = ${n.el};`);
4967
+ ctx.write(true, `$runtime.$onDestroy(() => ${n.target} = null);`);
4968
+ })};
4882
4969
  } else if(name == 'event') {
4883
4970
  if(prop.name.startsWith('@@')) {
4884
4971
  assert(!prop.value);
4885
- requireCD.$value(true);
4886
4972
  this.require('$events');
4887
4973
  if(prop.name == '@@') {
4888
4974
  return {
@@ -4891,7 +4977,7 @@
4891
4977
  }, (ctx, data) => {
4892
4978
  ctx.writeLine('for(let event in $events)');
4893
4979
  ctx.goIndent(() => {
4894
- ctx.writeLine(`$runtime.addEvent($cd, ${data.el}, event, $events[event]);`);
4980
+ ctx.writeLine(`$runtime.addEvent(${data.el}, event, $events[event]);`);
4895
4981
  });
4896
4982
  })
4897
4983
  };
@@ -4902,14 +4988,13 @@
4902
4988
  event: prop.name.substring(2),
4903
4989
  el: element.bindName()
4904
4990
  }, (ctx, n) => {
4905
- ctx.writeLine(`$events.${n.event} && $runtime.addEvent($cd, ${n.el}, '${n.event}', $events.${n.event});`);
4991
+ ctx.writeLine(`$events.${n.event} && $runtime.addEvent(${n.el}, '${n.event}', $events.${n.event});`);
4906
4992
  })
4907
4993
  };
4908
4994
  }
4909
4995
 
4910
4996
  let { event, fn, rootModifier } = this.makeEventProp(prop, () => element.bindName());
4911
4997
  if(rootModifier) this.require('rootEvent');
4912
- else requireCD.$value(true);
4913
4998
 
4914
4999
  return {
4915
5000
  bind: xNode('bindEvent', {
@@ -4919,7 +5004,7 @@
4919
5004
  rootModifier
4920
5005
  }, (ctx, n) => {
4921
5006
  if(n.rootModifier) ctx.write(true, `$$addRootEvent(${n.el}, '${n.event}', `);
4922
- else ctx.write(true, `$runtime.addEvent($cd, ${n.el}, '${n.event}', `);
5007
+ else ctx.write(true, `$runtime.addEvent(${n.el}, '${n.event}', `);
4923
5008
  ctx.build(n.fn);
4924
5009
  ctx.write(');');
4925
5010
  })
@@ -4930,7 +5015,6 @@
4930
5015
  return;
4931
5016
  }
4932
5017
 
4933
- requireCD.$value(true);
4934
5018
  this.require('apply');
4935
5019
  let exp;
4936
5020
  arg = arg.split(/[:|]/);
@@ -4964,7 +5048,7 @@
4964
5048
  bind: xNode('bindInput', {
4965
5049
  el: element.bindName()
4966
5050
  }, (ctx, n) => {
4967
- ctx.writeLine(`$runtime.bindInput($cd, ${n.el}, '${attr}', () => ${exp}, ${argName} => {${exp} = ${argName}; $$apply();});`);
5051
+ ctx.writeLine(`$runtime.bindInput(${n.el}, '${attr}', () => ${exp}, ${argName} => {${exp} = ${argName}; $$apply();});`);
4968
5052
  })
4969
5053
  };
4970
5054
  } else if(name == 'style' && arg) {
@@ -4986,7 +5070,7 @@
4986
5070
  name: styleName,
4987
5071
  value: prop.value
4988
5072
  }, (ctx, n) => {
4989
- ctx.writeLine(`${n.el}.style.${n.name} = \`${this.Q(n.value)}\`;`);
5073
+ ctx.writeLine(`${n.el}.style.${n.name} = \`${Q(n.value)}\`;`);
4990
5074
  })
4991
5075
  };
4992
5076
  }
@@ -5007,7 +5091,7 @@
5007
5091
  }, (ctx, n) => {
5008
5092
  if(n.hasElement) ctx.writeLine(`let $element=${n.el};`);
5009
5093
  if(ctx.inuse.apply) {
5010
- ctx.writeLine(`$runtime.bindStyle($cd, ${n.el}, '${n.styleName}', () => (${n.exp}));`);
5094
+ ctx.writeLine(`$runtime.bindStyle(${n.el}, '${n.styleName}', () => (${n.exp}));`);
5011
5095
  } else {
5012
5096
  ctx.writeLine(`${n.el}.style.${n.styleName} = ${n.exp};`);
5013
5097
  }
@@ -5016,21 +5100,21 @@
5016
5100
  };
5017
5101
  } else if(name == 'use') {
5018
5102
  if(arg) {
5019
- requireCD.$value(true);
5020
5103
  assert(isSimpleName(arg), 'Wrong name: ' + arg);
5021
5104
  this.checkRootName(arg);
5022
5105
  let args = prop.value ? `, () => [${getExpression()}]` : '';
5023
5106
  this.detectDependency(args);
5024
5107
  return {
5025
5108
  bind: xNode('action', {
5109
+ $wait: ['apply'],
5026
5110
  name: arg,
5027
5111
  args,
5028
5112
  el: element.bindName()
5029
5113
  }, (ctx, n) => {
5030
5114
  if(ctx.inuse.apply && n.args) {
5031
- ctx.writeLine(`$runtime.bindAction($cd, ${n.el}, ${n.name}${n.args}, $runtime.__bindActionSubscribe);`);
5115
+ ctx.writeLine(`$runtime.bindAction(${n.el}, ${n.name}${n.args}, $runtime.__bindActionSubscribe);`);
5032
5116
  } else {
5033
- ctx.writeLine(`$runtime.bindAction($cd, ${n.el}, ${n.name}${n.args});`);
5117
+ ctx.writeLine(`$runtime.bindAction(${n.el}, ${n.name}${n.args});`);
5034
5118
  }
5035
5119
  })
5036
5120
  };
@@ -5075,10 +5159,13 @@
5075
5159
  classes = [prop.name.slice(6)];
5076
5160
  }
5077
5161
  return this.config.passClass && classes.some(name => {
5078
- if(this.css.isExternalClass(name)) compound = true;
5079
- else if(name[0] == '$') {
5162
+ if(this.css.isExternalClass(name)) {
5163
+ compound = true;
5164
+ this.require('apply');
5165
+ } else if(name[0] == '$') {
5080
5166
  this.css.markAsExternal(name.substring(1));
5081
5167
  compound = true;
5168
+ this.require('apply');
5082
5169
  }
5083
5170
  });
5084
5171
  });
@@ -5095,14 +5182,14 @@
5095
5182
  assert(className);
5096
5183
  let exp = prop.value ? unwrapExp(prop.value) : className;
5097
5184
  this.detectDependency(exp);
5098
- return `(${exp}) ? \`${this.Q(className)}\` : ''`;
5185
+ return `(${exp}) ? \`${Q(className)}\` : ''`;
5099
5186
  }
5100
5187
  }).join(') + \' \' + (');
5101
5188
  const bind = xNode('compound-class', {
5189
+ $wait: ['apply'],
5102
5190
  el: element.bindName(),
5103
5191
  exp,
5104
- classes,
5105
- requireCD
5192
+ classes
5106
5193
  }, (ctx, n) => {
5107
5194
  let base = '';
5108
5195
  if(n.classes.length) {
@@ -5120,21 +5207,18 @@
5120
5207
 
5121
5208
  if(ctx.inuse.resolveClass) {
5122
5209
  if(ctx.inuse.apply) {
5123
- n.requireCD.$value(true);
5124
- ctx.write(true, `$runtime.bindClassExp($cd, ${n.el}, () => $$resolveClass((${n.exp})${base}))`);
5210
+ ctx.write(true, `$runtime.bindClassExp(${n.el}, () => $$resolveClass((${n.exp})${base}))`);
5125
5211
  } else {
5126
5212
  ctx.write(true, `$runtime.setClassToElement(${n.el}, $$resolveClass((${n.exp})${base}));`);
5127
5213
  }
5128
5214
  } else {
5129
5215
  if(ctx.inuse.apply) {
5130
- n.requireCD.$value(true);
5131
- ctx.write(true, `$runtime.bindClassExp($cd, ${n.el}, () => (${n.exp})${base})`);
5216
+ ctx.write(true, `$runtime.bindClassExp(${n.el}, () => (${n.exp})${base})`);
5132
5217
  } else {
5133
5218
  ctx.write(true, `$runtime.setClassToElement(${n.el}, ${n.exp}${base});`);
5134
5219
  }
5135
5220
  }
5136
5221
  });
5137
- requireCD.$depends(bind);
5138
5222
  return { bind };
5139
5223
  } else {
5140
5224
  let bind = xNode('block');
@@ -5150,21 +5234,19 @@
5150
5234
  this.detectDependency(exp);
5151
5235
 
5152
5236
  let n = xNode('bindClass', {
5153
- $deps: [this.glob.apply],
5237
+ $wait: ['apply'],
5154
5238
  el: element.bindName(),
5155
5239
  className,
5156
5240
  exp,
5157
- $element: exp.includes('$element'),
5158
- requireCD
5241
+ $element: exp.includes('$element')
5159
5242
  }, (ctx, n) => {
5160
5243
  if(n.$element) {
5161
5244
  ctx.writeLine('{');
5162
5245
  ctx.indent++;
5163
5246
  ctx.writeLine(`let $element = ${n.el};`);
5164
5247
  }
5165
- if(this.glob.apply.value) {
5166
- n.requireCD.$value(true);
5167
- ctx.writeLine(`$runtime.bindClass($cd, ${n.el}, () => !!(${n.exp}), '${n.className}');`);
5248
+ if(this.inuse.apply) {
5249
+ ctx.writeLine(`$runtime.bindClass(${n.el}, () => !!(${n.exp}), '${n.className}');`);
5168
5250
  } else {
5169
5251
  ctx.writeLine(`(${n.exp}) && $runtime.addClass(${n.el}, '${n.className}');`);
5170
5252
  }
@@ -5173,20 +5255,18 @@
5173
5255
  ctx.writeLine('}');
5174
5256
  }
5175
5257
  });
5176
- requireCD.$depends(n);
5177
5258
  bind.push(n);
5178
5259
  }
5179
5260
  });
5180
5261
  return { bind: bind.body.length ? bind : null };
5181
5262
  }
5182
5263
  } else if(name[0] == '^') {
5183
- requireCD.$value(true);
5184
5264
  return {
5185
5265
  bindTail: xNode('bindAnchor', {
5186
5266
  name: name.slice(1) || 'default',
5187
5267
  el: element.bindName()
5188
5268
  }, (ctx, n) => {
5189
- ctx.write(true, `$runtime.attachAnchor($option, $cd, ${n.el}`);
5269
+ ctx.write(true, `$runtime.attachAnchor($option, ${n.el}`);
5190
5270
  if(n.name == 'default') ctx.write(');');
5191
5271
  else ctx.write(`, '${n.name}');`);
5192
5272
  })
@@ -5213,31 +5293,28 @@
5213
5293
  };
5214
5294
 
5215
5295
  let n = xNode('bindAttribute', {
5296
+ $wait: ['apply'],
5216
5297
  name,
5217
5298
  exp,
5218
5299
  hasElement,
5219
- el: element.bindName(),
5220
- requireCD
5300
+ el: element.bindName()
5221
5301
  }, (ctx, data) => {
5222
5302
  if(data.hasElement) ctx.writeLine(`let $element=${data.el};`);
5223
5303
  if(propList[name]) {
5224
5304
  let propName = propList[name] === true ? name : propList[name];
5225
5305
  if(ctx.inuse.apply) {
5226
- requireCD.$value(true);
5227
- ctx.writeLine(`$watchReadOnly($cd, () => (${data.exp}), (value) => {${data.el}.${propName} = value;});`);
5306
+ ctx.writeLine(`$watch(() => (${data.exp}), (value) => {${data.el}.${propName} = value;});`);
5228
5307
  } else {
5229
5308
  ctx.writeLine(`${data.el}.${propName} = ${data.exp};`);
5230
5309
  }
5231
5310
  } else {
5232
5311
  if(ctx.inuse.apply) {
5233
- requireCD.$value(true);
5234
- ctx.writeLine(`$runtime.bindAttribute($cd, ${data.el}, '${data.name}', () => (${data.exp}));`);
5312
+ ctx.writeLine(`$runtime.bindAttribute(${data.el}, '${data.name}', () => (${data.exp}));`);
5235
5313
  } else {
5236
5314
  ctx.writeLine(`$runtime.bindAttributeBase(${data.el}, '${data.name}', ${data.exp});`);
5237
5315
  }
5238
5316
  }
5239
5317
  });
5240
- requireCD.$depends(n);
5241
5318
 
5242
5319
  return {
5243
5320
  bind: xNode('block', {
@@ -5247,7 +5324,7 @@
5247
5324
  };
5248
5325
  }
5249
5326
 
5250
- if(node.spreading) return node.spreading.push(`${name}: \`${this.Q(prop.value)}\``);
5327
+ if(node.spreading) return node.spreading.push(`${name}: \`${Q(prop.value)}\``);
5251
5328
 
5252
5329
  element.attributes.push({
5253
5330
  name: prop.name,
@@ -5256,12 +5333,11 @@
5256
5333
  }
5257
5334
  }
5258
5335
 
5259
- function makeifBlock(data, element, requireCD) {
5336
+ function makeifBlock(data, element, parentElement) {
5260
5337
  let r = data.value.match(/^#if (.*)$/s);
5261
5338
  let exp = r[1];
5262
5339
  assert(exp, 'Wrong binding: ' + data.value);
5263
5340
  this.detectDependency(exp);
5264
- this.require('$cd');
5265
5341
 
5266
5342
  let mainBlock, elseBlock;
5267
5343
 
@@ -5284,20 +5360,19 @@
5284
5360
  mainBlock = getBlock(this.buildBlock(data, { protectLastTag: true, allowSingleBlock: true }));
5285
5361
  }
5286
5362
 
5287
- const result = xNode('if:bind', {
5288
- $deps: [this.glob.apply],
5289
- requireCD,
5363
+ return xNode('if:bind', {
5364
+ $wait: ['apply'],
5290
5365
  el: element.bindName(),
5366
+ parentElement,
5291
5367
  exp,
5292
5368
  mainBlock: mainBlock,
5293
5369
  elseBlock: elseBlock
5294
5370
  }, (ctx, n) => {
5295
- if(this.glob.apply.value) {
5296
- n.requireCD.$value(true);
5297
- ctx.write(true, `$runtime.ifBlock($cd, ${n.el}, () => !!(${n.exp}),`);
5371
+ let missing = '';
5372
+ if(this.inuse.apply) {
5373
+ ctx.write(true, `$runtime.ifBlock(${n.el}, () => !!(${n.exp}),`);
5298
5374
  } else {
5299
- this.glob.component.$value(true);
5300
- ctx.write(true, `$runtime.ifBlockReadOnly($component, ${n.el}, () => !!(${n.exp}),`);
5375
+ ctx.write(true, `$runtime.ifBlockReadOnly(${n.el}, () => !!(${n.exp}),`);
5301
5376
  }
5302
5377
 
5303
5378
  ctx.indent++;
@@ -5306,24 +5381,23 @@
5306
5381
  if(n.elseBlock) {
5307
5382
  ctx.write(',');
5308
5383
  ctx.add(n.elseBlock);
5309
- }
5384
+ } else missing = ', null';
5310
5385
  ctx.indent--;
5311
- ctx.write(true, ');', true);
5386
+ ctx.write(true);
5387
+ if(n.parentElement) ctx.write(missing + ', true');
5388
+ ctx.write(');', true);
5312
5389
  });
5313
- requireCD.$depends(result);
5314
- this.glob.component.$depends(result);
5315
- return result;
5316
5390
  }
5317
5391
 
5318
5392
  function makeEachBlock(data, option) {
5319
- this.require('apply');
5393
+ this.require('rootCD');
5320
5394
 
5321
5395
  // #each items as item, index (key)
5322
5396
  let rx = data.value.match(/^#each\s+(.+)\s+as\s+(.+)$/s);
5323
5397
  assert(rx, `Wrong #each expression '${data.value}'`);
5324
5398
  let arrayName = rx[1];
5325
5399
  let right = rx[2];
5326
- let keyName;
5400
+ let keyName, keyFunction = null;
5327
5401
 
5328
5402
  // get keyName
5329
5403
  rx = right.match(/^(.*)\s*\(\s*([^()]+)\s*\)\s*$/s);
@@ -5333,73 +5407,105 @@
5333
5407
  }
5334
5408
  right = right.trim();
5335
5409
 
5336
- let itemName, indexName, blockPrefix = null;
5337
- if(right[0] == '{') {
5338
- rx = right.match(/^(\{[^}]+\})(.*)$/s);
5339
- assert(rx, `Wrong #each expression '${data.value}'`);
5340
- let exp = rx[1], keywords;
5410
+ const makeKeyFunction = (keyLink) => {
5411
+ const e = parseJS(keyName).transform((n, pk) => {
5412
+ if(n.type != 'Identifier') return;
5413
+ if(pk == 'property') return;
5414
+ let r = keyLink[n.name];
5415
+ if(r) n.name = r;
5416
+ });
5417
+ let exp = e.build(e.ast.body[0].expression);
5418
+ keyFunction = xNode('key-function', {
5419
+ exp
5420
+ }, (ctx, n) => {
5421
+ ctx.write(`($$item, $index) => ${n.exp}`);
5422
+ });
5423
+ };
5341
5424
 
5425
+ let itemName, indexName = null, blockPrefix = null;
5426
+ if(right[0] == '{' || right[0] == '[') {
5427
+ let keywords, unwrap;
5342
5428
  try {
5343
- keywords = acorn.parse(`(${exp} = $$item)`, { sourceType: 'module', ecmaVersion: 12 }).body[0].expression.left.properties.map(p => p.key.name);
5429
+ let exp = `[${right}]`;
5430
+ let e = parseJS(exp);
5431
+ assert(e.ast.body.length == 1);
5432
+
5433
+ itemName = '$$item';
5434
+ let n = e.ast.body[0];
5435
+ assert(n.expression.elements.length == 1 || n.expression.elements.length == 2);
5436
+ let a = n.expression.elements[0];
5437
+ unwrap = exp.substring(a.start, a.end);
5438
+
5439
+ if(n.expression.elements.length == 2) {
5440
+ let b = n.expression.elements[1];
5441
+ assert(b.type == 'Identifier');
5442
+ indexName = exp.substring(b.start, b.end);
5443
+ }
5444
+
5445
+ e = parseJS(`(${unwrap} = $$item)`);
5446
+ let l = e.ast.body[0].expression.left;
5447
+ if(l.type == 'ArrayPattern') {
5448
+ keywords = l.elements.map(p => p.name);
5449
+
5450
+ if(keyName) {
5451
+ let keyLink = {};
5452
+ if(indexName) keyLink[indexName] = '$index';
5453
+ for(let i in keywords) keyLink[keywords[i]] = `$$item[${i}]`;
5454
+ makeKeyFunction(keyLink);
5455
+ }
5456
+ } else {
5457
+ assert(l.type == 'ObjectPattern');
5458
+ keywords = l.properties.map(p => p.key.name);
5459
+
5460
+ if(keyName) {
5461
+ let keyLink = {};
5462
+ if(indexName) keyLink[indexName] = '$index';
5463
+ for(let k of keywords) keyLink[k] = `$$item.${k}`;
5464
+ makeKeyFunction(keyLink);
5465
+ }
5466
+ }
5344
5467
  } catch (e) {
5345
5468
  throw new Error('Wrong destructuring in each: ' + data.value);
5346
5469
  }
5347
5470
 
5348
- itemName = '$$item';
5349
- indexName = rx[2].trim();
5350
- if(indexName[0] == ',') indexName = indexName.substring(1).trim();
5351
- indexName = indexName || '$index';
5352
-
5353
5471
  blockPrefix = xNode('each:unwrap', {
5354
- exp,
5472
+ unwrap,
5355
5473
  keywords
5356
5474
  }, (ctx, n) => {
5357
- if(this.script.readOnly) ctx.writeLine(`let ${n.exp} = $$item;`);
5475
+ if(this.script.readOnly) ctx.writeLine(`let ${n.unwrap} = $$item;`);
5358
5476
  else {
5359
5477
  ctx.writeLine(`let ${n.keywords.join(', ')};`);
5360
- ctx.writeLine(`$runtime.prefixPush($cd, () => (${n.exp} = $$item));`);
5478
+ ctx.writeLine(`$runtime.prefixPush(() => (${n.unwrap} = $$item));`);
5361
5479
  }
5362
5480
  });
5363
5481
  } else {
5364
- rx = right.trim().split(/\s*,\s*/);
5482
+ rx = right.trim().split(/\s*\,\s*/);
5365
5483
  assert(rx.length <= 2, `Wrong #each expression '${data.value}'`);
5366
5484
  itemName = rx[0];
5367
- indexName = rx[1] || '$index';
5485
+ indexName = rx[1] || null;
5486
+ if(keyName) {
5487
+ if(keyName == itemName) keyFunction = 'noop';
5488
+ else {
5489
+ let keyLink = {[itemName]: '$$item'};
5490
+ if(indexName) keyLink[indexName] = '$index';
5491
+ makeKeyFunction(keyLink);
5492
+ }
5493
+ }
5368
5494
  }
5369
5495
  assert(isSimpleName(itemName), `Wrong name '${itemName}'`);
5370
- assert(isSimpleName(indexName), `Wrong name '${indexName}'`);
5371
-
5372
- let keyFunction = null;
5373
- if(keyName == itemName) {
5374
- keyName = null;
5375
- keyFunction = 'noop';
5376
- }
5377
- if(keyName) assert(detectExpressionType(keyName) == 'identifier', `Wrong key '${keyName}'`);
5378
-
5379
- if(keyName) {
5380
- this.detectDependency(keyName);
5381
- keyFunction = xNode('function', {
5382
- inline: true,
5383
- arrow: true,
5384
- args: [itemName, 'i'],
5385
- body: [xNode('block', {
5386
- index: indexName,
5387
- key: keyName
5388
- }, (ctx, data) => {
5389
- if(data.key == data.index) ctx.writeLine('return i;');
5390
- else ctx.writeLine(`return ${data.key};`);
5391
- })]
5392
- });
5393
- }
5394
5496
 
5395
5497
  let rebind;
5396
5498
  if(!this.script.readOnly) {
5397
- rebind = xNode('block', {
5398
- itemName,
5399
- indexName
5400
- }, (ctx, n) => {
5401
- ctx.write(`(_${n.indexName}, _${n.itemName}) => {${n.indexName}=_${n.indexName}; ${n.itemName}=_${n.itemName};}`);
5402
- });
5499
+ if(!indexName && keyName == itemName) rebind = null;
5500
+ else {
5501
+ rebind = xNode('block', {
5502
+ itemName,
5503
+ indexName
5504
+ }, (ctx, n) => {
5505
+ if(n.indexName) ctx.write(`(_${n.itemName}, _${n.indexName}) => {${n.itemName}=_${n.itemName}; ${n.indexName}=_${n.indexName};}`);
5506
+ else ctx.write(`(_${n.itemName}) => {${n.itemName}=_${n.itemName};}`);
5507
+ });
5508
+ }
5403
5509
  }
5404
5510
 
5405
5511
  let nodeItems = trimEmptyNodes(data.body);
@@ -5423,10 +5529,13 @@
5423
5529
  itemName,
5424
5530
  indexName
5425
5531
  }, (ctx, n) => {
5426
- ctx.write(`$runtime.makeEachSingleBlock((${n.itemName}, ${n.indexName}) => [`);
5532
+ ctx.write(`$runtime.makeEachSingleBlock((${n.itemName}`);
5533
+ if(n.indexName) ctx.write(`, ${n.indexName}`);
5534
+ ctx.write(`) => [`);
5427
5535
  ctx.indent++;
5428
5536
  ctx.write(true);
5429
- ctx.add(n.rebind);
5537
+ if(n.rebind) ctx.add(n.rebind);
5538
+ else ctx.write('null');
5430
5539
  ctx.write(',', true);
5431
5540
  ctx.add(n.block);
5432
5541
  ctx.indent--;
@@ -5438,7 +5547,7 @@
5438
5547
  keyFunction,
5439
5548
  block: itemBlock
5440
5549
  }, (ctx, n) => {
5441
- ctx.writeLine(`$runtime.$$eachBlock($cd, ${option.elName}, ${option.onlyChild ? 1 : 0}, () => (${arrayName}),`);
5550
+ ctx.writeLine(`$runtime.$$eachBlock(${option.elName}, ${option.onlyChild ? 1 : 0}, () => (${arrayName}),`);
5442
5551
  ctx.indent++;
5443
5552
  ctx.write(true);
5444
5553
  if(n.keyFunction === 'noop') ctx.write('$runtime.noop');
@@ -5454,25 +5563,16 @@
5454
5563
  return { source };
5455
5564
  }
5456
5565
 
5457
- function makeHtmlBlock(exp, label, requireCD) {
5566
+ function makeHtmlBlock(exp, label) {
5458
5567
  this.detectDependency(exp);
5459
- this.require('$cd');
5460
- const result = xNode('block', {
5461
- $deps: [this.glob.apply],
5568
+ return xNode('block', {
5569
+ $wait: ['apply'],
5462
5570
  el: label.bindName(),
5463
- exp,
5464
- requireCD
5571
+ exp
5465
5572
  }, (ctx, n) => {
5466
- let cd;
5467
- if(this.glob.apply.value) {
5468
- n.requireCD.$value(true);
5469
- cd = '$cd';
5470
- } else cd = 'null';
5471
- ctx.write(true, `$runtime.$$htmlBlock(${cd}, ${n.el}, () => (${n.exp}));`);
5573
+ if(this.inuse.apply) ctx.write(true, `$runtime.$$htmlBlock(${n.el}, () => (${n.exp}));`);
5574
+ else ctx.write(true, `$runtime.$$htmlBlockStatic(${n.el}, ${n.exp});`);
5472
5575
  });
5473
-
5474
- requireCD.$depends(result);
5475
- return result;
5476
5576
  }
5477
5577
 
5478
5578
  function makeAwaitBlock(node, element) {
@@ -5534,7 +5634,7 @@
5534
5634
  parts,
5535
5635
  keywords
5536
5636
  }, (ctx, n) => {
5537
- ctx.write(true, `$runtime.$$awaitBlock($cd, ${n.el}, () => [${n.keywords.join(', ')}], () => ${n.exp},`);
5637
+ ctx.write(true, `$runtime.$$awaitBlock(${n.el}, () => [${n.keywords.join(', ')}], () => ${n.exp},`);
5538
5638
  ctx.indent++;
5539
5639
  n.parts.forEach((part, index) => {
5540
5640
  if(index) ctx.write(', ');
@@ -5548,7 +5648,7 @@
5548
5648
  });
5549
5649
  }
5550
5650
 
5551
- function attachSlot(slotName, node, requireCD) {
5651
+ function attachSlot(slotName, node) {
5552
5652
  let props = [], staticProps = true;
5553
5653
 
5554
5654
  if(node.attributes && node.attributes.length) {
@@ -5568,19 +5668,16 @@
5568
5668
  if(node.body?.length) placeholder = this.buildBlock(node).block;
5569
5669
 
5570
5670
  this.require('$context');
5571
- this.glob.component.$value(true);
5671
+ this.require('$component');
5572
5672
 
5573
5673
  let result = xNode('slot', {
5574
- $deps: [this.glob.apply],
5674
+ $wait: ['apply'],
5575
5675
  name: slotName,
5576
5676
  props,
5577
5677
  staticProps,
5578
5678
  placeholder,
5579
- requireCD
5580
5679
  }, (ctx, n) => {
5581
- let dynamicProps = this.glob.apply.value && !n.staticProps;
5582
-
5583
- if(dynamicProps) n.requireCD.$value(true);
5680
+ let dynamicProps = this.inuse.apply && !n.staticProps;
5584
5681
 
5585
5682
  let missed = '', slotName = n.name == 'default' ? 'null' : n.name;
5586
5683
  if(dynamicProps) ctx.write(`$runtime.invokeSlot($component, ${slotName}, $context`);
@@ -5610,11 +5707,10 @@
5610
5707
  }
5611
5708
  ctx.write(')');
5612
5709
  });
5613
- requireCD.$depends(result);
5614
5710
  return result;
5615
5711
  }
5616
5712
 
5617
- function makeFragment(node, requireCD) {
5713
+ function makeFragment(node) {
5618
5714
  let rx = node.value.match(/#fragment:(\S+)(.*)$/s);
5619
5715
  assert(rx);
5620
5716
  let name = rx[1], external = false;
@@ -5630,8 +5726,6 @@
5630
5726
  });
5631
5727
  }
5632
5728
 
5633
- if(external) requireCD.$value(true);
5634
-
5635
5729
  let block;
5636
5730
  if(node.body && node.body.length) {
5637
5731
  block = this.buildBlock({ body: trimEmptyNodes(node.body) }, { inline: true, context: 'fragment', parentElement: '$dom' });
@@ -5643,27 +5737,24 @@
5643
5737
  }
5644
5738
 
5645
5739
  return xNode('fragment', {
5646
- $compile: [block.source, this.glob.apply],
5647
- $deps: [block.requireCD],
5740
+ $compile: [block.source],
5648
5741
  name,
5649
5742
  props,
5650
5743
  external,
5651
5744
  block
5652
5745
  }, (ctx, n) => {
5653
5746
  if(ctx.isEmpty(n.block.source)) {
5654
- ctx.write(true, `let $fragment_${n.name} = $runtime.makeStaticBlock(`);
5747
+ ctx.write(true, `let $fragment_${n.name} = $runtime.makeBlock(`);
5655
5748
  ctx.add(n.block.template);
5656
5749
  ctx.write(');');
5657
5750
  } else {
5658
5751
  ctx.write(true, `function $fragment_${n.name}($props, $events={}, $$fragmentSlot) {`);
5659
5752
  ctx.indent++;
5660
5753
 
5661
- if(n.block.requireCD.value) ctx.write(true, 'let $cd = $runtime.cd_new();');
5662
-
5663
5754
  if(n.props?.length) {
5664
- if(this.glob.apply.value) {
5755
+ if(this.inuse.apply) {
5665
5756
  ctx.writeLine('let ' + n.props.join(', ') + ';');
5666
- ctx.writeLine(`$runtime.unwrapProps($cd, $props, ($$) => ({${n.props.join(', ')}} = $$));`);
5757
+ ctx.writeLine(`$runtime.unwrapProps($props, ($$) => ({${n.props.join(', ')}} = $$));`);
5667
5758
  } else {
5668
5759
  ctx.writeLine('let ' + n.props.join(', ') + ';');
5669
5760
  ctx.writeLine(`$props && ({${n.props.join(', ')}} = ($runtime.isFunction($props) ? $props() : $props));`);
@@ -5671,17 +5762,17 @@
5671
5762
  }
5672
5763
 
5673
5764
  ctx.write(true, 'let $dom = ');
5765
+ n.block.template.cloneNode = true;
5674
5766
  ctx.add(n.block.template);
5675
5767
  ctx.write(';');
5676
5768
 
5677
5769
  ctx.add(n.block.source);
5678
- if(n.block.requireCD.value) ctx.write(true, 'return {$cd, $dom};');
5679
- else ctx.write(true, 'return {$dom};');
5770
+ ctx.write(true, 'return $dom;');
5680
5771
 
5681
5772
  ctx.indent--;
5682
5773
  ctx.writeLine('}');
5683
5774
  }
5684
- if(n.external) ctx.writeLine(`$runtime.exportFragment($cd, '${n.name}', $fragment_${n.name});`);
5775
+ if(n.external) ctx.writeLine(`$runtime.exportFragment('${n.name}', $fragment_${n.name});`);
5685
5776
  });
5686
5777
  }
5687
5778
 
@@ -5733,7 +5824,6 @@
5733
5824
 
5734
5825
  return xNode('call-fragment', {
5735
5826
  $compile: [slot?.source],
5736
- $deps: [this.glob.apply],
5737
5827
  forwardAllEvents,
5738
5828
  name,
5739
5829
  events,
@@ -5750,7 +5840,7 @@
5750
5840
 
5751
5841
  const writeProps = () => ctx.write('{' + n.props.map(p => p.name == p.value ? p.name : `${p.name}: ${p.value}`).join(', ') + '}');
5752
5842
 
5753
- if(n.staticProps || !this.glob.apply.value) writeProps();
5843
+ if(n.staticProps || !this.inuse.apply) writeProps();
5754
5844
  else {
5755
5845
  ctx.write('() => (');
5756
5846
  writeProps();
@@ -5784,13 +5874,13 @@
5784
5874
  ctx.write(missed, ',', true);
5785
5875
  missed = '';
5786
5876
  if(ctx.isEmpty(n.slot.source)) {
5787
- ctx.write('$runtime.makeStaticBlock(');
5877
+ ctx.write('$runtime.makeBlock(');
5788
5878
  ctx.add(n.slot.template);
5789
5879
  ctx.write(')');
5790
5880
  } else {
5791
5881
  ctx.write('$runtime.makeBlock(');
5792
5882
  ctx.add(n.slot.template);
5793
- ctx.write(', ($cd, $parentElement) => {', true);
5883
+ ctx.write(', ($parentElement) => {', true);
5794
5884
  ctx.indent++;
5795
5885
  ctx.add(n.slot.source);
5796
5886
  ctx.indent--;
@@ -5805,20 +5895,16 @@
5805
5895
  }
5806
5896
 
5807
5897
 
5808
- function attachFragmentSlot(label, requireCD) {
5809
- requireCD.$value(true);
5810
-
5898
+ function attachFragmentSlot(label) {
5811
5899
  return xNode('fragment-slot', {
5812
5900
  el: label.bindName()
5813
5901
  }, (ctx, n) => {
5814
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, $$fragmentSlot?.())`);
5902
+ ctx.write(true, `$runtime.attachBlock(${n.el}, $$fragmentSlot?.())`);
5815
5903
  });
5816
5904
  }
5817
5905
 
5818
5906
 
5819
- function attchExportedFragment(node, label, componentName, requireCD) {
5820
- requireCD.$value(true);
5821
-
5907
+ function attchExportedFragment(node, label, componentName) {
5822
5908
  let data = {
5823
5909
  name: node.elArg,
5824
5910
  componentName,
@@ -5829,7 +5915,7 @@
5829
5915
  if(body.length) {
5830
5916
  data.slot = this.buildBlock({ body }, { inline: true });
5831
5917
  data.$compile = [data.slot.source];
5832
- data.$deps = [data.slot.requireCD];
5918
+ data.$wait = [data.slot.requireCD];
5833
5919
  // assert(!data.slot.template.svg, 'SVG is not supported for exported fragment');
5834
5920
  }
5835
5921
 
@@ -5837,7 +5923,7 @@
5837
5923
  data = { ...pa, ...data };
5838
5924
 
5839
5925
  return xNode('attach-exported-fragment', data, (ctx, n) => {
5840
- ctx.write(true, `$runtime.attachBlock($cd, ${n.label}, $runtime.callExportedFragment($instance_${n.componentName}, '${n.name}'`);
5926
+ ctx.write(true, `$runtime.attachBlock(${n.label}, $runtime.callExportedFragment($instance_${n.componentName}, '${n.name}'`);
5841
5927
  ctx.indent++;
5842
5928
  let missed = '';
5843
5929
 
@@ -5845,13 +5931,13 @@
5845
5931
  ctx.write(',', true);
5846
5932
 
5847
5933
  if(ctx.isEmpty(n.slot.source)) {
5848
- ctx.write('$runtime.makeStaticBlock(');
5934
+ ctx.write('$runtime.makeBlock(');
5849
5935
  ctx.add(n.slot.template);
5850
5936
  ctx.write(')');
5851
5937
  } else {
5852
- ctx.write('$runtime.makeBlockBound($cd, ');
5938
+ ctx.write('$runtime.makeBlockBound(');
5853
5939
  ctx.add(n.slot.template);
5854
- ctx.write(', ($cd, $parentElement) => {', true);
5940
+ ctx.write(', ($parentElement) => {', true);
5855
5941
  ctx.indent++;
5856
5942
  ctx.add(n.slot.source);
5857
5943
  ctx.indent--;
@@ -5903,7 +5989,7 @@
5903
5989
  });
5904
5990
  }
5905
5991
 
5906
- function attachHead(n, requireCD) {
5992
+ function attachHead(n) {
5907
5993
  if(n.elArg == 'window' || n.elArg == 'body') {
5908
5994
  let name = 'el' + (this.uniqIndex++);
5909
5995
  let block = this.buildBlock({ body: [n] }, { malinaElement: true, inline: true, oneElement: name, bindAttributes: true });
@@ -5930,8 +6016,7 @@
5930
6016
  });
5931
6017
 
5932
6018
  let d = {
5933
- $deps: [this.glob.apply],
5934
- requireCD
6019
+ $wait: ['apply']
5935
6020
  };
5936
6021
  if(title?.body?.[0]) {
5937
6022
  assert(title.body[0].type == 'text');
@@ -5953,21 +6038,16 @@
5953
6038
  });
5954
6039
  d.source = bb.source;
5955
6040
  d.template = bb.template;
5956
- d.blockCD = bb.requireCD;
5957
-
5958
6041
  d.$compile = [d.source];
5959
- d.$deps.push(d.blockCD);
5960
6042
 
5961
6043
  this.require('$onDestroy');
5962
6044
  }
5963
6045
 
5964
6046
  const result = xNode('malina:head', d, (ctx, n) => {
5965
- if(n.blockCD.value) n.requireCD.$value(true);
5966
6047
  if(n.title != null) ctx.writeLine(`document.title = ${n.title};`);
5967
6048
  if(n.dynTitle) {
5968
- if(this.glob.apply.value) {
5969
- n.requireCD.$value(true);
5970
- ctx.writeLine(`$watchReadOnly($cd, () => (${n.dynTitle}), (value) => {document.title = value;});`);
6049
+ if(this.inuse.apply) {
6050
+ ctx.writeLine(`$watch(() => (${n.dynTitle}), (value) => {document.title = value;});`);
5971
6051
  } else ctx.writeLine(`document.title = ${n.dynTitle};`);
5972
6052
  }
5973
6053
 
@@ -5983,7 +6063,6 @@
5983
6063
  ctx.writeLine('}');
5984
6064
  }
5985
6065
  });
5986
- requireCD.$depends(result);
5987
6066
  return result;
5988
6067
  } else throw 'Wrong tag';
5989
6068
  }
@@ -6027,7 +6106,7 @@
6027
6106
  if(!statical) value = pe.result;
6028
6107
  } else if(value) {
6029
6108
  rawValue = value;
6030
- value = '`' + this.Q(value) + '`';
6109
+ value = '`' + Q(value) + '`';
6031
6110
  statical = true;
6032
6111
  } else {
6033
6112
  rawValue = true;
@@ -6038,7 +6117,7 @@
6038
6117
  return { name, value, rawValue, static: statical };
6039
6118
  }
6040
6119
 
6041
- function attachPortal(node, requireCD) {
6120
+ function attachPortal(node) {
6042
6121
  let body = trimEmptyNodes(node.body || []);
6043
6122
  if(!body.length) return;
6044
6123
 
@@ -6051,20 +6130,15 @@
6051
6130
  }
6052
6131
  });
6053
6132
 
6054
- this.require('$component');
6055
-
6056
6133
  let mount = node.attributes.find(a => a.name == 'mount')?.value;
6057
6134
  if(mount) mount = unwrapExp(mount);
6058
6135
 
6059
6136
  const result = xNode('portal', {
6060
6137
  $compile: [bb.source],
6061
- $deps: [bb.requireCD],
6062
6138
  mount,
6063
6139
  source: bb.source,
6064
- template: bb.template,
6065
- requireCD
6140
+ template: bb.template
6066
6141
  }, (ctx, n) => {
6067
- if(n.$deps[0].value) n.requireCD.$value(true);
6068
6142
  let label = n.mount || 'document.body';
6069
6143
  ctx.writeLine('{');
6070
6144
  ctx.indent++;
@@ -6072,12 +6146,11 @@
6072
6146
  ctx.add(n.source);
6073
6147
  ctx.writeLine('let $$first = $parentElement[$runtime.firstChild];');
6074
6148
  ctx.writeLine('let $$last = $parentElement.lastChild;');
6075
- ctx.writeLine(`$runtime.cd_onDestroy(${n.$deps[0].value ? '$cd' : '$component'}, () => $runtime.$$removeElements($$first, $$last));`);
6149
+ ctx.writeLine(`$runtime.$onDestroy(() => $runtime.$$removeElements($$first, $$last));`);
6076
6150
  ctx.writeLine(`$tick(() => ${label}.appendChild($parentElement));`);
6077
6151
  ctx.indent--;
6078
6152
  ctx.writeLine('}');
6079
6153
  });
6080
- requireCD.$depends(result);
6081
6154
  return result;
6082
6155
  }
6083
6156
 
@@ -6223,7 +6296,7 @@
6223
6296
  return { event, fn, rootModifier };
6224
6297
  }
6225
6298
 
6226
- const version = '0.7.0a2';
6299
+ const version = '0.7.0-a6';
6227
6300
 
6228
6301
 
6229
6302
  async function compile(source, config = {}) {
@@ -6250,7 +6323,6 @@
6250
6323
  uniqIndex: 0,
6251
6324
  warning: config.warning || (w => console.warn('!', w.message || w)),
6252
6325
 
6253
- Q: config.inlineTemplate ? Q2 : Q,
6254
6326
  buildBlock,
6255
6327
  bindProp,
6256
6328
  makeEachBlock,
@@ -6273,29 +6345,26 @@
6273
6345
 
6274
6346
  inuse: {},
6275
6347
  glob: {
6348
+ $component: xNode('$component', false),
6349
+ rootCD: xNode('root-cd', false),
6276
6350
  apply: xNode('apply', false),
6277
- component: xNode('$component', false),
6278
6351
  componentFn: xNode('componentFn', false),
6279
- rootCD: xNode('root-cd', false)
6352
+ $onMount: xNode('$onMount', false)
6280
6353
  },
6281
6354
  require: function(...args) {
6282
6355
  for(let name of args) {
6283
6356
  let deps = true;
6284
6357
  if(name == '$props:no-deps') { name = '$props'; deps = false; }
6285
- if(name == 'apply' && ctx.script.readOnly) name = 'blankApply';
6358
+ if(name == 'apply' && ctx.script.readOnly) {
6359
+ ctx.glob.apply.$value('readOnly');
6360
+ continue;
6361
+ }
6286
6362
  if(ctx.inuse[name] == null) ctx.inuse[name] = 0;
6287
6363
  ctx.inuse[name]++;
6288
6364
  if(!deps) continue;
6289
- if(name == 'apply') ctx.glob.apply.$value(true);
6290
- if(name == '$component') ctx.glob.component.$value(true);
6291
6365
  if(name == '$attributes') ctx.require('$props');
6292
- if(name == '$props' && !ctx.script.readOnly) ctx.require('apply', '$cd');
6293
- if(name == '$cd') {
6294
- ctx.glob.rootCD.$value(true);
6295
- ctx.require('$component');
6296
- }
6297
- if(name == '$onDestroy') ctx.require('$component');
6298
- if(name == '$onMount') ctx.require('$component');
6366
+ if(name == '$props' && !ctx.script.readOnly) ctx.require('apply', 'rootCD');
6367
+ if(['apply', '$onMount', '$component', 'componentFn', 'rootCD'].includes(name)) ctx.glob[name].$value(true);
6299
6368
  }
6300
6369
  },
6301
6370
  detectDependency,
@@ -6308,7 +6377,6 @@
6308
6377
  scriptNodes: null,
6309
6378
  js_parse: parse$1,
6310
6379
  js_transform: transform,
6311
- js_build: build,
6312
6380
 
6313
6381
  styleNodes: null,
6314
6382
  css: null,
@@ -6323,13 +6391,11 @@
6323
6391
  head: xNode('block'),
6324
6392
  code: xNode('block'),
6325
6393
  body: xNode('block')
6326
- },
6327
-
6328
- xBuild: node => {
6329
- return xBuild(ctx, node);
6330
6394
  }
6331
6395
  };
6332
6396
 
6397
+ use_context(ctx, () => setup.call(ctx));
6398
+
6333
6399
  await hook(ctx, 'dom:before');
6334
6400
  ctx.parseHTML();
6335
6401
  await hook(ctx, 'dom');
@@ -6355,7 +6421,7 @@
6355
6421
  await hook(ctx, 'js:before');
6356
6422
  ctx.js_parse();
6357
6423
  await hook(ctx, 'js');
6358
- ctx.js_transform();
6424
+ use_context(ctx, () => ctx.js_transform());
6359
6425
  await hook(ctx, 'js:after');
6360
6426
 
6361
6427
  await hook(ctx, 'css:before');
@@ -6364,23 +6430,33 @@
6364
6430
  await hook(ctx, 'css');
6365
6431
 
6366
6432
  await hook(ctx, 'runtime:before');
6367
- ctx.buildRuntime();
6433
+ use_context(ctx, () => ctx.buildRuntime());
6368
6434
  await hook(ctx, 'runtime');
6369
6435
 
6370
-
6371
6436
  await hook(ctx, 'build:before');
6372
- const result = ctx.result = xNode('block');
6373
- result.push('import * as $runtime from \'malinajs/runtime.js\';');
6374
- result.push('import { $watch, $watchReadOnly, $tick } from \'malinajs/runtime.js\';');
6375
- if(config.hideLabel) {
6376
- result.push('import { $$htmlToFragmentClean as $$htmlToFragment } from \'malinajs/runtime.js\';');
6377
- } else {
6378
- result.push('import { $$htmlToFragment } from \'malinajs/runtime.js\';');
6379
- }
6380
- result.push(ctx.module.top);
6381
- result.push(makeComponentFn.call(ctx));
6382
6437
 
6383
- ctx.result = xBuild(ctx, result);
6438
+ use_context(ctx, () => {
6439
+ const result = ctx.result = xNode('block');
6440
+ result.push('import * as $runtime from \'malinajs/runtime.js\';');
6441
+ result.push('import { $watch, $tick } from \'malinajs/runtime.js\';');
6442
+ if(config.hideLabel) {
6443
+ result.push('import { $$htmlToFragmentClean as $$htmlToFragment } from \'malinajs/runtime.js\';');
6444
+ } else {
6445
+ result.push('import { $$htmlToFragment } from \'malinajs/runtime.js\';');
6446
+ }
6447
+ result.push(ctx.module.top);
6448
+ result.push(xNode('componentFn-wrapper', {
6449
+ $compile: [ctx.module.head, ctx.module.code, ctx.module.body, ctx.glob.rootCD],
6450
+ name: config.name,
6451
+ componentFn: ctx.glob.componentFn
6452
+ }, (ctx, n) => {
6453
+ if(config.exportDefault) ctx.write(true, 'export default ');
6454
+ else ctx.write(true, `const ${n.name} = `);
6455
+ ctx.add(n.componentFn);
6456
+ }));
6457
+
6458
+ ctx.result = xBuild(result);
6459
+ });
6384
6460
 
6385
6461
  await hook(ctx, 'build');
6386
6462
  return ctx;
@@ -6441,57 +6517,26 @@
6441
6517
  }
6442
6518
 
6443
6519
 
6444
- function makeComponentFn() {
6445
- let componentFn = xNode('componentFn', {
6446
- $deps: [this.glob.apply, this.glob.rootCD],
6520
+ function setup() {
6521
+ this.glob.componentFn = xNode(this.glob.componentFn, {
6522
+ $wait: [this.glob.rootCD],
6447
6523
  body: [this.module.head, this.module.code, this.module.body]
6448
6524
  }, (ctx, n) => {
6449
- let component = xNode('function', {
6450
- args: ['$option'],
6451
- inline: true,
6452
- arrow: true,
6453
- body: n.body
6454
- });
6455
-
6456
- if(this.glob.apply.value) {
6457
- ctx.add(this.glob.componentFn);
6458
- ctx.write('$runtime.makeComponent(');
6459
- component.args.push('$$apply');
6460
- ctx.add(component);
6461
- ctx.write(', $runtime.$base);', true);
6462
- } else if(this.glob.rootCD.value || ctx.inuse.$cd || ctx.inuse.$component || ctx.inuse.$context || ctx.inuse.blankApply) {
6463
- ctx.add(this.glob.componentFn);
6464
- if(ctx.inuse.blankApply) {
6465
- component.body[0].body.unshift(xNode('block', (ctx) => {
6466
- ctx.writeLine('let $$apply = $runtime.noop;');
6467
- }));
6468
- }
6469
-
6470
- ctx.write('$runtime.makeComponent(');
6471
- ctx.add(component);
6472
- ctx.write(');', true);
6525
+ if(n.value || this.glob.rootCD.value) {
6526
+ n.value = true;
6527
+ ctx.write('$runtime.makeComponent($option => {');
6528
+ ctx.indent++;
6529
+ ctx.add(xNode('block', { body: n.body }));
6530
+ ctx.indent--;
6531
+ ctx.write(true, '});', true);
6473
6532
  } else {
6474
- this.glob.componentFn.$value('thin');
6475
- ctx.add(this.glob.componentFn);
6476
6533
  ctx.write('($option={}) => {', true);
6477
- ctx.goIndent(() => {
6478
- ctx.add(xNode('block', { body: n.body }));
6479
- });
6534
+ ctx.indent++;
6535
+ ctx.add(xNode('block', { body: n.body }));
6536
+ ctx.indent--;
6480
6537
  ctx.write(true, '}');
6481
6538
  }
6482
6539
  });
6483
-
6484
- return xNode('block', {
6485
- $compile: [this.module.head, this.module.code, this.module.body],
6486
- name: this.config.name,
6487
- componentFn
6488
- }, (ctx, n) => {
6489
- ctx.writeIndent();
6490
- if(this.config.exportDefault) ctx.write('export default ');
6491
- else ctx.write(`const ${n.name} = `);
6492
- ctx.add(this.glob.apply);
6493
- ctx.add(n.componentFn);
6494
- });
6495
6540
  }
6496
6541
 
6497
6542
  exports.compile = compile;