@lumjs/core 1.0.0-beta.4 → 1.1.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.
@@ -4,6 +4,7 @@ const {O, F, S, SY} = require('./js');
4
4
  * See if a value is a non-null `object`.
5
5
  * @param {*} v - The value we're testing.
6
6
  * @returns {boolean}
7
+ * @alias module:@lumjs/core/types.isObj
7
8
  */
8
9
  function isObj(v) { return (typeof v === O && v !== null); }
9
10
 
@@ -12,6 +13,7 @@ const {O, F, S, SY} = require('./js');
12
13
  * Like `isObj()`, `null` does not count as an `object`.
13
14
  * @param {*} v - The value we're testing.
14
15
  * @returns {boolean}
16
+ * @alias module:@lumjs/core/types.isComplex
15
17
  */
16
18
  function isComplex(v) { return (typeof v === F || isObj(v)); }
17
19
 
@@ -19,6 +21,7 @@ const {O, F, S, SY} = require('./js');
19
21
  * See if a value is *nil* (i.e. either `null` or `undefined`).
20
22
  * @param {*} v - The value we're testing.
21
23
  * @returns {boolean}
24
+ * @alias module:@lumjs/core/types.isNil
22
25
  */
23
26
  function isNil(v) { return (v === undefined || v === null); }
24
27
 
@@ -26,6 +29,7 @@ const {O, F, S, SY} = require('./js');
26
29
  * See if a value is not *nil* (i.e. neither `null` nor `undefined`).
27
30
  * @param {*} v - The value we're testing.
28
31
  * @returns {boolean}
32
+ * @alias module:@lumjs/core/types.notNil
29
33
  */
30
34
  function notNil(v) { return (v !== undefined && v !== null); }
31
35
 
@@ -35,14 +39,17 @@ const {O, F, S, SY} = require('./js');
35
39
  * is neither *nil* nor *complex*.
36
40
  * @param {*} v - The value we're testing.
37
41
  * @returns {boolean}
42
+ * @alias module:@lumjs/core/types.isScalar
38
43
  */
39
44
  function isScalar(v) { return (notNil(v) && !isComplex(v)); }
40
45
 
41
46
  /**
42
47
  * See if a value is an `Array` object.
43
48
  * This is literally just a copy of `Array.isArray`.
49
+ * @function
44
50
  * @param {*} v - The value we're testing.
45
51
  * @returns {boolean}
52
+ * @alias module:@lumjs/core/types.isArray
46
53
  */
47
54
  const isArray = Array.isArray;
48
55
 
@@ -50,6 +57,7 @@ const {O, F, S, SY} = require('./js');
50
57
  * See if a value is a `TypedArray` object.
51
58
  * @param {*} v - The value we're testing.
52
59
  * @returns {boolean}
60
+ * @alias module:@lumjs/core/types.isTypedArray
53
61
  */
54
62
  function isTypedArray(v)
55
63
  {
@@ -62,6 +70,7 @@ const {O, F, S, SY} = require('./js');
62
70
  * @param {boolean} [typed=false] If `true` we want a `TypedArray`.
63
71
  * If `false` (default) we want a regular `Array`.
64
72
  * @returns {boolean}
73
+ * @alias module:@lumjs/core/types.nonEmptyArray
65
74
  */
66
75
  function nonEmptyArray(v, typed=false)
67
76
  {
@@ -75,6 +84,7 @@ const {O, F, S, SY} = require('./js');
75
84
  * See if a value is an `arguments` object.
76
85
  * @param {*} v - The value we're testing.
77
86
  * @returns {boolean}
87
+ * @alias module:@lumjs/core/types.isArguments
78
88
  */
79
89
  function isArguments(v)
80
90
  {
@@ -85,6 +95,7 @@ const {O, F, S, SY} = require('./js');
85
95
  * See if a value is a Property name.
86
96
  * @param {*} v - The value we're testing.
87
97
  * @returns {boolean}
98
+ * @alias module:@lumjs/core/types.isProperty
88
99
  */
89
100
  function isProperty(v)
90
101
  {
@@ -93,22 +104,23 @@ function isProperty(v)
93
104
  }
94
105
 
95
106
  /**
96
- * See if an object can be used as a valid descriptor.
107
+ * See if an object can be used as a valid *descriptor*.
97
108
  *
98
- * Basically in order to be considered a valid descriptor,
109
+ * Basically in order to be considered a valid *descriptor*,
99
110
  * one of the the following sets of rules must be true:
100
111
  *
101
- * - A Data Descriptor:
112
+ * - A *Data descriptor*:
102
113
  * - Has a `value` property.
103
114
  * - Does not have a `get` property.
104
115
  * - Does not have a `set` property.
105
- * - An Accessor Descriptor:
116
+ * - An *Accessor descriptor*:
106
117
  * - Has a `get` and/or `set` property.
107
118
  * - Does not have a `value` property.
108
119
  * - Does not have a `writable` property.
109
120
  *
110
121
  * @param {object} obj - The object we are testing.
111
122
  * @returns {boolean} - Is the object a valid descriptor?
123
+ * @alias module:@lumjs/core/types.doesDescriptor
112
124
  */
113
125
  function doesDescriptor(obj)
114
126
  {
@@ -133,10 +145,56 @@ function isProperty(v)
133
145
  return false;
134
146
  }
135
147
 
136
- // Now export those.
137
- module.exports =
138
- {
139
- isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
140
- nonEmptyArray, isArguments, isProperty, doesDescriptor,
141
- }
142
-
148
+ /**
149
+ * See if an object can be used as a valid *descriptor template*.
150
+ *
151
+ * This is similar to `doesDescriptor`, except that a *template*
152
+ * **must not** contain `value`, `get` or `set` properties.
153
+ *
154
+ * @param {object} obj - The object we are testing.
155
+ * @param {boolean} [accessor=false] Template is for an Accessor.
156
+ * If this is `true` then the `writable` property will also be forbidden.
157
+ * @param {boolean} [strict=true] Only allow valid descriptor properties.
158
+ * If this is `true` then **only** allow `configurable`, `enumerable`, and
159
+ * conditionally `writable` (only if `accessor` is `false`.)
160
+ * If this is `false` then any unknown properties will be ignored.
161
+ *
162
+ * @returns {boolean} Is the object a valid descriptor template?
163
+ * @alias module:@lumjs/core/types.doesDescriptorTemplate
164
+ */
165
+ function doesDescriptorTemplate(obj, accessor=false, strict=true)
166
+ {
167
+ if (!isObj(obj)) return false;
168
+
169
+ // Get a list of enumerable properties in the object.
170
+ const props = Object.keys(obj);
171
+
172
+ if (strict)
173
+ { // Strict enforcement, only valid descriptor properties allowed.
174
+ const valid = ['configurable', 'enumerable'];
175
+ if (!accessor) valid.push('writable');
176
+ for (const prop of props)
177
+ {
178
+ if (!valid.includes(prop)) return false;
179
+ }
180
+ }
181
+ else
182
+ { // Loose enforcement mode, reject on forbidden properties only.
183
+ const forbidden = ['value','get','set'];
184
+ if (accessor) forbidden.push('writable');
185
+ for (const prop of props)
186
+ {
187
+ if (forbidden.includes(prop)) return false;
188
+ }
189
+ }
190
+
191
+ // No tests failed, this can be used as a template.
192
+ return true;
193
+ }
194
+
195
+ // Now export those.
196
+ module.exports =
197
+ {
198
+ isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
199
+ nonEmptyArray, isArguments, isProperty, doesDescriptor, doesDescriptorTemplate,
200
+ }
package/lib/types/def.js CHANGED
@@ -4,6 +4,9 @@ const {F, B} = require('./js');
4
4
  const {isObj, isNil, isProperty, doesDescriptor} = require('./basics');
5
5
  const copy = require('../obj/copyall');
6
6
 
7
+ // A really really cheap version of clone().
8
+ const clone = obj => copy({}, obj);
9
+
7
10
  /**
8
11
  * A wrapper around `Object.defineProperty()`.
9
12
  *
@@ -12,16 +15,22 @@ const copy = require('../obj/copyall');
12
15
  *
13
16
  * @param {(object|function)} obj - The object to add a property to.
14
17
  * @param {?(string|boolean|object)} name - If a `string`, the property name.
18
+ * Property names may also be `symbol` values.
15
19
  *
16
20
  * If this is `null` or `undefined` then the `value` is ignored entirely,
17
21
  * and instead a bound version of this function is created with the
18
- * `obj` already passed as the first parameter. Can be useful if you
19
- * need to add a lot of properties to the same object.
22
+ * `obj` already passed as the first parameter, and any of the options from
23
+ * `opts` added to a new default set of options bound to the function.
24
+ * Can be useful if you need to add a lot of properties to the same object.
20
25
  *
21
26
  * If this is a `boolean`, then the same logic as if it was `null` or
22
27
  * `undefined` will apply, except that an `enumerable` property with this
23
28
  * value will also be added to the descriptors.
24
29
  *
30
+ * If this is an `object`, we also ignore `value` entirely, as each of
31
+ * the keys of this object will be used as the name of a property,
32
+ * and the value associated with the key will be the value to assign it.
33
+ *
25
34
  * @param {*} value - Used to determine the value of the property.
26
35
  *
27
36
  * If it is an a valid descriptor object (as per `doesDescriptor()`),
@@ -29,31 +38,29 @@ const copy = require('../obj/copyall');
29
38
  * property defined, one will be added, and will be set to `true`.
30
39
  * This behaviour may be overridden by the `opts` parameter.
31
40
  *
32
- * If this is a `function` and `opts` is a `boolean` or `function`,
33
- * then this will be used as a getter or setter (see `opts` for details.)
41
+ * If this and `opts` are both `function` values, then this will
42
+ * be used as a *getter*, and `opts` will be used a *setter*.
34
43
  *
35
44
  * Any other value passed here will be used as the `value` in a
36
45
  * pre-canned descriptor, also with `configurable` set to `true`.
37
46
  *
38
- * @param {(object|function|boolean)} [opts] - A multi-purpose option.
47
+ * @param {*} [opts] - A multi-purpose option.
39
48
  *
40
49
  * If this is an `object` then it is reserved for named options.
41
- * Any other use of this is dependent on the `value` parameter.
50
+ * The named options `configurable`, `enumerable`, and `writable`
51
+ * can be used to define default values to the descriptor properties
52
+ * of the same name.
42
53
  *
43
54
  * If `value` and this are both `function` values, then `value` will
44
55
  * be used as a *getter* and this will be used as a *setter*.
45
56
  *
46
- * If `value` is a `function` and this is `true`, then `value` will
47
- * be used as a *getter* and no *setter* will be assigned.
48
- *
49
- * If `value` is a `function` and this is `false`, then `value` will
50
- * be used as a *setter* and no *getter* will be assigned.
51
- *
52
57
  * If `value` is a valid descriptor object, then setting this to `false`
53
58
  * will disable the assumption that it is the descriptor to set.
54
59
  * Setting this to `true` on will instruct the function to make a clone
55
60
  * of the descriptor object before modifying any properties in it.
56
61
  *
62
+ * This defaults to `undefined`, except if
63
+ *
57
64
  * @returns {*} Normally the `obj` argument with new property added.
58
65
  *
59
66
  * The exception is if this is a bound copy of the function created
@@ -66,6 +73,7 @@ const copy = require('../obj/copyall');
66
73
  * def(myObj)('name', "Bob")('age', 42);
67
74
  * ```
68
75
  *
76
+ * @alias module:@lumjs/core/types.def
69
77
  */
70
78
  function def(obj, name, value, opts)
71
79
  {
@@ -132,17 +140,12 @@ function def(obj, name, value, opts)
132
140
 
133
141
  if (opts !== false && doesDescriptor(value))
134
142
  { // The value is a descriptor, let's use it.
135
- desc = (opts === true) ? copy(value) : value;
143
+ desc = (opts === true) ? clone(value) : value;
136
144
  }
137
145
  else if (typeof value === F && typeof opts === F)
138
146
  { // A getter and setter were both specified.
139
147
  desc = {get: value, set: opts};
140
148
  }
141
- else if (typeof value === F && typeof opts === B)
142
- { // A function value with a boolean opts is a getter or setter.
143
- const prop = opts ? 'get' : 'set';
144
- desc = {[prop]: value};
145
- }
146
149
  else
147
150
  { // The value is just a value, so let's assign it.
148
151
  desc = {value};
@@ -1,4 +1,20 @@
1
- /// Type checking and other features common to everything else.
1
+ /**
2
+ * Fundamental Types sub-module.
3
+ *
4
+ * As `@lumjs/core` is the foundation for all my JS libraries,
5
+ * this sub-module is the foundation for `@lumjs/core`.
6
+ * Everything else is built upon this.
7
+ *
8
+ * @module @lumjs/core/types
9
+ * @property {string} O - "object"
10
+ * @property {string} F - "function"
11
+ * @property {string} S - "string"
12
+ * @property {string} B - "binary"
13
+ * @property {string} N - "number"
14
+ * @property {string} U - "undefined"
15
+ * @property {string} SY - "symbol"
16
+ * @property {string} BI - "bigint"
17
+ */
2
18
 
3
19
  // Constants representing core Javascript types.
4
20
  const {O, F, S, B, N, U, SY, BI} = require('./js');
@@ -8,6 +24,7 @@ const
8
24
  {
9
25
  isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
10
26
  nonEmptyArray, isArguments, isProperty, doesDescriptor,
27
+ doesDescriptorTemplate,
11
28
  } = require('./basics');
12
29
 
13
30
  // Root namespace helpers.
@@ -23,6 +40,7 @@ const {needObj, needType, needs} = require('./needs');
23
40
 
24
41
  const def = require('./def');
25
42
  const TYPES = require('./typelist');
43
+ const stringify = require('./stringify');
26
44
 
27
45
  // Okay, add all those to our exports.
28
46
  // Further tests can be added by `TYPES.add()` later.
@@ -31,7 +49,8 @@ module.exports =
31
49
  O, F, S, B, N, U, SY, BI, TYPES, root, unbound, def,
32
50
  isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
33
51
  nonEmptyArray, isArguments, isProperty, doesDescriptor,
34
- isInstance, isType, isa, needObj, needType, needs,
52
+ isInstance, isType, isa, needObj, needType, needs, stringify,
53
+ doesDescriptorTemplate,
35
54
  }
36
55
 
37
56
  // Last but not least, this will be the module for TYPES.add()
package/lib/types/isa.js CHANGED
@@ -8,6 +8,7 @@ const TYPES = require('./typelist');
8
8
  * @param {function} f - The constructor/class we want.
9
9
  * @param {boolean} [needProto=false] If true, the `v` must have a `prototype`.
10
10
  * @returns {boolean}
11
+ * @alias module:@lumjs/core/types.isInstance
11
12
  */
12
13
  function isInstance(v, f, needProto=false)
13
14
  {
@@ -30,24 +31,15 @@ const TYPES = require('./typelist');
30
31
  *
31
32
  * @param {string} type - The type we're checking for.
32
33
  *
33
- * This supports all the same type names as `typeof` plus:
34
- *
35
- * - `arguments` → An arguments object inside a function.
36
- * - `array` → An Array object.
37
- * - `null` → A null value.
38
- * - `typedarray` → One of the typed array objects.
39
- * - `descriptor` → An object which is a valid descriptor.
40
- * - `complex` → Either an `object` or a `function.
41
- * - `scalar` → Anything other than an `object` or `function`.
42
- * - `property` → A `string` or a `symbol`.
43
- * - `nil` → Either `null` or `undefined`.
34
+ * This supports all the same type names as `typeof` plus any of
35
+ * the properties defined in the `TYPES` object.
44
36
  *
45
37
  * One other thing, while `typeof` reports `null` as being an `object`,
46
38
  * this function does not count `null` as a valid `object`.
47
39
  *
48
40
  * @param {*} v - The value we're testing.
49
- *
50
41
  * @returns {boolean} If the value was of the desired type.
42
+ * @alias module:@lumjs/core/types.isType
51
43
  */
52
44
  function isType(type, v)
53
45
  {
@@ -138,6 +130,7 @@ const TYPES = require('./typelist');
138
130
  * Any other type value will only match if `v === type`
139
131
  *
140
132
  * @returns {boolean} Was the value one of the desired types?
133
+ * @alias module:@lumjs/core/types.isa
141
134
  */
142
135
  function isa(v, ...types)
143
136
  {
@@ -9,6 +9,7 @@ const {isObj, isComplex} = require('./basics');
9
9
  * @param {boolean} [allowFunc=false] - Also accept functions?
10
10
  * @param {string} [msg] A custom error message.
11
11
  * @throws {TypeError} If the type check failed.
12
+ * @alias module:@lumjs/core/types.needObj
12
13
  */
13
14
  function needObj (v, allowFunc=false, msg=null)
14
15
  {
@@ -33,6 +34,7 @@ exports.needObj = needObj;
33
34
  * @param {*} v - The value we're testing.
34
35
  * @param {string} [msg] A custom error message.
35
36
  * @throws {TypeError} If the type check failed.
37
+ * @alias module:@lumjs/core/types.needType
36
38
  */
37
39
  function needType (type, v, msg, unused)
38
40
  {
@@ -77,7 +79,10 @@ const NEEDS_PARSER = function(type, v)
77
79
  * look for an `object` with a single property named `error`
78
80
  * which can be either a `string` or any subclass of `Error`.
79
81
  * If specified, it will override the error message that will be thrown.
80
- *
82
+ *
83
+ * @throws {TypeError} If the type check failed.
84
+ * @throws {Error} If a custom error was specified.
85
+ * @alias module:@lumjs/core/types.needs
81
86
  */
82
87
  function needs(v, ...types)
83
88
  {
package/lib/types/root.js CHANGED
@@ -9,6 +9,7 @@ function no_root()
9
9
 
10
10
  /**
11
11
  * The global root object. Usually `globalThis` these days.
12
+ * @alias module:@lumjs/core/types.root
12
13
  */
13
14
  const root = typeof globalThis !== U ? globalThis
14
15
  : typeof global !== U ? global
@@ -32,6 +33,7 @@ const unboundObjects = [];
32
33
  * If the is `true` we use an global list that can register special
33
34
  * internal objects. Otherwise an `Array` of unbound objects may be used.
34
35
  * @returns {boolean}
36
+ * @alias module:@lumjs/core/types.unbound
35
37
  */
36
38
  function unbound(whatIsThis, rootIsUnbound=true, areUnbound=false)
37
39
  {
@@ -56,13 +58,11 @@ const def = require('./def');
56
58
  /**
57
59
  * Add an item to the unbound global objects list.
58
60
  *
59
- * @method unbound.add
60
- *
61
+ * @function
61
62
  * @param {(object|function)} obj - The object to be considered unbound.
62
- *
63
63
  * @returns {boolean} Will be `false` if `obj` is already unbound.
64
- *
65
64
  * @throws {TypeError} If `obj` was neither an `object` nor a `function`.
65
+ * @alias module:@lumjs/core/types.unbound.add
66
66
  */
67
67
  def(unbound, 'add', function (obj)
68
68
  {
@@ -79,13 +79,11 @@ def(unbound, 'add', function (obj)
79
79
  /**
80
80
  * Remove an item from the unbound global objects list.
81
81
  *
82
- * @method unbound.remove
83
- *
82
+ * @function
84
83
  * @param {(object|function)} obj - The object to be removed.
85
- *
86
84
  * @returns {boolean} Will be `false` if the item was not in the list.
87
- *
88
85
  * @throws {TypeError} If `obj` was neither an `object` nor a `function`.
86
+ * @alias module:@lumjs/core/types.unbound.remove
89
87
  */
90
88
  def(unbound, 'remove', function(obj)
91
89
  {
@@ -0,0 +1,142 @@
1
+ // Get the extended type list.
2
+ const TYPES = require('./typelist');
3
+ const {isObj, isArray, isTypedArray} = require('./basics');
4
+ const def = require('./def');
5
+
6
+ const TOSTRING_TYPES = [TYPES.F, TYPES.SY];
7
+ const TOSTRING_INSTANCES = [RegExp];
8
+ const CUSTOM = [];
9
+
10
+ /**
11
+ * Stringify a Javascript value.
12
+ *
13
+ * We typically just use `JSON.stringify()` but that doesn't work on
14
+ * some types. So this function adds string formats for:
15
+ * - `function`
16
+ * - `symbol`
17
+ * - `TypedArray`
18
+ * - `Map`
19
+ * - `Set`
20
+ * - `Error`
21
+ * I may add even more extended types in the future, but that's enough
22
+ * for now.
23
+ *
24
+ * This is NOT meant for serializing data, and does not use a JSON-friendly
25
+ * output format. I'm writing a different library for that.
26
+ *
27
+ * @param {*} what - The value to stringify.
28
+ * @param {integer} [recurse=1] Recurse objects to this depth.
29
+ * @param {boolean} [addNew=false] Use 'new Class()' instead of 'Class()'.
30
+ * @returns {string} The stringified value.
31
+ * @alias module:@lumjs/core/types.stringify
32
+ */
33
+ function stringify (what, recurse=1, addNew=false)
34
+ {
35
+ const whatType = typeof what;
36
+
37
+ for (const test of CUSTOM)
38
+ { // If there are custom extensions, we check them first.
39
+ const ret = test.call({stringify}, what, recurse, addNew);
40
+ if (typeof ret === TYPES.S)
41
+ { // The extension processed the item.
42
+ return ret;
43
+ }
44
+ }
45
+
46
+ // A few types we simply stringify right now.
47
+ if (TOSTRING_TYPES.includes(whatType)) return what.toString();
48
+
49
+ if (isObj(what))
50
+ { // We support a few kinds of objects.
51
+
52
+ // Any class instance that we can simply call `toString()` on, let's do that.
53
+ for (const aClass of TOSTRING_INSTANCES)
54
+ {
55
+ if (what instanceof aClass)
56
+ {
57
+ return what.toString();
58
+ }
59
+ }
60
+
61
+ // A few formatting helpers used below.
62
+ const classname = () => (addNew ? 'new ' : '') + what.constructor.name;
63
+ const construct = val => `${classname()}(${val})`;
64
+ const reconstruct = val => construct(stringify(val,recurse,addNew));
65
+ const arrayish = vals => reconstruct(Array.from(vals));
66
+
67
+ if (isTypedArray(what))
68
+ { // This one is pretty simple.
69
+ return construct(what.toString());
70
+ }
71
+
72
+ if (what instanceof Map)
73
+ {
74
+ return arrayish(what.entries());
75
+ }
76
+
77
+ if (what instanceof Set)
78
+ {
79
+ return arrayish(what.values());
80
+ }
81
+
82
+ if (what instanceof Error)
83
+ {
84
+ return `${what.name}(${JSON.stringify(what.message)})`;
85
+ }
86
+
87
+ if (recurse)
88
+ { // Recursion mode enabled.
89
+ let out = '';
90
+ if (isArray(what))
91
+ { // Stringify an array.
92
+ out = '[';
93
+ out += what.map(item => stringify(item, recurse-1, addNew)).join(',');
94
+ out += ']';
95
+ }
96
+ else
97
+ { // Stringify a plain object.
98
+ out = '{';
99
+ function add(key, pre='')
100
+ {
101
+ out += `${pre}${key}:${stringify(what[key], recurse-1, addNew)}`
102
+ }
103
+ const keys = Object.keys(what);
104
+ //console.debug("keys!", keys);
105
+ if (keys.length > 0)
106
+ { // Let's add the first key, then all subsequent keys.
107
+ add(keys.shift());
108
+ for (const key of keys)
109
+ {
110
+ add(key, ',');
111
+ }
112
+ }
113
+ out += '}';
114
+ }
115
+ return out;
116
+ }
117
+
118
+ } // if isObj
119
+
120
+ // If we reached here, there's no special methods, use JSON.
121
+ return JSON.stringify(what);
122
+ }
123
+
124
+ // Add a custom extension.
125
+ def(stringify, '$extend',
126
+ function(func, registration=false)
127
+ {
128
+ if (typeof func === TYPES.F)
129
+ {
130
+ if (registration)
131
+ { // Using the function to register custom behaviour.
132
+ func.call({stringify, TOSTRING_INSTANCES, TOSTRING_TYPES}, CUSTOM);
133
+ }
134
+ else
135
+ { // The function is a custom test.
136
+ CUSTOM.push(func);
137
+ }
138
+ }
139
+ });
140
+
141
+ // Export it.
142
+ module.exports = stringify;
@@ -7,12 +7,76 @@ const
7
7
  } = require('./basics');
8
8
 
9
9
  /**
10
- * A map of type names including special and union types.
10
+ * A map of **Types**, including *special* and *union* types.
11
+ *
12
+ * Contains the same `O, F, S, B, N, U, SY, BI` properties as also
13
+ * found in the top-level {@link module:@lumjs/core/types} module.
14
+ * While most of the core JS types simply use `typeof` as their
15
+ * test, this maps the `O` (`object`) type to the `isObj` test.
16
+ *
11
17
  * Will also contain a few helper functions, and a map of tests
12
- * for any types that require tests other than `typeof v === 'typename'`
18
+ * that are used by `isType`, `isa`, `needType`, and `needs`.
19
+ * Any one of these properties may be passed to those functions as
20
+ * the desired *type* a desired value must be.
21
+ *
22
+ * We will list the types added by the `types` module in
23
+ * the *Properties* table, and any types added by other *core modules*
24
+ * in the *Members* list, prior to listing the *Methods*.
25
+ *
26
+ * @namespace module:@lumjs/core/types.TYPES
27
+ * @property {string} NULL - Represents `null` values.
28
+ * @property {string} ARGS - Represents an *argument* object.
29
+ * @property {string} PROP - A `string` or a `symbol`.
30
+ * @property {string} ARRAY - An `Array` object.
31
+ * @property {string} TYPEDARRAY - A `TypedArray` object.
32
+ * @property {string} DESCRIPTOR - A *Descriptor* object (Data or Accessor).
33
+ * @property {string} COMPLEX - A `function` or an `object`.
34
+ * @property {string} SCALAR - A non-null value that is **not** *complex*.
35
+ * @property {string} NIL - Either `null` or `undefined`.
36
+ * @property {string} NOTNIL - Anything other than `null` or `undefined`.
37
+ * @property {string} MAP - A `Map` object.
38
+ * @property {object} tests - A map of tests for the above types.
13
39
  */
14
40
  const TYPES = {};
15
41
 
42
+ /**
43
+ * Add a new type to the `TYPES`.
44
+ * @name module:@lumjs/core/types.TYPES.add
45
+ * @function
46
+ * @param {(string|object)} name - If a `string` the property name to use.
47
+ * When adding the property the string will be forced to uppercase.
48
+ *
49
+ * If an `object` then its a shortcut for adding a bunch of types at once.
50
+ * Each key will be the `name`, and the type of the *value* can be one of:
51
+ * - `string` → Use as the `ident` parameter.
52
+ * - `function` → Use as the `test` parameter.
53
+ * - `object` → Supports `id`, `test`, and `export` parameters.
54
+ *
55
+ * @param {?string} [ident] The identifier string for the type.
56
+ * If not specified or `null`, it will default to a completely lowercase
57
+ * version of the `name` parameter.
58
+ * @param {function} [test] A type check test.
59
+ * Must accept a single value to test, must return a boolean.
60
+ * @param {string} [exportTest] A name to export the test as.
61
+ * The test will be added to the `types` module with this name.
62
+ *
63
+ * @returns {void}
64
+ */
65
+
66
+ /**
67
+ * Get a list of type properties available in `TYPES`.
68
+ * @name module:@lumjs/core/types.TYPES.keys
69
+ * @function
70
+ * @returns {string[]}
71
+ */
72
+
73
+ /**
74
+ * Get a list of type identifier values available in `TYPES`.
75
+ * @name module:@lumjs/core/types.TYPES.list
76
+ * @function
77
+ * @returns {string[]}
78
+ */
79
+
16
80
  // Let's setup the TYPES with its magic functions.
17
81
  const dt = def(TYPES);
18
82
  dt('tests', {})