npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

appcfg

v0.5.4

Published

Application Configuration Library for Node.js

Downloads

10,167

Readme

Application Configuration Library for Node.js and Browser

CircleCI NPM version

About

Load and Combine Configuration from many sources:

  • Files
    • JavaScript Module
    • JSON
    • Yaml
    • ENV + .env
    • S3 Storage
  • Directory (combine files)
  • MongoDB

Additional features:

When combining objects from many sources, deep copy is used:

// a
{ sub: { foo: 'foo' }, arr: [ 'foo' ] }
// b
{ sub: { bar: 'bar' }, arr: [ 'bar' ] }

// combined (a + b)
{
    sub: { foo: 'foo', bar: 'bar'},
    arr: ['foo', 'bar']
}

// E.g you want completely to overwrite `arr` property, then prefix the key's name with `!`

// a
{ sub: { foo: 'foo' }, arr: [ 'foo' ] }
// b
{ sub: { bar: 'bar' }, '!arr': [ 'bar' ] }

// combined (a + b)
{
    sub: { foo: 'foo', bar: 'bar'},
    arr: ['bar']
}

Example:

import AppCfg from 'appcfg'

const config = await AppCfg.fetch([
    // from file. (with Special Folder format syntax support)
    {
        path: '%APPDATA%/.appName/config.yml',

        // set this source as writable for configuration persistance
        writable: true
    },
    // ENV + .env
    {
        dotenv: true,
        // per default CWD is checked, can be overriden
        path: './foo/bar/'
    },
    // directory
    {
        path: 'defaults/**.yml'
    },
    // mongodb
    {
        mongo: 'barSettings'
    },
    // from file, but use only nested property
    {
        path: 'package.json',
        getterProperty: 'atma'
    }
]);
Command Line overrides

Command line arguments are parsed and also set to the configuration object.

$ node app --foo.bar barValue --debug
let config = await Config.fetch(someSources);

assert.has(config, {
    foo: {
        bar: 'barValue'
    },
    debug: true
})
Conditions

Yaml conditions example. (same is also for json format)

# conditional root configuration example
'#if debug':
    name: Foo
    host: dev.example.com
'#if test':
    name: Baz
    host: localhost

# conditional property example
port:
    '#if debug': 5000
    '#if test': 5030
    'default': 8080

# conditional array item example
scipts:
    - lib.js
    - '#if debug || test'
        - lib.debug-extension.js

Arguments lookup:

  • in configuration object
  • in cli overrides
  • in process.env
  • compare value as string from process.env.ENV
# from cli example
$ node app --debug

# from environment
$ set ENV=DEBUG
$ node app
{
    name: 'Foo',
    host: 'localhost',
    port: 5000,
    scripts: [
        "lib.js",
        "lib.debug-extension.js"
    ]
}
Special Folder

Use special folders for loading/writing configurations, like %APPDATA% or %HOME%. Is system agnostic and is parsed from the environment variables.

Config.fetch({
    path: '%APPDATA%/.myApplication/global.yml',
    writable: true
});

Interpolations

Sometimes to not repeat the configuration it is convenient to use interpolations. It will embed configuration from itself.

# someConfig.yml
name: 'Foo'
A:
    lorem: '#[name]'
B:
    ipsum: '#[A.lorem]'
let config = await Config.fetch({
    path: 'someConfig.yml'
});

assert.has(config, {
    name: 'Foo',
    A: { lorem: 'Foo' },
    B: { ipsum: 'Foo' }
});

API

Config

static

.fetch(Array<Source>) => Config Instance

Start loading the configuration from specified sources, returns new deferrable configuration instance

methods

<Constructor> (Array<Source>)
  • .$read(?Mix)

    • Mix:
      • String: File/Directory/Glob path
      • Source: Source object
      • Array<Source>
      • @default - Array taken from constructor
    • @return: self. Is deferrable, so you can attach done callbacks to it.

    Load configuration from sources

  • .$write(config:Object [, ?deepExtend:Boolean, ?setterPath:String):Deferred

    Update and save the configuration. Use first matched writable source.

    • deepExtend: complex objects and arrays are merged
    • setterPath: define nested object in current configuration
  • .$get(property:String)

    • property: Dot delimited accessor config.$get('foo.bar.quux')

      // is the same as you if you would write null-check expressions yourself:
      var quuxVal = config.foo && config.foo.bar && config.foo.bar.quux;
    • @return: null or value

  • .$is(name:String):Boolean

    Check conditional environment variable, e.g.: config.$is('debug')

    Ways to define the variables. (Example defines DEBUG and TEST flags)

    • directly in the configuration
      // foo.yml
      debug: true
      test: true
    • from the command line:
      > node index --debug --test
    • using environment configuration(comma delimited)
      $ set ENV=DEBUG,TEST
      # also
      $ set NODE_ENV=DEBUG,TEST
      $ node index
  • .toJSON():Object

    Returns clean json configuration object.

  • .done(callback)

    Fire the callback when the configuration is loaded

Source

Common properties for all source types
{
    // Define specific property to extract SUB-JSON from the loaded configuration
    // @default: null
    getterProperty: String

    // Define specific property in the root configuration,
    // where the loaded configuration should be inserted into
    // @default: null
    setterProperty: String

    // Specify if this source can be used for persistence
    // @default: false
    writable: Boolean

    // Fires before source $read function is called
    // (e.g. change this.path property or any other things)
    beforeRead: Function<Source, RootConfig>

    // Fires after source completes reading
    // (e.g. access config object in `Source.config`)
    afterRead: Function<Source, RootConfig>

    // If true, do not log any warning if the source returns 404
    // @default: false
    optional: true

    // If true, then waits until all previous sources are loaded
    // @default: false
    sync: true
}
FileSource
{
    // File path
    path: String
}
DirectorySource

It will be mapped to multiple FileSources

{
    // Directory path with GLOB look-up, e.g. 'configs/**.json'
    path: String
}
MongoDBSource

Depends on ClassJS

{
    // Collection name
    mongo: String,

    // if source is writable
    // @default: true
    writable: Boolean

    // MongoDB Connection Settings
    // It can be also specified in previous configuration source, under `mongodb` property
    // @default: null -
    settings: {
        // connection string
        connection: String
        // or

        // Port, default 27017
        port: Number,
        // IP, default '127.0.0.1'
        ip: String,

        // Database name, no default
        db: String
    }
}
CustomSource

This source type can suit any needs.

// Constructor with the Deferrable Interface and the method `read`
Function

class Foo {
    config: any
    async read (){
        // do any reads and calcs, after that resolve the source
        this.config = await loadConfig();
    }
}
Embedded

Include config direct into the source

{
    config: Object
}

Test

$ npm install
$ npm test

(c) 2014-2022 MIT License