Skip to content

Commit

Permalink
fix(ui): fix circular dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Dec 9, 2022
1 parent c1de21d commit 1b21527
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 56 deletions.
57 changes: 1 addition & 56 deletions packages/ui/src/components/form/abstract-control.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,16 @@
/* eslint-disable @typescript-eslint/no-this-alias */
import type { FormGroup } from './form-group';
import type { AsyncValidatorFn, ValidationErrors, ValidatorFn } from './validators';
import type { Subscription } from 'rxjs';

import { isArray } from 'lodash';
import { from, Subject } from 'rxjs';
import { forkJoin } from 'rxjs';

import { FormGroup } from './form-group';

export type FormControlStatus = 'VALID' | 'INVALID' | 'PENDING' | 'DISABLED';

export const [VALID, INVALID, PENDING, DISABLED] = ['VALID', 'INVALID', 'PENDING', 'DISABLED'] as FormControlStatus[];

type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};

type GetFormControlPropertyFromArray<T, A> = Mutable<A> extends [infer K, ...infer R]
? K extends keyof T
? GetFormControlPropertyFromArray<T[K], R>
: null
: T;

type GetFormControlProperty<T, S> = S extends `${infer K}.${infer R}`
? K extends keyof T
? GetFormControlProperty<T[K], R>
: null
: S extends keyof T
? T[S]
: null;

function find(control: AbstractControl, path: string[] | string, delimiter: string) {
if (path == null) return null;

if (!Array.isArray(path)) {
path = path.split(delimiter);
}
if (Array.isArray(path) && path.length === 0) return null;

// Not using Array.reduce here due to a Chrome 80 bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
let controlToFind: AbstractControl | null = control;
path.forEach((name) => {
if (controlToFind instanceof FormGroup) {
controlToFind = name in controlToFind.controls ? controlToFind.controls[name] : null;
} else {
controlToFind = null;
}
});
return controlToFind;
}

function mergeErrors(arrayOfErrors: (ValidationErrors | null)[]): ValidationErrors | null {
const res: { [key: string]: any } = {};

Expand Down Expand Up @@ -323,21 +283,6 @@ export abstract class AbstractControl<V = any> {
}
}

get<S extends string>(path: S): AbstractControl<GetFormControlProperty<V, S>>;
get<S extends ArrayLike<string>>(path: S): AbstractControl<GetFormControlPropertyFromArray<V, S>>;
get(path: string[] | string): AbstractControl | null {
return find(this, path, '.');
}

getError(errorCode: string, path?: string[] | string): any {
const control = path ? this.get(path) : this;
return control && control.errors ? control.errors[errorCode] : null;
}

hasError(errorCode: string, path?: string[] | string): boolean {
return !!this.getError(errorCode, path);
}

protected abstract _value: V;

protected abstract _status: FormControlStatus;
Expand Down
8 changes: 8 additions & 0 deletions packages/ui/src/components/form/form-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ export class FormControl<V> extends AbstractControl<V> {
this.updateValueAndValidity(true);
}

getError(errorCode: string): any {
return this && this.errors ? this.errors[errorCode] : null;
}

hasError(errorCode: string): boolean {
return !!this.getError(errorCode);
}

override setValue(value: V, onlySelf?: boolean): void {
this._value = value;
this.updateValueAndValidity(onlySelf);
Expand Down
54 changes: 54 additions & 0 deletions packages/ui/src/components/form/form-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,45 @@ import type { AsyncValidatorFn, ValidatorFn } from './validators';

import { AbstractControl, VALID } from './abstract-control';

type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};

type GetFormControlPropertyFromArray<T, A> = Mutable<A> extends [infer K, ...infer R]
? K extends keyof T
? GetFormControlPropertyFromArray<T[K], R>
: null
: T;

type GetFormControlProperty<T, S> = S extends `${infer K}.${infer R}`
? K extends keyof T
? GetFormControlProperty<T[K], R>
: null
: S extends keyof T
? T[S]
: null;

function find(control: AbstractControl, path: string[] | string, delimiter: string) {
if (path == null) return null;

if (!Array.isArray(path)) {
path = path.split(delimiter);
}
if (Array.isArray(path) && path.length === 0) return null;

// Not using Array.reduce here due to a Chrome 80 bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
let controlToFind: AbstractControl | null = control;
path.forEach((name) => {
if (controlToFind instanceof FormGroup) {
controlToFind = name in controlToFind.controls ? controlToFind.controls[name] : null;
} else {
controlToFind = null;
}
});
return controlToFind;
}

export class FormGroup<T extends { [K in keyof T]: AbstractControl } = any> extends AbstractControl<{ [K in keyof T]: T[K]['value'] }> {
protected _value!: { [K in keyof T]: T[K]['value'] };
protected _status: FormControlStatus = VALID;
Expand All @@ -17,6 +56,21 @@ export class FormGroup<T extends { [K in keyof T]: AbstractControl } = any> exte
this.updateValueAndValidity(true);
}

get<S extends string>(path: S): AbstractControl<GetFormControlProperty<T, S>>;
get<S extends ArrayLike<string>>(path: S): AbstractControl<GetFormControlPropertyFromArray<T, S>>;
get(path: string[] | string): AbstractControl | null {
return find(this, path, '.');
}

getError(errorCode: string, path?: string[] | string): any {
const control = path ? this.get(path) : this;
return control && control.errors ? control.errors[errorCode] : null;
}

hasError(errorCode: string, path?: string[] | string): boolean {
return !!this.getError(errorCode, path);
}

addControl<K extends keyof T>(name: K, control: T[K]): void;
addControl(name: string, control: AbstractControl): void;
addControl(name: string, control: AbstractControl): void {
Expand Down

0 comments on commit 1b21527

Please sign in to comment.