@@ -195,19 +195,40 @@ export namespace Config {
195195 return result
196196 } )
197197
198- async function load ( path : string ) {
199- const data = await Bun . file ( path )
200- . json ( )
198+ async function load ( configPath : string ) {
199+ let text = await Bun . file ( configPath )
200+ . text ( )
201201 . catch ( ( err ) => {
202- if ( err . code === "ENOENT" ) return { }
203- throw new JsonError ( { path } , { cause : err } )
202+ if ( err . code === "ENOENT" ) return "{}"
203+ throw new JsonError ( { path : configPath } , { cause : err } )
204204 } )
205205
206+ text = text . replace ( / \{ e n v : ( [ ^ } ] + ) \} / g, ( _ , varName ) => {
207+ return process . env [ varName ] || ""
208+ } )
209+
210+ const fileMatches = text . match ( / \{ f i l e : ( [ ^ } ] + ) \} / g)
211+ if ( fileMatches ) {
212+ const configDir = path . dirname ( configPath )
213+ for ( const match of fileMatches ) {
214+ const filePath = match . slice ( 6 , - 1 )
215+ const resolvedPath = path . isAbsolute ( filePath ) ? filePath : path . resolve ( configDir , filePath )
216+ const fileContent = await Bun . file ( resolvedPath ) . text ( )
217+ text = text . replace ( match , fileContent )
218+ }
219+ }
220+
221+ let data : any
222+ try {
223+ data = JSON . parse ( text )
224+ } catch ( err ) {
225+ throw new JsonError ( { path : configPath } , { cause : err as Error } )
226+ }
227+
206228 const parsed = Info . safeParse ( data )
207229 if ( parsed . success ) return parsed . data
208- throw new InvalidError ( { path, issues : parsed . error . issues } )
230+ throw new InvalidError ( { path : configPath , issues : parsed . error . issues } )
209231 }
210-
211232 export const JsonError = NamedError . create (
212233 "ConfigJsonError" ,
213234 z . object ( {
0 commit comments