Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAKING] Fix #155 | Upgrade jest & node version #172

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
node-version: [ 10, 12, 14 ]
node-version: [ 10, 12, 14, 16 ]

steps:
- uses: actions/checkout@v2
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"prepare": "tsc",
"coverage": "jest --coverage",
"lint": "tsc && prettier -list-different --write src tests",
"test": "jest"
"test": "jest -i"
},
"repository": {
"type": "git",
Expand All @@ -40,9 +40,9 @@
"@types/jest": "26.0.24",
"@types/node": "16.4.0",
"husky": "4.3.6",
"jest": "27.0.6",
"jest": "27.3.0",
"prettier": "2.3.2",
"ts-jest": "27.0.4",
"ts-jest": "27.0.7",
"typescript": "4.3.5"
},
"author": "Aaron Franks",
Expand Down
4 changes: 2 additions & 2 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function validateVar<T>({
}: {
name: string
rawValue: string | T
spec: Spec<T> & { _parse: (input: string) => T }
spec: Spec & { _parse: (input: string) => T }
}) {
if (typeof spec._parse !== 'function') {
throw new EnvError(`Invalid spec for "${name}"`)
Expand All @@ -36,7 +36,7 @@ function validateVar<T>({
}

// Format a string error message for when a required env var is missing
function formatSpecDescription<T>(spec: Spec<T>) {
function formatSpecDescription(spec: Spec) {
const egText = spec.example ? ` (eg. "${spec.example}")` : ''
const docsText = spec.docs ? `. See ${spec.docs}` : ''
return `${spec.desc}${egText}${docsText}`
Expand Down
10 changes: 5 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
export interface Spec<T> {
export interface Spec {
/**
* An Array that lists the admissable parsed values for the env var.
*/
choices?: ReadonlyArray<T>
choices?: ReadonlyArray<string>
/**
* A fallback value, which will be used if the env var wasn't specified. Providing a default effectively makes the env var optional.
*/
default?: T
default?: string
/**
* A fallback value to use only when NODE_ENV is not 'production'.
* This is handy for env vars that are required for production environments, but optional for development and testing.
*/
devDefault?: T
devDefault?: string
/**
* A string that describes the env var.
*/
Expand All @@ -26,7 +26,7 @@ export interface Spec<T> {
docs?: string
}

export interface ValidatorSpec<T> extends Spec<T> {
export interface ValidatorSpec<T> extends Spec {
_parse: (input: string) => T
}

Expand Down
51 changes: 24 additions & 27 deletions src/validators.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Spec, ValidatorSpec } from './types'
import { EnvError } from './errors'
import { URL } from 'url'

// Simplified adaptation of https://github.com/validatorjs/validator.js/blob/master/src/lib/isFQDN.js
const isFQDN = (input: string) => {
Expand Down Expand Up @@ -28,23 +29,21 @@ const isIP = (input: string) => {
const EMAIL_REGEX = /^[^@\s]+@[^@\s]+\.[^@\s]+$/ // intentionally non-exhaustive

export const makeValidator = <T>(parseFn: (input: string) => T) => {
return function (spec?: Spec<T>): ValidatorSpec<T> {
return function (spec?: Spec): ValidatorSpec<T> {
return { ...spec, _parse: parseFn }
}
}

// The reason for the function wrapper is to enable the <T extends boolean = boolean> type parameter
// that enables better type inference. For more context, check out the following PR:
// https://github.com/af/envalid/pull/118
export function bool<T extends boolean = boolean>(spec?: Spec<T>) {
return makeValidator((input: string | boolean) => {
export function bool(spec?: Spec) {
return makeValidator<boolean>((input: string): boolean => {
switch (input) {
case true:
case 'true':
case 't':
case '1':
return true
case false:
case 'false':
case 'f':
case '0':
Expand All @@ -55,39 +54,39 @@ export function bool<T extends boolean = boolean>(spec?: Spec<T>) {
})(spec)
}

export function num<T extends number = number>(spec?: Spec<T>) {
return makeValidator((input: string) => {
export function num(spec?: Spec) {
return makeValidator<number>((input: string): number => {
const coerced = parseFloat(input)
if (Number.isNaN(coerced)) throw new EnvError(`Invalid number input: "${input}"`)
return coerced
})(spec)
}

export function str<T extends string = string>(spec?: Spec<T>) {
return makeValidator((input: string) => {
if (typeof input === 'string') return input
export function str(spec?: Spec) {
return makeValidator<string>((input: string): string => {
if (input.trim() !== '') return input
throw new EnvError(`Not a string: "${input}"`)
})(spec)
}

export function email<T extends string = string>(spec?: Spec<T>) {
return makeValidator((x: string) => {
if (EMAIL_REGEX.test(x)) return x
throw new EnvError(`Invalid email address: "${x}"`)
export function email(spec?: Spec) {
return makeValidator<string>((input: string): string => {
if (EMAIL_REGEX.test(input)) return input
throw new EnvError(`Invalid email address: "${input}"`)
})(spec)
}

export function host<T extends string = string>(spec?: Spec<T>) {
return makeValidator((input: string) => {
export function host(spec?: Spec) {
return makeValidator<string>((input: string): string => {
if (!isFQDN(input) && !isIP(input)) {
throw new EnvError(`Invalid host (domain or ip): "${input}"`)
}
return input
})(spec)
}

export function port<T extends number = number>(spec?: Spec<T>) {
return makeValidator((input: string) => {
export function port(spec?: Spec) {
return makeValidator<number>((input: string): number => {
const coerced = +input
if (
Number.isNaN(coerced) ||
Expand All @@ -102,12 +101,10 @@ export function port<T extends number = number>(spec?: Spec<T>) {
})(spec)
}

export function url<T extends string = string>(spec?: Spec<T>) {
return makeValidator((x: string) => {
export function url(spec?: Spec) {
return makeValidator<URL>((x: string): URL => {
try {
// @ts-expect-error TS doesn't acknowledge this API by default yet
new URL(x)
return x
return new URL(x)
} catch (e) {
throw new EnvError(`Invalid url: "${x}"`)
}
Expand All @@ -120,12 +117,12 @@ export function url<T extends string = string>(spec?: Spec<T>) {
// cleanEnv({
// MY_VAR: json<{ foo: number }>({ default: { foo: 123 } }),
// })
export function json<T = any>(spec?: Spec<T>) {
return makeValidator<T>((x: string) => {
export function json(spec?: Spec) {
return makeValidator<unknown>((input: string): unknown => {
try {
return JSON.parse(x)
return JSON.parse(input)
} catch (e) {
throw new EnvError(`Invalid json: "${x}"`)
throw new EnvError(`Invalid json: "${input}"`)
}
})(spec)
}
2 changes: 1 addition & 1 deletion tests/basics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ test('falsy devDefault', () => {

test('devDefault and default together', () => {
const spec = {
FOO: num({ devDefault: 3000, default: 80 }),
FOO: num({ devDefault: '3000', default: '80' }),
}

const env = cleanEnv({ NODE_ENV: 'test' }, spec)
Expand Down
2 changes: 1 addition & 1 deletion tests/validators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ test('bool() works with various formats', () => {
const f = cleanEnv({ FOO: 'f' }, { FOO: bool() })
expect(f).toEqual({ FOO: false })

const defaultF = cleanEnv({}, { FOO: bool({ default: false }) })
const defaultF = cleanEnv({}, { FOO: bool({ default: 'false' }) })
expect(defaultF).toEqual({ FOO: false })
})

Expand Down
Loading