bajo 2.17.0 → 2.19.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 (73) hide show
  1. package/class/_helper.js +22 -7
  2. package/class/app.js +148 -35
  3. package/class/bajo.js +156 -206
  4. package/class/base.js +3 -3
  5. package/class/cache.js +61 -2
  6. package/class/err.js +14 -11
  7. package/class/log.js +41 -40
  8. package/class/plugin.js +35 -36
  9. package/class/print.js +54 -51
  10. package/class/tools.js +3 -4
  11. package/docs/App.html +7 -7
  12. package/docs/Bajo.html +2 -2
  13. package/docs/Base.html +1 -1
  14. package/docs/Cache.html +3 -0
  15. package/docs/Err.html +2 -2
  16. package/docs/Log.html +2 -2
  17. package/docs/Plugin.html +1 -1
  18. package/docs/Print.html +1 -1
  19. package/docs/Tools.html +3 -0
  20. package/docs/class__helper.js.html +694 -0
  21. package/docs/class_app.js.html +307 -149
  22. package/docs/class_bajo.js.html +316 -464
  23. package/docs/class_base.js.html +35 -32
  24. package/docs/class_cache.js.html +150 -0
  25. package/docs/class_err.js.html +144 -0
  26. package/docs/class_log.js.html +270 -0
  27. package/docs/class_plugin.js.html +98 -71
  28. package/docs/class_print.js.html +261 -0
  29. package/docs/class_tools.js.html +44 -0
  30. package/docs/data/search.json +1 -1
  31. package/docs/global.html +1 -4
  32. package/docs/index.html +1 -1
  33. package/docs/index.js.html +21 -14
  34. package/docs/lib_find-deep.js.html +27 -0
  35. package/docs/lib_formats.js.html +19 -19
  36. package/docs/lib_freeze.js.html +19 -0
  37. package/docs/lib_import-module.js.html +16 -14
  38. package/docs/lib_index.js.html +9 -0
  39. package/docs/lib_log-levels.js.html +2 -2
  40. package/docs/module-Helper.html +3 -0
  41. package/docs/module-Lib.html +3 -8
  42. package/docs/scripts/core.js +477 -476
  43. package/docs/scripts/resize.js +36 -36
  44. package/docs/scripts/search.js +105 -105
  45. package/docs/scripts/third-party/fuse.js +1 -1
  46. package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
  47. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  48. package/docs/scripts/third-party/hljs-original.js +1202 -1195
  49. package/docs/scripts/third-party/hljs.js +1 -1
  50. package/docs/scripts/third-party/popper.js +1 -1
  51. package/docs/scripts/third-party/tippy.js +1 -1
  52. package/docs/scripts/third-party/tocbot.js +509 -508
  53. package/index.js +8 -11
  54. package/lib/find-deep.js +3 -3
  55. package/lib/formats.js +17 -17
  56. package/lib/freeze.js +3 -3
  57. package/lib/import-module.js +9 -9
  58. package/package.json +1 -1
  59. package/test/app.test.js +183 -0
  60. package/test/bajo.test.js +125 -0
  61. package/test/base.test.js +74 -107
  62. package/test/cache.test.js +94 -0
  63. package/test/e2e.test.js +137 -0
  64. package/test/err.test.js +73 -0
  65. package/test/helper.test.js +39 -0
  66. package/test/import-module.test.js +138 -0
  67. package/test/integration.test.js +218 -0
  68. package/test/log.test.js +119 -0
  69. package/test/plugin.test.js +116 -0
  70. package/test/print.test.js +100 -0
  71. package/test/tools.test.js +38 -0
  72. package/wiki/CHANGES.md +10 -0
  73. package/.mocharc.json +0 -4
package/class/_helper.js CHANGED
@@ -140,13 +140,13 @@ dayjs.extend(weekOfYear)
140
140
 
141
141
  /**
142
142
  * @typedef {Object} TAppLib
143
- * @property {Object} _ - Access to {@link https://lodash.com|lodash}
144
- * @property {Object} fs - Access to {@link https://github.com/jprichardson/node-fs-extra|fs-extra}
145
- * @property {Object} fastGlob - Access to {@link https://github.com/mrmlnc/fast-glob|fast-glob}
146
- * @property {Object} sprintf - Access to {@link https://github.com/alexei/sprintf.js|sprintf}
147
- * @property {Object} aneka - Access to {@link https://github.com/ardhi/aneka|aneka}
148
- * @property {Object} outmatch - Access to {@link https://github.com/axtgr/outmatch|outmatch}
149
- * @property {Object} dayjs - Access to {@link https://day.js.org|dayjs} with utc & customParseFormat plugin already applied
143
+ * @property {Object} _ Access to {@link https://lodash.com|lodash}.
144
+ * @property {Object} fs Access to {@link https://github.com/jprichardson/node-fs-extra|fs-extra}.
145
+ * @property {Object} fastGlob Access to {@link https://github.com/mrmlnc/fast-glob|fast-glob}.
146
+ * @property {Object} sprintf Access to {@link https://github.com/alexei/sprintf.js|sprintf}.
147
+ * @property {Object} aneka Access to {@link https://github.com/ardhi/aneka|aneka}.
148
+ * @property {Object} outmatch Access to {@link https://github.com/axtgr/outmatch|outmatch}.
149
+ * @property {Object} dayjs Access to {@link https://day.js.org|dayjs} with utc & customParseFormat plugin already applied.
150
150
  * @property {Object} freeze
151
151
  * @property {Object} findDeep
152
152
  * @see App
@@ -173,6 +173,8 @@ export const lib = {
173
173
  * - read the list of plugins from ```.plugins``` file
174
174
  *
175
175
  * @async
176
+ * @method
177
+ * @memberof module:Helper
176
178
  */
177
179
  export async function buildBaseConfig () {
178
180
  // dirs
@@ -214,6 +216,7 @@ export async function buildBaseConfig () {
214
216
  * - attach these plugins to the app instance
215
217
  *
216
218
  * @async
219
+ * @memberof module:Helper
217
220
  */
218
221
  export async function buildPlugins () {
219
222
  const { resolvePath } = this.app.lib.aneka
@@ -247,6 +250,7 @@ export async function buildPlugins () {
247
250
  * Collect all config handlers, including the one provided by plugins
248
251
  *
249
252
  * @async
253
+ * @memberof module:Helper
250
254
  */
251
255
  export async function collectConfigHandlers () {
252
256
  for (const pkg of this.app.pluginPkgs) {
@@ -271,6 +275,7 @@ export async function collectConfigHandlers () {
271
275
  * - Set environment (```dev``` or ```prod```)
272
276
  *
273
277
  * @async
278
+ * @memberof module:Helper
274
279
  */
275
280
  export async function buildExtConfig () {
276
281
  // config merging
@@ -321,6 +326,7 @@ export async function buildExtConfig () {
321
326
  * Setup plugins boot orders by reading plugin's ```.bootorder``` file if provided.
322
327
  *
323
328
  * @async
329
+ * @memberof module:Helper
324
330
  */
325
331
  export async function bootOrder () {
326
332
  const { freeze } = this.app.lib
@@ -349,6 +355,7 @@ export async function bootOrder () {
349
355
  * Build configurations
350
356
  *
351
357
  * @async
358
+ * @memberof module:Helper
352
359
  */
353
360
  export async function buildConfigs () {
354
361
  this.bajo.log.debug('readConfigs')
@@ -363,6 +370,7 @@ export async function buildConfigs () {
363
370
  * Ensure for names and aliases to be unique and no clashes with other plugins
364
371
  *
365
372
  * @async
373
+ * @memberof module:Helper
366
374
  */
367
375
  export async function checkNameAliases () {
368
376
  this.bajo.log.debug('checkAliasNameClash')
@@ -382,6 +390,7 @@ export async function checkNameAliases () {
382
390
  * Ensure dependencies are met
383
391
  *
384
392
  * @async
393
+ * @memberof module:Helper
385
394
  */
386
395
  export async function checkDependencies () {
387
396
  const { join } = this.bajo
@@ -417,6 +426,7 @@ export async function checkDependencies () {
417
426
  * Collect and build hooks and push them to the bajo's hook system
418
427
  *
419
428
  * @async
429
+ * @memberof module:Helper
420
430
  * @fires bajo:afterCollectHooks
421
431
  */
422
432
  export async function collectHooks () {
@@ -482,6 +492,7 @@ export async function collectHooks () {
482
492
  * @fires {ns}:before{method}
483
493
  * @fires {ns}:after{method}
484
494
  * @fires bajo:afterAll{method}
495
+ * @memberof module:Helper
485
496
  */
486
497
  export async function run () {
487
498
  const me = this
@@ -552,6 +563,7 @@ export async function run () {
552
563
  * 5. {@link module:Helper/Base.run|run plugins}
553
564
  *
554
565
  * @async
566
+ * @memberof module:Helper
555
567
  */
556
568
  export async function bootPlugins () {
557
569
  await buildConfigs.call(this.app)
@@ -565,6 +577,7 @@ export async function bootPlugins () {
565
577
  * Attach plugins exit handlers and make sure the app shutdowns gracefully
566
578
  *
567
579
  * @async
580
+ * @memberof module:Helper
568
581
  */
569
582
  export async function exitHandler () {
570
583
  if (!this.config.exitHandler) return
@@ -629,6 +642,7 @@ export async function exitHandler () {
629
642
  * @async
630
643
  * @fires {ns}:beforeAppletRun
631
644
  * @fires {ns}:afterAppletRun
645
+ * @memberof module:Helper
632
646
  */
633
647
  export async function runAsApplet () {
634
648
  const { isString, map, find } = this.app.lib._
@@ -671,6 +685,7 @@ export async function runAsApplet () {
671
685
  * @param {...any} params
672
686
  * @see {@tutorial hook}
673
687
  * @see module:Helper/Bajo.runAsApplet
688
+ * @memberof module:Helper
674
689
  */
675
690
  await this.runHook(`${applet.ns}:afterAppletRun`, ...this.app.args)
676
691
  }
package/class/app.js CHANGED
@@ -3,6 +3,7 @@ import Bajo from './bajo.js'
3
3
  import Base from './base.js'
4
4
  import Cache from './cache.js'
5
5
  import Tools from './tools.js'
6
+ import Plugin from './plugin.js'
6
7
  import { outmatchNs, parseObject, lib, runAsApplet } from './_helper.js'
7
8
  import { fileURLToPath } from 'url'
8
9
 
@@ -43,21 +44,21 @@ function getCallerFilename () {
43
44
  */
44
45
  class App {
45
46
  /**
46
- * @param {Object} [options] - App options
47
- * @param {string} [options.cwd] - Set current working directory. Defaults to the script directory
48
- * @param {string[]} [options.plugins] - Array of plugins to load. If provided, it override the list in ```package.json``` and ```.plugins``` file
49
- * @param {Object} [options.config] - Plugin's config object. If provided, plugin configs will no longer be read from its config files
47
+ * @param {Object} [options] - App options.
48
+ * @param {string} [options.cwd] - Set current working directory. Defaults to the script directory.
49
+ * @param {string[]} [options.plugins] - Array of plugins to load. If provided, it override the list in ```package.json``` and ```.plugins``` file.
50
+ * @param {Object} [options.config] - Plugin's config object. If provided, plugin configs will no longer be read from its config files.
50
51
  */
51
52
  constructor (options = {}) {
52
53
  /**
53
- * Copy of provided options
54
+ * Copy of provided options.
54
55
  *
55
56
  * @type {Object}
56
57
  */
57
58
  this.options = options
58
59
 
59
60
  /**
60
- * Your main namespace. And yes, you suppose to NOT CHANGE this
61
+ * Your main namespace. And yes, you suppose to NOT CHANGE this.
61
62
  *
62
63
  * @memberof App
63
64
  * @constant {string}
@@ -66,27 +67,29 @@ class App {
66
67
  this.mainNs = 'main'
67
68
 
68
69
  /**
69
- * App environments
70
+ * App environments.
71
+ *
70
72
  * @memberof App
71
73
  * @constant {TAppEnv}
72
74
  */
73
75
  this.envs = { dev: 'development', prod: 'production' }
74
76
 
75
77
  /**
76
- * Date/time when your app start
78
+ * Date/time when your app start.
79
+ *
77
80
  * @type {Date}
78
81
  */
79
82
  this.runAt = new Date()
80
83
 
81
84
  /**
82
- * Applets
85
+ * Applets container.
83
86
  *
84
87
  * @type {Array}
85
88
  */
86
89
  this.applets = []
87
90
 
88
91
  /**
89
- * List of all loaded plugin's package names
92
+ * Plugin's package names container. This is the list of plugins to load. It is read from ```package.json``` and ```.plugins``` file by default, but you can override it by providing ```options.plugins``` at constructor.
90
93
  *
91
94
  * @type {Array}
92
95
  */
@@ -94,9 +97,9 @@ class App {
94
97
 
95
98
  /**
96
99
  * @typedef {Object} TAppConfigHandler
97
- * @property {string} ext - File extension
98
- * @property {function} [readHandler] - Function to call for reading
99
- * @property {function} [writeHandler] - Function to call for writing
100
+ * @property {string} ext - File extension.
101
+ * @property {function} [readHandler] - Function to call for reading.
102
+ * @property {function} [writeHandler] - Function to call for writing.
100
103
  * @see App#configHandlers
101
104
  */
102
105
 
@@ -105,7 +108,7 @@ class App {
105
108
  *
106
109
  * By default, there are two built-in handlers available: ```.js```
107
110
  * and ```.json```. Use plugins to add more, e.g {@link https://github.com/ardhi/bajo-config|bajo-config}
108
- * lets you to use ```.yaml/.yml``` and ```.toml```
111
+ * lets you to use ```.yaml/.yml``` and ```.toml```.
109
112
  *
110
113
  * @type {TAppConfigHandler[]}
111
114
  */
@@ -128,7 +131,7 @@ class App {
128
131
  this.lib.parseObject = parseObject.bind(this)
129
132
 
130
133
  /**
131
- * Instance of system log
134
+ * Instance of system log.
132
135
  *
133
136
  * @type {Log}
134
137
  */
@@ -147,14 +150,14 @@ class App {
147
150
  this.baseClass = { Base, Tools }
148
151
 
149
152
  /**
150
- * If app runs in applet mode, this will be the applet's name
153
+ * If app runs in applet mode, this will be the applet's name.
151
154
  *
152
155
  * @type {string}
153
156
  */
154
157
  this.applet = undefined
155
158
 
156
159
  /**
157
- * Program arguments
160
+ * Program arguments.
158
161
  *
159
162
  * ```
160
163
  * $ node index.js arg1 arg2
@@ -233,11 +236,11 @@ class App {
233
236
  }
234
237
 
235
238
  /**
236
- * Add and save plugin and it's base class definition (if provided)
239
+ * Add and save plugin and it's base class definition (if provided).
237
240
  *
238
241
  * @method
239
- * @param {TPlugin} plugin - A valid bajo plugin
240
- * @param {Object} [baseClass] - Base class definition
242
+ * @param {TPlugin} plugin - A valid bajo plugin.
243
+ * @param {Object} [baseClass] - Base class definition.
241
244
  */
242
245
  addPlugin = (plugin, baseClass) => {
243
246
  if (this[plugin.ns]) throw new Error(`Plugin '${plugin.ns}' added already`)
@@ -246,7 +249,7 @@ class App {
246
249
  }
247
250
 
248
251
  /**
249
- * Get all loaded plugin namespaces
252
+ * Get all loaded plugin namespaces.
250
253
  *
251
254
  * @method
252
255
  * @returns {string[]}
@@ -255,6 +258,103 @@ class App {
255
258
  return this.pluginPkgs.map(pkg => camelCase(pkg))
256
259
  }
257
260
 
261
+ /**
262
+ * Get loaded plugins.
263
+ *
264
+ * @method
265
+ * @param {string[]} [nss] - Array of namespaces. If empty, it returns all loaded plugins.
266
+ * @returns {TPlugin[]}
267
+ */
268
+ getPlugins = (nss) => {
269
+ const allNs = nss ?? this.getAllNs()
270
+ return allNs.map(ns => this[ns])
271
+ }
272
+
273
+ /**
274
+ * Get all plugins loaded plugins.
275
+ *
276
+ * @method
277
+ * @returns {TPlugin[]}
278
+ */
279
+ getAllPlugins = () => {
280
+ return this.getPlugins()
281
+ }
282
+
283
+ /**
284
+ * Get plugin by its namespace.
285
+ *
286
+ * @method
287
+ * @param {string} name - Plugin name/namespace or alias.
288
+ * @param {boolean} [silent] - If ```true```, silently return undefined even on error.
289
+ * @returns {Object} Plugin object.
290
+ */
291
+ getPlugin = (name, silent) => {
292
+ if (!this[name]) {
293
+ // alias?
294
+ let plugin
295
+ for (const key in this) {
296
+ const item = this[key]
297
+ if (item instanceof Plugin && (item.alias === name || item.pkgName === name)) {
298
+ plugin = item
299
+ break
300
+ }
301
+ }
302
+ if (!plugin) {
303
+ if (silent) return false
304
+ throw this.bajo.error('pluginWithNameAliasNotLoaded%s', name)
305
+ }
306
+ name = plugin.ns
307
+ }
308
+ return this[name]
309
+ }
310
+
311
+ /**
312
+ * Get plugin data directory
313
+ *
314
+ * @method
315
+ * @param {string} name - Plugin name (namespace) or alias.
316
+ * @param {boolean} [ensureDir=true] - Set ```true``` (default) to ensure directory is existed.
317
+ * @returns {string}
318
+ */
319
+ getPluginDataDir = (name, ensureDir = true) => {
320
+ const { fs } = this.lib
321
+ const plugin = this.getPlugin(name)
322
+ const dir = `${this.bajo.dir.data}/plugins/${plugin.ns}`
323
+ if (ensureDir) fs.ensureDirSync(dir)
324
+ return dir
325
+ }
326
+
327
+ /**
328
+ * Resolve file path from:
329
+ *
330
+ * - local/absolute file
331
+ * - TNsPath (```myPlugin:/path/to/file.txt```)
332
+ * - file under node_modules, e.g. ```myPlugin:node_modules/some-package/file.txt```
333
+ *
334
+ * @method
335
+ * @param {string} file - File path, see above for supported types.
336
+ * @returns {string} Resolved file path.
337
+ */
338
+ getPluginFile = (file) => {
339
+ const { currentLoc } = this.lib.aneka
340
+ const { fs } = this.lib
341
+ const { trim } = this.lib._
342
+ if (!this) return file
343
+ if (file[0] === '.') file = `${currentLoc(import.meta).dir}/${trim(file.slice(1), '/')}`
344
+ if (file.includes(':')) {
345
+ if (file.slice(1, 2) === ':') return file // windows fs
346
+ const { ns, path } = this.bajo.breakNsPath(file, false)
347
+ if (ns !== 'file' && this && this[ns] && ns.length > 1) {
348
+ file = `${this[ns].dir.pkg}${path}`
349
+ if (path.startsWith('node_modules/')) {
350
+ file = `${this[ns].dir.pkg}/${path}`
351
+ if (!fs.existsSync(file)) file = `${this[ns].dir.pkg}/../${path.slice('node_modules/'.length)}`
352
+ }
353
+ }
354
+ }
355
+ return file
356
+ }
357
+
258
358
  /**
259
359
  * Dumping variable on screen. Like ```console.log``` with configurable options. Useful for quick debugging and testing. You can also use it to dump variables in production without worrying about performance because it is using Bajo's built-in cache to store the result of util's inspect, so it will only be processed once for each unique variable.
260
360
  *
@@ -268,12 +368,13 @@ class App {
268
368
  * See {@link Bajo#config} for details.
269
369
  *
270
370
  * @method
271
- * @param {...any} args - Variables to dump
371
+ * @param {...any} args - Variables to dump.
272
372
  */
273
373
  dump = (...args) => {
274
374
  let caller = getCallerFilename()
275
375
  caller = caller ? fileURLToPath(caller) : 'Unavailable'
276
- const terminate = last(args) === true
376
+ const opts = last(args)
377
+ const terminate = isPlainObject(opts) && opts.abort
277
378
  if (terminate) args.pop()
278
379
  const value = args.length === 1 ? args[0] : args
279
380
  const options = { ...this.bajo.config.dump }
@@ -346,10 +447,10 @@ class App {
346
447
  }
347
448
 
348
449
  /**
349
- * Terminate the app and back to console
450
+ * Terminate the app and back to console.
350
451
  *
351
452
  * @method
352
- * @param {string} [signal=SIGINT] - Signal to send
453
+ * @param {string} [signal=SIGINT] - Signal to send.
353
454
  */
354
455
  exit = (signal = 'SIGINT') => {
355
456
  if (signal === true) process.exit('1')
@@ -357,10 +458,10 @@ class App {
357
458
  }
358
459
 
359
460
  /**
360
- * Load internationalization & languages files for particular plugin
461
+ * Load internationalization & languages files for particular plugin.
361
462
  *
362
463
  * @method
363
- * @param {string} ns - Plugin name
464
+ * @param {string} ns - Plugin name.
364
465
  */
365
466
  loadIntl = (ns) => {
366
467
  const { fs } = this.lib
@@ -426,9 +527,9 @@ class App {
426
527
  * const translated = this.t('My cute cat is %s', 'purring')
427
528
  * ```
428
529
  * @method
429
- * @param {string} ns - Namespace
430
- * @param {string} text - Text to translate
431
- * @param {...any} params - Arguments
530
+ * @param {string} ns - Namespace.
531
+ * @param {string} text - Text to translate.
532
+ * @param {...any} params - Arguments.
432
533
  * @returns {string}
433
534
  */
434
535
  t = (ns, text, ...params) => {
@@ -449,18 +550,17 @@ class App {
449
550
  * Check whether translation text/key exists
450
551
  *
451
552
  * @method
452
- * @param {string} ns - Namespace
453
- * @param {string} text - Text to translate
553
+ * @param {string} ns - Namespace.
554
+ * @param {string} text - Text to translate.
454
555
  * @returns {boolean}
455
556
  */
456
-
457
557
  te = (ns, text, ...params) => {
458
558
  const { trans } = this._prepTrans(ns, text, params)
459
559
  return !!trans
460
560
  }
461
561
 
462
562
  /**
463
- * Helper method to list all supported config formats
563
+ * Helper method to list all supported config formats.
464
564
  *
465
565
  * @returns {string[]}
466
566
  */
@@ -468,12 +568,25 @@ class App {
468
568
  return map(this.configHandlers, 'ext')
469
569
  }
470
570
 
571
+ /**
572
+ * Start a plugin.
573
+ *
574
+ * @param {string} ns - Plugin namespace.
575
+ * @param {...any} args - Arguments to pass to the plugin's start method.
576
+ */
471
577
  startPlugin = (ns, ...args) => {
472
578
  this[ns].start(...args)
473
579
  }
474
580
 
581
+ /**
582
+ * Stop a plugin.
583
+ *
584
+ * @param {string} ns - Plugin namespace.
585
+ * @param {...any} args - Arguments to pass to the plugin's stop method.
586
+ */
475
587
  stopPlugin = (ns, ...args) => {
476
- this[ns].stop(...args)
588
+ // Disabled for now, reserved for future use. It is not a good idea to stop a plugin because other plugins might be dependent on it.
589
+ // this[ns].stop(...args)
477
590
  }
478
591
  }
479
592