Skip to content

Commit eff5db8

Browse files
committed
feat: schema覆盖
用于跳过子级检测,允许转换
1 parent 55b72e4 commit eff5db8

File tree

6 files changed

+161
-5
lines changed

6 files changed

+161
-5
lines changed

projects/view-angular-core/builder-base/create-field.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function createField(
3131
let control;
3232
if (isRoot) {
3333
control = new (FieldClass as any)(
34-
field.sourceSchema,
34+
field.checkSchema ?? field.sourceSchema,
3535
injector,
3636
) as AbstractControl;
3737
if (isFieldLogicGroup(control)) {
@@ -42,7 +42,7 @@ export function createField(
4242
control = parentForm.get([key]);
4343
if (!control) {
4444
control = new (FieldClass as any)(
45-
field.sourceSchema,
45+
field.checkSchema ?? field.sourceSchema,
4646
injector,
4747
) as AbstractControl;
4848
if (isFieldLogicGroup(control)) {

projects/view-angular-core/convert/handle/core.schema-handle.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,99 @@ import { FieldFormConfig } from '../../field/type';
3838
import { KeyPath } from '../../util';
3939
import { NonFieldControlAction } from '../action/non-field-control';
4040
import { Provider, StaticProvider } from '@angular/core';
41+
import { pick } from 'es-toolkit';
4142
export type InjectorProvider = Provider | StaticProvider;
43+
const AnyDefine = v.any();
44+
function AnyDefault(
45+
input: v.BaseSchema<any, any, any>,
46+
schemahandle: CoreSchemaHandle<any, any>,
47+
) {
48+
return schemahandle.undefinedable
49+
? v.optional(input, schemahandle.defaultValue)
50+
: schemahandle.nullable
51+
? v.nullable(input, schemahandle.defaultValue)
52+
: input;
53+
}
54+
const checkOverride = {
55+
logicGroup: (schemahandle: CoreSchemaHandle<any, any>) => {
56+
return v.pipe(
57+
AnyDefault(v.pipe(AnyDefine, v.check(Boolean)), schemahandle),
58+
);
59+
},
60+
array: (schemahandle: CoreSchemaHandle<any, any>) => {
61+
let source = schemahandle.coreSchema as v.TupleSchema<any[], any>;
62+
63+
let length =
64+
source &&
65+
schemahandle.formConfig.groupMode &&
66+
schemahandle.formConfig.groupMode !== 'reset'
67+
? source.items.length
68+
: undefined;
69+
70+
return v.pipe(
71+
AnyDefault(
72+
v.pipe(
73+
AnyDefine,
74+
v.check((value: any[]) => {
75+
if (!Array.isArray(value)) {
76+
return false;
77+
}
78+
if (schemahandle.formConfig.groupMode === 'strict') {
79+
return value.length === length;
80+
}
81+
return true;
82+
}),
83+
v.transform((value) => {
84+
if (
85+
schemahandle.formConfig.groupMode === 'default' &&
86+
value.length !== length
87+
) {
88+
return value.slice(0, length);
89+
}
90+
return value;
91+
}),
92+
),
93+
schemahandle,
94+
),
95+
);
96+
},
97+
group: (schemahandle: CoreSchemaHandle<any, any>) => {
98+
let source = schemahandle.coreSchema as v.ObjectSchema<any, any>;
99+
100+
let keys =
101+
source &&
102+
schemahandle.formConfig.groupMode &&
103+
schemahandle.formConfig.groupMode !== 'reset'
104+
? (Object.keys(source.entries) as unknown as string[])
105+
: undefined;
106+
107+
return v.pipe(
108+
AnyDefault(
109+
v.pipe(
110+
AnyDefine,
111+
v.check((value) => {
112+
if (typeof value !== 'object') {
113+
return false;
114+
}
115+
if (schemahandle.formConfig.groupMode === 'strict') {
116+
return Object.keys(value).every((key) => {
117+
return key in source.entries;
118+
});
119+
}
120+
return true;
121+
}),
122+
v.transform((a) => {
123+
if (schemahandle.formConfig.groupMode === 'default') {
124+
return pick(a, keys!);
125+
}
126+
return a;
127+
}),
128+
),
129+
schemahandle,
130+
),
131+
);
132+
},
133+
};
42134
export class CoreSchemaHandle<
43135
Self extends CoreSchemaHandle<any, any>,
44136
RESOLVED_FN extends () => any,
@@ -62,6 +154,11 @@ export class CoreSchemaHandle<
62154
nonFieldControl = false;
63155
hooks?: HookConfig<ReturnType<RESOLVED_FN>>;
64156
providers?: InjectorProvider[];
157+
checkSchema?: v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>;
158+
checkActions: (
159+
| v.BaseValidation<any, any, any>
160+
| v.BaseTransformation<any, any, any>
161+
)[] = [];
65162
override lazySchema(schema: LazySchema): void {
66163
super.lazySchema(schema);
67164
if (this.parent) {
@@ -213,10 +310,43 @@ export class CoreSchemaHandle<
213310
break;
214311
}
215312
}
313+
override validation(
314+
item: v.BaseValidation<any, any, v.BaseIssue<unknown>>,
315+
): void {
316+
super.validation(item);
317+
this.checkActions.push(item);
318+
}
319+
override transformation(
320+
item: v.BaseTransformation<any, any, v.BaseIssue<unknown>>,
321+
): void {
322+
super.transformation(item);
323+
this.checkActions.push(item);
324+
}
216325
override end(schema: SchemaOrPipe): void {
217326
super.end(schema);
218327
this.formConfig.defaultValue =
219328
this.defaultValue ?? (this.nullable ? null : undefined);
329+
if (this.isGroup) {
330+
this.checkSchema = v.pipe(
331+
checkOverride.group(this),
332+
...this.checkActions,
333+
);
334+
} else if (this.isTuple || this.isArray) {
335+
this.checkSchema = v.pipe(
336+
checkOverride.array(this),
337+
...this.checkActions,
338+
);
339+
} else if (this.isLogicAnd || this.isLogicOr) {
340+
this.checkSchema = v.pipe(
341+
checkOverride.logicGroup(this),
342+
...this.checkActions,
343+
);
344+
}
345+
}
346+
coreSchema!: v.BaseSchema<any, any, any>;
347+
override defineSchema(schema: SchemaOrPipe): void {
348+
super.defineSchema(schema);
349+
this.coreSchema = schema;
220350
}
221351
}
222352
export type AnyCoreSchemaHandle = CoreSchemaHandle<

projects/view-angular-core/field/field-group.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class FieldGroup<
4040
get controls() {
4141
return this.#controls$$();
4242
}
43-
override children$$ = computed(() =>this.#controls$$());
43+
override children$$ = computed(() => this.#controls$$());
4444

4545
removeRestControl(key: string): void {
4646
if (!this.resetControls$()[key]) {

projects/view-angular-core/test/custom-handle.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import { Injectable } from '@angular/core';
1616
describe('自定义handle', () => {
1717
it('默认条件', () => {
1818
class HiddenType extends CoreSchemaHandle<any, any> {
19-
override defineSchema(schema: Schema): void {}
19+
override defineSchema(schema: Schema): void {
20+
this.coreSchema = schema;
21+
}
2022
}
2123

2224
const obj = v.object({

projects/view-angular-core/test/field-logic-group.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('field-logic-group', () => {
1717
result.form.control.updateValue({ k1: 0 });
1818
expect(result.form.control.activateIndex$()).toEqual(0);
1919
});
20-
it('union-index', () => {
20+
it('union-index-strict', () => {
2121
const obj = v.union([
2222
v.strictObject({ k1: v.number() }),
2323
v.strictObject({ k1: v.number(), k2: v.string() }),
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as v from 'valibot';
2+
3+
import { createBuilder } from './util/create-builder';
4+
import { AbstractControl } from '../field/abstract_model';
5+
import { FieldControl } from '../../../dist/view-core';
6+
describe('transform', () => {
7+
it('str-to-number', () => {
8+
const obj = v.object({
9+
v1: v.pipe(
10+
v.string(),
11+
v.transform((a) => {
12+
return +a;
13+
}),
14+
),
15+
});
16+
const result = createBuilder(obj);
17+
result.form.control?.updateValue({ v1: '11' });
18+
let v1Field = result.get(['v1'])?.form.control as any as FieldControl;
19+
v1Field.viewValueChange('22');
20+
expect(v1Field.value).toBe(22);
21+
expect(result.form.control?.value).toEqual({ v1: 22 });
22+
expect(result.form.root.valid).toBeTrue();
23+
});
24+
});

0 commit comments

Comments
 (0)