bobe 0.0.11 → 0.0.13

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
 
@@ -15,19 +15,101 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
15
15
  })(TokenType || {});
16
16
  var LogicType = /* @__PURE__ */ ((LogicType2) => {
17
17
  LogicType2[LogicType2["If"] = 1] = "If";
18
- LogicType2[LogicType2["ElseIf"] = 2] = "ElseIf";
18
+ LogicType2[LogicType2["Fail"] = 2] = "Fail";
19
19
  LogicType2[LogicType2["Else"] = 4] = "Else";
20
20
  LogicType2[LogicType2["For"] = 8] = "For";
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 /* Fail */ | 4 /* Else */ | 8 /* For */;
28
+ const CondType = 1 /* If */ | 2 /* Fail */ | 4 /* Else */;
29
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
30
+ NodeType2[NodeType2["Logic"] = Logical] = "Logic";
31
+ NodeType2[NodeType2["Real"] = 128 /* Real */] = "Real";
32
+ NodeType2[NodeType2["Component"] = 16 /* Component */] = "Component";
33
+ return NodeType2;
34
+ })(NodeType || {});
26
35
  var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
27
36
  TerpEvt2["AllAttrGot"] = "all-attr-got";
28
37
  TerpEvt2["HandledComponentNode"] = "handled-component-node";
29
38
  return TerpEvt2;
30
39
  })(TerpEvt || {});
40
+ const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
41
+
42
+ class TypedStack {
43
+ constructor() {
44
+ this.top = null;
45
+ // 存储每种类型最近一次出现的包装单元引用
46
+ // 使用 Record 来动态支持不同的类型标签
47
+ this.lastNodes = {};
48
+ this.length = 0;
49
+ }
50
+ /**
51
+ * @param rawNode 原始节点数据
52
+ * @param type 节点类型
53
+ */
54
+ push(rawNode, type) {
55
+ var _a;
56
+ const newNode = {
57
+ data: rawNode,
58
+ type,
59
+ prev: this.top,
60
+ prevSameType: (_a = this.lastNodes[type]) != null ? _a : null
61
+ };
62
+ this.top = newNode;
63
+ this.length++;
64
+ this.lastNodes[type] = newNode;
65
+ }
66
+ /**
67
+ * 出栈操作
68
+ * @returns 原始节点数据或 null
69
+ */
70
+ pop() {
71
+ if (!this.top) return null;
72
+ const popped = this.top;
73
+ this.lastNodes[popped.type] = popped.prevSameType;
74
+ this.top = popped.prev;
75
+ this.length--;
76
+ return popped.data;
77
+ }
78
+ /**
79
+ * O(1) 获取栈顶节点的前一个同类型节点
80
+ */
81
+ getPrevSameType() {
82
+ if (!this.top || !this.top.prevSameType) {
83
+ return null;
84
+ }
85
+ return this.top.prevSameType.data;
86
+ }
87
+ findPrevSameType(cb) {
88
+ if (!this.top) {
89
+ return null;
90
+ }
91
+ let point = this.top.prevSameType;
92
+ while (point) {
93
+ if (cb(point.data)) {
94
+ return point.data;
95
+ }
96
+ point = point.prevSameType;
97
+ }
98
+ return null;
99
+ }
100
+ /**
101
+ * 获取当前栈顶的类型
102
+ */
103
+ get peekType() {
104
+ return this.top ? this.top.type : null;
105
+ }
106
+ /**
107
+ * 获取栈顶元素
108
+ */
109
+ peek() {
110
+ return this.top.data;
111
+ }
112
+ }
31
113
 
32
114
  var __defProp$1 = Object.defineProperty;
33
115
  var __defProps$1 = Object.defineProperties;
@@ -77,61 +159,96 @@ class Interpreter {
77
159
  return [hookType, value];
78
160
  };
79
161
  }
80
- // /** program 要挂载的父节点位置 */
81
- // root: any;
82
- // /** program 挂载的前置节点 */
83
- // anchor: any;
162
+ isLogicNode(node) {
163
+ return node && node.__logicType & Logical;
164
+ }
84
165
  program(root, before) {
166
+ var _a;
85
167
  const componentNode = {
86
168
  __logicType: LogicType.Component,
87
169
  realParent: root,
88
170
  store: new Store()
89
171
  };
90
172
  this.tokenizer.consume();
91
- let prevSibling = null;
92
- let current;
93
- const stack = [{ node: root, prev: prevSibling }];
173
+ const stack = new TypedStack();
174
+ stack.push({ node: root, prev: null }, NodeType.Real);
175
+ const ctx = {
176
+ realParent: root,
177
+ prevSibling: before,
178
+ current: null,
179
+ stack,
180
+ before
181
+ };
182
+ const rootPulling = getPulling();
94
183
  while (1) {
95
184
  if (this.tokenizer.isEof()) {
96
- this.handleInsert(root, current, prevSibling, componentNode);
185
+ if (!ctx.prevSibling) ctx.prevSibling = before;
186
+ this.handleInsert(root, ctx.current, ctx.prevSibling, componentNode);
97
187
  break;
98
188
  }
99
189
  const token = this.tokenizer.token;
100
190
  if (token.type & TokenType.Indent) {
101
191
  this.tokenizer.consume();
102
- stack.push({
103
- node: current,
104
- prev: prevSibling
105
- });
106
- current = this.declaration({ stack, prevSibling });
107
- prevSibling = null;
108
- continue;
109
- }
110
- if (current) {
111
- if (stack.length > 1) {
112
- const { node: parent } = stack[stack.length - 1];
113
- this.handleInsert(parent, current, prevSibling);
192
+ const isLogicNode = this.isLogicNode(ctx.current);
193
+ stack.push(
194
+ {
195
+ node: ctx.current,
196
+ prev: ctx.prevSibling
197
+ },
198
+ ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
199
+ );
200
+ if (ctx.current.__logicType) {
201
+ if (isLogicNode) {
202
+ setPulling(ctx.current.effect.ins);
203
+ }
114
204
  } else {
115
- if (!prevSibling) {
116
- prevSibling = before;
205
+ if (ctx.current) {
206
+ ctx.realParent = ctx.current;
117
207
  }
118
- this.handleInsert(root, current, prevSibling, componentNode);
208
+ ctx.prevSibling = null;
119
209
  }
210
+ ctx.current = this.declaration(ctx);
211
+ continue;
212
+ }
213
+ if (ctx.current) {
214
+ if (stack.length === 1 && !ctx.prevSibling) {
215
+ ctx.prevSibling = before;
216
+ }
217
+ this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
120
218
  }
121
219
  if (this.tokenizer.token.type & TokenType.Dedent) {
122
220
  this.tokenizer.consume();
123
- const { node: parent, prev } = stack.pop();
124
- prevSibling = prev;
125
- current = parent;
221
+ const { node: parent, prev } = stack.peek();
222
+ if (!parent.__logicType) {
223
+ const prevSameType = stack.getPrevSameType();
224
+ ctx.realParent = (prevSameType == null ? void 0 : prevSameType.node) || root;
225
+ } else {
226
+ if (this.isLogicNode(parent)) {
227
+ const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
228
+ if (parentLogic) {
229
+ setPulling(parentLogic.effect.ins);
230
+ } else {
231
+ setPulling(rootPulling);
232
+ }
233
+ }
234
+ }
235
+ stack.pop();
236
+ ctx.prevSibling = prev;
237
+ ctx.current = parent;
126
238
  } else {
127
- prevSibling = current;
128
- current = this.declaration({ stack, prevSibling });
239
+ ctx.prevSibling = ctx.current || ctx.prevSibling;
240
+ ctx.current = this.declaration(ctx);
129
241
  }
130
242
  }
131
- componentNode.lastInserted = this.lastInserted;
132
- this.lastInserted = null;
133
243
  return componentNode;
134
244
  }
245
+ insertAfterAnchor(ctx) {
246
+ const { realParent, prevSibling, stack, before } = ctx;
247
+ const afterAnchor = this.createAnchor();
248
+ ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
249
+ this.handleInsert(realParent, afterAnchor, prevSibling);
250
+ return afterAnchor;
251
+ }
135
252
  /** 处理
136
253
  * 是逻辑 是普通
137
254
  * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
@@ -143,25 +260,14 @@ class Interpreter {
143
260
  if (!prev || !prev.__logicType) {
144
261
  this.insertAfter(parent, child, prev);
145
262
  } else {
146
- const before = prev.lastInserted;
263
+ const before = prev.realAfter;
147
264
  this.insertAfter(parent, child, before);
148
- prev.realAfter = child;
149
265
  }
150
266
  } else {
151
267
  const childCmp = child;
152
268
  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;
269
+ if (prev == null ? void 0 : prev.__logicType) {
270
+ childCmp.realBefore = prev.realAfter;
165
271
  } else {
166
272
  childCmp.realBefore = prev;
167
273
  }
@@ -188,8 +294,8 @@ class Interpreter {
188
294
  declaration(ctx) {
189
295
  const [hookType, value] = this._hook({});
190
296
  let _node;
191
- if (value === "if") {
192
- return this.ifDeclaration();
297
+ if (value === "if" || value === "else" || value === "fail") {
298
+ return this.condDeclaration(ctx);
193
299
  } else if (hookType) {
194
300
  if (hookType === "static") {
195
301
  if (typeof value === "function" && value.prototype instanceof Store) {
@@ -263,37 +369,127 @@ class Interpreter {
263
369
  child[Keys.Raw][key] = value;
264
370
  }
265
371
  };
372
+ const afterAnchor = this.insertAfterAnchor(ctx);
373
+ const { realParent, prevSibling } = ctx;
266
374
  tap.once(TerpEvt.AllAttrGot, () => {
267
- const parent = ctx.stack[ctx.stack.length - 1].node;
268
- const prev = ctx.prevSibling;
375
+ const parent = realParent;
376
+ const prev = prevSibling;
269
377
  this.onePropParsed = prevOnePropParsed;
270
378
  const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
379
+ componentNode.realAfter = afterAnchor;
271
380
  tap.emit(TerpEvt.HandledComponentNode, componentNode);
272
381
  });
273
382
  return { __logicType: LogicType.Component };
274
383
  }
275
- ifDeclaration() {
276
- this.tokenizer.consume();
277
- const [isHook, value] = this._hook({});
384
+ // TODO: 优化代码逻辑,拆分 if elseif else
385
+ condDeclaration(ctx) {
386
+ const { prevSibling } = ctx;
387
+ const snapbackUp = this.tokenizer.snapshot();
388
+ const keyWord = this.tokenizer.consume();
389
+ const noSelfCond = this.tokenizer.token.type === TokenType.NewLine;
390
+ const [hookType, value] = this._hook({});
391
+ const isElse = keyWord.value === "else";
392
+ const isIf = keyWord.value === "if";
393
+ const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondType;
394
+ const needCalcWithPrevIf = isElse && preIsCond;
278
395
  const ifNode = {
279
- __logicType: LogicType.If,
280
- condition: value,
396
+ __logicType: isElse ? LogicType.Else : isIf ? LogicType.If : LogicType.Fail,
397
+ snapshot: noSelfCond ? snapbackUp : this.tokenizer.snapshot(),
398
+ condition: null,
281
399
  realParent: null,
282
- snapshot: this.tokenizer.snapshot(),
400
+ preCond: preIsCond ? prevSibling : null,
283
401
  isFirstRender: true,
284
- watcher: null,
285
- anchor: null
402
+ effect: null
286
403
  };
287
- ifNode.watcher = effect(
404
+ let signal;
405
+ if (noSelfCond) {
406
+ if (isElse) {
407
+ signal = $(() => {
408
+ let point = ifNode.preCond;
409
+ while (point) {
410
+ if (point.condition.v) {
411
+ return false;
412
+ }
413
+ if (point.__logicType === LogicType.If) {
414
+ break;
415
+ }
416
+ point = point.preCond;
417
+ }
418
+ return true;
419
+ });
420
+ } else {
421
+ signal = $(() => {
422
+ let point = ifNode.preCond;
423
+ while (point) {
424
+ if (point.condition.v) {
425
+ return false;
426
+ }
427
+ point = point.preCond;
428
+ }
429
+ return true;
430
+ });
431
+ }
432
+ } else {
433
+ const valueIsMapKey = Reflect.has(this.data[Keys.Raw], value);
434
+ if (valueIsMapKey && !needCalcWithPrevIf) {
435
+ runWithPulling(() => this.data[value], null);
436
+ const { cells } = this.data[Keys.Meta];
437
+ signal = cells.get(value);
438
+ } else {
439
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
440
+ if (needCalcWithPrevIf) {
441
+ signal = $(() => {
442
+ let point = ifNode.preCond;
443
+ while (point) {
444
+ if (point.condition.v) {
445
+ return false;
446
+ }
447
+ if (point.__logicType === LogicType.If) {
448
+ break;
449
+ }
450
+ point = point.preCond;
451
+ }
452
+ return fn();
453
+ });
454
+ } else {
455
+ signal = $(fn);
456
+ }
457
+ }
458
+ }
459
+ ifNode.condition = signal;
460
+ ifNode.realAfter = this.insertAfterAnchor(ctx);
461
+ ifNode.effect = effect(
288
462
  ({ val }) => {
289
463
  if (val) {
290
- this.tokenizer.consume();
291
- this.tokenizer.consume();
464
+ if (ifNode.isFirstRender) {
465
+ if (!noSelfCond) {
466
+ this.tokenizer.consume();
467
+ }
468
+ this.tokenizer.consume();
469
+ } else {
470
+ this.tokenizer.resume(ifNode.snapshot);
471
+ this.program(ifNode.realParent, ifNode.realBefore);
472
+ }
292
473
  } else {
293
- this.tokenizer.skip();
474
+ if (ifNode.isFirstRender) {
475
+ if (noSelfCond) {
476
+ this.tokenizer.i = this.tokenizer.i - 1;
477
+ this.tokenizer.needIndent = false;
478
+ }
479
+ this.tokenizer.skip();
480
+ } else {
481
+ const { realBefore, realAfter, realParent } = ifNode;
482
+ let point = realBefore ? this.nextSib(realBefore) : this.kid(realParent);
483
+ while (point !== realAfter) {
484
+ const next = this.nextSib(point);
485
+ this.remove(point, realParent, realBefore);
486
+ point = next;
487
+ }
488
+ }
294
489
  }
490
+ ifNode.isFirstRender = false;
295
491
  },
296
- [value]
492
+ [signal]
297
493
  );
298
494
  return ifNode;
299
495
  }
@@ -371,6 +567,14 @@ class Interpreter {
371
567
  nextSib(node) {
372
568
  return node.nextSibling;
373
569
  }
570
+ kid(node) {
571
+ return node.firstChild;
572
+ }
573
+ _createAnchor() {
574
+ const anchor = this.createAnchor();
575
+ anchor[IsAnchor] = true;
576
+ return anchor;
577
+ }
374
578
  createAnchor() {
375
579
  return {
376
580
  name: "anchor",
@@ -378,7 +582,6 @@ class Interpreter {
378
582
  };
379
583
  }
380
584
  insertAfter(parent, node, prev) {
381
- this.lastInserted = node;
382
585
  return this.defaultInsert(parent, node, prev);
383
586
  }
384
587
  defaultInsert(parent, node, prev) {
@@ -387,14 +590,16 @@ class Interpreter {
387
590
  prev.nextSibling = node;
388
591
  node.nextSibling = next;
389
592
  } else {
593
+ const next = parent.firstChild;
390
594
  parent.firstChild = node;
595
+ node.nextSibling = next;
391
596
  }
392
597
  }
393
- remove(parent, node, prevSibling) {
394
- return this.defaultRemove(parent, node, prevSibling);
598
+ remove(node, parent, prev) {
599
+ return this.defaultRemove(node, parent, prev);
395
600
  }
396
601
  // TODO: 默认改成 prevItem
397
- defaultRemove(parent, node, prevSibling) {
602
+ defaultRemove(node, parent, prevSibling) {
398
603
  const next = node.nextSibling;
399
604
  if (prevSibling) {
400
605
  prevSibling.nextSibling = next;
@@ -467,7 +672,7 @@ const _Tokenizer = class _Tokenizer {
467
672
  };
468
673
  }
469
674
  skip() {
470
- const dentLen = this.dentStack[this.dentStack.length - 1];
675
+ const logicDentLen = this.dentStack[this.dentStack.length - 1];
471
676
  let needIndent = false;
472
677
  let skipFragment = ``;
473
678
  this.token = void 0;
@@ -488,7 +693,7 @@ const _Tokenizer = class _Tokenizer {
488
693
  const { value, isEmptyLine } = this.getDentValue();
489
694
  const currLen = value.length;
490
695
  if (isEmptyLine) continue;
491
- if (value.length > dentLen) {
696
+ if (currLen > logicDentLen) {
492
697
  skipFragment += value;
493
698
  } else {
494
699
  for (let i = this.dentStack.length - 1; i >= 0; i--) {
@@ -497,6 +702,9 @@ const _Tokenizer = class _Tokenizer {
497
702
  if (currLen > expLen) {
498
703
  throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
499
704
  }
705
+ if (this.shorterThanBaseDentEof()) {
706
+ break;
707
+ }
500
708
  this.dentStack.pop();
501
709
  if (!this.token) {
502
710
  this.setToken(TokenType.Dedent, String(expLen));
@@ -761,12 +969,15 @@ ${_Tokenizer.EofId}`;
761
969
  return indentHasLen;
762
970
  }
763
971
  if (currLen < prevLen) {
764
- for (let i = this.dentStack.length - 2; i >= 0; i--) {
972
+ for (let i = this.dentStack.length; i--; ) {
765
973
  const expLen = this.dentStack[i];
766
- const prevExpLen = this.dentStack[i + 1];
767
- if (currLen > expLen && currLen < prevExpLen) {
974
+ if (currLen === expLen) break;
975
+ if (currLen > expLen) {
768
976
  throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
769
977
  }
978
+ if (this.shorterThanBaseDentEof()) {
979
+ return;
980
+ }
770
981
  this.dentStack.pop();
771
982
  if (!this.token) {
772
983
  this.setToken(TokenType.Dedent, String(expLen));
@@ -777,14 +988,26 @@ ${_Tokenizer.EofId}`;
777
988
  value: String(expLen)
778
989
  });
779
990
  }
780
- if (currLen === expLen) {
781
- break;
782
- }
783
991
  }
784
992
  return indentHasLen;
785
993
  }
786
994
  return indentHasLen;
787
995
  }
996
+ shorterThanBaseDentEof() {
997
+ const yes = this.dentStack.length === 1;
998
+ if (yes) {
999
+ if (!this.token) {
1000
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1001
+ } else {
1002
+ this.waitingTokens.push({
1003
+ type: TokenType.Identifier,
1004
+ typeName: TokenType[TokenType.Identifier],
1005
+ value: _Tokenizer.EofId
1006
+ });
1007
+ }
1008
+ }
1009
+ return yes;
1010
+ }
788
1011
  identifier(char) {
789
1012
  let value = char;
790
1013
  let nextC;