-
Notifications
You must be signed in to change notification settings - Fork 221
/
Copy pathbaseutil.js
324 lines (299 loc) · 8.86 KB
/
baseutil.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
* Includes common utility methods and shims
*/
import {contains, isString} from "../util";
import {URL_KEYS} from '../constants';
export function omit(obj, keys) {
obj = obj || {};
let srcKeys = Object.keys(obj).filter(key => !contains(keys, key));
let filtered = {};
srcKeys.forEach(key => filtered[key] = obj[key]);
return filtered;
}
/**
* Return true if all items in list are strings
* @function Util.allString
* @param {Array} list - an array of items
*/
export var allStrings = function(list) {
return list.length && list.every(isString);
};
/**
* Creates a new array without the given item.
* @function Util.without
* @param {Array} array - original array
* @param {*} item - the item to exclude from the new array
* @return {Array} a new array made of the original array's items except for `item`
*/
export var without = function(array, item) {
return array.filter(v=>v!==item);
};
/**
* Return true is value is a number or a string representation of a number.
* @function Util.isNumberLike
* @param {*} value
* @returns {boolean} true if value is a number
* @example
* Util.isNumber(0) // true
* Util.isNumber("1.3") // true
* Util.isNumber("") // false
* Util.isNumber(undefined) // false
*/
export var isNumberLike = function(value) {
return (value != null) && !isNaN(parseFloat(value));
};
/**
* Escape all characters matching unsafe in the given string
* @function Util.smartEscape
* @param {string} string - source string to escape
* @param {RegExp} unsafe - characters that must be escaped
* @return {string} escaped string
*/
export var smartEscape = function(string, unsafe = /([^a-zA-Z0-9_.\-\/:]+)/g) {
return string.replace(unsafe, function(match) {
return match.split("").map(function(c) {
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
}).join("");
});
};
/**
* Assign values from sources if they are not defined in the destination.
* Once a value is set it does not change
* @function Util.defaults
* @param {Object} destination - the object to assign defaults to
* @param {...Object} source - the source object(s) to assign defaults from
* @return {Object} destination after it was modified
*/
export var defaults = function(destination, ...sources) {
return sources.reduce(function(dest, source) {
let key, value;
for (key in source) {
value = source[key];
if (dest[key] === void 0) {
dest[key] = value;
}
}
return dest;
}, destination);
};
/*********** lodash functions */
export var objectProto = Object.prototype;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
export var objToString = objectProto.toString;
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
#isObject({});
* // => true
*
#isObject([1, 2, 3]);
* // => true
*
#isObject(1);
* // => false
*/
export var isObject = function(value) {
var type;
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
type = typeof value;
return !!value && (type === 'object' || type === 'function');
};
export var funcTag = '[object Function]';
/**
* Checks if `value` is classified as a `Function` object.
* @function Util.isFunction
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* function Foo(){};
* isFunction(Foo);
* // => true
*
* isFunction(/abc/);
* // => false
*/
export var isFunction = function(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 which returns 'object' for typed array constructors.
return isObject(value) && objToString.call(value) === funcTag;
};
/*********** lodash functions */
/** Used to match words to create compound words. */
export var reWords = (function() {
var lower, upper;
upper = '[A-Z]';
lower = '[a-z]+';
return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');
})();
/**
* Convert string to camelCase
* @function Util.camelCase
* @param {string} source - the string to convert
* @return {string} in camelCase format
*/
export var camelCase = function(source) {
var words = source.match(reWords);
words = words.map(word=> word.charAt(0).toLocaleUpperCase() + word.slice(1).toLocaleLowerCase());
words[0] = words[0].toLocaleLowerCase();
return words.join('');
};
/**
* Convert string to snake_case
* @function Util.snakeCase
* @param {string} source - the string to convert
* @return {string} in snake_case format
*/
export var snakeCase = function(source) {
var words = source.match(reWords);
words = words.map(word=> word.toLocaleLowerCase());
return words.join('_');
};
/**
* Creates a new object from source, with the keys transformed using the converter.
* @param {object} source
* @param {function|null} converter
* @returns {object}
*/
export var convertKeys = function(source, converter) {
var result, value;
result = {};
for (let key in source) {
value = source[key];
if(converter) {
key = converter(key);
}
if (!isEmpty(key)) {
result[key] = value;
}
}
return result;
};
/**
* Create a copy of the source object with all keys in camelCase
* @function Util.withCamelCaseKeys
* @param {Object} value - the object to copy
* @return {Object} a new object
*/
export var withCamelCaseKeys = function(source) {
return convertKeys(source, camelCase);
};
/**
* Create a copy of the source object with all keys in snake_case
* @function Util.withSnakeCaseKeys
* @param {Object} value - the object to copy
* @return {Object} a new object
*/
export var withSnakeCaseKeys = function(source) {
return convertKeys(source, snakeCase);
};
// Browser
// Node.js
export var base64Encode = typeof btoa !== 'undefined' && isFunction(btoa) ? btoa : typeof Buffer !== 'undefined' && isFunction(Buffer) ? function(input) {
if (!(input instanceof Buffer)) {
input = new Buffer.from(String(input), 'binary');
}
return input.toString('base64');
} : function(input) {
throw new Error("No base64 encoding function found");
};
/**
* Returns the Base64-decoded version of url.<br>
* This method delegates to `btoa` if present. Otherwise it tries `Buffer`.
* @function Util.base64EncodeURL
* @param {string} url - the url to encode. the value is URIdecoded and then re-encoded before converting to base64 representation
* @return {string} the base64 representation of the URL
*/
export var base64EncodeURL = function(url) {
try {
url = decodeURI(url);
} finally {
url = encodeURI(url);
}
return base64Encode(url);
};
/**
* Create a new object with only URL parameters
* @param {object} options The source object
* @return {Object} An object containing only URL parameters
*/
export function extractUrlParams(options) {
return URL_KEYS.reduce((obj, key) => {
if (options[key] != null) {
obj[key] = options[key];
}
return obj;
}, {});
}
/**
* Handle the format parameter for fetch urls
* @private
* @param options url and transformation options. This argument may be changed by the function!
*/
export function patchFetchFormat(options) {
if(options == null) {
options = {};
}
if (options.type === "fetch") {
if (options.fetch_format == null) {
options.fetch_format = optionConsume(options, "format");
}
}
}
/**
* Deletes `option_name` from `options` and return the value if present.
* If `options` doesn't contain `option_name` the default value is returned.
* @param {Object} options a collection
* @param {String} option_name the name (key) of the desired value
* @param {*} [default_value] the value to return is option_name is missing
*/
export function optionConsume(options, option_name, default_value) {
let result = options[option_name];
delete options[option_name];
if (result != null) {
return result;
} else {
return default_value;
}
}
/**
* Returns true if value is empty:
* <ul>
* <li>value is null or undefined</li>
* <li>value is an array or string of length 0</li>
* <li>value is an object with no keys</li>
* </ul>
* @function Util.isEmpty
* @param value
* @returns {boolean} true if value is empty
*/
export function isEmpty(value) {
if(value == null) {
return true;
}
if( typeof value.length == "number") {
return value.length === 0;
}
if( typeof value.size == "number") {
return value.size === 0;
}
if(typeof value == "object") {
for(let key in value) {
if(value.hasOwnProperty(key)) {
return false;
}
}
return true;
}
return true;
}