bobe 0.0.35 → 0.0.36
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.cjs.js +116 -12
- package/dist/bobe.cjs.js.map +1 -1
- package/dist/bobe.compiler.cjs.js +116 -12
- package/dist/bobe.compiler.cjs.js.map +1 -1
- package/dist/bobe.compiler.esm.js +116 -13
- package/dist/bobe.compiler.esm.js.map +1 -1
- package/dist/bobe.esm.js +116 -13
- package/dist/bobe.esm.js.map +1 -1
- package/dist/index.d.ts +20 -2
- package/dist/index.umd.js +116 -12
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/bobe.esm.js
CHANGED
|
@@ -42,6 +42,13 @@ let NodeSort = function (NodeSort) {
|
|
|
42
42
|
TerpEvt["HandledComponentNode"] = "handled-component-node";
|
|
43
43
|
return TerpEvt;
|
|
44
44
|
})({});
|
|
45
|
+
class ParseSyntaxError extends SyntaxError {
|
|
46
|
+
constructor(code, message, loc) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.loc = loc;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
45
52
|
|
|
46
53
|
class Tokenizer {
|
|
47
54
|
TabSize = 2;
|
|
@@ -80,6 +87,25 @@ class Tokenizer {
|
|
|
80
87
|
column: this.column
|
|
81
88
|
};
|
|
82
89
|
}
|
|
90
|
+
unclosedLoc(startOffset, startLine, startCol) {
|
|
91
|
+
const end = this.code.length - 1;
|
|
92
|
+
return {
|
|
93
|
+
start: {
|
|
94
|
+
offset: startOffset,
|
|
95
|
+
line: startLine,
|
|
96
|
+
column: startCol
|
|
97
|
+
},
|
|
98
|
+
end: {
|
|
99
|
+
offset: end,
|
|
100
|
+
line: this.line,
|
|
101
|
+
column: this.column
|
|
102
|
+
},
|
|
103
|
+
source: this.code.slice(startOffset, end)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
throwUnclosed(code, message, startOffset, startLine, startCol) {
|
|
107
|
+
throw new ParseSyntaxError(code, message, this.unclosedLoc(startOffset, startLine, startCol));
|
|
108
|
+
}
|
|
83
109
|
resume(_snapshot) {
|
|
84
110
|
this.token = undefined;
|
|
85
111
|
this.needIndent = false;
|
|
@@ -248,8 +274,7 @@ class Tokenizer {
|
|
|
248
274
|
}
|
|
249
275
|
return this.token;
|
|
250
276
|
} catch (error) {
|
|
251
|
-
|
|
252
|
-
return this.token;
|
|
277
|
+
throw error;
|
|
253
278
|
} finally {
|
|
254
279
|
this.handledTokens.push(this.token);
|
|
255
280
|
}
|
|
@@ -312,6 +337,9 @@ class Tokenizer {
|
|
|
312
337
|
this.setToken(TokenType.Pipe, '|');
|
|
313
338
|
}
|
|
314
339
|
staticIns() {
|
|
340
|
+
const startOffset = this.preI,
|
|
341
|
+
startLine = this.line,
|
|
342
|
+
startCol = this.preCol;
|
|
315
343
|
let nextC = this.code[this.i + 1];
|
|
316
344
|
if (nextC !== '{') {
|
|
317
345
|
return false;
|
|
@@ -321,6 +349,9 @@ class Tokenizer {
|
|
|
321
349
|
let innerBrace = 0;
|
|
322
350
|
while (1) {
|
|
323
351
|
nextC = this.code[this.i + 1];
|
|
352
|
+
if (nextC === undefined) {
|
|
353
|
+
this.throwUnclosed('UNCLOSED_STATIC_INS', '未闭合的 "${...}"', startOffset, startLine, startCol);
|
|
354
|
+
}
|
|
324
355
|
value += nextC;
|
|
325
356
|
this.next();
|
|
326
357
|
if (nextC === '{') {
|
|
@@ -337,6 +368,9 @@ class Tokenizer {
|
|
|
337
368
|
return true;
|
|
338
369
|
}
|
|
339
370
|
brace() {
|
|
371
|
+
const startOffset = this.preI,
|
|
372
|
+
startLine = this.line,
|
|
373
|
+
startCol = this.preCol;
|
|
340
374
|
let inComment,
|
|
341
375
|
inString,
|
|
342
376
|
count = 0,
|
|
@@ -344,6 +378,9 @@ class Tokenizer {
|
|
|
344
378
|
backslashCount = 0;
|
|
345
379
|
while (1) {
|
|
346
380
|
const char = this.code[this.i];
|
|
381
|
+
if (char === undefined) {
|
|
382
|
+
this.throwUnclosed('UNCLOSED_BRACE', '未闭合的 "{"', startOffset, startLine, startCol);
|
|
383
|
+
}
|
|
347
384
|
const nextChar = this.code[this.i + 1];
|
|
348
385
|
if (inComment === 'single' && char === '\n') {
|
|
349
386
|
inComment = null;
|
|
@@ -526,11 +563,17 @@ class Tokenizer {
|
|
|
526
563
|
this.setToken(TokenType.Identifier, realValue);
|
|
527
564
|
}
|
|
528
565
|
str(char) {
|
|
566
|
+
const startOffset = this.preI,
|
|
567
|
+
startLine = this.line,
|
|
568
|
+
startCol = this.preCol;
|
|
529
569
|
let value = '';
|
|
530
570
|
let nextC;
|
|
531
571
|
let continuousBackslashCount = 0;
|
|
532
572
|
while (1) {
|
|
533
573
|
nextC = this.code[this.i + 1];
|
|
574
|
+
if (nextC === undefined) {
|
|
575
|
+
this.throwUnclosed('UNCLOSED_STRING', '未闭合的字符串字面量', startOffset, startLine, startCol);
|
|
576
|
+
}
|
|
534
577
|
const memoCount = continuousBackslashCount;
|
|
535
578
|
if (nextC === '\\') {
|
|
536
579
|
continuousBackslashCount++;
|
|
@@ -838,18 +881,47 @@ class Compiler {
|
|
|
838
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);
|
|
839
882
|
_initProto = _applyDecs$e[0];
|
|
840
883
|
}
|
|
884
|
+
errors = (_initProto(this), []);
|
|
841
885
|
constructor(tokenizer, hooks = {}) {
|
|
842
886
|
this.tokenizer = tokenizer;
|
|
843
887
|
this.hooks = hooks;
|
|
844
|
-
|
|
888
|
+
}
|
|
889
|
+
addError(code, message, loc) {
|
|
890
|
+
this.errors.push({
|
|
891
|
+
code,
|
|
892
|
+
message,
|
|
893
|
+
loc
|
|
894
|
+
});
|
|
895
|
+
}
|
|
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
|
+
};
|
|
845
907
|
}
|
|
846
908
|
parseProgram() {
|
|
847
|
-
this.tokenizer.nextToken();
|
|
848
909
|
const body = [];
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
910
|
+
try {
|
|
911
|
+
this.tokenizer.nextToken();
|
|
912
|
+
while (!this.tokenizer.isEof()) {
|
|
913
|
+
const node = this.templateNode(body);
|
|
914
|
+
if (node) {
|
|
915
|
+
body.push(node);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
} catch (error) {
|
|
919
|
+
if (error instanceof ParseSyntaxError) {
|
|
920
|
+
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());
|
|
853
925
|
}
|
|
854
926
|
}
|
|
855
927
|
return {
|
|
@@ -875,7 +947,7 @@ class Compiler {
|
|
|
875
947
|
if (this.tokenizer.token.type & TokenType.Indent) {
|
|
876
948
|
this.tokenizer.nextToken();
|
|
877
949
|
while (!(this.tokenizer.token.type & TokenType.Dedent) && !this.tokenizer.isEof()) {
|
|
878
|
-
const child = this.templateNode();
|
|
950
|
+
const child = this.templateNode(children);
|
|
879
951
|
if (child) {
|
|
880
952
|
children.push(child);
|
|
881
953
|
}
|
|
@@ -886,13 +958,25 @@ class Compiler {
|
|
|
886
958
|
}
|
|
887
959
|
return children;
|
|
888
960
|
}
|
|
889
|
-
templateNode() {
|
|
890
|
-
this.tokenizer.token;
|
|
961
|
+
templateNode(siblings) {
|
|
962
|
+
const token = this.tokenizer.token;
|
|
963
|
+
if (token.type & TokenType.Pipe) {
|
|
964
|
+
this.addError('PIPE_IN_WRONG_CONTEXT', '"|" 只能出现在元素属性扩展行中', token.loc ?? this.emptyLoc());
|
|
965
|
+
this.tokenizer.nextToken();
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
891
968
|
const _this$tokenizer$_hook = this.tokenizer._hook({}),
|
|
892
969
|
_this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
|
|
893
970
|
hookType = _this$tokenizer$_hook2[0],
|
|
894
971
|
value = _this$tokenizer$_hook2[1];
|
|
895
972
|
if (value === 'if' || value === 'else' || value === 'fail') {
|
|
973
|
+
if (value === 'else' || value === 'fail') {
|
|
974
|
+
const lastSibling = siblings[siblings.length - 1];
|
|
975
|
+
const lastType = lastSibling?.type;
|
|
976
|
+
if (lastType !== NodeType.If && lastType !== NodeType.Else && lastType !== NodeType.Fail) {
|
|
977
|
+
this.addError('ELSE_WITHOUT_IF', `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.emptyLoc());
|
|
978
|
+
}
|
|
979
|
+
}
|
|
896
980
|
return this.parseConditionalNode();
|
|
897
981
|
}
|
|
898
982
|
if (value === 'for') {
|
|
@@ -917,6 +1001,13 @@ class Compiler {
|
|
|
917
1001
|
}
|
|
918
1002
|
parseElementNode(node) {
|
|
919
1003
|
const tagToken = this.tokenizer.token;
|
|
1004
|
+
if (!(tagToken.type & TokenType.Identifier)) {
|
|
1005
|
+
this.addError('INVALID_TAG_NAME', `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.emptyLoc());
|
|
1006
|
+
while (!(this.tokenizer.token.type & TokenType.NewLine) && !this.tokenizer.isEof()) {
|
|
1007
|
+
this.tokenizer.nextToken();
|
|
1008
|
+
}
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
920
1011
|
const tagName = tagToken.value;
|
|
921
1012
|
this.tokenizer.nextToken();
|
|
922
1013
|
const props = this.headerLineAndExtensions();
|
|
@@ -942,15 +1033,25 @@ class Compiler {
|
|
|
942
1033
|
return node;
|
|
943
1034
|
}
|
|
944
1035
|
parseLoopNode(node) {
|
|
1036
|
+
const forLoc = this.tokenizer.token.loc ?? this.emptyLoc();
|
|
945
1037
|
this.tokenizer.nextToken();
|
|
946
1038
|
const collection = this.parsePropertyValue();
|
|
947
|
-
|
|
1039
|
+
if (!collection.value && collection.value !== 0) {
|
|
1040
|
+
this.addError('MISSING_FOR_COLLECTION', '"for" 缺少集合表达式', forLoc);
|
|
1041
|
+
}
|
|
1042
|
+
const semicolonToken = this.tokenizer.nextToken();
|
|
1043
|
+
if (!(semicolonToken.type & TokenType.Semicolon)) {
|
|
1044
|
+
this.addError('MISSING_FOR_SEMICOLON', '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.emptyLoc());
|
|
1045
|
+
}
|
|
948
1046
|
const itemToken = this.tokenizer.nextToken();
|
|
949
1047
|
const isDestruct = itemToken.type === TokenType.InsertionExp;
|
|
950
1048
|
if (isDestruct) {
|
|
951
1049
|
itemToken.value = '{' + itemToken.value + '}';
|
|
952
1050
|
}
|
|
953
1051
|
const item = this.parsePropertyValue();
|
|
1052
|
+
if (!item.value && item.value !== 0) {
|
|
1053
|
+
this.addError('MISSING_FOR_ITEM', '"for" 缺少 item 变量名', itemToken.loc ?? this.emptyLoc());
|
|
1054
|
+
}
|
|
954
1055
|
let char = this.tokenizer.peekChar(),
|
|
955
1056
|
key,
|
|
956
1057
|
index;
|
|
@@ -1013,6 +1114,8 @@ class Compiler {
|
|
|
1013
1114
|
this.tokenizer.nextToken();
|
|
1014
1115
|
node.value = this.parsePropertyValue();
|
|
1015
1116
|
this.tokenizer.nextToken();
|
|
1117
|
+
} else {
|
|
1118
|
+
this.addError('MISSING_ASSIGN', `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.emptyLoc());
|
|
1016
1119
|
}
|
|
1017
1120
|
node.loc.start = node.key.loc.start;
|
|
1018
1121
|
node.loc.end = node.value ? node.value.loc.end : node.key.loc.end;
|
|
@@ -2010,5 +2113,5 @@ function customRender(option) {
|
|
|
2010
2113
|
};
|
|
2011
2114
|
}
|
|
2012
2115
|
|
|
2013
|
-
export { Compiler, NodeType, Tokenizer, bobe, customRender };
|
|
2116
|
+
export { Compiler, NodeType, ParseSyntaxError, Tokenizer, bobe, customRender };
|
|
2014
2117
|
//# sourceMappingURL=bobe.esm.js.map
|