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