@nejs/basic-extensions 2.8.0 → 2.9.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/README.md +268 -147
- package/bin/version +100 -0
- package/dist/@nejs/basic-extensions.bundle.2.8.0.js +19 -0
- package/dist/@nejs/basic-extensions.bundle.2.8.0.js.map +7 -0
- package/dist/cjs/json.extensions.js +3 -2
- package/dist/cjs/json.extensions.js.map +1 -1
- package/dist/cjs/object.extensions.js +18 -6
- package/dist/cjs/object.extensions.js.map +1 -1
- package/dist/cjs/string.extensions.js +218 -28
- package/dist/cjs/string.extensions.js.map +1 -1
- package/dist/cjs/symbol.extensions.js +150 -29
- package/dist/cjs/symbol.extensions.js.map +1 -1
- package/dist/mjs/json.extensions.js +3 -2
- package/dist/mjs/json.extensions.js.map +1 -1
- package/dist/mjs/object.extensions.js +18 -6
- package/dist/mjs/object.extensions.js.map +1 -1
- package/dist/mjs/string.extensions.js +218 -28
- package/dist/mjs/string.extensions.js.map +1 -1
- package/dist/mjs/symbol.extensions.js +151 -30
- package/dist/mjs/symbol.extensions.js.map +1 -1
- package/docs/index.html +1045 -525
- package/package.json +4 -4
- package/src/json.extensions.js +3 -2
- package/src/object.extensions.js +21 -6
- package/src/string.extensions.js +259 -40
- package/src/symbol.extensions.js +151 -30
- package/dist/@nejs/basic-extensions.bundle.2.7.0.js +0 -19
- package/dist/@nejs/basic-extensions.bundle.2.7.0.js.map +0 -7
package/package.json
CHANGED
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"repl": "npm run build && node --no-warnings repl.bootstrap.js"
|
|
61
61
|
},
|
|
62
62
|
"type": "module",
|
|
63
|
-
"version": "2.
|
|
63
|
+
"version": "2.9.0",
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@nejs/extension": "^2.
|
|
65
|
+
"@nejs/extension": "^2.20.0",
|
|
66
66
|
"zod": "^3.22.5"
|
|
67
67
|
},
|
|
68
|
-
"browser": "dist/@nejs/basic-extensions.bundle.2.
|
|
69
|
-
}
|
|
68
|
+
"browser": "dist/@nejs/basic-extensions.bundle.2.9.0.js"
|
|
69
|
+
}
|
package/src/json.extensions.js
CHANGED
|
@@ -65,8 +65,9 @@ export const JSONExtensions = new Patch(JSON, {
|
|
|
65
65
|
* // Using `mightContain`
|
|
66
66
|
* console.log(JSON.mightContain(str)) // Output: true
|
|
67
67
|
*/
|
|
68
|
-
mightContain(string) {
|
|
69
|
-
|
|
68
|
+
mightContain(string, detail = false) {
|
|
69
|
+
const results = this.JSONStartPattern.exec(string)
|
|
70
|
+
return detail ? [!!results, results?.index ?? -1, results] : !!results
|
|
70
71
|
},
|
|
71
72
|
|
|
72
73
|
/**
|
package/src/object.extensions.js
CHANGED
|
@@ -181,18 +181,27 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
181
181
|
return Object.defineProperty(object, key, { ...properties, get, set })
|
|
182
182
|
},
|
|
183
183
|
|
|
184
|
+
addAccessor(to, key, getter, setter, storage) {
|
|
185
|
+
const store = storage ?? (!getter && !setter) ? true : undefined;
|
|
186
|
+
return this.add({ to, key, get: getter, set: setter, storage: store })
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
addData(to, key, value) {
|
|
190
|
+
return this.add({ to, key, value })
|
|
191
|
+
},
|
|
192
|
+
|
|
184
193
|
add(...args) {
|
|
185
194
|
const { isDescriptor } = Descriptor
|
|
186
195
|
const { isObject: isObj } = this
|
|
187
196
|
const { kDescriptorStore } = this
|
|
188
197
|
|
|
189
|
-
let
|
|
198
|
+
let obj, key, value, _get, _set, storage, storageKey
|
|
190
199
|
let _type, _flag, _desc
|
|
191
200
|
|
|
192
201
|
// Check to see if we received multiple arguments or an object
|
|
193
202
|
if (args.length && isObj(args[0])) {
|
|
194
203
|
({
|
|
195
|
-
|
|
204
|
+
to: obj,
|
|
196
205
|
key,
|
|
197
206
|
value,
|
|
198
207
|
get: _get,
|
|
@@ -206,7 +215,7 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
206
215
|
}
|
|
207
216
|
else if (args.length > 1) {
|
|
208
217
|
([
|
|
209
|
-
|
|
218
|
+
to,
|
|
210
219
|
_type,
|
|
211
220
|
key,
|
|
212
221
|
getOrValue,
|
|
@@ -217,6 +226,7 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
217
226
|
_desc,
|
|
218
227
|
] = args)
|
|
219
228
|
|
|
229
|
+
obj = to
|
|
220
230
|
_type = (
|
|
221
231
|
['accessor', 'data'].includes(_type.toLowerCase())
|
|
222
232
|
? _type.toLowerCase() : 'data'
|
|
@@ -225,6 +235,11 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
225
235
|
_value = _type === 'data' ? getOrValue : undefined
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
if (!this.isObject(obj)) {
|
|
239
|
+
console.warn('Object.add() must receive an object for `toObject`')
|
|
240
|
+
return obj;
|
|
241
|
+
}
|
|
242
|
+
|
|
228
243
|
const more = isDescriptor(_desc) ? _desc : {}
|
|
229
244
|
const flag = _flag || Object.definitionType.mutablyVisible
|
|
230
245
|
const props = { ...Patch.getDescriptorOverridesFromSymbol(flag), ...more }
|
|
@@ -250,7 +265,7 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
250
265
|
}
|
|
251
266
|
// store should be defined by here: object or undefined
|
|
252
267
|
|
|
253
|
-
if (!get && !set && makeStore) {
|
|
268
|
+
if ((!get && !set) && makeStore) {
|
|
254
269
|
// being lazy here, someone has defined we make an accessor but
|
|
255
270
|
// wants the default accessor behaviors with an associated store
|
|
256
271
|
// made by us.
|
|
@@ -261,11 +276,11 @@ export const ObjectExtensions = new Patch(Object, {
|
|
|
261
276
|
writable: true,
|
|
262
277
|
})
|
|
263
278
|
|
|
264
|
-
get = () => this[kDescriptorStore]
|
|
279
|
+
get = () => this[kDescriptorStore]?.data?.[storeKey]
|
|
265
280
|
set = (value) => { this[kDescriptorStore].data[storeKey] = value }
|
|
266
281
|
}
|
|
267
282
|
|
|
268
|
-
else if (get
|
|
283
|
+
else if (get?.length && set?.length > 1 && store) {
|
|
269
284
|
// if we received a get or set that takes more arguments than
|
|
270
285
|
// expected, assume the last argument should be the store variable
|
|
271
286
|
// so we execute the supplied function with the storage and its
|
package/src/string.extensions.js
CHANGED
|
@@ -273,68 +273,287 @@ export const StringExtensions = new Patch(String, {
|
|
|
273
273
|
return `rgba(${red}, ${green}, ${blue}, ${alpha.toFixed(2)})`
|
|
274
274
|
},
|
|
275
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Applies Select Graphic Rendition (SGR) parameters to a given message for
|
|
278
|
+
* styling in terminal environments. This function allows for the dynamic
|
|
279
|
+
* styling of text output using ANSI escape codes. It supports a variety of
|
|
280
|
+
* modes such as color, brightness, and text decorations like bold or underline.
|
|
281
|
+
*
|
|
282
|
+
* @param {string} message The message to be styled.
|
|
283
|
+
* @param {...string} useModes A series of strings representing the desired
|
|
284
|
+
* styling modes. Modes can include colors (e.g., 'red', 'blue'), brightness
|
|
285
|
+
* ('bright'), foreground/background ('fg', 'bg'), and text decorations
|
|
286
|
+
* ('bold', 'underline'). Modes can be combined in a single string using
|
|
287
|
+
* commas or passed as separate arguments.
|
|
288
|
+
*
|
|
289
|
+
* Colors:
|
|
290
|
+
* ```
|
|
291
|
+
* 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
|
|
292
|
+
* ```
|
|
293
|
+
* Color Specifiers:
|
|
294
|
+
* ```
|
|
295
|
+
* 'fg' -> foreground | 'bg' -> background | 'bright' -> bright colors
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* Modes:
|
|
299
|
+
* ```
|
|
300
|
+
* 'blink' or 'k' | 'conceal' or 'c' | 'italics' or 'i' | 'strike' or 's'
|
|
301
|
+
* 'bold' or 'b' | 'dim' or 'd' | 'negative' or 'n' | 'underline' or 'u'
|
|
302
|
+
* ```
|
|
303
|
+
*
|
|
304
|
+
* Examples:
|
|
305
|
+
* - `sgr('Hello', 'red')` applies red color to 'Hello'.
|
|
306
|
+
* - `sgr('World', 'green,bold')` applies green color and bold styling
|
|
307
|
+
* to 'World'.
|
|
308
|
+
* - `sgr('Example', 'bluebgbright')` applies bright blue
|
|
309
|
+
* background color.
|
|
310
|
+
*
|
|
311
|
+
* Short hand syntax is also allowed:
|
|
312
|
+
* - `sgr('hello', 'biu')` applies bold, italics and underline
|
|
313
|
+
* - `sgr('hello', 'bi,redfg')` applies bold, italics and red foreground
|
|
314
|
+
*
|
|
315
|
+
* As a bonus, there is a secret getter applied to the return string that
|
|
316
|
+
* allows you to invoke `sgr(...).show` to automatically log the output to
|
|
317
|
+
* `console.log`. This is done by wrapping the output string in `Object()`
|
|
318
|
+
* to make it a `String` instance and then adding the property descriptor.
|
|
319
|
+
* A custom `Symbol` is applied to make it evaluate in nodejs as though it
|
|
320
|
+
* were a normal string. To strip the extras, wrap the output in `String()`
|
|
321
|
+
*
|
|
322
|
+
* @returns {string} The message wrapped in ANSI escape codes corresponding
|
|
323
|
+
* to the specified modes. The returned string, when printed to a terminal,
|
|
324
|
+
* displays the styled message. Additional properties are attached to the
|
|
325
|
+
* result for utility purposes, such as 'show' for immediate console output.
|
|
326
|
+
*/
|
|
327
|
+
sgr(message, ...useModes) {
|
|
328
|
+
const colors = Object.assign(
|
|
329
|
+
['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'],
|
|
330
|
+
{
|
|
331
|
+
isBG: a => !!/bg/i.exec(a),
|
|
332
|
+
isBright: a => !!/bright/i.exec(a),
|
|
333
|
+
isColor: a => {
|
|
334
|
+
let color = colors.find(c => new RegExp(c, 'i').exec(a));
|
|
335
|
+
return [!!color, colors.indexOf(color)];
|
|
336
|
+
},
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
const arrayifyString = s => {
|
|
341
|
+
if (Array.isArray(s)) {
|
|
342
|
+
let results = [];
|
|
343
|
+
|
|
344
|
+
for (const i of s) {
|
|
345
|
+
results = [ ...results, ...arrayifyString(i) ];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return results.flat().filter(i => i.length);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!s || typeof s !== 'string') {
|
|
352
|
+
return [''];
|
|
353
|
+
}
|
|
354
|
+
else if (s.includes(',')) {
|
|
355
|
+
return arrayifyString(s.split(','));
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
if (!colors.isColor(s)[0] && s.length > 1) {
|
|
359
|
+
return [...s];
|
|
360
|
+
}
|
|
361
|
+
else return [s];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
let modes = arrayifyString(useModes)
|
|
366
|
+
|
|
367
|
+
const sgrModes = {
|
|
368
|
+
blink: ['\x1b[5m', '\x1b[25m', 'k'],
|
|
369
|
+
bold: ['\x1b[1m', '\x1b[22m', 'b'],
|
|
370
|
+
conceal: ['\x1b[8m', '\x1b[28m', 'c'],
|
|
371
|
+
dim: ['\x1b[2m', '\x1b[22m', 'd'],
|
|
372
|
+
italics: ['\x1b[3m', '\x1b[23m', 'i'],
|
|
373
|
+
negative: ['\x1b[7m', '\x1b[27m', 'n'],
|
|
374
|
+
strike: ['\x1b[9m', '\x1b[29m', 's'],
|
|
375
|
+
underline: ['\x1b[4m', '\x1b[24m', 'u'],
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
Object.values(sgrModes).forEach(mode => sgrModes[mode[2]] = mode);
|
|
379
|
+
|
|
380
|
+
const codes = a => {
|
|
381
|
+
let open = '', close = '', mode = String(a).toLowerCase();
|
|
382
|
+
let [_isColor, colorIndex] = colors.isColor(mode);
|
|
383
|
+
|
|
384
|
+
if (_isColor) {
|
|
385
|
+
open = colors.isBG(mode)
|
|
386
|
+
? `\x1b[${colors.isBright(mode) ? 10 : 4}${colorIndex}m`
|
|
387
|
+
: `\x1b[${colors.isBright(mode) ? 9 : 3}${colorIndex}m`;
|
|
388
|
+
close = colors.isBG(mode) ? '\x1b[49m' : `\x1b[39m`;
|
|
389
|
+
}
|
|
390
|
+
else if (sgrModes[mode]) {
|
|
391
|
+
open = sgrModes[mode][0];
|
|
392
|
+
close = sgrModes[mode][1];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return [open, close];
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const onOrder = modes.map(key => codes(key)[0]).join('');
|
|
399
|
+
const offOrder = modes.map(key => codes(key)[1]).reverse().join('');
|
|
400
|
+
|
|
401
|
+
let result = Object(`${onOrder}${message}${offOrder}`)
|
|
402
|
+
|
|
403
|
+
Object.defineProperties(result, {
|
|
404
|
+
show: {
|
|
405
|
+
get() { console.log(String(this)); return this },
|
|
406
|
+
enumerable: false,
|
|
407
|
+
},
|
|
408
|
+
[Symbol.for('nodejs.util.inspect.custom')]: {
|
|
409
|
+
value(depth, options, inspect) {
|
|
410
|
+
return inspect(String(this), options)
|
|
411
|
+
},
|
|
412
|
+
enumerable: false,
|
|
413
|
+
},
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
return result
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Wraps an object's properties into a formatted string.
|
|
421
|
+
*
|
|
422
|
+
* This method takes an object and a set of options to format the
|
|
423
|
+
* object's properties into a string. It allows customization of
|
|
424
|
+
* indentation, line endings, maximum line length, and more.
|
|
425
|
+
*
|
|
426
|
+
* @param {Object} [object=globalThis] - The object to wrap.
|
|
427
|
+
* @param {Object} [options={}] - The formatting options.
|
|
428
|
+
* @param {number} [options.indent=2] - The number of indentation
|
|
429
|
+
* characters to use.
|
|
430
|
+
* @param {string} [options.indentCharacter=' '] - The character to use
|
|
431
|
+
* for indentation.
|
|
432
|
+
* @param {Array} [options.inspector=[Object, 'getOwnPropertyNames']] -
|
|
433
|
+
* The inspector to use for retrieving object properties.
|
|
434
|
+
* @param {string} [options.lineEnding='\n'] - The line ending character.
|
|
435
|
+
* @param {number} [options.maxLen=78] - The maximum line length.
|
|
436
|
+
* @param {Function} [options.perLine=undefined] - A function to apply
|
|
437
|
+
* per line of output.
|
|
438
|
+
* @param {Function} [options.perLinePerProperty=undefined] - A function
|
|
439
|
+
* to apply per property per line of output.
|
|
440
|
+
* @param {Function} [options.preProcess=undefined] - A function to
|
|
441
|
+
* preprocess the object's properties.
|
|
442
|
+
* @param {Function} [options.preReturn=undefined] - A function to apply
|
|
443
|
+
* to the final output before returning.
|
|
444
|
+
* @param {string} [options.separator=', '] - The separator to use
|
|
445
|
+
* between properties.
|
|
446
|
+
*
|
|
447
|
+
* @returns {string} The formatted string representation of the object.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* const obj = { a: 1, b: 2, c: 3 }
|
|
451
|
+
* const wrapped = StringExtensions.wrap(obj, { maxLen: 20 })
|
|
452
|
+
* console.log(wrapped)
|
|
453
|
+
* // Output:
|
|
454
|
+
* // {
|
|
455
|
+
* // a: 1,
|
|
456
|
+
* // b: 2,
|
|
457
|
+
* // c: 3
|
|
458
|
+
* // }
|
|
459
|
+
*/
|
|
276
460
|
wrap(
|
|
277
|
-
|
|
461
|
+
objectOrLines,
|
|
278
462
|
options = {
|
|
463
|
+
colorProperties: undefined,
|
|
279
464
|
indent: 2,
|
|
280
|
-
separator: ', ',
|
|
281
465
|
indentCharacter: ' ',
|
|
282
|
-
lineEnding: '\n',
|
|
283
466
|
inspector: [Object, 'getOwnPropertyNames'],
|
|
284
|
-
|
|
285
|
-
|
|
467
|
+
lineEnding: '\n',
|
|
468
|
+
maxLen: 78,
|
|
469
|
+
perLine: undefined,
|
|
470
|
+
perLinePerProperty: undefined,
|
|
471
|
+
preProcess: undefined,
|
|
472
|
+
preReturn: undefined,
|
|
473
|
+
separator: ', ',
|
|
286
474
|
}
|
|
287
475
|
) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
indentCharacter = ' ',
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
476
|
+
let {
|
|
477
|
+
colorProperties = undefined,
|
|
478
|
+
indent = options?.indent ?? 2,
|
|
479
|
+
indentCharacter = options?.indentCharacter ?? ' ',
|
|
480
|
+
inspector = options?.inspector ?? [Object, 'getOwnPropertyNames'],
|
|
481
|
+
lineEnding = options?.lineEnding ?? '\n',
|
|
482
|
+
maxLen = options?.maxLen ?? 78,
|
|
483
|
+
perLine = options?.perLine ?? undefined,
|
|
484
|
+
perLinePerProperty = options?.perLinePerProperty ?? undefined,
|
|
485
|
+
preProcess = options?.preProcess ?? undefined,
|
|
486
|
+
preReturn = options?.preReturn ?? undefined,
|
|
487
|
+
separator = options?.separator ?? ', ',
|
|
296
488
|
} = options ?? {}
|
|
297
489
|
|
|
298
|
-
let tab = indent === 0 ? ''
|
|
299
|
-
|
|
300
|
-
|
|
490
|
+
let tab = indent === 0 ? ''
|
|
491
|
+
: indentCharacter.repeat(Number(indent) || 2)
|
|
492
|
+
maxLen = 78 - tab.length
|
|
493
|
+
|
|
494
|
+
const sgr = this.sgr;
|
|
495
|
+
const validMapper = f => typeof f === 'function'
|
|
496
|
+
|
|
497
|
+
let line = []
|
|
301
498
|
let getElements = inspector[0][inspector[1]]
|
|
302
|
-
let values = Array.isArray(
|
|
499
|
+
let values = Array.isArray(objectOrLines)
|
|
500
|
+
? objectOrLines : getElements(Object(objectOrLines))
|
|
303
501
|
|
|
304
|
-
if (
|
|
305
|
-
values = values
|
|
502
|
+
if (validMapper(preProcess)) {
|
|
503
|
+
values = preProcess(values)
|
|
306
504
|
}
|
|
307
505
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
].join('').trim();
|
|
506
|
+
const context = { indent, indentCharacter, lineEnding, maxLen, tab, sgr }
|
|
507
|
+
|
|
508
|
+
let finalLines = values.reduce((acc, nextProp) => {
|
|
509
|
+
let ifCombined = [...line, nextProp].join(separator)
|
|
313
510
|
|
|
314
|
-
if (ifCombined.length
|
|
315
|
-
line.push(
|
|
511
|
+
if ((tab.length + ifCombined.length) <= maxLen) {
|
|
512
|
+
line.push(nextProp)
|
|
316
513
|
}
|
|
514
|
+
|
|
317
515
|
else {
|
|
516
|
+
let lineProps = [...line]
|
|
517
|
+
|
|
518
|
+
if (validMapper(perLinePerProperty)) {
|
|
519
|
+
lineProps = lineProps.map((value, index, array) => {
|
|
520
|
+
return perLinePerProperty(value, index, array, context)
|
|
521
|
+
})
|
|
522
|
+
}
|
|
318
523
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
524
|
+
if (colorProperties) {
|
|
525
|
+
const sgrArgs = (Array.isArray(colorProperties)
|
|
526
|
+
? colorProperties
|
|
527
|
+
: [colorProperties]
|
|
528
|
+
)
|
|
529
|
+
lineProps = lineProps.map(v => sgr(v, ...sgrArgs))
|
|
323
530
|
}
|
|
324
531
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
532
|
+
lineProps = [tab, lineProps.join(separator)].join('')
|
|
533
|
+
if (validMapper(perLine)) {
|
|
534
|
+
lineProps = perLine(lineProps[0], 0, lineProps)?.[0] ?? lineProps[0]
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
acc.push(lineProps)
|
|
538
|
+
line = []
|
|
539
|
+
}
|
|
330
540
|
|
|
331
|
-
|
|
541
|
+
return acc
|
|
542
|
+
}, [])
|
|
332
543
|
|
|
333
|
-
|
|
334
|
-
|
|
544
|
+
if (validMapper(preReturn)) {
|
|
545
|
+
finalLines = finalLines.map((value, index, array) => {
|
|
546
|
+
return preReturn(value, index, array, context)
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
Symbol.for(`@nejs.string.wrap ${JSON.stringify({lines: finalLines})}`)
|
|
551
|
+
|
|
552
|
+
if (lineEnding) {
|
|
553
|
+
finalLines = finalLines.join(lineEnding)
|
|
554
|
+
}
|
|
335
555
|
|
|
336
|
-
|
|
337
|
-
}, []).join(lineEnding)
|
|
556
|
+
return finalLines
|
|
338
557
|
},
|
|
339
558
|
});
|
|
340
559
|
|
package/src/symbol.extensions.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Patch } from '@nejs/extension';
|
|
1
|
+
import { Patch, PatchToggle } from '@nejs/extension';
|
|
2
2
|
|
|
3
3
|
import { Symkeys } from './classes/symkeys.js'
|
|
4
4
|
import { JSONExtensions } from './json.extensions.js'
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const JSONToggle = new PatchToggle(JSONExtensions)
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* `SymbolExtensions` is a patch for the JavaScript built-in `Symbol` class. It
|
|
@@ -14,31 +14,16 @@ const { extractFrom, mightContain } = JSONExtensions.patches
|
|
|
14
14
|
* utility functions.
|
|
15
15
|
*/
|
|
16
16
|
export const SymbolExtensions = new Patch(Symbol, {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* const symbolWithData = Symbol.withData('mySymbol', { foo: 'bar' })
|
|
30
|
-
* console.log(symbolWithData.toString())
|
|
31
|
-
* // Output: "Symbol(mySymbol {"foo":"bar"})"
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* const symbolWithoutData = Symbol.withData('mySymbol')
|
|
35
|
-
* console.log(symbolWithoutData.toString())
|
|
36
|
-
* // Output: "Symbol(mySymbol)"
|
|
37
|
-
*/
|
|
38
|
-
withData(name, data) {
|
|
39
|
-
return data !== undefined
|
|
40
|
-
? Symbol.for(`${name} ${JSON.stringify(data)}`)
|
|
41
|
-
: Symbol.for(name)
|
|
17
|
+
add(named, associatedData = {}) {
|
|
18
|
+
return this.keys.add(named, associatedData)
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
deleteData(forSymbol, replaceWith = undefined) {
|
|
22
|
+
return this.keys.deleteData(forSymbol, replaceWith)
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
hasData(forSymbol) {
|
|
26
|
+
return this.keys.hasData(forSymbol)
|
|
42
27
|
},
|
|
43
28
|
|
|
44
29
|
/**
|
|
@@ -125,6 +110,37 @@ export const SymbolExtensions = new Patch(Symbol, {
|
|
|
125
110
|
* kOriginal.data = [Object.prototype, Array.prototype] // ...both work
|
|
126
111
|
*/
|
|
127
112
|
keys: new Symkeys('nejs'),
|
|
113
|
+
|
|
114
|
+
setData(forSymbol, value) {
|
|
115
|
+
this.keys.setData(forSymbol, value)
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a new Symbol with the given name and optional data. If data
|
|
120
|
+
* is provided, it will be stringified and appended to the symbol's
|
|
121
|
+
* name. This method is useful for creating unique symbols that carry
|
|
122
|
+
* additional metadata.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} name The name of the symbol.
|
|
125
|
+
* @param {*} [data] Optional data to be associated with the symbol.
|
|
126
|
+
* @returns {symbol} A new symbol created with Symbol.for(), using the
|
|
127
|
+
* provided name and stringified data (if provided).
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const symbolWithData = Symbol.withData('mySymbol', { foo: 'bar' })
|
|
131
|
+
* console.log(symbolWithData.toString())
|
|
132
|
+
* // Output: "Symbol(mySymbol {"foo":"bar"})"
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* const symbolWithoutData = Symbol.withData('mySymbol')
|
|
136
|
+
* console.log(symbolWithoutData.toString())
|
|
137
|
+
* // Output: "Symbol(mySymbol)"
|
|
138
|
+
*/
|
|
139
|
+
withData(name, data) {
|
|
140
|
+
return data !== undefined
|
|
141
|
+
? Symbol.for(`${name} ${JSON.stringify(data)}`)
|
|
142
|
+
: Symbol.for(name)
|
|
143
|
+
},
|
|
128
144
|
});
|
|
129
145
|
|
|
130
146
|
export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
|
|
@@ -195,7 +211,23 @@ export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
|
|
|
195
211
|
}
|
|
196
212
|
}
|
|
197
213
|
|
|
198
|
-
|
|
214
|
+
let result = undefined;
|
|
215
|
+
let revertToggle = false
|
|
216
|
+
if (!JSONExtensions.applied) {
|
|
217
|
+
JSONToggle.start()
|
|
218
|
+
revertToggle = true
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (JSON.mightContain(this.description)) {
|
|
222
|
+
try { result = JSON.extractFrom(this.description) }
|
|
223
|
+
catch (ignore) { }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (revertToggle) {
|
|
227
|
+
JSONToggle.stop()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return result
|
|
199
231
|
},
|
|
200
232
|
|
|
201
233
|
/**
|
|
@@ -262,7 +294,96 @@ export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
|
|
|
262
294
|
* console.log(sym.mightHaveEmbeddedJSON) // Output: false
|
|
263
295
|
*/
|
|
264
296
|
get mightHaveEmbeddedJSON() {
|
|
265
|
-
return mightContain(this.description)
|
|
297
|
+
return mightContain(this.description)
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
get sgrString() {
|
|
301
|
+
let revert = false
|
|
302
|
+
let detail = undefined
|
|
303
|
+
|
|
304
|
+
let { sgr } = String
|
|
305
|
+
if (!sgr) { sgr = (string, ...args) => string }
|
|
306
|
+
|
|
307
|
+
if (!JSONExtensions.applied) { JSONToggle.start(); revert = true }
|
|
308
|
+
if ((detail = JSON.mightContain(this.description, true))) {
|
|
309
|
+
let jsonText = detail[2][0]
|
|
310
|
+
let index = detail[1]
|
|
311
|
+
|
|
312
|
+
if (~index && jsonText && jsonText.length > 30) {
|
|
313
|
+
let desc = this.description
|
|
314
|
+
let newDescription = [
|
|
315
|
+
sgr(`Symbol.for(${desc.slice(0, index)}`, 'green'),
|
|
316
|
+
sgr(jsonText.slice(0, 10), 'di'),
|
|
317
|
+
'...',
|
|
318
|
+
sgr(jsonText.slice(-5), 'di'),
|
|
319
|
+
sgr(`${desc.slice(index + jsonText.length + 1)})`, 'green'),
|
|
320
|
+
].join('')
|
|
321
|
+
|
|
322
|
+
if (revert) { JSONToggle.stop() }
|
|
323
|
+
return `${newDescription}`
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (revert) { JSONToggle.stop() }
|
|
328
|
+
|
|
329
|
+
return newDescription
|
|
266
330
|
},
|
|
267
|
-
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Custom inspect method for Node.js util.inspect.
|
|
334
|
+
*
|
|
335
|
+
* NOTE: this will only apply if looking at an instance of Symbol,
|
|
336
|
+
* sadly; {@see SymbolPrototypeExtensions.instance}
|
|
337
|
+
*
|
|
338
|
+
* This method is used by Node.js util.inspect to provide a custom
|
|
339
|
+
* representation of the symbol when inspected. It checks if the
|
|
340
|
+
* symbol's description might contain JSON data and if so, it
|
|
341
|
+
* truncates the JSON data in the description to a maximum of 30
|
|
342
|
+
* characters and formats the output with colors using the `sgr`
|
|
343
|
+
* function from the `String` object.
|
|
344
|
+
*
|
|
345
|
+
* @param {number} depth - The current depth of the recursive
|
|
346
|
+
* inspection.
|
|
347
|
+
* @param {Object} options - The options object passed to
|
|
348
|
+
* util.inspect.
|
|
349
|
+
* @param {Function} inspect - The original util.inspect function.
|
|
350
|
+
*
|
|
351
|
+
* @returns {string} - The formatted representation of the symbol.
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* const sym = Symbol.for('fun {"name":"John Doe"}')
|
|
355
|
+
* console.log(util.inspect(sym))
|
|
356
|
+
* // Output: Symbol.for(fun {"name":"John ...hn Doe"})
|
|
357
|
+
*/
|
|
358
|
+
[Symbol.for('nodejs.util.inspect.custom')](depth, options, inspect) {
|
|
359
|
+
let revert = false
|
|
360
|
+
let detail = undefined
|
|
361
|
+
|
|
362
|
+
let { sgr } = String
|
|
363
|
+
if (!sgr) { sgr = (string, ...args) => string }
|
|
364
|
+
|
|
365
|
+
if (!JSONExtensions.applied) { JSONToggle.start(); revert = true }
|
|
366
|
+
if ((detail = JSON.mightContain(this.description, true))) {
|
|
367
|
+
let jsonText = detail[2][0]
|
|
368
|
+
let index = detail[1]
|
|
369
|
+
|
|
370
|
+
if (~index && jsonText && jsonText.length > 30) {
|
|
371
|
+
let desc = this.description
|
|
372
|
+
let newDescription = [
|
|
373
|
+
sgr(`Symbol.for(${desc.slice(0, index)}`, 'green'),
|
|
374
|
+
sgr(jsonText.slice(0, 10), 'di'),
|
|
375
|
+
'...',
|
|
376
|
+
sgr(jsonText.slice(-5), 'di'),
|
|
377
|
+
sgr(`${desc.slice(index + jsonText.length + 1)})`, 'green'),
|
|
378
|
+
].join('')
|
|
379
|
+
|
|
380
|
+
if (revert) { JSONToggle.stop() }
|
|
381
|
+
return `${newDescription}`
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (revert) { JSONToggle.stop() }
|
|
386
|
+
return inspect(this, { colors: true })
|
|
387
|
+
},
|
|
388
|
+
},
|
|
268
389
|
})
|