@lumjs/core 1.38.5 → 1.38.7
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/lib/console.js +36 -11
- package/lib/obj/ns/index.js +2 -2
- package/lib/traits/index.js +3 -9
- package/lib/types/index.js +13 -1
- package/lib/types/stringify.js +5 -292
- package/package.json +6 -3
- package/lib/obj/cycle.js +0 -182
- package/lib/obj/cycle2.js +0 -122
- package/lib/traits/funcs.js +0 -570
- package/lib/traits/registry.js +0 -166
- package/lib/traits/trait.js +0 -194
package/lib/console.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
const {
|
|
1
|
+
const { df } = require('./obj/df');
|
|
2
|
+
const { isObj } = require('./types/basics');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A super simple singleton wrapper around the Javascript console.
|
|
@@ -54,7 +54,7 @@ const LC =
|
|
|
54
54
|
*
|
|
55
55
|
* Only applicable if `handler` is an `Array`.
|
|
56
56
|
*
|
|
57
|
-
* This used to be hard-coded as `"arguments"` but the `
|
|
57
|
+
* This used to be hard-coded as `"arguments"` but the `msgArgs`
|
|
58
58
|
* option has replaced it as the array is simpler for most purposes.
|
|
59
59
|
*
|
|
60
60
|
* Default value: `null`
|
|
@@ -83,7 +83,7 @@ const LC =
|
|
|
83
83
|
* @alias module:@lumjs/core/console.real
|
|
84
84
|
*/
|
|
85
85
|
const RC = globalThis.console;
|
|
86
|
-
|
|
86
|
+
df(LC, 'real', RC);
|
|
87
87
|
|
|
88
88
|
// Only including a few common ones.
|
|
89
89
|
const DEFAULT_METHODS = ['debug','info','log','warn','error'];
|
|
@@ -101,9 +101,9 @@ const HANDLER_OPTIONS =
|
|
|
101
101
|
*/
|
|
102
102
|
function addMethod(method)
|
|
103
103
|
{
|
|
104
|
-
|
|
104
|
+
df(LC, method, function(...args)
|
|
105
105
|
{
|
|
106
|
-
if (typeof LC.trigger ===
|
|
106
|
+
if (typeof LC.trigger === 'function')
|
|
107
107
|
{ // Support for core.observable(core.console);
|
|
108
108
|
LC.trigger(method, ...args);
|
|
109
109
|
}
|
|
@@ -140,7 +140,7 @@ function addMethod(method)
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
if (typeof handler ===
|
|
143
|
+
if (typeof handler === 'function')
|
|
144
144
|
{ // A custom handler function.
|
|
145
145
|
checkHandlerOptions(handler);
|
|
146
146
|
if (opts.methodArg)
|
|
@@ -170,7 +170,7 @@ function addMethod(method)
|
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
df(LC, 'addMethod', addMethod);
|
|
174
174
|
|
|
175
175
|
for (const method of DEFAULT_METHODS)
|
|
176
176
|
{
|
|
@@ -189,7 +189,7 @@ for (const method of DEFAULT_METHODS)
|
|
|
189
189
|
*
|
|
190
190
|
* @function module:@lumjs/core/console.export
|
|
191
191
|
*/
|
|
192
|
-
|
|
192
|
+
df(LC, 'export', function(handler)
|
|
193
193
|
{
|
|
194
194
|
if (handler !== undefined)
|
|
195
195
|
{ // Save the existing handler as 'preHandler'
|
|
@@ -210,7 +210,7 @@ def(LC, 'export', function(handler)
|
|
|
210
210
|
*
|
|
211
211
|
* @function module:@lumjs/core/console.restore
|
|
212
212
|
*/
|
|
213
|
-
|
|
213
|
+
df(LC, 'restore', function()
|
|
214
214
|
{
|
|
215
215
|
if (LC.preHandler !== undefined)
|
|
216
216
|
{
|
|
@@ -226,9 +226,34 @@ def(LC, 'restore', function()
|
|
|
226
226
|
* A shortcut for `LC.export(false)`
|
|
227
227
|
* @function module:@lumjs/core/console.mute
|
|
228
228
|
*/
|
|
229
|
-
|
|
229
|
+
df(LC, 'mute', function()
|
|
230
230
|
{
|
|
231
231
|
return LC.export(false);
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Call a closure function with the console muted.
|
|
236
|
+
*
|
|
237
|
+
* Literally just calls `LC.mute()`, runs the function,
|
|
238
|
+
* then calls `LC.restore()` when finished.
|
|
239
|
+
*
|
|
240
|
+
* @param {function} fn - The function to call.
|
|
241
|
+
* @param {mixed} [ctx] Used as `this` in the function.
|
|
242
|
+
* @param {...mixed} [args] Arguments to pass to the function.
|
|
243
|
+
* @returns {mixed} The return value from the function.
|
|
244
|
+
* @throws {TypeError} if `fn` is not a function.
|
|
245
|
+
*/
|
|
246
|
+
df(LC, 'muted', function(fn, ctx, ...args) {
|
|
247
|
+
if (typeof fn !== 'function') {
|
|
248
|
+
console.error('@lumjs/core/console.muted', {fn, ctx, args});
|
|
249
|
+
throw new TypeError('first argument must be a function');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let retVal;
|
|
253
|
+
LC.mute();
|
|
254
|
+
retVal = fn.apply(ctx, args);
|
|
255
|
+
LC.restore();
|
|
256
|
+
return retVal;
|
|
257
|
+
});
|
|
258
|
+
|
|
234
259
|
module.exports = LC;
|
package/lib/obj/ns/index.js
CHANGED
|
@@ -37,7 +37,7 @@ exports.SOA = SOA;
|
|
|
37
37
|
* Get a namespace path array.
|
|
38
38
|
*
|
|
39
39
|
* If it's already an array, return it as is.
|
|
40
|
-
* If it's a string, split it into an array
|
|
40
|
+
* If it's a string, split it into an array (using one of our formats).
|
|
41
41
|
*
|
|
42
42
|
* @param {(string|string[])} ns - A dotted string, or array of paths.
|
|
43
43
|
* @param {(object|string)} [opts] Options.
|
|
@@ -48,7 +48,7 @@ exports.SOA = SOA;
|
|
|
48
48
|
* @param {(module:@lumjs/core/obj.NS~Format|Array)} [opts.format] Format.
|
|
49
49
|
*
|
|
50
50
|
* You can specify a single format, or an array of formats, in which case
|
|
51
|
-
* the
|
|
51
|
+
* the canParse() method will be called on each of them and the first one
|
|
52
52
|
* that returns true will be used. If none return true, the last one listed
|
|
53
53
|
* will be used.
|
|
54
54
|
*
|
package/lib/traits/index.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A
|
|
2
|
+
* A deprecated alias to the @lumjs/traits package.
|
|
3
|
+
* Will be removed in v2.x.
|
|
3
4
|
* @module @lumjs/core/traits
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const funcs = require('./funcs');
|
|
9
|
-
const Trait = require('./trait');
|
|
10
|
-
const regfns = require('./registry');
|
|
11
|
-
|
|
12
|
-
// Export all the things
|
|
13
|
-
Object.assign(exports, funcs, regfns, {Trait});
|
|
7
|
+
module.exports = require('@lumjs/traits');
|
package/lib/types/index.js
CHANGED
|
@@ -16,7 +16,6 @@ Object.assign(exports,
|
|
|
16
16
|
require('./basics'),
|
|
17
17
|
require('./root'),
|
|
18
18
|
require('./isa'),
|
|
19
|
-
require('./stringify'),
|
|
20
19
|
require('./needs'),
|
|
21
20
|
{ // A few standalone exports.
|
|
22
21
|
def,
|
|
@@ -50,3 +49,16 @@ wrapDepr(exports, 'lazy',
|
|
|
50
49
|
rep: 'core.obj.lazy',
|
|
51
50
|
get: () => require('../obj/df').lazy,
|
|
52
51
|
});
|
|
52
|
+
|
|
53
|
+
// And for the stringify library
|
|
54
|
+
wrapDepr(exports, 'stringify', {
|
|
55
|
+
dep: 'core.types.stringify',
|
|
56
|
+
rep: '@lumjs/describe',
|
|
57
|
+
get: () => require('./stringify').stringify,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
wrapDepr(exports, 'Stringify', {
|
|
61
|
+
dep: 'core.types.Stringify',
|
|
62
|
+
rep: '@lumjs/describe',
|
|
63
|
+
get: () => require('./stringify').Stringify,
|
|
64
|
+
});
|
package/lib/types/stringify.js
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
// Get the extended type list.
|
|
2
|
-
const TYPES = require('./typelist');
|
|
3
|
-
const {F, S, N, B, isObj, isArray, isTypedArray} = require('./basics');
|
|
4
|
-
const def = require('./def');
|
|
5
|
-
|
|
6
|
-
const TOSTRING_TYPES = [TYPES.SY];
|
|
7
|
-
const TOSTRING_INSTANCES = [RegExp];
|
|
8
|
-
const CUSTOM = [];
|
|
9
|
-
const DEF =
|
|
10
|
-
{
|
|
11
|
-
MAXD: 1,
|
|
12
|
-
NEWD: 0,
|
|
13
|
-
}
|
|
14
|
-
const ANY = '{...}';
|
|
15
|
-
|
|
16
|
-
function _opts(opts) {
|
|
17
|
-
return (typeof opts === N
|
|
18
|
-
? { maxDepth: opts }
|
|
19
|
-
: (isObj(opts)
|
|
20
|
-
? opts
|
|
21
|
-
: {}
|
|
22
|
-
)
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
1
|
/**
|
|
27
2
|
* Stringify a Javascript value.
|
|
28
3
|
*
|
|
@@ -45,26 +20,12 @@ function _opts(opts) {
|
|
|
45
20
|
*
|
|
46
21
|
* @returns {string} The stringified value
|
|
47
22
|
*
|
|
48
|
-
* @
|
|
23
|
+
* @deprecated replaced by `@lumjs/describe` package
|
|
24
|
+
* @function module:@lumjs/core/types.stringify
|
|
49
25
|
* @see module:@lumjs/core/types.Stringify
|
|
50
26
|
* @see module:@lumjs/core/types.Stringify#stringify
|
|
51
27
|
*/
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
opts = _opts(opts);
|
|
55
|
-
|
|
56
|
-
if (typeof addNew === N)
|
|
57
|
-
{
|
|
58
|
-
opts.newDepth = addNew;
|
|
59
|
-
}
|
|
60
|
-
else if (typeof addNew === B)
|
|
61
|
-
{
|
|
62
|
-
opts.newDepth = addNew ? 1 : 0;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const si = new Stringify(opts);
|
|
66
|
-
return si.stringify(what);
|
|
67
|
-
}
|
|
28
|
+
const {stringify, Describe: Stringify} = require('@lumjs/describe');
|
|
68
29
|
|
|
69
30
|
/**
|
|
70
31
|
* A class to stringify Javascript values for testing and debugging.
|
|
@@ -86,256 +47,8 @@ function stringify (what, opts={}, addNew=null)
|
|
|
86
47
|
* Any other JS value types (`number`,`boolean`, `string`, etc.) will
|
|
87
48
|
* be serialized using JSON.
|
|
88
49
|
*
|
|
89
|
-
* @
|
|
50
|
+
* @class module:@lumjs/core/types.Stringify
|
|
51
|
+
* @deprecated replaced by `@lumjs/describe` package
|
|
90
52
|
*/
|
|
91
|
-
class Stringify
|
|
92
|
-
{
|
|
93
|
-
/**
|
|
94
|
-
* Create a new Stringify instance
|
|
95
|
-
* @param {object} [opts] Options; saved to `this.options`
|
|
96
|
-
* @param {number} [opts.maxDepth=1] Max depth to recurse?
|
|
97
|
-
* @param {number} [opts.newDepth=0] Depth to prepend 'new' to strings?
|
|
98
|
-
* @param {boolean} [opts.fnString=false] Fully stringify functions?
|
|
99
|
-
* @param {(Array|function)} [opts.setCustom] Set custom stringifiers;
|
|
100
|
-
* used *INSTEAD* of the globally registered ones.
|
|
101
|
-
* @param {(Array|function)} [opts.addCustom] Add custom stringifiers;
|
|
102
|
-
* used *in addition* to the globally registered ones.
|
|
103
|
-
*/
|
|
104
|
-
constructor(opts={})
|
|
105
|
-
{
|
|
106
|
-
opts = _opts(opts);
|
|
107
|
-
|
|
108
|
-
this.options = opts;
|
|
109
|
-
this.maxDepth = opts.maxDepth ?? DEF.MAXD;
|
|
110
|
-
this.newDepth = opts.newDepth ?? DEF.NEWD;
|
|
111
|
-
this.seenObjects = new Map(); // object => description
|
|
112
|
-
this.seenDescrip = new Map(); // description => count
|
|
113
|
-
this.strClass = TOSTRING_INSTANCES.slice();
|
|
114
|
-
this.strTypes = TOSTRING_TYPES.slice();
|
|
115
|
-
|
|
116
|
-
if (opts.fnString)
|
|
117
|
-
{
|
|
118
|
-
this.strTypes.push(F);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (opts.errString)
|
|
122
|
-
{
|
|
123
|
-
this.strClass.push(Error);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (Array.isArray(opts.setCustom))
|
|
127
|
-
{
|
|
128
|
-
this.customFn = opts.setCustom.slice();
|
|
129
|
-
}
|
|
130
|
-
else if (typeof opts.setCustom === F)
|
|
131
|
-
{
|
|
132
|
-
this.customFn = [];
|
|
133
|
-
opts.setCustom.call(this, this.customFn);
|
|
134
|
-
}
|
|
135
|
-
else
|
|
136
|
-
{ // Start out with the global custom tests.
|
|
137
|
-
this.customFn = CUSTOM.slice();
|
|
138
|
-
if (Array.isArray(opts.addCustom))
|
|
139
|
-
{
|
|
140
|
-
this.customFn.push(...opts.addCustom);
|
|
141
|
-
}
|
|
142
|
-
else if (typeof opts.addCustom === F)
|
|
143
|
-
{
|
|
144
|
-
opts.addCustom.call(this, this.customFn);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Stringify a JS value
|
|
152
|
-
* @param {*} what - Value to stringify
|
|
153
|
-
* @returns {string} A friendly representation of `what`
|
|
154
|
-
*/
|
|
155
|
-
stringify(what, curd=0)
|
|
156
|
-
{
|
|
157
|
-
if (this.seenObjects.has(what))
|
|
158
|
-
{ // Cached string for this subject already found.
|
|
159
|
-
return this.seenObjects.get(what);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const recurse = curd < this.maxDepth;
|
|
163
|
-
const addNew = curd < this.newDepth;
|
|
164
|
-
const whatType = typeof what;
|
|
165
|
-
const strFor = (str) => this._stringFor(what, str);
|
|
166
|
-
|
|
167
|
-
for (const test of this.customFn)
|
|
168
|
-
{ // If there are custom extensions, we check them first.
|
|
169
|
-
const ret = test.call(this, what, curd);
|
|
170
|
-
if (typeof ret === S)
|
|
171
|
-
{ // The extension processed the item.
|
|
172
|
-
return strFor(ret);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// A few types we simply stringify right now.
|
|
177
|
-
if (this.strTypes.includes(whatType))
|
|
178
|
-
{
|
|
179
|
-
return strFor(what.toString());
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (!this.options.fnString && typeof what === F)
|
|
183
|
-
{ // Simple format for functions
|
|
184
|
-
return strFor(what.name+'()');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (isObj(what))
|
|
188
|
-
{ // We support a few kinds of objects.
|
|
189
|
-
|
|
190
|
-
// Any class instance that we can simply call `toString()` on, let's do that.
|
|
191
|
-
for (const aClass of this.strClass)
|
|
192
|
-
{
|
|
193
|
-
if (what instanceof aClass)
|
|
194
|
-
{
|
|
195
|
-
return strFor(what.toString());
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// A few formatting helpers used below.
|
|
200
|
-
const nameFor = (name=what.constructor.name) =>
|
|
201
|
-
(addNew ? 'new ' : '') + strFor(name);
|
|
202
|
-
|
|
203
|
-
const container = (content, ps='[', pe=']') =>
|
|
204
|
-
{
|
|
205
|
-
let cstr = nameFor();
|
|
206
|
-
if (recurse)
|
|
207
|
-
{
|
|
208
|
-
cstr += ps;
|
|
209
|
-
if (!Array.isArray(content))
|
|
210
|
-
{
|
|
211
|
-
content = Array.from(content);
|
|
212
|
-
}
|
|
213
|
-
cstr += (content
|
|
214
|
-
.map(item => this.stringify(item, curd+1))
|
|
215
|
-
.join(','));
|
|
216
|
-
cstr += pe;
|
|
217
|
-
}
|
|
218
|
-
return cstr;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (isTypedArray(what))
|
|
222
|
-
{ // This one is pretty simple.
|
|
223
|
-
if (this.options.typedContent)
|
|
224
|
-
{
|
|
225
|
-
return container(what.toString());
|
|
226
|
-
}
|
|
227
|
-
return nameFor();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (what instanceof Map)
|
|
231
|
-
{
|
|
232
|
-
return container(what.entries());
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (what instanceof Set)
|
|
236
|
-
{
|
|
237
|
-
return container(what.values());
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (isArray(what))
|
|
241
|
-
{
|
|
242
|
-
return container(what);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (!this.options.errString && what instanceof Error)
|
|
246
|
-
{
|
|
247
|
-
return nameFor(what.name)+'('+JSON.stringify(what.message)+')';
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// If we reached here, it's another kind of object entirely.
|
|
251
|
-
if (recurse)
|
|
252
|
-
{
|
|
253
|
-
let cstr = nameFor() + '{';
|
|
254
|
-
let keys = Object.keys(what);
|
|
255
|
-
for (let k=0; k < keys.length; k++)
|
|
256
|
-
{
|
|
257
|
-
let key = keys[k], val = what[key];
|
|
258
|
-
if (k > 0) cstr += ', ';
|
|
259
|
-
cstr += key + ':' + this.stringify(val, curd+1)
|
|
260
|
-
}
|
|
261
|
-
cstr += '}';
|
|
262
|
-
return cstr;
|
|
263
|
-
}
|
|
264
|
-
else
|
|
265
|
-
{
|
|
266
|
-
if (this.options.jsonObjects)
|
|
267
|
-
{
|
|
268
|
-
let json;
|
|
269
|
-
try {
|
|
270
|
-
json = JSON.stringify(what);
|
|
271
|
-
} catch (err) {
|
|
272
|
-
console.error(err);
|
|
273
|
-
json = ANY;
|
|
274
|
-
}
|
|
275
|
-
return nameFor() + json;
|
|
276
|
-
}
|
|
277
|
-
else
|
|
278
|
-
{
|
|
279
|
-
return nameFor() + ANY;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
} // if isObj
|
|
284
|
-
|
|
285
|
-
// If we reached here, there's no special methods, use JSON.
|
|
286
|
-
return JSON.stringify(what);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
_stringFor(obj, str)
|
|
290
|
-
{
|
|
291
|
-
let count = 0;
|
|
292
|
-
if (this.seenDescrip.has(str))
|
|
293
|
-
{
|
|
294
|
-
count = this.seenDescrip.get(str);
|
|
295
|
-
}
|
|
296
|
-
this.seenDescrip.set(str, ++count);
|
|
297
|
-
str += '#' + count.toString(16).padStart(3, '0');
|
|
298
|
-
this.seenObjects.set(obj, str);
|
|
299
|
-
return str;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
static addCustoms(...testFns)
|
|
303
|
-
{
|
|
304
|
-
for (let fn of testFns)
|
|
305
|
-
{
|
|
306
|
-
if (typeof fn === F)
|
|
307
|
-
{
|
|
308
|
-
CUSTOM.push(fn);
|
|
309
|
-
}
|
|
310
|
-
else
|
|
311
|
-
{
|
|
312
|
-
console.debug({fn, testFns});
|
|
313
|
-
throw new TypeError("Invalid custom stringify function");
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
static registerCustoms(registerFn)
|
|
319
|
-
{
|
|
320
|
-
if (typeof registerFn === F)
|
|
321
|
-
{
|
|
322
|
-
registerFn.call(this, this);
|
|
323
|
-
}
|
|
324
|
-
else
|
|
325
|
-
{
|
|
326
|
-
console.debug({registerFn});
|
|
327
|
-
throw new TypeError("Invalid custom registration function");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
} // Stringify
|
|
332
|
-
|
|
333
|
-
// Add some static properties for registerCustoms to use
|
|
334
|
-
def(Stringify)
|
|
335
|
-
('strClass', {value: TOSTRING_INSTANCES})
|
|
336
|
-
('strTypes', {value: TOSTRING_TYPES})
|
|
337
|
-
('customFn', {value: CUSTOM})
|
|
338
|
-
('DEFAULTS', {value: DEF})
|
|
339
53
|
|
|
340
|
-
// Export it.
|
|
341
54
|
module.exports = {stringify, Stringify};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumjs/core",
|
|
3
|
-
"version": "1.38.
|
|
3
|
+
"version": "1.38.7",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"exports":
|
|
6
6
|
{
|
|
@@ -35,14 +35,17 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies":
|
|
37
37
|
{
|
|
38
|
-
"@lumjs/
|
|
38
|
+
"@lumjs/cp": "^1.0.0",
|
|
39
|
+
"@lumjs/describe": "^1.0.0",
|
|
39
40
|
"@lumjs/events-observable": "^1.0.1",
|
|
41
|
+
"@lumjs/opts": "^1.0.0",
|
|
42
|
+
"@lumjs/traits": "^1.0.0",
|
|
40
43
|
"semver": "^7.7.3"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies":
|
|
43
46
|
{
|
|
44
47
|
"@lumjs/build": "^1.1.0",
|
|
45
|
-
"@lumjs/tests": "^2.
|
|
48
|
+
"@lumjs/tests": "^2.2.0"
|
|
46
49
|
},
|
|
47
50
|
"scripts":
|
|
48
51
|
{
|
package/lib/obj/cycle.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
cycle.js
|
|
3
|
-
2021-05-31
|
|
4
|
-
|
|
5
|
-
Public Domain.
|
|
6
|
-
|
|
7
|
-
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
|
8
|
-
|
|
9
|
-
This code should be minified before deployment.
|
|
10
|
-
See https://www.crockford.com/jsmin.html
|
|
11
|
-
|
|
12
|
-
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
|
13
|
-
NOT CONTROL.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
// The file uses the WeakMap feature of ES6.
|
|
17
|
-
|
|
18
|
-
/*jslint eval */
|
|
19
|
-
|
|
20
|
-
/*property
|
|
21
|
-
$ref, decycle, forEach, get, indexOf, isArray, keys, length, push,
|
|
22
|
-
retrocycle, set, stringify, test
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
if (typeof JSON.decycle !== "function") {
|
|
26
|
-
JSON.decycle = function decycle(object, replacer) {
|
|
27
|
-
"use strict";
|
|
28
|
-
|
|
29
|
-
// Make a deep copy of an object or array, assuring that there is at most
|
|
30
|
-
// one instance of each object or array in the resulting structure. The
|
|
31
|
-
// duplicate references (which might be forming cycles) are replaced with
|
|
32
|
-
// an object of the form
|
|
33
|
-
|
|
34
|
-
// {"$ref": PATH}
|
|
35
|
-
|
|
36
|
-
// where the PATH is a JSONPath string that locates the first occurance.
|
|
37
|
-
|
|
38
|
-
// So,
|
|
39
|
-
|
|
40
|
-
// var a = [];
|
|
41
|
-
// a[0] = a;
|
|
42
|
-
// return JSON.stringify(JSON.decycle(a));
|
|
43
|
-
|
|
44
|
-
// produces the string '[{"$ref":"$"}]'.
|
|
45
|
-
|
|
46
|
-
// If a replacer function is provided, then it will be called for each value.
|
|
47
|
-
// A replacer function receives a value and returns a replacement value.
|
|
48
|
-
|
|
49
|
-
// JSONPath is used to locate the unique object. $ indicates the top level of
|
|
50
|
-
// the object or array. [NUMBER] or [STRING] indicates a child element or
|
|
51
|
-
// property.
|
|
52
|
-
|
|
53
|
-
var objects = new WeakMap(); // object to path mappings
|
|
54
|
-
|
|
55
|
-
return (function derez(value, path) {
|
|
56
|
-
|
|
57
|
-
// The derez function recurses through the object, producing the deep copy.
|
|
58
|
-
|
|
59
|
-
var old_path; // The path of an earlier occurance of value
|
|
60
|
-
var nu; // The new object or array
|
|
61
|
-
|
|
62
|
-
// If a replacer function was provided, then call it to get a replacement value.
|
|
63
|
-
|
|
64
|
-
if (replacer !== undefined) {
|
|
65
|
-
value = replacer(value);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// typeof null === "object", so go on if this value is really an object but not
|
|
69
|
-
// one of the weird builtin objects.
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
typeof value === "object"
|
|
73
|
-
&& value !== null
|
|
74
|
-
&& !(value instanceof Boolean)
|
|
75
|
-
&& !(value instanceof Date)
|
|
76
|
-
&& !(value instanceof Number)
|
|
77
|
-
&& !(value instanceof RegExp)
|
|
78
|
-
&& !(value instanceof String)
|
|
79
|
-
) {
|
|
80
|
-
|
|
81
|
-
// If the value is an object or array, look to see if we have already
|
|
82
|
-
// encountered it. If so, return a {"$ref":PATH} object. This uses an
|
|
83
|
-
// ES6 WeakMap.
|
|
84
|
-
|
|
85
|
-
old_path = objects.get(value);
|
|
86
|
-
if (old_path !== undefined) {
|
|
87
|
-
return {$ref: old_path};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Otherwise, accumulate the unique value and its path.
|
|
91
|
-
|
|
92
|
-
objects.set(value, path);
|
|
93
|
-
|
|
94
|
-
// If it is an array, replicate the array.
|
|
95
|
-
|
|
96
|
-
if (Array.isArray(value)) {
|
|
97
|
-
nu = [];
|
|
98
|
-
value.forEach(function (element, i) {
|
|
99
|
-
nu[i] = derez(element, path + "[" + i + "]");
|
|
100
|
-
});
|
|
101
|
-
} else {
|
|
102
|
-
|
|
103
|
-
// If it is an object, replicate the object.
|
|
104
|
-
|
|
105
|
-
nu = {};
|
|
106
|
-
Object.keys(value).forEach(function (name) {
|
|
107
|
-
nu[name] = derez(
|
|
108
|
-
value[name],
|
|
109
|
-
path + "[" + JSON.stringify(name) + "]"
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
return nu;
|
|
114
|
-
}
|
|
115
|
-
return value;
|
|
116
|
-
}(object, "$"));
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (typeof JSON.retrocycle !== "function") {
|
|
122
|
-
JSON.retrocycle = function retrocycle($) {
|
|
123
|
-
"use strict";
|
|
124
|
-
|
|
125
|
-
// Restore an object that was reduced by decycle. Members whose values are
|
|
126
|
-
// objects of the form
|
|
127
|
-
// {$ref: PATH}
|
|
128
|
-
// are replaced with references to the value found by the PATH. This will
|
|
129
|
-
// restore cycles. The object will be mutated.
|
|
130
|
-
|
|
131
|
-
// The eval function is used to locate the values described by a PATH. The
|
|
132
|
-
// root object is kept in a $ variable. A regular expression is used to
|
|
133
|
-
// assure that the PATH is extremely well formed. The regexp contains nested
|
|
134
|
-
// * quantifiers. That has been known to have extremely bad performance
|
|
135
|
-
// problems on some browsers for very long strings. A PATH is expected to be
|
|
136
|
-
// reasonably short. A PATH is allowed to belong to a very restricted subset of
|
|
137
|
-
// Goessner's JSONPath.
|
|
138
|
-
|
|
139
|
-
// So,
|
|
140
|
-
// var s = '[{"$ref":"$"}]';
|
|
141
|
-
// return JSON.retrocycle(JSON.parse(s));
|
|
142
|
-
// produces an array containing a single element which is the array itself.
|
|
143
|
-
|
|
144
|
-
var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
|
|
145
|
-
|
|
146
|
-
(function rez(value) {
|
|
147
|
-
|
|
148
|
-
// The rez function walks recursively through the object looking for $ref
|
|
149
|
-
// properties. When it finds one that has a value that is a path, then it
|
|
150
|
-
// replaces the $ref object with a reference to the value that is found by
|
|
151
|
-
// the path.
|
|
152
|
-
|
|
153
|
-
if (value && typeof value === "object") {
|
|
154
|
-
if (Array.isArray(value)) {
|
|
155
|
-
value.forEach(function (element, i) {
|
|
156
|
-
if (typeof element === "object" && element !== null) {
|
|
157
|
-
var path = element.$ref;
|
|
158
|
-
if (typeof path === "string" && px.test(path)) {
|
|
159
|
-
value[i] = eval(path);
|
|
160
|
-
} else {
|
|
161
|
-
rez(element);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
} else {
|
|
166
|
-
Object.keys(value).forEach(function (name) {
|
|
167
|
-
var item = value[name];
|
|
168
|
-
if (typeof item === "object" && item !== null) {
|
|
169
|
-
var path = item.$ref;
|
|
170
|
-
if (typeof path === "string" && px.test(path)) {
|
|
171
|
-
value[name] = eval(path);
|
|
172
|
-
} else {
|
|
173
|
-
rez(item);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}($));
|
|
180
|
-
return $;
|
|
181
|
-
};
|
|
182
|
-
}
|