@nejs/basic-extensions 2.9.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 (167) hide show
  1. package/dist/@nejs/basic-extensions.bundle.2.10.0.js +19 -0
  2. package/dist/@nejs/basic-extensions.bundle.2.10.0.js.map +7 -0
  3. package/dist/cjs/array.extensions.js +174 -0
  4. package/dist/cjs/array.extensions.js.map +1 -1
  5. package/dist/cjs/big.int.extension.js +1 -0
  6. package/dist/cjs/big.int.extension.js.map +1 -1
  7. package/dist/cjs/classes/descriptor.js +1 -1
  8. package/dist/cjs/classes/descriptor.js.map +1 -1
  9. package/dist/cjs/classes/index.d.ts +1 -0
  10. package/dist/cjs/classes/index.js +3 -0
  11. package/dist/cjs/classes/index.js.map +1 -1
  12. package/dist/cjs/classes/iterable.d.ts +44 -0
  13. package/dist/cjs/classes/iterable.js +64 -0
  14. package/dist/cjs/classes/iterable.js.map +1 -1
  15. package/dist/cjs/classes/param.parser.d.ts +10 -10
  16. package/dist/cjs/classes/property.d.ts +86 -0
  17. package/dist/cjs/classes/property.js +284 -0
  18. package/dist/cjs/classes/property.js.map +1 -0
  19. package/dist/cjs/classes/symkeys.d.ts +68 -11
  20. package/dist/cjs/classes/symkeys.js +103 -17
  21. package/dist/cjs/classes/symkeys.js.map +1 -1
  22. package/dist/cjs/classes/type.d.ts +4 -4
  23. package/dist/cjs/function.extensions.js +1 -0
  24. package/dist/cjs/function.extensions.js.map +1 -1
  25. package/dist/cjs/global.this.js +29 -0
  26. package/dist/cjs/global.this.js.map +1 -1
  27. package/dist/cjs/index.d.ts +2 -0
  28. package/dist/cjs/index.js +18 -0
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/json.extensions.js +19 -18
  31. package/dist/cjs/json.extensions.js.map +1 -1
  32. package/dist/cjs/map.extensions.js +1 -0
  33. package/dist/cjs/map.extensions.js.map +1 -1
  34. package/dist/cjs/number.extension.js +1 -0
  35. package/dist/cjs/number.extension.js.map +1 -1
  36. package/dist/cjs/object.extensions.d.ts +0 -29
  37. package/dist/cjs/object.extensions.js +218 -255
  38. package/dist/cjs/object.extensions.js.map +1 -1
  39. package/dist/cjs/set.extensions.js +1 -0
  40. package/dist/cjs/set.extensions.js.map +1 -1
  41. package/dist/cjs/string.extensions.js +474 -469
  42. package/dist/cjs/string.extensions.js.map +1 -1
  43. package/dist/cjs/symbol.extensions.js +386 -31
  44. package/dist/cjs/symbol.extensions.js.map +1 -1
  45. package/dist/cjs/utils/copy.object.d.ts +408 -0
  46. package/dist/cjs/utils/copy.object.js +720 -0
  47. package/dist/cjs/utils/copy.object.js.map +1 -0
  48. package/dist/cjs/utils/index.d.ts +1 -0
  49. package/dist/cjs/utils/index.js +19 -0
  50. package/dist/cjs/utils/index.js.map +1 -0
  51. package/dist/cjs/utils/toolkit.d.ts +1897 -0
  52. package/dist/cjs/utils/toolkit.js +1377 -0
  53. package/dist/cjs/utils/toolkit.js.map +1 -0
  54. package/dist/mjs/array.extensions.js +174 -0
  55. package/dist/mjs/array.extensions.js.map +1 -1
  56. package/dist/mjs/big.int.extension.js +1 -0
  57. package/dist/mjs/big.int.extension.js.map +1 -1
  58. package/dist/mjs/classes/descriptor.js +1 -1
  59. package/dist/mjs/classes/descriptor.js.map +1 -1
  60. package/dist/mjs/classes/index.d.ts +1 -0
  61. package/dist/mjs/classes/index.js +3 -0
  62. package/dist/mjs/classes/index.js.map +1 -1
  63. package/dist/mjs/classes/iterable.d.ts +44 -0
  64. package/dist/mjs/classes/iterable.js +64 -0
  65. package/dist/mjs/classes/iterable.js.map +1 -1
  66. package/dist/mjs/classes/param.parser.d.ts +10 -10
  67. package/dist/mjs/classes/property.d.ts +86 -0
  68. package/dist/mjs/classes/property.js +280 -0
  69. package/dist/mjs/classes/property.js.map +1 -0
  70. package/dist/mjs/classes/symkeys.d.ts +68 -11
  71. package/dist/mjs/classes/symkeys.js +103 -17
  72. package/dist/mjs/classes/symkeys.js.map +1 -1
  73. package/dist/mjs/classes/type.d.ts +4 -4
  74. package/dist/mjs/function.extensions.js +1 -0
  75. package/dist/mjs/function.extensions.js.map +1 -1
  76. package/dist/mjs/global.this.js +6 -0
  77. package/dist/mjs/global.this.js.map +1 -1
  78. package/dist/mjs/index.d.ts +2 -0
  79. package/dist/mjs/index.js +4 -0
  80. package/dist/mjs/index.js.map +1 -1
  81. package/dist/mjs/json.extensions.js +19 -18
  82. package/dist/mjs/json.extensions.js.map +1 -1
  83. package/dist/mjs/map.extensions.js +1 -0
  84. package/dist/mjs/map.extensions.js.map +1 -1
  85. package/dist/mjs/number.extension.js +1 -0
  86. package/dist/mjs/number.extension.js.map +1 -1
  87. package/dist/mjs/object.extensions.d.ts +0 -29
  88. package/dist/mjs/object.extensions.js +215 -251
  89. package/dist/mjs/object.extensions.js.map +1 -1
  90. package/dist/mjs/set.extensions.js +1 -0
  91. package/dist/mjs/set.extensions.js.map +1 -1
  92. package/dist/mjs/string.extensions.js +474 -469
  93. package/dist/mjs/string.extensions.js.map +1 -1
  94. package/dist/mjs/symbol.extensions.js +386 -31
  95. package/dist/mjs/symbol.extensions.js.map +1 -1
  96. package/dist/mjs/utils/copy.object.d.ts +408 -0
  97. package/dist/mjs/utils/copy.object.js +702 -0
  98. package/dist/mjs/utils/copy.object.js.map +1 -0
  99. package/dist/mjs/utils/index.d.ts +1 -0
  100. package/dist/mjs/utils/index.js +3 -0
  101. package/dist/mjs/utils/index.js.map +1 -0
  102. package/dist/mjs/utils/toolkit.d.ts +1897 -0
  103. package/dist/mjs/utils/toolkit.js +1372 -0
  104. package/dist/mjs/utils/toolkit.js.map +1 -0
  105. package/package.json +29 -37
  106. package/repl.bootstrap.js +12 -1
  107. package/src/array.extensions.js +191 -1
  108. package/src/big.int.extension.js +3 -1
  109. package/src/classes/descriptor.js +1 -1
  110. package/src/classes/index.js +4 -0
  111. package/src/classes/iterable.js +74 -0
  112. package/src/classes/property.js +333 -0
  113. package/src/classes/symkeys.js +120 -19
  114. package/src/function.extensions.js +2 -0
  115. package/src/global.this.js +8 -0
  116. package/src/index.js +5 -0
  117. package/src/json.extensions.js +18 -19
  118. package/src/map.extensions.js +3 -1
  119. package/src/number.extension.js +3 -1
  120. package/src/object.extensions.js +240 -277
  121. package/src/set.extensions.js +3 -1
  122. package/src/string.extensions.js +512 -506
  123. package/src/symbol.extensions.js +412 -29
  124. package/src/utils/copy.object.js +780 -0
  125. package/src/utils/index.js +2 -0
  126. package/src/utils/toolkit.js +1471 -0
  127. package/tests/arrayextensions.test.js +2 -0
  128. package/tests/index.test.js +1 -0
  129. package/tests/newClasses/asyncIterable.test.js +2 -0
  130. package/tests/newClasses/deferred.test.js +5 -3
  131. package/tests/newClasses/descriptor.test.js +2 -0
  132. package/tests/newClasses/iterable.test.js +2 -0
  133. package/tests/newClasses/refmap.test.js +2 -1
  134. package/tests/newClasses/refset.test.js +2 -0
  135. package/tests/objectextensions.test.js +2 -0
  136. package/tests/setextensions.test.js +2 -0
  137. package/tests/stringextensions.test.js +1 -0
  138. package/tests/utils/toolkit.test.js +223 -0
  139. package/tsconfig.base.json +1 -1
  140. package/vitest.config.js +7 -0
  141. package/dist/@nejs/basic-extensions.bundle.2.8.0.js +0 -19
  142. package/dist/@nejs/basic-extensions.bundle.2.8.0.js.map +0 -7
  143. package/docs/assets/anchor.js +0 -350
  144. package/docs/assets/bass-addons.css +0 -12
  145. package/docs/assets/bass.css +0 -544
  146. package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
  147. package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
  148. package/docs/assets/fonts/LICENSE.txt +0 -93
  149. package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
  150. package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
  151. package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
  152. package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
  153. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
  154. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
  155. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
  156. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
  157. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
  158. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
  159. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  160. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  161. package/docs/assets/fonts/source-code-pro.css +0 -23
  162. package/docs/assets/github.css +0 -123
  163. package/docs/assets/site.js +0 -168
  164. package/docs/assets/split.css +0 -15
  165. package/docs/assets/split.js +0 -782
  166. package/docs/assets/style.css +0 -147
  167. package/docs/index.html +0 -35485
@@ -9,482 +9,486 @@ const parenthesisPair = ['(', ')'];
9
9
  * utility functions.
10
10
  */
11
11
  export const StringExtensions = new Patch(String, {
12
- /**
13
- * The `isString` method does exactly what one would it expect. It returns
14
- * true if the string matches typeof or instanceof as a string.
15
- *
16
- * @param {*} value checks to see if the `value` is a string
17
- * @returns {boolean} `true` if it is a `String`, `false` otherwise
18
- */
19
- isString(value) {
20
- return (value !== null && value !== undefined &&
21
- (typeof value === 'string' || value instanceof String));
22
- },
23
- /**
24
- * Conditionally returns a value based on whether the supplied
25
- * `value` is a `String` or not. If the `value` is a `String`,
26
- * the `thenValue` will be returned. If it is not a `String`,
27
- * the `elseValue` will be returned instead.
28
- *
29
- * @param {any} value the value to check to determine if it is a
30
- * `String`
31
- * @param {any} thenValue the value to return if the supplied
32
- * `value` is a `String`
33
- * @param {any} elseValue the value to return if the supplied
34
- * `value` is not a `String`
35
- * @returns {any} either the `thenValue` or `elseValue` depending
36
- * on if the supplied `value` is a `String`
37
- *
38
- * @example
39
- * const str = 'hello'
40
- * const num = 42
41
- * ifString(str, 'is a string', 'not a string') // 'is a string'
42
- * ifString(num, 'is a string', 'not a string') // 'not a string'
43
- */
44
- ifString(value, thenValue, elseValue) {
45
- return isThenElse(this.isString(value), thenValue, elseValue);
46
- },
47
- /**
48
- * A getter property that returns a pair of parentheses as an array.
49
- * This property can be used when operations require a clear distinction
50
- * between the opening and closing parentheses, such as parsing or
51
- * matching balanced expressions in strings.
52
- *
53
- * @returns {[string, string]} An array containing a pair of strings: the
54
- * opening parenthesis '(' as the first element, and the closing parenthesis
55
- * ')' as the second element.
56
- */
57
- get parenthesisPair() {
58
- return ['(', ')'];
59
- },
60
- /**
61
- * A getter property that returns a pair of square brackets as an array.
62
- * This property is particularly useful for operations that require a clear
63
- * distinction between the opening and closing square brackets, such as
64
- * parsing arrays in strings or matching balanced expressions within
65
- * square brackets.
66
- *
67
- * @returns {[string, string]} An array containing a pair of strings: the
68
- * opening square bracket '[' as the first element, and the closing square
69
- * bracket ']' as the second element.
70
- */
71
- get squareBracketsPair() {
72
- return ['[', ']'];
73
- },
74
- /**
75
- * A getter property that returns a pair of curly brackets as an array.
76
- * This property is particularly useful for operations that require a clear
77
- * distinction between the opening and closing curly brackets, such as
78
- * parsing objects in strings or matching balanced expressions within
79
- * curly brackets. The returned array consists of the opening curly bracket
80
- * '{' as the first element, and the closing curly bracket '}' as the
81
- * second element.
82
- *
83
- * @returns {[string, string]} An array containing a pair of strings: the
84
- * opening curly bracket '{' as the first element, and the closing curly
85
- * bracket '}' as the second element.
86
- */
87
- get curlyBracketsPair() {
88
- return ['{', '}'];
89
- },
90
- /**
91
- * Generates a random string using base 36 (numbers and lowercase letters).
92
- * This method is useful when you need a random string that includes both
93
- * numbers and letters. The generated string does not include the leading
94
- * '0.' that is part of the string representation of a random number in
95
- * base 36.
96
- *
97
- * @returns {string} A random string of characters in base 36.
98
- *
99
- * @example
100
- * const randomStr = StringExtensions.random36();
101
- * console.log(randomStr); // Output: "3n5yzxjkf2o"
102
- */
103
- random36() {
104
- return Math.random().toString(36).slice(2);
105
- },
106
- /**
107
- * Generates a random string using base 16 (hexadecimal numbers).
108
- * This method is useful when you need a random string that includes both
109
- * numbers and letters in hexadecimal format. The generated string does not
110
- * include the leading '0.' that is part of the string representation of a
111
- * random number in base 16.
112
- *
113
- * @returns {string} A random string of characters in base 16.
114
- *
115
- * @example
116
- * const randomStr = StringExtensions.random16();
117
- * console.log(randomStr); // Output: "3a5f4c"
118
- */
119
- random16() {
120
- return Math.random().toString(16).slice(2);
121
- },
122
- /**
123
- * Generates a random RGB color code.
124
- *
125
- * This method generates a random hexadecimal number, slices off the
126
- * leading '0.' and takes the first 6 characters. It then pads the
127
- * end of the string with '0' until it is 6 characters long. The
128
- * result is a string that can be used as a color code in CSS.
129
- *
130
- * @param {string} [prefix='#'] - The prefix to prepend to the color
131
- * code. Defaults to '#'.
132
- *
133
- * @returns {string} A random RGB color code.
134
- *
135
- * @example
136
- * const randomColor = StringExtensions.randomRGB();
137
- * console.log(randomColor); // Output: "#3a5f4c"
138
- */
139
- randomRGBHex(prefix = '#') {
140
- const hex = Math.random().toString(16).slice(2).substring(0, 6);
141
- return `${prefix}${hex.padEnd(6, '0')}`;
142
- },
143
- /**
144
- * Generates a random ARGB color code.
145
- *
146
- * This method generates a random hexadecimal number, slices off the
147
- * leading '0.' and takes the first 8 characters. It then pads the
148
- * start of the string with '0' until it is 6 characters long and the
149
- * end of the string with '0' until it is 8 characters long. The
150
- * result is a string that can be used as a color code in CSS.
151
- *
152
- * @param {string} [prefix='#'] - The prefix to prepend to the color
153
- * code. Defaults to '#'.
154
- *
155
- * @returns {string} A random ARGB color code.
156
- *
157
- * @example
158
- * const randomColor = StringExtensions.randomARGB();
159
- * console.log(randomColor); // Output: "#3a5f4c00"
160
- */
161
- randomARGBHex(prefix = '#') {
162
- const hex = Math.random().toString(16).slice(2).substring(0, 8);
163
- return `${prefix}${hex.padStart(6, '0').padEnd(8, '0')}`;
164
- },
165
- /**
166
- * Generates a random RGBA color code.
167
- *
168
- * This method generates a random hexadecimal number, slices off the
169
- * leading '0.' and takes the first 8 characters. It then pads the
170
- * start of the string with '0' until it is 6 characters long and the
171
- * end of the string with '0' until it is 8 characters long. The
172
- * result is a string that can be used as a color code in CSS.
173
- *
174
- * @param {string} [prefix='#'] - The prefix to prepend to the color
175
- * code. Defaults to '#'.
176
- *
177
- * @returns {string} A random RGBA color code.
178
- *
179
- * @example
180
- * const randomColor = StringExtensions.randomRGBA();
181
- * console.log(randomColor); // Output: "#3a5f4c00"
182
- */
183
- randomRGBAHex(prefix = '#') {
184
- const hex = Math.random().toString(16).slice(2).substring(0, 8);
185
- return `${prefix}${hex.padStart(6, '0').padStart(8, '0')}`;
186
- },
187
- /**
188
- * Generates a random RGB color code.
189
- *
190
- * This method generates a random hexadecimal number, slices off the
191
- * leading '0.' and pads the end of the string with '0' until it is
192
- * 8 characters long. It then parses the first 6 characters into
193
- * three separate 2-character strings, each representing a color
194
- * component (red, green, blue) in hexadecimal format. These strings
195
- * are then converted into decimal format and used to construct an
196
- * RGB color code.
197
- *
198
- * @returns {string} A random RGB color code.
199
- *
200
- * @example
201
- * const randomColor = StringExtensions.randomRGB();
202
- * console.log(randomColor); // Output: "rgb(58,95,76)"
203
- */
204
- randomRGB() {
205
- const hex = Math.random().toString(16).slice(2).padEnd(8, '0');
206
- const red = parseInt(hex.substring(0, 2), 16);
207
- const green = parseInt(hex.substring(2, 4), 16);
208
- const blue = parseInt(hex.substring(4, 6), 16);
209
- return `rgb(${red}, ${green}, ${blue})`;
210
- },
211
- /**
212
- * Generates a random RGBA color code with optional forced color values.
213
- *
214
- * This method generates a random hexadecimal number, slices off the
215
- * leading '0.' and pads the end of the string with '0' until it is
216
- * 8 characters long. It then parses the first 8 characters into
217
- * four separate 2-character strings, each representing a color
218
- * component (red, green, blue, alpha) in hexadecimal format. These strings
219
- * are then converted into decimal format and used to construct an
220
- * RGBA color code.
221
- *
222
- * If a color component is provided in the `force` parameter, it will
223
- * be used instead of a random value for that component.
224
- *
225
- * @param {Object} force - An object with properties for each color
226
- * component (red, green, blue, alpha) that should be forced to a
227
- * specific value. If a property is undefined or not provided, a
228
- * random value will be used for that component.
229
- * @param {number} force.red - The red component (0-255).
230
- * @param {number} force.green - The green component (0-255).
231
- * @param {number} force.blue - The blue component (0-255).
232
- * @param {number} force.alpha - The alpha component (0.0-1.0).
233
- *
234
- * @returns {string} A random RGBA color code.
235
- *
236
- * @example
237
- * const randomColor = StringExtensions.randomRGBA();
238
- * console.log(randomColor); // Output: "rgba(58,95,76,0.50)"
239
- *
240
- * const forcedGreen = StringExtensions.randomRGBA({ green: 255 });
241
- * console.log(forcedGreen); // Output: "rgba(58,255,76,0.50)"
242
- */
243
- randomRGBA(force = {
244
- red: undefined,
245
- green: undefined,
246
- blue: undefined,
247
- alpha: undefined
248
- }) {
249
- const hex = Math.random().toString(16).slice(2).padEnd(8, '0');
250
- const red = force.red ?? parseInt(hex.substring(0, 2), 16);
251
- const green = force.green ?? parseInt(hex.substring(2, 4), 16);
252
- const blue = force.blue ?? parseInt(hex.substring(4, 6), 16);
253
- const alpha = force.alpha ??
254
- (parseInt(hex.substring(6, 8), 16) / 255.0) * 1.0;
255
- return `rgba(${red}, ${green}, ${blue}, ${alpha.toFixed(2)})`;
256
- },
257
- /**
258
- * Applies Select Graphic Rendition (SGR) parameters to a given message for
259
- * styling in terminal environments. This function allows for the dynamic
260
- * styling of text output using ANSI escape codes. It supports a variety of
261
- * modes such as color, brightness, and text decorations like bold or underline.
262
- *
263
- * @param {string} message The message to be styled.
264
- * @param {...string} useModes A series of strings representing the desired
265
- * styling modes. Modes can include colors (e.g., 'red', 'blue'), brightness
266
- * ('bright'), foreground/background ('fg', 'bg'), and text decorations
267
- * ('bold', 'underline'). Modes can be combined in a single string using
268
- * commas or passed as separate arguments.
269
- *
270
- * Colors:
271
- * ```
272
- * 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
273
- * ```
274
- * Color Specifiers:
275
- * ```
276
- * 'fg' -> foreground | 'bg' -> background | 'bright' -> bright colors
277
- * ```
278
- *
279
- * Modes:
280
- * ```
281
- * 'blink' or 'k' | 'conceal' or 'c' | 'italics' or 'i' | 'strike' or 's'
282
- * 'bold' or 'b' | 'dim' or 'd' | 'negative' or 'n' | 'underline' or 'u'
283
- * ```
284
- *
285
- * Examples:
286
- * - `sgr('Hello', 'red')` applies red color to 'Hello'.
287
- * - `sgr('World', 'green,bold')` applies green color and bold styling
288
- * to 'World'.
289
- * - `sgr('Example', 'bluebgbright')` applies bright blue
290
- * background color.
291
- *
292
- * Short hand syntax is also allowed:
293
- * - `sgr('hello', 'biu')` applies bold, italics and underline
294
- * - `sgr('hello', 'bi,redfg')` applies bold, italics and red foreground
295
- *
296
- * As a bonus, there is a secret getter applied to the return string that
297
- * allows you to invoke `sgr(...).show` to automatically log the output to
298
- * `console.log`. This is done by wrapping the output string in `Object()`
299
- * to make it a `String` instance and then adding the property descriptor.
300
- * A custom `Symbol` is applied to make it evaluate in nodejs as though it
301
- * were a normal string. To strip the extras, wrap the output in `String()`
302
- *
303
- * @returns {string} The message wrapped in ANSI escape codes corresponding
304
- * to the specified modes. The returned string, when printed to a terminal,
305
- * displays the styled message. Additional properties are attached to the
306
- * result for utility purposes, such as 'show' for immediate console output.
307
- */
308
- sgr(message, ...useModes) {
309
- const colors = Object.assign(['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'], {
310
- isBG: a => !!/bg/i.exec(a),
311
- isBright: a => !!/bright/i.exec(a),
312
- isColor: a => {
313
- let color = colors.find(c => new RegExp(c, 'i').exec(a));
314
- return [!!color, colors.indexOf(color)];
315
- },
316
- });
317
- const arrayifyString = s => {
318
- if (Array.isArray(s)) {
319
- let results = [];
320
- for (const i of s) {
321
- results = [...results, ...arrayifyString(i)];
12
+ [Patch.kMutablyHidden]: {
13
+ /**
14
+ * The `isString` method does exactly what one would it expect. It returns
15
+ * true if the string matches typeof or instanceof as a string.
16
+ *
17
+ * @param {*} value checks to see if the `value` is a string
18
+ * @returns {boolean} `true` if it is a `String`, `false` otherwise
19
+ */
20
+ isString(value) {
21
+ return (value !== null && value !== undefined &&
22
+ (typeof value === 'string' || value instanceof String));
23
+ },
24
+ /**
25
+ * Conditionally returns a value based on whether the supplied
26
+ * `value` is a `String` or not. If the `value` is a `String`,
27
+ * the `thenValue` will be returned. If it is not a `String`,
28
+ * the `elseValue` will be returned instead.
29
+ *
30
+ * @param {any} value the value to check to determine if it is a
31
+ * `String`
32
+ * @param {any} thenValue the value to return if the supplied
33
+ * `value` is a `String`
34
+ * @param {any} elseValue the value to return if the supplied
35
+ * `value` is not a `String`
36
+ * @returns {any} either the `thenValue` or `elseValue` depending
37
+ * on if the supplied `value` is a `String`
38
+ *
39
+ * @example
40
+ * const str = 'hello'
41
+ * const num = 42
42
+ * ifString(str, 'is a string', 'not a string') // 'is a string'
43
+ * ifString(num, 'is a string', 'not a string') // 'not a string'
44
+ */
45
+ ifString(value, thenValue, elseValue) {
46
+ return isThenElse(String.isString(value), thenValue, elseValue);
47
+ },
48
+ /**
49
+ * A getter property that returns a pair of parentheses as an array.
50
+ * This property can be used when operations require a clear distinction
51
+ * between the opening and closing parentheses, such as parsing or
52
+ * matching balanced expressions in strings.
53
+ *
54
+ * @returns {[string, string]} An array containing a pair of strings: the
55
+ * opening parenthesis '(' as the first element, and the closing parenthesis
56
+ * ')' as the second element.
57
+ */
58
+ get parenthesisPair() {
59
+ return ['(', ')'];
60
+ },
61
+ /**
62
+ * A getter property that returns a pair of square brackets as an array.
63
+ * This property is particularly useful for operations that require a clear
64
+ * distinction between the opening and closing square brackets, such as
65
+ * parsing arrays in strings or matching balanced expressions within
66
+ * square brackets.
67
+ *
68
+ * @returns {[string, string]} An array containing a pair of strings: the
69
+ * opening square bracket '[' as the first element, and the closing square
70
+ * bracket ']' as the second element.
71
+ */
72
+ get squareBracketsPair() {
73
+ return ['[', ']'];
74
+ },
75
+ /**
76
+ * A getter property that returns a pair of curly brackets as an array.
77
+ * This property is particularly useful for operations that require a clear
78
+ * distinction between the opening and closing curly brackets, such as
79
+ * parsing objects in strings or matching balanced expressions within
80
+ * curly brackets. The returned array consists of the opening curly bracket
81
+ * '{' as the first element, and the closing curly bracket '}' as the
82
+ * second element.
83
+ *
84
+ * @returns {[string, string]} An array containing a pair of strings: the
85
+ * opening curly bracket '{' as the first element, and the closing curly
86
+ * bracket '}' as the second element.
87
+ */
88
+ get curlyBracketsPair() {
89
+ return ['{', '}'];
90
+ },
91
+ /**
92
+ * Generates a random string using base 36 (numbers and lowercase letters).
93
+ * This method is useful when you need a random string that includes both
94
+ * numbers and letters. The generated string does not include the leading
95
+ * '0.' that is part of the string representation of a random number in
96
+ * base 36.
97
+ *
98
+ * @returns {string} A random string of characters in base 36.
99
+ *
100
+ * @example
101
+ * const randomStr = StringExtensions.random36();
102
+ * console.log(randomStr); // Output: "3n5yzxjkf2o"
103
+ */
104
+ random36() {
105
+ return Math.random().toString(36).slice(2);
106
+ },
107
+ /**
108
+ * Generates a random string using base 16 (hexadecimal numbers).
109
+ * This method is useful when you need a random string that includes both
110
+ * numbers and letters in hexadecimal format. The generated string does not
111
+ * include the leading '0.' that is part of the string representation of a
112
+ * random number in base 16.
113
+ *
114
+ * @returns {string} A random string of characters in base 16.
115
+ *
116
+ * @example
117
+ * const randomStr = StringExtensions.random16();
118
+ * console.log(randomStr); // Output: "3a5f4c"
119
+ */
120
+ random16() {
121
+ return Math.random().toString(16).slice(2);
122
+ },
123
+ /**
124
+ * Generates a random RGB color code.
125
+ *
126
+ * This method generates a random hexadecimal number, slices off the
127
+ * leading '0.' and takes the first 6 characters. It then pads the
128
+ * end of the string with '0' until it is 6 characters long. The
129
+ * result is a string that can be used as a color code in CSS.
130
+ *
131
+ * @param {string} [prefix='#'] - The prefix to prepend to the color
132
+ * code. Defaults to '#'.
133
+ *
134
+ * @returns {string} A random RGB color code.
135
+ *
136
+ * @example
137
+ * const randomColor = StringExtensions.randomRGB();
138
+ * console.log(randomColor); // Output: "#3a5f4c"
139
+ */
140
+ randomRGBHex(prefix = '#') {
141
+ const hex = Math.random().toString(16).slice(2).substring(0, 6);
142
+ return `${prefix}${hex.padEnd(6, '0')}`;
143
+ },
144
+ /**
145
+ * Generates a random ARGB color code.
146
+ *
147
+ * This method generates a random hexadecimal number, slices off the
148
+ * leading '0.' and takes the first 8 characters. It then pads the
149
+ * start of the string with '0' until it is 6 characters long and the
150
+ * end of the string with '0' until it is 8 characters long. The
151
+ * result is a string that can be used as a color code in CSS.
152
+ *
153
+ * @param {string} [prefix='#'] - The prefix to prepend to the color
154
+ * code. Defaults to '#'.
155
+ *
156
+ * @returns {string} A random ARGB color code.
157
+ *
158
+ * @example
159
+ * const randomColor = StringExtensions.randomARGB();
160
+ * console.log(randomColor); // Output: "#3a5f4c00"
161
+ */
162
+ randomARGBHex(prefix = '#') {
163
+ const hex = Math.random().toString(16).slice(2).substring(0, 8);
164
+ return `${prefix}${hex.padStart(6, '0').padEnd(8, '0')}`;
165
+ },
166
+ /**
167
+ * Generates a random RGBA color code.
168
+ *
169
+ * This method generates a random hexadecimal number, slices off the
170
+ * leading '0.' and takes the first 8 characters. It then pads the
171
+ * start of the string with '0' until it is 6 characters long and the
172
+ * end of the string with '0' until it is 8 characters long. The
173
+ * result is a string that can be used as a color code in CSS.
174
+ *
175
+ * @param {string} [prefix='#'] - The prefix to prepend to the color
176
+ * code. Defaults to '#'.
177
+ *
178
+ * @returns {string} A random RGBA color code.
179
+ *
180
+ * @example
181
+ * const randomColor = StringExtensions.randomRGBA();
182
+ * console.log(randomColor); // Output: "#3a5f4c00"
183
+ */
184
+ randomRGBAHex(prefix = '#') {
185
+ const hex = Math.random().toString(16).slice(2).substring(0, 8);
186
+ return `${prefix}${hex.padStart(6, '0').padStart(8, '0')}`;
187
+ },
188
+ /**
189
+ * Generates a random RGB color code.
190
+ *
191
+ * This method generates a random hexadecimal number, slices off the
192
+ * leading '0.' and pads the end of the string with '0' until it is
193
+ * 8 characters long. It then parses the first 6 characters into
194
+ * three separate 2-character strings, each representing a color
195
+ * component (red, green, blue) in hexadecimal format. These strings
196
+ * are then converted into decimal format and used to construct an
197
+ * RGB color code.
198
+ *
199
+ * @returns {string} A random RGB color code.
200
+ *
201
+ * @example
202
+ * const randomColor = StringExtensions.randomRGB();
203
+ * console.log(randomColor); // Output: "rgb(58,95,76)"
204
+ */
205
+ randomRGB() {
206
+ const hex = Math.random().toString(16).slice(2).padEnd(8, '0');
207
+ const red = parseInt(hex.substring(0, 2), 16);
208
+ const green = parseInt(hex.substring(2, 4), 16);
209
+ const blue = parseInt(hex.substring(4, 6), 16);
210
+ return `rgb(${red}, ${green}, ${blue})`;
211
+ },
212
+ /**
213
+ * Generates a random RGBA color code with optional forced color values.
214
+ *
215
+ * This method generates a random hexadecimal number, slices off the
216
+ * leading '0.' and pads the end of the string with '0' until it is
217
+ * 8 characters long. It then parses the first 8 characters into
218
+ * four separate 2-character strings, each representing a color
219
+ * component (red, green, blue, alpha) in hexadecimal format. These strings
220
+ * are then converted into decimal format and used to construct an
221
+ * RGBA color code.
222
+ *
223
+ * If a color component is provided in the `force` parameter, it will
224
+ * be used instead of a random value for that component.
225
+ *
226
+ * @param {Object} force - An object with properties for each color
227
+ * component (red, green, blue, alpha) that should be forced to a
228
+ * specific value. If a property is undefined or not provided, a
229
+ * random value will be used for that component.
230
+ * @param {number} force.red - The red component (0-255).
231
+ * @param {number} force.green - The green component (0-255).
232
+ * @param {number} force.blue - The blue component (0-255).
233
+ * @param {number} force.alpha - The alpha component (0.0-1.0).
234
+ *
235
+ * @returns {string} A random RGBA color code.
236
+ *
237
+ * @example
238
+ * const randomColor = StringExtensions.randomRGBA();
239
+ * console.log(randomColor); // Output: "rgba(58,95,76,0.50)"
240
+ *
241
+ * const forcedGreen = StringExtensions.randomRGBA({ green: 255 });
242
+ * console.log(forcedGreen); // Output: "rgba(58,255,76,0.50)"
243
+ */
244
+ randomRGBA(force = {
245
+ red: undefined,
246
+ green: undefined,
247
+ blue: undefined,
248
+ alpha: undefined
249
+ }) {
250
+ const hex = Math.random().toString(16).slice(2).padEnd(8, '0');
251
+ const red = force.red ?? parseInt(hex.substring(0, 2), 16);
252
+ const green = force.green ?? parseInt(hex.substring(2, 4), 16);
253
+ const blue = force.blue ?? parseInt(hex.substring(4, 6), 16);
254
+ const alpha = force.alpha ??
255
+ (parseInt(hex.substring(6, 8), 16) / 255.0) * 1.0;
256
+ return `rgba(${red}, ${green}, ${blue}, ${alpha.toFixed(2)})`;
257
+ },
258
+ /**
259
+ * Applies Select Graphic Rendition (SGR) parameters to a given message for
260
+ * styling in terminal environments. This function allows for the dynamic
261
+ * styling of text output using ANSI escape codes. It supports a variety of
262
+ * modes such as color, brightness, and text decorations like bold or underline.
263
+ *
264
+ * @param {string} message The message to be styled.
265
+ * @param {...string} useModes A series of strings representing the desired
266
+ * styling modes. Modes can include colors (e.g., 'red', 'blue'), brightness
267
+ * ('bright'), foreground/background ('fg', 'bg'), and text decorations
268
+ * ('bold', 'underline'). Modes can be combined in a single string using
269
+ * commas or passed as separate arguments.
270
+ *
271
+ * Colors:
272
+ * ```
273
+ * 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
274
+ * ```
275
+ * Color Specifiers:
276
+ * ```
277
+ * 'fg' -> foreground | 'bg' -> background | 'bright' -> bright colors
278
+ * ```
279
+ *
280
+ * Modes:
281
+ * ```
282
+ * 'blink' or 'k' | 'conceal' or 'c' | 'italics' or 'i' | 'strike' or 's'
283
+ * 'bold' or 'b' | 'dim' or 'd' | 'negative' or 'n' | 'underline' or 'u'
284
+ * ```
285
+ *
286
+ * Examples:
287
+ * - `sgr('Hello', 'red')` applies red color to 'Hello'.
288
+ * - `sgr('World', 'green,bold')` applies green color and bold styling
289
+ * to 'World'.
290
+ * - `sgr('Example', 'bluebgbright')` applies bright blue
291
+ * background color.
292
+ *
293
+ * Short hand syntax is also allowed:
294
+ * - `sgr('hello', 'biu')` applies bold, italics and underline
295
+ * - `sgr('hello', 'bi,redfg')` applies bold, italics and red foreground
296
+ *
297
+ * As a bonus, there is a secret getter applied to the return string that
298
+ * allows you to invoke `sgr(...).show` to automatically log the output to
299
+ * `console.log`. This is done by wrapping the output string in `Object()`
300
+ * to make it a `String` instance and then adding the property descriptor.
301
+ * A custom `Symbol` is applied to make it evaluate in nodejs as though it
302
+ * were a normal string. To strip the extras, wrap the output in `String()`
303
+ *
304
+ * @returns {string} The message wrapped in ANSI escape codes corresponding
305
+ * to the specified modes. The returned string, when printed to a terminal,
306
+ * displays the styled message. Additional properties are attached to the
307
+ * result for utility purposes, such as 'show' for immediate console output.
308
+ */
309
+ sgr(message, ...useModes) {
310
+ const colors = Object.assign(['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'], {
311
+ isBG: a => !!/bg/i.exec(a),
312
+ isBright: a => !!/bright/i.exec(a),
313
+ isColor: a => {
314
+ let color = colors.find(c => new RegExp(c, 'i').exec(a));
315
+ return [!!color, colors.indexOf(color)];
316
+ },
317
+ });
318
+ const arrayifyString = s => {
319
+ if (Array.isArray(s)) {
320
+ let results = [];
321
+ for (const i of s) {
322
+ results = [...results, ...arrayifyString(i)];
323
+ }
324
+ return results.flat().filter(i => i.length);
322
325
  }
323
- return results.flat().filter(i => i.length);
324
- }
325
- if (!s || typeof s !== 'string') {
326
- return [''];
327
- }
328
- else if (s.includes(',')) {
329
- return arrayifyString(s.split(','));
330
- }
331
- else {
332
- if (!colors.isColor(s)[0] && s.length > 1) {
333
- return [...s];
326
+ if (!s || typeof s !== 'string') {
327
+ return [''];
334
328
  }
335
- else
336
- return [s];
337
- }
338
- };
339
- let modes = arrayifyString(useModes);
340
- const sgrModes = {
341
- blink: ['\x1b[5m', '\x1b[25m', 'k'],
342
- bold: ['\x1b[1m', '\x1b[22m', 'b'],
343
- conceal: ['\x1b[8m', '\x1b[28m', 'c'],
344
- dim: ['\x1b[2m', '\x1b[22m', 'd'],
345
- italics: ['\x1b[3m', '\x1b[23m', 'i'],
346
- negative: ['\x1b[7m', '\x1b[27m', 'n'],
347
- strike: ['\x1b[9m', '\x1b[29m', 's'],
348
- underline: ['\x1b[4m', '\x1b[24m', 'u'],
349
- };
350
- Object.values(sgrModes).forEach(mode => sgrModes[mode[2]] = mode);
351
- const codes = a => {
352
- let open = '', close = '', mode = String(a).toLowerCase();
353
- let [_isColor, colorIndex] = colors.isColor(mode);
354
- if (_isColor) {
355
- open = colors.isBG(mode)
356
- ? `\x1b[${colors.isBright(mode) ? 10 : 4}${colorIndex}m`
357
- : `\x1b[${colors.isBright(mode) ? 9 : 3}${colorIndex}m`;
358
- close = colors.isBG(mode) ? '\x1b[49m' : `\x1b[39m`;
359
- }
360
- else if (sgrModes[mode]) {
361
- open = sgrModes[mode][0];
362
- close = sgrModes[mode][1];
363
- }
364
- return [open, close];
365
- };
366
- const onOrder = modes.map(key => codes(key)[0]).join('');
367
- const offOrder = modes.map(key => codes(key)[1]).reverse().join('');
368
- let result = Object(`${onOrder}${message}${offOrder}`);
369
- Object.defineProperties(result, {
370
- show: {
371
- get() { console.log(String(this)); return this; },
372
- enumerable: false,
373
- },
374
- [Symbol.for('nodejs.util.inspect.custom')]: {
375
- value(depth, options, inspect) {
376
- return inspect(String(this), options);
329
+ else if (s.includes(',')) {
330
+ return arrayifyString(s.split(','));
331
+ }
332
+ else {
333
+ if (!colors.isColor(s)[0] && s.length > 1) {
334
+ return [...s];
335
+ }
336
+ else
337
+ return [s];
338
+ }
339
+ };
340
+ let modes = arrayifyString(useModes);
341
+ const sgrModes = {
342
+ blink: ['\x1b[5m', '\x1b[25m', 'k'],
343
+ bold: ['\x1b[1m', '\x1b[22m', 'b'],
344
+ conceal: ['\x1b[8m', '\x1b[28m', 'c'],
345
+ dim: ['\x1b[2m', '\x1b[22m', 'd'],
346
+ italics: ['\x1b[3m', '\x1b[23m', 'i'],
347
+ negative: ['\x1b[7m', '\x1b[27m', 'n'],
348
+ strike: ['\x1b[9m', '\x1b[29m', 's'],
349
+ underline: ['\x1b[4m', '\x1b[24m', 'u'],
350
+ };
351
+ Object.values(sgrModes).forEach(mode => sgrModes[mode[2]] = mode);
352
+ const codes = a => {
353
+ let open = '', close = '', mode = String(a).toLowerCase();
354
+ let [_isColor, colorIndex] = colors.isColor(mode);
355
+ if (_isColor) {
356
+ open = colors.isBG(mode)
357
+ ? `\x1b[${colors.isBright(mode) ? 10 : 4}${colorIndex}m`
358
+ : `\x1b[${colors.isBright(mode) ? 9 : 3}${colorIndex}m`;
359
+ close = colors.isBG(mode) ? '\x1b[49m' : `\x1b[39m`;
360
+ }
361
+ else if (sgrModes[mode]) {
362
+ open = sgrModes[mode][0];
363
+ close = sgrModes[mode][1];
364
+ }
365
+ return [open, close];
366
+ };
367
+ const onOrder = modes.map(key => codes(key)[0]).join('');
368
+ const offOrder = modes.map(key => codes(key)[1]).reverse().join('');
369
+ let result = Object(`${onOrder}${message}${offOrder}`);
370
+ Object.defineProperties(result, {
371
+ show: {
372
+ get() { console.log(String(this)); return this; },
373
+ enumerable: false,
377
374
  },
378
- enumerable: false,
379
- },
380
- });
381
- return result;
382
- },
383
- /**
384
- * Wraps an object's properties into a formatted string.
385
- *
386
- * This method takes an object and a set of options to format the
387
- * object's properties into a string. It allows customization of
388
- * indentation, line endings, maximum line length, and more.
389
- *
390
- * @param {Object} [object=globalThis] - The object to wrap.
391
- * @param {Object} [options={}] - The formatting options.
392
- * @param {number} [options.indent=2] - The number of indentation
393
- * characters to use.
394
- * @param {string} [options.indentCharacter=' '] - The character to use
395
- * for indentation.
396
- * @param {Array} [options.inspector=[Object, 'getOwnPropertyNames']] -
397
- * The inspector to use for retrieving object properties.
398
- * @param {string} [options.lineEnding='\n'] - The line ending character.
399
- * @param {number} [options.maxLen=78] - The maximum line length.
400
- * @param {Function} [options.perLine=undefined] - A function to apply
401
- * per line of output.
402
- * @param {Function} [options.perLinePerProperty=undefined] - A function
403
- * to apply per property per line of output.
404
- * @param {Function} [options.preProcess=undefined] - A function to
405
- * preprocess the object's properties.
406
- * @param {Function} [options.preReturn=undefined] - A function to apply
407
- * to the final output before returning.
408
- * @param {string} [options.separator=', '] - The separator to use
409
- * between properties.
410
- *
411
- * @returns {string} The formatted string representation of the object.
412
- *
413
- * @example
414
- * const obj = { a: 1, b: 2, c: 3 }
415
- * const wrapped = StringExtensions.wrap(obj, { maxLen: 20 })
416
- * console.log(wrapped)
417
- * // Output:
418
- * // {
419
- * // a: 1,
420
- * // b: 2,
421
- * // c: 3
422
- * // }
423
- */
424
- wrap(objectOrLines, options = {
425
- colorProperties: undefined,
426
- indent: 2,
427
- indentCharacter: ' ',
428
- inspector: [Object, 'getOwnPropertyNames'],
429
- lineEnding: '\n',
430
- maxLen: 78,
431
- perLine: undefined,
432
- perLinePerProperty: undefined,
433
- preProcess: undefined,
434
- preReturn: undefined,
435
- separator: ', ',
436
- }) {
437
- let { colorProperties = undefined, indent = options?.indent ?? 2, indentCharacter = options?.indentCharacter ?? ' ', inspector = options?.inspector ?? [Object, 'getOwnPropertyNames'], lineEnding = options?.lineEnding ?? '\n', maxLen = options?.maxLen ?? 78, perLine = options?.perLine ?? undefined, perLinePerProperty = options?.perLinePerProperty ?? undefined, preProcess = options?.preProcess ?? undefined, preReturn = options?.preReturn ?? undefined, separator = options?.separator ?? ', ', } = options ?? {};
438
- let tab = indent === 0 ? ''
439
- : indentCharacter.repeat(Number(indent) || 2);
440
- maxLen = 78 - tab.length;
441
- const sgr = this.sgr;
442
- const validMapper = f => typeof f === 'function';
443
- let line = [];
444
- let getElements = inspector[0][inspector[1]];
445
- let values = Array.isArray(objectOrLines)
446
- ? objectOrLines : getElements(Object(objectOrLines));
447
- if (validMapper(preProcess)) {
448
- values = preProcess(values);
449
- }
450
- const context = { indent, indentCharacter, lineEnding, maxLen, tab, sgr };
451
- let finalLines = values.reduce((acc, nextProp) => {
452
- let ifCombined = [...line, nextProp].join(separator);
453
- if ((tab.length + ifCombined.length) <= maxLen) {
454
- line.push(nextProp);
455
- }
456
- else {
457
- let lineProps = [...line];
458
- if (validMapper(perLinePerProperty)) {
459
- lineProps = lineProps.map((value, index, array) => {
460
- return perLinePerProperty(value, index, array, context);
461
- });
375
+ [Symbol.for('nodejs.util.inspect.custom')]: {
376
+ value(depth, options, inspect) { return String(this); },
377
+ enumerable: false,
378
+ },
379
+ [Symbol.toStringTag]: {
380
+ get() { return "SgrString"; },
381
+ enumerable: false,
462
382
  }
463
- if (colorProperties) {
464
- const sgrArgs = (Array.isArray(colorProperties)
465
- ? colorProperties
466
- : [colorProperties]);
467
- lineProps = lineProps.map(v => sgr(v, ...sgrArgs));
383
+ });
384
+ return result;
385
+ },
386
+ /**
387
+ * Wraps an object's properties into a formatted string.
388
+ *
389
+ * This method takes an object and a set of options to format the
390
+ * object's properties into a string. It allows customization of
391
+ * indentation, line endings, maximum line length, and more.
392
+ *
393
+ * @param {Object} [object=globalThis] - The object to wrap.
394
+ * @param {Object} [options={}] - The formatting options.
395
+ * @param {number} [options.indent=2] - The number of indentation
396
+ * characters to use.
397
+ * @param {string} [options.indentCharacter=' '] - The character to use
398
+ * for indentation.
399
+ * @param {Array} [options.inspector=[Object, 'getOwnPropertyNames']] -
400
+ * The inspector to use for retrieving object properties.
401
+ * @param {string} [options.lineEnding='\n'] - The line ending character.
402
+ * @param {number} [options.maxLen=78] - The maximum line length.
403
+ * @param {Function} [options.perLine=undefined] - A function to apply
404
+ * per line of output.
405
+ * @param {Function} [options.perLinePerProperty=undefined] - A function
406
+ * to apply per property per line of output.
407
+ * @param {Function} [options.preProcess=undefined] - A function to
408
+ * preprocess the object's properties.
409
+ * @param {Function} [options.preReturn=undefined] - A function to apply
410
+ * to the final output before returning.
411
+ * @param {string} [options.separator=', '] - The separator to use
412
+ * between properties.
413
+ *
414
+ * @returns {string} The formatted string representation of the object.
415
+ *
416
+ * @example
417
+ * const obj = { a: 1, b: 2, c: 3 }
418
+ * const wrapped = StringExtensions.wrap(obj, { maxLen: 20 })
419
+ * console.log(wrapped)
420
+ * // Output:
421
+ * // {
422
+ * // a: 1,
423
+ * // b: 2,
424
+ * // c: 3
425
+ * // }
426
+ */
427
+ wrap(objectOrLines, options = {
428
+ colorProperties: undefined,
429
+ indent: 2,
430
+ indentCharacter: ' ',
431
+ inspector: [Object, 'getOwnPropertyNames'],
432
+ lineEnding: '\n',
433
+ maxLen: 78,
434
+ perLine: undefined,
435
+ perLinePerProperty: undefined,
436
+ preProcess: undefined,
437
+ preReturn: undefined,
438
+ separator: ', ',
439
+ }) {
440
+ let { colorProperties = undefined, indent = options?.indent ?? 2, indentCharacter = options?.indentCharacter ?? ' ', inspector = options?.inspector ?? [Object, 'getOwnPropertyNames'], lineEnding = options?.lineEnding ?? '\n', maxLen = options?.maxLen ?? 78, perLine = options?.perLine ?? undefined, perLinePerProperty = options?.perLinePerProperty ?? undefined, preProcess = options?.preProcess ?? undefined, preReturn = options?.preReturn ?? undefined, separator = options?.separator ?? ', ', } = options ?? {};
441
+ let tab = indent === 0 ? ''
442
+ : indentCharacter.repeat(Number(indent) || 2);
443
+ maxLen = 78 - tab.length;
444
+ const sgr = this.sgr;
445
+ const validMapper = f => typeof f === 'function';
446
+ let line = [];
447
+ let getElements = inspector[0][inspector[1]];
448
+ let values = Array.isArray(objectOrLines)
449
+ ? objectOrLines : getElements(Object(objectOrLines));
450
+ if (validMapper(preProcess)) {
451
+ values = preProcess(values);
452
+ }
453
+ const context = { indent, indentCharacter, lineEnding, maxLen, tab, sgr };
454
+ let finalLines = values.reduce((acc, nextProp) => {
455
+ let ifCombined = [...line, nextProp].join(separator);
456
+ if ((tab.length + ifCombined.length) <= maxLen) {
457
+ line.push(nextProp);
468
458
  }
469
- lineProps = [tab, lineProps.join(separator)].join('');
470
- if (validMapper(perLine)) {
471
- lineProps = perLine(lineProps[0], 0, lineProps)?.[0] ?? lineProps[0];
459
+ else {
460
+ let lineProps = [...line];
461
+ if (validMapper(perLinePerProperty)) {
462
+ lineProps = lineProps.map((value, index, array) => {
463
+ return perLinePerProperty(value, index, array, context);
464
+ });
465
+ }
466
+ if (colorProperties) {
467
+ const sgrArgs = (Array.isArray(colorProperties)
468
+ ? colorProperties
469
+ : [colorProperties]);
470
+ lineProps = lineProps.map(v => sgr(v, ...sgrArgs));
471
+ }
472
+ lineProps = [tab, lineProps.join(separator)].join('');
473
+ if (validMapper(perLine)) {
474
+ lineProps = perLine(lineProps[0], 0, lineProps)?.[0] ?? lineProps[0];
475
+ }
476
+ acc.push(lineProps);
477
+ line = [];
472
478
  }
473
- acc.push(lineProps);
474
- line = [];
479
+ return acc;
480
+ }, []);
481
+ if (validMapper(preReturn)) {
482
+ finalLines = finalLines.map((value, index, array) => {
483
+ return preReturn(value, index, array, context);
484
+ });
475
485
  }
476
- return acc;
477
- }, []);
478
- if (validMapper(preReturn)) {
479
- finalLines = finalLines.map((value, index, array) => {
480
- return preReturn(value, index, array, context);
481
- });
482
- }
483
- Symbol.for(`@nejs.string.wrap ${JSON.stringify({ lines: finalLines })}`);
484
- if (lineEnding) {
485
- finalLines = finalLines.join(lineEnding);
486
- }
487
- return finalLines;
486
+ Symbol.for(`@nejs.string.wrap ${JSON.stringify({ lines: finalLines })}`);
487
+ if (lineEnding) {
488
+ finalLines = finalLines.join(lineEnding);
489
+ }
490
+ return finalLines;
491
+ },
488
492
  },
489
493
  });
490
494
  const { isString: pIsString, ifString: pIfString } = StringExtensions.patches;
@@ -645,6 +649,7 @@ export const StringPrototypeExtensions = new Patch(String.prototype, {
645
649
  // Object<->Function<->Global occurs. See original source in global.this.js
646
650
  // {@see globalThis.isThenElse}
647
651
  function isThenElse(bv, tv, ev) {
652
+ function isFunction(value) { typeof value === 'function'; }
648
653
  if (arguments.length > 1) {
649
654
  var _then = isFunction(tv) ? tv(bv) : tv;
650
655
  if (arguments.length > 2) {