znv
Advanced tools
Comparing version 0.4.0 to 0.5.0-rc.0
@@ -5,1 +5,7 @@ export { z } from "zod"; | ||
export * from "./extra-schemas.js"; | ||
import { type ParseEnv } from "./parse-env.js"; | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment. | ||
*/ | ||
export declare const parseEnv: ParseEnv; |
@@ -17,3 +17,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.z = void 0; | ||
exports.parseEnv = exports.z = void 0; | ||
var zod_1 = require("zod"); | ||
@@ -24,2 +24,18 @@ Object.defineProperty(exports, "z", { enumerable: true, get: function () { return zod_1.z; } }); | ||
__exportStar(require("./extra-schemas.js"), exports); | ||
const parse_env_js_1 = require("./parse-env.js"); | ||
const tty_colors_js_1 = require("./util/tty-colors.js"); | ||
// This entrypoint provides a colorized reporter by default; this requires tty | ||
// detection, which in turn relies on Node's built-in `tty` module. | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment. | ||
*/ | ||
const parseEnv = (env, schemas, reporterOrTokenFormatters = { | ||
formatVarName: tty_colors_js_1.yellow, | ||
formatObjKey: tty_colors_js_1.green, | ||
formatReceivedValue: tty_colors_js_1.cyan, | ||
formatDefaultValue: tty_colors_js_1.cyan, | ||
formatHeader: tty_colors_js_1.red, | ||
}) => (0, parse_env_js_1.parseEnvImpl)(env, schemas, reporterOrTokenFormatters); | ||
exports.parseEnv = parseEnv; | ||
//# sourceMappingURL=index.js.map |
import * as z from "zod"; | ||
import type { DeepReadonlyObject } from "./util.js"; | ||
import { type TokenFormatters, type Reporter } from "./reporter.js"; | ||
import type { DeepReadonlyObject } from "./util/type-helpers.js"; | ||
export type SimpleSchema<TOut = any, TIn = any> = z.ZodType<TOut, z.ZodTypeDef, TIn>; | ||
@@ -48,7 +49,13 @@ export type DetailedSpec<TSchema extends SimpleSchema = SimpleSchema<unknown, unknown>> = TSchema extends SimpleSchema<any, infer TIn> ? { | ||
export declare const inferSchemas: <T extends Schemas>(schemas: T & RestrictSchemas<T>) => T & RestrictSchemas<T>; | ||
export type ParseEnv = <T extends Schemas>(env: Record<string, string | undefined>, schemas: T & RestrictSchemas<T>, reporterOrTokenFormatters?: Reporter | TokenFormatters) => DeepReadonlyObject<ParsedSchema<T>>; | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment.. | ||
* and returns the immutably-typed, parsed environment. | ||
* | ||
* This version of `parseEnv` is intended for internal use and requires a | ||
* reporter or token formatters to be passed in. The versions exported in | ||
* `index.js` and `compat.js` provide defaults for this third parameter, making | ||
* it optional. | ||
*/ | ||
export declare function parseEnv<T extends Schemas>(env: Record<string, string | undefined>, schemas: T & RestrictSchemas<T>): DeepReadonlyObject<ParsedSchema<T>>; | ||
export declare function parseEnvImpl<T extends Schemas>(env: Record<string, string | undefined>, schemas: T, reporterOrTokenFormatters: Reporter | TokenFormatters): DeepReadonlyObject<ParsedSchema<T>>; | ||
export {}; |
@@ -26,3 +26,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseEnv = exports.inferSchemas = exports.resolveDefaultValueForSpec = void 0; | ||
exports.parseEnvImpl = exports.inferSchemas = exports.resolveDefaultValueForSpec = void 0; | ||
const z = __importStar(require("zod")); | ||
@@ -55,5 +55,13 @@ const preprocessors_js_1 = require("./preprocessors.js"); | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment.. | ||
* and returns the immutably-typed, parsed environment. | ||
* | ||
* This version of `parseEnv` is intended for internal use and requires a | ||
* reporter or token formatters to be passed in. The versions exported in | ||
* `index.js` and `compat.js` provide defaults for this third parameter, making | ||
* it optional. | ||
*/ | ||
function parseEnv(env, schemas) { | ||
function parseEnvImpl(env, schemas, reporterOrTokenFormatters) { | ||
const reporter = typeof reporterOrTokenFormatters === "function" | ||
? reporterOrTokenFormatters | ||
: (0, reporter_js_1.makeDefaultReporter)(reporterOrTokenFormatters); | ||
const parsed = {}; | ||
@@ -112,7 +120,7 @@ const errors = []; | ||
if (errors.length > 0) { | ||
throw new Error((0, reporter_js_1.reportErrors)(errors, schemas)); | ||
throw new Error(reporter(errors, schemas)); | ||
} | ||
return parsed; | ||
} | ||
exports.parseEnv = parseEnv; | ||
exports.parseEnvImpl = parseEnvImpl; | ||
//# sourceMappingURL=parse-env.js.map |
@@ -28,3 +28,3 @@ "use strict"; | ||
const z = __importStar(require("zod")); | ||
const util_js_1 = require("./util.js"); | ||
const type_helpers_js_1 = require("./util/type-helpers.js"); | ||
const { ZodFirstPartyTypeKind: TypeName } = z; | ||
@@ -191,3 +191,3 @@ /** | ||
default: { | ||
(0, util_js_1.assertNever)(typeName); | ||
(0, type_helpers_js_1.assertNever)(typeName); | ||
} | ||
@@ -194,0 +194,0 @@ } |
import { ZodErrorMap } from "zod"; | ||
import { Schemas } from "./parse-env.js"; | ||
import type { Schemas } from "./parse-env.js"; | ||
export declare const errorMap: ZodErrorMap; | ||
export interface ErrorWithContext { | ||
/** The env var name. */ | ||
key: string; | ||
/** The actual value present in `process.env[key]`, or undefined. */ | ||
receivedValue: unknown; | ||
/** `ZodError` if Zod parsing failed, or `Error` if a preprocessor threw. */ | ||
error: unknown; | ||
/** If a default was provided, whether the default value was used. */ | ||
defaultUsed: boolean; | ||
/** If a default was provided, the given default value. */ | ||
defaultValue: unknown; | ||
} | ||
export declare function reportErrors(errors: ErrorWithContext[], schemas: Schemas): string; | ||
export interface TokenFormatters { | ||
/** Formatter for the env var name. */ | ||
formatVarName?: (key: string) => string; | ||
/** For parsed objects with errors, formatter for object keys. */ | ||
formatObjKey?: (key: string) => string; | ||
/** Formatter for the actual value we received for the env var. */ | ||
formatReceivedValue?: (val: unknown) => string; | ||
/** Formatter for the default value provided for the schema. */ | ||
formatDefaultValue?: (val: unknown) => string; | ||
/** Formatter for the error summary header. */ | ||
formatHeader?: (header: string) => string; | ||
} | ||
export type Reporter = (errors: ErrorWithContext[], schemas: Schemas) => string; | ||
export declare function makeDefaultReporter(formatters: TokenFormatters): Reporter; | ||
export declare function reportErrors(errors: ErrorWithContext[], schemas: Schemas, { formatVarName, formatObjKey, formatReceivedValue, formatDefaultValue, formatHeader, }?: TokenFormatters): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.reportErrors = exports.errorMap = void 0; | ||
exports.reportErrors = exports.makeDefaultReporter = exports.errorMap = void 0; | ||
const zod_1 = require("zod"); | ||
const colorette_1 = require("colorette"); | ||
// Even though we also have our own formatter, we pass a custom error map to | ||
@@ -10,3 +9,3 @@ // Zod's `.parse()` for two reasons: | ||
// error map that might override our formatting | ||
// - to return slightly friendly error messages in some common scenarios. | ||
// - to return slightly friendlier error messages in some common scenarios. | ||
const errorMap = (issue, ctx) => { | ||
@@ -21,5 +20,15 @@ if (issue.code === zod_1.ZodIssueCode.invalid_type && | ||
const indent = (str, amt) => `${" ".repeat(amt)}${str}`; | ||
function reportErrors(errors, schemas) { | ||
function makeDefaultReporter(formatters) { | ||
const reporter = (errors, schemas) => reportErrors(errors, schemas, formatters); | ||
return reporter; | ||
} | ||
exports.makeDefaultReporter = makeDefaultReporter; | ||
function reportErrors(errors, schemas, { formatVarName = String, formatObjKey = String, formatReceivedValue = String, formatDefaultValue = String, formatHeader = String, } = {}) { | ||
const formattedErrors = errors.map(({ key, receivedValue, error, defaultUsed, defaultValue }) => { | ||
const message = [`[${(0, colorette_1.yellow)(key)}]:`]; | ||
let title = `[${formatVarName(key)}]:`; | ||
const desc = schemas[key]?.description; | ||
if (desc) { | ||
title += ` ${desc}`; | ||
} | ||
const message = [title]; | ||
if (error instanceof zod_1.ZodError) { | ||
@@ -33,3 +42,3 @@ const { formErrors, fieldErrors } = error.flatten(); | ||
for (const [objKey, keyErrors] of fieldErrorEntries) { | ||
message.push(indent(`[${(0, colorette_1.green)(objKey)}]:`, 4)); | ||
message.push(indent(`[${formatObjKey(objKey)}]:`, 4)); | ||
for (const fe of keyErrors) | ||
@@ -48,20 +57,15 @@ message.push(indent(fe, 6)); | ||
} | ||
message.push(indent(`(received ${(0, colorette_1.cyan)(receivedValue === undefined | ||
message.push(indent(`(received ${formatReceivedValue(receivedValue === undefined | ||
? "undefined" | ||
: JSON.stringify(receivedValue))})`, 2)); | ||
if (defaultUsed) { | ||
message.push(indent(`(used default of ${(0, colorette_1.cyan)(defaultValue === undefined | ||
message.push(indent(`(used default of ${formatDefaultValue(defaultValue === undefined | ||
? "undefined" | ||
: JSON.stringify(defaultValue))})`, 2)); | ||
} | ||
const desc = schemas[key]?.description; | ||
if (desc) { | ||
message.push(""); | ||
message.push(`Description of [${(0, colorette_1.yellow)(key)}]: ${schemas[key].description}`); | ||
} | ||
return message.map((l) => indent(l, 2)).join("\n"); | ||
}); | ||
return `${(0, colorette_1.red)("Errors found while parsing environment:")}\n${formattedErrors.join("\n\n")}\n`; | ||
return `${formatHeader("Errors found while parsing environment:")}\n${formattedErrors.join("\n\n")}\n`; | ||
} | ||
exports.reportErrors = reportErrors; | ||
//# sourceMappingURL=reporter.js.map |
@@ -5,1 +5,7 @@ export { z } from "zod"; | ||
export * from "./extra-schemas.js"; | ||
import { type ParseEnv } from "./parse-env.js"; | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment. | ||
*/ | ||
export declare const parseEnv: ParseEnv; |
@@ -5,2 +5,17 @@ export { z } from "zod"; | ||
export * from "./extra-schemas.js"; | ||
import { parseEnvImpl } from "./parse-env.js"; | ||
import { cyan, green, red, yellow } from "./util/tty-colors.js"; | ||
// This entrypoint provides a colorized reporter by default; this requires tty | ||
// detection, which in turn relies on Node's built-in `tty` module. | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment. | ||
*/ | ||
export const parseEnv = (env, schemas, reporterOrTokenFormatters = { | ||
formatVarName: yellow, | ||
formatObjKey: green, | ||
formatReceivedValue: cyan, | ||
formatDefaultValue: cyan, | ||
formatHeader: red, | ||
}) => parseEnvImpl(env, schemas, reporterOrTokenFormatters); | ||
//# sourceMappingURL=index.js.map |
import * as z from "zod"; | ||
import type { DeepReadonlyObject } from "./util.js"; | ||
import { type TokenFormatters, type Reporter } from "./reporter.js"; | ||
import type { DeepReadonlyObject } from "./util/type-helpers.js"; | ||
export type SimpleSchema<TOut = any, TIn = any> = z.ZodType<TOut, z.ZodTypeDef, TIn>; | ||
@@ -48,7 +49,13 @@ export type DetailedSpec<TSchema extends SimpleSchema = SimpleSchema<unknown, unknown>> = TSchema extends SimpleSchema<any, infer TIn> ? { | ||
export declare const inferSchemas: <T extends Schemas>(schemas: T & RestrictSchemas<T>) => T & RestrictSchemas<T>; | ||
export type ParseEnv = <T extends Schemas>(env: Record<string, string | undefined>, schemas: T & RestrictSchemas<T>, reporterOrTokenFormatters?: Reporter | TokenFormatters) => DeepReadonlyObject<ParsedSchema<T>>; | ||
/** | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment.. | ||
* and returns the immutably-typed, parsed environment. | ||
* | ||
* This version of `parseEnv` is intended for internal use and requires a | ||
* reporter or token formatters to be passed in. The versions exported in | ||
* `index.js` and `compat.js` provide defaults for this third parameter, making | ||
* it optional. | ||
*/ | ||
export declare function parseEnv<T extends Schemas>(env: Record<string, string | undefined>, schemas: T & RestrictSchemas<T>): DeepReadonlyObject<ParsedSchema<T>>; | ||
export declare function parseEnvImpl<T extends Schemas>(env: Record<string, string | undefined>, schemas: T, reporterOrTokenFormatters: Reporter | TokenFormatters): DeepReadonlyObject<ParsedSchema<T>>; | ||
export {}; |
import * as z from "zod"; | ||
import { getSchemaWithPreprocessor } from "./preprocessors.js"; | ||
import { reportErrors, errorMap } from "./reporter.js"; | ||
import { makeDefaultReporter, errorMap, } from "./reporter.js"; | ||
/** | ||
@@ -26,5 +26,13 @@ * Since there might be a provided default value of `null` or `undefined`, we | ||
* Parses the passed environment object using the provided map of Zod schemas | ||
* and returns the immutably-typed, parsed environment.. | ||
* and returns the immutably-typed, parsed environment. | ||
* | ||
* This version of `parseEnv` is intended for internal use and requires a | ||
* reporter or token formatters to be passed in. The versions exported in | ||
* `index.js` and `compat.js` provide defaults for this third parameter, making | ||
* it optional. | ||
*/ | ||
export function parseEnv(env, schemas) { | ||
export function parseEnvImpl(env, schemas, reporterOrTokenFormatters) { | ||
const reporter = typeof reporterOrTokenFormatters === "function" | ||
? reporterOrTokenFormatters | ||
: makeDefaultReporter(reporterOrTokenFormatters); | ||
const parsed = {}; | ||
@@ -83,3 +91,3 @@ const errors = []; | ||
if (errors.length > 0) { | ||
throw new Error(reportErrors(errors, schemas)); | ||
throw new Error(reporter(errors, schemas)); | ||
} | ||
@@ -86,0 +94,0 @@ return parsed; |
import * as z from "zod"; | ||
import { assertNever } from "./util.js"; | ||
import { assertNever } from "./util/type-helpers.js"; | ||
const { ZodFirstPartyTypeKind: TypeName } = z; | ||
@@ -4,0 +4,0 @@ /** |
import { ZodErrorMap } from "zod"; | ||
import { Schemas } from "./parse-env.js"; | ||
import type { Schemas } from "./parse-env.js"; | ||
export declare const errorMap: ZodErrorMap; | ||
export interface ErrorWithContext { | ||
/** The env var name. */ | ||
key: string; | ||
/** The actual value present in `process.env[key]`, or undefined. */ | ||
receivedValue: unknown; | ||
/** `ZodError` if Zod parsing failed, or `Error` if a preprocessor threw. */ | ||
error: unknown; | ||
/** If a default was provided, whether the default value was used. */ | ||
defaultUsed: boolean; | ||
/** If a default was provided, the given default value. */ | ||
defaultValue: unknown; | ||
} | ||
export declare function reportErrors(errors: ErrorWithContext[], schemas: Schemas): string; | ||
export interface TokenFormatters { | ||
/** Formatter for the env var name. */ | ||
formatVarName?: (key: string) => string; | ||
/** For parsed objects with errors, formatter for object keys. */ | ||
formatObjKey?: (key: string) => string; | ||
/** Formatter for the actual value we received for the env var. */ | ||
formatReceivedValue?: (val: unknown) => string; | ||
/** Formatter for the default value provided for the schema. */ | ||
formatDefaultValue?: (val: unknown) => string; | ||
/** Formatter for the error summary header. */ | ||
formatHeader?: (header: string) => string; | ||
} | ||
export type Reporter = (errors: ErrorWithContext[], schemas: Schemas) => string; | ||
export declare function makeDefaultReporter(formatters: TokenFormatters): Reporter; | ||
export declare function reportErrors(errors: ErrorWithContext[], schemas: Schemas, { formatVarName, formatObjKey, formatReceivedValue, formatDefaultValue, formatHeader, }?: TokenFormatters): string; |
import { ZodError, ZodIssueCode } from "zod"; | ||
import { yellow, red, cyan, green } from "colorette"; | ||
// Even though we also have our own formatter, we pass a custom error map to | ||
@@ -7,3 +6,3 @@ // Zod's `.parse()` for two reasons: | ||
// error map that might override our formatting | ||
// - to return slightly friendly error messages in some common scenarios. | ||
// - to return slightly friendlier error messages in some common scenarios. | ||
export const errorMap = (issue, ctx) => { | ||
@@ -17,5 +16,14 @@ if (issue.code === ZodIssueCode.invalid_type && | ||
const indent = (str, amt) => `${" ".repeat(amt)}${str}`; | ||
export function reportErrors(errors, schemas) { | ||
export function makeDefaultReporter(formatters) { | ||
const reporter = (errors, schemas) => reportErrors(errors, schemas, formatters); | ||
return reporter; | ||
} | ||
export function reportErrors(errors, schemas, { formatVarName = String, formatObjKey = String, formatReceivedValue = String, formatDefaultValue = String, formatHeader = String, } = {}) { | ||
const formattedErrors = errors.map(({ key, receivedValue, error, defaultUsed, defaultValue }) => { | ||
const message = [`[${yellow(key)}]:`]; | ||
let title = `[${formatVarName(key)}]:`; | ||
const desc = schemas[key]?.description; | ||
if (desc) { | ||
title += ` ${desc}`; | ||
} | ||
const message = [title]; | ||
if (error instanceof ZodError) { | ||
@@ -29,3 +37,3 @@ const { formErrors, fieldErrors } = error.flatten(); | ||
for (const [objKey, keyErrors] of fieldErrorEntries) { | ||
message.push(indent(`[${green(objKey)}]:`, 4)); | ||
message.push(indent(`[${formatObjKey(objKey)}]:`, 4)); | ||
for (const fe of keyErrors) | ||
@@ -44,19 +52,14 @@ message.push(indent(fe, 6)); | ||
} | ||
message.push(indent(`(received ${cyan(receivedValue === undefined | ||
message.push(indent(`(received ${formatReceivedValue(receivedValue === undefined | ||
? "undefined" | ||
: JSON.stringify(receivedValue))})`, 2)); | ||
if (defaultUsed) { | ||
message.push(indent(`(used default of ${cyan(defaultValue === undefined | ||
message.push(indent(`(used default of ${formatDefaultValue(defaultValue === undefined | ||
? "undefined" | ||
: JSON.stringify(defaultValue))})`, 2)); | ||
} | ||
const desc = schemas[key]?.description; | ||
if (desc) { | ||
message.push(""); | ||
message.push(`Description of [${yellow(key)}]: ${schemas[key].description}`); | ||
} | ||
return message.map((l) => indent(l, 2)).join("\n"); | ||
}); | ||
return `${red("Errors found while parsing environment:")}\n${formattedErrors.join("\n\n")}\n`; | ||
return `${formatHeader("Errors found while parsing environment:")}\n${formattedErrors.join("\n\n")}\n`; | ||
} | ||
//# sourceMappingURL=reporter.js.map |
{ | ||
"name": "znv", | ||
"version": "0.4.0", | ||
"version": "0.5.0-rc.0", | ||
"description": "Parse your environment with Zod schemas", | ||
"type": "module", | ||
"license": "MIT", | ||
"keywords": [ | ||
@@ -12,5 +12,2 @@ "env", | ||
], | ||
"main": "dist-cjs/index.js", | ||
"types": "dist/index.d.ts", | ||
"module": "dist/index.js", | ||
"author": "s <https://github.com/lostfictions>", | ||
@@ -25,2 +22,6 @@ "homepage": "https://github.com/lostfictions/znv", | ||
}, | ||
"type": "module", | ||
"main": "dist-cjs/index.js", | ||
"types": "dist/index.d.ts", | ||
"module": "dist/index.js", | ||
"files": [ | ||
@@ -40,5 +41,14 @@ "dist/", | ||
} | ||
}, | ||
"./compat": { | ||
"import": { | ||
"types": "./dist/compat.d.ts", | ||
"default": "./dist/compat.js" | ||
}, | ||
"require": { | ||
"types": "./dist-cjs/compat.d.ts", | ||
"default": "./dist-cjs/compat.js" | ||
} | ||
} | ||
}, | ||
"license": "MIT", | ||
"scripts": { | ||
@@ -59,5 +69,2 @@ "build": "run-s -l build:*", | ||
}, | ||
"dependencies": { | ||
"colorette": "^2.0.19" | ||
}, | ||
"peerDependencies": { | ||
@@ -67,11 +74,11 @@ "zod": "^3.13.2" | ||
"devDependencies": { | ||
"@types/jest": "^29.5.4", | ||
"@types/node": "^16.18.24", | ||
"eslint": "^8.48.0", | ||
"eslint-config-lostfictions": "^6.0.0", | ||
"jest": "^29.6.4", | ||
"@types/jest": "^29.5.11", | ||
"@types/node": "^18.19.3", | ||
"eslint": "^8.55.0", | ||
"eslint-config-lostfictions": "^6.1.0", | ||
"jest": "^29.7.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^3.0.3", | ||
"prettier": "^3.1.1", | ||
"ts-jest": "^29.1.1", | ||
"ts-node": "^10.9.1", | ||
"ts-node": "^10.9.2", | ||
"typescript": "^4.9.5", | ||
@@ -78,0 +85,0 @@ "zod": "~3.13.2" |
113
README.md
@@ -21,2 +21,8 @@ # znv | ||
## Features | ||
- No dependencies | ||
- Fully type-safe | ||
- Compatible with serverless environments (import `znv/compat` instead of `znv`) | ||
## Status | ||
@@ -35,3 +41,3 @@ | ||
- [Usage](#usage) | ||
- [`parseEnv`](#parseenvenvironment-schemas) | ||
- [`parseEnv`](#parseenvenvironment-schemas-reporterOrFormatters) | ||
- [Extra schemas](#extra-schemas) | ||
@@ -48,2 +54,4 @@ - [Coercion rules](#coercion-rules) | ||
# or | ||
pnpm add znv zod | ||
# or | ||
yarn add znv zod | ||
@@ -180,3 +188,3 @@ ``` | ||
znv is a small module that works hand-in-hand with Zod. Since env vars, when | ||
defined, are always strings, Zod schemas like `z.number()` will fail to parse | ||
defined, are _always strings_, Zod schemas like `z.number()` will fail to parse | ||
them out-of-the-box. Zod allows you to use a [`preprocess` | ||
@@ -193,2 +201,9 @@ schema](https://github.com/colinhacks/zod#preprocess) to handle coercions, but | ||
> Since `v3.20`, Zod provides | ||
> [`z.coerce`](https://github.com/colinhacks/zod#coercion-for-primitives) for | ||
> primitive coercion, but this is often too naive to be useful. For example, | ||
> `z.coerce.boolean()` will parse "false" into `true`, since the string "false" | ||
> is _truthy_ in JavaScript. znv will coerce "false" into `false`, which is | ||
> probably what you expect. | ||
znv also makes it easy to define defaults for env vars based on your | ||
@@ -201,3 +216,3 @@ environment. Zod allows you to add a default value for a schema, but making a | ||
### `parseEnv(environment, schemas)` | ||
### `parseEnv(environment, schemas, reporterOrFormatters?)` | ||
@@ -211,2 +226,9 @@ Parse the given `environment` using the given `schemas`. Returns a read-only | ||
Optionally, you can pass a custom error reporter as the third parameter to | ||
`parseEnv` to customize how errors are displayed. The reporter is a function | ||
that receives error details and returns a `string`. Alternately, you can pass an | ||
object of _token formatters_ as the third parameter to `parseEnv`; this can be | ||
useful if you want to retain the default error reporting format but want to | ||
customize some aspects of it (for example, by redacting secrets). | ||
#### `environment: Record<string, string | undefined>` | ||
@@ -311,2 +333,62 @@ | ||
#### `reporterOrFormatters?: Reporter | TokenFormatters` | ||
An optional error reporter or object of error token formatters, for customizing | ||
the displayed output when a validation error occurs. | ||
- `Reporter: (errors: ErrorWithContext[], schemas: Schemas) => string` | ||
A reporter is a function that takes a list of errors and the schemas you | ||
passed to `parseEnv` and returns a `string`. Each error has the following | ||
format: | ||
```ts | ||
{ | ||
/** The env var name. */ | ||
key: string; | ||
/** The actual value present in `process.env[key]`, or undefined. */ | ||
receivedValue: unknown; | ||
/** `ZodError` if Zod parsing failed, or `Error` if a preprocessor threw. */ | ||
error: unknown; | ||
/** If a default was provided, whether the default value was used. */ | ||
defaultUsed: boolean; | ||
/** If a default was provided, the given default value. */ | ||
defaultValue: unknown; | ||
} | ||
``` | ||
- `TokenFormatters` | ||
An object with the following structure: | ||
```ts | ||
{ | ||
/** Formatter for the env var name. */ | ||
formatVarName?: (key: string) => string; | ||
/** For parsed objects with errors, formatter for object keys. */ | ||
formatObjKey?: (key: string) => string; | ||
/** Formatter for the actual value we received for the env var. */ | ||
formatReceivedValue?: (val: unknown) => string; | ||
/** Formatter for the default value provided for the schema. */ | ||
formatDefaultValue?: (val: unknown) => string; | ||
/** Formatter for the error summary header. */ | ||
formatHeader?: (header: string) => string; | ||
} | ||
``` | ||
For example, if you want to redact value names, you can invoke `parseEnv` like | ||
this: | ||
```ts | ||
export const { SOME_VAL } = parseEnv( | ||
process.env, | ||
{ SOME_VAL: z.number().nonnegative() }, | ||
{ formatReceivedValue: () => "<redacted>" }, | ||
); | ||
``` | ||
### Extra schemas | ||
@@ -374,7 +456,7 @@ | ||
value. This has a number of pitfalls, since the `Date()` constructor is | ||
excessively forgiving. The value is passed in as a string, which means trying | ||
to pass a Unix epoch will yield unexpected results. (Epochs need to be passed | ||
in as `number`: `new Date()` with an epoch as a string will either give you | ||
`invalid date` or a completely nonsensical date.) _You should only pass in ISO | ||
8601 date strings_, such as those returned by | ||
excessively forgiving. The value is passed in as a string, which means | ||
**trying to pass a Unix epoch will yield unexpected results**. (Epochs need to | ||
be passed in as `number`: `new Date()` with an epoch as a string will either | ||
give you `invalid date` or a completely nonsensical date.) _You should only | ||
pass in ISO 8601 date strings_, such as those returned by | ||
[`Date.prototype.toISOString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). | ||
@@ -413,2 +495,17 @@ Improved validation for Date schemas could be added in a future version. | ||
### [Zod](https://github.com/colinhacks/zod) | ||
Hey, what's Zod doing here? Doesn't znv use Zod? | ||
If you just want to parse some values against a certain schema, **you might not | ||
need znv**. Just use Zod directly. | ||
znv is best-suited for _environment validation_: it automatically wraps your Zod | ||
schemas in preprocessors that coerce env vars, which are always strings, into | ||
the appropriate type. This is different from Zod's built-in `z.coerce`, which is | ||
often too naive to be useful. For example, `z.coerce.boolean()` will parse | ||
"false" into `true`, since the string "false" is _truthy_ in JavaScript. znv | ||
will coerce "false" into `false`, which is probably what you expect. Check the | ||
section on [coercion rules](#coercion-rules) for more information. | ||
## Complementary tooling | ||
@@ -415,0 +512,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
111132
1
52
1242
516
0
- Removedcolorette@^2.0.19
- Removedcolorette@2.0.20(transitive)