From 257e053f9f9775dbb4fa426c2b571e9cad5cf2f5 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 19 Dec 2022 11:30:08 -0500 Subject: [PATCH] *Update dist --- dist/index.d.ts | 49 +---- dist/index.js | 483 +++++------------------------------------------- 2 files changed, 59 insertions(+), 473 deletions(-) diff --git a/dist/index.d.ts b/dist/index.d.ts index 70b7737..a101a14 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -4,46 +4,22 @@ * https://github.com/bcoin-org/bcoin */ /// -export interface Options { - suffix?: string; - fallback?: string; - alias?: object; -} -export interface LoadOptions { - hash?: string | boolean; - query?: string | boolean; - env?: object | boolean; - argv?: string[] | boolean; - config?: string | boolean; -} +import arg from "arg"; /** * Config Parser */ export default class Config { private module; - private prefix; - private suffix?; - private fallback?; - private options; - private alias; private data; - private env; - private args; - private argv; - private pass; - private query; - private hash; - constructor(module: string, options?: Options); - private init; + constructor(module: string); inject(options: object): void; - load(options: LoadOptions): void; - open(file: string): void; + load(): void; openDir(dir: string): void; - openJson(file: string): void; - saveConfigJson(file: string, data: object): void; - filter(name: string): Config; + open(file: string): void; + save(file: string, data: object): void; set(key: string, value: any): void; - has(key: string): boolean; + has(key: string): any; + private normalize; get(key: string, fallback?: any): any; typeOf(key: string): "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | "null"; str(key: string, fallback?: any): any; @@ -58,16 +34,7 @@ export default class Config { array(key: string, fallback?: any): any; obj(key: string, fallback?: any): any; func(key: string, fallback?: any): any; - path(key: string, fallback?: any): any; mb(key: string, fallback?: any): any; - getSuffix(): any; - getPrefix(): string; - getFile(file: string): any; - location(file: string): string; - parseConfig(text: string): void; - parseArg(argv?: string[]): void; + parseArg(args: arg.Result): void; parseEnv(env?: object): void; - parseQuery(query: string): void | {}; - parseHash(hash: string): void | {}; - parseForm(query: string, ch: string, map: object): void; } diff --git a/dist/index.js b/dist/index.js index b0f33db..6abb613 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10,60 +10,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const bsert_1 = __importDefault(require("bsert")); const path_1 = __importDefault(require("path")); -const os_1 = __importDefault(require("os")); const fs_1 = __importDefault(require("fs")); -const HOME = os_1.default.homedir ? os_1.default.homedir() : "/"; +const arg_1 = __importDefault(require("arg")); +const object_path_1 = __importDefault(require("object-path")); +const deep_to_flat_object_1 = __importDefault(require("deep-to-flat-object")); /** * Config Parser */ class Config { module; - prefix; - suffix; - fallback; - options = {}; - alias = {}; data = {}; - env = {}; - args = {}; - argv = []; - pass = []; - query = {}; - hash = {}; - constructor(module, options) { + constructor(module) { (0, bsert_1.default)(typeof module === "string"); (0, bsert_1.default)(module.length > 0); this.module = module; - this.prefix = path_1.default.join(HOME, `.${module}`); - if (options) { - this.init(options); - } - } - init(options) { - (0, bsert_1.default)(options && typeof options === "object"); - if (options.suffix != null) { - (0, bsert_1.default)(typeof options.suffix === "string"); - this.suffix = options.suffix; - } - if (options.fallback != null) { - (0, bsert_1.default)(typeof options.fallback === "string"); - this.fallback = options.fallback; - } - if (options.alias) { - (0, bsert_1.default)(typeof options.alias === "object"); - for (const key of Object.keys(options.alias)) { - const value = options.alias[key]; - (0, bsert_1.default)(typeof value === "string"); - this.alias[key] = value; - } - } } inject(options) { for (const key of Object.keys(options)) { const value = options[key]; switch (key) { - case "hash": - case "query": case "env": case "argv": case "config": @@ -72,41 +37,19 @@ class Config { this.set(key, value); } } - load(options) { - if (options.hash) { - this.parseHash(options.hash); - } - if (options.query) { - this.parseQuery(options.query); - } - if (options.env) { - this.parseEnv(options.env); - } - if (options.argv) { - this.parseArg(options.argv); - } - this.prefix = this.getPrefix(); - } - open(file) { - const path = this.getFile(file); - let text; - try { - text = fs_1.default.readFileSync(path, "utf8"); - } - catch (e) { - if (e.code === "ENOENT") - return; - throw e; - } - this.parseConfig(text); - this.prefix = this.getPrefix(); + load() { + const args = (0, arg_1.default)({}, { permissive: true }); + this.parseArg(args); } openDir(dir) { (0, bsert_1.default)(fs_1.default.existsSync(dir), `Directory ${dir} does not exist`); - let files = fs_1.default.readdirSync(dir).map((item) => path_1.default.join(dir, item)); - files.forEach(this.openJson.bind(this)); + let files = fs_1.default + .readdirSync(dir) + .filter((item) => item.endsWith(".json")) + .map((item) => path_1.default.join(dir, item)); + files.forEach(this.open.bind(this)); } - openJson(file) { + open(file) { let json; try { json = fs_1.default.readFileSync(file, "utf8"); @@ -118,20 +61,22 @@ class Config { throw new Error(`Error parsing file ${file}: ${e.message}`); } (0, bsert_1.default)(typeof json === "object", `Config file ${file} must be an object`); - for (const key of Object.keys(json)) { + const settings = (0, deep_to_flat_object_1.default)(json); + for (const key of Object.keys(settings)) { const value = json[key]; - switch (true) { - case Array.isArray(value): - this.set(key, [...(this.array(key) ?? []), ...value]); - break; - default: - this.set(key, value); - break; + let keyPath = key.split("."); + let isArray = typeof parseInt(keyPath.pop()) === "number"; + if (isArray) { + let itemPath = keyPath.join("."); + let item = this.get(itemPath, []); + item.push(value); + this.set(itemPath, item); + continue; } + this.set(key, value); } - this.prefix = this.getPrefix(); } - saveConfigJson(file, data) { + save(file, data) { (0, bsert_1.default)(typeof data === "object"); (0, bsert_1.default)(!Array.isArray(data)); const configDir = this.str("configdir"); @@ -140,56 +85,34 @@ class Config { fs_1.default.mkdirSync(configDir, { recursive: true }); } fs_1.default.writeFileSync(fullPath, JSON.stringify(data)); - this.openJson(fullPath); - } - filter(name) { - (0, bsert_1.default)(typeof name === "string"); - const child = new Config(this.module); - child.prefix = this.prefix; - child.suffix = this.suffix; - child.fallback = this.fallback; - child.argv = this.argv; - child.pass = this.pass; - _filter(name, this.env, child.env); - _filter(name, this.args, child.args); - _filter(name, this.query, child.query); - _filter(name, this.hash, child.hash); - _filter(name, this.options, child.options); - return child; + this.open(fullPath); } set(key, value) { (0, bsert_1.default)(typeof key === "string", "Key must be a string."); if (value == null) { return; } - key = key.replace(/-/g, ""); - key = key.toLowerCase(); - this.options[key] = value; + key = this.normalize(key); + object_path_1.default.set(this.data, key, value); + this.data[key] = value; } has(key) { - if (typeof key === "number") { - (0, bsert_1.default)(key >= 0, "Index must be positive."); - return key < this.argv.length; - } (0, bsert_1.default)(typeof key === "string", "Key must be a string."); key = key.replace(/-/g, ""); key = key.toLowerCase(); - if (key in this.hash && this.hash[key] !== null) { - return true; + return object_path_1.default.has(this.data, key); + } + normalize(key, env = false) { + (0, bsert_1.default)(typeof key === "string", "Key must be a string."); + if (env) { + key = key.replace(/__/g, "."); + key = key.replace(/_/g, ""); } - if (key in this.query && this.query[key] !== null) { - return true; + else { + key = key.replace(/-/g, ""); } - if (key in this.args && this.args[key] !== null) { - return true; - } - if (key in this.env && this.env[key] !== null) { - return true; - } - if (key in this.data && this.data[key] !== null) { - return true; - } - return this.options[key] !== null; + key = key.toLowerCase(); + return key; } get(key, fallback = null) { if (Array.isArray(key)) { @@ -202,38 +125,9 @@ class Config { } return fallback; } - if (typeof key === "number") { - (0, bsert_1.default)(key >= 0, "Index must be positive."); - if (key >= this.argv.length) { - return fallback; - } - if (this.argv[key] != null) { - return this.argv[key]; - } - return fallback; - } (0, bsert_1.default)(typeof key === "string", "Key must be a string."); - key = key.replace(/-/g, ""); - key = key.toLowerCase(); - if (key in this.hash && this.hash[key] !== null) { - return this.hash[key]; - } - if (key in this.query && this.query[key] !== null) { - return this.query[key]; - } - if (key in this.args && this.args[key] !== null) { - return this.args[key]; - } - if (key in this.env && this.env[key] !== null) { - return this.env[key]; - } - if (key in this.data && this.data[key] !== null) { - return this.data[key]; - } - if (key in this.options && this.options[key] !== null) { - return this.options[key]; - } - return fallback; + key = this.normalize(key); + return object_path_1.default.get(this.data, key); } typeOf(key) { const value = this.get(key); @@ -429,26 +323,6 @@ class Config { } return value; } - path(key, fallback = null) { - let value = this.str(key); - if (value === null) { - return fallback; - } - if (value.length === 0) { - return fallback; - } - switch (value[0]) { - case "~": // home dir - value = path_1.default.join(HOME, value.substring(1)); - break; - case "@": // prefix - value = path_1.default.join(this.prefix, value.substring(1)); - break; - default: // cwd - break; - } - return path_1.default.normalize(value); - } mb(key, fallback = null) { const value = this.uint(key); if (value === null) { @@ -456,176 +330,10 @@ class Config { } return value * 1024 * 1024; } - getSuffix() { - if (!this.suffix) { - throw new Error("No suffix presented."); - } - const suffix = this.str(this.suffix, this.fallback); - (0, bsert_1.default)(isAlpha(suffix), "Bad suffix."); - return suffix; - } - getPrefix() { - let prefix = this.str("prefix"); - if (prefix) { - if (prefix[0] === "~") { - prefix = path_1.default.join(HOME, prefix.substring(1)); - } - } - else { - prefix = path_1.default.join(HOME, `.${this.module}`); - } - if (this.suffix) { - const suffix = this.str(this.suffix); - if (suffix) { - (0, bsert_1.default)(isAlpha(suffix), "Bad suffix."); - if (this.fallback && suffix !== this.fallback) { - prefix = path_1.default.join(prefix, suffix); - } - } - } - return path_1.default.normalize(prefix); - } - getFile(file) { - const name = this.str("config"); - if (name) { - return name; - } - return path_1.default.join(this.prefix, file); - } - location(file) { - return path_1.default.join(this.prefix, file); - } - parseConfig(text) { - (0, bsert_1.default)(typeof text === "string", "Config must be text."); - if (text.charCodeAt(0) === 0xfeff) { - text = text.substring(1); - } - text = text.replace(/\r\n/g, "\n"); - text = text.replace(/\r/g, "\n"); - text = text.replace(/\\\n/g, ""); - let num = 0; - for (const chunk of text.split("\n")) { - const line = chunk.trim(); - num += 1; - if (line.length === 0) { - continue; - } - if (line[0] === "#") { - continue; - } - const index = line.indexOf(":"); - if (index === -1) { - throw new Error(`Expected ':' on line ${num}: "${line}".`); - } - let key = line.substring(0, index).trim(); - key = key.replace(/\-/g, ""); - if (!isLowerKey(key)) { - throw new Error(`Invalid option on line ${num}: ${key}.`); - } - const value = line.substring(index + 1).trim(); - if (value.length === 0) { - continue; - } - const alias = this.alias[key]; - if (alias) { - key = alias; - } - this.data[key] = value; - } - } - parseArg(argv) { - if (!argv || typeof argv !== "object") - argv = process.argv; - (0, bsert_1.default)(Array.isArray(argv)); - let last = null; - let pass = false; - for (let i = 2; i < argv.length; i++) { - const arg = argv[i]; - (0, bsert_1.default)(typeof arg === "string"); - if (arg === "--") { - pass = true; - continue; - } - if (pass) { - this.pass.push(arg); - continue; - } - if (arg.length === 0) { - last = null; - continue; - } - if (arg.indexOf("--") === 0) { - const index = arg.indexOf("="); - let key = null; - let value = null; - let empty = false; - if (index !== -1) { - // e.g. --opt=val - key = arg.substring(2, index); - value = arg.substring(index + 1); - last = null; - empty = false; - } - else { - // e.g. --opt - key = arg.substring(2); - value = "true"; - last = null; - empty = true; - } - key = key.replace(/\-/g, ""); - if (!isLowerKey(key)) { - throw new Error(`Invalid argument: --${key}.`); - } - if (value.length === 0) { - continue; - } - // Do not allow one-letter aliases. - if (key.length > 1) { - const alias = this.alias[key]; - if (alias) { - key = alias; - } - } - this.args[key] = value; - if (empty) { - last = key; - } - continue; - } - if (arg[0] === "-") { - // e.g. -abc - last = null; - for (let j = 1; j < arg.length; j++) { - let key = arg[j]; - if ((key < "a" || key > "z") && - (key < "A" || key > "Z") && - (key < "0" || key > "9") && - key !== "?") { - throw new Error(`Invalid argument: -${key}.`); - } - const alias = this.alias[key]; - if (alias) { - key = alias; - } - this.args[key] = "true"; - last = key; - } - continue; - } - // e.g. foo - const value = arg; - if (value.length === 0) { - last = null; - continue; - } - if (last) { - this.args[last] = value; - last = null; - } - else { - this.argv.push(value); - } + parseArg(args) { + for (let key in args) { + let newKey = key.replace("-", ""); + object_path_1.default.set(this.data, newKey, args[key]); } } parseEnv(env) { @@ -640,84 +348,18 @@ class Config { for (let key of Object.keys(env)) { const value = env[key]; (0, bsert_1.default)(typeof value === "string"); - if (key.indexOf(prefix) !== 0) + if (key.indexOf(prefix) !== 0) { continue; - key = key.substring(prefix.length); - key = key.replace(/_/g, ""); + } if (!isUpperKey(key)) { continue; } + key = key.substring(prefix.length); + key = this.normalize(key, true); if (value.length === 0) { continue; } - key = key.toLowerCase(); - // Do not allow one-letter aliases. - if (key.length > 1) { - const alias = this.alias[key]; - if (alias) { - key = alias; - } - } - this.env[key] = value; - } - } - parseQuery(query) { - if (typeof query !== "string") { - if (!global.location) { - return {}; - } - query = global.location.search; - if (typeof query !== "string") { - return {}; - } - } - return this.parseForm(query, "?", this.query); - } - parseHash(hash) { - if (typeof hash !== "string") { - if (!global.location) { - return {}; - } - hash = global.location.hash; - if (typeof hash !== "string") { - return {}; - } - } - return this.parseForm(hash, "#", this.hash); - } - parseForm(query, ch, map) { - (0, bsert_1.default)(typeof query === "string"); - if (query.length === 0) { - return; - } - if (query[0] === ch) { - query = query.substring(1); - } - for (const pair of query.split("&")) { - const index = pair.indexOf("="); - let key, value; - if (index !== -1) { - key = pair.substring(0, index); - value = pair.substring(index + 1); - } - else { - key = pair; - value = "true"; - } - key = unescape(key); - key = key.replace(/\-/g, ""); - if (!isLowerKey(key)) { - continue; - } - value = unescape(value); - if (value.length === 0) { - continue; - } - const alias = this.alias[key]; - if (alias) { - key = alias; - } - map[key] = value; + object_path_1.default.set(this.data, key); } } } @@ -734,41 +376,18 @@ function fmt(key) { } return key; } -function unescape(str) { - try { - str = decodeURIComponent(str); - str = str.replace(/\+/g, " "); - } - catch (e) { } - str = str.replace(/\0/g, ""); - return str; -} function isAlpha(str) { return /^[a-z0-9_\-]+$/i.test(str); } function isKey(key) { return /^[a-zA-Z0-9]+$/.test(key); } -function isLowerKey(key) { - if (!isKey(key)) { - return false; - } - return !/[A-Z]/.test(key); -} function isUpperKey(key) { if (!isKey(key)) { return false; } return !/[a-z]/.test(key); } -function _filter(name, a, b) { - for (const key of Object.keys(a)) { - if (key.length > name.length && key.indexOf(name) === 0) { - const sub = key.substring(name.length); - b[sub] = a[key]; - } - } -} function fromFloat(num, exp) { (0, bsert_1.default)(typeof num === "number" && isFinite(num)); (0, bsert_1.default)(Number.isSafeInteger(exp));