bobe 0.0.36 → 0.0.37
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 +47 -31
- package/dist/bobe.cjs.js.map +1 -1
- package/dist/bobe.compiler.cjs.js +47 -31
- package/dist/bobe.compiler.cjs.js.map +1 -1
- package/dist/bobe.compiler.esm.js +47 -31
- package/dist/bobe.compiler.esm.js.map +1 -1
- package/dist/bobe.esm.js +47 -31
- package/dist/bobe.esm.js.map +1 -1
- package/dist/index.d.ts +19 -4
- package/dist/index.umd.js +47 -31
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -174,7 +174,22 @@ type TerpConf = Partial<Pick<Interpreter, 'createNode' | 'setProp' | 'insertAfte
|
|
|
174
174
|
type CustomRenderConf = Pick<TerpConf, 'createNode' | 'setProp' | 'insertAfter' | 'remove' | 'createAnchor' | 'firstChild' | 'nextSib'>;
|
|
175
175
|
type Hook = (props: HookProps) => any;
|
|
176
176
|
type HookType = 'dynamic' | 'static';
|
|
177
|
-
|
|
177
|
+
declare enum ParseErrorCode {
|
|
178
|
+
UNCLOSED_BRACE = 9001,
|
|
179
|
+
UNCLOSED_STRING = 9002,
|
|
180
|
+
UNCLOSED_STATIC_INS = 9003,
|
|
181
|
+
INCONSISTENT_INDENT = 9004,
|
|
182
|
+
INDENT_MISMATCH = 9005,
|
|
183
|
+
MISSING_ASSIGN = 9006,
|
|
184
|
+
INVALID_TAG_NAME = 9007,
|
|
185
|
+
ELSE_WITHOUT_IF = 9008,
|
|
186
|
+
EMPTY_IF_BODY = 9009,
|
|
187
|
+
EMPTY_FOR_BODY = 9010,
|
|
188
|
+
MISSING_FOR_COLLECTION = 9011,
|
|
189
|
+
MISSING_FOR_SEMICOLON = 9012,
|
|
190
|
+
MISSING_FOR_ITEM = 9013,
|
|
191
|
+
PIPE_IN_WRONG_CONTEXT = 9014
|
|
192
|
+
}
|
|
178
193
|
type ParseError = {
|
|
179
194
|
code: ParseErrorCode;
|
|
180
195
|
message: string;
|
|
@@ -310,6 +325,7 @@ declare class Tokenizer {
|
|
|
310
325
|
private brace;
|
|
311
326
|
private newLine;
|
|
312
327
|
private getDentValue;
|
|
328
|
+
emptyLoc(): SourceLocation;
|
|
313
329
|
private dent;
|
|
314
330
|
private shorterThanBaseDentEof;
|
|
315
331
|
private identifier;
|
|
@@ -413,7 +429,6 @@ declare class Compiler {
|
|
|
413
429
|
errors: ParseError[];
|
|
414
430
|
constructor(tokenizer: Tokenizer, hooks?: ParseHooks);
|
|
415
431
|
private addError;
|
|
416
|
-
private emptyLoc;
|
|
417
432
|
/**
|
|
418
433
|
* 编译程序入口,生成AST
|
|
419
434
|
*/
|
|
@@ -476,5 +491,5 @@ type ParseHooks = Partial<{
|
|
|
476
491
|
declare function bobe(fragments: TemplateStringsArray, ...values: any[]): BobeUI;
|
|
477
492
|
declare function customRender(option: CustomRenderConf): <T>(Ctor: typeof Store, root: any) => (ComponentNode$1 | Store)[];
|
|
478
493
|
|
|
479
|
-
export { Compiler, NodeType, ParseSyntaxError, Tokenizer, bobe, customRender };
|
|
480
|
-
export type { ASTNodeType, BaseNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, InterpolationNode, LoopNode, ParseError,
|
|
494
|
+
export { Compiler, NodeType, ParseErrorCode, ParseSyntaxError, Tokenizer, bobe, customRender };
|
|
495
|
+
export type { ASTNodeType, BaseNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, InterpolationNode, LoopNode, ParseError, Program, Property, PropertyKeyNode, PropertyValue, SourceLocation, StaticValue, TemplateNode, TextNode };
|
package/dist/index.umd.js
CHANGED
|
@@ -44,6 +44,23 @@
|
|
|
44
44
|
TerpEvt["HandledComponentNode"] = "handled-component-node";
|
|
45
45
|
return TerpEvt;
|
|
46
46
|
})({});
|
|
47
|
+
let ParseErrorCode = function (ParseErrorCode) {
|
|
48
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_BRACE"] = 9001] = "UNCLOSED_BRACE";
|
|
49
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_STRING"] = 9002] = "UNCLOSED_STRING";
|
|
50
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_STATIC_INS"] = 9003] = "UNCLOSED_STATIC_INS";
|
|
51
|
+
ParseErrorCode[ParseErrorCode["INCONSISTENT_INDENT"] = 9004] = "INCONSISTENT_INDENT";
|
|
52
|
+
ParseErrorCode[ParseErrorCode["INDENT_MISMATCH"] = 9005] = "INDENT_MISMATCH";
|
|
53
|
+
ParseErrorCode[ParseErrorCode["MISSING_ASSIGN"] = 9006] = "MISSING_ASSIGN";
|
|
54
|
+
ParseErrorCode[ParseErrorCode["INVALID_TAG_NAME"] = 9007] = "INVALID_TAG_NAME";
|
|
55
|
+
ParseErrorCode[ParseErrorCode["ELSE_WITHOUT_IF"] = 9008] = "ELSE_WITHOUT_IF";
|
|
56
|
+
ParseErrorCode[ParseErrorCode["EMPTY_IF_BODY"] = 9009] = "EMPTY_IF_BODY";
|
|
57
|
+
ParseErrorCode[ParseErrorCode["EMPTY_FOR_BODY"] = 9010] = "EMPTY_FOR_BODY";
|
|
58
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_COLLECTION"] = 9011] = "MISSING_FOR_COLLECTION";
|
|
59
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_SEMICOLON"] = 9012] = "MISSING_FOR_SEMICOLON";
|
|
60
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_ITEM"] = 9013] = "MISSING_FOR_ITEM";
|
|
61
|
+
ParseErrorCode[ParseErrorCode["PIPE_IN_WRONG_CONTEXT"] = 9014] = "PIPE_IN_WRONG_CONTEXT";
|
|
62
|
+
return ParseErrorCode;
|
|
63
|
+
}({});
|
|
47
64
|
class ParseSyntaxError extends SyntaxError {
|
|
48
65
|
constructor(code, message, loc) {
|
|
49
66
|
super(message);
|
|
@@ -161,7 +178,7 @@
|
|
|
161
178
|
const expLen = this.dentStack[i];
|
|
162
179
|
if (currLen === expLen) break;
|
|
163
180
|
if (currLen > expLen) {
|
|
164
|
-
throw
|
|
181
|
+
throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
|
|
165
182
|
}
|
|
166
183
|
if (this.shorterThanBaseDentEof()) {
|
|
167
184
|
break;
|
|
@@ -352,7 +369,7 @@
|
|
|
352
369
|
while (1) {
|
|
353
370
|
nextC = this.code[this.i + 1];
|
|
354
371
|
if (nextC === undefined) {
|
|
355
|
-
this.throwUnclosed(
|
|
372
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_STATIC_INS, '未闭合的 "${...}"', startOffset, startLine, startCol);
|
|
356
373
|
}
|
|
357
374
|
value += nextC;
|
|
358
375
|
this.next();
|
|
@@ -381,7 +398,7 @@
|
|
|
381
398
|
while (1) {
|
|
382
399
|
const char = this.code[this.i];
|
|
383
400
|
if (char === undefined) {
|
|
384
|
-
this.throwUnclosed(
|
|
401
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_BRACE, '未闭合的 "{"', startOffset, startLine, startCol);
|
|
385
402
|
}
|
|
386
403
|
const nextChar = this.code[this.i + 1];
|
|
387
404
|
if (inComment === 'single' && char === '\n') {
|
|
@@ -470,6 +487,18 @@
|
|
|
470
487
|
isEmptyLine
|
|
471
488
|
};
|
|
472
489
|
}
|
|
490
|
+
emptyLoc() {
|
|
491
|
+
const pos = this.getCurrentPos();
|
|
492
|
+
return {
|
|
493
|
+
start: pos,
|
|
494
|
+
end: {
|
|
495
|
+
offset: pos.offset + 1,
|
|
496
|
+
line: pos.line,
|
|
497
|
+
column: pos.column + 1
|
|
498
|
+
},
|
|
499
|
+
source: ' '
|
|
500
|
+
};
|
|
501
|
+
}
|
|
473
502
|
dent() {
|
|
474
503
|
const _this$getDentValue2 = this.getDentValue(),
|
|
475
504
|
value = _this$getDentValue2.value,
|
|
@@ -496,7 +525,7 @@
|
|
|
496
525
|
const expLen = this.dentStack[i];
|
|
497
526
|
if (currLen === expLen) break;
|
|
498
527
|
if (currLen > expLen) {
|
|
499
|
-
throw
|
|
528
|
+
throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
|
|
500
529
|
}
|
|
501
530
|
if (this.shorterThanBaseDentEof()) {
|
|
502
531
|
return;
|
|
@@ -574,7 +603,7 @@
|
|
|
574
603
|
while (1) {
|
|
575
604
|
nextC = this.code[this.i + 1];
|
|
576
605
|
if (nextC === undefined) {
|
|
577
|
-
this.throwUnclosed(
|
|
606
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_STRING, '未闭合的字符串字面量', startOffset, startLine, startCol);
|
|
578
607
|
}
|
|
579
608
|
const memoCount = continuousBackslashCount;
|
|
580
609
|
if (nextC === '\\') {
|
|
@@ -895,18 +924,6 @@
|
|
|
895
924
|
loc
|
|
896
925
|
});
|
|
897
926
|
}
|
|
898
|
-
emptyLoc() {
|
|
899
|
-
const pos = this.tokenizer.getCurrentPos();
|
|
900
|
-
return {
|
|
901
|
-
start: pos,
|
|
902
|
-
end: {
|
|
903
|
-
offset: pos.offset + 1,
|
|
904
|
-
line: pos.line,
|
|
905
|
-
column: pos.column + 1
|
|
906
|
-
},
|
|
907
|
-
source: ' '
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
927
|
parseProgram() {
|
|
911
928
|
const body = [];
|
|
912
929
|
try {
|
|
@@ -920,10 +937,8 @@
|
|
|
920
937
|
} catch (error) {
|
|
921
938
|
if (error instanceof ParseSyntaxError) {
|
|
922
939
|
this.addError(error.code, error.message, error.loc);
|
|
923
|
-
} else
|
|
924
|
-
|
|
925
|
-
const code = knownCodes.includes(error.message) ? error.message : 'INCONSISTENT_INDENT';
|
|
926
|
-
this.addError(code, error.message, this.emptyLoc());
|
|
940
|
+
} else {
|
|
941
|
+
this.addError(error.toString(), '未知错误', this.tokenizer.emptyLoc());
|
|
927
942
|
}
|
|
928
943
|
}
|
|
929
944
|
return {
|
|
@@ -963,7 +978,7 @@
|
|
|
963
978
|
templateNode(siblings) {
|
|
964
979
|
const token = this.tokenizer.token;
|
|
965
980
|
if (token.type & TokenType.Pipe) {
|
|
966
|
-
this.addError(
|
|
981
|
+
this.addError(ParseErrorCode.PIPE_IN_WRONG_CONTEXT, '"|" 只能出现在元素属性扩展行中', token.loc ?? this.tokenizer.emptyLoc());
|
|
967
982
|
this.tokenizer.nextToken();
|
|
968
983
|
return null;
|
|
969
984
|
}
|
|
@@ -971,12 +986,13 @@
|
|
|
971
986
|
_this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
|
|
972
987
|
hookType = _this$tokenizer$_hook2[0],
|
|
973
988
|
value = _this$tokenizer$_hook2[1];
|
|
974
|
-
|
|
975
|
-
|
|
989
|
+
const isElseOrFail = value === 'else' || value === 'fail';
|
|
990
|
+
if (value === 'if' || isElseOrFail) {
|
|
991
|
+
if (isElseOrFail) {
|
|
976
992
|
const lastSibling = siblings[siblings.length - 1];
|
|
977
993
|
const lastType = lastSibling?.type;
|
|
978
994
|
if (lastType !== NodeType.If && lastType !== NodeType.Else && lastType !== NodeType.Fail) {
|
|
979
|
-
this.addError(
|
|
995
|
+
this.addError(ParseErrorCode.ELSE_WITHOUT_IF, `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.tokenizer.emptyLoc());
|
|
980
996
|
}
|
|
981
997
|
}
|
|
982
998
|
return this.parseConditionalNode();
|
|
@@ -1004,7 +1020,7 @@
|
|
|
1004
1020
|
parseElementNode(node) {
|
|
1005
1021
|
const tagToken = this.tokenizer.token;
|
|
1006
1022
|
if (!(tagToken.type & TokenType.Identifier)) {
|
|
1007
|
-
this.addError(
|
|
1023
|
+
this.addError(ParseErrorCode.INVALID_TAG_NAME, `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.tokenizer.emptyLoc());
|
|
1008
1024
|
while (!(this.tokenizer.token.type & TokenType.NewLine) && !this.tokenizer.isEof()) {
|
|
1009
1025
|
this.tokenizer.nextToken();
|
|
1010
1026
|
}
|
|
@@ -1035,15 +1051,15 @@
|
|
|
1035
1051
|
return node;
|
|
1036
1052
|
}
|
|
1037
1053
|
parseLoopNode(node) {
|
|
1038
|
-
const forLoc = this.tokenizer.token.loc ?? this.emptyLoc();
|
|
1054
|
+
const forLoc = this.tokenizer.token.loc ?? this.tokenizer.emptyLoc();
|
|
1039
1055
|
this.tokenizer.nextToken();
|
|
1040
1056
|
const collection = this.parsePropertyValue();
|
|
1041
1057
|
if (!collection.value && collection.value !== 0) {
|
|
1042
|
-
this.addError(
|
|
1058
|
+
this.addError(ParseErrorCode.MISSING_FOR_COLLECTION, '"for" 缺少集合表达式', forLoc);
|
|
1043
1059
|
}
|
|
1044
1060
|
const semicolonToken = this.tokenizer.nextToken();
|
|
1045
1061
|
if (!(semicolonToken.type & TokenType.Semicolon)) {
|
|
1046
|
-
this.addError(
|
|
1062
|
+
this.addError(ParseErrorCode.MISSING_FOR_SEMICOLON, '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.tokenizer.emptyLoc());
|
|
1047
1063
|
}
|
|
1048
1064
|
const itemToken = this.tokenizer.nextToken();
|
|
1049
1065
|
const isDestruct = itemToken.type === TokenType.InsertionExp;
|
|
@@ -1052,7 +1068,7 @@
|
|
|
1052
1068
|
}
|
|
1053
1069
|
const item = this.parsePropertyValue();
|
|
1054
1070
|
if (!item.value && item.value !== 0) {
|
|
1055
|
-
this.addError(
|
|
1071
|
+
this.addError(ParseErrorCode.MISSING_FOR_ITEM, '"for" 缺少 item 变量名', itemToken.loc ?? this.tokenizer.emptyLoc());
|
|
1056
1072
|
}
|
|
1057
1073
|
let char = this.tokenizer.peekChar(),
|
|
1058
1074
|
key,
|
|
@@ -1117,7 +1133,7 @@
|
|
|
1117
1133
|
node.value = this.parsePropertyValue();
|
|
1118
1134
|
this.tokenizer.nextToken();
|
|
1119
1135
|
} else {
|
|
1120
|
-
this.addError(
|
|
1136
|
+
this.addError(ParseErrorCode.MISSING_ASSIGN, `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.tokenizer.emptyLoc());
|
|
1121
1137
|
}
|
|
1122
1138
|
node.loc.start = node.key.loc.start;
|
|
1123
1139
|
node.loc.end = node.value ? node.value.loc.end : node.key.loc.end;
|