bajo 2.23.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.
- package/.jsdoc.conf.json +2 -1
- package/class/app.js +220 -107
- package/class/bajo.js +246 -174
- package/class/base.js +85 -24
- package/class/cache.js +8 -16
- package/class/err.js +31 -10
- package/class/log.js +46 -38
- package/class/plugin.js +53 -30
- package/class/print.js +18 -15
- package/class/tools.js +6 -5
- package/docs/App.html +51 -1
- package/docs/Bajo.html +1 -1
- package/docs/Base.html +34 -1
- package/docs/Cache.html +1 -1
- package/docs/Err.html +2 -2
- package/docs/Log.html +2 -2
- package/docs/Main.html +3 -0
- package/docs/Plugin.html +1 -1
- package/docs/Print.html +1 -1
- package/docs/Tools.html +1 -1
- package/docs/class_app.js.html +222 -109
- package/docs/class_bajo.js.html +260 -179
- package/docs/class_base.js.html +87 -26
- package/docs/class_cache.js.html +10 -18
- package/docs/class_err.js.html +33 -12
- package/docs/class_log.js.html +48 -40
- package/docs/class_plugin.js.html +55 -32
- package/docs/class_print.js.html +20 -17
- package/docs/class_tools.js.html +8 -7
- package/docs/data/search.json +1 -1
- package/docs/extend_bajo_hook.js.html +289 -0
- package/docs/global.html +22 -1
- package/docs/index.html +1 -1
- package/docs/index.js.html +53 -16
- package/docs/lib_applet-hook.js.html +328 -0
- package/docs/lib_config.js.html +167 -0
- package/docs/lib_helper.js.html +186 -192
- package/docs/module-Applet.html +3 -0
- package/docs/module-Helper-Main.html +3 -0
- package/docs/module-Helper.html +1 -8
- package/docs/module-Hook.html +1 -1
- package/docs/tutorial-01_WELCOME.html +3 -0
- package/docs/tutorial-02_GETTING_STARTED.html +125 -0
- package/docs/tutorial-03_USER_GUIDE.html +54 -0
- package/docs/tutorial-04_DEV_GUIDE.html +178 -0
- package/docs/tutorial-05_ECOSYSTEM.html +3 -0
- package/extend/bajo/intl/en-US.json +2 -1
- package/extend/bajo/intl/id.json +2 -1
- package/index.js +51 -14
- package/lib/applet-hook.js +325 -0
- package/lib/config.js +164 -0
- package/lib/helper.js +184 -190
- package/package.json +6 -2
- package/test/00-global-hooks.test.js +44 -0
- package/test/e2e/_run.js +19 -0
- package/test/e2e/e2e-applet-process.test.js +66 -0
- package/test/e2e/e2e-boot-process.test.js +62 -0
- package/test/e2e/e2e-hooks-process.test.js +68 -0
- package/test/integration/_setup.js +55 -0
- package/test/integration/aspect-01-boot-instance.test.js +24 -0
- package/test/integration/aspect-02-plugin-loading.test.js +24 -0
- package/test/integration/aspect-03-config-merge.test.js +27 -0
- package/test/integration/aspect-04-intl-loading.test.js +29 -0
- package/test/integration/aspect-05-cache-roundtrip.test.js +26 -0
- package/test/integration/aspect-06-log-file-save.test.js +28 -0
- package/test/integration/aspect-07-plugin-data-dir.test.js +25 -0
- package/test/integration/aspect-08-plugin-lookup.test.js +25 -0
- package/test/integration/aspect-09-config-formats.test.js +26 -0
- package/test/integration/aspect-10-hooks.test.js +38 -0
- package/test/unit/app.test.js +115 -0
- package/test/unit/applet-hook.test.js +10 -0
- package/test/unit/bajo.test.js +151 -0
- package/test/unit/base.test.js +90 -0
- package/test/unit/cache.test.js +89 -0
- package/test/unit/config.test.js +14 -0
- package/test/unit/err.test.js +57 -0
- package/test/unit/helper.test.js +116 -0
- package/test/unit/index.test.js +40 -0
- package/test/unit/log.test.js +84 -0
- package/test/unit/plugin.test.js +95 -0
- package/test/unit/print.test.js +72 -0
- package/test/unit/tools.test.js +29 -0
- package/wiki/CHANGES.md +4 -0
- package/wiki/tutorials/01_WELCOME.md +18 -0
- package/wiki/tutorials/02_GETTING_STARTED.md +366 -0
- package/wiki/tutorials/03_USER_GUIDE.md +262 -0
- package/wiki/tutorials/04_DEV_GUIDE.md +386 -0
- package/wiki/tutorials/05_ECOSYSTEM.md +95 -0
- package/wiki/tutorials/tutorials.json +17 -0
- package/lib/hook.js +0 -228
- package/test/app.test.js +0 -183
- package/test/bajo.test.js +0 -124
- package/test/base.test.js +0 -75
- package/test/cache.test.js +0 -94
- package/test/e2e.test.js +0 -137
- package/test/err.test.js +0 -73
- package/test/helper.test.js +0 -39
- package/test/import-module.test.js +0 -138
- package/test/integration.test.js +0 -218
- package/test/log.test.js +0 -119
- package/test/plugin.test.js +0 -116
- package/test/print.test.js +0 -100
- package/test/tools.test.js +0 -38
- package/wiki/CONFIG.md +0 -36
- package/wiki/DEV_GUIDE.md +0 -3
- package/wiki/ECOSYSTEM.md +0 -93
- package/wiki/GETTING-STARTED.md +0 -356
- 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
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
81
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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 {
|
|
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 {
|
|
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
|
-
*
|
|
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
|
-
*
|
|
89
|
+
* Reference to the app instance
|
|
88
90
|
* @type {App}
|
|
89
91
|
*/
|
|
90
92
|
this.app = app
|
|
91
93
|
|
|
92
|
-
|
|
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
|
-
*
|
|
99
|
-
* 1. `level` `prefix` `text` `
|
|
100
|
-
* 2. `level` `prefix` `data` `text` `
|
|
101
|
-
* 3. `level` `prefix` `error` - Format as {@link Err} object. If current log level is
|
|
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 {
|
|
114
|
+
* @param {...*} params - See format above
|
|
109
115
|
* @see Err
|
|
110
116
|
* @see Log.TJsonOutput
|
|
111
117
|
*/
|
|
112
|
-
formatMsg = (level, prefix, ...
|
|
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, ...
|
|
125
|
+
let [data, msg, ...params] = args
|
|
120
126
|
if (data instanceof Error) {
|
|
121
127
|
msg = 'error%s'
|
|
122
|
-
|
|
128
|
+
params = [this.getErrorMessage(data)]
|
|
123
129
|
console.error(data)
|
|
124
130
|
}
|
|
125
131
|
if (typeof data === 'string') {
|
|
126
|
-
|
|
132
|
+
params.unshift(msg)
|
|
127
133
|
msg = data
|
|
128
134
|
data = null
|
|
129
135
|
}
|
|
130
|
-
|
|
131
|
-
msg = this.app.t(prefix, msg, ...
|
|
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
|
|
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
|
|
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 {
|
|
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, ...
|
|
236
|
-
this.formatMsg('trace', prefix, ...
|
|
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 {
|
|
252
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
245
253
|
*/
|
|
246
|
-
debug = (prefix, ...
|
|
247
|
-
this.formatMsg('debug', prefix, ...
|
|
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 {
|
|
263
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
256
264
|
*/
|
|
257
|
-
info = (prefix, ...
|
|
258
|
-
this.formatMsg('info', prefix, ...
|
|
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 {
|
|
274
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
267
275
|
*/
|
|
268
|
-
warn = (prefix, ...
|
|
269
|
-
this.formatMsg('warn', prefix, ...
|
|
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 {
|
|
285
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
278
286
|
*/
|
|
279
|
-
error = (prefix, ...
|
|
280
|
-
this.formatMsg('error', prefix, ...
|
|
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 {
|
|
296
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
289
297
|
*/
|
|
290
|
-
fatal = (prefix, ...
|
|
291
|
-
this.formatMsg('fatal', prefix, ...
|
|
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 {
|
|
307
|
+
* @param {...*} args - Arguments to be passed to the message. See {@link Log#formatMsg|formatMsg} for details.
|
|
300
308
|
*/
|
|
301
|
-
silent = (prefix, ...
|
|
302
|
-
this.formatMsg('silent', prefix, ...
|
|
309
|
+
silent = (prefix, ...args) => {
|
|
310
|
+
this.formatMsg('silent', prefix, ...args)
|
|
303
311
|
}
|
|
304
312
|
|
|
305
313
|
/**
|