-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuilderBuilder.js
executable file
·140 lines (129 loc) · 3.6 KB
/
builderBuilder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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;
}