@lumjs/core 1.16.0 → 1.19.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
+ }
@@ -1,5 +1,5 @@
1
- const def = require('./def');
2
- const {F} = require('./js');
1
+ const def = require('./types/def');
2
+ const {F} = require('./types/js');
3
3
 
4
4
  /**
5
5
  * A super simple singleton wrapper around the Javascript console.
@@ -7,7 +7,7 @@ const {F} = require('./js');
7
7
  * By default includes `info`, `log`, `warn`, and `error` methods.
8
8
  * It may be expanded further using the `addMethod` method.
9
9
  *
10
- * @exports module:@lumjs/core/types/console
10
+ * @exports module:@lumjs/core/console
11
11
  */
12
12
  const LC =
13
13
  {
@@ -80,7 +80,7 @@ const LC =
80
80
 
81
81
  /**
82
82
  * A reference to the real console object.
83
- * @alias module:@lumjs/core/types/console.real
83
+ * @alias module:@lumjs/core/console.real
84
84
  */
85
85
  const RC = globalThis.console;
86
86
  def(LC, 'real', RC);
@@ -97,14 +97,14 @@ const HANDLER_OPTIONS =
97
97
  /**
98
98
  * Add a wrapper method to the console wrapper object.
99
99
  * @param {string} method - The console method to wrap.
100
- * @alias module:@lumjs/core/types/console.addMethod
100
+ * @alias module:@lumjs/core/console.addMethod
101
101
  */
102
102
  function addMethod(method)
103
103
  {
104
104
  def(LC, method, function(...args)
105
105
  {
106
106
  if (typeof LC.trigger === F)
107
- { // Support for core.observable(core.types.console);
107
+ { // Support for core.observable(core.console);
108
108
  LC.trigger(method, ...args);
109
109
  }
110
110
 
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
@@ -72,6 +79,13 @@ lazy(exports, 'flags', () => require('./flags'));
72
79
  */
73
80
  lazy(exports, 'obj', () => require('./obj'));
74
81
 
82
+ /**
83
+ * A wrapper around the Javascript console.
84
+ * @name module:@lumjs/core.console
85
+ * @type {module:@lumjs/core/console}
86
+ */
87
+ lazy(exports, 'console', () => require('./console'));
88
+
75
89
  /**
76
90
  * Functions for getting values and properties with fallback defaults «Lazy»
77
91
  * @name module:@lumjs/core.opt
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
+ }
package/lib/observable.js CHANGED
@@ -11,31 +11,46 @@ const lock = Object.freeze;
11
11
  * @param {object} el - The object we are making observable.
12
12
  * @param {object} [opts] Options that define behaviours.
13
13
  * @param {string} [opts.wildcard='*'] The event name used as a wildcard.
14
- * @param {boolean} [opts.wrapthis=false] If `true`, `this` will be a wrapper.
15
14
  *
16
- * If `wrapthis` is `true`, the function will be called with a wrapper object
17
- * as the `this` variable instead of the target object. The wrapper will be:
18
- *
15
+ * @param {boolean} [opts.wrapargs=false] If `true`, the event handlers will
16
+ * be passed a wrapper object as the sole argument:
17
+ *
19
18
  * ```js
20
- * {
19
+ * {
21
20
  * isObservable:
22
- * {
21
+ * { // Immutable;
23
22
  * event: true, // This is an event data object.
24
23
  * target: false, // This is not the target object.
25
24
  * },
26
- * self: el, // The target object.
27
- * name: event, // The event name that was triggered.
28
25
  * wildcard: bool, // Will be true if this was a wildcard event handler.
29
26
  * func: function, // The function being called.
30
27
  * args: array, // The arguments passed to trigger.
28
+ * self: el, // The target object.
29
+ * name: event, // The event name that was triggered.
30
+ * target: el, // An alias to `self`.
31
+ * type: event, // An alias to `name`.
32
+ * // ...
31
33
  * }
32
34
  * ```
33
35
  *
34
- * The object will be frozen so its values cannot be modified.
36
+ * @param {boolean} [opts.wrapthis=false] If `true`, `this` in event
37
+ * handlers will be the same object as `opts.wrapargs`.
38
+ *
39
+ * @param {?function} [opts.wrapsetup=null] Setup function for wrapper data.
40
+ *
41
+ * This function will be called with the target `el` as `this`,
42
+ * and will be passed the wrapper object (before it is locked),
43
+ * so it can examine the event name and arguments passed to
44
+ * `trigger()` and adjust the object accordingly.
35
45
  *
36
- * @param {boolean} [opts.wrapargs=false] If `true`, the functions will be
37
- * passed a single object as the sole argument. The object will be the same
38
- * as the one from `opts.wrapthis`.
46
+ * This allows the wrapper objects to have a lot more custom properties,
47
+ * and feel more like the standard Event objects used by the `DOM`.
48
+ *
49
+ * If this is specified, but neither `opts.wrapargs` or `opts.wrapthis`
50
+ * is `true`, then `opts.wrapargs` will be changed to `true` implicitly.
51
+ *
52
+ * @param {boolean} [opts.wraplock=true] If `true`, the wrapper object
53
+ * will be made immutable using the `Object.freeze()` method.
39
54
  *
40
55
  * @param {boolean} [opts.addname] If `true` callbacks with
41
56
  * multiple events will have the name of the triggered event added as
@@ -99,16 +114,24 @@ function observable (el={}, opts={})
99
114
  ? opts.wildcard
100
115
  : '*';
101
116
 
117
+ const wrapsetup = (typeof opts.wrapsetup === F)
118
+ ? opts.wrapsetup
119
+ : null;
120
+
102
121
  const wrapthis = (typeof opts.wrapthis === B)
103
122
  ? opts.wrapthis
104
123
  : false;
105
124
 
106
125
  const wrapargs = (typeof opts.wrapargs === B)
107
126
  ? opts.wrapargs
108
- : false;
127
+ : (wrapsetup ? !wrapthis : false);
109
128
 
110
129
  const wrapped = (wrapthis || wrapargs);
111
130
 
131
+ const wraplock = (typeof opts.wraplock === B)
132
+ ? opts.wraplock
133
+ : true;
134
+
112
135
  const addname = (typeof opts.addname === B)
113
136
  ? opts.addname
114
137
  : !wrapped;
@@ -154,15 +177,28 @@ function observable (el={}, opts={})
154
177
  { // Something is going to use our wrapper object.
155
178
  const isWild = (name === wildcard);
156
179
  const fname = isWild ? (addname ? args[0] : args.shift()) : name;
180
+
157
181
  fobj =
158
- lock({
182
+ {
159
183
  isObservable: lock({event: true, target: false}),
160
184
  self: el,
161
- name: fname,
185
+ target: el,
186
+ name: fname,
187
+ type: fname,
162
188
  func: fn,
163
189
  wildcard: isWild,
164
190
  args,
165
- });
191
+ };
192
+
193
+ if (wrapsetup)
194
+ {
195
+ wrapsetup.call(el, fobj);
196
+ }
197
+
198
+ if (wraplock)
199
+ {
200
+ lock(fobj);
201
+ }
166
202
  }
167
203
 
168
204
  const fthis = wrapthis ? fobj : el;