@litert/typeguard 1.3.0 → 1.4.1
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/CHANGES.md +11 -1
- package/lib/BuiltInTypeCompiler.d.ts +1 -1
- package/lib/BuiltInTypeCompiler.js +4 -4
- package/lib/BuiltInTypeCompiler.js.map +1 -1
- package/lib/BuiltInTypes.d.ts +1 -1
- package/lib/BuiltInTypes.js +1 -1
- package/lib/Common.d.ts +6 -5
- package/lib/Common.d.ts.map +1 -1
- package/lib/Common.js +1 -1
- package/lib/Compiler.d.ts +1 -1
- package/lib/Compiler.d.ts.map +1 -1
- package/lib/Compiler.js +58 -36
- package/lib/Compiler.js.map +1 -1
- package/lib/Context.d.ts +2 -2
- package/lib/Context.d.ts.map +1 -1
- package/lib/Context.js +2 -2
- package/lib/Context.js.map +1 -1
- package/lib/FilterCompiler.d.ts +3 -3
- package/lib/FilterCompiler.d.ts.map +1 -1
- package/lib/FilterCompiler.js +4 -4
- package/lib/FilterCompiler.js.map +1 -1
- package/lib/InlineCompiler.d.ts +2 -2
- package/lib/InlineCompiler.d.ts.map +1 -1
- package/lib/InlineCompiler.js +5 -7
- package/lib/InlineCompiler.js.map +1 -1
- package/lib/Internal.d.ts +9 -4
- package/lib/Internal.d.ts.map +1 -1
- package/lib/Internal.js +45 -4
- package/lib/Internal.js.map +1 -1
- package/lib/Modifiers.d.ts +2 -1
- package/lib/Modifiers.d.ts.map +1 -1
- package/lib/Modifiers.js +3 -2
- package/lib/Modifiers.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/langs/JavaScript.d.ts +1 -1
- package/lib/langs/JavaScript.js +2 -2
- package/package.json +10 -12
- package/src/examples/quick-start.ts +5 -1
- package/src/lib/BuiltInTypeCompiler.ts +4 -4
- package/src/lib/BuiltInTypes.ts +1 -1
- package/src/lib/Common.ts +5 -4
- package/src/lib/Compiler.ts +67 -40
- package/src/lib/Context.ts +2 -2
- package/src/lib/FilterCompiler.ts +3 -3
- package/src/lib/InlineCompiler.ts +6 -9
- package/src/lib/Internal.ts +73 -4
- package/src/lib/Modifiers.ts +3 -1
- package/src/lib/index.ts +1 -1
- package/src/lib/langs/JavaScript.ts +2 -2
- package/src/test/00-all.ts +0 -35
- package/src/test/01-elemental-types.ts +0 -1963
- package/src/test/02-array-and-list.ts +0 -197
- package/src/test/03-tuple.ts +0 -220
- package/src/test/04-from-string.ts +0 -1488
- package/src/test/05-string-asserts.ts +0 -794
- package/src/test/06-structure.ts +0 -277
- package/src/test/07-modifiers.ts +0 -220
- package/src/test/08-map-and-dict.ts +0 -151
- package/src/test/09-exceptions.ts +0 -67
- package/src/test/abstracts.ts +0 -211
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litert/typeguard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "An easy and powerful data validation code generator by JavaScript.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -34,18 +34,16 @@
|
|
|
34
34
|
"types": "lib/index.d.ts",
|
|
35
35
|
"typings": "lib/index.d.ts",
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@commitlint/cli": "^17.
|
|
38
|
-
"@commitlint/config-conventional": "^17.
|
|
39
|
-
"@
|
|
40
|
-
"@types/
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"mocha": "^10.0.0",
|
|
46
|
-
"typescript": "^4.7.4"
|
|
37
|
+
"@commitlint/cli": "^17.6.5",
|
|
38
|
+
"@commitlint/config-conventional": "^17.6.5",
|
|
39
|
+
"@litert/eslint-plugin-rules": "^0.1.3",
|
|
40
|
+
"@types/mocha": "^10.0.1",
|
|
41
|
+
"@types/node": "^20.3.1",
|
|
42
|
+
"husky": "^8.0.3",
|
|
43
|
+
"mocha": "^10.2.0",
|
|
44
|
+
"typescript": "~5.0.0"
|
|
47
45
|
},
|
|
48
46
|
"engines": {
|
|
49
|
-
"node": ">=
|
|
47
|
+
"node": ">=14.0.0"
|
|
50
48
|
}
|
|
51
49
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -170,3 +170,7 @@ executeTest(
|
|
|
170
170
|
{ 'a': '123312312', 'b': 'ccc' },
|
|
171
171
|
]
|
|
172
172
|
);
|
|
173
|
+
|
|
174
|
+
console.log(tgc.compile({
|
|
175
|
+
rule: '@enum(1, 2, 3, "ss\\"")',
|
|
176
|
+
}).toString());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -502,7 +502,7 @@ implements I.IBuiltInTypeCompiler {
|
|
|
502
502
|
}
|
|
503
503
|
case B.STRUCT: {
|
|
504
504
|
|
|
505
|
-
return this._lang.
|
|
505
|
+
return this._lang.isStructure(ctx.vName, true);
|
|
506
506
|
}
|
|
507
507
|
case B.NUMERIC: {
|
|
508
508
|
|
|
@@ -738,7 +738,7 @@ implements I.IBuiltInTypeCompiler {
|
|
|
738
738
|
|
|
739
739
|
if (fromString) {
|
|
740
740
|
|
|
741
|
-
ctx.
|
|
741
|
+
ctx.popUp();
|
|
742
742
|
|
|
743
743
|
return this._lang.and([
|
|
744
744
|
this._lang.or([
|
|
@@ -891,7 +891,7 @@ implements I.IBuiltInTypeCompiler {
|
|
|
891
891
|
|
|
892
892
|
if (fromString) {
|
|
893
893
|
|
|
894
|
-
ctx.
|
|
894
|
+
ctx.popUp();
|
|
895
895
|
|
|
896
896
|
return this._lang.and([
|
|
897
897
|
this._lang.or([
|
package/src/lib/BuiltInTypes.ts
CHANGED
package/src/lib/Common.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
export type ITypeChecker<T> = (v: unknown, errorTraces?: string[]) => v is T;
|
|
18
|
+
export type IPreDefinedTypeChecker<T> = (v: unknown, ...args: any[]) => v is T;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* @deprecated Use `ITypeChecker` instead.
|
|
@@ -167,7 +168,7 @@ export interface ILanguageBuilder {
|
|
|
167
168
|
*/
|
|
168
169
|
modOf(a: string, b: string): string;
|
|
169
170
|
|
|
170
|
-
literal(val: string | boolean | number): string;
|
|
171
|
+
literal(val: string | boolean | number | null): string;
|
|
171
172
|
|
|
172
173
|
/**
|
|
173
174
|
* Get the statement checking if a string expression includes a given
|
|
@@ -249,7 +250,7 @@ export interface ILanguageBuilder {
|
|
|
249
250
|
* @param expr The expression to be checked.
|
|
250
251
|
* @param positive Assert positive or negative.
|
|
251
252
|
*/
|
|
252
|
-
|
|
253
|
+
isStructure(expr: string, positive: boolean): string;
|
|
253
254
|
|
|
254
255
|
/**
|
|
255
256
|
* Get the statement checking if an expression is an integer value.
|
|
@@ -306,7 +307,7 @@ export interface ILanguageBuilder {
|
|
|
306
307
|
stringLength(expr: string): string;
|
|
307
308
|
|
|
308
309
|
/**
|
|
309
|
-
* Get the statement of the keys list of an
|
|
310
|
+
* Get the statement of the keys list of an dictionary.
|
|
310
311
|
*
|
|
311
312
|
* @param expr The expression of dictionary.
|
|
312
313
|
*/
|
package/src/lib/Compiler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -215,7 +215,7 @@ class Compiler implements C.ICompiler {
|
|
|
215
215
|
break;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
throw new TypeError('
|
|
218
|
+
throw new TypeError('Unknown rules.');
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
private _compileStringRule(ctx: I.IContext, rule: string): string {
|
|
@@ -313,7 +313,7 @@ class Compiler implements C.ICompiler {
|
|
|
313
313
|
]);
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
if (rule.startsWith(I.
|
|
316
|
+
if (rule.startsWith(I.PRE_DEF_TYPE_SYMBOL)) {
|
|
317
317
|
|
|
318
318
|
return this._usePredefinedType(ctx, rule.slice(1));
|
|
319
319
|
}
|
|
@@ -360,19 +360,20 @@ class Compiler implements C.ICompiler {
|
|
|
360
360
|
|
|
361
361
|
private _usePredefinedType(
|
|
362
362
|
ctx: I.IContext,
|
|
363
|
-
|
|
363
|
+
typeExpr: string
|
|
364
364
|
): string {
|
|
365
365
|
|
|
366
|
-
|
|
366
|
+
const expr = I.decodePreDefinedCallExpr(typeExpr);
|
|
367
367
|
|
|
368
|
-
ctx.referredTypes[
|
|
368
|
+
ctx.referredTypes[expr.name] = true;
|
|
369
369
|
|
|
370
370
|
return this._lang.call(
|
|
371
371
|
this._lang.fieldIndex(
|
|
372
372
|
ctx.typeSlotName,
|
|
373
|
-
this._lang.literal(
|
|
373
|
+
this._lang.literal(expr.name)
|
|
374
374
|
),
|
|
375
|
-
ctx.vName
|
|
375
|
+
ctx.vName,
|
|
376
|
+
...expr.args.map(i => this._lang.literal(i))
|
|
376
377
|
);
|
|
377
378
|
}
|
|
378
379
|
|
|
@@ -383,7 +384,7 @@ class Compiler implements C.ICompiler {
|
|
|
383
384
|
|
|
384
385
|
const assertRule = /^:([-\w]+):/.exec(rule);
|
|
385
386
|
|
|
386
|
-
const offset = assertRule
|
|
387
|
+
const offset = (assertRule?.[1]?.length ?? 0) + 2;
|
|
387
388
|
|
|
388
389
|
switch ((assertRule?.[1]) ?? rule.slice(0, 2)) {
|
|
389
390
|
case '==':
|
|
@@ -546,7 +547,7 @@ class Compiler implements C.ICompiler {
|
|
|
546
547
|
|
|
547
548
|
if (!rules.length) {
|
|
548
549
|
|
|
549
|
-
throw new TypeError('
|
|
550
|
+
throw new TypeError('Unknown type "[]".');
|
|
550
551
|
}
|
|
551
552
|
|
|
552
553
|
/**
|
|
@@ -617,6 +618,10 @@ class Compiler implements C.ICompiler {
|
|
|
617
618
|
|
|
618
619
|
return this._compileModifierTYPE(ctx, rules.slice(1));
|
|
619
620
|
}
|
|
621
|
+
case M.ENUM: {
|
|
622
|
+
|
|
623
|
+
return this._compileModifierEnum(ctx, rules.slice(1));
|
|
624
|
+
}
|
|
620
625
|
}
|
|
621
626
|
|
|
622
627
|
throw new TypeError(`Unknown modifier "${rules[0]}".`);
|
|
@@ -630,7 +635,7 @@ class Compiler implements C.ICompiler {
|
|
|
630
635
|
|
|
631
636
|
const result = this._compileModifiedRule(ctx, rules);
|
|
632
637
|
|
|
633
|
-
ctx.
|
|
638
|
+
ctx.popUp();
|
|
634
639
|
|
|
635
640
|
return result;
|
|
636
641
|
}
|
|
@@ -645,7 +650,7 @@ class Compiler implements C.ICompiler {
|
|
|
645
650
|
|
|
646
651
|
result.push(this._compile(ctx, r));
|
|
647
652
|
|
|
648
|
-
ctx.
|
|
653
|
+
ctx.popUp();
|
|
649
654
|
}
|
|
650
655
|
|
|
651
656
|
return this._lang.or(result);
|
|
@@ -687,6 +692,7 @@ class Compiler implements C.ICompiler {
|
|
|
687
692
|
[CLOSURE_PARAM],
|
|
688
693
|
[CLOSURE_ARG],
|
|
689
694
|
this._lang.series([
|
|
695
|
+
// eslint-disable-next-line @litert/rules/disable-for-each-method
|
|
690
696
|
this._lang.forEach(
|
|
691
697
|
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
692
698
|
this._lang.not(this._compile(ctx, rules)),
|
|
@@ -698,7 +704,7 @@ class Compiler implements C.ICompiler {
|
|
|
698
704
|
));
|
|
699
705
|
}
|
|
700
706
|
|
|
701
|
-
ctx.
|
|
707
|
+
ctx.popUp();
|
|
702
708
|
|
|
703
709
|
return this._lang.and(result);
|
|
704
710
|
}
|
|
@@ -819,6 +825,7 @@ class Compiler implements C.ICompiler {
|
|
|
819
825
|
[CLOSURE_PARAM],
|
|
820
826
|
[CLOSURE_ARG],
|
|
821
827
|
this._lang.series([
|
|
828
|
+
// eslint-disable-next-line @litert/rules/disable-for-each-method
|
|
822
829
|
this._lang.forEach(
|
|
823
830
|
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
824
831
|
this._lang.not(this._compile(ctx, rules.slice(1))),
|
|
@@ -830,7 +837,7 @@ class Compiler implements C.ICompiler {
|
|
|
830
837
|
));
|
|
831
838
|
}
|
|
832
839
|
|
|
833
|
-
ctx.
|
|
840
|
+
ctx.popUp();
|
|
834
841
|
|
|
835
842
|
return this._lang.and(result);
|
|
836
843
|
}
|
|
@@ -946,7 +953,7 @@ class Compiler implements C.ICompiler {
|
|
|
946
953
|
tupleLength++;
|
|
947
954
|
}
|
|
948
955
|
|
|
949
|
-
ctx.
|
|
956
|
+
ctx.popUp();
|
|
950
957
|
}
|
|
951
958
|
|
|
952
959
|
if (tupleLength >= 0) {
|
|
@@ -975,23 +982,13 @@ class Compiler implements C.ICompiler {
|
|
|
975
982
|
return this._lang.and(result);
|
|
976
983
|
}
|
|
977
984
|
|
|
978
|
-
private _validateTypeName(name: unknown): void {
|
|
979
|
-
|
|
980
|
-
if (typeof name !== 'string' || !I.RE_VALID_CUSTOM_TYPE_NAME.test(name)) {
|
|
981
|
-
|
|
982
|
-
throw new TypeError(`Invalid name ${
|
|
983
|
-
JSON.stringify(name)
|
|
984
|
-
} for a pre-defined type.`);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
|
|
988
985
|
private _compileModifierTYPE(ctx: I.IContext, rules: any[]): string {
|
|
989
986
|
|
|
990
|
-
|
|
987
|
+
I.validateTypeName(rules[0]);
|
|
991
988
|
|
|
992
989
|
if (this._defTypes[rules[0]]) {
|
|
993
990
|
|
|
994
|
-
throw new Error(`
|
|
991
|
+
throw new Error(`Duplicated name ${JSON.stringify(rules[0])} for a pre-defined type.`);
|
|
995
992
|
}
|
|
996
993
|
|
|
997
994
|
this._defTypes[rules[0]] = this.compile({
|
|
@@ -1015,7 +1012,7 @@ class Compiler implements C.ICompiler {
|
|
|
1015
1012
|
|
|
1016
1013
|
const ret = this._compile(ctx, rules);
|
|
1017
1014
|
|
|
1018
|
-
ctx.
|
|
1015
|
+
ctx.popUp();
|
|
1019
1016
|
|
|
1020
1017
|
return ret;
|
|
1021
1018
|
}
|
|
@@ -1033,7 +1030,7 @@ class Compiler implements C.ICompiler {
|
|
|
1033
1030
|
|
|
1034
1031
|
const ret = this._compile(ctx, rules);
|
|
1035
1032
|
|
|
1036
|
-
ctx.
|
|
1033
|
+
ctx.popUp();
|
|
1037
1034
|
|
|
1038
1035
|
return ret;
|
|
1039
1036
|
}
|
|
@@ -1057,7 +1054,7 @@ class Compiler implements C.ICompiler {
|
|
|
1057
1054
|
ctx.tracePath = `${ctx.tracePath}[${this._lang.stringTemplateVar(vKey)}]`;
|
|
1058
1055
|
|
|
1059
1056
|
const result = this._lang.and([
|
|
1060
|
-
this._lang.
|
|
1057
|
+
this._lang.isStructure(vCArg, true),
|
|
1061
1058
|
this._lang.closure(
|
|
1062
1059
|
[vCParam],
|
|
1063
1060
|
[vCArg],
|
|
@@ -1073,11 +1070,41 @@ class Compiler implements C.ICompiler {
|
|
|
1073
1070
|
)
|
|
1074
1071
|
]);
|
|
1075
1072
|
|
|
1076
|
-
ctx.
|
|
1073
|
+
ctx.popUp();
|
|
1077
1074
|
|
|
1078
1075
|
return result;
|
|
1079
1076
|
}
|
|
1080
1077
|
|
|
1078
|
+
private _compileModifierEnum(ctx: I.IContext, rules: any[]): string {
|
|
1079
|
+
|
|
1080
|
+
if (rules.length === 0) {
|
|
1081
|
+
|
|
1082
|
+
throw new SyntaxError(`At least one enum candidate is required for $.enum`);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
const ret: string[] = [];
|
|
1086
|
+
|
|
1087
|
+
for (const r of rules) {
|
|
1088
|
+
|
|
1089
|
+
switch (typeof r) {
|
|
1090
|
+
|
|
1091
|
+
case 'string':
|
|
1092
|
+
case 'number':
|
|
1093
|
+
case 'boolean':
|
|
1094
|
+
ret.push(this._lang.eq(ctx.vName, this._lang.literal(r)));
|
|
1095
|
+
break;
|
|
1096
|
+
default:
|
|
1097
|
+
if (r === null) {
|
|
1098
|
+
ret.push(this._lang.eq(ctx.vName, this._lang.literal(null)));
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
throw new SyntaxError(`Invalid literal value ${JSON.stringify(rules)} for $.enum.`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
return this._lang.or(ret);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1081
1108
|
private _compileModifierDICT(ctx: I.IContext, rules: any[]): string {
|
|
1082
1109
|
|
|
1083
1110
|
if (rules.length < 2 || !Array.isArray(rules[0])) {
|
|
@@ -1094,7 +1121,7 @@ class Compiler implements C.ICompiler {
|
|
|
1094
1121
|
rules.slice(1)
|
|
1095
1122
|
]);
|
|
1096
1123
|
|
|
1097
|
-
const type = `${I.
|
|
1124
|
+
const type = `${I.PRE_DEF_TYPE_SYMBOL}${this._lang.varName(id)}`;
|
|
1098
1125
|
|
|
1099
1126
|
for (const key of rules[0]) {
|
|
1100
1127
|
|
|
@@ -1119,7 +1146,7 @@ class Compiler implements C.ICompiler {
|
|
|
1119
1146
|
const result: string[] = [
|
|
1120
1147
|
this._addTraceOr(
|
|
1121
1148
|
ctx,
|
|
1122
|
-
this._lang.
|
|
1149
|
+
this._lang.isStructure(ctx.vName, true),
|
|
1123
1150
|
'!object'
|
|
1124
1151
|
)
|
|
1125
1152
|
];
|
|
@@ -1212,10 +1239,10 @@ class Compiler implements C.ICompiler {
|
|
|
1212
1239
|
this._compile(ctx, rule)
|
|
1213
1240
|
));
|
|
1214
1241
|
|
|
1215
|
-
ctx.
|
|
1242
|
+
ctx.popUp();
|
|
1216
1243
|
}
|
|
1217
1244
|
|
|
1218
|
-
if (strict
|
|
1245
|
+
if (strict) {
|
|
1219
1246
|
|
|
1220
1247
|
result.splice(
|
|
1221
1248
|
1,
|
|
@@ -1247,7 +1274,7 @@ class Compiler implements C.ICompiler {
|
|
|
1247
1274
|
}
|
|
1248
1275
|
|
|
1249
1276
|
const result: string[] = [
|
|
1250
|
-
this._lang.
|
|
1277
|
+
this._lang.isStructure(ctx.vName, true)
|
|
1251
1278
|
];
|
|
1252
1279
|
|
|
1253
1280
|
ctx.trap();
|
|
@@ -1364,7 +1391,7 @@ class Compiler implements C.ICompiler {
|
|
|
1364
1391
|
));
|
|
1365
1392
|
}
|
|
1366
1393
|
|
|
1367
|
-
ctx.
|
|
1394
|
+
ctx.popUp();
|
|
1368
1395
|
}
|
|
1369
1396
|
|
|
1370
1397
|
if (keys.length) {
|
|
@@ -1389,7 +1416,7 @@ class Compiler implements C.ICompiler {
|
|
|
1389
1416
|
])
|
|
1390
1417
|
));
|
|
1391
1418
|
|
|
1392
|
-
ctx.
|
|
1419
|
+
ctx.popUp();
|
|
1393
1420
|
|
|
1394
1421
|
return this._lang.and(result);
|
|
1395
1422
|
}
|
|
@@ -1411,9 +1438,9 @@ class Compiler implements C.ICompiler {
|
|
|
1411
1438
|
*/
|
|
1412
1439
|
export function createCompiler(lang: C.ILanguageBuilder): C.ICompiler {
|
|
1413
1440
|
|
|
1414
|
-
const
|
|
1441
|
+
const ret = new BuiltInTypeCompiler(lang);
|
|
1415
1442
|
|
|
1416
1443
|
return new Compiler(
|
|
1417
|
-
lang,
|
|
1444
|
+
lang, ret, new FilterCompiler(lang, ret)
|
|
1418
1445
|
);
|
|
1419
1446
|
}
|
package/src/lib/Context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -71,7 +71,7 @@ export class Context implements i.IContext {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
public
|
|
74
|
+
public popUp(): void {
|
|
75
75
|
|
|
76
76
|
const prev = this.stack.pop();
|
|
77
77
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -22,7 +22,7 @@ implements I.IFilterCompiler {
|
|
|
22
22
|
|
|
23
23
|
public constructor(
|
|
24
24
|
private readonly _lang: C.ILanguageBuilder,
|
|
25
|
-
private readonly
|
|
25
|
+
private readonly _memCompiler: I.IBuiltInTypeCompiler
|
|
26
26
|
) {}
|
|
27
27
|
|
|
28
28
|
public compile(rule: string, ctx: I.IContext): string {
|
|
@@ -51,7 +51,7 @@ implements I.IFilterCompiler {
|
|
|
51
51
|
ret.push(this._lang.isNumber(vName, true));
|
|
52
52
|
break;
|
|
53
53
|
default:
|
|
54
|
-
ret.push(this.
|
|
54
|
+
ret.push(this._memCompiler.compile(filter[0], ctx, []));
|
|
55
55
|
break;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -50,7 +50,7 @@ export interface IInlineCompiler {
|
|
|
50
50
|
* @param name The name of the pre-defined type (without prefix `@`)
|
|
51
51
|
* @param checker The checker callback of the pre-defined type.
|
|
52
52
|
*/
|
|
53
|
-
addPredefinedType<T>(name: string, checker: C.
|
|
53
|
+
addPredefinedType<T>(name: string, checker: C.IPreDefinedTypeChecker<T>): this;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Check if a pre-defined type is compiled.
|
|
@@ -91,12 +91,12 @@ implements IInlineCompiler {
|
|
|
91
91
|
|
|
92
92
|
const result = this._compiler.compile(options);
|
|
93
93
|
|
|
94
|
-
this.
|
|
94
|
+
this._prepareDefinedTypes(result.referredTypes, options.stopOnEntry);
|
|
95
95
|
|
|
96
96
|
return this._wrapCheckerCode(result, options.stopOnEntry);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
private
|
|
99
|
+
private _prepareDefinedTypes(
|
|
100
100
|
types: string[],
|
|
101
101
|
stopOnEntry?: boolean
|
|
102
102
|
): void {
|
|
@@ -118,7 +118,7 @@ implements IInlineCompiler {
|
|
|
118
118
|
|
|
119
119
|
this._defTypes[x] = this._wrapCheckerCode(info, stopOnEntry);
|
|
120
120
|
|
|
121
|
-
this.
|
|
121
|
+
this._prepareDefinedTypes(info.referredTypes);
|
|
122
122
|
|
|
123
123
|
delete this._missingTypes[x];
|
|
124
124
|
}
|
|
@@ -126,10 +126,7 @@ implements IInlineCompiler {
|
|
|
126
126
|
|
|
127
127
|
public addPredefinedType(name: string, checker: C.ITypeChecker<any>): this {
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
throw new TypeError(`Invalid name ${ JSON.stringify(name) } for a pre-defined type.`);
|
|
132
|
-
}
|
|
129
|
+
I.validateTypeName(name);
|
|
133
130
|
|
|
134
131
|
this._defTypes[name] = checker;
|
|
135
132
|
|
package/src/lib/Internal.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -24,7 +24,7 @@ export const FILTER_PREFIX = '|';
|
|
|
24
24
|
|
|
25
25
|
export const IMPLICIT_SYMBOL = '?';
|
|
26
26
|
|
|
27
|
-
export const
|
|
27
|
+
export const PRE_DEF_TYPE_SYMBOL = '@';
|
|
28
28
|
|
|
29
29
|
export const NEGATIVE_SYMBOL = '!';
|
|
30
30
|
|
|
@@ -95,7 +95,7 @@ export interface IContext extends IContextData {
|
|
|
95
95
|
|
|
96
96
|
trap(subjChanged?: boolean): void;
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
popUp(): void;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
export interface IFilterCompiler {
|
|
@@ -126,4 +126,73 @@ export interface IBuiltInTypeCompiler {
|
|
|
126
126
|
isElemental(type: string): boolean;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
const RE_VALID_CUSTOM_TYPE_NAME = /^[-:.\w]+$/;
|
|
130
|
+
|
|
131
|
+
export interface IPreDefinedCallExpr {
|
|
132
|
+
|
|
133
|
+
name: string;
|
|
134
|
+
|
|
135
|
+
args: any[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function validateTypeName(name: string): void {
|
|
139
|
+
|
|
140
|
+
if (typeof name !== 'string' || !RE_VALID_CUSTOM_TYPE_NAME.test(name)) {
|
|
141
|
+
|
|
142
|
+
throw new TypeError(`Invalid name ${
|
|
143
|
+
JSON.stringify(name)
|
|
144
|
+
} for a pre-defined type.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function decodePreDefinedCallExpr(input: string): IPreDefinedCallExpr {
|
|
149
|
+
|
|
150
|
+
let expr = input;
|
|
151
|
+
|
|
152
|
+
expr = expr.replace(/\\['"]/g, (i) => `\\u00${i.charCodeAt(1).toString(16)}`);
|
|
153
|
+
|
|
154
|
+
const r = /^([-:.\w]+)\s*(\((.*)\))?$/.exec(expr);
|
|
155
|
+
|
|
156
|
+
if (!r) {
|
|
157
|
+
|
|
158
|
+
throw new SyntaxError(`Invalid type expression: ${input}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const fn = r[1];
|
|
162
|
+
|
|
163
|
+
expr = r[3];
|
|
164
|
+
|
|
165
|
+
if (!expr) {
|
|
166
|
+
|
|
167
|
+
return { name: fn, args: [] };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const args = [];
|
|
171
|
+
|
|
172
|
+
while (expr) {
|
|
173
|
+
|
|
174
|
+
const m = /^\s*([-]?\d+(\.\d+)?|[-]?0x[a-fA-F0-9]+|true|false|null|"[^"]+"|'[^']+')\s*(,|$)/i.exec(expr);
|
|
175
|
+
|
|
176
|
+
if (!m) {
|
|
177
|
+
|
|
178
|
+
throw new SyntaxError(`Invalid type expression "${expr}" in "${input}"`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
expr = expr.slice(m[0].length);
|
|
182
|
+
|
|
183
|
+
if (m[1].startsWith("'") && m[1].endsWith("'")) {
|
|
184
|
+
args.push(JSON.parse(`"${m[1].slice(1, -1)}"`));
|
|
185
|
+
}
|
|
186
|
+
else if (m[1].startsWith('0x')) {
|
|
187
|
+
args.push(parseInt(m[1].slice(2), 16));
|
|
188
|
+
}
|
|
189
|
+
else if (m[1].startsWith('-0x')) {
|
|
190
|
+
args.push(-parseInt(m[1].slice(3), 16));
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
args.push(JSON.parse(m[1]));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { name: fn, args };
|
|
198
|
+
}
|
package/src/lib/Modifiers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -43,3 +43,5 @@ export const EQUAL: string = `${I.MODIFIER_PREFIX}equal`;
|
|
|
43
43
|
export const TAG: string = `${I.MODIFIER_PREFIX}tag`;
|
|
44
44
|
|
|
45
45
|
export const TYPE: string = `${I.MODIFIER_PREFIX}type`;
|
|
46
|
+
|
|
47
|
+
export const ENUM: string = `${I.MODIFIER_PREFIX}enum`;
|
package/src/lib/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2023 Angus Fenying <fenying@litert.org>
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -227,7 +227,7 @@ implements C.ILanguageBuilder {
|
|
|
227
227
|
return `typeof ${vn} ${this._equal(positive)} "string"`;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
public
|
|
230
|
+
public isStructure(vn: string, positive: boolean = true): string {
|
|
231
231
|
|
|
232
232
|
return positive ?
|
|
233
233
|
`(typeof ${vn} === "object" && ${vn} !== null && !Array.isArray(${vn}))` :
|