bajo 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.jsdoc.conf.json +38 -0
  2. package/README.md +57 -3
  3. package/boot/attach-helper.js +26 -0
  4. package/boot/boot-order.js +34 -0
  5. package/boot/build-config.js +94 -0
  6. package/boot/create-scope.js +36 -0
  7. package/boot/exit-handler.js +60 -0
  8. package/boot/helper/build-collections.js +40 -0
  9. package/boot/helper/call-helper-or-handler.js +15 -0
  10. package/boot/helper/current-loc.js +11 -0
  11. package/boot/helper/defaults-deep.js +14 -0
  12. package/boot/helper/dump.js +10 -0
  13. package/boot/helper/each-plugins.js +94 -0
  14. package/boot/helper/envs.js +14 -0
  15. package/boot/helper/error.js +47 -0
  16. package/boot/helper/fatal.js +12 -0
  17. package/boot/helper/generate-id.js +19 -0
  18. package/boot/helper/get-config.js +18 -0
  19. package/boot/helper/get-global-module-dir.js +27 -0
  20. package/boot/helper/get-helper.js +11 -0
  21. package/boot/helper/get-item-by-name.js +26 -0
  22. package/boot/helper/get-key-by-value.js +5 -0
  23. package/boot/helper/get-module-dir.js +22 -0
  24. package/boot/helper/get-plugin-name.js +39 -0
  25. package/boot/helper/get-plugin.js +7 -0
  26. package/boot/helper/import-module.js +25 -0
  27. package/boot/helper/import-pkg.js +67 -0
  28. package/boot/helper/index.js +36 -0
  29. package/boot/helper/is-empty-dir.js +9 -0
  30. package/boot/helper/is-log-in-range.js +10 -0
  31. package/boot/helper/is-set.js +5 -0
  32. package/boot/helper/is-valid-app.js +12 -0
  33. package/boot/helper/is-valid-plugin.js +12 -0
  34. package/boot/helper/log-levels.js +19 -0
  35. package/boot/helper/pascal-case.js +7 -0
  36. package/boot/helper/print.js +89 -0
  37. package/boot/helper/read-config.js +46 -0
  38. package/boot/helper/read-json.js +10 -0
  39. package/boot/helper/resolve-path.js +15 -0
  40. package/boot/helper/resolve-tpl-path.js +21 -0
  41. package/boot/helper/run-hook.js +46 -0
  42. package/boot/helper/save-as-download.js +18 -0
  43. package/boot/helper/white-space.js +3 -0
  44. package/boot/index.js +60 -0
  45. package/boot/lib/bora.js +97 -0
  46. package/boot/lib/build-helper.js +58 -0
  47. package/boot/lib/logger.js +75 -0
  48. package/boot/lib/omitted-plugin-keys.js +3 -0
  49. package/boot/lib/parse-args-argv.js +75 -0
  50. package/boot/lib/parse-env.js +36 -0
  51. package/boot/lib/shim.js +14 -0
  52. package/boot/plugins/attach-helper.js +20 -0
  53. package/boot/plugins/build-config.js +75 -0
  54. package/boot/plugins/check-clash.js +18 -0
  55. package/boot/plugins/check-dependency.js +37 -0
  56. package/boot/plugins/collect-config-handlers.js +25 -0
  57. package/boot/plugins/collect-exit-handlers.js +23 -0
  58. package/boot/plugins/collect-hooks.js +33 -0
  59. package/boot/plugins/extend-config.js +21 -0
  60. package/boot/plugins/index.js +28 -0
  61. package/boot/plugins/run.js +31 -0
  62. package/boot/run-tool.js +34 -0
  63. package/docs/boot_build-config.js.html +75 -0
  64. package/docs/boot_create-scope.js.html +25 -0
  65. package/docs/boot_index.js.html +43 -0
  66. package/docs/data/search.json +1 -0
  67. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  68. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  69. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  70. package/docs/helper_emit.js.html +18 -0
  71. package/docs/helper_envs.js.html +16 -0
  72. package/docs/helper_error.js.html +25 -0
  73. package/docs/helper_get-bajo.js.html +42 -0
  74. package/docs/helper_index.js.html +39 -0
  75. package/docs/helper_log-levels.js.html +20 -0
  76. package/docs/helper_set-hook.js.html +38 -0
  77. package/docs/helper_walk-bajos.js.html +51 -0
  78. package/docs/index.html +16 -0
  79. package/docs/module-boot.html +3 -0
  80. package/docs/module-boot_buildConfig.html +3 -0
  81. package/docs/module-boot_createScope.html +3 -0
  82. package/docs/module-helper.html +7 -0
  83. package/docs/module-helper_setHook.html +4 -0
  84. package/docs/module-helper_walkBajos.html +6 -0
  85. package/docs/scripts/core.js +655 -0
  86. package/docs/scripts/core.min.js +23 -0
  87. package/docs/scripts/resize.js +90 -0
  88. package/docs/scripts/search.js +265 -0
  89. package/docs/scripts/search.min.js +6 -0
  90. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  91. package/docs/scripts/third-party/fuse.js +9 -0
  92. package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
  93. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  94. package/docs/scripts/third-party/hljs-original.js +5171 -0
  95. package/docs/scripts/third-party/hljs.js +1 -0
  96. package/docs/scripts/third-party/popper.js +5 -0
  97. package/docs/scripts/third-party/tippy.js +1 -0
  98. package/docs/scripts/third-party/tocbot.js +672 -0
  99. package/docs/scripts/third-party/tocbot.min.js +1 -0
  100. package/docs/styles/clean-jsdoc-theme-base.css +975 -0
  101. package/docs/styles/clean-jsdoc-theme-dark.css +407 -0
  102. package/docs/styles/clean-jsdoc-theme-light.css +388 -0
  103. package/docs/styles/clean-jsdoc-theme.min.css +1 -0
  104. package/package.json +36 -4
  105. package/test/helper-error.js +25 -0
  106. package/test/helper-isSet.js +41 -0
  107. package/test/helper-pathResolve.js +28 -0
@@ -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,11 @@
1
+ import { get } from 'lodash-es'
2
+ import error from './error.js'
3
+
4
+ function getHelper (name = '', thrown = true) {
5
+ const [plugin, method] = name.split(':')
6
+ const helper = get(this, `${plugin}.helper.${method}`)
7
+ if (helper) return helper
8
+ if (thrown) throw error.call(this, 'Can\'t find helper named \'%s\'', name)
9
+ }
10
+
11
+ 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,5 @@
1
+ const getKeyByValue = (object, value) => {
2
+ return Object.keys(object).find(key => object[key] === value)
3
+ }
4
+
5
+ export default getKeyByValue
@@ -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,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,7 @@
1
+ async function getPlugin (name) {
2
+ const { error } = this.bajo.helper
3
+ if (!this[name]) throw error('\'%s\' is not loaded', name)
4
+ return this[name]
5
+ }
6
+
7
+ 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
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Bajo Helper is a general-purpose container that consists of functions, objects, or arrays
3
+ * that are accessible across all plugins/Bajos and applications. It also serves as a proxy
4
+ * to some exported third-party libraries.
5
+ *
6
+ * To use it, simply deconstruct the variables you want from Bajo Helper as shown in the
7
+ * example below.
8
+ *
9
+ * @module helper
10
+ * @example
11
+ * module.exports = async function () {
12
+ * const { fs, getConfig } = this.bajo.helper
13
+ * const config = getConfig('bajoExtra')
14
+ * await fs.writeFile('./bajo-extra-config.json', JSON.stringify(config), 'utf8')
15
+ * }
16
+ */
17
+
18
+ /**
19
+ * | Attached As | Package Name | Usage |
20
+ * |-------------|--------------|-------|
21
+ * | _ | [lodash](https://lodash.com/) | ```const { _ } = this.bajo.helper``` |
22
+ * | callsites | [callsites](https://github.com/sindresorhus/callsites) | ```const { _ } = this.bajo.helper``` |
23
+ * | dateFormat | [dateformat](https://github.com/felixge/node-dateformat) | ```const { dateFormat } = this.bajo.helper``` |
24
+ * | fastGlob | [fast-glob](https://github.com/mrmlnc/fast-glob) | ```const { fastGlob } = this.bajo.helper``` |
25
+ * | flatten | [flat](https://github.com/hughsk/flat) | ```const { flatten } = this.bajo.helper``` |
26
+ * | freeze | [deep-freeze-strict](https://github.com/jsdf/deep-freeze) | ```const { freeze } = this.bajo.helper``` |
27
+ * | fs | [fs-extra](https://github.com/jprichardson/node-fs-extra) | ```const { fs } = this.bajo.helper``` |
28
+ * | lockfile | [proper-lockfile](https://github.com/moxystudio/node-proper-lockfile) | ```const { lockfile } = this.bajo.helper``` |
29
+ * | outmatch | [outmatch](https://github.com/axtgr/outmatch) | ```const { outmatch } = this.bajo.helper``` |
30
+ * | semver | [semver](https://github.com/npm/node-semver) | ```const { semver } = this.bajo.helper``` |
31
+ * | unflatten | [flat](https://github.com/hughsk/flat) | ```const { unflatten } = this.bajo.helper``` |
32
+ *
33
+ * @memberof module:helper/3rdPartyLibs
34
+ * @name 3rd Party Libraries
35
+ * @instance
36
+ */
@@ -0,0 +1,9 @@
1
+ import emptyDir from 'empty-dir'
2
+ import fs from 'fs-extra'
3
+
4
+ const isEmptyDir = async (dir) => {
5
+ await fs.exists(dir)
6
+ return await emptyDir(dir)
7
+ }
8
+
9
+ export default isEmptyDir
@@ -0,0 +1,10 @@
1
+ import logLevels from './log-levels.js'
2
+ import { keys, indexOf } from 'lodash-es'
3
+
4
+ function isLogInRange (level) {
5
+ const levels = keys(logLevels)
6
+ const logLevel = indexOf(levels, this.bajo.config.log.level)
7
+ return indexOf(levels, level) >= logLevel
8
+ }
9
+
10
+ export default isLogInRange
@@ -0,0 +1,5 @@
1
+ const isSet = (input) => {
2
+ return ![null, undefined].includes(input)
3
+ }
4
+
5
+ export default isSet
@@ -0,0 +1,12 @@
1
+ import fs from 'fs-extra'
2
+ import resolvePath from './resolve-path.js'
3
+
4
+ const isValidApp = (dir) => {
5
+ if (!dir) dir = process.env.BAJOCWD
6
+ dir = resolvePath(dir)
7
+ const hasAppDir = fs.existsSync(`${dir}/app/bajo`)
8
+ const hasPackageJson = fs.existsSync(`${dir}/package.json`)
9
+ return hasAppDir && hasPackageJson
10
+ }
11
+
12
+ export default isValidApp
@@ -0,0 +1,12 @@
1
+ import fs from 'fs-extra'
2
+ import resolvePath from './resolve-path.js'
3
+
4
+ const isValidPlugin = (dir) => {
5
+ if (!dir) dir = process.env.BAJOCWD
6
+ dir = resolvePath(dir)
7
+ const hasBajoDir = fs.existsSync(`${dir}/bajo`)
8
+ const hasPackageJson = fs.existsSync(`${dir}/package.json`)
9
+ return hasBajoDir && hasPackageJson
10
+ }
11
+
12
+ export default isValidPlugin
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Supported logger levels including its level priority
3
+ *
4
+ * @memberof module:helper
5
+ * @type Object
6
+ * @instance
7
+ */
8
+
9
+ const logLevels = {
10
+ trace: 10,
11
+ debug: 20,
12
+ info: 30,
13
+ warn: 40,
14
+ error: 50,
15
+ fatal: 60,
16
+ silent: 99
17
+ }
18
+
19
+ export default logLevels
@@ -0,0 +1,7 @@
1
+ import { camelCase, upperFirst } from 'lodash-es'
2
+
3
+ const pascalCase = (text) => {
4
+ return upperFirst(camelCase(text))
5
+ }
6
+
7
+ export default pascalCase
@@ -0,0 +1,89 @@
1
+ import bora from '../lib/bora.js'
2
+ import Sprintf from 'sprintf-js'
3
+ import { last, isPlainObject, get } from 'lodash-es'
4
+ import defaultsDeep from './defaults-deep.js'
5
+ import getPluginName from './get-plugin-name.js'
6
+
7
+ const { sprintf } = Sprintf
8
+
9
+ function prep (args) {
10
+ let opts = { type: 'bora', exit: false, skipSilent: false }
11
+ const l = last(args)
12
+ if (isPlainObject(l)) opts = defaultsDeep(args.pop(), opts)
13
+ const [pkg, msg, ...params] = args
14
+ opts.pkg = pkg
15
+ opts.ns = pkg === 'bajo' ? 'bajoI18N' : pkg
16
+ return { ns: opts.ns, pkg, msg, params, opts }
17
+ }
18
+
19
+ function format (...args) {
20
+ const { ns, msg, params, opts } = prep(args)
21
+ if (!msg) return ''
22
+ const i18n = get(this, 'bajoI18N.instance')
23
+ if (i18n) {
24
+ if (isPlainObject(params[0])) return i18n.t(msg, params[0])
25
+ return i18n.t(msg, { ns, pkg: opts.pkg, postProcess: 'sprintf', sprintf: params })
26
+ }
27
+ return sprintf(msg, ...params)
28
+ }
29
+
30
+ const print = {
31
+ __: function (...args) {
32
+ const [msg, ...params] = args
33
+ const pkg = getPluginName.call(this, 2)
34
+ return format.call(this, pkg, msg, ...params)
35
+ },
36
+ _format: format,
37
+ fail: function (...args) {
38
+ args.unshift(getPluginName.call(this, 2))
39
+ const { ns, opts, msg, params } = prep(args)
40
+ if (msg) {
41
+ if (opts.type === 'bora') bora.call(this, ns, opts).fail(msg, ...params)
42
+ else console.error(format.call(this, ns, msg, ...params))
43
+ }
44
+ if (opts.exit) process.exit(1)
45
+ },
46
+ succeed: function (...args) {
47
+ args.unshift(getPluginName.call(this, 2))
48
+ const { ns, opts, msg, params } = prep(args)
49
+ if (msg) {
50
+ if (opts.type === 'bora') bora.call(this, ns, opts).succeed(msg, ...params)
51
+ else console.log(format.call(this, ns, msg, ...params))
52
+ }
53
+ if (opts.exit) process.exit(0)
54
+ },
55
+ warn: function (...args) {
56
+ args.unshift(getPluginName.call(this, 2))
57
+ const { ns, opts, msg, params } = prep(args)
58
+ if (msg) {
59
+ if (opts.type === 'bora') bora.call(this, ns, opts).warn(msg, ...params)
60
+ else console.log(format.call(this, ns, msg, ...params))
61
+ }
62
+ if (opts.exit) process.exit(0)
63
+ },
64
+ info: function (...args) {
65
+ args.unshift(getPluginName.call(this, 2))
66
+ const { ns, opts, msg, params } = prep(args)
67
+ if (msg) {
68
+ if (opts.type === 'bora') bora.call(this, ns, opts).info(msg, ...params)
69
+ else console.log(format.call(this, ns, msg, ...params))
70
+ }
71
+ if (opts.exit) process.exit(0)
72
+ },
73
+ fatal: function (...args) {
74
+ args.unshift(getPluginName.call(this, 2))
75
+ const { ns, opts, msg, params } = prep(args)
76
+ if (msg) {
77
+ if (opts.type === 'bora') bora.call(this, ns, opts).fatal(msg, ...params)
78
+ else console.error(format.call(this, ns, msg, ...params))
79
+ }
80
+ process.exit(0)
81
+ },
82
+ bora: function (...args) {
83
+ let ns = getPluginName.call(this, 2)
84
+ if (ns === 'bajo') ns = 'bajoI18N'
85
+ return bora.call(this, ns, ...args)
86
+ }
87
+ }
88
+
89
+ export default print
@@ -0,0 +1,46 @@
1
+ import path from 'path'
2
+ import resolvePath from './resolve-path.js'
3
+ import readJson from './read-json.js'
4
+ import { find, map, isEmpty } from 'lodash-es'
5
+ import error from './error.js'
6
+ import fg from 'fast-glob'
7
+
8
+ async function readConfig (file, { pattern, globOptions = {}, ignoreError, defValue = {} } = {}) {
9
+ file = resolvePath(file)
10
+ let ext = path.extname(file)
11
+ const fname = path.dirname(file) + '/' + path.basename(file, ext)
12
+ ext = ext.toLowerCase()
13
+ if (['.mjs', '.js'].includes(ext)) {
14
+ const { handler } = find(this.bajo.configHandlers, { ext })
15
+ return await handler.call(this, file)
16
+ }
17
+ if (ext === '.json') return await readJson(file)
18
+ if (!['', '.*'].includes(ext)) {
19
+ const item = find(this.bajo.configHandlers, { ext })
20
+ if (!item) {
21
+ if (!ignoreError) throw error.call(this, 'Can\'t parse \'%s\'', file, { code: 'BAJO_CONFIG_NO_PARSER' })
22
+ return defValue
23
+ }
24
+ return item.handler.call(this, file)
25
+ }
26
+ const item = pattern ?? `${fname}.{${map(map(this.bajo.configHandlers, 'ext'), k => k.slice(1)).join(',')}}`
27
+ const files = await fg(item, globOptions)
28
+ if (files.length === 0) {
29
+ if (!ignoreError) throw error.call(this, 'No config file found', { code: 'BAJO_CONFIG_FILE_NOT_FOUND' })
30
+ return defValue
31
+ }
32
+ let config = defValue
33
+ for (const f of files) {
34
+ const ext = path.extname(f).toLowerCase()
35
+ const item = find(this.bajo.configHandlers, { ext })
36
+ if (!item) {
37
+ if (!ignoreError) throw error.call(this, 'Can\'t parse \'%s\'', f, { code: 'BAJO_CONFIG_NO_PARSER' })
38
+ continue
39
+ }
40
+ config = await item.handler.call(this, f)
41
+ if (!isEmpty(config)) break
42
+ }
43
+ return config
44
+ }
45
+
46
+ export default readConfig
@@ -0,0 +1,10 @@
1
+ import fs from 'fs-extra'
2
+ import { isEmpty } from 'lodash-es'
3
+
4
+ const readJson = (file) => {
5
+ let resp = fs.readFileSync(file, 'utf8')
6
+ if (isEmpty(resp)) resp = '{}'
7
+ return JSON.parse(resp)
8
+ }
9
+
10
+ export default readJson
@@ -0,0 +1,15 @@
1
+ import path from 'path'
2
+ import { fileURLToPath } from 'url'
3
+ import os from 'os'
4
+
5
+ const resolvePath = (item, asFileUrl) => {
6
+ if (item.startsWith('file://')) item = fileURLToPath(item)
7
+ item = path.resolve(item)
8
+ if (os.platform() === 'win32') {
9
+ item = item.replace(/\\/g, '/')
10
+ }
11
+ if (asFileUrl) item = `file:///${item}`
12
+ return item
13
+ }
14
+
15
+ export default resolvePath
@@ -0,0 +1,21 @@
1
+ import { isEmpty, trim } from 'lodash-es'
2
+ import fs from 'fs-extra'
3
+
4
+ function resolveTplPath (name, baseTpl, extTpl = '') {
5
+ const { error, getConfig } = this.bajo.helper
6
+ let [ns, path] = name.split(':')
7
+ if (isEmpty(path)) {
8
+ path = ns
9
+ ns = 'app'
10
+ }
11
+ if (path.startsWith('.')) throw error('Path \'%s\' must be an absolute path', path)
12
+ if (!this[ns]) throw error('Unknown plugin \'%s\' or plugin isn\'t loaded yet', ns)
13
+ const cfgNs = getConfig(ns, { full: true })
14
+ const cfgApp = getConfig('app', { full: true })
15
+ let file = `${cfgNs.dir}/${baseTpl}/${trim(path, '/')}${extTpl}`
16
+ const override = `${cfgApp.dir}/${baseTpl}/override/${ns}/${trim(path, '/')}${extTpl}`
17
+ if (fs.existsSync(override)) file = override
18
+ return file
19
+ }
20
+
21
+ export default resolveTplPath
@@ -0,0 +1,46 @@
1
+ import { filter, isEmpty, orderBy } from 'lodash-es'
2
+
3
+ /**
4
+ * @module helper/runHook
5
+ */
6
+
7
+ /**
8
+ * Set hook defined by parameter ```hookName```. Hook name should be in this following format:
9
+ * ```<namespace>:<identifier>``` - where namespace is a valid Bajo name and
10
+ * identifier is a unique string set by Bajo developer to identify a hook inside a Bajo
11
+ *
12
+ * @instance
13
+ * @async
14
+ * @param {string} hookName - Hook's name
15
+ *
16
+ * @example
17
+ * const { runHook } = this.bajo.helper
18
+ * await runHook('myBajo:afterStartApp')
19
+ */
20
+
21
+ async function runHook (hookName, ...args) {
22
+ // const { log } = this.bajo.helper
23
+ // log.trace('Run hook: %s', hookName)
24
+ const [ns, path] = (hookName ?? '').split(':')
25
+ let fns = filter(this.bajo.hooks, { ns, path })
26
+ if (isEmpty(fns)) return
27
+ fns = orderBy(fns, ['level'])
28
+ const results = []
29
+ for (const i in fns) {
30
+ const fn = fns[i]
31
+ /*
32
+ if (config.log.report.includes(id)) {
33
+ log.trace({ args }, 'Call hook: %s', id)
34
+ }
35
+ */
36
+ const res = await fn.handler.call(this, ...args)
37
+ results.push({
38
+ hook: hookName,
39
+ tag: fn.tag,
40
+ resp: res
41
+ })
42
+ }
43
+ return results
44
+ }
45
+
46
+ export default runHook
@@ -0,0 +1,18 @@
1
+ import fs from 'fs-extra'
2
+ import path from 'path'
3
+ import { trim } from 'lodash-es'
4
+ import increment from 'add-filename-increment'
5
+
6
+ async function saveAsDownload (file, obj, printSaved = true) {
7
+ const { print, getPluginName, resolvePath } = this.bajo.helper
8
+ const config = this.bajo.config
9
+ const plugin = getPluginName(4)
10
+ const fname = resolvePath(increment(`${config.dir.data}/plugins/${plugin}/${trim(file, '/')}`, { fs: true }))
11
+ const dir = path.dirname(fname)
12
+ if (!fs.existsSync(dir)) fs.ensureDirSync(dir)
13
+ await fs.writeFile(fname, obj, 'utf8')
14
+ if (printSaved) print.bora('Saved as \'%s\'', path.resolve(fname), { skipSilence: true }).succeed()
15
+ return fname
16
+ }
17
+
18
+ export default saveAsDownload
@@ -0,0 +1,3 @@
1
+ const whiteSpace = [' ', '\t', '\n', '\r']
2
+
3
+ export default whiteSpace