bajo 2.18.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/class/_helper.js +22 -7
  2. package/class/app.js +59 -45
  3. package/class/bajo.js +150 -129
  4. package/class/base.js +3 -3
  5. package/class/cache.js +60 -0
  6. package/class/err.js +14 -11
  7. package/class/log.js +41 -40
  8. package/class/plugin.js +35 -36
  9. package/class/print.js +54 -51
  10. package/class/tools.js +3 -4
  11. package/docs/App.html +7 -7
  12. package/docs/Bajo.html +2 -2
  13. package/docs/Base.html +1 -1
  14. package/docs/Cache.html +3 -0
  15. package/docs/Err.html +2 -2
  16. package/docs/Log.html +2 -2
  17. package/docs/Plugin.html +1 -1
  18. package/docs/Print.html +1 -1
  19. package/docs/Tools.html +3 -0
  20. package/docs/class__helper.js.html +694 -0
  21. package/docs/class_app.js.html +307 -149
  22. package/docs/class_bajo.js.html +316 -464
  23. package/docs/class_base.js.html +35 -32
  24. package/docs/class_cache.js.html +150 -0
  25. package/docs/class_err.js.html +144 -0
  26. package/docs/class_log.js.html +270 -0
  27. package/docs/class_plugin.js.html +98 -71
  28. package/docs/class_print.js.html +261 -0
  29. package/docs/class_tools.js.html +44 -0
  30. package/docs/data/search.json +1 -1
  31. package/docs/global.html +1 -4
  32. package/docs/index.html +1 -1
  33. package/docs/index.js.html +21 -14
  34. package/docs/lib_find-deep.js.html +27 -0
  35. package/docs/lib_formats.js.html +19 -19
  36. package/docs/lib_freeze.js.html +19 -0
  37. package/docs/lib_import-module.js.html +16 -14
  38. package/docs/lib_index.js.html +9 -0
  39. package/docs/lib_log-levels.js.html +2 -2
  40. package/docs/module-Helper.html +3 -0
  41. package/docs/module-Lib.html +3 -8
  42. package/docs/scripts/core.js +477 -476
  43. package/docs/scripts/resize.js +36 -36
  44. package/docs/scripts/search.js +105 -105
  45. package/docs/scripts/third-party/fuse.js +1 -1
  46. package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
  47. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  48. package/docs/scripts/third-party/hljs-original.js +1202 -1195
  49. package/docs/scripts/third-party/hljs.js +1 -1
  50. package/docs/scripts/third-party/popper.js +1 -1
  51. package/docs/scripts/third-party/tippy.js +1 -1
  52. package/docs/scripts/third-party/tocbot.js +509 -508
  53. package/index.js +8 -11
  54. package/lib/find-deep.js +3 -3
  55. package/lib/formats.js +17 -17
  56. package/lib/freeze.js +3 -3
  57. package/lib/import-module.js +8 -8
  58. package/package.json +1 -1
  59. package/test/app.test.js +183 -0
  60. package/test/bajo.test.js +125 -0
  61. package/test/base.test.js +74 -107
  62. package/test/cache.test.js +94 -0
  63. package/test/e2e.test.js +137 -0
  64. package/test/err.test.js +73 -0
  65. package/test/helper.test.js +39 -0
  66. package/test/import-module.test.js +138 -0
  67. package/test/integration.test.js +218 -0
  68. package/test/log.test.js +119 -0
  69. package/test/plugin.test.js +116 -0
  70. package/test/print.test.js +100 -0
  71. package/test/tools.test.js +38 -0
  72. package/wiki/CHANGES.md +5 -0
  73. package/.mocharc.json +0 -4
@@ -1,41 +1,35 @@
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: class/app.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="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><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</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#event:bajo:afterAll%257Bmethod%257D">bajo:afterAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBootComplete">bajo:afterBootComplete</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBuildCollection">bajo:afterBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterCollectHooks">bajo:afterCollectHooks</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeAll%257Bmethod%257D">bajo:beforeAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeBuildCollection">bajo:beforeBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:afterAppletRun">{ns}:afterAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:after%257Bmethod%257D">{ns}:after{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:beforeAppletRun">{ns}:beforeAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:before%257Bmethod%257D">{ns}:before{method}</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_Bajo.html">Helper/Bajo</a></div><div class="sidebar-section-children"><a href="module-Helper_Base.html">Helper/Base</a></div><div class="sidebar-section-children"><a href="module-Lib.html">Lib</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#TAppConfigHandler">TAppConfigHandler</a></div><div class="sidebar-section-children"><a href="global.html#TAppEnv">TAppEnv</a></div><div class="sidebar-section-children"><a href="global.html#TAppLib">TAppLib</a></div><div class="sidebar-section-children"><a href="global.html#TBajoDataType">TBajoDataType</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatResult">TBajoFormatResult</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatType">TBajoFormatType</a></div><div class="sidebar-section-children"><a href="global.html#TLogJson">TLogJson</a></div><div class="sidebar-section-children"><a href="global.html#TLogLevels">TLogLevels</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathPairs">TNsPathPairs</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathResult">TNsPathResult</a></div><div class="sidebar-section-children"><a href="global.html#TPrintOptions">TPrintOptions</a></div><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">class_app.js</h1></header><article><pre class="prettyprint source lang-js"><code>import util from 'util'
4
- import lodash from 'lodash'
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-events"><div>Events</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#event:bajo:afterAll%257Bmethod%257D">bajo:afterAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBootComplete">bajo:afterBootComplete</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBuildCollection">bajo:afterBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterCollectHooks">bajo:afterCollectHooks</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeAll%257Bmethod%257D">bajo:beforeAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeBuildCollection">bajo:beforeBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:after%257Bmethod%257D">{ns}:after{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:beforeAppletRun">{ns}:beforeAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:before%257Bmethod%257D">{ns}:before{method}</a></div><div class="sidebar-section-children"><a href="module-Helper%257Bns%257D_afterAppletRun.html">Helper{ns}:afterAppletRun</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-Lib.html">Lib</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#TAppConfigHandler">TAppConfigHandler</a></div><div class="sidebar-section-children"><a href="global.html#TAppEnv">TAppEnv</a></div><div class="sidebar-section-children"><a href="global.html#TBajoDataType">TBajoDataType</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatResult">TBajoFormatResult</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatType">TBajoFormatType</a></div><div class="sidebar-section-children"><a href="global.html#TLogJson">TLogJson</a></div><div class="sidebar-section-children"><a href="global.html#TLogLevels">TLogLevels</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathPairs">TNsPathPairs</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathResult">TNsPathResult</a></div><div class="sidebar-section-children"><a href="global.html#TPrintOptions">TPrintOptions</a></div><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">class_app.js</h1></header><article><pre class="prettyprint source lang-js"><code>import util from 'util'
5
4
  import Bajo from './bajo.js'
6
- import fastGlob from 'fast-glob'
7
- import { sprintf } from 'sprintf-js'
8
- import outmatch from 'outmatch'
9
- import fs from 'fs-extra'
10
- import aneka from 'aneka/index.js'
11
5
  import Base from './base.js'
12
- import resolvePath from '../lib/resolve-path.js'
13
- import parseArgsArgv from '../lib/parse-args-argv.js'
14
- import parseEnv from '../lib/parse-env.js'
15
- import { runAsApplet } from './helper/bajo.js'
16
- import dayjs from 'dayjs'
17
- import utc from 'dayjs/plugin/utc.js'
18
- import customParseFormat from 'dayjs/plugin/customParseFormat.js'
19
- import localizedFormat from 'dayjs/plugin/localizedFormat.js'
20
-
21
- dayjs.extend(utc)
22
- dayjs.extend(customParseFormat)
23
- dayjs.extend(localizedFormat)
24
-
25
- const { isPlainObject, get, reverse, map, isString, last, without, keys } = lodash
6
+ import Cache from './cache.js'
7
+ import Tools from './tools.js'
8
+ import Plugin from './plugin.js'
9
+ import { outmatchNs, parseObject, lib, runAsApplet } from './_helper.js'
10
+ import { fileURLToPath } from 'url'
11
+
12
+ const { camelCase, isPlainObject, get, reverse, map, last, without, set } = lib._
13
+ const { pascalCase } = lib.aneka
26
14
  let unknownLangWarning = false
27
15
 
28
- function outmatchNs (source, pattern) {
29
- const { breakNsPath } = this.bajo
30
- const [src, subSrc] = source.split(':')
31
- if (!subSrc) return pattern === src
16
+ function getCallerFilename () {
17
+ const originalFunc = Error.prepareStackTrace
18
+ let callerfile
19
+
32
20
  try {
33
- const { fullNs, path } = breakNsPath(pattern)
34
- const isMatch = outmatch(path)
35
- return src === fullNs &amp;&amp; isMatch(subSrc)
36
- } catch (err) {
37
- return false
38
- }
21
+ const err = new Error()
22
+ Error.prepareStackTrace = (_, stack) => stack
23
+ const currentfile = err.stack.shift().getFileName()
24
+
25
+ while (err.stack.length) {
26
+ callerfile = err.stack.shift().getFileName()
27
+ if (currentfile !== callerfile) break
28
+ }
29
+ } catch (e) {}
30
+
31
+ Error.prepareStackTrace = originalFunc
32
+ return callerfile
39
33
  }
40
34
 
41
35
  /**
@@ -45,27 +39,6 @@ function outmatchNs (source, pattern) {
45
39
  * @see App
46
40
  */
47
41
 
48
- /**
49
- * @typedef {Object} TAppLib
50
- * @property {Object} _ - Access to {@link https://lodash.com|lodash}
51
- * @property {Object} fs - Access to {@link https://github.com/jprichardson/node-fs-extra|fs-extra}
52
- * @property {Object} fastGlob - Access to {@link https://github.com/mrmlnc/fast-glob|fast-glob}
53
- * @property {Object} sprintf - Access to {@link https://github.com/alexei/sprintf.js|sprintf}
54
- * @property {Object} aneka - Access to {@link https://github.com/ardhi/aneka|aneka}
55
- * @property {Object} outmatch - Access to {@link https://github.com/axtgr/outmatch|outmatch}
56
- * @property {Object} dayjs - Access to {@link https://day.js.org|dayjs} with utc &amp; customParseFormat plugin already applied
57
- * @see App
58
- */
59
- const lib = {
60
- _: lodash,
61
- fs,
62
- fastGlob,
63
- sprintf,
64
- outmatch,
65
- dayjs,
66
- aneka
67
- }
68
-
69
42
  /**
70
43
  * App class. This is the root. This is where all plugins call it home.
71
44
  *
@@ -73,50 +46,62 @@ const lib = {
73
46
  */
74
47
  class App {
75
48
  /**
76
- * Your main namespace. And yes, you suppose to NOT CHANGE this
77
- *
78
- * @memberof App
79
- * @constant {string}
80
- * @default 'main'
49
+ * @param {Object} [options] - App options.
50
+ * @param {string} [options.cwd] - Set current working directory. Defaults to the script directory.
51
+ * @param {string[]} [options.plugins] - Array of plugins to load. If provided, it override the list in ```package.json``` and ```.plugins``` file.
52
+ * @param {Object} [options.config] - Plugin's config object. If provided, plugin configs will no longer be read from its config files.
81
53
  */
82
- static mainNs = 'main'
54
+ constructor (options = {}) {
55
+ /**
56
+ * Copy of provided options.
57
+ *
58
+ * @type {Object}
59
+ */
60
+ this.options = options
83
61
 
84
- /**
85
- * App environments
86
- * @memberof App
87
- * @constant {TAppEnv}
88
- */
89
- static envs = { dev: 'development', prod: 'production' }
62
+ /**
63
+ * Your main namespace. And yes, you suppose to NOT CHANGE this.
64
+ *
65
+ * @memberof App
66
+ * @constant {string}
67
+ * @default 'main'
68
+ */
69
+ this.mainNs = 'main'
70
+
71
+ /**
72
+ * App environments.
73
+ *
74
+ * @memberof App
75
+ * @constant {TAppEnv}
76
+ */
77
+ this.envs = { dev: 'development', prod: 'production' }
90
78
 
91
- /**
92
- * @param {string} cwd - Current working dirctory
93
- */
94
- constructor (cwd) {
95
79
  /**
96
- * Date/time when your app start
80
+ * Date/time when your app start.
81
+ *
97
82
  * @type {Date}
98
83
  */
99
84
  this.runAt = new Date()
100
85
 
101
86
  /**
102
- * Applets
87
+ * Applets container.
103
88
  *
104
89
  * @type {Array}
105
90
  */
106
91
  this.applets = []
107
92
 
108
93
  /**
109
- * List of all loaded plugin's package names
94
+ * Plugin's package names container. This is the list of plugins to load. It is read from ```package.json``` and ```.plugins``` file by default, but you can override it by providing ```options.plugins``` at constructor.
110
95
  *
111
96
  * @type {Array}
112
97
  */
113
- this.pluginPkgs = []
98
+ this.pluginPkgs = options.plugins ?? []
114
99
 
115
100
  /**
116
101
  * @typedef {Object} TAppConfigHandler
117
- * @property {string} ext - File extension
118
- * @property {function} [readHandler] - Function to call for reading
119
- * @property {function} [writeHandler] - Function to call for writing
102
+ * @property {string} ext - File extension.
103
+ * @property {function} [readHandler] - Function to call for reading.
104
+ * @property {function} [writeHandler] - Function to call for writing.
120
105
  * @see App#configHandlers
121
106
  */
122
107
 
@@ -125,7 +110,7 @@ class App {
125
110
  *
126
111
  * By default, there are two built-in handlers available: ```.js```
127
112
  * and ```.json```. Use plugins to add more, e.g {@link https://github.com/ardhi/bajo-config|bajo-config}
128
- * lets you to use ```.yaml/.yml``` and ```.toml```
113
+ * lets you to use ```.yaml/.yml``` and ```.toml```.
129
114
  *
130
115
  * @type {TAppConfigHandler[]}
131
116
  */
@@ -145,35 +130,36 @@ class App {
145
130
  */
146
131
  this.lib = lib
147
132
  this.lib.outmatchNs = outmatchNs.bind(this)
133
+ this.lib.parseObject = parseObject.bind(this)
148
134
 
149
135
  /**
150
- * Instance of system log
136
+ * Instance of system log.
151
137
  *
152
138
  * @type {Log}
153
139
  */
154
140
  this.log = {}
155
141
 
156
142
  /**
157
- * All plugin's class definitions are saved here as key-value pairs with plugin name as its key.
158
- * The special key ```base``` is for {@link Base}'s class so anytime you want to
143
+ * All plugin's base class are saved here as key-value pairs with plugin name as its key.
144
+ * The special key ```Base``` &amp;&amp; ```Tools``` is for {@link Base} &amp; {@link Tools} class so anytime you want to
159
145
  * create your own plugin, just use something like this:
160
146
  *
161
147
  * ```javascript
162
- * class MyPlugin extends this.app.pluginClass.base {
148
+ * class MyPlugin extends this.app.baseClass.Base {
163
149
  * ... your class
164
150
  * }
165
151
  */
166
- this.pluginClass = { base: Base }
152
+ this.baseClass = { Base, Tools }
167
153
 
168
154
  /**
169
- * If app runs in applet mode, this will be the applet's name
155
+ * If app runs in applet mode, this will be the applet's name.
170
156
  *
171
157
  * @type {string}
172
158
  */
173
159
  this.applet = undefined
174
160
 
175
161
  /**
176
- * Program arguments
162
+ * Program arguments.
177
163
  *
178
164
  * ```
179
165
  * $ node index.js arg1 arg2
@@ -234,57 +220,176 @@ class App {
234
220
  */
235
221
  this.envVars = {}
236
222
 
237
- if (!cwd) cwd = process.cwd()
223
+ /**
224
+ * Placeholder for boxen that will get imported from ```bajoCli``` later during boot process.
225
+ */
226
+ this.boxen = null
227
+
228
+ this.cache = new Cache(this)
229
+
230
+ if (!options.cwd) options.cwd = process.cwd()
238
231
  const l = last(process.argv)
239
232
  if (l.startsWith('--cwd')) {
240
233
  const parts = l.split('=')
241
- cwd = parts[1]
234
+ options.cwd = parts[1]
242
235
  }
243
- this.dir = resolvePath(cwd)
236
+ this.dir = this.lib.aneka.resolvePath(options.cwd)
244
237
  process.env.APPDIR = this.dir
245
238
  }
246
239
 
247
- get mainNs () {
248
- return this.constructor.mainNs
249
- }
250
-
251
240
  /**
252
- * Add and save plugin and it's class definition (if provided)
241
+ * Add and save plugin and it's base class definition (if provided).
253
242
  *
254
243
  * @method
255
- * @param {TPlugin} plugin - A valid bajo plugin
256
- * @param {Object} [pluginClass] - Plugin's class definition
244
+ * @param {TPlugin} plugin - A valid bajo plugin.
245
+ * @param {Object} [baseClass] - Base class definition.
257
246
  */
258
- addPlugin = (plugin, pluginClass) => {
247
+ addPlugin = (plugin, baseClass) => {
259
248
  if (this[plugin.ns]) throw new Error(`Plugin '${plugin.ns}' added already`)
260
249
  this[plugin.ns] = plugin
261
- if (pluginClass) this.pluginClass[plugin.ns] = pluginClass
250
+ if (baseClass) this.baseClass[pascalCase(plugin.ns)] = baseClass
262
251
  }
263
252
 
264
253
  /**
265
- * Get all loaded plugin namesspaces
254
+ * Get all loaded plugin namespaces.
266
255
  *
267
256
  * @method
268
257
  * @returns {string[]}
269
258
  */
270
259
  getAllNs = () => {
271
- return without(keys(this.pluginClass), 'base')
260
+ return this.pluginPkgs.map(pkg => camelCase(pkg))
272
261
  }
273
262
 
274
263
  /**
275
- * Dumping variable on screen. Like ```console.log``` but with max 10 depth.
264
+ * Get loaded plugins.
276
265
  *
277
266
  * @method
278
- * @param {...any} args - any arguments passed will be displayed on screen. If the last argument is a boolean 'true', app will quit rightaway
267
+ * @param {string[]} [nss] - Array of namespaces. If empty, it returns all loaded plugins.
268
+ * @returns {TPlugin[]}
269
+ */
270
+ getPlugins = (nss) => {
271
+ const allNs = nss ?? this.getAllNs()
272
+ return allNs.map(ns => this[ns])
273
+ }
274
+
275
+ /**
276
+ * Get all plugins loaded plugins.
277
+ *
278
+ * @method
279
+ * @returns {TPlugin[]}
280
+ */
281
+ getAllPlugins = () => {
282
+ return this.getPlugins()
283
+ }
284
+
285
+ /**
286
+ * Get plugin by its namespace.
287
+ *
288
+ * @method
289
+ * @param {string} name - Plugin name/namespace or alias.
290
+ * @param {boolean} [silent] - If ```true```, silently return undefined even on error.
291
+ * @returns {Object} Plugin object.
292
+ */
293
+ getPlugin = (name, silent) => {
294
+ if (!this[name]) {
295
+ // alias?
296
+ let plugin
297
+ for (const key in this) {
298
+ const item = this[key]
299
+ if (item instanceof Plugin &amp;&amp; (item.alias === name || item.pkgName === name)) {
300
+ plugin = item
301
+ break
302
+ }
303
+ }
304
+ if (!plugin) {
305
+ if (silent) return false
306
+ throw this.bajo.error('pluginWithNameAliasNotLoaded%s', name)
307
+ }
308
+ name = plugin.ns
309
+ }
310
+ return this[name]
311
+ }
312
+
313
+ /**
314
+ * Get plugin data directory
315
+ *
316
+ * @method
317
+ * @param {string} name - Plugin name (namespace) or alias.
318
+ * @param {boolean} [ensureDir=true] - Set ```true``` (default) to ensure directory is existed.
319
+ * @returns {string}
320
+ */
321
+ getPluginDataDir = (name, ensureDir = true) => {
322
+ const { fs } = this.lib
323
+ const plugin = this.getPlugin(name)
324
+ const dir = `${this.bajo.dir.data}/plugins/${plugin.ns}`
325
+ if (ensureDir) fs.ensureDirSync(dir)
326
+ return dir
327
+ }
328
+
329
+ /**
330
+ * Resolve file path from:
331
+ *
332
+ * - local/absolute file
333
+ * - TNsPath (```myPlugin:/path/to/file.txt```)
334
+ * - file under node_modules, e.g. ```myPlugin:node_modules/some-package/file.txt```
335
+ *
336
+ * @method
337
+ * @param {string} file - File path, see above for supported types.
338
+ * @returns {string} Resolved file path.
339
+ */
340
+ getPluginFile = (file) => {
341
+ const { currentLoc } = this.lib.aneka
342
+ const { fs } = this.lib
343
+ const { trim } = this.lib._
344
+ if (!this) return file
345
+ if (file[0] === '.') file = `${currentLoc(import.meta).dir}/${trim(file.slice(1), '/')}`
346
+ if (file.includes(':')) {
347
+ if (file.slice(1, 2) === ':') return file // windows fs
348
+ const { ns, path } = this.bajo.breakNsPath(file, false)
349
+ if (ns !== 'file' &amp;&amp; this &amp;&amp; this[ns] &amp;&amp; ns.length > 1) {
350
+ file = `${this[ns].dir.pkg}${path}`
351
+ if (path.startsWith('node_modules/')) {
352
+ file = `${this[ns].dir.pkg}/${path}`
353
+ if (!fs.existsSync(file)) file = `${this[ns].dir.pkg}/../${path.slice('node_modules/'.length)}`
354
+ }
355
+ }
356
+ }
357
+ return file
358
+ }
359
+
360
+ /**
361
+ * Dumping variable on screen. Like ```console.log``` with configurable options. Useful for quick debugging and testing. You can also use it to dump variables in production without worrying about performance because it is using Bajo's built-in cache to store the result of util's inspect, so it will only be processed once for each unique variable.
362
+ *
363
+ * Any argument passed to this method will be displayed on screen.
364
+ * If the last argument is a boolean ```true```, app will quit rightaway after dumping.
365
+ *
366
+ * If you have ```bajoCli``` plugin installed, variables will be displayed in a nice box using ```boxen``` package.
367
+ * Otherwise, it will fallback to ```console.log``` with util's inspect result.
368
+ *
369
+ * To have more control on how the variable is displayed, you can set options in Bajo's config under ```dump``` key.
370
+ * See {@link Bajo#config} for details.
371
+ *
372
+ * @method
373
+ * @param {...any} args - Variables to dump.
279
374
  */
280
375
  dump = (...args) => {
281
- const terminate = last(args) === true
376
+ let caller = getCallerFilename()
377
+ caller = caller ? fileURLToPath(caller) : 'Unavailable'
378
+ const opts = last(args)
379
+ const terminate = isPlainObject(opts) &amp;&amp; opts.abort
282
380
  if (terminate) args.pop()
283
- for (const arg of args) {
284
- const result = util.inspect(arg, { depth: 10, colors: true })
381
+ const value = args.length === 1 ? args[0] : args
382
+ const options = { ...this.bajo.config.dump }
383
+ if (this.boxen) {
384
+ const result = util.inspect(value, options)
385
+ const opts = { ...this.bajo.config.dump.frame }
386
+ if (options.caller) opts.title = `Caller: ${caller}`
387
+ console.log(this.boxen(result, opts))
388
+ } else {
389
+ const result = util.inspect(options.caller ? [caller, value] : value, options)
285
390
  console.log(result)
286
391
  }
287
- if (terminate) process.kill(process.pid, 'SIGINT')
392
+ if (terminate) process.exit('1')
288
393
  }
289
394
 
290
395
  /**
@@ -294,27 +399,42 @@ class App {
294
399
  * - Create {@link Bajo|Bajo} instance &amp; initialize it
295
400
  * - {@link module:Helper/Bajo.runAsApplet|Run in applet mode} if ```-a``` or ```--applet``` is given
296
401
  *
297
- * After boot process is completed, event ```bajo:afterBootComplete``` is emitted.
402
+ * After boot process is completed, event ```bajo:afterBootCompleted``` is emitted.
298
403
  *
299
404
  * If app mode is ```applet```, it runs your choosen applet instead.
300
405
  *
301
406
  * @method
302
407
  * @async
303
408
  * @returns {App}
304
- * @fires bajo:afterBootComplete
409
+ * @fires bajo:afterBootCompleted
305
410
  */
306
411
  boot = async () => {
307
- // argv/args/env
308
412
  this.bajo = new Bajo(this)
309
- const { argv, args } = await parseArgsArgv.call(this) ?? {}
413
+ const hooks = (this.options.hooks ?? []).map(item => {
414
+ item.src = item.src ?? 'bajo'
415
+ return item
416
+ })
417
+ this.bajo.hooks.push(...hooks)
418
+ delete this.options.hooks
419
+ // argv/args/env
420
+ const { parseArgsArgv, parseEnv, secToHms } = this.lib.aneka
421
+ const { parseObject } = this.lib
422
+ const { argv, args } = await parseArgsArgv({ cwd: this.options.cwd })
423
+
310
424
  this.args = args
311
- this.argv = argv
312
- this.envVars = parseEnv.call(this)
425
+ this.argv = parseObject(argv, { parseValue: true })
426
+ this.envVars = parseObject(parseEnv(), { parseValue: true })
427
+ if (get(this, 'envVars._.env') === '[object Object]') set(this, 'envVars._.env', 'dev')
313
428
  this.applet = this.envVars._.applet ?? this.argv._.applet
429
+ await this.bajo.runHook('bajo:beforeBoot')
314
430
  await this.bajo.init()
431
+ if (this.bajoCli) this.boxen = await this.bajo.importPkg('bajoCli:boxen')
432
+ // cache
433
+ this.cache.purge()
434
+ setInterval(this.cache.purge, this.bajo.config.cache.purgeIntvDur)
315
435
  // boot complete
316
436
  const elapsed = new Date() - this.runAt
317
- this.bajo.log.debug('bootCompleted%s', this.lib.aneka.secToHms(elapsed, true))
437
+ this.bajo.log.debug('bootCompleted%s', secToHms(elapsed, true))
318
438
  /**
319
439
  * Run after boot process is completed
320
440
  *
@@ -323,28 +443,31 @@ class App {
323
443
  * @see {@tutorial hook}
324
444
  * @see App#boot
325
445
  */
326
- await this.bajo.runHook('bajo:afterBootComplete')
446
+ await this.bajo.runHook('bajo:afterBoot')
327
447
  if (this.applet) await runAsApplet.call(this.bajo)
328
448
  return this
329
449
  }
330
450
 
331
451
  /**
332
- * Terminate the app and back to console
452
+ * Terminate the app and back to console.
333
453
  *
334
454
  * @method
335
- * @param {string} [signal=SIGINT] - Signal to send
455
+ * @param {string} [signal=SIGINT] - Signal to send.
336
456
  */
337
457
  exit = (signal = 'SIGINT') => {
338
- process.kill(process.pid, 'SIGINT')
458
+ if (signal === true) process.exit('1')
459
+ process.kill(process.pid, signal)
339
460
  }
340
461
 
341
462
  /**
342
- * Load internationalization &amp; languages files for particular plugin
463
+ * Load internationalization &amp; languages files for particular plugin.
343
464
  *
344
465
  * @method
345
- * @param {string} ns - Plugin name
466
+ * @param {string} ns - Plugin name.
346
467
  */
347
468
  loadIntl = (ns) => {
469
+ const { fs } = this.lib
470
+
348
471
  this[ns].intl = {}
349
472
  for (const l of this.bajo.config.intl.supported) {
350
473
  this[ns].intl[l] = {}
@@ -357,25 +480,9 @@ class App {
357
480
  }
358
481
  }
359
482
 
360
- /**
361
- * Translate text and interpolate with given ```args```.
362
- *
363
- * There is a shortcut to this method attached on all plugins. You'll normally call that shorcut
364
- * instead of this method, because it is bound to plugin's name already
365
- *
366
- * ```javascript
367
- * ... within your main plugin
368
- * const translated = this.app.t('main', 'My cute cat is %s', 'purring')
369
- * // or
370
- * const translated = this.t('My cute cat is %s', 'purring')
371
- * ```
372
- * @method
373
- * @param {string} ns - Namespace
374
- * @param {string} text - Text to translate
375
- * @param {...any} params - Arguments
376
- * @returns {string}
377
- */
378
- t = (ns, text, ...params) => {
483
+ _prepTrans = (ns, text, params) => {
484
+ const { fallback, supported } = this.bajo.config.intl
485
+ const { isSet } = this.lib.aneka
379
486
  if (!text) {
380
487
  text = ns
381
488
  ns = 'bajo'
@@ -386,7 +493,6 @@ class App {
386
493
  params.pop()
387
494
  if (opts.lang) lang = opts.lang
388
495
  }
389
- const { fallback, supported } = this.bajo.config.intl
390
496
  if (!unknownLangWarning &amp;&amp; !supported.includes(lang)) {
391
497
  unknownLangWarning = true
392
498
  this.bajo.log.warn(`Unsupported language, fallback to '${fallback}'`)
@@ -394,30 +500,69 @@ class App {
394
500
  const plugins = reverse(without([...this.getAllNs()], ns))
395
501
  plugins.unshift(ns)
396
502
  plugins.push('bajo')
397
-
398
503
  let trans
399
504
  for (const p of plugins) {
400
505
  const store = get(this, `${p}.intl.${lang}`, {})
401
506
  trans = get(store, text)
402
- if (trans) break
507
+ if (isSet(trans)) break
403
508
  }
404
- if (!trans) {
509
+ if (!isSet(trans)) {
405
510
  for (const p of plugins) {
406
511
  const store = get(this, `${p}.intl.${fallback}`, {})
407
512
  trans = get(store, text)
408
- if (trans) break
513
+ if (isSet(trans)) break
409
514
  }
410
515
  }
411
- if (!trans) trans = text
412
- const values = map(params, a => {
413
- if (!isString(a)) return a
414
- return a
415
- })
416
- return sprintf(trans, ...values)
516
+ return { ns, text, lang, params, plugins, trans }
517
+ }
518
+
519
+ /**
520
+ * Translate text and interpolate with given ```args```.
521
+ *
522
+ * There is a shortcut to this method attached on all plugins. You'll normally call that shorcut
523
+ * instead of this method, because it is bound to plugin's name already
524
+ *
525
+ * ```javascript
526
+ * ... within your main plugin
527
+ * const translated = this.app.t('main', 'My cute cat is %s', 'purring')
528
+ * // or
529
+ * const translated = this.t('My cute cat is %s', 'purring')
530
+ * ```
531
+ * @method
532
+ * @param {string} ns - Namespace.
533
+ * @param {string} text - Text to translate.
534
+ * @param {...any} params - Arguments.
535
+ * @returns {string}
536
+ */
537
+ t = (ns, text, ...params) => {
538
+ const { formatText, isSet } = this.lib.aneka
539
+ const { isArray, last } = this.lib._
540
+ const { join } = this.bajo
541
+ let { text: newText, trans, params: args } = this._prepTrans(ns, text, params)
542
+ if (!isSet(trans)) trans = newText
543
+ const lang = isPlainObject(last(args)) ? last(args).lang : undefined
544
+ for (const idx in args) {
545
+ const arg = args[idx]
546
+ if (isArray(arg)) args[idx] = join(arg, { lang })
547
+ }
548
+ return formatText(trans, ...args)
549
+ }
550
+
551
+ /**
552
+ * Check whether translation text/key exists
553
+ *
554
+ * @method
555
+ * @param {string} ns - Namespace.
556
+ * @param {string} text - Text to translate.
557
+ * @returns {boolean}
558
+ */
559
+ te = (ns, text, ...params) => {
560
+ const { trans } = this._prepTrans(ns, text, params)
561
+ return !!trans
417
562
  }
418
563
 
419
564
  /**
420
- * Helper method to list all supported config formats
565
+ * Helper method to list all supported config formats.
421
566
  *
422
567
  * @returns {string[]}
423
568
  */
@@ -425,14 +570,27 @@ class App {
425
570
  return map(this.configHandlers, 'ext')
426
571
  }
427
572
 
573
+ /**
574
+ * Start a plugin.
575
+ *
576
+ * @param {string} ns - Plugin namespace.
577
+ * @param {...any} args - Arguments to pass to the plugin's start method.
578
+ */
428
579
  startPlugin = (ns, ...args) => {
429
580
  this[ns].start(...args)
430
581
  }
431
582
 
583
+ /**
584
+ * Stop a plugin.
585
+ *
586
+ * @param {string} ns - Plugin namespace.
587
+ * @param {...any} args - Arguments to pass to the plugin's stop method.
588
+ */
432
589
  stopPlugin = (ns, ...args) => {
433
- this[ns].stop(...args)
590
+ // Disabled for now, reserved for future use. It is not a good idea to stop a plugin because other plugins might be dependent on it.
591
+ // this[ns].stop(...args)
434
592
  }
435
593
  }
436
594
 
437
595
  export default App
438
- </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="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><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</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#event:bajo:afterAll%257Bmethod%257D">bajo:afterAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBootComplete">bajo:afterBootComplete</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBuildCollection">bajo:afterBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterCollectHooks">bajo:afterCollectHooks</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeAll%257Bmethod%257D">bajo:beforeAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeBuildCollection">bajo:beforeBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:afterAppletRun">{ns}:afterAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:after%257Bmethod%257D">{ns}:after{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:beforeAppletRun">{ns}:beforeAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:before%257Bmethod%257D">{ns}:before{method}</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_Bajo.html">Helper/Bajo</a></div><div class="sidebar-section-children"><a href="module-Helper_Base.html">Helper/Base</a></div><div class="sidebar-section-children"><a href="module-Lib.html">Lib</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#TAppConfigHandler">TAppConfigHandler</a></div><div class="sidebar-section-children"><a href="global.html#TAppEnv">TAppEnv</a></div><div class="sidebar-section-children"><a href="global.html#TAppLib">TAppLib</a></div><div class="sidebar-section-children"><a href="global.html#TBajoDataType">TBajoDataType</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatResult">TBajoFormatResult</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatType">TBajoFormatType</a></div><div class="sidebar-section-children"><a href="global.html#TLogJson">TLogJson</a></div><div class="sidebar-section-children"><a href="global.html#TLogLevels">TLogLevels</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathPairs">TNsPathPairs</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathResult">TNsPathResult</a></div><div class="sidebar-section-children"><a href="global.html#TPrintOptions">TPrintOptions</a></div><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>
596
+ </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-events"><div>Events</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#event:bajo:afterAll%257Bmethod%257D">bajo:afterAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBootComplete">bajo:afterBootComplete</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterBuildCollection">bajo:afterBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:afterCollectHooks">bajo:afterCollectHooks</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeAll%257Bmethod%257D">bajo:beforeAll{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:bajo:beforeBuildCollection">bajo:beforeBuildCollection</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:after%257Bmethod%257D">{ns}:after{method}</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:beforeAppletRun">{ns}:beforeAppletRun</a></div><div class="sidebar-section-children"><a href="global.html#event:%257Bns%257D:before%257Bmethod%257D">{ns}:before{method}</a></div><div class="sidebar-section-children"><a href="module-Helper%257Bns%257D_afterAppletRun.html">Helper{ns}:afterAppletRun</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-Lib.html">Lib</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#TAppConfigHandler">TAppConfigHandler</a></div><div class="sidebar-section-children"><a href="global.html#TAppEnv">TAppEnv</a></div><div class="sidebar-section-children"><a href="global.html#TBajoDataType">TBajoDataType</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatResult">TBajoFormatResult</a></div><div class="sidebar-section-children"><a href="global.html#TBajoFormatType">TBajoFormatType</a></div><div class="sidebar-section-children"><a href="global.html#TLogJson">TLogJson</a></div><div class="sidebar-section-children"><a href="global.html#TLogLevels">TLogLevels</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathPairs">TNsPathPairs</a></div><div class="sidebar-section-children"><a href="global.html#TNsPathResult">TNsPathResult</a></div><div class="sidebar-section-children"><a href="global.html#TPrintOptions">TPrintOptions</a></div><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>