bobe 0.0.14 → 0.0.16

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,119 @@ 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;
97
+ peekByType(cat) {
98
+ var _a;
99
+ return (_a = this.typeTops[cat]) == null ? void 0 : _a.value;
87
100
  }
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;
101
+ peekType() {
102
+ var _a;
103
+ return (_a = this.top) == null ? void 0 : _a.types;
100
104
  }
101
105
  /**
102
- * 获取当前栈顶的类型
106
+ * 获取全局栈顶
103
107
  */
104
- get peekType() {
105
- return this.top ? this.top.type : null;
108
+ peek() {
109
+ var _a;
110
+ return (_a = this.top) == null ? void 0 : _a.value;
106
111
  }
107
112
  /**
108
- * 获取栈顶元素
113
+ * 1. 全局向前遍历 (不分类)
114
+ * 从栈顶开始,沿着全局链条向栈底遍历
109
115
  */
110
- peek() {
111
- return this.top.data;
116
+ forEach(callback) {
117
+ let current = this.top;
118
+ while (current !== null) {
119
+ const shouldBreak = callback(current.value, current.types);
120
+ if (shouldBreak) break;
121
+ current = current.prevGlobal;
122
+ }
123
+ }
124
+ /**
125
+ * 2. 按类别向前遍历
126
+ * 仅遍历属于指定类别 cat 的节点
127
+ */
128
+ forEachByType(cat, callback) {
129
+ let current = this.typeTops[cat];
130
+ while (current) {
131
+ const shouldBreak = callback(current.value);
132
+ if (shouldBreak) break;
133
+ current = current.prevByType[cat];
134
+ }
112
135
  }
113
136
  }
114
137
 
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
138
  const tap = new bobeShared.BaseEvent();
135
139
  class Interpreter {
136
140
  constructor(tokenizer) {
137
141
  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
- };
142
+ this.rootComponent = null;
162
143
  }
163
144
  isLogicNode(node) {
164
- return node && node.__logicType & Logical;
145
+ return node && node.__logicType & LogicalBit;
165
146
  }
166
- program(root, before) {
167
- var _a;
168
- const componentNode = {
169
- __logicType: LogicType.Component,
170
- realParent: root,
171
- store: new aoye.Store()
172
- };
147
+ program(root, componentNode, before) {
148
+ var _a, _b;
149
+ this.rootComponent = componentNode;
173
150
  this.tokenizer.consume();
174
- const stack = new TypedStack();
175
- stack.push({ node: root, prev: null }, NodeType.Real);
176
- const ctx = {
151
+ const stack = new MultiTypeStack();
152
+ stack.push({ node: root, prev: null }, NodeSort.Real);
153
+ stack.push(
154
+ { node: componentNode, prev: null },
155
+ NodeSort.Component | NodeSort.CtxProvider | NodeSort.TokenizerSwitcher
156
+ );
157
+ const ctx = this.ctx = {
177
158
  realParent: root,
178
159
  prevSibling: before,
179
160
  current: null,
@@ -196,7 +177,7 @@ class Interpreter {
196
177
  node: ctx.current,
197
178
  prev: ctx.prevSibling
198
179
  },
199
- ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
180
+ !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
181
  );
201
182
  if (ctx.current.__logicType) {
202
183
  if (isLogicNode) {
@@ -212,28 +193,31 @@ class Interpreter {
212
193
  continue;
213
194
  }
214
195
  if (ctx.current) {
215
- if (stack.length === 1 && !ctx.prevSibling) {
196
+ if (stack.length === 2 && !ctx.prevSibling) {
216
197
  ctx.prevSibling = before;
217
198
  }
218
199
  this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
219
200
  }
220
201
  if (this.tokenizer.token.type & TokenType.Dedent) {
221
202
  this.tokenizer.consume();
222
- const { node: parent, prev } = stack.peek();
203
+ const [{ node: parent, prev }, sort] = stack.pop();
223
204
  if (!parent.__logicType) {
224
- const prevSameType = stack.getPrevSameType();
205
+ const prevSameType = stack.peekByType(NodeSort.Real);
225
206
  ctx.realParent = (prevSameType == null ? void 0 : prevSameType.node) || root;
226
207
  } else {
227
- if (this.isLogicNode(parent)) {
228
- const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
208
+ if (sort & NodeSort.Logic) {
209
+ const parentLogic = (_a = stack.peekByType(NodeSort.Logic)) == null ? void 0 : _a.node;
229
210
  if (parentLogic) {
230
211
  aoye.setPulling(parentLogic.effect.ins);
231
212
  } else {
232
213
  aoye.setPulling(rootPulling);
233
214
  }
234
215
  }
216
+ if (sort & NodeSort.TokenizerSwitcher) {
217
+ const switcher = (_b = stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _b.node;
218
+ this.tokenizer = switcher.tokenizer;
219
+ }
235
220
  }
236
- stack.pop();
237
221
  ctx.prevSibling = prev;
238
222
  ctx.current = parent;
239
223
  } else {
@@ -243,10 +227,15 @@ class Interpreter {
243
227
  }
244
228
  return componentNode;
245
229
  }
230
+ switcherIsRootComponent() {
231
+ var _a;
232
+ const currentSwitcher = (_a = this.ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
233
+ return currentSwitcher === this.rootComponent;
234
+ }
246
235
  insertAfterAnchor(ctx) {
247
236
  const { realParent, prevSibling, stack, before } = ctx;
248
237
  const afterAnchor = this.createAnchor();
249
- ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
238
+ ctx.prevSibling = stack.length === 2 && !prevSibling ? before : prevSibling;
250
239
  this.handleInsert(realParent, afterAnchor, prevSibling);
251
240
  return afterAnchor;
252
241
  }
@@ -293,7 +282,7 @@ class Interpreter {
293
282
  * <declaration> ::= <tagName=token> <headerLine> <extensionLines>
294
283
  * */
295
284
  declaration(ctx) {
296
- const [hookType, value] = this._hook({});
285
+ const [hookType, value] = this.tokenizer._hook({});
297
286
  let _node;
298
287
  if (value === "if" || value === "else" || value === "fail") {
299
288
  return this.condDeclaration(ctx);
@@ -302,12 +291,13 @@ class Interpreter {
302
291
  if (typeof value === "function" && value.prototype instanceof aoye.Store) {
303
292
  _node = this.componentDeclaration(value, ctx);
304
293
  } else if (typeof value === "function") {
305
- _node = this.fragmentDeclaration(value);
294
+ _node = this.fragmentDeclaration(value, ctx);
306
295
  } else {
307
296
  throw new SyntaxError(`declaration \u4E0D\u652F\u6301 ${value} \u7C7B\u578B\u7684\u9759\u6001\u63D2\u503C`);
308
297
  }
309
298
  } else {
310
- Boolean(this.data[aoye.Keys.Raw][value]);
299
+ const data = this.getData();
300
+ Boolean(data[aoye.Keys.Raw][value]);
311
301
  new Function("data", `let v;with(data){v=(${value})};return v`);
312
302
  _node = this.createNode(value);
313
303
  }
@@ -317,19 +307,26 @@ class Interpreter {
317
307
  this.tokenizer.consume();
318
308
  this.headerLine(_node);
319
309
  this.extensionLines(_node);
320
- if (_node.__logicType === LogicType.Component) {
310
+ if (_node.__logicType === FakeType.Component) {
321
311
  tap.once(TerpEvt.HandledComponentNode, (node) => _node = node);
322
312
  tap.emit(TerpEvt.AllAttrGot);
323
313
  }
324
314
  return _node;
325
315
  }
316
+ getData() {
317
+ const { node } = this.ctx.stack.peekByType(NodeSort.CtxProvider);
318
+ return node.data || node.owner.data;
319
+ }
326
320
  // TODO: 指定挂载位置
327
- fragmentDeclaration(renderFragment) {
321
+ fragmentDeclaration(renderFragment, ctx) {
322
+ const data = this.getData();
323
+ const tokenizer = renderFragment.call(data, this.opt, { data, root: "", anchor: "" });
328
324
  const fragmentNode = {
329
- __logicType: LogicType.Fragment,
330
- realParent: null
325
+ __logicType: FakeType.Fragment,
326
+ realParent: null,
327
+ tokenizer,
328
+ data: null
331
329
  };
332
- renderFragment.call(this.data, this.opt, { data: this.data, root: "", anchor: "" });
333
330
  return fragmentNode;
334
331
  }
335
332
  /**
@@ -340,15 +337,17 @@ class Interpreter {
340
337
  *
341
338
  * mapKey 映射, 对应子组件的属性
342
339
  * */
343
- onePropParsed(node, key, value, valueIsMapKey, hookI) {
344
- if (typeof value === "function") {
340
+ onePropParsed(data, node, key, value, valueIsMapKey, isFn, hookI) {
341
+ if (isFn) {
342
+ this.setProp(node, key, value, hookI);
343
+ } else if (typeof value === "function") {
345
344
  aoye.effect(() => {
346
345
  const res = value();
347
346
  this.setProp(node, key, res, hookI);
348
347
  });
349
348
  } else if (valueIsMapKey) {
350
349
  aoye.effect(() => {
351
- const res = this.data[value];
350
+ const res = data[value];
352
351
  this.setProp(node, key, res, hookI);
353
352
  });
354
353
  } else {
@@ -357,10 +356,18 @@ class Interpreter {
357
356
  }
358
357
  componentDeclaration(Component, ctx) {
359
358
  const child = Component.new();
359
+ const componentNode = {
360
+ __logicType: FakeType.Component,
361
+ realParent: ctx.realParent,
362
+ data: child,
363
+ tokenizer: null
364
+ };
360
365
  const prevOnePropParsed = this.onePropParsed;
361
- this.onePropParsed = (node, key, value, valueIsMapKey, hookI) => {
362
- if (valueIsMapKey) {
363
- aoye.shareSignal(this.data, value, child, key);
366
+ this.onePropParsed = (data, node, key, value, valueIsMapKey, isFn, hookI) => {
367
+ if (isFn) {
368
+ child[aoye.Keys.Raw][key] = value;
369
+ } else if (valueIsMapKey) {
370
+ aoye.shareSignal(data, value, child, key);
364
371
  } else if (typeof value === "function") {
365
372
  const meta = child[aoye.Keys.Meta];
366
373
  const cells = meta.cells;
@@ -370,37 +377,40 @@ class Interpreter {
370
377
  child[aoye.Keys.Raw][key] = value;
371
378
  }
372
379
  };
373
- const afterAnchor = this.insertAfterAnchor(ctx);
380
+ componentNode.realAfter = this.insertAfterAnchor(ctx);
374
381
  const { realParent, prevSibling } = ctx;
375
382
  tap.once(TerpEvt.AllAttrGot, () => {
376
- const parent = realParent;
377
- const prev = prevSibling;
378
383
  this.onePropParsed = prevOnePropParsed;
379
- const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
380
- componentNode.realAfter = afterAnchor;
384
+ const subTkr = child["ui"](true);
385
+ componentNode.tokenizer = subTkr;
386
+ this.tokenizer = subTkr;
381
387
  tap.emit(TerpEvt.HandledComponentNode, componentNode);
382
388
  });
383
- return { __logicType: LogicType.Component };
389
+ return componentNode;
384
390
  }
385
391
  // TODO: 优化代码逻辑,拆分 if elseif else
386
392
  condDeclaration(ctx) {
393
+ var _a;
387
394
  const { prevSibling } = ctx;
388
395
  const snapbackUp = this.tokenizer.snapshot();
389
396
  const keyWord = this.tokenizer.consume();
390
397
  const noSelfCond = this.tokenizer.token.type === TokenType.NewLine;
391
- const [hookType, value] = this._hook({});
398
+ const [hookType, value] = this.tokenizer._hook({});
392
399
  const isElse = keyWord.value === "else";
393
400
  const isIf = keyWord.value === "if";
394
- const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondType;
401
+ const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondBit;
395
402
  const needCalcWithPrevIf = isElse && preIsCond;
403
+ const data = this.getData();
404
+ const owner = (_a = ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
396
405
  const ifNode = {
397
- __logicType: isElse ? LogicType.Else : isIf ? LogicType.If : LogicType.Fail,
406
+ __logicType: isElse ? FakeType.Else : isIf ? FakeType.If : FakeType.Fail,
398
407
  snapshot: noSelfCond ? snapbackUp : this.tokenizer.snapshot(),
399
408
  condition: null,
400
409
  realParent: null,
401
410
  preCond: preIsCond ? prevSibling : null,
402
411
  isFirstRender: true,
403
- effect: null
412
+ effect: null,
413
+ owner
404
414
  };
405
415
  let signal;
406
416
  if (noSelfCond) {
@@ -411,7 +421,7 @@ class Interpreter {
411
421
  if (point.condition.v) {
412
422
  return false;
413
423
  }
414
- if (point.__logicType === LogicType.If) {
424
+ if (point.__logicType === FakeType.If) {
415
425
  break;
416
426
  }
417
427
  point = point.preCond;
@@ -431,13 +441,13 @@ class Interpreter {
431
441
  });
432
442
  }
433
443
  } else {
434
- const valueIsMapKey = Reflect.has(this.data[aoye.Keys.Raw], value);
444
+ const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
435
445
  if (valueIsMapKey && !needCalcWithPrevIf) {
436
- aoye.runWithPulling(() => this.data[value], null);
437
- const { cells } = this.data[aoye.Keys.Meta];
446
+ aoye.runWithPulling(() => data[value], null);
447
+ const { cells } = data[aoye.Keys.Meta];
438
448
  signal = cells.get(value);
439
449
  } else {
440
- const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
450
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
441
451
  if (needCalcWithPrevIf) {
442
452
  signal = aoye.$(() => {
443
453
  let point = ifNode.preCond;
@@ -445,7 +455,7 @@ class Interpreter {
445
455
  if (point.condition.v) {
446
456
  return false;
447
457
  }
448
- if (point.__logicType === LogicType.If) {
458
+ if (point.__logicType === FakeType.If) {
449
459
  break;
450
460
  }
451
461
  point = point.preCond;
@@ -468,8 +478,9 @@ class Interpreter {
468
478
  }
469
479
  this.tokenizer.consume();
470
480
  } else {
481
+ this.tokenizer = ifNode.owner.tokenizer;
471
482
  this.tokenizer.resume(ifNode.snapshot);
472
- this.program(ifNode.realParent, ifNode.realBefore);
483
+ this.program(ifNode.realParent, ifNode.owner, ifNode.realBefore);
473
484
  }
474
485
  } else {
475
486
  if (ifNode.isFirstRender) {
@@ -480,7 +491,7 @@ class Interpreter {
480
491
  this.tokenizer.skip();
481
492
  } else {
482
493
  const { realBefore, realAfter, realParent } = ifNode;
483
- let point = realBefore ? this.nextSib(realBefore) : this.kid(realParent);
494
+ let point = realBefore ? this.nextSib(realBefore) : this.firstChild(realParent);
484
495
  while (point !== realAfter) {
485
496
  const next = this.nextSib(point);
486
497
  this.remove(point, realParent, realBefore);
@@ -532,21 +543,24 @@ class Interpreter {
532
543
  */
533
544
  attributeList(_node) {
534
545
  let key, eq;
546
+ const data = this.getData();
535
547
  while (!(this.tokenizer.token.type & TokenType.NewLine)) {
536
548
  if (key == null) {
537
549
  key = this.tokenizer.token.value;
538
550
  } else if (eq == null) {
539
551
  eq = "=";
540
552
  } else {
541
- const [hookType, value] = this._hook({});
553
+ const [hookType, value, hookI] = this.tokenizer._hook({});
554
+ const rawVal = Reflect.get(data[aoye.Keys.Raw], value);
555
+ const isFn = typeof rawVal === "function";
542
556
  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);
557
+ const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
558
+ const fn = isFn ? rawVal : valueIsMapKey ? value : new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
559
+ this.onePropParsed(data, _node, key, fn, valueIsMapKey, isFn, hookI);
546
560
  } else if (hookType === "static") {
547
- this.onePropParsed(_node, key, value, false, this.hookI);
561
+ this.onePropParsed(data, _node, key, value, false, isFn, hookI);
548
562
  } else {
549
- this.onePropParsed(_node, key, value, false, this.hookI);
563
+ this.onePropParsed(data, _node, key, value, false, isFn, hookI);
550
564
  }
551
565
  key = null;
552
566
  eq = null;
@@ -568,7 +582,7 @@ class Interpreter {
568
582
  nextSib(node) {
569
583
  return node.nextSibling;
570
584
  }
571
- kid(node) {
585
+ firstChild(node) {
572
586
  return node.firstChild;
573
587
  }
574
588
  _createAnchor() {
@@ -612,28 +626,35 @@ class Interpreter {
612
626
  setProp(node, key, value, hookI) {
613
627
  node.props[key] = value;
614
628
  }
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
629
  }
628
630
 
631
+ var __defProp = Object.defineProperty;
632
+ var __defProps = Object.defineProperties;
633
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
634
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
635
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
636
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
637
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
638
+ var __spreadValues = (a, b) => {
639
+ for (var prop in b || (b = {}))
640
+ if (__hasOwnProp.call(b, prop))
641
+ __defNormalProp(a, prop, b[prop]);
642
+ if (__getOwnPropSymbols)
643
+ for (var prop of __getOwnPropSymbols(b)) {
644
+ if (__propIsEnum.call(b, prop))
645
+ __defNormalProp(a, prop, b[prop]);
646
+ }
647
+ return a;
648
+ };
649
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
629
650
  const _Tokenizer = class _Tokenizer {
630
- constructor() {
651
+ constructor(hook, isSubToken) {
652
+ this.hook = hook;
653
+ this.isSubToken = isSubToken;
631
654
  /** 缩进大小 默认 2 */
632
655
  this.TabSize = 2;
633
656
  /** 缩进字符 */
634
657
  this.Tab = Array.from({ length: this.TabSize }, () => " ").join("");
635
- /** 匹配标识符 */
636
- this.IdExp = /[\d\w\/]/;
637
658
  /** 回车后需要判断缩进 */
638
659
  this.needIndent = false;
639
660
  /** 用于跳过第一个节点前的空白字符串,以及生成基础缩进 */
@@ -642,6 +663,7 @@ const _Tokenizer = class _Tokenizer {
642
663
  this.dentStack = [0];
643
664
  /** 当前字符 index */
644
665
  this.i = 0;
666
+ // TODO: 生产环境不需要这个,导致不必要的内存占用
645
667
  this.handledTokens = [];
646
668
  /**
647
669
  * 有些标识符能产生多个 token
@@ -652,6 +674,31 @@ const _Tokenizer = class _Tokenizer {
652
674
  * parent2 <- 产生两个 dedent
653
675
  */
654
676
  this.waitingTokens = new bobeShared.Queue();
677
+ /** 模板字符串动态节点的占位符 */
678
+ this.HookId = "_h_o_o_k_";
679
+ /** 模板字符串动态节点索引 */
680
+ this.hookI = 0;
681
+ this._hook = (props) => {
682
+ const value = this.token.value;
683
+ const isDynamicHook = this.token.type & TokenType.InsertionExp;
684
+ const isStaticHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
685
+ const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
686
+ if (this.hook && isStaticHook) {
687
+ const hookI = Number(value.slice(this.HookId.length));
688
+ const res = this.hook(__spreadProps(__spreadValues({}, props), {
689
+ HookId: this.HookId,
690
+ i: hookI
691
+ }));
692
+ return [hookType, res, hookI];
693
+ } else if (isDynamicHook) {
694
+ return [hookType, value];
695
+ }
696
+ return [hookType, value];
697
+ };
698
+ if (isSubToken) {
699
+ this.setToken(TokenType.Indent, "");
700
+ this.isFirstToken = true;
701
+ }
655
702
  }
656
703
  consume() {
657
704
  const token = this.token;
@@ -765,7 +812,7 @@ ${_Tokenizer.EofId}`;
765
812
  }
766
813
  testId(value) {
767
814
  if (typeof value !== "string") return false;
768
- return this.IdExp.test(value);
815
+ return _Tokenizer.IdExp.test(value);
769
816
  }
770
817
  nextToken() {
771
818
  try {
@@ -998,13 +1045,25 @@ ${_Tokenizer.EofId}`;
998
1045
  const yes = this.dentStack.length === 1;
999
1046
  if (yes) {
1000
1047
  if (!this.token) {
1001
- this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1048
+ if (this.isSubToken) {
1049
+ this.setToken(TokenType.Dedent, "");
1050
+ } else {
1051
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1052
+ }
1002
1053
  } else {
1003
- this.waitingTokens.push({
1004
- type: TokenType.Identifier,
1005
- typeName: TokenType[TokenType.Identifier],
1006
- value: _Tokenizer.EofId
1007
- });
1054
+ if (this.isSubToken) {
1055
+ this.waitingTokens.push({
1056
+ type: TokenType.Dedent,
1057
+ typeName: TokenType[TokenType.Dedent],
1058
+ value: ""
1059
+ });
1060
+ } else {
1061
+ this.waitingTokens.push({
1062
+ type: TokenType.Identifier,
1063
+ typeName: TokenType[TokenType.Identifier],
1064
+ value: _Tokenizer.EofId
1065
+ });
1066
+ }
1008
1067
  }
1009
1068
  }
1010
1069
  return yes;
@@ -1020,6 +1079,10 @@ ${_Tokenizer.EofId}`;
1020
1079
  value += nextC;
1021
1080
  this.next();
1022
1081
  }
1082
+ if (value === _Tokenizer.EofId && this.isSubToken) {
1083
+ this.setToken(TokenType.Dedent, "");
1084
+ return;
1085
+ }
1023
1086
  let realValue = value === "null" ? null : value === "undefined" ? void 0 : value === "false" ? false : value === "true" ? true : value;
1024
1087
  this.setToken(TokenType.Identifier, realValue);
1025
1088
  }
@@ -1059,52 +1122,50 @@ ${_Tokenizer.EofId}`;
1059
1122
  eof() {
1060
1123
  this.setToken(TokenType.Eof, "End Of File");
1061
1124
  }
1125
+ init(fragments) {
1126
+ if (typeof fragments === "string") {
1127
+ this.setCode(fragments);
1128
+ } else {
1129
+ let code = "";
1130
+ for (let i = 0; i < fragments.length - 1; i++) {
1131
+ const fragment = fragments[i];
1132
+ code += fragment + `${this.HookId}${i}`;
1133
+ }
1134
+ this.setCode(code + fragments[fragments.length - 1]);
1135
+ }
1136
+ }
1062
1137
  };
1138
+ /** 匹配标识符 */
1139
+ _Tokenizer.IdExp = /[\d\w\/]/;
1063
1140
  /** Eof 标识符的值 */
1064
1141
  _Tokenizer.EofId = `__EOF__${Date.now()}`;
1142
+ _Tokenizer.DedentId = `__DEDENT__${Date.now()}`;
1065
1143
  let Tokenizer = _Tokenizer;
1066
1144
 
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
1145
  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);
1146
+ const ui = function ui2(isSub) {
1147
+ const tokenizer = new Tokenizer(({ i }) => {
1148
+ return values[i];
1149
+ }, isSub);
1150
+ tokenizer.init(Array.from(fragments));
1151
+ return tokenizer;
1101
1152
  };
1102
1153
  return ui;
1103
1154
  }
1104
1155
  function customRender(option) {
1105
1156
  return function render(Ctor, root) {
1106
1157
  const store = Ctor.new();
1107
- return [store["ui"](option, { data: store }, root), store];
1158
+ const tokenizer = store["ui"](false);
1159
+ const terp = new Interpreter(tokenizer);
1160
+ terp.config(option);
1161
+ const componentNode = {
1162
+ __logicType: FakeType.Component,
1163
+ realParent: root,
1164
+ data: store,
1165
+ tokenizer
1166
+ };
1167
+ terp.program(root, componentNode);
1168
+ return [componentNode, store];
1108
1169
  };
1109
1170
  }
1110
1171