UNPKG

builder-builder

Version:

A runtime builder generator for use in node, io or the browser

141 lines (129 loc) 3.68 kB
function builderBuilder(params) { 'use strict'; if (!params) { throw new Error('Missing required params argument in builderBuilder. This can contain required, optional and defaults'); } function warn() { if (console && console.warn) { console.warn.apply(console, arguments); } } function loop(arr, callback) { var key, returnVal; for (key in arr) { if (arr.hasOwnProperty(key)) { returnVal = callback(arr[key], key); if (returnVal === false) { return; } } } } function asArray(strOrArray) { return typeof strOrArray === 'object' ? strOrArray : [strOrArray]; } function capitalize(str) { return str.substr(0, 1).toUpperCase() + str.substr(1); } var constructor = function (getterOrObj) { var self = {}, state = {}, defaults = {}, required = asArray(params.required || []), optional = asArray(params.optional || []), names = required.concat(optional); if (params.defaults) { loop(params.defaults, function (val, paramName) { defaults[paramName] = val; if (names.indexOf(paramName) === -1) { names.push(paramName); } }); } function setter(name, value) { state[name] = value; return self; } loop(names, function (name) { var casedName = capitalize(name); self['with' + casedName] = setter.bind(null, name); self['without' + casedName] = function () { delete state[name]; return self; }; }); self.with = function (name, value) { if (names.indexOf(name) > -1) { setter(name, value); } else { warn('Key ', name, ' ignored as it wasn\'t defined in builder configuration'); } return self; }; self.listMissingFields = function () { var missing = []; loop(required, function (name) { if (state[name] === undefined && defaults[name] === undefined) { missing.push(name); } }); return missing; }; self.readFromObject = function (obj) { return self.readFromGetterFunction(function (name) { return obj[name]; }); }; self.readFromGetterFunction = function (getter) { loop(names, function (name) { var value = getter(name); if (value !== undefined) { setter(name, value); } }); return self; }; self.validate = function () { return self.listMissingFields().length === 0; }; self.buildWithoutValidating = function () { var built = {}; loop(names, function (name) { if (state.hasOwnProperty(name)) { built[name] = state[name]; } else if (defaults.hasOwnProperty(name)) { built[name] = defaults[name]; } }); if (params.postBuildHook) { built = params.postBuildHook(built); } return built; }; self.build = function () { if (!self.validate()) { throw new Error('Could not build as builder didn\'t validate: missing ' + self.listMissingFields().join(', ')); } return self.buildWithoutValidating(); }; self.clone = function () { var newBuilder = constructor(); loop(state, function (val, key) { newBuilder.with(key, val); }); return newBuilder; }; if (getterOrObj) { if (typeof getterOrObj === 'function') { self.readFromGetterFunction(getterOrObj); } else { self.readFromObject(getterOrObj); } } return self; }; return constructor; } if (typeof module === 'object') { module.exports = builderBuilder; }