@lumjs/core 1.25.2 → 1.30.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/README.md +14 -0
- package/TODO.md +2 -0
- package/lib/console.js +54 -0
- package/lib/enum.js +27 -6
- package/lib/index.js +12 -16
- package/lib/meta.js +68 -88
- package/lib/obj/clone.js +1 -1
- package/lib/obj/copyprops.js +1 -1
- package/lib/obj/merge.js +1 -1
- package/lib/obj/ns.js +8 -3
- package/lib/objectid.js +34 -13
- package/lib/observable.js +1 -1
- package/lib/old/abstractclass.js +82 -0
- package/lib/opt/args.js +50 -0
- package/lib/opt/getpath.js +70 -0
- package/lib/opt/getval.js +61 -0
- package/lib/opt/index.js +21 -0
- package/lib/opt/val.js +63 -0
- package/lib/strings.js +1 -1
- package/lib/types/basics.js +43 -16
- package/lib/types/def.js +49 -36
- package/lib/types/dt.js +147 -18
- package/lib/types/index.js +35 -59
- package/lib/types/isa.js +4 -0
- package/lib/types/js.js +29 -12
- package/lib/types/lazy.js +3 -2
- package/lib/types/needs.js +0 -1
- package/package.json +7 -3
- package/lib/opt.js +0 -404
package/README.md
CHANGED
|
@@ -6,6 +6,16 @@ and work in CommonJS/Node.js and modern browsers without any modifications.
|
|
|
6
6
|
|
|
7
7
|
Used by all the rest of my *Lum.js* libraries.
|
|
8
8
|
|
|
9
|
+
## Notes
|
|
10
|
+
|
|
11
|
+
As of version `1.30.0` the `opt.Opts` class has been split into its the new
|
|
12
|
+
[@lumjs/opts] package, which itself depends on a new [@lumjs/errors] package.
|
|
13
|
+
|
|
14
|
+
Until the next major release (`2.0`), this package will have
|
|
15
|
+
a dependency on the split-away pacakages, so that it can have a deprecated
|
|
16
|
+
alias to the old class name available. As of `2.0` that alias will be
|
|
17
|
+
removed, and the dependencies will also be removed.
|
|
18
|
+
|
|
9
19
|
## Documentation
|
|
10
20
|
|
|
11
21
|
### [API Docs](https://supernovus.github.io/docs/js/@lumjs/core/)
|
|
@@ -34,3 +44,7 @@ Timothy Totten <2010@totten.ca>
|
|
|
34
44
|
|
|
35
45
|
[MIT](https://spdx.org/licenses/MIT.html)
|
|
36
46
|
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
[@lumjs/opts]: https://github.com/supernovus/lum.opts.js
|
|
50
|
+
[@lumjs/errors]: https://github.com/supernovus/lum.errors.js
|
package/TODO.md
CHANGED
|
@@ -17,6 +17,8 @@ for the future would be a good idea. A few of the things I want to do:
|
|
|
17
17
|
- Cut anything that seems superfluous or rarely used
|
|
18
18
|
- Add ability to copy `Symbol` properties
|
|
19
19
|
- Replace `obj.syncNested` with `obj.sync` using the new `obj.copy` API
|
|
20
|
+
- Move `opt.Opts` into its own separate package
|
|
21
|
+
- Give `observable` some TLC
|
|
20
22
|
|
|
21
23
|
I will likely update this list a bit before I get around to starting the
|
|
22
24
|
new branch that will eventually become the `2.0.0` release.
|
package/lib/console.js
CHANGED
|
@@ -177,4 +177,58 @@ for (const method of DEFAULT_METHODS)
|
|
|
177
177
|
addMethod(method);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Export our wrapper to replace the real console
|
|
182
|
+
* in the global namespace.
|
|
183
|
+
*
|
|
184
|
+
* @param {*} [handler] Set a handler while we're exported.
|
|
185
|
+
*
|
|
186
|
+
* See the description of `handler` for possible values.
|
|
187
|
+
* Any existing handler value will be saved to the `preHandler`
|
|
188
|
+
* static property.
|
|
189
|
+
*
|
|
190
|
+
* @function module:@lumjs/core/console.export
|
|
191
|
+
*/
|
|
192
|
+
def(LC, 'export', function(handler)
|
|
193
|
+
{
|
|
194
|
+
if (handler !== undefined)
|
|
195
|
+
{ // Save the existing handler as 'preHandler'
|
|
196
|
+
LC.preHandler = LC.handler ?? null; // Prevent `undefined`
|
|
197
|
+
LC.handler = handler;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
globalThis.console = LC;
|
|
201
|
+
return LC;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Restore the real console.
|
|
206
|
+
*
|
|
207
|
+
* If a `handler` was passed to `export()`, then
|
|
208
|
+
* it will be removed, and the previous handler value
|
|
209
|
+
* will be restored.
|
|
210
|
+
*
|
|
211
|
+
* @function module:@lumjs/core/console.restore
|
|
212
|
+
*/
|
|
213
|
+
def(LC, 'restore', function()
|
|
214
|
+
{
|
|
215
|
+
if (LC.preHandler !== undefined)
|
|
216
|
+
{
|
|
217
|
+
LC.handler = LC.preHandler;
|
|
218
|
+
delete LC.preHandler;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
globalThis.console = LC.real;
|
|
222
|
+
return LC;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* A shortcut for `LC.export(false)`
|
|
227
|
+
* @function module:@lumjs/core/console.mute
|
|
228
|
+
*/
|
|
229
|
+
def(LC, 'mute', function()
|
|
230
|
+
{
|
|
231
|
+
return LC.export(false);
|
|
232
|
+
});
|
|
233
|
+
|
|
180
234
|
module.exports = LC;
|
package/lib/enum.js
CHANGED
|
@@ -2,7 +2,10 @@ const {S,def,notNil,isObj,needObj,TYPES} = require('./types');
|
|
|
2
2
|
const {InternalObjectId} = require('./objectid');
|
|
3
3
|
|
|
4
4
|
// Internal id instances should never be exported.
|
|
5
|
-
const
|
|
5
|
+
const EID = '@lumjs/core/enum';
|
|
6
|
+
const ENUM_ID = new InternalObjectId({name: EID});
|
|
7
|
+
const isEnum = ENUM_ID.isFunction();
|
|
8
|
+
const EOPT = Symbol(EID+':opts');
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* A function to build magic Enum objects.
|
|
@@ -72,7 +75,16 @@ function Enum (spec, opts={})
|
|
|
72
75
|
needObj(spec, "Enum spec must be an object")
|
|
73
76
|
needObj(opts, "Enum options must be an object")
|
|
74
77
|
|
|
75
|
-
const
|
|
78
|
+
const isExisting = isEnum(opts);
|
|
79
|
+
const anEnum = isExisting ? opts : ENUM_ID.tag({});
|
|
80
|
+
if (isExisting)
|
|
81
|
+
{
|
|
82
|
+
opts = anEnum[EOPT];
|
|
83
|
+
if (!isObj(opts))
|
|
84
|
+
{
|
|
85
|
+
throw new Error("existing Enum was not open for changes");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
76
88
|
|
|
77
89
|
const configurable = opts.configurable ?? false;
|
|
78
90
|
const enumerable = opts.enumerable ?? true;
|
|
@@ -130,6 +142,10 @@ function Enum (spec, opts={})
|
|
|
130
142
|
counter++;
|
|
131
143
|
}
|
|
132
144
|
}
|
|
145
|
+
if (opts.open)
|
|
146
|
+
{ // Save the last counter value into the opts
|
|
147
|
+
opts.counter = counter;
|
|
148
|
+
}
|
|
133
149
|
}
|
|
134
150
|
else
|
|
135
151
|
{ // An object mapping of property name to value.
|
|
@@ -141,7 +157,14 @@ function Enum (spec, opts={})
|
|
|
141
157
|
}
|
|
142
158
|
}
|
|
143
159
|
|
|
144
|
-
if (
|
|
160
|
+
if (opts.open)
|
|
161
|
+
{
|
|
162
|
+
if (!isExisting)
|
|
163
|
+
{ // Save the options into a special Symbol property.
|
|
164
|
+
def(anEnum, EOPT, {value: opts});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else
|
|
145
168
|
{
|
|
146
169
|
if (notNil(opts.lock))
|
|
147
170
|
{ // Use lock() function.
|
|
@@ -180,13 +203,11 @@ function Enum (spec, opts={})
|
|
|
180
203
|
* @param {*} obj - The expected object/function to test.
|
|
181
204
|
* @returns {boolean}
|
|
182
205
|
*/
|
|
183
|
-
const isEnum = ENUM_ID.isFunction()
|
|
184
206
|
def(Enum, 'is', isEnum);
|
|
185
207
|
|
|
186
208
|
/**
|
|
187
209
|
* Is a value an *Enum* magic object?
|
|
188
|
-
* @
|
|
189
|
-
* @function
|
|
210
|
+
* @function module:@lumjs/core/types.isEnum
|
|
190
211
|
* @param {*} v - The value to test.
|
|
191
212
|
* @returns {boolean}
|
|
192
213
|
* @see module:@lumjs/core/enum.is
|
package/lib/index.js
CHANGED
|
@@ -98,24 +98,19 @@ lazy(exports, 'traits', () => require('./traits'));
|
|
|
98
98
|
* @name module:@lumjs/core.opt
|
|
99
99
|
* @type {module:@lumjs/core/opt}
|
|
100
100
|
*/
|
|
101
|
-
|
|
102
|
-
lazy(exports, 'opt', () => require('./opt'), optOpts);
|
|
101
|
+
lazy(exports, 'opt', () => require('./opt'), {def:{autoDesc: false}});
|
|
103
102
|
|
|
104
103
|
// Get a bunch of properties from a submodule.
|
|
105
|
-
function from(submod
|
|
104
|
+
function from(submod)
|
|
106
105
|
{
|
|
107
|
-
for (const
|
|
106
|
+
for (const key in submod)
|
|
108
107
|
{
|
|
109
|
-
def(exports,
|
|
108
|
+
def(exports, key, submod[key]);
|
|
110
109
|
}
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
// ObjectID stuff is imported directly without registering a sub-module.
|
|
114
|
-
|
|
115
|
-
from(objectid,
|
|
116
|
-
'randomNumber',
|
|
117
|
-
'UniqueObjectIds',
|
|
118
|
-
'InternalObjectId');
|
|
113
|
+
from(require('./objectid'));
|
|
119
114
|
|
|
120
115
|
/**
|
|
121
116
|
* Get a simplistic debugging stacktrace
|
|
@@ -143,15 +138,16 @@ from(objectid,
|
|
|
143
138
|
* @see module:@lumjs/core/meta.NYI
|
|
144
139
|
*/
|
|
145
140
|
|
|
141
|
+
// TODO: documentation for 'deprecated' and 'wrapDepr'
|
|
142
|
+
|
|
146
143
|
// These are exported directly, but a meta sub-module also exists.
|
|
147
144
|
// Unlike most sub-modules there is no `meta` property in the main library.
|
|
148
145
|
const meta = require('./meta');
|
|
149
|
-
from(meta
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
'NYI');
|
|
146
|
+
from(meta);
|
|
147
|
+
def(exports, 'AbstractClass',
|
|
148
|
+
{
|
|
149
|
+
get() { return meta.AbstractClass; }
|
|
150
|
+
});
|
|
155
151
|
|
|
156
152
|
/**
|
|
157
153
|
* Create a magic *Enum* object «Lazy»
|
package/lib/meta.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
* Meta-programming helpers.
|
|
3
|
-
* @module @lumjs/core/meta
|
|
4
|
-
*/
|
|
1
|
+
"use strict";
|
|
5
2
|
|
|
6
|
-
const {F
|
|
3
|
+
const {F} = require('./types/js');
|
|
7
4
|
|
|
8
5
|
/**
|
|
9
6
|
* Get a stacktrace. Differs from browser to browser.
|
|
@@ -16,7 +13,7 @@ const {F,S,isArray,isa,console} = require('./types');
|
|
|
16
13
|
* @param {string} [msg] - A message for the Error object.
|
|
17
14
|
*
|
|
18
15
|
* @returns {string[]} An array of stack strings.
|
|
19
|
-
* @alias module:@lumjs/core
|
|
16
|
+
* @alias module:@lumjs/core.stacktrace
|
|
20
17
|
*/
|
|
21
18
|
function stacktrace(msg)
|
|
22
19
|
{
|
|
@@ -25,85 +22,6 @@ function stacktrace(msg)
|
|
|
25
22
|
|
|
26
23
|
exports.stacktrace = stacktrace;
|
|
27
24
|
|
|
28
|
-
/**
|
|
29
|
-
* Abstract classes for Javascript.
|
|
30
|
-
* @deprecated Just use `throw new AbstractError()` instead.
|
|
31
|
-
* @alias module:@lumjs/core/meta.AbstractClass
|
|
32
|
-
*/
|
|
33
|
-
class AbstractClass
|
|
34
|
-
{
|
|
35
|
-
/**
|
|
36
|
-
* If you want to mark a method as abstract use this.
|
|
37
|
-
*/
|
|
38
|
-
$abstract(name)
|
|
39
|
-
{
|
|
40
|
-
if (name.indexOf('(') === -1)
|
|
41
|
-
{ // Add empty method signature.
|
|
42
|
-
name += '()';
|
|
43
|
-
}
|
|
44
|
-
throw new Error(`Abstract method ${name} was not implemented`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Check for required properties
|
|
49
|
-
*
|
|
50
|
-
* @param {...(string|Array)} needs - What is needed
|
|
51
|
-
*
|
|
52
|
-
* If this is a `string` it should be in a format like:
|
|
53
|
-
*
|
|
54
|
-
* - `methodName(arg1,arg2,arg3)`
|
|
55
|
-
* - `anotherMethod(number, string, object) : boolean`
|
|
56
|
-
* - `yetAnother (className) : resultClass`
|
|
57
|
-
*
|
|
58
|
-
* The names are case sensitive, and we'll look for the method after
|
|
59
|
-
* stripping off anything from the first *non-word* character.
|
|
60
|
-
*
|
|
61
|
-
* If this is an `Array`, the first item must be the name of a property,
|
|
62
|
-
* and each other item should be a type checking value, or array of type
|
|
63
|
-
* checking values from the [TYPES]{@link module:@lumjs/core/types.TYPES}
|
|
64
|
-
* object, as used by [isa()]{@link module:@lumjs/core/types.isa}.
|
|
65
|
-
*
|
|
66
|
-
* If you are calling this in an abstract class constructor, likely only
|
|
67
|
-
* the method checks will be useful, as the `super()` call must be done
|
|
68
|
-
* *before* any instance property assignments.
|
|
69
|
-
*
|
|
70
|
-
*/
|
|
71
|
-
$needs(...needs)
|
|
72
|
-
{
|
|
73
|
-
const className = this.constructor.name;
|
|
74
|
-
|
|
75
|
-
const getName = fullName => fullName.replace(/\W.*/, '');
|
|
76
|
-
const missing = propName =>
|
|
77
|
-
{
|
|
78
|
-
throw new Error(`${className} is missing ${propName}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
for (const need of needs)
|
|
82
|
-
{
|
|
83
|
-
if (typeof need === S)
|
|
84
|
-
{ // A simple method
|
|
85
|
-
const meth = getName(need);
|
|
86
|
-
if (typeof this[meth] !== F)
|
|
87
|
-
{
|
|
88
|
-
missing(need);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else if (isArray(need))
|
|
92
|
-
{
|
|
93
|
-
const prop = getName(need[0]);
|
|
94
|
-
const types = need.slice(1);
|
|
95
|
-
if (!isa(this[prop], ...types))
|
|
96
|
-
{
|
|
97
|
-
missing(need);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
exports.AbstractClass = AbstractClass;
|
|
106
|
-
|
|
107
25
|
/**
|
|
108
26
|
* An Error that can be thrown from abstract methods.
|
|
109
27
|
*
|
|
@@ -132,7 +50,7 @@ exports.AbstractClass = AbstractClass;
|
|
|
132
50
|
* }
|
|
133
51
|
* ```
|
|
134
52
|
*
|
|
135
|
-
* @alias module:@lumjs/core
|
|
53
|
+
* @alias module:@lumjs/core.AbstractError
|
|
136
54
|
*/
|
|
137
55
|
class AbstractError extends Error
|
|
138
56
|
{
|
|
@@ -165,7 +83,7 @@ exports.AbstractError = AbstractError;
|
|
|
165
83
|
/**
|
|
166
84
|
* Function prototypes for async, generator, and async generator functions.
|
|
167
85
|
* @namespace
|
|
168
|
-
* @alias module:@lumjs/core
|
|
86
|
+
* @alias module:@lumjs/core.Functions
|
|
169
87
|
*/
|
|
170
88
|
const Functions =
|
|
171
89
|
{
|
|
@@ -196,7 +114,7 @@ exports.Functions = Functions;
|
|
|
196
114
|
* @param {string} [prefix=''] A prefix for the error message.
|
|
197
115
|
*
|
|
198
116
|
* @returns {void}
|
|
199
|
-
* @alias module:@lumjs/core
|
|
117
|
+
* @alias module:@lumjs/core.NYI
|
|
200
118
|
*/
|
|
201
119
|
function NYI(fatal=true, prefix='')
|
|
202
120
|
{
|
|
@@ -208,3 +126,65 @@ function NYI(fatal=true, prefix='')
|
|
|
208
126
|
}
|
|
209
127
|
|
|
210
128
|
exports.NYI = NYI;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Send a deprecation message with a stack trace.
|
|
132
|
+
*
|
|
133
|
+
* @param {string} dep - Name of what is deprecated
|
|
134
|
+
* @param {(string|string[])} [rep] Replacement suggestion(s).
|
|
135
|
+
* @param {*} [ret] Value to return
|
|
136
|
+
* @returns {mixed} `ret`
|
|
137
|
+
* @alias module:@lumjs/core.deprecated
|
|
138
|
+
*/
|
|
139
|
+
function deprecated(dep, rep, ret)
|
|
140
|
+
{
|
|
141
|
+
const msgs = [dep,'is deprecated'];
|
|
142
|
+
if (rep)
|
|
143
|
+
{
|
|
144
|
+
msgs.push('replace with', rep);
|
|
145
|
+
}
|
|
146
|
+
console.trace(...msgs);
|
|
147
|
+
return ret;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
exports.deprecated = deprecated;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Assign a getter property that when accessed will
|
|
154
|
+
* show a deprecation message via `deprecated()` function
|
|
155
|
+
* before returning the deprecated property value.
|
|
156
|
+
*
|
|
157
|
+
* @param {object} obj - Target to assign property on
|
|
158
|
+
* @param {string} prop - Property to assign
|
|
159
|
+
* @param {(object|function)} spec - Specification
|
|
160
|
+
*
|
|
161
|
+
* If this is a `function` it will be used as the `spec.get` value.
|
|
162
|
+
*
|
|
163
|
+
* @param {function} spec.get - The function that returns the real value
|
|
164
|
+
* @param {string} [spec.dep=prop] Name of what is deprecated;
|
|
165
|
+
* defaults to `prop` if omitted.
|
|
166
|
+
* @param {(string|string[])} [spec.rep] Replacement suggestion(s).
|
|
167
|
+
* @param {object} [spec.opts] Options for `def()` to add getter with.
|
|
168
|
+
*
|
|
169
|
+
* @returns {object} `obj`
|
|
170
|
+
*/
|
|
171
|
+
function wrapDepr(obj,prop,spec)
|
|
172
|
+
{
|
|
173
|
+
if (typeof spec === F)
|
|
174
|
+
spec = {get: spec};
|
|
175
|
+
if (typeof spec.get !== F)
|
|
176
|
+
throw new TypeError("invalid init");
|
|
177
|
+
|
|
178
|
+
return def(obj, prop,
|
|
179
|
+
{
|
|
180
|
+
get: () =>
|
|
181
|
+
deprecated(spec.dep??prop, spec.rep, spec.get())
|
|
182
|
+
}, spec.opts);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
exports.wrapDepr = wrapDepr;
|
|
186
|
+
|
|
187
|
+
// This is near the bottom, but before any calls to wrapDepr.
|
|
188
|
+
const def = require('./types/def');
|
|
189
|
+
|
|
190
|
+
wrapDepr(exports, 'AbstractClass', () => require('./old/abstractclass'));
|
package/lib/obj/clone.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Import *most* required bits here.
|
|
2
|
-
const {N,F, isObj, isComplex, def, isArray
|
|
2
|
+
const {N,F, isObj, isComplex, def, isArray} = require('../types');
|
|
3
3
|
const copyProps = require('./copyprops');
|
|
4
4
|
const getProp = require('./getproperty');
|
|
5
5
|
|
package/lib/obj/copyprops.js
CHANGED
package/lib/obj/merge.js
CHANGED
package/lib/obj/ns.js
CHANGED
|
@@ -3,7 +3,7 @@ const
|
|
|
3
3
|
{
|
|
4
4
|
B, S,
|
|
5
5
|
root, isObj, needObj, def, nonEmptyArray, notNil,
|
|
6
|
-
doesDescriptorTemplate,
|
|
6
|
+
doesDescriptorTemplate,
|
|
7
7
|
} = require('../types');
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -83,6 +83,11 @@ exports.nsArray = nsArray;
|
|
|
83
83
|
* @param {(object|boolean)} [opts] Options changing the behaviours.
|
|
84
84
|
* If this is a `boolean` it's assumed to be the `opts.log` option.
|
|
85
85
|
* @param {boolean} [opts.log=false] Log errors for missing namespaces?
|
|
86
|
+
* @param {boolean} [opts.allowFun=true] Allow `obj` to be a `function` ?
|
|
87
|
+
*
|
|
88
|
+
* By default both `object` and `function` are valid `obj` argument values;
|
|
89
|
+
* if this is set to `false`, only `object` values will be allowed.
|
|
90
|
+
*
|
|
86
91
|
* @param {*} [opts.default] A default value if the namespace is not found.
|
|
87
92
|
*
|
|
88
93
|
* @return {*} The property if found, or `opts.default` if not.
|
|
@@ -90,13 +95,13 @@ exports.nsArray = nsArray;
|
|
|
90
95
|
*/
|
|
91
96
|
function getObjectPath(obj, proppath, opts={})
|
|
92
97
|
{
|
|
93
|
-
needObj(obj, true);
|
|
94
|
-
|
|
95
98
|
if (typeof opts === B)
|
|
96
99
|
opts = {log: opts};
|
|
97
100
|
else if (!isObj(opts))
|
|
98
101
|
opts = {};
|
|
99
102
|
|
|
103
|
+
needObj(obj, (opts.allowFun ?? true));
|
|
104
|
+
|
|
100
105
|
proppath = nsArray(proppath);
|
|
101
106
|
|
|
102
107
|
for (let p = 0; p < proppath.length; p++)
|
package/lib/objectid.js
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
|
|
2
2
|
const {notNil,def,isNil,F,N,S,SY} = require('./types');
|
|
3
|
+
const argOpts = require('./opt/args');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* Generate a
|
|
6
|
+
* Generate a random number.
|
|
6
7
|
*
|
|
7
|
-
* @param {number} [
|
|
8
|
+
* @param {(object|number)} [opts] Options
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* @param {number} [opts.seed] A base number to use.
|
|
11
|
+
*
|
|
12
|
+
* If this is omitted, or an invalid value (including `0`),
|
|
13
|
+
* the default is to use `Date.now()` as the `seed`.
|
|
14
|
+
*
|
|
15
|
+
* @param {number} [mode=1] Determine how to handle return value
|
|
16
|
+
*
|
|
17
|
+
* | Mode | Description |
|
|
18
|
+
* | ------- | --------------------------------------------------------- |
|
|
19
|
+
* | `0` | Return unmodified floating point number |
|
|
20
|
+
* | `1` | `Math.round()` (default) |
|
|
21
|
+
* | `2` | `Math.floor()` |
|
|
22
|
+
* | `3` | `Math.ceil()` |
|
|
10
23
|
*
|
|
11
24
|
* @returns {number}
|
|
12
25
|
* @alias module:@lumjs/core.randomNumber
|
|
13
26
|
*/
|
|
14
|
-
function randomNumber(seed)
|
|
27
|
+
function randomNumber(seed=0, mode=1)
|
|
15
28
|
{
|
|
16
|
-
if (typeof seed !== N) seed = Date.now();
|
|
17
|
-
|
|
29
|
+
if (typeof seed !== N || seed === 0) seed = Date.now();
|
|
30
|
+
|
|
31
|
+
const rand = Math.random() * seed;
|
|
32
|
+
|
|
33
|
+
switch(mode)
|
|
34
|
+
{
|
|
35
|
+
case 1: return Math.round(rand);
|
|
36
|
+
case 2: return Math.floor(rand);
|
|
37
|
+
case 3: return Math.ceil(rand);
|
|
38
|
+
default: return rand;
|
|
39
|
+
}
|
|
18
40
|
}
|
|
19
41
|
|
|
20
42
|
exports.randomNumber = randomNumber;
|
|
@@ -206,20 +228,20 @@ class InternalObjectId
|
|
|
206
228
|
* @param {object} opts - Named options to change default behaviours.
|
|
207
229
|
* @param {string} [opts.name] A friendly name for diagnostics.
|
|
208
230
|
* @param {(string|number)} [opts.id] An internal id value.
|
|
209
|
-
*
|
|
231
|
+
* A reasonable default will be generated if it's not specified.
|
|
210
232
|
* @param {(string|Symbol)} [opts.property] The property name or Symbol.
|
|
211
233
|
* This is the property that will be set on objects that are tagged
|
|
212
|
-
* with this InternalObjectId. Default is `Symbol
|
|
234
|
+
* with this InternalObjectId. Default is a unique (non-global) `Symbol`.
|
|
213
235
|
* @param {boolean} [opts.useInstance=true] Store object or id value?
|
|
214
236
|
* If this is `true` (now the default), we store the instance itself.
|
|
215
237
|
* If this is `false` (the old default), we store just the `id` value.
|
|
216
238
|
*/
|
|
217
239
|
constructor(opts={})
|
|
218
240
|
{
|
|
241
|
+
const ui = this.useInstance = opts.useInstance ?? true;
|
|
219
242
|
this.name = opts.name;
|
|
220
|
-
this.id = opts.id ?? randomNumber();
|
|
221
|
-
this.property = opts.property ?? Symbol(this.id);
|
|
222
|
-
this.useInstance = opts.useInstance ?? true;
|
|
243
|
+
this.id = opts.id ?? (ui ? Date.now() : randomNumber());
|
|
244
|
+
this.property = opts.property ?? Symbol(this.name ?? this.id);
|
|
223
245
|
}
|
|
224
246
|
|
|
225
247
|
/**
|
|
@@ -268,8 +290,7 @@ class InternalObjectId
|
|
|
268
290
|
*/
|
|
269
291
|
isFunction()
|
|
270
292
|
{
|
|
271
|
-
|
|
272
|
-
return function(obj) { return oid.is(obj); }
|
|
293
|
+
return obj => this.is(obj);
|
|
273
294
|
}
|
|
274
295
|
|
|
275
296
|
}
|
package/lib/observable.js
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {F,S,isArray,isa} = require('../types');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Abstract classes for Javascript.
|
|
7
|
+
* @deprecated Just use `throw new AbstractError()` instead.
|
|
8
|
+
* @alias module:@lumjs/core/meta.AbstractClass
|
|
9
|
+
*/
|
|
10
|
+
class AbstractClass
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* If you want to mark a method as abstract use this.
|
|
14
|
+
*/
|
|
15
|
+
$abstract(name)
|
|
16
|
+
{
|
|
17
|
+
if (name.indexOf('(') === -1)
|
|
18
|
+
{ // Add empty method signature.
|
|
19
|
+
name += '()';
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Abstract method ${name} was not implemented`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Check for required properties
|
|
26
|
+
*
|
|
27
|
+
* @param {...(string|Array)} needs - What is needed
|
|
28
|
+
*
|
|
29
|
+
* If this is a `string` it should be in a format like:
|
|
30
|
+
*
|
|
31
|
+
* - `methodName(arg1,arg2,arg3)`
|
|
32
|
+
* - `anotherMethod(number, string, object) : boolean`
|
|
33
|
+
* - `yetAnother (className) : resultClass`
|
|
34
|
+
*
|
|
35
|
+
* The names are case sensitive, and we'll look for the method after
|
|
36
|
+
* stripping off anything from the first *non-word* character.
|
|
37
|
+
*
|
|
38
|
+
* If this is an `Array`, the first item must be the name of a property,
|
|
39
|
+
* and each other item should be a type checking value, or array of type
|
|
40
|
+
* checking values from the [TYPES]{@link module:@lumjs/core/types.TYPES}
|
|
41
|
+
* object, as used by [isa()]{@link module:@lumjs/core/types.isa}.
|
|
42
|
+
*
|
|
43
|
+
* If you are calling this in an abstract class constructor, likely only
|
|
44
|
+
* the method checks will be useful, as the `super()` call must be done
|
|
45
|
+
* *before* any instance property assignments.
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
$needs(...needs)
|
|
49
|
+
{
|
|
50
|
+
const className = this.constructor.name;
|
|
51
|
+
|
|
52
|
+
const getName = fullName => fullName.replace(/\W.*/, '');
|
|
53
|
+
const missing = propName =>
|
|
54
|
+
{
|
|
55
|
+
throw new Error(`${className} is missing ${propName}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const need of needs)
|
|
59
|
+
{
|
|
60
|
+
if (typeof need === S)
|
|
61
|
+
{ // A simple method
|
|
62
|
+
const meth = getName(need);
|
|
63
|
+
if (typeof this[meth] !== F)
|
|
64
|
+
{
|
|
65
|
+
missing(need);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (isArray(need))
|
|
69
|
+
{
|
|
70
|
+
const prop = getName(need[0]);
|
|
71
|
+
const types = need.slice(1);
|
|
72
|
+
if (!isa(this[prop], ...types))
|
|
73
|
+
{
|
|
74
|
+
missing(need);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = AbstractClass;
|