11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4+ import * as dotenv from 'dotenv' ;
45import * as fsapi from 'fs-extra' ;
56import * as path from 'path' ;
67import { Disposable , env , l10n , LanguageStatusSeverity , LogOutputChannel , Uri } from 'vscode' ;
@@ -21,51 +22,6 @@ import { getConfiguration } from './vscodeapi';
2122
2223export type IInitOptions = { settings : ISettings [ ] ; globalSettings : ISettings } ;
2324
24- /**
25- * Parses a .env file and returns a record of environment variables.
26- * Supports KEY=VALUE, KEY="VALUE", KEY='VALUE', comments (#), and empty lines.
27- *
28- * Limitations: no multi-line values, no variable interpolation, no escaped quotes.
29- */
30- function parseEnvFile ( content : string ) : Record < string , string > {
31- const env : Record < string , string > = { } ;
32- for ( const line of content . split ( / \r ? \n / ) ) {
33- const trimmed = line . trim ( ) ;
34- if ( ! trimmed || trimmed . startsWith ( '#' ) ) {
35- continue ;
36- }
37- const eqIndex = trimmed . indexOf ( '=' ) ;
38- if ( eqIndex < 0 ) {
39- continue ;
40- }
41- const key = trimmed
42- . substring ( 0 , eqIndex )
43- . trim ( )
44- . replace ( / ^ e x p o r t \s + / , '' ) ;
45- let value = trimmed . substring ( eqIndex + 1 ) . trim ( ) ;
46- // Strip inline comments for unquoted values
47- if ( ! value . startsWith ( '"' ) && ! value . startsWith ( "'" ) ) {
48- const commentIndex = value . indexOf ( ' #' ) ;
49- if ( commentIndex !== - 1 ) {
50- value = value . substring ( 0 , commentIndex ) . trimEnd ( ) ;
51- }
52- }
53- // Strip surrounding quotes
54- if ( ( value . startsWith ( '"' ) && value . endsWith ( '"' ) ) || ( value . startsWith ( "'" ) && value . endsWith ( "'" ) ) ) {
55- value = value . slice ( 1 , - 1 ) ;
56- }
57- if ( key ) {
58- env [ key ] = value ;
59- }
60- }
61- return env ;
62- }
63-
64- /**
65- * Reads environment variables from the configured python.envFile (defaults
66- * to `${workspaceFolder}/.env`). Returns an empty record when the file
67- * does not exist or cannot be read.
68- */
6925async function loadEnvFile ( workspacePath : string ) : Promise < Record < string , string > > {
7026 try {
7127 const pythonConfig = getConfiguration ( 'python' , Uri . file ( workspacePath ) ) ;
@@ -74,7 +30,7 @@ async function loadEnvFile(workspacePath: string): Promise<Record<string, string
7430
7531 if ( await fsapi . pathExists ( envFilePath ) ) {
7632 const content = await fsapi . readFile ( envFilePath , 'utf-8' ) ;
77- const envVars = parseEnvFile ( content ) ;
33+ const envVars = dotenv . parse ( content ) ;
7834 const count = Object . keys ( envVars ) . length ;
7935 if ( count > 0 ) {
8036 traceInfo ( `Loaded ${ count } environment variable(s) from ${ envFilePath } ` ) ;
@@ -97,7 +53,7 @@ async function loadEnvFile(workspacePath: string): Promise<Record<string, string
9753 */
9854export function getServerCwd ( settings : ISettings ) : string {
9955 const hasFileVariable = / \$ \{ ( f i l e | r e l a t i v e F i l e ) / . test ( settings . cwd ) ;
100- return hasFileVariable ? Uri . file ( settings . workspace ) . fsPath : settings . cwd ;
56+ return hasFileVariable ? Uri . parse ( settings . workspace ) . fsPath : settings . cwd ;
10157}
10258
10359async function createServer (
@@ -114,7 +70,7 @@ async function createServer(
11470 const newEnv = { ...process . env } ;
11571
11672 // Load environment variables from python.envFile (.env)
117- const workspacePath = Uri . file ( settings . workspace ) . fsPath ;
73+ const workspacePath = Uri . parse ( settings . workspace ) . fsPath ;
11874 const envFileVars = await loadEnvFile ( workspacePath ) ;
11975 for ( const [ key , val ] of Object . entries ( envFileVars ) ) {
12076 if ( ( key === 'PYTHONPATH' || key === 'PATH' ) && newEnv [ key ] ) {
0 commit comments