bajo 2.1.0 → 2.2.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 (99) hide show
  1. package/.github/FUNDING.yml +0 -0
  2. package/.github/workflows/repo-lockdown.yml +0 -0
  3. package/.jsdoc.conf.json +0 -0
  4. package/.mocharc.json +4 -0
  5. package/LICENSE +0 -0
  6. package/README.md +0 -0
  7. package/class/{misc → app}/log.js +8 -2
  8. package/class/app.js +63 -50
  9. package/class/bajo.js +43 -211
  10. package/class/base.js +25 -22
  11. package/class/helper/bajo.js +55 -53
  12. package/class/helper/base.js +34 -75
  13. package/class/{misc → plugin}/err.js +23 -18
  14. package/class/{misc → plugin}/print.js +7 -16
  15. package/class/plugin/tools.js +42 -0
  16. package/class/plugin.js +58 -54
  17. package/docs/App.html +0 -0
  18. package/docs/Bajo.html +0 -0
  19. package/docs/Base.html +0 -0
  20. package/docs/Err.html +0 -0
  21. package/docs/Log.html +0 -0
  22. package/docs/Plugin.html +0 -0
  23. package/docs/Print.html +0 -0
  24. package/docs/class_app.js.html +0 -0
  25. package/docs/class_bajo.js.html +0 -0
  26. package/docs/class_base.js.html +0 -0
  27. package/docs/class_helper_bajo.js.html +0 -0
  28. package/docs/class_helper_base.js.html +0 -0
  29. package/docs/class_misc_err.js.html +0 -0
  30. package/docs/class_misc_log.js.html +0 -0
  31. package/docs/class_misc_print.js.html +0 -0
  32. package/docs/class_plugin.js.html +0 -0
  33. package/docs/data/search.json +0 -0
  34. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  35. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  36. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  37. package/docs/global.html +0 -0
  38. package/docs/index.html +0 -0
  39. package/docs/index.js.html +0 -0
  40. package/docs/lib_current-loc.js.html +0 -0
  41. package/docs/lib_formats.js.html +0 -0
  42. package/docs/lib_import-module.js.html +0 -0
  43. package/docs/lib_log-levels.js.html +0 -0
  44. package/docs/lib_parse-args-argv.js.html +0 -0
  45. package/docs/lib_parse-env.js.html +0 -0
  46. package/docs/lib_resolve-path.js.html +0 -0
  47. package/docs/lib_shim.js.html +0 -0
  48. package/docs/module-Helper_Bajo.html +0 -0
  49. package/docs/module-Helper_Base.html +0 -0
  50. package/docs/module-Lib.html +0 -0
  51. package/docs/scripts/core.js +476 -477
  52. package/docs/scripts/core.min.js +0 -0
  53. package/docs/scripts/resize.js +36 -36
  54. package/docs/scripts/search.js +105 -105
  55. package/docs/scripts/search.min.js +0 -0
  56. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -0
  57. package/docs/scripts/third-party/fuse.js +1 -1
  58. package/docs/scripts/third-party/hljs-line-num-original.js +282 -285
  59. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  60. package/docs/scripts/third-party/hljs-original.js +1195 -1202
  61. package/docs/scripts/third-party/hljs.js +1 -1
  62. package/docs/scripts/third-party/popper.js +1 -1
  63. package/docs/scripts/third-party/tippy.js +1 -1
  64. package/docs/scripts/third-party/tocbot.js +508 -509
  65. package/docs/scripts/third-party/tocbot.min.js +0 -0
  66. package/docs/static/bitcoin.jpeg +0 -0
  67. package/docs/static/home.md +0 -0
  68. package/docs/static/logo-ecosystem.png +0 -0
  69. package/docs/static/logo.png +0 -0
  70. package/docs/styles/clean-jsdoc-theme-base.css +0 -0
  71. package/docs/styles/clean-jsdoc-theme-dark.css +0 -0
  72. package/docs/styles/clean-jsdoc-theme-light.css +0 -0
  73. package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -0
  74. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -0
  75. package/docs/styles/clean-jsdoc-theme.min.css +0 -0
  76. package/extend/bajo/intl/en-US.json +10 -5
  77. package/extend/bajo/intl/id.json +10 -5
  78. package/extend/waibuStatic/virtual.json +0 -0
  79. package/index.js +9 -1
  80. package/lib/find-deep.js +24 -0
  81. package/lib/formats.js +0 -0
  82. package/lib/freeze.js +16 -0
  83. package/lib/import-module.js +5 -3
  84. package/lib/index.js +6 -0
  85. package/lib/log-levels.js +0 -0
  86. package/package.json +5 -11
  87. package/test/base.test.js +108 -0
  88. package/wiki/CHANGES.md +63 -0
  89. package/wiki/CONFIG.md +0 -0
  90. package/wiki/CONTRIBUTING.md +0 -0
  91. package/wiki/DEV_GUIDE.md +0 -0
  92. package/wiki/ECOSYSTEM.md +0 -0
  93. package/wiki/GETTING-STARTED.md +1 -1
  94. package/wiki/USER-GUIDE.md +0 -0
  95. package/lib/current-loc.js +0 -33
  96. package/lib/parse-args-argv.js +0 -80
  97. package/lib/parse-env.js +0 -50
  98. package/lib/resolve-path.js +0 -24
  99. package/lib/shim.js +0 -37
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -23,11 +23,10 @@
23
23
  "setupBootOrder": "Setup boot order",
24
24
  "configHandlers%s": "Config handlers: %s",
25
25
  "dataDir%s": "Data dir: %s",
26
- "exited": "Exited",
26
+ "exited%s": "- %s exited",
27
27
  "appShutdown": "App shutdown",
28
28
  "appletModeActivated": "Applet mode activated",
29
- "collected%s%d": "%s collected: %d",
30
- "attachMethods": "Attach methods",
29
+ "collected%s%d": "Collected %s: %d",
31
30
  "readConfigs": "Read configurations",
32
31
  "checkAliasNameClash": "Checking alias & name clashes",
33
32
  "checkDeps": "Checking dependencies",
@@ -127,7 +126,7 @@
127
126
  "offlineL": "offline",
128
127
  "reconnectingL": "reconnecting",
129
128
  "connMustHave%s": "Connection must have '%s'",
130
- "notFound%s%s": "%s '%s' not found",
129
+ "notFound%s%s": "%s|upperFirst '%s' not found",
131
130
  "connection": "Connection",
132
131
  "file": "File",
133
132
  "applet": "Applet",
@@ -175,5 +174,11 @@
175
174
  "buildPluginsComplete": "Building plugins completed",
176
175
  "pluginPackageNotFound%s": "Plugin package '%s' file not found!",
177
176
  "pluginPackageInvalid%s": "`Plugin package '%s' should be an instance of Base class`",
178
- "appletNeedsBajoCli": "Applet needs to have 'bajo-cli' loaded"
177
+ "appletNeedsBajoCli": "Applet needs to have 'bajo-cli' loaded",
178
+ "unknown%s%s": "Unknown %s|toLower '%s'",
179
+ "notImplemented%s%s": "%s|upperFirst '%s' not implemented yet",
180
+ "method": "Method",
181
+ "exist%s%s": "%s|upperFirst '%s' exists already",
182
+ "fieldError%s%s": "'%s': %s|lowerFirst",
183
+ "reservedName%s%s": "%s|upperFirst name '%s' is a reserved name. Please rename to something else"
179
184
  }
@@ -23,11 +23,10 @@
23
23
  "setupBootOrder": "Atur urutan booting",
24
24
  "configHandlers%s": "Pengatur konfigurasi: %s",
25
25
  "dataDir%s": "Dir data: %s",
26
- "exited": "Exited",
26
+ "exited%s": "- %s keluar",
27
27
  "appShutdown": "Aplikasi ditutup",
28
28
  "appletModeActivated": "Mode applet diaktifkan",
29
- "collected%s%d": "%s terkoleksi: %d",
30
- "attachMethods": "Tempelkan metode",
29
+ "collected%s%d": "%s|upperFirst terkoleksi: %d",
31
30
  "readConfigs": "Baca konfigurasi",
32
31
  "checkAliasNameClash": "Cek bentrokan nama dan alias",
33
32
  "checkDeps": "Cek ketergantungan",
@@ -127,7 +126,7 @@
127
126
  "offlineL": "offline",
128
127
  "reconnectingL": "mencoba menghubung kembali",
129
128
  "connMustHave%s": "Koneksi harus memiliki '%s'",
130
- "notFound%s%s": "%s '%s' tidak ditemukan",
129
+ "notFound%s%s": "%s|upperFirst '%s' tidak ditemukan",
131
130
  "connection": "Koneksi",
132
131
  "file": "Berkas",
133
132
  "applet": "Applet",
@@ -175,5 +174,11 @@
175
174
  "buildPluginsComplete": "Pemuatan plugin komplit",
176
175
  "pluginPackageNotFound%s": "Berkas paket plugin '%s' tidak ditemukan!",
177
176
  "pluginPackageInvalid%s": "Paket plugin '%s' harus berupa instan dari kelas Base",
178
- "appletNeedsBajoCli": "Applet membutuhkan 'bajo-cli' yang harus termuat terlebih dahulu"
177
+ "appletNeedsBajoCli": "Applet membutuhkan 'bajo-cli' yang harus termuat terlebih dahulu",
178
+ "unknown%s%s": "%s|upperFirst '%s' tidak dikenal",
179
+ "notImplemented%s%s": "%s|upperFirst '%s' belum diimplementasikan",
180
+ "method": "Metode",
181
+ "exist%s%s": "%s|upperFirst '%s' sudah ada",
182
+ "fieldError%s%s": "'%s': %s|lowerFirst",
183
+ "reservedName%s%s": "Nama %s|lowerFirst '%s' adalah nama tang di reserve. Silahkan gunakan nama lainnya"
179
184
  }
File without changes
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import App from './class/app.js'
2
- import shim from './lib/shim.js'
2
+ import { shim } from 'aneka'
3
+ import fs from 'fs-extra'
3
4
 
4
5
  shim()
5
6
 
@@ -25,6 +26,13 @@ shim()
25
26
  * @returns {App}
26
27
  */
27
28
  async function boot (cwd) {
29
+ if (!cwd) cwd = process.cwd()
30
+ const pkgFile = `${cwd}/package.json`
31
+ const pkg = fs.readJsonSync(pkgFile)
32
+ if (pkg.type !== 'module') {
33
+ console.error(`Please turn on ES6 parsing by adding "type": "module" to ${pkgFile}!`)
34
+ process.exit(1)
35
+ }
28
36
  const app = new App(cwd)
29
37
  return await app.boot()
30
38
  }
@@ -0,0 +1,24 @@
1
+ import fs from 'fs'
2
+
3
+ /**
4
+ * Find item deep in paths
5
+ *
6
+ * @method
7
+ * @memberof module:Lib
8
+ * @param {string} item - Item to find
9
+ * @param {Array} paths - Array of path to look for
10
+ * @returns {string}
11
+ */
12
+ function findDeep (item, paths) {
13
+ let dir
14
+ for (const p of paths) {
15
+ const d = `${p}/${item}`
16
+ if (fs.existsSync(d)) {
17
+ dir = d
18
+ break
19
+ }
20
+ }
21
+ return dir
22
+ }
23
+
24
+ export default findDeep
package/lib/formats.js CHANGED
File without changes
package/lib/freeze.js ADDED
@@ -0,0 +1,16 @@
1
+ import deepFreezeStrict from 'deep-freeze-strict'
2
+
3
+ /**
4
+ * Freeze object
5
+ *
6
+ * @method
7
+ * @memberof module:Lib
8
+ * @param {Object} obj - Object to freeze
9
+ * @param {boolean} [shallow=false] - If ```false``` (default), deep freeze object
10
+ */
11
+ function freeze (obj, shallow = false) {
12
+ if (shallow) Object.freeze(obj)
13
+ else deepFreezeStrict(obj)
14
+ }
15
+
16
+ export default freeze
@@ -1,6 +1,8 @@
1
- import resolvePath from './resolve-path.js'
2
1
  import fs from 'fs-extra'
3
2
  import lodash from 'lodash'
3
+ import aneka from 'aneka'
4
+
5
+ const { resolvePath } = aneka
4
6
  const { isFunction, isPlainObject } = lodash
5
7
 
6
8
  /**
@@ -32,8 +34,8 @@ const { isFunction, isPlainObject } = lodash
32
34
  * @returns {any}
33
35
  * @see Bajo#importModule
34
36
  */
35
- async function importModule (file, { asDefaultImport, asHandler, noCache } = {}) {
36
- const load = async (file, asDefaultImport = true, noCache = false) => {
37
+ async function importModule (file, { asDefaultImport = true, asHandler, noCache } = {}) {
38
+ const load = async (file, asDefaultImport, noCache = false) => {
37
39
  file = resolvePath(file, true)
38
40
  if (noCache) file += `?_=${Date.now()}`
39
41
  const imported = await import(file)
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * External helpers you can use by importing its file directly
3
+ *
4
+ * @name Lib
5
+ * @module Lib
6
+ */
package/lib/log-levels.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "bajo",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "The ultimate framework for whipping up massive apps in no time",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "build-doc": "jsdoc -c .jsdoc.conf.json",
8
- "test": "mocha"
8
+ "test": "mocha --recursive"
9
9
  },
10
10
  "type": "module",
11
11
  "repository": {
@@ -26,29 +26,23 @@
26
26
  "homepage": "https://github.com/ardhi/bajo#readme",
27
27
  "dependencies": {
28
28
  "add-filename-increment": "^1.0.0",
29
- "aneka": "^0.1.5",
29
+ "aneka": "^0.10.0",
30
30
  "chalk": "^5.6.0",
31
31
  "dayjs": "^1.11.13",
32
32
  "deep-freeze-strict": "^1.1.1",
33
33
  "delay": "^6.0.0",
34
- "dotenv": "^17.2.1",
35
- "dotenv-parse-variables": "^2.0.0",
36
34
  "empty-dir": "^3.0.0",
37
35
  "fast-glob": "^3.3.3",
38
- "flat": "^6.0.1",
39
36
  "fs-extra": "^11.3.1",
40
37
  "get-global-path": "^0.0.1",
41
38
  "lodash": "^4.17.21",
42
- "ms": "^2.1.3",
43
- "nanoid": "^5.1.5",
44
39
  "omit-deep": "^0.3.0",
45
40
  "ora": "^8.2.0",
46
41
  "outmatch": "^1.0.0",
47
- "semver": "^7.7.2",
48
- "sprintf-js": "^1.1.3",
49
- "yargs": "^18.0.0"
42
+ "semver": "^7.7.2"
50
43
  },
51
44
  "devDependencies": {
45
+ "chai": "^6.2.1",
52
46
  "clean-jsdoc-theme": "^4.3.0",
53
47
  "docdash": "^2.0.2"
54
48
  }
@@ -0,0 +1,108 @@
1
+ import { expect } from 'chai'
2
+ import Base from '../class/base.js'
3
+
4
+ function makeMockApp ({ mainNs = 'app-main', throwOnDataConfig = false } = {}) {
5
+ // small lodash-like helpers used by Base.loadConfig
6
+ const _ = {
7
+ get: (obj, path, defVal) => {
8
+ if (!obj) return defVal
9
+ const parts = String(path).split('.')
10
+ let cur = obj
11
+ for (const p of parts) {
12
+ if (cur == null) return defVal
13
+ cur = cur[p]
14
+ }
15
+ return cur === undefined ? defVal : cur
16
+ },
17
+ kebabCase: s => String(s).replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase(),
18
+ keys: obj => obj ? Object.keys(obj) : [],
19
+ pick: (obj, keys) => {
20
+ const out = {}
21
+ if (!obj) return out
22
+ for (const k of keys) if (k in obj) out[k] = obj[k]
23
+ return out
24
+ }
25
+ }
26
+
27
+ // simple defaultsDeep-ish helper suitable for these tests:
28
+ // later objects in args take precedence over earlier ones (shallow)
29
+ const defaultsDeep = (...objs) => Object.assign({}, ...objs.filter(Boolean))
30
+
31
+ // bajo helpers (file reads etc). readAllConfigs will be called twice by Base.loadConfig:
32
+ // - once for module dir config
33
+ // - once for data dir config (may throw)
34
+ let readAllCalls = 0
35
+ const readAllConfigs = async (path) => {
36
+ readAllCalls += 1
37
+ if (throwOnDataConfig && readAllCalls === 2) throw new Error('readAllConfigs data dir error')
38
+ // return a small config object to test merge/path logic
39
+ return { alpha: 'file', title: 'FromFile', other: 'ignore-me' }
40
+ }
41
+
42
+ return {
43
+ mainNs,
44
+ lib: { aneka: { defaultsDeep }, _ },
45
+ bajo: {
46
+ dir: { base: '/base', data: '/data' },
47
+ readAllConfigs,
48
+ readJson: async (p) => ({ name: 'bajo-foo', version: '1.2.3', description: 'pkg' }),
49
+ parseObject: (o) => o,
50
+ getModuleDir: (pkgName) => `/modules/${pkgName}`,
51
+ log: { trace: () => {} }
52
+ },
53
+ env: {},
54
+ argv: {}
55
+ }
56
+ }
57
+
58
+ describe('Base.loadConfig', () => {
59
+ it('derives alias from pkgName starting with "bajo-" using kebabCase', async () => {
60
+ const app = makeMockApp()
61
+ const inst = new Base('bajo-MyPlugin', app)
62
+ // ensure namespace used by loadConfig
63
+ inst.ns = 'myplugin'
64
+ // set an initial config shape so defKeys isn't empty
65
+ inst.config = { alpha: 'default', title: 'Default' }
66
+
67
+ await inst.loadConfig()
68
+
69
+ // alias is stored on the constructor
70
+ expect(inst.constructor.alias).to.equal('my-plugin')
71
+ // dir pkg should be set according to mainNs mismatch
72
+ expect(inst.dir.pkg).to.equal('/modules/bajo-MyPlugin')
73
+ // config should keep keys only from defKeys (alpha & title), parseObject ran (no throw)
74
+ expect(Object.keys(inst.config)).to.include('alpha')
75
+ expect(Object.keys(inst.config)).to.include('title')
76
+ })
77
+
78
+ it('when ns === app.mainNs uses app.mainNs as alias and sets title to alias', async () => {
79
+ const app = makeMockApp({ mainNs: 'mainns' })
80
+ const inst = new Base('bajo-mainpkg', app)
81
+ inst.ns = 'mainns'
82
+ inst.config = { title: undefined } // start with no title
83
+
84
+ await inst.loadConfig()
85
+
86
+ expect(inst.constructor.alias).to.equal('mainns')
87
+ // title should be set to alias when ns is mainNs
88
+ expect(inst.title).to.equal(inst.constructor.alias)
89
+ })
90
+
91
+ it('continues when readAllConfigs for data dir throws (tolerant behavior)', async () => {
92
+ const app = makeMockApp({ throwOnDataConfig: true })
93
+ const inst = new Base('bajo-throwtest', app)
94
+ inst.ns = 'throwtest'
95
+ inst.config = { alpha: 'start' }
96
+
97
+ // should not throw even if second readAllConfigs throws
98
+ let threw = false
99
+ try {
100
+ await inst.loadConfig()
101
+ } catch (err) {
102
+ threw = true
103
+ }
104
+ expect(threw).to.equal(false)
105
+ // config should still be an object and title present (or undefined but not crash)
106
+ expect(inst.config).to.be.an('object')
107
+ })
108
+ })
@@ -0,0 +1,63 @@
1
+ # Changes
2
+
3
+ ## 2026-01-11
4
+
5
+ - [2.2.0] Simplify numerous things by putting most of static properties back as normal class properties
6
+
7
+ ## 2025-12-29
8
+
9
+ - [2.2.0] Add ```this.selfBind()``` to class ```Plugin```
10
+
11
+ ## 2025-12-27
12
+
13
+ - [2.2.0] Add some translations
14
+
15
+ ## 2025-12-27
16
+
17
+ - [2.2.0] Add config object ```this.config.runtime``` to adjust some runtime settings
18
+
19
+ ## 2025-12-24
20
+
21
+ - [2.2.0] Pass ```true``` to ```this.app.exit()``` to exit abruptly. Defaults to ```SIGINT```
22
+ - [2.2.0] Add ```detailsMessage``` to ```Err``` class if error object has ```details``` in payload
23
+ - [2.2.0] Upgrade ```aneka@0.10.0```
24
+ - [2.2.0] Bugfix: program arguments should not parsed as object
25
+
26
+ ## 2025-12-21
27
+
28
+ - [2.2.0] ```runHook()``` now accept both ```alias``` & ```ns``` prefixed name
29
+ - [2.2.0] In case of unknown plugin or plugin isn't loaded, ```runHook``` simply exit silently
30
+ - [2.2.0] ```this.app.pluginClass``` is now ```this.app.baseClass``` and all containing class definition keys are pascal cased to match with their constructor names
31
+
32
+ ## 2025-12-20
33
+
34
+ - [2.2.0] Removing dynamically attached methods because its problematic and leads to confusion
35
+
36
+ ## 2025-12-19
37
+
38
+ - [2.2.0] Upgrade to ```aneka@0.9.0```
39
+
40
+ ## 2025-12-13
41
+
42
+ - [2.2.0] Add ```app.lib.formatText()```
43
+ - [2.2.0] Move most bajo methods that doesn't relate to Bajo to app.lib functions
44
+
45
+ ## 2025-12-11
46
+
47
+ - [2.1.1] Upgrade to ```aneka@0.5.0```
48
+
49
+ ## 2025-12-09
50
+
51
+ - [2.1.1] Upgrade to ```aneka@0.2.3```
52
+ - [2.1.1] Some organizatory file location changes
53
+ - [2.1.1] Typo on class ```Tools```
54
+
55
+ ## 2025-12-05
56
+
57
+ - [2.1.1] Upgrade to ```aneka@0.2.1```
58
+ - [2.1.1] New class ```Tools```, serves as anchestor for ```Err``` & ```Print```
59
+
60
+ ## 2025-12-03
61
+
62
+ - [2.1.1] Add method ```getPkgInfo()``` to plugins main class.
63
+ - [2.1.1] Now you can put your plugins either in ```{dataDir}/config/.plugins``` or directly as an array in your app ```package.json``` under the ```bajo.plugins``` tree. The later takes precedence.
package/wiki/CONFIG.md CHANGED
File without changes
File without changes
package/wiki/DEV_GUIDE.md CHANGED
File without changes
package/wiki/ECOSYSTEM.md CHANGED
File without changes
@@ -139,7 +139,7 @@ This file is the main plugin factory. It gets created automatically if it's not
139
139
  async function factory (pkgName) {
140
140
  const me = this
141
141
 
142
- return class Main extends this.app.pluginClass.base {
142
+ return class Main extends this.app.baseClass.Base {
143
143
  constructor () {
144
144
  super(pkgName, me.app)
145
145
  this.config = {}
File without changes
@@ -1,33 +0,0 @@
1
- import path from 'path'
2
- import resolvePath from './resolve-path.js'
3
- import { fileURLToPath } from 'url'
4
-
5
- /**
6
- * Get current directory & file. An attempt to brings back the old ```__dirname``` and ```__filename```
7
- * to the ES6 era.
8
- *
9
- * Returns object with the following keys:
10
- * - ```__dirname``` (aliases to ```dir```) - current directory name
11
- * - ```__filename``` (aliases to ```file```) - current file path
12
- *
13
- * Example:
14
- * ```javascript
15
- * const { importModule } = this.app.bajo
16
- * const currentLoc = await importModule('bajo:/lib/current-loc.js')
17
- *
18
- * const { __dirname, __filename } = currentLoc(import.meta)
19
- * console.log(__dirname, __filename)
20
- * ```
21
- *
22
- * @method
23
- * @memberof module:Lib
24
- * @param {Object} metaImport - ```import.meta``` object
25
- * @returns {Object}
26
- */
27
- const currentLoc = (metaImport) => {
28
- const file = resolvePath(fileURLToPath(metaImport.url))
29
- const dir = path.dirname(file)
30
- return { dir, file, __dirname: dir, __filename: file }
31
- }
32
-
33
- export default currentLoc
@@ -1,80 +0,0 @@
1
- import yargs from 'yargs'
2
- import { Parser } from 'yargs/helpers'
3
- import { unflatten } from 'flat'
4
- import dotenvParseVariables from 'dotenv-parse-variables'
5
- import lodash from 'lodash'
6
- import fs from 'fs-extra'
7
- import path from 'path'
8
-
9
- const { find, each, set, camelCase, forOwn } = lodash
10
- const delimiter = '-'
11
- const splitter = ':'
12
-
13
- const parseItem = (data, delimiter) => {
14
- return unflatten(data, {
15
- delimiter,
16
- safe: true,
17
- overwrite: true
18
- })
19
- }
20
-
21
- async function parseWithParser () {
22
- return Parser(process.argv.slice(2), {
23
- configuration: {
24
- 'camel-case-expansion': false
25
- }
26
- })
27
- }
28
-
29
- async function parseWithYargs () {
30
- const pkg = fs.readJSONSync(`${this.dir}/package.json`)
31
- let name = `node ${pkg.main}`
32
- if (pkg.bin) name = path.basename(pkg.bin, '.js')
33
- const cli = yargs(process.argv.slice(2))
34
- .usage('Usage: $0 [args...]')
35
- .scriptName(name)
36
- .positional('args', {
37
- describe: 'Optional one or more arguments'
38
- })
39
- .parserConfiguration({
40
- 'camel-case-expansion': false
41
- })
42
- .version(pkg.version).alias('version', 'v')
43
- .help().alias('help', 'h')
44
- .alias('applet', 'a')
45
- if (pkg.homepage) cli.epilog(`For more information please visit ${pkg.homepage}`)
46
- return cli.argv
47
- }
48
-
49
- /**
50
- * Parse program arguments (args) & options (argv). See {@link App#args|args} & {@link App#argv|argv} for examples
51
- *
52
- * @method
53
- * @async
54
- * @memberof module:Lib
55
- * @param {boolean} [useParser] - If ```true```, skip {@link https://github.com/yargs/yargs|yargs}
56
- * @returns {{args: Array, argv: Object}} An object containing ```args``` and ```argv```
57
- * @see App#args
58
- * @see App#argv
59
- */
60
- async function parseArgsArgv (useParser) {
61
- if (!useParser) useParser = find(process.argv, a => a.startsWith('--spawn'))
62
- let argv = useParser ? await parseWithParser.call(this) : await parseWithYargs.call(this)
63
- const args = argv._
64
- delete argv._
65
- delete argv.$0
66
- argv = dotenvParseVariables(argv)
67
- const all = { _: {} }
68
- each(argv, (v, k) => {
69
- const parts = k.split(splitter)
70
- if (!parts[1]) all._[parts[0]] = v
71
- else set(all, `${camelCase(parts[0])}.${parts[1]}`, v)
72
- })
73
- const result = {}
74
- forOwn(all, (v, k) => {
75
- result[k] = parseItem(v, delimiter)
76
- })
77
- return { args, argv: this.bajo.parseObject(result, { parseValue: true }) }
78
- }
79
-
80
- export default parseArgsArgv
package/lib/parse-env.js DELETED
@@ -1,50 +0,0 @@
1
- import dotenvParseVariables from 'dotenv-parse-variables'
2
- import { unflatten } from 'flat'
3
- import dotEnv from 'dotenv'
4
- import lodash from 'lodash'
5
-
6
- const { each, set, camelCase, forOwn } = lodash
7
- const parse = (data, delimiter) => {
8
- return unflatten(data, {
9
- delimiter,
10
- safe: true,
11
- overwrite: true,
12
- transformKey: k => {
13
- return camelCase(k.toLowerCase())
14
- }
15
- })
16
- }
17
-
18
- const delimiter = '__'
19
- const splitter = '.'
20
-
21
- /**
22
- * Parse environment variables. See {@link App#envVars|envVars} for examples
23
- *
24
- * @method
25
- * @memberof module:Lib
26
- * @returns {Object}
27
- * @see App#envVars
28
- */
29
- function parseEnv () {
30
- let env
31
- try {
32
- env = dotEnv.config({ quiet: true })
33
- } catch (err) {
34
- }
35
- env = dotenvParseVariables(process.env, { assignToProcessEnv: false })
36
- const all = { _: {} }
37
- each(env, (v, k) => {
38
- const parts = k.split(splitter)
39
- if (!parts[1]) all._[parts[0]] = v
40
- else set(all, `${camelCase(parts[0])}.${parts[1]}`, v)
41
- })
42
- const result = {}
43
- forOwn(all, (v, k) => {
44
- result[k] = parse(v, delimiter)
45
- })
46
- if (result._.lang) result._.lang = result._.lang.split('.')[0].replaceAll('_', '-')
47
- return this.bajo.parseObject(result, { parseValue: true })
48
- }
49
-
50
- export default parseEnv
@@ -1,24 +0,0 @@
1
- import path from 'path'
2
- import { fileURLToPath } from 'url'
3
- import os from 'os'
4
-
5
- /**
6
- * Resolve file name to filesystem's path. Windows path separator ```\```
7
- * is normalized to Unix's ```/```
8
- *
9
- * @memberof module:Lib
10
- * @param {string} file - File to resolve
11
- * @param {boolean} [asFileUrl=false] - Return as file URL format ```file:///<name>```
12
- * @returns {string}
13
- */
14
- function resolvePath (item, asFileUrl) {
15
- if (item.startsWith('file://')) item = fileURLToPath(item)
16
- item = path.resolve(item)
17
- if (os.platform() === 'win32') {
18
- item = item.replace(/\\/g, '/')
19
- }
20
- if (asFileUrl) item = `file:///${item}`
21
- return item
22
- }
23
-
24
- export default resolvePath
package/lib/shim.js DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * External helpers you can use by importing its file directly
3
- *
4
- * @name Lib
5
- * @module Lib
6
- */
7
-
8
- /**
9
- * Function to attach some of the methods needed but probably not provided by your node installation:
10
- *
11
- * - ```String.prototype.replaceAll```
12
- * - ```String.prototype.splice```
13
- *
14
- * @memberof module:Lib
15
- */
16
- function shim () {
17
- // taken from: https://vanillajstoolkit.com/polyfills/stringreplaceall/
18
- if (!String.prototype.replaceAll) {
19
- String.prototype.replaceAll = function(str, newStr) { // eslint-disable-line
20
- if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
21
- return this.replace(str, newStr)
22
- }
23
- return this.replace(new RegExp(str, 'g'), newStr)
24
- }
25
- }
26
- if (!String.prototype.splice) {
27
- String.prototype.splice = function(index, count, add) { // eslint-disable-line
28
- if (index < 0) {
29
- index += this.length
30
- if (index < 0) index = 0
31
- }
32
- return this.slice(0, index) + (add || '') + this.slice(index + count)
33
- }
34
- }
35
- }
36
-
37
- export default shim