@lumjs/core 1.19.0 → 1.21.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.
- package/lib/observable.js +30 -8
- package/lib/types/index.js +2 -2
- package/lib/types/isa.js +137 -4
- package/package.json +1 -1
package/lib/observable.js
CHANGED
|
@@ -4,11 +4,11 @@ const {duplicateAll: clone} = require('./obj/copyall');
|
|
|
4
4
|
const lock = Object.freeze;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Make
|
|
7
|
+
* Make a target object (or function) support the *Observable* API.
|
|
8
8
|
*
|
|
9
9
|
* Adds `on()`, `off()`, `one()`, and `trigger()` methods.
|
|
10
10
|
*
|
|
11
|
-
* @param {object} el - The
|
|
11
|
+
* @param {(object|function)} el - The target 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
14
|
*
|
|
@@ -78,13 +78,29 @@ const lock = Object.freeze;
|
|
|
78
78
|
*
|
|
79
79
|
* @param {string} [opts.addre] If set, add a method with this name
|
|
80
80
|
* to the `el` object, which is a function that can re-build the
|
|
81
|
-
* observable API methods with new `opts` replacing the old ones.
|
|
81
|
+
* observable API methods with new `opts` replacing the old ones.
|
|
82
|
+
*
|
|
83
|
+
* The method added takes two arguments, the first being an `object`
|
|
84
|
+
* representing the new options to set on the target.
|
|
85
|
+
*
|
|
86
|
+
* The second is an optional `boolean` value that determines if the
|
|
87
|
+
* existing `opts` should be used as defaults for any options not
|
|
88
|
+
* specified in the first argument.
|
|
89
|
+
*
|
|
90
|
+
* @param {boolean} [opts.reinherit=false] Used as the default value of
|
|
91
|
+
* the second argument of the method added by `opts.addre`.
|
|
92
|
+
*
|
|
93
|
+
* @param {boolean} [redefine=false] If `true` allow targets already
|
|
94
|
+
* implementing the `on()` and `trigger()` methods to be re-initialized.
|
|
95
|
+
*
|
|
96
|
+
* Generally only needed if you need to change the `opts` for some reason.
|
|
97
|
+
* This is forced to `true` by the method added by `opts.addre`.
|
|
82
98
|
*
|
|
83
99
|
* @returns {object} el
|
|
84
100
|
*
|
|
85
101
|
* @exports module:@lumjs/core/observable
|
|
86
102
|
*/
|
|
87
|
-
function observable (el={}, opts={})
|
|
103
|
+
function observable (el={}, opts={}, redefine=false)
|
|
88
104
|
{
|
|
89
105
|
//console.debug("observable", el, opts);
|
|
90
106
|
|
|
@@ -93,7 +109,7 @@ function observable (el={}, opts={})
|
|
|
93
109
|
throw new Error("non-object sent to observable()");
|
|
94
110
|
}
|
|
95
111
|
|
|
96
|
-
if (
|
|
112
|
+
if (isObservable(el) && !redefine)
|
|
97
113
|
{ // It's already observable.
|
|
98
114
|
return el;
|
|
99
115
|
}
|
|
@@ -338,9 +354,15 @@ function observable (el={}, opts={})
|
|
|
338
354
|
|
|
339
355
|
if (addre)
|
|
340
356
|
{ // Add a method to change the observable options.
|
|
341
|
-
|
|
357
|
+
const reinherit = opts.reinherit ?? false;
|
|
358
|
+
|
|
359
|
+
add(addre, function(replacementOpts={}, inherit=reinherit)
|
|
342
360
|
{
|
|
343
|
-
|
|
361
|
+
const newOpts
|
|
362
|
+
= inherit
|
|
363
|
+
? Object.assign({}, opts, replacementOpts)
|
|
364
|
+
: replacementOpts;
|
|
365
|
+
return observable(el, replacementOpts, true);
|
|
344
366
|
});
|
|
345
367
|
}
|
|
346
368
|
|
|
@@ -362,7 +384,7 @@ module.exports = observable;
|
|
|
362
384
|
*/
|
|
363
385
|
function isObservable(obj)
|
|
364
386
|
{
|
|
365
|
-
return (
|
|
387
|
+
return (isComplex(obj)
|
|
366
388
|
&& typeof obj.trigger === F
|
|
367
389
|
&& typeof obj.on === F);
|
|
368
390
|
}
|
package/lib/types/index.js
CHANGED
|
@@ -31,7 +31,7 @@ const
|
|
|
31
31
|
const {root, unbound} = require('./root');
|
|
32
32
|
|
|
33
33
|
// Advanced type checks.
|
|
34
|
-
const {isInstance, isType, isa} = require('./isa');
|
|
34
|
+
const {isInstance, isType, isArrayOf, isa} = require('./isa');
|
|
35
35
|
|
|
36
36
|
// Error-throwing type checks.
|
|
37
37
|
const {needObj, needType, needs} = require('./needs');
|
|
@@ -55,7 +55,7 @@ module.exports =
|
|
|
55
55
|
isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
|
|
56
56
|
nonEmptyArray, isArguments, isProperty, doesDescriptor,
|
|
57
57
|
isInstance, isType, isa, needObj, needType, needs, stringify,
|
|
58
|
-
doesDescriptorTemplate, ownCount,
|
|
58
|
+
doesDescriptorTemplate, ownCount, isArrayOf,
|
|
59
59
|
console,
|
|
60
60
|
}
|
|
61
61
|
|
package/lib/types/isa.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const {O, F, S} = require('./js');
|
|
2
|
-
const {isObj} = require('./basics');
|
|
2
|
+
const {isObj,isArray} = require('./basics');
|
|
3
3
|
const TYPES = require('./typelist');
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -126,8 +126,8 @@ function processOptions(type, v)
|
|
|
126
126
|
* @param {*} v - The value we're testing.
|
|
127
127
|
* @param {...any} types - The types the value should be one of.
|
|
128
128
|
*
|
|
129
|
-
* For each of the `types`, if it is a `string`
|
|
130
|
-
* if it is a `function` we test with `isInstance()`.
|
|
129
|
+
* For each of the `types`, by default if it is a `string`
|
|
130
|
+
* we test with `isType()`, if it is a `function` we test with `isInstance()`.
|
|
131
131
|
*
|
|
132
132
|
* If it is an `object` and has an `is()` method, use that as the test.
|
|
133
133
|
*
|
|
@@ -139,7 +139,9 @@ function processOptions(type, v)
|
|
|
139
139
|
* - `parsers: function`, Add another options parser function.
|
|
140
140
|
* - `process: function`, A one-time set-up function.
|
|
141
141
|
* - `test: function`, Pass the `v` to this test and return `true` if it passes.
|
|
142
|
-
* -
|
|
142
|
+
* - `typeof: boolean`, If `true` use `typeof` instead of `isType()` for tests.
|
|
143
|
+
* - `instanceof: boolean`, If `true` use `instanceof` instead of `isInstance()`.
|
|
144
|
+
* - Anything else will be set as an option that may be used by other parsers.
|
|
143
145
|
*
|
|
144
146
|
* Any other type value will only match if `v === type`
|
|
145
147
|
*
|
|
@@ -154,6 +156,8 @@ function isa(v, ...types)
|
|
|
154
156
|
needProto: false,
|
|
155
157
|
parsers: [DEFAULT_ISA_PARSER],
|
|
156
158
|
process: processOptions,
|
|
159
|
+
typeof: false,
|
|
160
|
+
instanceof: false,
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
for (const type of types)
|
|
@@ -164,10 +168,12 @@ function isa(v, ...types)
|
|
|
164
168
|
// With that out of the way, let's go!
|
|
165
169
|
if (typeof type === S)
|
|
166
170
|
{ // A string is passed to isType()
|
|
171
|
+
if (opts.typeof && typeof v === type) return true;
|
|
167
172
|
if (isType(type, v)) return true;
|
|
168
173
|
}
|
|
169
174
|
else if (typeof type === F)
|
|
170
175
|
{ // A function is passed to isInstance()
|
|
176
|
+
if (opts.instanceof && v instanceof type) return true;
|
|
171
177
|
if (isInstance(v, type, opts.needProto)) return true;
|
|
172
178
|
}
|
|
173
179
|
else if (isObj(type))
|
|
@@ -181,3 +187,130 @@ function isa(v, ...types)
|
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
exports.isa = isa;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extended return value from `isArrayOf()`.
|
|
193
|
+
*
|
|
194
|
+
* Used if the `opts.details` option was `true`.
|
|
195
|
+
*
|
|
196
|
+
* @typedef module:@lumjs/core/types~IsArrayOfResult
|
|
197
|
+
*
|
|
198
|
+
* @prop {boolean} pass - Did the `isArrayOf()` test pass?
|
|
199
|
+
* @prop {boolean} empty - Was the array empty?
|
|
200
|
+
*
|
|
201
|
+
* @prop {object} [failed] Failure information;
|
|
202
|
+
* Only addedd if `pass` is false.
|
|
203
|
+
*
|
|
204
|
+
* @prop {number} failed.index - Index of item that caused the failure.
|
|
205
|
+
* Will be set to `-1` if the `opts.value` argument is not an Array,
|
|
206
|
+
* or if the array is empty and `opts.empty` was not set to `true`.
|
|
207
|
+
*
|
|
208
|
+
* @prop {mixed} failed.value - The item that caused the failure.
|
|
209
|
+
* Will be the `opts.value` itself if `failed.index` is `-1`.
|
|
210
|
+
*
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* See if every item in an Array passes an `isa()` test.
|
|
215
|
+
*
|
|
216
|
+
* @param {(object|Array)} opts - Options for this test function.
|
|
217
|
+
*
|
|
218
|
+
* If this argument is an `Array` it is assumed to be the
|
|
219
|
+
* `opts.value` named option.
|
|
220
|
+
*
|
|
221
|
+
* @param {Array} opts.value - The actual Array value to test.
|
|
222
|
+
* @param {boolean} [opts.details=false] Return detailed test results?
|
|
223
|
+
* @param {boolean} [opts.empty=false] Does an empty array pass the test?
|
|
224
|
+
*
|
|
225
|
+
* @param {...any} types - See {@link module:@lumjs/core/types.isa}.
|
|
226
|
+
*
|
|
227
|
+
* All arguments other than `opts` are passed to `isa()` with each item
|
|
228
|
+
* from the `opts.value` array as the subject of the test.
|
|
229
|
+
*
|
|
230
|
+
* @returns {(boolean|object)} Results of the test.
|
|
231
|
+
*
|
|
232
|
+
* If `opts.details` was `true` this will be a
|
|
233
|
+
* {@link module:@lumjs/core/types~IsArrayOfResult} object.
|
|
234
|
+
*
|
|
235
|
+
* Otherwise it will be a simple `boolean` value indicating
|
|
236
|
+
* if the test passed or failed.
|
|
237
|
+
*
|
|
238
|
+
* @alias module:@lumjs/core/types.isArrayOf
|
|
239
|
+
*/
|
|
240
|
+
function isArrayOf(opts, ...types)
|
|
241
|
+
{
|
|
242
|
+
if (!isObj(opts)) return false; // Failure right off the bat!
|
|
243
|
+
|
|
244
|
+
if (Array.isArray(opts))
|
|
245
|
+
{ // The array subject was passed.
|
|
246
|
+
opts = {value: opts};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let res; // Format depends on the options.
|
|
250
|
+
|
|
251
|
+
if (opts.details)
|
|
252
|
+
{
|
|
253
|
+
res =
|
|
254
|
+
{
|
|
255
|
+
pass: false,
|
|
256
|
+
empty: false,
|
|
257
|
+
failed:
|
|
258
|
+
{
|
|
259
|
+
index: -1,
|
|
260
|
+
value: val,
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else
|
|
265
|
+
{
|
|
266
|
+
res = false;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!isArray(opts.value)) return res;
|
|
270
|
+
|
|
271
|
+
if (opts.value.length === 0)
|
|
272
|
+
{ // An empty array.
|
|
273
|
+
if (opts.details)
|
|
274
|
+
{
|
|
275
|
+
res.empty = true;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!opts.empty)
|
|
279
|
+
{ // Empty arrays are failure unless `opts.empty` is true.
|
|
280
|
+
return res;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else
|
|
284
|
+
{ // Run the tests on each item.
|
|
285
|
+
for (let i=0; i < opts.value.length; i++)
|
|
286
|
+
{
|
|
287
|
+
const vi = opts.value[i];
|
|
288
|
+
|
|
289
|
+
if (opts.details)
|
|
290
|
+
{
|
|
291
|
+
res.failed.index = i;
|
|
292
|
+
res.failed.value = vi;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!isa(vi, ...types))
|
|
296
|
+
{ // An item did not pass the test.
|
|
297
|
+
return res;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// If we made it here, we passed.
|
|
303
|
+
if (opts.details)
|
|
304
|
+
{
|
|
305
|
+
res.pass = true;
|
|
306
|
+
delete res.failed;
|
|
307
|
+
}
|
|
308
|
+
else
|
|
309
|
+
{
|
|
310
|
+
res = true;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return res;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
exports.isArrayOf = isArrayOf;
|