@nejs/basic-extensions 2.21.0 → 2.22.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/.idea/markdown.xml +8 -0
- package/.idea/modules.xml +8 -0
- package/.idea/ne-basic-extensions.iml +8 -0
- package/.idea/vcs.xml +6 -0
- package/CODE_STYLE.md +393 -0
- package/CODING_PHILOSOPHY.md +36 -0
- package/DOCUMENTATION_GUIDELINES.md +221 -0
- package/README.md +78 -4
- package/dist/@nejs/basic-extensions.bundle.2.22.6.js +25 -0
- package/dist/@nejs/basic-extensions.bundle.2.22.6.js.map +7 -0
- package/dist/cjs/classes/index.cjs +11129 -0
- package/dist/cjs/classes/index.cjs.map +7 -0
- package/dist/cjs/index.cjs +15191 -0
- package/dist/cjs/index.cjs.map +7 -0
- package/dist/cjs/utils/index.cjs +3954 -0
- package/dist/cjs/utils/index.cjs.map +7 -0
- package/dist/esm/basic-extensions.mjs +25 -0
- package/dist/esm/basic-extensions.mjs.map +7 -0
- package/package.json +16 -22
- package/repl.bootstrap.js +4 -7
- package/repl.history +30 -30
- package/src/big.int.extension.js +171 -45
- package/src/classes/enumeration.js +466 -0
- package/src/classes/index.js +5 -1
- package/src/index.js +5 -1
- package/src/math.extension.js +73 -0
- package/src/number.extension.js +18 -0
- package/src/regular.expression.extensions.js +0 -35
- package/src/utils/toolkit.js +699 -516
- package/tests/arrayextensions.test.js +3 -3
- package/tests/index.test.js +3 -1
- package/tests/newClasses/asyncIterable.test.js +3 -3
- package/tests/newClasses/deferred.test.js +3 -3
- package/tests/newClasses/descriptor.test.js +3 -3
- package/tests/newClasses/iterable.test.js +3 -3
- package/tests/newClasses/refmap.test.js +3 -3
- package/tests/newClasses/refset.test.js +3 -3
- package/tests/objectextensions.test.js +3 -3
- package/tests/setextensions.test.js +3 -3
- package/tests/stringextensions.test.js +3 -2
- package/tests/utils/descriptor.utils.test.js +1 -1
- package/tests/utils/toolkit.test.js +429 -163
- package/.esdoc.json +0 -9
- package/.vscode/settings.json +0 -5
- package/bin/build +0 -27
- package/bin/clean +0 -14
- package/bin/esbuild +0 -91
- package/bin/fixup +0 -13
- package/bin/repl.basics.js +0 -584
- package/bin/repl.signature.js +0 -63
- package/bin/version +0 -100
- package/dist/@nejs/basic-extensions.bundle.2.21.0.js +0 -25
- package/dist/@nejs/basic-extensions.bundle.2.21.0.js.map +0 -7
- package/dist/cjs/array.extensions.d.ts +0 -39
- package/dist/cjs/array.extensions.js +0 -477
- package/dist/cjs/array.extensions.js.map +0 -1
- package/dist/cjs/big.int.extension.d.ts +0 -31
- package/dist/cjs/big.int.extension.js +0 -165
- package/dist/cjs/big.int.extension.js.map +0 -1
- package/dist/cjs/classes/asyncIterable.d.ts +0 -126
- package/dist/cjs/classes/asyncIterable.js +0 -209
- package/dist/cjs/classes/asyncIterable.js.map +0 -1
- package/dist/cjs/classes/deferred.d.ts +0 -146
- package/dist/cjs/classes/deferred.js +0 -291
- package/dist/cjs/classes/deferred.js.map +0 -1
- package/dist/cjs/classes/descriptor.d.ts +0 -334
- package/dist/cjs/classes/descriptor.js +0 -537
- package/dist/cjs/classes/descriptor.js.map +0 -1
- package/dist/cjs/classes/enum.d.ts +0 -50
- package/dist/cjs/classes/enum.js +0 -405
- package/dist/cjs/classes/enum.js.map +0 -1
- package/dist/cjs/classes/index.d.ts +0 -15
- package/dist/cjs/classes/index.js +0 -63
- package/dist/cjs/classes/index.js.map +0 -1
- package/dist/cjs/classes/introspector.d.ts +0 -20
- package/dist/cjs/classes/introspector.js +0 -130
- package/dist/cjs/classes/introspector.js.map +0 -1
- package/dist/cjs/classes/iterable.d.ts +0 -169
- package/dist/cjs/classes/iterable.js +0 -268
- package/dist/cjs/classes/iterable.js.map +0 -1
- package/dist/cjs/classes/param.parser.d.ts +0 -221
- package/dist/cjs/classes/param.parser.js +0 -242
- package/dist/cjs/classes/param.parser.js.map +0 -1
- package/dist/cjs/classes/pluggable.proxy.d.ts +0 -153
- package/dist/cjs/classes/pluggable.proxy.js +0 -444
- package/dist/cjs/classes/pluggable.proxy.js.map +0 -1
- package/dist/cjs/classes/property.d.ts +0 -79
- package/dist/cjs/classes/property.js +0 -284
- package/dist/cjs/classes/property.js.map +0 -1
- package/dist/cjs/classes/refmap.d.ts +0 -238
- package/dist/cjs/classes/refmap.js +0 -421
- package/dist/cjs/classes/refmap.js.map +0 -1
- package/dist/cjs/classes/refset.d.ts +0 -186
- package/dist/cjs/classes/refset.js +0 -370
- package/dist/cjs/classes/refset.js.map +0 -1
- package/dist/cjs/classes/symkeys.d.ts +0 -349
- package/dist/cjs/classes/symkeys.js +0 -510
- package/dist/cjs/classes/symkeys.js.map +0 -1
- package/dist/cjs/classes/type.d.ts +0 -56
- package/dist/cjs/classes/type.js +0 -405
- package/dist/cjs/classes/type.js.map +0 -1
- package/dist/cjs/function.extensions.d.ts +0 -12
- package/dist/cjs/function.extensions.js +0 -758
- package/dist/cjs/function.extensions.js.map +0 -1
- package/dist/cjs/global.this.d.ts +0 -2
- package/dist/cjs/global.this.js +0 -300
- package/dist/cjs/global.this.js.map +0 -1
- package/dist/cjs/index.d.ts +0 -31
- package/dist/cjs/index.js +0 -226
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/json.extensions.d.ts +0 -2
- package/dist/cjs/json.extensions.js +0 -109
- package/dist/cjs/json.extensions.js.map +0 -1
- package/dist/cjs/map.extensions.d.ts +0 -3
- package/dist/cjs/map.extensions.js +0 -143
- package/dist/cjs/map.extensions.js.map +0 -1
- package/dist/cjs/number.extension.d.ts +0 -44
- package/dist/cjs/number.extension.js +0 -261
- package/dist/cjs/number.extension.js.map +0 -1
- package/dist/cjs/object.extensions.d.ts +0 -33
- package/dist/cjs/object.extensions.js +0 -1091
- package/dist/cjs/object.extensions.js.map +0 -1
- package/dist/cjs/package.json +0 -3
- package/dist/cjs/proxy.extensions.d.ts +0 -2
- package/dist/cjs/proxy.extensions.js +0 -207
- package/dist/cjs/proxy.extensions.js.map +0 -1
- package/dist/cjs/reflect.extensions.d.ts +0 -14
- package/dist/cjs/reflect.extensions.js +0 -316
- package/dist/cjs/reflect.extensions.js.map +0 -1
- package/dist/cjs/regular.expression.extensions.d.ts +0 -2
- package/dist/cjs/regular.expression.extensions.js +0 -423
- package/dist/cjs/regular.expression.extensions.js.map +0 -1
- package/dist/cjs/set.extensions.d.ts +0 -40
- package/dist/cjs/set.extensions.js +0 -355
- package/dist/cjs/set.extensions.js.map +0 -1
- package/dist/cjs/string.extensions.d.ts +0 -23
- package/dist/cjs/string.extensions.js +0 -704
- package/dist/cjs/string.extensions.js.map +0 -1
- package/dist/cjs/symbol.extensions.d.ts +0 -11
- package/dist/cjs/symbol.extensions.js +0 -735
- package/dist/cjs/symbol.extensions.js.map +0 -1
- package/dist/cjs/utils/copy.object.d.ts +0 -408
- package/dist/cjs/utils/copy.object.js +0 -720
- package/dist/cjs/utils/copy.object.js.map +0 -1
- package/dist/cjs/utils/descriptor.utils.d.ts +0 -298
- package/dist/cjs/utils/descriptor.utils.js +0 -889
- package/dist/cjs/utils/descriptor.utils.js.map +0 -1
- package/dist/cjs/utils/index.d.ts +0 -75
- package/dist/cjs/utils/index.js +0 -61
- package/dist/cjs/utils/index.js.map +0 -1
- package/dist/cjs/utils/stdout.d.ts +0 -742
- package/dist/cjs/utils/stdout.js +0 -1042
- package/dist/cjs/utils/stdout.js.map +0 -1
- package/dist/cjs/utils/toolkit.d.ts +0 -1898
- package/dist/cjs/utils/toolkit.js +0 -1378
- package/dist/cjs/utils/toolkit.js.map +0 -1
- package/dist/cjs/weakref.extensions.d.ts +0 -2
- package/dist/cjs/weakref.extensions.js +0 -19
- package/dist/cjs/weakref.extensions.js.map +0 -1
- package/dist/mjs/array.extensions.d.ts +0 -39
- package/dist/mjs/array.extensions.js +0 -474
- package/dist/mjs/array.extensions.js.map +0 -1
- package/dist/mjs/big.int.extension.d.ts +0 -31
- package/dist/mjs/big.int.extension.js +0 -162
- package/dist/mjs/big.int.extension.js.map +0 -1
- package/dist/mjs/classes/asyncIterable.d.ts +0 -126
- package/dist/mjs/classes/asyncIterable.js +0 -204
- package/dist/mjs/classes/asyncIterable.js.map +0 -1
- package/dist/mjs/classes/deferred.d.ts +0 -146
- package/dist/mjs/classes/deferred.js +0 -287
- package/dist/mjs/classes/deferred.js.map +0 -1
- package/dist/mjs/classes/descriptor.d.ts +0 -334
- package/dist/mjs/classes/descriptor.js +0 -533
- package/dist/mjs/classes/descriptor.js.map +0 -1
- package/dist/mjs/classes/enum.d.ts +0 -50
- package/dist/mjs/classes/enum.js +0 -400
- package/dist/mjs/classes/enum.js.map +0 -1
- package/dist/mjs/classes/index.d.ts +0 -15
- package/dist/mjs/classes/index.js +0 -46
- package/dist/mjs/classes/index.js.map +0 -1
- package/dist/mjs/classes/introspector.d.ts +0 -20
- package/dist/mjs/classes/introspector.js +0 -126
- package/dist/mjs/classes/introspector.js.map +0 -1
- package/dist/mjs/classes/iterable.d.ts +0 -169
- package/dist/mjs/classes/iterable.js +0 -263
- package/dist/mjs/classes/iterable.js.map +0 -1
- package/dist/mjs/classes/param.parser.d.ts +0 -221
- package/dist/mjs/classes/param.parser.js +0 -238
- package/dist/mjs/classes/param.parser.js.map +0 -1
- package/dist/mjs/classes/pluggable.proxy.d.ts +0 -153
- package/dist/mjs/classes/pluggable.proxy.js +0 -438
- package/dist/mjs/classes/pluggable.proxy.js.map +0 -1
- package/dist/mjs/classes/property.d.ts +0 -79
- package/dist/mjs/classes/property.js +0 -280
- package/dist/mjs/classes/property.js.map +0 -1
- package/dist/mjs/classes/refmap.d.ts +0 -238
- package/dist/mjs/classes/refmap.js +0 -417
- package/dist/mjs/classes/refmap.js.map +0 -1
- package/dist/mjs/classes/refset.d.ts +0 -186
- package/dist/mjs/classes/refset.js +0 -366
- package/dist/mjs/classes/refset.js.map +0 -1
- package/dist/mjs/classes/symkeys.d.ts +0 -349
- package/dist/mjs/classes/symkeys.js +0 -506
- package/dist/mjs/classes/symkeys.js.map +0 -1
- package/dist/mjs/classes/type.d.ts +0 -56
- package/dist/mjs/classes/type.js +0 -401
- package/dist/mjs/classes/type.js.map +0 -1
- package/dist/mjs/function.extensions.d.ts +0 -12
- package/dist/mjs/function.extensions.js +0 -755
- package/dist/mjs/function.extensions.js.map +0 -1
- package/dist/mjs/global.this.d.ts +0 -2
- package/dist/mjs/global.this.js +0 -264
- package/dist/mjs/global.this.js.map +0 -1
- package/dist/mjs/index.d.ts +0 -31
- package/dist/mjs/index.js +0 -204
- package/dist/mjs/index.js.map +0 -1
- package/dist/mjs/json.extensions.d.ts +0 -2
- package/dist/mjs/json.extensions.js +0 -106
- package/dist/mjs/json.extensions.js.map +0 -1
- package/dist/mjs/map.extensions.d.ts +0 -3
- package/dist/mjs/map.extensions.js +0 -140
- package/dist/mjs/map.extensions.js.map +0 -1
- package/dist/mjs/number.extension.d.ts +0 -44
- package/dist/mjs/number.extension.js +0 -258
- package/dist/mjs/number.extension.js.map +0 -1
- package/dist/mjs/object.extensions.d.ts +0 -33
- package/dist/mjs/object.extensions.js +0 -1088
- package/dist/mjs/object.extensions.js.map +0 -1
- package/dist/mjs/package.json +0 -3
- package/dist/mjs/proxy.extensions.d.ts +0 -2
- package/dist/mjs/proxy.extensions.js +0 -204
- package/dist/mjs/proxy.extensions.js.map +0 -1
- package/dist/mjs/reflect.extensions.d.ts +0 -14
- package/dist/mjs/reflect.extensions.js +0 -313
- package/dist/mjs/reflect.extensions.js.map +0 -1
- package/dist/mjs/regular.expression.extensions.d.ts +0 -2
- package/dist/mjs/regular.expression.extensions.js +0 -420
- package/dist/mjs/regular.expression.extensions.js.map +0 -1
- package/dist/mjs/set.extensions.d.ts +0 -40
- package/dist/mjs/set.extensions.js +0 -352
- package/dist/mjs/set.extensions.js.map +0 -1
- package/dist/mjs/string.extensions.d.ts +0 -23
- package/dist/mjs/string.extensions.js +0 -701
- package/dist/mjs/string.extensions.js.map +0 -1
- package/dist/mjs/symbol.extensions.d.ts +0 -11
- package/dist/mjs/symbol.extensions.js +0 -732
- package/dist/mjs/symbol.extensions.js.map +0 -1
- package/dist/mjs/utils/copy.object.d.ts +0 -408
- package/dist/mjs/utils/copy.object.js +0 -702
- package/dist/mjs/utils/copy.object.js.map +0 -1
- package/dist/mjs/utils/descriptor.utils.d.ts +0 -298
- package/dist/mjs/utils/descriptor.utils.js +0 -875
- package/dist/mjs/utils/descriptor.utils.js.map +0 -1
- package/dist/mjs/utils/index.d.ts +0 -75
- package/dist/mjs/utils/index.js +0 -45
- package/dist/mjs/utils/index.js.map +0 -1
- package/dist/mjs/utils/stdout.d.ts +0 -742
- package/dist/mjs/utils/stdout.js +0 -1037
- package/dist/mjs/utils/stdout.js.map +0 -1
- package/dist/mjs/utils/toolkit.d.ts +0 -1898
- package/dist/mjs/utils/toolkit.js +0 -1373
- package/dist/mjs/utils/toolkit.js.map +0 -1
- package/dist/mjs/weakref.extensions.d.ts +0 -2
- package/dist/mjs/weakref.extensions.js +0 -16
- package/dist/mjs/weakref.extensions.js.map +0 -1
- package/jsdoc-config.json +0 -31
- package/tsconfig.base.json +0 -28
- package/tsconfig.cjs.json +0 -8
- package/tsconfig.esm.json +0 -8
- package/vitest.config.js +0 -7
|
@@ -1,875 +0,0 @@
|
|
|
1
|
-
/** @typedef {string|symbol|number} PropertyKey */
|
|
2
|
-
/**
|
|
3
|
-
* The `IsDescriptorStats` block contains all the information used to make
|
|
4
|
-
* a determination as to whether a given value is a an instance of the type
|
|
5
|
-
* {@link PropertyDescriptor} or at least compatible to used as one.
|
|
6
|
-
*
|
|
7
|
-
* @typedef {Object} IsDescriptorStats
|
|
8
|
-
* @property {number} confidence this is going to be a number from 0.0-1.0
|
|
9
|
-
* indicating the confidence ratio that the object supplied to `isDescriptor`
|
|
10
|
-
* is actually a valid `PropertyDescriptor` object. If the number is greater
|
|
11
|
-
* than 0 but less than 1.0, it likely indicates that the object can be used
|
|
12
|
-
* as a `PropertyDescriptor` but one or more factors gives it less than 100%
|
|
13
|
-
* confidence that being such is the objects intended purpose (e.g. it could
|
|
14
|
-
* be that there are more properties than a descriptor might have or that
|
|
15
|
-
* it is missing crucial properties such as `value`, `get` or `set`)
|
|
16
|
-
* @property {boolean} isAccessor true if the object is functional as an
|
|
17
|
-
* accessor descriptor; false otherwise
|
|
18
|
-
* @property {boolean} isData true if the object is functional as a data
|
|
19
|
-
* descriptor; false otherwise
|
|
20
|
-
* @property {boolean} isValid true if the object is technically a valid
|
|
21
|
-
* `PropertyDescriptor` object or compatible as one.
|
|
22
|
-
* @property {boolean} hasBaseDescriptorKeys true if the object has either
|
|
23
|
-
* `configurable` or `enumerable` property keys and both are `undefined` or
|
|
24
|
-
* of type `boolean`.
|
|
25
|
-
* @property {boolean} hasAccessorKeys true if the object has either `get`
|
|
26
|
-
* or `set` property keys and both are either `undefined` or of type
|
|
27
|
-
* `function`
|
|
28
|
-
* @property {boolean} hasDataKeys true if the object has either `value` or
|
|
29
|
-
* `writable` property keys and if `writable` is present, then it is of type
|
|
30
|
-
* `boolean`
|
|
31
|
-
*/
|
|
32
|
-
/**
|
|
33
|
-
* The response from a call to {@link DescriptorUtils.isDescriptor} can
|
|
34
|
-
* be either a {@link boolean} or a {@link IsDescriptorStats} object.
|
|
35
|
-
*
|
|
36
|
-
* @typedef {IsDescriptorStats | boolean} IsDescriptorResponse
|
|
37
|
-
*/
|
|
38
|
-
/**
|
|
39
|
-
* A set of utility functions work with {@link PropertyDescriptor} objects.
|
|
40
|
-
* The creation of property descriptors can be large in boiler plate so
|
|
41
|
-
* these tools can reduce the boiler plate and increase readability.
|
|
42
|
-
*
|
|
43
|
-
* @name DescriptorUtils
|
|
44
|
-
* @typedef {DescriptorUtils}
|
|
45
|
-
*/
|
|
46
|
-
export const DescriptorUtils = {
|
|
47
|
-
/**
|
|
48
|
-
* Creates an accessor descriptor object
|
|
49
|
-
*
|
|
50
|
-
* This function has multiple possible overloads
|
|
51
|
-
*
|
|
52
|
-
* ```markdown
|
|
53
|
-
* _**zeroFn** is a function that takes no parameters_
|
|
54
|
-
* _**oneFn** is a function that takes a single parameter_
|
|
55
|
-
* _**oneOrNone** is a either a function that takes a single parameter or nullish_
|
|
56
|
-
* _**nonFn** is any value that is not a function_
|
|
57
|
-
* _**nullish** is either null or undefined_
|
|
58
|
-
* _**...** means configurable?, enumerable?, storage?, key? liaison? as
|
|
59
|
-
* subsequent following parameters in that order_
|
|
60
|
-
*
|
|
61
|
-
* **accessor()**
|
|
62
|
-
* creates a storage backed accessor that is both read and write.
|
|
63
|
-
* The storage object will be a provided empty object with the key
|
|
64
|
-
* being 'value'. Configurable and enumerable flags will be set to
|
|
65
|
-
* `true`.
|
|
66
|
-
*
|
|
67
|
-
* **accessor(options)**
|
|
68
|
-
* this single argument variant of accessor() consists of a single
|
|
69
|
-
* options object. If neither `get` nor `set` are provided, a
|
|
70
|
-
* storage backed read-write accessor with undefined as the initial
|
|
71
|
-
* value will be constructed.
|
|
72
|
-
*
|
|
73
|
-
* **accessor(nonFn)**
|
|
74
|
-
* **accessor(any, true, options?)**
|
|
75
|
-
* **accessor(any, true, ...)**
|
|
76
|
-
* supplying only a non-function only parameter or any value and the
|
|
77
|
-
* value `true` as the second parameter, you will get a read-write
|
|
78
|
-
* accessor stored in the default or specified storage. The resultant
|
|
79
|
-
* initial value will be whatever is provided as the first parameter.
|
|
80
|
-
* See options to customize `configurable`, `enumerable`, `storage`,
|
|
81
|
-
* `key` and the `liaison` factory function.
|
|
82
|
-
*
|
|
83
|
-
* **accessor(any, false, options?)**
|
|
84
|
-
* **accessor(any, false, ...)**
|
|
85
|
-
* supplying only a non-function only parameter or any value and the
|
|
86
|
-
* value `false` as the second parameter, you will get a read-only
|
|
87
|
-
* getter stored in the default or specified storage. The resultant
|
|
88
|
-
* value will be whatever is provided as the first parameter.
|
|
89
|
-
* See options to customize `configurable`, `enumerable`, `storage`,
|
|
90
|
-
* `key` and the `liaison` factory function.
|
|
91
|
-
*
|
|
92
|
-
* **accessor(zeroFn)**
|
|
93
|
-
* **accessor(zeroFn, nullish, options?)**
|
|
94
|
-
* **accessor(zeroFn, nullish, ...)**
|
|
95
|
-
* creates a generic read-only accessor with the first no-argument
|
|
96
|
-
* function parameter being the getter and either null or undefined
|
|
97
|
-
* for the setter. Either an options object or the manually ordered
|
|
98
|
-
* parameters can optionally follow if a nullish value for setter
|
|
99
|
-
* is provided.
|
|
100
|
-
*
|
|
101
|
-
* **accessor(zeroFn, oneOrNone, options?)**
|
|
102
|
-
* **accessor(zeroFn, oneOrNone, ...)**
|
|
103
|
-
* creates a generic read-write accessor with the first no-argument
|
|
104
|
-
* function parameter being the getter and the second single-argument
|
|
105
|
-
* function parameter being the setter. Either an options object or
|
|
106
|
-
* the manually ordered parameters can optionally follow.
|
|
107
|
-
*
|
|
108
|
-
* **accessor(oneFn, oneFn, options?)**
|
|
109
|
-
* **accessor(oneFn, oneFn, ...)**
|
|
110
|
-
* this special variant of the accessor() invocation, allows a single
|
|
111
|
-
* argument getter and setter factory to be supplied. These will
|
|
112
|
-
* automatically be invoked with the specified or default storage
|
|
113
|
-
* object. The result of the getter factory should be a no argument
|
|
114
|
-
* function. And the result of the setter factory should be a single
|
|
115
|
-
* argument function. The options for `liaison` and `key` will be
|
|
116
|
-
* ignored and should be handled specifically in the factory
|
|
117
|
-
* functions to suit your own use case.
|
|
118
|
-
* ```
|
|
119
|
-
*
|
|
120
|
-
* Options are an object oriented way of supplying the alternate
|
|
121
|
-
* flags to the data descriptor. They are
|
|
122
|
-
*
|
|
123
|
-
* • `get` - only referenced when an options object is the only parameter
|
|
124
|
-
* • `set` - only referenced when an options object is the only parameter
|
|
125
|
-
* • `configurable` - if true, the descriptor of the object that this
|
|
126
|
-
* accessor descriptor represents can be redefined at later time by
|
|
127
|
-
* subsequent calls to {@link Object.defineProperty} or
|
|
128
|
-
* {@link Object.defineProperties}
|
|
129
|
-
* • `enumerable` - if true, enumeration over the object this
|
|
130
|
-
* descriptor is applied to, will show the property
|
|
131
|
-
* represented by this descriptor. See the associated MDN
|
|
132
|
-
* page regarding this {@link PropertyDescriptor} if you
|
|
133
|
-
* want to know more.
|
|
134
|
-
* • `storage` - an object, usually {@link Object} or {@link Map} or
|
|
135
|
-
* nullish if unused
|
|
136
|
-
* • `key` - a {@link PropertyKey} of your choosing or the default
|
|
137
|
-
* string `"value"`
|
|
138
|
-
* • `bind` - true if you wish to have the `storage` object bound as
|
|
139
|
-
* the `thisObj` for both the `get` and `set` functions when
|
|
140
|
-
* storage is used. **note* this will not work if you supply a
|
|
141
|
-
* big arrow function for the accessor function in question. This
|
|
142
|
-
* defaults to `false`.
|
|
143
|
-
* • `liaison` - an optional factory function that must return an
|
|
144
|
-
* object with two properties. The first is a `get()` function that
|
|
145
|
-
* returns a value and the second is a `set(value)` function that
|
|
146
|
-
* stores a value. The factory function receives `storage` and
|
|
147
|
-
* `key`, in that order. The default uses {@link Map.get} and
|
|
148
|
-
* {@link Map.set} if the storage is an instance of {@link Map}.
|
|
149
|
-
* Otherwise, the typical `object[key]` format is used if the
|
|
150
|
-
* storage object is an instanceof {@link Object}
|
|
151
|
-
*
|
|
152
|
-
* @param {(object|any)?} value the JavaScript value representing
|
|
153
|
-
* this descriptor's value or an options object if it is the
|
|
154
|
-
* only parameter.
|
|
155
|
-
* @param {(object|boolean)?} optionsOrConfigurable true or false if
|
|
156
|
-
* you wish the `configurable` flag to be set. Optionally supply an
|
|
157
|
-
* object with one of the supported options to configure the run
|
|
158
|
-
* of the function.
|
|
159
|
-
* @param {boolean?} enumerable true or false if you wish to
|
|
160
|
-
* configure the `.enumerable` property of the descriptor
|
|
161
|
-
* @param {object?} storage an object upon which data storage should
|
|
162
|
-
* be written to and read from. Defaults to an empty {@link Object}
|
|
163
|
-
* when storage is needed and not supplied via this parameter or
|
|
164
|
-
* an options object.
|
|
165
|
-
* @param {PropertyKey?} key the key used to store content on the
|
|
166
|
-
* storage object.
|
|
167
|
-
* @param {(object, PropertyKey) => { get: ()=>any, set: (v)=>void}} liaison
|
|
168
|
-
* an optional function that, given a storage object and property key,
|
|
169
|
-
* returns an object with a no argument `get()` function that returns
|
|
170
|
-
* the value on the storage object with a given key and a single argument
|
|
171
|
-
* `set(value)` function that stores a new value using the property key
|
|
172
|
-
* on the supplied storage object. This exists because access to a
|
|
173
|
-
* {@link Map} and {@link Object} values are handled differently. If you
|
|
174
|
-
* need support for some other class than `Map` or `Object` then you
|
|
175
|
-
* should provide a liaison function to define access.
|
|
176
|
-
*
|
|
177
|
-
* @returns {PropertyDescriptor}
|
|
178
|
-
*
|
|
179
|
-
* @see {@link PropertyDescriptor}
|
|
180
|
-
* @note More info on this can be found at the
|
|
181
|
-
* [MDN Object.defineProperty/ies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
|
|
182
|
-
* page
|
|
183
|
-
*
|
|
184
|
-
* @type {Function & { keys: string[] }}
|
|
185
|
-
*/
|
|
186
|
-
get accessor() {
|
|
187
|
-
function accessor(get, set, optionsOrConfigurable = true, enumerable = true, storage, key = 'value', liaison) {
|
|
188
|
-
const count = arguments.length;
|
|
189
|
-
const storageKeys = ['storage', 'key', 'liaison', 'initial', 'bind'];
|
|
190
|
-
const optionKeys = [
|
|
191
|
-
// accessor functions
|
|
192
|
-
'get', 'set',
|
|
193
|
-
// descriptor flags
|
|
194
|
-
'configurable', 'enumerable',
|
|
195
|
-
// storage configuration keys
|
|
196
|
-
...storageKeys
|
|
197
|
-
];
|
|
198
|
-
const has = (object, key) => isObject(object) && Reflect.has(object, key);
|
|
199
|
-
const isOpts = object => optionKeys.some(key => has(object, key));
|
|
200
|
-
let configurable = !!optionsOrConfigurable;
|
|
201
|
-
let initial = undefined;
|
|
202
|
-
let bind = false;
|
|
203
|
-
let options = {};
|
|
204
|
-
if (count === 1 && isObject(get) && hasSome(get, ...optionKeys)) {
|
|
205
|
-
options = { ...get };
|
|
206
|
-
({ get, set } = get);
|
|
207
|
-
}
|
|
208
|
-
if (isObject(optionsOrConfigurable) || isObject(set)) {
|
|
209
|
-
options = isObject(set) && count === 2
|
|
210
|
-
? { ...set }
|
|
211
|
-
: { ...optionsOrConfigurable };
|
|
212
|
-
({ configurable, enumerable, storage, key, bind, initial } = options);
|
|
213
|
-
}
|
|
214
|
-
liaison = options?.liaison ?? liaison ?? ((storage, key) => ({
|
|
215
|
-
get() {
|
|
216
|
-
if (storage instanceof Map)
|
|
217
|
-
return storage.get(key);
|
|
218
|
-
else if (isObject(storage))
|
|
219
|
-
return storage[key];
|
|
220
|
-
},
|
|
221
|
-
set(value) {
|
|
222
|
-
if (storage instanceof Map)
|
|
223
|
-
storage.set(key, value);
|
|
224
|
-
else if (isObject(storage))
|
|
225
|
-
storage[key] = value;
|
|
226
|
-
}
|
|
227
|
-
}));
|
|
228
|
-
configurable = configurable ?? true;
|
|
229
|
-
enumerable = enumerable ?? true;
|
|
230
|
-
key = key ?? 'value';
|
|
231
|
-
bind = bind ?? false;
|
|
232
|
-
const nullish = (value) => value === null || value === undefined;
|
|
233
|
-
const nonFn = (value) => !nullish(value) && typeof value !== 'function';
|
|
234
|
-
const yesFn = (value) => typeof value === 'function';
|
|
235
|
-
const zeroFn = (value) => (yesFn(value) && value.length === 0);
|
|
236
|
-
const oneFn = (value) => (yesFn(value) && value.length === 1);
|
|
237
|
-
const isTrue = (value) => value === true;
|
|
238
|
-
const isFalse = (value) => value === false;
|
|
239
|
-
const addRefs = (fn, value) => Object.defineProperties(fn, {
|
|
240
|
-
storage: { value, configurable: true, enumerable: false },
|
|
241
|
-
key: { value: key, configurable: true, enumerable: false },
|
|
242
|
-
});
|
|
243
|
-
if (count === 0 || (!get && !set)) {
|
|
244
|
-
storage = { [key]: initial };
|
|
245
|
-
const _ = liaison(storage, key);
|
|
246
|
-
get = addRefs(function () { return _.get(); }, storage);
|
|
247
|
-
set = addRefs(function (value) { _.set(value); }, storage);
|
|
248
|
-
return { get, set, configurable, enumerable };
|
|
249
|
-
}
|
|
250
|
-
if (count === 1 && oneFn(get)) {
|
|
251
|
-
set = false;
|
|
252
|
-
}
|
|
253
|
-
if ((count === 1 && nonFn(get)) || (isTrue(set) || isFalse(set))) {
|
|
254
|
-
const skipSet = isFalse(set);
|
|
255
|
-
if (!storage || !(storage instanceof Map) || !isObject(storage)) {
|
|
256
|
-
storage = {};
|
|
257
|
-
}
|
|
258
|
-
const _ = liaison(storage, key);
|
|
259
|
-
_.set(get);
|
|
260
|
-
let _get = function () { return _.get(); };
|
|
261
|
-
let _set = function (value) { _.set(value); };
|
|
262
|
-
if (bind) {
|
|
263
|
-
_get = _get.bind(storage);
|
|
264
|
-
_set = _set.bind(storage);
|
|
265
|
-
}
|
|
266
|
-
get = addRefs(_get, storage);
|
|
267
|
-
set = addRefs(_set, storage);
|
|
268
|
-
if (skipSet) {
|
|
269
|
-
set = undefined;
|
|
270
|
-
}
|
|
271
|
-
return { get, set, configurable, enumerable };
|
|
272
|
-
}
|
|
273
|
-
if ((zeroFn(get) && !set) || (zeroFn(get) && oneFn(set))) {
|
|
274
|
-
const descriptor = { get, set, configurable, enumerable };
|
|
275
|
-
if (isObject(options) && Reflect.has(options, 'initial'))
|
|
276
|
-
descriptor.set(initial);
|
|
277
|
-
return descriptor;
|
|
278
|
-
}
|
|
279
|
-
if (oneFn(get) && oneFn(set)) {
|
|
280
|
-
storage = storage || {};
|
|
281
|
-
let _get = get(storage);
|
|
282
|
-
let _set = set(storage);
|
|
283
|
-
if (bind) {
|
|
284
|
-
_get = _get.bind(storage);
|
|
285
|
-
_set = _set.bind(storage);
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
get: addRefs(_get, storage),
|
|
289
|
-
set: addRefs(_set, storage),
|
|
290
|
-
configurable,
|
|
291
|
-
enumerable,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return { get, set, configurable, enumerable };
|
|
295
|
-
}
|
|
296
|
-
Object.defineProperty(accessor, 'keys', {
|
|
297
|
-
get() {
|
|
298
|
-
return Object.defineProperties(['get', 'set', 'configurable', 'enumerable'], {
|
|
299
|
-
from: {
|
|
300
|
-
value: function extractKeysFrom(object) {
|
|
301
|
-
const response = {
|
|
302
|
-
get: undefined,
|
|
303
|
-
set: undefined,
|
|
304
|
-
configurable: undefined,
|
|
305
|
-
enumerable: undefined,
|
|
306
|
-
};
|
|
307
|
-
if (!object || !(object instanceof Object))
|
|
308
|
-
return response;
|
|
309
|
-
for (const key of DescriptorUtils.accessor.keys) {
|
|
310
|
-
if (Reflect.has(object, key))
|
|
311
|
-
response[key] = object[key];
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
writable: false,
|
|
315
|
-
configurable: false,
|
|
316
|
-
enumerable: false
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
},
|
|
320
|
-
configurable: true,
|
|
321
|
-
enumerable: false,
|
|
322
|
-
});
|
|
323
|
-
return accessor;
|
|
324
|
-
},
|
|
325
|
-
/**
|
|
326
|
-
* Creates a data descriptor object
|
|
327
|
-
*
|
|
328
|
-
* This function has multiple possible overloads
|
|
329
|
-
*
|
|
330
|
-
* ```markdown
|
|
331
|
-
* **data()**
|
|
332
|
-
* creates a data descriptor with a value of `undefined` that
|
|
333
|
-
* is writable, configurable and enumerable.
|
|
334
|
-
*
|
|
335
|
-
* **data(options)**
|
|
336
|
-
* if the only parameter is an object and that object contains
|
|
337
|
-
* at least a `.value` property, this funtion will return a
|
|
338
|
-
* data descriptor with the associated values. This variant
|
|
339
|
-
* is useful if you want to extract the normal data descriptor
|
|
340
|
-
* properties: value, writable, configurable and/or enumerable
|
|
341
|
-
* from an object that has properties with these names, in
|
|
342
|
-
* addition to other properties or functions. Note that if you
|
|
343
|
-
* wish for the value of the descriptor to be an object that
|
|
344
|
-
* also contains a `.value` property, use `data({value: obj})`
|
|
345
|
-
* instead.
|
|
346
|
-
*
|
|
347
|
-
* **data(value)**
|
|
348
|
-
* **data(value, options?)**
|
|
349
|
-
* creates a data descriptor from the supplied `value`,
|
|
350
|
-
* optionally augmented by additional `options`. The defaults
|
|
351
|
-
* for this writable, configurable and enumerable values set
|
|
352
|
-
* to `true`
|
|
353
|
-
*
|
|
354
|
-
* **data(value, writable?, configurable?, enumerable?)**
|
|
355
|
-
* if writable, configurable or enumerable or true or false
|
|
356
|
-
* then this function creates a data descriptor with those
|
|
357
|
-
* flags and the supplied value (there's no real reason to
|
|
358
|
-
* invoke this function if you're supplying all four values)
|
|
359
|
-
* ```
|
|
360
|
-
*
|
|
361
|
-
* Options are an object oriented way of supplying the alternate
|
|
362
|
-
* flags to the data descriptor. They are
|
|
363
|
-
*
|
|
364
|
-
* • `value` - only referenced when an options object is the
|
|
365
|
-
* only parameter
|
|
366
|
-
* • `writable` - true if the value represented by this data
|
|
367
|
-
* descriptor can be reassigned a new value.
|
|
368
|
-
* • `configurable` - if true, the descriptor of the object
|
|
369
|
-
* that this data descriptor represents can be redefined at
|
|
370
|
-
* later time by subsequent calls to `Object.defineProperty`
|
|
371
|
-
* or `Object.defineProperties`. If `.configurable` is true
|
|
372
|
-
* this can be done even if `.writable` is set to false
|
|
373
|
-
* • `enumerable` - if true, enumeration over the object this
|
|
374
|
-
* descriptor is applied to, will show the property
|
|
375
|
-
* represented by this descriptor. See the associated MDN
|
|
376
|
-
* page regarding this `PropertyDescriptor` if you want to
|
|
377
|
-
* know more.
|
|
378
|
-
*
|
|
379
|
-
* @param {(object|any)?} value the JavaScript value representing
|
|
380
|
-
* this descriptor's value or an options object if it is the
|
|
381
|
-
* only parameter.
|
|
382
|
-
* @param {(object|boolean)?} optionsOrWritable true or false if
|
|
383
|
-
* you wish the writable flag to be set. Optionally supply an
|
|
384
|
-
* object with one of the supported options to configure the run
|
|
385
|
-
* of the function.
|
|
386
|
-
* @param {boolean?} configurable true or false if you wish to
|
|
387
|
-
* configure the `.configurable` property of the descriptor
|
|
388
|
-
* @param {boolean?} enumerable true or false if you wish to
|
|
389
|
-
* configure the `.enumerable` property of the descriptor
|
|
390
|
-
* @returns {PropertyDescriptor}
|
|
391
|
-
*
|
|
392
|
-
* @note More info on this can be found at the
|
|
393
|
-
* [MDN Object.defineProperty/ies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
|
|
394
|
-
* page
|
|
395
|
-
*
|
|
396
|
-
* @type {Function & { keys: string[] }}
|
|
397
|
-
*/
|
|
398
|
-
get data() {
|
|
399
|
-
function data(value, optionsOrWritable, configurable, enumerable) {
|
|
400
|
-
const count = arguments.length;
|
|
401
|
-
let valueIsDescriptor = false;
|
|
402
|
-
if (count === 0) {
|
|
403
|
-
return {
|
|
404
|
-
value: undefined,
|
|
405
|
-
writable: true,
|
|
406
|
-
configurable: true,
|
|
407
|
-
enumerable: true
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
if (count === 1) {
|
|
411
|
-
const stats = DescriptorUtils.isDescriptor(value, true);
|
|
412
|
-
if (stats.isValid && stats.isData) {
|
|
413
|
-
valueIsDescriptor = true;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
let writable = optionsOrWritable === undefined
|
|
417
|
-
? true
|
|
418
|
-
: !!optionsOrWritable;
|
|
419
|
-
let options = typeof optionsOrWritable === 'boolean'
|
|
420
|
-
? {}
|
|
421
|
-
: Object(optionsOrWritable);
|
|
422
|
-
configurable = configurable === undefined ? true : !!configurable;
|
|
423
|
-
enumerable = enumerable === undefined ? true : !!enumerable;
|
|
424
|
-
if (valueIsDescriptor && !(options?.allowDescriptorValue)) {
|
|
425
|
-
options = {
|
|
426
|
-
writable: value?.writable ?? true,
|
|
427
|
-
configurable: value?.configurable ?? true,
|
|
428
|
-
enumerable: value?.enumerable ?? true,
|
|
429
|
-
};
|
|
430
|
-
value = value?.value;
|
|
431
|
-
}
|
|
432
|
-
if (options) {
|
|
433
|
-
({ writable, configurable, enumerable } = {
|
|
434
|
-
...{ writable, configurable, enumerable },
|
|
435
|
-
...options
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
return { value, writable, configurable, enumerable };
|
|
439
|
-
}
|
|
440
|
-
Object.defineProperty(data, 'keys', {
|
|
441
|
-
value: Object.defineProperties(['value', 'writable', 'configurable', 'enumerable'], {
|
|
442
|
-
from: {
|
|
443
|
-
value: function extractKeysFrom(object) {
|
|
444
|
-
const response = {
|
|
445
|
-
value: undefined,
|
|
446
|
-
writable: undefined,
|
|
447
|
-
configurable: undefined,
|
|
448
|
-
enumerable: undefined,
|
|
449
|
-
};
|
|
450
|
-
if (!object || !(object instanceof Object))
|
|
451
|
-
return response;
|
|
452
|
-
for (const key of DescriptorUtils.data.keys) {
|
|
453
|
-
if (Reflect.has(object, key))
|
|
454
|
-
response[key] = object[key];
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
writable: false,
|
|
458
|
-
configurable: false,
|
|
459
|
-
enumerable: false,
|
|
460
|
-
}
|
|
461
|
-
}),
|
|
462
|
-
writable: false,
|
|
463
|
-
configurable: true,
|
|
464
|
-
enumerable: false
|
|
465
|
-
});
|
|
466
|
-
return data;
|
|
467
|
-
},
|
|
468
|
-
describe(object, key, value, detectDescriptorValues = true) {
|
|
469
|
-
const { isAccessor, isData, data } = DescriptorUtils;
|
|
470
|
-
if (!(object && object instanceof Object))
|
|
471
|
-
return undefined;
|
|
472
|
-
if (!(['string', 'number', 'symbol'].includes(typeof key)))
|
|
473
|
-
return undefined;
|
|
474
|
-
if (detectDescriptorValues && isAccessor(value) || isData(value)) {
|
|
475
|
-
return Object.defineProperty(object, key, value);
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
return Object.defineProperty(object, key, data(value));
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
describeMany(object, keyValues, detectDescriptorValues = true) {
|
|
482
|
-
const { isAccessor, isData, isDescriptor, data, describe } = DescriptorUtils;
|
|
483
|
-
const isKey = k => ['string', 'number', 'symbol'].includes(typeof k);
|
|
484
|
-
let map = undefined;
|
|
485
|
-
if (Array.isArray(keyValues)) {
|
|
486
|
-
map = new Map(keyValues.filter(keyValue => {
|
|
487
|
-
return typeof keyValue === 'function' && keyValue.length === 2;
|
|
488
|
-
}));
|
|
489
|
-
}
|
|
490
|
-
else if (keyValues instanceof Map) {
|
|
491
|
-
map = keyValues;
|
|
492
|
-
}
|
|
493
|
-
else if (keyValues instanceof Object) {
|
|
494
|
-
const descriptors = Object.getOwnPropertyDescriptors(keyValues);
|
|
495
|
-
map = new Object.entries(descriptors);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
return [];
|
|
499
|
-
}
|
|
500
|
-
for (const [key, value] of map) {
|
|
501
|
-
if (detectDescriptorValues) {
|
|
502
|
-
if (isDescriptor(key)) {
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
const accessorBase = { enumerable: true, configurable: true };
|
|
507
|
-
const dataBase = { writable: true, ...accessorBase };
|
|
508
|
-
const extractBase = descriptor => {
|
|
509
|
-
if (isAccessor(descriptor)) {
|
|
510
|
-
const { configurable, enumerable } = descriptor;
|
|
511
|
-
return { configurable, enumerable };
|
|
512
|
-
}
|
|
513
|
-
else if (isData(descriptor)) {
|
|
514
|
-
const { writable, configurable, enumerable } = descriptor;
|
|
515
|
-
return { writable, configurable, enumerable };
|
|
516
|
-
}
|
|
517
|
-
return undefined;
|
|
518
|
-
};
|
|
519
|
-
// convert all map entries to
|
|
520
|
-
// [baseDescriptor, {key: value, key: value, ...}]
|
|
521
|
-
// unless detectDescriptorValues == false in which case
|
|
522
|
-
// [dataBase, { key: value, key: value, etc... }]
|
|
523
|
-
// ... dropping all non-isKey(key) values
|
|
524
|
-
for (const [key, value] of map.entries()) {
|
|
525
|
-
const descriptor = (detectDescriptorValues && isDescriptor(value)
|
|
526
|
-
? value
|
|
527
|
-
: data(value, dataBase));
|
|
528
|
-
}
|
|
529
|
-
},
|
|
530
|
-
extract(fromObject, keysToExtract, defaultIfMissing = undefined, extractDescriptors = false) {
|
|
531
|
-
const { data } = DescriptorUtils;
|
|
532
|
-
const output = {};
|
|
533
|
-
if (!fromObject || typeof fromObject !== 'object')
|
|
534
|
-
return output;
|
|
535
|
-
if (!Array.isArray(keysToExtract))
|
|
536
|
-
keysToExtract = [keysToExtract];
|
|
537
|
-
for (const key of keysToExtract) {
|
|
538
|
-
let descriptor = Object.getOwnPropertyDescriptor(fromObject, key);
|
|
539
|
-
if (!descriptor)
|
|
540
|
-
descriptor = data(defaultIfMissing);
|
|
541
|
-
if (extractDescriptors)
|
|
542
|
-
descriptor.value = data(descriptor, { allowDescriptorValue: true });
|
|
543
|
-
Object.defineProperty(output, key, descriptor);
|
|
544
|
-
}
|
|
545
|
-
return output;
|
|
546
|
-
},
|
|
547
|
-
/**
|
|
548
|
-
* Determines if a given value is an accessor descriptor.
|
|
549
|
-
*
|
|
550
|
-
* An accessor descriptor is a property descriptor that defines
|
|
551
|
-
* getter and/or setter functions for a property. This function
|
|
552
|
-
* checks the validity of the descriptor and whether it qualifies
|
|
553
|
-
* as an accessor.
|
|
554
|
-
*
|
|
555
|
-
* @param {Object} value - The descriptor object to evaluate.
|
|
556
|
-
* @param {boolean} [strict=true] - If true, performs a strict
|
|
557
|
-
* validation of the descriptor.
|
|
558
|
-
* @returns {boolean} Returns true if the descriptor is valid and
|
|
559
|
-
* is an accessor descriptor, otherwise false.
|
|
560
|
-
*
|
|
561
|
-
* @example
|
|
562
|
-
* // Example usage:
|
|
563
|
-
* const descriptor = { get: () => 42, set: (val) => {} }
|
|
564
|
-
* const result = DescriptorUtils.isAccessor(descriptor)
|
|
565
|
-
* console.log(result) // Outputs: true
|
|
566
|
-
*/
|
|
567
|
-
isAccessor(value, strict = true) {
|
|
568
|
-
const stats = DescriptorUtils.isDescriptor(value, true, strict);
|
|
569
|
-
return stats.isValid && stats.isAccessor;
|
|
570
|
-
},
|
|
571
|
-
/**
|
|
572
|
-
* Checks if a given value is a data descriptor.
|
|
573
|
-
*
|
|
574
|
-
* A data descriptor is a property descriptor that defines a value
|
|
575
|
-
* and optionally a writable attribute for a property. This function
|
|
576
|
-
* evaluates the descriptor's validity and whether it qualifies as
|
|
577
|
-
* a data descriptor.
|
|
578
|
-
*
|
|
579
|
-
* @param {Object} value - The descriptor object to evaluate.
|
|
580
|
-
* @param {boolean} [strict=true] - If true, performs a strict
|
|
581
|
-
* validation of the descriptor.
|
|
582
|
-
* @returns {boolean} Returns true if the descriptor is valid and
|
|
583
|
-
* is a data descriptor, otherwise false.
|
|
584
|
-
*
|
|
585
|
-
* @example
|
|
586
|
-
* // Example usage:
|
|
587
|
-
* const descriptor = { value: 42, writable: true }
|
|
588
|
-
* const result = DescriptorUtils.isData(descriptor)
|
|
589
|
-
* console.log(result) // Outputs: true
|
|
590
|
-
*/
|
|
591
|
-
isData(value, strict = true) {
|
|
592
|
-
const stats = DescriptorUtils.isDescriptor(value, true, strict);
|
|
593
|
-
return stats.isValid && stats.isData;
|
|
594
|
-
},
|
|
595
|
-
/**
|
|
596
|
-
* A function that, given a value that might be a `PropertyDescriptor`,
|
|
597
|
-
* calculates a deterministic probability that the supplied value is
|
|
598
|
-
* an object that either is a `PropertyDescriptor` or that can function
|
|
599
|
-
* as one.
|
|
600
|
-
*
|
|
601
|
-
* @param {unknown} value a JavaScript value that might be a
|
|
602
|
-
* `PropertyDescriptor` type.
|
|
603
|
-
* @param {boolean?} returnStats if this value is true, instead of returning
|
|
604
|
-
* a determined boolean value indicating the supplied value might be a
|
|
605
|
-
* `PropertyDescriptor`, an object containing the determined flags and score
|
|
606
|
-
* the led to the determination instead is returned.
|
|
607
|
-
* @param {boolean?} strict if this value is `true`, which is the default,
|
|
608
|
-
* then the function will not allow descriptor compatible objects, rather it
|
|
609
|
-
* will only return true if the object has keys that belong in a descriptor
|
|
610
|
-
* and do not form an invalid combination.
|
|
611
|
-
* @returns {IsDescriptorResponse} if `returnStats` is `true`
|
|
612
|
-
* an object of type {@link IsDescriptorStats} is returned. This object
|
|
613
|
-
* will have a lot of {@link Boolean} flags pertaining to the `true`/`false`
|
|
614
|
-
* evaluation. If `returnStats` is `false`, then a boolean value denoting
|
|
615
|
-
* whether or not the value is a {@link PropertyDescriptor} is returned
|
|
616
|
-
* instead. This is effectively the same as the `isValid` parameter from the
|
|
617
|
-
* stats block.
|
|
618
|
-
*/
|
|
619
|
-
isDescriptor(value, returnStats = false, strict = true) {
|
|
620
|
-
const areBools = (...props) => props.flat().every(prop => boolTypes.includes(typeof value[prop]));
|
|
621
|
-
const areFuncs = (...props) => props.flat().every(prop => funcTypes.includes(typeof value[prop]));
|
|
622
|
-
const hasKeyFn = (property) => Reflect.has(value, property);
|
|
623
|
-
const isOfType = (type) => (element) => typeof element === type;
|
|
624
|
-
const baseProps = ['configurable', 'enumerable'];
|
|
625
|
-
const dataProps = ['value', 'writable'];
|
|
626
|
-
const accessorProps = ['get', 'set'];
|
|
627
|
-
const anyDescProps = [...baseProps, ...dataProps, ...accessorProps];
|
|
628
|
-
const boolTypes = ['undefined', 'boolean'];
|
|
629
|
-
const funcTypes = ['undefined', 'function'];
|
|
630
|
-
const stats = {
|
|
631
|
-
confidence: 0,
|
|
632
|
-
hasAccessorKeys: false,
|
|
633
|
-
hasBaseDescriptorKeys: false,
|
|
634
|
-
hasDataKeys: false,
|
|
635
|
-
isAccessor: false,
|
|
636
|
-
isData: false,
|
|
637
|
-
isValid: false,
|
|
638
|
-
isBase: false,
|
|
639
|
-
};
|
|
640
|
-
if (!value || typeof value !== 'object' || !(value instanceof Object))
|
|
641
|
-
return returnStats ? stats : false;
|
|
642
|
-
let score = 0;
|
|
643
|
-
if (value && typeof value === 'object') {
|
|
644
|
-
const objKeys = Reflect.ownKeys(value);
|
|
645
|
-
const nonDescKeys = objKeys.filter(k => !(anyDescProps.includes(k)));
|
|
646
|
-
if (strict && nonDescKeys.length)
|
|
647
|
-
return false;
|
|
648
|
-
if (objKeys.length <= 4)
|
|
649
|
-
score++;
|
|
650
|
-
stats.hasAccessorKeys =
|
|
651
|
-
accessorProps.some(hasKeyFn) && areFuncs(accessorProps);
|
|
652
|
-
stats.hasDataKeys =
|
|
653
|
-
dataProps.some(hasKeyFn) && areBools('writable');
|
|
654
|
-
stats.hasBaseDescriptorKeys =
|
|
655
|
-
baseProps.some(hasKeyFn) && areBools(baseProps);
|
|
656
|
-
if (stats.hasBaseDescriptorKeys)
|
|
657
|
-
score++;
|
|
658
|
-
if (stats.hasAccessorKeys || stats.hasDataKeys)
|
|
659
|
-
score++;
|
|
660
|
-
if (score > 0)
|
|
661
|
-
stats.isValid = true;
|
|
662
|
-
if (score > 0 && stats.hasAccessorKeys)
|
|
663
|
-
stats.isAccessor = true;
|
|
664
|
-
if (score > 0 && stats.hasDataKeys)
|
|
665
|
-
stats.isData = true;
|
|
666
|
-
if (stats.isValid && !(['get', 'set', 'value'].some(hasKeyFn)))
|
|
667
|
-
stats.isBase = true;
|
|
668
|
-
if (stats.isValid && stats.isData && Reflect.has(value, 'value'))
|
|
669
|
-
score++;
|
|
670
|
-
else if (stats.isValid && stats.isAccessor) {
|
|
671
|
-
if ([value?.get, value?.set].some(isOfType('function')))
|
|
672
|
-
score++;
|
|
673
|
-
}
|
|
674
|
-
if (stats.hasAccessorKeys && stats.hasDataKeys) {
|
|
675
|
-
score = 0;
|
|
676
|
-
stats.isValid = false;
|
|
677
|
-
}
|
|
678
|
-
stats.confidence = parseFloat(score / 4.0);
|
|
679
|
-
}
|
|
680
|
-
if (returnStats)
|
|
681
|
-
return stats;
|
|
682
|
-
return score >= 0.0
|
|
683
|
-
? true
|
|
684
|
-
: false;
|
|
685
|
-
},
|
|
686
|
-
/**
|
|
687
|
-
* Redefines a property on an object with new descriptors and options.
|
|
688
|
-
* This function allows renaming, aliasing, and redefining property
|
|
689
|
-
* descriptors such as configurable, enumerable, writable, get, and set.
|
|
690
|
-
*
|
|
691
|
-
* @param {Object} object - The target object whose property is to be
|
|
692
|
-
* redefined.
|
|
693
|
-
* @param {string|symbol} key - The key of the property to redefine.
|
|
694
|
-
* @param {Object} as - An object containing new property descriptors.
|
|
695
|
-
* @param {Object} [options] - Optional settings for renaming and aliasing.
|
|
696
|
-
* @param {string|symbol} [options.rename] - New key name for the property.
|
|
697
|
-
* @param {Array<string|symbol>} [options.alsoAs] - Additional aliases for
|
|
698
|
-
* the property.
|
|
699
|
-
* @param {Object} [options.moveTo] optionally move the descriptor from this
|
|
700
|
-
* object to another.
|
|
701
|
-
* @returns {any} the result of `object[key]` in its final state
|
|
702
|
-
*
|
|
703
|
-
* @example
|
|
704
|
-
* const obj = { a: 1 }
|
|
705
|
-
* redescribe(obj, 'a', { writable: false }, { rename: 'b', alsoAs: ['c'] })
|
|
706
|
-
* console.log(obj.b) // Outputs: 1
|
|
707
|
-
* console.log(obj.c) // Outputs: 1
|
|
708
|
-
*/
|
|
709
|
-
redescribe(object, key, as, options) {
|
|
710
|
-
const { isAccessor, isData } = DescriptorUtils;
|
|
711
|
-
const ifThen = (condition, fn, ...args) => condition && fn(...args);
|
|
712
|
-
const isBool = value => typeof value === 'boolean' || value instanceof Boolean;
|
|
713
|
-
const isFunction = value => typeof value === 'function';
|
|
714
|
-
const isObject = value => value && value instanceof Object;
|
|
715
|
-
const isDefined = (value, key) => isObject(value) && Reflect.has(value, key);
|
|
716
|
-
const isObjectKey = v => ['string', 'number', 'symbol'].includes(typeof v);
|
|
717
|
-
const define = (key, values) => Object.defineProperty(object, key, values);
|
|
718
|
-
const assign = (object, ...values) => Object.assign(object, ...values);
|
|
719
|
-
const isAnObject = isObject(object);
|
|
720
|
-
let asIsObject = isObject(as);
|
|
721
|
-
const descriptor = isAnObject && Object.getOwnPropertyDescriptor(object, key);
|
|
722
|
-
const aliases = [];
|
|
723
|
-
if (descriptor && !asIsObject) {
|
|
724
|
-
asIsObject = true;
|
|
725
|
-
as = {};
|
|
726
|
-
}
|
|
727
|
-
if (isObject(options)) {
|
|
728
|
-
if (isDefined(options, 'rename')) {
|
|
729
|
-
const successfulDelete = delete object[key];
|
|
730
|
-
if (successfulDelete)
|
|
731
|
-
key = options.rename;
|
|
732
|
-
}
|
|
733
|
-
if (isDefined(options, 'alsoAs')) {
|
|
734
|
-
if (Array.isArray(options.alsoAs)) {
|
|
735
|
-
for (const value of options.alsoAs.filter(v => isObjectKey(v)))
|
|
736
|
-
aliases.push(value);
|
|
737
|
-
}
|
|
738
|
-
else if (isObjectKey(options.alsoAs)) {
|
|
739
|
-
aliases.push(options.alsoAs);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
if (isDefined(options, 'moveTo')) {
|
|
743
|
-
ifThen(isObject(options.moveTo), () => (object = options.moveTo));
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
if (isAnObject && asIsObject) {
|
|
747
|
-
let { configurable, enumerable, writable, get, set, value } = as;
|
|
748
|
-
if (isAccessor(descriptor)) {
|
|
749
|
-
ifThen(isFunction(get), () => assign(descriptor, { get }));
|
|
750
|
-
ifThen(isFunction(set), () => assign(descriptor, { set }));
|
|
751
|
-
}
|
|
752
|
-
ifThen(isBool(writable) && isData(descriptor), () => {
|
|
753
|
-
assign(descriptor, {
|
|
754
|
-
writable,
|
|
755
|
-
value: isDefined(as, 'value')
|
|
756
|
-
? value
|
|
757
|
-
: descriptor.value,
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
ifThen(isBool(configurable), () => assign(descriptor, { configurable }));
|
|
761
|
-
ifThen(isBool(enumerable), () => assign(descriptor, { enumerable }));
|
|
762
|
-
define(key, descriptor);
|
|
763
|
-
for (const alias of aliases) {
|
|
764
|
-
define(alias, descriptor);
|
|
765
|
-
}
|
|
766
|
-
return object[key];
|
|
767
|
-
}
|
|
768
|
-
},
|
|
769
|
-
/**
|
|
770
|
-
* Retrieves the keys associated with accessor descriptors.
|
|
771
|
-
*
|
|
772
|
-
* Accessor descriptors are property descriptors that define
|
|
773
|
-
* getter and/or setter functions for a property.
|
|
774
|
-
*
|
|
775
|
-
* @type {string[]}
|
|
776
|
-
*
|
|
777
|
-
* @example
|
|
778
|
-
* // Example usage:
|
|
779
|
-
* const keys = DescriptorUtils.kAccessorDescriptorKeys
|
|
780
|
-
* console.log(keys) // Output: ['get', 'set']
|
|
781
|
-
*/
|
|
782
|
-
get kAccessorDescriptorKeys() {
|
|
783
|
-
return ['get', 'set'];
|
|
784
|
-
},
|
|
785
|
-
/**
|
|
786
|
-
* Retrieves the keys associated with data descriptors.
|
|
787
|
-
*
|
|
788
|
-
* Data descriptors are property descriptors that define a value
|
|
789
|
-
* and optionally a writable attribute for a property.
|
|
790
|
-
*
|
|
791
|
-
* @type {string[]}
|
|
792
|
-
*
|
|
793
|
-
* @example
|
|
794
|
-
* // Example usage:
|
|
795
|
-
* const keys = DescriptorUtils.kDataDescriptorKeys
|
|
796
|
-
* console.log(keys) // Output: ['value', 'writable']
|
|
797
|
-
*/
|
|
798
|
-
get kDataDescriptorKeys() {
|
|
799
|
-
return ['value', 'writable'];
|
|
800
|
-
},
|
|
801
|
-
/**
|
|
802
|
-
* Retrieves the keys associated with shared descriptors.
|
|
803
|
-
*
|
|
804
|
-
* Shared descriptors are property descriptors that define
|
|
805
|
-
* common attributes for a property, such as whether the
|
|
806
|
-
* property is configurable or enumerable.
|
|
807
|
-
*
|
|
808
|
-
* @type {string[]}
|
|
809
|
-
*
|
|
810
|
-
* @example
|
|
811
|
-
* // Example usage:
|
|
812
|
-
* const keys = DescriptorUtils.kSharedDescriptorKeys
|
|
813
|
-
* console.log(keys) // Output: ['configurable', 'enumerable']
|
|
814
|
-
*/
|
|
815
|
-
get kSharedDescriptorKeys() {
|
|
816
|
-
return ['configurable', 'enumerable'];
|
|
817
|
-
},
|
|
818
|
-
/**
|
|
819
|
-
* Retrieves all descriptor keys, combining accessor, data, and shared
|
|
820
|
-
* descriptor keys.
|
|
821
|
-
*
|
|
822
|
-
* This getter method aggregates keys from accessor descriptors,
|
|
823
|
-
* data descriptors, and shared descriptors into a single array.
|
|
824
|
-
* This can be useful when you need to validate or inspect all
|
|
825
|
-
* possible descriptor keys.
|
|
826
|
-
*
|
|
827
|
-
* @type {string[]}
|
|
828
|
-
*
|
|
829
|
-
* @example
|
|
830
|
-
* // Example usage:
|
|
831
|
-
* const allKeys = DescriptorUtils.kDescriptorKeys
|
|
832
|
-
* console.log(allKeys)
|
|
833
|
-
* // Output: [
|
|
834
|
-
* // 'get', 'set', 'value', 'writable', 'configurable', 'enumerable'
|
|
835
|
-
* // ]
|
|
836
|
-
*/
|
|
837
|
-
get kDescriptorKeys() {
|
|
838
|
-
return [
|
|
839
|
-
...(this.kAccessorDescriptorKeys),
|
|
840
|
-
...(this.kDataDescriptorKeys),
|
|
841
|
-
...(this.kSharedDescriptorKeys),
|
|
842
|
-
];
|
|
843
|
-
}
|
|
844
|
-
};
|
|
845
|
-
// Destructure the functions individually...
|
|
846
|
-
const { accessor, data, describe, describeMany, extract, isDescriptor, isAccessor, isData, redescribe, } = DescriptorUtils;
|
|
847
|
-
// ...also destructure the constants individually....
|
|
848
|
-
const { kAccessorDescriptorKeys, kDataDescriptorKeys, kDescriptorKeys, kSharedDescriptorKeys } = DescriptorUtils;
|
|
849
|
-
// ... so they can also be individually exported.
|
|
850
|
-
export { accessor, data, describe, describeMany, extract, isAccessor, isData, isDescriptor, redescribe, kAccessorDescriptorKeys, kDataDescriptorKeys, kDescriptorKeys, kSharedDescriptorKeys };
|
|
851
|
-
// Provide default exports as well
|
|
852
|
-
export default {
|
|
853
|
-
DescriptorUtils,
|
|
854
|
-
accessor,
|
|
855
|
-
data,
|
|
856
|
-
describe,
|
|
857
|
-
describeMany,
|
|
858
|
-
extract,
|
|
859
|
-
isAccessor,
|
|
860
|
-
isData,
|
|
861
|
-
isDescriptor,
|
|
862
|
-
redescribe,
|
|
863
|
-
kAccessorDescriptorKeys,
|
|
864
|
-
kDataDescriptorKeys,
|
|
865
|
-
kDescriptorKeys,
|
|
866
|
-
kSharedDescriptorKeys
|
|
867
|
-
};
|
|
868
|
-
// ---- non-exported helper functions ----
|
|
869
|
-
function isObject(o) { return o && typeof o === 'object'; }
|
|
870
|
-
function hasSome(object, ...keys) { return hasQuantity('some', object, keys); }
|
|
871
|
-
function hasQuantity(quantityFn, object, keys) {
|
|
872
|
-
return isObject(object) && (keys.flat(Infinity)
|
|
873
|
-
.map(key => Reflect.has(object, key))[quantityFn](has => has));
|
|
874
|
-
}
|
|
875
|
-
//# sourceMappingURL=descriptor.utils.js.map
|