@nejs/basic-extensions 2.21.5 → 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/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 +26 -26
- package/src/classes/enumeration.js +466 -0
- package/src/classes/index.js +5 -1
- package/src/index.js +3 -1
- 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.5.js +0 -25
- package/dist/@nejs/basic-extensions.bundle.2.21.5.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 -273
- 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 -228
- 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/math.extension.d.ts +0 -14
- package/dist/cjs/math.extension.js +0 -71
- package/dist/cjs/math.extension.js.map +0 -1
- package/dist/cjs/number.extension.d.ts +0 -44
- package/dist/cjs/number.extension.js +0 -278
- 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 -270
- 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 -206
- 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/math.extension.d.ts +0 -14
- package/dist/mjs/math.extension.js +0 -68
- package/dist/mjs/math.extension.js.map +0 -1
- package/dist/mjs/number.extension.d.ts +0 -44
- package/dist/mjs/number.extension.js +0 -275
- 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
|
@@ -0,0 +1,3954 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/utils/index.js
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
COPropertyHandler: () => COPropertyHandler,
|
|
23
|
+
DescriptorUtils: () => DescriptorUtils,
|
|
24
|
+
FlexiblyHiddenHandler: () => FlexiblyHiddenHandler,
|
|
25
|
+
FlexiblyVisibleHandler: () => FlexiblyVisibleHandler,
|
|
26
|
+
ImmutablyHiddenHandler: () => ImmutablyHiddenHandler,
|
|
27
|
+
ImmutablyVisibleHandler: () => ImmutablyVisibleHandler,
|
|
28
|
+
MutablyHiddenHandler: () => MutablyHiddenHandler,
|
|
29
|
+
MutablyVisibleHandler: () => MutablyVisibleHandler,
|
|
30
|
+
SC: () => SC,
|
|
31
|
+
StdoutGlobalPatches: () => StdoutGlobalPatches,
|
|
32
|
+
StringConsole: () => StringConsole,
|
|
33
|
+
StringConsoleExtension: () => StringConsoleExtension,
|
|
34
|
+
VisibilityKeys: () => VisibilityKeys,
|
|
35
|
+
VisibilityScopeHandler: () => VisibilityScopeHandler,
|
|
36
|
+
accessor: () => accessor,
|
|
37
|
+
as: () => as,
|
|
38
|
+
captureStdout: () => captureStdout,
|
|
39
|
+
copyObject: () => copyObject,
|
|
40
|
+
createToolkit: () => createToolkit,
|
|
41
|
+
customCopyObject: () => customCopyObject,
|
|
42
|
+
data: () => data,
|
|
43
|
+
default: () => index_default,
|
|
44
|
+
describe: () => describe,
|
|
45
|
+
describeMany: () => describeMany,
|
|
46
|
+
extract: () => extract,
|
|
47
|
+
has: () => has,
|
|
48
|
+
is: () => is,
|
|
49
|
+
isAccessor: () => isAccessor,
|
|
50
|
+
isData: () => isData,
|
|
51
|
+
isDescriptor: () => isDescriptor,
|
|
52
|
+
kAccessorDescriptorKeys: () => kAccessorDescriptorKeys,
|
|
53
|
+
kDataDescriptorKeys: () => kDataDescriptorKeys,
|
|
54
|
+
kDescriptorKeys: () => kDescriptorKeys,
|
|
55
|
+
kSharedDescriptorKeys: () => kSharedDescriptorKeys,
|
|
56
|
+
kVisibilityKeys: () => kVisibilityKeys,
|
|
57
|
+
makeTransducer: () => makeTransducer,
|
|
58
|
+
redescribe: () => redescribe,
|
|
59
|
+
si: () => si,
|
|
60
|
+
transduceFrom: () => transduceFrom,
|
|
61
|
+
transduceFromCOHandler: () => transduceFromCOHandler,
|
|
62
|
+
tryIgnore: () => tryIgnore
|
|
63
|
+
});
|
|
64
|
+
module.exports = __toCommonJS(index_exports);
|
|
65
|
+
|
|
66
|
+
// src/utils/copy.object.js
|
|
67
|
+
function tryIgnore(code) {
|
|
68
|
+
try {
|
|
69
|
+
return code();
|
|
70
|
+
} catch (ignore) {
|
|
71
|
+
return void 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function transduceFrom(array, transform, into = {}) {
|
|
75
|
+
if (typeof transform !== "function") {
|
|
76
|
+
return into;
|
|
77
|
+
}
|
|
78
|
+
return array.reduce((accumulator, element) => {
|
|
79
|
+
const { key, value } = transform?.(element) ?? {};
|
|
80
|
+
if (key && value) {
|
|
81
|
+
accumulator[key] = value;
|
|
82
|
+
}
|
|
83
|
+
return accumulator;
|
|
84
|
+
}, into);
|
|
85
|
+
}
|
|
86
|
+
function transduceFromCOHandler(element) {
|
|
87
|
+
const result = {};
|
|
88
|
+
if (element instanceof COPropertyHandler) {
|
|
89
|
+
result.key = element.property;
|
|
90
|
+
result.value = element;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function makeTransducer(array, transform) {
|
|
95
|
+
return transduceFrom.bind(null, array, transform);
|
|
96
|
+
}
|
|
97
|
+
var COPropertyHandler = class _COPropertyHandler {
|
|
98
|
+
/**
|
|
99
|
+
* The name of the property this handler is responsible for.
|
|
100
|
+
* @type {string|undefined}
|
|
101
|
+
*/
|
|
102
|
+
property = void 0;
|
|
103
|
+
/**
|
|
104
|
+
* The property handler. When provided and invoked, it will receive
|
|
105
|
+
* a the property name of the value being handled, the current
|
|
106
|
+
* descriptor to transform, and the object into which values are
|
|
107
|
+
* currently being copied into.
|
|
108
|
+
*
|
|
109
|
+
* The result must be a COPropertyHandler response type, which can
|
|
110
|
+
* be made with {@link COPropertyHandler.makeResponse} and which
|
|
111
|
+
* can be validated with {@link COPropertyHandler.isResponse}.
|
|
112
|
+
*
|
|
113
|
+
* The handler should have the following parameters
|
|
114
|
+
* - {string} property - The name of the property being handled.
|
|
115
|
+
* - {Object} curDescriptor - The property descriptor to handle.
|
|
116
|
+
* - {Object} destination - The destination object into which
|
|
117
|
+
* properties are being copied.
|
|
118
|
+
*
|
|
119
|
+
* An should return
|
|
120
|
+
* - {Object} a `COPropertyHandler.Response` type object which
|
|
121
|
+
* can be made with {@link COPropertyHandler.makeResponse}.
|
|
122
|
+
*
|
|
123
|
+
* @type {function|undefined}
|
|
124
|
+
*/
|
|
125
|
+
handler = void 0;
|
|
126
|
+
/**
|
|
127
|
+
* Creates a new COPropertyHandler instance.
|
|
128
|
+
* @param {string} [property] - The name of the property to handle.
|
|
129
|
+
* @param {function} [handler] - The function to handle the property
|
|
130
|
+
* descriptor.
|
|
131
|
+
*/
|
|
132
|
+
constructor(property2, handler) {
|
|
133
|
+
Object.assign(this, { property: property2, handler });
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Handles a property descriptor using the registered handler function.
|
|
137
|
+
* @param {string} property - The name of the property being handled.
|
|
138
|
+
* @param {Object} descriptor - The property descriptor to handle.
|
|
139
|
+
* @returns {Object} The resulting property descriptor after handling.
|
|
140
|
+
*/
|
|
141
|
+
handle(property2, descriptor, destination) {
|
|
142
|
+
if (this.handler) {
|
|
143
|
+
return _COPropertyHandler.defaultHandle(
|
|
144
|
+
property2,
|
|
145
|
+
descriptor,
|
|
146
|
+
this.handler
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return descriptor;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The default property descriptor handler.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} property - The name of the property being handled.
|
|
155
|
+
* @param {Object} curDescriptor - The property descriptor to handle.
|
|
156
|
+
* @param {Object} destination - The destination object into which
|
|
157
|
+
* properties are being copied.
|
|
158
|
+
* @param {function} handler - The function to handle the property
|
|
159
|
+
* descriptor.
|
|
160
|
+
* @returns {Object} a `COPropertyHandler.Response` type object which
|
|
161
|
+
* can be made with {@link COPropertyHandler.makeResponse}.
|
|
162
|
+
*/
|
|
163
|
+
static defaultHandle(property2, curDescriptor, destination, handler) {
|
|
164
|
+
if (typeof handler === "function") {
|
|
165
|
+
try {
|
|
166
|
+
const {
|
|
167
|
+
descriptor,
|
|
168
|
+
flow
|
|
169
|
+
} = handler(property2, curDescriptor, destination);
|
|
170
|
+
return this.makeResponse(descriptor, flow);
|
|
171
|
+
} catch (ignore) {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return this.makeResponse(curDescriptor);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Creates a COPropertyHandler response object.
|
|
178
|
+
*
|
|
179
|
+
* @param {Object} descriptor - The property descriptor.
|
|
180
|
+
* @param {string} [flow=COPropertyHandler.kNoChange] - The flow control
|
|
181
|
+
* directive. Must be one of the values from
|
|
182
|
+
* {@link COPropertyHandler.flowTypes} if provided.
|
|
183
|
+
* @returns {COPropertyHandler.Response} The response object.
|
|
184
|
+
* @example
|
|
185
|
+
* COPropertyHandler.makeResponse({ value: 42, writable: false })
|
|
186
|
+
* // => {
|
|
187
|
+
* // newDescriptor: { value: 42, writable: false },
|
|
188
|
+
* // flow: 'nochange'
|
|
189
|
+
* // }
|
|
190
|
+
*/
|
|
191
|
+
static makeResponse(descriptor, flow) {
|
|
192
|
+
return {
|
|
193
|
+
newDescriptor: descriptor,
|
|
194
|
+
flow: flow ?? this.kNoChange,
|
|
195
|
+
get [Symbol.toStringTag]() {
|
|
196
|
+
return "COPropertyHandler.Response";
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Checks if a value is a valid COPropertyHandler response object.
|
|
202
|
+
* @param {*} value - The value to check.
|
|
203
|
+
* @returns {boolean} `true` if the value is a response object, `false`
|
|
204
|
+
* otherwise.
|
|
205
|
+
* @example
|
|
206
|
+
* COPropertyHandler.isResponse({
|
|
207
|
+
* newDescriptor: { value: 42 },
|
|
208
|
+
* flow: 'nochange'
|
|
209
|
+
* })
|
|
210
|
+
* // => true
|
|
211
|
+
*/
|
|
212
|
+
static isResponse(value) {
|
|
213
|
+
return value && typeof value === "object" && value[Symbol.toStringTag] === "COPropertyHandler.Response";
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The flow control directive indicating no change in flow.
|
|
217
|
+
* @type {string}
|
|
218
|
+
*/
|
|
219
|
+
static get kNoChange() {
|
|
220
|
+
return "nochange";
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The flow control directive indicating to continue the loop.
|
|
224
|
+
* @type {string}
|
|
225
|
+
*/
|
|
226
|
+
static get kContinue() {
|
|
227
|
+
return "continue";
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The flow control directive indicating to break the loop.
|
|
231
|
+
* @type {string}
|
|
232
|
+
*/
|
|
233
|
+
static get kBreak() {
|
|
234
|
+
return "break";
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* An array of all valid flow control directive values.
|
|
238
|
+
* @type {string[]}
|
|
239
|
+
*/
|
|
240
|
+
static get flowTypes() {
|
|
241
|
+
return [this.kNoChange, this.kContinue, this.kBreak];
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* An object mapping flow control directive values to their
|
|
245
|
+
* corresponding string representations.
|
|
246
|
+
* @type {Object.<string, string>}
|
|
247
|
+
*/
|
|
248
|
+
static get flowEnum() {
|
|
249
|
+
return {
|
|
250
|
+
[this.kNoChange]: this.kNoChange,
|
|
251
|
+
[this.kContinue]: this.kContinue,
|
|
252
|
+
[this.kBreak]: this.kBreak
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
function kVisibilityKeys() {
|
|
257
|
+
const keys = {
|
|
258
|
+
get mutablyHidden() {
|
|
259
|
+
return Symbol.for(JSON.stringify({
|
|
260
|
+
enumerable: false,
|
|
261
|
+
configurable: true
|
|
262
|
+
}));
|
|
263
|
+
},
|
|
264
|
+
get mutablyVisible() {
|
|
265
|
+
return Symbol.for(JSON.stringify({
|
|
266
|
+
enumerable: true,
|
|
267
|
+
configurable: true
|
|
268
|
+
}));
|
|
269
|
+
},
|
|
270
|
+
get immutablyHidden() {
|
|
271
|
+
return Symbol.for(JSON.stringify({
|
|
272
|
+
enumerable: false,
|
|
273
|
+
configurable: false
|
|
274
|
+
}));
|
|
275
|
+
},
|
|
276
|
+
get immutablyVisible() {
|
|
277
|
+
return Symbol.for(JSON.stringify({
|
|
278
|
+
enumerable: true,
|
|
279
|
+
configurable: false
|
|
280
|
+
}));
|
|
281
|
+
},
|
|
282
|
+
get flexiblyHidden() {
|
|
283
|
+
return Symbol.for(JSON.stringify({
|
|
284
|
+
enumerable: false,
|
|
285
|
+
configurable: false,
|
|
286
|
+
writable: true
|
|
287
|
+
}));
|
|
288
|
+
},
|
|
289
|
+
get flexiblyVisible() {
|
|
290
|
+
return Symbol.for(JSON.stringify({
|
|
291
|
+
enumerable: true,
|
|
292
|
+
configurable: false,
|
|
293
|
+
writable: true
|
|
294
|
+
}));
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const enumerated = {
|
|
298
|
+
mutablyHidden: keys.mutablyHidden,
|
|
299
|
+
mutablyVisible: keys.mutablyVisible,
|
|
300
|
+
immutablyHidden: keys.immutablyHidden,
|
|
301
|
+
immutablyVisible: keys.immutablyVisible,
|
|
302
|
+
flexiblyHidden: keys.flexiblyHidden,
|
|
303
|
+
flexiblyVisible: keys.flexiblyVisible
|
|
304
|
+
};
|
|
305
|
+
function* keyGenerator() {
|
|
306
|
+
for (const key of Object.keys(enumerated)) {
|
|
307
|
+
yield key;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function* symbolGenerator() {
|
|
311
|
+
for (const value of Object.values(enumerated)) {
|
|
312
|
+
yield value;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function* entryGenerator() {
|
|
316
|
+
for (const entry of Object.entries(enumerated)) {
|
|
317
|
+
yield entry;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function* descriptorGenertor() {
|
|
321
|
+
for (const [key, value] of entryGenerator()) {
|
|
322
|
+
yield [key, JSON.parse(value.description)];
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
Object.defineProperties(keys, {
|
|
326
|
+
enumeration: { get() {
|
|
327
|
+
return enumerated;
|
|
328
|
+
}, enumerable: false },
|
|
329
|
+
keys: { get() {
|
|
330
|
+
return keyGenerator();
|
|
331
|
+
}, enumerable: false },
|
|
332
|
+
symbols: { get() {
|
|
333
|
+
return symbolGenerator();
|
|
334
|
+
}, enumerable: false },
|
|
335
|
+
entries: { get() {
|
|
336
|
+
return entryGenerator();
|
|
337
|
+
}, enumerable: false },
|
|
338
|
+
descriptors: { get() {
|
|
339
|
+
return descriptorGenertor();
|
|
340
|
+
}, enumerable: false },
|
|
341
|
+
descriptorFor: {
|
|
342
|
+
value(symbol) {
|
|
343
|
+
try {
|
|
344
|
+
return JSON.parse(symbol.description);
|
|
345
|
+
} catch (ignored) {
|
|
346
|
+
}
|
|
347
|
+
return void 0;
|
|
348
|
+
},
|
|
349
|
+
enumerable: false
|
|
350
|
+
},
|
|
351
|
+
[Symbol.iterator]: { get() {
|
|
352
|
+
return symbolGenerator();
|
|
353
|
+
} }
|
|
354
|
+
});
|
|
355
|
+
return keys;
|
|
356
|
+
}
|
|
357
|
+
var VisibilityKeys = kVisibilityKeys();
|
|
358
|
+
var VisibilityScopeHandler = class extends COPropertyHandler {
|
|
359
|
+
overrides = void 0;
|
|
360
|
+
/**
|
|
361
|
+
* Creates a new VisibilityScopeHandler instance.
|
|
362
|
+
*
|
|
363
|
+
* @constructor
|
|
364
|
+
* @param {symbol} visibilityKey - The visibility key to use for handling
|
|
365
|
+
* property descriptors.
|
|
366
|
+
*/
|
|
367
|
+
constructor(visibilityKey) {
|
|
368
|
+
super(visibilityKey, (property2, descriptor, dest, source) => {
|
|
369
|
+
let data2 = descriptor?.value;
|
|
370
|
+
if (!descriptor || typeof descriptor.value !== "object") {
|
|
371
|
+
return COPropertyHandler.makeResponse(descriptor, "nochange");
|
|
372
|
+
}
|
|
373
|
+
if (!data2 && (descriptor?.get || descriptor?.set)) {
|
|
374
|
+
const newDescriptor = this.applyOverridesTo(descriptor);
|
|
375
|
+
return COPropertyHandler.makeResponse(newDescriptor, "nochange");
|
|
376
|
+
}
|
|
377
|
+
data2 = customCopyObject({ deep: false }, {}, data2 ?? {});
|
|
378
|
+
this.walkAndApply(data2);
|
|
379
|
+
descriptor.value = data2;
|
|
380
|
+
return COPropertyHandler.makeResponse(descriptor, "continue");
|
|
381
|
+
});
|
|
382
|
+
tryIgnore(() => this.overrides = JSON.parse(property.description));
|
|
383
|
+
}
|
|
384
|
+
applyOverridesTo(existingDescriptor, overwrite = false) {
|
|
385
|
+
const allowed = ["value", "get", "set", "writable", "configurable", "enumerable"];
|
|
386
|
+
const output = overwrite ? existingDescriptor : { ...existingDescriptor };
|
|
387
|
+
for (let [key, value] of Object.entries(this.overrides ?? {})) {
|
|
388
|
+
if (!~allowed.indexOf(key)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (!(["get", "set"].some((k) => k === key) && ["undefined", "function"].some((t) => typeof value === t))) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (!(["enumerable", "configurable", "writable"].some((k) => k === key) && typeof value !== "boolean")) {
|
|
395
|
+
value = !!value;
|
|
396
|
+
}
|
|
397
|
+
delete output[key];
|
|
398
|
+
output[key] = value;
|
|
399
|
+
}
|
|
400
|
+
return output;
|
|
401
|
+
}
|
|
402
|
+
walkAndApply(to) {
|
|
403
|
+
Reflect.ownKeys(to).forEach((key) => {
|
|
404
|
+
tryIgnore(() => {
|
|
405
|
+
let result = Object.getOwnPropertyDescriptor(to, key);
|
|
406
|
+
this.applyOverridesTo(result, true);
|
|
407
|
+
Object.defineProperty(to, key, result);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
var MutablyVisibleHandler = class extends VisibilityScopeHandler {
|
|
413
|
+
constructor() {
|
|
414
|
+
super(VisibilityKeys.mutablyVisible);
|
|
415
|
+
}
|
|
416
|
+
static get shared() {
|
|
417
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
418
|
+
}
|
|
419
|
+
static #singleton;
|
|
420
|
+
};
|
|
421
|
+
var MutablyHiddenHandler = class extends VisibilityScopeHandler {
|
|
422
|
+
constructor() {
|
|
423
|
+
super(VisibilityKeys.mutablyHidden);
|
|
424
|
+
}
|
|
425
|
+
static get shared() {
|
|
426
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
427
|
+
}
|
|
428
|
+
static #singleton;
|
|
429
|
+
};
|
|
430
|
+
var ImmutablyVisibleHandler = class extends VisibilityScopeHandler {
|
|
431
|
+
constructor() {
|
|
432
|
+
super(VisibilityKeys.immutablyVisible);
|
|
433
|
+
}
|
|
434
|
+
static get shared() {
|
|
435
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
436
|
+
}
|
|
437
|
+
static #singleton;
|
|
438
|
+
};
|
|
439
|
+
var ImmutablyHiddenHandler = class extends VisibilityScopeHandler {
|
|
440
|
+
constructor() {
|
|
441
|
+
super(VisibilityKeys.immutablyHidden);
|
|
442
|
+
}
|
|
443
|
+
static get shared() {
|
|
444
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
445
|
+
}
|
|
446
|
+
static #singleton;
|
|
447
|
+
};
|
|
448
|
+
var FlexiblyVisibleHandler = class extends VisibilityScopeHandler {
|
|
449
|
+
constructor() {
|
|
450
|
+
super(VisibilityKeys.flexiblyVisible);
|
|
451
|
+
}
|
|
452
|
+
static get shared() {
|
|
453
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
454
|
+
}
|
|
455
|
+
static #singleton;
|
|
456
|
+
};
|
|
457
|
+
var FlexiblyHiddenHandler = class extends VisibilityScopeHandler {
|
|
458
|
+
constructor() {
|
|
459
|
+
super(VisibilityKeys.flexiblyHidden);
|
|
460
|
+
}
|
|
461
|
+
static get shared() {
|
|
462
|
+
return this.#singleton ?? (this.#singleton = new this());
|
|
463
|
+
}
|
|
464
|
+
static #singleton;
|
|
465
|
+
};
|
|
466
|
+
Object.defineProperties(COPropertyHandler, {
|
|
467
|
+
MutablyHiddenHandler: { get() {
|
|
468
|
+
return MutablyHiddenHandler.shared;
|
|
469
|
+
} },
|
|
470
|
+
MutablyVisibleHandler: { get() {
|
|
471
|
+
return MutablyVisibleHandler.shared;
|
|
472
|
+
} },
|
|
473
|
+
ImmutablyHiddenHandler: { get() {
|
|
474
|
+
return ImmutablyHiddenHandler.shared;
|
|
475
|
+
} },
|
|
476
|
+
ImmutablyVisibleHandler: { get() {
|
|
477
|
+
return ImmutablyVisibleHandler.shared;
|
|
478
|
+
} },
|
|
479
|
+
FlexiblyHiddenHandler: { get() {
|
|
480
|
+
return FlexiblyHiddenHandler.shared;
|
|
481
|
+
} },
|
|
482
|
+
FlexiblyVisibleHandler: { get() {
|
|
483
|
+
return FlexiblyVisibleHandler.shared;
|
|
484
|
+
} },
|
|
485
|
+
handlers: {
|
|
486
|
+
value: [
|
|
487
|
+
MutablyHiddenHandler,
|
|
488
|
+
MutablyVisibleHandler,
|
|
489
|
+
ImmutablyHiddenHandler,
|
|
490
|
+
ImmutablyVisibleHandler,
|
|
491
|
+
FlexiblyHiddenHandler,
|
|
492
|
+
FlexiblyVisibleHandler
|
|
493
|
+
].map((klass) => klass.shared),
|
|
494
|
+
configurable: true,
|
|
495
|
+
enumerable: true
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
function copyObject(deep, destination, ...sources) {
|
|
499
|
+
const options = {
|
|
500
|
+
deep: deep || false,
|
|
501
|
+
propertyHandlers: COPropertyHandler?.handlers ?? []
|
|
502
|
+
};
|
|
503
|
+
return customCopyObject(options, destination, ...sources);
|
|
504
|
+
}
|
|
505
|
+
function customCopyObject(_options, _destination, ..._sources) {
|
|
506
|
+
const visited = /* @__PURE__ */ new Set();
|
|
507
|
+
const [options, destination, sources] = ccoParseArgs(
|
|
508
|
+
_options,
|
|
509
|
+
_destination,
|
|
510
|
+
..._sources
|
|
511
|
+
);
|
|
512
|
+
let { deep } = options;
|
|
513
|
+
for (const source of sources) {
|
|
514
|
+
if (source === null || typeof source !== "object" || visited.has(source)) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
visited.add(source);
|
|
518
|
+
const keys = Reflect.ownKeys(source);
|
|
519
|
+
for (let key of keys) {
|
|
520
|
+
let descriptor;
|
|
521
|
+
try {
|
|
522
|
+
descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
523
|
+
} catch (err) {
|
|
524
|
+
console.warn(`Failed to get descriptor for key "${key}": ${err}`);
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const isDataDesc = Reflect.has(descriptor, "value");
|
|
528
|
+
const keyedValue = descriptor?.value;
|
|
529
|
+
const conditionsMet = [
|
|
530
|
+
isDataDesc,
|
|
531
|
+
keyedValue,
|
|
532
|
+
typeof keyedValue === "object",
|
|
533
|
+
!visited.has(keyedValue)
|
|
534
|
+
].every((condition) => condition);
|
|
535
|
+
if (conditionsMet) {
|
|
536
|
+
visited.add(keyedValue);
|
|
537
|
+
const prototype = Object.getPrototypeOf(keyedValue);
|
|
538
|
+
const descriptors = Object.getOwnPropertyDescriptors(keyedValue);
|
|
539
|
+
const replacement = Object.create(prototype, descriptors);
|
|
540
|
+
descriptor.value = deep ? customCopyObject(options, replacement, keyedValue) : replacement;
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
Object.defineProperty(destination, key, descriptor);
|
|
544
|
+
} catch (err) {
|
|
545
|
+
console.error(`Failed to define property "${key}": ${err}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return destination;
|
|
550
|
+
}
|
|
551
|
+
function ccoParseArgs(options, destination, ...sources) {
|
|
552
|
+
let { deep = true, propertyHandlers = [] } = options;
|
|
553
|
+
deep = !!deep;
|
|
554
|
+
propertyHandlers = (Array.isArray(propertyHandlers) ? propertyHandlers : [propertyHandlers]).filter((element) => element instanceof COPropertyHandler);
|
|
555
|
+
const transducer = makeTransducer(propertyHandlers, transduceFromCOHandler);
|
|
556
|
+
propertyHandlers = transducer({});
|
|
557
|
+
options = { deep, propertyHandlers };
|
|
558
|
+
sources = sources.filter((source) => source && typeof source === "object");
|
|
559
|
+
if (!destination) {
|
|
560
|
+
destination = {};
|
|
561
|
+
}
|
|
562
|
+
return [options, destination, sources];
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/utils/stdout.js
|
|
566
|
+
var import_extension = require("@nejs/extension");
|
|
567
|
+
function captureStdout(callback, args = [], thisArg = console) {
|
|
568
|
+
let captured = "";
|
|
569
|
+
const originalWrite = process.stdout.write;
|
|
570
|
+
if (typeof callback !== "function") {
|
|
571
|
+
let newArgs = [callback];
|
|
572
|
+
if (thisArg) {
|
|
573
|
+
newArgs.push(thisArg);
|
|
574
|
+
}
|
|
575
|
+
newArgs = newArgs.concat(args);
|
|
576
|
+
callback = function() {
|
|
577
|
+
console.log(...newArgs);
|
|
578
|
+
};
|
|
579
|
+
thisArg = console;
|
|
580
|
+
args = [];
|
|
581
|
+
}
|
|
582
|
+
process.stdout.write = (chunk, encoding, callback2) => {
|
|
583
|
+
captured += chunk;
|
|
584
|
+
};
|
|
585
|
+
try {
|
|
586
|
+
callback.apply(thisArg, args);
|
|
587
|
+
} finally {
|
|
588
|
+
process.stdout.write = originalWrite;
|
|
589
|
+
}
|
|
590
|
+
return captured.substring(0, captured.length - 1);
|
|
591
|
+
}
|
|
592
|
+
var StringConsole = class _StringConsole {
|
|
593
|
+
/**
|
|
594
|
+
* @type {Array}
|
|
595
|
+
* @description
|
|
596
|
+
* The buffer array is used to store captured console output. It is
|
|
597
|
+
* initialized as an empty array and can be populated with strings
|
|
598
|
+
* representing console messages. This buffer serves as a temporary
|
|
599
|
+
* storage for output that can be manipulated or inspected later.
|
|
600
|
+
*
|
|
601
|
+
* @example
|
|
602
|
+
* const console = new StringConsole()
|
|
603
|
+
* console.buffer.push('Hello, World!')
|
|
604
|
+
* console.buffer // ['Hello, World!']
|
|
605
|
+
*/
|
|
606
|
+
buffer = [];
|
|
607
|
+
/**
|
|
608
|
+
* The last index of the buffer when capture began. This number should be
|
|
609
|
+
* set to `NaN` when not in use.
|
|
610
|
+
*
|
|
611
|
+
* @type {number|NaN}
|
|
612
|
+
*/
|
|
613
|
+
capturedAt = NaN;
|
|
614
|
+
/**
|
|
615
|
+
* If this is `true`, all "logged" output will be captured in an ever
|
|
616
|
+
* growing buffer.
|
|
617
|
+
*
|
|
618
|
+
* @type {boolean}
|
|
619
|
+
* @see {@link StringConsole.buffer}
|
|
620
|
+
*/
|
|
621
|
+
captureOutput = true;
|
|
622
|
+
/**
|
|
623
|
+
* @typedef {
|
|
624
|
+
* Int8Array|Int16Array|Int32Array|Float32Array|Float64Array
|
|
625
|
+
* } TypedArray
|
|
626
|
+
*/
|
|
627
|
+
/**
|
|
628
|
+
* @typedef {(
|
|
629
|
+
* chunk: string|Buffer|TypedArray|DataView,
|
|
630
|
+
* encoding: string|null,
|
|
631
|
+
* callback: ()=>{}
|
|
632
|
+
* )=>boolean} StringConsoleRecorder
|
|
633
|
+
* @property {boolean} [Symbol.for('StringConsole.recorder')]
|
|
634
|
+
*/
|
|
635
|
+
/**
|
|
636
|
+
* The recorder function is what is subsituted for the `process.stdout.write`
|
|
637
|
+
* function whenever we need to temporarily capture the output of data bound
|
|
638
|
+
* for the bidirectional read-write stream, `stdout`.
|
|
639
|
+
*
|
|
640
|
+
* @type {StringConsoleRecorder}
|
|
641
|
+
* @param {string|Buffer|TypedArray|DataView|any} chunk Optional data to
|
|
642
|
+
* write. For streams not operating in object mode, chunk must be a
|
|
643
|
+
* {@link String}, {@link Buffer}, {@link Int8Array}, {@link Int16Array},
|
|
644
|
+
* {@link Int32Array}, {@link Float32Array}, {@link Float64Array} or
|
|
645
|
+
* {@link DataView}. For object mode streams, chunk may be any JavaScript
|
|
646
|
+
* value other than `null`.
|
|
647
|
+
* @param {string|null} encoding the encoding, if chunk is a string.
|
|
648
|
+
* Default: `'utf8'`
|
|
649
|
+
* @param {Function} callback callback for when this chunk of data is
|
|
650
|
+
* flushed.
|
|
651
|
+
*
|
|
652
|
+
* @returns {boolean} false if the stream wishes for the calling code to
|
|
653
|
+
* wait for the 'drain' event to be emitted before continuing to write
|
|
654
|
+
* additional data; otherwise true.
|
|
655
|
+
*/
|
|
656
|
+
recorder = Object.defineProperty(
|
|
657
|
+
function recorder(chunk, encoding, callback) {
|
|
658
|
+
this.buffer.push(chunk);
|
|
659
|
+
},
|
|
660
|
+
Symbol.for(`StringConsole.recorder`),
|
|
661
|
+
{ value: true, configurable: true }
|
|
662
|
+
);
|
|
663
|
+
/**
|
|
664
|
+
* Initializes a new instance of the StringConsole class.
|
|
665
|
+
*
|
|
666
|
+
* @param {string|string[]} [initialContents] - The initial contents to
|
|
667
|
+
* populate the buffer. If an array is provided, it will be used directly
|
|
668
|
+
* as the buffer. If a single string is provided, it will be converted
|
|
669
|
+
* to a string and added to the buffer.
|
|
670
|
+
*
|
|
671
|
+
* @example
|
|
672
|
+
* const console1 = new StringConsole('Hello')
|
|
673
|
+
* console1.buffer // ['Hello']
|
|
674
|
+
*
|
|
675
|
+
* const console2 = new StringConsole(['Hello', 'World'])
|
|
676
|
+
* console2.buffer // ['Hello', 'World']
|
|
677
|
+
*/
|
|
678
|
+
constructor(captureOutput = true, initialContents = void 0) {
|
|
679
|
+
this.recorder = this.recorder.bind(this);
|
|
680
|
+
if (Array.isArray(initialContents))
|
|
681
|
+
this.buffer = initialContents;
|
|
682
|
+
else if (initialContents)
|
|
683
|
+
this.buffer.push(String(initialContents));
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Clears the buffer by removing all elements.
|
|
687
|
+
*
|
|
688
|
+
* This method utilizes the `splice` function to remove all elements
|
|
689
|
+
* from the buffer array, effectively resetting it to an empty state.
|
|
690
|
+
* This is useful when you want to discard all previously captured
|
|
691
|
+
* console output and start fresh.
|
|
692
|
+
*
|
|
693
|
+
* @returns {StringConsole} `this` to allow for calling `clear()`
|
|
694
|
+
* before immediately invoking a console method.
|
|
695
|
+
*
|
|
696
|
+
* @example
|
|
697
|
+
* const console = new StringConsole(['Hello', 'World'])
|
|
698
|
+
* console.clear()
|
|
699
|
+
* console.buffer // []
|
|
700
|
+
*/
|
|
701
|
+
clear() {
|
|
702
|
+
this.buffer.splice(0, this.buffer.length);
|
|
703
|
+
return this;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Checks if the console output is currently being captured.
|
|
707
|
+
*
|
|
708
|
+
* This method determines if the `process.stdout.write` function has been
|
|
709
|
+
* overridden to capture console output by checking for the presence of
|
|
710
|
+
* a specific symbol.
|
|
711
|
+
*
|
|
712
|
+
* @returns {boolean} True if capturing is active, false otherwise.
|
|
713
|
+
*
|
|
714
|
+
* @example
|
|
715
|
+
* const stringConsole = new StringConsole()
|
|
716
|
+
* stringConsole.startCapture()
|
|
717
|
+
* console.log(stringConsole.isCapturing()) // Stores 'true' in the buffer
|
|
718
|
+
*/
|
|
719
|
+
isCapturing() {
|
|
720
|
+
return Reflect.has(
|
|
721
|
+
process.stdout.write,
|
|
722
|
+
Symbol.for("StringConsole.recorder")
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Starts capturing console output.
|
|
727
|
+
*
|
|
728
|
+
* This method overrides the `process.stdout.write` function with a custom
|
|
729
|
+
* recorder function to capture all console output.
|
|
730
|
+
*
|
|
731
|
+
* @returns {number} the last index of the buffer in its current state or
|
|
732
|
+
* 0 if it is empty
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* const stringConsole = new StringConsole()
|
|
736
|
+
* stringConsole.startCapture()
|
|
737
|
+
* console.log('This will be stored in stringConsole.buffer')
|
|
738
|
+
*/
|
|
739
|
+
startCapture() {
|
|
740
|
+
if (this.captureOutput === false)
|
|
741
|
+
this.buffer = [];
|
|
742
|
+
process.stdout.write = this.recorder;
|
|
743
|
+
process.stderr.write = this.recorder;
|
|
744
|
+
this.capturedAt = this.buffer.length ? this.buffer.length : 0;
|
|
745
|
+
return this.capturedAt;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* An object containing two properties covering the captured content
|
|
749
|
+
* while `process.stdout.write` was swapped. It should contain the
|
|
750
|
+
* range of line indicies as well as the content as an array of strings
|
|
751
|
+
*
|
|
752
|
+
* @typedef {object} StringConsoleCapturedOutput
|
|
753
|
+
* @property {number[]} range an array of two numbers, a starting index
|
|
754
|
+
* and an ending index. This value will be [NaN,NaN] if this instance
|
|
755
|
+
* has indicated that storing captured output is disabled.
|
|
756
|
+
* @property {string[]} lines an array of strings of captured output
|
|
757
|
+
* that occurred in between calls to {@link ~startCapture} and then
|
|
758
|
+
* ending call to {@link ~stopCapture}
|
|
759
|
+
*/
|
|
760
|
+
/**
|
|
761
|
+
* Stops capturing console output.
|
|
762
|
+
*
|
|
763
|
+
* This method restores the original `process.stdout.write` function,
|
|
764
|
+
* ceasing the capture of console output.
|
|
765
|
+
*
|
|
766
|
+
* @returns {StringConsoleCapturedOutput} the range of indices capturing
|
|
767
|
+
* the lines of the buffer that have been added since capturing was
|
|
768
|
+
* started.
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* const stringConsole = new StringConsole()
|
|
772
|
+
* stringConsole.startCapture()
|
|
773
|
+
* console.log('This will be stored in stringConsole.buffer')
|
|
774
|
+
* stringConsole.stopCapture()
|
|
775
|
+
* console.log('This will not be captured')
|
|
776
|
+
*/
|
|
777
|
+
stopCapture() {
|
|
778
|
+
const range = [this.capturedAt || 0, this.buffer.length - 1];
|
|
779
|
+
const lines = this.buffer.slice(range[0], range[1] + 1);
|
|
780
|
+
if (this.captureOutput === false)
|
|
781
|
+
this.buffer = [];
|
|
782
|
+
process.stdout.write = _StringConsole[Symbol.for("process.stdout.write")];
|
|
783
|
+
process.stderr.write = _StringConsole[Symbol.for("process.stderr.write")];
|
|
784
|
+
this.capturedAt = NaN;
|
|
785
|
+
return { range, lines };
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Joins the StringConsole output as a single string. By default, each entry
|
|
789
|
+
* captured so far is joined on a new line. Pass a different joiner such as
|
|
790
|
+
* an empty string or a whitespace character, as examples, to change the
|
|
791
|
+
* output string.
|
|
792
|
+
*
|
|
793
|
+
* @param {string} joinOn the string to join the output buffer on, defaults
|
|
794
|
+
* to a new line character
|
|
795
|
+
* @returns a single string of contatenated entries so far to this buffer.
|
|
796
|
+
*/
|
|
797
|
+
toString(joinOn = "") {
|
|
798
|
+
return this.buffer.join(joinOn);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Captures formatted debug messages as though they'd been printed. The
|
|
802
|
+
* resulting output that would have been printed is stored in the buffer
|
|
803
|
+
* as well as being returned.
|
|
804
|
+
*
|
|
805
|
+
* This method formats the provided arguments with color coding specific
|
|
806
|
+
* to the 'debug' level as though `console.debug` were used. The output
|
|
807
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
808
|
+
* actually printed to the standard output.
|
|
809
|
+
*
|
|
810
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
811
|
+
* of any type and will be formatted with color coding without being logged.
|
|
812
|
+
*
|
|
813
|
+
* @returns {string} The captured console output as a string.
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* const stringConsole = new StringConsole()
|
|
817
|
+
* stringConsole.debug('[debug]', 'message')
|
|
818
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
819
|
+
*/
|
|
820
|
+
debug(...args) {
|
|
821
|
+
args = this.constructor.colorArgs("debug", args);
|
|
822
|
+
this.startCapture();
|
|
823
|
+
console.debug(...args);
|
|
824
|
+
return this.stopCapture().lines.join("\n");
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Captures formatted error messages as though they'd been printed. The
|
|
828
|
+
* resulting output that would have been printed is stored in the buffer
|
|
829
|
+
* as well as being returned.
|
|
830
|
+
*
|
|
831
|
+
* This method formats the provided arguments with color coding specific
|
|
832
|
+
* to the 'error' level as though `console.error` were used. The output
|
|
833
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
834
|
+
* actually printed to the standard output.
|
|
835
|
+
*
|
|
836
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
837
|
+
* of any type and will be formatted with color coding without being logged.
|
|
838
|
+
*
|
|
839
|
+
* @returns {string} The captured console output as a string.
|
|
840
|
+
*
|
|
841
|
+
* @example
|
|
842
|
+
* const stringConsole = new StringConsole()
|
|
843
|
+
* stringConsole.error('[error]', 'message')
|
|
844
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
845
|
+
*/
|
|
846
|
+
error(...args) {
|
|
847
|
+
args = this.constructor.colorArgs("error", args);
|
|
848
|
+
this.startCapture();
|
|
849
|
+
console.error(...args);
|
|
850
|
+
return this.stopCapture().lines.join("\n");
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Groups console output under a specified group name and captures the
|
|
854
|
+
* output. No content will actually be logged to the console, just
|
|
855
|
+
* the output that normally would be is formatted in a string and returned
|
|
856
|
+
* instead.
|
|
857
|
+
*
|
|
858
|
+
* This method allows you to format multiple messages under a single
|
|
859
|
+
* group name. It captures the output of each invocation and stores it in
|
|
860
|
+
* a buffer. The captured output is returned as a single string.
|
|
861
|
+
*
|
|
862
|
+
* @param {string} groupName - The name of the group under which the
|
|
863
|
+
* messages will be logged.
|
|
864
|
+
* @param {...Array} invocations - An array of invocations where each
|
|
865
|
+
* invocation is an array. The first element is the log level (e.g.,
|
|
866
|
+
* 'log', 'info'), and the remaining elements are the arguments to be
|
|
867
|
+
* logged.
|
|
868
|
+
*
|
|
869
|
+
* @returns {string} The captured console output as a string.
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* const console = new StringConsole()
|
|
873
|
+
* const output = console.group('MyGroup',
|
|
874
|
+
* ['log', 'Hello'],
|
|
875
|
+
* ['warn', 'Warning!']
|
|
876
|
+
* )
|
|
877
|
+
*
|
|
878
|
+
* console.buffer // Contains the captured group output
|
|
879
|
+
*/
|
|
880
|
+
group(groupName, ...invocations) {
|
|
881
|
+
const commands = ["log", "info", "warn", "error", "debug", "trace"];
|
|
882
|
+
const buffer = [];
|
|
883
|
+
invocations = invocations.filter((i) => commands.includes(i?.[0]));
|
|
884
|
+
if (groupName)
|
|
885
|
+
groupName = this.constructor.style(groupName, ["underline", "bold"]);
|
|
886
|
+
else
|
|
887
|
+
groupName = this.constructor.style("grouped", ["underline", "bold"]);
|
|
888
|
+
this.startCapture();
|
|
889
|
+
console.group(groupName);
|
|
890
|
+
for (const invocation of invocations) {
|
|
891
|
+
if (!Array.isArray(invocation) || invocation.length < 2)
|
|
892
|
+
continue;
|
|
893
|
+
const [level, ...args] = invocation;
|
|
894
|
+
console[level](...this.constructor.colorArgs(level, args));
|
|
895
|
+
}
|
|
896
|
+
console.groupEnd(groupName);
|
|
897
|
+
return this.stopCapture().lines.join("");
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Captures formatted info messages as though they'd been printed. The
|
|
901
|
+
* resulting output that would have been printed is stored in the buffer
|
|
902
|
+
* as well as being returned.
|
|
903
|
+
*
|
|
904
|
+
* This method formats the provided arguments with color coding specific
|
|
905
|
+
* to the 'info' level as though `console.info` were used. The output
|
|
906
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
907
|
+
* actually printed to the standard output.
|
|
908
|
+
*
|
|
909
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
910
|
+
* of any type and will be formatted with color coding without being logged.
|
|
911
|
+
*
|
|
912
|
+
* @returns {string} The captured console output as a string.
|
|
913
|
+
*
|
|
914
|
+
* @example
|
|
915
|
+
* const stringConsole = new StringConsole()
|
|
916
|
+
* stringConsole.info('[info]', 'message')
|
|
917
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
918
|
+
*/
|
|
919
|
+
info(...args) {
|
|
920
|
+
args = this.constructor.colorArgs("info", args);
|
|
921
|
+
this.startCapture();
|
|
922
|
+
console.info(...args);
|
|
923
|
+
return this.stopCapture().lines.join("\n");
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Captures formatted log messages as though they'd been printed. The
|
|
927
|
+
* resulting output that would have been printed is stored in the buffer
|
|
928
|
+
* as well as being returned.
|
|
929
|
+
*
|
|
930
|
+
* This method formats the provided arguments with color coding specific
|
|
931
|
+
* to the 'log' level as though `console.log` were used. The output
|
|
932
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
933
|
+
* actually printed to the standard output.
|
|
934
|
+
*
|
|
935
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
936
|
+
* of any type and will be formatted with color coding without being logged.
|
|
937
|
+
*
|
|
938
|
+
* @returns {string} The captured console output as a string.
|
|
939
|
+
*
|
|
940
|
+
* @example
|
|
941
|
+
* const stringConsole = new StringConsole()
|
|
942
|
+
* stringConsole.log('[log]', 'message')
|
|
943
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
944
|
+
*/
|
|
945
|
+
log(...args) {
|
|
946
|
+
args = this.constructor.colorArgs("log", args);
|
|
947
|
+
this.startCapture();
|
|
948
|
+
console.log(...args);
|
|
949
|
+
return this.stopCapture().lines.join("\n");
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Captures formatted trace messages as though they'd been printed. The
|
|
953
|
+
* resulting output that would have been printed is stored in the buffer
|
|
954
|
+
* as well as being returned.
|
|
955
|
+
*
|
|
956
|
+
* This method formats the provided arguments with color coding specific
|
|
957
|
+
* to the 'trace' level as though `console.trace` were used. The output
|
|
958
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
959
|
+
* actually printed to the standard output.
|
|
960
|
+
*
|
|
961
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
962
|
+
* of any type and will be formatted with color coding without being logged.
|
|
963
|
+
*
|
|
964
|
+
* @returns {string} The captured console output as a string.
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* const stringConsole = new StringConsole()
|
|
968
|
+
* stringConsole.trace('[trace]', 'message')
|
|
969
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
970
|
+
*/
|
|
971
|
+
trace(...args) {
|
|
972
|
+
args = this.constructor.colorArgs("trace", args);
|
|
973
|
+
this.startCapture();
|
|
974
|
+
console.trace(...args);
|
|
975
|
+
return this.stopCapture().lines.join("\n");
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Captures formatted warn messages as though they'd been printed. The
|
|
979
|
+
* resulting output that would have been printed is stored in the buffer
|
|
980
|
+
* as well as being returned.
|
|
981
|
+
*
|
|
982
|
+
* This method formats the provided arguments with color coding specific
|
|
983
|
+
* to the 'warn' level as though `console.warn` were used. The output
|
|
984
|
+
* is captured and stored in the buffer for later inspection, but not
|
|
985
|
+
* actually printed to the standard output.
|
|
986
|
+
*
|
|
987
|
+
* @param {any[]} args - The arguments to be log captured. These can be
|
|
988
|
+
* of any type and will be formatted with color coding without being logged.
|
|
989
|
+
*
|
|
990
|
+
* @returns {string} The captured console output as a string.
|
|
991
|
+
*
|
|
992
|
+
* @example
|
|
993
|
+
* const stringConsole = new StringConsole()
|
|
994
|
+
* stringConsole.warn('[warn]', 'message')
|
|
995
|
+
* stringConsole.buffer // Contains the captured messages so far as an array
|
|
996
|
+
*/
|
|
997
|
+
warn(...args) {
|
|
998
|
+
args = this.constructor.colorArgs("warn", args);
|
|
999
|
+
this.startCapture();
|
|
1000
|
+
console.warn(...args);
|
|
1001
|
+
return this.stopCapture().lines.join("\n");
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Captures a single line of text that would be logged to the console if
|
|
1005
|
+
* the console function of the same name were to be invoked. The string
|
|
1006
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1007
|
+
* those are untouched. After formatting, the string is returned.
|
|
1008
|
+
*
|
|
1009
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1010
|
+
* type and will be passed to the underlying console's method of the same
|
|
1011
|
+
* name.
|
|
1012
|
+
*
|
|
1013
|
+
* @returns {string}
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* const string = StringConsole.debug('[debug]: %o', someVariable)
|
|
1017
|
+
*/
|
|
1018
|
+
static debug(...args) {
|
|
1019
|
+
return this.#console.clear().debug(...args);
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Captures a single line of text that would be logged to the console if
|
|
1023
|
+
* the console function of the same name were to be invoked. The string
|
|
1024
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1025
|
+
* those are untouched. After formatting, the string is returned.
|
|
1026
|
+
*
|
|
1027
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1028
|
+
* type and will be passed to the underlying console's method of the same
|
|
1029
|
+
* name.
|
|
1030
|
+
*
|
|
1031
|
+
* @returns {string}
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* const string = StringConsole.error('[error]: %o', someVariable)
|
|
1035
|
+
*/
|
|
1036
|
+
static error(...args) {
|
|
1037
|
+
return this.#console.clear().error(...args);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Groups console output under a specified group name and captures the
|
|
1041
|
+
* output. No content will actually be logged to the console, just
|
|
1042
|
+
* the output that normally would be is formatted in a string and returned
|
|
1043
|
+
* instead.
|
|
1044
|
+
*
|
|
1045
|
+
* This method allows you to format multiple messages under a single
|
|
1046
|
+
* group name. It captures the output of each invocation and stores it in
|
|
1047
|
+
* a buffer. The captured output is returned as a single string.
|
|
1048
|
+
*
|
|
1049
|
+
* @param {string} groupName - The name of the group under which the
|
|
1050
|
+
* messages will be logged.
|
|
1051
|
+
* @param {...Array} invocations - An array of invocations where each
|
|
1052
|
+
* invocation is an array. The first element is the log level (e.g.,
|
|
1053
|
+
* 'log', 'info'), and the remaining elements are the arguments to be
|
|
1054
|
+
* logged.
|
|
1055
|
+
*
|
|
1056
|
+
* @returns {string} The captured console output as a string.
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* const console = new StringConsole()
|
|
1060
|
+
* const output = console.group('MyGroup',
|
|
1061
|
+
* ['log', 'Hello'],
|
|
1062
|
+
* ['warn', 'Warning!']
|
|
1063
|
+
* )
|
|
1064
|
+
*
|
|
1065
|
+
* console.buffer // Contains the captured group output
|
|
1066
|
+
*/
|
|
1067
|
+
static group(groupName, ...invocations) {
|
|
1068
|
+
return this.#console.clear().group(groupName, ...invocations);
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Captures a single line of text that would be logged to the console if
|
|
1072
|
+
* the console function of the same name were to be invoked. The string
|
|
1073
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1074
|
+
* those are untouched. After formatting, the string is returned.
|
|
1075
|
+
*
|
|
1076
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1077
|
+
* type and will be passed to the underlying console's method of the same
|
|
1078
|
+
* name.
|
|
1079
|
+
*
|
|
1080
|
+
* @returns {string}
|
|
1081
|
+
*
|
|
1082
|
+
* @example
|
|
1083
|
+
* const string = StringConsole.info('[info]: %o', someVariable)
|
|
1084
|
+
*/
|
|
1085
|
+
static info(...args) {
|
|
1086
|
+
return this.#console.clear().info(...args);
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Captures a single line of text that would be logged to the console if
|
|
1090
|
+
* the console function of the same name were to be invoked. The string
|
|
1091
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1092
|
+
* those are untouched. After formatting, the string is returned.
|
|
1093
|
+
*
|
|
1094
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1095
|
+
* type and will be passed to the underlying console's method of the same
|
|
1096
|
+
* name.
|
|
1097
|
+
*
|
|
1098
|
+
* @returns {string}
|
|
1099
|
+
*
|
|
1100
|
+
* @example
|
|
1101
|
+
* const string = StringConsole.log('[log]: %o', someVariable)
|
|
1102
|
+
*/
|
|
1103
|
+
static log(...args) {
|
|
1104
|
+
return this.#console.clear().log(...args);
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Captures a single line of text that would be logged to the console if
|
|
1108
|
+
* the console function of the same name were to be invoked. The string
|
|
1109
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1110
|
+
* those are untouched. After formatting, the string is returned.
|
|
1111
|
+
*
|
|
1112
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1113
|
+
* type and will be passed to the underlying console's method of the same
|
|
1114
|
+
* name.
|
|
1115
|
+
*
|
|
1116
|
+
* @returns {string}
|
|
1117
|
+
*
|
|
1118
|
+
* @example
|
|
1119
|
+
* const string = StringConsole.trace('[trace]: %o', someVariable)
|
|
1120
|
+
*/
|
|
1121
|
+
static trace(...args) {
|
|
1122
|
+
return this.#console.clear().trace(...args);
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Captures a single line of text that would be logged to the console if
|
|
1126
|
+
* the console function of the same name were to be invoked. The string
|
|
1127
|
+
* is formatted according to the log colors, or any pre-existing colors as
|
|
1128
|
+
* those are untouched. After formatting, the string is returned.
|
|
1129
|
+
*
|
|
1130
|
+
* @param {...*} args the arguments to be logged. These can be of any
|
|
1131
|
+
* type and will be passed to the underlying console's method of the same
|
|
1132
|
+
* name.
|
|
1133
|
+
*
|
|
1134
|
+
* @returns {string}
|
|
1135
|
+
*
|
|
1136
|
+
* @example
|
|
1137
|
+
* const string = StringConsole.warn('[warn]: %o', someVariable)
|
|
1138
|
+
*/
|
|
1139
|
+
static warn(...args) {
|
|
1140
|
+
return this.#console.clear().warn(...args);
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Internal instance of {@link StringConsole} used for static logging
|
|
1144
|
+
* methods.
|
|
1145
|
+
*
|
|
1146
|
+
* @type {StringConsole}
|
|
1147
|
+
*/
|
|
1148
|
+
static #console = new _StringConsole(false);
|
|
1149
|
+
/**
|
|
1150
|
+
* A static map defining color codes for console output. Each color is
|
|
1151
|
+
* associated with an array containing two numbers, which represent
|
|
1152
|
+
* the ANSI escape codes for styling text in the terminal.
|
|
1153
|
+
*
|
|
1154
|
+
* The first number in the array is the suffix code for the standard
|
|
1155
|
+
* color, while the second number suffix code to undo the color. These
|
|
1156
|
+
* codes are useless without the pen prefix code.
|
|
1157
|
+
*
|
|
1158
|
+
* @type {Map<string, number[]>}
|
|
1159
|
+
* @see {@link StringConsole.pens}
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* // Accessing the color codes for 'red'
|
|
1163
|
+
* const redCodes = StringConsole.colors.get('red')
|
|
1164
|
+
* const fgCodes = StringConsole.pens.get('foreground')
|
|
1165
|
+
* const prefix = `\x1b[${fgCodes[0]}${redCodes[0]}m`
|
|
1166
|
+
* const suffix = `\x1b[${fgCodes[1]}${redCodes[1]}m`
|
|
1167
|
+
* // Outputs: "Text" in red but "!!" in the default color
|
|
1168
|
+
* console.log(`${prefix}Text!!${suffix}`)
|
|
1169
|
+
*
|
|
1170
|
+
* @description
|
|
1171
|
+
* This map is used to apply color coding to console messages, enhancing
|
|
1172
|
+
* readability and providing visual cues for different log levels.
|
|
1173
|
+
*/
|
|
1174
|
+
static colors = /* @__PURE__ */ new Map([
|
|
1175
|
+
["black", [0, 9]],
|
|
1176
|
+
["red", [1, 9]],
|
|
1177
|
+
["green", [2, 9]],
|
|
1178
|
+
["yellow", [3, 9]],
|
|
1179
|
+
["blue", [4, 9]],
|
|
1180
|
+
["magenta", [5, 9]],
|
|
1181
|
+
["cyan", [6, 9]],
|
|
1182
|
+
["white", [7, 9]]
|
|
1183
|
+
]);
|
|
1184
|
+
/**
|
|
1185
|
+
* A static map defining the color schemes for different logging levels.
|
|
1186
|
+
* Each log level is associated with an array of color styles that are
|
|
1187
|
+
* applied to the console output for that level.
|
|
1188
|
+
*
|
|
1189
|
+
* The available log levels and their corresponding color styles are:
|
|
1190
|
+
* - 'log': White
|
|
1191
|
+
* - 'info': Cyan
|
|
1192
|
+
* - 'warn': Yellow
|
|
1193
|
+
* - 'error': Red
|
|
1194
|
+
* - 'trace': Magenta
|
|
1195
|
+
* - 'debug': Bold Yellow
|
|
1196
|
+
*
|
|
1197
|
+
* @type {Map<string, string[]>}
|
|
1198
|
+
*
|
|
1199
|
+
* @example
|
|
1200
|
+
* const logColor = StringConsole.levels.get('log') // ['white']
|
|
1201
|
+
* const errorColor = StringConsole.levels.get('error') // ['red']
|
|
1202
|
+
*/
|
|
1203
|
+
static levels = Object.defineProperties(/* @__PURE__ */ new Map([
|
|
1204
|
+
["log", ["white"]],
|
|
1205
|
+
["info", ["cyan"]],
|
|
1206
|
+
["warn", ["yellow"]],
|
|
1207
|
+
["error", ["red"]],
|
|
1208
|
+
["trace", ["magenta"]],
|
|
1209
|
+
["debug", ["bold", "yellow"]]
|
|
1210
|
+
]), {
|
|
1211
|
+
color: {
|
|
1212
|
+
value: function color(key) {
|
|
1213
|
+
for (const value of this.get(key)) {
|
|
1214
|
+
if (_StringConsole.colors.has(value)) {
|
|
1215
|
+
return _StringConsole.colors.get(value);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return _StringConsole.colors.get("white");
|
|
1219
|
+
},
|
|
1220
|
+
configurable: true
|
|
1221
|
+
},
|
|
1222
|
+
styles: {
|
|
1223
|
+
value: function styles(key) {
|
|
1224
|
+
const styles2 = [];
|
|
1225
|
+
for (const value of this.get(key)) {
|
|
1226
|
+
if (_StringConsole.styles.has(value)) {
|
|
1227
|
+
styles2.push(_StringConsole.styles.get(value));
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return styles2;
|
|
1231
|
+
},
|
|
1232
|
+
configurable: true
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
/**
|
|
1236
|
+
* A static map defining the ANSI escape codes for different pen styles
|
|
1237
|
+
* used in console output. Each pen style is associated with an array
|
|
1238
|
+
* containing two numbers: the first for setting the style and the second
|
|
1239
|
+
* for resetting it.
|
|
1240
|
+
*
|
|
1241
|
+
* The available pen styles and their corresponding ANSI codes are:
|
|
1242
|
+
* - 'foreground': [3, 3] - Standard foreground color
|
|
1243
|
+
* - 'background': [4, 4] - Standard background color
|
|
1244
|
+
* - 'bright.foreground': [9, 3] - Bright foreground color
|
|
1245
|
+
* - 'bright.background': [10, 4] - Bright background color
|
|
1246
|
+
*
|
|
1247
|
+
* These are prefixes for both enabling and disabling. Normally a red color
|
|
1248
|
+
* is represented using SGR (Select Graphic Rendition) codes like \x1b[31m
|
|
1249
|
+
* for the foreground and \x1b[39m to return to normal color. So the 3
|
|
1250
|
+
* determines a foreground prefix for starting and stopping (the 3's in 31
|
|
1251
|
+
* and 39). Background prefixes are usually 4. These change for bright
|
|
1252
|
+
* colors which use 9 and 3, and 10 and 4, respectively.
|
|
1253
|
+
*
|
|
1254
|
+
* @type {Map<string, number[]>}
|
|
1255
|
+
*
|
|
1256
|
+
* @example
|
|
1257
|
+
* // [3, 3]
|
|
1258
|
+
* const foregroundPen = StringConsole.pens.get('foreground')
|
|
1259
|
+
*
|
|
1260
|
+
* // [10, 4]
|
|
1261
|
+
* const brightBackgroundPen = StringConsole.pens.get('bright.background')
|
|
1262
|
+
*/
|
|
1263
|
+
static pens = /* @__PURE__ */ new Map([
|
|
1264
|
+
["foreground", [3, 3]],
|
|
1265
|
+
["background", [4, 4]],
|
|
1266
|
+
["bright.foreground", [9, 3]],
|
|
1267
|
+
["bright.background", [10, 4]]
|
|
1268
|
+
]);
|
|
1269
|
+
/**
|
|
1270
|
+
* A static map defining ANSI escape codes for various text styles used
|
|
1271
|
+
* in console output. Each style is associated with an array containing
|
|
1272
|
+
* two escape codes: one for enabling the style and one for disabling it.
|
|
1273
|
+
*
|
|
1274
|
+
* The available styles and their corresponding ANSI codes are:
|
|
1275
|
+
* - 'reset': Resets all styles to default.
|
|
1276
|
+
* - 'blink': Enables blinking text.
|
|
1277
|
+
* - 'bold': Makes text bold.
|
|
1278
|
+
* - 'conceal': Conceals text.
|
|
1279
|
+
* - 'dim': Dims the text.
|
|
1280
|
+
* - 'italics': Italicizes the text.
|
|
1281
|
+
* - 'negative': Inverts the foreground and background colors.
|
|
1282
|
+
* - 'strike': Strikes through the text.
|
|
1283
|
+
* - 'underline': Underlines the text.
|
|
1284
|
+
*
|
|
1285
|
+
* @type {Map<string, string[]>}
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* const boldStyle = StringConsole.styles.get('bold')
|
|
1289
|
+
* // ['\x1b[1m', '\x1b[22m']
|
|
1290
|
+
*/
|
|
1291
|
+
static styles = /* @__PURE__ */ new Map([
|
|
1292
|
+
["reset", ["\x1B[0m"]],
|
|
1293
|
+
["blink", ["\x1B[5m", "\x1B[25m"]],
|
|
1294
|
+
["bold", ["\x1B[1m", "\x1B[22m"]],
|
|
1295
|
+
["conceal", ["\x1B[8m", "\x1B[28m"]],
|
|
1296
|
+
["dim", ["\x1B[2m", "\x1B[22m"]],
|
|
1297
|
+
["italics", ["\x1B[3m", "\x1B[23m"]],
|
|
1298
|
+
["negative", ["\x1B[7m", "\x1B[27m"]],
|
|
1299
|
+
["strike", ["\x1B[9m", "\x1B[29m"]],
|
|
1300
|
+
["underline", ["\x1B[4m", "\x1B[24m"]]
|
|
1301
|
+
]);
|
|
1302
|
+
/**
|
|
1303
|
+
* Applies ANSI color codes to a given string based on specified options.
|
|
1304
|
+
* This method checks if the string already contains color codes or if
|
|
1305
|
+
* the input is not a string, in which case it returns the original input.
|
|
1306
|
+
* Otherwise, it formats the string with the specified color and pen
|
|
1307
|
+
* options.
|
|
1308
|
+
*
|
|
1309
|
+
* @param {string} string - The string to be colorized.
|
|
1310
|
+
* @param {Object} [options] - Configuration options for colorization.
|
|
1311
|
+
* @param {string} [options.level] - The log level determining
|
|
1312
|
+
* which colors to apply.
|
|
1313
|
+
* @param {number[]} [options.rgb8] a single color code where 0 - 7, for
|
|
1314
|
+
* the 'standard' colors specified by the SGR sequences 30 to 37; 8-15 are
|
|
1315
|
+
* high intensity or bright colors,
|
|
1316
|
+
* @param {number[]} [options.rgb24] An array of three values, ordered, red,
|
|
1317
|
+
* green and then blue. The values should range from 0 to 255.
|
|
1318
|
+
* @param {string|string[]} [options.styles] defaulting to an empty array, if
|
|
1319
|
+
* supplied with a single known style {@link ~styles}, or an array of them.
|
|
1320
|
+
* @param {string} [options.pen='foreground'] - The pen type for color
|
|
1321
|
+
* application, either 'foreground' or 'background'.
|
|
1322
|
+
* @param {Array} [options.buffer=[]] - An array to prepend to the
|
|
1323
|
+
* formatted string.
|
|
1324
|
+
* @param {Array} [options.before=[]] - An array of strings to prepend
|
|
1325
|
+
* before the main string.
|
|
1326
|
+
* @param {Array} [options.after=[]] - An array of strings to append
|
|
1327
|
+
* after the main string. 16 - 231, for the colors in the 6 × 6 × 6 cube
|
|
1328
|
+
* defined by 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5); 232-255:
|
|
1329
|
+
* grayscale from dark to light in 24 steps.
|
|
1330
|
+
*
|
|
1331
|
+
* @returns {string} The colorized string with ANSI codes applied.
|
|
1332
|
+
*
|
|
1333
|
+
* @example
|
|
1334
|
+
* const coloredString = StringConsole.color('Hello', {
|
|
1335
|
+
* level: 'info',
|
|
1336
|
+
* pen: 'bright.foreground'
|
|
1337
|
+
* })
|
|
1338
|
+
* console.log(coloredString)
|
|
1339
|
+
*/
|
|
1340
|
+
static color(string, options = {
|
|
1341
|
+
level: void 0,
|
|
1342
|
+
color: void 0,
|
|
1343
|
+
pen: "foreground",
|
|
1344
|
+
rgb8: void 0,
|
|
1345
|
+
rgb24: [186, 186, 186],
|
|
1346
|
+
styles: [],
|
|
1347
|
+
buffer: [],
|
|
1348
|
+
before: [],
|
|
1349
|
+
after: []
|
|
1350
|
+
}) {
|
|
1351
|
+
const { colors: Colors, styles: Styles, pens: Pens, levels: Levels } = this;
|
|
1352
|
+
let useColors = void 0;
|
|
1353
|
+
let useRGB = false;
|
|
1354
|
+
let styles = [];
|
|
1355
|
+
const pens = this.pens.get(options?.pen ?? "foreground");
|
|
1356
|
+
const [p0, p1] = pens;
|
|
1357
|
+
if (options?.styles) {
|
|
1358
|
+
if (Array.isArray(options.styles))
|
|
1359
|
+
styles = options.styles.filter((s) => Styles.has(s)).map((s) => Styles.get(s));
|
|
1360
|
+
else if (typeof options.styles === "string" && Styles.has(options.styles))
|
|
1361
|
+
styles = Styles.get(options.styles);
|
|
1362
|
+
}
|
|
1363
|
+
if (options?.level && Levels.has(options.level)) {
|
|
1364
|
+
useColors = Levels.color(options.level);
|
|
1365
|
+
const addlStyles = Levels.styles(options.level);
|
|
1366
|
+
if (addlStyles.length)
|
|
1367
|
+
styles = styles.concat(addlStyles);
|
|
1368
|
+
} else if (options?.color && Colors.has(options.color))
|
|
1369
|
+
useColors = Colors.get(options.color);
|
|
1370
|
+
else if (options?.rgb24 && Array.isArray(options.rgb24)) {
|
|
1371
|
+
useColors = [`\x1B[${p0}8;2;${options.rgb24.join(";")};m`, `\x1B[${p1}9m`];
|
|
1372
|
+
useRGB = true;
|
|
1373
|
+
} else if (options?.rgb8 && typeof options.rgb8 === "number") {
|
|
1374
|
+
useColors = [`\x1B[${p0}8;5;${options.rgb8}m`, `\x1B[${p1}9m`];
|
|
1375
|
+
useRGB = true;
|
|
1376
|
+
} else useColors = [9, 9];
|
|
1377
|
+
const [c0, c1] = useRGB ? useColors : useColors?.map((c, i) => `\x1B[${pens[i]}${c}m`) ?? [`\x1B[39;49m`];
|
|
1378
|
+
if (this.hasColor(string)) return string;
|
|
1379
|
+
if (typeof string !== "string") return string;
|
|
1380
|
+
if (string instanceof String) string = String(string);
|
|
1381
|
+
if (!useColors) return string;
|
|
1382
|
+
if (options?.buffer && !Array.isArray(options.buffer))
|
|
1383
|
+
options.buffer = [String(options.buffer)];
|
|
1384
|
+
if (options?.before && !Array.isArray(options.before))
|
|
1385
|
+
options.before = [String(options.before)];
|
|
1386
|
+
if (options?.after && !Array.isArray(options.after))
|
|
1387
|
+
options.after = [String(options.after)];
|
|
1388
|
+
const buffer = [].concat(options?.buffer ?? []);
|
|
1389
|
+
const before = [].concat(options?.before ?? []);
|
|
1390
|
+
const after = [].concat(options?.after ?? []);
|
|
1391
|
+
if (c0)
|
|
1392
|
+
before.push(c0);
|
|
1393
|
+
if (c1)
|
|
1394
|
+
after.push(c1);
|
|
1395
|
+
for (const style of styles) {
|
|
1396
|
+
if (style?.[0])
|
|
1397
|
+
before.push(style[0]);
|
|
1398
|
+
if (style?.[1])
|
|
1399
|
+
after.push(style[1]);
|
|
1400
|
+
}
|
|
1401
|
+
return [...buffer, before.join(""), string, after.join("")].join("");
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Applies color formatting to each argument based on the specified log level.
|
|
1405
|
+
*
|
|
1406
|
+
* This method processes an array of arguments, applying color formatting
|
|
1407
|
+
* to each one according to the provided log level. The color formatting
|
|
1408
|
+
* is determined by the `color` method, which uses the log level to
|
|
1409
|
+
* select the appropriate color scheme.
|
|
1410
|
+
*
|
|
1411
|
+
* @param {string} level - The log level that determines the color scheme
|
|
1412
|
+
* to be applied. Common levels include 'log', 'info', 'warn', 'error',
|
|
1413
|
+
* etc.
|
|
1414
|
+
* @param {Array} args - An array of arguments to be formatted. Each
|
|
1415
|
+
* argument will be processed individually to apply the color formatting.
|
|
1416
|
+
*
|
|
1417
|
+
* @returns {Array} A new array containing the formatted arguments with
|
|
1418
|
+
* color applied.
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* const formattedArgs = StringConsole.colorArgs(
|
|
1422
|
+
* 'info',
|
|
1423
|
+
* ['Message 1', 'Message 2']
|
|
1424
|
+
* )
|
|
1425
|
+
* // formattedArgs will contain the messages with 'info' level
|
|
1426
|
+
* // color formatting
|
|
1427
|
+
*/
|
|
1428
|
+
static colorArgs(level, args) {
|
|
1429
|
+
const newArgs = [];
|
|
1430
|
+
if (args === null || args === void 0 || !Array.isArray(args))
|
|
1431
|
+
return args;
|
|
1432
|
+
for (const arg of args) {
|
|
1433
|
+
newArgs.push(this.color(arg, { level }));
|
|
1434
|
+
}
|
|
1435
|
+
return newArgs;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Determines if a given string contains ANSI color codes.
|
|
1439
|
+
*
|
|
1440
|
+
* This method checks for the presence of ANSI escape codes in the
|
|
1441
|
+
* provided string, which are used for color formatting in terminal
|
|
1442
|
+
* outputs. The presence of these codes indicates that the string
|
|
1443
|
+
* has color formatting applied.
|
|
1444
|
+
*
|
|
1445
|
+
* @param {string} string - The string to be checked for ANSI color codes.
|
|
1446
|
+
*
|
|
1447
|
+
* @returns {boolean} Returns true if the string contains ANSI color codes,
|
|
1448
|
+
* otherwise false.
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* const hasColor = StringConsole.hasColor('\x1b[31mRed Text\x1b[0m')
|
|
1452
|
+
* // hasColor will be true
|
|
1453
|
+
*
|
|
1454
|
+
* const noColor = StringConsole.hasColor('Plain Text')
|
|
1455
|
+
* // noColor will be false
|
|
1456
|
+
*/
|
|
1457
|
+
static hasColor(string) {
|
|
1458
|
+
return string.includes("\x1B[");
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Applies a series of styles to a given string using ANSI escape codes.
|
|
1462
|
+
*
|
|
1463
|
+
* This method takes a string and an array of style names or style arrays,
|
|
1464
|
+
* and applies the corresponding ANSI escape codes to the string. The
|
|
1465
|
+
* styles are defined in the `styles` map, which associates style names
|
|
1466
|
+
* with their respective ANSI codes.
|
|
1467
|
+
*
|
|
1468
|
+
* @param {string} string - The string to which styles will be applied.
|
|
1469
|
+
* @param {string|string[]} styles - A style name or an array of style
|
|
1470
|
+
* names/arrays to be applied. Each style can be a string that matches
|
|
1471
|
+
* a key in the `styles` map or an array containing ANSI codes.
|
|
1472
|
+
*
|
|
1473
|
+
* @returns {string} The styled string with ANSI escape codes applied.
|
|
1474
|
+
*
|
|
1475
|
+
* @example
|
|
1476
|
+
* const styledText = StringConsole.style('Hello', ['bold', 'underline'])
|
|
1477
|
+
* // styledText will have 'Hello' with bold and underline styles
|
|
1478
|
+
*/
|
|
1479
|
+
static style(string, styles) {
|
|
1480
|
+
const before = [];
|
|
1481
|
+
const after = [];
|
|
1482
|
+
const buffer = [];
|
|
1483
|
+
if (typeof styles === "string" && this.styles.has(styles)) {
|
|
1484
|
+
styles = [styles];
|
|
1485
|
+
}
|
|
1486
|
+
for (const style of styles) {
|
|
1487
|
+
let group = [];
|
|
1488
|
+
if (this.styles.has(style))
|
|
1489
|
+
group = this.styles.get(style);
|
|
1490
|
+
else if (Array.isArray(style) && style.length >= 1)
|
|
1491
|
+
group = style;
|
|
1492
|
+
if (group?.[0])
|
|
1493
|
+
before.push(group?.[0]);
|
|
1494
|
+
if (group?.[1])
|
|
1495
|
+
after.push(group?.[1]);
|
|
1496
|
+
}
|
|
1497
|
+
return [before.join(""), string, after.join("")].join("");
|
|
1498
|
+
}
|
|
1499
|
+
static {
|
|
1500
|
+
Object.defineProperties(_StringConsole, {
|
|
1501
|
+
[Symbol.for("process.stdout.write")]: {
|
|
1502
|
+
value: Object.defineProperties(process.stdout.write, {
|
|
1503
|
+
[Symbol.for("original")]: { value: true, configurable: true },
|
|
1504
|
+
isOriginal: { get() {
|
|
1505
|
+
return true;
|
|
1506
|
+
}, configurable: true }
|
|
1507
|
+
}),
|
|
1508
|
+
configurable: true
|
|
1509
|
+
},
|
|
1510
|
+
[Symbol.for("process.stderr.write")]: {
|
|
1511
|
+
value: Object.defineProperties(process.stderr.write, {
|
|
1512
|
+
[Symbol.for("original")]: { value: true, configurable: true },
|
|
1513
|
+
isOriginal: { get() {
|
|
1514
|
+
return true;
|
|
1515
|
+
}, configurable: true }
|
|
1516
|
+
}),
|
|
1517
|
+
configurable: true
|
|
1518
|
+
}
|
|
1519
|
+
});
|
|
1520
|
+
if (!Reflect.has(_StringConsole, "writer")) {
|
|
1521
|
+
Object.defineProperties(_StringConsole, {
|
|
1522
|
+
writer: {
|
|
1523
|
+
value: _StringConsole[Symbol.for("process.stdout.write")],
|
|
1524
|
+
configurable: true
|
|
1525
|
+
},
|
|
1526
|
+
errorWriter: {
|
|
1527
|
+
value: _StringConsole[Symbol.for("process.stderr.write")],
|
|
1528
|
+
configurable: true
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
var SC = StringConsole;
|
|
1535
|
+
var StringConsoleExtension = new import_extension.Extension(StringConsole);
|
|
1536
|
+
var StdoutGlobalPatches = new import_extension.Patch(globalThis, {
|
|
1537
|
+
[import_extension.Patch.kMutablyHidden]: {
|
|
1538
|
+
captureStdout
|
|
1539
|
+
}
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
// src/utils/toolkit.js
|
|
1543
|
+
var map = /* @__PURE__ */ new Map([
|
|
1544
|
+
["object", Object],
|
|
1545
|
+
[Object, "object"],
|
|
1546
|
+
["Object", Object],
|
|
1547
|
+
["number", Number],
|
|
1548
|
+
[Number, "number"],
|
|
1549
|
+
["Number", Number],
|
|
1550
|
+
["string", String],
|
|
1551
|
+
[String, "string"],
|
|
1552
|
+
["String", String],
|
|
1553
|
+
["function", Function],
|
|
1554
|
+
[Function, "function"],
|
|
1555
|
+
["Function", Function],
|
|
1556
|
+
["boolean", Boolean],
|
|
1557
|
+
[Boolean, "boolean"],
|
|
1558
|
+
["Boolean", Boolean],
|
|
1559
|
+
["bigint", BigInt],
|
|
1560
|
+
[BigInt, "bigint"],
|
|
1561
|
+
["BigInt", BigInt],
|
|
1562
|
+
["symbol", Symbol],
|
|
1563
|
+
[Symbol, "symbol"],
|
|
1564
|
+
["Symbol", Symbol],
|
|
1565
|
+
["undefined", void 0],
|
|
1566
|
+
[void 0, "undefined"],
|
|
1567
|
+
["null", null],
|
|
1568
|
+
[null, "null"]
|
|
1569
|
+
]);
|
|
1570
|
+
var is = {
|
|
1571
|
+
/**
|
|
1572
|
+
* Checks if a value matches a specified type or class.
|
|
1573
|
+
*
|
|
1574
|
+
* This function determines if the provided value matches the specified
|
|
1575
|
+
* type or class. It supports both primitive types and class constructors.
|
|
1576
|
+
*
|
|
1577
|
+
* @param {*} value - The value to check.
|
|
1578
|
+
* @param {*} typeOrClass - The type or class to compare against.
|
|
1579
|
+
* @returns {boolean} True if the value matches the type or class,
|
|
1580
|
+
* false otherwise.
|
|
1581
|
+
*
|
|
1582
|
+
* @example
|
|
1583
|
+
* // Returns true
|
|
1584
|
+
* is.a(42, 'number')
|
|
1585
|
+
*
|
|
1586
|
+
* @example
|
|
1587
|
+
* // Returns true
|
|
1588
|
+
* is.a(new Date(), Date)
|
|
1589
|
+
*
|
|
1590
|
+
* @example
|
|
1591
|
+
* // Returns false
|
|
1592
|
+
* is.a('string', Number)
|
|
1593
|
+
*/
|
|
1594
|
+
a(value, typeOrClass) {
|
|
1595
|
+
const valueType = typeof value;
|
|
1596
|
+
const valueTag = this.object(value) && value[Symbol.toStringTag];
|
|
1597
|
+
if (value === typeOrClass)
|
|
1598
|
+
return true;
|
|
1599
|
+
if (this.function(typeOrClass)) {
|
|
1600
|
+
const typeTag = this.object(typeOrClass) && typeOrClass[Symbol.toStringTag];
|
|
1601
|
+
if (valueTag && valueTag === typeOrClass.name)
|
|
1602
|
+
return true;
|
|
1603
|
+
if (typeOrClass?.prototype && value instanceof typeOrClass)
|
|
1604
|
+
return true;
|
|
1605
|
+
return map.get(valueType) === typeOrClass;
|
|
1606
|
+
} else if (map.get(valueType)?.name === typeOrClass)
|
|
1607
|
+
return true;
|
|
1608
|
+
else if (valueType === typeOrClass || valueTag === typeOrClass)
|
|
1609
|
+
return true;
|
|
1610
|
+
return false;
|
|
1611
|
+
},
|
|
1612
|
+
/**
|
|
1613
|
+
* Check if a value is an accessor descriptor.
|
|
1614
|
+
*
|
|
1615
|
+
* An accessor descriptor is an object that describes the configuration of a
|
|
1616
|
+
* property on an object, specifically focusing on the 'get' and 'set'
|
|
1617
|
+
* attributes. Computed accessor descriptors are invalid if they also have
|
|
1618
|
+
* a `value` and/or `writable` property.
|
|
1619
|
+
*
|
|
1620
|
+
* @param value The value to check.
|
|
1621
|
+
* @returns True if the value is an accessor descriptor, false otherwise.
|
|
1622
|
+
*
|
|
1623
|
+
* @example
|
|
1624
|
+
* // Returns true
|
|
1625
|
+
* is.accessorDescriptor({ get: () => 42, set: () => {} })
|
|
1626
|
+
*
|
|
1627
|
+
* // Returns false
|
|
1628
|
+
* is.accessorDescriptor({ value: 42, writable: true })
|
|
1629
|
+
*/
|
|
1630
|
+
accessorDescriptor(value) {
|
|
1631
|
+
return !!(this.descriptor(value) && (value?.get || value?.set) && value?.writable === void 0 && value?.value === void 0);
|
|
1632
|
+
},
|
|
1633
|
+
/**
|
|
1634
|
+
* Check if a value is an array.
|
|
1635
|
+
*
|
|
1636
|
+
* @param value The value to check.
|
|
1637
|
+
* @returns True if the value is an array, false otherwise.
|
|
1638
|
+
*
|
|
1639
|
+
* @example
|
|
1640
|
+
* is.array([1, 2, 3]) // true
|
|
1641
|
+
* is.array('string') // false
|
|
1642
|
+
*/
|
|
1643
|
+
array(value) {
|
|
1644
|
+
return Array.isArray(value);
|
|
1645
|
+
},
|
|
1646
|
+
/**
|
|
1647
|
+
* Check if a value is a bigint.
|
|
1648
|
+
*
|
|
1649
|
+
* @param value The value to check.
|
|
1650
|
+
* @returns True if the value is a bigint, false otherwise.
|
|
1651
|
+
*
|
|
1652
|
+
* @example
|
|
1653
|
+
* is.bigint(123n) // true
|
|
1654
|
+
* is.bigint(123) // false
|
|
1655
|
+
*/
|
|
1656
|
+
bigint(value) {
|
|
1657
|
+
return typeof value === "bigint" || value instanceof globalThis?.BigInt;
|
|
1658
|
+
},
|
|
1659
|
+
/**
|
|
1660
|
+
* Checks if a value is strictly a boolean (true or false).
|
|
1661
|
+
*
|
|
1662
|
+
* This method verifies if the provided value is either `true` or `false`.
|
|
1663
|
+
*
|
|
1664
|
+
* @param {*} value - The value to check.
|
|
1665
|
+
* @returns {boolean} True if the value is a boolean, false otherwise.
|
|
1666
|
+
*
|
|
1667
|
+
* @example
|
|
1668
|
+
* is.boolean(true) // true
|
|
1669
|
+
* is.boolean(false) // true
|
|
1670
|
+
* is.boolean(1) // false
|
|
1671
|
+
* is.boolean("true") // false
|
|
1672
|
+
*/
|
|
1673
|
+
boolean(value) {
|
|
1674
|
+
return [true, false].some((bool) => bool === value);
|
|
1675
|
+
},
|
|
1676
|
+
/**
|
|
1677
|
+
* Check if an object is callable. This function is more or less a
|
|
1678
|
+
* synonym or alias for `is.function()`.
|
|
1679
|
+
*
|
|
1680
|
+
* @param object The object to check.
|
|
1681
|
+
* @returns True if the object is callable, false otherwise.
|
|
1682
|
+
*
|
|
1683
|
+
* @note if you wish to know if a descriptor has a callable `value`,
|
|
1684
|
+
* `get`, or `set` function, use `is.callableDescriptor` instead.
|
|
1685
|
+
*
|
|
1686
|
+
* @example
|
|
1687
|
+
* is.callable(function() {}) // true
|
|
1688
|
+
*/
|
|
1689
|
+
callable(object) {
|
|
1690
|
+
return this.function(object);
|
|
1691
|
+
},
|
|
1692
|
+
/**
|
|
1693
|
+
* Check if an object is a callable descriptor. It looks to see if the
|
|
1694
|
+
* object represents a descriptor that is callable by checking object
|
|
1695
|
+
* properties named `value`, `get`, and `set`. If any of the three
|
|
1696
|
+
* yields a function type, true is returned.
|
|
1697
|
+
*
|
|
1698
|
+
* @param object The object to check.
|
|
1699
|
+
* @returns True if the object is a callable descriptor, false otherwise.
|
|
1700
|
+
*
|
|
1701
|
+
* @example
|
|
1702
|
+
* is.callableDescriptor({ get: function() {} }) // true
|
|
1703
|
+
* is.callableDescriptor(123) // false
|
|
1704
|
+
*
|
|
1705
|
+
* // Note the differences between these
|
|
1706
|
+
* const object = { get name() { return "Brie"; } }
|
|
1707
|
+
* const descriptor = Object.getOwnPropertyDescriptor(object, 'name')
|
|
1708
|
+
* is.callableDescriptor(object) // false
|
|
1709
|
+
* is.callableDescriptor(descriptor) // true
|
|
1710
|
+
*/
|
|
1711
|
+
callableDescriptor(object) {
|
|
1712
|
+
const { value, get, set } = this.shiny(object) ? object : {};
|
|
1713
|
+
return [value, get, set].some((val) => this.function(val));
|
|
1714
|
+
},
|
|
1715
|
+
/**
|
|
1716
|
+
* Check if a value is a data property descriptor.
|
|
1717
|
+
*
|
|
1718
|
+
* A data descriptor is an object that describes the configuration of a
|
|
1719
|
+
* property on an object, specifically focusing on the 'value' and
|
|
1720
|
+
* 'writable' attributes. The descriptor is invalid if it contains
|
|
1721
|
+
* the accessor descriptors `get` or `set`.
|
|
1722
|
+
*
|
|
1723
|
+
* @param value The value to check.
|
|
1724
|
+
* @returns True if the value is a data descriptor, false otherwise.
|
|
1725
|
+
*
|
|
1726
|
+
* @example
|
|
1727
|
+
* // Returns true
|
|
1728
|
+
* is.dataDescriptor({ value: 42, writable: true })
|
|
1729
|
+
*
|
|
1730
|
+
* // Returns false
|
|
1731
|
+
* is.dataDescriptor({ get: () => 42, set: () => {} })
|
|
1732
|
+
*/
|
|
1733
|
+
dataDescriptor(value) {
|
|
1734
|
+
return !!(this.descriptor(value) && (value?.value !== void 0 || value?.writable !== void 0) && value?.get === void 0 && value?.set === void 0);
|
|
1735
|
+
},
|
|
1736
|
+
/**
|
|
1737
|
+
* Check if a value is a property descriptor.
|
|
1738
|
+
*
|
|
1739
|
+
* A property descriptor is an object that describes the configuration of a
|
|
1740
|
+
* property on an object. This function checks if the provided value is an
|
|
1741
|
+
* object and contains any of the standard property descriptor keys.
|
|
1742
|
+
*
|
|
1743
|
+
* @param value The value to check.
|
|
1744
|
+
* @returns True if the value is a property descriptor, false otherwise.
|
|
1745
|
+
*
|
|
1746
|
+
* @example
|
|
1747
|
+
* is.descriptor({ configurable: true, enumerable: false }) // true
|
|
1748
|
+
* is.descriptor({ get: () => {}, set: () => {} }) // true
|
|
1749
|
+
* is.descriptor({}) // false
|
|
1750
|
+
*/
|
|
1751
|
+
descriptor(value) {
|
|
1752
|
+
if (!is.object(value)) {
|
|
1753
|
+
return false;
|
|
1754
|
+
}
|
|
1755
|
+
const _has = (key) => Reflect.has(value, key);
|
|
1756
|
+
const hasBase = ["configurable", "enumerable"].some((key) => _has(key));
|
|
1757
|
+
const hasData = ["value", "writable"].some((key) => _has(key));
|
|
1758
|
+
const hasAccess = ["get", "set"].some((key) => _has(key));
|
|
1759
|
+
return hasBase || hasData || hasAccess;
|
|
1760
|
+
},
|
|
1761
|
+
/**
|
|
1762
|
+
* Checks if a value is strictly false.
|
|
1763
|
+
*
|
|
1764
|
+
* This method verifies if the provided value is strictly `false`.
|
|
1765
|
+
*
|
|
1766
|
+
* @param {*} value - The value to check.
|
|
1767
|
+
* @returns {boolean} True if the value is strictly false, false otherwise.
|
|
1768
|
+
*
|
|
1769
|
+
* @example
|
|
1770
|
+
* is.false(false) // true
|
|
1771
|
+
* is.false(true) // false
|
|
1772
|
+
* is.false(0) // false
|
|
1773
|
+
*/
|
|
1774
|
+
false(value) {
|
|
1775
|
+
return value === false;
|
|
1776
|
+
},
|
|
1777
|
+
/**
|
|
1778
|
+
* Checks if a value is falsy.
|
|
1779
|
+
*
|
|
1780
|
+
* This method converts the provided value to a boolean and returns
|
|
1781
|
+
* `true` if the value is falsy (i.e., false, 0, "", null, undefined,
|
|
1782
|
+
* or NaN).
|
|
1783
|
+
*
|
|
1784
|
+
* @param {*} value - The value to check.
|
|
1785
|
+
* @returns {boolean} True if the value is falsy, false otherwise.
|
|
1786
|
+
*
|
|
1787
|
+
* @example
|
|
1788
|
+
* is.falsy(0) // true
|
|
1789
|
+
* is.falsy("") // true
|
|
1790
|
+
* is.falsy(1) // false
|
|
1791
|
+
* is.falsy("hello") // false
|
|
1792
|
+
*/
|
|
1793
|
+
falsy(value) {
|
|
1794
|
+
return !!!value;
|
|
1795
|
+
},
|
|
1796
|
+
/**
|
|
1797
|
+
* Alias for the `falsy` method.
|
|
1798
|
+
*
|
|
1799
|
+
* This method is an alias for `is.falsy` and performs the same check.
|
|
1800
|
+
*
|
|
1801
|
+
* @param {*} value - The value to check.
|
|
1802
|
+
* @returns {boolean} True if the value is falsy, false otherwise.
|
|
1803
|
+
*
|
|
1804
|
+
* @example
|
|
1805
|
+
* is.falsey(0) // true
|
|
1806
|
+
* is.falsey("") // true
|
|
1807
|
+
* is.falsey(1) // false
|
|
1808
|
+
* is.falsey("hello") // false
|
|
1809
|
+
*/
|
|
1810
|
+
falsey(value) {
|
|
1811
|
+
return this.falsy(value);
|
|
1812
|
+
},
|
|
1813
|
+
/**
|
|
1814
|
+
* Check if a value is a function.
|
|
1815
|
+
*
|
|
1816
|
+
* @param value The value to check.
|
|
1817
|
+
* @returns True if the value is a function, false otherwise.
|
|
1818
|
+
*
|
|
1819
|
+
* @example
|
|
1820
|
+
* is.function(function() {}) // true
|
|
1821
|
+
* is.function(123) // false
|
|
1822
|
+
*/
|
|
1823
|
+
function(value) {
|
|
1824
|
+
return typeof value === "function" || value instanceof Function;
|
|
1825
|
+
},
|
|
1826
|
+
/**
|
|
1827
|
+
* Check if a value is iterable. Depending on the environment, JavaScript
|
|
1828
|
+
* will permit `'string'[Symbol.iterator]()` whereas in some places, you
|
|
1829
|
+
* will need to wrap string in an object first. Since other JSVM provided
|
|
1830
|
+
* environments may or may not be leniant with this, we play it safe by
|
|
1831
|
+
* implicitly object converting values before checking for the symbol. If
|
|
1832
|
+
* a value is already an object, it will simply be passed through.
|
|
1833
|
+
*
|
|
1834
|
+
* @param value The value to check.
|
|
1835
|
+
* @returns True if the value is iterable, false otherwise.
|
|
1836
|
+
*
|
|
1837
|
+
* @example
|
|
1838
|
+
* is.iterable([1, 2, 3]) // true
|
|
1839
|
+
* is.iterable('string') // true
|
|
1840
|
+
* is.iterable(123) // false
|
|
1841
|
+
*/
|
|
1842
|
+
iterable(value) {
|
|
1843
|
+
const object = Object(value);
|
|
1844
|
+
return object && Reflect.has(object, Symbol.iterator);
|
|
1845
|
+
},
|
|
1846
|
+
/**
|
|
1847
|
+
* Check if a value is null or undefined.
|
|
1848
|
+
*
|
|
1849
|
+
* @param value The value to check.
|
|
1850
|
+
* @returns True if the value is null or undefined, false otherwise.
|
|
1851
|
+
*
|
|
1852
|
+
* @example
|
|
1853
|
+
* is.nullish(null) // true
|
|
1854
|
+
* is.nullish(undefined) // true
|
|
1855
|
+
* is.nullish('value') // false
|
|
1856
|
+
*/
|
|
1857
|
+
nullish(value) {
|
|
1858
|
+
return value === null || value === void 0;
|
|
1859
|
+
},
|
|
1860
|
+
/**
|
|
1861
|
+
* Check if a value is a number.
|
|
1862
|
+
*
|
|
1863
|
+
* @param value The value to check.
|
|
1864
|
+
* @returns True if the value is a number, false otherwise.
|
|
1865
|
+
*
|
|
1866
|
+
* @example
|
|
1867
|
+
* is.number(123) // true
|
|
1868
|
+
* is.number('123') // false
|
|
1869
|
+
*/
|
|
1870
|
+
number(value) {
|
|
1871
|
+
return typeof value === "number" || value instanceof Number;
|
|
1872
|
+
},
|
|
1873
|
+
/**
|
|
1874
|
+
* Check if a value is an object.
|
|
1875
|
+
*
|
|
1876
|
+
* @param value The value to check.
|
|
1877
|
+
* @returns True if the value is an object, false otherwise.
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* is.object({}) // true
|
|
1881
|
+
* is.object(null) // false
|
|
1882
|
+
*/
|
|
1883
|
+
object(value) {
|
|
1884
|
+
return !!(value && typeof value === "object");
|
|
1885
|
+
},
|
|
1886
|
+
/**
|
|
1887
|
+
* The {@link Object#entries} function returns the properties of a given
|
|
1888
|
+
* value as an array of arrays where each element of the inner arrays is
|
|
1889
|
+
* a valid object key (so one of {@link String}, {@link Number}, or
|
|
1890
|
+
* {@link Symbol}) and the second element is the value of the pair which
|
|
1891
|
+
* can be any type.
|
|
1892
|
+
*
|
|
1893
|
+
* This function vets this criteria and would return true for each entry
|
|
1894
|
+
* in the returned outer array of a call to {@link Object#entries}.
|
|
1895
|
+
*
|
|
1896
|
+
* @param {any} value the value to test
|
|
1897
|
+
* @returns {boolean} true if the value is a valid object entry in the
|
|
1898
|
+
* form of `[key, value]`.
|
|
1899
|
+
*/
|
|
1900
|
+
objectEntry(value) {
|
|
1901
|
+
if (!// Must be an array
|
|
1902
|
+
(Array.isArray(value) && // Must have only two elements
|
|
1903
|
+
value.length == 2 && // Must have its first element be string|number|symbol
|
|
1904
|
+
(this.string(value[0]) || this.number(value[0]) || this.symbol(value[0])))) {
|
|
1905
|
+
return false;
|
|
1906
|
+
}
|
|
1907
|
+
return true;
|
|
1908
|
+
},
|
|
1909
|
+
/**
|
|
1910
|
+
* Check if a value is a valid object key. Valid object keys are strings,
|
|
1911
|
+
* numbers, or symbols — the same types accepted as property keys in
|
|
1912
|
+
* JavaScript objects.
|
|
1913
|
+
*
|
|
1914
|
+
* @param {*} value - The value to check.
|
|
1915
|
+
* @returns {boolean} True if the value is a string, number, or symbol,
|
|
1916
|
+
* false otherwise.
|
|
1917
|
+
*
|
|
1918
|
+
* @example
|
|
1919
|
+
* is.objectKey('name') // true
|
|
1920
|
+
* is.objectKey(0) // true
|
|
1921
|
+
* is.objectKey(Symbol('id')) // true
|
|
1922
|
+
* is.objectKey({}) // false
|
|
1923
|
+
* is.objectKey(null) // false
|
|
1924
|
+
*/
|
|
1925
|
+
objectKey(value) {
|
|
1926
|
+
return this.string(value) || this.number(value) || this.symbol(value);
|
|
1927
|
+
},
|
|
1928
|
+
/**
|
|
1929
|
+
* Check if a value is a primitive type.
|
|
1930
|
+
*
|
|
1931
|
+
* This function determines if the provided value is one of the JavaScript
|
|
1932
|
+
* primitive types: string, number, boolean, bigint, or symbol.
|
|
1933
|
+
*
|
|
1934
|
+
* @param value The value to check.
|
|
1935
|
+
* @returns True if the value is a primitive type, false otherwise.
|
|
1936
|
+
*
|
|
1937
|
+
* @example
|
|
1938
|
+
* // Returns true
|
|
1939
|
+
* is.primitive('hello')
|
|
1940
|
+
*
|
|
1941
|
+
* // Returns true
|
|
1942
|
+
* is.primitive(123)
|
|
1943
|
+
*
|
|
1944
|
+
* // Returns true
|
|
1945
|
+
* is.primitive(true)
|
|
1946
|
+
*
|
|
1947
|
+
* // Returns true
|
|
1948
|
+
* is.primitive(123n)
|
|
1949
|
+
*
|
|
1950
|
+
* // Returns true
|
|
1951
|
+
* is.primitive(Symbol('symbol'))
|
|
1952
|
+
*
|
|
1953
|
+
* // Returns false
|
|
1954
|
+
* is.primitive({})
|
|
1955
|
+
*
|
|
1956
|
+
* // Returns false
|
|
1957
|
+
* is.primitive([])
|
|
1958
|
+
*/
|
|
1959
|
+
primitive(value) {
|
|
1960
|
+
if (this.nullish(value))
|
|
1961
|
+
return true;
|
|
1962
|
+
return ["string", "number", "boolean", "bigint", "symbol"].some(
|
|
1963
|
+
(type) => typeof value === type
|
|
1964
|
+
);
|
|
1965
|
+
},
|
|
1966
|
+
/**
|
|
1967
|
+
* The use of `typeof` is not a safe guarantor when it comes to Reflect
|
|
1968
|
+
* supported values. Any non-null value that returns a `typeof` either
|
|
1969
|
+
* `object` or `function` should suffice. Note that arrays return 'object'
|
|
1970
|
+
* when run through `typeof`. Shiny is clearly a reference to something
|
|
1971
|
+
* reflective and is much shorter to type. Also, Mal says shiny. :)
|
|
1972
|
+
*
|
|
1973
|
+
* @param value The value to check.
|
|
1974
|
+
* @returns True if the value is an object or a function, false otherwise.
|
|
1975
|
+
*
|
|
1976
|
+
* @example
|
|
1977
|
+
* is.shiny({}) // true
|
|
1978
|
+
* is.shiny(function() {}) // true
|
|
1979
|
+
* is.shiny(123) // false
|
|
1980
|
+
*/
|
|
1981
|
+
shiny(value) {
|
|
1982
|
+
return !!(this.object(value) || this.function(value));
|
|
1983
|
+
},
|
|
1984
|
+
/**
|
|
1985
|
+
* Check if a value is a string.
|
|
1986
|
+
*
|
|
1987
|
+
* @param value The value to check.
|
|
1988
|
+
* @returns True if the value is a string, false otherwise.
|
|
1989
|
+
*
|
|
1990
|
+
* @example
|
|
1991
|
+
* is.string('hello') // true
|
|
1992
|
+
* is.string(123) // false
|
|
1993
|
+
*/
|
|
1994
|
+
string(value) {
|
|
1995
|
+
return typeof value === "string" || value instanceof String;
|
|
1996
|
+
},
|
|
1997
|
+
/**
|
|
1998
|
+
* Checks if a value is a symbol.
|
|
1999
|
+
*
|
|
2000
|
+
* This function determines whether the provided value is of type
|
|
2001
|
+
* 'symbol' or an instance of the Symbol object.
|
|
2002
|
+
*
|
|
2003
|
+
* @param value - The value to check.
|
|
2004
|
+
* @returns True if the value is a symbol, false otherwise.
|
|
2005
|
+
*
|
|
2006
|
+
* @example
|
|
2007
|
+
* is.symbol(Symbol('foo')) // Returns true
|
|
2008
|
+
* is.symbol('foo') // Returns false
|
|
2009
|
+
*/
|
|
2010
|
+
symbol(value) {
|
|
2011
|
+
return typeof value === "symbol" || value instanceof Symbol;
|
|
2012
|
+
},
|
|
2013
|
+
/**
|
|
2014
|
+
* Checks if a value is strictly true.
|
|
2015
|
+
*
|
|
2016
|
+
* This method verifies if the provided value is strictly `true`.
|
|
2017
|
+
*
|
|
2018
|
+
* @param {*} value - The value to check.
|
|
2019
|
+
* @returns {boolean} True if the value is strictly true, false otherwise.
|
|
2020
|
+
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* is.true(true) // true
|
|
2023
|
+
* is.true(false) // false
|
|
2024
|
+
* is.true(1) // false
|
|
2025
|
+
*/
|
|
2026
|
+
true(value) {
|
|
2027
|
+
return value === true;
|
|
2028
|
+
},
|
|
2029
|
+
/**
|
|
2030
|
+
* Checks if a value is truthy.
|
|
2031
|
+
*
|
|
2032
|
+
* This method converts the provided value to a boolean and returns
|
|
2033
|
+
* `true` if the value is truthy (i.e., not false, 0, "", null, undefined,
|
|
2034
|
+
* or NaN).
|
|
2035
|
+
*
|
|
2036
|
+
* @param {*} value - The value to check.
|
|
2037
|
+
* @returns {boolean} True if the value is truthy, false otherwise.
|
|
2038
|
+
*
|
|
2039
|
+
* @example
|
|
2040
|
+
* is.truthy(1) // true
|
|
2041
|
+
* is.truthy("hello") // true
|
|
2042
|
+
* is.truthy(0) // false
|
|
2043
|
+
* is.truthy("") // false
|
|
2044
|
+
*/
|
|
2045
|
+
truthy(value) {
|
|
2046
|
+
return !!value;
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
var si = {
|
|
2050
|
+
/**
|
|
2051
|
+
* Inline if-then-else based on whether value matches a specified type or
|
|
2052
|
+
* class. Delegates the condition check to {@link is#a}.
|
|
2053
|
+
*
|
|
2054
|
+
* @param {*} value - The value to check.
|
|
2055
|
+
* @param {*} typeOrClass - The type or class to compare against.
|
|
2056
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2057
|
+
* returned) if value matches typeOrClass.
|
|
2058
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2059
|
+
* returned) if value does not match typeOrClass.
|
|
2060
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2061
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2062
|
+
* its return value is used instead.
|
|
2063
|
+
*
|
|
2064
|
+
* @example
|
|
2065
|
+
* si.a(42, 'number', 'yes', 'no') // 'yes'
|
|
2066
|
+
* si.a('str', Number, 'yes', 'no') // 'no'
|
|
2067
|
+
* si.a(42, 'number', () => 'computed', 'no') // 'computed'
|
|
2068
|
+
*/
|
|
2069
|
+
a(value, typeOrClass, thenValue, elseValue) {
|
|
2070
|
+
return ifThenElse(is.a(value, typeOrClass), thenValue, elseValue);
|
|
2071
|
+
},
|
|
2072
|
+
/**
|
|
2073
|
+
* Inline if-then-else based on whether value is an accessor descriptor.
|
|
2074
|
+
* Delegates the condition check to {@link is#accessorDescriptor}.
|
|
2075
|
+
*
|
|
2076
|
+
* @param {*} value - The value to check.
|
|
2077
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2078
|
+
* returned) if value is an accessor descriptor.
|
|
2079
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2080
|
+
* returned) if value is not an accessor descriptor.
|
|
2081
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2082
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2083
|
+
* its return value is used instead.
|
|
2084
|
+
*
|
|
2085
|
+
* @example
|
|
2086
|
+
* si.accessorDescriptor({ get: () => 42 }, 'yes', 'no') // 'yes'
|
|
2087
|
+
* si.accessorDescriptor({ value: 42 }, 'yes', 'no') // 'no'
|
|
2088
|
+
* si.accessorDescriptor({ get: () => 42 }, () => 'computed', 'no') // 'computed'
|
|
2089
|
+
*/
|
|
2090
|
+
accessorDescriptor(value, thenValue, elseValue) {
|
|
2091
|
+
return ifThenElse(is.accessorDescriptor(value), thenValue, elseValue);
|
|
2092
|
+
},
|
|
2093
|
+
/**
|
|
2094
|
+
* Inline if-then-else based on whether value is an array.
|
|
2095
|
+
* Delegates the condition check to {@link is#array}.
|
|
2096
|
+
*
|
|
2097
|
+
* @param {*} value - The value to check.
|
|
2098
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2099
|
+
* returned) if value is an array.
|
|
2100
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2101
|
+
* returned) if value is not an array.
|
|
2102
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2103
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2104
|
+
* its return value is used instead.
|
|
2105
|
+
*
|
|
2106
|
+
* @example
|
|
2107
|
+
* si.array([1, 2, 3], 'yes', 'no') // 'yes'
|
|
2108
|
+
* si.array('string', 'yes', 'no') // 'no'
|
|
2109
|
+
* si.array([1, 2, 3], () => 'computed', 'no') // 'computed'
|
|
2110
|
+
*/
|
|
2111
|
+
array(value, thenValue, elseValue) {
|
|
2112
|
+
return ifThenElse(is.array(value), thenValue, elseValue);
|
|
2113
|
+
},
|
|
2114
|
+
/**
|
|
2115
|
+
* Inline if-then-else based on whether value is a bigint.
|
|
2116
|
+
* Delegates the condition check to {@link is#bigint}.
|
|
2117
|
+
*
|
|
2118
|
+
* @param {*} value - The value to check.
|
|
2119
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2120
|
+
* returned) if value is a bigint.
|
|
2121
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2122
|
+
* returned) if value is not a bigint.
|
|
2123
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2124
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2125
|
+
* its return value is used instead.
|
|
2126
|
+
*
|
|
2127
|
+
* @example
|
|
2128
|
+
* si.bigint(123n, 'yes', 'no') // 'yes'
|
|
2129
|
+
* si.bigint(123, 'yes', 'no') // 'no'
|
|
2130
|
+
* si.bigint(123n, () => 'computed', 'no') // 'computed'
|
|
2131
|
+
*/
|
|
2132
|
+
bigint(value, thenValue, elseValue) {
|
|
2133
|
+
return ifThenElse(is.bigint(value), thenValue, elseValue);
|
|
2134
|
+
},
|
|
2135
|
+
/**
|
|
2136
|
+
* Inline if-then-else based on whether value is a boolean.
|
|
2137
|
+
* Delegates the condition check to {@link is#boolean}.
|
|
2138
|
+
*
|
|
2139
|
+
* @param {*} value - The value to check.
|
|
2140
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2141
|
+
* returned) if value is a boolean.
|
|
2142
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2143
|
+
* returned) if value is not a boolean.
|
|
2144
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2145
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2146
|
+
* its return value is used instead.
|
|
2147
|
+
*
|
|
2148
|
+
* @example
|
|
2149
|
+
* si.boolean(true, 'yes', 'no') // 'yes'
|
|
2150
|
+
* si.boolean(1, 'yes', 'no') // 'no'
|
|
2151
|
+
* si.boolean(false, () => 'computed', 'no') // 'computed'
|
|
2152
|
+
*/
|
|
2153
|
+
boolean(value, thenValue, elseValue) {
|
|
2154
|
+
return ifThenElse(is.boolean(value), thenValue, elseValue);
|
|
2155
|
+
},
|
|
2156
|
+
/**
|
|
2157
|
+
* Inline if-then-else based on whether object is callable.
|
|
2158
|
+
* Delegates the condition check to {@link is#callable}.
|
|
2159
|
+
*
|
|
2160
|
+
* @param {*} object - The object to check.
|
|
2161
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2162
|
+
* returned) if object is callable.
|
|
2163
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2164
|
+
* returned) if object is not callable.
|
|
2165
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2166
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2167
|
+
* its return value is used instead.
|
|
2168
|
+
*
|
|
2169
|
+
* @example
|
|
2170
|
+
* si.callable(function() {}, 'yes', 'no') // 'yes'
|
|
2171
|
+
* si.callable(123, 'yes', 'no') // 'no'
|
|
2172
|
+
* si.callable(function() {}, () => 'computed', 'no') // 'computed'
|
|
2173
|
+
*/
|
|
2174
|
+
callable(object, thenValue, elseValue) {
|
|
2175
|
+
return ifThenElse(is.callable(object), thenValue, elseValue);
|
|
2176
|
+
},
|
|
2177
|
+
/**
|
|
2178
|
+
* Inline if-then-else based on whether object is a callable descriptor.
|
|
2179
|
+
* Delegates the condition check to {@link is#callableDescriptor}.
|
|
2180
|
+
*
|
|
2181
|
+
* @param {*} object - The object to check.
|
|
2182
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2183
|
+
* returned) if object is a callable descriptor.
|
|
2184
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2185
|
+
* returned) if object is not a callable descriptor.
|
|
2186
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2187
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2188
|
+
* its return value is used instead.
|
|
2189
|
+
*
|
|
2190
|
+
* @example
|
|
2191
|
+
* si.callableDescriptor({ get: function() {} }, 'yes', 'no') // 'yes'
|
|
2192
|
+
* si.callableDescriptor(123, 'yes', 'no') // 'no'
|
|
2193
|
+
* si.callableDescriptor({ get: function() {} }, () => 'computed', 'no') // 'computed'
|
|
2194
|
+
*/
|
|
2195
|
+
callableDescriptor(object, thenValue, elseValue) {
|
|
2196
|
+
return ifThenElse(is.callableDescriptor(object), thenValue, elseValue);
|
|
2197
|
+
},
|
|
2198
|
+
/**
|
|
2199
|
+
* Inline if-then-else based on whether value is a data property descriptor.
|
|
2200
|
+
* Delegates the condition check to {@link is#dataDescriptor}.
|
|
2201
|
+
*
|
|
2202
|
+
* @param {*} value - The value to check.
|
|
2203
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2204
|
+
* returned) if value is a data descriptor.
|
|
2205
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2206
|
+
* returned) if value is not a data descriptor.
|
|
2207
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2208
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2209
|
+
* its return value is used instead.
|
|
2210
|
+
*
|
|
2211
|
+
* @example
|
|
2212
|
+
* si.dataDescriptor({ value: 42, writable: true }, 'yes', 'no') // 'yes'
|
|
2213
|
+
* si.dataDescriptor({ get: () => 42 }, 'yes', 'no') // 'no'
|
|
2214
|
+
* si.dataDescriptor({ value: 42 }, () => 'computed', 'no') // 'computed'
|
|
2215
|
+
*/
|
|
2216
|
+
dataDescriptor(value, thenValue, elseValue) {
|
|
2217
|
+
return ifThenElse(is.dataDescriptor(value), thenValue, elseValue);
|
|
2218
|
+
},
|
|
2219
|
+
/**
|
|
2220
|
+
* Inline if-then-else based on whether value is a property descriptor.
|
|
2221
|
+
* Delegates the condition check to {@link is#descriptor}.
|
|
2222
|
+
*
|
|
2223
|
+
* @param {*} value - The value to check.
|
|
2224
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2225
|
+
* returned) if value is a property descriptor.
|
|
2226
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2227
|
+
* returned) if value is not a property descriptor.
|
|
2228
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2229
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2230
|
+
* its return value is used instead.
|
|
2231
|
+
*
|
|
2232
|
+
* @example
|
|
2233
|
+
* si.descriptor({ configurable: true }, 'yes', 'no') // 'yes'
|
|
2234
|
+
* si.descriptor({}, 'yes', 'no') // 'no'
|
|
2235
|
+
* si.descriptor({ get: () => {} }, () => 'computed', 'no') // 'computed'
|
|
2236
|
+
*/
|
|
2237
|
+
descriptor(value, thenValue, elseValue) {
|
|
2238
|
+
return ifThenElse(is.descriptor(value), thenValue, elseValue);
|
|
2239
|
+
},
|
|
2240
|
+
/**
|
|
2241
|
+
* Inline if-then-else based on whether value is strictly false.
|
|
2242
|
+
* Delegates the condition check to {@link is#false}.
|
|
2243
|
+
*
|
|
2244
|
+
* @param {*} value - The value to check.
|
|
2245
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2246
|
+
* returned) if value is strictly false.
|
|
2247
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2248
|
+
* returned) if value is not strictly false.
|
|
2249
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2250
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2251
|
+
* its return value is used instead.
|
|
2252
|
+
*
|
|
2253
|
+
* @example
|
|
2254
|
+
* si.false(false, 'yes', 'no') // 'yes'
|
|
2255
|
+
* si.false(0, 'yes', 'no') // 'no'
|
|
2256
|
+
* si.false(false, () => 'computed', 'no') // 'computed'
|
|
2257
|
+
*/
|
|
2258
|
+
false(value, thenValue, elseValue) {
|
|
2259
|
+
return ifThenElse(is.false(value), thenValue, elseValue);
|
|
2260
|
+
},
|
|
2261
|
+
/**
|
|
2262
|
+
* Inline if-then-else based on whether value is falsy.
|
|
2263
|
+
* Delegates the condition check to {@link is#falsy}.
|
|
2264
|
+
*
|
|
2265
|
+
* @param {*} value - The value to check.
|
|
2266
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2267
|
+
* returned) if value is falsy.
|
|
2268
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2269
|
+
* returned) if value is not falsy.
|
|
2270
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2271
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2272
|
+
* its return value is used instead.
|
|
2273
|
+
*
|
|
2274
|
+
* @example
|
|
2275
|
+
* si.falsy(0, 'yes', 'no') // 'yes'
|
|
2276
|
+
* si.falsy(1, 'yes', 'no') // 'no'
|
|
2277
|
+
* si.falsy('', () => 'computed', 'no') // 'computed'
|
|
2278
|
+
*/
|
|
2279
|
+
falsy(value, thenValue, elseValue) {
|
|
2280
|
+
return ifThenElse(is.falsy(value), thenValue, elseValue);
|
|
2281
|
+
},
|
|
2282
|
+
/**
|
|
2283
|
+
* Alias for {@link si#falsy}. Inline if-then-else based on whether value
|
|
2284
|
+
* is falsy. Delegates the condition check to {@link is#falsey}.
|
|
2285
|
+
*
|
|
2286
|
+
* @param {*} value - The value to check.
|
|
2287
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2288
|
+
* returned) if value is falsy.
|
|
2289
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2290
|
+
* returned) if value is not falsy.
|
|
2291
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2292
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2293
|
+
* its return value is used instead.
|
|
2294
|
+
*
|
|
2295
|
+
* @example
|
|
2296
|
+
* si.falsey(0, 'yes', 'no') // 'yes'
|
|
2297
|
+
* si.falsey(1, 'yes', 'no') // 'no'
|
|
2298
|
+
* si.falsey('', () => 'computed', 'no') // 'computed'
|
|
2299
|
+
*/
|
|
2300
|
+
falsey(value, thenValue, elseValue) {
|
|
2301
|
+
return ifThenElse(is.falsey(value), thenValue, elseValue);
|
|
2302
|
+
},
|
|
2303
|
+
/**
|
|
2304
|
+
* Inline if-then-else based on whether value is a function.
|
|
2305
|
+
* Delegates the condition check to {@link is#function}.
|
|
2306
|
+
*
|
|
2307
|
+
* @param {*} value - The value to check.
|
|
2308
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2309
|
+
* returned) if value is a function.
|
|
2310
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2311
|
+
* returned) if value is not a function.
|
|
2312
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2313
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2314
|
+
* its return value is used instead.
|
|
2315
|
+
*
|
|
2316
|
+
* @example
|
|
2317
|
+
* si.function(function() {}, 'yes', 'no') // 'yes'
|
|
2318
|
+
* si.function(123, 'yes', 'no') // 'no'
|
|
2319
|
+
* si.function(function() {}, () => 'computed', 'no') // 'computed'
|
|
2320
|
+
*/
|
|
2321
|
+
function(value, thenValue, elseValue) {
|
|
2322
|
+
return ifThenElse(is.function(value), thenValue, elseValue);
|
|
2323
|
+
},
|
|
2324
|
+
/**
|
|
2325
|
+
* Inline if-then-else based on whether value is iterable.
|
|
2326
|
+
* Delegates the condition check to {@link is#iterable}.
|
|
2327
|
+
*
|
|
2328
|
+
* @param {*} value - The value to check.
|
|
2329
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2330
|
+
* returned) if value is iterable.
|
|
2331
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2332
|
+
* returned) if value is not iterable.
|
|
2333
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2334
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2335
|
+
* its return value is used instead.
|
|
2336
|
+
*
|
|
2337
|
+
* @example
|
|
2338
|
+
* si.iterable([1, 2, 3], 'yes', 'no') // 'yes'
|
|
2339
|
+
* si.iterable(123, 'yes', 'no') // 'no'
|
|
2340
|
+
* si.iterable('string', () => 'computed', 'no') // 'computed'
|
|
2341
|
+
*/
|
|
2342
|
+
iterable(value, thenValue, elseValue) {
|
|
2343
|
+
return ifThenElse(is.iterable(value), thenValue, elseValue);
|
|
2344
|
+
},
|
|
2345
|
+
/**
|
|
2346
|
+
* Inline if-then-else based on whether value is null or undefined.
|
|
2347
|
+
* Delegates the condition check to {@link is#nullish}.
|
|
2348
|
+
*
|
|
2349
|
+
* @param {*} value - The value to check.
|
|
2350
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2351
|
+
* returned) if value is nullish.
|
|
2352
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2353
|
+
* returned) if value is not nullish.
|
|
2354
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2355
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2356
|
+
* its return value is used instead.
|
|
2357
|
+
*
|
|
2358
|
+
* @example
|
|
2359
|
+
* si.nullish(null, 'yes', 'no') // 'yes'
|
|
2360
|
+
* si.nullish('value', 'yes', 'no') // 'no'
|
|
2361
|
+
* si.nullish(undefined, () => 'computed', 'no') // 'computed'
|
|
2362
|
+
*/
|
|
2363
|
+
nullish(value, thenValue, elseValue) {
|
|
2364
|
+
return ifThenElse(is.nullish(value), thenValue, elseValue);
|
|
2365
|
+
},
|
|
2366
|
+
/**
|
|
2367
|
+
* Inline if-then-else based on whether value is a number.
|
|
2368
|
+
* Delegates the condition check to {@link is#number}.
|
|
2369
|
+
*
|
|
2370
|
+
* @param {*} value - The value to check.
|
|
2371
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2372
|
+
* returned) if value is a number.
|
|
2373
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2374
|
+
* returned) if value is not a number.
|
|
2375
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2376
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2377
|
+
* its return value is used instead.
|
|
2378
|
+
*
|
|
2379
|
+
* @example
|
|
2380
|
+
* si.number(123, 'yes', 'no') // 'yes'
|
|
2381
|
+
* si.number('123', 'yes', 'no') // 'no'
|
|
2382
|
+
* si.number(123, () => 'computed', 'no') // 'computed'
|
|
2383
|
+
*/
|
|
2384
|
+
number(value, thenValue, elseValue) {
|
|
2385
|
+
return ifThenElse(is.number(value), thenValue, elseValue);
|
|
2386
|
+
},
|
|
2387
|
+
/**
|
|
2388
|
+
* Inline if-then-else based on whether value is an object.
|
|
2389
|
+
* Delegates the condition check to {@link is#object}.
|
|
2390
|
+
*
|
|
2391
|
+
* @param {*} value - The value to check.
|
|
2392
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2393
|
+
* returned) if value is an object.
|
|
2394
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2395
|
+
* returned) if value is not an object.
|
|
2396
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2397
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2398
|
+
* its return value is used instead.
|
|
2399
|
+
*
|
|
2400
|
+
* @example
|
|
2401
|
+
* si.object({}, 'yes', 'no') // 'yes'
|
|
2402
|
+
* si.object(null, 'yes', 'no') // 'no'
|
|
2403
|
+
* si.object({}, () => 'computed', 'no') // 'computed'
|
|
2404
|
+
*/
|
|
2405
|
+
object(value, thenValue, elseValue) {
|
|
2406
|
+
return ifThenElse(is.object(value), thenValue, elseValue);
|
|
2407
|
+
},
|
|
2408
|
+
/**
|
|
2409
|
+
* Inline if-then-else based on whether value is a valid object entry.
|
|
2410
|
+
* Delegates the condition check to {@link is#objectEntry}.
|
|
2411
|
+
*
|
|
2412
|
+
* @param {any} value - The value to check.
|
|
2413
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2414
|
+
* returned) if value is a valid object entry.
|
|
2415
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2416
|
+
* returned) if value is not a valid object entry.
|
|
2417
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2418
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2419
|
+
* its return value is used instead.
|
|
2420
|
+
*
|
|
2421
|
+
* @example
|
|
2422
|
+
* si.objectEntry(['key', 42], 'yes', 'no') // 'yes'
|
|
2423
|
+
* si.objectEntry([1, 2, 3], 'yes', 'no') // 'no'
|
|
2424
|
+
* si.objectEntry(['key', 42], () => 'computed', 'no') // 'computed'
|
|
2425
|
+
*/
|
|
2426
|
+
objectEntry(value, thenValue, elseValue) {
|
|
2427
|
+
return ifThenElse(is.objectEntry(value), thenValue, elseValue);
|
|
2428
|
+
},
|
|
2429
|
+
/**
|
|
2430
|
+
* Inline if-then-else based on whether value is a valid object key.
|
|
2431
|
+
* Delegates the condition check to {@link is#objectKey}.
|
|
2432
|
+
*
|
|
2433
|
+
* @param {*} value - The value to check.
|
|
2434
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2435
|
+
* returned) if value is a valid object key.
|
|
2436
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2437
|
+
* returned) if value is not a valid object key.
|
|
2438
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2439
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2440
|
+
* its return value is used instead.
|
|
2441
|
+
*
|
|
2442
|
+
* @example
|
|
2443
|
+
* si.objectKey('name', 'yes', 'no') // 'yes'
|
|
2444
|
+
* si.objectKey({}, 'yes', 'no') // 'no'
|
|
2445
|
+
* si.objectKey(Symbol('id'), () => 'computed', 'no') // 'computed'
|
|
2446
|
+
*/
|
|
2447
|
+
objectKey(value, thenValue, elseValue) {
|
|
2448
|
+
return ifThenElse(is.objectKey(value), thenValue, elseValue);
|
|
2449
|
+
},
|
|
2450
|
+
/**
|
|
2451
|
+
* Inline if-then-else based on whether value is a primitive type.
|
|
2452
|
+
* Delegates the condition check to {@link is#primitive}.
|
|
2453
|
+
*
|
|
2454
|
+
* @param {*} value - The value to check.
|
|
2455
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2456
|
+
* returned) if value is a primitive.
|
|
2457
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2458
|
+
* returned) if value is not a primitive.
|
|
2459
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2460
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2461
|
+
* its return value is used instead.
|
|
2462
|
+
*
|
|
2463
|
+
* @example
|
|
2464
|
+
* si.primitive('hello', 'yes', 'no') // 'yes'
|
|
2465
|
+
* si.primitive({}, 'yes', 'no') // 'no'
|
|
2466
|
+
* si.primitive(123, () => 'computed', 'no') // 'computed'
|
|
2467
|
+
*/
|
|
2468
|
+
primitive(value, thenValue, elseValue) {
|
|
2469
|
+
return ifThenElse(is.primitive(value), thenValue, elseValue);
|
|
2470
|
+
},
|
|
2471
|
+
/**
|
|
2472
|
+
* Inline if-then-else based on whether value is shiny (object or function).
|
|
2473
|
+
* Delegates the condition check to {@link is#shiny}.
|
|
2474
|
+
*
|
|
2475
|
+
* @param {*} value - The value to check.
|
|
2476
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2477
|
+
* returned) if value is shiny.
|
|
2478
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2479
|
+
* returned) if value is not shiny.
|
|
2480
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2481
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2482
|
+
* its return value is used instead.
|
|
2483
|
+
*
|
|
2484
|
+
* @example
|
|
2485
|
+
* si.shiny({}, 'yes', 'no') // 'yes'
|
|
2486
|
+
* si.shiny(123, 'yes', 'no') // 'no'
|
|
2487
|
+
* si.shiny(function() {}, () => 'computed', 'no') // 'computed'
|
|
2488
|
+
*/
|
|
2489
|
+
shiny(value, thenValue, elseValue) {
|
|
2490
|
+
return ifThenElse(is.shiny(value), thenValue, elseValue);
|
|
2491
|
+
},
|
|
2492
|
+
/**
|
|
2493
|
+
* Inline if-then-else based on whether value is a string.
|
|
2494
|
+
* Delegates the condition check to {@link is#string}.
|
|
2495
|
+
*
|
|
2496
|
+
* @param {*} value - The value to check.
|
|
2497
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2498
|
+
* returned) if value is a string.
|
|
2499
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2500
|
+
* returned) if value is not a string.
|
|
2501
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2502
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2503
|
+
* its return value is used instead.
|
|
2504
|
+
*
|
|
2505
|
+
* @example
|
|
2506
|
+
* si.string('hello', 'yes', 'no') // 'yes'
|
|
2507
|
+
* si.string(123, 'yes', 'no') // 'no'
|
|
2508
|
+
* si.string('hello', () => 'computed', 'no') // 'computed'
|
|
2509
|
+
*/
|
|
2510
|
+
string(value, thenValue, elseValue) {
|
|
2511
|
+
return ifThenElse(is.string(value), thenValue, elseValue);
|
|
2512
|
+
},
|
|
2513
|
+
/**
|
|
2514
|
+
* Inline if-then-else based on whether value is a symbol.
|
|
2515
|
+
* Delegates the condition check to {@link is#symbol}.
|
|
2516
|
+
*
|
|
2517
|
+
* @param {*} value - The value to check.
|
|
2518
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2519
|
+
* returned) if value is a symbol.
|
|
2520
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2521
|
+
* returned) if value is not a symbol.
|
|
2522
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2523
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2524
|
+
* its return value is used instead.
|
|
2525
|
+
*
|
|
2526
|
+
* @example
|
|
2527
|
+
* si.symbol(Symbol('foo'), 'yes', 'no') // 'yes'
|
|
2528
|
+
* si.symbol('foo', 'yes', 'no') // 'no'
|
|
2529
|
+
* si.symbol(Symbol('foo'), () => 'computed', 'no') // 'computed'
|
|
2530
|
+
*/
|
|
2531
|
+
symbol(value, thenValue, elseValue) {
|
|
2532
|
+
return ifThenElse(is.symbol(value), thenValue, elseValue);
|
|
2533
|
+
},
|
|
2534
|
+
/**
|
|
2535
|
+
* Inline if-then-else using an arbitrary condition. If condition is a
|
|
2536
|
+
* function, it is called and its result is used as the condition; otherwise
|
|
2537
|
+
* the condition value is evaluated directly.
|
|
2538
|
+
*
|
|
2539
|
+
* @param {function|*} condition - The condition to evaluate. If a function,
|
|
2540
|
+
* it is called and its return value is used as the condition.
|
|
2541
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2542
|
+
* returned) if the condition is truthy.
|
|
2543
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2544
|
+
* returned) if the condition is falsy.
|
|
2545
|
+
* @returns {*} The result of thenValue if the condition is truthy,
|
|
2546
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2547
|
+
* its return value is used instead.
|
|
2548
|
+
*
|
|
2549
|
+
* @example
|
|
2550
|
+
* si.then(true, 'yes', 'no') // 'yes'
|
|
2551
|
+
* si.then(false, 'yes', 'no') // 'no'
|
|
2552
|
+
* si.then(() => true, 'yes', 'no') // 'yes'
|
|
2553
|
+
* si.then(() => false, () => 'computed', 'no') // 'no'
|
|
2554
|
+
*/
|
|
2555
|
+
then(condition, thenValue, elseValue) {
|
|
2556
|
+
return ifThenElse(
|
|
2557
|
+
is.function(condition) ? condition() : condition,
|
|
2558
|
+
thenValue,
|
|
2559
|
+
elseValue
|
|
2560
|
+
);
|
|
2561
|
+
},
|
|
2562
|
+
/**
|
|
2563
|
+
* Inline if-then-else based on whether value is strictly true.
|
|
2564
|
+
* Delegates the condition check to {@link is#true}.
|
|
2565
|
+
*
|
|
2566
|
+
* @param {*} value - The value to check.
|
|
2567
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2568
|
+
* returned) if value is strictly true.
|
|
2569
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2570
|
+
* returned) if value is not strictly true.
|
|
2571
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2572
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2573
|
+
* its return value is used instead.
|
|
2574
|
+
*
|
|
2575
|
+
* @example
|
|
2576
|
+
* si.true(true, 'yes', 'no') // 'yes'
|
|
2577
|
+
* si.true(1, 'yes', 'no') // 'no'
|
|
2578
|
+
* si.true(true, () => 'computed', 'no') // 'computed'
|
|
2579
|
+
*/
|
|
2580
|
+
true(value, thenValue, elseValue) {
|
|
2581
|
+
return ifThenElse(is.true(value), thenValue, elseValue);
|
|
2582
|
+
},
|
|
2583
|
+
/**
|
|
2584
|
+
* Inline if-then-else based on whether value is truthy.
|
|
2585
|
+
* Delegates the condition check to {@link is#truthy}.
|
|
2586
|
+
*
|
|
2587
|
+
* @param {*} value - The value to check.
|
|
2588
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2589
|
+
* returned) if value is truthy.
|
|
2590
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2591
|
+
* returned) if value is not truthy.
|
|
2592
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2593
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2594
|
+
* its return value is used instead.
|
|
2595
|
+
*
|
|
2596
|
+
* @example
|
|
2597
|
+
* si.truthy(1, 'yes', 'no') // 'yes'
|
|
2598
|
+
* si.truthy(0, 'yes', 'no') // 'no'
|
|
2599
|
+
* si.truthy("hello", () => 'computed', 'no') // 'computed'
|
|
2600
|
+
*/
|
|
2601
|
+
truthy(value, thenValue, elseValue) {
|
|
2602
|
+
return ifThenElse(is.truthy(value), thenValue, elseValue);
|
|
2603
|
+
},
|
|
2604
|
+
/**
|
|
2605
|
+
* Inline if-then-else based on whether value is undefined.
|
|
2606
|
+
* Delegates the condition check to {@link is#a} with type 'undefined'.
|
|
2607
|
+
*
|
|
2608
|
+
* @param {*} value - The value to check.
|
|
2609
|
+
* @param {function|*} thenValue - Returned (or called and its result
|
|
2610
|
+
* returned) if value is undefined.
|
|
2611
|
+
* @param {function|*} elseValue - Returned (or called and its result
|
|
2612
|
+
* returned) if value is not undefined.
|
|
2613
|
+
* @returns {*} The result of thenValue if the condition is true,
|
|
2614
|
+
* elseValue otherwise. If thenValue or elseValue is a function,
|
|
2615
|
+
* its return value is used instead.
|
|
2616
|
+
*
|
|
2617
|
+
* @example
|
|
2618
|
+
* si.undefined(undefined, 'yes', 'no') // 'yes'
|
|
2619
|
+
* si.undefined('value', 'yes', 'no') // 'no'
|
|
2620
|
+
* si.undefined(undefined, () => 'computed', 'no') // 'computed'
|
|
2621
|
+
*/
|
|
2622
|
+
undefined(value, thenValue, elseValue) {
|
|
2623
|
+
return ifThenElse(is.a(value, "undefined"), thenValue, elseValue);
|
|
2624
|
+
}
|
|
2625
|
+
};
|
|
2626
|
+
var has = function has2(object, key) {
|
|
2627
|
+
if ([Map, Set, WeakMap, WeakSet].some((i) => object instanceof i)) {
|
|
2628
|
+
return object.has(key);
|
|
2629
|
+
}
|
|
2630
|
+
return is.shiny(object) && Reflect.has(object, key);
|
|
2631
|
+
};
|
|
2632
|
+
Object.assign(has, {
|
|
2633
|
+
/**
|
|
2634
|
+
* Checks if an object contains all specified keys.
|
|
2635
|
+
*
|
|
2636
|
+
* This function determines if the provided object contains all the keys
|
|
2637
|
+
* specified in the keys array. It supports various types of objects
|
|
2638
|
+
* including Map, Set, WeakMap, and WeakSet. For other objects, it uses
|
|
2639
|
+
* the Reflect API to check for the keys.
|
|
2640
|
+
*
|
|
2641
|
+
* @param object The object to check.
|
|
2642
|
+
* @param keys The array of keys to look for in the object.
|
|
2643
|
+
* @returns True if the object contains all the keys, false otherwise.
|
|
2644
|
+
*
|
|
2645
|
+
* @example
|
|
2646
|
+
* // Returns true
|
|
2647
|
+
* has.all(new Map([
|
|
2648
|
+
* ['key1', 'value1'], ['key2', 'value2']
|
|
2649
|
+
* ]), ['key1', 'key2'])
|
|
2650
|
+
*
|
|
2651
|
+
* @example
|
|
2652
|
+
* // Returns false
|
|
2653
|
+
* has.all({}, ['key1', 'key2'])
|
|
2654
|
+
*/
|
|
2655
|
+
all(object, keys) {
|
|
2656
|
+
if (!is.shiny(object) || !is.array(keys) || !keys.length) {
|
|
2657
|
+
return false;
|
|
2658
|
+
}
|
|
2659
|
+
return keys.every((key) => has(object, key));
|
|
2660
|
+
},
|
|
2661
|
+
/**
|
|
2662
|
+
* Checks if an object contains at least one of the specified keys.
|
|
2663
|
+
*
|
|
2664
|
+
* This function determines if the provided object contains at least one
|
|
2665
|
+
* of the keys specified in the keys array. It supports various types of
|
|
2666
|
+
* objects including Map, Set, WeakMap, and WeakSet. For other objects,
|
|
2667
|
+
* it uses the Reflect API to check for the keys.
|
|
2668
|
+
*
|
|
2669
|
+
* @param object The object to check.
|
|
2670
|
+
* @param keys The array of keys to look for in the object.
|
|
2671
|
+
* @returns True if the object contains at least one of the keys, false
|
|
2672
|
+
* otherwise.
|
|
2673
|
+
*
|
|
2674
|
+
* @example
|
|
2675
|
+
* // Returns true
|
|
2676
|
+
* has.some(new Map([['key1', 'value1'], ['key2', 'value2']]), ['key1'])
|
|
2677
|
+
*
|
|
2678
|
+
* @example
|
|
2679
|
+
* // Returns false
|
|
2680
|
+
* has.some({}, ['key1', 'key2'])
|
|
2681
|
+
*/
|
|
2682
|
+
some(object, keys) {
|
|
2683
|
+
if (!is.shiny(object) || !is.array(keys) || !keys.length) {
|
|
2684
|
+
return false;
|
|
2685
|
+
}
|
|
2686
|
+
return keys.some((key) => has(object, key));
|
|
2687
|
+
},
|
|
2688
|
+
/**
|
|
2689
|
+
* Checks if an object has a 'prototype' property.
|
|
2690
|
+
*
|
|
2691
|
+
* This function is one way to determine if a supplied function is a big
|
|
2692
|
+
* arrow function or not. Regular functions and class functions, both
|
|
2693
|
+
* static and instance level, all have prototypes. Only big arrow functions
|
|
2694
|
+
* do not.
|
|
2695
|
+
*
|
|
2696
|
+
* @param {Object} object - The object to check.
|
|
2697
|
+
* @returns {boolean} True if the object has a 'prototype' property,
|
|
2698
|
+
* false otherwise.
|
|
2699
|
+
*
|
|
2700
|
+
* @example
|
|
2701
|
+
* // Returns true
|
|
2702
|
+
* has.prototype(function() {})
|
|
2703
|
+
*
|
|
2704
|
+
* @example
|
|
2705
|
+
* // Returns false
|
|
2706
|
+
* has.prototype(() => {})
|
|
2707
|
+
* has.prototype(5)
|
|
2708
|
+
* has.prototype(true)
|
|
2709
|
+
*/
|
|
2710
|
+
prototype(object) {
|
|
2711
|
+
return is.shiny(object) && has(object, "prototype");
|
|
2712
|
+
},
|
|
2713
|
+
/**
|
|
2714
|
+
* Checks if an object has a custom string tag.
|
|
2715
|
+
*
|
|
2716
|
+
* This method determines if the object has a Symbol.toStringTag property,
|
|
2717
|
+
* which is used to customize the behavior of Object.prototype.toString().
|
|
2718
|
+
*
|
|
2719
|
+
* @param object - The object to check.
|
|
2720
|
+
* @returns True if the object has a custom string tag, false otherwise.
|
|
2721
|
+
*
|
|
2722
|
+
* @example
|
|
2723
|
+
* const obj = { [Symbol.toStringTag]: 'CustomObject' }
|
|
2724
|
+
* has.stringTag(obj) // Returns true
|
|
2725
|
+
*/
|
|
2726
|
+
stringTag(object) {
|
|
2727
|
+
return is.object(object) && has(object, Symbol.toStringTag);
|
|
2728
|
+
},
|
|
2729
|
+
/**
|
|
2730
|
+
* Checks if an object has a custom toPrimitive method.
|
|
2731
|
+
*
|
|
2732
|
+
* This method determines if the object has a Symbol.toPrimitive property,
|
|
2733
|
+
* which is used to convert an object to a primitive value.
|
|
2734
|
+
*
|
|
2735
|
+
* @param object - The object to check.
|
|
2736
|
+
* @returns True if the object has a custom toPrimitive method,
|
|
2737
|
+
* false otherwise.
|
|
2738
|
+
*
|
|
2739
|
+
* @example
|
|
2740
|
+
* const obj = { [Symbol.toPrimitive]: () => 42 }
|
|
2741
|
+
* has.toPrimitive(obj) // Returns true
|
|
2742
|
+
*/
|
|
2743
|
+
toPrimitive(object) {
|
|
2744
|
+
return is.object(object) && has(object, Symbol.toPrimitive);
|
|
2745
|
+
},
|
|
2746
|
+
/**
|
|
2747
|
+
* Checks if an object has a custom valueOf method.
|
|
2748
|
+
*
|
|
2749
|
+
* This method determines if the object has a valueOf property that is a
|
|
2750
|
+
* function, which is used to convert an object to a primitive value.
|
|
2751
|
+
*
|
|
2752
|
+
* @param object - The object to check.
|
|
2753
|
+
* @returns True if the object has a custom valueOf method, false otherwise.
|
|
2754
|
+
*
|
|
2755
|
+
* @example
|
|
2756
|
+
* const obj = { valueOf: () => 42 }
|
|
2757
|
+
* has.valueOfFn(obj) // Returns true
|
|
2758
|
+
*/
|
|
2759
|
+
valueOfFn(object) {
|
|
2760
|
+
return is.object(object) && Object.hasOwn(object, "valueOf") && is.function(object.valueOf);
|
|
2761
|
+
}
|
|
2762
|
+
});
|
|
2763
|
+
var as = {
|
|
2764
|
+
/**
|
|
2765
|
+
* Converts a value to an array if it is iterable.
|
|
2766
|
+
*
|
|
2767
|
+
* @param value The value to convert.
|
|
2768
|
+
* @returns The converted array if the value is iterable, otherwise undefined.
|
|
2769
|
+
*
|
|
2770
|
+
* @example
|
|
2771
|
+
* // Returns [1, 2, 3]
|
|
2772
|
+
* as.array([1, 2, 3])
|
|
2773
|
+
*
|
|
2774
|
+
* @example
|
|
2775
|
+
* // Returns ['s', 't', 'r', 'i', 'n', 'g']
|
|
2776
|
+
* as.array('string')
|
|
2777
|
+
*
|
|
2778
|
+
* @example
|
|
2779
|
+
* // Returns undefined
|
|
2780
|
+
* as.array(123)
|
|
2781
|
+
*/
|
|
2782
|
+
array(value) {
|
|
2783
|
+
return is.iterable(value) && Array.from(value) || void 0;
|
|
2784
|
+
},
|
|
2785
|
+
/**
|
|
2786
|
+
* Converts a value to an object. If the supplied value is a primitive
|
|
2787
|
+
* value, in many cases, this will convert it to an object instance of
|
|
2788
|
+
* that type. Numbers, strings, symbols, and big integers, all have
|
|
2789
|
+
* object instance variants. Wrapping them in a call to `Object()` will
|
|
2790
|
+
* convert the primitive into this instance variant.
|
|
2791
|
+
*
|
|
2792
|
+
* @param value The value to convert.
|
|
2793
|
+
* @returns The converted object.
|
|
2794
|
+
*
|
|
2795
|
+
* @example
|
|
2796
|
+
* // Returns { key: 'value' }
|
|
2797
|
+
* as.object({ key: 'value' })
|
|
2798
|
+
*
|
|
2799
|
+
* @example
|
|
2800
|
+
* // String instance as oppposed to primitive string
|
|
2801
|
+
* typeof as.object('string') // 'object'
|
|
2802
|
+
* as.object('string') instanceof String // true
|
|
2803
|
+
* 'string' instanceof String // false
|
|
2804
|
+
*
|
|
2805
|
+
* @example
|
|
2806
|
+
* // Returns {}
|
|
2807
|
+
* as.object(null)
|
|
2808
|
+
*/
|
|
2809
|
+
object(value) {
|
|
2810
|
+
return Object(value);
|
|
2811
|
+
},
|
|
2812
|
+
/**
|
|
2813
|
+
* Converts a given value to a string. This function handles various types
|
|
2814
|
+
* of values, including null, undefined, objects with custom
|
|
2815
|
+
* [Symbol.toPrimitive] methods, and objects with toString or valueOf
|
|
2816
|
+
* methods.
|
|
2817
|
+
*
|
|
2818
|
+
* @param value The value to convert to a string.
|
|
2819
|
+
* @param use Optional configuration object:
|
|
2820
|
+
* - description: If true, returns the description of a Symbol.
|
|
2821
|
+
* - stringTag: If true, returns the [Symbol.toStringTag] value if present.
|
|
2822
|
+
* @returns The string representation of the value.
|
|
2823
|
+
*
|
|
2824
|
+
* @example
|
|
2825
|
+
* // Returns 'null'
|
|
2826
|
+
* as.string(null)
|
|
2827
|
+
*
|
|
2828
|
+
* @example
|
|
2829
|
+
* // Returns '123'
|
|
2830
|
+
* as.string(123)
|
|
2831
|
+
*
|
|
2832
|
+
* @example
|
|
2833
|
+
* // Returns 'custom'
|
|
2834
|
+
* const obj = {
|
|
2835
|
+
* [Symbol.toPrimitive](hint) {
|
|
2836
|
+
* if (hint === 'string') return 'custom'
|
|
2837
|
+
* return null
|
|
2838
|
+
* }
|
|
2839
|
+
* }
|
|
2840
|
+
* as.string(obj)
|
|
2841
|
+
*
|
|
2842
|
+
* @example
|
|
2843
|
+
* // Returns 'mySymbol'
|
|
2844
|
+
* as.string(Symbol('mySymbol'), { description: true })
|
|
2845
|
+
*
|
|
2846
|
+
* @example
|
|
2847
|
+
* // Returns 'Array'
|
|
2848
|
+
* as.string([], { stringTag: true })
|
|
2849
|
+
*/
|
|
2850
|
+
string(value, use = {
|
|
2851
|
+
description: false,
|
|
2852
|
+
stringTag: false
|
|
2853
|
+
}) {
|
|
2854
|
+
if (value === null || value === void 0) {
|
|
2855
|
+
return String(value);
|
|
2856
|
+
}
|
|
2857
|
+
if (is.symbol(value) && use?.description) {
|
|
2858
|
+
return value.description;
|
|
2859
|
+
}
|
|
2860
|
+
if (has.stringTag(value) && use?.stringTag) {
|
|
2861
|
+
return value[Symbol.toStringTag];
|
|
2862
|
+
}
|
|
2863
|
+
if (is.function(value?.[Symbol.toPrimitive])) {
|
|
2864
|
+
const primitiveValue = value[Symbol.toPrimitive]("string");
|
|
2865
|
+
if (is.string(primitiveValue)) {
|
|
2866
|
+
return primitiveValue;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
if (is.function(value?.valueOf)) {
|
|
2870
|
+
const valueOfValue = value.valueOf();
|
|
2871
|
+
if (is.string(valueOfValue)) {
|
|
2872
|
+
return valueOfValue;
|
|
2873
|
+
}
|
|
2874
|
+
if (!is.object(valueOfValue)) {
|
|
2875
|
+
return String(valueOfValue);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
if (is.function(value?.toString)) {
|
|
2879
|
+
const stringValue = value.toString();
|
|
2880
|
+
if (is.string(stringValue)) {
|
|
2881
|
+
return stringValue;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
return String(value);
|
|
2885
|
+
},
|
|
2886
|
+
/**
|
|
2887
|
+
* Converts a given value to a string representing an integer.
|
|
2888
|
+
*
|
|
2889
|
+
* This method first converts the value to a number string and then extracts
|
|
2890
|
+
* the integer part by splitting the string at the decimal point.
|
|
2891
|
+
*
|
|
2892
|
+
* @param value The value to convert to an integer string.
|
|
2893
|
+
* @returns The integer part of the value as a string.
|
|
2894
|
+
*
|
|
2895
|
+
* @example
|
|
2896
|
+
* // Returns '123'
|
|
2897
|
+
* as.integerString(123.456)
|
|
2898
|
+
*
|
|
2899
|
+
* @example
|
|
2900
|
+
* // Returns '0'
|
|
2901
|
+
* as.integerString('0.789')
|
|
2902
|
+
*/
|
|
2903
|
+
integerString(value) {
|
|
2904
|
+
return this.numberString(value).split(".")[0];
|
|
2905
|
+
},
|
|
2906
|
+
/**
|
|
2907
|
+
* Converts a given value to a string representing a number.
|
|
2908
|
+
*
|
|
2909
|
+
* This method first converts the value to a string, trims any whitespace,
|
|
2910
|
+
* and removes any non-numeric characters except for '.', 'e', 'E', '+',
|
|
2911
|
+
* and '-'. It then uses a regular expression to match a floating-point
|
|
2912
|
+
* number, allowing an optional leading '+' or '-' sign, digits before
|
|
2913
|
+
* and after a single decimal point.
|
|
2914
|
+
*
|
|
2915
|
+
* @param value The value to convert to a number string.
|
|
2916
|
+
* @returns The sanitized number string or an empty string if no valid
|
|
2917
|
+
* float was found.
|
|
2918
|
+
*
|
|
2919
|
+
* @example
|
|
2920
|
+
* // Returns '123.456'
|
|
2921
|
+
* as.numberString(' 123.456abc ')
|
|
2922
|
+
*
|
|
2923
|
+
* @example
|
|
2924
|
+
* // Returns '-0.789'
|
|
2925
|
+
* as.numberString('-0.789xyz')
|
|
2926
|
+
*/
|
|
2927
|
+
numberString(value) {
|
|
2928
|
+
const string = this.string(value).trim().replace(/[^0-9.eE+-]/g, "");
|
|
2929
|
+
const sanitizedStr = string.match(/^[-+]?\d*\.?\d+([eE][-+]?\d+)?/);
|
|
2930
|
+
return sanitizedStr ? sanitizedStr[0] : "";
|
|
2931
|
+
},
|
|
2932
|
+
/**
|
|
2933
|
+
* Converts a given value to a number.
|
|
2934
|
+
*
|
|
2935
|
+
* This method uses the `numberString` method to sanitize the input value
|
|
2936
|
+
* and then converts it to a number.
|
|
2937
|
+
*
|
|
2938
|
+
* @param value The value to convert to a number.
|
|
2939
|
+
* @returns The numeric representation of the value.
|
|
2940
|
+
*
|
|
2941
|
+
* @example
|
|
2942
|
+
* // Returns 123.456
|
|
2943
|
+
* as.number('123.456abc')
|
|
2944
|
+
*
|
|
2945
|
+
* @example
|
|
2946
|
+
* // Returns -0.789
|
|
2947
|
+
* as.number('-0.789xyz')
|
|
2948
|
+
*/
|
|
2949
|
+
number(value) {
|
|
2950
|
+
return Number(this.numberString(value));
|
|
2951
|
+
},
|
|
2952
|
+
/**
|
|
2953
|
+
* Converts a given value to a bigint.
|
|
2954
|
+
*
|
|
2955
|
+
* This method uses the `integerString` method to sanitize the input value
|
|
2956
|
+
* and then converts it to a bigint.
|
|
2957
|
+
*
|
|
2958
|
+
* @param value The value to convert to a bigint.
|
|
2959
|
+
* @returns The bigint representation of the value.
|
|
2960
|
+
*
|
|
2961
|
+
* @example
|
|
2962
|
+
* // Returns 123n
|
|
2963
|
+
* as.bigint('123.456abc')
|
|
2964
|
+
*
|
|
2965
|
+
* @example
|
|
2966
|
+
* // Returns 0n
|
|
2967
|
+
* as.bigint('0.789xyz')
|
|
2968
|
+
*/
|
|
2969
|
+
bigint(value) {
|
|
2970
|
+
const BigInt2 = globalThis?.BigInt;
|
|
2971
|
+
return BigInt2(this.integerString(value));
|
|
2972
|
+
},
|
|
2973
|
+
/**
|
|
2974
|
+
* Converts a given value to a boolean.
|
|
2975
|
+
*
|
|
2976
|
+
* This method takes a value, converts it to a string, and then checks
|
|
2977
|
+
* if it matches common representations of boolean values. It returns
|
|
2978
|
+
* `true` for "1", "yes", and "true" (case insensitive), and `false`
|
|
2979
|
+
* for "0", "no", and "false" (case insensitive). For any other values,
|
|
2980
|
+
* it returns the boolean representation of the value.
|
|
2981
|
+
*
|
|
2982
|
+
* @param {*} value - The value to convert to a boolean.
|
|
2983
|
+
* @returns {boolean} The boolean representation of the value.
|
|
2984
|
+
*
|
|
2985
|
+
* @example
|
|
2986
|
+
* // Returns true
|
|
2987
|
+
* as.boolean("yes")
|
|
2988
|
+
*
|
|
2989
|
+
* @example
|
|
2990
|
+
* // Returns false
|
|
2991
|
+
* as.boolean("no")
|
|
2992
|
+
*
|
|
2993
|
+
* @example
|
|
2994
|
+
* // Returns true
|
|
2995
|
+
* as.boolean(1)
|
|
2996
|
+
*
|
|
2997
|
+
* @example
|
|
2998
|
+
* // Returns false
|
|
2999
|
+
* as.boolean(0)
|
|
3000
|
+
*
|
|
3001
|
+
* @example
|
|
3002
|
+
* // Returns true
|
|
3003
|
+
* as.boolean("true")
|
|
3004
|
+
*
|
|
3005
|
+
* @example
|
|
3006
|
+
* // Returns false
|
|
3007
|
+
* as.boolean("false")
|
|
3008
|
+
*
|
|
3009
|
+
* @example
|
|
3010
|
+
* // Returns true
|
|
3011
|
+
* as.boolean({})
|
|
3012
|
+
*
|
|
3013
|
+
* @example
|
|
3014
|
+
* // Returns false
|
|
3015
|
+
* as.boolean(null)
|
|
3016
|
+
*/
|
|
3017
|
+
boolean(value) {
|
|
3018
|
+
switch (String(value).toLowerCase()) {
|
|
3019
|
+
case "1":
|
|
3020
|
+
case "yes":
|
|
3021
|
+
case "true":
|
|
3022
|
+
return true;
|
|
3023
|
+
case "0":
|
|
3024
|
+
case "no":
|
|
3025
|
+
case "false":
|
|
3026
|
+
return false;
|
|
3027
|
+
default:
|
|
3028
|
+
return Boolean(value);
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
};
|
|
3032
|
+
function createToolkit() {
|
|
3033
|
+
return { si, is, has, as };
|
|
3034
|
+
}
|
|
3035
|
+
function ifThenElse(condition, thenCase, elseCase) {
|
|
3036
|
+
if (typeof thenCase === "undefined" && typeof elseCase === "undefined")
|
|
3037
|
+
return !!condition;
|
|
3038
|
+
if (typeof thenCase === "undefined")
|
|
3039
|
+
thenCase = condition;
|
|
3040
|
+
if (condition) {
|
|
3041
|
+
if (is.function(thenCase))
|
|
3042
|
+
return thenCase();
|
|
3043
|
+
else
|
|
3044
|
+
return thenCase;
|
|
3045
|
+
} else {
|
|
3046
|
+
if (is.function(elseCase))
|
|
3047
|
+
return elseCase();
|
|
3048
|
+
else
|
|
3049
|
+
return elseCase;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
// src/utils/descriptor.utils.js
|
|
3054
|
+
var DescriptorUtils = {
|
|
3055
|
+
/**
|
|
3056
|
+
* Creates an accessor descriptor object
|
|
3057
|
+
*
|
|
3058
|
+
* This function has multiple possible overloads
|
|
3059
|
+
*
|
|
3060
|
+
* ```markdown
|
|
3061
|
+
* _**zeroFn** is a function that takes no parameters_
|
|
3062
|
+
* _**oneFn** is a function that takes a single parameter_
|
|
3063
|
+
* _**oneOrNone** is a either a function that takes a single parameter or nullish_
|
|
3064
|
+
* _**nonFn** is any value that is not a function_
|
|
3065
|
+
* _**nullish** is either null or undefined_
|
|
3066
|
+
* _**...** means configurable?, enumerable?, storage?, key? liaison? as
|
|
3067
|
+
* subsequent following parameters in that order_
|
|
3068
|
+
*
|
|
3069
|
+
* **accessor()**
|
|
3070
|
+
* creates a storage backed accessor that is both read and write.
|
|
3071
|
+
* The storage object will be a provided empty object with the key
|
|
3072
|
+
* being 'value'. Configurable and enumerable flags will be set to
|
|
3073
|
+
* `true`.
|
|
3074
|
+
*
|
|
3075
|
+
* **accessor(options)**
|
|
3076
|
+
* this single argument variant of accessor() consists of a single
|
|
3077
|
+
* options object. If neither `get` nor `set` are provided, a
|
|
3078
|
+
* storage backed read-write accessor with undefined as the initial
|
|
3079
|
+
* value will be constructed.
|
|
3080
|
+
*
|
|
3081
|
+
* **accessor(nonFn)**
|
|
3082
|
+
* **accessor(any, true, options?)**
|
|
3083
|
+
* **accessor(any, true, ...)**
|
|
3084
|
+
* supplying only a non-function only parameter or any value and the
|
|
3085
|
+
* value `true` as the second parameter, you will get a read-write
|
|
3086
|
+
* accessor stored in the default or specified storage. The resultant
|
|
3087
|
+
* initial value will be whatever is provided as the first parameter.
|
|
3088
|
+
* See options to customize `configurable`, `enumerable`, `storage`,
|
|
3089
|
+
* `key` and the `liaison` factory function.
|
|
3090
|
+
*
|
|
3091
|
+
* **accessor(any, false, options?)**
|
|
3092
|
+
* **accessor(any, false, ...)**
|
|
3093
|
+
* supplying only a non-function only parameter or any value and the
|
|
3094
|
+
* value `false` as the second parameter, you will get a read-only
|
|
3095
|
+
* getter stored in the default or specified storage. The resultant
|
|
3096
|
+
* value will be whatever is provided as the first parameter.
|
|
3097
|
+
* See options to customize `configurable`, `enumerable`, `storage`,
|
|
3098
|
+
* `key` and the `liaison` factory function.
|
|
3099
|
+
*
|
|
3100
|
+
* **accessor(zeroFn)**
|
|
3101
|
+
* **accessor(zeroFn, nullish, options?)**
|
|
3102
|
+
* **accessor(zeroFn, nullish, ...)**
|
|
3103
|
+
* creates a generic read-only accessor with the first no-argument
|
|
3104
|
+
* function parameter being the getter and either null or undefined
|
|
3105
|
+
* for the setter. Either an options object or the manually ordered
|
|
3106
|
+
* parameters can optionally follow if a nullish value for setter
|
|
3107
|
+
* is provided.
|
|
3108
|
+
*
|
|
3109
|
+
* **accessor(zeroFn, oneOrNone, options?)**
|
|
3110
|
+
* **accessor(zeroFn, oneOrNone, ...)**
|
|
3111
|
+
* creates a generic read-write accessor with the first no-argument
|
|
3112
|
+
* function parameter being the getter and the second single-argument
|
|
3113
|
+
* function parameter being the setter. Either an options object or
|
|
3114
|
+
* the manually ordered parameters can optionally follow.
|
|
3115
|
+
*
|
|
3116
|
+
* **accessor(oneFn, oneFn, options?)**
|
|
3117
|
+
* **accessor(oneFn, oneFn, ...)**
|
|
3118
|
+
* this special variant of the accessor() invocation, allows a single
|
|
3119
|
+
* argument getter and setter factory to be supplied. These will
|
|
3120
|
+
* automatically be invoked with the specified or default storage
|
|
3121
|
+
* object. The result of the getter factory should be a no argument
|
|
3122
|
+
* function. And the result of the setter factory should be a single
|
|
3123
|
+
* argument function. The options for `liaison` and `key` will be
|
|
3124
|
+
* ignored and should be handled specifically in the factory
|
|
3125
|
+
* functions to suit your own use case.
|
|
3126
|
+
* ```
|
|
3127
|
+
*
|
|
3128
|
+
* Options are an object oriented way of supplying the alternate
|
|
3129
|
+
* flags to the data descriptor. They are
|
|
3130
|
+
*
|
|
3131
|
+
* • `get` - only referenced when an options object is the only parameter
|
|
3132
|
+
* • `set` - only referenced when an options object is the only parameter
|
|
3133
|
+
* • `configurable` - if true, the descriptor of the object that this
|
|
3134
|
+
* accessor descriptor represents can be redefined at later time by
|
|
3135
|
+
* subsequent calls to {@link Object.defineProperty} or
|
|
3136
|
+
* {@link Object.defineProperties}
|
|
3137
|
+
* • `enumerable` - if true, enumeration over the object this
|
|
3138
|
+
* descriptor is applied to, will show the property
|
|
3139
|
+
* represented by this descriptor. See the associated MDN
|
|
3140
|
+
* page regarding this {@link PropertyDescriptor} if you
|
|
3141
|
+
* want to know more.
|
|
3142
|
+
* • `storage` - an object, usually {@link Object} or {@link Map} or
|
|
3143
|
+
* nullish if unused
|
|
3144
|
+
* • `key` - a {@link PropertyKey} of your choosing or the default
|
|
3145
|
+
* string `"value"`
|
|
3146
|
+
* • `bind` - true if you wish to have the `storage` object bound as
|
|
3147
|
+
* the `thisObj` for both the `get` and `set` functions when
|
|
3148
|
+
* storage is used. **note* this will not work if you supply a
|
|
3149
|
+
* big arrow function for the accessor function in question. This
|
|
3150
|
+
* defaults to `false`.
|
|
3151
|
+
* • `liaison` - an optional factory function that must return an
|
|
3152
|
+
* object with two properties. The first is a `get()` function that
|
|
3153
|
+
* returns a value and the second is a `set(value)` function that
|
|
3154
|
+
* stores a value. The factory function receives `storage` and
|
|
3155
|
+
* `key`, in that order. The default uses {@link Map.get} and
|
|
3156
|
+
* {@link Map.set} if the storage is an instance of {@link Map}.
|
|
3157
|
+
* Otherwise, the typical `object[key]` format is used if the
|
|
3158
|
+
* storage object is an instanceof {@link Object}
|
|
3159
|
+
*
|
|
3160
|
+
* @param {(object|any)?} value the JavaScript value representing
|
|
3161
|
+
* this descriptor's value or an options object if it is the
|
|
3162
|
+
* only parameter.
|
|
3163
|
+
* @param {(object|boolean)?} optionsOrConfigurable true or false if
|
|
3164
|
+
* you wish the `configurable` flag to be set. Optionally supply an
|
|
3165
|
+
* object with one of the supported options to configure the run
|
|
3166
|
+
* of the function.
|
|
3167
|
+
* @param {boolean?} enumerable true or false if you wish to
|
|
3168
|
+
* configure the `.enumerable` property of the descriptor
|
|
3169
|
+
* @param {object?} storage an object upon which data storage should
|
|
3170
|
+
* be written to and read from. Defaults to an empty {@link Object}
|
|
3171
|
+
* when storage is needed and not supplied via this parameter or
|
|
3172
|
+
* an options object.
|
|
3173
|
+
* @param {PropertyKey?} key the key used to store content on the
|
|
3174
|
+
* storage object.
|
|
3175
|
+
* @param {(object, PropertyKey) => { get: ()=>any, set: (v)=>void}} liaison
|
|
3176
|
+
* an optional function that, given a storage object and property key,
|
|
3177
|
+
* returns an object with a no argument `get()` function that returns
|
|
3178
|
+
* the value on the storage object with a given key and a single argument
|
|
3179
|
+
* `set(value)` function that stores a new value using the property key
|
|
3180
|
+
* on the supplied storage object. This exists because access to a
|
|
3181
|
+
* {@link Map} and {@link Object} values are handled differently. If you
|
|
3182
|
+
* need support for some other class than `Map` or `Object` then you
|
|
3183
|
+
* should provide a liaison function to define access.
|
|
3184
|
+
*
|
|
3185
|
+
* @returns {PropertyDescriptor}
|
|
3186
|
+
*
|
|
3187
|
+
* @see {@link PropertyDescriptor}
|
|
3188
|
+
* @note More info on this can be found at the
|
|
3189
|
+
* [MDN Object.defineProperty/ies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
|
|
3190
|
+
* page
|
|
3191
|
+
*
|
|
3192
|
+
* @type {Function & { keys: string[] }}
|
|
3193
|
+
*/
|
|
3194
|
+
get accessor() {
|
|
3195
|
+
function accessor2(get, set, optionsOrConfigurable = true, enumerable = true, storage, key = "value", liaison) {
|
|
3196
|
+
const count = arguments.length;
|
|
3197
|
+
const storageKeys = ["storage", "key", "liaison", "initial", "bind"];
|
|
3198
|
+
const optionKeys = [
|
|
3199
|
+
// accessor functions
|
|
3200
|
+
"get",
|
|
3201
|
+
"set",
|
|
3202
|
+
// descriptor flags
|
|
3203
|
+
"configurable",
|
|
3204
|
+
"enumerable",
|
|
3205
|
+
// storage configuration keys
|
|
3206
|
+
...storageKeys
|
|
3207
|
+
];
|
|
3208
|
+
const has3 = (object, key2) => isObject(object) && Reflect.has(object, key2);
|
|
3209
|
+
const isOpts = (object) => optionKeys.some((key2) => has3(object, key2));
|
|
3210
|
+
let configurable = !!optionsOrConfigurable;
|
|
3211
|
+
let initial = void 0;
|
|
3212
|
+
let bind = false;
|
|
3213
|
+
let options = {};
|
|
3214
|
+
if (count === 1 && isObject(get) && hasSome(get, ...optionKeys)) {
|
|
3215
|
+
options = { ...get };
|
|
3216
|
+
({ get, set } = get);
|
|
3217
|
+
}
|
|
3218
|
+
if (isObject(optionsOrConfigurable) || isObject(set)) {
|
|
3219
|
+
options = isObject(set) && count === 2 ? { ...set } : { ...optionsOrConfigurable };
|
|
3220
|
+
({ configurable, enumerable, storage, key, bind, initial } = options);
|
|
3221
|
+
}
|
|
3222
|
+
liaison = options?.liaison ?? liaison ?? ((storage2, key2) => ({
|
|
3223
|
+
get() {
|
|
3224
|
+
if (storage2 instanceof Map)
|
|
3225
|
+
return storage2.get(key2);
|
|
3226
|
+
else if (isObject(storage2))
|
|
3227
|
+
return storage2[key2];
|
|
3228
|
+
},
|
|
3229
|
+
set(value) {
|
|
3230
|
+
if (storage2 instanceof Map)
|
|
3231
|
+
storage2.set(key2, value);
|
|
3232
|
+
else if (isObject(storage2))
|
|
3233
|
+
storage2[key2] = value;
|
|
3234
|
+
}
|
|
3235
|
+
}));
|
|
3236
|
+
configurable = configurable ?? true;
|
|
3237
|
+
enumerable = enumerable ?? true;
|
|
3238
|
+
key = key ?? "value";
|
|
3239
|
+
bind = bind ?? false;
|
|
3240
|
+
const nullish = (value) => value === null || value === void 0;
|
|
3241
|
+
const nonFn = (value) => !nullish(value) && typeof value !== "function";
|
|
3242
|
+
const yesFn = (value) => typeof value === "function";
|
|
3243
|
+
const zeroFn = (value) => yesFn(value) && value.length === 0;
|
|
3244
|
+
const oneFn = (value) => yesFn(value) && value.length === 1;
|
|
3245
|
+
const isTrue = (value) => value === true;
|
|
3246
|
+
const isFalse = (value) => value === false;
|
|
3247
|
+
const addRefs = (fn, value) => Object.defineProperties(fn, {
|
|
3248
|
+
storage: { value, configurable: true, enumerable: false },
|
|
3249
|
+
key: { value: key, configurable: true, enumerable: false }
|
|
3250
|
+
});
|
|
3251
|
+
if (count === 0 || !get && !set) {
|
|
3252
|
+
storage = { [key]: initial };
|
|
3253
|
+
const _ = liaison(storage, key);
|
|
3254
|
+
get = addRefs(function() {
|
|
3255
|
+
return _.get();
|
|
3256
|
+
}, storage);
|
|
3257
|
+
set = addRefs(function(value) {
|
|
3258
|
+
_.set(value);
|
|
3259
|
+
}, storage);
|
|
3260
|
+
return { get, set, configurable, enumerable };
|
|
3261
|
+
}
|
|
3262
|
+
if (count === 1 && oneFn(get)) {
|
|
3263
|
+
set = false;
|
|
3264
|
+
}
|
|
3265
|
+
if (count === 1 && nonFn(get) || (isTrue(set) || isFalse(set))) {
|
|
3266
|
+
const skipSet = isFalse(set);
|
|
3267
|
+
if (!storage || !(storage instanceof Map) || !isObject(storage)) {
|
|
3268
|
+
storage = {};
|
|
3269
|
+
}
|
|
3270
|
+
const _ = liaison(storage, key);
|
|
3271
|
+
_.set(get);
|
|
3272
|
+
let _get = function() {
|
|
3273
|
+
return _.get();
|
|
3274
|
+
};
|
|
3275
|
+
let _set = function(value) {
|
|
3276
|
+
_.set(value);
|
|
3277
|
+
};
|
|
3278
|
+
if (bind) {
|
|
3279
|
+
_get = _get.bind(storage);
|
|
3280
|
+
_set = _set.bind(storage);
|
|
3281
|
+
}
|
|
3282
|
+
get = addRefs(_get, storage);
|
|
3283
|
+
set = addRefs(_set, storage);
|
|
3284
|
+
if (skipSet) {
|
|
3285
|
+
set = void 0;
|
|
3286
|
+
}
|
|
3287
|
+
return { get, set, configurable, enumerable };
|
|
3288
|
+
}
|
|
3289
|
+
if (zeroFn(get) && !set || zeroFn(get) && oneFn(set)) {
|
|
3290
|
+
const descriptor = { get, set, configurable, enumerable };
|
|
3291
|
+
if (isObject(options) && Reflect.has(options, "initial"))
|
|
3292
|
+
descriptor.set(initial);
|
|
3293
|
+
return descriptor;
|
|
3294
|
+
}
|
|
3295
|
+
if (oneFn(get) && oneFn(set)) {
|
|
3296
|
+
storage = storage || {};
|
|
3297
|
+
let _get = get(storage);
|
|
3298
|
+
let _set = set(storage);
|
|
3299
|
+
if (bind) {
|
|
3300
|
+
_get = _get.bind(storage);
|
|
3301
|
+
_set = _set.bind(storage);
|
|
3302
|
+
}
|
|
3303
|
+
return {
|
|
3304
|
+
get: addRefs(_get, storage),
|
|
3305
|
+
set: addRefs(_set, storage),
|
|
3306
|
+
configurable,
|
|
3307
|
+
enumerable
|
|
3308
|
+
};
|
|
3309
|
+
}
|
|
3310
|
+
return { get, set, configurable, enumerable };
|
|
3311
|
+
}
|
|
3312
|
+
Object.defineProperty(accessor2, "keys", {
|
|
3313
|
+
get() {
|
|
3314
|
+
return Object.defineProperties(
|
|
3315
|
+
["get", "set", "configurable", "enumerable"],
|
|
3316
|
+
{
|
|
3317
|
+
from: {
|
|
3318
|
+
value: function extractKeysFrom(object) {
|
|
3319
|
+
const response = {
|
|
3320
|
+
get: void 0,
|
|
3321
|
+
set: void 0,
|
|
3322
|
+
configurable: void 0,
|
|
3323
|
+
enumerable: void 0
|
|
3324
|
+
};
|
|
3325
|
+
if (!object || !(object instanceof Object))
|
|
3326
|
+
return response;
|
|
3327
|
+
for (const key of DescriptorUtils.accessor.keys) {
|
|
3328
|
+
if (Reflect.has(object, key))
|
|
3329
|
+
response[key] = object[key];
|
|
3330
|
+
}
|
|
3331
|
+
},
|
|
3332
|
+
writable: false,
|
|
3333
|
+
configurable: false,
|
|
3334
|
+
enumerable: false
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
);
|
|
3338
|
+
},
|
|
3339
|
+
configurable: true,
|
|
3340
|
+
enumerable: false
|
|
3341
|
+
});
|
|
3342
|
+
return accessor2;
|
|
3343
|
+
},
|
|
3344
|
+
/**
|
|
3345
|
+
* Creates a data descriptor object
|
|
3346
|
+
*
|
|
3347
|
+
* This function has multiple possible overloads
|
|
3348
|
+
*
|
|
3349
|
+
* ```markdown
|
|
3350
|
+
* **data()**
|
|
3351
|
+
* creates a data descriptor with a value of `undefined` that
|
|
3352
|
+
* is writable, configurable and enumerable.
|
|
3353
|
+
*
|
|
3354
|
+
* **data(options)**
|
|
3355
|
+
* if the only parameter is an object and that object contains
|
|
3356
|
+
* at least a `.value` property, this funtion will return a
|
|
3357
|
+
* data descriptor with the associated values. This variant
|
|
3358
|
+
* is useful if you want to extract the normal data descriptor
|
|
3359
|
+
* properties: value, writable, configurable and/or enumerable
|
|
3360
|
+
* from an object that has properties with these names, in
|
|
3361
|
+
* addition to other properties or functions. Note that if you
|
|
3362
|
+
* wish for the value of the descriptor to be an object that
|
|
3363
|
+
* also contains a `.value` property, use `data({value: obj})`
|
|
3364
|
+
* instead.
|
|
3365
|
+
*
|
|
3366
|
+
* **data(value)**
|
|
3367
|
+
* **data(value, options?)**
|
|
3368
|
+
* creates a data descriptor from the supplied `value`,
|
|
3369
|
+
* optionally augmented by additional `options`. The defaults
|
|
3370
|
+
* for this writable, configurable and enumerable values set
|
|
3371
|
+
* to `true`
|
|
3372
|
+
*
|
|
3373
|
+
* **data(value, writable?, configurable?, enumerable?)**
|
|
3374
|
+
* if writable, configurable or enumerable or true or false
|
|
3375
|
+
* then this function creates a data descriptor with those
|
|
3376
|
+
* flags and the supplied value (there's no real reason to
|
|
3377
|
+
* invoke this function if you're supplying all four values)
|
|
3378
|
+
* ```
|
|
3379
|
+
*
|
|
3380
|
+
* Options are an object oriented way of supplying the alternate
|
|
3381
|
+
* flags to the data descriptor. They are
|
|
3382
|
+
*
|
|
3383
|
+
* • `value` - only referenced when an options object is the
|
|
3384
|
+
* only parameter
|
|
3385
|
+
* • `writable` - true if the value represented by this data
|
|
3386
|
+
* descriptor can be reassigned a new value.
|
|
3387
|
+
* • `configurable` - if true, the descriptor of the object
|
|
3388
|
+
* that this data descriptor represents can be redefined at
|
|
3389
|
+
* later time by subsequent calls to `Object.defineProperty`
|
|
3390
|
+
* or `Object.defineProperties`. If `.configurable` is true
|
|
3391
|
+
* this can be done even if `.writable` is set to false
|
|
3392
|
+
* • `enumerable` - if true, enumeration over the object this
|
|
3393
|
+
* descriptor is applied to, will show the property
|
|
3394
|
+
* represented by this descriptor. See the associated MDN
|
|
3395
|
+
* page regarding this `PropertyDescriptor` if you want to
|
|
3396
|
+
* know more.
|
|
3397
|
+
*
|
|
3398
|
+
* @param {(object|any)?} value the JavaScript value representing
|
|
3399
|
+
* this descriptor's value or an options object if it is the
|
|
3400
|
+
* only parameter.
|
|
3401
|
+
* @param {(object|boolean)?} optionsOrWritable true or false if
|
|
3402
|
+
* you wish the writable flag to be set. Optionally supply an
|
|
3403
|
+
* object with one of the supported options to configure the run
|
|
3404
|
+
* of the function.
|
|
3405
|
+
* @param {boolean?} configurable true or false if you wish to
|
|
3406
|
+
* configure the `.configurable` property of the descriptor
|
|
3407
|
+
* @param {boolean?} enumerable true or false if you wish to
|
|
3408
|
+
* configure the `.enumerable` property of the descriptor
|
|
3409
|
+
* @returns {PropertyDescriptor}
|
|
3410
|
+
*
|
|
3411
|
+
* @note More info on this can be found at the
|
|
3412
|
+
* [MDN Object.defineProperty/ies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
|
|
3413
|
+
* page
|
|
3414
|
+
*
|
|
3415
|
+
* @type {Function & { keys: string[] }}
|
|
3416
|
+
*/
|
|
3417
|
+
get data() {
|
|
3418
|
+
function data2(value, optionsOrWritable, configurable, enumerable) {
|
|
3419
|
+
const count = arguments.length;
|
|
3420
|
+
let valueIsDescriptor = false;
|
|
3421
|
+
if (count === 0) {
|
|
3422
|
+
return {
|
|
3423
|
+
value: void 0,
|
|
3424
|
+
writable: true,
|
|
3425
|
+
configurable: true,
|
|
3426
|
+
enumerable: true
|
|
3427
|
+
};
|
|
3428
|
+
}
|
|
3429
|
+
if (count === 1) {
|
|
3430
|
+
const stats = DescriptorUtils.isDescriptor(value, true);
|
|
3431
|
+
if (stats.isValid && stats.isData) {
|
|
3432
|
+
valueIsDescriptor = true;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
let writable = optionsOrWritable === void 0 ? true : !!optionsOrWritable;
|
|
3436
|
+
let options = typeof optionsOrWritable === "boolean" ? {} : Object(optionsOrWritable);
|
|
3437
|
+
configurable = configurable === void 0 ? true : !!configurable;
|
|
3438
|
+
enumerable = enumerable === void 0 ? true : !!enumerable;
|
|
3439
|
+
if (valueIsDescriptor && !options?.allowDescriptorValue) {
|
|
3440
|
+
options = {
|
|
3441
|
+
writable: value?.writable ?? true,
|
|
3442
|
+
configurable: value?.configurable ?? true,
|
|
3443
|
+
enumerable: value?.enumerable ?? true
|
|
3444
|
+
};
|
|
3445
|
+
value = value?.value;
|
|
3446
|
+
}
|
|
3447
|
+
if (options) {
|
|
3448
|
+
({ writable, configurable, enumerable } = {
|
|
3449
|
+
...{ writable, configurable, enumerable },
|
|
3450
|
+
...options
|
|
3451
|
+
});
|
|
3452
|
+
}
|
|
3453
|
+
return { value, writable, configurable, enumerable };
|
|
3454
|
+
}
|
|
3455
|
+
Object.defineProperty(data2, "keys", {
|
|
3456
|
+
value: Object.defineProperties(
|
|
3457
|
+
["value", "writable", "configurable", "enumerable"],
|
|
3458
|
+
{
|
|
3459
|
+
from: {
|
|
3460
|
+
value: function extractKeysFrom(object) {
|
|
3461
|
+
const response = {
|
|
3462
|
+
value: void 0,
|
|
3463
|
+
writable: void 0,
|
|
3464
|
+
configurable: void 0,
|
|
3465
|
+
enumerable: void 0
|
|
3466
|
+
};
|
|
3467
|
+
if (!object || !(object instanceof Object))
|
|
3468
|
+
return response;
|
|
3469
|
+
for (const key of DescriptorUtils.data.keys) {
|
|
3470
|
+
if (Reflect.has(object, key))
|
|
3471
|
+
response[key] = object[key];
|
|
3472
|
+
}
|
|
3473
|
+
},
|
|
3474
|
+
writable: false,
|
|
3475
|
+
configurable: false,
|
|
3476
|
+
enumerable: false
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
),
|
|
3480
|
+
writable: false,
|
|
3481
|
+
configurable: true,
|
|
3482
|
+
enumerable: false
|
|
3483
|
+
});
|
|
3484
|
+
return data2;
|
|
3485
|
+
},
|
|
3486
|
+
describe(object, key, value, detectDescriptorValues = true) {
|
|
3487
|
+
const { isAccessor: isAccessor2, isData: isData2, data: data2 } = DescriptorUtils;
|
|
3488
|
+
if (!(object && object instanceof Object))
|
|
3489
|
+
return void 0;
|
|
3490
|
+
if (!["string", "number", "symbol"].includes(typeof key))
|
|
3491
|
+
return void 0;
|
|
3492
|
+
if (detectDescriptorValues && isAccessor2(value) || isData2(value)) {
|
|
3493
|
+
return Object.defineProperty(object, key, value);
|
|
3494
|
+
} else {
|
|
3495
|
+
return Object.defineProperty(object, key, data2(value));
|
|
3496
|
+
}
|
|
3497
|
+
},
|
|
3498
|
+
describeMany(object, keyValues, detectDescriptorValues = true) {
|
|
3499
|
+
const { isAccessor: isAccessor2, isData: isData2, isDescriptor: isDescriptor2, data: data2, describe: describe2 } = DescriptorUtils;
|
|
3500
|
+
const isKey = (k) => ["string", "number", "symbol"].includes(typeof k);
|
|
3501
|
+
let map2 = void 0;
|
|
3502
|
+
if (Array.isArray(keyValues)) {
|
|
3503
|
+
map2 = new Map(keyValues.filter((keyValue) => {
|
|
3504
|
+
return typeof keyValue === "function" && keyValue.length === 2;
|
|
3505
|
+
}));
|
|
3506
|
+
} else if (keyValues instanceof Map) {
|
|
3507
|
+
map2 = keyValues;
|
|
3508
|
+
} else if (keyValues instanceof Object) {
|
|
3509
|
+
const descriptors = Object.getOwnPropertyDescriptors(keyValues);
|
|
3510
|
+
map2 = new Object.entries(descriptors);
|
|
3511
|
+
} else {
|
|
3512
|
+
return [];
|
|
3513
|
+
}
|
|
3514
|
+
for (const [key, value] of map2) {
|
|
3515
|
+
if (detectDescriptorValues) {
|
|
3516
|
+
if (isDescriptor2(key)) {
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
const accessorBase = { enumerable: true, configurable: true };
|
|
3521
|
+
const dataBase = { writable: true, ...accessorBase };
|
|
3522
|
+
const extractBase = (descriptor) => {
|
|
3523
|
+
if (isAccessor2(descriptor)) {
|
|
3524
|
+
const { configurable, enumerable } = descriptor;
|
|
3525
|
+
return { configurable, enumerable };
|
|
3526
|
+
} else if (isData2(descriptor)) {
|
|
3527
|
+
const { writable, configurable, enumerable } = descriptor;
|
|
3528
|
+
return { writable, configurable, enumerable };
|
|
3529
|
+
}
|
|
3530
|
+
return void 0;
|
|
3531
|
+
};
|
|
3532
|
+
for (const [key, value] of map2.entries()) {
|
|
3533
|
+
const descriptor = detectDescriptorValues && isDescriptor2(value) ? value : data2(value, dataBase);
|
|
3534
|
+
}
|
|
3535
|
+
},
|
|
3536
|
+
extract(fromObject, keysToExtract, defaultIfMissing = void 0, extractDescriptors = false) {
|
|
3537
|
+
const { data: data2 } = DescriptorUtils;
|
|
3538
|
+
const output = {};
|
|
3539
|
+
if (!fromObject || typeof fromObject !== "object")
|
|
3540
|
+
return output;
|
|
3541
|
+
if (!Array.isArray(keysToExtract))
|
|
3542
|
+
keysToExtract = [keysToExtract];
|
|
3543
|
+
for (const key of keysToExtract) {
|
|
3544
|
+
let descriptor = Object.getOwnPropertyDescriptor(fromObject, key);
|
|
3545
|
+
if (!descriptor)
|
|
3546
|
+
descriptor = data2(defaultIfMissing);
|
|
3547
|
+
if (extractDescriptors)
|
|
3548
|
+
descriptor.value = data2(descriptor, { allowDescriptorValue: true });
|
|
3549
|
+
Object.defineProperty(output, key, descriptor);
|
|
3550
|
+
}
|
|
3551
|
+
return output;
|
|
3552
|
+
},
|
|
3553
|
+
/**
|
|
3554
|
+
* Determines if a given value is an accessor descriptor.
|
|
3555
|
+
*
|
|
3556
|
+
* An accessor descriptor is a property descriptor that defines
|
|
3557
|
+
* getter and/or setter functions for a property. This function
|
|
3558
|
+
* checks the validity of the descriptor and whether it qualifies
|
|
3559
|
+
* as an accessor.
|
|
3560
|
+
*
|
|
3561
|
+
* @param {Object} value - The descriptor object to evaluate.
|
|
3562
|
+
* @param {boolean} [strict=true] - If true, performs a strict
|
|
3563
|
+
* validation of the descriptor.
|
|
3564
|
+
* @returns {boolean} Returns true if the descriptor is valid and
|
|
3565
|
+
* is an accessor descriptor, otherwise false.
|
|
3566
|
+
*
|
|
3567
|
+
* @example
|
|
3568
|
+
* // Example usage:
|
|
3569
|
+
* const descriptor = { get: () => 42, set: (val) => {} }
|
|
3570
|
+
* const result = DescriptorUtils.isAccessor(descriptor)
|
|
3571
|
+
* console.log(result) // Outputs: true
|
|
3572
|
+
*/
|
|
3573
|
+
isAccessor(value, strict = true) {
|
|
3574
|
+
const stats = DescriptorUtils.isDescriptor(value, true, strict);
|
|
3575
|
+
return stats.isValid && stats.isAccessor;
|
|
3576
|
+
},
|
|
3577
|
+
/**
|
|
3578
|
+
* Checks if a given value is a data descriptor.
|
|
3579
|
+
*
|
|
3580
|
+
* A data descriptor is a property descriptor that defines a value
|
|
3581
|
+
* and optionally a writable attribute for a property. This function
|
|
3582
|
+
* evaluates the descriptor's validity and whether it qualifies as
|
|
3583
|
+
* a data descriptor.
|
|
3584
|
+
*
|
|
3585
|
+
* @param {Object} value - The descriptor object to evaluate.
|
|
3586
|
+
* @param {boolean} [strict=true] - If true, performs a strict
|
|
3587
|
+
* validation of the descriptor.
|
|
3588
|
+
* @returns {boolean} Returns true if the descriptor is valid and
|
|
3589
|
+
* is a data descriptor, otherwise false.
|
|
3590
|
+
*
|
|
3591
|
+
* @example
|
|
3592
|
+
* // Example usage:
|
|
3593
|
+
* const descriptor = { value: 42, writable: true }
|
|
3594
|
+
* const result = DescriptorUtils.isData(descriptor)
|
|
3595
|
+
* console.log(result) // Outputs: true
|
|
3596
|
+
*/
|
|
3597
|
+
isData(value, strict = true) {
|
|
3598
|
+
const stats = DescriptorUtils.isDescriptor(value, true, strict);
|
|
3599
|
+
return stats.isValid && stats.isData;
|
|
3600
|
+
},
|
|
3601
|
+
/**
|
|
3602
|
+
* A function that, given a value that might be a `PropertyDescriptor`,
|
|
3603
|
+
* calculates a deterministic probability that the supplied value is
|
|
3604
|
+
* an object that either is a `PropertyDescriptor` or that can function
|
|
3605
|
+
* as one.
|
|
3606
|
+
*
|
|
3607
|
+
* @param {unknown} value a JavaScript value that might be a
|
|
3608
|
+
* `PropertyDescriptor` type.
|
|
3609
|
+
* @param {boolean?} returnStats if this value is true, instead of returning
|
|
3610
|
+
* a determined boolean value indicating the supplied value might be a
|
|
3611
|
+
* `PropertyDescriptor`, an object containing the determined flags and score
|
|
3612
|
+
* the led to the determination instead is returned.
|
|
3613
|
+
* @param {boolean?} strict if this value is `true`, which is the default,
|
|
3614
|
+
* then the function will not allow descriptor compatible objects, rather it
|
|
3615
|
+
* will only return true if the object has keys that belong in a descriptor
|
|
3616
|
+
* and do not form an invalid combination.
|
|
3617
|
+
* @returns {IsDescriptorResponse} if `returnStats` is `true`
|
|
3618
|
+
* an object of type {@link IsDescriptorStats} is returned. This object
|
|
3619
|
+
* will have a lot of {@link Boolean} flags pertaining to the `true`/`false`
|
|
3620
|
+
* evaluation. If `returnStats` is `false`, then a boolean value denoting
|
|
3621
|
+
* whether or not the value is a {@link PropertyDescriptor} is returned
|
|
3622
|
+
* instead. This is effectively the same as the `isValid` parameter from the
|
|
3623
|
+
* stats block.
|
|
3624
|
+
*/
|
|
3625
|
+
isDescriptor(value, returnStats = false, strict = true) {
|
|
3626
|
+
const areBools = (...props) => props.flat().every(
|
|
3627
|
+
(prop) => boolTypes.includes(typeof value[prop])
|
|
3628
|
+
);
|
|
3629
|
+
const areFuncs = (...props) => props.flat().every(
|
|
3630
|
+
(prop) => funcTypes.includes(typeof value[prop])
|
|
3631
|
+
);
|
|
3632
|
+
const hasKeyFn = (property2) => Reflect.has(value, property2);
|
|
3633
|
+
const isOfType = (type) => (element) => typeof element === type;
|
|
3634
|
+
const baseProps = ["configurable", "enumerable"];
|
|
3635
|
+
const dataProps = ["value", "writable"];
|
|
3636
|
+
const accessorProps = ["get", "set"];
|
|
3637
|
+
const anyDescProps = [...baseProps, ...dataProps, ...accessorProps];
|
|
3638
|
+
const boolTypes = ["undefined", "boolean"];
|
|
3639
|
+
const funcTypes = ["undefined", "function"];
|
|
3640
|
+
const stats = {
|
|
3641
|
+
confidence: 0,
|
|
3642
|
+
hasAccessorKeys: false,
|
|
3643
|
+
hasBaseDescriptorKeys: false,
|
|
3644
|
+
hasDataKeys: false,
|
|
3645
|
+
isAccessor: false,
|
|
3646
|
+
isData: false,
|
|
3647
|
+
isValid: false,
|
|
3648
|
+
isBase: false
|
|
3649
|
+
};
|
|
3650
|
+
if (!value || typeof value !== "object" || !(value instanceof Object))
|
|
3651
|
+
return returnStats ? stats : false;
|
|
3652
|
+
let score = 0;
|
|
3653
|
+
if (value && typeof value === "object") {
|
|
3654
|
+
const objKeys = Reflect.ownKeys(value);
|
|
3655
|
+
const nonDescKeys = objKeys.filter((k) => !anyDescProps.includes(k));
|
|
3656
|
+
if (strict && nonDescKeys.length)
|
|
3657
|
+
return false;
|
|
3658
|
+
if (objKeys.length <= 4)
|
|
3659
|
+
score++;
|
|
3660
|
+
stats.hasAccessorKeys = accessorProps.some(hasKeyFn) && areFuncs(accessorProps);
|
|
3661
|
+
stats.hasDataKeys = dataProps.some(hasKeyFn) && areBools("writable");
|
|
3662
|
+
stats.hasBaseDescriptorKeys = baseProps.some(hasKeyFn) && areBools(baseProps);
|
|
3663
|
+
if (stats.hasBaseDescriptorKeys)
|
|
3664
|
+
score++;
|
|
3665
|
+
if (stats.hasAccessorKeys || stats.hasDataKeys)
|
|
3666
|
+
score++;
|
|
3667
|
+
if (score > 0)
|
|
3668
|
+
stats.isValid = true;
|
|
3669
|
+
if (score > 0 && stats.hasAccessorKeys)
|
|
3670
|
+
stats.isAccessor = true;
|
|
3671
|
+
if (score > 0 && stats.hasDataKeys)
|
|
3672
|
+
stats.isData = true;
|
|
3673
|
+
if (stats.isValid && !["get", "set", "value"].some(hasKeyFn))
|
|
3674
|
+
stats.isBase = true;
|
|
3675
|
+
if (stats.isValid && stats.isData && Reflect.has(value, "value"))
|
|
3676
|
+
score++;
|
|
3677
|
+
else if (stats.isValid && stats.isAccessor) {
|
|
3678
|
+
if ([value?.get, value?.set].some(isOfType("function")))
|
|
3679
|
+
score++;
|
|
3680
|
+
}
|
|
3681
|
+
if (stats.hasAccessorKeys && stats.hasDataKeys) {
|
|
3682
|
+
score = 0;
|
|
3683
|
+
stats.isValid = false;
|
|
3684
|
+
}
|
|
3685
|
+
stats.confidence = parseFloat(score / 4);
|
|
3686
|
+
}
|
|
3687
|
+
if (returnStats)
|
|
3688
|
+
return stats;
|
|
3689
|
+
return score >= 0 ? true : false;
|
|
3690
|
+
},
|
|
3691
|
+
/**
|
|
3692
|
+
* Redefines a property on an object with new descriptors and options.
|
|
3693
|
+
* This function allows renaming, aliasing, and redefining property
|
|
3694
|
+
* descriptors such as configurable, enumerable, writable, get, and set.
|
|
3695
|
+
*
|
|
3696
|
+
* @param {Object} object - The target object whose property is to be
|
|
3697
|
+
* redefined.
|
|
3698
|
+
* @param {string|symbol} key - The key of the property to redefine.
|
|
3699
|
+
* @param {Object} as - An object containing new property descriptors.
|
|
3700
|
+
* @param {Object} [options] - Optional settings for renaming and aliasing.
|
|
3701
|
+
* @param {string|symbol} [options.rename] - New key name for the property.
|
|
3702
|
+
* @param {Array<string|symbol>} [options.alsoAs] - Additional aliases for
|
|
3703
|
+
* the property.
|
|
3704
|
+
* @param {Object} [options.moveTo] optionally move the descriptor from this
|
|
3705
|
+
* object to another.
|
|
3706
|
+
* @returns {any} the result of `object[key]` in its final state
|
|
3707
|
+
*
|
|
3708
|
+
* @example
|
|
3709
|
+
* const obj = { a: 1 }
|
|
3710
|
+
* redescribe(obj, 'a', { writable: false }, { rename: 'b', alsoAs: ['c'] })
|
|
3711
|
+
* console.log(obj.b) // Outputs: 1
|
|
3712
|
+
* console.log(obj.c) // Outputs: 1
|
|
3713
|
+
*/
|
|
3714
|
+
redescribe(object, key, as2, options) {
|
|
3715
|
+
const { isAccessor: isAccessor2, isData: isData2 } = DescriptorUtils;
|
|
3716
|
+
const ifThen = (condition, fn, ...args) => condition && fn(...args);
|
|
3717
|
+
const isBool = (value) => typeof value === "boolean" || value instanceof Boolean;
|
|
3718
|
+
const isFunction = (value) => typeof value === "function";
|
|
3719
|
+
const isObject2 = (value) => value && value instanceof Object;
|
|
3720
|
+
const isDefined = (value, key2) => isObject2(value) && Reflect.has(value, key2);
|
|
3721
|
+
const isObjectKey = (v) => ["string", "number", "symbol"].includes(typeof v);
|
|
3722
|
+
const define = (key2, values) => Object.defineProperty(object, key2, values);
|
|
3723
|
+
const assign = (object2, ...values) => Object.assign(object2, ...values);
|
|
3724
|
+
const isAnObject = isObject2(object);
|
|
3725
|
+
let asIsObject = isObject2(as2);
|
|
3726
|
+
const descriptor = isAnObject && Object.getOwnPropertyDescriptor(object, key);
|
|
3727
|
+
const aliases = [];
|
|
3728
|
+
if (descriptor && !asIsObject) {
|
|
3729
|
+
asIsObject = true;
|
|
3730
|
+
as2 = {};
|
|
3731
|
+
}
|
|
3732
|
+
if (isObject2(options)) {
|
|
3733
|
+
if (isDefined(options, "rename")) {
|
|
3734
|
+
const successfulDelete = delete object[key];
|
|
3735
|
+
if (successfulDelete)
|
|
3736
|
+
key = options.rename;
|
|
3737
|
+
}
|
|
3738
|
+
if (isDefined(options, "alsoAs")) {
|
|
3739
|
+
if (Array.isArray(options.alsoAs)) {
|
|
3740
|
+
for (const value of options.alsoAs.filter((v) => isObjectKey(v)))
|
|
3741
|
+
aliases.push(value);
|
|
3742
|
+
} else if (isObjectKey(options.alsoAs)) {
|
|
3743
|
+
aliases.push(options.alsoAs);
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
if (isDefined(options, "moveTo")) {
|
|
3747
|
+
ifThen(isObject2(options.moveTo), () => object = options.moveTo);
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
if (isAnObject && asIsObject) {
|
|
3751
|
+
let { configurable, enumerable, writable, get, set, value } = as2;
|
|
3752
|
+
if (isAccessor2(descriptor)) {
|
|
3753
|
+
ifThen(isFunction(get), () => assign(descriptor, { get }));
|
|
3754
|
+
ifThen(isFunction(set), () => assign(descriptor, { set }));
|
|
3755
|
+
}
|
|
3756
|
+
ifThen(isBool(writable) && isData2(descriptor), () => {
|
|
3757
|
+
assign(descriptor, {
|
|
3758
|
+
writable,
|
|
3759
|
+
value: isDefined(as2, "value") ? value : descriptor.value
|
|
3760
|
+
});
|
|
3761
|
+
});
|
|
3762
|
+
ifThen(isBool(configurable), () => assign(descriptor, { configurable }));
|
|
3763
|
+
ifThen(isBool(enumerable), () => assign(descriptor, { enumerable }));
|
|
3764
|
+
define(key, descriptor);
|
|
3765
|
+
for (const alias of aliases) {
|
|
3766
|
+
define(alias, descriptor);
|
|
3767
|
+
}
|
|
3768
|
+
return object[key];
|
|
3769
|
+
}
|
|
3770
|
+
},
|
|
3771
|
+
/**
|
|
3772
|
+
* Retrieves the keys associated with accessor descriptors.
|
|
3773
|
+
*
|
|
3774
|
+
* Accessor descriptors are property descriptors that define
|
|
3775
|
+
* getter and/or setter functions for a property.
|
|
3776
|
+
*
|
|
3777
|
+
* @type {string[]}
|
|
3778
|
+
*
|
|
3779
|
+
* @example
|
|
3780
|
+
* // Example usage:
|
|
3781
|
+
* const keys = DescriptorUtils.kAccessorDescriptorKeys
|
|
3782
|
+
* console.log(keys) // Output: ['get', 'set']
|
|
3783
|
+
*/
|
|
3784
|
+
get kAccessorDescriptorKeys() {
|
|
3785
|
+
return ["get", "set"];
|
|
3786
|
+
},
|
|
3787
|
+
/**
|
|
3788
|
+
* Retrieves the keys associated with data descriptors.
|
|
3789
|
+
*
|
|
3790
|
+
* Data descriptors are property descriptors that define a value
|
|
3791
|
+
* and optionally a writable attribute for a property.
|
|
3792
|
+
*
|
|
3793
|
+
* @type {string[]}
|
|
3794
|
+
*
|
|
3795
|
+
* @example
|
|
3796
|
+
* // Example usage:
|
|
3797
|
+
* const keys = DescriptorUtils.kDataDescriptorKeys
|
|
3798
|
+
* console.log(keys) // Output: ['value', 'writable']
|
|
3799
|
+
*/
|
|
3800
|
+
get kDataDescriptorKeys() {
|
|
3801
|
+
return ["value", "writable"];
|
|
3802
|
+
},
|
|
3803
|
+
/**
|
|
3804
|
+
* Retrieves the keys associated with shared descriptors.
|
|
3805
|
+
*
|
|
3806
|
+
* Shared descriptors are property descriptors that define
|
|
3807
|
+
* common attributes for a property, such as whether the
|
|
3808
|
+
* property is configurable or enumerable.
|
|
3809
|
+
*
|
|
3810
|
+
* @type {string[]}
|
|
3811
|
+
*
|
|
3812
|
+
* @example
|
|
3813
|
+
* // Example usage:
|
|
3814
|
+
* const keys = DescriptorUtils.kSharedDescriptorKeys
|
|
3815
|
+
* console.log(keys) // Output: ['configurable', 'enumerable']
|
|
3816
|
+
*/
|
|
3817
|
+
get kSharedDescriptorKeys() {
|
|
3818
|
+
return ["configurable", "enumerable"];
|
|
3819
|
+
},
|
|
3820
|
+
/**
|
|
3821
|
+
* Retrieves all descriptor keys, combining accessor, data, and shared
|
|
3822
|
+
* descriptor keys.
|
|
3823
|
+
*
|
|
3824
|
+
* This getter method aggregates keys from accessor descriptors,
|
|
3825
|
+
* data descriptors, and shared descriptors into a single array.
|
|
3826
|
+
* This can be useful when you need to validate or inspect all
|
|
3827
|
+
* possible descriptor keys.
|
|
3828
|
+
*
|
|
3829
|
+
* @type {string[]}
|
|
3830
|
+
*
|
|
3831
|
+
* @example
|
|
3832
|
+
* // Example usage:
|
|
3833
|
+
* const allKeys = DescriptorUtils.kDescriptorKeys
|
|
3834
|
+
* console.log(allKeys)
|
|
3835
|
+
* // Output: [
|
|
3836
|
+
* // 'get', 'set', 'value', 'writable', 'configurable', 'enumerable'
|
|
3837
|
+
* // ]
|
|
3838
|
+
*/
|
|
3839
|
+
get kDescriptorKeys() {
|
|
3840
|
+
return [
|
|
3841
|
+
...this.kAccessorDescriptorKeys,
|
|
3842
|
+
...this.kDataDescriptorKeys,
|
|
3843
|
+
...this.kSharedDescriptorKeys
|
|
3844
|
+
];
|
|
3845
|
+
}
|
|
3846
|
+
};
|
|
3847
|
+
var {
|
|
3848
|
+
accessor,
|
|
3849
|
+
data,
|
|
3850
|
+
describe,
|
|
3851
|
+
describeMany,
|
|
3852
|
+
extract,
|
|
3853
|
+
isDescriptor,
|
|
3854
|
+
isAccessor,
|
|
3855
|
+
isData,
|
|
3856
|
+
redescribe
|
|
3857
|
+
} = DescriptorUtils;
|
|
3858
|
+
var {
|
|
3859
|
+
kAccessorDescriptorKeys,
|
|
3860
|
+
kDataDescriptorKeys,
|
|
3861
|
+
kDescriptorKeys,
|
|
3862
|
+
kSharedDescriptorKeys
|
|
3863
|
+
} = DescriptorUtils;
|
|
3864
|
+
function isObject(o) {
|
|
3865
|
+
return o && typeof o === "object";
|
|
3866
|
+
}
|
|
3867
|
+
function hasSome(object, ...keys) {
|
|
3868
|
+
return hasQuantity("some", object, keys);
|
|
3869
|
+
}
|
|
3870
|
+
function hasQuantity(quantityFn, object, keys) {
|
|
3871
|
+
return isObject(object) && keys.flat(Infinity).map((key) => Reflect.has(object, key))[quantityFn]((has3) => has3);
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
// src/utils/index.js
|
|
3875
|
+
var index_default = {
|
|
3876
|
+
COPropertyHandler,
|
|
3877
|
+
FlexiblyHiddenHandler,
|
|
3878
|
+
FlexiblyVisibleHandler,
|
|
3879
|
+
ImmutablyHiddenHandler,
|
|
3880
|
+
ImmutablyVisibleHandler,
|
|
3881
|
+
MutablyHiddenHandler,
|
|
3882
|
+
MutablyVisibleHandler,
|
|
3883
|
+
StdoutGlobalPatches,
|
|
3884
|
+
StringConsole,
|
|
3885
|
+
VisibilityKeys,
|
|
3886
|
+
VisibilityScopeHandler,
|
|
3887
|
+
as,
|
|
3888
|
+
has,
|
|
3889
|
+
is,
|
|
3890
|
+
si,
|
|
3891
|
+
accessor,
|
|
3892
|
+
captureStdout,
|
|
3893
|
+
copyObject,
|
|
3894
|
+
createToolkit,
|
|
3895
|
+
customCopyObject,
|
|
3896
|
+
data,
|
|
3897
|
+
describe,
|
|
3898
|
+
describeMany,
|
|
3899
|
+
extract,
|
|
3900
|
+
isDescriptor,
|
|
3901
|
+
makeTransducer,
|
|
3902
|
+
redescribe,
|
|
3903
|
+
transduceFrom,
|
|
3904
|
+
transduceFromCOHandler,
|
|
3905
|
+
tryIgnore,
|
|
3906
|
+
kAccessorDescriptorKeys,
|
|
3907
|
+
kDataDescriptorKeys,
|
|
3908
|
+
kDescriptorKeys,
|
|
3909
|
+
kVisibilityKeys
|
|
3910
|
+
};
|
|
3911
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3912
|
+
0 && (module.exports = {
|
|
3913
|
+
COPropertyHandler,
|
|
3914
|
+
DescriptorUtils,
|
|
3915
|
+
FlexiblyHiddenHandler,
|
|
3916
|
+
FlexiblyVisibleHandler,
|
|
3917
|
+
ImmutablyHiddenHandler,
|
|
3918
|
+
ImmutablyVisibleHandler,
|
|
3919
|
+
MutablyHiddenHandler,
|
|
3920
|
+
MutablyVisibleHandler,
|
|
3921
|
+
SC,
|
|
3922
|
+
StdoutGlobalPatches,
|
|
3923
|
+
StringConsole,
|
|
3924
|
+
StringConsoleExtension,
|
|
3925
|
+
VisibilityKeys,
|
|
3926
|
+
VisibilityScopeHandler,
|
|
3927
|
+
accessor,
|
|
3928
|
+
as,
|
|
3929
|
+
captureStdout,
|
|
3930
|
+
copyObject,
|
|
3931
|
+
createToolkit,
|
|
3932
|
+
customCopyObject,
|
|
3933
|
+
data,
|
|
3934
|
+
describe,
|
|
3935
|
+
describeMany,
|
|
3936
|
+
extract,
|
|
3937
|
+
has,
|
|
3938
|
+
is,
|
|
3939
|
+
isAccessor,
|
|
3940
|
+
isData,
|
|
3941
|
+
isDescriptor,
|
|
3942
|
+
kAccessorDescriptorKeys,
|
|
3943
|
+
kDataDescriptorKeys,
|
|
3944
|
+
kDescriptorKeys,
|
|
3945
|
+
kSharedDescriptorKeys,
|
|
3946
|
+
kVisibilityKeys,
|
|
3947
|
+
makeTransducer,
|
|
3948
|
+
redescribe,
|
|
3949
|
+
si,
|
|
3950
|
+
transduceFrom,
|
|
3951
|
+
transduceFromCOHandler,
|
|
3952
|
+
tryIgnore
|
|
3953
|
+
});
|
|
3954
|
+
//# sourceMappingURL=index.cjs.map
|