bajo 2.22.0 → 2.24.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 (108) hide show
  1. package/.jsdoc.conf.json +2 -1
  2. package/class/app.js +220 -107
  3. package/class/bajo.js +258 -177
  4. package/class/base.js +85 -24
  5. package/class/cache.js +8 -16
  6. package/class/err.js +31 -10
  7. package/class/log.js +46 -38
  8. package/class/plugin.js +53 -30
  9. package/class/print.js +18 -15
  10. package/class/tools.js +6 -5
  11. package/docs/App.html +51 -1
  12. package/docs/Bajo.html +1 -1
  13. package/docs/Base.html +34 -1
  14. package/docs/Cache.html +1 -1
  15. package/docs/Err.html +2 -2
  16. package/docs/Log.html +2 -2
  17. package/docs/Main.html +3 -0
  18. package/docs/Plugin.html +1 -1
  19. package/docs/Print.html +1 -1
  20. package/docs/Tools.html +1 -1
  21. package/docs/class_app.js.html +222 -109
  22. package/docs/class_bajo.js.html +260 -179
  23. package/docs/class_base.js.html +87 -26
  24. package/docs/class_cache.js.html +10 -18
  25. package/docs/class_err.js.html +33 -12
  26. package/docs/class_log.js.html +48 -40
  27. package/docs/class_plugin.js.html +55 -32
  28. package/docs/class_print.js.html +20 -17
  29. package/docs/class_tools.js.html +8 -7
  30. package/docs/data/search.json +1 -1
  31. package/docs/extend_bajo_hook.js.html +289 -0
  32. package/docs/global.html +22 -1
  33. package/docs/index.html +1 -1
  34. package/docs/index.js.html +53 -16
  35. package/docs/lib_applet-hook.js.html +328 -0
  36. package/docs/lib_config.js.html +167 -0
  37. package/docs/lib_helper.js.html +186 -192
  38. package/docs/module-Applet.html +3 -0
  39. package/docs/module-Helper-Main.html +3 -0
  40. package/docs/module-Helper.html +1 -8
  41. package/docs/module-Hook.html +1 -1
  42. package/docs/tutorial-01_WELCOME.html +3 -0
  43. package/docs/tutorial-02_GETTING_STARTED.html +125 -0
  44. package/docs/tutorial-03_USER_GUIDE.html +54 -0
  45. package/docs/tutorial-04_DEV_GUIDE.html +178 -0
  46. package/docs/tutorial-05_ECOSYSTEM.html +3 -0
  47. package/extend/bajo/intl/en-US.json +2 -1
  48. package/extend/bajo/intl/id.json +2 -1
  49. package/index.js +51 -14
  50. package/lib/applet-hook.js +325 -0
  51. package/lib/config.js +164 -0
  52. package/lib/helper.js +184 -190
  53. package/package.json +6 -2
  54. package/test/00-global-hooks.test.js +44 -0
  55. package/test/e2e/_run.js +19 -0
  56. package/test/e2e/e2e-applet-process.test.js +66 -0
  57. package/test/e2e/e2e-boot-process.test.js +62 -0
  58. package/test/e2e/e2e-hooks-process.test.js +68 -0
  59. package/test/integration/_setup.js +55 -0
  60. package/test/integration/aspect-01-boot-instance.test.js +24 -0
  61. package/test/integration/aspect-02-plugin-loading.test.js +24 -0
  62. package/test/integration/aspect-03-config-merge.test.js +27 -0
  63. package/test/integration/aspect-04-intl-loading.test.js +29 -0
  64. package/test/integration/aspect-05-cache-roundtrip.test.js +26 -0
  65. package/test/integration/aspect-06-log-file-save.test.js +28 -0
  66. package/test/integration/aspect-07-plugin-data-dir.test.js +25 -0
  67. package/test/integration/aspect-08-plugin-lookup.test.js +25 -0
  68. package/test/integration/aspect-09-config-formats.test.js +26 -0
  69. package/test/integration/aspect-10-hooks.test.js +38 -0
  70. package/test/unit/app.test.js +115 -0
  71. package/test/unit/applet-hook.test.js +10 -0
  72. package/test/unit/bajo.test.js +151 -0
  73. package/test/unit/base.test.js +90 -0
  74. package/test/unit/cache.test.js +89 -0
  75. package/test/unit/config.test.js +14 -0
  76. package/test/unit/err.test.js +57 -0
  77. package/test/unit/helper.test.js +116 -0
  78. package/test/unit/index.test.js +40 -0
  79. package/test/unit/log.test.js +84 -0
  80. package/test/unit/plugin.test.js +95 -0
  81. package/test/unit/print.test.js +72 -0
  82. package/test/unit/tools.test.js +29 -0
  83. package/wiki/CHANGES.md +9 -0
  84. package/wiki/tutorials/01_WELCOME.md +18 -0
  85. package/wiki/tutorials/02_GETTING_STARTED.md +366 -0
  86. package/wiki/tutorials/03_USER_GUIDE.md +262 -0
  87. package/wiki/tutorials/04_DEV_GUIDE.md +386 -0
  88. package/wiki/tutorials/05_ECOSYSTEM.md +95 -0
  89. package/wiki/tutorials/tutorials.json +17 -0
  90. package/lib/hook.js +0 -228
  91. package/test/app.test.js +0 -183
  92. package/test/bajo.test.js +0 -124
  93. package/test/base.test.js +0 -75
  94. package/test/cache.test.js +0 -94
  95. package/test/e2e.test.js +0 -137
  96. package/test/err.test.js +0 -73
  97. package/test/helper.test.js +0 -39
  98. package/test/import-module.test.js +0 -138
  99. package/test/integration.test.js +0 -218
  100. package/test/log.test.js +0 -119
  101. package/test/plugin.test.js +0 -116
  102. package/test/print.test.js +0 -100
  103. package/test/tools.test.js +0 -38
  104. package/wiki/CONFIG.md +0 -36
  105. package/wiki/DEV_GUIDE.md +0 -3
  106. package/wiki/ECOSYSTEM.md +0 -93
  107. package/wiki/GETTING-STARTED.md +0 -356
  108. package/wiki/USER-GUIDE.md +0 -256
package/class/base.js CHANGED
@@ -1,8 +1,72 @@
1
1
  import Plugin from './plugin.js'
2
2
 
3
3
  /**
4
- * This is the class your own plugin suppose to extend. Don't use {@link Plugin} directly
5
- * unless you know what you're doing.
4
+ * To be recognized as a valid Bajo plugin, your package must be an `ES6 module` and have a `package.json` file
5
+ * with the additional `bajo` property and at least the `type` property set to `plugin`.
6
+ *
7
+ * Other than `type`, you might need to specify these additional properties:
8
+ * - `type`: `string`, must be set to `plugin`
9
+ * - `alias`: `string`, the alias name of your plugin. Must be unique among all plugins. If it is missing, it will be generated by Bajo as camel-cased version of your plugin namespace.
10
+ * - `dependencies`: `array`, if your plugin requires one or more other plugins to work, you need to put their **package names** in this array
11
+ *
12
+ * Example:
13
+ * ```json
14
+ * {
15
+ * "name": "my-plugin",
16
+ * "version": "1.0.0",
17
+ * "description": "My Bajo plugin",
18
+ * "type": "module",
19
+ * "main": "index.js",
20
+ * "bajo": {
21
+ * "type": "plugin",
22
+ * "alias": "myplugin",
23
+ * "dependencies": ["bajo-config", "bajo-cli"]
24
+ * }
25
+ * }
26
+ * ...
27
+ * ```
28
+ *
29
+ * > **Note**: The dot symbol in `package.json` has been replaced with `·` symbol because of JSDoc theme limitation
30
+ *
31
+ * > **Warning**: Do not confuse with your app's {@link package·json|package.json} specification, since this one is for plugin while the other is for app.
32
+ * @memberof Base
33
+ * @typedef package·json
34
+ */
35
+
36
+ /**
37
+ * Base class for all plugins.
38
+ *
39
+ * This is the class you must extend when creating a new plugin. It provides basic methods and properties to manage your plugin.
40
+ *
41
+ * You need to wrap your plugin in a factory function with a single parameter `pkgName`, which will be called by the Bajo framework
42
+ * during boot process. The factory function must return your plugin class.
43
+ *
44
+ * Don't forget to write `package.json` for your plugin that follows {@link Base.package·json|this specification}. Please do not
45
+ * confuse this with your app's {@link package·json|package.json} specification, since this one is for your plugin only.
46
+ *
47
+ * Example:
48
+ * ```js
49
+ * // index.js
50
+ * async function factory (pkgName) {
51
+ * const { Base } = this.app.baseClass // get Base from app's baseClass repository
52
+ * const me = this // 'this' is Bajo instance. See Bajo boot process for more details
53
+ * class BajoCache extends Base {
54
+ * constructor () {
55
+ * super(pkgName, me.app)
56
+ * this.config = {} // your plugin's configuration object. If omitted, it will be set to an empty object
57
+ * }
58
+ *
59
+ * init = async () => {
60
+ * // your plugin's initialization code here
61
+ * }
62
+ *
63
+ * start = async () => {
64
+ * // your plugin's start code here
65
+ * }
66
+ * }
67
+ * return BajoCache
68
+ * }
69
+ * ```
6
70
  *
7
71
  * @class
8
72
  */
@@ -18,29 +82,30 @@ class Base extends Plugin {
18
82
  super(pkgName, app)
19
83
 
20
84
  /**
21
- * Dependencies to other plugins. Enter all plugin's package name your plugin dependent from.
22
- *
23
- * Semver is also supported.
24
- *
85
+ * Array of plugin dependencies. If your plugin depends on other plugins, you can specify their package names here e.g. `['bajo-config', 'bajo-cli']`, NOT the plugin name/namespace
25
86
  * @type {string[]}
26
87
  */
27
88
  this.dependencies = []
28
89
 
29
90
  this.state = {}
91
+
92
+ /**
93
+ * Package information from `package.json`. It will be automatically loaded by the framework during plugin initialization
94
+ * @type {object}
95
+ */
30
96
  this.pkg = {}
31
97
  }
32
98
 
33
99
  /**
34
- * Load config from file in data directory, program arguments and environment variables. Level of importance:
35
- * `Env Variables > Program Arguments > Config File`
100
+ * Load plugin configuration. This method will be called by the framework during boot process.
36
101
  *
37
102
  * @method
38
103
  * @async
39
- * @returns {void}
104
+ * @returns {Promise<void>}
40
105
  */
41
106
  loadConfig = async () => {
42
107
  const { defaultsDeep } = this.app.lib.aneka
43
- const { get, keys, pick, isEmpty, upperFirst } = this.app.lib._
108
+ const { get, keys, pick, isEmpty, upperFirst, camelCase } = this.app.lib._
44
109
  const { log, getModuleDir, readAllConfigs } = this.app.bajo
45
110
  const { parseObject } = this.app.lib
46
111
 
@@ -57,42 +122,40 @@ class Base extends Plugin {
57
122
  // merge with config from datadir
58
123
  try {
59
124
  let altCfg = get(this, `app.options.config.${this.ns}`, {})
60
- if (isEmpty(altCfg)) altCfg = await readAllConfigs(`${this.app.bajo.dir.data}/config/${this.ns}`)
125
+ if (isEmpty(altCfg)) altCfg = await readAllConfigs(`${this.app.bajo.dir.data}/config/${camelCase(this.ns)}`)
61
126
  cfg = defaultsDeep({}, altCfg, cfg)
62
127
  } catch (err) {}
63
128
  const cfgEnv = get(this, `app.env.${this.ns}`, {})
64
129
  const cfgArgv = get(this, `app.argv.${this.ns}`, {})
65
- cfg = pick(defaultsDeep({}, cfgEnv ?? {}, cfgArgv ?? {}, cfg ?? {}, this[`config${upperFirst(this.app.bajo.config.env)}`] ?? {}, this.config ?? {}), defKeys)
130
+ const envValue = this[`config${upperFirst(this.app.bajo.config.env)}`]
131
+ cfg = pick(defaultsDeep({}, envValue ?? {}, cfgEnv ?? {}, cfgArgv ?? {}, cfg ?? {}, envValue ?? {}, this.config ?? {}), defKeys)
66
132
  this.config = parseObject(cfg, { parseValue: true })
67
133
  }
68
134
 
69
135
  /**
70
- * After config is read, plugin will be initialized.
71
- *
136
+ * Plugin initialization. This method will be called by the framework during boot process, after configuration is loaded.
72
137
  * @method
73
138
  * @async
74
- * @returns {void}
139
+ * @returns {Promise<void>}
75
140
  */
76
141
  init = async () => {
77
142
  }
78
143
 
79
144
  /**
80
- * This method will be called after plugin's init. You can still change your config here,
81
- * because after plugin is started, config will be deep frozen
82
- *
145
+ * Plugin start. This method will be called by the framework during boot process, after initialization. You still can
146
+ * modifiy your plugin's configuration here before it is deep frozen.
83
147
  * @method
84
148
  * @async
85
- * @returns {void}
149
+ * @returns {Promise<void>}
86
150
  */
87
151
  start = async () => {
88
152
  }
89
153
 
90
154
  /**
91
155
  * Reserved for future use. This method will be called before plugin is stopped.
92
- *
93
156
  * @method
94
157
  * @async
95
- * @returns {void}
158
+ * @returns {Promise<void>}
96
159
  */
97
160
  stop = async () => {
98
161
  }
@@ -100,10 +163,9 @@ class Base extends Plugin {
100
163
  /**
101
164
  * Upon app termination, this method will be called first. Mostly useful for system cleanup,
102
165
  * delete temporary files, freeing resources etc.
103
- *
104
166
  * @method
105
167
  * @async
106
- * @returns {void}
168
+ * @returns {Promise<void>}
107
169
  */
108
170
  exit = async () => {
109
171
  await this.dispose()
@@ -111,7 +173,6 @@ class Base extends Plugin {
111
173
 
112
174
  /**
113
175
  * Dispose internal references.
114
- *
115
176
  * @async
116
177
  * @method
117
178
  * @returns {Promise<void>}
package/class/cache.js CHANGED
@@ -1,21 +1,19 @@
1
1
  /**
2
- * File-system backed cache helper with TTL-based invalidation.
2
+ * Simple, file-system based cache with TTL-based invalidation for every day use.
3
3
  *
4
4
  * @class
5
5
  */
6
6
  class Cache {
7
7
  /**
8
8
  * Constructor.
9
- *
10
- * @param {object} app - Application container
9
+ * @param {App} app - App instance
11
10
  */
12
11
  constructor (app) {
13
12
  this.app = app
14
13
  }
15
14
 
16
15
  /**
17
- * Get root directory for this class. It will be used to store all cache files, organized by namespace and TTL.
18
- *
16
+ * Get root directory. It will be used to store all cache files, organized by namespace and TTL.
19
17
  * @method
20
18
  * @returns {string} Absolute cache root directory
21
19
  */
@@ -25,7 +23,6 @@ class Cache {
25
23
 
26
24
  /**
27
25
  * Prepare cache paths for a namespaced key and TTL.
28
- *
29
26
  * @method
30
27
  * @param {string} name - Cache key in namespaced path format
31
28
  * @param {number|string} [ttlDur=0] - TTL duration (milliseconds or parseable duration)
@@ -46,11 +43,10 @@ class Cache {
46
43
 
47
44
  /**
48
45
  * Load cached content when available and not expired.
49
- *
50
46
  * @method
51
47
  * @param {string} name - Cache key in namespaced path format
52
48
  * @param {number|string} [ttlDur=0] - TTL duration (milliseconds or parseable duration)
53
- * @returns {Promise<any>} Cached value, or undefined if missing/expired
49
+ * @returns {Promise<*>} Cached value, or undefined if missing/expired
54
50
  */
55
51
  load = async (name, ttlDur = 0) => {
56
52
  const { fs } = this.app.lib
@@ -71,10 +67,9 @@ class Cache {
71
67
 
72
68
  /**
73
69
  * Save a value into cache for the given key and TTL directory.
74
- *
75
70
  * @method
76
71
  * @param {string} name - Cache key in namespaced path format
77
- * @param {any} item - Value to persist
72
+ * @param {*} item - Value to persist
78
73
  * @param {number|string} [ttlDur=0] - TTL duration (milliseconds or parseable duration)
79
74
  * @returns {Promise<void>} Resolves when the value is written
80
75
  */
@@ -92,13 +87,12 @@ class Cache {
92
87
  }
93
88
 
94
89
  /**
95
- * Return cached content, and store the fallback value if cache is empty.
96
- *
90
+ * Return cached content, and store the fallback value if cache is empty
97
91
  * @method
98
92
  * @param {string} name - Cache key in namespaced path format
99
- * @param {any} item - Fallback value to save when cache miss happens
93
+ * @param {*} item - Fallback value to save when cache miss happens
100
94
  * @param {number|string} [ttlDur=0] - TTL duration (milliseconds or parseable duration)
101
- * @returns {Promise<any>} Cached content
95
+ * @returns {Promise<*>} Cached content
102
96
  */
103
97
  sync = async (name, item, ttlDur = 0) => {
104
98
  const content = await this.loadCache(name, ttlDur)
@@ -108,7 +102,6 @@ class Cache {
108
102
 
109
103
  /**
110
104
  * Remove a specific cache namespace or all first-level namespaces.
111
- *
112
105
  * @method
113
106
  * @param {string} name - Namespace name or `*` for all
114
107
  * @returns {void}
@@ -149,7 +142,6 @@ class Cache {
149
142
 
150
143
  /**
151
144
  * Dispose internal reference.
152
- *
153
145
  * @async
154
146
  * @method
155
147
  * @returns {Promise<void>}
package/class/err.js CHANGED
@@ -6,13 +6,27 @@ const { isPlainObject, each, isArray, get, isEmpty, merge } = lodash
6
6
  Error.stackTraceLimit = 15
7
7
 
8
8
  /**
9
- * Bajo error class, a thin wrapper of node's Error object.
9
+ * Error details object type definition. This type is used to represent detailed information about an error,
10
+ * including the field that caused the error, the error message, the value that caused the error, and any additional context.
11
+ *
12
+ * This type is particularly useful for validation errors, where you want to provide detailed feedback about what went wrong.
13
+ * @typedef TErrDetails
14
+ * @memberof Err
15
+ * @type {Object}
16
+ * @property {string} field - Field name
17
+ * @property {string} error - Error message
18
+ * @property {*} [value] - The value that caused the error
19
+ * @property {Object} [ext] - Additional context about the error
20
+ */
21
+
22
+ /**
23
+ * Bajo error class, a thin wrapper around the node's Error object.
10
24
  *
11
25
  * Every Bajo {@link Plugin|plugin} has a built-in method called `error` which basically the shortcut to create a new Err instance.
12
26
  * It helps you create this instance anywhere in your code quickly without the hassle of importing & instantiating:
13
27
  *
14
28
  * ```javascript
15
- * ... anywhere inside your code
29
+ * // anywhere inside your code
16
30
  * if (notfound) throw this.error('Sorry, item is nowhere to be found!')
17
31
  * ```
18
32
  */
@@ -22,32 +36,39 @@ class Err extends Tools {
22
36
  *
23
37
  * @param {Plugin} plugin - Plugin instance
24
38
  * @param {string} msg - Error message
25
- * @param {...any} [args] - Variables to interpolate with error message. Payload object can be pushed at the very last argument
39
+ * @param {...*} [args] - Variables to interpolate with error message. Error's payload can be pushed to the very last argument if needed
26
40
  */
27
41
  constructor (plugin, msg, ...args) {
28
42
  super(plugin)
29
43
 
30
44
  /**
31
- * Error payload extracted from the last arguments.
45
+ * Error payload extracted from the last arguments, if any
32
46
  * @type {Object}
33
47
  */
34
48
  this.payload = args.length > 0 && isPlainObject(args[args.length - 1]) ? args[args.length - 1] : {}
35
49
 
36
50
  /**
37
- * Original message before translation.
51
+ * Original message before translation
38
52
  * @type {string}
39
53
  */
40
54
  this.orgMessage = msg
41
55
 
42
56
  /**
43
- * Translated message.
57
+ * Translated message
44
58
  * @type {string}
45
59
  */
46
60
  this.message = this.payload.noTrans ? msg : this.plugin.t(msg, ...args)
47
61
  }
48
62
 
49
63
  /**
50
- * Write message to the console.
64
+ * Write message to the console. Chainable method, returns the Err instance itself.
65
+ *
66
+ * If a payload is provided, it will be merged with the existing payload. If `details` is provided in the payload,
67
+ * it will be formatted and merged to the existing payload and a `detailsMessage` will be generated for display purpose.
68
+ *
69
+ * Original message and translated message will be stored in `orgMessage` and `message` properties respectively.
70
+ *
71
+ * `ns` property will be set to the plugin's namespace.
51
72
  *
52
73
  * @method
53
74
  * @returns {Err} - Error object, useful for chaining
@@ -91,14 +112,14 @@ class Err extends Tools {
91
112
  }
92
113
 
93
114
  /**
94
- * Pretty format error details.
115
+ * Pretty format error details. Used to format error payloads that contain `details` property, which is an array of error details.
95
116
  *
96
- * Formatted error will be applied directly to the value parameter, and a detailsMessage
117
+ * Formatted error will be applied directly to the value parameter, and a `detailsMessage`
97
118
  * will be returned for display purpose.
98
119
  *
99
120
  * @method
100
121
  * @param {Object} value - Value to format
101
- * @returns {Object}
122
+ * @returns {{result: TErrDetails[], detailsMessage: string}} - Formatted result and details message
102
123
  */
103
124
  formatErrorDetails = (value) => {
104
125
  const { isString, last } = this.app.lib._
package/class/log.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import os from 'os'
2
+ import fs from 'fs-extra'
2
3
  import chalk from 'chalk'
3
4
  import { stripVTControlCharacters } from 'node:util'
4
5
 
@@ -57,7 +58,8 @@ export const logLevels = {
57
58
  /**
58
59
  * A thin & fast logger system.
59
60
  *
60
- * An instance is created by the {@link App|app} and available to use from anywhere inside your code.
61
+ * You typically don't need to create an instance of this class, since an instance is already created by the {@link App|app}
62
+ * and available to use from anywhere inside your code.
61
63
  *
62
64
  * Shortcuts to log's methods are also available on every Bajo {@link Plugin|plugin}. Call on
63
65
  * these shortcuts will be prefixed with it's plugin name automatically.
@@ -84,51 +86,55 @@ class Log {
84
86
  */
85
87
  this._lastDelta = 0
86
88
  /**
87
- * The app instance.
89
+ * Reference to the app instance
88
90
  * @type {App}
89
91
  */
90
92
  this.app = app
91
93
 
92
- const { fs } = this.app.lib
94
+ /**
95
+ * Directory to save log files. Defaults to `{dataDir}/log`. If log saving is on (see {@link App#config|app.config.log.save})
96
+ * and directory does not exist, this directory will be created automatically.
97
+ * @type {string}
98
+ */
93
99
  this.logDir = `${this.app.bajo.dir.data}/log`
94
100
  if (this.app.bajo.config.log.save) fs.ensureDirSync(this.logDir)
95
101
  }
96
102
 
97
103
  /**
98
- * Display & format message according to one of these rules:
99
- * 1. `level` `prefix` `text` `var 1` `var 2` `...var n` - Translate `text` and interpolate with `vars` for level `level`
100
- * 2. `level` `prefix` `data` `text` `var 1` `var 2` `...var n` - As above, and append stringified `data`
101
- * 3. `level` `prefix` `error` - Format as {@link Err} object. If current log level is _trace_, dump it on screen
104
+ * Format & display log message according to the current log level with the following syntax:
105
+ * 1. `level` `prefix` `text` `param 1` `param 2` `...param n` - Translate `text` and interpolate with `params` for level `level`
106
+ * 2. `level` `prefix` `{data}` `text` `param 1` `param 2` `...param n` - Same as above, but with additional stringified `data` object to be logged
107
+ * 3. `level` `prefix` `{error}` - Format as {@link Err} object. If current log level is **trace**, dump it on screen
102
108
  *
103
109
  * In `prod` environment, log will be delivered as JSON stringified object. See {@link Log.TJsonOutput} for more info
104
110
  *
105
111
  * @method
106
112
  * @param {string} level - Log level to use
107
113
  * @param {string} prefix - Prefix to the message
108
- * @param {...any} params - See format above
114
+ * @param {...*} params - See format above
109
115
  * @see Err
110
116
  * @see Log.TJsonOutput
111
117
  */
112
- formatMsg = (level, prefix, ...params) => {
118
+ formatMsg = (level, prefix, ...args) => {
113
119
  const { dayjs } = this.app.lib
114
120
  const { isEmpty, merge, without } = this.app.lib._
115
121
 
116
122
  if (this.app.bajo.config.log.level === 'silent') return
117
123
  if (!this.app.bajo.isLogInRange(level)) return
118
124
  const { useUtc, timeTaken, dateFormat, pretty } = this.app.bajo.config.log
119
- let [data, msg, ...args] = params
125
+ let [data, msg, ...params] = args
120
126
  if (data instanceof Error) {
121
127
  msg = 'error%s'
122
- args = [this.getErrorMessage(data)]
128
+ params = [this.getErrorMessage(data)]
123
129
  console.error(data)
124
130
  }
125
131
  if (typeof data === 'string') {
126
- args.unshift(msg)
132
+ params.unshift(msg)
127
133
  msg = data
128
134
  data = null
129
135
  }
130
- args = without(args, undefined)
131
- msg = this.app.t(prefix, msg, ...args)
136
+ params = without(params, undefined)
137
+ msg = this.app.t(prefix, msg, ...params)
132
138
  let text
133
139
  const dt = dayjs()
134
140
  let diff = null
@@ -161,8 +167,7 @@ class Log {
161
167
  }
162
168
 
163
169
  /**
164
- * Get error message from an Error object. If the message is empty, return the code or statusCode instead.
165
- *
170
+ * Get error message from an Error object. If the error message is empty, return the error code or status code instead.
166
171
  * @method
167
172
  * @param {Error} error - Error object
168
173
  * @returns {string} Error message
@@ -174,6 +179,7 @@ class Log {
174
179
 
175
180
  /**
176
181
  * Calculate pattern used for log rotation. Used by {@link Log#save|save} method to determine the log file name.
182
+ * Rotation pattern is based on the `rotation.cycle` configuration. See {@link App#config|app.config.log.rotation.cycle} for more info.
177
183
  *
178
184
  * @method
179
185
  * @param {boolean} isPrev - If `true`, calculate previous rotation pattern.
@@ -206,7 +212,7 @@ class Log {
206
212
  }
207
213
 
208
214
  /**
209
- * Save log to file in `{dataDir}/log`.
215
+ * Save log to file in {@link Log#logDir|logDir}.
210
216
  *
211
217
  * @method
212
218
  * @param {string} text - Log message to save
@@ -230,10 +236,12 @@ class Log {
230
236
  *
231
237
  * @method
232
238
  * @param {string} prefix - Message prefix
233
- * @param {...any} params - Parameters
239
+ * @param {...*} args - Argumets to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
240
+ * @see Err
241
+ * @see Log.TJsonOutput
234
242
  */
235
- trace = (prefix, ...params) => {
236
- this.formatMsg('trace', prefix, ...params)
243
+ trace = (prefix, ...args) => {
244
+ this.formatMsg('trace', prefix, ...args)
237
245
  }
238
246
 
239
247
  /**
@@ -241,10 +249,10 @@ class Log {
241
249
  *
242
250
  * @method
243
251
  * @param {string} prefix - Message prefix
244
- * @param {...any} params - Parameters
252
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
245
253
  */
246
- debug = (prefix, ...params) => {
247
- this.formatMsg('debug', prefix, ...params)
254
+ debug = (prefix, ...args) => {
255
+ this.formatMsg('debug', prefix, ...args)
248
256
  }
249
257
 
250
258
  /**
@@ -252,10 +260,10 @@ class Log {
252
260
  *
253
261
  * @method
254
262
  * @param {string} prefix - Message prefix
255
- * @param {...any} params - Parameters
263
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
256
264
  */
257
- info = (prefix, ...params) => {
258
- this.formatMsg('info', prefix, ...params)
265
+ info = (prefix, ...args) => {
266
+ this.formatMsg('info', prefix, ...args)
259
267
  }
260
268
 
261
269
  /**
@@ -263,10 +271,10 @@ class Log {
263
271
  *
264
272
  * @method
265
273
  * @param {string} prefix - Message prefix
266
- * @param {...any} params - Parameters
274
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
267
275
  */
268
- warn = (prefix, ...params) => {
269
- this.formatMsg('warn', prefix, ...params)
276
+ warn = (prefix, ...args) => {
277
+ this.formatMsg('warn', prefix, ...args)
270
278
  }
271
279
 
272
280
  /**
@@ -274,10 +282,10 @@ class Log {
274
282
  *
275
283
  * @method
276
284
  * @param {string} prefix - Message prefix
277
- * @param {...any} params - Parameters
285
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
278
286
  */
279
- error = (prefix, ...params) => {
280
- this.formatMsg('error', prefix, ...params)
287
+ error = (prefix, ...args) => {
288
+ this.formatMsg('error', prefix, ...args)
281
289
  }
282
290
 
283
291
  /**
@@ -285,10 +293,10 @@ class Log {
285
293
  *
286
294
  * @method
287
295
  * @param {string} prefix - Message prefix
288
- * @param {...any} params - Parameters
296
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
289
297
  */
290
- fatal = (prefix, ...params) => {
291
- this.formatMsg('fatal', prefix, ...params)
298
+ fatal = (prefix, ...args) => {
299
+ this.formatMsg('fatal', prefix, ...args)
292
300
  }
293
301
 
294
302
  /**
@@ -296,10 +304,10 @@ class Log {
296
304
  *
297
305
  * @method
298
306
  * @param {string} prefix - Message prefix
299
- * @param {...any} params - Parameters
307
+ * @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
300
308
  */
301
- silent = (prefix, ...params) => {
302
- this.formatMsg('silent', prefix, ...params)
309
+ silent = (prefix, ...args) => {
310
+ this.formatMsg('silent', prefix, ...args)
303
311
  }
304
312
 
305
313
  /**