const def = require('./types/def');
const {F} = require('./types/js');
/**
* A super simple singleton wrapper around the Javascript console.
*
* By default includes `info`, `log`, `warn`, and `error` methods.
* It may be expanded further using the `addMethod` method.
*
* @exports module:@lumjs/core/console
*/
const LC =
{
/**
* A custom handler.
*
* If a `function`, it will be called to handle all method calls.
*
* If an `Array`, it will have all log entries added as objects with
* at least `time`, `method`, and `opts` properties.
* By default and `arguments` property will also be included.
* See `msgArguments` and `msgArgs` for further details.
*
* If the boolean value `false`, all output will be thrown into the void.
*
* If it is an `object`, then each property name represents a method name,
* and the values will be treated as a handler for that method only.
* All handler types are supported (i.e. `function`, `Array`, or `false`.)
* A special method name of `DEFAULT` may be specified as a default handler
* for method names not explicitly specified in the object.
* If no `DEFAULT` is specified and there is no handler value for a method
* name, calls to it will be passed through to the real console object.
*
* If no handler was set, all methods are passed to the real console object.
*
* Default value: `null`
*/
handler: null,
/**
* Return the message object?
*
* Only applicable if `handler` is an `Array`.
*
* If `true`, return the message `object`.
* If `false`, returns `undefined`.
*
* Default value: `false`
*/
returnMsg: false,
/**
* The name to include the `arguments` magic object in the log.
*
* Only applicable if `handler` is an `Array`.
*
* This used to be hard-coded as `"arguments"` but the `shortArgs`
* option has replaced it as the array is simpler for most purposes.
*
* Default value: `null`
*/
msgArguments: null,
/**
* The name to include the `args` array in the log.
*
* Only applicable if `handler` is an `Array`.
*
* Default value: `"arguments"`
*/
msgArgs: 'arguments',
/**
* Use the method name as the first argument in function calls.
*
* Default value: `true`
*/
methodArg: true,
}
/**
* A reference to the real console object.
* @alias module:@lumjs/core/console.real
*/
const RC = globalThis.console;
def(LC, 'real', RC);
// Only including a few common ones.
const DEFAULT_METHODS = ['debug','info','log','warn','error'];
// Options that can be changed via handler settings.
const HANDLER_OPTIONS =
[
'returnMsg', 'methodArg', 'msgArguments', 'msgArgs'
];
/**
* Add a wrapper method to the console wrapper object.
* @param {string} method - The console method to wrap.
* @alias module:@lumjs/core/console.addMethod
*/
function addMethod(method)
{
def(LC, method, function(...args)
{
if (typeof LC.trigger === F)
{ // Support for core.observable(core.console);
LC.trigger(method, ...args);
}
let handler = LC.handler;
const opts = {}
function checkHandlerOptions(src)
{
for (const opt of HANDLER_OPTIONS)
{
if (src[opt] !== undefined)
{
opts[opt] = src[opt];
}
}
}
// Get the default options.
checkHandlerOptions(LC);
// Check for complex handler definitions as a plain object.
if (isObj(handler) && !Array.isArray(handler))
{ // Look for options in the handler defs.
checkHandlerOptions(handler);
if (handler[method] !== undefined)
{ // A handler for that method was found.
handler = handler[method];
}
else if (handler.DEFAULT !== undefined)
{ // A default handler.
handler = handler.DEFAULT;
}
}
if (typeof handler === F)
{ // A custom handler function.
checkHandlerOptions(handler);
if (opts.methodArg)
args.unshift(method)
return handler(...args);
}
else if (Array.isArray(handler))
{ // Add a message item to a log array.
checkHandlerOptions(handler);
const time = new Date().toJSON();
const msg = {time, method, opts};
if (typeof opts.msgArguments === S)
msg[opts.msgArguments] = arguments;
if (typeof opts.msgArgs === S)
msg[opts.msgArgs] = args;
handler.push(msg);
if (opts.returnMsg) return msg;
}
else if (handler !== false)
{ // Pass through to the real console.
return RC[method](...args);
}
});
}
def(LC, 'addMethod', addMethod);
for (const method of DEFAULT_METHODS)
{
addMethod(method);
}
module.exports = LC;