wishthis/node_modules/resolve-options/index.js
2022-01-21 09:28:41 +01:00

111 lines
2.2 KiB
JavaScript

'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,
};
// Keep constants separately
var constants = {};
function resolveConstant(key) {
if (constants.hasOwnProperty(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;