bajo 0.3.10 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +127 -26
  2. package/bajoI18N/resource/id.json +31 -0
  3. package/boot/class/app.js +69 -0
  4. package/boot/class/bajo-core/helper/attach-method.js +30 -0
  5. package/boot/{boot-order.js → class/bajo-core/helper/boot-order.js} +10 -10
  6. package/boot/class/bajo-core/helper/boot-plugins.js +19 -0
  7. package/boot/class/bajo-core/helper/build-config.js +61 -0
  8. package/boot/class/bajo-core/helper/build-plugins.js +26 -0
  9. package/boot/class/bajo-core/helper/collect-config-handlers.js +21 -0
  10. package/boot/{exit-handler.js → class/bajo-core/helper/exit-handler.js} +10 -16
  11. package/boot/class/bajo-core/helper/run-as-applet.js +26 -0
  12. package/boot/class/bajo-core/method/arrange-array.js +18 -0
  13. package/boot/class/bajo-core/method/break-ns-path-from-file.js +24 -0
  14. package/boot/class/bajo-core/method/break-ns-path.js +29 -0
  15. package/boot/class/bajo-core/method/build-collections.js +46 -0
  16. package/boot/class/bajo-core/method/call-handler.js +29 -0
  17. package/boot/{helper → class/bajo-core/method}/defaults-deep.js +1 -1
  18. package/boot/class/bajo-core/method/each-plugins.js +55 -0
  19. package/boot/class/bajo-core/method/envs.js +7 -0
  20. package/boot/{helper → class/bajo-core/method}/generate-id.js +4 -0
  21. package/boot/{helper → class/bajo-core/method}/get-global-module-dir.js +5 -6
  22. package/boot/class/bajo-core/method/get-method.js +10 -0
  23. package/boot/{helper → class/bajo-core/method}/get-module-dir.js +3 -4
  24. package/boot/{helper → class/bajo-core/method}/get-plugin-data-dir.js +2 -3
  25. package/boot/class/bajo-core/method/get-plugin-file.js +18 -0
  26. package/boot/class/bajo-core/method/get-plugin.js +23 -0
  27. package/boot/{helper → class/bajo-core/method}/import-module.js +4 -10
  28. package/boot/{helper → class/bajo-core/method}/import-pkg.js +9 -3
  29. package/boot/class/bajo-core/method/includes.js +13 -0
  30. package/boot/class/bajo-core/method/is-class.js +7 -0
  31. package/boot/{helper → class/bajo-core/method}/is-log-in-range.js +1 -1
  32. package/boot/{helper → class/bajo-core/method}/is-valid-app.js +2 -2
  33. package/boot/class/bajo-core/method/join.js +15 -0
  34. package/boot/class/bajo-core/method/log-levels.js +9 -0
  35. package/boot/class/bajo-core/method/num-unit.js +9 -0
  36. package/boot/{helper → class/bajo-core/method}/parse-object.js +24 -8
  37. package/boot/class/bajo-core/method/read-config.js +48 -0
  38. package/boot/{helper → class/bajo-core/method}/read-json.js +2 -2
  39. package/boot/class/bajo-core/method/run-hook.js +26 -0
  40. package/boot/{helper → class/bajo-core/method}/save-as-download.js +2 -2
  41. package/boot/class/bajo-core/method/slice-string.js +13 -0
  42. package/boot/class/bajo-core/method/titleize.js +23 -0
  43. package/boot/class/bajo-core.js +30 -0
  44. package/boot/class/bajo-plugin/helper/attach-method.js +14 -0
  45. package/boot/class/bajo-plugin/helper/build-config.js +10 -0
  46. package/boot/class/bajo-plugin/helper/check-clash.js +16 -0
  47. package/boot/class/bajo-plugin/helper/check-dependency.js +37 -0
  48. package/boot/class/bajo-plugin/helper/collect-exit-handlers.js +14 -0
  49. package/boot/class/bajo-plugin/helper/collect-hooks.js +29 -0
  50. package/boot/class/bajo-plugin/helper/run.js +20 -0
  51. package/boot/class/bajo-plugin.js +78 -0
  52. package/boot/class/error.js +59 -0
  53. package/boot/class/log.js +67 -0
  54. package/boot/class/plugin.js +51 -0
  55. package/boot/class/print.js +103 -0
  56. package/boot/index.js +4 -51
  57. package/boot/lib/create-method.js +30 -0
  58. package/boot/{helper → lib}/current-loc.js +1 -1
  59. package/boot/lib/get-global-module-path.js +189 -0
  60. package/boot/lib/omitted-plugin-keys.js +1 -1
  61. package/boot/lib/parse-args-argv.js +8 -11
  62. package/boot/lib/parse-env.js +7 -6
  63. package/boot/lib/read-all-configs.js +36 -0
  64. package/boot/lib/translate.js +18 -0
  65. package/docs/ecosystem.md +55 -0
  66. package/docs/hook.md +11 -0
  67. package/package.json +54 -56
  68. package/test/{helper-isSet.js → method/isSet.js} +6 -4
  69. package/waibuStatic/virtual.json +7 -0
  70. package/boot/attach-helper.js +0 -40
  71. package/boot/build-config.js +0 -99
  72. package/boot/create-scope.js +0 -36
  73. package/boot/helper/break-ns-path.js +0 -20
  74. package/boot/helper/build-collections.js +0 -43
  75. package/boot/helper/build-name.js +0 -17
  76. package/boot/helper/call-helper-or-handler.js +0 -15
  77. package/boot/helper/dump.js +0 -14
  78. package/boot/helper/each-plugins.js +0 -106
  79. package/boot/helper/envs.js +0 -14
  80. package/boot/helper/error.js +0 -77
  81. package/boot/helper/fatal.js +0 -13
  82. package/boot/helper/get-config.js +0 -19
  83. package/boot/helper/get-helper.js +0 -12
  84. package/boot/helper/get-item-by-name.js +0 -26
  85. package/boot/helper/get-plugin-file.js +0 -16
  86. package/boot/helper/get-plugin-name.js +0 -39
  87. package/boot/helper/get-plugin.js +0 -14
  88. package/boot/helper/join.js +0 -11
  89. package/boot/helper/log-levels.js +0 -19
  90. package/boot/helper/read-config.js +0 -48
  91. package/boot/helper/resolve-tpl-path.js +0 -15
  92. package/boot/helper/run-hook.js +0 -49
  93. package/boot/helper/spinner.js +0 -9
  94. package/boot/helper/start-plugin.js +0 -7
  95. package/boot/helper/titleize.js +0 -14
  96. package/boot/lib/build-helper.js +0 -60
  97. package/boot/lib/logger.js +0 -76
  98. package/boot/lib/print.js +0 -138
  99. package/boot/plugins/attach-helper.js +0 -20
  100. package/boot/plugins/build-config.js +0 -68
  101. package/boot/plugins/check-clash.js +0 -18
  102. package/boot/plugins/check-dependency.js +0 -37
  103. package/boot/plugins/collect-config-handlers.js +0 -22
  104. package/boot/plugins/collect-exit-handlers.js +0 -18
  105. package/boot/plugins/collect-hooks.js +0 -34
  106. package/boot/plugins/extend-config.js +0 -21
  107. package/boot/plugins/index.js +0 -27
  108. package/boot/plugins/run.js +0 -26
  109. package/boot/run-tool.js +0 -41
  110. package/docs/boot_build-config.js.html +0 -75
  111. package/docs/boot_create-scope.js.html +0 -25
  112. package/docs/boot_index.js.html +0 -43
  113. package/docs/data/search.json +0 -1
  114. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  115. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  116. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  117. package/docs/helper_emit.js.html +0 -18
  118. package/docs/helper_envs.js.html +0 -16
  119. package/docs/helper_error.js.html +0 -25
  120. package/docs/helper_get-bajo.js.html +0 -42
  121. package/docs/helper_index.js.html +0 -39
  122. package/docs/helper_log-levels.js.html +0 -20
  123. package/docs/helper_set-hook.js.html +0 -38
  124. package/docs/helper_walk-bajos.js.html +0 -51
  125. package/docs/index.html +0 -16
  126. package/docs/module-boot.html +0 -3
  127. package/docs/module-boot_buildConfig.html +0 -3
  128. package/docs/module-boot_createScope.html +0 -3
  129. package/docs/module-helper.html +0 -7
  130. package/docs/module-helper_setHook.html +0 -4
  131. package/docs/module-helper_walkBajos.html +0 -6
  132. package/docs/scripts/core.js +0 -655
  133. package/docs/scripts/core.min.js +0 -23
  134. package/docs/scripts/resize.js +0 -90
  135. package/docs/scripts/search.js +0 -265
  136. package/docs/scripts/search.min.js +0 -6
  137. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
  138. package/docs/scripts/third-party/fuse.js +0 -9
  139. package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
  140. package/docs/scripts/third-party/hljs-line-num.js +0 -1
  141. package/docs/scripts/third-party/hljs-original.js +0 -5171
  142. package/docs/scripts/third-party/hljs.js +0 -1
  143. package/docs/scripts/third-party/popper.js +0 -5
  144. package/docs/scripts/third-party/tippy.js +0 -1
  145. package/docs/scripts/third-party/tocbot.js +0 -672
  146. package/docs/scripts/third-party/tocbot.min.js +0 -1
  147. package/docs/styles/clean-jsdoc-theme-base.css +0 -975
  148. package/docs/styles/clean-jsdoc-theme-dark.css +0 -407
  149. package/docs/styles/clean-jsdoc-theme-light.css +0 -388
  150. package/docs/styles/clean-jsdoc-theme.min.css +0 -1
  151. package/test/helper-error.js +0 -25
  152. package/test/helper-pathResolve.js +0 -28
  153. /package/boot/{helper → class/bajo-core/method}/get-key-by-value.js +0 -0
  154. /package/boot/{helper → class/bajo-core/method}/is-empty-dir.js +0 -0
  155. /package/boot/{helper → class/bajo-core/method}/is-set.js +0 -0
  156. /package/boot/{helper → class/bajo-core/method}/is-valid-plugin.js +0 -0
  157. /package/boot/{helper → class/bajo-core/method}/paginate.js +0 -0
  158. /package/boot/{helper → class/bajo-core/method}/pascal-case.js +0 -0
  159. /package/boot/{helper → class/bajo-core/method}/pick.js +0 -0
  160. /package/boot/{helper → class/bajo-core/method}/resolve-path.js +0 -0
  161. /package/boot/{helper → class/bajo-core/method}/round.js +0 -0
  162. /package/boot/{helper → class/bajo-core/method}/sec-to-hms.js +0 -0
  163. /package/boot/{helper → class/bajo-core/method}/white-space.js +0 -0
@@ -0,0 +1,30 @@
1
+ import Plugin from './plugin.js'
2
+ import dayjs from '../lib/dayjs.js'
3
+ import importModule from './bajo-core/method/import-module.js'
4
+ import readJson from './bajo-core/method/read-json.js'
5
+
6
+ import { isFunction } from 'lodash-es'
7
+
8
+ async function defConfigHandler (file, opts) {
9
+ let mod = await importModule(file)
10
+ if (isFunction(mod)) mod = await mod.call(this, opts)
11
+ return mod
12
+ }
13
+
14
+ class BajoCore extends Plugin {
15
+ constructor (app) {
16
+ super('bajo', app)
17
+ this.runAt = new Date()
18
+ this.mainNs = 'main'
19
+ this.lib.dayjs = dayjs
20
+ this.applets = []
21
+ this.pluginPkgs = []
22
+ this.pluginNames = []
23
+ this.configHandlers = [
24
+ { ext: '.js', readHandler: defConfigHandler },
25
+ { ext: '.json', readHandler: readJson }
26
+ ]
27
+ }
28
+ }
29
+
30
+ export default BajoCore
@@ -0,0 +1,14 @@
1
+ import createMethod from '../../../lib/create-method.js'
2
+
3
+ async function attachMethod () {
4
+ const { eachPlugins } = this.bajo
5
+ const me = this
6
+ me.bajo.log.debug('Attach methods')
7
+ await eachPlugins(async function ({ ns, pkgName }) {
8
+ const dir = ns === me.bajo.mainNs ? (`${me.bajo.dir.base}/${me.bajo.mainNs}`) : me.bajo.getModuleDir(pkgName)
9
+ const num = await createMethod.call(me[ns], `${dir}/bajo/method`, pkgName)
10
+ me.bajo.log.trace('- %s (%d)', ns, num)
11
+ })
12
+ }
13
+
14
+ export default attachMethod
@@ -0,0 +1,10 @@
1
+ import { camelCase } from 'lodash-es'
2
+
3
+ async function buildConfig () {
4
+ this.bajo.log.debug('Read configurations')
5
+ for (const pkg of this.bajo.pluginPkgs) {
6
+ await this[camelCase(pkg)].loadConfig()
7
+ }
8
+ }
9
+
10
+ export default buildConfig
@@ -0,0 +1,16 @@
1
+ import { find } from 'lodash-es'
2
+
3
+ async function checkAlias () {
4
+ const { eachPlugins } = this.bajo
5
+ this.bajo.log.debug('Checking alias & name clashes')
6
+ const refs = []
7
+ await eachPlugins(async function ({ ns, pkgName, alias }) {
8
+ let item = find(refs, { ns })
9
+ if (item) throw this.error('Plugin name clash: \'%s (%s)\' with \'%s (%s)\'', ns, pkgName, item.ns, item.pkgName, { code: 'BAJO_NAME_CLASH' })
10
+ item = find(refs, { alias })
11
+ if (item) throw this.error('Plugin alias clash: \'%s (%s)\' with \'%s (%s)\'', alias, pkgName, item.alias, item.pkgName, { code: 'BAJO_ALIAS_CLASH' })
12
+ refs.push({ ns, alias, pkgName })
13
+ })
14
+ }
15
+
16
+ export default checkAlias
@@ -0,0 +1,37 @@
1
+ import { reduce, map, trim, keys, intersection, each, camelCase, get } from 'lodash-es'
2
+ import semver from 'semver'
3
+
4
+ async function runner ({ ns, pkgName }) {
5
+ const { join } = this.app.bajo
6
+ this.app.bajo.log.trace('- %s', ns)
7
+ const odep = reduce(this.dependencies, (o, k) => {
8
+ const item = map(k.split('@'), m => trim(m))
9
+ if (k[0] === '@') o['@' + item[1]] = item[2]
10
+ else o[item[0]] = item[1]
11
+ return o
12
+ }, {})
13
+ const deps = keys(odep)
14
+ if (deps.length > 0) {
15
+ if (intersection(this.app.bajo.pluginPkgs, deps).length !== deps.length) {
16
+ throw this.error('Dependency for \'%s\' unfulfilled: %s', pkgName, join(deps), { code: 'BAJO_DEPENDENCY' })
17
+ }
18
+ each(deps, d => {
19
+ if (!odep[d]) return
20
+ const ver = get(this.app[camelCase(d)], 'config.pkg.version')
21
+ if (!ver) return
22
+ if (!semver.satisfies(ver, odep[d])) {
23
+ throw this.error('Semver check \'%s\' against \'%s\' failed', pkgName, `${d}@${odep[d]}`, { code: 'BAJO_DEPENDENCY_SEMVER' })
24
+ }
25
+ })
26
+ }
27
+ }
28
+
29
+ async function checkDependency () {
30
+ const { eachPlugins } = this.bajo
31
+ this.bajo.log.debug('Checking dependencies')
32
+ await eachPlugins(async function ({ ns, pkgName, config }) {
33
+ await runner.call(this, { ns, pkgName, config })
34
+ })
35
+ }
36
+
37
+ export default checkDependency
@@ -0,0 +1,14 @@
1
+ async function collectExitHandlers () {
2
+ const { importModule, eachPlugins, print, join } = this.bajo
3
+ if (!this.bajo.config.exitHandler) return
4
+ const nss = []
5
+ await eachPlugins(async function ({ ns, dir }) {
6
+ const mod = await importModule(`${dir}/bajo/exit.js`)
7
+ if (!mod) return undefined
8
+ this.app[ns].exitHandler = mod
9
+ nss.push(ns)
10
+ })
11
+ this.bajo.log.trace('Exit handlers: %s', nss.length === 0 ? print.write('none') : join(nss))
12
+ }
13
+
14
+ export default collectExitHandlers
@@ -0,0 +1,29 @@
1
+ import { merge, forOwn, groupBy } from 'lodash-es'
2
+
3
+ async function collectHooks () {
4
+ const { eachPlugins, runHook, isLogInRange, importModule, breakNsPathFromFile } = this.bajo
5
+ const me = this
6
+ me.bajo.hooks = this.bajo.hooks ?? []
7
+ me.bajo.log.debug('Collect hooks')
8
+ // collects
9
+ await eachPlugins(async function ({ ns, dir, file }) {
10
+ const { fullNs, path } = breakNsPathFromFile({ file, dir, baseNs: ns, suffix: '/hook/' })
11
+ const mod = await importModule(file, { asHandler: true })
12
+ if (!mod) return undefined
13
+ merge(mod, { ns: fullNs, path, src: ns })
14
+ me.bajo.hooks.push(mod)
15
+ }, { glob: 'hook/**/*.js', prefix: me.bajo.name })
16
+ // for log trace purpose only
17
+ if (!isLogInRange('trace')) return
18
+ const items = groupBy(me.bajo.hooks, 'ns')
19
+ forOwn(items, (v, k) => {
20
+ const hooks = groupBy(v, 'path')
21
+ forOwn(hooks, (v1, k1) => {
22
+ me.bajo.log.trace('- %s:%s (%d)', k, k1, v1.length)
23
+ })
24
+ })
25
+ // run handler
26
+ await runHook('bajo:afterCollectHooks')
27
+ }
28
+
29
+ export default collectHooks
@@ -0,0 +1,20 @@
1
+ import { camelCase, map } from 'lodash-es'
2
+
3
+ async function run () {
4
+ const me = this
5
+ const { runHook, eachPlugins, join } = me.bajo
6
+ const methods = ['init']
7
+ if (!me.bajo.applet) methods.push('start')
8
+ for (const method of methods) {
9
+ await runHook(`bajo:${camelCase(`before ${method} all plugins`)}`)
10
+ await eachPlugins(async function ({ ns }) {
11
+ await runHook(`${ns}:${camelCase(`before ${method}`)}`)
12
+ await me[ns][method]()
13
+ await runHook(`${ns}:${camelCase(`after ${method}`)}`)
14
+ })
15
+ await runHook(`bajo:${camelCase(`after ${method} all plugins`)}`)
16
+ }
17
+ me.bajo.log.debug('Loaded plugins: %s', join(map(me.bajo.pluginPkgs, b => camelCase(b))))
18
+ }
19
+
20
+ export default run
@@ -0,0 +1,78 @@
1
+ import Plugin from './plugin.js'
2
+ import { pick, isString, omit, camelCase } from 'lodash-es'
3
+ import omittedPluginKeys from '../lib/omitted-plugin-keys.js'
4
+ import readAllConfigs from '../lib/read-all-configs.js'
5
+ import titleize from './bajo-core/method/titleize.js'
6
+ import fs from 'fs-extra'
7
+
8
+ class BajoPlugin extends Plugin {
9
+ constructor (pkgName, app) {
10
+ super(pkgName, app)
11
+ this.state = {}
12
+ }
13
+
14
+ async loadConfig () {
15
+ const { log, getModuleDir, readJson, defaultsDeep } = this.app.bajo
16
+ log.trace('- %s', this.name)
17
+ const dir = this.name === this.app.bajo.mainNs ? (`${this.app.bajo.dir.base}/${this.app.bajo.mainNs}`) : getModuleDir(this.pkgName)
18
+ let cfg = await readAllConfigs.call(this.app, `${dir}/bajo/config`)
19
+ this.alias = this.pkgName.slice(0, 5) === 'bajo-' ? this.pkgName.slice(5).toLowerCase() : this.name.toLowerCase()
20
+ const aliasFile = `${dir}/bajo/.alias`
21
+ if (fs.existsSync(aliasFile)) this.alias = fs.readFileSync(aliasFile, 'utf8')
22
+ this.alias = camelCase(this.alias)
23
+
24
+ this.dir = {
25
+ pkg: dir,
26
+ data: `${this.app.bajo.dir.data}/plugins/${this.name}`
27
+ }
28
+ const file = `${dir + (this.name === this.app.bajo.mainNs ? '/..' : '')}/package.json`
29
+ const pkgJson = await readJson(file)
30
+ this.pkg = pick(pkgJson,
31
+ ['name', 'version', 'description', 'author', 'license', 'homepage'])
32
+ if (this.name === this.app.bajo.mainNs) {
33
+ this.alias = this.app.bajo.mainNs
34
+ this.title = 'Main'
35
+ }
36
+ // merge with config from datadir
37
+ try {
38
+ const altCfg = await readAllConfigs.call(this.app, `${this.app.bajo.dir.data}/config/${this.name}`)
39
+ cfg = defaultsDeep({}, omit(altCfg, omittedPluginKeys), cfg)
40
+ } catch (err) {}
41
+ const envArgv = defaultsDeep({}, omit(this.app.env[this.name] ?? {}, omittedPluginKeys) ?? {}, omit(this.app.argv[this.name] ?? {}, omittedPluginKeys) ?? {})
42
+ cfg = defaultsDeep({}, envArgv ?? {}, cfg ?? {})
43
+ this.title = this.title ?? cfg.title ?? titleize(this.alias)
44
+ this.dependencies = cfg.dependencies ?? []
45
+ if (isString(this.dependencies)) this.dependencies = [this.dependencies]
46
+ this.config = omit(cfg, ['title', 'dependencies'])
47
+ }
48
+
49
+ async _onoff (item, text, ...args) {
50
+ this.state[item] = false
51
+ const { runHook, importModule } = this.app.bajo
52
+ const { camelCase } = this.app.bajo.lib._
53
+ const mod = await importModule(`${this.dir.pkg}/bajo/${item}.js`)
54
+ if (mod) {
55
+ this.log.trace(text)
56
+ await runHook(`${this.name}:${camelCase(`before ${item}`)}`)
57
+ await mod.call(this, ...args)
58
+ await runHook(`${this.name}:${camelCase(`after ${item}`)}`)
59
+ }
60
+ this.state[item] = true
61
+ }
62
+
63
+ async init () {
64
+ await this._onoff('init', 'Init plugin...')
65
+ }
66
+
67
+ async start (...args) {
68
+ const { freeze } = this.app.bajo
69
+ freeze(this.config)
70
+ await this._onoff('start', 'Start plugin...', ...args)
71
+ }
72
+
73
+ async stop () {
74
+ await this._onoff('stop', 'Stop plugin...')
75
+ }
76
+ }
77
+
78
+ export default BajoPlugin
@@ -0,0 +1,59 @@
1
+ import { isPlainObject, each, isArray, get, isEmpty, merge } from 'lodash-es'
2
+
3
+ Error.stackTraceLimit = 15
4
+
5
+ class BajoError {
6
+ constructor (plugin, msg, ...args) {
7
+ this.plugin = plugin
8
+ this.payload = args.length > 0 && isPlainObject(args[args.length - 1]) ? args[args.length - 1] : {}
9
+ this.orgMessage = msg
10
+ this.message = this.plugin.print.write(msg, ...args)
11
+ this.write()
12
+ }
13
+
14
+ write (fatal) {
15
+ let err
16
+ if (this.payload.class) err = this.payload.class(this.message)
17
+ else err = Error(this.message)
18
+ delete this.payload.class
19
+ const stacks = err.stack.split('\n')
20
+ stacks.splice(1, 1)
21
+ stacks.splice(1, 1)
22
+ err.stack = stacks.join('\n')
23
+ const values = {}
24
+ for (const key in this.payload) {
25
+ const value = this.payload[key]
26
+ if (key === 'details' && isArray(value)) {
27
+ const result = this.formatErrorDetails(value)
28
+ if (result) merge(values, result)
29
+ }
30
+ err[key] = value
31
+ }
32
+ if (!isEmpty(values)) err.values = values
33
+ return err
34
+ }
35
+
36
+ formatErrorDetails (value) {
37
+ const { isString } = this.plugin.app.bajo.lib._
38
+ const result = {}
39
+ const me = this
40
+ each(value, (v, i) => {
41
+ const print = me.plugin.print
42
+ if (isString(v)) v = { error: v }
43
+ if (!v.context) return undefined
44
+ v.context.message = v.message
45
+ if (v.type === 'any.only') v.context.ref = print.write(`field.${get(v, 'context.valids.0.key')}`)
46
+ const field = get(v, 'context.key')
47
+ const val = get(v, 'context.value')
48
+ value[i] = {
49
+ field,
50
+ error: print.write(`validation.${v.type}`, v.context),
51
+ value: val,
52
+ ext: { type: v.type, context: v.context }
53
+ }
54
+ })
55
+ return result
56
+ }
57
+ }
58
+
59
+ export default BajoError
@@ -0,0 +1,67 @@
1
+ import os from 'os'
2
+ import { isEmpty, without, merge, upperFirst } from 'lodash-es'
3
+ import levels from './bajo-core/method/log-levels.js'
4
+ import isLogInRange from './bajo-core/method/is-log-in-range.js'
5
+ import translate from '../lib/translate.js'
6
+ import dayjs from 'dayjs'
7
+
8
+ class Log {
9
+ constructor (plugin) {
10
+ this.plugin = plugin
11
+ this.format = 'YYYY-MM-DDTHH:mm:ss.SSS[Z]'
12
+ }
13
+
14
+ init () {
15
+ this.bajoLog = this.plugin.app.bajo.config.log.logger ?? 'bajoLogger'
16
+ }
17
+
18
+ write (text, ...args) {
19
+ return translate.call(this.plugin, null, text, ...args)
20
+ }
21
+
22
+ isExtLogger () {
23
+ return this.plugin.app[this.bajoLog] && this.plugin.app[this.bajoLog].logger
24
+ }
25
+
26
+ child () {
27
+ if (this.isExtLogger()) return this.plugin.app[this.bajoLog].logger.child()
28
+ return this.plugin.app
29
+ }
30
+
31
+ formatMsg (level, ...params) {
32
+ if (this.plugin.app.bajo.config.log.level === 'silent') return
33
+ if (!isLogInRange.call(this.plugin.app.bajo, level)) return
34
+ let [data, msg, ...args] = params
35
+ if (typeof data === 'string') {
36
+ args.unshift(msg)
37
+ msg = data
38
+ data = null
39
+ }
40
+ args = without(args, undefined)
41
+ msg = this.write(`[%s] ${msg}`, this.plugin.name, ...args)
42
+ if (this.plugin.app[this.bajoLog] && this.plugin.app[this.bajoLog].logger) {
43
+ this.plugin.app[this.bajoLog].logger[level](data, msg, ...args)
44
+ } else {
45
+ let text
46
+ const dt = new Date()
47
+ if (this.plugin.app.bajo.config.env === 'prod') {
48
+ const json = { level: levels[level], time: dt.valueOf(), pid: process.pid, hostname: os.hostname() }
49
+ if (!isEmpty(data)) merge(json, data)
50
+ merge(json, { msg })
51
+ text = JSON.stringify(json)
52
+ } else {
53
+ text = `[${dayjs(dt).utc(true).format(this.format)}] ${upperFirst(level)}: ${msg}`
54
+ if (!isEmpty(data)) text += '\n' + JSON.stringify(data)
55
+ }
56
+ console.log(text)
57
+ }
58
+ }
59
+ }
60
+
61
+ Object.keys(levels).forEach(level => {
62
+ Log.prototype[level] = function (...params) {
63
+ this.formatMsg(level, ...params)
64
+ }
65
+ })
66
+
67
+ export default Log
@@ -0,0 +1,51 @@
1
+ import { get, isEmpty, cloneDeep, omit, isPlainObject, camelCase } from 'lodash-es'
2
+ import omittedPluginKeys from '../lib/omitted-plugin-keys.js'
3
+ import Log from './log.js'
4
+ import Print from './print.js'
5
+ import BajoError from './error.js'
6
+
7
+ class Plugin {
8
+ constructor (pkgName, app) {
9
+ this.pkgName = pkgName
10
+ this.name = camelCase(pkgName)
11
+ this.app = app
12
+ this.config = {}
13
+ this.lib = {}
14
+ this.exitHandler = undefined
15
+ this.initLog()
16
+ }
17
+
18
+ getConfig (path, options = {}) {
19
+ let obj = isEmpty(path) ? this.config : get(this.config, path, options.defValue)
20
+ options.omit = options.omit ?? omittedPluginKeys
21
+ if (isPlainObject(obj) && !isEmpty(options.omit)) obj = omit(obj, options.omit)
22
+ if (!options.noclone) obj = cloneDeep(obj)
23
+ return obj
24
+ }
25
+
26
+ initLog () {
27
+ this.log = new Log(this)
28
+ }
29
+
30
+ initPrint (opts) {
31
+ this.print = new Print(this, opts)
32
+ }
33
+
34
+ error (msg, ...args) {
35
+ if (!this.print) return new Error(msg, ...args)
36
+ const error = new BajoError(this, msg, ...args)
37
+ return error.write()
38
+ }
39
+
40
+ fatal (msg, ...args) {
41
+ let e
42
+ if (this.print) {
43
+ const error = new BajoError(this, msg, ...args)
44
+ e = error.write(true)
45
+ } else e = new Error(msg, ...args)
46
+ console.error(e)
47
+ process.kill(process.pid, 'SIGINT')
48
+ }
49
+ }
50
+
51
+ export default Plugin
@@ -0,0 +1,103 @@
1
+ import ora from 'ora'
2
+ import { isPlainObject } from 'lodash-es'
3
+ import defaultsDeep from './bajo-core/method/defaults-deep.js'
4
+ import translate from '../lib/translate.js'
5
+
6
+ class Print {
7
+ constructor (plugin, opts = {}) {
8
+ this.opts = opts
9
+ this.plugin = plugin
10
+ this.startTime = this.plugin.app.bajo.lib.dayjs()
11
+ this.setOpts()
12
+ this.ora = ora(this.opts)
13
+ }
14
+
15
+ setOpts (args = []) {
16
+ const config = this.plugin.app.bajo.config
17
+ let opts = {}
18
+ if (isPlainObject(args.slice(-1)[0])) opts = args.pop()
19
+ this.opts.isSilent = !!(config.silent || this.opts.isSilent)
20
+ this.opts = defaultsDeep(opts, this.opts)
21
+ }
22
+
23
+ setText (text, ...args) {
24
+ text = this.write(text, ...args)
25
+ this.setOpts(args)
26
+ const prefixes = []
27
+ const texts = []
28
+ if (this.opts.showDatetime) prefixes.push('[' + this.plugin.app.bajo.lib.dayjs().toISOString() + ']')
29
+ if (this.opts.showCounter) texts.push('[' + this.getElapsed() + ']')
30
+ if (prefixes.length > 0) this.ora.prefixText = this.ora.prefixText + prefixes.join(' ')
31
+ if (texts.length > 0) text = texts.join(' ') + ' ' + text
32
+ this.ora.text = text
33
+ return this
34
+ }
35
+
36
+ write (text, ...args) {
37
+ return translate.call(this.plugin, null, text, ...args)
38
+ }
39
+
40
+ getElapsed (unit = 'hms') {
41
+ const u = unit === 'hms' ? 'second' : unit
42
+ const elapsed = this.plugin.app.bajo.lib.dayjs().diff(this.startTime, u)
43
+ return unit === 'hms' ? this.plugin.app.bajo.secToHms(elapsed) : elapsed
44
+ }
45
+
46
+ start (text, ...args) {
47
+ this.setOpts(args)
48
+ this.setText(text, ...args)
49
+ this.ora.start()
50
+ return this
51
+ }
52
+
53
+ stop () {
54
+ this.ora.stop()
55
+ return this
56
+ }
57
+
58
+ succeed (text, ...args) {
59
+ this.setText(text, ...args)
60
+ this.ora.succeed()
61
+ return this
62
+ }
63
+
64
+ fail (text, ...args) {
65
+ this.setText(text, ...args)
66
+ this.ora.fail()
67
+ return this
68
+ }
69
+
70
+ warn (text, ...args) {
71
+ this.setText(text, ...args)
72
+ this.ora.warn()
73
+ return this
74
+ }
75
+
76
+ info (text, ...args) {
77
+ this.setText(text, ...args)
78
+ this.ora.info()
79
+ return this
80
+ }
81
+
82
+ clear () {
83
+ this.ora.clear()
84
+ return this
85
+ }
86
+
87
+ render () {
88
+ this.ora.render()
89
+ return this
90
+ }
91
+
92
+ fatal (text, ...args) {
93
+ this.setText(text, ...args)
94
+ this.ora.fail()
95
+ process.kill(process.pid, 'SIGINT')
96
+ }
97
+
98
+ spinner () {
99
+ return new Print(this.plugin)
100
+ }
101
+ }
102
+
103
+ export default Print
package/boot/index.js CHANGED
@@ -1,59 +1,12 @@
1
- /**
2
- * Boot process:
3
- * 1. [Creating scope]{@link module:boot/createScope}
4
- * 2. [Building config object]{@link module:boot/buildConfig}
5
- * 3. Attaching helpers
6
- * 4. Attaching system report
7
- * 5. Determine boot orders
8
- * 6. Register plugins
9
- * 7. Attaching exit handlers
10
- * @module boot
11
- */
12
-
13
- import createScope from './create-scope.js'
14
- import buildConfig from './build-config.js'
15
- import attachHelper from './attach-helper.js'
16
- import bootOrder from './boot-order.js'
17
- import bootPlugins from './plugins/index.js'
18
- import exitHandler from './exit-handler.js'
19
- import runTool from './run-tool.js'
1
+ import App from './class/app.js'
20
2
  import shim from './lib/shim.js'
21
- import { last } from 'lodash-es'
22
- import resolvePath from './helper/resolve-path.js'
23
3
 
24
4
  shim()
25
5
 
26
- /**
27
- * The entry point to boot Bajo based application
28
- *
29
- * @instance
30
- * @async
31
- * @returns {Object} scope
32
- */
33
-
34
6
  async function boot (cwd) {
35
- if (!cwd) cwd = process.cwd()
36
- const l = last(process.argv)
37
- if (l.startsWith('--cwd')) {
38
- const parts = l.split('=')
39
- cwd = parts[1]
40
- }
41
- cwd = resolvePath(cwd)
42
- process.env.BAJOCWD = cwd
43
- const scope = createScope()
44
- await buildConfig.call(scope, cwd)
45
- await attachHelper.call(scope)
46
- await bootOrder.call(scope)
47
- await bootPlugins.call(scope)
48
- await exitHandler.call(scope)
49
- // boot complete
50
- const { runHook, log } = scope.bajo.helper
51
- await runHook('bajo:bootComplete')
52
- const elapsed = new Date() - scope.bajo.runAt
53
- log.info('Boot process completed in %s', scope.bajo.helper.secToHms(elapsed, true))
54
- // run tool
55
- await runTool.call(scope)
56
- return scope
7
+ const app = new App(cwd)
8
+ await app.boot()
9
+ return app
57
10
  }
58
11
 
59
12
  export default boot
@@ -0,0 +1,30 @@
1
+ import fastGlob from 'fast-glob'
2
+ import path from 'path'
3
+ import { camelCase, isFunction, isPlainObject, forOwn } from 'lodash-es'
4
+ import resolvePath from '../class/bajo-core/method/resolve-path.js'
5
+ import importModule from '../class/bajo-core/method/import-module.js'
6
+ import readJson from '../class/bajo-core/method/read-json.js'
7
+
8
+ export default async function (dir, pkg = 'bajo') {
9
+ dir = resolvePath(dir)
10
+ const files = await fastGlob([`!${dir}/**/_*.{js,json}`, `${dir}/**/*.{js,json}`])
11
+ for (const f of files) {
12
+ const ext = path.extname(f)
13
+ const base = f.replace(dir, '').replace(ext, '')
14
+ const name = camelCase(base)
15
+ let mod
16
+ if (ext === '.json') mod = readJson(f)
17
+ else mod = await importModule(f)
18
+ if (isFunction(mod)) {
19
+ mod = mod.bind(this)
20
+ } else if (isPlainObject(mod)) {
21
+ if (!mod.exec) { // mod.exec offer unbind, nacked function people can bind to anything else later
22
+ forOwn(mod, (v, k) => {
23
+ if (isFunction(v)) mod[k] = v.bind(this)
24
+ })
25
+ }
26
+ }
27
+ this[name] = mod
28
+ }
29
+ return files.length
30
+ }
@@ -1,5 +1,5 @@
1
1
  import path from 'path'
2
- import resolvePath from './resolve-path.js'
2
+ import resolvePath from '../class/bajo-core/method/resolve-path.js'
3
3
  import { fileURLToPath } from 'url'
4
4
 
5
5
  const currentLoc = (meta) => {