bobe 0.0.56 → 0.0.58

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
@@ -1,8 +1,17 @@
1
1
  import { Queue } from 'bobe-shared';
2
2
  import * as aoye from 'aoye';
3
- import { Store, Keys, Effect, effect as effect$1, Scope, Signal, Computed, SignalNode, ValueDiff, CustomEffectOpt } from 'aoye';
3
+ import { Keys, Store, Effect, effect as effect$1, Scope, Signal, Computed, SignalNode, ValueDiff, CustomEffectOpt } from 'aoye';
4
4
  export { Store } from 'aoye';
5
5
 
6
+ declare class InlineFragment {
7
+ snapshot: Partial<Tokenizer>;
8
+ data: any;
9
+ key: string;
10
+ tokenizer: Tokenizer;
11
+ [Keys.ProxyFreeObject]: boolean;
12
+ constructor(snapshot: Partial<Tokenizer>, data: any, key: string, tokenizer: Tokenizer);
13
+ }
14
+
6
15
  declare class Interpreter {
7
16
  private tokenizer;
8
17
  opt: TerpConf;
@@ -27,6 +36,7 @@ declare class Interpreter {
27
36
  * <declaration> ::= <tagName=token> <headerLineAndExtensions>
28
37
  * */
29
38
  declaration(ctx: ProgramCtx): any;
39
+ dynamicDeclaration(pData: any, value: string, ctx: ProgramCtx): DynamicNode;
30
40
  createContextNode(): ContextNode;
31
41
  formatForCollection(collection: any): {
32
42
  arr: any[];
@@ -52,6 +62,7 @@ declare class Interpreter {
52
62
  * */
53
63
  onePropParsed(data: Store, node: any, key: string, value: any, valueIsMapKey: boolean, isFn: boolean, hookI?: number): void;
54
64
  oneRealPropParsed: Interpreter['onePropParsed'];
65
+ private createComponentData;
55
66
  componentOrFragmentDeclaration(ComponentOrRender: UI | typeof Store | InlineFragment, ctx: ProgramCtx): ComponentNode$1;
56
67
  getFn(data: any, expression: string | number): any;
57
68
  getAssignFn(data: any, expression: string | number): any;
@@ -95,14 +106,6 @@ declare class Interpreter {
95
106
  Effect: typeof Effect;
96
107
  effect: typeof effect$1;
97
108
  }
98
- declare class InlineFragment {
99
- snapshot: Partial<Tokenizer>;
100
- data: any;
101
- key: string;
102
- tokenizer: Tokenizer;
103
- [Keys.ProxyFreeObject]: boolean;
104
- constructor(snapshot: Partial<Tokenizer>, data: any, key: string, tokenizer: Tokenizer);
105
- }
106
109
 
107
110
  interface StackNode<T> {
108
111
  value: T;
@@ -161,7 +164,8 @@ declare enum FakeType {
161
164
  Component = 16,
162
165
  Fragment = 32,
163
166
  ForItem = 64,
164
- Context = 128
167
+ Context = 128,
168
+ DynamicText = 256
165
169
  }
166
170
  type NodeSortBit = number;
167
171
  type BaseType = string | number | boolean | undefined | null;
@@ -236,6 +240,7 @@ type ProgramCtx = {
236
240
  type UI<T = any> = {
237
241
  /** 在哪个 Store 声明的 */
238
242
  boundStore: Store;
243
+ __BOBE_IS_UI: true;
239
244
  /** 用户声明片段内可用的 props */
240
245
  defineProps?: T;
241
246
  (isSub: boolean): Tokenizer;
@@ -284,8 +289,23 @@ type IfNode = LogicNode & {
284
289
  type ContextNode = Omit<LogicNode, 'data'> & {
285
290
  context: any;
286
291
  };
292
+ type DynamicNode = Omit<LogicNode, 'data'> & {
293
+ tokenizer: Tokenizer;
294
+ /** 模版片段快照 */
295
+ fragmentSnapshot?: ReturnType<Tokenizer['snapshot']>;
296
+ /** 渲染模版片段前的 快照,渲染完成后用于恢复 */
297
+ resumeSnapshot?: ReturnType<Tokenizer['snapshot']>;
298
+ snapshot: ReturnType<Tokenizer['snapshot']>;
299
+ owner: ComponentNode$1 | FragmentNode$1;
300
+ data?: any;
301
+ parentDataProvider: any;
302
+ effect: Effect;
303
+ textNode: any;
304
+ };
287
305
  type FragmentNode$1 = LogicNode & {
288
306
  tokenizer: Tokenizer;
307
+ fragmentSnapshot?: ReturnType<Tokenizer['snapshot']>;
308
+ resumeSnapshot?: ReturnType<Tokenizer['snapshot']>;
289
309
  };
290
310
  type ComponentNode$1 = LogicNode & {
291
311
  tokenizer: Tokenizer;
package/dist/index.umd.js CHANGED
@@ -34,11 +34,12 @@
34
34
  FakeType[FakeType["Fragment"] = 32] = "Fragment";
35
35
  FakeType[FakeType["ForItem"] = 64] = "ForItem";
36
36
  FakeType[FakeType["Context"] = 128] = "Context";
37
+ FakeType[FakeType["DynamicText"] = 256] = "DynamicText";
37
38
  return FakeType;
38
39
  }({});
39
40
  const CondBit = FakeType.If | FakeType.Fail | FakeType.Else;
40
41
  const LogicalBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem;
41
- FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem | FakeType.Component | FakeType.Fragment;
42
+ const CtxProviderBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem | FakeType.Component | FakeType.Fragment | FakeType.DynamicText;
42
43
  const ContextBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.ForItem | FakeType.Context;
43
44
  const TokenizerSwitcherBit = FakeType.Component | FakeType.Fragment;
44
45
  let NodeSort = function (NodeSort) {
@@ -1419,6 +1420,17 @@
1419
1420
  }
1420
1421
  return candyLast;
1421
1422
  }
1423
+ class InlineFragment {
1424
+ [aoye.Keys.ProxyFreeObject] = true;
1425
+ constructor(snapshot, data, key, tokenizer) {
1426
+ this.snapshot = snapshot;
1427
+ this.data = data;
1428
+ this.key = key;
1429
+ this.tokenizer = tokenizer;
1430
+ }
1431
+ }
1432
+ const isUI = fn => typeof fn === 'function' && fn.__BOBE_IS_UI;
1433
+ const isRenderAble = val => aoye.isStore(val) || isUI(val) || val instanceof InlineFragment;
1422
1434
 
1423
1435
  const KEY_INDEX = '__BOBE_KEY_INDEX';
1424
1436
  let _ctxStack;
@@ -1475,7 +1487,7 @@
1475
1487
  stack.push({
1476
1488
  node: ctx.current,
1477
1489
  prev: ctx.prevSibling
1478
- }, !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 !== FakeType.Context ? NodeSort.CtxProvider : 0));
1490
+ }, !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));
1479
1491
  if (ctx.current.__logicType) {
1480
1492
  if (isLogicNode) {
1481
1493
  aoye.setPulling(ctx.current.effect);
@@ -1609,21 +1621,14 @@
1609
1621
  } else if (hookType) {
1610
1622
  const data = this.getData();
1611
1623
  if (hookType === 'static') {
1612
- if (typeof value === 'function') {
1624
+ if (isRenderAble(value)) {
1613
1625
  _node = this.componentOrFragmentDeclaration(value, ctx);
1614
1626
  } else {
1615
- throw new SyntaxError(`declaration 不支持 ${value} 类型的静态插值`);
1616
- }
1617
- } else {
1618
- const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
1619
- const val = data[aoye.Keys.Raw][value];
1620
- if (typeof val === 'function' || val instanceof InlineFragment) {
1621
- _node = this.componentOrFragmentDeclaration(val, ctx);
1622
- } else {
1623
- const str = valueIsMapKey ? value : this.getFn(data, value);
1624
1627
  _node = this.createNode('text');
1625
- this.onePropParsed(data, _node, 'text', str, valueIsMapKey, false);
1628
+ _node.text = String(value);
1626
1629
  }
1630
+ } else {
1631
+ return this.dynamicDeclaration(data, value, ctx);
1627
1632
  }
1628
1633
  } else {
1629
1634
  _node = this.createNode(value);
@@ -1641,6 +1646,96 @@
1641
1646
  }
1642
1647
  return _node;
1643
1648
  }
1649
+ dynamicDeclaration(pData, value, ctx) {
1650
+ const valueIsMapKey = Reflect.has(pData[aoye.Keys.Raw], value);
1651
+ let node = {
1652
+ __logicType: null,
1653
+ realParent: null,
1654
+ tokenizer: null,
1655
+ effect: null,
1656
+ textNode: null,
1657
+ owner: ctx.stack.peekByType(NodeSort.TokenizerSwitcher)?.node,
1658
+ snapshot: this.tokenizer.snapshot(['dentStack']),
1659
+ parentDataProvider: ctx.stack.peekByType(NodeSort.CtxProvider)?.node
1660
+ };
1661
+ let isUpdate = false;
1662
+ node.realAfter = this.insertAfterAnchor(`dynamic-after`);
1663
+ node.effect = this.effect(({
1664
+ old,
1665
+ val
1666
+ }) => {
1667
+ let oldLogicType = node.__logicType,
1668
+ oldTextNode = node.textNode;
1669
+ if (oldLogicType) {
1670
+ this.removeLogicNode(node);
1671
+ bobeShared.pickInPlace(node, ['realParent', 'realBefore', 'realAfter',, 'owner', 'snapshot', 'parentDataProvider']);
1672
+ }
1673
+ if (isRenderAble(val)) {
1674
+ if (oldTextNode) {
1675
+ this.remove(oldTextNode);
1676
+ }
1677
+ const info = this.createComponentData(val);
1678
+ info.__logicType;
1679
+ Object.assign(node, info);
1680
+ this.onePropParsed = info.onePropParsed;
1681
+ if (isUpdate) {
1682
+ this.tokenizer = node.owner.tokenizer;
1683
+ this.tokenizer.resume(node.snapshot);
1684
+ this.ctx.stack.push({
1685
+ node: node.parentDataProvider,
1686
+ prev: null
1687
+ }, NodeSort.CtxProvider);
1688
+ }
1689
+ this.tokenizer.nextToken();
1690
+ this.headerLineAndExtensions(node);
1691
+ if (isUpdate) {
1692
+ this.ctx.stack.pop();
1693
+ }
1694
+ this.onePropParsed = this.oneRealPropParsed;
1695
+ this.tokenizer = node.tokenizer;
1696
+ if (node.fragmentSnapshot) {
1697
+ this.tokenizer.resume(node.fragmentSnapshot);
1698
+ this.tokenizer.useDedentAsEof = true;
1699
+ this.tokenizer.initIndentWhenUseDedentAsEof();
1700
+ }
1701
+ if (isUpdate) {
1702
+ this.program(node.realParent, node.owner, node.realBefore, node);
1703
+ }
1704
+ } else {
1705
+ node.__logicType = FakeType.DynamicText;
1706
+ let textNode = oldTextNode;
1707
+ const isNewTextNode = !textNode;
1708
+ if (isNewTextNode) {
1709
+ textNode = node.textNode = this.createNode('text');
1710
+ }
1711
+ textNode.text = String(val);
1712
+ if (isNewTextNode) {
1713
+ if (isUpdate) {
1714
+ this.handleInsert(node.realParent, textNode, node.realBefore);
1715
+ } else {
1716
+ this.tokenizer.nextToken();
1717
+ this.headerLineAndExtensions(node);
1718
+ const _this$ctx2 = this.ctx,
1719
+ realParent = _this$ctx2.realParent,
1720
+ prevSibling = _this$ctx2.prevSibling;
1721
+ this.handleInsert(realParent, textNode, prevSibling);
1722
+ }
1723
+ }
1724
+ }
1725
+ isUpdate = true;
1726
+ return isDestroy => {
1727
+ if (isDestroy) {
1728
+ this.removeLogicNode(node);
1729
+ }
1730
+ };
1731
+ }, [() => {
1732
+ const val = valueIsMapKey ? pData[value] : this.getFn(pData, value)();
1733
+ return val;
1734
+ }], {
1735
+ type: 'render'
1736
+ });
1737
+ return node;
1738
+ }
1644
1739
  createContextNode() {
1645
1740
  const child = aoye.deepSignal({}, aoye.getPulling());
1646
1741
  const parentContext = this.ctx.stack.peekByType(NodeSort.Context)?.node?.context;
@@ -2059,20 +2154,22 @@
2059
2154
  }
2060
2155
  }
2061
2156
  oneRealPropParsed = this.onePropParsed.bind(this);
2062
- componentOrFragmentDeclaration(ComponentOrRender, ctx) {
2063
- let Component, tokenizer, child, fragmentSnapshot, resumeSnapshot;
2157
+ createComponentData(ComponentOrRender) {
2158
+ let tokenizer, child, fragmentSnapshot, resumeSnapshot, __logicType;
2064
2159
  const isCC = ComponentOrRender.prototype instanceof aoye.Store;
2065
2160
  if (isCC) {
2066
- Component = ComponentOrRender;
2161
+ const Component = ComponentOrRender;
2067
2162
  child = Component.new();
2068
2163
  tokenizer = child.ui(true);
2164
+ __logicType = FakeType.Component;
2069
2165
  } else if (ComponentOrRender instanceof InlineFragment) {
2070
2166
  const conf = ComponentOrRender;
2071
2167
  child = aoye.deepSignal({}, aoye.getPulling(), true);
2072
2168
  Object.setPrototypeOf(child, conf.data);
2073
2169
  tokenizer = conf.tokenizer;
2074
2170
  fragmentSnapshot = conf.snapshot;
2075
- resumeSnapshot = tokenizer.snapshot(['token', 'needIndent', 'isFirstToken', 'dentStack', 'isFirstToken', 'useDedentAsEof']);
2171
+ __logicType = FakeType.Fragment;
2172
+ resumeSnapshot = tokenizer.snapshot(['dentStack', 'token', 'needIndent', 'isFirstToken', 'isFirstToken', 'useDedentAsEof']);
2076
2173
  } else {
2077
2174
  const render = ComponentOrRender;
2078
2175
  const boundStore = render.boundStore;
@@ -2081,18 +2178,36 @@
2081
2178
  Object.setPrototypeOf(child, boundStore);
2082
2179
  }
2083
2180
  tokenizer = render(true);
2181
+ __logicType = FakeType.Fragment;
2084
2182
  }
2183
+ return {
2184
+ data: child,
2185
+ tokenizer,
2186
+ onePropParsed: createStoreOnePropParsed(child),
2187
+ fragmentSnapshot,
2188
+ resumeSnapshot,
2189
+ __logicType
2190
+ };
2191
+ }
2192
+ componentOrFragmentDeclaration(ComponentOrRender, ctx) {
2193
+ const _this$createComponent = this.createComponentData(ComponentOrRender),
2194
+ data = _this$createComponent.data,
2195
+ tokenizer = _this$createComponent.tokenizer,
2196
+ onePropParsed = _this$createComponent.onePropParsed,
2197
+ fragmentSnapshot = _this$createComponent.fragmentSnapshot,
2198
+ resumeSnapshot = _this$createComponent.resumeSnapshot,
2199
+ __logicType = _this$createComponent.__logicType;
2085
2200
  const node = {
2086
- __logicType: isCC ? FakeType.Component : FakeType.Fragment,
2201
+ __logicType,
2087
2202
  realParent: ctx.realParent,
2088
2203
  realBefore: null,
2089
2204
  realAfter: null,
2090
- data: child,
2205
+ data,
2091
2206
  tokenizer,
2092
2207
  fragmentSnapshot,
2093
2208
  resumeSnapshot
2094
2209
  };
2095
- this.onePropParsed = createStoreOnePropParsed(child);
2210
+ this.onePropParsed = onePropParsed;
2096
2211
  node.realAfter = this.insertAfterAnchor('component-after');
2097
2212
  return node;
2098
2213
  }
@@ -2272,10 +2387,54 @@
2272
2387
  hookI = _this$tokenizer$_hook4[2];
2273
2388
  const rawVal = data[aoye.Keys.Raw][value];
2274
2389
  const isFn = typeof rawVal === 'function';
2275
- if (key === 'ref') {
2390
+ if (key === 'props') {
2391
+ let prevKeys = new Set();
2392
+ const savedDefaults = new Map();
2393
+ new this.Effect(() => {
2394
+ const props = isFn ? rawVal : Reflect.has(data[aoye.Keys.Raw], value) ? data[value] : this.getFn(data, value)();
2395
+ const isComponent = _node.__logicType & TokenizerSwitcherBit;
2396
+ const rawTarget = isComponent ? _node.data[aoye.Keys.Raw] : null;
2397
+ const cleanupKeys = keysToClean => {
2398
+ for (const k of keysToClean) {
2399
+ if (k.startsWith('on')) continue;
2400
+ if (isComponent) {
2401
+ _node.data[k] = savedDefaults.has(k) ? savedDefaults.get(k) : undefined;
2402
+ } else {
2403
+ this.setProp(_node, k, undefined, hookI);
2404
+ }
2405
+ }
2406
+ };
2407
+ if (!props || typeof props !== 'object') {
2408
+ cleanupKeys(prevKeys);
2409
+ prevKeys.clear();
2410
+ return;
2411
+ }
2412
+ props[aoye.Keys.Iterator];
2413
+ const raw = props[aoye.Keys.Raw] || props;
2414
+ const keys = Object.keys(raw);
2415
+ const newKeys = new Set();
2416
+ for (let i = 0; i < keys.length; i++) {
2417
+ const k = keys[i];
2418
+ newKeys.add(k);
2419
+ prevKeys.delete(k);
2420
+ if (isComponent) {
2421
+ const savedK = savedDefaults.has(k);
2422
+ if (!savedK && Object.prototype.hasOwnProperty.call(rawTarget, k)) {
2423
+ savedDefaults.set(k, rawTarget[k]);
2424
+ }
2425
+ const val = props[k];
2426
+ _node.data[k] = val === undefined && savedK ? savedDefaults.get(k) : val;
2427
+ } else {
2428
+ this.onePropParsed(props, _node, k, k, true, false, hookI);
2429
+ }
2430
+ }
2431
+ cleanupKeys(prevKeys);
2432
+ prevKeys = newKeys;
2433
+ }, aoye.ScheduleType.Render);
2434
+ } else if (key === 'ref') {
2276
2435
  const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
2277
2436
  let refValue = _node;
2278
- if (_node.__logicType === FakeType.Component) {
2437
+ if (_node.__logicType & TokenizerSwitcherBit) {
2279
2438
  refValue = _node.data;
2280
2439
  } else {
2281
2440
  refValue[aoye.Keys.ProxyFreeObject] = true;
@@ -2301,8 +2460,8 @@
2301
2460
  } else {
2302
2461
  this.onePropParsed(data, _node, key, value, false, isFn, hookI);
2303
2462
  }
2304
- key = null;
2305
- eq = null;
2463
+ key = undefined;
2464
+ eq = undefined;
2306
2465
  }
2307
2466
  this.tokenizer.nextToken();
2308
2467
  }
@@ -2390,15 +2549,6 @@
2390
2549
  };
2391
2550
  return onePropParsed;
2392
2551
  }
2393
- class InlineFragment {
2394
- [aoye.Keys.ProxyFreeObject] = true;
2395
- constructor(snapshot, data, key, tokenizer) {
2396
- this.snapshot = snapshot;
2397
- this.data = data;
2398
- this.key = key;
2399
- this.tokenizer = tokenizer;
2400
- }
2401
- }
2402
2552
 
2403
2553
  function bobe(fragments, ...values) {
2404
2554
  const ui = function ui(isSub) {
@@ -2411,6 +2561,7 @@
2411
2561
  return tokenizer;
2412
2562
  };
2413
2563
  ui.boundStore = aoye.Store.Current;
2564
+ ui.__BOBE_IS_UI = true;
2414
2565
  return ui;
2415
2566
  }
2416
2567
  function customRender(option) {