@abw/badger 1.0.4 → 1.0.5

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/README.md CHANGED
@@ -25,7 +25,7 @@ Install `badger` using your favourite package manager.
25
25
  ## Manual
26
26
 
27
27
  Read the [Manual](https://abw.github.io/badger-js/docs/manual/) for an introduction to the
28
- toolkit and example of use.
28
+ toolkit and examples of use.
29
29
  ## API Documentation
30
30
 
31
31
  Read the [API documentation](https://abw.github.io/badger-js/docs/) for further information
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("js-yaml"),e=require("node:process"),r=require("node:path"),s=require("node:fs/promises");function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}function o(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,s.get?s:{enumerable:!0,get:function(){return t[r]}})}})),e.default=t,Object.freeze(e)}var n=i(t),a=i(e),u=i(r);function c(t){return"string"==typeof t}function d(t){return Array.isArray(t)}function h(t){return"object"==typeof t&&!d(t)&&!f(t)}function p(t){return void 0===t}function f(t){return null===t}function l(t){return!(p(t)||f(t))}function g(t){return!l(t)}function b(...t){throw new Error(t.join(""))}function x(t){throw t}function y(){}const m={reset:0,bold:1,bright:1,dark:2,black:0,red:1,green:2,yellow:3,blue:4,magenta:5,cyan:6,grey:7,white:8,fg:30,bg:40},w=(t,e="fg")=>{let r=[],s=t.split(/ /,2);const i=s.pop(),o=(e?m[e]:0)+m[i];if(r.push(o),s.length){const t=s.length?s.shift():"dark";r.push(m[t])}return"["+r.join(";")+"m"};function j(t,e="",r){return t?e?(t,...s)=>console.log("%s"+e+"%s"+t,r?((t={})=>{const e=h(t)?t:{fg:t};let r=[];return e.bg&&r.push(w(e.bg,"bg")),e.fg&&r.push(w(e.fg,"fg")),r.join("")})(r):"",w("reset",!1),...s):console.log.bind(console):y}function E(t,e,r="",s){t.debug=j(e,r,s)}const v={json:{encode:t=>JSON.stringify(t),decode:t=>JSON.parse(t)},yaml:{encode:t=>n.default.dump(t),decode:t=>n.default.load(t)}},P=t=>v[t.toLowerCase()],k={encoding:"utf8"};class D{constructor(t,e={}){t instanceof D&&(t=t.path()),this.state={path:t,options:{...k,...e}},E(this,e.debug,e.debugPrefix||"Path",e.debugColor)}path(){return this.state.path}relativePath(...t){return u.default.join(this.state.path,...t)}options(t={}){return{...this.state.options,...t}}async exists(){try{return await this.stat(),!0}catch(t){return"ENOENT"!==t.code&&x(t)}}async stat(){const t=await s.stat(this.state.path);return this.state.stats=t}unstat(){return this.state.stats=void 0,this}}class C extends D{directory(t){return F(u.default.dirname(this.state.path),t)}dir(...t){return this.directory(...t)}read(t){const e=this.options(t),r=s.readFile(this.state.path,e);return e.codec?r.then((t=>P(e.codec).decode(t))):r}write(t,e){const r=this.options(e),i=r.codec?P(r.codec).encode(t):t;return s.writeFile(this.state.path,i,r).then((()=>this))}async delete(t){return await s.rm(this.state.path,t),this}}const O=(t,e)=>new C(t,e);class q extends D{file(t,e){return this.debug("file(%s, %o)",t,e),O(this.relativePath(t),this.options(e))}directory(t,e){return this.debug("directory(%s, %o)",t,e),F(this.relativePath(t),this.options(e))}dir(t,e){return this.debug("dir(%s, %o)",t,e),this.directory(t,e)}parent(t){return this.debug("parent()"),this.directory("..",t)}async read(){return this.debug("read()"),await s.readdir(this.path())}async isEmpty(){this.debug("isEmpty()");return 0===(await this.read()).length}async notEmpty(){this.debug("notEmpty()");return!await this.isEmpty()}async empty(t={}){return this.debug("empty(%o)",t),await this.exists()&&await this.notEmpty()&&await s.rm(this.path(),t),this}async mkdir(t={}){this.debug("mkdir(%o)",t);return await this.exists()||await s.mkdir(this.path(),t),this}async rmdir(t={}){return this.debug("rmdir(%o)",t),t.empty&&await this.empty(t),await this.exists()&&await s.rmdir(this.path()),this}create(t={recursive:!0}){return this.debug("create(%o)",t),this.mkdir(t)}destroy(t={empty:!0,recursive:!0,force:!0}){return this.debug("destroy(%o)",t),this.rmdir(t)}async mustExist(t={}){return this.debug("mustExist(%o)",t),await this.exists()?this:t.mkdir?this.mkdir(t):t.create?this.create():void b("Directory does not exist: ",this.path())}}const F=(t,e)=>new q(t,e);function L(t){return g(t)?[]:c(t)?t.length?t.split(/,\s*|\s+/):[]:d(t)?t:[t]}function N(t,e=" ",r=e){let s=[...t];const i=s.pop();return s.length?[s.join(e),i].join(r):i}function _(t,e=", ",r=" or "){return N(t,e,r)}function A(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}class M{constructor(t){const e=this.initDirs(t);this.state={dirs:e}}initDirs(t){return L(t).map((t=>F(t)))}async dirs(){return this.state.dirsExist||(this.state.dirsExist=await this.dirsExist())}async dirsExist(){const t=this.state.dirs,e=await Promise.all(t.map((t=>t.exists())));return t.filter(((t,r)=>e[r]))}}const S={codecs:["yaml","json"],jsExt:["js","mjs"]};class W extends M{constructor(t,e={}){super(t);const r={...S,...e};this.state.codecs=L(r.codecs),this.state.jsExt=L(r.jsExt),E(this,e.debug,e.debugPrefix,e.debugColor)}async firstFileWithExt(t,e,r=y){const s=await this.dirs();for(let i of s)for(let s of e){const e=t+"."+s,o=i.file(e,r(t,s));if(this.debug("looking for config file: ",o.path()),await o.exists())return this.debug("config file exists: ",o.path()),o}}async jsFile(t){return await this.firstFileWithExt(t,this.state.jsExt)}async file(t){return await this.firstFileWithExt(t,this.state.codecs,((t,e)=>({codec:e})))}async config(t,e){const r=await this.jsFile(t);if(r){return(await(s=r.path(),Promise.resolve().then((function(){return o(require(s))})))).default}var s;const i=await this.file(t);return i?await i.read():e||b("No configuration file for "+t)}}const T={jsExt:"js mjs"};class V extends M{constructor(t,e={}){super(t);const r=L({...T,...e}.jsExt).map((t=>t.replace(/^\./,"")));this.state.exts=r,E(this,e.debug,e.debugPrefix,e.debugColor),this.debug("state: ",this.state)}async lib(t){const e=await this.dirs(),r=this.state.exts;for(let s of e)for(let e of r){const r=s.file(t+"."+e);this.debug("looking for module %s as",t,r.path());if(await r.exists()){const t=await function(t){return Promise.resolve().then((function(){return o(require(t))}))}(r.path());return this.debug("loaded %s as",r.path()),t}}b("Library not found: ",t)}}function J(t={},e){const r=t[e];if(l(r))return r;b("Missing value for required parameter: ",e)}function U(t={},e){return L(e).map((e=>J(t,e)))}const z=U;const B={dir:"lib library src components"},G={dir:"config"};class H{constructor(t,e={}){const r=F(t),s=r.dir(e.config?.dir||G.dir),i={...G,...e.config||{}},o=new W(s,i),n=L(e.library?.dir||B.dir).map((t=>r.dir(t))),a={...B,...e.library||{}},u=new V(n,a);this.state={rootDir:r,config:o,library:u},E(this,e.debug,e.debugPrefix,e.debugColor),this.debug("root dir: ",r.path()),this.debug("config dir: ",s.path()),this.debug("libDirs: ",n),this.debug("libOpts: ",a)}dir(t,e){return this.debug("dir(%s, %o)",t,e),l(t)?this.state.rootDir.dir(t,e):this.state.rootDir}file(t,e){return this.debug("file(%s, %o)",t,e),this.state.rootDir.file(t,e)}read(t,e){return this.debug("read(%s, %o)",t,e),this.file(t,e).read()}write(t,e,r){return this.debug("write(%s, %o, %o)",t,e,r),this.file(t,r).write(e)}configDir(t,e){return this.debug("configDir(%s, %o)",t,e),l(t)?this.state.configDir(t,e):this.state.configDir}async config(t,e){return this.debug("config(%s, %o)",t,e),l(t)?this.state.config.config(t,e):this.state.config}async lib(t){return this.state.library.lib(t)}async component(t,e){const r=await this.config(t,{}),s=await this.lib(r.component?.library||t),i=r.component?.export||"default";return new(s[i]||b("No '",i,"' export from component library: ",t))(this,{...r,...e})}}exports.Component=class{constructor(t,e={}){this.workspace=t,this.props=e,E(this,e.debug,e.debugPrefix,e.debugColor),this.initComponent(e)}initComponent(){}},exports.Config=W,exports.Debugger=j,exports.Library=V,exports.Path=D,exports.Workspace=H,exports.addDebug=E,exports.allParams=z,exports.anyParams=function(t,e){let r=!1;const s=L(e),i=s.map((e=>{const s=t[e];return l(s)&&(r=!0),s}));return r?i:b("Missing value for one of: ",_(s))},exports.bin=(t,e)=>F(u.default.dirname(t.replace(/^file:\/\//,"")),e),exports.capitalise=A,exports.codec=P,exports.codecs=v,exports.config=(t,e)=>new W(t,e),exports.cwd=t=>F(a.default.cwd(),t),exports.dir=F,exports.doNothing=y,exports.fail=b,exports.file=O,exports.hasValue=l,exports.haveValue=function(...t){return t.every((t=>l(t)))},exports.isArray=d,exports.isFunction=function(t){return"function"==typeof t},exports.isNull=f,exports.isObject=h,exports.isString=c,exports.isUndefined=p,exports.joinList=N,exports.joinListAnd=function(t,e=", ",r=" and "){return N(t,e,r)},exports.joinListOr=_,exports.library=(t,e)=>new V(t,e),exports.noValue=g,exports.requiredParam=J,exports.requiredParams=U,exports.rethrow=x,exports.snakeToCamel=function(t){return t.split("/").map((t=>t.split("_").map(((t,e)=>e?A(t):t)).join(""))).join("/")},exports.snakeToStudly=function(t){return t.split("/").map((t=>t.split("_").map(A).join(""))).join("/")},exports.splitList=L,exports.workspace=(t,e)=>new H(t,e);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("js-yaml"),e=require("node:process"),r=require("node:path"),s=require("node:fs/promises");function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}function o(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,s.get?s:{enumerable:!0,get:function(){return t[r]}})}})),e.default=t,Object.freeze(e)}var n=i(t),a=i(e),u=i(r);function c(t){return"string"==typeof t}function h(t){return Array.isArray(t)}function d(t){return"object"==typeof t&&!h(t)&&!l(t)}function p(t){return void 0===t}function l(t){return null===t}function f(t){return!(p(t)||l(t))}function g(t){return!f(t)}function b(...t){throw new Error(t.join(""))}function x(t){throw t}function y(){}const m={reset:0,bold:1,bright:1,dark:2,black:0,red:1,green:2,yellow:3,blue:4,magenta:5,cyan:6,grey:7,white:8,fg:30,bg:40},w=(t,e="fg")=>{let r=[],s=t.split(/ /,2);const i=s.pop(),o=(e?m[e]:0)+m[i];if(r.push(o),s.length){const t=s.length?s.shift():"dark";r.push(m[t])}return"["+r.join(";")+"m"},j=(t={})=>{const e=d(t)?t:{fg:t};let r=[];return e.bg&&r.push(w(e.bg,"bg")),e.fg&&r.push(w(e.fg,"fg")),r.join("")},v=()=>w("reset",!1);function E(t,e="",r){return t?e?(t,...s)=>console.log("%s"+e+"%s"+t,r?j(r):"",v(),...s):console.log.bind(console):y}function P(t,e,r="",s){t.debug=E(e,r,s)}const D={json:{encode:t=>JSON.stringify(t),decode:t=>JSON.parse(t)},yaml:{encode:t=>n.default.dump(t),decode:t=>n.default.load(t)}},k=t=>D[t.toLowerCase()],C={encoding:"utf8"};class O{constructor(t,e={}){t instanceof O&&(t=t.path()),this.state={path:t,options:{...C,...e}},P(this,e.debug,e.debugPrefix||"Path",e.debugColor)}path(){return this.state.path}relativePath(...t){return u.default.join(this.state.path,...t)}options(t={}){return{...this.state.options,...t}}async exists(){try{return await this.stat(),!0}catch(t){return"ENOENT"!==t.code&&x(t)}}async stat(){const t=await s.stat(this.state.path);return this.state.stats=t}unstat(){return this.state.stats=void 0,this}}class N extends O{directory(t){return A(u.default.dirname(this.state.path),t)}dir(...t){return this.directory(...t)}read(t){const e=this.options(t),r=s.readFile(this.state.path,e);return e.codec?r.then((t=>k(e.codec).decode(t))):r}write(t,e){const r=this.options(e),i=r.codec?k(r.codec).encode(t):t;return s.writeFile(this.state.path,i,r).then((()=>this))}async delete(t){return await s.rm(this.state.path,t),this}}const S=(t,e)=>new N(t,e);class q extends O{file(t,e){return this.debug("file(%s, %o)",t,e),S(this.relativePath(t),this.options(e))}directory(t,e){return this.debug("directory(%s, %o)",t,e),A(this.relativePath(t),this.options(e))}dir(t,e){return this.debug("dir(%s, %o)",t,e),this.directory(t,e)}parent(t){return this.debug("parent()"),this.directory("..",t)}async read(){return this.debug("read()"),await s.readdir(this.path())}async isEmpty(){this.debug("isEmpty()");return 0===(await this.read()).length}async notEmpty(){this.debug("notEmpty()");return!await this.isEmpty()}async empty(t={}){return this.debug("empty(%o)",t),await this.exists()&&await this.notEmpty()&&await s.rm(this.path(),t),this}async mkdir(t={}){this.debug("mkdir(%o)",t);return await this.exists()||await s.mkdir(this.path(),t),this}async rmdir(t={}){return this.debug("rmdir(%o)",t),t.empty&&await this.empty(t),await this.exists()&&await s.rmdir(this.path()),this}create(t={recursive:!0}){return this.debug("create(%o)",t),this.mkdir(t)}destroy(t={empty:!0,recursive:!0,force:!0}){return this.debug("destroy(%o)",t),this.rmdir(t)}async mustExist(t={}){return this.debug("mustExist(%o)",t),await this.exists()?this:t.mkdir?this.mkdir(t):t.create?this.create():void b("Directory does not exist: ",this.path())}}const A=(t,e)=>new q(t,e);function F(t){return g(t)?[]:c(t)?t.length?t.split(/,\s*|\s+/):[]:h(t)?t:[t]}function L(t,e=" ",r=e){let s=[...t];const i=s.pop();return s.length?[s.join(e),i].join(r):i}function $(t,e=", ",r=" or "){return L(t,e,r)}function _(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}class M{constructor(t){const e=this.initDirs(t);this.state={dirs:e}}initDirs(t){return F(t).map((t=>A(t)))}async dirs(){return this.state.dirsExist||(this.state.dirsExist=await this.dirsExist())}async dirsExist(){const t=this.state.dirs,e=await Promise.all(t.map((t=>t.exists())));return t.filter(((t,r)=>e[r]))}}const W={b:"\b",f:"\f",n:"\n",r:"\r",t:"\t",v:"\v",'"':'"',"'":"'","\\":"\\"},I=t=>{let e=[];return[...t.matchAll(/(?:(\/)|'((?:\\[\\']|.)*?)'|"((?:\\[\\"nrt]|.)*?)"|([^/?]+))(\??)/g)].map((([,,t,r,s,i])=>{let o;t?o=t.replace(/\\([\\'bfnrtv])/g,((t,e)=>W[e]||`\\${e}`)):r?o=r.replace(/\\([\\"bfnrtv])/g,((t,e)=>W[e]||`\\${e}`)):s&&(o=s),f(o)&&e.push(i?[o,{optional:!0}]:o)})),e},T=(t,e)=>{let r=t,s=I(e),i=[];for(let t of s){const[e,s]=h(t)?t:[t,{}];if(r=r[e],i.push(e),g(r)){if(s.optional)return r;b("No value for data at path: ",i.join("/"))}}return r},V={codec:["yaml","json"],jsExt:["js","mjs"]};class J extends M{constructor(t,e={}){super(t);const r={...V,...e};this.state.codec=F(r.codec),this.state.jsExt=F(r.jsExt),P(this,e.debug,e.debugPrefix,e.debugColor)}async firstFileWithExt(t,e,r=y){const s=await this.dirs();for(let i of s)for(let s of e){const e=t+"."+s,o=i.file(e,r(t,s));if(this.debug("looking for config file: ",o.path()),await o.exists())return this.debug("config file exists: ",o.path()),o}}async jsFile(t){return await this.firstFileWithExt(t,this.state.jsExt)}async file(t){return await this.firstFileWithExt(t,this.state.codec,((t,e)=>({codec:e})))}async config(t,e){const[r,s]=t.split("#",2);let i,n,a;if(i=await this.jsFile(r))a=await(u=i.path(),Promise.resolve().then((function(){return o(require(u))})));else if(n=await this.file(r))a=await n.read();else{if(!e)return b("No configuration file for "+r);a=e}var u;return s?T(a,s):a}}const Q={jsExt:"js mjs"};class U extends M{constructor(t,e={}){super(t);const r=F({...Q,...e}.jsExt).map((t=>t.replace(/^\./,"")));this.state.exts=r,P(this,e.debug,e.debugPrefix,e.debugColor),this.debug("state: ",this.state)}async library(t){const[e,r]=t.split("#",2),s=await this.dirs(),i=this.state.exts;for(let t of s)for(let s of i){const i=t.file(e+"."+s);this.debug("looking for module %s as",e,i.path());if(await i.exists()){const t=await function(t){return Promise.resolve().then((function(){return o(require(t))}))}(i.path());return this.debug("loaded %s as",i.path()),r?T(t,r):t}}b("Library not found: ",t)}}function z(t={},e){const r=t[e];if(f(r))return r;b("Missing value for required parameter: ",e)}function B(t={},e){return F(e).map((e=>z(t,e)))}const G=B;const H={dir:"lib library src components"},K={dir:"config"};class R{constructor(t,e={}){const r=A(t),s=r.dir(e.config?.dir||K.dir),i={...K,...e.config||{}},o=new J(s,i),n=F(e.library?.dir||H.dir).map((t=>r.dir(t))),a={...H,...e.library||{}},u=new U(n,a);this.state={rootDir:r,config:o,library:u},P(this,e.debug,e.debugPrefix,e.debugColor),this.debug("root dir: ",r.path()),this.debug("config dir: ",s.path()),this.debug("libDirs: ",n),this.debug("libOpts: ",a)}dir(t,e){return this.debug("dir(%s, %o)",t,e),f(t)?this.state.rootDir.dir(t,e):this.state.rootDir}file(t,e){return this.debug("file(%s, %o)",t,e),this.state.rootDir.file(t,e)}read(t,e){return this.debug("read(%s, %o)",t,e),this.file(t,e).read()}write(t,e,r){return this.debug("write(%s, %o, %o)",t,e,r),this.file(t,r).write(e)}configDir(t,e){return this.debug("configDir(%s, %o)",t,e),f(t)?this.state.configDir(t,e):this.state.configDir}async config(t,e){return this.debug("config(%s, %o)",t,e),f(t)?this.state.config.config(t,e):this.state.config}async library(t){return this.state.library.library(t)}async component(t,e){const r=await this.config(t,{}),s=await this.library(r.component?.library||t),i=r.component?.export||"default";return new(s[i]||b("No '",i,"' export from component library: ",t))(this,{...r,...e})}}exports.ANSIescape=j,exports.ANSIescapeCode=w,exports.ANSIreset=v,exports.Component=class{constructor(t,e={}){this.workspace=t,this.props=e,P(this,e.debug,e.debugPrefix,e.debugColor),this.initComponent(e)}initComponent(){}},exports.Config=J,exports.Debugger=E,exports.Directory=q,exports.File=N,exports.Library=U,exports.Path=O,exports.Workspace=R,exports.addDebug=P,exports.allParams=G,exports.anyParams=function(t,e){let r=!1;const s=F(e),i=s.map((e=>{const s=t[e];return f(s)&&(r=!0),s}));return r?i:b("Missing value for one of: ",$(s))},exports.bin=(t,e)=>A(u.default.dirname(t.replace(/^file:\/\//,"")),e),exports.capitalise=_,exports.codec=k,exports.codecs=D,exports.config=(t,e)=>new J(t,e),exports.cwd=t=>A(a.default.cwd(),t),exports.dataPath=T,exports.dir=A,exports.doNothing=y,exports.fail=b,exports.file=S,exports.hasValue=f,exports.haveValue=function(...t){return t.every((t=>f(t)))},exports.isArray=h,exports.isFunction=function(t){return"function"==typeof t},exports.isNull=l,exports.isObject=d,exports.isString=c,exports.isUndefined=p,exports.joinList=L,exports.joinListAnd=function(t,e=", ",r=" and "){return L(t,e,r)},exports.joinListOr=$,exports.library=(t,e)=>new U(t,e),exports.matchDoubleQuotedString=t=>{const e=t.match(/^"((?:\\[\\"nrt]|.)*?)"$/);return e?e[1].replace(/\\([\\"bfnrtv])/g,((t,e)=>W[e]||`\\${e}`)):null},exports.matchSingleQuotedString=t=>{const e=t.match(/^'((?:\\[\\']|.)*?)'$/);return e?e[1].replace(/\\([\\'bfnrtv])/g,((t,e)=>W[e]||`\\${e}`)):null},exports.noValue=g,exports.requiredParam=z,exports.requiredParams=B,exports.rethrow=x,exports.snakeToCamel=function(t){return t.split("/").map((t=>t.split("_").map(((t,e)=>e?_(t):t)).join(""))).join("/")},exports.snakeToStudly=function(t){return t.split("/").map((t=>t.split("_").map(_).join(""))).join("/")},exports.splitDataPath=I,exports.splitList=F,exports.workspace=(t,e)=>new R(t,e);
2
2
  //# sourceMappingURL=badger.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"badger.cjs.js","sources":["../src/Badger/Utils/Misc.js","../src/Badger/Utils/Color.js","../src/Badger/Utils/Debug.js","../src/Badger/Codecs/Json.js","../src/Badger/Codecs/index.js","../src/Badger/Codecs/Yaml.js","../src/Badger/Filesystem/Path.js","../src/Badger/Filesystem/File.js","../src/Badger/Filesystem/Directory.js","../src/Badger/Utils/Text.js","../src/Badger/Filesystem/DirPath.js","../src/Badger/Config.js","../src/Badger/Library.js","../src/Badger/Utils/Params.js","../src/Badger/Workspace.js","../src/Badger/Component.js"],"sourcesContent":["/**\n * Determines if a value is a string\n * @param {String} value - value to test\n * @return {Boolean} true if `value` is a string or false if not\n */\nexport function isString(value) {\n return typeof value === 'string';\n}\n\n/**\n * Determines if a value is an array\n * @param {Array} value - value to test\n * @return {Boolean} true if `value` is an Array or false if not\n */\nexport function isArray(value) {\n return Array.isArray(value);\n}\n\n/**\n * Determines if a value is a Function\n * @param {Function} value - value to test\n * @return {Boolean} true if `value` is a Function or false if not\n */\nexport function isFunction(value) {\n return typeof value === 'function'\n}\n\n/**\n * Determines if a value is an Object (but not an Array)\n * @param {Object} value - value to test\n * @return {Boolean} true if `value` is an Object or false if not\n */\nexport function isObject(value) {\n return typeof value === \"object\"\n && ! isArray(value)\n && ! isNull(value);\n}\n\n/**\n * Determines if a value is `undefined`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or false if not\n */\nexport function isUndefined(value) {\n return typeof value === 'undefined';\n}\n\n/**\n * Determines if a value is `null`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `null` or false if not\n */\nexport function isNull(value) {\n return value === null;\n}\n\n/**\n * Determines if a value is defined and not null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is not `undefined` or `null`\n */\nexport function hasValue(value) {\n return ! (isUndefined(value) || isNull(value));\n}\n\n/**\n * Determines if all values are defined and not null\n * @param {any[]} values - values to test\n * @return {Boolean} true if all values are not `undefined` or `null`\n */\nexport function haveValue(...values) {\n return values.every( value => hasValue(value) );\n}\n\n/**\n * Determines if a value is undefined or null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or `null`\n */\nexport function noValue(value) {\n return ! hasValue(value);\n}\n\n/**\n * Throws a new Error object\n * @param {String[]} message - error message string(s)\n * @throws {Error}\n */\nexport function fail(...message) {\n throw new Error(message.join(''));\n}\n\n/**\n * Re-throw an existing Error object\n * @param {Error} error - error object\n * @throws {Error}\n */\nexport function rethrow(error) {\n throw error;\n}\n\n/**\n * Do nothing. Nothing at all.\n */\nexport function doNothing() {\n // speak again Cordelia\n}","import { isObject } from \"./Misc.js\";\n\nexport const ANSIStart = '\\u001B[';\nexport const ANSIEnd = 'm';\nexport const ANSIColors = {\n reset: 0,\n bold: 1,\n bright: 1,\n dark: 2,\n black: 0,\n red: 1,\n green: 2,\n yellow: 3,\n blue: 4,\n magenta: 5,\n cyan: 6,\n grey: 7,\n white: 8,\n fg: 30,\n bg: 40,\n};\n\n/**\n * Returns an ANSI escape code for a color string. This can be a single color\n * name, e.g. `red`, `green`, etc., or a color prefixed with `bright` or `dark`,\n * e.g. `bright red`, `dark green`, etc. An optional section argument can be\n * set to `fg` (default) to set a foreground color or `bg` for a background color.\n * @param {String} color - color name with optional modifier prefix\n * @param {String} [base='fg'] - `fg` or `bg` to set foreground or background color respectively\n * @return {String} ANSI escape code string\n * @example\n * const str = escapeCode('red')\n * @example\n * const str = escapeCode('bright red')\n * @example\n * const str = escapeCode('bright red', 'bg')\n */\nexport const escapeCode = (color, base='fg') => {\n let codes = [ ];\n let pair = color.split(/ /, 2);\n const hue = pair.pop();\n const code = (base ? ANSIColors[base] : 0) + ANSIColors[hue];\n codes.push(code);\n if (pair.length) {\n const shade = pair.length ? pair.shift() : 'dark';\n codes.push(ANSIColors[shade])\n }\n // console.log('escapeCode(%s, %s) => ', color, base, codes.join(';'));\n return ANSIStart + codes.join(';') + ANSIEnd;\n}\n\n/**\n * Returns an ANSI escape code for a color string or combination of foreground and\n * background colors.\n * @param {String|Object} colors - either a simple color name or object contain foreground and background colors\n * @param {String} [colors.fg] - foreground color\n * @param {String} [colors.fg] - background color\n * @return {String} ANSI escape code string\n * @example\n * const str = escape('red')\n * @example\n * const str = escape('bright red')\n * @example\n * const str = escape({ fg: 'bright yellow', bg: 'blue' })\n */\nexport const escape = (colors={}) => {\n const col = isObject(colors) ? colors : { fg: colors };\n let escapes = [ ];\n if (col.bg) {\n escapes.push(escapeCode(col.bg, 'bg'));\n }\n if (col.fg) {\n escapes.push(escapeCode(col.fg, 'fg'));\n }\n return escapes.join('');\n}\n\nexport const reset = () => escapeCode('reset', false)\n\n","import { escape, reset } from './Color.js'\nimport { doNothing } from './Misc.js';\n\n/**\n * Returns a debugging function which is enabled by the first `enabled` argument.\n * If this is `false` then it returns a function which does nothing. If it is\n * true then it returns a function that forwards all arguments to `console.log`.\n * An optional `prefix` be be specified to prefix each debugging line. The\n * optional third argument `color` can be used to specify a color for the prefix.\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @return {Function} a debugging function\n * @example\n * const debug = Debugger(true)\n * @example\n * const debug = Debugger(true, 'Debug > ')\n * @example\n * const debug = Debugger(true, 'Debug > ', 'blue')\n * @example\n * const debug = Debugger(true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function Debugger(enabled, prefix='', color) {\n return enabled\n ? prefix\n ? (format, ...args) =>\n console.log(\n '%s' + prefix + '%s' + format,\n color ? escape(color) : '',\n reset(),\n ...args,\n )\n : console.log.bind(console)\n : doNothing;\n}\n\n/**\n * Creates a debugging function via {@link Debugger} and attaches it to the object\n * passed as the first argument as the `debug` function.\n * @param {Object} obj - the object to receive the `debug` function\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @example\n * const debug = addDebug(myObject, true)\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', 'blue')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function addDebug(obj, enabled, prefix='', color) {\n obj.debug = Debugger(enabled, prefix, color);\n}\n","/**\n * Function to encode JSON\n * @param {Object} data - The data to encode as JSON text\n * @return {String} a JSON encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nexport const encode = data => JSON.stringify(data);\n\n/**\n * Function to decode JSON\n * @param {String} text - The JSON text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"{ message: 'Hello World' }\")\n */\nexport const decode = text => JSON.parse(text);\n\n/**\n * An object containing the JSON `encode` and `decode` functions\n */\nexport const codec = { encode, decode };\n\nexport default codec\n","import json from './Json.js'\nimport yaml from './Yaml.js'\n\n/**\n * Codecs provide a consistent encode()/decode() interface for serialising\n * and de-serialising data. This standard naming convention makes it possible\n * for the ../Filesystem/File.js module to support a \"codec\" option for\n * files. When this option is set the file.read() and file.write() methods\n * automatically handle the translation to and from the serialised format\n * using a codec object returned by the codec() function below. The codec\n * name can be specified in any case, e.g. \"Yaml\", \"YAML\", \"yaml\", \"YaML\",\n * etc., and it will be converted to lower case.\n */\n\n/**\n * Lookup table for codecs\n */\nexport const codecs = {\n json, yaml\n};\n\n/**\n * Function to fetch a codec\n * @param {string} name - The title of the code, in any case, e.g. \"yaml\", \"YAML\", \"Yaml\"\n */\nexport const codec = name => codecs[\n name.toLowerCase()\n];\n\nexport default codecs\n","// simple wrapper around JSON load/dump\nimport yaml from 'js-yaml';\n\n/**\n * Function to encode YAML\n * @param {Object} data - The data to encode as YAML text\n * @return {String} a YAML encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nexport const encode = data => yaml.dump(data);\n\n/**\n * Function to decode YAML\n * @param {String} text - The YAML text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"message: Hello World\")\n */\nexport const decode = text => yaml.load(text);\n\n/**\n * An object containing the YAML `encode` and `decode` functions\n */\nexport const codec = { encode, decode };\n\nexport default codec\n","import path from 'node:path';\nimport { stat } from 'node:fs/promises'\nimport { rethrow } from '../Utils/Misc.js';\nimport { addDebug } from '../Utils/Debug.js';\n\nconst defaultOptions = {\n encoding: 'utf8'\n}\n\n/**\n * The Path class implements a base class for the {@link File} and {@link Directory}\n * classes. It implements the common functionality for representing a filesystem path.\n */\nexport class Path {\n /**\n * Constructor for filesystem paths.\n * @param {string} path - file path\n * @param {Object} [options] - configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Path} object\n */\n constructor(path, options={}) {\n // allow path/file/directory to be constructed from an existing object\n if (path instanceof Path) {\n path = path.path();\n }\n this.state = { path, options: { ...defaultOptions, ...options } };\n addDebug(this, options.debug, options.debugPrefix || 'Path', options.debugColor);\n }\n\n /**\n * Accessor method to return the filesystem path.\n * @return {String} the filesystem path\n */\n path() {\n return this.state.path;\n }\n\n /**\n * Create a path relative to the current path.\n * @param {String[]} parts - part(s) of the filesystem path\n * @return {String} the new path\n * @example\n * const p = new Path('/path/to/here')\n * const q = p.relativePath('there') // -> /path/to/here/there\n * const r = p.relativePath('and', 'there') // -> /path/to/here/and/there\n */\n relativePath(...parts) {\n return path.join(this.state.path, ...parts);\n }\n\n /**\n * Internal method to merge any options with the pre-defined options passed to the\n * constructor. Options passed as arguments will take precedence.\n * @param {Object} options - new options\n * @return {Object} the merged options\n * @example\n * const p = new Path('/path/to/here', { option1: 'hello' })\n * const q = p.options({ option2: 'world' }) // -> { option1: 'hello', options2: 'world' }\n */\n options(options={}) {\n return { ...this.state.options, ...options };\n }\n\n /**\n * Method to assert that the path exists.\n * @return {Promise} fulfills with `true` if the path exists or rejects if the path doesn't\n * @example\n * const p = new Path('/path/to/here')\n * p.exists()\n * .then( console.log('path exists') )\n * .catch( console.log('path does not exist') )\n */\n async exists() {\n try {\n await this.stat();\n return true;\n }\n catch (error) {\n return error.code === 'ENOENT'\n ? false\n : rethrow(error);\n }\n }\n\n /**\n * Method to fetch stats for the path. Uses the `stat` function from `node:fs/promises`.\n * Stats are cached internally (subject to change)\n * @return {Promise} fulfills with path stats returned from the `stat` function\n * @example\n * const p = new Path('/path/to/here')\n * p.stat()\n * .then( stats => console.log('path stats:', stats) )\n * .catch( console.log('path does not exist') )\n */\n async stat() {\n const stats = await stat(this.state.path);\n return this.state.stats = stats;\n }\n\n /**\n * Method to clear internal cache of path stats (subject to change)\n */\n unstat() {\n this.state.stats = undefined;\n return this;\n }\n}\n\nexport default Path\n","import path from 'node:path'\nimport Path from './Path.js'\nimport { dir } from './Directory.js'\nimport { codec } from '../Codecs/index.js'\nimport { readFile, writeFile, rm } from 'node:fs/promises'\n\n/**\n * The File class implements a wrapper around a filesystem\n * file.\n */\nclass File extends Path {\n /**\n * Returns a new {@link Directory} object for the parent directory of the file\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n directory(options) {\n return dir(path.dirname(this.state.path), options);\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the parent {@link Directory} object\n */\n dir(...args) {\n return this.directory(...args);\n }\n\n /**\n * Reads the file content. If a `codec` has been specified then the content is decoded.\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {String|Object} the file content\n * @example\n * const text = file('myfile.txt').read();\n * @example\n * const data = file('myfile.json', { codec: 'json' }).read();\n * @example\n * const data = file('myfile.json').read({ codec: 'json' });\n */\n read(options) {\n const opts = this.options(options);\n const file = readFile(this.state.path, opts);\n return opts.codec\n ? file.then(text => codec(opts.codec).decode(text))\n : file;\n }\n\n /**\n * Writes the file content. If a `codec` has been specified then the content will be encoded.\n * @param {String|Object} data - directory configuration options\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @example\n * file('myfile.txt').write('Hello World');\n * @example\n * file('myfile.json', { codec: 'json' }).write({ message: 'Hello World' });\n * @example\n * file('myfile.json').write({ message: 'Hello World' }, { codec: 'json' });\n */\n write(data, options) {\n const opts = this.options(options);\n const text = opts.codec\n ? codec(opts.codec).encode(data)\n : data;\n return writeFile(this.state.path, text, opts).then( () => this );\n }\n\n async delete(options) {\n await rm(this.state.path, options);\n return this;\n }\n}\n\n/**\n * Function to create a new {@link File} object for a file\n * @param {String} path - file path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link File} object\n */\nexport const file = (path, options) => {\n return new File(path, options);\n}\n\nexport default File\n","import process from 'node:process';\nimport path from 'node:path';\nimport Path from './Path.js'\nimport { file } from './File.js'\nimport { fail } from '../Utils/Misc.js';\nimport { rm, mkdir, rmdir, readdir } from 'node:fs/promises'\n\n/**\n * The Directory class implements a wrapper around a filesystem\n * directory.\n */\nclass Directory extends Path {\n /**\n * Fetch a new {@link File} object for a file in the directory.\n * @param {string} path - file path\n * @param {Object} [options] - file configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link File} object\n */\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return file(this.relativePath(path), this.options(options));\n }\n\n /**\n * Fetch a new {@link Directory} object for a sub-directory in the directory.\n * @param {string} path - directory path\n * @param {Object} [options] - directory configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Directory} object\n */\n directory(path, options) {\n this.debug(\"directory(%s, %o)\", path, options);\n return dir(this.relativePath(path), this.options(options));\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the {@link Directory} object\n */\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return this.directory(path, options);\n }\n\n /**\n * Returns a new {@link Directory} object for the parent directory\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n parent(options) {\n this.debug(\"parent()\");\n return this.directory('..', options);\n }\n\n /**\n * Returns the names of the files and sub-directories in the directory\n * @return {Promise} fulfills with an array of the file and directory names\n */\n async read() {\n this.debug(\"read()\");\n return await readdir(this.path());\n }\n\n /**\n * Determines if the directory is empty.\n * @return {Promise} fulfills with a boolean value true (empty) or false (not empty).\n */\n async isEmpty() {\n this.debug(\"isEmpty()\");\n const entries = await this.read();\n return entries.length === 0;\n }\n\n /**\n * Determines if the directory is not empty.\n * @return {Promise} fulfills with a boolean value true (not empty) or false (empty).\n */\n async notEmpty() {\n this.debug(\"notEmpty()\");\n const empty = await this.isEmpty();\n return !empty;\n }\n\n /**\n * Empty the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.force] - force removal of files and directories\n * @param {Boolean} [options.recursive] - recursively empty and delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async empty(options={}) {\n this.debug(\"empty(%o)\", options);\n if (await this.exists() && await this.notEmpty()) {\n await rm(this.path(), options);\n }\n return this;\n }\n\n /**\n * Make the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive] - create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mkdir(options={}) {\n this.debug(\"mkdir(%o)\", options);\n const exists = await this.exists();\n if (! exists) {\n await mkdir(this.path(), options);\n }\n return this;\n }\n\n /**\n * Remove the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty] - delete items in directory\n * @param {Boolean} [options.force] - force delete files and directories\n * @param {Boolean} [options.recursive] - recursively delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async rmdir(options={}) {\n this.debug(\"rmdir(%o)\", options);\n if (options.empty) {\n await this.empty(options);\n }\n if (await this.exists()) {\n await rmdir(this.path());\n }\n return this;\n }\n\n /**\n * Create the directory and any intermediate directories.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive=true] - recursively create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n create(options={ recursive: true }) {\n this.debug(\"create(%o)\", options);\n return this.mkdir(options);\n }\n\n /**\n * Empty and delete the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty=true] - empty directory of any files and sub-directories\n * @param {Boolean} [options.recursive=true] - recursively delete sub-directories\n * @param {Boolean} [options.force=true] - force deletion of files and sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n destroy(options={ empty: true, recursive: true, force: true }) {\n this.debug(\"destroy(%o)\", options);\n return this.rmdir(options);\n }\n\n /**\n * Assert that a directory exists and optionally create it\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.create] - create the directory and any intermediate directories if it doesn't exist - equivalent to adding `mkdir` and `recursive` options or calling {@link create}\n * @param {Boolean} [options.mkdir] - create the directory, add the `recursive` option to create intermediate directories - equivalent to calling {@link mkdir}\n * @param {Boolean} [options.recursive] - when used with `mkdir`, creates any intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mustExist(options={}) {\n this.debug(\"mustExist(%o)\", options);\n if (await this.exists()) {\n return this;\n }\n if (options.mkdir) {\n return this.mkdir(options);\n }\n if (options.create) {\n return this.create();\n }\n fail(\"Directory does not exist: \", this.path());\n }\n}\n\n/**\n * Function to create a new {@link Directory} object\n * @param {string} path - directory path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const dir = (path, options) => {\n return new Directory(path, options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the current working directory\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const cwd = options => {\n return dir(process.cwd(), options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the directory of a JS source file\n * @param {string} url - module url - from `import.meta.url`\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const bin = (url, options) => {\n return dir(\n path.dirname(url.replace(/^file:\\/\\//, '')),\n options\n );\n}\n\nexport default Directory\n","import { isString, isArray, noValue } from \"./Misc.js\";\n\n/**\n * Split a comma/whitespace delimited string into an Array\n * @param {String} [value] - string to split\n * @return {Array} array of split strings\n * @example\n * const strings = splitList('one two three')\n * @example\n * const strings = splitList('one,two,three')\n * @example\n * const strings = splitList('one, two, three')\n */\nexport function splitList(value) {\n if (noValue(value)) {\n return [ ];\n }\n else if (isString(value)) {\n return value.length\n ? value.split(/,\\s*|\\s+/)\n : [ ]\n }\n else if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\n/**\n * Join an Array into a single string\n * @param {Array} [array] - array to join\n * @param {String} [joint=' '] - delimiter to join strings\n * @param {String} [lastJoint=joint] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinList(['one', 'two', 'three']); // one two three\n * @example\n * joinList(['one', 'two', 'three'], ', '); // one, two, three\n * @example\n * joinList(['one', 'two', 'three'], ', ', ' and '); // one, two and three\n */\nexport function joinList(array, joint=' ', lastJoint=joint) {\n let copy = [...array];\n const last = copy.pop();\n return copy.length\n ? [copy.join(joint), last].join(lastJoint)\n : last;\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` and ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' and '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListAnd(['one', 'two', 'three']); // one, two and three\n */\nexport function joinListAnd(array, joint=', ', lastJoint=' and ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` or ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' or '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListOr(['one', 'two', 'three']); // one, two or three\n */\nexport function joinListOr(array, joint=', ', lastJoint=' or ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Capitalise a string by converting the first character to upper case and other characters to lower case\n * @param {String} [word] - word to capitalise\n * @return {String} capitalised string\n * @example\n * capitalise('badger'); // Badger\n * @example\n * capitalise('BADGER'); // Badger\n */\nexport function capitalise(word) {\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n}\n\n/**\n * Convert a snake case string to studly caps\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToStudly('happy_badger_dance'); // HappyBadgerDance\n * @example\n * snakeToStudly('happy_badger/dance'); // HappyBadger/Dance\n */\nexport function snakeToStudly(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to FooBar\n segment => segment.split('_').map(capitalise).join('')\n ).join('/');\n}\n\n/**\n * Convert a snake case string to camel case\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToCamel('happy_badger_dance'); // happyBadgerDance\n * @example\n * snakeToCamel('happy_badger/dance'); // happyBadger/dance\n */\nexport function snakeToCamel(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to fooBar\n segment => segment.split('_').map((i, n) => n ? capitalise(i) : i).join('')\n ).join('/');\n}\n","import { dir as fsDir } from \"./Directory.js\";\nimport { splitList } from \"../Utils/Text.js\";\n\n/**\n * The DirPath class implements a base class for objects that\n * can search one or more directories.\n */\nexport class DirPath {\n /**\n * Constructor for filesystem paths.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Object} the {@link DirPath} object\n */\n constructor(dir) {\n const dirs = this.initDirs(dir);\n this.state = {\n dirs\n }\n }\n\n /**\n * Internal method to initialise the directories. If the `dir` argument is a string then it will be split on\n * commas and/or whitespace and converted to an array of {@link Directory} objects. If the `dir` is a\n * {@link Directory} object then it will be wrapped in an array. If the `dir` argument is already an array\n * (presumably of {@link Directory} objects) then no further processing is required.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Array} an array of {@link Directory} objects\n */\n initDirs(dir) {\n return splitList(dir).map( dir => fsDir(dir) );\n }\n\n /**\n * Internal method to return an array of the directories in the `dirs` argument passed to the constructor that\n * actually exist in the filesystem. The checks to determine if the directories exists are only carried\n * out the first time the method is called. Subsequent calls will return the cached value stored in\n * `this.state.dirsExist`.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirs() {\n return this.state.dirsExist\n || ( this.state.dirsExist = await this.dirsExist() );\n }\n\n /**\n * Internal method to determine which of the directories in the `dirs` argument passed to the constructor\n * actually exist in the filesystem.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirsExist() {\n const dirs = this.state.dirs;\n const exists = await Promise.all(\n dirs.map( d => d.exists() )\n );\n return dirs.filter((value, index) => exists[index]);\n }\n}\n\nexport default DirPath","import { DirPath } from './Filesystem/DirPath.js';\nimport { splitList } from './Utils/Text.js'\nimport { doNothing, fail } from './Utils/Misc.js';\nimport { addDebug } from './Utils/Debug.js';\n\nconst defaults = {\n codecs: ['yaml', 'json'],\n jsExt: ['js', 'mjs'],\n};\n\n/**\n * The Config class implements an object which can load configuration\n * files from a configuration directory. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default) or data files using any\n * of the standard codecs (`.yaml` or `.json` by default).\n */\nexport class Config extends DirPath {\n /**\n * Constructor for Config object.\n * @param {String} dir - one or more directories that contain configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codecs='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n this.state.codecs = splitList(params.codecs),\n this.state.jsExt = splitList(params.jsExt),\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n }\n\n /**\n * Internal method to locate the first config file with one of a number of file extensions.\n * @param {String} uri - base part of filename\n * @param {Array} [exts] - array of possible extensions\n * @param {Function} [makeOptions] - optional function to generate options for a {@link File} object\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async firstFileWithExt(uri, exts, makeOptions=doNothing) {\n const dirs = await this.dirs();\n\n for (let dir of dirs) {\n for (let ext of exts) {\n const path = uri + '.' + ext;\n const file = dir.file(path, makeOptions(uri, ext));\n this.debug('looking for config file: ', file.path());\n if (await file.exists()) {\n this.debug('config file exists: ', file.path());\n return file;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Internal method to locate a Javascript configuration file with one of the `jsExt` extensions (`.js` or `.mjs` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async jsFile(uri) {\n return await this.firstFileWithExt(uri, this.state.jsExt);\n }\n\n /**\n * Internal method to locate a configuration file with one of the `codecs` extensions (`.yaml` or `.json` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async file(uri) {\n return await this.firstFileWithExt(uri, this.state.codecs, (uri, codec) => ({ codec }));\n }\n\n /**\n * Method to fetch configuration data from a file. The file can be a Javascript file which should\n * return the configuration data as the default export, or a YAML (`.yaml`) or JSON (`.json`) file.\n * If the file isn't found then the method returns the `defaults` data if provided, or throws an\n * error if not.\n * @param {String} uri - base part of filename\n * @param {Object} [defaults] - default configuration options to be used if a file isn't found\n * @return {Object} the configuration data loaded from the file\n */\n async config(uri, defaults) {\n // first look for a JS file, e.g. <uri>.js, <uri>.mjs\n const jsFile = await this.jsFile(uri);\n if (jsFile) {\n const load = await import(jsFile.path());\n return load.default;\n }\n // then for a config file with a codec extension, e.g. <uri>.yaml, <uri>.yaml\n const file = await this.file(uri);\n if (file) {\n return await file.read();\n }\n return defaults || fail(\"No configuration file for \" + uri);\n }\n}\n\n/**\n * Function to create a new Config object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codecs='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\nexport const config = (dir, options) => new Config(dir, options)\n\nexport default Config\n","import { DirPath } from \"./Filesystem/DirPath.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { fail } from \"./Utils/Misc.js\";\n\nconst defaults = {\n jsExt: 'js mjs',\n}\n\n/**\n * The Library class implements an object which can load Javascript files\n * from one or more library directories. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default)\n */\nexport class Library extends DirPath {\n /**\n * Constructor for Library object.\n * @param {String} dir - one or more directories that contain Javascript libraries\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n const exts = splitList(params.jsExt).map( ext => ext.replace(/^\\./, '') ); // remove leading '.'\n this.state.exts = exts;\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug(\"state: \", this.state)\n }\n\n /**\n * Method to load a Javascript library in one of the library directories and with one of the `jsExt` extensions (`.js` or `.mjs` by default).\n * Returns the exports from the library if found or throws an error if not.\n * @param {String} uri - base part of filename\n * @return {Object} the exports from the loaded libary\n */\n async lib(uri) {\n const dirs = await this.dirs();\n const exts = this.state.exts;\n for (let dir of dirs) {\n for (let ext of exts) {\n const file = dir.file(uri + '.' + ext);\n this.debug('looking for module %s as', uri, file.path());\n const exists = await file.exists();\n if (exists) {\n const load = await import(file.path());\n this.debug('loaded %s as', file.path());\n return load;\n }\n }\n }\n fail(\"Library not found: \", uri);\n }\n}\n\n/**\n * Function to create a new Library object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\nexport const library = (dir, options) => new Library(dir, options);\n\nexport default library;","import { hasValue, fail } from \"./Misc.js\";\nimport { joinListOr, splitList } from \"./Text.js\";\n\n/**\n * Assert that a parameter object contains an item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {String} name - parameter that must be included\n * @return {any} the parameter value\n * @throws {Error} if the parameter is not defined or null\n * @example\n * const foo = requiredParam({ foo: 10 }, 'foo');\n */\nexport function requiredParam(params={}, name) {\n const value = params[name];\n if (hasValue(value)) {\n return value;\n }\n else {\n fail(\"Missing value for required parameter: \", name);\n }\n}\n\n/**\n * Assert that a parameter object contains all specified item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters that must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = requiredParams({ foo: 10, bar: 20 }, 'foo bar');\n */\nexport function requiredParams(params={}, names) {\n return splitList(names).map( name => requiredParam(params, name) );\n}\n\n/**\n * An alias for {@link requiredParams} for people who don't like typing long names (and for symmetry with {@link anyParams}))\n */\nexport const allParams=requiredParams;\n\n/**\n * Assert that a parameter object contains any of the specified items with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters of which at least one must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = anyParams({ foo: 10, wiz: 99 }, 'foo bar');\n */\nexport function anyParams(params, names) {\n let found = false;\n const nlist = splitList(names);\n const values = nlist.map(\n name => {\n const value = params[name];\n if (hasValue(value)) {\n found = true;\n }\n return value;\n }\n );\n return found\n ? values\n : fail(\"Missing value for one of: \", joinListOr(nlist));\n}\n","import { dir as fsDir } from \"./Filesystem/Directory.js\";\nimport { fail, hasValue } from \"./Utils/Misc.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { Config } from \"./Config.js\";\nimport { Library } from \"./Library.js\";\n\nconst defaults = {\n library: {\n dir: 'lib library src components',\n },\n config: {\n dir: 'config',\n }\n}\nexport class Workspace {\n constructor(dir, options={}) {\n const rootDir = fsDir(dir);\n const cfgDir = rootDir.dir(options.config?.dir || defaults.config.dir);\n const cfgOpts = { ...defaults.config, ...(options.config||{}) };\n const config = new Config(cfgDir, cfgOpts);\n const libDirs = splitList(options.library?.dir || defaults.library.dir).map( dir => rootDir.dir(dir) );\n const libOpts = { ...defaults.library, ...(options.library||{}) };\n const library = new Library(libDirs, libOpts);\n\n this.state = {\n rootDir,\n config,\n library\n }\n\n // console.log('options: ', options);\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug('root dir: ', rootDir.path());\n this.debug('config dir: ', cfgDir.path());\n this.debug('libDirs: ', libDirs);\n this.debug('libOpts: ', libOpts);\n }\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.rootDir.dir(path, options)\n : this.state.rootDir;\n }\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return this.state.rootDir.file(path, options)\n }\n read(path, options) {\n this.debug(\"read(%s, %o)\", path, options);\n return this.file(path, options).read();\n }\n write(path, data, options) {\n this.debug(\"write(%s, %o, %o)\", path, data, options);\n return this.file(path, options).write(data);\n }\n configDir(path, options) {\n this.debug(\"configDir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.configDir(path, options)\n : this.state.configDir;\n }\n async config(uri, defaults) {\n this.debug(\"config(%s, %o)\", uri, defaults);\n return hasValue(uri)\n ? this.state.config.config(uri, defaults)\n : this.state.config;\n }\n async lib(uri) {\n return this.state.library.lib(uri);\n }\n async component(uri, props) {\n const config = await this.config(uri, {});\n const lib = await this.lib(config.component?.library || uri);\n const exp = config.component?.export || 'default';\n const compcls = lib[exp] || fail(\"No '\", exp, \"' export from component library: \", uri);\n const comp = new compcls(this, { ...config, ...props });\n // this.debug(\"created component \", uri)\n return comp;\n }\n}\n\nexport const workspace = (dir, options) => new Workspace(dir, options);\n\nexport default Workspace;","import { addDebug } from \"./Utils/Debug.js\";\n\nexport class Component {\n constructor(workspace, props={}) {\n this.workspace = workspace;\n this.props = props;\n addDebug(this, props.debug, props.debugPrefix, props.debugColor);\n this.initComponent(props);\n }\n initComponent() {\n // stub for subclasses\n }\n}\n\nexport default Component"],"names":["isString","value","isArray","Array","isObject","isNull","isUndefined","hasValue","noValue","fail","message","Error","join","rethrow","error","doNothing","ANSIColors","reset","bold","bright","dark","black","red","green","yellow","blue","magenta","cyan","grey","white","fg","bg","escapeCode","color","base","codes","pair","split","hue","pop","code","push","length","shade","shift","Debugger","enabled","prefix","format","args","console","log","colors","col","escapes","escape","bind","addDebug","obj","debug","codecs","json","encode","data","JSON","stringify","decode","text","parse","yaml","dump","load","codec","name","toLowerCase","defaultOptions","encoding","Path","constructor","path","options","this","state","debugPrefix","debugColor","relativePath","parts","async","stat","stats","unstat","undefined","File","directory","dir","dirname","read","opts","file","readFile","then","write","writeFile","rm","Directory","parent","readdir","isEmpty","exists","notEmpty","mkdir","empty","rmdir","create","recursive","destroy","force","splitList","joinList","array","joint","lastJoint","copy","last","joinListOr","capitalise","word","charAt","toUpperCase","slice","DirPath","dirs","initDirs","map","fsDir","dirsExist","Promise","all","d","filter","index","defaults","jsExt","Config","super","params","uri","exts","makeOptions","ext","firstFileWithExt","jsFile","t","resolve","_interopNamespace","require","default","Library","replace","requiredParam","requiredParams","names","allParams","Workspace","rootDir","cfgDir","config","cfgOpts","libDirs","library","libOpts","configDir","lib","props","component","exp","export","workspace","initComponent","found","nlist","values","url","process","cwd","every","snake","segment","i","n"],"mappings":"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"}
1
+ {"version":3,"file":"badger.cjs.js","sources":["../src/Badger/Utils/Misc.js","../src/Badger/Utils/Color.js","../src/Badger/Utils/Debug.js","../src/Badger/Codecs/Json.js","../src/Badger/Codecs/index.js","../src/Badger/Codecs/Yaml.js","../src/Badger/Filesystem/Path.js","../src/Badger/Filesystem/File.js","../src/Badger/Filesystem/Directory.js","../src/Badger/Utils/Text.js","../src/Badger/Filesystem/DirPath.js","../src/Badger/Utils/DataPath.js","../src/Badger/Config.js","../src/Badger/Library.js","../src/Badger/Utils/Params.js","../src/Badger/Workspace.js","../src/Badger/Component.js"],"sourcesContent":["/**\n * Determines if a value is a string\n * @param {String} value - value to test\n * @return {Boolean} true if `value` is a string or false if not\n */\nexport function isString(value) {\n return typeof value === 'string';\n}\n\n/**\n * Determines if a value is an array\n * @param {Array} value - value to test\n * @return {Boolean} true if `value` is an Array or false if not\n */\nexport function isArray(value) {\n return Array.isArray(value);\n}\n\n/**\n * Determines if a value is a Function\n * @param {Function} value - value to test\n * @return {Boolean} true if `value` is a Function or false if not\n */\nexport function isFunction(value) {\n return typeof value === 'function'\n}\n\n/**\n * Determines if a value is an Object (but not an Array)\n * @param {Object} value - value to test\n * @return {Boolean} true if `value` is an Object or false if not\n */\nexport function isObject(value) {\n return typeof value === \"object\"\n && ! isArray(value)\n && ! isNull(value);\n}\n\n/**\n * Determines if a value is `undefined`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or false if not\n */\nexport function isUndefined(value) {\n return typeof value === 'undefined';\n}\n\n/**\n * Determines if a value is `null`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `null` or false if not\n */\nexport function isNull(value) {\n return value === null;\n}\n\n/**\n * Determines if a value is defined and not null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is not `undefined` or `null`\n */\nexport function hasValue(value) {\n return ! (isUndefined(value) || isNull(value));\n}\n\n/**\n * Determines if all values are defined and not null\n * @param {any[]} values - values to test\n * @return {Boolean} true if all values are not `undefined` or `null`\n */\nexport function haveValue(...values) {\n return values.every( value => hasValue(value) );\n}\n\n/**\n * Determines if a value is undefined or null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or `null`\n */\nexport function noValue(value) {\n return ! hasValue(value);\n}\n\n/**\n * Throws a new Error object\n * @param {String[]} message - error message string(s)\n * @throws {Error}\n */\nexport function fail(...message) {\n throw new Error(message.join(''));\n}\n\n/**\n * Re-throw an existing Error object\n * @param {Error} error - error object\n * @throws {Error}\n */\nexport function rethrow(error) {\n throw error;\n}\n\n/**\n * Do nothing. Nothing at all.\n */\nexport function doNothing() {\n // speak again Cordelia\n}","import { isObject } from \"./Misc.js\";\n\nconst ANSIStart = '\\u001B[';\nconst ANSIEnd = 'm';\nconst ANSIColors = {\n reset: 0,\n bold: 1,\n bright: 1,\n dark: 2,\n black: 0,\n red: 1,\n green: 2,\n yellow: 3,\n blue: 4,\n magenta: 5,\n cyan: 6,\n grey: 7,\n white: 8,\n fg: 30,\n bg: 40,\n};\n\n/**\n * Returns an ANSI escape code for a color string. This can be a single color\n * name, e.g. `red`, `green`, etc., or a color prefixed with `bright` or `dark`,\n * e.g. `bright red`, `dark green`, etc. An optional section argument can be\n * set to `fg` (default) to set a foreground color or `bg` for a background color.\n * @param {String} color - color name with optional modifier prefix\n * @param {String} [base='fg'] - `fg` or `bg` to set foreground or background color respectively\n * @return {String} ANSI escape code string\n * @example\n * const str = escapeCode('red')\n * @example\n * const str = escapeCode('bright red')\n * @example\n * const str = escapeCode('bright red', 'bg')\n */\nexport const ANSIescapeCode = (color, base='fg') => {\n let codes = [ ];\n let pair = color.split(/ /, 2);\n const hue = pair.pop();\n const code = (base ? ANSIColors[base] : 0) + ANSIColors[hue];\n codes.push(code);\n if (pair.length) {\n const shade = pair.length ? pair.shift() : 'dark';\n codes.push(ANSIColors[shade])\n }\n // console.log('escapeCode(%s, %s) => ', color, base, codes.join(';'));\n return ANSIStart + codes.join(';') + ANSIEnd;\n}\n\n/**\n * Returns an ANSI escape code for a color string or combination of foreground and\n * background colors.\n * @param {String|Object} colors - either a simple color name or object contain foreground and background colors\n * @param {String} [colors.fg] - foreground color\n * @param {String} [colors.fg] - background color\n * @return {String} ANSI escape code string\n * @example\n * const str = escape('red')\n * @example\n * const str = escape('bright red')\n * @example\n * const str = escape({ fg: 'bright yellow', bg: 'blue' })\n */\nexport const ANSIescape = (colors={}) => {\n const col = isObject(colors) ? colors : { fg: colors };\n let escapes = [ ];\n if (col.bg) {\n escapes.push(ANSIescapeCode(col.bg, 'bg'));\n }\n if (col.fg) {\n escapes.push(ANSIescapeCode(col.fg, 'fg'));\n }\n return escapes.join('');\n}\n\n/**\n * Returns an ANSI escape code to reset all colors.\n * @return {String} ANSI escape reset string\n */\nexport const ANSIreset = () => ANSIescapeCode('reset', false)\n\n","import { ANSIescape, ANSIreset } from './Color.js'\nimport { doNothing } from './Misc.js';\n\n/**\n * Returns a debugging function which is enabled by the first `enabled` argument.\n * If this is `false` then it returns a function which does nothing. If it is\n * true then it returns a function that forwards all arguments to `console.log`.\n * An optional `prefix` be be specified to prefix each debugging line. The\n * optional third argument `color` can be used to specify a color for the prefix.\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @return {Function} a debugging function\n * @example\n * const debug = Debugger(true)\n * @example\n * const debug = Debugger(true, 'Debug > ')\n * @example\n * const debug = Debugger(true, 'Debug > ', 'blue')\n * @example\n * const debug = Debugger(true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function Debugger(enabled, prefix='', color) {\n return enabled\n ? prefix\n ? (format, ...args) =>\n console.log(\n '%s' + prefix + '%s' + format,\n color ? ANSIescape(color) : '',\n ANSIreset(),\n ...args,\n )\n : console.log.bind(console)\n : doNothing;\n}\n\n/**\n * Creates a debugging function via {@link Debugger} and attaches it to the object\n * passed as the first argument as the `debug` function.\n * @param {Object} obj - the object to receive the `debug` function\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @example\n * const debug = addDebug(myObject, true)\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', 'blue')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function addDebug(obj, enabled, prefix='', color) {\n obj.debug = Debugger(enabled, prefix, color);\n}\n","/**\n * Function to encode JSON\n * @param {Object} data - The data to encode as JSON text\n * @return {String} a JSON encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nconst encode = data => JSON.stringify(data);\n\n/**\n * Function to decode JSON\n * @param {String} text - The JSON text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"{ message: 'Hello World' }\")\n */\nconst decode = text => JSON.parse(text);\n\n/**\n * An object containing the JSON `encode` and `decode` functions\n */\nexport const jsonCodec = { encode, decode };\n\nexport default jsonCodec\n","import json from './Json.js'\nimport yaml from './Yaml.js'\n\n/**\n * Codecs provide a consistent encode()/decode() interface for serialising\n * and de-serialising data. This standard naming convention makes it possible\n * for the ../Filesystem/File.js module to support a \"codec\" option for\n * files. When this option is set the file.read() and file.write() methods\n * automatically handle the translation to and from the serialised format\n * using a codec object returned by the codec() function below. The codec\n * name can be specified in any case, e.g. \"Yaml\", \"YAML\", \"yaml\", \"YaML\",\n * etc., and it will be converted to lower case.\n */\n\n/**\n * Lookup table for codecs\n */\nexport const codecs = {\n json, yaml\n};\n\n/**\n * Function to fetch a codec\n * @param {string} name - The title of the code, in any case, e.g. \"yaml\", \"YAML\", \"Yaml\"\n */\nexport const codec = name => codecs[\n name.toLowerCase()\n];\n\nexport default codecs\n","// simple wrapper around JSON load/dump\nimport yaml from 'js-yaml';\n\n/**\n * Function to encode YAML\n * @param {Object} data - The data to encode as YAML text\n * @return {String} a YAML encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nconst encode = data => yaml.dump(data);\n\n/**\n * Function to decode YAML\n * @param {String} text - The YAML text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"message: Hello World\")\n */\nconst decode = text => yaml.load(text);\n\n/**\n * An object containing the YAML `encode` and `decode` functions\n */\nexport const yamlCodec = { encode, decode };\n\nexport default yamlCodec\n","import path from 'node:path';\nimport { stat } from 'node:fs/promises'\nimport { rethrow } from '../Utils/Misc.js';\nimport { addDebug } from '../Utils/Debug.js';\n\nconst defaultOptions = {\n encoding: 'utf8'\n}\n\n/**\n * The Path class implements a base class for the {@link File} and {@link Directory}\n * classes. It implements the common functionality for representing a filesystem path.\n */\nexport class Path {\n /**\n * Constructor for filesystem paths.\n * @param {string} path - file path\n * @param {Object} [options] - configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Path} object\n */\n constructor(path, options={}) {\n // allow path/file/directory to be constructed from an existing object\n if (path instanceof Path) {\n path = path.path();\n }\n this.state = { path, options: { ...defaultOptions, ...options } };\n addDebug(this, options.debug, options.debugPrefix || 'Path', options.debugColor);\n }\n\n /**\n * Accessor method to return the filesystem path.\n * @return {String} the filesystem path\n */\n path() {\n return this.state.path;\n }\n\n /**\n * Create a path relative to the current path.\n * @param {String[]} parts - part(s) of the filesystem path\n * @return {String} the new path\n * @example\n * const p = new Path('/path/to/here')\n * const q = p.relativePath('there') // -> /path/to/here/there\n * const r = p.relativePath('and', 'there') // -> /path/to/here/and/there\n */\n relativePath(...parts) {\n return path.join(this.state.path, ...parts);\n }\n\n /**\n * Internal method to merge any options with the pre-defined options passed to the\n * constructor. Options passed as arguments will take precedence.\n * @param {Object} options - new options\n * @return {Object} the merged options\n * @example\n * const p = new Path('/path/to/here', { option1: 'hello' })\n * const q = p.options({ option2: 'world' }) // -> { option1: 'hello', options2: 'world' }\n */\n options(options={}) {\n return { ...this.state.options, ...options };\n }\n\n /**\n * Method to assert that the path exists.\n * @return {Promise} fulfills with `true` if the path exists or rejects if the path doesn't\n * @example\n * const p = new Path('/path/to/here')\n * p.exists()\n * .then( console.log('path exists') )\n * .catch( console.log('path does not exist') )\n */\n async exists() {\n try {\n await this.stat();\n return true;\n }\n catch (error) {\n return error.code === 'ENOENT'\n ? false\n : rethrow(error);\n }\n }\n\n /**\n * Method to fetch stats for the path. Uses the `stat` function from `node:fs/promises`.\n * Stats are cached internally (subject to change)\n * @return {Promise} fulfills with path stats returned from the `stat` function\n * @example\n * const p = new Path('/path/to/here')\n * p.stat()\n * .then( stats => console.log('path stats:', stats) )\n * .catch( console.log('path does not exist') )\n */\n async stat() {\n const stats = await stat(this.state.path);\n return this.state.stats = stats;\n }\n\n /**\n * Method to clear internal cache of path stats (subject to change)\n */\n unstat() {\n this.state.stats = undefined;\n return this;\n }\n}\n\nexport default Path\n","import path from 'node:path'\nimport Path from './Path.js'\nimport { dir } from './Directory.js'\nimport { codec } from '../Codecs/index.js'\nimport { readFile, writeFile, rm } from 'node:fs/promises'\n\n/**\n * The File class implements a wrapper around a filesystem\n * file.\n */\nexport class File extends Path {\n /**\n * Returns a new {@link Directory} object for the parent directory of the file\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n directory(options) {\n return dir(path.dirname(this.state.path), options);\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the parent {@link Directory} object\n */\n dir(...args) {\n return this.directory(...args);\n }\n\n /**\n * Reads the file content. If a `codec` has been specified then the content is decoded.\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {String|Object} the file content\n * @example\n * const text = file('myfile.txt').read();\n * @example\n * const data = file('myfile.json', { codec: 'json' }).read();\n * @example\n * const data = file('myfile.json').read({ codec: 'json' });\n */\n read(options) {\n const opts = this.options(options);\n const file = readFile(this.state.path, opts);\n return opts.codec\n ? file.then(text => codec(opts.codec).decode(text))\n : file;\n }\n\n /**\n * Writes the file content. If a `codec` has been specified then the content will be encoded.\n * @param {String|Object} data - directory configuration options\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @example\n * file('myfile.txt').write('Hello World');\n * @example\n * file('myfile.json', { codec: 'json' }).write({ message: 'Hello World' });\n * @example\n * file('myfile.json').write({ message: 'Hello World' }, { codec: 'json' });\n */\n write(data, options) {\n const opts = this.options(options);\n const text = opts.codec\n ? codec(opts.codec).encode(data)\n : data;\n return writeFile(this.state.path, text, opts).then( () => this );\n }\n\n async delete(options) {\n await rm(this.state.path, options);\n return this;\n }\n}\n\n/**\n * Function to create a new {@link File} object for a file\n * @param {String} path - file path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link File} object\n */\nexport const file = (path, options) => {\n return new File(path, options);\n}\n\nexport default File\n","import process from 'node:process';\nimport path from 'node:path';\nimport Path from './Path.js'\nimport { file } from './File.js'\nimport { fail } from '../Utils/Misc.js';\nimport { rm, mkdir, rmdir, readdir } from 'node:fs/promises'\n\n/**\n * The Directory class implements a wrapper around a filesystem\n * directory.\n */\nexport class Directory extends Path {\n /**\n * Fetch a new {@link File} object for a file in the directory.\n * @param {string} path - file path\n * @param {Object} [options] - file configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link File} object\n */\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return file(this.relativePath(path), this.options(options));\n }\n\n /**\n * Fetch a new {@link Directory} object for a sub-directory in the directory.\n * @param {string} path - directory path\n * @param {Object} [options] - directory configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Directory} object\n */\n directory(path, options) {\n this.debug(\"directory(%s, %o)\", path, options);\n return dir(this.relativePath(path), this.options(options));\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the {@link Directory} object\n */\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return this.directory(path, options);\n }\n\n /**\n * Returns a new {@link Directory} object for the parent directory\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n parent(options) {\n this.debug(\"parent()\");\n return this.directory('..', options);\n }\n\n /**\n * Returns the names of the files and sub-directories in the directory\n * @return {Promise} fulfills with an array of the file and directory names\n */\n async read() {\n this.debug(\"read()\");\n return await readdir(this.path());\n }\n\n /**\n * Determines if the directory is empty.\n * @return {Promise} fulfills with a boolean value true (empty) or false (not empty).\n */\n async isEmpty() {\n this.debug(\"isEmpty()\");\n const entries = await this.read();\n return entries.length === 0;\n }\n\n /**\n * Determines if the directory is not empty.\n * @return {Promise} fulfills with a boolean value true (not empty) or false (empty).\n */\n async notEmpty() {\n this.debug(\"notEmpty()\");\n const empty = await this.isEmpty();\n return !empty;\n }\n\n /**\n * Empty the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.force] - force removal of files and directories\n * @param {Boolean} [options.recursive] - recursively empty and delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async empty(options={}) {\n this.debug(\"empty(%o)\", options);\n if (await this.exists() && await this.notEmpty()) {\n await rm(this.path(), options);\n }\n return this;\n }\n\n /**\n * Make the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive] - create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mkdir(options={}) {\n this.debug(\"mkdir(%o)\", options);\n const exists = await this.exists();\n if (! exists) {\n await mkdir(this.path(), options);\n }\n return this;\n }\n\n /**\n * Remove the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty] - delete items in directory\n * @param {Boolean} [options.force] - force delete files and directories\n * @param {Boolean} [options.recursive] - recursively delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async rmdir(options={}) {\n this.debug(\"rmdir(%o)\", options);\n if (options.empty) {\n await this.empty(options);\n }\n if (await this.exists()) {\n await rmdir(this.path());\n }\n return this;\n }\n\n /**\n * Create the directory and any intermediate directories.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive=true] - recursively create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n create(options={ recursive: true }) {\n this.debug(\"create(%o)\", options);\n return this.mkdir(options);\n }\n\n /**\n * Empty and delete the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty=true] - empty directory of any files and sub-directories\n * @param {Boolean} [options.recursive=true] - recursively delete sub-directories\n * @param {Boolean} [options.force=true] - force deletion of files and sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n destroy(options={ empty: true, recursive: true, force: true }) {\n this.debug(\"destroy(%o)\", options);\n return this.rmdir(options);\n }\n\n /**\n * Assert that a directory exists and optionally create it\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.create] - create the directory and any intermediate directories if it doesn't exist - equivalent to adding `mkdir` and `recursive` options or calling {@link create}\n * @param {Boolean} [options.mkdir] - create the directory, add the `recursive` option to create intermediate directories - equivalent to calling {@link mkdir}\n * @param {Boolean} [options.recursive] - when used with `mkdir`, creates any intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mustExist(options={}) {\n this.debug(\"mustExist(%o)\", options);\n if (await this.exists()) {\n return this;\n }\n if (options.mkdir) {\n return this.mkdir(options);\n }\n if (options.create) {\n return this.create();\n }\n fail(\"Directory does not exist: \", this.path());\n }\n}\n\n/**\n * Function to create a new {@link Directory} object\n * @param {string} path - directory path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const dir = (path, options) => {\n return new Directory(path, options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the current working directory\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const cwd = options => {\n return dir(process.cwd(), options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the directory of a JS source file\n * @param {string} url - module url - from `import.meta.url`\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const bin = (url, options) => {\n return dir(\n path.dirname(url.replace(/^file:\\/\\//, '')),\n options\n );\n}\n\nexport default Directory\n","import { isString, isArray, noValue } from \"./Misc.js\";\n\n/**\n * Split a comma/whitespace delimited string into an Array\n * @param {String} [value] - string to split\n * @return {Array} array of split strings\n * @example\n * const strings = splitList('one two three')\n * @example\n * const strings = splitList('one,two,three')\n * @example\n * const strings = splitList('one, two, three')\n */\nexport function splitList(value) {\n if (noValue(value)) {\n return [ ];\n }\n else if (isString(value)) {\n return value.length\n ? value.split(/,\\s*|\\s+/)\n : [ ]\n }\n else if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\n/**\n * Join an Array into a single string\n * @param {Array} [array] - array to join\n * @param {String} [joint=' '] - delimiter to join strings\n * @param {String} [lastJoint=joint] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinList(['one', 'two', 'three']); // one two three\n * @example\n * joinList(['one', 'two', 'three'], ', '); // one, two, three\n * @example\n * joinList(['one', 'two', 'three'], ', ', ' and '); // one, two and three\n */\nexport function joinList(array, joint=' ', lastJoint=joint) {\n let copy = [...array];\n const last = copy.pop();\n return copy.length\n ? [copy.join(joint), last].join(lastJoint)\n : last;\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` and ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' and '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListAnd(['one', 'two', 'three']); // one, two and three\n */\nexport function joinListAnd(array, joint=', ', lastJoint=' and ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` or ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' or '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListOr(['one', 'two', 'three']); // one, two or three\n */\nexport function joinListOr(array, joint=', ', lastJoint=' or ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Capitalise a string by converting the first character to upper case and other characters to lower case\n * @param {String} [word] - word to capitalise\n * @return {String} capitalised string\n * @example\n * capitalise('badger'); // Badger\n * @example\n * capitalise('BADGER'); // Badger\n */\nexport function capitalise(word) {\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n}\n\n/**\n * Convert a snake case string to studly caps\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToStudly('happy_badger_dance'); // HappyBadgerDance\n * @example\n * snakeToStudly('happy_badger/dance'); // HappyBadger/Dance\n */\nexport function snakeToStudly(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to FooBar\n segment => segment.split('_').map(capitalise).join('')\n ).join('/');\n}\n\n/**\n * Convert a snake case string to camel case\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToCamel('happy_badger_dance'); // happyBadgerDance\n * @example\n * snakeToCamel('happy_badger/dance'); // happyBadger/dance\n */\nexport function snakeToCamel(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to fooBar\n segment => segment.split('_').map((i, n) => n ? capitalise(i) : i).join('')\n ).join('/');\n}\n","import { dir as fsDir } from \"./Directory.js\";\nimport { splitList } from \"../Utils/Text.js\";\n\n/**\n * The DirPath class implements a base class for objects that\n * can search one or more directories.\n */\nexport class DirPath {\n /**\n * Constructor for filesystem paths.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Object} the {@link DirPath} object\n */\n constructor(dir) {\n const dirs = this.initDirs(dir);\n this.state = {\n dirs\n }\n }\n\n /**\n * Internal method to initialise the directories. If the `dir` argument is a string then it will be split on\n * commas and/or whitespace and converted to an array of {@link Directory} objects. If the `dir` is a\n * {@link Directory} object then it will be wrapped in an array. If the `dir` argument is already an array\n * (presumably of {@link Directory} objects) then no further processing is required.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Array} an array of {@link Directory} objects\n */\n initDirs(dir) {\n return splitList(dir).map( dir => fsDir(dir) );\n }\n\n /**\n * Internal method to return an array of the directories in the `dirs` argument passed to the constructor that\n * actually exist in the filesystem. The checks to determine if the directories exists are only carried\n * out the first time the method is called. Subsequent calls will return the cached value stored in\n * `this.state.dirsExist`.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirs() {\n return this.state.dirsExist\n || ( this.state.dirsExist = await this.dirsExist() );\n }\n\n /**\n * Internal method to determine which of the directories in the `dirs` argument passed to the constructor\n * actually exist in the filesystem.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirsExist() {\n const dirs = this.state.dirs;\n const exists = await Promise.all(\n dirs.map( d => d.exists() )\n );\n return dirs.filter((value, index) => exists[index]);\n }\n}\n\nexport default DirPath","import { fail, hasValue, isArray, noValue } from \"./Misc.js\";\n\nconst quotedEscapes = {\n b: \"\\b\",\n f: \"\\f\",\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n v: \"\\v\",\n '\"': '\"',\n \"'\": \"'\",\n '\\\\': '\\\\',\n}\n\nexport const matchDoubleQuotedString = string => {\n const regex = /^\"((?:\\\\[\\\\\"nrt]|.)*?)\"$/\n const match = string.match(regex);\n return match\n ? match[1].replace(/\\\\([\\\\\"bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`)\n : null;\n}\n\nexport const matchSingleQuotedString = string => {\n const regex = /^'((?:\\\\[\\\\']|.)*?)'$/\n const match = string.match(regex);\n return match\n ? match[1].replace(/\\\\([\\\\'bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`)\n : null;\n}\n\nexport const splitDataPath = path => {\n // * match a slash: \\/\n // * match a single quoted string: '...'\n // * match a double quoted string: \"...\"\n // * match anything else: hello world!\n let parts = [ ];\n const regex = /(?:(\\/)|'((?:\\\\[\\\\']|.)*?)'|\"((?:\\\\[\\\\\"nrt]|.)*?)\"|([^/?]+))(\\??)/g;\n // console.log('\\nsplitDataPath [%s]', path);\n const matches = [...path.matchAll(regex)];\n\n matches.map(\n ([ , , single, double, other, optional]) => {\n let part;\n // console.log('match [slash:%s] [single:%s] [double:%s] [other:%s]', slash, single, double, other);\n\n if (single) {\n part = single.replace(/\\\\([\\\\'bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`);\n }\n else if (double) {\n part = double.replace(/\\\\([\\\\\"bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`);\n }\n else if (other) {\n part = other\n }\n if (hasValue(part)) {\n parts.push(optional ? [part, {optional:true}] : part);\n }\n }\n )\n // console.log('MATCHED ', parts);\n\n return parts;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport const dataPath = (data, path) => {\n let root = data;\n let parts = splitDataPath(path);\n let done = [ ];\n // console.log('parts: ', parts);\n\n for (let part of parts) {\n const [word, opts] = isArray(part) ? part : [part, {}];\n root = root[word];\n done.push(word);\n if (noValue(root)) {\n if (opts.optional) {\n return root;\n }\n else {\n fail(\"No value for data at path: \", done.join('/'));\n }\n }\n }\n return root;\n}\n","import { DirPath } from './Filesystem/DirPath.js';\nimport { splitList } from './Utils/Text.js'\nimport { doNothing, fail } from './Utils/Misc.js';\nimport { addDebug } from './Utils/Debug.js';\nimport { dataPath } from '../Badger/Utils/DataPath.js';\n\nconst defaults = {\n codec: ['yaml', 'json'],\n jsExt: ['js', 'mjs'],\n};\n\n/**\n * The Config class implements an object which can load configuration\n * files from a configuration directory. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default) or data files using any\n * of the standard codecs (`.yaml` or `.json` by default).\n */\nexport class Config extends DirPath {\n /**\n * Constructor for Config object.\n * @param {String} dir - one or more directories that contain configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codec='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n this.state.codec = splitList(params.codec),\n this.state.jsExt = splitList(params.jsExt),\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n }\n\n /**\n * Internal method to locate the first config file with one of a number of file extensions.\n * @param {String} uri - base part of filename\n * @param {Array} [exts] - array of possible extensions\n * @param {Function} [makeOptions] - optional function to generate options for a {@link File} object\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async firstFileWithExt(uri, exts, makeOptions=doNothing) {\n const dirs = await this.dirs();\n\n for (let dir of dirs) {\n for (let ext of exts) {\n const path = uri + '.' + ext;\n const file = dir.file(path, makeOptions(uri, ext));\n this.debug('looking for config file: ', file.path());\n if (await file.exists()) {\n this.debug('config file exists: ', file.path());\n return file;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Internal method to locate a Javascript configuration file with one of the `jsExt` extensions (`.js` or `.mjs` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async jsFile(uri) {\n return await this.firstFileWithExt(uri, this.state.jsExt);\n }\n\n /**\n * Internal method to locate a configuration file with one of the `codec` extensions (`.yaml` or `.json` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async file(uri) {\n return await this.firstFileWithExt(uri, this.state.codec, (uri, codec) => ({ codec }));\n }\n\n /**\n * Method to fetch configuration data from a file. The file can be a Javascript file which should\n * return the configuration data as the default export, or a YAML (`.yaml`) or JSON (`.json`) file.\n * If the file isn't found then the method returns the `defaults` data if provided, or throws an\n * error if not.\n * @param {String} uri - base part of filename\n * @param {Object} [defaults] - default configuration options to be used if a file isn't found\n * @return {Object} the configuration data loaded from the file\n */\n async config(uri, defaults) {\n const [base, fragment] = uri.split('#', 2);\n let jsFile, file, data;\n\n // first look for a JS file, e.g. <uri>.js, <uri>.mjs\n if ((jsFile = await this.jsFile(base))) {\n data = await import(jsFile.path());\n }\n // then for a config file with a codec extension, e.g. <uri>.yaml, <uri>.yaml\n else if ((file = await this.file(base))) {\n data = await file.read();\n }\n // failing that use any default value\n else if (defaults) {\n data = defaults;\n }\n // anything else is a big pile of fail\n else {\n return fail(\"No configuration file for \" + base);\n }\n // resolve any data path in a #fragment\n return fragment\n ? dataPath(data, fragment)\n : data;\n }\n}\n\n/**\n * Function to create a new Config object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codec='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\nexport const config = (dir, options) => new Config(dir, options)\n\nexport default Config\n","import { DirPath } from \"./Filesystem/DirPath.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { fail } from \"./Utils/Misc.js\";\nimport { dataPath } from \"./Utils/DataPath.js\";\n\nconst defaults = {\n jsExt: 'js mjs',\n}\n\n/**\n * The Library class implements an object which can load Javascript files\n * from one or more library directories. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default)\n */\nexport class Library extends DirPath {\n /**\n * Constructor for Library object.\n * @param {String} dir - one or more directories that contain Javascript libraries\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n const exts = splitList(params.jsExt).map( ext => ext.replace(/^\\./, '') ); // remove leading '.'\n this.state.exts = exts;\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug(\"state: \", this.state)\n }\n\n /**\n * Method to load a Javascript library in one of the library directories and with one of the `jsExt` extensions (`.js` or `.mjs` by default).\n * Returns the exports from the library if found or throws an error if not.\n * @param {String} uri - base part of filename\n * @return {Object} the exports from the loaded libary\n */\n async library(uri) {\n const [base, fragment] = uri.split('#', 2);\n const dirs = await this.dirs();\n const exts = this.state.exts;\n for (let dir of dirs) {\n for (let ext of exts) {\n const file = dir.file(base + '.' + ext);\n this.debug('looking for module %s as', base, file.path());\n const exists = await file.exists();\n if (exists) {\n const load = await import(file.path());\n this.debug('loaded %s as', file.path());\n return fragment\n ? dataPath(load, fragment)\n : load;\n }\n }\n }\n fail(\"Library not found: \", uri);\n }\n}\n\n/**\n * Function to create a new Library object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\nexport const library = (dir, options) => new Library(dir, options);\n\nexport default library;","import { hasValue, fail } from \"./Misc.js\";\nimport { joinListOr, splitList } from \"./Text.js\";\n\n/**\n * Assert that a parameter object contains an item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {String} name - parameter that must be included\n * @return {any} the parameter value\n * @throws {Error} if the parameter is not defined or null\n * @example\n * const foo = requiredParam({ foo: 10 }, 'foo');\n */\nexport function requiredParam(params={}, name) {\n const value = params[name];\n if (hasValue(value)) {\n return value;\n }\n else {\n fail(\"Missing value for required parameter: \", name);\n }\n}\n\n/**\n * Assert that a parameter object contains all specified item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters that must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = requiredParams({ foo: 10, bar: 20 }, 'foo bar');\n */\nexport function requiredParams(params={}, names) {\n return splitList(names).map( name => requiredParam(params, name) );\n}\n\n/**\n * An alias for {@link requiredParams} for people who don't like typing long names (and for symmetry with {@link anyParams}))\n */\nexport const allParams=requiredParams;\n\n/**\n * Assert that a parameter object contains any of the specified items with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters of which at least one must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = anyParams({ foo: 10, wiz: 99 }, 'foo bar');\n */\nexport function anyParams(params, names) {\n let found = false;\n const nlist = splitList(names);\n const values = nlist.map(\n name => {\n const value = params[name];\n if (hasValue(value)) {\n found = true;\n }\n return value;\n }\n );\n return found\n ? values\n : fail(\"Missing value for one of: \", joinListOr(nlist));\n}\n","import { dir as fsDir } from \"./Filesystem/Directory.js\";\nimport { fail, hasValue } from \"./Utils/Misc.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { Config } from \"./Config.js\";\nimport { Library } from \"./Library.js\";\n\nconst defaults = {\n library: {\n dir: 'lib library src components',\n },\n config: {\n dir: 'config',\n }\n}\nexport class Workspace {\n constructor(dir, options={}) {\n const rootDir = fsDir(dir);\n const cfgDir = rootDir.dir(options.config?.dir || defaults.config.dir);\n const cfgOpts = { ...defaults.config, ...(options.config||{}) };\n const config = new Config(cfgDir, cfgOpts);\n const libDirs = splitList(options.library?.dir || defaults.library.dir).map( dir => rootDir.dir(dir) );\n const libOpts = { ...defaults.library, ...(options.library||{}) };\n const library = new Library(libDirs, libOpts);\n\n this.state = {\n rootDir,\n config,\n library\n }\n\n // console.log('options: ', options);\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug('root dir: ', rootDir.path());\n this.debug('config dir: ', cfgDir.path());\n this.debug('libDirs: ', libDirs);\n this.debug('libOpts: ', libOpts);\n }\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.rootDir.dir(path, options)\n : this.state.rootDir;\n }\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return this.state.rootDir.file(path, options)\n }\n read(path, options) {\n this.debug(\"read(%s, %o)\", path, options);\n return this.file(path, options).read();\n }\n write(path, data, options) {\n this.debug(\"write(%s, %o, %o)\", path, data, options);\n return this.file(path, options).write(data);\n }\n configDir(path, options) {\n this.debug(\"configDir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.configDir(path, options)\n : this.state.configDir;\n }\n async config(uri, defaults) {\n this.debug(\"config(%s, %o)\", uri, defaults);\n return hasValue(uri)\n ? this.state.config.config(uri, defaults)\n : this.state.config;\n }\n async library(uri) {\n return this.state.library.library(uri);\n }\n async component(uri, props) {\n const config = await this.config(uri, {});\n const lib = await this.library(config.component?.library || uri);\n const exp = config.component?.export || 'default';\n const compcls = lib[exp] || fail(\"No '\", exp, \"' export from component library: \", uri);\n const comp = new compcls(this, { ...config, ...props });\n // this.debug(\"created component \", uri)\n return comp;\n }\n}\n\nexport const workspace = (dir, options) => new Workspace(dir, options);\n\nexport default Workspace;","import { addDebug } from \"./Utils/Debug.js\";\n\nexport class Component {\n constructor(workspace, props={}) {\n this.workspace = workspace;\n this.props = props;\n addDebug(this, props.debug, props.debugPrefix, props.debugColor);\n this.initComponent(props);\n }\n initComponent() {\n // stub for subclasses\n }\n}\n\nexport default Component"],"names":["isString","value","isArray","Array","isObject","isNull","isUndefined","hasValue","noValue","fail","message","Error","join","rethrow","error","doNothing","ANSIColors","reset","bold","bright","dark","black","red","green","yellow","blue","magenta","cyan","grey","white","fg","bg","ANSIescapeCode","color","base","codes","pair","split","hue","pop","code","push","length","shade","shift","ANSIescape","colors","col","escapes","ANSIreset","Debugger","enabled","prefix","format","args","console","log","bind","addDebug","obj","debug","codecs","json","encode","data","JSON","stringify","decode","text","parse","yaml","dump","load","codec","name","toLowerCase","defaultOptions","encoding","Path","constructor","path","options","this","state","debugPrefix","debugColor","relativePath","parts","async","stat","stats","unstat","undefined","File","directory","dir","dirname","read","opts","file","readFile","then","write","writeFile","rm","Directory","parent","readdir","isEmpty","exists","notEmpty","mkdir","empty","rmdir","create","recursive","destroy","force","splitList","joinList","array","joint","lastJoint","copy","last","joinListOr","capitalise","word","charAt","toUpperCase","slice","DirPath","dirs","initDirs","map","fsDir","dirsExist","Promise","all","d","filter","index","quotedEscapes","b","f","n","r","t","v","splitDataPath","matchAll","single","double","other","optional","part","replace","one","dataPath","root","done","defaults","jsExt","Config","super","params","uri","exts","makeOptions","ext","firstFileWithExt","fragment","jsFile","resolve","_interopNamespace","require","Library","requiredParam","requiredParams","names","allParams","Workspace","rootDir","cfgDir","config","cfgOpts","libDirs","library","libOpts","configDir","props","lib","component","exp","export","workspace","initComponent","found","nlist","values","url","process","cwd","every","string","match","snake","segment","i"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import t from"js-yaml";import i from"node:process";import s from"node:path";import{stat as e,readFile as r,writeFile as n,rm as o,readdir as a,mkdir as c,rmdir as h}from"node:fs/promises";function u(t){return"string"==typeof t}function d(t){return Array.isArray(t)}function f(t){return"function"==typeof t}function p(t){return"object"==typeof t&&!d(t)&&!g(t)}function l(t){return void 0===t}function g(t){return null===t}function b(t){return!(l(t)||g(t))}function m(...t){return t.every((t=>b(t)))}function y(t){return!b(t)}function w(...t){throw new Error(t.join(""))}function x(t){throw t}function j(){}const E={reset:0,bold:1,bright:1,dark:2,black:0,red:1,green:2,yellow:3,blue:4,magenta:5,cyan:6,grey:7,white:8,fg:30,bg:40},D=(t,i="fg")=>{let s=[],e=t.split(/ /,2);const r=e.pop(),n=(i?E[i]:0)+E[r];if(s.push(n),e.length){const t=e.length?e.shift():"dark";s.push(E[t])}return"["+s.join(";")+"m"};function k(t,i="",s){return t?i?(t,...e)=>console.log("%s"+i+"%s"+t,s?((t={})=>{const i=p(t)?t:{fg:t};let s=[];return i.bg&&s.push(D(i.bg,"bg")),i.fg&&s.push(D(i.fg,"fg")),s.join("")})(s):"",D("reset",!1),...e):console.log.bind(console):j}function v(t,i,s="",e){t.debug=k(i,s,e)}class C{constructor(t,i={}){this.workspace=t,this.props=i,v(this,i.debug,i.debugPrefix,i.debugColor),this.initComponent(i)}initComponent(){}}const P={json:{encode:t=>JSON.stringify(t),decode:t=>JSON.parse(t)},yaml:{encode:i=>t.dump(i),decode:i=>t.load(i)}},N=t=>P[t.toLowerCase()],F={encoding:"utf8"};class O{constructor(t,i={}){t instanceof O&&(t=t.path()),this.state={path:t,options:{...F,...i}},v(this,i.debug,i.debugPrefix||"Path",i.debugColor)}path(){return this.state.path}relativePath(...t){return s.join(this.state.path,...t)}options(t={}){return{...this.state.options,...t}}async exists(){try{return await this.stat(),!0}catch(t){return"ENOENT"!==t.code&&x(t)}}async stat(){const t=await e(this.state.path);return this.state.stats=t}unstat(){return this.state.stats=void 0,this}}class A extends O{directory(t){return J(s.dirname(this.state.path),t)}dir(...t){return this.directory(...t)}read(t){const i=this.options(t),s=r(this.state.path,i);return i.codec?s.then((t=>N(i.codec).decode(t))):s}write(t,i){const s=this.options(i),e=s.codec?N(s.codec).encode(t):t;return n(this.state.path,e,s).then((()=>this))}async delete(t){return await o(this.state.path,t),this}}const L=(t,i)=>new A(t,i);class W extends O{file(t,i){return this.debug("file(%s, %o)",t,i),L(this.relativePath(t),this.options(i))}directory(t,i){return this.debug("directory(%s, %o)",t,i),J(this.relativePath(t),this.options(i))}dir(t,i){return this.debug("dir(%s, %o)",t,i),this.directory(t,i)}parent(t){return this.debug("parent()"),this.directory("..",t)}async read(){return this.debug("read()"),await a(this.path())}async isEmpty(){this.debug("isEmpty()");return 0===(await this.read()).length}async notEmpty(){this.debug("notEmpty()");return!await this.isEmpty()}async empty(t={}){return this.debug("empty(%o)",t),await this.exists()&&await this.notEmpty()&&await o(this.path(),t),this}async mkdir(t={}){this.debug("mkdir(%o)",t);return await this.exists()||await c(this.path(),t),this}async rmdir(t={}){return this.debug("rmdir(%o)",t),t.empty&&await this.empty(t),await this.exists()&&await h(this.path()),this}create(t={recursive:!0}){return this.debug("create(%o)",t),this.mkdir(t)}destroy(t={empty:!0,recursive:!0,force:!0}){return this.debug("destroy(%o)",t),this.rmdir(t)}async mustExist(t={}){return this.debug("mustExist(%o)",t),await this.exists()?this:t.mkdir?this.mkdir(t):t.create?this.create():void w("Directory does not exist: ",this.path())}}const J=(t,i)=>new W(t,i),M=t=>J(i.cwd(),t),S=(t,i)=>J(s.dirname(t.replace(/^file:\/\//,"")),i);function _(t){return y(t)?[]:u(t)?t.length?t.split(/,\s*|\s+/):[]:d(t)?t:[t]}function q(t,i=" ",s=i){let e=[...t];const r=e.pop();return e.length?[e.join(i),r].join(s):r}function T(t,i=", ",s=" and "){return q(t,i,s)}function U(t,i=", ",s=" or "){return q(t,i,s)}function z(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}function B(t){return t.split("/").map((t=>t.split("_").map(z).join(""))).join("/")}function G(t){return t.split("/").map((t=>t.split("_").map(((t,i)=>i?z(t):t)).join(""))).join("/")}class H{constructor(t){const i=this.initDirs(t);this.state={dirs:i}}initDirs(t){return _(t).map((t=>J(t)))}async dirs(){return this.state.dirsExist||(this.state.dirsExist=await this.dirsExist())}async dirsExist(){const t=this.state.dirs,i=await Promise.all(t.map((t=>t.exists())));return t.filter(((t,s)=>i[s]))}}const I={codecs:["yaml","json"],jsExt:["js","mjs"]};class K extends H{constructor(t,i={}){super(t);const s={...I,...i};this.state.codecs=_(s.codecs),this.state.jsExt=_(s.jsExt),v(this,i.debug,i.debugPrefix,i.debugColor)}async firstFileWithExt(t,i,s=j){const e=await this.dirs();for(let r of e)for(let e of i){const i=t+"."+e,n=r.file(i,s(t,e));if(this.debug("looking for config file: ",n.path()),await n.exists())return this.debug("config file exists: ",n.path()),n}}async jsFile(t){return await this.firstFileWithExt(t,this.state.jsExt)}async file(t){return await this.firstFileWithExt(t,this.state.codecs,((t,i)=>({codec:i})))}async config(t,i){const s=await this.jsFile(t);if(s){return(await import(s.path())).default}const e=await this.file(t);return e?await e.read():i||w("No configuration file for "+t)}}const Q=(t,i)=>new K(t,i),R={jsExt:"js mjs"};class V extends H{constructor(t,i={}){super(t);const s=_({...R,...i}.jsExt).map((t=>t.replace(/^\./,"")));this.state.exts=s,v(this,i.debug,i.debugPrefix,i.debugColor),this.debug("state: ",this.state)}async lib(t){const i=await this.dirs(),s=this.state.exts;for(let e of i)for(let i of s){const s=e.file(t+"."+i);this.debug("looking for module %s as",t,s.path());if(await s.exists()){const t=await import(s.path());return this.debug("loaded %s as",s.path()),t}}w("Library not found: ",t)}}const X=(t,i)=>new V(t,i);function Y(t={},i){const s=t[i];if(b(s))return s;w("Missing value for required parameter: ",i)}function Z(t={},i){return _(i).map((i=>Y(t,i)))}const $=Z;function tt(t,i){let s=!1;const e=_(i),r=e.map((i=>{const e=t[i];return b(e)&&(s=!0),e}));return s?r:w("Missing value for one of: ",U(e))}const it={dir:"lib library src components"},st={dir:"config"};class et{constructor(t,i={}){const s=J(t),e=s.dir(i.config?.dir||st.dir),r={...st,...i.config||{}},n=new K(e,r),o=_(i.library?.dir||it.dir).map((t=>s.dir(t))),a={...it,...i.library||{}},c=new V(o,a);this.state={rootDir:s,config:n,library:c},v(this,i.debug,i.debugPrefix,i.debugColor),this.debug("root dir: ",s.path()),this.debug("config dir: ",e.path()),this.debug("libDirs: ",o),this.debug("libOpts: ",a)}dir(t,i){return this.debug("dir(%s, %o)",t,i),b(t)?this.state.rootDir.dir(t,i):this.state.rootDir}file(t,i){return this.debug("file(%s, %o)",t,i),this.state.rootDir.file(t,i)}read(t,i){return this.debug("read(%s, %o)",t,i),this.file(t,i).read()}write(t,i,s){return this.debug("write(%s, %o, %o)",t,i,s),this.file(t,s).write(i)}configDir(t,i){return this.debug("configDir(%s, %o)",t,i),b(t)?this.state.configDir(t,i):this.state.configDir}async config(t,i){return this.debug("config(%s, %o)",t,i),b(t)?this.state.config.config(t,i):this.state.config}async lib(t){return this.state.library.lib(t)}async component(t,i){const s=await this.config(t,{}),e=await this.lib(s.component?.library||t),r=s.component?.export||"default";return new(e[r]||w("No '",r,"' export from component library: ",t))(this,{...s,...i})}}const rt=(t,i)=>new et(t,i);export{C as Component,K as Config,k as Debugger,V as Library,O as Path,et as Workspace,v as addDebug,$ as allParams,tt as anyParams,S as bin,z as capitalise,N as codec,P as codecs,Q as config,M as cwd,J as dir,j as doNothing,w as fail,L as file,b as hasValue,m as haveValue,d as isArray,f as isFunction,g as isNull,p as isObject,u as isString,l as isUndefined,q as joinList,T as joinListAnd,U as joinListOr,X as library,y as noValue,Y as requiredParam,Z as requiredParams,x as rethrow,G as snakeToCamel,B as snakeToStudly,_ as splitList,rt as workspace};
1
+ import t from"js-yaml";import i from"node:process";import e from"node:path";import{stat as s,readFile as r,writeFile as n,rm as o,readdir as a,mkdir as c,rmdir as u}from"node:fs/promises";function h(t){return"string"==typeof t}function d(t){return Array.isArray(t)}function f(t){return"function"==typeof t}function l(t){return"object"==typeof t&&!d(t)&&!g(t)}function p(t){return void 0===t}function g(t){return null===t}function b(t){return!(p(t)||g(t))}function m(...t){return t.every((t=>b(t)))}function y(t){return!b(t)}function w(...t){throw new Error(t.join(""))}function x(t){throw t}function j(){}const E={reset:0,bold:1,bright:1,dark:2,black:0,red:1,green:2,yellow:3,blue:4,magenta:5,cyan:6,grey:7,white:8,fg:30,bg:40},v=(t,i="fg")=>{let e=[],s=t.split(/ /,2);const r=s.pop(),n=(i?E[i]:0)+E[r];if(e.push(n),s.length){const t=s.length?s.shift():"dark";e.push(E[t])}return"["+e.join(";")+"m"},D=(t={})=>{const i=l(t)?t:{fg:t};let e=[];return i.bg&&e.push(v(i.bg,"bg")),i.fg&&e.push(v(i.fg,"fg")),e.join("")},k=()=>v("reset",!1);function C(t,i="",e){return t?i?(t,...s)=>console.log("%s"+i+"%s"+t,e?D(e):"",k(),...s):console.log.bind(console):j}function P(t,i,e="",s){t.debug=C(i,e,s)}class N{constructor(t,i={}){this.workspace=t,this.props=i,P(this,i.debug,i.debugPrefix,i.debugColor),this.initComponent(i)}initComponent(){}}const $={json:{encode:t=>JSON.stringify(t),decode:t=>JSON.parse(t)},yaml:{encode:i=>t.dump(i),decode:i=>t.load(i)}},F=t=>$[t.toLowerCase()],A={encoding:"utf8"};class O{constructor(t,i={}){t instanceof O&&(t=t.path()),this.state={path:t,options:{...A,...i}},P(this,i.debug,i.debugPrefix||"Path",i.debugColor)}path(){return this.state.path}relativePath(...t){return e.join(this.state.path,...t)}options(t={}){return{...this.state.options,...t}}async exists(){try{return await this.stat(),!0}catch(t){return"ENOENT"!==t.code&&x(t)}}async stat(){const t=await s(this.state.path);return this.state.stats=t}unstat(){return this.state.stats=void 0,this}}class L extends O{directory(t){return M(e.dirname(this.state.path),t)}dir(...t){return this.directory(...t)}read(t){const i=this.options(t),e=r(this.state.path,i);return i.codec?e.then((t=>F(i.codec).decode(t))):e}write(t,i){const e=this.options(i),s=e.codec?F(e.codec).encode(t):t;return n(this.state.path,s,e).then((()=>this))}async delete(t){return await o(this.state.path,t),this}}const W=(t,i)=>new L(t,i);class J extends O{file(t,i){return this.debug("file(%s, %o)",t,i),W(this.relativePath(t),this.options(i))}directory(t,i){return this.debug("directory(%s, %o)",t,i),M(this.relativePath(t),this.options(i))}dir(t,i){return this.debug("dir(%s, %o)",t,i),this.directory(t,i)}parent(t){return this.debug("parent()"),this.directory("..",t)}async read(){return this.debug("read()"),await a(this.path())}async isEmpty(){this.debug("isEmpty()");return 0===(await this.read()).length}async notEmpty(){this.debug("notEmpty()");return!await this.isEmpty()}async empty(t={}){return this.debug("empty(%o)",t),await this.exists()&&await this.notEmpty()&&await o(this.path(),t),this}async mkdir(t={}){this.debug("mkdir(%o)",t);return await this.exists()||await c(this.path(),t),this}async rmdir(t={}){return this.debug("rmdir(%o)",t),t.empty&&await this.empty(t),await this.exists()&&await u(this.path()),this}create(t={recursive:!0}){return this.debug("create(%o)",t),this.mkdir(t)}destroy(t={empty:!0,recursive:!0,force:!0}){return this.debug("destroy(%o)",t),this.rmdir(t)}async mustExist(t={}){return this.debug("mustExist(%o)",t),await this.exists()?this:t.mkdir?this.mkdir(t):t.create?this.create():void w("Directory does not exist: ",this.path())}}const M=(t,i)=>new J(t,i),S=t=>M(i.cwd(),t),_=(t,i)=>M(e.dirname(t.replace(/^file:\/\//,"")),i);function q(t){return y(t)?[]:h(t)?t.length?t.split(/,\s*|\s+/):[]:d(t)?t:[t]}function T(t,i=" ",e=i){let s=[...t];const r=s.pop();return s.length?[s.join(i),r].join(e):r}function U(t,i=", ",e=" and "){return T(t,i,e)}function z(t,i=", ",e=" or "){return T(t,i,e)}function B(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}function G(t){return t.split("/").map((t=>t.split("_").map(B).join(""))).join("/")}function H(t){return t.split("/").map((t=>t.split("_").map(((t,i)=>i?B(t):t)).join(""))).join("/")}class I{constructor(t){const i=this.initDirs(t);this.state={dirs:i}}initDirs(t){return q(t).map((t=>M(t)))}async dirs(){return this.state.dirsExist||(this.state.dirsExist=await this.dirsExist())}async dirsExist(){const t=this.state.dirs,i=await Promise.all(t.map((t=>t.exists())));return t.filter(((t,e)=>i[e]))}}const K={b:"\b",f:"\f",n:"\n",r:"\r",t:"\t",v:"\v",'"':'"',"'":"'","\\":"\\"},Q=t=>{const i=t.match(/^"((?:\\[\\"nrt]|.)*?)"$/);return i?i[1].replace(/\\([\\"bfnrtv])/g,((t,i)=>K[i]||`\\${i}`)):null},R=t=>{const i=t.match(/^'((?:\\[\\']|.)*?)'$/);return i?i[1].replace(/\\([\\'bfnrtv])/g,((t,i)=>K[i]||`\\${i}`)):null},V=t=>{let i=[];return[...t.matchAll(/(?:(\/)|'((?:\\[\\']|.)*?)'|"((?:\\[\\"nrt]|.)*?)"|([^/?]+))(\??)/g)].map((([,,t,e,s,r])=>{let n;t?n=t.replace(/\\([\\'bfnrtv])/g,((t,i)=>K[i]||`\\${i}`)):e?n=e.replace(/\\([\\"bfnrtv])/g,((t,i)=>K[i]||`\\${i}`)):s&&(n=s),b(n)&&i.push(r?[n,{optional:!0}]:n)})),i},X=(t,i)=>{let e=t,s=V(i),r=[];for(let t of s){const[i,s]=d(t)?t:[t,{}];if(e=e[i],r.push(i),y(e)){if(s.optional)return e;w("No value for data at path: ",r.join("/"))}}return e},Y={codec:["yaml","json"],jsExt:["js","mjs"]};class Z extends I{constructor(t,i={}){super(t);const e={...Y,...i};this.state.codec=q(e.codec),this.state.jsExt=q(e.jsExt),P(this,i.debug,i.debugPrefix,i.debugColor)}async firstFileWithExt(t,i,e=j){const s=await this.dirs();for(let r of s)for(let s of i){const i=t+"."+s,n=r.file(i,e(t,s));if(this.debug("looking for config file: ",n.path()),await n.exists())return this.debug("config file exists: ",n.path()),n}}async jsFile(t){return await this.firstFileWithExt(t,this.state.jsExt)}async file(t){return await this.firstFileWithExt(t,this.state.codec,((t,i)=>({codec:i})))}async config(t,i){const[e,s]=t.split("#",2);let r,n,o;if(r=await this.jsFile(e))o=await import(r.path());else if(n=await this.file(e))o=await n.read();else{if(!i)return w("No configuration file for "+e);o=i}return s?X(o,s):o}}const tt=(t,i)=>new Z(t,i),it={jsExt:"js mjs"};class et extends I{constructor(t,i={}){super(t);const e=q({...it,...i}.jsExt).map((t=>t.replace(/^\./,"")));this.state.exts=e,P(this,i.debug,i.debugPrefix,i.debugColor),this.debug("state: ",this.state)}async library(t){const[i,e]=t.split("#",2),s=await this.dirs(),r=this.state.exts;for(let t of s)for(let s of r){const r=t.file(i+"."+s);this.debug("looking for module %s as",i,r.path());if(await r.exists()){const t=await import(r.path());return this.debug("loaded %s as",r.path()),e?X(t,e):t}}w("Library not found: ",t)}}const st=(t,i)=>new et(t,i);function rt(t={},i){const e=t[i];if(b(e))return e;w("Missing value for required parameter: ",i)}function nt(t={},i){return q(i).map((i=>rt(t,i)))}const ot=nt;function at(t,i){let e=!1;const s=q(i),r=s.map((i=>{const s=t[i];return b(s)&&(e=!0),s}));return e?r:w("Missing value for one of: ",z(s))}const ct={dir:"lib library src components"},ut={dir:"config"};class ht{constructor(t,i={}){const e=M(t),s=e.dir(i.config?.dir||ut.dir),r={...ut,...i.config||{}},n=new Z(s,r),o=q(i.library?.dir||ct.dir).map((t=>e.dir(t))),a={...ct,...i.library||{}},c=new et(o,a);this.state={rootDir:e,config:n,library:c},P(this,i.debug,i.debugPrefix,i.debugColor),this.debug("root dir: ",e.path()),this.debug("config dir: ",s.path()),this.debug("libDirs: ",o),this.debug("libOpts: ",a)}dir(t,i){return this.debug("dir(%s, %o)",t,i),b(t)?this.state.rootDir.dir(t,i):this.state.rootDir}file(t,i){return this.debug("file(%s, %o)",t,i),this.state.rootDir.file(t,i)}read(t,i){return this.debug("read(%s, %o)",t,i),this.file(t,i).read()}write(t,i,e){return this.debug("write(%s, %o, %o)",t,i,e),this.file(t,e).write(i)}configDir(t,i){return this.debug("configDir(%s, %o)",t,i),b(t)?this.state.configDir(t,i):this.state.configDir}async config(t,i){return this.debug("config(%s, %o)",t,i),b(t)?this.state.config.config(t,i):this.state.config}async library(t){return this.state.library.library(t)}async component(t,i){const e=await this.config(t,{}),s=await this.library(e.component?.library||t),r=e.component?.export||"default";return new(s[r]||w("No '",r,"' export from component library: ",t))(this,{...e,...i})}}const dt=(t,i)=>new ht(t,i);export{D as ANSIescape,v as ANSIescapeCode,k as ANSIreset,N as Component,Z as Config,C as Debugger,J as Directory,L as File,et as Library,O as Path,ht as Workspace,P as addDebug,ot as allParams,at as anyParams,_ as bin,B as capitalise,F as codec,$ as codecs,tt as config,S as cwd,X as dataPath,M as dir,j as doNothing,w as fail,W as file,b as hasValue,m as haveValue,d as isArray,f as isFunction,g as isNull,l as isObject,h as isString,p as isUndefined,T as joinList,U as joinListAnd,z as joinListOr,st as library,Q as matchDoubleQuotedString,R as matchSingleQuotedString,y as noValue,rt as requiredParam,nt as requiredParams,x as rethrow,H as snakeToCamel,G as snakeToStudly,V as splitDataPath,q as splitList,dt as workspace};
2
2
  //# sourceMappingURL=badger.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"badger.esm.js","sources":["../src/Badger/Utils/Misc.js","../src/Badger/Utils/Color.js","../src/Badger/Utils/Debug.js","../src/Badger/Component.js","../src/Badger/Codecs/Json.js","../src/Badger/Codecs/index.js","../src/Badger/Codecs/Yaml.js","../src/Badger/Filesystem/Path.js","../src/Badger/Filesystem/File.js","../src/Badger/Filesystem/Directory.js","../src/Badger/Utils/Text.js","../src/Badger/Filesystem/DirPath.js","../src/Badger/Config.js","../src/Badger/Library.js","../src/Badger/Utils/Params.js","../src/Badger/Workspace.js"],"sourcesContent":["/**\n * Determines if a value is a string\n * @param {String} value - value to test\n * @return {Boolean} true if `value` is a string or false if not\n */\nexport function isString(value) {\n return typeof value === 'string';\n}\n\n/**\n * Determines if a value is an array\n * @param {Array} value - value to test\n * @return {Boolean} true if `value` is an Array or false if not\n */\nexport function isArray(value) {\n return Array.isArray(value);\n}\n\n/**\n * Determines if a value is a Function\n * @param {Function} value - value to test\n * @return {Boolean} true if `value` is a Function or false if not\n */\nexport function isFunction(value) {\n return typeof value === 'function'\n}\n\n/**\n * Determines if a value is an Object (but not an Array)\n * @param {Object} value - value to test\n * @return {Boolean} true if `value` is an Object or false if not\n */\nexport function isObject(value) {\n return typeof value === \"object\"\n && ! isArray(value)\n && ! isNull(value);\n}\n\n/**\n * Determines if a value is `undefined`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or false if not\n */\nexport function isUndefined(value) {\n return typeof value === 'undefined';\n}\n\n/**\n * Determines if a value is `null`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `null` or false if not\n */\nexport function isNull(value) {\n return value === null;\n}\n\n/**\n * Determines if a value is defined and not null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is not `undefined` or `null`\n */\nexport function hasValue(value) {\n return ! (isUndefined(value) || isNull(value));\n}\n\n/**\n * Determines if all values are defined and not null\n * @param {any[]} values - values to test\n * @return {Boolean} true if all values are not `undefined` or `null`\n */\nexport function haveValue(...values) {\n return values.every( value => hasValue(value) );\n}\n\n/**\n * Determines if a value is undefined or null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or `null`\n */\nexport function noValue(value) {\n return ! hasValue(value);\n}\n\n/**\n * Throws a new Error object\n * @param {String[]} message - error message string(s)\n * @throws {Error}\n */\nexport function fail(...message) {\n throw new Error(message.join(''));\n}\n\n/**\n * Re-throw an existing Error object\n * @param {Error} error - error object\n * @throws {Error}\n */\nexport function rethrow(error) {\n throw error;\n}\n\n/**\n * Do nothing. Nothing at all.\n */\nexport function doNothing() {\n // speak again Cordelia\n}","import { isObject } from \"./Misc.js\";\n\nexport const ANSIStart = '\\u001B[';\nexport const ANSIEnd = 'm';\nexport const ANSIColors = {\n reset: 0,\n bold: 1,\n bright: 1,\n dark: 2,\n black: 0,\n red: 1,\n green: 2,\n yellow: 3,\n blue: 4,\n magenta: 5,\n cyan: 6,\n grey: 7,\n white: 8,\n fg: 30,\n bg: 40,\n};\n\n/**\n * Returns an ANSI escape code for a color string. This can be a single color\n * name, e.g. `red`, `green`, etc., or a color prefixed with `bright` or `dark`,\n * e.g. `bright red`, `dark green`, etc. An optional section argument can be\n * set to `fg` (default) to set a foreground color or `bg` for a background color.\n * @param {String} color - color name with optional modifier prefix\n * @param {String} [base='fg'] - `fg` or `bg` to set foreground or background color respectively\n * @return {String} ANSI escape code string\n * @example\n * const str = escapeCode('red')\n * @example\n * const str = escapeCode('bright red')\n * @example\n * const str = escapeCode('bright red', 'bg')\n */\nexport const escapeCode = (color, base='fg') => {\n let codes = [ ];\n let pair = color.split(/ /, 2);\n const hue = pair.pop();\n const code = (base ? ANSIColors[base] : 0) + ANSIColors[hue];\n codes.push(code);\n if (pair.length) {\n const shade = pair.length ? pair.shift() : 'dark';\n codes.push(ANSIColors[shade])\n }\n // console.log('escapeCode(%s, %s) => ', color, base, codes.join(';'));\n return ANSIStart + codes.join(';') + ANSIEnd;\n}\n\n/**\n * Returns an ANSI escape code for a color string or combination of foreground and\n * background colors.\n * @param {String|Object} colors - either a simple color name or object contain foreground and background colors\n * @param {String} [colors.fg] - foreground color\n * @param {String} [colors.fg] - background color\n * @return {String} ANSI escape code string\n * @example\n * const str = escape('red')\n * @example\n * const str = escape('bright red')\n * @example\n * const str = escape({ fg: 'bright yellow', bg: 'blue' })\n */\nexport const escape = (colors={}) => {\n const col = isObject(colors) ? colors : { fg: colors };\n let escapes = [ ];\n if (col.bg) {\n escapes.push(escapeCode(col.bg, 'bg'));\n }\n if (col.fg) {\n escapes.push(escapeCode(col.fg, 'fg'));\n }\n return escapes.join('');\n}\n\nexport const reset = () => escapeCode('reset', false)\n\n","import { escape, reset } from './Color.js'\nimport { doNothing } from './Misc.js';\n\n/**\n * Returns a debugging function which is enabled by the first `enabled` argument.\n * If this is `false` then it returns a function which does nothing. If it is\n * true then it returns a function that forwards all arguments to `console.log`.\n * An optional `prefix` be be specified to prefix each debugging line. The\n * optional third argument `color` can be used to specify a color for the prefix.\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @return {Function} a debugging function\n * @example\n * const debug = Debugger(true)\n * @example\n * const debug = Debugger(true, 'Debug > ')\n * @example\n * const debug = Debugger(true, 'Debug > ', 'blue')\n * @example\n * const debug = Debugger(true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function Debugger(enabled, prefix='', color) {\n return enabled\n ? prefix\n ? (format, ...args) =>\n console.log(\n '%s' + prefix + '%s' + format,\n color ? escape(color) : '',\n reset(),\n ...args,\n )\n : console.log.bind(console)\n : doNothing;\n}\n\n/**\n * Creates a debugging function via {@link Debugger} and attaches it to the object\n * passed as the first argument as the `debug` function.\n * @param {Object} obj - the object to receive the `debug` function\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @example\n * const debug = addDebug(myObject, true)\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', 'blue')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function addDebug(obj, enabled, prefix='', color) {\n obj.debug = Debugger(enabled, prefix, color);\n}\n","import { addDebug } from \"./Utils/Debug.js\";\n\nexport class Component {\n constructor(workspace, props={}) {\n this.workspace = workspace;\n this.props = props;\n addDebug(this, props.debug, props.debugPrefix, props.debugColor);\n this.initComponent(props);\n }\n initComponent() {\n // stub for subclasses\n }\n}\n\nexport default Component","/**\n * Function to encode JSON\n * @param {Object} data - The data to encode as JSON text\n * @return {String} a JSON encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nexport const encode = data => JSON.stringify(data);\n\n/**\n * Function to decode JSON\n * @param {String} text - The JSON text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"{ message: 'Hello World' }\")\n */\nexport const decode = text => JSON.parse(text);\n\n/**\n * An object containing the JSON `encode` and `decode` functions\n */\nexport const codec = { encode, decode };\n\nexport default codec\n","import json from './Json.js'\nimport yaml from './Yaml.js'\n\n/**\n * Codecs provide a consistent encode()/decode() interface for serialising\n * and de-serialising data. This standard naming convention makes it possible\n * for the ../Filesystem/File.js module to support a \"codec\" option for\n * files. When this option is set the file.read() and file.write() methods\n * automatically handle the translation to and from the serialised format\n * using a codec object returned by the codec() function below. The codec\n * name can be specified in any case, e.g. \"Yaml\", \"YAML\", \"yaml\", \"YaML\",\n * etc., and it will be converted to lower case.\n */\n\n/**\n * Lookup table for codecs\n */\nexport const codecs = {\n json, yaml\n};\n\n/**\n * Function to fetch a codec\n * @param {string} name - The title of the code, in any case, e.g. \"yaml\", \"YAML\", \"Yaml\"\n */\nexport const codec = name => codecs[\n name.toLowerCase()\n];\n\nexport default codecs\n","// simple wrapper around JSON load/dump\nimport yaml from 'js-yaml';\n\n/**\n * Function to encode YAML\n * @param {Object} data - The data to encode as YAML text\n * @return {String} a YAML encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nexport const encode = data => yaml.dump(data);\n\n/**\n * Function to decode YAML\n * @param {String} text - The YAML text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"message: Hello World\")\n */\nexport const decode = text => yaml.load(text);\n\n/**\n * An object containing the YAML `encode` and `decode` functions\n */\nexport const codec = { encode, decode };\n\nexport default codec\n","import path from 'node:path';\nimport { stat } from 'node:fs/promises'\nimport { rethrow } from '../Utils/Misc.js';\nimport { addDebug } from '../Utils/Debug.js';\n\nconst defaultOptions = {\n encoding: 'utf8'\n}\n\n/**\n * The Path class implements a base class for the {@link File} and {@link Directory}\n * classes. It implements the common functionality for representing a filesystem path.\n */\nexport class Path {\n /**\n * Constructor for filesystem paths.\n * @param {string} path - file path\n * @param {Object} [options] - configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Path} object\n */\n constructor(path, options={}) {\n // allow path/file/directory to be constructed from an existing object\n if (path instanceof Path) {\n path = path.path();\n }\n this.state = { path, options: { ...defaultOptions, ...options } };\n addDebug(this, options.debug, options.debugPrefix || 'Path', options.debugColor);\n }\n\n /**\n * Accessor method to return the filesystem path.\n * @return {String} the filesystem path\n */\n path() {\n return this.state.path;\n }\n\n /**\n * Create a path relative to the current path.\n * @param {String[]} parts - part(s) of the filesystem path\n * @return {String} the new path\n * @example\n * const p = new Path('/path/to/here')\n * const q = p.relativePath('there') // -> /path/to/here/there\n * const r = p.relativePath('and', 'there') // -> /path/to/here/and/there\n */\n relativePath(...parts) {\n return path.join(this.state.path, ...parts);\n }\n\n /**\n * Internal method to merge any options with the pre-defined options passed to the\n * constructor. Options passed as arguments will take precedence.\n * @param {Object} options - new options\n * @return {Object} the merged options\n * @example\n * const p = new Path('/path/to/here', { option1: 'hello' })\n * const q = p.options({ option2: 'world' }) // -> { option1: 'hello', options2: 'world' }\n */\n options(options={}) {\n return { ...this.state.options, ...options };\n }\n\n /**\n * Method to assert that the path exists.\n * @return {Promise} fulfills with `true` if the path exists or rejects if the path doesn't\n * @example\n * const p = new Path('/path/to/here')\n * p.exists()\n * .then( console.log('path exists') )\n * .catch( console.log('path does not exist') )\n */\n async exists() {\n try {\n await this.stat();\n return true;\n }\n catch (error) {\n return error.code === 'ENOENT'\n ? false\n : rethrow(error);\n }\n }\n\n /**\n * Method to fetch stats for the path. Uses the `stat` function from `node:fs/promises`.\n * Stats are cached internally (subject to change)\n * @return {Promise} fulfills with path stats returned from the `stat` function\n * @example\n * const p = new Path('/path/to/here')\n * p.stat()\n * .then( stats => console.log('path stats:', stats) )\n * .catch( console.log('path does not exist') )\n */\n async stat() {\n const stats = await stat(this.state.path);\n return this.state.stats = stats;\n }\n\n /**\n * Method to clear internal cache of path stats (subject to change)\n */\n unstat() {\n this.state.stats = undefined;\n return this;\n }\n}\n\nexport default Path\n","import path from 'node:path'\nimport Path from './Path.js'\nimport { dir } from './Directory.js'\nimport { codec } from '../Codecs/index.js'\nimport { readFile, writeFile, rm } from 'node:fs/promises'\n\n/**\n * The File class implements a wrapper around a filesystem\n * file.\n */\nclass File extends Path {\n /**\n * Returns a new {@link Directory} object for the parent directory of the file\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n directory(options) {\n return dir(path.dirname(this.state.path), options);\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the parent {@link Directory} object\n */\n dir(...args) {\n return this.directory(...args);\n }\n\n /**\n * Reads the file content. If a `codec` has been specified then the content is decoded.\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {String|Object} the file content\n * @example\n * const text = file('myfile.txt').read();\n * @example\n * const data = file('myfile.json', { codec: 'json' }).read();\n * @example\n * const data = file('myfile.json').read({ codec: 'json' });\n */\n read(options) {\n const opts = this.options(options);\n const file = readFile(this.state.path, opts);\n return opts.codec\n ? file.then(text => codec(opts.codec).decode(text))\n : file;\n }\n\n /**\n * Writes the file content. If a `codec` has been specified then the content will be encoded.\n * @param {String|Object} data - directory configuration options\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @example\n * file('myfile.txt').write('Hello World');\n * @example\n * file('myfile.json', { codec: 'json' }).write({ message: 'Hello World' });\n * @example\n * file('myfile.json').write({ message: 'Hello World' }, { codec: 'json' });\n */\n write(data, options) {\n const opts = this.options(options);\n const text = opts.codec\n ? codec(opts.codec).encode(data)\n : data;\n return writeFile(this.state.path, text, opts).then( () => this );\n }\n\n async delete(options) {\n await rm(this.state.path, options);\n return this;\n }\n}\n\n/**\n * Function to create a new {@link File} object for a file\n * @param {String} path - file path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link File} object\n */\nexport const file = (path, options) => {\n return new File(path, options);\n}\n\nexport default File\n","import process from 'node:process';\nimport path from 'node:path';\nimport Path from './Path.js'\nimport { file } from './File.js'\nimport { fail } from '../Utils/Misc.js';\nimport { rm, mkdir, rmdir, readdir } from 'node:fs/promises'\n\n/**\n * The Directory class implements a wrapper around a filesystem\n * directory.\n */\nclass Directory extends Path {\n /**\n * Fetch a new {@link File} object for a file in the directory.\n * @param {string} path - file path\n * @param {Object} [options] - file configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link File} object\n */\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return file(this.relativePath(path), this.options(options));\n }\n\n /**\n * Fetch a new {@link Directory} object for a sub-directory in the directory.\n * @param {string} path - directory path\n * @param {Object} [options] - directory configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Directory} object\n */\n directory(path, options) {\n this.debug(\"directory(%s, %o)\", path, options);\n return dir(this.relativePath(path), this.options(options));\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the {@link Directory} object\n */\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return this.directory(path, options);\n }\n\n /**\n * Returns a new {@link Directory} object for the parent directory\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n parent(options) {\n this.debug(\"parent()\");\n return this.directory('..', options);\n }\n\n /**\n * Returns the names of the files and sub-directories in the directory\n * @return {Promise} fulfills with an array of the file and directory names\n */\n async read() {\n this.debug(\"read()\");\n return await readdir(this.path());\n }\n\n /**\n * Determines if the directory is empty.\n * @return {Promise} fulfills with a boolean value true (empty) or false (not empty).\n */\n async isEmpty() {\n this.debug(\"isEmpty()\");\n const entries = await this.read();\n return entries.length === 0;\n }\n\n /**\n * Determines if the directory is not empty.\n * @return {Promise} fulfills with a boolean value true (not empty) or false (empty).\n */\n async notEmpty() {\n this.debug(\"notEmpty()\");\n const empty = await this.isEmpty();\n return !empty;\n }\n\n /**\n * Empty the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.force] - force removal of files and directories\n * @param {Boolean} [options.recursive] - recursively empty and delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async empty(options={}) {\n this.debug(\"empty(%o)\", options);\n if (await this.exists() && await this.notEmpty()) {\n await rm(this.path(), options);\n }\n return this;\n }\n\n /**\n * Make the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive] - create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mkdir(options={}) {\n this.debug(\"mkdir(%o)\", options);\n const exists = await this.exists();\n if (! exists) {\n await mkdir(this.path(), options);\n }\n return this;\n }\n\n /**\n * Remove the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty] - delete items in directory\n * @param {Boolean} [options.force] - force delete files and directories\n * @param {Boolean} [options.recursive] - recursively delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async rmdir(options={}) {\n this.debug(\"rmdir(%o)\", options);\n if (options.empty) {\n await this.empty(options);\n }\n if (await this.exists()) {\n await rmdir(this.path());\n }\n return this;\n }\n\n /**\n * Create the directory and any intermediate directories.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive=true] - recursively create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n create(options={ recursive: true }) {\n this.debug(\"create(%o)\", options);\n return this.mkdir(options);\n }\n\n /**\n * Empty and delete the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty=true] - empty directory of any files and sub-directories\n * @param {Boolean} [options.recursive=true] - recursively delete sub-directories\n * @param {Boolean} [options.force=true] - force deletion of files and sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n destroy(options={ empty: true, recursive: true, force: true }) {\n this.debug(\"destroy(%o)\", options);\n return this.rmdir(options);\n }\n\n /**\n * Assert that a directory exists and optionally create it\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.create] - create the directory and any intermediate directories if it doesn't exist - equivalent to adding `mkdir` and `recursive` options or calling {@link create}\n * @param {Boolean} [options.mkdir] - create the directory, add the `recursive` option to create intermediate directories - equivalent to calling {@link mkdir}\n * @param {Boolean} [options.recursive] - when used with `mkdir`, creates any intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mustExist(options={}) {\n this.debug(\"mustExist(%o)\", options);\n if (await this.exists()) {\n return this;\n }\n if (options.mkdir) {\n return this.mkdir(options);\n }\n if (options.create) {\n return this.create();\n }\n fail(\"Directory does not exist: \", this.path());\n }\n}\n\n/**\n * Function to create a new {@link Directory} object\n * @param {string} path - directory path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const dir = (path, options) => {\n return new Directory(path, options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the current working directory\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const cwd = options => {\n return dir(process.cwd(), options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the directory of a JS source file\n * @param {string} url - module url - from `import.meta.url`\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const bin = (url, options) => {\n return dir(\n path.dirname(url.replace(/^file:\\/\\//, '')),\n options\n );\n}\n\nexport default Directory\n","import { isString, isArray, noValue } from \"./Misc.js\";\n\n/**\n * Split a comma/whitespace delimited string into an Array\n * @param {String} [value] - string to split\n * @return {Array} array of split strings\n * @example\n * const strings = splitList('one two three')\n * @example\n * const strings = splitList('one,two,three')\n * @example\n * const strings = splitList('one, two, three')\n */\nexport function splitList(value) {\n if (noValue(value)) {\n return [ ];\n }\n else if (isString(value)) {\n return value.length\n ? value.split(/,\\s*|\\s+/)\n : [ ]\n }\n else if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\n/**\n * Join an Array into a single string\n * @param {Array} [array] - array to join\n * @param {String} [joint=' '] - delimiter to join strings\n * @param {String} [lastJoint=joint] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinList(['one', 'two', 'three']); // one two three\n * @example\n * joinList(['one', 'two', 'three'], ', '); // one, two, three\n * @example\n * joinList(['one', 'two', 'three'], ', ', ' and '); // one, two and three\n */\nexport function joinList(array, joint=' ', lastJoint=joint) {\n let copy = [...array];\n const last = copy.pop();\n return copy.length\n ? [copy.join(joint), last].join(lastJoint)\n : last;\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` and ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' and '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListAnd(['one', 'two', 'three']); // one, two and three\n */\nexport function joinListAnd(array, joint=', ', lastJoint=' and ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` or ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' or '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListOr(['one', 'two', 'three']); // one, two or three\n */\nexport function joinListOr(array, joint=', ', lastJoint=' or ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Capitalise a string by converting the first character to upper case and other characters to lower case\n * @param {String} [word] - word to capitalise\n * @return {String} capitalised string\n * @example\n * capitalise('badger'); // Badger\n * @example\n * capitalise('BADGER'); // Badger\n */\nexport function capitalise(word) {\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n}\n\n/**\n * Convert a snake case string to studly caps\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToStudly('happy_badger_dance'); // HappyBadgerDance\n * @example\n * snakeToStudly('happy_badger/dance'); // HappyBadger/Dance\n */\nexport function snakeToStudly(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to FooBar\n segment => segment.split('_').map(capitalise).join('')\n ).join('/');\n}\n\n/**\n * Convert a snake case string to camel case\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToCamel('happy_badger_dance'); // happyBadgerDance\n * @example\n * snakeToCamel('happy_badger/dance'); // happyBadger/dance\n */\nexport function snakeToCamel(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to fooBar\n segment => segment.split('_').map((i, n) => n ? capitalise(i) : i).join('')\n ).join('/');\n}\n","import { dir as fsDir } from \"./Directory.js\";\nimport { splitList } from \"../Utils/Text.js\";\n\n/**\n * The DirPath class implements a base class for objects that\n * can search one or more directories.\n */\nexport class DirPath {\n /**\n * Constructor for filesystem paths.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Object} the {@link DirPath} object\n */\n constructor(dir) {\n const dirs = this.initDirs(dir);\n this.state = {\n dirs\n }\n }\n\n /**\n * Internal method to initialise the directories. If the `dir` argument is a string then it will be split on\n * commas and/or whitespace and converted to an array of {@link Directory} objects. If the `dir` is a\n * {@link Directory} object then it will be wrapped in an array. If the `dir` argument is already an array\n * (presumably of {@link Directory} objects) then no further processing is required.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Array} an array of {@link Directory} objects\n */\n initDirs(dir) {\n return splitList(dir).map( dir => fsDir(dir) );\n }\n\n /**\n * Internal method to return an array of the directories in the `dirs` argument passed to the constructor that\n * actually exist in the filesystem. The checks to determine if the directories exists are only carried\n * out the first time the method is called. Subsequent calls will return the cached value stored in\n * `this.state.dirsExist`.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirs() {\n return this.state.dirsExist\n || ( this.state.dirsExist = await this.dirsExist() );\n }\n\n /**\n * Internal method to determine which of the directories in the `dirs` argument passed to the constructor\n * actually exist in the filesystem.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirsExist() {\n const dirs = this.state.dirs;\n const exists = await Promise.all(\n dirs.map( d => d.exists() )\n );\n return dirs.filter((value, index) => exists[index]);\n }\n}\n\nexport default DirPath","import { DirPath } from './Filesystem/DirPath.js';\nimport { splitList } from './Utils/Text.js'\nimport { doNothing, fail } from './Utils/Misc.js';\nimport { addDebug } from './Utils/Debug.js';\n\nconst defaults = {\n codecs: ['yaml', 'json'],\n jsExt: ['js', 'mjs'],\n};\n\n/**\n * The Config class implements an object which can load configuration\n * files from a configuration directory. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default) or data files using any\n * of the standard codecs (`.yaml` or `.json` by default).\n */\nexport class Config extends DirPath {\n /**\n * Constructor for Config object.\n * @param {String} dir - one or more directories that contain configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codecs='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n this.state.codecs = splitList(params.codecs),\n this.state.jsExt = splitList(params.jsExt),\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n }\n\n /**\n * Internal method to locate the first config file with one of a number of file extensions.\n * @param {String} uri - base part of filename\n * @param {Array} [exts] - array of possible extensions\n * @param {Function} [makeOptions] - optional function to generate options for a {@link File} object\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async firstFileWithExt(uri, exts, makeOptions=doNothing) {\n const dirs = await this.dirs();\n\n for (let dir of dirs) {\n for (let ext of exts) {\n const path = uri + '.' + ext;\n const file = dir.file(path, makeOptions(uri, ext));\n this.debug('looking for config file: ', file.path());\n if (await file.exists()) {\n this.debug('config file exists: ', file.path());\n return file;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Internal method to locate a Javascript configuration file with one of the `jsExt` extensions (`.js` or `.mjs` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async jsFile(uri) {\n return await this.firstFileWithExt(uri, this.state.jsExt);\n }\n\n /**\n * Internal method to locate a configuration file with one of the `codecs` extensions (`.yaml` or `.json` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async file(uri) {\n return await this.firstFileWithExt(uri, this.state.codecs, (uri, codec) => ({ codec }));\n }\n\n /**\n * Method to fetch configuration data from a file. The file can be a Javascript file which should\n * return the configuration data as the default export, or a YAML (`.yaml`) or JSON (`.json`) file.\n * If the file isn't found then the method returns the `defaults` data if provided, or throws an\n * error if not.\n * @param {String} uri - base part of filename\n * @param {Object} [defaults] - default configuration options to be used if a file isn't found\n * @return {Object} the configuration data loaded from the file\n */\n async config(uri, defaults) {\n // first look for a JS file, e.g. <uri>.js, <uri>.mjs\n const jsFile = await this.jsFile(uri);\n if (jsFile) {\n const load = await import(jsFile.path());\n return load.default;\n }\n // then for a config file with a codec extension, e.g. <uri>.yaml, <uri>.yaml\n const file = await this.file(uri);\n if (file) {\n return await file.read();\n }\n return defaults || fail(\"No configuration file for \" + uri);\n }\n}\n\n/**\n * Function to create a new Config object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codecs='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\nexport const config = (dir, options) => new Config(dir, options)\n\nexport default Config\n","import { DirPath } from \"./Filesystem/DirPath.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { fail } from \"./Utils/Misc.js\";\n\nconst defaults = {\n jsExt: 'js mjs',\n}\n\n/**\n * The Library class implements an object which can load Javascript files\n * from one or more library directories. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default)\n */\nexport class Library extends DirPath {\n /**\n * Constructor for Library object.\n * @param {String} dir - one or more directories that contain Javascript libraries\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n const exts = splitList(params.jsExt).map( ext => ext.replace(/^\\./, '') ); // remove leading '.'\n this.state.exts = exts;\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug(\"state: \", this.state)\n }\n\n /**\n * Method to load a Javascript library in one of the library directories and with one of the `jsExt` extensions (`.js` or `.mjs` by default).\n * Returns the exports from the library if found or throws an error if not.\n * @param {String} uri - base part of filename\n * @return {Object} the exports from the loaded libary\n */\n async lib(uri) {\n const dirs = await this.dirs();\n const exts = this.state.exts;\n for (let dir of dirs) {\n for (let ext of exts) {\n const file = dir.file(uri + '.' + ext);\n this.debug('looking for module %s as', uri, file.path());\n const exists = await file.exists();\n if (exists) {\n const load = await import(file.path());\n this.debug('loaded %s as', file.path());\n return load;\n }\n }\n }\n fail(\"Library not found: \", uri);\n }\n}\n\n/**\n * Function to create a new Library object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\nexport const library = (dir, options) => new Library(dir, options);\n\nexport default library;","import { hasValue, fail } from \"./Misc.js\";\nimport { joinListOr, splitList } from \"./Text.js\";\n\n/**\n * Assert that a parameter object contains an item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {String} name - parameter that must be included\n * @return {any} the parameter value\n * @throws {Error} if the parameter is not defined or null\n * @example\n * const foo = requiredParam({ foo: 10 }, 'foo');\n */\nexport function requiredParam(params={}, name) {\n const value = params[name];\n if (hasValue(value)) {\n return value;\n }\n else {\n fail(\"Missing value for required parameter: \", name);\n }\n}\n\n/**\n * Assert that a parameter object contains all specified item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters that must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = requiredParams({ foo: 10, bar: 20 }, 'foo bar');\n */\nexport function requiredParams(params={}, names) {\n return splitList(names).map( name => requiredParam(params, name) );\n}\n\n/**\n * An alias for {@link requiredParams} for people who don't like typing long names (and for symmetry with {@link anyParams}))\n */\nexport const allParams=requiredParams;\n\n/**\n * Assert that a parameter object contains any of the specified items with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters of which at least one must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = anyParams({ foo: 10, wiz: 99 }, 'foo bar');\n */\nexport function anyParams(params, names) {\n let found = false;\n const nlist = splitList(names);\n const values = nlist.map(\n name => {\n const value = params[name];\n if (hasValue(value)) {\n found = true;\n }\n return value;\n }\n );\n return found\n ? values\n : fail(\"Missing value for one of: \", joinListOr(nlist));\n}\n","import { dir as fsDir } from \"./Filesystem/Directory.js\";\nimport { fail, hasValue } from \"./Utils/Misc.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { Config } from \"./Config.js\";\nimport { Library } from \"./Library.js\";\n\nconst defaults = {\n library: {\n dir: 'lib library src components',\n },\n config: {\n dir: 'config',\n }\n}\nexport class Workspace {\n constructor(dir, options={}) {\n const rootDir = fsDir(dir);\n const cfgDir = rootDir.dir(options.config?.dir || defaults.config.dir);\n const cfgOpts = { ...defaults.config, ...(options.config||{}) };\n const config = new Config(cfgDir, cfgOpts);\n const libDirs = splitList(options.library?.dir || defaults.library.dir).map( dir => rootDir.dir(dir) );\n const libOpts = { ...defaults.library, ...(options.library||{}) };\n const library = new Library(libDirs, libOpts);\n\n this.state = {\n rootDir,\n config,\n library\n }\n\n // console.log('options: ', options);\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug('root dir: ', rootDir.path());\n this.debug('config dir: ', cfgDir.path());\n this.debug('libDirs: ', libDirs);\n this.debug('libOpts: ', libOpts);\n }\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.rootDir.dir(path, options)\n : this.state.rootDir;\n }\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return this.state.rootDir.file(path, options)\n }\n read(path, options) {\n this.debug(\"read(%s, %o)\", path, options);\n return this.file(path, options).read();\n }\n write(path, data, options) {\n this.debug(\"write(%s, %o, %o)\", path, data, options);\n return this.file(path, options).write(data);\n }\n configDir(path, options) {\n this.debug(\"configDir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.configDir(path, options)\n : this.state.configDir;\n }\n async config(uri, defaults) {\n this.debug(\"config(%s, %o)\", uri, defaults);\n return hasValue(uri)\n ? this.state.config.config(uri, defaults)\n : this.state.config;\n }\n async lib(uri) {\n return this.state.library.lib(uri);\n }\n async component(uri, props) {\n const config = await this.config(uri, {});\n const lib = await this.lib(config.component?.library || uri);\n const exp = config.component?.export || 'default';\n const compcls = lib[exp] || fail(\"No '\", exp, \"' export from component library: \", uri);\n const comp = new compcls(this, { ...config, ...props });\n // this.debug(\"created component \", uri)\n return comp;\n }\n}\n\nexport const workspace = (dir, options) => new Workspace(dir, options);\n\nexport default Workspace;"],"names":["isString","value","isArray","Array","isFunction","isObject","isNull","isUndefined","hasValue","haveValue","values","every","noValue","fail","message","Error","join","rethrow","error","doNothing","ANSIColors","reset","bold","bright","dark","black","red","green","yellow","blue","magenta","cyan","grey","white","fg","bg","escapeCode","color","base","codes","pair","split","hue","pop","code","push","length","shade","shift","Debugger","enabled","prefix","format","args","console","log","colors","col","escapes","escape","bind","addDebug","obj","debug","Component","constructor","workspace","props","this","debugPrefix","debugColor","initComponent","codecs","json","encode","data","JSON","stringify","decode","text","parse","yaml","dump","load","codec","name","toLowerCase","defaultOptions","encoding","Path","path","options","state","relativePath","parts","async","stat","stats","unstat","undefined","File","directory","dir","dirname","read","opts","file","readFile","then","write","writeFile","rm","Directory","parent","readdir","isEmpty","exists","notEmpty","mkdir","empty","rmdir","create","recursive","destroy","force","cwd","process","bin","url","replace","splitList","joinList","array","joint","lastJoint","copy","last","joinListAnd","joinListOr","capitalise","word","charAt","toUpperCase","slice","snakeToStudly","snake","map","segment","snakeToCamel","i","n","DirPath","dirs","initDirs","fsDir","dirsExist","Promise","all","d","filter","index","defaults","jsExt","Config","super","params","uri","exts","makeOptions","ext","firstFileWithExt","jsFile","import","default","config","Library","library","requiredParam","requiredParams","names","allParams","anyParams","found","nlist","Workspace","rootDir","cfgDir","cfgOpts","libDirs","libOpts","configDir","lib","component","exp","export"],"mappings":"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"}
1
+ {"version":3,"file":"badger.esm.js","sources":["../src/Badger/Utils/Misc.js","../src/Badger/Utils/Color.js","../src/Badger/Utils/Debug.js","../src/Badger/Component.js","../src/Badger/Codecs/Json.js","../src/Badger/Codecs/index.js","../src/Badger/Codecs/Yaml.js","../src/Badger/Filesystem/Path.js","../src/Badger/Filesystem/File.js","../src/Badger/Filesystem/Directory.js","../src/Badger/Utils/Text.js","../src/Badger/Filesystem/DirPath.js","../src/Badger/Utils/DataPath.js","../src/Badger/Config.js","../src/Badger/Library.js","../src/Badger/Utils/Params.js","../src/Badger/Workspace.js"],"sourcesContent":["/**\n * Determines if a value is a string\n * @param {String} value - value to test\n * @return {Boolean} true if `value` is a string or false if not\n */\nexport function isString(value) {\n return typeof value === 'string';\n}\n\n/**\n * Determines if a value is an array\n * @param {Array} value - value to test\n * @return {Boolean} true if `value` is an Array or false if not\n */\nexport function isArray(value) {\n return Array.isArray(value);\n}\n\n/**\n * Determines if a value is a Function\n * @param {Function} value - value to test\n * @return {Boolean} true if `value` is a Function or false if not\n */\nexport function isFunction(value) {\n return typeof value === 'function'\n}\n\n/**\n * Determines if a value is an Object (but not an Array)\n * @param {Object} value - value to test\n * @return {Boolean} true if `value` is an Object or false if not\n */\nexport function isObject(value) {\n return typeof value === \"object\"\n && ! isArray(value)\n && ! isNull(value);\n}\n\n/**\n * Determines if a value is `undefined`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or false if not\n */\nexport function isUndefined(value) {\n return typeof value === 'undefined';\n}\n\n/**\n * Determines if a value is `null`\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `null` or false if not\n */\nexport function isNull(value) {\n return value === null;\n}\n\n/**\n * Determines if a value is defined and not null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is not `undefined` or `null`\n */\nexport function hasValue(value) {\n return ! (isUndefined(value) || isNull(value));\n}\n\n/**\n * Determines if all values are defined and not null\n * @param {any[]} values - values to test\n * @return {Boolean} true if all values are not `undefined` or `null`\n */\nexport function haveValue(...values) {\n return values.every( value => hasValue(value) );\n}\n\n/**\n * Determines if a value is undefined or null\n * @param {any} value - value to test\n * @return {Boolean} true if `value` is `undefined` or `null`\n */\nexport function noValue(value) {\n return ! hasValue(value);\n}\n\n/**\n * Throws a new Error object\n * @param {String[]} message - error message string(s)\n * @throws {Error}\n */\nexport function fail(...message) {\n throw new Error(message.join(''));\n}\n\n/**\n * Re-throw an existing Error object\n * @param {Error} error - error object\n * @throws {Error}\n */\nexport function rethrow(error) {\n throw error;\n}\n\n/**\n * Do nothing. Nothing at all.\n */\nexport function doNothing() {\n // speak again Cordelia\n}","import { isObject } from \"./Misc.js\";\n\nconst ANSIStart = '\\u001B[';\nconst ANSIEnd = 'm';\nconst ANSIColors = {\n reset: 0,\n bold: 1,\n bright: 1,\n dark: 2,\n black: 0,\n red: 1,\n green: 2,\n yellow: 3,\n blue: 4,\n magenta: 5,\n cyan: 6,\n grey: 7,\n white: 8,\n fg: 30,\n bg: 40,\n};\n\n/**\n * Returns an ANSI escape code for a color string. This can be a single color\n * name, e.g. `red`, `green`, etc., or a color prefixed with `bright` or `dark`,\n * e.g. `bright red`, `dark green`, etc. An optional section argument can be\n * set to `fg` (default) to set a foreground color or `bg` for a background color.\n * @param {String} color - color name with optional modifier prefix\n * @param {String} [base='fg'] - `fg` or `bg` to set foreground or background color respectively\n * @return {String} ANSI escape code string\n * @example\n * const str = escapeCode('red')\n * @example\n * const str = escapeCode('bright red')\n * @example\n * const str = escapeCode('bright red', 'bg')\n */\nexport const ANSIescapeCode = (color, base='fg') => {\n let codes = [ ];\n let pair = color.split(/ /, 2);\n const hue = pair.pop();\n const code = (base ? ANSIColors[base] : 0) + ANSIColors[hue];\n codes.push(code);\n if (pair.length) {\n const shade = pair.length ? pair.shift() : 'dark';\n codes.push(ANSIColors[shade])\n }\n // console.log('escapeCode(%s, %s) => ', color, base, codes.join(';'));\n return ANSIStart + codes.join(';') + ANSIEnd;\n}\n\n/**\n * Returns an ANSI escape code for a color string or combination of foreground and\n * background colors.\n * @param {String|Object} colors - either a simple color name or object contain foreground and background colors\n * @param {String} [colors.fg] - foreground color\n * @param {String} [colors.fg] - background color\n * @return {String} ANSI escape code string\n * @example\n * const str = escape('red')\n * @example\n * const str = escape('bright red')\n * @example\n * const str = escape({ fg: 'bright yellow', bg: 'blue' })\n */\nexport const ANSIescape = (colors={}) => {\n const col = isObject(colors) ? colors : { fg: colors };\n let escapes = [ ];\n if (col.bg) {\n escapes.push(ANSIescapeCode(col.bg, 'bg'));\n }\n if (col.fg) {\n escapes.push(ANSIescapeCode(col.fg, 'fg'));\n }\n return escapes.join('');\n}\n\n/**\n * Returns an ANSI escape code to reset all colors.\n * @return {String} ANSI escape reset string\n */\nexport const ANSIreset = () => ANSIescapeCode('reset', false)\n\n","import { ANSIescape, ANSIreset } from './Color.js'\nimport { doNothing } from './Misc.js';\n\n/**\n * Returns a debugging function which is enabled by the first `enabled` argument.\n * If this is `false` then it returns a function which does nothing. If it is\n * true then it returns a function that forwards all arguments to `console.log`.\n * An optional `prefix` be be specified to prefix each debugging line. The\n * optional third argument `color` can be used to specify a color for the prefix.\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @return {Function} a debugging function\n * @example\n * const debug = Debugger(true)\n * @example\n * const debug = Debugger(true, 'Debug > ')\n * @example\n * const debug = Debugger(true, 'Debug > ', 'blue')\n * @example\n * const debug = Debugger(true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function Debugger(enabled, prefix='', color) {\n return enabled\n ? prefix\n ? (format, ...args) =>\n console.log(\n '%s' + prefix + '%s' + format,\n color ? ANSIescape(color) : '',\n ANSIreset(),\n ...args,\n )\n : console.log.bind(console)\n : doNothing;\n}\n\n/**\n * Creates a debugging function via {@link Debugger} and attaches it to the object\n * passed as the first argument as the `debug` function.\n * @param {Object} obj - the object to receive the `debug` function\n * @param {Boolean} enabled - is debugging enabled?\n * @param {String} [prefix] - optional prefix for debugging messages\n * @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})\n * @param {String} [color.fg] - foreground color\n * @param {String} [color.bg] - background color\n * @example\n * const debug = addDebug(myObject, true)\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', 'blue')\n * @example\n * const debug = addDebug(myObject, true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })\n */\nexport function addDebug(obj, enabled, prefix='', color) {\n obj.debug = Debugger(enabled, prefix, color);\n}\n","import { addDebug } from \"./Utils/Debug.js\";\n\nexport class Component {\n constructor(workspace, props={}) {\n this.workspace = workspace;\n this.props = props;\n addDebug(this, props.debug, props.debugPrefix, props.debugColor);\n this.initComponent(props);\n }\n initComponent() {\n // stub for subclasses\n }\n}\n\nexport default Component","/**\n * Function to encode JSON\n * @param {Object} data - The data to encode as JSON text\n * @return {String} a JSON encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nconst encode = data => JSON.stringify(data);\n\n/**\n * Function to decode JSON\n * @param {String} text - The JSON text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"{ message: 'Hello World' }\")\n */\nconst decode = text => JSON.parse(text);\n\n/**\n * An object containing the JSON `encode` and `decode` functions\n */\nexport const jsonCodec = { encode, decode };\n\nexport default jsonCodec\n","import json from './Json.js'\nimport yaml from './Yaml.js'\n\n/**\n * Codecs provide a consistent encode()/decode() interface for serialising\n * and de-serialising data. This standard naming convention makes it possible\n * for the ../Filesystem/File.js module to support a \"codec\" option for\n * files. When this option is set the file.read() and file.write() methods\n * automatically handle the translation to and from the serialised format\n * using a codec object returned by the codec() function below. The codec\n * name can be specified in any case, e.g. \"Yaml\", \"YAML\", \"yaml\", \"YaML\",\n * etc., and it will be converted to lower case.\n */\n\n/**\n * Lookup table for codecs\n */\nexport const codecs = {\n json, yaml\n};\n\n/**\n * Function to fetch a codec\n * @param {string} name - The title of the code, in any case, e.g. \"yaml\", \"YAML\", \"Yaml\"\n */\nexport const codec = name => codecs[\n name.toLowerCase()\n];\n\nexport default codecs\n","// simple wrapper around JSON load/dump\nimport yaml from 'js-yaml';\n\n/**\n * Function to encode YAML\n * @param {Object} data - The data to encode as YAML text\n * @return {String} a YAML encoded string\n * @example\n * encode({ message: 'Hello World' })\n */\nconst encode = data => yaml.dump(data);\n\n/**\n * Function to decode YAML\n * @param {String} text - The YAML text to decode\n * @return {Object|Array} the decoded object or array\n * @example\n * decode(\"message: Hello World\")\n */\nconst decode = text => yaml.load(text);\n\n/**\n * An object containing the YAML `encode` and `decode` functions\n */\nexport const yamlCodec = { encode, decode };\n\nexport default yamlCodec\n","import path from 'node:path';\nimport { stat } from 'node:fs/promises'\nimport { rethrow } from '../Utils/Misc.js';\nimport { addDebug } from '../Utils/Debug.js';\n\nconst defaultOptions = {\n encoding: 'utf8'\n}\n\n/**\n * The Path class implements a base class for the {@link File} and {@link Directory}\n * classes. It implements the common functionality for representing a filesystem path.\n */\nexport class Path {\n /**\n * Constructor for filesystem paths.\n * @param {string} path - file path\n * @param {Object} [options] - configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Path} object\n */\n constructor(path, options={}) {\n // allow path/file/directory to be constructed from an existing object\n if (path instanceof Path) {\n path = path.path();\n }\n this.state = { path, options: { ...defaultOptions, ...options } };\n addDebug(this, options.debug, options.debugPrefix || 'Path', options.debugColor);\n }\n\n /**\n * Accessor method to return the filesystem path.\n * @return {String} the filesystem path\n */\n path() {\n return this.state.path;\n }\n\n /**\n * Create a path relative to the current path.\n * @param {String[]} parts - part(s) of the filesystem path\n * @return {String} the new path\n * @example\n * const p = new Path('/path/to/here')\n * const q = p.relativePath('there') // -> /path/to/here/there\n * const r = p.relativePath('and', 'there') // -> /path/to/here/and/there\n */\n relativePath(...parts) {\n return path.join(this.state.path, ...parts);\n }\n\n /**\n * Internal method to merge any options with the pre-defined options passed to the\n * constructor. Options passed as arguments will take precedence.\n * @param {Object} options - new options\n * @return {Object} the merged options\n * @example\n * const p = new Path('/path/to/here', { option1: 'hello' })\n * const q = p.options({ option2: 'world' }) // -> { option1: 'hello', options2: 'world' }\n */\n options(options={}) {\n return { ...this.state.options, ...options };\n }\n\n /**\n * Method to assert that the path exists.\n * @return {Promise} fulfills with `true` if the path exists or rejects if the path doesn't\n * @example\n * const p = new Path('/path/to/here')\n * p.exists()\n * .then( console.log('path exists') )\n * .catch( console.log('path does not exist') )\n */\n async exists() {\n try {\n await this.stat();\n return true;\n }\n catch (error) {\n return error.code === 'ENOENT'\n ? false\n : rethrow(error);\n }\n }\n\n /**\n * Method to fetch stats for the path. Uses the `stat` function from `node:fs/promises`.\n * Stats are cached internally (subject to change)\n * @return {Promise} fulfills with path stats returned from the `stat` function\n * @example\n * const p = new Path('/path/to/here')\n * p.stat()\n * .then( stats => console.log('path stats:', stats) )\n * .catch( console.log('path does not exist') )\n */\n async stat() {\n const stats = await stat(this.state.path);\n return this.state.stats = stats;\n }\n\n /**\n * Method to clear internal cache of path stats (subject to change)\n */\n unstat() {\n this.state.stats = undefined;\n return this;\n }\n}\n\nexport default Path\n","import path from 'node:path'\nimport Path from './Path.js'\nimport { dir } from './Directory.js'\nimport { codec } from '../Codecs/index.js'\nimport { readFile, writeFile, rm } from 'node:fs/promises'\n\n/**\n * The File class implements a wrapper around a filesystem\n * file.\n */\nexport class File extends Path {\n /**\n * Returns a new {@link Directory} object for the parent directory of the file\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n directory(options) {\n return dir(path.dirname(this.state.path), options);\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the parent {@link Directory} object\n */\n dir(...args) {\n return this.directory(...args);\n }\n\n /**\n * Reads the file content. If a `codec` has been specified then the content is decoded.\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {String|Object} the file content\n * @example\n * const text = file('myfile.txt').read();\n * @example\n * const data = file('myfile.json', { codec: 'json' }).read();\n * @example\n * const data = file('myfile.json').read({ codec: 'json' });\n */\n read(options) {\n const opts = this.options(options);\n const file = readFile(this.state.path, opts);\n return opts.codec\n ? file.then(text => codec(opts.codec).decode(text))\n : file;\n }\n\n /**\n * Writes the file content. If a `codec` has been specified then the content will be encoded.\n * @param {String|Object} data - directory configuration options\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @example\n * file('myfile.txt').write('Hello World');\n * @example\n * file('myfile.json', { codec: 'json' }).write({ message: 'Hello World' });\n * @example\n * file('myfile.json').write({ message: 'Hello World' }, { codec: 'json' });\n */\n write(data, options) {\n const opts = this.options(options);\n const text = opts.codec\n ? codec(opts.codec).encode(data)\n : data;\n return writeFile(this.state.path, text, opts).then( () => this );\n }\n\n async delete(options) {\n await rm(this.state.path, options);\n return this;\n }\n}\n\n/**\n * Function to create a new {@link File} object for a file\n * @param {String} path - file path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link File} object\n */\nexport const file = (path, options) => {\n return new File(path, options);\n}\n\nexport default File\n","import process from 'node:process';\nimport path from 'node:path';\nimport Path from './Path.js'\nimport { file } from './File.js'\nimport { fail } from '../Utils/Misc.js';\nimport { rm, mkdir, rmdir, readdir } from 'node:fs/promises'\n\n/**\n * The Directory class implements a wrapper around a filesystem\n * directory.\n */\nexport class Directory extends Path {\n /**\n * Fetch a new {@link File} object for a file in the directory.\n * @param {string} path - file path\n * @param {Object} [options] - file configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link File} object\n */\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return file(this.relativePath(path), this.options(options));\n }\n\n /**\n * Fetch a new {@link Directory} object for a sub-directory in the directory.\n * @param {string} path - directory path\n * @param {Object} [options] - directory configuration options\n * @param {String} [options.codec] - codec for encoding/decoding file data\n * @return {Object} the {@link Directory} object\n */\n directory(path, options) {\n this.debug(\"directory(%s, %o)\", path, options);\n return dir(this.relativePath(path), this.options(options));\n }\n\n /**\n * An alias for the {@link directory} method for lazy people\n * @return {Object} the {@link Directory} object\n */\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return this.directory(path, options);\n }\n\n /**\n * Returns a new {@link Directory} object for the parent directory\n * @param {Object} [options] - directory configuration options\n * @param {Boolean} [options.codec] - codec for encoding/decoding file data\n * @return {Object} a {@link Directory} object for the parent\n */\n parent(options) {\n this.debug(\"parent()\");\n return this.directory('..', options);\n }\n\n /**\n * Returns the names of the files and sub-directories in the directory\n * @return {Promise} fulfills with an array of the file and directory names\n */\n async read() {\n this.debug(\"read()\");\n return await readdir(this.path());\n }\n\n /**\n * Determines if the directory is empty.\n * @return {Promise} fulfills with a boolean value true (empty) or false (not empty).\n */\n async isEmpty() {\n this.debug(\"isEmpty()\");\n const entries = await this.read();\n return entries.length === 0;\n }\n\n /**\n * Determines if the directory is not empty.\n * @return {Promise} fulfills with a boolean value true (not empty) or false (empty).\n */\n async notEmpty() {\n this.debug(\"notEmpty()\");\n const empty = await this.isEmpty();\n return !empty;\n }\n\n /**\n * Empty the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.force] - force removal of files and directories\n * @param {Boolean} [options.recursive] - recursively empty and delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async empty(options={}) {\n this.debug(\"empty(%o)\", options);\n if (await this.exists() && await this.notEmpty()) {\n await rm(this.path(), options);\n }\n return this;\n }\n\n /**\n * Make the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive] - create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mkdir(options={}) {\n this.debug(\"mkdir(%o)\", options);\n const exists = await this.exists();\n if (! exists) {\n await mkdir(this.path(), options);\n }\n return this;\n }\n\n /**\n * Remove the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty] - delete items in directory\n * @param {Boolean} [options.force] - force delete files and directories\n * @param {Boolean} [options.recursive] - recursively delete sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async rmdir(options={}) {\n this.debug(\"rmdir(%o)\", options);\n if (options.empty) {\n await this.empty(options);\n }\n if (await this.exists()) {\n await rmdir(this.path());\n }\n return this;\n }\n\n /**\n * Create the directory and any intermediate directories.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.recursive=true] - recursively create intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n create(options={ recursive: true }) {\n this.debug(\"create(%o)\", options);\n return this.mkdir(options);\n }\n\n /**\n * Empty and delete the directory.\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.empty=true] - empty directory of any files and sub-directories\n * @param {Boolean} [options.recursive=true] - recursively delete sub-directories\n * @param {Boolean} [options.force=true] - force deletion of files and sub-directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n destroy(options={ empty: true, recursive: true, force: true }) {\n this.debug(\"destroy(%o)\", options);\n return this.rmdir(options);\n }\n\n /**\n * Assert that a directory exists and optionally create it\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.create] - create the directory and any intermediate directories if it doesn't exist - equivalent to adding `mkdir` and `recursive` options or calling {@link create}\n * @param {Boolean} [options.mkdir] - create the directory, add the `recursive` option to create intermediate directories - equivalent to calling {@link mkdir}\n * @param {Boolean} [options.recursive] - when used with `mkdir`, creates any intermediate directories\n * @return {Promise} fulfills to the {@link Directory} object\n */\n async mustExist(options={}) {\n this.debug(\"mustExist(%o)\", options);\n if (await this.exists()) {\n return this;\n }\n if (options.mkdir) {\n return this.mkdir(options);\n }\n if (options.create) {\n return this.create();\n }\n fail(\"Directory does not exist: \", this.path());\n }\n}\n\n/**\n * Function to create a new {@link Directory} object\n * @param {string} path - directory path\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const dir = (path, options) => {\n return new Directory(path, options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the current working directory\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const cwd = options => {\n return dir(process.cwd(), options);\n}\n\n/**\n * Function to create a new {@link Directory} object for the directory of a JS source file\n * @param {string} url - module url - from `import.meta.url`\n * @param {Object} [options] - configuration options\n * @param {Boolean} [options.codec] - a codec for encoding/decoding files\n * @return {Object} the {@link Directory} object\n */\nexport const bin = (url, options) => {\n return dir(\n path.dirname(url.replace(/^file:\\/\\//, '')),\n options\n );\n}\n\nexport default Directory\n","import { isString, isArray, noValue } from \"./Misc.js\";\n\n/**\n * Split a comma/whitespace delimited string into an Array\n * @param {String} [value] - string to split\n * @return {Array} array of split strings\n * @example\n * const strings = splitList('one two three')\n * @example\n * const strings = splitList('one,two,three')\n * @example\n * const strings = splitList('one, two, three')\n */\nexport function splitList(value) {\n if (noValue(value)) {\n return [ ];\n }\n else if (isString(value)) {\n return value.length\n ? value.split(/,\\s*|\\s+/)\n : [ ]\n }\n else if (isArray(value)) {\n return value;\n }\n return [value];\n}\n\n/**\n * Join an Array into a single string\n * @param {Array} [array] - array to join\n * @param {String} [joint=' '] - delimiter to join strings\n * @param {String} [lastJoint=joint] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinList(['one', 'two', 'three']); // one two three\n * @example\n * joinList(['one', 'two', 'three'], ', '); // one, two, three\n * @example\n * joinList(['one', 'two', 'three'], ', ', ' and '); // one, two and three\n */\nexport function joinList(array, joint=' ', lastJoint=joint) {\n let copy = [...array];\n const last = copy.pop();\n return copy.length\n ? [copy.join(joint), last].join(lastJoint)\n : last;\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` and ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' and '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListAnd(['one', 'two', 'three']); // one, two and three\n */\nexport function joinListAnd(array, joint=', ', lastJoint=' and ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Join an Array into a single string using commas for delimiters and ` or ` for the final item\n * @param {Array} [array] - array to join\n * @param {String} [joint=', '] - delimiter to join strings\n * @param {String} [lastJoint=' or '] - delimiter for final item\n * @return {String} joined string\n * @example\n * joinListOr(['one', 'two', 'three']); // one, two or three\n */\nexport function joinListOr(array, joint=', ', lastJoint=' or ') {\n return joinList(array, joint, lastJoint);\n}\n\n/**\n * Capitalise a string by converting the first character to upper case and other characters to lower case\n * @param {String} [word] - word to capitalise\n * @return {String} capitalised string\n * @example\n * capitalise('badger'); // Badger\n * @example\n * capitalise('BADGER'); // Badger\n */\nexport function capitalise(word) {\n return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();\n}\n\n/**\n * Convert a snake case string to studly caps\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToStudly('happy_badger_dance'); // HappyBadgerDance\n * @example\n * snakeToStudly('happy_badger/dance'); // HappyBadger/Dance\n */\nexport function snakeToStudly(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to FooBar\n segment => segment.split('_').map(capitalise).join('')\n ).join('/');\n}\n\n/**\n * Convert a snake case string to camel case\n * @param {String} [snake] - word to capitalise\n * @return {String} capitalised string\n * @example\n * snakeToCamel('happy_badger_dance'); // happyBadgerDance\n * @example\n * snakeToCamel('happy_badger/dance'); // happyBadger/dance\n */\nexport function snakeToCamel(snake) {\n return snake.split('/').map(\n // each segment can be like foo_bar which we convert to fooBar\n segment => segment.split('_').map((i, n) => n ? capitalise(i) : i).join('')\n ).join('/');\n}\n","import { dir as fsDir } from \"./Directory.js\";\nimport { splitList } from \"../Utils/Text.js\";\n\n/**\n * The DirPath class implements a base class for objects that\n * can search one or more directories.\n */\nexport class DirPath {\n /**\n * Constructor for filesystem paths.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Object} the {@link DirPath} object\n */\n constructor(dir) {\n const dirs = this.initDirs(dir);\n this.state = {\n dirs\n }\n }\n\n /**\n * Internal method to initialise the directories. If the `dir` argument is a string then it will be split on\n * commas and/or whitespace and converted to an array of {@link Directory} objects. If the `dir` is a\n * {@link Directory} object then it will be wrapped in an array. If the `dir` argument is already an array\n * (presumably of {@link Directory} objects) then no further processing is required.\n * @param {String|Array} dir - comma/whitespace delimited string containing directories, or a {@link Directory} object or Array of {@link Directory} objects\n * @return {Array} an array of {@link Directory} objects\n */\n initDirs(dir) {\n return splitList(dir).map( dir => fsDir(dir) );\n }\n\n /**\n * Internal method to return an array of the directories in the `dirs` argument passed to the constructor that\n * actually exist in the filesystem. The checks to determine if the directories exists are only carried\n * out the first time the method is called. Subsequent calls will return the cached value stored in\n * `this.state.dirsExist`.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirs() {\n return this.state.dirsExist\n || ( this.state.dirsExist = await this.dirsExist() );\n }\n\n /**\n * Internal method to determine which of the directories in the `dirs` argument passed to the constructor\n * actually exist in the filesystem.\n * @return {Array} an array of {@link Directory} objects that exist\n */\n async dirsExist() {\n const dirs = this.state.dirs;\n const exists = await Promise.all(\n dirs.map( d => d.exists() )\n );\n return dirs.filter((value, index) => exists[index]);\n }\n}\n\nexport default DirPath","import { fail, hasValue, isArray, noValue } from \"./Misc.js\";\n\nconst quotedEscapes = {\n b: \"\\b\",\n f: \"\\f\",\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n v: \"\\v\",\n '\"': '\"',\n \"'\": \"'\",\n '\\\\': '\\\\',\n}\n\nexport const matchDoubleQuotedString = string => {\n const regex = /^\"((?:\\\\[\\\\\"nrt]|.)*?)\"$/\n const match = string.match(regex);\n return match\n ? match[1].replace(/\\\\([\\\\\"bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`)\n : null;\n}\n\nexport const matchSingleQuotedString = string => {\n const regex = /^'((?:\\\\[\\\\']|.)*?)'$/\n const match = string.match(regex);\n return match\n ? match[1].replace(/\\\\([\\\\'bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`)\n : null;\n}\n\nexport const splitDataPath = path => {\n // * match a slash: \\/\n // * match a single quoted string: '...'\n // * match a double quoted string: \"...\"\n // * match anything else: hello world!\n let parts = [ ];\n const regex = /(?:(\\/)|'((?:\\\\[\\\\']|.)*?)'|\"((?:\\\\[\\\\\"nrt]|.)*?)\"|([^/?]+))(\\??)/g;\n // console.log('\\nsplitDataPath [%s]', path);\n const matches = [...path.matchAll(regex)];\n\n matches.map(\n ([ , , single, double, other, optional]) => {\n let part;\n // console.log('match [slash:%s] [single:%s] [double:%s] [other:%s]', slash, single, double, other);\n\n if (single) {\n part = single.replace(/\\\\([\\\\'bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`);\n }\n else if (double) {\n part = double.replace(/\\\\([\\\\\"bfnrtv])/g, (all, one) => quotedEscapes[one] || `\\\\${one}`);\n }\n else if (other) {\n part = other\n }\n if (hasValue(part)) {\n parts.push(optional ? [part, {optional:true}] : part);\n }\n }\n )\n // console.log('MATCHED ', parts);\n\n return parts;\n}\n\n// eslint-disable-next-line no-unused-vars\nexport const dataPath = (data, path) => {\n let root = data;\n let parts = splitDataPath(path);\n let done = [ ];\n // console.log('parts: ', parts);\n\n for (let part of parts) {\n const [word, opts] = isArray(part) ? part : [part, {}];\n root = root[word];\n done.push(word);\n if (noValue(root)) {\n if (opts.optional) {\n return root;\n }\n else {\n fail(\"No value for data at path: \", done.join('/'));\n }\n }\n }\n return root;\n}\n","import { DirPath } from './Filesystem/DirPath.js';\nimport { splitList } from './Utils/Text.js'\nimport { doNothing, fail } from './Utils/Misc.js';\nimport { addDebug } from './Utils/Debug.js';\nimport { dataPath } from '../Badger/Utils/DataPath.js';\n\nconst defaults = {\n codec: ['yaml', 'json'],\n jsExt: ['js', 'mjs'],\n};\n\n/**\n * The Config class implements an object which can load configuration\n * files from a configuration directory. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default) or data files using any\n * of the standard codecs (`.yaml` or `.json` by default).\n */\nexport class Config extends DirPath {\n /**\n * Constructor for Config object.\n * @param {String} dir - one or more directories that contain configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codec='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n this.state.codec = splitList(params.codec),\n this.state.jsExt = splitList(params.jsExt),\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n }\n\n /**\n * Internal method to locate the first config file with one of a number of file extensions.\n * @param {String} uri - base part of filename\n * @param {Array} [exts] - array of possible extensions\n * @param {Function} [makeOptions] - optional function to generate options for a {@link File} object\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async firstFileWithExt(uri, exts, makeOptions=doNothing) {\n const dirs = await this.dirs();\n\n for (let dir of dirs) {\n for (let ext of exts) {\n const path = uri + '.' + ext;\n const file = dir.file(path, makeOptions(uri, ext));\n this.debug('looking for config file: ', file.path());\n if (await file.exists()) {\n this.debug('config file exists: ', file.path());\n return file;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Internal method to locate a Javascript configuration file with one of the `jsExt` extensions (`.js` or `.mjs` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async jsFile(uri) {\n return await this.firstFileWithExt(uri, this.state.jsExt);\n }\n\n /**\n * Internal method to locate a configuration file with one of the `codec` extensions (`.yaml` or `.json` by default)\n * @param {String} uri - base part of filename\n * @return {Object} the {@link File} object if it exists or `undefined` if not\n */\n async file(uri) {\n return await this.firstFileWithExt(uri, this.state.codec, (uri, codec) => ({ codec }));\n }\n\n /**\n * Method to fetch configuration data from a file. The file can be a Javascript file which should\n * return the configuration data as the default export, or a YAML (`.yaml`) or JSON (`.json`) file.\n * If the file isn't found then the method returns the `defaults` data if provided, or throws an\n * error if not.\n * @param {String} uri - base part of filename\n * @param {Object} [defaults] - default configuration options to be used if a file isn't found\n * @return {Object} the configuration data loaded from the file\n */\n async config(uri, defaults) {\n const [base, fragment] = uri.split('#', 2);\n let jsFile, file, data;\n\n // first look for a JS file, e.g. <uri>.js, <uri>.mjs\n if ((jsFile = await this.jsFile(base))) {\n data = await import(jsFile.path());\n }\n // then for a config file with a codec extension, e.g. <uri>.yaml, <uri>.yaml\n else if ((file = await this.file(base))) {\n data = await file.read();\n }\n // failing that use any default value\n else if (defaults) {\n data = defaults;\n }\n // anything else is a big pile of fail\n else {\n return fail(\"No configuration file for \" + base);\n }\n // resolve any data path in a #fragment\n return fragment\n ? dataPath(data, fragment)\n : data;\n }\n}\n\n/**\n * Function to create a new Config object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @param {Array|String} [options.codec='yaml json'] - Array or comma/whitespace delimited string of codec names\n * @return {Object} the Config object\n */\nexport const config = (dir, options) => new Config(dir, options)\n\nexport default Config\n","import { DirPath } from \"./Filesystem/DirPath.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { fail } from \"./Utils/Misc.js\";\nimport { dataPath } from \"./Utils/DataPath.js\";\n\nconst defaults = {\n jsExt: 'js mjs',\n}\n\n/**\n * The Library class implements an object which can load Javascript files\n * from one or more library directories. Files can be Javascript files\n * (with `.js` or `.mjs` extensions by default)\n */\nexport class Library extends DirPath {\n /**\n * Constructor for Library object.\n * @param {String} dir - one or more directories that contain Javascript libraries\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\n constructor(dir, options={}) {\n super(dir);\n const params = { ...defaults, ...options };\n const exts = splitList(params.jsExt).map( ext => ext.replace(/^\\./, '') ); // remove leading '.'\n this.state.exts = exts;\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug(\"state: \", this.state)\n }\n\n /**\n * Method to load a Javascript library in one of the library directories and with one of the `jsExt` extensions (`.js` or `.mjs` by default).\n * Returns the exports from the library if found or throws an error if not.\n * @param {String} uri - base part of filename\n * @return {Object} the exports from the loaded libary\n */\n async library(uri) {\n const [base, fragment] = uri.split('#', 2);\n const dirs = await this.dirs();\n const exts = this.state.exts;\n for (let dir of dirs) {\n for (let ext of exts) {\n const file = dir.file(base + '.' + ext);\n this.debug('looking for module %s as', base, file.path());\n const exists = await file.exists();\n if (exists) {\n const load = await import(file.path());\n this.debug('loaded %s as', file.path());\n return fragment\n ? dataPath(load, fragment)\n : load;\n }\n }\n }\n fail(\"Library not found: \", uri);\n }\n}\n\n/**\n * Function to create a new Library object\n * @param {String} dir - directory or directories containing configuration files\n * @param {Object} [options] - configuration options\n * @param {Array|String} [options.jsExt='js mjs'] - Array or comma/whitespace delimited string of Javascript file extensions\n * @return {Object} the Library object\n */\nexport const library = (dir, options) => new Library(dir, options);\n\nexport default library;","import { hasValue, fail } from \"./Misc.js\";\nimport { joinListOr, splitList } from \"./Text.js\";\n\n/**\n * Assert that a parameter object contains an item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {String} name - parameter that must be included\n * @return {any} the parameter value\n * @throws {Error} if the parameter is not defined or null\n * @example\n * const foo = requiredParam({ foo: 10 }, 'foo');\n */\nexport function requiredParam(params={}, name) {\n const value = params[name];\n if (hasValue(value)) {\n return value;\n }\n else {\n fail(\"Missing value for required parameter: \", name);\n }\n}\n\n/**\n * Assert that a parameter object contains all specified item with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters that must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = requiredParams({ foo: 10, bar: 20 }, 'foo bar');\n */\nexport function requiredParams(params={}, names) {\n return splitList(names).map( name => requiredParam(params, name) );\n}\n\n/**\n * An alias for {@link requiredParams} for people who don't like typing long names (and for symmetry with {@link anyParams}))\n */\nexport const allParams=requiredParams;\n\n/**\n * Assert that a parameter object contains any of the specified items with a defined/non-null value\n * @param {Object} params={} - parameters object\n * @param {Array|String} names - parameters of which at least one must be included, as an Array or whitespace/comma delimited string (see {@link splitList})\n * @return {Array} the parameter values\n * @throws {Error} if any parameter is not defined or null\n * @example\n * const [foo, bar] = anyParams({ foo: 10, wiz: 99 }, 'foo bar');\n */\nexport function anyParams(params, names) {\n let found = false;\n const nlist = splitList(names);\n const values = nlist.map(\n name => {\n const value = params[name];\n if (hasValue(value)) {\n found = true;\n }\n return value;\n }\n );\n return found\n ? values\n : fail(\"Missing value for one of: \", joinListOr(nlist));\n}\n","import { dir as fsDir } from \"./Filesystem/Directory.js\";\nimport { fail, hasValue } from \"./Utils/Misc.js\";\nimport { addDebug } from \"./Utils/Debug.js\";\nimport { splitList } from \"./Utils/Text.js\";\nimport { Config } from \"./Config.js\";\nimport { Library } from \"./Library.js\";\n\nconst defaults = {\n library: {\n dir: 'lib library src components',\n },\n config: {\n dir: 'config',\n }\n}\nexport class Workspace {\n constructor(dir, options={}) {\n const rootDir = fsDir(dir);\n const cfgDir = rootDir.dir(options.config?.dir || defaults.config.dir);\n const cfgOpts = { ...defaults.config, ...(options.config||{}) };\n const config = new Config(cfgDir, cfgOpts);\n const libDirs = splitList(options.library?.dir || defaults.library.dir).map( dir => rootDir.dir(dir) );\n const libOpts = { ...defaults.library, ...(options.library||{}) };\n const library = new Library(libDirs, libOpts);\n\n this.state = {\n rootDir,\n config,\n library\n }\n\n // console.log('options: ', options);\n addDebug(this, options.debug, options.debugPrefix, options.debugColor);\n this.debug('root dir: ', rootDir.path());\n this.debug('config dir: ', cfgDir.path());\n this.debug('libDirs: ', libDirs);\n this.debug('libOpts: ', libOpts);\n }\n dir(path, options) {\n this.debug(\"dir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.rootDir.dir(path, options)\n : this.state.rootDir;\n }\n file(path, options) {\n this.debug(\"file(%s, %o)\", path, options);\n return this.state.rootDir.file(path, options)\n }\n read(path, options) {\n this.debug(\"read(%s, %o)\", path, options);\n return this.file(path, options).read();\n }\n write(path, data, options) {\n this.debug(\"write(%s, %o, %o)\", path, data, options);\n return this.file(path, options).write(data);\n }\n configDir(path, options) {\n this.debug(\"configDir(%s, %o)\", path, options);\n return hasValue(path)\n ? this.state.configDir(path, options)\n : this.state.configDir;\n }\n async config(uri, defaults) {\n this.debug(\"config(%s, %o)\", uri, defaults);\n return hasValue(uri)\n ? this.state.config.config(uri, defaults)\n : this.state.config;\n }\n async library(uri) {\n return this.state.library.library(uri);\n }\n async component(uri, props) {\n const config = await this.config(uri, {});\n const lib = await this.library(config.component?.library || uri);\n const exp = config.component?.export || 'default';\n const compcls = lib[exp] || fail(\"No '\", exp, \"' export from component library: \", uri);\n const comp = new compcls(this, { ...config, ...props });\n // this.debug(\"created component \", uri)\n return comp;\n }\n}\n\nexport const workspace = (dir, options) => new Workspace(dir, options);\n\nexport default Workspace;"],"names":["isString","value","isArray","Array","isFunction","isObject","isNull","isUndefined","hasValue","haveValue","values","every","noValue","fail","message","Error","join","rethrow","error","doNothing","ANSIColors","reset","bold","bright","dark","black","red","green","yellow","blue","magenta","cyan","grey","white","fg","bg","ANSIescapeCode","color","base","codes","pair","split","hue","pop","code","push","length","shade","shift","ANSIescape","colors","col","escapes","ANSIreset","Debugger","enabled","prefix","format","args","console","log","bind","addDebug","obj","debug","Component","constructor","workspace","props","this","debugPrefix","debugColor","initComponent","codecs","json","encode","data","JSON","stringify","decode","text","parse","yaml","dump","load","codec","name","toLowerCase","defaultOptions","encoding","Path","path","options","state","relativePath","parts","async","stat","stats","unstat","undefined","File","directory","dir","dirname","read","opts","file","readFile","then","write","writeFile","rm","Directory","parent","readdir","isEmpty","exists","notEmpty","mkdir","empty","rmdir","create","recursive","destroy","force","cwd","process","bin","url","replace","splitList","joinList","array","joint","lastJoint","copy","last","joinListAnd","joinListOr","capitalise","word","charAt","toUpperCase","slice","snakeToStudly","snake","map","segment","snakeToCamel","i","n","DirPath","dirs","initDirs","fsDir","dirsExist","Promise","all","d","filter","index","quotedEscapes","b","f","r","t","v","matchDoubleQuotedString","string","match","one","matchSingleQuotedString","splitDataPath","matchAll","single","double","other","optional","part","dataPath","root","done","defaults","jsExt","Config","super","params","uri","exts","makeOptions","ext","firstFileWithExt","fragment","jsFile","import","config","Library","library","requiredParam","requiredParams","names","allParams","anyParams","found","nlist","Workspace","rootDir","cfgDir","cfgOpts","libDirs","libOpts","configDir","lib","component","exp","export"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abw/badger",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Component based framework and utility modules",
5
5
  "type": "module",
6
6
  "main": "dist/badger.cjs.js",
@@ -36,6 +36,8 @@
36
36
  "devDependencies": {
37
37
  "@itsjamie/esdoc-cli": "^0.5.0",
38
38
  "@itsjamie/esdoc-core": "^0.5.0",
39
+ "@itsjamie/esdoc-importpath-plugin": "^0.5.0",
40
+ "@itsjamie/esdoc-inject-style-plugin": "^0.5.0",
39
41
  "@itsjamie/esdoc-standard-plugin": "^0.5.0",
40
42
  "@rollup/plugin-commonjs": "^11.0.1",
41
43
  "@rollup/plugin-node-resolve": "^7.1.3",