bobe 0.0.23 → 0.0.25

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/index.umd.js CHANGED
@@ -73,54 +73,50 @@
73
73
  }
74
74
  }
75
75
 
76
- var TokenType = /* @__PURE__ */(TokenType2 => {
77
- TokenType2[TokenType2["NewLine"] = 1] = "NewLine";
78
- TokenType2[TokenType2["Indent"] = 2] = "Indent";
79
- TokenType2[TokenType2["Dedent"] = 4] = "Dedent";
80
- TokenType2[TokenType2["Identifier"] = 8] = "Identifier";
81
- TokenType2[TokenType2["Assign"] = 16] = "Assign";
82
- TokenType2[TokenType2["Pipe"] = 32] = "Pipe";
83
- TokenType2[TokenType2["Eof"] = 64] = "Eof";
84
- TokenType2[TokenType2["InsertionExp"] = 128] = "InsertionExp";
85
- TokenType2[TokenType2["Semicolon"] = 256] = "Semicolon";
86
- return TokenType2;
87
- })(TokenType || {});
88
- var FakeType = /* @__PURE__ */(FakeType2 => {
89
- FakeType2[FakeType2["If"] = 1] = "If";
90
- FakeType2[FakeType2["Fail"] = 2] = "Fail";
91
- FakeType2[FakeType2["Else"] = 4] = "Else";
92
- FakeType2[FakeType2["For"] = 8] = "For";
93
- FakeType2[FakeType2["Component"] = 16] = "Component";
94
- FakeType2[FakeType2["Fragment"] = 32] = "Fragment";
95
- FakeType2[FakeType2["ForItem"] = 64] = "ForItem";
96
- return FakeType2;
97
- })(FakeType || {});
98
- const CondBit = 1 /* If */ | 2 /* Fail */ | 4 /* Else */;
99
- const LogicalBit = 1 /* If */ | 2 /* Fail */ | 4 /* Else */ | 8 /* For */ | 64 /* ForItem */;
100
- const TokenizerSwitcherBit = 16 /* Component */ | 32 /* Fragment */;
101
- var NodeSort = /* @__PURE__ */(NodeSort2 => {
102
- NodeSort2[NodeSort2["Logic"] = 1] = "Logic";
103
- NodeSort2[NodeSort2["Real"] = 2] = "Real";
104
- NodeSort2[NodeSort2["Component"] = 4] = "Component";
105
- NodeSort2[NodeSort2["CtxProvider"] = 8] = "CtxProvider";
106
- NodeSort2[NodeSort2["TokenizerSwitcher"] = 16] = "TokenizerSwitcher";
107
- return NodeSort2;
108
- })(NodeSort || {});
76
+ let TokenType = function (TokenType) {
77
+ TokenType[TokenType["NewLine"] = 1] = "NewLine";
78
+ TokenType[TokenType["Indent"] = 2] = "Indent";
79
+ TokenType[TokenType["Dedent"] = 4] = "Dedent";
80
+ TokenType[TokenType["Identifier"] = 8] = "Identifier";
81
+ TokenType[TokenType["Assign"] = 16] = "Assign";
82
+ TokenType[TokenType["Pipe"] = 32] = "Pipe";
83
+ TokenType[TokenType["Eof"] = 64] = "Eof";
84
+ TokenType[TokenType["InsertionExp"] = 128] = "InsertionExp";
85
+ TokenType[TokenType["Semicolon"] = 256] = "Semicolon";
86
+ return TokenType;
87
+ }({});
88
+ let FakeType = function (FakeType) {
89
+ FakeType[FakeType["If"] = 1] = "If";
90
+ FakeType[FakeType["Fail"] = 2] = "Fail";
91
+ FakeType[FakeType["Else"] = 4] = "Else";
92
+ FakeType[FakeType["For"] = 8] = "For";
93
+ FakeType[FakeType["Component"] = 16] = "Component";
94
+ FakeType[FakeType["Fragment"] = 32] = "Fragment";
95
+ FakeType[FakeType["ForItem"] = 64] = "ForItem";
96
+ return FakeType;
97
+ }({});
98
+ const CondBit = FakeType.If | FakeType.Fail | FakeType.Else;
99
+ const LogicalBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem;
100
+ FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem | FakeType.Component | FakeType.Fragment;
101
+ const TokenizerSwitcherBit = FakeType.Component | FakeType.Fragment;
102
+ let NodeSort = function (NodeSort) {
103
+ NodeSort[NodeSort["Logic"] = 1] = "Logic";
104
+ NodeSort[NodeSort["Real"] = 2] = "Real";
105
+ NodeSort[NodeSort["Component"] = 4] = "Component";
106
+ NodeSort[NodeSort["CtxProvider"] = 8] = "CtxProvider";
107
+ NodeSort[NodeSort["TokenizerSwitcher"] = 16] = "TokenizerSwitcher";
108
+ return NodeSort;
109
+ }({});
110
+ (function (TerpEvt) {
111
+ TerpEvt["AllAttrGot"] = "all-attr-got";
112
+ TerpEvt["HandledComponentNode"] = "handled-component-node";
113
+ return TerpEvt;
114
+ })({});
109
115
 
110
116
  class MultiTypeStack {
111
- constructor() {
112
- // 记录全局栈顶
113
- // private top: StackNode<T> | null = null;
114
- // 记录每个类别的当前最新节点(各分类的“栈顶”)
115
- this.typeTops = {};
116
- this.length = 0;
117
- this.stack = [];
118
- }
119
- /**
120
- * 入栈操作
121
- * @param value 数据
122
- * @param bits 该节点所属的类别数组
123
- */
117
+ typeTops = {};
118
+ length = 0;
119
+ stack = [];
124
120
  push(value, bits) {
125
121
  const newNode = {
126
122
  value,
@@ -132,18 +128,15 @@
132
128
  bit = bits & ~bits + 1;
133
129
  if (!bit) break;
134
130
  bits &= ~bit;
135
- newNode.prevByType[bit] = this.typeTops[bit] || void 0;
131
+ newNode.prevByType[bit] = this.typeTops[bit] || undefined;
136
132
  this.typeTops[bit] = newNode;
137
133
  }
138
134
  this.stack[this.length++] = newNode;
139
135
  }
140
- /**
141
- * 出栈操作
142
- */
143
136
  pop() {
144
137
  const poppedNode = this.stack[this.length - 1];
145
138
  this.stack[--this.length] = null;
146
- if (!poppedNode) return void 0;
139
+ if (!poppedNode) return undefined;
147
140
  let bits = poppedNode.types;
148
141
  let bit;
149
142
  while (1) {
@@ -154,63 +147,26 @@
154
147
  }
155
148
  return [poppedNode.value, poppedNode.types];
156
149
  }
157
- /**
158
- * 获取某个类别的当前“顶部”元素
159
- */
160
150
  peekByType(cat) {
161
151
  return this.typeTops[cat]?.value;
162
152
  }
163
153
  peekType() {
164
154
  return this.stack.at(-1).types;
165
155
  }
166
- /**
167
- * 获取全局栈顶
168
- */
169
156
  peek() {
170
157
  return this.stack.at(-1).value;
171
158
  }
172
- // /**
173
- // * 1. 全局向前遍历 (不分类)
174
- // * 从栈顶开始,沿着全局链条向栈底遍历
175
- // */
176
- // forEach(callback: (value: T, types: number) => any): void {
177
- // let current = this.top;
178
- // while (current !== null) {
179
- // // 执行回调,如果返回 false 则立即停止
180
- // const shouldBreak = callback(current.value, current.types);
181
- // if (shouldBreak) break;
182
- // current = current.prevGlobal;
183
- // }
184
- // }
185
- // /**
186
- // * 2. 按类别向前遍历
187
- // * 仅遍历属于指定类别 cat 的节点
188
- // */
189
- // forEachByType(cat: number, callback: (value: T) => any): void {
190
- // // 从该类别的当前“顶端”节点开始
191
- // let current = this.typeTops[cat];
192
- // while (current) {
193
- // const shouldBreak = callback(current.value);
194
- // if (shouldBreak) break;
195
- // // 关键点:直接跳向该节点记录的“上一个同类节点”
196
- // // 这比遍历全局栈再筛选类别要快得多 (O(m) vs O(n))
197
- // current = current.prevByType[cat];
198
- // }
199
- // }
200
159
  }
201
160
 
202
161
  const _excluded = ["dentStack", "isFirstToken"];
203
- new bobeShared.BaseEvent();
204
162
  class Interpreter {
205
163
  constructor(tokenizer) {
206
164
  this.tokenizer = tokenizer;
207
- this.rootComponent = null;
208
- this.forItemId = 0;
209
- this.oneRealPropParsed = this.onePropParsed.bind(this);
210
165
  }
211
166
  isLogicNode(node) {
212
167
  return node && node.__logicType & LogicalBit;
213
168
  }
169
+ rootComponent = null;
214
170
  program(root, componentNode, before, ctxProvider) {
215
171
  this.rootComponent = componentNode;
216
172
  this.tokenizer.nextToken();
@@ -253,7 +209,7 @@
253
209
  }, !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);
254
210
  if (ctx.current.__logicType) {
255
211
  if (isLogicNode) {
256
- aoye.setPulling(ctx.current.effect.ins);
212
+ aoye.setPulling(ctx.current.effect);
257
213
  }
258
214
  } else {
259
215
  if (ctx.current) {
@@ -285,7 +241,7 @@
285
241
  if (sort & NodeSort.Logic) {
286
242
  const parentLogic = stack.peekByType(NodeSort.Logic)?.node;
287
243
  if (parentLogic) {
288
- aoye.setPulling(parentLogic.effect.ins);
244
+ aoye.setPulling(parentLogic.effect);
289
245
  } else {
290
246
  aoye.setPulling(rootPulling);
291
247
  }
@@ -295,7 +251,8 @@
295
251
  this.tokenizer = switcher.tokenizer;
296
252
  }
297
253
  if (parent.__logicType === FakeType.ForItem) {
298
- const forNode = parent.forNode;
254
+ const _ref = parent,
255
+ forNode = _ref.forNode;
299
256
  const i = forNode.i,
300
257
  arr = forNode.arr,
301
258
  snapshot = forNode.snapshot;
@@ -321,7 +278,7 @@
321
278
  }
322
279
  return componentNode;
323
280
  }
324
- insertAfterAnchor(name = "anchor") {
281
+ insertAfterAnchor(name = 'anchor') {
325
282
  const _this$ctx = this.ctx,
326
283
  realParent = _this$ctx.realParent,
327
284
  prevSibling = _this$ctx.prevSibling,
@@ -332,12 +289,6 @@
332
289
  this.handleInsert(realParent, afterAnchor, prevSibling);
333
290
  return afterAnchor;
334
291
  }
335
- /** 处理
336
- * 是逻辑 是普通
337
- * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
338
- * 子节点 仅插入到父逻辑节点 将本节点插入父节点
339
- * 理论上父节点不能是一个 逻辑节点,遇到if 时 Terp 会重新执行 program 这种情况下,会指定 root 为真实 dom
340
- */
341
292
  handleInsert(parent, child, prev, parentComponent) {
342
293
  if (!child.__logicType) {
343
294
  if (!prev || !prev.__logicType) {
@@ -356,7 +307,6 @@
356
307
  }
357
308
  }
358
309
  }
359
- /** 考虑到同级 逻辑模块 */
360
310
  getPrevRealSibling(prevSibling) {
361
311
  if (!prevSibling || !prevSibling.__logicType) {
362
312
  return prevSibling;
@@ -369,38 +319,33 @@
369
319
  point = point.anchor;
370
320
  }
371
321
  }
372
- /**
373
- * 声明部分:
374
- * 包含首行定义和(可选的)多行属性扩展
375
- * <declaration> ::= <tagName=token> <headerLine> <extensionLines>
376
- * */
377
322
  declaration(ctx) {
378
323
  const _this$tokenizer$_hook = this.tokenizer._hook({}),
379
324
  _this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
380
325
  hookType = _this$tokenizer$_hook2[0],
381
326
  value = _this$tokenizer$_hook2[1];
382
327
  let _node;
383
- if (value === "if" || value === "else" || value === "fail") {
328
+ if (value === 'if' || value === 'else' || value === 'fail') {
384
329
  return this.condDeclaration(ctx);
385
- } else if (value === "for") {
330
+ } else if (value === 'for') {
386
331
  return this.forDeclaration();
387
332
  } else if (hookType) {
388
333
  const data = this.getData();
389
- if (hookType === "static") {
390
- if (typeof value === "function") {
334
+ if (hookType === 'static') {
335
+ if (typeof value === 'function') {
391
336
  _node = this.componentOrFragmentDeclaration(value, ctx);
392
337
  } else {
393
- throw new SyntaxError(`declaration \u4E0D\u652F\u6301 ${value} \u7C7B\u578B\u7684\u9759\u6001\u63D2\u503C`);
338
+ throw new SyntaxError(`declaration 不支持 ${value} 类型的静态插值`);
394
339
  }
395
340
  } else {
396
341
  const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
397
342
  const val = data[aoye.Keys.Raw][value];
398
- if (typeof val === "function") {
343
+ if (typeof val === 'function') {
399
344
  _node = this.componentOrFragmentDeclaration(val, ctx);
400
345
  } else {
401
346
  const str = valueIsMapKey ? value : this.getFn(data, value);
402
- _node = this.createNode("text");
403
- this.onePropParsed(data, _node, "text", str, valueIsMapKey, false);
347
+ _node = this.createNode('text');
348
+ this.onePropParsed(data, _node, 'text', str, valueIsMapKey, false);
404
349
  }
405
350
  }
406
351
  } else {
@@ -422,12 +367,12 @@
422
367
  const isDestruct = itemToken.type === TokenType.InsertionExp;
423
368
  let itemExp = itemToken.value;
424
369
  if (isDestruct) {
425
- itemExp = "{" + itemExp + "}";
426
- const vars = itemExp.match(bobeShared.jsVarRegexp).join(",");
427
- itemExp = new Function("item", `let ${vars}; (${itemExp}=item); return {${vars}};`);
370
+ itemExp = '{' + itemExp + '}';
371
+ const vars = itemExp.match(bobeShared.jsVarRegexp).join(',');
372
+ itemExp = new Function('item', `let ${vars}; (${itemExp}=item); return {${vars}};`);
428
373
  }
429
374
  let indexName, keyExp;
430
- while (this.tokenizer.code[this.tokenizer.i] !== "\n") {
375
+ while (this.tokenizer.code[this.tokenizer.i] !== '\n') {
431
376
  const next = this.tokenizer.nextToken();
432
377
  if (next.type !== TokenType.Semicolon) {
433
378
  if (!indexName) {
@@ -441,7 +386,7 @@
441
386
  const prevSibling = this.ctx.prevSibling;
442
387
  const forNode = {
443
388
  __logicType: FakeType.For,
444
- snapshot: this.tokenizer.snapshot(["dentStack", "isFirstToken"]),
389
+ snapshot: this.tokenizer.snapshot(['dentStack', 'isFirstToken']),
445
390
  realParent: this.ctx.realParent,
446
391
  prevSibling,
447
392
  realBefore: prevSibling?.realAfter || prevSibling,
@@ -456,25 +401,21 @@
456
401
  i: 0
457
402
  };
458
403
  if (keyExp) {
459
- forNode.getKey = new Function("data", `let v;with(data){v=${keyExp}};return v;`);
404
+ forNode.getKey = new Function('data', `let v;with(data){v=${keyExp}};return v;`);
460
405
  }
461
- window["for1"] = forNode;
406
+ window['for1'] = forNode;
462
407
  const data = this.getData();
463
408
  const cells = data[aoye.Keys.Meta].cells;
464
409
  const hasArrExpKey = Reflect.has(data[aoye.Keys.Raw], arrExp);
465
- const arrSignal = hasArrExpKey ? (
466
- // key 直接拿
467
- data[arrExp], cells.get(arrExp)) :
468
- // 无key
469
- aoye.$(this.getFn(data, arrExp));
470
- forNode.realAfter = this.insertAfterAnchor("for-after");
410
+ const arrSignal = hasArrExpKey ? (data[arrExp], cells.get(arrExp)) : new aoye.Computed(this.getFn(data, arrExp));
411
+ forNode.realAfter = this.insertAfterAnchor('for-after');
471
412
  const _forNode$snapshot = forNode.snapshot;
472
413
  _forNode$snapshot.dentStack;
473
414
  _forNode$snapshot.isFirstToken;
474
415
  const snapshotForUpdate = _objectWithoutProperties(_forNode$snapshot, _excluded);
475
416
  let isFirstRender = true;
476
- forNode.effect = aoye.effect(() => {
477
- let arr = forNode.arr = arrSignal.v;
417
+ forNode.effect = new aoye.Effect(() => {
418
+ let arr = forNode.arr = arrSignal.get();
478
419
  arr[aoye.Keys.Iterator];
479
420
  arr = aoye.toRaw(arr);
480
421
  const children = forNode.children;
@@ -483,7 +424,7 @@
483
424
  for (let i = len; i--;) {
484
425
  const nextItem = children[i + 1];
485
426
  const item = this.createForItem(forNode, i, data);
486
- const anchor = this.insertAfterAnchor("for-item-after");
427
+ const anchor = this.insertAfterAnchor('for-item-after');
487
428
  item.realAfter = anchor;
488
429
  if (nextItem) {
489
430
  nextItem.realBefore = anchor;
@@ -510,7 +451,7 @@
510
451
  const child = children[i];
511
452
  this.removeLogicNode(child);
512
453
  this.remove(child.realAfter);
513
- child.effect();
454
+ child.effect.dispose();
514
455
  }
515
456
  }
516
457
  if (oldLen < newLen) {
@@ -519,7 +460,7 @@
519
460
  const item = this.createForItem(forNode, i, data);
520
461
  newChildren[i] = item;
521
462
  const nextItem = newChildren[i + 1];
522
- const anchor = this.createAnchor("for-item-after");
463
+ const anchor = this.createAnchor('for-item-after');
523
464
  this.insertAfter(forNode.realParent, anchor, lastAfter);
524
465
  item.realAfter = anchor;
525
466
  if (nextItem) {
@@ -531,7 +472,7 @@
531
472
  this.tokenizer.useDedentAsEof = false;
532
473
  aoye.runWithPulling(() => {
533
474
  this.program(forNode.realParent, forNode.owner, lastAfter, item);
534
- }, item.effect.ins);
475
+ }, item.effect);
535
476
  }
536
477
  const firstInsert = newChildren[oldLen];
537
478
  if (firstInsert) {
@@ -541,7 +482,7 @@
541
482
  for (let i = minLen; i--;) {
542
483
  const child = children[i];
543
484
  newChildren[i] = child;
544
- if (typeof itemExp === "string") {
485
+ if (typeof itemExp === 'string') {
545
486
  child.data[itemExp] = arr[i];
546
487
  } else {
547
488
  Object.assign(child.data, itemExp(arr[i]));
@@ -554,27 +495,32 @@
554
495
  });
555
496
  return forNode.children[0] || forNode;
556
497
  }
498
+ forItemId = 0;
557
499
  createForItem(forNode, i, parentData) {
558
500
  let forItemNode;
559
- const effect2 = aoye.scope(() => {}, null);
501
+ const scope = new aoye.Scope(() => {});
502
+ scope.scope = null;
503
+ aoye.runWithPulling(() => {
504
+ scope.get();
505
+ }, null);
560
506
  const arr = forNode.arr,
561
507
  itemExp = forNode.itemExp,
562
508
  indexName = forNode.indexName,
563
509
  getKey = forNode.getKey;
564
510
  let data;
565
- if (typeof itemExp === "string") {
566
- data = aoye.$(indexName ? {
511
+ if (typeof itemExp === 'string') {
512
+ data = aoye.deepSignal(indexName ? {
567
513
  [itemExp]: arr[i],
568
514
  [indexName]: i
569
515
  } : {
570
516
  [itemExp]: arr[i]
571
- });
517
+ }, aoye.getPulling());
572
518
  } else {
573
519
  const rawData = itemExp(arr[i]);
574
520
  if (indexName) {
575
521
  rawData[indexName] = i;
576
522
  }
577
- data = aoye.$(rawData);
523
+ data = aoye.deepSignal(rawData, aoye.getPulling());
578
524
  }
579
525
  Object.setPrototypeOf(data, parentData);
580
526
  forItemNode = {
@@ -588,7 +534,7 @@
588
534
  effect: null,
589
535
  data
590
536
  };
591
- forItemNode.effect = effect2;
537
+ forItemNode.effect = scope;
592
538
  return forItemNode;
593
539
  }
594
540
  getData() {
@@ -596,24 +542,16 @@
596
542
  node = _this$ctx$stack$peekB.node;
597
543
  return node.data || node.owner.data;
598
544
  }
599
- /**
600
- * key 元素,组件的 key
601
- * value
602
- * 1. 静态类型值
603
- * 2. 插值计算 函数,可以考虑 使用 effect 或 computed 做处理
604
- *
605
- * mapKey 映射, 对应子组件的属性
606
- * */
607
545
  onePropParsed(data, node, key, value, valueIsMapKey, isFn, hookI) {
608
546
  if (isFn) {
609
547
  this.setProp(node, key, value, hookI);
610
- } else if (typeof value === "function") {
611
- aoye.effect(() => {
548
+ } else if (typeof value === 'function') {
549
+ new aoye.Effect(() => {
612
550
  const res = value();
613
551
  this.setProp(node, key, res, hookI);
614
552
  });
615
553
  } else if (valueIsMapKey) {
616
- aoye.effect(() => {
554
+ new aoye.Effect(() => {
617
555
  const res = data[value];
618
556
  this.setProp(node, key, res, hookI);
619
557
  });
@@ -621,6 +559,7 @@
621
559
  this.setProp(node, key, value, hookI);
622
560
  }
623
561
  }
562
+ oneRealPropParsed = this.onePropParsed.bind(this);
624
563
  componentOrFragmentDeclaration(ComponentOrRender, ctx) {
625
564
  let Component, render, child;
626
565
  const isCC = ComponentOrRender.prototype instanceof aoye.Store;
@@ -639,7 +578,7 @@
639
578
  realBefore: null,
640
579
  realAfter: null,
641
580
  data: child,
642
- tokenizer: render ? render(true) : child["ui"](true)
581
+ tokenizer: render ? render(true) : child['ui'](true)
643
582
  };
644
583
  this.onePropParsed = (data, _, key, value, valueIsMapKey, isFn, hookI) => {
645
584
  if (isFn) {
@@ -649,32 +588,31 @@
649
588
  } else {
650
589
  const meta = child[aoye.Keys.Meta];
651
590
  const cells = meta.cells;
652
- if (typeof value === "function") {
653
- const computed = aoye.$(value);
591
+ if (typeof value === 'function') {
592
+ const computed = new aoye.Computed(value);
654
593
  cells.set(key, computed);
655
- child[aoye.Keys.Raw][key] = void 0;
594
+ child[aoye.Keys.Raw][key] = undefined;
656
595
  } else {
657
596
  cells.set(key, {
658
- v: value
597
+ get: () => value
659
598
  });
660
599
  child[aoye.Keys.Raw][key] = value;
661
600
  }
662
601
  }
663
602
  };
664
- node.realAfter = this.insertAfterAnchor("component-after");
603
+ node.realAfter = this.insertAfterAnchor('component-after');
665
604
  return node;
666
605
  }
667
606
  getFn(data, expression) {
668
- return new Function("data", `let v;with(data){v=${expression}};return v;`).bind(void 0, data);
607
+ return new Function('data', `let v;with(data){v=${expression}};return v;`).bind(undefined, data);
669
608
  }
670
- // TODO: 优化代码逻辑,拆分 if elseif else
671
609
  condDeclaration(ctx) {
672
610
  const prevSibling = ctx.prevSibling;
673
611
  const keyWord = this.tokenizer.token;
674
612
  const expToken = this.tokenizer.condExp();
675
613
  const value = expToken.value;
676
- const isElse = keyWord.value === "else";
677
- const isIf = keyWord.value === "if";
614
+ const isElse = keyWord.value === 'else';
615
+ const isIf = keyWord.value === 'if';
678
616
  const preIsCond = prevSibling?.__logicType & CondBit;
679
617
  const data = this.getData();
680
618
  const noCond = value === true;
@@ -682,7 +620,6 @@
682
620
  const owner = ctx.stack.peekByType(NodeSort.TokenizerSwitcher)?.node;
683
621
  const ifNode = {
684
622
  __logicType: isElse ? FakeType.Else : isIf ? FakeType.If : FakeType.Fail,
685
- // 此时 token 是 exp, 下次解析 从 \n 开始
686
623
  snapshot: this.tokenizer.snapshot(),
687
624
  realParent: null,
688
625
  realBefore: null,
@@ -695,22 +632,22 @@
695
632
  };
696
633
  let signal;
697
634
  switch (keyWord.value) {
698
- case "if":
635
+ case 'if':
699
636
  if (valueIsMapKey) {
700
637
  aoye.runWithPulling(() => data[value], null);
701
638
  const cells = data[aoye.Keys.Meta].cells;
702
639
  signal = cells.get(value);
703
640
  } else {
704
641
  const fn = this.getFn(data, value);
705
- signal = aoye.$(fn);
642
+ signal = new aoye.Computed(fn);
706
643
  }
707
644
  break;
708
- case "else":
645
+ case 'else':
709
646
  if (noCond) {
710
- signal = aoye.$(() => {
647
+ signal = new aoye.Computed(() => {
711
648
  let point = ifNode.preCond;
712
649
  while (point) {
713
- if (point.condition.v) {
650
+ if (point.condition.get()) {
714
651
  return false;
715
652
  }
716
653
  if (point.__logicType === FakeType.If) {
@@ -722,10 +659,10 @@
722
659
  });
723
660
  } else {
724
661
  const fn = valueIsMapKey ? null : this.getFn(data, value);
725
- signal = aoye.$(() => {
662
+ signal = new aoye.Computed(() => {
726
663
  let point = ifNode.preCond;
727
664
  while (point) {
728
- if (point.condition.v) {
665
+ if (point.condition.get()) {
729
666
  return false;
730
667
  }
731
668
  if (point.__logicType === FakeType.If) {
@@ -737,11 +674,11 @@
737
674
  });
738
675
  }
739
676
  break;
740
- case "fail":
741
- signal = aoye.$(() => {
677
+ case 'fail':
678
+ signal = new aoye.Computed(() => {
742
679
  let point = ifNode.preCond;
743
680
  while (point) {
744
- if (point.condition.v) {
681
+ if (point.condition.get()) {
745
682
  return false;
746
683
  }
747
684
  point = point.preCond;
@@ -752,7 +689,7 @@
752
689
  }
753
690
  ifNode.condition = signal;
754
691
  ifNode.realAfter = this.insertAfterAnchor(`${keyWord.value}-after`);
755
- ifNode.effect = aoye.effect(({
692
+ const ef = aoye.effect(({
756
693
  val
757
694
  }) => {
758
695
  if (val) {
@@ -774,6 +711,7 @@
774
711
  }
775
712
  ifNode.isFirstRender = false;
776
713
  }, [signal]);
714
+ ifNode.effect = ef.ins;
777
715
  return ifNode;
778
716
  }
779
717
  removeLogicNode(node) {
@@ -787,10 +725,6 @@
787
725
  point = next;
788
726
  }
789
727
  }
790
- /**
791
- * <extensionLines> ::= PIPE <attributeList> NEWLINE <extensionLines>
792
- * | ε
793
- */
794
728
  extensionLines(_node) {
795
729
  while (1) {
796
730
  if ((this.tokenizer.token.type & TokenType.Pipe) === 0) {
@@ -804,25 +738,10 @@
804
738
  this.tokenizer.nextToken();
805
739
  }
806
740
  }
807
- /**
808
- * 首行:
809
- * 节点名称 + 属性列表 + 换行
810
- * <headerLine> ::= <attributeList> NEWLINE
811
- */
812
741
  headerLine(_node) {
813
742
  this.attributeList(_node);
814
743
  this.tokenizer.nextToken();
815
744
  }
816
- /**
817
- * 属性列表:
818
- * 可以是空的,或者包含多个属性
819
- * <attributeList> ::= <attribute> <attributeList>
820
- * | ε
821
- *
822
- * <attribute> ::= <key> = <value>
823
- * 1. 普通节点 执行 setProps 🪝
824
- * 2. 组件节点 收集映射关系,或 产生 computed
825
- */
826
745
  attributeList(_node) {
827
746
  let key, eq;
828
747
  const data = this.getData();
@@ -830,7 +749,7 @@
830
749
  if (key == null) {
831
750
  key = this.tokenizer.token.value;
832
751
  } else if (eq == null) {
833
- eq = "=";
752
+ eq = '=';
834
753
  } else {
835
754
  const _this$tokenizer$_hook3 = this.tokenizer._hook({}),
836
755
  _this$tokenizer$_hook4 = _slicedToArray(_this$tokenizer$_hook3, 3),
@@ -838,12 +757,12 @@
838
757
  value = _this$tokenizer$_hook4[1],
839
758
  hookI = _this$tokenizer$_hook4[2];
840
759
  const rawVal = data[aoye.Keys.Raw][value];
841
- const isFn = typeof rawVal === "function";
842
- if (hookType === "dynamic") {
760
+ const isFn = typeof rawVal === 'function';
761
+ if (hookType === 'dynamic') {
843
762
  const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
844
763
  const fn = isFn ? rawVal : valueIsMapKey ? value : this.getFn(data, value);
845
764
  this.onePropParsed(data, _node, key, fn, valueIsMapKey, isFn, hookI);
846
- } else if (hookType === "static") {
765
+ } else if (hookType === 'static') {
847
766
  this.onePropParsed(data, _node, key, value, false, isFn, hookI);
848
767
  } else {
849
768
  this.onePropParsed(data, _node, key, value, false, isFn, hookI);
@@ -894,7 +813,6 @@
894
813
  remove(node, parent, prev) {
895
814
  return this.defaultRemove(node, parent, prev);
896
815
  }
897
- // TODO: 默认改成 prevItem
898
816
  defaultRemove(node, parent, prevSibling) {
899
817
  const next = node.nextSibling;
900
818
  if (prevSibling) {
@@ -910,76 +828,33 @@
910
828
  }
911
829
 
912
830
  class Tokenizer {
831
+ TabSize = 2;
832
+ Tab = Array.from({
833
+ length: this.TabSize
834
+ }, () => ' ').join('');
835
+ static EofId = `__EOF__${Date.now()}`;
836
+ static DedentId = `__DEDENT__${Date.now()}`;
837
+ needIndent = false;
838
+ isFirstToken = true;
839
+ dentStack = [0];
840
+ i = 0;
841
+ handledTokens = [];
842
+ waitingTokens = new bobeShared.Queue();
913
843
  constructor(hook, useDedentAsEof) {
914
844
  this.hook = hook;
915
845
  this.useDedentAsEof = useDedentAsEof;
916
- /** 缩进大小 默认 2 */
917
- this.TabSize = 2;
918
- /** 缩进字符 */
919
- this.Tab = Array.from({
920
- length: this.TabSize
921
- }, () => " ").join("");
922
- /** 回车后需要判断缩进 */
923
- this.needIndent = false;
924
- /** 用于跳过第一个节点前的空白字符串,以及生成基础缩进 */
925
- this.isFirstToken = true;
926
- /** 记录历史缩进的长度,相对于行首 */
927
- this.dentStack = [0];
928
- /** 当前字符 index */
929
- this.i = 0;
930
- // TODO: 生产环境不需要这个,导致不必要的内存占用
931
- this.handledTokens = [];
932
- /**
933
- * 有些标识符能产生多个 token
934
- * 例如 dedent
935
- * parent1
936
- * child
937
- * subChild
938
- * parent2 <- 产生两个 dedent
939
- */
940
- this.waitingTokens = new bobeShared.Queue();
941
- /** 模板字符串动态节点的占位符 */
942
- this.HookId = "_h_o_o_k_";
943
- /** 模板字符串动态节点索引 */
944
- this.hookI = 0;
945
- this._hook = props => {
946
- const value = this.token.value;
947
- const isDynamicHook = this.token.type & TokenType.InsertionExp;
948
- const isStaticHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
949
- const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
950
- if (this.hook && isStaticHook) {
951
- const hookI = Number(value.slice(this.HookId.length));
952
- const res = this.hook({
953
- ...props,
954
- HookId: this.HookId,
955
- i: hookI
956
- });
957
- return [hookType, res, hookI];
958
- } else if (isDynamicHook) {
959
- return [hookType, value];
960
- }
961
- return [hookType, value];
962
- };
963
846
  if (useDedentAsEof) {
964
- this.setToken(TokenType.Indent, "");
847
+ this.setToken(TokenType.Indent, '');
965
848
  this.isFirstToken = true;
966
849
  }
967
850
  }
968
- static {
969
- /** Eof 标识符的值 */
970
- this.EofId = `__EOF__${Date.now()}`;
971
- }
972
- static {
973
- this.DedentId = `__DEDENT__${Date.now()}`;
974
- }
975
851
  consume() {
976
852
  const token = this.token;
977
853
  this.nextToken();
978
854
  return token;
979
855
  }
980
- // /** 恢复至某一个现场,进行 token 重算 */
981
856
  resume(_snapshot) {
982
- this.token = void 0;
857
+ this.token = undefined;
983
858
  this.needIndent = false;
984
859
  this.isFirstToken = true;
985
860
  this.dentStack = [0];
@@ -993,7 +868,7 @@
993
868
  if (keys) {
994
869
  for (const k of keys) {
995
870
  snap[k] = this[k];
996
- if (k === "dentStack") {
871
+ if (k === 'dentStack') {
997
872
  snap[k] = this[k].slice();
998
873
  }
999
874
  }
@@ -1004,10 +879,10 @@
1004
879
  const logicDentLen = this.dentStack[this.dentStack.length - 1];
1005
880
  let needIndent = false;
1006
881
  let skipFragment = ``;
1007
- this.token = void 0;
882
+ this.token = undefined;
1008
883
  while (1) {
1009
884
  const char = this.code[this.i];
1010
- if (char === "\n") {
885
+ if (char === '\n') {
1011
886
  needIndent = true;
1012
887
  skipFragment += char;
1013
888
  this.i++;
@@ -1031,7 +906,7 @@
1031
906
  const expLen = this.dentStack[i];
1032
907
  if (currLen === expLen) break;
1033
908
  if (currLen > expLen) {
1034
- throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
909
+ throw SyntaxError(`缩进错误,缩进长度不匹配`);
1035
910
  }
1036
911
  if (this.shorterThanBaseDentEof()) {
1037
912
  break;
@@ -1056,13 +931,12 @@
1056
931
  return skipFragment;
1057
932
  }
1058
933
  setCode(code) {
1059
- this.code = "\n" + code.trimEnd() + `
1060
- ${Tokenizer.EofId}`;
934
+ this.code = '\n' + code.trimEnd() + `\n${Tokenizer.EofId}`;
1061
935
  }
1062
936
  tokenize() {
1063
937
  do {
1064
938
  this.nextToken();
1065
- console.log("token:", TokenType[this.token?.type], JSON.stringify(this.token?.value || ""));
939
+ console.log('token:', TokenType[this.token?.type], JSON.stringify(this.token?.value || ''));
1066
940
  } while (!this.isEof());
1067
941
  }
1068
942
  isEof() {
@@ -1082,7 +956,7 @@ ${Tokenizer.EofId}`;
1082
956
  if (this.isEof()) {
1083
957
  return this.token;
1084
958
  }
1085
- this.token = void 0;
959
+ this.token = undefined;
1086
960
  if (this.waitingTokens.len) {
1087
961
  const item = this.waitingTokens.shift();
1088
962
  this.setToken(item.type, item.value);
@@ -1094,40 +968,39 @@ ${Tokenizer.EofId}`;
1094
968
  } else {
1095
969
  const char = this.code[this.i];
1096
970
  switch (char) {
1097
- case " ":
1098
- case " ":
971
+ case '\t':
972
+ case ' ':
1099
973
  break;
1100
- // 找后续所有 newLine
1101
- case "\n":
974
+ case '\n':
1102
975
  this.newLine();
1103
976
  this.needIndent = true;
1104
977
  break;
1105
- case "=":
978
+ case '=':
1106
979
  this.assignment();
1107
980
  break;
1108
- case "|":
981
+ case '|':
1109
982
  this.pipe();
1110
983
  break;
1111
984
  case "'":
1112
985
  case '"':
1113
986
  this.str(char);
1114
987
  break;
1115
- case "{":
988
+ case '{':
1116
989
  const braceToken = this.brace();
1117
990
  this.setToken(TokenType.InsertionExp, braceToken);
1118
991
  break;
1119
- case "$":
992
+ case '$':
1120
993
  const handled = this.dynamic(char);
1121
994
  if (handled) break;
1122
- case ";":
1123
- this.setToken(TokenType.Semicolon, ";");
995
+ case ';':
996
+ this.setToken(TokenType.Semicolon, ';');
1124
997
  break;
1125
998
  default:
1126
999
  if (bobeShared.isNum(char)) {
1127
1000
  this.number(char);
1128
1001
  break;
1129
1002
  }
1130
- if (typeof char === "string" && bobeShared.matchIdStart2(char, 0)) {
1003
+ if (typeof char === 'string' && bobeShared.matchIdStart2(char, 0)) {
1131
1004
  this.identifier(char);
1132
1005
  }
1133
1006
  break;
@@ -1147,11 +1020,11 @@ ${Tokenizer.EofId}`;
1147
1020
  }
1148
1021
  }
1149
1022
  condExp() {
1150
- let value = "";
1023
+ let value = '';
1151
1024
  this.token = null;
1152
1025
  while (1) {
1153
1026
  const char = this.code[this.i];
1154
- if (char === "\n") {
1027
+ if (char === '\n') {
1155
1028
  break;
1156
1029
  }
1157
1030
  value += char;
@@ -1161,21 +1034,14 @@ ${Tokenizer.EofId}`;
1161
1034
  this.setToken(TokenType.Identifier, value || true);
1162
1035
  return this.token;
1163
1036
  }
1164
- /**
1165
- * 解析到 for 时使用这个方法获取 for 后方的子表达式
1166
- * 表达式通过 “;” 分割
1167
- * // 最多可有三个表达式
1168
- * for arr ; item index; item.key
1169
- * @returns {boolean} 是否含有 key
1170
- */
1171
1037
  forLoopSubExp() {
1172
1038
  this.token = null;
1173
- let value = "";
1039
+ let value = '';
1174
1040
  let count = 0;
1175
1041
  while (1) {
1176
1042
  const char = this.code[this.i];
1177
- const isSemicolon = char === ";";
1178
- if (isSemicolon || char === "\n") {
1043
+ const isSemicolon = char === ';';
1044
+ if (isSemicolon || char === '\n') {
1179
1045
  value = value.trim();
1180
1046
  if (!this.token) {
1181
1047
  this.setToken(TokenType.Identifier, value);
@@ -1186,10 +1052,10 @@ ${Tokenizer.EofId}`;
1186
1052
  value
1187
1053
  });
1188
1054
  }
1189
- value = "";
1055
+ value = '';
1190
1056
  count++;
1191
1057
  if (count > 3) {
1192
- throw SyntaxError(`for \u5FAA\u73AF\u6700\u591A\u53EF\u5305\u542B\u4E09\u4E2A\u8868\u8FBE\u5F0F, \u5206\u522B\u4E3A arr ; item index [; key]`);
1058
+ throw SyntaxError(`for 循环最多可包含三个表达式, 分别为 arr ; item index [; key]`);
1193
1059
  }
1194
1060
  if (!isSemicolon) return count === 3;
1195
1061
  } else {
@@ -1199,27 +1065,27 @@ ${Tokenizer.EofId}`;
1199
1065
  }
1200
1066
  }
1201
1067
  assignment() {
1202
- this.setToken(TokenType.Assign, "=");
1068
+ this.setToken(TokenType.Assign, '=');
1203
1069
  }
1204
1070
  pipe() {
1205
- this.setToken(TokenType.Pipe, "|");
1071
+ this.setToken(TokenType.Pipe, '|');
1206
1072
  }
1207
1073
  dynamic(char) {
1208
1074
  let nextC = this.code[this.i + 1];
1209
- if (nextC !== "{") {
1075
+ if (nextC !== '{') {
1210
1076
  return false;
1211
1077
  }
1212
1078
  this.i++;
1213
- let value = "${";
1079
+ let value = '${';
1214
1080
  let innerBrace = 0;
1215
1081
  while (1) {
1216
1082
  nextC = this.code[this.i + 1];
1217
1083
  value += nextC;
1218
1084
  this.i++;
1219
- if (nextC === "{") {
1085
+ if (nextC === '{') {
1220
1086
  innerBrace++;
1221
1087
  }
1222
- if (nextC === "}") {
1088
+ if (nextC === '}') {
1223
1089
  if (!innerBrace) {
1224
1090
  break;
1225
1091
  }
@@ -1233,14 +1099,14 @@ ${Tokenizer.EofId}`;
1233
1099
  let inComment,
1234
1100
  inString,
1235
1101
  count = 0,
1236
- value = "",
1102
+ value = '',
1237
1103
  backslashCount = 0;
1238
1104
  while (1) {
1239
1105
  const char = this.code[this.i];
1240
1106
  const nextChar = this.code[this.i + 1];
1241
- if (inComment === "single" && char === "\n") {
1107
+ if (inComment === 'single' && char === '\n') {
1242
1108
  inComment = null;
1243
- } else if (inComment === "multi" && char === "*" && nextChar === "/") {
1109
+ } else if (inComment === 'multi' && char === '*' && nextChar === '/') {
1244
1110
  inComment = null;
1245
1111
  value += this.code[this.i];
1246
1112
  this.i++;
@@ -1248,21 +1114,21 @@ ${Tokenizer.EofId}`;
1248
1114
  if (char === inString && backslashCount % 2 === 0) {
1249
1115
  inString = null;
1250
1116
  }
1251
- backslashCount = char === "\\" ? backslashCount + 1 : 0;
1117
+ backslashCount = char === '\\' ? backslashCount + 1 : 0;
1252
1118
  } else {
1253
- if (char === "/" && nextChar === "/") {
1254
- inComment = "single";
1119
+ if (char === '/' && nextChar === '/') {
1120
+ inComment = 'single';
1255
1121
  value += this.code[this.i];
1256
1122
  this.i++;
1257
- } else if (char === "/" && nextChar === "*") {
1258
- inComment = "multi";
1123
+ } else if (char === '/' && nextChar === '*') {
1124
+ inComment = 'multi';
1259
1125
  value += this.code[this.i];
1260
1126
  this.i++;
1261
- } else if (char === "'" || char === '"' || char === "`") {
1127
+ } else if (char === "'" || char === '"' || char === '`') {
1262
1128
  inString = char;
1263
- } else if (char === "{") {
1129
+ } else if (char === '{') {
1264
1130
  count++;
1265
- } else if (char === "}") {
1131
+ } else if (char === '}') {
1266
1132
  count--;
1267
1133
  }
1268
1134
  }
@@ -1274,11 +1140,11 @@ ${Tokenizer.EofId}`;
1274
1140
  }
1275
1141
  }
1276
1142
  newLine() {
1277
- let value = "\n";
1143
+ let value = '\n';
1278
1144
  let nextC;
1279
1145
  while (1) {
1280
1146
  nextC = this.code[this.i + 1];
1281
- if (nextC !== "\n") {
1147
+ if (nextC !== '\n') {
1282
1148
  break;
1283
1149
  }
1284
1150
  value += nextC;
@@ -1290,26 +1156,26 @@ ${Tokenizer.EofId}`;
1290
1156
  this.setToken(TokenType.NewLine, value);
1291
1157
  }
1292
1158
  getDentValue() {
1293
- let value = "";
1159
+ let value = '';
1294
1160
  let nextC;
1295
1161
  let isEmptyLine = false;
1296
1162
  while (1) {
1297
1163
  const nextChar = this.code[this.i];
1298
1164
  switch (nextChar) {
1299
- case " ":
1165
+ case '\t':
1300
1166
  nextC = this.Tab;
1301
1167
  break;
1302
- case " ":
1303
- nextC = " ";
1168
+ case ' ':
1169
+ nextC = ' ';
1304
1170
  break;
1305
- case "\n":
1306
- nextC = "\n";
1171
+ case '\n':
1172
+ nextC = '\n';
1307
1173
  break;
1308
1174
  default:
1309
- nextC = "";
1175
+ nextC = '';
1310
1176
  break;
1311
1177
  }
1312
- if (nextC === "\n") {
1178
+ if (nextC === '\n') {
1313
1179
  isEmptyLine = true;
1314
1180
  break;
1315
1181
  }
@@ -1350,7 +1216,7 @@ ${Tokenizer.EofId}`;
1350
1216
  const expLen = this.dentStack[i];
1351
1217
  if (currLen === expLen) break;
1352
1218
  if (currLen > expLen) {
1353
- throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
1219
+ throw SyntaxError('缩进大小不统一');
1354
1220
  }
1355
1221
  if (this.shorterThanBaseDentEof()) {
1356
1222
  return;
@@ -1375,7 +1241,7 @@ ${Tokenizer.EofId}`;
1375
1241
  if (yes) {
1376
1242
  if (!this.token) {
1377
1243
  if (this.useDedentAsEof) {
1378
- this.setToken(TokenType.Dedent, "");
1244
+ this.setToken(TokenType.Dedent, '');
1379
1245
  } else {
1380
1246
  this.setToken(TokenType.Identifier, Tokenizer.EofId);
1381
1247
  }
@@ -1384,7 +1250,7 @@ ${Tokenizer.EofId}`;
1384
1250
  this.waitingTokens.push({
1385
1251
  type: TokenType.Dedent,
1386
1252
  typeName: TokenType[TokenType.Dedent],
1387
- value: ""
1253
+ value: ''
1388
1254
  });
1389
1255
  } else {
1390
1256
  this.waitingTokens.push({
@@ -1402,27 +1268,27 @@ ${Tokenizer.EofId}`;
1402
1268
  let nextC;
1403
1269
  while (1) {
1404
1270
  nextC = this.code[this.i + 1];
1405
- if (typeof nextC !== "string" || !bobeShared.matchIdStart2(nextC, 0)) {
1271
+ if (typeof nextC !== 'string' || !bobeShared.matchIdStart2(nextC, 0)) {
1406
1272
  break;
1407
1273
  }
1408
1274
  value += nextC;
1409
1275
  this.i++;
1410
1276
  }
1411
1277
  if (value === Tokenizer.EofId && this.useDedentAsEof) {
1412
- this.setToken(TokenType.Dedent, "");
1278
+ this.setToken(TokenType.Dedent, '');
1413
1279
  return;
1414
1280
  }
1415
- let realValue = value === "null" ? null : value === "undefined" ? void 0 : value === "false" ? false : value === "true" ? true : value;
1281
+ let realValue = value === 'null' ? null : value === 'undefined' ? undefined : value === 'false' ? false : value === 'true' ? true : value;
1416
1282
  this.setToken(TokenType.Identifier, realValue);
1417
1283
  }
1418
1284
  str(char) {
1419
- let value = "";
1285
+ let value = '';
1420
1286
  let nextC;
1421
1287
  let continuousBackslashCount = 0;
1422
1288
  while (1) {
1423
1289
  nextC = this.code[this.i + 1];
1424
1290
  const memoCount = continuousBackslashCount;
1425
- if (nextC === "\\") {
1291
+ if (nextC === '\\') {
1426
1292
  continuousBackslashCount++;
1427
1293
  } else {
1428
1294
  continuousBackslashCount = 0;
@@ -1449,13 +1315,33 @@ ${Tokenizer.EofId}`;
1449
1315
  this.setToken(TokenType.Identifier, Number(value));
1450
1316
  }
1451
1317
  eof() {
1452
- this.setToken(TokenType.Eof, "End Of File");
1453
- }
1318
+ this.setToken(TokenType.Eof, 'End Of File');
1319
+ }
1320
+ HookId = '_h_o_o_k_';
1321
+ hookI = 0;
1322
+ _hook = props => {
1323
+ const value = this.token.value;
1324
+ const isDynamicHook = this.token.type & TokenType.InsertionExp;
1325
+ const isStaticHook = typeof value === 'string' && value.indexOf(this.HookId) === 0;
1326
+ const hookType = isDynamicHook ? 'dynamic' : isStaticHook ? 'static' : undefined;
1327
+ if (this.hook && isStaticHook) {
1328
+ const hookI = Number(value.slice(this.HookId.length));
1329
+ const res = this.hook({
1330
+ ...props,
1331
+ HookId: this.HookId,
1332
+ i: hookI
1333
+ });
1334
+ return [hookType, res, hookI];
1335
+ } else if (isDynamicHook) {
1336
+ return [hookType, value];
1337
+ }
1338
+ return [hookType, value];
1339
+ };
1454
1340
  init(fragments) {
1455
- if (typeof fragments === "string") {
1341
+ if (typeof fragments === 'string') {
1456
1342
  this.setCode(fragments);
1457
1343
  } else {
1458
- let code = "";
1344
+ let code = '';
1459
1345
  for (let i = 0; i < fragments.length - 1; i++) {
1460
1346
  const fragment = fragments[i];
1461
1347
  code += fragment + `${this.HookId}${i}`;
@@ -1466,7 +1352,7 @@ ${Tokenizer.EofId}`;
1466
1352
  }
1467
1353
 
1468
1354
  function bobe(fragments, ...values) {
1469
- const ui = function ui2(isSub) {
1355
+ const ui = function ui(isSub) {
1470
1356
  const tokenizer = new Tokenizer(({
1471
1357
  i
1472
1358
  }) => {
@@ -1481,7 +1367,7 @@ ${Tokenizer.EofId}`;
1481
1367
  function customRender(option) {
1482
1368
  return function render(Ctor, root) {
1483
1369
  const store = Ctor.new();
1484
- const tokenizer = store["ui"](false);
1370
+ const tokenizer = store['ui'](false);
1485
1371
  const terp = new Interpreter(tokenizer);
1486
1372
  terp.config(option);
1487
1373
  const componentNode = {