@piying/view-angular-core 1.7.8 → 1.8.1

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.
@@ -1,135 +1,795 @@
1
- import { map, switchMap } from 'rxjs/operators';
2
- import rfdc from 'rfdc';
1
+ import { isString, uniq, isBoolean, isUndefined, isNil, intersection, union, difference } from 'es-toolkit';
3
2
  import * as v from 'valibot';
4
3
  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, merge } from 'rxjs';
4
+ import { hideWhen, patchInputs, asControl, setComponent } from '@piying/view-angular-core';
5
+ import { computed } from '@angular/core';
6
+ import { merge, map, BehaviorSubject, switchMap, combineLatest } from 'rxjs';
8
7
  import { schema } from '@piying/valibot-visit';
9
- import { deepEqual } from 'fast-equals';
8
+ import rfdc from 'rfdc';
10
9
 
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
10
  function isNumber(value) {
24
11
  return typeof value === 'number';
25
12
  }
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));
13
+
14
+ var ChildKind;
15
+ (function (ChildKind) {
16
+ ChildKind[ChildKind["child"] = 0] = "child";
17
+ ChildKind[ChildKind["condition"] = 1] = "condition";
18
+ })(ChildKind || (ChildKind = {}));
19
+ class TypeContext {
20
+ parent;
21
+ parentObject;
22
+ level = 0;
23
+ instance;
24
+ }
25
+ class BaseTypeService {
26
+ static index = 0;
27
+ context = new TypeContext();
28
+ parent;
29
+ instance;
30
+ schema;
31
+ name;
32
+ index = 0;
33
+ instanceNamePrefix$$ = computed(() => `${this.index}-type`);
34
+ constructor(instance, schema) {
35
+ this.context.instance = this;
36
+ this.instance = instance;
37
+ this.schema = schema;
41
38
  }
42
- if (isString(schema.description)) {
43
- action.push(v.description(schema.description));
39
+ getAllActionList(actionList) {
40
+ return [...actionList, ...this.getExtraActionList()];
44
41
  }
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
- };
42
+ isOptional() {
43
+ return this.schema.__resolved.type.optional;
44
+ }
45
+ parseBase(actionList) {
46
+ const Define = v.pipe(this.getBaseDefine(), ...this.getAllActionList(actionList));
47
+ const OptDefine = this.isOptional()
48
+ ? v.optional(Define, this.schema.default)
49
+ : Define;
50
+ return OptDefine;
51
+ }
52
+ parse(actionList) {
53
+ const OptDefine = this.parseBase(actionList);
54
+ return (this.instance.options?.schemaHandle?.type?.afterResolve(OptDefine, this.schema, this.name) ?? OptDefine);
55
+ }
56
+ getBaseDefine() {
57
+ throw new Error('');
58
+ }
59
+ getValidationActionList(schema) {
60
+ const action = [];
61
+ // string/array
62
+ if (isNumber(schema.minLength) || isNumber(schema.minItems)) {
63
+ action.push(v.minLength(schema.minLength ?? schema.minItems));
64
+ }
65
+ // string/array
66
+ if (isNumber(schema.maxLength) || isNumber(schema.maxItems)) {
67
+ action.push(v.maxLength(schema.maxLength ?? schema.maxItems));
68
+ }
69
+ // string
70
+ if (isString(schema.pattern)) {
71
+ action.push(v.regex(new RegExp(schema.pattern)));
72
+ }
73
+ // todo format https://json-schema.org/understanding-json-schema/reference/type#built-in-formats
74
+ // duration idn-email idn-hostname uri-reference iri iri-reference uri-template json-pointer regex
75
+ if (schema.format) {
76
+ switch (schema.format) {
77
+ // case 'date-time': {
78
+ // action.push(v.isoDateTime());
79
+ // break;
80
+ // }
81
+ // case 'time': {
82
+ // action.push(v.isoTime());
83
+ // break;
84
+ // }
85
+ case 'date': {
86
+ action.push(v.isoDate());
87
+ break;
88
+ }
89
+ case 'email': {
90
+ action.push(v.email());
91
+ break;
92
+ }
93
+ case 'ipv4': {
94
+ action.push(v.ipv4());
95
+ break;
96
+ }
97
+ case 'ipv6': {
98
+ action.push(v.ipv6());
99
+ break;
100
+ }
101
+ case 'uuid': {
102
+ action.push(v.uuid());
103
+ break;
104
+ }
105
+ case 'uri': {
106
+ action.push(v.url());
107
+ break;
108
+ }
109
+ default:
110
+ break;
58
111
  }
59
- else {
60
- return { value: result };
112
+ }
113
+ // number
114
+ if (isNumber(schema.exclusiveMinimum)) {
115
+ action.push(v.gtValue(schema.exclusiveMinimum));
116
+ }
117
+ if (isNumber(schema.exclusiveMaximum)) {
118
+ action.push(v.ltValue(schema.exclusiveMaximum));
119
+ }
120
+ if (isNumber(schema.minimum)) {
121
+ action.push(v.minValue(schema.minimum));
122
+ }
123
+ if (isNumber(schema.maximum)) {
124
+ action.push(v.maxValue(schema.maximum));
125
+ }
126
+ // number
127
+ if (isNumber(schema.multipleOf)) {
128
+ action.push(v.multipleOf(schema.multipleOf));
129
+ }
130
+ // array
131
+ if (schema.uniqueItems) {
132
+ action.push(v.check((input) => uniq(input).length === input.length));
133
+ }
134
+ // object
135
+ if (isNumber(schema.maxProperties)) {
136
+ action.push(v.maxEntries(schema.maxProperties));
137
+ }
138
+ // object
139
+ if (isNumber(schema.minProperties)) {
140
+ action.push(v.minEntries(schema.minProperties));
141
+ }
142
+ if (schema.actions) {
143
+ for (const rawAction of schema.actions) {
144
+ const inlineActions = jsonActions[rawAction.name] ??
145
+ this.instance.options?.customActions?.[rawAction.name];
146
+ if (!inlineActions) {
147
+ throw new Error(`action:[${rawAction.name}]❗`);
148
+ }
149
+ action.push(inlineActions(...rawAction.params));
61
150
  }
62
151
  }
63
- return {
64
- value: a.length ? a : b,
65
- };
152
+ return action;
153
+ }
154
+ getExtraActionList() {
155
+ return [];
156
+ }
157
+ typeParse(type, schema, actionList, options) {
158
+ const instance = this.getTypeParse(type, schema, options);
159
+ return instance.parse(actionList);
160
+ }
161
+ getTypeParse(type, schema, options) {
162
+ const Parser = this.instance.getTypeParser(type);
163
+ const instance = new Parser(this.instance, schema);
164
+ instance.index = ++BaseTypeService.index;
165
+ instance.context.parent = this.context;
166
+ if (instance.context.level) {
167
+ instance.context.parentObject = this.context.parentObject;
168
+ }
169
+ if (options?.kind === ChildKind.child) {
170
+ if (instance.context.level === 0) {
171
+ instance.context.parentObject = instance.context;
172
+ }
173
+ }
174
+ else if (options?.kind === ChildKind.condition) {
175
+ instance.context.level++;
176
+ instance.context.parentObject = this.context.parentObject ?? this.context;
177
+ }
178
+ return instance;
179
+ }
180
+ commonTypeParse(schema, options) {
181
+ // const resolved = this.resolveSchema2(schema as any);
182
+ return this.typeParse('common', schema, [], options);
183
+ }
184
+ resolveSchema2(schema) {
185
+ return this.instance.resolveSchema2(schema);
186
+ }
187
+ schemahasRef(schema) {
188
+ if (isBoolean(schema)) {
189
+ return false;
190
+ }
191
+ else {
192
+ const result = this.resolveSchema2(schema);
193
+ return result.__resolved.hasRef;
194
+ }
195
+ }
196
+ getFixedChild() {
197
+ let context = this.context;
198
+ let childObject = {};
199
+ while (context?.level) {
200
+ context = context.parentObject;
201
+ const instance = context?.instance;
202
+ childObject = { ...childObject, ...instance.childObject };
203
+ }
204
+ return childObject;
205
+ }
206
+ getFixedChildBy(key) {
207
+ let context = this.context;
208
+ while (context?.level) {
209
+ context = context.parentObject;
210
+ const instance = context?.instance;
211
+ if (instance.name === 'object') {
212
+ const maybeName = instance.getFixedChildPath(key);
213
+ if (maybeName) {
214
+ return maybeName;
215
+ }
216
+ }
217
+ }
218
+ throw new Error('');
66
219
  }
67
- return { value: a ?? b };
68
220
  }
69
- // 应该传入定制
70
- function jsonSchemaToValibot(schema, options) {
71
- return new JsonSchemaToValibot(schema, options).convert();
221
+
222
+ class NumberTypeService extends BaseTypeService {
223
+ name = 'number';
224
+ getBaseDefine() {
225
+ return v.number();
226
+ }
72
227
  }
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;
228
+
229
+ class IntegerTypeService extends NumberTypeService {
230
+ name = 'integer';
231
+ getBaseDefine() {
232
+ return v.number();
82
233
  }
83
- convert() {
84
- return this.#jSchemaToVSchema(clone(this.root));
234
+ getExtraActionList() {
235
+ return [v.integer()];
85
236
  }
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));
237
+ }
238
+
239
+ class BooleanTypeService extends BaseTypeService {
240
+ name = 'boolean';
241
+ getBaseDefine() {
242
+ return v.boolean();
243
+ }
244
+ }
245
+
246
+ class StringTypeService extends BaseTypeService {
247
+ name = 'string';
248
+ getBaseDefine() {
249
+ return v.string();
250
+ }
251
+ }
252
+
253
+ class NullTypeService extends BaseTypeService {
254
+ name = 'number';
255
+ parseBase(actionList) {
256
+ const Define = v.pipe(v.optional(v.null(), null), ...this.getAllActionList(actionList));
257
+ return Define;
258
+ }
259
+ }
260
+
261
+ class ConstTypeService extends BaseTypeService {
262
+ name = 'const';
263
+ parseBase(actionList) {
264
+ const value = this.schema.const;
265
+ const Define = v.pipe(v.optional(v.literal(value), value), ...this.getAllActionList(actionList));
266
+ return Define;
267
+ }
268
+ }
269
+
270
+ class ObjectTypeService extends BaseTypeService {
271
+ name = 'object';
272
+ actionList = [];
273
+ #optional = false;
274
+ childObject = {};
275
+ fixedActionList = [];
276
+ // fixedObjName!: string;
277
+ isOptional() {
278
+ return super.isOptional() || this.#optional;
279
+ }
280
+ getExtraActionList() {
281
+ return this.actionList;
282
+ }
283
+ getFixedChildPath(key) {
284
+ if (key in this.childObject) {
285
+ return this.instanceNamePrefix$$();
91
286
  }
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 };
287
+ return undefined;
288
+ }
289
+ getBaseDefine() {
290
+ const fixedObjName = `${this.instanceNamePrefix$$()}-fixed`;
291
+ const actionList = this.actionList;
292
+ const schema$1 = this.schema;
293
+ const childObject = {};
294
+ this.childObject = childObject;
295
+ /** 附加 */
296
+ let defaultRest;
297
+ let mode = 'default';
298
+ if (schema$1.dependentRequired) {
299
+ actionList.push(v.rawCheck(({ dataset, addIssue }) => {
300
+ if (dataset.issues) {
301
+ return;
302
+ }
303
+ Object.keys(schema$1.dependentRequired).forEach((key) => {
304
+ if (dataset.value?.[key] !== undefined) {
305
+ for (const reqKey of schema$1.dependentRequired[key]) {
306
+ if (dataset.value[reqKey] === undefined) {
307
+ addIssue({
308
+ label: `dependentRequired:${key}=>${reqKey}`,
309
+ expected: '[required]',
310
+ received: 'undefined',
311
+ });
112
312
  }
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
313
  }
314
+ }
315
+ });
316
+ }));
317
+ }
318
+ let hasRequiredKey = false;
319
+ // 普通属性
320
+ if (schema$1.properties) {
321
+ for (const key in schema$1.properties) {
322
+ const propJSchema = schema$1.properties[key];
323
+ let propData;
324
+ if (isBoolean(propJSchema)) {
325
+ propData = { optional: false, hasRef: false };
326
+ }
327
+ else {
328
+ const rSchema = this.resolveSchema2(propJSchema);
329
+ propData = {
330
+ optional: rSchema.__resolved.type.optional,
331
+ hasRef: rSchema.__resolved.hasRef,
332
+ };
333
+ }
334
+ const isRequired = !!schema$1.required?.includes(key);
335
+ const wrapperOptional = !isRequired && !propData.optional;
336
+ if (isRequired && !propData.optional) {
337
+ hasRequiredKey = true;
338
+ }
339
+ const createRef = () => {
340
+ let propVSchema = this.commonTypeParse(propJSchema, {
341
+ kind: ChildKind.child,
123
342
  });
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
- });
343
+ const depList = schema$1.dependentRequired?.[key];
344
+ if (depList) {
345
+ propVSchema = v.pipe(propVSchema, jsonActions.patchHooks({
346
+ allFieldsResolved: (field) => {
347
+ field.form.control.statusChanges.subscribe(() => {
348
+ const valid = field.form.control.valid;
349
+ depList.map((item) => {
350
+ field.form.parent.get(item)?.config$.update((config) => ({
351
+ ...config,
352
+ required: valid,
353
+ }));
354
+ });
355
+ });
356
+ },
357
+ }));
358
+ }
359
+ return propVSchema;
360
+ };
361
+ childObject[key] = propData.hasRef
362
+ ? wrapperOptional
363
+ ? v.optional(v.lazy(() => createRef()))
364
+ : v.lazy(() => createRef())
365
+ : wrapperOptional
366
+ ? v.optional(createRef())
367
+ : createRef();
368
+ }
369
+ }
370
+ // 附加属性规则
371
+ if (isBoolean(schema$1.additionalProperties)) {
372
+ mode = schema$1.additionalProperties === false ? 'strict' : mode;
373
+ }
374
+ else if (schema$1.additionalProperties) {
375
+ mode = 'rest';
376
+ // rest要符合的规则
377
+ defaultRest = this.commonTypeParse(schema$1.additionalProperties, {
378
+ kind: ChildKind.condition,
379
+ });
380
+ }
381
+ const patternRestList = [];
382
+ if (schema$1.patternProperties) {
383
+ for (const key in schema$1.patternProperties) {
384
+ const item = this.commonTypeParse(schema$1.patternProperties[key], {
385
+ kind: ChildKind.condition,
386
+ });
387
+ if (!item) {
388
+ throw new Error(`patternProperties->${key}: 定义未找到`);
389
+ }
390
+ patternRestList.push({
391
+ regexp: new RegExp(key),
392
+ schema: item,
393
+ });
394
+ }
395
+ }
396
+ /** 条件显示 */
397
+ const conditionList = [];
398
+ if (schema$1.dependentSchemas) {
399
+ const depSchemaMap = {};
400
+ for (const key in schema$1.dependentSchemas) {
401
+ const jSchema = schema$1.dependentSchemas[key];
402
+ let vSchema = this.commonTypeParse(jSchema, {
403
+ kind: ChildKind.condition,
404
+ });
405
+ if (!vSchema) {
406
+ throw new Error(`依赖->${key}: 定义未找到`);
407
+ }
408
+ depSchemaMap[key] = vSchema;
409
+ vSchema = v.pipe(vSchema, jsonActions.renderConfig({ hidden: true }), hideWhen({
410
+ disabled: true,
411
+ listen: (fn, field) => {
412
+ const controlField = field.get(['..', '..', 0, key]).form
413
+ .control;
414
+ return merge(controlField.valueChanges, controlField.statusChanges).pipe(map(() => !(controlField.valid && controlField.value !== undefined)));
415
+ },
416
+ }));
417
+ conditionList.push(vSchema);
418
+ }
419
+ actionList.push(v.rawCheck(({ dataset, addIssue }) => {
420
+ if (dataset.issues) {
421
+ return;
422
+ }
423
+ Object.keys(schema$1.dependentSchemas).forEach((key) => {
424
+ if (dataset.value?.[key] !== undefined) {
425
+ const result = v.safeParse(depSchemaMap[key], dataset.value);
426
+ if (!result.success) {
427
+ for (const item of result.issues) {
428
+ addIssue({
429
+ ...item,
430
+ });
431
+ }
432
+ }
433
+ }
434
+ });
435
+ }));
436
+ }
437
+ if (isBoolean(schema$1.propertyNames) && !schema$1.propertyNames) {
438
+ actionList.push(v.check(() => false));
439
+ }
440
+ else if (schema$1.propertyNames) {
441
+ const propNameSchema = this.commonTypeParse(schema$1.propertyNames);
442
+ actionList.push(v.rawCheck(({ dataset, addIssue }) => {
443
+ if (dataset.issues) {
444
+ return;
445
+ }
446
+ if (dataset.value && typeof dataset.value === 'object') {
447
+ for (const key of Object.keys(dataset.value)) {
448
+ const result = v.safeParse(propNameSchema, key);
449
+ if (!result.success) {
450
+ addIssue({
451
+ label: `propertyNames:${key}`,
452
+ expected: `[match]`,
453
+ received: key,
454
+ });
455
+ }
456
+ }
457
+ }
458
+ }));
459
+ }
460
+ let schemaDefine;
461
+ if (!Object.keys(childObject).length || !hasRequiredKey) {
462
+ this.#optional = true;
463
+ }
464
+ if (mode === 'default') {
465
+ if (conditionList.length) {
466
+ schemaDefine = schema.intersect([
467
+ v.pipe(v.looseObject(childObject), jsonActions.setAlias(fixedObjName)),
468
+ v.optional(v.intersect(conditionList)),
469
+ ]);
470
+ }
471
+ else {
472
+ schemaDefine = v.pipe(v.looseObject(childObject), jsonActions.setAlias(fixedObjName));
473
+ }
474
+ }
475
+ else if (mode === 'strict') {
476
+ if (conditionList.length) {
477
+ schemaDefine = v.pipe(schema.intersect([
478
+ v.pipe(v.object(childObject), jsonActions.setAlias(fixedObjName)),
479
+ v.optional(v.intersect(conditionList)),
480
+ ]));
481
+ }
482
+ else {
483
+ schemaDefine = v.pipe(v.object(childObject), jsonActions.setAlias(fixedObjName));
484
+ }
485
+ }
486
+ else {
487
+ // rest
488
+ let restDefine = v.any();
489
+ //propCheck patternMapRest addonRest
490
+ if (defaultRest && !patternRestList.length) {
491
+ restDefine = defaultRest;
492
+ }
493
+ else {
494
+ restDefine = v.any();
495
+ }
496
+ if (conditionList.length) {
497
+ schemaDefine = v.intersect([
498
+ v.pipe(v.objectWithRest(childObject, restDefine), jsonActions.setAlias(fixedObjName)),
499
+ v.optional(v.intersect(conditionList)),
500
+ ]);
501
+ }
502
+ else {
503
+ schemaDefine = v.pipe(v.objectWithRest(childObject, restDefine), jsonActions.setAlias(fixedObjName));
504
+ }
505
+ }
506
+ if (schema$1.patternProperties && schema$1.additionalProperties) {
507
+ actionList.push(v.rawCheck(({ dataset, addIssue }) => {
508
+ if (dataset.issues || dataset.value === undefined) {
509
+ return;
510
+ }
511
+ if (typeof dataset.value === 'object') {
512
+ datasetLoop: for (const key in dataset.value) {
513
+ if (key in childObject) {
514
+ continue;
515
+ }
516
+ for (const { regexp, schema } of patternRestList) {
517
+ const isMatch = regexp.test(key);
518
+ if (!isMatch) {
519
+ continue;
520
+ }
521
+ const result = v.safeParse(schema, dataset.value[key]);
522
+ if (!result.success) {
523
+ addIssue();
524
+ }
525
+ continue datasetLoop;
526
+ }
527
+ if (defaultRest) {
528
+ const result = v.safeParse(defaultRest, dataset.value[key]);
529
+ if (!result.success) {
530
+ addIssue();
531
+ }
532
+ }
533
+ }
534
+ }
535
+ }));
536
+ }
537
+ return schemaDefine;
538
+ }
539
+ }
540
+
541
+ function createImpasseAction(key, value) {
542
+ return v.rawCheck(({ dataset, addIssue }) => {
543
+ if (dataset.issues) {
544
+ return;
545
+ }
546
+ addIssue({
547
+ label: `impasse:${key}`,
548
+ expected: '[no validation conflict]',
549
+ received: value,
550
+ });
551
+ });
552
+ }
553
+
554
+ class ArrayTypeService extends BaseTypeService {
555
+ name = 'array';
556
+ actionList = [];
557
+ getExtraActionList() {
558
+ return this.actionList;
559
+ }
560
+ getBaseDefine() {
561
+ const actionList = this.actionList;
562
+ const schema = this.schema;
563
+ let parent;
564
+ const fixedItems = schema.prefixItems;
565
+ if (isBoolean(schema.contains) && !schema.contains) {
566
+ actionList.push(createImpasseAction('contains', schema.contains));
567
+ }
568
+ else if (schema.contains && !isBoolean(schema.contains)) {
569
+ const containsSchema = this.commonTypeParse(schema.contains);
570
+ const minContains = schema.minContains ?? 1;
571
+ actionList.push(v.check((list) => {
572
+ if (Array.isArray(list)) {
573
+ const result = list.filter((item) => v.safeParse(containsSchema, item).success);
574
+ if (result.length < minContains) {
575
+ return false;
576
+ }
577
+ if (typeof schema.maxContains === 'number') {
578
+ return result.length <= schema.maxContains;
579
+ }
580
+ return true;
581
+ }
582
+ return false;
583
+ }));
584
+ }
585
+ const jSchemaToVSchema = (schema) => {
586
+ const hasRef = this.schemahasRef(schema);
587
+ return hasRef
588
+ ? v.lazy(() => this.commonTypeParse(schema))
589
+ : this.commonTypeParse(schema);
590
+ };
591
+ if (fixedItems && fixedItems.length) {
592
+ const fixedList = fixedItems.map((item) => jSchemaToVSchema(item));
593
+ if (schema.items) {
594
+ const result = jSchemaToVSchema(schema.items);
595
+ parent = v.tupleWithRest(fixedList, result);
596
+ }
597
+ else if (schema.items === false) {
598
+ parent = v.tuple(fixedList);
599
+ }
600
+ else {
601
+ parent = v.looseTuple(fixedList);
602
+ }
603
+ }
604
+ else if (isBoolean(schema.items)) {
605
+ parent = schema.items ? v.array(v.any()) : v.tuple([]);
606
+ }
607
+ else if (schema.items) {
608
+ const result = jSchemaToVSchema(schema.items);
609
+ parent = v.array(result);
610
+ }
611
+ else {
612
+ parent = v.array(v.any());
613
+ }
614
+ return parent;
615
+ }
616
+ }
617
+
618
+ const alwaysTrueDefine = v.pipe(v.any(), jsonActions.setComponent('always-true'));
619
+ const alwaysFalseDefine = v.pipe(v.any(), v.check((value) => isUndefined(value)));
620
+ function getBooleanDefine(value) {
621
+ return value ? alwaysTrueDefine : alwaysFalseDefine;
622
+ }
623
+
624
+ const clone = rfdc({ proto: false, circles: false });
625
+
626
+ function toFixedList(data, labelFn = (a) => a) {
627
+ return data.map((item) => {
628
+ return { label: labelFn(item), value: item };
629
+ });
630
+ }
631
+
632
+ function arrayIntersection(a, b) {
633
+ if (!isNil(a) && !isNil(b)) {
634
+ a = Array.isArray(a) ? a : [a];
635
+ b = Array.isArray(b) ? b : [b];
636
+ if (a.length && b.length) {
637
+ const result = intersection(a, b);
638
+ if (result.length === 0) {
639
+ return {
640
+ action: createImpasseAction('applicator'),
641
+ value: undefined,
642
+ };
643
+ }
644
+ else {
645
+ return { value: result };
646
+ }
647
+ }
648
+ return {
649
+ value: a.length ? a : b,
650
+ };
651
+ }
652
+ return { value: a ?? b };
653
+ }
654
+ function getMetadataAction(schema) {
655
+ const action = [];
656
+ if (isString(schema.title)) {
657
+ action.push(v.title(schema.title));
658
+ }
659
+ if (isString(schema.description)) {
660
+ action.push(v.description(schema.description));
661
+ }
662
+ return action;
663
+ }
664
+ class CommonTypeService extends BaseTypeService {
665
+ name = 'common';
666
+ cacheSchema = new WeakMap();
667
+ parse(actionList) {
668
+ return this.jSchemaToVSchema2(this.schema);
669
+ }
670
+ jSchemaToVSchema2(input) {
671
+ if (isBoolean(input)) {
672
+ return getBooleanDefine(input);
673
+ }
674
+ if (this.cacheSchema.has(input)) {
675
+ return this.cacheSchema.get(input);
676
+ }
677
+ const schema = this.resolveSchema2(input);
678
+ this.schema = schema;
679
+ const actionList = this.#applicatorNot(schema);
680
+ const result = actionList.length
681
+ ? v.pipe(this.#applicatorParse(schema), ...actionList)
682
+ : this.#applicatorParse(schema);
683
+ this.cacheSchema.set(input, result);
684
+ return result;
685
+ }
686
+ #applicatorNot(schema) {
687
+ const actionList = [];
688
+ if (isBoolean(schema.not)) {
689
+ if (schema.not) {
690
+ actionList.push(createImpasseAction('not', schema.not));
691
+ }
692
+ }
693
+ else if (schema.not) {
694
+ const vSchema = this.#jsonSchemaBase(this.resolveSchema2(schema.not), () => []);
695
+ actionList.push(v.rawCheck(({ dataset, addIssue }) => {
696
+ if (dataset.issues) {
697
+ return;
698
+ }
699
+ const result = v.safeParse(vSchema, dataset.value);
700
+ if (result.success) {
701
+ addIssue({ label: `applicator:not` });
702
+ }
703
+ }));
704
+ }
705
+ return actionList;
706
+ }
707
+ #jsonSchemaBase(schema, getValidationActionList) {
708
+ const types = schema.__resolved.type;
709
+ // 暂时为只支持一个
710
+ const type = types.types[0];
711
+ const actionList = getMetadataAction(schema);
712
+ switch (type) {
713
+ case 'picklist': {
714
+ return this.typeParse('__fixedList', {
715
+ type: '__fixedList',
716
+ data: { options: [toFixedList(schema.enum)], multi: false },
717
+ }, [...getValidationActionList(), ...actionList]);
718
+ }
719
+ case 'const':
720
+ case '__fixedList':
721
+ case 'object':
722
+ case 'null':
723
+ case 'string':
724
+ case 'boolean':
725
+ case 'integer':
726
+ case 'number': {
727
+ return this.typeParse(type, schema, [
728
+ ...getValidationActionList(),
729
+ ...actionList,
730
+ ]);
731
+ }
732
+ case 'array': {
733
+ if (schema.items && !isBoolean(schema.items)) {
734
+ let result = this.getOptions([this.resolveSchema2(schema)]);
735
+ if (result) {
736
+ return this.typeParse('__fixedList', { type: '__fixedList', data: result }, [...getValidationActionList(), ...actionList]);
737
+ }
738
+ }
739
+ return this.typeParse(type, schema, [
740
+ ...getValidationActionList(),
741
+ ...actionList,
742
+ ]);
743
+ }
744
+ default:
745
+ throw new Error(`未知类型:${type}`);
746
+ }
747
+ }
748
+ #applicatorParse(schema$1) {
749
+ let vSchema;
750
+ if (schema$1.allOf) {
751
+ const result = this.#mergeSchema(schema$1, ...schema$1.allOf);
752
+ vSchema = v.pipe(this.#jsonSchemaBase(result.schema, () => result.actionList));
753
+ }
754
+ else if (schema$1.anyOf) {
755
+ vSchema = this.#conditionCreate(schema$1, {
756
+ useOr: false,
757
+ getChildren: () => schema$1.anyOf,
758
+ conditionCheckActionFn(childOriginSchemaList, getActivateList) {
759
+ return v.rawCheck(({ dataset, addIssue }) => {
760
+ if (dataset.issues) {
761
+ return;
762
+ }
763
+ let childFailedResult;
764
+ // 验证项全为可选,所以需要这里再次验证
765
+ const hasSuccess = childOriginSchemaList.some((item, index) => {
766
+ const isActive = getActivateList()[index];
767
+ if (!isActive) {
768
+ childFailedResult ??= { index: index };
769
+ return false;
770
+ }
771
+ const result = v.safeParse(item, dataset.value);
772
+ if (!result.success) {
773
+ childFailedResult = { index: index, issues: result.issues };
774
+ }
775
+ return result.success;
776
+ });
777
+ if (!hasSuccess) {
778
+ const extMessage = childFailedResult?.issues
779
+ ?.map((item) => item.message)
780
+ .join(',') ?? '';
781
+ addIssue({
782
+ label: `anyOf:${childFailedResult?.index ?? ''}:${extMessage}`,
783
+ });
784
+ }
785
+ });
786
+ },
787
+ conditionSchemaFn: (baseSchema, conditionVSchema, childSchemaList) => v.pipe(v.intersect([
788
+ conditionVSchema,
789
+ baseSchema,
790
+ v.pipe(schema.intersect(childSchemaList.map((item) => v.pipe(v.optional(item), jsonActions.renderConfig({ hidden: true })))), jsonActions.setAlias(`${this.instanceNamePrefix$$()}-cond-display`)),
791
+ ]), jsonActions.setComponent('anyOf-condition')),
792
+ });
133
793
  }
134
794
  else if (schema$1.oneOf) {
135
795
  vSchema = this.#conditionCreate(schema$1, {
@@ -154,8 +814,8 @@ class JsonSchemaToValibot {
154
814
  if (hasSuccess.length !== 1) {
155
815
  addIssue({
156
816
  label: `oneOf`,
157
- expected: '1',
158
- received: `${hasSuccess.length}`,
817
+ expected: '1📏',
818
+ received: `${hasSuccess.length}📏`,
159
819
  });
160
820
  }
161
821
  });
@@ -176,8 +836,8 @@ class JsonSchemaToValibot {
176
836
  */
177
837
  const useThen$ = new BehaviorSubject(undefined);
178
838
  const baseSchema = v.pipe(this.#jsonSchemaBase(schema$1, () => [
179
- ...this.#getValidationAction(schema$1),
180
- hideWhen({
839
+ ...this.getValidationActionList(schema$1),
840
+ jsonActions.hideWhen({
181
841
  disabled: false,
182
842
  listen: (fn) => fn({}).pipe(map(({ list: [value], field }) => {
183
843
  const isThen = isBoolean(schema$1.if)
@@ -201,7 +861,7 @@ class JsonSchemaToValibot {
201
861
  function hideAction(isThen) {
202
862
  return [
203
863
  jsonActions.renderConfig({ hidden: true }),
204
- hideWhen({
864
+ jsonActions.hideWhen({
205
865
  disabled: true,
206
866
  listen(fn) {
207
867
  return fn({ list: [['..', 0]] }).pipe(switchMap(({ list: [] }) => useThen$), map((a) => (a === undefined ? true : isThen ? !a : a)));
@@ -230,7 +890,7 @@ class JsonSchemaToValibot {
230
890
  baseSchema,
231
891
  thenSchema ?? baseSchema,
232
892
  elseSchema ?? baseSchema,
233
- ].filter(Boolean)), formConfig({ disableOrUpdateActivate: true }), v.rawCheck(({ dataset, addIssue }) => {
893
+ ].filter(Boolean)), jsonActions.formConfig({ disableOrUpdateActivate: true }), v.rawCheck(({ dataset, addIssue }) => {
234
894
  if (dataset.issues) {
235
895
  return;
236
896
  }
@@ -254,523 +914,18 @@ class JsonSchemaToValibot {
254
914
  else {
255
915
  vSchema = v.pipe(
256
916
  // 通用部分
257
- this.#jsonSchemaBase(this.#jsonSchemaCompatiable(schema$1), () => this.#getValidationAction(schema$1)));
258
- }
259
- return (this.#options?.schemaHandle?.afterResolve?.(vSchema, schema$1) ?? 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
- }));
917
+ this.#jsonSchemaBase(this.resolveSchema2(schema$1), () => this.getValidationActionList(schema$1)));
279
918
  }
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
- let 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(result2, schema$1, type) ?? result2);
335
- };
336
- if (!isNil(schema$1.const)) {
337
- type = 'const';
338
- return createTypeFn(v.literal(schema$1.const));
339
- }
340
- if (Array.isArray(schema$1.enum)) {
341
- type = 'enum';
342
- return createTypeFn(v.picklist(schema$1.enum));
343
- }
344
- switch (type) {
345
- case 'number': {
346
- return createTypeFn(v.number());
347
- }
348
- case 'integer': {
349
- actionList.push(v.integer());
350
- return createTypeFn(v.number());
351
- }
352
- case 'boolean': {
353
- return createTypeFn(v.boolean());
354
- }
355
- case 'string': {
356
- return createTypeFn(v.string());
357
- }
358
- case 'null': {
359
- return createTypeFn(v.optional(v.null(), null));
360
- }
361
- case 'object': {
362
- const childObject = {};
363
- /** 附加 */
364
- let defaultRest;
365
- let mode = 'default';
366
- if (schema$1.dependentRequired) {
367
- actionList.push(v.rawCheck(({ dataset, addIssue }) => {
368
- if (dataset.issues) {
369
- return;
370
- }
371
- Object.keys(schema$1.dependentRequired).forEach((key) => {
372
- if (dataset.value?.[key] !== undefined) {
373
- for (const reqKey of schema$1.dependentRequired[key]) {
374
- if (dataset.value[reqKey] === undefined) {
375
- addIssue({
376
- label: `dependentRequired:${key}=>${reqKey}`,
377
- expected: '[required]',
378
- received: 'undefined',
379
- });
380
- }
381
- }
382
- }
383
- });
384
- }));
385
- }
386
- let hasRequiredKey = false;
387
- // 普通属性
388
- if (schema$1.properties) {
389
- for (const key in schema$1.properties) {
390
- const propJSchema = schema$1.properties[key];
391
- let propData;
392
- if (isBoolean(propJSchema)) {
393
- propData = { optional: false, hasRef: false };
394
- }
395
- else {
396
- const rSchema = this.#resolveSchema2(propJSchema);
397
- propData = {
398
- optional: rSchema.__resolved.type.optional,
399
- hasRef: rSchema.__resolved.hasRef,
400
- };
401
- }
402
- const isRequired = !!schema$1.required?.includes(key);
403
- const wrapperOptional = !isRequired && !propData.optional;
404
- if (isRequired && !propData.optional) {
405
- hasRequiredKey = true;
406
- }
407
- const createRef = () => {
408
- let propVSchema = this.#jSchemaToVSchema(propJSchema);
409
- const depList = schema$1.dependentRequired?.[key];
410
- if (depList) {
411
- propVSchema = v.pipe(propVSchema, jsonActions.patchHooks({
412
- allFieldsResolved: (field) => {
413
- field.form.control.statusChanges.subscribe(() => {
414
- const valid = field.form.control.valid;
415
- depList.map((item) => {
416
- field.form.parent
417
- .get(item)
418
- ?.config$.update((config) => ({
419
- ...config,
420
- required: valid,
421
- }));
422
- });
423
- });
424
- },
425
- }));
426
- }
427
- return propVSchema;
428
- };
429
- childObject[key] = propData.hasRef
430
- ? wrapperOptional
431
- ? v.optional(v.lazy(() => createRef()))
432
- : v.lazy(() => createRef())
433
- : wrapperOptional
434
- ? v.optional(createRef())
435
- : createRef();
436
- }
437
- }
438
- // 附加属性规则
439
- if (isBoolean(schema$1.additionalProperties)) {
440
- mode = schema$1.additionalProperties === false ? 'strict' : mode;
441
- }
442
- else if (schema$1.additionalProperties) {
443
- mode = 'rest';
444
- // rest要符合的规则
445
- defaultRest = this.#jSchemaToVSchema(schema$1.additionalProperties);
446
- }
447
- const patternRestList = [];
448
- if (schema$1.patternProperties) {
449
- for (const key in schema$1.patternProperties) {
450
- const item = this.#jSchemaToVSchema(schema$1.patternProperties[key]);
451
- if (!item) {
452
- throw new Error(`patternProperties->${key}: 定义未找到`);
453
- }
454
- patternRestList.push({
455
- regexp: new RegExp(key),
456
- schema: item,
457
- });
458
- }
459
- }
460
- /** 条件显示 */
461
- const conditionList = [];
462
- if (schema$1.dependentSchemas) {
463
- const depSchemaMap = {};
464
- for (const key in schema$1.dependentSchemas) {
465
- const jSchema = schema$1.dependentSchemas[key];
466
- let vSchema = this.#jSchemaToVSchema(jSchema);
467
- if (!vSchema) {
468
- throw new Error(`依赖->${key}: 定义未找到`);
469
- }
470
- depSchemaMap[key] = vSchema;
471
- vSchema = v.pipe(vSchema, jsonActions.renderConfig({ hidden: true }), hideWhen({
472
- disabled: true,
473
- listen: (fn, field) => {
474
- let controlField = field.get(['..', '..', 0, key]).form
475
- .control;
476
- return merge(controlField.valueChanges, controlField.statusChanges).pipe(map(() => {
477
- return !(controlField.valid && controlField.value !== undefined);
478
- }));
479
- },
480
- }));
481
- conditionList.push(vSchema);
482
- }
483
- actionList.push(v.rawCheck(({ dataset, addIssue }) => {
484
- if (dataset.issues) {
485
- return;
486
- }
487
- Object.keys(schema$1.dependentSchemas).forEach((key) => {
488
- if (dataset.value?.[key] !== undefined) {
489
- const result = v.safeParse(depSchemaMap[key], dataset.value);
490
- if (!result.success) {
491
- for (const item of result.issues) {
492
- addIssue({
493
- ...item,
494
- });
495
- }
496
- }
497
- }
498
- });
499
- }));
500
- }
501
- if (isBoolean(schema$1.propertyNames) && !schema$1.propertyNames) {
502
- actionList.push(v.check(() => false));
503
- }
504
- else if (schema$1.propertyNames) {
505
- const propNameSchema = this.#jSchemaToVSchema(schema$1.propertyNames);
506
- actionList.push(v.rawCheck(({ dataset, addIssue }) => {
507
- if (dataset.issues) {
508
- return;
509
- }
510
- if (dataset.value && typeof dataset.value === 'object') {
511
- for (const key of Object.keys(dataset.value)) {
512
- const result = v.safeParse(propNameSchema, key);
513
- if (!result.success) {
514
- addIssue({
515
- label: `propertyNames:${key}`,
516
- expected: `[match]`,
517
- received: key,
518
- });
519
- }
520
- }
521
- }
522
- }));
523
- }
524
- let schemaDefine;
525
- if (!Object.keys(childObject).length || !hasRequiredKey) {
526
- types.optional = true;
527
- }
528
- if (mode === 'default') {
529
- if (conditionList.length) {
530
- schemaDefine = v.pipe(schema.intersect([
531
- v.looseObject(childObject),
532
- v.optional(v.intersect(conditionList)),
533
- ]));
534
- }
535
- else {
536
- schemaDefine = v.pipe(v.looseObject(childObject));
537
- }
538
- }
539
- else if (mode === 'strict') {
540
- if (conditionList.length) {
541
- schemaDefine = v.pipe(schema.intersect([
542
- v.object(childObject),
543
- v.optional(v.intersect(conditionList)),
544
- ]));
545
- }
546
- else {
547
- schemaDefine = v.pipe(v.object(childObject));
548
- }
549
- }
550
- else {
551
- // rest
552
- let restDefine = v.any();
553
- //propCheck patternMapRest addonRest
554
- if (defaultRest && !patternRestList.length) {
555
- restDefine = defaultRest;
556
- }
557
- else {
558
- restDefine = v.any();
559
- }
560
- if (conditionList.length) {
561
- schemaDefine = v.intersect([
562
- v.objectWithRest(childObject, restDefine),
563
- v.optional(v.intersect(conditionList)),
564
- ]);
565
- }
566
- else {
567
- schemaDefine = v.pipe(v.objectWithRest(childObject, restDefine));
568
- }
569
- }
570
- if (schema$1.patternProperties && schema$1.additionalProperties) {
571
- actionList.push(v.rawCheck(({ dataset, addIssue }) => {
572
- if (dataset.issues || dataset.value === undefined) {
573
- return;
574
- }
575
- if (typeof dataset.value === 'object') {
576
- datasetLoop: for (const key in dataset.value) {
577
- if (key in childObject) {
578
- continue;
579
- }
580
- for (const { regexp, schema } of patternRestList) {
581
- const isMatch = regexp.test(key);
582
- if (!isMatch) {
583
- continue;
584
- }
585
- const result = v.safeParse(schema, dataset.value[key]);
586
- if (!result.success) {
587
- addIssue();
588
- }
589
- continue datasetLoop;
590
- }
591
- if (defaultRest) {
592
- const result = v.safeParse(defaultRest, dataset.value[key]);
593
- if (!result.success) {
594
- addIssue();
595
- }
596
- }
597
- }
598
- }
599
- }));
600
- }
601
- return createTypeFn(schemaDefine);
602
- }
603
- case 'array': {
604
- let parent;
605
- const fixedItems = schema$1.prefixItems;
606
- if (isBoolean(schema$1.contains) && !schema$1.contains) {
607
- actionList.push(createImpasseAction('contains', schema$1.contains));
608
- }
609
- else if (schema$1.contains && !isBoolean(schema$1.contains)) {
610
- const containsSchema = this.#jSchemaToVSchema(schema$1.contains);
611
- const minContains = schema$1.minContains ?? 1;
612
- actionList.push(v.check((list) => {
613
- if (Array.isArray(list)) {
614
- const result = list.filter((item) => v.safeParse(containsSchema, item).success);
615
- if (result.length < minContains) {
616
- return false;
617
- }
618
- if (typeof schema$1.maxContains === 'number') {
619
- return result.length <= schema$1.maxContains;
620
- }
621
- return true;
622
- }
623
- return false;
624
- }));
625
- }
626
- const jSchemaToVSchema = (schema) => {
627
- const hasRef = this.#schemahasRef(schema);
628
- return hasRef
629
- ? v.lazy(() => this.#jSchemaToVSchema(schema))
630
- : this.#jSchemaToVSchema(schema);
631
- };
632
- if (fixedItems && fixedItems.length) {
633
- const fixedList = fixedItems.map((item) => jSchemaToVSchema(item));
634
- if (schema$1.items) {
635
- const result = jSchemaToVSchema(schema$1.items);
636
- parent = v.tupleWithRest(fixedList, result);
637
- }
638
- else if (schema$1.items === false) {
639
- parent = v.tuple(fixedList);
640
- }
641
- else {
642
- parent = v.looseTuple(fixedList);
643
- }
644
- }
645
- else if (isBoolean(schema$1.items)) {
646
- parent = schema$1.items ? v.array(v.any()) : v.tuple([]);
647
- }
648
- else if (schema$1.items) {
649
- const result = jSchemaToVSchema(schema$1.items);
650
- parent = v.array(result);
651
- }
652
- else {
653
- parent = v.array(v.any());
654
- }
655
- return createTypeFn(parent);
656
- }
657
- default:
658
- throw new Error(`未知类型:${type}`);
659
- }
660
- }
661
- #resolveDefinition(schema) {
662
- if (!schema.$ref) {
663
- return schema;
664
- }
665
- const [uri, pointer] = schema.$ref.split('#/');
666
- if (uri) {
667
- throw Error(`Remote schemas for ${schema.$ref} not supported yet.`);
668
- }
669
- const definition = !pointer
670
- ? null
671
- : pointer
672
- .split('/')
673
- .reduce((def, path) => def?.hasOwnProperty(path) ? def[path] : null, this.root);
674
- if (!definition) {
675
- throw Error(`Cannot find a definition for ${schema.$ref}.`);
676
- }
677
- if (definition.$ref) {
678
- return this.#resolveDefinition(definition);
679
- }
680
- return {
681
- ...definition,
682
- ...['title', 'description', 'default', 'actions'].reduce((annotation, p) => {
683
- if (schema.hasOwnProperty(p)) {
684
- annotation[p] = schema[p];
685
- }
686
- return annotation;
687
- }, {}),
688
- $ref: undefined,
689
- __resolved: {
690
- hasRef: true,
691
- },
692
- };
693
- }
694
- /** todo 当前只能存在一个类型 */
695
- #guessSchemaType(schema) {
696
- let type = schema?.type;
697
- let optional = 'default' in schema;
698
- if (isString(type)) {
699
- return { types: [type], optional: optional };
700
- }
701
- if (Array.isArray(type)) {
702
- if (type.length === 1) {
703
- return { types: type, optional: optional };
704
- }
705
- const nullIndex = type.findIndex((item) => item === 'null');
706
- if (nullIndex !== -1) {
707
- type.splice(nullIndex, 1);
708
- }
709
- return {
710
- types: type,
711
- optional: optional || nullIndex !== -1,
712
- };
713
- }
714
- if (schema.items ||
715
- schema.prefixItems ||
716
- isNumber(schema.minContains) ||
717
- isNumber(schema.maxContains) ||
718
- !isNil(schema.contains) ||
719
- isBoolean(schema.uniqueItems)) {
720
- type = 'array';
721
- }
722
- else if (isNumber(schema.minimum) ||
723
- isNumber(schema.maximum) ||
724
- isNumber(schema.exclusiveMaximum) ||
725
- isNumber(schema.exclusiveMinimum) ||
726
- isNumber(schema.multipleOf)) {
727
- type = 'number';
728
- }
729
- else if (isNumber(schema.minLength) ||
730
- isNumber(schema.maxLength) ||
731
- isString(schema.pattern)) {
732
- type = 'string';
733
- }
734
- return type
735
- ? { types: [type], optional: optional }
736
- : { types: anyType, optional: optional };
737
- }
738
- #objectCompatible(schema) {
739
- if ('dependencies' in schema && schema.dependencies) {
740
- const dependencies = schema.dependencies;
741
- const dependentRequiredData = {};
742
- const dependentSchemasData = {};
743
- Object.keys(dependencies).forEach((prop) => {
744
- const dependency = dependencies[prop];
745
- if (Array.isArray(dependency)) {
746
- dependentRequiredData[prop] = dependency;
747
- }
748
- else {
749
- dependentSchemasData[prop] = dependency;
750
- }
751
- });
752
- schema.dependentRequired = dependentRequiredData;
753
- schema.dependentSchemas = dependentSchemasData;
754
- delete schema.dependencies;
755
- }
756
- }
757
- #arrayCompatible(schema) {
758
- if (this.root.$schema !== Schema2012 || !isNil(schema.additionalItems)) {
759
- if (!isNil(schema.items) || !isNil(schema.additionalItems)) {
760
- // 2019-09
761
- schema.prefixItems = schema.items;
762
- schema.items = schema.additionalItems;
763
- }
764
- }
765
- return;
919
+ return (this.instance.options?.schemaHandle?.afterResolve?.(vSchema, schema$1) ??
920
+ vSchema);
766
921
  }
767
922
  #mergeSchema(schema, ...list) {
768
923
  let base = clone(schema);
769
924
  let baseKeyList = Object.keys(base);
770
- const actionList = this.#getValidationAction(base);
771
- for (let childSchema of list.filter((item) => !isBoolean(item))) {
772
- childSchema = this.#resolveSchema2(childSchema);
773
- actionList.push(...this.#getValidationAction(childSchema));
925
+ const actionList = this.getValidationActionList(base);
926
+ for (const rawChildSchema of list.filter((item) => !isBoolean(item))) {
927
+ const childSchema = this.resolveSchema2(rawChildSchema);
928
+ actionList.push(...this.getValidationActionList(childSchema));
774
929
  baseKeyList = union(baseKeyList, Object.keys(childSchema));
775
930
  for (const key of baseKeyList) {
776
931
  switch (key) {
@@ -798,7 +953,7 @@ class JsonSchemaToValibot {
798
953
  }
799
954
  case 'contains': {
800
955
  if (childSchema[key] === false || base[key] === false) {
801
- actionList.push(v.check(() => false));
956
+ actionList.push(createImpasseAction('contains', false));
802
957
  break;
803
958
  }
804
959
  else if (childSchema[key] === true) {
@@ -838,6 +993,10 @@ class JsonSchemaToValibot {
838
993
  }
839
994
  break;
840
995
  }
996
+ case 'required': {
997
+ childSchema.required = union(childSchema.required ?? [], base.required ?? []);
998
+ break;
999
+ }
841
1000
  default:
842
1001
  childSchema[key] ??= base[key];
843
1002
  break;
@@ -845,192 +1004,10 @@ class JsonSchemaToValibot {
845
1004
  }
846
1005
  base = childSchema;
847
1006
  }
848
- return { schema: this.#jsonSchemaCompatiable(base), actionList };
849
- }
850
- #resolveSchema2(schema) {
851
- return this.#jsonSchemaCompatiable(this.#resolveDefinition(schema));
852
- }
853
- #schemahasRef(schema) {
854
- if (isBoolean(schema)) {
855
- return false;
856
- }
857
- else {
858
- const result = this.#resolveSchema2(schema);
859
- return result.__resolved.hasRef;
860
- }
861
- }
862
- #parseEnum(schema) {
863
- // 普通枚举
864
- if (schema.enum) {
865
- return {
866
- type: 'enum',
867
- data: {
868
- enum: schema.enum,
869
- },
870
- };
871
- }
872
- else if (schema.const) {
873
- return { type: 'const', data: { const: schema.const } };
874
- }
875
- else if (schema.items && !isBoolean(schema.items)) {
876
- const result = this.#parseEnum(schema.items);
877
- if (result?.data) {
878
- return {
879
- type: 'multiselect',
880
- data: {
881
- items: result.data,
882
- },
883
- };
884
- }
885
- return undefined;
886
- }
887
- return undefined;
888
- }
889
- #intersectSchemaType(a, b) {
890
- const parent = a ? this.#resolveSchema2(a) : undefined;
891
- b = parent ? this.#mergeSchema(parent, b).schema : b;
892
- const child = this.#resolveSchema2(b);
893
- const parentEnum = parent ? this.#parseEnum(parent) : undefined;
894
- const childEnum = this.#parseEnum(child);
895
- if (parentEnum?.data.items && childEnum?.data.items) {
896
- const result = intersection(parentEnum.data.items.enum, childEnum.data.items.enum);
897
- if (result.length) {
898
- return {
899
- type: 'multiselect',
900
- data: {
901
- items: {
902
- enum: result,
903
- },
904
- },
905
- };
906
- }
907
- }
908
- else if (childEnum?.type === 'multiselect') {
909
- return childEnum;
910
- }
911
- // 枚举
912
- if (parentEnum?.data.enum && childEnum?.data.enum) {
913
- const result = intersection(parentEnum.data.enum, childEnum.data.enum);
914
- if (result.length) {
915
- return {
916
- type: 'enum',
917
- data: { enum: result },
918
- };
919
- }
920
- }
921
- else if (childEnum?.data.enum) {
922
- return childEnum;
923
- }
924
- // 常量
925
- if (isNil(parentEnum?.data.const) && !isNil(childEnum?.data.const)) {
926
- return childEnum;
927
- }
928
- // 类型
929
- const typeResult = parent?.__resolved.type.types
930
- ? intersection(parent.__resolved.type.types, child.__resolved.type.types)
931
- : child.__resolved.type.types;
932
- if (typeResult.length) {
933
- delete child['resolved'];
934
- const result = this.#jsonSchemaCompatiable({
935
- ...child,
936
- type: typeResult[0],
937
- });
938
- return {
939
- type: typeResult[0],
940
- data: result,
941
- };
942
- }
943
- return;
944
- }
945
- #schemaExtract(schema, ...childList) {
946
- /** 所有子属性key */
947
- const childKeyList = uniq(childList.flatMap((item) => Object.keys(item.properties ?? {})));
948
- if (!childKeyList.length) {
949
- // 无效返回
950
- return;
951
- }
952
- const conditionJSchema = {
953
- properties: {},
954
- additionalProperties: false,
955
- };
956
- const childConditionJSchemaList = childList.map(() => ({ properties: {} }));
957
- const conditionKeyList = [];
958
- for (const key of childKeyList) {
959
- const parentItem = schema.properties?.[key];
960
- //如果父级不存在这个属性,并且禁止添加,跳过
961
- // todo 还应该增加额外的匹配
962
- if (!parentItem && schema.additionalProperties === false) {
963
- continue;
964
- }
965
- // 所有子级都存在某个Key
966
- const keyExist = childList.every((item) => {
967
- const propItem = item.properties?.[key];
968
- // todo 对象应该先解析
969
- return propItem && !isBoolean(propItem) && propItem.type !== 'object';
970
- });
971
- if (!keyExist) {
972
- continue;
973
- }
974
- let currentType = undefined;
975
- const childPropList = [];
976
- for (const sub of childList) {
977
- const result = this.#intersectSchemaType(schema?.properties?.[key], sub.properties[key]);
978
- if (!result) {
979
- currentType = undefined;
980
- break;
981
- }
982
- else if (currentType === undefined ||
983
- deepEqual(currentType, result.type)) {
984
- currentType = result.type;
985
- // 枚举
986
- if (result.data.enum ||
987
- 'const' in result.data ||
988
- result.type === 'multiselect') {
989
- childPropList.push(result.data);
990
- }
991
- else {
992
- childPropList.push(result.data);
993
- }
994
- }
995
- else {
996
- break;
997
- }
998
- }
999
- if (currentType) {
1000
- conditionKeyList.push(key);
1001
- for (let index = 0; index < childConditionJSchemaList.length; index++) {
1002
- const schema = childConditionJSchemaList[index];
1003
- schema.properties[key] = childPropList[index];
1004
- }
1005
- if (currentType === 'enum') {
1006
- conditionJSchema.properties[key] = {
1007
- enum: childPropList.flatMap((item) => item.enum),
1008
- };
1009
- }
1010
- else if (currentType === 'const') {
1011
- conditionJSchema.properties[key] = {
1012
- enum: childPropList.flatMap((item) => item.const),
1013
- };
1014
- }
1015
- else if (currentType === 'multiselect') {
1016
- conditionJSchema.properties[key] = {
1017
- type: 'array',
1018
- items: {
1019
- enum: childPropList.flatMap((item) => item.items.enum),
1020
- },
1021
- uniqueItems: true,
1022
- };
1023
- }
1024
- else {
1025
- conditionJSchema.properties[key] = {
1026
- type: currentType,
1027
- };
1028
- }
1029
- }
1030
- }
1031
- return { conditionJSchema, childConditionJSchemaList, conditionKeyList };
1007
+ return { schema: base, actionList };
1032
1008
  }
1033
1009
  #conditionCreate(schema, options) {
1010
+ const fixedKeyList = Object.keys(this.getFixedChild());
1034
1011
  const resolvedChildList = options
1035
1012
  .getChildren()
1036
1013
  .map((item) => this.#mergeSchema(schema, item));
@@ -1044,146 +1021,428 @@ class JsonSchemaToValibot {
1044
1021
  if (isObject) {
1045
1022
  const conditionResult = this.#schemaExtract(schema, ...resolvedChildJSchemaList);
1046
1023
  if (conditionResult) {
1024
+ const conditionKeyList = conditionResult.conditionKeyList;
1025
+ const excludeFixedConditionList = difference(conditionResult.conditionKeyList, fixedKeyList);
1047
1026
  /** 子级的共同部分验证,用于检测是哪个子级,不显示 */
1048
1027
  const childConditionVSchemaList = conditionResult.childConditionJSchemaList.map((schema) => {
1049
- const rSchema = this.#jsonSchemaCompatiable(schema);
1050
- return v.pipe(this.#jsonSchemaBase(rSchema, () => this.#getValidationAction(rSchema)));
1028
+ const rSchema = this.resolveSchema2(schema);
1029
+ return v.pipe(this.#jsonSchemaBase(rSchema, () => this.getValidationActionList(rSchema)));
1051
1030
  });
1052
- /** 主条件部分,用于显示切换 */
1053
- const conditionVSchema = v.pipe(this.#jsonSchemaBase(this.#jsonSchemaCompatiable(conditionResult.conditionJSchema), () => []), jsonActions.valueChange((fn) => {
1054
- fn().subscribe(({ list: [value], field }) => {
1055
- activateList.length = 0;
1056
- const conditionParent = field.get(['..', 2]).form
1057
- .control;
1058
- const parentAList = [];
1059
- for (let index = 0; index < childConditionVSchemaList.length; index++) {
1060
- const schema = childConditionVSchemaList[index];
1061
- const result = v.safeParse(schema, value);
1062
- activateList.push(result.success);
1063
- field.get(['..', 2, index])?.renderConfig.update((data) => ({
1064
- ...data,
1065
- hidden: !result.success,
1066
- }));
1067
- if (result.success) {
1068
- parentAList.push(conditionParent.children$$()[index]);
1069
- }
1070
- }
1071
- if (!options.useOr) {
1072
- conditionParent.activateControls$.set(parentAList);
1031
+ if (fixedKeyList.length) {
1032
+ for (const key of fixedKeyList) {
1033
+ delete conditionResult.conditionJSchema.properties?.[key];
1034
+ conditionResult.childConditionJSchemaList.forEach((schema) => {
1035
+ delete schema.properties?.[key];
1036
+ });
1037
+ }
1038
+ conditionResult.conditionKeyList = excludeFixedConditionList;
1039
+ }
1040
+ const checkAction = jsonActions.patchHooks({
1041
+ allFieldsResolved: (field) => {
1042
+ const displayName = ['..', 2];
1043
+ const list = [];
1044
+ const currenConditionSchema = field;
1045
+ list.push(currenConditionSchema.form.control.valueChanges);
1046
+ if (fixedKeyList.length) {
1047
+ list.push(combineLatest(fixedKeyList.map((key) => {
1048
+ const instanceNamePrefix = this.getFixedChildBy(key);
1049
+ return field.get([
1050
+ '#',
1051
+ `@${instanceNamePrefix}-fixed`,
1052
+ key,
1053
+ ]).form.control.valueChanges;
1054
+ })).pipe(map((list) => list.reduce((obj, cur, i) => {
1055
+ obj[fixedKeyList[i]] = cur;
1056
+ return obj;
1057
+ }, {}))));
1073
1058
  }
1074
- });
1075
- }));
1076
- conditionResult.conditionKeyList.forEach((key) => {
1059
+ combineLatest(list)
1060
+ .pipe(map((list) => list.reduce((obj, cur) => {
1061
+ obj = { ...obj, ...cur };
1062
+ return obj;
1063
+ }, {})))
1064
+ .subscribe((value) => {
1065
+ activateList.length = 0;
1066
+ const conditionDisplay = field.get([...displayName]).form
1067
+ .control;
1068
+ const parentAList = [];
1069
+ for (let index = 0; index < childConditionVSchemaList.length; index++) {
1070
+ const schema = childConditionVSchemaList[index];
1071
+ const result = v.safeParse(schema, value);
1072
+ activateList.push(result.success);
1073
+ // todo key需要查询
1074
+ field
1075
+ .get([...displayName, index])
1076
+ ?.renderConfig.update((data) => ({
1077
+ ...data,
1078
+ hidden: !result.success,
1079
+ }));
1080
+ if (result.success) {
1081
+ parentAList.push(conditionDisplay.children$$()[index]);
1082
+ }
1083
+ }
1084
+ if (!options.useOr) {
1085
+ conditionDisplay.activateControls$.set(parentAList);
1086
+ }
1087
+ });
1088
+ },
1089
+ });
1090
+ // todo 修改支持父级监听
1091
+ // todo 主条件要过滤
1092
+ /** 主条件部分,用于显示切换 */
1093
+ const conditionVSchema = v.pipe(this.#jsonSchemaBase(this.resolveSchema2(conditionResult.conditionJSchema), () => []), checkAction);
1094
+ conditionKeyList.forEach((key) => {
1077
1095
  resolvedChildJSchemaList.forEach((item) => {
1078
1096
  delete item.properties[key];
1079
1097
  });
1080
1098
  delete schema.properties?.[key];
1081
1099
  });
1082
- const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.#getValidationAction(schema)));
1100
+ const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.getValidationActionList(schema)));
1101
+ // todo 解析条件也要过滤
1083
1102
  const childVSchemaList = resolvedChildJSchemaList.map((item) =>
1084
1103
  // 验证部分被单独提取出来
1085
1104
  v.pipe(this.#jsonSchemaBase(item, () => [])));
1086
- return v.pipe(options.conditionSchemaFn(baseSchema, conditionVSchema, childVSchemaList), conditionCheckAction);
1105
+ return v.pipe(options.conditionSchemaFn(baseSchema, v.pipe(conditionVSchema, jsonActions.setAlias(`${this.instanceNamePrefix$$()}-cond`)), childVSchemaList), conditionCheckAction);
1087
1106
  }
1088
1107
  }
1089
- const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.#getValidationAction(schema)));
1108
+ const result = this.getOptions(resolvedChildJSchemaList);
1109
+ if (result) {
1110
+ const instance = this.getTypeParse('__fixedList', {
1111
+ data: result,
1112
+ type: '__fixedList',
1113
+ });
1114
+ activateList = childOriginSchemaList.map((_, i) => true);
1115
+ return v.pipe(instance.parse([]), conditionCheckAction);
1116
+ }
1117
+ const baseSchema = v.pipe(this.#jsonSchemaBase(schema, () => this.getValidationActionList(schema)));
1090
1118
  activateList = childOriginSchemaList.map((_, i) => true);
1091
1119
  return v.pipe(baseSchema, conditionCheckAction);
1092
1120
  }
1093
- #getValidationAction(schema) {
1094
- const action = [];
1095
- // string/array
1096
- if (isNumber(schema.minLength) || isNumber(schema.minItems)) {
1097
- action.push(v.minLength(schema.minLength ?? schema.minItems));
1098
- }
1099
- // string/array
1100
- if (isNumber(schema.maxLength) || isNumber(schema.maxItems)) {
1101
- action.push(v.maxLength(schema.maxLength ?? schema.maxItems));
1102
- }
1103
- // string
1104
- if (isString(schema.pattern)) {
1105
- action.push(v.regex(new RegExp(schema.pattern)));
1121
+ getOptions(childList) {
1122
+ if (!childList.length) {
1123
+ return;
1106
1124
  }
1107
- // todo format https://json-schema.org/understanding-json-schema/reference/type#built-in-formats
1108
- // duration idn-email idn-hostname uri-reference iri iri-reference uri-template json-pointer regex
1109
- if (schema.format) {
1110
- switch (schema.format) {
1111
- // case 'date-time': {
1112
- // action.push(v.isoDateTime());
1113
- // break;
1114
- // }
1115
- // case 'time': {
1116
- // action.push(v.isoTime());
1117
- // break;
1118
- // }
1119
- case 'date': {
1120
- action.push(v.isoDate());
1121
- break;
1125
+ const fn2 = () => {
1126
+ let data = {
1127
+ multi: undefined,
1128
+ uniqueItems: true,
1129
+ };
1130
+ const fn = (schema) => {
1131
+ let options;
1132
+ let multi2 = false;
1133
+ if (!isUndefined(schema.const)) {
1134
+ options = [
1135
+ { value: schema.const, label: schema.title ?? schema.const },
1136
+ ];
1122
1137
  }
1123
- case 'email': {
1124
- action.push(v.email());
1125
- break;
1138
+ else if (schema.enum) {
1139
+ if (schema.enum.length === 1) {
1140
+ options = [
1141
+ {
1142
+ value: schema.enum[0],
1143
+ label: schema.title ?? schema.enum[0],
1144
+ },
1145
+ ];
1146
+ }
1147
+ options = schema.enum.map((item) => ({ label: item, value: item }));
1126
1148
  }
1127
- case 'ipv4': {
1128
- action.push(v.ipv4());
1129
- break;
1149
+ else if (schema.items && !isBoolean(schema.items)) {
1150
+ const items = this.resolveSchema2(schema.items);
1151
+ options = fn2().fn(items);
1152
+ multi2 = true;
1153
+ data.uniqueItems &&= !!schema.uniqueItems;
1130
1154
  }
1131
- case 'ipv6': {
1132
- action.push(v.ipv6());
1133
- break;
1155
+ if (!options) {
1156
+ return undefined;
1134
1157
  }
1135
- case 'uuid': {
1136
- action.push(v.uuid());
1137
- break;
1158
+ if (data.multi === undefined) {
1159
+ data.multi = multi2;
1138
1160
  }
1139
- case 'uri': {
1140
- action.push(v.url());
1141
- break;
1161
+ else if (data.multi !== multi2) {
1162
+ throw new Error(`options multi conflict`);
1142
1163
  }
1143
- default:
1144
- break;
1164
+ return options;
1165
+ };
1166
+ return {
1167
+ fn,
1168
+ getData: () => data,
1169
+ };
1170
+ };
1171
+ const list = [];
1172
+ const fn$ = fn2();
1173
+ for (const schema of childList) {
1174
+ const item = fn$.fn(schema);
1175
+ if (!item) {
1176
+ return undefined;
1145
1177
  }
1178
+ list.push(item);
1146
1179
  }
1147
- // number
1148
- if (isNumber(schema.exclusiveMinimum)) {
1149
- action.push(v.gtValue(schema.exclusiveMinimum));
1180
+ let data = fn$.getData();
1181
+ return {
1182
+ uniqueItems: data.uniqueItems,
1183
+ multi: data.multi,
1184
+ options: list,
1185
+ };
1186
+ }
1187
+ #schemaExtract(schema, ...childList) {
1188
+ const childKeyList = childList.reduce((cur, item) => {
1189
+ if (cur && !cur.length) {
1190
+ return cur;
1191
+ }
1192
+ const keyList = Object.keys(item.properties ?? {}).filter((key) => {
1193
+ const propItem = item.properties[key];
1194
+ if (isBoolean(propItem)) {
1195
+ return false;
1196
+ }
1197
+ const resolved = this.resolveSchema2(propItem);
1198
+ return !resolved.__resolved.type.types.includes('object');
1199
+ });
1200
+ if (!cur) {
1201
+ return keyList;
1202
+ }
1203
+ else {
1204
+ return intersection(cur, keyList);
1205
+ }
1206
+ }, undefined);
1207
+ if (!childKeyList.length) {
1208
+ // 无效返回
1209
+ return;
1150
1210
  }
1151
- if (isNumber(schema.exclusiveMaximum)) {
1152
- action.push(v.ltValue(schema.exclusiveMaximum));
1211
+ const conditionJSchema = {
1212
+ properties: {},
1213
+ additionalProperties: false,
1214
+ };
1215
+ const childConditionJSchemaList = childList.map(() => ({ properties: {} }));
1216
+ const conditionKeyList = [];
1217
+ for (const key of childKeyList) {
1218
+ const parentItem = schema.properties?.[key];
1219
+ //如果父级不存在这个属性,并且禁止添加,跳过
1220
+ // todo 还应该增加额外的匹配
1221
+ if (!parentItem && schema.additionalProperties === false) {
1222
+ continue;
1223
+ }
1224
+ const optionsResult = this.getOptions(childList.map((item) => this.resolveSchema2(item.properties[key])));
1225
+ if (optionsResult) {
1226
+ conditionKeyList.push(key);
1227
+ conditionJSchema.properties[key] = {
1228
+ type: '__fixedList',
1229
+ data: optionsResult,
1230
+ };
1231
+ childConditionJSchemaList.forEach((item, i) => {
1232
+ item.properties[key] = childList[i].properties[key];
1233
+ });
1234
+ }
1235
+ else {
1236
+ conditionKeyList.push(key);
1237
+ conditionJSchema.properties[key] = {
1238
+ type: this.resolveSchema2(childList[0].properties[key])
1239
+ .__resolved.type.types[0],
1240
+ };
1241
+ childConditionJSchemaList.forEach((item, i) => {
1242
+ item.properties[key] = childList[i].properties[key];
1243
+ });
1244
+ }
1153
1245
  }
1154
- if (isNumber(schema.minimum)) {
1155
- action.push(v.minValue(schema.minimum));
1246
+ return { conditionJSchema, childConditionJSchemaList, conditionKeyList };
1247
+ }
1248
+ }
1249
+
1250
+ class ListTypeService extends BaseTypeService {
1251
+ name = '__fixedList';
1252
+ parse(actionList) {
1253
+ const context = this.schema['data'];
1254
+ const define = v.picklist(context.options.flat().map((option) => option.value));
1255
+ if (context.multi) {
1256
+ return v.pipe(v.array(define), patchInputs({ options: context.options }), asControl(), setComponent(context.uniqueItems ? 'multiselect' : 'multiselect-repeat'));
1156
1257
  }
1157
- if (isNumber(schema.maximum)) {
1158
- action.push(v.maxValue(schema.maximum));
1258
+ else {
1259
+ return v.pipe(define, patchInputs({ options: context.options }));
1159
1260
  }
1160
- // number
1161
- if (isNumber(schema.multipleOf)) {
1162
- action.push(v.multipleOf(schema.multipleOf));
1261
+ }
1262
+ }
1263
+
1264
+ const anyType = [
1265
+ 'object',
1266
+ 'array',
1267
+ 'string',
1268
+ 'number',
1269
+ 'boolean',
1270
+ 'null',
1271
+ 'integer',
1272
+ ];
1273
+ // 应该传入定制
1274
+ function jsonSchemaToValibot(schema, options) {
1275
+ return new JsonSchemaToValibot(schema, options).convert();
1276
+ }
1277
+ const Schema2012 = 'https://json-schema.org/draft/2020-12/schema';
1278
+ const TypeMap = {
1279
+ number: NumberTypeService,
1280
+ integer: IntegerTypeService,
1281
+ boolean: BooleanTypeService,
1282
+ string: StringTypeService,
1283
+ null: NullTypeService,
1284
+ const: ConstTypeService,
1285
+ object: ObjectTypeService,
1286
+ array: ArrayTypeService,
1287
+ common: CommonTypeService,
1288
+ __fixedList: ListTypeService,
1289
+ };
1290
+ class JsonSchemaToValibot {
1291
+ root;
1292
+ options;
1293
+ cacheSchema = new WeakMap();
1294
+ constructor(root, options) {
1295
+ this.root = root;
1296
+ this.options = options;
1297
+ root.$schema ??= Schema2012;
1298
+ }
1299
+ convert() {
1300
+ const Service = TypeMap['common'];
1301
+ const instance = new Service(this, this.root);
1302
+ return instance.parse([]);
1303
+ }
1304
+ #jsonSchemaCompatiable(schema) {
1305
+ if ('__resolved' in schema && schema.__resolved.isResolved) {
1306
+ return schema;
1163
1307
  }
1164
- // array
1165
- if (schema.uniqueItems) {
1166
- action.push(v.check((input) => uniq(input).length === input.length));
1308
+ const resolved = schema;
1309
+ const type = this.#guessSchemaType(resolved);
1310
+ resolved.__resolved = { ...resolved.__resolved, type, isResolved: true };
1311
+ if (type.types.includes('object')) {
1312
+ this.#objectCompatible(resolved);
1167
1313
  }
1168
- // object
1169
- if (isNumber(schema.maxProperties)) {
1170
- action.push(v.maxEntries(schema.maxProperties));
1314
+ if (type.types.includes('array')) {
1315
+ this.#arrayCompatible(resolved);
1171
1316
  }
1172
- // object
1173
- if (isNumber(schema.minProperties)) {
1174
- action.push(v.minEntries(schema.minProperties));
1317
+ if (type.types.includes('number') || type.types.includes('integer')) {
1318
+ if (resolved.exclusiveMaximum === true) {
1319
+ resolved.exclusiveMaximum = resolved.maximum;
1320
+ delete resolved.maximum;
1321
+ }
1322
+ if (resolved.exclusiveMinimum === true) {
1323
+ resolved.exclusiveMinimum = resolved.minimum;
1324
+ delete resolved.minimum;
1325
+ }
1175
1326
  }
1176
- if (schema.actions) {
1177
- for (const rawAction of schema.actions) {
1178
- const inlineActions = jsonActions[rawAction.name] ??
1179
- this.#options?.customActions?.[rawAction.name];
1180
- if (!inlineActions) {
1181
- throw new Error(`action:[${rawAction.name}]❗`);
1327
+ return resolved;
1328
+ }
1329
+ #resolveDefinition(schema) {
1330
+ if (!schema.$ref) {
1331
+ return schema;
1332
+ }
1333
+ const [uri, pointer] = schema.$ref.split('#/');
1334
+ if (uri) {
1335
+ throw Error(`Remote schemas for ${schema.$ref} not supported yet.`);
1336
+ }
1337
+ const definition = !pointer
1338
+ ? null
1339
+ : pointer
1340
+ .split('/')
1341
+ .reduce((def, path) => def?.hasOwnProperty(path) ? def[path] : null, this.root);
1342
+ if (!definition) {
1343
+ throw Error(`Cannot find a definition for ${schema.$ref}.`);
1344
+ }
1345
+ if (definition.$ref) {
1346
+ return this.#resolveDefinition(definition);
1347
+ }
1348
+ return {
1349
+ ...definition,
1350
+ ...['title', 'description', 'default', 'actions'].reduce((annotation, p) => {
1351
+ if (schema.hasOwnProperty(p)) {
1352
+ annotation[p] = schema[p];
1182
1353
  }
1183
- action.push(inlineActions.apply(undefined, rawAction.params));
1354
+ return annotation;
1355
+ }, {}),
1356
+ $ref: undefined,
1357
+ __resolved: {
1358
+ hasRef: true,
1359
+ },
1360
+ };
1361
+ }
1362
+ /** todo 当前只能存在一个类型 */
1363
+ #guessSchemaType(schema) {
1364
+ const optional = 'default' in schema;
1365
+ if (!isUndefined(schema.const)) {
1366
+ return { types: ['const'], optional: optional };
1367
+ }
1368
+ else if (Array.isArray(schema.enum)) {
1369
+ return { types: ['picklist'], optional: optional };
1370
+ }
1371
+ let type = schema?.type;
1372
+ if (isString(type)) {
1373
+ return { types: [type], optional: optional };
1374
+ }
1375
+ if (Array.isArray(type)) {
1376
+ if (type.length === 1) {
1377
+ return { types: type, optional: optional };
1184
1378
  }
1379
+ const nullIndex = type.findIndex((item) => item === 'null');
1380
+ if (nullIndex !== -1) {
1381
+ type.splice(nullIndex, 1);
1382
+ }
1383
+ return {
1384
+ types: type,
1385
+ optional: optional || nullIndex !== -1,
1386
+ };
1185
1387
  }
1186
- return action;
1388
+ if (schema.items ||
1389
+ schema.prefixItems ||
1390
+ isNumber(schema.minContains) ||
1391
+ isNumber(schema.maxContains) ||
1392
+ !isNil(schema.contains) ||
1393
+ isBoolean(schema.uniqueItems)) {
1394
+ type = 'array';
1395
+ }
1396
+ else if (isNumber(schema.minimum) ||
1397
+ isNumber(schema.maximum) ||
1398
+ isNumber(schema.exclusiveMaximum) ||
1399
+ isNumber(schema.exclusiveMinimum) ||
1400
+ isNumber(schema.multipleOf)) {
1401
+ type = 'number';
1402
+ }
1403
+ else if (isNumber(schema.minLength) ||
1404
+ isNumber(schema.maxLength) ||
1405
+ isString(schema.pattern)) {
1406
+ type = 'string';
1407
+ }
1408
+ return type
1409
+ ? { types: [type], optional: optional }
1410
+ : { types: anyType, optional: optional };
1411
+ }
1412
+ #objectCompatible(schema) {
1413
+ if ('dependencies' in schema && schema.dependencies) {
1414
+ const dependencies = schema.dependencies;
1415
+ const dependentRequiredData = {};
1416
+ const dependentSchemasData = {};
1417
+ Object.keys(dependencies).forEach((prop) => {
1418
+ const dependency = dependencies[prop];
1419
+ if (Array.isArray(dependency)) {
1420
+ dependentRequiredData[prop] = dependency;
1421
+ }
1422
+ else {
1423
+ dependentSchemasData[prop] = dependency;
1424
+ }
1425
+ });
1426
+ schema.dependentRequired = dependentRequiredData;
1427
+ schema.dependentSchemas = dependentSchemasData;
1428
+ delete schema.dependencies;
1429
+ }
1430
+ }
1431
+ #arrayCompatible(schema) {
1432
+ if (this.root.$schema !== Schema2012 || !isNil(schema.additionalItems)) {
1433
+ if (!isNil(schema.items) || !isNil(schema.additionalItems)) {
1434
+ // 2019-09
1435
+ schema.prefixItems = schema.items;
1436
+ schema.items = schema.additionalItems;
1437
+ }
1438
+ }
1439
+ return;
1440
+ }
1441
+ resolveSchema2(schema) {
1442
+ return this.#jsonSchemaCompatiable(this.#resolveDefinition(schema));
1443
+ }
1444
+ getTypeParser(type) {
1445
+ return TypeMap[type];
1187
1446
  }
1188
1447
  }
1189
1448