UNPKG

env-file-rw

Version:
173 lines (172 loc) 6.21 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = require("fs"); const promises_1 = require("fs/promises"); var NodeType; (function (NodeType) { NodeType[NodeType["VARIABLE"] = 0] = "VARIABLE"; NodeType[NodeType["COMMENT"] = 1] = "COMMENT"; NodeType[NodeType["UNKNOWN"] = 2] = "UNKNOWN"; })(NodeType || (NodeType = {})); const RE_NEWLINES = /\\n/g; const NEWLINE = '\n'; const NEWLINES_MATCH = /\r\n|\n|\r/; class EnvFileWriter { /** * if immediateParse, content is parsed synchronously */ constructor(fileName, immediateParse = true) { this.tree = {}; this.treePendingChanges = {}; this.fileName = fileName; if (immediateParse) { this.parseSync(); } } parseSingleValue(value) { const end = value.length - 1; const isDoubleQuoted = value[0] === '"' && value[end] === '"'; const isSingleQuoted = value[0] === "'" && value[end] === "'"; if (isSingleQuoted || isDoubleQuoted) { value = value.substring(1, end); if (isDoubleQuoted) { value = value.replace(RE_NEWLINES, NEWLINE); } } else { value = value.trim(); } return value; } /** * Categorize each line and it's type */ constructTreeFromString(fileContent) { const allLines = fileContent.split(NEWLINES_MATCH); const tree = {}; // use of foreach to have the index allLines.forEach((line, index) => { var _a; // higly inspired from the parse function of dotenv, because reasons const keyValue = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/); if (keyValue) { const key = keyValue[1]; const value = ((_a = keyValue[2]) !== null && _a !== void 0 ? _a : ''); tree[key] = { type: NodeType.VARIABLE, key, value: this.parseSingleValue(value), line: index }; } else if (line.trimStart().startsWith("#")) { tree[index] = { type: NodeType.COMMENT, key: index.toString(), value: line, line: index }; } else { tree[index] = { type: NodeType.UNKNOWN, key: index.toString(), value: line, line: index }; } }); return tree; } applyPendingChangesOnString(fileContent) { const eachLines = fileContent.split(NEWLINES_MATCH); for (const key in this.treePendingChanges) { const element = this.treePendingChanges[key]; if (element.line === undefined) { eachLines.push(`${element.key}=${element.value}`); } else { eachLines[element.line] = `${element.key}=${element.value}`; } } return eachLines.join("\n"); } /** * read the file and parse the content, synchronously */ parseSync() { const fileContent = fs_1.readFileSync(this.fileName, "utf8"); return this.tree = this.constructTreeFromString(fileContent); } /** * read the file and parse the content */ parse() { return __awaiter(this, void 0, void 0, function* () { const fileContent = yield promises_1.readFile(this.fileName, "utf8"); return this.tree = this.constructTreeFromString(fileContent); }); } exists(key) { return this.tree[key] !== undefined; } /** * Get the value of a key */ get(key, defaultValue) { var _a, _b; return (_b = (_a = this.tree[key]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : defaultValue; } /** * Set the value of a key * call .save() to persist changes */ set(key, value) { if (!this.exists(key)) { this.treePendingChanges[key] = { key: key, value: this.parseSingleValue(value), type: NodeType.VARIABLE, line: undefined, }; } else { this.treePendingChanges[key] = { key: key, value: this.parseSingleValue(value), type: this.tree[key].type, line: this.tree[key].line, }; } } /** * Persists the pending changes, synchronously */ saveSync() { const fileContent = fs_1.readFileSync(this.fileName, "utf8"); fs_1.writeFileSync(this.fileName, this.applyPendingChangesOnString(fileContent)); this.tree = Object.assign(Object.assign({}, this.tree), this.treePendingChanges); this.treePendingChanges = {}; } /** * Persists the pending changes */ save() { return __awaiter(this, void 0, void 0, function* () { const fileContent = (yield promises_1.readFile(this.fileName, "utf8")); yield promises_1.writeFile(this.fileName, this.applyPendingChangesOnString(fileContent)); this.tree = Object.assign(Object.assign({}, this.tree), this.treePendingChanges); this.treePendingChanges = {}; }); } } exports.default = EnvFileWriter;