@nocobase/plugin-workflow-request-interceptor 2.0.25 → 2.1.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/RequestInterceptionTrigger.d.ts +10 -0
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -0
- package/dist/node_modules/joi/lib/annotate.js +175 -0
- package/dist/node_modules/joi/lib/base.js +1069 -0
- package/dist/node_modules/joi/lib/cache.js +143 -0
- package/dist/node_modules/joi/lib/common.js +216 -0
- package/dist/node_modules/joi/lib/compile.js +283 -0
- package/dist/node_modules/joi/lib/errors.js +271 -0
- package/dist/node_modules/joi/lib/extend.js +312 -0
- package/dist/node_modules/joi/lib/index.d.ts +2365 -0
- package/dist/node_modules/joi/lib/index.js +1 -0
- package/dist/node_modules/joi/lib/manifest.js +476 -0
- package/dist/node_modules/joi/lib/messages.js +178 -0
- package/dist/node_modules/joi/lib/modify.js +267 -0
- package/dist/node_modules/joi/lib/ref.js +414 -0
- package/dist/node_modules/joi/lib/schemas.js +302 -0
- package/dist/node_modules/joi/lib/state.js +166 -0
- package/dist/node_modules/joi/lib/template.js +463 -0
- package/dist/node_modules/joi/lib/trace.js +346 -0
- package/dist/node_modules/joi/lib/types/alternatives.js +364 -0
- package/dist/node_modules/joi/lib/types/any.js +174 -0
- package/dist/node_modules/joi/lib/types/array.js +809 -0
- package/dist/node_modules/joi/lib/types/binary.js +100 -0
- package/dist/node_modules/joi/lib/types/boolean.js +150 -0
- package/dist/node_modules/joi/lib/types/date.js +233 -0
- package/dist/node_modules/joi/lib/types/function.js +93 -0
- package/dist/node_modules/joi/lib/types/keys.js +1067 -0
- package/dist/node_modules/joi/lib/types/link.js +168 -0
- package/dist/node_modules/joi/lib/types/number.js +363 -0
- package/dist/node_modules/joi/lib/types/object.js +22 -0
- package/dist/node_modules/joi/lib/types/string.js +850 -0
- package/dist/node_modules/joi/lib/types/symbol.js +102 -0
- package/dist/node_modules/joi/lib/validator.js +750 -0
- package/dist/node_modules/joi/lib/values.js +263 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.d.ts +60 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.js +225 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/package.json +30 -0
- package/dist/node_modules/joi/package.json +1 -0
- package/dist/server/RequestInterceptionTrigger.d.ts +3 -0
- package/dist/server/RequestInterceptionTrigger.js +11 -0
- package/package.json +5 -2
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DeepEqual = require('@hapi/hoek/lib/deepEqual');
|
|
4
|
+
const Pinpoint = require('@sideway/pinpoint');
|
|
5
|
+
|
|
6
|
+
const Errors = require('./errors');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const internals = {
|
|
10
|
+
codes: {
|
|
11
|
+
error: 1,
|
|
12
|
+
pass: 2,
|
|
13
|
+
full: 3
|
|
14
|
+
},
|
|
15
|
+
labels: {
|
|
16
|
+
0: 'never used',
|
|
17
|
+
1: 'always error',
|
|
18
|
+
2: 'always pass'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
exports.setup = function (root) {
|
|
24
|
+
|
|
25
|
+
const trace = function () {
|
|
26
|
+
|
|
27
|
+
root._tracer = root._tracer || new internals.Tracer();
|
|
28
|
+
return root._tracer;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
root.trace = trace;
|
|
32
|
+
root[Symbol.for('@hapi/lab/coverage/initialize')] = trace;
|
|
33
|
+
|
|
34
|
+
root.untrace = () => {
|
|
35
|
+
|
|
36
|
+
root._tracer = null;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
exports.location = function (schema) {
|
|
42
|
+
|
|
43
|
+
return schema.$_setFlag('_tracerLocation', Pinpoint.location(2)); // base.tracer(), caller
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
internals.Tracer = class {
|
|
48
|
+
|
|
49
|
+
constructor() {
|
|
50
|
+
|
|
51
|
+
this.name = 'Joi';
|
|
52
|
+
this._schemas = new Map();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_register(schema) {
|
|
56
|
+
|
|
57
|
+
const existing = this._schemas.get(schema);
|
|
58
|
+
if (existing) {
|
|
59
|
+
return existing.store;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const store = new internals.Store(schema);
|
|
63
|
+
const { filename, line } = schema._flags._tracerLocation || Pinpoint.location(5); // internals.tracer(), internals.entry(), exports.entry(), validate(), caller
|
|
64
|
+
this._schemas.set(schema, { filename, line, store });
|
|
65
|
+
return store;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_combine(merged, sources) {
|
|
69
|
+
|
|
70
|
+
for (const { store } of this._schemas.values()) {
|
|
71
|
+
store._combine(merged, sources);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
report(file) {
|
|
76
|
+
|
|
77
|
+
const coverage = [];
|
|
78
|
+
|
|
79
|
+
// Process each registered schema
|
|
80
|
+
|
|
81
|
+
for (const { filename, line, store } of this._schemas.values()) {
|
|
82
|
+
if (file &&
|
|
83
|
+
file !== filename) {
|
|
84
|
+
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Process sub schemas of the registered root
|
|
89
|
+
|
|
90
|
+
const missing = [];
|
|
91
|
+
const skipped = [];
|
|
92
|
+
|
|
93
|
+
for (const [schema, log] of store._sources.entries()) {
|
|
94
|
+
|
|
95
|
+
// Check if sub schema parent skipped
|
|
96
|
+
|
|
97
|
+
if (internals.sub(log.paths, skipped)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check if sub schema reached
|
|
102
|
+
|
|
103
|
+
if (!log.entry) {
|
|
104
|
+
missing.push({
|
|
105
|
+
status: 'never reached',
|
|
106
|
+
paths: [...log.paths]
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
skipped.push(...log.paths);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check values
|
|
114
|
+
|
|
115
|
+
for (const type of ['valid', 'invalid']) {
|
|
116
|
+
const set = schema[`_${type}s`];
|
|
117
|
+
if (!set) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const values = new Set(set._values);
|
|
122
|
+
const refs = new Set(set._refs);
|
|
123
|
+
for (const { value, ref } of log[type]) {
|
|
124
|
+
values.delete(value);
|
|
125
|
+
refs.delete(ref);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (values.size ||
|
|
129
|
+
refs.size) {
|
|
130
|
+
|
|
131
|
+
missing.push({
|
|
132
|
+
status: [...values, ...[...refs].map((ref) => ref.display)],
|
|
133
|
+
rule: `${type}s`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Check rules status
|
|
139
|
+
|
|
140
|
+
const rules = schema._rules.map((rule) => rule.name);
|
|
141
|
+
for (const type of ['default', 'failover']) {
|
|
142
|
+
if (schema._flags[type] !== undefined) {
|
|
143
|
+
rules.push(type);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const name of rules) {
|
|
148
|
+
const status = internals.labels[log.rule[name] || 0];
|
|
149
|
+
if (status) {
|
|
150
|
+
const report = { rule: name, status };
|
|
151
|
+
if (log.paths.size) {
|
|
152
|
+
report.paths = [...log.paths];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
missing.push(report);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (missing.length) {
|
|
161
|
+
coverage.push({
|
|
162
|
+
filename,
|
|
163
|
+
line,
|
|
164
|
+
missing,
|
|
165
|
+
severity: 'error',
|
|
166
|
+
message: `Schema missing tests for ${missing.map(internals.message).join(', ')}`
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return coverage.length ? coverage : null;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
internals.Store = class {
|
|
177
|
+
|
|
178
|
+
constructor(schema) {
|
|
179
|
+
|
|
180
|
+
this.active = true;
|
|
181
|
+
this._sources = new Map(); // schema -> { paths, entry, rule, valid, invalid }
|
|
182
|
+
this._combos = new Map(); // merged -> [sources]
|
|
183
|
+
this._scan(schema);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
debug(state, source, name, result) {
|
|
187
|
+
|
|
188
|
+
state.mainstay.debug && state.mainstay.debug.push({ type: source, name, result, path: state.path });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
entry(schema, state) {
|
|
192
|
+
|
|
193
|
+
internals.debug(state, { type: 'entry' });
|
|
194
|
+
|
|
195
|
+
this._record(schema, (log) => {
|
|
196
|
+
|
|
197
|
+
log.entry = true;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
filter(schema, state, source, value) {
|
|
202
|
+
|
|
203
|
+
internals.debug(state, { type: source, ...value });
|
|
204
|
+
|
|
205
|
+
this._record(schema, (log) => {
|
|
206
|
+
|
|
207
|
+
log[source].add(value);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
log(schema, state, source, name, result) {
|
|
212
|
+
|
|
213
|
+
internals.debug(state, { type: source, name, result: result === 'full' ? 'pass' : result });
|
|
214
|
+
|
|
215
|
+
this._record(schema, (log) => {
|
|
216
|
+
|
|
217
|
+
log[source][name] = log[source][name] || 0;
|
|
218
|
+
log[source][name] |= internals.codes[result];
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
resolve(state, ref, to) {
|
|
223
|
+
|
|
224
|
+
if (!state.mainstay.debug) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const log = { type: 'resolve', ref: ref.display, to, path: state.path };
|
|
229
|
+
state.mainstay.debug.push(log);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
value(state, by, from, to, name) {
|
|
233
|
+
|
|
234
|
+
if (!state.mainstay.debug ||
|
|
235
|
+
DeepEqual(from, to)) {
|
|
236
|
+
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const log = { type: 'value', by, from, to, path: state.path };
|
|
241
|
+
if (name) {
|
|
242
|
+
log.name = name;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
state.mainstay.debug.push(log);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_record(schema, each) {
|
|
249
|
+
|
|
250
|
+
const log = this._sources.get(schema);
|
|
251
|
+
if (log) {
|
|
252
|
+
each(log);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const sources = this._combos.get(schema);
|
|
257
|
+
for (const source of sources) {
|
|
258
|
+
this._record(source, each);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
_scan(schema, _path) {
|
|
263
|
+
|
|
264
|
+
const path = _path || [];
|
|
265
|
+
|
|
266
|
+
let log = this._sources.get(schema);
|
|
267
|
+
if (!log) {
|
|
268
|
+
log = {
|
|
269
|
+
paths: new Set(),
|
|
270
|
+
entry: false,
|
|
271
|
+
rule: {},
|
|
272
|
+
valid: new Set(),
|
|
273
|
+
invalid: new Set()
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
this._sources.set(schema, log);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (path.length) {
|
|
280
|
+
log.paths.add(path);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const each = (sub, source) => {
|
|
284
|
+
|
|
285
|
+
const subId = internals.id(sub, source);
|
|
286
|
+
this._scan(sub, path.concat(subId));
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
schema.$_modify({ each, ref: false });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_combine(merged, sources) {
|
|
293
|
+
|
|
294
|
+
this._combos.set(merged, sources);
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
internals.message = function (item) {
|
|
300
|
+
|
|
301
|
+
const path = item.paths ? Errors.path(item.paths[0]) + (item.rule ? ':' : '') : '';
|
|
302
|
+
return `${path}${item.rule || ''} (${item.status})`;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
internals.id = function (schema, { source, name, path, key }) {
|
|
307
|
+
|
|
308
|
+
if (schema._flags.id) {
|
|
309
|
+
return schema._flags.id;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (key) {
|
|
313
|
+
return key;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
name = `@${name}`;
|
|
317
|
+
|
|
318
|
+
if (source === 'terms') {
|
|
319
|
+
return [name, path[Math.min(path.length - 1, 1)]];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return name;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
internals.sub = function (paths, skipped) {
|
|
327
|
+
|
|
328
|
+
for (const path of paths) {
|
|
329
|
+
for (const skip of skipped) {
|
|
330
|
+
if (DeepEqual(path.slice(0, skip.length), skip)) {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return false;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
internals.debug = function (state, event) {
|
|
341
|
+
|
|
342
|
+
if (state.mainstay.debug) {
|
|
343
|
+
event.path = state.debug ? [...state.path, state.debug] : state.path;
|
|
344
|
+
state.mainstay.debug.push(event);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Assert = require('@hapi/hoek/lib/assert');
|
|
4
|
+
const Merge = require('@hapi/hoek/lib/merge');
|
|
5
|
+
|
|
6
|
+
const Any = require('./any');
|
|
7
|
+
const Common = require('../common');
|
|
8
|
+
const Compile = require('../compile');
|
|
9
|
+
const Errors = require('../errors');
|
|
10
|
+
const Ref = require('../ref');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const internals = {};
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
module.exports = Any.extend({
|
|
17
|
+
|
|
18
|
+
type: 'alternatives',
|
|
19
|
+
|
|
20
|
+
flags: {
|
|
21
|
+
|
|
22
|
+
match: { default: 'any' } // 'any', 'one', 'all'
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
terms: {
|
|
26
|
+
|
|
27
|
+
matches: { init: [], register: Ref.toSibling }
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
args(schema, ...schemas) {
|
|
31
|
+
|
|
32
|
+
if (schemas.length === 1) {
|
|
33
|
+
if (Array.isArray(schemas[0])) {
|
|
34
|
+
return schema.try(...schemas[0]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return schema.try(...schemas);
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
validate(value, helpers) {
|
|
42
|
+
|
|
43
|
+
const { schema, error, state, prefs } = helpers;
|
|
44
|
+
|
|
45
|
+
// Match all or one
|
|
46
|
+
|
|
47
|
+
if (schema._flags.match) {
|
|
48
|
+
const matched = [];
|
|
49
|
+
const failed = [];
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < schema.$_terms.matches.length; ++i) {
|
|
52
|
+
const item = schema.$_terms.matches[i];
|
|
53
|
+
const localState = state.nest(item.schema, `match.${i}`);
|
|
54
|
+
localState.snapshot();
|
|
55
|
+
|
|
56
|
+
const result = item.schema.$_validate(value, localState, prefs);
|
|
57
|
+
if (!result.errors) {
|
|
58
|
+
matched.push(result.value);
|
|
59
|
+
localState.commit();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
failed.push(result.errors);
|
|
63
|
+
localState.restore();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (matched.length === 0) {
|
|
68
|
+
const context = {
|
|
69
|
+
details: failed.map((f) => Errors.details(f, { override: false }))
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return { errors: error('alternatives.any', context) };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Match one
|
|
76
|
+
|
|
77
|
+
if (schema._flags.match === 'one') {
|
|
78
|
+
return matched.length === 1 ? { value: matched[0] } : { errors: error('alternatives.one') };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Match all
|
|
82
|
+
|
|
83
|
+
if (matched.length !== schema.$_terms.matches.length) {
|
|
84
|
+
const context = {
|
|
85
|
+
details: failed.map((f) => Errors.details(f, { override: false }))
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return { errors: error('alternatives.all', context) };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const isAnyObj = (alternative) => {
|
|
92
|
+
|
|
93
|
+
return alternative.$_terms.matches.some((v) => {
|
|
94
|
+
|
|
95
|
+
return v.schema.type === 'object' ||
|
|
96
|
+
(v.schema.type === 'alternatives' && isAnyObj(v.schema));
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return isAnyObj(schema) ? { value: matched.reduce((acc, v) => Merge(acc, v, { mergeArrays: false })) } : { value: matched[matched.length - 1] };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Match any
|
|
104
|
+
|
|
105
|
+
const errors = [];
|
|
106
|
+
for (let i = 0; i < schema.$_terms.matches.length; ++i) {
|
|
107
|
+
const item = schema.$_terms.matches[i];
|
|
108
|
+
|
|
109
|
+
// Try
|
|
110
|
+
|
|
111
|
+
if (item.schema) {
|
|
112
|
+
const localState = state.nest(item.schema, `match.${i}`);
|
|
113
|
+
localState.snapshot();
|
|
114
|
+
|
|
115
|
+
const result = item.schema.$_validate(value, localState, prefs);
|
|
116
|
+
if (!result.errors) {
|
|
117
|
+
localState.commit();
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
localState.restore();
|
|
122
|
+
errors.push({ schema: item.schema, reports: result.errors });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Conditional
|
|
127
|
+
|
|
128
|
+
const input = item.ref ? item.ref.resolve(value, state, prefs) : value;
|
|
129
|
+
const tests = item.is ? [item] : item.switch;
|
|
130
|
+
|
|
131
|
+
for (let j = 0; j < tests.length; ++j) {
|
|
132
|
+
const test = tests[j];
|
|
133
|
+
const { is, then, otherwise } = test;
|
|
134
|
+
|
|
135
|
+
const id = `match.${i}${item.switch ? '.' + j : ''}`;
|
|
136
|
+
if (!is.$_match(input, state.nest(is, `${id}.is`), prefs)) {
|
|
137
|
+
if (otherwise) {
|
|
138
|
+
return otherwise.$_validate(value, state.nest(otherwise, `${id}.otherwise`), prefs);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (then) {
|
|
142
|
+
return then.$_validate(value, state.nest(then, `${id}.then`), prefs);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return internals.errors(errors, helpers);
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
rules: {
|
|
151
|
+
|
|
152
|
+
conditional: {
|
|
153
|
+
method(condition, options) {
|
|
154
|
+
|
|
155
|
+
Assert(!this._flags._endedSwitch, 'Unreachable condition');
|
|
156
|
+
Assert(!this._flags.match, 'Cannot combine match mode', this._flags.match, 'with conditional rule');
|
|
157
|
+
Assert(options.break === undefined, 'Cannot use break option with alternatives conditional');
|
|
158
|
+
|
|
159
|
+
const obj = this.clone();
|
|
160
|
+
|
|
161
|
+
const match = Compile.when(obj, condition, options);
|
|
162
|
+
const conditions = match.is ? [match] : match.switch;
|
|
163
|
+
for (const item of conditions) {
|
|
164
|
+
if (item.then &&
|
|
165
|
+
item.otherwise) {
|
|
166
|
+
|
|
167
|
+
obj.$_setFlag('_endedSwitch', true, { clone: false });
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
obj.$_terms.matches.push(match);
|
|
173
|
+
return obj.$_mutateRebuild();
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
match: {
|
|
178
|
+
method(mode) {
|
|
179
|
+
|
|
180
|
+
Assert(['any', 'one', 'all'].includes(mode), 'Invalid alternatives match mode', mode);
|
|
181
|
+
|
|
182
|
+
if (mode !== 'any') {
|
|
183
|
+
for (const match of this.$_terms.matches) {
|
|
184
|
+
Assert(match.schema, 'Cannot combine match mode', mode, 'with conditional rules');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return this.$_setFlag('match', mode);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
try: {
|
|
193
|
+
method(...schemas) {
|
|
194
|
+
|
|
195
|
+
Assert(schemas.length, 'Missing alternative schemas');
|
|
196
|
+
Common.verifyFlat(schemas, 'try');
|
|
197
|
+
|
|
198
|
+
Assert(!this._flags._endedSwitch, 'Unreachable condition');
|
|
199
|
+
|
|
200
|
+
const obj = this.clone();
|
|
201
|
+
for (const schema of schemas) {
|
|
202
|
+
obj.$_terms.matches.push({ schema: obj.$_compile(schema) });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return obj.$_mutateRebuild();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
overrides: {
|
|
211
|
+
|
|
212
|
+
label(name) {
|
|
213
|
+
|
|
214
|
+
const obj = this.$_parent('label', name);
|
|
215
|
+
const each = (item, source) => {
|
|
216
|
+
|
|
217
|
+
return source.path[0] !== 'is' && typeof item._flags.label !== 'string' ? item.label(name) : undefined;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
return obj.$_modify({ each, ref: false });
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
rebuild(schema) {
|
|
225
|
+
|
|
226
|
+
// Flag when an alternative type is an array
|
|
227
|
+
|
|
228
|
+
const each = (item) => {
|
|
229
|
+
|
|
230
|
+
if (Common.isSchema(item) &&
|
|
231
|
+
item.type === 'array') {
|
|
232
|
+
|
|
233
|
+
schema.$_setFlag('_arrayItems', true, { clone: false });
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
schema.$_modify({ each });
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
manifest: {
|
|
241
|
+
|
|
242
|
+
build(obj, desc) {
|
|
243
|
+
|
|
244
|
+
if (desc.matches) {
|
|
245
|
+
for (const match of desc.matches) {
|
|
246
|
+
const { schema, ref, is, not, then, otherwise } = match;
|
|
247
|
+
if (schema) {
|
|
248
|
+
obj = obj.try(schema);
|
|
249
|
+
}
|
|
250
|
+
else if (ref) {
|
|
251
|
+
obj = obj.conditional(ref, { is, then, not, otherwise, switch: match.switch });
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
obj = obj.conditional(is, { then, otherwise });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return obj;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
messages: {
|
|
264
|
+
'alternatives.all': '{{#label}} does not match all of the required types',
|
|
265
|
+
'alternatives.any': '{{#label}} does not match any of the allowed types',
|
|
266
|
+
'alternatives.match': '{{#label}} does not match any of the allowed types',
|
|
267
|
+
'alternatives.one': '{{#label}} matches more than one allowed type',
|
|
268
|
+
'alternatives.types': '{{#label}} must be one of {{#types}}'
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
// Helpers
|
|
274
|
+
|
|
275
|
+
internals.errors = function (failures, { error, state }) {
|
|
276
|
+
|
|
277
|
+
// Nothing matched due to type criteria rules
|
|
278
|
+
|
|
279
|
+
if (!failures.length) {
|
|
280
|
+
return { errors: error('alternatives.any') };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Single error
|
|
284
|
+
|
|
285
|
+
if (failures.length === 1) {
|
|
286
|
+
return { errors: failures[0].reports };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Analyze reasons
|
|
290
|
+
|
|
291
|
+
const valids = new Set();
|
|
292
|
+
const complex = [];
|
|
293
|
+
|
|
294
|
+
for (const { reports, schema } of failures) {
|
|
295
|
+
|
|
296
|
+
// Multiple errors (!abortEarly)
|
|
297
|
+
|
|
298
|
+
if (reports.length > 1) {
|
|
299
|
+
return internals.unmatched(failures, error);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Custom error
|
|
303
|
+
|
|
304
|
+
const report = reports[0];
|
|
305
|
+
if (report instanceof Errors.Report === false) {
|
|
306
|
+
return internals.unmatched(failures, error);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Internal object or array error
|
|
310
|
+
|
|
311
|
+
if (report.state.path.length !== state.path.length) {
|
|
312
|
+
complex.push({ type: schema.type, report });
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Valids
|
|
317
|
+
|
|
318
|
+
if (report.code === 'any.only') {
|
|
319
|
+
for (const valid of report.local.valids) {
|
|
320
|
+
valids.add(valid);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Base type
|
|
327
|
+
|
|
328
|
+
const [type, code] = report.code.split('.');
|
|
329
|
+
if (code !== 'base') {
|
|
330
|
+
complex.push({ type: schema.type, report });
|
|
331
|
+
}
|
|
332
|
+
else if (report.code === 'object.base') {
|
|
333
|
+
valids.add(report.local.type);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
valids.add(type);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// All errors are base types or valids
|
|
341
|
+
|
|
342
|
+
if (!complex.length) {
|
|
343
|
+
return { errors: error('alternatives.types', { types: [...valids] }) };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Single complex error
|
|
347
|
+
|
|
348
|
+
if (complex.length === 1) {
|
|
349
|
+
return { errors: complex[0].report };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return internals.unmatched(failures, error);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
internals.unmatched = function (failures, error) {
|
|
357
|
+
|
|
358
|
+
const errors = [];
|
|
359
|
+
for (const failure of failures) {
|
|
360
|
+
errors.push(...failure.reports);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return { errors: error('alternatives.match', Errors.details(errors, { override: false })) };
|
|
364
|
+
};
|