bobe 0.0.59 → 0.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -16,11 +16,10 @@ declare class Interpreter {
16
16
  private tokenizer;
17
17
  opt: TerpConf;
18
18
  constructor(tokenizer: Tokenizer);
19
- isLogicNode(node: any): number;
20
19
  ctx: ProgramCtx;
21
20
  rootComponent: ComponentNode$1 | null;
22
21
  program(root: any, componentNode?: ComponentNode$1, before?: any, ctxProvider?: any): ComponentNode$1;
23
- insertAnchor(name?: string, isBefore?: boolean): any;
22
+ insertAnchor(node: any, name?: string, isBefore?: boolean): any;
24
23
  /** 处理
25
24
  * 是逻辑 是普通
26
25
  * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
@@ -37,12 +36,17 @@ declare class Interpreter {
37
36
  * */
38
37
  declaration(ctx: ProgramCtx): any;
39
38
  dynamicDeclaration(pData: any, value: string, ctx: ProgramCtx): DynamicNode;
39
+ createTpNode(): TpNode;
40
40
  createContextNode(): ContextNode;
41
41
  formatForCollection(collection: any): {
42
42
  arr: any[];
43
43
  keys: string[] | null;
44
44
  };
45
45
  forDeclaration(): ForNode | ForItemNode;
46
+ /** after 锚点,对 fake 节点反引用
47
+ * 用于 tp 节点 移动时,可以通过 after 锚点找到 fake 节点并做 realParent 的修正
48
+ */
49
+ anchorRefBack(anchor: any, node: LogicNode): void;
46
50
  insertForItem(forNode: ForNode, i: number, parentData: any, newChildren: ForItemNode[], before: any, snapshotForUpdate: any): void;
47
51
  removeForItem(children: ForItemNode[], i: number): void;
48
52
  reuseForItem(child: ForItemNode, data: any, itemExp: string | ((value: any) => any), i: number, indexName?: string,
@@ -169,7 +173,8 @@ declare enum FakeType {
169
173
  Fragment = 32,
170
174
  ForItem = 64,
171
175
  Context = 128,
172
- DynamicText = 256
176
+ DynamicText = 256,
177
+ Tp = 512
173
178
  }
174
179
  type NodeSortBit = number;
175
180
  type BaseType = string | number | boolean | undefined | null;
@@ -296,6 +301,14 @@ type IfNode = LogicNode & {
296
301
  type ContextNode = Omit<LogicNode, 'data'> & {
297
302
  context: any;
298
303
  };
304
+ type TpNode = LogicNode & {
305
+ tpData: any;
306
+ effect: Effect;
307
+ contentBefore: any;
308
+ contentAfter: any;
309
+ owner: ComponentNode$1 | FragmentNode$1;
310
+ snapshot: ReturnType<Tokenizer['snapshot']>;
311
+ };
299
312
  type DynamicNode = Omit<LogicNode, 'data'> & {
300
313
  tokenizer: Tokenizer;
301
314
  /** 模版片段快照 */
@@ -584,7 +597,7 @@ type ParseHooks = Partial<{
584
597
  }>;
585
598
 
586
599
  declare function bobe<T extends Record<any, any> = any>(fragments: TemplateStringsArray, ...values: any[]): UI<T>;
587
- declare function customRender(option: CustomRenderConf): <T>(Ctor: typeof Store, root: any) => (ComponentNode$1 | Store)[];
600
+ declare function customRender(option: CustomRenderConf): <T extends typeof Store>(Ctor: T, root: any) => readonly [ComponentNode$1, InstanceType<T>];
588
601
 
589
602
  type IContext = {
590
603
  <T = any>(name: string): T;
@@ -595,4 +608,4 @@ declare const context: IContext;
595
608
  declare const effect: (callback: (...args: ValueDiff[]) => void, depOrOpt?: Dep[] | Dep | CustomEffectOpt, opt?: CustomEffectOpt) => aoye.Effect;
596
609
 
597
610
  export { Compiler, FakeType, NodeType, ParseErrorCode, ParseSyntaxError, Tokenizer, bobe, context, customRender, effect };
598
- export type { ASTNodeType, BaseNode, CommentNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, IContext, InterpolationNode, LogicNode, LoopNode, ParseError, Program, Property, PropertyKeyNode, PropertyValue, SourceLocation, StaticValue, TemplateNode, TextNode };
611
+ export type { ASTNodeType, BaseNode, CommentNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, IContext, InterpolationNode, LogicNode, LoopNode, ParseError, Program, Property, PropertyKeyNode, PropertyValue, SourceLocation, StaticValue, TemplateNode, TextNode, UI };
package/dist/index.umd.js CHANGED
@@ -35,15 +35,15 @@
35
35
  FakeType[FakeType["ForItem"] = 64] = "ForItem";
36
36
  FakeType[FakeType["Context"] = 128] = "Context";
37
37
  FakeType[FakeType["DynamicText"] = 256] = "DynamicText";
38
+ FakeType[FakeType["Tp"] = 512] = "Tp";
38
39
  return FakeType;
39
40
  }({});
40
41
  const CondBit = FakeType.If | FakeType.Fail | FakeType.Else;
41
- const LogicalBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem;
42
42
  const CtxProviderBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem | FakeType.Component | FakeType.Fragment | FakeType.DynamicText;
43
- const ContextBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.ForItem | FakeType.Context;
43
+ const ContextBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.ForItem | FakeType.Context | FakeType.Tp;
44
44
  const TokenizerSwitcherBit = FakeType.Component | FakeType.Fragment;
45
45
  let NodeSort = function (NodeSort) {
46
- NodeSort[NodeSort["Logic"] = 1] = "Logic";
46
+ NodeSort[NodeSort["EffectNode"] = 1] = "EffectNode";
47
47
  NodeSort[NodeSort["Real"] = 2] = "Real";
48
48
  NodeSort[NodeSort["Component"] = 4] = "Component";
49
49
  NodeSort[NodeSort["CtxProvider"] = 8] = "CtxProvider";
@@ -56,6 +56,7 @@
56
56
  TerpEvt["HandledComponentNode"] = "handled-component-node";
57
57
  return TerpEvt;
58
58
  })({});
59
+ const FakeNode = Symbol('fake-node');
59
60
  let ParseErrorCode = function (ParseErrorCode) {
60
61
  ParseErrorCode[ParseErrorCode["UNCLOSED_BRACE"] = 9001] = "UNCLOSED_BRACE";
61
62
  ParseErrorCode[ParseErrorCode["UNCLOSED_STRING"] = 9002] = "UNCLOSED_STRING";
@@ -1431,6 +1432,14 @@
1431
1432
  }
1432
1433
  const isUI = fn => typeof fn === 'function' && fn.__BOBE_IS_UI;
1433
1434
  const isRenderAble = val => aoye.isStore(val) || isUI(val) || val instanceof InlineFragment;
1435
+ const SAFE_HANDLER = {
1436
+ has: () => true,
1437
+ get: (t, k) => {
1438
+ if (typeof k === 'symbol') return t[k];
1439
+ return k in t ? t[k] : undefined;
1440
+ }
1441
+ };
1442
+ const safe = data => new Proxy(data, SAFE_HANDLER);
1434
1443
 
1435
1444
  const KEY_INDEX = '__BOBE_KEY_INDEX';
1436
1445
  let _ctxStack;
@@ -1442,9 +1451,6 @@
1442
1451
  constructor(tokenizer) {
1443
1452
  this.tokenizer = tokenizer;
1444
1453
  }
1445
- isLogicNode(node) {
1446
- return node && node.__logicType & LogicalBit;
1447
- }
1448
1454
  rootComponent = null;
1449
1455
  program(root, componentNode, before, ctxProvider) {
1450
1456
  this.rootComponent = componentNode;
@@ -1463,7 +1469,7 @@
1463
1469
  stack.push({
1464
1470
  node: ctxProvider,
1465
1471
  prev: null
1466
- }, (ctxProvider.__logicType & LogicalBit ? NodeSort.Logic : 0) | NodeSort.CtxProvider);
1472
+ }, (ctxProvider.__logicType && ctxProvider.effect ? NodeSort.EffectNode : 0) | NodeSort.CtxProvider);
1467
1473
  }
1468
1474
  const rootLen = stack.length;
1469
1475
  const ctx = this.ctx = {
@@ -1486,18 +1492,22 @@
1486
1492
  const token = this.tokenizer.token;
1487
1493
  if (token.type & TokenType.Indent) {
1488
1494
  this.tokenizer.nextToken();
1489
- const isLogicNode = this.isLogicNode(ctx.current);
1495
+ const isEffectNode = ctx.current && ctx.current.__logicType && ctx.current.effect;
1490
1496
  stack.push({
1491
1497
  node: ctx.current,
1492
1498
  prev: ctx.prevSibling
1493
- }, !ctx.current.__logicType ? NodeSort.Real : (ctx.current.__logicType & LogicalBit ? NodeSort.Logic : 0) | (ctx.current.__logicType & TokenizerSwitcherBit ? NodeSort.TokenizerSwitcher : 0) | (ctx.current.__logicType & ContextBit ? NodeSort.Context : 0) | (ctx.current.__logicType === FakeType.Component ? NodeSort.Component : 0) | (ctx.current.__logicType & CtxProviderBit ? NodeSort.CtxProvider : 0));
1499
+ }, !ctx.current.__logicType ? NodeSort.Real : (isEffectNode ? NodeSort.EffectNode : 0) | (ctx.current.__logicType & TokenizerSwitcherBit ? NodeSort.TokenizerSwitcher : 0) | (ctx.current.__logicType & ContextBit ? NodeSort.Context : 0) | (ctx.current.__logicType === FakeType.Component ? NodeSort.Component : 0) | (ctx.current.__logicType & CtxProviderBit ? NodeSort.CtxProvider : 0));
1494
1500
  if (ctx.current.__logicType) {
1495
1501
  this.beforeLogicIndent?.(ctx.current);
1496
- if (isLogicNode) {
1502
+ if (isEffectNode) {
1497
1503
  aoye.setPulling(ctx.current.effect);
1498
1504
  if (ctx.current.__logicType & FakeType.ForItem) {
1499
1505
  ctx.prevSibling = ctx.current.realBefore;
1500
1506
  }
1507
+ if (ctx.current.__logicType & FakeType.Tp) {
1508
+ ctx.realParent = ctx.current.tpData[aoye.Keys.Raw].node;
1509
+ ctx.prevSibling = ctx.current.contentBefore;
1510
+ }
1501
1511
  }
1502
1512
  } else {
1503
1513
  if (ctx.current) {
@@ -1533,14 +1543,17 @@
1533
1543
  const prevSameType = stack.peekByType(NodeSort.Real);
1534
1544
  ctx.realParent = prevSameType?.node || root;
1535
1545
  } else {
1536
- if (sort & NodeSort.Logic) {
1537
- const parentLogic = stack.peekByType(NodeSort.Logic)?.node;
1546
+ if (sort & NodeSort.EffectNode) {
1547
+ const parentLogic = stack.peekByType(NodeSort.EffectNode)?.node;
1538
1548
  if (parentLogic) {
1539
1549
  aoye.setPulling(parentLogic.effect);
1540
1550
  } else {
1541
1551
  aoye.setPulling(rootPulling);
1542
1552
  }
1543
1553
  }
1554
+ if (parent.__logicType === FakeType.Tp) {
1555
+ ctx.realParent = parent.realParent;
1556
+ }
1544
1557
  if (sort & NodeSort.TokenizerSwitcher) {
1545
1558
  const switcher = stack.peekByType(NodeSort.TokenizerSwitcher)?.node;
1546
1559
  if (parent.resumeSnapshot) {
@@ -1577,13 +1590,17 @@
1577
1590
  }
1578
1591
  return componentNode;
1579
1592
  }
1580
- insertAnchor(name = 'anchor', isBefore = false) {
1593
+ insertAnchor(node, name = 'anchor', isBefore = false) {
1581
1594
  const _this$ctx = this.ctx,
1582
1595
  realParent = _this$ctx.realParent,
1583
1596
  prevSibling = _this$ctx.prevSibling,
1584
1597
  stack = _this$ctx.stack,
1585
1598
  before = _this$ctx.before;
1599
+ _this$ctx.current;
1586
1600
  const afterAnchor = this.createAnchor(name, isBefore);
1601
+ if (!isBefore) {
1602
+ this.anchorRefBack(afterAnchor, node);
1603
+ }
1587
1604
  this.ctx.prevSibling = stack.length === 2 && !prevSibling ? before : prevSibling;
1588
1605
  this.handleInsert(realParent, afterAnchor, prevSibling);
1589
1606
  return afterAnchor;
@@ -1628,6 +1645,8 @@
1628
1645
  return this.condDeclaration(ctx);
1629
1646
  } else if (value === 'context') {
1630
1647
  _node = this.createContextNode();
1648
+ } else if (value === 'tp') {
1649
+ return this.createTpNode();
1631
1650
  } else if (value === 'for') {
1632
1651
  return this.forDeclaration();
1633
1652
  } else if (hookType) {
@@ -1667,11 +1686,11 @@
1667
1686
  effect: null,
1668
1687
  textNode: null,
1669
1688
  owner: ctx.stack.peekByType(NodeSort.TokenizerSwitcher)?.node,
1670
- snapshot: this.tokenizer.snapshot(['dentStack']),
1689
+ snapshot: this.tokenizer.snapshot(['dentStack', 'isFirstToken']),
1671
1690
  parentDataProvider: ctx.stack.peekByType(NodeSort.CtxProvider)?.node
1672
1691
  };
1673
1692
  let isUpdate = false;
1674
- node.realAfter = this.insertAnchor(`dynamic-after`);
1693
+ node.realAfter = this.insertAnchor(node, `dynamic-after`);
1675
1694
  node.effect = this.effect(({
1676
1695
  old,
1677
1696
  val
@@ -1680,7 +1699,7 @@
1680
1699
  oldTextNode = node.textNode;
1681
1700
  if (oldLogicType) {
1682
1701
  this.removeLogicNode(node);
1683
- bobeShared.pickInPlace(node, ['realParent', 'realBefore', 'realAfter',, 'owner', 'snapshot', 'parentDataProvider']);
1702
+ bobeShared.pickInPlace(node, ['realParent', 'realBefore', 'realAfter', 'owner', 'snapshot', 'parentDataProvider']);
1684
1703
  }
1685
1704
  if (isRenderAble(val)) {
1686
1705
  if (oldTextNode) {
@@ -1710,7 +1729,7 @@
1710
1729
  }
1711
1730
  if (isUpdate) {
1712
1731
  this.tokenizer.useDedentAsEof = false;
1713
- this.program(node.realParent, node.owner, node.realBefore, node);
1732
+ this.program(node.realParent, node, node.realBefore);
1714
1733
  } else {
1715
1734
  this.tokenizer.useDedentAsEof = true;
1716
1735
  this.tokenizer.initIndentWhenUseDedentAsEof();
@@ -1751,6 +1770,93 @@
1751
1770
  });
1752
1771
  return node;
1753
1772
  }
1773
+ createTpNode() {
1774
+ const child = aoye.deepSignal({}, aoye.getPulling());
1775
+ const node = {
1776
+ __logicType: FakeType.Tp,
1777
+ data: this.getData(),
1778
+ realParent: null,
1779
+ realBefore: null,
1780
+ realAfter: null,
1781
+ contentBefore: null,
1782
+ contentAfter: null,
1783
+ effect: null,
1784
+ snapshot: null,
1785
+ tpData: child,
1786
+ owner: this.ctx.stack.peekByType(NodeSort.TokenizerSwitcher)?.node
1787
+ };
1788
+ this.onePropParsed = createStoreOnePropParsed(child);
1789
+ this.tokenizer.nextToken();
1790
+ this.headerLineAndExtensions(node);
1791
+ this.onePropParsed = this.oneRealPropParsed;
1792
+ node.realAfter = this.insertAnchor(node, 'tp-after');
1793
+ const before = node.contentBefore = this.createAnchor('tp-content-before', true);
1794
+ const after = node.contentAfter = this.createAnchor('tp-content-after', true);
1795
+ let firstRender = true;
1796
+ node.effect = this.effect(({
1797
+ old: oldDom,
1798
+ val: dom
1799
+ }) => {
1800
+ const removeTpChild = () => {
1801
+ if (oldDom) {
1802
+ let point = before;
1803
+ do {
1804
+ const next = this.nextSib(point);
1805
+ this.remove(point, oldDom, null);
1806
+ if (point === after) break;
1807
+ point = next;
1808
+ } while (true);
1809
+ }
1810
+ };
1811
+ if (firstRender) {
1812
+ if (dom) {
1813
+ this.handleInsert(dom, after, null);
1814
+ this.handleInsert(dom, before, null);
1815
+ } else {
1816
+ if (this.tokenizer.token.type === TokenType.Indent) {
1817
+ const dentLen = this.tokenizer.dentStack[this.tokenizer.dentStack.length - 2] ?? 0;
1818
+ this.tokenizer.skip(dentLen);
1819
+ }
1820
+ }
1821
+ } else {
1822
+ if (dom) {
1823
+ if (oldDom) {
1824
+ let point = before,
1825
+ lastInsert = null;
1826
+ do {
1827
+ const next = this.nextSib(point);
1828
+ const fakeNode = point[FakeNode];
1829
+ if (fakeNode) {
1830
+ fakeNode.realParent = dom;
1831
+ }
1832
+ this.handleInsert(dom, point, lastInsert);
1833
+ if (point === after) break;
1834
+ lastInsert = point;
1835
+ point = next;
1836
+ } while (true);
1837
+ } else {
1838
+ this.handleInsert(dom, after, null);
1839
+ this.handleInsert(dom, before, null);
1840
+ this.tokenizer = node.owner.tokenizer;
1841
+ this.tokenizer.resume(node.snapshot);
1842
+ this.tokenizer.useDedentAsEof = false;
1843
+ this.program(dom, node.owner, before, node);
1844
+ }
1845
+ } else {
1846
+ removeTpChild();
1847
+ }
1848
+ }
1849
+ firstRender = false;
1850
+ return isDestroy => {
1851
+ if (isDestroy) {
1852
+ removeTpChild();
1853
+ }
1854
+ };
1855
+ }, [() => child.node], {
1856
+ type: 'render'
1857
+ });
1858
+ return node;
1859
+ }
1754
1860
  createContextNode() {
1755
1861
  const child = aoye.deepSignal({}, aoye.getPulling());
1756
1862
  const parentContext = this.ctx.stack.peekByType(NodeSort.Context)?.node?.context;
@@ -1765,7 +1871,7 @@
1765
1871
  realBefore: null,
1766
1872
  realAfter: null
1767
1873
  };
1768
- node.realAfter = this.insertAnchor('context-after');
1874
+ node.realAfter = this.insertAnchor(node, 'context-after');
1769
1875
  return node;
1770
1876
  }
1771
1877
  formatForCollection(collection) {
@@ -1855,15 +1961,15 @@
1855
1961
  i: 0
1856
1962
  };
1857
1963
  if (keyExp) {
1858
- forNode.getKey = new Function('data', `let v;with(data){v=${keyExp}\n};return v;`);
1964
+ const rawGetKey = new Function('data', `with(data){return (${keyExp})}`);
1965
+ forNode.getKey = data => rawGetKey(safe(data));
1859
1966
  }
1860
- window['for1'] = forNode;
1861
1967
  const data = this.getData();
1862
1968
  const cells = data[aoye.Keys.Meta].cells;
1863
1969
  const hasArrExpKey = Reflect.has(data[aoye.Keys.Raw], arrExp);
1864
1970
  const arrSignal = hasArrExpKey ? (data[arrExp], cells.get(arrExp)) : new aoye.Computed(this.getFn(data, arrExp));
1865
1971
  forNode.arrSignal = arrSignal;
1866
- forNode.realAfter = this.insertAnchor('for-after');
1972
+ forNode.realAfter = this.insertAnchor(forNode, 'for-after');
1867
1973
  const _forNode$snapshot = forNode.snapshot;
1868
1974
  _forNode$snapshot.dentStack;
1869
1975
  _forNode$snapshot.isFirstToken;
@@ -1886,8 +1992,8 @@
1886
1992
  const len = arr.length;
1887
1993
  for (let i = len; i--;) {
1888
1994
  const item = this.createForItem(forNode, i, data);
1889
- item.realAfter = this.insertAnchor('for-item-after');
1890
- item.realBefore = this.insertAnchor('for-item-before', true);
1995
+ item.realAfter = this.insertAnchor(item, 'for-item-after');
1996
+ item.realBefore = this.insertAnchor(item, 'for-item-before', true);
1891
1997
  item.realParent = forNode.realParent;
1892
1998
  children[i] = item;
1893
1999
  }
@@ -2049,10 +2155,14 @@
2049
2155
  }, aoye.ScheduleType.Render);
2050
2156
  return forNode.children[0] || forNode;
2051
2157
  }
2158
+ anchorRefBack(anchor, node) {
2159
+ anchor[FakeNode] = node;
2160
+ }
2052
2161
  insertForItem(forNode, i, parentData, newChildren, before, snapshotForUpdate) {
2053
2162
  const item = this.createForItem(forNode, i, parentData);
2054
2163
  newChildren[i] = item;
2055
2164
  let realAfter = this.createAnchor('for-item-after');
2165
+ this.anchorRefBack(realAfter, item);
2056
2166
  this.handleInsert(forNode.realParent, realAfter, before);
2057
2167
  let realBefore = this.createAnchor('for-item-before', true);
2058
2168
  this.handleInsert(forNode.realParent, realBefore, before);
@@ -2223,11 +2333,11 @@
2223
2333
  resumeSnapshot
2224
2334
  };
2225
2335
  this.onePropParsed = onePropParsed;
2226
- node.realAfter = this.insertAnchor('component-after');
2336
+ node.realAfter = this.insertAnchor(node, 'component-after');
2227
2337
  return node;
2228
2338
  }
2229
2339
  getFn(data, expression) {
2230
- return new Function('data', `let v;with(data){v=${expression}};return v;`).bind(undefined, data);
2340
+ return new Function('data', `with(data){return (${expression})}`).bind(undefined, safe(data));
2231
2341
  }
2232
2342
  getAssignFn(data, expression) {
2233
2343
  const valueId = `value_bobe_${bobeShared.date32()}`;
@@ -2318,7 +2428,7 @@
2318
2428
  break;
2319
2429
  }
2320
2430
  ifNode.condition = signal;
2321
- ifNode.realAfter = this.insertAnchor(`${keyWord.value}-after`);
2431
+ ifNode.realAfter = this.insertAnchor(ifNode, `${keyWord.value}-after`);
2322
2432
  const ef = this.effect(({
2323
2433
  val
2324
2434
  }) => {
@@ -2361,10 +2471,11 @@
2361
2471
  const tokenizer = this.tokenizer;
2362
2472
  do {
2363
2473
  const isComponent = _node.__logicType & TokenizerSwitcherBit;
2474
+ const isTp = _node.__logicType === FakeType.Tp;
2364
2475
  let snapshot, dentLen;
2365
2476
  const data = this.getData();
2366
2477
  const unHandledKey = this.attributeList(_node, data);
2367
- if (isComponent) {
2478
+ if (isComponent || isTp) {
2368
2479
  snapshot = tokenizer.snapshot(undefined, -1);
2369
2480
  dentLen = tokenizer.dentStack[tokenizer.dentStack.length - 1];
2370
2481
  }
@@ -2376,6 +2487,9 @@
2376
2487
  if ((tokenizer.token.type & TokenType.Pipe) === 0) {
2377
2488
  break;
2378
2489
  }
2490
+ } else if (isTp) {
2491
+ _node.snapshot = snapshot;
2492
+ break;
2379
2493
  } else {
2380
2494
  break;
2381
2495
  }
@@ -2577,6 +2691,7 @@
2577
2691
  return tokenizer;
2578
2692
  };
2579
2693
  ui.boundStore = aoye.Store.Current;
2694
+ ui[aoye.Keys.ProxyFreeObject] = true;
2580
2695
  ui.__BOBE_IS_UI = true;
2581
2696
  return ui;
2582
2697
  }