@piying/view-angular-core 1.7.2 → 1.7.3
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/adapter/index.d.ts +52 -0
- package/fesm2022/piying-view-angular-core-adapter.mjs +1183 -0
- package/fesm2022/piying-view-angular-core-adapter.mjs.map +1 -0
- package/fesm2022/piying-view-angular-core.mjs +56 -57
- package/fesm2022/piying-view-angular-core.mjs.map +1 -1
- package/index.d.ts +4 -3
- package/package.json +5 -1
|
@@ -0,0 +1,1183 @@
|
|
|
1
|
+
import { map, switchMap } from 'rxjs/operators';
|
|
2
|
+
import rfdc from 'rfdc';
|
|
3
|
+
import * as v from 'valibot';
|
|
4
|
+
import * as jsonActions from '@piying/view-angular-core';
|
|
5
|
+
import { hideWhen, formConfig } from '@piying/view-angular-core';
|
|
6
|
+
import { isString, isNil, intersection, isBoolean, isUndefined, union, uniq } from 'es-toolkit';
|
|
7
|
+
import { BehaviorSubject } from 'rxjs';
|
|
8
|
+
import { schema } from '@piying/valibot-visit';
|
|
9
|
+
import { deepEqual } from 'fast-equals';
|
|
10
|
+
|
|
11
|
+
function createImpasseAction(key, value) {
|
|
12
|
+
return v.rawCheck(({ dataset, addIssue }) => {
|
|
13
|
+
if (dataset.issues) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
addIssue({
|
|
17
|
+
label: `impasse:${key}`,
|
|
18
|
+
expected: '[no validation conflict]',
|
|
19
|
+
received: value,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function isNumber(value) {
|
|
24
|
+
return typeof value === 'number';
|
|
25
|
+
}
|
|
26
|
+
const anyType = [
|
|
27
|
+
'object',
|
|
28
|
+
'array',
|
|
29
|
+
'string',
|
|
30
|
+
'number',
|
|
31
|
+
'boolean',
|
|
32
|
+
'null',
|
|
33
|
+
'integer',
|
|
34
|
+
];
|
|
35
|
+
// todo 先按照类型不可变设计,之后修改代码支持组件变更
|
|
36
|
+
const clone = rfdc({ proto: false, circles: false });
|
|
37
|
+
function getMetadataAction(schema) {
|
|
38
|
+
const action = [];
|
|
39
|
+
if (isString(schema.title)) {
|
|
40
|
+
action.push(v.title(schema.title));
|
|
41
|
+
}
|
|
42
|
+
if (isString(schema.description)) {
|
|
43
|
+
action.push(v.description(schema.description));
|
|
44
|
+
}
|
|
45
|
+
return action;
|
|
46
|
+
}
|
|
47
|
+
function arrayIntersection(a, b) {
|
|
48
|
+
if (!isNil(a) && !isNil(b)) {
|
|
49
|
+
a = Array.isArray(a) ? a : [a];
|
|
50
|
+
b = Array.isArray(b) ? b : [b];
|
|
51
|
+
if (a.length && b.length) {
|
|
52
|
+
const result = intersection(a, b);
|
|
53
|
+
if (result.length === 0) {
|
|
54
|
+
return {
|
|
55
|
+
action: createImpasseAction('applicator'),
|
|
56
|
+
value: undefined,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return { value: result };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
value: a.length ? a : b,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return { value: a ?? b };
|
|
68
|
+
}
|
|
69
|
+
// 应该传入定制
|
|
70
|
+
function jsonSchemaToValibot(schema, options) {
|
|
71
|
+
return new JsonSchemaToValibot(schema, options).convert();
|
|
72
|
+
}
|
|
73
|
+
const Schema2012 = 'https://json-schema.org/draft/2020-12/schema';
|
|
74
|
+
class JsonSchemaToValibot {
|
|
75
|
+
root;
|
|
76
|
+
#options;
|
|
77
|
+
cacheSchema = new WeakMap();
|
|
78
|
+
constructor(root, options) {
|
|
79
|
+
this.root = root;
|
|
80
|
+
this.#options = options;
|
|
81
|
+
root.$schema ??= Schema2012;
|
|
82
|
+
}
|
|
83
|
+
convert() {
|
|
84
|
+
return this.#jSchemaToVSchema(clone(this.root));
|
|
85
|
+
}
|
|
86
|
+
#applicatorParse(schema$1) {
|
|
87
|
+
let vSchema;
|
|
88
|
+
if (schema$1.allOf) {
|
|
89
|
+
const result = this.#mergeSchema(schema$1, ...schema$1.allOf);
|
|
90
|
+
vSchema = v.pipe(this.#jsonSchemaBase(result.schema, () => result.actionList));
|
|
91
|
+
}
|
|
92
|
+
else if (schema$1.anyOf) {
|
|
93
|
+
vSchema = this.#conditionCreate(schema$1, {
|
|
94
|
+
useOr: false,
|
|
95
|
+
getChildren: () => schema$1.anyOf,
|
|
96
|
+
conditionCheckActionFn(childOriginSchemaList, getActivateList) {
|
|
97
|
+
return v.rawCheck(({ dataset, addIssue }) => {
|
|
98
|
+
if (dataset.issues) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
let childFailedResult;
|
|
102
|
+
// 验证项全为可选,所以需要这里再次验证
|
|
103
|
+
const hasSuccess = childOriginSchemaList.some((item, index) => {
|
|
104
|
+
const isActive = getActivateList()[index];
|
|
105
|
+
if (!isActive) {
|
|
106
|
+
childFailedResult ??= { index: index };
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const result = v.safeParse(item, dataset.value);
|
|
110
|
+
if (!result.success) {
|
|
111
|
+
childFailedResult = { index: index, issues: result.issues };
|
|
112
|
+
}
|
|
113
|
+
return result.success;
|
|
114
|
+
});
|
|
115
|
+
if (!hasSuccess) {
|
|
116
|
+
const extMessage = childFailedResult?.issues
|
|
117
|
+
?.map((item) => item.message)
|
|
118
|
+
.join(',') ?? '';
|
|
119
|
+
addIssue({
|
|
120
|
+
label: `anyOf:${childFailedResult?.index ?? ''}:${extMessage}`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
conditionSchemaFn(baseSchema, conditionVSchema, childSchemaList) {
|
|
126
|
+
return v.pipe(v.intersect([
|
|
127
|
+
conditionVSchema,
|
|
128
|
+
baseSchema,
|
|
129
|
+
schema.intersect(childSchemaList.map((item) => v.pipe(v.optional(item), jsonActions.renderConfig({ hidden: true })))),
|
|
130
|
+
]), jsonActions.setComponent('anyOf-condition'));
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else if (schema$1.oneOf) {
|
|
135
|
+
vSchema = this.#conditionCreate(schema$1, {
|
|
136
|
+
useOr: true,
|
|
137
|
+
getChildren() {
|
|
138
|
+
return schema$1.oneOf;
|
|
139
|
+
},
|
|
140
|
+
conditionCheckActionFn(childOriginSchemaList, getActivateList) {
|
|
141
|
+
return v.rawCheck(({ dataset, addIssue }) => {
|
|
142
|
+
if (dataset.issues) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// 验证项全为可选,所以需要这里再次验证
|
|
146
|
+
const hasSuccess = childOriginSchemaList.filter((item, index) => {
|
|
147
|
+
const isActive = getActivateList()[index];
|
|
148
|
+
if (!isActive) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const result = v.safeParse(item, dataset.value);
|
|
152
|
+
return result.success;
|
|
153
|
+
});
|
|
154
|
+
if (hasSuccess.length !== 1) {
|
|
155
|
+
addIssue({
|
|
156
|
+
label: `oneOf`,
|
|
157
|
+
expected: '1',
|
|
158
|
+
received: `${hasSuccess.length}`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
conditionSchemaFn(baseSchema, conditionVSchema, childSchemaList) {
|
|
164
|
+
return v.pipe(schema.intersect([
|
|
165
|
+
conditionVSchema,
|
|
166
|
+
baseSchema,
|
|
167
|
+
v.union(childSchemaList.map((item) => v.pipe(item, jsonActions.renderConfig({ hidden: true })))),
|
|
168
|
+
]), jsonActions.setComponent('oneOf-condition'));
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
else if ('if' in schema$1) {
|
|
173
|
+
/**
|
|
174
|
+
* 当前设计中if/then/else是采用的分离显示
|
|
175
|
+
* 也就是then/else都会合并base,然后按条件展示,
|
|
176
|
+
*/
|
|
177
|
+
const useThen$ = new BehaviorSubject(undefined);
|
|
178
|
+
const baseSchema = v.pipe(this.#jsonSchemaBase(schema$1, () => [
|
|
179
|
+
...this.#getValidationAction(schema$1),
|
|
180
|
+
hideWhen({
|
|
181
|
+
disabled: false,
|
|
182
|
+
listen: (fn) => fn({}).pipe(map(({ list: [value], field }) => {
|
|
183
|
+
const isThen = isBoolean(schema$1.if)
|
|
184
|
+
? schema$1.if
|
|
185
|
+
: v.safeParse(ifVSchema, value).success;
|
|
186
|
+
field.form.parent.activateIndex$.set(isThen ? 1 : 2);
|
|
187
|
+
useThen$.next(isThen);
|
|
188
|
+
return !((isThen && !thenSchema) || (!isThen && !elseSchema));
|
|
189
|
+
})),
|
|
190
|
+
}),
|
|
191
|
+
]));
|
|
192
|
+
/** 仅为验证项,非显示用 */
|
|
193
|
+
let ifVSchema;
|
|
194
|
+
if (isBoolean(schema$1.if)) {
|
|
195
|
+
ifVSchema = v.literal(schema$1.if);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const ifSchema = this.#mergeSchema(schema$1, schema$1.if);
|
|
199
|
+
ifVSchema = v.pipe(this.#jsonSchemaBase(ifSchema.schema, () => ifSchema.actionList));
|
|
200
|
+
}
|
|
201
|
+
function hideAction(isThen) {
|
|
202
|
+
return [
|
|
203
|
+
jsonActions.renderConfig({ hidden: true }),
|
|
204
|
+
hideWhen({
|
|
205
|
+
disabled: true,
|
|
206
|
+
listen(fn) {
|
|
207
|
+
return fn({ list: [['..', 0]] }).pipe(switchMap(({ list: [] }) => useThen$), map((a) => (a === undefined ? true : isThen ? !a : a)));
|
|
208
|
+
},
|
|
209
|
+
}),
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
let thenSchema;
|
|
213
|
+
if (schema$1.then && !isBoolean(schema$1.then)) {
|
|
214
|
+
const subSchema = this.#mergeSchema(schema$1, schema$1.then);
|
|
215
|
+
thenSchema = v.pipe(this.#jsonSchemaBase(subSchema.schema, () => [
|
|
216
|
+
...subSchema.actionList,
|
|
217
|
+
...hideAction(true),
|
|
218
|
+
]));
|
|
219
|
+
}
|
|
220
|
+
let elseSchema;
|
|
221
|
+
if (schema$1.else && !isBoolean(schema$1.else)) {
|
|
222
|
+
const subSchema = this.#mergeSchema(schema$1, schema$1.else);
|
|
223
|
+
elseSchema = v.pipe(this.#jsonSchemaBase(subSchema.schema, () => [
|
|
224
|
+
...subSchema.actionList,
|
|
225
|
+
...hideAction(false),
|
|
226
|
+
]));
|
|
227
|
+
}
|
|
228
|
+
// 这种逻辑没问题,因为jsonschema验证中,也会出现base和子级架构一起验证
|
|
229
|
+
vSchema = v.pipe(v.union([
|
|
230
|
+
baseSchema,
|
|
231
|
+
thenSchema ?? baseSchema,
|
|
232
|
+
elseSchema ?? baseSchema,
|
|
233
|
+
].filter(Boolean)), formConfig({ disableOrUpdateActivate: true }), v.rawCheck(({ dataset, addIssue }) => {
|
|
234
|
+
if (dataset.issues) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const status = useThen$.value;
|
|
238
|
+
if (status && thenSchema) {
|
|
239
|
+
const result = v.safeParse(thenSchema, dataset.value);
|
|
240
|
+
if (!result.success) {
|
|
241
|
+
addIssue();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (!status && elseSchema) {
|
|
246
|
+
const result = v.safeParse(elseSchema, dataset.value);
|
|
247
|
+
if (!result.success) {
|
|
248
|
+
addIssue();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
vSchema = v.pipe(
|
|
256
|
+
// 通用部分
|
|
257
|
+
this.#jsonSchemaBase(this.#jsonSchemaCompatiable(schema$1), () => this.#getValidationAction(schema$1)));
|
|
258
|
+
}
|
|
259
|
+
return (this.#options?.schemaHandle?.afterResolve?.(schema$1, vSchema) ?? vSchema);
|
|
260
|
+
}
|
|
261
|
+
#applicatorNot(schema) {
|
|
262
|
+
const actionList = [];
|
|
263
|
+
if (isBoolean(schema.not)) {
|
|
264
|
+
if (schema.not) {
|
|
265
|
+
actionList.push(createImpasseAction('not', schema.not));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else if (schema.not) {
|
|
269
|
+
const vSchema = this.#jSchemaToVSchema(schema.not);
|
|
270
|
+
actionList.push(v.rawCheck(({ dataset, addIssue }) => {
|
|
271
|
+
if (dataset.issues) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const result = v.safeParse(vSchema, dataset.value);
|
|
275
|
+
if (result.success) {
|
|
276
|
+
addIssue({ label: `applicator:not` });
|
|
277
|
+
}
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
return actionList;
|
|
281
|
+
}
|
|
282
|
+
#jSchemaToVSchema(input) {
|
|
283
|
+
if (isBoolean(input)) {
|
|
284
|
+
return input
|
|
285
|
+
? v.pipe(v.any(), jsonActions.setComponent('always-true'))
|
|
286
|
+
: v.pipe(v.any(), v.check((value) => isUndefined(value)));
|
|
287
|
+
}
|
|
288
|
+
if (this.cacheSchema.has(input)) {
|
|
289
|
+
return this.cacheSchema.get(input);
|
|
290
|
+
}
|
|
291
|
+
const schema = this.#resolveSchema2(input);
|
|
292
|
+
const actionList = this.#applicatorNot(schema);
|
|
293
|
+
const result = actionList.length
|
|
294
|
+
? v.pipe(this.#applicatorParse(schema), ...actionList)
|
|
295
|
+
: this.#applicatorParse(schema);
|
|
296
|
+
this.cacheSchema.set(input, result);
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
#jsonSchemaCompatiable(schema) {
|
|
300
|
+
if ('__resolved' in schema && schema.__resolved.isResolved) {
|
|
301
|
+
return schema;
|
|
302
|
+
}
|
|
303
|
+
const resolved = schema;
|
|
304
|
+
const type = this.#guessSchemaType(resolved);
|
|
305
|
+
resolved.__resolved = { ...resolved.__resolved, type, isResolved: true };
|
|
306
|
+
if (type.types.includes('object')) {
|
|
307
|
+
this.#objectCompatible(resolved);
|
|
308
|
+
}
|
|
309
|
+
if (type.types.includes('array')) {
|
|
310
|
+
this.#arrayCompatible(resolved);
|
|
311
|
+
}
|
|
312
|
+
if (type.types.includes('number') || type.types.includes('integer')) {
|
|
313
|
+
if (resolved.exclusiveMaximum === true) {
|
|
314
|
+
resolved.exclusiveMaximum = resolved.maximum;
|
|
315
|
+
delete resolved.maximum;
|
|
316
|
+
}
|
|
317
|
+
if (resolved.exclusiveMinimum === true) {
|
|
318
|
+
resolved.exclusiveMinimum = resolved.minimum;
|
|
319
|
+
delete resolved.minimum;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return resolved;
|
|
323
|
+
}
|
|
324
|
+
#jsonSchemaBase(schema$1, getValidationActionList) {
|
|
325
|
+
const types = schema$1.__resolved.type;
|
|
326
|
+
// 暂时为只支持一个
|
|
327
|
+
const type = types.types[0];
|
|
328
|
+
const actionList = getMetadataAction(schema$1);
|
|
329
|
+
const createTypeFn = (input) => {
|
|
330
|
+
const result = v.pipe(input, ...actionList, ...getValidationActionList());
|
|
331
|
+
const result2 = types.optional
|
|
332
|
+
? v.optional(result, schema$1.default)
|
|
333
|
+
: result;
|
|
334
|
+
return (this.#options?.schemaHandle?.type?.afterResolve(type, result2, result) ?? result2);
|
|
335
|
+
};
|
|
336
|
+
if (!isNil(schema$1.const)) {
|
|
337
|
+
return createTypeFn(v.literal(schema$1.const));
|
|
338
|
+
}
|
|
339
|
+
if (Array.isArray(schema$1.enum)) {
|
|
340
|
+
return createTypeFn(v.picklist(schema$1.enum));
|
|
341
|
+
}
|
|
342
|
+
switch (type) {
|
|
343
|
+
case 'number': {
|
|
344
|
+
return createTypeFn(v.number());
|
|
345
|
+
}
|
|
346
|
+
case 'integer': {
|
|
347
|
+
actionList.push(v.integer());
|
|
348
|
+
return createTypeFn(v.number());
|
|
349
|
+
}
|
|
350
|
+
case 'boolean': {
|
|
351
|
+
return createTypeFn(v.boolean());
|
|
352
|
+
}
|
|
353
|
+
case 'string': {
|
|
354
|
+
return createTypeFn(v.string());
|
|
355
|
+
}
|
|
356
|
+
case 'null': {
|
|
357
|
+
return createTypeFn(v.optional(v.null(), null));
|
|
358
|
+
}
|
|
359
|
+
case 'object': {
|
|
360
|
+
const childObject = {};
|
|
361
|
+
/** 附加 */
|
|
362
|
+
let defaultRest;
|
|
363
|
+
let mode = 'default';
|
|
364
|
+
if (schema$1.dependentRequired) {
|
|
365
|
+
actionList.push(v.rawCheck(({ dataset, addIssue }) => {
|
|
366
|
+
if (dataset.issues) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
Object.keys(schema$1.dependentRequired).forEach((key) => {
|
|
370
|
+
if (dataset.value?.[key] !== undefined) {
|
|
371
|
+
for (const reqKey of schema$1.dependentRequired[key]) {
|
|
372
|
+
if (dataset.value[reqKey] === undefined) {
|
|
373
|
+
addIssue({
|
|
374
|
+
label: `dependentRequired:${key}=>${reqKey}`,
|
|
375
|
+
expected: '[required]',
|
|
376
|
+
received: 'undefined',
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}));
|
|
383
|
+
}
|
|
384
|
+
// 普通属性
|
|
385
|
+
if (schema$1.properties) {
|
|
386
|
+
for (const key in schema$1.properties) {
|
|
387
|
+
const propJSchema = schema$1.properties[key];
|
|
388
|
+
let propData;
|
|
389
|
+
if (isBoolean(propJSchema)) {
|
|
390
|
+
propData = { optional: false, hasRef: false };
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
const rSchema = this.#resolveSchema2(propJSchema);
|
|
394
|
+
propData = {
|
|
395
|
+
optional: rSchema.__resolved.type.optional,
|
|
396
|
+
hasRef: rSchema.__resolved.hasRef,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const isRequired = !!schema$1.required?.includes(key);
|
|
400
|
+
const wrapperOptional = !isRequired && !propData.optional;
|
|
401
|
+
const createRef = () => {
|
|
402
|
+
let propVSchema = this.#jSchemaToVSchema(propJSchema);
|
|
403
|
+
const depList = schema$1.dependentRequired?.[key];
|
|
404
|
+
if (depList) {
|
|
405
|
+
propVSchema = v.pipe(propVSchema, jsonActions.patchHooks({
|
|
406
|
+
allFieldsResolved: (field) => {
|
|
407
|
+
field.form.control.statusChanges.subscribe(() => {
|
|
408
|
+
const valid = field.form.control.valid;
|
|
409
|
+
depList.map((item) => {
|
|
410
|
+
field.form.parent
|
|
411
|
+
.get(item)
|
|
412
|
+
?.config$.update((config) => ({
|
|
413
|
+
...config,
|
|
414
|
+
required: valid,
|
|
415
|
+
}));
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
},
|
|
419
|
+
}));
|
|
420
|
+
}
|
|
421
|
+
return propVSchema;
|
|
422
|
+
};
|
|
423
|
+
childObject[key] = propData.hasRef
|
|
424
|
+
? wrapperOptional
|
|
425
|
+
? v.optional(v.lazy(() => createRef()))
|
|
426
|
+
: v.lazy(() => createRef())
|
|
427
|
+
: wrapperOptional
|
|
428
|
+
? v.optional(createRef())
|
|
429
|
+
: createRef();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// 附加属性规则
|
|
433
|
+
if (isBoolean(schema$1.additionalProperties)) {
|
|
434
|
+
mode = schema$1.additionalProperties === false ? 'strict' : mode;
|
|
435
|
+
}
|
|
436
|
+
else if (schema$1.additionalProperties) {
|
|
437
|
+
mode = 'rest';
|
|
438
|
+
// rest要符合的规则
|
|
439
|
+
defaultRest = this.#jSchemaToVSchema(schema$1.additionalProperties);
|
|
440
|
+
}
|
|
441
|
+
const patternRestList = [];
|
|
442
|
+
if (schema$1.patternProperties) {
|
|
443
|
+
for (const key in schema$1.patternProperties) {
|
|
444
|
+
const item = this.#jSchemaToVSchema(schema$1.patternProperties[key]);
|
|
445
|
+
if (!item) {
|
|
446
|
+
throw new Error(`patternProperties->${key}: 定义未找到`);
|
|
447
|
+
}
|
|
448
|
+
patternRestList.push({
|
|
449
|
+
regexp: new RegExp(key),
|
|
450
|
+
schema: item,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/** 条件显示 */
|
|
455
|
+
const conditionList = [];
|
|
456
|
+
if (schema$1.dependentSchemas) {
|
|
457
|
+
const depSchemaMap = {};
|
|
458
|
+
for (const key in schema$1.dependentSchemas) {
|
|
459
|
+
const jSchema = schema$1.dependentSchemas[key];
|
|
460
|
+
let vSchema = this.#jSchemaToVSchema(jSchema);
|
|
461
|
+
if (!vSchema) {
|
|
462
|
+
throw new Error(`依赖->${key}: 定义未找到`);
|
|
463
|
+
}
|
|
464
|
+
depSchemaMap[key] = vSchema;
|
|
465
|
+
vSchema = v.pipe(vSchema, hideWhen({
|
|
466
|
+
disabled: true,
|
|
467
|
+
listen: (fn, field) => field
|
|
468
|
+
.get(['..', '..', 0, key])
|
|
469
|
+
.form.control.statusChanges.pipe(map((item) => item === 'VALID')),
|
|
470
|
+
}));
|
|
471
|
+
conditionList.push(vSchema);
|
|
472
|
+
}
|
|
473
|
+
actionList.push(v.rawCheck(({ dataset, addIssue }) => {
|
|
474
|
+
if (dataset.issues) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
Object.keys(schema$1.dependentSchemas).forEach((key) => {
|
|
478
|
+
if (dataset.value?.[key] !== undefined) {
|
|
479
|
+
const result = v.safeParse(depSchemaMap[key], dataset.value);
|
|
480
|
+
if (!result.success) {
|
|
481
|
+
for (const item of result.issues) {
|
|
482
|
+
addIssue({
|
|
483
|
+
...item,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
491
|
+
if (isBoolean(schema$1.propertyNames) && !schema$1.propertyNames) {
|
|
492
|
+
actionList.push(v.check(() => false));
|
|
493
|
+
}
|
|
494
|
+
else if (schema$1.propertyNames) {
|
|
495
|
+
const propNameSchema = this.#jSchemaToVSchema(schema$1.propertyNames);
|
|
496
|
+
actionList.push(v.rawCheck(({ dataset, addIssue }) => {
|
|
497
|
+
if (dataset.issues) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (dataset.value && typeof dataset.value === 'object') {
|
|
501
|
+
for (const key of Object.keys(dataset.value)) {
|
|
502
|
+
const result = v.safeParse(propNameSchema, key);
|
|
503
|
+
if (!result.success) {
|
|
504
|
+
addIssue({
|
|
505
|
+
label: `propertyNames:${key}`,
|
|
506
|
+
expected: `[match]`,
|
|
507
|
+
received: key,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}));
|
|
513
|
+
}
|
|
514
|
+
let schemaDefine;
|
|
515
|
+
if (!Object.keys(childObject).length) {
|
|
516
|
+
types.optional = true;
|
|
517
|
+
}
|
|
518
|
+
if (mode === 'default') {
|
|
519
|
+
if (conditionList.length) {
|
|
520
|
+
schemaDefine = v.pipe(schema.intersect([
|
|
521
|
+
v.looseObject(childObject),
|
|
522
|
+
v.optional(v.intersect(conditionList)),
|
|
523
|
+
]));
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
schemaDefine = v.pipe(v.looseObject(childObject));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
else if (mode === 'strict') {
|
|
530
|
+
if (conditionList.length) {
|
|
531
|
+
schemaDefine = v.pipe(schema.intersect([
|
|
532
|
+
v.object(childObject),
|
|
533
|
+
v.optional(v.intersect(conditionList)),
|
|
534
|
+
]));
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
schemaDefine = v.pipe(v.object(childObject));
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
// rest
|
|
542
|
+
let restDefine = v.any();
|
|
543
|
+
//propCheck patternMapRest addonRest
|
|
544
|
+
if (defaultRest && !patternRestList.length) {
|
|
545
|
+
restDefine = defaultRest;
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
restDefine = v.any();
|
|
549
|
+
}
|
|
550
|
+
if (conditionList.length) {
|
|
551
|
+
schemaDefine = v.intersect([
|
|
552
|
+
v.objectWithRest(childObject, restDefine),
|
|
553
|
+
v.optional(v.intersect(conditionList)),
|
|
554
|
+
]);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
schemaDefine = v.pipe(v.objectWithRest(childObject, restDefine));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
if (schema$1.patternProperties && schema$1.additionalProperties) {
|
|
561
|
+
actionList.push(v.rawCheck(({ dataset, addIssue }) => {
|
|
562
|
+
if (dataset.issues || dataset.value === undefined) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (typeof dataset.value === 'object') {
|
|
566
|
+
datasetLoop: for (const key in dataset.value) {
|
|
567
|
+
if (key in childObject) {
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
for (const { regexp, schema } of patternRestList) {
|
|
571
|
+
const isMatch = regexp.test(key);
|
|
572
|
+
if (!isMatch) {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const result = v.safeParse(schema, dataset.value[key]);
|
|
576
|
+
if (!result.success) {
|
|
577
|
+
addIssue();
|
|
578
|
+
}
|
|
579
|
+
continue datasetLoop;
|
|
580
|
+
}
|
|
581
|
+
if (defaultRest) {
|
|
582
|
+
const result = v.safeParse(defaultRest, dataset.value[key]);
|
|
583
|
+
if (!result.success) {
|
|
584
|
+
addIssue();
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}));
|
|
590
|
+
}
|
|
591
|
+
return createTypeFn(schemaDefine);
|
|
592
|
+
}
|
|
593
|
+
case 'array': {
|
|
594
|
+
let parent;
|
|
595
|
+
const fixedItems = schema$1.prefixItems;
|
|
596
|
+
if (isBoolean(schema$1.contains) && !schema$1.contains) {
|
|
597
|
+
actionList.push(createImpasseAction('contains', schema$1.contains));
|
|
598
|
+
}
|
|
599
|
+
else if (schema$1.contains && !isBoolean(schema$1.contains)) {
|
|
600
|
+
const containsSchema = this.#jSchemaToVSchema(schema$1.contains);
|
|
601
|
+
const minContains = schema$1.minContains ?? 1;
|
|
602
|
+
actionList.push(v.check((list) => {
|
|
603
|
+
if (Array.isArray(list)) {
|
|
604
|
+
const result = list.filter((item) => v.safeParse(containsSchema, item).success);
|
|
605
|
+
if (result.length < minContains) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
if (typeof schema$1.maxContains === 'number') {
|
|
609
|
+
return result.length <= schema$1.maxContains;
|
|
610
|
+
}
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
return false;
|
|
614
|
+
}));
|
|
615
|
+
}
|
|
616
|
+
const jSchemaToVSchema = (schema) => {
|
|
617
|
+
const hasRef = this.#schemahasRef(schema);
|
|
618
|
+
return hasRef
|
|
619
|
+
? v.lazy(() => this.#jSchemaToVSchema(schema))
|
|
620
|
+
: this.#jSchemaToVSchema(schema);
|
|
621
|
+
};
|
|
622
|
+
if (fixedItems && fixedItems.length) {
|
|
623
|
+
const fixedList = fixedItems.map((item) => jSchemaToVSchema(item));
|
|
624
|
+
if (schema$1.items) {
|
|
625
|
+
const result = jSchemaToVSchema(schema$1.items);
|
|
626
|
+
parent = v.tupleWithRest(fixedList, result);
|
|
627
|
+
}
|
|
628
|
+
else if (schema$1.items === false) {
|
|
629
|
+
parent = v.tuple(fixedList);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
parent = v.looseTuple(fixedList);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else if (isBoolean(schema$1.items)) {
|
|
636
|
+
parent = schema$1.items ? v.array(v.any()) : v.tuple([]);
|
|
637
|
+
}
|
|
638
|
+
else if (schema$1.items) {
|
|
639
|
+
const result = jSchemaToVSchema(schema$1.items);
|
|
640
|
+
parent = v.array(result);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
parent = v.array(v.any());
|
|
644
|
+
}
|
|
645
|
+
return createTypeFn(parent);
|
|
646
|
+
}
|
|
647
|
+
default:
|
|
648
|
+
throw new Error(`未知类型:${type}`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
#resolveDefinition(schema) {
|
|
652
|
+
if (!schema.$ref) {
|
|
653
|
+
return schema;
|
|
654
|
+
}
|
|
655
|
+
const [uri, pointer] = schema.$ref.split('#/');
|
|
656
|
+
if (uri) {
|
|
657
|
+
throw Error(`Remote schemas for ${schema.$ref} not supported yet.`);
|
|
658
|
+
}
|
|
659
|
+
const definition = !pointer
|
|
660
|
+
? null
|
|
661
|
+
: pointer
|
|
662
|
+
.split('/')
|
|
663
|
+
.reduce((def, path) => def?.hasOwnProperty(path) ? def[path] : null, this.root);
|
|
664
|
+
if (!definition) {
|
|
665
|
+
throw Error(`Cannot find a definition for ${schema.$ref}.`);
|
|
666
|
+
}
|
|
667
|
+
if (definition.$ref) {
|
|
668
|
+
return this.#resolveDefinition(definition);
|
|
669
|
+
}
|
|
670
|
+
return {
|
|
671
|
+
...definition,
|
|
672
|
+
...['title', 'description', 'default', 'actions'].reduce((annotation, p) => {
|
|
673
|
+
if (schema.hasOwnProperty(p)) {
|
|
674
|
+
annotation[p] = schema[p];
|
|
675
|
+
}
|
|
676
|
+
return annotation;
|
|
677
|
+
}, {}),
|
|
678
|
+
$ref: undefined,
|
|
679
|
+
__resolved: {
|
|
680
|
+
hasRef: true,
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
/** todo 当前只能存在一个类型 */
|
|
685
|
+
#guessSchemaType(schema) {
|
|
686
|
+
let type = schema?.type;
|
|
687
|
+
if (isString(type)) {
|
|
688
|
+
return { types: [type], optional: false };
|
|
689
|
+
}
|
|
690
|
+
if (Array.isArray(type)) {
|
|
691
|
+
if (type.length === 1) {
|
|
692
|
+
return { types: type, optional: false };
|
|
693
|
+
}
|
|
694
|
+
const nullIndex = type.findIndex((item) => item === 'null');
|
|
695
|
+
if (nullIndex !== -1) {
|
|
696
|
+
type.splice(nullIndex, 1);
|
|
697
|
+
}
|
|
698
|
+
return {
|
|
699
|
+
types: type,
|
|
700
|
+
optional: nullIndex !== -1,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
if (schema.items ||
|
|
704
|
+
schema.prefixItems ||
|
|
705
|
+
isNumber(schema.minContains) ||
|
|
706
|
+
isNumber(schema.maxContains) ||
|
|
707
|
+
!isNil(schema.contains) ||
|
|
708
|
+
isBoolean(schema.uniqueItems)) {
|
|
709
|
+
type = 'array';
|
|
710
|
+
}
|
|
711
|
+
else if (isNumber(schema.minimum) ||
|
|
712
|
+
isNumber(schema.maximum) ||
|
|
713
|
+
isNumber(schema.exclusiveMaximum) ||
|
|
714
|
+
isNumber(schema.exclusiveMinimum) ||
|
|
715
|
+
isNumber(schema.multipleOf)) {
|
|
716
|
+
type = 'number';
|
|
717
|
+
}
|
|
718
|
+
else if (isNumber(schema.minLength) ||
|
|
719
|
+
isNumber(schema.maxLength) ||
|
|
720
|
+
isString(schema.pattern)) {
|
|
721
|
+
type = 'string';
|
|
722
|
+
}
|
|
723
|
+
return type
|
|
724
|
+
? { types: [type], optional: false }
|
|
725
|
+
: { types: anyType, optional: false };
|
|
726
|
+
}
|
|
727
|
+
#objectCompatible(schema) {
|
|
728
|
+
if ('dependencies' in schema && schema.dependencies) {
|
|
729
|
+
const dependencies = schema.dependencies;
|
|
730
|
+
const dependentRequiredData = {};
|
|
731
|
+
const dependentSchemasData = {};
|
|
732
|
+
Object.keys(dependencies).forEach((prop) => {
|
|
733
|
+
const dependency = dependencies[prop];
|
|
734
|
+
if (Array.isArray(dependency)) {
|
|
735
|
+
dependentRequiredData[prop] = dependency;
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
dependentSchemasData[prop] = dependency;
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
schema.dependentRequired = dependentRequiredData;
|
|
742
|
+
schema.dependentSchemas = dependentSchemasData;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
#arrayCompatible(schema) {
|
|
746
|
+
if (this.root.$schema !== Schema2012 || !isNil(schema.additionalItems)) {
|
|
747
|
+
if (!isNil(schema.items) || !isNil(schema.additionalItems)) {
|
|
748
|
+
// 2019-09
|
|
749
|
+
schema.prefixItems = schema.items;
|
|
750
|
+
schema.items = schema.additionalItems;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
#mergeSchema(schema, ...list) {
|
|
756
|
+
let base = clone(schema);
|
|
757
|
+
let baseKeyList = Object.keys(base);
|
|
758
|
+
const actionList = this.#getValidationAction(base);
|
|
759
|
+
for (let childSchema of list.filter((item) => !isBoolean(item))) {
|
|
760
|
+
childSchema = this.#resolveSchema2(childSchema);
|
|
761
|
+
actionList.push(...this.#getValidationAction(childSchema));
|
|
762
|
+
baseKeyList = union(baseKeyList, Object.keys(childSchema));
|
|
763
|
+
for (const key of baseKeyList) {
|
|
764
|
+
switch (key) {
|
|
765
|
+
case 'const': {
|
|
766
|
+
childSchema[key] ??= base[key];
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
case 'type':
|
|
770
|
+
case 'enum': {
|
|
771
|
+
// 类型
|
|
772
|
+
const typeResult = arrayIntersection(base[key], childSchema[key]);
|
|
773
|
+
if (typeResult.action) {
|
|
774
|
+
actionList.push(typeResult.action);
|
|
775
|
+
}
|
|
776
|
+
if (!isUndefined(typeResult.value)) {
|
|
777
|
+
childSchema[key] = typeResult.value;
|
|
778
|
+
}
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
case 'additionalProperties': {
|
|
782
|
+
// todo 此属性false在当前使用,子级会验证失败,
|
|
783
|
+
// 附加属性
|
|
784
|
+
childSchema.additionalProperties ??= base.additionalProperties;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
case 'contains': {
|
|
788
|
+
if (childSchema[key] === false || base[key] === false) {
|
|
789
|
+
actionList.push(v.check(() => false));
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
else if (childSchema[key] === true) {
|
|
793
|
+
childSchema[key] = base[key];
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
else if (base[key] === true) {
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
if (!isUndefined(childSchema[key])) {
|
|
800
|
+
childSchema[key] = {
|
|
801
|
+
...base[key],
|
|
802
|
+
...childSchema[key],
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
childSchema[key] = base[key];
|
|
807
|
+
}
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
case 'if':
|
|
811
|
+
case 'then':
|
|
812
|
+
case 'else':
|
|
813
|
+
case 'patternProperties':
|
|
814
|
+
case 'dependentSchemas':
|
|
815
|
+
case 'propertyNames':
|
|
816
|
+
case 'properties': {
|
|
817
|
+
// 属性赋值
|
|
818
|
+
if (!isUndefined(childSchema[key])) {
|
|
819
|
+
childSchema[key] = {
|
|
820
|
+
...base[key],
|
|
821
|
+
...childSchema[key],
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
childSchema[key] = base[key];
|
|
826
|
+
}
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
default:
|
|
830
|
+
childSchema[key] ??= base[key];
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
base = childSchema;
|
|
835
|
+
}
|
|
836
|
+
return { schema: this.#jsonSchemaCompatiable(base), actionList };
|
|
837
|
+
}
|
|
838
|
+
#resolveSchema2(schema) {
|
|
839
|
+
return this.#jsonSchemaCompatiable(this.#resolveDefinition(schema));
|
|
840
|
+
}
|
|
841
|
+
#schemahasRef(schema) {
|
|
842
|
+
if (isBoolean(schema)) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
const result = this.#resolveSchema2(schema);
|
|
847
|
+
return result.__resolved.hasRef;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
#parseEnum(schema) {
|
|
851
|
+
// 普通枚举
|
|
852
|
+
if (schema.enum) {
|
|
853
|
+
return {
|
|
854
|
+
type: 'enum',
|
|
855
|
+
data: {
|
|
856
|
+
enum: schema.enum,
|
|
857
|
+
},
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
else if (schema.const) {
|
|
861
|
+
return { type: 'const', data: { const: schema.const } };
|
|
862
|
+
}
|
|
863
|
+
else if (schema.items && !isBoolean(schema.items)) {
|
|
864
|
+
const result = this.#parseEnum(schema.items);
|
|
865
|
+
if (result?.data) {
|
|
866
|
+
return {
|
|
867
|
+
type: 'multiselect',
|
|
868
|
+
data: {
|
|
869
|
+
items: result.data,
|
|
870
|
+
},
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
return undefined;
|
|
874
|
+
}
|
|
875
|
+
return undefined;
|
|
876
|
+
}
|
|
877
|
+
#intersectSchemaType(a, b) {
|
|
878
|
+
const parent = a ? this.#resolveSchema2(a) : undefined;
|
|
879
|
+
b = parent ? this.#mergeSchema(parent, b).schema : b;
|
|
880
|
+
const child = this.#resolveSchema2(b);
|
|
881
|
+
const parentEnum = parent ? this.#parseEnum(parent) : undefined;
|
|
882
|
+
const childEnum = this.#parseEnum(child);
|
|
883
|
+
if (parentEnum?.data.items && childEnum?.data.items) {
|
|
884
|
+
const result = intersection(parentEnum.data.items.enum, childEnum.data.items.enum);
|
|
885
|
+
if (result.length) {
|
|
886
|
+
return {
|
|
887
|
+
type: 'multiselect',
|
|
888
|
+
data: {
|
|
889
|
+
items: {
|
|
890
|
+
enum: result,
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
else if (childEnum?.type === 'multiselect') {
|
|
897
|
+
return childEnum;
|
|
898
|
+
}
|
|
899
|
+
// 枚举
|
|
900
|
+
if (parentEnum?.data.enum && childEnum?.data.enum) {
|
|
901
|
+
const result = intersection(parentEnum.data.enum, childEnum.data.enum);
|
|
902
|
+
if (result.length) {
|
|
903
|
+
return {
|
|
904
|
+
type: 'enum',
|
|
905
|
+
data: { enum: result },
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
else if (childEnum?.data.enum) {
|
|
910
|
+
return childEnum;
|
|
911
|
+
}
|
|
912
|
+
// 常量
|
|
913
|
+
if (isNil(parentEnum?.data.const) && !isNil(childEnum?.data.const)) {
|
|
914
|
+
return childEnum;
|
|
915
|
+
}
|
|
916
|
+
// 类型
|
|
917
|
+
const typeResult = parent?.__resolved.type.types
|
|
918
|
+
? intersection(parent.__resolved.type.types, child.__resolved.type.types)
|
|
919
|
+
: child.__resolved.type.types;
|
|
920
|
+
if (typeResult.length) {
|
|
921
|
+
delete child['resolved'];
|
|
922
|
+
const result = this.#jsonSchemaCompatiable({
|
|
923
|
+
...child,
|
|
924
|
+
type: typeResult[0],
|
|
925
|
+
});
|
|
926
|
+
return {
|
|
927
|
+
type: typeResult[0],
|
|
928
|
+
data: result,
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
#schemaExtract(schema, ...childList) {
|
|
934
|
+
/** 所有子属性key */
|
|
935
|
+
const childKeyList = uniq(childList.flatMap((item) => Object.keys(item.properties ?? {})));
|
|
936
|
+
if (!childKeyList.length) {
|
|
937
|
+
// 无效返回
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const conditionJSchema = {
|
|
941
|
+
properties: {},
|
|
942
|
+
additionalProperties: false,
|
|
943
|
+
};
|
|
944
|
+
const childConditionJSchemaList = childList.map(() => ({ properties: {} }));
|
|
945
|
+
const conditionKeyList = [];
|
|
946
|
+
for (const key of childKeyList) {
|
|
947
|
+
const parentItem = schema.properties?.[key];
|
|
948
|
+
//如果父级不存在这个属性,并且禁止添加,跳过
|
|
949
|
+
// todo 还应该增加额外的匹配
|
|
950
|
+
if (!parentItem && schema.additionalProperties === false) {
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
// 所有子级都存在某个Key
|
|
954
|
+
const keyExist = childList.every((item) => {
|
|
955
|
+
const propItem = item.properties?.[key];
|
|
956
|
+
// todo 对象应该先解析
|
|
957
|
+
return propItem && !isBoolean(propItem) && propItem.type !== 'object';
|
|
958
|
+
});
|
|
959
|
+
if (!keyExist) {
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
let currentType = undefined;
|
|
963
|
+
const childPropList = [];
|
|
964
|
+
for (const sub of childList) {
|
|
965
|
+
const result = this.#intersectSchemaType(schema?.properties?.[key], sub.properties[key]);
|
|
966
|
+
if (!result) {
|
|
967
|
+
currentType = undefined;
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
else if (currentType === undefined ||
|
|
971
|
+
deepEqual(currentType, result.type)) {
|
|
972
|
+
currentType = result.type;
|
|
973
|
+
// 枚举
|
|
974
|
+
if (result.data.enum ||
|
|
975
|
+
'const' in result.data ||
|
|
976
|
+
result.type === 'multiselect') {
|
|
977
|
+
childPropList.push(result.data);
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
childPropList.push(result.data);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (currentType) {
|
|
988
|
+
conditionKeyList.push(key);
|
|
989
|
+
for (let index = 0; index < childConditionJSchemaList.length; index++) {
|
|
990
|
+
const schema = childConditionJSchemaList[index];
|
|
991
|
+
schema.properties[key] = childPropList[index];
|
|
992
|
+
}
|
|
993
|
+
if (currentType === 'enum') {
|
|
994
|
+
conditionJSchema.properties[key] = {
|
|
995
|
+
enum: childPropList.flatMap((item) => item.enum),
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
else if (currentType === 'const') {
|
|
999
|
+
conditionJSchema.properties[key] = {
|
|
1000
|
+
enum: childPropList.flatMap((item) => item.const),
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
else if (currentType === 'multiselect') {
|
|
1004
|
+
conditionJSchema.properties[key] = {
|
|
1005
|
+
type: 'array',
|
|
1006
|
+
items: {
|
|
1007
|
+
enum: childPropList.flatMap((item) => item.items.enum),
|
|
1008
|
+
},
|
|
1009
|
+
uniqueItems: true,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
conditionJSchema.properties[key] = {
|
|
1014
|
+
type: currentType,
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return { conditionJSchema, childConditionJSchemaList, conditionKeyList };
|
|
1020
|
+
}
|
|
1021
|
+
#conditionCreate(schema, options) {
|
|
1022
|
+
const resolvedChildList = options
|
|
1023
|
+
.getChildren()
|
|
1024
|
+
.map((item) => this.#mergeSchema(schema, item));
|
|
1025
|
+
const resolvedChildJSchemaList = resolvedChildList.map((item) => item.schema);
|
|
1026
|
+
const isObject = [schema, ...resolvedChildJSchemaList].every((item) => item.__resolved.type.types.includes('object'));
|
|
1027
|
+
/** 通用子级验证部分,不显示 */
|
|
1028
|
+
const childOriginSchemaList = resolvedChildList.map((item) => v.pipe(this.#jsonSchemaBase(item.schema, () => item.actionList)));
|
|
1029
|
+
let activateList = [];
|
|
1030
|
+
const conditionCheckAction = options.conditionCheckActionFn(childOriginSchemaList, () => activateList);
|
|
1031
|
+
// 仅处理object,实现条件显示
|
|
1032
|
+
if (isObject) {
|
|
1033
|
+
const conditionResult = this.#schemaExtract(schema, ...resolvedChildJSchemaList);
|
|
1034
|
+
if (conditionResult) {
|
|
1035
|
+
/** 子级的共同部分验证,用于检测是哪个子级,不显示 */
|
|
1036
|
+
const childConditionVSchemaList = conditionResult.childConditionJSchemaList.map((schema) => {
|
|
1037
|
+
const rSchema = this.#jsonSchemaCompatiable(schema);
|
|
1038
|
+
return v.pipe(this.#jsonSchemaBase(rSchema, () => this.#getValidationAction(rSchema)));
|
|
1039
|
+
});
|
|
1040
|
+
/** 主条件部分,用于显示切换 */
|
|
1041
|
+
const conditionVSchema = v.pipe(this.#jsonSchemaBase(this.#jsonSchemaCompatiable(conditionResult.conditionJSchema), () => []), jsonActions.valueChange((fn) => {
|
|
1042
|
+
fn().subscribe(({ list: [value], field }) => {
|
|
1043
|
+
activateList.length = 0;
|
|
1044
|
+
const conditionParent = field.get(['..', 2]).form
|
|
1045
|
+
.control;
|
|
1046
|
+
const parentAList = [];
|
|
1047
|
+
for (let index = 0; index < childConditionVSchemaList.length; index++) {
|
|
1048
|
+
const schema = childConditionVSchemaList[index];
|
|
1049
|
+
const result = v.safeParse(schema, value);
|
|
1050
|
+
activateList.push(result.success);
|
|
1051
|
+
field.get(['..', 2, index])?.renderConfig.update((data) => ({
|
|
1052
|
+
...data,
|
|
1053
|
+
hidden: !result.success,
|
|
1054
|
+
}));
|
|
1055
|
+
if (result.success) {
|
|
1056
|
+
parentAList.push(conditionParent.children$$()[index]);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (!options.useOr) {
|
|
1060
|
+
conditionParent.activateControls$.set(parentAList);
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
}));
|
|
1064
|
+
conditionResult.conditionKeyList.forEach((key) => {
|
|
1065
|
+
resolvedChildJSchemaList.forEach((item) => {
|
|
1066
|
+
delete item.properties[key];
|
|
1067
|
+
});
|
|
1068
|
+
delete schema.properties?.[key];
|
|
1069
|
+
});
|
|
1070
|
+
const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.#getValidationAction(schema)));
|
|
1071
|
+
const childVSchemaList = resolvedChildJSchemaList.map((item) =>
|
|
1072
|
+
// 验证部分被单独提取出来
|
|
1073
|
+
v.pipe(this.#jsonSchemaBase(item, () => [])));
|
|
1074
|
+
return v.pipe(options.conditionSchemaFn(baseSchema, conditionVSchema, childVSchemaList), conditionCheckAction);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.#getValidationAction(schema)));
|
|
1078
|
+
activateList = childOriginSchemaList.map((_, i) => true);
|
|
1079
|
+
return v.pipe(baseSchema, conditionCheckAction);
|
|
1080
|
+
}
|
|
1081
|
+
#getValidationAction(schema) {
|
|
1082
|
+
const action = [];
|
|
1083
|
+
// string/array
|
|
1084
|
+
if (isNumber(schema.minLength) || isNumber(schema.minItems)) {
|
|
1085
|
+
action.push(v.minLength(schema.minLength ?? schema.minItems));
|
|
1086
|
+
}
|
|
1087
|
+
// string/array
|
|
1088
|
+
if (isNumber(schema.maxLength) || isNumber(schema.maxItems)) {
|
|
1089
|
+
action.push(v.maxLength(schema.maxLength ?? schema.maxItems));
|
|
1090
|
+
}
|
|
1091
|
+
// string
|
|
1092
|
+
if (isString(schema.pattern)) {
|
|
1093
|
+
action.push(v.regex(new RegExp(schema.pattern)));
|
|
1094
|
+
}
|
|
1095
|
+
// todo format https://json-schema.org/understanding-json-schema/reference/type#built-in-formats
|
|
1096
|
+
// duration idn-email idn-hostname uri-reference iri iri-reference uri-template json-pointer regex
|
|
1097
|
+
if (schema.format) {
|
|
1098
|
+
switch (schema.format) {
|
|
1099
|
+
// case 'date-time': {
|
|
1100
|
+
// action.push(v.isoDateTime());
|
|
1101
|
+
// break;
|
|
1102
|
+
// }
|
|
1103
|
+
// case 'time': {
|
|
1104
|
+
// action.push(v.isoTime());
|
|
1105
|
+
// break;
|
|
1106
|
+
// }
|
|
1107
|
+
case 'date': {
|
|
1108
|
+
action.push(v.isoDate());
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
case 'email': {
|
|
1112
|
+
action.push(v.email());
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
case 'ipv4': {
|
|
1116
|
+
action.push(v.ipv4());
|
|
1117
|
+
break;
|
|
1118
|
+
}
|
|
1119
|
+
case 'ipv6': {
|
|
1120
|
+
action.push(v.ipv6());
|
|
1121
|
+
break;
|
|
1122
|
+
}
|
|
1123
|
+
case 'uuid': {
|
|
1124
|
+
action.push(v.uuid());
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
case 'uri': {
|
|
1128
|
+
action.push(v.url());
|
|
1129
|
+
break;
|
|
1130
|
+
}
|
|
1131
|
+
default:
|
|
1132
|
+
break;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
// number
|
|
1136
|
+
if (isNumber(schema.exclusiveMinimum)) {
|
|
1137
|
+
action.push(v.gtValue(schema.exclusiveMinimum));
|
|
1138
|
+
}
|
|
1139
|
+
if (isNumber(schema.exclusiveMaximum)) {
|
|
1140
|
+
action.push(v.ltValue(schema.exclusiveMaximum));
|
|
1141
|
+
}
|
|
1142
|
+
if (isNumber(schema.minimum)) {
|
|
1143
|
+
action.push(v.minValue(schema.minimum));
|
|
1144
|
+
}
|
|
1145
|
+
if (isNumber(schema.maximum)) {
|
|
1146
|
+
action.push(v.maxValue(schema.maximum));
|
|
1147
|
+
}
|
|
1148
|
+
// number
|
|
1149
|
+
if (isNumber(schema.multipleOf)) {
|
|
1150
|
+
action.push(v.multipleOf(schema.multipleOf));
|
|
1151
|
+
}
|
|
1152
|
+
// array
|
|
1153
|
+
if (schema.uniqueItems) {
|
|
1154
|
+
action.push(v.check((input) => uniq(input).length === input.length));
|
|
1155
|
+
}
|
|
1156
|
+
// object
|
|
1157
|
+
if (isNumber(schema.maxProperties)) {
|
|
1158
|
+
action.push(v.maxEntries(schema.maxProperties));
|
|
1159
|
+
}
|
|
1160
|
+
// object
|
|
1161
|
+
if (isNumber(schema.minProperties)) {
|
|
1162
|
+
action.push(v.minEntries(schema.minProperties));
|
|
1163
|
+
}
|
|
1164
|
+
if (schema.actions) {
|
|
1165
|
+
for (const rawAction of schema.actions) {
|
|
1166
|
+
const inlineActions = jsonActions[rawAction.name] ??
|
|
1167
|
+
this.#options?.customActions?.[rawAction.name];
|
|
1168
|
+
if (!inlineActions) {
|
|
1169
|
+
throw new Error(`action:[${rawAction.name}]❗`);
|
|
1170
|
+
}
|
|
1171
|
+
action.push(inlineActions.apply(undefined, rawAction.params));
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
return action;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Generated bundle index. Do not edit.
|
|
1180
|
+
*/
|
|
1181
|
+
|
|
1182
|
+
export { JsonSchemaToValibot, jsonSchemaToValibot };
|
|
1183
|
+
//# sourceMappingURL=piying-view-angular-core-adapter.mjs.map
|