Coder Social home page Coder Social logo

confit's Introduction

confit

Build Status

Simple, environment-based configuration. confit loads a default JSON configuration file, additionally loading environment-specific files, if applicable. It will also process the loaded files using any configured shortstop protocol handlers—see Options below.

confit adds support for adding JavaScript-style comments in your json files as each file is processed by shush before being merged into your config.

Usage

const confit = require('confit');

confit([options])

  • options (String | Object) - the base directory in which config files live or a configuration object. If no arguments is provided, defaults to the directory of the calling file.
  • returns - config factory.
'use strict';

const path = require('path');
const confit = require('confit');

const basedir = path.join(__dirname, 'config');
confit(basedir).create(function (err, config) {
    config.get; // Function
    config.set; // Function
    config.use; // Function

    config.get('env:env'); // 'development'
});

config factory

  • addOverride(filepath) (or) addOverride(obj) - Use this to add file (.json or .js), to merge with the config datastore and override the overlapping data if any. Alternatively, you can also pass a json object to override.
  • addDefault(filepath) (or) addDefault(obj) - Use this to add default file (.json or .js), to merge with the config datastore and serve as the default datastore. Alternatively, you can also pass a json object for defaults.
  • create(callback) - Creates the config object, ready for use. Callback signature: function (err, config) {}
// All methods besides `create` are chainable
confit(options)
    .addDefault('./mydefaults.json')  //or .addDefault({foo: 'bar'})
    .addOverride('./mysettings.json') //or .addOverride({foo: 'baz'})
    .create(function (err, config) {
        // ...
    });

// - or -
//
// const factory = confit(options);
// factory.addOverride('./mysettings.json');
// factory.create(function (err, config) {
//     // ...
// });

Options

  • basedir (String) - the base directory in which config files can be found.
  • protocols (Object) - An object containing a mapping of shortstop protocols to either handler implementations or an array or handler implementations. These protocols will be used to process the config data prior to registration. If using an array of handler implementations, each handler is run in series (see Multiple handlers in the shortstop README).
  • defaults (String) - the name of the file containing all default values. Defaults to config.json.
  • envignore (Array) - any properties found in process.env that should be ignored
'use strict';

const path = require('path');
const confit = require('confit');
const handlers = require('shortstop-handlers');


const options = {
    basedir: path.join(__dirname, 'config'),
    protocols: {
        file: handlers.file(__dirname),
        glob: handlers.glob(__dirname)
    }
};

confit(options).create(function (err, config) {
    // ...
});

Config API

  • get(key) - Retrieve the value for a given key. Colon-delimited keys can be used to traverse the object hierarchy.
  • set(key, value) - Set a value for the given key. Colon-delimited keys can be used to traverse the object hierarchy.
  • use(obj) - merge provided object into config.
config.set('foo', 'bar');
config.get('foo'); // 'bar'

config.use({ foo: 'baz' });
config.get('foo'); // 'baz'

config.use({ a: { b: { c: 'd' } } } );
config.get('a:b:c'); // 'd'

Default Behavior

By default, confit loads process.env and argv values upon initialization. Additionally, it creates convenience environment properties prefixed with env: based on the current NODE_ENV setting, defaulting to development. It also normalizes NODE_ENV settings so values starting with prod become production, starting with stag become staging, starting with test become test and starting with dev become development.

// NODE_ENV='dev'
config.get('NODE_ENV');        // 'dev'
config.get('env:env');         // 'development'
config.get('env:development'); // true
config.get('env:test');        // false
config.get('env:staging');     // false
config.get('env:production');  // false
// NODE_ENV='custom'
config.get('NODE_ENV');        // 'custom'
config.get('env:env');         // 'custom'
config.get('env:development'); // false
config.get('env:test');        // false
config.get('env:staging');     // false
config.get('env:production');  // false
config.get('env:custom');      // true

Precedence

Precedence takes the following form (lower numbers overwrite higher numbers):

  1. command line arguments
  2. env variables
  3. environment-specific config (e.g., development.json)
  4. main config (config.json)
  5. env normalization (env, env:development, etc)

Shortstop Handlers

Confit by default comes with 2 shortstop handlers enabled.

  • import: Merges the contents of the specified file into configuration under a given key.
{
    "foo": "import:./myjsonfile"
}
  • config: Replaces with the value at a given key. Note that the keys in this case are dot (.) delimited.
{
    "foo": {
        "bar": true
    },
    "foobar": "config:foo.bar"
}

confit's People

Contributors

aredridel avatar christophior avatar gabrielcsapo avatar grawk avatar jasisk avatar jeffharrell avatar jonathansamines-xoom avatar pvenkatakrishnan avatar shaunwarman avatar subeeshcbabu avatar sumeetkakkar avatar totherik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

confit's Issues

Issue with unit test (or confit) isolation

While developing a feature PR for confit, I came across an interesting problem. By simply adding a valid unit test to confit-test.js:

t.test('override with stringified number as env variable', function (t) {
        var factory;
        var env = process.env;

        process.env = {
            NODE_ENV: 'test',
            nested: '2001',
            override: '8000'
        };
        console.log(process.env);
        factory = confit(path.join(__dirname, 'fixtures', 'defaults'));
        factory.create(function (err, config) {
            t.error(err);
            t.ok(config);
            t.equal(config.get('nested'), '2001');
            t.equal(config.get('override'), '8000');

            t.end();
        });

        t.on('end', function () {
            process.env = env;
        });

    });

I caused another valid unit test "precedence" to fail.

I'm not sure what's going on but commenting out either "precedence" or "override with ..." test will allow the other to pass.

Typo in an example

https://github.com/krakenjs/confit#options

Please note there is a semi-colon instead of a comma. The example doesn't work as-is:

'use strict';

var path = require('path');
var confit = require('confit');
var handlers = require('shortstop-handlers');


var options = {
    basedir: path.join(__dirname, 'config'); // <-- that should be a comma
    protocols: {
        file: handlers.file,
        glob: handlers.glob
    }
};

confit(options).create(function (err, config) {
    // ...
});

NPM High vulnerability on async dependency

Detailed Description

npm audit report reported a High vulnerability on the async dependency used in the confit dependency
Screen Shot 2022-05-04 at 11 30 22

Possible Implementation

For versions 0.x.x, 1.x.x and 2.x.x use an async version >= 2.6.4 for 3.x.x versions use >= 3.2.2
More details can be found here: GHSA-fwr7-v2mv-hh25

Environment Details

  • Version used: 2.3.0 (But still an issue on 3.0.0)
  • Environment versions: Node v12.19.0, npm v6.14.13
  • Operating System and version: OSX 10.15.7 (Catalina)

expose better api for post-import config mutating

@aredridel and I were chatting about a potential new feature inside kraken to prevent us from having to broganize (wrap kraken opts). One step we could take would be exposing a better signature for config post-import normalization, plus registering more protocols after init but before create.

The first part of that we basically already have. The only change required would be to push the final import into the constructor (and either out of the create method or in addition to it, in order to support asynchronous imports). Then, we could simply add a method in place of using the .promise.

The second part would be a simple method to write.

We already do similar behaviors elsewhere (at least for the second part—double confit stuff in kraken), this would just expose a better api for it.

Thoughts?

v2.2.0 don't work without extensions

Hi all.
With the new version v2.2.0 (that should have been compatible since it's a minor), using:
import:something
don't work anymore. Extension is now required.
import:something.json

Add debuglog statements.

  • Attempts to write an immutable property. (warning)
  • No defaults (config.json) file found/loaded. (warning)
  • No config files found/loaded. (warning)
  • When a config file is loaded for a configured environment. (info)
  • Calcualated node env name (info)

setting environment property named "env" makes config.get('env:env') undefined

  • If anyone sets an environment property named exactly as env then config.get('env:env') goes undefined.
     export env="development"
    config.get('env:env') // This returns undefined

Synchronous vs Asynchronous callback?

Hi there,

In previous versions of KrakenJS, nconf was used instead of confit. If I needed to refer to a config key anywhere in my project, I could do the following:

var nconf = require('nconf');
var myVar = nconf.get('myVar');

With confit, we need to now use a callback, e.g.

var basedir = path.join(__dirname, '/config');
var config = confit(basedir).create(function (err, config) {
  var myVar = config.get('myVar');
});

Is the callback really needed? Ideally I would like to just do the following:

var basedir = path.join(__dirname, '/config');
var config = confit(basedir);
var myVar = config.get('myVar');

It looks like there is a "_store" object where I can extract the config keys I need, without having to execute the "create" command.

For example, this works:

var basedir = path.join(__dirname, '/config');
var config = confit(basedir);
var myVar = config._store.myVar;

Ideally, I would like to use the 'get' function directly from the config object. Is this an enhancement that can be considered? Or is there a specific reason that confit requires a callback?

Thanks,
Adrian

Confit convert number to string

Hi,

after a change from 2.1.0 to 2.2.1 we found out that somehow a breaking change occured.
We have this object in our config.json (kraken)

    "cookies": {
      "expires": 0,
      "secure": false,
      "signed": true
    }

In 2.1.0 after using:
config.get('cookies')
we received: { expires: 0, secure: false, signed: true }

but in 2.2.1 we got:
{ expires: '0', secure: false, signed: true }

Please take a look at this issue, unfortunately kraken-js is taking all non-breaking changes from confit and it has impact on our project.

undefined config when running under jest

The code segment below fails for me when running tests that use confit under jest. However, executing the code directly (not using jest) works fine. Jest must muck with the global Object? Not really sure, but I think this code is too fragile.

If/when I find some time, I can try to create an example project that shows the problem. Regardless, my feeling is the code below does not pass the code smell test.

The result is that my tests that use confit return undefined for any config that is accessed with colon delimiters. The same code runs fine outside of jest.

https://github.com/krakenjs/confit/blob/2.x/lib/config.js#L34

                if (obj.constructor !== Object) {
                    // Do not allow traversal into complex types,
                    // such as Buffer, Date, etc. So, this type
                    // of key will fail: 'foo:mystring:length'
                    return undefined;
                }

node 7.2.1
jest 17.0.3
confit 2.1.0

Wrong filename for env-specific config file

When I start my Node.js app in production mode using env NODE_ENV=production node server I see that it is trying to load the following configuration file: config/production.json

I would have expected the production configuration file to be config/config-production.json

Is this the expected behavior or a bug?

Error: Cannot find module denpendency

Error: Cannot find module '.........../node_modules/confit/dist/lib/base.js'
at Function.Module._resolveFilename (module.js:455:15)
    at Function.resolve (internal/module.js:27:19)
    at shush (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/confit/node_modules/shush/index.js:27:19)
    at Factory._resolveFile (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/confit/dist/lib/factory.js:125:28)
    at Factory._add (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/confit/dist/lib/factory.js:112:33)
    at Factory.addDefault (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/confit/dist/lib/factory.js:81:22)
    at Object.<anonymous> (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/src/config/index.js:16:6)
    at Module._compile (module.js:556:32)
    at loader (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/eqielb/Development/mogujie/Groups/xmen/xmen/node_modules/babel-register/lib/node.js:154:7)

complex JSON env variable behavior

From experimenting I find that only strings at the base level of process.env can be used correctly in confit.

E.g. if my config.json is:

{
  "foo": {
    "bar": "baz"
  }
}

And I set this to the environment:

process.env.foo = {
  bar: 'bang'
}

In my resolved configuration I see:

foo: '[object Object]',

If I stringify the JSON, instead I see the following in resolved config:

foo: '{"bar": "bang"}'

I understand that env traditionally holds string values, but it would be nice if I could stringify a complex JSON object and confit would pull overrides out of that, like this:

process.env.foo = JSON.stringify({
  bar: 'bang'
});

resolves in config as:

foo: {
  bar: 'bang'
}

I have a use case that could be satisfied by such a feature. Do you think it is feasible to add it? Or is it something you'd accept a PR for?

changes needed for debugging with Webstorm

I wanted to set breakpoints in webstorm, and found I had to do the following in order for it to work:

  1. install babel-register, babel-preset-es2015, babel-plugin-add-module-exports
  2. create a module with the following code (I named it [confit dir]/test/ws-debug-shim.js)
require('babel-register')({
    "presets": ["es2015"],
    "plugins": [
        "add-module-exports"
    ]
});

Add this new module as an argument in the webstorm run config:

run_debug_configurations_and_ws-debug-shim_js_-_confit_-____src_confit_

So. Not sure if it's worth adding to the docs, or adding these modules and shim to the project, but at least this issue can be used as reference if anyone else has the same question in the future.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.