Skip to content

Commit

Permalink
Merge 94ace62 into 4fbb627
Browse files Browse the repository at this point in the history
  • Loading branch information
erikkemperman committed Jul 18, 2017
2 parents 4fbb627 + 94ace62 commit 105ddaa
Show file tree
Hide file tree
Showing 3 changed files with 349 additions and 22 deletions.
90 changes: 70 additions & 20 deletions index.js
@@ -1,6 +1,5 @@
'use strict';

var koalas = require('koalas');
var normalize = require('value-or-function');

var slice = Array.prototype.slice;
Expand All @@ -12,49 +11,100 @@ function createResolver(config, options) {

var resolver = {
resolve: resolve,
isConstant: isConstant,
};

var lastKey;
// Keep constants separately
var constants = {};

// Keep requested keys to detect (and disallow) recursive resolution
var stack = [];

function resolve(key) {
if (typeof key !== 'string') {
return;
}

var appliedArgs = slice.call(arguments, 1);
if (isConstant(key)) {
return constants[key];
}

var definition = config[key];
// Ignore options that are not defined
if (!definition) {
return;
}

if (key === lastKey) {
if (stack.some(function(s) {
if (key === s) {
return true;
}
})) {
throw new Error('Recursive resolution denied.');
}
lastKey = key;

var option = options[key];
// Bind the option so it can resolve other options if necessary
if (typeof option === 'function') {
option = option.bind(resolver);
stack.push(key);
try {
var option = options[key];
var appliedArgs = slice.call(arguments, 1);
var args = [definition.type, option].concat(appliedArgs);

if (typeof option === 'function') {
option = normalize.apply(null, args);
} else {
option = null;
}

if (option === null) {
option = definition.default;
if (typeof option === 'function') {
option = option.apply(resolver, appliedArgs);
}
}

stack.pop();
return option;

} catch (err) {
stack.pop();
throw err;
}
}


function isConstant(key) {
return constants.hasOwnProperty(key);
}

var args = [definition.type, option].concat(appliedArgs);
var result = normalize.apply(null, args);

// Pre-process
options = Object.keys(config).reduce(function(opts, key) {

var definition = config[key];
var option = options[key];

if (!!option || options.hasOwnProperty(key)) {
if (typeof option !== 'function') {
option = normalize.call(null, definition.type, option);
if (option !== null) {
constants[key] = option;
return opts;
}
// Fall through
} else {
opts[key] = option.bind(resolver);
return opts;
}
}

var fallback = definition.default;
// Bind & apply the default so it can resolve other options if necessary
if (typeof fallback === 'function') {
fallback = fallback.apply(resolver, appliedArgs);
if (typeof fallback !== 'function') {
constants[key] = fallback;
}

lastKey = null;
return opts;
}, {});

return koalas(result, fallback);
}

return resolver;
}


module.exports = createResolver;
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -24,7 +24,6 @@
"coveralls": "npm run cover && istanbul-coveralls"
},
"dependencies": {
"koalas": "^1.0.2",
"value-or-function": "^2.0.0"
},
"devDependencies": {
Expand Down

0 comments on commit 105ddaa

Please sign in to comment.