bajo 2.0.1 → 2.1.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 (101) hide show
  1. package/.github/FUNDING.yml +13 -0
  2. package/.github/workflows/repo-lockdown.yml +24 -0
  3. package/.jsdoc.conf.json +7 -6
  4. package/LICENSE +1 -1
  5. package/README.md +50 -18
  6. package/class/app.js +378 -54
  7. package/class/bajo.js +228 -149
  8. package/class/base.js +106 -0
  9. package/class/helper/bajo.js +146 -90
  10. package/class/helper/{plugin.js → base.js} +96 -22
  11. package/class/{base → misc}/err.js +44 -14
  12. package/class/misc/log.js +255 -0
  13. package/class/misc/print.js +264 -0
  14. package/class/plugin.js +120 -68
  15. package/docs/App.html +23 -1
  16. package/docs/Bajo.html +2 -9
  17. package/docs/Base.html +3 -0
  18. package/docs/Err.html +3 -1
  19. package/docs/Log.html +5 -1
  20. package/docs/Plugin.html +1 -1
  21. package/docs/Print.html +1 -1
  22. package/docs/class_app.js.html +378 -56
  23. package/docs/class_bajo.js.html +230 -151
  24. package/docs/class_base.js.html +109 -0
  25. package/docs/class_helper_bajo.js.html +138 -87
  26. package/docs/class_helper_base.js.html +246 -0
  27. package/docs/class_misc_err.js.html +129 -0
  28. package/docs/class_misc_log.js.html +210 -0
  29. package/docs/class_misc_print.js.html +267 -0
  30. package/docs/class_plugin.js.html +122 -70
  31. package/docs/data/search.json +1 -1
  32. package/docs/global.html +4 -1
  33. package/docs/index.html +2 -2
  34. package/docs/index.js.html +35 -0
  35. package/docs/lib_current-loc.js.html +36 -0
  36. package/docs/lib_formats.js.html +8 -8
  37. package/docs/lib_import-module.js.html +59 -0
  38. package/docs/lib_log-levels.js.html +17 -7
  39. package/docs/lib_parse-args-argv.js.html +83 -0
  40. package/docs/lib_parse-env.js.html +53 -0
  41. package/docs/lib_resolve-path.js.html +3 -6
  42. package/docs/lib_shim.js.html +8 -3
  43. package/docs/module-Helper_Bajo.html +3 -0
  44. package/docs/module-Helper_Base.html +3 -0
  45. package/docs/module-Lib.html +15 -0
  46. package/docs/static/home.md +32 -0
  47. package/docs/static/logo-ecosystem.png +0 -0
  48. package/docs/static/logo.png +0 -0
  49. package/extend/bajo/intl/en-US.json +9 -2
  50. package/extend/bajo/intl/id.json +9 -2
  51. package/index.js +22 -2
  52. package/lib/current-loc.js +24 -2
  53. package/lib/formats.js +6 -6
  54. package/lib/import-module.js +29 -0
  55. package/lib/log-levels.js +15 -5
  56. package/lib/parse-args-argv.js +20 -12
  57. package/lib/parse-env.js +18 -7
  58. package/lib/resolve-path.js +1 -4
  59. package/lib/shim.js +6 -1
  60. package/package.json +4 -7
  61. package/wiki/CONFIG.md +36 -0
  62. package/wiki/CONTRIBUTING.md +5 -0
  63. package/wiki/DEV_GUIDE.md +3 -0
  64. package/wiki/ECOSYSTEM.md +93 -0
  65. package/wiki/GETTING-STARTED.md +356 -0
  66. package/wiki/USER-GUIDE.md +256 -0
  67. package/class/base/log.js +0 -205
  68. package/class/base/plugin.js +0 -168
  69. package/class/base/print.js +0 -272
  70. package/docs/BasePlugin.html +0 -5
  71. package/docs/class_base_err.js.html +0 -99
  72. package/docs/class_base_log.js.html +0 -208
  73. package/docs/class_base_plugin.js.html +0 -180
  74. package/docs/class_base_print.js.html +0 -275
  75. package/docs/class_helper_plugin.js.html +0 -172
  76. package/docs/lib_create-method.js.html +0 -42
  77. package/docs/module-class_helper_bajo.html +0 -3
  78. package/docs/module-class_helper_plugin.html +0 -3
  79. package/docs/module-lib_create-method.html +0 -3
  80. package/docs/module-lib_formats.html +0 -3
  81. package/docs/module-lib_log-levels.html +0 -3
  82. package/docs/module-lib_resolve-path.html +0 -3
  83. package/docs/module-lib_shim.html +0 -3
  84. package/docs/tutorial-contribution.html +0 -3
  85. package/docs/tutorial-ecosystem.html +0 -3
  86. package/docs/tutorial-getting-started.html +0 -13
  87. package/docs/tutorial-plugin-dev.html +0 -3
  88. package/docs/tutorial-user-guide.html +0 -3
  89. package/lib/create-method.js +0 -39
  90. package/lib/dayjs.js +0 -8
  91. package/lib/omitted-plugin-keys.js +0 -3
  92. package/lib/read-all-configs.js +0 -19
  93. package/misc-docs/.hook.md +0 -11
  94. package/misc-docs/bitcoin.jpeg +0 -0
  95. package/misc-docs/contribution.md +0 -20
  96. package/misc-docs/ecosystem.md +0 -94
  97. package/misc-docs/getting-started.md +0 -142
  98. package/misc-docs/plugin-dev.md +0 -0
  99. package/misc-docs/toc.json +0 -17
  100. package/misc-docs/user-guide.md +0 -1
  101. /package/docs/{bitcoin.jpeg → static/bitcoin.jpeg} +0 -0
@@ -0,0 +1,256 @@
1
+ # User Guide
2
+
3
+ ## Overview
4
+
5
+ ### Definitions
6
+
7
+ Before proceeding, familiarize yourself with these terminologies used throughout this documentation:
8
+
9
+ 1. ```{appDir}```: The application's project directory where all your code residese.
10
+ 2. ```{dataDir}```: The directory for all data; defaults to ```{appDir}/data``` and is created automatically if missing.
11
+ 3. ```{tmpDir}```: The temporary directory, defaults to the OS temporary directory.
12
+ 4. ```{pkgName}```: The plugin's package name, typically matching its npm listing.
13
+ 5. ```{ns}```: The plugin name or namespace, which is the camel-cased version of the package name.
14
+ 6. ```{mainNs}```: The special main namespace and directory named main within your ```{appDir}```; this is where all application code should be written.
15
+
16
+ ### Directory Structure
17
+
18
+ Your typical Bajo app directory structure should look like this:
19
+
20
+ ```
21
+ .
22
+ └── {appDir}
23
+ ├── {dataDir}
24
+ │ ├── config
25
+ │ │ ├── .plugin
26
+ │ │ ├── bajo.json
27
+ │ │ ├── main.json
28
+ │ │ └── ...
29
+ │ └── plugins
30
+ │ └── ...
31
+ ├── main
32
+ │ ├── extend
33
+ │ │ └── ...
34
+ │ ├── index.js
35
+ │ └── ...
36
+ ├── package.json
37
+ ├── index.js
38
+ └── ...
39
+ ```
40
+
41
+ 1. You can move ```{dataDir}``` out of ```{appDir}``` if you want, but you need to tell Bajo where to find it. For more on this, please follow along.
42
+ 2. ```{dataDir}``` should be the only place Bajo **writes** anything. Bajo and its plugins should **never** be allowed to write anything outside ```{dataDir}``` on their own.
43
+ 3. ```config``` is a special directory within ```{dataDir}``` where your configuration files should reside. Inside this directory, you should find:
44
+ - a special file named ```.plugins``` that tells Bajo which plugins should be loaded
45
+ - a file named ```bajo.json``` to configure global settings
46
+ - all plugin-specific config files, named after their namespace
47
+ 4. The ```main``` directory, or ```{mainNs}``` namespace, is the special plugin where you put your application code. And yes, it is actually a normal Bajo plugin! This means everything in there will be handled just like a regular plugin—it has the ability to extend other plugins, has its own config file, and more — with a few differences:
48
+ - it's always available and can't be disabled
49
+ - it's always the last one to start
50
+ - if this directory is missing, it will be created automatically on startup
51
+ - if the plugin's factory function is missing (```index.js```), it will be created dynamically
52
+ 5. ```index.js``` is the main entry point for your app.
53
+
54
+ To set your ```{dataDir}``` somewhere else, you need to tell Bajo where to find it by using an argument switch.
55
+
56
+ Assuming your data directory is ```my-data-dir``` at the same level as your app directory, run your app like this:
57
+
58
+ ```bash
59
+ $ node index.js --dir-data=../my-data-dir
60
+ ```
61
+
62
+ If using program arguments seems a bit like a hassle for you, just use Bajo's [dotenv](https://github.com/motdotla/dotenv) support. Create a ```.env``` file in your app directory and put this inside:
63
+
64
+ ```text
65
+ DIR__DATA=../my-data-dir # double underscores!!!
66
+ ```
67
+
68
+ From now on, you can start the app just by typing:
69
+
70
+ ```bash
71
+ $ node index.js
72
+ ```
73
+
74
+ ### Runtime
75
+
76
+ Bajo should run perfectly fine on Node.js version 20 or higher. Using the latest stable runtime is recommended. Bajo-based apps are also known to run with **Bun** without any problems. But Bajo **cannot** run on Deno due to its heavy reliance on Node.js-specific libraries and environments.
77
+
78
+ Bajo is a pure ES6 framework that utilizes dynamic imports ```a lot```. Running on a system with a fast disk (e.g., SSD) and enough RAM is highly recommended, especially when you load a lot of plugins.
79
+
80
+ ## Configuration
81
+
82
+ ### General Rules
83
+
84
+ - All configuration files must be placed in the ```{dataDir}/config``` subfolder.
85
+ - Config files must be named after their plugin namespace.
86
+ - The file format should be either ```.json``` or ```.js```. If a ```.js``` file is used, it must be in ES6 format and should export either a plain JavaScript object or a function. Both synchronous and asynchronous functions are supported. If it returns a function, this function will be called within its plugin scope and should return a plain JS object.
87
+ - Other formats (```.yml```, ```.yaml```, and ```.toml```) can also be used by installing and loading the [bajoConfig](https://github.com/ardhi/bajo-config) plugin.
88
+ - Other formats (```.yml```, ```.yaml``` and ```.toml```) can also be used by installing & loading [bajoConfig](https://github.com/ardhi/bajo-config) plugin
89
+ - The order of precedence is ```.js``` > ```.json``` > ```.yml``` > ```.yaml``` > ```.toml```. This means that if a .js file exists, it will be used instead of a .json file or any other format.
90
+
91
+ Example: bajo.json
92
+ ```json
93
+ {
94
+ "env": "prod",
95
+ "log": {
96
+ "pretty": true,
97
+ "timeTaken": true
98
+ },
99
+ "lang": "id"
100
+ }
101
+ ```
102
+
103
+ ### Using Plugins
104
+
105
+ Plugins are what make the Bajo Framework so great and flexible: they extend app features and functionalities!
106
+
107
+ To use plugins, follow these steps:
108
+
109
+ 1. Install it with ```npm install {package}```, where ```{package}``` is the plugin's package name. You can install as many plugins as you want; for a complete list of plugins, please [click here](ecosystem.md).
110
+ 2. Optionally, create ```{dataDir}/config/{ns}.json``` to customize the plugin's settings, where ```{ns}``` is the namespace or plugin name.
111
+ 3. Open or create ```{dataDir}/config/.plugins``` and list the plugin's ```{package}``` name in it, one per line.
112
+
113
+ For example, the text below will load ```bajo-config```, ```bajo-extra```, and ```bajo-template```:
114
+
115
+ ```text
116
+ # .plugin file
117
+ bajo-config
118
+ bajo-extra
119
+ bajo-template
120
+ ```
121
+
122
+ If you later decide to disable one or more plugins, you just need to remove them from the ```.plugins``` file or place a ```#``` hash mark in front of the package name and restart your app.
123
+
124
+ > **Warning**: Please do not confuse ```{package}``` and ```{ns}```. The plugin package is the name of the JS package listed on npm, while ```{ns}``` is the namespace or plugin name, which is basically the camel-cased version of the plugin's package name.
125
+
126
+ ### Environment Support
127
+
128
+ Configuration file support for different environments is also available. All you need to do is create a ```{ns}-{env}.json``` file in your ```{dataDir}/config```, where:
129
+
130
+ - ```{ns}```: the namespace/plugin name
131
+ - ```{env}```: your desired environment (```dev``` or ```prod```)
132
+ - App-wide settings with ```bajo-{env}.json``` are also possible.
133
+
134
+ Bajo is smart enough to select which config file will be used based on the following order of precedence:
135
+
136
+ 1. Use ```{ns}-{env}.json``` if the file exists.
137
+ 2. If not, use ```{ns}.json```.
138
+ 3. If that also doesn't exist, then use the plugin's default config values.
139
+
140
+ ### Runtime Override
141
+
142
+ You can easily override ANY key-value pair setting with environment variables and program argument switches. Bajo also supports [dotenv](https://github.com/motdotla/dotenv) with a ```.env``` file.
143
+
144
+ The order of precedence is: environment variable > argument switches > config files > default, built-in values.
145
+
146
+ All values (whether they come from environment variables, argument switches, or config files) will be parsed using [dotenv-parse-variables](https://github.com/ladjs/dotenv-parse-variables), so please make sure you visit the repository to fully understand how it works.
147
+
148
+ #### dotenv
149
+
150
+ - Create or open ```{appDir}/.env```
151
+ - Use ```__``` (double underscores) as replacement for dots in an object.
152
+ - ```DIR__DATA```: Sets the ```{dataDir}``` data directory.
153
+ - ```DIR__TMP```: Sets ```{tmpDir}``` temporary directory.
154
+ - For every key in ```{ns|bajo}.json```, use its snake-cased, upper-cased version. For example:
155
+ - ```env: 'prod'``` → ```ENV=prod```
156
+ - ```log.dateFormat: 'YYYY-MM-DD'``` → ```LOG__DATE_FORMAT=YYYY-MM-DD```
157
+ - ```exitHandler: true``` → ```EXIT_HANDLER=true```
158
+ - To override a plugin's config, prepend every key in the plugin's config with the snake-cased, upper-cased version of the namespace followed by a dot. For example:
159
+ - ```key``` in ```myPlugin``` → ```MY_PLUGIN.KEY=...```
160
+ - ```key.subKey.subSubKey``` in ```myPlugin``` → ```MY_PLUGIN.KEY__SUB_KEY__SUB_SUB_KEY=...```
161
+
162
+ Example:
163
+ ```text
164
+ # .env file
165
+ ENV=prod
166
+ LOG__PRETTY=true
167
+ LOG__TIME_TAKEN=true
168
+ LANG=id
169
+ ```
170
+
171
+ #### Argument Switches
172
+
173
+ - Use switches, for example: ```node index.js --xxx=one --yyy=two```
174
+ - Use ```-``` as the replacement for dots in an object.
175
+ - ```--dir-data```: Sets the ```{dataDir}``` data directory.
176
+ - ```--dir-tmp```: Sets the ```{tmpDir}``` temporary directory.
177
+ - For every key in ```{ns|bajo}.json```, add ```--``` prefix. For example:
178
+ - ```env: 'prod'``` → ```--env=prod```
179
+ - ```log.dateFormat: 'YYYY-MM-DD'``` → ```--log-dateFormat=YYYY-MM-DD```
180
+ - ```exitHandler: true``` → ```--exitHandler```
181
+ - To override a plugin's config, prepend every key in the plugin's config with the plugin name followed by a colon ```:```. For example:
182
+ - ```key``` in ```myPlugin``` → ```--myPlugin:key=...```
183
+ - ```key.subKey.subSubKey``` in ```myPlugin``` → ```--myPlugin:key-subKey-subSubKey=...```
184
+
185
+ Example:
186
+ ```bash
187
+ $ node index.js --env=prod --log-pretty --log-timeTaken --lang=id
188
+ ```
189
+
190
+ ## System Hook
191
+
192
+ A **hook** refers to a mechanism that allows you to inject a custom function to extend Bajo's functionality at specific points. These points are typically predefined by the framework, providing opportunities to execute code before, during, or after a particular operation.
193
+
194
+ ### Usage
195
+
196
+ In Bajo, hooks can be created anywhere very easily. Simply call the ```runHook``` method followed by the parameters you want to pass.
197
+
198
+ The hook name is always in the form of [TNsPairs](global.html#TNsPathPairs), while its parameters are a rest parameter. This means you can pass any number of parameters to the function, or none at all.
199
+
200
+ Example:
201
+
202
+ 1. In your JavaScript file, add the following code snippet:
203
+
204
+ ```javascript
205
+ const { runHook } = this.app.bajo
206
+ await runHook('main:sayHello', 'Don', 'Meri', { movie: 'Jumbo', year: 2025 })
207
+ ````
208
+ 2. Go to directory ```{appDir}/main/extend/bajo/hook```. Create one if it doesn't exist yet.
209
+ 3. Create file ```main@say-hello.js``` in the directory above.
210
+ 4. Enter these lines:
211
+ ```javascript
212
+ async function sayHello (...params) {
213
+ const [mainChar, friend, payload] = params
214
+ console.log(mainChar, friend, payload) // output: Don, Meri, { movie: 'Jumbo', year: 2025 }
215
+ }
216
+
217
+ export default sayHello
218
+ ```
219
+
220
+ Note the hook name and its associated file name:
221
+
222
+ ```main:sayHello``` → ```main@say-hello.js```
223
+
224
+ Because a colon (```:```) is prohibited in a file name, Bajo replaces it with the ```@``` symbol.
225
+
226
+ During the boot process, Bajo will scan for hook files and load them into the hook list. When your ```runHook``` is executed, Bajo will find its related object from the list. If such a hook exists, its function handler will be called.
227
+
228
+ ### Anatomy
229
+
230
+ Many times, there are more than one handler listening for a particular hook name. Especially in a framework that uses plugins extensively like Bajo, many plugins can listen to one hook at the same time. This creates a problem with call order.
231
+
232
+ To overcome this problem, Bajo gives you the opportunity to set a ```level```. Functions with a lower level will be called earlier. Functions with no level will be assigned level 999 by default.
233
+
234
+ Now, change your ```main@say-hello.js``` file above to export an object instead of a function:
235
+
236
+ ```javascript
237
+ const sayHello = {
238
+ level: 10, // <-- will get called early
239
+ handler: async function (...params) {
240
+ const [mainChar, friend, payload] = params
241
+ console.log(mainChar, friend, payload) // output: Don, Meri, { movie: 'Jumbo', year: 2025 }
242
+ }
243
+ }
244
+ ```
245
+
246
+ ### Caveats
247
+
248
+ Hooks give you a lot of flexibility and freedom, but you need to be aware of the following caveats:
249
+
250
+ 1. You need to use an **asynchronous** function. Even if your function is synchronous, it will be called as an asynchronous one—and as you know, there is a performance degradation when using asynchronous operations
251
+ 2. **Stay away** from using ```runHook``` inside a hook! Even though it's possible, your code will become unreadable and messy pretty soon.
252
+ 3. It's hard to trace errors in a hook. Because of its sequential nature, if a handler that's called earlier than yours throws an error, your hook won't be called at all.
253
+ 4. If you use so many plugins that use the hook system so extensively with so many files, your app's boot time can take much longer than it's supposed to.
254
+
255
+ My advice is to **use it wisely**. Don't use hooks unless necessary; this will make your app or plugin clean and easy to understand.
256
+
package/class/base/log.js DELETED
@@ -1,205 +0,0 @@
1
- import os from 'os'
2
- import lodash from 'lodash'
3
- import dayjs from 'dayjs'
4
- import logLevels from '../../lib/log-levels.js'
5
- import chalk from 'chalk'
6
-
7
- const { isEmpty, without, merge } = lodash
8
-
9
- export function isIgnored (level) {
10
- const { filter, isArray } = this.lib._
11
- let ignore = this.app.bajo.config.log.ignore ?? []
12
- if (!isArray(ignore)) ignore = [ignore]
13
- const items = filter(ignore, i => {
14
- const [ns, lvl] = i.split(':')
15
- if (lvl) return ns === this.name && lvl === level
16
- return ns === this.name
17
- })
18
- return items.length > 0
19
- }
20
-
21
- /**
22
- * A thin logger system.
23
- *
24
- * @class
25
- */
26
- class Log {
27
- /**
28
- * @param {Object} plugin - Plugin instance
29
- */
30
- constructor (plugin) {
31
- this.plugin = plugin
32
- this.format = 'YYYY-MM-DDTHH:mm:ss.SSS[Z]'
33
- }
34
-
35
- /**
36
- * Initialize logger. Auto detect to use different logger via Bajo's config file
37
- *
38
- * @method
39
- */
40
- init = () => {
41
- this.bajoLog = this.plugin.app.bajo.config.log.logger ?? 'bajoLogger'
42
- }
43
-
44
- /**
45
- * Interpolate and translate text via plugin's print engine. Check Print class
46
- * for more information
47
- *
48
- * @method
49
- * @param {string} text - Text pattern to use
50
- * @param {...any} [args] - Variables to interpolate with text pattern above
51
- * @returns {string} Interpolated & translated text
52
- */
53
- write = (text, ...args) => {
54
- return this.plugin.print.write(text, ...args)
55
- }
56
-
57
- /**
58
- * Do we use external logger or Bajo's built-in one?
59
- *
60
- * @method
61
- * @returns {boolean}
62
- */
63
- isExtLogger = () => {
64
- return !!(this.plugin.app[this.bajoLog] && this.plugin.app[this.bajoLog].logger)
65
- }
66
-
67
- /**
68
- * Is provided level being ignored by config?
69
- *
70
- * @method
71
- * @param {string} level - Log level
72
- * @returns {boolean}
73
- */
74
- isIgnored = level => {
75
- return isIgnored.call(this.plugin, level)
76
- }
77
-
78
- /**
79
- * Create child logger
80
- *
81
- * @method
82
- * @returns {Object} Child logger instance
83
- */
84
- child = () => {
85
- if (this.isExtLogger()) return this.plugin.app[this.bajoLog].logger.child()
86
- return this.plugin.app
87
- }
88
-
89
- /**
90
- * Display & format message according to one of these rules:
91
- * 1. ```level``` ```text``` ```var 1``` ```var 2``` ```...var n``` - Translate ```text``` and interpolate with ```vars``` for level ```level```
92
- * 2. ```level``` ```data``` ```text``` ```var 1``` ```var 2``` ```...var n``` - As above, and append stringified ```data```
93
- * 3. ```level``` ```error``` - Format as **error**. If current log level is _trace_, dump the error object on screen
94
- *
95
- * @method
96
- * @param {string} level - Log level to use
97
- * @param {...any} params - See format above
98
- */
99
- formatMsg = (level, ...params) => {
100
- if (this.plugin.app.bajo.config.log.level === 'silent') return
101
- if (!this.plugin.app.bajo.isLogInRange(level)) return
102
- const plain = this.plugin.app.bajo.config.log.plain
103
- let [data, msg, ...args] = params
104
- if (typeof data === 'string') {
105
- args.unshift(msg)
106
- msg = data
107
- data = null
108
- }
109
- args = without(args, undefined)
110
- if (data instanceof Error) {
111
- msg = 'error%s'
112
- args = [data.message]
113
- }
114
- msg = this.write(msg, ...args)
115
- if (this.plugin.app[this.bajoLog] && this.plugin.app[this.bajoLog].logger) {
116
- this.plugin.app[this.bajoLog].logger[level](data, `[${this.plugin.name}] ${msg}`, ...args)
117
- } else {
118
- let text
119
- const dt = new Date()
120
- if (this.plugin.app.bajo.config.env === 'prod') {
121
- const json = { level: logLevels[level].number, time: dt.valueOf(), pid: process.pid, hostname: os.hostname() }
122
- if (!isEmpty(data)) merge(json, data)
123
- merge(json, { msg: `[${this.plugin.name}] ${msg}` })
124
- text = JSON.stringify(json)
125
- } else {
126
- const date = dayjs(dt).utc(true).format(this.format)
127
- const tdate = plain ? `[${date}]` : chalk.cyan(date)
128
- const tlevel = plain ? level.toUpperCase() : chalk[logLevels[level].color](level.toUpperCase())
129
- const tplugin = plain ? `[${this.plugin.name}]` : chalk.bgBlue(`${this.plugin.name}`)
130
- text = `${tdate} ${tlevel}: ${tplugin} ${msg}`
131
- if (!isEmpty(data)) text += '\n' + JSON.stringify(data)
132
- }
133
- if (!this.isIgnored(level)) {
134
- console.log(text)
135
- if (data instanceof Error && level === 'trace') console.error(data)
136
- }
137
- }
138
- }
139
-
140
- /**
141
- * Display & format message as ```trace``` level. See {@link Log#formatMsg|formatMsg} for details
142
- *
143
- * @method
144
- * @param {...any} params
145
- */
146
- trace = (...params) => {
147
- this.formatMsg('trace', ...params)
148
- }
149
-
150
- /**
151
- * Display & format message as ```debug``` level. See {@link Log#formatMsg|formatMsg} for details
152
- *
153
- * @method
154
- * @param {...any} params
155
- */
156
- debug = (...params) => {
157
- this.formatMsg('debug', ...params)
158
- }
159
-
160
- /**
161
- * Display & format message as ```info``` level. See {@link Log#formatMsg|formatMsg} for details
162
- *
163
- * @method
164
- * @param {...any} params
165
- */
166
- info = (...params) => {
167
- this.formatMsg('info', ...params)
168
- }
169
-
170
- /**
171
- * Display & format message as ```warn``` level. See {@link Log#formatMsg|formatMsg} for details
172
- *
173
- * @method
174
- * @param {...any} params
175
- */
176
- warn = (...params) => {
177
- this.formatMsg('warn', ...params)
178
- }
179
-
180
- /**
181
- * Display & format message as ```error``` level. See {@link Log#formatMsg|formatMsg} for details
182
- *
183
- * @method
184
- * @param {...any} params
185
- */
186
- error = (...params) => {
187
- this.formatMsg('error', ...params)
188
- }
189
-
190
- /**
191
- * Display & format message as ```fatal``` level. See {@link Log#formatMsg|formatMsg} for details
192
- *
193
- * @method
194
- * @param {...any} params
195
- */
196
- fatal = (...params) => {
197
- this.formatMsg('fatal', ...params)
198
- }
199
-
200
- silent = (...params) => {
201
- this.formatMsg('silent', ...params)
202
- }
203
- }
204
-
205
- export default Log
@@ -1,168 +0,0 @@
1
- import lodash from 'lodash'
2
- import omittedPluginKeys from '../../lib/omitted-plugin-keys.js'
3
- import Log from './log.js'
4
- import Print from './print.js'
5
- import Err from './err.js'
6
- import fastGlob from 'fast-glob'
7
- import { sprintf } from 'sprintf-js'
8
- import outmatch from 'outmatch'
9
- import dayjs from '../../lib/dayjs.js'
10
- import fs from 'fs-extra'
11
- import aneka from 'aneka/index.js'
12
-
13
- function outmatchNs (source, pattern) {
14
- const { breakNsPath } = this.app.bajo
15
- const [src, subSrc] = source.split(':')
16
- if (!subSrc) return pattern === src
17
- try {
18
- const { fullNs, path } = breakNsPath(pattern)
19
- const isMatch = outmatch(path)
20
- return src === fullNs && isMatch(subSrc)
21
- } catch (err) {
22
- return false
23
- }
24
- }
25
-
26
- const lib = {
27
- _: lodash,
28
- fs,
29
- fastGlob,
30
- sprintf,
31
- outmatch,
32
- dayjs,
33
- aneka
34
- }
35
-
36
- const { get, isEmpty, cloneDeep, omit, isPlainObject, camelCase } = lodash
37
-
38
- /**
39
- * This is the base class of bajo's plugin system.
40
- *
41
- * @class
42
- */
43
- class BasePlugin {
44
- /**
45
- * @param {string} pkgName - Package name (the one you use in package.json)
46
- * @param {Object} app - App instance reference. Usefull to call app method inside a plugin
47
- */
48
- constructor (pkgName, app) {
49
- /**
50
- * Package name, the one from package.json
51
- * @type {string}
52
- */
53
- this.pkgName = pkgName
54
-
55
- /**
56
- * Plugin name. Simply the camel cased version of plugin's package name
57
- *
58
- * @type {string}
59
- */
60
- this.name = camelCase(pkgName)
61
-
62
- /**
63
- * Reference to app instance
64
- *
65
- * @type {Object}
66
- */
67
- this.app = app
68
-
69
- /**
70
- * Config object
71
- *
72
- * @type {Object}
73
- */
74
- this.config = {}
75
-
76
- /**
77
- * Property to give you direct access to the most commonly used 3rd party library in a bajo based app.
78
- * No manual import necessary, always available, everywhere, anytime!
79
- *
80
- * Example:
81
- * ```javascript
82
- * const { camelCase, kebabCase } = this.lib._
83
- * console.log(camelCase('Elit commodo sit et aliqua'))
84
- * ```
85
- *
86
- * @type {Object}
87
- * @property {Object} _ - Access to {@link https://lodash.com|lodash}
88
- * @property {Object} fs - Access to {@link https://github.com/jprichardson/node-fs-extra|fs-extra}
89
- * @property {Object} fastGlob - Access to {@link https://github.com/mrmlnc/fast-glob|fast-glob}
90
- * @property {Object} sprintf - Access to {@link https://github.com/alexei/sprintf.js|sprintf}
91
- * @property {Object} aneka - Access to {@link https://github.com/ardhi/aneka|aneka}
92
- * @property {Object} outmatch - Access to {@link https://github.com/axtgr/outmatch|outmatch}
93
- * @property {Object} dayjs - Access to {@link https://day.js.org|dayjs} with utc & customParseFormat plugin already applied
94
- */
95
- this.lib = lib
96
- this.lib.outmatchNs = outmatchNs.bind(this)
97
- }
98
-
99
- /**
100
- * Get plugin's config value
101
- *
102
- * @method
103
- * @param {string} [path] - dot separated config path (think of lodash's 'get'). If not provided, the full config will be given
104
- * @param {Object} [options={}] - Options
105
- * @param {any} [options.defValue={}] - Default value to use if returned object is undefined
106
- * @param {string[]} [options.omit=[]] - Omit these keys from returned object
107
- * @param {boolean} [options.noClone=false] - Set true to NOT clone returned object
108
- * @returns {Object} Returned object. If no path provided, the whole config object is returned
109
- */
110
- getConfig = (path, options = {}) => {
111
- let obj = isEmpty(path) ? this.config : get(this.config, path, options.defValue ?? {})
112
- options.omit = options.omit ?? omittedPluginKeys
113
- if (isPlainObject(obj) && !isEmpty(options.omit)) obj = omit(obj, options.omit)
114
- if (!options.noClone) obj = cloneDeep(obj)
115
- return obj
116
- }
117
-
118
- /**
119
- * Initialize log. Please refer to {@link Log} class for more info
120
- *
121
- * @method
122
- */
123
- initLog = () => {
124
- this.log = new Log(this)
125
- this.log.init()
126
- }
127
-
128
- /**
129
- * Initialize print engine. Please refer to {@link Print} class for more info
130
- *
131
- * @method
132
- * @param {Object} [options] - Print options
133
- */
134
- initPrint = (options) => {
135
- this.print = new Print(this, options)
136
- this.print.init()
137
- }
138
-
139
- /**
140
- * Create an instance of {@link Err} object
141
- *
142
- * @method
143
- * @param {msg} msg - Error message
144
- * @param {...any} [args] - Argument variables you might want to add to the error object
145
- * @returns {Object} Err instance
146
- */
147
- error = (msg, ...args) => {
148
- if (!this.print) return new Error(msg, ...args)
149
- const error = new Err(this, msg, ...args)
150
- return error.write()
151
- }
152
-
153
- /**
154
- * Create an instance of Err object, display it on screen and then force
155
- * terminate the app process
156
- *
157
- * @method
158
- * @param {msg} msg - Error message
159
- * @param {...any} [args] - Argument variables you might want to add to the error object
160
- */
161
- fatal = (msg, ...args) => {
162
- if (!this.print) return new Error(msg, ...args)
163
- const error = new Err(this, msg, ...args)
164
- error.fatal()
165
- }
166
- }
167
-
168
- export default BasePlugin