Skip to content

Commit 0769c15

Browse files
authored
Feature/regex rule (#24)
* WIP * WIP * Added regex rule * Added regex to export
1 parent 744f95f commit 0769c15

File tree

5 files changed

+92
-8
lines changed

5 files changed

+92
-8
lines changed

__tests__/suits/Validator.test.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('test validator', () => {
109109

110110
it('should merge rules', () => {
111111
const rules = Validator.mergeRules(['rule_one', 'rule_two'], 'rule_tree|rule_four', ['rule_five|rule_six']);
112-
expect(rules.length).toBe(6);
112+
expect(rules.length).toBe(5);
113113
});
114114

115115
it('should throw an error when trying to get area when not in area', () => {

__tests__/suits/rules/regex.test.tsx

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Validator } from '@/Validator';
2+
import { mount } from 'enzyme';
3+
import { ValidatorArea, ValidatorAreaProps } from '@/components/ValidatorArea';
4+
import React from 'react';
5+
import regex from '@/rules/regex';
6+
import tick from '../../common/tick';
7+
8+
describe('test regex rule', () => {
9+
beforeEach(() => {
10+
Validator.extend('regex', regex);
11+
});
12+
13+
it('should always validate inputs and not validate non-inputs', async (): Promise<void> => {
14+
const input = document.createElement('input');
15+
const canvas = document.createElement('canvas');
16+
input.value = 'foo,|bar';
17+
18+
const validator_input = new Validator([
19+
input
20+
],
21+
['regex:(\\w)+,(\\w)+'],
22+
'');
23+
24+
const validator_canvas = new Validator([
25+
canvas
26+
],
27+
['regex:(\\w)+,(\\w)+'],
28+
'');
29+
30+
await validator_input.validate();
31+
expect(validator_input.getErrors().length).toBe(1);
32+
33+
await validator_canvas.validate();
34+
expect(validator_canvas.getErrors().length).toBe(0);
35+
});
36+
37+
it('should validate select', async () => {
38+
const area = mount<ValidatorArea, ValidatorAreaProps>(
39+
<ValidatorArea rules="regex:(\w)+,(\w)+">
40+
<select name="test">
41+
<option value="4" selected>Option</option>
42+
</select>
43+
</ValidatorArea>
44+
);
45+
46+
area.find('select').simulate('blur');
47+
await tick();
48+
expect(area.state().errors.length).toBe(1);
49+
});
50+
});

src/Validator.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,35 @@ export class Validator {
124124
return typeof Validator.rules[rule] === 'function';
125125
}
126126

127+
/**
128+
* Get the rule name and the parameters as tuple
129+
*/
130+
private static getRuleNameAndParameters(rule: string): [string, string[]] {
131+
const [name, ...splittedParameters] = rule.split(':');
132+
const parameters = splittedParameters.join(':');
133+
134+
if (['regex'].indexOf(name) !== -1) {
135+
return [name, [parameters]];
136+
}
137+
138+
return [name, parameters.split(',')];
139+
}
140+
127141
/**
128142
* Validate a specific rule
129143
*/
130144
private async validateRule(rule: string): Promise<boolean> {
131-
const [ruleName, ruleArgs = ''] = rule.split(':');
145+
const [ruleName, ruleParameters] = Validator.getRuleNameAndParameters(rule);
132146

133147
if (Validator.ruleExists(ruleName)) {
134148
const ruleObj: RuleObject = Validator.isRuleFunction(ruleName)
135149
? (Validator.rules[ruleName] as RuleFunction)(this)
136150
: Validator.rules[ruleName] as RuleObject;
137151

138-
const ruleArgsArray = ruleArgs.split(',');
139-
140-
const passed = await ruleObj.passed(this.elements, ...ruleArgsArray);
152+
const passed = await ruleObj.passed(this.elements, ...ruleParameters);
141153

142154
if(!passed) {
143-
this.errors.push(this.localize(ruleObj.message(), ...ruleArgsArray));
155+
this.errors.push(this.localize(ruleObj.message(), ...ruleParameters));
144156
return false;
145157
}
146158

@@ -215,12 +227,12 @@ export class Validator {
215227
* Merges rules from different sources into one array
216228
*/
217229
public static mergeRules(...rules: RuleOptions[]): string[] {
218-
const mergedRules: string[] = [];
230+
let mergedRules: string[] = [];
219231
rules.forEach((rule: string | string[]) => {
220232
if (typeof rule === 'string') {
221233
rule.split('|').forEach((subRule) => mergedRules.push(subRule));
222234
} else if (Array.isArray(rule) && rule.length) {
223-
Validator.mergeRules(...rule).forEach((subRule) => mergedRules.push(subRule));
235+
mergedRules = [...mergedRules, ...rule];
224236
}
225237
});
226238

src/rules/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export { default as min } from '@/rules/min';
22
export { default as max } from '@/rules/max';
33
export { default as required } from '@/rules/required';
44
export { default as activeUrl } from '@/rules/activeUrl';
5+
export { default as regex } from '@/rules/regex';
56
export { IncorrectArgumentTypeError } from '@/rules/IncorrectArgumentTypeError';

src/rules/regex.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { isInputElement, isSelectElement, getValue } from '@/common/dom';
2+
3+
4+
export default {
5+
passed(elements: HTMLElement[], pattern: string): boolean {
6+
return elements.every((element: HTMLElement) => {
7+
const matchesRegex = (value: string) => new RegExp(pattern).test(value);
8+
9+
if (isInputElement(element) || isSelectElement(element)) {
10+
const values = getValue(element).filter(Boolean);
11+
12+
return values.every((value) => matchesRegex(value));
13+
}
14+
15+
return true;
16+
})
17+
},
18+
message(): string {
19+
return '{name} heeft een ongeldig formaat';
20+
}
21+
}

0 commit comments

Comments
 (0)