Skip to content

Commit

Permalink
fix: if this makes sense
Browse files Browse the repository at this point in the history
  • Loading branch information
imranbarbhuiya committed Dec 6, 2022
1 parent b652b78 commit e2ebb91
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 14 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -809,12 +809,10 @@ provides the schema when `is` resolves truthy, and `otherwise` provides the sche
##### Available options for providing `is`

When `is` is not provided (`=== undefined`) it is strictly resolved as `Boolean(value)` wherein `value` is the current
value of the referenced sibling. Note that if the refeferenced sibling is an array that this will mean the result is
always `true` because `Boolean([...])` is true.
value of the referenced sibling. Note that if multiple siblings are referenced then all the values of the array need to
resolve truthy for the `is` to resolve truthy.

When `is` is a primitive literal it is strictly compared (`===`) to the current value of the referenced sibling, or
through [`Array#some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) with
a strict negative comparison (`!==`) for each element if multiple siblings are referenced.
When `is` is a primitive literal it is strictly compared (`===`) to the current value.

If you want to use a different form of equality you can provide a function like: `is: (value) => value === true`.

Expand Down
14 changes: 6 additions & 8 deletions src/constraints/ObjectConstrains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export function whenConstraint<T extends BaseValidator<any>, I, Key extends When
return Result.err(new ExpectedConstraintError('s.object(T.when)', 'Validator has no parent', parent, 'Validator to have a parent'));
}

const value = Array.isArray(key) ? key.map((k) => get(parent, k)) : get(parent, key);
const isKeyArray = Array.isArray(key);

const predicate = resolveBooleanIs<T, Key>(options, value) ? options.then : options.otherwise;
const value = isKeyArray ? key.map((k) => get(parent, k)) : get(parent, key);

const predicate = resolveBooleanIs<T, Key>(options, value, isKeyArray) ? options.then : options.otherwise;

if (predicate) {
return predicate(validator).run(input) as Result<I, ExpectedConstraintError<I>>;
Expand All @@ -38,18 +40,14 @@ export function whenConstraint<T extends BaseValidator<any>, I, Key extends When
};
}

function resolveBooleanIs<T extends BaseValidator<any>, Key extends WhenKey>(options: WhenOptions<T, Key>, value: any) {
function resolveBooleanIs<T extends BaseValidator<any>, Key extends WhenKey>(options: WhenOptions<T, Key>, value: any, isKeyArray: boolean) {
if (options.is === undefined) {
return Boolean(value);
return isKeyArray ? !value.some((val: any) => !val) : Boolean(value);
}

if (typeof options.is === 'function') {
return options.is(value);
}

if (Array.isArray(value)) {
return !value.some((val) => val !== options.is);
}

return value === options.is;
}
51 changes: 50 additions & 1 deletion tests/validators/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ describe('ObjectValidator', () => {
);
});

test('Given a key WITH is boolean THEN return value based on the value at key position', () => {
test('Given a key WITH is primitive literal THEN return value based on the value strictly equal to the primitive literal', () => {
const whenPredicate = s.object({
booleanLike: s.boolean,
numberLike: s.number.when('booleanLike', {
Expand Down Expand Up @@ -434,6 +434,55 @@ describe('ObjectValidator', () => {
);
});

test('Given an array of keys WITHOUT is THEN check truly of each values', () => {
const whenPredicate = s.object({
booleanLike: s.boolean,
stringLike: s.string,
numberLike: s.number.when(['booleanLike', 'stringLike'], {
then: (schema) => schema.greaterThanOrEqual(5),
otherwise: (schema) => schema.lessThanOrEqual(5)
})
});

expect(whenPredicate.parse({ booleanLike: true, stringLike: 'foo', numberLike: 6 })).toStrictEqual({
booleanLike: true,
stringLike: 'foo',
numberLike: 6
});
expectError(
() => whenPredicate.parse({ booleanLike: true, stringLike: 'foo', numberLike: 4 }),
new CombinedPropertyError([
['numberLike', new ExpectedConstraintError('s.number.greaterThanOrEqual', 'Invalid number value', 4, 'expected >= 5')]
])
);

expect(whenPredicate.parse({ booleanLike: false, stringLike: 'foo', numberLike: 4 })).toStrictEqual({
booleanLike: false,
stringLike: 'foo',
numberLike: 4
});

expect(whenPredicate.parse({ booleanLike: true, stringLike: '', numberLike: 4 })).toStrictEqual({
booleanLike: true,
stringLike: '',
numberLike: 4
});

expectError(
() => whenPredicate.parse({ booleanLike: false, stringLike: 'foo', numberLike: 6 }),
new CombinedPropertyError([
['numberLike', new ExpectedConstraintError('s.number.lessThanOrEqual', 'Invalid number value', 6, 'expected <= 5')]
])
);

expectError(
() => whenPredicate.parse({ booleanLike: true, stringLike: '', numberLike: 6 }),
new CombinedPropertyError([
['numberLike', new ExpectedConstraintError('s.number.lessThanOrEqual', 'Invalid number value', 6, 'expected <= 5')]
])
);
});

test('Given a number key THEN return return value based on the key', () => {
const whenPredicate = s.object({
1: s.boolean,
Expand Down

0 comments on commit e2ebb91

Please sign in to comment.