Skip to content

Commit

Permalink
fix(s.union): fix union overrides (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranet authored Mar 13, 2022
1 parent 682bcae commit 56e9b19
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 22 deletions.
13 changes: 9 additions & 4 deletions src/validators/UnionValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class UnionValidator<T> extends BaseValidator<T> {
return this.clone();
}

return new UnionValidator([new LiteralValidator(undefined), this.clone()]);
return new UnionValidator([new LiteralValidator(undefined), ...this.validators]);
}

public override get nullable(): UnionValidator<T | null> {
Expand All @@ -56,19 +56,24 @@ export class UnionValidator<T> extends BaseValidator<T> {
return this.clone();
}

return new UnionValidator([new LiteralValidator(null), this.clone()]);
return new UnionValidator([new LiteralValidator(null), ...this.validators]);
}

public override get nullish(): UnionValidator<T | null | undefined> {
if (this.validators.length === 0) return new UnionValidator<T | null | undefined>([new NullishValidator()], this.constraints);

const [validator] = this.validators;
if (validator instanceof NullishValidator) {
if (validator instanceof LiteralValidator) {
// If already nullable or optional, promote the union to nullish:
if (validator.expected === null || validator.expected === undefined) {
return new UnionValidator<T | null | undefined>([new NullishValidator(), ...this.validators.slice(1)], this.constraints);
}
} else if (validator instanceof NullishValidator) {
// If it's already nullish, return a clone:
return this.clone();
}

return new UnionValidator<T | null | undefined>([new NullishValidator(), this.clone()]);
return new UnionValidator<T | null | undefined>([new NullishValidator(), ...this.validators]);
}

public override or<O>(...predicates: readonly BaseValidator<O>[]): UnionValidator<T | O> {
Expand Down
43 changes: 25 additions & 18 deletions tests/validators/union.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,23 @@ describe('UnionValidator', () => {
() => optionalPredicate.parse(value),
new CombinedError([
new ExpectedValidationError('s.literal(V)', 'Expected values to be equals', value, undefined),
new CombinedError([
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
);
});

// TODO: Fix
test.skip('GIVEN s.union(s.string, s.number).optional THEN returns s.union(s.undefined, s.string, s.number)', () => {
test('GIVEN s.union(s.string, s.number).optional THEN returns s.union(s.undefined, s.string, s.number)', () => {
expectClonedValidator(optionalPredicate, s.union(s.undefined, s.string, s.number));
});

describe('nullish', () => {
const nullishPredicate = optionalPredicate.nullish;

test('GIVEN s.union(s.string, s.number).nullable.nullish THEN returns s.union(s.nullish, s.string, s.number)', () => {
expectClonedValidator(nullishPredicate, s.union(s.nullish, s.string, s.number));
});
});
});

describe('nullable', () => {
Expand All @@ -86,18 +91,23 @@ describe('UnionValidator', () => {
() => nullablePredicate.parse(value),
new CombinedError([
new ExpectedValidationError('s.literal(V)', 'Expected values to be equals', value, null),
new CombinedError([
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
);
});

// TODO: Fix
test.skip('GIVEN s.union(s.string, s.number).nullable THEN returns s.union(s.null, s.string, s.number)', () => {
test('GIVEN s.union(s.string, s.number).nullable THEN returns s.union(s.null, s.string, s.number)', () => {
expectClonedValidator(nullablePredicate, s.union(s.null, s.string, s.number));
});

describe('nullish', () => {
const nullishPredicate = nullablePredicate.nullish;

test('GIVEN s.union(s.string, s.number).nullable.nullish THEN returns s.union(s.nullish, s.string, s.number)', () => {
expectClonedValidator(nullishPredicate, s.union(s.nullish, s.string, s.number));
});
});
});

describe('nullish', () => {
Expand All @@ -112,16 +122,13 @@ describe('UnionValidator', () => {
() => nullishPredicate.parse(value),
new CombinedError([
new ValidationError('s.nullish', 'Expected undefined or null', value),
new CombinedError([
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
new ValidationError('s.string', 'Expected a string primitive', value),
new ValidationError('s.number', 'Expected a number primitive', value)
])
);
});

// TODO: Fix
test.skip('GIVEN s.union(s.string, s.number).nullable THEN returns s.union(s.null, s.string, s.number)', () => {
test('GIVEN s.union(s.string, s.number).nullable THEN returns s.union(s.null, s.string, s.number)', () => {
expectClonedValidator(nullishPredicate, s.union(s.null, s.string, s.number));
});
});
Expand Down

0 comments on commit 56e9b19

Please sign in to comment.