@lumjs/core 1.0.0-beta.4 → 1.0.0-beta.6
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 +6 -3
- package/TODO.md +6 -12
- package/docs/changelogs/1.0-beta.md +33 -3
- package/docs/changelogs/1.x.md +17 -0
- package/lib/arrays.js +19 -7
- package/lib/context.js +46 -9
- package/lib/enum.js +29 -15
- package/lib/flags.js +6 -0
- package/lib/index.js +77 -5
- package/lib/lazy.js +7 -5
- package/lib/meta.js +10 -0
- package/lib/modules.js +27 -3
- package/lib/obj/clone.js +11 -9
- package/lib/obj/copyall.js +3 -0
- package/lib/obj/copyprops.js +1 -0
- package/lib/obj/index.js +4 -4
- package/lib/obj/lock.js +13 -9
- 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 -9
- package/lib/opt.js +6 -1
- package/lib/strings.js +43 -4
- package/lib/types/basics.js +12 -0
- package/lib/types/def.js +21 -18
- package/lib/types/index.js +19 -2
- package/lib/types/isa.js +5 -12
- package/lib/types/needs.js +6 -1
- package/lib/types/root.js +6 -8
- package/lib/types/stringify.js +98 -0
- package/lib/types/typelist.js +66 -2
- package/package.json +21 -3
- package/test/types.js +102 -13
package/lib/types/index.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
|
|
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');
|
|
@@ -23,6 +39,7 @@ const {needObj, needType, needs} = require('./needs');
|
|
|
23
39
|
|
|
24
40
|
const def = require('./def');
|
|
25
41
|
const TYPES = require('./typelist');
|
|
42
|
+
const stringify = require('./stringify');
|
|
26
43
|
|
|
27
44
|
// Okay, add all those to our exports.
|
|
28
45
|
// Further tests can be added by `TYPES.add()` later.
|
|
@@ -31,7 +48,7 @@ module.exports =
|
|
|
31
48
|
O, F, S, B, N, U, SY, BI, TYPES, root, unbound, def,
|
|
32
49
|
isObj, isComplex, isNil, notNil, isScalar, isArray, isTypedArray,
|
|
33
50
|
nonEmptyArray, isArguments, isProperty, doesDescriptor,
|
|
34
|
-
isInstance, isType, isa, needObj, needType, needs,
|
|
51
|
+
isInstance, isType, isa, needObj, needType, needs, stringify,
|
|
35
52
|
}
|
|
36
53
|
|
|
37
54
|
// 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
|
{
|
package/lib/types/needs.js
CHANGED
|
@@ -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
|
-
* @
|
|
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
|
-
* @
|
|
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,98 @@
|
|
|
1
|
+
// Get the extended type list.
|
|
2
|
+
const TYPES = require('./typelist');
|
|
3
|
+
const {isObj, isArray, isTypedArray} = require('./basics');
|
|
4
|
+
|
|
5
|
+
const TOSTRING = [TYPES.F, TYPES.SY];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Stringify a Javascript value.
|
|
9
|
+
*
|
|
10
|
+
* We typically just use `JSON.stringify()` but that doesn't work on
|
|
11
|
+
* some types. So this function adds string formats for:
|
|
12
|
+
* - `function`
|
|
13
|
+
* - `symbol`
|
|
14
|
+
* - `TypedArray`
|
|
15
|
+
* - `Map`
|
|
16
|
+
* - `Set`
|
|
17
|
+
* - `Error`
|
|
18
|
+
* I may add even more extended types in the future, but that's enough
|
|
19
|
+
* for now.
|
|
20
|
+
*
|
|
21
|
+
* This is NOT meant for serializing data, and does not use a JSON-friendly
|
|
22
|
+
* output format. I'm writing a different library for that.
|
|
23
|
+
*
|
|
24
|
+
* @param {*} what - The value to stringify.
|
|
25
|
+
* @param {integer} [recurse=1] Recurse objects to this depth.
|
|
26
|
+
* @param {boolean} [addNew=false] Use 'new Class()' instead of 'Class()'.
|
|
27
|
+
* @returns {string} The stringified value.
|
|
28
|
+
* @alias module:@lumjs/core/types.stringify
|
|
29
|
+
*/
|
|
30
|
+
function stringify (what, recurse=1, addNew=false)
|
|
31
|
+
{
|
|
32
|
+
const whatType = typeof what;
|
|
33
|
+
if (TOSTRING.includes(whatType)) return what.toString();
|
|
34
|
+
|
|
35
|
+
// A few formatting helpers used below.
|
|
36
|
+
|
|
37
|
+
const classname = () => (addNew ? 'new ' : '') + what.constructor.name;
|
|
38
|
+
const construct = val => `${classname()}(${val})`;
|
|
39
|
+
const reconstruct = val => construct(stringify(val,recurse,addNew));
|
|
40
|
+
const arrayish = vals => reconstruct(Array.from(vals));
|
|
41
|
+
|
|
42
|
+
if (isTypedArray(what))
|
|
43
|
+
{ // This one is pretty simple.
|
|
44
|
+
return construct(what.toString());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (what instanceof Map)
|
|
48
|
+
{
|
|
49
|
+
return arrayish(what.entries());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (what instanceof Set)
|
|
53
|
+
{
|
|
54
|
+
return arrayish(what.values());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (what instanceof Error)
|
|
58
|
+
{
|
|
59
|
+
return construct(what.message);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (recurse && isObj(what))
|
|
63
|
+
{ // Recursion mode enabled.
|
|
64
|
+
let out = '';
|
|
65
|
+
if (isArray(what))
|
|
66
|
+
{ // Stringify an array.
|
|
67
|
+
out = '[';
|
|
68
|
+
out += what.map(item => stringify(item, recurse-1, addNew)).join(',');
|
|
69
|
+
out += ']';
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{ // Stringify a plain object.
|
|
73
|
+
out = '{';
|
|
74
|
+
function add(key, pre='')
|
|
75
|
+
{
|
|
76
|
+
out += `${pre}${key}:${stringify(what[key], recurse-1, addNew)}`
|
|
77
|
+
}
|
|
78
|
+
const keys = Object.keys(what);
|
|
79
|
+
//console.debug("keys!", keys);
|
|
80
|
+
if (keys.length > 0)
|
|
81
|
+
{ // Let's add the first key, then all subsequent keys.
|
|
82
|
+
add(keys.shift());
|
|
83
|
+
for (const key of keys)
|
|
84
|
+
{
|
|
85
|
+
add(key, ',');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
out += '}';
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
else
|
|
93
|
+
{ // If we reached here, there's no special methods, use JSON.
|
|
94
|
+
return JSON.stringify(what);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = stringify;
|
package/lib/types/typelist.js
CHANGED
|
@@ -7,12 +7,76 @@ const
|
|
|
7
7
|
} = require('./basics');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* A map of
|
|
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
|
-
*
|
|
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', {})
|
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumjs/core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.6",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
|
+
"exports":
|
|
6
|
+
{
|
|
7
|
+
".": "./lib/index.js",
|
|
8
|
+
"./types": "./lib/types/index.js",
|
|
9
|
+
"./arrays": "./lib/arrays.js",
|
|
10
|
+
"./context": "./lib/context.js",
|
|
11
|
+
"./strings": "./lib/strings.js",
|
|
12
|
+
"./flags": "./lib/flags.js",
|
|
13
|
+
"./obj": "./lib/obj/index.js",
|
|
14
|
+
"./opt": "./lib/opt.js",
|
|
15
|
+
"./modules": "./lib/moduless.js",
|
|
16
|
+
"./meta": "./lib/meta.js",
|
|
17
|
+
"./enum": "./lib/enum.js",
|
|
18
|
+
"./observable": "./lib/observable.js",
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
5
21
|
"license": "MIT",
|
|
6
22
|
"repository":
|
|
7
23
|
{
|
|
@@ -10,11 +26,13 @@
|
|
|
10
26
|
},
|
|
11
27
|
"devDependencies":
|
|
12
28
|
{
|
|
13
|
-
"@lumjs/tests": "^1.0.0"
|
|
29
|
+
"@lumjs/tests": "^1.0.0",
|
|
30
|
+
"jsdoc": "^3.6.10"
|
|
14
31
|
},
|
|
15
32
|
"scripts":
|
|
16
33
|
{
|
|
17
34
|
"-TODO-1": "Use `lumtest` once its available",
|
|
18
|
-
"test": "prove -e node --ext js ./test"
|
|
35
|
+
"test": "prove -e node --ext js ./test",
|
|
36
|
+
"build-docs": "jsdoc -c ./jsdoc.json"
|
|
19
37
|
}
|
|
20
38
|
}
|
package/test/types.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
// Current test count.
|
|
2
|
-
const plan =
|
|
2
|
+
const plan = 120;
|
|
3
3
|
// A new test instance.
|
|
4
4
|
const t = require('@lumjs/tests').new({module, plan});
|
|
5
5
|
// The types core module
|
|
6
6
|
const types = require('../lib/types');
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// A quick reference to the type names.
|
|
9
9
|
const TYP = types.TYPES;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function stringify (what)
|
|
13
|
-
{
|
|
14
|
-
if (typeof what === TYP.F) return what.toString();
|
|
15
|
-
if (typeof what === TYP.SY) return what.constructor.toString();
|
|
16
|
-
return JSON.stringify(what);
|
|
17
|
-
}
|
|
10
|
+
// And the stringify function.
|
|
11
|
+
const stringify = types.stringify;
|
|
18
12
|
|
|
19
13
|
// Now for some further basics.
|
|
20
14
|
t.ok(types.isObj({}), 'isObj({})');
|
|
@@ -55,10 +49,16 @@ class SubtypeClass extends TypeClass {}
|
|
|
55
49
|
const typesInstance = new TypeClass();
|
|
56
50
|
const subtypeInstance = new SubtypeClass();
|
|
57
51
|
|
|
52
|
+
class DifferentClass {}
|
|
53
|
+
|
|
54
|
+
const differentInstance = new DifferentClass();
|
|
55
|
+
|
|
58
56
|
t.ok(types.isInstance(typesInstance, TypeClass), 'isInstance(typeInstance,TypeClass)');
|
|
59
57
|
t.ok(types.isInstance(subtypeInstance, SubtypeClass), 'isInstance(subtypeInstance, SubtypeClass)');
|
|
60
58
|
t.ok(types.isInstance(subtypeInstance, TypeClass), 'isInstance(subtypeInstance, TypeClass)');
|
|
61
|
-
t.ok(!types.isInstance(typesInstance, SubtypeClass), '!isInstance(typeInstance, SubtypeClass');
|
|
59
|
+
t.ok(!types.isInstance(typesInstance, SubtypeClass), '!isInstance(typeInstance, SubtypeClass)');
|
|
60
|
+
t.ok(!types.isInstance(differentInstance, TypeClass), '!isInstance(differentInstance, TypeClass)');
|
|
61
|
+
t.ok(!types.isInstance(typesInstance, DifferentClass), '!isInstance(typesInstance, DifferentClass)');
|
|
62
62
|
|
|
63
63
|
function doesDesc (tests, not=false)
|
|
64
64
|
{
|
|
@@ -126,7 +126,7 @@ testIsType(
|
|
|
126
126
|
[TYP.SCALAR, true],
|
|
127
127
|
[TYP.SCALAR, 'hi'],
|
|
128
128
|
[TYP.PROP, 'woah'],
|
|
129
|
-
[TYP.PROP, Symbol('woah')
|
|
129
|
+
[TYP.PROP, Symbol('woah')],
|
|
130
130
|
]);
|
|
131
131
|
|
|
132
132
|
testIsType(
|
|
@@ -161,18 +161,107 @@ t.dies(function(){types.needObj(null); return true}, '!needObj(null)');
|
|
|
161
161
|
t.ok((function(){types.needType(TYP.S, 'hi'); return true})(), "needType('string','hi')");
|
|
162
162
|
t.dies(function(){types.needType(TYP.O, null); return true}, "!needType('object',null)");
|
|
163
163
|
|
|
164
|
+
{ // Tests of isa() method.
|
|
165
|
+
let wants = [TYP.S, TYP.N];
|
|
166
|
+
t.ok(types.isa('hi', ...wants), 'isa(val, ...types)');
|
|
167
|
+
t.isa('hello', wants, ' ^ using Test.isa()');
|
|
168
|
+
t.isa(42, wants, ' ^ with second type');
|
|
169
|
+
t.ok(!types.isa({}, ...wants), '!isa(val, ...types)');
|
|
170
|
+
t.nota({}, wants, ' ^ using Test.nota()');
|
|
171
|
+
|
|
172
|
+
wants = [SubtypeClass, DifferentClass];
|
|
173
|
+
t.isa(subtypeInstance, wants, 'isa(val, ...classes)');
|
|
174
|
+
t.isa(differentInstance, wants, ' ^ with second class');
|
|
175
|
+
t.nota(typesInstance, wants, 'nota(val, ...classes)');
|
|
176
|
+
|
|
177
|
+
wants = [TYP.B, TypeClass];
|
|
178
|
+
t.isa(true, wants, 'isa() → with mixed types/classes');
|
|
179
|
+
t.isa(subtypeInstance, wants, ' ^ with second type/class');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
{ // Tests of needs() method.
|
|
183
|
+
let needs = [TYP.S, TYP.N];
|
|
184
|
+
t.lives(() => types.needs('hi', ...needs), 'needs(val, ...types)');
|
|
185
|
+
t.lives(() => types.needs(42, ...needs), ' ^ with second type');
|
|
186
|
+
t.dies(() => types.needs({}, ...needs), ' ^ throws on failure');
|
|
187
|
+
|
|
188
|
+
needs = [SubtypeClass, DifferentClass];
|
|
189
|
+
t.lives(() => types.needs(subtypeInstance, ...needs), 'needs(val, ...classes)');
|
|
190
|
+
t.lives(() => types.needs(differentInstance, ...needs), ' ^ with second class');
|
|
191
|
+
t.dies(() => types.needs(typesInstance, ...needs), ' ^ throws on failure');
|
|
192
|
+
|
|
193
|
+
needs = [TYP.B, TypeClass];
|
|
194
|
+
t.lives(() => types.needs(true, ...needs), 'needs() → with mixed types/classes');
|
|
195
|
+
t.lives(() => types.needs(subtypeInstance, ...needs), ' ^ with second type/class');
|
|
196
|
+
}
|
|
197
|
+
|
|
164
198
|
{ // Try a few versions of 'def'
|
|
165
199
|
const obj = {};
|
|
166
200
|
types.def(obj, 'test1', 'Test 1');
|
|
167
201
|
t.is(obj.test1, 'Test 1', 'def(obj, name, value)');
|
|
168
202
|
types.def(obj)('test2', 'Test 2');
|
|
169
203
|
t.is(obj.test2, 'Test 2', 'def(obj)(name, value)');
|
|
204
|
+
obj.test2 = '2 Test';
|
|
205
|
+
t.is(obj.test2, 'Test 2', 'def() is read-only by default');
|
|
206
|
+
|
|
207
|
+
types.def(obj, true)('test3', 'Test 3');
|
|
208
|
+
t.is(Object.keys(obj).length, 1, 'def(obj, true)(...)');
|
|
209
|
+
|
|
210
|
+
types.def(obj, 'a1', function()
|
|
211
|
+
{ // Returning a different property.
|
|
212
|
+
return this.test2;
|
|
213
|
+
},
|
|
214
|
+
function(val)
|
|
215
|
+
{ // Assigning to a different property.
|
|
216
|
+
this.$$ = val;
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const gs = 'def(obj, name, getter, setter)';
|
|
220
|
+
t.is(obj.a1, 'Test 2', gs+'~getter');
|
|
221
|
+
obj.a1 = 'A1->$$';
|
|
222
|
+
t.is(obj.$$, 'A1->$$', gs+'~setter');
|
|
223
|
+
|
|
224
|
+
types.def(obj, 'test4', 'Test 4', {writable: true});
|
|
225
|
+
t.is(obj.test4, 'Test 4', 'def(..., {writable}) → added property');
|
|
226
|
+
obj.test4 = '4 Test';
|
|
227
|
+
t.is(obj.test4, '4 Test', ' ^ and it was writable');
|
|
228
|
+
|
|
229
|
+
const td = types.def(obj);
|
|
230
|
+
td('getOnly', {get: function() { return 'GETTER'; }});
|
|
231
|
+
obj.getOnly = 'blah blah blah';
|
|
232
|
+
t.is(obj.getOnly, 'GETTER', 'def(..., {get: getter}) → getter worked');
|
|
233
|
+
td('setOnly', {set: function(val) { this.__ = val; }});
|
|
234
|
+
obj.setOnly = 'SETTER';
|
|
235
|
+
t.is(obj.__, 'SETTER', 'def(..., {set: setter}) → setter worked');
|
|
236
|
+
t.is(obj.setOnly, undefined, ' ^ get is undefined');
|
|
237
|
+
|
|
238
|
+
td('foobar', {value: 'FOO BAR'});
|
|
239
|
+
t.is(obj.foobar, 'FOO BAR', 'def(..., {value})');
|
|
240
|
+
|
|
241
|
+
let anObj = {value: 'BAR FOO'};
|
|
242
|
+
td('barfoo', anObj, false);
|
|
243
|
+
t.is(obj.barfoo, anObj, 'def(..., descriptor, false) → assigned object as value');
|
|
170
244
|
|
|
171
|
-
|
|
245
|
+
td('barfoo2', anObj);
|
|
246
|
+
t.is(anObj.configurable, true, 'def(..., descriptor) → descriptor is a reference');
|
|
247
|
+
|
|
248
|
+
anObj = {value: 'new test'};
|
|
249
|
+
td('barfoo3', anObj, true);
|
|
250
|
+
|
|
251
|
+
t.is(anObj.configurable, undefined, 'def(..., descriptor, true) → cloned descriptor');
|
|
252
|
+
t.is(obj.barfoo3, 'new test', ' ^ value was correct')
|
|
253
|
+
|
|
254
|
+
td(
|
|
255
|
+
{
|
|
256
|
+
hello: 'World',
|
|
257
|
+
goodbye: 'Universe',
|
|
258
|
+
});
|
|
172
259
|
|
|
260
|
+
t.ok((obj.hello === 'World' && obj.goodbye === 'Universe'), 'def(obj, {prop1: value1, prop2: value2})')
|
|
173
261
|
}
|
|
174
262
|
|
|
175
263
|
// TODO: isa() and needs()
|
|
264
|
+
// TODO: stringify()
|
|
176
265
|
|
|
177
266
|
// All done.
|
|
178
267
|
t.output();
|