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.cjs.js CHANGED
@@ -22,13 +22,94 @@ var LogicType = /* @__PURE__ */ ((LogicType2) => {
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 /* ElseIf */ | 4 /* Else */ | 8 /* For */;
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 || {});
27
35
  var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
28
36
  TerpEvt2["AllAttrGot"] = "all-attr-got";
29
37
  TerpEvt2["HandledComponentNode"] = "handled-component-node";
30
38
  return TerpEvt2;
31
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
+ }
32
113
 
33
114
  var __defProp$1 = Object.defineProperty;
34
115
  var __defProps$1 = Object.defineProperties;
@@ -78,61 +159,94 @@ class Interpreter {
78
159
  return [hookType, value];
79
160
  };
80
161
  }
81
- // /** program 要挂载的父节点位置 */
82
- // root: any;
83
- // /** program 挂载的前置节点 */
84
- // anchor: any;
162
+ isLogicNode(node) {
163
+ return node && node.__logicType & Logical;
164
+ }
85
165
  program(root, before) {
166
+ var _a;
86
167
  const componentNode = {
87
168
  __logicType: LogicType.Component,
88
169
  realParent: root,
89
170
  store: new aoye.Store()
90
171
  };
91
172
  this.tokenizer.consume();
92
- let prevSibling = null;
93
- let current;
94
- 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 = aoye.getPulling();
95
183
  while (1) {
96
184
  if (this.tokenizer.isEof()) {
97
- this.handleInsert(root, current, prevSibling, componentNode);
185
+ if (!ctx.prevSibling) ctx.prevSibling = before;
186
+ this.handleInsert(root, ctx.current, ctx.prevSibling, componentNode);
98
187
  break;
99
188
  }
100
189
  const token = this.tokenizer.token;
101
190
  if (token.type & TokenType.Indent) {
102
191
  this.tokenizer.consume();
103
- stack.push({
104
- node: current,
105
- prev: prevSibling
106
- });
107
- current = this.declaration({ stack, prevSibling });
108
- prevSibling = null;
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
+ aoye.setPulling(ctx.current.effect.ins);
203
+ }
204
+ } else {
205
+ ctx.realParent = ctx.current;
206
+ ctx.prevSibling = null;
207
+ }
208
+ ctx.current = this.declaration(ctx);
109
209
  continue;
110
210
  }
111
- if (current) {
112
- if (stack.length > 1) {
113
- const { node: parent } = stack[stack.length - 1];
114
- this.handleInsert(parent, current, prevSibling);
115
- } else {
116
- if (!prevSibling) {
117
- prevSibling = before;
118
- }
119
- this.handleInsert(root, current, prevSibling, componentNode);
211
+ if (ctx.current) {
212
+ if (stack.length === 1 && !ctx.prevSibling) {
213
+ ctx.prevSibling = before;
120
214
  }
215
+ this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
121
216
  }
122
217
  if (this.tokenizer.token.type & TokenType.Dedent) {
123
218
  this.tokenizer.consume();
124
- const { node: parent, prev } = stack.pop();
125
- prevSibling = prev;
126
- current = parent;
219
+ const { node: parent, prev } = stack.peek();
220
+ if (!parent.__logicType) {
221
+ const prevSameType = stack.getPrevSameType();
222
+ ctx.realParent = prevSameType == null ? void 0 : prevSameType.node;
223
+ } else {
224
+ if (this.isLogicNode(parent)) {
225
+ const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
226
+ if (parentLogic) {
227
+ aoye.setPulling(parentLogic.effect.ins);
228
+ } else {
229
+ aoye.setPulling(rootPulling);
230
+ }
231
+ }
232
+ }
233
+ stack.pop();
234
+ ctx.prevSibling = prev;
235
+ ctx.current = parent;
127
236
  } else {
128
- prevSibling = current;
129
- current = this.declaration({ stack, prevSibling });
237
+ ctx.prevSibling = ctx.current || ctx.prevSibling;
238
+ ctx.current = this.declaration(ctx);
130
239
  }
131
240
  }
132
- componentNode.lastInserted = this.lastInserted;
133
- this.lastInserted = null;
134
241
  return componentNode;
135
242
  }
243
+ insertAfterAnchor(ctx) {
244
+ const { realParent, prevSibling, stack, before } = ctx;
245
+ const afterAnchor = this.createAnchor();
246
+ ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
247
+ this.handleInsert(realParent, afterAnchor, prevSibling);
248
+ return afterAnchor;
249
+ }
136
250
  /** 处理
137
251
  * 是逻辑 是普通
138
252
  * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
@@ -144,25 +258,14 @@ class Interpreter {
144
258
  if (!prev || !prev.__logicType) {
145
259
  this.insertAfter(parent, child, prev);
146
260
  } else {
147
- const before = prev.lastInserted;
261
+ const before = prev.realAfter;
148
262
  this.insertAfter(parent, child, before);
149
- prev.realAfter = child;
150
263
  }
151
264
  } else {
152
265
  const childCmp = child;
153
266
  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;
267
+ if (prev.__logicType) {
268
+ childCmp.realBefore = prev.realAfter;
166
269
  } else {
167
270
  childCmp.realBefore = prev;
168
271
  }
@@ -190,7 +293,7 @@ class Interpreter {
190
293
  const [hookType, value] = this._hook({});
191
294
  let _node;
192
295
  if (value === "if") {
193
- return this.ifDeclaration();
296
+ return this.ifDeclaration(ctx);
194
297
  } else if (hookType) {
195
298
  if (hookType === "static") {
196
299
  if (typeof value === "function" && value.prototype instanceof aoye.Store) {
@@ -264,37 +367,66 @@ class Interpreter {
264
367
  child[aoye.Keys.Raw][key] = value;
265
368
  }
266
369
  };
370
+ const afterAnchor = this.insertAfterAnchor(ctx);
267
371
  tap.once(TerpEvt.AllAttrGot, () => {
268
- const parent = ctx.stack[ctx.stack.length - 1].node;
372
+ const parent = ctx.realParent;
269
373
  const prev = ctx.prevSibling;
270
374
  this.onePropParsed = prevOnePropParsed;
271
375
  const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
376
+ componentNode.realAfter = afterAnchor;
272
377
  tap.emit(TerpEvt.HandledComponentNode, componentNode);
273
378
  });
274
379
  return { __logicType: LogicType.Component };
275
380
  }
276
- ifDeclaration() {
381
+ ifDeclaration(ctx) {
277
382
  this.tokenizer.consume();
278
- const [isHook, value] = this._hook({});
383
+ const [hookType, value] = this._hook({});
279
384
  const ifNode = {
280
385
  __logicType: LogicType.If,
281
- condition: value,
282
- realParent: null,
283
386
  snapshot: this.tokenizer.snapshot(),
387
+ condition: null,
388
+ realParent: null,
284
389
  isFirstRender: true,
285
- watcher: null,
286
- anchor: null
390
+ effect: null
287
391
  };
288
- ifNode.watcher = aoye.effect(
392
+ const valueIsMapKey = Reflect.has(this.data[aoye.Keys.Raw], value);
393
+ let signal;
394
+ if (valueIsMapKey) {
395
+ aoye.runWithPulling(() => this.data[value], null);
396
+ const { cells } = this.data[aoye.Keys.Meta];
397
+ signal = cells.get(value);
398
+ } else {
399
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
400
+ signal = aoye.$(fn);
401
+ }
402
+ ifNode.condition = signal;
403
+ ifNode.realAfter = this.insertAfterAnchor(ctx);
404
+ ifNode.effect = aoye.effect(
289
405
  ({ val }) => {
290
406
  if (val) {
291
- this.tokenizer.consume();
292
- this.tokenizer.consume();
407
+ if (ifNode.isFirstRender) {
408
+ this.tokenizer.consume();
409
+ this.tokenizer.consume();
410
+ } else {
411
+ this.tokenizer.resume(ifNode.snapshot);
412
+ this.program(ifNode.realParent, ifNode.realBefore);
413
+ }
293
414
  } else {
294
- this.tokenizer.skip();
415
+ if (ifNode.isFirstRender) {
416
+ this.tokenizer.skip();
417
+ } else {
418
+ const { realBefore, realAfter, realParent } = ifNode;
419
+ let point = this.nextSib(realBefore);
420
+ while (point !== realAfter) {
421
+ const next = this.nextSib(point);
422
+ this.remove(point, realParent, realBefore);
423
+ point = next;
424
+ }
425
+ }
295
426
  }
427
+ ifNode.isFirstRender = false;
296
428
  },
297
- [value]
429
+ [signal]
298
430
  );
299
431
  return ifNode;
300
432
  }
@@ -372,6 +504,11 @@ class Interpreter {
372
504
  nextSib(node) {
373
505
  return node.nextSibling;
374
506
  }
507
+ _createAnchor() {
508
+ const anchor = this.createAnchor();
509
+ anchor[IsAnchor] = true;
510
+ return anchor;
511
+ }
375
512
  createAnchor() {
376
513
  return {
377
514
  name: "anchor",
@@ -379,7 +516,6 @@ class Interpreter {
379
516
  };
380
517
  }
381
518
  insertAfter(parent, node, prev) {
382
- this.lastInserted = node;
383
519
  return this.defaultInsert(parent, node, prev);
384
520
  }
385
521
  defaultInsert(parent, node, prev) {
@@ -391,11 +527,11 @@ class Interpreter {
391
527
  parent.firstChild = node;
392
528
  }
393
529
  }
394
- remove(parent, node, prevSibling) {
395
- return this.defaultRemove(parent, node, prevSibling);
530
+ remove(node, parent, prev) {
531
+ return this.defaultRemove(node, parent, prev);
396
532
  }
397
533
  // TODO: 默认改成 prevItem
398
- defaultRemove(parent, node, prevSibling) {
534
+ defaultRemove(node, parent, prevSibling) {
399
535
  const next = node.nextSibling;
400
536
  if (prevSibling) {
401
537
  prevSibling.nextSibling = next;
@@ -468,7 +604,7 @@ const _Tokenizer = class _Tokenizer {
468
604
  };
469
605
  }
470
606
  skip() {
471
- const dentLen = this.dentStack[this.dentStack.length - 1];
607
+ const logicDentLen = this.dentStack[this.dentStack.length - 1];
472
608
  let needIndent = false;
473
609
  let skipFragment = ``;
474
610
  this.token = void 0;
@@ -489,7 +625,7 @@ const _Tokenizer = class _Tokenizer {
489
625
  const { value, isEmptyLine } = this.getDentValue();
490
626
  const currLen = value.length;
491
627
  if (isEmptyLine) continue;
492
- if (value.length > dentLen) {
628
+ if (currLen > logicDentLen) {
493
629
  skipFragment += value;
494
630
  } else {
495
631
  for (let i = this.dentStack.length - 1; i >= 0; i--) {
@@ -498,6 +634,9 @@ const _Tokenizer = class _Tokenizer {
498
634
  if (currLen > expLen) {
499
635
  throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
500
636
  }
637
+ if (this.shorterThanBaseDentEof()) {
638
+ break;
639
+ }
501
640
  this.dentStack.pop();
502
641
  if (!this.token) {
503
642
  this.setToken(TokenType.Dedent, String(expLen));
@@ -762,12 +901,15 @@ ${_Tokenizer.EofId}`;
762
901
  return indentHasLen;
763
902
  }
764
903
  if (currLen < prevLen) {
765
- for (let i = this.dentStack.length - 2; i >= 0; i--) {
904
+ for (let i = this.dentStack.length; i--; ) {
766
905
  const expLen = this.dentStack[i];
767
- const prevExpLen = this.dentStack[i + 1];
768
- if (currLen > expLen && currLen < prevExpLen) {
906
+ if (currLen === expLen) break;
907
+ if (currLen > expLen) {
769
908
  throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
770
909
  }
910
+ if (this.shorterThanBaseDentEof()) {
911
+ return;
912
+ }
771
913
  this.dentStack.pop();
772
914
  if (!this.token) {
773
915
  this.setToken(TokenType.Dedent, String(expLen));
@@ -778,14 +920,26 @@ ${_Tokenizer.EofId}`;
778
920
  value: String(expLen)
779
921
  });
780
922
  }
781
- if (currLen === expLen) {
782
- break;
783
- }
784
923
  }
785
924
  return indentHasLen;
786
925
  }
787
926
  return indentHasLen;
788
927
  }
928
+ shorterThanBaseDentEof() {
929
+ const yes = this.dentStack.length === 1;
930
+ if (yes) {
931
+ if (!this.token) {
932
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
933
+ } else {
934
+ this.waitingTokens.push({
935
+ type: TokenType.Identifier,
936
+ typeName: TokenType[TokenType.Identifier],
937
+ value: _Tokenizer.EofId
938
+ });
939
+ }
940
+ }
941
+ return yes;
942
+ }
789
943
  identifier(char) {
790
944
  let value = char;
791
945
  let nextC;