@lumjs/core 1.0.0-beta.2 → 1.0.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 +11 -2
- package/TODO.md +12 -5
- package/docs/changelogs/1.0-beta.md +99 -0
- package/docs/changelogs/1.x.md +17 -0
- package/jsdoc.json +33 -0
- package/lib/arrays.js +78 -0
- package/lib/context.js +49 -10
- package/lib/enum.js +30 -13
- package/lib/flags.js +6 -0
- package/lib/index.js +87 -25
- package/lib/lazy.js +33 -35
- package/lib/meta.js +38 -1
- package/lib/modules.js +43 -7
- package/lib/obj/clone.js +158 -139
- package/lib/obj/copyall.js +3 -0
- package/lib/obj/copyprops.js +1 -0
- package/lib/obj/index.js +12 -7
- package/lib/obj/lock.js +16 -13
- package/lib/obj/merge.js +2 -0
- package/lib/obj/ns.js +45 -8
- package/lib/objectid.js +2 -3
- package/lib/observable.js +23 -8
- package/lib/opt.js +6 -1
- package/lib/strings.js +43 -4
- package/lib/types/basics.js +154 -0
- package/lib/types/def.js +183 -0
- package/lib/types/index.js +55 -0
- package/lib/types/isa.js +186 -0
- package/lib/types/js.js +12 -0
- package/lib/types/needs.js +117 -0
- package/lib/types/root.js +92 -0
- package/lib/types/stringify.js +98 -0
- package/lib/types/typelist.js +168 -0
- package/package.json +25 -2
- package/test/arrays.js +19 -0
- package/test/meta.js +17 -0
- package/test/types.js +105 -22
- package/CHANGELOG.md +0 -25
- package/lib/descriptors.js +0 -243
- package/lib/prop.js +0 -170
- package/lib/types.js +0 -545
package/lib/lazy.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
|
|
2
|
-
const {S,F,
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const {S,F,TYPES:{COMPLEX},needType,needObj,def} = require('./types');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @callback module:@lumjs/core~InitFunc
|
|
6
|
+
* @param {string} name - The `name` parameter passed to `lazy()`
|
|
7
|
+
* @this {object} - The `obj` parameter passed to `lazy()`
|
|
8
|
+
*/
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Build a lazy initializer property.
|
|
8
12
|
*
|
|
9
13
|
* Basically the first time the property is accessed it's built.
|
|
10
14
|
* Subsequent accesses will use the already built property.
|
|
11
|
-
* This is an extension of the {@link
|
|
12
|
-
* alias called `
|
|
15
|
+
* This is an extension of the {@link def} method, and indeed an
|
|
16
|
+
* alias called `def.lazy()` is also available.
|
|
13
17
|
*
|
|
14
|
-
* @param {
|
|
18
|
+
* @param {Object} obj - The object to add the property to.
|
|
15
19
|
* @param {string} name - The name of the property to add.
|
|
16
|
-
* @param {
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* It will also be passed `name` as the sole parameter.
|
|
20
|
-
*
|
|
21
|
-
* @param {mixed} [onset] How to handle assignment.
|
|
20
|
+
* @param {module:@lumjs/core~InitFunc} initfunc
|
|
21
|
+
* The function to initialize the property.
|
|
22
|
+
* @param {*} [onset] How to handle assignment.
|
|
22
23
|
*
|
|
23
24
|
* If this is `true` then the new value will be assigned directly,
|
|
24
25
|
* skipping the initialization process entirely.
|
|
@@ -36,29 +37,26 @@ const {DESC} = require('./descriptors');
|
|
|
36
37
|
*
|
|
37
38
|
* If this is anything else, assignment will do nothing at all.
|
|
38
39
|
*
|
|
39
|
-
* @param {
|
|
40
|
+
* @param {Object} [desc={}] Descriptor rules for the property.
|
|
41
|
+
* We only support two descriptor rules with this function, and
|
|
42
|
+
* their default values are the same as the `def()` function.
|
|
43
|
+
* - `configurable` → `true`
|
|
44
|
+
* - `enumerable` → `false`
|
|
45
|
+
* Any other descriptor properties are invalid here.
|
|
40
46
|
*
|
|
41
|
-
* @return {
|
|
47
|
+
* @return {Object} The object we defined the property on.
|
|
48
|
+
* @alias module:@lumjs/core.lazy
|
|
42
49
|
*/
|
|
43
|
-
function lazy(obj, name, initfunc, onset, desc=
|
|
50
|
+
function lazy(obj, name, initfunc, onset, desc={})
|
|
44
51
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (typeof name !== S)
|
|
50
|
-
{
|
|
51
|
-
throw new TypeError("name parameter was not a string");
|
|
52
|
-
}
|
|
53
|
-
if (typeof initfunc !== F)
|
|
54
|
-
{
|
|
55
|
-
throw new TypeError("initfunc parameter was not a function");
|
|
56
|
-
}
|
|
52
|
+
needType(COMPLEX, obj, 'obj must be an object');
|
|
53
|
+
needType(S, name, 'name must be a string');
|
|
54
|
+
needType(F, initfunc, 'initfunc must be a function');
|
|
55
|
+
needObj(desc, 'desc parameter was not an object');
|
|
57
56
|
|
|
58
57
|
let value;
|
|
59
|
-
let setter = null;
|
|
60
58
|
|
|
61
|
-
function
|
|
59
|
+
desc.get = function()
|
|
62
60
|
{
|
|
63
61
|
if (value === undefined)
|
|
64
62
|
{
|
|
@@ -69,23 +67,23 @@ function lazy(obj, name, initfunc, onset, desc=DESC.CONF)
|
|
|
69
67
|
|
|
70
68
|
if (onset === true)
|
|
71
69
|
{ // Allow direct assignment.
|
|
72
|
-
|
|
70
|
+
desc.set = function(newval)
|
|
73
71
|
{
|
|
74
72
|
value = newval;
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
else if (onset === false)
|
|
78
76
|
{ // Throw an error on assignment.
|
|
79
|
-
|
|
77
|
+
desc.set = function()
|
|
80
78
|
{
|
|
81
79
|
throw new ReferenceError("The "+name+" property is read-only");
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
82
|
else if (typeof onset === F)
|
|
85
83
|
{ // A proxy method for assignment.
|
|
86
|
-
|
|
84
|
+
desc.set = function(newval)
|
|
87
85
|
{
|
|
88
|
-
const setval = onset.call(this, newval);
|
|
86
|
+
const setval = onset.call(this, newval, value);
|
|
89
87
|
if (setval !== undefined)
|
|
90
88
|
{
|
|
91
89
|
value = setval;
|
|
@@ -93,10 +91,10 @@ function lazy(obj, name, initfunc, onset, desc=DESC.CONF)
|
|
|
93
91
|
}
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
|
|
94
|
+
def(obj, name, desc);
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
// Gotta be one of the greatest lines...
|
|
100
|
-
|
|
98
|
+
def(def, 'lazy', lazy);
|
|
101
99
|
|
|
102
100
|
module.exports = lazy;
|
package/lib/meta.js
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Meta-programming helpers.
|
|
3
|
+
* @module @lumjs/core/meta
|
|
4
|
+
*/
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Get a stacktrace. Differs from browser to browser.
|
|
8
|
+
*
|
|
9
|
+
* Uses the `stack` property of an `Error` object as the source.
|
|
10
|
+
* This is a super simplistic hack. For a more complete solution, try
|
|
11
|
+
* the `stacktrace-js` library, which will be used in the new `@lumjs/debug`
|
|
12
|
+
* library as a dependency.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} [msg] - A message for the Error object.
|
|
15
|
+
*
|
|
16
|
+
* @returns {string[]} An array of stack strings.
|
|
17
|
+
* @alias module:@lumjs/core/meta.stacktrace
|
|
5
18
|
*/
|
|
6
19
|
function stacktrace(msg)
|
|
7
20
|
{
|
|
@@ -12,6 +25,7 @@ exports.stacktrace = stacktrace;
|
|
|
12
25
|
|
|
13
26
|
/**
|
|
14
27
|
* Abstract classes for Javascript.
|
|
28
|
+
* @alias module:@lumjs/core/meta.AbstractClass
|
|
15
29
|
*/
|
|
16
30
|
class AbstractClass
|
|
17
31
|
{
|
|
@@ -38,6 +52,8 @@ exports.AbstractClass = AbstractClass;
|
|
|
38
52
|
|
|
39
53
|
/**
|
|
40
54
|
* Function prototypes for async, generator, and async generator functions.
|
|
55
|
+
* @namespace
|
|
56
|
+
* @alias module:@lumjs/core/meta.Functions
|
|
41
57
|
*/
|
|
42
58
|
const Functions =
|
|
43
59
|
{
|
|
@@ -59,3 +75,24 @@ const Functions =
|
|
|
59
75
|
}
|
|
60
76
|
|
|
61
77
|
exports.Functions = Functions;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* A placeholder function for when something is not implemented.
|
|
81
|
+
*
|
|
82
|
+
* @param {boolean} [fatal=true] If `true` throw Error.
|
|
83
|
+
* If `false` use `console.error()` instead.
|
|
84
|
+
* @param {string} [prefix=''] A prefix for the error message.
|
|
85
|
+
*
|
|
86
|
+
* @returns {void}
|
|
87
|
+
* @alias module:@lumjs/core/meta.NYI
|
|
88
|
+
*/
|
|
89
|
+
function NYI(fatal=true, prefix='')
|
|
90
|
+
{
|
|
91
|
+
const msg = prefix+"« NOT YET IMPLEMENTED »";
|
|
92
|
+
if (fatal)
|
|
93
|
+
throw new Error(msg);
|
|
94
|
+
else
|
|
95
|
+
console.error(msg);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
exports.NYI = NYI;
|
package/lib/modules.js
CHANGED
|
@@ -1,24 +1,59 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Module helpers.
|
|
3
|
+
* @module @lumjs/core/modules
|
|
4
|
+
*/
|
|
2
5
|
|
|
3
6
|
const path = require('path');
|
|
4
|
-
const {S,
|
|
7
|
+
const {S,isObj} = require('./types');
|
|
5
8
|
const replace = require('./strings').replaceItems;
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Get the name of a module.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
13
|
+
* @param {(object|string)} module - Either a module object, or filename.
|
|
14
|
+
* If it is an `object`, it should be a CommonJS `module` object.
|
|
15
|
+
* If it is a `string`, it should be the module filename.
|
|
16
|
+
* @param {object} [opts] Options.
|
|
17
|
+
*
|
|
18
|
+
* @param {boolean} [opts.useAuto=true] Enable automatic name cleaning.
|
|
19
|
+
* If *basename* mode was **not** used, then once all other rules have been
|
|
20
|
+
* applied, strip any leading `.` and `/` characters, and the file extension.
|
|
21
|
+
*
|
|
22
|
+
* @param {boolean} [opts.basename=false] Use `path.basename()`
|
|
23
|
+
* This will strip all parent directories, and the file extension.
|
|
24
|
+
* If no other rules are specified in the `opts`, then this will
|
|
25
|
+
* be applied automatically as a fallback method. If it is set to
|
|
26
|
+
* `true` explicitly, then it will be applied *before* any other options.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} [opts.replace] Call {@link module:@lumjs/core/strings.replaceItems}
|
|
29
|
+
* This uses the default `useAll` values based on the `object` format.
|
|
30
|
+
* @param {object} [opts.replaceOne] `replace` but `useAll` set to `false`.
|
|
31
|
+
* @param {object} [opts.replaceAll] `replace` but `useAll` set to `true`.
|
|
32
|
+
* @param {(string|string[])} [opts.strip] Sub-strings to remove entirely.
|
|
33
|
+
* @returns {string} The *name* of a module as per the options set.
|
|
34
|
+
* @alias module:@lumjs/core/modules.name
|
|
11
35
|
*/
|
|
12
36
|
function name(module, opts={})
|
|
13
37
|
{
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
let filename;
|
|
39
|
+
|
|
40
|
+
if (typeof module === S)
|
|
41
|
+
{ // Going to assume a string is the filename.
|
|
42
|
+
filename = module;
|
|
43
|
+
}
|
|
44
|
+
else if (isObj(module) && typeof module.filename === S)
|
|
45
|
+
{ // It's a CommonJS module context object.
|
|
46
|
+
filename = module.filename;
|
|
47
|
+
}
|
|
48
|
+
else
|
|
49
|
+
{ // Sorry, we don't support that.
|
|
50
|
+
throw new TypeError("Unsupported module parameter");
|
|
51
|
+
}
|
|
16
52
|
|
|
17
|
-
let filename = module.filename;
|
|
18
53
|
const ext = path.extname(filename);
|
|
19
54
|
|
|
20
55
|
let useFallback = true;
|
|
21
|
-
let useAuto =
|
|
56
|
+
let useAuto = opts.useAuto ?? true;
|
|
22
57
|
|
|
23
58
|
if (opts.basename)
|
|
24
59
|
{ // We want to run the basename sequence first.
|
|
@@ -72,6 +107,7 @@ function name(module, opts={})
|
|
|
72
107
|
.replace(RegExp(ext+'$'), '');
|
|
73
108
|
}
|
|
74
109
|
|
|
110
|
+
return filename;
|
|
75
111
|
}
|
|
76
112
|
|
|
77
113
|
exports.name = name;
|
package/lib/obj/clone.js
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
// Import *most* required bits here.
|
|
2
2
|
const {B,N,F, isObj, isComplex, def} = require('../types');
|
|
3
3
|
const Enum = require('../enum');
|
|
4
|
-
const {getDescriptor, DESC} = require('../descriptors');
|
|
5
4
|
const copyProps = require('./copyprops');
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* An enum of supported modes for the `clone` method.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
13
|
-
* `CLONE.ALL` → Shallow clone of all properties (Arrays included.)
|
|
9
|
+
* - **P** = All properties. If unchecked, enumerable properties only.
|
|
10
|
+
* - **A** = Uses `Array.slice()` shortcut for shallow Array cloning.
|
|
11
|
+
* - **R** = Recursive (deep) cloning of nested objects.
|
|
14
12
|
*
|
|
13
|
+
* | Mode | P | A | R | Notes |
|
|
14
|
+
* | ---- | - | - | - | ----- |
|
|
15
|
+
* | `CLONE.DEF` | × | ✓ | × | Default mode for cloning functions. |
|
|
16
|
+
* | `CLONE.DEEP` | × | × | ✓ | |
|
|
17
|
+
* | `CLONE.FULL` | ✓ | ✓ | × | |
|
|
18
|
+
* | `CLONE.ALL` | ✓ | × | × | |
|
|
19
|
+
* | `CLONE.ENTIRE` | ✓ | × | ✓ | |
|
|
20
|
+
* | `CLONE.JSON` | × | × | ✓ | Uses JSON, so no `function` or `symbol` support. |
|
|
21
|
+
*
|
|
22
|
+
* @alias module:@lumjs/core/obj.CLONE
|
|
15
23
|
*/
|
|
16
|
-
const CLONE = Enum(['DEF','
|
|
24
|
+
const CLONE = Enum(['DEF','FULL','ALL','DEEP','ENTIRE','JSON']);
|
|
17
25
|
|
|
18
26
|
exports.CLONE = CLONE;
|
|
27
|
+
|
|
28
|
+
// A list of modes that should use the array.slice shallow shortcut.
|
|
29
|
+
const SLICE_ARRAYS = [CLONE.DEF, CLONE.FULL];
|
|
30
|
+
|
|
31
|
+
// A list of modes that should get *all* properties.
|
|
32
|
+
const ALL_PROPS = [CLONE.FULL, CLONE.ALL, CLONE.DEEP];
|
|
33
|
+
|
|
34
|
+
// A list of modes that should do recursive cloning of objects.
|
|
35
|
+
const RECURSIVE = [CLONE.DEEP, CLONE.ENTIRE];
|
|
19
36
|
|
|
20
37
|
/**
|
|
21
38
|
* Clone an object or function.
|
|
@@ -23,111 +40,113 @@ const copyProps = require('./copyprops');
|
|
|
23
40
|
* @param {object|function} obj - The object we want to clone.
|
|
24
41
|
* @param {object} [opts={}] - Options for the cloning process.
|
|
25
42
|
*
|
|
26
|
-
* @param {number} [opts.mode=
|
|
27
|
-
*
|
|
28
|
-
* For any mode that doesn't saay "Arrays included", Array objects will
|
|
29
|
-
* use a shortcut technique of `obj.slice()` to create the clone.
|
|
43
|
+
* @param {number} [opts.mode=CLONE.DEF] - One of the `CLONE.*` enum values.
|
|
30
44
|
*
|
|
31
45
|
* Note: The `CLONE` enum is also aliased as `clone.MODE` as an alternative.
|
|
32
46
|
*
|
|
33
|
-
* @param {boolean} [opts.addClone=false] - Call
|
|
47
|
+
* @param {boolean} [opts.addClone=false] - Call `addClone()` on the cloned object.
|
|
34
48
|
*
|
|
35
49
|
* The options sent to this function will be used as the defaults in
|
|
36
|
-
* the clone() method added to the object.
|
|
50
|
+
* the `clone()` method added to the object.
|
|
37
51
|
*
|
|
38
|
-
* @param {boolean} [opts.addLock=false] - Call
|
|
52
|
+
* @param {boolean} [opts.addLock=false] - Call `addLock()` on the cloned object.
|
|
39
53
|
*
|
|
40
|
-
* No further options for this, just add a lock() method to the clone.
|
|
54
|
+
* No further options for this, just add a `lock()` method to the clone.
|
|
41
55
|
*
|
|
42
|
-
* @param {?object} [opts.copy] Call
|
|
56
|
+
* @param {?object} [opts.copy] Call `copyProps()` on the cloned object.
|
|
43
57
|
*
|
|
44
58
|
* Will pass the original `obj` as the source to copy from.
|
|
45
59
|
* Will pass `opts.copy` as the options.
|
|
46
60
|
*
|
|
47
61
|
* @return {object} - The clone of the object.
|
|
62
|
+
* @alias module:@lumjs/core/obj.clone
|
|
48
63
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
64
|
+
function clone(obj, opts={})
|
|
65
|
+
{
|
|
66
|
+
//console.debug("clone()", obj, opts);
|
|
67
|
+
|
|
68
|
+
if (!isComplex(obj))
|
|
69
|
+
{ // Doesn't need cloning.
|
|
70
|
+
//console.debug("no cloning required");
|
|
71
|
+
return obj;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!isObj(opts))
|
|
75
|
+
{ // Opts has to be a valid object.
|
|
76
|
+
opts = {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const mode = typeof opts.mode === N ? opts.mode : CLONE.DEF;
|
|
80
|
+
const reclone = typeof opts.addClone === B ? opts.addClone : false;
|
|
81
|
+
const relock = typeof opts.addLock === B ? opts.addLock : false;
|
|
82
|
+
|
|
83
|
+
let copy;
|
|
84
|
+
|
|
85
|
+
//console.debug("::clone", {mode, reclone, relock});
|
|
86
|
+
|
|
87
|
+
if (mode === CLONE.JSON)
|
|
88
|
+
{ // Deep clone enumerable properties using JSON trickery.
|
|
89
|
+
//console.debug("::clone using JSON cloning");
|
|
90
|
+
copy = JSON.parse(JSON.stringify(obj));
|
|
91
|
+
}
|
|
92
|
+
else if (Array.isArray(obj) && SLICE_ARRAYS.includes(mode))
|
|
93
|
+
{ // Make a shallow copy using slice.
|
|
94
|
+
//console.debug("::clone using Array.slice()");
|
|
95
|
+
copy = obj.slice();
|
|
96
|
+
}
|
|
97
|
+
else
|
|
98
|
+
{ // Build a clone using a simple loop.
|
|
99
|
+
//console.debug("::clone using simple loop");
|
|
100
|
+
copy = {};
|
|
101
|
+
|
|
102
|
+
let props;
|
|
103
|
+
if (ALL_PROPS.includes(mode))
|
|
104
|
+
{ // All object properties.
|
|
105
|
+
//console.debug("::clone getting all properties");
|
|
106
|
+
props = Object.getOwnPropertyNames(obj);
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
{ // Enumerable properties.
|
|
110
|
+
//console.debug("::clone getting enumerable properties");
|
|
111
|
+
props = Object.keys(obj);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//console.debug("::clone[props]", props);
|
|
115
|
+
|
|
116
|
+
for (const prop of props)
|
|
117
|
+
{
|
|
118
|
+
let val = obj[prop];
|
|
119
|
+
if (isObj(val) && RECURSIVE.includes(mode))
|
|
120
|
+
{ // Deep cloning.
|
|
121
|
+
val = clone(val, {mode});
|
|
122
|
+
}
|
|
123
|
+
copy[prop] = val;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (reclone)
|
|
128
|
+
{ // Add the clone() method to the clone, with the passed opts as defaults.
|
|
129
|
+
addClone(copy, opts);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (opts.copy)
|
|
133
|
+
{ // Pass the clone through the copyProps() function as well.
|
|
134
|
+
copyProps(obj, copy, opts.copy);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (relock)
|
|
138
|
+
{ // Add the lock() method to the clone.
|
|
139
|
+
addLock(copy, opts);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return copy;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Alias the CLONE enum as clone.MODE
|
|
146
|
+
def(clone, 'MODE', CLONE);
|
|
147
|
+
|
|
148
|
+
// Export the clone here.
|
|
149
|
+
exports.clone = clone;
|
|
131
150
|
|
|
132
151
|
/**
|
|
133
152
|
* Add a clone() method to an object.
|
|
@@ -139,28 +158,28 @@ const copyProps = require('./copyprops');
|
|
|
139
158
|
*
|
|
140
159
|
* ```{mode: CLONE.DEF, addClone: true, addLock: false}```
|
|
141
160
|
*
|
|
142
|
-
* @
|
|
161
|
+
* @alias module:@lumjs/core/obj.addClone
|
|
143
162
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
function addClone(obj, defOpts=null)
|
|
164
|
+
{
|
|
165
|
+
if (!isObj(defOpts))
|
|
166
|
+
{ // Assign a default set of defaults.
|
|
167
|
+
defOpts = {mode: CLONE.DEF, addClone: true, addLock: false};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const defDesc = defOpts.cloneDesc ?? {};
|
|
171
|
+
|
|
172
|
+
defDesc.value = function (opts)
|
|
173
|
+
{
|
|
174
|
+
if (!isObj(opts))
|
|
175
|
+
opts = defOpts;
|
|
176
|
+
return clone(obj, opts);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return def(obj, 'clone', defDesc);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
exports.addClone = addClone;
|
|
164
183
|
|
|
165
184
|
/**
|
|
166
185
|
* Clone an object if it's not extensible (locked, sealed, frozen, etc.)
|
|
@@ -168,34 +187,34 @@ const copyProps = require('./copyprops');
|
|
|
168
187
|
* If the object is extensible, it's returned as is.
|
|
169
188
|
*
|
|
170
189
|
* If not, if the object has a `clone()` method it will be used.
|
|
171
|
-
* Otherwise use
|
|
190
|
+
* Otherwise use our `clone()` function.
|
|
172
191
|
*
|
|
173
192
|
* @param {object} obj - The object to clone if needed.
|
|
174
193
|
* @param {object} [opts] - Options to pass to `clone()` method.
|
|
175
194
|
*
|
|
176
195
|
* @return {object} - Either the original object, or an extensible clone.
|
|
177
196
|
*
|
|
178
|
-
* @
|
|
197
|
+
* @alias module:@lumjs/core/obj.cloneIfLocked
|
|
179
198
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
function cloneIfLocked(obj, opts)
|
|
200
|
+
{
|
|
201
|
+
if (!Object.isExtensible(obj))
|
|
202
|
+
{
|
|
203
|
+
if (typeof obj.clone === F)
|
|
204
|
+
{ // Use the object's clone() method.
|
|
205
|
+
return obj.clone(opts);
|
|
206
|
+
}
|
|
207
|
+
else
|
|
208
|
+
{ // Use our own clone method.
|
|
209
|
+
return clone(obj, opts);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Return the object itself, it's fine.
|
|
214
|
+
return obj;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
exports.cloneIfLocked = cloneIfLocked;
|
|
199
218
|
|
|
200
219
|
// Import `addLock()` here *after* assigning the clone methods.
|
|
201
220
|
const {addLock} = require('./lock');
|
package/lib/obj/copyall.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* It does no type checking, and has no qualms about overwriting properties.
|
|
5
5
|
* You probably want something like `copyProps` instead.
|
|
6
|
+
*
|
|
7
|
+
* @alias module:@lumjs/core/obj.copyAll
|
|
6
8
|
*/
|
|
7
9
|
function copyAll(target, ...sources)
|
|
8
10
|
{
|
|
@@ -13,6 +15,7 @@ function copyAll(target, ...sources)
|
|
|
13
15
|
target[name] = source[name];
|
|
14
16
|
}
|
|
15
17
|
}
|
|
18
|
+
return target;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
module.exports = copyAll;
|
package/lib/obj/copyprops.js
CHANGED
|
@@ -23,6 +23,7 @@ const {B,isObj,isComplex,isArray,def: defProp} = require('../types');
|
|
|
23
23
|
* if that property can be overwritten or not.
|
|
24
24
|
*
|
|
25
25
|
* @returns {object} The `target` object.
|
|
26
|
+
* @alias module:@lumjs/core/obj.copyProps
|
|
26
27
|
*/
|
|
27
28
|
function copyProps(source, target, propOpts)
|
|
28
29
|
{
|
package/lib/obj/index.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Object helpers sub-module.
|
|
3
|
+
* @module @lumjs/core/obj
|
|
4
|
+
*/
|
|
5
5
|
|
|
6
6
|
const copyAll = require('./copyall');
|
|
7
7
|
const copyProps = require('./copyprops');
|
|
8
8
|
const {CLONE,clone,addClone,cloneIfLocked} = require('./clone');
|
|
9
9
|
const {lock,addLock} = require('./lock');
|
|
10
10
|
const {mergeNested,syncNested} = require('./merge');
|
|
11
|
-
const
|
|
11
|
+
const ns = require('./ns');
|
|
12
|
+
const
|
|
13
|
+
{
|
|
14
|
+
getObjectPath,setObjectPath,
|
|
15
|
+
getNamespace,setNamespace,
|
|
16
|
+
} = ns;
|
|
12
17
|
|
|
13
18
|
module.exports =
|
|
14
19
|
{
|
|
15
20
|
CLONE, clone, addClone, cloneIfLocked, lock, addLock,
|
|
16
|
-
mergeNested, syncNested,
|
|
17
|
-
getObjectPath, setObjectPath,
|
|
21
|
+
mergeNested, syncNested, copyProps, copyAll, ns,
|
|
22
|
+
getObjectPath, setObjectPath, getNamespace, setNamespace,
|
|
18
23
|
}
|