malinajs 0.7.0-a7 → 0.7.0-a8

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 +120 -62
  2. package/package.json +1 -1
  3. package/runtime.js +12 -1
package/malina.js CHANGED
@@ -179,22 +179,24 @@
179
179
  };
180
180
 
181
181
 
182
- const replaceElementKeyword = (exp, fn) => {
182
+ const replaceKeyword = (exp, fn) => {
183
183
  let changed = false;
184
184
  let r = parseJS(exp).transform((n, pk) => {
185
185
  if(n.type != 'Identifier') return;
186
186
  if(pk == 'property' || pk == 'params') return;
187
- if(n.name != '$element') return;
188
- n.name = fn();
189
- changed = true;
187
+ let name = fn(n.name);
188
+ if(name) {
189
+ n.name = name;
190
+ changed = true;
191
+ }
190
192
  });
191
- return changed ? r.build().trim() : exp;
193
+ return changed ? r.build() : exp;
192
194
  };
193
195
 
194
196
 
195
197
  const parseJS = (exp) => {
196
198
  let self = {};
197
- self.ast = acorn.parse(exp, { sourceType: 'module', ecmaVersion: 12 });
199
+ self.ast = acorn.parseExpressionAt(exp, 0, {ecmaVersion: 12});
198
200
 
199
201
  self.transform = function(fn) {
200
202
  const rec = (n, pk) => {
@@ -225,7 +227,7 @@
225
227
  };
226
228
 
227
229
  self.build = function(data) {
228
- return astring.generate(data || self.ast);
230
+ return astring.generate(data || self.ast, {indent: '', lineEnd: ''});
229
231
  };
230
232
  return self;
231
233
  };
@@ -1556,6 +1558,8 @@
1556
1558
  });
1557
1559
  }
1558
1560
 
1561
+ let exportedFunctions = [];
1562
+
1559
1563
  ast.body.forEach(n => {
1560
1564
  if(n.type == 'ImportDeclaration') {
1561
1565
  imports.push(n);
@@ -1571,8 +1575,14 @@
1571
1575
  });
1572
1576
  return;
1573
1577
  } else if(n.type == 'ExportNamedDeclaration') {
1574
- if(n.declaration.kind != 'const') constantProps = false;
1578
+ if(n.declaration.type == 'FunctionDeclaration') {
1579
+ exportedFunctions.push(n.declaration.id.name);
1580
+ resultBody.push(n.declaration);
1581
+ return;
1582
+ }
1583
+
1575
1584
  assert(n.declaration.type == 'VariableDeclaration', 'Wrong export');
1585
+ if(n.declaration.kind != 'const') constantProps = false;
1576
1586
  n.declaration.declarations.forEach(d => {
1577
1587
  assert(d.type == 'VariableDeclarator', 'Wrong export');
1578
1588
  let p = { name: d.id.name };
@@ -1674,6 +1684,16 @@
1674
1684
  });
1675
1685
  }));
1676
1686
  }
1687
+
1688
+ this.module.code.push(xNode('exported-functions', {
1689
+ $hold: ['$component'],
1690
+ list: exportedFunctions
1691
+ }, (ctx, n) => {
1692
+ if(!n.list.length) return;
1693
+ this.require('$component');
1694
+ for(let name of n.list)
1695
+ ctx.write(true, `$component.${name} = ${name};`);
1696
+ }));
1677
1697
  }
1678
1698
 
1679
1699
 
@@ -1785,17 +1805,37 @@
1785
1805
  let bb = this.buildBlock(this.DOM, {
1786
1806
  inline: true,
1787
1807
  protectLastTag: true,
1808
+ allowSingleBlock: true,
1788
1809
  template: {
1789
1810
  name: '$parentElement',
1790
1811
  cloneNode: true
1791
1812
  }
1792
1813
  });
1793
- runtime.push(bb.template);
1794
- runtime.push(xNode('root-event', (ctx) => {
1795
- if(!this.inuse.rootEvent) return;
1796
- ctx.write(true, 'const $$addRootEvent = $runtime.makeRootEvent($parentElement);');
1797
- }));
1798
- runtime.push(bb.source);
1814
+ if(bb.singleBlock) {
1815
+ runtime.push(xNode('attach-block', {
1816
+ block: bb.singleBlock,
1817
+ reference: bb.reference
1818
+ }, (ctx, n) => {
1819
+ if(n.reference) {
1820
+ ctx.write(true, `${n.reference} = `);
1821
+ ctx.add(n.block);
1822
+ ctx.write(';');
1823
+ ctx.write(true, `let $parentElement = ${n.reference}.$dom;`);
1824
+ } else {
1825
+ ctx.write(true, `let $parentElement = `);
1826
+ ctx.add(n.block);
1827
+ ctx.write('.$dom;');
1828
+ }
1829
+ }));
1830
+ } else {
1831
+ runtime.push(bb.template);
1832
+ runtime.push(xNode('root-event', (ctx) => {
1833
+ if(!this.inuse.rootEvent) return;
1834
+ ctx.write(true, 'const $$addRootEvent = $runtime.makeRootEvent($parentElement);');
1835
+ }));
1836
+ runtime.push(bb.source);
1837
+ }
1838
+
1799
1839
 
1800
1840
  if(this.script.onMount) runtime.push('$runtime.$onMount(onMount);');
1801
1841
  if(this.script.onDestroy) runtime.push('$runtime.$onDestroy(onDestroy);');
@@ -1857,13 +1897,21 @@
1857
1897
 
1858
1898
  if(option.each?.blockPrefix) binds.push(option.each.blockPrefix);
1859
1899
 
1860
- if(option.allowSingleBlock && data.body.length == 1) {
1861
- let n = data.body[0];
1862
- if(n.type == 'node' && n.name.match(/^[A-Z]/)) {
1863
- let component = this.makeComponent(n);
1864
- return {
1865
- singleBlock: component.bind
1866
- };
1900
+ if(option.allowSingleBlock) {
1901
+ let nodesForSingleBlock = data.body.filter(n => {
1902
+ if(n.type == 'comment' && !this.config.preserveComments) return false;
1903
+ return true;
1904
+ });
1905
+
1906
+ if(nodesForSingleBlock.length == 1) {
1907
+ let n = nodesForSingleBlock[0];
1908
+ if(n.type == 'node' && n.name.match(/^[A-Z]/)) {
1909
+ let component = this.makeComponent(n);
1910
+ return {
1911
+ singleBlock: component.bind,
1912
+ reference: component.reference
1913
+ };
1914
+ }
1867
1915
  }
1868
1916
  }
1869
1917
 
@@ -1969,7 +2017,7 @@
1969
2017
  if(!exp.endsWith(';')) exp += ';';
1970
2018
  binds.push(xNode('block', {
1971
2019
  body: [
1972
- replaceElementKeyword(exp, () => textNode.bindName())
2020
+ replaceKeyword(exp, (name) => name == '$element' ? textNode.bindName() : null)
1973
2021
  ]
1974
2022
  }));
1975
2023
  });
@@ -2006,11 +2054,18 @@
2006
2054
  let component = this.makeComponent(n);
2007
2055
  binds.push(xNode('insert-component', {
2008
2056
  component: component.bind,
2057
+ reference: component.reference,
2009
2058
  el: el.bindName()
2010
2059
  }, (ctx, n) => {
2011
- ctx.write(true, `$runtime.insertAfter(${n.el}, `);
2012
- ctx.add(n.component);
2013
- ctx.write('.$dom);');
2060
+ if(n.reference) {
2061
+ ctx.write(true, `${n.reference} = `);
2062
+ ctx.add(n.component);
2063
+ ctx.write(true, `$runtime.attachBlock(${n.el}, ${n.reference});`);
2064
+ } else {
2065
+ ctx.write(true, `$runtime.attachBlock(${n.el}, `);
2066
+ ctx.add(n.component);
2067
+ ctx.write(');');
2068
+ }
2014
2069
  }));
2015
2070
  }
2016
2071
  } else {
@@ -4427,7 +4482,10 @@
4427
4482
  let n = new Node(e.name, { __node: e });
4428
4483
  e.attributes.forEach(a => {
4429
4484
  if(a.name == 'class') {
4430
- if(a.value != null) n.className += ' ' + a.value;
4485
+ if(a.value != null) {
4486
+ if(a.value.includes('{')) n.dynClass = true;
4487
+ else n.className += ' ' + a.value;
4488
+ }
4431
4489
  n.attributes[a.name] = a.value;
4432
4490
  } else if(a.name == 'id') n.attributes.id = n.id = a.value;
4433
4491
  else if(a.name.startsWith('class:')) {
@@ -4507,18 +4565,20 @@
4507
4565
  if(names.length != 1) throw 'Not supported';
4508
4566
  let cls = names[0];
4509
4567
 
4568
+ let rx = RegExp('(^|\\s)' + cls + '(\\s|$)', 'i');
4510
4569
  let result = [];
4511
- this.childNodes.forEach(n => {
4512
- let rx = RegExp('(^|\\s)' + cls + '(\\s|$)', 'i');
4513
- if(rx.test(n.className)) result.push(n);
4514
- result.push.apply(result, n.getElementsByClassName(cls));
4515
- });
4570
+ const walk = (node) => {
4571
+ node.childNodes.forEach(n => {
4572
+ if(n.dynClass) result.push(n);
4573
+ else if(rx.test(n.className)) result.push(n);
4574
+ walk(n);
4575
+ });
4576
+ };
4577
+ walk(this);
4516
4578
  return result;
4517
4579
  };
4518
4580
 
4519
4581
  function makeComponent(node) {
4520
- this.require('apply');
4521
-
4522
4582
  let propList = node.attributes;
4523
4583
 
4524
4584
  this.require('$context');
@@ -4531,7 +4591,7 @@
4531
4591
  let componentName = node.name;
4532
4592
  if(componentName != 'component' && this.config.autoimport) {
4533
4593
  let imported = this.script.autoimport[componentName] || this.script.importedNames.includes(componentName) ||
4534
- this.script.rootVariables[componentName] || this.script.rootFunctions[componentName];
4594
+ this.script.rootVariables[componentName] || this.script.rootFunctions[componentName];
4535
4595
 
4536
4596
  if(!imported) {
4537
4597
  let r = this.config.autoimport(componentName, this.config.path, this);
@@ -4758,14 +4818,12 @@
4758
4818
  staticProps,
4759
4819
  props: propsFn,
4760
4820
  propsSetter,
4761
- reference,
4762
4821
  $class,
4763
4822
  forwardAllEvents,
4764
4823
  events,
4765
4824
  slots: slotBlocks.length ? slotBlocks : null,
4766
4825
  anchors: anchorBlocks.length ? anchorBlocks : null
4767
4826
  }, (ctx, n) => {
4768
- if(n.reference) throw 'not implemented'; // FIXME
4769
4827
  let comma = false;
4770
4828
  ctx.write(`$runtime.callComponent($context, ${n.componentName}, {`);
4771
4829
 
@@ -4829,6 +4887,11 @@
4829
4887
  ctx.indent--;
4830
4888
  ctx.write(true, '}');
4831
4889
  }
4890
+ if(n.$class.length && !ctx.inuse.apply) {
4891
+ if(comma) ctx.write(', ');
4892
+ comma = true;
4893
+ ctx.write(`$class: {${n.$class.join(', ')}}`);
4894
+ }
4832
4895
  ctx.write('}');
4833
4896
 
4834
4897
  let other = '';
@@ -4850,7 +4913,7 @@
4850
4913
  ctx.write(',\n', true, `($$_value) => ({${n.propsSetter.join(', ')}} = $$_value)`);
4851
4914
  } else other += ', null';
4852
4915
 
4853
- if(n.$class.length) {
4916
+ if(n.$class.length && ctx.inuse.apply) {
4854
4917
  if(other) ctx.write(other);
4855
4918
  other = '';
4856
4919
  ctx.write(',\n', true, `() => ({${n.$class.join(', ')}})`);
@@ -4860,7 +4923,7 @@
4860
4923
  ctx.write(true, ')');
4861
4924
  });
4862
4925
 
4863
- return { bind: result };
4926
+ return { bind: result, reference };
4864
4927
  }
4865
4928
 
4866
4929
  function makeComponentDyn(node, element) {
@@ -4878,17 +4941,20 @@
4878
4941
  }
4879
4942
 
4880
4943
  assert(dynamicComponent);
4944
+ this.require('apply');
4881
4945
  this.detectDependency(dynamicComponent);
4882
4946
 
4883
- let component = this.makeComponent(node).bind;
4947
+ let {bind: component, reference} = this.makeComponent(node);
4884
4948
 
4885
4949
  component.componentName = '$ComponentConstructor';
4886
4950
  return xNode('dyn-component', {
4887
4951
  el: element.bindName(),
4888
4952
  exp: dynamicComponent,
4889
- component
4953
+ component,
4954
+ reference
4890
4955
  }, (ctx, n) => {
4891
4956
  ctx.write(true, `$runtime.attachDynComponent(${n.el}, () => ${n.exp}, ($ComponentConstructor) => `);
4957
+ if(n.reference) ctx.write(`${n.reference} = `);
4892
4958
  ctx.add(n.component);
4893
4959
  ctx.write(')');
4894
4960
  });
@@ -4905,7 +4971,7 @@
4905
4971
  return {
4906
4972
  bind: xNode('block', {
4907
4973
  body: [
4908
- replaceElementKeyword(exp, () => element.bindName())
4974
+ replaceKeyword(exp, (name) => name == '$element' ? element.bindName() : null)
4909
4975
  ]
4910
4976
  })
4911
4977
  };
@@ -5408,15 +5474,8 @@
5408
5474
  right = right.trim();
5409
5475
 
5410
5476
  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
5477
  keyFunction = xNode('key-function', {
5419
- exp
5478
+ exp: replaceKeyword(keyName, n => keyLink[n])
5420
5479
  }, (ctx, n) => {
5421
5480
  ctx.write(`($$item, $index) => ${n.exp}`);
5422
5481
  });
@@ -5428,22 +5487,19 @@
5428
5487
  try {
5429
5488
  let exp = `[${right}]`;
5430
5489
  let e = parseJS(exp);
5431
- assert(e.ast.body.length == 1);
5432
-
5490
+ assert(e.ast.elements.length == 1 || e.ast.elements.length == 2);
5433
5491
  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];
5492
+
5493
+ unwrap = e.build(e.ast.elements[0]);
5494
+
5495
+ if(e.ast.elements.length == 2) {
5496
+ let b = e.ast.elements[1];
5441
5497
  assert(b.type == 'Identifier');
5442
- indexName = exp.substring(b.start, b.end);
5498
+ indexName = e.build(b);
5443
5499
  }
5444
5500
 
5445
5501
  e = parseJS(`(${unwrap} = $$item)`);
5446
- let l = e.ast.body[0].expression.left;
5502
+ let l = e.ast.left;
5447
5503
  if(l.type == 'ArrayPattern') {
5448
5504
  keywords = l.elements.map(p => p.name);
5449
5505
 
@@ -6197,7 +6253,9 @@
6197
6253
  if(prop.value) {
6198
6254
  assert$1(!handler);
6199
6255
  exp = unwrapExp(prop.value);
6200
- exp = replaceElementKeyword(exp, requireElement);
6256
+ exp = replaceKeyword(exp, (name) => {
6257
+ if(name == '$element') return requireElement();
6258
+ });
6201
6259
  } else if(!handler) handler = event;
6202
6260
 
6203
6261
  this.detectDependency(exp || handler);
@@ -6296,7 +6354,7 @@
6296
6354
  return { event, fn, rootModifier };
6297
6355
  }
6298
6356
 
6299
- const version = '0.7.0-a7';
6357
+ const version = '0.7.0-a8';
6300
6358
 
6301
6359
 
6302
6360
  async function compile(source, config = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "malinajs",
3
- "version": "0.7.0-a7",
3
+ "version": "0.7.0-a8",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "prepare": "npm run build",
package/runtime.js CHANGED
@@ -806,6 +806,17 @@ const mount = (label, component, option) => {
806
806
  return app;
807
807
  };
808
808
 
809
+ const mountStatic = (label, component, option) => {
810
+ current_destroyList = [];
811
+ try {
812
+ let app = component(option);
813
+ label.appendChild(app.$dom);
814
+ return app;
815
+ } finally {
816
+ current_destroyList = null;
817
+ }
818
+ };
819
+
809
820
  let create = (tag, html) => {
810
821
  let fr;
811
822
  if(tag.parentElement instanceof SVGElement) {
@@ -1160,4 +1171,4 @@ const makeSlot = (fr, fn) => {
1160
1171
  };
1161
1172
  };
1162
1173
 
1163
- export { $$addEventForComponent, $$awaitBlock, $$cloneDeep, $$compareArray, $$compareDeep, $$deepComparator, $$eachBlock, $$htmlBlock, $$htmlBlockStatic, $$htmlToFragment, $$htmlToFragmentClean, $$removeElements, $$removeItem, $context, $digest, $makeEmitter, $onDestroy, $onMount, $tick, $watch, WatchObject, __app_onerror, __bindActionSubscribe, addClass, addEvent, addStyles, attachAnchor, attachBlock, attachDynComponent, autoSubscribe, bindAction, bindAttribute, bindAttributeBase, bindClass, bindClassExp, bindInput, bindStyle, bindText, callComponent, callExportedFragment, cd_attach, cd_attach2, cd_component, cd_detach, cd_new, childNodes, cloneDeep, configure, createTextNode, current_cd, current_component, current_destroyList, destroyResults, eachDefaultKey, exportFragment, fire, firstChild, getFinalLabel, ifBlock, ifBlockReadOnly, insertAfter, invokeSlot, invokeSlotBase, isArray, isFunction, iterNodes, keyComparator, makeAnchor, makeApply, makeBlock, makeBlockBound, makeClassResolver, makeComponent, makeEachBlock, makeEachSingleBlock, makeExternalProperty, makeRootEvent, makeSlot, mergeEvents, mount, noop, prefixPush, removeElementsBetween, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };
1174
+ export { $$addEventForComponent, $$awaitBlock, $$cloneDeep, $$compareArray, $$compareDeep, $$deepComparator, $$eachBlock, $$htmlBlock, $$htmlBlockStatic, $$htmlToFragment, $$htmlToFragmentClean, $$removeElements, $$removeItem, $context, $digest, $makeEmitter, $onDestroy, $onMount, $tick, $watch, WatchObject, __app_onerror, __bindActionSubscribe, addClass, addEvent, addStyles, attachAnchor, attachBlock, attachDynComponent, autoSubscribe, bindAction, bindAttribute, bindAttributeBase, bindClass, bindClassExp, bindInput, bindStyle, bindText, callComponent, callExportedFragment, cd_attach, cd_attach2, cd_component, cd_detach, cd_new, childNodes, cloneDeep, configure, createTextNode, current_cd, current_component, current_destroyList, destroyResults, eachDefaultKey, exportFragment, fire, firstChild, getFinalLabel, ifBlock, ifBlockReadOnly, insertAfter, invokeSlot, invokeSlotBase, isArray, isFunction, iterNodes, keyComparator, makeAnchor, makeApply, makeBlock, makeBlockBound, makeClassResolver, makeComponent, makeEachBlock, makeEachSingleBlock, makeExternalProperty, makeRootEvent, makeSlot, mergeEvents, mount, mountStatic, noop, prefixPush, removeElementsBetween, setClassToElement, spreadAttributes, svgToFragment, unwrapProps };