UNPKG

@plasmapay/options-resolver

Version:

Port of Symfony component OptionsResolver. This library processes and validates option object

546 lines (441 loc) 16.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.default = createResolver; var _array = require('lodash/array'); var _object = require('lodash/object'); var _lang = require('lodash/lang'); var _lang2 = _interopRequireDefault(_lang); var _collection = require('lodash/collection'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function createResolver() { var state = { defined: {}, defaults: {}, required: {}, resolved: {}, normalizers: {}, allowedValues: {}, allowedTypes: {}, lazy: {}, calling: {}, locked: false }; var clone = { locked: false }; function setDefault(option, value) { if (state.locked) { throw new Error('Default values cannot be set from a lazy option or normalizer.'); } if (!state.defined.hasOwnProperty(option) || null === state.defined[option] || state.resolved.hasOwnProperty(option)) { state.resolved[option] = value; } state.defaults[option] = value; state.defined[option] = true; return this; } function setDefaults(defaults) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = Object.keys(defaults)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var option = _step.value; setDefault(option, defaults[option]); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return this; } function hasDefault(option) { return state.defaults.hasOwnProperty(option); } function setRequired(optionNames) { if (state.locked) { throw new Error('Options cannot be made required from a lazy option or normalizer.'); } if (!Array.isArray(optionNames)) { optionNames = [optionNames]; } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = optionNames[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var option = _step2.value; state.defined[option] = true; state.required[option] = true; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return this; } function isRequired(option) { return state.required.hasOwnProperty(option) && null !== state.required[option]; } function getRequiredOptions() { return Object.keys(state.required); } function isMissing(option) { return isRequired(option) && !hasDefault(option); } function getMissingOptions() { return (0, _array.difference)(Object.keys(state.required), Object.keys(state.defaults)); } function setDefined(optionNames) { if (state.locked) { throw new Error('Options cannot be defined from a lazy option or normalizer.'); } if (!Array.isArray(optionNames)) { optionNames = [optionNames]; } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = optionNames[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var option = _step3.value; state.defined[option] = true; } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return this; } function isDefined(option) { return state.defined.hasOwnProperty(option) && null !== state.defined[option]; } function getDefinedOptions() { return Object.keys(state.defined); } function setNormalizer(option, normalizer) { if (state.locked) { throw new Error('Normalizers cannot be set from a lazy option or normalizer.'); } if (!isDefined(option)) { var definedOptions = Object.keys(state.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } state.normalizers[option] = normalizer; state.resolved = (0, _object.omit)(state.resolved, option); return this; } function setAllowedValues(option, values) { if (state.locked) { throw new Error('Allowed values cannot be set from a lazy option or normalizer.'); } if (!isDefined(option)) { var definedOptions = Object.keys(state.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } state.allowedValues[option] = Array.isArray(values) ? values : [values]; state.resolved = (0, _object.omit)(state.resolved, option); return this; } function addAllowedValues(option, values) { if (state.locked) { throw new Error('Allowed values cannot be set from a lazy option or normalizer.'); } if (!isDefined(option)) { var definedOptions = Object.keys(state.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } if (!Array.isArray(values)) { values = [values]; } if (!state.allowedValues.hasOwnProperty(option) || null === state.allowedValues[option]) { state.allowedValues[option] = values; } else { state.allowedValues[option] = [].concat(_toConsumableArray(state.allowedValues[option]), _toConsumableArray(values)); } state.resolved = (0, _object.omit)(state.resolved, option); return this; } function setAllowedTypes(option, types) { if (state.locked) { throw new Error('Allowed types cannot be set from a lazy option or normalizer.'); } if (!isDefined(option)) { var definedOptions = Object.keys(state.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } state.allowedTypes[option] = Array.isArray(types) ? types : [types]; state.resolved = (0, _object.omit)(state.resolved, option); return this; } function addAllowedTypes(option, types) { if (state.locked) { throw new Error('Allowed types cannot be set from a lazy option or normalizer.'); } if (!isDefined(option)) { var definedOptions = Object.keys(state.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } if (!Array.isArray(types)) { types = [types]; } if (!state.allowedTypes.hasOwnProperty(option) || null === state.allowedTypes[option]) { state.allowedTypes[option] = types; } else { state.allowedTypes[option] = [].concat(_toConsumableArray(state.allowedTypes[option]), _toConsumableArray(types)); } state.resolved = (0, _object.omit)(state.resolved, option); return this; } function remove(optionNames) { if (state.locked) { throw new Error('Options cannot be removed from a lazy option or normalizer.'); } state.defined = (0, _object.omit)(state.defined, optionNames); state.defaults = (0, _object.omit)(state.defaults, optionNames); state.required = (0, _object.omit)(state.required, optionNames); state.resolved = (0, _object.omit)(state.resolved, optionNames); state.lazy = (0, _object.omit)(state.lazy, optionNames); state.normalizers = (0, _object.omit)(state.normalizers, optionNames); state.allowedValues = (0, _object.omit)(state.allowedValues, optionNames); state.allowedTypes = (0, _object.omit)(state.allowedTypes, optionNames); return this; } function clear() { if (state.locked) { throw new Error('Options cannot be cleared from a lazy option or normalizer.'); } state.defined = {}; state.defaults = {}; state.required = {}; state.resolved = {}; state.lazy = {}; state.normalizers = {}; state.allowedValues = {}; state.allowedTypes = {}; state.calling = {}; return this; } function resolve() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return new Promise(function (resolve, reject) { if (state.locked) { var err = new Error('Options cannot be state.resolved from a lazy option or normalizer.'); return reject(err); } clone = _lang2.default.clone(state, true); var definedDiff = (0, _array.difference)(Object.keys(options), Object.keys(clone.defined)); if (definedDiff.length) { var definedKeys = (0, _collection.sortBy)(Object.keys(clone.defined)).join('", "'); var diffKeys = (0, _collection.sortBy)(definedDiff).join('", "'); var _err = 'The option(s) "' + diffKeys + '" do not exist. Defined options are: "' + definedKeys + '"'; return reject(_err); } clone.defaults = (0, _object.merge)(clone.defaults, options); clone.resolved = (0, _object.omit)(clone.resolved, Object.keys(options)); clone.lazy = (0, _object.omit)(clone.lazy, options); var requiredDiff = (0, _array.difference)(Object.keys(clone.required), Object.keys(clone.defaults)); if (requiredDiff.length) { var _diffKeys = (0, _collection.sortBy)(requiredDiff).join('", "'); var _err2 = 'The required options "' + _diffKeys + '" are missing'; return reject(_err2); } clone.locked = true; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = Object.keys(clone.defaults)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var option = _step4.value; get(option); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var resolved = _lang2.default.clone(clone.resolved, true); clone = { locked: false }; resolve(resolved); }); } function get(option) { if (!clone.locked) { throw new Error('get is only supported within closures of lazy options and normalizers.'); } if (clone.resolved.hasOwnProperty(option)) { return clone.resolved[option]; } if (!clone.defaults.hasOwnProperty(option)) { if (!clone.defined.hasOwnProperty(option) || null === clone.defined[option]) { var definedOptions = Object.keys(clone.defined).join('", "'); throw new Error('The option "' + option + '" does not exist. Defined options are : "' + definedOptions + '"'); } throw new Error('The optional option "' + option + '" has no value set. You should make sure it is set with "isset" before reading it.'); } var value = clone.defaults[option]; // @todo : process lazy option if (clone.allowedTypes.hasOwnProperty(option) && null !== clone.allowedTypes[option]) { var valid = false; var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = clone.allowedTypes[option][Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var allowedType = _step5.value; var functionName = 'is' + allowedType.charAt(0).toUpperCase() + allowedType.substr(1).toLowerCase(); if (_lang2.default.hasOwnProperty(functionName)) { if (_lang2.default[functionName](value)) { valid = true; break; } continue; } if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === allowedType) { valid = true; break; } } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } if (!valid) { // @todo add better log error throw new Error('Invalid type for option "' + option + '".'); } } if (clone.allowedValues.hasOwnProperty(option) && null !== clone.allowedValues[option]) { var success = false; var printableAllowedValues = []; var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = clone.allowedValues[option][Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var allowedValue = _step6.value; if (_lang2.default.isFunction(allowedValue)) { if (allowedValue(value)) { success = true; break; } continue; } else if (value === allowedValue) { success = true; break; } printableAllowedValues.push(allowedValue); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } if (!success) { var message = 'The option "' + option + '" is invalid.'; if (printableAllowedValues.length) { message += ' Accepted values are : ' + printableAllowedValues.join(', '); } throw new Error(message); } } if (clone.normalizers.hasOwnProperty(option) && null !== clone.normalizers[option]) { if (clone.calling.hasOwnProperty(option) && null !== clone.calling[option]) { var callingKeys = Object.keys(clone.calling).join('", "'); throw new Error('The options "' + callingKeys + '" have a cyclic dependency'); } var normalizer = clone.normalizers[option]; clone.calling[option] = true; try { value = normalizer(value); } finally { clone.calling = (0, _object.omit)(clone.calling, option); } } clone.resolved[option] = value; return value; } return { setDefault: setDefault, setDefaults: setDefaults, hasDefault: hasDefault, setRequired: setRequired, isRequired: isRequired, getRequiredOptions: getRequiredOptions, isMissing: isMissing, getMissingOptions: getMissingOptions, setDefined: setDefined, isDefined: isDefined, getDefinedOptions: getDefinedOptions, setNormalizer: setNormalizer, setAllowedValues: setAllowedValues, addAllowedValues: addAllowedValues, setAllowedTypes: setAllowedTypes, addAllowedTypes: addAllowedTypes, remove: remove, clear: clear, resolve: resolve, get: get }; } module.exports = exports['default'];