UNPKG

8.04 kBJavaScriptView Raw
1'use strict';
2
3const fs = require('fs');
4const vm = require('vm');
5
6const query = require('./query');
7const style = require('./style');
8const emojify = require('./emojify');
9const colorize = require('./colorize');
10
11const {
12 camelize, deepClone, distinct, expand, filter, flatten, formatBytes, formatNumber, merge,
13 precisionRound, project, range, remove, resolve, resolves, set, setTypes, size, unique,
14} = require('./utils');
15
16Math.$round = precisionRound;
17
18Number.$asBytes = formatBytes;
19Number.$format = formatNumber;
20Number.$range = range;
21
22Object.$expand = expand;
23Object.$filter = filter;
24Object.$flatten = flatten;
25Object.$project = project;
26Object.$query = query;
27Object.$remove = remove;
28Object.$resolve = resolve;
29Object.$resolves = resolves;
30Object.$set = set;
31Object.$setTypes = setTypes;
32Object.$size = size;
33
34//////////
35
36Object.defineProperty(Array.prototype, '$all', {
37 value (predicate) {
38 return this.reduce((acc, value) => acc && predicate(value), true);
39 },
40 enumerable: false,
41 configurable: true,
42});
43
44/**
45 * For arrays of objects that have an id field find the object that matches
46 * the passed in id. If the Array has an item that's not an Object, or an item
47 * does not contain a valid 'id', or we don't find the id 'needle' then return
48 * undefined
49 * @param needle
50 * @param caseInsensitive
51 * @returns {*}
52 */
53Object.defineProperty(Array.prototype, '$byId', {
54 value (needle, caseInsensitive) {
55 return this.byKey('id', needle, caseInsensitive);
56 },
57 enumerable: false,
58 configurable: true,
59});
60
61/**
62 * For arrays of objects that have an name field find the object that matches
63 * the passed in name. If the Array has an item that's not an Object, or an item
64 * does not contain a valid 'name', or we don't find the name 'needle' then return
65 * undefined
66 * @param needle
67 * @param caseInsensitive
68 * @returns {*}
69 */
70Object.defineProperty(Array.prototype, '$byName', {
71 value (needle, caseInsensitive) {
72 return this.byKey('name', needle, caseInsensitive);
73 },
74 enumerable: false,
75 configurable: true,
76});
77
78/**
79 * For arrays of objects that have the specified key field find the object that matches
80 * the passed in needle value. If the Array has an item that's not an Object, or an item
81 * does not contain a valid key field, or we don't find the name 'needle' then return
82 * undefined
83 * @param key
84 * @param needle
85 * @param caseInsensitive
86 * @returns {*}
87 */
88Object.defineProperty(Array.prototype, '$byKey', {
89 value (key, needle, caseInsensitive) {
90 for (let i = 0; this.length; i++) {
91 if (typeof this[i] !== 'object') {
92 return undefined;
93 }
94 if (!this[i][key]) {
95 return undefined;
96 }
97 if (this[i][key] === needle) {
98 return this[i];
99 }
100 if (caseInsensitive && this[i][key].toLowerCase() === needle.toLowerCase()) {
101 return this[i];
102 }
103 }
104 return undefined;
105 },
106 enumerable: false,
107 configurable: true,
108});
109
110Object.defineProperty(Array.prototype, '$distinct', {
111 value (selector) {
112 return distinct(this, selector);
113 },
114 enumerable: false,
115 configurable: true,
116});
117
118Object.defineProperty(Array.prototype, '$first', {
119 value () {
120 if (this.length) {
121 return this[0];
122 }
123 return undefined;
124 },
125 enumerable: false,
126 configurable: true,
127});
128
129Object.defineProperty(Array.prototype, '$last', {
130 value () {
131 if (this.length) {
132 return this[this.length - 1];
133 }
134 return undefined;
135 },
136 enumerable: false,
137 configurable: true,
138});
139
140Object.defineProperty(Array.prototype, '$none', {
141 value (predicate) {
142 return this.reduce((acc, value) => !acc && !predicate(value), false);
143 },
144 enumerable: false,
145 configurable: true,
146});
147
148Object.defineProperty(Array.prototype, '$partition', {
149 value (predicate) {
150 return this.reduce((result, item) => {
151 const [ listA, listB ] = result;
152
153 if (predicate(item) === true) {
154 listA.push(item);
155 } else {
156 listB.push(item);
157 }
158
159 return result;
160 }, [ [], [] ]);
161 },
162 enumerable: false,
163 configurable: true,
164});
165
166Object.defineProperty(Array.prototype, '$pick', {
167 value (count, asArray) {
168 const arr = this.slice();
169 const picks = [];
170
171 if (count === 1 && arr.length === 1) {
172 return arr[0];
173 } else if (count >= arr.length) {
174 return arr;
175 }
176
177 while (picks.length < count) {
178 const i = arr.$random();
179 picks.push(arr[i]);
180 arr.splice(i, 1);
181 }
182
183 if (picks.length === 1 && !asArray) {
184 return picks[0];
185 }
186 return picks;
187 },
188 enumerable: false,
189 configurable: true,
190});
191
192Object.defineProperty(Array.prototype, '$random', {
193 value () {
194 return Math.floor(Math.random() * this.length);
195 },
196 enumerable: false,
197 configurable: true,
198});
199
200Object.defineProperty(Array.prototype, '$shuffle', {
201 value () {
202 let j;
203 let x;
204 let i;
205
206 for (i = this.length; i; i--) {
207 j = Math.floor(Math.random() * i);
208 x = this[i - 1];
209 this[i - 1] = this[j];
210 this[j] = x;
211 }
212 return this;
213 },
214 enumerable: false,
215 configurable: true,
216});
217
218Object.defineProperty(Array.prototype, '$some', {
219 value (predicate) {
220 return this.reduce((acc, value) => acc || predicate(value), false);
221 },
222 enumerable: false,
223 configurable: true,
224});
225
226Object.defineProperty(Array.prototype, '$unique', {
227 value () {
228 return unique(this);
229 },
230 enumerable: false,
231 configurable: true,
232});
233
234//////////
235
236/**
237 * Colorize a string with a common color name.
238 * @param colorName
239 */
240Object.defineProperty(String.prototype, '$colorize', {
241 value (colorName) {
242 return colorize(colorName, this);
243 },
244 enumerable: false,
245 configurable: true,
246});
247
248/**
249 * Colorize a string with RGB values
250 * @param {Array} rgbArray
251 */
252Object.defineProperty(String.prototype, '$rgb', {
253 value (rgbArray) {
254 return colorize.rgb(rgbArray, this);
255 },
256 enumerable: false,
257 configurable: true,
258});
259
260/**
261 * Style a string
262 * @param {Object|string} a
263 * @param {Array|string} b
264 */
265Object.defineProperty(String.prototype, '$style', {
266 value (a, b) {
267 return style(this, a, b);
268 },
269 enumerable: false,
270 configurable: true,
271});
272
273/**
274 * Remove whitespace from a string
275 */
276Object.defineProperty(String.prototype, '$stripWhitespace', {
277 value () {
278 return this.replace(/\s/g, '');
279 },
280 enumerable: false,
281 configurable: true,
282});
283
284/**
285 * Emojify a string (parse out and substitute all :emoji:)
286 */
287Object.defineProperty(String.prototype, '$emojify', {
288 value () {
289 return emojify(this);
290 },
291 enumerable: false,
292 configurable: true,
293});
294
295/**
296 * Capitalize the first letter of a string
297 */
298Object.defineProperty(String.prototype, '$capitalize', {
299 value () {
300 return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
301 },
302 enumerable: false,
303 configurable: true,
304});
305
306/**
307 * Camelcase a string
308 */
309Object.defineProperty(String.prototype, '$camelize', {
310 value () {
311 return camelize(this);
312 },
313 enumerable: false,
314 configurable: true,
315});
316
317/**
318 * Read a JSON file through a sandbox to ensure it is a clean object
319 */
320JSON.$read = function (path) {
321 return vm.runInNewContext(`JSON.parse(fs.readFileSync('${ path }'));`, { fs });
322};
323
324JSON.$write = function (path, object) {
325 return fs.writeFileSync(path, JSON.stringify(object, null, 2));
326};
327
328Object.$clone = function (object, deep = false) {
329 if (deep) {
330 return deepClone(object);
331 }
332 return JSON.parse(JSON.stringify(object));
333};
334
335Object.$deepClone = function (object) {
336 return deepClone(object);
337};
338
339Object.$merge = function (objectA, objectB, createNew = false) {
340 return merge(objectA, objectB, createNew);
341};
342
343/**
344 * Add a non-enumerable property to an object. If the property already exists, just set it
345 */
346Object.$private = function (body, key, value) {
347 if (typeof body !== 'object') {
348 return;
349 }
350 if (body.hasOwnProperty(key)) {
351 body[key] = value;
352 } else {
353 Object.defineProperty(body, key, {
354 value,
355 enumerable: false,
356 writable: true,
357 configurable: true,
358 });
359 }
360};