@litert/typeguard 1.1.0 → 1.3.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 +10 -0
- package/lib/BuiltInTypeCompiler.d.ts +2 -2
- package/lib/BuiltInTypeCompiler.d.ts.map +1 -1
- package/lib/BuiltInTypeCompiler.js +1 -1
- 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 +19 -2
- 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 +93 -39
- package/lib/Compiler.js.map +1 -1
- package/lib/Context.d.ts +5 -4
- package/lib/Context.d.ts.map +1 -1
- package/lib/Context.js +9 -6
- 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 +2 -2
- package/lib/FilterCompiler.js.map +1 -1
- package/lib/InlineCompiler.d.ts +10 -3
- package/lib/InlineCompiler.d.ts.map +1 -1
- package/lib/InlineCompiler.js +16 -5
- package/lib/InlineCompiler.js.map +1 -1
- package/lib/Internal.d.ts +6 -4
- package/lib/Internal.d.ts.map +1 -1
- package/lib/Internal.js +3 -2
- package/lib/Internal.js.map +1 -1
- package/lib/Modifiers.d.ts +1 -1
- package/lib/Modifiers.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +6 -2
- package/lib/index.js.map +1 -1
- package/lib/langs/JavaScript.d.ts +1 -1
- package/lib/langs/JavaScript.d.ts.map +1 -1
- package/lib/langs/JavaScript.js +29 -4
- package/lib/langs/JavaScript.js.map +1 -1
- package/package.json +12 -12
- package/src/examples/quick-start.ts +118 -2
- package/src/lib/BuiltInTypeCompiler.ts +2 -2
- package/src/lib/BuiltInTypes.ts +1 -1
- package/src/lib/Common.ts +41 -2
- package/src/lib/Compiler.ts +155 -50
- package/src/lib/Context.ts +9 -11
- package/src/lib/FilterCompiler.ts +4 -4
- package/src/lib/InlineCompiler.ts +36 -10
- package/src/lib/Internal.ts +8 -4
- package/src/lib/Modifiers.ts +1 -1
- package/src/lib/index.ts +1 -1
- package/src/lib/langs/JavaScript.ts +58 -5
- package/src/test/00-all.ts +1 -1
- package/src/test/01-elemental-types.ts +2 -1
- package/src/test/02-array-and-list.ts +18 -18
- package/src/test/03-tuple.ts +1 -1
- package/src/test/04-from-string.ts +2 -1
- package/src/test/05-string-asserts.ts +1 -1
- package/src/test/06-structure.ts +26 -26
- package/src/test/07-modifiers.ts +71 -10
- package/src/test/08-map-and-dict.ts +20 -20
- package/src/test/09-exceptions.ts +4 -4
- package/src/test/abstracts.ts +45 -7
package/src/lib/Compiler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 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,15 +22,14 @@ 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
|
|
|
30
29
|
public constructor(
|
|
31
|
-
private _lang: C.ILanguageBuilder,
|
|
32
|
-
private _builtInTypes: I.IBuiltInTypeCompiler,
|
|
33
|
-
private _filters: I.IFilterCompiler
|
|
30
|
+
private readonly _lang: C.ILanguageBuilder,
|
|
31
|
+
private readonly _builtInTypes: I.IBuiltInTypeCompiler,
|
|
32
|
+
private readonly _filters: I.IFilterCompiler
|
|
34
33
|
) {
|
|
35
34
|
this._defTypes = {};
|
|
36
35
|
}
|
|
@@ -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
|
|
@@ -164,6 +210,9 @@ implements C.ICompiler {
|
|
|
164
210
|
case 'undefined':
|
|
165
211
|
|
|
166
212
|
return this._lang.isUndefined(ctx.vName, true);
|
|
213
|
+
|
|
214
|
+
default:
|
|
215
|
+
break;
|
|
167
216
|
}
|
|
168
217
|
|
|
169
218
|
throw new TypeError('Unknwn rules.');
|
|
@@ -197,53 +246,65 @@ implements C.ICompiler {
|
|
|
197
246
|
let regResult: RegExpMatchArray | null = /\[\s*(\d*|\d+\s*,\s*\d*)\s*\]$/.exec(rule);
|
|
198
247
|
|
|
199
248
|
/**
|
|
200
|
-
* For rules like `xxx[123]` or `xxx[1,5]`.
|
|
249
|
+
* For rules like `xxx[123]` or `xxx[1,5]` or `xxx[1,]`.
|
|
201
250
|
*/
|
|
202
251
|
if (regResult) {
|
|
203
252
|
|
|
204
253
|
if (regResult[1]) {
|
|
205
254
|
|
|
206
|
-
|
|
255
|
+
const range = regResult[1].split(',').map((x) => parseInt(x.trim()));
|
|
207
256
|
|
|
208
257
|
if (range.length === 1) {
|
|
209
258
|
|
|
259
|
+
/**
|
|
260
|
+
* For rules like `xxx[123]`.
|
|
261
|
+
*/
|
|
210
262
|
return this._compileModifiedRule(ctx, [
|
|
211
263
|
M.ARRAY,
|
|
212
264
|
range[0],
|
|
213
|
-
rule.
|
|
265
|
+
rule.slice(0, regResult.index)
|
|
214
266
|
]);
|
|
215
267
|
}
|
|
216
268
|
else if (Number.isNaN(range[1])) {
|
|
217
269
|
|
|
270
|
+
/**
|
|
271
|
+
* For rules like `xxx[1,]`.
|
|
272
|
+
*/
|
|
218
273
|
return this._compileModifiedRule(ctx, [
|
|
219
274
|
M.ARRAY,
|
|
220
275
|
[range[0]],
|
|
221
|
-
rule.
|
|
276
|
+
rule.slice(0, regResult.index)
|
|
222
277
|
]);
|
|
223
278
|
}
|
|
224
279
|
else {
|
|
225
280
|
|
|
281
|
+
/**
|
|
282
|
+
* For rules like `xxx[1,5]`.
|
|
283
|
+
*/
|
|
226
284
|
return this._compileModifiedRule(ctx, [
|
|
227
285
|
M.ARRAY,
|
|
228
286
|
range,
|
|
229
|
-
rule.
|
|
287
|
+
rule.slice(0, regResult.index)
|
|
230
288
|
]);
|
|
231
289
|
}
|
|
232
290
|
}
|
|
233
291
|
else {
|
|
234
292
|
|
|
293
|
+
/**
|
|
294
|
+
* For rules like `xxx[]`.
|
|
295
|
+
*/
|
|
235
296
|
return this._compileModifiedRule(ctx, [
|
|
236
297
|
M.LIST,
|
|
237
|
-
rule.
|
|
298
|
+
rule.slice(0, regResult.index)
|
|
238
299
|
]);
|
|
239
300
|
}
|
|
240
301
|
}
|
|
241
302
|
|
|
242
|
-
/**
|
|
243
|
-
* For rules like `xxx{}`.
|
|
244
|
-
*/
|
|
245
303
|
if (rule.endsWith(I.MAP_SUFFIX)) {
|
|
246
304
|
|
|
305
|
+
/**
|
|
306
|
+
* For rules like `xxx{}`.
|
|
307
|
+
*/
|
|
247
308
|
return this._lang.and([
|
|
248
309
|
this._compileModifiedRule(ctx, [
|
|
249
310
|
M.MAP,
|
|
@@ -324,7 +385,7 @@ implements C.ICompiler {
|
|
|
324
385
|
|
|
325
386
|
const offset = assertRule ? assertRule[1].length + 2 : 2;
|
|
326
387
|
|
|
327
|
-
switch ((assertRule?.[1]) ?? rule.
|
|
388
|
+
switch ((assertRule?.[1]) ?? rule.slice(0, 2)) {
|
|
328
389
|
case '==':
|
|
329
390
|
case 'equal':
|
|
330
391
|
|
|
@@ -576,7 +637,7 @@ implements C.ICompiler {
|
|
|
576
637
|
|
|
577
638
|
private _compileModifierOR(ctx: I.IContext, rules: any[]): string {
|
|
578
639
|
|
|
579
|
-
|
|
640
|
+
const result: string[] = [];
|
|
580
641
|
|
|
581
642
|
for (const r of rules) {
|
|
582
643
|
|
|
@@ -597,7 +658,7 @@ implements C.ICompiler {
|
|
|
597
658
|
);
|
|
598
659
|
}
|
|
599
660
|
|
|
600
|
-
private _compileModifierLIST(ctx: I.IContext, rules: any[]): string {
|
|
661
|
+
private _compileModifierLIST(ctx: I.IContext, rules: any[], traceOffset: number = 0): string {
|
|
601
662
|
|
|
602
663
|
const result: string[] = [];
|
|
603
664
|
|
|
@@ -615,6 +676,10 @@ implements C.ICompiler {
|
|
|
615
676
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
616
677
|
|
|
617
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
|
+
)}]`;
|
|
618
683
|
|
|
619
684
|
if (rules[0] !== B.ANY) {
|
|
620
685
|
|
|
@@ -623,9 +688,9 @@ implements C.ICompiler {
|
|
|
623
688
|
[CLOSURE_ARG],
|
|
624
689
|
this._lang.series([
|
|
625
690
|
this._lang.forEach(
|
|
626
|
-
CLOSURE_PARAM, ctx.vName, this._lang.ifThen(
|
|
691
|
+
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
627
692
|
this._lang.not(this._compile(ctx, rules)),
|
|
628
|
-
this._lang.returnValue(this.
|
|
693
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
629
694
|
)
|
|
630
695
|
),
|
|
631
696
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -638,7 +703,7 @@ implements C.ICompiler {
|
|
|
638
703
|
return this._lang.and(result);
|
|
639
704
|
}
|
|
640
705
|
|
|
641
|
-
private _compileModifierARRAY(ctx: I.IContext, rules: any[]): string {
|
|
706
|
+
private _compileModifierARRAY(ctx: I.IContext, rules: any[], traceOffset: number = 0): string {
|
|
642
707
|
|
|
643
708
|
let a: number = 0;
|
|
644
709
|
let b: number = -1;
|
|
@@ -718,6 +783,10 @@ implements C.ICompiler {
|
|
|
718
783
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
719
784
|
|
|
720
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
|
+
)}]`;
|
|
721
790
|
|
|
722
791
|
switch (b) {
|
|
723
792
|
case -1: {
|
|
@@ -751,9 +820,9 @@ implements C.ICompiler {
|
|
|
751
820
|
[CLOSURE_ARG],
|
|
752
821
|
this._lang.series([
|
|
753
822
|
this._lang.forEach(
|
|
754
|
-
CLOSURE_PARAM, ctx.vName, this._lang.ifThen(
|
|
823
|
+
CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(
|
|
755
824
|
this._lang.not(this._compile(ctx, rules.slice(1))),
|
|
756
|
-
this._lang.returnValue(this.
|
|
825
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
757
826
|
)
|
|
758
827
|
),
|
|
759
828
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -783,6 +852,7 @@ implements C.ICompiler {
|
|
|
783
852
|
|
|
784
853
|
const types = rules.slice();
|
|
785
854
|
let tupleLength = 0;
|
|
855
|
+
let tupleLengthMin = 0;
|
|
786
856
|
|
|
787
857
|
while (1) {
|
|
788
858
|
|
|
@@ -819,10 +889,11 @@ implements C.ICompiler {
|
|
|
819
889
|
if (type !== 'any') {
|
|
820
890
|
|
|
821
891
|
result.push(this._compileModifierLIST(
|
|
822
|
-
ctx, type
|
|
892
|
+
ctx, type, i
|
|
823
893
|
));
|
|
824
894
|
}
|
|
825
895
|
|
|
896
|
+
tupleLengthMin = tupleLength;
|
|
826
897
|
tupleLength = -1;
|
|
827
898
|
}
|
|
828
899
|
else if (!/^\d+$/.test(dots.slice(3))) {
|
|
@@ -833,22 +904,27 @@ implements C.ICompiler {
|
|
|
833
904
|
|
|
834
905
|
const length = parseInt(dots.slice(3));
|
|
835
906
|
|
|
836
|
-
if (length
|
|
907
|
+
if (length === 0) {
|
|
837
908
|
|
|
838
|
-
|
|
909
|
+
throw new TypeError(`Invalid syntax for tuple: ${dots}`);
|
|
910
|
+
}
|
|
911
|
+
else if (length === 1) {
|
|
839
912
|
|
|
840
|
-
|
|
913
|
+
const vName = ctx.vName;
|
|
841
914
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
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
|
+
));
|
|
845
921
|
}
|
|
846
922
|
else {
|
|
847
923
|
|
|
848
924
|
ctx.vName = this._lang.arraySlice(ctx.vName, i, i + length);
|
|
849
925
|
|
|
850
926
|
result.push(this._compileModifierARRAY(
|
|
851
|
-
ctx, [length, type]
|
|
927
|
+
ctx, [length, type], i
|
|
852
928
|
));
|
|
853
929
|
|
|
854
930
|
i += length;
|
|
@@ -861,8 +937,12 @@ implements C.ICompiler {
|
|
|
861
937
|
|
|
862
938
|
ctx.trap(true);
|
|
863
939
|
|
|
940
|
+
ctx.tracePath = `${ctx.tracePath}[${i}]`;
|
|
864
941
|
ctx.vName = this._lang.arrayIndex(ctx.vName, i++);
|
|
865
|
-
result.push(this.
|
|
942
|
+
result.push(this._addTraceOr(
|
|
943
|
+
ctx,
|
|
944
|
+
this._compile(ctx, type),
|
|
945
|
+
));
|
|
866
946
|
tupleLength++;
|
|
867
947
|
}
|
|
868
948
|
|
|
@@ -871,9 +951,24 @@ implements C.ICompiler {
|
|
|
871
951
|
|
|
872
952
|
if (tupleLength >= 0) {
|
|
873
953
|
|
|
874
|
-
result.splice(1, -1, this.
|
|
875
|
-
|
|
876
|
-
|
|
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'
|
|
877
972
|
));
|
|
878
973
|
}
|
|
879
974
|
|
|
@@ -882,7 +977,7 @@ implements C.ICompiler {
|
|
|
882
977
|
|
|
883
978
|
private _validateTypeName(name: unknown): void {
|
|
884
979
|
|
|
885
|
-
if (typeof name !== 'string' ||
|
|
980
|
+
if (typeof name !== 'string' || !I.RE_VALID_CUSTOM_TYPE_NAME.test(name)) {
|
|
886
981
|
|
|
887
982
|
throw new TypeError(`Invalid name ${
|
|
888
983
|
JSON.stringify(name)
|
|
@@ -900,7 +995,8 @@ implements C.ICompiler {
|
|
|
900
995
|
}
|
|
901
996
|
|
|
902
997
|
this._defTypes[rules[0]] = this.compile({
|
|
903
|
-
rule: rules.slice(1)
|
|
998
|
+
rule: rules.slice(1),
|
|
999
|
+
traceErrors: !!ctx.vTraceName
|
|
904
1000
|
});
|
|
905
1001
|
|
|
906
1002
|
return this._usePredefinedType(ctx, rules[0]);
|
|
@@ -951,24 +1047,25 @@ implements C.ICompiler {
|
|
|
951
1047
|
|
|
952
1048
|
ctx.trap(true);
|
|
953
1049
|
|
|
954
|
-
const
|
|
1050
|
+
const vCArg = ctx.vName;
|
|
955
1051
|
|
|
956
|
-
const
|
|
1052
|
+
const vCParam = this._lang.varName(ctx.vCursor++);
|
|
957
1053
|
|
|
958
|
-
const
|
|
1054
|
+
const vKey = this._lang.varName(ctx.vCursor++);
|
|
959
1055
|
|
|
960
1056
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
1057
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.stringTemplateVar(vKey)}]`;
|
|
961
1058
|
|
|
962
1059
|
const result = this._lang.and([
|
|
963
|
-
this._lang.isStrucutre(
|
|
1060
|
+
this._lang.isStrucutre(vCArg, true),
|
|
964
1061
|
this._lang.closure(
|
|
965
|
-
[
|
|
966
|
-
[
|
|
1062
|
+
[vCParam],
|
|
1063
|
+
[vCArg],
|
|
967
1064
|
this._lang.series([
|
|
968
1065
|
this._lang.forIn(
|
|
969
|
-
|
|
1066
|
+
vCParam, vKey, ctx.vName, this._lang.ifThen(
|
|
970
1067
|
this._lang.not(this._compile(ctx, rules)),
|
|
971
|
-
this._lang.returnValue(this.
|
|
1068
|
+
this._lang.returnValue(this._addTrace(ctx))
|
|
972
1069
|
)
|
|
973
1070
|
),
|
|
974
1071
|
this._lang.returnValue(this._lang.literal(true))
|
|
@@ -988,7 +1085,7 @@ implements C.ICompiler {
|
|
|
988
1085
|
throw new SyntaxError(`Invalid dict ${JSON.stringify(rules)}.`);
|
|
989
1086
|
}
|
|
990
1087
|
|
|
991
|
-
|
|
1088
|
+
const tmp: Record<string, string> = {};
|
|
992
1089
|
|
|
993
1090
|
const id = `${Date.now()}${Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)}`;
|
|
994
1091
|
|
|
@@ -999,7 +1096,7 @@ implements C.ICompiler {
|
|
|
999
1096
|
|
|
1000
1097
|
const type = `${I.PREDEF_TYPE_SYMBOL}${this._lang.varName(id)}`;
|
|
1001
1098
|
|
|
1002
|
-
for (
|
|
1099
|
+
for (const key of rules[0]) {
|
|
1003
1100
|
|
|
1004
1101
|
if (typeof key !== 'string') {
|
|
1005
1102
|
|
|
@@ -1020,7 +1117,11 @@ implements C.ICompiler {
|
|
|
1020
1117
|
const strict = !!ctx.flags[I.EFlags.STRICT];
|
|
1021
1118
|
|
|
1022
1119
|
const result: string[] = [
|
|
1023
|
-
this.
|
|
1120
|
+
this._addTraceOr(
|
|
1121
|
+
ctx,
|
|
1122
|
+
this._lang.isStrucutre(ctx.vName, true),
|
|
1123
|
+
'!object'
|
|
1124
|
+
)
|
|
1024
1125
|
];
|
|
1025
1126
|
|
|
1026
1127
|
const keys: string[] = [];
|
|
@@ -1104,8 +1205,12 @@ implements C.ICompiler {
|
|
|
1104
1205
|
keys.push(k);
|
|
1105
1206
|
|
|
1106
1207
|
ctx.vName = this._lang.fieldIndex(ctx.vName, this._lang.literal(k));
|
|
1208
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.literal(k)}]`;
|
|
1107
1209
|
|
|
1108
|
-
result.push(this.
|
|
1210
|
+
result.push(this._addTraceOr(
|
|
1211
|
+
ctx,
|
|
1212
|
+
this._compile(ctx, rule)
|
|
1213
|
+
));
|
|
1109
1214
|
|
|
1110
1215
|
ctx.untrap();
|
|
1111
1216
|
}
|
package/src/lib/Context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 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.
|
|
@@ -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
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 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.
|
|
@@ -21,8 +21,8 @@ export class FilterCompiler
|
|
|
21
21
|
implements I.IFilterCompiler {
|
|
22
22
|
|
|
23
23
|
public constructor(
|
|
24
|
-
private _lang: C.ILanguageBuilder,
|
|
25
|
-
private _bitc: I.IBuiltInTypeCompiler
|
|
24
|
+
private readonly _lang: C.ILanguageBuilder,
|
|
25
|
+
private readonly _bitc: I.IBuiltInTypeCompiler
|
|
26
26
|
) {}
|
|
27
27
|
|
|
28
28
|
public compile(rule: string, ctx: I.IContext): string {
|
|
@@ -36,7 +36,7 @@ implements I.IFilterCompiler {
|
|
|
36
36
|
throw new TypeError('Only number is allowed as filter arguments.');
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const ret: string[] = [];
|
|
40
40
|
|
|
41
41
|
switch (filter[0]) {
|
|
42
42
|
case 'array.length':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 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.
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { createCompiler } from './Compiler';
|
|
18
18
|
import { createJavaScriptLanguageBuilder } from './langs/JavaScript';
|
|
19
19
|
import * as C from './Common';
|
|
20
|
+
import * as I from './Internal';
|
|
20
21
|
|
|
21
22
|
export interface IInlineCompileOptions extends C.ICompileOptions {
|
|
22
23
|
|
|
@@ -34,14 +35,22 @@ export interface IInlineCompiler {
|
|
|
34
35
|
*
|
|
35
36
|
* @param options The options of compilation.
|
|
36
37
|
*/
|
|
37
|
-
compile<T>(options: IInlineCompileOptions): C.
|
|
38
|
+
compile<T>(options: IInlineCompileOptions): C.ITypeChecker<T>;
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Get the type-checker of a pre-defined type.
|
|
41
42
|
*
|
|
42
43
|
* @param name The name of the pre-defined type.
|
|
43
44
|
*/
|
|
44
|
-
getPredefinedType<T>(name: string): C.
|
|
45
|
+
getPredefinedType<T>(name: string): C.ITypeChecker<T>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Register a pre-defined type checker.
|
|
49
|
+
*
|
|
50
|
+
* @param name The name of the pre-defined type (without prefix `@`)
|
|
51
|
+
* @param checker The checker callback of the pre-defined type.
|
|
52
|
+
*/
|
|
53
|
+
addPredefinedType<T>(name: string, checker: C.ITypeChecker<T>): this;
|
|
45
54
|
|
|
46
55
|
/**
|
|
47
56
|
* Check if a pre-defined type is compiled.
|
|
@@ -59,11 +68,11 @@ export interface IInlineCompiler {
|
|
|
59
68
|
class InlineCompiler
|
|
60
69
|
implements IInlineCompiler {
|
|
61
70
|
|
|
62
|
-
private _defTypes: Record<string, C.
|
|
71
|
+
private _defTypes: Record<string, C.ITypeChecker<any>>;
|
|
63
72
|
|
|
64
73
|
private _missingTypes: Record<string, boolean>;
|
|
65
74
|
|
|
66
|
-
private _compiler: C.ICompiler;
|
|
75
|
+
private readonly _compiler: C.ICompiler;
|
|
67
76
|
|
|
68
77
|
public constructor() {
|
|
69
78
|
|
|
@@ -78,7 +87,7 @@ implements IInlineCompiler {
|
|
|
78
87
|
);
|
|
79
88
|
}
|
|
80
89
|
|
|
81
|
-
public compile<T>(options: IInlineCompileOptions): C.
|
|
90
|
+
public compile<T>(options: IInlineCompileOptions): C.ITypeChecker<T> {
|
|
82
91
|
|
|
83
92
|
const result = this._compiler.compile(options);
|
|
84
93
|
|
|
@@ -92,7 +101,7 @@ implements IInlineCompiler {
|
|
|
92
101
|
stopOnEntry?: boolean
|
|
93
102
|
): void {
|
|
94
103
|
|
|
95
|
-
for (
|
|
104
|
+
for (const x of types) {
|
|
96
105
|
|
|
97
106
|
if (this._defTypes[x]) {
|
|
98
107
|
|
|
@@ -115,6 +124,18 @@ implements IInlineCompiler {
|
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
|
|
127
|
+
public addPredefinedType(name: string, checker: C.ITypeChecker<any>): this {
|
|
128
|
+
|
|
129
|
+
if (!I.RE_VALID_CUSTOM_TYPE_NAME.test(name)) {
|
|
130
|
+
|
|
131
|
+
throw new TypeError(`Invalid name ${ JSON.stringify(name) } for a pre-defined type.`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this._defTypes[name] = checker;
|
|
135
|
+
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
public detectUndefinedTypes(): string[] {
|
|
119
140
|
|
|
120
141
|
return Object.keys(this._missingTypes);
|
|
@@ -125,7 +146,7 @@ implements IInlineCompiler {
|
|
|
125
146
|
return !!this._defTypes[name];
|
|
126
147
|
}
|
|
127
148
|
|
|
128
|
-
public getPredefinedType(name: string): C.
|
|
149
|
+
public getPredefinedType(name: string): C.ITypeChecker<any> {
|
|
129
150
|
|
|
130
151
|
if (!this._defTypes[name]) {
|
|
131
152
|
|
|
@@ -138,13 +159,18 @@ implements IInlineCompiler {
|
|
|
138
159
|
private _wrapCheckerCode(
|
|
139
160
|
info: C.ICompileResult,
|
|
140
161
|
stopOnEntry: boolean = false
|
|
141
|
-
): C.
|
|
162
|
+
): C.ITypeChecker<any> {
|
|
142
163
|
|
|
143
164
|
const soe = stopOnEntry ? 'debugger;' : '';
|
|
144
165
|
|
|
145
166
|
return (new Function(
|
|
146
167
|
info.typeSlotName,
|
|
147
|
-
`return function(${
|
|
168
|
+
`return function(${
|
|
169
|
+
info.arguments
|
|
170
|
+
.map((a) => a.initial ? `${a.name} = ${a.initial}` : a.name)
|
|
171
|
+
.join(',')
|
|
172
|
+
}) {
|
|
173
|
+
${soe}
|
|
148
174
|
|
|
149
175
|
return ${info.source};
|
|
150
176
|
};`
|
package/src/lib/Internal.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2022 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.
|
|
@@ -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
|
|
|
@@ -123,3 +125,5 @@ export interface IBuiltInTypeCompiler {
|
|
|
123
125
|
|
|
124
126
|
isElemental(type: string): boolean;
|
|
125
127
|
}
|
|
128
|
+
|
|
129
|
+
export const RE_VALID_CUSTOM_TYPE_NAME = /^[-:.\w]+$/;
|