Skip to content

Commit 7bb316c

Browse files
Fixed issue with optional schemas (#9)
1 parent c262e5e commit 7bb316c

File tree

5 files changed

+78
-9
lines changed

5 files changed

+78
-9
lines changed

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { cwd } from 'process'
22
import path from 'node:path'
3-
import { type Plugin, loadEnv, normalizePath } from 'vite'
3+
import { type ConfigEnv, type Plugin, type UserConfig, loadEnv, normalizePath } from 'vite'
44
import { createConfigLoader as createLoader } from 'unconfig'
55
import { builtinValidation } from './validators/builtin'
66
import { zodValidation } from './validators/zod'
77
import type { FullPluginOptions, PluginOptions, Schema } from './contracts'
8-
import type { ConfigEnv, UserConfig } from 'vite'
98

109
/**
1110
* Load schema defined in `env.ts` file using unconfig

src/validators/builtin/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ export function builtinValidation(env: Record<string, string>, schema: PoppinsSc
2424
for (const [key, validator] of Object.entries(schema!)) {
2525
try {
2626
const res = validator(key, env[key])
27+
28+
// Handle undefined aka optional results
29+
if (typeof res === 'undefined') {
30+
delete process.env[key]
31+
return
32+
}
33+
2734
process.env[key] = res
2835
} catch (err) {
2936
errors.push({ key, err })

src/validators/zod/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ export async function zodValidation(env: Record<string, string>, schema: ZodSche
2929
continue
3030
}
3131

32+
// Handle undefined aka optional results
33+
if (typeof result.data === 'undefined') {
34+
delete process.env[key]
35+
return
36+
}
37+
3238
process.env[key] = result.data
3339
}
3440

tests/common.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,28 @@ test.group('vite-plugin-validate-env', (group) => {
167167
assert.include(error.message, 'Missing environment variable "VITE_TEST2"')
168168
}
169169
})
170+
171+
test('Optional Variables', async ({ assert }) => {
172+
// assert.plan(2);
173+
174+
const plugin = ValidateEnv({ VITE_OPTIONAL: Schema.number.optional() })
175+
176+
// Test with the variable set, but invalid
177+
await fs.add('.env.development', 'VITE_OPTIONAL=not a number')
178+
try {
179+
// @ts-ignore
180+
await plugin.config(viteConfig, viteEnvConfig)
181+
} catch (error: any) {
182+
assert.include(
183+
error.message,
184+
'Value for environment variable "VITE_OPTIONAL" must be numeric, instead received'
185+
)
186+
}
187+
188+
// Test without variable
189+
await fs.add('.env.development', '')
190+
// @ts-ignore
191+
await plugin.config(viteConfig, viteEnvConfig)
192+
assert.equal(process.env.VITE_OPTIONAL, undefined)
193+
})
170194
})

tests/zod.spec.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ const fs = new Filesystem(join(__dirname, 'fixtures'))
1111
const viteConfig = { root: fs.basePath }
1212
const viteEnvConfig = { mode: 'development', command: 'serve' } as const
1313

14-
test.group('Zod validation adaptater', () => {
14+
const ENV_FILENAME = '.env.development'
15+
16+
test.group('Zod validation adaptater', (group) => {
17+
group.each.teardown(async () => {
18+
await fs.cleanup()
19+
})
20+
1521
test('Basic', async ({ assert }) => {
1622
assert.plan(1)
1723

@@ -20,7 +26,7 @@ test.group('Zod validation adaptater', () => {
2026
schema: { VITE_TEST: z.string().url().max(10) },
2127
})
2228

23-
await fs.add(`.env.development`, `VITE_TEST=htest`)
29+
await fs.add(ENV_FILENAME, 'VITE_TEST=htest')
2430

2531
try {
2632
// @ts-ignore
@@ -41,9 +47,9 @@ test.group('Zod validation adaptater', () => {
4147
},
4248
})
4349

44-
await fs.add(`.env.development`, `VITE_TEST=hello`)
50+
await fs.add(ENV_FILENAME, 'VITE_TEST=hello')
4551

46-
// @ts-expect-error - `config` is the handler
52+
// @ts-expect-error - 'config' is the handler
4753
await plugin.config!(viteConfig, viteEnvConfig)
4854
assert.equal(process.env.VITE_TEST, 'HELLO')
4955
})
@@ -58,7 +64,7 @@ test.group('Zod validation adaptater', () => {
5864
},
5965
})
6066

61-
await fs.add(`.env.development`, `VITE_LONG_STRING=superlongstring`)
67+
await fs.add(ENV_FILENAME, 'VITE_LONG_STRING=superlongstring')
6268

6369
try {
6470
// @ts-ignore
@@ -80,7 +86,7 @@ test.group('Zod validation adaptater', () => {
8086
},
8187
})
8288

83-
await fs.add(`.env.development`, `VITE_REFINED=superlongstring`)
89+
await fs.add(ENV_FILENAME, 'VITE_REFINED=superlongstring')
8490

8591
try {
8692
// @ts-ignore
@@ -101,7 +107,7 @@ test.group('Zod validation adaptater', () => {
101107
},
102108
})
103109

104-
await fs.add(`.env.development`, ``)
110+
await fs.add(ENV_FILENAME, '')
105111

106112
try {
107113
// @ts-ignore
@@ -111,4 +117,31 @@ test.group('Zod validation adaptater', () => {
111117
assert.include(error.message, 'Invalid value for "VITE_B" : Required')
112118
}
113119
})
120+
121+
test('Optional Variables', async ({ assert }) => {
122+
assert.plan(2)
123+
124+
const plugin = ValidateEnv({
125+
validator: 'zod',
126+
schema: { VITE_OPTIONAL_ZOD: z.string().max(2).optional() },
127+
})
128+
129+
// Test with the variable set, but invalid
130+
await fs.add(ENV_FILENAME, 'VITE_OPTIONAL_ZOD=hello')
131+
try {
132+
// @ts-ignore
133+
await plugin.config(viteConfig, viteEnvConfig)
134+
} catch (error: any) {
135+
assert.include(
136+
error.message,
137+
'Invalid value for "VITE_OPTIONAL_ZOD" : String must contain at most 2 character(s)'
138+
)
139+
}
140+
141+
// Test without variable
142+
await fs.add(ENV_FILENAME, '')
143+
// @ts-ignore
144+
await plugin.config(viteConfig, viteEnvConfig)
145+
assert.equal(process.env.VITE_OPTIONAL_ZOD, undefined)
146+
})
114147
})

0 commit comments

Comments
 (0)