bajo 2.18.0 → 2.20.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 (74) hide show
  1. package/.github/workflows/test.yml +37 -0
  2. package/class/_helper.js +23 -7
  3. package/class/app.js +64 -47
  4. package/class/bajo.js +182 -138
  5. package/class/base.js +3 -3
  6. package/class/cache.js +60 -0
  7. package/class/err.js +14 -11
  8. package/class/log.js +41 -40
  9. package/class/plugin.js +35 -36
  10. package/class/print.js +54 -51
  11. package/class/tools.js +3 -4
  12. package/docs/App.html +7 -7
  13. package/docs/Bajo.html +2 -2
  14. package/docs/Base.html +1 -1
  15. package/docs/Cache.html +3 -0
  16. package/docs/Err.html +2 -2
  17. package/docs/Log.html +2 -2
  18. package/docs/Plugin.html +1 -1
  19. package/docs/Print.html +1 -1
  20. package/docs/Tools.html +3 -0
  21. package/docs/class__helper.js.html +694 -0
  22. package/docs/class_app.js.html +307 -149
  23. package/docs/class_bajo.js.html +316 -464
  24. package/docs/class_base.js.html +35 -32
  25. package/docs/class_cache.js.html +150 -0
  26. package/docs/class_err.js.html +144 -0
  27. package/docs/class_log.js.html +270 -0
  28. package/docs/class_plugin.js.html +98 -71
  29. package/docs/class_print.js.html +261 -0
  30. package/docs/class_tools.js.html +44 -0
  31. package/docs/data/search.json +1 -1
  32. package/docs/global.html +1 -4
  33. package/docs/index.html +1 -1
  34. package/docs/index.js.html +21 -14
  35. package/docs/lib_find-deep.js.html +27 -0
  36. package/docs/lib_formats.js.html +19 -19
  37. package/docs/lib_freeze.js.html +19 -0
  38. package/docs/lib_import-module.js.html +16 -14
  39. package/docs/lib_index.js.html +9 -0
  40. package/docs/lib_log-levels.js.html +2 -2
  41. package/docs/module-Helper.html +3 -0
  42. package/docs/module-Lib.html +3 -8
  43. package/docs/scripts/core.js +477 -476
  44. package/docs/scripts/resize.js +36 -36
  45. package/docs/scripts/search.js +105 -105
  46. package/docs/scripts/third-party/fuse.js +1 -1
  47. package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
  48. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  49. package/docs/scripts/third-party/hljs-original.js +1202 -1195
  50. package/docs/scripts/third-party/hljs.js +1 -1
  51. package/docs/scripts/third-party/popper.js +1 -1
  52. package/docs/scripts/third-party/tippy.js +1 -1
  53. package/docs/scripts/third-party/tocbot.js +509 -508
  54. package/index.js +8 -11
  55. package/lib/find-deep.js +3 -3
  56. package/lib/formats.js +17 -17
  57. package/lib/freeze.js +3 -3
  58. package/lib/import-module.js +8 -8
  59. package/package.json +3 -2
  60. package/test/app.test.js +183 -0
  61. package/test/bajo.test.js +125 -0
  62. package/test/base.test.js +74 -107
  63. package/test/cache.test.js +94 -0
  64. package/test/e2e.test.js +137 -0
  65. package/test/err.test.js +73 -0
  66. package/test/helper.test.js +39 -0
  67. package/test/import-module.test.js +138 -0
  68. package/test/integration.test.js +218 -0
  69. package/test/log.test.js +119 -0
  70. package/test/plugin.test.js +116 -0
  71. package/test/print.test.js +100 -0
  72. package/test/tools.test.js +38 -0
  73. package/wiki/CHANGES.md +12 -0
  74. package/.mocharc.json +0 -4
package/class/bajo.js CHANGED
@@ -35,6 +35,24 @@ const {
35
35
 
36
36
  const { resolvePath } = aneka
37
37
 
38
+ /**
39
+ * Name based ```{ns}:{path}``` format.
40
+ *
41
+ * @typedef {string} TNsPathPairs
42
+ * @see TNsPathResult
43
+ * @see Bajo#buildNsPath
44
+ * @see Bajo#breakNsPath
45
+ */
46
+
47
+ /**
48
+ * Object returned by {@link Bajo#getUnitFormat|bajo:getUnitFormat}.
49
+ *
50
+ * @typedef {Object} TBajoFormatResult
51
+ * @property {string} unitSys - Unit system.
52
+ * @property {Object} format - Format object.
53
+ * @see Bajo#getUnitFormat
54
+ */
55
+
38
56
  /**
39
57
  * The Core. The main engine. The one and only plugin that control app's boot process and
40
58
  * making sure all other plugins working nicely.
@@ -43,23 +61,24 @@ const { resolvePath } = aneka
43
61
  */
44
62
  class Bajo extends Plugin {
45
63
  /**
46
- * @param {App} app - App instance. Usefull to call app method inside a plugin
64
+ * @param {App} app - App instance. Usefull to call app method inside a plugin.
47
65
  */
48
66
  constructor (app) {
49
67
  super('bajo', app)
50
68
  this.alias = 'bajo'
51
69
  this.whiteSpace = [' ', '\t', '\n', '\r']
52
70
  /**
53
- * Config object
71
+ * Config object.
54
72
  *
55
73
  * @type {Object}
56
74
  * @see {@tutorial config}
57
75
  */
58
76
  this.config = {}
59
77
 
78
+ // by defaualt, only these config formats below are supported.
60
79
  app.configHandlers = [
61
- { ext: '.js', readHandler: this.fromJs },
62
- { ext: '.json', readHandler: this.fromJson, writeHandler: this.toJson }
80
+ { ns: 'bajo', ext: '.js', readHandler: this.fromJs },
81
+ { ns: 'bajo', ext: '.json', readHandler: this.fromJson, writeHandler: this.toJson }
63
82
  ]
64
83
 
65
84
  this.hooks = []
@@ -113,23 +132,15 @@ class Bajo extends Plugin {
113
132
  }
114
133
 
115
134
  /**
116
- * Name based ```{ns}:{path}``` format
117
- * @typedef {string} TNsPathPairs
118
- * @see TNsPathResult
119
- * @see Bajo#buildNsPath
120
- * @see Bajo#breakNsPath
121
- */
122
-
123
- /**
124
- * Build ns/path pairs
135
+ * Build ns/path pairs.
125
136
  *
126
137
  * @method
127
- * @param {object} [options={}] - Options object
128
- * @param {string} [options.ns=''] - Namespace
129
- * @param {string} [options.subNs] - Sub namespace
130
- * @param {string} [options.subSubNs] - Sub sub namespace
131
- * @param {string} [options.path] - Path
132
- * @returns {TNsPathPairs} - Ns/path pairs
138
+ * @param {object} [options={}] - Options object.
139
+ * @param {string} [options.ns=''] - Namespace.
140
+ * @param {string} [options.subNs] - Sub namespace.
141
+ * @param {string} [options.subSubNs] - Sub sub namespace.
142
+ * @param {string} [options.path] - Path.
143
+ * @returns {TNsPathPairs} Ns/path pairs.
133
144
  */
134
145
  buildNsPath = ({ ns = '', subNs, subSubNs, path } = {}) => {
135
146
  if (subNs) ns += '.' + subNs
@@ -138,21 +149,21 @@ class Bajo extends Plugin {
138
149
  }
139
150
 
140
151
  /**
141
- * Object returned by {@link Bajo#breakNsPath|bajo:breakNsPath}
152
+ * Object returned by {@link Bajo#breakNsPath|bajo:breakNsPath}.
142
153
  *
143
154
  * @typedef {Object} TNsPathResult
144
- * @property {string} ns - Namespace
145
- * @property {string} [subNs] - Sub namespace
146
- * @property {string} [subSubNs] - Sub of sub namespace
147
- * @property {string} path - Path without query string or hash
148
- * @property {string} fullPath - Full path, including query string and hash
155
+ * @property {string} ns - Namespace.
156
+ * @property {string} [subNs] - Sub namespace.
157
+ * @property {string} [subSubNs] - Sub of sub namespace.
158
+ * @property {string} path - Path without query string or hash.
159
+ * @property {string} fullPath - Full path, including query string and hash.
149
160
  * @see TNsPathPairs
150
161
  * @see Bajo#buildNsPath
151
162
  * @see Bajo#breakNsPath
152
163
  */
153
164
 
154
165
  /**
155
- * Break name to its namespace & path infos
166
+ * Break name to its namespace & path infos.
156
167
  *
157
168
  * @method
158
169
  * @param {(TNsPathPairs|string)} name - Name to break
@@ -209,12 +220,12 @@ class Bajo extends Plugin {
209
220
  *
210
221
  * @method
211
222
  * @async
212
- * @param {Object} options - Options
223
+ * @param {Object} options - Options.
213
224
  * @param {string} [options.ns] - Namespace. If not provided, defaults to ```bajo```
214
- * @param {function} [options.handler] - Handler to call while building the collection item
215
- * @param {string[]} [options.dupChecks=[]] - Array of keys to check for duplicates
216
- * @param {string} options.container - Key used as container name
217
- * @param {boolean} [options.useDefaultName=true] - If true (default) and ```name``` key is not provided, returned collection will be named ```default```
225
+ * @param {function} [options.handler] - Handler to call while building the collection item.
226
+ * @param {string[]} [options.dupChecks=[]] - Array of keys to check for duplicates.
227
+ * @param {string} options.container - Key used as container name.
228
+ * @param {boolean} [options.useDefaultName=true] - If true (default) and ```name``` key is not provided, returned collection will be named ```default```.
218
229
  * @fires bajo:beforeBuildCollection
219
230
  * @fires bajo:afterBuildCollection
220
231
  * @returns {Object[]} The collection
@@ -229,7 +240,7 @@ class Bajo extends Plugin {
229
240
  this.app[ns].log.trace('collecting%s', this.t(container))
230
241
 
231
242
  /**
232
- * Run before collection is built
243
+ * Run before collection is built.
233
244
  *
234
245
  * @global
235
246
  * @event bajo:beforeBuildCollection
@@ -291,9 +302,9 @@ class Bajo extends Plugin {
291
302
  *
292
303
  * @method
293
304
  * @async
294
- * @param {(TNsPathPairs|Object|function)} name - Method's name, function handler, plain object or plugin instance
295
- * @param {...any} [args] - One or more arguments passed as parameter to the handler
296
- * @returns {any} Returned value
305
+ * @param {(TNsPathPairs|Object|function)} name - Method's name, function handler, plain object or plugin instance.
306
+ * @param {...any} [args] - One or more arguments passed as parameter to the handler.
307
+ * @returns {any} Returned value.
297
308
  */
298
309
  callHandler = async (item, ...args) => {
299
310
  let result
@@ -332,13 +343,13 @@ class Bajo extends Plugin {
332
343
  *
333
344
  * @method
334
345
  * @async
335
- * @param {function} handler - Function handler. Can be an async function. Scoped to the running plugin
346
+ * @param {function} handler - Function handler. Can be an async function. Scoped to the running plugin.
336
347
  * @param {(string|Object)} [options={}] - Options. If a string is provided, it serves as the glob pattern, otherwise:
337
348
  * @param {(string|string[])} [options.glob] - Glob pattern. If provided,
338
- * @param {boolean} [options.useBajo=false] - If true, add ```bajo``` to the running plugins too
339
- * @param {string} [options.prefix=''] - Prepend glob pattern with prefix
340
- * @param {boolean} [options.noUnderscore=true] - If true (default), matched file with name starts with underscore is ignored
341
- * @param {any} [options.returnItems] - If true, each value of returned handler call will be saved as an object with running plugin name as its keys
349
+ * @param {boolean} [options.useBajo=false] - If true, add ```bajo``` to the running plugins too.
350
+ * @param {string} [options.prefix=''] - Prepend glob pattern with prefix.
351
+ * @param {boolean} [options.noUnderscore=true] - If true (default), matched file with name starts with underscore is ignored.
352
+ * @param {any} [options.returnItems] - If true, each value of returned handler call will be saved as an object with running plugin name as its keys.
342
353
  * @returns {any}
343
354
  */
344
355
  eachPlugins = async (handler, options = {}) => {
@@ -386,22 +397,13 @@ class Bajo extends Plugin {
386
397
  }
387
398
 
388
399
  /**
389
- * Object returned by {@link Bajo#getUnitFormat|bajo:getUnitFormat}
390
- *
391
- * @typedef {Object} TBajoFormatResult
392
- * @property {string} unitSys - Unit system
393
- * @property {Object} format - Format object
394
- * @see Bajo#getUnitFormat
395
- */
396
-
397
- /**
398
- * Get unit format
400
+ * Get unit format.
399
401
  *
400
402
  * @method
401
- * @param {Object} [options={}] - Options
402
- * @param {string} [options.lang] - Language to use. Defaults to the one you set in config
403
- * @param {string} [options.unitSys] - Unit system to use. Defaults to language's unit system or ```metric``` if unspecified
404
- * @returns {TBajoFormatResult} - Returned value
403
+ * @param {Object} [options={}] - Options.
404
+ * @param {string} [options.lang] - Language to use. Defaults to the one you set in config.
405
+ * @param {string} [options.unitSys] - Unit system to use. Defaults to language's unit system or ```metric``` if unspecified.
406
+ * @returns {TBajoFormatResult} Returned value.
405
407
  */
406
408
  getUnitFormat = (options = {}) => {
407
409
  const lang = options.lang ?? this.config.lang
@@ -411,16 +413,16 @@ class Bajo extends Plugin {
411
413
  }
412
414
 
413
415
  /**
414
- * Format value by type
416
+ * Format value by type.
415
417
  *
416
418
  * @method
417
- * @param {string} type - Format type. See {@link TBajoFormatType} for acceptable values
418
- * @param {any} value - Value to format
419
- * @param {string} [dataType] - Value's data type. See {@link TBajoDataType} for acceptable values
420
- * @param {Object} [options={}] - Options
421
- * @param {boolean} [options.withUnit=true] - Return with its unit appended
422
- * @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config
423
- * @returns {(Array|string)} Return string if ```withUnit``` is true. Otherwise is an array of ```[value, unit, separator]```
419
+ * @param {string} type - Format type. See {@link TBajoFormatType} for acceptable values.
420
+ * @param {any} value - Value to format.
421
+ * @param {string} [dataType] - Value's data type. See {@link TBajoDataType} for acceptable values.
422
+ * @param {Object} [options={}] - Options.
423
+ * @param {boolean} [options.withUnit=true] - Return with its unit appended.
424
+ * @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config.
425
+ * @returns {(Array|string)} Return string if ```withUnit``` is true. Otherwise is an array of ```[value, unit, separator]```.
424
426
  */
425
427
  formatByType = (type, value, dataType, options = {}) => {
426
428
  const { defaultsDeep } = this.app.lib.aneka
@@ -437,18 +439,18 @@ class Bajo extends Plugin {
437
439
  }
438
440
 
439
441
  /**
440
- * Format value
442
+ * Format value.
441
443
  *
442
444
  * @method
443
- * @param {any} value - Value to format
444
- * @param {string} [type] - Data type to use. See {@link TBajoDataType} for acceptable values. If not provided, return the untouched value
445
- * @param {Object} [options={}] - Options
446
- * @param {string} [options.emptyValue=''] - Empty value to use if function resulted empty. Defaults to the one from your config
447
- * @param {boolean} [options.withUnit=true] - Return with its unit appended
448
- * @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config
449
- * @param {string} [options.latitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as latitude in degree, minute, second
450
- * @param {string} [options.longitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as longitude in degree, minute, second
451
- * @returns {string} Formatted value
445
+ * @param {any} value - Value to format.
446
+ * @param {string} [type] - Data type to use. See {@link TBajoDataType} for acceptable values. If not provided, return the untouched value.
447
+ * @param {Object} [options={}] - Options.
448
+ * @param {string} [options.emptyValue=''] - Empty value to use if function resulted empty. Defaults to the one from your config.
449
+ * @param {boolean} [options.withUnit=true] - Return with its unit appended.
450
+ * @param {string} [options.lang] - Format value according to this language. Defaults to the one you set in config.
451
+ * @param {string} [options.latitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as latitude in degree, minute, second.
452
+ * @param {string} [options.longitude] - If Bajo Spatial is loaded and data type is a double or float, then format it as longitude in degree, minute, second.
453
+ * @returns {string} Formatted value.
452
454
  */
453
455
  format = (value, type, options = {}) => {
454
456
  const { defaultsDeep, isSet } = this.app.lib.aneka
@@ -498,19 +500,11 @@ class Bajo extends Plugin {
498
500
  }
499
501
 
500
502
  /**
501
- * Format text according using sprintf with extra ability to run its arguments through a serie of modifiers
502
- *
503
- * @param {string} text - Text to be formatted
504
- * @param {...any} args - Argumennts
505
- * @returns {string} Formatted text
506
- */
507
-
508
- /**
509
- * Get NPM global module directory
503
+ * Get NPM global module directory.
510
504
  *
511
505
  * @method
512
- * @param {string} [pkgName] - If provided, return this package global directory. Otherwise the npm global module directory
513
- * @param {boolean} [silent=true] - Set to ```false``` to throw exception in case of error. Otherwise silently returns undefined
506
+ * @param {string} [pkgName] - If provided, return this package global directory. Otherwise the npm global module directory.
507
+ * @param {boolean} [silent=true] - Set to ```false``` to throw exception in case of error. Otherwise silently returns undefined.
514
508
  * @returns {string}
515
509
  */
516
510
  getGlobalModuleDir = (pkgName, silent = true) => {
@@ -534,12 +528,12 @@ class Bajo extends Plugin {
534
528
  }
535
529
 
536
530
  /**
537
- * Get class method by name
531
+ * Get class method by name.
538
532
  *
539
533
  * @method
540
- * @param {string} name - Name in format ```ns:methodName```
541
- * @param {boolean} [thrown=true] - If ```true``` (default), throw exceptiom in case of error
542
- * @returns {function} Class method
534
+ * @param {string} name - Name in format ```ns:methodName```.
535
+ * @param {boolean} [thrown=true] - If ```true``` (default), throw exception in case of error.
536
+ * @returns {function} Class method.
543
537
  */
544
538
  getMethod = (name = '', thrown = true) => {
545
539
  const { ns, path } = this.breakNsPath(name, thrown)
@@ -549,12 +543,12 @@ class Bajo extends Plugin {
549
543
  }
550
544
 
551
545
  /**
552
- * Get module directory, locally and globally
546
+ * Get module directory, locally and globally.
553
547
  *
554
548
  * @method
555
- * @param {string} pkgName - Package name to find
556
- * @param {string} base - Provide base name if ```pkgName``` is a module under ```base```'s package name
557
- * @returns {string} Return absolute package directory
549
+ * @param {string} pkgName - Package name to find.
550
+ * @param {string} base - Provide base name if ```pkgName``` is a module under ```base```'s package name.
551
+ * @returns {string} Return absolute package directory.
558
552
  */
559
553
  getModuleDir = (pkgName, base) => {
560
554
  const { findDeep } = this.app.lib
@@ -609,8 +603,8 @@ class Bajo extends Plugin {
609
603
  *
610
604
  * @method
611
605
  * @async
612
- * @param {...TNsPathPairs} pkgs - One or more packages in format ```{ns}:{packageName}```
613
- * @returns {(Object|Array)} See above
606
+ * @param {...TNsPathPairs} pkgs - One or more packages in format ```{ns}:{packageName}```.
607
+ * @returns {(Object|Array)} See above.
614
608
  */
615
609
  importPkg = async (...pkgs) => {
616
610
  const { defaultsDeep } = this.app.lib.aneka
@@ -654,7 +648,7 @@ class Bajo extends Plugin {
654
648
  *
655
649
  * @method
656
650
  * @async
657
- * @param {(string|TNsPathPairs)} dir - Directory to check
651
+ * @param {(string|TNsPathPairs)} dir - Directory to check.
658
652
  * @param {function} filterFn - Filter function to filter out files that cause false positives.
659
653
  * @returns {boolean}
660
654
  */
@@ -665,10 +659,10 @@ class Bajo extends Plugin {
665
659
  }
666
660
 
667
661
  /**
668
- * Check whether log level is within log's app current level
662
+ * Check whether log level is within log's app current level.
669
663
  *
670
664
  * @method
671
- * @param {string} level - Level to check. See {@link TLogLevels} for more
665
+ * @param {string} level - Level to check. See {@link TLogLevels} for more.
672
666
  * @returns {boolean}
673
667
  */
674
668
  isLogInRange = (level) => {
@@ -692,11 +686,11 @@ class Bajo extends Plugin {
692
686
  }
693
687
 
694
688
  /**
695
- * Check whether directory is a valid Bajo app
689
+ * Check whether directory is a valid Bajo app.
696
690
  *
697
691
  * @method
698
- * @param {string} dir - Directory to check
699
- * @param {boolean} [returnPkg] - Set ```true``` to return its package.json content
692
+ * @param {string} dir - Directory to check.
693
+ * @param {boolean} [returnPkg] - Set ```true``` to return its package.json content.
700
694
  * @returns {(boolean|Object)}
701
695
  */
702
696
  isValidApp = (dir, returnPkg) => {
@@ -705,11 +699,11 @@ class Bajo extends Plugin {
705
699
  }
706
700
 
707
701
  /**
708
- * Check whether directory is a valid Bajo plugin
702
+ * Check whether directory is a valid Bajo plugin.
709
703
  *
710
704
  * @method
711
- * @param {string} dir - Directory to check
712
- * @param {boolean} [returnPkg] - Set ```true``` to return its package.json content
705
+ * @param {string} dir - Directory to check.
706
+ * @param {boolean} [returnPkg] - Set ```true``` to return its package.json content.
713
707
  * @returns {(boolean|Object)}
714
708
  */
715
709
  isValidPlugin = (dir, returnPkg) => {
@@ -722,9 +716,9 @@ class Bajo extends Plugin {
722
716
  *
723
717
  * @method
724
718
  * @param {any[]} array - Array to join
725
- * @param {(string|Object)} options - If provided and is a string, it will be used as separator
726
- * @param {string} [options.separator=', '] - Separator to use
727
- * @param {string} [options.lastSeparator=and] - Text to use as the last separator
719
+ * @param {(string|Object)} options - If provided and is a string, it will be used as separator.
720
+ * @param {string} [options.separator=', '] - Separator to use.
721
+ * @param {string} [options.lastSeparator=and] - Text to use as the last separator.
728
722
  * @returns {string}
729
723
  */
730
724
  join = (input = [], options = {}) => {
@@ -742,11 +736,11 @@ class Bajo extends Plugin {
742
736
  }
743
737
 
744
738
  /**
745
- * Return its numeric portion of a value
739
+ * Return its numeric portion of a value.
746
740
  *
747
741
  * @method
748
- * @param {string} [value=''] - Value to get its numeric portion
749
- * @param {string} [defUnit=''] - Default unit if value doesn't have one
742
+ * @param {string} [value=''] - Value to get its numeric portion.
743
+ * @param {string} [defUnit=''] - Default unit if value doesn't have one.
750
744
  * @returns {string}
751
745
  */
752
746
  numUnit = (value = '', defUnit = '') => {
@@ -757,20 +751,20 @@ class Bajo extends Plugin {
757
751
 
758
752
  /**
759
753
  * Read and parse file as config object. Supported types: ```.js``` and ```.json```.
760
- * 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
754
+ * 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.
761
755
  *
762
756
  * If file extension is ```.*```, it will be auto detected and parsed accordingly
763
757
  *
764
758
  * @method
765
759
  * @async
766
- * @param {string} file - File to read and parse
767
- * @param {Object} [options={}] - Options
768
- * @param {boolean} [options.ignoreError] - Any exception will be silently discarded
769
- * @param {string} [options.ns] - If given, use this as the scope
770
- * @param {string} [options.pattern] - If given and auto detection is on (extension is ```.*```), it will be used for instead the default one
771
- * @param {Object} [options.defValue={}] - Default value to use if value returned empty
772
- * @param {Object} [options.parserOpts={}] - Parser setting
773
- * @param {Object} [options.globOpts={}] - {@link https://github.com/mrmlnc/fast-glob|fast-glob} options
760
+ * @param {string} file - File to read and parse.
761
+ * @param {Object} [options={}] - Options.
762
+ * @param {boolean} [options.ignoreError] - Any exception will be silently discarded.
763
+ * @param {string} [options.ns] - If given, use this as the scope.
764
+ * @param {string} [options.pattern] - If given and auto detection is on (extension is ```.*```), it will be used for instead the default one.
765
+ * @param {Object} [options.defValue={}] - Default value to use if value returned empty.
766
+ * @param {Object} [options.parserOpts={}] - Parser setting.
767
+ * @param {Object} [options.globOpts={}] - {@link https://github.com/mrmlnc/fast-glob|fast-glob} options.
774
768
  * @returns {Object}
775
769
  */
776
770
  readConfig = async (file, options = {}) => {
@@ -849,20 +843,20 @@ class Bajo extends Plugin {
849
843
  let ext = path.extname(file)
850
844
  const fname = path.dirname(file) + '/' + path.basename(file, ext)
851
845
  ext = ext.toLowerCase()
852
- if (ext === '.js') {
853
- const { readHandler } = find(this.app.configHandlers, { ext })
854
- return await output(await readHandler.call(this.app[ns], file, parserOpts))
846
+ if (['.js', '.json'].includes(ext)) {
847
+ const item = find(this.app.configHandlers, { ext })
848
+ return await output(await item.readHandler.call(this.app[item.ns], file, parserOpts))
855
849
  }
856
- if (ext === '.json') return await output(await this.fromJson(file, parserOpts))
857
850
  if (!['', '.*'].includes(ext)) {
858
851
  const item = find(this.app.configHandlers, { ext })
859
852
  if (!item) {
860
853
  if (!ignoreError) throw this.error('cantParse%s', file, { code: 'BAJO_CONFIG_NO_PARSER' })
861
854
  return await output(defValue)
862
855
  }
863
- return await output(await item.readHandler.call(this.app[ns], file, parserOpts))
856
+ return await output(await item.readHandler.call(this.app[item.ns], file, parserOpts))
864
857
  }
865
- const item = pattern ?? `${fname}.{${map(map(this.app.configHandlers, 'ext'), k => k.slice(1)).join(',')}}`
858
+ const formats = this.app.getConfigFormats(true)
859
+ const item = pattern ?? `${fname}.{${formats.join(',')}}`
866
860
  const files = await fastGlob(item, globOpts ?? {})
867
861
  if (files.length === 0) {
868
862
  if (!ignoreError) throw this.error('noConfigFileFound', { code: 'BAJO_CONFIG_FILE_NOT_FOUND' })
@@ -876,18 +870,18 @@ class Bajo extends Plugin {
876
870
  if (!ignoreError) throw this.error('cantParse%s', f, { code: 'BAJO_CONFIG_NO_PARSER' })
877
871
  continue
878
872
  }
879
- config = await item.readHandler.call(this.app[ns], f, parserOpts)
873
+ config = await item.readHandler.call(this.app[item.ns], f, parserOpts)
880
874
  if (!isEmpty(config)) break
881
875
  }
882
876
  return await output(config)
883
877
  }
884
878
 
885
879
  /**
886
- * Read and parse json file
880
+ * Read and parse json file.
887
881
  *
888
882
  * @method
889
- * @param {string} file - File to read
890
- * @param {boolean} [thrownNotFound=false] - If ```true```, silently ignore if file is not found
883
+ * @param {string} file - File to read.
884
+ * @param {boolean} [thrownNotFound=false] - If ```true```, silently ignore if file is not found.
891
885
  * @returns {Object}
892
886
  */
893
887
  readJson = (file, thrownNotFound = false) => {
@@ -902,6 +896,15 @@ class Bajo extends Plugin {
902
896
  return parseObject(JSON.parse(resp))
903
897
  }
904
898
 
899
+ /**
900
+ * Read and parse JavaScript file.
901
+ *
902
+ * @async
903
+ * @method
904
+ * @param {string} file - File to read and parse.
905
+ * @param {Object} [options={}] - Options.
906
+ * @returns {Object} Parsed JavaScript object.
907
+ */
905
908
  async fromJs (file, options = {}) {
906
909
  const args = options.args ?? []
907
910
  let mod = await importModule(file)
@@ -909,11 +912,28 @@ class Bajo extends Plugin {
909
912
  return mod
910
913
  }
911
914
 
915
+ /**
916
+ * Read and parse JSON string or object.
917
+ *
918
+ * @param {string} data - Filename to load from or JSON string to parse.
919
+ * @param {Object} [options={}] - Options.
920
+ * @returns {Object} Parsed JSON object.
921
+ */
912
922
  fromJson (data, options = {}) {
913
923
  const content = options.readFromFile ? fs.readFileSync(data, 'utf8') : data
914
924
  return JSON.parse(content)
915
925
  }
916
926
 
927
+ /**
928
+ * Convert data to JSON string.
929
+ *
930
+ * @method
931
+ * @param {Object} data - Data to convert to JSON string.
932
+ * @param {Object} [options={}] - Options.
933
+ * @param {boolean} [options.writeToFile=false] - If true, write the JSON string to a file.
934
+ * @param {string} [options.saveAsFile] - The file path to save the JSON string if writeToFile is true.
935
+ * @returns {string} JSON string
936
+ */
917
937
  toJson = (data, options = {}) => {
918
938
  const content = JSON.stringify(data, null, omit(options, ['writeToFile']))
919
939
  if (options.writeToFile) {
@@ -924,12 +944,13 @@ class Bajo extends Plugin {
924
944
  }
925
945
 
926
946
  /**
927
- * Read all config files by path
947
+ * Read all config files from path.
928
948
  *
929
949
  * @method
930
950
  * @async
931
- * @param {string} path - Base path to start looking config files
932
- * @returns {Object}
951
+ * @param {string} path - Base path to start looking config files.
952
+ * @param {Object} [options={}] - Options.
953
+ * @returns {Object} Merged configuration object.
933
954
  */
934
955
  readAllConfigs = async (path, options) => {
935
956
  const { defaultsDeep } = this.app.lib.aneka
@@ -951,13 +972,13 @@ class Bajo extends Plugin {
951
972
  }
952
973
 
953
974
  /**
954
- * Run named hook/event
975
+ * Run named hook/event.
955
976
  *
956
977
  * @method
957
978
  * @async
958
- * @param {TNsPathPairs} hookName
959
- * @param {...any} [args] - Argument passed to the hook function
960
- * @returns {Array} Array of hook execution results
979
+ * @param {TNsPathPairs} hookName - Name of the hook to run.
980
+ * @param {...any} [args] - Argument passed to the hook function.
981
+ * @returns {Array} Array of hook execution results.
961
982
  */
962
983
  runHook = async (hookName, ...args) => {
963
984
  let fns = filter(this.hooks, { name: hookName })
@@ -988,10 +1009,10 @@ class Bajo extends Plugin {
988
1009
  *
989
1010
  * @method
990
1011
  * @async
991
- * @param {string} file - File name
992
- * @param {Object} item - Item to save
993
- * @param {boolean} [printSaved=true] - Print info on screen
994
- * @returns {string} Full file path
1012
+ * @param {string} file - File name.
1013
+ * @param {Object} item - Item to save.
1014
+ * @param {boolean} [printSaved=true] - Print info on screen.
1015
+ * @returns {string} Full file path.
995
1016
  */
996
1017
  saveAsDownload = async (file, item, printSaved = true) => {
997
1018
  const { print } = this.app.bajo
@@ -1002,6 +1023,29 @@ class Bajo extends Plugin {
1002
1023
  if (printSaved) print.succeed('savedAs%s', path.resolve(fname), { skipSilence: true })
1003
1024
  return fname
1004
1025
  }
1026
+
1027
+ /**
1028
+ * Read config using all registered config handlers. The first handler that returns a
1029
+ * valid object or array will be used.
1030
+ *
1031
+ * @param {string} input - The input string to be processed by the config handlers.
1032
+ * @param {string[]} [exts] - Optional array of extensions to filter the config handlers. If provided, only handlers with matching extensions will be used.
1033
+ * @param {object} [options={}] - Options to be passed to the config handlers.
1034
+ * @returns {Object|Array|null} The result from the first successful config handler, or null if none succeed.
1035
+ */
1036
+ readAsConfig = async (input, exts, options = {}) => {
1037
+ let result
1038
+ const handlers = exts ? this.app.configHandlers.filter(h => exts.includes(h.ext)) : this.app.configHandlers
1039
+ for (const handler of handlers) {
1040
+ if (result) break
1041
+ try {
1042
+ const resp = await handler.readHandler.call(this.app[handler.ns], input, options)
1043
+ if (isPlainObject(resp) || isArray(resp)) result = resp
1044
+ } catch (err) {
1045
+ }
1046
+ }
1047
+ return result
1048
+ }
1005
1049
  }
1006
1050
 
1007
1051
  export default Bajo
package/class/base.js CHANGED
@@ -9,8 +9,8 @@ import Plugin from './plugin.js'
9
9
 
10
10
  class Base extends Plugin {
11
11
  /**
12
- * @param {string} pkgName - Package name (the one you use in package.json)
13
- * @param {Object} app - App instance reference. Usefull to call app method inside a plugin
12
+ * @param {string} pkgName - Package name (the one you use in package.json).
13
+ * @param {Object} app - App instance reference. Useful to call app method inside a plugin.
14
14
  */
15
15
  constructor (pkgName, app) {
16
16
  super(pkgName, app)
@@ -98,7 +98,7 @@ class Base extends Plugin {
98
98
  }
99
99
 
100
100
  /**
101
- * Dispose internal references
101
+ * Dispose internal references.
102
102
  */
103
103
  dispose = async () => {
104
104
  await super.dispose()