44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import fs from "node:fs";
|
|||
|
|
|
||
|
|
interface EnvEntry {
|
||
|
|
key: string;
|
||
|
|
value: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseEnvLines(content: string): EnvEntry[] {
|
||
|
|
const entries: EnvEntry[] = [];
|
||
|
|
for (const line of content.split("\n")) {
|
||
|
|
const trimmed = line.trim();
|
||
|
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
||
|
|
const eq = trimmed.indexOf("=");
|
||
|
|
if (eq === -1) continue;
|
||
|
|
entries.push({ key: trimmed.slice(0, eq), value: trimmed.slice(eq + 1) });
|
||
|
|
}
|
||
|
|
return entries;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Loads a `.env` file into `process.env`, without overriding vars already set. */
|
||
|
|
export function loadDotenv(envPath: string): void {
|
||
|
|
if (!fs.existsSync(envPath)) return;
|
||
|
|
for (const { key, value } of parseEnvLines(fs.readFileSync(envPath, "utf-8"))) {
|
||
|
|
if (process.env[key] === undefined) process.env[key] = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Sets `key=value` in a `.env` file, replacing an existing line for that key rather than duplicating it. */
|
||
|
|
export function upsertEnvVar(envPath: string, key: string, value: string): void {
|
||
|
|
const lines = fs.existsSync(envPath)
|
||
|
|
? fs.readFileSync(envPath, "utf-8").split("\n")
|
||
|
|
: [];
|
||
|
|
const prefix = `${key}=`;
|
||
|
|
const index = lines.findIndex((line) => line.startsWith(prefix));
|
||
|
|
const newLine = `${key}=${value}`;
|
||
|
|
if (index >= 0) {
|
||
|
|
lines[index] = newLine;
|
||
|
|
} else {
|
||
|
|
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
||
|
|
lines.push(newLine);
|
||
|
|
}
|
||
|
|
fs.writeFileSync(envPath, lines.join("\n") + "\n");
|
||
|
|
}
|