@nejs/basic-extensions 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +268 -147
  2. package/bin/version +100 -0
  3. package/dist/@nejs/basic-extensions.bundle.2.10.0.js +19 -0
  4. package/dist/@nejs/basic-extensions.bundle.2.10.0.js.map +7 -0
  5. package/dist/cjs/array.extensions.js +174 -0
  6. package/dist/cjs/array.extensions.js.map +1 -1
  7. package/dist/cjs/big.int.extension.js +1 -0
  8. package/dist/cjs/big.int.extension.js.map +1 -1
  9. package/dist/cjs/classes/descriptor.js +1 -1
  10. package/dist/cjs/classes/descriptor.js.map +1 -1
  11. package/dist/cjs/classes/index.d.ts +1 -0
  12. package/dist/cjs/classes/index.js +3 -0
  13. package/dist/cjs/classes/index.js.map +1 -1
  14. package/dist/cjs/classes/iterable.d.ts +44 -0
  15. package/dist/cjs/classes/iterable.js +64 -0
  16. package/dist/cjs/classes/iterable.js.map +1 -1
  17. package/dist/cjs/classes/param.parser.d.ts +10 -10
  18. package/dist/cjs/classes/property.d.ts +86 -0
  19. package/dist/cjs/classes/property.js +284 -0
  20. package/dist/cjs/classes/property.js.map +1 -0
  21. package/dist/cjs/classes/symkeys.d.ts +68 -11
  22. package/dist/cjs/classes/symkeys.js +103 -17
  23. package/dist/cjs/classes/symkeys.js.map +1 -1
  24. package/dist/cjs/classes/type.d.ts +4 -4
  25. package/dist/cjs/function.extensions.js +1 -0
  26. package/dist/cjs/function.extensions.js.map +1 -1
  27. package/dist/cjs/global.this.js +29 -0
  28. package/dist/cjs/global.this.js.map +1 -1
  29. package/dist/cjs/index.d.ts +2 -0
  30. package/dist/cjs/index.js +18 -0
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/json.extensions.js +22 -20
  33. package/dist/cjs/json.extensions.js.map +1 -1
  34. package/dist/cjs/map.extensions.js +1 -0
  35. package/dist/cjs/map.extensions.js.map +1 -1
  36. package/dist/cjs/number.extension.js +1 -0
  37. package/dist/cjs/number.extension.js.map +1 -1
  38. package/dist/cjs/object.extensions.d.ts +0 -29
  39. package/dist/cjs/object.extensions.js +218 -243
  40. package/dist/cjs/object.extensions.js.map +1 -1
  41. package/dist/cjs/set.extensions.js +1 -0
  42. package/dist/cjs/set.extensions.js.map +1 -1
  43. package/dist/cjs/string.extensions.js +478 -283
  44. package/dist/cjs/string.extensions.js.map +1 -1
  45. package/dist/cjs/symbol.extensions.js +500 -24
  46. package/dist/cjs/symbol.extensions.js.map +1 -1
  47. package/dist/cjs/utils/copy.object.d.ts +408 -0
  48. package/dist/cjs/utils/copy.object.js +720 -0
  49. package/dist/cjs/utils/copy.object.js.map +1 -0
  50. package/dist/cjs/utils/index.d.ts +1 -0
  51. package/dist/cjs/utils/index.js +19 -0
  52. package/dist/cjs/utils/index.js.map +1 -0
  53. package/dist/cjs/utils/toolkit.d.ts +1897 -0
  54. package/dist/cjs/utils/toolkit.js +1377 -0
  55. package/dist/cjs/utils/toolkit.js.map +1 -0
  56. package/dist/mjs/array.extensions.js +174 -0
  57. package/dist/mjs/array.extensions.js.map +1 -1
  58. package/dist/mjs/big.int.extension.js +1 -0
  59. package/dist/mjs/big.int.extension.js.map +1 -1
  60. package/dist/mjs/classes/descriptor.js +1 -1
  61. package/dist/mjs/classes/descriptor.js.map +1 -1
  62. package/dist/mjs/classes/index.d.ts +1 -0
  63. package/dist/mjs/classes/index.js +3 -0
  64. package/dist/mjs/classes/index.js.map +1 -1
  65. package/dist/mjs/classes/iterable.d.ts +44 -0
  66. package/dist/mjs/classes/iterable.js +64 -0
  67. package/dist/mjs/classes/iterable.js.map +1 -1
  68. package/dist/mjs/classes/param.parser.d.ts +10 -10
  69. package/dist/mjs/classes/property.d.ts +86 -0
  70. package/dist/mjs/classes/property.js +280 -0
  71. package/dist/mjs/classes/property.js.map +1 -0
  72. package/dist/mjs/classes/symkeys.d.ts +68 -11
  73. package/dist/mjs/classes/symkeys.js +103 -17
  74. package/dist/mjs/classes/symkeys.js.map +1 -1
  75. package/dist/mjs/classes/type.d.ts +4 -4
  76. package/dist/mjs/function.extensions.js +1 -0
  77. package/dist/mjs/function.extensions.js.map +1 -1
  78. package/dist/mjs/global.this.js +6 -0
  79. package/dist/mjs/global.this.js.map +1 -1
  80. package/dist/mjs/index.d.ts +2 -0
  81. package/dist/mjs/index.js +4 -0
  82. package/dist/mjs/index.js.map +1 -1
  83. package/dist/mjs/json.extensions.js +22 -20
  84. package/dist/mjs/json.extensions.js.map +1 -1
  85. package/dist/mjs/map.extensions.js +1 -0
  86. package/dist/mjs/map.extensions.js.map +1 -1
  87. package/dist/mjs/number.extension.js +1 -0
  88. package/dist/mjs/number.extension.js.map +1 -1
  89. package/dist/mjs/object.extensions.d.ts +0 -29
  90. package/dist/mjs/object.extensions.js +215 -239
  91. package/dist/mjs/object.extensions.js.map +1 -1
  92. package/dist/mjs/set.extensions.js +1 -0
  93. package/dist/mjs/set.extensions.js.map +1 -1
  94. package/dist/mjs/string.extensions.js +478 -283
  95. package/dist/mjs/string.extensions.js.map +1 -1
  96. package/dist/mjs/symbol.extensions.js +501 -25
  97. package/dist/mjs/symbol.extensions.js.map +1 -1
  98. package/dist/mjs/utils/copy.object.d.ts +408 -0
  99. package/dist/mjs/utils/copy.object.js +702 -0
  100. package/dist/mjs/utils/copy.object.js.map +1 -0
  101. package/dist/mjs/utils/index.d.ts +1 -0
  102. package/dist/mjs/utils/index.js +3 -0
  103. package/dist/mjs/utils/index.js.map +1 -0
  104. package/dist/mjs/utils/toolkit.d.ts +1897 -0
  105. package/dist/mjs/utils/toolkit.js +1372 -0
  106. package/dist/mjs/utils/toolkit.js.map +1 -0
  107. package/package.json +30 -38
  108. package/repl.bootstrap.js +12 -1
  109. package/src/array.extensions.js +191 -1
  110. package/src/big.int.extension.js +3 -1
  111. package/src/classes/descriptor.js +1 -1
  112. package/src/classes/index.js +4 -0
  113. package/src/classes/iterable.js +74 -0
  114. package/src/classes/property.js +333 -0
  115. package/src/classes/symkeys.js +120 -19
  116. package/src/function.extensions.js +2 -0
  117. package/src/global.this.js +8 -0
  118. package/src/index.js +5 -0
  119. package/src/json.extensions.js +21 -21
  120. package/src/map.extensions.js +3 -1
  121. package/src/number.extension.js +3 -1
  122. package/src/object.extensions.js +240 -262
  123. package/src/set.extensions.js +3 -1
  124. package/src/string.extensions.js +531 -306
  125. package/src/symbol.extensions.js +529 -25
  126. package/src/utils/copy.object.js +780 -0
  127. package/src/utils/index.js +2 -0
  128. package/src/utils/toolkit.js +1471 -0
  129. package/tests/arrayextensions.test.js +2 -0
  130. package/tests/index.test.js +1 -0
  131. package/tests/newClasses/asyncIterable.test.js +2 -0
  132. package/tests/newClasses/deferred.test.js +5 -3
  133. package/tests/newClasses/descriptor.test.js +2 -0
  134. package/tests/newClasses/iterable.test.js +2 -0
  135. package/tests/newClasses/refmap.test.js +2 -1
  136. package/tests/newClasses/refset.test.js +2 -0
  137. package/tests/objectextensions.test.js +2 -0
  138. package/tests/setextensions.test.js +2 -0
  139. package/tests/stringextensions.test.js +1 -0
  140. package/tests/utils/toolkit.test.js +223 -0
  141. package/tsconfig.base.json +1 -1
  142. package/vitest.config.js +7 -0
  143. package/dist/@nejs/basic-extensions.bundle.2.7.0.js +0 -19
  144. package/dist/@nejs/basic-extensions.bundle.2.7.0.js.map +0 -7
  145. package/docs/assets/anchor.js +0 -350
  146. package/docs/assets/bass-addons.css +0 -12
  147. package/docs/assets/bass.css +0 -544
  148. package/docs/assets/fonts/EOT/SourceCodePro-Bold.eot +0 -0
  149. package/docs/assets/fonts/EOT/SourceCodePro-Regular.eot +0 -0
  150. package/docs/assets/fonts/LICENSE.txt +0 -93
  151. package/docs/assets/fonts/OTF/SourceCodePro-Bold.otf +0 -0
  152. package/docs/assets/fonts/OTF/SourceCodePro-Regular.otf +0 -0
  153. package/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf +0 -0
  154. package/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf +0 -0
  155. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff +0 -0
  156. package/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff +0 -0
  157. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff +0 -0
  158. package/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff +0 -0
  159. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 +0 -0
  160. package/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 +0 -0
  161. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 +0 -0
  162. package/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 +0 -0
  163. package/docs/assets/fonts/source-code-pro.css +0 -23
  164. package/docs/assets/github.css +0 -123
  165. package/docs/assets/site.js +0 -168
  166. package/docs/assets/split.css +0 -15
  167. package/docs/assets/split.js +0 -782
  168. package/docs/assets/style.css +0 -147
  169. package/docs/index.html +0 -34965
@@ -1,9 +1,10 @@
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 { extractFrom, mightContain } = JSONExtensions.patches
6
+ const JSONToggle = new PatchToggle(JSONExtensions)
7
+ const symkeys = new Symkeys('nejs')
7
8
 
8
9
  /**
9
10
  * `SymbolExtensions` is a patch for the JavaScript built-in `Symbol` class. It
@@ -15,30 +16,160 @@ const { extractFrom, mightContain } = JSONExtensions.patches
15
16
  */
16
17
  export const SymbolExtensions = new Patch(Symbol, {
17
18
  /**
18
- * Creates a new Symbol with the given name and optional data. If data
19
- * is provided, it will be stringified and appended to the symbol's
20
- * name. This method is useful for creating unique symbols that carry
21
- * additional metadata.
19
+ * Adds a new symbol to the Symkeys instance with the given name and
20
+ * associated data.
22
21
  *
23
- * @param {string} name The name of the symbol.
24
- * @param {*} [data] Optional data to be associated with the symbol.
25
- * @returns {symbol} A new symbol created with Symbol.for(), using the
26
- * provided name and stringified data (if provided).
22
+ * This method generates a unique symbol based on the provided name,
23
+ * optional domain, separator, and token. It also allows embedding
24
+ * additional data into the symbol's name.
25
+ *
26
+ * @param {string} named - The base name for the new symbol.
27
+ * @param {Object} options - Additional options for the symbol.
28
+ * @param {*} [options.associate={}] - Data to associate with the symbol.
29
+ * @param {Object} [options.embed] - Optional data to embed in the symbol.
30
+ * @param {string} [options.useDomain] - Optional domain to include in the
31
+ * symbol's name.
32
+ * @param {string} [options.useSeparator] - Optional separator to use in
33
+ * the symbol's name.
34
+ * @param {string} [options.useToken] - Optional token to use for the
35
+ * symbol. If not provided, a random token is generated.
36
+ * @returns {Symbol} The newly created symbol.
27
37
  *
28
38
  * @example
29
- * const symbolWithData = Symbol.withData('mySymbol', { foo: 'bar' })
30
- * console.log(symbolWithData.toString())
31
- * // Output: "Symbol(mySymbol {"foo":"bar"})"
39
+ * // Add a symbol with associated data
40
+ * const mySymbol = SymbolExtensions.add('myIdentifier', {
41
+ * associate: { foo: 'bar' },
42
+ * embed: { baz: 'qux' },
43
+ * useDomain: 'exampleDomain',
44
+ * useSeparator: '-',
45
+ * useToken: 'customToken',
46
+ * })
47
+ * console.log(mySymbol)
48
+ * // Symbol(@exampleDomain-myIdentifier {"baz":"qux"} #customToken)
49
+ */
50
+ add(named, { associate = {}, embed, useToken, useDomain, useSeparator }) {
51
+ return this.keys.add(named, {
52
+ associate, embed, useToken, useDomain, useSeparator,
53
+ })
54
+ },
55
+
56
+ /**
57
+ * Deletes the data associated with a given symbol from the Symkeys
58
+ * instance.
59
+ *
60
+ * This method allows removal of the data that has been associated with a
61
+ * particular symbol in the Symkeys instance. It is useful when you want
62
+ * to clean up or remove stored information associated with a symbol.
63
+ *
64
+ * @param {Symbol} forSymbol - The symbol whose associated data is to be
65
+ * deleted.
66
+ * @param {*} [replaceWith=undefined] - Optionally, if `replaceWith` is
67
+ * not `undefined`, a new value can be set after the original is deleted
68
+ * @returns {boolean} - Returns true if an element in the Symkeys existed
69
+ * and has been removed, or false if the element does not exist
32
70
  *
33
71
  * @example
34
- * const symbolWithoutData = Symbol.withData('mySymbol')
35
- * console.log(symbolWithoutData.toString())
36
- * // Output: "Symbol(mySymbol)"
72
+ * // Assuming 'mySymbol' is a symbol that has been added to the Symkeys
73
+ * // with associated data
74
+ * const isDeleted = Symbol.deleteData(mySymbol)
75
+ * console.log(isDeleted) // Output: true if data was deleted, false
76
+ *
77
+ * @example
78
+ * // Deleting data and replacing it with a new value
79
+ * const mySymbol = Symbol.for('mySymbol')
80
+ * Symbol.setData(mySymbol, { foo: 'bar' })
81
+ * Symbol.deleteData(mySymbol, { newFoo: 'newBar' })
82
+ * console.log(Symbol.keys.data(mySymbol)) // Output: { newFoo: 'newBar' }
37
83
  */
38
- withData(name, data) {
39
- return data !== undefined
40
- ? Symbol.for(`${name} ${JSON.stringify(data)}`)
41
- : Symbol.for(name)
84
+ deleteData(forSymbol, replaceWith = undefined) {
85
+ return this.keys.deleteData(forSymbol, replaceWith)
86
+ },
87
+
88
+ /**
89
+ * Evaluates a key or value and generates a shared symbol key based on
90
+ * the provided object name and owner name.
91
+ *
92
+ * This method takes a key or value, an object name, and an object owner
93
+ * name as parameters. It determines the type of each parameter and
94
+ * constructs a token string by concatenating the owner name, object
95
+ * name, and key/value (if they are valid object keys).
96
+ *
97
+ * The token string is then used to create a shared symbol key using the
98
+ * `sharedKey` method of the current instance. The shared symbol key is
99
+ * returned along with the token as associated data.
100
+ *
101
+ * @param {string|Symbol} keyOrValue - The key or value to evaluate.
102
+ * @param {string|Symbol} objectName - The name of the object associated
103
+ * with the key or value.
104
+ * @param {string|Function|Object} objectOwnerName - The name of the
105
+ * owner of the object.
106
+ * @returns {Symbol} The shared symbol key generated based on the
107
+ * provided parameters.
108
+ *
109
+ * @example
110
+ * const symbolKey = SymbolExtensions.evalKey('myKey', 'myObject', 'myOwner')
111
+ * console.log(symbolKey)
112
+ * // Output: Symbol(@nejs.internal.refkey:myOwner.myObject.myKey)
113
+ *
114
+ * @example
115
+ * const symbolKey = SymbolExtensions.evalKey(
116
+ * 'myValue', () => {}, { [Symbol.toStringTag]: 'myOwner' }
117
+ * )
118
+ * console.log(symbolKey)
119
+ * // Output: Symbol(@nejs.internal.refkey:myOwner.myValue)
120
+ */
121
+ evalKey(keyOrValue, objectName, objectOwnerName) {
122
+ const is = {
123
+ string(v) { return typeof v === 'string' },
124
+ func(v) { return typeof v === 'function' },
125
+ object(v) { return typeof v === 'object' },
126
+ objKey(v) { return ['symbol', 'string'].some(k => typeof v === k) },
127
+ }
128
+ is.key = is.objKey(keyOrValue)
129
+
130
+ const ownerName = (
131
+ (is.string(objectOwnerName) && objectOwnerName) ||
132
+ (is.func(objectOwnerName) && objectOwnerName?.name) ||
133
+ (is.object(objectOwnerName) && objectOwnerName?.[Symbol.toStringTag]) ||
134
+ undefined
135
+ )
136
+
137
+ const token = [
138
+ ownerName && `${ownerName}.` || '',
139
+ is.objKey(objectName) && `${objectName}.` || '',
140
+ is.objKey(keyOrValue) && `${keyOrValue}`,
141
+ ].join('')
142
+
143
+ return this.sharedKey(`internal.refkey:${token}`, { token })
144
+ },
145
+
146
+ /**
147
+ * Checks if the Symkeys instance has data associated with a given
148
+ * symbol
149
+ *
150
+ * This method checks if the Symkeys instance has any data associated
151
+ * with the provided symbol. It is useful when you need to verify if
152
+ * data exists for a particular symbol before attempting to retrieve
153
+ * or manipulate it
154
+ *
155
+ * @param {Symbol} forSymbol - The symbol to check for associated data
156
+ * @returns {boolean} Returns true if data exists for the symbol,
157
+ * false otherwise
158
+ *
159
+ * @example
160
+ * // Assuming 'mySymbol' is a symbol that has been added to the
161
+ * // Symkeys with associated data
162
+ * const hasData = Symbol.hasData(mySymbol)
163
+ * console.log(hasData) // Output: true
164
+ *
165
+ * @example
166
+ * // Assuming 'nonExistentSymbol' is a symbol that has not been added
167
+ * // to the Symkeys
168
+ * const hasData = Symbol.hasData(nonExistentSymbol)
169
+ * console.log(hasData) // Output: false
170
+ */
171
+ hasData(forSymbol) {
172
+ return this.keys.hasData(forSymbol)
42
173
  },
43
174
 
44
175
  /**
@@ -124,7 +255,114 @@ export const SymbolExtensions = new Patch(Symbol, {
124
255
  * kOriginal.data.original = Object.prototype // ...and...
125
256
  * kOriginal.data = [Object.prototype, Array.prototype] // ...both work
126
257
  */
127
- keys: new Symkeys('nejs'),
258
+ get keys() { return symkeys },
259
+
260
+ /**
261
+ * Sets the data associated with a given symbol in the Symkeys
262
+ * instance.
263
+ *
264
+ * This method allows you to store data associated with a specific
265
+ * symbol in the Symkeys instance. It is useful when you want to
266
+ * attach additional information or metadata to a symbol for later
267
+ * retrieval.
268
+ *
269
+ * @param {Symbol} forSymbol - The symbol for which to set the
270
+ * associated data.
271
+ * @param {*} value - The data to be associated with the symbol.
272
+ *
273
+ * @example
274
+ * // Create a symbol
275
+ * const mySymbol = Symbol.for('mySymbol')
276
+ *
277
+ * // Set data for the symbol
278
+ * Symbol.setData(mySymbol, { foo: 'bar' })
279
+ *
280
+ * // Retrieve the data associated with the symbol
281
+ * const data = Symbol.keys.data(mySymbol)
282
+ * console.log(data) // Output: { foo: 'bar' }
283
+ */
284
+ setData(forSymbol, value) {
285
+ this.keys.setData(forSymbol, value)
286
+ },
287
+
288
+ /**
289
+ * Creates or retrieves a shared symbol key with the given name and
290
+ * optional associated data.
291
+ *
292
+ * This method generates a shared symbol key using the provided name
293
+ * and optional parameters. If the symbol already exists in the
294
+ * Symkeys's internal map, it updates the associated data if provided.
295
+ * Otherwise, it creates a new symbol with the specified parameters.
296
+ *
297
+ * @param {string} named - The name to use for the shared symbol key.
298
+ * @param {Object} options - Optional parameters for the shared symbol key.
299
+ * @param {Object} [options.associate] - Data to associate with the symbol.
300
+ * @param {Object} [options.embed] - Data to embed in the symbol's name.
301
+ * @param {string} [options.useDomain] - Domain to include in the symbol's name.
302
+ * @param {string} [options.useSeparator] - Separator to use in the symbol's name.
303
+ * @returns {Symbol} The shared symbol key.
304
+ *
305
+ * @example
306
+ * // Create or retrieve a shared symbol key with associated data
307
+ * const sharedSymbol = Symbol.sharedKey('mySharedKey', {
308
+ * associate: { foo: 'bar' },
309
+ * embed: { baz: 'qux' },
310
+ * useDomain: 'exampleDomain',
311
+ * useSeparator: '-',
312
+ * })
313
+ * console.log(sharedSymbol)
314
+ * // Output: Symbol(@exampleDomain-mySharedKey {"baz":"qux"} #shared)
315
+ */
316
+ sharedKey(named, options) {
317
+ return this.keys.sharedKey(named, options)
318
+ },
319
+
320
+ /**
321
+ * A symbol used as the storage key for the single instance of a
322
+ * singleton.
323
+ *
324
+ * This getter returns a unique symbol created using `Symbol.for()`
325
+ * with the string 'singleton'. The symbol is used to store and
326
+ * retrieve the single instance of a singleton object.
327
+ *
328
+ * @type {symbol}
329
+ * @readonly
330
+ *
331
+ * @example
332
+ * const singletonKey = Symbol.singleton
333
+ * const singletonInstance = {}
334
+ * global[singletonKey] = singletonInstance
335
+ */
336
+ get singleton() {
337
+ return Symbol.for('singleton')
338
+ },
339
+
340
+ /**
341
+ * Creates a new Symbol with the given name and optional data. If data
342
+ * is provided, it will be stringified and appended to the symbol's
343
+ * name. This method is useful for creating unique symbols that carry
344
+ * additional metadata.
345
+ *
346
+ * @param {string} name The name of the symbol.
347
+ * @param {*} [data] Optional data to be associated with the symbol.
348
+ * @returns {symbol} A new symbol created with Symbol.for(), using the
349
+ * provided name and stringified data (if provided).
350
+ *
351
+ * @example
352
+ * const symbolWithData = Symbol.withData('mySymbol', { foo: 'bar' })
353
+ * console.log(symbolWithData.toString())
354
+ * // Output: "Symbol(mySymbol {"foo":"bar"})"
355
+ *
356
+ * @example
357
+ * const symbolWithoutData = Symbol.withData('mySymbol')
358
+ * console.log(symbolWithoutData.toString())
359
+ * // Output: "Symbol(mySymbol)"
360
+ */
361
+ withData(name, data) {
362
+ return data !== undefined
363
+ ? Symbol.for(`${name} ${JSON.stringify(data)}`)
364
+ : Symbol.for(name)
365
+ },
128
366
  });
129
367
 
130
368
  export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
@@ -195,7 +433,23 @@ export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
195
433
  }
196
434
  }
197
435
 
198
- return extractFrom(string)
436
+ let result = undefined;
437
+ let revertToggle = false
438
+ if (!JSONExtensions.applied) {
439
+ JSONToggle.start()
440
+ revertToggle = true
441
+ }
442
+
443
+ if (JSON.mightContain(this.description)) {
444
+ try { result = JSON.extractFrom(this.description) }
445
+ catch (ignore) { }
446
+ }
447
+
448
+ if (revertToggle) {
449
+ JSONToggle.stop()
450
+ }
451
+
452
+ return result
199
453
  },
200
454
 
201
455
  /**
@@ -238,9 +492,104 @@ export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
238
492
  * Symkeys.getData(symWithData) // returns { name: 'Jane', age: 26 }
239
493
  */
240
494
  set data(value) {
241
- if (Symkeys.isSymkey(this) && Symkeys.hasData(this)) {
495
+ if (Symkeys.isSymkey(this)) {
242
496
  Symbol.keys.setData(this, value)
243
497
  }
498
+ else {
499
+ console.error(`The symbol ${this.description} is not a symkey`)
500
+ }
501
+ },
502
+
503
+ /**
504
+ * Retrieves the embedded JSON data from the symbol's description.
505
+ *
506
+ * This getter method checks if the symbol's description might contain
507
+ * JSON data. If the description contains JSON, it parses and returns
508
+ * the first JSON object found. If no JSON is found, it returns
509
+ * `undefined`.
510
+ *
511
+ * @returns {Object|undefined} - The parsed JSON object if found,
512
+ * otherwise `undefined`.
513
+ *
514
+ * @example
515
+ * const sym = Symbol.for('example {"name":"Brie"}')
516
+ * console.log(sym.embeddedJSON) // Output: { name: 'Brie' }
517
+ *
518
+ * @example
519
+ * const sym = Symbol('noJSON')
520
+ * console.log(sym.embeddedJSON) // Output: undefined
521
+ */
522
+ get embeddedJSON() {
523
+ return JSONToggle.perform((toggle, patch) => {
524
+ let [mightHave, index, parsed] = JSON.mightContain(
525
+ this.description, true
526
+ )
527
+
528
+ if (mightHave) {
529
+ return parsed?.[0]
530
+ }
531
+
532
+ return undefined
533
+ })
534
+ },
535
+
536
+ /**
537
+ * Parses the embedded JSON data from the symbol's description.
538
+ *
539
+ * This getter method first retrieves the embedded JSON data using the
540
+ * `embeddedJSON` getter. If JSON data is found, it attempts to parse
541
+ * the JSON string and return the resulting object. If parsing fails,
542
+ * an error is logged to the console.
543
+ *
544
+ * @returns {Object|undefined} - The parsed JSON object if parsing is
545
+ * successful, otherwise `undefined`.
546
+ *
547
+ * @example
548
+ * const sym = Symbol.for('example {"name":"Brie"}')
549
+ * console.log(sym.embeddedJSONParsed) // Output: { name: 'Brie' }
550
+ *
551
+ * @example
552
+ * const sym = Symbol('invalidJSON')
553
+ * console.log(sym.embeddedJSONParsed) // Output: undefined
554
+ */
555
+ get embeddedJSONParsed() {
556
+ const json = this.embeddedJSON
557
+
558
+ if (json) {
559
+ try {
560
+ return JSON.parse(json)
561
+ }
562
+ catch (error) {
563
+ console.error(`Failed to parse json: "${json}"`)
564
+ }
565
+ }
566
+
567
+ return undefined
568
+ },
569
+
570
+ /**
571
+ * Checks if the current symbol is a Symkey.
572
+ *
573
+ * This getter method determines whether the current symbol instance
574
+ * conforms to the Symkey pattern. A Symkey is a symbol that matches
575
+ * a specific pattern defined in the Symkeys class.
576
+ *
577
+ * @type {boolean}
578
+ * @readonly
579
+ *
580
+ * @returns {boolean} - Returns true if the symbol is a Symkey,
581
+ * otherwise false.
582
+ *
583
+ * @example
584
+ * const sym = Symbol('@nejs.prototype #rwiy2o905d')
585
+ * console.log(sym.isSymkey) // Output: true
586
+ *
587
+ * @example
588
+ * const sym = Symbol('regularSymbol')
589
+ * console.log(sym.isSymkey) // Output: false
590
+ */
591
+ get isSymkey() {
592
+ return Symkeys.isSymkey(this)
244
593
  },
245
594
 
246
595
  /**
@@ -262,7 +611,162 @@ export const SymbolPrototypeExtensions = new Patch(Symbol.prototype, {
262
611
  * console.log(sym.mightHaveEmbeddedJSON) // Output: false
263
612
  */
264
613
  get mightHaveEmbeddedJSON() {
265
- return mightContain(this.description) && typeof this.data === 'function'
614
+ return JSONToggle.perform((toggle, patch) => {
615
+ return JSON.mightContain(this.description)
616
+ })
617
+ },
618
+
619
+ /**
620
+ * Retrieves the reference object associated with the symbol.
621
+ *
622
+ * This getter method checks if the symbol's description matches a
623
+ * specific pattern using a regular expression. If a match is found,
624
+ * it extracts the token from the description and constructs a shared
625
+ * key using the token. It then retrieves the symbol associated with
626
+ * the shared key using the `sharedKey` method of the
627
+ * `SymbolExtensions.patches` object. Finally, it returns the data
628
+ * associated with the retrieved symbol.
629
+ *
630
+ * If no match is found or the retrieved symbol has no associated
631
+ * data, `undefined` is returned.
632
+ *
633
+ * @type {any}
634
+ * @readonly
635
+ *
636
+ * @example
637
+ * const sym = Symbol.for('@nejs.internal.refkey:example #shared')
638
+ * console.log(sym.refObject) // Output: the data associated with the
639
+ * // 'internal.refkey:example' shared key
640
+ *
641
+ * @example
642
+ * const sym = Symbol('no_match')
643
+ * console.log(sym.refObject) // Output: undefined
644
+ */
645
+ get refObject() {
646
+ const re = /@nejs.internal.refkey:(\S+) #shared/.exec(this.description)
647
+ if (re?.[1]) {
648
+ const [_match, token] = re
649
+ const shareKey = `internal.refkey:${token}`
650
+ const symbol = SymbolExtensions.patches.sharedKey(shareKey)
651
+ return symbol?.data
652
+ }
653
+
654
+ return undefined
266
655
  },
267
- }
656
+
657
+ /**
658
+ * Returns a formatted string representation of the symbol's
659
+ * description, highlighting any embedded JSON data.
660
+ *
661
+ * This getter method checks if the symbol's description contains
662
+ * JSON data and formats it for better readability. It uses the
663
+ * `sgr` function from the `String` object to apply color formatting
664
+ * to the output.
665
+ *
666
+ * If the symbol's description contains JSON data longer than 30
667
+ * characters, it truncates the JSON data and displays an ellipsis
668
+ * in the middle. The JSON data is highlighted using the 'di' color
669
+ * code.
670
+ *
671
+ * @type {string}
672
+ * @readonly
673
+ *
674
+ * @example
675
+ * const sym = Symbol.for('mySymbol {"name":"John Doe"}')
676
+ * console.log(sym.sgrString)
677
+ * // Output: Symbol.for(mySymbol {"name":"John ...hn Doe"})
678
+ *
679
+ * @example
680
+ * const sym = Symbol('mySymbol')
681
+ * console.log(sym.sgrString)
682
+ * // Output: mySymbol
683
+ */
684
+ get sgrString() {
685
+ let { sgr } = String
686
+
687
+ if (!sgr) {
688
+ sgr = (string, ...args) => string
689
+ }
690
+
691
+ const response = JSONToggle.perform((toggle, patch) => {
692
+ let [mightContain, index, jsonResponse] =
693
+ JSON.mightContain(this.description, true)
694
+ let jsonText = jsonResponse?.[0]
695
+
696
+ if (mightContain) {
697
+ if (~index && jsonText && jsonText.length > 30) {
698
+ let desc = this.description
699
+ let newDescription = [
700
+ sgr(`Symbol.for(${desc.slice(0, index)}`, 'green'),
701
+ sgr(jsonText.slice(0, 10), 'di'),
702
+ '...',
703
+ sgr(jsonText.slice(-5), 'di'),
704
+ sgr(`${desc.slice(index + jsonText.length + 1)})`, 'green')
705
+ ].join('')
706
+
707
+ return `${newDescription}`
708
+ }
709
+ }
710
+ })
711
+
712
+ return response ?? this.description
713
+ },
714
+
715
+ /**
716
+ * Custom inspect method for Node.js util.inspect.
717
+ *
718
+ * NOTE: this will only apply if looking at an instance of Symbol,
719
+ * sadly; {@see SymbolPrototypeExtensions.instance}
720
+ *
721
+ * This method is used by Node.js util.inspect to provide a custom
722
+ * representation of the symbol when inspected. It checks if the
723
+ * symbol's description might contain JSON data and if so, it
724
+ * truncates the JSON data in the description to a maximum of 30
725
+ * characters and formats the output with colors using the `sgr`
726
+ * function from the `String` object.
727
+ *
728
+ * @param {number} depth - The current depth of the recursive
729
+ * inspection.
730
+ * @param {Object} options - The options object passed to
731
+ * util.inspect.
732
+ * @param {Function} inspect - The original util.inspect function.
733
+ *
734
+ * @returns {string} - The formatted representation of the symbol.
735
+ *
736
+ * @example
737
+ * const sym = Symbol.for('fun {"name":"John Doe"}')
738
+ * console.log(util.inspect(sym))
739
+ * // Output: Symbol.for(fun {"name":"John ...hn Doe"})
740
+ */
741
+ [Symbol.for('nodejs.util.inspect.custom')](depth, options, inspect) {
742
+ let revert = false
743
+ let detail = undefined
744
+
745
+ let { sgr } = String
746
+ if (!sgr) { sgr = (string, ...args) => string }
747
+
748
+ if (!JSONExtensions.applied) { JSONToggle.start(); revert = true }
749
+ if ((detail = JSON.mightContain(this.description, true))) {
750
+ let jsonText = detail[2][0]
751
+ let index = detail[1]
752
+
753
+ if (~index && jsonText && jsonText.length > 30) {
754
+ let desc = this.description
755
+ let newDescription = [
756
+ sgr(`Symbol.for(${desc.slice(0, index)}`, 'green'),
757
+ sgr(jsonText.slice(0, 10), 'di'),
758
+ '...',
759
+ sgr(jsonText.slice(-5), 'di'),
760
+ sgr(`${desc.slice(index + jsonText.length + 1)})`, 'green'),
761
+ ].join('')
762
+
763
+ if (revert) { JSONToggle.stop() }
764
+ return `${newDescription}`
765
+ }
766
+ }
767
+
768
+ if (revert) { JSONToggle.stop() }
769
+ return inspect(this, { colors: true })
770
+ },
771
+ },
268
772
  })