123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- '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;
|