Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

configly

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

configly - npm Package Compare versions

Comparing version 4.0.3 to 4.1.0

lib/include_files.js

27

index.js

@@ -1,10 +0,11 @@

var merge = require('deeply')
var merge = require('deeply')
// sub-modules
, compare = require('./compare.js')
, parsers = require('./parsers.js')
, compare = require('./compare.js')
, parsers = require('./parsers.js')
// library files
, configly = require('./lib/configly.js')
, load = require('./lib/load.js')
, envVars = require('./lib/env_vars.js')
, createNew = require('./lib/create_new.js')
, configly = require('./lib/configly.js')
, load = require('./lib/load.js')
, envVars = require('./lib/env_vars.js')
, includeFiles = require('./lib/include_files.js')
, createNew = require('./lib/create_new.js')
;

@@ -24,7 +25,12 @@

configly.defaults = {
directory : './config',
environment : 'development',
customEnvVars: 'custom-environment-variables'
directory : './config',
environment : 'development',
customEnvVars : 'custom-environment-variables',
customIncludeFiles: 'custom-include-files'
};
// no specific directory set (yet)
// fallback to the default one
configly.directory = null;
// filename chunk separator

@@ -39,2 +45,3 @@ configly.separator = '-';

configly.hooks[configly.defaults.customEnvVars] = envVars;
configly.hooks[configly.defaults.customIncludeFiles] = includeFiles;

@@ -41,0 +48,0 @@ // Public API

@@ -13,3 +13,4 @@ // Public API

{
Object.keys(this.hooks).forEach(function(hook)
// sort hooks short first + alphabetically
Object.keys(this.hooks).sort(compareHooks).forEach(function(hook)
{

@@ -20,3 +21,3 @@ // in order to match hook should either the same length

{
config = this.hooks[hook](config);
config = this.hooks[hook].call(this, config);
}

@@ -27,1 +28,13 @@ }.bind(this));

}
/**
* Compares hook names shorter to longer and alphabetically
*
* @param {string} a - first key
* @param {string} b - second key
* @returns {number} -1 - `a` comes first, 0 - positions unchanged, 1 - `b` comes first
*/
function compareHooks(a, b)
{
return a.length < b.length ? -1 : (a.length > b.length ? 1 : (a < b ? -1 : (a > b ? 1 : 0)));
}

@@ -31,17 +31,16 @@ var typeOf = require('precise-typeof')

// create new running context with custom options
context = this.new(options || {});
// fallback to default directory
directory = directory || context.defaults.directory;
context = this.new(merge(options || {}, {directory: directory || this.defaults.directory}));
// prepare cache key
cacheKey = getCacheKey.call(context, directory);
cacheKey = getCacheKey.call(context);
if (!this._cache[cacheKey])
if (!(cacheKey in this._cache))
{
this.load(directory, context);
this.load(context);
}
// return immutable copy
return merge(this._cache[cacheKey]);
// always return object here
return merge(this._cache[cacheKey] || {});
}

@@ -117,2 +117,3 @@ var os = require('os')

'local',
this.defaults.customIncludeFiles,
this.defaults.customEnvVars,

@@ -119,0 +120,0 @@ 'runtime'

var getVar = require('./get_var.js')
, isObject = require('./is_object.js')
, isEmpty = require('./is_empty.js')
, notEmpty = require('./not_empty.js')

@@ -27,3 +29,3 @@ , parseTokens = require('./parse_tokens.js')

// try simple match first, for non-empty value
value = getVar(config[key], process.env);
value = getVar.call(this, config[key], process.env);

@@ -33,3 +35,3 @@ // if not, try parsing for variables

{
value = parseTokens(config[key], process.env);
value = parseTokens.call(this, config[key], process.env);
}

@@ -50,3 +52,3 @@

{
envVars(config[key], backRef.concat(key));
envVars.call(this, config[key], backRef.concat(key));
}

@@ -58,27 +60,5 @@ // Unsupported entry type

}
});
}.bind(this));
return config;
}
/**
* Check if provided variable is really an object
*
* @param {mixed} obj - variable to check
* @returns {boolean} true if variable is real object, false otherwise
*/
function isObject(obj)
{
return (obj !== null) && (typeof obj == 'object') && !(Array.isArray(obj));
}
/**
* Shortcut for positive checks
*
* @param {string} str - string to check
* @returns {boolean} - true is string is empty, false otherwise
*/
function isEmpty(str)
{
return !notEmpty(str);
}

@@ -14,3 +14,3 @@ var path = require('path')

*
* @param {string} directory - search directory
* @param {string} [directory] - search directory
* @returns {string} - cache key

@@ -20,2 +20,5 @@ */

{
// use the one from the context
directory = directory || this.directory;
return resolveDir(directory)

@@ -22,0 +25,0 @@ + ':'

@@ -1,11 +0,7 @@

var path = require('path')
, fs = require('fs')
, merge = require('deeply')
var merge = require('deeply')
, typeOf = require('precise-typeof')
, stripBOM = require('stripbom')
, applyHooks = require('./apply_hooks.js')
, getCacheKey = require('./get_cache_key.js')
, getFiles = require('./get_files.js')
, loadFiles = require('./load_files.js')
, mergeLayers = require('./merge_layers.js')
, resolveExts = require('./resolve_exts.js')
;

@@ -21,4 +17,4 @@

*
* @param {string} directory - directory to search for config files within
* @param {object} [context] - custom context to use for search and loading config files
* @param {string} [directory] - directory to search for config files within
* @param {function|object} [context] - custom context to use for search and loading config files
* @returns {object} - result merged config object

@@ -33,11 +29,21 @@ */

context = context || {};
// function|object passed as the first argument
// consider it `context`
if (typeOf(directory) == 'function' || typeOf(directory) == 'object')
{
context = directory;
directory = context.directory;
}
// create new context
// in case if function called directly with options object
context = typeof context == 'function' ? context : this.new(context || {});
// in case if `load` called without context
context = typeOf(context) == 'function' ? context : this.new(context);
// fallback to defaults
directory = directory || context.defaults.directory;
context.directory = directory || context.directory || context.defaults.directory;
// prepare cache key
cacheKey = getCacheKey.call(context, directory);
cacheKey = getCacheKey.call(context);

@@ -48,3 +54,3 @@ // get config files names suitable for the situation

// load all available files
layers = loadFiles.call(context, directory, files);
layers = loadFiles.call(context, context.directory, files);

@@ -57,95 +63,1 @@ // merge loaded layers

}
/**
* Loads and parses config from available files
*
* @param {string} dirs - directory to search in
* @param {array} files - list of files to search for
* @returns {array} - list of loaded configs in order of provided files
*/
function loadFiles(dirs, files)
{
// sort extensions to provide deterministic order of loading
var _instance = this
, extensions = resolveExts.call(this)
, layers = []
;
// treat all inputs as list of directories
dirs = (typeOf(dirs) == 'array') ? dirs : [dirs];
files.forEach(function(filename)
{
var layer = {file: filename, exts: []};
extensions.forEach(function(ext)
{
var layerExt = {ext: ext, dirs: []};
dirs.forEach(function(dir)
{
var cfg, file = path.resolve(dir, filename + '.' + ext);
if (fs.existsSync(file))
{
cfg = loadContent.call(_instance, file, _instance.parsers[ext]);
// check if any hooks needed to be applied
cfg = applyHooks.call(_instance, cfg, filename);
}
if (cfg)
{
layerExt.dirs.push({
dir : dir,
config: cfg
});
}
});
// populate with non-empty layers only
if (layerExt.dirs.length)
{
layer.exts.push(layerExt);
}
});
// populate with non-empty layers only
if (layer.exts.length)
{
layers.push(layer);
}
});
return layers;
}
/**
* Loads and parses provided file (synchronous).
*
* @param {string} file - absolute path to the file
* @param {function} parser - function to parse provided content and return config object
* @returns {object} - parsed config object
*/
function loadContent(file, parser)
{
var content, config;
try
{
content = stripBOM(fs.readFileSync(file, {encoding: 'utf8'}));
// provide file path as the second argument for complex parsing,
// also it matches `module._compile` nodejs API.
// Note: JSON.parse accepts two arguments, but ignores anything
// but function on the second place, so it's safe to pass a filename
// Other parsers might need to have wrappers.
config = parser(content, file);
}
catch (e)
{
throw new Error('Config file ' + file + ' cannot be read or malformed.');
}
return config;
}

@@ -16,3 +16,3 @@ var merge = require('deeply');

var _instance = this
, result = {}
, result = null
;

@@ -30,3 +30,3 @@

'array': _instance.arrayMerge
}, result, cfg.config);
}, result || {}, cfg.config);
});

@@ -36,3 +36,5 @@ });

// return `null` if noting found
// and let downstream layers to make the decision
return result;
}

@@ -26,3 +26,3 @@ var getVar = require('./get_var.js')

{
var value = getVar(name, env);
var value = getVar.call(this, name, env);

@@ -35,3 +35,3 @@ // need to have `found` counter

return value;
});
}.bind(this));
}

@@ -38,0 +38,0 @@

{
"name": "configly",
"version": "4.0.3",
"version": "4.1.0",
"description": "A developer-friendly lightweight replacement for the 'config' module that works with custom config directory and pluggable parsers",

@@ -8,2 +8,3 @@ "main": "index.js",

"lint": "eslint index.js test/*.js",
"ci-lint": "is-node-modern && npm run lint || is-node-not-modern",
"test": "nyc --reporter=lcov --reporter=text --check-coverage --lines 99 --functions 99 --branches 99 tape test/*.js | tap-spec",

@@ -58,3 +59,3 @@ "debug": "tape test/*.js | tap-spec"

"deeply": "^2.0.3",
"fulcon": "^1.0.1",
"fulcon": "^1.0.2",
"precise-typeof": "^1.0.2",

@@ -64,18 +65,19 @@ "stripbom": "^3.0.0"

"devDependencies": {
"coffee-script": "^1.10.0",
"coveralls": "^2.11.12",
"cson": "^3.0.2",
"eslint": "^2.13.1",
"hjson": "^2.0.5",
"coffee-script": "^1.11.1",
"coveralls": "^2.11.14",
"cson-parser": "^1.3.4",
"eslint": "^3.8.0",
"hjson": "^2.3.1",
"ini": "^1.3.4",
"is-node-modern": "^1.0.0",
"js-yaml": "^3.6.1",
"json5": "^0.5.0",
"nyc": "^8.1.0",
"nyc": "^8.3.1",
"pre-commit": "^1.1.3",
"properties": "^1.2.1",
"sinon": "^1.17.5",
"sinon": "^1.17.6",
"tap-spec": "^4.1.1",
"tape": "^4.6.0",
"tape": "^4.6.2",
"toml": "^2.3.0"
}
}

@@ -6,2 +6,3 @@ # configly [![NPM Module](https://img.shields.io/npm/v/configly.svg?style=flat)](https://www.npmjs.com/package/configly)

[![Linux Build](https://img.shields.io/travis/alexindigo/configly/master.svg?label=linux:0.10-6.x&style=flat)](https://travis-ci.org/alexindigo/configly)
[![MacOS Build](https://img.shields.io/travis/alexindigo/configly/master.svg?label=macos:0.10-6.x&style=flat)](https://travis-ci.org/alexindigo/configly)
[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/configly/master.svg?label=windows:0.10-6.x&style=flat)](https://ci.appveyor.com/project/alexindigo/configly)

@@ -53,3 +54,5 @@

var ini = require('ini');
var cson = require('cson');
// Note: recommended to use `cson-parser` over `cson`
// due to https://github.com/groupon/cson-parser/issues/56
var cson = require('cson-parser');
var yaml = require('js-yaml');

@@ -236,2 +239,95 @@ var properties = require('properties');

### Custom Environment Variables
It allows to combine environment variables within a single entry (e.g. `"endpoint": "${REMOTE_HOST}:${REMOTE_PORT}"`), which helps to keep application config consumption simple and to the point, and gives greater control over different environments, like using Docker environment variables for linked containers.
`custom-environment-variables.json`:
```json
{
"Customers":
{
"dbPassword" :"ENV_VAR_NAME_AS_STRING",
"dbPassword2" :"${ENV_VAR_NAME_VARIABLE}"
},
"CombinedWithText" : "${VARPART1}:${VARPART2}",
"BothVarsEmptyWillBeSkippedCompletely" : "${NOEXISTING} + another ${EMPTY} var"
}
```
### Custom Include Files
For better integration with other configuration systems and third-party tools that generate configs, `configly` can "mount" custom config files into specified entries, for example if you need to pull webpack manifest files into app's config).
`custom-include-files.json`:
```json
{
"MyModule": {
"WillBeIgnored": "NONEXISTENT_FILE",
"and": {
"here": {
"some": {
"nested": {
"structure": "custom_file"
}
}
}
}
},
"AnotherModule": {
"yes": {
"it": {
"should": {
"be": {
"filename": {
"no": {
"extension": "../include_files/another_file"
}
}
}
}
}
}
}
}
```
In the above example it will check for following custom files, (given `NODE_ENV` equals `production`):
- `custom_file.js`
- `custom_file.json`
- `custom_file-production.js`
- `custom_file-production.json`
- `../include_files/another_file.js`
- `../include_files/another_file.json`
- `../include_files/another_file-production.js`
- `../include_files/another_file-production.json`
And will attach their content to the respective branches.
### Custom Hooks
Developers can extend `configly`'s functionality with custom hooks for config files. For example if you need to pull in sensitive into your config and it couldn't be stored on disk among rest of the configuration data, you can add your own hooks to relace placeholders or attach extra values with data pull from the environment or from a secure storage. All hooks should be synchronous.
```javascript
var customHooks = merge(configly.hooks, {
// will be applied to `local`, `local-development` and other `local*` files
// expects `config` object of the parsed file
local: function(config)
{
iterate(config, function(value, key, node)
{
// increments each value by 4
node[key] = value + 4;
});
// expected to return updated object
return config;
}
});
var config = configly(configDir, {hooks: customHooks});
```
### Migration from `config`

@@ -374,4 +470,5 @@

- Configly provides deterministic (and controllable) order of the file extensions it loads from.
- Configly provides post-load hooks for config files, (e.g. `custom-environment-variables` works via this mechanism).
- Configly provides post-load hooks for config files, (e.g. `custom-environment-variables` and `custom-include-files` work via this mechanism).
- Configly provides ability to combine environment variables within one entry (e.g. `"endpoint": "${REMOTE_HOST}:${REMOTE_PORT}"`).
- Configly provides ability to "mount" custom config files into specified entries (useful to pull webpack manifest files into app's config).
- Configly provides access to the underlying functions and defaults, allowing to utilize parts of the functionality for greater flexibility.

@@ -387,5 +484,4 @@

## License
Configly is licensed under the MIT license.
Configly is released under the MIT license.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc