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.
- package/.github/FUNDING.yml +13 -0
- package/.github/workflows/repo-lockdown.yml +24 -0
- package/.jsdoc.conf.json +7 -6
- package/LICENSE +1 -1
- package/README.md +50 -18
- package/class/app.js +378 -54
- package/class/bajo.js +228 -149
- package/class/base.js +106 -0
- package/class/helper/bajo.js +146 -90
- package/class/helper/{plugin.js → base.js} +96 -22
- package/class/{base → misc}/err.js +44 -14
- package/class/misc/log.js +255 -0
- package/class/misc/print.js +264 -0
- package/class/plugin.js +120 -68
- package/docs/App.html +23 -1
- package/docs/Bajo.html +2 -9
- package/docs/Base.html +3 -0
- package/docs/Err.html +3 -1
- package/docs/Log.html +5 -1
- package/docs/Plugin.html +1 -1
- package/docs/Print.html +1 -1
- package/docs/class_app.js.html +378 -56
- package/docs/class_bajo.js.html +230 -151
- package/docs/class_base.js.html +109 -0
- package/docs/class_helper_bajo.js.html +138 -87
- package/docs/class_helper_base.js.html +246 -0
- package/docs/class_misc_err.js.html +129 -0
- package/docs/class_misc_log.js.html +210 -0
- package/docs/class_misc_print.js.html +267 -0
- package/docs/class_plugin.js.html +122 -70
- package/docs/data/search.json +1 -1
- package/docs/global.html +4 -1
- package/docs/index.html +2 -2
- package/docs/index.js.html +35 -0
- package/docs/lib_current-loc.js.html +36 -0
- package/docs/lib_formats.js.html +8 -8
- package/docs/lib_import-module.js.html +59 -0
- package/docs/lib_log-levels.js.html +17 -7
- package/docs/lib_parse-args-argv.js.html +83 -0
- package/docs/lib_parse-env.js.html +53 -0
- package/docs/lib_resolve-path.js.html +3 -6
- package/docs/lib_shim.js.html +8 -3
- package/docs/module-Helper_Bajo.html +3 -0
- package/docs/module-Helper_Base.html +3 -0
- package/docs/module-Lib.html +15 -0
- package/docs/static/home.md +32 -0
- package/docs/static/logo-ecosystem.png +0 -0
- package/docs/static/logo.png +0 -0
- package/extend/bajo/intl/en-US.json +9 -2
- package/extend/bajo/intl/id.json +9 -2
- package/index.js +22 -2
- package/lib/current-loc.js +24 -2
- package/lib/formats.js +6 -6
- package/lib/import-module.js +29 -0
- package/lib/log-levels.js +15 -5
- package/lib/parse-args-argv.js +20 -12
- package/lib/parse-env.js +18 -7
- package/lib/resolve-path.js +1 -4
- package/lib/shim.js +6 -1
- package/package.json +4 -7
- package/wiki/CONFIG.md +36 -0
- package/wiki/CONTRIBUTING.md +5 -0
- package/wiki/DEV_GUIDE.md +3 -0
- package/wiki/ECOSYSTEM.md +93 -0
- package/wiki/GETTING-STARTED.md +356 -0
- package/wiki/USER-GUIDE.md +256 -0
- package/class/base/log.js +0 -205
- package/class/base/plugin.js +0 -168
- package/class/base/print.js +0 -272
- package/docs/BasePlugin.html +0 -5
- package/docs/class_base_err.js.html +0 -99
- package/docs/class_base_log.js.html +0 -208
- package/docs/class_base_plugin.js.html +0 -180
- package/docs/class_base_print.js.html +0 -275
- package/docs/class_helper_plugin.js.html +0 -172
- package/docs/lib_create-method.js.html +0 -42
- package/docs/module-class_helper_bajo.html +0 -3
- package/docs/module-class_helper_plugin.html +0 -3
- package/docs/module-lib_create-method.html +0 -3
- package/docs/module-lib_formats.html +0 -3
- package/docs/module-lib_log-levels.html +0 -3
- package/docs/module-lib_resolve-path.html +0 -3
- package/docs/module-lib_shim.html +0 -3
- package/docs/tutorial-contribution.html +0 -3
- package/docs/tutorial-ecosystem.html +0 -3
- package/docs/tutorial-getting-started.html +0 -13
- package/docs/tutorial-plugin-dev.html +0 -3
- package/docs/tutorial-user-guide.html +0 -3
- package/lib/create-method.js +0 -39
- package/lib/dayjs.js +0 -8
- package/lib/omitted-plugin-keys.js +0 -3
- package/lib/read-all-configs.js +0 -19
- package/misc-docs/.hook.md +0 -11
- package/misc-docs/bitcoin.jpeg +0 -0
- package/misc-docs/contribution.md +0 -20
- package/misc-docs/ecosystem.md +0 -94
- package/misc-docs/getting-started.md +0 -142
- package/misc-docs/plugin-dev.md +0 -0
- package/misc-docs/toc.json +0 -17
- package/misc-docs/user-guide.md +0 -1
- /package/docs/{bitcoin.jpeg → static/bitcoin.jpeg} +0 -0
package/class/bajo.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Plugin from './plugin.js'
|
|
2
|
-
import BasePlugin from './base/plugin.js'
|
|
3
2
|
import increment from 'add-filename-increment'
|
|
4
3
|
import fs from 'fs-extra'
|
|
5
4
|
import path from 'path'
|
|
@@ -19,6 +18,15 @@ import resolvePath from '../lib/resolve-path.js'
|
|
|
19
18
|
import importModule from '../lib/import-module.js'
|
|
20
19
|
import logLevels from '../lib/log-levels.js'
|
|
21
20
|
import { types as formatTypes, formats } from '../lib/formats.js'
|
|
21
|
+
import {
|
|
22
|
+
buildBaseConfig,
|
|
23
|
+
buildExtConfig,
|
|
24
|
+
buildPlugins,
|
|
25
|
+
collectConfigHandlers,
|
|
26
|
+
bootOrder,
|
|
27
|
+
bootPlugins,
|
|
28
|
+
exitHandler
|
|
29
|
+
} from './helper/bajo.js'
|
|
22
30
|
|
|
23
31
|
const require = createRequire(import.meta.url)
|
|
24
32
|
|
|
@@ -31,67 +39,30 @@ const {
|
|
|
31
39
|
|
|
32
40
|
/**
|
|
33
41
|
* The Core. The main engine. The one and only plugin that control app's boot process and
|
|
34
|
-
* making sure all other plugins working
|
|
42
|
+
* making sure all other plugins working nicely.
|
|
35
43
|
*
|
|
36
44
|
* @class
|
|
37
45
|
*/
|
|
38
|
-
class Bajo extends
|
|
46
|
+
class Bajo extends Plugin {
|
|
47
|
+
static alias = 'bajo'
|
|
39
48
|
/**
|
|
40
|
-
* @param {
|
|
41
|
-
* @param {Object} app - App instance reference. Usefull to call app method inside a plugin
|
|
49
|
+
* @param {App} app - App instance. Usefull to call app method inside a plugin
|
|
42
50
|
*/
|
|
43
51
|
constructor (app) {
|
|
44
52
|
super('bajo', app)
|
|
53
|
+
this.whiteSpace = [' ', '\t', '\n', '\r']
|
|
45
54
|
/**
|
|
46
|
-
*
|
|
47
|
-
* @type {Date}
|
|
48
|
-
*/
|
|
49
|
-
this.runAt = new Date()
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Your main namespace. And yes, you suppose NOT to change this
|
|
53
|
-
*
|
|
54
|
-
* @type {string}
|
|
55
|
-
*/
|
|
56
|
-
this.mainNs = 'main'
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Storage for applets
|
|
60
|
-
*
|
|
61
|
-
* @type {Array}
|
|
62
|
-
*/
|
|
63
|
-
this.applets = []
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* List of all loaded plugin's package names
|
|
67
|
-
*
|
|
68
|
-
* @type {Array}
|
|
69
|
-
*/
|
|
70
|
-
this.pluginPkgs = []
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* List of all loaded plugin's names
|
|
55
|
+
* Config object
|
|
74
56
|
*
|
|
75
|
-
* @type {
|
|
57
|
+
* @type {Object}
|
|
58
|
+
* @see {@tutorial config}
|
|
76
59
|
*/
|
|
77
|
-
this.
|
|
60
|
+
this.config = {}
|
|
78
61
|
|
|
79
|
-
|
|
80
|
-
* Storage for config handlers. By default there are only two handlers available: ```.js```
|
|
81
|
-
* and ```.json```.
|
|
82
|
-
*
|
|
83
|
-
* Use plugin to add more type - e.g: {@link https://github.com/ardhi/bajo-config|bajo-config}
|
|
84
|
-
* lets you to use ```.yaml``` and ```.toml```
|
|
85
|
-
*
|
|
86
|
-
* @type {Array}
|
|
87
|
-
*/
|
|
88
|
-
this.configHandlers = [
|
|
62
|
+
app.configHandlers = [
|
|
89
63
|
{ ext: '.js', readHandler: this._defConfigHandler },
|
|
90
|
-
{ ext: '.json', readHandler: this.
|
|
64
|
+
{ ext: '.json', readHandler: this.fromJson, writeHandler: this.toJson }
|
|
91
65
|
]
|
|
92
|
-
this.whiteSpace = [' ', '\t', '\n', '\r']
|
|
93
|
-
this.envs = { dev: 'development', staging: 'staging', prod: 'production' }
|
|
94
|
-
this.lib.Plugin = Plugin
|
|
95
66
|
}
|
|
96
67
|
|
|
97
68
|
async _defConfigHandler (file, opts = {}) {
|
|
@@ -100,6 +71,30 @@ class Bajo extends BasePlugin {
|
|
|
100
71
|
return mod
|
|
101
72
|
}
|
|
102
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Initialization:
|
|
76
|
+
*
|
|
77
|
+
* 1. Building {@link module:Helper/Bajo.buildBaseConfig|base config}
|
|
78
|
+
* 2. {@link module:Helper/Bajo.buildPlugins|Building plugins}
|
|
79
|
+
* 3. Collect all {@link module:Helper/Bajo.collectConfigHandlers|config handler}
|
|
80
|
+
* 4. Building {@link module:Helper/Bajo.buildExtConfig|extra config}
|
|
81
|
+
* 5. Setup {@link module:Helper/Bajo.bootOrder|boot order}
|
|
82
|
+
* 6. {@link module:Helper/Bajo.bootPlugins|Boot loaded plugins}
|
|
83
|
+
* 7. Attach {@link module:Helper/Bajo.exitHandler|exit handlers}
|
|
84
|
+
*
|
|
85
|
+
* @method
|
|
86
|
+
* @async
|
|
87
|
+
*/
|
|
88
|
+
init = async () => {
|
|
89
|
+
await buildBaseConfig.call(this)
|
|
90
|
+
await collectConfigHandlers.call(this)
|
|
91
|
+
await buildExtConfig.call(this)
|
|
92
|
+
await buildPlugins.call(this)
|
|
93
|
+
await bootOrder.call(this)
|
|
94
|
+
await bootPlugins.call(this)
|
|
95
|
+
await exitHandler.call(this)
|
|
96
|
+
}
|
|
97
|
+
|
|
103
98
|
/**
|
|
104
99
|
* Resolve file name to filesystem's path. Windows path separator ```\```
|
|
105
100
|
* is normalized to Unix's ```/```
|
|
@@ -117,10 +112,10 @@ class Bajo extends BasePlugin {
|
|
|
117
112
|
* Freeze object
|
|
118
113
|
*
|
|
119
114
|
* @method
|
|
120
|
-
* @param {Object} obj - Object
|
|
121
|
-
* @param {boolean} [shallow=false] - If
|
|
115
|
+
* @param {Object} obj - Object to freeze
|
|
116
|
+
* @param {boolean} [shallow=false] - If ```false``` (default), deep freeze object
|
|
122
117
|
*/
|
|
123
|
-
freeze = (obj, shallow) => {
|
|
118
|
+
freeze = (obj, shallow = false) => {
|
|
124
119
|
if (shallow) Object.freeze(obj)
|
|
125
120
|
else deepFreeze(obj)
|
|
126
121
|
}
|
|
@@ -151,6 +146,25 @@ class Bajo extends BasePlugin {
|
|
|
151
146
|
return { ns, subNs, path: _path, fullNs: names.join('.'), type }
|
|
152
147
|
}
|
|
153
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Name based ```{ns}:{path}``` format
|
|
151
|
+
* @typedef {string} TNsPathPairs
|
|
152
|
+
* @see TNsPathResult
|
|
153
|
+
* @see Bajo#buildNsPath
|
|
154
|
+
* @see Bajo#breakNsPath
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Build ns/path pairs
|
|
159
|
+
*
|
|
160
|
+
* @method
|
|
161
|
+
* @param {object} [options={}] - Options object
|
|
162
|
+
* @param {string} [options.ns=''] - Namespace
|
|
163
|
+
* @param {string} [options.subNs] - Sub namespace
|
|
164
|
+
* @param {string} [options.subSubNs] - Sub sub namespace
|
|
165
|
+
* @param {string} [options.path] - Path
|
|
166
|
+
* @returns {TNsPathPairs} - Ns/path pairs
|
|
167
|
+
*/
|
|
154
168
|
buildNsPath = ({ ns = '', subNs, subSubNs, path } = {}) => {
|
|
155
169
|
if (subNs) ns += '.' + subNs
|
|
156
170
|
if (subSubNs) ns += '.' + subSubNs
|
|
@@ -158,23 +172,26 @@ class Bajo extends BasePlugin {
|
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
/**
|
|
161
|
-
* Object returned by {@link
|
|
175
|
+
* Object returned by {@link Bajo#breakNsPath|bajo:breakNsPath}
|
|
162
176
|
*
|
|
163
|
-
* @typedef {Object}
|
|
177
|
+
* @typedef {Object} TNsPathResult
|
|
164
178
|
* @property {string} ns - Namespace
|
|
165
179
|
* @property {string} [subNs] - Sub namespace
|
|
166
180
|
* @property {string} [subSubNs] - Sub of sub namespace
|
|
167
181
|
* @property {string} path - Path without query string or hash
|
|
168
182
|
* @property {string} fullPath - Full path, including query string and hash
|
|
183
|
+
* @see TNsPathPairs
|
|
184
|
+
* @see Bajo#buildNsPath
|
|
185
|
+
* @see Bajo#breakNsPath
|
|
169
186
|
*/
|
|
170
187
|
|
|
171
188
|
/**
|
|
172
189
|
* Break name to its namespace & path infos
|
|
173
190
|
*
|
|
174
191
|
* @method
|
|
175
|
-
* @param {string} name - Name to break
|
|
176
|
-
* @param {boolean} [checkNs=true] - If true (default), namespace will be checked for its validity
|
|
177
|
-
* @returns {
|
|
192
|
+
* @param {(TNsPathPairs|string)} name - Name to break
|
|
193
|
+
* @param {boolean} [checkNs=true] - If ```true``` (default), namespace will be checked for its validity
|
|
194
|
+
* @returns {TNsPathResult}
|
|
178
195
|
*/
|
|
179
196
|
breakNsPath = (name = '', checkNs = true) => {
|
|
180
197
|
let [ns, ...path] = name.split(':')
|
|
@@ -190,7 +207,7 @@ class Bajo extends BasePlugin {
|
|
|
190
207
|
if (checkNs) {
|
|
191
208
|
if (!this.app[ns]) {
|
|
192
209
|
const plugin = this.getPlugin(ns)
|
|
193
|
-
if (plugin) ns = plugin.
|
|
210
|
+
if (plugin) ns = plugin.ns
|
|
194
211
|
}
|
|
195
212
|
if (!this.app[ns]) throw this.error('unknownPluginOrNotLoaded%s')
|
|
196
213
|
}
|
|
@@ -222,31 +239,39 @@ class Bajo extends BasePlugin {
|
|
|
222
239
|
}
|
|
223
240
|
|
|
224
241
|
/**
|
|
225
|
-
* Method to transform
|
|
226
|
-
*
|
|
227
|
-
* Emitted hooks:
|
|
228
|
-
* 1. ```{ns}:beforeBuildCollection (container)``` - called before collection is built
|
|
229
|
-
* 2. ```{ns}:afterBuildCollection (container, items)``` - called after collection is built
|
|
242
|
+
* Method to transform config's array or object into an array of collection.
|
|
230
243
|
*
|
|
231
244
|
* @method
|
|
232
245
|
* @async
|
|
233
246
|
* @param {Object} options - Options
|
|
234
247
|
* @param {string} [options.ns] - Namespace. If not provided, defaults to ```bajo```
|
|
235
248
|
* @param {function} [options.handler] - Handler to call while building the collection item
|
|
236
|
-
* @param {
|
|
249
|
+
* @param {string[]} [options.dupChecks=[]] - Array of keys to check for duplicates
|
|
237
250
|
* @param {string} options.container - Key used as container name
|
|
238
251
|
* @param {boolean} [options.useDefaultName=true] - If true (default) and ```name``` key is not provided, returned collection will be named ```default```
|
|
239
|
-
* @
|
|
252
|
+
* @fires bajo:beforeBuildCollection
|
|
253
|
+
* @fires bajo:afterBuildCollection
|
|
254
|
+
* @returns {Object[]} The collection
|
|
240
255
|
*/
|
|
241
256
|
buildCollections = async (options = {}) => {
|
|
242
257
|
let { ns, handler, dupChecks = [], container, useDefaultName } = options
|
|
243
258
|
useDefaultName = useDefaultName ?? true
|
|
244
|
-
if (!ns) ns = this.
|
|
259
|
+
if (!ns) ns = this.ns
|
|
245
260
|
const cfg = this.app[ns].getConfig()
|
|
246
261
|
let items = get(cfg, container, [])
|
|
247
262
|
if (!isArray(items)) items = [items]
|
|
248
|
-
this.app[ns].log.trace('collecting%s', this.
|
|
249
|
-
|
|
263
|
+
this.app[ns].log.trace('collecting%s', this.t(container))
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Run before collection is built
|
|
267
|
+
*
|
|
268
|
+
* @global
|
|
269
|
+
* @event bajo:beforeBuildCollection
|
|
270
|
+
* @param {string} container
|
|
271
|
+
* @see {@tutorial hook}
|
|
272
|
+
* @see Bajo#buildCollections
|
|
273
|
+
*/
|
|
274
|
+
await this.runHook(`${ns}:beforeBuildCollection`, container)
|
|
250
275
|
const deleted = []
|
|
251
276
|
for (const index in items) {
|
|
252
277
|
const item = items[index]
|
|
@@ -260,7 +285,7 @@ class Bajo extends BasePlugin {
|
|
|
260
285
|
const result = await handler.call(this.app[ns], { item, index, cfg })
|
|
261
286
|
if (result) items[index] = result
|
|
262
287
|
else if (result === false) deleted.push(index)
|
|
263
|
-
if (this.app.
|
|
288
|
+
if (this.app.applet && item.skipOnApplet && !deleted.includes(index)) deleted.push(index)
|
|
264
289
|
}
|
|
265
290
|
if (deleted.length > 0) pullAt(items, deleted)
|
|
266
291
|
|
|
@@ -272,13 +297,25 @@ class Bajo extends BasePlugin {
|
|
|
272
297
|
if (checkers.includes(checker)) this.app[ns].fatal('oneOrMoreSharedTheSame%s%s', container, this.join(dupChecks.filter(i => !isFunction(i))))
|
|
273
298
|
}
|
|
274
299
|
}
|
|
275
|
-
|
|
276
|
-
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Run after collection is built
|
|
303
|
+
*
|
|
304
|
+
* @global
|
|
305
|
+
* @event bajo:afterBuildCollection
|
|
306
|
+
* @param {string} container
|
|
307
|
+
* @param {Object[]} items
|
|
308
|
+
* @see {@tutorial hook}
|
|
309
|
+
* @see Bajo#buildCollections
|
|
310
|
+
*/
|
|
311
|
+
await this.runHook(`${ns}:afterBuildCollection`, container, items)
|
|
312
|
+
this.app[ns].log.debug('collected%s%d', this.t(container), items.length)
|
|
277
313
|
return items
|
|
278
314
|
}
|
|
279
315
|
|
|
280
316
|
/**
|
|
281
|
-
* Calling any plugin's method by its name
|
|
317
|
+
* Calling any plugin's method by its name:
|
|
318
|
+
*
|
|
282
319
|
* - If name is a string, the corresponding plugin's method will be called with passed args as its parameters
|
|
283
320
|
* - If name is a plugin instance, this will be used as the scope instead. The first args is now the handler name and the rest are its parameters
|
|
284
321
|
* - If name is a function, this function will be run under scope with the remaining args
|
|
@@ -286,7 +323,7 @@ class Bajo extends BasePlugin {
|
|
|
286
323
|
*
|
|
287
324
|
* @method
|
|
288
325
|
* @async
|
|
289
|
-
* @param {(
|
|
326
|
+
* @param {(TNsPathPairs|Object|function)} name - Method's name, function handler, plain object or plugin instance
|
|
290
327
|
* @param {...any} [args] - One or more arguments passed as parameter to the handler
|
|
291
328
|
* @returns {any} Returned value
|
|
292
329
|
*/
|
|
@@ -299,10 +336,10 @@ class Bajo extends BasePlugin {
|
|
|
299
336
|
}
|
|
300
337
|
const bajo = scope.app.bajo
|
|
301
338
|
if (isString(item)) {
|
|
302
|
-
if (item.startsWith('applet:') && bajo.applets.length > 0) {
|
|
339
|
+
if (item.startsWith('applet:') && bajo.app.applets.length > 0) {
|
|
303
340
|
const [, ns, path] = item.split(':')
|
|
304
|
-
const applet = find(bajo.applets, a => (a.ns === ns || a.alias === ns))
|
|
305
|
-
if (applet) result = await
|
|
341
|
+
const applet = find(bajo.app.applets, a => (a.ns === ns || a.alias === ns))
|
|
342
|
+
if (applet && scope.app.bajoCli) result = await scope.app.bajoCli.runApplet(applet, path, ...args)
|
|
306
343
|
} else {
|
|
307
344
|
const [ns, method, ...params] = item.split(':')
|
|
308
345
|
const fn = bajo.getMethod(`${ns}:${method}`)
|
|
@@ -330,7 +367,7 @@ class Bajo extends BasePlugin {
|
|
|
330
367
|
* @async
|
|
331
368
|
* @param {function} handler - Function handler. Can be an async function. Scoped to the running plugin
|
|
332
369
|
* @param {(string|Object)} [options={}] - Options. If a string is provided, it serves as the glob pattern, otherwise:
|
|
333
|
-
* @param {(string|
|
|
370
|
+
* @param {(string|string[])} [options.glob] - Glob pattern. If provided,
|
|
334
371
|
* @param {boolean} [options.useBajo=false] - If true, add ```bajo``` to the running plugins too
|
|
335
372
|
* @param {string} [options.prefix=''] - Prepend glob pattern with prefix
|
|
336
373
|
* @param {boolean} [options.noUnderscore=true] - If true (default), matched file with name starts with underscore is ignored
|
|
@@ -340,7 +377,7 @@ class Bajo extends BasePlugin {
|
|
|
340
377
|
eachPlugins = async (handler, options = {}) => {
|
|
341
378
|
if (typeof options === 'string') options = { glob: options }
|
|
342
379
|
const result = {}
|
|
343
|
-
const pluginPkgs = cloneDeep(this.app.
|
|
380
|
+
const pluginPkgs = cloneDeep(this.app.pluginPkgs) ?? []
|
|
344
381
|
const { glob, useBajo, prefix = '', noUnderscore = true, returnItems } = options
|
|
345
382
|
if (useBajo) pluginPkgs.unshift('bajo')
|
|
346
383
|
for (const pkgName of pluginPkgs) {
|
|
@@ -386,11 +423,12 @@ class Bajo extends BasePlugin {
|
|
|
386
423
|
}
|
|
387
424
|
|
|
388
425
|
/**
|
|
389
|
-
* Object returned by {@link
|
|
426
|
+
* Object returned by {@link Bajo#getUnitFormat|bajo:getUnitFormat}
|
|
390
427
|
*
|
|
391
|
-
* @typedef {Object}
|
|
428
|
+
* @typedef {Object} TBajoFormatResult
|
|
392
429
|
* @property {string} unitSys - Unit system
|
|
393
430
|
* @property {Object} format - Format object
|
|
431
|
+
* @see Bajo#getUnitFormat
|
|
394
432
|
*/
|
|
395
433
|
|
|
396
434
|
/**
|
|
@@ -400,7 +438,7 @@ class Bajo extends BasePlugin {
|
|
|
400
438
|
* @param {Object} [options={}] - Options
|
|
401
439
|
* @param {string} [options.lang] - Language to use. Defaults to the one you set in config
|
|
402
440
|
* @param {string} [options.unitSys] - Unit system to use. Defaults to language's unit system or ```metric``` if unspecified
|
|
403
|
-
* @returns {
|
|
441
|
+
* @returns {TBajoFormatResult} - Returned value
|
|
404
442
|
*/
|
|
405
443
|
getUnitFormat = (options = {}) => {
|
|
406
444
|
const lang = options.lang ?? this.config.lang
|
|
@@ -413,16 +451,16 @@ class Bajo extends BasePlugin {
|
|
|
413
451
|
* Format value by type
|
|
414
452
|
*
|
|
415
453
|
* @method
|
|
416
|
-
* @param {string} type - Format type. See {@link
|
|
454
|
+
* @param {string} type - Format type. See {@link TBajoFormatType} for acceptable values
|
|
417
455
|
* @param {any} value - Value to format
|
|
418
|
-
* @param {string} [dataType] - Value's data type. See {@link
|
|
456
|
+
* @param {string} [dataType] - Value's data type. See {@link TBajoDataType} for acceptable values
|
|
419
457
|
* @param {Object} [options={}] - Options
|
|
420
458
|
* @param {boolean} [options.withUnit=true] - Return with its unit appended
|
|
421
459
|
* @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config
|
|
422
460
|
* @returns {(Array|string)} Return string if ```withUnit``` is true. Otherwise is an array of ```[value, unit, separator]```
|
|
423
461
|
*/
|
|
424
462
|
formatByType = (type, value, dataType, options = {}) => {
|
|
425
|
-
const { defaultsDeep } = this.lib.aneka
|
|
463
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
426
464
|
const { format } = this.getUnitFormat(options)
|
|
427
465
|
const { withUnit = true } = options
|
|
428
466
|
const lang = options.lang ?? this.config.lang
|
|
@@ -440,7 +478,7 @@ class Bajo extends BasePlugin {
|
|
|
440
478
|
*
|
|
441
479
|
* @method
|
|
442
480
|
* @param {any} value - Value to format
|
|
443
|
-
* @param {string} [type] - Data type to use. See {@link
|
|
481
|
+
* @param {string} [type] - Data type to use. See {@link TBajoDataType} for acceptable values. If not provided, return the untouched value
|
|
444
482
|
* @param {Object} [options={}] - Options
|
|
445
483
|
* @param {string} [options.emptyValue=''] - Empty value to use if function resulted empty. Defaults to the one from your config
|
|
446
484
|
* @param {boolean} [options.withUnit=true] - Return with its unit appended
|
|
@@ -450,7 +488,7 @@ class Bajo extends BasePlugin {
|
|
|
450
488
|
* @returns {string} Formatted value
|
|
451
489
|
*/
|
|
452
490
|
format = (value, type, options = {}) => {
|
|
453
|
-
const { defaultsDeep } = this.lib.aneka
|
|
491
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
454
492
|
const { format } = this.config.intl
|
|
455
493
|
const { emptyValue = format.emptyValue } = options
|
|
456
494
|
const lang = options.lang ?? this.config.lang
|
|
@@ -461,7 +499,7 @@ class Bajo extends BasePlugin {
|
|
|
461
499
|
if (value instanceof Date) type = 'datetime'
|
|
462
500
|
}
|
|
463
501
|
if (['float', 'double'].includes(type) && this.app.bajoSpatial) {
|
|
464
|
-
const { latToDms, lngToDms } = this.app.
|
|
502
|
+
const { latToDms, lngToDms } = this.app.lib.anekaSpatial
|
|
465
503
|
if (options.latitude) return latToDms(value)
|
|
466
504
|
if (options.longitude) return lngToDms(value)
|
|
467
505
|
}
|
|
@@ -594,7 +632,7 @@ class Bajo extends BasePlugin {
|
|
|
594
632
|
*
|
|
595
633
|
* @method
|
|
596
634
|
* @param {string} pkgName - Package name to find
|
|
597
|
-
* @param {
|
|
635
|
+
* @param {string} base - Provide base name if ```pkgName``` is a module under ```base```'s package name
|
|
598
636
|
* @returns {string} Return absolute package directory
|
|
599
637
|
*/
|
|
600
638
|
getModuleDir = (pkgName, base) => {
|
|
@@ -622,7 +660,7 @@ class Bajo extends BasePlugin {
|
|
|
622
660
|
*/
|
|
623
661
|
getPluginDataDir = (name, ensureDir = true) => {
|
|
624
662
|
const plugin = this.getPlugin(name)
|
|
625
|
-
const dir = `${this.app.bajo.dir.data}/plugins/${plugin.
|
|
663
|
+
const dir = `${this.app.bajo.dir.data}/plugins/${plugin.ns}`
|
|
626
664
|
if (ensureDir) fs.ensureDirSync(dir)
|
|
627
665
|
return dir
|
|
628
666
|
}
|
|
@@ -631,7 +669,7 @@ class Bajo extends BasePlugin {
|
|
|
631
669
|
* Resolve file path from:
|
|
632
670
|
*
|
|
633
671
|
* - local/absolute file
|
|
634
|
-
* -
|
|
672
|
+
* - TNsPath (```myPlugin:/path/to/file.txt```)
|
|
635
673
|
*
|
|
636
674
|
* @method
|
|
637
675
|
* @param {string} file - File path, see above for supported types
|
|
@@ -673,46 +711,38 @@ class Bajo extends BasePlugin {
|
|
|
673
711
|
if (silent) return false
|
|
674
712
|
throw this.error('pluginWithNameAliasNotLoaded%s', name)
|
|
675
713
|
}
|
|
676
|
-
name = plugin.
|
|
714
|
+
name = plugin.ns
|
|
677
715
|
}
|
|
678
716
|
return this.app[name]
|
|
679
717
|
}
|
|
680
718
|
|
|
681
719
|
/**
|
|
682
|
-
* Import file/module from any loaded plugins
|
|
720
|
+
* Import file/module from any loaded plugins.
|
|
683
721
|
*
|
|
684
|
-
*
|
|
685
|
-
* ```
|
|
686
|
-
* |- src
|
|
687
|
-
* | |- lib
|
|
688
|
-
* | | |- my-module.js
|
|
689
|
-
* |- index.js
|
|
690
|
-
* |- package.json
|
|
691
|
-
* ```
|
|
722
|
+
* Method proxy from {@link module:Lib.importModule}
|
|
692
723
|
*
|
|
693
|
-
* Inside your app/plugin:
|
|
694
|
-
* ```javascript
|
|
695
|
-
* const { importModule } = this.app.bajo
|
|
696
|
-
* const myModule = await importModule('myPlugin:/src/lib/my-module.js')
|
|
697
|
-
* ```
|
|
698
724
|
* @method
|
|
699
725
|
* @async
|
|
700
|
-
* @
|
|
701
|
-
* @param {Object} [options={}] - Options
|
|
702
|
-
* @param {boolean} [options.asDefaultImport=true] - If ```true``` (default), return default imported module
|
|
703
|
-
* @param {boolean} [options.asHandler] - If ```true```, return as a {@link HandlerType|handler}
|
|
704
|
-
* @param {boolean} [options.noCache] - If ```true```, always import as a fresh copy
|
|
705
|
-
* @returns {(function|Object)}
|
|
726
|
+
* @see module:Lib.importModule
|
|
706
727
|
*/
|
|
707
728
|
importModule = async (file, { asDefaultImport, asHandler, noCache } = {}) => {
|
|
708
729
|
return await importModule.call(this, file, { asDefaultImport, asHandler, noCache })
|
|
709
730
|
}
|
|
710
731
|
|
|
711
732
|
/**
|
|
712
|
-
* Import one or more
|
|
733
|
+
* Import one or more packages belongs to a plugin.
|
|
734
|
+
*
|
|
735
|
+
* If the last arguments passed is an object, this object serves as options object:
|
|
736
|
+
* - ```returnDefault```: should return package's default export. Defaults to ```true```
|
|
737
|
+
* - ```throwNotFound```: should throw if package is not found. Defaults to ```false```
|
|
738
|
+
* - ```noCache```: always use fresh import. Defaults to ```false```
|
|
739
|
+
* - ```asObject```: see below. Defaults to ```false```
|
|
713
740
|
*
|
|
714
|
-
*
|
|
741
|
+
* Return value:
|
|
742
|
+
* - if ```options.asObject``` is ```true``` (default ```false```), return as object with package's names as it's keys
|
|
743
|
+
* - Otherwise depends on how many parameters are provided, it should return the named package or an array of packages
|
|
715
744
|
*
|
|
745
|
+
* Example: you want to import ```delay``` and ```chalk``` from ```bajo``` plugin because you want to use it in your code
|
|
716
746
|
* ```javascript
|
|
717
747
|
* const { importPkg } from this.app.bajo
|
|
718
748
|
* const [delay, chalk] = await importPkg('bajo:delay', 'bajo:chalk')
|
|
@@ -723,14 +753,14 @@ class Bajo extends BasePlugin {
|
|
|
723
753
|
*
|
|
724
754
|
* @method
|
|
725
755
|
* @async
|
|
726
|
-
* @param {...
|
|
727
|
-
* @returns {(Object|Array)}
|
|
756
|
+
* @param {...TNsPathPairs} pkgs - One or more packages in format ```{ns}:{packageName}```
|
|
757
|
+
* @returns {(Object|Array)} See above
|
|
728
758
|
*/
|
|
729
759
|
importPkg = async (...pkgs) => {
|
|
730
|
-
const { defaultsDeep } = this.lib.aneka
|
|
760
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
731
761
|
const result = {}
|
|
732
762
|
const notFound = []
|
|
733
|
-
let opts = { returnDefault: true,
|
|
763
|
+
let opts = { returnDefault: true, throwNotFound: false }
|
|
734
764
|
if (isPlainObject(last(pkgs))) {
|
|
735
765
|
opts = defaultsDeep(pkgs.pop(), opts)
|
|
736
766
|
}
|
|
@@ -742,7 +772,7 @@ class Bajo extends BasePlugin {
|
|
|
742
772
|
notFound.push(pkg)
|
|
743
773
|
continue
|
|
744
774
|
}
|
|
745
|
-
const p = this.readJson(`${dir}/package.json`, opts.
|
|
775
|
+
const p = this.readJson(`${dir}/package.json`, opts.throwNotFound)
|
|
746
776
|
const mainFileOrg = dir + '/' + (p.main ?? get(p, 'exports.default', 'index.js'))
|
|
747
777
|
let mainFile = resolvePath(mainFileOrg, os.platform() === 'win32')
|
|
748
778
|
if (isEmpty(path.extname(mainFile))) {
|
|
@@ -758,17 +788,17 @@ class Bajo extends BasePlugin {
|
|
|
758
788
|
result[name] = mod
|
|
759
789
|
}
|
|
760
790
|
if (notFound.length > 0) throw this.error('cantFind%s', this.join(notFound))
|
|
761
|
-
if (pkgs.length === 1) return result[keys(result)[0]]
|
|
762
791
|
if (opts.asObject) return result
|
|
792
|
+
if (pkgs.length === 1) return result[keys(result)[0]]
|
|
763
793
|
return values(result)
|
|
764
794
|
}
|
|
765
795
|
|
|
766
796
|
/**
|
|
767
|
-
* Check whether directory is empty or not. More info please {@link https://github.com/gulpjs/empty-dir|check here}.
|
|
797
|
+
* Check whether a directory is empty or not. More info please {@link https://github.com/gulpjs/empty-dir|check here}.
|
|
768
798
|
*
|
|
769
799
|
* @method
|
|
770
800
|
* @async
|
|
771
|
-
* @param {string} dir - Directory to check
|
|
801
|
+
* @param {(string|TNsPathPairs)} dir - Directory to check
|
|
772
802
|
* @param {function} filterFn - Filter function to filter out files that cause false positives.
|
|
773
803
|
* @returns {boolean}
|
|
774
804
|
*/
|
|
@@ -782,7 +812,7 @@ class Bajo extends BasePlugin {
|
|
|
782
812
|
* Check whether log level is within log's app current level
|
|
783
813
|
*
|
|
784
814
|
* @method
|
|
785
|
-
* @param {string} level - Level to check. See {@link
|
|
815
|
+
* @param {string} level - Level to check. See {@link TLogLevels} for more
|
|
786
816
|
* @returns {boolean}
|
|
787
817
|
*/
|
|
788
818
|
isLogInRange = (level) => {
|
|
@@ -831,19 +861,28 @@ class Bajo extends BasePlugin {
|
|
|
831
861
|
return this.isValidAppPlugin(dir, 'plugin', returnPkg)
|
|
832
862
|
}
|
|
833
863
|
|
|
834
|
-
|
|
835
|
-
|
|
864
|
+
/**
|
|
865
|
+
* Human friendly join array of items.
|
|
866
|
+
*
|
|
867
|
+
* @method
|
|
868
|
+
* @param {any[]} array - Array to join
|
|
869
|
+
* @param {(string|Object)} options - If provided and is a string, it will be used as separator
|
|
870
|
+
* @param {string} [options.separator=', '] - Separator to use
|
|
871
|
+
* @param {string} [options.lastSeparator=and] - Text to use as the last separator
|
|
872
|
+
* @returns {string}
|
|
873
|
+
*/
|
|
874
|
+
join = (array, options) => {
|
|
875
|
+
const { isSet } = this.app.lib.aneka
|
|
836
876
|
const translate = val => {
|
|
837
|
-
|
|
838
|
-
return val
|
|
877
|
+
return this.t(val).toLowerCase()
|
|
839
878
|
}
|
|
840
879
|
if (array.length === 0) return translate('none')
|
|
841
880
|
if (array.length === 1) return array[0]
|
|
842
|
-
if (isSet(
|
|
843
|
-
let { separator = ', ',
|
|
844
|
-
|
|
881
|
+
if (isSet(options) && !isPlainObject(options)) return array.join(options)
|
|
882
|
+
let { separator = ', ', lastSeparator = 'and' } = options ?? {}
|
|
883
|
+
lastSeparator = translate(lastSeparator)
|
|
845
884
|
const last = (array.pop() ?? '').trim()
|
|
846
|
-
return array.map(a => (a + '').trim()).join(separator) + ` ${
|
|
885
|
+
return array.map(a => (a + '').trim()).join(separator) + ` ${lastSeparator} ${last}`
|
|
847
886
|
}
|
|
848
887
|
|
|
849
888
|
/**
|
|
@@ -864,22 +903,24 @@ class Bajo extends BasePlugin {
|
|
|
864
903
|
* Parse duration to its millisecond value. Use {@link https://github.com/vercel/ms|ms} under the hood
|
|
865
904
|
*
|
|
866
905
|
* @method
|
|
867
|
-
* @param {(number|string)} dur - If string is given, parse this to its millisecond value. Otherwise
|
|
906
|
+
* @param {(number|string)} dur - If string is given, parse this to its millisecond value. Otherwise returns as is
|
|
868
907
|
* @returns {number}
|
|
908
|
+
* @see {@link https://github.com/vercel/ms|ms}
|
|
869
909
|
*/
|
|
870
910
|
parseDur = (dur) => {
|
|
871
911
|
return isNumber(dur) ? dur : ms(dur)
|
|
872
912
|
}
|
|
873
913
|
|
|
874
914
|
/**
|
|
875
|
-
* Parse datetime string as Javascript object. Please visit {@link https://day.js.org|dayjs} for valid formats and more infos
|
|
915
|
+
* Parse datetime string as Javascript date object. Please visit {@link https://day.js.org|dayjs} for valid formats and more infos
|
|
876
916
|
*
|
|
877
917
|
* @method
|
|
878
918
|
* @param {string} dt - Datetime string
|
|
879
|
-
* @returns {Object} Javascript object
|
|
919
|
+
* @returns {Object} Javascript date object
|
|
920
|
+
* @see {@link https://day.js.org|dayjs}
|
|
880
921
|
*/
|
|
881
922
|
parseDt = (dt) => {
|
|
882
|
-
const value = this.lib.dayjs(dt)
|
|
923
|
+
const value = this.app.lib.dayjs(dt)
|
|
883
924
|
if (!value.isValid()) throw this.error('dtUnparsable%s', dt)
|
|
884
925
|
return value.toDate()
|
|
885
926
|
}
|
|
@@ -889,7 +930,7 @@ class Bajo extends BasePlugin {
|
|
|
889
930
|
* to parse values, so please have a visit to know how it works
|
|
890
931
|
*
|
|
891
932
|
* If ```options.parseValue``` is ```true```, any key ends with ```Dur``` and ```Dt``` will
|
|
892
|
-
* also be parsed as millisecond and Javascript
|
|
933
|
+
* also be parsed as millisecond and Javascript date time accordingly.
|
|
893
934
|
*
|
|
894
935
|
* @method
|
|
895
936
|
* @param {(Object|string)} input - If string is given, parse it first using JSON.parse
|
|
@@ -898,14 +939,15 @@ class Bajo extends BasePlugin {
|
|
|
898
939
|
* @param {boolean} [options.parseValue=false] - If ```true```, values will be parsed & normalized
|
|
899
940
|
* @param {string} [options.lang] - If provided, use this language instead of the one in config
|
|
900
941
|
* @returns {Object}
|
|
942
|
+
* @see {@link https://github.com/ladjs/dotenv-parse-variables}
|
|
901
943
|
*/
|
|
902
944
|
parseObject = (input, options = {}) => {
|
|
903
945
|
const { silent = true, parseValue = false, lang, ns } = options
|
|
904
|
-
const { isSet } = this.lib.aneka
|
|
946
|
+
const { isSet } = this.app.lib.aneka
|
|
905
947
|
const translate = (item) => {
|
|
906
948
|
const scope = ns ? this.app[ns] : this
|
|
907
949
|
const [text, ...args] = item.split('|')
|
|
908
|
-
return scope.
|
|
950
|
+
return scope.t(text, ...args, { lang })
|
|
909
951
|
}
|
|
910
952
|
const statics = ['*']
|
|
911
953
|
if (isString(input)) {
|
|
@@ -955,7 +997,7 @@ class Bajo extends BasePlugin {
|
|
|
955
997
|
}
|
|
956
998
|
|
|
957
999
|
pick = (obj, items, excludeUnset) => {
|
|
958
|
-
const { isSet } = this.lib.aneka
|
|
1000
|
+
const { isSet } = this.app.lib.aneka
|
|
959
1001
|
const result = {}
|
|
960
1002
|
for (const item of items) {
|
|
961
1003
|
const [k, nk] = item.split(':')
|
|
@@ -984,25 +1026,25 @@ class Bajo extends BasePlugin {
|
|
|
984
1026
|
* @returns {Object}
|
|
985
1027
|
*/
|
|
986
1028
|
readConfig = async (file, { ns, pattern, globOptions = {}, ignoreError, defValue = {}, opts = {} } = {}) => {
|
|
987
|
-
if (!ns) ns = this.
|
|
1029
|
+
if (!ns) ns = this.ns
|
|
988
1030
|
file = resolvePath(this.getPluginFile(file))
|
|
989
1031
|
let ext = path.extname(file)
|
|
990
1032
|
const fname = path.dirname(file) + '/' + path.basename(file, ext)
|
|
991
1033
|
ext = ext.toLowerCase()
|
|
992
1034
|
if (ext === '.js') {
|
|
993
|
-
const { readHandler } = find(this.app.
|
|
1035
|
+
const { readHandler } = find(this.app.configHandlers, { ext })
|
|
994
1036
|
return this.parseObject(await readHandler.call(this.app[ns], file, opts))
|
|
995
1037
|
}
|
|
996
|
-
if (ext === '.json') return await this.
|
|
1038
|
+
if (ext === '.json') return await this.fromJson(file, null)
|
|
997
1039
|
if (!['', '.*'].includes(ext)) {
|
|
998
|
-
const item = find(this.app.
|
|
1040
|
+
const item = find(this.app.configHandlers, { ext })
|
|
999
1041
|
if (!item) {
|
|
1000
1042
|
if (!ignoreError) throw this.error('cantParse%s', file, { code: 'BAJO_CONFIG_NO_PARSER' })
|
|
1001
1043
|
return this.parseObject(defValue)
|
|
1002
1044
|
}
|
|
1003
1045
|
return this.parseObject(await item.readHandler.call(this.app[ns], file, opts))
|
|
1004
1046
|
}
|
|
1005
|
-
const item = pattern ?? `${fname}.{${map(map(this.app.
|
|
1047
|
+
const item = pattern ?? `${fname}.{${map(map(this.app.configHandlers, 'ext'), k => k.slice(1)).join(',')}}`
|
|
1006
1048
|
const files = await fastGlob(item, globOptions)
|
|
1007
1049
|
if (files.length === 0) {
|
|
1008
1050
|
if (!ignoreError) throw this.error('noConfigFileFound', { code: 'BAJO_CONFIG_FILE_NOT_FOUND' })
|
|
@@ -1011,12 +1053,12 @@ class Bajo extends BasePlugin {
|
|
|
1011
1053
|
let config = defValue
|
|
1012
1054
|
for (const f of files) {
|
|
1013
1055
|
const ext = path.extname(f).toLowerCase()
|
|
1014
|
-
const item = find(this.app.
|
|
1056
|
+
const item = find(this.app.configHandlers, { ext })
|
|
1015
1057
|
if (!item) {
|
|
1016
1058
|
if (!ignoreError) throw this.error('cantParse%s', f, { code: 'BAJO_CONFIG_NO_PARSER' })
|
|
1017
1059
|
continue
|
|
1018
1060
|
}
|
|
1019
|
-
config = await item.readHandler.call(this.app[ns], f, opts)
|
|
1061
|
+
config = await item.readHandler.call(this.app[ns], f, null, opts)
|
|
1020
1062
|
if (!isEmpty(config)) break
|
|
1021
1063
|
}
|
|
1022
1064
|
return this.parseObject(config)
|
|
@@ -1032,7 +1074,7 @@ class Bajo extends BasePlugin {
|
|
|
1032
1074
|
*/
|
|
1033
1075
|
readJson = (file, thrownNotFound = false) => {
|
|
1034
1076
|
if (isPlainObject(thrownNotFound)) thrownNotFound = false
|
|
1035
|
-
if (!fs.existsSync(file) && thrownNotFound) throw this.error('notFound%s%s', this.
|
|
1077
|
+
if (!fs.existsSync(file) && thrownNotFound) throw this.error('notFound%s%s', this.t('file'), file)
|
|
1036
1078
|
let resp
|
|
1037
1079
|
try {
|
|
1038
1080
|
resp = fs.readFileSync(file, 'utf8')
|
|
@@ -1041,12 +1083,49 @@ class Bajo extends BasePlugin {
|
|
|
1041
1083
|
return this.parseObject(JSON.parse(resp))
|
|
1042
1084
|
}
|
|
1043
1085
|
|
|
1086
|
+
fromJson (file, isContent) {
|
|
1087
|
+
const content = isContent ? file : fs.readFileSync(file, 'utf8')
|
|
1088
|
+
return JSON.parse(content)
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
toJson = (file, isContent, opts = 2) => {
|
|
1092
|
+
const content = isContent ? file : JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
1093
|
+
return JSON.stringify(content, null, opts)
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Read all config files by path
|
|
1098
|
+
*
|
|
1099
|
+
* @method
|
|
1100
|
+
* @async
|
|
1101
|
+
* @param {string} path - Base path to start looking config files
|
|
1102
|
+
* @returns {Object}
|
|
1103
|
+
*/
|
|
1104
|
+
readAllConfigs = async (path) => {
|
|
1105
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
1106
|
+
let cfg = {}
|
|
1107
|
+
let ext = {}
|
|
1108
|
+
// default config file
|
|
1109
|
+
try {
|
|
1110
|
+
cfg = await this.readConfig(`${path}.*`, { ignoreError: true })
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
if (['BAJO_CONFIG_NO_PARSER'].includes(err.code)) throw err
|
|
1113
|
+
}
|
|
1114
|
+
// env based config file
|
|
1115
|
+
try {
|
|
1116
|
+
ext = await this.readConfig(`${path}-${this.config.env}.*`, { ignoreError: true })
|
|
1117
|
+
} catch (err) {
|
|
1118
|
+
if (!['BAJO_CONFIG_FILE_NOT_FOUND'].includes(err.code)) throw err
|
|
1119
|
+
}
|
|
1120
|
+
return defaultsDeep({}, ext, cfg)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1044
1123
|
/**
|
|
1045
|
-
* Run named hook
|
|
1124
|
+
* Run named hook/event
|
|
1046
1125
|
*
|
|
1047
1126
|
* @method
|
|
1048
1127
|
* @async
|
|
1049
|
-
* @param {
|
|
1128
|
+
* @param {TNsPathPairs} hookName
|
|
1050
1129
|
* @param {...any} [args] - Argument passed to the hook function
|
|
1051
1130
|
* @returns {Array} Array of hook execution results
|
|
1052
1131
|
*/
|
|
@@ -1085,7 +1164,7 @@ class Bajo extends BasePlugin {
|
|
|
1085
1164
|
*/
|
|
1086
1165
|
saveAsDownload = async (file, item, printSaved = true) => {
|
|
1087
1166
|
const { print, getPluginDataDir } = this.app.bajo
|
|
1088
|
-
const fname = increment(`${getPluginDataDir(this.
|
|
1167
|
+
const fname = increment(`${getPluginDataDir(this.ns)}/download/${trim(file, '/')}`, { fs: true })
|
|
1089
1168
|
const dir = path.dirname(fname)
|
|
1090
1169
|
if (!fs.existsSync(dir)) fs.ensureDirSync(dir)
|
|
1091
1170
|
await fs.writeFile(fname, item, 'utf8')
|