@litert/typeguard 1.0.1 → 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 +16 -0
- package/lib/BuiltInTypeCompiler.d.ts +4 -4
- package/lib/BuiltInTypeCompiler.d.ts.map +1 -1
- package/lib/BuiltInTypeCompiler.js +167 -166
- package/lib/BuiltInTypeCompiler.js.map +1 -1
- package/lib/BuiltInTypes.d.ts +1 -1
- package/lib/BuiltInTypes.js +37 -36
- package/lib/BuiltInTypes.js.map +1 -1
- package/lib/Common.d.ts +27 -10
- package/lib/Common.d.ts.map +1 -1
- package/lib/Common.js +1 -1
- package/lib/Compiler.d.ts +2 -2
- package/lib/Compiler.d.ts.map +1 -1
- package/lib/Compiler.js +159 -102
- package/lib/Compiler.js.map +1 -1
- package/lib/Context.d.ts +6 -5
- package/lib/Context.d.ts.map +1 -1
- package/lib/Context.js +11 -7
- package/lib/Context.js.map +1 -1
- package/lib/FilterCompiler.d.ts +5 -5
- package/lib/FilterCompiler.d.ts.map +1 -1
- package/lib/FilterCompiler.js +25 -24
- package/lib/FilterCompiler.js.map +1 -1
- package/lib/InlineCompiler.d.ts +12 -5
- package/lib/InlineCompiler.d.ts.map +1 -1
- package/lib/InlineCompiler.js +18 -6
- 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 +12 -10
- package/lib/Internal.js.map +1 -1
- package/lib/Modifiers.d.ts +1 -1
- package/lib/Modifiers.js +2 -1
- package/lib/Modifiers.js.map +1 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.js +19 -7
- package/lib/index.js.map +1 -1
- package/lib/langs/JavaScript.d.ts +2 -2
- package/lib/langs/JavaScript.d.ts.map +1 -1
- package/lib/langs/JavaScript.js +55 -29
- package/lib/langs/JavaScript.js.map +1 -1
- package/package.json +17 -13
- package/src/examples/quick-start.ts +172 -0
- package/src/lib/BuiltInTypeCompiler.ts +171 -171
- package/src/lib/BuiltInTypes.ts +36 -36
- package/src/lib/Common.ts +49 -10
- package/src/lib/Compiler.ts +354 -247
- package/src/lib/Context.ts +11 -13
- package/src/lib/FilterCompiler.ts +84 -84
- package/src/lib/InlineCompiler.ts +41 -15
- package/src/lib/Internal.ts +17 -13
- package/src/lib/Modifiers.ts +2 -2
- package/src/lib/index.ts +5 -5
- package/src/lib/langs/JavaScript.ts +84 -31
- package/src/test/00-all.ts +10 -10
- package/src/test/01-elemental-types.ts +1111 -1110
- package/src/test/02-array-and-list.ts +75 -75
- package/src/test/03-tuple.ts +87 -87
- package/src/test/04-from-string.ts +849 -848
- package/src/test/05-string-asserts.ts +422 -422
- package/src/test/06-structure.ts +107 -107
- package/src/test/07-modifiers.ts +151 -42
- package/src/test/08-map-and-dict.ts +46 -46
- package/src/test/09-exceptions.ts +30 -9
- package/src/test/abstracts.ts +83 -45
- package/dist/typeguard.amd.d.ts +0 -588
- package/dist/typeguard.amd.d.ts.map +0 -1
- package/dist/typeguard.amd.js +0 -2069
- package/dist/typeguard.amd.js.map +0 -1
- package/dist/typeguard.system.d.ts +0 -588
- package/dist/typeguard.system.d.ts.map +0 -1
- package/dist/typeguard.system.js +0 -2185
- package/dist/typeguard.system.js.map +0 -1
- package/src/samples/quick-start.ts +0 -52
- package/tsconfig-amd.json +0 -72
- package/tsconfig-systemjs.json +0 -72
package/lib/Compiler.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Copyright
|
|
3
|
+
* Copyright 2022 Angus Fenying <fenying@litert.org>
|
|
4
4
|
*
|
|
5
5
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
6
|
* you may not use this file except in compliance with the License.
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.createCompiler = void 0;
|
|
18
19
|
const I = require("./Internal");
|
|
19
20
|
const M = require("./Modifiers");
|
|
20
21
|
const Context_1 = require("./Context");
|
|
@@ -34,23 +35,48 @@ class Compiler {
|
|
|
34
35
|
}
|
|
35
36
|
return null;
|
|
36
37
|
}
|
|
38
|
+
_addTrace(ctx) {
|
|
39
|
+
if (!ctx.vTraceName) {
|
|
40
|
+
return this._lang.literalFalse;
|
|
41
|
+
}
|
|
42
|
+
return this._lang.addTrace(ctx.vTraceName, ctx.vTracePrefix, ctx.tracePath);
|
|
43
|
+
}
|
|
44
|
+
_addTraceOr(ctx, expr, subPath = '') {
|
|
45
|
+
if (!ctx.vTraceName) {
|
|
46
|
+
return expr;
|
|
47
|
+
}
|
|
48
|
+
return this._lang.orAddTrace(expr, ctx.vTraceName, ctx.vTracePrefix, `${ctx.tracePath}${subPath}`);
|
|
49
|
+
}
|
|
37
50
|
compile(options) {
|
|
38
51
|
const referredTypes = {};
|
|
39
|
-
const ctx = new Context_1.Context(this._lang.varName(
|
|
52
|
+
const ctx = new Context_1.Context(this._lang.varName('entry'), options.traceErrors ? this._lang.varName('failedAsserts') : '', options.traceErrors ? this._lang.varName('tracePrefix') : '', this._lang.varName('types'), referredTypes);
|
|
40
53
|
if (options.name) {
|
|
41
54
|
this._compile(ctx, [M.TYPE, options.name, options.rule]);
|
|
42
55
|
return this._defTypes[options.name];
|
|
43
56
|
}
|
|
44
57
|
else {
|
|
45
58
|
const ret = {
|
|
46
|
-
source:
|
|
59
|
+
source: '',
|
|
47
60
|
arguments: [{
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
'name': ctx.vName,
|
|
62
|
+
'type': 'unknown',
|
|
63
|
+
'initial': ''
|
|
50
64
|
}],
|
|
51
65
|
typeSlotName: ctx.typeSlotName,
|
|
52
66
|
referredTypes: []
|
|
53
67
|
};
|
|
68
|
+
if (ctx.vTraceName) {
|
|
69
|
+
ret.arguments.push({
|
|
70
|
+
'name': ctx.vTraceName,
|
|
71
|
+
'type': 'string[]',
|
|
72
|
+
'initial': '[]'
|
|
73
|
+
});
|
|
74
|
+
ret.arguments.push({
|
|
75
|
+
'name': ctx.vTracePrefix,
|
|
76
|
+
'type': 'string',
|
|
77
|
+
'initial': this._lang.literal('data')
|
|
78
|
+
});
|
|
79
|
+
}
|
|
54
80
|
ret.source = this._compile(ctx, options.rule);
|
|
55
81
|
ret.referredTypes = Object.keys(ctx.referredTypes);
|
|
56
82
|
return ret;
|
|
@@ -58,9 +84,9 @@ class Compiler {
|
|
|
58
84
|
}
|
|
59
85
|
_compile(ctx, rules) {
|
|
60
86
|
switch (typeof rules) {
|
|
61
|
-
case
|
|
87
|
+
case 'string':
|
|
62
88
|
return this._compileStringRule(ctx, rules);
|
|
63
|
-
case
|
|
89
|
+
case 'boolean':
|
|
64
90
|
if (ctx.flags[I.EFlags.FROM_STRING]) {
|
|
65
91
|
return this._lang.or([
|
|
66
92
|
this._lang.eq(ctx.vName, this._lang.literal(rules)),
|
|
@@ -68,7 +94,7 @@ class Compiler {
|
|
|
68
94
|
]);
|
|
69
95
|
}
|
|
70
96
|
return this._lang.eq(ctx.vName, this._lang.literal(rules));
|
|
71
|
-
case
|
|
97
|
+
case 'number':
|
|
72
98
|
if (ctx.flags[I.EFlags.FROM_STRING]) {
|
|
73
99
|
return this._lang.or([
|
|
74
100
|
this._lang.eq(ctx.vName, this._lang.literal(rules)),
|
|
@@ -76,7 +102,7 @@ class Compiler {
|
|
|
76
102
|
]);
|
|
77
103
|
}
|
|
78
104
|
return this._lang.eq(ctx.vName, this._lang.literal(rules));
|
|
79
|
-
case
|
|
105
|
+
case 'object':
|
|
80
106
|
if (Array.isArray(rules)) {
|
|
81
107
|
return this._compileModifiedRule(ctx, rules);
|
|
82
108
|
}
|
|
@@ -84,16 +110,18 @@ class Compiler {
|
|
|
84
110
|
if (ctx.flags[I.EFlags.FROM_STRING]) {
|
|
85
111
|
return this._lang.or([
|
|
86
112
|
this._lang.isNull(ctx.vName, true),
|
|
87
|
-
this._lang.eq(ctx.vName, this._lang.literal(
|
|
113
|
+
this._lang.eq(ctx.vName, this._lang.literal('null'))
|
|
88
114
|
]);
|
|
89
115
|
}
|
|
90
116
|
return this._lang.isNull(ctx.vName, true);
|
|
91
117
|
}
|
|
92
118
|
return this._compileStructuredRule(ctx, rules);
|
|
93
|
-
case
|
|
119
|
+
case 'undefined':
|
|
94
120
|
return this._lang.isUndefined(ctx.vName, true);
|
|
121
|
+
default:
|
|
122
|
+
break;
|
|
95
123
|
}
|
|
96
|
-
throw new TypeError(
|
|
124
|
+
throw new TypeError('Unknwn rules.');
|
|
97
125
|
}
|
|
98
126
|
_compileStringRule(ctx, rule) {
|
|
99
127
|
const strAssert = this._useStringAssert(ctx, rule);
|
|
@@ -103,55 +131,67 @@ class Compiler {
|
|
|
103
131
|
strAssert
|
|
104
132
|
]);
|
|
105
133
|
}
|
|
106
|
-
if (rule
|
|
134
|
+
if (rule.startsWith(I.IMPLICIT_SYMBOL)) {
|
|
107
135
|
return this._lang.or([
|
|
108
136
|
this._builtInTypes.compile(B.VOID, ctx, []),
|
|
109
137
|
this._compileStringRule(ctx, rule.slice(1))
|
|
110
138
|
]);
|
|
111
139
|
}
|
|
112
|
-
if (rule
|
|
140
|
+
if (rule.startsWith(I.NEGATIVE_SYMBOL)) {
|
|
113
141
|
return this._lang.not(this._compileStringRule(ctx, rule.slice(1)));
|
|
114
142
|
}
|
|
115
|
-
let regResult;
|
|
143
|
+
let regResult = /\[\s*(\d*|\d+\s*,\s*\d*)\s*\]$/.exec(rule);
|
|
116
144
|
/**
|
|
117
|
-
* For rules like `xxx[123]` or `xxx[1,5]`.
|
|
145
|
+
* For rules like `xxx[123]` or `xxx[1,5]` or `xxx[1,]`.
|
|
118
146
|
*/
|
|
119
|
-
if (regResult
|
|
147
|
+
if (regResult) {
|
|
120
148
|
if (regResult[1]) {
|
|
121
|
-
|
|
149
|
+
const range = regResult[1].split(',').map((x) => parseInt(x.trim()));
|
|
122
150
|
if (range.length === 1) {
|
|
151
|
+
/**
|
|
152
|
+
* For rules like `xxx[123]`.
|
|
153
|
+
*/
|
|
123
154
|
return this._compileModifiedRule(ctx, [
|
|
124
155
|
M.ARRAY,
|
|
125
156
|
range[0],
|
|
126
|
-
rule.
|
|
157
|
+
rule.slice(0, regResult.index)
|
|
127
158
|
]);
|
|
128
159
|
}
|
|
129
160
|
else if (Number.isNaN(range[1])) {
|
|
161
|
+
/**
|
|
162
|
+
* For rules like `xxx[1,]`.
|
|
163
|
+
*/
|
|
130
164
|
return this._compileModifiedRule(ctx, [
|
|
131
165
|
M.ARRAY,
|
|
132
166
|
[range[0]],
|
|
133
|
-
rule.
|
|
167
|
+
rule.slice(0, regResult.index)
|
|
134
168
|
]);
|
|
135
169
|
}
|
|
136
170
|
else {
|
|
171
|
+
/**
|
|
172
|
+
* For rules like `xxx[1,5]`.
|
|
173
|
+
*/
|
|
137
174
|
return this._compileModifiedRule(ctx, [
|
|
138
175
|
M.ARRAY,
|
|
139
176
|
range,
|
|
140
|
-
rule.
|
|
177
|
+
rule.slice(0, regResult.index)
|
|
141
178
|
]);
|
|
142
179
|
}
|
|
143
180
|
}
|
|
144
181
|
else {
|
|
182
|
+
/**
|
|
183
|
+
* For rules like `xxx[]`.
|
|
184
|
+
*/
|
|
145
185
|
return this._compileModifiedRule(ctx, [
|
|
146
186
|
M.LIST,
|
|
147
|
-
rule.
|
|
187
|
+
rule.slice(0, regResult.index)
|
|
148
188
|
]);
|
|
149
189
|
}
|
|
150
190
|
}
|
|
151
|
-
/**
|
|
152
|
-
* For rules like `xxx{}`.
|
|
153
|
-
*/
|
|
154
191
|
if (rule.endsWith(I.MAP_SUFFIX)) {
|
|
192
|
+
/**
|
|
193
|
+
* For rules like `xxx{}`.
|
|
194
|
+
*/
|
|
155
195
|
return this._lang.and([
|
|
156
196
|
this._compileModifiedRule(ctx, [
|
|
157
197
|
M.MAP,
|
|
@@ -159,9 +199,10 @@ class Compiler {
|
|
|
159
199
|
])
|
|
160
200
|
]);
|
|
161
201
|
}
|
|
162
|
-
if (rule
|
|
202
|
+
if (rule.startsWith(I.PREDEF_TYPE_SYMBOL)) {
|
|
163
203
|
return this._usePredefinedType(ctx, rule.slice(1));
|
|
164
204
|
}
|
|
205
|
+
regResult = /^(\w+)(\(\s*(-?\d+(\.\d+)?)?\s*,?\s*(-?\d+(\.\d+)?)?\s*\))?$/.exec(rule);
|
|
165
206
|
/**
|
|
166
207
|
* For built-in-type rules like:
|
|
167
208
|
*
|
|
@@ -170,14 +211,14 @@ class Compiler {
|
|
|
170
211
|
* - `string`
|
|
171
212
|
* - `int(12, 34)`
|
|
172
213
|
*/
|
|
173
|
-
if (regResult
|
|
214
|
+
if (regResult) {
|
|
174
215
|
if (regResult[2]) {
|
|
175
|
-
const args = regResult[2].slice(1, -1).trim().split(
|
|
216
|
+
const args = regResult[2].slice(1, -1).trim().split(',').map((x) => parseFloat(x.trim()));
|
|
176
217
|
return this._builtInTypes.compile(regResult[1], ctx, args);
|
|
177
218
|
}
|
|
178
219
|
return this._builtInTypes.compile(regResult[1], ctx, []);
|
|
179
220
|
}
|
|
180
|
-
if (rule
|
|
221
|
+
if (rule.startsWith(I.FILTER_PREFIX)) {
|
|
181
222
|
return this._filters.compile(rule, ctx);
|
|
182
223
|
}
|
|
183
224
|
throw new TypeError(`Unknown type "${rule}".`);
|
|
@@ -188,64 +229,65 @@ class Compiler {
|
|
|
188
229
|
return this._lang.call(this._lang.fieldIndex(ctx.typeSlotName, this._lang.literal(typeName)), ctx.vName);
|
|
189
230
|
}
|
|
190
231
|
_useStringAssert(ctx, rule) {
|
|
191
|
-
|
|
232
|
+
var _a;
|
|
233
|
+
const assertRule = /^:([-\w]+):/.exec(rule);
|
|
192
234
|
const offset = assertRule ? assertRule[1].length + 2 : 2;
|
|
193
|
-
switch ((assertRule
|
|
194
|
-
case
|
|
195
|
-
case
|
|
235
|
+
switch ((_a = (assertRule === null || assertRule === void 0 ? void 0 : assertRule[1])) !== null && _a !== void 0 ? _a : rule.slice(0, 2)) {
|
|
236
|
+
case '==':
|
|
237
|
+
case 'equal':
|
|
196
238
|
return this._lang.eq(ctx.vName, this._lang.literal(rule.slice(offset)));
|
|
197
|
-
case
|
|
198
|
-
case
|
|
239
|
+
case '%=':
|
|
240
|
+
case 'equal-i':
|
|
199
241
|
return this._lang.eq(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase()));
|
|
200
|
-
case
|
|
201
|
-
case
|
|
242
|
+
case '!=':
|
|
243
|
+
case 'not-equal':
|
|
202
244
|
return this._lang.ne(ctx.vName, this._lang.literal(rule.slice(offset)));
|
|
203
|
-
case
|
|
204
|
-
case
|
|
245
|
+
case '%!':
|
|
246
|
+
case 'not-equal-i':
|
|
205
247
|
return this._lang.ne(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase()));
|
|
206
|
-
case
|
|
207
|
-
case
|
|
248
|
+
case '~=':
|
|
249
|
+
case 'match':
|
|
208
250
|
return this._lang.matchRegExp(ctx.vName, rule.slice(offset));
|
|
209
|
-
case
|
|
210
|
-
case
|
|
251
|
+
case '~!':
|
|
252
|
+
case 'not-match':
|
|
211
253
|
return this._lang.not(this._lang.matchRegExp(ctx.vName, rule.slice(offset)));
|
|
212
|
-
case
|
|
213
|
-
case
|
|
254
|
+
case '?=':
|
|
255
|
+
case 'include':
|
|
214
256
|
return this._lang.instr(ctx.vName, this._lang.literal(rule.slice(offset)));
|
|
215
|
-
case
|
|
216
|
-
case
|
|
257
|
+
case '?!':
|
|
258
|
+
case 'not-include':
|
|
217
259
|
return this._lang.not(this._lang.instr(ctx.vName, this._lang.literal(rule.slice(offset))));
|
|
218
|
-
case
|
|
219
|
-
case
|
|
260
|
+
case '*=':
|
|
261
|
+
case 'include-i':
|
|
220
262
|
return this._lang.instr(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase()));
|
|
221
|
-
case
|
|
222
|
-
case
|
|
263
|
+
case '*!':
|
|
264
|
+
case 'not-include-i':
|
|
223
265
|
return this._lang.not(this._lang.instr(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase())));
|
|
224
|
-
case
|
|
225
|
-
case
|
|
266
|
+
case '^=':
|
|
267
|
+
case 'start-with':
|
|
226
268
|
return this._lang.startsWith(ctx.vName, this._lang.literal(rule.slice(offset)));
|
|
227
|
-
case
|
|
269
|
+
case 'start-with-i':
|
|
228
270
|
return this._lang.startsWith(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase()));
|
|
229
|
-
case
|
|
230
|
-
case
|
|
271
|
+
case '^!':
|
|
272
|
+
case 'not-start-with':
|
|
231
273
|
return this._lang.not(this._lang.startsWith(ctx.vName, this._lang.literal(rule.slice(offset))));
|
|
232
|
-
case
|
|
274
|
+
case 'not-start-with-i':
|
|
233
275
|
return this._lang.not(this._lang.startsWith(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase())));
|
|
234
|
-
case
|
|
235
|
-
case
|
|
276
|
+
case '$=':
|
|
277
|
+
case 'end-with':
|
|
236
278
|
return this._lang.endsWith(ctx.vName, this._lang.literal(rule.slice(offset)));
|
|
237
|
-
case
|
|
279
|
+
case 'end-with-i':
|
|
238
280
|
return this._lang.endsWith(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase()));
|
|
239
|
-
case
|
|
240
|
-
case
|
|
281
|
+
case '$!':
|
|
282
|
+
case 'not-end-with':
|
|
241
283
|
return this._lang.not(this._lang.endsWith(ctx.vName, this._lang.literal(rule.slice(offset))));
|
|
242
|
-
case
|
|
284
|
+
case 'not-end-with-i':
|
|
243
285
|
return this._lang.not(this._lang.endsWith(this._lang.lowerCase(ctx.vName), this._lang.literal(rule.slice(offset).toLowerCase())));
|
|
244
286
|
default:
|
|
245
|
-
if (rule.startsWith(
|
|
287
|
+
if (rule.startsWith('=')) {
|
|
246
288
|
return this._lang.eq(ctx.vName, this._lang.literal(rule.slice(1)));
|
|
247
289
|
}
|
|
248
|
-
if (rule.startsWith(
|
|
290
|
+
if (rule.startsWith('~')) {
|
|
249
291
|
return this._lang.matchRegExp(ctx.vName, rule.slice(1));
|
|
250
292
|
}
|
|
251
293
|
}
|
|
@@ -253,12 +295,12 @@ class Compiler {
|
|
|
253
295
|
}
|
|
254
296
|
_compileModifiedRule(ctx, rules) {
|
|
255
297
|
if (!rules.length) {
|
|
256
|
-
throw new TypeError(
|
|
298
|
+
throw new TypeError('Unknwon type "[]".');
|
|
257
299
|
}
|
|
258
300
|
/**
|
|
259
301
|
* By default, use OR modifier.
|
|
260
302
|
*/
|
|
261
|
-
if (typeof rules[0] !==
|
|
303
|
+
if (typeof rules[0] !== 'string' ||
|
|
262
304
|
!rules[0].startsWith(I.MODIFIER_PREFIX)) {
|
|
263
305
|
if (rules.length === 1) {
|
|
264
306
|
return this._compile(ctx, rules[0]);
|
|
@@ -313,7 +355,7 @@ class Compiler {
|
|
|
313
355
|
return result;
|
|
314
356
|
}
|
|
315
357
|
_compileModifierOR(ctx, rules) {
|
|
316
|
-
|
|
358
|
+
const result = [];
|
|
317
359
|
for (const r of rules) {
|
|
318
360
|
ctx.trap();
|
|
319
361
|
result.push(this._compile(ctx, r));
|
|
@@ -324,7 +366,7 @@ class Compiler {
|
|
|
324
366
|
_compileModifierAND(ctx, rules) {
|
|
325
367
|
return this._lang.and(rules.map((rule) => this._compile(ctx, rule)));
|
|
326
368
|
}
|
|
327
|
-
_compileModifierLIST(ctx, rules) {
|
|
369
|
+
_compileModifierLIST(ctx, rules, traceOffset = 0) {
|
|
328
370
|
const result = [];
|
|
329
371
|
if (!ctx.flags[I.EFlags.ARRAY]) {
|
|
330
372
|
result.push(this._lang.isArray(ctx.vName, true));
|
|
@@ -334,16 +376,18 @@ class Compiler {
|
|
|
334
376
|
const CLOSURE_ARG = ctx.vName;
|
|
335
377
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
336
378
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
379
|
+
const vIter = this._lang.varName(ctx.vCursor++);
|
|
380
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.numberTemplateVar(traceOffset ? this._lang.add(traceOffset, vIter) : vIter)}]`;
|
|
337
381
|
if (rules[0] !== B.ANY) {
|
|
338
382
|
result.push(this._lang.closure([CLOSURE_PARAM], [CLOSURE_ARG], this._lang.series([
|
|
339
|
-
this._lang.forEach(CLOSURE_PARAM, ctx.vName, this._lang.ifThen(this._lang.not(this._compile(ctx, rules)), this._lang.returnValue(this.
|
|
383
|
+
this._lang.forEach(CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(this._lang.not(this._compile(ctx, rules)), this._lang.returnValue(this._addTrace(ctx)))),
|
|
340
384
|
this._lang.returnValue(this._lang.literal(true))
|
|
341
385
|
])));
|
|
342
386
|
}
|
|
343
387
|
ctx.untrap();
|
|
344
388
|
return this._lang.and(result);
|
|
345
389
|
}
|
|
346
|
-
_compileModifierARRAY(ctx, rules) {
|
|
390
|
+
_compileModifierARRAY(ctx, rules, traceOffset = 0) {
|
|
347
391
|
let a = 0;
|
|
348
392
|
let b = -1;
|
|
349
393
|
if (Number.isInteger(rules[0]) && rules[0] >= 0) {
|
|
@@ -389,6 +433,8 @@ class Compiler {
|
|
|
389
433
|
const CLOSURE_ARG = ctx.vName;
|
|
390
434
|
const CLOSURE_PARAM = this._lang.varName(ctx.vCursor++);
|
|
391
435
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
436
|
+
const vIter = this._lang.varName(ctx.vCursor++);
|
|
437
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.numberTemplateVar(traceOffset ? this._lang.add(traceOffset, vIter) : vIter)}]`;
|
|
392
438
|
switch (b) {
|
|
393
439
|
case -1: {
|
|
394
440
|
result.push(this._lang.eq(this._lang.arrayLength(CLOSURE_ARG), a));
|
|
@@ -405,7 +451,7 @@ class Compiler {
|
|
|
405
451
|
}
|
|
406
452
|
if (rules[1] !== B.ANY) {
|
|
407
453
|
result.push(this._lang.closure([CLOSURE_PARAM], [CLOSURE_ARG], this._lang.series([
|
|
408
|
-
this._lang.forEach(CLOSURE_PARAM, ctx.vName, this._lang.ifThen(this._lang.not(this._compile(ctx, rules.slice(1))), this._lang.returnValue(this.
|
|
454
|
+
this._lang.forEach(CLOSURE_PARAM, vIter, ctx.vName, this._lang.ifThen(this._lang.not(this._compile(ctx, rules.slice(1))), this._lang.returnValue(this._addTrace(ctx)))),
|
|
409
455
|
this._lang.returnValue(this._lang.literal(true))
|
|
410
456
|
])));
|
|
411
457
|
}
|
|
@@ -423,18 +469,19 @@ class Compiler {
|
|
|
423
469
|
let i = 0;
|
|
424
470
|
const types = rules.slice();
|
|
425
471
|
let tupleLength = 0;
|
|
472
|
+
let tupleLengthMin = 0;
|
|
426
473
|
while (1) {
|
|
427
474
|
type = types.shift();
|
|
428
475
|
if (type === undefined) {
|
|
429
476
|
break;
|
|
430
477
|
}
|
|
431
|
-
if (typeof type ===
|
|
478
|
+
if (typeof type === 'string' && type.startsWith('...')) {
|
|
432
479
|
throw new TypeError(`Invalid syntax for tuple: ${JSON.stringify(rules)}`);
|
|
433
480
|
}
|
|
434
|
-
if (typeof types[0] ===
|
|
481
|
+
if (typeof types[0] === 'string' && types[0].startsWith('...')) {
|
|
435
482
|
ctx.trap();
|
|
436
483
|
dots = types.shift();
|
|
437
|
-
if (dots ===
|
|
484
|
+
if (dots === '...') {
|
|
438
485
|
/**
|
|
439
486
|
* No more elements because "..." means all rest elements.
|
|
440
487
|
*/
|
|
@@ -442,9 +489,10 @@ class Compiler {
|
|
|
442
489
|
throw new TypeError(`Invalid syntax for tuple: ${JSON.stringify(rules)}`);
|
|
443
490
|
}
|
|
444
491
|
ctx.vName = this._lang.arraySlice(ctx.vName, i);
|
|
445
|
-
if (type !==
|
|
446
|
-
result.push(this._compileModifierLIST(ctx, type));
|
|
492
|
+
if (type !== 'any') {
|
|
493
|
+
result.push(this._compileModifierLIST(ctx, type, i));
|
|
447
494
|
}
|
|
495
|
+
tupleLengthMin = tupleLength;
|
|
448
496
|
tupleLength = -1;
|
|
449
497
|
}
|
|
450
498
|
else if (!/^\d+$/.test(dots.slice(3))) {
|
|
@@ -452,16 +500,18 @@ class Compiler {
|
|
|
452
500
|
}
|
|
453
501
|
else {
|
|
454
502
|
const length = parseInt(dots.slice(3));
|
|
455
|
-
if (length
|
|
503
|
+
if (length === 0) {
|
|
504
|
+
throw new TypeError(`Invalid syntax for tuple: ${dots}`);
|
|
505
|
+
}
|
|
506
|
+
else if (length === 1) {
|
|
456
507
|
const vName = ctx.vName;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
508
|
+
ctx.tracePath = `${ctx.tracePath}[${i}]`;
|
|
509
|
+
ctx.vName = this._lang.arrayIndex(vName, i++);
|
|
510
|
+
result.push(this._addTraceOr(ctx, this._compile(ctx, type)));
|
|
461
511
|
}
|
|
462
512
|
else {
|
|
463
513
|
ctx.vName = this._lang.arraySlice(ctx.vName, i, i + length);
|
|
464
|
-
result.push(this._compileModifierARRAY(ctx, [length, type]));
|
|
514
|
+
result.push(this._compileModifierARRAY(ctx, [length, type], i));
|
|
465
515
|
i += length;
|
|
466
516
|
}
|
|
467
517
|
tupleLength += length;
|
|
@@ -469,19 +519,23 @@ class Compiler {
|
|
|
469
519
|
}
|
|
470
520
|
else {
|
|
471
521
|
ctx.trap(true);
|
|
522
|
+
ctx.tracePath = `${ctx.tracePath}[${i}]`;
|
|
472
523
|
ctx.vName = this._lang.arrayIndex(ctx.vName, i++);
|
|
473
|
-
result.push(this._compile(ctx, type));
|
|
524
|
+
result.push(this._addTraceOr(ctx, this._compile(ctx, type)));
|
|
474
525
|
tupleLength++;
|
|
475
526
|
}
|
|
476
527
|
ctx.untrap();
|
|
477
528
|
}
|
|
478
529
|
if (tupleLength >= 0) {
|
|
479
|
-
result.splice(1, -1, this._lang.eq(this._lang.arrayLength(ctx.vName), tupleLength));
|
|
530
|
+
result.splice(1, -1, this._addTraceOr(ctx, this._lang.eq(this._lang.arrayLength(ctx.vName), tupleLength), '.length'));
|
|
531
|
+
}
|
|
532
|
+
else if (tupleLengthMin >= 0) {
|
|
533
|
+
result.splice(1, -1, this._addTraceOr(ctx, this._lang.gte(this._lang.arrayLength(ctx.vName), tupleLengthMin), '.length'));
|
|
480
534
|
}
|
|
481
535
|
return this._lang.and(result);
|
|
482
536
|
}
|
|
483
537
|
_validateTypeName(name) {
|
|
484
|
-
if (typeof name !==
|
|
538
|
+
if (typeof name !== 'string' || !I.RE_VALID_CUSTOM_TYPE_NAME.test(name)) {
|
|
485
539
|
throw new TypeError(`Invalid name ${JSON.stringify(name)} for a pre-defined type.`);
|
|
486
540
|
}
|
|
487
541
|
}
|
|
@@ -491,7 +545,8 @@ class Compiler {
|
|
|
491
545
|
throw new Error(`Dplicated name ${JSON.stringify(rules[0])} for a pre-defined type.`);
|
|
492
546
|
}
|
|
493
547
|
this._defTypes[rules[0]] = this.compile({
|
|
494
|
-
rule: rules.slice(1)
|
|
548
|
+
rule: rules.slice(1),
|
|
549
|
+
traceErrors: !!ctx.vTraceName
|
|
495
550
|
});
|
|
496
551
|
return this._usePredefinedType(ctx, rules[0]);
|
|
497
552
|
}
|
|
@@ -520,14 +575,15 @@ class Compiler {
|
|
|
520
575
|
rules = rules[0];
|
|
521
576
|
}
|
|
522
577
|
ctx.trap(true);
|
|
523
|
-
const
|
|
524
|
-
const
|
|
525
|
-
const
|
|
578
|
+
const vCArg = ctx.vName;
|
|
579
|
+
const vCParam = this._lang.varName(ctx.vCursor++);
|
|
580
|
+
const vKey = this._lang.varName(ctx.vCursor++);
|
|
526
581
|
ctx.vName = this._lang.varName(ctx.vCursor++);
|
|
582
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.stringTemplateVar(vKey)}]`;
|
|
527
583
|
const result = this._lang.and([
|
|
528
|
-
this._lang.isStrucutre(
|
|
529
|
-
this._lang.closure([
|
|
530
|
-
this._lang.forIn(
|
|
584
|
+
this._lang.isStrucutre(vCArg, true),
|
|
585
|
+
this._lang.closure([vCParam], [vCArg], this._lang.series([
|
|
586
|
+
this._lang.forIn(vCParam, vKey, ctx.vName, this._lang.ifThen(this._lang.not(this._compile(ctx, rules)), this._lang.returnValue(this._addTrace(ctx)))),
|
|
531
587
|
this._lang.returnValue(this._lang.literal(true))
|
|
532
588
|
]))
|
|
533
589
|
]);
|
|
@@ -538,15 +594,15 @@ class Compiler {
|
|
|
538
594
|
if (rules.length < 2 || !Array.isArray(rules[0])) {
|
|
539
595
|
throw new SyntaxError(`Invalid dict ${JSON.stringify(rules)}.`);
|
|
540
596
|
}
|
|
541
|
-
|
|
597
|
+
const tmp = {};
|
|
542
598
|
const id = `${Date.now()}${Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)}`;
|
|
543
599
|
this._compileModifierTYPE(ctx, [
|
|
544
600
|
this._lang.varName(id),
|
|
545
601
|
rules.slice(1)
|
|
546
602
|
]);
|
|
547
603
|
const type = `${I.PREDEF_TYPE_SYMBOL}${this._lang.varName(id)}`;
|
|
548
|
-
for (
|
|
549
|
-
if (typeof key !==
|
|
604
|
+
for (const key of rules[0]) {
|
|
605
|
+
if (typeof key !== 'string') {
|
|
550
606
|
throw new SyntaxError(`Invalid key ${JSON.stringify(key)} for dict.`);
|
|
551
607
|
}
|
|
552
608
|
tmp[key] = type;
|
|
@@ -556,7 +612,7 @@ class Compiler {
|
|
|
556
612
|
_compileSimpleStructure(ctx, rules) {
|
|
557
613
|
const strict = !!ctx.flags[I.EFlags.STRICT];
|
|
558
614
|
const result = [
|
|
559
|
-
this._lang.isStrucutre(ctx.vName, true)
|
|
615
|
+
this._addTraceOr(ctx, this._lang.isStrucutre(ctx.vName, true), '!object')
|
|
560
616
|
];
|
|
561
617
|
const keys = [];
|
|
562
618
|
for (let k in rules) {
|
|
@@ -584,7 +640,7 @@ class Compiler {
|
|
|
584
640
|
rule = [M.EQUAL, rule];
|
|
585
641
|
}
|
|
586
642
|
else {
|
|
587
|
-
const matchResult =
|
|
643
|
+
const matchResult = I.KEY_ARRAY_SUFFIX.exec(k);
|
|
588
644
|
if (matchResult) {
|
|
589
645
|
k = k.slice(0, matchResult.index);
|
|
590
646
|
if (matchResult[3]) {
|
|
@@ -615,7 +671,8 @@ class Compiler {
|
|
|
615
671
|
}
|
|
616
672
|
keys.push(k);
|
|
617
673
|
ctx.vName = this._lang.fieldIndex(ctx.vName, this._lang.literal(k));
|
|
618
|
-
|
|
674
|
+
ctx.tracePath = `${ctx.tracePath}[${this._lang.literal(k)}]`;
|
|
675
|
+
result.push(this._addTraceOr(ctx, this._compile(ctx, rule)));
|
|
619
676
|
ctx.untrap();
|
|
620
677
|
}
|
|
621
678
|
if (strict && keys.length) {
|
|
@@ -626,7 +683,7 @@ class Compiler {
|
|
|
626
683
|
_compileStructuredRule(ctx, rules) {
|
|
627
684
|
const mapSymbol = Object.keys(rules).filter((x) => x.startsWith(M.MAP));
|
|
628
685
|
if (mapSymbol.length > 1) {
|
|
629
|
-
throw new SyntaxError(
|
|
686
|
+
throw new SyntaxError('Only one \'$.map\' is allowed as rest-mapping.');
|
|
630
687
|
}
|
|
631
688
|
else if (mapSymbol.length === 0) {
|
|
632
689
|
return this._compileSimpleStructure(ctx, rules);
|
|
@@ -666,7 +723,7 @@ class Compiler {
|
|
|
666
723
|
rule = [M.EQUAL, rule];
|
|
667
724
|
}
|
|
668
725
|
else {
|
|
669
|
-
const matchResult =
|
|
726
|
+
const matchResult = I.KEY_ARRAY_SUFFIX.exec(k);
|
|
670
727
|
if (matchResult) {
|
|
671
728
|
k = k.slice(0, matchResult.index);
|
|
672
729
|
if (matchResult[3]) {
|
|
@@ -718,7 +775,7 @@ class Compiler {
|
|
|
718
775
|
}
|
|
719
776
|
_isOrRule(rule) {
|
|
720
777
|
return Array.isArray(rule) && (rule[0] === M.OR ||
|
|
721
|
-
typeof rule[0] !==
|
|
778
|
+
typeof rule[0] !== 'string' ||
|
|
722
779
|
!rule[0].startsWith(I.MODIFIER_PREFIX));
|
|
723
780
|
}
|
|
724
781
|
}
|