13
*/
14
export function parseEnvFile(src: string) {
15
>
const result = new Map<string, string>();
envfile.ts
16
>
17
>
// Normalize line breaks
18
>
const normalizedSrc = src.replace(/\r\n?/g, '\n');
19
>
const lines = normalizedSrc.split('\n');
20
>
21
>
for (let line of lines) {
22
>
// Skip empty lines and comments
23
>
line = line.trim();
24
>
if (!line || line.startsWith('#')) {
25
>
continue;
26
>
}
27
>
28
>
// Parse the line into key and value
29
>
const [key, value] = parseLine(line);
30
>
if (key) {
31
>
result.set(key, value);
32
>
}
33
>
}
34
>
35
>
return result;
36
>
37
>
function parseLine(line: string): [string, string] | [null, null] {
38
>
// Handle export prefix
39
>
if (line.startsWith('export ')) {
40
line = line.substring(7).trim();
41
}
43
>
// Find the key-value separator
44
>
const separatorIndex = findIndexOutsideQuotes(line, c => c === '=' || c === ':');
45
>
if (separatorIndex === -1) {
46
return [null, null];
47
}
49
>
const key = line.substring(0, separatorIndex).trim();
50
>
let value = line.substring(separatorIndex + 1).trim();
51
>
52
>
// Handle comments and remove them
53
>
const commentIndex = findIndexOutsideQuotes(value, c => c === '#');
54
>
if (commentIndex !== -1) {
55
>
value = value.substring(0, commentIndex).trim();
56
>
}
57
>
58
>
// Process quoted values
59
>
if (value.length >= 2) {
60
>
const firstChar = value[0];
61
>
const lastChar = value[value.length - 1];
62
>
63
>
if ((firstChar === '"' && lastChar === '"') ||
64
>
(firstChar === '\'' && lastChar === '\'') ||
65
>
(firstChar === '`' && lastChar === '`')) {
66
>
// Remove surrounding quotes
67
>
value = value.substring(1, value.length - 1);
68
>
69
>
// Handle escaped characters in double quotes
70
>
if (firstChar === '"') {
71
>
value = value.replace(/\\n/g, '\n').replace(/\\r/g, '\r');
72
>
}
73
>
}
74
>
}
75
>
76
>
return [key, value];
77
>
}
78
>
79
>
function findIndexOutsideQuotes(text: string, predicate: (char: string) => boolean): number {
80
>
let inQuote = false;
81
>
let quoteChar = '';
82
>
83
>
for (let i = 0; i < text.length; i++) {
84
>
const char = text[i];
85
>
86
>
if (inQuote) {
87
>
if (char === quoteChar && text[i - 1] !== '\\') {
88
>
inQuote = false;
89
>
}
90
>
} else if (char === '"' || char === '\'' || char === '`') {
91
>
inQuote = true;
92
>
quoteChar = char;
93
>
} else if (predicate(char)) {
94
>
return i;
95
>
}
96
>
}
97
>
98
>
return -1;
99
>
}
100
>
}