Skip to content

Commit 3e47321

Browse files
committed
feat: getTrimmedThrow and getValidatedThrow
1 parent ee2bcf0 commit 3e47321

3 files changed

Lines changed: 141 additions & 10 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ import {
8282
has,
8383
getDefault,
8484
getThrow,
85+
getTrimmedThrow,
86+
getValidatedThrow,
8587

8688
getIntegerThrowInvalid, // equivalent to get
8789
getIntegerDefault,
@@ -228,6 +230,8 @@ import {
228230
has,
229231
getDefault,
230232
getThrow,
233+
getTrimmedThrow,
234+
getValidatedThrow,
231235

232236
getIntegerThrowInvalid, // equivalent to get
233237
getIntegerDefault,
@@ -241,6 +245,8 @@ const {
241245
has,
242246
getDefault,
243247
getThrow,
248+
getTrimmedThrow,
249+
getValidatedThrow,
244250

245251
getIntegerThrowInvalid, // equivalent to get
246252
getIntegerDefault,
@@ -249,5 +255,18 @@ const {
249255

250256
console.log(`get('USER') >${get("USER")}`);
251257

258+
# Methods description
259+
260+
- `all()`: Returns a complete object containing all environment variables.
261+
- `get(key)`: Retrieves an environment variable if it exists, otherwise returns `undefined`.
262+
- `has(key)`: Checks if an environment variable exists.
263+
- `getDefault(key, defaultValue)`: Retrieves an environment variable or returns the specified `defaultValue` if not found.
264+
- `getThrow(key)`: Retrieves an environment variable or throws an error if it doesn't exist.
265+
- `getTrimmedThrow(key)`: Retrieves, trims, and throws an error if the variable is missing or empty after trimming.
266+
- `getValidatedThrow(key, validator)`: Retrieves and validates using a `RegExp` or a custom function. The validator function should return an error message `string` on failure, or `null`/`undefined` on success. It can also throw an error directly.
267+
- `getIntegerThrowInvalid(key)`: Retrieves and converts to an integer. Throws if it exists but is not a valid integer.
268+
- `getIntegerDefault(key, defaultValue)`: Retrieves as an integer, or returns `defaultValue` if not found or invalid.
269+
- `getIntegerThrow(key)`: Retrieves as an integer, throws if missing or invalid.
270+
252271
```
253272

src/source/env.ts

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,48 @@ if (isNode) {
2626

2727
/**
2828
* For testing purposes, it is possible to substitute the object process.env with a custom object.
29+
*
30+
* @param map - A record of environment variable names and their values.
2931
*/
3032
export function mockEnv(map: Record<string, string>): void {
3133
env = map;
3234
}
3335

3436
/**
35-
* Returns a complete object containing all environment variables
37+
* Returns a complete object containing all environment variables.
38+
*
39+
* @returns A record containing all environment variables.
3640
*/
3741
export function all(): Record<string, string> {
3842
return env;
3943
}
4044

4145
/**
42-
* Checks if an environment variable exists
46+
* Checks if an environment variable exists.
47+
*
48+
* @param key - The name of the environment variable.
49+
* @returns True if the variable exists as a string, false otherwise.
4350
*/
4451
export function has(key: string): boolean {
4552
return typeof env[key] === "string";
4653
}
4754

4855
/**
49-
* Retrieves an environment variable if it exists
56+
* Retrieves an environment variable if it exists.
57+
*
58+
* @param key - The name of the environment variable.
59+
* @returns The value of the environment variable if it exists, otherwise undefined.
5060
*/
5161
export function get(key: string): string | undefined {
5262
return env[key];
5363
}
5464

5565
/**
56-
* Retrieves an environment variable or returns the specified default value if not found
66+
* Retrieves an environment variable or returns the specified default value if not found.
67+
*
68+
* @param key - The name of the environment variable.
69+
* @param defaultValue - The value to return if the environment variable is not defined.
70+
* @returns The environment variable value or the provided default value.
5771
*/
5872
export function getDefault(key: string, defaultValue: string | number): string | number {
5973
if (has(key)) {
@@ -63,7 +77,12 @@ export function getDefault(key: string, defaultValue: string | number): string |
6377
}
6478

6579
/**
66-
* Retrieves an environment variable or throws an error if it doesn't exist
80+
* Retrieves an environment variable or throws an error if it doesn't exist.
81+
*
82+
* @param key - The name of the environment variable.
83+
* @param msg - An optional custom error message to throw.
84+
* @returns The value of the environment variable.
85+
* @throws Will throw an error if the environment variable is not defined.
6786
*/
6887
export function getThrow(key: string, msg?: string): string {
6988
if (has(key)) {
@@ -72,12 +91,59 @@ export function getThrow(key: string, msg?: string): string {
7291
throw th(msg || `env var ${key} is not defined`);
7392
}
7493

94+
/**
95+
* Retrieves an environment variable, trims it, and throws an error if it's missing or empty.
96+
*
97+
* @param key - The name of the environment variable.
98+
* @returns The trimmed value of the environment variable.
99+
* @throws Will throw if the variable is not defined or is an empty string after trimming.
100+
*/
101+
export function getTrimmedThrow(key: string): string {
102+
const value = getThrow(key).trim();
103+
104+
if (value === "") {
105+
throw th(`env var ${key} is defined but it is an empty string after trimming`);
106+
}
107+
108+
return value;
109+
}
110+
111+
/**
112+
* Retrieves an environment variable and validates it using a regex or a custom function.
113+
*
114+
* @param key - The name of the environment variable.
115+
* @param validator - A RegExp to test against or a function that returns an error message string (or throws) on failure.
116+
* @returns The original value of the environment variable if validation passes.
117+
* @throws Will throw if the variable is not defined, doesn't match the regex, or if the validator function returns a string or throws.
118+
*/
119+
export function getValidatedThrow(
120+
key: string,
121+
validator: RegExp | ((value: string) => string | null | undefined | void),
122+
): string {
123+
const value = getThrow(key);
124+
125+
if (validator instanceof RegExp) {
126+
if (!validator.test(value)) {
127+
throw th(`env var ${key} value >${value}< does not match regex >${validator}<`);
128+
}
129+
} else if (typeof validator === "function") {
130+
const result = validator(value);
131+
if (typeof result === "string") {
132+
throw th(result);
133+
}
134+
}
135+
136+
return value;
137+
}
138+
75139
const intTest = /^-?\d+$/;
76140

77141
/**
78-
* Retrieves an environment variable and converts it to an integer
79-
* Returns undefined if the variable doesn't exist
80-
* Throws an error if the variable exists but cannot be converted to a valid integer
142+
* Retrieves an environment variable and converts it to an integer.
143+
*
144+
* @param key - The name of the environment variable.
145+
* @returns The integer value if it exists and is valid, otherwise undefined.
146+
* @throws Will throw an error if the variable exists but cannot be converted to a valid integer.
81147
*/
82148
export function getIntegerThrowInvalid(key: string): number | undefined {
83149
if (has(key)) {
@@ -103,7 +169,11 @@ export function getIntegerThrowInvalid(key: string): number | undefined {
103169
}
104170

105171
/**
106-
* If not defined or not able to cast to int, return defaultValue.
172+
* Retrieves an environment variable as an integer, or returns a default value if not found or invalid.
173+
*
174+
* @param key - The name of the environment variable.
175+
* @param defaultValue - The value to return if the environment variable is not defined or invalid.
176+
* @returns The integer value or the default value.
107177
*/
108178
export function getIntegerDefault(key: string, defaultValue: number): number {
109179
try {
@@ -121,7 +191,10 @@ export function getIntegerDefault(key: string, defaultValue: number): number {
121191

122192
/**
123193
* Retrieves an environment variable, converts it to an integer, and returns the value.
124-
* Throws an error if the variable is not defined or cannot be converted to a valid integer.
194+
*
195+
* @param key - The name of the environment variable.
196+
* @returns The integer value of the environment variable.
197+
* @throws Will throw an error if the variable is not defined or cannot be converted to a valid integer.
125198
*/
126199
export function getIntegerThrow(key: string): number {
127200
const val = getIntegerThrowInvalid(key);

tests/env.unit.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
getIntegerDefault,
99
getIntegerThrow,
1010
getThrow,
11+
getTrimmedThrow,
12+
getValidatedThrow,
1113
all,
1214
} from "../src/source/env.ts";
1315

@@ -110,3 +112,40 @@ it("all - returns all environment variables", async () => {
110112
expect(all()).toEqual(mockEnvironment);
111113
expect(all()).toBe(mockEnvironment); // Check that it returns the same object reference
112114
});
115+
116+
it("getTrimmedThrow", async () => {
117+
mockEnv({
118+
ABC: " DEF ",
119+
EMPTY: " ",
120+
});
121+
122+
expect(getTrimmedThrow("ABC")).toEqual("DEF");
123+
expect(() => getTrimmedThrow("EMPTY")).toThrowError(
124+
"env.js: env var EMPTY is defined but it is an empty string after trimming",
125+
);
126+
expect(() => getTrimmedThrow("GHI")).toThrowError("env.js: env var GHI is not defined");
127+
});
128+
129+
it("getValidatedThrow", async () => {
130+
mockEnv({
131+
ABC: "123",
132+
DEF: "abc",
133+
});
134+
135+
expect(getValidatedThrow("ABC", /^\d+$/)).toEqual("123");
136+
expect(() => getValidatedThrow("DEF", /^\d+$/)).toThrowError(
137+
"env.js: env var DEF value >abc< does not match regex >/^\\d+$/<",
138+
);
139+
140+
expect(getValidatedThrow("ABC", (v) => (v === "123" ? null : "must be 123"))).toEqual("123");
141+
expect(() => getValidatedThrow("DEF", (v) => (v === "123" ? null : "must be 123"))).toThrowError(
142+
"env.js: must be 123",
143+
);
144+
145+
expect(() =>
146+
getValidatedThrow("ABC", () => {
147+
throw new Error("custom error");
148+
}),
149+
).toThrowError("custom error");
150+
});
151+

0 commit comments

Comments
 (0)