Skip to content

Commit

Permalink
added: [N4S] allOf compound rule (#533)
Browse files Browse the repository at this point in the history
  • Loading branch information
Moses3301 committed Dec 1, 2020
1 parent cd51080 commit c2ea710
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 5 deletions.
1 change: 1 addition & 0 deletions jsconfig.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions packages/n4s/docs/compound.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Alongside the list of rules that only accept data provided by the user, enforce also supports compound rules - these are rules that accept other rules as their arguments. These rules let you validate more complex scenarios with the ergonomics of enforce.

- [enforce.anyOf() - either/or validations](#anyof)
- [enforce.allOf() - all/and validations](#allof)
- [enforce.shape() - Object's shape matching](#shape)
- [enforce.optional() - nullable keys](#optional)
- [enforec.loose() - loose shape matching](#loose)
Expand All @@ -16,6 +17,41 @@ Sometimes a value has more than one valid possibilities, `any` lets us validate
enforce(value).anyOf(enforce.isString(), enforce.isArray()).isNotEmpty();
// A valid value would either an array or a string.
```
## enforce.allOf() - all/and validations :id=allof

`allOf` lets us validate that a value passes _all_ of the supplied rules or templates.

enforce(value).allOf(
enforce.isArray(),
enforce.longerThan(2)
);

This can be even more useful when combined with shapes and templates:

```js
const User = enforce.template(
enforce.loose({
id: enforce.isNumber()
name: enforce.shape({
first: enforce.isString(),
last: enforce.isString(),
middle: enforce.optional(enforce.isString()),
}),
})
);

const DisabledAccount = enforce.template(
enforce.loose({
disabled: enforce.equals(true)
})
)

enforce(value).allOf(
User,
DisabledAccount
);
// A valid is string and longer then 5.
```

## enforce.shape() - Lean schema validation. :id=shape

Expand Down
2 changes: 1 addition & 1 deletion packages/n4s/docs/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Username('1234'); // throws
Username('ab'); // throws
```

You can also use templates inside other compound rules, such as `shape`, `isArrayOf` or `anyOf`.
You can also use templates inside other compound rules, such as `shape`, `isArrayOf` ,`anyOf` or `allOf`.

```js
enforce({
Expand Down
65 changes: 65 additions & 0 deletions packages/n4s/src/enforce/compounds/__tests__/allOf.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import allOf from 'allOf';
import enforce from 'enforce';

describe('allOf validation', () => {
describe('Base behavior', () => {
it('Should fail when at least one rule fails', () => {
expect(allOf('test', enforce.isString(), enforce.longerThan(10))).toBe(
false
);
});
it('Should succeed when all of the rules apply', () => {
expect(allOf('test', enforce.isString(), enforce.longerThan(3))).toBe(
true
);
});
it('Should pass when no rules are provided', () => {
expect(allOf(3)).toBe(true);
});
});

describe('As part of enforce', () => {
const User = enforce.template(
enforce.loose({
id: enforce.isNumber(),
name: enforce.shape({
first: enforce.isString(),
last: enforce.isString(),
middle: enforce.optional(enforce.isString()),
}),
})
);

const DisabledAccount = enforce.template(
enforce.loose({
disabled: enforce.equals(true),
})
);

it('Should validate allof the rules correctly', () => {
enforce({
id: 123,
name: { first: 'Albert', last: 'Einstein' },
disabled: true,
}).allOf(User, DisabledAccount);
});

it('Should throw if one of the rules fail', () => {
expect(() => {
enforce({
id: 123,
name: { first: 'Albert', last: 0 },
disabled: true,
}).allOf(User, DisabledAccount);
}).toThrow();

expect(() => {
enforce({
id: 123,
name: { first: 'Albert', last: 'Einstein' },
disabled: false,
}).allOf(User, DisabledAccount);
}).toThrow();
});
});
});
2 changes: 0 additions & 2 deletions packages/n4s/src/enforce/compounds/__tests__/anyOf.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,13 @@ describe('AnyOf validation', () => {
expect(anyOf(5)).toBe(true);
});
});

describe('As part of enforce', () => {
it('Should validate anyof the rules correctly', () => {
enforce(77).anyOf(
enforce.isString(),
enforce.isNumber(),
enforce.isUndefined()
);

expect(() =>
enforce({ test: 4 }).anyOf(enforce.isNumber(), enforce.isUndefined())
).toThrow();
Expand Down
10 changes: 10 additions & 0 deletions packages/n4s/src/enforce/compounds/allOf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import runLazyRules from 'runLazyRules';
import { withFirst } from 'withArgs';

function allOf(value, rules) {
return (
!rules.length || rules.every(ruleGroup => runLazyRules(ruleGroup, value))
);
}

export default withFirst(allOf);
6 changes: 4 additions & 2 deletions packages/n4s/src/enforce/compounds/compounds.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import allOf from 'allOf';
import anyOf from 'anyOf';
import isArrayOf from 'isArrayOf';
import oneOf from 'oneOf';
import optional from 'optional';
import { shape, loose } from 'shape';

export default {
allOf,
anyOf,
isArrayOf,
loose,
oneOf,
optional,
shape,
oneOf
shape
};
4 changes: 4 additions & 0 deletions packages/vest/src/__tests__/test_types/fixtures/enforce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@ enforce
// anyOf
enforce(1).anyOf(enforce.isNumber(), enforce.isArray());
enforce.anyOf(enforce.isNumber(), enforce.isArray()).test(1);

// allOf
enforce('hello').allOf(enforce.isString(), enforce.longerThan(3));
enforce.allOf(enforce.isString(), enforce.longerThan(3)).test('hello');
4 changes: 4 additions & 0 deletions packages/vest/src/__tests__/test_types/fixtures/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,16 @@ enforce(0).shorterThanOrEquals;
enforce.shorterThanOrEquals;
enforce(0).startsWith;
enforce.startsWith;
enforce(0).allOf;
enforce.allOf;
enforce(0).anyOf;
enforce.anyOf;
enforce(0).isArrayOf;
enforce.isArrayOf;
enforce(0).loose;
enforce.loose;
enforce(0).oneOf;
enforce.oneOf;
enforce(0).optional;
enforce.optional;
enforce(0).shape;
Expand Down
2 changes: 2 additions & 0 deletions packages/vest/src/typings/enforce.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ interface IEnforceRules<T = {}> {
) => RuleReturn<T>;
isArrayOf: CompoundListOfRules<T>;
anyOf: CompoundListOfRules<T>;
allOf: CompoundListOfRules<T>;
oneOf: CompoundListOfRules<T>;
}

Expand Down Expand Up @@ -195,6 +196,7 @@ type TEnforceLazy = {
optional: LazyCopmoundListOfRules;
isArrayOf: LazyCopmoundListOfRules;
anyOf: LazyCopmoundListOfRules;
allOf: LazyCopmoundListOfRules;
oneOf: LazyCopmoundListOfRules;
};

Expand Down

0 comments on commit c2ea710

Please sign in to comment.