bobe 0.0.36 → 0.0.38

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
@@ -13,8 +13,15 @@ let TokenType = function (TokenType) {
13
13
  TokenType[TokenType["InsertionExp"] = 128] = "InsertionExp";
14
14
  TokenType[TokenType["Semicolon"] = 256] = "Semicolon";
15
15
  TokenType[TokenType["StaticInsExp"] = 512] = "StaticInsExp";
16
+ TokenType[TokenType["String"] = 1024] = "String";
17
+ TokenType[TokenType["Number"] = 2048] = "Number";
18
+ TokenType[TokenType["Boolean"] = 4096] = "Boolean";
19
+ TokenType[TokenType["Null"] = 8192] = "Null";
20
+ TokenType[TokenType["Undefined"] = 16384] = "Undefined";
16
21
  return TokenType;
17
22
  }({});
23
+ const BaseTokenType = TokenType.String | TokenType.Number | TokenType.Boolean | TokenType.Null | TokenType.Undefined;
24
+ const ValueTokenType = BaseTokenType | TokenType.InsertionExp | TokenType.StaticInsExp;
18
25
  let FakeType = function (FakeType) {
19
26
  FakeType[FakeType["If"] = 1] = "If";
20
27
  FakeType[FakeType["Fail"] = 2] = "Fail";
@@ -42,6 +49,25 @@ let NodeSort = function (NodeSort) {
42
49
  TerpEvt["HandledComponentNode"] = "handled-component-node";
43
50
  return TerpEvt;
44
51
  })({});
52
+ let ParseErrorCode = function (ParseErrorCode) {
53
+ ParseErrorCode[ParseErrorCode["UNCLOSED_BRACE"] = 9001] = "UNCLOSED_BRACE";
54
+ ParseErrorCode[ParseErrorCode["UNCLOSED_STRING"] = 9002] = "UNCLOSED_STRING";
55
+ ParseErrorCode[ParseErrorCode["UNCLOSED_STATIC_INS"] = 9003] = "UNCLOSED_STATIC_INS";
56
+ ParseErrorCode[ParseErrorCode["INCONSISTENT_INDENT"] = 9004] = "INCONSISTENT_INDENT";
57
+ ParseErrorCode[ParseErrorCode["INDENT_MISMATCH"] = 9005] = "INDENT_MISMATCH";
58
+ ParseErrorCode[ParseErrorCode["MISSING_ASSIGN"] = 9006] = "MISSING_ASSIGN";
59
+ ParseErrorCode[ParseErrorCode["INVALID_TAG_NAME"] = 9007] = "INVALID_TAG_NAME";
60
+ ParseErrorCode[ParseErrorCode["INVALID_PROP_KEY"] = 9008] = "INVALID_PROP_KEY";
61
+ ParseErrorCode[ParseErrorCode["ELSE_WITHOUT_IF"] = 9009] = "ELSE_WITHOUT_IF";
62
+ ParseErrorCode[ParseErrorCode["EMPTY_IF_BODY"] = 9010] = "EMPTY_IF_BODY";
63
+ ParseErrorCode[ParseErrorCode["EMPTY_FOR_BODY"] = 9011] = "EMPTY_FOR_BODY";
64
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_COLLECTION"] = 9012] = "MISSING_FOR_COLLECTION";
65
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_SEMICOLON"] = 9013] = "MISSING_FOR_SEMICOLON";
66
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_ITEM"] = 9014] = "MISSING_FOR_ITEM";
67
+ ParseErrorCode[ParseErrorCode["MISSING_PROP_ASSIGNMENT"] = 9015] = "MISSING_PROP_ASSIGNMENT";
68
+ ParseErrorCode[ParseErrorCode["PIPE_IN_WRONG_CONTEXT"] = 9016] = "PIPE_IN_WRONG_CONTEXT";
69
+ return ParseErrorCode;
70
+ }({});
45
71
  class ParseSyntaxError extends SyntaxError {
46
72
  constructor(code, message, loc) {
47
73
  super(message);
@@ -159,7 +185,7 @@ class Tokenizer {
159
185
  const expLen = this.dentStack[i];
160
186
  if (currLen === expLen) break;
161
187
  if (currLen > expLen) {
162
- throw SyntaxError(`缩进错误,缩进长度不匹配`);
188
+ throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
163
189
  }
164
190
  if (this.shorterThanBaseDentEof()) {
165
191
  break;
@@ -350,7 +376,7 @@ class Tokenizer {
350
376
  while (1) {
351
377
  nextC = this.code[this.i + 1];
352
378
  if (nextC === undefined) {
353
- this.throwUnclosed('UNCLOSED_STATIC_INS', '未闭合的 "${...}"', startOffset, startLine, startCol);
379
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_STATIC_INS, '未闭合的 "${...}"', startOffset, startLine, startCol);
354
380
  }
355
381
  value += nextC;
356
382
  this.next();
@@ -379,7 +405,7 @@ class Tokenizer {
379
405
  while (1) {
380
406
  const char = this.code[this.i];
381
407
  if (char === undefined) {
382
- this.throwUnclosed('UNCLOSED_BRACE', '未闭合的 "{"', startOffset, startLine, startCol);
408
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_BRACE, '未闭合的 "{"', startOffset, startLine, startCol);
383
409
  }
384
410
  const nextChar = this.code[this.i + 1];
385
411
  if (inComment === 'single' && char === '\n') {
@@ -468,6 +494,18 @@ class Tokenizer {
468
494
  isEmptyLine
469
495
  };
470
496
  }
497
+ emptyLoc() {
498
+ const pos = this.getCurrentPos();
499
+ return {
500
+ start: pos,
501
+ end: {
502
+ offset: pos.offset + 1,
503
+ line: pos.line,
504
+ column: pos.column + 1
505
+ },
506
+ source: ' '
507
+ };
508
+ }
471
509
  dent() {
472
510
  const _this$getDentValue2 = this.getDentValue(),
473
511
  value = _this$getDentValue2.value,
@@ -494,7 +532,7 @@ class Tokenizer {
494
532
  const expLen = this.dentStack[i];
495
533
  if (currLen === expLen) break;
496
534
  if (currLen > expLen) {
497
- throw SyntaxError('缩进大小不统一');
535
+ throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
498
536
  }
499
537
  if (this.shorterThanBaseDentEof()) {
500
538
  return;
@@ -559,8 +597,30 @@ class Tokenizer {
559
597
  this.setToken(TokenType.Dedent, '');
560
598
  return;
561
599
  }
562
- let realValue = value === 'null' ? null : value === 'undefined' ? undefined : value === 'false' ? false : value === 'true' ? true : value;
563
- this.setToken(TokenType.Identifier, realValue);
600
+ let realValue, tokenType;
601
+ switch (value) {
602
+ case 'null':
603
+ realValue = null;
604
+ tokenType = TokenType.Null;
605
+ break;
606
+ case 'undefined':
607
+ realValue = undefined;
608
+ tokenType = TokenType.Undefined;
609
+ break;
610
+ case 'false':
611
+ realValue = false;
612
+ tokenType = TokenType.Boolean;
613
+ break;
614
+ case 'true':
615
+ realValue = true;
616
+ tokenType = TokenType.Boolean;
617
+ break;
618
+ default:
619
+ realValue = value;
620
+ tokenType = TokenType.Identifier;
621
+ break;
622
+ }
623
+ this.setToken(tokenType, realValue);
564
624
  }
565
625
  str(char) {
566
626
  const startOffset = this.preI,
@@ -572,7 +632,7 @@ class Tokenizer {
572
632
  while (1) {
573
633
  nextC = this.code[this.i + 1];
574
634
  if (nextC === undefined) {
575
- this.throwUnclosed('UNCLOSED_STRING', '未闭合的字符串字面量', startOffset, startLine, startCol);
635
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_STRING, '未闭合的字符串字面量', startOffset, startLine, startCol);
576
636
  }
577
637
  const memoCount = continuousBackslashCount;
578
638
  if (nextC === '\\') {
@@ -586,7 +646,7 @@ class Tokenizer {
586
646
  }
587
647
  value += nextC;
588
648
  }
589
- this.setToken(TokenType.Identifier, value);
649
+ this.setToken(TokenType.String, value);
590
650
  }
591
651
  number(char) {
592
652
  let value = char;
@@ -599,7 +659,7 @@ class Tokenizer {
599
659
  value += nextC;
600
660
  this.next();
601
661
  }
602
- this.setToken(TokenType.Identifier, Number(value));
662
+ this.setToken(TokenType.Number, Number(value));
603
663
  }
604
664
  eof() {
605
665
  this.setToken(TokenType.Eof, 'End Of File');
@@ -878,7 +938,7 @@ var NodeType = function (NodeType) {
878
938
  let _initProto;
879
939
  class Compiler {
880
940
  static {
881
- var _applyDecs$e = _slicedToArray(_applyDecs2311(this, [], [[NodeHook, 2, "parseProgram"], [[NodeHook, NodeLoc], 2, "parseComponentNode"], [[NodeHook, NodeLoc], 2, "parseElementNode"], [[NodeHook, NodeLoc], 2, "parseConditionalNode"], [[NodeHook, NodeLoc], 2, "parseLoopNode"], [NodeHook, 2, "parseProperty"], [[NodeHook, TokenLoc], 2, "parsePropertyKey"], [[NodeHook, TokenLoc], 2, "parsePropertyValue"], [[NodeHook, TokenLoc], 2, "parseName"]]).e, 1);
941
+ var _applyDecs$e = _slicedToArray(_applyDecs2311(this, [], [[NodeHook, 2, "parseProgram"], [[NodeHook, NodeLoc], 2, "parseComponentNode"], [[NodeHook, NodeLoc], 2, "parseElementNode"], [[NodeHook, NodeLoc], 2, "parseConditionalNode"], [[NodeHook, NodeLoc], 2, "parseLoopNode"], [NodeHook, 2, "parseProperty"], [[NodeHook, TokenLoc], 2, "parsePropertyKey"], [[NodeHook, TokenLoc], 2, "parseJsExp"], [[NodeHook, TokenLoc], 2, "parsePropertyValue"], [[NodeHook, TokenLoc], 2, "parseName"]]).e, 1);
882
942
  _initProto = _applyDecs$e[0];
883
943
  }
884
944
  errors = (_initProto(this), []);
@@ -886,25 +946,16 @@ class Compiler {
886
946
  this.tokenizer = tokenizer;
887
947
  this.hooks = hooks;
888
948
  }
889
- addError(code, message, loc) {
949
+ addError(code, message, loc, node) {
950
+ if (node) {
951
+ node.hasError = true;
952
+ }
890
953
  this.errors.push({
891
954
  code,
892
955
  message,
893
956
  loc
894
957
  });
895
958
  }
896
- emptyLoc() {
897
- const pos = this.tokenizer.getCurrentPos();
898
- return {
899
- start: pos,
900
- end: {
901
- offset: pos.offset + 1,
902
- line: pos.line,
903
- column: pos.column + 1
904
- },
905
- source: ' '
906
- };
907
- }
908
959
  parseProgram() {
909
960
  const body = [];
910
961
  try {
@@ -918,10 +969,8 @@ class Compiler {
918
969
  } catch (error) {
919
970
  if (error instanceof ParseSyntaxError) {
920
971
  this.addError(error.code, error.message, error.loc);
921
- } else if (error instanceof SyntaxError) {
922
- const knownCodes = ['INCONSISTENT_INDENT', 'INDENT_MISMATCH'];
923
- const code = knownCodes.includes(error.message) ? error.message : 'INCONSISTENT_INDENT';
924
- this.addError(code, error.message, this.emptyLoc());
972
+ } else {
973
+ this.addError(error.toString(), '未知错误', this.tokenizer.emptyLoc());
925
974
  }
926
975
  }
927
976
  return {
@@ -961,7 +1010,7 @@ class Compiler {
961
1010
  templateNode(siblings) {
962
1011
  const token = this.tokenizer.token;
963
1012
  if (token.type & TokenType.Pipe) {
964
- this.addError('PIPE_IN_WRONG_CONTEXT', '"|" 只能出现在元素属性扩展行中', token.loc ?? this.emptyLoc());
1013
+ this.addError(ParseErrorCode.PIPE_IN_WRONG_CONTEXT, '"|" 只能出现在元素属性扩展行中', token.loc ?? this.tokenizer.emptyLoc());
965
1014
  this.tokenizer.nextToken();
966
1015
  return null;
967
1016
  }
@@ -969,12 +1018,13 @@ class Compiler {
969
1018
  _this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
970
1019
  hookType = _this$tokenizer$_hook2[0],
971
1020
  value = _this$tokenizer$_hook2[1];
972
- if (value === 'if' || value === 'else' || value === 'fail') {
973
- if (value === 'else' || value === 'fail') {
1021
+ const isElseOrFail = value === 'else' || value === 'fail';
1022
+ if (value === 'if' || isElseOrFail) {
1023
+ if (isElseOrFail) {
974
1024
  const lastSibling = siblings[siblings.length - 1];
975
1025
  const lastType = lastSibling?.type;
976
1026
  if (lastType !== NodeType.If && lastType !== NodeType.Else && lastType !== NodeType.Fail) {
977
- this.addError('ELSE_WITHOUT_IF', `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.emptyLoc());
1027
+ this.addError(ParseErrorCode.ELSE_WITHOUT_IF, `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.tokenizer.emptyLoc());
978
1028
  }
979
1029
  }
980
1030
  return this.parseConditionalNode();
@@ -1002,7 +1052,7 @@ class Compiler {
1002
1052
  parseElementNode(node) {
1003
1053
  const tagToken = this.tokenizer.token;
1004
1054
  if (!(tagToken.type & TokenType.Identifier)) {
1005
- this.addError('INVALID_TAG_NAME', `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.emptyLoc());
1055
+ this.addError(ParseErrorCode.INVALID_TAG_NAME, `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.tokenizer.emptyLoc(), node);
1006
1056
  while (!(this.tokenizer.token.type & TokenType.NewLine) && !this.tokenizer.isEof()) {
1007
1057
  this.tokenizer.nextToken();
1008
1058
  }
@@ -1022,7 +1072,7 @@ class Compiler {
1022
1072
  parseConditionalNode(node) {
1023
1073
  const keyword = this.tokenizer.token.value;
1024
1074
  this.tokenizer.condExp();
1025
- const condition = this.parsePropertyValue();
1075
+ const condition = this.parseJsExp();
1026
1076
  this.tokenizer.nextToken();
1027
1077
  this.tokenizer.nextToken();
1028
1078
  node.type = keyword === 'if' ? NodeType.If : keyword === 'else' ? NodeType.Else : NodeType.Fail;
@@ -1033,24 +1083,24 @@ class Compiler {
1033
1083
  return node;
1034
1084
  }
1035
1085
  parseLoopNode(node) {
1036
- const forLoc = this.tokenizer.token.loc ?? this.emptyLoc();
1086
+ const forLoc = this.tokenizer.token.loc ?? this.tokenizer.emptyLoc();
1037
1087
  this.tokenizer.nextToken();
1038
- const collection = this.parsePropertyValue();
1088
+ const collection = this.parseJsExp();
1039
1089
  if (!collection.value && collection.value !== 0) {
1040
- this.addError('MISSING_FOR_COLLECTION', '"for" 缺少集合表达式', forLoc);
1090
+ this.addError(ParseErrorCode.MISSING_FOR_COLLECTION, '"for" 缺少集合表达式', forLoc, node);
1041
1091
  }
1042
1092
  const semicolonToken = this.tokenizer.nextToken();
1043
1093
  if (!(semicolonToken.type & TokenType.Semicolon)) {
1044
- this.addError('MISSING_FOR_SEMICOLON', '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.emptyLoc());
1094
+ this.addError(ParseErrorCode.MISSING_FOR_SEMICOLON, '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.tokenizer.emptyLoc(), node);
1045
1095
  }
1046
1096
  const itemToken = this.tokenizer.nextToken();
1047
1097
  const isDestruct = itemToken.type === TokenType.InsertionExp;
1048
1098
  if (isDestruct) {
1049
1099
  itemToken.value = '{' + itemToken.value + '}';
1050
1100
  }
1051
- const item = this.parsePropertyValue();
1101
+ const item = this.parseJsExp();
1052
1102
  if (!item.value && item.value !== 0) {
1053
- this.addError('MISSING_FOR_ITEM', '"for" 缺少 item 变量名', itemToken.loc ?? this.emptyLoc());
1103
+ this.addError(ParseErrorCode.MISSING_FOR_ITEM, '"for" 缺少 item 变量名', itemToken.loc ?? this.tokenizer.emptyLoc(), node);
1054
1104
  }
1055
1105
  let char = this.tokenizer.peekChar(),
1056
1106
  key,
@@ -1059,16 +1109,16 @@ class Compiler {
1059
1109
  this.tokenizer.nextToken();
1060
1110
  if (this.tokenizer.peekChar() !== '\n') {
1061
1111
  this.tokenizer.jsExp();
1062
- key = this.parsePropertyValue();
1112
+ key = this.parseJsExp();
1063
1113
  }
1064
1114
  } else if (char === '\n') ; else {
1065
1115
  this.tokenizer.nextToken();
1066
- index = this.parsePropertyValue();
1116
+ index = this.parseJsExp();
1067
1117
  if (this.tokenizer.peekChar() === ';') {
1068
1118
  this.tokenizer.nextToken();
1069
1119
  if (this.tokenizer.peekChar() !== '\n') {
1070
1120
  this.tokenizer.jsExp();
1071
- key = this.parsePropertyValue();
1121
+ key = this.parseJsExp();
1072
1122
  }
1073
1123
  }
1074
1124
  }
@@ -1102,23 +1152,41 @@ class Compiler {
1102
1152
  attributeList() {
1103
1153
  const props = [];
1104
1154
  while (!(this.tokenizer.token.type & TokenType.NewLine) && !(this.tokenizer.token.type & TokenType.Pipe) && !this.tokenizer.isEof()) {
1105
- props.push(this.parseProperty());
1155
+ const prop = this.parseProperty();
1156
+ if (prop) {
1157
+ props.push(prop);
1158
+ }
1106
1159
  }
1107
1160
  return props;
1108
1161
  }
1109
1162
  parseProperty(node) {
1110
1163
  node.type = NodeType.Property;
1111
- node.key = this.parsePropertyKey();
1112
- const token = this.tokenizer.nextToken();
1113
- if (token.value === '=') {
1114
- this.tokenizer.nextToken();
1115
- node.value = this.parsePropertyValue();
1164
+ if (this.tokenizer.token.type !== TokenType.Identifier) {
1165
+ this.addError(ParseErrorCode.INVALID_PROP_KEY, `属性名 "${this.tokenizer.token.value}" 不合法`, this.tokenizer.token.loc ?? this.tokenizer.emptyLoc(), node);
1116
1166
  this.tokenizer.nextToken();
1117
- } else {
1118
- this.addError('MISSING_ASSIGN', `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.emptyLoc());
1167
+ return null;
1119
1168
  }
1169
+ node.key = this.parsePropertyKey();
1170
+ const token = this.tokenizer.nextToken();
1171
+ if (token.value !== '=') {
1172
+ this.addError(ParseErrorCode.MISSING_ASSIGN, `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.tokenizer.emptyLoc(), node);
1173
+ node.loc.start = node.key.loc.start;
1174
+ node.loc.end = node.key.loc.end;
1175
+ node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1176
+ return node;
1177
+ }
1178
+ const valueToken = this.tokenizer.nextToken();
1179
+ if ((valueToken.type & ValueTokenType) === 0) {
1180
+ this.addError(ParseErrorCode.MISSING_PROP_ASSIGNMENT, `属性值不合法, "${valueToken.value}" 不合法`, valueToken.loc ?? this.tokenizer.emptyLoc(), node);
1181
+ node.loc.start = node.key.loc.start;
1182
+ node.loc.end = node.key.loc.end;
1183
+ node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1184
+ return node;
1185
+ }
1186
+ node.value = this.parsePropertyValue();
1187
+ this.tokenizer.nextToken();
1120
1188
  node.loc.start = node.key.loc.start;
1121
- node.loc.end = node.value ? node.value.loc.end : node.key.loc.end;
1189
+ node.loc.end = node.value.loc.end;
1122
1190
  node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1123
1191
  return node;
1124
1192
  }
@@ -1127,7 +1195,7 @@ class Compiler {
1127
1195
  node.key = this.tokenizer.token.value;
1128
1196
  return node;
1129
1197
  }
1130
- parsePropertyValue(node) {
1198
+ parseJsExp(node) {
1131
1199
  const _this$tokenizer$_hook3 = this.tokenizer._hook({}),
1132
1200
  _this$tokenizer$_hook4 = _slicedToArray(_this$tokenizer$_hook3, 2),
1133
1201
  hookType = _this$tokenizer$_hook4[0],
@@ -1136,7 +1204,7 @@ class Compiler {
1136
1204
  node.value = value;
1137
1205
  return node;
1138
1206
  }
1139
- parseName(node) {
1207
+ parsePropertyValue(node) {
1140
1208
  const _this$tokenizer$_hook5 = this.tokenizer._hook({}),
1141
1209
  _this$tokenizer$_hook6 = _slicedToArray(_this$tokenizer$_hook5, 2),
1142
1210
  hookType = _this$tokenizer$_hook6[0],
@@ -1145,6 +1213,15 @@ class Compiler {
1145
1213
  node.value = value;
1146
1214
  return node;
1147
1215
  }
1216
+ parseName(node) {
1217
+ const _this$tokenizer$_hook7 = this.tokenizer._hook({}),
1218
+ _this$tokenizer$_hook8 = _slicedToArray(_this$tokenizer$_hook7, 2),
1219
+ hookType = _this$tokenizer$_hook8[0],
1220
+ value = _this$tokenizer$_hook8[1];
1221
+ node.type = hookType === 'dynamic' ? NodeType.DynamicValue : NodeType.StaticValue;
1222
+ node.value = value;
1223
+ return node;
1224
+ }
1148
1225
  }
1149
1226
  function NodeLoc(target, context) {
1150
1227
  return function (_node) {