malinajs 0.7.0-a2 → 0.7.0-a4

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 +561 -542
  2. package/package.json +2 -2
  3. package/runtime.js +301 -290
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
 
@@ -1415,7 +1487,7 @@
1415
1487
  } else throw 'Error';
1416
1488
  assertExpression(ex.right);
1417
1489
  const exp = source.substring(ex.right.start, ex.right.end);
1418
- result.watchers.push(`$runtime.prefixPush($cd, () => {${target} = ${exp};});`);
1490
+ result.watchers.push(`$runtime.prefixPush(() => {${target} = ${exp};});`);
1419
1491
  } else if(n.body.expression.type == 'SequenceExpression') {
1420
1492
  const ex = n.body.expression.expressions;
1421
1493
  const handler = ex[ex.length - 1];
@@ -1429,12 +1501,12 @@
1429
1501
  if(ex.length == 2) {
1430
1502
  assertExpression(ex[0]);
1431
1503
  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)});`);
1504
+ if(this.config.immutable) result.watchers.push(`$watch($cd, () => (${exp}), ${callback}, {ro: false});`);
1505
+ else result.watchers.push(`$watch($cd, () => (${exp}), ${callback}, {ro: false, cmp: $runtime.$$deepComparator(0)});`);
1434
1506
  } else if(ex.length > 2) {
1435
1507
  for(let i = 0; i < ex.length - 1; i++) assertExpression(ex[i]);
1436
1508
  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)});`);
1509
+ result.watchers.push(`$watch($cd, () => [${exp}], ($args) => { (${callback}).apply(null, $args); }, {ro: false, cmp: $runtime.$$deepComparator(1)});`);
1438
1510
  } else throw 'Error';
1439
1511
  } else throw 'Error';
1440
1512
  };
@@ -1501,140 +1573,82 @@
1501
1573
  resultBody.push(n);
1502
1574
  });
1503
1575
 
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
1576
  if(lastPropIndex != null) {
1515
- header.push(rawNode(() => {
1516
- if(this.inuse.$props) return 'let $props = $option.props || {};';
1577
+ this.module.head.push(xNode('$props', ctx => {
1578
+ if(this.inuse.$props) ctx.write(true, 'let $props = $option.props || {};');
1517
1579
  }));
1518
1580
 
1519
1581
  if(!constantProps && !this.script.readOnly) this.require('apply');
1520
1582
 
1521
- resultBody.splice(lastPropIndex, 0, rawNode(() => {
1522
- let code = [];
1583
+ this.module.code.push(xNode('ast', { body: resultBody.slice(0, lastPropIndex) }));
1584
+
1585
+ this.module.code.push(xNode('props', {
1586
+ props: this.script.props,
1587
+ constantProps
1588
+ }, (ctx, n) => {
1523
1589
  if(this.inuse.$attributes) {
1524
- let pa = result.props.map(p => {
1590
+ let pa = n.props.map(p => {
1525
1591
  if(p.value === void 0) return `${p.name}`;
1526
1592
  return `${p.name}=${p.value}`;
1527
1593
  }).join(', ');
1528
- code.push(`let {${pa}, ...$attributes} = $props;`);
1594
+ ctx.write(true, `let {${pa}, ...$attributes} = $props;`);
1529
1595
 
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(', ')}});`);
1596
+ if(!this.script.readOnly && !n.constantProps) {
1597
+ ctx.write(true, `$runtime.current_component.push = () => ({${n.props.map(p => p.name + '=' + p.name).join(', ')}, ...$attributes} = $props = $option.props || {});`);
1598
+ ctx.write(true, `$runtime.current_component.exportedProps = () => ({${n.props.map(p => p.name).join(', ')}});`);
1533
1599
  }
1534
1600
  } else if(this.inuse.$props) {
1535
- let pa = result.props.map(p => {
1601
+ let pa = n.props.map(p => {
1536
1602
  if(p.value === void 0) return `${p.name}`;
1537
1603
  return `${p.name}=${p.value}`;
1538
1604
  }).join(', ');
1539
- code.push(`let {${pa}} = $props;`);
1605
+ ctx.write(true, `let {${pa}} = $props;`);
1540
1606
 
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(', ')}});`);
1607
+ if(!this.script.readOnly && !n.constantProps) {
1608
+ ctx.write(true, `$runtime.current_component.push = () => ({${n.props.map(p => p.name + '=' + p.name).join(', ')}} = $props = $option.props || {});`);
1609
+ ctx.write(true, `$runtime.current_component.exportedProps = () => ({${n.props.map(p => p.name).join(', ')}});`);
1544
1610
  }
1545
1611
  }
1546
- return code;
1547
1612
  }));
1613
+
1614
+ this.module.code.push(xNode('ast', { body: resultBody.slice(lastPropIndex) }));
1548
1615
  } else {
1549
- header.push(rawNode(() => {
1550
- let code = [];
1616
+ this.module.head.push(xNode('no-props', ctx => {
1551
1617
  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;');
1618
+ ctx.write(true, 'let $props = $option.props || {}, $attributes = $props;');
1619
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $props = $attributes = $option.props || {};');
1554
1620
  } 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 || {};');
1621
+ ctx.write(true, 'let $props = $option.props || {};');
1622
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $props = $option.props || {};');
1557
1623
  } 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 || {};');
1624
+ ctx.write(true, 'let $attributes = $option.props || {};');
1625
+ if(!this.script.readOnly) ctx.write(true, '$runtime.current_component.push = () => $attributes = $option.props || {};');
1560
1626
  }
1561
- return code;
1562
- }));
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
-
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
1627
  }));
1583
- }
1584
1628
 
1585
- if(!rootFunctions.$emit) {
1586
- header.push(rawNode(() => {
1587
- if(this.inuse.$emit) return 'const $emit = $runtime.$makeEmitter($option);';
1588
- }));
1629
+ this.module.code.push(xNode('ast', { body: resultBody }));
1589
1630
  }
1590
1631
 
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
- });
1596
- }
1597
-
1598
- this.script.rootLevel = resultBody;
1599
-
1600
1632
  this.module.top.push(xNode('autoimport', (ctx) => {
1601
1633
  Object.values(this.script.autoimport).forEach(l => ctx.writeLine(l));
1602
1634
  }));
1603
1635
 
1604
1636
  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
- }
1622
1637
 
1623
-
1624
- function rawNode(exp, n) {
1625
- n = n || {};
1626
- n.type = 'Raw';
1627
- n.value = exp;
1628
- return n;
1638
+ if(this.scriptNodes[0] && this.scriptNodes[0].attributes.some(a => a.name == 'property') && this.script.props.length && !this.script.readOnly) {
1639
+ this.require('apply');
1640
+ this.module.code.push(xNode('external-property', {
1641
+ props: this.script.props
1642
+ }, (ctx, n) => {
1643
+ n.props.forEach(p => {
1644
+ ctx.write(true, `$runtime.makeExternalProperty('${p.name}', () => ${p.name}, _${p.name} => ${p.name} = _${p.name});`);
1645
+ });
1646
+ }));
1647
+ }
1629
1648
  }
1630
1649
 
1631
1650
 
1632
1651
  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
1652
  Raw: function(node, state) {
1639
1653
  let value = typeof node.value == 'function' ? node.value() : node.value;
1640
1654
  if(value) {
@@ -1675,27 +1689,78 @@
1675
1689
  };
1676
1690
 
1677
1691
  function buildRuntime() {
1678
- let runtime = xNode('block', { scope: true, $compile: [] });
1692
+ this.module.head.push(xNode('$events', (ctx) => {
1693
+ if(this.inuse.$events) ctx.write(true, 'const $events = $option.events || {};');
1694
+ }));
1679
1695
 
1680
- let rootCD = this.glob.rootCD;
1681
- rootCD.$handler = (ctx, n) => {
1682
- n.$value(!!n.$deps[0].value);
1696
+ this.module.head.push(xNode(this.glob.$component, {
1697
+ $hold: ['componentFn']
1698
+ }, (ctx, n) => {
1683
1699
  if(n.value) {
1684
- ctx.writeLine('let $cd = $component.$cd;');
1685
- this.glob.component.$value(true);
1700
+ this.require('componentFn');
1701
+ ctx.write(true, 'const $component = $runtime.current_component;');
1686
1702
  }
1687
- };
1688
- runtime.push(rootCD);
1689
- this.glob.component.$depends(rootCD);
1703
+ }));
1704
+
1705
+ this.module.head.push(xNode('$context', {
1706
+ $hold: ['componentFn'],
1707
+ }, (ctx) => {
1708
+ if(this.inuse.$context) {
1709
+ this.require('componentFn');
1710
+ ctx.write(true, 'const $context = $runtime.$context;');
1711
+ }
1712
+ }));
1713
+
1714
+ this.module.top.push(xNode(this.glob.$onMount, {
1715
+ $hold: ['componentFn']
1716
+ }, (ctx, n) => {
1717
+ if(n.value) {
1718
+ this.require('componentFn');
1719
+ ctx.write(true, `import { $onMount } from 'malinajs/runtime.js';`);
1720
+ }
1721
+ }));
1722
+
1723
+ this.module.top.push(xNode('$onDestroy', (ctx) => {
1724
+ if(this.inuse.$onDestroy) ctx.write(true, `import { $onDestroy } from 'malinajs/runtime.js';`);
1725
+ }));
1726
+
1727
+ this.module.head.unshift(xNode(this.glob.apply, {
1728
+ $hold: ['componentFn'],
1729
+ $wait: ['rootCD']
1730
+ }, (ctx, n) => {
1731
+ if(n.value || this.inuse.rootCD) {
1732
+ this.require('componentFn');
1733
+ if(n.value == 'readOnly') ctx.writeLine('const $$apply = $runtime.noop;');
1734
+ else ctx.writeLine('const $$apply = $runtime.makeApply();');
1735
+ }
1736
+ }));
1737
+
1738
+ this.module.head.push(xNode('$emit', (ctx) => {
1739
+ if(this.inuse.$emit) ctx.write(true, 'const $emit = $runtime.$makeEmitter($option);');
1740
+ }));
1741
+
1742
+ if(this.config.autoSubscribe && !this.script.readOnly) {
1743
+ this.module.head.push(xNode('autoSubscribe', {
1744
+ $hold: ['apply'],
1745
+ names: this.script.autosubscribeNames
1746
+ }, (ctx, n) => {
1747
+ if(!n.names.length) return;
1748
+ this.require('apply');
1749
+ ctx.write(true, `$runtime.autoSubscribe(${n.names.join(', ')});`);
1750
+ }));
1751
+ }
1752
+
1753
+ let runtime = xNode('block', { scope: true, $compile: [] });
1754
+ this.module.body.push(runtime);
1690
1755
 
1691
1756
  let bb = this.buildBlock(this.DOM, {
1692
1757
  inline: true,
1758
+ protectLastTag: true,
1693
1759
  template: {
1694
1760
  name: '$parentElement',
1695
1761
  cloneNode: true
1696
1762
  }
1697
1763
  });
1698
- bb.requireCD && rootCD.$depends(bb.requireCD);
1699
1764
  runtime.push(bb.template);
1700
1765
  runtime.push(xNode('root-event', (ctx) => {
1701
1766
  if(!this.inuse.rootEvent) return;
@@ -1713,25 +1778,22 @@
1713
1778
  if(!this.css.active()) return;
1714
1779
  let style = this.css.getContent();
1715
1780
  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)}\`);`);
1781
+ if(this.config.css) {
1782
+ if(typeof this.config.css == 'function') this.config.css(style, this.config.path, this, ctx);
1783
+ else ctx.writeLine(`$runtime.addStyles('${this.css.id}', \`${Q(style)}\`);`);
1720
1784
  } else {
1721
- ctx._ctx.css.result = style;
1785
+ this.css.result = style;
1722
1786
  }
1723
1787
  }));
1724
1788
 
1725
1789
  runtime.push(xNode('bind-component-element', {
1726
- $deps: [this.glob.componentFn]
1790
+ $wait: ['componentFn']
1727
1791
  }, (ctx) => {
1728
- if(this.glob.componentFn.value == 'thin') ctx.writeLine('return {$dom: $parentElement};');
1729
- else ctx.writeLine('return $parentElement;');
1792
+ if(this.inuse.componentFn) ctx.writeLine('return $parentElement;');
1793
+ else ctx.writeLine('return {$dom: $parentElement};');
1730
1794
  }));
1731
1795
 
1732
- this.module.body.push(runtime);
1733
-
1734
- if(!this.script.readOnly && this.css.active() && this.css.containsExternal()) this.require('apply', '$cd');
1796
+ if(!this.script.readOnly && this.css.active() && this.css.containsExternal()) this.require('apply', 'rootCD');
1735
1797
 
1736
1798
  this.module.head.push(xNode('resolveClass', (ctx) => {
1737
1799
  if(!this.inuse.resolveClass) return;
@@ -1758,12 +1820,12 @@
1758
1820
 
1759
1821
 
1760
1822
  function buildBlock(data, option = {}) {
1761
- let rootTemplate = xNode('node', { inline: true, _ctx: this });
1823
+ let rootTemplate = xNode('node', { inline: true });
1762
1824
  let rootSVG = false, requireFragment = option.template?.requireFragment;
1763
1825
  let binds = xNode('block');
1764
1826
  let result = {};
1765
- let requireCD = result.requireCD = xNode('require-cd', false);
1766
1827
  let inuse = Object.assign({}, this.inuse);
1828
+ let lastTagDynamic = false;
1767
1829
 
1768
1830
  if(!option.parentElement) option.parentElement = '$parentElement';
1769
1831
 
@@ -1772,9 +1834,8 @@
1772
1834
  if(option.allowSingleBlock && data.body.length == 1) {
1773
1835
  let n = data.body[0];
1774
1836
  if(n.type == 'node' && n.name.match(/^[A-Z]/)) {
1775
- let component = this.makeComponent(n, requireCD);
1837
+ let component = this.makeComponent(n);
1776
1838
  return {
1777
- requireCD,
1778
1839
  singleBlock: component.bind
1779
1840
  };
1780
1841
  }
@@ -1786,7 +1847,7 @@
1786
1847
  if(n.type == 'comment' && !this.config.preserveComments) return false;
1787
1848
  if(n.type == 'fragment') {
1788
1849
  try {
1789
- let f = this.makeFragment(n, requireCD);
1850
+ let f = this.makeFragment(n);
1790
1851
  f && binds.push(f);
1791
1852
  } catch (e) {
1792
1853
  wrapException(e, n);
@@ -1849,8 +1910,9 @@
1849
1910
  return el;
1850
1911
  };
1851
1912
 
1852
- const bindNode = (n) => {
1913
+ const bindNode = (n, nodeIndex) => {
1853
1914
  if(n.type === 'text') {
1915
+ if(isRoot) lastTagDynamic = false;
1854
1916
  let prev = tpl.getLast();
1855
1917
  if(prev?.$type == 'node:text' && prev._boundName) tpl.push(xNode('node:comment', { label: true }));
1856
1918
 
@@ -1864,17 +1926,15 @@
1864
1926
  } else {
1865
1927
  textNode = tpl.push(' ');
1866
1928
  let bindText = xNode('bindText', {
1867
- $deps: [this.glob.apply],
1929
+ $wait: ['apply'],
1868
1930
  el: textNode.bindName(),
1869
1931
  exp: pe.result
1870
1932
  }, (ctx, n) => {
1871
- if(this.glob.apply.value) {
1872
- requireCD.$value(true);
1873
- ctx.writeLine(`$runtime.bindText($cd, ${n.el}, () => ${n.exp});`);
1933
+ if(this.inuse.apply) {
1934
+ ctx.writeLine(`$runtime.bindText(${n.el}, () => ${n.exp});`);
1874
1935
  } else ctx.writeLine(`${n.el}.textContent = ${n.exp};`);
1875
1936
  });
1876
1937
  binds.push(bindText);
1877
- requireCD.$depends(bindText);
1878
1938
  }
1879
1939
 
1880
1940
  pe.parts.forEach(p => {
@@ -1893,6 +1953,7 @@
1893
1953
  lastStatic = tpl.push(n.value);
1894
1954
  }
1895
1955
  } else if(n.type === 'template') {
1956
+ if(isRoot) lastTagDynamic = false;
1896
1957
  lastStatic = null;
1897
1958
  tpl.push(n.openTag);
1898
1959
  tpl.push(n.content);
@@ -1900,11 +1961,12 @@
1900
1961
  } else if(n.type === 'node') {
1901
1962
  if(n.name == 'malina' && !option.malinaElement) {
1902
1963
  let b;
1903
- if(n.elArg == 'portal') b = this.attachPortal(n, requireCD);
1904
- else b = this.attachHead(n, requireCD);
1964
+ if(n.elArg == 'portal') b = this.attachPortal(n);
1965
+ else b = this.attachHead(n);
1905
1966
  b && binds.push(b);
1906
1967
  return;
1907
1968
  }
1969
+ if(isRoot) lastTagDynamic = false;
1908
1970
  if(n.name == 'component' || n.name.match(/^[A-Z]/)) {
1909
1971
  if(n.name == 'component' || !n.elArg) {
1910
1972
  // component
@@ -1913,61 +1975,59 @@
1913
1975
 
1914
1976
  if(n.name == 'component') {
1915
1977
  // dyn-component
1916
- binds.push(this.makeComponentDyn(n, requireCD, el));
1978
+ binds.push(this.makeComponentDyn(n, el));
1917
1979
  } else {
1918
- let component = this.makeComponent(n, requireCD);
1919
- binds.push(xNode('attach-component', {
1980
+ let component = this.makeComponent(n);
1981
+ binds.push(xNode('insert-component', {
1920
1982
  component: component.bind,
1921
1983
  el: el.bindName()
1922
1984
  }, (ctx, n) => {
1923
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, `);
1985
+ ctx.write(true, `$runtime.insertAfter(${n.el}, `);
1924
1986
  ctx.add(n.component);
1925
- ctx.write(')');
1987
+ ctx.write('.$dom);');
1926
1988
  }));
1927
1989
  }
1928
1990
  } else {
1991
+ if(isRoot) requireFragment = true;
1929
1992
  let el = placeLabel(`exported ${n.elArg}`);
1930
- let b = this.attchExportedFragment(n, el, n.name, requireCD);
1993
+ let b = this.attchExportedFragment(n, el, n.name);
1931
1994
  b && binds.push(b);
1932
1995
  }
1933
1996
  return;
1934
1997
  }
1935
1998
  if(n.name == 'slot') {
1999
+ if(isRoot) requireFragment = true;
1936
2000
  let slotName = n.elArg;
1937
2001
  if(!slotName) {
1938
2002
  if(option.context == 'fragment') {
1939
2003
  let el = placeLabel('fragment-slot');
1940
- binds.push(this.attachFragmentSlot(el, requireCD));
2004
+ binds.push(this.attachFragmentSlot(el));
1941
2005
  return;
1942
2006
  } else slotName = 'default';
1943
2007
  }
1944
2008
 
1945
2009
  let el = placeLabel(slotName);
1946
- let slot = this.attachSlot(slotName, n, requireCD);
2010
+ let slot = this.attachSlot(slotName, n);
1947
2011
 
1948
2012
  binds.push(xNode('attach-slot', {
1949
- $deps: [requireCD],
1950
2013
  $compile: [slot],
1951
2014
  el: el.bindName(),
1952
- slot,
1953
- requireCD
2015
+ slot
1954
2016
  }, (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}, `);
2017
+ ctx.write(true, `$runtime.attachBlock(${n.el}, `);
1957
2018
  ctx.add(n.slot);
1958
2019
  ctx.write(');', true);
1959
2020
  }));
1960
2021
  return;
1961
2022
  }
1962
2023
  if(n.name == 'fragment') {
1963
- requireCD.$value(true);
1964
2024
  assert(n.elArg, 'Fragment name is required');
1965
2025
  let el = placeLabel(`fragment ${n.elArg}`);
1966
2026
  binds.push(xNode('attach-fragment', {
1967
2027
  el: el.bindName(),
1968
2028
  fragment: this.attachFragment(n)
1969
2029
  }, (ctx, n) => {
1970
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, `);
2030
+ ctx.write(true, `$runtime.attachBlock(${n.el}, `);
1971
2031
  ctx.add(n.fragment);
1972
2032
  ctx.write(')');
1973
2033
  }));
@@ -1980,18 +2040,18 @@
1980
2040
  lastStatic = el;
1981
2041
 
1982
2042
  if(n.attributes.some(a => a.name.startsWith('{...'))) {
2043
+ this.require('rootCD');
1983
2044
  n.spreading = [];
1984
- requireCD.$value(true);
1985
2045
  binds.push(xNode('spread-to-element', {
1986
2046
  el: el.bindName(),
1987
2047
  props: n.spreading
1988
2048
  }, (ctx, n) => {
1989
- ctx.writeLine(`$runtime.spreadAttributes($cd, ${n.el}, () => ({${n.props.join(', ')}}));`);
2049
+ ctx.writeLine(`$runtime.spreadAttributes(${n.el}, () => ({${n.props.join(', ')}}));`);
1990
2050
  }));
1991
2051
  }
1992
2052
  let bindTail = [];
1993
2053
  n.attributes.forEach(p => {
1994
- let b = this.bindProp(p, n, el, requireCD);
2054
+ let b = this.bindProp(p, n, el);
1995
2055
  if(b) {
1996
2056
  if(b.bind) binds.push(b.bind);
1997
2057
  if(b.bindTail) bindTail.push(b.bindTail);
@@ -2004,7 +2064,7 @@
2004
2064
  binds.push(xNode('bindAttributes', { el }, (ctx, n) => {
2005
2065
  let elName = n.el.bindName();
2006
2066
  n.el.attributes.forEach(a => {
2007
- ctx.writeLine(`${elName}.setAttribute('${a.name}', \`${this.Q(a.value)}\`);`);
2067
+ ctx.writeLine(`${elName}.setAttribute('${a.name}', \`${Q(a.value)}\`);`);
2008
2068
  });
2009
2069
  }));
2010
2070
  binds.push(xNode('bindClasses', { el }, (ctx, n) => {
@@ -2023,7 +2083,6 @@
2023
2083
  go(n, false, el);
2024
2084
  }
2025
2085
  } else if(n.type === 'each') {
2026
- requireCD.$value(true);
2027
2086
  if(data.type == 'node' && data.body.length == 1) {
2028
2087
  lastStatic = null;
2029
2088
  let eachBlock = this.makeEachBlock(n, {
@@ -2033,15 +2092,22 @@
2033
2092
  binds.push(eachBlock.source);
2034
2093
  return;
2035
2094
  } else {
2036
- if(isRoot) requireFragment = true;
2095
+ if(isRoot) {
2096
+ requireFragment = true;
2097
+ lastTagDynamic = true;
2098
+ }
2037
2099
  let element = placeLabel(n.value);
2038
2100
  let eachBlock = this.makeEachBlock(n, { elName: element.bindName() });
2039
2101
  binds.push(eachBlock.source);
2040
2102
  return;
2041
2103
  }
2042
2104
  } else if(n.type === 'if') {
2043
- if(isRoot) requireFragment = true;
2044
- binds.push(this.makeifBlock(n, placeLabel(n.value), requireCD));
2105
+ if(isRoot) {
2106
+ requireFragment = true;
2107
+ lastTagDynamic = true;
2108
+ }
2109
+ if(nodeIndex == 0 && !isRoot) binds.push(this.makeifBlock(n, tpl, true));
2110
+ else binds.push(this.makeifBlock(n, placeLabel(n.value)));
2045
2111
  return;
2046
2112
  } else if(n.type === 'systag') {
2047
2113
  let r = n.value.match(/^@(\w+)\s+(.*)$/s);
@@ -2049,41 +2115,43 @@
2049
2115
  let exp = r[2];
2050
2116
 
2051
2117
  if(name == 'html') {
2052
- if(isRoot) requireFragment = true;
2118
+ if(isRoot) {
2119
+ requireFragment = true;
2120
+ lastTagDynamic = true;
2121
+ }
2053
2122
  let el = placeLabel('html');
2054
- binds.push(this.makeHtmlBlock(exp, el, requireCD));
2123
+ binds.push(this.makeHtmlBlock(exp, el));
2055
2124
  return;
2056
2125
  } else throw 'Wrong tag';
2057
2126
  } else if(n.type === 'await') {
2058
- if(isRoot) requireFragment = true;
2059
- requireCD.$value(true);
2127
+ if(isRoot) {
2128
+ requireFragment = true;
2129
+ lastTagDynamic = true;
2130
+ }
2060
2131
  let el = placeLabel(n.value);
2061
2132
  let r = this.makeAwaitBlock(n, el);
2062
2133
  r && binds.push(r);
2063
2134
  return;
2064
2135
  } else if(n.type === 'comment') {
2136
+ if(isRoot) lastTagDynamic = false;
2065
2137
  lastStatic = tpl.push(n.content);
2066
2138
  }
2067
2139
  };
2068
- body.forEach(node => {
2140
+ body.forEach((node, i) => {
2069
2141
  try {
2070
- bindNode(node);
2142
+ bindNode(node, i);
2071
2143
  } catch (e) {
2072
2144
  wrapException(e, node);
2073
2145
  }
2074
2146
  });
2075
2147
  };
2076
2148
  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
- }
2149
+ if(option.protectLastTag && lastTagDynamic) {
2150
+ rootTemplate.push(xNode('node:comment', { value: '' }));
2082
2151
  }
2083
2152
 
2084
2153
  let innerBlock = null;
2085
2154
  if(binds.body.length) {
2086
- binds.push(requireCD);
2087
2155
  innerBlock = xNode('block');
2088
2156
  if(!option.oneElement) {
2089
2157
  innerBlock.push(xNode('bindNodes', {
@@ -2120,7 +2188,6 @@
2120
2188
  result.source = innerBlock;
2121
2189
  }
2122
2190
  } else {
2123
- result.requireCD.$done = true;
2124
2191
  result.name = '$runtime.noop';
2125
2192
  result.source = null;
2126
2193
  }
@@ -2135,30 +2202,26 @@
2135
2202
  else template.inline = true;
2136
2203
 
2137
2204
  result.block = xNode('block', {
2138
- $compile: [innerBlock, requireCD],
2139
- $deps: [requireCD],
2140
- requireCD,
2205
+ $compile: [innerBlock],
2141
2206
  innerBlock,
2142
2207
  tpl: template,
2143
2208
  each: option.each,
2144
2209
  parentElement: option.parentElement
2145
2210
  }, (ctx, n) => {
2146
2211
  if(n.each && !ctx.isEmpty(n.innerBlock)) {
2147
- if(n.requireCD.value) ctx.write('$runtime.makeEachBlock(');
2148
- else ctx.write('$runtime.makeStaticEachBlock(');
2212
+ ctx.write('$runtime.makeEachBlock(');
2149
2213
  } else {
2150
- if(n.requireCD.value) ctx.write('$runtime.makeBlock(');
2151
- else ctx.write('$runtime.makeStaticBlock(');
2214
+ ctx.write('$runtime.makeBlock(');
2152
2215
  }
2153
2216
  ctx.add(n.tpl);
2154
2217
  if(!ctx.isEmpty(n.innerBlock)) {
2155
2218
  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);
2219
+ ctx.write(`, (${n.parentElement}, ${n.each.itemName}`);
2220
+ if(n.each.indexName) ctx.write(`, ${n.each.indexName}`);
2221
+ ctx.write(`) => {`, true);
2158
2222
  } else {
2159
2223
  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);
2224
+ ctx.write(`, (${n.parentElement}${extra}) => {`, true);
2162
2225
  }
2163
2226
  ctx.indent++;
2164
2227
  ctx.add(n.innerBlock);
@@ -4427,13 +4490,12 @@
4427
4490
  return result;
4428
4491
  };
4429
4492
 
4430
- function makeComponent(node, requireCD) {
4493
+ function makeComponent(node) {
4431
4494
  this.require('apply');
4432
4495
 
4433
4496
  let propList = node.attributes;
4434
4497
 
4435
4498
  this.require('$context');
4436
- requireCD.$value(true); // FIX
4437
4499
 
4438
4500
  let reference = null;
4439
4501
  let propsFn = [], propsSetter = [], $class = [], staticProps = true;
@@ -4510,12 +4572,11 @@
4510
4572
  }
4511
4573
 
4512
4574
  if(props) this.require('apply');
4513
- requireCD.$value(true); // FIXME
4514
4575
 
4515
4576
  let block = this.buildBlock(slot, { inline: true });
4516
4577
 
4517
4578
  slotBlocks.push(xNode('slot', {
4518
- $deps: [this.glob.apply],
4579
+ $wait: ['apply'],
4519
4580
  name: slot.name,
4520
4581
  template: block.template,
4521
4582
  bind: block.source,
@@ -4523,20 +4584,20 @@
4523
4584
  props
4524
4585
  }, (ctx, n) => {
4525
4586
  if(n.bind) {
4526
- ctx.write(true, `${n.name}: $runtime.makeSlot($cd, `);
4587
+ ctx.write(true, `${n.name}: $runtime.makeSlot(`);
4527
4588
  ctx.add(n.template);
4528
- ctx.write(`, ($cd, $parentElement, $context, $instance_${n.componentName}`);
4589
+ ctx.write(`, ($parentElement, $context, $instance_${n.componentName}`);
4529
4590
  if(n.props) ctx.write(', $localProps');
4530
4591
  ctx.write(') => {', true);
4531
4592
  ctx.indent++;
4532
4593
  if(n.props) ctx.write(true, `let {${n.props.join(', ')}} = $localProps;`);
4533
4594
  ctx.add(n.bind);
4534
4595
 
4535
- if(n.props && this.glob.apply.value) ctx.write(true, `return ($localProps) => ({${n.props.join(', ')}} = $localProps, $$apply());`);
4596
+ if(n.props && this.inuse.apply) ctx.write(true, `return ($localProps) => ({${n.props.join(', ')}} = $localProps, $$apply());`);
4536
4597
  ctx.indent--;
4537
4598
  ctx.writeLine('})');
4538
4599
  } else {
4539
- ctx.write(true, `${n.name}: $runtime.makeStaticBlock(`);
4600
+ ctx.write(true, `${n.name}: $runtime.makeBlock(`);
4540
4601
  ctx.add(n.template);
4541
4602
  ctx.write(')');
4542
4603
  }
@@ -4551,18 +4612,14 @@
4551
4612
 
4552
4613
  anchorBlocks.push(xNode('anchor', {
4553
4614
  $compile: [block],
4554
- $deps: [bb.requireCD],
4555
4615
  name,
4556
4616
  block
4557
4617
  }, (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) => {`);
4618
+ ctx.write(`${n.name}: $runtime.makeAnchor((el) => {`);
4561
4619
  ctx.indent++;
4562
4620
  ctx.build(n.block);
4563
4621
  ctx.indent--;
4564
- if(useCD) ctx.write(true, '}}');
4565
- else ctx.write(true, '}');
4622
+ ctx.write(true, '})');
4566
4623
  }));
4567
4624
  });
4568
4625
  }
@@ -4780,7 +4837,7 @@
4780
4837
  return { bind: result };
4781
4838
  }
4782
4839
 
4783
- function makeComponentDyn(node, requireCD, element) {
4840
+ function makeComponentDyn(node, element) {
4784
4841
  let dynamicComponent;
4785
4842
 
4786
4843
  if(node.elArg) {
@@ -4796,9 +4853,8 @@
4796
4853
 
4797
4854
  assert(dynamicComponent);
4798
4855
  this.detectDependency(dynamicComponent);
4799
- requireCD.$value(true);
4800
4856
 
4801
- let component = this.makeComponent(node, requireCD).bind;
4857
+ let component = this.makeComponent(node).bind;
4802
4858
 
4803
4859
  component.componentName = '$ComponentConstructor';
4804
4860
  return xNode('dyn-component', {
@@ -4806,13 +4862,13 @@
4806
4862
  exp: dynamicComponent,
4807
4863
  component
4808
4864
  }, (ctx, n) => {
4809
- ctx.write(true, `$runtime.attachDynComponent($cd, ${n.el}, () => ${n.exp}, ($ComponentConstructor) => `);
4865
+ ctx.write(true, `$runtime.attachDynComponent(${n.el}, () => ${n.exp}, ($ComponentConstructor) => `);
4810
4866
  ctx.add(n.component);
4811
4867
  ctx.write(')');
4812
4868
  });
4813
4869
  }
4814
4870
 
4815
- function bindProp(prop, node, element, requireCD) {
4871
+ function bindProp(prop, node, element) {
4816
4872
  let name, arg;
4817
4873
 
4818
4874
  if(prop.content.startsWith('{*')) {
@@ -4876,13 +4932,17 @@
4876
4932
 
4877
4933
  if(name[0] == '#') {
4878
4934
  let target = name.substring(1);
4879
- assert(isSimpleName(target), target);
4880
- this.checkRootName(target);
4881
- return { bind: `${target}=${element.bindName()};` };
4935
+ assert(detectExpressionType(target) == 'identifier', name);
4936
+ return { bind: xNode('reference-to-element', {
4937
+ target,
4938
+ el: element.bindName()
4939
+ }, (ctx, n) => {
4940
+ ctx.write(true, `${n.target} = ${n.el};`);
4941
+ ctx.write(true, `$runtime.$onDestroy(() => ${n.target} = null);`);
4942
+ })};
4882
4943
  } else if(name == 'event') {
4883
4944
  if(prop.name.startsWith('@@')) {
4884
4945
  assert(!prop.value);
4885
- requireCD.$value(true);
4886
4946
  this.require('$events');
4887
4947
  if(prop.name == '@@') {
4888
4948
  return {
@@ -4891,7 +4951,7 @@
4891
4951
  }, (ctx, data) => {
4892
4952
  ctx.writeLine('for(let event in $events)');
4893
4953
  ctx.goIndent(() => {
4894
- ctx.writeLine(`$runtime.addEvent($cd, ${data.el}, event, $events[event]);`);
4954
+ ctx.writeLine(`$runtime.addEvent(${data.el}, event, $events[event]);`);
4895
4955
  });
4896
4956
  })
4897
4957
  };
@@ -4902,14 +4962,13 @@
4902
4962
  event: prop.name.substring(2),
4903
4963
  el: element.bindName()
4904
4964
  }, (ctx, n) => {
4905
- ctx.writeLine(`$events.${n.event} && $runtime.addEvent($cd, ${n.el}, '${n.event}', $events.${n.event});`);
4965
+ ctx.writeLine(`$events.${n.event} && $runtime.addEvent(${n.el}, '${n.event}', $events.${n.event});`);
4906
4966
  })
4907
4967
  };
4908
4968
  }
4909
4969
 
4910
4970
  let { event, fn, rootModifier } = this.makeEventProp(prop, () => element.bindName());
4911
4971
  if(rootModifier) this.require('rootEvent');
4912
- else requireCD.$value(true);
4913
4972
 
4914
4973
  return {
4915
4974
  bind: xNode('bindEvent', {
@@ -4919,7 +4978,7 @@
4919
4978
  rootModifier
4920
4979
  }, (ctx, n) => {
4921
4980
  if(n.rootModifier) ctx.write(true, `$$addRootEvent(${n.el}, '${n.event}', `);
4922
- else ctx.write(true, `$runtime.addEvent($cd, ${n.el}, '${n.event}', `);
4981
+ else ctx.write(true, `$runtime.addEvent(${n.el}, '${n.event}', `);
4923
4982
  ctx.build(n.fn);
4924
4983
  ctx.write(');');
4925
4984
  })
@@ -4930,7 +4989,6 @@
4930
4989
  return;
4931
4990
  }
4932
4991
 
4933
- requireCD.$value(true);
4934
4992
  this.require('apply');
4935
4993
  let exp;
4936
4994
  arg = arg.split(/[:|]/);
@@ -4964,7 +5022,7 @@
4964
5022
  bind: xNode('bindInput', {
4965
5023
  el: element.bindName()
4966
5024
  }, (ctx, n) => {
4967
- ctx.writeLine(`$runtime.bindInput($cd, ${n.el}, '${attr}', () => ${exp}, ${argName} => {${exp} = ${argName}; $$apply();});`);
5025
+ ctx.writeLine(`$runtime.bindInput(${n.el}, '${attr}', () => ${exp}, ${argName} => {${exp} = ${argName}; $$apply();});`);
4968
5026
  })
4969
5027
  };
4970
5028
  } else if(name == 'style' && arg) {
@@ -4986,7 +5044,7 @@
4986
5044
  name: styleName,
4987
5045
  value: prop.value
4988
5046
  }, (ctx, n) => {
4989
- ctx.writeLine(`${n.el}.style.${n.name} = \`${this.Q(n.value)}\`;`);
5047
+ ctx.writeLine(`${n.el}.style.${n.name} = \`${Q(n.value)}\`;`);
4990
5048
  })
4991
5049
  };
4992
5050
  }
@@ -5007,7 +5065,7 @@
5007
5065
  }, (ctx, n) => {
5008
5066
  if(n.hasElement) ctx.writeLine(`let $element=${n.el};`);
5009
5067
  if(ctx.inuse.apply) {
5010
- ctx.writeLine(`$runtime.bindStyle($cd, ${n.el}, '${n.styleName}', () => (${n.exp}));`);
5068
+ ctx.writeLine(`$runtime.bindStyle(${n.el}, '${n.styleName}', () => (${n.exp}));`);
5011
5069
  } else {
5012
5070
  ctx.writeLine(`${n.el}.style.${n.styleName} = ${n.exp};`);
5013
5071
  }
@@ -5016,21 +5074,21 @@
5016
5074
  };
5017
5075
  } else if(name == 'use') {
5018
5076
  if(arg) {
5019
- requireCD.$value(true);
5020
5077
  assert(isSimpleName(arg), 'Wrong name: ' + arg);
5021
5078
  this.checkRootName(arg);
5022
5079
  let args = prop.value ? `, () => [${getExpression()}]` : '';
5023
5080
  this.detectDependency(args);
5024
5081
  return {
5025
5082
  bind: xNode('action', {
5083
+ $wait: ['apply'],
5026
5084
  name: arg,
5027
5085
  args,
5028
5086
  el: element.bindName()
5029
5087
  }, (ctx, n) => {
5030
5088
  if(ctx.inuse.apply && n.args) {
5031
- ctx.writeLine(`$runtime.bindAction($cd, ${n.el}, ${n.name}${n.args}, $runtime.__bindActionSubscribe);`);
5089
+ ctx.writeLine(`$runtime.bindAction(${n.el}, ${n.name}${n.args}, $runtime.__bindActionSubscribe);`);
5032
5090
  } else {
5033
- ctx.writeLine(`$runtime.bindAction($cd, ${n.el}, ${n.name}${n.args});`);
5091
+ ctx.writeLine(`$runtime.bindAction(${n.el}, ${n.name}${n.args});`);
5034
5092
  }
5035
5093
  })
5036
5094
  };
@@ -5075,10 +5133,13 @@
5075
5133
  classes = [prop.name.slice(6)];
5076
5134
  }
5077
5135
  return this.config.passClass && classes.some(name => {
5078
- if(this.css.isExternalClass(name)) compound = true;
5079
- else if(name[0] == '$') {
5136
+ if(this.css.isExternalClass(name)) {
5137
+ compound = true;
5138
+ this.require('apply');
5139
+ } else if(name[0] == '$') {
5080
5140
  this.css.markAsExternal(name.substring(1));
5081
5141
  compound = true;
5142
+ this.require('apply');
5082
5143
  }
5083
5144
  });
5084
5145
  });
@@ -5095,14 +5156,14 @@
5095
5156
  assert(className);
5096
5157
  let exp = prop.value ? unwrapExp(prop.value) : className;
5097
5158
  this.detectDependency(exp);
5098
- return `(${exp}) ? \`${this.Q(className)}\` : ''`;
5159
+ return `(${exp}) ? \`${Q(className)}\` : ''`;
5099
5160
  }
5100
5161
  }).join(') + \' \' + (');
5101
5162
  const bind = xNode('compound-class', {
5163
+ $wait: ['apply'],
5102
5164
  el: element.bindName(),
5103
5165
  exp,
5104
- classes,
5105
- requireCD
5166
+ classes
5106
5167
  }, (ctx, n) => {
5107
5168
  let base = '';
5108
5169
  if(n.classes.length) {
@@ -5120,21 +5181,18 @@
5120
5181
 
5121
5182
  if(ctx.inuse.resolveClass) {
5122
5183
  if(ctx.inuse.apply) {
5123
- n.requireCD.$value(true);
5124
- ctx.write(true, `$runtime.bindClassExp($cd, ${n.el}, () => $$resolveClass((${n.exp})${base}))`);
5184
+ ctx.write(true, `$runtime.bindClassExp(${n.el}, () => $$resolveClass((${n.exp})${base}))`);
5125
5185
  } else {
5126
5186
  ctx.write(true, `$runtime.setClassToElement(${n.el}, $$resolveClass((${n.exp})${base}));`);
5127
5187
  }
5128
5188
  } else {
5129
5189
  if(ctx.inuse.apply) {
5130
- n.requireCD.$value(true);
5131
- ctx.write(true, `$runtime.bindClassExp($cd, ${n.el}, () => (${n.exp})${base})`);
5190
+ ctx.write(true, `$runtime.bindClassExp(${n.el}, () => (${n.exp})${base})`);
5132
5191
  } else {
5133
5192
  ctx.write(true, `$runtime.setClassToElement(${n.el}, ${n.exp}${base});`);
5134
5193
  }
5135
5194
  }
5136
5195
  });
5137
- requireCD.$depends(bind);
5138
5196
  return { bind };
5139
5197
  } else {
5140
5198
  let bind = xNode('block');
@@ -5150,21 +5208,19 @@
5150
5208
  this.detectDependency(exp);
5151
5209
 
5152
5210
  let n = xNode('bindClass', {
5153
- $deps: [this.glob.apply],
5211
+ $wait: ['apply'],
5154
5212
  el: element.bindName(),
5155
5213
  className,
5156
5214
  exp,
5157
- $element: exp.includes('$element'),
5158
- requireCD
5215
+ $element: exp.includes('$element')
5159
5216
  }, (ctx, n) => {
5160
5217
  if(n.$element) {
5161
5218
  ctx.writeLine('{');
5162
5219
  ctx.indent++;
5163
5220
  ctx.writeLine(`let $element = ${n.el};`);
5164
5221
  }
5165
- if(this.glob.apply.value) {
5166
- n.requireCD.$value(true);
5167
- ctx.writeLine(`$runtime.bindClass($cd, ${n.el}, () => !!(${n.exp}), '${n.className}');`);
5222
+ if(this.inuse.apply) {
5223
+ ctx.writeLine(`$runtime.bindClass(${n.el}, () => !!(${n.exp}), '${n.className}');`);
5168
5224
  } else {
5169
5225
  ctx.writeLine(`(${n.exp}) && $runtime.addClass(${n.el}, '${n.className}');`);
5170
5226
  }
@@ -5173,20 +5229,18 @@
5173
5229
  ctx.writeLine('}');
5174
5230
  }
5175
5231
  });
5176
- requireCD.$depends(n);
5177
5232
  bind.push(n);
5178
5233
  }
5179
5234
  });
5180
5235
  return { bind: bind.body.length ? bind : null };
5181
5236
  }
5182
5237
  } else if(name[0] == '^') {
5183
- requireCD.$value(true);
5184
5238
  return {
5185
5239
  bindTail: xNode('bindAnchor', {
5186
5240
  name: name.slice(1) || 'default',
5187
5241
  el: element.bindName()
5188
5242
  }, (ctx, n) => {
5189
- ctx.write(true, `$runtime.attachAnchor($option, $cd, ${n.el}`);
5243
+ ctx.write(true, `$runtime.attachAnchor($option, ${n.el}`);
5190
5244
  if(n.name == 'default') ctx.write(');');
5191
5245
  else ctx.write(`, '${n.name}');`);
5192
5246
  })
@@ -5213,31 +5267,28 @@
5213
5267
  };
5214
5268
 
5215
5269
  let n = xNode('bindAttribute', {
5270
+ $wait: ['apply'],
5216
5271
  name,
5217
5272
  exp,
5218
5273
  hasElement,
5219
- el: element.bindName(),
5220
- requireCD
5274
+ el: element.bindName()
5221
5275
  }, (ctx, data) => {
5222
5276
  if(data.hasElement) ctx.writeLine(`let $element=${data.el};`);
5223
5277
  if(propList[name]) {
5224
5278
  let propName = propList[name] === true ? name : propList[name];
5225
5279
  if(ctx.inuse.apply) {
5226
- requireCD.$value(true);
5227
- ctx.writeLine(`$watchReadOnly($cd, () => (${data.exp}), (value) => {${data.el}.${propName} = value;});`);
5280
+ ctx.writeLine(`$watch(() => (${data.exp}), (value) => {${data.el}.${propName} = value;});`);
5228
5281
  } else {
5229
5282
  ctx.writeLine(`${data.el}.${propName} = ${data.exp};`);
5230
5283
  }
5231
5284
  } else {
5232
5285
  if(ctx.inuse.apply) {
5233
- requireCD.$value(true);
5234
- ctx.writeLine(`$runtime.bindAttribute($cd, ${data.el}, '${data.name}', () => (${data.exp}));`);
5286
+ ctx.writeLine(`$runtime.bindAttribute(${data.el}, '${data.name}', () => (${data.exp}));`);
5235
5287
  } else {
5236
5288
  ctx.writeLine(`$runtime.bindAttributeBase(${data.el}, '${data.name}', ${data.exp});`);
5237
5289
  }
5238
5290
  }
5239
5291
  });
5240
- requireCD.$depends(n);
5241
5292
 
5242
5293
  return {
5243
5294
  bind: xNode('block', {
@@ -5247,7 +5298,7 @@
5247
5298
  };
5248
5299
  }
5249
5300
 
5250
- if(node.spreading) return node.spreading.push(`${name}: \`${this.Q(prop.value)}\``);
5301
+ if(node.spreading) return node.spreading.push(`${name}: \`${Q(prop.value)}\``);
5251
5302
 
5252
5303
  element.attributes.push({
5253
5304
  name: prop.name,
@@ -5256,12 +5307,11 @@
5256
5307
  }
5257
5308
  }
5258
5309
 
5259
- function makeifBlock(data, element, requireCD) {
5310
+ function makeifBlock(data, element, parentElement) {
5260
5311
  let r = data.value.match(/^#if (.*)$/s);
5261
5312
  let exp = r[1];
5262
5313
  assert(exp, 'Wrong binding: ' + data.value);
5263
5314
  this.detectDependency(exp);
5264
- this.require('$cd');
5265
5315
 
5266
5316
  let mainBlock, elseBlock;
5267
5317
 
@@ -5284,20 +5334,19 @@
5284
5334
  mainBlock = getBlock(this.buildBlock(data, { protectLastTag: true, allowSingleBlock: true }));
5285
5335
  }
5286
5336
 
5287
- const result = xNode('if:bind', {
5288
- $deps: [this.glob.apply],
5289
- requireCD,
5337
+ return xNode('if:bind', {
5338
+ $wait: ['apply'],
5290
5339
  el: element.bindName(),
5340
+ parentElement,
5291
5341
  exp,
5292
5342
  mainBlock: mainBlock,
5293
5343
  elseBlock: elseBlock
5294
5344
  }, (ctx, n) => {
5295
- if(this.glob.apply.value) {
5296
- n.requireCD.$value(true);
5297
- ctx.write(true, `$runtime.ifBlock($cd, ${n.el}, () => !!(${n.exp}),`);
5345
+ let missing = '';
5346
+ if(this.inuse.apply) {
5347
+ ctx.write(true, `$runtime.ifBlock(${n.el}, () => !!(${n.exp}),`);
5298
5348
  } else {
5299
- this.glob.component.$value(true);
5300
- ctx.write(true, `$runtime.ifBlockReadOnly($component, ${n.el}, () => !!(${n.exp}),`);
5349
+ ctx.write(true, `$runtime.ifBlockReadOnly(${n.el}, () => !!(${n.exp}),`);
5301
5350
  }
5302
5351
 
5303
5352
  ctx.indent++;
@@ -5306,24 +5355,23 @@
5306
5355
  if(n.elseBlock) {
5307
5356
  ctx.write(',');
5308
5357
  ctx.add(n.elseBlock);
5309
- }
5358
+ } else missing = ', null';
5310
5359
  ctx.indent--;
5311
- ctx.write(true, ');', true);
5360
+ ctx.write(true);
5361
+ if(n.parentElement) ctx.write(missing + ', true');
5362
+ ctx.write(');', true);
5312
5363
  });
5313
- requireCD.$depends(result);
5314
- this.glob.component.$depends(result);
5315
- return result;
5316
5364
  }
5317
5365
 
5318
5366
  function makeEachBlock(data, option) {
5319
- this.require('apply');
5367
+ this.require('rootCD');
5320
5368
 
5321
5369
  // #each items as item, index (key)
5322
5370
  let rx = data.value.match(/^#each\s+(.+)\s+as\s+(.+)$/s);
5323
5371
  assert(rx, `Wrong #each expression '${data.value}'`);
5324
5372
  let arrayName = rx[1];
5325
5373
  let right = rx[2];
5326
- let keyName;
5374
+ let keyName, keyFunction = null;
5327
5375
 
5328
5376
  // get keyName
5329
5377
  rx = right.match(/^(.*)\s*\(\s*([^()]+)\s*\)\s*$/s);
@@ -5333,73 +5381,105 @@
5333
5381
  }
5334
5382
  right = right.trim();
5335
5383
 
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;
5384
+ const makeKeyFunction = (keyLink) => {
5385
+ const e = parseJS(keyName).transform((n, pk) => {
5386
+ if(n.type != 'Identifier') return;
5387
+ if(pk == 'property') return;
5388
+ let r = keyLink[n.name];
5389
+ if(r) n.name = r;
5390
+ });
5391
+ let exp = e.build(e.ast.body[0].expression);
5392
+ keyFunction = xNode('key-function', {
5393
+ exp
5394
+ }, (ctx, n) => {
5395
+ ctx.write(`($$item, $index) => ${n.exp}`);
5396
+ });
5397
+ };
5341
5398
 
5399
+ let itemName, indexName = null, blockPrefix = null;
5400
+ if(right[0] == '{' || right[0] == '[') {
5401
+ let keywords, unwrap;
5342
5402
  try {
5343
- keywords = acorn.parse(`(${exp} = $$item)`, { sourceType: 'module', ecmaVersion: 12 }).body[0].expression.left.properties.map(p => p.key.name);
5403
+ let exp = `[${right}]`;
5404
+ let e = parseJS(exp);
5405
+ assert(e.ast.body.length == 1);
5406
+
5407
+ itemName = '$$item';
5408
+ let n = e.ast.body[0];
5409
+ assert(n.expression.elements.length == 1 || n.expression.elements.length == 2);
5410
+ let a = n.expression.elements[0];
5411
+ unwrap = exp.substring(a.start, a.end);
5412
+
5413
+ if(n.expression.elements.length == 2) {
5414
+ let b = n.expression.elements[1];
5415
+ assert(b.type == 'Identifier');
5416
+ indexName = exp.substring(b.start, b.end);
5417
+ }
5418
+
5419
+ e = parseJS(`(${unwrap} = $$item)`);
5420
+ let l = e.ast.body[0].expression.left;
5421
+ if(l.type == 'ArrayPattern') {
5422
+ keywords = l.elements.map(p => p.name);
5423
+
5424
+ if(keyName) {
5425
+ let keyLink = {};
5426
+ if(indexName) keyLink[indexName] = '$index';
5427
+ for(let i in keywords) keyLink[keywords[i]] = `$$item[${i}]`;
5428
+ makeKeyFunction(keyLink);
5429
+ }
5430
+ } else {
5431
+ assert(l.type == 'ObjectPattern');
5432
+ keywords = l.properties.map(p => p.key.name);
5433
+
5434
+ if(keyName) {
5435
+ let keyLink = {};
5436
+ if(indexName) keyLink[indexName] = '$index';
5437
+ for(let k of keywords) keyLink[k] = `$$item.${k}`;
5438
+ makeKeyFunction(keyLink);
5439
+ }
5440
+ }
5344
5441
  } catch (e) {
5345
5442
  throw new Error('Wrong destructuring in each: ' + data.value);
5346
5443
  }
5347
5444
 
5348
- itemName = '$$item';
5349
- indexName = rx[2].trim();
5350
- if(indexName[0] == ',') indexName = indexName.substring(1).trim();
5351
- indexName = indexName || '$index';
5352
-
5353
5445
  blockPrefix = xNode('each:unwrap', {
5354
- exp,
5446
+ unwrap,
5355
5447
  keywords
5356
5448
  }, (ctx, n) => {
5357
- if(this.script.readOnly) ctx.writeLine(`let ${n.exp} = $$item;`);
5449
+ if(this.script.readOnly) ctx.writeLine(`let ${n.unwrap} = $$item;`);
5358
5450
  else {
5359
5451
  ctx.writeLine(`let ${n.keywords.join(', ')};`);
5360
- ctx.writeLine(`$runtime.prefixPush($cd, () => (${n.exp} = $$item));`);
5452
+ ctx.writeLine(`$runtime.prefixPush(() => (${n.unwrap} = $$item));`);
5361
5453
  }
5362
5454
  });
5363
5455
  } else {
5364
- rx = right.trim().split(/\s*,\s*/);
5456
+ rx = right.trim().split(/\s*\,\s*/);
5365
5457
  assert(rx.length <= 2, `Wrong #each expression '${data.value}'`);
5366
5458
  itemName = rx[0];
5367
- indexName = rx[1] || '$index';
5459
+ indexName = rx[1] || null;
5460
+ if(keyName) {
5461
+ if(keyName == itemName) keyFunction = 'noop';
5462
+ else {
5463
+ let keyLink = {[itemName]: '$$item'};
5464
+ if(indexName) keyLink[indexName] = '$index';
5465
+ makeKeyFunction(keyLink);
5466
+ }
5467
+ }
5368
5468
  }
5369
5469
  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
5470
 
5395
5471
  let rebind;
5396
5472
  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
- });
5473
+ if(!indexName && keyName == itemName) rebind = null;
5474
+ else {
5475
+ rebind = xNode('block', {
5476
+ itemName,
5477
+ indexName
5478
+ }, (ctx, n) => {
5479
+ if(n.indexName) ctx.write(`(_${n.itemName}, _${n.indexName}) => {${n.itemName}=_${n.itemName}; ${n.indexName}=_${n.indexName};}`);
5480
+ else ctx.write(`(_${n.itemName}) => {${n.itemName}=_${n.itemName};}`);
5481
+ });
5482
+ }
5403
5483
  }
5404
5484
 
5405
5485
  let nodeItems = trimEmptyNodes(data.body);
@@ -5423,10 +5503,13 @@
5423
5503
  itemName,
5424
5504
  indexName
5425
5505
  }, (ctx, n) => {
5426
- ctx.write(`$runtime.makeEachSingleBlock((${n.itemName}, ${n.indexName}) => [`);
5506
+ ctx.write(`$runtime.makeEachSingleBlock((${n.itemName}`);
5507
+ if(n.indexName) ctx.write(`, ${n.indexName}`);
5508
+ ctx.write(`) => [`);
5427
5509
  ctx.indent++;
5428
5510
  ctx.write(true);
5429
- ctx.add(n.rebind);
5511
+ if(n.rebind) ctx.add(n.rebind);
5512
+ else ctx.write('null');
5430
5513
  ctx.write(',', true);
5431
5514
  ctx.add(n.block);
5432
5515
  ctx.indent--;
@@ -5438,7 +5521,7 @@
5438
5521
  keyFunction,
5439
5522
  block: itemBlock
5440
5523
  }, (ctx, n) => {
5441
- ctx.writeLine(`$runtime.$$eachBlock($cd, ${option.elName}, ${option.onlyChild ? 1 : 0}, () => (${arrayName}),`);
5524
+ ctx.writeLine(`$runtime.$$eachBlock(${option.elName}, ${option.onlyChild ? 1 : 0}, () => (${arrayName}),`);
5442
5525
  ctx.indent++;
5443
5526
  ctx.write(true);
5444
5527
  if(n.keyFunction === 'noop') ctx.write('$runtime.noop');
@@ -5454,25 +5537,16 @@
5454
5537
  return { source };
5455
5538
  }
5456
5539
 
5457
- function makeHtmlBlock(exp, label, requireCD) {
5540
+ function makeHtmlBlock(exp, label) {
5458
5541
  this.detectDependency(exp);
5459
- this.require('$cd');
5460
- const result = xNode('block', {
5461
- $deps: [this.glob.apply],
5542
+ return xNode('block', {
5543
+ $wait: ['apply'],
5462
5544
  el: label.bindName(),
5463
- exp,
5464
- requireCD
5545
+ exp
5465
5546
  }, (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}));`);
5547
+ if(this.inuse.apply) ctx.write(true, `$runtime.$$htmlBlock(${n.el}, () => (${n.exp}));`);
5548
+ else ctx.write(true, `$runtime.$$htmlBlockStatic(${n.el}, ${n.exp});`);
5472
5549
  });
5473
-
5474
- requireCD.$depends(result);
5475
- return result;
5476
5550
  }
5477
5551
 
5478
5552
  function makeAwaitBlock(node, element) {
@@ -5534,7 +5608,7 @@
5534
5608
  parts,
5535
5609
  keywords
5536
5610
  }, (ctx, n) => {
5537
- ctx.write(true, `$runtime.$$awaitBlock($cd, ${n.el}, () => [${n.keywords.join(', ')}], () => ${n.exp},`);
5611
+ ctx.write(true, `$runtime.$$awaitBlock(${n.el}, () => [${n.keywords.join(', ')}], () => ${n.exp},`);
5538
5612
  ctx.indent++;
5539
5613
  n.parts.forEach((part, index) => {
5540
5614
  if(index) ctx.write(', ');
@@ -5548,7 +5622,7 @@
5548
5622
  });
5549
5623
  }
5550
5624
 
5551
- function attachSlot(slotName, node, requireCD) {
5625
+ function attachSlot(slotName, node) {
5552
5626
  let props = [], staticProps = true;
5553
5627
 
5554
5628
  if(node.attributes && node.attributes.length) {
@@ -5568,19 +5642,16 @@
5568
5642
  if(node.body?.length) placeholder = this.buildBlock(node).block;
5569
5643
 
5570
5644
  this.require('$context');
5571
- this.glob.component.$value(true);
5645
+ this.require('$component');
5572
5646
 
5573
5647
  let result = xNode('slot', {
5574
- $deps: [this.glob.apply],
5648
+ $wait: ['apply'],
5575
5649
  name: slotName,
5576
5650
  props,
5577
5651
  staticProps,
5578
5652
  placeholder,
5579
- requireCD
5580
5653
  }, (ctx, n) => {
5581
- let dynamicProps = this.glob.apply.value && !n.staticProps;
5582
-
5583
- if(dynamicProps) n.requireCD.$value(true);
5654
+ let dynamicProps = this.inuse.apply && !n.staticProps;
5584
5655
 
5585
5656
  let missed = '', slotName = n.name == 'default' ? 'null' : n.name;
5586
5657
  if(dynamicProps) ctx.write(`$runtime.invokeSlot($component, ${slotName}, $context`);
@@ -5610,11 +5681,10 @@
5610
5681
  }
5611
5682
  ctx.write(')');
5612
5683
  });
5613
- requireCD.$depends(result);
5614
5684
  return result;
5615
5685
  }
5616
5686
 
5617
- function makeFragment(node, requireCD) {
5687
+ function makeFragment(node) {
5618
5688
  let rx = node.value.match(/#fragment:(\S+)(.*)$/s);
5619
5689
  assert(rx);
5620
5690
  let name = rx[1], external = false;
@@ -5630,8 +5700,6 @@
5630
5700
  });
5631
5701
  }
5632
5702
 
5633
- if(external) requireCD.$value(true);
5634
-
5635
5703
  let block;
5636
5704
  if(node.body && node.body.length) {
5637
5705
  block = this.buildBlock({ body: trimEmptyNodes(node.body) }, { inline: true, context: 'fragment', parentElement: '$dom' });
@@ -5643,27 +5711,24 @@
5643
5711
  }
5644
5712
 
5645
5713
  return xNode('fragment', {
5646
- $compile: [block.source, this.glob.apply],
5647
- $deps: [block.requireCD],
5714
+ $compile: [block.source],
5648
5715
  name,
5649
5716
  props,
5650
5717
  external,
5651
5718
  block
5652
5719
  }, (ctx, n) => {
5653
5720
  if(ctx.isEmpty(n.block.source)) {
5654
- ctx.write(true, `let $fragment_${n.name} = $runtime.makeStaticBlock(`);
5721
+ ctx.write(true, `let $fragment_${n.name} = $runtime.makeBlock(`);
5655
5722
  ctx.add(n.block.template);
5656
5723
  ctx.write(');');
5657
5724
  } else {
5658
5725
  ctx.write(true, `function $fragment_${n.name}($props, $events={}, $$fragmentSlot) {`);
5659
5726
  ctx.indent++;
5660
5727
 
5661
- if(n.block.requireCD.value) ctx.write(true, 'let $cd = $runtime.cd_new();');
5662
-
5663
5728
  if(n.props?.length) {
5664
- if(this.glob.apply.value) {
5729
+ if(this.inuse.apply) {
5665
5730
  ctx.writeLine('let ' + n.props.join(', ') + ';');
5666
- ctx.writeLine(`$runtime.unwrapProps($cd, $props, ($$) => ({${n.props.join(', ')}} = $$));`);
5731
+ ctx.writeLine(`$runtime.unwrapProps($props, ($$) => ({${n.props.join(', ')}} = $$));`);
5667
5732
  } else {
5668
5733
  ctx.writeLine('let ' + n.props.join(', ') + ';');
5669
5734
  ctx.writeLine(`$props && ({${n.props.join(', ')}} = ($runtime.isFunction($props) ? $props() : $props));`);
@@ -5671,17 +5736,17 @@
5671
5736
  }
5672
5737
 
5673
5738
  ctx.write(true, 'let $dom = ');
5739
+ n.block.template.cloneNode = true;
5674
5740
  ctx.add(n.block.template);
5675
5741
  ctx.write(';');
5676
5742
 
5677
5743
  ctx.add(n.block.source);
5678
- if(n.block.requireCD.value) ctx.write(true, 'return {$cd, $dom};');
5679
- else ctx.write(true, 'return {$dom};');
5744
+ ctx.write(true, 'return $dom;');
5680
5745
 
5681
5746
  ctx.indent--;
5682
5747
  ctx.writeLine('}');
5683
5748
  }
5684
- if(n.external) ctx.writeLine(`$runtime.exportFragment($cd, '${n.name}', $fragment_${n.name});`);
5749
+ if(n.external) ctx.writeLine(`$runtime.exportFragment('${n.name}', $fragment_${n.name});`);
5685
5750
  });
5686
5751
  }
5687
5752
 
@@ -5733,7 +5798,6 @@
5733
5798
 
5734
5799
  return xNode('call-fragment', {
5735
5800
  $compile: [slot?.source],
5736
- $deps: [this.glob.apply],
5737
5801
  forwardAllEvents,
5738
5802
  name,
5739
5803
  events,
@@ -5750,7 +5814,7 @@
5750
5814
 
5751
5815
  const writeProps = () => ctx.write('{' + n.props.map(p => p.name == p.value ? p.name : `${p.name}: ${p.value}`).join(', ') + '}');
5752
5816
 
5753
- if(n.staticProps || !this.glob.apply.value) writeProps();
5817
+ if(n.staticProps || !this.inuse.apply) writeProps();
5754
5818
  else {
5755
5819
  ctx.write('() => (');
5756
5820
  writeProps();
@@ -5784,13 +5848,13 @@
5784
5848
  ctx.write(missed, ',', true);
5785
5849
  missed = '';
5786
5850
  if(ctx.isEmpty(n.slot.source)) {
5787
- ctx.write('$runtime.makeStaticBlock(');
5851
+ ctx.write('$runtime.makeBlock(');
5788
5852
  ctx.add(n.slot.template);
5789
5853
  ctx.write(')');
5790
5854
  } else {
5791
5855
  ctx.write('$runtime.makeBlock(');
5792
5856
  ctx.add(n.slot.template);
5793
- ctx.write(', ($cd, $parentElement) => {', true);
5857
+ ctx.write(', ($parentElement) => {', true);
5794
5858
  ctx.indent++;
5795
5859
  ctx.add(n.slot.source);
5796
5860
  ctx.indent--;
@@ -5805,20 +5869,16 @@
5805
5869
  }
5806
5870
 
5807
5871
 
5808
- function attachFragmentSlot(label, requireCD) {
5809
- requireCD.$value(true);
5810
-
5872
+ function attachFragmentSlot(label) {
5811
5873
  return xNode('fragment-slot', {
5812
5874
  el: label.bindName()
5813
5875
  }, (ctx, n) => {
5814
- ctx.write(true, `$runtime.attachBlock($cd, ${n.el}, $$fragmentSlot?.())`);
5876
+ ctx.write(true, `$runtime.attachBlock(${n.el}, $$fragmentSlot?.())`);
5815
5877
  });
5816
5878
  }
5817
5879
 
5818
5880
 
5819
- function attchExportedFragment(node, label, componentName, requireCD) {
5820
- requireCD.$value(true);
5821
-
5881
+ function attchExportedFragment(node, label, componentName) {
5822
5882
  let data = {
5823
5883
  name: node.elArg,
5824
5884
  componentName,
@@ -5829,7 +5889,7 @@
5829
5889
  if(body.length) {
5830
5890
  data.slot = this.buildBlock({ body }, { inline: true });
5831
5891
  data.$compile = [data.slot.source];
5832
- data.$deps = [data.slot.requireCD];
5892
+ data.$wait = [data.slot.requireCD];
5833
5893
  // assert(!data.slot.template.svg, 'SVG is not supported for exported fragment');
5834
5894
  }
5835
5895
 
@@ -5837,7 +5897,7 @@
5837
5897
  data = { ...pa, ...data };
5838
5898
 
5839
5899
  return xNode('attach-exported-fragment', data, (ctx, n) => {
5840
- ctx.write(true, `$runtime.attachBlock($cd, ${n.label}, $runtime.callExportedFragment($instance_${n.componentName}, '${n.name}'`);
5900
+ ctx.write(true, `$runtime.attachBlock(${n.label}, $runtime.callExportedFragment($instance_${n.componentName}, '${n.name}'`);
5841
5901
  ctx.indent++;
5842
5902
  let missed = '';
5843
5903
 
@@ -5845,13 +5905,13 @@
5845
5905
  ctx.write(',', true);
5846
5906
 
5847
5907
  if(ctx.isEmpty(n.slot.source)) {
5848
- ctx.write('$runtime.makeStaticBlock(');
5908
+ ctx.write('$runtime.makeBlock(');
5849
5909
  ctx.add(n.slot.template);
5850
5910
  ctx.write(')');
5851
5911
  } else {
5852
- ctx.write('$runtime.makeBlockBound($cd, ');
5912
+ ctx.write('$runtime.makeBlockBound(');
5853
5913
  ctx.add(n.slot.template);
5854
- ctx.write(', ($cd, $parentElement) => {', true);
5914
+ ctx.write(', ($parentElement) => {', true);
5855
5915
  ctx.indent++;
5856
5916
  ctx.add(n.slot.source);
5857
5917
  ctx.indent--;
@@ -5903,7 +5963,7 @@
5903
5963
  });
5904
5964
  }
5905
5965
 
5906
- function attachHead(n, requireCD) {
5966
+ function attachHead(n) {
5907
5967
  if(n.elArg == 'window' || n.elArg == 'body') {
5908
5968
  let name = 'el' + (this.uniqIndex++);
5909
5969
  let block = this.buildBlock({ body: [n] }, { malinaElement: true, inline: true, oneElement: name, bindAttributes: true });
@@ -5930,8 +5990,7 @@
5930
5990
  });
5931
5991
 
5932
5992
  let d = {
5933
- $deps: [this.glob.apply],
5934
- requireCD
5993
+ $wait: ['apply']
5935
5994
  };
5936
5995
  if(title?.body?.[0]) {
5937
5996
  assert(title.body[0].type == 'text');
@@ -5953,21 +6012,16 @@
5953
6012
  });
5954
6013
  d.source = bb.source;
5955
6014
  d.template = bb.template;
5956
- d.blockCD = bb.requireCD;
5957
-
5958
6015
  d.$compile = [d.source];
5959
- d.$deps.push(d.blockCD);
5960
6016
 
5961
6017
  this.require('$onDestroy');
5962
6018
  }
5963
6019
 
5964
6020
  const result = xNode('malina:head', d, (ctx, n) => {
5965
- if(n.blockCD.value) n.requireCD.$value(true);
5966
6021
  if(n.title != null) ctx.writeLine(`document.title = ${n.title};`);
5967
6022
  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;});`);
6023
+ if(this.inuse.apply) {
6024
+ ctx.writeLine(`$watch(() => (${n.dynTitle}), (value) => {document.title = value;});`);
5971
6025
  } else ctx.writeLine(`document.title = ${n.dynTitle};`);
5972
6026
  }
5973
6027
 
@@ -5983,7 +6037,6 @@
5983
6037
  ctx.writeLine('}');
5984
6038
  }
5985
6039
  });
5986
- requireCD.$depends(result);
5987
6040
  return result;
5988
6041
  } else throw 'Wrong tag';
5989
6042
  }
@@ -6027,7 +6080,7 @@
6027
6080
  if(!statical) value = pe.result;
6028
6081
  } else if(value) {
6029
6082
  rawValue = value;
6030
- value = '`' + this.Q(value) + '`';
6083
+ value = '`' + Q(value) + '`';
6031
6084
  statical = true;
6032
6085
  } else {
6033
6086
  rawValue = true;
@@ -6038,7 +6091,7 @@
6038
6091
  return { name, value, rawValue, static: statical };
6039
6092
  }
6040
6093
 
6041
- function attachPortal(node, requireCD) {
6094
+ function attachPortal(node) {
6042
6095
  let body = trimEmptyNodes(node.body || []);
6043
6096
  if(!body.length) return;
6044
6097
 
@@ -6051,20 +6104,15 @@
6051
6104
  }
6052
6105
  });
6053
6106
 
6054
- this.require('$component');
6055
-
6056
6107
  let mount = node.attributes.find(a => a.name == 'mount')?.value;
6057
6108
  if(mount) mount = unwrapExp(mount);
6058
6109
 
6059
6110
  const result = xNode('portal', {
6060
6111
  $compile: [bb.source],
6061
- $deps: [bb.requireCD],
6062
6112
  mount,
6063
6113
  source: bb.source,
6064
- template: bb.template,
6065
- requireCD
6114
+ template: bb.template
6066
6115
  }, (ctx, n) => {
6067
- if(n.$deps[0].value) n.requireCD.$value(true);
6068
6116
  let label = n.mount || 'document.body';
6069
6117
  ctx.writeLine('{');
6070
6118
  ctx.indent++;
@@ -6072,12 +6120,11 @@
6072
6120
  ctx.add(n.source);
6073
6121
  ctx.writeLine('let $$first = $parentElement[$runtime.firstChild];');
6074
6122
  ctx.writeLine('let $$last = $parentElement.lastChild;');
6075
- ctx.writeLine(`$runtime.cd_onDestroy(${n.$deps[0].value ? '$cd' : '$component'}, () => $runtime.$$removeElements($$first, $$last));`);
6123
+ ctx.writeLine(`$runtime.$onDestroy(() => $runtime.$$removeElements($$first, $$last));`);
6076
6124
  ctx.writeLine(`$tick(() => ${label}.appendChild($parentElement));`);
6077
6125
  ctx.indent--;
6078
6126
  ctx.writeLine('}');
6079
6127
  });
6080
- requireCD.$depends(result);
6081
6128
  return result;
6082
6129
  }
6083
6130
 
@@ -6223,7 +6270,7 @@
6223
6270
  return { event, fn, rootModifier };
6224
6271
  }
6225
6272
 
6226
- const version = '0.7.0a2';
6273
+ const version = '0.7.0-a4';
6227
6274
 
6228
6275
 
6229
6276
  async function compile(source, config = {}) {
@@ -6250,7 +6297,6 @@
6250
6297
  uniqIndex: 0,
6251
6298
  warning: config.warning || (w => console.warn('!', w.message || w)),
6252
6299
 
6253
- Q: config.inlineTemplate ? Q2 : Q,
6254
6300
  buildBlock,
6255
6301
  bindProp,
6256
6302
  makeEachBlock,
@@ -6273,29 +6319,26 @@
6273
6319
 
6274
6320
  inuse: {},
6275
6321
  glob: {
6322
+ $component: xNode('$component', false),
6323
+ rootCD: xNode('root-cd', false),
6276
6324
  apply: xNode('apply', false),
6277
- component: xNode('$component', false),
6278
6325
  componentFn: xNode('componentFn', false),
6279
- rootCD: xNode('root-cd', false)
6326
+ $onMount: xNode('$onMount', false)
6280
6327
  },
6281
6328
  require: function(...args) {
6282
6329
  for(let name of args) {
6283
6330
  let deps = true;
6284
6331
  if(name == '$props:no-deps') { name = '$props'; deps = false; }
6285
- if(name == 'apply' && ctx.script.readOnly) name = 'blankApply';
6332
+ if(name == 'apply' && ctx.script.readOnly) {
6333
+ ctx.glob.apply.$value('readOnly');
6334
+ continue;
6335
+ }
6286
6336
  if(ctx.inuse[name] == null) ctx.inuse[name] = 0;
6287
6337
  ctx.inuse[name]++;
6288
6338
  if(!deps) continue;
6289
- if(name == 'apply') ctx.glob.apply.$value(true);
6290
- if(name == '$component') ctx.glob.component.$value(true);
6291
6339
  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');
6340
+ if(name == '$props' && !ctx.script.readOnly) ctx.require('apply', 'rootCD');
6341
+ if(['apply', '$onMount', '$component', 'componentFn', 'rootCD'].includes(name)) ctx.glob[name].$value(true);
6299
6342
  }
6300
6343
  },
6301
6344
  detectDependency,
@@ -6308,7 +6351,6 @@
6308
6351
  scriptNodes: null,
6309
6352
  js_parse: parse$1,
6310
6353
  js_transform: transform,
6311
- js_build: build,
6312
6354
 
6313
6355
  styleNodes: null,
6314
6356
  css: null,
@@ -6323,13 +6365,11 @@
6323
6365
  head: xNode('block'),
6324
6366
  code: xNode('block'),
6325
6367
  body: xNode('block')
6326
- },
6327
-
6328
- xBuild: node => {
6329
- return xBuild(ctx, node);
6330
6368
  }
6331
6369
  };
6332
6370
 
6371
+ use_context(ctx, () => setup.call(ctx));
6372
+
6333
6373
  await hook(ctx, 'dom:before');
6334
6374
  ctx.parseHTML();
6335
6375
  await hook(ctx, 'dom');
@@ -6364,23 +6404,33 @@
6364
6404
  await hook(ctx, 'css');
6365
6405
 
6366
6406
  await hook(ctx, 'runtime:before');
6367
- ctx.buildRuntime();
6407
+ use_context(ctx, () => ctx.buildRuntime());
6368
6408
  await hook(ctx, 'runtime');
6369
6409
 
6370
-
6371
6410
  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
6411
 
6383
- ctx.result = xBuild(ctx, result);
6412
+ use_context(ctx, () => {
6413
+ const result = ctx.result = xNode('block');
6414
+ result.push('import * as $runtime from \'malinajs/runtime.js\';');
6415
+ result.push('import { $watch, $tick } from \'malinajs/runtime.js\';');
6416
+ if(config.hideLabel) {
6417
+ result.push('import { $$htmlToFragmentClean as $$htmlToFragment } from \'malinajs/runtime.js\';');
6418
+ } else {
6419
+ result.push('import { $$htmlToFragment } from \'malinajs/runtime.js\';');
6420
+ }
6421
+ result.push(ctx.module.top);
6422
+ result.push(xNode('componentFn-wrapper', {
6423
+ $compile: [ctx.module.head, ctx.module.code, ctx.module.body, ctx.glob.rootCD],
6424
+ name: config.name,
6425
+ componentFn: ctx.glob.componentFn
6426
+ }, (ctx, n) => {
6427
+ if(config.exportDefault) ctx.write(true, 'export default ');
6428
+ else ctx.write(true, `const ${n.name} = `);
6429
+ ctx.add(n.componentFn);
6430
+ }));
6431
+
6432
+ ctx.result = xBuild(result);
6433
+ });
6384
6434
 
6385
6435
  await hook(ctx, 'build');
6386
6436
  return ctx;
@@ -6441,57 +6491,26 @@
6441
6491
  }
6442
6492
 
6443
6493
 
6444
- function makeComponentFn() {
6445
- let componentFn = xNode('componentFn', {
6446
- $deps: [this.glob.apply, this.glob.rootCD],
6494
+ function setup() {
6495
+ this.glob.componentFn = xNode(this.glob.componentFn, {
6496
+ $wait: [this.glob.rootCD],
6447
6497
  body: [this.module.head, this.module.code, this.module.body]
6448
6498
  }, (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);
6499
+ if(n.value || this.glob.rootCD.value) {
6500
+ n.value = true;
6501
+ ctx.write('$runtime.makeComponent($option => {');
6502
+ ctx.indent++;
6503
+ ctx.add(xNode('block', { body: n.body }));
6504
+ ctx.indent--;
6505
+ ctx.write(true, '});', true);
6473
6506
  } else {
6474
- this.glob.componentFn.$value('thin');
6475
- ctx.add(this.glob.componentFn);
6476
6507
  ctx.write('($option={}) => {', true);
6477
- ctx.goIndent(() => {
6478
- ctx.add(xNode('block', { body: n.body }));
6479
- });
6508
+ ctx.indent++;
6509
+ ctx.add(xNode('block', { body: n.body }));
6510
+ ctx.indent--;
6480
6511
  ctx.write(true, '}');
6481
6512
  }
6482
6513
  });
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
6514
  }
6496
6515
 
6497
6516
  exports.compile = compile;