@wcaservices/config 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +86 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +45 -0
- package/dist/index.d.mts +45 -0
- package/dist/index.mjs +86 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +2 -2
- package/src/environment/EnvironmentVariables.ts +0 -103
- package/src/environment/Errors.ts +0 -10
- package/src/environment/Types.ts +0 -50
- package/src/environment/defineEnvironmentVariables.test-d.ts +0 -162
- package/src/environment/defineEnvironmentVariables.test.ts +0 -50
- package/src/environment/defineEnvironmentVariables.ts +0 -14
- package/src/environment/index.ts +0 -1
- package/src/index.ts +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
let _wcaservices_util_lib = require("@wcaservices/util/lib");
|
|
2
|
+
|
|
3
|
+
//#region src/environment/Errors.ts
|
|
4
|
+
var EnvironmentVariableError = class extends Error {};
|
|
5
|
+
var RequiredEnvironmentVariableError = class extends EnvironmentVariableError {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
super(`Required environment variable "${config.name}" is missing. Make sure one is set before starting the process!`);
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/environment/EnvironmentVariables.ts
|
|
14
|
+
var EnvironmentVariables = class {
|
|
15
|
+
constructor(variables) {
|
|
16
|
+
this.variables = variables;
|
|
17
|
+
return new Proxy(this, {
|
|
18
|
+
get(target, prop, receiver) {
|
|
19
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
20
|
+
return target.getVariable(prop);
|
|
21
|
+
},
|
|
22
|
+
set(target, prop, value, receiver) {
|
|
23
|
+
return target.setVariable(prop, value);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
validate() {
|
|
28
|
+
this.validateRequiredVariables();
|
|
29
|
+
}
|
|
30
|
+
validateRequiredVariables() {
|
|
31
|
+
Object.entries(this.variables).forEach(([key, config]) => {
|
|
32
|
+
if (!config.required) return;
|
|
33
|
+
if (typeof this.getVariable(key) === "undefined") throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getVariable(key) {
|
|
37
|
+
const config = this.variables[key];
|
|
38
|
+
if (!config) throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
39
|
+
const originalValue = process.env[key] ?? config.default;
|
|
40
|
+
let value = originalValue;
|
|
41
|
+
const cast = config.type ?? "default";
|
|
42
|
+
if (config.required && typeof value === "undefined") throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
43
|
+
switch (cast) {
|
|
44
|
+
case "BOOLEAN":
|
|
45
|
+
value = (0, _wcaservices_util_lib.envFlag)(key);
|
|
46
|
+
break;
|
|
47
|
+
case "NUMBER":
|
|
48
|
+
value = Number(value);
|
|
49
|
+
if (Number.isNaN(value)) throw new EnvironmentVariableError(`Invalid number type for '${key}': ${originalValue}`);
|
|
50
|
+
break;
|
|
51
|
+
case "JSON":
|
|
52
|
+
JSON.parse(String(value));
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
if (config.transform) value = config.transform(value);
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
setVariable(key, value) {
|
|
59
|
+
const config = this.variables[key];
|
|
60
|
+
if (!config) throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
61
|
+
if (config.transform) throw new EnvironmentVariableError("Setting environment variables with transform functions is not yet supported.");
|
|
62
|
+
switch (config.type) {
|
|
63
|
+
case "BOOLEAN":
|
|
64
|
+
case "NUMBER":
|
|
65
|
+
case "default":
|
|
66
|
+
process.env[key] = String(value);
|
|
67
|
+
return true;
|
|
68
|
+
case "JSON":
|
|
69
|
+
process.env[key] = JSON.stringify(value);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
throw new EnvironmentVariableError(`Invalid type '${config.type}' for environment variable '${key}'`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/environment/defineEnvironmentVariables.ts
|
|
78
|
+
function defineEnvironmentVariables(variables) {
|
|
79
|
+
const instance = new EnvironmentVariables(variables);
|
|
80
|
+
instance.validate();
|
|
81
|
+
return instance;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
exports.defineEnvironmentVariables = defineEnvironmentVariables;
|
|
86
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/environment/Errors.ts","../src/environment/EnvironmentVariables.ts","../src/environment/defineEnvironmentVariables.ts"],"sourcesContent":["import type { EnvironmentVariableConfig } from './Types.ts';\n\nexport class EnvironmentVariableError extends Error {\n}\n\nexport class RequiredEnvironmentVariableError extends EnvironmentVariableError {\n constructor(public readonly config: EnvironmentVariableConfig & { name: string }) {\n super(`Required environment variable \"${config.name}\" is missing. Make sure one is set before starting the process!`);\n }\n}","import { envFlag } from '@wcaservices/util/lib';\nimport { EnvironmentVariableError, RequiredEnvironmentVariableError } from './Errors.ts';\nimport type { VariableDefinitionMap, VariableOutputType } from './Types.ts';\n\nexport class EnvironmentVariables<TVariables extends VariableDefinitionMap> {\n constructor(protected readonly variables: TVariables) {\n return new Proxy(this, {\n get(target, prop, receiver) {\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n return target.getVariable(prop as string);\n },\n set(target, prop, value, receiver) {\n return target.setVariable(prop as string, value);\n }\n })\n }\n \n public validate(): void {\n this.validateRequiredVariables();\n }\n \n protected validateRequiredVariables(): void {\n Object.entries(this.variables).forEach(([key, config]) => {\n if (!config.required) {\n return;\n }\n \n const value = this.getVariable(key);\n \n if (typeof value === 'undefined') {\n throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));\n }\n })\n }\n \n protected getVariable(key: string): unknown {\n const config = this.variables[key];\n \n if (!config) {\n throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);\n }\n \n const originalValue = process.env[key] ?? config.default;\n let value: unknown = originalValue;\n const cast = config.type ?? 'default';\n \n if (config.required && typeof value === 'undefined') {\n throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));\n }\n \n switch (cast) {\n case 'BOOLEAN':\n value = envFlag(key);\n break;\n case 'NUMBER':\n value = Number(value);\n if (Number.isNaN(value)) {\n throw new EnvironmentVariableError(`Invalid number type for '${key}': ${originalValue}`);\n }\n break;\n case 'JSON':\n JSON.parse(String(value));\n break;\n }\n \n if (config.transform) {\n value = config.transform(value);\n }\n \n return value;\n }\n \n protected setVariable(key: string, value: unknown): boolean {\n const config = this.variables[key];\n \n if (!config) {\n throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);\n }\n \n if (config.transform) {\n throw new EnvironmentVariableError('Setting environment variables with transform functions is not yet supported.');\n }\n \n switch (config.type) {\n case 'BOOLEAN':\n case 'NUMBER':\n case 'default':\n process.env[key] = String(value);\n return true;\n case 'JSON':\n process.env[key] = JSON.stringify(value);\n return true;\n }\n \n throw new EnvironmentVariableError(`Invalid type '${config.type}' for environment variable '${key}'`);\n }\n}\n\nexport type EnvironmentVariablesInstance<TVariables extends VariableDefinitionMap> = EnvironmentVariables<TVariables> & {\n [key in keyof TVariables]: VariableOutputType<TVariables[key]>;\n}","import { EnvironmentVariables, type EnvironmentVariablesInstance } from './EnvironmentVariables.ts';\nimport type { VariableDefinitionMap } from './Types.ts';\n\nexport function defineEnvironmentVariables<\n TVariables extends VariableDefinitionMap\n>(variables: TVariables): EnvironmentVariablesInstance<TVariables> {\n const instance = new EnvironmentVariables(variables);\n \n instance.validate();\n \n // @ts-expect-error Type mismatch between result and explicit return type\n return instance;\n}\n\n"],"mappings":";;;AAEA,IAAa,2BAAb,cAA8C,MAAM;AAGpD,IAAa,mCAAb,cAAsD,yBAAyB;CAC3E,YAAY,AAAgB,QAAsD;AAC9E,QAAM,kCAAkC,OAAO,KAAK,iEAAiE;EAD7F;;;;;;ACFhC,IAAa,uBAAb,MAA4E;CACxE,YAAY,AAAmB,WAAuB;EAAvB;AAC3B,SAAO,IAAI,MAAM,MAAM;GACnB,IAAI,QAAQ,MAAM,UAAU;AACxB,QAAI,QAAQ,OACR,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAE9C,WAAO,OAAO,YAAY,KAAe;;GAE7C,IAAI,QAAQ,MAAM,OAAO,UAAU;AAC/B,WAAO,OAAO,YAAY,MAAgB,MAAM;;GAEvD,CAAC;;CAGN,AAAO,WAAiB;AACpB,OAAK,2BAA2B;;CAGpC,AAAU,4BAAkC;AACxC,SAAO,QAAQ,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,YAAY;AACtD,OAAI,CAAC,OAAO,SACR;AAKJ,OAAI,OAFU,KAAK,YAAY,IAAI,KAEd,YACjB,OAAM,IAAI,iCAAiC,OAAO,OAAO,EAAE,MAAM,KAAK,EAAE,OAAO,CAAC;IAEtF;;CAGN,AAAU,YAAY,KAAsB;EACxC,MAAM,SAAS,KAAK,UAAU;AAE9B,MAAI,CAAC,OACD,OAAM,IAAI,yBAAyB,oDAAoD,IAAI,GAAG;EAGlG,MAAM,gBAAgB,QAAQ,IAAI,QAAQ,OAAO;EACjD,IAAI,QAAiB;EACrB,MAAM,OAAO,OAAO,QAAQ;AAE5B,MAAI,OAAO,YAAY,OAAO,UAAU,YACpC,OAAM,IAAI,iCAAiC,OAAO,OAAO,EAAE,MAAM,KAAK,EAAE,OAAO,CAAC;AAGpF,UAAQ,MAAR;GACI,KAAK;AACD,+CAAgB,IAAI;AACpB;GACJ,KAAK;AACD,YAAQ,OAAO,MAAM;AACrB,QAAI,OAAO,MAAM,MAAM,CACnB,OAAM,IAAI,yBAAyB,4BAA4B,IAAI,KAAK,gBAAgB;AAE5F;GACJ,KAAK;AACD,SAAK,MAAM,OAAO,MAAM,CAAC;AACzB;;AAGR,MAAI,OAAO,UACP,SAAQ,OAAO,UAAU,MAAM;AAGnC,SAAO;;CAGX,AAAU,YAAY,KAAa,OAAyB;EACxD,MAAM,SAAS,KAAK,UAAU;AAE9B,MAAI,CAAC,OACD,OAAM,IAAI,yBAAyB,oDAAoD,IAAI,GAAG;AAGlG,MAAI,OAAO,UACP,OAAM,IAAI,yBAAyB,+EAA+E;AAGtH,UAAQ,OAAO,MAAf;GACI,KAAK;GACL,KAAK;GACL,KAAK;AACD,YAAQ,IAAI,OAAO,OAAO,MAAM;AAChC,WAAO;GACX,KAAK;AACD,YAAQ,IAAI,OAAO,KAAK,UAAU,MAAM;AACxC,WAAO;;AAGf,QAAM,IAAI,yBAAyB,iBAAiB,OAAO,KAAK,8BAA8B,IAAI,GAAG;;;;;;AC7F7G,SAAgB,2BAEd,WAAiE;CAC/D,MAAM,WAAW,IAAI,qBAAqB,UAAU;AAEpD,UAAS,UAAU;AAGnB,QAAO"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/environment/Types.d.ts
|
|
2
|
+
interface EnvironmentVariableConfig<TRequired extends boolean = boolean, TTypeCast extends keyof VariableTypeCast = keyof VariableTypeCast, TTransform = unknown> {
|
|
3
|
+
required?: TRequired;
|
|
4
|
+
type?: TTypeCast;
|
|
5
|
+
default?: VariableTypeCast[TTypeCast];
|
|
6
|
+
transform?: TransformFn<any, TTransform>;
|
|
7
|
+
}
|
|
8
|
+
type VariableDefinitionMap = { [key in keyof NodeJS.ProcessEnv]: EnvironmentVariableConfig };
|
|
9
|
+
type VariableOutputType<TConfig extends EnvironmentVariableConfig, TTypeCast extends keyof VariableTypeCast = (TConfig['type'] extends keyof VariableTypeCast ? TConfig['type'] : 'default'), TType = VariableTypeCast[TTypeCast], TCastOutputType = (TConfig['required'] extends true ? TType : TType | undefined)> = TConfig['transform'] extends TransformFn<TCastOutputType, infer TTransformOutput> ? TTransformOutput : TCastOutputType;
|
|
10
|
+
type TransformFn<TInput, TOutput> = (value: TInput) => TOutput;
|
|
11
|
+
interface VariableTypeCast {
|
|
12
|
+
/**
|
|
13
|
+
* Default type for environment variables.
|
|
14
|
+
*/
|
|
15
|
+
default: string;
|
|
16
|
+
/**
|
|
17
|
+
* Boolean flag (1, 0, true, false, yes, no)
|
|
18
|
+
*/
|
|
19
|
+
BOOLEAN: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Cast inputs to number.
|
|
22
|
+
*/
|
|
23
|
+
NUMBER: number;
|
|
24
|
+
/**
|
|
25
|
+
* Parse input as JSON
|
|
26
|
+
*/
|
|
27
|
+
JSON: unknown;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/environment/EnvironmentVariables.d.ts
|
|
31
|
+
declare class EnvironmentVariables<TVariables extends VariableDefinitionMap> {
|
|
32
|
+
protected readonly variables: TVariables;
|
|
33
|
+
constructor(variables: TVariables);
|
|
34
|
+
validate(): void;
|
|
35
|
+
protected validateRequiredVariables(): void;
|
|
36
|
+
protected getVariable(key: string): unknown;
|
|
37
|
+
protected setVariable(key: string, value: unknown): boolean;
|
|
38
|
+
}
|
|
39
|
+
type EnvironmentVariablesInstance<TVariables extends VariableDefinitionMap> = EnvironmentVariables<TVariables> & { [key in keyof TVariables]: VariableOutputType<TVariables[key]> };
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/environment/defineEnvironmentVariables.d.ts
|
|
42
|
+
declare function defineEnvironmentVariables<TVariables extends VariableDefinitionMap>(variables: TVariables): EnvironmentVariablesInstance<TVariables>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { defineEnvironmentVariables };
|
|
45
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/environment/Types.d.ts
|
|
2
|
+
interface EnvironmentVariableConfig<TRequired extends boolean = boolean, TTypeCast extends keyof VariableTypeCast = keyof VariableTypeCast, TTransform = unknown> {
|
|
3
|
+
required?: TRequired;
|
|
4
|
+
type?: TTypeCast;
|
|
5
|
+
default?: VariableTypeCast[TTypeCast];
|
|
6
|
+
transform?: TransformFn<any, TTransform>;
|
|
7
|
+
}
|
|
8
|
+
type VariableDefinitionMap = { [key in keyof NodeJS.ProcessEnv]: EnvironmentVariableConfig };
|
|
9
|
+
type VariableOutputType<TConfig extends EnvironmentVariableConfig, TTypeCast extends keyof VariableTypeCast = (TConfig['type'] extends keyof VariableTypeCast ? TConfig['type'] : 'default'), TType = VariableTypeCast[TTypeCast], TCastOutputType = (TConfig['required'] extends true ? TType : TType | undefined)> = TConfig['transform'] extends TransformFn<TCastOutputType, infer TTransformOutput> ? TTransformOutput : TCastOutputType;
|
|
10
|
+
type TransformFn<TInput, TOutput> = (value: TInput) => TOutput;
|
|
11
|
+
interface VariableTypeCast {
|
|
12
|
+
/**
|
|
13
|
+
* Default type for environment variables.
|
|
14
|
+
*/
|
|
15
|
+
default: string;
|
|
16
|
+
/**
|
|
17
|
+
* Boolean flag (1, 0, true, false, yes, no)
|
|
18
|
+
*/
|
|
19
|
+
BOOLEAN: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Cast inputs to number.
|
|
22
|
+
*/
|
|
23
|
+
NUMBER: number;
|
|
24
|
+
/**
|
|
25
|
+
* Parse input as JSON
|
|
26
|
+
*/
|
|
27
|
+
JSON: unknown;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/environment/EnvironmentVariables.d.ts
|
|
31
|
+
declare class EnvironmentVariables<TVariables extends VariableDefinitionMap> {
|
|
32
|
+
protected readonly variables: TVariables;
|
|
33
|
+
constructor(variables: TVariables);
|
|
34
|
+
validate(): void;
|
|
35
|
+
protected validateRequiredVariables(): void;
|
|
36
|
+
protected getVariable(key: string): unknown;
|
|
37
|
+
protected setVariable(key: string, value: unknown): boolean;
|
|
38
|
+
}
|
|
39
|
+
type EnvironmentVariablesInstance<TVariables extends VariableDefinitionMap> = EnvironmentVariables<TVariables> & { [key in keyof TVariables]: VariableOutputType<TVariables[key]> };
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/environment/defineEnvironmentVariables.d.ts
|
|
42
|
+
declare function defineEnvironmentVariables<TVariables extends VariableDefinitionMap>(variables: TVariables): EnvironmentVariablesInstance<TVariables>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { defineEnvironmentVariables };
|
|
45
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { envFlag } from "@wcaservices/util/lib";
|
|
2
|
+
|
|
3
|
+
//#region src/environment/Errors.ts
|
|
4
|
+
var EnvironmentVariableError = class extends Error {};
|
|
5
|
+
var RequiredEnvironmentVariableError = class extends EnvironmentVariableError {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
super(`Required environment variable "${config.name}" is missing. Make sure one is set before starting the process!`);
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/environment/EnvironmentVariables.ts
|
|
14
|
+
var EnvironmentVariables = class {
|
|
15
|
+
constructor(variables) {
|
|
16
|
+
this.variables = variables;
|
|
17
|
+
return new Proxy(this, {
|
|
18
|
+
get(target, prop, receiver) {
|
|
19
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
20
|
+
return target.getVariable(prop);
|
|
21
|
+
},
|
|
22
|
+
set(target, prop, value, receiver) {
|
|
23
|
+
return target.setVariable(prop, value);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
validate() {
|
|
28
|
+
this.validateRequiredVariables();
|
|
29
|
+
}
|
|
30
|
+
validateRequiredVariables() {
|
|
31
|
+
Object.entries(this.variables).forEach(([key, config]) => {
|
|
32
|
+
if (!config.required) return;
|
|
33
|
+
if (typeof this.getVariable(key) === "undefined") throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getVariable(key) {
|
|
37
|
+
const config = this.variables[key];
|
|
38
|
+
if (!config) throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
39
|
+
const originalValue = process.env[key] ?? config.default;
|
|
40
|
+
let value = originalValue;
|
|
41
|
+
const cast = config.type ?? "default";
|
|
42
|
+
if (config.required && typeof value === "undefined") throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
43
|
+
switch (cast) {
|
|
44
|
+
case "BOOLEAN":
|
|
45
|
+
value = envFlag(key);
|
|
46
|
+
break;
|
|
47
|
+
case "NUMBER":
|
|
48
|
+
value = Number(value);
|
|
49
|
+
if (Number.isNaN(value)) throw new EnvironmentVariableError(`Invalid number type for '${key}': ${originalValue}`);
|
|
50
|
+
break;
|
|
51
|
+
case "JSON":
|
|
52
|
+
JSON.parse(String(value));
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
if (config.transform) value = config.transform(value);
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
setVariable(key, value) {
|
|
59
|
+
const config = this.variables[key];
|
|
60
|
+
if (!config) throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
61
|
+
if (config.transform) throw new EnvironmentVariableError("Setting environment variables with transform functions is not yet supported.");
|
|
62
|
+
switch (config.type) {
|
|
63
|
+
case "BOOLEAN":
|
|
64
|
+
case "NUMBER":
|
|
65
|
+
case "default":
|
|
66
|
+
process.env[key] = String(value);
|
|
67
|
+
return true;
|
|
68
|
+
case "JSON":
|
|
69
|
+
process.env[key] = JSON.stringify(value);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
throw new EnvironmentVariableError(`Invalid type '${config.type}' for environment variable '${key}'`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/environment/defineEnvironmentVariables.ts
|
|
78
|
+
function defineEnvironmentVariables(variables) {
|
|
79
|
+
const instance = new EnvironmentVariables(variables);
|
|
80
|
+
instance.validate();
|
|
81
|
+
return instance;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
export { defineEnvironmentVariables };
|
|
86
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/environment/Errors.ts","../src/environment/EnvironmentVariables.ts","../src/environment/defineEnvironmentVariables.ts"],"sourcesContent":["import type { EnvironmentVariableConfig } from './Types.ts';\n\nexport class EnvironmentVariableError extends Error {\n}\n\nexport class RequiredEnvironmentVariableError extends EnvironmentVariableError {\n constructor(public readonly config: EnvironmentVariableConfig & { name: string }) {\n super(`Required environment variable \"${config.name}\" is missing. Make sure one is set before starting the process!`);\n }\n}","import { envFlag } from '@wcaservices/util/lib';\nimport { EnvironmentVariableError, RequiredEnvironmentVariableError } from './Errors.ts';\nimport type { VariableDefinitionMap, VariableOutputType } from './Types.ts';\n\nexport class EnvironmentVariables<TVariables extends VariableDefinitionMap> {\n constructor(protected readonly variables: TVariables) {\n return new Proxy(this, {\n get(target, prop, receiver) {\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n return target.getVariable(prop as string);\n },\n set(target, prop, value, receiver) {\n return target.setVariable(prop as string, value);\n }\n })\n }\n \n public validate(): void {\n this.validateRequiredVariables();\n }\n \n protected validateRequiredVariables(): void {\n Object.entries(this.variables).forEach(([key, config]) => {\n if (!config.required) {\n return;\n }\n \n const value = this.getVariable(key);\n \n if (typeof value === 'undefined') {\n throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));\n }\n })\n }\n \n protected getVariable(key: string): unknown {\n const config = this.variables[key];\n \n if (!config) {\n throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);\n }\n \n const originalValue = process.env[key] ?? config.default;\n let value: unknown = originalValue;\n const cast = config.type ?? 'default';\n \n if (config.required && typeof value === 'undefined') {\n throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));\n }\n \n switch (cast) {\n case 'BOOLEAN':\n value = envFlag(key);\n break;\n case 'NUMBER':\n value = Number(value);\n if (Number.isNaN(value)) {\n throw new EnvironmentVariableError(`Invalid number type for '${key}': ${originalValue}`);\n }\n break;\n case 'JSON':\n JSON.parse(String(value));\n break;\n }\n \n if (config.transform) {\n value = config.transform(value);\n }\n \n return value;\n }\n \n protected setVariable(key: string, value: unknown): boolean {\n const config = this.variables[key];\n \n if (!config) {\n throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);\n }\n \n if (config.transform) {\n throw new EnvironmentVariableError('Setting environment variables with transform functions is not yet supported.');\n }\n \n switch (config.type) {\n case 'BOOLEAN':\n case 'NUMBER':\n case 'default':\n process.env[key] = String(value);\n return true;\n case 'JSON':\n process.env[key] = JSON.stringify(value);\n return true;\n }\n \n throw new EnvironmentVariableError(`Invalid type '${config.type}' for environment variable '${key}'`);\n }\n}\n\nexport type EnvironmentVariablesInstance<TVariables extends VariableDefinitionMap> = EnvironmentVariables<TVariables> & {\n [key in keyof TVariables]: VariableOutputType<TVariables[key]>;\n}","import { EnvironmentVariables, type EnvironmentVariablesInstance } from './EnvironmentVariables.ts';\nimport type { VariableDefinitionMap } from './Types.ts';\n\nexport function defineEnvironmentVariables<\n TVariables extends VariableDefinitionMap\n>(variables: TVariables): EnvironmentVariablesInstance<TVariables> {\n const instance = new EnvironmentVariables(variables);\n \n instance.validate();\n \n // @ts-expect-error Type mismatch between result and explicit return type\n return instance;\n}\n\n"],"mappings":";;;AAEA,IAAa,2BAAb,cAA8C,MAAM;AAGpD,IAAa,mCAAb,cAAsD,yBAAyB;CAC3E,YAAY,AAAgB,QAAsD;AAC9E,QAAM,kCAAkC,OAAO,KAAK,iEAAiE;EAD7F;;;;;;ACFhC,IAAa,uBAAb,MAA4E;CACxE,YAAY,AAAmB,WAAuB;EAAvB;AAC3B,SAAO,IAAI,MAAM,MAAM;GACnB,IAAI,QAAQ,MAAM,UAAU;AACxB,QAAI,QAAQ,OACR,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAE9C,WAAO,OAAO,YAAY,KAAe;;GAE7C,IAAI,QAAQ,MAAM,OAAO,UAAU;AAC/B,WAAO,OAAO,YAAY,MAAgB,MAAM;;GAEvD,CAAC;;CAGN,AAAO,WAAiB;AACpB,OAAK,2BAA2B;;CAGpC,AAAU,4BAAkC;AACxC,SAAO,QAAQ,KAAK,UAAU,CAAC,SAAS,CAAC,KAAK,YAAY;AACtD,OAAI,CAAC,OAAO,SACR;AAKJ,OAAI,OAFU,KAAK,YAAY,IAAI,KAEd,YACjB,OAAM,IAAI,iCAAiC,OAAO,OAAO,EAAE,MAAM,KAAK,EAAE,OAAO,CAAC;IAEtF;;CAGN,AAAU,YAAY,KAAsB;EACxC,MAAM,SAAS,KAAK,UAAU;AAE9B,MAAI,CAAC,OACD,OAAM,IAAI,yBAAyB,oDAAoD,IAAI,GAAG;EAGlG,MAAM,gBAAgB,QAAQ,IAAI,QAAQ,OAAO;EACjD,IAAI,QAAiB;EACrB,MAAM,OAAO,OAAO,QAAQ;AAE5B,MAAI,OAAO,YAAY,OAAO,UAAU,YACpC,OAAM,IAAI,iCAAiC,OAAO,OAAO,EAAE,MAAM,KAAK,EAAE,OAAO,CAAC;AAGpF,UAAQ,MAAR;GACI,KAAK;AACD,YAAQ,QAAQ,IAAI;AACpB;GACJ,KAAK;AACD,YAAQ,OAAO,MAAM;AACrB,QAAI,OAAO,MAAM,MAAM,CACnB,OAAM,IAAI,yBAAyB,4BAA4B,IAAI,KAAK,gBAAgB;AAE5F;GACJ,KAAK;AACD,SAAK,MAAM,OAAO,MAAM,CAAC;AACzB;;AAGR,MAAI,OAAO,UACP,SAAQ,OAAO,UAAU,MAAM;AAGnC,SAAO;;CAGX,AAAU,YAAY,KAAa,OAAyB;EACxD,MAAM,SAAS,KAAK,UAAU;AAE9B,MAAI,CAAC,OACD,OAAM,IAAI,yBAAyB,oDAAoD,IAAI,GAAG;AAGlG,MAAI,OAAO,UACP,OAAM,IAAI,yBAAyB,+EAA+E;AAGtH,UAAQ,OAAO,MAAf;GACI,KAAK;GACL,KAAK;GACL,KAAK;AACD,YAAQ,IAAI,OAAO,OAAO,MAAM;AAChC,WAAO;GACX,KAAK;AACD,YAAQ,IAAI,OAAO,KAAK,UAAU,MAAM;AACxC,WAAO;;AAGf,QAAM,IAAI,yBAAyB,iBAAiB,OAAO,KAAK,8BAA8B,IAAI,GAAG;;;;;;AC7F7G,SAAgB,2BAEd,WAAiE;CAC/D,MAAM,WAAW,IAAI,qBAAqB,UAAU;AAEpD,UAAS,UAAU;AAGnB,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcaservices/config",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Jørgen Vatle <Jorgen@WcAServices.net> (https://github.com/JorgenVatle)",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"lint": "tsgo --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"
|
|
15
|
+
"dist"
|
|
16
16
|
],
|
|
17
17
|
"exports": {
|
|
18
18
|
"types": "./dist/index.d.mts",
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { envFlag } from '@wcaservices/util/lib';
|
|
2
|
-
import { EnvironmentVariableError, RequiredEnvironmentVariableError } from './Errors.ts';
|
|
3
|
-
import type { VariableDefinitionMap, VariableOutputType } from './Types.ts';
|
|
4
|
-
|
|
5
|
-
export class EnvironmentVariables<TVariables extends VariableDefinitionMap> {
|
|
6
|
-
constructor(protected readonly variables: TVariables) {
|
|
7
|
-
return new Proxy(this, {
|
|
8
|
-
get(target, prop, receiver) {
|
|
9
|
-
if (prop in target) {
|
|
10
|
-
return Reflect.get(target, prop, receiver);
|
|
11
|
-
}
|
|
12
|
-
return target.getVariable(prop as string);
|
|
13
|
-
},
|
|
14
|
-
set(target, prop, value, receiver) {
|
|
15
|
-
return target.setVariable(prop as string, value);
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public validate(): void {
|
|
21
|
-
this.validateRequiredVariables();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
protected validateRequiredVariables(): void {
|
|
25
|
-
Object.entries(this.variables).forEach(([key, config]) => {
|
|
26
|
-
if (!config.required) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const value = this.getVariable(key);
|
|
31
|
-
|
|
32
|
-
if (typeof value === 'undefined') {
|
|
33
|
-
throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
protected getVariable(key: string): unknown {
|
|
39
|
-
const config = this.variables[key];
|
|
40
|
-
|
|
41
|
-
if (!config) {
|
|
42
|
-
throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const originalValue = process.env[key] ?? config.default;
|
|
46
|
-
let value: unknown = originalValue;
|
|
47
|
-
const cast = config.type ?? 'default';
|
|
48
|
-
|
|
49
|
-
if (config.required && typeof value === 'undefined') {
|
|
50
|
-
throw new RequiredEnvironmentVariableError(Object.assign({ name: key }, config));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
switch (cast) {
|
|
54
|
-
case 'BOOLEAN':
|
|
55
|
-
value = envFlag(key);
|
|
56
|
-
break;
|
|
57
|
-
case 'NUMBER':
|
|
58
|
-
value = Number(value);
|
|
59
|
-
if (Number.isNaN(value)) {
|
|
60
|
-
throw new EnvironmentVariableError(`Invalid number type for '${key}': ${originalValue}`);
|
|
61
|
-
}
|
|
62
|
-
break;
|
|
63
|
-
case 'JSON':
|
|
64
|
-
JSON.parse(String(value));
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (config.transform) {
|
|
69
|
-
value = config.transform(value);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return value;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
protected setVariable(key: string, value: unknown): boolean {
|
|
76
|
-
const config = this.variables[key];
|
|
77
|
-
|
|
78
|
-
if (!config) {
|
|
79
|
-
throw new EnvironmentVariableError(`No configuration found for environment variable '${key}'`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (config.transform) {
|
|
83
|
-
throw new EnvironmentVariableError('Setting environment variables with transform functions is not yet supported.');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
switch (config.type) {
|
|
87
|
-
case 'BOOLEAN':
|
|
88
|
-
case 'NUMBER':
|
|
89
|
-
case 'default':
|
|
90
|
-
process.env[key] = String(value);
|
|
91
|
-
return true;
|
|
92
|
-
case 'JSON':
|
|
93
|
-
process.env[key] = JSON.stringify(value);
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
throw new EnvironmentVariableError(`Invalid type '${config.type}' for environment variable '${key}'`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export type EnvironmentVariablesInstance<TVariables extends VariableDefinitionMap> = EnvironmentVariables<TVariables> & {
|
|
102
|
-
[key in keyof TVariables]: VariableOutputType<TVariables[key]>;
|
|
103
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { EnvironmentVariableConfig } from './Types.ts';
|
|
2
|
-
|
|
3
|
-
export class EnvironmentVariableError extends Error {
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export class RequiredEnvironmentVariableError extends EnvironmentVariableError {
|
|
7
|
-
constructor(public readonly config: EnvironmentVariableConfig & { name: string }) {
|
|
8
|
-
super(`Required environment variable "${config.name}" is missing. Make sure one is set before starting the process!`);
|
|
9
|
-
}
|
|
10
|
-
}
|
package/src/environment/Types.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export interface EnvironmentVariableConfig<
|
|
2
|
-
TRequired extends boolean = boolean,
|
|
3
|
-
TTypeCast extends keyof VariableTypeCast = keyof VariableTypeCast,
|
|
4
|
-
TTransform = unknown
|
|
5
|
-
> {
|
|
6
|
-
required?: TRequired;
|
|
7
|
-
type?: TTypeCast;
|
|
8
|
-
default?: VariableTypeCast[TTypeCast];
|
|
9
|
-
transform?: TransformFn<any, TTransform>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type VariableDefinitionMap = {
|
|
13
|
-
[key in keyof NodeJS.ProcessEnv]: EnvironmentVariableConfig;
|
|
14
|
-
}
|
|
15
|
-
export type VariableOutputType<
|
|
16
|
-
TConfig extends EnvironmentVariableConfig,
|
|
17
|
-
TTypeCast extends keyof VariableTypeCast = TConfig['type'] extends keyof VariableTypeCast
|
|
18
|
-
? TConfig['type']
|
|
19
|
-
: 'default',
|
|
20
|
-
TType = VariableTypeCast[TTypeCast],
|
|
21
|
-
TCastOutputType = TConfig['required'] extends true
|
|
22
|
-
? TType
|
|
23
|
-
: TType | undefined,
|
|
24
|
-
> = TConfig['transform'] extends TransformFn<TCastOutputType, infer TTransformOutput>
|
|
25
|
-
? TTransformOutput
|
|
26
|
-
: TCastOutputType;
|
|
27
|
-
|
|
28
|
-
type TransformFn<TInput, TOutput> = (value: TInput) => TOutput;
|
|
29
|
-
|
|
30
|
-
interface VariableTypeCast {
|
|
31
|
-
/**
|
|
32
|
-
* Default type for environment variables.
|
|
33
|
-
*/
|
|
34
|
-
default: string;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Boolean flag (1, 0, true, false, yes, no)
|
|
38
|
-
*/
|
|
39
|
-
BOOLEAN: boolean;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Cast inputs to number.
|
|
43
|
-
*/
|
|
44
|
-
NUMBER: number;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Parse input as JSON
|
|
48
|
-
*/
|
|
49
|
-
JSON: unknown; // todo
|
|
50
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { describe, expectTypeOf, it } from 'vitest';
|
|
2
|
-
import { defineEnvironmentVariables } from './defineEnvironmentVariables.ts';
|
|
3
|
-
|
|
4
|
-
describe('Type inference for string types', () => {
|
|
5
|
-
const env = defineEnvironmentVariables({
|
|
6
|
-
NON_REQUIRED_ENV_VAR: {},
|
|
7
|
-
REQUIRED_ENV_VAR: { required: true },
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('Only yields the configured variables', () => {
|
|
11
|
-
expectTypeOf(env).toMatchTypeOf<{
|
|
12
|
-
REQUIRED_ENV_VAR: string,
|
|
13
|
-
NON_REQUIRED_ENV_VAR: string | undefined
|
|
14
|
-
}>();
|
|
15
|
-
|
|
16
|
-
expectTypeOf(env).not.toMatchTypeOf<{
|
|
17
|
-
REQUIRED_ENV_VAR: string,
|
|
18
|
-
NON_REQUIRED_ENV_VAR: string | undefined,
|
|
19
|
-
UNKNOWN_REQUIRED_ENV_VAR: string,
|
|
20
|
-
UNKNOWN_NON_REQUIRED_ENV_VAR: string | undefined
|
|
21
|
-
}>();
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('Should yield string or undefined for non-required variables', () => {
|
|
25
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).toEqualTypeOf<string | undefined>();
|
|
26
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).not.toEqualTypeOf<string>();
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it(`Should omit 'undefined' type for required variables`, () => {
|
|
30
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).toEqualTypeOf<string>();
|
|
31
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
32
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
33
|
-
});
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe('Type inference for NUMBER types', () => {
|
|
37
|
-
const env = defineEnvironmentVariables({
|
|
38
|
-
NON_REQUIRED_ENV_VAR: { type: 'NUMBER' },
|
|
39
|
-
REQUIRED_ENV_VAR: { type: 'NUMBER', required: true },
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('Only yields the configured variables', () => {
|
|
43
|
-
expectTypeOf(env).toMatchTypeOf<{
|
|
44
|
-
REQUIRED_ENV_VAR: number,
|
|
45
|
-
NON_REQUIRED_ENV_VAR: number | undefined
|
|
46
|
-
}>();
|
|
47
|
-
|
|
48
|
-
expectTypeOf(env).not.toMatchTypeOf<{
|
|
49
|
-
REQUIRED_ENV_VAR: number,
|
|
50
|
-
NON_REQUIRED_ENV_VAR: number | undefined,
|
|
51
|
-
UNKNOWN_REQUIRED_ENV_VAR: number,
|
|
52
|
-
UNKNOWN_NON_REQUIRED_ENV_VAR: number | undefined
|
|
53
|
-
}>();
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('Should yield number or undefined for non-required variables', () => {
|
|
57
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).toEqualTypeOf<number | undefined>();
|
|
58
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).not.toEqualTypeOf<number>();
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it(`Should omit 'undefined' type for required variables`, () => {
|
|
62
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).toEqualTypeOf<number>();
|
|
63
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
64
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
describe('Type inference for BOOLEAN types', () => {
|
|
70
|
-
const env = defineEnvironmentVariables({
|
|
71
|
-
NON_REQUIRED_ENV_VAR: { type: 'BOOLEAN' },
|
|
72
|
-
REQUIRED_ENV_VAR: { type: 'BOOLEAN', required: true },
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('Only yields the configured variables', () => {
|
|
76
|
-
expectTypeOf(env).toMatchTypeOf<{
|
|
77
|
-
REQUIRED_ENV_VAR: boolean,
|
|
78
|
-
NON_REQUIRED_ENV_VAR: boolean | undefined
|
|
79
|
-
}>();
|
|
80
|
-
|
|
81
|
-
expectTypeOf(env).not.toMatchTypeOf<{
|
|
82
|
-
REQUIRED_ENV_VAR: boolean,
|
|
83
|
-
NON_REQUIRED_ENV_VAR: boolean | undefined,
|
|
84
|
-
UNKNOWN_REQUIRED_ENV_VAR: boolean,
|
|
85
|
-
UNKNOWN_NON_REQUIRED_ENV_VAR: boolean | undefined
|
|
86
|
-
}>();
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('Should yield boolean or undefined for non-required variables', () => {
|
|
90
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).toEqualTypeOf<boolean | undefined>();
|
|
91
|
-
expectTypeOf(env.NON_REQUIRED_ENV_VAR).not.toEqualTypeOf<boolean>();
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it(`Should omit 'undefined' type for required variables`, () => {
|
|
95
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).toEqualTypeOf<boolean>();
|
|
96
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
97
|
-
expectTypeOf(env.REQUIRED_ENV_VAR).not.toEqualTypeOf<undefined>();
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe('Type inference with transformer functions', () => {
|
|
102
|
-
const env = defineEnvironmentVariables({
|
|
103
|
-
EXPLICIT_RETURN_TYPE: {
|
|
104
|
-
transform: (value): 'yes' | 'no' => value === 'yes' ? 'yes' : 'no',
|
|
105
|
-
},
|
|
106
|
-
IMPLICIT_RETURN_TYPE: {
|
|
107
|
-
transform: (value) => value === 'yes' ? 'yes' as const : 'no' as const,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('Can infer types with explicit return types', () => {
|
|
112
|
-
expectTypeOf(env.EXPLICIT_RETURN_TYPE).toEqualTypeOf<'yes' | 'no'>();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('Can infer types with implicit return types', () => {
|
|
116
|
-
expectTypeOf(env.IMPLICIT_RETURN_TYPE).toEqualTypeOf<'yes' | 'no'>();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it.todo('Will infer input types for required variables', () => {
|
|
120
|
-
const env = defineEnvironmentVariables({
|
|
121
|
-
IMPLICIT_REQUIRED_ARGUMENT_TYPE: {
|
|
122
|
-
required: true,
|
|
123
|
-
transform: (value) => {
|
|
124
|
-
// @ts-expect-error TODO: fix transform input type inference
|
|
125
|
-
expectTypeOf(value).toEqualTypeOf<string>()
|
|
126
|
-
return 'ok' as const;
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
expectTypeOf(env.IMPLICIT_REQUIRED_ARGUMENT_TYPE).toEqualTypeOf<'ok'>();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it.todo('Will infer input types for optional variables', () => {
|
|
135
|
-
const env = defineEnvironmentVariables({
|
|
136
|
-
IMPLICIT_OPTIONAL_ARGUMENT_TYPE: {
|
|
137
|
-
transform: (value) => {
|
|
138
|
-
// @ts-expect-error TODO: fix transform input type inference
|
|
139
|
-
expectTypeOf(value).toEqualTypeOf<string | undefined>()
|
|
140
|
-
return 'ok' as const;
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
expectTypeOf(env.IMPLICIT_OPTIONAL_ARGUMENT_TYPE).toEqualTypeOf<'ok'>();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('Will allow explicit argument types', () => {
|
|
149
|
-
const env = defineEnvironmentVariables({
|
|
150
|
-
EXPLICIT_REQUIRED_ARGUMENT_TYPE: {
|
|
151
|
-
required: true,
|
|
152
|
-
transform: (value: string) => 'ok' as const,
|
|
153
|
-
},
|
|
154
|
-
EXPLICIT_OPTIONAL_ARGUMENT_TYPE: {
|
|
155
|
-
transform: (value: string | undefined) => 'ok' as const,
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
expectTypeOf(env.EXPLICIT_REQUIRED_ARGUMENT_TYPE).toEqualTypeOf<'ok'>();
|
|
160
|
-
expectTypeOf(env.EXPLICIT_OPTIONAL_ARGUMENT_TYPE).toEqualTypeOf<'ok'>();
|
|
161
|
-
})
|
|
162
|
-
})
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { defineEnvironmentVariables } from './defineEnvironmentVariables.ts';
|
|
3
|
-
import { RequiredEnvironmentVariableError } from './Errors.ts';
|
|
4
|
-
|
|
5
|
-
const ORIGINAL_ENV = Object.freeze({
|
|
6
|
-
...process.env,
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
describe('Environment variable parsing', () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
process.env = {
|
|
12
|
-
...ORIGINAL_ENV,
|
|
13
|
-
TEST_STRING_HELLO: 'world',
|
|
14
|
-
TEST_NUMBER_123: '123',
|
|
15
|
-
TEST_BOOLEAN_TRUE: 'true',
|
|
16
|
-
TEST_BOOLEAN_FALSE: 'false',
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('should enforce required environment variables', () => {
|
|
21
|
-
expect(() => {
|
|
22
|
-
const env = defineEnvironmentVariables({
|
|
23
|
-
REQUIRED_ENV_VALUE: {
|
|
24
|
-
required: true,
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
}).toThrow(RequiredEnvironmentVariableError);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should apply transform functions', () => {
|
|
31
|
-
const transform = (value: boolean) => value ? 'yes' : 'no';
|
|
32
|
-
|
|
33
|
-
const env = defineEnvironmentVariables({
|
|
34
|
-
TEST_BOOLEAN_TRUE: {
|
|
35
|
-
type: 'BOOLEAN',
|
|
36
|
-
required: true,
|
|
37
|
-
transform,
|
|
38
|
-
},
|
|
39
|
-
TEST_BOOLEAN_FALSE: {
|
|
40
|
-
type: 'BOOLEAN',
|
|
41
|
-
required: true,
|
|
42
|
-
transform,
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(env.TEST_BOOLEAN_TRUE).toEqual('yes');
|
|
47
|
-
expect(env.TEST_BOOLEAN_FALSE).toEqual('no');
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { EnvironmentVariables, type EnvironmentVariablesInstance } from './EnvironmentVariables.ts';
|
|
2
|
-
import type { VariableDefinitionMap } from './Types.ts';
|
|
3
|
-
|
|
4
|
-
export function defineEnvironmentVariables<
|
|
5
|
-
TVariables extends VariableDefinitionMap
|
|
6
|
-
>(variables: TVariables): EnvironmentVariablesInstance<TVariables> {
|
|
7
|
-
const instance = new EnvironmentVariables(variables);
|
|
8
|
-
|
|
9
|
-
instance.validate();
|
|
10
|
-
|
|
11
|
-
// @ts-expect-error Type mismatch between result and explicit return type
|
|
12
|
-
return instance;
|
|
13
|
-
}
|
|
14
|
-
|
package/src/environment/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './defineEnvironmentVariables';
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './environment';
|