bajo 1.1.2 → 1.1.4
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/bajo/intl/en-US.json +4 -2
- package/bajo/intl/id.json +4 -2
- package/boot/class/app.js +1 -1
- package/boot/class/bajo-core/build-config.js +4 -1
- package/boot/class/bajo-core/build-plugins.js +9 -2
- package/boot/class/bajo-core.js +17 -20
- package/boot/class/bajo-plugin.js +2 -2
- package/boot/class/log.js +17 -1
- package/boot/class/plugin.js +29 -1
- package/boot/lib/create-method.js +11 -8
- package/package.json +1 -1
package/bajo/intl/en-US.json
CHANGED
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"file": "File",
|
|
132
132
|
"applet": "Applet",
|
|
133
133
|
"unsupported%s%s": "Unsupported %s '%s'",
|
|
134
|
-
"error%": "Error: %s",
|
|
134
|
+
"error%s": "Error: %s",
|
|
135
135
|
"savedAs%%": "%s saved as '%s'",
|
|
136
136
|
"loaded%s": "Loaded %s",
|
|
137
137
|
"production": "production",
|
|
@@ -154,5 +154,7 @@
|
|
|
154
154
|
"thankYou": "Thank you!",
|
|
155
155
|
"adminArea": "Admin Area",
|
|
156
156
|
"instanceCreatedOnConn%s%s": "Instance '%s' created on connection '%s'",
|
|
157
|
-
"fileNotModuleHandler%s": "File '%s' is NOT a module handler"
|
|
157
|
+
"fileNotModuleHandler%s": "File '%s' is NOT a module handler",
|
|
158
|
+
"error%s%s%s": "%s error (%s): %s",
|
|
159
|
+
"invalid%s%s": "Invalid %s (%s)"
|
|
158
160
|
}
|
package/bajo/intl/id.json
CHANGED
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"file": "Berkas",
|
|
132
132
|
"applet": "Applet",
|
|
133
133
|
"unsupported%s%s": "%s '%s' tidak didukung",
|
|
134
|
-
"error%": "Kesalahan: %s",
|
|
134
|
+
"error%s": "Kesalahan: %s",
|
|
135
135
|
"savedAs%%": "%s disimpan sbg '%s'",
|
|
136
136
|
"loaded%s": "%s termuat",
|
|
137
137
|
"production": "produksi",
|
|
@@ -154,5 +154,7 @@
|
|
|
154
154
|
"thankYou": "Terima kasih!",
|
|
155
155
|
"adminArea": "Area Admin",
|
|
156
156
|
"instanceCreatedOnConn%s%s": "Instance '%s' telah dibuat pada koneksi '%s'",
|
|
157
|
-
"fileNotModuleHandler%s": "Berkas '%s' BUKAN merupakan module handler"
|
|
157
|
+
"fileNotModuleHandler%s": "Berkas '%s' BUKAN merupakan module handler",
|
|
158
|
+
"error%s%s%s": "Kesalahan %s (%s): %s",
|
|
159
|
+
"invalid%s%s": "%s tidak valid (%s)"
|
|
158
160
|
}
|
package/boot/class/app.js
CHANGED
|
@@ -60,7 +60,7 @@ class App {
|
|
|
60
60
|
// boot complete
|
|
61
61
|
const elapsed = new Date() - bajo.runAt
|
|
62
62
|
bajo.log.info('bootCompleted%s', bajo.secToHms(elapsed, true))
|
|
63
|
-
await bajo.runHook('bajo:
|
|
63
|
+
await bajo.runHook('bajo:afterBootComplete')
|
|
64
64
|
if (bajo.applet) await runAsApplet.call(bajo)
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -42,8 +42,10 @@ export async function buildBaseConfig () {
|
|
|
42
42
|
if (!get(this, 'dir.data')) set(this, 'dir.data', `${this.dir.base}/data`)
|
|
43
43
|
this.dir.data = this.resolvePath(this.dir.data)
|
|
44
44
|
if (!fs.existsSync(this.dir.data)) {
|
|
45
|
-
|
|
45
|
+
console.log('Data directory (%s) doesn\'t exist yet', this.dir.data)
|
|
46
|
+
process.exit(1)
|
|
46
47
|
}
|
|
48
|
+
fs.ensureDirSync(`${this.dir.data}/config`)
|
|
47
49
|
if (!this.dir.tmp) {
|
|
48
50
|
this.dir.tmp = `${this.resolvePath(os.tmpdir())}/${this.name}`
|
|
49
51
|
fs.ensureDirSync(this.dir.tmp)
|
|
@@ -71,4 +73,5 @@ export async function buildExtConfig () {
|
|
|
71
73
|
this.initPrint()
|
|
72
74
|
this.initLog()
|
|
73
75
|
this.log.debug('configHandlers%s', this.join(exts))
|
|
76
|
+
this.config = this.parseObject(this.config, { parseValue: true })
|
|
74
77
|
}
|
|
@@ -19,8 +19,15 @@ async function buildPlugins () {
|
|
|
19
19
|
this.pluginPkgs.push(this.mainNs)
|
|
20
20
|
for (const pkg of this.pluginPkgs) {
|
|
21
21
|
const ns = camelCase(pkg)
|
|
22
|
-
|
|
23
|
-
if (ns
|
|
22
|
+
let dir
|
|
23
|
+
if (ns === 'main') {
|
|
24
|
+
dir = `${this.dir.base}/${this.mainNs}`
|
|
25
|
+
fs.ensureDirSync(dir)
|
|
26
|
+
fs.ensureDirSync(`${dir}/plugin`)
|
|
27
|
+
} else {
|
|
28
|
+
dir = this.getModuleDir(pkg)
|
|
29
|
+
if (!fs.existsSync(`${dir}/plugin`)) throw new Error(`Package '${pkg}' isn't a valid Bajo package`)
|
|
30
|
+
}
|
|
24
31
|
let plugin
|
|
25
32
|
const factory = `${dir}/plugin/factory.js`
|
|
26
33
|
if (fs.existsSync(factory)) {
|
package/boot/class/bajo-core.js
CHANGED
|
@@ -28,7 +28,7 @@ const {
|
|
|
28
28
|
isFunction, words, upperFirst, map, concat, uniq, forOwn, padStart,
|
|
29
29
|
trim, filter, isEmpty, orderBy, pullAt, find, camelCase, isNumber,
|
|
30
30
|
cloneDeep, isPlainObject, isArray, isString, set, omit, keys, indexOf,
|
|
31
|
-
last, get, has, values, dropRight, mergeWith
|
|
31
|
+
last, get, has, values, dropRight, pick, mergeWith
|
|
32
32
|
} = lodash
|
|
33
33
|
|
|
34
34
|
class BajoCore extends Plugin {
|
|
@@ -113,14 +113,14 @@ class BajoCore extends Plugin {
|
|
|
113
113
|
|
|
114
114
|
breakNsPath = (item = '', defaultNs = 'bajo', checkNs = true) => {
|
|
115
115
|
let [ns, ...path] = item.split(':')
|
|
116
|
+
const fullNs = ns
|
|
116
117
|
let subNs
|
|
117
118
|
let subSubNs
|
|
118
119
|
path = path.join(':')
|
|
119
|
-
if (path.startsWith('//'))
|
|
120
|
-
|
|
121
|
-
path = ns
|
|
122
|
-
ns = defaultNs
|
|
120
|
+
if (path.startsWith('//')) {
|
|
121
|
+
return { path: item } // for: http:// etc
|
|
123
122
|
}
|
|
123
|
+
|
|
124
124
|
[ns, subNs, subSubNs] = ns.split('.')
|
|
125
125
|
if (checkNs) {
|
|
126
126
|
if (!this.app[ns]) {
|
|
@@ -133,7 +133,7 @@ class BajoCore extends Plugin {
|
|
|
133
133
|
let qs
|
|
134
134
|
[path, qs] = path.split('?')
|
|
135
135
|
qs = querystring.parse(qs) ?? {}
|
|
136
|
-
return { ns, path, subNs, subSubNs, qs, fullPath }
|
|
136
|
+
return { ns, path, subNs, subSubNs, qs, fullPath, fullNs }
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
buildCollections = async (options = {}) => {
|
|
@@ -163,14 +163,11 @@ class BajoCore extends Plugin {
|
|
|
163
163
|
if (deleted.length > 0) pullAt(items, deleted)
|
|
164
164
|
|
|
165
165
|
// check for duplicity
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const match = filter(items, checker)
|
|
172
|
-
if (match.length > 1) this.app[ns].fatal('oneOrMoreSharedTheSame%s%s', container, this.join(dupChecks.filter(i => !isFunction(i))))
|
|
173
|
-
}
|
|
166
|
+
if (dupChecks.length > 0) {
|
|
167
|
+
const checkers = []
|
|
168
|
+
for (const c of items) {
|
|
169
|
+
const checker = JSON.stringify(pick(c, dupChecks))
|
|
170
|
+
if (checkers.includes(checker)) this.app[ns].fatal('oneOrMoreSharedTheSame%s%s', container, this.join(dupChecks.filter(i => !isFunction(i))))
|
|
174
171
|
}
|
|
175
172
|
}
|
|
176
173
|
await this.runHook(`${ns}:${camelCase('afterBuildCollection')}`, container)
|
|
@@ -192,8 +189,12 @@ class BajoCore extends Plugin {
|
|
|
192
189
|
const applet = find(bajo.applets, a => (a.ns === ns || a.alias === ns))
|
|
193
190
|
if (applet) result = await bajo.runApplet(applet, path, ...args)
|
|
194
191
|
} else {
|
|
195
|
-
const method =
|
|
196
|
-
|
|
192
|
+
const [ns, method, ...params] = item.split(':')
|
|
193
|
+
const fn = bajo.getMethod(`${ns}:${method}`)
|
|
194
|
+
if (fn) {
|
|
195
|
+
if (params.length > 0) args.unshift(...params)
|
|
196
|
+
result = await fn(...args)
|
|
197
|
+
}
|
|
197
198
|
}
|
|
198
199
|
} else if (isFunction(item)) {
|
|
199
200
|
result = await item.call(scope, ...args)
|
|
@@ -691,7 +692,6 @@ class BajoCore extends Plugin {
|
|
|
691
692
|
if (isEmpty(fns)) return
|
|
692
693
|
fns = orderBy(fns, ['level'])
|
|
693
694
|
const results = []
|
|
694
|
-
const removed = []
|
|
695
695
|
for (const i in fns) {
|
|
696
696
|
const fn = fns[i]
|
|
697
697
|
const scope = this.app[fn.src]
|
|
@@ -700,11 +700,8 @@ class BajoCore extends Plugin {
|
|
|
700
700
|
hook: hookName,
|
|
701
701
|
resp: res
|
|
702
702
|
})
|
|
703
|
-
if (path.startsWith('once')) removed.push(i)
|
|
704
703
|
if (this.config.log.traceHook) scope.log.trace('hookExecuted%s', hookName)
|
|
705
704
|
}
|
|
706
|
-
if (removed.length > 0) pullAt(this.app.bajo.hooks, removed)
|
|
707
|
-
|
|
708
705
|
return results
|
|
709
706
|
}
|
|
710
707
|
|
|
@@ -13,7 +13,7 @@ class BajoPlugin extends Plugin {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
loadConfig = async () => {
|
|
16
|
-
const { log, getModuleDir, readJson, defaultsDeep } = this.app.bajo
|
|
16
|
+
const { log, getModuleDir, readJson, defaultsDeep, parseObject } = this.app.bajo
|
|
17
17
|
log.trace('- %s', this.name)
|
|
18
18
|
const dir = this.name === this.app.bajo.mainNs ? (`${this.app.bajo.dir.base}/${this.app.bajo.mainNs}`) : getModuleDir(this.pkgName)
|
|
19
19
|
let cfg = await readAllConfigs.call(this.app, `${dir}/plugin/config`)
|
|
@@ -46,7 +46,7 @@ class BajoPlugin extends Plugin {
|
|
|
46
46
|
this.dependencies = this.dependencies ?? []
|
|
47
47
|
const depFile = `${dir}/plugin/.dependencies`
|
|
48
48
|
if (fs.existsSync(depFile)) this.dependencies = without(fs.readFileSync(depFile, 'utf8').split('\n').map(item => trim(item)), '')
|
|
49
|
-
this.config = omit(cfg, ['title', 'dependencies'])
|
|
49
|
+
this.config = parseObject(omit(cfg, ['title', 'dependencies']), { parseValue: true })
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
_onoff = async (item, ...args) => {
|
package/boot/class/log.js
CHANGED
|
@@ -5,6 +5,18 @@ import logLevels from '../lib/log-levels.js'
|
|
|
5
5
|
|
|
6
6
|
const { isEmpty, without, merge, upperFirst } = lodash
|
|
7
7
|
|
|
8
|
+
export function isIgnored (level) {
|
|
9
|
+
const { filter, isArray } = this.lib._
|
|
10
|
+
let ignore = this.app.bajo.config.log.ignore ?? []
|
|
11
|
+
if (!isArray(ignore)) ignore = [ignore]
|
|
12
|
+
const items = filter(ignore, i => {
|
|
13
|
+
const [ns, lvl] = i.split(':')
|
|
14
|
+
if (lvl) return ns === this.name && lvl === level
|
|
15
|
+
return ns === this.name
|
|
16
|
+
})
|
|
17
|
+
return items.length > 0
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
class Log {
|
|
9
21
|
constructor (plugin) {
|
|
10
22
|
this.plugin = plugin
|
|
@@ -23,6 +35,10 @@ class Log {
|
|
|
23
35
|
return this.plugin.app[this.bajoLog] && this.plugin.app[this.bajoLog].logger
|
|
24
36
|
}
|
|
25
37
|
|
|
38
|
+
isIgnored = level => {
|
|
39
|
+
return isIgnored.call(this.plugin, level)
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
child = () => {
|
|
27
43
|
if (this.isExtLogger()) return this.plugin.app[this.bajoLog].logger.child()
|
|
28
44
|
return this.plugin.app
|
|
@@ -53,7 +69,7 @@ class Log {
|
|
|
53
69
|
text = `[${dayjs(dt).utc(true).format(this.format)}] ${upperFirst(level)}: ${msg}`
|
|
54
70
|
if (!isEmpty(data)) text += '\n' + JSON.stringify(data)
|
|
55
71
|
}
|
|
56
|
-
console.log(text)
|
|
72
|
+
if (!this.isIgnored(level)) console.log(text)
|
|
57
73
|
}
|
|
58
74
|
}
|
|
59
75
|
}
|
package/boot/class/plugin.js
CHANGED
|
@@ -3,6 +3,33 @@ import omittedPluginKeys from '../lib/omitted-plugin-keys.js'
|
|
|
3
3
|
import Log from './log.js'
|
|
4
4
|
import Print from './print.js'
|
|
5
5
|
import BajoError from './error.js'
|
|
6
|
+
import fastGlob from 'fast-glob'
|
|
7
|
+
import { sprintf } from 'sprintf-js'
|
|
8
|
+
import outmatch from 'outmatch'
|
|
9
|
+
import dayjs from '../lib/dayjs.js'
|
|
10
|
+
import fs from 'fs-extra'
|
|
11
|
+
|
|
12
|
+
function outmatchNs (source, pattern) {
|
|
13
|
+
const { breakNsPath } = this.app.bajo
|
|
14
|
+
const [src, subSrc] = source.split(':')
|
|
15
|
+
if (!subSrc) return pattern === src
|
|
16
|
+
try {
|
|
17
|
+
const { fullNs, path } = breakNsPath(pattern)
|
|
18
|
+
const isMatch = outmatch(path)
|
|
19
|
+
return src === fullNs && isMatch(subSrc)
|
|
20
|
+
} catch (err) {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const lib = {
|
|
26
|
+
_: lodash,
|
|
27
|
+
fs,
|
|
28
|
+
fastGlob,
|
|
29
|
+
sprintf,
|
|
30
|
+
outmatch,
|
|
31
|
+
dayjs
|
|
32
|
+
}
|
|
6
33
|
|
|
7
34
|
const { get, isEmpty, cloneDeep, omit, isPlainObject, camelCase } = lodash
|
|
8
35
|
|
|
@@ -12,7 +39,8 @@ class Plugin {
|
|
|
12
39
|
this.name = camelCase(pkgName)
|
|
13
40
|
this.app = app
|
|
14
41
|
this.config = {}
|
|
15
|
-
this.lib =
|
|
42
|
+
this.lib = lib
|
|
43
|
+
this.lib.outmatchNs = outmatchNs.bind(this)
|
|
16
44
|
this.exitHandler = undefined
|
|
17
45
|
}
|
|
18
46
|
|
|
@@ -3,11 +3,12 @@ import path from 'path'
|
|
|
3
3
|
import lodash from 'lodash'
|
|
4
4
|
import resolvePath from './resolve-path.js'
|
|
5
5
|
|
|
6
|
-
const { camelCase, isFunction
|
|
6
|
+
const { camelCase, isFunction } = lodash
|
|
7
7
|
|
|
8
8
|
export default async function (dir, pkg = 'bajo') {
|
|
9
9
|
dir = resolvePath(dir)
|
|
10
10
|
const files = await fastGlob([`!${dir}/**/_*.{js,json}`, `${dir}/**/*.{js,json}`])
|
|
11
|
+
const me = this
|
|
11
12
|
for (const f of files) {
|
|
12
13
|
const ext = path.extname(f)
|
|
13
14
|
const base = f.replace(dir, '').replace(ext, '')
|
|
@@ -16,13 +17,15 @@ export default async function (dir, pkg = 'bajo') {
|
|
|
16
17
|
if (ext === '.json') mod = this.app.bajo.readJson(f)
|
|
17
18
|
else mod = await this.app.bajo.importModule(f)
|
|
18
19
|
if (isFunction(mod)) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
const fn = mod.bind(this)
|
|
21
|
+
if (mod.constructor.name === 'AsyncFunction') {
|
|
22
|
+
mod = async (...args) => {
|
|
23
|
+
await me.app.bajo.runHook(`${me.name}.${name}:beforeExec`, ...args)
|
|
24
|
+
const result = await fn(...args)
|
|
25
|
+
await me.app.bajo.runHook(`${me.name}.${name}:afterExec`, result, ...args)
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
28
|
+
} else mod = fn
|
|
26
29
|
}
|
|
27
30
|
this[name] = mod
|
|
28
31
|
}
|