@nejs/basic-extensions 2.20.0 → 2.21.5

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 (92) hide show
  1. package/.idea/markdown.xml +8 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/ne-basic-extensions.iml +8 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/CODE_STYLE.md +393 -0
  6. package/CODING_PHILOSOPHY.md +36 -0
  7. package/DOCUMENTATION_GUIDELINES.md +221 -0
  8. package/bin/repl.basics.js +36 -6
  9. package/bin/repl.signature.js +63 -0
  10. package/dist/@nejs/basic-extensions.bundle.2.21.5.js +25 -0
  11. package/dist/@nejs/basic-extensions.bundle.2.21.5.js.map +7 -0
  12. package/dist/cjs/big.int.extension.js +153 -45
  13. package/dist/cjs/big.int.extension.js.map +1 -1
  14. package/dist/cjs/classes/descriptor.d.ts +1 -1
  15. package/dist/cjs/classes/enum.d.ts +37 -19
  16. package/dist/cjs/classes/enum.js +181 -56
  17. package/dist/cjs/classes/enum.js.map +1 -1
  18. package/dist/cjs/classes/iterable.d.ts +3 -3
  19. package/dist/cjs/classes/param.parser.d.ts +1 -7
  20. package/dist/cjs/classes/pluggable.proxy.d.ts +2 -1
  21. package/dist/cjs/classes/property.d.ts +2 -9
  22. package/dist/cjs/classes/refset.d.ts +2 -2
  23. package/dist/cjs/classes/symkeys.d.ts +1 -1
  24. package/dist/cjs/global.this.js +17 -7
  25. package/dist/cjs/global.this.js.map +1 -1
  26. package/dist/cjs/index.d.ts +9 -6
  27. package/dist/cjs/index.js +15 -8
  28. package/dist/cjs/index.js.map +1 -1
  29. package/dist/cjs/math.extension.d.ts +14 -0
  30. package/dist/cjs/math.extension.js +71 -0
  31. package/dist/cjs/math.extension.js.map +1 -0
  32. package/dist/cjs/number.extension.js +17 -0
  33. package/dist/cjs/number.extension.js.map +1 -1
  34. package/dist/cjs/string.extensions.js +38 -0
  35. package/dist/cjs/string.extensions.js.map +1 -1
  36. package/dist/cjs/utils/copy.object.d.ts +2 -2
  37. package/dist/cjs/utils/descriptor.utils.d.ts +152 -0
  38. package/dist/cjs/utils/descriptor.utils.js +228 -9
  39. package/dist/cjs/utils/descriptor.utils.js.map +1 -1
  40. package/dist/cjs/utils/index.d.ts +15 -0
  41. package/dist/cjs/utils/index.js +9 -0
  42. package/dist/cjs/utils/index.js.map +1 -1
  43. package/dist/cjs/utils/stdout.d.ts +742 -0
  44. package/dist/cjs/utils/stdout.js +1042 -0
  45. package/dist/cjs/utils/stdout.js.map +1 -0
  46. package/dist/mjs/big.int.extension.js +153 -45
  47. package/dist/mjs/big.int.extension.js.map +1 -1
  48. package/dist/mjs/classes/descriptor.d.ts +1 -1
  49. package/dist/mjs/classes/enum.d.ts +37 -19
  50. package/dist/mjs/classes/enum.js +181 -57
  51. package/dist/mjs/classes/enum.js.map +1 -1
  52. package/dist/mjs/classes/iterable.d.ts +3 -3
  53. package/dist/mjs/classes/param.parser.d.ts +1 -7
  54. package/dist/mjs/classes/pluggable.proxy.d.ts +2 -1
  55. package/dist/mjs/classes/property.d.ts +2 -9
  56. package/dist/mjs/classes/refset.d.ts +2 -2
  57. package/dist/mjs/classes/symkeys.d.ts +1 -1
  58. package/dist/mjs/index.d.ts +9 -6
  59. package/dist/mjs/index.js +15 -8
  60. package/dist/mjs/index.js.map +1 -1
  61. package/dist/mjs/math.extension.d.ts +14 -0
  62. package/dist/mjs/math.extension.js +68 -0
  63. package/dist/mjs/math.extension.js.map +1 -0
  64. package/dist/mjs/number.extension.js +17 -0
  65. package/dist/mjs/number.extension.js.map +1 -1
  66. package/dist/mjs/string.extensions.js +38 -0
  67. package/dist/mjs/string.extensions.js.map +1 -1
  68. package/dist/mjs/utils/copy.object.d.ts +2 -2
  69. package/dist/mjs/utils/descriptor.utils.d.ts +152 -0
  70. package/dist/mjs/utils/descriptor.utils.js +222 -9
  71. package/dist/mjs/utils/descriptor.utils.js.map +1 -1
  72. package/dist/mjs/utils/index.d.ts +15 -0
  73. package/dist/mjs/utils/index.js +10 -1
  74. package/dist/mjs/utils/index.js.map +1 -1
  75. package/dist/mjs/utils/stdout.d.ts +742 -0
  76. package/dist/mjs/utils/stdout.js +1037 -0
  77. package/dist/mjs/utils/stdout.js.map +1 -0
  78. package/package.json +6 -20
  79. package/repl.bootstrap.js +24 -16
  80. package/repl.history +30 -30
  81. package/src/big.int.extension.js +171 -45
  82. package/src/classes/enum.js +249 -109
  83. package/src/index.js +24 -8
  84. package/src/math.extension.js +73 -0
  85. package/src/number.extension.js +18 -0
  86. package/src/string.extensions.js +41 -0
  87. package/src/utils/descriptor.utils.js +277 -9
  88. package/src/utils/index.js +20 -0
  89. package/src/utils/stdout.js +1151 -0
  90. package/tests/utils/descriptor.utils.test.js +130 -0
  91. package/dist/@nejs/basic-extensions.bundle.2.20.0.js +0 -19
  92. package/dist/@nejs/basic-extensions.bundle.2.20.0.js.map +0 -7
@@ -1,5 +1,5 @@
1
1
  import { Extension } from '@nejs/extension'
2
- import { accessor, as, data, isDescriptor } from '../utils/index.js'
2
+ import { accessor, as, data, isDescriptor, redescribe } from '../utils/index.js'
3
3
 
4
4
  /**
5
5
  * Creates an enumeration object with specified values and properties.
@@ -12,54 +12,32 @@ import { accessor, as, data, isDescriptor } from '../utils/index.js'
12
12
  * @returns {Object} The constructed enumeration object.
13
13
  *
14
14
  * @example
15
- * const colors = Enum('Colors', ['red', 'green', 'blue'])
16
- * console.log(colors.red) // EnumValue object for 'red'
17
- *
18
- * @description
19
- * The `Enum` function constructs an enumeration object with a given name,
20
- * values, and optional properties. It supports primitive types, arrays,
21
- * and objects as values. The function uses a combination of `Object.create`
22
- * and `Proxy` to define and manage the properties of the enumeration.
23
- *
24
- * The enumeration object includes:
25
- * - A `toString` method that returns the enumeration name.
26
- * - A `Symbol.toStringTag` for identifying the object as an 'Enum'.
27
- * - A `Symbol.for('Enum.name')` for storing the enumeration name.
28
- *
29
- * For array values, it creates a maker function that returns an
30
- * `EnumValue` object with properties like `real`, `value`, `type`,
31
- * `name`, and `compare`.
32
- */
15
+ * const colors = Enum('Colors', ['red', 'green', 'blue'])
16
+ * console.log(colors.red) // EnumValue object for 'red'
17
+ *
18
+ * @description
19
+ * The `Enum` function constructs an enumeration object with a given name,
20
+ * values, and optional properties. It supports primitive types, arrays,
21
+ * and objects as values. The function uses a combination of `Object.create`
22
+ * and `Proxy` to define and manage the properties of the enumeration.
23
+ *
24
+ * The enumeration object includes:
25
+ * - A `toString` method that returns the enumeration name.
26
+ * - A `Symbol.toStringTag` for identifying the object as an 'Enum'.
27
+ * - A `Symbol.for('Enum.name')` for storing the enumeration name.
28
+ *
29
+ * For array values, it creates a maker function that returns an
30
+ * `EnumValue` object with properties like `real`, `value`, `type`,
31
+ * `name`, and `compare`.
32
+ */
33
33
  export function Enum(name, values, properties) {
34
- const enumeration = Object.create({}, {
35
- [Symbol.toStringTag]: accessor('Enum', false, true, false),
36
- [Symbol.for('Enum.name')]: accessor(name, false, true, false),
37
- [Symbol.for('Enum.valueKeys')]: data([], false, true, false),
38
- [Symbol.for('nodejs.util.inspect.custom')]: data(
39
- function(depth, options, inspect) {
40
- const valueKeys = this[Symbol.for('Enum.valueKeys')] ?? []
41
- let valueText = valueKeys
42
- .map(key => `\x1b[1;2m${key}\x1b[22m`)
43
- .join(', ')
44
-
45
- if (valueText.length)
46
- valueText = ` { ${valueText} }`
47
-
48
- return `\x1b[1menum \x1b[22m${name}${valueText}`
49
- }, false, true, false
50
- ),
51
- toString: data(function() {
52
- return `Enum(${name})`
53
- }, false, true, false)
54
- })
55
-
56
- if (!Array.isArray(values)) {
57
- values = [values]
58
- }
59
-
60
- const asString = o => as.string(o, { description: true, stringTag: true })
61
-
62
- /**
34
+ const enumeration = makeBaseEnum(name)
35
+
36
+ if (!Array.isArray(values)) {
37
+ values = [values]
38
+ }
39
+
40
+ /**
63
41
  * A new base `EnumValue` type object. It contains enough custom symbols and
64
42
  * identifiers to allow things like a `compare(to)` function to also work on
65
43
  * each of the elements. Thing of this as the shared base functionality for
@@ -71,25 +49,25 @@ export function Enum(name, values, properties) {
71
49
  * custom {@link Symbol} keys. The `node.js` custom inspect symbol is also
72
50
  * defined for better REPL representation.
73
51
  */
74
- const makeEnumValue = (property, enumValue) => ({
75
- toString: data(() => enumValue, false, true, false),
76
-
77
- [Symbol.for('Enum.name')]: data(name, false, true, false),
78
- [Symbol.for('Enum.is')]: data(true, false, false, false),
79
- [Symbol.for('nodejs.util.inspect.custom')]: data(
80
- function(depth, options, inspect) {
81
- const _options = { ...(options || {}), colors: true }
82
- const _skip = this.value === Symbol.for('Enum.NonAssociatedValue')
83
- const _value = _skip
84
- ? ''
85
- : ` { value: ${inspect(this.value, _options) } }`;
86
-
87
- return `${property}${_value}`
88
- },
89
- false, true, false
90
- ),
91
- [Symbol.toStringTag]: accessor('EnumValue', false, true, false),
92
- [Symbol.for('compare')]: data(
52
+ const makeEnumValue = (property, enumValue) => ({
53
+ toString: data(() => enumValue, false, true, false),
54
+
55
+ [Symbol.for('Enum.name')]: data(name, false, true, false),
56
+ [Symbol.for('Enum.is')]: data(true, false, false, false),
57
+ [Symbol.for('nodejs.util.inspect.custom')]: data(
58
+ function(depth, options, inspect) {
59
+ const _options = { ...(options || {}), colors: true }
60
+ const _skip = this.value === Symbol.for('Enum.NonAssociatedValue')
61
+ const _value = _skip
62
+ ? ''
63
+ : ` { value: ${inspect(this.value, _options) } }`;
64
+
65
+ return `${property}${_value}`
66
+ },
67
+ false, true, false
68
+ ),
69
+ [Symbol.toStringTag]: accessor('EnumValue', false, true, false),
70
+ [Symbol.for('compare')]: data(
93
71
  function compareValue(to) {
94
72
  const toObj = (to && typeof to === 'object') ? to : { real: to }
95
73
  const kName = Symbol.for('Enum.name')
@@ -110,8 +88,8 @@ export function Enum(name, values, properties) {
110
88
  lName === rName && lType === rType &&
111
89
  lReal === rReal && lValue === rValue
112
90
  )
113
- }, false, true, false),
114
- [Symbol.toPrimitive]: data(
91
+ }, false, true, false),
92
+ [Symbol.toPrimitive]: data(
115
93
  function EnumValueToPrimitive(hint) {
116
94
  const original = this.real
117
95
  const type = typeof original
@@ -140,9 +118,9 @@ export function Enum(name, values, properties) {
140
118
  }
141
119
  },
142
120
  false, true, false),
143
- })
121
+ })
144
122
 
145
- /**
123
+ /**
146
124
  * Given a value, determine how to represent it as both a key and a response
147
125
  * or underlying original value. The method for this is dependent on the type
148
126
  * of the value itself.
@@ -151,7 +129,7 @@ export function Enum(name, values, properties) {
151
129
  * @returns {[string, any]} an array where the first value is the transformed
152
130
  * value as a key and the second element is the originally supplied value.
153
131
  */
154
- const fromPrimitive = (value) => {
132
+ const fromPrimitive = (value) => {
155
133
  let valueType = typeof value
156
134
 
157
135
  switch (valueType) {
@@ -173,17 +151,17 @@ export function Enum(name, values, properties) {
173
151
  return [str, str]
174
152
  }
175
153
  }
176
- }
154
+ }
177
155
 
178
- // Determine the keys that the final proxy should be aware of when computing
179
- // the enumeration value itself.
180
- const kValueProps = ['real', 'value', 'type', 'name', 'compare', 'isEnum']
181
- const kCustomPropKeys = []
156
+ // Determine the keys that the final proxy should be aware of when computing
157
+ // the enumeration value itself.
158
+ const kValueProps = ['real', 'value', 'type', 'name', 'compare', 'isEnum']
159
+ const kCustomPropKeys = []
182
160
 
183
- // Capture and calculate any custom properties defined for each element
184
- // of the enumeration. Each custom property is appended to `kCustomPropKeys`
185
- const props = {}
186
- if (properties) {
161
+ // Capture and calculate any custom properties defined for each element
162
+ // of the enumeration. Each custom property is appended to `kCustomPropKeys`
163
+ const props = {}
164
+ if (properties) {
187
165
  if (Array.isArray(properties)) {
188
166
  const entries = properties.filter(e => Array.isArray(e) && e.length === 2)
189
167
 
@@ -234,14 +212,13 @@ export function Enum(name, values, properties) {
234
212
  props[property] = value
235
213
  }
236
214
  }
237
- }
215
+ }
238
216
 
239
- for (const value of values) {
217
+ for (const value of values) {
240
218
  const valueType = Array.isArray(value) ? 'array' : typeof value
241
219
 
242
220
  let property = undefined
243
221
  let response = undefined
244
- let makeNew = undefined
245
222
  let wasArray = false
246
223
  let elements = value
247
224
 
@@ -258,31 +235,31 @@ export function Enum(name, values, properties) {
258
235
 
259
236
  const maker = {
260
237
  [property](initialValue) {
261
- const storage = new Map()
262
- const key = property
263
- const realValue = accessor(response, false, { storage, key })
264
-
265
- let _opts, associatedValue;
266
-
267
- if (wasArray) {
268
- _opts = { storage, key: key + '.associated' }
269
- associatedValue = elements.length === 1
270
- ? accessor(initialValue, true, _opts)
271
- : accessor(elements?.[1], elements?.[2], _opts);
272
- }
273
- else
238
+ const storage = new Map()
239
+ const key = property
240
+ const realValue = accessor(response, false, { storage, key })
241
+
242
+ let _opts, associatedValue;
243
+
244
+ if (wasArray) {
245
+ _opts = { storage, key: key + '.associated' }
246
+ associatedValue = elements.length === 1
247
+ ? accessor(initialValue, true, _opts)
248
+ : accessor(elements?.[1], elements?.[2], _opts);
249
+ }
250
+ else
274
251
  associatedValue = accessor(
275
252
  Symbol.for('Enum.NonAssociatedValue'),
276
253
  false, false, false)
277
254
 
278
- const _prop = Object(asString(response))
279
- const valueProps = [...kValueProps, ...kCustomPropKeys]
280
- const enumResponse = Object.create(_prop, {
255
+ const _prop = Object(asString(response))
256
+ const valueProps = [...kValueProps, ...kCustomPropKeys]
257
+ const enumResponse = Object.create(_prop, {
281
258
  ...makeEnumValue(property, response),
282
259
  ...props,
283
- })
260
+ })
284
261
 
285
- const proxy = new Proxy(_prop, {
262
+ const proxy = new Proxy(_prop, {
286
263
  get(target, _property, receiver) {
287
264
  if (_property === 'real')
288
265
  return realValue.get()
@@ -317,12 +294,12 @@ export function Enum(name, values, properties) {
317
294
 
318
295
  return false
319
296
  }
320
- })
297
+ })
321
298
 
322
- Object.setPrototypeOf(proxy, Object.getPrototypeOf(_prop))
323
- Object.setPrototypeOf(enumResponse, proxy)
299
+ Object.setPrototypeOf(proxy, Object.getPrototypeOf(_prop))
300
+ Object.setPrototypeOf(enumResponse, proxy)
324
301
 
325
- return enumResponse
302
+ return enumResponse
326
303
  }
327
304
  }
328
305
 
@@ -336,9 +313,172 @@ export function Enum(name, values, properties) {
336
313
  }
337
314
 
338
315
  Object.defineProperty(enumeration, property, data(dataValue, baseProps))
339
- }
316
+ }
317
+
318
+ return enumeration
319
+ }
320
+
321
+ export const EnumExtension = new Extension(Enum)
322
+
323
+
324
+
325
+ /**
326
+ * Converts a given value to a string representation with additional
327
+ * options for description and string tag.
328
+ *
329
+ * @param {any} value - The value to be converted to a string. This can
330
+ * be of any type, including objects, arrays, numbers, etc.
331
+ * @returns {string} A string representation of the input value, enhanced
332
+ * with a description and string tag if applicable.
333
+ *
334
+ * @example
335
+ * // Convert a number to a string with additional options
336
+ * const result = asString(123)
337
+ * console.log(result) // Outputs: "123" with description and string tag
338
+ *
339
+ * @example
340
+ * // Convert an object to a string with additional options
341
+ * const obj = { key: 'value' }
342
+ * const result = asString(obj)
343
+ * console.log(result) // Outputs: "[object Object]" with description and
344
+ * // string tag
345
+ */
346
+ function asString(value) {
347
+ return as.string(value, { description: true, stringTag: true })
348
+ }
340
349
 
341
- return enumeration
350
+ /**
351
+ * Creates a base enumeration object with predefined properties and
352
+ * symbols. This function is used to initialize an enumeration with
353
+ * specific characteristics, such as a name and various symbolic
354
+ * properties that enhance its functionality and identification.
355
+ *
356
+ * @param {string} name - The name of the enumeration. This name is
357
+ * used to identify the enumeration and is stored as a symbol on
358
+ * the object.
359
+ * @returns {Object} A new enumeration object with specific properties
360
+ * and symbols set for enhanced functionality and identification.
361
+ *
362
+ * @example
363
+ * // Create a base enum with the name 'Color'
364
+ * const colorEnum = makeBaseEnum('Color')
365
+ * console.log(colorEnum[Symbol.for('Enum.name')]) // Outputs: 'Color'
366
+ */
367
+ export function makeBaseEnum(name) {
368
+ return Object.create({}, {
369
+ /**
370
+ * Defines the `toStringTag` symbol on each enumeration to allow for
371
+ * type identification and to be consistent in naming conventions.
372
+ *
373
+ * @type {string}
374
+ */
375
+ [Symbol.toStringTag]: accessor('Enum', false, true, false),
376
+
377
+ /**
378
+ * In addition to the `toStringTag` symbol which defines this enumeration
379
+ * as an Enum type, the name of the enum is also codified in as a symbol
380
+ * on the object. It can be found using `Symbol.for('Enum.name')`.
381
+ *
382
+ * @type {string|symbol|number}
383
+ */
384
+ [Symbol.for('Enum.name')]: accessor(name, false, true, false),
385
+
386
+ /**
387
+ * Knowing which keys of the enum are part of the keys themselves is also
388
+ * crucial for enumerations. These can always be found on each Enum type
389
+ * as `Symbol.for('Enum.valueKeys')` as an array, but can also be found
390
+ * as the `.keys` property if there is no enum value of that name.
391
+ */
392
+ [Symbol.for('Enum.valueKeys')]: data([], false, true, false),
393
+
394
+ /**
395
+ * For users of the node.js REPL, this symbol represents enum types in a
396
+ * more readily readable format. See the docs for node's `util.inspect()`
397
+ * function for more details.
398
+ *
399
+ * @type {(number, object, Function) => string}
400
+ */
401
+ [Symbol.for('nodejs.util.inspect.custom')]: data(
402
+ function(depth, options, inspect) {
403
+ const valueKeys = this[Symbol.for('Enum.valueKeys')] ?? []
404
+ let valueText = valueKeys
405
+ .map(key => `\x1b[1;2m${key}\x1b[22m`)
406
+ .join(', ')
407
+
408
+ if (valueText.length)
409
+ valueText = ` { ${valueText} }`
410
+
411
+ return `\x1b[1menum \x1b[22m${name}${valueText}`
412
+ }, false, true, false
413
+ ),
414
+
415
+ /**
416
+ * This function checks the supplied `possibleEnumValue` to see if it
417
+ * is an enum value type from this enum.
418
+ *
419
+ * @param {any} possibleEnumValue the value to evaluate
420
+ * @returns {boolean} returns `true` if the value is an enum value type
421
+ * from this `Enum`, irrespective of any associated value. Returns `false`
422
+ * otherwise.
423
+ */
424
+ isValueOf: data(function isValueOf(possibleEnumValue) {
425
+ if (!possibleEnumValue || typeof possibleEnumValue !== 'object')
426
+ return false
427
+
428
+ const enumValueType = possibleEnumValue?.type
429
+ const enumValueName = possibleEnumValue?.name
430
+
431
+ const thisEnumName = this[Symbol.for('Enum.name')]
432
+ const thisEnumKeys = this[Symbol.for('Enum.valueKeys')]
433
+
434
+ return (
435
+ enumValueType === thisEnumName &&
436
+ thisEnumKeys.includes(enumValueName)
437
+ )
438
+ }, false, true, false),
439
+
440
+ /**
441
+ * A simple overload of the `toString()` method to represent the enum
442
+ * more identifiably when called. The result will be the word enum with
443
+ * the name of the enum in parenthesis. So a Gender enum might be seen
444
+ * as `Enum(Gender)` as a result to calling this function.
445
+ *
446
+ * @returns {string} a {@link String} representation of this object.
447
+ */
448
+ toString: data(function toString() {
449
+ return `Enum(${name})`
450
+ }, false, true, false)
451
+ })
452
+
453
+ const applySyntacticSugar = () => {
454
+ createSymlinks(Symbol.for('Enum.valueKeys'), 'keys')
455
+ createSymlinks(Symbol.for('Enum.name'), 'name')
456
+ }
457
+
458
+ return [base, applySyntacticSugar]
342
459
  }
343
460
 
344
- export const EnumExtension = new Extension(Enum)
461
+ /**
462
+ * Creates a symlink for a property from an existing key to a new key on
463
+ * the specified object. This function checks if the new key already
464
+ * exists on the object and, if not, it creates a new property with the
465
+ * same descriptor as the old key.
466
+ *
467
+ * Since this method creates the new link through the use of property
468
+ * descriptors, computed getters and setters also are mapped properly.
469
+ *
470
+ * @param {Object} on - The target object on which the symlink is to be
471
+ * created.
472
+ * @param {string|symbol} oldKey - The existing key whose property
473
+ * descriptor will be used for the new key.
474
+ * @param {string|symbol} newKey - The new key under which the property
475
+ * will be accessible.
476
+ *
477
+ * @example
478
+ * const obj = { a: 1 }
479
+ * createSymlink(obj, 'a', 'b')
480
+ * console.log(obj.b) // Outputs: 1
481
+ */
482
+ function createSymlinks(on, oldKey, ...newKeys) {
483
+ redescribe(on, oldKey, {}, { alsoAs: newKeys })
484
+ }
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ import { FunctionExtensions, FunctionPrototypeExtensions } from './function.exte
4
4
  import { GlobalFunctionsAndProps } from './global.this.js'
5
5
  import { JSONExtensions } from './json.extensions.js'
6
6
  import { MapExtensions, MapPrototypeExtensions } from './map.extensions.js'
7
+ import { MathExtensions } from './math.extension.js'
7
8
  import { NumberExtensions, NumberPrototypeExtensions } from './number.extension.js'
8
9
  import { ObjectExtensions, ObjectPrototypeExtensions } from './object.extensions.js'
9
10
  import { ReflectExtensions } from './reflect.extensions.js'
@@ -29,6 +30,15 @@ import { RefSetExtensions } from './classes/refset.js'
29
30
  import { SymkeysExtension } from './classes/symkeys.js'
30
31
  import { TypeExtensions } from './classes/type.js'
31
32
 
33
+ export * from './utils/stdout.js'
34
+ import {
35
+ StringConsole,
36
+ StdoutGlobalPatches,
37
+ StringConsoleExtension,
38
+
39
+ captureStdout,
40
+ } from './utils/stdout.js'
41
+
32
42
  export * from './utils/copy.object.js'
33
43
  export * from './utils/toolkit.js'
34
44
  export * from './utils/descriptor.utils.js'
@@ -44,6 +54,7 @@ const StaticPatches = [
44
54
  [Function, FunctionExtensions, Function.name],
45
55
  [JSON, JSONExtensions, 'JSON'], // Missing a .name property
46
56
  [Map, MapExtensions, Map.name],
57
+ [Math, MathExtensions, 'Math'],
47
58
  [Number, NumberExtensions, Number.name],
48
59
  [Object, ObjectExtensions, Object.name],
49
60
  [Reflect, ReflectExtensions, 'Reflect'], // Missing a .name property
@@ -68,6 +79,9 @@ const InstancePatches = [
68
79
  const Patches = new Map([
69
80
  ...StaticPatches,
70
81
  ...InstancePatches,
82
+
83
+ [globalThis, GlobalFunctionsAndProps, 'globalThis'], // Missing .name property
84
+ [globalThis, StdoutGlobalPatches, 'globalThis'], // Missing .name property
71
85
  ])
72
86
 
73
87
  const Extensions = {
@@ -85,6 +99,7 @@ const Extensions = {
85
99
  [PropertyExtensions.key]: PropertyExtensions,
86
100
  [RefMapExtensions.key]: RefMapExtensions,
87
101
  [RefSetExtensions.key]: RefSetExtensions,
102
+ [StringConsoleExtension.key]: StringConsoleExtension,
88
103
  [SymkeysExtension.key]: SymkeysExtension,
89
104
  [TypeExtensions.key]: TypeExtensions,
90
105
  }
@@ -121,7 +136,6 @@ Object.assign(Controls, {
121
136
 
122
137
  enableExtensions() {
123
138
  Object.values(Extensions).forEach((extension) => { extension.apply() })
124
- GlobalFunctionsAndProps.apply()
125
139
  },
126
140
 
127
141
  disableAll() {
@@ -147,7 +161,6 @@ Object.assign(Controls, {
147
161
 
148
162
  disableExtensions() {
149
163
  Object.values(Extensions).forEach((extension) => { extension.revert() })
150
- GlobalFunctionsAndProps.revert()
151
164
  },
152
165
  })
153
166
 
@@ -193,7 +206,9 @@ export const all = (() => {
193
206
  .reduce(entriesReducer, dest.classes)
194
207
  )
195
208
 
196
- for (const [key, entry] of GlobalFunctionsAndProps) {
209
+ const globals = [...GlobalFunctionsAndProps].concat([...StdoutGlobalPatches])
210
+
211
+ for (const [key, entry] of globals) {
197
212
  const descriptor = new Descriptor(entry.descriptor, entry.owner)
198
213
  Object.defineProperty(dest.global, key, descriptor.toObject(true))
199
214
  }
@@ -203,15 +218,16 @@ export const all = (() => {
203
218
 
204
219
  const results = {
205
220
  ...Controls,
221
+ all,
222
+ Controls,
206
223
  Extensions,
207
- Patches,
224
+ extensions: Extensions,
208
225
  GlobalFunctionsAndProps,
209
- StaticPatches,
210
226
  InstancePatches,
211
- Controls,
212
- extensions: Extensions,
227
+ Patches,
213
228
  patches: Patches,
214
- all,
229
+ StaticPatches,
230
+ StdoutGlobalPatches,
215
231
  }
216
232
 
217
233
  export default results
@@ -0,0 +1,73 @@
1
+ import { Patch } from '@nejs/extension'
2
+
3
+ /**
4
+ * `Math` extensions. Building better worlds...actually just
5
+ * providing some parity between Number and BigInt types for
6
+ * now, but later, better worlds.
7
+ *
8
+ * @type {Patch}
9
+ * @example
10
+ * import { MathExtensions } from 'math.extension.js'
11
+ *
12
+ * MathExtensions.apply()
13
+ * // Now the `Math` class has additional methods available
14
+ */
15
+ export const MathExtensions = new Patch(Math, {
16
+ [Patch.kMutablyHidden]: {
17
+ /**
18
+ * The Math.min() static method returns the smallest of the numbers given
19
+ * as input parameters, or Infinity if there are no parameters.
20
+ *
21
+ * @param {bigint|number} values value1, …, valueN – Zero or more numbers
22
+ * among which the lowest value will be selected and returned.
23
+ * @returns {bigint|number|NaN|Infinity} The smallest of the given numbers.
24
+ * Returns NaN if any of the parameters is or is converted into NaN or if
25
+ * the types of numbers are mismatched (i.e., bigint vs. number types).
26
+ * Returns Infinity if no parameters are provided.
27
+ */
28
+ min(...values) {
29
+ const sorter = (l,r) => l < r ? -1 : l > r ? 1 : 0
30
+
31
+ if (!values.length)
32
+ return Infinity
33
+
34
+ if (values.every(n => typeof n === 'bigint')) {
35
+ return values.toSorted(sorter).at(0)
36
+ }
37
+ else if (values.every(n => typeof n === 'number')) {
38
+ return values.toSorted(sorter).at(0)
39
+ }
40
+ else {
41
+ return NaN
42
+ }
43
+ },
44
+
45
+ /**
46
+ * The Math.max() static method returns the largest of the numbers given
47
+ * as input parameters, or Infinity if there are no parameters.
48
+ *
49
+ * @param {bigint|number} values value1, …, valueN – Zero or more numbers
50
+ * among which the largest value will be selected and returned.
51
+ * @returns {bigint|number|NaN|Infinity} The largest of the given numbers.
52
+ * Returns NaN if any of the parameters is or is converted into NaN or if
53
+ * the types of numbers are mismatched (i.e., bigint vs. number types).
54
+ * Returns Infinity if no parameters are provided.
55
+ */
56
+ max(...values) {
57
+ const sorter = (l,r) => l < r ? -1 : l > r ? 1 : 0
58
+
59
+ if (!values.length)
60
+ return Infinity
61
+
62
+ if (values.every(n => typeof n === 'bigint')) {
63
+ return values.toSorted(sorter).at(-1)
64
+ }
65
+ else if (values.every(n => typeof n === 'number')) {
66
+ return values.toSorted(sorter).at(-1)
67
+ }
68
+ else {
69
+ return NaN
70
+ }
71
+ },
72
+ },
73
+ })
@@ -258,6 +258,24 @@ export const NumberPrototypeExtensions = new Patch(Number.prototype, {
258
258
  ifNumber(thenValue, elseValue) {
259
259
  return pIfNumber(this, thenValue, elseValue)
260
260
  },
261
+
262
+ /**
263
+ * Provides a way when dealing with numbers to determine if
264
+ * a given number is within a range of values. By default, if
265
+ * no parameters are supplied, it always returns true since
266
+ * the default range is -Infinity to +Infinity. Additionally,
267
+ * by default, the number will always be less than the supplied
268
+ * max unless inclusive is set to true.
269
+ *
270
+ * @param min the lower range value, defaults to -Infinity
271
+ * @param max the upper range value, defaults to +Infinity
272
+ * @param inclusive defaults to false, set to true if you
273
+ * want the max value to less than and equals to
274
+ * @returns {boolean} true if within the range, false otherwise
275
+ */
276
+ within(min = -Infinity, max = Infinity, inclusive = false) {
277
+ return this >= min && (inclusive ? this <= max : this < max)
278
+ }
261
279
  }
262
280
  })
263
281