@jayalfredprufrock/confetti 0.1.3 → 0.2.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/README.md +251 -0
- package/dist/index.cjs +167 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -28
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +90 -28
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +154 -86
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,68 +1,130 @@
|
|
|
1
1
|
//#region src/symbols.d.ts
|
|
2
2
|
declare const CONFETTI: unique symbol;
|
|
3
3
|
declare const DEFAULT: unique symbol;
|
|
4
|
-
declare const
|
|
4
|
+
declare const ENV: unique symbol;
|
|
5
5
|
declare const DATA: unique symbol;
|
|
6
|
+
declare const TYPE: unique symbol;
|
|
6
7
|
//#endregion
|
|
7
8
|
//#region src/types.d.ts
|
|
8
9
|
type Obj<T = unknown> = Record<string, T>;
|
|
9
10
|
type Primitive = string | number | boolean | null;
|
|
10
11
|
type MaybeArray<T> = T | T[];
|
|
11
|
-
type
|
|
12
|
+
type ConfigValFn<T = unknown> = (env: string) => T;
|
|
13
|
+
type ConfigVal = MaybeArray<Primitive> | ConfigValFn<any>;
|
|
14
|
+
type TypeTag = "string" | "number" | "boolean" | "string[]" | "number[]" | "boolean[]";
|
|
15
|
+
type TypeMap = {
|
|
16
|
+
string: string;
|
|
17
|
+
number: number;
|
|
18
|
+
boolean: boolean;
|
|
19
|
+
"string[]": string[];
|
|
20
|
+
"number[]": number[];
|
|
21
|
+
"boolean[]": boolean[];
|
|
22
|
+
};
|
|
12
23
|
type IsConfigValPerEnv<T> = T extends {
|
|
13
24
|
[DEFAULT]: any;
|
|
14
25
|
} | {
|
|
15
|
-
[
|
|
26
|
+
[ENV]: any;
|
|
16
27
|
} | {
|
|
17
28
|
[DATA]: any;
|
|
29
|
+
} | {
|
|
30
|
+
[TYPE]: any;
|
|
18
31
|
} ? true : false;
|
|
19
|
-
type
|
|
20
|
-
[
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
|
|
32
|
+
type ConfigValPerEnvTyped<T extends TypeTag> = {
|
|
33
|
+
readonly [TYPE]: T;
|
|
34
|
+
readonly [DEFAULT]?: TypeMap[T] | ConfigValFn<TypeMap[T]>;
|
|
35
|
+
readonly [ENV]?: string;
|
|
36
|
+
readonly [DATA]?: any;
|
|
37
|
+
readonly [key: string]: TypeMap[T] | ConfigValFn<TypeMap[T]>;
|
|
38
|
+
};
|
|
39
|
+
type ConfigValPerEnvFetcher = {
|
|
40
|
+
readonly [TYPE]?: never;
|
|
41
|
+
readonly [DEFAULT]?: string | ConfigValFn<string>;
|
|
42
|
+
readonly [ENV]?: string;
|
|
43
|
+
readonly [DATA]?: any;
|
|
44
|
+
readonly [key: string]: string | ConfigValFn<string> | undefined;
|
|
45
|
+
};
|
|
46
|
+
type ConfigValPerEnvPlain<D extends ConfigVal = ConfigVal> = {
|
|
47
|
+
readonly [TYPE]?: never;
|
|
48
|
+
readonly [DEFAULT]?: D;
|
|
49
|
+
readonly [ENV]?: never;
|
|
50
|
+
readonly [DATA]?: never;
|
|
51
|
+
readonly [key: string]: D;
|
|
52
|
+
};
|
|
53
|
+
type ConfigValPerEnv = ConfigValPerEnvTyped<TypeTag> | ConfigValPerEnvFetcher | ConfigValPerEnvPlain;
|
|
24
54
|
type Config = {
|
|
25
55
|
[key: string]: Config | ConfigVal | ConfigValPerEnv;
|
|
26
56
|
};
|
|
27
|
-
type
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
type ValidateConfig<C> = { [K in keyof C]: C[K] extends {
|
|
58
|
+
[TYPE]: infer T extends TypeTag;
|
|
59
|
+
} ? ConfigValPerEnvTyped<T> : C[K] extends {
|
|
60
|
+
[ENV]: any;
|
|
61
|
+
} | {
|
|
62
|
+
[DATA]: any;
|
|
63
|
+
} ? ConfigValPerEnvFetcher : C[K] extends {
|
|
64
|
+
[DEFAULT]: any;
|
|
65
|
+
} ? C[K] : C[K] extends Obj ? ValidateConfig<C[K]> : C[K] };
|
|
66
|
+
type WidenLiteral<T> = T extends boolean ? boolean : T extends number ? number : T extends string ? string : T extends readonly (infer E)[] ? WidenLiteral<E>[] : T;
|
|
67
|
+
type ResolvedValue<V> = V extends ((...args: any[]) => any) ? Awaited<ReturnType<V>> : WidenLiteral<V>;
|
|
68
|
+
type ResolvedConfig<C> = { [K in keyof C]: C[K] extends Obj ? IsConfigValPerEnv<C[K]> extends true ? ResolveNode<C[K]> : ResolvedConfig<C[K]> : ResolvedValue<C[K]> };
|
|
69
|
+
type IsNestedConfig<T> = T extends Obj ? (IsConfigValPerEnv<T> extends true ? false : true) : false;
|
|
70
|
+
type Paths<C> = C extends Obj ? { [K in keyof C & string]: IsNestedConfig<C[K]> extends true ? K | `${K}.${Paths<C[K]> & string}` : K }[keyof C & string] : never;
|
|
71
|
+
type SubtreePaths<C> = C extends Obj ? { [K in keyof C & string]: IsNestedConfig<C[K]> extends true ? K | `${K}.${SubtreePaths<C[K]> & string}` : never }[keyof C & string] : never;
|
|
72
|
+
type ResolveNode<T> = T extends Obj ? IsConfigValPerEnv<T> extends true ? T extends {
|
|
73
|
+
[TYPE]: infer Tag extends TypeTag;
|
|
74
|
+
} ? TypeMap[Tag] : T extends {
|
|
75
|
+
[ENV]: any;
|
|
76
|
+
} | {
|
|
77
|
+
[DATA]: any;
|
|
78
|
+
} ? string : T extends ConfigValPerEnvPlain<infer D> ? ResolvedValue<D> : never : ResolvedConfig<T> : ResolvedValue<T>;
|
|
79
|
+
type ValueAtPath<C, P extends string> = P extends `${infer Head}.${infer Rest}` ? Head extends keyof C ? ValueAtPath<C[Head], Rest> : never : P extends keyof C ? ResolveNode<C[P]> : never;
|
|
80
|
+
interface FetcherContext<D = unknown> {
|
|
81
|
+
env: string;
|
|
82
|
+
default?: D;
|
|
35
83
|
envVar?: string;
|
|
84
|
+
data?: unknown;
|
|
85
|
+
type?: TypeTag;
|
|
36
86
|
}
|
|
37
|
-
|
|
87
|
+
type Fetcher<D = unknown, T = unknown> = (context: FetcherContext<D>) => Promise<T | undefined>;
|
|
88
|
+
interface ConfigEntry {
|
|
38
89
|
path: string;
|
|
39
|
-
|
|
90
|
+
value?: unknown;
|
|
91
|
+
default?: unknown;
|
|
40
92
|
envVar?: string;
|
|
41
93
|
data?: unknown;
|
|
94
|
+
type?: TypeTag;
|
|
42
95
|
}
|
|
43
96
|
type Confetti<C> = {
|
|
44
97
|
[CONFETTI]: "CONFETTI";
|
|
45
98
|
(env: string): {
|
|
46
99
|
config: C;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
resolveEnv: () => Promise<Obj<string>>;
|
|
100
|
+
get(): ResolvedConfig<C>;
|
|
101
|
+
get<P extends Paths<C> & string>(path: P): ValueAtPath<C, P>;
|
|
102
|
+
resolve(fetcher: Fetcher): Promise<ResolvedConfig<C>>;
|
|
103
|
+
resolve<P extends Paths<C> & string>(path: P, fetcher: Fetcher): Promise<ValueAtPath<C, P>>;
|
|
104
|
+
entries(startPath?: SubtreePaths<C> & string): IterableIterator<[string, ConfigEntry]>;
|
|
53
105
|
};
|
|
54
106
|
};
|
|
55
107
|
type GetConfig<T> = T extends Confetti<infer C> ? ResolvedConfig<C> : never;
|
|
56
108
|
//#endregion
|
|
57
109
|
//#region src/make-config.d.ts
|
|
58
|
-
declare const makeConfig: <C extends Config>(
|
|
110
|
+
declare const makeConfig: <const C extends Config>(input: (C & ValidateConfig<C>) | ((env: string) => C & ValidateConfig<C>)) => Confetti<C>;
|
|
59
111
|
//#endregion
|
|
60
112
|
//#region src/util.d.ts
|
|
61
113
|
declare const isObj: (val: unknown) => val is Obj;
|
|
62
114
|
declare const isConfigValPerEnv: (val: unknown) => val is ConfigValPerEnv;
|
|
115
|
+
declare const isNestedConfig: (val: unknown) => val is Obj;
|
|
63
116
|
declare const isConfetti: (val: unknown) => val is Confetti<any>;
|
|
64
|
-
declare const
|
|
65
|
-
declare const
|
|
117
|
+
declare const isThenable: (v: unknown) => v is PromiseLike<unknown>;
|
|
118
|
+
declare const getAtPath: (config: Obj, path: string) => unknown;
|
|
119
|
+
declare const coerceFromString: (raw: string, type: TypeTag, path: string) => unknown;
|
|
120
|
+
declare const buildEntry: (node: unknown, path: string, env: string) => ConfigEntry;
|
|
121
|
+
declare function entriesIter(config: Obj, env: string, pathPrefix?: string): IterableIterator<[string, ConfigEntry]>;
|
|
122
|
+
declare const invokeSync: (source: unknown, path: string, env: string) => unknown;
|
|
123
|
+
declare const invokeAsync: (source: unknown, env: string) => Promise<unknown>;
|
|
124
|
+
declare const resolveEntrySync: (entry: ConfigEntry, env: string) => unknown;
|
|
125
|
+
declare const resolveEntryAsync: (entry: ConfigEntry, env: string, fetcher: Fetcher) => Promise<unknown>;
|
|
126
|
+
declare const resolveSubtreeSync: (node: Obj, prefix: string, env: string) => Obj;
|
|
127
|
+
declare const resolveSubtreeAsync: (node: Obj, prefix: string, env: string, fetcher: Fetcher) => Promise<Obj>;
|
|
66
128
|
//#endregion
|
|
67
|
-
export { CONFETTI, Confetti, Config,
|
|
129
|
+
export { CONFETTI, Confetti, Config, ConfigEntry, ConfigVal, ConfigValFn, ConfigValPerEnv, ConfigValPerEnvFetcher, ConfigValPerEnvPlain, ConfigValPerEnvTyped, DATA, DEFAULT, ENV, Fetcher, FetcherContext, GetConfig, IsConfigValPerEnv, MaybeArray, Obj, Paths, Primitive, ResolvedConfig, ResolvedValue, SubtreePaths, TYPE, TypeMap, TypeTag, ValidateConfig, ValueAtPath, buildEntry, coerceFromString, entriesIter, getAtPath, invokeAsync, invokeSync, isConfetti, isConfigValPerEnv, isNestedConfig, isObj, isThenable, makeConfig, resolveEntryAsync, resolveEntrySync, resolveSubtreeAsync, resolveSubtreeSync };
|
|
68
130
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/symbols.ts","../src/types.ts","../src/make-config.ts","../src/util.ts"],"mappings":";cAAa,QAAA;AAAA,cACA,OAAA;AAAA,cACA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/symbols.ts","../src/types.ts","../src/make-config.ts","../src/util.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,68 +1,130 @@
|
|
|
1
1
|
//#region src/symbols.d.ts
|
|
2
2
|
declare const CONFETTI: unique symbol;
|
|
3
3
|
declare const DEFAULT: unique symbol;
|
|
4
|
-
declare const
|
|
4
|
+
declare const ENV: unique symbol;
|
|
5
5
|
declare const DATA: unique symbol;
|
|
6
|
+
declare const TYPE: unique symbol;
|
|
6
7
|
//#endregion
|
|
7
8
|
//#region src/types.d.ts
|
|
8
9
|
type Obj<T = unknown> = Record<string, T>;
|
|
9
10
|
type Primitive = string | number | boolean | null;
|
|
10
11
|
type MaybeArray<T> = T | T[];
|
|
11
|
-
type
|
|
12
|
+
type ConfigValFn<T = unknown> = (env: string) => T;
|
|
13
|
+
type ConfigVal = MaybeArray<Primitive> | ConfigValFn<any>;
|
|
14
|
+
type TypeTag = "string" | "number" | "boolean" | "string[]" | "number[]" | "boolean[]";
|
|
15
|
+
type TypeMap = {
|
|
16
|
+
string: string;
|
|
17
|
+
number: number;
|
|
18
|
+
boolean: boolean;
|
|
19
|
+
"string[]": string[];
|
|
20
|
+
"number[]": number[];
|
|
21
|
+
"boolean[]": boolean[];
|
|
22
|
+
};
|
|
12
23
|
type IsConfigValPerEnv<T> = T extends {
|
|
13
24
|
[DEFAULT]: any;
|
|
14
25
|
} | {
|
|
15
|
-
[
|
|
26
|
+
[ENV]: any;
|
|
16
27
|
} | {
|
|
17
28
|
[DATA]: any;
|
|
29
|
+
} | {
|
|
30
|
+
[TYPE]: any;
|
|
18
31
|
} ? true : false;
|
|
19
|
-
type
|
|
20
|
-
[
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
|
|
32
|
+
type ConfigValPerEnvTyped<T extends TypeTag> = {
|
|
33
|
+
readonly [TYPE]: T;
|
|
34
|
+
readonly [DEFAULT]?: TypeMap[T] | ConfigValFn<TypeMap[T]>;
|
|
35
|
+
readonly [ENV]?: string;
|
|
36
|
+
readonly [DATA]?: any;
|
|
37
|
+
readonly [key: string]: TypeMap[T] | ConfigValFn<TypeMap[T]>;
|
|
38
|
+
};
|
|
39
|
+
type ConfigValPerEnvFetcher = {
|
|
40
|
+
readonly [TYPE]?: never;
|
|
41
|
+
readonly [DEFAULT]?: string | ConfigValFn<string>;
|
|
42
|
+
readonly [ENV]?: string;
|
|
43
|
+
readonly [DATA]?: any;
|
|
44
|
+
readonly [key: string]: string | ConfigValFn<string> | undefined;
|
|
45
|
+
};
|
|
46
|
+
type ConfigValPerEnvPlain<D extends ConfigVal = ConfigVal> = {
|
|
47
|
+
readonly [TYPE]?: never;
|
|
48
|
+
readonly [DEFAULT]?: D;
|
|
49
|
+
readonly [ENV]?: never;
|
|
50
|
+
readonly [DATA]?: never;
|
|
51
|
+
readonly [key: string]: D;
|
|
52
|
+
};
|
|
53
|
+
type ConfigValPerEnv = ConfigValPerEnvTyped<TypeTag> | ConfigValPerEnvFetcher | ConfigValPerEnvPlain;
|
|
24
54
|
type Config = {
|
|
25
55
|
[key: string]: Config | ConfigVal | ConfigValPerEnv;
|
|
26
56
|
};
|
|
27
|
-
type
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
type ValidateConfig<C> = { [K in keyof C]: C[K] extends {
|
|
58
|
+
[TYPE]: infer T extends TypeTag;
|
|
59
|
+
} ? ConfigValPerEnvTyped<T> : C[K] extends {
|
|
60
|
+
[ENV]: any;
|
|
61
|
+
} | {
|
|
62
|
+
[DATA]: any;
|
|
63
|
+
} ? ConfigValPerEnvFetcher : C[K] extends {
|
|
64
|
+
[DEFAULT]: any;
|
|
65
|
+
} ? C[K] : C[K] extends Obj ? ValidateConfig<C[K]> : C[K] };
|
|
66
|
+
type WidenLiteral<T> = T extends boolean ? boolean : T extends number ? number : T extends string ? string : T extends readonly (infer E)[] ? WidenLiteral<E>[] : T;
|
|
67
|
+
type ResolvedValue<V> = V extends ((...args: any[]) => any) ? Awaited<ReturnType<V>> : WidenLiteral<V>;
|
|
68
|
+
type ResolvedConfig<C> = { [K in keyof C]: C[K] extends Obj ? IsConfigValPerEnv<C[K]> extends true ? ResolveNode<C[K]> : ResolvedConfig<C[K]> : ResolvedValue<C[K]> };
|
|
69
|
+
type IsNestedConfig<T> = T extends Obj ? (IsConfigValPerEnv<T> extends true ? false : true) : false;
|
|
70
|
+
type Paths<C> = C extends Obj ? { [K in keyof C & string]: IsNestedConfig<C[K]> extends true ? K | `${K}.${Paths<C[K]> & string}` : K }[keyof C & string] : never;
|
|
71
|
+
type SubtreePaths<C> = C extends Obj ? { [K in keyof C & string]: IsNestedConfig<C[K]> extends true ? K | `${K}.${SubtreePaths<C[K]> & string}` : never }[keyof C & string] : never;
|
|
72
|
+
type ResolveNode<T> = T extends Obj ? IsConfigValPerEnv<T> extends true ? T extends {
|
|
73
|
+
[TYPE]: infer Tag extends TypeTag;
|
|
74
|
+
} ? TypeMap[Tag] : T extends {
|
|
75
|
+
[ENV]: any;
|
|
76
|
+
} | {
|
|
77
|
+
[DATA]: any;
|
|
78
|
+
} ? string : T extends ConfigValPerEnvPlain<infer D> ? ResolvedValue<D> : never : ResolvedConfig<T> : ResolvedValue<T>;
|
|
79
|
+
type ValueAtPath<C, P extends string> = P extends `${infer Head}.${infer Rest}` ? Head extends keyof C ? ValueAtPath<C[Head], Rest> : never : P extends keyof C ? ResolveNode<C[P]> : never;
|
|
80
|
+
interface FetcherContext<D = unknown> {
|
|
81
|
+
env: string;
|
|
82
|
+
default?: D;
|
|
35
83
|
envVar?: string;
|
|
84
|
+
data?: unknown;
|
|
85
|
+
type?: TypeTag;
|
|
36
86
|
}
|
|
37
|
-
|
|
87
|
+
type Fetcher<D = unknown, T = unknown> = (context: FetcherContext<D>) => Promise<T | undefined>;
|
|
88
|
+
interface ConfigEntry {
|
|
38
89
|
path: string;
|
|
39
|
-
|
|
90
|
+
value?: unknown;
|
|
91
|
+
default?: unknown;
|
|
40
92
|
envVar?: string;
|
|
41
93
|
data?: unknown;
|
|
94
|
+
type?: TypeTag;
|
|
42
95
|
}
|
|
43
96
|
type Confetti<C> = {
|
|
44
97
|
[CONFETTI]: "CONFETTI";
|
|
45
98
|
(env: string): {
|
|
46
99
|
config: C;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
resolveEnv: () => Promise<Obj<string>>;
|
|
100
|
+
get(): ResolvedConfig<C>;
|
|
101
|
+
get<P extends Paths<C> & string>(path: P): ValueAtPath<C, P>;
|
|
102
|
+
resolve(fetcher: Fetcher): Promise<ResolvedConfig<C>>;
|
|
103
|
+
resolve<P extends Paths<C> & string>(path: P, fetcher: Fetcher): Promise<ValueAtPath<C, P>>;
|
|
104
|
+
entries(startPath?: SubtreePaths<C> & string): IterableIterator<[string, ConfigEntry]>;
|
|
53
105
|
};
|
|
54
106
|
};
|
|
55
107
|
type GetConfig<T> = T extends Confetti<infer C> ? ResolvedConfig<C> : never;
|
|
56
108
|
//#endregion
|
|
57
109
|
//#region src/make-config.d.ts
|
|
58
|
-
declare const makeConfig: <C extends Config>(
|
|
110
|
+
declare const makeConfig: <const C extends Config>(input: (C & ValidateConfig<C>) | ((env: string) => C & ValidateConfig<C>)) => Confetti<C>;
|
|
59
111
|
//#endregion
|
|
60
112
|
//#region src/util.d.ts
|
|
61
113
|
declare const isObj: (val: unknown) => val is Obj;
|
|
62
114
|
declare const isConfigValPerEnv: (val: unknown) => val is ConfigValPerEnv;
|
|
115
|
+
declare const isNestedConfig: (val: unknown) => val is Obj;
|
|
63
116
|
declare const isConfetti: (val: unknown) => val is Confetti<any>;
|
|
64
|
-
declare const
|
|
65
|
-
declare const
|
|
117
|
+
declare const isThenable: (v: unknown) => v is PromiseLike<unknown>;
|
|
118
|
+
declare const getAtPath: (config: Obj, path: string) => unknown;
|
|
119
|
+
declare const coerceFromString: (raw: string, type: TypeTag, path: string) => unknown;
|
|
120
|
+
declare const buildEntry: (node: unknown, path: string, env: string) => ConfigEntry;
|
|
121
|
+
declare function entriesIter(config: Obj, env: string, pathPrefix?: string): IterableIterator<[string, ConfigEntry]>;
|
|
122
|
+
declare const invokeSync: (source: unknown, path: string, env: string) => unknown;
|
|
123
|
+
declare const invokeAsync: (source: unknown, env: string) => Promise<unknown>;
|
|
124
|
+
declare const resolveEntrySync: (entry: ConfigEntry, env: string) => unknown;
|
|
125
|
+
declare const resolveEntryAsync: (entry: ConfigEntry, env: string, fetcher: Fetcher) => Promise<unknown>;
|
|
126
|
+
declare const resolveSubtreeSync: (node: Obj, prefix: string, env: string) => Obj;
|
|
127
|
+
declare const resolveSubtreeAsync: (node: Obj, prefix: string, env: string, fetcher: Fetcher) => Promise<Obj>;
|
|
66
128
|
//#endregion
|
|
67
|
-
export { CONFETTI, Confetti, Config,
|
|
129
|
+
export { CONFETTI, Confetti, Config, ConfigEntry, ConfigVal, ConfigValFn, ConfigValPerEnv, ConfigValPerEnvFetcher, ConfigValPerEnvPlain, ConfigValPerEnvTyped, DATA, DEFAULT, ENV, Fetcher, FetcherContext, GetConfig, IsConfigValPerEnv, MaybeArray, Obj, Paths, Primitive, ResolvedConfig, ResolvedValue, SubtreePaths, TYPE, TypeMap, TypeTag, ValidateConfig, ValueAtPath, buildEntry, coerceFromString, entriesIter, getAtPath, invokeAsync, invokeSync, isConfetti, isConfigValPerEnv, isNestedConfig, isObj, isThenable, makeConfig, resolveEntryAsync, resolveEntrySync, resolveSubtreeAsync, resolveSubtreeSync };
|
|
68
130
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/symbols.ts","../src/types.ts","../src/make-config.ts","../src/util.ts"],"mappings":";cAAa,QAAA;AAAA,cACA,OAAA;AAAA,cACA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/symbols.ts","../src/types.ts","../src/make-config.ts","../src/util.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,121 +1,189 @@
|
|
|
1
1
|
//#region src/symbols.ts
|
|
2
2
|
const CONFETTI = Symbol.for("CONFETTI");
|
|
3
3
|
const DEFAULT = Symbol.for("CONFETTI_DEFAULT");
|
|
4
|
-
const
|
|
4
|
+
const ENV = Symbol.for("CONFETTI_ENV");
|
|
5
5
|
const DATA = Symbol.for("CONFETTI_DATA");
|
|
6
|
+
const TYPE = Symbol.for("CONFETTI_TYPE");
|
|
6
7
|
//#endregion
|
|
7
8
|
//#region src/util.ts
|
|
8
9
|
const isObj = (val) => {
|
|
9
10
|
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
10
11
|
};
|
|
11
12
|
const isConfigValPerEnv = (val) => {
|
|
12
|
-
return isObj(val) && (DEFAULT in val || DATA in val ||
|
|
13
|
+
return isObj(val) && (DEFAULT in val || DATA in val || ENV in val || TYPE in val);
|
|
14
|
+
};
|
|
15
|
+
const isNestedConfig = (val) => {
|
|
16
|
+
return isObj(val) && !isConfigValPerEnv(val);
|
|
13
17
|
};
|
|
14
18
|
const isConfetti = (val) => {
|
|
15
19
|
return typeof val === "function" && Object.hasOwn(val, CONFETTI);
|
|
16
20
|
};
|
|
17
|
-
const
|
|
18
|
-
return
|
|
19
|
-
const path = `${_currentPath}${key}`;
|
|
20
|
-
if (isObj(value)) {
|
|
21
|
-
if (isConfigValPerEnv(value)) {
|
|
22
|
-
let unresolvedValue;
|
|
23
|
-
if (value[ENV_VAR] && process.env[value[ENV_VAR]] !== void 0) try {
|
|
24
|
-
unresolvedValue = JSON.parse(process.env[value[ENV_VAR]]);
|
|
25
|
-
} catch {
|
|
26
|
-
unresolvedValue = process.env[value[ENV_VAR]];
|
|
27
|
-
}
|
|
28
|
-
else if (value[env] !== void 0) unresolvedValue = value[env];
|
|
29
|
-
else if (value[DEFAULT] !== void 0) unresolvedValue = value[DEFAULT];
|
|
30
|
-
if (unresolvedValue === void 0) throw new Error(`Unable to find '${env}' config value at '${path}`);
|
|
31
|
-
return map({
|
|
32
|
-
path,
|
|
33
|
-
unresolvedValue,
|
|
34
|
-
envVar: value[ENV_VAR],
|
|
35
|
-
data: value[DATA]
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return configFlatMap(env, value, map, `${path}.`);
|
|
39
|
-
}
|
|
40
|
-
return map({
|
|
41
|
-
path,
|
|
42
|
-
unresolvedValue: value
|
|
43
|
-
});
|
|
44
|
-
});
|
|
21
|
+
const isThenable = (v) => {
|
|
22
|
+
return v !== null && typeof v === "object" && "then" in v && typeof v.then === "function";
|
|
45
23
|
};
|
|
46
|
-
const
|
|
24
|
+
const getAtPath = (config, path) => {
|
|
25
|
+
if (!path) return config;
|
|
47
26
|
const segments = path.split(".");
|
|
48
|
-
let
|
|
49
|
-
for (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!isObj(objAtSeg[segment])) objAtSeg[segment] = {};
|
|
54
|
-
objAtSeg = objAtSeg[segment];
|
|
55
|
-
}
|
|
27
|
+
let node = config;
|
|
28
|
+
for (const segment of segments) {
|
|
29
|
+
if (!isNestedConfig(node)) throw new Error(`Invalid config path '${path}'.`);
|
|
30
|
+
node = node[segment];
|
|
31
|
+
if (node === void 0) throw new Error(`Invalid config path '${path}'.`);
|
|
56
32
|
}
|
|
33
|
+
return node;
|
|
34
|
+
};
|
|
35
|
+
const matchesType = (val, type) => {
|
|
36
|
+
if (type === "string") return typeof val === "string";
|
|
37
|
+
if (type === "number") return typeof val === "number" && !Number.isNaN(val);
|
|
38
|
+
if (type === "boolean") return typeof val === "boolean";
|
|
39
|
+
if (!Array.isArray(val)) return false;
|
|
40
|
+
const elem = type.slice(0, -2);
|
|
41
|
+
return val.every((x) => typeof x === elem);
|
|
42
|
+
};
|
|
43
|
+
const coerceFromString = (raw, type, path) => {
|
|
44
|
+
if (type === "string") return raw;
|
|
45
|
+
if (type === "number") {
|
|
46
|
+
if (raw === "") throw new Error(`Cannot coerce empty string to number at '${path}'.`);
|
|
47
|
+
const n = Number(raw);
|
|
48
|
+
if (Number.isNaN(n)) throw new Error(`Cannot coerce '${raw}' to number at '${path}'.`);
|
|
49
|
+
return n;
|
|
50
|
+
}
|
|
51
|
+
if (type === "boolean") {
|
|
52
|
+
if (raw === "true") return true;
|
|
53
|
+
if (raw === "false") return false;
|
|
54
|
+
throw new Error(`Cannot coerce '${raw}' to boolean at '${path}' (expected 'true' or 'false').`);
|
|
55
|
+
}
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(raw);
|
|
59
|
+
} catch {
|
|
60
|
+
throw new Error(`Cannot coerce '${raw}' to ${type} at '${path}' (invalid JSON).`);
|
|
61
|
+
}
|
|
62
|
+
if (!Array.isArray(parsed)) throw new Error(`Cannot coerce '${raw}' to ${type} at '${path}' (not an array).`);
|
|
63
|
+
const elem = type.slice(0, -2);
|
|
64
|
+
if (!parsed.every((x) => typeof x === elem)) throw new Error(`Cannot coerce '${raw}' to ${type} at '${path}' (element type mismatch).`);
|
|
65
|
+
return parsed;
|
|
66
|
+
};
|
|
67
|
+
const coerceFetched = (fetched, type, path) => {
|
|
68
|
+
if (type === void 0) {
|
|
69
|
+
if (typeof fetched !== "string") throw new Error(`Fetcher for '${path}' must return a string (add [TYPE] to use non-string values).`);
|
|
70
|
+
return fetched;
|
|
71
|
+
}
|
|
72
|
+
if (typeof fetched === "string") return coerceFromString(fetched, type, path);
|
|
73
|
+
if (matchesType(fetched, type)) return fetched;
|
|
74
|
+
throw new Error(`Fetcher for '${path}' returned value that doesn't match [TYPE] '${type}'.`);
|
|
75
|
+
};
|
|
76
|
+
const buildEntry = (node, path, env) => {
|
|
77
|
+
if (!isConfigValPerEnv(node)) return {
|
|
78
|
+
path,
|
|
79
|
+
value: node
|
|
80
|
+
};
|
|
81
|
+
const envVar = node[ENV];
|
|
82
|
+
const data = node[DATA];
|
|
83
|
+
const defaultVal = node[DEFAULT];
|
|
84
|
+
const typeTag = node[TYPE];
|
|
85
|
+
const entry = { path };
|
|
86
|
+
if (envVar && process.env[envVar] !== void 0) {
|
|
87
|
+
const raw = process.env[envVar];
|
|
88
|
+
entry.value = typeTag ? coerceFromString(raw, typeTag, path) : raw;
|
|
89
|
+
} else if (node[env] !== void 0) entry.value = node[env];
|
|
90
|
+
if (defaultVal !== void 0) entry.default = defaultVal;
|
|
91
|
+
if (envVar) entry.envVar = envVar;
|
|
92
|
+
if (data !== void 0) entry.data = data;
|
|
93
|
+
if (typeTag !== void 0) entry.type = typeTag;
|
|
94
|
+
return entry;
|
|
95
|
+
};
|
|
96
|
+
function* entriesIter(config, env, pathPrefix = "") {
|
|
97
|
+
for (const [key, value] of Object.entries(config)) {
|
|
98
|
+
const path = pathPrefix + key;
|
|
99
|
+
if (isNestedConfig(value)) yield* entriesIter(value, env, `${path}.`);
|
|
100
|
+
else yield [path, buildEntry(value, path, env)];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const invokeSync = (source, path, env) => {
|
|
104
|
+
if (typeof source !== "function") return source;
|
|
105
|
+
const result = source(env);
|
|
106
|
+
if (isThenable(result)) throw new Error(`Config at '${path}' requires async resolution (use resolve).`);
|
|
107
|
+
return result;
|
|
108
|
+
};
|
|
109
|
+
const invokeAsync = async (source, env) => {
|
|
110
|
+
return typeof source === "function" ? await source(env) : source;
|
|
111
|
+
};
|
|
112
|
+
const resolveEntrySync = (entry, env) => {
|
|
113
|
+
if ("value" in entry) return invokeSync(entry.value, entry.path, env);
|
|
114
|
+
if ("default" in entry) return invokeSync(entry.default, entry.path, env);
|
|
115
|
+
throw new Error(`Config at '${entry.path}' requires async resolution (use resolve).`);
|
|
116
|
+
};
|
|
117
|
+
const resolveEntryAsync = async (entry, env, fetcher) => {
|
|
118
|
+
if ("value" in entry) return invokeAsync(entry.value, env);
|
|
119
|
+
if (entry.envVar !== void 0 || entry.data !== void 0) {
|
|
120
|
+
const fetched = await fetcher({
|
|
121
|
+
env,
|
|
122
|
+
default: entry.default,
|
|
123
|
+
envVar: entry.envVar,
|
|
124
|
+
data: entry.data,
|
|
125
|
+
type: entry.type
|
|
126
|
+
});
|
|
127
|
+
if (fetched !== void 0) return coerceFetched(fetched, entry.type, entry.path);
|
|
128
|
+
}
|
|
129
|
+
if ("default" in entry) return invokeAsync(entry.default, env);
|
|
130
|
+
throw new Error(`Unable to resolve config value at '${entry.path}'.`);
|
|
131
|
+
};
|
|
132
|
+
const resolveSubtreeSync = (node, prefix, env) => {
|
|
133
|
+
const result = {};
|
|
134
|
+
for (const [key, child] of Object.entries(node)) {
|
|
135
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
136
|
+
result[key] = isNestedConfig(child) ? resolveSubtreeSync(child, path, env) : resolveEntrySync(buildEntry(child, path, env), env);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
};
|
|
140
|
+
const resolveSubtreeAsync = async (node, prefix, env, fetcher) => {
|
|
141
|
+
const keys = Object.keys(node);
|
|
142
|
+
const values = await Promise.all(keys.map((key) => {
|
|
143
|
+
const child = node[key];
|
|
144
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
145
|
+
return isNestedConfig(child) ? resolveSubtreeAsync(child, path, env, fetcher) : resolveEntryAsync(buildEntry(child, path, env), env, fetcher);
|
|
146
|
+
}));
|
|
147
|
+
const result = {};
|
|
148
|
+
keys.forEach((key, i) => {
|
|
149
|
+
result[key] = values[i];
|
|
150
|
+
});
|
|
151
|
+
return result;
|
|
57
152
|
};
|
|
58
153
|
//#endregion
|
|
59
154
|
//#region src/make-config.ts
|
|
60
|
-
const makeConfig = (
|
|
155
|
+
const makeConfig = (input) => {
|
|
156
|
+
const factory = typeof input === "function" ? input : () => input;
|
|
61
157
|
const confetti = (env) => {
|
|
62
|
-
const config =
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (!context) throw new Error(`Invalid config path '${path}'.`);
|
|
68
|
-
const { unresolvedValue } = context;
|
|
69
|
-
const value = typeof unresolvedValue === "function" ? await unresolvedValue(context) : unresolvedValue;
|
|
70
|
-
if (value === void 0) throw new Error(`Config value at '${path}' resolved to undefined.`);
|
|
71
|
-
return value;
|
|
72
|
-
};
|
|
73
|
-
const resolveValueSync = (path) => {
|
|
74
|
-
const context = contextByPath[path];
|
|
75
|
-
if (!context) throw new Error(`Invalid config path '${path}'.`);
|
|
76
|
-
const { unresolvedValue } = context;
|
|
77
|
-
if (typeof unresolvedValue === "function") throw new Error(`Cannot resolve config value at "${path}" synchronously.`);
|
|
78
|
-
return unresolvedValue;
|
|
79
|
-
};
|
|
80
|
-
const resolve = async () => {
|
|
81
|
-
const resolvedConfig = {};
|
|
82
|
-
const promises = Object.keys(contextByPath).map(async (path) => {
|
|
83
|
-
return resolveValue(path).then((resolvedValue) => setAtPath(resolvedConfig, path, resolvedValue));
|
|
84
|
-
});
|
|
85
|
-
await Promise.all(promises);
|
|
86
|
-
return resolvedConfig;
|
|
158
|
+
const config = factory(env);
|
|
159
|
+
const get = (path) => {
|
|
160
|
+
if (!path) return resolveSubtreeSync(config, "", env);
|
|
161
|
+
const node = getAtPath(config, path);
|
|
162
|
+
return isNestedConfig(node) ? resolveSubtreeSync(node, path, env) : resolveEntrySync(buildEntry(node, path, env), env);
|
|
87
163
|
};
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
164
|
+
const resolve = async (pathOrFetcher, maybeFetcher) => {
|
|
165
|
+
if (typeof pathOrFetcher === "function") return resolveSubtreeAsync(config, "", env, pathOrFetcher);
|
|
166
|
+
const path = pathOrFetcher;
|
|
167
|
+
const fetcher = maybeFetcher;
|
|
168
|
+
const node = getAtPath(config, path);
|
|
169
|
+
return isNestedConfig(node) ? resolveSubtreeAsync(node, path, env, fetcher) : resolveEntryAsync(buildEntry(node, path, env), env, fetcher);
|
|
92
170
|
};
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (!envVar) return [];
|
|
98
|
-
return resolveValue(context.path).then((resolvedValue) => {
|
|
99
|
-
envVars[envVar] = JSON.stringify(resolvedValue);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
await Promise.all(promises);
|
|
103
|
-
return envVars;
|
|
171
|
+
const entries = (startPath) => {
|
|
172
|
+
const root = startPath ? getAtPath(config, startPath) : config;
|
|
173
|
+
if (!isNestedConfig(root)) throw new Error(`'${startPath}' is not a config subtree.`);
|
|
174
|
+
return entriesIter(root, env, startPath ? `${startPath}.` : "");
|
|
104
175
|
};
|
|
105
176
|
return {
|
|
106
177
|
config,
|
|
107
|
-
|
|
108
|
-
resolveValue,
|
|
109
|
-
resolveValueSync,
|
|
178
|
+
get,
|
|
110
179
|
resolve,
|
|
111
|
-
|
|
112
|
-
resolveEnv
|
|
180
|
+
entries
|
|
113
181
|
};
|
|
114
182
|
};
|
|
115
183
|
confetti[CONFETTI] = "CONFETTI";
|
|
116
184
|
return confetti;
|
|
117
185
|
};
|
|
118
186
|
//#endregion
|
|
119
|
-
export { CONFETTI, DATA, DEFAULT,
|
|
187
|
+
export { CONFETTI, DATA, DEFAULT, ENV, TYPE, buildEntry, coerceFromString, entriesIter, getAtPath, invokeAsync, invokeSync, isConfetti, isConfigValPerEnv, isNestedConfig, isObj, isThenable, makeConfig, resolveEntryAsync, resolveEntrySync, resolveSubtreeAsync, resolveSubtreeSync };
|
|
120
188
|
|
|
121
189
|
//# sourceMappingURL=index.mjs.map
|