bajo 0.0.1 → 0.2.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 +38 -0
- package/README.md +57 -3
- package/bajoBook/book/doc/.metadata.json +28 -0
- package/bajoBook/book/doc/How-to-Make-a-Paper-Boat-564x400@2x.jpg +0 -0
- package/bajoBook/book/doc/pages/guides/definition.md +7 -0
- package/bajoBook/book/doc/pages/guides/intro.md +3 -0
- package/bajoBook/book/doc/pages/guides/setup.md +22 -0
- package/bajoBook/book/reference/.metadata.json +152 -0
- package/bajoBook/book/reference/concept-leadership-business-with-paper-boats.jpg +0 -0
- package/bajoBook/book/reference/pages/configuration/configuration-file.md +52 -0
- package/bajoBook/book/reference/pages/helper/break-ns-path.md +24 -0
- package/bajoBook/book/reference/pages/helper/build-collections.md +19 -0
- package/bajoBook/book/reference/pages/helper/call-helper-or-handler.md +35 -0
- package/bajoBook/book/reference/pages/helper/current-loc.md +28 -0
- package/bajoBook/book/reference/pages/helper/dayjs.md +13 -0
- package/bajoBook/book/reference/pages/helper/defaults-deep.md +29 -0
- package/bajoBook/book/reference/pages/helper/dump.md +32 -0
- package/bajoBook/book/reference/pages/helper/each-plugins.md +24 -0
- package/bajoBook/book/reference/pages/helper/envs.md +11 -0
- package/bajoBook/book/reference/pages/helper/error.md +29 -0
- package/bajoBook/book/reference/pages/helper/fatal.md +18 -0
- package/bajoBook/book/reference/pages/helper/freeze.md +13 -0
- package/bajoBook/book/reference/pages/helper/generate-id.md +36 -0
- package/bajoBook/book/reference/pages/helper/get-config.md +27 -0
- package/bajoBook/book/reference/pages/helper/get-global-module-dir.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-helper.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-item-by-name.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-key-by-value.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-module-dir.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-plugin-data-dir.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-plugin-name.md +13 -0
- package/bajoBook/book/reference/pages/helper/get-plugin.md +13 -0
- package/bajoBook/book/reference/pages/helper/import-module.md +13 -0
- package/bajoBook/book/reference/pages/helper/import-pkg.md +13 -0
- package/bajoBook/book/reference/pages/helper/is-empty-dir.md +13 -0
- package/bajoBook/book/reference/pages/helper/is-log-in-range.md +13 -0
- package/bajoBook/book/reference/pages/helper/is-set.md +13 -0
- package/bajoBook/book/reference/pages/helper/is-valid-app.md +13 -0
- package/bajoBook/book/reference/pages/helper/is-valid-plugin.md +13 -0
- package/bajoBook/book/reference/pages/helper/log-levels.md +13 -0
- package/bajoBook/book/reference/pages/helper/log.md +13 -0
- package/bajoBook/book/reference/pages/helper/paginate.md +13 -0
- package/bajoBook/book/reference/pages/helper/pascal-case.md +13 -0
- package/bajoBook/book/reference/pages/helper/print.md +13 -0
- package/bajoBook/book/reference/pages/helper/read-config.md +13 -0
- package/bajoBook/book/reference/pages/helper/read-json.md +13 -0
- package/bajoBook/book/reference/pages/helper/resolve-path.md +13 -0
- package/bajoBook/book/reference/pages/helper/resolve-tpl-path.md +13 -0
- package/bajoBook/book/reference/pages/helper/run-hook.md +13 -0
- package/bajoBook/book/reference/pages/helper/save-as-download.md +13 -0
- package/bajoBook/book/reference/pages/helper/titleize.md +13 -0
- package/bajoBook/book/reference/pages/helper/white-space.md +13 -0
- package/boot/attach-helper.js +34 -0
- package/boot/boot-order.js +34 -0
- package/boot/build-config.js +99 -0
- package/boot/create-scope.js +36 -0
- package/boot/exit-handler.js +60 -0
- package/boot/helper/break-ns-path.js +17 -0
- package/boot/helper/build-collections.js +34 -0
- package/boot/helper/call-helper-or-handler.js +15 -0
- package/boot/helper/current-loc.js +11 -0
- package/boot/helper/defaults-deep.js +14 -0
- package/boot/helper/dump.js +10 -0
- package/boot/helper/each-plugins.js +104 -0
- package/boot/helper/envs.js +14 -0
- package/boot/helper/error.js +67 -0
- package/boot/helper/fatal.js +12 -0
- package/boot/helper/generate-id.js +20 -0
- package/boot/helper/get-config.js +19 -0
- package/boot/helper/get-global-module-dir.js +27 -0
- package/boot/helper/get-helper.js +12 -0
- package/boot/helper/get-item-by-name.js +26 -0
- package/boot/helper/get-key-by-value.js +5 -0
- package/boot/helper/get-module-dir.js +22 -0
- package/boot/helper/get-plugin-data-dir.js +12 -0
- package/boot/helper/get-plugin-name.js +39 -0
- package/boot/helper/get-plugin.js +14 -0
- package/boot/helper/import-module.js +25 -0
- package/boot/helper/import-pkg.js +67 -0
- package/boot/helper/is-empty-dir.js +9 -0
- package/boot/helper/is-log-in-range.js +10 -0
- package/boot/helper/is-set.js +5 -0
- package/boot/helper/is-valid-app.js +12 -0
- package/boot/helper/is-valid-plugin.js +12 -0
- package/boot/helper/log-levels.js +19 -0
- package/boot/helper/paginate.js +26 -0
- package/boot/helper/pascal-case.js +7 -0
- package/boot/helper/print.js +99 -0
- package/boot/helper/read-config.js +46 -0
- package/boot/helper/read-json.js +10 -0
- package/boot/helper/resolve-path.js +15 -0
- package/boot/helper/resolve-tpl-path.js +15 -0
- package/boot/helper/run-hook.js +46 -0
- package/boot/helper/save-as-download.js +17 -0
- package/boot/helper/titleize.js +14 -0
- package/boot/helper/white-space.js +3 -0
- package/boot/index.js +60 -0
- package/boot/lib/bora.js +97 -0
- package/boot/lib/build-helper.js +57 -0
- package/boot/lib/logger.js +75 -0
- package/boot/lib/omitted-plugin-keys.js +3 -0
- package/boot/lib/parse-args-argv.js +75 -0
- package/boot/lib/parse-env.js +36 -0
- package/boot/lib/shim.js +14 -0
- package/boot/plugins/attach-helper.js +20 -0
- package/boot/plugins/build-config.js +82 -0
- package/boot/plugins/check-clash.js +18 -0
- package/boot/plugins/check-dependency.js +37 -0
- package/boot/plugins/collect-config-handlers.js +25 -0
- package/boot/plugins/collect-exit-handlers.js +23 -0
- package/boot/plugins/collect-hooks.js +34 -0
- package/boot/plugins/extend-config.js +21 -0
- package/boot/plugins/index.js +28 -0
- package/boot/plugins/run.js +31 -0
- package/boot/run-tool.js +34 -0
- package/docs/boot_build-config.js.html +75 -0
- package/docs/boot_create-scope.js.html +25 -0
- package/docs/boot_index.js.html +43 -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/helper_emit.js.html +18 -0
- package/docs/helper_envs.js.html +16 -0
- package/docs/helper_error.js.html +25 -0
- package/docs/helper_get-bajo.js.html +42 -0
- package/docs/helper_index.js.html +39 -0
- package/docs/helper_log-levels.js.html +20 -0
- package/docs/helper_set-hook.js.html +38 -0
- package/docs/helper_walk-bajos.js.html +51 -0
- package/docs/index.html +16 -0
- package/docs/module-boot.html +3 -0
- package/docs/module-boot_buildConfig.html +3 -0
- package/docs/module-boot_createScope.html +3 -0
- package/docs/module-helper.html +7 -0
- package/docs/module-helper_setHook.html +4 -0
- package/docs/module-helper_walkBajos.html +6 -0
- package/docs/scripts/core.js +655 -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 +975 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +407 -0
- package/docs/styles/clean-jsdoc-theme-light.css +388 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/package.json +36 -4
- package/test/helper-error.js +25 -0
- package/test/helper-isSet.js +41 -0
- package/test/helper-pathResolve.js +28 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
async function exit (signal) {
|
|
2
|
+
const { eachPlugins, log } = this.bajo.helper
|
|
3
|
+
log.warn('\'%s\' signal received', signal)
|
|
4
|
+
await eachPlugins(async function ({ plugin }) {
|
|
5
|
+
const handler = this.bajo.exitHandler[plugin]
|
|
6
|
+
if (!handler) return undefined
|
|
7
|
+
await handler.call(this)
|
|
8
|
+
log.debug('Exited: %s', plugin)
|
|
9
|
+
})
|
|
10
|
+
log.debug('Program shutdown')
|
|
11
|
+
process.exit(0)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function exitHandler () {
|
|
15
|
+
const { log, getConfig } = this.bajo.helper
|
|
16
|
+
const config = getConfig()
|
|
17
|
+
if (!config.exitHandler) return
|
|
18
|
+
|
|
19
|
+
log.debug('Exit handlings')
|
|
20
|
+
|
|
21
|
+
process.on('SIGINT', async () => {
|
|
22
|
+
await exit.call(this, 'SIGINT')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
process.on('SIGTERM', async () => {
|
|
26
|
+
await exit.call(this, 'SIGTERM')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
process.on('uncaughtException', (error, origin) => {
|
|
30
|
+
const { getConfig } = this.bajo.helper
|
|
31
|
+
const config = getConfig()
|
|
32
|
+
if (config.log.report.includes('sys:uncaughtException')) log.fatal({ origin }, '%s', error.message)
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
console.error(error)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}, 50)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
40
|
+
const stackFile = reason.stack.split('\n')[1]
|
|
41
|
+
let file
|
|
42
|
+
const info = stackFile.match(/\((.*)\)/) // file is in (<file>)
|
|
43
|
+
if (info) file = info[1]
|
|
44
|
+
else if (stackFile.startsWith(' at ')) file = stackFile.slice(7) // file is stackFile itself
|
|
45
|
+
if (!file) return
|
|
46
|
+
const parts = file.split(':')
|
|
47
|
+
const column = parseInt(parts[parts.length - 1])
|
|
48
|
+
const line = parseInt(parts[parts.length - 2])
|
|
49
|
+
parts.pop()
|
|
50
|
+
parts.pop()
|
|
51
|
+
file = parts.join(':')
|
|
52
|
+
log.error({ file, line, column }, '%s', reason.message)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
process.on('warning', warning => {
|
|
56
|
+
log.error('%s', warning.message)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default exitHandler
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { isEmpty } from 'lodash-es'
|
|
2
|
+
|
|
3
|
+
function breakNsPath (item = '') {
|
|
4
|
+
const { error, getPlugin } = this.bajo.helper
|
|
5
|
+
let [ns, ...path] = item.split(':')
|
|
6
|
+
path = path.join(':')
|
|
7
|
+
if (isEmpty(path)) {
|
|
8
|
+
path = ns
|
|
9
|
+
ns = null
|
|
10
|
+
}
|
|
11
|
+
// if (path.startsWith('.')) throw error('Path \'%s\' must be an absolute path', path)
|
|
12
|
+
if (!this[ns]) ns = (getPlugin(ns) || {}).name
|
|
13
|
+
if (!this[ns]) throw error('Unknown plugin \'%s\' or plugin isn\'t loaded yet', ns)
|
|
14
|
+
return [ns, path]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default breakNsPath
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { filter, isArray, each, pullAt, camelCase } from 'lodash-es'
|
|
2
|
+
|
|
3
|
+
async function buildCollections (options = {}) {
|
|
4
|
+
const { getConfig, getPluginName, fatal, runHook } = this.bajo.helper
|
|
5
|
+
let { plugin, handler, dupChecks = [], container = 'connections' } = options
|
|
6
|
+
if (!plugin) plugin = getPluginName(4)
|
|
7
|
+
const cfg = getConfig(plugin, { full: true })
|
|
8
|
+
if (!cfg[container]) return []
|
|
9
|
+
if (!isArray(cfg[container])) cfg[container] = [cfg[container]]
|
|
10
|
+
cfg[container] = cfg[container] ?? []
|
|
11
|
+
await runHook(`${plugin}:${camelCase(`before build ${container}`)}`)
|
|
12
|
+
const deleted = []
|
|
13
|
+
for (const index in cfg[container]) {
|
|
14
|
+
const item = cfg[container][index]
|
|
15
|
+
const result = await handler.call(this, { item, index, cfg })
|
|
16
|
+
if (result) cfg[container][index] = result
|
|
17
|
+
else if (result === false) deleted.push(index)
|
|
18
|
+
}
|
|
19
|
+
if (deleted.length > 0) pullAt(cfg[container], deleted)
|
|
20
|
+
|
|
21
|
+
// check for duplicity
|
|
22
|
+
each(cfg[container], c => {
|
|
23
|
+
const checker = {}
|
|
24
|
+
each(dupChecks, d => {
|
|
25
|
+
checker[d] = c[d]
|
|
26
|
+
})
|
|
27
|
+
const match = filter(cfg[container], checker)
|
|
28
|
+
if (match.length > 1) fatal('One or more %s shared the same \'%s\'', container, dupChecks.join(', '), { code: 'BAJOMQTT_CONNECTION_NOT_UNIQUE' })
|
|
29
|
+
})
|
|
30
|
+
await runHook(`${plugin}:${camelCase(`after build ${container}`)}`)
|
|
31
|
+
return cfg[container]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default buildCollections
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isString, isFunction } from 'lodash-es'
|
|
2
|
+
import getHelper from './get-helper.js'
|
|
3
|
+
|
|
4
|
+
async function callHelperOrHandler (nameOrFn, ...args) {
|
|
5
|
+
let result
|
|
6
|
+
if (isString(nameOrFn)) {
|
|
7
|
+
const helper = getHelper.call(this, nameOrFn)
|
|
8
|
+
if (isFunction(helper)) result = await helper(...args)
|
|
9
|
+
} else if (isFunction(nameOrFn)) {
|
|
10
|
+
result = await nameOrFn.call(this, ...args)
|
|
11
|
+
}
|
|
12
|
+
return result
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default callHelperOrHandler
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import resolvePath from './resolve-path.js'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
|
|
5
|
+
const currentLoc = (meta) => {
|
|
6
|
+
const file = resolvePath(fileURLToPath(meta.url))
|
|
7
|
+
const dir = path.dirname(file)
|
|
8
|
+
return { dir, file, __dirname: dir, __filename: file }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default currentLoc
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { mergeWith, isArray } from 'lodash-es'
|
|
2
|
+
// taken from https://github.com/nodeutils/defaults-deep/blob/master/lib/index.js
|
|
3
|
+
|
|
4
|
+
const defaultsDeep = (...args) => {
|
|
5
|
+
const output = {}
|
|
6
|
+
args.reverse().forEach(function (item) {
|
|
7
|
+
mergeWith(output, item, function (objectValue, sourceValue) {
|
|
8
|
+
return isArray(sourceValue) ? sourceValue : undefined
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
return output
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default defaultsDeep
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { camelCase, isString, omit, trim } from 'lodash-es'
|
|
2
|
+
import fastGlob from 'fast-glob'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import omittedPluginKeys from '../lib/omitted-plugin-keys.js'
|
|
5
|
+
|
|
6
|
+
async function _eachPlugins (handler, { key = 'name', glob, ns, useBajo } = {}) {
|
|
7
|
+
const { getConfig } = this.bajo.helper
|
|
8
|
+
const config = getConfig()
|
|
9
|
+
const result = {}
|
|
10
|
+
const plugins = [...config.plugins]
|
|
11
|
+
if (useBajo) plugins.unshift('bajo')
|
|
12
|
+
for (const pkg of plugins) {
|
|
13
|
+
const plugin = camelCase(pkg)
|
|
14
|
+
let cfg = getConfig(plugin, { full: true })
|
|
15
|
+
const { alias, dependencies } = cfg
|
|
16
|
+
const dir = cfg.dir.pkg
|
|
17
|
+
cfg = omit(cfg, omittedPluginKeys)
|
|
18
|
+
let r
|
|
19
|
+
if (glob) {
|
|
20
|
+
const base = `${dir}/${ns}`
|
|
21
|
+
let opts = isString(glob) ? { pattern: [glob] } : glob
|
|
22
|
+
let pattern = opts.pattern ?? []
|
|
23
|
+
if (isString(pattern)) pattern = [pattern]
|
|
24
|
+
opts = omit(opts, ['pattern'])
|
|
25
|
+
for (const i in pattern) {
|
|
26
|
+
pattern[i] = `${base}/${pattern[i]}`
|
|
27
|
+
}
|
|
28
|
+
const files = await fastGlob(pattern, opts)
|
|
29
|
+
for (const f of files) {
|
|
30
|
+
const resp = await handler.call(this, { plugin, pkg, cfg, alias, file: f, dir: base, dependencies })
|
|
31
|
+
if (resp === false) break
|
|
32
|
+
else if (resp === undefined) continue
|
|
33
|
+
else {
|
|
34
|
+
result[plugin] = result[plugin] ?? {}
|
|
35
|
+
result[plugin][f] = resp
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
r = await handler.call(this, { plugin, pkg, cfg, dir, alias, dependencies })
|
|
40
|
+
if (r === false) break
|
|
41
|
+
else if (r === undefined) continue
|
|
42
|
+
else result[plugin] = r
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @module helper/eachPlugins
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Callback function that will be executed while walking through all Bajos
|
|
54
|
+
*
|
|
55
|
+
* @callback handlerFn
|
|
56
|
+
* @async
|
|
57
|
+
* @param {Object} argument - Provides information about current Bajo
|
|
58
|
+
* @param {string} argument.name - Bajo's name
|
|
59
|
+
* @param {string} argument.pkgName - Bajo's package name
|
|
60
|
+
* @param {Object} argument.cfg - Bajo's config object
|
|
61
|
+
* @returns {Object|boolean|undefined}
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Walk through all plugins and execute the callback handler
|
|
66
|
+
*
|
|
67
|
+
* @instance
|
|
68
|
+
* @async
|
|
69
|
+
* @param {function} handlerFn - [The callback]{@link module:helper/eachPlugins~handlerFn}
|
|
70
|
+
* @param {Object} [options] - Optional parameter
|
|
71
|
+
* @param {string} [options.key=name] - Key of Bajo's config object that will be used as the key of returned object
|
|
72
|
+
* @returns {Object} Results from callback execution through all Bajos
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* const { eachPlugins } = this.bajo.helper
|
|
76
|
+
* await eachPlugins(async function ({ name }) => {
|
|
77
|
+
* console.log(name)
|
|
78
|
+
* })
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
async function eachPlugins (handler, options = {}) {
|
|
82
|
+
const { getConfig, getPluginName } = this.bajo.helper
|
|
83
|
+
let { key = 'name', glob, ns, extend, extendHandler, useBajo } = options
|
|
84
|
+
if (!extendHandler) extendHandler = handler
|
|
85
|
+
ns = ns ?? getPluginName(4)
|
|
86
|
+
const result = await _eachPlugins.call(this, handler, { key, glob, ns, useBajo })
|
|
87
|
+
if (extend && isString(glob)) {
|
|
88
|
+
let nsExtend = ns
|
|
89
|
+
if (isString(extend)) nsExtend += '/' + trim(extend, '/')
|
|
90
|
+
const cfg = getConfig('app', { full: true })
|
|
91
|
+
const ext = `${cfg.dir.pkg}/${nsExtend}/extend/*`
|
|
92
|
+
const exts = await fastGlob(ext, { onlyDirectories: true })
|
|
93
|
+
for (const e of exts) {
|
|
94
|
+
const plugin = path.basename(e)
|
|
95
|
+
const files = await fastGlob(`${e}/${glob}`)
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
await extendHandler.call(this, { file, plugin, dir: e })
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result // TODO: merge with extender
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export default eachPlugins
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { last, isPlainObject, each, isArray, get } from 'lodash-es'
|
|
2
|
+
import print from './print.js'
|
|
3
|
+
import getPluginName from './get-plugin-name.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* It's a shortcut to create an instance of Error with message and optional parameter
|
|
7
|
+
* in a single line
|
|
8
|
+
*
|
|
9
|
+
* @memberof helper
|
|
10
|
+
* @type Object
|
|
11
|
+
* @instance
|
|
12
|
+
* @param {string} msg - String that will be used as error message
|
|
13
|
+
* @param {options} [options] - Optional parameter
|
|
14
|
+
* @param {string} [options.code] - Error code
|
|
15
|
+
* @returns {error} Instance of Error
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
Error.stackTraceLimit = 15
|
|
19
|
+
|
|
20
|
+
function formatErrorDetails (value, ns) {
|
|
21
|
+
each(value, (v, i) => {
|
|
22
|
+
if (!v.context) {
|
|
23
|
+
v.error = print._format.call(this, ns, v.error, {})
|
|
24
|
+
return undefined
|
|
25
|
+
}
|
|
26
|
+
v.context.message = v.message
|
|
27
|
+
if (v.type === 'any.only') v.context.ref = print._format.call(this, ns, `field.${get(v, 'context.valids.0.key')}`, {})
|
|
28
|
+
value[i] = {
|
|
29
|
+
field: get(v, 'context.key'),
|
|
30
|
+
error: print._format.call(this, ns, `validation.${v.type}`, v.context, {})
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function error (msg = 'Internal server error', ...args) {
|
|
36
|
+
let payload = last(args)
|
|
37
|
+
let ns
|
|
38
|
+
if (isPlainObject(payload)) {
|
|
39
|
+
payload = args.pop()
|
|
40
|
+
ns = payload.ns
|
|
41
|
+
}
|
|
42
|
+
if (!ns) ns = getPluginName.call(this, 3)
|
|
43
|
+
const orgMsg = msg
|
|
44
|
+
const message = print._format.call(this, ns, msg, ...args)
|
|
45
|
+
let err
|
|
46
|
+
if (isPlainObject(payload) && payload.class) err = payload.class(message)
|
|
47
|
+
else err = Error(message)
|
|
48
|
+
const stacks = err.stack.split('\n')
|
|
49
|
+
stacks.splice(1, 1) // this file
|
|
50
|
+
if (stacks[1].includes('/helper/fatal.js')) stacks.splice(1, 1) // if it goes to fatal.js
|
|
51
|
+
stacks.splice(1, 1) // for buildHelper.js
|
|
52
|
+
err.stack = stacks.join('\n')
|
|
53
|
+
if (isPlainObject(payload)) {
|
|
54
|
+
delete payload.class
|
|
55
|
+
delete payload.ns
|
|
56
|
+
for (const key in payload) {
|
|
57
|
+
const value = payload[key]
|
|
58
|
+
if (key === 'details' && isArray(value) && orgMsg === 'Validation Error') {
|
|
59
|
+
formatErrorDetails.call(this, value, ns)
|
|
60
|
+
}
|
|
61
|
+
err[key] = value
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return err
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default error
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import error from './error.js'
|
|
2
|
+
import getPluginName from './get-plugin-name.js'
|
|
3
|
+
|
|
4
|
+
function fatal (...args) {
|
|
5
|
+
const ns = getPluginName.call(this, 3)
|
|
6
|
+
args.push({ ns })
|
|
7
|
+
const err = error(...args)
|
|
8
|
+
console.error(err)
|
|
9
|
+
process.exit(1)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default fatal
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cloneDeep, isPlainObject } from 'lodash-es'
|
|
2
|
+
import { customAlphabet } from 'nanoid'
|
|
3
|
+
|
|
4
|
+
const generateId = (options = {}) => {
|
|
5
|
+
let { pattern, length = 21, returnInstance } = options
|
|
6
|
+
let opts = {}
|
|
7
|
+
if (isPlainObject(pattern)) {
|
|
8
|
+
opts = cloneDeep(pattern)
|
|
9
|
+
returnInstance = opts.returnInstance
|
|
10
|
+
length = opts.length
|
|
11
|
+
pattern = opts.pattern
|
|
12
|
+
}
|
|
13
|
+
pattern = pattern ?? 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
14
|
+
if (opts.lowerCase) pattern = pattern.toLowerCase()
|
|
15
|
+
else if (opts.upperCase) pattern = pattern.toUpperCase()
|
|
16
|
+
const nid = customAlphabet(pattern, length)
|
|
17
|
+
return returnInstance ? nid : nid()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default generateId
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isEmpty, isPlainObject, cloneDeep, omit, find } from 'lodash-es'
|
|
2
|
+
import omittedPluginKeys from '../lib/omitted-plugin-keys.js'
|
|
3
|
+
|
|
4
|
+
function getConfig (name, options = {}) {
|
|
5
|
+
const { full, clone } = options
|
|
6
|
+
if (name === 'bajo' || isEmpty(name)) return this.bajo.config
|
|
7
|
+
if (this[name] && isPlainObject(this[name].config) && this[name].config.name === name) {
|
|
8
|
+
const cfg = clone ? cloneDeep(this[name].config) : this[name].config
|
|
9
|
+
return full ? cfg : omit(cfg, omittedPluginKeys)
|
|
10
|
+
}
|
|
11
|
+
const ref = find(this.bajo.pluginRefs ?? [], { alias: name })
|
|
12
|
+
if (ref) {
|
|
13
|
+
const cfg = clone ? cloneDeep(this[ref.plugin].config) : this[ref.plugin].config
|
|
14
|
+
return full ? cfg : omit(cfg, omittedPluginKeys)
|
|
15
|
+
}
|
|
16
|
+
return {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default getConfig
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import globalModulesPath from 'global-modules-path'
|
|
2
|
+
import resolvePath from './resolve-path.js'
|
|
3
|
+
import error from './error.js'
|
|
4
|
+
import { dropRight } from 'lodash-es'
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
|
|
7
|
+
const getGlobalModuleDir = (pkgName, silent = true) => {
|
|
8
|
+
let nodeModulesDir = process.env.BAJO_GLOBAL_MODULE_DIR
|
|
9
|
+
if (!nodeModulesDir) {
|
|
10
|
+
const npmPath = globalModulesPath.getPath('npm')
|
|
11
|
+
if (!npmPath) {
|
|
12
|
+
if (silent) return
|
|
13
|
+
throw error('Can\'t locate npm global module directory', { code: 'BAJO_CANT_LOCATE_NPM_GLOBAL_DIR' })
|
|
14
|
+
}
|
|
15
|
+
nodeModulesDir = dropRight(resolvePath(npmPath).split('/'), 1).join('/')
|
|
16
|
+
process.env.BAJO_GLOBAL_MODULE_DIR = nodeModulesDir
|
|
17
|
+
}
|
|
18
|
+
if (!pkgName) return nodeModulesDir
|
|
19
|
+
const dir = `${nodeModulesDir}/${pkgName}`
|
|
20
|
+
if (!fs.existsSync(dir)) {
|
|
21
|
+
if (silent) return
|
|
22
|
+
throw error('Can\'t locate \'%s\' global module directory', pkgName, { code: 'BAJO_CANT_LOCATE_MODULE_GLOBAL_DIR' })
|
|
23
|
+
}
|
|
24
|
+
return dir
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default getGlobalModuleDir
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { get } from 'lodash-es'
|
|
2
|
+
import error from './error.js'
|
|
3
|
+
import breakNsPath from './break-ns-path.js'
|
|
4
|
+
|
|
5
|
+
function getHelper (name = '', thrown = true) {
|
|
6
|
+
const [plugin, method] = breakNsPath(name)
|
|
7
|
+
const helper = get(this, `${plugin}.helper.${method}`)
|
|
8
|
+
if (helper) return helper
|
|
9
|
+
if (thrown) throw error.call(this, 'Can\'t find helper named \'%s\'', name)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default getHelper
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
|
|
3
|
+
async function getItemByName (name) {
|
|
4
|
+
const { resolvePath, getConfig, readConfig, error } = this.bajo.helper
|
|
5
|
+
const config = getConfig()
|
|
6
|
+
const [type, ...paths] = name.split(':')
|
|
7
|
+
let result
|
|
8
|
+
switch (type) {
|
|
9
|
+
case 'config': {
|
|
10
|
+
let file = paths.join(':')
|
|
11
|
+
if (!path.isAbsolute(file)) file = resolvePath(`${config.dir.data}/config/${file}`)
|
|
12
|
+
result = await readConfig(file)
|
|
13
|
+
break
|
|
14
|
+
}
|
|
15
|
+
case 'helper': {
|
|
16
|
+
const [ns, fn] = paths.join(':').split('.')
|
|
17
|
+
if (!(ns && fn)) throw error('Unknown helper \'%s.%s\'', ns, fn, { code: 'BAJO_UNKNOWN_HELPER' })
|
|
18
|
+
result = this[ns].helper[fn]
|
|
19
|
+
break
|
|
20
|
+
}
|
|
21
|
+
default: throw error('Unsupported type \'%s\'', type, { code: 'BAJO_UNSUPPORTED_TYPE' })
|
|
22
|
+
}
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default getItemByName
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import resolvePath from './resolve-path.js'
|
|
3
|
+
import { createRequire } from 'module'
|
|
4
|
+
const require = createRequire(import.meta.url)
|
|
5
|
+
|
|
6
|
+
const getModuleDir = (pkgName, base) => {
|
|
7
|
+
if (base === 'app') base = process.env.BAJOCWD
|
|
8
|
+
let pkgPath = pkgName + '/package.json'
|
|
9
|
+
if (base) pkgPath = `${base}/node_modules/${pkgPath}`
|
|
10
|
+
const paths = require.resolve.paths(pkgPath)
|
|
11
|
+
paths.unshift(path.join(process.env.BAJOCWD, 'node_modules', pkgName))
|
|
12
|
+
let resolved
|
|
13
|
+
try {
|
|
14
|
+
resolved = require.resolve(pkgPath, { paths })
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
const dir = resolvePath(path.dirname(resolved))
|
|
19
|
+
return dir
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default getModuleDir
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from 'fs-extra'
|
|
2
|
+
|
|
3
|
+
function getPluginDataDir (name, ensureDir = true) {
|
|
4
|
+
const { getPlugin, getConfig } = this.bajo.helper
|
|
5
|
+
const plugin = getPlugin(name)
|
|
6
|
+
const cfg = getConfig()
|
|
7
|
+
const dir = `${cfg.dir.data}/plugins/${plugin.config.name}`
|
|
8
|
+
if (ensureDir) fs.ensureDirSync(dir)
|
|
9
|
+
return dir
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default getPluginDataDir
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { isString, isNumber, each, camelCase } from 'lodash-es'
|
|
2
|
+
import callsites from 'callsites'
|
|
3
|
+
import error from './error.js'
|
|
4
|
+
import resolvePath from './resolve-path.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the right Bajo name inside your app or plugins/Bajos. If parameter ```fname```
|
|
8
|
+
* is not provided, it will be set to the actual file this function is called.
|
|
9
|
+
*
|
|
10
|
+
* @memberof helper
|
|
11
|
+
* @instance
|
|
12
|
+
* @param {string} [fname] - File name (relative/absolute)
|
|
13
|
+
* @throws Will throw if Bajo name coldn't be resolved
|
|
14
|
+
* @returns {string} Bajo name
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function getPluginName (fname) {
|
|
18
|
+
const config = this.bajo.config
|
|
19
|
+
let file
|
|
20
|
+
if (isString(fname)) file = fname
|
|
21
|
+
else file = callsites()[isNumber(fname) ? fname : 2].getFileName()
|
|
22
|
+
if (!file) throw error('Can\'t resolve bajo named \'%s\', sorry!', fname, { code: 'BAJO_UNABLE_TO_RESOLVE_BAJO_NAME' })
|
|
23
|
+
file = resolvePath(file)
|
|
24
|
+
let match
|
|
25
|
+
each(config.plugins, b => {
|
|
26
|
+
if (file.includes('/bajo/boot/')) {
|
|
27
|
+
match = 'bajo'
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
if (file.includes('/' + b + '/')) {
|
|
31
|
+
match = b
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
if (match) return camelCase(match)
|
|
36
|
+
return 'bajo'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default getPluginName
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { find } from 'lodash-es'
|
|
2
|
+
|
|
3
|
+
function getPlugin (name) {
|
|
4
|
+
const { error } = this.bajo.helper
|
|
5
|
+
if (!this[name]) {
|
|
6
|
+
// alias?
|
|
7
|
+
const ref = find(this.bajo.pluginRefs ?? [], { alias: name })
|
|
8
|
+
if (!ref) throw error('\'%s\' is not loaded', name)
|
|
9
|
+
name = ref.name
|
|
10
|
+
}
|
|
11
|
+
return this[name]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default getPlugin
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import resolvePath from './resolve-path.js'
|
|
2
|
+
import { isFunction, isPlainObject } from 'lodash-es'
|
|
3
|
+
import error from './error.js'
|
|
4
|
+
|
|
5
|
+
async function load (file, asDefaultImport = true) {
|
|
6
|
+
const imported = await import(resolvePath(file, true))
|
|
7
|
+
if (asDefaultImport) return imported.default
|
|
8
|
+
return imported
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function importModule (file, { asDefaultImport, asHandler } = {}) {
|
|
12
|
+
let mod = await load(file, asDefaultImport)
|
|
13
|
+
if (!asHandler) return mod
|
|
14
|
+
if (isFunction(mod)) mod = { level: 999, handler: mod }
|
|
15
|
+
if (!isPlainObject(mod)) throw error.call(this, 'File \'%s\' is NOT a handler module', file)
|
|
16
|
+
if (mod.forceAsync && mod.handler.constructor.name !== 'AsyncFunction') {
|
|
17
|
+
const oldHandler = mod.handler
|
|
18
|
+
mod.handler = async function (...args) {
|
|
19
|
+
oldHandler.call(this, ...args)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return mod
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default importModule
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isPlainObject, map, last, isEmpty, has, keys, values, trim, get } from 'lodash-es'
|
|
2
|
+
import os from 'os'
|
|
3
|
+
import getModuleDir from './get-module-dir.js'
|
|
4
|
+
import resolvePath from './resolve-path.js'
|
|
5
|
+
import readJson from './read-json.js'
|
|
6
|
+
import defaultsDeep from './defaults-deep.js'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import fs from 'fs-extra'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Load/import a package dynamically. You can import package one-by-one or multiple
|
|
12
|
+
* packages at once.
|
|
13
|
+
*
|
|
14
|
+
* Package 'pkg' must be in the following format: ```<original name>:<new name>:<bajo package name>```
|
|
15
|
+
* ```<new name>``` can be omitted, so the format will be: ```<name>::<bajo package name>```
|
|
16
|
+
*
|
|
17
|
+
* If you only import one package, returned value is the imported package itself
|
|
18
|
+
* If multiple packages are imported, returned value is an object with ```<new name>``` as its
|
|
19
|
+
* keys and imported packages as its values
|
|
20
|
+
*
|
|
21
|
+
* Example:
|
|
22
|
+
* ```
|
|
23
|
+
* const imported = await importPkg('ora::bajo-cli')
|
|
24
|
+
* const multiple = await importPkg('ora::bajo-cli', 'lodash:_:bajo')
|
|
25
|
+
*
|
|
26
|
+
* @param {...string} pkg
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const importPkg = async (...pkg) => {
|
|
31
|
+
const result = {}
|
|
32
|
+
let opts = { returnDefault: true }
|
|
33
|
+
if (isPlainObject(last(pkg))) {
|
|
34
|
+
opts = defaultsDeep(pkg.pop(), opts)
|
|
35
|
+
}
|
|
36
|
+
for (const p of pkg) {
|
|
37
|
+
const parts = map(p.split(':'), i => trim(i))
|
|
38
|
+
let [ns, orgName, name] = parts
|
|
39
|
+
if (parts.length === 1) {
|
|
40
|
+
orgName = ns
|
|
41
|
+
ns = 'bajo'
|
|
42
|
+
name = orgName
|
|
43
|
+
} else if (parts.length === 2) {
|
|
44
|
+
name = orgName
|
|
45
|
+
}
|
|
46
|
+
if (isEmpty(name)) name = orgName
|
|
47
|
+
const dir = getModuleDir(orgName, ns)
|
|
48
|
+
const pkg = readJson(`${dir}/package.json`)
|
|
49
|
+
const mainFileOrg = dir + '/' + (pkg.main ?? get(pkg, 'exports.default', 'index.js'))
|
|
50
|
+
let mainFile = resolvePath(mainFileOrg, os.platform() === 'win32')
|
|
51
|
+
if (isEmpty(path.extname(mainFile))) {
|
|
52
|
+
if (fs.existsSync(`${mainFileOrg}/index.js`)) mainFile += '/index.js'
|
|
53
|
+
else mainFile += '.js'
|
|
54
|
+
}
|
|
55
|
+
let mod = await import(mainFile)
|
|
56
|
+
if (opts.returnDefault && has(mod, 'default')) {
|
|
57
|
+
mod = mod.default
|
|
58
|
+
if (opts.returnDefault && has(mod, 'default')) mod = mod.default
|
|
59
|
+
}
|
|
60
|
+
result[name] = mod
|
|
61
|
+
}
|
|
62
|
+
if (pkg.length === 1) return result[keys(result)[0]]
|
|
63
|
+
if (opts.asObject) return result
|
|
64
|
+
return values(result)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default importPkg
|