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