Skip to content

Commit

Permalink
feat: validator types improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
foxhound87 committed Jan 17, 2024
1 parent 3eebace commit 415cc6a
Show file tree
Hide file tree
Showing 30 changed files with 122 additions and 94 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 6.9.0 (master)
- Validator types improvements.
- introduced `ValidationPlugin`, `ExtendPlugin` and `ValidationPluginConfig` models.
- mandatory `package` prop when defining Validation Plugins.
- deprecated `allowRequired` option (SVK).
- Fix: `showErrors()` deep disabled when validating field.

# 6.8.3 (master)
- Fix: deprecated field `showAsyncErrors()`, use `showErrors()`.
Expand Down Expand Up @@ -122,7 +128,7 @@
- Updated Issue: #283

# 5.9.1 (next)
Fix: using `autoTrimValue` option will not trigger `onChange` Event Hook
- Fix: using `autoTrimValue` option will not trigger `onChange` Event Hook

# 5.9.0 (next)

Expand All @@ -138,10 +144,12 @@ Fix: using `autoTrimValue` option will not trigger `onChange` Event Hook
- Introduced `validateOnSubmit` form option (active by default).
- Fix: `ref` prop for separated props mode renamed to `refs` (plural)
- Fix: #337

# 5.7.1 (next)

- fix: allow `ref` prop on `set()`
- fix: `ref` computed accessible (before was accessed by $ref)

# 5.7.0 (next)

- Introduced `ref` Field prop. (handle React Refs);
Expand Down Expand Up @@ -200,6 +208,7 @@ fix: #371 #399 #408

- Form level onChange hook
- introduced reducer

# 4.0.0 / 5.0.0 (next)

- Typescript support
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ import dvr from 'mobx-react-form/lib/validators/DVR';
import validatorjs from 'validatorjs';

const plugins = {
dvr: dvr(validatorjs)
dvr: dvr({
package: validatorjs
})
};
```

Expand Down
46 changes: 19 additions & 27 deletions src/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import _ from "lodash";
import { $try } from "./utils";
import ValidatorInterface, {
DriversMap,
ValidationPlugin,
ValidationPluginInterface,
ValidationPlugins,
} from "./models/ValidatorInterface";
Expand Down Expand Up @@ -33,33 +34,30 @@ export default class Validator implements ValidatorInterface {
validate: action,
validateField: action,
});
_.merge(this.plugins, obj.plugins);

this.form = obj.form;
Object.assign(this.plugins, obj.plugins);

this.initDrivers();
this.checkSVKValidationPlugin();
}

initDrivers(): void {
_.map(
this.plugins,
(driver, key) =>
(this.drivers[key] =
driver &&
_.has(driver, "class") &&
new driver.class({
config: driver.config,
_.map(this.plugins, (plugin: ValidationPlugin, key: string) =>
(this.drivers[key] = (plugin && plugin.class) &&
new plugin.class({
config: plugin.config,
state: this.form.state,
promises: this.promises,
}))
);
);
}

validate(opt: any = {}, obj: any = {}): Promise<any> {
const path = $try(opt.path, opt);
const path: string = $try(opt.path, opt);
const instance = $try(opt.field, this.form.select(path, null, false), this.form);
const related = $try(opt.related, obj.related, true);
const showErrors = $try(opt.showErrors, obj.showErrors, false);
const related: boolean = $try(opt.related, obj.related, true);
const showErrors: boolean = $try(opt.showErrors, obj.showErrors, false);
instance.$validating = true;
instance.$validated += 1;

Expand Down Expand Up @@ -112,7 +110,7 @@ export default class Validator implements ValidatorInterface {
related = false,
field = null,
path,
}: any): void {
}): void {
const instance = field || this.form.select(path);
const { options } = this.form.state;
// check if the field is a valid instance
Expand All @@ -129,7 +127,7 @@ export default class Validator implements ValidatorInterface {
if (options.get(OptionsEnum.validateTrimmedValue, instance)) instance.trim();

// get stop on error
const stopOnError = options.get(
const stopOnError: boolean = options.get(
OptionsEnum.stopValidationOnError,
instance
);
Expand All @@ -140,20 +138,18 @@ export default class Validator implements ValidatorInterface {
instance
);

const drivers = validationPluginOrder
const drivers: DriversMap = validationPluginOrder
? validationPluginOrder.map((n: string) => this.drivers[n])
: this.drivers;

// validate with all enabled drivers
_.each(drivers, (driver: ValidationPluginInterface) => {
driver && driver.validate(instance);
if (stopOnError && instance.hasError) {
return false;
}
if (stopOnError && instance.hasError) return;
});

// send error to the view
instance.showErrors(showErrors);
instance.showErrors(showErrors, false);

// related validation
if (related) this.validateRelatedFields(instance, showErrors);
Expand All @@ -166,7 +162,7 @@ export default class Validator implements ValidatorInterface {
validateRelatedFields(field: FieldInterface, showErrors: boolean): void {
if (!field.related || !field.related.length) return;

_.each(field.related, (path) =>
field.related.map((path) =>
this.validateField({
related: false,
showErrors,
Expand All @@ -177,12 +173,8 @@ export default class Validator implements ValidatorInterface {

checkSVKValidationPlugin(): void {
if (_.isNil(this.drivers.svk) && _.get(this.plugins, "svk.config.schema")) {
const form = (this as any).state.form.name
? `Form: ${(this as any).state.form.name}`
: "";
throw new Error(
`The SVK validation schema is defined but no plugin provided (SVK). ${form}`
);
const name = this.form.name ? `Form: ${this.form.name}` : "";
throw new Error(`The SVK validation schema is defined but no plugin provided (SVK). ${name}`);
}
}
}
47 changes: 36 additions & 11 deletions src/models/ValidatorInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,59 @@ export interface ValidatorInterface {
error: string | null;
initDrivers(): void;
validate(opt?: any, obj?: any): Promise<any>;
validateField(opt: any): void;
validateField(opt: {
showErrors: boolean,
related: boolean,
field: FieldInterface,
path: string,
}): void;
validateRelatedFields(field: any, showErrors: boolean): void;
checkSVKValidationPlugin(): void;
}

export type ValidationPlugin = {
class: any,
config?: ValidationPluginConfig,
};

export interface ValidationPlugins {
vjf?: any;
dvr?: any;
svk?: any;
yup?: any;
zod?: any;
vjf?: ValidationPlugin;
dvr?: ValidationPlugin;
svk?: ValidationPlugin;
yup?: ValidationPlugin;
zod?: ValidationPlugin;
}

export type ValidationPackage = any;

export type ExtendPlugin = ({ validator, form }: {
validator: any, // the plugin instance
form: FormInterface
}) => void;

export interface ValidationPluginConfig {
package: ValidationPackage;
schema?: any;
options?: any;
extend?: ExtendPlugin;
}

export interface ValidationPluginConstructor {
config: any;
config: ValidationPluginConfig;
state: StateInterface;
promises: Promise<unknown>[];
}

export interface ValidationPluginInterface extends ValidationPluginConstructor {
extend: any;
validator: any;
validator: ValidatorInterface;
schema?: any;
extend?: ExtendPlugin;
validate(field: FieldInterface);
class?(constructor: ValidationPluginConstructor): void;
}

export interface DriversMap {
[index: string]: ValidationPluginInterface;
export type DriversMap = {
[key in keyof ValidationPlugins]: ValidationPluginInterface;
}

export enum ValidationHooks {
Expand Down
10 changes: 6 additions & 4 deletions src/validators/DVR.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import _ from "lodash";
import {
ValidationPlugin,
ValidationPluginConfig,
ValidationPluginConstructor,
ValidationPluginInterface,
} from "../models/ValidatorInterface";
Expand Down Expand Up @@ -27,14 +29,14 @@ export class DVR implements ValidationPluginInterface {
validator = null;

constructor({
config = {},
config,
state = null,
promises = [],
}: ValidationPluginConstructor) {
this.state = state;
this.promises = promises;
this.extend = config.extend;
this.validator = config.package || config;
this.extend = config?.extend;
this.validator = config.package;
this.extendValidator();
}

Expand Down Expand Up @@ -149,7 +151,7 @@ export class DVR implements ValidationPluginInterface {
}
}

export default (config?: any) => ({
export default (config?: ValidationPluginConfig): ValidationPlugin => ({
class: DVR,
config,
});
23 changes: 7 additions & 16 deletions src/validators/SVK.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import _ from "lodash";
import {
ValidationPlugin,
ValidationPluginConfig,
ValidationPluginConstructor,
ValidationPluginInterface,
} from "../models/ValidatorInterface";
Expand Down Expand Up @@ -34,20 +36,19 @@ class SVK implements ValidationPluginInterface {
schema = null;

constructor({
config = {},
config,
state = null,
promises = [],
}: ValidationPluginConstructor) {
this.state = state;
this.promises = promises;
this.extend = config.extend;
this.extend = config?.extend;
this.schema = config.schema;
this.initAJV(config);
}

extendOptions(options = {}) {
return Object.assign(options, {
allowRequired: _.get(options, "allowRequired") || false,
errorDataPath: "property",
allErrors: true,
coerceTypes: true,
Expand All @@ -57,7 +58,7 @@ class SVK implements ValidationPluginInterface {

initAJV(config) {
// get ajv package
const ajv = config.package || config;
const ajv = config.package;
// create ajv instance
const validator = new ajv(this.extendOptions(config.options));
// extend ajv using "extend" callback
Expand All @@ -72,7 +73,7 @@ class SVK implements ValidationPluginInterface {
}

validate(field) {
const validate = this.validator(this.parseValues(field.state.form.validatedValues));
const validate = this.validator(field.state.form.validatedValues);
// check if is $async schema
if (isPromise(validate)) {
const $p = validate
Expand Down Expand Up @@ -126,19 +127,9 @@ class SVK implements ValidationPluginInterface {
field.invalidate(field.validationAsyncData.message, false, true);
}
}

parseValues(values) {
if (_.get(this.config, "options.allowRequired") === true) {
return _.omitBy(
values,
_.isEmpty || _.isNull || _.isUndefined || _.isNaN
);
}
return values;
}
}

export default (config?: any) => ({
export default (config?: ValidationPluginConfig): ValidationPlugin => ({
class: SVK,
config,
});
10 changes: 6 additions & 4 deletions src/validators/VJF.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
ValidationPlugin,
ValidationPluginConfig,
ValidationPluginConstructor,
ValidationPluginInterface,
} from "../models/ValidatorInterface";
Expand Down Expand Up @@ -32,14 +34,14 @@ export class VJF implements ValidationPluginInterface {
validator = null;

constructor({
config = {},
config,
state = null,
promises = [],
}: ValidationPluginConstructor) {
this.state = state;
this.promises = promises;
this.extend = config.extend;
this.validator = config.package || config;
this.extend = config?.extend;
this.validator = config?.package;
this.extendValidator();
}

Expand Down Expand Up @@ -146,7 +148,7 @@ export class VJF implements ValidationPluginInterface {
}
}

export default (config?: any) => ({
export default (config?: ValidationPluginConfig): ValidationPlugin => ({
class: VJF,
config,
});

0 comments on commit 415cc6a

Please sign in to comment.