generated from sapphiredev/sapphire-template
-
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: lazy validator * fix: types and nested test * test: add circular test * chore: add expect error * chore: peopleware chapter 8: "you never get anything done around here between 9 and 5." permalink: http://whatthecommit.com/17d9ac5396b751c8be5cceca8c56769f * chore: merge pull my finger request permalink: http://whatthecommit.com/569aa58b98f6e4aac466357a4997c2b2 * chore: dismiss 2 approvals * chore: this is why docs are important permalink: http://whatthecommit.com/3bdc00b8165a743b7ee0716faf792d4f Co-authored-by: Jeroen Claassens <support@favware.tech>
- Loading branch information
1 parent
d3751f6
commit 807666e
Showing
3 changed files
with
100 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { Result } from '../lib/Result'; | ||
import type { IConstraint, Unwrap } from '../type-exports'; | ||
import { BaseValidator, ValidatorError } from './imports'; | ||
|
||
export class LazyValidator<T extends BaseValidator<unknown>, R = Unwrap<T>> extends BaseValidator<R> { | ||
private readonly validator: (value: unknown) => T; | ||
|
||
public constructor(validator: (value: unknown) => T, constraints: readonly IConstraint<R>[] = []) { | ||
super(constraints); | ||
this.validator = validator; | ||
} | ||
|
||
protected override clone(): this { | ||
return Reflect.construct(this.constructor, [this.validator, this.constraints]); | ||
} | ||
|
||
protected handle(values: unknown): Result<R, ValidatorError> { | ||
return this.validator(values).run(values) as Result<R, ValidatorError>; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { CombinedPropertyError, ExpectedConstraintError, MissingPropertyError, s, SchemaOf, ValidationError } from '../../src'; | ||
import { expectError } from '../common/macros/comparators'; | ||
|
||
describe('LazyValidator', () => { | ||
const predicate = s.lazy((value) => { | ||
if (typeof value === 'boolean') return s.boolean.true; | ||
return s.string; | ||
}); | ||
|
||
test.each([true, 'hello'])('GIVEN %j THEN returns the given value', (input) => { | ||
expect<true | string>(predicate.parse(input)).toBe(input); | ||
}); | ||
|
||
test('GIVEN an invalid value THEN throw ValidationError', () => { | ||
expectError(() => predicate.parse(123), new ValidationError('s.string', 'Expected a string primitive', 123)); | ||
}); | ||
}); | ||
|
||
describe('NestedLazyValidator', () => { | ||
const predicate = s.lazy((value) => { | ||
if (typeof value === 'boolean') return s.boolean.true; | ||
return s.lazy((value) => { | ||
if (typeof value === 'string') return s.string.lengthEqual(5); | ||
return s.number; | ||
}); | ||
}); | ||
|
||
test.each([true, 'hello', 123])('GIVEN %j THEN returns the given value', (input) => { | ||
expect<true | string | number>(predicate.parse(input)).toBe(input); | ||
}); | ||
|
||
test('GIVEN an invalid value THEN throw ValidationError', () => { | ||
expectError( | ||
() => predicate.parse('Sapphire'), | ||
new ExpectedConstraintError('s.string.lengthEqual', 'Invalid string length', 'Sapphire', 'expected.length === 5') | ||
); | ||
}); | ||
}); | ||
|
||
describe('CircularLazyValidator', () => { | ||
interface PredicateSchema { | ||
id: string; | ||
items: PredicateSchema; | ||
} | ||
|
||
const predicate: SchemaOf<PredicateSchema> = s.object({ | ||
id: s.string, | ||
items: s.lazy<SchemaOf<PredicateSchema>>(() => predicate) | ||
}); | ||
|
||
test('GIVEN circular schema THEN throw ', () => { | ||
expectError( | ||
() => predicate.parse({ id: 'Hello', items: { id: 'Hello', items: { id: 'Hello' } } }), | ||
new CombinedPropertyError([ | ||
['items', new CombinedPropertyError([['items', new CombinedPropertyError([['items', new MissingPropertyError('items')]])]])] | ||
]) | ||
); | ||
}); | ||
}); | ||
|
||
describe('PassingCircularLazyValidator', () => { | ||
interface PredicateSchema { | ||
id: string; | ||
items?: PredicateSchema; | ||
} | ||
|
||
const predicate: SchemaOf<PredicateSchema> = s.object({ | ||
id: s.string, | ||
items: s.lazy<SchemaOf<PredicateSchema>>(() => predicate).optional | ||
}); | ||
|
||
test('GIVEN circular schema THEN return given value', () => { | ||
expect(predicate.parse({ id: 'Sapphire', items: { id: 'Hello' } })).toStrictEqual({ id: 'Sapphire', items: { id: 'Hello' } }); | ||
}); | ||
}); |