Compare commits

...

81 Commits

Author SHA1 Message Date
semantic-release-bot 06464fe4ae chore(release): 0.1.15 [skip ci]
## [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](82f603c00a))
2023-07-07 14:13:40 +00:00
Derrick Hammer f93b5d049b
Merge remote-tracking branch 'origin/master' 2023-07-07 10:12:46 -04:00
Derrick Hammer 82f603c00a
fix: need to use set, not objectPath directly 2023-07-07 10:12:39 -04:00
semantic-release-bot 576b461b20 chore(release): 0.1.14 [skip ci]
## [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](4475f122f1))
2023-07-07 14:09:17 +00:00
Derrick Hammer dbaabbf2f1
Merge remote-tracking branch 'origin/master' 2023-07-07 10:08:24 -04:00
Derrick Hammer 4475f122f1
fix: use regex 2023-07-07 10:08:16 -04:00
semantic-release-bot b861401eb2 chore(release): 0.1.13 [skip ci]
## [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](ecb2990572))
2023-07-07 13:59:22 +00:00
Derrick Hammer 4f9cb35ac4
Merge remote-tracking branch 'origin/master' 2023-07-07 09:58:15 -04:00
Derrick Hammer ecb2990572
fix: bad for loop 2023-07-07 09:58:11 -04:00
semantic-release-bot 601d9fbd2d chore(release): 0.1.12 [skip ci]
## [0.1.12](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.11...v0.1.12) (2023-07-07)
2023-07-07 13:53:00 +00:00
Derrick Hammer 636c974e80
Merge remote-tracking branch 'origin/master' 2023-07-07 09:52:08 -04:00
Derrick Hammer 5a01ee6cec
refactor: rewrite arg parsing 2023-07-07 09:52:03 -04:00
semantic-release-bot 4fd50b28ab chore(release): 0.1.11 [skip ci]
## [0.1.11](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.10...v0.1.11) (2023-07-07)
2023-07-07 13:20:18 +00:00
Derrick Hammer 2334cf73aa
Merge remote-tracking branch 'origin/master' 2023-07-07 09:19:30 -04:00
Derrick Hammer 97aec6432f
dep: add arg 2023-07-07 09:19:21 -04:00
semantic-release-bot b4434c0805 chore(release): 0.1.10 [skip ci]
## [0.1.10](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.9...v0.1.10) (2023-07-07)
2023-07-07 13:16:14 +00:00
Derrick Hammer 9c2dc57d13
Merge remote-tracking branch 'origin/master' 2023-07-07 09:15:07 -04:00
Derrick Hammer b4f6015e02
refactor: add cjs support 2023-07-07 09:14:12 -04:00
semantic-release-bot ffec85fee5 chore(release): 0.1.9 [skip ci]
## [0.1.9](https://git.lumeweb.com/LumeWeb/relay-cfg/compare/v0.1.8...v0.1.9) (2023-07-04)
2023-07-04 07:48:57 +00:00
Derrick Hammer ba35a9c743
Merge remote-tracking branch 'origin/master' 2023-07-04 03:48:15 -04:00
Derrick Hammer b2ec0fe5e3
refactor: don't export as default 2023-07-04 03:48:10 -04:00
Derrick Hammer e5dc651b79
style: fix import order 2023-07-04 03:47:34 -04:00
semantic-release-bot 2530c55307 chore(release): 0.1.8 [skip ci]
## [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](1b5a7c0605))
2023-07-04 07:39:00 +00:00
Derrick Hammer ee3162fbbb
chore: prune README.md 2023-07-04 02:50:07 -04:00
Derrick Hammer 3e7dffb4b4
ci: add publishConfig 2023-07-04 02:27:25 -04:00
Derrick Hammer 9dca063dd0
ci: add npm-shrinkwrap.json 2023-07-04 02:17:26 -04:00
Derrick Hammer 4d8eb4bc55
chore: update package.json 2023-07-04 02:16:47 -04:00
Derrick Hammer 1b5a7c0605
fix: fix or disable errors in eslint 2023-07-04 02:15:05 -04:00
Derrick Hammer 3f1b1dca42
ci: setup 2023-07-04 02:14:19 -04:00
Derrick Hammer 62856686f2
*Update dist 2023-04-18 23:36:33 -04:00
Derrick Hammer e1c57ea40b
*Make the config property meta 2023-04-18 23:36:10 -04:00
Derrick Hammer e1d4785240
*Update dist 2022-12-22 09:45:05 -05:00
Derrick Hammer 9e8e44b9c5
*Heavily simplify config loading and just pass it to the set method, don't try to handle arrays special 2022-12-22 09:44:40 -05:00
Derrick Hammer 792ec3976f
*Bug fix, setting data property directly 2022-12-22 09:43:58 -05:00
Derrick Hammer 17a434f400
*Update dist 2022-12-21 15:16:14 -05:00
Derrick Hammer 6e0608c9a9
*Add savePath utility method 2022-12-21 15:15:55 -05:00
Derrick Hammer 302181c707
*Update dist 2022-12-21 15:09:14 -05:00
Derrick Hammer 618ab73d14
*Remove the need to add a file extension since all files should be JSON 2022-12-21 15:08:51 -05:00
Derrick Hammer e11e94c61c
*Update dist 2022-12-19 13:58:29 -05:00
Derrick Hammer 8875bdd2a7
*Bug fix 2022-12-19 13:58:01 -05:00
Derrick Hammer 2a1078a3a2
*Update dist 2022-12-19 13:49:11 -05:00
Derrick Hammer a3f3e157b9
*improve object path check 2022-12-19 13:48:39 -05:00
Derrick Hammer 785e0b836c
*Pass fallback to objectPath.get 2022-12-19 13:48:12 -05:00
Derrick Hammer f69a12fb52
*Update dist 2022-12-19 11:35:45 -05:00
Derrick Hammer e535abd2ff
*Need to use the _ property 2022-12-19 11:35:24 -05:00
Derrick Hammer 257e053f9f
*Update dist 2022-12-19 11:30:08 -05:00
Derrick Hammer f70348f055
*Update dep 2022-12-19 11:29:59 -05:00
Derrick Hammer afb5389243
*Heavily refactor and simplification
*Support dot notation in accessing and creating settings
*Ensure we only load .json files
2022-12-19 11:29:03 -05:00
Derrick Hammer 8e5b9d2bc6
*Update dist 2022-12-06 16:48:52 -05:00
Derrick Hammer 6e37b22988
*Do mkdir on just configdir 2022-12-06 16:48:30 -05:00
Derrick Hammer 647dc9a2ec
*Update dist 2022-12-06 16:39:23 -05:00
Derrick Hammer 7c631f3af5
*Force create of config directory if it does not exist 2022-12-06 16:38:58 -05:00
Derrick Hammer 3e412d5090
*Update dist 2022-09-21 17:36:47 -04:00
Derrick Hammer c416218d88
*Switch case needs to be on true not the value 2022-09-21 17:36:30 -04:00
Derrick Hammer 3a030e051b
*Update dist 2022-09-21 17:28:37 -04:00
Derrick Hammer 438c3df467
*Merge arrays with splat, don't push 2022-09-21 17:28:16 -04:00
Derrick Hammer 7483aafb46
*Update dist 2022-09-21 17:21:43 -04:00
Derrick Hammer ea0e7a3696
*add error including path if json parse fails 2022-09-21 17:20:54 -04:00
Derrick Hammer 935a225e57
*Update dist 2022-09-21 17:19:01 -04:00
Derrick Hammer 1491fa7567
*openJson needs to be bound 2022-09-21 17:18:45 -04:00
Derrick Hammer 4dca570ba8
*Update dist 2022-09-21 17:17:09 -04:00
Derrick Hammer e49ce56cb8
*Remove getFile call 2022-09-21 17:16:38 -04:00
Derrick Hammer 1c3eeb3004
*Update dist 2022-09-21 16:56:02 -04:00
Derrick Hammer 8b49a6ed6b
*Ensure key is both not undefined and not null 2022-09-21 16:55:46 -04:00
Derrick Hammer 44b8aa18e6
*Update dist 2022-09-21 16:44:17 -04:00
Derrick Hammer cf07c6074e
*set options to empty object 2022-09-21 16:44:01 -04:00
Derrick Hammer fcc3c40ba1
*Update dist 2022-09-21 16:38:11 -04:00
Derrick Hammer c98b544689
*Process json after saving to store in active config 2022-09-21 16:37:56 -04:00
Derrick Hammer 30de3530fc
*Update dist 2022-09-21 16:30:17 -04:00
Derrick Hammer c893ddd428
*add missing file argument 2022-09-21 16:30:03 -04:00
Derrick Hammer f7751a3995
*Update dist 2022-09-21 16:28:05 -04:00
Derrick Hammer d50269aac7
*add saveConfigJson method 2022-09-21 16:27:38 -04:00
Derrick Hammer 909e233f23
*Update dist 2022-09-21 15:56:48 -04:00
Derrick Hammer d260933384
*Update LoadOptions 2022-09-21 15:56:34 -04:00
Derrick Hammer f3edf4ff07
*Update dist 2022-09-21 15:54:50 -04:00
Derrick Hammer ecbdd3bede
*add type defs 2022-09-21 15:54:40 -04:00
Derrick Hammer a84ab0fd7f
*Add dist 2022-09-21 15:48:20 -04:00
Derrick Hammer b8ea90253a
*set outDir 2022-09-21 15:47:50 -04:00
Derrick Hammer 19891e34f8
*Export Config class 2022-09-21 15:47:42 -04:00
Derrick Hammer 334078669a
*add api to read files from dir and parse as JSON 2022-09-21 15:46:01 -04:00
Derrick Hammer 82dddc75cf
*Initial port to typescript 2022-09-21 14:16:00 -04:00
16 changed files with 19831 additions and 1519 deletions

View File

@ -1,152 +0,0 @@
{
"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"]
}
}

13
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Build/Publish
on:
push:
branches:
- master
- develop
- develop-*
jobs:
main:
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
secrets: inherit

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
build/
node_modules/
npm-debug.log

View File

@ -1,17 +0,0 @@
.babel*
.bmocharc*
.bpkgignore
.editorconfig
.eslint*
.git*
.mocharc*
.yarnignore
bench/
build/
docs/
node_modules/
npm-debug.log
package-lock.json
test/
webpack.*.js
yarn.lock

6
.presetterrc.json Normal file
View File

@ -0,0 +1,6 @@
{
"preset": [
"presetter-preset-hybrid",
"@lumeweb/node-library-preset"
]
}

35
CHANGELOG.md Normal file
View File

@ -0,0 +1,35 @@
## [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))

View File

@ -1,6 +1,6 @@
This software is licensed under the MIT License.
Copyright (c) 2017, Christopher Jeffrey (https://github.com/chjj)
Copyright (c) 2017, Christopher Jeffrey (https://github.com/chjj), 2022 Hammer Technologies LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,55 +1 @@
# 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.
# relay-cfg

View File

@ -1,9 +0,0 @@
/*!
* 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

View File

@ -1,3 +0,0 @@
'use strict';
exports.unsupported = true;

View File

@ -1,3 +0,0 @@
'use strict';
module.exports = require('fs');

19139
npm-shrinkwrap.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,47 @@
{
"name": "bcfg",
"version": "0.1.7",
"description": "Config parser for bcoin",
"keywords": [
"conf",
"config"
],
"name": "@lumeweb/relay-cfg",
"version": "0.1.15",
"main": "lib/index.js",
"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"
"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>"
],
"repository": {
"type": "git",
"url": "gitea@git.lumeweb.com:LumeWeb/relay-cfg.git"
},
"author": "Christopher Jeffrey <chjjeffrey@gmail.com>",
"main": "./lib/bcfg.js",
"scripts": {
"lint": "eslint lib/ || exit 0",
"test": "bmocha --reporter spec test/*-test.js"
},
"dependencies": {
"bsert": "~0.0.10"
"prepare": "presetter bootstrap",
"build": "run build",
"semantic-release": "semantic-release"
},
"devDependencies": {
"bmocha": "^2.1.0"
"@lumeweb/node-library-preset": "^0.2.7",
"presetter": "*",
"presetter-preset-hybrid": "^4.0.1"
},
"engines": {
"node": ">=8.0.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"
},
"browser": {
"./lib/fs": "./lib/fs-browser.js"
"files": [
"lib"
],
"publishConfig": {
"access": "public"
}
}

591
src/index.ts Normal file
View File

@ -0,0 +1,591 @@
/* 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);
}

View File

@ -1,41 +0,0 @@
'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');
});
});