@nejs/basic-extensions 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +268 -147
  2. package/bin/version +100 -0
  3. package/dist/@nejs/basic-extensions.bundle.2.10.0.js +19 -0
  4. package/dist/@nejs/basic-extensions.bundle.2.10.0.js.map +7 -0
  5. package/dist/cjs/array.extensions.js +174 -0
  6. package/dist/cjs/array.extensions.js.map +1 -1
  7. package/dist/cjs/big.int.extension.js +1 -0
  8. package/dist/cjs/big.int.extension.js.map +1 -1
  9. package/dist/cjs/classes/descriptor.js +1 -1
  10. package/dist/cjs/classes/descriptor.js.map +1 -1
  11. package/dist/cjs/classes/index.d.ts +1 -0
  12. package/dist/cjs/classes/index.js +3 -0
  13. package/dist/cjs/classes/index.js.map +1 -1
  14. package/dist/cjs/classes/iterable.d.ts +44 -0
  15. package/dist/cjs/classes/iterable.js +64 -0
  16. package/dist/cjs/classes/iterable.js.map +1 -1
  17. package/dist/cjs/classes/param.parser.d.ts +10 -10
  18. package/dist/cjs/classes/property.d.ts +86 -0
  19. package/dist/cjs/classes/property.js +284 -0
  20. package/dist/cjs/classes/property.js.map +1 -0
  21. package/dist/cjs/classes/symkeys.d.ts +68 -11
  22. package/dist/cjs/classes/symkeys.js +103 -17
  23. package/dist/cjs/classes/symkeys.js.map +1 -1
  24. package/dist/cjs/classes/type.d.ts +4 -4
  25. package/dist/cjs/function.extensions.js +1 -0
  26. package/dist/cjs/function.extensions.js.map +1 -1
  27. package/dist/cjs/global.this.js +29 -0
  28. package/dist/cjs/global.this.js.map +1 -1
  29. package/dist/cjs/index.d.ts +2 -0
  30. package/dist/cjs/index.js +18 -0
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/json.extensions.js +22 -20
  33. package/dist/cjs/json.extensions.js.map +1 -1
  34. package/dist/cjs/map.extensions.js +1 -0
  35. package/dist/cjs/map.extensions.js.map +1 -1
  36. package/dist/cjs/number.extension.js +1 -0
  37. package/dist/cjs/number.extension.js.map +1 -1
  38. package/dist/cjs/object.extensions.d.ts +0 -29
  39. package/dist/cjs/object.extensions.js +218 -243
  40. package/dist/cjs/object.extensions.js.map +1 -1
  41. package/dist/cjs/set.extensions.js +1 -0
  42. package/dist/cjs/set.extensions.js.map +1 -1
  43. package/dist/cjs/string.extensions.js +478 -283
  44. package/dist/cjs/string.extensions.js.map +1 -1
  45. package/dist/cjs/symbol.extensions.js +500 -24
  46. package/dist/cjs/symbol.extensions.js.map +1 -1
  47. package/dist/cjs/utils/copy.object.d.ts +408 -0
  48. package/dist/cjs/utils/copy.object.js +720 -0
  49. package/dist/cjs/utils/copy.object.js.map +1 -0
  50. package/dist/cjs/utils/index.d.ts +1 -0
  51. package/dist/cjs/utils/index.js +19 -0
  52. package/dist/cjs/utils/index.js.map +1 -0
  53. package/dist/cjs/utils/toolkit.d.ts +1897 -0
  54. package/dist/cjs/utils/toolkit.js +1377 -0
  55. package/dist/cjs/utils/toolkit.js.map +1 -0
  56. package/dist/mjs/array.extensions.js +174 -0
  57. package/dist/mjs/array.extensions.js.map +1 -1
  58. package/dist/mjs/big.int.extension.js +1 -0
  59. package/dist/mjs/big.int.extension.js.map +1 -1
  60. package/dist/mjs/classes/descriptor.js +1 -1
  61. package/dist/mjs/classes/descriptor.js.map +1 -1
  62. package/dist/mjs/classes/index.d.ts +1 -0
  63. package/dist/mjs/classes/index.js +3 -0
  64. package/dist/mjs/classes/index.js.map +1 -1
  65. package/dist/mjs/classes/iterable.d.ts +44 -0
  66. package/dist/mjs/classes/iterable.js +64 -0
  67. package/dist/mjs/classes/iterable.js.map +1 -1
  68. package/dist/mjs/classes/param.parser.d.ts +10 -10
  69. package/dist/mjs/classes/property.d.ts +86 -0
  70. package/dist/mjs/classes/property.js +280 -0
  71. package/dist/mjs/classes/property.js.map +1 -0
  72. package/dist/mjs/classes/symkeys.d.ts +68 -11
  73. package/dist/mjs/classes/symkeys.js +103 -17
  74. package/dist/mjs/classes/symkeys.js.map +1 -1
  75. package/dist/mjs/classes/type.d.ts +4 -4
  76. package/dist/mjs/function.extensions.js +1 -0
  77. package/dist/mjs/function.extensions.js.map +1 -1
  78. package/dist/mjs/global.this.js +6 -0
  79. package/dist/mjs/global.this.js.map +1 -1
  80. package/dist/mjs/index.d.ts +2 -0
  81. package/dist/mjs/index.js +4 -0
  82. package/dist/mjs/index.js.map +1 -1
  83. package/dist/mjs/json.extensions.js +22 -20
  84. package/dist/mjs/json.extensions.js.map +1 -1
  85. package/dist/mjs/map.extensions.js +1 -0
  86. package/dist/mjs/map.extensions.js.map +1 -1
  87. package/dist/mjs/number.extension.js +1 -0
  88. package/dist/mjs/number.extension.js.map +1 -1
  89. package/dist/mjs/object.extensions.d.ts +0 -29
  90. package/dist/mjs/object.extensions.js +215 -239
  91. package/dist/mjs/object.extensions.js.map +1 -1
  92. package/dist/mjs/set.extensions.js +1 -0
  93. package/dist/mjs/set.extensions.js.map +1 -1
  94. package/dist/mjs/string.extensions.js +478 -283
  95. package/dist/mjs/string.extensions.js.map +1 -1
  96. package/dist/mjs/symbol.extensions.js +501 -25
  97. package/dist/mjs/symbol.extensions.js.map +1 -1
  98. package/dist/mjs/utils/copy.object.d.ts +408 -0
  99. package/dist/mjs/utils/copy.object.js +702 -0
  100. package/dist/mjs/utils/copy.object.js.map +1 -0
  101. package/dist/mjs/utils/index.d.ts +1 -0
  102. package/dist/mjs/utils/index.js +3 -0
  103. package/dist/mjs/utils/index.js.map +1 -0
  104. package/dist/mjs/utils/toolkit.d.ts +1897 -0
  105. package/dist/mjs/utils/toolkit.js +1372 -0
  106. package/dist/mjs/utils/toolkit.js.map +1 -0
  107. package/package.json +30 -38
  108. package/repl.bootstrap.js +12 -1
  109. package/src/array.extensions.js +191 -1
  110. package/src/big.int.extension.js +3 -1
  111. package/src/classes/descriptor.js +1 -1
  112. package/src/classes/index.js +4 -0
  113. package/src/classes/iterable.js +74 -0
  114. package/src/classes/property.js +333 -0
  115. package/src/classes/symkeys.js +120 -19
  116. package/src/function.extensions.js +2 -0
  117. package/src/global.this.js +8 -0
  118. package/src/index.js +5 -0
  119. package/src/json.extensions.js +21 -21
  120. package/src/map.extensions.js +3 -1
  121. package/src/number.extension.js +3 -1
  122. package/src/object.extensions.js +240 -262
  123. package/src/set.extensions.js +3 -1
  124. package/src/string.extensions.js +531 -306
  125. package/src/symbol.extensions.js +529 -25
  126. package/src/utils/copy.object.js +780 -0
  127. package/src/utils/index.js +2 -0
  128. package/src/utils/toolkit.js +1471 -0
  129. package/tests/arrayextensions.test.js +2 -0
  130. package/tests/index.test.js +1 -0
  131. package/tests/newClasses/asyncIterable.test.js +2 -0
  132. package/tests/newClasses/deferred.test.js +5 -3
  133. package/tests/newClasses/descriptor.test.js +2 -0
  134. package/tests/newClasses/iterable.test.js +2 -0
  135. package/tests/newClasses/refmap.test.js +2 -1
  136. package/tests/newClasses/refset.test.js +2 -0
  137. package/tests/objectextensions.test.js +2 -0
  138. package/tests/setextensions.test.js +2 -0
  139. package/tests/stringextensions.test.js +1 -0
  140. package/tests/utils/toolkit.test.js +223 -0
  141. package/tsconfig.base.json +1 -1
  142. package/vitest.config.js +7 -0
  143. package/dist/@nejs/basic-extensions.bundle.2.7.0.js +0 -19
  144. package/dist/@nejs/basic-extensions.bundle.2.7.0.js.map +0 -7
  145. package/docs/assets/anchor.js +0 -350
  146. package/docs/assets/bass-addons.css +0 -12
  147. package/docs/assets/bass.css +0 -544
  148. package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
  149. package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
  150. package/docs/assets/fonts/LICENSE.txt +0 -93
  151. package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
  152. package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
  153. package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
  154. package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
  155. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
  156. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
  157. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
  158. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
  159. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
  160. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
  161. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  162. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  163. package/docs/assets/fonts/source-code-pro.css +0 -23
  164. package/docs/assets/github.css +0 -123
  165. package/docs/assets/site.js +0 -168
  166. package/docs/assets/split.css +0 -15
  167. package/docs/assets/split.js +0 -782
  168. package/docs/assets/style.css +0 -147
  169. package/docs/index.html +0 -34965
@@ -0,0 +1,780 @@
1
+ /**
2
+ * Transforms an array into an object using a provided transform
3
+ * function.
4
+ *
5
+ * @function transduceFrom
6
+ * @param {Array} array - The array to transform.
7
+ * @param {Function} transform - The function used to transform each
8
+ * element of the array. It should return an object with 'key' and
9
+ * 'value' properties.
10
+ * @param {Object} [into={}] - The object to transform the array into.
11
+ * @returns {Object} The transformed object.
12
+ * @example
13
+ * const array = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]
14
+ * const transform = (element) => ({ key: element.id, value: element.name })
15
+ * transduceFrom(array, transform)
16
+ * // => { 1: 'John', 2: 'Jane' }
17
+ */
18
+ export function tryIgnore(code) {
19
+ try { return code() } catch(ignore) { return undefined }
20
+ }
21
+
22
+ export function transduceFrom(array, transform, into = {}) {
23
+ if (typeof transform !== 'function') {
24
+ return into
25
+ }
26
+
27
+ return array.reduce((accumulator, element) => {
28
+ const { key, value } = (transform?.(element) ?? {})
29
+ if (key && value) {
30
+ accumulator[key] = value
31
+ }
32
+
33
+ return accumulator
34
+ }, into)
35
+ }
36
+
37
+ /**
38
+ * Transforms a COHandler instance into an object with 'key' and 'value'
39
+ * properties.
40
+ *
41
+ * @function transduceFromCOHandler
42
+ * @param {COHandler} element - The COHandler instance to transform.
43
+ * @returns {Object} An object with 'key' and 'value' properties, where
44
+ * 'key' is the 'property' of the COHandler instance and 'value' is
45
+ * the COHandler instance itself.
46
+ * @example
47
+ * const handler = new COHandler('foo')
48
+ * transduceFromCOHandler(handler)
49
+ * // => { key: 'foo', value: handler }
50
+ */
51
+ export function transduceFromCOHandler(element) {
52
+ const result = {}
53
+
54
+ if (element instanceof COPropertyHandler) {
55
+ result.key = element.property
56
+ result.value = element
57
+ }
58
+
59
+ return result
60
+ }
61
+
62
+ /**
63
+ * Creates a transducer function by partially applying the 'array' and
64
+ * 'transform' arguments to the 'transduceFrom' function.
65
+ *
66
+ * @function makeTransducer
67
+ * @param {Array} array - The array to transform.
68
+ * @param {Function} transform - The function used to transform each
69
+ * element of the array.
70
+ * @returns {Function} A transducer function that takes an 'into' object
71
+ * and returns the result of calling 'transduceFrom' with the provided
72
+ * 'array', 'transform', and 'into' arguments.
73
+ * @example
74
+ * const array = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]
75
+ * const transform = (element) => ({ key: element.id, value: element.name })
76
+ * const transducer = makeTransducer(array, transform)
77
+ * transducer({ 3: 'Jim' })
78
+ * // => { 1: 'John', 2: 'Jane', 3: 'Jim' }
79
+ */
80
+ export function makeTransducer(array, transform) {
81
+ return transduceFrom.bind(null, array, transform)
82
+ }
83
+
84
+ /**
85
+ * A class for handling property descriptors during object copying.
86
+ * @class
87
+ * @example
88
+ * const handler = new COPropertyHandler('foo', (prop, descriptor) => {
89
+ * descriptor.enumerable = false
90
+ * return descriptor
91
+ * })
92
+ * handler.handle('foo', { value: 42, writable: true, enumerable: true })
93
+ * // => { value: 42, writable: true, enumerable: false }
94
+ */
95
+ export class COPropertyHandler {
96
+ /**
97
+ * The name of the property this handler is responsible for.
98
+ * @type {string|undefined}
99
+ */
100
+ property = undefined;
101
+
102
+ /**
103
+ * The property handler. When provided and invoked, it will receive
104
+ * a the property name of the value being handled, the current
105
+ * descriptor to transform, and the object into which values are
106
+ * currently being copied into.
107
+ *
108
+ * The result must be a COPropertyHandler response type, which can
109
+ * be made with {@link COPropertyHandler.makeResponse} and which
110
+ * can be validated with {@link COPropertyHandler.isResponse}.
111
+ *
112
+ * The handler should have the following parameters
113
+ * - {string} property - The name of the property being handled.
114
+ * - {Object} curDescriptor - The property descriptor to handle.
115
+ * - {Object} destination - The destination object into which
116
+ * properties are being copied.
117
+ *
118
+ * An should return
119
+ * - {Object} a `COPropertyHandler.Response` type object which
120
+ * can be made with {@link COPropertyHandler.makeResponse}.
121
+ *
122
+ * @type {function|undefined}
123
+ */
124
+ handler = undefined;
125
+
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(property, handler) {
133
+ Object.assign(this, { property, handler })
134
+ }
135
+
136
+ /**
137
+ * Handles a property descriptor using the registered handler function.
138
+ * @param {string} property - The name of the property being handled.
139
+ * @param {Object} descriptor - The property descriptor to handle.
140
+ * @returns {Object} The resulting property descriptor after handling.
141
+ */
142
+ handle(property, descriptor, destination) {
143
+ if (this.handler) {
144
+ return COPropertyHandler.defaultHandle(
145
+ property,
146
+ descriptor,
147
+ this.handler,
148
+ )
149
+ }
150
+
151
+ return descriptor
152
+ }
153
+
154
+ /**
155
+ * The default property descriptor handler.
156
+ *
157
+ * @param {string} property - The name of the property being handled.
158
+ * @param {Object} curDescriptor - The property descriptor to handle.
159
+ * @param {Object} destination - The destination object into which
160
+ * properties are being copied.
161
+ * @param {function} handler - The function to handle the property
162
+ * descriptor.
163
+ * @returns {Object} a `COPropertyHandler.Response` type object which
164
+ * can be made with {@link COPropertyHandler.makeResponse}.
165
+ */
166
+ static defaultHandle(property, curDescriptor, destination, handler) {
167
+ if (typeof handler === 'function') {
168
+ try {
169
+ const {
170
+ descriptor,
171
+ flow
172
+ } = handler(property, curDescriptor, destination)
173
+ return this.makeResponse(descriptor, flow)
174
+ }
175
+ catch (ignore) { }
176
+ }
177
+
178
+ return this.makeResponse(curDescriptor)
179
+ }
180
+
181
+ /**
182
+ * Creates a COPropertyHandler response object.
183
+ *
184
+ * @param {Object} descriptor - The property descriptor.
185
+ * @param {string} [flow=COPropertyHandler.kNoChange] - The flow control
186
+ * directive. Must be one of the values from
187
+ * {@link COPropertyHandler.flowTypes} if provided.
188
+ * @returns {COPropertyHandler.Response} The response object.
189
+ * @example
190
+ * COPropertyHandler.makeResponse({ value: 42, writable: false })
191
+ * // => {
192
+ * // newDescriptor: { value: 42, writable: false },
193
+ * // flow: 'nochange'
194
+ * // }
195
+ */
196
+ static makeResponse(descriptor, flow) {
197
+ return {
198
+ newDescriptor: descriptor,
199
+ flow: flow ?? this.kNoChange,
200
+ get [Symbol.toStringTag]() { return 'COPropertyHandler.Response' }
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Checks if a value is a valid COPropertyHandler response object.
206
+ * @param {*} value - The value to check.
207
+ * @returns {boolean} `true` if the value is a response object, `false`
208
+ * otherwise.
209
+ * @example
210
+ * COPropertyHandler.isResponse({
211
+ * newDescriptor: { value: 42 },
212
+ * flow: 'nochange'
213
+ * })
214
+ * // => true
215
+ */
216
+ static isResponse(value) {
217
+ return (
218
+ value && typeof value === 'object' &&
219
+ value[Symbol.toStringTag] === 'COPropertyHandler.Response'
220
+ )
221
+ }
222
+
223
+ /**
224
+ * The flow control directive indicating no change in flow.
225
+ * @type {string}
226
+ */
227
+ static get kNoChange() { return 'nochange' }
228
+
229
+ /**
230
+ * The flow control directive indicating to continue the loop.
231
+ * @type {string}
232
+ */
233
+ static get kContinue() { return 'continue' }
234
+
235
+ /**
236
+ * The flow control directive indicating to break the loop.
237
+ * @type {string}
238
+ */
239
+ static get kBreak() { return 'break' }
240
+
241
+ /**
242
+ * An array of all valid flow control directive values.
243
+ * @type {string[]}
244
+ */
245
+ static get flowTypes() {
246
+ return [this.kNoChange, this.kContinue, this.kBreak]
247
+ }
248
+
249
+ /**
250
+ * An object mapping flow control directive values to their
251
+ * corresponding string representations.
252
+ * @type {Object.<string, string>}
253
+ */
254
+ static get flowEnum() {
255
+ return {
256
+ [this.kNoChange]: this.kNoChange,
257
+ [this.kContinue]: this.kContinue,
258
+ [this.kBreak]: this.kBreak,
259
+ }
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Returns an object containing getter functions that return Symbol
265
+ * values representing different visibility configurations for object
266
+ * properties.
267
+ *
268
+ * @function
269
+ * @name kVisibilityKeys
270
+ * @returns {Object} An object with the following properties:
271
+ * @property {symbol} mutablyHidden - Returns a Symbol representing a
272
+ * property that is not enumerable but is configurable.
273
+ * @property {symbol} mutablyVisible - Returns a Symbol representing a
274
+ * property that is both enumerable and configurable.
275
+ * @property {symbol} immutablyHidden - Returns a Symbol representing
276
+ * a property that is neither enumerable nor configurable.
277
+ * @property {symbol} immutablyVisible - Returns a Symbol representing
278
+ * a property that is enumerable but not configurable.
279
+ * @property {symbol} flexiblyHidden - Returns a Symbol representing a
280
+ * property that is not enumerable, writable and not configurable.
281
+ * @property {symbol} flexiblyVisible - Returns a Symbol representing
282
+ * a property that is both enumerable and writable, but not
283
+ * configurable.
284
+ * @property {Generator} keys - Returns a generator that yields the
285
+ * string keys of the visibility configurations.
286
+ * @property {Generator} symbols - Returns a generator that yields the
287
+ * Symbol values of the visibility configurations.
288
+ * @property {Generator} entries - Returns a generator that yields
289
+ * [key, Symbol] pairs for each visibility configuration.
290
+ * @property {Generator} descriptors - Returns a generator that yields
291
+ * [key, descriptor] pairs for each visibility configuration, where
292
+ * descriptor is the parsed JSON representation of the Symbol's
293
+ * description.
294
+ * @property {Generator} [Symbol.iterator] - Returns the same generator
295
+ * as the symbols property, allowing the object to be iterated over
296
+ * directly to access the Symbol values.
297
+ *
298
+ * @example
299
+ * const { mutablyHidden, mutablyVisible } = kVisibilityKeys()
300
+ *
301
+ * const obj = {
302
+ * [mutablyHidden]: 'hidden value',
303
+ * [mutablyVisible]: 'visible value',
304
+ * }
305
+ *
306
+ * console.log(obj) // { [Symbol()]: 'visible value' }
307
+ * console.log(obj[mutablyHidden]) // 'hidden value'
308
+ * console.log(obj[mutablyVisible]) // 'visible value'
309
+ *
310
+ * @example
311
+ * const visibilityKeys = kVisibilityKeys()
312
+ *
313
+ * for (const key of visibilityKeys.keys()) {
314
+ * console.log(key)
315
+ * }
316
+ * // Output:
317
+ * // 'mutablyHidden'
318
+ * // 'mutablyVisible'
319
+ * // 'immutablyHidden'
320
+ * // 'immutablyVisible'
321
+ * // 'flexiblyHidden'
322
+ * // 'flexiblyVisible'
323
+ *
324
+ * @example
325
+ * const visibilityKeys = kVisibilityKeys()
326
+ *
327
+ * for (const symbol of visibilityKeys) {
328
+ * console.log(symbol)
329
+ * }
330
+ * // Output:
331
+ * // Symbol({"enumerable":false,"configurable":true})
332
+ * // Symbol({"enumerable":true,"configurable":true})
333
+ * // Symbol({"enumerable":false,"configurable":false})
334
+ * // Symbol({"enumerable":true,"configurable":false})
335
+ * // Symbol({"enumerable":false,"writable":true})
336
+ * // Symbol({"enumerable":true,"writable":true})
337
+ */
338
+ export function kVisibilityKeys() {
339
+ const keys = {
340
+ get mutablyHidden() {
341
+ return Symbol.for(JSON.stringify({
342
+ enumerable: false,
343
+ configurable: true,
344
+ }))
345
+ },
346
+
347
+ get mutablyVisible() {
348
+ return Symbol.for(JSON.stringify({
349
+ enumerable: true,
350
+ configurable: true,
351
+ }))
352
+ },
353
+
354
+ get immutablyHidden() {
355
+ return Symbol.for(JSON.stringify({
356
+ enumerable: false,
357
+ configurable: false,
358
+ }))
359
+ },
360
+
361
+ get immutablyVisible() {
362
+ return Symbol.for(JSON.stringify({
363
+ enumerable: true,
364
+ configurable: false,
365
+ }))
366
+ },
367
+
368
+ get flexiblyHidden() {
369
+ return Symbol.for(JSON.stringify({
370
+ enumerable: false,
371
+ configurable: false,
372
+ writable: true,
373
+ }))
374
+ },
375
+
376
+ get flexiblyVisible() {
377
+ return Symbol.for(JSON.stringify({
378
+ enumerable: true,
379
+ configurable: false,
380
+ writable: true,
381
+ }))
382
+ },
383
+ }
384
+
385
+ const enumerated = {
386
+ mutablyHidden: keys.mutablyHidden,
387
+ mutablyVisible: keys.mutablyVisible,
388
+ immutablyHidden: keys.immutablyHidden,
389
+ immutablyVisible: keys.immutablyVisible,
390
+ flexiblyHidden: keys.flexiblyHidden,
391
+ flexiblyVisible: keys.flexiblyVisible,
392
+ }
393
+
394
+ function *keyGenerator() {
395
+ for (const key of Object.keys(enumerated)) { yield key }
396
+ }
397
+
398
+ function *symbolGenerator() {
399
+ for (const value of Object.values(enumerated)) { yield value }
400
+ }
401
+
402
+ function *entryGenerator() {
403
+ for (const entry of Object.entries(enumerated)) { yield entry }
404
+ }
405
+
406
+ function *descriptorGenertor() {
407
+ for (const [key, value] of entryGenerator()) {
408
+ yield [key, JSON.parse(value.description)]
409
+ }
410
+ }
411
+
412
+ Object.defineProperties(keys, {
413
+ enumeration: { get() { return enumerated }, enumerable: false },
414
+ keys: { get() { return keyGenerator() }, enumerable: false },
415
+ symbols: { get() { return symbolGenerator() }, enumerable: false},
416
+ entries: { get() { return entryGenerator() }, enumerable: false},
417
+ descriptors: { get() { return descriptorGenertor() }, enumerable: false },
418
+ descriptorFor: {
419
+ value(symbol) {
420
+ try {
421
+ return JSON.parse(symbol.description)
422
+ }
423
+ catch (ignored) {}
424
+ return undefined
425
+ },
426
+ enumerable: false
427
+ },
428
+ [Symbol.iterator]: { get() { return symbolGenerator() } },
429
+ })
430
+
431
+ return keys
432
+ }
433
+
434
+ /**
435
+ * An object containing Symbol values representing different visibility
436
+ * configurations for object properties.
437
+ *
438
+ * @constant {Object} VisibilityKeys
439
+ * @property {symbol} mutablyHidden - A Symbol representing a property
440
+ * that is not enumerable but is configurable.
441
+ * @property {symbol} mutablyVisible - A Symbol representing a property
442
+ * that is both enumerable and configurable.
443
+ * @property {symbol} immutablyHidden - A Symbol representing a property
444
+ * that is neither enumerable nor configurable.
445
+ * @property {symbol} immutablyVisible - A Symbol representing a property
446
+ * that is enumerable but not configurable.
447
+ * @property {symbol} flexiblyHidden - A Symbol representing a property
448
+ * that is not enumerable, writable and not configurable.
449
+ * @property {symbol} flexiblyVisible - A Symbol representing a property
450
+ * that is both enumerable and writable, but not configurable.
451
+ */
452
+ export const VisibilityKeys = kVisibilityKeys()
453
+
454
+ /**
455
+ * A class for handling property descriptors during object copying based
456
+ * on a specified visibility key.
457
+ *
458
+ * @class VisibilityScopeHandler
459
+ * @extends COPropertyHandler
460
+ * @param {symbol} visibilityKey - The visibility key to use for handling
461
+ * property descriptors.
462
+ * @example
463
+ * const handler = new VisibilityScopeHandler(VisibilityKeys.mutablyHidden)
464
+ * handler.handle('foo', { value: 42, writable: true, enumerable: true })
465
+ * // => { value: 42, writable: true, enumerable: false }
466
+ */
467
+ export class VisibilityScopeHandler extends COPropertyHandler {
468
+ overrides = undefined;
469
+
470
+ /**
471
+ * Creates a new VisibilityScopeHandler instance.
472
+ *
473
+ * @constructor
474
+ * @param {symbol} visibilityKey - The visibility key to use for handling
475
+ * property descriptors.
476
+ */
477
+ constructor(visibilityKey) {
478
+ super(visibilityKey, (property, descriptor, dest, source) => {
479
+ let data = descriptor?.value
480
+ if (!descriptor || typeof descriptor.value !== 'object') {
481
+ return COPropertyHandler.makeResponse(descriptor, 'nochange')
482
+ }
483
+
484
+ if (!data && (descriptor?.get || descriptor?.set)) {
485
+ const newDescriptor = this.applyOverridesTo(descriptor)
486
+ return COPropertyHandler.makeResponse(newDescriptor, 'nochange')
487
+ }
488
+
489
+ data = customCopyObject({deep: false}, {}, data ?? {})
490
+ this.walkAndApply(data)
491
+ descriptor.value = data
492
+
493
+ return COPropertyHandler.makeResponse(descriptor, 'continue')
494
+ })
495
+
496
+ tryIgnore(() => this.overrides = JSON.parse(property.description))
497
+ }
498
+
499
+ applyOverridesTo(existingDescriptor, overwrite = false) {
500
+ const allowed = ['value','get','set','writable','configurable','enumerable']
501
+ const output = overwrite ? existingDescriptor : { ...existingDescriptor }
502
+ for (let [key, value] of Object.entries(this.overrides ?? {})) {
503
+ if (!~allowed.indexOf(key)) {
504
+ continue
505
+ }
506
+
507
+ if (!(
508
+ ['get','set'].some(k => k === key) &&
509
+ ['undefined', 'function'].some(t => typeof value === t)
510
+ )) {
511
+ continue
512
+ }
513
+
514
+ if (!(
515
+ ['enumerable','configurable','writable'].some(k => k === key) &&
516
+ typeof value !== 'boolean'
517
+ )) {
518
+ value = !!value
519
+ }
520
+
521
+ delete output[key]
522
+ output[key] = value
523
+ }
524
+ return output
525
+ }
526
+
527
+ walkAndApply(to) {
528
+ Reflect.ownKeys(to).forEach(key => {
529
+ tryIgnore(() => {
530
+ let result = Object.getOwnPropertyDescriptor(to, key)
531
+ this.applyOverridesTo(result, true)
532
+ Object.defineProperty(to, key, result)
533
+ })
534
+ })
535
+ }
536
+ }
537
+
538
+ /**
539
+ * A handler for mutably visible properties during object copying.
540
+ * @class
541
+ * @extends VisibilityScopeHandler
542
+ * @example
543
+ * const handler = new MutablyVisibleHandler()
544
+ * const sharedHandler = MutablyVisibleHandler.shared
545
+ */
546
+ export class MutablyVisibleHandler extends VisibilityScopeHandler {
547
+ constructor() { super(VisibilityKeys.mutablyVisible) }
548
+ static get shared() {
549
+ return this.#singleton ?? (this.#singleton = new this)
550
+ }
551
+ static #singleton
552
+ }
553
+
554
+ /**
555
+ * A handler for mutably hidden properties during object copying.
556
+ * @class
557
+ * @extends VisibilityScopeHandler
558
+ * @example
559
+ * const handler = new MutablyHiddenHandler()
560
+ * const sharedHandler = MutablyHiddenHandler.shared
561
+ */
562
+ export class MutablyHiddenHandler extends VisibilityScopeHandler {
563
+ constructor() { super(VisibilityKeys.mutablyHidden) }
564
+ static get shared() {
565
+ return this.#singleton ?? (this.#singleton = new this)
566
+ }
567
+ static #singleton
568
+ }
569
+
570
+ /**
571
+ * A handler for immutably visible properties during object copying.
572
+ * @class
573
+ * @extends VisibilityScopeHandler
574
+ * @example
575
+ * const handler = new ImmutablyVisibleHandler()
576
+ * const sharedHandler = ImmutablyVisibleHandler.shared
577
+ */
578
+ export class ImmutablyVisibleHandler extends VisibilityScopeHandler {
579
+ constructor() { super(VisibilityKeys.immutablyVisible) }
580
+ static get shared() {
581
+ return this.#singleton ?? (this.#singleton = new this)
582
+ }
583
+ static #singleton
584
+ }
585
+
586
+ /**
587
+ * A handler for immutably hidden properties during object copying.
588
+ * @class
589
+ * @extends VisibilityScopeHandler
590
+ * @example
591
+ * const handler = new ImmutablyHiddenHandler()
592
+ * const sharedHandler = ImmutablyHiddenHandler.shared
593
+ */
594
+ export class ImmutablyHiddenHandler extends VisibilityScopeHandler {
595
+ constructor() { super(VisibilityKeys.immutablyHidden) }
596
+ static get shared() {
597
+ return this.#singleton ?? (this.#singleton = new this)
598
+ }
599
+ static #singleton
600
+ }
601
+
602
+ /**
603
+ * A handler for flexibly visible properties during object copying.
604
+ * @class
605
+ * @extends VisibilityScopeHandler
606
+ * @example
607
+ * const handler = new FlexiblyVisibleHandler()
608
+ * const sharedHandler = FlexiblyVisibleHandler.shared
609
+ */
610
+ export class FlexiblyVisibleHandler extends VisibilityScopeHandler {
611
+ constructor() { super(VisibilityKeys.flexiblyVisible) }
612
+ static get shared() {
613
+ return this.#singleton ?? (this.#singleton = new this)
614
+ }
615
+ static #singleton
616
+ }
617
+
618
+ /**
619
+ * A handler for flexibly hidden properties during object copying.
620
+ * @class
621
+ * @extends VisibilityScopeHandler
622
+ * @example
623
+ * const handler = new FlexiblyHiddenHandler()
624
+ * const sharedHandler = FlexiblyHiddenHandler.shared
625
+ */
626
+ export class FlexiblyHiddenHandler extends VisibilityScopeHandler {
627
+ constructor() { super(VisibilityKeys.flexiblyHidden) }
628
+ static get shared() {
629
+ return this.#singleton ?? (this.#singleton = new this)
630
+ }
631
+ static #singleton
632
+ }
633
+
634
+ Object.defineProperties(COPropertyHandler, {
635
+ MutablyHiddenHandler: { get() { return MutablyHiddenHandler.shared } },
636
+ MutablyVisibleHandler: { get() { return MutablyVisibleHandler.shared } },
637
+ ImmutablyHiddenHandler: { get() { return ImmutablyHiddenHandler.shared } },
638
+ ImmutablyVisibleHandler: { get() { return ImmutablyVisibleHandler.shared } },
639
+ FlexiblyHiddenHandler: { get() { return FlexiblyHiddenHandler.shared } },
640
+ FlexiblyVisibleHandler: { get() { return FlexiblyVisibleHandler.shared } },
641
+ handlers: {
642
+ value: [
643
+ MutablyHiddenHandler, MutablyVisibleHandler, ImmutablyHiddenHandler,
644
+ ImmutablyVisibleHandler, FlexiblyHiddenHandler, FlexiblyVisibleHandler,
645
+ ].map(klass => klass.shared),
646
+ configurable: true,
647
+ enumerable: true
648
+ },
649
+ })
650
+
651
+ /**
652
+ * Creates a deep or shallow copy of the provided source objects and merges
653
+ * them into the destination object. The function uses a Set to keep track
654
+ * of visited objects to avoid circular references.
655
+ *
656
+ * @function
657
+ * @name copyObject
658
+ * @param {boolean} deep - If true, performs a deep copy, otherwise performs
659
+ * a shallow copy.
660
+ * @param {object} destination - The object to which properties will be copied.
661
+ * @param {...object} sources - The source object(s) from which properties
662
+ * will be copied.
663
+ * @returns {object} The destination object with the copied properties.
664
+ *
665
+ * @example
666
+ * // Shallow copy
667
+ * const obj1 = { a: 1, b: { c: 2 } };
668
+ * const obj2 = { b: { d: 3 }, e: 4 };
669
+ * const result = copyObject(false, obj1, obj2);
670
+ * console.log(result); // Output: { a: 1, b: { d: 3 }, e: 4 }
671
+ *
672
+ * @example
673
+ * // Deep copy
674
+ * const obj1 = { a: 1, b: { c: 2 } };
675
+ * const obj2 = { b: { d: 3 }, e: 4 };
676
+ * const result = copyObject(true, obj1, obj2);
677
+ * console.log(result); // Output: { a: 1, b: { c: 2, d: 3 }, e: 4 }
678
+ */
679
+ export function copyObject(deep, destination, ...sources) {
680
+ const options = {
681
+ deep: deep || false,
682
+ propertyHandlers: COPropertyHandler?.handlers ?? [],
683
+ }
684
+
685
+ return customCopyObject(options, destination, ...sources)
686
+ }
687
+
688
+ export function customCopyObject(_options, _destination, ..._sources) {
689
+ const visited = new Set()
690
+ const [options, destination, sources] = ccoParseArgs(
691
+ _options, _destination, ..._sources
692
+ )
693
+
694
+ let { deep } = options
695
+
696
+ for (const source of sources) {
697
+ if (source === null || typeof source !== 'object' || visited.has(source)) {
698
+ continue
699
+ }
700
+
701
+ visited.add(source)
702
+ const keys = Reflect.ownKeys(source)
703
+ for (let key of keys) {
704
+ let descriptor
705
+
706
+ try {
707
+ descriptor = Object.getOwnPropertyDescriptor(source, key)
708
+ } catch (err) {
709
+ console.warn(`Failed to get descriptor for key "${key}": ${err}`)
710
+ continue
711
+ }
712
+
713
+ const isDataDesc = Reflect.has(descriptor, 'value')
714
+ const keyedValue = descriptor?.value
715
+
716
+ const conditionsMet = [
717
+ isDataDesc,
718
+ keyedValue,
719
+ typeof keyedValue === 'object',
720
+ !visited.has(keyedValue)
721
+ ].every(condition => condition)
722
+
723
+ if (conditionsMet) {
724
+ visited.add(keyedValue)
725
+
726
+ const prototype = Object.getPrototypeOf(keyedValue)
727
+ const descriptors = Object.getOwnPropertyDescriptors(keyedValue)
728
+ const replacement = Object.create(prototype, descriptors)
729
+
730
+ descriptor.value = deep
731
+ ? customCopyObject(options, replacement, keyedValue)
732
+ : replacement
733
+ }
734
+
735
+ try {
736
+ Object.defineProperty(destination, key, descriptor)
737
+ } catch (err) {
738
+ console.error(`Failed to define property "${key}": ${err}`)
739
+ }
740
+ }
741
+ }
742
+
743
+ return destination
744
+ }
745
+
746
+ function ccoParseArgs(options, destination, ...sources) {
747
+ // Parse options
748
+ let { deep = true, propertyHandlers = [] } = options
749
+
750
+ // Ensure boolean'ness
751
+ deep = !!deep
752
+
753
+ // Ensure propertyHandlers are converted for our ease of use
754
+ // Transform 1: Ensure array of COPropertyHandlers at the
755
+ // cost of potentially having none
756
+ propertyHandlers = (Array.isArray(propertyHandlers)
757
+ ? propertyHandlers
758
+ : [propertyHandlers]
759
+ ).filter(element => element instanceof COPropertyHandler)
760
+
761
+ // Transform 2: Convert array of handlers into an object keyed
762
+ // as { [handler.property]: handler }
763
+ const transducer = makeTransducer(propertyHandlers, transduceFromCOHandler)
764
+ propertyHandlers = transducer({})
765
+
766
+ // Rebuild options in the case that we recurse
767
+ options = { deep, propertyHandlers }
768
+
769
+ // Ensure sources have only objects
770
+ sources = sources.filter(source => source && typeof source === 'object')
771
+
772
+ // Ensure the destination is not null
773
+ if (!destination) {
774
+ destination = {}
775
+ }
776
+
777
+ return [ options, destination, sources ]
778
+ }
779
+
780
+ export default copyObject