File size: 2,274 Bytes
bc20498 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
'use strict';
var normalize = require('value-or-function');
var slice = Array.prototype.slice;
function createResolver(config, options) {
// TODO: should the config object be validated?
config = config || {};
options = options || {};
var resolver = {
resolve: resolve,
resolveConstant: resolveConstant,
};
// Keep constants separately
var constants = {};
function resolveConstant(key) {
if (Object.prototype.hasOwnProperty.call(constants, key)) {
return constants[key];
}
var definition = config[key];
// Ignore options that are not defined
if (!definition) {
return;
}
var option = options[key];
if (option != null) {
if (typeof option === 'function') {
return;
}
option = normalize.call(resolver, definition.type, option);
if (option != null) {
constants[key] = option;
return option;
}
}
var fallback = definition.default;
if (option == null && typeof fallback !== 'function') {
constants[key] = fallback;
return fallback;
}
}
// Keep requested keys to detect (and disallow) recursive resolution
var stack = [];
function resolve(key) {
var option = resolveConstant(key);
if (option != null) {
return option;
}
var definition = config[key];
// Ignore options that are not defined
if (!definition) {
return;
}
if (stack.indexOf(key) >= 0) {
throw new Error('Recursive resolution denied.');
}
option = options[key];
var fallback = definition.default;
var appliedArgs = slice.call(arguments, 1);
var args = [definition.type, option].concat(appliedArgs);
function toResolve() {
stack.push(key);
var option = normalize.apply(resolver, args);
if (option == null) {
option = fallback;
if (typeof option === 'function') {
option = option.apply(resolver, appliedArgs);
}
}
return option;
}
function onResolve() {
stack.pop();
}
return tryResolve(toResolve, onResolve);
}
return resolver;
}
function tryResolve(toResolve, onResolve) {
try {
return toResolve();
} finally {
onResolve();
}
}
module.exports = createResolver;
|