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/docs/lib_helper.js.html
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: lib/helper.js</title><!--[if lt IE 9]>
|
|
2
2
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
3
|
-
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">Bajo API</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="App.html">App</a></div><div class="sidebar-section-children"><a href="Bajo.html">Bajo</a></div><div class="sidebar-section-children"><a href="Base.html">Base</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="Err.html">Err</a></div><div class="sidebar-section-children"><a href="Log.html">Log</a></div><div class="sidebar-section-children"><a href="Plugin.html">Plugin</a></div><div class="sidebar-section-children"><a href="Print.html">Print</a></div><div class="sidebar-section-children"><a href="Tools.html">Tools</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-Helper.html">Helper</a></div><div class="sidebar-section-children"><a href="module-Hook.html">Hook</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#boot">boot</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="https://www.npmjs.com/package/bajo" target="">NPM</a></div><div class="navbar-item"><a id="" href="https://github.com/ardhi/bajo" target="">Github</a></div><div class="navbar-item"><a id="" href="https://bajo.app" target="">Bajo</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">lib_helper.js</h1></header><article><pre class="prettyprint source lang-js"><code>import Print from '../class/print.js'
|
|
3
|
+
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">Bajo API</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-01_WELCOME.html">Welcome</a></div><div class="sidebar-section-children"><a href="tutorial-02_GETTING_STARTED.html">Getting Started</a></div><div class="sidebar-section-children"><a href="tutorial-03_USER_GUIDE.html">User Guide</a></div><div class="sidebar-section-children"><a href="tutorial-04_DEV_GUIDE.html">Developer Guide</a></div><div class="sidebar-section-children"><a href="tutorial-05_ECOSYSTEM.html">Ecosystem</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="App.html">App</a></div><div class="sidebar-section-children"><a href="Bajo.html">Bajo</a></div><div class="sidebar-section-children"><a href="Base.html">Base</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="Err.html">Err</a></div><div class="sidebar-section-children"><a href="Log.html">Log</a></div><div class="sidebar-section-children"><a href="Main.html">Main</a></div><div class="sidebar-section-children"><a href="Plugin.html">Plugin</a></div><div class="sidebar-section-children"><a href="Print.html">Print</a></div><div class="sidebar-section-children"><a href="Tools.html">Tools</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-Applet.html">Applet</a></div><div class="sidebar-section-children"><a href="module-Helper.html">Helper</a></div><div class="sidebar-section-children"><a href="module-Hook.html">Hook</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#TConfig">TConfig</a></div><div class="sidebar-section-children"><a href="global.html#boot">boot</a></div><div class="sidebar-section-children"><a href="global.html#package%25C2%25B7json">package·json</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="https://www.npmjs.com/package/bajo" target="">NPM</a></div><div class="navbar-item"><a id="" href="https://github.com/ardhi/bajo" target="">Github</a></div><div class="navbar-item"><a id="" href="https://bajo.app" target="">Bajo</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">lib_helper.js</h1></header><article><pre class="prettyprint source lang-js"><code>import Print from '../class/print.js'
|
|
4
4
|
import Log from '../class/log.js'
|
|
5
5
|
import os from 'os'
|
|
6
6
|
import fs from 'fs-extra'
|
|
@@ -9,12 +9,14 @@ import semver from 'semver'
|
|
|
9
9
|
import aneka from 'aneka/index.js'
|
|
10
10
|
import outmatch from 'outmatch'
|
|
11
11
|
import fastGlob from 'fast-glob'
|
|
12
|
+
import * as readline from 'readline/promises'
|
|
12
13
|
import { sprintf } from 'sprintf-js'
|
|
13
14
|
import dayjs from 'dayjs'
|
|
14
15
|
import utc from 'dayjs/plugin/utc.js'
|
|
15
16
|
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
|
|
16
17
|
import localizedFormat from 'dayjs/plugin/localizedFormat.js'
|
|
17
18
|
import weekOfYear from 'dayjs/plugin/weekOfYear.js'
|
|
19
|
+
import defConfig from './config.js'
|
|
18
20
|
const { resolvePath } = aneka
|
|
19
21
|
const {
|
|
20
22
|
isFunction, isPlainObject, cloneDeep, merge, forOwn, groupBy, find, reduce, map,
|
|
@@ -23,74 +25,40 @@ const {
|
|
|
23
25
|
} = lodash
|
|
24
26
|
|
|
25
27
|
/**
|
|
28
|
+
* # Helper
|
|
29
|
+
*
|
|
26
30
|
* Internal helpers called by Bajo and other classes. It should remains
|
|
27
|
-
* hidden and not to be imported by any program.
|
|
31
|
+
* hidden and not to be imported by any program. It listed here for documentation purpose only.
|
|
28
32
|
*
|
|
29
33
|
* @module Helper
|
|
30
34
|
*/
|
|
31
35
|
|
|
32
36
|
const omitted = ['spawn', 'cwd', 'name', 'alias', 'applet', 'a', 'plugins']
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
breakLength: 80,
|
|
59
|
-
caller: true,
|
|
60
|
-
frame: {
|
|
61
|
-
titleAllignment: 'center',
|
|
62
|
-
padding: 1,
|
|
63
|
-
margin: 1,
|
|
64
|
-
borderStyle: 'round'
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
lang: Intl.DateTimeFormat().resolvedOptions().lang ?? 'en-US',
|
|
68
|
-
intl: {
|
|
69
|
-
supported: ['en-US', 'id'],
|
|
70
|
-
fallback: 'en-US',
|
|
71
|
-
lookupOrder: [],
|
|
72
|
-
format: {
|
|
73
|
-
emptyValue: '',
|
|
74
|
-
datetime: { dateStyle: 'medium', timeStyle: 'short', timeZone: 'UTC' },
|
|
75
|
-
date: { dateStyle: 'medium', timeZone: 'UTC' },
|
|
76
|
-
time: { timeStyle: 'short', timeZone: 'UTC' },
|
|
77
|
-
float: { maximumFractionDigits: 2 },
|
|
78
|
-
double: { maximumFractionDigits: 5 },
|
|
79
|
-
smallint: {},
|
|
80
|
-
integer: {}
|
|
81
|
-
},
|
|
82
|
-
unitSys: {
|
|
83
|
-
'en-US': 'imperial',
|
|
84
|
-
id: 'metric'
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
exitHandler: true,
|
|
88
|
-
cache: {
|
|
89
|
-
purge: [],
|
|
90
|
-
purgeIntvDur: '5m'
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Main plugin class. This is the special plugin created by Bajo during the boot process, solely made
|
|
40
|
+
* for you to write your own code for your application. It behaves like any other plugin, with a few differences:
|
|
41
|
+
*
|
|
42
|
+
* - It always there, can't be disabled nor removed, reside in the app's root directory named `main`.
|
|
43
|
+
* If it's folder is missing, Bajo will create it during the boot process with the default template and settings.
|
|
44
|
+
* - You don't have to put this plugin in your `.plugin` file or `package.json` file,
|
|
45
|
+
* it is always present and always loaded as the **last** plugin to load.
|
|
46
|
+
* - You write your app the same way you would do it with plugin:
|
|
47
|
+
* - by creating properties & methods within your class
|
|
48
|
+
* - by extending other plugins inside `/main/extend/{pluginNs}` folder
|
|
49
|
+
* - by tapping hooks inside `/main/extend/bajo/hook` folder or `/main/extend/bajo/hook.js` file
|
|
50
|
+
* - you even have your own config file in `{dataDir}/config/main.{ext}`
|
|
51
|
+
*
|
|
52
|
+
* Why it has to be a plugin? Because Bajo is a plugin-based framework, and everything is a plugin.
|
|
53
|
+
* This brings some flexibilities, e.g. when someday you think your main plugin become too big,
|
|
54
|
+
* just turn it into a separate plugin and move it to its own package with almost no code changes at all.
|
|
55
|
+
*
|
|
56
|
+
* For more on this, see {@link Plugin} and {@link module:Hook}
|
|
57
|
+
*
|
|
58
|
+
* @class
|
|
59
|
+
* @global
|
|
60
|
+
* @name Main
|
|
61
|
+
*/
|
|
94
62
|
const defMain = `async function factory (pkgName) {
|
|
95
63
|
const me = this
|
|
96
64
|
|
|
@@ -105,7 +73,19 @@ const defMain = `async function factory (pkgName) {
|
|
|
105
73
|
export default factory
|
|
106
74
|
`
|
|
107
75
|
|
|
108
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Outmacth with support for scoped source and pattern. Scoped source/pattern is a source/pattern that has a plugin's namespace prefix,
|
|
78
|
+
* separated by `:` symbol.
|
|
79
|
+
*
|
|
80
|
+
* This function is usefull for matching a source/pattern that is scoped to a specific plugin's namespace.
|
|
81
|
+
* For example, if you have a source `myPlugin:foo/bar` and a pattern `myPlugin:foo/*`,
|
|
82
|
+
* this function will return `true` because the source matches the pattern within the same namespace.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} source - Scoped source to match against the pattern. It should be in the format of `ns:path`
|
|
85
|
+
* @param {string} pattern - Scoped pattern to match against the source. It should be in the format of `ns:path`
|
|
86
|
+
* @returns {boolean} Returns `true` if the source matches the pattern, otherwise `false`.
|
|
87
|
+
*/
|
|
88
|
+
export function outmatchNs (source, pattern) {
|
|
109
89
|
const { breakNsPath } = this.bajo
|
|
110
90
|
const [src, subSrc] = source.split(':')
|
|
111
91
|
if (!subSrc) return pattern === src
|
|
@@ -118,7 +98,20 @@ function outmatchNs (source, pattern) {
|
|
|
118
98
|
}
|
|
119
99
|
}
|
|
120
100
|
|
|
121
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Parse object and normalize their values.
|
|
103
|
+
*
|
|
104
|
+
* Support automatic value translation for keys with `t:` prefix. The keys are then
|
|
105
|
+
* converted to the one without the `t:` prefix, and the original key is removed from the object.
|
|
106
|
+
*
|
|
107
|
+
* See {@link https://ardhi.github.io/aneka/global.html#parseObject|aneka.parseObject()} for more details.
|
|
108
|
+
*
|
|
109
|
+
* @method
|
|
110
|
+
* @param {*} obj - The object to parse and normalize.
|
|
111
|
+
* @param {object} [options={}] - Options for parsing and translation.
|
|
112
|
+
* @returns {object} The parsed and normalized object.
|
|
113
|
+
*/
|
|
114
|
+
export function parseObject (obj, options = {}) {
|
|
122
115
|
const me = this
|
|
123
116
|
const { ns = 'bajo', lang } = options
|
|
124
117
|
options.translator = {
|
|
@@ -139,6 +132,15 @@ dayjs.extend(localizedFormat)
|
|
|
139
132
|
dayjs.extend(weekOfYear)
|
|
140
133
|
|
|
141
134
|
/**
|
|
135
|
+
* Most commonly used libraries by Bajo and its plugins. They are already imported and ready to use,
|
|
136
|
+
* so you don't have to import them again in your plugin.
|
|
137
|
+
*
|
|
138
|
+
* Example:
|
|
139
|
+
* ```javascript
|
|
140
|
+
* const { fs, dayjs } = this.app.lib
|
|
141
|
+
* fs.ensureDirSync('/path/to/dir')
|
|
142
|
+
* const now = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
143
|
+
* ```
|
|
142
144
|
* @typedef {Object} TLib
|
|
143
145
|
* @memberof App
|
|
144
146
|
* @property {Object} _ Access to {@link https://lodash.com|lodash}.
|
|
@@ -148,8 +150,11 @@ dayjs.extend(weekOfYear)
|
|
|
148
150
|
* @property {Object} aneka Access to {@link https://github.com/ardhi/aneka|aneka}.
|
|
149
151
|
* @property {Object} outmatch Access to {@link https://github.com/axtgr/outmatch|outmatch}.
|
|
150
152
|
* @property {Object} dayjs Access to {@link https://day.js.org|dayjs} with utc & customParseFormat plugin already applied.
|
|
151
|
-
* @property {Object} freeze
|
|
152
|
-
* @property {Object} findDeep
|
|
153
|
+
* @property {Object} freeze Freeze object. See {@link module:Helper.freeze|freeze} for more details.
|
|
154
|
+
* @property {Object} findDeep Deep file file in an array of files. See {@link module:Helper.findDeep|findDeep} for more details.
|
|
155
|
+
* @property {Object} outmatchNs Like outmatch, but support scoped source & pattern. See {@link module:Helper.outmatchNs|outmatchNs} for more details.
|
|
156
|
+
* @property {Object} parseObject Parse object and normalize their values. Also support translation. See {@link module:Helper.parseObject|parseObject} for more details.
|
|
157
|
+
* @property {Object} [anekaSpatial] Access to {@link https://ardhi.github.io/bajo-spatial|aneka-spatial} helpers if `bajoSpatial` plugin is loaded.
|
|
153
158
|
* @see App
|
|
154
159
|
*/
|
|
155
160
|
export const lib = {
|
|
@@ -166,27 +171,49 @@ export const lib = {
|
|
|
166
171
|
parseObject
|
|
167
172
|
}
|
|
168
173
|
|
|
174
|
+
export async function ask (question, ...args) {
|
|
175
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
176
|
+
let answer
|
|
177
|
+
try {
|
|
178
|
+
answer = await rl.question(this.t(question, ...args))
|
|
179
|
+
} catch (err) {
|
|
180
|
+
console.error(err)
|
|
181
|
+
} finally {
|
|
182
|
+
rl.close()
|
|
183
|
+
}
|
|
184
|
+
return answer
|
|
185
|
+
}
|
|
186
|
+
|
|
169
187
|
/**
|
|
170
|
-
*
|
|
171
|
-
* -
|
|
172
|
-
* -
|
|
173
|
-
* -
|
|
174
|
-
* -
|
|
175
|
-
* - read the list of plugins from ```.plugins``` file
|
|
188
|
+
* Build base configuration object for Bajo. This function is called by Bajo during the {@link Bajo#init|initialization process}:
|
|
189
|
+
* - it sets up the base directory,
|
|
190
|
+
* - it checks the validity of the data directory,
|
|
191
|
+
* - it ensures the temporary directory exists,
|
|
192
|
+
* - it reads the list of used plugins from the `package.json`, `.plugins` file or command line options.
|
|
176
193
|
*
|
|
177
194
|
* @async
|
|
178
195
|
* @method
|
|
179
196
|
*/
|
|
180
197
|
export async function buildBaseConfig () {
|
|
181
|
-
// dirs
|
|
182
198
|
const { defaultsDeep, textToArray, currentLoc, resolvePath } = this.app.lib.aneka
|
|
183
|
-
|
|
199
|
+
// dirs
|
|
200
|
+
this.config = defaultsDeep({}, this.app.envVars._, this.app.argv._)
|
|
184
201
|
set(this, 'dir.base', this.app.dir)
|
|
185
202
|
const path = currentLoc(import.meta).dir + '/..'
|
|
186
203
|
set(this, 'dir.pkg', resolvePath(path))
|
|
187
204
|
if (get(this, 'config.dir.data')) set(this, 'dir.data', this.config.dir.data)
|
|
188
205
|
if (!get(this, 'dir.data')) set(this, 'dir.data', `${this.dir.base}/data`)
|
|
189
206
|
this.dir.data = resolvePath(this.dir.data)
|
|
207
|
+
if (!fs.existsSync(this.dir.data)) {
|
|
208
|
+
console.error("Data directory does not exist: '%s'", this.dir.data)
|
|
209
|
+
let answer
|
|
210
|
+
do {
|
|
211
|
+
answer = await ask.call(this, 'Create one now? (y/n) ', this.dir.data)
|
|
212
|
+
answer = answer.trim().toLowerCase()
|
|
213
|
+
} while (!['y', 'n'].includes(answer))
|
|
214
|
+
if (answer === 'n') this.app.exit(true, 'Aborted')
|
|
215
|
+
fs.ensureDirSync(this.dir.data)
|
|
216
|
+
}
|
|
190
217
|
fs.ensureDirSync(`${this.dir.data}/config`)
|
|
191
218
|
if (!this.dir.tmp) {
|
|
192
219
|
this.dir.tmp = `${resolvePath(os.tmpdir())}/${this.ns}`
|
|
@@ -194,8 +221,8 @@ export async function buildBaseConfig () {
|
|
|
194
221
|
}
|
|
195
222
|
this.pkg = await this.getPkgInfo()
|
|
196
223
|
let pluginPkgs = this.app.pluginPkgs
|
|
224
|
+
// collect list of plugins
|
|
197
225
|
if (isEmpty(pluginPkgs)) {
|
|
198
|
-
// collect list of plugins
|
|
199
226
|
const mainPkg = await this.getPkgInfo(this.app.dir)
|
|
200
227
|
pluginPkgs = get(mainPkg, 'bajo.plugins', [])
|
|
201
228
|
if (isEmpty(pluginPkgs)) {
|
|
@@ -210,12 +237,12 @@ export async function buildBaseConfig () {
|
|
|
210
237
|
}
|
|
211
238
|
|
|
212
239
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* - iterate through the list and build related plugins
|
|
216
|
-
* - making sure main plugin is there. If not, create from template
|
|
217
|
-
* - attach these plugins to the app instance
|
|
240
|
+
* Load, build and sanitize all plugins defined in `package.json` or `.plugins` file, and add them to the app's plugin list.
|
|
241
|
+
* It will also make sure the `main` plugin is there too, if not, it will be created with the default template and settings.
|
|
218
242
|
*
|
|
243
|
+
* Finally, it will loop through all loaded plugins and its config and language files.
|
|
244
|
+
*
|
|
245
|
+
* This function is called by Bajo during the {@link Bajo#init|initialization process}.
|
|
219
246
|
* @async
|
|
220
247
|
*/
|
|
221
248
|
export async function buildPlugins () {
|
|
@@ -243,12 +270,17 @@ export async function buildPlugins () {
|
|
|
243
270
|
this.app.addPlugin(plugin, ClassDef)
|
|
244
271
|
this.log.trace('- ' + pkg)
|
|
245
272
|
}
|
|
273
|
+
// load all plugins' config & language files
|
|
274
|
+
for (const ns of this.app.getAllNs()) {
|
|
275
|
+
await this.app[ns].loadConfig()
|
|
276
|
+
this.app[ns].print = new Print(this.app[ns])
|
|
277
|
+
this.app.loadIntl(ns)
|
|
278
|
+
}
|
|
246
279
|
this.log.debug('buildPluginsComplete')
|
|
247
280
|
}
|
|
248
281
|
|
|
249
282
|
/**
|
|
250
|
-
* Collect all config handlers
|
|
251
|
-
*
|
|
283
|
+
* Collect all plugins' config handlers and push them to the app's {@link App#configHandlers|configHandlers} array.
|
|
252
284
|
* @async
|
|
253
285
|
*/
|
|
254
286
|
export async function collectConfigHandlers () {
|
|
@@ -269,14 +301,17 @@ export async function collectConfigHandlers () {
|
|
|
269
301
|
}
|
|
270
302
|
|
|
271
303
|
/**
|
|
272
|
-
* Bajo
|
|
273
|
-
*
|
|
274
|
-
* -
|
|
275
|
-
*
|
|
304
|
+
* Building Bajo configuration object. Called after all config handlers are collected,
|
|
305
|
+
* this function will read config files written in any of config handlers' supported formats:
|
|
306
|
+
* - if runtime configuration object is provided (the one passed to the app constructor), it will be
|
|
307
|
+
* used as the base. Otherwise, files are read from the `{dataDir}/config`
|
|
308
|
+
* - then it will be merged with the configuration coming from the command line arguments and environment variables
|
|
309
|
+
* - doing some normalization and validation works, including setting the language, environment, log level, and cache purge settings
|
|
310
|
+
* - and setting up the app's log instance with the proper log level
|
|
276
311
|
*
|
|
277
312
|
* @async
|
|
278
313
|
*/
|
|
279
|
-
export async function
|
|
314
|
+
export async function buildConfig () {
|
|
280
315
|
// config merging
|
|
281
316
|
const { defaultsDeep, includes } = this.app.lib.aneka
|
|
282
317
|
const { parseObject } = this.app.lib
|
|
@@ -322,7 +357,8 @@ export async function buildExtConfig () {
|
|
|
322
357
|
}
|
|
323
358
|
|
|
324
359
|
/**
|
|
325
|
-
*
|
|
360
|
+
* Determine the boot order of plugins based on their `bajo.bootorder` property in their `package.json` file.
|
|
361
|
+
* If not provided, the plugin will be booted in the order they are listed in the `package.json` file or `.plugins` file.
|
|
326
362
|
*
|
|
327
363
|
* @async
|
|
328
364
|
*/
|
|
@@ -350,50 +386,36 @@ export async function bootOrder () {
|
|
|
350
386
|
}
|
|
351
387
|
|
|
352
388
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
* @async
|
|
356
|
-
*/
|
|
357
|
-
export async function buildConfigs () {
|
|
358
|
-
this.bajo.log.debug('readConfigs')
|
|
359
|
-
for (const ns of this.getAllNs()) {
|
|
360
|
-
await this[ns].loadConfig()
|
|
361
|
-
this[ns].print = new Print(this[ns])
|
|
362
|
-
this.loadIntl(ns)
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Ensure for names and aliases to be unique and no clashes with other plugins
|
|
368
|
-
*
|
|
389
|
+
* Ensure the uniqueness of all plugins' name and alias. If there is a clash, an error will be thrown.
|
|
369
390
|
* @async
|
|
370
391
|
*/
|
|
371
392
|
export async function checkNameAliases () {
|
|
372
|
-
this.
|
|
393
|
+
this.log.debug('checkAliasNameClash')
|
|
373
394
|
const refs = []
|
|
374
|
-
for (const pkg of this.
|
|
375
|
-
const plugin = this.
|
|
395
|
+
for (const pkg of this.app.pluginPkgs) {
|
|
396
|
+
const plugin = this.app[camelCase(pkg)]
|
|
376
397
|
const { ns, alias } = plugin
|
|
377
398
|
let item = find(refs, { ns })
|
|
378
|
-
if (item) throw this.
|
|
399
|
+
if (item) throw this.error('pluginNameClash%s%s%s%s', ns, pkg, item.ns, item.pkg, { code: 'BAJO_NAME_CLASH' })
|
|
379
400
|
item = find(refs, { alias })
|
|
380
|
-
if (item) throw this.
|
|
401
|
+
if (item) throw this.error('pluginNameClash%s%s%s%s', alias, pkg, item.alias, item.pkg, { code: 'BAJO_ALIAS_CLASH' })
|
|
381
402
|
refs.push({ ns, alias, pkg })
|
|
382
403
|
}
|
|
383
404
|
}
|
|
384
405
|
|
|
385
406
|
/**
|
|
386
|
-
* Ensure dependencies are met
|
|
407
|
+
* Ensure all plugins' dependencies are met. If there is a missing dependency, an error will be thrown.
|
|
387
408
|
*
|
|
409
|
+
* Semver is also supported, so if a plugin requires a specific version of another plugin, it will be checked as well.
|
|
388
410
|
* @async
|
|
389
411
|
*/
|
|
390
412
|
export async function checkDependencies () {
|
|
391
|
-
const { join } = this
|
|
392
|
-
this.
|
|
393
|
-
for (const pkg of this.
|
|
394
|
-
const plugin = this.
|
|
413
|
+
const { join } = this
|
|
414
|
+
this.log.debug('checkDeps')
|
|
415
|
+
for (const pkg of this.app.pluginPkgs) {
|
|
416
|
+
const plugin = this.app[camelCase(pkg)]
|
|
395
417
|
const { ns, dependencies } = plugin
|
|
396
|
-
this.
|
|
418
|
+
this.log.trace('- %s', ns)
|
|
397
419
|
const odep = reduce(dependencies, (o, k) => {
|
|
398
420
|
const item = map(k.split('@'), m => trim(m))
|
|
399
421
|
if (k[0] === '@') o['@' + item[1]] = item[2]
|
|
@@ -402,15 +424,15 @@ export async function checkDependencies () {
|
|
|
402
424
|
}, {})
|
|
403
425
|
const deps = keys(odep)
|
|
404
426
|
if (deps.length > 0) {
|
|
405
|
-
if (intersection(this.
|
|
406
|
-
throw this.
|
|
427
|
+
if (intersection(this.app.pluginPkgs, deps).length !== deps.length) {
|
|
428
|
+
throw this.error('dependencyUnfulfilled%s%s', pkg, join(deps), { code: 'BAJO_DEPENDENCY' })
|
|
407
429
|
}
|
|
408
430
|
each(deps, d => {
|
|
409
431
|
if (!odep[d]) return
|
|
410
|
-
const ver = get(this.
|
|
432
|
+
const ver = get(this.app[camelCase(d)], 'pkg.version')
|
|
411
433
|
if (!ver) return
|
|
412
434
|
if (!semver.satisfies(ver, odep[d])) {
|
|
413
|
-
throw this.
|
|
435
|
+
throw this.error('semverCheckFailed%s%s', pkg, `${d}@${odep[d]}`, { code: 'BAJO_DEPENDENCY_SEMVER' })
|
|
414
436
|
}
|
|
415
437
|
})
|
|
416
438
|
}
|
|
@@ -418,15 +440,14 @@ export async function checkDependencies () {
|
|
|
418
440
|
}
|
|
419
441
|
|
|
420
442
|
/**
|
|
421
|
-
* Collect
|
|
422
|
-
*
|
|
443
|
+
* Collect all plugins' hooks and push them to the app's {@link App#hooks|hooks} array.
|
|
423
444
|
* @async
|
|
424
445
|
*/
|
|
425
446
|
export async function collectHooks () {
|
|
426
|
-
const { eachPlugins, runHook, isLogInRange, importModule } = this
|
|
427
|
-
const { isArray, isPlainObject } = this.lib._
|
|
428
|
-
const me = this // "this" is "
|
|
429
|
-
|
|
447
|
+
const { eachPlugins, runHook, isLogInRange, importModule } = this
|
|
448
|
+
const { isArray, isPlainObject } = this.app.lib._
|
|
449
|
+
const me = this // "this" is "bajo"
|
|
450
|
+
this.log.trace('collecting%s', this.t('hooks'))
|
|
430
451
|
await eachPlugins(async function ({ dir, file }) {
|
|
431
452
|
let mod = await importModule(file, { asHandler: true })
|
|
432
453
|
if (!mod) return undefined
|
|
@@ -437,11 +458,11 @@ export async function collectHooks () {
|
|
|
437
458
|
if (!m.name) throw me.bajo.error('missing%s%s', 'name', file)
|
|
438
459
|
if (isArray(m.name)) {
|
|
439
460
|
for (const name of m.name) {
|
|
440
|
-
me.
|
|
461
|
+
me.hooks.push(merge({}, m, { name, src: this.ns }))
|
|
441
462
|
}
|
|
442
463
|
} else {
|
|
443
464
|
m.src = this.ns
|
|
444
|
-
me.
|
|
465
|
+
me.hooks.push(m)
|
|
445
466
|
}
|
|
446
467
|
}
|
|
447
468
|
} else {
|
|
@@ -451,81 +472,55 @@ export async function collectHooks () {
|
|
|
451
472
|
for (let name of names) {
|
|
452
473
|
name = name.split('.').map(n => camelCase(n)).join('.')
|
|
453
474
|
const m = merge({}, mod, { name: `${name}:${camelCase(path)}`, src: this.ns })
|
|
454
|
-
me.
|
|
475
|
+
me.hooks.push(m)
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
|
-
}, { glob: ['hook/*.js', 'hook.js'], prefix:
|
|
478
|
+
}, { glob: ['hook/*.js', 'hook.js'], prefix: this.ns })
|
|
458
479
|
// for log trace purpose only
|
|
459
480
|
if (isLogInRange('trace')) {
|
|
460
|
-
const items = groupBy(
|
|
481
|
+
const items = groupBy(this.hooks, item => item.name)
|
|
461
482
|
forOwn(items, (v, k) => {
|
|
462
483
|
const [name, path] = k.split(':')
|
|
463
|
-
|
|
484
|
+
this.log.trace('- %s:%s (%s)', name, path, v.length)
|
|
464
485
|
})
|
|
465
486
|
}
|
|
466
487
|
|
|
467
|
-
await runHook('bajo:afterCollectHooks', this.
|
|
468
|
-
|
|
488
|
+
await runHook('bajo:afterCollectHooks', this.hooks)
|
|
489
|
+
this.log.debug('collected%s%d', this.t('hooks'), this.hooks.length)
|
|
469
490
|
}
|
|
470
491
|
|
|
471
492
|
/**
|
|
472
|
-
*
|
|
493
|
+
* Run all loaded plugins' `init()` and `start()` methods in the order determined previously during boot process.
|
|
473
494
|
*
|
|
474
495
|
* @async
|
|
475
|
-
* @see module:Hook
|
|
476
|
-
* @see module:Hook~{ns}:beforeInit
|
|
477
|
-
* @see module:Hook~{ns}:afterInit
|
|
478
|
-
* @see module:Hook~bajo:afterAllInit
|
|
479
|
-
* @see module:Hook~bajo:beforeAllStart
|
|
480
|
-
* @see module:Hook~{ns}:beforeStart
|
|
481
|
-
* @see module:Hook~{ns}:afterStart
|
|
482
|
-
* @see module:Hook~bajo:afterAllStart
|
|
496
|
+
* @see module:Hook
|
|
483
497
|
*/
|
|
484
|
-
export async function
|
|
498
|
+
export async function runPlugins () {
|
|
485
499
|
const me = this
|
|
486
|
-
const { runHook, eachPlugins, join } =
|
|
487
|
-
const { freeze } =
|
|
500
|
+
const { runHook, eachPlugins, join } = this
|
|
501
|
+
const { freeze } = this.app.lib
|
|
488
502
|
const methods = ['init']
|
|
489
|
-
if (!
|
|
503
|
+
if (!this.app.applet) methods.push('start')
|
|
490
504
|
for (const method of methods) {
|
|
491
505
|
await runHook(`bajo:${camelCase(`before all ${method}`)}`)
|
|
492
506
|
await eachPlugins(async function () {
|
|
493
507
|
const { ns } = this
|
|
494
508
|
await runHook(`${ns}:${camelCase(`before ${method}`)}`)
|
|
495
|
-
await me[ns][method]()
|
|
509
|
+
await me.app[ns][method]()
|
|
496
510
|
await runHook(`${ns}:${camelCase(`after ${method}`)}`)
|
|
497
|
-
if (method === 'start') freeze(me[ns].config)
|
|
511
|
+
if (method === 'start') freeze(me.app[ns].config)
|
|
498
512
|
})
|
|
499
513
|
await runHook(`bajo:${camelCase(`after all ${method}`)}`)
|
|
500
514
|
}
|
|
501
|
-
if (
|
|
502
|
-
let text = join(map(
|
|
503
|
-
text += ` (${
|
|
504
|
-
|
|
505
|
-
} else
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Iterate through all plugins loaded and do:
|
|
510
|
-
*
|
|
511
|
-
* 1. {@link module:Helper/Base.buildConfigs|build configs}
|
|
512
|
-
* 2. {@link module:Helper/Base.checkNameAliases|ensure names & aliases uniqueness}
|
|
513
|
-
* 3. {@link module:Helper/Base.checkDependencies|ensure dependencies are met}
|
|
514
|
-
* 4. {@link module:Helper/Base.collectHooks|collect hooks}
|
|
515
|
-
* 5. {@link module:Helper/Base.run|run plugins}
|
|
516
|
-
*
|
|
517
|
-
* @async
|
|
518
|
-
*/
|
|
519
|
-
export async function bootPlugins () {
|
|
520
|
-
await buildConfigs.call(this.app)
|
|
521
|
-
await checkNameAliases.call(this.app)
|
|
522
|
-
await checkDependencies.call(this.app)
|
|
523
|
-
await collectHooks.call(this.app)
|
|
524
|
-
await run.call(this.app)
|
|
515
|
+
if (this.config.log.level === 'trace') {
|
|
516
|
+
let text = join(map(this.app.pluginPkgs, b => camelCase(b)))
|
|
517
|
+
text += ` (${this.app.pluginPkgs.length})`
|
|
518
|
+
this.log.trace('loadedPlugins%s', text)
|
|
519
|
+
} else this.log.debug('loadedPlugins%s', this.app.pluginPkgs.length)
|
|
525
520
|
}
|
|
526
521
|
|
|
527
522
|
/**
|
|
528
|
-
* Attach plugins exit handlers
|
|
523
|
+
* Attach plugins exit handlers to make sure when the app shuts down, all plugins shut down gracefully first
|
|
529
524
|
*
|
|
530
525
|
* @async
|
|
531
526
|
*/
|
|
@@ -533,15 +528,14 @@ export async function exitHandler () {
|
|
|
533
528
|
if (!this.config.exitHandler) return
|
|
534
529
|
|
|
535
530
|
async function exit (signal) {
|
|
536
|
-
const { eachPlugins } = this
|
|
537
531
|
if (signal) this.log.warn('signalReceived%s', signal)
|
|
538
|
-
const
|
|
539
|
-
|
|
532
|
+
const allNs = this.app.getAllNs().reverse()
|
|
533
|
+
for (const ns of allNs) {
|
|
540
534
|
try {
|
|
541
|
-
await this.exit()
|
|
535
|
+
await this.app[ns].exit()
|
|
542
536
|
} catch (err) {}
|
|
543
|
-
|
|
544
|
-
}
|
|
537
|
+
this.log.trace('exited%s', ns)
|
|
538
|
+
}
|
|
545
539
|
this.log.debug('appShutdown')
|
|
546
540
|
process.exit(0)
|
|
547
541
|
}
|
|
@@ -587,11 +581,10 @@ export async function exitHandler () {
|
|
|
587
581
|
}
|
|
588
582
|
|
|
589
583
|
/**
|
|
590
|
-
* If app is in
|
|
584
|
+
* If app is in `applet` mode, this little helper should take care plugin's applet boot process
|
|
591
585
|
*
|
|
592
586
|
* @async
|
|
593
|
-
* @
|
|
594
|
-
* @fires {ns}:afterAppletRun
|
|
587
|
+
* @see module:Applet
|
|
595
588
|
*/
|
|
596
589
|
export async function runAsApplet () {
|
|
597
590
|
const { isString, map, find } = this.app.lib._
|
|
@@ -624,27 +617,27 @@ export async function runAsApplet () {
|
|
|
624
617
|
* Import file/module from any loaded plugins.
|
|
625
618
|
*
|
|
626
619
|
* E.g. your plugin structure looks like this:
|
|
627
|
-
*
|
|
620
|
+
* `
|
|
628
621
|
* |- src
|
|
629
622
|
* | |- lib
|
|
630
623
|
* | | |- my-module.js
|
|
631
624
|
* |- index.js
|
|
632
625
|
* |- package.json
|
|
633
|
-
*
|
|
626
|
+
* `
|
|
634
627
|
*
|
|
635
|
-
* And this is how to import
|
|
636
|
-
*
|
|
628
|
+
* And this is how to import `my-module.js`:
|
|
629
|
+
* `javascript
|
|
637
630
|
* const { importModule } = this.app.bajo
|
|
638
631
|
* const myModule = await importModule('myPlugin:/src/lib/my-module.js')
|
|
639
|
-
*
|
|
632
|
+
* `
|
|
640
633
|
*
|
|
641
634
|
* @method
|
|
642
635
|
* @async
|
|
643
636
|
* @param {TNsPathPairs} file File to import.
|
|
644
637
|
* @param {Object} [options={}] Options.
|
|
645
|
-
* @param {boolean} [options.asDefaultImport=true] If
|
|
646
|
-
* @param {boolean} [options.asHandler] If
|
|
647
|
-
* @param {boolean} [options.noCache] If
|
|
638
|
+
* @param {boolean} [options.asDefaultImport=true] If `true` (default), return default imported module.
|
|
639
|
+
* @param {boolean} [options.asHandler] If `true`, return as a {@link HandlerType|handler}.
|
|
640
|
+
* @param {boolean} [options.noCache] If `true`, always import as a fresh copy.
|
|
648
641
|
* @returns {any}
|
|
649
642
|
* @see Bajo#importModule
|
|
650
643
|
*/
|
|
@@ -660,6 +653,7 @@ export async function importModule (file, { asDefaultImport = true, asHandler, n
|
|
|
660
653
|
if (this) file = this.app.getPluginFile(file)
|
|
661
654
|
if (!fs.existsSync(file)) return
|
|
662
655
|
let mod = await load(file, asDefaultImport, noCache)
|
|
656
|
+
if (!mod) return
|
|
663
657
|
if (!asHandler) return mod
|
|
664
658
|
if (isFunction(mod)) mod = { level: 999, handler: mod }
|
|
665
659
|
if (!isPlainObject(mod)) {
|
|
@@ -674,7 +668,7 @@ export async function importModule (file, { asDefaultImport = true, asHandler, n
|
|
|
674
668
|
*
|
|
675
669
|
* @method
|
|
676
670
|
* @param {Object} obj Object to freeze.
|
|
677
|
-
* @param {boolean} [shallow=false] If
|
|
671
|
+
* @param {boolean} [shallow=false] If `false` (default), deep freeze object.
|
|
678
672
|
*/
|
|
679
673
|
export function freeze (obj, options = {}) {
|
|
680
674
|
const { shallow = false, clone = false } = options
|
|
@@ -802,4 +796,4 @@ export const formats = {
|
|
|
802
796
|
degreeUnitSep: ''
|
|
803
797
|
}
|
|
804
798
|
}
|
|
805
|
-
</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">Bajo API</a><div class="mobile-nav-links"><div class="navbar-item"><a id="" href="https://www.npmjs.com/package/bajo" target="">NPM</a></div><div class="navbar-item"><a id="" href="https://github.com/ardhi/bajo" target="">Github</a></div><div class="navbar-item"><a id="" href="https://bajo.app" target="">Bajo</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="App.html">App</a></div><div class="sidebar-section-children"><a href="Bajo.html">Bajo</a></div><div class="sidebar-section-children"><a href="Base.html">Base</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="Err.html">Err</a></div><div class="sidebar-section-children"><a href="Log.html">Log</a></div><div class="sidebar-section-children"><a href="Plugin.html">Plugin</a></div><div class="sidebar-section-children"><a href="Print.html">Print</a></div><div class="sidebar-section-children"><a href="Tools.html">Tools</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-Helper.html">Helper</a></div><div class="sidebar-section-children"><a href="module-Hook.html">Hook</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#boot">boot</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
|
|
799
|
+
</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">Bajo API</a><div class="mobile-nav-links"><div class="navbar-item"><a id="" href="https://www.npmjs.com/package/bajo" target="">NPM</a></div><div class="navbar-item"><a id="" href="https://github.com/ardhi/bajo" target="">Github</a></div><div class="navbar-item"><a id="" href="https://bajo.app" target="">Bajo</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-01_WELCOME.html">Welcome</a></div><div class="sidebar-section-children"><a href="tutorial-02_GETTING_STARTED.html">Getting Started</a></div><div class="sidebar-section-children"><a href="tutorial-03_USER_GUIDE.html">User Guide</a></div><div class="sidebar-section-children"><a href="tutorial-04_DEV_GUIDE.html">Developer Guide</a></div><div class="sidebar-section-children"><a href="tutorial-05_ECOSYSTEM.html">Ecosystem</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="App.html">App</a></div><div class="sidebar-section-children"><a href="Bajo.html">Bajo</a></div><div class="sidebar-section-children"><a href="Base.html">Base</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="Err.html">Err</a></div><div class="sidebar-section-children"><a href="Log.html">Log</a></div><div class="sidebar-section-children"><a href="Main.html">Main</a></div><div class="sidebar-section-children"><a href="Plugin.html">Plugin</a></div><div class="sidebar-section-children"><a href="Print.html">Print</a></div><div class="sidebar-section-children"><a href="Tools.html">Tools</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-Applet.html">Applet</a></div><div class="sidebar-section-children"><a href="module-Helper.html">Helper</a></div><div class="sidebar-section-children"><a href="module-Hook.html">Hook</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#TConfig">TConfig</a></div><div class="sidebar-section-children"><a href="global.html#boot">boot</a></div><div class="sidebar-section-children"><a href="global.html#package%25C2%25B7json">package·json</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
|