bobe 0.0.15 → 0.0.17

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
@@ -14,25 +14,27 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
14
14
  TokenType2[TokenType2["InsertionExp"] = 128] = "InsertionExp";
15
15
  return TokenType2;
16
16
  })(TokenType || {});
17
- var LogicType = /* @__PURE__ */ ((LogicType2) => {
18
- LogicType2[LogicType2["If"] = 1] = "If";
19
- LogicType2[LogicType2["Fail"] = 2] = "Fail";
20
- LogicType2[LogicType2["Else"] = 4] = "Else";
21
- LogicType2[LogicType2["For"] = 8] = "For";
22
- LogicType2[LogicType2["Component"] = 16] = "Component";
23
- LogicType2[LogicType2["Fragment"] = 32] = "Fragment";
24
- LogicType2[LogicType2["Root"] = 64] = "Root";
25
- LogicType2[LogicType2["Real"] = 128] = "Real";
26
- return LogicType2;
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 || {});
17
+ var FakeType = /* @__PURE__ */ ((FakeType2) => {
18
+ FakeType2[FakeType2["If"] = 1] = "If";
19
+ FakeType2[FakeType2["Fail"] = 2] = "Fail";
20
+ FakeType2[FakeType2["Else"] = 4] = "Else";
21
+ FakeType2[FakeType2["For"] = 8] = "For";
22
+ FakeType2[FakeType2["Component"] = 16] = "Component";
23
+ FakeType2[FakeType2["Fragment"] = 32] = "Fragment";
24
+ FakeType2[FakeType2["ForItem"] = 64] = "ForItem";
25
+ return FakeType2;
26
+ })(FakeType || {});
27
+ const CondBit = 1 /* If */ | 2 /* Fail */ | 4 /* Else */;
28
+ const LogicalBit = 1 /* If */ | 2 /* Fail */ | 4 /* Else */ | 8 /* For */ | 64 /* ForItem */;
29
+ const TokenizerSwitcherBit = 16 /* Component */ | 32 /* Fragment */;
30
+ var NodeSort = /* @__PURE__ */ ((NodeSort2) => {
31
+ NodeSort2[NodeSort2["Logic"] = 1] = "Logic";
32
+ NodeSort2[NodeSort2["Real"] = 2] = "Real";
33
+ NodeSort2[NodeSort2["Component"] = 4] = "Component";
34
+ NodeSort2[NodeSort2["CtxProvider"] = 8] = "CtxProvider";
35
+ NodeSort2[NodeSort2["TokenizerSwitcher"] = 16] = "TokenizerSwitcher";
36
+ return NodeSort2;
37
+ })(NodeSort || {});
36
38
  var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
37
39
  TerpEvt2["AllAttrGot"] = "all-attr-got";
38
40
  TerpEvt2["HandledComponentNode"] = "handled-component-node";
@@ -40,140 +42,123 @@ var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
40
42
  })(TerpEvt || {});
41
43
  const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
42
44
 
43
- class TypedStack {
45
+ class MultiTypeStack {
44
46
  constructor() {
47
+ // 记录全局栈顶
45
48
  this.top = null;
46
- // 存储每种类型最近一次出现的包装单元引用
47
- // 使用 Record 来动态支持不同的类型标签
48
- this.lastNodes = {};
49
+ // 记录每个类别的当前最新节点(各分类的“栈顶”)
50
+ this.typeTops = {};
49
51
  this.length = 0;
50
52
  }
51
53
  /**
52
- * @param rawNode 原始节点数据
53
- * @param type 节点类型
54
+ * 入栈操作
55
+ * @param value 数据
56
+ * @param bits 该节点所属的类别数组
54
57
  */
55
- push(rawNode, type) {
56
- var _a;
58
+ push(value, bits) {
57
59
  const newNode = {
58
- data: rawNode,
59
- type,
60
- prev: this.top,
61
- prevSameType: (_a = this.lastNodes[type]) != null ? _a : null
60
+ value,
61
+ types: bits,
62
+ prevGlobal: this.top,
63
+ prevByType: {}
62
64
  };
65
+ let bit;
66
+ while (1) {
67
+ bit = bits & ~bits + 1;
68
+ if (!bit) break;
69
+ bits &= ~bit;
70
+ newNode.prevByType[bit] = this.typeTops[bit] || void 0;
71
+ this.typeTops[bit] = newNode;
72
+ }
63
73
  this.top = newNode;
64
74
  this.length++;
65
- this.lastNodes[type] = newNode;
66
75
  }
67
76
  /**
68
77
  * 出栈操作
69
- * @returns 原始节点数据或 null
70
78
  */
71
79
  pop() {
72
- if (!this.top) return null;
73
- const popped = this.top;
74
- this.lastNodes[popped.type] = popped.prevSameType;
75
- this.top = popped.prev;
80
+ if (!this.top) return void 0;
81
+ const poppedNode = this.top;
82
+ let { types: bits } = poppedNode;
83
+ let bit;
84
+ while (1) {
85
+ bit = bits & ~bits + 1;
86
+ if (!bit) break;
87
+ bits &= ~bit;
88
+ this.typeTops[bit] = poppedNode.prevByType[bit];
89
+ }
90
+ this.top = poppedNode.prevGlobal;
76
91
  this.length--;
77
- return popped.data;
92
+ return [poppedNode.value, poppedNode.types];
78
93
  }
79
94
  /**
80
- * O(1) 获取栈顶节点的前一个同类型节点
95
+ * 获取某个类别的当前“顶部”元素
81
96
  */
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;
97
+ peekByType(cat) {
98
+ var _a;
99
+ return (_a = this.typeTops[cat]) == null ? void 0 : _a.value;
100
100
  }
101
- /**
102
- * 获取当前栈顶的类型
103
- */
104
- get peekType() {
105
- return this.top ? this.top.type : null;
101
+ peekType() {
102
+ var _a;
103
+ return (_a = this.top) == null ? void 0 : _a.types;
106
104
  }
107
105
  /**
108
- * 获取栈顶元素
106
+ * 获取全局栈顶
109
107
  */
110
108
  peek() {
111
- return this.top.data;
109
+ var _a;
110
+ return (_a = this.top) == null ? void 0 : _a.value;
112
111
  }
112
+ // /**
113
+ // * 1. 全局向前遍历 (不分类)
114
+ // * 从栈顶开始,沿着全局链条向栈底遍历
115
+ // */
116
+ // forEach(callback: (value: T, types: number) => any): void {
117
+ // let current = this.top;
118
+ // while (current !== null) {
119
+ // // 执行回调,如果返回 false 则立即停止
120
+ // const shouldBreak = callback(current.value, current.types);
121
+ // if (shouldBreak) break;
122
+ // current = current.prevGlobal;
123
+ // }
124
+ // }
125
+ // /**
126
+ // * 2. 按类别向前遍历
127
+ // * 仅遍历属于指定类别 cat 的节点
128
+ // */
129
+ // forEachByType(cat: number, callback: (value: T) => any): void {
130
+ // // 从该类别的当前“顶端”节点开始
131
+ // let current = this.typeTops[cat];
132
+ // while (current) {
133
+ // const shouldBreak = callback(current.value);
134
+ // if (shouldBreak) break;
135
+ // // 关键点:直接跳向该节点记录的“上一个同类节点”
136
+ // // 这比遍历全局栈再筛选类别要快得多 (O(m) vs O(n))
137
+ // current = current.prevByType[cat];
138
+ // }
139
+ // }
113
140
  }
114
141
 
115
- var __defProp$1 = Object.defineProperty;
116
- var __defProps$1 = Object.defineProperties;
117
- var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
118
- var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
119
- var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
120
- var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
121
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
122
- var __spreadValues$1 = (a, b) => {
123
- for (var prop in b || (b = {}))
124
- if (__hasOwnProp$1.call(b, prop))
125
- __defNormalProp$1(a, prop, b[prop]);
126
- if (__getOwnPropSymbols$1)
127
- for (var prop of __getOwnPropSymbols$1(b)) {
128
- if (__propIsEnum$1.call(b, prop))
129
- __defNormalProp$1(a, prop, b[prop]);
130
- }
131
- return a;
132
- };
133
- var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
134
142
  const tap = new bobeShared.BaseEvent();
135
143
  class Interpreter {
136
144
  constructor(tokenizer) {
137
145
  this.tokenizer = tokenizer;
138
- /** 模板字符串动态节点的占位符 */
139
- this.HookId = "_h_o_o_k_";
140
- /** 用于渲染的数据 */
141
- this.data = {};
142
- /** 模板字符串动态节点索引 */
143
- this.hookI = 0;
144
- this._hook = (props) => {
145
- const value = this.tokenizer.token.value;
146
- const isDynamicHook = this.tokenizer.token.type & TokenType.InsertionExp;
147
- const isStaticHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
148
- const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
149
- if (this.hook && isStaticHook) {
150
- const hookI = Number(value.slice(this.HookId.length));
151
- const res = this.hook(__spreadProps$1(__spreadValues$1({}, props), {
152
- HookId: this.HookId,
153
- i: hookI
154
- }));
155
- this.hookI++;
156
- return [hookType, res];
157
- } else if (isDynamicHook) {
158
- return [hookType, value];
159
- }
160
- return [hookType, value];
161
- };
146
+ this.rootComponent = null;
162
147
  }
163
148
  isLogicNode(node) {
164
- return node && node.__logicType & Logical;
149
+ return node && node.__logicType & LogicalBit;
165
150
  }
166
- program(root, before) {
167
- var _a;
168
- const componentNode = {
169
- __logicType: LogicType.Component,
170
- realParent: root,
171
- store: new aoye.Store()
172
- };
173
- this.tokenizer.consume();
174
- const stack = new TypedStack();
175
- stack.push({ node: root, prev: null }, NodeType.Real);
176
- const ctx = {
151
+ program(root, componentNode, before) {
152
+ var _a, _b;
153
+ this.rootComponent = componentNode;
154
+ this.tokenizer.nextToken();
155
+ const stack = new MultiTypeStack();
156
+ stack.push({ node: root, prev: null }, NodeSort.Real);
157
+ stack.push(
158
+ { node: componentNode, prev: null },
159
+ NodeSort.Component | NodeSort.CtxProvider | NodeSort.TokenizerSwitcher
160
+ );
161
+ const ctx = this.ctx = {
177
162
  realParent: root,
178
163
  prevSibling: before,
179
164
  current: null,
@@ -189,14 +174,14 @@ class Interpreter {
189
174
  }
190
175
  const token = this.tokenizer.token;
191
176
  if (token.type & TokenType.Indent) {
192
- this.tokenizer.consume();
177
+ this.tokenizer.nextToken();
193
178
  const isLogicNode = this.isLogicNode(ctx.current);
194
179
  stack.push(
195
180
  {
196
181
  node: ctx.current,
197
182
  prev: ctx.prevSibling
198
183
  },
199
- ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
184
+ !ctx.current.__logicType ? NodeSort.Real : (ctx.current.__logicType & LogicalBit ? NodeSort.Logic : 0) | (ctx.current.__logicType & TokenizerSwitcherBit ? NodeSort.TokenizerSwitcher : 0) | (ctx.current.__logicType === FakeType.Component ? NodeSort.Component : 0) | NodeSort.CtxProvider
200
185
  );
201
186
  if (ctx.current.__logicType) {
202
187
  if (isLogicNode) {
@@ -212,28 +197,31 @@ class Interpreter {
212
197
  continue;
213
198
  }
214
199
  if (ctx.current) {
215
- if (stack.length === 1 && !ctx.prevSibling) {
200
+ if (stack.length === 2 && !ctx.prevSibling) {
216
201
  ctx.prevSibling = before;
217
202
  }
218
203
  this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
219
204
  }
220
205
  if (this.tokenizer.token.type & TokenType.Dedent) {
221
- this.tokenizer.consume();
222
- const { node: parent, prev } = stack.peek();
206
+ this.tokenizer.nextToken();
207
+ const [{ node: parent, prev }, sort] = stack.pop();
223
208
  if (!parent.__logicType) {
224
- const prevSameType = stack.getPrevSameType();
209
+ const prevSameType = stack.peekByType(NodeSort.Real);
225
210
  ctx.realParent = (prevSameType == null ? void 0 : prevSameType.node) || root;
226
211
  } else {
227
- if (this.isLogicNode(parent)) {
228
- const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
212
+ if (sort & NodeSort.Logic) {
213
+ const parentLogic = (_a = stack.peekByType(NodeSort.Logic)) == null ? void 0 : _a.node;
229
214
  if (parentLogic) {
230
215
  aoye.setPulling(parentLogic.effect.ins);
231
216
  } else {
232
217
  aoye.setPulling(rootPulling);
233
218
  }
234
219
  }
220
+ if (sort & NodeSort.TokenizerSwitcher) {
221
+ const switcher = (_b = stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _b.node;
222
+ this.tokenizer = switcher.tokenizer;
223
+ }
235
224
  }
236
- stack.pop();
237
225
  ctx.prevSibling = prev;
238
226
  ctx.current = parent;
239
227
  } else {
@@ -243,10 +231,15 @@ class Interpreter {
243
231
  }
244
232
  return componentNode;
245
233
  }
234
+ switcherIsRootComponent() {
235
+ var _a;
236
+ const currentSwitcher = (_a = this.ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
237
+ return currentSwitcher === this.rootComponent;
238
+ }
246
239
  insertAfterAnchor(ctx) {
247
240
  const { realParent, prevSibling, stack, before } = ctx;
248
241
  const afterAnchor = this.createAnchor();
249
- ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
242
+ ctx.prevSibling = stack.length === 2 && !prevSibling ? before : prevSibling;
250
243
  this.handleInsert(realParent, afterAnchor, prevSibling);
251
244
  return afterAnchor;
252
245
  }
@@ -293,7 +286,7 @@ class Interpreter {
293
286
  * <declaration> ::= <tagName=token> <headerLine> <extensionLines>
294
287
  * */
295
288
  declaration(ctx) {
296
- const [hookType, value] = this._hook({});
289
+ const [hookType, value] = this.tokenizer._hook({});
297
290
  let _node;
298
291
  if (value === "if" || value === "else" || value === "fail") {
299
292
  return this.condDeclaration(ctx);
@@ -302,34 +295,42 @@ class Interpreter {
302
295
  if (typeof value === "function" && value.prototype instanceof aoye.Store) {
303
296
  _node = this.componentDeclaration(value, ctx);
304
297
  } else if (typeof value === "function") {
305
- _node = this.fragmentDeclaration(value);
298
+ _node = this.fragmentDeclaration(value, ctx);
306
299
  } else {
307
300
  throw new SyntaxError(`declaration \u4E0D\u652F\u6301 ${value} \u7C7B\u578B\u7684\u9759\u6001\u63D2\u503C`);
308
301
  }
309
302
  } else {
310
- Boolean(this.data[aoye.Keys.Raw][value]);
303
+ const data = this.getData();
304
+ Boolean(data[aoye.Keys.Raw][value]);
311
305
  new Function("data", `let v;with(data){v=(${value})};return v`);
312
306
  _node = this.createNode(value);
313
307
  }
314
308
  } else {
315
309
  _node = this.createNode(value);
316
310
  }
317
- this.tokenizer.consume();
311
+ this.tokenizer.nextToken();
318
312
  this.headerLine(_node);
319
313
  this.extensionLines(_node);
320
- if (_node.__logicType === LogicType.Component) {
314
+ if (_node.__logicType === FakeType.Component) {
321
315
  tap.once(TerpEvt.HandledComponentNode, (node) => _node = node);
322
316
  tap.emit(TerpEvt.AllAttrGot);
323
317
  }
324
318
  return _node;
325
319
  }
320
+ getData() {
321
+ const { node } = this.ctx.stack.peekByType(NodeSort.CtxProvider);
322
+ return node.data || node.owner.data;
323
+ }
326
324
  // TODO: 指定挂载位置
327
- fragmentDeclaration(renderFragment) {
325
+ fragmentDeclaration(renderFragment, ctx) {
326
+ const data = this.getData();
327
+ const tokenizer = renderFragment.call(data, this.opt, { data, root: "", anchor: "" });
328
328
  const fragmentNode = {
329
- __logicType: LogicType.Fragment,
330
- realParent: null
329
+ __logicType: FakeType.Fragment,
330
+ realParent: null,
331
+ tokenizer,
332
+ data: null
331
333
  };
332
- renderFragment.call(this.data, this.opt, { data: this.data, root: "", anchor: "" });
333
334
  return fragmentNode;
334
335
  }
335
336
  /**
@@ -340,15 +341,17 @@ class Interpreter {
340
341
  *
341
342
  * mapKey 映射, 对应子组件的属性
342
343
  * */
343
- onePropParsed(node, key, value, valueIsMapKey, hookI) {
344
- if (typeof value === "function") {
344
+ onePropParsed(data, node, key, value, valueIsMapKey, isFn, hookI) {
345
+ if (isFn) {
346
+ this.setProp(node, key, value, hookI);
347
+ } else if (typeof value === "function") {
345
348
  aoye.effect(() => {
346
349
  const res = value();
347
350
  this.setProp(node, key, res, hookI);
348
351
  });
349
352
  } else if (valueIsMapKey) {
350
353
  aoye.effect(() => {
351
- const res = this.data[value];
354
+ const res = data[value];
352
355
  this.setProp(node, key, res, hookI);
353
356
  });
354
357
  } else {
@@ -357,10 +360,18 @@ class Interpreter {
357
360
  }
358
361
  componentDeclaration(Component, ctx) {
359
362
  const child = Component.new();
363
+ const componentNode = {
364
+ __logicType: FakeType.Component,
365
+ realParent: ctx.realParent,
366
+ data: child,
367
+ tokenizer: null
368
+ };
360
369
  const prevOnePropParsed = this.onePropParsed;
361
- this.onePropParsed = (node, key, value, valueIsMapKey, hookI) => {
362
- if (valueIsMapKey) {
363
- aoye.shareSignal(this.data, value, child, key);
370
+ this.onePropParsed = (data, node, key, value, valueIsMapKey, isFn, hookI) => {
371
+ if (isFn) {
372
+ child[aoye.Keys.Raw][key] = value;
373
+ } else if (valueIsMapKey) {
374
+ aoye.shareSignal(data, value, child, key);
364
375
  } else if (typeof value === "function") {
365
376
  const meta = child[aoye.Keys.Meta];
366
377
  const cells = meta.cells;
@@ -370,37 +381,41 @@ class Interpreter {
370
381
  child[aoye.Keys.Raw][key] = value;
371
382
  }
372
383
  };
373
- const afterAnchor = this.insertAfterAnchor(ctx);
384
+ componentNode.realAfter = this.insertAfterAnchor(ctx);
374
385
  const { realParent, prevSibling } = ctx;
375
386
  tap.once(TerpEvt.AllAttrGot, () => {
376
- const parent = realParent;
377
- const prev = prevSibling;
378
387
  this.onePropParsed = prevOnePropParsed;
379
- const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
380
- componentNode.realAfter = afterAnchor;
388
+ const subTkr = child["ui"](true);
389
+ componentNode.tokenizer = subTkr;
390
+ this.tokenizer = subTkr;
381
391
  tap.emit(TerpEvt.HandledComponentNode, componentNode);
382
392
  });
383
- return { __logicType: LogicType.Component };
393
+ return componentNode;
384
394
  }
385
395
  // TODO: 优化代码逻辑,拆分 if elseif else
386
396
  condDeclaration(ctx) {
397
+ var _a;
387
398
  const { prevSibling } = ctx;
388
399
  const snapbackUp = this.tokenizer.snapshot();
389
- const keyWord = this.tokenizer.consume();
400
+ const keyWord = this.tokenizer.token;
401
+ this.tokenizer.nextToken();
390
402
  const noSelfCond = this.tokenizer.token.type === TokenType.NewLine;
391
- const [hookType, value] = this._hook({});
403
+ const [hookType, value] = this.tokenizer._hook({});
392
404
  const isElse = keyWord.value === "else";
393
405
  const isIf = keyWord.value === "if";
394
- const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondType;
406
+ const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondBit;
395
407
  const needCalcWithPrevIf = isElse && preIsCond;
408
+ const data = this.getData();
409
+ const owner = (_a = ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
396
410
  const ifNode = {
397
- __logicType: isElse ? LogicType.Else : isIf ? LogicType.If : LogicType.Fail,
411
+ __logicType: isElse ? FakeType.Else : isIf ? FakeType.If : FakeType.Fail,
398
412
  snapshot: noSelfCond ? snapbackUp : this.tokenizer.snapshot(),
399
413
  condition: null,
400
414
  realParent: null,
401
415
  preCond: preIsCond ? prevSibling : null,
402
416
  isFirstRender: true,
403
- effect: null
417
+ effect: null,
418
+ owner
404
419
  };
405
420
  let signal;
406
421
  if (noSelfCond) {
@@ -411,7 +426,7 @@ class Interpreter {
411
426
  if (point.condition.v) {
412
427
  return false;
413
428
  }
414
- if (point.__logicType === LogicType.If) {
429
+ if (point.__logicType === FakeType.If) {
415
430
  break;
416
431
  }
417
432
  point = point.preCond;
@@ -431,13 +446,13 @@ class Interpreter {
431
446
  });
432
447
  }
433
448
  } else {
434
- const valueIsMapKey = Reflect.has(this.data[aoye.Keys.Raw], value);
449
+ const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
435
450
  if (valueIsMapKey && !needCalcWithPrevIf) {
436
- aoye.runWithPulling(() => this.data[value], null);
437
- const { cells } = this.data[aoye.Keys.Meta];
451
+ aoye.runWithPulling(() => data[value], null);
452
+ const { cells } = data[aoye.Keys.Meta];
438
453
  signal = cells.get(value);
439
454
  } else {
440
- const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
455
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
441
456
  if (needCalcWithPrevIf) {
442
457
  signal = aoye.$(() => {
443
458
  let point = ifNode.preCond;
@@ -445,7 +460,7 @@ class Interpreter {
445
460
  if (point.condition.v) {
446
461
  return false;
447
462
  }
448
- if (point.__logicType === LogicType.If) {
463
+ if (point.__logicType === FakeType.If) {
449
464
  break;
450
465
  }
451
466
  point = point.preCond;
@@ -464,12 +479,13 @@ class Interpreter {
464
479
  if (val) {
465
480
  if (ifNode.isFirstRender) {
466
481
  if (!noSelfCond) {
467
- this.tokenizer.consume();
482
+ this.tokenizer.nextToken();
468
483
  }
469
- this.tokenizer.consume();
484
+ this.tokenizer.nextToken();
470
485
  } else {
486
+ this.tokenizer = ifNode.owner.tokenizer;
471
487
  this.tokenizer.resume(ifNode.snapshot);
472
- this.program(ifNode.realParent, ifNode.realBefore);
488
+ this.program(ifNode.realParent, ifNode.owner, ifNode.realBefore);
473
489
  }
474
490
  } else {
475
491
  if (ifNode.isFirstRender) {
@@ -480,7 +496,7 @@ class Interpreter {
480
496
  this.tokenizer.skip();
481
497
  } else {
482
498
  const { realBefore, realAfter, realParent } = ifNode;
483
- let point = realBefore ? this.nextSib(realBefore) : this.kid(realParent);
499
+ let point = realBefore ? this.nextSib(realBefore) : this.firstChild(realParent);
484
500
  while (point !== realAfter) {
485
501
  const next = this.nextSib(point);
486
502
  this.remove(point, realParent, realBefore);
@@ -500,15 +516,15 @@ class Interpreter {
500
516
  */
501
517
  extensionLines(_node) {
502
518
  while (1) {
503
- if (!(this.tokenizer.token.type & TokenType.Pipe)) {
519
+ if ((this.tokenizer.token.type & TokenType.Pipe) === 0) {
504
520
  return;
505
521
  }
506
- this.tokenizer.consume();
522
+ this.tokenizer.nextToken();
507
523
  this.attributeList(_node);
508
- if (!(this.tokenizer.token.type & TokenType.NewLine)) {
524
+ if ((this.tokenizer.token.type & TokenType.NewLine) === 0) {
509
525
  return;
510
526
  }
511
- this.tokenizer.consume();
527
+ this.tokenizer.nextToken();
512
528
  }
513
529
  }
514
530
  /**
@@ -518,7 +534,7 @@ class Interpreter {
518
534
  */
519
535
  headerLine(_node) {
520
536
  this.attributeList(_node);
521
- this.tokenizer.consume();
537
+ this.tokenizer.nextToken();
522
538
  }
523
539
  /**
524
540
  * 属性列表:
@@ -528,30 +544,33 @@ class Interpreter {
528
544
  *
529
545
  * <attribute> ::= <key> = <value>
530
546
  * 1. 普通节点 执行 setProps 🪝
531
- * 2. 组件节点 收集映射关系,或通过 effect 直接设值
547
+ * 2. 组件节点 收集映射关系,或 产生 computed
532
548
  */
533
549
  attributeList(_node) {
534
550
  let key, eq;
535
- while (!(this.tokenizer.token.type & TokenType.NewLine)) {
551
+ const data = this.getData();
552
+ while ((this.tokenizer.token.type & TokenType.NewLine) === 0) {
536
553
  if (key == null) {
537
554
  key = this.tokenizer.token.value;
538
555
  } else if (eq == null) {
539
556
  eq = "=";
540
557
  } else {
541
- const [hookType, value] = this._hook({});
558
+ const [hookType, value, hookI] = this.tokenizer._hook({});
559
+ const rawVal = data[aoye.Keys.Raw][value];
560
+ const isFn = typeof rawVal === "function";
542
561
  if (hookType === "dynamic") {
543
- const valueIsMapKey = Reflect.has(this.data[aoye.Keys.Raw], value);
544
- const fn = valueIsMapKey ? value : new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
545
- this.onePropParsed(_node, key, fn, valueIsMapKey, this.hookI);
562
+ const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
563
+ const fn = isFn ? rawVal : valueIsMapKey ? value : new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
564
+ this.onePropParsed(data, _node, key, fn, valueIsMapKey, isFn, hookI);
546
565
  } else if (hookType === "static") {
547
- this.onePropParsed(_node, key, value, false, this.hookI);
566
+ this.onePropParsed(data, _node, key, value, false, isFn, hookI);
548
567
  } else {
549
- this.onePropParsed(_node, key, value, false, this.hookI);
568
+ this.onePropParsed(data, _node, key, value, false, isFn, hookI);
550
569
  }
551
570
  key = null;
552
571
  eq = null;
553
572
  }
554
- this.tokenizer.consume();
573
+ this.tokenizer.nextToken();
555
574
  }
556
575
  }
557
576
  config(opt) {
@@ -568,7 +587,7 @@ class Interpreter {
568
587
  nextSib(node) {
569
588
  return node.nextSibling;
570
589
  }
571
- kid(node) {
590
+ firstChild(node) {
572
591
  return node.firstChild;
573
592
  }
574
593
  _createAnchor() {
@@ -612,28 +631,35 @@ class Interpreter {
612
631
  setProp(node, key, value, hookI) {
613
632
  node.props[key] = value;
614
633
  }
615
- init(fragments) {
616
- if (typeof fragments === "string") {
617
- this.tokenizer.setCode(fragments);
618
- } else {
619
- let code = "";
620
- for (let i = 0; i < fragments.length - 1; i++) {
621
- const fragment = fragments[i];
622
- code += fragment + `${this.HookId}${i}`;
623
- }
624
- this.tokenizer.setCode(code + fragments[fragments.length - 1]);
625
- }
626
- }
627
634
  }
628
635
 
636
+ var __defProp = Object.defineProperty;
637
+ var __defProps = Object.defineProperties;
638
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
639
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
640
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
641
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
642
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
643
+ var __spreadValues = (a, b) => {
644
+ for (var prop in b || (b = {}))
645
+ if (__hasOwnProp.call(b, prop))
646
+ __defNormalProp(a, prop, b[prop]);
647
+ if (__getOwnPropSymbols)
648
+ for (var prop of __getOwnPropSymbols(b)) {
649
+ if (__propIsEnum.call(b, prop))
650
+ __defNormalProp(a, prop, b[prop]);
651
+ }
652
+ return a;
653
+ };
654
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
629
655
  const _Tokenizer = class _Tokenizer {
630
- constructor() {
656
+ constructor(hook, isSubToken) {
657
+ this.hook = hook;
658
+ this.isSubToken = isSubToken;
631
659
  /** 缩进大小 默认 2 */
632
660
  this.TabSize = 2;
633
661
  /** 缩进字符 */
634
662
  this.Tab = Array.from({ length: this.TabSize }, () => " ").join("");
635
- /** 匹配标识符 */
636
- this.IdExp = /[\d\w\/]/;
637
663
  /** 回车后需要判断缩进 */
638
664
  this.needIndent = false;
639
665
  /** 用于跳过第一个节点前的空白字符串,以及生成基础缩进 */
@@ -642,6 +668,7 @@ const _Tokenizer = class _Tokenizer {
642
668
  this.dentStack = [0];
643
669
  /** 当前字符 index */
644
670
  this.i = 0;
671
+ // TODO: 生产环境不需要这个,导致不必要的内存占用
645
672
  this.handledTokens = [];
646
673
  /**
647
674
  * 有些标识符能产生多个 token
@@ -652,6 +679,31 @@ const _Tokenizer = class _Tokenizer {
652
679
  * parent2 <- 产生两个 dedent
653
680
  */
654
681
  this.waitingTokens = new bobeShared.Queue();
682
+ /** 模板字符串动态节点的占位符 */
683
+ this.HookId = "_h_o_o_k_";
684
+ /** 模板字符串动态节点索引 */
685
+ this.hookI = 0;
686
+ this._hook = (props) => {
687
+ const value = this.token.value;
688
+ const isDynamicHook = this.token.type & TokenType.InsertionExp;
689
+ const isStaticHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
690
+ const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
691
+ if (this.hook && isStaticHook) {
692
+ const hookI = Number(value.slice(this.HookId.length));
693
+ const res = this.hook(__spreadProps(__spreadValues({}, props), {
694
+ HookId: this.HookId,
695
+ i: hookI
696
+ }));
697
+ return [hookType, res, hookI];
698
+ } else if (isDynamicHook) {
699
+ return [hookType, value];
700
+ }
701
+ return [hookType, value];
702
+ };
703
+ if (isSubToken) {
704
+ this.setToken(TokenType.Indent, "");
705
+ this.isFirstToken = true;
706
+ }
655
707
  }
656
708
  consume() {
657
709
  const token = this.token;
@@ -678,16 +730,16 @@ const _Tokenizer = class _Tokenizer {
678
730
  let skipFragment = ``;
679
731
  this.token = void 0;
680
732
  while (1) {
681
- const char = this.char;
733
+ const char = this.code[this.i];
682
734
  if (char === "\n") {
683
735
  needIndent = true;
684
736
  skipFragment += char;
685
- this.next();
737
+ this.i++;
686
738
  continue;
687
739
  }
688
740
  if (!needIndent) {
689
741
  skipFragment += char;
690
- this.next();
742
+ this.i++;
691
743
  continue;
692
744
  }
693
745
  needIndent = false;
@@ -740,21 +792,6 @@ ${_Tokenizer.EofId}`;
740
792
  if (!this.token) return false;
741
793
  return this.token.type & TokenType.Identifier && this.token.value === _Tokenizer.EofId;
742
794
  }
743
- get char() {
744
- return this.code[this.i];
745
- }
746
- get prev() {
747
- return this.code[this.i - 1];
748
- }
749
- get after() {
750
- return this.code[this.i + 1];
751
- }
752
- next() {
753
- const prev = this.code[this.i];
754
- this.i++;
755
- const curr = this.code[this.i];
756
- return [prev, curr];
757
- }
758
795
  setToken(type, value) {
759
796
  this.token = {
760
797
  type,
@@ -763,10 +800,6 @@ ${_Tokenizer.EofId}`;
763
800
  };
764
801
  this.isFirstToken = false;
765
802
  }
766
- testId(value) {
767
- if (typeof value !== "string") return false;
768
- return this.IdExp.test(value);
769
- }
770
803
  nextToken() {
771
804
  try {
772
805
  if (this.isEof()) {
@@ -782,7 +815,7 @@ ${_Tokenizer.EofId}`;
782
815
  if (this.needIndent) {
783
816
  this.dent();
784
817
  } else {
785
- let { char } = this;
818
+ const char = this.code[this.i];
786
819
  switch (char) {
787
820
  case " ":
788
821
  case " ":
@@ -813,12 +846,12 @@ ${_Tokenizer.EofId}`;
813
846
  this.number(char);
814
847
  break;
815
848
  }
816
- if (this.testId(char)) {
849
+ if (typeof char === "string" && bobeShared.matchIdStart(char)) {
817
850
  this.identifier(char);
818
851
  }
819
852
  break;
820
853
  }
821
- this.next();
854
+ this.i++;
822
855
  }
823
856
  if (this.token) {
824
857
  break;
@@ -827,6 +860,7 @@ ${_Tokenizer.EofId}`;
827
860
  return this.token;
828
861
  } catch (error) {
829
862
  console.error(error);
863
+ return this.token;
830
864
  } finally {
831
865
  this.handledTokens.push(this.token);
832
866
  }
@@ -838,17 +872,17 @@ ${_Tokenizer.EofId}`;
838
872
  this.setToken(TokenType.Pipe, "|");
839
873
  }
840
874
  dynamic(char) {
841
- let nextC = this.after;
875
+ let nextC = this.code[this.i + 1];
842
876
  if (nextC !== "{") {
843
877
  return false;
844
878
  }
845
- this.next();
879
+ this.i++;
846
880
  let value = "${";
847
881
  let innerBrace = 0;
848
882
  while (1) {
849
- nextC = this.after;
883
+ nextC = this.code[this.i + 1];
850
884
  value += nextC;
851
- this.next();
885
+ this.i++;
852
886
  if (nextC === "{") {
853
887
  innerBrace++;
854
888
  }
@@ -865,13 +899,14 @@ ${_Tokenizer.EofId}`;
865
899
  brace() {
866
900
  let inComment, inString, count = 0, value = "", backslashCount = 0;
867
901
  while (1) {
868
- const char = this.char;
869
- const nextChar = this.after;
902
+ const char = this.code[this.i];
903
+ const nextChar = this.code[this.i + 1];
870
904
  if (inComment === "single" && char === "\n") {
871
905
  inComment = null;
872
906
  } else if (inComment === "multi" && char === "*" && nextChar === "/") {
873
907
  inComment = null;
874
- value += this.next()[0];
908
+ value += this.code[this.i];
909
+ this.i++;
875
910
  } else if (inString) {
876
911
  if (char === inString && backslashCount % 2 === 0) {
877
912
  inString = null;
@@ -880,10 +915,12 @@ ${_Tokenizer.EofId}`;
880
915
  } else {
881
916
  if (char === "/" && nextChar === "/") {
882
917
  inComment = "single";
883
- value += this.next()[0];
918
+ value += this.code[this.i];
919
+ this.i++;
884
920
  } else if (char === "/" && nextChar === "*") {
885
921
  inComment = "multi";
886
- value += this.next()[0];
922
+ value += this.code[this.i];
923
+ this.i++;
887
924
  } else if (char === "'" || char === '"' || char === "`") {
888
925
  inString = char;
889
926
  } else if (char === "{") {
@@ -896,19 +933,20 @@ ${_Tokenizer.EofId}`;
896
933
  this.setToken(TokenType.InsertionExp, value.slice(1));
897
934
  return;
898
935
  }
899
- value += this.next()[0];
936
+ value += this.code[this.i];
937
+ this.i++;
900
938
  }
901
939
  }
902
940
  newLine() {
903
941
  let value = "\n";
904
942
  let nextC;
905
943
  while (1) {
906
- nextC = this.after;
944
+ nextC = this.code[this.i + 1];
907
945
  if (nextC !== "\n") {
908
946
  break;
909
947
  }
910
948
  value += nextC;
911
- this.next();
949
+ this.i++;
912
950
  }
913
951
  if (this.isFirstToken) {
914
952
  return;
@@ -920,7 +958,7 @@ ${_Tokenizer.EofId}`;
920
958
  let nextC;
921
959
  let isEmptyLine = false;
922
960
  while (1) {
923
- const nextChar = this.char;
961
+ const nextChar = this.code[this.i];
924
962
  switch (nextChar) {
925
963
  case " ":
926
964
  nextC = this.Tab;
@@ -943,7 +981,7 @@ ${_Tokenizer.EofId}`;
943
981
  break;
944
982
  }
945
983
  value += nextC;
946
- this.next();
984
+ this.i++;
947
985
  }
948
986
  return {
949
987
  value,
@@ -966,7 +1004,7 @@ ${_Tokenizer.EofId}`;
966
1004
  const prevLen = this.dentStack[this.dentStack.length - 1];
967
1005
  if (currLen > prevLen) {
968
1006
  this.dentStack.push(currLen);
969
- this.setToken(TokenType.Indent, String(currLen));
1007
+ this.setToken(TokenType.Indent, currLen);
970
1008
  return indentHasLen;
971
1009
  }
972
1010
  if (currLen < prevLen) {
@@ -998,13 +1036,25 @@ ${_Tokenizer.EofId}`;
998
1036
  const yes = this.dentStack.length === 1;
999
1037
  if (yes) {
1000
1038
  if (!this.token) {
1001
- this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1039
+ if (this.isSubToken) {
1040
+ this.setToken(TokenType.Dedent, "");
1041
+ } else {
1042
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1043
+ }
1002
1044
  } else {
1003
- this.waitingTokens.push({
1004
- type: TokenType.Identifier,
1005
- typeName: TokenType[TokenType.Identifier],
1006
- value: _Tokenizer.EofId
1007
- });
1045
+ if (this.isSubToken) {
1046
+ this.waitingTokens.push({
1047
+ type: TokenType.Dedent,
1048
+ typeName: TokenType[TokenType.Dedent],
1049
+ value: ""
1050
+ });
1051
+ } else {
1052
+ this.waitingTokens.push({
1053
+ type: TokenType.Identifier,
1054
+ typeName: TokenType[TokenType.Identifier],
1055
+ value: _Tokenizer.EofId
1056
+ });
1057
+ }
1008
1058
  }
1009
1059
  }
1010
1060
  return yes;
@@ -1013,98 +1063,98 @@ ${_Tokenizer.EofId}`;
1013
1063
  let value = char;
1014
1064
  let nextC;
1015
1065
  while (1) {
1016
- nextC = this.after;
1017
- if (!this.testId(nextC)) {
1066
+ nextC = this.code[this.i + 1];
1067
+ if (typeof nextC !== "string" || !bobeShared.matchIdStart(nextC)) {
1018
1068
  break;
1019
1069
  }
1020
1070
  value += nextC;
1021
- this.next();
1071
+ this.i++;
1072
+ }
1073
+ if (value === _Tokenizer.EofId && this.isSubToken) {
1074
+ this.setToken(TokenType.Dedent, "");
1075
+ return;
1022
1076
  }
1023
1077
  let realValue = value === "null" ? null : value === "undefined" ? void 0 : value === "false" ? false : value === "true" ? true : value;
1024
1078
  this.setToken(TokenType.Identifier, realValue);
1025
1079
  }
1026
1080
  str(char) {
1027
- let value = '"';
1081
+ let value = "";
1028
1082
  let nextC;
1029
1083
  let continuousBackslashCount = 0;
1030
1084
  while (1) {
1031
- nextC = this.after;
1032
- value += nextC;
1085
+ nextC = this.code[this.i + 1];
1033
1086
  const memoCount = continuousBackslashCount;
1034
1087
  if (nextC === "\\") {
1035
1088
  continuousBackslashCount++;
1036
1089
  } else {
1037
1090
  continuousBackslashCount = 0;
1038
1091
  }
1039
- this.next();
1092
+ this.i++;
1040
1093
  if (nextC === char && memoCount % 2 === 0) {
1041
1094
  break;
1042
1095
  }
1096
+ value += nextC;
1043
1097
  }
1044
- this.setToken(TokenType.Identifier, JSON.parse(value.slice(0, -1) + '"'));
1098
+ this.setToken(TokenType.Identifier, value);
1045
1099
  }
1046
1100
  number(char) {
1047
1101
  let value = char;
1048
1102
  let nextC;
1049
1103
  while (1) {
1050
- nextC = this.after;
1104
+ nextC = this.code[this.i + 1];
1051
1105
  if (!bobeShared.isNum(nextC)) {
1052
1106
  break;
1053
1107
  }
1054
1108
  value += nextC;
1055
- this.next();
1109
+ this.i++;
1056
1110
  }
1057
1111
  this.setToken(TokenType.Identifier, Number(value));
1058
1112
  }
1059
1113
  eof() {
1060
1114
  this.setToken(TokenType.Eof, "End Of File");
1061
1115
  }
1116
+ init(fragments) {
1117
+ if (typeof fragments === "string") {
1118
+ this.setCode(fragments);
1119
+ } else {
1120
+ let code = "";
1121
+ for (let i = 0; i < fragments.length - 1; i++) {
1122
+ const fragment = fragments[i];
1123
+ code += fragment + `${this.HookId}${i}`;
1124
+ }
1125
+ this.setCode(code + fragments[fragments.length - 1]);
1126
+ }
1127
+ }
1062
1128
  };
1063
1129
  /** Eof 标识符的值 */
1064
1130
  _Tokenizer.EofId = `__EOF__${Date.now()}`;
1131
+ _Tokenizer.DedentId = `__DEDENT__${Date.now()}`;
1065
1132
  let Tokenizer = _Tokenizer;
1066
1133
 
1067
- var __defProp = Object.defineProperty;
1068
- var __defProps = Object.defineProperties;
1069
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
1070
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1071
- var __hasOwnProp = Object.prototype.hasOwnProperty;
1072
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
1073
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1074
- var __spreadValues = (a, b) => {
1075
- for (var prop in b || (b = {}))
1076
- if (__hasOwnProp.call(b, prop))
1077
- __defNormalProp(a, prop, b[prop]);
1078
- if (__getOwnPropSymbols)
1079
- for (var prop of __getOwnPropSymbols(b)) {
1080
- if (__propIsEnum.call(b, prop))
1081
- __defNormalProp(a, prop, b[prop]);
1082
- }
1083
- return a;
1084
- };
1085
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1086
1134
  function bobe(fragments, ...values) {
1087
- const ui = function ui2(options, valueOpt, root, before) {
1088
- const tokenizer = new Tokenizer();
1089
- const cmp = new Interpreter(tokenizer);
1090
- Object.assign(cmp, valueOpt);
1091
- cmp.config(__spreadProps(__spreadValues({}, options), {
1092
- hook({ i }) {
1093
- return values[i];
1094
- },
1095
- setProp(node, key, value, hookI) {
1096
- node.props[key] = value;
1097
- }
1098
- }));
1099
- cmp.init(Array.from(fragments));
1100
- return cmp.program(root, before);
1135
+ const ui = function ui2(isSub) {
1136
+ const tokenizer = new Tokenizer(({ i }) => {
1137
+ return values[i];
1138
+ }, isSub);
1139
+ tokenizer.init(Array.from(fragments));
1140
+ return tokenizer;
1101
1141
  };
1102
1142
  return ui;
1103
1143
  }
1104
1144
  function customRender(option) {
1105
1145
  return function render(Ctor, root) {
1106
1146
  const store = Ctor.new();
1107
- return [store["ui"](option, { data: store }, root), store];
1147
+ const tokenizer = store["ui"](false);
1148
+ const terp = new Interpreter(tokenizer);
1149
+ terp.config(option);
1150
+ const componentNode = {
1151
+ __logicType: FakeType.Component,
1152
+ realParent: root,
1153
+ data: store,
1154
+ tokenizer
1155
+ };
1156
+ terp.program(root, componentNode);
1157
+ return [componentNode, store];
1108
1158
  };
1109
1159
  }
1110
1160