bobe 0.0.11 → 0.0.12

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/bobe.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Store, Keys, effect, shareSignal, $ } from 'aoye';
1
+ import { Store, getPulling, setPulling, Keys, effect, shareSignal, $, runWithPulling } from 'aoye';
2
2
  export * from 'aoye';
3
3
  import { BaseEvent, Queue, isNum } from 'bobe-shared';
4
4
 
@@ -21,13 +21,94 @@ var LogicType = /* @__PURE__ */ ((LogicType2) => {
21
21
  LogicType2[LogicType2["Component"] = 16] = "Component";
22
22
  LogicType2[LogicType2["Fragment"] = 32] = "Fragment";
23
23
  LogicType2[LogicType2["Root"] = 64] = "Root";
24
+ LogicType2[LogicType2["Real"] = 128] = "Real";
24
25
  return LogicType2;
25
26
  })(LogicType || {});
27
+ const Logical = 1 /* If */ | 2 /* ElseIf */ | 4 /* Else */ | 8 /* For */;
28
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
29
+ NodeType2[NodeType2["Logic"] = Logical] = "Logic";
30
+ NodeType2[NodeType2["Real"] = 128 /* Real */] = "Real";
31
+ NodeType2[NodeType2["Component"] = 16 /* Component */] = "Component";
32
+ return NodeType2;
33
+ })(NodeType || {});
26
34
  var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
27
35
  TerpEvt2["AllAttrGot"] = "all-attr-got";
28
36
  TerpEvt2["HandledComponentNode"] = "handled-component-node";
29
37
  return TerpEvt2;
30
38
  })(TerpEvt || {});
39
+ const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
40
+
41
+ class TypedStack {
42
+ constructor() {
43
+ this.top = null;
44
+ // 存储每种类型最近一次出现的包装单元引用
45
+ // 使用 Record 来动态支持不同的类型标签
46
+ this.lastNodes = {};
47
+ this.length = 0;
48
+ }
49
+ /**
50
+ * @param rawNode 原始节点数据
51
+ * @param type 节点类型
52
+ */
53
+ push(rawNode, type) {
54
+ var _a;
55
+ const newNode = {
56
+ data: rawNode,
57
+ type,
58
+ prev: this.top,
59
+ prevSameType: (_a = this.lastNodes[type]) != null ? _a : null
60
+ };
61
+ this.top = newNode;
62
+ this.length++;
63
+ this.lastNodes[type] = newNode;
64
+ }
65
+ /**
66
+ * 出栈操作
67
+ * @returns 原始节点数据或 null
68
+ */
69
+ pop() {
70
+ if (!this.top) return null;
71
+ const popped = this.top;
72
+ this.lastNodes[popped.type] = popped.prevSameType;
73
+ this.top = popped.prev;
74
+ this.length--;
75
+ return popped.data;
76
+ }
77
+ /**
78
+ * O(1) 获取栈顶节点的前一个同类型节点
79
+ */
80
+ getPrevSameType() {
81
+ if (!this.top || !this.top.prevSameType) {
82
+ return null;
83
+ }
84
+ return this.top.prevSameType.data;
85
+ }
86
+ findPrevSameType(cb) {
87
+ if (!this.top) {
88
+ return null;
89
+ }
90
+ let point = this.top.prevSameType;
91
+ while (point) {
92
+ if (cb(point.data)) {
93
+ return point.data;
94
+ }
95
+ point = point.prevSameType;
96
+ }
97
+ return null;
98
+ }
99
+ /**
100
+ * 获取当前栈顶的类型
101
+ */
102
+ get peekType() {
103
+ return this.top ? this.top.type : null;
104
+ }
105
+ /**
106
+ * 获取栈顶元素
107
+ */
108
+ peek() {
109
+ return this.top.data;
110
+ }
111
+ }
31
112
 
32
113
  var __defProp$1 = Object.defineProperty;
33
114
  var __defProps$1 = Object.defineProperties;
@@ -77,61 +158,94 @@ class Interpreter {
77
158
  return [hookType, value];
78
159
  };
79
160
  }
80
- // /** program 要挂载的父节点位置 */
81
- // root: any;
82
- // /** program 挂载的前置节点 */
83
- // anchor: any;
161
+ isLogicNode(node) {
162
+ return node && node.__logicType & Logical;
163
+ }
84
164
  program(root, before) {
165
+ var _a;
85
166
  const componentNode = {
86
167
  __logicType: LogicType.Component,
87
168
  realParent: root,
88
169
  store: new Store()
89
170
  };
90
171
  this.tokenizer.consume();
91
- let prevSibling = null;
92
- let current;
93
- const stack = [{ node: root, prev: prevSibling }];
172
+ const stack = new TypedStack();
173
+ stack.push({ node: root, prev: null }, NodeType.Real);
174
+ const ctx = {
175
+ realParent: root,
176
+ prevSibling: before,
177
+ current: null,
178
+ stack,
179
+ before
180
+ };
181
+ const rootPulling = getPulling();
94
182
  while (1) {
95
183
  if (this.tokenizer.isEof()) {
96
- this.handleInsert(root, current, prevSibling, componentNode);
184
+ if (!ctx.prevSibling) ctx.prevSibling = before;
185
+ this.handleInsert(root, ctx.current, ctx.prevSibling, componentNode);
97
186
  break;
98
187
  }
99
188
  const token = this.tokenizer.token;
100
189
  if (token.type & TokenType.Indent) {
101
190
  this.tokenizer.consume();
102
- stack.push({
103
- node: current,
104
- prev: prevSibling
105
- });
106
- current = this.declaration({ stack, prevSibling });
107
- prevSibling = null;
191
+ const isLogicNode = this.isLogicNode(ctx.current);
192
+ stack.push(
193
+ {
194
+ node: ctx.current,
195
+ prev: ctx.prevSibling
196
+ },
197
+ ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
198
+ );
199
+ if (ctx.current.__logicType) {
200
+ if (isLogicNode) {
201
+ setPulling(ctx.current.effect.ins);
202
+ }
203
+ } else {
204
+ ctx.realParent = ctx.current;
205
+ ctx.prevSibling = null;
206
+ }
207
+ ctx.current = this.declaration(ctx);
108
208
  continue;
109
209
  }
110
- if (current) {
111
- if (stack.length > 1) {
112
- const { node: parent } = stack[stack.length - 1];
113
- this.handleInsert(parent, current, prevSibling);
114
- } else {
115
- if (!prevSibling) {
116
- prevSibling = before;
117
- }
118
- this.handleInsert(root, current, prevSibling, componentNode);
210
+ if (ctx.current) {
211
+ if (stack.length === 1 && !ctx.prevSibling) {
212
+ ctx.prevSibling = before;
119
213
  }
214
+ this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
120
215
  }
121
216
  if (this.tokenizer.token.type & TokenType.Dedent) {
122
217
  this.tokenizer.consume();
123
- const { node: parent, prev } = stack.pop();
124
- prevSibling = prev;
125
- current = parent;
218
+ const { node: parent, prev } = stack.peek();
219
+ if (!parent.__logicType) {
220
+ const prevSameType = stack.getPrevSameType();
221
+ ctx.realParent = prevSameType == null ? void 0 : prevSameType.node;
222
+ } else {
223
+ if (this.isLogicNode(parent)) {
224
+ const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
225
+ if (parentLogic) {
226
+ setPulling(parentLogic.effect.ins);
227
+ } else {
228
+ setPulling(rootPulling);
229
+ }
230
+ }
231
+ }
232
+ stack.pop();
233
+ ctx.prevSibling = prev;
234
+ ctx.current = parent;
126
235
  } else {
127
- prevSibling = current;
128
- current = this.declaration({ stack, prevSibling });
236
+ ctx.prevSibling = ctx.current || ctx.prevSibling;
237
+ ctx.current = this.declaration(ctx);
129
238
  }
130
239
  }
131
- componentNode.lastInserted = this.lastInserted;
132
- this.lastInserted = null;
133
240
  return componentNode;
134
241
  }
242
+ insertAfterAnchor(ctx) {
243
+ const { realParent, prevSibling, stack, before } = ctx;
244
+ const afterAnchor = this.createAnchor();
245
+ ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
246
+ this.handleInsert(realParent, afterAnchor, prevSibling);
247
+ return afterAnchor;
248
+ }
135
249
  /** 处理
136
250
  * 是逻辑 是普通
137
251
  * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
@@ -143,25 +257,14 @@ class Interpreter {
143
257
  if (!prev || !prev.__logicType) {
144
258
  this.insertAfter(parent, child, prev);
145
259
  } else {
146
- const before = prev.lastInserted;
260
+ const before = prev.realAfter;
147
261
  this.insertAfter(parent, child, before);
148
- prev.realAfter = child;
149
262
  }
150
263
  } else {
151
264
  const childCmp = child;
152
265
  childCmp.realParent = parent;
153
- if (!prev) {
154
- const anchor = this.createAnchor();
155
- this.insertAfter(parent, anchor, prev);
156
- this.insertAfter(parent, child, anchor);
157
- childCmp.realBefore = anchor;
158
- } else if (prev.__logicType) {
159
- const before = prev.lastInserted;
160
- const anchor = this.createAnchor();
161
- this.insertAfter(parent, anchor, before);
162
- this.insertAfter(parent, child, anchor);
163
- childCmp.realBefore = anchor;
164
- prev.realAfter = anchor;
266
+ if (prev.__logicType) {
267
+ childCmp.realBefore = prev.realAfter;
165
268
  } else {
166
269
  childCmp.realBefore = prev;
167
270
  }
@@ -189,7 +292,7 @@ class Interpreter {
189
292
  const [hookType, value] = this._hook({});
190
293
  let _node;
191
294
  if (value === "if") {
192
- return this.ifDeclaration();
295
+ return this.ifDeclaration(ctx);
193
296
  } else if (hookType) {
194
297
  if (hookType === "static") {
195
298
  if (typeof value === "function" && value.prototype instanceof Store) {
@@ -263,37 +366,66 @@ class Interpreter {
263
366
  child[Keys.Raw][key] = value;
264
367
  }
265
368
  };
369
+ const afterAnchor = this.insertAfterAnchor(ctx);
266
370
  tap.once(TerpEvt.AllAttrGot, () => {
267
- const parent = ctx.stack[ctx.stack.length - 1].node;
371
+ const parent = ctx.realParent;
268
372
  const prev = ctx.prevSibling;
269
373
  this.onePropParsed = prevOnePropParsed;
270
374
  const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
375
+ componentNode.realAfter = afterAnchor;
271
376
  tap.emit(TerpEvt.HandledComponentNode, componentNode);
272
377
  });
273
378
  return { __logicType: LogicType.Component };
274
379
  }
275
- ifDeclaration() {
380
+ ifDeclaration(ctx) {
276
381
  this.tokenizer.consume();
277
- const [isHook, value] = this._hook({});
382
+ const [hookType, value] = this._hook({});
278
383
  const ifNode = {
279
384
  __logicType: LogicType.If,
280
- condition: value,
281
- realParent: null,
282
385
  snapshot: this.tokenizer.snapshot(),
386
+ condition: null,
387
+ realParent: null,
283
388
  isFirstRender: true,
284
- watcher: null,
285
- anchor: null
389
+ effect: null
286
390
  };
287
- ifNode.watcher = effect(
391
+ const valueIsMapKey = Reflect.has(this.data[Keys.Raw], value);
392
+ let signal;
393
+ if (valueIsMapKey) {
394
+ runWithPulling(() => this.data[value], null);
395
+ const { cells } = this.data[Keys.Meta];
396
+ signal = cells.get(value);
397
+ } else {
398
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
399
+ signal = $(fn);
400
+ }
401
+ ifNode.condition = signal;
402
+ ifNode.realAfter = this.insertAfterAnchor(ctx);
403
+ ifNode.effect = effect(
288
404
  ({ val }) => {
289
405
  if (val) {
290
- this.tokenizer.consume();
291
- this.tokenizer.consume();
406
+ if (ifNode.isFirstRender) {
407
+ this.tokenizer.consume();
408
+ this.tokenizer.consume();
409
+ } else {
410
+ this.tokenizer.resume(ifNode.snapshot);
411
+ this.program(ifNode.realParent, ifNode.realBefore);
412
+ }
292
413
  } else {
293
- this.tokenizer.skip();
414
+ if (ifNode.isFirstRender) {
415
+ this.tokenizer.skip();
416
+ } else {
417
+ const { realBefore, realAfter, realParent } = ifNode;
418
+ let point = this.nextSib(realBefore);
419
+ while (point !== realAfter) {
420
+ const next = this.nextSib(point);
421
+ this.remove(point, realParent, realBefore);
422
+ point = next;
423
+ }
424
+ }
294
425
  }
426
+ ifNode.isFirstRender = false;
295
427
  },
296
- [value]
428
+ [signal]
297
429
  );
298
430
  return ifNode;
299
431
  }
@@ -371,6 +503,11 @@ class Interpreter {
371
503
  nextSib(node) {
372
504
  return node.nextSibling;
373
505
  }
506
+ _createAnchor() {
507
+ const anchor = this.createAnchor();
508
+ anchor[IsAnchor] = true;
509
+ return anchor;
510
+ }
374
511
  createAnchor() {
375
512
  return {
376
513
  name: "anchor",
@@ -378,7 +515,6 @@ class Interpreter {
378
515
  };
379
516
  }
380
517
  insertAfter(parent, node, prev) {
381
- this.lastInserted = node;
382
518
  return this.defaultInsert(parent, node, prev);
383
519
  }
384
520
  defaultInsert(parent, node, prev) {
@@ -390,11 +526,11 @@ class Interpreter {
390
526
  parent.firstChild = node;
391
527
  }
392
528
  }
393
- remove(parent, node, prevSibling) {
394
- return this.defaultRemove(parent, node, prevSibling);
529
+ remove(node, parent, prev) {
530
+ return this.defaultRemove(node, parent, prev);
395
531
  }
396
532
  // TODO: 默认改成 prevItem
397
- defaultRemove(parent, node, prevSibling) {
533
+ defaultRemove(node, parent, prevSibling) {
398
534
  const next = node.nextSibling;
399
535
  if (prevSibling) {
400
536
  prevSibling.nextSibling = next;
@@ -467,7 +603,7 @@ const _Tokenizer = class _Tokenizer {
467
603
  };
468
604
  }
469
605
  skip() {
470
- const dentLen = this.dentStack[this.dentStack.length - 1];
606
+ const logicDentLen = this.dentStack[this.dentStack.length - 1];
471
607
  let needIndent = false;
472
608
  let skipFragment = ``;
473
609
  this.token = void 0;
@@ -488,7 +624,7 @@ const _Tokenizer = class _Tokenizer {
488
624
  const { value, isEmptyLine } = this.getDentValue();
489
625
  const currLen = value.length;
490
626
  if (isEmptyLine) continue;
491
- if (value.length > dentLen) {
627
+ if (currLen > logicDentLen) {
492
628
  skipFragment += value;
493
629
  } else {
494
630
  for (let i = this.dentStack.length - 1; i >= 0; i--) {
@@ -497,6 +633,9 @@ const _Tokenizer = class _Tokenizer {
497
633
  if (currLen > expLen) {
498
634
  throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
499
635
  }
636
+ if (this.shorterThanBaseDentEof()) {
637
+ break;
638
+ }
500
639
  this.dentStack.pop();
501
640
  if (!this.token) {
502
641
  this.setToken(TokenType.Dedent, String(expLen));
@@ -761,12 +900,15 @@ ${_Tokenizer.EofId}`;
761
900
  return indentHasLen;
762
901
  }
763
902
  if (currLen < prevLen) {
764
- for (let i = this.dentStack.length - 2; i >= 0; i--) {
903
+ for (let i = this.dentStack.length; i--; ) {
765
904
  const expLen = this.dentStack[i];
766
- const prevExpLen = this.dentStack[i + 1];
767
- if (currLen > expLen && currLen < prevExpLen) {
905
+ if (currLen === expLen) break;
906
+ if (currLen > expLen) {
768
907
  throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
769
908
  }
909
+ if (this.shorterThanBaseDentEof()) {
910
+ return;
911
+ }
770
912
  this.dentStack.pop();
771
913
  if (!this.token) {
772
914
  this.setToken(TokenType.Dedent, String(expLen));
@@ -777,14 +919,26 @@ ${_Tokenizer.EofId}`;
777
919
  value: String(expLen)
778
920
  });
779
921
  }
780
- if (currLen === expLen) {
781
- break;
782
- }
783
922
  }
784
923
  return indentHasLen;
785
924
  }
786
925
  return indentHasLen;
787
926
  }
927
+ shorterThanBaseDentEof() {
928
+ const yes = this.dentStack.length === 1;
929
+ if (yes) {
930
+ if (!this.token) {
931
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
932
+ } else {
933
+ this.waitingTokens.push({
934
+ type: TokenType.Identifier,
935
+ typeName: TokenType[TokenType.Identifier],
936
+ value: _Tokenizer.EofId
937
+ });
938
+ }
939
+ }
940
+ return yes;
941
+ }
788
942
  identifier(char) {
789
943
  let value = char;
790
944
  let nextC;