bajo 2.18.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 +59 -45
  3. package/class/bajo.js +150 -129
  4. package/class/base.js +3 -3
  5. package/class/cache.js +60 -0
  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 +8 -8
  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 +5 -0
  73. package/.mocharc.json +0 -4
@@ -0,0 +1,119 @@
1
+ /* global describe, it, beforeEach, afterEach */
2
+
3
+ import os from 'node:os'
4
+ import path from 'node:path'
5
+ import { expect } from 'chai'
6
+ import fs from 'fs-extra'
7
+ import dayjs from 'dayjs'
8
+
9
+ import Log from '../class/log.js'
10
+
11
+ const createTempRoot = () => fs.mkdtempSync(path.join(os.tmpdir(), 'bajo-log-test-'))
12
+
13
+ describe('Log', () => {
14
+ let root
15
+ let app
16
+ let log
17
+
18
+ beforeEach(() => {
19
+ root = createTempRoot()
20
+ app = {
21
+ runAt: new Date(),
22
+ t: (prefix, text, ...args) => `${prefix}:${text}:${args.join('|')}`,
23
+ lib: {
24
+ fs,
25
+ dayjs,
26
+ _: {
27
+ isEmpty: (v) => v == null || v === '' || (typeof v === 'object' && Object.keys(v).length === 0),
28
+ merge: (a, b) => Object.assign(a, b),
29
+ without: (arr, item) => arr.filter(i => i !== item)
30
+ }
31
+ },
32
+ bajo: {
33
+ dir: { data: root },
34
+ config: {
35
+ env: 'dev',
36
+ log: {
37
+ level: 'trace',
38
+ save: false,
39
+ pretty: false,
40
+ useUtc: false,
41
+ timeTaken: false,
42
+ dateFormat: 'YYYY-MM-DD',
43
+ rotation: { cycle: 'none', byPlugin: false }
44
+ }
45
+ },
46
+ isLogInRange: () => true
47
+ }
48
+ }
49
+ })
50
+
51
+ afterEach(() => {
52
+ if (root) fs.rmSync(root, { recursive: true, force: true })
53
+ })
54
+
55
+ it('formats and prints messages in dev mode', () => {
56
+ const originalLog = console.log
57
+ const lines = []
58
+ console.log = (line) => lines.push(line)
59
+ log = new Log(app)
60
+
61
+ try {
62
+ log.info('main', 'hello %s', 'x')
63
+ } finally {
64
+ console.log = originalLog
65
+ }
66
+
67
+ expect(lines.length).to.equal(1)
68
+ expect(lines[0]).to.include('[INFO]')
69
+ expect(lines[0]).to.include('[main]')
70
+ expect(lines[0]).to.include('main:hello %s:x')
71
+ })
72
+
73
+ it('returns error message fallback by code/statusCode', () => {
74
+ log = new Log(app)
75
+
76
+ expect(log.getErrorMessage(new Error('x'))).to.equal('x')
77
+ expect(log.getErrorMessage({ message: '', code: 'E1' })).to.equal('E1')
78
+ expect(log.getErrorMessage({ message: '', statusCode: 404 })).to.equal(404)
79
+ })
80
+
81
+ it('builds rotation patterns and saves file', () => {
82
+ app.bajo.config.log.save = true
83
+ log = new Log(app)
84
+ app.bajo.config.log.rotation.cycle = 'daily'
85
+
86
+ const pattern = log.getRotationPattern()
87
+ log.save('\u001b[31mhello\u001b[0m', 'x')
88
+
89
+ expect(pattern).to.be.a('string')
90
+ expect(fs.existsSync(path.join(root, 'log', `bajo.${pattern}.log`))).to.equal(true)
91
+ })
92
+
93
+ it('supports prod json output', () => {
94
+ app.bajo.config.env = 'prod'
95
+ log = new Log(app)
96
+ const originalLog = console.log
97
+ const lines = []
98
+ console.log = (line) => lines.push(line)
99
+
100
+ try {
101
+ log.warn('core', { id: 1 }, 'hi')
102
+ } finally {
103
+ console.log = originalLog
104
+ }
105
+
106
+ const payload = JSON.parse(lines[0])
107
+ expect(payload.prefix).to.equal('core')
108
+ expect(payload.level).to.be.a('number')
109
+ expect(payload).to.have.property('data')
110
+ })
111
+
112
+ it('disposes app reference', async () => {
113
+ log = new Log(app)
114
+
115
+ await log.dispose()
116
+
117
+ expect(log.app).to.equal(null)
118
+ })
119
+ })
@@ -0,0 +1,116 @@
1
+ /* global describe, it, beforeEach */
2
+
3
+ import os from 'node:os'
4
+ import path from 'node:path'
5
+ import { expect } from 'chai'
6
+ import fs from 'fs-extra'
7
+ import lodash from 'lodash'
8
+
9
+ import Plugin from '../class/plugin.js'
10
+
11
+ const createTempRoot = () => fs.mkdtempSync(path.join(os.tmpdir(), 'bajo-plugin-test-'))
12
+
13
+ describe('Plugin', () => {
14
+ let app
15
+
16
+ beforeEach(() => {
17
+ const calls = []
18
+ app = {
19
+ lib: {
20
+ _: lodash,
21
+ fs
22
+ },
23
+ log: {
24
+ trace: (...args) => calls.push(['trace', ...args]),
25
+ debug: (...args) => calls.push(['debug', ...args]),
26
+ info: (...args) => calls.push(['info', ...args]),
27
+ warn: (...args) => calls.push(['warn', ...args]),
28
+ error: (...args) => calls.push(['error', ...args]),
29
+ fatal: (...args) => calls.push(['fatal', ...args]),
30
+ silent: (...args) => calls.push(['silent', ...args])
31
+ },
32
+ t: (ns, text, ...params) => `${ns}:${text}:${params.join('|')}`,
33
+ te: (ns, text) => `${ns}:${text}`,
34
+ dump: (...args) => calls.push(['dump', ...args]),
35
+ _calls: calls
36
+ }
37
+ })
38
+
39
+ it('initializes namespace and prefixed log shortcuts', () => {
40
+ const plugin = new Plugin('my-plugin', app)
41
+
42
+ plugin.log.info('hello')
43
+
44
+ expect(plugin.ns).to.equal('myPlugin')
45
+ expect(app._calls[0]).to.deep.equal(['info', 'myPlugin', 'hello'])
46
+ })
47
+
48
+ it('reads package info and selected keys', async () => {
49
+ const root = createTempRoot()
50
+ const pkgDir = path.join(root, 'plugin')
51
+ await fs.ensureDir(pkgDir)
52
+ await fs.writeJson(path.join(pkgDir, 'package.json'), {
53
+ name: 'my-plugin',
54
+ version: '1.2.3',
55
+ private: true
56
+ })
57
+ const plugin = new Plugin('my-plugin', app)
58
+ plugin.dir = { pkg: pkgDir }
59
+
60
+ expect(plugin.getPkgInfo()).to.deep.equal({
61
+ name: 'my-plugin',
62
+ version: '1.2.3'
63
+ })
64
+ expect(plugin.getPkgInfo(pkgDir, [])).to.include({ private: true })
65
+ })
66
+
67
+ it('returns config value with clone and omit support', () => {
68
+ const plugin = new Plugin('my-plugin', app)
69
+ plugin.config = { a: { b: 1, c: 2 } }
70
+
71
+ const val = plugin.getConfig('a', { omit: ['c'] })
72
+ val.b = 99
73
+
74
+ expect(val).to.deep.equal({ b: 99 })
75
+ expect(plugin.config.a.b).to.equal(1)
76
+ expect(plugin.getConfig('missing', { defValue: { x: 1 } })).to.deep.equal({ x: 1 })
77
+ expect(plugin.getConfig('a', { noClone: true })).to.equal(plugin.config.a)
78
+ })
79
+
80
+ it('returns native Error when print is unavailable', () => {
81
+ const plugin = new Plugin('my-plugin', app)
82
+
83
+ const err = plugin.error('plain error')
84
+ const fatalErr = plugin.fatal('fatal error')
85
+
86
+ expect(err).to.be.instanceOf(Error)
87
+ expect(err.message).to.equal('plain error')
88
+ expect(fatalErr).to.be.instanceOf(Error)
89
+ })
90
+
91
+ it('delegates translation and dump to app', () => {
92
+ const plugin = new Plugin('my-plugin', app)
93
+
94
+ expect(plugin.t('hello', 'x')).to.equal('myPlugin:hello:x')
95
+ expect(plugin.te('hello')).to.equal('myPlugin:hello')
96
+ plugin.dump(1, 2)
97
+
98
+ expect(app._calls[0]).to.deep.equal(['dump', 1, 2])
99
+ })
100
+
101
+ it('binds methods and disposes references', async () => {
102
+ const plugin = new Plugin('my-plugin', app)
103
+ plugin.value = 42
104
+ plugin.read = function () {
105
+ return this.value
106
+ }
107
+
108
+ plugin.selfBind('read')
109
+ const reader = plugin.read
110
+ await plugin.dispose()
111
+
112
+ expect(reader()).to.equal(42)
113
+ expect(plugin.app).to.equal(null)
114
+ expect(plugin.config).to.equal(null)
115
+ })
116
+ })
@@ -0,0 +1,100 @@
1
+ /* global describe, it, beforeEach */
2
+
3
+ import { expect } from 'chai'
4
+ import dayjs from 'dayjs'
5
+
6
+ import Print from '../class/print.js'
7
+
8
+ describe('Print', () => {
9
+ let plugin
10
+ let print
11
+
12
+ beforeEach(() => {
13
+ plugin = {
14
+ app: {
15
+ applet: false,
16
+ exit: () => {},
17
+ lib: { dayjs },
18
+ bajo: {
19
+ config: {
20
+ silent: false,
21
+ counter: false,
22
+ datetime: false
23
+ }
24
+ }
25
+ },
26
+ t: (text, ...args) => `${text}:${args.join('|')}`
27
+ }
28
+ print = new Print(plugin)
29
+ print.ora = {
30
+ text: '',
31
+ startCalled: false,
32
+ stopCalled: false,
33
+ start () { this.startCalled = true },
34
+ stop () { this.stopCalled = true },
35
+ succeedCalled: false,
36
+ succeed () { this.succeedCalled = true },
37
+ failCalled: false,
38
+ fail () { this.failCalled = true },
39
+ warnCalled: false,
40
+ warn () { this.warnCalled = true },
41
+ infoCalled: false,
42
+ info () { this.infoCalled = true },
43
+ clearCalled: false,
44
+ clear () { this.clearCalled = true },
45
+ renderCalled: false,
46
+ render () { this.renderCalled = true }
47
+ }
48
+ })
49
+
50
+ it('builds translated text with optional prefixes', () => {
51
+ print.options.showCounter = true
52
+
53
+ const text = print.buildText('hello')
54
+
55
+ expect(text).to.include('hello:')
56
+ expect(text).to.match(/\[\d\d:/)
57
+ })
58
+
59
+ it('starts and stops spinner', () => {
60
+ print.start('start')
61
+ print.stop()
62
+
63
+ expect(print.ora.startCalled).to.equal(true)
64
+ expect(print.ora.stopCalled).to.equal(true)
65
+ })
66
+
67
+ it('uses succeed/fail/warn/info/clear/render chainable methods', () => {
68
+ expect(print.succeed('ok')).to.equal(print)
69
+ expect(print.fail('x')).to.equal(print)
70
+ expect(print.warn('w')).to.equal(print)
71
+ expect(print.info('i')).to.equal(print)
72
+ expect(print.clear()).to.equal(print)
73
+ expect(print.render()).to.equal(print)
74
+
75
+ expect(print.ora.succeedCalled).to.equal(true)
76
+ expect(print.ora.failCalled).to.equal(true)
77
+ expect(print.ora.warnCalled).to.equal(true)
78
+ expect(print.ora.infoCalled).to.equal(true)
79
+ expect(print.ora.clearCalled).to.equal(true)
80
+ expect(print.ora.renderCalled).to.equal(true)
81
+ })
82
+
83
+ it('fails and exits on fatal', () => {
84
+ let exited = false
85
+ plugin.app.exit = () => { exited = true }
86
+
87
+ print.fatal('boom')
88
+
89
+ expect(print.ora.failCalled).to.equal(true)
90
+ expect(exited).to.equal(true)
91
+ })
92
+
93
+ it('creates a new spinner sharing start time', () => {
94
+ const spin = print.spinner()
95
+
96
+ expect(spin).to.be.instanceOf(Print)
97
+ expect(spin).to.not.equal(print)
98
+ expect(spin.startTime.valueOf()).to.equal(print.startTime.valueOf())
99
+ })
100
+ })
@@ -0,0 +1,38 @@
1
+ /* global describe, it */
2
+
3
+ import { expect } from 'chai'
4
+
5
+ import Tools from '../class/tools.js'
6
+
7
+ describe('Tools', () => {
8
+ it('stores plugin and app references', () => {
9
+ const plugin = { app: { name: 'app' } }
10
+ const tools = new Tools(plugin)
11
+
12
+ expect(tools.plugin).to.equal(plugin)
13
+ expect(tools.app).to.equal(plugin.app)
14
+ })
15
+
16
+ it('binds methods to self', () => {
17
+ const plugin = { app: {} }
18
+ const tools = new Tools(plugin)
19
+ tools.value = 7
20
+ tools.read = function () {
21
+ return this.value
22
+ }
23
+
24
+ tools.selfBind(['read'])
25
+ const rebound = tools.read
26
+
27
+ expect(rebound()).to.equal(7)
28
+ })
29
+
30
+ it('disposes references', async () => {
31
+ const tools = new Tools({ app: {} })
32
+
33
+ await tools.dispose()
34
+
35
+ expect(tools.app).to.equal(null)
36
+ expect(tools.plugin).to.equal(null)
37
+ })
38
+ })
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-06-26
4
+
5
+ - [2.19.0] Documentation overhaul
6
+ - [2.19.0] Make much needed tests
7
+
3
8
  ## 2026-06-12
4
9
 
5
10
  - [2.18.0] Move plugin related methods to ```app```
package/.mocharc.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "spec": "test/**/*.test.js",
3
- "timeout": 5000
4
- }