bajo 1.2.8 → 2.0.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 +6 -3
- package/README.md +8 -148
- package/class/app.js +113 -0
- package/{boot/class/bajo-core.js → class/bajo.js} +449 -37
- package/{boot/class/error.js → class/base/err.js} +29 -3
- package/class/base/log.js +205 -0
- package/class/base/plugin.js +177 -0
- package/class/base/print.js +272 -0
- package/class/helper/bajo.js +344 -0
- package/class/helper/plugin.js +169 -0
- package/{boot/class/bajo-plugin.js → class/plugin.js} +60 -3
- package/docs/App.html +3 -0
- package/docs/Bajo.html +15 -0
- package/docs/BasePlugin.html +5 -0
- package/docs/Err.html +3 -0
- package/docs/Log.html +3 -0
- package/docs/Plugin.html +3 -0
- package/docs/Print.html +3 -0
- package/docs/bitcoin.jpeg +0 -0
- package/docs/class_app.js.html +116 -0
- package/docs/class_bajo.js.html +1100 -0
- package/docs/class_base_err.js.html +99 -0
- package/docs/class_base_log.js.html +208 -0
- package/docs/class_base_plugin.js.html +180 -0
- package/docs/class_base_print.js.html +275 -0
- package/docs/class_helper_bajo.js.html +347 -0
- package/docs/class_helper_plugin.js.html +172 -0
- package/docs/class_plugin.js.html +121 -0
- package/docs/data/search.json +1 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/global.html +3 -0
- package/docs/index.html +3 -0
- package/docs/lib_create-method.js.html +42 -0
- package/docs/lib_formats.js.html +68 -0
- package/docs/lib_log-levels.js.html +28 -0
- package/docs/lib_resolve-path.js.html +30 -0
- package/docs/lib_shim.js.html +35 -0
- package/docs/module-class_helper_bajo.html +3 -0
- package/docs/module-class_helper_plugin.html +3 -0
- package/docs/module-lib_create-method.html +3 -0
- package/docs/module-lib_formats.html +3 -0
- package/docs/module-lib_log-levels.html +3 -0
- package/docs/module-lib_resolve-path.html +3 -0
- package/docs/module-lib_shim.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/tutorial-contribution.html +3 -0
- package/docs/tutorial-ecosystem.html +3 -0
- package/docs/tutorial-getting-started.html +13 -0
- package/docs/tutorial-plugin-dev.html +3 -0
- package/docs/tutorial-user-guide.html +3 -0
- package/lib/create-method.js +39 -0
- package/{boot/lib → lib}/formats.js +28 -0
- package/lib/log-levels.js +25 -0
- package/{boot/lib → lib}/parse-args-argv.js +1 -1
- package/{boot/lib → lib}/resolve-path.js +12 -0
- package/{boot/lib → lib}/shim.js +10 -0
- package/misc-docs/bitcoin.jpeg +0 -0
- package/misc-docs/contribution.md +20 -0
- package/{docs → misc-docs}/ecosystem.md +41 -12
- package/misc-docs/getting-started.md +142 -0
- package/misc-docs/plugin-dev.md +0 -0
- package/misc-docs/toc.json +17 -0
- package/misc-docs/user-guide.md +1 -0
- package/package.json +14 -12
- package/bajoBook/book/doc/.metadata.json +0 -28
- package/bajoBook/book/doc/How-to-Make-a-Paper-Boat-564x400@2x.jpg +0 -0
- package/bajoBook/book/doc/pages/guides/definition.md +0 -7
- package/bajoBook/book/doc/pages/guides/intro.md +0 -3
- package/bajoBook/book/doc/pages/guides/setup.md +0 -22
- package/bajoBook/book/reference/.metadata.json +0 -152
- package/bajoBook/book/reference/concept-leadership-business-with-paper-boats.jpg +0 -0
- package/bajoBook/book/reference/pages/configuration/configuration-file.md +0 -52
- package/bajoBook/book/reference/pages/helper/break-ns-path.md +0 -24
- package/bajoBook/book/reference/pages/helper/build-collections.md +0 -19
- package/bajoBook/book/reference/pages/helper/call-helper-or-handler.md +0 -35
- package/bajoBook/book/reference/pages/helper/current-loc.md +0 -28
- package/bajoBook/book/reference/pages/helper/dayjs.md +0 -13
- package/bajoBook/book/reference/pages/helper/defaults-deep.md +0 -29
- package/bajoBook/book/reference/pages/helper/dump.md +0 -32
- package/bajoBook/book/reference/pages/helper/each-plugins.md +0 -24
- package/bajoBook/book/reference/pages/helper/envs.md +0 -11
- package/bajoBook/book/reference/pages/helper/error.md +0 -29
- package/bajoBook/book/reference/pages/helper/fatal.md +0 -18
- package/bajoBook/book/reference/pages/helper/freeze.md +0 -13
- package/bajoBook/book/reference/pages/helper/generate-id.md +0 -36
- package/bajoBook/book/reference/pages/helper/get-config.md +0 -27
- package/bajoBook/book/reference/pages/helper/get-global-module-dir.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-helper.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-item-by-name.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-key-by-value.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-module-dir.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-plugin-data-dir.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-plugin-name.md +0 -13
- package/bajoBook/book/reference/pages/helper/get-plugin.md +0 -13
- package/bajoBook/book/reference/pages/helper/import-module.md +0 -13
- package/bajoBook/book/reference/pages/helper/import-pkg.md +0 -13
- package/bajoBook/book/reference/pages/helper/is-empty-dir.md +0 -13
- package/bajoBook/book/reference/pages/helper/is-log-in-range.md +0 -13
- package/bajoBook/book/reference/pages/helper/is-set.md +0 -13
- package/bajoBook/book/reference/pages/helper/is-valid-app.md +0 -13
- package/bajoBook/book/reference/pages/helper/is-valid-plugin.md +0 -13
- package/bajoBook/book/reference/pages/helper/log-levels.md +0 -13
- package/bajoBook/book/reference/pages/helper/log.md +0 -13
- package/bajoBook/book/reference/pages/helper/paginate.md +0 -13
- package/bajoBook/book/reference/pages/helper/pascal-case.md +0 -13
- package/bajoBook/book/reference/pages/helper/print.md +0 -13
- package/bajoBook/book/reference/pages/helper/read-config.md +0 -13
- package/bajoBook/book/reference/pages/helper/read-json.md +0 -13
- package/bajoBook/book/reference/pages/helper/resolve-path.md +0 -13
- package/bajoBook/book/reference/pages/helper/resolve-tpl-path.md +0 -13
- package/bajoBook/book/reference/pages/helper/run-hook.md +0 -13
- package/bajoBook/book/reference/pages/helper/save-as-download.md +0 -13
- package/bajoBook/book/reference/pages/helper/titleize.md +0 -13
- package/bajoBook/book/reference/pages/helper/white-space.md +0 -13
- package/boot/class/app.js +0 -67
- package/boot/class/bajo-core/boot-order.js +0 -35
- package/boot/class/bajo-core/boot-plugins.js +0 -17
- package/boot/class/bajo-core/build-config.js +0 -85
- package/boot/class/bajo-core/build-plugins.js +0 -44
- package/boot/class/bajo-core/collect-config-handlers.js +0 -20
- package/boot/class/bajo-core/exit-handler.js +0 -53
- package/boot/class/bajo-core/run-as-applet.js +0 -26
- package/boot/class/bajo-plugin/attach-method.js +0 -14
- package/boot/class/bajo-plugin/build-config.js +0 -15
- package/boot/class/bajo-plugin/check-clash.js +0 -18
- package/boot/class/bajo-plugin/check-dependency.js +0 -39
- package/boot/class/bajo-plugin/collect-hooks.js +0 -31
- package/boot/class/bajo-plugin/run.js +0 -23
- package/boot/class/log.js +0 -90
- package/boot/class/plugin.js +0 -79
- package/boot/class/print.js +0 -153
- package/boot/lib/create-method.js +0 -33
- package/boot/lib/log-levels.js +0 -1
- package/test/method/isSet.js +0 -43
- /package/{bajo → extend/bajo}/intl/en-US.json +0 -0
- /package/{bajo → extend/bajo}/intl/id.json +0 -0
- /package/{waibuStatic → extend/waibuStatic}/virtual.json +0 -0
- /package/{boot/index.js → index.js} +0 -0
- /package/{boot/lib → lib}/current-loc.js +0 -0
- /package/{boot/lib → lib}/dayjs.js +0 -0
- /package/{boot/lib → lib}/import-module.js +0 -0
- /package/{boot/lib → lib}/omitted-plugin-keys.js +0 -0
- /package/{boot/lib → lib}/parse-env.js +0 -0
- /package/{boot/lib → lib}/read-all-configs.js +0 -0
- /package/{docs/hook.md → misc-docs/.hook.md} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Plugin from './plugin.js'
|
|
2
|
-
import
|
|
2
|
+
import BasePlugin from './base/plugin.js'
|
|
3
3
|
import increment from 'add-filename-increment'
|
|
4
4
|
import fs from 'fs-extra'
|
|
5
5
|
import path from 'path'
|
|
@@ -29,22 +29,69 @@ const {
|
|
|
29
29
|
last, get, has, values, dropRight, pick
|
|
30
30
|
} = lodash
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* The Core. The main engine. The one and only plugin that control app's boot process and
|
|
34
|
+
* making sure all other plugins working smoothly.
|
|
35
|
+
*
|
|
36
|
+
* @class
|
|
37
|
+
*/
|
|
38
|
+
class Bajo extends BasePlugin {
|
|
39
|
+
/**
|
|
40
|
+
* @param {Object} app
|
|
41
|
+
* @param {Object} app - App instance reference. Usefull to call app method inside a plugin
|
|
42
|
+
*/
|
|
33
43
|
constructor (app) {
|
|
34
44
|
super('bajo', app)
|
|
45
|
+
/**
|
|
46
|
+
* Date/time when your app start
|
|
47
|
+
* @type {Date}
|
|
48
|
+
*/
|
|
35
49
|
this.runAt = new Date()
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Your main namespace. And yes, you suppose NOT to change this
|
|
53
|
+
*
|
|
54
|
+
* @type {string}
|
|
55
|
+
*/
|
|
36
56
|
this.mainNs = 'main'
|
|
37
|
-
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Storage for applets
|
|
60
|
+
*
|
|
61
|
+
* @type {Array}
|
|
62
|
+
*/
|
|
38
63
|
this.applets = []
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* List of all loaded plugin's package names
|
|
67
|
+
*
|
|
68
|
+
* @type {Array}
|
|
69
|
+
*/
|
|
39
70
|
this.pluginPkgs = []
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* List of all loaded plugin's names
|
|
74
|
+
*
|
|
75
|
+
* @type {Array}
|
|
76
|
+
*/
|
|
40
77
|
this.pluginNames = []
|
|
78
|
+
|
|
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
|
+
*/
|
|
41
88
|
this.configHandlers = [
|
|
42
89
|
{ ext: '.js', readHandler: this._defConfigHandler },
|
|
43
90
|
{ ext: '.json', readHandler: this.readJson }
|
|
44
91
|
]
|
|
45
92
|
this.whiteSpace = [' ', '\t', '\n', '\r']
|
|
46
|
-
this.logLevels = logLevels
|
|
47
93
|
this.envs = { dev: 'development', staging: 'staging', prod: 'production' }
|
|
94
|
+
this.lib.Plugin = Plugin
|
|
48
95
|
}
|
|
49
96
|
|
|
50
97
|
async _defConfigHandler (file, opts = {}) {
|
|
@@ -53,13 +100,29 @@ class BajoCore extends Plugin {
|
|
|
53
100
|
return mod
|
|
54
101
|
}
|
|
55
102
|
|
|
56
|
-
|
|
57
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Resolve file name to filesystem's path. Windows path separator ```\```
|
|
105
|
+
* is normalized to Unix's ```/```
|
|
106
|
+
*
|
|
107
|
+
* @method
|
|
108
|
+
* @param {string} file - File to resolve
|
|
109
|
+
* @param {boolean} [asFileUrl=false] - Return as file URL format ```file:///<name>```
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
resolvePath = (file, asFileUrl) => {
|
|
113
|
+
return resolvePath(file, asFileUrl)
|
|
58
114
|
}
|
|
59
115
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Freeze object
|
|
118
|
+
*
|
|
119
|
+
* @method
|
|
120
|
+
* @param {Object} obj - Object
|
|
121
|
+
* @param {boolean} [shallow=false] - If true (default), deep freeze object
|
|
122
|
+
*/
|
|
123
|
+
freeze = (obj, shallow) => {
|
|
124
|
+
if (shallow) Object.freeze(obj)
|
|
125
|
+
else deepFreeze(obj)
|
|
63
126
|
}
|
|
64
127
|
|
|
65
128
|
setImmediate = async () => {
|
|
@@ -94,14 +157,33 @@ class BajoCore extends Plugin {
|
|
|
94
157
|
return `${ns}:${path}`
|
|
95
158
|
}
|
|
96
159
|
|
|
97
|
-
|
|
98
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Object returned by {@link BajoCore#breakNsPath|breakNsPath}
|
|
162
|
+
*
|
|
163
|
+
* @typedef {Object} NsPathType
|
|
164
|
+
* @property {string} ns - Namespace
|
|
165
|
+
* @property {string} [subNs] - Sub namespace
|
|
166
|
+
* @property {string} [subSubNs] - Sub of sub namespace
|
|
167
|
+
* @property {string} path - Path without query string or hash
|
|
168
|
+
* @property {string} fullPath - Full path, including query string and hash
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Break name to its namespace & path infos
|
|
173
|
+
*
|
|
174
|
+
* @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 {NsPathType}
|
|
178
|
+
*/
|
|
179
|
+
breakNsPath = (name = '', checkNs = true) => {
|
|
180
|
+
let [ns, ...path] = name.split(':')
|
|
99
181
|
const fullNs = ns
|
|
100
182
|
let subNs
|
|
101
183
|
let subSubNs
|
|
102
184
|
path = path.join(':')
|
|
103
185
|
if (path.startsWith('//')) {
|
|
104
|
-
return { path:
|
|
186
|
+
return { path: name } // for: http:// etc
|
|
105
187
|
}
|
|
106
188
|
|
|
107
189
|
[ns, subNs, subSubNs] = ns.split('.')
|
|
@@ -139,6 +221,23 @@ class BajoCore extends Plugin {
|
|
|
139
221
|
return { ns, path, subNs, subSubNs, qs, fullPath, fullNs, realPath, realFullPath }
|
|
140
222
|
}
|
|
141
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Method to transform an array or object from config into an array of collection safely.
|
|
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
|
|
230
|
+
*
|
|
231
|
+
* @method
|
|
232
|
+
* @async
|
|
233
|
+
* @param {Object} options - Options
|
|
234
|
+
* @param {string} [options.ns] - Namespace. If not provided, defaults to ```bajo```
|
|
235
|
+
* @param {function} [options.handler] - Handler to call while building the collection item
|
|
236
|
+
* @param {Array} [options.dupChecks=[]] - Array of keys to check for duplicates
|
|
237
|
+
* @param {string} options.container - Key used as container name
|
|
238
|
+
* @param {boolean} [options.useDefaultName=true] - If true (default) and ```name``` key is not provided, returned collection will be named ```default```
|
|
239
|
+
* @returns {Array} The collection
|
|
240
|
+
*/
|
|
142
241
|
buildCollections = async (options = {}) => {
|
|
143
242
|
let { ns, handler, dupChecks = [], container, useDefaultName } = options
|
|
144
243
|
useDefaultName = useDefaultName ?? true
|
|
@@ -173,15 +272,28 @@ class BajoCore extends Plugin {
|
|
|
173
272
|
if (checkers.includes(checker)) this.app[ns].fatal('oneOrMoreSharedTheSame%s%s', container, this.join(dupChecks.filter(i => !isFunction(i))))
|
|
174
273
|
}
|
|
175
274
|
}
|
|
176
|
-
await this.runHook(`${ns}:${camelCase('afterBuildCollection')}`, container)
|
|
275
|
+
await this.runHook(`${ns}:${camelCase('afterBuildCollection')}`, container, items)
|
|
177
276
|
this.app[ns].log.debug('collected%s%d', this.app[ns].print.write(container), items.length)
|
|
178
277
|
return items
|
|
179
278
|
}
|
|
180
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Calling any plugin's method by its name. Name format: ```ns:methodName```.
|
|
282
|
+
* - If name is a string, the corresponding plugin's method will be called with passed args as its parameters
|
|
283
|
+
* - 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
|
+
* - If name is a function, this function will be run under scope with the remaining args
|
|
285
|
+
* - If name is an object and has ```handler``` key in it, this function handler will be instead
|
|
286
|
+
*
|
|
287
|
+
* @method
|
|
288
|
+
* @async
|
|
289
|
+
* @param {(string|Object|function)} name - Method's name, function handler, plain object or plugin instance
|
|
290
|
+
* @param {...any} [args] - One or more arguments passed as parameter to the handler
|
|
291
|
+
* @returns {any} Returned value
|
|
292
|
+
*/
|
|
181
293
|
callHandler = async (item, ...args) => {
|
|
182
294
|
let result
|
|
183
295
|
let scope = this
|
|
184
|
-
if (item instanceof
|
|
296
|
+
if (item instanceof Plugin) {
|
|
185
297
|
scope = item
|
|
186
298
|
item = args.shift()
|
|
187
299
|
}
|
|
@@ -201,12 +313,30 @@ class BajoCore extends Plugin {
|
|
|
201
313
|
}
|
|
202
314
|
} else if (isFunction(item)) {
|
|
203
315
|
result = await item.call(scope, ...args)
|
|
204
|
-
} else if (isPlainObject(item) && item.handler) {
|
|
316
|
+
} else if (isPlainObject(item) && isFunction(item.handler)) {
|
|
205
317
|
result = await item.handler.call(scope, ...args)
|
|
206
318
|
}
|
|
207
319
|
return result
|
|
208
320
|
}
|
|
209
321
|
|
|
322
|
+
/**
|
|
323
|
+
* This function iterates through all loaded plugins and call the provided handler scoped as the running plugin.
|
|
324
|
+
* And an object with the following key serves as its parameter:
|
|
325
|
+
*
|
|
326
|
+
* - ```file```: file matched the glob pattern
|
|
327
|
+
* - ```dir```: plugin's base directory
|
|
328
|
+
*
|
|
329
|
+
* @method
|
|
330
|
+
* @async
|
|
331
|
+
* @param {function} handler - Function handler. Can be an async function. Scoped to the running plugin
|
|
332
|
+
* @param {(string|Object)} [options={}] - Options. If a string is provided, it serves as the glob pattern, otherwise:
|
|
333
|
+
* @param {(string|Array)} [options.glob] - Glob pattern. If provided,
|
|
334
|
+
* @param {boolean} [options.useBajo=false] - If true, add ```bajo``` to the running plugins too
|
|
335
|
+
* @param {string} [options.prefix=''] - Prepend glob pattern with prefix
|
|
336
|
+
* @param {boolean} [options.noUnderscore=true] - If true (default), matched file with name starts with underscore is ignored
|
|
337
|
+
* @param {any} [options.returnItems] - If true, each value of returned handler call will be saved as an object with running plugin name as its keys
|
|
338
|
+
* @returns {any}
|
|
339
|
+
*/
|
|
210
340
|
eachPlugins = async (handler, options = {}) => {
|
|
211
341
|
if (typeof options === 'string') options = { glob: options }
|
|
212
342
|
const result = {}
|
|
@@ -215,11 +345,9 @@ class BajoCore extends Plugin {
|
|
|
215
345
|
if (useBajo) pluginPkgs.unshift('bajo')
|
|
216
346
|
for (const pkgName of pluginPkgs) {
|
|
217
347
|
const ns = camelCase(pkgName)
|
|
218
|
-
const config = this.app[ns].config
|
|
219
|
-
const alias = this.app[ns].alias
|
|
220
348
|
let r
|
|
221
349
|
if (glob) {
|
|
222
|
-
const base = prefix === '' ? this.app[ns].dir.pkg : `${this.app[ns].dir.pkg}/${prefix}`
|
|
350
|
+
const base = prefix === '' ? `${this.app[ns].dir.pkg}/extend` : `${this.app[ns].dir.pkg}/extend/${prefix}`
|
|
223
351
|
let opts = isString(glob) ? { pattern: [glob] } : glob
|
|
224
352
|
let pattern = opts.pattern ?? []
|
|
225
353
|
if (isString(pattern)) pattern = [pattern]
|
|
@@ -230,7 +358,7 @@ class BajoCore extends Plugin {
|
|
|
230
358
|
const files = await fastGlob(pattern, opts)
|
|
231
359
|
for (const f of files) {
|
|
232
360
|
if (path.basename(f)[0] === '_' && noUnderscore) continue
|
|
233
|
-
const resp = await handler.call(this.app[ns], {
|
|
361
|
+
const resp = await handler.call(this.app[ns], { file: f, dir: base })
|
|
234
362
|
if (resp === false) break
|
|
235
363
|
else if (resp === undefined) continue
|
|
236
364
|
else {
|
|
@@ -239,7 +367,7 @@ class BajoCore extends Plugin {
|
|
|
239
367
|
}
|
|
240
368
|
}
|
|
241
369
|
} else {
|
|
242
|
-
r = await handler.call(this.app[ns], {
|
|
370
|
+
r = await handler.call(this.app[ns], { dir: this.app[ns].dir.pkg })
|
|
243
371
|
if (r === false) break
|
|
244
372
|
else if (r === undefined) continue
|
|
245
373
|
else result[ns] = r
|
|
@@ -257,6 +385,23 @@ class BajoCore extends Plugin {
|
|
|
257
385
|
return result
|
|
258
386
|
}
|
|
259
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Object returned by {@link BajoCore#getUnitFormat|getUnitFormat}
|
|
390
|
+
*
|
|
391
|
+
* @typedef {Object} ObjectFormatType
|
|
392
|
+
* @property {string} unitSys - Unit system
|
|
393
|
+
* @property {Object} format - Format object
|
|
394
|
+
*/
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get unit format
|
|
398
|
+
*
|
|
399
|
+
* @method
|
|
400
|
+
* @param {Object} [options={}] - Options
|
|
401
|
+
* @param {string} [options.lang] - Language to use. Defaults to the one you set in config
|
|
402
|
+
* @param {string} [options.unitSys] - Unit system to use. Defaults to language's unit system or ```metric``` if unspecified
|
|
403
|
+
* @returns {ObjectFormatType} - Returned value
|
|
404
|
+
*/
|
|
260
405
|
getUnitFormat = (options = {}) => {
|
|
261
406
|
const lang = options.lang ?? this.config.lang
|
|
262
407
|
let unitSys = options.unitSys ?? this.config.intl.unitSys[lang] ?? 'metric'
|
|
@@ -264,6 +409,18 @@ class BajoCore extends Plugin {
|
|
|
264
409
|
return { unitSys, format: formats[unitSys] }
|
|
265
410
|
}
|
|
266
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Format value by type
|
|
414
|
+
*
|
|
415
|
+
* @method
|
|
416
|
+
* @param {string} type - Format type. See {@link FormatType} for acceptable values
|
|
417
|
+
* @param {any} value - Value to format
|
|
418
|
+
* @param {string} [dataType] - Value's data type. See {@link DataType} for acceptable values
|
|
419
|
+
* @param {Object} [options={}] - Options
|
|
420
|
+
* @param {boolean} [options.withUnit=true] - Return with its unit appended
|
|
421
|
+
* @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config
|
|
422
|
+
* @returns {(Array|string)} Return string if ```withUnit``` is true. Otherwise is an array of ```[value, unit, separator]```
|
|
423
|
+
*/
|
|
267
424
|
formatByType = (type, value, dataType, options = {}) => {
|
|
268
425
|
const { defaultsDeep } = this.lib.aneka
|
|
269
426
|
const { format } = this.getUnitFormat(options)
|
|
@@ -278,6 +435,20 @@ class BajoCore extends Plugin {
|
|
|
278
435
|
return `${value}${sep}${unit}`
|
|
279
436
|
}
|
|
280
437
|
|
|
438
|
+
/**
|
|
439
|
+
* Format value
|
|
440
|
+
*
|
|
441
|
+
* @method
|
|
442
|
+
* @param {any} value - Value to format
|
|
443
|
+
* @param {string} [type] - Data type to use. See {@link DataType} for acceptable values. If not provided, return the untouched value
|
|
444
|
+
* @param {Object} [options={}] - Options
|
|
445
|
+
* @param {string} [options.emptyValue=''] - Empty value to use if function resulted empty. Defaults to the one from your config
|
|
446
|
+
* @param {boolean} [options.withUnit=true] - Return with its unit appended
|
|
447
|
+
* @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config
|
|
448
|
+
* @param {string} [options.latitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as latitude in degree, minute, second
|
|
449
|
+
* @param {string} [options.longitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as longitude in degree, minute, second
|
|
450
|
+
* @returns {string} Formatted value
|
|
451
|
+
*/
|
|
281
452
|
format = (value, type, options = {}) => {
|
|
282
453
|
const { defaultsDeep } = this.lib.aneka
|
|
283
454
|
const { format } = this.config.intl
|
|
@@ -324,6 +495,17 @@ class BajoCore extends Plugin {
|
|
|
324
495
|
return value
|
|
325
496
|
}
|
|
326
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Generate unique random characters that can be used as ID. Use {@link https://github.com/ai/nanoid|nanoid} under the hood
|
|
500
|
+
*
|
|
501
|
+
* @method
|
|
502
|
+
* @param {(boolean|string|Object)} [options={}] - Options. If set to ```true``` or ```alpha```, it will generate alphaphet only characters. If set to ```int```, it will generate integer only characters. Otherwise:
|
|
503
|
+
* @param {string} [options.pattern] - Character pattern to use. Defaults to all available alphanumeric characters
|
|
504
|
+
* @param {number} [options.length=13] - Length of resulted characters
|
|
505
|
+
* @param {string} [options.case] - If set to ```lower``` to use lower cased pattern only. For upper cased pattern, set it to ```upper```
|
|
506
|
+
* @param {boolean} [options.returnInstance] - Set to ```true``` to return {@link https://github.com/ai/nanoid|nanoid} instance instead of string
|
|
507
|
+
* @returns {(string|Object)} Return string or instance of {@link https://github.com/ai/nanoid|nanoid}
|
|
508
|
+
*/
|
|
327
509
|
generateId = (options = {}) => {
|
|
328
510
|
let type
|
|
329
511
|
if (options === true) options = 'alpha'
|
|
@@ -344,6 +526,14 @@ class BajoCore extends Plugin {
|
|
|
344
526
|
return type === 'int' ? parseInt(value) : value
|
|
345
527
|
}
|
|
346
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Get NPM global module directory
|
|
531
|
+
*
|
|
532
|
+
* @method
|
|
533
|
+
* @param {string} [pkgName] - If provided, return this package global directory. Otherwise the npm global module directory
|
|
534
|
+
* @param {boolean} [silent=true] - Set to ```false``` to throw exception in case of error. Otherwise silently returns undefined
|
|
535
|
+
* @returns {string}
|
|
536
|
+
*/
|
|
347
537
|
getGlobalModuleDir = (pkgName, silent = true) => {
|
|
348
538
|
let nodeModulesDir = process.env.BAJO_GLOBAL_MODULE_DIR
|
|
349
539
|
if (!nodeModulesDir) {
|
|
@@ -364,6 +554,14 @@ class BajoCore extends Plugin {
|
|
|
364
554
|
return dir
|
|
365
555
|
}
|
|
366
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Get class method by name
|
|
559
|
+
*
|
|
560
|
+
* @method
|
|
561
|
+
* @param {string} name - Name in format ```ns:methodName```
|
|
562
|
+
* @param {boolean} [thrown=true] - If ```true``` (default), throw exceptiom in case of error
|
|
563
|
+
* @returns {function} Class method
|
|
564
|
+
*/
|
|
367
565
|
getMethod = (name = '', thrown = true) => {
|
|
368
566
|
const { ns, path } = this.breakNsPath(name)
|
|
369
567
|
const method = get(this.app, `${ns}.${path}`)
|
|
@@ -371,6 +569,14 @@ class BajoCore extends Plugin {
|
|
|
371
569
|
if (thrown) throw this.error('cantFindMethod%s', name)
|
|
372
570
|
}
|
|
373
571
|
|
|
572
|
+
/**
|
|
573
|
+
* Find item deep in paths
|
|
574
|
+
*
|
|
575
|
+
* @method
|
|
576
|
+
* @param {string} item - Item to find
|
|
577
|
+
* @param {Array} paths - Array of path to look for
|
|
578
|
+
* @returns {string}
|
|
579
|
+
*/
|
|
374
580
|
findDeep = (item, paths) => {
|
|
375
581
|
let dir
|
|
376
582
|
for (const p of paths) {
|
|
@@ -383,6 +589,14 @@ class BajoCore extends Plugin {
|
|
|
383
589
|
return dir
|
|
384
590
|
}
|
|
385
591
|
|
|
592
|
+
/**
|
|
593
|
+
* Get module directory, locally and globally
|
|
594
|
+
*
|
|
595
|
+
* @method
|
|
596
|
+
* @param {string} pkgName - Package name to find
|
|
597
|
+
* @param {*} base - Provide base name if ```pkgName``` is a module under ```base```'s package name
|
|
598
|
+
* @returns {string} Return absolute package directory
|
|
599
|
+
*/
|
|
386
600
|
getModuleDir = (pkgName, base) => {
|
|
387
601
|
if (pkgName === 'main') return resolvePath(this.app.dir)
|
|
388
602
|
if (base === 'main') base = this.app.dir
|
|
@@ -398,6 +612,14 @@ class BajoCore extends Plugin {
|
|
|
398
612
|
return resolvePath(path.dirname(dir))
|
|
399
613
|
}
|
|
400
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Get plugin data directory
|
|
617
|
+
*
|
|
618
|
+
* @method
|
|
619
|
+
* @param {string} name - Plugin name (namespace) or alias
|
|
620
|
+
* @param {boolean} [ensureDir=true] - Set ```true``` (default) to ensure directory is existed
|
|
621
|
+
* @returns {string}
|
|
622
|
+
*/
|
|
401
623
|
getPluginDataDir = (name, ensureDir = true) => {
|
|
402
624
|
const plugin = this.getPlugin(name)
|
|
403
625
|
const dir = `${this.app.bajo.dir.data}/plugins/${plugin.name}`
|
|
@@ -405,6 +627,16 @@ class BajoCore extends Plugin {
|
|
|
405
627
|
return dir
|
|
406
628
|
}
|
|
407
629
|
|
|
630
|
+
/**
|
|
631
|
+
* Resolve file path from:
|
|
632
|
+
*
|
|
633
|
+
* - local/absolute file
|
|
634
|
+
* - ns based path (```myPlugin:/path/to/file.txt```)
|
|
635
|
+
*
|
|
636
|
+
* @method
|
|
637
|
+
* @param {string} file - File path, see above for supported types
|
|
638
|
+
* @returns {string} Resolved file path
|
|
639
|
+
*/
|
|
408
640
|
getPluginFile = (file) => {
|
|
409
641
|
if (!this) return file
|
|
410
642
|
if (file[0] === '.') file = `${currentLoc(import.meta).dir}/${trim(file.slice(1), '/')}`
|
|
@@ -418,13 +650,21 @@ class BajoCore extends Plugin {
|
|
|
418
650
|
return file
|
|
419
651
|
}
|
|
420
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Get plugin by name
|
|
655
|
+
*
|
|
656
|
+
* @method
|
|
657
|
+
* @param {string} name - Plugin name/namespace or alias
|
|
658
|
+
* @param {boolean} [silent] - If ```true```, silently return undefined even on error
|
|
659
|
+
* @returns {Object} Plugin object
|
|
660
|
+
*/
|
|
421
661
|
getPlugin = (name, silent) => {
|
|
422
662
|
if (!this.app[name]) {
|
|
423
663
|
// alias?
|
|
424
664
|
let plugin
|
|
425
665
|
for (const key in this.app) {
|
|
426
666
|
const item = this.app[key]
|
|
427
|
-
if (item instanceof
|
|
667
|
+
if (item instanceof Plugin && (item.alias === name || item.pkgName === name)) {
|
|
428
668
|
plugin = item
|
|
429
669
|
break
|
|
430
670
|
}
|
|
@@ -438,10 +678,54 @@ class BajoCore extends Plugin {
|
|
|
438
678
|
return this.app[name]
|
|
439
679
|
}
|
|
440
680
|
|
|
681
|
+
/**
|
|
682
|
+
* Import file/module from any loaded plugins
|
|
683
|
+
*
|
|
684
|
+
* Your plugin structure:
|
|
685
|
+
* ```
|
|
686
|
+
* |- src
|
|
687
|
+
* | |- lib
|
|
688
|
+
* | | |- my-module.js
|
|
689
|
+
* |- index.js
|
|
690
|
+
* |- package.json
|
|
691
|
+
* ```
|
|
692
|
+
*
|
|
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
|
+
* @method
|
|
699
|
+
* @async
|
|
700
|
+
* @param {string} file - File in format ```ns:<ns based file path>```
|
|
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)}
|
|
706
|
+
*/
|
|
441
707
|
importModule = async (file, { asDefaultImport, asHandler, noCache } = {}) => {
|
|
442
708
|
return await importModule.call(this, file, { asDefaultImport, asHandler, noCache })
|
|
443
709
|
}
|
|
444
710
|
|
|
711
|
+
/**
|
|
712
|
+
* Import one or more package belongs to a plugin
|
|
713
|
+
*
|
|
714
|
+
* Example: you want to import packages ```delay``` and ```chalk``` from ```bajo``` namespace and use it inside your app/plugin
|
|
715
|
+
*
|
|
716
|
+
* ```javascript
|
|
717
|
+
* const { importPkg } from this.app.bajo
|
|
718
|
+
* const [delay, chalk] = await importPkg('bajo:delay', 'bajo:chalk')
|
|
719
|
+
*
|
|
720
|
+
* await delay(1000)
|
|
721
|
+
* ...
|
|
722
|
+
* ```
|
|
723
|
+
*
|
|
724
|
+
* @method
|
|
725
|
+
* @async
|
|
726
|
+
* @param {...any} pkgs - One or more packages in format ```ns:packageName```
|
|
727
|
+
* @returns {(Object|Array)} Depends on how many parameters are provided, it should return the named package or an array of packages
|
|
728
|
+
*/
|
|
445
729
|
importPkg = async (...pkgs) => {
|
|
446
730
|
const { defaultsDeep } = this.lib.aneka
|
|
447
731
|
const result = {}
|
|
@@ -450,7 +734,8 @@ class BajoCore extends Plugin {
|
|
|
450
734
|
if (isPlainObject(last(pkgs))) {
|
|
451
735
|
opts = defaultsDeep(pkgs.pop(), opts)
|
|
452
736
|
}
|
|
453
|
-
for (
|
|
737
|
+
for (let pkg of pkgs) {
|
|
738
|
+
if (pkg.indexOf(':') === -1) pkg = `bajo:${pkg}`
|
|
454
739
|
const { ns, path: name } = this.breakNsPath(pkg)
|
|
455
740
|
const dir = this.getModuleDir(name, ns)
|
|
456
741
|
if (!dir) {
|
|
@@ -478,13 +763,30 @@ class BajoCore extends Plugin {
|
|
|
478
763
|
return values(result)
|
|
479
764
|
}
|
|
480
765
|
|
|
481
|
-
|
|
766
|
+
/**
|
|
767
|
+
* Check whether directory is empty or not. More info please {@link https://github.com/gulpjs/empty-dir|check here}.
|
|
768
|
+
*
|
|
769
|
+
* @method
|
|
770
|
+
* @async
|
|
771
|
+
* @param {string} dir - Directory to check. Can be a ns based directory too!
|
|
772
|
+
* @param {function} filterFn - Filter function to filter out files that cause false positives.
|
|
773
|
+
* @returns {boolean}
|
|
774
|
+
*/
|
|
775
|
+
isEmptyDir = async (dir, filterFn) => {
|
|
776
|
+
dir = resolvePath(this.getPluginFile(dir))
|
|
482
777
|
await fs.exists(dir)
|
|
483
|
-
return await emptyDir(dir)
|
|
778
|
+
return await emptyDir(dir, filterFn)
|
|
484
779
|
}
|
|
485
780
|
|
|
781
|
+
/**
|
|
782
|
+
* Check whether log level is within log's app current level
|
|
783
|
+
*
|
|
784
|
+
* @method
|
|
785
|
+
* @param {string} level - Level to check. See {@link LogLevelsType} for more
|
|
786
|
+
* @returns {boolean}
|
|
787
|
+
*/
|
|
486
788
|
isLogInRange = (level) => {
|
|
487
|
-
const levels = keys(
|
|
789
|
+
const levels = keys(logLevels)
|
|
488
790
|
const logLevel = indexOf(levels, this.app.bajo.config.log.level)
|
|
489
791
|
return indexOf(levels, level) >= logLevel
|
|
490
792
|
}
|
|
@@ -503,11 +805,27 @@ class BajoCore extends Plugin {
|
|
|
503
805
|
}
|
|
504
806
|
}
|
|
505
807
|
|
|
808
|
+
/**
|
|
809
|
+
* Check whether directory is a valid Bajo app
|
|
810
|
+
*
|
|
811
|
+
* @method
|
|
812
|
+
* @param {string} dir - Directory to check
|
|
813
|
+
* @param {boolean} [returnPkg] - Set ```true``` to return its package.json content
|
|
814
|
+
* @returns {(boolean|Object)}
|
|
815
|
+
*/
|
|
506
816
|
isValidApp = (dir, returnPkg) => {
|
|
507
817
|
if (!dir) dir = this.app.dir
|
|
508
818
|
return this.isValidAppPlugin(dir, 'app', returnPkg)
|
|
509
819
|
}
|
|
510
820
|
|
|
821
|
+
/**
|
|
822
|
+
* Check whether directory is a valid Bajo plugin
|
|
823
|
+
*
|
|
824
|
+
* @method
|
|
825
|
+
* @param {string} dir - Directory to check
|
|
826
|
+
* @param {boolean} [returnPkg] - Set ```true``` to return its package.json content
|
|
827
|
+
* @returns {(boolean|Object)}
|
|
828
|
+
*/
|
|
511
829
|
isValidPlugin = (dir, returnPkg) => {
|
|
512
830
|
if (!dir) dir = this.app.dir
|
|
513
831
|
return this.isValidAppPlugin(dir, 'plugin', returnPkg)
|
|
@@ -528,22 +846,59 @@ class BajoCore extends Plugin {
|
|
|
528
846
|
return array.map(a => (a + '').trim()).join(separator) + ` ${joiner} ${last}`
|
|
529
847
|
}
|
|
530
848
|
|
|
849
|
+
/**
|
|
850
|
+
* Return its numeric portion of a value
|
|
851
|
+
*
|
|
852
|
+
* @method
|
|
853
|
+
* @param {string} [value=''] - Value to get its numeric portion
|
|
854
|
+
* @param {string} [defUnit=''] - Default unit if value doesn't have one
|
|
855
|
+
* @returns {string}
|
|
856
|
+
*/
|
|
531
857
|
numUnit = (value = '', defUnit = '') => {
|
|
532
858
|
const num = value.match(/\d+/g)
|
|
533
859
|
const unit = value.match(/[a-zA-Z]+/g)
|
|
534
860
|
return `${num[0]}${isEmpty(unit) ? defUnit : unit[0]}`
|
|
535
861
|
}
|
|
536
862
|
|
|
537
|
-
|
|
538
|
-
|
|
863
|
+
/**
|
|
864
|
+
* Parse duration to its millisecond value. Use {@link https://github.com/vercel/ms|ms} under the hood
|
|
865
|
+
*
|
|
866
|
+
* @method
|
|
867
|
+
* @param {(number|string)} dur - If string is given, parse this to its millisecond value. Otherwise return as is
|
|
868
|
+
* @returns {number}
|
|
869
|
+
*/
|
|
870
|
+
parseDur = (dur) => {
|
|
871
|
+
return isNumber(dur) ? dur : ms(dur)
|
|
539
872
|
}
|
|
540
873
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
874
|
+
/**
|
|
875
|
+
* Parse datetime string as Javascript object. Please visit {@link https://day.js.org|dayjs} for valid formats and more infos
|
|
876
|
+
*
|
|
877
|
+
* @method
|
|
878
|
+
* @param {string} dt - Datetime string
|
|
879
|
+
* @returns {Object} Javascript object
|
|
880
|
+
*/
|
|
881
|
+
parseDt = (dt) => {
|
|
882
|
+
const value = this.lib.dayjs(dt)
|
|
883
|
+
if (!value.isValid()) throw this.error('dtUnparsable%s', dt)
|
|
884
|
+
return value.toDate()
|
|
545
885
|
}
|
|
546
886
|
|
|
887
|
+
/**
|
|
888
|
+
* Parse an object and optionally normalize its values recursively. Use {@link https://github.com/ladjs/dotenv-parse-variables}
|
|
889
|
+
* to parse values, so please have a visit to know how it works
|
|
890
|
+
*
|
|
891
|
+
* If ```options.parseValue``` is ```true```, any key ends with ```Dur``` and ```Dt``` will
|
|
892
|
+
* also be parsed as millisecond and Javascript datetime accordingly
|
|
893
|
+
*
|
|
894
|
+
* @method
|
|
895
|
+
* @param {(Object|string)} input - If string is given, parse it first using JSON.parse
|
|
896
|
+
* @param {Object} [options={}] - Options
|
|
897
|
+
* @param {boolean} [options.silent=true] - If ```true``` (default), exception are not thrown and silently ignored
|
|
898
|
+
* @param {boolean} [options.parseValue=false] - If ```true```, values will be parsed & normalized
|
|
899
|
+
* @param {string} [options.lang] - If provided, use this language instead of the one in config
|
|
900
|
+
* @returns {Object}
|
|
901
|
+
*/
|
|
547
902
|
parseObject = (input, options = {}) => {
|
|
548
903
|
const { silent = true, parseValue = false, lang, ns } = options
|
|
549
904
|
const { isSet } = this.lib.aneka
|
|
@@ -553,6 +908,14 @@ class BajoCore extends Plugin {
|
|
|
553
908
|
return scope.print.write(text, ...args, { lang })
|
|
554
909
|
}
|
|
555
910
|
const statics = ['*']
|
|
911
|
+
if (isString(input)) {
|
|
912
|
+
try {
|
|
913
|
+
input = JSON.parse(input)
|
|
914
|
+
} catch (err) {
|
|
915
|
+
if (silent) input = {}
|
|
916
|
+
else throw err
|
|
917
|
+
}
|
|
918
|
+
}
|
|
556
919
|
let obj = cloneDeep(input)
|
|
557
920
|
const keys = Object.keys(obj)
|
|
558
921
|
const mutated = []
|
|
@@ -602,13 +965,31 @@ class BajoCore extends Plugin {
|
|
|
602
965
|
return result
|
|
603
966
|
}
|
|
604
967
|
|
|
968
|
+
/**
|
|
969
|
+
* Read and parse file as config object. Supported types: ```.js``` and ```.json```.
|
|
970
|
+
* More supports can be added using plugin. {@link https://github.com/ardhi/bajo-config|bajo-config} gives you additional supports for ```.yml```, ```.yaml``` and ```.toml``` file
|
|
971
|
+
*
|
|
972
|
+
* If file extension is ```.*```, it will be auto detected and parsed accordingly
|
|
973
|
+
*
|
|
974
|
+
* @method
|
|
975
|
+
* @async
|
|
976
|
+
* @param {string} file - File to read and parse
|
|
977
|
+
* @param {Object} [options={}] - Options
|
|
978
|
+
* @param {boolean} [options.ignoreError] - Any exception will be silently discarded
|
|
979
|
+
* @param {string} [options.ns] - If given, use this as the scope
|
|
980
|
+
* @param {string} [options.pattern] - If given and auto detection is on (extension is ```.*```), it will be used for instead the default one
|
|
981
|
+
* @param {Object} [options.globOptions={}] - {@link https://github.com/mrmlnc/fast-glob|fast-glob} options
|
|
982
|
+
* @param {Object} [options.defValue={}] - Default value to use if value returned empty
|
|
983
|
+
* @param {Object} [options.opts={}] - Parser setting
|
|
984
|
+
* @returns {Object}
|
|
985
|
+
*/
|
|
605
986
|
readConfig = async (file, { ns, pattern, globOptions = {}, ignoreError, defValue = {}, opts = {} } = {}) => {
|
|
606
987
|
if (!ns) ns = this.name
|
|
607
988
|
file = resolvePath(this.getPluginFile(file))
|
|
608
989
|
let ext = path.extname(file)
|
|
609
990
|
const fname = path.dirname(file) + '/' + path.basename(file, ext)
|
|
610
991
|
ext = ext.toLowerCase()
|
|
611
|
-
if (
|
|
992
|
+
if (ext === '.js') {
|
|
612
993
|
const { readHandler } = find(this.app.bajo.configHandlers, { ext })
|
|
613
994
|
return this.parseObject(await readHandler.call(this.app[ns], file, opts))
|
|
614
995
|
}
|
|
@@ -641,6 +1022,14 @@ class BajoCore extends Plugin {
|
|
|
641
1022
|
return this.parseObject(config)
|
|
642
1023
|
}
|
|
643
1024
|
|
|
1025
|
+
/**
|
|
1026
|
+
* Read and parse json file
|
|
1027
|
+
*
|
|
1028
|
+
* @method
|
|
1029
|
+
* @param {string} file - File to read
|
|
1030
|
+
* @param {boolean} [thrownNotFound=false] - If ```true```, silently ignore if file is not found
|
|
1031
|
+
* @returns {Object}
|
|
1032
|
+
*/
|
|
644
1033
|
readJson = (file, thrownNotFound = false) => {
|
|
645
1034
|
if (isPlainObject(thrownNotFound)) thrownNotFound = false
|
|
646
1035
|
if (!fs.existsSync(file) && thrownNotFound) throw this.error('notFound%s%s', this.print.write('file'), file)
|
|
@@ -652,10 +1041,19 @@ class BajoCore extends Plugin {
|
|
|
652
1041
|
return this.parseObject(JSON.parse(resp))
|
|
653
1042
|
}
|
|
654
1043
|
|
|
1044
|
+
/**
|
|
1045
|
+
* Run named hook
|
|
1046
|
+
*
|
|
1047
|
+
* @method
|
|
1048
|
+
* @async
|
|
1049
|
+
* @param {string} hookName - ns based hook name
|
|
1050
|
+
* @param {...any} [args] - Argument passed to the hook function
|
|
1051
|
+
* @returns {Array} Array of hook execution results
|
|
1052
|
+
*/
|
|
655
1053
|
runHook = async (hookName, ...args) => {
|
|
656
1054
|
const [ns, path] = (hookName ?? '').split(':')
|
|
657
1055
|
let fns = filter(this.app.bajo.hooks, { ns, path })
|
|
658
|
-
if (isEmpty(fns)) return
|
|
1056
|
+
if (isEmpty(fns)) return []
|
|
659
1057
|
fns = orderBy(fns, ['level'])
|
|
660
1058
|
const results = []
|
|
661
1059
|
for (const i in fns) {
|
|
@@ -671,15 +1069,29 @@ class BajoCore extends Plugin {
|
|
|
671
1069
|
return results
|
|
672
1070
|
}
|
|
673
1071
|
|
|
674
|
-
|
|
1072
|
+
/**
|
|
1073
|
+
* Save item as file in Bajo's download directory. That is a directory inside your
|
|
1074
|
+
* Bajo plugin's data directory.
|
|
1075
|
+
*
|
|
1076
|
+
* If file exists already, file will automatically be
|
|
1077
|
+
* renamed incrementally.
|
|
1078
|
+
*
|
|
1079
|
+
* @method
|
|
1080
|
+
* @async
|
|
1081
|
+
* @param {string} file - File name
|
|
1082
|
+
* @param {Object} item - Item to save
|
|
1083
|
+
* @param {boolean} [printSaved=true] - Print info on screen
|
|
1084
|
+
* @returns {string} Full file path
|
|
1085
|
+
*/
|
|
1086
|
+
saveAsDownload = async (file, item, printSaved = true) => {
|
|
675
1087
|
const { print, getPluginDataDir } = this.app.bajo
|
|
676
|
-
const fname = increment(`${getPluginDataDir(this.name)}/${trim(file, '/')}`, { fs: true })
|
|
1088
|
+
const fname = increment(`${getPluginDataDir(this.name)}/download/${trim(file, '/')}`, { fs: true })
|
|
677
1089
|
const dir = path.dirname(fname)
|
|
678
1090
|
if (!fs.existsSync(dir)) fs.ensureDirSync(dir)
|
|
679
|
-
await fs.writeFile(fname,
|
|
1091
|
+
await fs.writeFile(fname, item, 'utf8')
|
|
680
1092
|
if (printSaved) print.succeed('savedAs%s', path.resolve(fname), { skipSilence: true })
|
|
681
1093
|
return fname
|
|
682
1094
|
}
|
|
683
1095
|
}
|
|
684
1096
|
|
|
685
|
-
export default
|
|
1097
|
+
export default Bajo
|