Skip to content

Commit 526ce63

Browse files
authored
feat(parser): rename identifier to defineIdentifier and add IfMissingDefineIdentifier
feat(parser): rename identifier to defineIdentifier and add IfMissing…
1 parent 92d406c commit 526ce63

File tree

4 files changed

+155
-3
lines changed

4 files changed

+155
-3
lines changed

src/env.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,34 @@ export class Env<EnvValues extends Record<string, any>> {
5858
/**
5959
* Define an identifier for any environment value. The callback is invoked
6060
* when the value match the identifier to modify its interpolation.
61+
*
62+
* @deprecated use `Env.defineIdentifier` instead
6163
*/
6264
static identifier(name: string, callback: (value: string) => Promise<string> | string): void {
63-
EnvParser.identifier(name, callback)
65+
return EnvParser.defineIdentifier(name, callback)
66+
}
67+
68+
/**
69+
* Define an identifier for any environment value. The callback is invoked
70+
* when the value match the identifier to modify its interpolation.
71+
*/
72+
static defineIdentifier(
73+
name: string,
74+
callback: (value: string) => Promise<string> | string
75+
): void {
76+
EnvParser.defineIdentifier(name, callback)
77+
}
78+
79+
/**
80+
* Define an identifier for any environment value, if it's not already defined.
81+
* The callback is invoked when the value match the identifier to modify its
82+
* interpolation.
83+
*/
84+
static defineIdentifierIfMissing(
85+
name: string,
86+
callback: (value: string) => Promise<string> | string
87+
): void {
88+
EnvParser.defineIdentifierIfMissing(name, callback)
6489
}
6590

6691
/**

src/parser.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,42 @@ export class EnvParser {
6666
/**
6767
* Define an identifier for any environment value. The callback is invoked
6868
* when the value match the identifier to modify its interpolation.
69+
*
70+
* @deprecated use `EnvParser.defineIdentifier` instead
6971
*/
7072
static identifier(name: string, callback: (value: string) => Promise<string> | string): void {
73+
EnvParser.defineIdentifier(name, callback)
74+
}
75+
76+
/**
77+
* Define an identifier for any environment value. The callback is invoked
78+
* when the value match the identifier to modify its interpolation.
79+
*/
80+
static defineIdentifier(
81+
name: string,
82+
callback: (value: string) => Promise<string> | string
83+
): void {
7184
if (this.#identifiers[name]) {
7285
throw new E_IDENTIFIER_ALREADY_DEFINED([name])
7386
}
7487

7588
this.#identifiers[name] = callback
7689
}
7790

91+
/**
92+
* Define an identifier for any environment value, if it's not already defined.
93+
* The callback is invoked when the value match the identifier to modify its
94+
* interpolation.
95+
*/
96+
static defineIdentifierIfMissing(
97+
name: string,
98+
callback: (value: string) => Promise<string> | string
99+
): void {
100+
if (typeof this.#identifiers[name] === 'undefined') {
101+
this.#identifiers[name] = callback
102+
}
103+
}
104+
78105
/**
79106
* Remove an identifier
80107
*/

tests/env.spec.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,64 @@ test.group('Env', (group) => {
2121

2222
cleanup(() => {
2323
Env.removeIdentifier('file')
24+
delete process.env.PORT
25+
})
26+
27+
Env.defineIdentifier('file', (_value: string) => {
28+
assert.isTrue(true)
29+
30+
return '3000'
31+
})
32+
33+
await fs.create('.env', 'PORT=file:romain')
34+
await Env.create(fs.baseUrl, {
35+
PORT: Env.schema.number(),
36+
})
37+
})
38+
39+
test('throw exception when identifier is already defined', async ({ assert, cleanup }) => {
40+
assert.plan(1)
41+
42+
cleanup(() => {
43+
Env.removeIdentifier('file')
44+
delete process.env.PORT
2445
})
2546

26-
Env.identifier('file', (_value: string) => {
47+
Env.defineIdentifier('file', (_value: string) => {
48+
return '3000'
49+
})
50+
51+
assert.throws(
52+
() =>
53+
Env.defineIdentifier('file', (_value: string) => {
54+
return '3000'
55+
}),
56+
'The identifier "file" is already defined'
57+
)
58+
})
59+
60+
test('silently ignore when adding the same identifier with IfMissing variant', async ({
61+
assert,
62+
cleanup,
63+
fs,
64+
}) => {
65+
assert.plan(1)
66+
67+
cleanup(() => {
68+
Env.removeIdentifier('file')
69+
delete process.env.PORT
70+
})
71+
72+
Env.defineIdentifier('file', (_value: string) => {
2773
assert.isTrue(true)
2874

2975
return '3000'
3076
})
3177

78+
Env.defineIdentifierIfMissing('file', (_value: string) => {
79+
return '3000'
80+
})
81+
3282
await fs.create('.env', 'PORT=file:romain')
3383
await Env.create(fs.baseUrl, {
3484
PORT: Env.schema.number(),

tests/parser.spec.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,57 @@ test.group('Env Parser', () => {
5858
EnvParser.removeIdentifier('file')
5959
})
6060

61-
EnvParser.identifier('file', (_value: string) => {
61+
EnvParser.defineIdentifier('file', (_value: string) => {
62+
return '3000'
63+
})
64+
65+
const envString = ['ENV_USER=file:romain'].join('\n')
66+
const parser = new EnvParser(envString)
67+
const parsed = await parser.parse()
68+
69+
expectTypeOf(parsed).toEqualTypeOf<DotenvParseOutput>()
70+
assert.deepEqual(parsed, {
71+
ENV_USER: '3000',
72+
})
73+
})
74+
75+
test('throw exception when identifier is already defined', async ({ assert, cleanup }) => {
76+
cleanup(() => {
77+
EnvParser.removeIdentifier('file')
78+
})
79+
80+
EnvParser.defineIdentifier('file', (_value: string) => {
81+
return '3000'
82+
})
83+
84+
assert.throws(
85+
() =>
86+
EnvParser.defineIdentifier('file', (_value: string) => {
87+
return '3000'
88+
}),
89+
'The identifier "file" is already defined'
90+
)
91+
})
92+
93+
test('silently ignore when adding the same identifier with IfMissing variant', async ({
94+
assert,
95+
cleanup,
96+
expectTypeOf,
97+
}) => {
98+
assert.plan(2)
99+
100+
cleanup(() => {
101+
EnvParser.removeIdentifier('file')
102+
})
103+
104+
EnvParser.defineIdentifier('file', (_value: string) => {
105+
console.log('Never called')
106+
assert.isTrue(true)
107+
108+
return '3000'
109+
})
110+
111+
EnvParser.defineIdentifierIfMissing('file', (_value: string) => {
62112
return '3000'
63113
})
64114

0 commit comments

Comments
 (0)