@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 CHANGED
@@ -1,5 +1,5 @@
1
- const def = require('./types/def');
2
- const {F,isObj} = require('./types/basics');
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 `shortArgs`
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
- def(LC, 'real', RC);
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
- def(LC, method, function(...args)
104
+ df(LC, method, function(...args)
105
105
  {
106
- if (typeof LC.trigger === F)
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 === F)
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
- def(LC, 'addMethod', addMethod);
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
- def(LC, 'export', function(handler)
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
- def(LC, 'restore', function()
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
- def(LC, 'mute', function()
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;
@@ -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, with the `.` delimiter.
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 canStringify() method will be called on each of them and the first one
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
  *
@@ -1,13 +1,7 @@
1
1
  /**
2
- * A very simplistic Trait system.
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
- "use strict";
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');
@@ -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
+ });
@@ -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
- * @alias module:@lumjs/core/types.stringify
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
- function stringify (what, opts={}, addNew=null)
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
- * @alias module:@lumjs/core/types.Stringify
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.5",
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/opts": "^1.0.0",
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.0.0"
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
- }