UNPKG

6.01 kBJavaScriptView Raw
1'use strict';
2
3var extend = require('extend');
4var expand = require('./lib/expand');
5var Utils = require('./lib/utils');
6var flatten = require('./lib/flatten');
7var MODE_FLAT = 'flat';
8var MODE_NESTED = 'nested';
9var MODES = [MODE_FLAT, MODE_NESTED];
10
11/**
12 * Object wrapping class.
13 */
14var Homefront = function Homefront(data, mode) {
15 this.data = data || {};
16
17 this.setMode(mode);
18};
19
20var staticAccessors = { MODE_NESTED: {},MODE_FLAT: {} };
21
22/**
23 * Recursively merges given sources into data.
24 *
25 * @param {...Object} sources One or more, or array of, objects to merge into data (left to right).
26 *
27 * @return {Homefront}
28 */
29staticAccessors.MODE_NESTED.get = function () {
30 return MODE_NESTED;
31};
32
33/**
34 * @return {string}
35 */
36staticAccessors.MODE_FLAT.get = function () {
37 return MODE_FLAT;
38};
39
40Homefront.prototype.merge = function merge (sources) {
41 var this$1 = this;
42
43 sources = Array.isArray(sources) ? sources : Array.prototype.slice.call(arguments);
44 var mergeData = [];
45
46 sources.forEach(function (source) {
47 if (!source) {
48 return;
49 }
50
51 if (source instanceof Homefront) {
52 source = source.data;
53 }
54
55 mergeData.push(this$1.isModeFlat() ? flatten(source) : expand(source));
56 });
57
58 extend.apply(extend, [true, this.data].concat(mergeData));
59
60 return this;
61};
62
63/**
64 * Static version of merge, allowing you to merge objects together.
65 *
66 * @param {...Object} sources One or more, or array of, objects to merge (left to right).
67 *
68 * @return {{}}
69 */
70Homefront.merge = function merge (sources) {
71 sources = Array.isArray(sources) ? sources : Array.prototype.slice.call(arguments);
72
73 return extend.apply(extend, [true].concat(sources));
74};
75
76/**
77 * Sets the mode.
78 *
79 * @param {String} [mode] Defaults to nested.
80 *
81 * @returns {Homefront} Fluent interface
82 *
83 * @throws {Error}
84 */
85Homefront.prototype.setMode = function setMode (mode) {
86 mode = mode || MODE_NESTED;
87
88 if (MODES.indexOf(mode) === -1) {
89 throw new Error(
90 ("Invalid mode supplied. Must be one of \"" + (MODES.join('" or "')) + "\"")
91 );
92 }
93
94 this.mode = mode;
95
96 return this;
97};
98
99/**
100 * Gets the mode.
101 *
102 * @return {String}
103 */
104Homefront.prototype.getMode = function getMode () {
105 return this.mode;
106};
107
108/**
109 * Expands flat object to nested object.
110 *
111 * @return {{}}
112 */
113Homefront.prototype.expand = function expand$1 () {
114 return this.isModeNested() ? this.data : expand(this.data);
115};
116
117/**
118 * Flattens nested object (dot separated keys).
119 *
120 * @return {{}}
121 */
122Homefront.prototype.flatten = function flatten$1 () {
123 return this.isModeFlat() ? this.data : flatten(this.data);
124};
125
126/**
127 * Returns whether or not mode is flat.
128 *
129 * @return {boolean}
130 */
131Homefront.prototype.isModeFlat = function isModeFlat () {
132 return this.mode === MODE_FLAT;
133};
134
135/**
136 * Returns whether or not mode is nested.
137 *
138 * @return {boolean}
139 */
140Homefront.prototype.isModeNested = function isModeNested () {
141 return this.mode === MODE_NESTED;
142};
143
144/**
145 * Convenience method. Calls .fetch(), and on null result calls .put() using provided toPut.
146 *
147 * @param {String|Array} key
148 * @param {*} toPut
149 *
150 * @return {*}
151 */
152Homefront.prototype.fetchOrPut = function fetchOrPut (key, toPut) {
153 var wanted = this.fetch(key);
154
155 if (wanted === null) {
156 wanted = toPut;
157
158 this.put(key, toPut);
159 }
160
161 return wanted;
162};
163
164/**
165 * Fetches value of given key.
166 *
167 * @param {String|Array} key
168 * @param {*} [defaultValue] Value to return if key was not found
169 *
170 * @returns {*}
171 */
172Homefront.prototype.fetch = function fetch (key, defaultValue) {
173 defaultValue = typeof defaultValue === 'undefined' ? null : defaultValue;
174
175 if (typeof this.data[key] !== 'undefined') {
176 return this.data[key];
177 }
178
179 if (this.isModeFlat()) {
180 return defaultValue;
181 }
182
183 var keys = Utils.normalizeKey(key);
184 var lastKey = keys.pop();
185 var tmp = this.data;
186
187 for (var i = 0; i < keys.length; i++) {
188 if (typeof tmp[keys[i]] === 'undefined') {
189 return defaultValue;
190 }
191
192 tmp = tmp[keys[i]];
193 }
194
195 return typeof tmp[lastKey] === 'undefined' ? defaultValue : tmp[lastKey];
196};
197
198/**
199 * Sets value for a key (creates object in path when not found).
200 *
201 * @param {String|Array} key Array of key parts, or dot separated key.
202 * @param {*} value
203 *
204 * @returns {Homefront}
205 */
206Homefront.prototype.put = function put (key, value) {
207 if (this.isModeFlat() || key.indexOf('.') === -1) {
208 this.data[key] = value;
209
210 return this;
211 }
212
213 var keys = Utils.normalizeKey(key);
214 var lastKey = keys.pop();
215 var tmp = this.data;
216
217 keys.forEach(function (value) {
218 if (typeof tmp[value] === 'undefined') {
219 tmp[value] = {};
220 }
221
222 tmp = tmp[value];
223 });
224
225 tmp[lastKey] = value;
226
227 return this;
228};
229
230/**
231 * Removes value by key.
232 *
233 * @param {String} key
234 *
235 * @returns {Homefront}
236 */
237Homefront.prototype.remove = function remove (key) {
238 if (this.isModeFlat() || key.indexOf('.') === -1) {
239 delete this.data[key];
240
241 return this;
242 }
243
244 var normalizedKey = Utils.normalizeKey(key);
245 var lastKey = normalizedKey.pop();
246 var source = this.fetch(normalizedKey);
247
248 if (typeof source === 'object') {
249 delete source[lastKey];
250 }
251
252 return this;
253};
254
255/**
256 * Search and return keys and values that match given string.
257 *
258 * @param {String|Number} phrase
259 *
260 * @returns {Array}
261 */
262Homefront.prototype.search = function search (phrase) {
263 var found = [];
264 var data= this.data;
265
266 if (this.isModeNested()) {
267 data = flatten(this.data);
268 }
269
270 Object.getOwnPropertyNames(data).forEach(function (key) {
271 var searchTarget = Array.isArray(data[key]) ? JSON.stringify(data[key]) : data[key];
272
273 if (searchTarget.search(phrase) > -1) {
274 found.push({key: key, value: data[key]});
275 }
276 });
277
278 return found;
279};
280
281Object.defineProperties( Homefront, staticAccessors );
282
283module.exports.flatten = flatten;
284module.exports.expand = expand;
285module.exports.expand = expand;
286module.exports.Homefront = Homefront;