@lumjs/core 1.30.0 → 1.31.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/README.md +1 -1
- package/jsdoc.js +13 -0
- package/lib/enum.js +38 -9
- package/lib/events/event.js +85 -0
- package/lib/events/index.js +42 -0
- package/lib/events/listener.js +127 -0
- package/lib/events/registry.js +737 -0
- package/lib/index.js +26 -2
- package/lib/meta.js +15 -6
- package/lib/obj/copyprops.js +1 -1
- package/lib/obj/cp.js +1375 -0
- package/lib/obj/flip.js +2 -0
- package/lib/obj/index.js +2 -1
- package/lib/objectid.js +7 -0
- package/lib/state.js +61 -0
- package/lib/types/basics.js +6 -14
- package/lib/types/dt.js +3 -3
- package/lib/types/index.js +0 -3
- package/lib/types/js.js +21 -2
- package/lib/types/typelist.js +6 -4
- package/lum.build.js +11 -0
- package/package.json +19 -13
- package/TODO.md +0 -76
- package/jsdoc.json +0 -33
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ You can compile the documentation using `npm run build-docs`
|
|
|
26
26
|
which will put the generated docs into the `./docs/api` folder.
|
|
27
27
|
|
|
28
28
|
### [Changelog](./docs/changelogs/1.x.md)
|
|
29
|
-
### [TODO](TODO.md)
|
|
29
|
+
### [TODO](./docs/TODO.md)
|
|
30
30
|
### [Homepage](https://supernovus.github.io/)
|
|
31
31
|
|
|
32
32
|
## Official URLs
|
package/jsdoc.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const docRules = require('@lumjs/build/jsdoc-rules');
|
|
4
|
+
const ourRules = docRules.docsReadme.srcDocs.clone();
|
|
5
|
+
module.exports = ourRules;
|
|
6
|
+
|
|
7
|
+
/*console.debug(
|
|
8
|
+
{
|
|
9
|
+
docRules,
|
|
10
|
+
ourRules,
|
|
11
|
+
incPath: ourRules?.source?.include,
|
|
12
|
+
});*/
|
|
13
|
+
|
package/lib/enum.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
const {S,def,notNil,isObj,needObj,TYPES} = require('./types');
|
|
1
|
+
const {S,F,def,notNil,isObj,needObj,TYPES} = require('./types');
|
|
2
2
|
const {InternalObjectId} = require('./objectid');
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* A pseudo-module describing everything associated with `core.Enum`
|
|
6
|
+
* @module @lumjs/core/enum
|
|
7
|
+
*/
|
|
8
|
+
|
|
4
9
|
// Internal id instances should never be exported.
|
|
5
10
|
const EID = '@lumjs/core/enum';
|
|
6
11
|
const ENUM_ID = new InternalObjectId({name: EID});
|
|
@@ -12,6 +17,8 @@ const EOPT = Symbol(EID+':opts');
|
|
|
12
17
|
*
|
|
13
18
|
* Like the built-in `Symbol`, this is called as a function, not a constructor.
|
|
14
19
|
*
|
|
20
|
+
* This is the *actual* exported value from the `enum` pseudo-module.
|
|
21
|
+
*
|
|
15
22
|
* @param {(string[]|object)} spec - May be in one of two formats:
|
|
16
23
|
*
|
|
17
24
|
* - An `Array` of strings. Each string represents the name of an Enum
|
|
@@ -27,7 +34,13 @@ const EOPT = Symbol(EID+':opts');
|
|
|
27
34
|
*
|
|
28
35
|
* @param {object} [opts] Options for creating the Enum
|
|
29
36
|
*
|
|
30
|
-
*
|
|
37
|
+
* If the `opts` is an _open_ `Enum` object, then
|
|
38
|
+
*
|
|
39
|
+
* @param {(bool|function)} [opts.symbols=false] Use `Symbol` property values.
|
|
40
|
+
*
|
|
41
|
+
* If this is a `function`, it will be passed the name that would be used as
|
|
42
|
+
* the symbol key, and must return the actual key string to use, or any
|
|
43
|
+
* non-string value to disable the use of symbols for that name.
|
|
31
44
|
*
|
|
32
45
|
* @param {bool} [opts.globals=false] Use `Symbol.for()` property values.
|
|
33
46
|
*
|
|
@@ -48,18 +61,24 @@ const EOPT = Symbol(EID+':opts');
|
|
|
48
61
|
*
|
|
49
62
|
* The default value is `1` if `opts.flags` is `true` or `0` otherwise.
|
|
50
63
|
*
|
|
51
|
-
* @param {bool} [opts.open=false]
|
|
52
|
-
*
|
|
64
|
+
* @param {bool} [opts.open=false] Should the Enum be open to be extended?
|
|
65
|
+
*
|
|
66
|
+
* - If `true` the Enum object won't be locked, and the `opts` will be saved.
|
|
67
|
+
* - If `false` (default value) we use `Object.freeze()` to lock the object.
|
|
53
68
|
*
|
|
54
69
|
* @param {(bool|object|Array)} [opts.lock=null] If this is *not* `null`,
|
|
55
70
|
* use {@see module:@lumjs/core/obj.lock lock()} instead of `Object.freeze()`.
|
|
56
71
|
*
|
|
57
|
-
*
|
|
72
|
+
* If `opts.open` is `false`, the supported values are:
|
|
58
73
|
*
|
|
59
74
|
* - `Array`: The `[cloneable, cloneOpts, useSeal]` parameters for `clone()`.
|
|
60
75
|
* - `object`: The `cloneOpts` parameter for `clone()`.
|
|
61
76
|
* - `bool`: The `cloneable` parameter for `clone()`.
|
|
62
77
|
*
|
|
78
|
+
* If `opts.open` is `true`, this only supports an `object` which will be
|
|
79
|
+
* used as the `opts` for {@see module:@lumjs/core/obj.addLock addLock()},
|
|
80
|
+
* which will be called on the open Enum object.
|
|
81
|
+
*
|
|
63
82
|
* @param {bool} [opts.configurable=false] Enum properties are configurable?
|
|
64
83
|
*
|
|
65
84
|
* This option is ignored if `opts.open` is `false`.
|
|
@@ -68,7 +87,7 @@ const EOPT = Symbol(EID+':opts');
|
|
|
68
87
|
*
|
|
69
88
|
* @returns {object} A magic Enum object.
|
|
70
89
|
* @throws {TypeError} If an invalid value was passed.
|
|
71
|
-
* @
|
|
90
|
+
* @alias module:@lumjs/core/enum.Enum
|
|
72
91
|
*/
|
|
73
92
|
function Enum (spec, opts={})
|
|
74
93
|
{
|
|
@@ -89,17 +108,23 @@ function Enum (spec, opts={})
|
|
|
89
108
|
const configurable = opts.configurable ?? false;
|
|
90
109
|
const enumerable = opts.enumerable ?? true;
|
|
91
110
|
|
|
111
|
+
const symKey
|
|
112
|
+
= (typeof opts.symbols === F)
|
|
113
|
+
? opts.symbols
|
|
114
|
+
: v => v;
|
|
115
|
+
|
|
92
116
|
function getVal (name, def)
|
|
93
117
|
{
|
|
94
118
|
if (opts.symbols)
|
|
95
119
|
{ // We want to use symbols.
|
|
120
|
+
const key = symKey(name);
|
|
96
121
|
if (opts.globals)
|
|
97
122
|
{
|
|
98
|
-
return Symbol.for(
|
|
123
|
+
return Symbol.for(key);
|
|
99
124
|
}
|
|
100
125
|
else
|
|
101
126
|
{
|
|
102
|
-
return Symbol(
|
|
127
|
+
return Symbol(key);
|
|
103
128
|
}
|
|
104
129
|
}
|
|
105
130
|
else
|
|
@@ -162,6 +187,10 @@ function Enum (spec, opts={})
|
|
|
162
187
|
if (!isExisting)
|
|
163
188
|
{ // Save the options into a special Symbol property.
|
|
164
189
|
def(anEnum, EOPT, {value: opts});
|
|
190
|
+
if (isObj(opts.lock))
|
|
191
|
+
{ // Add lock() method.
|
|
192
|
+
addLock(anEnum, opts.lock);
|
|
193
|
+
}
|
|
165
194
|
}
|
|
166
195
|
}
|
|
167
196
|
else
|
|
@@ -223,4 +252,4 @@ TYPES.add('ENUM', 'enum', isEnum, 'isEnum');
|
|
|
223
252
|
module.exports = Enum;
|
|
224
253
|
|
|
225
254
|
// Loading this at the end.
|
|
226
|
-
const {lock} = require('./obj/lock');
|
|
255
|
+
const {lock,addLock} = require('./obj/lock');
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {F,isObj} = require('../types');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An Event object to emit to handler callbacks.
|
|
7
|
+
*
|
|
8
|
+
* @prop {module:@lumjs/core/events.Listener} eventListener
|
|
9
|
+
* The event Listener instance this event was emitted from.
|
|
10
|
+
* @prop {string} name - The event name that was triggered.
|
|
11
|
+
* @prop {object} target - Target object for this event.
|
|
12
|
+
* @prop {Array} args - Arguments passed to `emit()`
|
|
13
|
+
* @prop {object} options - Composes options from the
|
|
14
|
+
* Registry and the Listener. Listener options take priority.
|
|
15
|
+
* @prop {?object} data
|
|
16
|
+
* If `args[0]` is any kind of `object` other than another Event
|
|
17
|
+
* instance, it will be used as the `data` property.
|
|
18
|
+
* If `args[0]` is not an `object`, this property will be `null`.
|
|
19
|
+
* @prop {module:@lumjs/core/events.Event} origEvent
|
|
20
|
+
* Unless `this.prevEvent` is set, this should always be
|
|
21
|
+
* a reference to `this` instance itself.
|
|
22
|
+
* @prop {?module:@lumjs/core/events.Event} prevEvent
|
|
23
|
+
* If `args[0]` is another Event instance this property
|
|
24
|
+
* will be set with its value, as well as the following
|
|
25
|
+
* changes to the default behavior:
|
|
26
|
+
*
|
|
27
|
+
* - `this.data` will be set to `prevEvent.data`.
|
|
28
|
+
* - `this.origEvent` will be set to `prevEvent.origEvent`
|
|
29
|
+
*
|
|
30
|
+
* @prop {module:@lumjs/core/events~Status} emitStatus
|
|
31
|
+
*
|
|
32
|
+
* @alias module:@lumjs/core/events.Event
|
|
33
|
+
*/
|
|
34
|
+
class LumEvent
|
|
35
|
+
{
|
|
36
|
+
/**
|
|
37
|
+
* Create a new Event instance; should not be called directly.
|
|
38
|
+
* @protected
|
|
39
|
+
* @param {module:@lumjs/core/events.Listener} listener
|
|
40
|
+
* @param {object} target
|
|
41
|
+
* @param {string} name
|
|
42
|
+
* @param {Array} args
|
|
43
|
+
* @param {object} status
|
|
44
|
+
*/
|
|
45
|
+
constructor(listener, target, name, args, status)
|
|
46
|
+
{
|
|
47
|
+
const reg = listener.registry;
|
|
48
|
+
this.eventListener = listener;
|
|
49
|
+
this.args = args;
|
|
50
|
+
this.target = target;
|
|
51
|
+
this.name = name;
|
|
52
|
+
this.emitStatus = status;
|
|
53
|
+
this.options = Object.assign({},
|
|
54
|
+
reg.options,
|
|
55
|
+
listener.options,
|
|
56
|
+
status.options);
|
|
57
|
+
|
|
58
|
+
this.data = null;
|
|
59
|
+
this.prevEvent = null;
|
|
60
|
+
this.origEvent = this;
|
|
61
|
+
|
|
62
|
+
if (isObj(args[0]))
|
|
63
|
+
{ // The first argument is an object.
|
|
64
|
+
const ao = args[0];
|
|
65
|
+
if (ao instanceof LumEvent)
|
|
66
|
+
{ // A previous event.
|
|
67
|
+
this.prevEvent = ao;
|
|
68
|
+
this.origEvent = ao.origEvent;
|
|
69
|
+
this.data = ao.data;
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{ // Use it as a data object.
|
|
73
|
+
this.data = ao;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof this.options.setupEvent === F)
|
|
78
|
+
{
|
|
79
|
+
this.options.setupEvent.call(listener, this);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = LumEvent;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simplistic event registration and dispatch module.
|
|
3
|
+
*
|
|
4
|
+
* Designed to be a replacement for the `observable` API which started
|
|
5
|
+
* out simple enough (when I forked it from `riot.js`), but has since
|
|
6
|
+
* grown into a big mess with many unusual and unexpected behaviours.
|
|
7
|
+
*
|
|
8
|
+
* So this has been designed to work with a cleaner, more consistent,
|
|
9
|
+
* yet extremely flexible event model.
|
|
10
|
+
*
|
|
11
|
+
* @module @lumjs/core/events
|
|
12
|
+
*/
|
|
13
|
+
exports = module.exports =
|
|
14
|
+
{
|
|
15
|
+
Registry: require('./registry'),
|
|
16
|
+
Listener: require('./listener'),
|
|
17
|
+
Event: require('./event'),
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A shortcut function to create a new Registry instance.
|
|
21
|
+
* All arguments are passed to the Registry constructor.
|
|
22
|
+
* @param {(object|module:@lumjs/core/events~GetTargets)} targets
|
|
23
|
+
* @param {object} [opts]
|
|
24
|
+
* @returns {module:@lumjs/core/events.Registry}
|
|
25
|
+
*/
|
|
26
|
+
register(targets, opts)
|
|
27
|
+
{
|
|
28
|
+
return new exports.Registry(targets, opts);
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a registry for a single target object, then return the target.
|
|
33
|
+
* @param {object} target
|
|
34
|
+
* @param {object} [opts]
|
|
35
|
+
* @returns {object} `target`
|
|
36
|
+
*/
|
|
37
|
+
extend(target, opts)
|
|
38
|
+
{
|
|
39
|
+
exports.register(target, opts);
|
|
40
|
+
return target;
|
|
41
|
+
},
|
|
42
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {F,isObj} = require('../types');
|
|
4
|
+
const Event = require('./event');
|
|
5
|
+
|
|
6
|
+
const REMOVE_OPTS = ['listener','handler','eventNames'];
|
|
7
|
+
|
|
8
|
+
function makeOpts(spec)
|
|
9
|
+
{
|
|
10
|
+
const opts = Object.assign({}, spec, spec.options);
|
|
11
|
+
for (const rm of REMOVE_OPTS)
|
|
12
|
+
{
|
|
13
|
+
delete opts[rm];
|
|
14
|
+
}
|
|
15
|
+
return opts;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Is something a valid value for an event listener?
|
|
20
|
+
*
|
|
21
|
+
* Valid listener values are inspired by the `DOM.EventTarget` interface:
|
|
22
|
+
*
|
|
23
|
+
* - A `function`
|
|
24
|
+
* - An `object` with a `handleEvent()` method
|
|
25
|
+
*
|
|
26
|
+
* @param {*} v - Value we are testing
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
* @alias module:@lumjs/core/events.Listener.isListener
|
|
29
|
+
*/
|
|
30
|
+
function isListener(v)
|
|
31
|
+
{
|
|
32
|
+
return (typeof v === F || (isObj(v) && typeof v.handleEvent === F));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* An Event Listener instance used by a Registry
|
|
37
|
+
*
|
|
38
|
+
* Used internally by the Registry class, there's likely very few
|
|
39
|
+
* reasons you'd want to call any methods on this manually.
|
|
40
|
+
*
|
|
41
|
+
* @prop {module:@lumjs/core/events.Registry} registry
|
|
42
|
+
* The Registry instance this Listener belongs to.
|
|
43
|
+
* @prop {(function|object)} handler - Event handler callback
|
|
44
|
+
* @prop {Set} eventNames - A set of all event names handled by this
|
|
45
|
+
* @prop {object} options - Options specific to this listener.
|
|
46
|
+
*
|
|
47
|
+
* See {@link module:@lumjs/core/events.Registry#makeListener makeListener()}
|
|
48
|
+
* for details on what this may contain and how it is populated.
|
|
49
|
+
*
|
|
50
|
+
* @alias module:@lumjs/core/events.Listener
|
|
51
|
+
*/
|
|
52
|
+
class LumEventListener
|
|
53
|
+
{
|
|
54
|
+
/**
|
|
55
|
+
* Build a listener; called by Registry instance
|
|
56
|
+
* @private
|
|
57
|
+
* @param {module:@lumjs/core/events.Registry} registry
|
|
58
|
+
* @param {object} spec
|
|
59
|
+
*/
|
|
60
|
+
constructor(registry, spec)
|
|
61
|
+
{
|
|
62
|
+
if (isListener(spec.listener))
|
|
63
|
+
{
|
|
64
|
+
this.handler = spec.listener;
|
|
65
|
+
}
|
|
66
|
+
else if (isListener(spec.handler))
|
|
67
|
+
{
|
|
68
|
+
this.handler = spec.handler;
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
{
|
|
72
|
+
console.error({spec,registry});
|
|
73
|
+
throw new TypeError("Invalid listener/handler in spec");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Assign the rest here.
|
|
77
|
+
this.registry = registry;
|
|
78
|
+
this.options = makeOpts(spec);
|
|
79
|
+
this.eventNames = registry.getEventNames(spec.eventNames);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* See if there is at least one item in `this.eventNames`
|
|
84
|
+
* @type {boolean}
|
|
85
|
+
*/
|
|
86
|
+
get hasEvents()
|
|
87
|
+
{
|
|
88
|
+
return this.eventNames.size > 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Used by {@link module:@lumjs/core/events.Registry#emit emit()} to create
|
|
93
|
+
* and emit a new Event instance for a specified event name and target.
|
|
94
|
+
*
|
|
95
|
+
* This is a *protected method* and should not be called directly.
|
|
96
|
+
* @protected
|
|
97
|
+
* @param {string} eventName - A single event name that was triggered
|
|
98
|
+
* @param {object} target - A single target object
|
|
99
|
+
* @param {Array} args - Arguments passed to `emit()`
|
|
100
|
+
* @param {module:@lumjs/core/events~Status} status - Emit status info
|
|
101
|
+
* @returns {module:@lumjs/core/events.Event} The new Event that was emitted
|
|
102
|
+
*/
|
|
103
|
+
emitEvent(eventName, target, args, status)
|
|
104
|
+
{
|
|
105
|
+
const event = new Event(this, target, eventName, args, status);
|
|
106
|
+
|
|
107
|
+
if (typeof this.handler === F)
|
|
108
|
+
{ // The simplest is the good old function
|
|
109
|
+
this.handler.call(event.target, event);
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
{ // An object with a `handleEvent()` method
|
|
113
|
+
this.handler.handleEvent(event);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (event.options.once)
|
|
117
|
+
{ // This listener is to be removed
|
|
118
|
+
status.onceRemoved.add(this);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return event;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
LumEventListener.isListener = isListener;
|
|
127
|
+
module.exports = LumEventListener;
|