defined-options
Version:
Define option properties with optional validation, filter and default value. Read, write, validate and merge option values as simple as possible.
146 lines (125 loc) • 4.71 kB
JavaScript
'use strict';
var is = require('validate-by-shorthand');
var Option = require('./option.js');
function Options(definitions) {
Object.defineProperty(this, '__options', {value: {}});
this.defineOptions(definitions);
}
Options.prototype.defineOption = function(name, defs) {
var definition = name;
if (is('object!empty', defs)) {
definition = defs;
definition.name = name;
}
var option = new Option(definition, this);
this.removeOption(option.name)
.__options[option.name] = option;
Object.defineProperty(this, option.name, {
get: function() {
return this.__options[option.name].value;
},
set: function(value) {
this.__options[option.name].value = value;
},
configurable: true,
enumerable: true
});
return this;
};
Options.prototype.defineOptions = function(definitions) {
definitions = is('object{}', definitions) ? definitions : {};
Object.keys(definitions).forEach(function(optionName) {
this.defineOption(optionName, definitions[optionName]);
}.bind(this));
return this;
};
Options.prototype.removeOption = function(optionName) {
if (this.hasOption(optionName)) {
delete this[optionName];
delete this.__options[optionName];
}
return this;
};
Options.prototype.hasOption = function(optionName) {
return this.hasOwnProperty(optionName) && this.__options.hasOwnProperty(optionName) ?
true : false;
};
Options.prototype.getPlainObject = function() {
return Object.keys(this).reduce(function(options, optionName) {
options[optionName] = this[optionName];
return options;
}.bind(this), {});
};
Options.prototype.mergeOptionValues = function() {
var args = arguments;
Object.keys(args).forEach(function(i) {
var values = is('object', args[i]) ? args[i] : {};
Object.keys(values).filter(function(optionName) {
return this.hasOption(optionName);
}.bind(this)).forEach(function(optionName) {
this[optionName] = values[optionName];
}.bind(this));
}.bind(this));
return this;
};
Options.prototype.merge = Options.prototype.mergeOptionValues;
Options.prototype.mergeOptions = function() {
var args = arguments;
Object.keys(args).forEach(function(i) {
var options = is('object', args[i]) ? args[i] : {};
if (options.constructor === this.constructor) {
var definitions = options.getOptionDefinitions();
this.defineOptions(Object.keys(definitions).reduce(function(opts, optionName) {
opts[optionName] = Object.keys(Option.properties).reduce(function(opt, propertyName) {
opt[propertyName] = definitions[optionName][propertyName];
return opt;
}, {});
return opts;
}, {}));
}
}.bind(this));
return this;
};
Options.prototype.getOptionDefinition = function(optionName) {
return this.__options[optionName];
};
Options.prototype.getOptionDefinitions = function() {
return this.__options;
};
Options.prototype.setDefaultOptionValue = function(optionName) {
if (this.hasOption(optionName)) {
this.__options[optionName].setDefault();
}
return this;
};
Options.prototype.setDefaultOptionValues = function() {
Object.keys(this.__options).forEach(this.setDefaultOptionValue.bind(this));
return this;
};
Options.prototype.default = function(optionName) {
if (optionName !== undefined) {
this.setDefaultOptionValue(optionName);
} else {
this.setDefaultOptionValues();
}
return this;
};
Options.prototype.validateOptionValue = function(optionName, value) {
value = Object.keys(arguments).length > 1 ? value : this[optionName];
return is.call(this.__options[optionName], this.__options[optionName].validate, value);
};
Options.prototype.validateOptionValues = function(values, ignoreUnknown) {
values = values === undefined ? this.getPlainObject() : values;
ignoreUnknown = ignoreUnknown === undefined ? false : true;
return is('object', values) && Object.keys(values).every(function(optionName) {
return (!this.hasOption(optionName) && ignoreUnknown) ||
(this.hasOption(optionName) && this.validateOptionValue(optionName, values[optionName]));
}.bind(this));
};
Options.prototype.validate = function() {
if (is('string', arguments[0])) {
return this.hasOption.apply(this, arguments) && this.validateOptionValue.apply(this, arguments);
}
return this.validateOptionValues.apply(this, arguments);
};
module.exports = Options;