bajo 2.22.0 → 2.24.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.
- package/.jsdoc.conf.json +2 -1
- package/class/app.js +220 -107
- package/class/bajo.js +258 -177
- package/class/base.js +85 -24
- package/class/cache.js +8 -16
- package/class/err.js +31 -10
- package/class/log.js +46 -38
- package/class/plugin.js +53 -30
- package/class/print.js +18 -15
- package/class/tools.js +6 -5
- package/docs/App.html +51 -1
- package/docs/Bajo.html +1 -1
- package/docs/Base.html +34 -1
- package/docs/Cache.html +1 -1
- package/docs/Err.html +2 -2
- package/docs/Log.html +2 -2
- package/docs/Main.html +3 -0
- package/docs/Plugin.html +1 -1
- package/docs/Print.html +1 -1
- package/docs/Tools.html +1 -1
- package/docs/class_app.js.html +222 -109
- package/docs/class_bajo.js.html +260 -179
- package/docs/class_base.js.html +87 -26
- package/docs/class_cache.js.html +10 -18
- package/docs/class_err.js.html +33 -12
- package/docs/class_log.js.html +48 -40
- package/docs/class_plugin.js.html +55 -32
- package/docs/class_print.js.html +20 -17
- package/docs/class_tools.js.html +8 -7
- package/docs/data/search.json +1 -1
- package/docs/extend_bajo_hook.js.html +289 -0
- package/docs/global.html +22 -1
- package/docs/index.html +1 -1
- package/docs/index.js.html +53 -16
- package/docs/lib_applet-hook.js.html +328 -0
- package/docs/lib_config.js.html +167 -0
- package/docs/lib_helper.js.html +186 -192
- package/docs/module-Applet.html +3 -0
- package/docs/module-Helper-Main.html +3 -0
- package/docs/module-Helper.html +1 -8
- package/docs/module-Hook.html +1 -1
- package/docs/tutorial-01_WELCOME.html +3 -0
- package/docs/tutorial-02_GETTING_STARTED.html +125 -0
- package/docs/tutorial-03_USER_GUIDE.html +54 -0
- package/docs/tutorial-04_DEV_GUIDE.html +178 -0
- package/docs/tutorial-05_ECOSYSTEM.html +3 -0
- package/extend/bajo/intl/en-US.json +2 -1
- package/extend/bajo/intl/id.json +2 -1
- package/index.js +51 -14
- package/lib/applet-hook.js +325 -0
- package/lib/config.js +164 -0
- package/lib/helper.js +184 -190
- package/package.json +6 -2
- package/test/00-global-hooks.test.js +44 -0
- package/test/e2e/_run.js +19 -0
- package/test/e2e/e2e-applet-process.test.js +66 -0
- package/test/e2e/e2e-boot-process.test.js +62 -0
- package/test/e2e/e2e-hooks-process.test.js +68 -0
- package/test/integration/_setup.js +55 -0
- package/test/integration/aspect-01-boot-instance.test.js +24 -0
- package/test/integration/aspect-02-plugin-loading.test.js +24 -0
- package/test/integration/aspect-03-config-merge.test.js +27 -0
- package/test/integration/aspect-04-intl-loading.test.js +29 -0
- package/test/integration/aspect-05-cache-roundtrip.test.js +26 -0
- package/test/integration/aspect-06-log-file-save.test.js +28 -0
- package/test/integration/aspect-07-plugin-data-dir.test.js +25 -0
- package/test/integration/aspect-08-plugin-lookup.test.js +25 -0
- package/test/integration/aspect-09-config-formats.test.js +26 -0
- package/test/integration/aspect-10-hooks.test.js +38 -0
- package/test/unit/app.test.js +115 -0
- package/test/unit/applet-hook.test.js +10 -0
- package/test/unit/bajo.test.js +151 -0
- package/test/unit/base.test.js +90 -0
- package/test/unit/cache.test.js +89 -0
- package/test/unit/config.test.js +14 -0
- package/test/unit/err.test.js +57 -0
- package/test/unit/helper.test.js +116 -0
- package/test/unit/index.test.js +40 -0
- package/test/unit/log.test.js +84 -0
- package/test/unit/plugin.test.js +95 -0
- package/test/unit/print.test.js +72 -0
- package/test/unit/tools.test.js +29 -0
- package/wiki/CHANGES.md +9 -0
- package/wiki/tutorials/01_WELCOME.md +18 -0
- package/wiki/tutorials/02_GETTING_STARTED.md +366 -0
- package/wiki/tutorials/03_USER_GUIDE.md +262 -0
- package/wiki/tutorials/04_DEV_GUIDE.md +386 -0
- package/wiki/tutorials/05_ECOSYSTEM.md +95 -0
- package/wiki/tutorials/tutorials.json +17 -0
- package/lib/hook.js +0 -228
- package/test/app.test.js +0 -183
- package/test/bajo.test.js +0 -124
- package/test/base.test.js +0 -75
- package/test/cache.test.js +0 -94
- package/test/e2e.test.js +0 -137
- package/test/err.test.js +0 -73
- package/test/helper.test.js +0 -39
- package/test/import-module.test.js +0 -138
- package/test/integration.test.js +0 -218
- package/test/log.test.js +0 -119
- package/test/plugin.test.js +0 -116
- package/test/print.test.js +0 -100
- package/test/tools.test.js +0 -38
- package/wiki/CONFIG.md +0 -36
- package/wiki/DEV_GUIDE.md +0 -3
- package/wiki/ECOSYSTEM.md +0 -93
- package/wiki/GETTING-STARTED.md +0 -356
- package/wiki/USER-GUIDE.md +0 -256
package/lib/hook.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module Hook
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef THook
|
|
7
|
-
* @type {Object}
|
|
8
|
-
* @property {string} name - Hook name
|
|
9
|
-
* @property {string} ns - Hook namespace
|
|
10
|
-
* @property {function} handler - Hook handler function
|
|
11
|
-
* @property {number} [level=999] - Hook level (lower number means higher priority)
|
|
12
|
-
* @property {string} src - Hook source (origin plugin namespace). Bajo will set this automatically, any value you set will be overriden.
|
|
13
|
-
* @property {boolean} [noWait=false] - If true, Bajo will not wait for this hook to complete before proceeding to the next hook. Default is false.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Run before boot process. You can use this hook to do some pre-boot process.
|
|
18
|
-
*
|
|
19
|
-
* @name bajo:beforeBoot
|
|
20
|
-
* @async
|
|
21
|
-
* @method
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Run after boot process. You can use this hook to do some post-boot process.
|
|
26
|
-
*
|
|
27
|
-
* @name bajo:afterBoot
|
|
28
|
-
* @async
|
|
29
|
-
* @method
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Run after hooks are collected. You can use this hook to modify the collected hooks before
|
|
34
|
-
* they are recognized as application hooks.
|
|
35
|
-
*
|
|
36
|
-
* @async
|
|
37
|
-
* @method
|
|
38
|
-
* @name bajo:afterCollectHooks
|
|
39
|
-
* @param {Array<module:Hook~THook>} hooks - Array of hook objects
|
|
40
|
-
* @see module:Helper.collectHooks
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Run before all plugins are initialized. You can use this hook to do some pre-initialization process.
|
|
45
|
-
*
|
|
46
|
-
* @async
|
|
47
|
-
* @method
|
|
48
|
-
* @name bajo:beforeAllInit
|
|
49
|
-
* @see module:Helper.run
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Run after all plugins are initialized. You can use this hook to do some post-initialization process.
|
|
54
|
-
*
|
|
55
|
-
* @async
|
|
56
|
-
* @method
|
|
57
|
-
* @name bajo:afterAllInit
|
|
58
|
-
* @see module:Helper.run
|
|
59
|
-
*/
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Run before all plugins are started. You can use this hook to do some pre-start process.
|
|
63
|
-
*
|
|
64
|
-
* @async
|
|
65
|
-
* @method
|
|
66
|
-
* @name bajo:beforeAllStart
|
|
67
|
-
* @see module:Helper.run
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Run after all plugins are started. You can use this hook to do some post-start process.
|
|
72
|
-
*
|
|
73
|
-
* @async
|
|
74
|
-
* @method
|
|
75
|
-
* @name bajo:afterAllStart
|
|
76
|
-
* @see module:Helper.run
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Run before `{ns}` plugins are initialized. You can use this hook to do some pre-initialization process.
|
|
81
|
-
*
|
|
82
|
-
* @async
|
|
83
|
-
* @method
|
|
84
|
-
* @name {ns}:beforeInit
|
|
85
|
-
* @see module:Helper.run
|
|
86
|
-
*/
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Run after `{ns}` plugins are initialized. You can use this hook to do some post-initialization process.
|
|
90
|
-
*
|
|
91
|
-
* @async
|
|
92
|
-
* @method
|
|
93
|
-
* @name {ns}:afterInit
|
|
94
|
-
* @see module:Helper.run
|
|
95
|
-
*/
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Run after `{ns}` plugins are initialized. You can use this hook to do some pre-start process.
|
|
99
|
-
*
|
|
100
|
-
* @async
|
|
101
|
-
* @method
|
|
102
|
-
* @name {ns}:beforeStart
|
|
103
|
-
* @see module:Helper.run
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Run after `{ns}` plugins are started. You can use this hook to do some post-start process.
|
|
108
|
-
*
|
|
109
|
-
* @async
|
|
110
|
-
* @method
|
|
111
|
-
* @name {ns}:afterStart
|
|
112
|
-
* @see module:Helper.run
|
|
113
|
-
*/
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Run before applet is run. `{ns}` is the applet's namespace
|
|
117
|
-
*
|
|
118
|
-
* @name {ns}:beforeAppletRun
|
|
119
|
-
* @async
|
|
120
|
-
* @method
|
|
121
|
-
* @param {...any} args - Arguments passed to the applet
|
|
122
|
-
* @see module:Helper.runAsApplet
|
|
123
|
-
*/
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Run after applet is run. `{ns}` is the applet's namespace
|
|
127
|
-
*
|
|
128
|
-
* @name {ns}:afterAppletRun
|
|
129
|
-
* @async
|
|
130
|
-
* @method
|
|
131
|
-
* @param {...any} args - Arguments passed to the applet
|
|
132
|
-
* @see module:Helper.runAsApplet
|
|
133
|
-
*/
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Run before collection is built.
|
|
137
|
-
*
|
|
138
|
-
* @async
|
|
139
|
-
* @method
|
|
140
|
-
* @name bajo:beforeBuildCollection
|
|
141
|
-
* @param {string} container - Collection container name
|
|
142
|
-
* @see Bajo#buildCollections
|
|
143
|
-
*/
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Run after collection is built.
|
|
147
|
-
*
|
|
148
|
-
* @async
|
|
149
|
-
* @method
|
|
150
|
-
* @name bajo:afterBuildCollection
|
|
151
|
-
* @param {string} container - Collection container name
|
|
152
|
-
* @param {array<object>} items - Collection items
|
|
153
|
-
* @see Bajo#buildCollections
|
|
154
|
-
*/
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Run after a non override/extended configuration file is read.
|
|
158
|
-
*
|
|
159
|
-
* @async
|
|
160
|
-
* @method
|
|
161
|
-
* @name bajo.default:afterReadConfig
|
|
162
|
-
* @param {string} file - Config file path
|
|
163
|
-
* @param {string} orgObj - Original config object before parsing
|
|
164
|
-
* @param {object} options - readConfig options
|
|
165
|
-
*/
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Run before a configuration file override is read.
|
|
169
|
-
*
|
|
170
|
-
* @async
|
|
171
|
-
* @method
|
|
172
|
-
* @name bajo.override:beforeReadConfig
|
|
173
|
-
* @param {string} fileExt - Config file extension
|
|
174
|
-
* @param {object} options - readConfig options
|
|
175
|
-
*/
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Run after a configuration file override is read.
|
|
179
|
-
*
|
|
180
|
-
* @async
|
|
181
|
-
* @method
|
|
182
|
-
* @name bajo.override:afterReadConfig
|
|
183
|
-
* @param {string} fileExt - Config file extension
|
|
184
|
-
* @param {object} result - Resulting config object after parsing
|
|
185
|
-
* @param {object} options - readConfig options
|
|
186
|
-
*/
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Run before a extended configuration file is read.
|
|
190
|
-
*
|
|
191
|
-
* @async
|
|
192
|
-
* @method
|
|
193
|
-
* @name bajo.extend:beforeReadConfig
|
|
194
|
-
* @param {string} fileExt - Config file extension
|
|
195
|
-
* @param {object} options - readConfig options
|
|
196
|
-
*/
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Run after a extended configuration file is read.
|
|
200
|
-
*
|
|
201
|
-
* @async
|
|
202
|
-
* @method
|
|
203
|
-
* @name bajo.extend:afterReadConfig
|
|
204
|
-
* @param {string} fileExt - Config file extension
|
|
205
|
-
* @param {object} result - Resulting config object after parsing
|
|
206
|
-
* @param {object} options - readConfig options
|
|
207
|
-
*/
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Run before a configuration file is read.
|
|
211
|
-
*
|
|
212
|
-
* @async
|
|
213
|
-
* @method
|
|
214
|
-
* @name bajo:beforeReadConfig
|
|
215
|
-
* @param {string} file - Config file path
|
|
216
|
-
* @param {object} options - readConfig options
|
|
217
|
-
*/
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Run after all read processes of a configuration file are completed.
|
|
221
|
-
*
|
|
222
|
-
* @async
|
|
223
|
-
* @method
|
|
224
|
-
* @name bajo:afterReadConfig
|
|
225
|
-
* @param {string} file - Config file path
|
|
226
|
-
* @param {object} result - Resulting config object after parsing
|
|
227
|
-
* @param {object} options - readConfig options
|
|
228
|
-
*/
|
package/test/app.test.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
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
|
-
|
|
8
|
-
import App from '../class/app.js'
|
|
9
|
-
import Plugin from '../class/plugin.js'
|
|
10
|
-
|
|
11
|
-
const createTempRoot = () => fs.mkdtempSync(path.join(os.tmpdir(), 'bajo-app-test-'))
|
|
12
|
-
|
|
13
|
-
describe('App', () => {
|
|
14
|
-
let rootDir
|
|
15
|
-
let app
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
rootDir = createTempRoot()
|
|
19
|
-
app = new App({ cwd: rootDir })
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
if (rootDir) fs.rmSync(rootDir, { recursive: true, force: true })
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('adds plugins and base class mappings', () => {
|
|
27
|
-
const plugin = new Plugin('my-plugin', app)
|
|
28
|
-
const MyBase = class {}
|
|
29
|
-
|
|
30
|
-
app.addPlugin(plugin, MyBase)
|
|
31
|
-
|
|
32
|
-
expect(app.myPlugin).to.equal(plugin)
|
|
33
|
-
expect(app.baseClass.MyPlugin).to.equal(MyBase)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('throws when adding the same plugin namespace twice', () => {
|
|
37
|
-
const plugin = new Plugin('dup-plugin', app)
|
|
38
|
-
app.addPlugin(plugin)
|
|
39
|
-
|
|
40
|
-
expect(() => app.addPlugin(plugin)).to.throw("Plugin 'dupPlugin' added already")
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('lists namespaces and loaded plugins', () => {
|
|
44
|
-
app.pluginPkgs = ['alpha-plugin', 'beta-plugin']
|
|
45
|
-
app.alphaPlugin = { ns: 'alphaPlugin' }
|
|
46
|
-
app.betaPlugin = { ns: 'betaPlugin' }
|
|
47
|
-
|
|
48
|
-
expect(app.getAllNs()).to.deep.equal(['alphaPlugin', 'betaPlugin'])
|
|
49
|
-
expect(app.getPlugins()).to.deep.equal([app.alphaPlugin, app.betaPlugin])
|
|
50
|
-
expect(app.getPlugins(['betaPlugin'])).to.deep.equal([app.betaPlugin])
|
|
51
|
-
expect(app.getAllPlugins()).to.deep.equal([app.alphaPlugin, app.betaPlugin])
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('gets plugin by namespace, alias, and package name', () => {
|
|
55
|
-
const plugin = new Plugin('my-plugin', app)
|
|
56
|
-
plugin.alias = 'mine'
|
|
57
|
-
app.addPlugin(plugin)
|
|
58
|
-
app.bajo = { error: (code, value) => new Error(`${code}:${value}`) }
|
|
59
|
-
|
|
60
|
-
expect(app.getPlugin('myPlugin')).to.equal(plugin)
|
|
61
|
-
expect(app.getPlugin('mine')).to.equal(plugin)
|
|
62
|
-
expect(app.getPlugin('my-plugin')).to.equal(plugin)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('supports silent and throwing behavior for missing plugin lookup', () => {
|
|
66
|
-
app.bajo = { error: (code, value) => new Error(`${code}:${value}`) }
|
|
67
|
-
|
|
68
|
-
expect(app.getPlugin('missing', true)).to.equal(false)
|
|
69
|
-
expect(() => app.getPlugin('missing')).to.throw('pluginWithNameAliasNotLoaded%s:missing')
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('creates and returns plugin data directory', () => {
|
|
73
|
-
const plugin = new Plugin('my-plugin', app)
|
|
74
|
-
app.addPlugin(plugin)
|
|
75
|
-
app.bajo = { dir: { data: path.join(rootDir, 'data') } }
|
|
76
|
-
|
|
77
|
-
const dir = app.getPluginDataDir('myPlugin')
|
|
78
|
-
|
|
79
|
-
expect(dir).to.equal(path.join(rootDir, 'data', 'plugins', 'myPlugin'))
|
|
80
|
-
expect(fs.existsSync(dir)).to.equal(true)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('resolves plugin-scoped files and node_modules fallback paths', async () => {
|
|
84
|
-
const plugin = new Plugin('my-plugin', app)
|
|
85
|
-
plugin.dir = { pkg: path.join(rootDir, 'plugins', 'my-plugin') }
|
|
86
|
-
await fs.ensureDir(plugin.dir.pkg)
|
|
87
|
-
app.addPlugin(plugin)
|
|
88
|
-
|
|
89
|
-
app.bajo = {
|
|
90
|
-
breakNsPath: () => ({ ns: 'myPlugin', path: '/src/feature.js' })
|
|
91
|
-
}
|
|
92
|
-
expect(app.getPluginFile('myPlugin:/src/feature.js')).to.equal(path.join(plugin.dir.pkg, 'src/feature.js'))
|
|
93
|
-
|
|
94
|
-
const fallbackFile = path.join(rootDir, 'plugins', 'dep', 'index.js')
|
|
95
|
-
await fs.ensureDir(path.dirname(fallbackFile))
|
|
96
|
-
await fs.writeFile(fallbackFile, 'export default 1', 'utf8')
|
|
97
|
-
app.bajo.breakNsPath = () => ({ ns: 'myPlugin', path: 'node_modules/dep/index.js' })
|
|
98
|
-
|
|
99
|
-
expect(app.getPluginFile('myPlugin:node_modules/dep/index.js')).to.equal(`${plugin.dir.pkg}/../dep/index.js`)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('translates and checks translation existence', () => {
|
|
103
|
-
app.pluginPkgs = ['my-plugin']
|
|
104
|
-
app.myPlugin = {
|
|
105
|
-
intl: {
|
|
106
|
-
id: {
|
|
107
|
-
greet: 'Halo %s',
|
|
108
|
-
list: 'Daftar: %s'
|
|
109
|
-
},
|
|
110
|
-
en: {
|
|
111
|
-
greet: 'Hello %s'
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
app.bajo = {
|
|
116
|
-
config: {
|
|
117
|
-
lang: 'id',
|
|
118
|
-
intl: {
|
|
119
|
-
fallback: 'en',
|
|
120
|
-
supported: ['id', 'en']
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
join: (items) => items.join(', '),
|
|
124
|
-
log: { warn: () => {} }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
expect(app.t('myPlugin', 'greet', 'Ardhi')).to.equal('Halo Ardhi')
|
|
128
|
-
expect(app.t('myPlugin', 'list', ['A', 'B'])).to.equal('Daftar: A, B')
|
|
129
|
-
expect(app.t('myPlugin', 'unknown %s', 'X')).to.equal('unknown X')
|
|
130
|
-
expect(app.te('myPlugin', 'greet')).to.equal(true)
|
|
131
|
-
expect(app.te('myPlugin', 'not.exists')).to.equal(false)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
it('returns supported config formats', () => {
|
|
135
|
-
app.configHandlers = [{ ext: '.json' }, { ext: '.yaml' }]
|
|
136
|
-
|
|
137
|
-
expect(app.getConfigFormats()).to.deep.equal(['.json', '.yaml'])
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('starts plugin by namespace with arguments', () => {
|
|
141
|
-
const calls = []
|
|
142
|
-
app.sample = {
|
|
143
|
-
start: (...args) => {
|
|
144
|
-
calls.push(args)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
app.startPlugin('sample', 1, 'x')
|
|
149
|
-
|
|
150
|
-
expect(calls).to.deep.equal([[1, 'x']])
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('kills process with signal and exits abruptly when true is passed', () => {
|
|
154
|
-
const originalKill = process.kill
|
|
155
|
-
const originalExit = process.exit
|
|
156
|
-
const killCalls = []
|
|
157
|
-
let exitArg
|
|
158
|
-
|
|
159
|
-
process.kill = (...args) => {
|
|
160
|
-
killCalls.push(args)
|
|
161
|
-
return true
|
|
162
|
-
}
|
|
163
|
-
process.exit = (arg) => {
|
|
164
|
-
exitArg = arg
|
|
165
|
-
throw new Error('__EXIT__')
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
app.exit('SIGTERM')
|
|
170
|
-
try {
|
|
171
|
-
app.exit(true)
|
|
172
|
-
} catch (err) {
|
|
173
|
-
if (err.message !== '__EXIT__') throw err
|
|
174
|
-
}
|
|
175
|
-
} finally {
|
|
176
|
-
process.kill = originalKill
|
|
177
|
-
process.exit = originalExit
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
expect(killCalls).to.deep.equal([[process.pid, 'SIGTERM']])
|
|
181
|
-
expect(exitArg).to.equal('1')
|
|
182
|
-
})
|
|
183
|
-
})
|
package/test/bajo.test.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
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
|
-
|
|
8
|
-
import App from '../class/app.js'
|
|
9
|
-
import Bajo from '../class/bajo.js'
|
|
10
|
-
|
|
11
|
-
const createTempRoot = () => fs.mkdtempSync(path.join(os.tmpdir(), 'bajo-core-test-'))
|
|
12
|
-
|
|
13
|
-
describe('Bajo', () => {
|
|
14
|
-
let root
|
|
15
|
-
let app
|
|
16
|
-
let bajo
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
root = createTempRoot()
|
|
20
|
-
app = new App({ cwd: root })
|
|
21
|
-
bajo = new Bajo(app)
|
|
22
|
-
app.bajo = bajo
|
|
23
|
-
app.main = { dir: { pkg: root } }
|
|
24
|
-
app.mainNs = 'main'
|
|
25
|
-
app.main = { pkgName: 'main', dir: { pkg: root } }
|
|
26
|
-
app.demo = {
|
|
27
|
-
dir: { pkg: path.join(root, 'demo') },
|
|
28
|
-
greet: (name) => `hi ${name}`
|
|
29
|
-
}
|
|
30
|
-
bajo.config = {
|
|
31
|
-
env: 'dev',
|
|
32
|
-
lang: 'en-US',
|
|
33
|
-
intl: {
|
|
34
|
-
unitSys: { 'en-US': 'metric' },
|
|
35
|
-
format: {
|
|
36
|
-
emptyValue: '-',
|
|
37
|
-
datetime: { dateStyle: 'medium', timeStyle: 'short', timeZone: 'UTC' },
|
|
38
|
-
date: { dateStyle: 'medium', timeZone: 'UTC' },
|
|
39
|
-
time: { timeStyle: 'short', timeZone: 'UTC' },
|
|
40
|
-
float: { maximumFractionDigits: 2 },
|
|
41
|
-
double: { maximumFractionDigits: 2 },
|
|
42
|
-
integer: {},
|
|
43
|
-
smallint: {}
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
log: {
|
|
47
|
-
level: 'trace'
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
bajo.t = (text) => text
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
afterEach(() => {
|
|
54
|
-
if (root) fs.rmSync(root, { recursive: true, force: true })
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('builds and breaks namespace paths', () => {
|
|
58
|
-
const built = bajo.buildNsPath({ ns: 'demo', subNs: 'api', subSubNs: 'v1', path: '/users' })
|
|
59
|
-
const broken = bajo.breakNsPath('demo.api:/users/:id|42?q=x')
|
|
60
|
-
|
|
61
|
-
expect(built).to.equal('demo.api.v1:/users')
|
|
62
|
-
expect(broken).to.include({ ns: 'demo', subNs: 'api', path: '/users/:id', realPath: '/users/42' })
|
|
63
|
-
expect(broken.qs).to.deep.equal({ q: 'x' })
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('breaks ns path details from filename', () => {
|
|
67
|
-
const info = bajo.breakNsPathFromFile({
|
|
68
|
-
file: 'x/extend/route/demo.api@user-list.js',
|
|
69
|
-
dir: 'x/extend/',
|
|
70
|
-
suffix: '',
|
|
71
|
-
ns: 'demo',
|
|
72
|
-
getType: true
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
expect(info).to.include({ ns: 'demo', subNs: 'api', path: 'userList', type: 'route' })
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('returns unit format and formats values', () => {
|
|
79
|
-
const unit = bajo.getUnitFormat({ lang: 'en-US' })
|
|
80
|
-
const joined = bajo.format(['a', 'b'], 'array')
|
|
81
|
-
const integer = bajo.format(12345, 'integer')
|
|
82
|
-
|
|
83
|
-
expect(unit.unitSys).to.equal('metric')
|
|
84
|
-
expect(unit.format).to.be.an('object')
|
|
85
|
-
expect(joined).to.equal('a, b')
|
|
86
|
-
expect(integer).to.be.a('string')
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('gets method by ns path and supports non-throw mode', () => {
|
|
90
|
-
const fn = bajo.getMethod('demo:greet')
|
|
91
|
-
const miss = bajo.getMethod('demo:notFound', false)
|
|
92
|
-
|
|
93
|
-
expect(fn('a')).to.equal('hi a')
|
|
94
|
-
expect(miss).to.equal(undefined)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('validates app/plugin package and utility helpers', async () => {
|
|
98
|
-
const appPkg = path.join(root, 'appdir')
|
|
99
|
-
const pluginPkg = path.join(root, 'plugindir')
|
|
100
|
-
await fs.ensureDir(appPkg)
|
|
101
|
-
await fs.ensureDir(pluginPkg)
|
|
102
|
-
await fs.ensureDir(path.join(root, 'empty'))
|
|
103
|
-
await fs.writeJson(path.join(appPkg, 'package.json'), { bajo: { type: 'app' } })
|
|
104
|
-
await fs.writeJson(path.join(pluginPkg, 'package.json'), { bajo: { type: 'plugin' } })
|
|
105
|
-
|
|
106
|
-
expect(bajo.isValidApp(appPkg)).to.equal(true)
|
|
107
|
-
expect(bajo.isValidPlugin(pluginPkg)).to.equal(true)
|
|
108
|
-
expect(bajo.join(['a', 'b', 'c'])).to.equal('a, b and c')
|
|
109
|
-
expect(bajo.numUnit('10mb', 'kb')).to.equal('10mb')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('reads/writes json helpers', async () => {
|
|
113
|
-
const file = path.join(root, 'x.json')
|
|
114
|
-
const content = bajo.toJson({ a: 1 })
|
|
115
|
-
await fs.writeFile(file, content, 'utf8')
|
|
116
|
-
|
|
117
|
-
expect(bajo.fromJson(content)).to.deep.equal({ a: 1 })
|
|
118
|
-
expect(bajo.readJson(file)).to.deep.equal({ a: 1 })
|
|
119
|
-
|
|
120
|
-
const out = path.join(root, 'out.json')
|
|
121
|
-
bajo.toJson({ b: 2 }, { writeToFile: true, saveAsFile: out })
|
|
122
|
-
expect(fs.existsSync(out)).to.equal(true)
|
|
123
|
-
})
|
|
124
|
-
})
|
package/test/base.test.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/* global describe, it, beforeEach */
|
|
2
|
-
|
|
3
|
-
import { expect } from 'chai'
|
|
4
|
-
import lodash from 'lodash'
|
|
5
|
-
|
|
6
|
-
import Base from '../class/base.js'
|
|
7
|
-
|
|
8
|
-
describe('Base', () => {
|
|
9
|
-
let app
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
app = {
|
|
13
|
-
mainNs: 'main',
|
|
14
|
-
getAllNs: () => ['alpha', 'beta'],
|
|
15
|
-
lib: {
|
|
16
|
-
_: lodash,
|
|
17
|
-
aneka: {
|
|
18
|
-
defaultsDeep: (...objs) => lodash.defaultsDeep(...objs)
|
|
19
|
-
},
|
|
20
|
-
parseObject: (obj) => obj
|
|
21
|
-
},
|
|
22
|
-
bajo: {
|
|
23
|
-
dir: { base: '/app', data: '/data' },
|
|
24
|
-
config: { env: 'dev' },
|
|
25
|
-
log: { trace: () => {} },
|
|
26
|
-
getModuleDir: () => '/modules/my-plugin',
|
|
27
|
-
readAllConfigs: async () => ({ fromFile: true })
|
|
28
|
-
},
|
|
29
|
-
env: {
|
|
30
|
-
myPlugin: { x: 3 }
|
|
31
|
-
},
|
|
32
|
-
argv: {
|
|
33
|
-
myPlugin: { y: 2 }
|
|
34
|
-
},
|
|
35
|
-
options: {
|
|
36
|
-
config: {
|
|
37
|
-
myPlugin: { z: 1 }
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('initializes defaults', () => {
|
|
44
|
-
const base = new Base('my-plugin', app)
|
|
45
|
-
|
|
46
|
-
expect(base.ns).to.equal('myPlugin')
|
|
47
|
-
expect(base.dependencies).to.deep.equal([])
|
|
48
|
-
expect(base.state).to.deep.equal({})
|
|
49
|
-
expect(base.pkg).to.deep.equal({})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('loads config and sets package/data directories', async () => {
|
|
53
|
-
const base = new Base('my-plugin', app)
|
|
54
|
-
base.config = { title: 'my app', z: 9, x: 0, y: 0 }
|
|
55
|
-
|
|
56
|
-
await base.loadConfig()
|
|
57
|
-
|
|
58
|
-
expect(base.dir).to.deep.equal({
|
|
59
|
-
pkg: '/modules/my-plugin',
|
|
60
|
-
data: '/data/plugins/myPlugin'
|
|
61
|
-
})
|
|
62
|
-
expect(base.getConfig('x')).to.equal(3)
|
|
63
|
-
expect(base.getConfig('y')).to.equal(2)
|
|
64
|
-
expect(base.getConfig('z')).to.equal(1)
|
|
65
|
-
expect(base.getConfig('title')).to.equal('my app')
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('runs no-op lifecycle methods and exits by disposing', async () => {
|
|
69
|
-
const base = new Base('my-plugin', app)
|
|
70
|
-
|
|
71
|
-
await base.init()
|
|
72
|
-
await base.start()
|
|
73
|
-
await base.stop()
|
|
74
|
-
})
|
|
75
|
-
})
|
package/test/cache.test.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
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 fastGlob from 'fast-glob'
|
|
8
|
-
import lodash from 'lodash'
|
|
9
|
-
|
|
10
|
-
import Cache from '../class/cache.js'
|
|
11
|
-
|
|
12
|
-
const createTempRoot = () => fs.mkdtempSync(path.join(os.tmpdir(), 'bajo-cache-test-'))
|
|
13
|
-
|
|
14
|
-
describe('Cache', () => {
|
|
15
|
-
let root
|
|
16
|
-
let app
|
|
17
|
-
let cache
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
root = createTempRoot()
|
|
21
|
-
app = {
|
|
22
|
-
getPluginDataDir: () => path.join(root, 'bajo'),
|
|
23
|
-
bajo: {
|
|
24
|
-
breakNsPath: (name) => {
|
|
25
|
-
const [nsPart, p] = name.split(':')
|
|
26
|
-
const [ns, subNs] = nsPart.split('.')
|
|
27
|
-
return { ns, subNs, path: p }
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
lib: {
|
|
31
|
-
aneka: {
|
|
32
|
-
parseDuration: (v) => typeof v === 'number' ? v : 0
|
|
33
|
-
},
|
|
34
|
-
fs,
|
|
35
|
-
fastGlob,
|
|
36
|
-
_: lodash
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
cache = new Cache(app)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
if (root) fs.rmSync(root, { recursive: true, force: true })
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('prepares cache location only for namespaced key and non-zero ttl', () => {
|
|
47
|
-
expect(cache.prep('main:path', 0)).to.equal(undefined)
|
|
48
|
-
expect(cache.prep('main:path', 1000)).to.equal(undefined)
|
|
49
|
-
|
|
50
|
-
const prep = cache.prep('main.api:path/to/item', 1000)
|
|
51
|
-
expect(prep.file).to.include('/main/api/1000/path/to/item')
|
|
52
|
-
expect(fs.existsSync(prep.dir)).to.equal(true)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('saves and loads json/object content', async () => {
|
|
56
|
-
await cache.save('main.api:item', { a: 1 }, 1000)
|
|
57
|
-
const item = await cache.load('main.api:item', 1000)
|
|
58
|
-
|
|
59
|
-
expect(item).to.deep.equal({ a: 1 })
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('returns undefined for expired cache and removes ttl directory', async () => {
|
|
63
|
-
await cache.save('main.api:item', 'ok', 1)
|
|
64
|
-
const { dir } = cache.prep('main.api:item', 1)
|
|
65
|
-
const old = Date.now() - 5000
|
|
66
|
-
fs.utimesSync(dir, old / 1000, old / 1000)
|
|
67
|
-
|
|
68
|
-
const result = await cache.load('main.api:item', 1)
|
|
69
|
-
|
|
70
|
-
expect(result).to.equal(undefined)
|
|
71
|
-
expect(fs.existsSync(dir)).to.equal(false)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('purges by name and wildcard', () => {
|
|
75
|
-
const a = cache.prep('main.api:a', 1000)
|
|
76
|
-
const b = cache.prep('main.web:b', 1000)
|
|
77
|
-
fs.writeFileSync(a.file, 'a', 'utf8')
|
|
78
|
-
fs.writeFileSync(b.file, 'b', 'utf8')
|
|
79
|
-
|
|
80
|
-
cache.purge('main')
|
|
81
|
-
expect(fs.existsSync(cache.getRootDir() + '/main')).to.equal(false)
|
|
82
|
-
|
|
83
|
-
const c = cache.prep('other.api:c', 1000)
|
|
84
|
-
fs.writeFileSync(c.file, 'c', 'utf8')
|
|
85
|
-
cache._purgeItem('*')
|
|
86
|
-
expect(fs.existsSync(cache.getRootDir() + '/other')).to.equal(false)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('disposes app reference', async () => {
|
|
90
|
-
await cache.dispose()
|
|
91
|
-
|
|
92
|
-
expect(cache.app).to.equal(null)
|
|
93
|
-
})
|
|
94
|
-
})
|