@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.
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ const {isObj} = require('../types/basics');
4
+
5
+ /**
6
+ * A helper function to support both positional arguments
7
+ * and named options in the same method signature.
8
+ *
9
+ * @param {object} opts - Options built from positional arguments
10
+ *
11
+ * Keep in mind that this object **WILL** be modified!
12
+ *
13
+ * @param {string} optArg - The option that may contain named options
14
+ *
15
+ * Generally the name of the first positional argument that may be
16
+ * an `object` full of options or a different positional argument value.
17
+ *
18
+ * The biggest limitation is that it cannot be an `object` value when used
19
+ * as a positional argument, as that will always be seen as the _options_.
20
+ *
21
+ * @param {*} optDef - A default value for `opts[optArg]`
22
+ *
23
+ * If `opts[optArg]` was an `object`, we'll compose its properties
24
+ * into `opts` directly. If after that `opts[optArg]` is still the
25
+ * options `object` then this value will be used instead.
26
+ *
27
+ * @example <caption>Example usage</caption>
28
+ *
29
+ * function example(first=true, second=null, third="test")
30
+ * {
31
+ * const opts = argOpts({first, second, third}, 'first', true);
32
+ * }
33
+ *
34
+ * @exports module:@lumjs/core/opt/args
35
+ */
36
+ function argOpts(opts, optArg, optDef)
37
+ {
38
+ if (isObj(opts[optArg]))
39
+ { // Merge the named options.
40
+ const specOpts = opts[optArg];
41
+ Object.assign(opts, specOpts);
42
+ if (opts[optArg] === specOpts)
43
+ { // specOpts didn't override the real option.
44
+ opts[optArg] = optDef;
45
+ }
46
+ }
47
+ return opts;
48
+ } // argOpts()
49
+
50
+ module.exports = argOpts;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ const {isArrayOf,S} = require('../types/basics');
4
+ const {getObjectPath} = require('../obj/ns');
5
+ const {val} = require('./val');
6
+
7
+ /**
8
+ * An alternative to `get()` that uses `getObjectPath()`
9
+ * to look for a specific nested property value.
10
+ *
11
+ * While `get()` supports positional arguments like `val()`,
12
+ * this function _only_ supports named options.
13
+ *
14
+ * @param {object} obj - Object we're looking for properties in
15
+ * @param {(string|Array)} path - Path for `getObjectPath()`
16
+ * @param {object} [opts] Options
17
+ *
18
+ * This supports all of the same options as `get()`, plus all of the
19
+ * options supported by `getObjectPath()`. See the docs for both those
20
+ * functions to see what all is supported. If the same option is supported
21
+ * by *both* functions (e.g. `allowFun`) then the default value
22
+ * will be the one from `getObjectPath()` rather than `get()`.
23
+ *
24
+ * @param {boolean} [opts.ro=false] Should `opts` be read-only?
25
+ *
26
+ * If `true`, a copy of the `opts` will be made before any changes
27
+ * are performed, ensuring the original options aren't modified.
28
+ *
29
+ * @returns {*} The property if found, or `opts.default` if not.
30
+ *
31
+ * @see module:@lumjs/core/opt.get
32
+ * @see module:@lumjs/core/obj.getObjectPath
33
+ * @alias module:@lumjs/core/opt.getPath
34
+ */
35
+ function getPath(obj, path, opts={})
36
+ {
37
+ const defvalue = opts.default;
38
+ if (opts.ro)
39
+ {
40
+ opts = Object.assign({}, opts);
41
+ }
42
+ delete opts.default;
43
+
44
+ return val(getObjectPath(obj, path, opts), defvalue,
45
+ (opts.allowNull ?? true),
46
+ opts.isLazy,
47
+ (opts.lazyThis ?? obj),
48
+ opts.lazyArgs);
49
+ }
50
+
51
+ /**
52
+ * Does a value appear to be a path usable by the
53
+ * {@link module:@lumjs/core/opt.getPath} function?
54
+ *
55
+ * @param {*} value - Value to test;
56
+ * will be considered a path if it is:
57
+ *
58
+ * - An `Array` with only `string` values in it.
59
+ * - A string with a `.` character in it.
60
+ *
61
+ * @returns {boolean}
62
+ * @alias module:@lumjs/core/opt.isPath
63
+ */
64
+ function isPath(value)
65
+ {
66
+ return (isArrayOf(value, S)
67
+ || (typeof value === S && value.includes('.')));
68
+ }
69
+
70
+ module.exports = {getPath, isPath};
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ const {S,needObj,needType} = require('../types');
4
+ const {_opts,val} = require('./val');
5
+
6
+ /**
7
+ * See if a property in an object is set.
8
+ *
9
+ * If it is, return the property, otherwise return a default value.
10
+ * This uses the `val()` method, and as such supports the same arguments.
11
+ * However read the descriptions, as defaults may be quite different!
12
+ *
13
+ * @param {object} obj - An object to test for a property in.
14
+ * @param {string} optname - The property name we're checking for.
15
+ * @param {*} defvalue - The default value.
16
+ *
17
+ * @param {(object|boolean)} [opts] Options
18
+ *
19
+ * If this is a `boolean` it is used as the `allowNull` option.
20
+ *
21
+ * @param {boolean} [opts.allowNull=true] Passed to `val()`;
22
+ * default is `true`, which differs from `val()`.
23
+ * @param {boolean} [opts.isLazy=false] Passed to `val()`;
24
+ * default is `false`, the same as `val()`.
25
+ * @param {object} [opts.lazyThis=obj] Passed to `val()`;
26
+ * default is `obj`, which differs from `val()`.
27
+ * @param {Array} [opts.lazyArgs] Passed to `val()`
28
+ * @param {boolean} [opts.allowFun=false] Allow `obj` to be a `function` ?
29
+ *
30
+ * By default only `object` values are valid for `obj`; this can be set to
31
+ * `true` to allow `function` values to be used.
32
+ *
33
+ * @param {boolean} [isLazy=false] Same as `opts.isLazy`
34
+ * @param {object} [lazyThis=opts] Same as `opts.lazyThis`
35
+ * @param {Array} [lazyArgs] Same as `opts.lazyArgs`
36
+ * @param {boolean} [allowFun] Same as `opts.allowFun`
37
+ *
38
+ * @returns {*} Either the property value, or the default value.
39
+ * @see module:@lumjs/core/opt.val
40
+ * @alias module:@lumjs/core/opt.get
41
+ */
42
+ function get(obj, optname, defvalue,
43
+ allowNull=true,
44
+ isLazy=false,
45
+ lazyThis=obj,
46
+ lazyArgs=[],
47
+ allowFun=false)
48
+ {
49
+ const opts = _opts({allowNull,isLazy,lazyThis,lazyArgs,allowFun}, true);
50
+
51
+ needObj(obj, opts.allowFun);
52
+ needType(S, optname);
53
+
54
+ return val(obj[optname], defvalue,
55
+ opts.allowNull,
56
+ opts.isLazy,
57
+ opts.lazyThis,
58
+ opts.lazyArgs);
59
+ }
60
+
61
+ module.exports = {val, get};
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Functions for working with options and default values.
3
+ * @module @lumjs/core/opt
4
+ */
5
+
6
+ const argOpts = require('./args');
7
+ const {getPath,isPath} = require('./getpath');
8
+ const {val,get} = require('./getval');
9
+
10
+ exports = module.exports =
11
+ {
12
+ argOpts, get, getPath, isPath, val,
13
+ }
14
+
15
+ const {wrapDepr} = require('../meta');
16
+ wrapDepr(exports, 'Opts',
17
+ {
18
+ dep: '@lumjs/core.opt.Opts',
19
+ rep: '@lumjs/opts',
20
+ get: () => require('@lumjs/opts'),
21
+ });
package/lib/opt/val.js ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ const {U,F} = require('../types/js');
4
+ const argOpts = require('./args');
5
+
6
+ // Helper for `val()` and `get()` to support new-style options.
7
+ function _opts(opts, defNull)
8
+ {
9
+ return argOpts(opts, 'allowNull', defNull);
10
+ }
11
+
12
+ /**
13
+ * See if a value is *set*, and if not, return a default value.
14
+ *
15
+ * This function used to use all positional arguments, but it now
16
+ * supports named options if an `object` is passed as the third argument.
17
+ * If both named options and the corresponding positional arguments are
18
+ * specified, the named options will take precedence.
19
+ *
20
+ * @param {*} optvalue - The value we are testing.
21
+ * @param {*} defvalue - The default value if opt was null or undefined.
22
+ *
23
+ * @param {(object|boolean)} opts - Options
24
+ *
25
+ * If this is a `boolean` it is used as the `allowNull` option.
26
+ *
27
+ * @param {boolean} [opts.allowNull=false] If true, allow null to count as *set*.
28
+ * @param {boolean} [opts.isLazy=false] If true, and `defvalue` is a function,
29
+ * use the value from the function as
30
+ * the default.
31
+ * @param {object} [opts.lazyThis=null] If `isLazy` is true, this object will
32
+ * be used as `this` for the function.
33
+ * @param {Array} [opts.lazyArgs] If `isLazy` is true, this may be used
34
+ * as a list of arguments to pass.
35
+ *
36
+ * @param {boolean} [isLazy=false] Same as `opts.isLazy`
37
+ * @param {object} [lazyThis=null] Same as `opts.lazyThis`
38
+ * @param {Array} [lazyArgs] Same as `opts.lazyArgs`
39
+ *
40
+ * @return {*} Either `optvalue` or `defvalue` depending on the test.
41
+ * @alias module:@lumjs/core/opt.val
42
+ */
43
+ function val(optvalue, defvalue,
44
+ allowNull=false,
45
+ isLazy=false,
46
+ lazyThis=null,
47
+ lazyArgs=[])
48
+ {
49
+ const opts = _opts({allowNull,isLazy,lazyThis,lazyArgs}, false);
50
+
51
+ if (typeof optvalue === U || (!opts.allowNull && optvalue === null))
52
+ { // The defined value was not "set" as per our rules.
53
+ if (opts.isLazy && typeof defvalue === F)
54
+ { // Get the default value from a passed in function.
55
+ return defvalue.apply(opts.lazyThis, opts.lazyArgs);
56
+ }
57
+ return defvalue;
58
+ }
59
+
60
+ return optvalue;
61
+ }
62
+
63
+ module.exports = {_opts, val};
package/lib/strings.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * String and locale related functions.
3
3
  * @module @lumjs/core/strings
4
4
  */
5
- const {S,B,F,isObj,root,isArray,needType,needObj,console} = require('./types');
5
+ const {S,B,F,isObj,root,isArray,needType,needObj} = require('./types');
6
6
 
7
7
  /**
8
8
  * Get the locale/language string.
@@ -1,10 +1,35 @@
1
- const {O, F, S, SY} = require('./js');
1
+ "use strict";
2
+
3
+ /**
4
+ * Basic types sub-module.
5
+ *
6
+ * Provides simple type tests, and a few one or two character constants
7
+ * One or two character identifiers for the core JS type names.
8
+ *
9
+ * These are only the strings returned by the `typeof` operator.
10
+ * See {@link module:@lumjs/core/types.TYPES} for a list
11
+ * that includes special types and compound pseudo-types, etc.
12
+ *
13
+ * @prop {string} O - object
14
+ * @prop {string} F - function
15
+ * @prop {string} S - string
16
+ * @prop {string} B - boolean
17
+ * @prop {string} N - number
18
+ * @prop {string} U - undefined
19
+ * @prop {string} SY - symbol
20
+ * @prop {string} BI - bigint
21
+ *
22
+ * @module @lumjs/core/types/basics
23
+ */
24
+
25
+ const JS = require('./js');
26
+ const {O, F, S, SY} = JS;
2
27
 
3
28
  /**
4
29
  * See if a value is a non-null `object`.
5
30
  * @param {*} v - The value we're testing.
6
31
  * @returns {boolean}
7
- * @alias module:@lumjs/core/types.isObj
32
+ * @alias module:@lumjs/core/types/basics.isObj
8
33
  */
9
34
  function isObj(v) { return (typeof v === O && v !== null); }
10
35
 
@@ -13,7 +38,7 @@ function isObj(v) { return (typeof v === O && v !== null); }
13
38
  * Like `isObj()`, `null` does not count as an `object`.
14
39
  * @param {*} v - The value we're testing.
15
40
  * @returns {boolean}
16
- * @alias module:@lumjs/core/types.isComplex
41
+ * @alias module:@lumjs/core/types/basics.isComplex
17
42
  */
18
43
  function isComplex(v) { return (typeof v === F || isObj(v)); }
19
44
 
@@ -21,7 +46,7 @@ function isComplex(v) { return (typeof v === F || isObj(v)); }
21
46
  * See if a value is *nil* (i.e. either `null` or `undefined`).
22
47
  * @param {*} v - The value we're testing.
23
48
  * @returns {boolean}
24
- * @alias module:@lumjs/core/types.isNil
49
+ * @alias module:@lumjs/core/types/basics.isNil
25
50
  */
26
51
  function isNil(v) { return (v === undefined || v === null); }
27
52
 
@@ -29,7 +54,7 @@ function isNil(v) { return (v === undefined || v === null); }
29
54
  * See if a value is not *nil* (i.e. neither `null` nor `undefined`).
30
55
  * @param {*} v - The value we're testing.
31
56
  * @returns {boolean}
32
- * @alias module:@lumjs/core/types.notNil
57
+ * @alias module:@lumjs/core/types/basics.notNil
33
58
  */
34
59
  function notNil(v) { return (v !== undefined && v !== null); }
35
60
 
@@ -39,7 +64,7 @@ function notNil(v) { return (v !== undefined && v !== null); }
39
64
  * is neither *nil* nor *complex*.
40
65
  * @param {*} v - The value we're testing.
41
66
  * @returns {boolean}
42
- * @alias module:@lumjs/core/types.isScalar
67
+ * @alias module:@lumjs/core/types/basics.isScalar
43
68
  */
44
69
  function isScalar(v) { return (notNil(v) && !isComplex(v)); }
45
70
 
@@ -49,7 +74,7 @@ function isScalar(v) { return (notNil(v) && !isComplex(v)); }
49
74
  * @function
50
75
  * @param {*} v - The value we're testing.
51
76
  * @returns {boolean}
52
- * @alias module:@lumjs/core/types.isArray
77
+ * @alias module:@lumjs/core/types/basics.isArray
53
78
  */
54
79
  const isArray = Array.isArray;
55
80
 
@@ -57,7 +82,7 @@ const isArray = Array.isArray;
57
82
  * See if a value is a `TypedArray` object.
58
83
  * @param {*} v - The value we're testing.
59
84
  * @returns {boolean}
60
- * @alias module:@lumjs/core/types.isTypedArray
85
+ * @alias module:@lumjs/core/types/basics.isTypedArray
61
86
  */
62
87
  function isTypedArray(v)
63
88
  {
@@ -70,7 +95,7 @@ function isTypedArray(v)
70
95
  * @param {boolean} [typed=false] If `true` we want a `TypedArray`.
71
96
  * If `false` (default) we want a regular `Array`.
72
97
  * @returns {boolean}
73
- * @alias module:@lumjs/core/types.nonEmptyArray
98
+ * @alias module:@lumjs/core/types/basics.nonEmptyArray
74
99
  */
75
100
  function nonEmptyArray(v, typed=false)
76
101
  {
@@ -84,7 +109,7 @@ function nonEmptyArray(v, typed=false)
84
109
  * See if a value is an `arguments` object.
85
110
  * @param {*} v - The value we're testing.
86
111
  * @returns {boolean}
87
- * @alias module:@lumjs/core/types.isArguments
112
+ * @alias module:@lumjs/core/types/basics.isArguments
88
113
  */
89
114
  function isArguments(v)
90
115
  {
@@ -95,7 +120,7 @@ function isArguments(v)
95
120
  * See if a value is a Property name.
96
121
  * @param {*} v - The value we're testing.
97
122
  * @returns {boolean}
98
- * @alias module:@lumjs/core/types.isProperty
123
+ * @alias module:@lumjs/core/types/basics.isProperty
99
124
  */
100
125
  function isProperty(v)
101
126
  {
@@ -117,7 +142,7 @@ function isProperty(v)
117
142
  * function will pass the test.
118
143
  *
119
144
  * @returns {boolean}
120
- * @alias module:@lumjs/core/types.isIterable
145
+ * @alias module:@lumjs/core/types/basics.isIterable
121
146
  */
122
147
  function isIterable(v)
123
148
  {
@@ -129,7 +154,7 @@ function isIterable(v)
129
154
  *
130
155
  * @param {*} v - Value to test
131
156
  * @returns {boolean}
132
- * @alias module:@lumjs/core/types.isConstructor
157
+ * @alias module:@lumjs/core/types/basics.isConstructor
133
158
  */
134
159
  function isConstructor(v)
135
160
  {
@@ -153,7 +178,7 @@ function isConstructor(v)
153
178
  *
154
179
  * @param {object} obj - The object we are testing.
155
180
  * @returns {boolean} - Is the object a valid descriptor?
156
- * @alias module:@lumjs/core/types.doesDescriptor
181
+ * @alias module:@lumjs/core/types/basics.doesDescriptor
157
182
  */
158
183
  function doesDescriptor(obj)
159
184
  {
@@ -193,7 +218,7 @@ function doesDescriptor(obj)
193
218
  * If this is `false` then any unknown properties will be ignored.
194
219
  *
195
220
  * @returns {boolean} Is the object a valid descriptor template?
196
- * @alias module:@lumjs/core/types.doesDescriptorTemplate
221
+ * @alias module:@lumjs/core/types/basics.doesDescriptorTemplate
197
222
  */
198
223
  function doesDescriptorTemplate(obj, accessor=false, strict=true)
199
224
  {
@@ -229,5 +254,7 @@ module.exports =
229
254
  {
230
255
  isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
231
256
  isIterable, nonEmptyArray, isArguments, isProperty, isConstructor,
232
- doesDescriptor, doesDescriptorTemplate,
257
+ doesDescriptor, doesDescriptorTemplate, JS,
233
258
  }
259
+
260
+ JS.addTo(module.exports);
package/lib/types/def.js CHANGED
@@ -2,29 +2,27 @@
2
2
  const unbound = require('./root').unbound;
3
3
  const {F, B} = require('./js');
4
4
  const {isObj, isNil, isProperty, doesDescriptor} = require('./basics');
5
- const {copy, duplicateOne: clone} = require('../obj/copyall');
5
+ const clone = (...args) => Object.assign({}, ...args);
6
6
 
7
7
  /**
8
- * A wrapper around `Object.defineProperty()`.
9
- *
10
- * This has a few features that makes adding properties a lot nicer.
11
- * It replaces the `prop()` method from the old Lum.js v4.
8
+ * A wrapper around `Object.defineProperty()` with added flair!
12
9
  *
13
10
  * @param {(object|function)} obj - The object to add a property to.
11
+ *
14
12
  * @param {?(string|symbol|boolean|object)} name
15
13
  * If a `string` or `symbol`, it's the property name.
16
14
  *
17
15
  * If this is `null` or `undefined` then the `value` is ignored entirely,
18
16
  * and instead a bound version of this function is created with the
19
- * `obj` already passed as the first parameter, and any of the options from
20
- * `opts` added to a new default set of options bound to the function.
21
- * Can be useful if you need to add a lot of properties to the same object.
17
+ * `obj` already passed as the first parameter. It will generate context
18
+ * options which will compose the enumerable properties of `opts` if
19
+ * that argument is passed.
22
20
  *
23
21
  * If this is a `boolean`, then the same logic as if it was `null` or
24
22
  * `undefined` will apply, except that an `enumerable` property with this
25
23
  * value will also be added to the descriptors.
26
24
  *
27
- * If this is an `object`, we also ignore `value` entirely, as each of
25
+ * If this is an `object`, the `value` will be ignored, as each of
28
26
  * the keys of this object will be used as the name of a property,
29
27
  * and the value associated with the key will be the value to assign it.
30
28
  *
@@ -101,6 +99,40 @@ function def(obj, name, value, opts)
101
99
  = !unbound(this, true, true)
102
100
  && typeof this.bound === F;
103
101
 
102
+ if (isNil(name) || typeof name === B)
103
+ { // Binding of Isaac?
104
+ const bindOpts = (to) =>
105
+ {
106
+ Object.assign(to, opts);
107
+ if (typeof name === B) to.enumerable = name;
108
+ return to;
109
+ }
110
+
111
+ if (isBound)
112
+ { // Already bound, update options and return.
113
+ return bindOpts(this).bound;
114
+ }
115
+
116
+ const V = (value) => ({value, configurable: false});
117
+
118
+ // Create a fresh binding context for the bound function.
119
+ const bind = bindOpts({});
120
+ // Create a bound function.
121
+ const bound = def.bind(bind, obj);
122
+ // Add a reference to the function in the binding context.
123
+ def(bind, 'bound', V(bound));
124
+ // And a reference to the binding options from the function.
125
+ def(bound, '$this', V(bind));
126
+
127
+ if (value)
128
+ { // Add DescriptorTemplate magic properties.
129
+ const dopts = clone(value, {desc: bind});
130
+ DT.addInstance(bound, dopts);
131
+ }
132
+
133
+ return bound;
134
+ }
135
+
104
136
  // When we're finished, return this value.
105
137
  const done = () =>
106
138
  {
@@ -114,9 +146,12 @@ function def(obj, name, value, opts)
114
146
  }
115
147
  }
116
148
 
117
- if (isBound && isNil(opts))
118
- { // We'll use `this` as the options.
119
- opts = this;
149
+ if (isBound)
150
+ { // Assign `this` options.
151
+ if (isNil(opts))
152
+ opts = this;
153
+ else if (isObj(opts))
154
+ opts = clone(this, opts);
120
155
  }
121
156
 
122
157
  if (isObj(name))
@@ -128,29 +163,6 @@ function def(obj, name, value, opts)
128
163
  // Okay, we're done now.
129
164
  return done();
130
165
  }
131
- else if (isNil(name) || typeof name === B)
132
- { // Create a fresh binding context for the bound function.
133
- const bind = {};
134
-
135
- if (isObj(opts))
136
- { // Copy our existing options as defaults.
137
- copy(bind, opts);
138
- }
139
-
140
- if (typeof name === B)
141
- { // A boolean `name` overrides the enumerable option.
142
- bind.enumerable = name;
143
- }
144
-
145
- // Create a bound function.
146
- const bound = def.bind(bind, obj);
147
- // Add a reference to the function in the binding context.
148
- bind.bound = bound;
149
- // And a reference to the binding options from the function.
150
- bound.$this = bind;
151
-
152
- return bound;
153
- }
154
166
  else if (!isProperty(name))
155
167
  { // That's not valid.
156
168
  throw new TypeError("Property name must be a string or a Symbol");
@@ -225,4 +237,5 @@ module.exports = def;
225
237
 
226
238
  // Now we'll setup the descriptor template accessors.
227
239
  const DT = require('./dt');
228
- DT.addTo(def);
240
+ DT.addInit(def);
241
+ def.DT = DT;