@litert/typeguard 1.2.0 → 1.3.0-dev.0
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 +5 -0
- package/lib/Common.d.ts +15 -2
- package/lib/Common.d.ts.map +1 -1
- package/lib/Compiler.d.ts.map +1 -1
- package/lib/Compiler.js +85 -33
- package/lib/Compiler.js.map +1 -1
- package/lib/Context.d.ts +4 -3
- package/lib/Context.d.ts.map +1 -1
- package/lib/Context.js +8 -5
- package/lib/Context.js.map +1 -1
- package/lib/InlineCompiler.d.ts.map +1 -1
- package/lib/InlineCompiler.js +4 -1
- package/lib/InlineCompiler.js.map +1 -1
- package/lib/Internal.d.ts +4 -3
- package/lib/Internal.d.ts.map +1 -1
- package/lib/Internal.js.map +1 -1
- package/lib/langs/JavaScript.d.ts.map +1 -1
- package/lib/langs/JavaScript.js +27 -2
- package/lib/langs/JavaScript.js.map +1 -1
- package/package.json +8 -8
- package/src/examples/quick-start.ts +117 -1
- package/src/lib/Common.ts +35 -1
- package/src/lib/Compiler.ts +143 -41
- package/src/lib/Context.ts +8 -10
- package/src/lib/InlineCompiler.ts +6 -1
- package/src/lib/Internal.ts +5 -3
- package/src/lib/langs/JavaScript.ts +56 -3
- package/src/test/abstracts.ts +33 -4
package/src/lib/Compiler.ts
CHANGED
|
@@ -22,8 +22,7 @@ import * as B from './BuiltInTypes';
|
|
|
22
22
|
import { BuiltInTypeCompiler } from './BuiltInTypeCompiler';
|
|
23
23
|
import { FilterCompiler } from './FilterCompiler';
|
|
24
24
|
|
|
25
|
-
class Compiler
|
|
26
|
-
implements C.ICompiler {
|
|
25
|
+
class Compiler implements C.ICompiler {
|
|
27
26
|
|
|
28
27
|
private _defTypes: Record<string, C.ICompileResult>;
|
|
29
28
|
|
|
@@ -45,12 +44,43 @@ implements C.ICompiler {
|
|
|
45
44
|
return null;
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
private _addTrace(ctx: I.IContext): string {
|
|
48
|
+
|
|
49
|
+
if (!ctx.vTraceName) {
|
|
50
|
+
|
|
51
|
+
return this._lang.literalFalse;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this._lang.addTrace(
|
|
55
|
+
ctx.vTraceName,
|
|
56
|
+
ctx.vTracePrefix,
|
|
57
|
+
ctx.tracePath
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private _addTraceOr(ctx: I.IContext, expr: string, subPath: string = ''): string {
|
|
62
|
+
|
|
63
|
+
if (!ctx.vTraceName) {
|
|
64
|
+
|
|
65
|
+
return expr;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this._lang.orAddTrace(
|
|
69
|
+
expr,
|
|
70
|
+
ctx.vTraceName,
|
|
71
|
+
ctx.vTracePrefix,
|
|
72
|
+
`${ctx.tracePath}${subPath}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
48
76
|
public compile(options: C.ICompileOptions): C.ICompileResult {
|
|
49
77
|
|
|
50
78
|
const referredTypes: Record<string, true> = {};
|
|
51
79
|
|
|
52
80
|
const ctx: I.IContext = new Context(
|
|
53
81
|
this._lang.varName('entry'),
|
|
82
|
+
options.traceErrors ? this._lang.varName('failedAsserts') : '',
|
|
83
|
+
options.traceErrors ? this._lang.varName('tracePrefix') : '',
|
|
54
84
|
this._lang.varName('types'),
|
|
55
85
|
referredTypes
|
|
56
86
|
);
|
|
@@ -71,12 +101,28 @@ implements C.ICompiler {
|
|
|
71
101
|
source: '',
|
|
72
102
|
arguments: [{
|
|
73
103
|
'name': ctx.vName,
|
|
74
|
-
'type': 'unknown'
|
|
104
|
+
'type': 'unknown',
|
|
105
|
+
'initial': ''
|
|
75
106
|
}],
|
|
76
107
|
typeSlotName: ctx.typeSlotName,
|
|
77
108
|
referredTypes: []
|
|
78
109
|
};
|
|
79
110
|
|
|
111
|
+
if (ctx.vTraceName) {
|
|
112
|
+
|
|
113
|
+
ret.arguments.push({
|
|
114
|
+
'name': ctx.vTraceName,
|
|
115
|
+
'type': 'string[]',
|
|
116
|
+
'initial': '[]'
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
ret.arguments.push({
|
|
120
|
+
'name': ctx.vTracePrefix,
|
|
121
|
+
'type': 'string',
|
|
122
|
+
'initial': this._lang.literal('data')
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
80
126
|
ret.source = this._compile(
|
|
81
127
|
ctx,
|
|
82
128
|
options.rule
|
|
@@ -200,7 +246,7 @@ implements C.ICompiler {
|
|
|
200
246
|
let regResult: RegExpMatchArray | null = /\[\s*(\d*|\d+\s*,\s*\d*)\s*\]$/.exec(rule);
|
|
201
247
|
|
|
202
248
|
/**
|
|
203
|
-
* For rules like `xxx[123]` or `xxx[1,5]`.
|
|
249
|
+
* For rules like `xxx[123]` or `xxx[1,5]` or `xxx[1,]`.
|
|
204
250
|
*/
|
|
205
251
|
if (regResult) {
|
|
206
252
|
|
|
@@ -210,43 +256,55 @@ implements C.ICompiler {
|
|
|
210
256
|
|
|
211
257
|
if (range.length === 1) {
|
|
212
258
|
|
|
259
|
+
/**
|
|
260
|
+
* For rules like `xxx[123]`.
|
|
261
|
+
*/
|
|
213
262
|
return this._compileModifiedRule(ctx, [
|
|
214
263
|
M.ARRAY,
|
|
215
264
|
range[0],
|
|
216
|
-
rule.
|
|
265
|
+
rule.slice(0, regResult.index)
|
|
217
266
|
]);
|
|
218
267
|
}
|
|
219
268
|
else if (Number.isNaN(range[1])) {
|
|
220
269
|
|
|
270
|
+
/**
|
|
271
|
+
* For rules like `xxx[1,]`.
|
|
272
|
+
*/
|
|
221
273
|
return this._compileModifiedRule(ctx, [
|
|
222
274
|
M.ARRAY,
|
|
223
275
|
[range[0]],
|
|
224
|
-
rule.
|
|
276
|
+
rule.slice(0, regResult.index)
|
|
225
277
|
]);
|
|
226
278
|
}
|
|
227
279
|
else {
|
|
228
280
|
|
|
281
|
+
/**
|
|
282
|
+
* For rules like `xxx[1,5]`.
|
|
283
|
+
*/
|
|
229
284
|
return this._compileModifiedRule(ctx, [
|
|
230
285
|
M.ARRAY,
|
|
231
286
|
range,
|
|
232
|
-
rule.
|
|
287
|
+
rule.slice(0, regResult.index)
|
|
233
288
|
]);
|
|
234
289
|
}
|
|
235
290
|
}
|
|
236
291
|
else {
|
|
237
292
|
|
|
293
|
+
/**
|
|
294
|
+
* For rules like `xxx[]`.
|
|
295
|
+
*/
|
|
238
296
|
return this._compileModifiedRule(ctx, [
|
|
239
297
|
M.LIST,
|
|
240
|
-
rule.
|
|
298
|
+
rule.slice(0, regResult.index)
|
|
241
299
|
]);
|
|
242
300
|
}
|
|
243
301
|
}
|
|
244
302
|
|
|
245
|
-
/**
|
|
246
|
-
* For rules like `xxx{}`.
|
|
247
|
-
*/
|
|
248
303
|
if (rule.endsWith(I.MAP_SUFFIX)) {
|
|
249
304
|
|
|
305
|
+
/**
|
|
306
|
+
* For rules like `xxx{}`.
|
|
307
|
+
*/
|
|
250
308
|
return this._lang.and([
|
|
251
309
|
this._compileModifiedRule(ctx, [
|
|
252
310
|
M.MAP,
|
|
@@ -327,7 +385,7 @@ implements C.ICompiler {
|
|
|
327
385
|
|
|
328
386
|
const offset = assertRule ? assertRule[1].length + 2 : 2;
|
|
329
387
|
|
|
330
|
-
switch ((assertRule?.[1]) ?? rule.
|
|
388
|
+
switch ((assertRule?.[1]) ?? rule.slice(0, 2)) {
|
|
331
389
|
case '==':
|
|
332
390
|
case 'equal':
|
|
333
391
|
|
|
@@ -600,7 +658,7 @@ implements C.ICompiler {
|
|
|
600
658
|
);
|
|
601
659
|
}
|
|
602
660
|
|
|
603
|
-
private _compileModifierLIST(ctx: I.IContext, rules: any[]): string {
|
|
661
|
+
private _compileModifierLIST(ctx: I.IContext, rules: any[], traceOffset: number = 0): string {
|
|
604
662
|
|
|
605
663
|
const result: string[] = [];
|
|
606
664
|
|
|
@@ -618,6 +676,10 @@ implements C.ICompiler {
|
|
|
618
676
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
619
677
|
|
|
620
678
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
679
|
+
const vIter = this._lang.varName(ctx.vCursor++);
|
|
680
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.numberTemplateVar(
|
|
681
|
+
traceOffset ? this._lang.add(traceOffset, vIter) : vIter
|
|
682
|
+
)}]`;
|
|
621
683
|
|
|
622
684
|
if (rules[0] !== B.ANY) {
|
|
623
685
|
|
|
@@ -626,9 +688,9 @@ implements C.ICompiler {
|
|
|
626
688
|
[CLOSURE_ARG],
|
|
627
689
|
this._lang.series([
|
|
628
690
|
this._lang.forEach(
|
|
629
|
-
CLOSURE_PARAM, ctx.vName, this._lang.ifThen(
|
|
691
|
+
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
630
692
|
this._lang.not(this._compile(ctx, rules)),
|
|
631
|
-
this._lang.returnValue(this.
|
|
693
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
632
694
|
)
|
|
633
695
|
),
|
|
634
696
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -641,7 +703,7 @@ implements C.ICompiler {
|
|
|
641
703
|
return this._lang.and(result);
|
|
642
704
|
}
|
|
643
705
|
|
|
644
|
-
private _compileModifierARRAY(ctx: I.IContext, rules: any[]): string {
|
|
706
|
+
private _compileModifierARRAY(ctx: I.IContext, rules: any[], traceOffset: number = 0): string {
|
|
645
707
|
|
|
646
708
|
let a: number = 0;
|
|
647
709
|
let b: number = -1;
|
|
@@ -721,6 +783,10 @@ implements C.ICompiler {
|
|
|
721
783
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
722
784
|
|
|
723
785
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
786
|
+
const vIter = this._lang.varName(ctx.vCursor++);
|
|
787
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.numberTemplateVar(
|
|
788
|
+
traceOffset ? this._lang.add(traceOffset, vIter) : vIter
|
|
789
|
+
)}]`;
|
|
724
790
|
|
|
725
791
|
switch (b) {
|
|
726
792
|
case -1: {
|
|
@@ -754,9 +820,9 @@ implements C.ICompiler {
|
|
|
754
820
|
[CLOSURE_ARG],
|
|
755
821
|
this._lang.series([
|
|
756
822
|
this._lang.forEach(
|
|
757
|
-
CLOSURE_PARAM, ctx.vName, this._lang.ifThen(
|
|
823
|
+
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
758
824
|
this._lang.not(this._compile(ctx, rules.slice(1))),
|
|
759
|
-
this._lang.returnValue(this.
|
|
825
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
760
826
|
)
|
|
761
827
|
),
|
|
762
828
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -786,6 +852,7 @@ implements C.ICompiler {
|
|
|
786
852
|
|
|
787
853
|
const types = rules.slice();
|
|
788
854
|
let tupleLength = 0;
|
|
855
|
+
let tupleLengthMin = 0;
|
|
789
856
|
|
|
790
857
|
while (1) {
|
|
791
858
|
|
|
@@ -822,10 +889,11 @@ implements C.ICompiler {
|
|
|
822
889
|
if (type !== 'any') {
|
|
823
890
|
|
|
824
891
|
result.push(this._compileModifierLIST(
|
|
825
|
-
ctx, type
|
|
892
|
+
ctx, type, i
|
|
826
893
|
));
|
|
827
894
|
}
|
|
828
895
|
|
|
896
|
+
tupleLengthMin = tupleLength;
|
|
829
897
|
tupleLength = -1;
|
|
830
898
|
}
|
|
831
899
|
else if (!/^\d+$/.test(dots.slice(3))) {
|
|
@@ -836,22 +904,27 @@ implements C.ICompiler {
|
|
|
836
904
|
|
|
837
905
|
const length = parseInt(dots.slice(3));
|
|
838
906
|
|
|
839
|
-
if (length
|
|
907
|
+
if (length === 0) {
|
|
840
908
|
|
|
841
|
-
|
|
909
|
+
throw new TypeError(`Invalid syntax for tuple: ${dots}`);
|
|
910
|
+
}
|
|
911
|
+
else if (length === 1) {
|
|
842
912
|
|
|
843
|
-
|
|
913
|
+
const vName = ctx.vName;
|
|
844
914
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
915
|
+
ctx.tracePath = `${ctx.tracePath}[${i}]`;
|
|
916
|
+
ctx.vName = this._lang.arrayIndex(vName, i++);
|
|
917
|
+
result.push(this._addTraceOr(
|
|
918
|
+
ctx,
|
|
919
|
+
this._compile(ctx, type),
|
|
920
|
+
));
|
|
848
921
|
}
|
|
849
922
|
else {
|
|
850
923
|
|
|
851
924
|
ctx.vName = this._lang.arraySlice(ctx.vName, i, i + length);
|
|
852
925
|
|
|
853
926
|
result.push(this._compileModifierARRAY(
|
|
854
|
-
ctx, [length, type]
|
|
927
|
+
ctx, [length, type], i
|
|
855
928
|
));
|
|
856
929
|
|
|
857
930
|
i += length;
|
|
@@ -864,8 +937,12 @@ implements C.ICompiler {
|
|
|
864
937
|
|
|
865
938
|
ctx.trap(true);
|
|
866
939
|
|
|
940
|
+
ctx.tracePath = `${ctx.tracePath}[${i}]`;
|
|
867
941
|
ctx.vName = this._lang.arrayIndex(ctx.vName, i++);
|
|
868
|
-
result.push(this.
|
|
942
|
+
result.push(this._addTraceOr(
|
|
943
|
+
ctx,
|
|
944
|
+
this._compile(ctx, type),
|
|
945
|
+
));
|
|
869
946
|
tupleLength++;
|
|
870
947
|
}
|
|
871
948
|
|
|
@@ -874,9 +951,24 @@ implements C.ICompiler {
|
|
|
874
951
|
|
|
875
952
|
if (tupleLength >= 0) {
|
|
876
953
|
|
|
877
|
-
result.splice(1, -1, this.
|
|
878
|
-
|
|
879
|
-
|
|
954
|
+
result.splice(1, -1, this._addTraceOr(
|
|
955
|
+
ctx,
|
|
956
|
+
this._lang.eq(
|
|
957
|
+
this._lang.arrayLength(ctx.vName),
|
|
958
|
+
tupleLength
|
|
959
|
+
),
|
|
960
|
+
'.length'
|
|
961
|
+
));
|
|
962
|
+
}
|
|
963
|
+
else if (tupleLengthMin >= 0) {
|
|
964
|
+
|
|
965
|
+
result.splice(1, -1, this._addTraceOr(
|
|
966
|
+
ctx,
|
|
967
|
+
this._lang.gte(
|
|
968
|
+
this._lang.arrayLength(ctx.vName),
|
|
969
|
+
tupleLengthMin
|
|
970
|
+
),
|
|
971
|
+
'.length'
|
|
880
972
|
));
|
|
881
973
|
}
|
|
882
974
|
|
|
@@ -903,7 +995,8 @@ implements C.ICompiler {
|
|
|
903
995
|
}
|
|
904
996
|
|
|
905
997
|
this._defTypes[rules[0]] = this.compile({
|
|
906
|
-
rule: rules.slice(1)
|
|
998
|
+
rule: rules.slice(1),
|
|
999
|
+
traceErrors: !!ctx.vTraceName
|
|
907
1000
|
});
|
|
908
1001
|
|
|
909
1002
|
return this._usePredefinedType(ctx, rules[0]);
|
|
@@ -954,24 +1047,25 @@ implements C.ICompiler {
|
|
|
954
1047
|
|
|
955
1048
|
ctx.trap(true);
|
|
956
1049
|
|
|
957
|
-
const
|
|
1050
|
+
const vCArg = ctx.vName;
|
|
958
1051
|
|
|
959
|
-
const
|
|
1052
|
+
const vCParam = this._lang.varName(ctx.vCursor++);
|
|
960
1053
|
|
|
961
|
-
const
|
|
1054
|
+
const vKey = this._lang.varName(ctx.vCursor++);
|
|
962
1055
|
|
|
963
1056
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
1057
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.stringTemplateVar(vKey)}]`;
|
|
964
1058
|
|
|
965
1059
|
const result = this._lang.and([
|
|
966
|
-
this._lang.isStrucutre(
|
|
1060
|
+
this._lang.isStrucutre(vCArg, true),
|
|
967
1061
|
this._lang.closure(
|
|
968
|
-
[
|
|
969
|
-
[
|
|
1062
|
+
[vCParam],
|
|
1063
|
+
[vCArg],
|
|
970
1064
|
this._lang.series([
|
|
971
1065
|
this._lang.forIn(
|
|
972
|
-
|
|
1066
|
+
vCParam, vKey, ctx.vName, this._lang.ifThen(
|
|
973
1067
|
this._lang.not(this._compile(ctx, rules)),
|
|
974
|
-
this._lang.returnValue(this.
|
|
1068
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
975
1069
|
)
|
|
976
1070
|
),
|
|
977
1071
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -1023,7 +1117,11 @@ implements C.ICompiler {
|
|
|
1023
1117
|
const strict = !!ctx.flags[I.EFlags.STRICT];
|
|
1024
1118
|
|
|
1025
1119
|
const result: string[] = [
|
|
1026
|
-
this.
|
|
1120
|
+
this._addTraceOr(
|
|
1121
|
+
ctx,
|
|
1122
|
+
this._lang.isStrucutre(ctx.vName, true),
|
|
1123
|
+
'!object'
|
|
1124
|
+
)
|
|
1027
1125
|
];
|
|
1028
1126
|
|
|
1029
1127
|
const keys: string[] = [];
|
|
@@ -1107,8 +1205,12 @@ implements C.ICompiler {
|
|
|
1107
1205
|
keys.push(k);
|
|
1108
1206
|
|
|
1109
1207
|
ctx.vName = this._lang.fieldIndex(ctx.vName, this._lang.literal(k));
|
|
1208
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.literal(k)}]`;
|
|
1110
1209
|
|
|
1111
|
-
result.push(this.
|
|
1210
|
+
result.push(this._addTraceOr(
|
|
1211
|
+
ctx,
|
|
1212
|
+
this._compile(ctx, rule)
|
|
1213
|
+
));
|
|
1112
1214
|
|
|
1113
1215
|
ctx.untrap();
|
|
1114
1216
|
}
|
package/src/lib/Context.ts
CHANGED
|
@@ -18,18 +18,18 @@ import * as i from './Internal';
|
|
|
18
18
|
|
|
19
19
|
export class Context implements i.IContext {
|
|
20
20
|
|
|
21
|
-
public trace: boolean;
|
|
22
|
-
|
|
23
|
-
public tracePoint: number;
|
|
24
|
-
|
|
25
21
|
public vCursor: number;
|
|
26
22
|
|
|
27
23
|
public stack: i.IContextData[];
|
|
28
24
|
|
|
29
25
|
public flags: Record<string, i.EFlagValue>;
|
|
30
26
|
|
|
27
|
+
public tracePath: string = '';
|
|
28
|
+
|
|
31
29
|
public constructor(
|
|
32
30
|
public vName: string,
|
|
31
|
+
public vTraceName: string,
|
|
32
|
+
public vTracePrefix: string,
|
|
33
33
|
public readonly typeSlotName: string,
|
|
34
34
|
public readonly referredTypes: Record<string, boolean>
|
|
35
35
|
) {
|
|
@@ -38,17 +38,14 @@ export class Context implements i.IContext {
|
|
|
38
38
|
this.vCursor = 0;
|
|
39
39
|
|
|
40
40
|
this.flags = {};
|
|
41
|
-
|
|
42
|
-
this.tracePoint = 0;
|
|
43
|
-
|
|
44
|
-
this.trace = false;
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
public trap(subjChanged: boolean = false): void {
|
|
48
44
|
|
|
49
45
|
this.stack.push({
|
|
50
46
|
vName: this.vName,
|
|
51
|
-
flags: this.flags
|
|
47
|
+
flags: this.flags,
|
|
48
|
+
tracePath: this.tracePath,
|
|
52
49
|
});
|
|
53
50
|
|
|
54
51
|
const prevFlags = this.flags;
|
|
@@ -83,7 +80,8 @@ export class Context implements i.IContext {
|
|
|
83
80
|
throw new Error('Failed to pop stack.');
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
this.vName = prev.vName;
|
|
87
83
|
this.flags = prev.flags;
|
|
84
|
+
this.vName = prev.vName;
|
|
85
|
+
this.tracePath = prev.tracePath;
|
|
88
86
|
}
|
|
89
87
|
}
|
|
@@ -165,7 +165,12 @@ implements IInlineCompiler {
|
|
|
165
165
|
|
|
166
166
|
return (new Function(
|
|
167
167
|
info.typeSlotName,
|
|
168
|
-
`return function(${
|
|
168
|
+
`return function(${
|
|
169
|
+
info.arguments
|
|
170
|
+
.map((a) => a.initial ? `${a.name} = ${a.initial}` : a.name)
|
|
171
|
+
.join(',')
|
|
172
|
+
}) {
|
|
173
|
+
${soe}
|
|
169
174
|
|
|
170
175
|
return ${info.source};
|
|
171
176
|
};`
|
package/src/lib/Internal.ts
CHANGED
|
@@ -72,16 +72,18 @@ export enum EFlagValue {
|
|
|
72
72
|
|
|
73
73
|
export interface IContextData {
|
|
74
74
|
|
|
75
|
+
flags: Record<string, EFlagValue>;
|
|
76
|
+
|
|
75
77
|
vName: string;
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
tracePath: string;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
export interface IContext extends IContextData {
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
vTraceName: string;
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
vTracePrefix: string;
|
|
85
87
|
|
|
86
88
|
vCursor: number;
|
|
87
89
|
|
|
@@ -289,12 +289,14 @@ implements C.ILanguageBuilder {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
public forEach(
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
arrVar: string,
|
|
293
|
+
elVar: string,
|
|
294
|
+
iterVar: string,
|
|
294
295
|
body: string
|
|
295
296
|
): string {
|
|
296
297
|
|
|
297
|
-
return `for (
|
|
298
|
+
return `for (let ${elVar} = 0; ${elVar} < ${arrVar}.length; ${elVar}++) {
|
|
299
|
+
const ${iterVar} = ${arrVar}[${elVar}];
|
|
298
300
|
${body}
|
|
299
301
|
}`;
|
|
300
302
|
}
|
|
@@ -424,6 +426,57 @@ implements C.ILanguageBuilder {
|
|
|
424
426
|
args.join(', ')
|
|
425
427
|
})`;
|
|
426
428
|
}
|
|
429
|
+
|
|
430
|
+
public escape(str: string): string {
|
|
431
|
+
|
|
432
|
+
return str.replace(/(['"])/g, '\\$1').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
public stringTemplateVar(varExpr: string): string {
|
|
436
|
+
|
|
437
|
+
return `"\${${varExpr}.replace(/(['"])/g, '\\\\$1').replace(/\\n/g, '\\\\n').replace(/\\r/g, '\\\\r')}"`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
public numberTemplateVar(varExpr: string): string {
|
|
441
|
+
|
|
442
|
+
return `\${${varExpr}}`;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
public addTrace(
|
|
446
|
+
vTrace: string,
|
|
447
|
+
vTraceStack: string,
|
|
448
|
+
path: string,
|
|
449
|
+
negative: boolean = false
|
|
450
|
+
): string {
|
|
451
|
+
|
|
452
|
+
if (negative) {
|
|
453
|
+
|
|
454
|
+
return `(${vTrace}.push(\`\${${vTraceStack}}${path}\`), true)`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return `(${vTrace}.push(\`\${${vTraceStack}}${path}\`), false)`;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
public add(a: string | number, b: string | number): string {
|
|
461
|
+
|
|
462
|
+
return `${a} + ${b}`;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
public orAddTrace(
|
|
466
|
+
expr: string,
|
|
467
|
+
vTrace: string,
|
|
468
|
+
vTraceStack: string,
|
|
469
|
+
path: string,
|
|
470
|
+
negative: boolean = false
|
|
471
|
+
): string {
|
|
472
|
+
|
|
473
|
+
if (negative) {
|
|
474
|
+
|
|
475
|
+
return `((${expr}) && (${vTrace}.push(\`\${${vTraceStack}}${path}\`), true))`;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return `((${expr}) || (${vTrace}.push(\`\${${vTraceStack}}${path}\`), false))`;
|
|
479
|
+
}
|
|
427
480
|
}
|
|
428
481
|
|
|
429
482
|
/**
|
package/src/test/abstracts.ts
CHANGED
|
@@ -112,6 +112,17 @@ compiler.addPredefinedType<string>(
|
|
|
112
112
|
}
|
|
113
113
|
);
|
|
114
114
|
|
|
115
|
+
const compiler2 = TypeGuard.createInlineCompiler();
|
|
116
|
+
|
|
117
|
+
compiler2.addPredefinedType<string>(
|
|
118
|
+
'ipv4_address',
|
|
119
|
+
function(i): i is string {
|
|
120
|
+
return typeof i === 'string'
|
|
121
|
+
&& /^[0-9]{1,3}(\.[0-9]{1,3}){3}$/.test(i)
|
|
122
|
+
&& i.split('.').map(x => parseInt(x, 10)).every(x => x >= 0 && x <= 255);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
115
126
|
export function assertItem(input: unknown, expect: boolean | 'throw'): ITestItem {
|
|
116
127
|
|
|
117
128
|
return {
|
|
@@ -150,15 +161,28 @@ export function createTestDefinition(suite: ITestSuite) {
|
|
|
150
161
|
assert.throws(() => {
|
|
151
162
|
|
|
152
163
|
compiler.compile<any>({
|
|
153
|
-
'rule': section.rule
|
|
164
|
+
'rule': section.rule,
|
|
165
|
+
traceErrors: true,
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
assert.throws(() => {
|
|
170
|
+
|
|
171
|
+
compiler2.compile<any>({
|
|
172
|
+
'rule': section.rule,
|
|
154
173
|
});
|
|
155
174
|
});
|
|
156
175
|
});
|
|
157
176
|
return;
|
|
158
177
|
}
|
|
159
178
|
|
|
160
|
-
const
|
|
161
|
-
'rule': section.rule
|
|
179
|
+
const checkWithTrace = compiler.compile<any>({
|
|
180
|
+
'rule': section.rule,
|
|
181
|
+
traceErrors: true,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const checkWithoutTrace = compiler2.compile<any>({
|
|
185
|
+
'rule': section.rule,
|
|
162
186
|
});
|
|
163
187
|
|
|
164
188
|
for (const item of section.items.sort((a, b) => a.expect === b.expect ? 0 : (a.expect ? -1 : 1))) {
|
|
@@ -170,7 +194,12 @@ export function createTestDefinition(suite: ITestSuite) {
|
|
|
170
194
|
}.`, function() {
|
|
171
195
|
|
|
172
196
|
assert.equal(
|
|
173
|
-
|
|
197
|
+
checkWithTrace(item.inputValue),
|
|
198
|
+
item.expect
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
assert.equal(
|
|
202
|
+
checkWithoutTrace(item.inputValue),
|
|
174
203
|
item.expect
|
|
175
204
|
);
|
|
176
205
|
});
|