@lumjs/core 1.15.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,233 @@
1
+
2
+ const {N,def} = require('../types');
3
+
4
+ /**
5
+ * Functions for adding values to arrays in different ways.
6
+ * @alias module:@lumjs/core/arrays.add
7
+ */
8
+ const ArrayAdd = module.exports = exports =
9
+ {
10
+ prepend, before, append, after, insert,
11
+ }
12
+
13
+ function _addWith(array, oldValue, newValue, ifMissing, fn)
14
+ {
15
+ let pos = array.indexOf(oldValue);
16
+
17
+ if (pos === -1)
18
+ {
19
+ if (typeof ifMissing === N)
20
+ {
21
+ pos = ifMissing;
22
+ }
23
+ else
24
+ {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ return fn(array, newValue, pos);
30
+ }
31
+
32
+ /**
33
+ * Prepend a value to an array.
34
+ *
35
+ * @param {Array} array - Array to add the value to.
36
+ * @param {*} value - Value to add to the array.
37
+ * @param {number} [pos=0] Position to prepend at.
38
+ *
39
+ * If `pos` is `0` then `array.unshift(value)` is used.
40
+ * Otherwise `array.splice(pos, 0, value)` is used.
41
+ *
42
+ * @returns {Array} `array`
43
+ * @alias module:@lumjs/core/arrays.add.prepend
44
+ */
45
+ function prepend(array, value, pos=0)
46
+ {
47
+ if (pos === 0)
48
+ {
49
+ array.unshift(value);
50
+ }
51
+ else
52
+ {
53
+ array.splice(pos, 0, value);
54
+ }
55
+
56
+ return array;
57
+ }
58
+
59
+ /**
60
+ * Append a value to an array.
61
+ *
62
+ * @param {Array} array - Array to add the value to.
63
+ * @param {*} value - Value to add to the array.
64
+ * @param {number} [pos=-1] Position to append at.
65
+ *
66
+ * If `pos` is `-1` then `array.push(value)` is used.
67
+ * Otherwise `array.splice(pos+1, 0, value)` is used.
68
+ *
69
+ * @returns {Array} `array`
70
+ * @alias module:@lumjs/core/arrays.add.append
71
+ */
72
+ function append(array, value, pos=-1)
73
+ {
74
+ if (pos === -1)
75
+ {
76
+ array.push(value);
77
+ }
78
+ else
79
+ {
80
+ array.splice(pos+1, 0, value);
81
+ }
82
+
83
+ return array;
84
+ }
85
+
86
+ /**
87
+ * Add a value to an array _before_ an existing value.
88
+ *
89
+ * This uses `prepend()` to add the value.
90
+ *
91
+ * @param {Array} array - Array to add the value to.
92
+ * @param {*} oldValue - Existing value to find.
93
+ * @param {*} newValue - Value to add to the array.
94
+ * @param {(number|false)} [ifMissing=0] If `oldValue` is not found.
95
+ *
96
+ * If this is a `number` it will be used as the `pos` argument.
97
+ *
98
+ * If this is `false` the function will not add the value at all,
99
+ * but will return `false` instead.
100
+ *
101
+ * @returns {(Array|false)} Usually the input `array`; but will return
102
+ * `false` if `ifMissing` was `false` and the `oldValue` was not found.
103
+ *
104
+ * @alias module:@lumjs/core/arrays.add.before
105
+ */
106
+ function before(array, oldValue, newValue, ifMissing=0)
107
+ {
108
+ return _addWith(array, oldValue, newValue, ifMissing, prepend);
109
+ }
110
+
111
+ /**
112
+ * Add a value to an array _after_ an existing value.
113
+ *
114
+ * This uses `append()` to add the value.
115
+ *
116
+ * @param {Array} array - Array to add the value to.
117
+ * @param {*} oldValue - Existing value to find.
118
+ * @param {*} newValue - Value to add to the array.
119
+ * @param {(number|false)} [ifMissing=-1] If `oldValue` is not found.
120
+ *
121
+ * If this is a `number` it will be used as the `pos` argument.
122
+ *
123
+ * If this is `false` the function will not add the value at all,
124
+ * but will return `false` instead.
125
+ *
126
+ * @returns {(Array|false)} Usually the input `array`; but will return
127
+ * `false` if `ifMissing` was `false` and the `oldValue` was not found.
128
+ *
129
+ * @alias module:@lumjs/core/arrays.add.after
130
+ */
131
+ function after(array, oldValue, newValue, ifMissing=-1)
132
+ {
133
+ return _addWith(array, oldValue, newValue, ifMissing, append);
134
+ }
135
+
136
+ /**
137
+ * Insert a value to an array using special logic.
138
+ *
139
+ * See the `pos` argument for the positioning logic used.
140
+ *
141
+ * @param {Array} array - Array to add the value to.
142
+ * @param {*} value - Value to add to the array.
143
+ * @param {number} [pos=-1] Position to insert at.
144
+ *
145
+ * If `pos` is less than `0` this uses `append()`;
146
+ * Otherwise it uses `prepend()`.
147
+ *
148
+ * @returns {Array} `array`
149
+ * @alias module:@lumjs/core/arrays.add.insert
150
+ */
151
+ function insert(array, value, pos=-1)
152
+ {
153
+ if (pos < 0)
154
+ {
155
+ return append(array, value, pos);
156
+ }
157
+ else
158
+ {
159
+ return prepend(array, value, pos);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * A wrapper class to provide helper methods to Arrays.
165
+ *
166
+ * Provides wrapped versions of `prepend()`, `append()`,
167
+ * `before()`, `after()`, and `insert()`.
168
+ *
169
+ * The methods obviously pass the array argument, so remove it from
170
+ * the argument signature when using the wrapper method. Other than that,
171
+ * the rest of the arguments are the same as the wrapped functions.
172
+ *
173
+ * @alias module:@lumjs/core/arrays.add.At
174
+ */
175
+ class ArrayAt
176
+ {
177
+ /**
178
+ * Build a wrapper around an array.
179
+ *
180
+ * @param {Array} array - Array to wrap.
181
+ */
182
+ constructor(array)
183
+ {
184
+ this.array = array;
185
+ }
186
+
187
+ /**
188
+ * Add wrappers for the helper functions to the Array directly.
189
+ *
190
+ * WARNING: This is monkey patching the array object instance.
191
+ * If you're okay with that, cool.
192
+ *
193
+ * Otherwise, use a new `ArrayAt` object instance instead.
194
+ *
195
+ * @param {Array} array - Array to add methods to.
196
+ *
197
+ * @returns {Array} The input `array`
198
+ */
199
+ static extend(array)
200
+ {
201
+ for (const methName in ArrayAdd)
202
+ {
203
+ const methFunc = ArrayAdd[methName];
204
+ def(array, methName, methFunc.bind(array, array));
205
+ }
206
+ return array;
207
+ }
208
+
209
+ /**
210
+ * A static method that calls `new ArrayAt(array)`;
211
+ *
212
+ * @param {Array} array - Array to wrap
213
+ * @returns {module:@lumjs/core/arrays.ArrayAt} A new instance.
214
+ */
215
+ static new(array)
216
+ {
217
+ return new this(array);
218
+ }
219
+
220
+ } // ArrayAt class
221
+
222
+ // Set up ArrayAt methods, and export the functions.
223
+ for (const methName in ArrayAdd)
224
+ {
225
+ const methFunc = ArrayAdd[methName];
226
+
227
+ def(ArrayAt.prototype, methName, function()
228
+ {
229
+ methFunc(this.array, ...arguments);
230
+ });
231
+ }
232
+
233
+ def(ArrayAdd, 'At', ArrayAt);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Array helper libraries
3
+ *
4
+ * @module @lumjs/core/arrays
5
+ */
6
+
7
+ const {lazy} = require('../types');
8
+ const {powerset, random} = require('./util');
9
+
10
+ // Utils.
11
+ exports.powerset = powerset;
12
+ exports.random = random;
13
+
14
+ // List stuff.
15
+ lazy(exports, 'List', () => require('./list'));
16
+ lazy(exports, 'containsAny', () => exports.List.containsAny);
17
+ lazy(exports, 'containsAll', () => exports.List.containsAll);
18
+ lazy(exports, 'removeItems', () => exports.List.removeItems);
19
+
20
+ // Add functions and At class.
21
+ lazy(exports, 'add', () => require('./add'));
@@ -1,8 +1,5 @@
1
- /**
2
- * Array (and other list objects) helper functions.
3
- * @module @lumjs/core/arrays
4
- */
5
- const {F,S} = require('./types/js');
1
+
2
+ const {F,S} = require('../types');
6
3
 
7
4
  /**
8
5
  * A wrapper class to abstract functionality of various kinds of lists.
@@ -278,6 +275,8 @@ function containsAny(list, ...items)
278
275
  return List.for(list, CONTAINS_OPTS).containsAny(...items);
279
276
  }
280
277
 
278
+ List.containsAny = containsAny;
279
+
281
280
  /**
282
281
  * See if a list contains *all* of the specified items.
283
282
  *
@@ -291,6 +290,8 @@ function containsAll(list, ...items)
291
290
  return List.for(list, CONTAINS_OPTS).containsAll(...items);
292
291
  }
293
292
 
293
+ List.containsAll = containsAll;
294
+
294
295
  const REMOVE_OPTS = {closures: ['remove']};
295
296
 
296
297
  /**
@@ -309,42 +310,6 @@ function removeItems(list, ...items)
309
310
  return List.for(list, REMOVE_OPTS).removeAll(...items);
310
311
  }
311
312
 
312
- /**
313
- * Return a Powerset of values in the array.
314
- * @param {Array} array The array to make the powerset from.
315
- * @returns {Array} The powerset.
316
- * @alias module:@lumjs/core/arrays.powerset
317
- */
318
- function powerset(array)
319
- {
320
- var ps = [[]];
321
- for (var i=0; i < array.length; i++)
322
- {
323
- // we modify the ps array in the next loop,
324
- // so can't use the ps.length property directly in the loop condition.
325
- var current_length = ps.length;
326
- for (var j = 0; j < current_length; j++)
327
- {
328
- ps.push(ps[j].concat(array[i]));
329
- }
330
- }
331
- return ps;
332
- }
333
-
334
- /**
335
- * Get a random element from an array.
336
- * @param {Array} array The array to get an item from.
337
- * @returns {mixed} The randomly selected item.
338
- * @alias module:@lumjs/core/arrays.random
339
- */
340
- function random(array)
341
- {
342
- return array[Math.floor(Math.random()*array.length)];
343
- }
344
-
345
- module.exports = exports =
346
- {
347
- List, containsAny, containsAll,
348
- removeItems, powerset, random,
349
- }
313
+ List.removeItems = removeItems;
350
314
 
315
+ module.exports = exports = List;
@@ -0,0 +1,38 @@
1
+
2
+ /**
3
+ * Return a Powerset of values in the array.
4
+ * @param {Array} array The array to make the powerset from.
5
+ * @returns {Array} The powerset.
6
+ * @alias module:@lumjs/core/arrays.powerset
7
+ */
8
+ function powerset(array)
9
+ {
10
+ var ps = [[]];
11
+ for (var i=0; i < array.length; i++)
12
+ {
13
+ // we modify the ps array in the next loop,
14
+ // so can't use the ps.length property directly in the loop condition.
15
+ var current_length = ps.length;
16
+ for (var j = 0; j < current_length; j++)
17
+ {
18
+ ps.push(ps[j].concat(array[i]));
19
+ }
20
+ }
21
+ return ps;
22
+ }
23
+
24
+ /**
25
+ * Get a random element from an array.
26
+ * @param {Array} array The array to get an item from.
27
+ * @returns {mixed} The randomly selected item.
28
+ * @alias module:@lumjs/core/arrays.random
29
+ */
30
+ function random(array)
31
+ {
32
+ return array[Math.floor(Math.random()*array.length)];
33
+ }
34
+
35
+ module.exports = exports =
36
+ {
37
+ powerset, random,
38
+ }
package/lib/index.js CHANGED
@@ -44,6 +44,13 @@ def(exports, 'lazy', lazy);
44
44
  */
45
45
  lazy(exports, 'arrays', () => require('./arrays'));
46
46
 
47
+ /**
48
+ * Map utility functions «Lazy»
49
+ * @name module:@lumjs/core.maps
50
+ * @type {module:@lumjs/core/maps}
51
+ */
52
+ lazy(exports, 'maps', () => require('./maps'));
53
+
47
54
  /**
48
55
  * Information about the JS context we're running in
49
56
  * @name module:@lumjs/core.context
package/lib/maps.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Map object helper functions.
3
+ * @module @lumjs/core/maps
4
+ */
5
+ const {F,isObj} = require('./types/js');
6
+
7
+ /**
8
+ * Build a `Map` instance out of various types of objects.
9
+ *
10
+ * @param {object} input - An object to be converted into a `Map`.
11
+ *
12
+ * Supported object types:
13
+ *
14
+ * - `Array`, `Map`, or any other object with an `entries()` method.
15
+ * - Implements `Iterable` interface (`[Symbol.iterator]`).
16
+ * - Implements `Iterator` interface (`next()`).
17
+ * - Anything other object we'll use all enumerable properties.
18
+ *
19
+ * @returns {Map}
20
+ * @alias module:@lumjs/core/maps.mapOf
21
+ */
22
+ function mapOf(input)
23
+ {
24
+ if (!isObj(input))
25
+ {
26
+ throw new TypeError('Non-object passed to mapOf');
27
+ }
28
+
29
+ if (typeof input.entries === F)
30
+ { // Short-cut for Arrays, other Maps, etc.
31
+ return new Map(input.entries());
32
+ }
33
+
34
+ const map = new Map();
35
+
36
+ if (typeof input[Symbol.iterator] === F)
37
+ { // Using the Iterable interface.
38
+ let i = 0;
39
+ for (const value of input)
40
+ {
41
+ map.set(i++, value);
42
+ }
43
+ }
44
+ else if (typeof thing.next === F)
45
+ { // Using the Iterator interface.
46
+ let i = 0, next;
47
+
48
+ while ((next = input.next()) && !next.done)
49
+ {
50
+ map.set(i++, next.value);
51
+ }
52
+ }
53
+ else
54
+ { // A plain old object. Use enumerable properties.
55
+ for (const key in input)
56
+ {
57
+ map.set(key, input[key]);
58
+ }
59
+ }
60
+
61
+ return map;
62
+ }
63
+
64
+ module.exports =
65
+ {
66
+ mapOf,
67
+ }
@@ -0,0 +1,52 @@
1
+ const {F,isObj} = require('../types');
2
+ const copyProps = require('./copyprops');
3
+
4
+ /**
5
+ * Apply functions to an object
6
+ *
7
+ * In addition to the parameters passed, we'll also define:
8
+ *
9
+ * - `cp` will be a `CopyProps` instance via `copyProps.cache.into(obj)`;
10
+ * - `args` will be an array of `[obj, opts]`;
11
+ * - `opts` will be an object of `{obj, cp, args}`;
12
+ *
13
+ * @param {(object|function)} obj - The target we're applying to.
14
+ *
15
+ * @param {...(function|object)} fns - Values we are applying.
16
+ *
17
+ * For each value of `fns` as `fn`:
18
+ *
19
+ * - If a `function` we'll call `fn.apply(obj, args)`;
20
+ * - If an `object` we'll call `cp.from(fn)`.
21
+ *
22
+ * @returns {object} `obj`
23
+ * @throws {TypeError} If a `fns` value is not valid.
24
+ * @alias module:@lumjs/core/obj.apply
25
+ */
26
+ function apply(obj, ...fns)
27
+ {
28
+ const cp = copyProps.cache.into(obj);
29
+ const opts = {obj, cp};
30
+ const args = [obj, opts];
31
+ opts.args = args;
32
+
33
+ for (const fn of fns)
34
+ {
35
+ if (typeof fn === F)
36
+ {
37
+ fn.apply(obj, args);
38
+ }
39
+ else if (isObj(fn))
40
+ {
41
+ cp.from(fn);
42
+ }
43
+ else
44
+ {
45
+ throw new TypeError("invalid parameter value");
46
+ }
47
+ }
48
+
49
+ return obj;
50
+ }
51
+
52
+ module.exports = apply;
@@ -39,7 +39,7 @@ exports.duplicateOne = copyAll.clone = obj => copyAll({}, obj);
39
39
  *
40
40
  * Use `copyProps.into({}).from(...sources)` for a more robust version.
41
41
  *
42
- * Alias: `copyAll.clone`
42
+ * Alias: `copyAll.duplicate`
43
43
  *
44
44
  * @alias module:@lumjs/core/obj.duplicateOne
45
45
  * @param {object} obj - The object to duplicate.
@@ -1,7 +1,7 @@
1
1
 
2
2
  // Get some constants
3
- const {B,N,F,isObj,isArray,needObj,def,console} = require('../types');
4
- const {duplicateOne: clone} = require('./copyall');
3
+ const {S,B,N,F,isObj,isArray,needObj,def,console} = require('../types');
4
+ const {copyAll, duplicateOne: clone} = require('./copyall');
5
5
 
6
6
  const RECURSE_NONE = 0;
7
7
  const RECURSE_ALL = -1;
@@ -233,22 +233,35 @@ def(copyProps, 'RECURSE_LIST', RECURSE_LIST);
233
233
  * // Get a copy of the `copyProps` function.
234
234
  * const cp = require('@lumjs/core').obj.copyProps;
235
235
  *
236
- * // Starting with the target:
236
+ * // Starting with the target(s):
237
237
  * cp.into(targetObj).given({all: true}).from(source1, source2);
238
238
  *
239
- * // Starting with the sources:
239
+ * // Starting with the source(s):
240
240
  * cp.from(sourceObj).given({exclude: ['dontCopy']}).into(target1, target2);
241
241
  *
242
242
  * // Starting with the options:
243
243
  * cp.given({recursive: cp.RECURSE_ALL}).from(source1, source2).into(target1, target2);
244
244
  *
245
+ * // Call `cp.into()` and cache the instance in a `Map`.
246
+ * // Future calls with the same `targetObj` will return the cached instance.
247
+ * // Unlike `cp.into()`, only supports a single `targetObj`.
248
+ * cp.cache.into(targetObj);
249
+ *
250
+ * // Call `cp.from()` and cache the instance in a `Map`.
251
+ * // Future calls with the same `sourceObj` will return the cached instance.
252
+ * // Unlike `cp.from()`, only supports a single `sourceObj`.
253
+ * cp.cache.from(sourceObj);
245
254
  *
255
+ * // Clear the `Map` instances for `cp.cache.into` and `cp.cache.from`
256
+ * cp.cache.clear();
257
+ *
246
258
  * ```
247
259
  *
248
260
  * @alias module:@lumjs/core/obj~CopyProps
249
261
  */
250
262
  class $CopyProps
251
263
  {
264
+ // Constructor is private so we won't document it.
252
265
  constructor(opts={})
253
266
  {
254
267
  this.opts = opts;
@@ -257,21 +270,42 @@ class $CopyProps
257
270
  }
258
271
 
259
272
  /**
260
- * Set a single option.
261
- * @param {string} name - The option name
262
- * @param {*} value - The option value
273
+ * Set options.
274
+ *
275
+ * @param {(string|object)} opt - Option(s) to set.
276
+ *
277
+ * If this is a `string` it's the name of an option to set.
278
+ * If this is an `object`, it's map of options to set with `copyAll`.
279
+ *
280
+ * @param {*} value - The option value.
281
+ *
282
+ * Only used if `option` is a `string`.
283
+ *
263
284
  * @returns {object} `this`
264
285
  */
265
- set(name, value)
286
+ set(opt, value)
266
287
  {
267
- this.opts[name] = value;
288
+ //console.debug("CopyProps.set(", opt, value, ')');
289
+ if (typeof opt === S)
290
+ { // Set a single option.
291
+ this.opts[opt] = value;
292
+ }
293
+ else if (isObj(opt))
294
+ { // Set a bunch of options.
295
+ copyAll(this.opts, opt);
296
+ }
297
+ else
298
+ { // That's not supported
299
+ console.error("invalid opt", {opt, value, cp: this});
300
+ }
301
+ //console.debug("CopyProps.set:after", this);
268
302
  return this;
269
303
  }
270
304
 
271
305
  /**
272
- * Set all of the options.
306
+ * Set all options.
273
307
  *
274
- * This replaces the currently set options entirely.
308
+ * This replaces any existing options entirely.
275
309
  *
276
310
  * @param {object} opts - The options to set.
277
311
  * @returns {object} `this`
@@ -372,4 +406,48 @@ copyProps.from = function(...sources)
372
406
  return ((new $CopyProps()).from(...sources));
373
407
  }
374
408
 
409
+ const CPC = copyProps.cache =
410
+ {
411
+ into(target)
412
+ {
413
+ if (this.intoCache === undefined)
414
+ this.intoCache = new Map();
415
+ const cache = this.intoCache;
416
+ if (cache.has(target))
417
+ {
418
+ return cache.get(target);
419
+ }
420
+ else
421
+ {
422
+ const cp = copyProps.into(target);
423
+ cache.set(target, cp);
424
+ return cp;
425
+ }
426
+ },
427
+ from(source)
428
+ {
429
+ if (this.fromCache === undefined)
430
+ this.fromCache = new Map();
431
+ const cache = this.fromCache;
432
+ if (cache.has(source))
433
+ {
434
+ return cache.get(source);
435
+ }
436
+ else
437
+ {
438
+ const cp = copyProps.from(source);
439
+ cache.set(source, cp);
440
+ return cp;
441
+ }
442
+ },
443
+ clear()
444
+ {
445
+ if (this.intoCache)
446
+ this.intoCache.clear();
447
+ if (this.fromCache)
448
+ this.fromCache.clear();
449
+ return this;
450
+ },
451
+ };
452
+
375
453
  module.exports = copyProps;
package/lib/obj/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * @module @lumjs/core/obj
4
4
  */
5
5
 
6
+ const apply = require('./apply');
6
7
  const {copyAll,duplicateOne,duplicateAll} = require('./copyall');
7
8
  const copyProps = require('./copyprops');
8
9
  const {CLONE,clone,addClone,cloneIfLocked} = require('./clone');
@@ -23,5 +24,5 @@ module.exports =
23
24
  mergeNested, syncNested, copyProps, copyAll, ns,
24
25
  getObjectPath, setObjectPath, getNamespace, setNamespace,
25
26
  getProperty, duplicateAll, duplicateOne, getMethods, signatureOf,
26
- MethodFilter,
27
+ MethodFilter, apply,
27
28
  }