UNPKG

properties-reader

Version:

Properties file reader for Node.js

360 lines (348 loc) 10.3 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { bindToExpress: () => bindToExpress, default: () => index_default, expressBasePath: () => expressBasePath, propertiesReader: () => propertiesReader }); module.exports = __toCommonJS(index_exports); // src/actions/append.ts var import_node_fs = require("fs"); // src/actions/read.ts function readLine(line, task) { const trimmed = line.trim(); if (!trimmed) { return task; } const section = /^\[([^=]+)]$/.exec(trimmed); const property = !section && /^([^#=]+)(={0,1})(.*)$/.exec(trimmed); if (section) { task.section = section[1]; } else if (property) { const currentSection = task.section ? `${task.section}.` : ""; task.properties.set(currentSection + property[1].trim(), property[3].trim()); } return task; } function read(input, task) { return String(input).split("\n").reduce( (task2, line) => { return readLine(line, task2); }, { ...task, section: "" } ); } // src/actions/append.ts function newTask() { return { section: "", properties: /* @__PURE__ */ new Map() }; } function append(sourceFile, encoding, task = newTask()) { if (!sourceFile) { return task; } const file = (0, import_node_fs.readFileSync)(sourceFile, encoding); return read(file, task); } // src/actions/save.ts var import_promises = require("fs/promises"); async function save(destFile, props) { let pointer = null; try { pointer = await (0, import_promises.open)(destFile, "w"); for (const line of props) { await pointer.writeFile(`${line} `, "utf8"); } } finally { await pointer?.close(); } } // src/bind-to-express.ts var import_node_path = require("path"); var import_file_exists = require("@kwsites/file-exists"); var import_mkdirp = require("mkdirp"); function expressBasePath(basePath) { return (0, import_node_path.resolve)(basePath || process.cwd(), "./") + import_node_path.sep; } function bindToExpress(reader, app, basePath, makePaths) { for (const [key, value] of reader.entries()) { if (value && /\.(path|dir)$/.test(key)) { const resolvedValue = (0, import_node_path.resolve)(basePath, value); reader.set(key, resolvedValue); try { const directoryPath = /dir$/.test(key) ? resolvedValue : (0, import_node_path.dirname)(resolvedValue); if (makePaths) { import_mkdirp.mkdirp.sync(directoryPath); } else if (!(0, import_file_exists.exists)(directoryPath, import_file_exists.FOLDER)) { throw new Error("Path is not a directory that already exists"); } } catch { throw new Error(`Unable to create directory ${value}`); } } app.set(key, reader.get(key)); if (/^browser\./.test(key) && app.locals) { app.locals[key.substr(8)] = reader.get(key); } } app.set("properties", reader); return reader; } // src/parse-value.ts function parseValue(input) { const parsedValue = String(input).trim(); switch (parsedValue) { case "undefined": case "null": return null; case (!isNaN(parsedValue) && !!parsedValue && parsedValue): return +parsedValue; case "false": case "true": return parsedValue === "true"; default: { const replacements = { "\\n": "\n", "\\r": "\r", "\\t": " " }; return parsedValue.replace(/\\[nrt]/g, (key) => replacements[key]); } } } // src/get-by-root.ts function getByRoot(store, root = "") { return Object.fromEntries(parsedEntries(store, `${root}.`)); } function* parsedEntries(store, prefix = "") { for (const [storeKey, storeValue] of store.entries()) { const key = parsedKey(storeKey, prefix); if (key) { yield [key, parseValue(storeValue)]; } } } function parsedKey(key, prefix) { if (!prefix) { return key; } if (key.startsWith(prefix)) { return key.substring(prefix.length); } } // src/output.ts function output(properties, allowDuplicateSections, saveSections) { if (!allowDuplicateSections) { properties = collapseSections(properties); } return saveSections ? generatePropertiesWithSections(properties) : generatePropertiesWithoutSections(properties); } function* generatePropertiesWithoutSections(properties) { for (const [key, value] of properties.entries()) { yield `${key}=${value}`; } } function* generatePropertiesWithSections(properties) { let section = null; for (let [key, value] of properties.entries()) { const [prefix, ...tokens] = key.split("."); if (tokens.length) { if (section !== prefix) { section = prefix; yield `[${section}]`; } key = tokens.join("."); } else { section = null; } yield `${key}=${value}`; } } function collapseSections(properties) { const sections = /* @__PURE__ */ new Map(); for (const [key, value] of properties.entries()) { const [section] = key.split("."); const map = sections.get(section) ?? []; map.push([key, value]); sections.set(section, map); } return new Map(Array.from(sections.values()).flat()); } // src/properties-path.ts function addLeaf(branch, leaf, key) { branch.leaves.set(leaf, key); if (Object.hasOwn(branch.branches, leaf)) { branch.branches[leaf].dual = true; } } function addBranch(branch, token) { const next = branch.branches[token] ??= childBranch(branch, token); if (branch.leaves.has(token)) { next.dual = true; } return next; } function childBranch(parent, child = "") { return { dual: false, leaves: /* @__PURE__ */ new Map(), branches: /* @__PURE__ */ Object.create(null), path: (parent?.path ? `${parent.path}.` : "") + child, parent }; } function pathLayers(map) { const paths = childBranch(null); for (const key of map.keys()) { const tokens = key.split("."); const leaf = tokens.pop(); const path = tokens.reduce((branch, token) => addBranch(branch, token), paths); addLeaf(path, leaf, key); } return paths; } function memoize(fn) { const cache = /* @__PURE__ */ new Map(); return (key) => { if (!cache.has(key)) { cache.set(key, fn(key)); } return cache.get(key); }; } function propertiesPath(map) { const shape = pathLayers(map); const value = (layer, key) => { if (!key) { return map.get(layer.path); } const leaf = layer.leaves.get(key); const branch = Object.hasOwn(layer.branches, key); if (branch) { return make(layer.branches[key]); } return typeof leaf === "string" ? map.get(leaf) : void 0; }; const make = memoize((layer) => { const ownKeys = /* @__PURE__ */ new Set([...layer.leaves.keys(), ...Object.keys(layer.branches)]); const target = Object.defineProperties( /* @__PURE__ */ Object.create(null), Object.fromEntries( [...ownKeys].map((name) => [ name, { configurable: false, enumerable: true, get() { return value(layer, name); } } ]) ) ); if (layer.dual) { Object.defineProperty(target, "", { configurable: false, enumerable: true, get() { return value(layer, ""); } }); } return target; }); return make(shape); } // src/reader.ts var createPropertiesReader = ({ sourceFile, encoding = "utf-8", allowDuplicateSections = false, saveSections = true } = {}) => { const store = append(sourceFile, encoding); function entries(options = {}) { return options.parsed === true ? parsedEntries(store.properties) : store.properties.entries(); } const instance = { get length() { return store.properties.size; }, append(sourceFile2, enc = encoding) { append(sourceFile2, enc, store); return instance; }, clone() { const next = createPropertiesReader({ allowDuplicateSections, encoding, saveSections }); for (const [key, value] of store.properties.entries()) { next.set(key, value); } return next; }, bindToExpress(app, basePath, makePaths = false) { return bindToExpress(instance, app, expressBasePath(basePath), makePaths); }, each(fn, scope) { for (const [key, value] of store.properties.entries()) { fn.call(scope || instance, key, value); } return instance; }, entries, get(key) { return parseValue(store.properties.get(key)); }, getAllProperties() { return Object.fromEntries(store.properties.entries()); }, getByRoot(root) { return getByRoot(store.properties, root); }, getRaw(key) { return store.properties.has(key) ? store.properties.get(key) : null; }, out() { return output(store.properties, allowDuplicateSections, saveSections); }, path() { return propertiesPath(store.properties); }, read(input) { read(typeof input === "string" ? input : input.toString(encoding), store); return instance; }, save(destFile) { return save(destFile, instance.out()); }, set(key, value) { store.properties.set(key, String(value)); return instance; } }; return instance; }; // src/index.ts var index_default = createPropertiesReader; var propertiesReader = createPropertiesReader; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { bindToExpress, expressBasePath, propertiesReader }); //# sourceMappingURL=index.cjs.map