@lumjs/core 1.38.1 → 1.38.3
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/arrays/index.js +1 -1
- package/lib/arrays/typed.js +139 -0
- package/lib/events/index.js +103 -70
- package/lib/events/observable.js +2 -237
- package/lib/index.js +13 -12
- package/lib/meta.js +2 -2
- package/lib/obj/assignd.js +52 -5
- package/lib/obj/df.js +221 -74
- package/lib/obj/getprotos.js +25 -0
- package/lib/obj/index.js +26 -6
- package/lib/obj/ns.js +96 -20
- package/lib/objectid.js +43 -13
- package/lib/observable.js +1 -0
- package/lib/types/basics.js +29 -3
- package/lib/types/def.js +4 -1
- package/lib/types/index.js +10 -2
- package/lib/types/isa.js +4 -4
- package/lib/types/lazy.js +12 -219
- package/package.json +3 -2
- package/lib/events/event.js +0 -89
- package/lib/events/listener.js +0 -139
- package/lib/events/registry.js +0 -875
package/lib/obj/assignd.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {dfa} = require('./df');
|
|
4
|
-
const {isObj,isNil} = require('../types');
|
|
3
|
+
const {df,dfa} = require('./df');
|
|
4
|
+
const {isObj,isIterable,isNil} = require('../types');
|
|
5
|
+
const cp = Object.assign;
|
|
6
|
+
const ASSIGND_OPTS = Symbol('@lumjs/core/obj.assignd~opts');
|
|
7
|
+
const DEF_OPTS = {force: 'configurable'};
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Copy properties into a target object.
|
|
@@ -13,27 +16,71 @@ const {isObj,isNil} = require('../types');
|
|
|
13
16
|
* Basically a super simple, non-recursive replacement for my copyProps()
|
|
14
17
|
* and cp() functions that were overly complex and tried to do way too much.
|
|
15
18
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
19
|
+
* The default options used by this function when calling dfa() are:
|
|
20
|
+
*
|
|
21
|
+
* `{configurable: true, force: 'configurable'}`
|
|
22
|
+
*
|
|
23
|
+
* Which simply means that by default the `configurable` descriptor property
|
|
24
|
+
* will be forced to `true` on the properties assigned, allowing them to be
|
|
25
|
+
* re-assigned later. You can override the defaults using special properties
|
|
26
|
+
* in either the target or source objects.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} target - The target object to copy properties into.
|
|
29
|
+
*
|
|
30
|
+
* If you create a `target[assignd.OPTS]` property as an object, it may be
|
|
31
|
+
* used to set any of the options supported by the dfa() function.
|
|
32
|
+
* The options specified here take priority over the defaults shown above,
|
|
33
|
+
* and will be used for all sources.
|
|
34
|
+
*
|
|
35
|
+
* In addition to the options supported by dfa(), an additional `skip`
|
|
36
|
+
* option may be specified, it should be an array of property keys that
|
|
37
|
+
* SHOULD NOT be overwritten in the target. The `assignd.OPTS` property
|
|
38
|
+
* is always implicitly in the skip list and will never be overridden.
|
|
39
|
+
*
|
|
40
|
+
* @param {...object} sources - Source objects to copy properties from.
|
|
41
|
+
*
|
|
42
|
+
* If you create a `source[assignd.OPTS]` property as an object, it may be
|
|
43
|
+
* used to set any of the options supported by the dfa() function.
|
|
44
|
+
* The options specified here take priority over any set in the `target`,
|
|
45
|
+
* and only apply to that specific source object.
|
|
46
|
+
*
|
|
47
|
+
* The options assigned to source objects do NOT support the `skip` option.
|
|
48
|
+
*
|
|
18
49
|
* @returns {object} the `target` object
|
|
19
50
|
*
|
|
20
51
|
* @alias module:@lumjs/core/obj.assignd
|
|
21
52
|
*/
|
|
22
53
|
function assignd (target, ...sources)
|
|
23
54
|
{
|
|
55
|
+
const skips = [ASSIGND_OPTS];
|
|
56
|
+
const topts = cp({}, DEF_OPTS, target[ASSIGND_OPTS]);
|
|
57
|
+
|
|
58
|
+
if (isIterable(topts.skip))
|
|
59
|
+
{
|
|
60
|
+
skips.push(...topts.skip);
|
|
61
|
+
}
|
|
62
|
+
|
|
24
63
|
for (const src of sources)
|
|
25
64
|
{
|
|
26
65
|
if (isObj(src))
|
|
27
66
|
{
|
|
67
|
+
const sopts = cp({}, topts, src[ASSIGND_OPTS]);
|
|
28
68
|
const descs = Object.getOwnPropertyDescriptors(src);
|
|
29
|
-
|
|
69
|
+
for (let skip of skips)
|
|
70
|
+
{
|
|
71
|
+
delete descs[skip];
|
|
72
|
+
}
|
|
73
|
+
dfa(target, descs, sopts);
|
|
30
74
|
}
|
|
31
75
|
else if (!isNil(src))
|
|
32
76
|
{
|
|
33
77
|
console.error("Invalid assignd source", {src, sources, target});
|
|
34
78
|
}
|
|
35
79
|
}
|
|
80
|
+
|
|
36
81
|
return target;
|
|
37
82
|
}
|
|
38
83
|
|
|
84
|
+
df(assignd, 'OPTS', {value: ASSIGND_OPTS});
|
|
85
|
+
|
|
39
86
|
module.exports = assignd;
|
package/lib/obj/df.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const {B,F,S,doesDescriptor} = require('../types/basics');
|
|
4
|
+
const {needObj,needType} = require('../types/needs');
|
|
5
|
+
const TYPES = require('../types/typelist');
|
|
4
6
|
|
|
5
7
|
const DEF_DESC = {configurable: true}
|
|
6
8
|
|
|
@@ -11,8 +13,8 @@ const dps = Object.defineProperties;
|
|
|
11
13
|
/**
|
|
12
14
|
* Handle populating descriptor objects for df() and family.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
+
* Alias: `df.descriptor()`
|
|
17
|
+
* @alias module:@lumjs/core/obj~descriptor
|
|
16
18
|
*
|
|
17
19
|
* @param {object} desc - Descriptor object from df()
|
|
18
20
|
* @param {object} opts - Options from df();
|
|
@@ -30,8 +32,17 @@ const dps = Object.defineProperties;
|
|
|
30
32
|
* only applies to data descriptors (ones with a `value` property),
|
|
31
33
|
* NOT to accessor descriptors.
|
|
32
34
|
*
|
|
35
|
+
* @param {(boolean|string|string[])} [opts.force=false] Force `opts` values?
|
|
36
|
+
*
|
|
37
|
+
* If this is set to true, then any descriptor property specified in `opts`
|
|
38
|
+
* will be set on `desc` regardless as to if it already has that property.
|
|
39
|
+
* That includes the fallback `configurable` property value.
|
|
40
|
+
*
|
|
41
|
+
* You may also set this to the name(s) of the properties which should
|
|
42
|
+
* be forced (any not in the list will only be assigned if not in the
|
|
43
|
+
* `desc` object already).
|
|
44
|
+
*
|
|
33
45
|
* @returns {object} `desc`
|
|
34
|
-
* @alias module:@lumjs/core/obj~descriptor
|
|
35
46
|
*/
|
|
36
47
|
function descriptor(desc, opts)
|
|
37
48
|
{
|
|
@@ -40,9 +51,24 @@ function descriptor(desc, opts)
|
|
|
40
51
|
const dps = ['configurable', 'enumerable'];
|
|
41
52
|
if (desc.value) dps.push('writable');
|
|
42
53
|
|
|
54
|
+
let force;
|
|
55
|
+
if (!opts.force)
|
|
56
|
+
{ // force NONE
|
|
57
|
+
force = [];
|
|
58
|
+
}
|
|
59
|
+
else if (opts.force === true)
|
|
60
|
+
{ // force ALL
|
|
61
|
+
force = dps;
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
{ // force selected
|
|
65
|
+
force = Array.isArray(opts.force) ? opts.force : [opts.force];
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
for (const dp of dps)
|
|
44
69
|
{
|
|
45
|
-
if (typeof
|
|
70
|
+
if (typeof opts[dp] === B
|
|
71
|
+
&& (force.includes(dp) || typeof desc[dp] !== B))
|
|
46
72
|
{
|
|
47
73
|
desc[dp] = opts[dp];
|
|
48
74
|
}
|
|
@@ -52,14 +78,10 @@ function descriptor(desc, opts)
|
|
|
52
78
|
}
|
|
53
79
|
|
|
54
80
|
/**
|
|
55
|
-
* A
|
|
56
|
-
*
|
|
57
|
-
* Instead of one function where every argument has several different
|
|
58
|
-
* purposes depending on the type of value, there are now a bunch
|
|
59
|
-
* of functions, each one with a single purpose, and a single signature.
|
|
81
|
+
* A wrapper around Object.defineProperty() which simplifies things a bit.
|
|
60
82
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
83
|
+
* Alias: `df.one`
|
|
84
|
+
* @alias module:@lumjs/core/obj.df
|
|
63
85
|
*
|
|
64
86
|
* @param {(object|function)} obj - Target to define property in
|
|
65
87
|
* @param {(string|symbol)} name - Property identifier
|
|
@@ -68,9 +90,15 @@ function descriptor(desc, opts)
|
|
|
68
90
|
* See `opts.useDesc` for how this value is handled in regards to
|
|
69
91
|
* whether it is treated as a property descriptor or a plain data value.
|
|
70
92
|
*
|
|
71
|
-
* @param {object} [opts] Options
|
|
93
|
+
* @param {(object|function|boolean)} [opts] Options
|
|
72
94
|
*
|
|
73
|
-
*
|
|
95
|
+
* If this is a boolean, it will be used as `opts.useDesc`.
|
|
96
|
+
*
|
|
97
|
+
* If both `value` and this are functions, then they will be used
|
|
98
|
+
* as the `get` and `set` descriptor values and `opts.useDesc` will
|
|
99
|
+
* be set to `true`.
|
|
100
|
+
*
|
|
101
|
+
* See {@link module:@lumjs/core/obj~descriptor} for more options that
|
|
74
102
|
* are used as descriptor defaults when assigning the property.
|
|
75
103
|
*
|
|
76
104
|
* @param {?boolean} [opts.useDesc=null] Treat `value` is a descriptor?
|
|
@@ -86,8 +114,7 @@ function descriptor(desc, opts)
|
|
|
86
114
|
* [doesDescriptor()]{@link module:@lumjs/core/types.doesDescriptor},
|
|
87
115
|
* and that will determine if the value is treated as a descriptor or not.
|
|
88
116
|
*
|
|
89
|
-
* @returns {object} `obj`
|
|
90
|
-
* @alias module:@lumjs/core/obj.df
|
|
117
|
+
* @returns {(object|function)} `obj`
|
|
91
118
|
*/
|
|
92
119
|
function df(obj, name, value, opts={})
|
|
93
120
|
{
|
|
@@ -95,26 +122,37 @@ function df(obj, name, value, opts={})
|
|
|
95
122
|
needObj(obj, {log, fun: true});
|
|
96
123
|
needType(TYPES.PROP, name, {log});
|
|
97
124
|
|
|
125
|
+
if (typeof opts === B)
|
|
126
|
+
{
|
|
127
|
+
opts = {useDesc: opts};
|
|
128
|
+
}
|
|
129
|
+
else if (typeof opts === F && typeof value === F)
|
|
130
|
+
{
|
|
131
|
+
value = {get: value, set: opts};
|
|
132
|
+
opts = {useDesc: true};
|
|
133
|
+
}
|
|
134
|
+
|
|
98
135
|
const useDesc = opts.useDesc ?? doesDescriptor(value);
|
|
99
136
|
const desc = descriptor((useDesc ? value : {value}), opts);
|
|
100
137
|
|
|
101
138
|
return Object.defineProperty(obj, name, desc);
|
|
102
139
|
}
|
|
103
140
|
|
|
104
|
-
|
|
141
|
+
df(df, 'one', df);
|
|
105
142
|
df(df, 'descriptor', descriptor);
|
|
106
|
-
df(df, 'lazy', lazy);
|
|
107
143
|
|
|
108
144
|
/**
|
|
109
145
|
* A wrapper around df() that defines multiple properties at once.
|
|
146
|
+
*
|
|
147
|
+
* Alias: `df.all`
|
|
148
|
+
* @alias module:@lumjs/core/obj.dfa
|
|
110
149
|
*
|
|
111
150
|
* @param {(object|function)} obj - Target to define property in
|
|
112
151
|
* @param {object} values
|
|
113
152
|
* All string-keyed enumerable properties will be passed to df()
|
|
114
|
-
* @param {object} [opts] See df() for details
|
|
153
|
+
* @param {(object|boolean)} [opts] See df() for details
|
|
115
154
|
*
|
|
116
|
-
* @returns {object} `obj`
|
|
117
|
-
* @alias module:@lumjs/core/obj.dfa
|
|
155
|
+
* @returns {(object|function)} `obj`
|
|
118
156
|
*/
|
|
119
157
|
function dfa(obj, values, opts)
|
|
120
158
|
{
|
|
@@ -132,55 +170,38 @@ function dfa(obj, values, opts)
|
|
|
132
170
|
df(df, 'all', dfa);
|
|
133
171
|
|
|
134
172
|
/**
|
|
135
|
-
*
|
|
136
|
-
* BOTH a getter and a setter specified explicitly.
|
|
137
|
-
*
|
|
138
|
-
* @param {(object|function)} obj - Target to define property in
|
|
139
|
-
* @param {(string|symbol)} name - Property identifier
|
|
140
|
-
* @param {function} getter - Getter function
|
|
141
|
-
* @param {function} setter - Setter function
|
|
142
|
-
* @param {object} [opts] Options
|
|
143
|
-
*
|
|
144
|
-
* The actual options passed to df() will be a clone, with the
|
|
145
|
-
* `useDesc` option explicitly forced to `true`.
|
|
146
|
-
*
|
|
147
|
-
*/
|
|
148
|
-
function dfb(obj, name, getter, setter, opts)
|
|
149
|
-
{
|
|
150
|
-
const log = {obj,name,getter,setter,opts};
|
|
151
|
-
opts = clone(opts, {useDesc: true});
|
|
152
|
-
return df(obj, name, {get: getter, set: setter}, opts);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
df(df, 'both', dfb);
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Build magic closures to define properties using a chained syntax.
|
|
173
|
+
* Build closures to define properties using a chained syntax.
|
|
159
174
|
*
|
|
160
|
-
* This
|
|
161
|
-
* You can switch between them using
|
|
175
|
+
* This creates closures for df(), dfa(), and lazy().
|
|
176
|
+
* You can switch between them using special properties.
|
|
162
177
|
*
|
|
163
178
|
* The closures when called will pass their arguments to the function
|
|
164
179
|
* they are wrapping, and in a bit of brain-melting recursion, the
|
|
165
180
|
* return value from each closure is the closure itself.
|
|
166
181
|
*
|
|
167
|
-
*
|
|
182
|
+
* Special Properties that are added to all of the closures:
|
|
168
183
|
*
|
|
169
|
-
* - `one(name,
|
|
170
|
-
*
|
|
171
|
-
* - `
|
|
172
|
-
* - `lazy(name, func)`
|
|
173
|
-
* - `update(opts)`
|
|
184
|
+
* - `one(name, val, [set])` → A closure that wraps df();
|
|
185
|
+
* `set` (setter function) is only used if `val` is a getter function.
|
|
186
|
+
* - `all(values)` → A closure that wraps dfa()
|
|
187
|
+
* - `lazy(name, func)` → A closure that wraps lazy()
|
|
188
|
+
* - `update(opts)` → Update the options used by the closures.
|
|
174
189
|
* Uses Object.assign() to copy options from the specied object
|
|
175
|
-
* to the internal options object from the original
|
|
190
|
+
* to the internal options object from the original dfor() call.
|
|
176
191
|
* This is a method call, NOT a closure function.
|
|
177
|
-
* - `opts`
|
|
178
|
-
* - `obj`
|
|
179
|
-
* - `for(obj)`
|
|
192
|
+
* - `opts` → The options object used by the closures.
|
|
193
|
+
* - `obj` → The target object used by the closures.
|
|
194
|
+
* - `for(obj)` → A wrapper method that will call dfor().
|
|
180
195
|
* When using this method, a *new set of closures* will be created,
|
|
181
196
|
* with the current options, but a new target object.
|
|
182
197
|
* If you use this in a chained statement, any calls after this
|
|
183
198
|
* will be using the new closures rather than the original ones.
|
|
199
|
+
* - `prev` → The previous closure(s) from which
|
|
200
|
+
* the chained `for()` method was called. If there is no previous
|
|
201
|
+
* set of closures, then this will return the current closure.
|
|
202
|
+
*
|
|
203
|
+
* Alias: `df.for()`
|
|
204
|
+
* @alias module:@lumjs/core/obj.dfor
|
|
184
205
|
*
|
|
185
206
|
* @param {(object|function)} obj - Target to define property in;
|
|
186
207
|
* available as the `obj` magic property on the closures.
|
|
@@ -188,12 +209,22 @@ df(df, 'both', dfb);
|
|
|
188
209
|
* @param {object} [opts] Options - see df() for details;
|
|
189
210
|
* available as the `opts` magic property on the closures.
|
|
190
211
|
*
|
|
212
|
+
* @param {?function} [prev=null] INTERNAL USE ONLY;
|
|
213
|
+
* if the `for()` wrapper method is used in a closure,
|
|
214
|
+
* that closure will be passed here, which makes returning
|
|
215
|
+
* to the previous closure possible.
|
|
216
|
+
*
|
|
191
217
|
* @returns {function} The `one` closure.
|
|
192
218
|
*/
|
|
193
|
-
function
|
|
219
|
+
function dfor(obj, opts={}, prev=null)
|
|
194
220
|
{
|
|
195
|
-
const fnOne = function (name, value)
|
|
221
|
+
const fnOne = function (name, value, setter)
|
|
196
222
|
{
|
|
223
|
+
if (typeof setter === F && typeof value === F)
|
|
224
|
+
{
|
|
225
|
+
value = {get: value, set: setter}
|
|
226
|
+
opts = clone(opts, {useDesc: true});
|
|
227
|
+
}
|
|
197
228
|
df(obj, name, value, opts);
|
|
198
229
|
return fnOne;
|
|
199
230
|
}
|
|
@@ -204,12 +235,6 @@ function dfc(obj, opts={})
|
|
|
204
235
|
return fnAll;
|
|
205
236
|
}
|
|
206
237
|
|
|
207
|
-
const fnBoth = function (name, getter, setter)
|
|
208
|
-
{
|
|
209
|
-
dfb(obj, name, getter, setter, opts);
|
|
210
|
-
return fnBoth;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
238
|
const fnLazy = function (name, initfunc)
|
|
214
239
|
{
|
|
215
240
|
lazy(obj, name, initfunc, opts);
|
|
@@ -222,8 +247,8 @@ function dfc(obj, opts={})
|
|
|
222
247
|
opts: {value: opts},
|
|
223
248
|
one: {value: fnOne},
|
|
224
249
|
all: {value: fnAll},
|
|
225
|
-
both: {value: fnBoth},
|
|
226
250
|
lazy: {value: fnLazy},
|
|
251
|
+
prev: {get() { return prev ?? this }},
|
|
227
252
|
update:
|
|
228
253
|
{
|
|
229
254
|
value()
|
|
@@ -236,25 +261,147 @@ function dfc(obj, opts={})
|
|
|
236
261
|
{
|
|
237
262
|
value(newobj)
|
|
238
263
|
{
|
|
239
|
-
|
|
264
|
+
|
|
265
|
+
return dfor(newobj, opts);
|
|
240
266
|
},
|
|
241
267
|
},
|
|
242
268
|
}
|
|
243
269
|
|
|
244
|
-
// Quick alias
|
|
245
|
-
ctx.next = ctx.for;
|
|
246
|
-
|
|
247
270
|
dps(fnOne, ctx);
|
|
248
271
|
dps(fnAll, ctx);
|
|
249
|
-
dps(fnBoth, ctx);
|
|
250
272
|
dps(fnLazy, ctx);
|
|
251
273
|
|
|
252
274
|
return fnOne;
|
|
253
275
|
}
|
|
254
276
|
|
|
255
|
-
df(df, 'for',
|
|
277
|
+
df(df, 'for', dfor);
|
|
256
278
|
|
|
257
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Build a lazy initializer property.
|
|
281
|
+
*
|
|
282
|
+
* This builds an *accessor* property that will replace itself
|
|
283
|
+
* with a initialized property, the value of which is obtained from
|
|
284
|
+
* a supplied initialization function. Any subsequent use of the
|
|
285
|
+
* property will obviously be using the initialized property directly.
|
|
286
|
+
*
|
|
287
|
+
* The general purpose is if there is a property that requires
|
|
288
|
+
* a fairly intensive load time, or requires a large library that
|
|
289
|
+
* you may not always *need* for basic things, you can use this
|
|
290
|
+
* to ensure that the property is only initialized when needed.
|
|
291
|
+
*
|
|
292
|
+
* Alias: `df.lazy`
|
|
293
|
+
* @alias module:@lumjs/core/obj.lazy
|
|
294
|
+
*
|
|
295
|
+
* @param {(object|function)} target - The object to add the property to.
|
|
296
|
+
*
|
|
297
|
+
* @param {string} name - The name of the property to add.
|
|
298
|
+
*
|
|
299
|
+
* @param {module:@lumjs/core/obj~LazyGetter} initfunc
|
|
300
|
+
* The function to initialize the property.
|
|
301
|
+
*
|
|
302
|
+
* This will normally only ever be called the first time the property
|
|
303
|
+
* is accessed in a *read* operation. The return value from this
|
|
304
|
+
* will be assigned to the property using `def()`, replacing the
|
|
305
|
+
* lazy accessor property.
|
|
306
|
+
*
|
|
307
|
+
* @param {object} [opts] Options to customize behavior.
|
|
308
|
+
*
|
|
309
|
+
* @param {module:@lumjs/core/obj~LazySetter} [opts.set]
|
|
310
|
+
* A function to handle assignment attempts.
|
|
311
|
+
*
|
|
312
|
+
* This obviously only applies to the *lazy accessor* property,
|
|
313
|
+
* and will have no affect once the property has been replaced
|
|
314
|
+
* by its initialized value.
|
|
315
|
+
*
|
|
316
|
+
* @param {boolean} [opts.enumerable=false] Is the property enumerable?
|
|
317
|
+
*
|
|
318
|
+
* This applies to the *lazy accessor* property only.
|
|
319
|
+
* You can set custom descriptor rules in the `initfunc`
|
|
320
|
+
* if you need them on the initialized property.
|
|
321
|
+
*
|
|
322
|
+
* @param {?boolean} [opts.assign] The *default* value for the `assign` property
|
|
323
|
+
* in the [LazyDef]{@link module:@lumjs/core/obj~LazyDef} object.
|
|
324
|
+
*
|
|
325
|
+
* @param {*} [opts.df] The *default* value for the `df`/`def` property in
|
|
326
|
+
* the [LazyDef]{@link module:@lumjs/core/obj~LazyDef} object.
|
|
327
|
+
*
|
|
328
|
+
* @param {*} [opts.def] Alias of `opts.df` for compatibility.
|
|
329
|
+
*
|
|
330
|
+
* @returns {(object|function)} The `target` argument
|
|
331
|
+
*/
|
|
332
|
+
function lazy(target, name, initfunc, opts={})
|
|
258
333
|
{
|
|
259
|
-
|
|
334
|
+
let log = {target, name, initfunc, opts};
|
|
335
|
+
needObj(target, {log, fun: true});
|
|
336
|
+
needType(TYPES.PROP, name, {log});
|
|
337
|
+
needType(F, initfunc, {log});
|
|
338
|
+
needObj(opts, {log});
|
|
339
|
+
|
|
340
|
+
// The `this` object for the functions.
|
|
341
|
+
const ctx =
|
|
342
|
+
{
|
|
343
|
+
name,
|
|
344
|
+
target,
|
|
345
|
+
opts,
|
|
346
|
+
arguments,
|
|
347
|
+
assign: opts.assign,
|
|
348
|
+
df: opts.df ?? opts.def ?? {},
|
|
349
|
+
}
|
|
350
|
+
ctx.def = ctx.df;
|
|
351
|
+
|
|
352
|
+
// The descriptor for the lazy accessor.
|
|
353
|
+
const desc =
|
|
354
|
+
{
|
|
355
|
+
configurable: true,
|
|
356
|
+
enumerable: opts.enumerable ?? false,
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// Replace the property if rules are correct.
|
|
360
|
+
const defval = function(value)
|
|
361
|
+
{
|
|
362
|
+
if (ctx.assign ?? value !== undefined)
|
|
363
|
+
{ // Replace the lazy accessor with the returned value.
|
|
364
|
+
df(target, name, value, ctx.df);
|
|
365
|
+
// Now return the newly assigned value.
|
|
366
|
+
return target[name];
|
|
367
|
+
}
|
|
368
|
+
else if (doesDescriptor(value))
|
|
369
|
+
{ // A descriptor was returned, extract the real value.
|
|
370
|
+
if (typeof value.get === F)
|
|
371
|
+
{
|
|
372
|
+
return value.get();
|
|
373
|
+
}
|
|
374
|
+
else
|
|
375
|
+
{
|
|
376
|
+
return value.value;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else
|
|
380
|
+
{ // Just return the original value.
|
|
381
|
+
return value;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
desc.get = function()
|
|
386
|
+
{
|
|
387
|
+
return defval(initfunc.call(ctx,ctx));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (typeof opts.set === F)
|
|
391
|
+
{ // We want to assign a lazy setter as well.
|
|
392
|
+
desc.set = function(value)
|
|
393
|
+
{
|
|
394
|
+
defval(opts.set.call(ctx,value,ctx));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Assign the lazy accessor property.
|
|
399
|
+
return df(target, name, desc);
|
|
260
400
|
}
|
|
401
|
+
|
|
402
|
+
df(df, 'lazy', lazy);
|
|
403
|
+
df(lazy, 'df', df);
|
|
404
|
+
// TODO: remove this for v2.x
|
|
405
|
+
lazy(lazy, 'def', () => require('../types/def'));
|
|
406
|
+
|
|
407
|
+
module.exports = {descriptor, df, dfa, dfor, lazy}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function getPrototypesOf(obj)
|
|
4
|
+
{
|
|
5
|
+
let chain = [];
|
|
6
|
+
while (true)
|
|
7
|
+
{
|
|
8
|
+
if (obj && typeof obj === 'object')
|
|
9
|
+
{
|
|
10
|
+
let objClass = obj.constructor;
|
|
11
|
+
if (!chain.includes(objClass))
|
|
12
|
+
{
|
|
13
|
+
chain.push(objClass);
|
|
14
|
+
}
|
|
15
|
+
obj = getProto(obj);
|
|
16
|
+
}
|
|
17
|
+
else
|
|
18
|
+
{
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return chain;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = getPrototypesOf;
|
package/lib/obj/index.js
CHANGED
|
@@ -8,10 +8,11 @@ const assignd = require('./assignd');
|
|
|
8
8
|
const {copyAll,duplicateOne,duplicateAll} = require('./copyall');
|
|
9
9
|
const copyProps = require('./copyprops');
|
|
10
10
|
const {CLONE,clone,addClone,cloneIfLocked} = require('./clone');
|
|
11
|
-
const {df,dfa,
|
|
11
|
+
const {df,dfa,dfor,lazy} = require('./df');
|
|
12
12
|
const {flip, flipKeyVal, flipMap} = require('./flip');
|
|
13
13
|
const {getMethods,signatureOf,MethodFilter} = require('./getmethods');
|
|
14
14
|
const getProperty = require('./getproperty');
|
|
15
|
+
const getPrototypesOf = require('./getprotos');
|
|
15
16
|
const {lock,addLock} = require('./lock');
|
|
16
17
|
const {mergeNested,syncNested} = require('./merge');
|
|
17
18
|
const ns = require('./ns');
|
|
@@ -20,16 +21,35 @@ const unlocked = require('./unlocked');
|
|
|
20
21
|
|
|
21
22
|
const
|
|
22
23
|
{
|
|
23
|
-
getObjectPath,setObjectPath,
|
|
24
|
-
getNamespace,setNamespace,
|
|
24
|
+
getObjectPath,setObjectPath,delObjectPath,
|
|
25
|
+
getNamespace,setNamespace,nsFactory,
|
|
25
26
|
} = ns;
|
|
26
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Create a new object with a `null` prototype.
|
|
30
|
+
*
|
|
31
|
+
* @alias module:@lumjs/core/obj.discrete
|
|
32
|
+
*
|
|
33
|
+
* Unlike regular objects, discrete objects won't have any
|
|
34
|
+
* of the usual meta-programming methods or properties.
|
|
35
|
+
* Not sure why you'd want that, but anyway, here you go.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} [props] Optional properties to define in
|
|
38
|
+
* the new object. Uses the same format as Object.defineProperties()
|
|
39
|
+
*
|
|
40
|
+
* @returns {object}
|
|
41
|
+
*/
|
|
42
|
+
const discrete = (props) => Object.create(null, props);
|
|
43
|
+
|
|
44
|
+
// TODO: reorder the following alphabetically, for sanity sake...
|
|
27
45
|
module.exports =
|
|
28
46
|
{
|
|
29
47
|
assignd, cp, CLONE, clone, addClone, cloneIfLocked, lock, addLock,
|
|
30
|
-
df, dfa,
|
|
31
|
-
mergeNested, syncNested, copyProps, copyAll, ns,
|
|
32
|
-
getObjectPath, setObjectPath, getNamespace, setNamespace,
|
|
48
|
+
df, dfa, dfor, lazy, discrete,
|
|
49
|
+
mergeNested, syncNested, copyProps, copyAll, ns, nsFactory,
|
|
50
|
+
getObjectPath, setObjectPath, delObjectPath, getNamespace, setNamespace,
|
|
33
51
|
getProperty, duplicateAll, duplicateOne, getMethods, signatureOf,
|
|
34
52
|
MethodFilter, apply, flip, flipKeyVal, flipMap, unlocked,
|
|
53
|
+
getPrototypesOf,
|
|
35
54
|
}
|
|
55
|
+
|