Skip to content

Commit

Permalink
More rigorous isNode check, infer env keys in ReporterOptions type
Browse files Browse the repository at this point in the history
  • Loading branch information
af committed Oct 18, 2020
1 parent 0d0e8f1 commit 9eb3486
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 18 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ positional arguments:
validated and cleaned. Envalid ships with default middleware, but you can
customize its behavior by supplying your own

By default, `cleanEnv()` will log an error message and exit if any required
env vars are missing or invalid.
By default, `cleanEnv()` will log an error message and exit (in Node) or throw (in browser) if any required
env vars are missing or invalid. You can override this behavior by writing your own reporter.

```js
const envalid = require('envalid')
Expand Down
17 changes: 6 additions & 11 deletions src/envalid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,19 @@ function formatSpecDescription<T>(spec: Spec<T>) {
* specified in the `validators` parameter will be accessible on the returned
* object.
* @param environment An object containing your env vars (eg. process.env).
* @param validators An object that specifies the format of required vars.
* @param specs An object that specifies the format of required vars.
* @param options An object that specifies options for cleanEnv.
*/
// export function cleanEnv<T>(
// environment: unknown,
// validators: { [K in keyof T]: ValidatorSpec<T[K]> },
// options: StrictCleanOptions,
// ): Readonly<T> & CleanEnv
function cleanEnv<T>(
env: unknown,
environment: unknown,
specs: { [K in keyof T]: ValidatorSpec<T[K]> },
options: CleanOptions = { middleware: defaultMiddlewares },
options: CleanOptions<T> = { middleware: defaultMiddlewares },
): Readonly<T> & CleanEnv {
let output: any = {}
let defaultNodeEnv = ''
const errors: any = {}
const varKeys = Object.keys(specs) as Array<keyof T>
const rawNodeEnv = (env as any).NODE_ENV
const rawNodeEnv = (environment as any).NODE_ENV

// FIXME: make this opt-in, as an exported util?
// If validation for NODE_ENV isn't specified, use the default validation:
Expand All @@ -83,7 +78,7 @@ function cleanEnv<T>(
const usingDevDefault = rawNodeEnv !== 'production' && spec.hasOwnProperty('devDefault')
const devDefault = usingDevDefault ? spec.devDefault : undefined
// @ts-ignore FIXME
const rawValue = env[k] ?? (devDefault === undefined ? spec.default : devDefault)
const rawValue = environment[k] ?? (devDefault === undefined ? spec.default : devDefault)

// Default values can be anything falsy (including an explicitly set undefined), without
// triggering validation errors:
Expand Down Expand Up @@ -131,7 +126,7 @@ function cleanEnv<T>(

// Apply middlewares to transform the validated env object
if (!options.middleware?.length) return output
return options.middleware.reduce((acc, mw) => mw(acc, env), output)
return options.middleware.reduce((acc, mw) => mw(acc, environment), output)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type ReporterInput = {
env: unknown
}

const isNode = typeof process === 'object'
const isNode = !!(typeof process === 'object' && process?.versions?.node)
const colorWith = (colorCode: string) => (str: string) =>
isNode ? `\x1b[${colorCode}m${str}\x1b[0m` : str

Expand Down
8 changes: 4 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ export interface CleanEnv {
readonly isProd: boolean
}

interface ReporterOptions {
errors: { [key: string]: Error }
interface ReporterOptions<T> {
errors: Record<keyof T, Error>
env: unknown
}

export type Middleware<T = unknown, U = unknown> = (inputEnv: T, rawEnv: unknown) => U

export interface CleanOptions {
export interface CleanOptions<T> {
/**
* Pass in a function to override the default error handling and console output.
* See ./reporter.js for the default implementation.
*/
reporter?: ((opts: ReporterOptions) => void) | null
reporter?: ((opts: ReporterOptions<T>) => void) | null

/**
* Array of functions that can transform the cleaned environment object after validation
Expand Down
3 changes: 3 additions & 0 deletions src/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export const makeValidator = <T>(parseFn: (input: string) => T) => {
}
}

// 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) => {
switch (input) {
Expand Down

0 comments on commit 9eb3486

Please sign in to comment.