bajo 2.1.0 → 2.2.1
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 +0 -0
- package/.github/workflows/repo-lockdown.yml +0 -0
- package/.jsdoc.conf.json +0 -0
- package/.mocharc.json +4 -0
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/class/{misc → app}/log.js +8 -2
- package/class/app.js +63 -50
- package/class/bajo.js +43 -211
- package/class/base.js +25 -22
- package/class/helper/bajo.js +55 -53
- package/class/helper/base.js +37 -75
- package/class/{misc → plugin}/err.js +23 -18
- package/class/{misc → plugin}/print.js +7 -16
- package/class/plugin/tools.js +42 -0
- package/class/plugin.js +58 -54
- package/docs/App.html +0 -0
- package/docs/Bajo.html +0 -0
- package/docs/Base.html +0 -0
- package/docs/Err.html +0 -0
- package/docs/Log.html +0 -0
- package/docs/Plugin.html +0 -0
- package/docs/Print.html +0 -0
- package/docs/class_app.js.html +0 -0
- package/docs/class_bajo.js.html +0 -0
- package/docs/class_base.js.html +0 -0
- package/docs/class_helper_bajo.js.html +0 -0
- package/docs/class_helper_base.js.html +0 -0
- package/docs/class_misc_err.js.html +0 -0
- package/docs/class_misc_log.js.html +0 -0
- package/docs/class_misc_print.js.html +0 -0
- package/docs/class_plugin.js.html +0 -0
- package/docs/data/search.json +0 -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 +0 -0
- package/docs/index.html +0 -0
- package/docs/index.js.html +0 -0
- package/docs/lib_current-loc.js.html +0 -0
- package/docs/lib_formats.js.html +0 -0
- package/docs/lib_import-module.js.html +0 -0
- package/docs/lib_log-levels.js.html +0 -0
- package/docs/lib_parse-args-argv.js.html +0 -0
- package/docs/lib_parse-env.js.html +0 -0
- package/docs/lib_resolve-path.js.html +0 -0
- package/docs/lib_shim.js.html +0 -0
- package/docs/module-Helper_Bajo.html +0 -0
- package/docs/module-Helper_Base.html +0 -0
- package/docs/module-Lib.html +0 -0
- package/docs/scripts/core.js +476 -477
- package/docs/scripts/core.min.js +0 -0
- package/docs/scripts/resize.js +36 -36
- package/docs/scripts/search.js +105 -105
- package/docs/scripts/search.min.js +0 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +0 -0
- package/docs/scripts/third-party/fuse.js +1 -1
- package/docs/scripts/third-party/hljs-line-num-original.js +282 -285
- package/docs/scripts/third-party/hljs-line-num.js +1 -1
- package/docs/scripts/third-party/hljs-original.js +1195 -1202
- package/docs/scripts/third-party/hljs.js +1 -1
- package/docs/scripts/third-party/popper.js +1 -1
- package/docs/scripts/third-party/tippy.js +1 -1
- package/docs/scripts/third-party/tocbot.js +508 -509
- package/docs/scripts/third-party/tocbot.min.js +0 -0
- package/docs/static/bitcoin.jpeg +0 -0
- package/docs/static/home.md +0 -0
- package/docs/static/logo-ecosystem.png +0 -0
- package/docs/static/logo.png +0 -0
- package/docs/styles/clean-jsdoc-theme-base.css +0 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +0 -0
- package/docs/styles/clean-jsdoc-theme-light.css +0 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -0
- package/docs/styles/clean-jsdoc-theme.min.css +0 -0
- package/extend/bajo/intl/en-US.json +10 -5
- package/extend/bajo/intl/id.json +10 -5
- package/extend/waibuStatic/virtual.json +0 -0
- package/index.js +9 -1
- package/lib/find-deep.js +24 -0
- package/lib/formats.js +0 -0
- package/lib/freeze.js +16 -0
- package/lib/import-module.js +5 -3
- package/lib/index.js +6 -0
- package/lib/log-levels.js +0 -0
- package/package.json +5 -11
- package/test/base.test.js +108 -0
- package/wiki/CHANGES.md +68 -0
- package/wiki/CONFIG.md +0 -0
- package/wiki/CONTRIBUTING.md +0 -0
- package/wiki/DEV_GUIDE.md +0 -0
- package/wiki/ECOSYSTEM.md +0 -0
- package/wiki/GETTING-STARTED.md +1 -1
- package/wiki/USER-GUIDE.md +0 -0
- package/lib/current-loc.js +0 -33
- package/lib/parse-args-argv.js +0 -80
- package/lib/parse-env.js +0 -50
- package/lib/resolve-path.js +0 -24
- package/lib/shim.js +0 -37
package/class/helper/bajo.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import Print from '../misc/print.js'
|
|
4
|
-
import Log from '../misc/log.js'
|
|
1
|
+
import Print from '../plugin/print.js'
|
|
2
|
+
import Log from '../app/log.js'
|
|
5
3
|
import omitDeep from 'omit-deep'
|
|
6
4
|
import os from 'os'
|
|
7
5
|
import fs from 'fs-extra'
|
|
@@ -10,15 +8,14 @@ import {
|
|
|
10
8
|
buildConfigs,
|
|
11
9
|
checkDependencies,
|
|
12
10
|
checkNameAliases,
|
|
13
|
-
attachMethods,
|
|
14
11
|
collectHooks,
|
|
15
12
|
run
|
|
16
13
|
} from './base.js'
|
|
14
|
+
import aneka from 'aneka'
|
|
15
|
+
|
|
16
|
+
const { currentLoc, resolvePath } = aneka
|
|
17
17
|
|
|
18
18
|
const {
|
|
19
|
-
reduce,
|
|
20
|
-
isNaN,
|
|
21
|
-
forOwn,
|
|
22
19
|
orderBy,
|
|
23
20
|
isFunction,
|
|
24
21
|
isPlainObject,
|
|
@@ -40,6 +37,9 @@ const omitted = ['spawn', 'cwd', 'name', 'alias', 'applet', 'a', 'plugins']
|
|
|
40
37
|
|
|
41
38
|
const defConfig = {
|
|
42
39
|
env: 'dev',
|
|
40
|
+
runtime: {
|
|
41
|
+
noWarning: false
|
|
42
|
+
},
|
|
43
43
|
log: {
|
|
44
44
|
timeTaken: false,
|
|
45
45
|
dateFormat: 'YYYY-MM-DDTHH:mm:ss.SSS',
|
|
@@ -81,7 +81,7 @@ const defConfig = {
|
|
|
81
81
|
const defMain = `async function factory (pkgName) {
|
|
82
82
|
const me = this
|
|
83
83
|
|
|
84
|
-
return class Main extends this.app.
|
|
84
|
+
return class Main extends this.app.baseClass.Base {
|
|
85
85
|
constructor () {
|
|
86
86
|
super(pkgName, me.app)
|
|
87
87
|
this.config = {}
|
|
@@ -115,20 +115,24 @@ export async function buildBaseConfig () {
|
|
|
115
115
|
this.config = defaultsDeep({}, this.app.envVars._, this.app.argv._)
|
|
116
116
|
set(this, 'dir.base', this.app.dir)
|
|
117
117
|
const path = currentLoc(import.meta).dir + '/../..'
|
|
118
|
-
set(this, 'dir.pkg',
|
|
118
|
+
set(this, 'dir.pkg', resolvePath(path))
|
|
119
119
|
if (get(this, 'config.dir.data')) set(this, 'dir.data', this.config.dir.data)
|
|
120
120
|
if (!get(this, 'dir.data')) set(this, 'dir.data', `${this.dir.base}/data`)
|
|
121
|
-
this.dir.data =
|
|
121
|
+
this.dir.data = resolvePath(this.dir.data)
|
|
122
122
|
fs.ensureDirSync(`${this.dir.data}/config`)
|
|
123
123
|
if (!this.dir.tmp) {
|
|
124
|
-
this.dir.tmp = `${
|
|
124
|
+
this.dir.tmp = `${resolvePath(os.tmpdir())}/${this.ns}`
|
|
125
125
|
fs.ensureDirSync(this.dir.tmp)
|
|
126
126
|
}
|
|
127
|
+
this.pkg = await this.getPkgInfo()
|
|
127
128
|
// collect list of plugins
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
129
|
+
const mainPkg = await this.getPkgInfo(this.app.dir)
|
|
130
|
+
let pluginPkgs = get(mainPkg, 'bajo.plugins', [])
|
|
131
|
+
if (isEmpty(pluginPkgs)) {
|
|
132
|
+
const pluginsFile = `${this.dir.data}/config/.plugins`
|
|
133
|
+
if (fs.existsSync(pluginsFile)) {
|
|
134
|
+
pluginPkgs = pluginPkgs.concat(filter(map(trim(fs.readFileSync(pluginsFile, 'utf8')).split('\n'), p => trim(p)), b => !isEmpty(b)))
|
|
135
|
+
}
|
|
132
136
|
}
|
|
133
137
|
this.app.pluginPkgs = map(filter(without(uniq(pluginPkgs), this.app.mainNs), p => {
|
|
134
138
|
return p[0] !== '#'
|
|
@@ -164,7 +168,10 @@ export async function buildPlugins () {
|
|
|
164
168
|
const { default: builder } = await import(resolvePath(factory, true))
|
|
165
169
|
const ClassDef = await builder.call(this, pkg)
|
|
166
170
|
const plugin = new ClassDef()
|
|
167
|
-
if (!(plugin instanceof this.app.
|
|
171
|
+
if (!(plugin instanceof this.app.baseClass.Base)) throw this.error('pluginPackageInvalid%s', pkg)
|
|
172
|
+
plugin.pkg = plugin.getPkgInfo(ns === 'main' ? this.dir.base : dir)
|
|
173
|
+
plugin.alias = ns === 'main' ? this.app.mainNs : get(plugin.pkg, 'bajo.alias', (pkg.slice(0, 5) === 'bajo-' ? pkg.slice(5) : ns).toLowerCase())
|
|
174
|
+
plugin.dependencies = get(plugin.pkg, 'bajo.dependencies', [])
|
|
168
175
|
this.app.addPlugin(plugin, ClassDef)
|
|
169
176
|
this.log.trace('- ' + pkg)
|
|
170
177
|
}
|
|
@@ -190,7 +197,6 @@ export async function collectConfigHandlers () {
|
|
|
190
197
|
if (isPlainObject(mod)) mod = [mod]
|
|
191
198
|
this.app.configHandlers = this.app.configHandlers.concat(mod)
|
|
192
199
|
}
|
|
193
|
-
this.app.log = new Log(this.app)
|
|
194
200
|
}
|
|
195
201
|
|
|
196
202
|
/**
|
|
@@ -204,9 +210,11 @@ export async function collectConfigHandlers () {
|
|
|
204
210
|
export async function buildExtConfig () {
|
|
205
211
|
// config merging
|
|
206
212
|
const { defaultsDeep } = this.app.lib.aneka
|
|
213
|
+
const { parseObject } = this.app.lib
|
|
214
|
+
|
|
207
215
|
let resp = await this.readAllConfigs(`${this.dir.data}/config/${this.ns}`)
|
|
208
|
-
resp = omitDeep(pick(resp, ['log', 'exitHandler', 'env']), omitted)
|
|
209
|
-
const envs = this.app.
|
|
216
|
+
resp = omitDeep(pick(resp, ['log', 'exitHandler', 'env', 'runtime']), omitted)
|
|
217
|
+
const envs = this.app.envs
|
|
210
218
|
this.config = defaultsDeep({}, this.config, resp, defConfig)
|
|
211
219
|
// language
|
|
212
220
|
this.config.lang = (this.config.lang ?? '').split('.')[0]
|
|
@@ -219,13 +227,15 @@ export async function buildExtConfig () {
|
|
|
219
227
|
if (!this.config.log.level) this.config.log.level = this.config.env === 'dev' ? 'debug' : 'info'
|
|
220
228
|
// misc
|
|
221
229
|
const obj = this.app.applet ? this.config : pick(this.config, keys(defConfig))
|
|
222
|
-
this.config =
|
|
230
|
+
this.config = parseObject(obj, { parseValue: true })
|
|
223
231
|
const exts = this.app.getConfigFormats()
|
|
224
232
|
if (this.app.applet) {
|
|
225
233
|
if (!this.app.pluginPkgs.includes('bajo-cli')) throw this.error('appletNeedsBajoCli')
|
|
226
234
|
if (!this.config.log.applet) this.config.log.level = 'silent'
|
|
227
235
|
this.config.exitHandler = false
|
|
228
236
|
}
|
|
237
|
+
if (this.config.runtime.noWarning) process.removeAllListeners('warning')
|
|
238
|
+
this.app.log = new Log(this.app)
|
|
229
239
|
this.log.trace('dataDir%s', this.dir.data)
|
|
230
240
|
this.log.debug('configHandlers%s', this.join(exts))
|
|
231
241
|
}
|
|
@@ -236,32 +246,26 @@ export async function buildExtConfig () {
|
|
|
236
246
|
* @async
|
|
237
247
|
*/
|
|
238
248
|
export async function bootOrder () {
|
|
249
|
+
const { freeze } = this.app.lib
|
|
250
|
+
const { isNumber } = this.app.lib._
|
|
239
251
|
this.log.debug('setupBootOrder')
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
norder[n] = Number(trim(await fs.readFile(`${dir}/.bootorder`, 'utf8')))
|
|
254
|
-
} catch (err) {}
|
|
252
|
+
let counter = 1000
|
|
253
|
+
const orders = []
|
|
254
|
+
for (const pkg of this.app.pluginPkgs) {
|
|
255
|
+
const item = { pkg }
|
|
256
|
+
const ns = camelCase(pkg)
|
|
257
|
+
const order = get(this.app[ns], 'pkg.bajo.bootorder')
|
|
258
|
+
if (isNumber(order)) item.val = order
|
|
259
|
+
else {
|
|
260
|
+
item.val = counter
|
|
261
|
+
counter++
|
|
262
|
+
}
|
|
263
|
+
orders.push(item)
|
|
255
264
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const item = { k, v: isNaN(norder[k]) ? v : norder[k] }
|
|
259
|
-
result.push(item)
|
|
260
|
-
})
|
|
261
|
-
this.app.pluginPkgs = map(orderBy(result, ['v']), 'k')
|
|
262
|
-
this.log.debug('runInEnv%s', this.t(this.app.constructor.envs[this.config.env]))
|
|
265
|
+
this.app.pluginPkgs = map(orderBy(orders, ['val']), 'pkg')
|
|
266
|
+
this.log.debug('runInEnv%s', this.t(this.app.envs[this.config.env]))
|
|
263
267
|
// misc
|
|
264
|
-
|
|
268
|
+
freeze(this.config)
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
/**
|
|
@@ -270,9 +274,8 @@ export async function bootOrder () {
|
|
|
270
274
|
* 1. {@link module:Helper/Base.buildConfigs|build configs}
|
|
271
275
|
* 2. {@link module:Helper/Base.checkNameAliases|ensure names & aliases uniqueness}
|
|
272
276
|
* 3. {@link module:Helper/Base.checkDependencies|ensure dependencies are met}
|
|
273
|
-
* 4. {@link module:Helper/Base.
|
|
274
|
-
* 5. {@link module:Helper/Base.
|
|
275
|
-
* 6. {@link module:Helper/Base.run|run plugins}
|
|
277
|
+
* 4. {@link module:Helper/Base.collectHooks|collect hooks}
|
|
278
|
+
* 5. {@link module:Helper/Base.run|run plugins}
|
|
276
279
|
*
|
|
277
280
|
* @async
|
|
278
281
|
*/
|
|
@@ -280,7 +283,6 @@ export async function bootPlugins () {
|
|
|
280
283
|
await buildConfigs.call(this.app)
|
|
281
284
|
await checkNameAliases.call(this.app)
|
|
282
285
|
await checkDependencies.call(this.app)
|
|
283
|
-
await attachMethods.call(this.app)
|
|
284
286
|
await collectHooks.call(this.app)
|
|
285
287
|
await run.call(this.app)
|
|
286
288
|
}
|
|
@@ -296,11 +298,12 @@ export async function exitHandler () {
|
|
|
296
298
|
async function exit (signal) {
|
|
297
299
|
const { eachPlugins } = this
|
|
298
300
|
if (signal) this.log.warn('signalReceived%s', signal)
|
|
301
|
+
const me = this
|
|
299
302
|
await eachPlugins(async function ({ ns }) {
|
|
300
303
|
try {
|
|
301
304
|
await this.exit()
|
|
302
305
|
} catch (err) {}
|
|
303
|
-
|
|
306
|
+
me.log.trace('exited%s', this.ns)
|
|
304
307
|
})
|
|
305
308
|
this.log.debug('appShutdown')
|
|
306
309
|
process.exit(0)
|
|
@@ -356,8 +359,7 @@ export async function exitHandler () {
|
|
|
356
359
|
export async function runAsApplet () {
|
|
357
360
|
const { isString, map, find } = this.app.lib._
|
|
358
361
|
await this.eachPlugins(async function ({ file }) {
|
|
359
|
-
const { ns } = this
|
|
360
|
-
const { alias } = this.constructor
|
|
362
|
+
const { ns, alias } = this
|
|
361
363
|
this.app.applets.push({ ns, file, alias })
|
|
362
364
|
}, { glob: 'applet.js', prefix: 'bajoCli' })
|
|
363
365
|
|
|
@@ -385,7 +387,7 @@ export async function runAsApplet () {
|
|
|
385
387
|
* @see {@tutorial hook}
|
|
386
388
|
* @see module:Helper/Bajo.runAsApplet
|
|
387
389
|
*/
|
|
388
|
-
await this.runHook(`${
|
|
390
|
+
await this.runHook(`${applet.ns}:beforeAppletRun`, ...this.app.args)
|
|
389
391
|
await this.app.bajoCli.runApplet(applet, path, ...this.app.args)
|
|
390
392
|
/**
|
|
391
393
|
* Run after applet is run. ```[ns]``` is applet's namespace
|
|
@@ -396,5 +398,5 @@ export async function runAsApplet () {
|
|
|
396
398
|
* @see {@tutorial hook}
|
|
397
399
|
* @see module:Helper/Bajo.runAsApplet
|
|
398
400
|
*/
|
|
399
|
-
await this.runHook(`${
|
|
401
|
+
await this.runHook(`${applet.ns}:afterAppletRun`, ...this.app.args)
|
|
400
402
|
}
|
package/class/helper/base.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import semver from 'semver'
|
|
2
2
|
import lodash from 'lodash'
|
|
3
|
-
import Print from '../
|
|
4
|
-
import path from 'path'
|
|
5
|
-
import resolvePath from '../../lib/resolve-path.js'
|
|
3
|
+
import Print from '../plugin/print.js'
|
|
6
4
|
|
|
7
5
|
const {
|
|
8
|
-
isFunction,
|
|
9
6
|
merge,
|
|
10
7
|
forOwn,
|
|
11
8
|
groupBy,
|
|
@@ -27,41 +24,6 @@ const {
|
|
|
27
24
|
* @module Helper/Base
|
|
28
25
|
*/
|
|
29
26
|
|
|
30
|
-
/**
|
|
31
|
-
* Scan plugins ```method``` directories, and turn + attach its found files as methods dynamically.
|
|
32
|
-
*
|
|
33
|
-
* @async
|
|
34
|
-
*/
|
|
35
|
-
export async function attachMethods () {
|
|
36
|
-
const { fastGlob } = this.lib
|
|
37
|
-
|
|
38
|
-
async function createMethod (dir) {
|
|
39
|
-
dir = resolvePath(dir)
|
|
40
|
-
const files = await fastGlob([`!${dir}/**/_*.{js,json}`, `${dir}/**/*.{js,json}`])
|
|
41
|
-
for (const f of files) {
|
|
42
|
-
const ext = path.extname(f)
|
|
43
|
-
const base = f.replace(dir, '').slice(0, -ext.length)
|
|
44
|
-
const name = camelCase(base)
|
|
45
|
-
let mod
|
|
46
|
-
if (ext === '.json') mod = this.app.bajo.readJson(f)
|
|
47
|
-
else mod = await this.app.bajo.importModule(f)
|
|
48
|
-
if (isFunction(mod)) mod = mod.bind(this)
|
|
49
|
-
this[name] = mod
|
|
50
|
-
}
|
|
51
|
-
return files.length
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const { eachPlugins } = this.bajo
|
|
55
|
-
const me = this // the app
|
|
56
|
-
me.bajo.log.debug('attachMethods')
|
|
57
|
-
await eachPlugins(async function () {
|
|
58
|
-
const { ns, pkgName } = this
|
|
59
|
-
const dir = ns === me.mainNs ? (`${me.bajo.dir.base}/${me.mainNs}`) : me.bajo.getModuleDir(pkgName)
|
|
60
|
-
const num = await createMethod.call(me[ns], `${dir}/method`, pkgName)
|
|
61
|
-
me.bajo.log.trace('- %s (%d)', ns, num)
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
|
|
65
27
|
/**
|
|
66
28
|
* Build configurations
|
|
67
29
|
*
|
|
@@ -82,18 +44,17 @@ export async function buildConfigs () {
|
|
|
82
44
|
* @async
|
|
83
45
|
*/
|
|
84
46
|
export async function checkNameAliases () {
|
|
85
|
-
const { eachPlugins } = this.bajo
|
|
86
47
|
this.bajo.log.debug('checkAliasNameClash')
|
|
87
48
|
const refs = []
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
const { alias } =
|
|
49
|
+
for (const pkg of this.bajo.app.pluginPkgs) {
|
|
50
|
+
const plugin = this.bajo.app[camelCase(pkg)]
|
|
51
|
+
const { ns, alias } = plugin
|
|
91
52
|
let item = find(refs, { ns })
|
|
92
|
-
if (item) throw this.error('pluginNameClash%s%s%s%s', ns,
|
|
53
|
+
if (item) throw this.error('pluginNameClash%s%s%s%s', ns, pkg, item.ns, item.pkg, { code: 'BAJO_NAME_CLASH' })
|
|
93
54
|
item = find(refs, { alias })
|
|
94
|
-
if (item) throw this.error('pluginNameClash%s%s%s%s', alias,
|
|
95
|
-
refs.push({ ns, alias,
|
|
96
|
-
}
|
|
55
|
+
if (item) throw this.error('pluginNameClash%s%s%s%s', alias, pkg, item.alias, item.pkg, { code: 'BAJO_ALIAS_CLASH' })
|
|
56
|
+
refs.push({ ns, alias, pkg })
|
|
57
|
+
}
|
|
97
58
|
}
|
|
98
59
|
|
|
99
60
|
/**
|
|
@@ -102,11 +63,12 @@ export async function checkNameAliases () {
|
|
|
102
63
|
* @async
|
|
103
64
|
*/
|
|
104
65
|
export async function checkDependencies () {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
const { dependencies } =
|
|
66
|
+
const { join } = this.bajo
|
|
67
|
+
this.bajo.log.debug('checkDeps')
|
|
68
|
+
for (const pkg of this.bajo.app.pluginPkgs) {
|
|
69
|
+
const plugin = this.bajo.app[camelCase(pkg)]
|
|
70
|
+
const { ns, dependencies } = plugin
|
|
71
|
+
this.bajo.log.trace('- %s', ns)
|
|
110
72
|
const odep = reduce(dependencies, (o, k) => {
|
|
111
73
|
const item = map(k.split('@'), m => trim(m))
|
|
112
74
|
if (k[0] === '@') o['@' + item[1]] = item[2]
|
|
@@ -115,25 +77,19 @@ export async function checkDependencies () {
|
|
|
115
77
|
}, {})
|
|
116
78
|
const deps = keys(odep)
|
|
117
79
|
if (deps.length > 0) {
|
|
118
|
-
if (intersection(this.app.pluginPkgs, deps).length !== deps.length) {
|
|
119
|
-
throw this.error('dependencyUnfulfilled%s%s',
|
|
80
|
+
if (intersection(this.bajo.app.pluginPkgs, deps).length !== deps.length) {
|
|
81
|
+
throw this.error('dependencyUnfulfilled%s%s', pkg, join(deps), { code: 'BAJO_DEPENDENCY' })
|
|
120
82
|
}
|
|
121
83
|
each(deps, d => {
|
|
122
84
|
if (!odep[d]) return
|
|
123
|
-
const ver = get(this.app[camelCase(d)], '
|
|
85
|
+
const ver = get(this.bajo.app[camelCase(d)], 'pkg.version')
|
|
124
86
|
if (!ver) return
|
|
125
87
|
if (!semver.satisfies(ver, odep[d])) {
|
|
126
|
-
throw this.error('semverCheckFailed%s%s',
|
|
88
|
+
throw this.error('semverCheckFailed%s%s', pkg, `${d}@${odep[d]}`, { code: 'BAJO_DEPENDENCY_SEMVER' })
|
|
127
89
|
}
|
|
128
90
|
})
|
|
129
91
|
}
|
|
130
92
|
}
|
|
131
|
-
|
|
132
|
-
const { eachPlugins } = this.bajo
|
|
133
|
-
this.bajo.log.debug('checkDeps')
|
|
134
|
-
await eachPlugins(async function () {
|
|
135
|
-
await runner.call(this)
|
|
136
|
-
})
|
|
137
93
|
}
|
|
138
94
|
|
|
139
95
|
/**
|
|
@@ -146,25 +102,26 @@ export async function collectHooks () {
|
|
|
146
102
|
const { eachPlugins, runHook, isLogInRange, importModule, breakNsPathFromFile } = this.bajo
|
|
147
103
|
const me = this
|
|
148
104
|
me.bajo.hooks = this.bajo.hooks ?? []
|
|
149
|
-
me.bajo.log.
|
|
105
|
+
me.bajo.log.trace('collecting%s', this.t('hooks'))
|
|
150
106
|
// collects
|
|
151
107
|
await eachPlugins(async function ({ dir, file }) {
|
|
152
|
-
const { ns } = this
|
|
153
|
-
const {
|
|
108
|
+
const { ns: baseNs } = this
|
|
109
|
+
const { ns, subNs, path } = breakNsPathFromFile({ file, dir, baseNs, suffix: '/hook/' })
|
|
154
110
|
const mod = await importModule(file, { asHandler: true })
|
|
155
111
|
if (!mod) return undefined
|
|
156
|
-
merge(mod, { ns
|
|
112
|
+
merge(mod, { ns, subNs, path, src: baseNs })
|
|
157
113
|
me.bajo.hooks.push(mod)
|
|
158
114
|
}, { glob: 'hook/**/*.js', prefix: me.bajo.ns })
|
|
159
115
|
// for log trace purpose only
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
116
|
+
if (isLogInRange('trace')) {
|
|
117
|
+
const items = groupBy(me.bajo.hooks, item => item.ns + (item.subNs ? `.${item.subNs}` : ''))
|
|
118
|
+
forOwn(items, (v, k) => {
|
|
119
|
+
const hooks = groupBy(v, 'path')
|
|
120
|
+
forOwn(hooks, (v1, k1) => {
|
|
121
|
+
me.bajo.log.trace('- %s:%s (%d)', k, k1, v1.length)
|
|
122
|
+
})
|
|
166
123
|
})
|
|
167
|
-
}
|
|
124
|
+
}
|
|
168
125
|
|
|
169
126
|
/**
|
|
170
127
|
* Run after hooks are collected
|
|
@@ -176,6 +133,7 @@ export async function collectHooks () {
|
|
|
176
133
|
* @see module:Helper/Base.collectHooks
|
|
177
134
|
*/
|
|
178
135
|
await runHook('bajo:afterCollectHooks', this.bajo.hooks)
|
|
136
|
+
me.bajo.log.debug('collected%s%d', this.t('hooks'), me.bajo.hooks.length)
|
|
179
137
|
}
|
|
180
138
|
|
|
181
139
|
/**
|
|
@@ -190,10 +148,9 @@ export async function collectHooks () {
|
|
|
190
148
|
export async function run () {
|
|
191
149
|
const me = this
|
|
192
150
|
const { runHook, eachPlugins, join } = me.bajo
|
|
193
|
-
const { freeze } = me.
|
|
151
|
+
const { freeze } = me.lib
|
|
194
152
|
const methods = ['init']
|
|
195
153
|
if (!me.applet) methods.push('start')
|
|
196
|
-
me.bajo.log.debug('loadedPlugins%s', join(map(me.bajo.app.pluginPkgs, b => camelCase(b))))
|
|
197
154
|
for (const method of methods) {
|
|
198
155
|
/**
|
|
199
156
|
* Run before all ```{method}``` executed. Accepted ```{method}```: ```Init``` or ```Start```
|
|
@@ -240,4 +197,9 @@ export async function run () {
|
|
|
240
197
|
*/
|
|
241
198
|
await runHook(`bajo:${camelCase(`after all ${method}`)}`)
|
|
242
199
|
}
|
|
200
|
+
if (me.bajo.config.log.level === 'trace') {
|
|
201
|
+
let text = join(map(me.bajo.app.pluginPkgs, b => camelCase(b)))
|
|
202
|
+
text += ` (${me.bajo.app.pluginPkgs.length})`
|
|
203
|
+
me.bajo.log.trace('loadedPlugins%s', text)
|
|
204
|
+
} else me.bajo.log.debug('loadedPlugins%s', me.bajo.app.pluginPkgs.length)
|
|
243
205
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import lodash from 'lodash'
|
|
2
|
+
import Tools from './tools.js'
|
|
3
|
+
|
|
2
4
|
const { isPlainObject, each, isArray, get, isEmpty, merge } = lodash
|
|
3
5
|
|
|
4
6
|
Error.stackTraceLimit = 15
|
|
@@ -14,24 +16,14 @@ Error.stackTraceLimit = 15
|
|
|
14
16
|
* if (notfound) throw this.error('Sorry, item is nowhere to be found!')
|
|
15
17
|
* ```
|
|
16
18
|
*/
|
|
17
|
-
class Err {
|
|
19
|
+
class Err extends Tools {
|
|
18
20
|
/**
|
|
19
21
|
* @param {Plugin} plugin - Plugin instance
|
|
20
22
|
* @param {string} msg - Error message
|
|
21
23
|
* @param {...any} [args] - Variables to interpolate with error message. Payload object can be pushed at the very last argument
|
|
22
24
|
*/
|
|
23
25
|
constructor (plugin, msg, ...args) {
|
|
24
|
-
|
|
25
|
-
* Attached plugin
|
|
26
|
-
* @type {Plugin}
|
|
27
|
-
*/
|
|
28
|
-
this.plugin = plugin
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The app instance
|
|
32
|
-
* @type {App}
|
|
33
|
-
*/
|
|
34
|
-
this.app = plugin.app
|
|
26
|
+
super(plugin)
|
|
35
27
|
|
|
36
28
|
/**
|
|
37
29
|
* Error payload extracted from the last arguments
|
|
@@ -50,7 +42,6 @@ class Err {
|
|
|
50
42
|
* @type {string}
|
|
51
43
|
*/
|
|
52
44
|
this.message = this.payload.noTrans ? msg : this.plugin.t(msg, ...args)
|
|
53
|
-
this.write()
|
|
54
45
|
}
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -69,10 +60,12 @@ class Err {
|
|
|
69
60
|
stacks.splice(1, 1)
|
|
70
61
|
err.stack = stacks.join('\n')
|
|
71
62
|
const values = {}
|
|
63
|
+
let detailsMessage
|
|
72
64
|
for (const key in this.payload) {
|
|
73
65
|
const value = this.payload[key]
|
|
74
66
|
if (key === 'details' && isArray(value)) {
|
|
75
|
-
const result = this.formatErrorDetails(value)
|
|
67
|
+
const { result, detailsMessage: dm } = this.formatErrorDetails(value)
|
|
68
|
+
if (!isEmpty(dm)) detailsMessage = dm
|
|
76
69
|
if (result) merge(values, result)
|
|
77
70
|
}
|
|
78
71
|
err[key] = value
|
|
@@ -80,6 +73,7 @@ class Err {
|
|
|
80
73
|
if (!isEmpty(values)) err.values = values
|
|
81
74
|
err.ns = this.plugin.ns
|
|
82
75
|
err.orgMessage = this.orgMessage
|
|
76
|
+
if (detailsMessage) err.detailsMessage = detailsMessage
|
|
83
77
|
return err
|
|
84
78
|
}
|
|
85
79
|
|
|
@@ -91,7 +85,7 @@ class Err {
|
|
|
91
85
|
fatal = () => {
|
|
92
86
|
const err = this.write()
|
|
93
87
|
console.error(err)
|
|
94
|
-
this.app.exit()
|
|
88
|
+
this.app.exit(true)
|
|
95
89
|
}
|
|
96
90
|
|
|
97
91
|
/**
|
|
@@ -102,9 +96,10 @@ class Err {
|
|
|
102
96
|
* @returns {Object}
|
|
103
97
|
*/
|
|
104
98
|
formatErrorDetails = (value) => {
|
|
105
|
-
const { isString } = this.app.lib._
|
|
99
|
+
const { isString, last } = this.app.lib._
|
|
106
100
|
const result = {}
|
|
107
101
|
const me = this
|
|
102
|
+
const detailsMessage = []
|
|
108
103
|
each(value, (v, i) => {
|
|
109
104
|
if (isString(v)) v = { error: v }
|
|
110
105
|
if (!v.context) return undefined
|
|
@@ -112,14 +107,24 @@ class Err {
|
|
|
112
107
|
if (v.type === 'any.only') v.context.ref = get(v, 'context.valids', []).join(', ')
|
|
113
108
|
const field = get(v, 'context.key')
|
|
114
109
|
const val = get(v, 'context.value')
|
|
110
|
+
let error = me.plugin.t(`validation.${v.type}`, v.context ?? {}, {})
|
|
111
|
+
if (error.includes(' ref:')) {
|
|
112
|
+
const item = last(error.split(' '))
|
|
113
|
+
const [, rfield] = item.split(':')
|
|
114
|
+
error = error.replace(item, `'${me.plugin.t('field.' + rfield)}'`)
|
|
115
|
+
}
|
|
115
116
|
value[i] = {
|
|
116
117
|
field,
|
|
117
|
-
error
|
|
118
|
+
error,
|
|
118
119
|
value: val,
|
|
119
120
|
ext: { type: v.type, context: v.context }
|
|
120
121
|
}
|
|
122
|
+
detailsMessage.push(me.plugin.t('fieldError%s%s', field, value[i].error))
|
|
121
123
|
})
|
|
122
|
-
return
|
|
124
|
+
return {
|
|
125
|
+
result,
|
|
126
|
+
detailsMessage: detailsMessage.length > 0 ? (me.plugin.t('error') + ': ' + detailsMessage.join(', ')) : ''
|
|
127
|
+
}
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import ora from 'ora'
|
|
2
2
|
import lodash from 'lodash'
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import defaultsDeep from 'aneka/src/defaults-deep.js'
|
|
4
|
+
import secToHms from 'aneka/src/sec-to-hms.js'
|
|
5
|
+
import Tools from './tools.js'
|
|
5
6
|
|
|
6
7
|
const { isPlainObject } = lodash
|
|
7
8
|
|
|
@@ -22,29 +23,19 @@ const { isPlainObject } = lodash
|
|
|
22
23
|
*
|
|
23
24
|
* @class
|
|
24
25
|
*/
|
|
25
|
-
class Print {
|
|
26
|
+
class Print extends Tools {
|
|
26
27
|
/**
|
|
27
28
|
* @param {Plugin} plugin - Plugin instance
|
|
28
29
|
* @param {TPrintOptions} [options={}] - Options object
|
|
29
30
|
*/
|
|
30
31
|
constructor (plugin, options = {}) {
|
|
32
|
+
super(plugin)
|
|
33
|
+
|
|
31
34
|
/**
|
|
32
35
|
* Options object
|
|
33
36
|
* @type {TPrintOptions}
|
|
34
37
|
*/
|
|
35
38
|
this.options = options
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Attached plugin
|
|
39
|
-
* @type {Plugin}
|
|
40
|
-
*/
|
|
41
|
-
this.plugin = plugin
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The app instance
|
|
45
|
-
* @type {App}
|
|
46
|
-
*/
|
|
47
|
-
this.app = plugin.app
|
|
48
39
|
if (this.app.applet) {
|
|
49
40
|
if (this.app.bajo.config.counter) this.options.showCounter = true
|
|
50
41
|
if (this.app.bajo.config.datetime) this.options.showDatetime = true
|
|
@@ -122,7 +113,7 @@ class Print {
|
|
|
122
113
|
getElapsed = (unit = 'hms') => {
|
|
123
114
|
const u = unit === 'hms' ? 'second' : unit
|
|
124
115
|
const elapsed = this.app.lib.dayjs().diff(this.startTime, u)
|
|
125
|
-
return unit === 'hms' ?
|
|
116
|
+
return unit === 'hms' ? secToHms(elapsed) : elapsed
|
|
126
117
|
}
|
|
127
118
|
|
|
128
119
|
/**
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base tools class
|
|
3
|
+
*
|
|
4
|
+
* @class
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class Tools {
|
|
8
|
+
constructor (plugin) {
|
|
9
|
+
/**
|
|
10
|
+
* Attached plugin
|
|
11
|
+
* @type {Plugin}
|
|
12
|
+
*/
|
|
13
|
+
this.plugin = plugin
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The app instance
|
|
17
|
+
* @type {App}
|
|
18
|
+
*/
|
|
19
|
+
this.app = plugin.app
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Force bind methods to self (```this```)
|
|
24
|
+
*
|
|
25
|
+
* @param {string[]} names - Method's names
|
|
26
|
+
*/
|
|
27
|
+
selfBind (names) {
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
this[name] = this[name].bind(this)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Dispose internal references
|
|
35
|
+
*/
|
|
36
|
+
dispose () {
|
|
37
|
+
this.app = null
|
|
38
|
+
this.plugin = null
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Tools
|