@nejs/basic-extensions 1.6.1 → 1.7.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.
- package/.esdoc.json +9 -0
- package/README.md +2025 -11
- package/bin/clean +6 -0
- package/dist/@nejs/basic-extensions.bundle.1.6.1.js +4 -0
- package/dist/@nejs/basic-extensions.bundle.1.6.1.js.map +7 -0
- package/dist/cjs/arrayextensions.js +1 -0
- package/dist/cjs/arrayextensions.js.map +1 -0
- package/dist/cjs/functionextensions.js +1 -0
- package/dist/cjs/functionextensions.js.map +1 -0
- package/dist/cjs/globals.js +2 -1
- package/dist/cjs/globals.js.map +1 -0
- package/dist/cjs/index.d.ts +10 -19
- package/dist/cjs/index.js +69 -76
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mapextensions.d.ts +2 -0
- package/dist/cjs/mapextensions.js +30 -0
- package/dist/cjs/mapextensions.js.map +1 -0
- package/dist/cjs/newClasses/asyncIterable.d.ts +123 -0
- package/dist/cjs/{asyncIterable.js → newClasses/asyncIterable.js} +7 -4
- package/dist/cjs/newClasses/asyncIterable.js.map +1 -0
- package/dist/cjs/newClasses/descriptor.d.ts +401 -0
- package/dist/cjs/{descriptor.js → newClasses/descriptor.js} +150 -80
- package/dist/cjs/newClasses/descriptor.js.map +1 -0
- package/dist/cjs/newClasses/iterable.d.ts +125 -0
- package/dist/cjs/{iterable.js → newClasses/iterable.js} +36 -10
- package/dist/cjs/newClasses/iterable.js.map +1 -0
- package/dist/cjs/newClasses/refmap.d.ts +238 -0
- package/dist/cjs/newClasses/refmap.js +433 -0
- package/dist/cjs/newClasses/refmap.js.map +1 -0
- package/dist/cjs/newClasses/refset.d.ts +186 -0
- package/dist/cjs/{refset.js → newClasses/refset.js} +4 -2
- package/dist/cjs/newClasses/refset.js.map +1 -0
- package/dist/cjs/objectextensions.d.ts +7 -6
- package/dist/cjs/objectextensions.js +85 -43
- package/dist/cjs/objectextensions.js.map +1 -0
- package/dist/cjs/reflectextensions.js +16 -12
- package/dist/cjs/reflectextensions.js.map +1 -0
- package/dist/cjs/stringextensions.js +1 -0
- package/dist/cjs/stringextensions.js.map +1 -0
- package/dist/cjs/symbolextensions.js +3 -1
- package/dist/cjs/symbolextensions.js.map +1 -0
- package/dist/cjs/weakrefextensions.js +1 -0
- package/dist/cjs/weakrefextensions.js.map +1 -0
- package/dist/mjs/arrayextensions.js +1 -0
- package/dist/mjs/arrayextensions.js.map +1 -0
- package/dist/mjs/functionextensions.js +1 -0
- package/dist/mjs/functionextensions.js.map +1 -0
- package/dist/mjs/globals.js +2 -1
- package/dist/mjs/globals.js.map +1 -0
- package/dist/mjs/index.d.ts +10 -19
- package/dist/mjs/index.js +67 -60
- package/dist/mjs/index.js.map +1 -0
- package/dist/mjs/mapextensions.d.ts +2 -0
- package/dist/mjs/mapextensions.js +27 -0
- package/dist/mjs/mapextensions.js.map +1 -0
- package/dist/mjs/newClasses/asyncIterable.d.ts +123 -0
- package/dist/mjs/{asyncIterable.js → newClasses/asyncIterable.js} +106 -105
- package/dist/mjs/newClasses/asyncIterable.js.map +1 -0
- package/dist/mjs/newClasses/descriptor.d.ts +401 -0
- package/dist/mjs/{descriptor.js → newClasses/descriptor.js} +129 -67
- package/dist/mjs/newClasses/descriptor.js.map +1 -0
- package/dist/mjs/newClasses/iterable.d.ts +125 -0
- package/dist/mjs/newClasses/iterable.js +199 -0
- package/dist/mjs/newClasses/iterable.js.map +1 -0
- package/dist/mjs/newClasses/refmap.d.ts +238 -0
- package/dist/mjs/newClasses/refmap.js +417 -0
- package/dist/mjs/newClasses/refmap.js.map +1 -0
- package/dist/mjs/newClasses/refset.d.ts +186 -0
- package/dist/mjs/{refset.js → newClasses/refset.js} +3 -2
- package/dist/mjs/newClasses/refset.js.map +1 -0
- package/dist/mjs/objectextensions.d.ts +7 -6
- package/dist/mjs/objectextensions.js +84 -42
- package/dist/mjs/objectextensions.js.map +1 -0
- package/dist/mjs/reflectextensions.js +16 -12
- package/dist/mjs/reflectextensions.js.map +1 -0
- package/dist/mjs/stringextensions.js +1 -0
- package/dist/mjs/stringextensions.js.map +1 -0
- package/dist/mjs/symbolextensions.js +3 -1
- package/dist/mjs/symbolextensions.js.map +1 -0
- package/dist/mjs/weakrefextensions.js +1 -0
- package/dist/mjs/weakrefextensions.js.map +1 -0
- package/docs/assets/anchor.js +350 -0
- package/docs/assets/bass-addons.css +12 -0
- package/docs/assets/bass.css +544 -0
- package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
- package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
- package/docs/assets/fonts/LICENSE.txt +93 -0
- package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
- package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
- package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
- package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
- package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
- package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
- package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
- package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
- package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
- package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
- package/docs/assets/fonts/source-code-pro.css +23 -0
- package/docs/assets/github.css +123 -0
- package/docs/assets/site.js +168 -0
- package/docs/assets/split.css +15 -0
- package/docs/assets/split.js +782 -0
- package/docs/assets/style.css +147 -0
- package/docs/index.html +13060 -0
- package/jsdoc-config.json +31 -0
- package/package.json +12 -3
- package/src/globals.js +1 -1
- package/src/index.js +75 -82
- package/src/mapextensions.js +30 -0
- package/src/{asyncIterable.js → newClasses/asyncIterable.js} +117 -117
- package/src/{descriptor.js → newClasses/descriptor.js} +137 -74
- package/src/newClasses/iterable.js +221 -0
- package/src/newClasses/refmap.js +483 -0
- package/src/{refset.js → newClasses/refset.js} +2 -2
- package/src/objectextensions.js +97 -46
- package/src/reflectextensions.js +16 -14
- package/src/symbolextensions.js +2 -1
- package/tests/index.test.js +1 -1
- package/tests/{asyncIterable.test.js → newClasses/asyncIterable.test.js} +3 -4
- package/tests/newClasses/descriptor.test.js +252 -0
- package/tests/{iterable.test.js → newClasses/iterable.test.js} +2 -4
- package/tests/newClasses/refmap.test.js +69 -0
- package/tests/{refset.test.js → newClasses/refset.test.js} +2 -4
- package/tests/objectextensions.test.js +128 -0
- package/tsconfig.base.json +2 -1
- package/dist/@nejs/basic-extensions.bundle.1.6.0.js +0 -2
- package/dist/@nejs/basic-extensions.bundle.1.6.0.js.map +0 -7
- package/dist/cjs/asyncIterable.d.ts +0 -3
- package/dist/cjs/descriptor.d.ts +0 -2
- package/dist/cjs/iterable.d.ts +0 -3
- package/dist/cjs/refset.d.ts +0 -2
- package/dist/mjs/asyncIterable.d.ts +0 -3
- package/dist/mjs/descriptor.d.ts +0 -2
- package/dist/mjs/iterable.d.ts +0 -3
- package/dist/mjs/iterable.js +0 -184
- package/dist/mjs/refset.d.ts +0 -2
- package/src/iterable.js +0 -203
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { Extension } from '@nejs/extension'
|
|
2
|
-
import { ObjectExtensions } from '
|
|
3
|
-
import {
|
|
4
|
-
import { ReflectExtensions } from './reflectextensions.js'
|
|
2
|
+
import { ObjectExtensions } from '../objectextensions.js'
|
|
3
|
+
import { ReflectExtensions } from '../reflectextensions.js'
|
|
5
4
|
|
|
6
|
-
const isObject = ObjectExtensions.
|
|
7
|
-
const
|
|
8
|
-
const isString = StringExtensions.patchEntries?.isString?.computed
|
|
9
|
-
const hasSome = ReflectExtensions.patchEntries?.hasSome?.computed
|
|
5
|
+
const { isObject, isValidKey } = ObjectExtensions.patches
|
|
6
|
+
const { hasSome } = ReflectExtensions.patches
|
|
10
7
|
|
|
11
|
-
class Descriptor {
|
|
12
|
-
|
|
8
|
+
export class Descriptor {
|
|
9
|
+
/**
|
|
10
|
+
* The default private descriptor value is that of `enigmatic`
|
|
11
|
+
*
|
|
12
|
+
* @private
|
|
13
|
+
* @type {object}
|
|
14
|
+
*/
|
|
15
|
+
#desc = undefined
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An optionally associated object, usually the parent from which
|
|
19
|
+
* the descriptor was taken, or undefined if none was able to be
|
|
20
|
+
* derived.
|
|
21
|
+
*
|
|
22
|
+
* @type {object}
|
|
23
|
+
*/
|
|
24
|
+
#object = undefined
|
|
13
25
|
|
|
14
26
|
/**
|
|
15
27
|
* Creates a new instance of Descriptor either from another object or
|
|
@@ -21,13 +33,21 @@ class Descriptor {
|
|
|
21
33
|
* on the aforesupplied object.
|
|
22
34
|
*/
|
|
23
35
|
constructor(object, key) {
|
|
24
|
-
|
|
36
|
+
if ((object ?? key) === undefined) {
|
|
37
|
+
this.#desc = Descriptor.enigmatic
|
|
38
|
+
}
|
|
25
39
|
|
|
26
|
-
if (
|
|
40
|
+
if (Descriptor.isDescriptor(object)) {
|
|
41
|
+
this.#desc = object
|
|
42
|
+
this.#object = undefined
|
|
43
|
+
}
|
|
44
|
+
else if (isObject(object) && isValidKey(key)) {
|
|
27
45
|
this.#desc = Object.getOwnPropertyDescriptor(object, key)
|
|
46
|
+
this.#object = object
|
|
28
47
|
}
|
|
29
48
|
|
|
30
49
|
if (!this.isDescriptor) {
|
|
50
|
+
console.error('Current descriptor:', this.#desc)
|
|
31
51
|
throw new Error(`Not a valid descriptor:`, this.#desc)
|
|
32
52
|
}
|
|
33
53
|
}
|
|
@@ -160,6 +180,18 @@ class Descriptor {
|
|
|
160
180
|
return this.#desc?.get
|
|
161
181
|
}
|
|
162
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Retrieves the {@link get} function for this accessor and binds it to
|
|
185
|
+
* the object from which the descriptor was derived, if that value is set.
|
|
186
|
+
* Otherwise this method is identical to the {@link get} accessor.
|
|
187
|
+
*
|
|
188
|
+
* @returns {function} the getter if one is defined. If possible this
|
|
189
|
+
* getter will be bound the associated and previously set `object`.
|
|
190
|
+
*/
|
|
191
|
+
get boundGet() {
|
|
192
|
+
return (isObject(this.#object) ? this.get?.bind(this.#object) : this.get)
|
|
193
|
+
}
|
|
194
|
+
|
|
163
195
|
/**
|
|
164
196
|
* Sets the `get` value of this object. If the internal descriptor
|
|
165
197
|
* store is invalid, the value is thrown away
|
|
@@ -179,7 +211,19 @@ class Descriptor {
|
|
|
179
211
|
* is undefined.
|
|
180
212
|
*/
|
|
181
213
|
get set() {
|
|
182
|
-
return this.#desc
|
|
214
|
+
return (this.#desc || {}).set
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Retrieves the {@link set} function for this accessor and binds it to
|
|
219
|
+
* the object from which the descriptor was derived, if that value is set.
|
|
220
|
+
* Otherwise this method is identical to the {@link set} accessor.
|
|
221
|
+
*
|
|
222
|
+
* @returns {function} the setter if one is defined. If possible this
|
|
223
|
+
* setter will be bound the associated and previously set `object`.
|
|
224
|
+
*/
|
|
225
|
+
get boundSet() {
|
|
226
|
+
return (isObject(this.#object) ? this.set?.bind(this.#object) : this.set)
|
|
183
227
|
}
|
|
184
228
|
|
|
185
229
|
/**
|
|
@@ -192,6 +236,52 @@ class Descriptor {
|
|
|
192
236
|
(this.#desc || {}).set = value
|
|
193
237
|
}
|
|
194
238
|
|
|
239
|
+
/**
|
|
240
|
+
* The function checks the descriptor's associated object has been set on this
|
|
241
|
+
* instance of `Descriptor`.
|
|
242
|
+
*
|
|
243
|
+
* @returns {boolean} `true` if the `object` property has been set,
|
|
244
|
+
* `false` otherwise
|
|
245
|
+
*/
|
|
246
|
+
get hasObject() { return isObject(this.#object) }
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Returns the descriptor's associated `object` value. This is usually the
|
|
250
|
+
* parent object from which the descriptor was derived. If the value is preset
|
|
251
|
+
* it will be returned. Undefined will be returned otherwise
|
|
252
|
+
*
|
|
253
|
+
* @returns {object} the associated object for this descriptor or undefined
|
|
254
|
+
* if it has not yet been set.
|
|
255
|
+
*/
|
|
256
|
+
get object() { return this.#object }
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Sets the descriptor's associated `object` value. This is usually the
|
|
260
|
+
* parent object from which the descriptor was derived.
|
|
261
|
+
*
|
|
262
|
+
* @param {object} value sets the object for which this descriptor is to
|
|
263
|
+
* be associated with.
|
|
264
|
+
*/
|
|
265
|
+
set object(value) { this.#object = Object(value) }
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* The function returns a string representation of a descriptor object with
|
|
269
|
+
* additional information about its type when used in the NodeJS repl.
|
|
270
|
+
*
|
|
271
|
+
* @param {number} depth - The `depth` parameter is used to specify the
|
|
272
|
+
* maximum depth to which nested objects and arrays will be formatted. If
|
|
273
|
+
* the depth is exceeded, the output will be truncated with ellipses.
|
|
274
|
+
* @param {object} options - The `options` parameter is an object that
|
|
275
|
+
* contains various configuration options for the `inspect` function.
|
|
276
|
+
* These options can be used to customize the output of the inspection.
|
|
277
|
+
* @param {function} inspect - The `inspect` parameter is a function that
|
|
278
|
+
* is used to convert an object into a string representation. It is
|
|
279
|
+
* typically used for debugging purposes or when displaying an object's
|
|
280
|
+
* properties.
|
|
281
|
+
* @returns a string that represents a descriptor. The string includes the
|
|
282
|
+
* type of the descriptor (either "Accessor" or "Data") and the result of
|
|
283
|
+
* inspecting the descriptor object using the provided options and depth.
|
|
284
|
+
*/
|
|
195
285
|
[Symbol.for('nodejs.util.inspect.custom')](depth, options, inspect) {
|
|
196
286
|
const type = this.isAccessor ? ' (Accessor)' : this.isData ? ' (Data)' : ''
|
|
197
287
|
return `Descriptor${type} ${inspect(this.#desc, {...options, depth})}`
|
|
@@ -205,12 +295,15 @@ class Descriptor {
|
|
|
205
295
|
* object to return a descriptor for.
|
|
206
296
|
* @returns an object descriptor for the requested field or null
|
|
207
297
|
*/
|
|
208
|
-
static for(object, key) {
|
|
209
|
-
if (!isObject(object)
|
|
298
|
+
static for(object, key, wrap = false) {
|
|
299
|
+
if (!isObject(object) || !isValidKey(key) || !Reflect.has(object, key)) {
|
|
210
300
|
return null
|
|
211
301
|
}
|
|
212
302
|
|
|
213
|
-
return
|
|
303
|
+
return (wrap
|
|
304
|
+
? new Descriptor(Object.getOwnPropertyDescriptor(object, key))
|
|
305
|
+
: Object.getOwnPropertyDescriptor(object, key)
|
|
306
|
+
)
|
|
214
307
|
}
|
|
215
308
|
|
|
216
309
|
/**
|
|
@@ -277,29 +370,25 @@ class Descriptor {
|
|
|
277
370
|
* The function `getData` retrieves the value of a property from an object
|
|
278
371
|
* if it exists and is a data property.
|
|
279
372
|
*
|
|
280
|
-
* @param object - The "object" parameter is the object from which
|
|
281
|
-
* retrieve data.
|
|
282
|
-
* @param property - The `property` parameter is the name of
|
|
283
|
-
* you want to retrieve the data from.
|
|
373
|
+
* @param {object} object - The "object" parameter is the object from which
|
|
374
|
+
* we want to retrieve data.
|
|
375
|
+
* @param {string|symbol} property - The `property` parameter is the name of
|
|
376
|
+
* the property that you want to retrieve the data from.
|
|
284
377
|
* @returns either the value of the specified property if it exists and is
|
|
285
378
|
* a data property, or undefined if the property does not exist or is not
|
|
286
379
|
* a data property.
|
|
287
380
|
*/
|
|
288
381
|
static getData(object, property) {
|
|
289
|
-
if (!isObject(object) || !
|
|
290
|
-
return
|
|
382
|
+
if (!isObject(object) || !Reflect.has(object, property)) {
|
|
383
|
+
return undefined;
|
|
291
384
|
}
|
|
292
385
|
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (Descriptor.isData(descriptor)) {
|
|
298
|
-
return descriptor.value
|
|
299
|
-
}
|
|
386
|
+
const descriptor = Descriptor.for(object, property, true)
|
|
387
|
+
if (!descriptor.isData) {
|
|
388
|
+
return null
|
|
300
389
|
}
|
|
301
390
|
|
|
302
|
-
return
|
|
391
|
+
return descriptor.value
|
|
303
392
|
}
|
|
304
393
|
|
|
305
394
|
/**
|
|
@@ -318,41 +407,16 @@ class Descriptor {
|
|
|
318
407
|
* returns undefined.
|
|
319
408
|
*/
|
|
320
409
|
static getAccessor(object, property) {
|
|
321
|
-
if (!isObject(object))
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (descriptors.has(property) || isDescriptor) {
|
|
330
|
-
const descriptor = isDescriptor ? object : descriptors.get(property)
|
|
331
|
-
|
|
332
|
-
if (Descriptor.isAccessor(descriptor)) {
|
|
333
|
-
results[OBJECT] = descriptors.object(property)
|
|
334
|
-
results[GETTER] = descriptor?.get
|
|
335
|
-
results[SETTER] = descriptor?.set
|
|
336
|
-
|
|
337
|
-
Object.assign(results, {
|
|
338
|
-
get() { this[GETTER].bind(this[OBJECT])() },
|
|
339
|
-
set(value) { this[SETTER].bind(this[OBJECT])(value) },
|
|
340
|
-
get accessor() { return true },
|
|
341
|
-
get descriptor() { return descriptor },
|
|
342
|
-
get boundDescriptor() {
|
|
343
|
-
return {
|
|
344
|
-
...descriptor,
|
|
345
|
-
get: descriptor.get?.bind(object),
|
|
346
|
-
set: descriptor.set?.bind(object),
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
return results
|
|
352
|
-
}
|
|
410
|
+
if (!isObject(object) || !Reflect.has(object, property)) {
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const descriptor = Descriptor.for(object, property, true)
|
|
415
|
+
if (!descriptor.isAccessor) {
|
|
416
|
+
return null
|
|
353
417
|
}
|
|
354
418
|
|
|
355
|
-
return
|
|
419
|
+
return descriptor.get.bind(object)()
|
|
356
420
|
}
|
|
357
421
|
|
|
358
422
|
/**
|
|
@@ -433,8 +497,11 @@ class Descriptor {
|
|
|
433
497
|
}
|
|
434
498
|
|
|
435
499
|
/**
|
|
436
|
-
* The function checks if an object is a
|
|
437
|
-
* JavaScript.
|
|
500
|
+
* The function checks if an object is a likely an object descriptor in
|
|
501
|
+
* JavaScript. This is determined as an object with some of the known
|
|
502
|
+
* descriptor keys (e.g. enumerable, configurable, value, writable, get,
|
|
503
|
+
* or set). Technically, any object could serve as a descriptor but this
|
|
504
|
+
* function only returns true if known descriptor keys are found.
|
|
438
505
|
*
|
|
439
506
|
* @param object - The `object` parameter is the object that we want to
|
|
440
507
|
* check if it is a descriptor.
|
|
@@ -453,6 +520,8 @@ class Descriptor {
|
|
|
453
520
|
/**
|
|
454
521
|
* The function checks if a given property or descriptor is a data property.
|
|
455
522
|
*
|
|
523
|
+
* brie
|
|
524
|
+
*
|
|
456
525
|
* @param descriptor_orProp - The `descriptor_orProp` parameter can be
|
|
457
526
|
* either a descriptor or a property name.
|
|
458
527
|
* @param object - The `object` parameter is the object that you want to
|
|
@@ -472,13 +541,10 @@ class Descriptor {
|
|
|
472
541
|
: object_orProp
|
|
473
542
|
)
|
|
474
543
|
|
|
475
|
-
const {
|
|
544
|
+
const { DATA_KEYS } = this
|
|
476
545
|
let validData = false
|
|
477
546
|
|
|
478
|
-
if (hasSome(descriptor,
|
|
479
|
-
validData = false
|
|
480
|
-
}
|
|
481
|
-
else if (hasSome(descriptor, DATA_KEYS)) {
|
|
547
|
+
if (hasSome(descriptor, DATA_KEYS)) {
|
|
482
548
|
validData = true
|
|
483
549
|
}
|
|
484
550
|
|
|
@@ -507,13 +573,10 @@ class Descriptor {
|
|
|
507
573
|
? Descriptor.for(object_orProp, property)
|
|
508
574
|
: object_orProp)
|
|
509
575
|
|
|
510
|
-
const { ACCESSOR_KEYS
|
|
576
|
+
const { ACCESSOR_KEYS } = this
|
|
511
577
|
let validAccessor = false
|
|
512
578
|
|
|
513
|
-
if (hasSome(descriptor,
|
|
514
|
-
validAccessor = false
|
|
515
|
-
}
|
|
516
|
-
else if (hasSome(descriptor, ACCESSOR_KEYS)) {
|
|
579
|
+
if (hasSome(descriptor, ACCESSOR_KEYS)) {
|
|
517
580
|
validAccessor = true
|
|
518
581
|
}
|
|
519
582
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Extension } from '@nejs/extension'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The Iterable class is designed to provide a convenient way to create synchronous
|
|
5
|
+
* iterable objects. It can be initialized with either an array or individual elements.
|
|
6
|
+
* This class implements the iterable protocol, allowing instances to be used with
|
|
7
|
+
* `for...of` loops and other standard JavaScript iteration mechanisms.
|
|
8
|
+
*/
|
|
9
|
+
export class Iterable {
|
|
10
|
+
/**
|
|
11
|
+
* Private field to store the elements of the iterable.
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
#elements = [];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructs an instance of Iterable. It can be initialized with either an
|
|
18
|
+
* iterable object (such as an array, Set, Map, string, or any object
|
|
19
|
+
* implementing the iterable protocol) or individual elements. If the first
|
|
20
|
+
* argument is an iterable, the class instance is initialized with the
|
|
21
|
+
* elements from the iterable, followed by any additional arguments. If the
|
|
22
|
+
* first argument is not an iterable, all arguments are treated as individual
|
|
23
|
+
* elements.
|
|
24
|
+
*
|
|
25
|
+
* @param {Iterable|*} elementsOrFirstElement - An iterable object or the
|
|
26
|
+
* first element.
|
|
27
|
+
* @param {...*} moreElements - Additional elements if the first argument is
|
|
28
|
+
* not an iterable.
|
|
29
|
+
*/
|
|
30
|
+
constructor(elementsOrFirstElement, ...moreElements) {
|
|
31
|
+
if (
|
|
32
|
+
elementsOrFirstElement != null &&
|
|
33
|
+
typeof elementsOrFirstElement[Symbol.iterator] === 'function'
|
|
34
|
+
) {
|
|
35
|
+
this.#elements = [...elementsOrFirstElement, ...moreElements];
|
|
36
|
+
} else {
|
|
37
|
+
this.#elements = [elementsOrFirstElement, ...moreElements];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Implements the iterable protocol. When an instance of Iterable is used
|
|
43
|
+
* in a `for...of` loop or spread syntax, this generator function is invoked
|
|
44
|
+
* to yield the elements one by one in a synchronous manner.
|
|
45
|
+
*
|
|
46
|
+
* @returns {Generator} A generator that yields each element of the iterable.
|
|
47
|
+
*/
|
|
48
|
+
*[Symbol.iterator]() {
|
|
49
|
+
for (const element of this.#elements) {
|
|
50
|
+
yield element;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Provides access to the elements as a standard array. Useful for scenarios
|
|
56
|
+
* where array methods and behaviors are needed.
|
|
57
|
+
*
|
|
58
|
+
* @returns {Array} An array containing all the elements of the iterable.
|
|
59
|
+
*/
|
|
60
|
+
get asArray() {
|
|
61
|
+
return this.#elements;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Ensures that the constructor of this object instance's name
|
|
66
|
+
* is returned if the string tag for this instance is queried
|
|
67
|
+
*
|
|
68
|
+
* @returns {string} the name of the class
|
|
69
|
+
*/
|
|
70
|
+
get [Symbol.toStringTag]() {
|
|
71
|
+
return this.constructor.name
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Checks if a given value is an iterable. This method determines if the
|
|
76
|
+
* provided value has a `Symbol.iterator` property that is a generator
|
|
77
|
+
* function. It's a precise way to identify if the value conforms to the
|
|
78
|
+
* iterable protocol using a generator function.
|
|
79
|
+
*
|
|
80
|
+
* Note: This method specifically checks for generator functions. Some
|
|
81
|
+
* iterables might use regular functions that return an iterator, which
|
|
82
|
+
* this method won't identify.
|
|
83
|
+
*
|
|
84
|
+
* @param {*} value - The value to be checked for iterability.
|
|
85
|
+
* @returns {boolean} - Returns true if the value is an iterable implemented
|
|
86
|
+
* using a generator function, false otherwise.
|
|
87
|
+
*/
|
|
88
|
+
static isIterable(value) {
|
|
89
|
+
const type = Object.prototype.toString.call(value?.[Symbol.iterator]);
|
|
90
|
+
return type === '[object GeneratorFunction]';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Being able to create a compliant `Iterator` around any type of iterable
|
|
96
|
+
* object. This can be wrapped around any type of object that has a
|
|
97
|
+
* `[Symbol.iterator]` property assigned to a generator function.
|
|
98
|
+
*/
|
|
99
|
+
export class Iterator {
|
|
100
|
+
/**
|
|
101
|
+
* A private function that when provided has the following signature:
|
|
102
|
+
* `function mapEach(entry) -> entry`. This allows any changes to be made
|
|
103
|
+
* to each element, conditionally and programmatically, as needed before
|
|
104
|
+
* they are returned to the called code.
|
|
105
|
+
*/
|
|
106
|
+
#mapEach = undefined
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates a new `Iterator` object instance.
|
|
110
|
+
*
|
|
111
|
+
* @param {object} iterable any object that has a `[Symbol.iterator]`
|
|
112
|
+
* property assigned to a generator function.
|
|
113
|
+
* @param {function} mapEach when provided `mapEach` is a callback that
|
|
114
|
+
* takes an entry as input and receives one as output.
|
|
115
|
+
*/
|
|
116
|
+
constructor(iterable, mapEach) {
|
|
117
|
+
if (!iterable || !Reflect.has(iterable, Symbol.iterator)) {
|
|
118
|
+
throw new TypeError(
|
|
119
|
+
'Value used to instantiate Iterator is not iterable'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.#iterable = iterable;
|
|
124
|
+
this.#iterator = iterable[Symbol.iterator]();
|
|
125
|
+
this.#mapEach = typeof mapEach === 'function' ? mapEach : undefined
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns a new `Array` derived from the iterable this object
|
|
130
|
+
* wraps.
|
|
131
|
+
*
|
|
132
|
+
* @returns {array} a new `Array` generated from the wrapped
|
|
133
|
+
* iterable. The method is generated from `Array.from()`
|
|
134
|
+
*/
|
|
135
|
+
get asArray() {
|
|
136
|
+
return Array.from(this.#iterable)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the actual iterable object passed to the constructor that
|
|
141
|
+
* created this instance.
|
|
142
|
+
*
|
|
143
|
+
* @returns {object} the object containing the `[Symbol.iterator]`
|
|
144
|
+
*/
|
|
145
|
+
get iterable() {
|
|
146
|
+
return this.#iterable
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The function retrieves the next value in the iterator. If the
|
|
151
|
+
* the iterator has run its course, `reset()` can be invoked to
|
|
152
|
+
* reset the pointer to the beginning of the iteration.
|
|
153
|
+
*
|
|
154
|
+
* @returns {any} the next value
|
|
155
|
+
*/
|
|
156
|
+
next() {
|
|
157
|
+
const input = this.#iterator.next();
|
|
158
|
+
let output = input
|
|
159
|
+
|
|
160
|
+
if (output.done) {
|
|
161
|
+
return { value: undefined, done: true };
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
if (this.#mapEach && typeof this.#mapEach === 'function') {
|
|
165
|
+
output.value = this.#mapEach(input.value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { value: output.value, done: false };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Resets the iterator to the beginning allowing it to be
|
|
174
|
+
* iterated over again.
|
|
175
|
+
*/
|
|
176
|
+
reset() {
|
|
177
|
+
this.#iterator = this.#iterable[Symbol.iterator]();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The existence of this symbol on the object instances, indicates that
|
|
182
|
+
* it can be used in `for(.. of ..)` loops and its values can be
|
|
183
|
+
* extracted from calls to `Array.from()`
|
|
184
|
+
*
|
|
185
|
+
* @returns {Iterator} this is returned since this object is already
|
|
186
|
+
* conforming to the expected JavaScript Iterator interface
|
|
187
|
+
*/
|
|
188
|
+
[Symbol.iterator]() {
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Ensures that the constructor of this object instance's name
|
|
194
|
+
* is returned if the string tag for this instance is queried
|
|
195
|
+
*
|
|
196
|
+
* @returns {string} the name of the class
|
|
197
|
+
*/
|
|
198
|
+
get [Symbol.toStringTag]() {
|
|
199
|
+
return this.constructor.name
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The object from which its iterator functionality is derived.
|
|
204
|
+
*
|
|
205
|
+
* @type {object}
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
#iterable = null;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The results of a call to the iterable's `[Symbol.iterator]`
|
|
212
|
+
* generator function.
|
|
213
|
+
*
|
|
214
|
+
* @type {object}
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
#iterator = null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export const IterableExtensions = new Extension(Iterable)
|
|
221
|
+
export const IteratorExtensions = new Extension(Iterator)
|