Skip to content

Commit

Permalink
feat: add optionalWhen variant (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
RomainLanz authored Dec 20, 2024
1 parent d4192cb commit 9126796
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/schema/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,20 @@ boolean.optional = function optionalBoolean(options?: SchemaFnOptions) {
return castToBoolean(key, value, options?.message)
}
}

/**
* Same as the optional rule, but allows a condition to decide when to
* validate the value
*/
boolean.optionalWhen = function optionalWhenBoolean(
condition: boolean | ((key: string, value?: string) => boolean),
options?: SchemaFnOptions
) {
return function validate(key: string, value?: string): boolean | undefined {
if (typeof condition === 'function' ? condition(key, value) : condition) {
return boolean.optional(options)(key, value)
}

return boolean(options)(key, value)
}
}
17 changes: 17 additions & 0 deletions src/schema/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,20 @@ number.optional = function optionalNumber(options?: SchemaFnOptions) {
return castToNumber(key, value, options?.message)
}
}

/**
* Same as the optional rule, but allows a condition to decide when to
* validate the value
*/
number.optionalWhen = function optionalWhenNumber(
condition: boolean | ((key: string, value?: string) => boolean),
options?: SchemaFnOptions
) {
return function validate(key: string, value?: string): number | undefined {
if (typeof condition === 'function' ? condition(key, value) : condition) {
return number.optional(options)(key, value)
}

return number(options)(key, value)
}
}
17 changes: 17 additions & 0 deletions src/schema/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,20 @@ string.optional = function optionalString(options?: StringFnOptions) {
return value
}
}

/**
* Same as the optional rule, but allows a condition to decide when to
* validate the value
*/
string.optionalWhen = function optionalWhenString(
condition: boolean | ((key: string, value?: string) => boolean),
options?: StringFnOptions
) {
return function validate(key: string, value?: string): string | undefined {
if (typeof condition === 'function' ? condition(key, value) : condition) {
return string.optional(options)(key, value)
}

return string(options)(key, value)
}
}
78 changes: 78 additions & 0 deletions tests/schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,32 @@ test.group('schema | number.optional', () => {
expectTypeOf(value).toEqualTypeOf<number | undefined>()
assert.deepEqual(value, -22.198)
})

test('allow conditional optional', ({ assert, expectTypeOf }) => {
const value = schema.number.optionalWhen(true)('PORT')
expectTypeOf(value).toEqualTypeOf<number | undefined>()
assert.isUndefined(value)

const value2 = schema.number.optionalWhen(false)('PORT', '22')
expectTypeOf(value2).toEqualTypeOf<number | undefined>()
assert.deepEqual(value2, 22)

const fn = () => schema.number.optionalWhen(false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})

test('allow conditional optional with function', ({ assert, expectTypeOf }) => {
const value = schema.number.optionalWhen(() => true)('PORT')
expectTypeOf(value).toEqualTypeOf<number | undefined>()
assert.isUndefined(value)

const value2 = schema.number.optionalWhen(() => false)('PORT', '22')
expectTypeOf(value2).toEqualTypeOf<number | undefined>()
assert.deepEqual(value2, 22)

const fn = () => schema.number.optionalWhen(() => false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})
})

test.group('schema | string', () => {
Expand Down Expand Up @@ -154,6 +180,32 @@ test.group('schema | string.optional', () => {
'mailgun:1234/v1'
)
})

test('allow conditional optional', ({ assert, expectTypeOf }) => {
const value = schema.string.optionalWhen(true)('PORT')
expectTypeOf(value).toEqualTypeOf<string | undefined>()
assert.deepEqual(value, undefined)

const value2 = schema.string.optionalWhen(false)('PORT', '22')
expectTypeOf(value2).toEqualTypeOf<string | undefined>()
assert.deepEqual(value2, '22')

const fn = () => schema.string.optionalWhen(false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})

test('allow conditional optional with function', ({ assert, expectTypeOf }) => {
const value = schema.string.optionalWhen(() => true)('PORT')
expectTypeOf(value).toEqualTypeOf<string | undefined>()
assert.deepEqual(value, undefined)

const value2 = schema.string.optionalWhen(() => false)('PORT', '22')
expectTypeOf(value2).toEqualTypeOf<string | undefined>()
assert.deepEqual(value2, '22')

const fn = () => schema.string.optionalWhen(() => false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})
})

test.group('schema | boolean', () => {
Expand Down Expand Up @@ -238,6 +290,32 @@ test.group('schema | boolean.optional', () => {
expectTypeOf(value).toEqualTypeOf<boolean | undefined>()
assert.deepEqual(value, false)
})

test('allow conditional optional', ({ assert, expectTypeOf }) => {
const value = schema.boolean.optionalWhen(true)('PORT')
expectTypeOf(value).toEqualTypeOf<boolean | undefined>()
assert.deepEqual(value, undefined)

const value2 = schema.boolean.optionalWhen(false)('PORT', 'true')
expectTypeOf(value2).toEqualTypeOf<boolean | undefined>()
assert.deepEqual(value2, true)

const fn = () => schema.boolean.optionalWhen(false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})

test('allow conditional optional with function', ({ assert, expectTypeOf }) => {
const value = schema.boolean.optionalWhen(() => true)('PORT')
expectTypeOf(value).toEqualTypeOf<boolean | undefined>()
assert.deepEqual(value, undefined)

const value2 = schema.boolean.optionalWhen(() => false)('PORT', 'true')
expectTypeOf(value2).toEqualTypeOf<boolean | undefined>()
assert.deepEqual(value2, true)

const fn = () => schema.boolean.optionalWhen(() => false)('PORT')
assert.throws(fn, 'Missing environment variable "PORT"')
})
})

test.group('schema | enum', () => {
Expand Down

0 comments on commit 9126796

Please sign in to comment.