| | | 1 | | /** |
| | | 2 | | * dotenv's `LINE` grammar and `parse`, copied from dotenv 17 with two changes. |
| | | 3 | | * The key class also admits `/`, the hierarchy separator map files use |
| | | 4 | | * (`Database/Password`). dotenv skips such a line, so reading the files we |
| | | 5 | | * write through it would lose those keys, both when merging into an existing |
| | | 6 | | * file and when checking the result before it reaches disk. |
| | | 7 | | * |
| | | 8 | | * And the blanks before a key stop at a line break. dotenv's `\s*` there lets |
| | | 9 | | * every blank line start an attempt that scans the whole run after it, so a |
| | | 10 | | * file of blank lines takes quadratic time: about 100 s for 200 KB. The match |
| | | 11 | | * that begins on the key's own line captures the same key and value, so the |
| | | 12 | | * result does not change. dotenv 18 keeps the same grammar. |
| | | 13 | | * |
| | | 14 | | * Everything else is dotenv's, value rules included, so a file without `/` in |
| | | 15 | | * its keys parses exactly as dotenv parses it. The conformance tests pin that. |
| | | 16 | | */ |
| | | 17 | | const LINE = |
| | 14 | 18 | | /(?:^|^)[^\S\n\r\u2028\u2029]*(?:export\s+)?([\w./-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?: |
| | | 19 | | |
| | | 20 | | export function parseEnvFile(src: string): Record<string, string> { |
| | | 21 | | // A plain object on purpose, as in dotenv: `__proto__` must vanish here too, |
| | | 22 | | // which is why the name rule rejects it. |
| | 483 | 23 | | const obj: Record<string, string> = {}; |
| | 483 | 24 | | const lines = src.replace(/\r\n?/gm, '\n'); |
| | | 25 | | |
| | 483 | 26 | | for (const match of lines.matchAll(LINE)) { |
| | 640 | 27 | | const key = match[1]; |
| | 640 | 28 | | let value = (match[2] || '').trim(); |
| | 640 | 29 | | const maybeQuote = value[0]; |
| | 640 | 30 | | value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2'); |
| | 640 | 31 | | if (maybeQuote === '"') { |
| | 98 | 32 | | value = value.replace(/\\n/g, '\n').replace(/\\r/g, '\r'); |
| | | 33 | | } |
| | 640 | 34 | | obj[key] = value; |
| | | 35 | | } |
| | | 36 | | |
| | 483 | 37 | | return obj; |
| | | 38 | | } |