bobe 0.0.10 → 0.0.12

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,5 +1,6 @@
1
- import { Store, Keys, effect, shareSignal, $ } from 'aoye';
2
- import { BaseEvent } from 'bobe-shared';
1
+ import { Store, getPulling, setPulling, Keys, effect, shareSignal, $, runWithPulling } from 'aoye';
2
+ export * from 'aoye';
3
+ import { BaseEvent, Queue, isNum } from 'bobe-shared';
3
4
 
4
5
  var TokenType = /* @__PURE__ */ ((TokenType2) => {
5
6
  TokenType2[TokenType2["NewLine"] = 1] = "NewLine";
@@ -20,35 +21,116 @@ var LogicType = /* @__PURE__ */ ((LogicType2) => {
20
21
  LogicType2[LogicType2["Component"] = 16] = "Component";
21
22
  LogicType2[LogicType2["Fragment"] = 32] = "Fragment";
22
23
  LogicType2[LogicType2["Root"] = 64] = "Root";
24
+ LogicType2[LogicType2["Real"] = 128] = "Real";
23
25
  return LogicType2;
24
26
  })(LogicType || {});
27
+ const Logical = 1 /* If */ | 2 /* ElseIf */ | 4 /* Else */ | 8 /* For */;
28
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
29
+ NodeType2[NodeType2["Logic"] = Logical] = "Logic";
30
+ NodeType2[NodeType2["Real"] = 128 /* Real */] = "Real";
31
+ NodeType2[NodeType2["Component"] = 16 /* Component */] = "Component";
32
+ return NodeType2;
33
+ })(NodeType || {});
25
34
  var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
26
35
  TerpEvt2["AllAttrGot"] = "all-attr-got";
27
36
  TerpEvt2["HandledComponentNode"] = "handled-component-node";
28
37
  return TerpEvt2;
29
38
  })(TerpEvt || {});
39
+ const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
30
40
 
31
- var __defProp = Object.defineProperty;
32
- var __defProps = Object.defineProperties;
33
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
34
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
35
- var __hasOwnProp = Object.prototype.hasOwnProperty;
36
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
37
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
38
- var __spreadValues = (a, b) => {
41
+ class TypedStack {
42
+ constructor() {
43
+ this.top = null;
44
+ // 存储每种类型最近一次出现的包装单元引用
45
+ // 使用 Record 来动态支持不同的类型标签
46
+ this.lastNodes = {};
47
+ this.length = 0;
48
+ }
49
+ /**
50
+ * @param rawNode 原始节点数据
51
+ * @param type 节点类型
52
+ */
53
+ push(rawNode, type) {
54
+ var _a;
55
+ const newNode = {
56
+ data: rawNode,
57
+ type,
58
+ prev: this.top,
59
+ prevSameType: (_a = this.lastNodes[type]) != null ? _a : null
60
+ };
61
+ this.top = newNode;
62
+ this.length++;
63
+ this.lastNodes[type] = newNode;
64
+ }
65
+ /**
66
+ * 出栈操作
67
+ * @returns 原始节点数据或 null
68
+ */
69
+ pop() {
70
+ if (!this.top) return null;
71
+ const popped = this.top;
72
+ this.lastNodes[popped.type] = popped.prevSameType;
73
+ this.top = popped.prev;
74
+ this.length--;
75
+ return popped.data;
76
+ }
77
+ /**
78
+ * O(1) 获取栈顶节点的前一个同类型节点
79
+ */
80
+ getPrevSameType() {
81
+ if (!this.top || !this.top.prevSameType) {
82
+ return null;
83
+ }
84
+ return this.top.prevSameType.data;
85
+ }
86
+ findPrevSameType(cb) {
87
+ if (!this.top) {
88
+ return null;
89
+ }
90
+ let point = this.top.prevSameType;
91
+ while (point) {
92
+ if (cb(point.data)) {
93
+ return point.data;
94
+ }
95
+ point = point.prevSameType;
96
+ }
97
+ return null;
98
+ }
99
+ /**
100
+ * 获取当前栈顶的类型
101
+ */
102
+ get peekType() {
103
+ return this.top ? this.top.type : null;
104
+ }
105
+ /**
106
+ * 获取栈顶元素
107
+ */
108
+ peek() {
109
+ return this.top.data;
110
+ }
111
+ }
112
+
113
+ var __defProp$1 = Object.defineProperty;
114
+ var __defProps$1 = Object.defineProperties;
115
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
116
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
117
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
118
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
119
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
120
+ var __spreadValues$1 = (a, b) => {
39
121
  for (var prop in b || (b = {}))
40
- if (__hasOwnProp.call(b, prop))
41
- __defNormalProp(a, prop, b[prop]);
42
- if (__getOwnPropSymbols)
43
- for (var prop of __getOwnPropSymbols(b)) {
44
- if (__propIsEnum.call(b, prop))
45
- __defNormalProp(a, prop, b[prop]);
122
+ if (__hasOwnProp$1.call(b, prop))
123
+ __defNormalProp$1(a, prop, b[prop]);
124
+ if (__getOwnPropSymbols$1)
125
+ for (var prop of __getOwnPropSymbols$1(b)) {
126
+ if (__propIsEnum$1.call(b, prop))
127
+ __defNormalProp$1(a, prop, b[prop]);
46
128
  }
47
129
  return a;
48
130
  };
49
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
131
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
50
132
  const tap = new BaseEvent();
51
- class Terp {
133
+ class Interpreter {
52
134
  constructor(tokenizer) {
53
135
  this.tokenizer = tokenizer;
54
136
  /** 模板字符串动态节点的占位符 */
@@ -57,7 +139,6 @@ class Terp {
57
139
  this.data = {};
58
140
  /** 模板字符串动态节点索引 */
59
141
  this.hookI = 0;
60
- this.stack = [];
61
142
  this._hook = (props) => {
62
143
  const value = this.tokenizer.token.value;
63
144
  const isDynamicHook = this.tokenizer.token.type & TokenType.InsertionExp;
@@ -65,7 +146,7 @@ class Terp {
65
146
  const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
66
147
  if (this.hook && isStaticHook) {
67
148
  const hookI = Number(value.slice(this.HookId.length));
68
- const res = this.hook(__spreadProps(__spreadValues({}, props), {
149
+ const res = this.hook(__spreadProps$1(__spreadValues$1({}, props), {
69
150
  HookId: this.HookId,
70
151
  i: hookI
71
152
  }));
@@ -77,123 +158,115 @@ class Terp {
77
158
  return [hookType, value];
78
159
  };
79
160
  }
80
- // /** program 要挂载的父节点位置 */
81
- // root: any;
82
- // /** program 挂载的前置节点 */
83
- // anchor: any;
84
- program() {
85
- const root = {
161
+ isLogicNode(node) {
162
+ return node && node.__logicType & Logical;
163
+ }
164
+ program(root, before) {
165
+ var _a;
166
+ const componentNode = {
86
167
  __logicType: LogicType.Component,
87
- store: this.data,
88
- realList: [],
89
- directList: []
168
+ realParent: root,
169
+ store: new Store()
90
170
  };
91
171
  this.tokenizer.consume();
92
- let current;
93
- let prevSibling;
94
- this.stack = [{ node: root, prevSibling }];
172
+ const stack = new TypedStack();
173
+ stack.push({ node: root, prev: null }, NodeType.Real);
174
+ const ctx = {
175
+ realParent: root,
176
+ prevSibling: before,
177
+ current: null,
178
+ stack,
179
+ before
180
+ };
181
+ const rootPulling = getPulling();
95
182
  while (1) {
96
183
  if (this.tokenizer.isEof()) {
97
- this.handleInsert(root, current, root.realList[root.realList.length - 1]);
184
+ if (!ctx.prevSibling) ctx.prevSibling = before;
185
+ this.handleInsert(root, ctx.current, ctx.prevSibling, componentNode);
98
186
  break;
99
187
  }
100
188
  const token = this.tokenizer.token;
101
189
  if (token.type & TokenType.Indent) {
102
190
  this.tokenizer.consume();
103
- this.stack.push({
104
- prevSibling,
105
- node: current
106
- });
107
- prevSibling = null;
108
- current = this.declaration();
191
+ const isLogicNode = this.isLogicNode(ctx.current);
192
+ stack.push(
193
+ {
194
+ node: ctx.current,
195
+ prev: ctx.prevSibling
196
+ },
197
+ ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
198
+ );
199
+ if (ctx.current.__logicType) {
200
+ if (isLogicNode) {
201
+ setPulling(ctx.current.effect.ins);
202
+ }
203
+ } else {
204
+ ctx.realParent = ctx.current;
205
+ ctx.prevSibling = null;
206
+ }
207
+ ctx.current = this.declaration(ctx);
109
208
  continue;
110
209
  }
111
- if (current) {
112
- if (this.stack.length > 1) {
113
- const parent = this.stack[this.stack.length - 1].node;
114
- this.handleInsert(parent, current, prevSibling);
115
- } else {
116
- this.handleInsert(root, current, prevSibling);
210
+ if (ctx.current) {
211
+ if (stack.length === 1 && !ctx.prevSibling) {
212
+ ctx.prevSibling = before;
117
213
  }
214
+ this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
118
215
  }
119
216
  if (this.tokenizer.token.type & TokenType.Dedent) {
120
217
  this.tokenizer.consume();
121
- const { node: parent, prevSibling: prevParent } = this.stack.pop();
122
- prevSibling = prevParent;
123
- current = parent;
218
+ const { node: parent, prev } = stack.peek();
219
+ if (!parent.__logicType) {
220
+ const prevSameType = stack.getPrevSameType();
221
+ ctx.realParent = prevSameType == null ? void 0 : prevSameType.node;
222
+ } else {
223
+ if (this.isLogicNode(parent)) {
224
+ const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
225
+ if (parentLogic) {
226
+ setPulling(parentLogic.effect.ins);
227
+ } else {
228
+ setPulling(rootPulling);
229
+ }
230
+ }
231
+ }
232
+ stack.pop();
233
+ ctx.prevSibling = prev;
234
+ ctx.current = parent;
124
235
  } else {
125
- prevSibling = current;
126
- current = this.declaration();
236
+ ctx.prevSibling = ctx.current || ctx.prevSibling;
237
+ ctx.current = this.declaration(ctx);
127
238
  }
128
239
  }
129
- return root;
240
+ return componentNode;
241
+ }
242
+ insertAfterAnchor(ctx) {
243
+ const { realParent, prevSibling, stack, before } = ctx;
244
+ const afterAnchor = this.createAnchor();
245
+ ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
246
+ this.handleInsert(realParent, afterAnchor, prevSibling);
247
+ return afterAnchor;
130
248
  }
131
249
  /** 处理
132
- * 是逻辑 是普通
133
- * 父节点 将子节点们插入到 realList 调用 insert 方法挨个插入子节点
134
- * 子节点 将其下 realList 插入到父节点 将本节点插入父节点
250
+ * 是逻辑 是普通
251
+ * 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
252
+ * 子节点 仅插入到父逻辑节点 将本节点插入父节点
253
+ * 理论上父节点不能是一个 逻辑节点,遇到if 时 Terp 会重新执行 program 这种情况下,会指定 root 为真实 dom
135
254
  */
136
- handleInsert(parent, child, prevSibling) {
137
- let insertFn = this.insert.bind(this);
138
- if (parent.__logicType) {
139
- insertFn = (parent2, child2, prevSibling2) => {
140
- parent2.realList.splice(parent2.realList.indexOf(prevSibling2) + 1, 0, child2);
141
- };
142
- }
143
- if (child.__logicType) {
144
- const realList = child.realList;
145
- for (let i = realList.length; i--; ) {
146
- const item = realList[i];
147
- insertFn(parent, item, prevSibling);
255
+ handleInsert(parent, child, prev, parentComponent) {
256
+ if (!child.__logicType) {
257
+ if (!prev || !prev.__logicType) {
258
+ this.insertAfter(parent, child, prev);
259
+ } else {
260
+ const before = prev.realAfter;
261
+ this.insertAfter(parent, child, before);
148
262
  }
149
263
  } else {
150
- insertFn(parent, child, prevSibling);
151
- }
152
- }
153
- /**
154
- * @deprecated
155
- * 节点列表:
156
- * 可以是一个节点,也可以跟随更多节点
157
- * <nodeList> ::= <node> <nodeList> <EOF|Dedent>
158
- * |
159
- */
160
- nodeList(parent) {
161
- let _node;
162
- let prevSibling;
163
- let prevItem;
164
- while (1) {
165
- if (this.tokenizer.isEof()) {
166
- return;
167
- }
168
- if (this.tokenizer.token.type & TokenType.Dedent) {
169
- this.tokenizer.consume();
170
- return;
171
- }
172
- _node = this.node();
173
- const insert = parent.__logicType ? this.defaultInsert : this.insert.bind(this);
174
- parent.__logicType ? this.defaultRemove : this.remove.bind(this);
175
- if (!_node.__logicType) {
176
- const realPrev = this.getPrevRealSibling(prevSibling);
177
- const currItem = insert(parent, _node, realPrev, prevItem);
178
- prevItem = currItem;
179
- prevSibling = _node;
180
- continue;
181
- }
182
- if (prevSibling) {
183
- _node.anchor = prevSibling;
184
- } else if (parent.__logicType) {
185
- _node.anchor = parent;
186
- } else ;
187
- if (_node.child && _node.condition()) {
188
- let item = _node.child;
189
- while (item != null) {
190
- const { value: child } = item;
191
- const realPrev = this.getPrevRealSibling(prevSibling);
192
- const currItem = insert(parent, child, realPrev, prevItem);
193
- item = item.next;
194
- prevItem = currItem;
195
- prevSibling = child;
196
- }
264
+ const childCmp = child;
265
+ childCmp.realParent = parent;
266
+ if (prev.__logicType) {
267
+ childCmp.realBefore = prev.realAfter;
268
+ } else {
269
+ childCmp.realBefore = prev;
197
270
  }
198
271
  }
199
272
  }
@@ -210,33 +283,20 @@ class Terp {
210
283
  point = point.anchor;
211
284
  }
212
285
  }
213
- /**
214
- * 单个节点:
215
- * 由声明部分和(可选的)子节点块组成
216
- * <node> ::= <declaration> <childrenBlockOpt>
217
- * */
218
- node() {
219
- const _declaration = this.declaration();
220
- if (_declaration.__logicType & LogicType.If && !_declaration.condition()) {
221
- return _declaration;
222
- }
223
- this.childrenBlockOpt(_declaration);
224
- return _declaration;
225
- }
226
286
  /**
227
287
  * 声明部分:
228
288
  * 包含首行定义和(可选的)多行属性扩展
229
289
  * <declaration> ::= <tagName=token> <headerLine> <extensionLines>
230
290
  * */
231
- declaration() {
291
+ declaration(ctx) {
232
292
  const [hookType, value] = this._hook({});
233
293
  let _node;
234
294
  if (value === "if") {
235
- return this.ifDeclaration();
295
+ return this.ifDeclaration(ctx);
236
296
  } else if (hookType) {
237
297
  if (hookType === "static") {
238
298
  if (typeof value === "function" && value.prototype instanceof Store) {
239
- _node = this.componentDeclaration(value);
299
+ _node = this.componentDeclaration(value, ctx);
240
300
  } else if (typeof value === "function") {
241
301
  _node = this.fragmentDeclaration(value);
242
302
  } else {
@@ -263,8 +323,7 @@ class Terp {
263
323
  fragmentDeclaration(renderFragment) {
264
324
  const fragmentNode = {
265
325
  __logicType: LogicType.Fragment,
266
- directList: [],
267
- realList: []
326
+ realParent: null
268
327
  };
269
328
  renderFragment.call(this.data, this.opt, { data: this.data, root: "", anchor: "" });
270
329
  return fragmentNode;
@@ -292,7 +351,7 @@ class Terp {
292
351
  this.setProp(node, key, value, hookI);
293
352
  }
294
353
  }
295
- componentDeclaration(Component) {
354
+ componentDeclaration(Component, ctx) {
296
355
  const child = Component.new();
297
356
  const prevOnePropParsed = this.onePropParsed;
298
357
  this.onePropParsed = (node, key, value, valueIsMapKey, hookI) => {
@@ -307,36 +366,66 @@ class Terp {
307
366
  child[Keys.Raw][key] = value;
308
367
  }
309
368
  };
369
+ const afterAnchor = this.insertAfterAnchor(ctx);
310
370
  tap.once(TerpEvt.AllAttrGot, () => {
371
+ const parent = ctx.realParent;
372
+ const prev = ctx.prevSibling;
311
373
  this.onePropParsed = prevOnePropParsed;
312
- const root = child["ui"](this.opt, { data: child });
313
- tap.emit(TerpEvt.HandledComponentNode, root);
374
+ const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
375
+ componentNode.realAfter = afterAnchor;
376
+ tap.emit(TerpEvt.HandledComponentNode, componentNode);
314
377
  });
315
378
  return { __logicType: LogicType.Component };
316
379
  }
317
- ifDeclaration() {
380
+ ifDeclaration(ctx) {
318
381
  this.tokenizer.consume();
319
- const [isHook, value] = this._hook({});
382
+ const [hookType, value] = this._hook({});
320
383
  const ifNode = {
321
384
  __logicType: LogicType.If,
322
- condition: value,
323
- directList: [],
324
- realList: [],
325
385
  snapshot: this.tokenizer.snapshot(),
386
+ condition: null,
387
+ realParent: null,
326
388
  isFirstRender: true,
327
- watcher: null,
328
- anchor: null
389
+ effect: null
329
390
  };
330
- ifNode.watcher = effect(
391
+ const valueIsMapKey = Reflect.has(this.data[Keys.Raw], value);
392
+ let signal;
393
+ if (valueIsMapKey) {
394
+ runWithPulling(() => this.data[value], null);
395
+ const { cells } = this.data[Keys.Meta];
396
+ signal = cells.get(value);
397
+ } else {
398
+ const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
399
+ signal = $(fn);
400
+ }
401
+ ifNode.condition = signal;
402
+ ifNode.realAfter = this.insertAfterAnchor(ctx);
403
+ ifNode.effect = effect(
331
404
  ({ val }) => {
332
405
  if (val) {
333
- this.tokenizer.consume();
334
- this.tokenizer.consume();
406
+ if (ifNode.isFirstRender) {
407
+ this.tokenizer.consume();
408
+ this.tokenizer.consume();
409
+ } else {
410
+ this.tokenizer.resume(ifNode.snapshot);
411
+ this.program(ifNode.realParent, ifNode.realBefore);
412
+ }
335
413
  } else {
336
- this.tokenizer.skip();
414
+ if (ifNode.isFirstRender) {
415
+ this.tokenizer.skip();
416
+ } else {
417
+ const { realBefore, realAfter, realParent } = ifNode;
418
+ let point = this.nextSib(realBefore);
419
+ while (point !== realAfter) {
420
+ const next = this.nextSib(point);
421
+ this.remove(point, realParent, realBefore);
422
+ point = next;
423
+ }
424
+ }
337
425
  }
426
+ ifNode.isFirstRender = false;
338
427
  },
339
- [value]
428
+ [signal]
340
429
  );
341
430
  return ifNode;
342
431
  }
@@ -400,19 +489,6 @@ class Terp {
400
489
  this.tokenizer.consume();
401
490
  }
402
491
  }
403
- /** 子节点块:
404
- * 必须被缩进包裹
405
- * <childrenBlockOpt> ::= INDENT <nodeList>
406
- * | ε /* 空(表示叶子节点,没有孩子)
407
- * */
408
- childrenBlockOpt(parent) {
409
- if (!(this.tokenizer.token.type & TokenType.Indent)) {
410
- return [];
411
- }
412
- this.tokenizer.consume();
413
- const list = this.nodeList(parent);
414
- return list;
415
- }
416
492
  config(opt) {
417
493
  Object.assign(this, opt);
418
494
  this.opt = opt;
@@ -420,28 +496,47 @@ class Terp {
420
496
  createNode(name) {
421
497
  return {
422
498
  name,
423
- props: {}
499
+ props: {},
500
+ nextSibling: null
424
501
  };
425
502
  }
426
- insert(parent, node, prevSibling, prevItem) {
427
- return this.defaultInsert(parent, node, prevSibling, prevItem);
503
+ nextSib(node) {
504
+ return node.nextSibling;
428
505
  }
429
- defaultInsert(parent, node, prevSibling, prevItem) {
430
- if (prevSibling) {
431
- const children = parent.children;
432
- const insertI = children.findIndex((item) => item === prevSibling);
433
- children.splice(insertI + 1, 0, node);
506
+ _createAnchor() {
507
+ const anchor = this.createAnchor();
508
+ anchor[IsAnchor] = true;
509
+ return anchor;
510
+ }
511
+ createAnchor() {
512
+ return {
513
+ name: "anchor",
514
+ nextSibling: null
515
+ };
516
+ }
517
+ insertAfter(parent, node, prev) {
518
+ return this.defaultInsert(parent, node, prev);
519
+ }
520
+ defaultInsert(parent, node, prev) {
521
+ if (prev) {
522
+ const next = prev.nextSibling;
523
+ prev.nextSibling = node;
524
+ node.nextSibling = next;
434
525
  } else {
435
- parent.children = [node];
526
+ parent.firstChild = node;
436
527
  }
437
528
  }
438
- remove(parent, node, prevSibling, prevItem) {
439
- return this.defaultRemove(parent, node, prevSibling, prevItem);
529
+ remove(node, parent, prev) {
530
+ return this.defaultRemove(node, parent, prev);
440
531
  }
441
532
  // TODO: 默认改成 prevItem
442
- defaultRemove(parent, node, prevSibling, prevItem) {
443
- if (parent.children) {
444
- parent.children.splice(parent.children.indexOf(node), 1);
533
+ defaultRemove(node, parent, prevSibling) {
534
+ const next = node.nextSibling;
535
+ if (prevSibling) {
536
+ prevSibling.nextSibling = next;
537
+ }
538
+ if (parent.firstChild === node) {
539
+ parent.firstChild = next;
445
540
  }
446
541
  }
447
542
  setProp(node, key, value, hookI) {
@@ -461,5 +556,487 @@ class Terp {
461
556
  }
462
557
  }
463
558
 
464
- export { Terp };
559
+ const _Tokenizer = class _Tokenizer {
560
+ constructor() {
561
+ /** 缩进大小 默认 2 */
562
+ this.TabSize = 2;
563
+ /** 缩进字符 */
564
+ this.Tab = Array.from({ length: this.TabSize }, () => " ").join("");
565
+ /** 匹配标识符 */
566
+ this.IdExp = /[\d\w\/]/;
567
+ /** 回车后需要判断缩进 */
568
+ this.needIndent = false;
569
+ /** 用于跳过第一个节点前的空白字符串,以及生成基础缩进 */
570
+ this.isFirstToken = true;
571
+ /** 记录历史缩进的长度,相对于行首 */
572
+ this.dentStack = [0];
573
+ /** 当前字符 index */
574
+ this.i = 0;
575
+ this.handledTokens = [];
576
+ /**
577
+ * 有些标识符能产生多个 token
578
+ * 例如 dedent
579
+ * parent1
580
+ * child
581
+ * subChild
582
+ * parent2 <- 产生两个 dedent
583
+ */
584
+ this.waitingTokens = new Queue();
585
+ }
586
+ consume() {
587
+ const token = this.token;
588
+ this.nextToken();
589
+ return token;
590
+ }
591
+ // /** 恢复至某一个现场,进行 token 重算 */
592
+ resume(_snapshot) {
593
+ this.token = void 0;
594
+ this.needIndent = false;
595
+ this.isFirstToken = true;
596
+ this.dentStack = [0];
597
+ Object.assign(this, _snapshot);
598
+ }
599
+ snapshot() {
600
+ return {
601
+ i: this.i,
602
+ waitingTokens: this.waitingTokens.clone()
603
+ };
604
+ }
605
+ skip() {
606
+ const logicDentLen = this.dentStack[this.dentStack.length - 1];
607
+ let needIndent = false;
608
+ let skipFragment = ``;
609
+ this.token = void 0;
610
+ while (1) {
611
+ const char = this.char;
612
+ if (char === "\n") {
613
+ needIndent = true;
614
+ skipFragment += char;
615
+ this.next();
616
+ continue;
617
+ }
618
+ if (!needIndent) {
619
+ skipFragment += char;
620
+ this.next();
621
+ continue;
622
+ }
623
+ needIndent = false;
624
+ const { value, isEmptyLine } = this.getDentValue();
625
+ const currLen = value.length;
626
+ if (isEmptyLine) continue;
627
+ if (currLen > logicDentLen) {
628
+ skipFragment += value;
629
+ } else {
630
+ for (let i = this.dentStack.length - 1; i >= 0; i--) {
631
+ const expLen = this.dentStack[i];
632
+ if (currLen === expLen) break;
633
+ if (currLen > expLen) {
634
+ throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
635
+ }
636
+ if (this.shorterThanBaseDentEof()) {
637
+ break;
638
+ }
639
+ this.dentStack.pop();
640
+ if (!this.token) {
641
+ this.setToken(TokenType.Dedent, String(expLen));
642
+ } else {
643
+ this.waitingTokens.push({
644
+ type: TokenType.Dedent,
645
+ typeName: TokenType[TokenType.Dedent],
646
+ value: String(expLen)
647
+ });
648
+ }
649
+ }
650
+ break;
651
+ }
652
+ }
653
+ if (!this.token) {
654
+ this.nextToken();
655
+ }
656
+ return skipFragment;
657
+ }
658
+ setCode(code) {
659
+ this.code = "\n" + code.trimEnd() + `
660
+ ${_Tokenizer.EofId}`;
661
+ }
662
+ tokenize() {
663
+ var _a, _b;
664
+ do {
665
+ this.nextToken();
666
+ console.log("token:", TokenType[(_a = this.token) == null ? void 0 : _a.type], JSON.stringify(((_b = this.token) == null ? void 0 : _b.value) || ""));
667
+ } while (!this.isEof());
668
+ }
669
+ isEof() {
670
+ if (!this.token) return false;
671
+ return this.token.type & TokenType.Identifier && this.token.value === _Tokenizer.EofId;
672
+ }
673
+ get char() {
674
+ return this.code[this.i];
675
+ }
676
+ get prev() {
677
+ return this.code[this.i - 1];
678
+ }
679
+ get after() {
680
+ return this.code[this.i + 1];
681
+ }
682
+ next() {
683
+ const prev = this.code[this.i];
684
+ this.i++;
685
+ const curr = this.code[this.i];
686
+ return [prev, curr];
687
+ }
688
+ setToken(type, value) {
689
+ this.token = {
690
+ type,
691
+ typeName: TokenType[type],
692
+ value
693
+ };
694
+ this.isFirstToken = false;
695
+ }
696
+ testId(value) {
697
+ if (typeof value !== "string") return false;
698
+ return this.IdExp.test(value);
699
+ }
700
+ nextToken() {
701
+ try {
702
+ if (this.isEof()) {
703
+ return this.token;
704
+ }
705
+ this.token = void 0;
706
+ if (this.waitingTokens.len) {
707
+ const item = this.waitingTokens.shift();
708
+ this.setToken(item.type, item.value);
709
+ return this.token;
710
+ }
711
+ outer: while (1) {
712
+ if (this.needIndent) {
713
+ this.dent();
714
+ } else {
715
+ let { char } = this;
716
+ switch (char) {
717
+ case " ":
718
+ case " ":
719
+ break;
720
+ // 找后续所有 newLine
721
+ case "\n":
722
+ this.newLine();
723
+ this.needIndent = true;
724
+ break;
725
+ case "=":
726
+ this.assignment();
727
+ break;
728
+ case "|":
729
+ this.pipe();
730
+ break;
731
+ case "'":
732
+ case '"':
733
+ this.str(char);
734
+ break;
735
+ case "{":
736
+ this.brace();
737
+ break;
738
+ case "$":
739
+ const handled = this.dynamic(char);
740
+ if (handled) break;
741
+ default:
742
+ if (isNum(char)) {
743
+ this.number(char);
744
+ break;
745
+ }
746
+ if (this.testId(char)) {
747
+ this.identifier(char);
748
+ }
749
+ break;
750
+ }
751
+ this.next();
752
+ }
753
+ if (this.token) {
754
+ break;
755
+ }
756
+ }
757
+ return this.token;
758
+ } catch (error) {
759
+ console.error(error);
760
+ } finally {
761
+ this.handledTokens.push(this.token);
762
+ }
763
+ }
764
+ assignment() {
765
+ this.setToken(TokenType.Assign, "=");
766
+ }
767
+ pipe() {
768
+ this.setToken(TokenType.Pipe, "|");
769
+ }
770
+ dynamic(char) {
771
+ let nextC = this.after;
772
+ if (nextC !== "{") {
773
+ return false;
774
+ }
775
+ this.next();
776
+ let value = "${";
777
+ let innerBrace = 0;
778
+ while (1) {
779
+ nextC = this.after;
780
+ value += nextC;
781
+ this.next();
782
+ if (nextC === "{") {
783
+ innerBrace++;
784
+ }
785
+ if (nextC === "}") {
786
+ if (!innerBrace) {
787
+ break;
788
+ }
789
+ innerBrace--;
790
+ }
791
+ }
792
+ this.setToken(TokenType.Identifier, value);
793
+ return true;
794
+ }
795
+ brace() {
796
+ let inComment, inString, count = 0, value = "", backslashCount = 0;
797
+ while (1) {
798
+ const char = this.char;
799
+ const nextChar = this.after;
800
+ if (inComment === "single" && char === "\n") {
801
+ inComment = null;
802
+ } else if (inComment === "multi" && char === "*" && nextChar === "/") {
803
+ inComment = null;
804
+ value += this.next()[0];
805
+ } else if (inString) {
806
+ if (char === inString && backslashCount % 2 === 0) {
807
+ inString = null;
808
+ }
809
+ backslashCount = char === "\\" ? backslashCount + 1 : 0;
810
+ } else {
811
+ if (char === "/" && nextChar === "/") {
812
+ inComment = "single";
813
+ value += this.next()[0];
814
+ } else if (char === "/" && nextChar === "*") {
815
+ inComment = "multi";
816
+ value += this.next()[0];
817
+ } else if (char === "'" || char === '"' || char === "`") {
818
+ inString = char;
819
+ } else if (char === "{") {
820
+ count++;
821
+ } else if (char === "}") {
822
+ count--;
823
+ }
824
+ }
825
+ if (count === 0 && inString == null && inComment == null) {
826
+ this.setToken(TokenType.InsertionExp, value.slice(1));
827
+ return;
828
+ }
829
+ value += this.next()[0];
830
+ }
831
+ }
832
+ newLine() {
833
+ let value = "\n";
834
+ let nextC;
835
+ while (1) {
836
+ nextC = this.after;
837
+ if (nextC !== "\n") {
838
+ break;
839
+ }
840
+ value += nextC;
841
+ this.next();
842
+ }
843
+ if (this.isFirstToken) {
844
+ return;
845
+ }
846
+ this.setToken(TokenType.NewLine, value);
847
+ }
848
+ getDentValue() {
849
+ let value = "";
850
+ let nextC;
851
+ let isEmptyLine = false;
852
+ while (1) {
853
+ const nextChar = this.char;
854
+ switch (nextChar) {
855
+ case " ":
856
+ nextC = this.Tab;
857
+ break;
858
+ case " ":
859
+ nextC = " ";
860
+ break;
861
+ case "\n":
862
+ nextC = "\n";
863
+ break;
864
+ default:
865
+ nextC = "";
866
+ break;
867
+ }
868
+ if (nextC === "\n") {
869
+ isEmptyLine = true;
870
+ break;
871
+ }
872
+ if (!nextC) {
873
+ break;
874
+ }
875
+ value += nextC;
876
+ this.next();
877
+ }
878
+ return {
879
+ value,
880
+ isEmptyLine
881
+ };
882
+ }
883
+ dent() {
884
+ const { value, isEmptyLine } = this.getDentValue();
885
+ if (isEmptyLine) {
886
+ this.needIndent = true;
887
+ return;
888
+ }
889
+ this.needIndent = false;
890
+ if (this.isFirstToken) {
891
+ this.dentStack[0] = value.length;
892
+ return;
893
+ }
894
+ let currLen = value.length;
895
+ const indentHasLen = currLen > 0;
896
+ const prevLen = this.dentStack[this.dentStack.length - 1];
897
+ if (currLen > prevLen) {
898
+ this.dentStack.push(currLen);
899
+ this.setToken(TokenType.Indent, String(currLen));
900
+ return indentHasLen;
901
+ }
902
+ if (currLen < prevLen) {
903
+ for (let i = this.dentStack.length; i--; ) {
904
+ const expLen = this.dentStack[i];
905
+ if (currLen === expLen) break;
906
+ if (currLen > expLen) {
907
+ throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
908
+ }
909
+ if (this.shorterThanBaseDentEof()) {
910
+ return;
911
+ }
912
+ this.dentStack.pop();
913
+ if (!this.token) {
914
+ this.setToken(TokenType.Dedent, String(expLen));
915
+ } else {
916
+ this.waitingTokens.push({
917
+ type: TokenType.Dedent,
918
+ typeName: TokenType[TokenType.Dedent],
919
+ value: String(expLen)
920
+ });
921
+ }
922
+ }
923
+ return indentHasLen;
924
+ }
925
+ return indentHasLen;
926
+ }
927
+ shorterThanBaseDentEof() {
928
+ const yes = this.dentStack.length === 1;
929
+ if (yes) {
930
+ if (!this.token) {
931
+ this.setToken(TokenType.Identifier, _Tokenizer.EofId);
932
+ } else {
933
+ this.waitingTokens.push({
934
+ type: TokenType.Identifier,
935
+ typeName: TokenType[TokenType.Identifier],
936
+ value: _Tokenizer.EofId
937
+ });
938
+ }
939
+ }
940
+ return yes;
941
+ }
942
+ identifier(char) {
943
+ let value = char;
944
+ let nextC;
945
+ while (1) {
946
+ nextC = this.after;
947
+ if (!this.testId(nextC)) {
948
+ break;
949
+ }
950
+ value += nextC;
951
+ this.next();
952
+ }
953
+ let realValue = value === "null" ? null : value === "undefined" ? void 0 : value === "false" ? false : value === "true" ? true : value;
954
+ this.setToken(TokenType.Identifier, realValue);
955
+ }
956
+ str(char) {
957
+ let value = '"';
958
+ let nextC;
959
+ let continuousBackslashCount = 0;
960
+ while (1) {
961
+ nextC = this.after;
962
+ value += nextC;
963
+ const memoCount = continuousBackslashCount;
964
+ if (nextC === "\\") {
965
+ continuousBackslashCount++;
966
+ } else {
967
+ continuousBackslashCount = 0;
968
+ }
969
+ this.next();
970
+ if (nextC === char && memoCount % 2 === 0) {
971
+ break;
972
+ }
973
+ }
974
+ this.setToken(TokenType.Identifier, JSON.parse(value.slice(0, -1) + '"'));
975
+ }
976
+ number(char) {
977
+ let value = char;
978
+ let nextC;
979
+ while (1) {
980
+ nextC = this.after;
981
+ if (!isNum(nextC)) {
982
+ break;
983
+ }
984
+ value += nextC;
985
+ this.next();
986
+ }
987
+ this.setToken(TokenType.Identifier, Number(value));
988
+ }
989
+ eof() {
990
+ this.setToken(TokenType.Eof, "End Of File");
991
+ }
992
+ };
993
+ /** Eof 标识符的值 */
994
+ _Tokenizer.EofId = `__EOF__${Date.now()}`;
995
+ let Tokenizer = _Tokenizer;
996
+
997
+ var __defProp = Object.defineProperty;
998
+ var __defProps = Object.defineProperties;
999
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
1000
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1001
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
1002
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
1003
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1004
+ var __spreadValues = (a, b) => {
1005
+ for (var prop in b || (b = {}))
1006
+ if (__hasOwnProp.call(b, prop))
1007
+ __defNormalProp(a, prop, b[prop]);
1008
+ if (__getOwnPropSymbols)
1009
+ for (var prop of __getOwnPropSymbols(b)) {
1010
+ if (__propIsEnum.call(b, prop))
1011
+ __defNormalProp(a, prop, b[prop]);
1012
+ }
1013
+ return a;
1014
+ };
1015
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1016
+ function bobe(fragments, ...values) {
1017
+ const ui = function ui2(options, valueOpt, root, before) {
1018
+ const tokenizer = new Tokenizer();
1019
+ const cmp = new Interpreter(tokenizer);
1020
+ Object.assign(cmp, valueOpt);
1021
+ cmp.config(__spreadProps(__spreadValues({}, options), {
1022
+ hook({ i }) {
1023
+ return values[i];
1024
+ },
1025
+ setProp(node, key, value, hookI) {
1026
+ node.props[key] = value;
1027
+ }
1028
+ }));
1029
+ cmp.init(Array.from(fragments));
1030
+ return cmp.program(root, before);
1031
+ };
1032
+ return ui;
1033
+ }
1034
+ function customRender(option) {
1035
+ return function render(Ctor, root) {
1036
+ const store = Ctor.new();
1037
+ return [store["ui"](option, { data: store }, root), store];
1038
+ };
1039
+ }
1040
+
1041
+ export { bobe, customRender };
465
1042
  //# sourceMappingURL=bobe.esm.js.map