bajo 2.0.2 → 2.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.
Files changed (99) hide show
  1. package/.github/FUNDING.yml +0 -0
  2. package/.github/workflows/repo-lockdown.yml +0 -0
  3. package/.jsdoc.conf.json +0 -0
  4. package/.mocharc.json +4 -0
  5. package/LICENSE +0 -0
  6. package/README.md +0 -0
  7. package/class/{misc → app}/log.js +73 -24
  8. package/class/app.js +65 -50
  9. package/class/bajo.js +43 -211
  10. package/class/base.js +25 -22
  11. package/class/helper/bajo.js +67 -60
  12. package/class/helper/base.js +34 -75
  13. package/class/{misc → plugin}/err.js +23 -18
  14. package/class/{misc → plugin}/print.js +7 -16
  15. package/class/plugin/tools.js +42 -0
  16. package/class/plugin.js +58 -54
  17. package/docs/App.html +0 -0
  18. package/docs/Bajo.html +0 -0
  19. package/docs/Base.html +0 -0
  20. package/docs/Err.html +0 -0
  21. package/docs/Log.html +0 -0
  22. package/docs/Plugin.html +0 -0
  23. package/docs/Print.html +0 -0
  24. package/docs/class_app.js.html +0 -0
  25. package/docs/class_bajo.js.html +0 -0
  26. package/docs/class_base.js.html +0 -0
  27. package/docs/class_helper_bajo.js.html +0 -0
  28. package/docs/class_helper_base.js.html +0 -0
  29. package/docs/class_misc_err.js.html +0 -0
  30. package/docs/class_misc_log.js.html +0 -0
  31. package/docs/class_misc_print.js.html +0 -0
  32. package/docs/class_plugin.js.html +0 -0
  33. package/docs/data/search.json +0 -0
  34. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  35. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  36. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  37. package/docs/global.html +0 -0
  38. package/docs/index.html +0 -0
  39. package/docs/index.js.html +0 -0
  40. package/docs/lib_current-loc.js.html +0 -0
  41. package/docs/lib_formats.js.html +0 -0
  42. package/docs/lib_import-module.js.html +0 -0
  43. package/docs/lib_log-levels.js.html +0 -0
  44. package/docs/lib_parse-args-argv.js.html +0 -0
  45. package/docs/lib_parse-env.js.html +0 -0
  46. package/docs/lib_resolve-path.js.html +0 -0
  47. package/docs/lib_shim.js.html +0 -0
  48. package/docs/module-Helper_Bajo.html +0 -0
  49. package/docs/module-Helper_Base.html +0 -0
  50. package/docs/module-Lib.html +0 -0
  51. package/docs/scripts/core.js +476 -477
  52. package/docs/scripts/core.min.js +0 -0
  53. package/docs/scripts/resize.js +36 -36
  54. package/docs/scripts/search.js +105 -105
  55. package/docs/scripts/search.min.js +0 -0
  56. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -0
  57. package/docs/scripts/third-party/fuse.js +1 -1
  58. package/docs/scripts/third-party/hljs-line-num-original.js +282 -285
  59. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  60. package/docs/scripts/third-party/hljs-original.js +1195 -1202
  61. package/docs/scripts/third-party/hljs.js +1 -1
  62. package/docs/scripts/third-party/popper.js +1 -1
  63. package/docs/scripts/third-party/tippy.js +1 -1
  64. package/docs/scripts/third-party/tocbot.js +508 -509
  65. package/docs/scripts/third-party/tocbot.min.js +0 -0
  66. package/docs/static/bitcoin.jpeg +0 -0
  67. package/docs/static/home.md +0 -0
  68. package/docs/static/logo-ecosystem.png +0 -0
  69. package/docs/static/logo.png +0 -0
  70. package/docs/styles/clean-jsdoc-theme-base.css +0 -0
  71. package/docs/styles/clean-jsdoc-theme-dark.css +0 -0
  72. package/docs/styles/clean-jsdoc-theme-light.css +0 -0
  73. package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -0
  74. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -0
  75. package/docs/styles/clean-jsdoc-theme.min.css +0 -0
  76. package/extend/bajo/intl/en-US.json +11 -5
  77. package/extend/bajo/intl/id.json +11 -5
  78. package/extend/waibuStatic/virtual.json +0 -0
  79. package/index.js +9 -1
  80. package/lib/find-deep.js +24 -0
  81. package/lib/formats.js +0 -0
  82. package/lib/freeze.js +16 -0
  83. package/lib/import-module.js +5 -3
  84. package/lib/index.js +6 -0
  85. package/lib/log-levels.js +0 -0
  86. package/package.json +5 -11
  87. package/test/base.test.js +108 -0
  88. package/wiki/CHANGES.md +63 -0
  89. package/wiki/CONFIG.md +7 -1
  90. package/wiki/CONTRIBUTING.md +0 -0
  91. package/wiki/DEV_GUIDE.md +0 -0
  92. package/wiki/ECOSYSTEM.md +0 -0
  93. package/wiki/GETTING-STARTED.md +1 -1
  94. package/wiki/USER-GUIDE.md +0 -0
  95. package/lib/current-loc.js +0 -33
  96. package/lib/parse-args-argv.js +0 -80
  97. package/lib/parse-env.js +0 -50
  98. package/lib/resolve-path.js +0 -24
  99. 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, isNumber,
36
- cloneDeep, isPlainObject, isArray, isString, set, omit, keys, indexOf,
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
- if (useBajo) pluginPkgs.unshift('bajo')
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.app.bajoSpatial) {
502
- const { latToDms, lngToDms } = this.app.lib.anekaSpatial
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
- * Generate unique random characters that can be used as ID. Use {@link https://github.com/ai/nanoid|nanoid} under the hood
505
+ * Format text according using sprintf with extra ability to run its arguments through a serie of modifiers
538
506
  *
539
- * @method
540
- * @param {(boolean|string|Object)} [options={}] - Options. If set to ```true``` or ```alpha```, it will generate alphaphet only characters. If set to ```int```, it will generate integer only characters. Otherwise:
541
- * @param {string} [options.pattern] - Character pattern to use. Defaults to all available alphanumeric characters
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 = this.findDeep(pkgPath, paths)
648
- if (base && !dir) dir = this.findDeep(`${base}/node_modules/${pkgPath}`, paths)
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 this.parseObject(await readHandler.call(this.app[ns], file, opts))
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 this.parseObject(defValue)
867
+ return parseObject(defValue)
1044
868
  }
1045
- return this.parseObject(await item.readHandler.call(this.app[ns], file, opts))
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 this.parseObject(defValue)
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 this.parseObject(config)
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 this.parseObject(JSON.parse(resp))
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
- const [ns, path] = (hookName ?? '').split(':')
1134
- let fns = filter(this.app.bajo.hooks, { ns, path })
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, kebabCase, keys, pick } = this.app.lib._
40
- const { log, readJson, parseObject, getModuleDir, readAllConfigs } = this.app.bajo
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