@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
@@ -0,0 +1,333 @@
1
+ import { Extension } from '@nejs/extension'
2
+
3
+ export class Property {
4
+ constructor(key, descriptor) {
5
+ if (key.startsWith(':')) key = Symbol.for(key.slice(1))
6
+ if (typeof key !== 'string' && typeof key !== 'symbol') {
7
+ throw new TypeError('Key or symbol or :symbol must be supplied!');
8
+ }
9
+
10
+ this.key = key;
11
+
12
+ if (!Property.is.descriptor(descriptor)) {
13
+ this.descriptor = {
14
+ value: descriptor,
15
+ writable: true,
16
+ configurable: true,
17
+ enumerable: true,
18
+ }
19
+ }
20
+ else {
21
+ this.descriptor = descriptor;
22
+ }
23
+ }
24
+
25
+ apply(toObject, asKey) {
26
+ if (!toObject || !['object','function'].some(k => k == typeof toObject))
27
+ return;
28
+
29
+ return Object.defineProperty(toObject, asKey ?? this.key, this.descriptor)
30
+ }
31
+
32
+ get descriptor() {
33
+ const baseline = { configurable: true, enumerable: false };
34
+ const result = {
35
+ enumerable: this.meta.enumerable,
36
+ configurable: this.meta.configurable,
37
+ };
38
+
39
+ if (this.is.accessor) {
40
+ result.get = this.meta.accessor.get;
41
+ result.set = this.meta.accessor.set;
42
+ }
43
+ else {
44
+ result.value = this.meta.data.value;
45
+ result.writable = this.meta.data.writable;
46
+ }
47
+
48
+ return Object.defineProperties(result, {
49
+ make: {
50
+ ...baseline,
51
+ get() {
52
+ const self = this;
53
+
54
+ return {
55
+ get enumerable() {self.enumerable = true; return self},
56
+ get hidden() {self.enumerable = false; return self},
57
+
58
+ get writable() {self.writable = true; return self},
59
+ get readonly() {self.writable = false; return self},
60
+
61
+ get configurable() {self.configurable = true; return self},
62
+ get immutable() {self.configurable = false; return self},
63
+ }
64
+ }
65
+ },
66
+
67
+ is: {
68
+ ...baseline,
69
+ get() {
70
+ const self = this;
71
+
72
+ return {
73
+ get accessor() {return self.is.accssor},
74
+ get data() {return self.is.data}
75
+ }
76
+ }
77
+ },
78
+ })
79
+ }
80
+
81
+ set descriptor(descriptor) {
82
+ const { is } = this.constructor;
83
+
84
+ if (!is.descriptor(descriptor))
85
+ return;
86
+
87
+ this.meta.configurable = descriptor.configurable ?? true
88
+ this.meta.enumerable = descriptor.enumerable ?? true
89
+
90
+ if (Reflect.has(descriptor, 'get') || Reflect.has(descriptor, 'set')) {
91
+ const { get, set } = descriptor;
92
+
93
+ if (get !== undefined) this.meta.accessor.get = get;
94
+ if (set !== undefined) this.meta.accessor.set = set;
95
+ }
96
+ else {
97
+ const { value, writable } = descriptor;
98
+
99
+ this.meta.data.value = value;
100
+ this.meta.data.writable = writable ?? true;
101
+ }
102
+ }
103
+
104
+ get is() {
105
+ const self = this;
106
+
107
+ return {
108
+ get accessor() {
109
+ return !!(
110
+ self.meta.accessor.get ||
111
+ self.meta.accessor.set
112
+ );
113
+ },
114
+
115
+ get data() {
116
+ return !!!this.accessor
117
+ },
118
+ }
119
+ }
120
+
121
+ toString(colors = false, {key, descriptor} = {}) {
122
+ const bold = s => colors ? `\x1b[1m${s}\x1b[22m` : s;
123
+ const dim = s => colors ? `\x1b[2m${s}\x1b[22m` : s;
124
+ const red = s => colors ? `\x1b[31m${s}\x1b[39m` : s;
125
+ const green = s => colors ? `\x1b[32m${s}\x1b[39m` : s;
126
+ const blue = s => colors ? `\x1b[34m${s}\x1b[39m` : s;
127
+
128
+ if (!key) ({key} = this);
129
+ if (!descriptor || !Property.is.descriptor(descriptor))
130
+ ({descriptor} = this);
131
+
132
+ const buffer = [`${bold(key)} { `]
133
+ const keyPresent = (object) => (key) => Reflect.has(object, key)
134
+ const eqeq = (value, compare = (a,b) => a === b) =>
135
+ (element) => compare(element, value);
136
+
137
+ if (['get', 'set'].some(keyPresent(descriptor))) {
138
+ if (descriptor.get) {
139
+ buffer.push(blue('getter'))
140
+ if (descriptor.set) {
141
+ buffer.push(bold('|'))
142
+ }
143
+ }
144
+
145
+ if (descriptor.set) {
146
+ buffer.push(blue('setter'))
147
+ }
148
+ }
149
+ else {
150
+ buffer.push(green('value'))
151
+ buffer.push(bold('|'))
152
+ buffer.push(descriptor.writable ? green('writable') : red('readonly'))
153
+ }
154
+
155
+ buffer.push(' ')
156
+ buffer.push(descriptor.configurable ? green('mutable') : red('immuatable'))
157
+
158
+ buffer.push(' ')
159
+ buffer.push(descriptor.enumerable ? green('visible') : red('hidden'))
160
+
161
+ buffer.push(' }')
162
+
163
+ return buffer.join('')
164
+ }
165
+
166
+ [Symbol.for('nodejs.util.inspect.custom')](depth, options, inspect) {
167
+ return this.toString(true);
168
+ }
169
+
170
+ /**
171
+ * Creates an accessor property with customizable getter and setter functions.
172
+ *
173
+ * This method offers flexible ways to define accessor properties, including
174
+ * support for storage-based getters and setters. It can handle various input
175
+ * formats, making it versatile for different use cases.
176
+ *
177
+ * @param {string} name - The name of the accessor property.
178
+ * @param {Object} accessors - Object containing getter and/or setter functions.
179
+ * @param {Function} [accessors.get] - Getter function for the property.
180
+ * @param {Function} [accessors.set] - Setter function for the property.
181
+ * @param {Object} [accessors.prototype] - Prototype object for getter/setter.
182
+ * @param {Object} [options] - Additional options for the accessor property.
183
+ * @param {boolean} [options.configurable=true] - Whether property is configurable.
184
+ * @param {boolean} [options.enumerable=true] - Whether property is enumerable.
185
+ * @param {Object} [options.storage] - Storage object for getter/setter closures.
186
+ * @returns {Property} A new Property instance representing the accessor.
187
+ * @throws {TypeError} If no name, getter, or setter is provided.
188
+ *
189
+ * @example
190
+ * // Basic usage
191
+ * Property.accessor('color', {
192
+ * get() { return this._color; },
193
+ * set(value) { this._color = value; }
194
+ * });
195
+ *
196
+ * @example
197
+ * // Using storage
198
+ * Property.accessor('keyword', {
199
+ * get(storage) { return () => storage.keyword; },
200
+ * set(storage) { return (value) => { storage.keyword = value; } }
201
+ * }, { storage: { keyword: 'initial' } });
202
+ *
203
+ * @example
204
+ * // Using named getter function
205
+ * Property.accessor('color', function get() { return 'red' })
206
+ *
207
+ * @example
208
+ * // Using prototype
209
+ * const ColorAccessors = {
210
+ * red: { get() { return this._red; } }
211
+ * };
212
+ * Property.accessor('red', ColorAccessors.red);
213
+ */
214
+ static accessor(
215
+ name,
216
+ {get, set, prototype},
217
+ {configurable, enumerable, storage} = {}
218
+ ) {
219
+ if (!get && !set && prototype) {
220
+ const constructor = prototype?.constructor;
221
+
222
+ if (constructor?.name === 'get') {
223
+ get = constructor;
224
+ }
225
+ else if (constructor?.name === 'set') {
226
+ set = constructor
227
+ }
228
+ }
229
+
230
+ if (get && storage && get.length == 1) {
231
+ get = get(storage);
232
+ }
233
+
234
+ if (set && storage && set.length == 1) {
235
+ set = set(storage);
236
+ }
237
+
238
+ if (!name && !get && !set) throw new TypeError('Cannot create accessor');
239
+
240
+ configurable ??= true
241
+ enumerable ??= true
242
+
243
+ return new Property(name, { get, set, configurable, enumerable });
244
+ }
245
+
246
+ static data(name, value, { writable, configurable, enumerable } = {}) {
247
+ if (!name) throw new TypeError('Cannot create data property without name')
248
+
249
+ writable ??= true
250
+ configurable ??= true
251
+ enumerable ??= true
252
+
253
+ return new Property(name, { value, writable, configurable, enumerable })
254
+ }
255
+
256
+ static from(object, name) {
257
+ const descriptor = Object.getOwnPropertyDescriptor(object, name);
258
+ return new Property(name, descriptor);
259
+ }
260
+
261
+ static get is() {
262
+ return {
263
+ object(value) {
264
+ return value && ['object','function'].some(k => k == typeof value);
265
+ },
266
+
267
+ descriptor(object) {
268
+ if (!Property.is.object(object)) {
269
+ return false;
270
+ }
271
+
272
+ const present = element => Reflect.has(object, element);
273
+ const props = {
274
+ base: ['configurable', 'enumerable'],
275
+ data: ['writable', 'value'],
276
+ accessor: ['get', 'set'],
277
+ };
278
+
279
+ if (Object.getOwnPropertyNames(object).length > 4)
280
+ return false;
281
+
282
+ if (props.data.some(present) && props.accessor.some(present))
283
+ return false;
284
+
285
+ if (props.base.some(present)) return true;
286
+ if (props.data.some(present)) return true;
287
+ if (props.accessor.some(present)) return true;
288
+
289
+ return false;
290
+ }
291
+ }
292
+ }
293
+
294
+ static {
295
+ const storage = Object.assign(Object.create(null), {
296
+ key: undefined,
297
+ meta: {
298
+ enumerable: true,
299
+ configurable: true,
300
+ accessor: {
301
+ get: undefined,
302
+ set: undefined
303
+ },
304
+ data: {
305
+ value: undefined,
306
+ writable: true
307
+ },
308
+ },
309
+ });
310
+
311
+ basic_accessor(this.prototype, 'key', storage.key, storage)
312
+ basic_accessor(this.prototype, 'meta', storage.meta, storage);
313
+ }
314
+ }
315
+
316
+ export const PropertyExtensions = new Extension(Property);
317
+
318
+ function basic_accessor(prototype, key, initialValue, storage = {}) {
319
+ storage[key] = initialValue;
320
+
321
+ Object.defineProperty(prototype, key, {
322
+ get() {
323
+ return storage[key]
324
+ },
325
+ set(value) {
326
+ storage[key] = value
327
+ },
328
+ enumerable: true,
329
+ configurable: true,
330
+ });
331
+
332
+ return Object.getOwnPropertyDescriptor(prototype, key);
333
+ }
@@ -18,35 +18,136 @@ import { Extension } from '@nejs/extension'
18
18
  */
19
19
  export class Symkeys {
20
20
  /**
21
- * Adds a new entry to the Symkeys with a unique symbol based on the provided
22
- * name and associates it with the given data.
23
- *
24
- * @param named - The base name for the symbol to be created.
25
- * @param [associatedData={}] - The data to associate with the symbol.
26
- * @returns The unique symbol created for the entry.
21
+ * Adds a new symbol to the Symkeys instance with the given name and
22
+ * associated data.
23
+ *
24
+ * This method generates a unique symbol based on the provided name,
25
+ * optional domain, separator, and token. It also allows embedding
26
+ * additional data into the symbol's name.
27
+ *
28
+ * @param {string} named - The base name for the new symbol.
29
+ * @param {Object} options - Additional options for the symbol.
30
+ * @param {*} [options.associate={}] - Data to associate with the symbol.
31
+ * @param {Object} [options.embed] - Optional data to embed in the symbol.
32
+ * @param {string} [options.useDomain] - Optional domain to include in the
33
+ * symbol's name.
34
+ * @param {string} [options.useSeparator] - Optional separator to use in
35
+ * the symbol's name.
36
+ * @param {string} [options.useToken] - Optional token to use for the
37
+ * symbol. If not provided, a random token is generated.
38
+ * @returns {Symbol} The newly created symbol.
27
39
  *
28
40
  * @example
29
- * // Add an entry with associated data
30
- * const symbol = Symkeys.add('myEntry', { foo: 'bar' });
31
- * // Retrieve the associated data using the symbol
32
- * const data = Symkeys.dataFor(symbol);
33
- * console.log(data); // Output: { foo: 'bar' }
41
+ * // Add a symbol with associated data
42
+ * const mySymbol = symkeys.add('myIdentifier', {
43
+ * associate: { foo: 'bar' },
44
+ * embed: { baz: 'qux' },
45
+ * useDomain: 'exampleDomain',
46
+ * useSeparator: '-',
47
+ * useToken: 'customToken',
48
+ * })
49
+ * console.log(mySymbol)
50
+ * // Symbol(@exampleDomain-myIdentifier {"baz":"qux"} #customToken)
34
51
  */
35
- add(named, associatedData = {}) {
52
+ add(
53
+ named,
54
+ {
55
+ associate = {},
56
+ embed = undefined,
57
+ useDomain = undefined,
58
+ useSeparator = undefined,
59
+ useToken = undefined,
60
+ }
61
+ ) {
36
62
  // Generate a unique token for the symbol
37
- const token = Symkeys.token;
63
+ const token = useToken ?? Symkeys.token
38
64
 
39
65
  // Calculate a name (optionally with domain and separator)
40
- const symName = this.calculateName(named)
66
+ let symName = this.calculateName(named, useDomain, useSeparator)
67
+
68
+ if (embed && typeof embed === 'object') {
69
+ try {
70
+ symName += ` ${JSON.stringify(embed)}`
71
+ }
72
+ catch (error) {
73
+ console.warn(`Cannot create JSON from ${embed}; skipping`)
74
+ }
75
+ }
41
76
 
42
77
  // Create a symbol using the provided name and the unique token
43
- const symbol = Symbol.for(`@${symName} #${token}`);
78
+ const symbol = Symbol.for(`@${symName} #${token}`)
44
79
 
45
80
  // Store the symbol and associated data in the Symkeys's internal map
46
- this[Symkeys.kDataKey].set(symbol, associatedData);
81
+ this[Symkeys.kDataKey].set(symbol, associate ?? {})
47
82
 
48
83
  // Return the unique symbol for external use
49
- return symbol;
84
+ return symbol
85
+ }
86
+
87
+ /**
88
+ * Creates or retrieves a shared symbol key with the given name and
89
+ * optional associated data.
90
+ *
91
+ * This method generates a shared symbol key using the provided name
92
+ * and optional parameters. If the symbol already exists in the
93
+ * Symkeys's internal map, it updates the associated data if provided.
94
+ * Otherwise, it creates a new symbol with the specified parameters.
95
+ *
96
+ * @param {string} named - The name to use for the shared symbol key.
97
+ * @param {Object} options - Optional parameters for the shared symbol key.
98
+ * @param {Object} [options.associate] - Data to associate with the symbol.
99
+ * @param {Object} [options.embed] - Data to embed in the symbol's name.
100
+ * @param {string} [options.useDomain] - Domain to include in the symbol's name.
101
+ * @param {string} [options.useSeparator] - Separator to use in the symbol's name.
102
+ * @returns {Symbol} The shared symbol key.
103
+ *
104
+ * @example
105
+ * // Create or retrieve a shared symbol key with associated data
106
+ * const sharedSymbol = symkeys.sharedKey('mySharedKey', {
107
+ * associate: { foo: 'bar' },
108
+ * embed: { baz: 'qux' },
109
+ * useDomain: 'exampleDomain',
110
+ * useSeparator: '-',
111
+ * })
112
+ * console.log(sharedSymbol)
113
+ * // Symbol(@exampleDomain-mySharedKey {"baz":"qux"} #shared)
114
+ */
115
+ sharedKey(named, { associate, embed, useDomain, useSeparator }) {
116
+ // Calculate the symbol name with optional domain and separator
117
+ const symName = this.calculateName(named, useDomain, useSeparator)
118
+
119
+ // Initialize JSON string for embedded data
120
+ let json = ''
121
+ if (embed && typeof embed === 'object') {
122
+ try {
123
+ json = ` ${JSON.stringify(embed)}`
124
+ } catch (ignored) {
125
+ // Ignore JSON stringify errors
126
+ }
127
+ }
128
+
129
+ // Create the shared symbol key
130
+ const symbol = Symbol.for(`@${symName}${json} #shared`)
131
+
132
+ // Check if the symbol already exists in the internal map
133
+ if (this[Symkeys.kDataKey].has(symbol)) {
134
+ // Update associated data if provided and symbol is a Symkey
135
+ if (associate && symbol.isSymkey) {
136
+ symbol.data = associate
137
+ }
138
+
139
+ // Return the existing symbol
140
+ return symbol
141
+ }
142
+
143
+ // Add a new symbol with the specified parameters
144
+ return this.add(named, {
145
+ associate: associate ?? {},
146
+ embed,
147
+ useDomain,
148
+ useSeparator,
149
+ useToken: 'shared'
150
+ })
50
151
  }
51
152
 
52
153
  /**
@@ -175,7 +276,7 @@ export class Symkeys {
175
276
  token(forSymbol) {
176
277
  // Use a regular expression to match the token pattern in the symbol
177
278
  // description exists on symbol but our JS output target is too old
178
- return /^.* \#(.*?)$/.exec(forSymbol).description?.[1];
279
+ return /^.* \#(.*?)$/.exec(forSymbol)?.description?.[1];
179
280
  }
180
281
 
181
282
  /**
@@ -386,7 +487,7 @@ export class Symkeys {
386
487
  return false
387
488
  }
388
489
 
389
- return !!/^@.*? #\w+$/.exec(value.description)
490
+ return !!/^@.*? #\w+$/.exec(value?.description)
390
491
  }
391
492
 
392
493
  /**
@@ -772,6 +772,8 @@ export const FunctionPrototypeExtensions = new Patch(Function.prototype, {
772
772
  // Object<->Function<->Global occurs. See original source in global.this.js
773
773
  // {@see globalThis.isThenElse}
774
774
  function isThenElse(bv, tv, ev) {
775
+ function isFunction(value) { typeof value === 'function' }
776
+
775
777
  if (arguments.length > 1) {
776
778
  var _then = isFunction(tv) ? tv(bv) : tv; if (arguments.length > 2) {
777
779
  var _else = isFunction(ev) ? tv(bv) : ev; return bv ? _then : _else
@@ -1,11 +1,19 @@
1
1
  import { Patch } from '@nejs/extension'
2
2
  import { FunctionExtensions } from './function.extensions.js'
3
+ import * as copyObject from './utils/copy.object.js'
4
+ import { as, has, is, si } from './utils/toolkit.js'
3
5
 
4
6
  const { isClass, isFunction } = FunctionExtensions.patches
5
7
  const CustomInspect = Symbol.for('nodejs.util.inspect.custom')
6
8
 
7
9
  export const GlobalFunctionsAndProps = new Patch(globalThis, {
8
10
  [Patch.kMutablyHidden]: {
11
+ /** copyObject suite exports into global */
12
+ ...copyObject,
13
+
14
+ /** Type toolkit exports into global */
15
+ as, has, is, si,
16
+
9
17
  /**
10
18
  * The `isThenElse` function is a utility function that behaves like a
11
19
  * ternary operator. It takes three arguments: `boolValue`, `thenValue`,
package/src/index.js CHANGED
@@ -17,6 +17,7 @@ import { DescriptorExtensions, Descriptor } from './classes/descriptor.js'
17
17
  import { IntrospectorExtensions } from './classes/introspector.js'
18
18
  import { IteratorExtensions, IterableExtensions } from './classes/iterable.js'
19
19
  import { ParamParserExtensions } from './classes/param.parser.js'
20
+ import { PropertyExtensions } from './classes/property.js'
20
21
  import {
21
22
  PluggableProxyExtensions,
22
23
  ProxyHandlerExtensions,
@@ -27,6 +28,9 @@ import { RefSetExtensions } from './classes/refset.js'
27
28
  import { SymkeysExtension } from './classes/symkeys.js'
28
29
  import { TypeExtensions } from './classes/type.js'
29
30
 
31
+ export * from './utils/copy.object.js'
32
+ export * from './utils/toolkit.js'
33
+
30
34
  import {
31
35
  AsyncIteratorExtensions,
32
36
  AsyncIterableExtensions
@@ -75,6 +79,7 @@ const Extensions = {
75
79
  [ParamParserExtensions.key]: ParamParserExtensions,
76
80
  [PluggableProxyExtensions.key]: PluggableProxyExtensions,
77
81
  [ProxyHandlerExtensions.key]: ProxyHandlerExtensions,
82
+ [PropertyExtensions.key]: PropertyExtensions,
78
83
  [RefMapExtensions.key]: RefMapExtensions,
79
84
  [RefSetExtensions.key]: RefSetExtensions,
80
85
  [SymkeysExtension.key]: SymkeysExtension,
@@ -2,6 +2,23 @@ import { Patch } from '@nejs/extension'
2
2
 
3
3
  export const JSONExtensions = new Patch(JSON, {
4
4
  [Patch.kMutablyHidden]: {
5
+ extractAllFrom(string) {
6
+ const pattern = this.JSONStartPattern
7
+ const notJSON = Symbol("Value is not valid JSON")
8
+ const decoder = part => {
9
+ try { return JSON.parse(part) } catch (_) { return notJSON }
10
+ }
11
+
12
+ const parts = []
13
+ let part = undefined
14
+
15
+ while ((part = pattern.exec(string))) {
16
+ parts.push(decoder(part?.[0]))
17
+ }
18
+
19
+ return parts.filter(isJSON => isJSON !== notJSON)
20
+ },
21
+
5
22
  /**
6
23
  * The `extractFrom` method attempts to extract a JSON object from a string.
7
24
  * It uses a regular expression to identify potential JSON objects in the
@@ -27,25 +44,7 @@ export const JSONExtensions = new Patch(JSON, {
27
44
  * console.log(JSON.extractFrom(str2)) // Output: {name: 'John', age: 30}
28
45
  */
29
46
  extractFrom(string) {
30
- const pattern = /([\w\{\[\"]+) ?/g
31
- const decoder = part => {
32
- try { return JSON.parse(part) } catch (_) { return undefined }
33
- }
34
-
35
- for (
36
- let part = pattern.exec(string);
37
- part;
38
- part = pattern.exec(string)
39
- ) {
40
- if (part && part?.index) {
41
- const decoded = decoder(string.substring(part.index))
42
- if (decoded) {
43
- return decoded
44
- }
45
- }
46
- }
47
-
48
- return undefined
47
+ this.extractAllFrom(string)?.[0]
49
48
  },
50
49
 
51
50
  /**
@@ -136,9 +136,11 @@ export const MapPrototypeExtensions = new Patch(Map.prototype, {
136
136
  // Object<->Function<->Global occurs. See original source in global.this.js
137
137
  // {@see globalThis.isThenElse}
138
138
  function isThenElse(bv, tv, ev) {
139
+ function isFunction(value) { typeof value === 'function' }
140
+
139
141
  if (arguments.length > 1) {
140
142
  var _then = isFunction(tv) ? tv(bv) : tv; if (arguments.length > 2) {
141
143
  var _else = isFunction(ev) ? tv(bv) : ev; return bv ? _then : _else
142
144
  } return bv || _then;
143
145
  } return bv
144
- }
146
+ }
@@ -265,9 +265,11 @@ export const NumberPrototypeExtensions = new Patch(Number.prototype, {
265
265
  // Object<->Function<->Global occurs. See original source in global.this.js
266
266
  // {@see globalThis.isThenElse}
267
267
  function isThenElse(bv, tv, ev) {
268
+ function isFunction(value) { typeof value === 'function' }
269
+
268
270
  if (arguments.length > 1) {
269
271
  var _then = isFunction(tv) ? tv(bv) : tv; if (arguments.length > 2) {
270
272
  var _else = isFunction(ev) ? tv(bv) : ev; return bv ? _then : _else
271
273
  } return bv || _then;
272
274
  } return bv
273
- }
275
+ }