Compare commits
No commits in common. "master" and "v0.1.7" have entirely different histories.
|
@ -0,0 +1,152 @@
|
|||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"globals": {
|
||||
"Atomics": "readable",
|
||||
"BigInt": "readable",
|
||||
"BigInt64Array": "readable",
|
||||
"BigUint64Array": "readable",
|
||||
"queueMicrotask": "readable",
|
||||
"SharedArrayBuffer": "readable",
|
||||
"TextEncoder": "readable",
|
||||
"TextDecoder": "readable"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.mjs"],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.cjs"],
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"test/{,**/}*.{mjs,cjs,js}"
|
||||
],
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"globals": {
|
||||
"register": "readable"
|
||||
},
|
||||
"rules": {
|
||||
"max-len": "off",
|
||||
"prefer-arrow-callback": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 10,
|
||||
"ecmaFeatures": {
|
||||
"globalReturn": true
|
||||
},
|
||||
"requireConfigFile": false,
|
||||
"sourceType": "script"
|
||||
},
|
||||
"root": true,
|
||||
"rules": {
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
"arrow-parens": ["error", "as-needed", {
|
||||
"requireForBlockBody": true
|
||||
}],
|
||||
"arrow-spacing": "error",
|
||||
"block-spacing": ["error", "always"],
|
||||
"brace-style": ["error", "1tbs"],
|
||||
"camelcase": ["error", {
|
||||
"properties": "never"
|
||||
}],
|
||||
"comma-dangle": ["error", "never"],
|
||||
"consistent-return": "error",
|
||||
"eol-last": ["error", "always"],
|
||||
"eqeqeq": ["error", "always", {
|
||||
"null": "ignore"
|
||||
}],
|
||||
"func-name-matching": "error",
|
||||
"indent": ["off", 2, {
|
||||
"ArrayExpression": "off",
|
||||
"SwitchCase": 1,
|
||||
"CallExpression": {
|
||||
"arguments": "off"
|
||||
},
|
||||
"FunctionDeclaration": {
|
||||
"parameters": "off"
|
||||
},
|
||||
"FunctionExpression": {
|
||||
"parameters": "off"
|
||||
},
|
||||
"MemberExpression": "off",
|
||||
"ObjectExpression": "off",
|
||||
"ImportDeclaration": "off"
|
||||
}],
|
||||
"handle-callback-err": "off",
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"max-len": ["error", {
|
||||
"code": 80,
|
||||
"ignorePattern": "function \\w+\\(",
|
||||
"ignoreUrls": true
|
||||
}],
|
||||
"max-statements-per-line": ["error", {
|
||||
"max": 1
|
||||
}],
|
||||
"new-cap": ["error", {
|
||||
"newIsCap": true,
|
||||
"capIsNew": false
|
||||
}],
|
||||
"new-parens": "error",
|
||||
"no-buffer-constructor": "error",
|
||||
"no-console": "off",
|
||||
"no-extra-semi": "off",
|
||||
"no-fallthrough": "off",
|
||||
"no-func-assign": "off",
|
||||
"no-implicit-coercion": "error",
|
||||
"no-multi-assign": "error",
|
||||
"no-multiple-empty-lines": ["error", {
|
||||
"max": 1
|
||||
}],
|
||||
"no-nested-ternary": "error",
|
||||
"no-param-reassign": "off",
|
||||
"no-return-assign": "error",
|
||||
"no-return-await": "off",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-tabs": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"args": "none",
|
||||
"ignoreRestSiblings": false
|
||||
}],
|
||||
"no-use-before-define": ["error", {
|
||||
"functions": false,
|
||||
"classes": false
|
||||
}],
|
||||
"no-useless-escape": "off",
|
||||
"no-var": "error",
|
||||
"nonblock-statement-body-position": ["error", "below"],
|
||||
"padded-blocks": ["error", "never"],
|
||||
"prefer-arrow-callback": "error",
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all",
|
||||
"ignoreReadBeforeAssign": true
|
||||
}],
|
||||
"prefer-template": "off",
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "always"],
|
||||
"spaced-comment": ["error", "always", {
|
||||
"exceptions": ["!"]
|
||||
}],
|
||||
"space-before-blocks": "error",
|
||||
"strict": "error",
|
||||
"unicode-bom": ["error", "never"],
|
||||
"valid-jsdoc": "error",
|
||||
"wrap-iife": ["error", "inside"]
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
name: Build/Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- develop-*
|
||||
|
||||
jobs:
|
||||
main:
|
||||
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
|
||||
secrets: inherit
|
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
node_modules/
|
||||
npm-debug.log
|
|
@ -0,0 +1,17 @@
|
|||
.babel*
|
||||
.bmocharc*
|
||||
.bpkgignore
|
||||
.editorconfig
|
||||
.eslint*
|
||||
.git*
|
||||
.mocharc*
|
||||
.yarnignore
|
||||
bench/
|
||||
build/
|
||||
docs/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
package-lock.json
|
||||
test/
|
||||
webpack.*.js
|
||||
yarn.lock
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"preset": [
|
||||
"presetter-preset-hybrid",
|
||||
"@lumeweb/node-library-preset"
|
||||
]
|
||||
}
|
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,35 +0,0 @@
|
|||
## [0.1.15](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.14...v0.1.15) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* need to use set, not objectPath directly ([82f603c](https://git.lumeweb.com/LumeWeb/relay-cfg/commit/82f603c00a44f6bf82da8b26acb4e37ad2df33ae))
|
||||
|
||||
## [0.1.14](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.13...v0.1.14) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use regex ([4475f12](https://git.lumeweb.com/LumeWeb/relay-cfg/commit/4475f122f12ccd7ecbaf055eb8ffc2596d4c71aa))
|
||||
|
||||
## [0.1.13](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.12...v0.1.13) (2023-07-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bad for loop ([ecb2990](https://git.lumeweb.com/LumeWeb/relay-cfg/commit/ecb29905726324165548f06ac505d0edfa3c4028))
|
||||
|
||||
## [0.1.12](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.11...v0.1.12) (2023-07-07)
|
||||
|
||||
## [0.1.11](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.10...v0.1.11) (2023-07-07)
|
||||
|
||||
## [0.1.10](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.9...v0.1.10) (2023-07-07)
|
||||
|
||||
## [0.1.9](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.8...v0.1.9) (2023-07-04)
|
||||
|
||||
## [0.1.8](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.7...v0.1.8) (2023-07-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix or disable errors in eslint ([1b5a7c0](https://git.lumeweb.com/LumeWeb/relay-cfg/commit/1b5a7c0605e2dcda3f379c0b61baccf0a3dfc257))
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
This software is licensed under the MIT License.
|
||||
|
||||
Copyright (c) 2017, Christopher Jeffrey (https://github.com/chjj), 2022 Hammer Technologies LLC
|
||||
Copyright (c) 2017, Christopher Jeffrey (https://github.com/chjj)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
56
README.md
56
README.md
|
@ -1 +1,55 @@
|
|||
# relay-cfg
|
||||
# bcfg
|
||||
|
||||
Config parser (used for bcoin).
|
||||
|
||||
## Usage
|
||||
|
||||
``` js
|
||||
const Config = require('bcfg');
|
||||
|
||||
// Will consider ~/.my-module the prefix directory.
|
||||
const config = new Config('my-module', {
|
||||
alias: {
|
||||
'n': 'network'
|
||||
}
|
||||
});
|
||||
|
||||
// Inject some custom options first.
|
||||
config.inject({
|
||||
some: 'user',
|
||||
options: 'here'
|
||||
});
|
||||
|
||||
config.load({
|
||||
// Parse URL hash
|
||||
hash: true,
|
||||
// Parse querystring
|
||||
query: true,
|
||||
// Parse environment
|
||||
env: true,
|
||||
// Parse args
|
||||
argv: true
|
||||
});
|
||||
|
||||
// Will parse ~/.my-module/my-config.conf (throws on FS error).
|
||||
config.open('my-config.conf');
|
||||
|
||||
// These will cast types and throw on incorrect type.
|
||||
console.log(config.str('username'));
|
||||
console.log(config.str('password'));
|
||||
console.log(config.uint('userid'));
|
||||
console.log(config.float('percent'));
|
||||
console.log(config.bool('initialize'));
|
||||
```
|
||||
|
||||
## Contribution and License Agreement
|
||||
|
||||
If you contribute code to this project, you are implicitly allowing your code
|
||||
to be distributed under the MIT license. You are also implicitly verifying that
|
||||
all code is your original work. `</legalese>`
|
||||
|
||||
## License
|
||||
|
||||
- Copyright (c) 2017, Christopher Jeffrey (MIT License).
|
||||
|
||||
See LICENSE for more info.
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* bcfg.js - configuration parsing for bcoin
|
||||
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./config');
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
exports.unsupported = true;
|
File diff suppressed because it is too large
Load Diff
60
package.json
60
package.json
|
@ -1,47 +1,33 @@
|
|||
{
|
||||
"name": "@lumeweb/relay-cfg",
|
||||
"version": "0.1.15",
|
||||
"main": "lib/index.js",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"types": "lib/index.d.ts",
|
||||
"module": "lib/index.mjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./lib/index.js",
|
||||
"import": "./lib/index.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"authors": [
|
||||
"Christopher Jeffrey <chjjeffrey@gmail.com>",
|
||||
"Hammer Technologies LLC <contact@lumeweb.com>"
|
||||
"name": "bcfg",
|
||||
"version": "0.1.7",
|
||||
"description": "Config parser for bcoin",
|
||||
"keywords": [
|
||||
"conf",
|
||||
"config"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/relay-cfg.git"
|
||||
"license": "MIT",
|
||||
"repository": "git://github.com/bcoin-org/bcfg.git",
|
||||
"homepage": "https://github.com/bcoin-org/bcfg",
|
||||
"bugs": {
|
||||
"url": "https://github.com/bcoin-org/bcfg/issues"
|
||||
},
|
||||
"author": "Christopher Jeffrey <chjjeffrey@gmail.com>",
|
||||
"main": "./lib/bcfg.js",
|
||||
"scripts": {
|
||||
"prepare": "presetter bootstrap",
|
||||
"build": "run build",
|
||||
"semantic-release": "semantic-release"
|
||||
"lint": "eslint lib/ || exit 0",
|
||||
"test": "bmocha --reporter spec test/*-test.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"bsert": "~0.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lumeweb/node-library-preset": "^0.2.7",
|
||||
"presetter": "*",
|
||||
"presetter-preset-hybrid": "^4.0.1"
|
||||
"bmocha": "^2.1.0"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"dependencies": {
|
||||
"arg": "^5.0.2",
|
||||
"bsert": "^0.0.12",
|
||||
"deep-to-flat-object": "^1.0.1",
|
||||
"object-path": "^0.11.8"
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
"browser": {
|
||||
"./lib/fs": "./lib/fs-browser.js"
|
||||
}
|
||||
}
|
||||
|
|
591
src/index.ts
591
src/index.ts
|
@ -1,591 +0,0 @@
|
|||
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable @typescript-eslint/member-ordering */
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
/* !
|
||||
* config.js - configuration parsing for bcoin
|
||||
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
import fs from "fs";
|
||||
import Path from "path";
|
||||
|
||||
import arg from "arg";
|
||||
import assert from "bsert";
|
||||
import deepToFlatObject from "deep-to-flat-object";
|
||||
import objectPath from "object-path";
|
||||
|
||||
/**
|
||||
* Config Parser
|
||||
*/
|
||||
|
||||
export class Config {
|
||||
private module: string;
|
||||
private data = {};
|
||||
private configProperty;
|
||||
|
||||
constructor(module: string, configProperty: string) {
|
||||
assert(typeof module === "string");
|
||||
assert(module.length > 0);
|
||||
|
||||
this.module = module;
|
||||
this.configProperty = configProperty;
|
||||
}
|
||||
|
||||
public inject(options: object) {
|
||||
for (const key of Object.keys(options)) {
|
||||
const value = options[key];
|
||||
|
||||
// eslint-disable-next-line default-case
|
||||
switch (key) {
|
||||
case "env":
|
||||
case "argv":
|
||||
case "config":
|
||||
continue;
|
||||
}
|
||||
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public load() {
|
||||
const args = arg({}, { permissive: true });
|
||||
|
||||
this.parseArg(args);
|
||||
}
|
||||
|
||||
public openDir(dir: string) {
|
||||
assert(fs.existsSync(dir), `Directory ${dir} does not exist`);
|
||||
|
||||
let files = fs
|
||||
.readdirSync(dir)
|
||||
.filter((item) => item.endsWith(".json"))
|
||||
.map((item) => Path.join(dir, item));
|
||||
files.forEach(this.open.bind(this));
|
||||
}
|
||||
|
||||
public open(file: string) {
|
||||
let json;
|
||||
try {
|
||||
json = fs.readFileSync(file, "utf8");
|
||||
json = JSON.parse(json);
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
return;
|
||||
}
|
||||
throw new Error(`Error parsing file ${file}: ${e.message}`);
|
||||
}
|
||||
|
||||
assert(typeof json === "object", `Config file ${file} must be an object`);
|
||||
|
||||
const settings = deepToFlatObject(json);
|
||||
|
||||
for (const key of Object.keys(settings)) {
|
||||
const value = settings[key];
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public save(file: string, data: object): void {
|
||||
assert(typeof data === "object");
|
||||
assert(!Array.isArray(data));
|
||||
|
||||
const configDir = this.str(this.configProperty) as string;
|
||||
const fullPath = Path.join(configDir, `${file}.json`);
|
||||
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
|
||||
fs.writeFileSync(fullPath, JSON.stringify(data));
|
||||
this.open(fullPath);
|
||||
}
|
||||
|
||||
public savePath(file: string, path: string): void {
|
||||
this.save(file, this.get(path));
|
||||
}
|
||||
|
||||
public set(key: string, value: any) {
|
||||
assert(typeof key === "string", "Key must be a string.");
|
||||
|
||||
if (value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
key = this.normalize(key);
|
||||
|
||||
objectPath.set(this.data, key, value);
|
||||
}
|
||||
|
||||
public has(key: string) {
|
||||
assert(typeof key === "string", "Key must be a string.");
|
||||
|
||||
key = key.replace(/-/g, "");
|
||||
key = key.toLowerCase();
|
||||
|
||||
return objectPath.has(this.data, key);
|
||||
}
|
||||
|
||||
private normalize(key: string, env = false): string {
|
||||
assert(typeof key === "string", "Key must be a string.");
|
||||
|
||||
if (env) {
|
||||
key = key.replace(/__/g, ".");
|
||||
key = key.replace(/_/g, "");
|
||||
} else {
|
||||
key = key.replace(/-/g, "");
|
||||
}
|
||||
|
||||
key = key.toLowerCase();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public get(key: string, fallback = null) {
|
||||
if (Array.isArray(key)) {
|
||||
const keys = key;
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value !== null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
assert(typeof key === "string", "Key must be a string.");
|
||||
|
||||
key = this.normalize(key);
|
||||
|
||||
return objectPath.get(this.data, key, fallback);
|
||||
}
|
||||
|
||||
public typeOf(key: string) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
return typeof value;
|
||||
}
|
||||
|
||||
public str(key: string, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
throw new Error(`${fmt(key)} must be a string.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public int(key, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
if (typeof value !== "number") {
|
||||
throw new Error(`${fmt(key)} must be an int.`);
|
||||
}
|
||||
|
||||
if (!Number.isSafeInteger(value)) {
|
||||
throw new Error(`${fmt(key)} must be an int.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!/^-?\d+$/.test(value)) {
|
||||
throw new Error(`${fmt(key)} must be an int.`);
|
||||
}
|
||||
|
||||
const num = parseInt(value, 10);
|
||||
|
||||
if (!Number.isSafeInteger(num)) {
|
||||
throw new Error(`${fmt(key)} must be an int.`);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public uint(key, fallback = null) {
|
||||
const value = this.int(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
throw new Error(`${fmt(key)} must be a uint.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public float(key, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
if (typeof value !== "number") {
|
||||
throw new Error(`${fmt(key)} must be a float.`);
|
||||
}
|
||||
|
||||
if (!isFinite(value)) {
|
||||
throw new Error(`${fmt(key)} must be a float.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!/^-?\d*(?:\.\d*)?$/.test(value)) {
|
||||
throw new Error(`${fmt(key)} must be a float.`);
|
||||
}
|
||||
|
||||
if (!/\d/.test(value)) {
|
||||
throw new Error(`${fmt(key)} must be a float.`);
|
||||
}
|
||||
|
||||
const num = parseFloat(value);
|
||||
|
||||
if (!isFinite(num)) {
|
||||
throw new Error(`${fmt(key)} must be a float.`);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
public ufloat(key, fallback = null) {
|
||||
const value = this.float(key);
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
throw new Error(`${fmt(key)} must be a positive float.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public fixed(key, exp, fallback = null) {
|
||||
const value = this.float(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
try {
|
||||
return fromFloat(value, exp || 0);
|
||||
} catch (e) {
|
||||
throw new Error(`${fmt(key)} must be a fixed number.`);
|
||||
}
|
||||
}
|
||||
|
||||
public ufixed(key, exp, fallback = null) {
|
||||
const value = this.fixed(key, exp);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
throw new Error(`${fmt(key)} must be a positive fixed number.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool(key, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// Bitcoin Core compat.
|
||||
if (typeof value === "number") {
|
||||
if (value === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value === 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
if (typeof value !== "boolean") {
|
||||
throw new Error(`${fmt(key)} must be a boolean.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value === "true" || value === "1") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value === "false" || value === "0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new Error(`${fmt(key)} must be a boolean.`);
|
||||
}
|
||||
|
||||
public buf(key: string, fallback = null, enc: BufferEncoding = "hex") {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
if (!Buffer.isBuffer(value)) {
|
||||
throw new Error(`${fmt(key)} must be a buffer.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const data = Buffer.from(value, enc);
|
||||
|
||||
if (data.length !== Buffer.byteLength(value, enc)) {
|
||||
throw new Error(`${fmt(key)} must be a ${enc} string.`);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public array(key: string, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
if (!Array.isArray(value)) {
|
||||
throw new Error(`${fmt(key)} must be an array.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const parts = value.trim().split(/\s*,\s*/);
|
||||
const result: string[] = [];
|
||||
for (const part of parts) {
|
||||
if (part.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push(part);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public obj(key: string, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new Error(`${fmt(key)} must be an object.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public func(key: string, fallback = null) {
|
||||
const value = this.get(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== "function") {
|
||||
throw new Error(`${fmt(key)} must be a function.`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public mb(key: string, fallback = null) {
|
||||
const value = this.uint(key);
|
||||
|
||||
if (value === null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
return value * 1024 * 1024;
|
||||
}
|
||||
|
||||
public parseArg(args: arg.Result<any>) {
|
||||
const argPairs = args._.reduce((prev: any, item: any) => {
|
||||
const parts = item.split("=");
|
||||
const key = parts[0].replace(/-/g, "");
|
||||
prev[key] = parts[1];
|
||||
|
||||
return prev;
|
||||
}, {});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-for-in-array
|
||||
for (const key in argPairs) {
|
||||
this.set(key, argPairs[key]);
|
||||
}
|
||||
}
|
||||
|
||||
public parseEnv(env?: object) {
|
||||
let prefix = this.module;
|
||||
|
||||
prefix = prefix.toUpperCase();
|
||||
prefix = prefix.replace(/-/g, "_");
|
||||
prefix += "_";
|
||||
|
||||
if (!env || typeof env !== "object") {
|
||||
env = process.env;
|
||||
}
|
||||
|
||||
assert(typeof env === "object");
|
||||
|
||||
for (let key of Object.keys(env)) {
|
||||
const value = env[key];
|
||||
|
||||
assert(typeof value === "string");
|
||||
|
||||
if (key.indexOf(prefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isUpperKey(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key = key.substring(prefix.length);
|
||||
key = this.normalize(key, true);
|
||||
|
||||
if (value.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
objectPath.set(this.data, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function fmt(key: string[] | string | number) {
|
||||
if (Array.isArray(key)) {
|
||||
key = key[0];
|
||||
}
|
||||
|
||||
if (typeof key === "number") {
|
||||
return `Argument #${key}`;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
function isAlpha(str: string) {
|
||||
return /^[a-z0-9_-]+$/i.test(str);
|
||||
}
|
||||
|
||||
function isKey(key: string) {
|
||||
return /^[a-zA-Z0-9]+$/.test(key);
|
||||
}
|
||||
|
||||
function isUpperKey(key: string) {
|
||||
if (!isKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !/[a-z]/.test(key);
|
||||
}
|
||||
|
||||
function fromFloat(num: number, exp: number) {
|
||||
assert(typeof num === "number" && isFinite(num));
|
||||
assert(Number.isSafeInteger(exp));
|
||||
|
||||
let str = num.toFixed(exp);
|
||||
let sign = 1;
|
||||
|
||||
if (str.length > 0 && str[0] === "-") {
|
||||
str = str.substring(1);
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
let hi: number | string = str;
|
||||
let lo: number | string = "0";
|
||||
|
||||
const index = str.indexOf(".");
|
||||
|
||||
if (index !== -1) {
|
||||
hi = str.substring(0, index);
|
||||
lo = str.substring(index + 1);
|
||||
}
|
||||
|
||||
hi = hi.replace(/^0+/, "");
|
||||
lo = lo.replace(/0+$/, "");
|
||||
|
||||
assert(hi.length <= 16 - exp, "Fixed number string exceeds 2^53-1.");
|
||||
|
||||
assert(lo.length <= exp, "Too many decimal places in fixed number string.");
|
||||
|
||||
if (hi.length === 0) {
|
||||
hi = "0";
|
||||
}
|
||||
|
||||
while (lo.length < exp) {
|
||||
lo += "0";
|
||||
}
|
||||
|
||||
if (lo.length === 0) {
|
||||
lo = "0";
|
||||
}
|
||||
|
||||
assert(
|
||||
/^\d+$/.test(hi) && /^\d+$/.test(lo),
|
||||
"Non-numeric characters in fixed number string.",
|
||||
);
|
||||
|
||||
hi = parseInt(hi, 10);
|
||||
lo = parseInt(lo, 10);
|
||||
|
||||
const mult = Math.pow(10, exp);
|
||||
const maxLo = Number.MAX_SAFE_INTEGER % mult;
|
||||
const maxHi = (Number.MAX_SAFE_INTEGER - maxLo) / mult;
|
||||
|
||||
assert(
|
||||
hi < maxHi || (hi === maxHi && lo <= maxLo),
|
||||
"Fixed number string exceeds 2^53-1.",
|
||||
);
|
||||
|
||||
return sign * (hi * mult + lo);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('bsert');
|
||||
const Config = require('../lib/config');
|
||||
|
||||
describe('bcfg', function() {
|
||||
it('should filter options', () => {
|
||||
const options = {
|
||||
testString: 'hello',
|
||||
childTestString: 'goodbye'
|
||||
};
|
||||
|
||||
const parent = new Config('bcfg');
|
||||
parent.inject(options);
|
||||
parent.load(options);
|
||||
|
||||
assert.strictEqual(parent.str('test-string'), 'hello');
|
||||
|
||||
const child = parent.filter('child');
|
||||
|
||||
assert.strictEqual(child.str('test-string'), 'goodbye');
|
||||
});
|
||||
|
||||
it('should filter argv', () => {
|
||||
const parent = new Config('bcfg');
|
||||
|
||||
// process.argv
|
||||
parent.parseArg([
|
||||
'node',
|
||||
'bcfg',
|
||||
'--test-string=hello',
|
||||
'--child-test-string=goodbye'
|
||||
]);
|
||||
|
||||
assert.strictEqual(parent.str('test-string'), 'hello');
|
||||
|
||||
const child = parent.filter('child');
|
||||
|
||||
assert.strictEqual(child.str('test-string'), 'goodbye');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue