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