Skip to content

Commit

Permalink
feat: added a new 'requiredBy' rule to configure field dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ziccardi committed Oct 2, 2020
1 parent abd9813 commit 3014ba1
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/rules/RequiredByRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {RuleConfig} from '../config/RuleConfig';
import {GenericValidator} from './GenericValidator';
import {Data} from '../Data';
import {get} from 'lodash';

export const rule = (config: RuleConfig) =>
new GenericValidator(
config,
(value: string, config: RuleConfig, data: Data) => {
const isEmpty = (val: string): boolean => !val || val.length === 0;

const parentValue = get(data, config.parent as string) as string;
return isEmpty(parentValue) || !isEmpty(value);
},
`'%s' is required by ${config.parent}`,
true
);

export const NAME = 'REQUIREDBY';
2 changes: 2 additions & 0 deletions src/rules/RuleBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {builder as LengthRuleBuilder} from './builders/LengthRuleBuilder';
import {builder as MatchesRuleBuilder} from './builders/MatchesRuleBuilder';
import {builder as IsBase64Builder} from './builders/IsBase64Builder';
import {builder as IsValidUrlBuilder} from './builders/IsValidUrlBuilder';
import {builder as RequiredByBuilder} from './builders/RequiredByRuleBuilder';

// tslint:disable-next-line:variable-name
export const RuleBuilder = {
Expand All @@ -17,4 +18,5 @@ export const RuleBuilder = {
matches: MatchesRuleBuilder.withPattern,
isBase64: IsBase64Builder,
isValidUrl: IsValidUrlBuilder.isValidUrl,
isRequiredBy: RequiredByBuilder,
};
16 changes: 16 additions & 0 deletions src/rules/builders/RequiredByRuleBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {RuleConfig} from '../../config/RuleConfig';
import * as RequiredByRule from '../RequiredByRule';

export class Builder {
private readonly config: RuleConfig;
constructor(config: RuleConfig) {
this.config = config;
}

public readonly build = () => this.config;
}

export const builder = {
withParent: (parent: string, errorMessage?: string): Builder =>
new Builder({type: RequiredByRule.NAME, parent, errorMessage}),
};
2 changes: 2 additions & 0 deletions src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as RequiredRule from './RequiredRule';
import * as ValidUrlPathRule from './ValidUrlPathRule';
import * as ValidUrlRule from './ValidUrlRule';
import * as LengthRule from './LengthRule';
import * as RequiredByRule from './RequiredByRule';
import {CompositeRule} from './CompositeRule';
import {RuleConfig} from '../config/RuleConfig';

Expand All @@ -15,4 +16,5 @@ export const RULE_DICTIONARY = {
[ValidUrlPathRule.NAME]: ValidUrlPathRule.rule,
[ValidUrlRule.NAME]: ValidUrlRule.rule,
[LengthRule.NAME]: LengthRule.rule,
[RequiredByRule.NAME]: RequiredByRule.rule,
};
64 changes: 64 additions & 0 deletions test/builder/RequiredBy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {testValidator} from '../utils';
import {RuleBuilder, Validator, validatorBuilder} from '../../src';

const validator: Validator = validatorBuilder()
.newRule()
.withField('webpushVapidPublicKey')
.validate(RuleBuilder.matches('^[A-Za-z0-9_-]*$'))
.withField('webpushVapidPrivateKey')
.validate(
RuleBuilder.isRequiredBy.withParent('webpushVapidPublicKey').build()
)
.validate(RuleBuilder.matches('^[A-Za-z0-9_-]*$'))
.withField('webpushAlias')
.validate(
RuleBuilder.required()
.withErrorMessage('Please enter a valid URL or mailto address')
.build()
)
.validate(
RuleBuilder.composite
.any()
.withSubRule(
RuleBuilder.matches(
'^mailto: ?(?:[a-z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\\])$'
)
)
.withSubRule(
RuleBuilder.isValidUrl()
.requireTld(true)
.requireHost(true)
.requireProtocol(true)
.build()
)
.build('Please enter a valid URL or mailto address')
)
.build();

describe('RequiredBy Validator Builder', () => {
it('Only name and alias', () => {
testValidator(validator, {
valid: [{name: 'test', webpushAlias: 'mailto:mziccard@redhat.com'}],
invalid: [{name: 'test'}],
});
});
it('Only name and alias and public key', () => {
testValidator(validator, {
valid: [
{
name: 'test',
webpushAlias: 'mailto:mziccard@redhat.com',
webpushVapidPublicKey: 'aaa',
webpushVapidPrivateKey: 'aaa',
},
],
invalid: [
{
name: 'test',
webpushAlias: 'mailto:mziccard@redhat.com',
webpushVapidPublicKey: 'aaa',
},
],
});
});
});

0 comments on commit 3014ba1

Please sign in to comment.