@jeengbe/config 0.0.3 → 0.0.5

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/env.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ValidationResult } from "./validation.mjs";
2
2
  import { EnvNode, EnvSpec, InferEnvSpec, Pretty, ScalarEnvNode } from "./ast.mjs";
3
3
  //#region src/env.d.ts
4
- declare const env: {
4
+ interface Env {
5
5
  string(key: string, defaultValue?: string): ScalarEnvNode<string>;
6
6
  number(key: string, defaultValue?: number): ScalarEnvNode<number>;
7
7
  boolean(key: string, defaultValue?: boolean): ScalarEnvNode<boolean>;
@@ -10,8 +10,9 @@ declare const env: {
10
10
  array<T>(itemType: ScalarEnvNode<T>, defaultValue?: readonly T[]): EnvNode<readonly T[]>;
11
11
  discriminate<K extends string, V extends string, M extends Partial<Record<V, Record<string, EnvSpec>>>>(discriminatorKey: K, discriminatorValueType: ScalarEnvNode<V>, mapping: M): EnvNode<DiscriminatorResult<K, V, M>>;
12
12
  load<S extends EnvSpec>(spec: S): Pretty<InferEnvSpec<S>>;
13
- };
13
+ }
14
+ declare const env: Env;
14
15
  type DiscriminatorResult<K extends string, V extends string, M extends Partial<Record<V, Record<string, EnvSpec>>>> = Pretty<V extends unknown ? Record<K, V> & InferEnvSpec<M[V] extends EnvSpec ? M[V] : {}> : never>;
15
16
  //#endregion
16
- export { env };
17
+ export { Env, env };
17
18
  //# sourceMappingURL=env.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.mts","names":[],"sources":["../src/env.ts"],"mappings":";;;cAMa;EACX,OAAM,aAAY,wBAA0B;EAI5C,OAAM,aAAY,wBAA0B;EAc5C,QAAO,aAAY,yBAA2B;EAa9C,WAAW,kBAAgB,aACd,iBACM,KAAG,eACL,IACd,cAAc;EAcjB,OAAO,GAAC,aACK,YACC,kBAAkB,iBAAiB,IAAE,eAClC,IACd,cAAc;EAWjB,MAAM,GAAC,UAAY,cAAc,IAAE,wBAA0B,MAAM,iBAAiB;EAoBpF,aACE,kBACA,kBACA,UAAU,QAAQ,OAAO,GAAG,eAAe,YAAU,kBAEnC,GAAC,wBACK,cAAc,IAAE,SAC/B,IACR,QAAQ,oBAAoB,GAAG,GAAG;EAkBrC,KAAK,UAAU,SAAO,MAAQ,IAAI,OAAO,aAAa;;KASnD,oBACH,kBACA,kBACA,UAAU,QAAQ,OAAO,GAAG,eAAe,cACzC,OAGF,oBAAoB,OAAO,GAAG,KAAK,aAAa,EAAE,WAAW,UAAU,EAAE"}
1
+ {"version":3,"file":"env.d.mts","names":[],"sources":["../src/env.ts"],"mappings":";;;UAMiB;EACf,OAAO,aAAa,wBAAwB;EAC5C,OAAO,aAAa,wBAAwB;EAC5C,QAAQ,aAAa,yBAAyB;EAC9C,WAAW,kBACT,aACA,iBAAiB,KACjB,eAAe,IACd,cAAc;EACjB,OAAO,GACL,aACA,YAAY,kBAAkB,iBAAiB,IAC/C,eAAe,IACd,cAAc;EACjB,MAAM,GAAG,UAAU,cAAc,IAAI,wBAAwB,MAAM,iBAAiB;EACpF,aACE,kBACA,kBACA,UAAU,QAAQ,OAAO,GAAG,eAAe,YAE3C,kBAAkB,GAClB,wBAAwB,cAAc,IACtC,SAAS,IACR,QAAQ,oBAAoB,GAAG,GAAG;EACrC,KAAK,UAAU,SAAS,MAAM,IAAI,OAAO,aAAa;;cAG3C,KAAK;KAgHb,oBACH,kBACA,kBACA,UAAU,QAAQ,OAAO,GAAG,eAAe,cACzC,OAGF,oBAAoB,OAAO,GAAG,KAAK,aAAa,EAAE,WAAW,UAAU,EAAE"}
package/dist/env.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.mjs","names":[],"sources":["../src/env.ts"],"sourcesContent":["import type { EnvSpec, InferEnvSpec, Pretty } from './ast.js';\nimport { EnvNode, ScalarEnvNode } from './ast.js';\nimport type { ValidationResult } from './validation.js';\nimport { arrayIncludes, combineValidationResults } from './validation.js';\nimport { Either } from '@jeengbe/prelude';\n\nexport const env = {\n string(key: string, defaultValue?: string): ScalarEnvNode<string> {\n return env.custom(key, (value) => Either.right(value), defaultValue);\n },\n\n number(key: string, defaultValue?: number): ScalarEnvNode<number> {\n return env.custom(\n key,\n (value) => {\n if (/^-?\\d+(?:\\.\\d+)?$/.test(value)) {\n return Either.right(Number(value));\n }\n\n return Either.left(['invalid number']);\n },\n defaultValue,\n );\n },\n\n boolean(key: string, defaultValue?: boolean): ScalarEnvNode<boolean> {\n return env.custom(\n key,\n (value) => {\n if (value.toLowerCase() === 'true') return Either.right(true);\n if (value.toLowerCase() === 'false') return Either.right(false);\n\n return Either.left([\"invalid boolean (must be 'true' or 'false')\"]);\n },\n defaultValue,\n );\n },\n\n enum<const T extends string>(\n key: string,\n values: readonly T[],\n defaultValue?: T,\n ): ScalarEnvNode<T> {\n return env.custom(\n key,\n (value) => {\n if (arrayIncludes(values, value)) return Either.right(value);\n\n return Either.left([\n `invalid enum value (must be one of: ${values.map((v) => `'${v}'`).join(', ')})`,\n ]);\n },\n defaultValue,\n );\n },\n\n custom<T>(\n key: string,\n transform: (value: string) => ValidationResult<T>,\n defaultValue?: T,\n ): ScalarEnvNode<T> {\n return new ScalarEnvNode(key, (value) => {\n if (value === undefined) {\n if (defaultValue !== undefined) return Either.right(defaultValue);\n return Either.left(['required']);\n }\n\n return transform(value);\n });\n },\n\n array<T>(itemType: ScalarEnvNode<T>, defaultValue?: readonly T[]): EnvNode<readonly T[]> {\n return new EnvNode((path, loadValue) => {\n const value = loadValue(itemType.key);\n if (value === undefined) {\n if (defaultValue !== undefined) return Either.right(defaultValue);\n return Either.left([`${itemType.key} (${path}): required`]);\n }\n if (value === '') return Either.right([]);\n\n return combineValidationResults(\n ...value\n .split(',')\n .map((v) => v.trim() || undefined)\n .map((v, i) =>\n itemType.validate(`${path}.${i}`, (k) => (k === itemType.key ? v : undefined)),\n ),\n );\n });\n },\n\n discriminate<\n K extends string,\n V extends string,\n M extends Partial<Record<V, Record<string, EnvSpec>>>,\n >(\n discriminatorKey: K,\n discriminatorValueType: ScalarEnvNode<V>,\n mapping: M,\n ): EnvNode<DiscriminatorResult<K, V, M>> {\n return new EnvNode((path, loadValue) => {\n return discriminatorValueType.validate(path, loadValue).flatMap((discriminatorValue) => {\n return resolveNode<NonNullable<M[keyof M]> | {}>(\n path,\n mapping[discriminatorValue] ?? {},\n loadValue,\n ).map(\n (mappingValues) =>\n ({\n [discriminatorKey]: discriminatorValue,\n ...mappingValues,\n }) as DiscriminatorResult<K, V, M>,\n );\n });\n });\n },\n\n load<S extends EnvSpec>(spec: S): Pretty<InferEnvSpec<S>> {\n return resolveNode('$', spec, (key) => process.env[key]?.trim() || undefined).getOrElse(\n (errors) => {\n throw new Error(`Failed to load config: ${errors.join(', ')}`);\n },\n );\n },\n};\n\ntype DiscriminatorResult<\n K extends string,\n V extends string,\n M extends Partial<Record<V, Record<string, EnvSpec>>>,\n> = Pretty<\n // This \"redundant\" condition is necessary to make sure that 'DiscriminatorResult' distributes over\n // the union type V\n V extends unknown ? Record<K, V> & InferEnvSpec<M[V] extends EnvSpec ? M[V] : {}> : never\n>;\n\nfunction resolveNode<S extends EnvSpec>(\n path: string,\n spec: S,\n loadValue: (key: string) => string | undefined,\n): ValidationResult<Pretty<InferEnvSpec<S>>> {\n if (spec instanceof EnvNode) {\n return (spec as EnvNode<Pretty<InferEnvSpec<S>>>).validate(path, loadValue);\n }\n\n return combineValidationResults(\n ...Object.entries(spec).map(([key, value]) =>\n resolveNode(`${path}.${key}`, value, loadValue).map((v) => [key, v] as const),\n ),\n ).map((entries) => Object.fromEntries(entries) as Pretty<InferEnvSpec<S>>);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"env.mjs","names":[],"sources":["../src/env.ts"],"sourcesContent":["import type { EnvSpec, InferEnvSpec, Pretty } from './ast.js';\nimport { EnvNode, ScalarEnvNode } from './ast.js';\nimport type { ValidationResult } from './validation.js';\nimport { arrayIncludes, combineValidationResults } from './validation.js';\nimport { Either } from '@jeengbe/prelude';\n\nexport interface Env {\n string(key: string, defaultValue?: string): ScalarEnvNode<string>;\n number(key: string, defaultValue?: number): ScalarEnvNode<number>;\n boolean(key: string, defaultValue?: boolean): ScalarEnvNode<boolean>;\n enum<const T extends string>(\n key: string,\n values: readonly T[],\n defaultValue?: T,\n ): ScalarEnvNode<T>;\n custom<T>(\n key: string,\n transform: (value: string) => ValidationResult<T>,\n defaultValue?: T,\n ): ScalarEnvNode<T>;\n array<T>(itemType: ScalarEnvNode<T>, defaultValue?: readonly T[]): EnvNode<readonly T[]>;\n discriminate<\n K extends string,\n V extends string,\n M extends Partial<Record<V, Record<string, EnvSpec>>>,\n >(\n discriminatorKey: K,\n discriminatorValueType: ScalarEnvNode<V>,\n mapping: M,\n ): EnvNode<DiscriminatorResult<K, V, M>>;\n load<S extends EnvSpec>(spec: S): Pretty<InferEnvSpec<S>>;\n}\n\nexport const env: Env = {\n string(key, defaultValue) {\n return env.custom(key, (value) => Either.right(value), defaultValue);\n },\n\n number(key, defaultValue) {\n return env.custom(\n key,\n (value) => {\n if (/^-?\\d+(?:\\.\\d+)?$/.test(value)) {\n return Either.right(Number(value));\n }\n\n return Either.left(['invalid number']);\n },\n defaultValue,\n );\n },\n\n boolean(key, defaultValue) {\n return env.custom(\n key,\n (value) => {\n if (value.toLowerCase() === 'true') return Either.right(true);\n if (value.toLowerCase() === 'false') return Either.right(false);\n\n return Either.left([\"invalid boolean (must be 'true' or 'false')\"]);\n },\n defaultValue,\n );\n },\n\n enum(key, values, defaultValue) {\n return env.custom(\n key,\n (value) => {\n if (arrayIncludes(values, value)) return Either.right(value);\n\n return Either.left([\n `invalid enum value (must be one of: ${values.map((v) => `'${v}'`).join(', ')})`,\n ]);\n },\n defaultValue,\n );\n },\n\n custom(key, transform, defaultValue) {\n return new ScalarEnvNode(key, (value) => {\n if (value === undefined) {\n if (defaultValue !== undefined) return Either.right(defaultValue);\n return Either.left(['required']);\n }\n\n return transform(value);\n });\n },\n\n array<T>(itemType: ScalarEnvNode<T>, defaultValue?: readonly T[]): EnvNode<readonly T[]> {\n return new EnvNode((path, loadValue) => {\n const value = loadValue(itemType.key);\n if (value === undefined) {\n if (defaultValue !== undefined) return Either.right(defaultValue);\n return Either.left([`${itemType.key} (${path}): required`]);\n }\n if (value === '') return Either.right([]);\n\n return combineValidationResults(\n ...value\n .split(',')\n .map((v) => v.trim() || undefined)\n .map((v, i) =>\n itemType.validate(`${path}.${i}`, (k) => (k === itemType.key ? v : undefined)),\n ),\n );\n });\n },\n\n discriminate<\n K extends string,\n V extends string,\n M extends Partial<Record<V, Record<string, EnvSpec>>>,\n >(\n discriminatorKey: K,\n discriminatorValueType: ScalarEnvNode<V>,\n mapping: M,\n ): EnvNode<DiscriminatorResult<K, V, M>> {\n return new EnvNode((path, loadValue) => {\n return discriminatorValueType.validate(path, loadValue).flatMap((discriminatorValue) => {\n return resolveNode<NonNullable<M[keyof M]> | {}>(\n path,\n mapping[discriminatorValue] ?? {},\n loadValue,\n ).map(\n (mappingValues) =>\n ({\n [discriminatorKey]: discriminatorValue,\n ...mappingValues,\n }) as DiscriminatorResult<K, V, M>,\n );\n });\n });\n },\n\n load(spec) {\n return resolveNode('$', spec, (key) => process.env[key]?.trim() || undefined).getOrElse(\n (errors) => {\n throw new Error(`Failed to load config: ${errors.join(', ')}`);\n },\n );\n },\n};\n\ntype DiscriminatorResult<\n K extends string,\n V extends string,\n M extends Partial<Record<V, Record<string, EnvSpec>>>,\n> = Pretty<\n // This \"redundant\" condition is necessary to make sure that 'DiscriminatorResult' distributes over\n // the union type V\n V extends unknown ? Record<K, V> & InferEnvSpec<M[V] extends EnvSpec ? M[V] : {}> : never\n>;\n\nfunction resolveNode<S extends EnvSpec>(\n path: string,\n spec: S,\n loadValue: (key: string) => string | undefined,\n): ValidationResult<Pretty<InferEnvSpec<S>>> {\n if (spec instanceof EnvNode) {\n return (spec as EnvNode<Pretty<InferEnvSpec<S>>>).validate(path, loadValue);\n }\n\n return combineValidationResults(\n ...Object.entries(spec).map(([key, value]) =>\n resolveNode(`${path}.${key}`, value, loadValue).map((v) => [key, v] as const),\n ),\n ).map((entries) => Object.fromEntries(entries) as Pretty<InferEnvSpec<S>>);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeengbe/config",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,8 @@
10
10
  "files": [
11
11
  "dist",
12
12
  "src",
13
- "!src/**/*.spec.ts"
13
+ "!src/**/*.spec.ts",
14
+ "!src/__snapshots__/*"
14
15
  ],
15
16
  "type": "module",
16
17
  "sideEffects": false,
@@ -26,7 +27,7 @@
26
27
  "access": "public"
27
28
  },
28
29
  "dependencies": {
29
- "@jeengbe/prelude": "0.0.3"
30
+ "@jeengbe/prelude": "0.0.5"
30
31
  },
31
32
  "devDependencies": {
32
33
  "oxfmt": "^0.60.0",
@@ -34,7 +35,7 @@
34
35
  "tsdown": "^0.22.14",
35
36
  "typescript": "^7.0.2",
36
37
  "vitest": "^4.1.10",
37
- "@jeengbe/scaffolding": "0.0.3"
38
+ "@jeengbe/scaffolding": "0.0.5"
38
39
  },
39
40
  "scripts": {
40
41
  "build": "tsdown",
package/src/env.ts CHANGED
@@ -4,12 +4,39 @@ import type { ValidationResult } from './validation.js';
4
4
  import { arrayIncludes, combineValidationResults } from './validation.js';
5
5
  import { Either } from '@jeengbe/prelude';
6
6
 
7
- export const env = {
8
- string(key: string, defaultValue?: string): ScalarEnvNode<string> {
7
+ export interface Env {
8
+ string(key: string, defaultValue?: string): ScalarEnvNode<string>;
9
+ number(key: string, defaultValue?: number): ScalarEnvNode<number>;
10
+ boolean(key: string, defaultValue?: boolean): ScalarEnvNode<boolean>;
11
+ enum<const T extends string>(
12
+ key: string,
13
+ values: readonly T[],
14
+ defaultValue?: T,
15
+ ): ScalarEnvNode<T>;
16
+ custom<T>(
17
+ key: string,
18
+ transform: (value: string) => ValidationResult<T>,
19
+ defaultValue?: T,
20
+ ): ScalarEnvNode<T>;
21
+ array<T>(itemType: ScalarEnvNode<T>, defaultValue?: readonly T[]): EnvNode<readonly T[]>;
22
+ discriminate<
23
+ K extends string,
24
+ V extends string,
25
+ M extends Partial<Record<V, Record<string, EnvSpec>>>,
26
+ >(
27
+ discriminatorKey: K,
28
+ discriminatorValueType: ScalarEnvNode<V>,
29
+ mapping: M,
30
+ ): EnvNode<DiscriminatorResult<K, V, M>>;
31
+ load<S extends EnvSpec>(spec: S): Pretty<InferEnvSpec<S>>;
32
+ }
33
+
34
+ export const env: Env = {
35
+ string(key, defaultValue) {
9
36
  return env.custom(key, (value) => Either.right(value), defaultValue);
10
37
  },
11
38
 
12
- number(key: string, defaultValue?: number): ScalarEnvNode<number> {
39
+ number(key, defaultValue) {
13
40
  return env.custom(
14
41
  key,
15
42
  (value) => {
@@ -23,7 +50,7 @@ export const env = {
23
50
  );
24
51
  },
25
52
 
26
- boolean(key: string, defaultValue?: boolean): ScalarEnvNode<boolean> {
53
+ boolean(key, defaultValue) {
27
54
  return env.custom(
28
55
  key,
29
56
  (value) => {
@@ -36,11 +63,7 @@ export const env = {
36
63
  );
37
64
  },
38
65
 
39
- enum<const T extends string>(
40
- key: string,
41
- values: readonly T[],
42
- defaultValue?: T,
43
- ): ScalarEnvNode<T> {
66
+ enum(key, values, defaultValue) {
44
67
  return env.custom(
45
68
  key,
46
69
  (value) => {
@@ -54,11 +77,7 @@ export const env = {
54
77
  );
55
78
  },
56
79
 
57
- custom<T>(
58
- key: string,
59
- transform: (value: string) => ValidationResult<T>,
60
- defaultValue?: T,
61
- ): ScalarEnvNode<T> {
80
+ custom(key, transform, defaultValue) {
62
81
  return new ScalarEnvNode(key, (value) => {
63
82
  if (value === undefined) {
64
83
  if (defaultValue !== undefined) return Either.right(defaultValue);
@@ -115,7 +134,7 @@ export const env = {
115
134
  });
116
135
  },
117
136
 
118
- load<S extends EnvSpec>(spec: S): Pretty<InferEnvSpec<S>> {
137
+ load(spec) {
119
138
  return resolveNode('$', spec, (key) => process.env[key]?.trim() || undefined).getOrElse(
120
139
  (errors) => {
121
140
  throw new Error(`Failed to load config: ${errors.join(', ')}`);