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/bajo.js
CHANGED
|
@@ -3,21 +3,16 @@ import increment from 'add-filename-increment'
|
|
|
3
3
|
import fs from 'fs-extra'
|
|
4
4
|
import path from 'path'
|
|
5
5
|
import os from 'os'
|
|
6
|
-
import ms from 'ms'
|
|
7
|
-
import dotenvParseVariables from 'dotenv-parse-variables'
|
|
8
6
|
import emptyDir from 'empty-dir'
|
|
9
7
|
import lodash from 'lodash'
|
|
10
|
-
import currentLoc from '../lib/current-loc.js'
|
|
11
8
|
import { createRequire } from 'module'
|
|
12
9
|
import getGlobalPath from 'get-global-path'
|
|
13
|
-
import { customAlphabet } from 'nanoid'
|
|
14
10
|
import fastGlob from 'fast-glob'
|
|
15
11
|
import querystring from 'querystring'
|
|
16
|
-
import deepFreeze from 'deep-freeze-strict'
|
|
17
|
-
import resolvePath from '../lib/resolve-path.js'
|
|
18
12
|
import importModule from '../lib/import-module.js'
|
|
19
13
|
import logLevels from '../lib/log-levels.js'
|
|
20
14
|
import { types as formatTypes, formats } from '../lib/formats.js'
|
|
15
|
+
import aneka from 'aneka'
|
|
21
16
|
import {
|
|
22
17
|
buildBaseConfig,
|
|
23
18
|
buildExtConfig,
|
|
@@ -32,11 +27,13 @@ const require = createRequire(import.meta.url)
|
|
|
32
27
|
|
|
33
28
|
const {
|
|
34
29
|
isFunction, map, isObject,
|
|
35
|
-
trim, filter, isEmpty, orderBy, pullAt, find, camelCase,
|
|
36
|
-
cloneDeep, isPlainObject, isArray, isString,
|
|
30
|
+
trim, filter, isEmpty, orderBy, pullAt, find, camelCase,
|
|
31
|
+
cloneDeep, isPlainObject, isArray, isString, omit, keys, indexOf,
|
|
37
32
|
last, get, has, values, dropRight, pick
|
|
38
33
|
} = lodash
|
|
39
34
|
|
|
35
|
+
const { resolvePath, currentLoc } = aneka
|
|
36
|
+
|
|
40
37
|
/**
|
|
41
38
|
* The Core. The main engine. The one and only plugin that control app's boot process and
|
|
42
39
|
* making sure all other plugins working nicely.
|
|
@@ -44,12 +41,12 @@ const {
|
|
|
44
41
|
* @class
|
|
45
42
|
*/
|
|
46
43
|
class Bajo extends Plugin {
|
|
47
|
-
static alias = 'bajo'
|
|
48
44
|
/**
|
|
49
45
|
* @param {App} app - App instance. Usefull to call app method inside a plugin
|
|
50
46
|
*/
|
|
51
47
|
constructor (app) {
|
|
52
48
|
super('bajo', app)
|
|
49
|
+
this.alias = 'bajo'
|
|
53
50
|
this.whiteSpace = [' ', '\t', '\n', '\r']
|
|
54
51
|
/**
|
|
55
52
|
* Config object
|
|
@@ -93,37 +90,9 @@ class Bajo extends Plugin {
|
|
|
93
90
|
await bootOrder.call(this)
|
|
94
91
|
await bootPlugins.call(this)
|
|
95
92
|
await exitHandler.call(this)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
* Resolve file name to filesystem's path. Windows path separator ```\```
|
|
100
|
-
* is normalized to Unix's ```/```
|
|
101
|
-
*
|
|
102
|
-
* @method
|
|
103
|
-
* @param {string} file - File to resolve
|
|
104
|
-
* @param {boolean} [asFileUrl=false] - Return as file URL format ```file:///<name>```
|
|
105
|
-
* @returns {string}
|
|
106
|
-
*/
|
|
107
|
-
resolvePath = (file, asFileUrl) => {
|
|
108
|
-
return resolvePath(file, asFileUrl)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Freeze object
|
|
113
|
-
*
|
|
114
|
-
* @method
|
|
115
|
-
* @param {Object} obj - Object to freeze
|
|
116
|
-
* @param {boolean} [shallow=false] - If ```false``` (default), deep freeze object
|
|
117
|
-
*/
|
|
118
|
-
freeze = (obj, shallow = false) => {
|
|
119
|
-
if (shallow) Object.freeze(obj)
|
|
120
|
-
else deepFreeze(obj)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
setImmediate = async () => {
|
|
124
|
-
return new Promise((resolve) => {
|
|
125
|
-
setImmediate(() => resolve())
|
|
126
|
-
})
|
|
93
|
+
if (this.app.bajoSpatial) {
|
|
94
|
+
this.anekaSpatial = await this.importPkg('bajoSpatial:aneka-spatial')
|
|
95
|
+
}
|
|
127
96
|
}
|
|
128
97
|
|
|
129
98
|
breakNsPathFromFile = ({ file, dir, baseNs, suffix = '', getType } = {}) => {
|
|
@@ -376,10 +345,9 @@ class Bajo extends Plugin {
|
|
|
376
345
|
*/
|
|
377
346
|
eachPlugins = async (handler, options = {}) => {
|
|
378
347
|
if (typeof options === 'string') options = { glob: options }
|
|
379
|
-
const result = {}
|
|
380
|
-
const pluginPkgs = cloneDeep(this.app.pluginPkgs) ?? []
|
|
381
348
|
const { glob, useBajo, prefix = '', noUnderscore = true, returnItems } = options
|
|
382
|
-
|
|
349
|
+
const pluginPkgs = useBajo ? [...cloneDeep(this.app.pluginPkgs), 'bajo'] : this.app.pluginPkgs
|
|
350
|
+
const result = {}
|
|
383
351
|
for (const pkgName of pluginPkgs) {
|
|
384
352
|
const ns = camelCase(pkgName)
|
|
385
353
|
let r
|
|
@@ -498,8 +466,8 @@ class Bajo extends Plugin {
|
|
|
498
466
|
if (type === 'auto') {
|
|
499
467
|
if (value instanceof Date) type = 'datetime'
|
|
500
468
|
}
|
|
501
|
-
if (['float', 'double'].includes(type) && this.
|
|
502
|
-
const { latToDms, lngToDms } = this.
|
|
469
|
+
if (['float', 'double'].includes(type) && this.anekaSpatial) {
|
|
470
|
+
const { latToDms, lngToDms } = this.anekaSpatial
|
|
503
471
|
if (options.latitude) return latToDms(value)
|
|
504
472
|
if (options.longitude) return lngToDms(value)
|
|
505
473
|
}
|
|
@@ -534,35 +502,12 @@ class Bajo extends Plugin {
|
|
|
534
502
|
}
|
|
535
503
|
|
|
536
504
|
/**
|
|
537
|
-
*
|
|
505
|
+
* Format text according using sprintf with extra ability to run its arguments through a serie of modifiers
|
|
538
506
|
*
|
|
539
|
-
* @
|
|
540
|
-
* @param
|
|
541
|
-
* @
|
|
542
|
-
* @param {number} [options.length=13] - Length of resulted characters
|
|
543
|
-
* @param {string} [options.case] - If set to ```lower``` to use lower cased pattern only. For upper cased pattern, set it to ```upper```
|
|
544
|
-
* @param {boolean} [options.returnInstance] - Set to ```true``` to return {@link https://github.com/ai/nanoid|nanoid} instance instead of string
|
|
545
|
-
* @returns {(string|Object)} Return string or instance of {@link https://github.com/ai/nanoid|nanoid}
|
|
507
|
+
* @param {string} text - Text to be formatted
|
|
508
|
+
* @param {...any} args - Argumennts
|
|
509
|
+
* @returns {string} Formatted text
|
|
546
510
|
*/
|
|
547
|
-
generateId = (options = {}) => {
|
|
548
|
-
let type
|
|
549
|
-
if (options === true) options = 'alpha'
|
|
550
|
-
if (options === 'int') {
|
|
551
|
-
type = options
|
|
552
|
-
options = { pattern: '0123456789', length: 15 }
|
|
553
|
-
} else if (options === 'alpha') {
|
|
554
|
-
type = options
|
|
555
|
-
options = { pattern: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', length: 15 }
|
|
556
|
-
}
|
|
557
|
-
let { pattern, length = 13, returnInstance } = options
|
|
558
|
-
pattern = pattern ?? 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
559
|
-
if (options.case === 'lower') pattern = pattern.toLowerCase()
|
|
560
|
-
else if (options.case === 'upper') pattern = pattern.toUpperCase()
|
|
561
|
-
const nid = customAlphabet(pattern, length)
|
|
562
|
-
if (returnInstance) return nid
|
|
563
|
-
const value = nid()
|
|
564
|
-
return type === 'int' ? parseInt(value) : value
|
|
565
|
-
}
|
|
566
511
|
|
|
567
512
|
/**
|
|
568
513
|
* Get NPM global module directory
|
|
@@ -607,26 +552,6 @@ class Bajo extends Plugin {
|
|
|
607
552
|
if (thrown) throw this.error('cantFindMethod%s', name)
|
|
608
553
|
}
|
|
609
554
|
|
|
610
|
-
/**
|
|
611
|
-
* Find item deep in paths
|
|
612
|
-
*
|
|
613
|
-
* @method
|
|
614
|
-
* @param {string} item - Item to find
|
|
615
|
-
* @param {Array} paths - Array of path to look for
|
|
616
|
-
* @returns {string}
|
|
617
|
-
*/
|
|
618
|
-
findDeep = (item, paths) => {
|
|
619
|
-
let dir
|
|
620
|
-
for (const p of paths) {
|
|
621
|
-
const d = `${p}/${item}`
|
|
622
|
-
if (fs.existsSync(d)) {
|
|
623
|
-
dir = d
|
|
624
|
-
break
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
return dir
|
|
628
|
-
}
|
|
629
|
-
|
|
630
555
|
/**
|
|
631
556
|
* Get module directory, locally and globally
|
|
632
557
|
*
|
|
@@ -636,6 +561,7 @@ class Bajo extends Plugin {
|
|
|
636
561
|
* @returns {string} Return absolute package directory
|
|
637
562
|
*/
|
|
638
563
|
getModuleDir = (pkgName, base) => {
|
|
564
|
+
const { findDeep } = this.app.lib
|
|
639
565
|
if (pkgName === 'main') return resolvePath(this.app.dir)
|
|
640
566
|
if (base === 'main') base = this.app.dir
|
|
641
567
|
else if (this && this.app && this.app[base]) base = this.app[base].pkgName
|
|
@@ -644,8 +570,8 @@ class Bajo extends Plugin {
|
|
|
644
570
|
const gdir = this.getGlobalModuleDir()
|
|
645
571
|
paths.unshift(gdir)
|
|
646
572
|
paths.unshift(resolvePath(path.join(this.app.dir, 'node_modules')))
|
|
647
|
-
let dir =
|
|
648
|
-
if (base && !dir) dir =
|
|
573
|
+
let dir = findDeep(pkgPath, paths)
|
|
574
|
+
if (base && !dir) dir = findDeep(`${base}/node_modules/${pkgPath}`, paths)
|
|
649
575
|
if (!dir) return null
|
|
650
576
|
return resolvePath(path.dirname(dir))
|
|
651
577
|
}
|
|
@@ -670,6 +596,7 @@ class Bajo extends Plugin {
|
|
|
670
596
|
*
|
|
671
597
|
* - local/absolute file
|
|
672
598
|
* - TNsPath (```myPlugin:/path/to/file.txt```)
|
|
599
|
+
* - file under node_modules, e.g. ```myPlugin:node_modules/some-package/file.txt```
|
|
673
600
|
*
|
|
674
601
|
* @method
|
|
675
602
|
* @param {string} file - File path, see above for supported types
|
|
@@ -683,6 +610,10 @@ class Bajo extends Plugin {
|
|
|
683
610
|
const { ns, path } = this.breakNsPath(file)
|
|
684
611
|
if (ns !== 'file' && this && this.app && this.app[ns] && ns.length > 1) {
|
|
685
612
|
file = `${this.app[ns].dir.pkg}${path}`
|
|
613
|
+
if (path.startsWith('node_modules/')) {
|
|
614
|
+
file = `${this.app[ns].dir.pkg}/${path}`
|
|
615
|
+
if (!fs.existsSync(file)) file = `${this.app[ns].dir.pkg}/../${path.slice('node_modules/'.length)}`
|
|
616
|
+
}
|
|
686
617
|
}
|
|
687
618
|
}
|
|
688
619
|
return file
|
|
@@ -787,7 +718,7 @@ class Bajo extends Plugin {
|
|
|
787
718
|
}
|
|
788
719
|
result[name] = mod
|
|
789
720
|
}
|
|
790
|
-
if (notFound.length > 0) throw this.error('cantFind%s', this.join(notFound))
|
|
721
|
+
if (notFound.length > 0 && opts.throwNotFound) throw this.error('cantFind%s', this.join(notFound))
|
|
791
722
|
if (opts.asObject) return result
|
|
792
723
|
if (pkgs.length === 1) return result[keys(result)[0]]
|
|
793
724
|
return values(result)
|
|
@@ -899,114 +830,6 @@ class Bajo extends Plugin {
|
|
|
899
830
|
return `${num[0]}${isEmpty(unit) ? defUnit : unit[0]}`
|
|
900
831
|
}
|
|
901
832
|
|
|
902
|
-
/**
|
|
903
|
-
* Parse duration to its millisecond value. Use {@link https://github.com/vercel/ms|ms} under the hood
|
|
904
|
-
*
|
|
905
|
-
* @method
|
|
906
|
-
* @param {(number|string)} dur - If string is given, parse this to its millisecond value. Otherwise returns as is
|
|
907
|
-
* @returns {number}
|
|
908
|
-
* @see {@link https://github.com/vercel/ms|ms}
|
|
909
|
-
*/
|
|
910
|
-
parseDur = (dur) => {
|
|
911
|
-
return isNumber(dur) ? dur : ms(dur)
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/**
|
|
915
|
-
* Parse datetime string as Javascript date object. Please visit {@link https://day.js.org|dayjs} for valid formats and more infos
|
|
916
|
-
*
|
|
917
|
-
* @method
|
|
918
|
-
* @param {string} dt - Datetime string
|
|
919
|
-
* @returns {Object} Javascript date object
|
|
920
|
-
* @see {@link https://day.js.org|dayjs}
|
|
921
|
-
*/
|
|
922
|
-
parseDt = (dt) => {
|
|
923
|
-
const value = this.app.lib.dayjs(dt)
|
|
924
|
-
if (!value.isValid()) throw this.error('dtUnparsable%s', dt)
|
|
925
|
-
return value.toDate()
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
/**
|
|
929
|
-
* Parse an object and optionally normalize its values recursively. Use {@link https://github.com/ladjs/dotenv-parse-variables}
|
|
930
|
-
* to parse values, so please have a visit to know how it works
|
|
931
|
-
*
|
|
932
|
-
* If ```options.parseValue``` is ```true```, any key ends with ```Dur``` and ```Dt``` will
|
|
933
|
-
* also be parsed as millisecond and Javascript date time accordingly.
|
|
934
|
-
*
|
|
935
|
-
* @method
|
|
936
|
-
* @param {(Object|string)} input - If string is given, parse it first using JSON.parse
|
|
937
|
-
* @param {Object} [options={}] - Options
|
|
938
|
-
* @param {boolean} [options.silent=true] - If ```true``` (default), exception are not thrown and silently ignored
|
|
939
|
-
* @param {boolean} [options.parseValue=false] - If ```true```, values will be parsed & normalized
|
|
940
|
-
* @param {string} [options.lang] - If provided, use this language instead of the one in config
|
|
941
|
-
* @returns {Object}
|
|
942
|
-
* @see {@link https://github.com/ladjs/dotenv-parse-variables}
|
|
943
|
-
*/
|
|
944
|
-
parseObject = (input, options = {}) => {
|
|
945
|
-
const { silent = true, parseValue = false, lang, ns } = options
|
|
946
|
-
const { isSet } = this.app.lib.aneka
|
|
947
|
-
const translate = (item) => {
|
|
948
|
-
const scope = ns ? this.app[ns] : this
|
|
949
|
-
const [text, ...args] = item.split('|')
|
|
950
|
-
return scope.t(text, ...args, { lang })
|
|
951
|
-
}
|
|
952
|
-
const statics = ['*']
|
|
953
|
-
if (isString(input)) {
|
|
954
|
-
try {
|
|
955
|
-
input = JSON.parse(input)
|
|
956
|
-
} catch (err) {
|
|
957
|
-
if (silent) input = {}
|
|
958
|
-
else throw err
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
let obj = cloneDeep(input)
|
|
962
|
-
const keys = Object.keys(obj)
|
|
963
|
-
const mutated = []
|
|
964
|
-
keys.forEach(k => {
|
|
965
|
-
let v = obj[k]
|
|
966
|
-
if (isPlainObject(v)) obj[k] = this.parseObject(v, options)
|
|
967
|
-
else if (isArray(v)) {
|
|
968
|
-
v.forEach((i, idx) => {
|
|
969
|
-
if (isPlainObject(i)) obj[k][idx] = this.parseObject(i, options)
|
|
970
|
-
else if (statics.includes(i)) obj[k][idx] = i
|
|
971
|
-
else if (parseValue) obj[k][idx] = dotenvParseVariables(set({}, 'item', obj[k][idx]), { assignToProcessEnv: false }).item
|
|
972
|
-
if (isArray(obj[k][idx])) obj[k][idx] = obj[k][idx].map(item => typeof item === 'string' ? item.trim() : item)
|
|
973
|
-
})
|
|
974
|
-
} else if (isSet(v)) {
|
|
975
|
-
if (isString(v) && v.startsWith('t:') && lang) v = translate(v.slice(2))
|
|
976
|
-
try {
|
|
977
|
-
if (statics.includes(v)) obj[k] = v
|
|
978
|
-
else if (k.startsWith('t:') && isString(v)) {
|
|
979
|
-
const newK = k.slice(2)
|
|
980
|
-
if (lang) obj[newK] = translate(v)
|
|
981
|
-
else obj[newK] = v
|
|
982
|
-
mutated.push(k)
|
|
983
|
-
} else if (parseValue) {
|
|
984
|
-
obj[k] = dotenvParseVariables(set({}, 'item', v), { assignToProcessEnv: false }).item
|
|
985
|
-
if (isArray(obj[k])) obj[k] = obj[k].map(item => typeof item === 'string' ? item.trim() : item)
|
|
986
|
-
}
|
|
987
|
-
if (k.slice(-3) === 'Dur') obj[k] = this.parseDur(v)
|
|
988
|
-
if (k.slice(-2) === 'Dt') obj[k] = this.parseDt(v)
|
|
989
|
-
} catch (err) {
|
|
990
|
-
obj[k] = undefined
|
|
991
|
-
if (!silent) throw err
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
})
|
|
995
|
-
if (mutated.length > 0) obj = omit(obj, mutated)
|
|
996
|
-
return obj
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
pick = (obj, items, excludeUnset) => {
|
|
1000
|
-
const { isSet } = this.app.lib.aneka
|
|
1001
|
-
const result = {}
|
|
1002
|
-
for (const item of items) {
|
|
1003
|
-
const [k, nk] = item.split(':')
|
|
1004
|
-
if (excludeUnset && !isSet(obj[k])) continue
|
|
1005
|
-
result[nk ?? k] = obj[k]
|
|
1006
|
-
}
|
|
1007
|
-
return result
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
833
|
/**
|
|
1011
834
|
* Read and parse file as config object. Supported types: ```.js``` and ```.json```.
|
|
1012
835
|
* More supports can be added using plugin. {@link https://github.com/ardhi/bajo-config|bajo-config} gives you additional supports for ```.yml```, ```.yaml``` and ```.toml``` file
|
|
@@ -1026,6 +849,7 @@ class Bajo extends Plugin {
|
|
|
1026
849
|
* @returns {Object}
|
|
1027
850
|
*/
|
|
1028
851
|
readConfig = async (file, { ns, pattern, globOptions = {}, ignoreError, defValue = {}, opts = {} } = {}) => {
|
|
852
|
+
const { parseObject } = this.app.lib
|
|
1029
853
|
if (!ns) ns = this.ns
|
|
1030
854
|
file = resolvePath(this.getPluginFile(file))
|
|
1031
855
|
let ext = path.extname(file)
|
|
@@ -1033,22 +857,22 @@ class Bajo extends Plugin {
|
|
|
1033
857
|
ext = ext.toLowerCase()
|
|
1034
858
|
if (ext === '.js') {
|
|
1035
859
|
const { readHandler } = find(this.app.configHandlers, { ext })
|
|
1036
|
-
return
|
|
860
|
+
return parseObject(await readHandler.call(this.app[ns], file, opts))
|
|
1037
861
|
}
|
|
1038
862
|
if (ext === '.json') return await this.fromJson(file, null)
|
|
1039
863
|
if (!['', '.*'].includes(ext)) {
|
|
1040
864
|
const item = find(this.app.configHandlers, { ext })
|
|
1041
865
|
if (!item) {
|
|
1042
866
|
if (!ignoreError) throw this.error('cantParse%s', file, { code: 'BAJO_CONFIG_NO_PARSER' })
|
|
1043
|
-
return
|
|
867
|
+
return parseObject(defValue)
|
|
1044
868
|
}
|
|
1045
|
-
return
|
|
869
|
+
return parseObject(await item.readHandler.call(this.app[ns], file, opts))
|
|
1046
870
|
}
|
|
1047
871
|
const item = pattern ?? `${fname}.{${map(map(this.app.configHandlers, 'ext'), k => k.slice(1)).join(',')}}`
|
|
1048
872
|
const files = await fastGlob(item, globOptions)
|
|
1049
873
|
if (files.length === 0) {
|
|
1050
874
|
if (!ignoreError) throw this.error('noConfigFileFound', { code: 'BAJO_CONFIG_FILE_NOT_FOUND' })
|
|
1051
|
-
return
|
|
875
|
+
return parseObject(defValue)
|
|
1052
876
|
}
|
|
1053
877
|
let config = defValue
|
|
1054
878
|
for (const f of files) {
|
|
@@ -1061,7 +885,7 @@ class Bajo extends Plugin {
|
|
|
1061
885
|
config = await item.readHandler.call(this.app[ns], f, null, opts)
|
|
1062
886
|
if (!isEmpty(config)) break
|
|
1063
887
|
}
|
|
1064
|
-
return
|
|
888
|
+
return parseObject(config)
|
|
1065
889
|
}
|
|
1066
890
|
|
|
1067
891
|
/**
|
|
@@ -1073,6 +897,7 @@ class Bajo extends Plugin {
|
|
|
1073
897
|
* @returns {Object}
|
|
1074
898
|
*/
|
|
1075
899
|
readJson = (file, thrownNotFound = false) => {
|
|
900
|
+
const { parseObject } = this.app.lib
|
|
1076
901
|
if (isPlainObject(thrownNotFound)) thrownNotFound = false
|
|
1077
902
|
if (!fs.existsSync(file) && thrownNotFound) throw this.error('notFound%s%s', this.t('file'), file)
|
|
1078
903
|
let resp
|
|
@@ -1080,7 +905,7 @@ class Bajo extends Plugin {
|
|
|
1080
905
|
resp = fs.readFileSync(file, 'utf8')
|
|
1081
906
|
} catch (err) {}
|
|
1082
907
|
if (isEmpty(resp)) return resp
|
|
1083
|
-
return
|
|
908
|
+
return parseObject(JSON.parse(resp))
|
|
1084
909
|
}
|
|
1085
910
|
|
|
1086
911
|
fromJson (file, isContent) {
|
|
@@ -1130,8 +955,15 @@ class Bajo extends Plugin {
|
|
|
1130
955
|
* @returns {Array} Array of hook execution results
|
|
1131
956
|
*/
|
|
1132
957
|
runHook = async (hookName, ...args) => {
|
|
1133
|
-
|
|
1134
|
-
let
|
|
958
|
+
let ns
|
|
959
|
+
let path
|
|
960
|
+
let subNs
|
|
961
|
+
try {
|
|
962
|
+
({ ns, subNs, path } = this.breakNsPath(hookName ?? ''))
|
|
963
|
+
} catch (err) {
|
|
964
|
+
return
|
|
965
|
+
}
|
|
966
|
+
let fns = filter(this.app.bajo.hooks, { ns, subNs, path })
|
|
1135
967
|
if (isEmpty(fns)) return []
|
|
1136
968
|
fns = orderBy(fns, ['level'])
|
|
1137
969
|
const results = []
|
package/class/base.js
CHANGED
|
@@ -8,23 +8,25 @@ import Plugin from './plugin.js'
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
class Base extends Plugin {
|
|
11
|
-
/**
|
|
12
|
-
* Dependencies to other plugins. Enter all plugin's package name your plugin dependent from.
|
|
13
|
-
*
|
|
14
|
-
* Semver is also supported.
|
|
15
|
-
*
|
|
16
|
-
* @constant {string[]}
|
|
17
|
-
* @memberof Base
|
|
18
|
-
*/
|
|
19
|
-
static dependencies = []
|
|
20
|
-
|
|
21
11
|
/**
|
|
22
12
|
* @param {string} pkgName - Package name (the one you use in package.json)
|
|
23
13
|
* @param {Object} app - App instance reference. Usefull to call app method inside a plugin
|
|
24
14
|
*/
|
|
25
15
|
constructor (pkgName, app) {
|
|
26
16
|
super(pkgName, app)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Dependencies to other plugins. Enter all plugin's package name your plugin dependent from.
|
|
20
|
+
*
|
|
21
|
+
* Semver is also supported.
|
|
22
|
+
*
|
|
23
|
+
* @constant {string[]}
|
|
24
|
+
* @memberof Base
|
|
25
|
+
*/
|
|
26
|
+
this.dependencies = []
|
|
27
|
+
|
|
27
28
|
this.state = {}
|
|
29
|
+
this.pkg = {}
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -36,27 +38,19 @@ class Base extends Plugin {
|
|
|
36
38
|
*/
|
|
37
39
|
loadConfig = async () => {
|
|
38
40
|
const { defaultsDeep } = this.app.lib.aneka
|
|
39
|
-
const { get,
|
|
40
|
-
const { log,
|
|
41
|
+
const { get, keys, pick } = this.app.lib._
|
|
42
|
+
const { log, getModuleDir, readAllConfigs } = this.app.bajo
|
|
43
|
+
const { parseObject } = this.app.lib
|
|
44
|
+
|
|
41
45
|
const defKeys = keys(this.config)
|
|
42
46
|
log.trace('- %s', this.ns)
|
|
43
47
|
const dir = this.ns === this.app.mainNs ? (`${this.app.bajo.dir.base}/${this.app.mainNs}`) : getModuleDir(this.pkgName)
|
|
44
48
|
let cfg = await readAllConfigs(`${dir}/config`)
|
|
45
|
-
this.constructor.alias = this.alias ?? (this.pkgName.slice(0, 5) === 'bajo-' ? this.pkgName.slice(5).toLowerCase() : this.ns.toLowerCase())
|
|
46
|
-
this.constructor.alias = kebabCase(this.alias)
|
|
47
49
|
|
|
48
50
|
this.dir = {
|
|
49
51
|
pkg: dir,
|
|
50
52
|
data: `${this.app.bajo.dir.data}/plugins/${this.ns}`
|
|
51
53
|
}
|
|
52
|
-
const file = `${dir + (this.ns === this.app.mainNs ? '/..' : '')}/package.json`
|
|
53
|
-
const pkgJson = await readJson(file)
|
|
54
|
-
this.pkg = pick(pkgJson,
|
|
55
|
-
['name', 'version', 'description', 'author', 'license', 'homepage'])
|
|
56
|
-
if (this.ns === this.app.mainNs) {
|
|
57
|
-
this.constructor.alias = this.app.mainNs
|
|
58
|
-
this.title = this.title ?? this.alias
|
|
59
|
-
}
|
|
60
54
|
// merge with config from datadir
|
|
61
55
|
try {
|
|
62
56
|
const altCfg = await readAllConfigs(`${this.app.bajo.dir.data}/config/${this.ns}`)
|
|
@@ -100,6 +94,15 @@ class Base extends Plugin {
|
|
|
100
94
|
* @async
|
|
101
95
|
*/
|
|
102
96
|
exit = async () => {
|
|
97
|
+
this.dispose()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Dispose internal references
|
|
102
|
+
*/
|
|
103
|
+
dispose = () => {
|
|
104
|
+
super.dispose()
|
|
105
|
+
this.state = null
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
|