@lumjs/core 1.0.0-beta.1
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/CHANGELOG.md +17 -0
- package/README.md +27 -0
- package/TODO.md +23 -0
- package/index.js +64 -0
- package/package.json +15 -0
- package/src/context.js +47 -0
- package/src/descriptors.js +243 -0
- package/src/enum.js +123 -0
- package/src/flags.js +45 -0
- package/src/lazy.js +102 -0
- package/src/meta.js +61 -0
- package/src/obj/clone.js +201 -0
- package/src/obj/copyall.js +18 -0
- package/src/obj/copyprops.js +104 -0
- package/src/obj/index.js +18 -0
- package/src/obj/lock.js +64 -0
- package/src/obj/merge.js +74 -0
- package/src/obj/ns.js +194 -0
- package/src/objectid.js +85 -0
- package/src/observable.js +292 -0
- package/src/opt.js +60 -0
- package/src/prop.js +170 -0
- package/src/strings.js +76 -0
- package/src/types.js +545 -0
- package/test/types.js +185 -0
package/src/types.js
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
/// Type checking and other features common to everything else.
|
|
2
|
+
|
|
3
|
+
// Constants representing core Javascript types.
|
|
4
|
+
const O='object', F='function', S='string', B='boolean', N='number',
|
|
5
|
+
U='undefined', SY='symbol', BI='bigint';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A map of type names including special and union types.
|
|
9
|
+
*/
|
|
10
|
+
const TYPES =
|
|
11
|
+
{
|
|
12
|
+
O, F, S, B, N, U, SY, BI, ARGS: 'arguments', ARRAY: 'array', NULL:'null',
|
|
13
|
+
TYPEDARRAY: 'typedarray', DESCRIPTOR: 'descriptor', COMPLEX: 'complex',
|
|
14
|
+
SCALAR: 'scalar', PROP: 'property',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A flat array of the type names supported in the `TYPES` constant.
|
|
19
|
+
*/
|
|
20
|
+
const TYPE_LIST = [];
|
|
21
|
+
for (const t in TYPES) { TYPE_LIST.push(TYPES[t]); }
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* See if a value is a non-null `object`.
|
|
25
|
+
* @param {*} v - The value we're testing.
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
function isObj(v) { return (typeof v === O && v !== null); }
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* See if a value is *complex* (i.e. either `object` or `function`).
|
|
32
|
+
* Like `isObj()`, `null` does not count as an `object`.
|
|
33
|
+
* @param {*} v - The value we're testing.
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
function isComplex(v) { return (typeof v === F || isObj(v)); }
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* See if a value is *nil* (i.e. either `null` or `undefined`).
|
|
40
|
+
* @param {*} v - The value we're testing.
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
*/
|
|
43
|
+
function isNil(v) { return (v === undefined || v === null); }
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* See if a value is not *nil* (i.e. neither `null` nor `undefined`).
|
|
47
|
+
* @param {*} v - The value we're testing.
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
function notNil(v) { return (v !== undefined && v !== null); }
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* See if a value is a scalar.
|
|
54
|
+
* For the purposes of this, a scalar is any value which
|
|
55
|
+
* is neither *nil* nor *complex*.
|
|
56
|
+
* @param {*} v - The value we're testing.
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
function isScalar(v) { return (notNil(v) && !isComplex(v)); }
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* See if a value is an `Array` object.
|
|
63
|
+
* This is literally just a copy of `Array.isArray`.
|
|
64
|
+
* @param {*} v - The value we're testing.
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
const isArray = Array.isArray;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* See if a value is a `TypedArray` object.
|
|
71
|
+
* @param {*} v - The value we're testing.
|
|
72
|
+
* @returns {boolean}
|
|
73
|
+
*/
|
|
74
|
+
function isTypedArray(v)
|
|
75
|
+
{
|
|
76
|
+
return (ArrayBuffer.isView(v) && !(v instanceof DataView));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* See if a value is a non-empty Array.
|
|
81
|
+
* @param {*} v - The value we're testing.
|
|
82
|
+
* @param {boolean} [typed=false] If `true` we want a `TypedArray`.
|
|
83
|
+
* If `false` (default) we want a regular `Array`.
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
function nonEmptyArray(v, typed=false)
|
|
87
|
+
{
|
|
88
|
+
if (typed)
|
|
89
|
+
return (isTypedArray(v) && v.length > 0);
|
|
90
|
+
else
|
|
91
|
+
return (isArray(v) && v.length > 0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* See if a value is an `arguments` object.
|
|
96
|
+
* @param {*} v - The value we're testing.
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
function isArguments(v)
|
|
100
|
+
{
|
|
101
|
+
return Object.prototype.toString.call(v) === '[object Arguments]';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* See if a value is an instance of a class.
|
|
106
|
+
* @param {*} v - The value we're testing.
|
|
107
|
+
* @param {function} f - The constructor/class we want.
|
|
108
|
+
* @returns {boolean}
|
|
109
|
+
*/
|
|
110
|
+
function isInstance(v, f, needProto=false)
|
|
111
|
+
{
|
|
112
|
+
if (!isObj(v)) return false; // Not an object.
|
|
113
|
+
if (needProto && (typeof v.prototype !== O || v.prototype === null))
|
|
114
|
+
{ // Has no prototype.
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (typeof f !== F || !(v instanceof f)) return false;
|
|
119
|
+
|
|
120
|
+
// Everything passed.
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* See if a value is a Property name.
|
|
126
|
+
* @param {*} v - The value we're testing.
|
|
127
|
+
* @returns {boolean}
|
|
128
|
+
*/
|
|
129
|
+
function isProperty(v)
|
|
130
|
+
{
|
|
131
|
+
const t = typeof v;
|
|
132
|
+
return (t === S || t === SY);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A smarter `typeof` function.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} type - The type we're checking for.
|
|
139
|
+
*
|
|
140
|
+
* This supports all the same type names as `typeof` plus:
|
|
141
|
+
*
|
|
142
|
+
* - `arguments` → An arguments object inside a function.
|
|
143
|
+
* - `array` → An Array object.
|
|
144
|
+
* - `null` → A null value.
|
|
145
|
+
* - `typedarray` → One of the typed array objects.
|
|
146
|
+
* - `descriptor` → An object which is a valid descriptor.
|
|
147
|
+
* - `complex` → Either an `object` or a `function.
|
|
148
|
+
* - `scalar` → Anything other than an `object` or `function`.
|
|
149
|
+
* - `property` → A `string` or a `symbol`.
|
|
150
|
+
*
|
|
151
|
+
* One other thing, while `typeof` reports `null` as being an `object`,
|
|
152
|
+
* this function does not count `null` as a valid `object`.
|
|
153
|
+
*
|
|
154
|
+
* @param {*} v - The value we're testing.
|
|
155
|
+
*
|
|
156
|
+
* @returns {boolean} If the value was of the desired type.
|
|
157
|
+
*/
|
|
158
|
+
function isType(type, v)
|
|
159
|
+
{
|
|
160
|
+
if (typeof type !== S || !TYPE_LIST.includes(type))
|
|
161
|
+
{
|
|
162
|
+
throw new TypeError(`Invalid type ${JSON.stringify(type)} specified`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
switch(type)
|
|
166
|
+
{
|
|
167
|
+
case O:
|
|
168
|
+
return isObj(v);
|
|
169
|
+
case TYPES.NULL:
|
|
170
|
+
return (v === null);
|
|
171
|
+
case TYPES.ARGS:
|
|
172
|
+
return isArguments(v);
|
|
173
|
+
case TYPES.ARRAY:
|
|
174
|
+
return isArray(v);
|
|
175
|
+
case TYPES.TYPEDARRAY:
|
|
176
|
+
return isTypedArray(v);
|
|
177
|
+
case TYPES.DESCRIPTOR:
|
|
178
|
+
return doesDescriptor(v);
|
|
179
|
+
case TYPES.COMPLEX:
|
|
180
|
+
return isComplex(v);
|
|
181
|
+
case TYPES.SCALAR:
|
|
182
|
+
return isScalar(v);
|
|
183
|
+
case TYPES.PROP:
|
|
184
|
+
return isProperty(v);
|
|
185
|
+
default:
|
|
186
|
+
return (typeof v === type);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* If a value is not an object, throw an error.
|
|
192
|
+
*
|
|
193
|
+
* @param {*} v - The value we're testing.
|
|
194
|
+
* @param {boolean} [allowFunc=false] - Also accept functions?
|
|
195
|
+
* @param {string} [msg] A custom error message.
|
|
196
|
+
* @throws {TypeError} If the type check failed.
|
|
197
|
+
*/
|
|
198
|
+
function needObj (v, allowFunc=false, msg=null)
|
|
199
|
+
{
|
|
200
|
+
if (allowFunc && isComplex(v)) return;
|
|
201
|
+
if (isObj(v)) return;
|
|
202
|
+
|
|
203
|
+
if (typeof msg !== S)
|
|
204
|
+
{ // Use a default message.
|
|
205
|
+
msg = "Invalid object";
|
|
206
|
+
if (allowFunc)
|
|
207
|
+
msg += " or function";
|
|
208
|
+
}
|
|
209
|
+
throw new TypeError(msg);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* If a value is not a certain type, throw an error.
|
|
214
|
+
*
|
|
215
|
+
* @param {string} type - The type name as per `isType`.
|
|
216
|
+
* @param {*} v - The value we're testing.
|
|
217
|
+
* @param {string} [msg] A custom error message.
|
|
218
|
+
* @throws {TypeError} If the type check failed.
|
|
219
|
+
*/
|
|
220
|
+
function needType (type, v, msg, unused)
|
|
221
|
+
{
|
|
222
|
+
if (!isType(type, v))
|
|
223
|
+
{
|
|
224
|
+
if (typeof msg === B)
|
|
225
|
+
{
|
|
226
|
+
console.warn("needType(): 'allowNull' is no longer supported");
|
|
227
|
+
if (typeof unused === S)
|
|
228
|
+
{ // Compatibility with old code.
|
|
229
|
+
msg = unused;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (typeof msg !== S)
|
|
234
|
+
{ // Use a default message.
|
|
235
|
+
msg = `Invalid ${type} value`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
throw new TypeError(msg);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* See if an array contains *any* of the specified items.
|
|
244
|
+
* @param {Array} array
|
|
245
|
+
* @param {...any} items
|
|
246
|
+
* @returns {boolean}
|
|
247
|
+
*/
|
|
248
|
+
function containsAny(array, ...items)
|
|
249
|
+
{
|
|
250
|
+
for (const item of items)
|
|
251
|
+
{
|
|
252
|
+
if (array.includes(item))
|
|
253
|
+
{ // Item found.
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// No items found.
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* See if an array contains *all* of the specified items.
|
|
264
|
+
* @param {Array} array
|
|
265
|
+
* @param {...any} items
|
|
266
|
+
* @returns {boolean}
|
|
267
|
+
*/
|
|
268
|
+
function containsAll(array, ...items)
|
|
269
|
+
{
|
|
270
|
+
for (const item of items)
|
|
271
|
+
{
|
|
272
|
+
if (!array.includes(item))
|
|
273
|
+
{ // An item was missing.
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// All items found.
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Remove items from an array.
|
|
284
|
+
* @param {Array} array
|
|
285
|
+
* @param {...any} items
|
|
286
|
+
* @returns {number} Number of items removed.
|
|
287
|
+
*/
|
|
288
|
+
function removeFromArray(array, ...items)
|
|
289
|
+
{
|
|
290
|
+
let removed = 0;
|
|
291
|
+
for (const item of items)
|
|
292
|
+
{
|
|
293
|
+
const index = array.indexOf(item);
|
|
294
|
+
if (index !== -1)
|
|
295
|
+
{
|
|
296
|
+
array.splice(index, 1);
|
|
297
|
+
removed++;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return removed;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// «private»
|
|
304
|
+
function no_root()
|
|
305
|
+
{
|
|
306
|
+
throw new Error("Invalid JS environment, no root object found");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* The global root object. Usually `globalThis` these days.
|
|
311
|
+
*/
|
|
312
|
+
const root = typeof globalThis !== U ? globalThis
|
|
313
|
+
: typeof global !== U ? global
|
|
314
|
+
: typeof self !== U ? self
|
|
315
|
+
: typeof window !== U ? window
|
|
316
|
+
: no_root(); // Unlike the old way, we'll die if the environment is undetermined.
|
|
317
|
+
|
|
318
|
+
// A list of objects to be considered unbound globally.
|
|
319
|
+
const unboundObjects = [];
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Pass `this` here to see if it is bound to an object.
|
|
323
|
+
*
|
|
324
|
+
* Always considers `null` and `undefined` as unbound.
|
|
325
|
+
*
|
|
326
|
+
* @param {*} whatIsThis - The `this` from any context.
|
|
327
|
+
* @param {boolean} [rootIsUnbound=true] The global root is unbound.
|
|
328
|
+
* @param {(boolean|Array)} [areUnbound=false] A list of unbound objects.
|
|
329
|
+
* If the is `true` we use an global list that can register special
|
|
330
|
+
* internal objects. Otherwise an `Array` of unbound objects may be used.
|
|
331
|
+
* @returns {boolean}
|
|
332
|
+
*/
|
|
333
|
+
function unbound(whatIsThis, rootIsUnbound=true, areUnbound=false)
|
|
334
|
+
{
|
|
335
|
+
if (areUnbound === true)
|
|
336
|
+
{ // If areUnbound is true, we use the unboundObjects
|
|
337
|
+
areUnbound = unboundObjects;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (isNil(whatIsThis)) return true;
|
|
341
|
+
if (rootIsUnbound && whatIsThis === root) return true;
|
|
342
|
+
if (isArray(areUnbound) && areUnbound.includes(whatIsThis)) return true;
|
|
343
|
+
|
|
344
|
+
// Nothing considered unbound.
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* See if an object can be used as a valid descriptor.
|
|
350
|
+
*
|
|
351
|
+
* Basically in order to be considered a valid descriptor,
|
|
352
|
+
* one of the the following sets of rules must be true:
|
|
353
|
+
*
|
|
354
|
+
* - A Data Descriptor:
|
|
355
|
+
* - Has a `value` property.
|
|
356
|
+
* - Does not have a `get` property.
|
|
357
|
+
* - Does not have a `set` property.
|
|
358
|
+
* - An Accessor Descriptor:
|
|
359
|
+
* - Has a `get` and/or `set` property.
|
|
360
|
+
* - Does not have a `value` property.
|
|
361
|
+
* - Does not have a `writable` property.
|
|
362
|
+
*
|
|
363
|
+
* @param {object} obj - The object we are testing.
|
|
364
|
+
* @returns {boolean} - Is the object a valid descriptor?
|
|
365
|
+
*/
|
|
366
|
+
function doesDescriptor(obj)
|
|
367
|
+
{
|
|
368
|
+
if (isObj(obj))
|
|
369
|
+
{
|
|
370
|
+
const hasValue = (obj.value !== undefined);
|
|
371
|
+
const hasGetter = (typeof obj.get === F);
|
|
372
|
+
const hasSetter = (typeof obj.set === F);
|
|
373
|
+
const hasWritable = (obj.writable !== undefined);
|
|
374
|
+
|
|
375
|
+
if (hasValue && !hasGetter && !hasSetter)
|
|
376
|
+
{ // We have a value, and no getter or setter.
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
else if ((hasGetter || hasSetter) && !hasValue && !hasWritable)
|
|
380
|
+
{ // We have a getter or setter, and no value or writable properties.
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Nothing matched, not a valid descriptor rule.
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* A minimalistic wrapper around `Object.defineProperty()`.
|
|
391
|
+
*
|
|
392
|
+
* This is not meant to be fancy, it simply changes a few default
|
|
393
|
+
* behaviours, and makes assigning simple non-accessor properties simpler.
|
|
394
|
+
*
|
|
395
|
+
* See the `prop()` function which expands on this with many more features.
|
|
396
|
+
*
|
|
397
|
+
* @param {(object|function)} obj - The object to add a property to.
|
|
398
|
+
* @param {?(string|boolean)} name - The name of the property we're adding.
|
|
399
|
+
*
|
|
400
|
+
* If this is `null` or `undefined` then the `value` is ignored entirely,
|
|
401
|
+
* and instead a bound version of this function is created with the
|
|
402
|
+
* `obj` already passed as the first parameter. Can be useful if you
|
|
403
|
+
* need to add a lot of properties to the same object.
|
|
404
|
+
*
|
|
405
|
+
* If this is a `boolean` value instead of a string, then the same logic
|
|
406
|
+
* as if it was `null` or `undefined` will apply, except that an
|
|
407
|
+
* `enumerable` property with this value will be added to the descriptors.
|
|
408
|
+
*
|
|
409
|
+
* @param {*} value - Used to determine the value of the property.
|
|
410
|
+
*
|
|
411
|
+
* If it is an a valid descriptor object (as per `doesDescriptor()`),
|
|
412
|
+
* it will be used as the descriptor. If it has no `configurable`
|
|
413
|
+
* property defined, one will be added, and will be set to `true`.
|
|
414
|
+
*
|
|
415
|
+
* Any other value passed here will be used as the `value` in a
|
|
416
|
+
* pre-canned descriptor, also with `configurable` set to `true`.
|
|
417
|
+
*
|
|
418
|
+
* @returns {*} Normally the `obj` argument with new property added.
|
|
419
|
+
*
|
|
420
|
+
* The exception is if this is a bound copy of the function created
|
|
421
|
+
* using the syntax described in the `name` parameter documentation.
|
|
422
|
+
* In that case the return value is the bound copy itself.
|
|
423
|
+
* While that might seem strange, it allows for chaining in a way
|
|
424
|
+
* that otherwise would not be possible, take this example:
|
|
425
|
+
*
|
|
426
|
+
* ```
|
|
427
|
+
* def(myObj)('name', "Bob")('age', 42);
|
|
428
|
+
* ```
|
|
429
|
+
*
|
|
430
|
+
*/
|
|
431
|
+
function def(obj, name, value)
|
|
432
|
+
{
|
|
433
|
+
if (isNil(name) || typeof name === B)
|
|
434
|
+
{ // Create a bound function, and return it.
|
|
435
|
+
const opts = {obj, enumerable: name};
|
|
436
|
+
// Yes, we're creating a circular reference.
|
|
437
|
+
opts.bound = def.bind(opts, obj);
|
|
438
|
+
// The reason why will be obvious later.
|
|
439
|
+
return opts.bound;
|
|
440
|
+
}
|
|
441
|
+
else if (!isProperty(name))
|
|
442
|
+
{ // That's not valid.
|
|
443
|
+
throw new TypeError("property name must be a string or a Symbol");
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const isBound = !unbound(this, true, true);
|
|
447
|
+
let desc;
|
|
448
|
+
|
|
449
|
+
if (doesDescriptor(value))
|
|
450
|
+
{ // The value is a descriptor, let's use it.
|
|
451
|
+
desc = value;
|
|
452
|
+
if (typeof desc.configurable !== B)
|
|
453
|
+
{ // No valid 'configurable' property, we default to true.
|
|
454
|
+
desc.configurable = true;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
else
|
|
458
|
+
{ // The value is just a value, so let's assign it.
|
|
459
|
+
desc = {configurable: true, value};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (isBound
|
|
463
|
+
&& typeof this.enumerable === B
|
|
464
|
+
&& typeof desc.enumerable !== B)
|
|
465
|
+
{ // We have an enumerable value, and the desc does not.
|
|
466
|
+
desc.enumerable = this.enumerable;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Add the property.
|
|
470
|
+
Object.defineProperty(obj, name, desc);
|
|
471
|
+
|
|
472
|
+
if (isBound && typeof this.bound === F)
|
|
473
|
+
{ // Bound version, returns itself recursively.
|
|
474
|
+
return this.bound;
|
|
475
|
+
}
|
|
476
|
+
else
|
|
477
|
+
{ // Not bound, or doesn't have a reference to itself.
|
|
478
|
+
return obj;
|
|
479
|
+
}
|
|
480
|
+
} // def()
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Add an item to the unbound global objects list.
|
|
484
|
+
*
|
|
485
|
+
* @method unbound.add
|
|
486
|
+
*
|
|
487
|
+
* @param {(object|function)} obj - The object to be considered unbound.
|
|
488
|
+
*
|
|
489
|
+
* @returns {boolean} Will be `false` if `obj` is already unbound.
|
|
490
|
+
*
|
|
491
|
+
* @throws {TypeError} If `obj` was neither an `object` nor a `function`.
|
|
492
|
+
*/
|
|
493
|
+
def(unbound, 'add', function (obj)
|
|
494
|
+
{
|
|
495
|
+
needObj(obj, true);
|
|
496
|
+
if (unbound(obj, true, true))
|
|
497
|
+
{ // Item is already unbound.
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
// Add to list and we're done.
|
|
501
|
+
unboundObjects.push(obj);
|
|
502
|
+
return true;
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Remove an item from the unbound global objects list.
|
|
507
|
+
*
|
|
508
|
+
* @method unbound.remove
|
|
509
|
+
*
|
|
510
|
+
* @param {(object|function)} obj - The object to be removed.
|
|
511
|
+
*
|
|
512
|
+
* @returns {boolean} Will be `false` if the item was not in the list.
|
|
513
|
+
*
|
|
514
|
+
* @throws {TypeError} If `obj` was neither an `object` nor a `function`.
|
|
515
|
+
*/
|
|
516
|
+
def(unbound, 'remove', function(obj)
|
|
517
|
+
{
|
|
518
|
+
needObj(obj, true);
|
|
519
|
+
return (removeFromArray(unboundObjects, obj) > 0);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* A placeholder function for when something is not implemented.
|
|
524
|
+
*
|
|
525
|
+
* @param {boolean} [fatal=true] - If `true` throw an `Error`.
|
|
526
|
+
* If `false` just uses `console.error()` instead.
|
|
527
|
+
* @returns {void}
|
|
528
|
+
*/
|
|
529
|
+
function NYI(fatal=true)
|
|
530
|
+
{
|
|
531
|
+
const msg = "Not yet implemented";
|
|
532
|
+
if (fatal)
|
|
533
|
+
throw new Error(msg);
|
|
534
|
+
else
|
|
535
|
+
console.error(msg);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Okay, add all those to our exports.
|
|
539
|
+
module.exports =
|
|
540
|
+
{
|
|
541
|
+
root, O, F, S, B, N, U, SY, BI, TYPES, TYPE_LIST, isType, NYI,
|
|
542
|
+
isObj, isNil, notNil, isComplex, isInstance, isArguments, isScalar,
|
|
543
|
+
isProperty, isArray, isTypedArray, nonEmptyArray, needObj, needType,
|
|
544
|
+
containsAny, containsAll, removeFromArray, doesDescriptor, def, unbound,
|
|
545
|
+
}
|