@@ -213,12 +213,14 @@ export class Config {
213
213
214
214
get serverExtraEnv ( ) : Env {
215
215
const extraEnv =
216
- this . get < { [ key : string ] : string | number } | null > ( "server.extraEnv" ) ?? { } ;
216
+ this . get < { [ key : string ] : { toString ( ) : string } | null } | null > (
217
+ "server.extraEnv" ,
218
+ ) ?? { } ;
217
219
return substituteVariablesInEnv (
218
220
Object . fromEntries (
219
221
Object . entries ( extraEnv ) . map ( ( [ k , v ] ) => [
220
222
k ,
221
- typeof v !== "string" ? v . toString ( ) : v ,
223
+ typeof v === "string" ? v : v ?. toString ( ) ,
222
224
] ) ,
223
225
) ,
224
226
) ;
@@ -398,22 +400,24 @@ export function prepareVSCodeConfig<T>(resp: T): T {
398
400
399
401
// FIXME: Merge this with `substituteVSCodeVariables` above
400
402
export function substituteVariablesInEnv ( env : Env ) : Env {
403
+ const depRe = new RegExp ( / \$ { (?< depName > .+ ?) } / g) ;
401
404
const missingDeps = new Set < string > ( ) ;
402
405
// vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
403
406
// to follow the same convention for our dependency tracking
404
407
const definedEnvKeys = new Set ( Object . keys ( env ) . map ( ( key ) => `env:${ key } ` ) ) ;
405
408
const envWithDeps = Object . fromEntries (
406
409
Object . entries ( env ) . map ( ( [ key , value ] ) => {
407
410
const deps = new Set < string > ( ) ;
408
- const depRe = new RegExp ( / \$ { (?< depName > .+ ?) } / g) ;
409
- let match = undefined ;
410
- while ( ( match = depRe . exec ( value ) ) ) {
411
- const depName = unwrapUndefinable ( match . groups ?. [ "depName" ] ) ;
412
- deps . add ( depName ) ;
413
- // `depName` at this point can have a form of `expression` or
414
- // `prefix:expression`
415
- if ( ! definedEnvKeys . has ( depName ) ) {
416
- missingDeps . add ( depName ) ;
411
+ if ( value ) {
412
+ let match = undefined ;
413
+ while ( ( match = depRe . exec ( value ) ) ) {
414
+ const depName = unwrapUndefinable ( match . groups ?. [ "depName" ] ) ;
415
+ deps . add ( depName ) ;
416
+ // `depName` at this point can have a form of `expression` or
417
+ // `prefix:expression`
418
+ if ( ! definedEnvKeys . has ( depName ) ) {
419
+ missingDeps . add ( depName ) ;
420
+ }
417
421
}
418
422
}
419
423
return [ `env:${ key } ` , { deps : [ ...deps ] , value } ] ;
@@ -454,12 +458,12 @@ export function substituteVariablesInEnv(env: Env): Env {
454
458
do {
455
459
leftToResolveSize = toResolve . size ;
456
460
for ( const key of toResolve ) {
457
- const item = unwrapUndefinable ( envWithDeps [ key ] ) ;
458
- if ( item . deps . every ( ( dep ) => resolved . has ( dep ) ) ) {
459
- item . value = item . value . replace ( / \$ { (?< depName > . + ? ) } / g , ( _wholeMatch , depName ) => {
460
- const item = unwrapUndefinable ( envWithDeps [ depName ] ) ;
461
- return item . value ;
462
- } ) ;
461
+ const item = envWithDeps [ key ] ;
462
+ if ( item && item . deps . every ( ( dep ) => resolved . has ( dep ) ) ) {
463
+ item . value =
464
+ item . value ?. replace ( / \$ { (?< depName > . + ? ) } / g , ( _wholeMatch , depName ) => {
465
+ return envWithDeps [ depName ] ? .value ?? "" ;
466
+ } ) ;
463
467
resolved . add ( key ) ;
464
468
toResolve . delete ( key ) ;
465
469
}
0 commit comments