From bdae5fc19d5ee8118b67c4d0eeff084e70578975 Mon Sep 17 00:00:00 2001 From: svc-cli-bot Date: Mon, 4 Mar 2024 23:02:13 +0000 Subject: [PATCH] Deploy website - based on ad8d0e16991bcf7341ab85fd91511450e0fd3f6e --- 404.html | 4 ++-- assets/js/{03a88bad.62d28b63.js => 03a88bad.58ba0022.js} | 2 +- assets/js/{03abeb31.89aea179.js => 03abeb31.62d31294.js} | 2 +- assets/js/{0b218a01.a5a6a16e.js => 0b218a01.c7ec91a6.js} | 2 +- assets/js/{104cbb75.891f291a.js => 104cbb75.23da78ae.js} | 2 +- assets/js/{19fd9079.626d5720.js => 19fd9079.580d846e.js} | 2 +- assets/js/{1ed4142b.29563194.js => 1ed4142b.e0b1cff1.js} | 2 +- assets/js/{1f61ef73.2c97d45b.js => 1f61ef73.050e594a.js} | 2 +- assets/js/{2486267b.f3aad5aa.js => 2486267b.95b52046.js} | 2 +- assets/js/{258a6413.3eeaaf68.js => 258a6413.fb7ccdd8.js} | 2 +- assets/js/{2a33acc4.d46170c8.js => 2a33acc4.1213b158.js} | 2 +- assets/js/{2f98ad87.07ccdeec.js => 2f98ad87.28a95877.js} | 2 +- assets/js/{3042343a.cb8ecb82.js => 3042343a.6f606eba.js} | 2 +- assets/js/{30d74566.5738672b.js => 30d74566.3e37533e.js} | 2 +- assets/js/{32060389.636715d9.js => 32060389.44959ed9.js} | 2 +- assets/js/{35586d92.eb012dea.js => 35586d92.d74a9192.js} | 2 +- assets/js/{3e452c7e.7eeef943.js => 3e452c7e.f8151866.js} | 2 +- assets/js/{53e18611.7a0136ba.js => 53e18611.ac600542.js} | 2 +- assets/js/{5d5620c4.1f758151.js => 5d5620c4.3f17b57d.js} | 2 +- assets/js/{6de0e435.c31d17e8.js => 6de0e435.ffe363a4.js} | 2 +- assets/js/{6f3bb722.458468c6.js => 6f3bb722.9a353140.js} | 2 +- assets/js/{713bb917.2de4941a.js => 713bb917.ce493d17.js} | 2 +- assets/js/{7bd58895.621b46ec.js => 7bd58895.45570e39.js} | 2 +- assets/js/{82247a8b.0c6962c1.js => 82247a8b.eaab3884.js} | 2 +- assets/js/{8705a681.31d90ccb.js => 8705a681.56669df9.js} | 2 +- assets/js/{935116ff.1384990f.js => 935116ff.5b67c00b.js} | 2 +- assets/js/{958c0a42.85c99996.js => 958c0a42.c6f748e3.js} | 2 +- assets/js/{9eaa546a.37cf75d3.js => 9eaa546a.46c67a2d.js} | 2 +- assets/js/{a92e169d.701f84c9.js => a92e169d.bd0fb0a8.js} | 2 +- assets/js/{a96ec439.3e244ed4.js => a96ec439.0aea02dd.js} | 2 +- assets/js/{b2f554cd.d0fa6f76.js => b2f554cd.8147c378.js} | 2 +- assets/js/{b3cc73c6.e528833c.js => b3cc73c6.d2977a60.js} | 2 +- assets/js/{b4a95747.0a5eacce.js => b4a95747.1e529c97.js} | 2 +- assets/js/{c5890d18.933b9d04.js => c5890d18.dbb7b07c.js} | 2 +- assets/js/{c81fd975.ec148956.js => c81fd975.cd142838.js} | 2 +- assets/js/{c94a68c1.db1aa280.js => c94a68c1.47c94d90.js} | 2 +- assets/js/{d0e73d62.7a23908d.js => d0e73d62.3830f8e4.js} | 2 +- assets/js/{d665a578.052e6995.js => d665a578.03eb317e.js} | 2 +- assets/js/{d9b0bdb4.15d89fe6.js => d9b0bdb4.03a2a904.js} | 2 +- assets/js/{df1cd967.74c1da59.js => df1cd967.ea06b04e.js} | 2 +- assets/js/{e360e27f.f1d2a447.js => e360e27f.17dbfd91.js} | 2 +- assets/js/{e3703649.2f81b37b.js => e3703649.4c80b50d.js} | 2 +- assets/js/{f182954c.026bff16.js => f182954c.264f8346.js} | 2 +- assets/js/{f6c5328e.39ab04ee.js => f6c5328e.36c1c2ed.js} | 2 +- assets/js/{f905d0fe.8522804b.js => f905d0fe.47993f97.js} | 2 +- assets/js/runtime~main.205bf67e.js | 1 - assets/js/runtime~main.62b4fabc.js | 1 + blog/2018/03/20/introducing-oclif/index.html | 4 ++-- blog/2019/02/20/cli-flags-explained/index.html | 4 ++-- blog/2019/10/31/oclif-node-updates/index.html | 4 ++-- blog/2019/12/05/oclif-eslint-migration/index.html | 4 ++-- blog/2020/05/05/introducing-custom-help-classes/index.html | 6 +++--- blog/2020/07/01/pretty-printable-errors/index.html | 4 ++-- blog/2020/08/26/summer-update/index.html | 4 ++-- blog/2021/03/01/introducing-oclif-core/index.html | 4 ++-- blog/2022/01/12/announcing-oclif-v2/index.html | 4 ++-- blog/archive/index.html | 4 ++-- blog/atom.xml | 2 +- blog/index.html | 6 +++--- blog/rss.xml | 2 +- docs/aliases/index.html | 6 +++--- docs/args/index.html | 6 +++--- docs/base_class/index.html | 6 +++--- docs/command_discovery_strategies/index.html | 6 +++--- docs/command_execution/index.html | 6 +++--- docs/commands/index.html | 6 +++--- docs/config/index.html | 6 +++--- docs/debugging/index.html | 6 +++--- docs/error_handling/index.html | 6 +++--- docs/esm/index.html | 6 +++--- docs/examples/index.html | 6 +++--- docs/external_links/index.html | 6 +++--- docs/faqs/index.html | 6 +++--- docs/features/index.html | 6 +++--- docs/feedback/index.html | 6 +++--- docs/flags/index.html | 6 +++--- docs/flexible_taxonomy/index.html | 6 +++--- docs/generator_commands/index.html | 6 +++--- docs/global_flags/index.html | 6 +++--- docs/help_classes/index.html | 6 +++--- docs/hooks/index.html | 6 +++--- docs/how_we_work/index.html | 6 +++--- docs/index.html | 6 +++--- docs/introduction/index.html | 6 +++--- docs/jit_plugins/index.html | 6 +++--- docs/json/index.html | 6 +++--- docs/notifications/index.html | 6 +++--- docs/nsis-installer_customization/index.html | 6 +++--- docs/plugin_loading/index.html | 6 +++--- docs/plugins/index.html | 6 +++--- docs/prompting/index.html | 6 +++--- docs/related_repos/index.html | 6 +++--- docs/releasing/index.html | 6 +++--- docs/running_programmatically/index.html | 6 +++--- docs/single_command_cli/index.html | 6 +++--- docs/spinner/index.html | 6 +++--- docs/table/index.html | 6 +++--- docs/testing/index.html | 6 +++--- docs/themes/index.html | 6 +++--- docs/topic_separator/index.html | 6 +++--- docs/topics/index.html | 6 +++--- index.html | 4 ++-- search/index.html | 4 ++-- 103 files changed, 200 insertions(+), 200 deletions(-) rename assets/js/{03a88bad.62d28b63.js => 03a88bad.58ba0022.js} (97%) rename assets/js/{03abeb31.89aea179.js => 03abeb31.62d31294.js} (98%) rename assets/js/{0b218a01.a5a6a16e.js => 0b218a01.c7ec91a6.js} (97%) rename assets/js/{104cbb75.891f291a.js => 104cbb75.23da78ae.js} (98%) rename assets/js/{19fd9079.626d5720.js => 19fd9079.580d846e.js} (98%) rename assets/js/{1ed4142b.29563194.js => 1ed4142b.e0b1cff1.js} (98%) rename assets/js/{1f61ef73.2c97d45b.js => 1f61ef73.050e594a.js} (99%) rename assets/js/{2486267b.f3aad5aa.js => 2486267b.95b52046.js} (98%) rename assets/js/{258a6413.3eeaaf68.js => 258a6413.fb7ccdd8.js} (96%) rename assets/js/{2a33acc4.d46170c8.js => 2a33acc4.1213b158.js} (98%) rename assets/js/{2f98ad87.07ccdeec.js => 2f98ad87.28a95877.js} (98%) rename assets/js/{3042343a.cb8ecb82.js => 3042343a.6f606eba.js} (99%) rename assets/js/{30d74566.5738672b.js => 30d74566.3e37533e.js} (99%) rename assets/js/{32060389.636715d9.js => 32060389.44959ed9.js} (99%) rename assets/js/{35586d92.eb012dea.js => 35586d92.d74a9192.js} (98%) rename assets/js/{3e452c7e.7eeef943.js => 3e452c7e.f8151866.js} (98%) rename assets/js/{53e18611.7a0136ba.js => 53e18611.ac600542.js} (98%) rename assets/js/{5d5620c4.1f758151.js => 5d5620c4.3f17b57d.js} (99%) rename assets/js/{6de0e435.c31d17e8.js => 6de0e435.ffe363a4.js} (95%) rename assets/js/{6f3bb722.458468c6.js => 6f3bb722.9a353140.js} (99%) rename assets/js/{713bb917.2de4941a.js => 713bb917.ce493d17.js} (99%) rename assets/js/{7bd58895.621b46ec.js => 7bd58895.45570e39.js} (98%) rename assets/js/{82247a8b.0c6962c1.js => 82247a8b.eaab3884.js} (99%) rename assets/js/{8705a681.31d90ccb.js => 8705a681.56669df9.js} (99%) rename assets/js/{935116ff.1384990f.js => 935116ff.5b67c00b.js} (99%) rename assets/js/{958c0a42.85c99996.js => 958c0a42.c6f748e3.js} (95%) rename assets/js/{9eaa546a.37cf75d3.js => 9eaa546a.46c67a2d.js} (99%) rename assets/js/{a92e169d.701f84c9.js => a92e169d.bd0fb0a8.js} (98%) rename assets/js/{a96ec439.3e244ed4.js => a96ec439.0aea02dd.js} (98%) rename assets/js/{b2f554cd.d0fa6f76.js => b2f554cd.8147c378.js} (99%) rename assets/js/{b3cc73c6.e528833c.js => b3cc73c6.d2977a60.js} (99%) rename assets/js/{b4a95747.0a5eacce.js => b4a95747.1e529c97.js} (98%) rename assets/js/{c5890d18.933b9d04.js => c5890d18.dbb7b07c.js} (99%) rename assets/js/{c81fd975.ec148956.js => c81fd975.cd142838.js} (99%) rename assets/js/{c94a68c1.db1aa280.js => c94a68c1.47c94d90.js} (98%) rename assets/js/{d0e73d62.7a23908d.js => d0e73d62.3830f8e4.js} (98%) rename assets/js/{d665a578.052e6995.js => d665a578.03eb317e.js} (98%) rename assets/js/{d9b0bdb4.15d89fe6.js => d9b0bdb4.03a2a904.js} (98%) rename assets/js/{df1cd967.74c1da59.js => df1cd967.ea06b04e.js} (98%) rename assets/js/{e360e27f.f1d2a447.js => e360e27f.17dbfd91.js} (99%) rename assets/js/{e3703649.2f81b37b.js => e3703649.4c80b50d.js} (99%) rename assets/js/{f182954c.026bff16.js => f182954c.264f8346.js} (98%) rename assets/js/{f6c5328e.39ab04ee.js => f6c5328e.36c1c2ed.js} (99%) rename assets/js/{f905d0fe.8522804b.js => f905d0fe.47993f97.js} (98%) delete mode 100644 assets/js/runtime~main.205bf67e.js create mode 100644 assets/js/runtime~main.62b4fabc.js diff --git a/404.html b/404.html index 0e94596c..f1b5a513 100644 --- a/404.html +++ b/404.html @@ -11,13 +11,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/03a88bad.62d28b63.js b/assets/js/03a88bad.58ba0022.js similarity index 97% rename from assets/js/03a88bad.62d28b63.js rename to assets/js/03a88bad.58ba0022.js index 72952e68..fe069df3 100644 --- a/assets/js/03a88bad.62d28b63.js +++ b/assets/js/03a88bad.58ba0022.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6568],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=p(r),d=o,m=s["".concat(l,".").concat(d)]||s[d]||f[d]||a;return r?n.createElement(m,c(c({ref:t},u),{},{components:r})):n.createElement(m,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[s]="string"==typeof e?e:o,c[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>p,toc:()=>s});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),c=["components"],i={},l=void 0,p={unversionedId:"index",id:"index",title:"index",description:"",source:"@site/../docs/index.md",sourceDirName:".",slug:"/",permalink:"/docs/",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/index.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{}},u={},s=[],f={toc:s},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,c);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("meta",{"http-equiv":"refresh",content:"0; url=https://oclif.io/docs/introduction.html"}))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6568],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=p(r),d=o,m=s["".concat(l,".").concat(d)]||s[d]||f[d]||a;return r?n.createElement(m,c(c({ref:t},u),{},{components:r})):n.createElement(m,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[s]="string"==typeof e?e:o,c[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>p,toc:()=>s});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),c=["components"],i={},l=void 0,p={unversionedId:"index",id:"index",title:"index",description:"",source:"@site/../docs/index.md",sourceDirName:".",slug:"/",permalink:"/docs/",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/index.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{}},u={},s=[],f={toc:s},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,c);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("meta",{"http-equiv":"refresh",content:"0; url=https://oclif.io/docs/introduction.html"}))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/03abeb31.89aea179.js b/assets/js/03abeb31.62d31294.js similarity index 98% rename from assets/js/03abeb31.89aea179.js rename to assets/js/03abeb31.62d31294.js index bdecd633..8e3ffb42 100644 --- a/assets/js/03abeb31.89aea179.js +++ b/assets/js/03abeb31.62d31294.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1660],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=c(n),g=o,f=p["".concat(u,".").concat(g)]||p[g]||d[g]||i;return n?r.createElement(f,a(a({ref:t},s),{},{components:n})):r.createElement(f,a({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=g;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:o,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>u,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],l={title:"Debugging"},u=void 0,c={unversionedId:"debugging",id:"debugging",title:"Debugging",description:"Use the debug for debugging. The CLI uses this module for all of its debugging. If you set the environment variable DEBUG=* it will print all the debug output to the screen.",source:"@site/../docs/debugging.md",sourceDirName:".",slug:"/debugging",permalink:"/docs/debugging",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/debugging.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Debugging"},sidebar:"docs",previous:{title:"Notifications",permalink:"/docs/notifications"},next:{title:"Flexible Taxonomy",permalink:"/docs/flexible_taxonomy"}},s={},p=[],d={toc:p},g="wrapper";function f(e){var t=e.components,l=(0,o.Z)(e,a);return(0,i.kt)(g,(0,r.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Use the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/visionmedia/debug"},"debug")," for debugging. The CLI uses this module for all of its debugging. If you set the environment variable ",(0,i.kt)("inlineCode",{parentName:"p"},"DEBUG=*")," it will print all the debug output to the screen."),(0,i.kt)("p",null,"Depending on your shell you may need to escape this with ",(0,i.kt)("inlineCode",{parentName:"p"},"DEBUG=\\*"),". On Windows you can't set environment variables in line, so you'll need to run ",(0,i.kt)("inlineCode",{parentName:"p"},"set DEBUG=*")," before running the command."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"debug demo",src:n(4924).Z,width:"2658",height:"1250"})))}f.isMDXComponent=!0},4924:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debug_demo-efc07abda59d2b82da3fc695b96596c8.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1660],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=c(n),g=o,f=p["".concat(u,".").concat(g)]||p[g]||d[g]||i;return n?r.createElement(f,a(a({ref:t},s),{},{components:n})):r.createElement(f,a({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=g;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:o,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>u,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],l={title:"Debugging"},u=void 0,c={unversionedId:"debugging",id:"debugging",title:"Debugging",description:"Use the debug for debugging. The CLI uses this module for all of its debugging. If you set the environment variable DEBUG=* it will print all the debug output to the screen.",source:"@site/../docs/debugging.md",sourceDirName:".",slug:"/debugging",permalink:"/docs/debugging",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/debugging.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Debugging"},sidebar:"docs",previous:{title:"Notifications",permalink:"/docs/notifications"},next:{title:"Flexible Taxonomy",permalink:"/docs/flexible_taxonomy"}},s={},p=[],d={toc:p},g="wrapper";function f(e){var t=e.components,l=(0,o.Z)(e,a);return(0,i.kt)(g,(0,r.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Use the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/visionmedia/debug"},"debug")," for debugging. The CLI uses this module for all of its debugging. If you set the environment variable ",(0,i.kt)("inlineCode",{parentName:"p"},"DEBUG=*")," it will print all the debug output to the screen."),(0,i.kt)("p",null,"Depending on your shell you may need to escape this with ",(0,i.kt)("inlineCode",{parentName:"p"},"DEBUG=\\*"),". On Windows you can't set environment variables in line, so you'll need to run ",(0,i.kt)("inlineCode",{parentName:"p"},"set DEBUG=*")," before running the command."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"debug demo",src:n(4924).Z,width:"2658",height:"1250"})))}f.isMDXComponent=!0},4924:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/debug_demo-efc07abda59d2b82da3fc695b96596c8.png"}}]); \ No newline at end of file diff --git a/assets/js/0b218a01.a5a6a16e.js b/assets/js/0b218a01.c7ec91a6.js similarity index 97% rename from assets/js/0b218a01.a5a6a16e.js rename to assets/js/0b218a01.c7ec91a6.js index 59e1d5f1..5ab0dfc5 100644 --- a/assets/js/0b218a01.a5a6a16e.js +++ b/assets/js/0b218a01.c7ec91a6.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3321],{3905:(e,n,a)=>{a.d(n,{Zo:()=>p,kt:()=>f});var t=a(7294);function i(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function s(e){for(var n=1;n=0||(i[a]=e[a]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=t.createContext({}),c=function(e){var n=t.useContext(l),a=n;return e&&(a="function"==typeof e?e(n):s(s({},n),e)),a},p=function(e){var n=c(e.components);return t.createElement(l.Provider,{value:n},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},u=t.forwardRef((function(e,n){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=c(a),u=i,f=d["".concat(l,".").concat(u)]||d[u]||m[u]||r;return a?t.createElement(f,s(s({ref:n},p),{},{components:a})):t.createElement(f,s({ref:n},p))}));function f(e,n){var a=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=a.length,s=new Array(r);s[0]=u;var o={};for(var l in n)hasOwnProperty.call(n,l)&&(o[l]=n[l]);o.originalType=e,o[d]="string"==typeof e?e:i,s[1]=o;for(var c=2;c{a.r(n),a.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>o,metadata:()=>c,toc:()=>d});var t=a(7462),i=a(3366),r=(a(7294),a(3905)),s=["components"],o={title:"Aliases"},l=void 0,c={unversionedId:"aliases",id:"aliases",title:"Aliases",description:"Command Aliases",source:"@site/../docs/aliases.md",sourceDirName:".",slug:"/aliases",permalink:"/docs/aliases",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/aliases.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Aliases"},sidebar:"docs",previous:{title:"Just-in-Time Plugin Installation",permalink:"/docs/jit_plugins"},next:{title:"NSIS Installer Customization",permalink:"/docs/nsis-installer_customization"}},p={},d=[{value:"Command Aliases",id:"command-aliases",level:2},{value:"Flag Aliases",id:"flag-aliases",level:2},{value:"Bin Aliases",id:"bin-aliases",level:2}],m={toc:d},u="wrapper";function f(e){var n=e.components,a=(0,i.Z)(e,s);return(0,r.kt)(u,(0,t.Z)({},m,a,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"command-aliases"},"Command Aliases"),(0,r.kt)("p",null,"Aliases let you define a string that maps to a command. This command can be run as ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config:index"),", or ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config:list"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, Flags} from '@oclif/core'\n\nexport class ConfigIndex extends Command {\n static aliases = ['config:index', 'config:list']\n}\n")),(0,r.kt)("p",null,'By default, aliases find the "real" command and just work. If you\'re providing command aliases for backward compatibility but prefer users to use the "real" command, set ',(0,r.kt)("inlineCode",{parentName:"p"},"deprecateAliases")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," to warn users about the correct name"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"export class ConfigIndex extends Command {\n static aliases = ['config:index', 'config:list']\n static deprecateAliases = true\n}\n")),(0,r.kt)("h2",{id:"flag-aliases"},"Flag Aliases"),(0,r.kt)("p",null,"Like command aliases, but on an individual flag. You can alias the name and short character, and optionally emit warnings when aliased names are used."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"export class ConfigIndex extends Command {\n static flags = {\n 'new-name': Flags.boolean({\n char: 'c',\n aliases: ['old-name', 'o'],\n deprecateAliases: true\n })\n }\n}\n\n")),(0,r.kt)("h2",{id:"bin-aliases"},"Bin Aliases"),(0,r.kt)("p",null,'Creating a CLI that responds to different names or "aliases" is easy, simply add a ',(0,r.kt)("inlineCode",{parentName:"p"},"binAliases")," property to your CLI's ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif")," property in ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "name": "mycli",\n "version": "0.0.0",\n "description": "My CLI",\n "main": "bin/run.js",\n "bin": {\n "mycli": "./bin/run.js",\n "mycli-alias": "./bin/run.js"\n },\n "oclif": {\n "binAliases": ["mycli", "mycli-alias"]\n }\n}\n')),(0,r.kt)("p",null,"Adding this property allows your CLI to respond to either of those names, and is used during the bundling and building process when shipping your CLI. Note that the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," section was also modified to include both aliases, which is how npm creates bin aliases. To create a unified experience, regardless of the installation method, a CLI author must change both to match. Bin aliases also play nicely with ",(0,r.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-autocomplete"),", so typing an alias and using autocomplete is the same experience as using the original name."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3321],{3905:(e,n,a)=>{a.d(n,{Zo:()=>p,kt:()=>f});var t=a(7294);function i(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function s(e){for(var n=1;n=0||(i[a]=e[a]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=t.createContext({}),c=function(e){var n=t.useContext(l),a=n;return e&&(a="function"==typeof e?e(n):s(s({},n),e)),a},p=function(e){var n=c(e.components);return t.createElement(l.Provider,{value:n},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},u=t.forwardRef((function(e,n){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=c(a),u=i,f=d["".concat(l,".").concat(u)]||d[u]||m[u]||r;return a?t.createElement(f,s(s({ref:n},p),{},{components:a})):t.createElement(f,s({ref:n},p))}));function f(e,n){var a=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=a.length,s=new Array(r);s[0]=u;var o={};for(var l in n)hasOwnProperty.call(n,l)&&(o[l]=n[l]);o.originalType=e,o[d]="string"==typeof e?e:i,s[1]=o;for(var c=2;c{a.r(n),a.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>o,metadata:()=>c,toc:()=>d});var t=a(7462),i=a(3366),r=(a(7294),a(3905)),s=["components"],o={title:"Aliases"},l=void 0,c={unversionedId:"aliases",id:"aliases",title:"Aliases",description:"Command Aliases",source:"@site/../docs/aliases.md",sourceDirName:".",slug:"/aliases",permalink:"/docs/aliases",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/aliases.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Aliases"},sidebar:"docs",previous:{title:"Just-in-Time Plugin Installation",permalink:"/docs/jit_plugins"},next:{title:"NSIS Installer Customization",permalink:"/docs/nsis-installer_customization"}},p={},d=[{value:"Command Aliases",id:"command-aliases",level:2},{value:"Flag Aliases",id:"flag-aliases",level:2},{value:"Bin Aliases",id:"bin-aliases",level:2}],m={toc:d},u="wrapper";function f(e){var n=e.components,a=(0,i.Z)(e,s);return(0,r.kt)(u,(0,t.Z)({},m,a,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"command-aliases"},"Command Aliases"),(0,r.kt)("p",null,"Aliases let you define a string that maps to a command. This command can be run as ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config:index"),", or ",(0,r.kt)("inlineCode",{parentName:"p"},"mycli config:list"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, Flags} from '@oclif/core'\n\nexport class ConfigIndex extends Command {\n static aliases = ['config:index', 'config:list']\n}\n")),(0,r.kt)("p",null,'By default, aliases find the "real" command and just work. If you\'re providing command aliases for backward compatibility but prefer users to use the "real" command, set ',(0,r.kt)("inlineCode",{parentName:"p"},"deprecateAliases")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," to warn users about the correct name"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"export class ConfigIndex extends Command {\n static aliases = ['config:index', 'config:list']\n static deprecateAliases = true\n}\n")),(0,r.kt)("h2",{id:"flag-aliases"},"Flag Aliases"),(0,r.kt)("p",null,"Like command aliases, but on an individual flag. You can alias the name and short character, and optionally emit warnings when aliased names are used."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"export class ConfigIndex extends Command {\n static flags = {\n 'new-name': Flags.boolean({\n char: 'c',\n aliases: ['old-name', 'o'],\n deprecateAliases: true\n })\n }\n}\n\n")),(0,r.kt)("h2",{id:"bin-aliases"},"Bin Aliases"),(0,r.kt)("p",null,'Creating a CLI that responds to different names or "aliases" is easy, simply add a ',(0,r.kt)("inlineCode",{parentName:"p"},"binAliases")," property to your CLI's ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif")," property in ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "name": "mycli",\n "version": "0.0.0",\n "description": "My CLI",\n "main": "bin/run.js",\n "bin": {\n "mycli": "./bin/run.js",\n "mycli-alias": "./bin/run.js"\n },\n "oclif": {\n "binAliases": ["mycli", "mycli-alias"]\n }\n}\n')),(0,r.kt)("p",null,"Adding this property allows your CLI to respond to either of those names, and is used during the bundling and building process when shipping your CLI. Note that the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," section was also modified to include both aliases, which is how npm creates bin aliases. To create a unified experience, regardless of the installation method, a CLI author must change both to match. Bin aliases also play nicely with ",(0,r.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-autocomplete"),", so typing an alias and using autocomplete is the same experience as using the original name."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/104cbb75.891f291a.js b/assets/js/104cbb75.23da78ae.js similarity index 98% rename from assets/js/104cbb75.891f291a.js rename to assets/js/104cbb75.23da78ae.js index 31f464d5..271a2192 100644 --- a/assets/js/104cbb75.891f291a.js +++ b/assets/js/104cbb75.23da78ae.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3316],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var m=o.createContext({}),c=function(e){var n=o.useContext(m),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=c(e.components);return o.createElement(m.Provider,{value:n},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},u=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,m=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),s=c(t),u=r,f=s["".concat(m,".").concat(u)]||s[u]||d[u]||a;return t?o.createElement(f,i(i({ref:n},p),{},{components:t})):o.createElement(f,i({ref:n},p))}));function f(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=u;var l={};for(var m in n)hasOwnProperty.call(n,m)&&(l[m]=n[m]);l.originalType=e,l[s]="string"==typeof e?e:r,i[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>m,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>s});var o=t(7462),r=t(3366),a=(t(7294),t(3905)),i=["components"],l={title:"Flexible Taxonomy"},m=void 0,c={unversionedId:"flexible_taxonomy",id:"flexible_taxonomy",title:"Flexible Taxonomy",description:"If you'd like for your customers to execute commands without adhereing to the defined command taxonomy, you can enable flexibleTaxonomy and add a hook to the oclif section of your package.json:",source:"@site/../docs/flexible_taxonomy.md",sourceDirName:".",slug:"/flexible_taxonomy",permalink:"/docs/flexible_taxonomy",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/flexible_taxonomy.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Flexible Taxonomy"},sidebar:"docs",previous:{title:"Debugging",permalink:"/docs/debugging"},next:{title:"Global Flags",permalink:"/docs/global_flags"}},p={},s=[{value:"Hook Implementation",id:"hook-implementation",level:3}],d={toc:s},u="wrapper";function f(e){var n=e.components,t=(0,r.Z)(e,i);return(0,a.kt)(u,(0,o.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you'd like for your customers to execute commands without adhereing to the defined command taxonomy, you can enable ",(0,a.kt)("inlineCode",{parentName:"p"},"flexibleTaxonomy")," and add a hook to the ",(0,a.kt)("inlineCode",{parentName:"p"},"oclif")," section of your package.json:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "flexibleTaxonomy": true,\n "hooks": {\n "command_incomplete": "./dist/hooks/command_incomplete.js"\n }\n }\n}\n')),(0,a.kt)("p",null,"There are two main benefits to enabling flexible taxonomy:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"It makes your CLI more user-friendly. For example, you might have a command, ",(0,a.kt)("inlineCode",{parentName:"li"},"my-cli foobars:list"),". If a user mistakenly enters ",(0,a.kt)("inlineCode",{parentName:"li"},"my-cli list:foobars")," then oclif will automatically know that it should execute ",(0,a.kt)("inlineCode",{parentName:"li"},"foobars:list")," instead of throwing an error."),(0,a.kt)("li",{parentName:"ol"},"It gives you the opportunity to prompt a user for the right command if they only provide part of a command. This makes individual commands more discoverable, especially if you have a large number of commands. See ",(0,a.kt)("a",{parentName:"li",href:"#hook-implementation"},"Hook Implementation")," for more details.")),(0,a.kt)("h3",{id:"hook-implementation"},"Hook Implementation"),(0,a.kt)("p",null,"When ",(0,a.kt)("inlineCode",{parentName:"p"},"flexibleTaxonomy")," is enabled, oclif will run the ",(0,a.kt)("inlineCode",{parentName:"p"},"command_incomplete")," hook anytime a user enters an incomplete command (e.g. the command is ",(0,a.kt)("inlineCode",{parentName:"p"},"one:two:three")," but they only entered ",(0,a.kt)("inlineCode",{parentName:"p"},"two"),"). This hook gives you the opportunity to create an interactive user experience."),(0,a.kt)("p",null,"This example shows how you can use the ",(0,a.kt)("a",{parentName:"p",href:"#https://www.npmjs.com/package/inquirer"},"inquirer")," package to prompt the user for which command they would like to run:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},'import { Hook, toConfiguredId, toStandardizedId } from "@oclif/core";\nimport { prompt } from "inquirer";\n\nconst hook: Hook.CommandIncomplete = async function ({\n config,\n matches,\n argv,\n}) {\n const { command } = await prompt<{ command: string }>([\n {\n name: "command",\n type: "list",\n message: "Which of these commands would you like to run?",\n choices: matches.map((p) => toConfiguredId(p.id, config)),\n },\n ]);\n\n if (argv.includes("--help") || argv.includes("-h")) {\n return config.runCommand("help", [toStandardizedId(command, config)]);\n }\n\n return config.runCommand(toStandardizedId(command, config), argv);\n};\n\nexport default hook;\n')),(0,a.kt)("p",null,"This is the prompt that the user would see:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli list\n? Which of these commands did you mean (Use arrow keys)\n\u276f foobars list\n config list\n env list\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3316],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var m=o.createContext({}),c=function(e){var n=o.useContext(m),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=c(e.components);return o.createElement(m.Provider,{value:n},e.children)},s="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},u=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,m=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),s=c(t),u=r,f=s["".concat(m,".").concat(u)]||s[u]||d[u]||a;return t?o.createElement(f,i(i({ref:n},p),{},{components:t})):o.createElement(f,i({ref:n},p))}));function f(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,i=new Array(a);i[0]=u;var l={};for(var m in n)hasOwnProperty.call(n,m)&&(l[m]=n[m]);l.originalType=e,l[s]="string"==typeof e?e:r,i[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>m,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>s});var o=t(7462),r=t(3366),a=(t(7294),t(3905)),i=["components"],l={title:"Flexible Taxonomy"},m=void 0,c={unversionedId:"flexible_taxonomy",id:"flexible_taxonomy",title:"Flexible Taxonomy",description:"If you'd like for your customers to execute commands without adhereing to the defined command taxonomy, you can enable flexibleTaxonomy and add a hook to the oclif section of your package.json:",source:"@site/../docs/flexible_taxonomy.md",sourceDirName:".",slug:"/flexible_taxonomy",permalink:"/docs/flexible_taxonomy",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/flexible_taxonomy.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Flexible Taxonomy"},sidebar:"docs",previous:{title:"Debugging",permalink:"/docs/debugging"},next:{title:"Global Flags",permalink:"/docs/global_flags"}},p={},s=[{value:"Hook Implementation",id:"hook-implementation",level:3}],d={toc:s},u="wrapper";function f(e){var n=e.components,t=(0,r.Z)(e,i);return(0,a.kt)(u,(0,o.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you'd like for your customers to execute commands without adhereing to the defined command taxonomy, you can enable ",(0,a.kt)("inlineCode",{parentName:"p"},"flexibleTaxonomy")," and add a hook to the ",(0,a.kt)("inlineCode",{parentName:"p"},"oclif")," section of your package.json:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "flexibleTaxonomy": true,\n "hooks": {\n "command_incomplete": "./dist/hooks/command_incomplete.js"\n }\n }\n}\n')),(0,a.kt)("p",null,"There are two main benefits to enabling flexible taxonomy:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"It makes your CLI more user-friendly. For example, you might have a command, ",(0,a.kt)("inlineCode",{parentName:"li"},"my-cli foobars:list"),". If a user mistakenly enters ",(0,a.kt)("inlineCode",{parentName:"li"},"my-cli list:foobars")," then oclif will automatically know that it should execute ",(0,a.kt)("inlineCode",{parentName:"li"},"foobars:list")," instead of throwing an error."),(0,a.kt)("li",{parentName:"ol"},"It gives you the opportunity to prompt a user for the right command if they only provide part of a command. This makes individual commands more discoverable, especially if you have a large number of commands. See ",(0,a.kt)("a",{parentName:"li",href:"#hook-implementation"},"Hook Implementation")," for more details.")),(0,a.kt)("h3",{id:"hook-implementation"},"Hook Implementation"),(0,a.kt)("p",null,"When ",(0,a.kt)("inlineCode",{parentName:"p"},"flexibleTaxonomy")," is enabled, oclif will run the ",(0,a.kt)("inlineCode",{parentName:"p"},"command_incomplete")," hook anytime a user enters an incomplete command (e.g. the command is ",(0,a.kt)("inlineCode",{parentName:"p"},"one:two:three")," but they only entered ",(0,a.kt)("inlineCode",{parentName:"p"},"two"),"). This hook gives you the opportunity to create an interactive user experience."),(0,a.kt)("p",null,"This example shows how you can use the ",(0,a.kt)("a",{parentName:"p",href:"#https://www.npmjs.com/package/inquirer"},"inquirer")," package to prompt the user for which command they would like to run:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},'import { Hook, toConfiguredId, toStandardizedId } from "@oclif/core";\nimport { prompt } from "inquirer";\n\nconst hook: Hook.CommandIncomplete = async function ({\n config,\n matches,\n argv,\n}) {\n const { command } = await prompt<{ command: string }>([\n {\n name: "command",\n type: "list",\n message: "Which of these commands would you like to run?",\n choices: matches.map((p) => toConfiguredId(p.id, config)),\n },\n ]);\n\n if (argv.includes("--help") || argv.includes("-h")) {\n return config.runCommand("help", [toStandardizedId(command, config)]);\n }\n\n return config.runCommand(toStandardizedId(command, config), argv);\n};\n\nexport default hook;\n')),(0,a.kt)("p",null,"This is the prompt that the user would see:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli list\n? Which of these commands did you mean (Use arrow keys)\n\u276f foobars list\n config list\n env list\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/19fd9079.626d5720.js b/assets/js/19fd9079.580d846e.js similarity index 98% rename from assets/js/19fd9079.626d5720.js rename to assets/js/19fd9079.580d846e.js index a2315398..f07ea9c2 100644 --- a/assets/js/19fd9079.626d5720.js +++ b/assets/js/19fd9079.580d846e.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8925],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),m=o,d=u["".concat(c,".").concat(m)]||u[m]||f[m]||a;return r?n.createElement(d,l(l({ref:t},p),{},{components:r})):n.createElement(d,l({ref:t},p))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),l=["components"],i={title:"External Links"},c=void 0,s={unversionedId:"external_links",id:"external_links",title:"External Links",description:"* Salesforce Release Announcement",source:"@site/../docs/external_links.md",sourceDirName:".",slug:"/external_links",permalink:"/docs/external_links",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/external_links.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"External Links"},sidebar:"docs",previous:{title:"Examples",permalink:"/docs/examples"},next:{title:"Related Repositories",permalink:"/docs/related_repos"}},p={},u=[],f={toc:u},m="wrapper";function d(e){var t=e.components,r=(0,o.Z)(e,l);return(0,a.kt)(m,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://engineering.salesforce.com/open-sourcing-oclif-the-cli-framework-that-powers-our-clis-21fbda99d33a"},"Salesforce Release Announcement")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://blog.heroku.com/open-cli-framework"},"Heroku Release Announcement"))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8925],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),m=o,d=u["".concat(c,".").concat(m)]||u[m]||f[m]||a;return r?n.createElement(d,l(l({ref:t},p),{},{components:r})):n.createElement(d,l({ref:t},p))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),l=["components"],i={title:"External Links"},c=void 0,s={unversionedId:"external_links",id:"external_links",title:"External Links",description:"* Salesforce Release Announcement",source:"@site/../docs/external_links.md",sourceDirName:".",slug:"/external_links",permalink:"/docs/external_links",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/external_links.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"External Links"},sidebar:"docs",previous:{title:"Examples",permalink:"/docs/examples"},next:{title:"Related Repositories",permalink:"/docs/related_repos"}},p={},u=[],f={toc:u},m="wrapper";function d(e){var t=e.components,r=(0,o.Z)(e,l);return(0,a.kt)(m,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://engineering.salesforce.com/open-sourcing-oclif-the-cli-framework-that-powers-our-clis-21fbda99d33a"},"Salesforce Release Announcement")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://blog.heroku.com/open-cli-framework"},"Heroku Release Announcement"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1ed4142b.29563194.js b/assets/js/1ed4142b.e0b1cff1.js similarity index 98% rename from assets/js/1ed4142b.29563194.js rename to assets/js/1ed4142b.e0b1cff1.js index b4bd66f1..31eaa5c6 100644 --- a/assets/js/1ed4142b.29563194.js +++ b/assets/js/1ed4142b.e0b1cff1.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3725],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),d=r,f=c["".concat(s,".").concat(d)]||c[d]||m[d]||i;return n?o.createElement(f,a(a({ref:t},p),{},{components:n})):o.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,a[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>u,toc:()=>c});var o=n(7462),r=n(3366),i=(n(7294),n(3905)),a=["components"],l={title:"Just-in-Time Plugin Installation"},s=void 0,u={unversionedId:"jit_plugins",id:"jit_plugins",title:"Just-in-Time Plugin Installation",description:"Sometimes you might want to have a plugin that isn't bundled in your CLI but gets installed the first time it's executed by the user - we call this just-in-time plugin installation, or JIT for short. This can be useful if you need to reduce the package size of your CLI while still allowing users access to all the plugins.",source:"@site/../docs/jit_plugins.md",sourceDirName:".",slug:"/jit_plugins",permalink:"/docs/jit_plugins",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/jit_plugins.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Just-in-Time Plugin Installation"},sidebar:"docs",previous:{title:"Running Commands Programmatically",permalink:"/docs/running_programmatically"},next:{title:"Aliases",permalink:"/docs/aliases"}},p={},c=[],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,r.Z)(e,a);return(0,i.kt)(d,(0,o.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Sometimes you might want to have a plugin that isn't bundled in your CLI but gets installed the first time it's executed by the user - we call this just-in-time plugin installation, or JIT for short. This can be useful if you need to reduce the package size of your CLI while still allowing users access to all the plugins."),(0,i.kt)("p",null,"To use this feature you need to:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Add ",(0,i.kt)("inlineCode",{parentName:"li"},"jitPlugins")," to the ",(0,i.kt)("inlineCode",{parentName:"li"},"oclif")," section of your package.json")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"oclif": {\n "jitPlugins": {\n "my-plugin": "^1.2.3",\n "another-plugin": "^1.2.3",\n }\n}\n')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Ensure that your build process includes generating a manifest using ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif manifest"),". The manifest will include the information about all the commands owned by JIT plugins which allows users to run ",(0,i.kt)("inlineCode",{parentName:"p"},"--help")," on those commands without having them installed yet. ",(0,i.kt)("strong",{parentName:"p"},"If the generated manifest doesn't get packed with your CLI, then the feature will not work."))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"jit_plugin_not_installed")," hook."))),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"@oclif/core")," attempts to be UX-agnostic, meaning that we don't want to impose any particular user experience on you. Any time a user experience is required we utilize hooks so that you can design the exact user experience you want your users to have."),(0,i.kt)("p",null,"In the case of JIT plugin installation, there are many possible user experiences that you might want - maybe you want to prompt the user for confirmation first, or maybe you want to log a specific message, etc..."),(0,i.kt)("p",null,"Here's an example of how you might implement the hook,"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import { Hook, CLIError, ux } from '@oclif/core';\n\nconst hook: Hook<'jit_plugin_not_installed'> = async function (opts) {\n try {\n const answer = await ux.confirm(`${opts.command.pluginName} not installed. Would you like to install?`)\n if (answer === 'y') {\n await opts.config.runCommand('plugins:install', [`${opts.command.pluginName}@${opts.pluginVersion}`]);\n }\n } catch (error) {\n throw new CLIError(`Could not install ${opts.command.pluginName}`, 'JitPluginInstallError');\n }\n};\n\nexport default hook;\n\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3725],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),d=r,f=c["".concat(s,".").concat(d)]||c[d]||m[d]||i;return n?o.createElement(f,a(a({ref:t},p),{},{components:n})):o.createElement(f,a({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,a[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>u,toc:()=>c});var o=n(7462),r=n(3366),i=(n(7294),n(3905)),a=["components"],l={title:"Just-in-Time Plugin Installation"},s=void 0,u={unversionedId:"jit_plugins",id:"jit_plugins",title:"Just-in-Time Plugin Installation",description:"Sometimes you might want to have a plugin that isn't bundled in your CLI but gets installed the first time it's executed by the user - we call this just-in-time plugin installation, or JIT for short. This can be useful if you need to reduce the package size of your CLI while still allowing users access to all the plugins.",source:"@site/../docs/jit_plugins.md",sourceDirName:".",slug:"/jit_plugins",permalink:"/docs/jit_plugins",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/jit_plugins.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Just-in-Time Plugin Installation"},sidebar:"docs",previous:{title:"Running Commands Programmatically",permalink:"/docs/running_programmatically"},next:{title:"Aliases",permalink:"/docs/aliases"}},p={},c=[],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,r.Z)(e,a);return(0,i.kt)(d,(0,o.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Sometimes you might want to have a plugin that isn't bundled in your CLI but gets installed the first time it's executed by the user - we call this just-in-time plugin installation, or JIT for short. This can be useful if you need to reduce the package size of your CLI while still allowing users access to all the plugins."),(0,i.kt)("p",null,"To use this feature you need to:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Add ",(0,i.kt)("inlineCode",{parentName:"li"},"jitPlugins")," to the ",(0,i.kt)("inlineCode",{parentName:"li"},"oclif")," section of your package.json")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"oclif": {\n "jitPlugins": {\n "my-plugin": "^1.2.3",\n "another-plugin": "^1.2.3",\n }\n}\n')),(0,i.kt)("ol",{start:2},(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Ensure that your build process includes generating a manifest using ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif manifest"),". The manifest will include the information about all the commands owned by JIT plugins which allows users to run ",(0,i.kt)("inlineCode",{parentName:"p"},"--help")," on those commands without having them installed yet. ",(0,i.kt)("strong",{parentName:"p"},"If the generated manifest doesn't get packed with your CLI, then the feature will not work."))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"jit_plugin_not_installed")," hook."))),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"@oclif/core")," attempts to be UX-agnostic, meaning that we don't want to impose any particular user experience on you. Any time a user experience is required we utilize hooks so that you can design the exact user experience you want your users to have."),(0,i.kt)("p",null,"In the case of JIT plugin installation, there are many possible user experiences that you might want - maybe you want to prompt the user for confirmation first, or maybe you want to log a specific message, etc..."),(0,i.kt)("p",null,"Here's an example of how you might implement the hook,"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import { Hook, CLIError, ux } from '@oclif/core';\n\nconst hook: Hook<'jit_plugin_not_installed'> = async function (opts) {\n try {\n const answer = await ux.confirm(`${opts.command.pluginName} not installed. Would you like to install?`)\n if (answer === 'y') {\n await opts.config.runCommand('plugins:install', [`${opts.command.pluginName}@${opts.pluginVersion}`]);\n }\n } catch (error) {\n throw new CLIError(`Could not install ${opts.command.pluginName}`, 'JitPluginInstallError');\n }\n};\n\nexport default hook;\n\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1f61ef73.2c97d45b.js b/assets/js/1f61ef73.050e594a.js similarity index 99% rename from assets/js/1f61ef73.2c97d45b.js rename to assets/js/1f61ef73.050e594a.js index 36a7bba8..28bb6517 100644 --- a/assets/js/1f61ef73.2c97d45b.js +++ b/assets/js/1f61ef73.050e594a.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[7006],{3905:(e,r,n)=>{n.d(r,{Zo:()=>d,kt:()=>m});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function i(e){for(var r=1;r=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=t.createContext({}),s=function(e){var r=t.useContext(c),n=r;return e&&(n="function"==typeof e?e(r):i(i({},r),e)),n},d=function(e){var r=s(e.components);return t.createElement(c.Provider,{value:r},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},u=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),h=s(n),u=o,m=h["".concat(c,".").concat(u)]||h[u]||p[u]||a;return n?t.createElement(m,i(i({ref:r},d),{},{components:n})):t.createElement(m,i({ref:r},d))}));function m(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=u;var l={};for(var c in r)hasOwnProperty.call(r,c)&&(l[c]=r[c]);l.originalType=e,l[h]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{n.r(r),n.d(r,{assets:()=>d,contentTitle:()=>c,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>h});var t=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],l={title:"Error Handling"},c=void 0,s={unversionedId:"error_handling",id:"error_handling",title:"Error Handling",description:"oclif handles intentionally - and unintentionally - thrown errors in two places. First in the Command.catch method and then, finally, in the bin/run catch handler where the Error is printed and the CLI exits. This error flow makes it possible for you to control and respond to errors that occur in your CLI as you see fit.",source:"@site/../docs/error_handling.md",sourceDirName:".",slug:"/error_handling",permalink:"/docs/error_handling",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/error_handling.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Error Handling"},sidebar:"docs",previous:{title:"Help Classes",permalink:"/docs/help_classes"},next:{title:"JSON",permalink:"/docs/json"}},d={},h=[{value:"Error Handling in the catch method",id:"error-handling-in-the-catch-method",level:2},{value:"bin/run.js catch handler",id:"binrunjs-catch-handler",level:2}],p={toc:h},u="wrapper";function m(e){var r=e.components,n=(0,o.Z)(e,i);return(0,a.kt)(u,(0,t.Z)({},p,n,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"oclif handles intentionally - and unintentionally - thrown errors in two places. First in the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command.catch")," method and then, finally, in the bin/run ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," handler where the Error is printed and the CLI exits. This error flow makes it possible for you to control and respond to errors that occur in your CLI as you see fit."),(0,a.kt)("h2",{id:"error-handling-in-the-catch-method"},"Error Handling in the ",(0,a.kt)("inlineCode",{parentName:"h2"},"catch")," method"),(0,a.kt)("p",null,"Every ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," instance has a ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method that is called when an error occurs throughout the course of a command run. This method handles the edge case of users asking for help or version output, if applicable, otherwise, it re-throws the error. You can extend or overwrite the ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method in your command class."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, flags} from '@oclif/core'\n\nexport default class Hello extends Command {\n async catch(error) {\n // do something or\n // re-throw to be handled globally\n throw error;\n }\n}\n")),(0,a.kt)("p",null,"If this type of error handling is being implemented across multiple commands consider using a Custom Base Class (",(0,a.kt)("a",{parentName:"p",href:"https://oclif.io/docs/base_class#docsNav"},"https://oclif.io/docs/base_class#docsNav"),") for your commands and overriding the ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method."),(0,a.kt)("h2",{id:"binrunjs-catch-handler"},"bin/run.js ",(0,a.kt)("inlineCode",{parentName:"h2"},"catch")," handler"),(0,a.kt)("p",null,"Every oclif CLI has a ./bin/run.js file that is the entry point of command invocation. Errors that occur in the CLI, including re-thrown errors from a Command, are caught here in the bin/run.js ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," handler."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},".catch(require('@oclif/core/handle'))\n")),(0,a.kt)("p",null,"This catch handler uses the ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/errors/handle")," function to display (and cleanup, if necessary) the error to the user. This handler can be swapped for any function that receives an error argument."),(0,a.kt)("p",null,"If you chose to implement your own handler here, we still recommend you delegate finally to the ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/core/handle")," function for clean-up and exiting logic."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},".catch((error) => {\n const oclifHandler = require('@oclif/core/handle');\n // do any extra work with error\n return oclifHandler(error);\n})\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[7006],{3905:(e,r,n)=>{n.d(r,{Zo:()=>d,kt:()=>m});var t=n(7294);function o(e,r,n){return r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n,e}function a(e,r){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r&&(t=t.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),n.push.apply(n,t)}return n}function i(e){for(var r=1;r=0||(o[n]=e[n]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=t.createContext({}),s=function(e){var r=t.useContext(c),n=r;return e&&(n="function"==typeof e?e(r):i(i({},r),e)),n},d=function(e){var r=s(e.components);return t.createElement(c.Provider,{value:r},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var r=e.children;return t.createElement(t.Fragment,{},r)}},u=t.forwardRef((function(e,r){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),h=s(n),u=o,m=h["".concat(c,".").concat(u)]||h[u]||p[u]||a;return n?t.createElement(m,i(i({ref:r},d),{},{components:n})):t.createElement(m,i({ref:r},d))}));function m(e,r){var n=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=u;var l={};for(var c in r)hasOwnProperty.call(r,c)&&(l[c]=r[c]);l.originalType=e,l[h]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{n.r(r),n.d(r,{assets:()=>d,contentTitle:()=>c,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>h});var t=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],l={title:"Error Handling"},c=void 0,s={unversionedId:"error_handling",id:"error_handling",title:"Error Handling",description:"oclif handles intentionally - and unintentionally - thrown errors in two places. First in the Command.catch method and then, finally, in the bin/run catch handler where the Error is printed and the CLI exits. This error flow makes it possible for you to control and respond to errors that occur in your CLI as you see fit.",source:"@site/../docs/error_handling.md",sourceDirName:".",slug:"/error_handling",permalink:"/docs/error_handling",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/error_handling.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Error Handling"},sidebar:"docs",previous:{title:"Help Classes",permalink:"/docs/help_classes"},next:{title:"JSON",permalink:"/docs/json"}},d={},h=[{value:"Error Handling in the catch method",id:"error-handling-in-the-catch-method",level:2},{value:"bin/run.js catch handler",id:"binrunjs-catch-handler",level:2}],p={toc:h},u="wrapper";function m(e){var r=e.components,n=(0,o.Z)(e,i);return(0,a.kt)(u,(0,t.Z)({},p,n,{components:r,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"oclif handles intentionally - and unintentionally - thrown errors in two places. First in the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command.catch")," method and then, finally, in the bin/run ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," handler where the Error is printed and the CLI exits. This error flow makes it possible for you to control and respond to errors that occur in your CLI as you see fit."),(0,a.kt)("h2",{id:"error-handling-in-the-catch-method"},"Error Handling in the ",(0,a.kt)("inlineCode",{parentName:"h2"},"catch")," method"),(0,a.kt)("p",null,"Every ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," instance has a ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method that is called when an error occurs throughout the course of a command run. This method handles the edge case of users asking for help or version output, if applicable, otherwise, it re-throws the error. You can extend or overwrite the ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method in your command class."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, flags} from '@oclif/core'\n\nexport default class Hello extends Command {\n async catch(error) {\n // do something or\n // re-throw to be handled globally\n throw error;\n }\n}\n")),(0,a.kt)("p",null,"If this type of error handling is being implemented across multiple commands consider using a Custom Base Class (",(0,a.kt)("a",{parentName:"p",href:"https://oclif.io/docs/base_class#docsNav"},"https://oclif.io/docs/base_class#docsNav"),") for your commands and overriding the ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," method."),(0,a.kt)("h2",{id:"binrunjs-catch-handler"},"bin/run.js ",(0,a.kt)("inlineCode",{parentName:"h2"},"catch")," handler"),(0,a.kt)("p",null,"Every oclif CLI has a ./bin/run.js file that is the entry point of command invocation. Errors that occur in the CLI, including re-thrown errors from a Command, are caught here in the bin/run.js ",(0,a.kt)("inlineCode",{parentName:"p"},"catch")," handler."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},".catch(require('@oclif/core/handle'))\n")),(0,a.kt)("p",null,"This catch handler uses the ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/errors/handle")," function to display (and cleanup, if necessary) the error to the user. This handler can be swapped for any function that receives an error argument."),(0,a.kt)("p",null,"If you chose to implement your own handler here, we still recommend you delegate finally to the ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/core/handle")," function for clean-up and exiting logic."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},".catch((error) => {\n const oclifHandler = require('@oclif/core/handle');\n // do any extra work with error\n return oclifHandler(error);\n})\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2486267b.f3aad5aa.js b/assets/js/2486267b.95b52046.js similarity index 98% rename from assets/js/2486267b.f3aad5aa.js rename to assets/js/2486267b.95b52046.js index b6a230f6..1028b9cf 100644 --- a/assets/js/2486267b.f3aad5aa.js +++ b/assets/js/2486267b.95b52046.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9562],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},l),{},{components:r})):n.createElement(f,i({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>s,metadata:()=>p,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],s={title:"Spinner"},c=void 0,p={unversionedId:"spinner",id:"spinner",title:"Spinner",description:"@oclif/core provides a simple ux.action, for more complex progress indicators we recommend using the listr library.",source:"@site/../docs/spinner.md",sourceDirName:".",slug:"/spinner",permalink:"/docs/spinner",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/spinner.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Spinner"},sidebar:"docs",previous:{title:"Prompting",permalink:"/docs/prompting"},next:{title:"Table",permalink:"/docs/table"}},l={},u=[{value:"ux.action",id:"uxaction",level:2},{value:"listr",id:"listr",level:2}],d={toc:u},m="wrapper";function f(e){var t=e.components,s=(0,o.Z)(e,i);return(0,a.kt)(m,(0,n.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core"},"@oclif/core")," provides a simple ",(0,a.kt)("inlineCode",{parentName:"p"},"ux.action"),", for more complex progress indicators we recommend using the ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/listr"},"listr")," library."),(0,a.kt)("h2",{id:"uxaction"},(0,a.kt)("inlineCode",{parentName:"h2"},"ux.action")),(0,a.kt)("p",null,"Shows a basic spinner"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport class MyCommand extends Command {\n async run() {\n // start the spinner\n ux.action.start('starting a process')\n // do some action...\n // stop the spinner\n ux.action.stop() // shows 'starting a process... done'\n\n // show on stdout instead of stderr\n ux.action.start('starting a process', 'initializing', {stdout: true})\n // do some action...\n // stop the spinner with a custom message\n ux.action.stop('custom message') // shows 'starting a process... custom message'\n }\n}\n")),(0,a.kt)("p",null,"This degrades gracefully when not connected to a TTY. It queues up any writes to stdout/stderr so they are displayed above the spinner."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"action demo",src:r(1305).Z,width:"563",height:"271"})),(0,a.kt)("h2",{id:"listr"},"listr"),(0,a.kt)("p",null,"Here is an example of the complex workflows supported by ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/listr"},"listr"),"."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"listr demo",src:r(3220).Z,width:"1177",height:"709"})))}f.isMDXComponent=!0},1305:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/action-3dc2f1c9da2526e7dacc7ba55a2e3f5a.gif"},3220:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/listr-fb034a43c5d3159c331547ffba3b6559.gif"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9562],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),p=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},l),{},{components:r})):n.createElement(f,i({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>s,metadata:()=>p,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],s={title:"Spinner"},c=void 0,p={unversionedId:"spinner",id:"spinner",title:"Spinner",description:"@oclif/core provides a simple ux.action, for more complex progress indicators we recommend using the listr library.",source:"@site/../docs/spinner.md",sourceDirName:".",slug:"/spinner",permalink:"/docs/spinner",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/spinner.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Spinner"},sidebar:"docs",previous:{title:"Prompting",permalink:"/docs/prompting"},next:{title:"Table",permalink:"/docs/table"}},l={},u=[{value:"ux.action",id:"uxaction",level:2},{value:"listr",id:"listr",level:2}],d={toc:u},m="wrapper";function f(e){var t=e.components,s=(0,o.Z)(e,i);return(0,a.kt)(m,(0,n.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core"},"@oclif/core")," provides a simple ",(0,a.kt)("inlineCode",{parentName:"p"},"ux.action"),", for more complex progress indicators we recommend using the ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/listr"},"listr")," library."),(0,a.kt)("h2",{id:"uxaction"},(0,a.kt)("inlineCode",{parentName:"h2"},"ux.action")),(0,a.kt)("p",null,"Shows a basic spinner"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport class MyCommand extends Command {\n async run() {\n // start the spinner\n ux.action.start('starting a process')\n // do some action...\n // stop the spinner\n ux.action.stop() // shows 'starting a process... done'\n\n // show on stdout instead of stderr\n ux.action.start('starting a process', 'initializing', {stdout: true})\n // do some action...\n // stop the spinner with a custom message\n ux.action.stop('custom message') // shows 'starting a process... custom message'\n }\n}\n")),(0,a.kt)("p",null,"This degrades gracefully when not connected to a TTY. It queues up any writes to stdout/stderr so they are displayed above the spinner."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"action demo",src:r(1305).Z,width:"563",height:"271"})),(0,a.kt)("h2",{id:"listr"},"listr"),(0,a.kt)("p",null,"Here is an example of the complex workflows supported by ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/listr"},"listr"),"."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"listr demo",src:r(3220).Z,width:"1177",height:"709"})))}f.isMDXComponent=!0},1305:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/action-3dc2f1c9da2526e7dacc7ba55a2e3f5a.gif"},3220:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/listr-fb034a43c5d3159c331547ffba3b6559.gif"}}]); \ No newline at end of file diff --git a/assets/js/258a6413.3eeaaf68.js b/assets/js/258a6413.fb7ccdd8.js similarity index 96% rename from assets/js/258a6413.3eeaaf68.js rename to assets/js/258a6413.fb7ccdd8.js index a3866329..8089454a 100644 --- a/assets/js/258a6413.3eeaaf68.js +++ b/assets/js/258a6413.fb7ccdd8.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2265],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},m=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=o,f=p["".concat(c,".").concat(d)]||p[d]||u[d]||a;return n?r.createElement(f,i(i({ref:t},m),{},{components:n})):r.createElement(f,i({ref:t},m))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>c,default:()=>f,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],l={title:"Single Command CLI"},c=void 0,s={unversionedId:"single_command_cli",id:"single_command_cli",title:"Single Command CLI",description:"Sometimes you may want your CLI's executable to also be the only command, similar to many bash utilities like ls or cat.",source:"@site/../docs/single_command_cli.md",sourceDirName:".",slug:"/single_command_cli",permalink:"/docs/single_command_cli",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/single_command_cli.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Single Command CLI"},sidebar:"docs",previous:{title:"Global Flags",permalink:"/docs/global_flags"},next:{title:"ESM",permalink:"/docs/esm"}},m={},p=[],u={toc:p},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,i);return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Sometimes you may want your CLI's executable to also be the only command, similar to many bash utilities like ",(0,a.kt)("inlineCode",{parentName:"p"},"ls")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"cat"),"."),(0,a.kt)("p",null,"To support this, you will need to put your command logic into ",(0,a.kt)("inlineCode",{parentName:"p"},"src/index.ts")," and add the following to the oclif section of your package.json:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "single",\n "target": "./dist/index.js"\n }\n }\n}\n')),(0,a.kt)("p",null,"See ",(0,a.kt)("a",{parentName:"p",href:"./command_discovery_strategies"},"Command Discovery Strategies")," for more details."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2265],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},m=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),p=s(n),d=o,f=p["".concat(c,".").concat(d)]||p[d]||u[d]||a;return n?r.createElement(f,i(i({ref:t},m),{},{components:n})):r.createElement(f,i({ref:t},m))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>c,default:()=>f,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],l={title:"Single Command CLI"},c=void 0,s={unversionedId:"single_command_cli",id:"single_command_cli",title:"Single Command CLI",description:"Sometimes you may want your CLI's executable to also be the only command, similar to many bash utilities like ls or cat.",source:"@site/../docs/single_command_cli.md",sourceDirName:".",slug:"/single_command_cli",permalink:"/docs/single_command_cli",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/single_command_cli.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Single Command CLI"},sidebar:"docs",previous:{title:"Global Flags",permalink:"/docs/global_flags"},next:{title:"ESM",permalink:"/docs/esm"}},m={},p=[],u={toc:p},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,i);return(0,a.kt)(d,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Sometimes you may want your CLI's executable to also be the only command, similar to many bash utilities like ",(0,a.kt)("inlineCode",{parentName:"p"},"ls")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"cat"),"."),(0,a.kt)("p",null,"To support this, you will need to put your command logic into ",(0,a.kt)("inlineCode",{parentName:"p"},"src/index.ts")," and add the following to the oclif section of your package.json:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "single",\n "target": "./dist/index.js"\n }\n }\n}\n')),(0,a.kt)("p",null,"See ",(0,a.kt)("a",{parentName:"p",href:"./command_discovery_strategies"},"Command Discovery Strategies")," for more details."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2a33acc4.d46170c8.js b/assets/js/2a33acc4.1213b158.js similarity index 98% rename from assets/js/2a33acc4.d46170c8.js rename to assets/js/2a33acc4.1213b158.js index 1a88817e..e8f664f0 100644 --- a/assets/js/2a33acc4.d46170c8.js +++ b/assets/js/2a33acc4.1213b158.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9244],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=p(n),f=o,m=d["".concat(s,".").concat(f)]||d[f]||u[f]||i;return n?r.createElement(m,a(a({ref:t},l),{},{components:n})):r.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:o,a[1]=c;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>c,metadata:()=>p,toc:()=>d});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],c={title:"Topics"},s=void 0,p={unversionedId:"topics",id:"topics",title:"Topics",description:"As CLIs grow it can be useful to nest commands within topics. This is supported simply by placing command files in subdirectories. For example, with the Salesforce CLI we have a topic sf config with commands like sf config set and sf config get. The directory structure looks like this:",source:"@site/../docs/topics.md",sourceDirName:".",slug:"/topics",permalink:"/docs/topics",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/topics.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Topics"},sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/config"},next:{title:"Topic Separators",permalink:"/docs/topic_separator"}},l={},d=[],u={toc:d},f="wrapper";function m(e){var t=e.components,n=(0,o.Z)(e,a);return(0,i.kt)(f,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"As CLIs grow it can be useful to nest commands within topics. This is supported simply by placing command files in subdirectories. For example, with the Salesforce CLI we have a topic ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config")," with commands like ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config set")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config get"),". The directory structure looks like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"package.json\nsrc/\n\u2514\u2500\u2500 commands/\n \u2514\u2500\u2500 config/\n \xa0 \u251c\u2500\u2500 index.ts\n \xa0\xa0\u251c\u2500\u2500 set.ts\n \xa0\xa0 \u2514\u2500\u2500 get.ts\n")),(0,i.kt)("p",null,"The help descriptions will be the description of the first command within a directory. If you'd like to customize the help description, add it to the ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json")," like so:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'{\n "oclif": {\n "topics": {\n "apps:favorites": { "description": "manage favorite apps" },\n "config": { "description": "manage heroku config variables" },\n }\n }\n}\n')),(0,i.kt)("p",null,"Subtopics can be created by making subdirectories within topic directories, but for UX reasons we generally discourage going more than 1 or 2 levels deep even for the largest CLIs."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9244],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=p(n),f=o,m=d["".concat(s,".").concat(f)]||d[f]||u[f]||i;return n?r.createElement(m,a(a({ref:t},l),{},{components:n})):r.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:o,a[1]=c;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>c,metadata:()=>p,toc:()=>d});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],c={title:"Topics"},s=void 0,p={unversionedId:"topics",id:"topics",title:"Topics",description:"As CLIs grow it can be useful to nest commands within topics. This is supported simply by placing command files in subdirectories. For example, with the Salesforce CLI we have a topic sf config with commands like sf config set and sf config get. The directory structure looks like this:",source:"@site/../docs/topics.md",sourceDirName:".",slug:"/topics",permalink:"/docs/topics",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/topics.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Topics"},sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/config"},next:{title:"Topic Separators",permalink:"/docs/topic_separator"}},l={},d=[],u={toc:d},f="wrapper";function m(e){var t=e.components,n=(0,o.Z)(e,a);return(0,i.kt)(f,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"As CLIs grow it can be useful to nest commands within topics. This is supported simply by placing command files in subdirectories. For example, with the Salesforce CLI we have a topic ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config")," with commands like ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config set")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"sf config get"),". The directory structure looks like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"package.json\nsrc/\n\u2514\u2500\u2500 commands/\n \u2514\u2500\u2500 config/\n \xa0 \u251c\u2500\u2500 index.ts\n \xa0\xa0\u251c\u2500\u2500 set.ts\n \xa0\xa0 \u2514\u2500\u2500 get.ts\n")),(0,i.kt)("p",null,"The help descriptions will be the description of the first command within a directory. If you'd like to customize the help description, add it to the ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json")," like so:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},'{\n "oclif": {\n "topics": {\n "apps:favorites": { "description": "manage favorite apps" },\n "config": { "description": "manage heroku config variables" },\n }\n }\n}\n')),(0,i.kt)("p",null,"Subtopics can be created by making subdirectories within topic directories, but for UX reasons we generally discourage going more than 1 or 2 levels deep even for the largest CLIs."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2f98ad87.07ccdeec.js b/assets/js/2f98ad87.28a95877.js similarity index 98% rename from assets/js/2f98ad87.07ccdeec.js rename to assets/js/2f98ad87.28a95877.js index 4d8331c7..d17aab9d 100644 --- a/assets/js/2f98ad87.07ccdeec.js +++ b/assets/js/2f98ad87.28a95877.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2048],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>u});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),m=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=m(e.components);return r.createElement(l.Provider,{value:n},e.children)},d="mdxType",f={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},s=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=m(t),s=o,u=d["".concat(l,".").concat(s)]||d[s]||f[s]||a;return t?r.createElement(u,i(i({ref:n},p),{},{components:t})):r.createElement(u,i({ref:n},p))}));function u(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=s;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var m=2;m{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>u,frontMatter:()=>c,metadata:()=>m,toc:()=>d});var r=t(7462),o=t(3366),a=(t(7294),t(3905)),i=["components"],c={title:"Generator Commands"},l=void 0,m={unversionedId:"generator_commands",id:"generator_commands",title:"Generator Commands",description:"- oclif generate NAME",source:"@site/../docs/generator_commands.md",sourceDirName:".",slug:"/generator_commands",permalink:"/docs/generator_commands",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/generator_commands.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Generator Commands"},sidebar:"docs",previous:{title:"FAQs",permalink:"/docs/faqs"},next:{title:"Command Execution",permalink:"/docs/command_execution"}},p={},d=[{value:"oclif generate NAME",id:"oclif-generate-name",level:2},{value:"oclif generate command NAME",id:"oclif-generate-command-name",level:2},{value:"oclif generate hook NAME",id:"oclif-generate-hook-name",level:2}],f={toc:d},s="wrapper";function u(e){var n=e.components,t=(0,o.Z)(e,i);return(0,a.kt)(s,(0,r.Z)({},f,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate NAME"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-command-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate command NAME"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-hook-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate hook NAME")))),(0,a.kt)("h2",{id:"oclif-generate-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate NAME")),(0,a.kt)("p",null,"generate a new CLI"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate [NAME]\n\nARGUMENTS\n NAME directory name of new project\n\nDESCRIPTION\n generate a new CLI\n\n This will clone the template repo 'oclif/hello-world' and update package properties\n")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"See code: ",(0,a.kt)("a",{parentName:"em",href:"https://github.com/oclif/oclif/blob/v2.2.0/src/commands/generate.ts"},"src/commands/generate.ts"))),(0,a.kt)("h2",{id:"oclif-generate-command-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate command NAME")),(0,a.kt)("p",null,"add a command to an existing CLI or plugin"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate command [NAME] [--force]\n\nARGUMENTS\n NAME name of command\n\nFLAGS\n --force overwrite existing files\n\nDESCRIPTION\n add a command to an existing CLI or plugin\n")),(0,a.kt)("h2",{id:"oclif-generate-hook-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate hook NAME")),(0,a.kt)("p",null,"add a hook to an existing CLI or plugin"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate hook [NAME] [--force] [--event ]\n\nARGUMENTS\n NAME name of hook (snake_case)\n\nFLAGS\n --event= [default: init] event to run hook on\n --force overwrite existing files\n\nDESCRIPTION\n add a hook to an existing CLI or plugin\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2048],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>u});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),m=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=m(e.components);return r.createElement(l.Provider,{value:n},e.children)},d="mdxType",f={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},s=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=m(t),s=o,u=d["".concat(l,".").concat(s)]||d[s]||f[s]||a;return t?r.createElement(u,i(i({ref:n},p),{},{components:t})):r.createElement(u,i({ref:n},p))}));function u(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=s;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var m=2;m{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>u,frontMatter:()=>c,metadata:()=>m,toc:()=>d});var r=t(7462),o=t(3366),a=(t(7294),t(3905)),i=["components"],c={title:"Generator Commands"},l=void 0,m={unversionedId:"generator_commands",id:"generator_commands",title:"Generator Commands",description:"- oclif generate NAME",source:"@site/../docs/generator_commands.md",sourceDirName:".",slug:"/generator_commands",permalink:"/docs/generator_commands",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/generator_commands.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Generator Commands"},sidebar:"docs",previous:{title:"FAQs",permalink:"/docs/faqs"},next:{title:"Command Execution",permalink:"/docs/command_execution"}},p={},d=[{value:"oclif generate NAME",id:"oclif-generate-name",level:2},{value:"oclif generate command NAME",id:"oclif-generate-command-name",level:2},{value:"oclif generate hook NAME",id:"oclif-generate-hook-name",level:2}],f={toc:d},s="wrapper";function u(e){var n=e.components,t=(0,o.Z)(e,i);return(0,a.kt)(s,(0,r.Z)({},f,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate NAME"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-command-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate command NAME"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#oclif-generate-hook-name"},(0,a.kt)("inlineCode",{parentName:"a"},"oclif generate hook NAME")))),(0,a.kt)("h2",{id:"oclif-generate-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate NAME")),(0,a.kt)("p",null,"generate a new CLI"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate [NAME]\n\nARGUMENTS\n NAME directory name of new project\n\nDESCRIPTION\n generate a new CLI\n\n This will clone the template repo 'oclif/hello-world' and update package properties\n")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"See code: ",(0,a.kt)("a",{parentName:"em",href:"https://github.com/oclif/oclif/blob/v2.2.0/src/commands/generate.ts"},"src/commands/generate.ts"))),(0,a.kt)("h2",{id:"oclif-generate-command-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate command NAME")),(0,a.kt)("p",null,"add a command to an existing CLI or plugin"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate command [NAME] [--force]\n\nARGUMENTS\n NAME name of command\n\nFLAGS\n --force overwrite existing files\n\nDESCRIPTION\n add a command to an existing CLI or plugin\n")),(0,a.kt)("h2",{id:"oclif-generate-hook-name"},(0,a.kt)("inlineCode",{parentName:"h2"},"oclif generate hook NAME")),(0,a.kt)("p",null,"add a hook to an existing CLI or plugin"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"USAGE\n $ oclif generate hook [NAME] [--force] [--event ]\n\nARGUMENTS\n NAME name of hook (snake_case)\n\nFLAGS\n --event= [default: init] event to run hook on\n --force overwrite existing files\n\nDESCRIPTION\n add a hook to an existing CLI or plugin\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3042343a.cb8ecb82.js b/assets/js/3042343a.6f606eba.js similarity index 99% rename from assets/js/3042343a.cb8ecb82.js rename to assets/js/3042343a.6f606eba.js index 43d78ea6..6f09cad0 100644 --- a/assets/js/3042343a.cb8ecb82.js +++ b/assets/js/3042343a.6f606eba.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5917],{3905:(e,a,n)=>{n.d(a,{Zo:()=>c,kt:()=>g});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function o(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var i=t.createContext({}),f=function(e){var a=t.useContext(i),n=a;return e&&(n="function"==typeof e?e(a):o(o({},a),e)),n},c=function(e){var a=f(e.components);return t.createElement(i.Provider,{value:a},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},p=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=f(n),p=l,g=u["".concat(i,".").concat(p)]||u[p]||m[p]||r;return n?t.createElement(g,o(o({ref:a},c),{},{components:n})):t.createElement(g,o({ref:a},c))}));function g(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=p;var s={};for(var i in a)hasOwnProperty.call(a,i)&&(s[i]=a[i]);s.originalType=e,s[u]="string"==typeof e?e:l,o[1]=s;for(var f=2;f{n.r(a),n.d(a,{assets:()=>c,contentTitle:()=>i,default:()=>g,frontMatter:()=>s,metadata:()=>f,toc:()=>u});var t=n(7462),l=n(3366),r=(n(7294),n(3905)),o=["components"],s={title:"Command Flags"},i=void 0,f={unversionedId:"flags",id:"flags",title:"Command Flags",description:"Flag options are non-positional arguments passed to the command. Flags can either be option flags which take an argument, or boolean flags which do not. An option flag must have an argument.",source:"@site/../docs/flags.md",sourceDirName:".",slug:"/flags",permalink:"/docs/flags",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/flags.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Flags"},sidebar:"docs",previous:{title:"Command Arguments",permalink:"/docs/args"},next:{title:"Configuration",permalink:"/docs/config"}},c={},u=[{value:"Custom Flags",id:"custom-flags",level:2},{value:"Alternative Flag Inputs",id:"alternative-flag-inputs",level:2}],m={toc:u},p="wrapper";function g(e){var a=e.components,n=(0,l.Z)(e,o);return(0,r.kt)(p,(0,t.Z)({},m,n,{components:a,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Flag options are non-positional arguments passed to the command. Flags can either be option flags which take an argument, or boolean flags which do not. An option flag must have an argument."),(0,r.kt)("p",null,"For example, if this command was run like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ mycli --force --file=./myfile\n")),(0,r.kt)("p",null,"It would be declared like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static flags = {\n // can pass either --force or -f\n force: Flags.boolean({char: 'f'}),\n file: Flags.string(),\n }\n\n async run() {\n const {flags} = await this.parse(MyCLI)\n if (flags.force) console.log('--force is set')\n if (flags.file) console.log(`--file is: ${flags.file}`)\n }\n}\n")),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"oclif supports a wide range of ",(0,r.kt)("a",{parentName:"em",href:"#alternative-flag-inputs"},"alternative flag inputs"),".")),(0,r.kt)("p",null,"Here are the options flags can have:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"static flags = {\n name: Flags.string({\n char: 'n', // shorter flag version\n summary: 'brief summary', // help summary for flag\n helpGroup: 'THE BEST FLAGS', // Put flag into THE BEST FLAGS group in help\n description: 'in-depth overview', // help description for flag\n hidden: false, // hide from help\n multiple: false, // allow setting this flag multiple times\n env: 'MY_NAME', // default to value of environment variable\n options: ['a', 'b'], // only allow the value to be from a discrete set\n parse: async input => 'output', // instead of the user input, return a different value\n default: 'world', // default value if flag not passed (can be an async function that returns a string or undefined)\n defaultHelp: 'a dynamic value' // dyanmic default value to show in help output (e.g. current working directory). Can be an async function that returns a string or undefined\n required: false, // make flag required\n aliases: ['username', 'u'], // aliases for the flag - can be short char or long flags\n deprecateAliases: false, // emit deprecation warning anytime a flag alias is provided\n dependsOn: ['extra-flag'], // this flag requires another flag\n exclusive: ['extra-flag'], // this flag cannot be specified alongside this other flag\n exactlyOne: ['extra-flag', 'another-flag'], // exactly one of these flags must be provided\n relationships: [ // define complex relationships between flags\n // Make this flag dependent on all of these flags\n {type: 'all', flags: ['flag-one', 'flag-two']}\n // Make this flag dependent on at least one of these flags\n {type: 'some', flags: ['flag-three', 'flag-four']}\n // Make this flag exclusive of all these flags\n {type: 'none', flags: ['flag-five', 'flag-six']}\n\n // Make this flag dependent on all of these flags\n {type: 'all', flags: [\n 'flag-one',\n 'flag-two',\n // Include flag-seven but only when flag-eight is equal to FooBar\n {name: 'flag-seven', when: async (flags) => flags['flag-eight'] === 'FooBar'}\n ]}\n ]\n }),\n\n // flag with no value (-f, --force)\n force: Flags.boolean({\n char: 'f', // short character for flag\n default: true, // default value if flag not passed (can be a function that returns a boolean)\n env: 'MY_NAME', // default value to the value of an environment variable\n // boolean flags may be reversed with `--no-` (in this case: `--no-force`).\n // The flag will be set to false if reversed. This functionality\n // is disabled by default, to enable it:\n // allowNo: true\n }),\n}\n")),(0,r.kt)("h2",{id:"custom-flags"},"Custom Flags"),(0,r.kt)("p",null,"For larger CLIs, it can be useful to declare a custom flag that can be shared amongst multiple commands. Here is an example of a custom flag:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"// src/flags.ts\nimport {Flags} from '@oclif/core'\n\nclass Team {\n public name: string;\n // etc...\n}\n\nfunction getTeam(): Promise {\n // imagine this reads a configuration file or something to find the team\n return new Team()\n}\n\nexport const team = Flags.custom({\n char: 't',\n description: 'team to use',\n default: () => getTeam(),\n})\n\n// src/commands/mycommand.ts\nimport {team} from '../flags'\nimport {Command} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static flags = {\n team: team(),\n }\n\n async run() {\n const {flags} = await this.parse(MyCLI)\n if (flags.team) console.log(`--team is ${flags.team.name}`)\n }\n}\n")),(0,r.kt)("p",null,"In the Salesforce CLI we make heavy use of custom flags. For example,"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A ",(0,r.kt)("a",{parentName:"li",href:"https://salesforcecli.github.io/sf-plugins-core/functions/flags_salesforceId.salesforceIdFlag.html"},(0,r.kt)("inlineCode",{parentName:"a"},"salesforceId"))," flag that ensures the provided string is a valid Salesforce Id."),(0,r.kt)("li",{parentName:"ul"},"A ",(0,r.kt)("a",{parentName:"li",href:"https://salesforcecli.github.io/sf-plugins-core/functions/flags_duration.durationFlag.html"},(0,r.kt)("inlineCode",{parentName:"a"},"duration"))," flag that converts a provided integer into a ",(0,r.kt)("inlineCode",{parentName:"li"},"Duration")," instance that we use for working with time based values.")),(0,r.kt)("p",null,"These and more are located ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/sf-plugins-core/tree/main/src/flags"},"here")," if you want to see more examples. You can also read the ",(0,r.kt)("a",{parentName:"p",href:"https://salesforcecli.github.io/sf-plugins-core/"},"API docs"),"."),(0,r.kt)("h2",{id:"alternative-flag-inputs"},"Alternative Flag Inputs"),(0,r.kt)("p",null,"Here are some other ways the user can use input flags. This is assuming the command has flags like ",(0,r.kt)("inlineCode",{parentName:"p"},"-f, --file=file")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"-v, --verbose")," (string and boolean flag):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ mycli --verbose\n$ mycli -v\n$ mycli --file=foo\n$ mycli --file foo\n$ mycli -f foo\n$ mycli -f=foo\n$ mycli -ffoo\n$ mycli -vffoo\n")),(0,r.kt)("p",null,"The last one seems a little odd at first glance, but it's relatively standard in unix and makes commands like ",(0,r.kt)("inlineCode",{parentName:"p"},"tar -xvzfmytarball.tar.gz")," possible."))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5917],{3905:(e,a,n)=>{n.d(a,{Zo:()=>c,kt:()=>g});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function o(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var i=t.createContext({}),f=function(e){var a=t.useContext(i),n=a;return e&&(n="function"==typeof e?e(a):o(o({},a),e)),n},c=function(e){var a=f(e.components);return t.createElement(i.Provider,{value:a},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},p=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=f(n),p=l,g=u["".concat(i,".").concat(p)]||u[p]||m[p]||r;return n?t.createElement(g,o(o({ref:a},c),{},{components:n})):t.createElement(g,o({ref:a},c))}));function g(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=p;var s={};for(var i in a)hasOwnProperty.call(a,i)&&(s[i]=a[i]);s.originalType=e,s[u]="string"==typeof e?e:l,o[1]=s;for(var f=2;f{n.r(a),n.d(a,{assets:()=>c,contentTitle:()=>i,default:()=>g,frontMatter:()=>s,metadata:()=>f,toc:()=>u});var t=n(7462),l=n(3366),r=(n(7294),n(3905)),o=["components"],s={title:"Command Flags"},i=void 0,f={unversionedId:"flags",id:"flags",title:"Command Flags",description:"Flag options are non-positional arguments passed to the command. Flags can either be option flags which take an argument, or boolean flags which do not. An option flag must have an argument.",source:"@site/../docs/flags.md",sourceDirName:".",slug:"/flags",permalink:"/docs/flags",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/flags.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Flags"},sidebar:"docs",previous:{title:"Command Arguments",permalink:"/docs/args"},next:{title:"Configuration",permalink:"/docs/config"}},c={},u=[{value:"Custom Flags",id:"custom-flags",level:2},{value:"Alternative Flag Inputs",id:"alternative-flag-inputs",level:2}],m={toc:u},p="wrapper";function g(e){var a=e.components,n=(0,l.Z)(e,o);return(0,r.kt)(p,(0,t.Z)({},m,n,{components:a,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Flag options are non-positional arguments passed to the command. Flags can either be option flags which take an argument, or boolean flags which do not. An option flag must have an argument."),(0,r.kt)("p",null,"For example, if this command was run like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ mycli --force --file=./myfile\n")),(0,r.kt)("p",null,"It would be declared like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static flags = {\n // can pass either --force or -f\n force: Flags.boolean({char: 'f'}),\n file: Flags.string(),\n }\n\n async run() {\n const {flags} = await this.parse(MyCLI)\n if (flags.force) console.log('--force is set')\n if (flags.file) console.log(`--file is: ${flags.file}`)\n }\n}\n")),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"oclif supports a wide range of ",(0,r.kt)("a",{parentName:"em",href:"#alternative-flag-inputs"},"alternative flag inputs"),".")),(0,r.kt)("p",null,"Here are the options flags can have:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"static flags = {\n name: Flags.string({\n char: 'n', // shorter flag version\n summary: 'brief summary', // help summary for flag\n helpGroup: 'THE BEST FLAGS', // Put flag into THE BEST FLAGS group in help\n description: 'in-depth overview', // help description for flag\n hidden: false, // hide from help\n multiple: false, // allow setting this flag multiple times\n env: 'MY_NAME', // default to value of environment variable\n options: ['a', 'b'], // only allow the value to be from a discrete set\n parse: async input => 'output', // instead of the user input, return a different value\n default: 'world', // default value if flag not passed (can be an async function that returns a string or undefined)\n defaultHelp: 'a dynamic value' // dyanmic default value to show in help output (e.g. current working directory). Can be an async function that returns a string or undefined\n required: false, // make flag required\n aliases: ['username', 'u'], // aliases for the flag - can be short char or long flags\n deprecateAliases: false, // emit deprecation warning anytime a flag alias is provided\n dependsOn: ['extra-flag'], // this flag requires another flag\n exclusive: ['extra-flag'], // this flag cannot be specified alongside this other flag\n exactlyOne: ['extra-flag', 'another-flag'], // exactly one of these flags must be provided\n relationships: [ // define complex relationships between flags\n // Make this flag dependent on all of these flags\n {type: 'all', flags: ['flag-one', 'flag-two']}\n // Make this flag dependent on at least one of these flags\n {type: 'some', flags: ['flag-three', 'flag-four']}\n // Make this flag exclusive of all these flags\n {type: 'none', flags: ['flag-five', 'flag-six']}\n\n // Make this flag dependent on all of these flags\n {type: 'all', flags: [\n 'flag-one',\n 'flag-two',\n // Include flag-seven but only when flag-eight is equal to FooBar\n {name: 'flag-seven', when: async (flags) => flags['flag-eight'] === 'FooBar'}\n ]}\n ]\n }),\n\n // flag with no value (-f, --force)\n force: Flags.boolean({\n char: 'f', // short character for flag\n default: true, // default value if flag not passed (can be a function that returns a boolean)\n env: 'MY_NAME', // default value to the value of an environment variable\n // boolean flags may be reversed with `--no-` (in this case: `--no-force`).\n // The flag will be set to false if reversed. This functionality\n // is disabled by default, to enable it:\n // allowNo: true\n }),\n}\n")),(0,r.kt)("h2",{id:"custom-flags"},"Custom Flags"),(0,r.kt)("p",null,"For larger CLIs, it can be useful to declare a custom flag that can be shared amongst multiple commands. Here is an example of a custom flag:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"// src/flags.ts\nimport {Flags} from '@oclif/core'\n\nclass Team {\n public name: string;\n // etc...\n}\n\nfunction getTeam(): Promise {\n // imagine this reads a configuration file or something to find the team\n return new Team()\n}\n\nexport const team = Flags.custom({\n char: 't',\n description: 'team to use',\n default: () => getTeam(),\n})\n\n// src/commands/mycommand.ts\nimport {team} from '../flags'\nimport {Command} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static flags = {\n team: team(),\n }\n\n async run() {\n const {flags} = await this.parse(MyCLI)\n if (flags.team) console.log(`--team is ${flags.team.name}`)\n }\n}\n")),(0,r.kt)("p",null,"In the Salesforce CLI we make heavy use of custom flags. For example,"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"A ",(0,r.kt)("a",{parentName:"li",href:"https://salesforcecli.github.io/sf-plugins-core/functions/flags_salesforceId.salesforceIdFlag.html"},(0,r.kt)("inlineCode",{parentName:"a"},"salesforceId"))," flag that ensures the provided string is a valid Salesforce Id."),(0,r.kt)("li",{parentName:"ul"},"A ",(0,r.kt)("a",{parentName:"li",href:"https://salesforcecli.github.io/sf-plugins-core/functions/flags_duration.durationFlag.html"},(0,r.kt)("inlineCode",{parentName:"a"},"duration"))," flag that converts a provided integer into a ",(0,r.kt)("inlineCode",{parentName:"li"},"Duration")," instance that we use for working with time based values.")),(0,r.kt)("p",null,"These and more are located ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/sf-plugins-core/tree/main/src/flags"},"here")," if you want to see more examples. You can also read the ",(0,r.kt)("a",{parentName:"p",href:"https://salesforcecli.github.io/sf-plugins-core/"},"API docs"),"."),(0,r.kt)("h2",{id:"alternative-flag-inputs"},"Alternative Flag Inputs"),(0,r.kt)("p",null,"Here are some other ways the user can use input flags. This is assuming the command has flags like ",(0,r.kt)("inlineCode",{parentName:"p"},"-f, --file=file")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"-v, --verbose")," (string and boolean flag):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ mycli --verbose\n$ mycli -v\n$ mycli --file=foo\n$ mycli --file foo\n$ mycli -f foo\n$ mycli -f=foo\n$ mycli -ffoo\n$ mycli -vffoo\n")),(0,r.kt)("p",null,"The last one seems a little odd at first glance, but it's relatively standard in unix and makes commands like ",(0,r.kt)("inlineCode",{parentName:"p"},"tar -xvzfmytarball.tar.gz")," possible."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/30d74566.5738672b.js b/assets/js/30d74566.3e37533e.js similarity index 99% rename from assets/js/30d74566.5738672b.js rename to assets/js/30d74566.3e37533e.js index 2d67f95c..15f3cae6 100644 --- a/assets/js/30d74566.5738672b.js +++ b/assets/js/30d74566.3e37533e.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8472],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),p=d(n),u=o,f=p["".concat(s,".").concat(u)]||p[u]||m[u]||i;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[p]="string"==typeof e?e:o,l[1]=r;for(var d=2;d{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>f,frontMatter:()=>r,metadata:()=>d,toc:()=>p});var a=n(7462),o=n(3366),i=(n(7294),n(3905)),l=["components"],r={title:"Command Discovery Strategies"},s=void 0,d={unversionedId:"command_discovery_strategies",id:"command_discovery_strategies",title:"Command Discovery Strategies",description:"When oclif loads a plugin is must find all the commands within that plugin that can be executed. There a three strategies for discovering these commands:",source:"@site/../docs/command_discovery_strategies.md",sourceDirName:".",slug:"/command_discovery_strategies",permalink:"/docs/command_discovery_strategies",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/command_discovery_strategies.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Discovery Strategies"},sidebar:"docs",previous:{title:"Plugin Loading",permalink:"/docs/plugin_loading"},next:{title:"Commands",permalink:"/docs/commands"}},c={},p=[{value:"pattern Strategy",id:"pattern-strategy",level:3},{value:"explicit Strategy",id:"explicit-strategy",level:3},{value:"Hooks",id:"hooks",level:4},{value:"Bundling",id:"bundling",level:4},{value:"single Strategy",id:"single-strategy",level:3},{value:"Note about oclif.manifest.json",id:"note-about-oclifmanifestjson",level:3}],m={toc:p},u="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,l);return(0,i.kt)(u,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"When oclif loads a plugin is must find all the commands within that plugin that can be executed. There a three strategies for discovering these commands:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"pattern")," - this is the default behavior that finds commands based on glob patterns."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"explicit")," - find commands that are exported from a specified file."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"single")," - CLI contains a single command executed by top-level bin.")),(0,i.kt)("h3",{id:"pattern-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"pattern")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"pattern")," strategy tells oclif to use a predefined set of globs to find command files in a specified directory. This is the default behavior of oclif unless otherwise stated."),(0,i.kt)("p",null,"Plugins can point the ",(0,i.kt)("inlineCode",{parentName:"p"},"commands")," property to a directory"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": "./dist/commands",\n }\n}\n')),(0,i.kt)("p",null,"This will tell oclif to look for commands in that directory (this is skipped if an ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," is present)"),(0,i.kt)("p",null,"Alternatively, you can set this configuration which will do the exact same thing:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "pattern",\n "target": "./dist/commands"\n }\n }\n}\n')),(0,i.kt)("p",null,"You also have the ability to set ",(0,i.kt)("inlineCode",{parentName:"p"},"globPatterns"),", which override the glob patterns that oclif uses when searching for command files:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "pattern",\n "target": "./dist/commands",\n "globPatterns": [\n "**/*.+(js|cjs|mjs|ts|tsx|mts|cts)",\n "!**/*.+(d.*|test.*|spec.*|helpers.*)?(x)"\n ]\n }\n }\n}\n')),(0,i.kt)("p",null,"This is useful if you like to put test or helper files in the same directory as your command files."),(0,i.kt)("h3",{id:"explicit-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"explicit")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy tells oclif to import commands from a single file. In this case the ",(0,i.kt)("inlineCode",{parentName:"p"},"target")," is the file that exports the commands and ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier")," is the name of the export (defaults to ",(0,i.kt)("inlineCode",{parentName:"p"},"default"),")."),(0,i.kt)("p",null,"To use this you would add a new file (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"src/commands.ts"),") and then add this configuration to the package.json"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "explicit",\n "target": "./dist/index.js",\n "identifier": "COMMANDS",\n }\n }\n}\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"src/index.ts")," would then need to have an export with the same name as the ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier")," (if not set, it defaults to ",(0,i.kt)("inlineCode",{parentName:"p"},"default"),") that's an object of command names to command classes, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import Hello from './commands/hello'\nimport HelloWorld from './commands/hello/world'\n\nexport const COMMANDS = {\n hello: Hello,\n 'hello:world': HelloWorld,\n howdy: Hello, // alias the `hello` command to `howdy`\n}\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy is useful to those who can't rely on file paths because they've bundled their code (see ",(0,i.kt)("a",{parentName:"p",href:"#bundling"},"Bundling"),') but it can also be used if you simply prefer to be more explicit about your commands instead of relying on oclif "magically" finding commands from the file system.'),(0,i.kt)("p",null,"It can also be leveraged to create or modify commands at runtime (e.g. internationalize messages at runtime or add flags to a command based on an API spec - see ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif + dynamic commands")," section below)."),(0,i.kt)("h4",{id:"hooks"},"Hooks"),(0,i.kt)("p",null,"Hooks can also be defined using the ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"oclif": {\n "hooks": {\n "init": {\n "target": "./dist/index.js",\n "identifier": "INIT_HOOK"\n }\n }\n}\n')),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"// src/index.ts\nimport Hello from './commands/hello'\nimport HelloWorld from './commands/hello/world'\nexport {default as INIT_HOOK} from './hooks/init/init.js'\n\nexport const COMMANDS = {\n hello: Hello,\n 'hello:world': HelloWorld,\n howdy: Hello, // alias the `hello` command to `howdy`\n}\n")),(0,i.kt)("p",null,"That configuration is essentially telling oclif to look for an ",(0,i.kt)("inlineCode",{parentName:"p"},"INIT_HOOK")," export inside of ",(0,i.kt)("inlineCode",{parentName:"p"},"./dist/index.js")),(0,i.kt)("h4",{id:"bundling"},"Bundling"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"We do not support bundling")," given the endless number of tools + configurations that could be used. But if you choose to use a bundler, like ",(0,i.kt)("inlineCode",{parentName:"p"},"esbuild")," there are a couple hard requirements - you must have a package.json in your root directory and a ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run.js")," bin script. ",(0,i.kt)("em",{parentName:"p"},"This means that you will not be able to successfully bundle your entire CLI (src code, package.json, node_modules, etc) into a single file.")),(0,i.kt)("p",null,"If you want to use a bundler, you can see this ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-test-esbuild/"},"example repo"),"."),(0,i.kt)("h3",{id:"single-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"single")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"single")," strategy tells oclif that this CLI contains a single command that can be executed by the ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run.js")," (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"ls")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"cat"),")."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "single",\n "target": "./dist/index.js"\n }\n }\n}\n')),(0,i.kt)("p",null,"In this example, ",(0,i.kt)("inlineCode",{parentName:"p"},"./dist/index.js")," exports the command class."),(0,i.kt)("h3",{id:"note-about-oclifmanifestjson"},"Note about ",(0,i.kt)("inlineCode",{parentName:"h3"},"oclif.manifest.json")),(0,i.kt)("p",null,"For all strategies, the ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," will be used to load the commands instead of the default behavior of the strategy."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8472],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),p=d(n),u=o,f=p["".concat(s,".").concat(u)]||p[u]||m[u]||i;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[p]="string"==typeof e?e:o,l[1]=r;for(var d=2;d{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>f,frontMatter:()=>r,metadata:()=>d,toc:()=>p});var a=n(7462),o=n(3366),i=(n(7294),n(3905)),l=["components"],r={title:"Command Discovery Strategies"},s=void 0,d={unversionedId:"command_discovery_strategies",id:"command_discovery_strategies",title:"Command Discovery Strategies",description:"When oclif loads a plugin is must find all the commands within that plugin that can be executed. There a three strategies for discovering these commands:",source:"@site/../docs/command_discovery_strategies.md",sourceDirName:".",slug:"/command_discovery_strategies",permalink:"/docs/command_discovery_strategies",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/command_discovery_strategies.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Discovery Strategies"},sidebar:"docs",previous:{title:"Plugin Loading",permalink:"/docs/plugin_loading"},next:{title:"Commands",permalink:"/docs/commands"}},c={},p=[{value:"pattern Strategy",id:"pattern-strategy",level:3},{value:"explicit Strategy",id:"explicit-strategy",level:3},{value:"Hooks",id:"hooks",level:4},{value:"Bundling",id:"bundling",level:4},{value:"single Strategy",id:"single-strategy",level:3},{value:"Note about oclif.manifest.json",id:"note-about-oclifmanifestjson",level:3}],m={toc:p},u="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,l);return(0,i.kt)(u,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"When oclif loads a plugin is must find all the commands within that plugin that can be executed. There a three strategies for discovering these commands:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"pattern")," - this is the default behavior that finds commands based on glob patterns."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"explicit")," - find commands that are exported from a specified file."),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("inlineCode",{parentName:"li"},"single")," - CLI contains a single command executed by top-level bin.")),(0,i.kt)("h3",{id:"pattern-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"pattern")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"pattern")," strategy tells oclif to use a predefined set of globs to find command files in a specified directory. This is the default behavior of oclif unless otherwise stated."),(0,i.kt)("p",null,"Plugins can point the ",(0,i.kt)("inlineCode",{parentName:"p"},"commands")," property to a directory"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": "./dist/commands",\n }\n}\n')),(0,i.kt)("p",null,"This will tell oclif to look for commands in that directory (this is skipped if an ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," is present)"),(0,i.kt)("p",null,"Alternatively, you can set this configuration which will do the exact same thing:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "pattern",\n "target": "./dist/commands"\n }\n }\n}\n')),(0,i.kt)("p",null,"You also have the ability to set ",(0,i.kt)("inlineCode",{parentName:"p"},"globPatterns"),", which override the glob patterns that oclif uses when searching for command files:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "pattern",\n "target": "./dist/commands",\n "globPatterns": [\n "**/*.+(js|cjs|mjs|ts|tsx|mts|cts)",\n "!**/*.+(d.*|test.*|spec.*|helpers.*)?(x)"\n ]\n }\n }\n}\n')),(0,i.kt)("p",null,"This is useful if you like to put test or helper files in the same directory as your command files."),(0,i.kt)("h3",{id:"explicit-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"explicit")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy tells oclif to import commands from a single file. In this case the ",(0,i.kt)("inlineCode",{parentName:"p"},"target")," is the file that exports the commands and ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier")," is the name of the export (defaults to ",(0,i.kt)("inlineCode",{parentName:"p"},"default"),")."),(0,i.kt)("p",null,"To use this you would add a new file (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"src/commands.ts"),") and then add this configuration to the package.json"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "explicit",\n "target": "./dist/index.js",\n "identifier": "COMMANDS",\n }\n }\n}\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"src/index.ts")," would then need to have an export with the same name as the ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier")," (if not set, it defaults to ",(0,i.kt)("inlineCode",{parentName:"p"},"default"),") that's an object of command names to command classes, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import Hello from './commands/hello'\nimport HelloWorld from './commands/hello/world'\n\nexport const COMMANDS = {\n hello: Hello,\n 'hello:world': HelloWorld,\n howdy: Hello, // alias the `hello` command to `howdy`\n}\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy is useful to those who can't rely on file paths because they've bundled their code (see ",(0,i.kt)("a",{parentName:"p",href:"#bundling"},"Bundling"),') but it can also be used if you simply prefer to be more explicit about your commands instead of relying on oclif "magically" finding commands from the file system.'),(0,i.kt)("p",null,"It can also be leveraged to create or modify commands at runtime (e.g. internationalize messages at runtime or add flags to a command based on an API spec - see ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif + dynamic commands")," section below)."),(0,i.kt)("h4",{id:"hooks"},"Hooks"),(0,i.kt)("p",null,"Hooks can also be defined using the ",(0,i.kt)("inlineCode",{parentName:"p"},"explicit")," strategy:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"oclif": {\n "hooks": {\n "init": {\n "target": "./dist/index.js",\n "identifier": "INIT_HOOK"\n }\n }\n}\n')),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"// src/index.ts\nimport Hello from './commands/hello'\nimport HelloWorld from './commands/hello/world'\nexport {default as INIT_HOOK} from './hooks/init/init.js'\n\nexport const COMMANDS = {\n hello: Hello,\n 'hello:world': HelloWorld,\n howdy: Hello, // alias the `hello` command to `howdy`\n}\n")),(0,i.kt)("p",null,"That configuration is essentially telling oclif to look for an ",(0,i.kt)("inlineCode",{parentName:"p"},"INIT_HOOK")," export inside of ",(0,i.kt)("inlineCode",{parentName:"p"},"./dist/index.js")),(0,i.kt)("h4",{id:"bundling"},"Bundling"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"We do not support bundling")," given the endless number of tools + configurations that could be used. But if you choose to use a bundler, like ",(0,i.kt)("inlineCode",{parentName:"p"},"esbuild")," there are a couple hard requirements - you must have a package.json in your root directory and a ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run.js")," bin script. ",(0,i.kt)("em",{parentName:"p"},"This means that you will not be able to successfully bundle your entire CLI (src code, package.json, node_modules, etc) into a single file.")),(0,i.kt)("p",null,"If you want to use a bundler, you can see this ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-test-esbuild/"},"example repo"),"."),(0,i.kt)("h3",{id:"single-strategy"},(0,i.kt)("inlineCode",{parentName:"h3"},"single")," Strategy"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"single")," strategy tells oclif that this CLI contains a single command that can be executed by the ",(0,i.kt)("inlineCode",{parentName:"p"},"bin/run.js")," (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"ls")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"cat"),")."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "commands": {\n "strategy": "single",\n "target": "./dist/index.js"\n }\n }\n}\n')),(0,i.kt)("p",null,"In this example, ",(0,i.kt)("inlineCode",{parentName:"p"},"./dist/index.js")," exports the command class."),(0,i.kt)("h3",{id:"note-about-oclifmanifestjson"},"Note about ",(0,i.kt)("inlineCode",{parentName:"h3"},"oclif.manifest.json")),(0,i.kt)("p",null,"For all strategies, the ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," will be used to load the commands instead of the default behavior of the strategy."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/32060389.636715d9.js b/assets/js/32060389.44959ed9.js similarity index 99% rename from assets/js/32060389.636715d9.js rename to assets/js/32060389.44959ed9.js index 4686574c..de6c33b5 100644 --- a/assets/js/32060389.636715d9.js +++ b/assets/js/32060389.44959ed9.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[7905],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>f});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),c=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(t),d=r,f=p["".concat(s,".").concat(d)]||p[d]||m[d]||o;return t?a.createElement(f,l(l({ref:n},u),{},{components:t})):a.createElement(f,l({ref:n},u))}));function f(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,l=new Array(o);l[0]=d;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[p]="string"==typeof e?e:r,l[1]=i;for(var c=2;c{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>p});var a=t(7462),r=t(3366),o=(t(7294),t(3905)),l=["components"],i={title:"Table"},s=void 0,c={unversionedId:"table",id:"table",title:"Table",description:"ux.table",source:"@site/../docs/table.md",sourceDirName:".",slug:"/table",permalink:"/docs/table",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/table.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Table"},sidebar:"docs",previous:{title:"Spinner",permalink:"/docs/spinner"},next:{title:"Notifications",permalink:"/docs/notifications"}},u={},p=[{value:"ux.table",id:"uxtable",level:2}],m={toc:p},d="wrapper";function f(e){var n=e.components,t=(0,r.Z)(e,l);return(0,o.kt)(d,(0,a.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"uxtable"},(0,o.kt)("inlineCode",{parentName:"h2"},"ux.table")),(0,o.kt)("p",null,"Displays tabular data"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"ux.table(data, columns, options)\n")),(0,o.kt)("p",null,"Where:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data"),": array of data objects to display"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"columns"),": ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/oclif/core/blob/main/src/cli-ux/styled/table.ts"},"Table.Columns")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"options"),": ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/oclif/core/blob/main/src/cli-ux/styled/table.ts"},"Table.Options"))),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.table.flags()")," returns an object containing all the table flags to include in your command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"{\n columns: Flags.string({exclusive: ['additional'], description: 'only show provided columns (comma-seperated)'}),\n sort: Flags.string({description: 'property to sort by (prepend '-' for descending)'}),\n filter: Flags.string({description: 'filter property by partial string matching, ex: name=foo'}),\n csv: Flags.boolean({exclusive: ['no-truncate'], description: 'output is csv format'}),\n extended: Flags.boolean({char: 'x', description: 'show extra columns'}),\n 'no-truncate': Flags.boolean({exclusive: ['csv'], description: 'do not truncate output to fit screen'}),\n 'no-header': Flags.boolean({exclusive: ['csv'], description: 'hide table header from output'}),\n}\n")),(0,o.kt)("p",null,"Passing ",(0,o.kt)("inlineCode",{parentName:"p"},"{only: ['columns']}")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"{except: ['columns']}")," as an argument into ",(0,o.kt)("inlineCode",{parentName:"p"},"cli.table.flags()")," will allow/block those flags from the returned object."),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.Table.Columns")," defines the table columns and their display options."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const columns: ux.Table.Columns = {\n // where `.name` is a property of a data object\n name: {}, // \"Name\" inferred as the column header\n id: {\n header: 'ID', // override column header\n minWidth: '10', // column must display at this width or greater\n extended: true, // only display this column when the --extended flag is present\n get: row => `US-O1-${row.id}`, // custom getter for data row object\n },\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.Table.Options")," defines the table options, most of which are the parsed flags from the user for display customization, all of which are optional."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const options: ux.Table.Options = {\n printLine: myLogger, // custom logger\n columns: flags.columns,\n sort: flags.sort,\n filter: flags.filter,\n csv: flags.csv,\n extended: flags.extended,\n 'no-truncate': flags['no-truncate'],\n 'no-header': flags['no-header'],\n}\n")),(0,o.kt)("p",null,"Example class:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\nimport axios from 'axios'\n\nexport default class Users extends Command {\n static flags = {\n ...ux.table.flags()\n }\n\n async run() {\n const {flags} = await this.parse(Users)\n const {data: users} = await axios.get('https://jsonplaceholder.typicode.com/users')\n\n ux.table(users, {\n name: {\n minWidth: 7,\n },\n company: {\n get: row => row.company && row.company.name\n },\n id: {\n header: 'ID',\n extended: true\n }\n }, {\n printLine: this.log.bind(this),\n ...flags, // parsed flags\n })\n }\n}\n")),(0,o.kt)("p",null,"Displays:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-shell"},'$ example-cli users\nName Company\nLeanne Graham Romaguera-Crona\nErvin Howell Deckow-Crist\nClementine Bauch Romaguera-Jacobson\nPatricia Lebsack Robel-Corkery\nChelsey Dietrich Keebler LLC\nMrs. Dennis Schulist Considine-Lockman\nKurtis Weissnat Johns Group\nNicholas Runolfsdottir V Abernathy Group\nGlenna Reichert Yost and Sons\nClementina DuBuque Hoeger LLC\n\n$ example-cli users --extended\nName Company ID\nLeanne Graham Romaguera-Crona 1\nErvin Howell Deckow-Crist 2\nClementine Bauch Romaguera-Jacobson 3\nPatricia Lebsack Robel-Corkery 4\nChelsey Dietrich Keebler LLC 5\nMrs. Dennis Schulist Considine-Lockman 6\nKurtis Weissnat Johns Group 7\nNicholas Runolfsdottir V Abernathy Group 8\nGlenna Reichert Yost and Sons 9\nClementina DuBuque Hoeger LLC 10\n\n$ example-cli users --columns=name\nName\nLeanne Graham\nErvin Howell\nClementine Bauch\nPatricia Lebsack\nChelsey Dietrich\nMrs. Dennis Schulist\nKurtis Weissnat\nNicholas Runolfsdottir V\nGlenna Reichert\nClementina DuBuque\n\n$ example-cli users --filter="company=Group"\nName Company\nKurtis Weissnat Johns Group\nNicholas Runolfsdottir V Abernathy Group\n\n$ example-cli users --sort=company\nName Company\nNicholas Runolfsdottir V Abernathy Group\nMrs. Dennis Schulist Considine-Lockman\nErvin Howell Deckow-Crist\nClementina DuBuque Hoeger LLC\nKurtis Weissnat Johns Group\nChelsey Dietrich Keebler LLC\nPatricia Lebsack Robel-Corkery\nLeanne Graham Romaguera-Crona\nClementine Bauch Romaguera-Jacobson\nGlenna Reichert Yost and Sons\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[7905],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>f});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),c=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(t),d=r,f=p["".concat(s,".").concat(d)]||p[d]||m[d]||o;return t?a.createElement(f,l(l({ref:n},u),{},{components:t})):a.createElement(f,l({ref:n},u))}));function f(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,l=new Array(o);l[0]=d;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[p]="string"==typeof e?e:r,l[1]=i;for(var c=2;c{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>p});var a=t(7462),r=t(3366),o=(t(7294),t(3905)),l=["components"],i={title:"Table"},s=void 0,c={unversionedId:"table",id:"table",title:"Table",description:"ux.table",source:"@site/../docs/table.md",sourceDirName:".",slug:"/table",permalink:"/docs/table",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/table.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Table"},sidebar:"docs",previous:{title:"Spinner",permalink:"/docs/spinner"},next:{title:"Notifications",permalink:"/docs/notifications"}},u={},p=[{value:"ux.table",id:"uxtable",level:2}],m={toc:p},d="wrapper";function f(e){var n=e.components,t=(0,r.Z)(e,l);return(0,o.kt)(d,(0,a.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"uxtable"},(0,o.kt)("inlineCode",{parentName:"h2"},"ux.table")),(0,o.kt)("p",null,"Displays tabular data"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"ux.table(data, columns, options)\n")),(0,o.kt)("p",null,"Where:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data"),": array of data objects to display"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"columns"),": ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/oclif/core/blob/main/src/cli-ux/styled/table.ts"},"Table.Columns")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"options"),": ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/oclif/core/blob/main/src/cli-ux/styled/table.ts"},"Table.Options"))),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.table.flags()")," returns an object containing all the table flags to include in your command."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"{\n columns: Flags.string({exclusive: ['additional'], description: 'only show provided columns (comma-seperated)'}),\n sort: Flags.string({description: 'property to sort by (prepend '-' for descending)'}),\n filter: Flags.string({description: 'filter property by partial string matching, ex: name=foo'}),\n csv: Flags.boolean({exclusive: ['no-truncate'], description: 'output is csv format'}),\n extended: Flags.boolean({char: 'x', description: 'show extra columns'}),\n 'no-truncate': Flags.boolean({exclusive: ['csv'], description: 'do not truncate output to fit screen'}),\n 'no-header': Flags.boolean({exclusive: ['csv'], description: 'hide table header from output'}),\n}\n")),(0,o.kt)("p",null,"Passing ",(0,o.kt)("inlineCode",{parentName:"p"},"{only: ['columns']}")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"{except: ['columns']}")," as an argument into ",(0,o.kt)("inlineCode",{parentName:"p"},"cli.table.flags()")," will allow/block those flags from the returned object."),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.Table.Columns")," defines the table columns and their display options."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const columns: ux.Table.Columns = {\n // where `.name` is a property of a data object\n name: {}, // \"Name\" inferred as the column header\n id: {\n header: 'ID', // override column header\n minWidth: '10', // column must display at this width or greater\n extended: true, // only display this column when the --extended flag is present\n get: row => `US-O1-${row.id}`, // custom getter for data row object\n },\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"ux.Table.Options")," defines the table options, most of which are the parsed flags from the user for display customization, all of which are optional."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"const options: ux.Table.Options = {\n printLine: myLogger, // custom logger\n columns: flags.columns,\n sort: flags.sort,\n filter: flags.filter,\n csv: flags.csv,\n extended: flags.extended,\n 'no-truncate': flags['no-truncate'],\n 'no-header': flags['no-header'],\n}\n")),(0,o.kt)("p",null,"Example class:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\nimport axios from 'axios'\n\nexport default class Users extends Command {\n static flags = {\n ...ux.table.flags()\n }\n\n async run() {\n const {flags} = await this.parse(Users)\n const {data: users} = await axios.get('https://jsonplaceholder.typicode.com/users')\n\n ux.table(users, {\n name: {\n minWidth: 7,\n },\n company: {\n get: row => row.company && row.company.name\n },\n id: {\n header: 'ID',\n extended: true\n }\n }, {\n printLine: this.log.bind(this),\n ...flags, // parsed flags\n })\n }\n}\n")),(0,o.kt)("p",null,"Displays:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-shell"},'$ example-cli users\nName Company\nLeanne Graham Romaguera-Crona\nErvin Howell Deckow-Crist\nClementine Bauch Romaguera-Jacobson\nPatricia Lebsack Robel-Corkery\nChelsey Dietrich Keebler LLC\nMrs. Dennis Schulist Considine-Lockman\nKurtis Weissnat Johns Group\nNicholas Runolfsdottir V Abernathy Group\nGlenna Reichert Yost and Sons\nClementina DuBuque Hoeger LLC\n\n$ example-cli users --extended\nName Company ID\nLeanne Graham Romaguera-Crona 1\nErvin Howell Deckow-Crist 2\nClementine Bauch Romaguera-Jacobson 3\nPatricia Lebsack Robel-Corkery 4\nChelsey Dietrich Keebler LLC 5\nMrs. Dennis Schulist Considine-Lockman 6\nKurtis Weissnat Johns Group 7\nNicholas Runolfsdottir V Abernathy Group 8\nGlenna Reichert Yost and Sons 9\nClementina DuBuque Hoeger LLC 10\n\n$ example-cli users --columns=name\nName\nLeanne Graham\nErvin Howell\nClementine Bauch\nPatricia Lebsack\nChelsey Dietrich\nMrs. Dennis Schulist\nKurtis Weissnat\nNicholas Runolfsdottir V\nGlenna Reichert\nClementina DuBuque\n\n$ example-cli users --filter="company=Group"\nName Company\nKurtis Weissnat Johns Group\nNicholas Runolfsdottir V Abernathy Group\n\n$ example-cli users --sort=company\nName Company\nNicholas Runolfsdottir V Abernathy Group\nMrs. Dennis Schulist Considine-Lockman\nErvin Howell Deckow-Crist\nClementina DuBuque Hoeger LLC\nKurtis Weissnat Johns Group\nChelsey Dietrich Keebler LLC\nPatricia Lebsack Robel-Corkery\nLeanne Graham Romaguera-Crona\nClementine Bauch Romaguera-Jacobson\nGlenna Reichert Yost and Sons\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/35586d92.eb012dea.js b/assets/js/35586d92.d74a9192.js similarity index 98% rename from assets/js/35586d92.eb012dea.js rename to assets/js/35586d92.d74a9192.js index fa6901a7..d9defd0a 100644 --- a/assets/js/35586d92.eb012dea.js +++ b/assets/js/35586d92.d74a9192.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=i,g=u["".concat(p,".").concat(m)]||u[m]||c[m]||o;return n?r.createElement(g,a(a({ref:t},d),{},{components:n})):r.createElement(g,a({ref:t},d))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>p,default:()=>g,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),i=n(3366),o=(n(7294),n(3905)),a=["components"],l={title:"Plugin Loading"},p=void 0,s={unversionedId:"plugin_loading",id:"plugin_loading",title:"Plugin Loading",description:"Below is a diagram that outlines how a plugin is loaded into the CLI.",source:"@site/../docs/plugin_loading.md",sourceDirName:".",slug:"/plugin_loading",permalink:"/docs/plugin_loading",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/plugin_loading.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Plugin Loading"},sidebar:"docs",previous:{title:"Command Execution",permalink:"/docs/command_execution"},next:{title:"Command Discovery Strategies",permalink:"/docs/command_discovery_strategies"}},d={},u=[{value:"Plugin Resolution Order",id:"plugin-resolution-order",level:3},{value:"Manifests Improve Performance",id:"manifests-improve-performance",level:3},{value:"Plugin Loading Diagram",id:"plugin-loading-diagram",level:2}],c={toc:u},m="wrapper";function g(e){var t=e.components,l=(0,i.Z)(e,a);return(0,o.kt)(m,(0,r.Z)({},c,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Below is a diagram that outlines how a plugin is loaded into the CLI."),(0,o.kt)("p",null,"There are a couple of important takeaways from this diagram:"),(0,o.kt)("h3",{id:"plugin-resolution-order"},"Plugin Resolution Order"),(0,o.kt)("p",null,"Plugins are resolved in the following order:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"User plugins (i.e. plugins installed by the users)"),(0,o.kt)("li",{parentName:"ol"},"Dev plugins (i.e. plugins listed under ",(0,o.kt)("inlineCode",{parentName:"li"},"devPlugins"),")"),(0,o.kt)("li",{parentName:"ol"},"Core plugins (i.e. plugins listed under ",(0,o.kt)("inlineCode",{parentName:"li"},"plugins"),")")),(0,o.kt)("h3",{id:"manifests-improve-performance"},"Manifests Improve Performance"),(0,o.kt)("p",null,"When loading a plugin, oclif needs to require each command file in order to get the static properties of the command - the ",(0,o.kt)("inlineCode",{parentName:"p"},"description"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"examples"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"flags"),", etc..."),(0,o.kt)("p",null,"However, oclif can skip this step if the plugin has an ",(0,o.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," (generated by ",(0,o.kt)("inlineCode",{parentName:"p"},"oclif manifest"),"). The manifest caches all of these properties so that there's no need to require every single command on every command execution."),(0,o.kt)("h2",{id:"plugin-loading-diagram"},"Plugin Loading Diagram"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"plugin loading",src:n(1944).Z,width:"8787",height:"5576"})))}g.isMDXComponent=!0},1944:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/plugin-loading-63d248baba4db7ba0a9340ef6b0c0856.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=i,g=u["".concat(p,".").concat(m)]||u[m]||c[m]||o;return n?r.createElement(g,a(a({ref:t},d),{},{components:n})):r.createElement(g,a({ref:t},d))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>p,default:()=>g,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),i=n(3366),o=(n(7294),n(3905)),a=["components"],l={title:"Plugin Loading"},p=void 0,s={unversionedId:"plugin_loading",id:"plugin_loading",title:"Plugin Loading",description:"Below is a diagram that outlines how a plugin is loaded into the CLI.",source:"@site/../docs/plugin_loading.md",sourceDirName:".",slug:"/plugin_loading",permalink:"/docs/plugin_loading",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/plugin_loading.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Plugin Loading"},sidebar:"docs",previous:{title:"Command Execution",permalink:"/docs/command_execution"},next:{title:"Command Discovery Strategies",permalink:"/docs/command_discovery_strategies"}},d={},u=[{value:"Plugin Resolution Order",id:"plugin-resolution-order",level:3},{value:"Manifests Improve Performance",id:"manifests-improve-performance",level:3},{value:"Plugin Loading Diagram",id:"plugin-loading-diagram",level:2}],c={toc:u},m="wrapper";function g(e){var t=e.components,l=(0,i.Z)(e,a);return(0,o.kt)(m,(0,r.Z)({},c,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Below is a diagram that outlines how a plugin is loaded into the CLI."),(0,o.kt)("p",null,"There are a couple of important takeaways from this diagram:"),(0,o.kt)("h3",{id:"plugin-resolution-order"},"Plugin Resolution Order"),(0,o.kt)("p",null,"Plugins are resolved in the following order:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"User plugins (i.e. plugins installed by the users)"),(0,o.kt)("li",{parentName:"ol"},"Dev plugins (i.e. plugins listed under ",(0,o.kt)("inlineCode",{parentName:"li"},"devPlugins"),")"),(0,o.kt)("li",{parentName:"ol"},"Core plugins (i.e. plugins listed under ",(0,o.kt)("inlineCode",{parentName:"li"},"plugins"),")")),(0,o.kt)("h3",{id:"manifests-improve-performance"},"Manifests Improve Performance"),(0,o.kt)("p",null,"When loading a plugin, oclif needs to require each command file in order to get the static properties of the command - the ",(0,o.kt)("inlineCode",{parentName:"p"},"description"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"examples"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"flags"),", etc..."),(0,o.kt)("p",null,"However, oclif can skip this step if the plugin has an ",(0,o.kt)("inlineCode",{parentName:"p"},"oclif.manifest.json")," (generated by ",(0,o.kt)("inlineCode",{parentName:"p"},"oclif manifest"),"). The manifest caches all of these properties so that there's no need to require every single command on every command execution."),(0,o.kt)("h2",{id:"plugin-loading-diagram"},"Plugin Loading Diagram"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"plugin loading",src:n(1944).Z,width:"8787",height:"5576"})))}g.isMDXComponent=!0},1944:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/plugin-loading-63d248baba4db7ba0a9340ef6b0c0856.jpg"}}]); \ No newline at end of file diff --git a/assets/js/3e452c7e.7eeef943.js b/assets/js/3e452c7e.f8151866.js similarity index 98% rename from assets/js/3e452c7e.7eeef943.js rename to assets/js/3e452c7e.f8151866.js index c964aba4..1463793c 100644 --- a/assets/js/3e452c7e.7eeef943.js +++ b/assets/js/3e452c7e.f8151866.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[637],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>u});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=a.createContext({}),i=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},m=function(e){var n=i(e.components);return a.createElement(c.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},f=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),p=i(t),f=r,u=p["".concat(c,".").concat(f)]||p[f]||d[f]||s;return t?a.createElement(u,o(o({ref:n},m),{},{components:t})):a.createElement(u,o({ref:n},m))}));function u(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var s=t.length,o=new Array(s);o[0]=f;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var i=2;i{t.r(n),t.d(n,{assets:()=>m,contentTitle:()=>c,default:()=>u,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var a=t(7462),r=t(3366),s=(t(7294),t(3905)),o=["components"],l={title:"Custom Base Class"},c=void 0,i={unversionedId:"base_class",id:"base_class",title:"Custom Base Class",description:"Use inheritance to share functionality between common commands. Here is an example of a command base class that has some common shared flags.",source:"@site/../docs/base_class.md",sourceDirName:".",slug:"/base_class",permalink:"/docs/base_class",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/base_class.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Custom Base Class"},sidebar:"docs",previous:{title:"NSIS Installer Customization",permalink:"/docs/nsis-installer_customization"},next:{title:"Prompting",permalink:"/docs/prompting"}},m={},p=[],d={toc:p},f="wrapper";function u(e){var n=e.components,t=(0,r.Z)(e,o);return(0,s.kt)(f,(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"Use inheritance to share functionality between common commands. Here is an example of a command base class that has some common shared flags."),(0,s.kt)("p",null,"For large CLIs with multiple plugins, it's useful to put this base class into its own npm package to be shared."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-typescript"},"// src/baseCommand.ts\nimport {Command, Flags, Interfaces} from '@oclif/core'\n\nenum LogLevel {\n debug = 'debug',\n info = 'info',\n warn = 'warn',\n error = 'error',\n}\n\nexport type Flags = Interfaces.InferredFlags\nexport type Args = Interfaces.InferredArgs\n\nexport abstract class BaseCommand extends Command {\n // add the --json flag\n static enableJsonFlag = true\n\n // define flags that can be inherited by any command that extends BaseCommand\n static baseFlags = {\n 'log-level': Flags.custom({\n summary: 'Specify level for logging.',\n options: Object.values(LogLevel),\n helpGroup: 'GLOBAL',\n })(),\n }\n\n protected flags!: Flags\n protected args!: Args\n\n public async init(): Promise {\n await super.init()\n const {args, flags} = await this.parse({\n flags: this.ctor.flags,\n baseFlags: (super.ctor as typeof BaseCommand).baseFlags,\n enableJsonFlag: this.ctor.enableJsonFlag,\n args: this.ctor.args,\n strict: this.ctor.strict,\n })\n this.flags = flags as Flags\n this.args = args as Args\n }\n\n protected async catch(err: Error & {exitCode?: number}): Promise {\n // add any custom logic to handle errors from the command\n // or simply return the parent class error handling\n return super.catch(err)\n }\n\n protected async finally(_: Error | undefined): Promise {\n // called after run and catch regardless of whether or not the command errored\n return super.finally(_)\n }\n}\n\n// src/commands/my-command.ts\n\nexport default class MyCommand extends BaseCommand {\n static summary = 'child class that extends BaseCommand'\n\n static examples = [\n '<%= config.bin %> <%= command.id %>',\n '<%= config.bin %> <%= command.id %> --json',\n '<%= config.bin %> <%= command.id %> --log-level debug',\n ]\n\n static flags = {\n name: Flags.string({\n char: 'n',\n summary: 'Name to print.',\n required: true,\n }),\n }\n\n public async run(): Promise> {\n for (const [flag, value] of Object.entries(this.flags)) {\n this.log(`${flag}: ${value}`)\n }\n\n return this.flags\n }\n}\n")),(0,s.kt)("p",null,"For a more complex example, ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/sf-plugins-core/blob/main/src/sfCommand.ts"},"here's")," how we do this for the Salesforce CLI."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[637],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>u});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var c=a.createContext({}),i=function(e){var n=a.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},m=function(e){var n=i(e.components);return a.createElement(c.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},f=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),p=i(t),f=r,u=p["".concat(c,".").concat(f)]||p[f]||d[f]||s;return t?a.createElement(u,o(o({ref:n},m),{},{components:t})):a.createElement(u,o({ref:n},m))}));function u(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var s=t.length,o=new Array(s);o[0]=f;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var i=2;i{t.r(n),t.d(n,{assets:()=>m,contentTitle:()=>c,default:()=>u,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var a=t(7462),r=t(3366),s=(t(7294),t(3905)),o=["components"],l={title:"Custom Base Class"},c=void 0,i={unversionedId:"base_class",id:"base_class",title:"Custom Base Class",description:"Use inheritance to share functionality between common commands. Here is an example of a command base class that has some common shared flags.",source:"@site/../docs/base_class.md",sourceDirName:".",slug:"/base_class",permalink:"/docs/base_class",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/base_class.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Custom Base Class"},sidebar:"docs",previous:{title:"NSIS Installer Customization",permalink:"/docs/nsis-installer_customization"},next:{title:"Prompting",permalink:"/docs/prompting"}},m={},p=[],d={toc:p},f="wrapper";function u(e){var n=e.components,t=(0,r.Z)(e,o);return(0,s.kt)(f,(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"Use inheritance to share functionality between common commands. Here is an example of a command base class that has some common shared flags."),(0,s.kt)("p",null,"For large CLIs with multiple plugins, it's useful to put this base class into its own npm package to be shared."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-typescript"},"// src/baseCommand.ts\nimport {Command, Flags, Interfaces} from '@oclif/core'\n\nenum LogLevel {\n debug = 'debug',\n info = 'info',\n warn = 'warn',\n error = 'error',\n}\n\nexport type Flags = Interfaces.InferredFlags\nexport type Args = Interfaces.InferredArgs\n\nexport abstract class BaseCommand extends Command {\n // add the --json flag\n static enableJsonFlag = true\n\n // define flags that can be inherited by any command that extends BaseCommand\n static baseFlags = {\n 'log-level': Flags.custom({\n summary: 'Specify level for logging.',\n options: Object.values(LogLevel),\n helpGroup: 'GLOBAL',\n })(),\n }\n\n protected flags!: Flags\n protected args!: Args\n\n public async init(): Promise {\n await super.init()\n const {args, flags} = await this.parse({\n flags: this.ctor.flags,\n baseFlags: (super.ctor as typeof BaseCommand).baseFlags,\n enableJsonFlag: this.ctor.enableJsonFlag,\n args: this.ctor.args,\n strict: this.ctor.strict,\n })\n this.flags = flags as Flags\n this.args = args as Args\n }\n\n protected async catch(err: Error & {exitCode?: number}): Promise {\n // add any custom logic to handle errors from the command\n // or simply return the parent class error handling\n return super.catch(err)\n }\n\n protected async finally(_: Error | undefined): Promise {\n // called after run and catch regardless of whether or not the command errored\n return super.finally(_)\n }\n}\n\n// src/commands/my-command.ts\n\nexport default class MyCommand extends BaseCommand {\n static summary = 'child class that extends BaseCommand'\n\n static examples = [\n '<%= config.bin %> <%= command.id %>',\n '<%= config.bin %> <%= command.id %> --json',\n '<%= config.bin %> <%= command.id %> --log-level debug',\n ]\n\n static flags = {\n name: Flags.string({\n char: 'n',\n summary: 'Name to print.',\n required: true,\n }),\n }\n\n public async run(): Promise> {\n for (const [flag, value] of Object.entries(this.flags)) {\n this.log(`${flag}: ${value}`)\n }\n\n return this.flags\n }\n}\n")),(0,s.kt)("p",null,"For a more complex example, ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/sf-plugins-core/blob/main/src/sfCommand.ts"},"here's")," how we do this for the Salesforce CLI."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/53e18611.7a0136ba.js b/assets/js/53e18611.ac600542.js similarity index 98% rename from assets/js/53e18611.7a0136ba.js rename to assets/js/53e18611.ac600542.js index f5faf7fd..51fc6c04 100644 --- a/assets/js/53e18611.7a0136ba.js +++ b/assets/js/53e18611.ac600542.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8349],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var c=2;c{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],l={title:"Introduction"},s=void 0,c={unversionedId:"introduction",id:"introduction",title:"Introduction",description:"oclif is a framework for building CLIs in Node. It can be used like a simple flag parser but is capable of much more. It's designed to be extensible so that you can easily add plugins such as the update warning plugin or build your own for users to install at runtime.",source:"@site/../docs/introduction.md",sourceDirName:".",slug:"/introduction",permalink:"/docs/introduction",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/introduction.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Introduction"},sidebar:"docs",next:{title:"Features",permalink:"/docs/features"}},u={},p=[{value:"Requirements",id:"requirements",level:2},{value:"Quickstart",id:"quickstart",level:2}],d={toc:p},f="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)(f,(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"oclif is a framework for building CLIs in Node. It can be used like a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core#usage"},"simple flag parser")," but is capable of much more. It's designed to be extensible so that you can easily add plugins such as the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-warn-if-update-available"},"update warning plugin")," or build your own for users to install at runtime."),(0,a.kt)("p",null,"The oclif generator creates a CLI project in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world"},"TypeScript")," to get you started quickly. It requires very few runtime dependencies and has extremely minimal overhead."),(0,a.kt)("p",null,"Everything is customizable in oclif. Even the flag parser and help generation is optional and can be replaced. It's a platform to build upon that provides smart defaults without locking you in to any specific tools or behavior."),(0,a.kt)("h2",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"Only ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/en/about/previous-releases"},"LTS Node versions")," are supported. You can add the ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/node"},"node")," package to your CLI to ensure users are on a specific Node version."),(0,a.kt)("h2",{id:"quickstart"},"Quickstart"),(0,a.kt)("p",null,"Creating a CLI:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ npx oclif generate mynewcli\n? npm package name (mynewcli): mynewcli\n$ cd mynewcli\n$ ./bin/dev.js hello world\nhello world! (./src/commands/hello/world.ts)\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8349],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(r),f=o,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var c=2;c{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>c,toc:()=>p});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],l={title:"Introduction"},s=void 0,c={unversionedId:"introduction",id:"introduction",title:"Introduction",description:"oclif is a framework for building CLIs in Node. It can be used like a simple flag parser but is capable of much more. It's designed to be extensible so that you can easily add plugins such as the update warning plugin or build your own for users to install at runtime.",source:"@site/../docs/introduction.md",sourceDirName:".",slug:"/introduction",permalink:"/docs/introduction",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/introduction.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Introduction"},sidebar:"docs",next:{title:"Features",permalink:"/docs/features"}},u={},p=[{value:"Requirements",id:"requirements",level:2},{value:"Quickstart",id:"quickstart",level:2}],d={toc:p},f="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)(f,(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"oclif is a framework for building CLIs in Node. It can be used like a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core#usage"},"simple flag parser")," but is capable of much more. It's designed to be extensible so that you can easily add plugins such as the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-warn-if-update-available"},"update warning plugin")," or build your own for users to install at runtime."),(0,a.kt)("p",null,"The oclif generator creates a CLI project in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world"},"TypeScript")," to get you started quickly. It requires very few runtime dependencies and has extremely minimal overhead."),(0,a.kt)("p",null,"Everything is customizable in oclif. Even the flag parser and help generation is optional and can be replaced. It's a platform to build upon that provides smart defaults without locking you in to any specific tools or behavior."),(0,a.kt)("h2",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"Only ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/en/about/previous-releases"},"LTS Node versions")," are supported. You can add the ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/node"},"node")," package to your CLI to ensure users are on a specific Node version."),(0,a.kt)("h2",{id:"quickstart"},"Quickstart"),(0,a.kt)("p",null,"Creating a CLI:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ npx oclif generate mynewcli\n? npm package name (mynewcli): mynewcli\n$ cd mynewcli\n$ ./bin/dev.js hello world\nhello world! (./src/commands/hello/world.ts)\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5d5620c4.1f758151.js b/assets/js/5d5620c4.3f17b57d.js similarity index 99% rename from assets/js/5d5620c4.1f758151.js rename to assets/js/5d5620c4.3f17b57d.js index 080a5d0a..a1361761 100644 --- a/assets/js/5d5620c4.1f758151.js +++ b/assets/js/5d5620c4.3f17b57d.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1926],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=i.createContext({}),s=function(e){var t=i.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=s(e.components);return i.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(p,".").concat(m)]||d[m]||c[m]||r;return n?i.createElement(g,l(l({ref:t},u),{},{components:n})):i.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=m;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:a,l[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>p,default:()=>g,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),a=n(3366),r=(n(7294),n(3905)),l=["components"],o={title:"ESM"},p=void 0,s={unversionedId:"esm",id:"esm",title:"ESM",description:"Version 3.0.0 of @oclif/core officially supports ESM plugin development and CJS/ESM interoperability, meaning that you can have a root plugin written with CJS and your bundled plugins written in ESM or vice versa.",source:"@site/../docs/esm.md",sourceDirName:".",slug:"/esm",permalink:"/docs/esm",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/esm.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"ESM"},sidebar:"docs",previous:{title:"Single Command CLI",permalink:"/docs/single_command_cli"},next:{title:"Themes",permalink:"/docs/themes"}},u={},d=[{value:"Interoperability Overview",id:"interoperability-overview",level:2},{value:"ESM Root plugin",id:"esm-root-plugin",level:3},{value:"CJS Root plugin",id:"cjs-root-plugin",level:3},{value:"Creating an ESM plugin",id:"creating-an-esm-plugin",level:2},{value:"Migrating a CJS plugin to ESM",id:"migrating-a-cjs-plugin-to-esm",level:2},{value:"Update bin scripts",id:"update-bin-scripts",level:3},{value:"bin/dev \u2192 bin/dev.js",id:"bindev--bindevjs",level:4},{value:"bin/run \u2192 bin/run.js",id:"binrun--binrunjs",level:4},{value:"Update tsconfig.json",id:"update-tsconfigjson",level:3},{value:"Update package.json to "module" type",id:"update-packagejson-to-module-type",level:3},{value:"Update references to bin scripts",id:"update-references-to-bin-scripts",level:3},{value:"Update mocharc settings",id:"update-mocharc-settings",level:3}],c={toc:d},m="wrapper";function g(e){var t=e.components,n=(0,a.Z)(e,l);return(0,r.kt)(m,(0,i.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Version 3.0.0 of ",(0,r.kt)("inlineCode",{parentName:"p"},"@oclif/core")," officially supports ESM plugin development and CJS/ESM interoperability, meaning that you can have a root plugin written with CJS and your bundled plugins written in ESM or vice versa."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#interoperability-overview"},"Interoperability Overview"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#esm-root-plugin"},"ESM Root plugin")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#cjs-root-plugin"},"CJS Root plugin")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#creating-an-esm-plugin"},"Creating an ESM plugin")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#migrating-a-cjs-plugin-to-esm"},"Migrating a CJS plugin to ESM"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-bin-scripts"},"Update bin scripts"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#bindev--bindevjs"},"bin/dev \u2192 bin/dev.js")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#binrun--binrunjs"},"bin/run \u2192 bin/run.js")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-tsconfigjson"},"Update tsconfig.json")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-packagejson-to-module-type"},'Update package.json to "module" type')),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-references-to-bin-scripts"},"Update references to bin scripts")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-mocharc-settings"},"Update mocharc settings"))))),(0,r.kt)("h2",{id:"interoperability-overview"},"Interoperability Overview"),(0,r.kt)("p",null,"Here's a high level overview of ESM/CJS interoperability:"),(0,r.kt)("h3",{id:"esm-root-plugin"},"ESM Root plugin"),(0,r.kt)("p",null,"\u2705 Install CJS plugins"),(0,r.kt)("p",null,"\u2705 Install ESM plugins"),(0,r.kt)("p",null,"\u2705 Link CJS plugins"),(0,r.kt)("p",null,"\u26a0\ufe0f Link ESM plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Auto-compilation will ",(0,r.kt)("strong",{parentName:"li"},"not")," work with linked ESM plugins. Instead, oclif will use the plugin's compiled source - this means that you must compile the plugin yourself before executing any of the commands. We plan to support this again once the node ecosystem offers more comprehensive native support for ESM.")),(0,r.kt)("h3",{id:"cjs-root-plugin"},"CJS Root plugin"),(0,r.kt)("p",null,"\u2705 Install CJS plugins"),(0,r.kt)("p",null,"\u2705 Install ESM plugins"),(0,r.kt)("p",null,"\u2705 Link CJS plugins"),(0,r.kt)("p",null,"\u26a0\ufe0f Link ESM plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Auto-compilation will ",(0,r.kt)("strong",{parentName:"li"},"not")," work with linked ESM plugins. Instead, oclif will use the plugin's compiled source - this means that you must compile the plugin yourself before executing any of the commands. We plan to support this again once the node ecosystem offers more comprehensive native support for ESM.")),(0,r.kt)("h2",{id:"creating-an-esm-plugin"},"Creating an ESM plugin"),(0,r.kt)("p",null,"To generate a new ESM plugin from the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world-esm"},"hello-world-esm template")," run the ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif generate")," command and select ",(0,r.kt)("inlineCode",{parentName:"p"},"ESM")," when it prompts you to select a module type:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ npx oclif generate my-esm-plugin\n? Select a module type\n CommonJS\n\u276f ESM\n")),(0,r.kt)("h2",{id:"migrating-a-cjs-plugin-to-esm"},"Migrating a CJS plugin to ESM"),(0,r.kt)("h3",{id:"update-bin-scripts"},"Update bin scripts"),(0,r.kt)("p",null,"First you will need to update the bin scripts under the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," directory."),(0,r.kt)("h4",{id:"bindev--bindevjs"},"bin/dev \u2192 bin/dev.js"),(0,r.kt)("p",null,"Rename ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/dev")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/dev.js")," and replace the existing code with the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning\n\nimport {execute} from '@oclif/core'\n\nawait execute({development: true, dir: import.meta.url})\n")),(0,r.kt)("p",null,"This leverages oclif's ",(0,r.kt)("inlineCode",{parentName:"p"},"execute")," function which handles all the development setup for you. You no longer need set the ",(0,r.kt)("inlineCode",{parentName:"p"},"NODE_ENV")," env var or register the project with ",(0,r.kt)("inlineCode",{parentName:"p"},"ts-node"),". You can still adjust oclif ",(0,r.kt)("inlineCode",{parentName:"p"},"settings")," before executing the CLI. For example,"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning\n\nimport {execute, settings} from '@oclif/core'\n\nsettings.performanceEnabled = true\n\nawait execute({development: true, dir: import.meta.url})\n")),(0,r.kt)("h4",{id:"binrun--binrunjs"},"bin/run \u2192 bin/run.js"),(0,r.kt)("p",null,"Rename ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/run")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/run.js")," and replace the existing code with the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env node\n\nimport {execute} from '@oclif/core'\n\nawait execute({dir: import.meta.url})\n")),(0,r.kt)("h3",{id:"update-tsconfigjson"},"Update tsconfig.json"),(0,r.kt)("p",null,"After updating the bin scripts you now need to update the ",(0,r.kt)("inlineCode",{parentName:"p"},"tsconfig.json")," to include the following options:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "compilerOptions": {\n "module": "ES2020",\n "moduleResolution": "node16",\n },\n "ts-node": {\n "esm": true\n }\n}\n')),(0,r.kt)("h3",{id:"update-packagejson-to-module-type"},'Update package.json to "module" type'),(0,r.kt)("p",null,"Add ",(0,r.kt)("inlineCode",{parentName:"p"},'"type": "module"')," to your package.json so that your files will be loaded as ESM modules"),(0,r.kt)("h3",{id:"update-references-to-bin-scripts"},"Update references to bin scripts"),(0,r.kt)("p",null,"You will need to update the references to your bin scripts to the bin scripts with the ",(0,r.kt)("inlineCode",{parentName:"p"},".js")," extension. In the ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json")," you will need to update the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},' "bin": {\n "my-cli": "./bin/run"\n },\n')),(0,r.kt)("p",null,"to"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},' "bin": {\n "my-cli": "./bin/run.js"\n },\n')),(0,r.kt)("p",null,"You may have references to the bin scripts in your ",(0,r.kt)("inlineCode",{parentName:"p"},".vscode/launch.json")," or in the ",(0,r.kt)("inlineCode",{parentName:"p"},"scripts")," of your ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json"),". You'll need to update these as well."),(0,r.kt)("h3",{id:"update-mocharc-settings"},"Update mocharc settings"),(0,r.kt)("p",null,"In order for your mocha tests to run, you'll need to make a couple of changes:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Add the following to the ",(0,r.kt)("inlineCode",{parentName:"li"},".mocharc.json"))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "node-option": [\n "loader=ts-node/esm"\n ]\n}\n')),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},"Update ",(0,r.kt)("inlineCode",{parentName:"li"},"test/helpers/init.js"))),(0,r.kt)("p",null,"If your plugin was generated ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif generate")," then you likely have a ",(0,r.kt)("inlineCode",{parentName:"p"},"test/helpers/init.js")," file that needs to be updated. You can either update the file extension to ",(0,r.kt)("inlineCode",{parentName:"p"},".cjs")," or update the ",(0,r.kt)("inlineCode",{parentName:"p"},"require")," at the top of the file to an ",(0,r.kt)("inlineCode",{parentName:"p"},"import"),","),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import path from 'node:path'\n")),(0,r.kt)("p",null,"Alternatively, you can safely delete this file since it's no longer necessary."))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1926],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=i.createContext({}),s=function(e){var t=i.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=s(e.components);return i.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=a,g=d["".concat(p,".").concat(m)]||d[m]||c[m]||r;return n?i.createElement(g,l(l({ref:t},u),{},{components:n})):i.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=m;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:a,l[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>p,default:()=>g,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),a=n(3366),r=(n(7294),n(3905)),l=["components"],o={title:"ESM"},p=void 0,s={unversionedId:"esm",id:"esm",title:"ESM",description:"Version 3.0.0 of @oclif/core officially supports ESM plugin development and CJS/ESM interoperability, meaning that you can have a root plugin written with CJS and your bundled plugins written in ESM or vice versa.",source:"@site/../docs/esm.md",sourceDirName:".",slug:"/esm",permalink:"/docs/esm",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/esm.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"ESM"},sidebar:"docs",previous:{title:"Single Command CLI",permalink:"/docs/single_command_cli"},next:{title:"Themes",permalink:"/docs/themes"}},u={},d=[{value:"Interoperability Overview",id:"interoperability-overview",level:2},{value:"ESM Root plugin",id:"esm-root-plugin",level:3},{value:"CJS Root plugin",id:"cjs-root-plugin",level:3},{value:"Creating an ESM plugin",id:"creating-an-esm-plugin",level:2},{value:"Migrating a CJS plugin to ESM",id:"migrating-a-cjs-plugin-to-esm",level:2},{value:"Update bin scripts",id:"update-bin-scripts",level:3},{value:"bin/dev \u2192 bin/dev.js",id:"bindev--bindevjs",level:4},{value:"bin/run \u2192 bin/run.js",id:"binrun--binrunjs",level:4},{value:"Update tsconfig.json",id:"update-tsconfigjson",level:3},{value:"Update package.json to "module" type",id:"update-packagejson-to-module-type",level:3},{value:"Update references to bin scripts",id:"update-references-to-bin-scripts",level:3},{value:"Update mocharc settings",id:"update-mocharc-settings",level:3}],c={toc:d},m="wrapper";function g(e){var t=e.components,n=(0,a.Z)(e,l);return(0,r.kt)(m,(0,i.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Version 3.0.0 of ",(0,r.kt)("inlineCode",{parentName:"p"},"@oclif/core")," officially supports ESM plugin development and CJS/ESM interoperability, meaning that you can have a root plugin written with CJS and your bundled plugins written in ESM or vice versa."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#interoperability-overview"},"Interoperability Overview"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#esm-root-plugin"},"ESM Root plugin")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#cjs-root-plugin"},"CJS Root plugin")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#creating-an-esm-plugin"},"Creating an ESM plugin")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#migrating-a-cjs-plugin-to-esm"},"Migrating a CJS plugin to ESM"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-bin-scripts"},"Update bin scripts"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#bindev--bindevjs"},"bin/dev \u2192 bin/dev.js")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#binrun--binrunjs"},"bin/run \u2192 bin/run.js")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-tsconfigjson"},"Update tsconfig.json")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-packagejson-to-module-type"},'Update package.json to "module" type')),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-references-to-bin-scripts"},"Update references to bin scripts")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-mocharc-settings"},"Update mocharc settings"))))),(0,r.kt)("h2",{id:"interoperability-overview"},"Interoperability Overview"),(0,r.kt)("p",null,"Here's a high level overview of ESM/CJS interoperability:"),(0,r.kt)("h3",{id:"esm-root-plugin"},"ESM Root plugin"),(0,r.kt)("p",null,"\u2705 Install CJS plugins"),(0,r.kt)("p",null,"\u2705 Install ESM plugins"),(0,r.kt)("p",null,"\u2705 Link CJS plugins"),(0,r.kt)("p",null,"\u26a0\ufe0f Link ESM plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Auto-compilation will ",(0,r.kt)("strong",{parentName:"li"},"not")," work with linked ESM plugins. Instead, oclif will use the plugin's compiled source - this means that you must compile the plugin yourself before executing any of the commands. We plan to support this again once the node ecosystem offers more comprehensive native support for ESM.")),(0,r.kt)("h3",{id:"cjs-root-plugin"},"CJS Root plugin"),(0,r.kt)("p",null,"\u2705 Install CJS plugins"),(0,r.kt)("p",null,"\u2705 Install ESM plugins"),(0,r.kt)("p",null,"\u2705 Link CJS plugins"),(0,r.kt)("p",null,"\u26a0\ufe0f Link ESM plugins"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Auto-compilation will ",(0,r.kt)("strong",{parentName:"li"},"not")," work with linked ESM plugins. Instead, oclif will use the plugin's compiled source - this means that you must compile the plugin yourself before executing any of the commands. We plan to support this again once the node ecosystem offers more comprehensive native support for ESM.")),(0,r.kt)("h2",{id:"creating-an-esm-plugin"},"Creating an ESM plugin"),(0,r.kt)("p",null,"To generate a new ESM plugin from the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world-esm"},"hello-world-esm template")," run the ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif generate")," command and select ",(0,r.kt)("inlineCode",{parentName:"p"},"ESM")," when it prompts you to select a module type:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ npx oclif generate my-esm-plugin\n? Select a module type\n CommonJS\n\u276f ESM\n")),(0,r.kt)("h2",{id:"migrating-a-cjs-plugin-to-esm"},"Migrating a CJS plugin to ESM"),(0,r.kt)("h3",{id:"update-bin-scripts"},"Update bin scripts"),(0,r.kt)("p",null,"First you will need to update the bin scripts under the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," directory."),(0,r.kt)("h4",{id:"bindev--bindevjs"},"bin/dev \u2192 bin/dev.js"),(0,r.kt)("p",null,"Rename ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/dev")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/dev.js")," and replace the existing code with the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning\n\nimport {execute} from '@oclif/core'\n\nawait execute({development: true, dir: import.meta.url})\n")),(0,r.kt)("p",null,"This leverages oclif's ",(0,r.kt)("inlineCode",{parentName:"p"},"execute")," function which handles all the development setup for you. You no longer need set the ",(0,r.kt)("inlineCode",{parentName:"p"},"NODE_ENV")," env var or register the project with ",(0,r.kt)("inlineCode",{parentName:"p"},"ts-node"),". You can still adjust oclif ",(0,r.kt)("inlineCode",{parentName:"p"},"settings")," before executing the CLI. For example,"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning\n\nimport {execute, settings} from '@oclif/core'\n\nsettings.performanceEnabled = true\n\nawait execute({development: true, dir: import.meta.url})\n")),(0,r.kt)("h4",{id:"binrun--binrunjs"},"bin/run \u2192 bin/run.js"),(0,r.kt)("p",null,"Rename ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/run")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"bin/run.js")," and replace the existing code with the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"#!/usr/bin/env node\n\nimport {execute} from '@oclif/core'\n\nawait execute({dir: import.meta.url})\n")),(0,r.kt)("h3",{id:"update-tsconfigjson"},"Update tsconfig.json"),(0,r.kt)("p",null,"After updating the bin scripts you now need to update the ",(0,r.kt)("inlineCode",{parentName:"p"},"tsconfig.json")," to include the following options:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "compilerOptions": {\n "module": "ES2020",\n "moduleResolution": "node16",\n },\n "ts-node": {\n "esm": true\n }\n}\n')),(0,r.kt)("h3",{id:"update-packagejson-to-module-type"},'Update package.json to "module" type'),(0,r.kt)("p",null,"Add ",(0,r.kt)("inlineCode",{parentName:"p"},'"type": "module"')," to your package.json so that your files will be loaded as ESM modules"),(0,r.kt)("h3",{id:"update-references-to-bin-scripts"},"Update references to bin scripts"),(0,r.kt)("p",null,"You will need to update the references to your bin scripts to the bin scripts with the ",(0,r.kt)("inlineCode",{parentName:"p"},".js")," extension. In the ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json")," you will need to update the ",(0,r.kt)("inlineCode",{parentName:"p"},"bin")," like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},' "bin": {\n "my-cli": "./bin/run"\n },\n')),(0,r.kt)("p",null,"to"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},' "bin": {\n "my-cli": "./bin/run.js"\n },\n')),(0,r.kt)("p",null,"You may have references to the bin scripts in your ",(0,r.kt)("inlineCode",{parentName:"p"},".vscode/launch.json")," or in the ",(0,r.kt)("inlineCode",{parentName:"p"},"scripts")," of your ",(0,r.kt)("inlineCode",{parentName:"p"},"package.json"),". You'll need to update these as well."),(0,r.kt)("h3",{id:"update-mocharc-settings"},"Update mocharc settings"),(0,r.kt)("p",null,"In order for your mocha tests to run, you'll need to make a couple of changes:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Add the following to the ",(0,r.kt)("inlineCode",{parentName:"li"},".mocharc.json"))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "node-option": [\n "loader=ts-node/esm"\n ]\n}\n')),(0,r.kt)("ol",{start:2},(0,r.kt)("li",{parentName:"ol"},"Update ",(0,r.kt)("inlineCode",{parentName:"li"},"test/helpers/init.js"))),(0,r.kt)("p",null,"If your plugin was generated ",(0,r.kt)("inlineCode",{parentName:"p"},"oclif generate")," then you likely have a ",(0,r.kt)("inlineCode",{parentName:"p"},"test/helpers/init.js")," file that needs to be updated. You can either update the file extension to ",(0,r.kt)("inlineCode",{parentName:"p"},".cjs")," or update the ",(0,r.kt)("inlineCode",{parentName:"p"},"require")," at the top of the file to an ",(0,r.kt)("inlineCode",{parentName:"p"},"import"),","),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import path from 'node:path'\n")),(0,r.kt)("p",null,"Alternatively, you can safely delete this file since it's no longer necessary."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6de0e435.c31d17e8.js b/assets/js/6de0e435.ffe363a4.js similarity index 95% rename from assets/js/6de0e435.c31d17e8.js rename to assets/js/6de0e435.ffe363a4.js index 0baca90d..09c901c2 100644 --- a/assets/js/6de0e435.c31d17e8.js +++ b/assets/js/6de0e435.ffe363a4.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6079],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,d=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(d,i(i({ref:t},c),{},{components:n})):r.createElement(d,i({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),a=n(3366),o=(n(7294),n(3905)),i=["components"],l={title:"Customizing Help in oclif"},p=void 0,s={permalink:"/blog/2020/05/05/introducing-custom-help-classes",source:"@site/blog/2020-05-05-introducing-custom-help-classes.md",title:"Customizing Help in oclif",description:"Out of the box oclif provides a great help experience for CLIs.",date:"2020-05-05T00:00:00.000Z",formattedDate:"May 5, 2020",tags:[],readingTime:1.67,hasTruncateMarker:!1,authors:[],frontMatter:{title:"Customizing Help in oclif"},prevItem:{title:"Pretty Printable Errors",permalink:"/blog/2020/07/01/pretty-printable-errors"},nextItem:{title:"oclif TSLint to ESLint Migration",permalink:"/blog/2019/12/05/oclif-eslint-migration"}},c={authorsImageUrls:[]},u=[{value:"Getting started with custom help",id:"getting-started-with-custom-help",level:2},{value:"Separating TOPICS & COMMANDS in the new deafult Help class",id:"separating-topics--commands-in-the-new-deafult-help-class",level:2}],h={toc:u},m="wrapper";function d(e){var t=e.components,n=(0,a.Z)(e,i);return(0,o.kt)(m,(0,r.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs."),(0,o.kt)("p",null,"But what if, as an oclif developer, you want to customize some or all of the output?"),(0,o.kt)("p",null,"You can now customize your CLI's help output by implementing the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class."),(0,o.kt)("h2",{id:"getting-started-with-custom-help"},"Getting started with custom help"),(0,o.kt)("p",null,"If you have not done so yet, update ",(0,o.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ yarn add --latest @oclif/core\n")),(0,o.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,o.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./lib/help"\n // ...\n }\n // ...\n}\n')),(0,o.kt)("p",null,"From here there are two paths, implement the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new ",(0,o.kt)("a",{parentName:"p",href:"../../../../docs/help_classes"},"Help Classes docs"),"."),(0,o.kt)("h2",{id:"separating-topics--commands-in-the-new-deafult-help-class"},"Separating TOPICS & COMMANDS in the new deafult ",(0,o.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,o.kt)("p",null,'Previously, topics and child commands were listed in help output under a single list heading called "COMMANDS". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).'),(0,o.kt)("p",null,"The new default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help"),' class splits the list of children into distinct lists of "TOPICS" and "COMMANDS", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - "COMMANDS" - and what is providing structure - "TOPICS" - when looking at the help output.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"VERSION\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\n\nUSAGE\n $ plugin-help-example [COMMAND]\n\nTOPICS\n topic this is a topic and has child topics or commands\n\nCOMMANDS\n hello describe the command here\n help display help for plugin-help-example\n")),(0,o.kt)("p",null,"We look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6079],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,d=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(d,i(i({ref:t},c),{},{components:n})):r.createElement(d,i({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),a=n(3366),o=(n(7294),n(3905)),i=["components"],l={title:"Customizing Help in oclif"},p=void 0,s={permalink:"/blog/2020/05/05/introducing-custom-help-classes",source:"@site/blog/2020-05-05-introducing-custom-help-classes.md",title:"Customizing Help in oclif",description:"Out of the box oclif provides a great help experience for CLIs.",date:"2020-05-05T00:00:00.000Z",formattedDate:"May 5, 2020",tags:[],readingTime:1.67,hasTruncateMarker:!1,authors:[],frontMatter:{title:"Customizing Help in oclif"},prevItem:{title:"Pretty Printable Errors",permalink:"/blog/2020/07/01/pretty-printable-errors"},nextItem:{title:"oclif TSLint to ESLint Migration",permalink:"/blog/2019/12/05/oclif-eslint-migration"}},c={authorsImageUrls:[]},u=[{value:"Getting started with custom help",id:"getting-started-with-custom-help",level:2},{value:"Separating TOPICS & COMMANDS in the new default Help class",id:"separating-topics--commands-in-the-new-default-help-class",level:2}],h={toc:u},m="wrapper";function d(e){var t=e.components,n=(0,a.Z)(e,i);return(0,o.kt)(m,(0,r.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs."),(0,o.kt)("p",null,"But what if, as an oclif developer, you want to customize some or all of the output?"),(0,o.kt)("p",null,"You can now customize your CLI's help output by implementing the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class."),(0,o.kt)("h2",{id:"getting-started-with-custom-help"},"Getting started with custom help"),(0,o.kt)("p",null,"If you have not done so yet, update ",(0,o.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ yarn add --latest @oclif/core\n")),(0,o.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,o.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./lib/help"\n // ...\n }\n // ...\n}\n')),(0,o.kt)("p",null,"From here there are two paths, implement the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new ",(0,o.kt)("a",{parentName:"p",href:"../../../../docs/help_classes"},"Help Classes docs"),"."),(0,o.kt)("h2",{id:"separating-topics--commands-in-the-new-default-help-class"},"Separating TOPICS & COMMANDS in the new default ",(0,o.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,o.kt)("p",null,'Previously, topics and child commands were listed in help output under a single list heading called "COMMANDS". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).'),(0,o.kt)("p",null,"The new default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help"),' class splits the list of children into distinct lists of "TOPICS" and "COMMANDS", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - "COMMANDS" - and what is providing structure - "TOPICS" - when looking at the help output.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"VERSION\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\n\nUSAGE\n $ plugin-help-example [COMMAND]\n\nTOPICS\n topic this is a topic and has child topics or commands\n\nCOMMANDS\n hello describe the command here\n help display help for plugin-help-example\n")),(0,o.kt)("p",null,"We look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6f3bb722.458468c6.js b/assets/js/6f3bb722.9a353140.js similarity index 99% rename from assets/js/6f3bb722.458468c6.js rename to assets/js/6f3bb722.9a353140.js index b6415495..97db2dd3 100644 --- a/assets/js/6f3bb722.458468c6.js +++ b/assets/js/6f3bb722.9a353140.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8504],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=o.createContext({}),m=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=m(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=m(n),u=r,h=c["".concat(l,".").concat(u)]||c[u]||p[u]||a;return n?o.createElement(h,i(i({ref:t},d),{},{components:n})):o.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var m=2;m{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>m,toc:()=>c});var o=n(7462),r=n(3366),a=(n(7294),n(3905)),i=["components"],s={title:"Commands"},l=void 0,m={unversionedId:"commands",id:"commands",title:"Commands",description:"A basic command looks like the following in TypeScript:",source:"@site/../docs/commands.md",sourceDirName:".",slug:"/commands",permalink:"/docs/commands",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/commands.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Commands"},sidebar:"docs",previous:{title:"Command Discovery Strategies",permalink:"/docs/command_discovery_strategies"},next:{title:"Command Arguments",permalink:"/docs/args"}},d={},c=[{value:"Avoiding Timeouts",id:"avoiding-timeouts",level:3},{value:"Other Command Options",id:"other-command-options",level:3},{value:"Command Methods",id:"command-methods",level:2},{value:"this.log(message: string)",id:"thislogmessage-string",level:3},{value:"this.warn(message: string | Error)",id:"thiswarnmessage-string--error",level:3},{value:"this.error(message: string | Error, options?: {code?: string, exit?: number, ref?: string; suggestions?: string[];})",id:"thiserrormessage-string--error-options-code-string-exit-number-ref-string-suggestions-string",level:3},{value:"this.exit(code: number = 0)",id:"thisexitcode-number--0",level:3},{value:"this.logToStderr(message: string)",id:"thislogtostderrmessage-string",level:3},{value:"this.jsonEnabled()",id:"thisjsonenabled",level:3},{value:"this.toSuccessJson(result: unknown)",id:"thistosuccessjsonresult-unknown",level:3},{value:"this.toErrorJson(result: unknown)",id:"thistoerrorjsonresult-unknown",level:3}],p={toc:c},u="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A basic command looks like the following in TypeScript:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"import {Command} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static description = 'description of this example command'\n\n async run(): Promise {\n console.log('running my command')\n }\n}\n")),(0,a.kt)("p",null,"The only part that is required is the run function. Accept user input with ",(0,a.kt)("a",{parentName:"p",href:"/docs/args"},"arguments")," and ",(0,a.kt)("a",{parentName:"p",href:"/docs/flags"},"flags"),"."),(0,a.kt)("p",null,"In JavaScript:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {Command} = require('@oclif/core')\n\nclass MyCommand extends Command {\n async run() {\n console.log('running my command')\n }\n}\n\nMyCommand.description = 'description of this example command'\n\nmodule.exports = MyCommand\n")),(0,a.kt)("p",null,"Note that the following examples will be in TypeScript. As JavaScript does not yet have static class properties, you will have to add them to the class after it is declared like we did with the description above."),(0,a.kt)("h3",{id:"avoiding-timeouts"},"Avoiding Timeouts"),(0,a.kt)("p",null,"In order to avoid command executions running indefinitely, oclif will terminate the node process 10 seconds after ",(0,a.kt)("inlineCode",{parentName:"p"},"Command.run")," resolves. This means that all command logic inside the ",(0,a.kt)("inlineCode",{parentName:"p"},"run")," method should either run synchronously or should return a ",(0,a.kt)("inlineCode",{parentName:"p"},"Promise"),". This will allow the entire command to run before the 10 second timeout starts."),(0,a.kt)("p",null,"In other words, ",(0,a.kt)("strong",{parentName:"p"},"if you execute a promise in ",(0,a.kt)("inlineCode",{parentName:"strong"},"Command.run")," without a awaiting it, then the command will likely timeout before it's completed.")),(0,a.kt)("h3",{id:"other-command-options"},"Other Command Options"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/command.ts"},"See the base class to get an idea of what methods can be called on a command"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static summary = 'A brief overview of your command.'\n static description = `\nAn in-depth description of the command.\nIt can be multiline.\n`\n\n // hide the command from help\n static hidden = false\n\n // custom usage string for help\n // this overrides the default usage\n static usage = 'mycommand --myflag'\n\n // examples to add to help\n // <%= config.bin %> resolves to the executable name\n // <%= command.id %> resolves to the command name\n static examples = [\n // Examples can be simple strings\n '<%= config.bin %> <%= command.id %> --help',\n // Or objects that provide a description of the example command\n {\n description: 'Force the command to execute',\n command: '<%= config.bin %> <%= command.id %> --force',\n }\n ]\n\n // this makes the parser not fail when it receives invalid arguments\n // defaults to true\n // set it to false if you need to accept a variable number of arguments\n static strict = false\n\n // define aliases that can execute this command.\n static aliases = ['alternate:name:for:this:command']\n\n // Set to true if you want to add the --json flag to your command.\n // oclif will automatically suppress logs (if you use this.log, this.warn, or this.error) and\n // display the JSON returned by the command's run method.\n static enableJsonFlag = true\n\n async run() {\n // show a warning\n this.warn('uh oh!')\n // exit with an error message\n this.error('uh oh!!!')\n // exit with status code\n this.exit(1)\n }\n}\n")),(0,a.kt)("h2",{id:"command-methods"},"Command Methods"),(0,a.kt)("p",null,""),(0,a.kt)("p",null,"The following assumes you are in the ",(0,a.kt)("inlineCode",{parentName:"p"},"run()")," method of an oclif ",(0,a.kt)("a",{parentName:"p",href:"/docs/commands"},"command"),"."),(0,a.kt)("h3",{id:"thislogmessage-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.log(message: string)")),(0,a.kt)("p",null,"Output message to stdout (non-blocking). ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log()")," works fine too, but that is a blocking call and won't be automatically suppressed when the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag is present. This uses ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/api/util.html#util_util_format_format_args"},"util.format()")," which behaves the same as ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log()"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.log('hello, world!')\n")),(0,a.kt)("h3",{id:"thiswarnmessage-string--error"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.warn(message: string | Error)")),(0,a.kt)("p",null,"Display an error or message as a warning"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.warn('uh oh!')\nthis.warn(new Error('uh oh!'))\n")),(0,a.kt)("h3",{id:"thiserrormessage-string--error-options-code-string-exit-number-ref-string-suggestions-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.error(message: string | Error, options?: {code?: string, exit?: number, ref?: string; suggestions?: string[];})")),(0,a.kt)("p",null,"Display error and exit. Also add a code to error object or exit status."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.error('uh oh!', {exit: 2})\nthis.error(new Error('uh oh!'))\n")),(0,a.kt)("p",null,"The options object has the following options:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"exit")," \u2014 exit code to use"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"code")," \u2014 a unique error code for the type of error"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"suggestions")," \u2014 an array of suggestions for a user to try next that may be useful or provide additional context"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ref")," \u2014 a url to documentation related to this error or fixing it")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"message"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"code"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"suggestions"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"ref")," properties will be displayed when an error is shown. Reusable ",(0,a.kt)("inlineCode",{parentName:"p"},"Error")," classes can be created that display the optional outputs above by implementing the ",(0,a.kt)("inlineCode",{parentName:"p"},"PrettyPrintableError")," interface from the ",(0,a.kt)("inlineCode",{parentName:"p"},"Errors")," namespace from ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/core")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"this.error")," will handle them appropriately."),(0,a.kt)("p",null,"These errors are friendly and won't show a traceback unless debugging is enabled with ",(0,a.kt)("inlineCode",{parentName:"p"},"DEBUG=*")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"CLI_NAME_DEBUG=1"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {CLIError} from '@oclif/errors'\n\nthrow new CLIError('my friendly error')\n")),(0,a.kt)("p",null,"Any error caught by the command of this ",(0,a.kt)("inlineCode",{parentName:"p"},"CLIError")," type will be shown without traceback."),(0,a.kt)("h3",{id:"thisexitcode-number--0"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.exit(code: number = 0)")),(0,a.kt)("p",null,"Exit process. Defaults to status 0."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.exit()\nthis.exit(1)\n")),(0,a.kt)("h3",{id:"thislogtostderrmessage-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.logToStderr(message: string)")),(0,a.kt)("p",null,"Log a message to the terminal's ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr"),"."),(0,a.kt)("h3",{id:"thisjsonenabled"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.jsonEnabled()")),(0,a.kt)("p",null,"Returns to ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," if the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag is present and ",(0,a.kt)("inlineCode",{parentName:"p"},"enableJsonFlag")," is set to ",(0,a.kt)("inlineCode",{parentName:"p"},"true")),(0,a.kt)("h3",{id:"thistosuccessjsonresult-unknown"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.toSuccessJson(result: unknown)")),(0,a.kt)("p",null,"Modify the command's success JSON output before it's displayed to the user."),(0,a.kt)("h3",{id:"thistoerrorjsonresult-unknown"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.toErrorJson(result: unknown)")),(0,a.kt)("p",null,"Modify the command's error JSON output before it's displayed to the user."))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8504],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=o.createContext({}),m=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=m(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=m(n),u=r,h=c["".concat(l,".").concat(u)]||c[u]||p[u]||a;return n?o.createElement(h,i(i({ref:t},d),{},{components:n})):o.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var m=2;m{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>m,toc:()=>c});var o=n(7462),r=n(3366),a=(n(7294),n(3905)),i=["components"],s={title:"Commands"},l=void 0,m={unversionedId:"commands",id:"commands",title:"Commands",description:"A basic command looks like the following in TypeScript:",source:"@site/../docs/commands.md",sourceDirName:".",slug:"/commands",permalink:"/docs/commands",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/commands.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Commands"},sidebar:"docs",previous:{title:"Command Discovery Strategies",permalink:"/docs/command_discovery_strategies"},next:{title:"Command Arguments",permalink:"/docs/args"}},d={},c=[{value:"Avoiding Timeouts",id:"avoiding-timeouts",level:3},{value:"Other Command Options",id:"other-command-options",level:3},{value:"Command Methods",id:"command-methods",level:2},{value:"this.log(message: string)",id:"thislogmessage-string",level:3},{value:"this.warn(message: string | Error)",id:"thiswarnmessage-string--error",level:3},{value:"this.error(message: string | Error, options?: {code?: string, exit?: number, ref?: string; suggestions?: string[];})",id:"thiserrormessage-string--error-options-code-string-exit-number-ref-string-suggestions-string",level:3},{value:"this.exit(code: number = 0)",id:"thisexitcode-number--0",level:3},{value:"this.logToStderr(message: string)",id:"thislogtostderrmessage-string",level:3},{value:"this.jsonEnabled()",id:"thisjsonenabled",level:3},{value:"this.toSuccessJson(result: unknown)",id:"thistosuccessjsonresult-unknown",level:3},{value:"this.toErrorJson(result: unknown)",id:"thistoerrorjsonresult-unknown",level:3}],p={toc:c},u="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A basic command looks like the following in TypeScript:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"import {Command} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static description = 'description of this example command'\n\n async run(): Promise {\n console.log('running my command')\n }\n}\n")),(0,a.kt)("p",null,"The only part that is required is the run function. Accept user input with ",(0,a.kt)("a",{parentName:"p",href:"/docs/args"},"arguments")," and ",(0,a.kt)("a",{parentName:"p",href:"/docs/flags"},"flags"),"."),(0,a.kt)("p",null,"In JavaScript:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {Command} = require('@oclif/core')\n\nclass MyCommand extends Command {\n async run() {\n console.log('running my command')\n }\n}\n\nMyCommand.description = 'description of this example command'\n\nmodule.exports = MyCommand\n")),(0,a.kt)("p",null,"Note that the following examples will be in TypeScript. As JavaScript does not yet have static class properties, you will have to add them to the class after it is declared like we did with the description above."),(0,a.kt)("h3",{id:"avoiding-timeouts"},"Avoiding Timeouts"),(0,a.kt)("p",null,"In order to avoid command executions running indefinitely, oclif will terminate the node process 10 seconds after ",(0,a.kt)("inlineCode",{parentName:"p"},"Command.run")," resolves. This means that all command logic inside the ",(0,a.kt)("inlineCode",{parentName:"p"},"run")," method should either run synchronously or should return a ",(0,a.kt)("inlineCode",{parentName:"p"},"Promise"),". This will allow the entire command to run before the 10 second timeout starts."),(0,a.kt)("p",null,"In other words, ",(0,a.kt)("strong",{parentName:"p"},"if you execute a promise in ",(0,a.kt)("inlineCode",{parentName:"strong"},"Command.run")," without a awaiting it, then the command will likely timeout before it's completed.")),(0,a.kt)("h3",{id:"other-command-options"},"Other Command Options"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/command.ts"},"See the base class to get an idea of what methods can be called on a command"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static summary = 'A brief overview of your command.'\n static description = `\nAn in-depth description of the command.\nIt can be multiline.\n`\n\n // hide the command from help\n static hidden = false\n\n // custom usage string for help\n // this overrides the default usage\n static usage = 'mycommand --myflag'\n\n // examples to add to help\n // <%= config.bin %> resolves to the executable name\n // <%= command.id %> resolves to the command name\n static examples = [\n // Examples can be simple strings\n '<%= config.bin %> <%= command.id %> --help',\n // Or objects that provide a description of the example command\n {\n description: 'Force the command to execute',\n command: '<%= config.bin %> <%= command.id %> --force',\n }\n ]\n\n // this makes the parser not fail when it receives invalid arguments\n // defaults to true\n // set it to false if you need to accept a variable number of arguments\n static strict = false\n\n // define aliases that can execute this command.\n static aliases = ['alternate:name:for:this:command']\n\n // Set to true if you want to add the --json flag to your command.\n // oclif will automatically suppress logs (if you use this.log, this.warn, or this.error) and\n // display the JSON returned by the command's run method.\n static enableJsonFlag = true\n\n async run() {\n // show a warning\n this.warn('uh oh!')\n // exit with an error message\n this.error('uh oh!!!')\n // exit with status code\n this.exit(1)\n }\n}\n")),(0,a.kt)("h2",{id:"command-methods"},"Command Methods"),(0,a.kt)("p",null,""),(0,a.kt)("p",null,"The following assumes you are in the ",(0,a.kt)("inlineCode",{parentName:"p"},"run()")," method of an oclif ",(0,a.kt)("a",{parentName:"p",href:"/docs/commands"},"command"),"."),(0,a.kt)("h3",{id:"thislogmessage-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.log(message: string)")),(0,a.kt)("p",null,"Output message to stdout (non-blocking). ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log()")," works fine too, but that is a blocking call and won't be automatically suppressed when the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag is present. This uses ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/api/util.html#util_util_format_format_args"},"util.format()")," which behaves the same as ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log()"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.log('hello, world!')\n")),(0,a.kt)("h3",{id:"thiswarnmessage-string--error"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.warn(message: string | Error)")),(0,a.kt)("p",null,"Display an error or message as a warning"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.warn('uh oh!')\nthis.warn(new Error('uh oh!'))\n")),(0,a.kt)("h3",{id:"thiserrormessage-string--error-options-code-string-exit-number-ref-string-suggestions-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.error(message: string | Error, options?: {code?: string, exit?: number, ref?: string; suggestions?: string[];})")),(0,a.kt)("p",null,"Display error and exit. Also add a code to error object or exit status."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.error('uh oh!', {exit: 2})\nthis.error(new Error('uh oh!'))\n")),(0,a.kt)("p",null,"The options object has the following options:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"exit")," \u2014 exit code to use"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"code")," \u2014 a unique error code for the type of error"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"suggestions")," \u2014 an array of suggestions for a user to try next that may be useful or provide additional context"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ref")," \u2014 a url to documentation related to this error or fixing it")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"message"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"code"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"suggestions"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"ref")," properties will be displayed when an error is shown. Reusable ",(0,a.kt)("inlineCode",{parentName:"p"},"Error")," classes can be created that display the optional outputs above by implementing the ",(0,a.kt)("inlineCode",{parentName:"p"},"PrettyPrintableError")," interface from the ",(0,a.kt)("inlineCode",{parentName:"p"},"Errors")," namespace from ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/core")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"this.error")," will handle them appropriately."),(0,a.kt)("p",null,"These errors are friendly and won't show a traceback unless debugging is enabled with ",(0,a.kt)("inlineCode",{parentName:"p"},"DEBUG=*")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"CLI_NAME_DEBUG=1"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {CLIError} from '@oclif/errors'\n\nthrow new CLIError('my friendly error')\n")),(0,a.kt)("p",null,"Any error caught by the command of this ",(0,a.kt)("inlineCode",{parentName:"p"},"CLIError")," type will be shown without traceback."),(0,a.kt)("h3",{id:"thisexitcode-number--0"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.exit(code: number = 0)")),(0,a.kt)("p",null,"Exit process. Defaults to status 0."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"this.exit()\nthis.exit(1)\n")),(0,a.kt)("h3",{id:"thislogtostderrmessage-string"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.logToStderr(message: string)")),(0,a.kt)("p",null,"Log a message to the terminal's ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr"),"."),(0,a.kt)("h3",{id:"thisjsonenabled"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.jsonEnabled()")),(0,a.kt)("p",null,"Returns to ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," if the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag is present and ",(0,a.kt)("inlineCode",{parentName:"p"},"enableJsonFlag")," is set to ",(0,a.kt)("inlineCode",{parentName:"p"},"true")),(0,a.kt)("h3",{id:"thistosuccessjsonresult-unknown"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.toSuccessJson(result: unknown)")),(0,a.kt)("p",null,"Modify the command's success JSON output before it's displayed to the user."),(0,a.kt)("h3",{id:"thistoerrorjsonresult-unknown"},(0,a.kt)("inlineCode",{parentName:"h3"},"this.toErrorJson(result: unknown)")),(0,a.kt)("p",null,"Modify the command's error JSON output before it's displayed to the user."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/713bb917.2de4941a.js b/assets/js/713bb917.ce493d17.js similarity index 99% rename from assets/js/713bb917.2de4941a.js rename to assets/js/713bb917.ce493d17.js index 6ff2d893..2ff104d0 100644 --- a/assets/js/713bb917.2de4941a.js +++ b/assets/js/713bb917.ce493d17.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[187],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),d=p(n),h=i,m=d["".concat(s,".").concat(h)]||d[h]||u[h]||l;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,o=new Array(l);o[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[d]="string"==typeof e?e:i,o[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>p,toc:()=>d});var a=n(7462),i=n(3366),l=(n(7294),n(3905)),o=["components"],r={title:"Release"},s=void 0,p={unversionedId:"releasing",id:"releasing",title:"Release",description:"There are 2 main strategies for releasing oclif CLIs: npm and standalone tarballs. You can publish to one or both.",source:"@site/../docs/releasing.md",sourceDirName:".",slug:"/releasing",permalink:"/docs/releasing",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/releasing.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Release"},sidebar:"docs",previous:{title:"JSON",permalink:"/docs/json"},next:{title:"Testing",permalink:"/docs/testing"}},c={},d=[{value:"npm",id:"npm",level:2},{value:"Standalone tarballs",id:"standalone-tarballs",level:2},{value:"Brew",id:"brew",level:2},{value:"Autoupdater",id:"autoupdater",level:2},{value:"Autoupdate Channels",id:"autoupdate-channels",level:2},{value:"Windows installer",id:"windows-installer",level:2},{value:"macOS installer",id:"macos-installer",level:2},{value:"Uploading to S3",id:"uploading-to-s3",level:3},{value:"Signing the installer",id:"signing-the-installer",level:3},{value:"Ubuntu/Debian packages",id:"ubuntudebian-packages",level:2},{value:"Snapcraft",id:"snapcraft",level:2}],u={toc:d},h="wrapper";function m(e){var t=e.components,n=(0,i.Z)(e,o);return(0,l.kt)(h,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"There are 2 main strategies for releasing oclif CLIs: npm and standalone tarballs. You can publish to one or both."),(0,l.kt)("h2",{id:"npm"},"npm"),(0,l.kt)("p",null,"Just use ",(0,l.kt)("inlineCode",{parentName:"p"},"npm publish")," like any other npm project. This includes a ",(0,l.kt)("inlineCode",{parentName:"p"},"run.cmd")," script that will automatically be used for Windows users."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ npm version (major|minor|patch) # bumps version, updates README, adds git tag\n$ npm publish\n$ npm install -g mynewcli\n$ mynewcli\n# OR\n$ npx mynewcli\n")),(0,l.kt)("p",null,"You'll need to ",(0,l.kt)("a",{parentName:"p",href:"https://www.npmjs.com/signup"},"register with npm")," and have verified your email address in order to publish."),(0,l.kt)("p",null,"This workflow can be improved slightly by running ",(0,l.kt)("inlineCode",{parentName:"p"},"npm version major|minor|patch")," before publishing which will create a git tag and bump the version automatically."),(0,l.kt)("h2",{id:"standalone-tarballs"},"Standalone tarballs"),(0,l.kt)("p",null,"Build standalone tarballs with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack tarballs")," from the root of your CLI. These include the node binary so the user does not have to already have node installed to use the CLI. It won't put this node binary on the PATH so the binary will not conflict with any node installation on the machine."),(0,l.kt)("p",null,"To publish, you can copy the files from ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist")," or use ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload tarballs")," to copy the files to S3. You'll need to set ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.bucket")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," to a valid S3 bucket and have credentials set in ",(0,l.kt)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," environment vars."),(0,l.kt)("p",null,"After you've uploaded the tarballs to S3, you can promote the tarballs to a release channel within S3 using ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote"),". This allows you to quickly promote and demote a specific version between release channels. For example, the Salesforce CLI has separate ",(0,l.kt)("inlineCode",{parentName:"p"},"stable")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"stable-rc")," channels that are updated weekly."),(0,l.kt)("h2",{id:"brew"},"Brew"),(0,l.kt)("p",null,"Your formula can be distributed through Brew. The main caveat is you must set the ",(0,l.kt)("inlineCode",{parentName:"p"},"CLIENT_HOME")," variable when you ship, otherwise it will break the update cycle. An example of this can be found in the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/heroku/homebrew-brew/blob/master/Formula/heroku.rb#L9"},"heroku cli formula"),". By exporting a variable of the form ",(0,l.kt)("inlineCode",{parentName:"p"},"CLI_NAME_OCLIF_CLIENT_HOME")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"CLI_NAME")," is the name of your CLI), you force the update mechanism to look at the brew install location instead of the default (which is ",(0,l.kt)("inlineCode",{parentName:"p"},"$XDG_DATA_HOME/.local/share/package_name/client"),")."),(0,l.kt)("h2",{id:"autoupdater"},"Autoupdater"),(0,l.kt)("p",null,"These tarballs as well as the installers below can be made autoupdatable by adding the ",(0,l.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-update")," plugin. Just add this plugin and the CLI will autoupdate in the background or when ",(0,l.kt)("inlineCode",{parentName:"p"},"mycli update")," is run."),(0,l.kt)("p",null,"If you don't want to use S3, you can still run ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack")," and it will build tarballs. To get the updater to work, set ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.host")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," to a host that has the files built in ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack"),". This host does not need to be an S3 host. To customize the URL paths, see the S3 templates in ",(0,l.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,l.kt)("h2",{id:"autoupdate-channels"},"Autoupdate Channels"),(0,l.kt)("p",null,"You can have separate channels for releases that work like Google Chrome Channels (such as beta, dev, canary). To create a channel, just change the version in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0-beta"),' (where "beta" is any string you like). Then when you pack with ',(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack"),", it will create beta tarballs. The user can change their channel with ",(0,l.kt)("inlineCode",{parentName:"p"},"mycli update beta")," and will receive all the future releases on that channel."),(0,l.kt)("p",null,"In the Heroku CLI, we have it automatically build and release the beta channel on every commit to the master branch. Then we have it build and release stable channel whenever a git tag is created in our CI."),(0,l.kt)("h2",{id:"windows-installer"},"Windows installer"),(0,l.kt)("p",null,"Build a windows installer with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack win"),". It will build into ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/win"),". This can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload win")," and promoted within S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --win"),"."),(0,l.kt)("p",null,"The installer uses 7zip and nsis. If you're in a mac or unix environment and don't have them, you can use homebrew to insall them."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"brew install nsis\nbrew install p7zip\n")),(0,l.kt)("h2",{id:"macos-installer"},"macOS installer"),(0,l.kt)("p",null,"Build a macOS .pkg installer with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack macos"),". It will build into ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/macos"),". This can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload macos")," and promoted within S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --macos"),". You need to set the macOS identifier at ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.macos.identifier")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),' (we use "com.heroku.cli" and "com.salesforce.cli" as the identifiers for the Heroku CLI and the Salesforce CLI, respectively).'),(0,l.kt)("h3",{id:"uploading-to-s3"},"Uploading to S3"),(0,l.kt)("p",null,"The upload command defaults to using the ACL setting ",(0,l.kt)("inlineCode",{parentName:"p"},"public-read")," unless another policy is specified under ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.acl")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),". However, when creating new S3 buckets, AWS's default recommendation can result in an access error (Code: AccessControlListNotSupported) when trying to upload with the ",(0,l.kt)("inlineCode",{parentName:"p"},"public-read")," setting."),(0,l.kt)("p",null,"To address this, consider updating the oclif section of your package.json with the desired ACL setting. The example below demonstrates how to set the acl to bucket-owner-full-control:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'"oclif": {\n "bin": "myOclifApp",\n "dirname": "myOclifApp-cli-data",\n "update": {\n "s3": {\n "host": "https://s3.console.aws.amazon.com/",\n "bucket": "myOclifApp-cli",\n "acl": "bucket-owner-full-control"\n }\n },\n "macos": {\n "identifier": "com.myOclifApp.cli"\n },\n\n...\n\n}\n')),(0,l.kt)("p",null,"Amazon has a userguide ",(0,l.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ensure-object-ownership.html#ensure-object-ownership-bucket-policy"},"here")," for help how to configure Bucket Policy settings."),(0,l.kt)("h3",{id:"signing-the-installer"},"Signing the installer"),(0,l.kt)("p",null,'To be able to sign an "installer signing identity" has to be available on the build machine (read more on certificates ',(0,l.kt)("a",{parentName:"p",href:"https://developer.apple.com/help/account/create-certificates/certificates-overview"},"here"),").",(0,l.kt)("br",{parentName:"p"}),"\n","Make sure such a certificate is created in developer.apple.com and that the certificate is downloaded and installed in the KeyChain of the build machine.",(0,l.kt)("br",{parentName:"p"}),"\n","The certificate name has to be specified in the ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.macos.sign")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),". "),(0,l.kt)("p",null,"Example: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},' "macos": {\n "identifier": "com.myOclifApp",\n "sign": "\\"3rd Party Mac Developer Installer: myOclifCompany (R2315646)\\""\n },\n')),(0,l.kt)("p",null,"Pay attention to the escaped quotation marks, the certificate name is passed on as an argument to the ",(0,l.kt)("inlineCode",{parentName:"p"},"pkgbuild")," command so without quotation marks it might break.",(0,l.kt)("br",{parentName:"p"}),"\n",'For the Heroku CLI the certificate name is "Developer ID Installer: Heroku INC". And optionally set the keychain with ',(0,l.kt)("inlineCode",{parentName:"p"},"OSX_KEYCHAIN"),"."),(0,l.kt)("p",null,"Installed certificates on the build machine can be viewed in the Keychain Access app."),(0,l.kt)("h2",{id:"ubuntudebian-packages"},"Ubuntu/Debian packages"),(0,l.kt)("p",null,"Build a deb package with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack deb"),". Set the ",(0,l.kt)("inlineCode",{parentName:"p"},"MYCLI_DEB_KEY")," to a gpg key id to create the gpg files. This will include all the files needed for an apt repository in ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/deb"),". They can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload deb")," and promoted within S3 using ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --deb"),"."),(0,l.kt)("p",null,"Once it's published to S3, users can install with the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh-session"},'$ wget -qO- https://mys3bucket.s3.amazonaws.com/apt/release.key | apt-key add - # you will need to upload this file manually\n$ sudo echo "deb https://mys3bucket.s3.amazonaws.com/apt ./" > /etc/apt/sources.list.d/mycli.list\n$ sudo apt update\n$ sudo apt install -y mycli\n')),(0,l.kt)("p",null,"This can be placed in a ",(0,l.kt)("a",{parentName:"p",href:"https://cli-assets.heroku.com/install-ubuntu.sh"},"script")," for users to install with ",(0,l.kt)("inlineCode",{parentName:"p"},"curl https://pathto/myscript | sh"),"."),(0,l.kt)("p",null,"These will not autoupdate as Ubuntu already has a reliable way for users to update their package."),(0,l.kt)("h2",{id:"snapcraft"},"Snapcraft"),(0,l.kt)("p",null,"Snap is a great way to distribute Linux CLIs and comes built into Ubuntu 16+. The Heroku CLI's ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/heroku/cli/blob/master/snap/snapcraft.yaml"},"snapcraft.yml")," file can be easily modified to work with any oclif CLI."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[187],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),d=p(n),h=i,m=d["".concat(s,".").concat(h)]||d[h]||u[h]||l;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,o=new Array(l);o[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[d]="string"==typeof e?e:i,o[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>p,toc:()=>d});var a=n(7462),i=n(3366),l=(n(7294),n(3905)),o=["components"],r={title:"Release"},s=void 0,p={unversionedId:"releasing",id:"releasing",title:"Release",description:"There are 2 main strategies for releasing oclif CLIs: npm and standalone tarballs. You can publish to one or both.",source:"@site/../docs/releasing.md",sourceDirName:".",slug:"/releasing",permalink:"/docs/releasing",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/releasing.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Release"},sidebar:"docs",previous:{title:"JSON",permalink:"/docs/json"},next:{title:"Testing",permalink:"/docs/testing"}},c={},d=[{value:"npm",id:"npm",level:2},{value:"Standalone tarballs",id:"standalone-tarballs",level:2},{value:"Brew",id:"brew",level:2},{value:"Autoupdater",id:"autoupdater",level:2},{value:"Autoupdate Channels",id:"autoupdate-channels",level:2},{value:"Windows installer",id:"windows-installer",level:2},{value:"macOS installer",id:"macos-installer",level:2},{value:"Uploading to S3",id:"uploading-to-s3",level:3},{value:"Signing the installer",id:"signing-the-installer",level:3},{value:"Ubuntu/Debian packages",id:"ubuntudebian-packages",level:2},{value:"Snapcraft",id:"snapcraft",level:2}],u={toc:d},h="wrapper";function m(e){var t=e.components,n=(0,i.Z)(e,o);return(0,l.kt)(h,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"There are 2 main strategies for releasing oclif CLIs: npm and standalone tarballs. You can publish to one or both."),(0,l.kt)("h2",{id:"npm"},"npm"),(0,l.kt)("p",null,"Just use ",(0,l.kt)("inlineCode",{parentName:"p"},"npm publish")," like any other npm project. This includes a ",(0,l.kt)("inlineCode",{parentName:"p"},"run.cmd")," script that will automatically be used for Windows users."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh-session"},"$ npm version (major|minor|patch) # bumps version, updates README, adds git tag\n$ npm publish\n$ npm install -g mynewcli\n$ mynewcli\n# OR\n$ npx mynewcli\n")),(0,l.kt)("p",null,"You'll need to ",(0,l.kt)("a",{parentName:"p",href:"https://www.npmjs.com/signup"},"register with npm")," and have verified your email address in order to publish."),(0,l.kt)("p",null,"This workflow can be improved slightly by running ",(0,l.kt)("inlineCode",{parentName:"p"},"npm version major|minor|patch")," before publishing which will create a git tag and bump the version automatically."),(0,l.kt)("h2",{id:"standalone-tarballs"},"Standalone tarballs"),(0,l.kt)("p",null,"Build standalone tarballs with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack tarballs")," from the root of your CLI. These include the node binary so the user does not have to already have node installed to use the CLI. It won't put this node binary on the PATH so the binary will not conflict with any node installation on the machine."),(0,l.kt)("p",null,"To publish, you can copy the files from ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist")," or use ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload tarballs")," to copy the files to S3. You'll need to set ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.bucket")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," to a valid S3 bucket and have credentials set in ",(0,l.kt)("inlineCode",{parentName:"p"},"AWS_ACCESS_KEY_ID")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"AWS_SECRET_ACCESS_KEY")," environment vars."),(0,l.kt)("p",null,"After you've uploaded the tarballs to S3, you can promote the tarballs to a release channel within S3 using ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote"),". This allows you to quickly promote and demote a specific version between release channels. For example, the Salesforce CLI has separate ",(0,l.kt)("inlineCode",{parentName:"p"},"stable")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"stable-rc")," channels that are updated weekly."),(0,l.kt)("h2",{id:"brew"},"Brew"),(0,l.kt)("p",null,"Your formula can be distributed through Brew. The main caveat is you must set the ",(0,l.kt)("inlineCode",{parentName:"p"},"CLIENT_HOME")," variable when you ship, otherwise it will break the update cycle. An example of this can be found in the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/heroku/homebrew-brew/blob/master/Formula/heroku.rb#L9"},"heroku cli formula"),". By exporting a variable of the form ",(0,l.kt)("inlineCode",{parentName:"p"},"CLI_NAME_OCLIF_CLIENT_HOME")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"CLI_NAME")," is the name of your CLI), you force the update mechanism to look at the brew install location instead of the default (which is ",(0,l.kt)("inlineCode",{parentName:"p"},"$XDG_DATA_HOME/.local/share/package_name/client"),")."),(0,l.kt)("h2",{id:"autoupdater"},"Autoupdater"),(0,l.kt)("p",null,"These tarballs as well as the installers below can be made autoupdatable by adding the ",(0,l.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-update")," plugin. Just add this plugin and the CLI will autoupdate in the background or when ",(0,l.kt)("inlineCode",{parentName:"p"},"mycli update")," is run."),(0,l.kt)("p",null,"If you don't want to use S3, you can still run ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack")," and it will build tarballs. To get the updater to work, set ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.host")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," to a host that has the files built in ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack"),". This host does not need to be an S3 host. To customize the URL paths, see the S3 templates in ",(0,l.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,l.kt)("h2",{id:"autoupdate-channels"},"Autoupdate Channels"),(0,l.kt)("p",null,"You can have separate channels for releases that work like Google Chrome Channels (such as beta, dev, canary). To create a channel, just change the version in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0-beta"),' (where "beta" is any string you like). Then when you pack with ',(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack"),", it will create beta tarballs. The user can change their channel with ",(0,l.kt)("inlineCode",{parentName:"p"},"mycli update beta")," and will receive all the future releases on that channel."),(0,l.kt)("p",null,"In the Heroku CLI, we have it automatically build and release the beta channel on every commit to the master branch. Then we have it build and release stable channel whenever a git tag is created in our CI."),(0,l.kt)("h2",{id:"windows-installer"},"Windows installer"),(0,l.kt)("p",null,"Build a windows installer with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack win"),". It will build into ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/win"),". This can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload win")," and promoted within S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --win"),"."),(0,l.kt)("p",null,"The installer uses 7zip and nsis. If you're in a mac or unix environment and don't have them, you can use homebrew to insall them."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"brew install nsis\nbrew install p7zip\n")),(0,l.kt)("h2",{id:"macos-installer"},"macOS installer"),(0,l.kt)("p",null,"Build a macOS .pkg installer with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack macos"),". It will build into ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/macos"),". This can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload macos")," and promoted within S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --macos"),". You need to set the macOS identifier at ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.macos.identifier")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),' (we use "com.heroku.cli" and "com.salesforce.cli" as the identifiers for the Heroku CLI and the Salesforce CLI, respectively).'),(0,l.kt)("h3",{id:"uploading-to-s3"},"Uploading to S3"),(0,l.kt)("p",null,"The upload command defaults to using the ACL setting ",(0,l.kt)("inlineCode",{parentName:"p"},"public-read")," unless another policy is specified under ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.update.s3.acl")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),". However, when creating new S3 buckets, AWS's default recommendation can result in an access error (Code: AccessControlListNotSupported) when trying to upload with the ",(0,l.kt)("inlineCode",{parentName:"p"},"public-read")," setting."),(0,l.kt)("p",null,"To address this, consider updating the oclif section of your package.json with the desired ACL setting. The example below demonstrates how to set the acl to bucket-owner-full-control:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'"oclif": {\n "bin": "myOclifApp",\n "dirname": "myOclifApp-cli-data",\n "update": {\n "s3": {\n "host": "https://s3.console.aws.amazon.com/",\n "bucket": "myOclifApp-cli",\n "acl": "bucket-owner-full-control"\n }\n },\n "macos": {\n "identifier": "com.myOclifApp.cli"\n },\n\n...\n\n}\n')),(0,l.kt)("p",null,"Amazon has a userguide ",(0,l.kt)("a",{parentName:"p",href:"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ensure-object-ownership.html#ensure-object-ownership-bucket-policy"},"here")," for help how to configure Bucket Policy settings."),(0,l.kt)("h3",{id:"signing-the-installer"},"Signing the installer"),(0,l.kt)("p",null,'To be able to sign an "installer signing identity" has to be available on the build machine (read more on certificates ',(0,l.kt)("a",{parentName:"p",href:"https://developer.apple.com/help/account/create-certificates/certificates-overview"},"here"),").",(0,l.kt)("br",{parentName:"p"}),"\n","Make sure such a certificate is created in developer.apple.com and that the certificate is downloaded and installed in the KeyChain of the build machine.",(0,l.kt)("br",{parentName:"p"}),"\n","The certificate name has to be specified in the ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif.macos.sign")," in ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),". "),(0,l.kt)("p",null,"Example: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},' "macos": {\n "identifier": "com.myOclifApp",\n "sign": "\\"3rd Party Mac Developer Installer: myOclifCompany (R2315646)\\""\n },\n')),(0,l.kt)("p",null,"Pay attention to the escaped quotation marks, the certificate name is passed on as an argument to the ",(0,l.kt)("inlineCode",{parentName:"p"},"pkgbuild")," command so without quotation marks it might break.",(0,l.kt)("br",{parentName:"p"}),"\n",'For the Heroku CLI the certificate name is "Developer ID Installer: Heroku INC". And optionally set the keychain with ',(0,l.kt)("inlineCode",{parentName:"p"},"OSX_KEYCHAIN"),"."),(0,l.kt)("p",null,"Installed certificates on the build machine can be viewed in the Keychain Access app."),(0,l.kt)("h2",{id:"ubuntudebian-packages"},"Ubuntu/Debian packages"),(0,l.kt)("p",null,"Build a deb package with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif pack deb"),". Set the ",(0,l.kt)("inlineCode",{parentName:"p"},"MYCLI_DEB_KEY")," to a gpg key id to create the gpg files. This will include all the files needed for an apt repository in ",(0,l.kt)("inlineCode",{parentName:"p"},"./dist/deb"),". They can be uploaded to S3 with ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif upload deb")," and promoted within S3 using ",(0,l.kt)("inlineCode",{parentName:"p"},"oclif promote --deb"),"."),(0,l.kt)("p",null,"Once it's published to S3, users can install with the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh-session"},'$ wget -qO- https://mys3bucket.s3.amazonaws.com/apt/release.key | apt-key add - # you will need to upload this file manually\n$ sudo echo "deb https://mys3bucket.s3.amazonaws.com/apt ./" > /etc/apt/sources.list.d/mycli.list\n$ sudo apt update\n$ sudo apt install -y mycli\n')),(0,l.kt)("p",null,"This can be placed in a ",(0,l.kt)("a",{parentName:"p",href:"https://cli-assets.heroku.com/install-ubuntu.sh"},"script")," for users to install with ",(0,l.kt)("inlineCode",{parentName:"p"},"curl https://pathto/myscript | sh"),"."),(0,l.kt)("p",null,"These will not autoupdate as Ubuntu already has a reliable way for users to update their package."),(0,l.kt)("h2",{id:"snapcraft"},"Snapcraft"),(0,l.kt)("p",null,"Snap is a great way to distribute Linux CLIs and comes built into Ubuntu 16+. The Heroku CLI's ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/heroku/cli/blob/master/snap/snapcraft.yaml"},"snapcraft.yml")," file can be easily modified to work with any oclif CLI."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7bd58895.621b46ec.js b/assets/js/7bd58895.45570e39.js similarity index 98% rename from assets/js/7bd58895.621b46ec.js rename to assets/js/7bd58895.45570e39.js index 90491fe7..f20a6c27 100644 --- a/assets/js/7bd58895.621b46ec.js +++ b/assets/js/7bd58895.45570e39.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[257],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>g});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),m=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=m(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),c=m(n),d=o,g=c["".concat(p,".").concat(d)]||c[d]||u[d]||a;return n?r.createElement(g,i(i({ref:t},l),{},{components:n})):r.createElement(g,i({ref:t},l))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:o,i[1]=s;for(var m=2;m{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>p,default:()=>g,frontMatter:()=>s,metadata:()=>m,toc:()=>c});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],s={title:"Prompting"},p=void 0,m={unversionedId:"prompting",id:"prompting",title:"Prompting",description:"The ux export provides a simple cli.prompt() function, for more complex input prompts, we recommend using the inquirer library.",source:"@site/../docs/prompting.md",sourceDirName:".",slug:"/prompting",permalink:"/docs/prompting",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/prompting.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Prompting"},sidebar:"docs",previous:{title:"Custom Base Class",permalink:"/docs/base_class"},next:{title:"Spinner",permalink:"/docs/spinner"}},l={},c=[{value:"ux.prompt()",id:"uxprompt",level:2},{value:"inquirer",id:"inquirer",level:2}],u={toc:c},d="wrapper";function g(e){var t=e.components,s=(0,o.Z)(e,i);return(0,a.kt)(d,(0,r.Z)({},u,s,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/cli-ux/README.md"},"ux")," export provides a simple ",(0,a.kt)("inlineCode",{parentName:"p"},"cli.prompt()")," function, for more complex input prompts, we recommend using the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/SBoudrias/Inquirer.js"},"inquirer")," library."),(0,a.kt)("h2",{id:"uxprompt"},(0,a.kt)("inlineCode",{parentName:"h2"},"ux.prompt()")),(0,a.kt)("p",null,"Prompt for basic input with ",(0,a.kt)("inlineCode",{parentName:"p"},"ux"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport class MyCommand extends Command {\n async run() {\n // just prompt for input\n const name = await ux.prompt('What is your name?')\n\n // mask input after enter is pressed\n const secondFactor = await ux.prompt('What is your two-factor token?', {type: 'mask'})\n\n // hide input while typing\n const password = await ux.prompt('What is your password?', {type: 'hide'})\n\n this.log(`You entered: ${name}, ${secondFactor}, ${password}`)\n }\n}\n")),(0,a.kt)("p",null,"Demo:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"prompt demo",src:n(740).Z,width:"941",height:"605"})),(0,a.kt)("h2",{id:"inquirer"},(0,a.kt)("inlineCode",{parentName:"h2"},"inquirer")),(0,a.kt)("p",null,"Here is an example command that uses ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/SBoudrias/Inquirer.js"},"inquirer"),". You will need to add ",(0,a.kt)("inlineCode",{parentName:"p"},"inquirer")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"@types/inquirer")," (for TypeScript CLIs) for this to work."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\nimport * as inquirer from 'inquirer'\n\nexport class MyCommand extends Command {\n static flags = {\n stage: Flags.string({options: ['development', 'staging', 'production']})\n }\n\n async run() {\n const {flags} = await this.parse(MyCommand)\n let stage = flags.stage\n if (!stage) {\n let responses: any = await inquirer.prompt([{\n name: 'stage',\n message: 'select a stage',\n type: 'list',\n choices: [{name: 'development'}, {name: 'staging'}, {name: 'production'}],\n }])\n stage = responses.stage\n }\n this.log(`the stage is: ${stage}`)\n }\n}\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"NOTE"),": inquirer >= v9 is an ESM package. If you aren't using ESM in your CLI/plugin, you should set ",(0,a.kt)("a",{parentName:"p",href:"https://www.typescriptlang.org/tsconfig#moduleResolution"},(0,a.kt)("inlineCode",{parentName:"a"},"moduleResolution")," to ",(0,a.kt)("inlineCode",{parentName:"a"},"node16"))," in your tsconfig.json and ",(0,a.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import"},"import it using ",(0,a.kt)("inlineCode",{parentName:"a"},"await import")),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static flags = {\n stage: Flags.string({options: ['development', 'staging', 'production']})\n }\n\n async run() {\n const {flags} = await this.parse(MyCommand)\n let stage = flags.stage\n if (!stage) {\n const { default: inquirer } = await import(\"inquirer\")\n let responses: any = inquirer.prompt([{\n name: 'stage',\n message: 'select a stage',\n type: 'list',\n choices: [{name: 'development'}, {name: 'staging'}, {name: 'production'}],\n }])\n stage = responses.stage\n }\n this.log(`the stage is: ${stage}`)\n }\n}\n")),(0,a.kt)("p",null,"Demo:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"inquirer demo",src:n(2813).Z,width:"1254",height:"806"})))}g.isMDXComponent=!0},2813:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/inquirer_demo-4d4cd8f9cf0bf300a5b853a4beef5672.gif"},740:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/prompt_demo-7bc9d5f614fdad73636bec3c864aff15.gif"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[257],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>g});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),m=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=m(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),c=m(n),d=o,g=c["".concat(p,".").concat(d)]||c[d]||u[d]||a;return n?r.createElement(g,i(i({ref:t},l),{},{components:n})):r.createElement(g,i({ref:t},l))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:o,i[1]=s;for(var m=2;m{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>p,default:()=>g,frontMatter:()=>s,metadata:()=>m,toc:()=>c});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),i=["components"],s={title:"Prompting"},p=void 0,m={unversionedId:"prompting",id:"prompting",title:"Prompting",description:"The ux export provides a simple cli.prompt() function, for more complex input prompts, we recommend using the inquirer library.",source:"@site/../docs/prompting.md",sourceDirName:".",slug:"/prompting",permalink:"/docs/prompting",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/prompting.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Prompting"},sidebar:"docs",previous:{title:"Custom Base Class",permalink:"/docs/base_class"},next:{title:"Spinner",permalink:"/docs/spinner"}},l={},c=[{value:"ux.prompt()",id:"uxprompt",level:2},{value:"inquirer",id:"inquirer",level:2}],u={toc:c},d="wrapper";function g(e){var t=e.components,s=(0,o.Z)(e,i);return(0,a.kt)(d,(0,r.Z)({},u,s,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/cli-ux/README.md"},"ux")," export provides a simple ",(0,a.kt)("inlineCode",{parentName:"p"},"cli.prompt()")," function, for more complex input prompts, we recommend using the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/SBoudrias/Inquirer.js"},"inquirer")," library."),(0,a.kt)("h2",{id:"uxprompt"},(0,a.kt)("inlineCode",{parentName:"h2"},"ux.prompt()")),(0,a.kt)("p",null,"Prompt for basic input with ",(0,a.kt)("inlineCode",{parentName:"p"},"ux"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport class MyCommand extends Command {\n async run() {\n // just prompt for input\n const name = await ux.prompt('What is your name?')\n\n // mask input after enter is pressed\n const secondFactor = await ux.prompt('What is your two-factor token?', {type: 'mask'})\n\n // hide input while typing\n const password = await ux.prompt('What is your password?', {type: 'hide'})\n\n this.log(`You entered: ${name}, ${secondFactor}, ${password}`)\n }\n}\n")),(0,a.kt)("p",null,"Demo:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"prompt demo",src:n(740).Z,width:"941",height:"605"})),(0,a.kt)("h2",{id:"inquirer"},(0,a.kt)("inlineCode",{parentName:"h2"},"inquirer")),(0,a.kt)("p",null,"Here is an example command that uses ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/SBoudrias/Inquirer.js"},"inquirer"),". You will need to add ",(0,a.kt)("inlineCode",{parentName:"p"},"inquirer")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"@types/inquirer")," (for TypeScript CLIs) for this to work."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\nimport * as inquirer from 'inquirer'\n\nexport class MyCommand extends Command {\n static flags = {\n stage: Flags.string({options: ['development', 'staging', 'production']})\n }\n\n async run() {\n const {flags} = await this.parse(MyCommand)\n let stage = flags.stage\n if (!stage) {\n let responses: any = await inquirer.prompt([{\n name: 'stage',\n message: 'select a stage',\n type: 'list',\n choices: [{name: 'development'}, {name: 'staging'}, {name: 'production'}],\n }])\n stage = responses.stage\n }\n this.log(`the stage is: ${stage}`)\n }\n}\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"NOTE"),": inquirer >= v9 is an ESM package. If you aren't using ESM in your CLI/plugin, you should set ",(0,a.kt)("a",{parentName:"p",href:"https://www.typescriptlang.org/tsconfig#moduleResolution"},(0,a.kt)("inlineCode",{parentName:"a"},"moduleResolution")," to ",(0,a.kt)("inlineCode",{parentName:"a"},"node16"))," in your tsconfig.json and ",(0,a.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import"},"import it using ",(0,a.kt)("inlineCode",{parentName:"a"},"await import")),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, Flags} from '@oclif/core'\n\nexport class MyCommand extends Command {\n static flags = {\n stage: Flags.string({options: ['development', 'staging', 'production']})\n }\n\n async run() {\n const {flags} = await this.parse(MyCommand)\n let stage = flags.stage\n if (!stage) {\n const { default: inquirer } = await import(\"inquirer\")\n let responses: any = inquirer.prompt([{\n name: 'stage',\n message: 'select a stage',\n type: 'list',\n choices: [{name: 'development'}, {name: 'staging'}, {name: 'production'}],\n }])\n stage = responses.stage\n }\n this.log(`the stage is: ${stage}`)\n }\n}\n")),(0,a.kt)("p",null,"Demo:"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"inquirer demo",src:n(2813).Z,width:"1254",height:"806"})))}g.isMDXComponent=!0},2813:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/inquirer_demo-4d4cd8f9cf0bf300a5b853a4beef5672.gif"},740:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/prompt_demo-7bc9d5f614fdad73636bec3c864aff15.gif"}}]); \ No newline at end of file diff --git a/assets/js/82247a8b.0c6962c1.js b/assets/js/82247a8b.eaab3884.js similarity index 99% rename from assets/js/82247a8b.0c6962c1.js rename to assets/js/82247a8b.eaab3884.js index 7233f7eb..18baf35b 100644 --- a/assets/js/82247a8b.0c6962c1.js +++ b/assets/js/82247a8b.eaab3884.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2026],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),c=p(n),d=r,f=c["".concat(s,".").concat(d)]||c[d]||u[d]||i;return n?a.createElement(f,o(o({ref:t},m),{},{components:n})):a.createElement(f,o({ref:t},m))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var a=n(7462),r=n(3366),i=(n(7294),n(3905)),o=["components"],l={title:"Configuration"},s=void 0,p={unversionedId:"config",id:"config",title:"Configuration",description:"Inside a command, this.config provides useful properties you can use in your command. Here are a list of its methods and properties:",source:"@site/../docs/config.md",sourceDirName:".",slug:"/config",permalink:"/docs/config",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/config.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Configuration"},sidebar:"docs",previous:{title:"Command Flags",permalink:"/docs/flags"},next:{title:"Topics",permalink:"/docs/topics"}},m={},c=[{value:"Custom User Configuration",id:"custom-user-configuration",level:2}],u={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,r.Z)(e,o);return(0,i.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Inside a command, ",(0,i.kt)("inlineCode",{parentName:"p"},"this.config")," provides useful properties you can use in your command. Here are a list of its methods and properties:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"name")," - name of CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"version")," - Version of the CLI."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"pjson")," - Parsed and ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/npm/normalize-package-data"},"normalized")," CLI ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"bin")," - CLI bin name"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"binAliases")," - An array of strings that will all execute the CLI's bin. This is useful for backwards compatibility and for CLIs built with installers or tarballs. For npm-installed CLIs, change the ",(0,i.kt)("inlineCode",{parentName:"li"},"bin")," property in ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json")," instead. See ",(0,i.kt)("a",{parentName:"li",href:"https://oclif.io/docs/aliases"},"Bin Aliases")," for more information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"nsisCustomization")," - A path to a .nsis file that's used to customize the installer for Windows. See ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/oclif/nsis-custom"},"nsis-custom")," for more information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"cacheDir")," - CLI cache directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"macOS: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/Library/Caches/mycli")),(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.cache/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_CACHE_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"configDir")," - CLI config directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.config/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_CONFIG_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"dataDir")," - CLI data directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.data/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_DATA_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"dirname")," - dirname used with ",(0,i.kt)("inlineCode",{parentName:"li"},"cacheDir|configDir|dataDir"),". Can be overridden in ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"errlog")," - path to error log inside of ",(0,i.kt)("inlineCode",{parentName:"li"},"cacheDir")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"home")," - user home directory"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"platform")," - operating system ",(0,i.kt)("inlineCode",{parentName:"li"},"darwin|linux|win32")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"arch")," - process architecture ",(0,i.kt)("inlineCode",{parentName:"li"},"x64|x86")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"shell")," - current shell in use"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"userAgent")," - user-agent intended for http calls. example: ",(0,i.kt)("inlineCode",{parentName:"li"},"mycli/1.2.3 (darwin-x64) node-9.0.0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"windows")," - boolean"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"topicSeparator")," - the separator to use between topics - only colons (",(0,i.kt)("inlineCode",{parentName:"li"},'":"'),") and spaces (",(0,i.kt)("inlineCode",{parentName:"li"},'" "'),") are supported."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"debug")," - set to 1 if debug is enabled (with ",(0,i.kt)("inlineCode",{parentName:"li"},"${BIN}_DEBUG=1")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"DEBUG=$BIN"),"). In the future this may be used for multiple debug levels."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"npmRegistry")," - current npm registry to use with the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-plugins"},"plugins")," plugin"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"plugins")," - loaded plugins"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"commands")," - all commands in CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"default")," - default cli command"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"topics")," - all topics in CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"commandIDs")," - string IDs of all commands"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"async runHook(event, opts)")," - trigger a hook")),(0,i.kt)("h2",{id:"custom-user-configuration"},"Custom User Configuration"),(0,i.kt)("p",null,"Often it's useful to have a custom configuration for your users. One way to implement this is to read a ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," file from the CLI's config directory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nimport * as fs from 'fs-extra'\nimport * as path from 'path'\n\nexport class extends Command {\n async run() {\n const userConfig = await fs.readJSON(path.join(this.config.configDir, 'config.json'))\n\n this.log('User config:')\n console.dir(userConfig)\n }\n}\n")),(0,i.kt)("p",null,"To share this logic between different commands, use a ",(0,i.kt)("a",{parentName:"p",href:"/docs/base_class"},"base class"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2026],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),c=p(n),d=r,f=c["".concat(s,".").concat(d)]||c[d]||u[d]||i;return n?a.createElement(f,o(o({ref:t},m),{},{components:n})):a.createElement(f,o({ref:t},m))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var a=n(7462),r=n(3366),i=(n(7294),n(3905)),o=["components"],l={title:"Configuration"},s=void 0,p={unversionedId:"config",id:"config",title:"Configuration",description:"Inside a command, this.config provides useful properties you can use in your command. Here are a list of its methods and properties:",source:"@site/../docs/config.md",sourceDirName:".",slug:"/config",permalink:"/docs/config",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/config.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Configuration"},sidebar:"docs",previous:{title:"Command Flags",permalink:"/docs/flags"},next:{title:"Topics",permalink:"/docs/topics"}},m={},c=[{value:"Custom User Configuration",id:"custom-user-configuration",level:2}],u={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,r.Z)(e,o);return(0,i.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Inside a command, ",(0,i.kt)("inlineCode",{parentName:"p"},"this.config")," provides useful properties you can use in your command. Here are a list of its methods and properties:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"name")," - name of CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"version")," - Version of the CLI."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"pjson")," - Parsed and ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/npm/normalize-package-data"},"normalized")," CLI ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"bin")," - CLI bin name"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"binAliases")," - An array of strings that will all execute the CLI's bin. This is useful for backwards compatibility and for CLIs built with installers or tarballs. For npm-installed CLIs, change the ",(0,i.kt)("inlineCode",{parentName:"li"},"bin")," property in ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json")," instead. See ",(0,i.kt)("a",{parentName:"li",href:"https://oclif.io/docs/aliases"},"Bin Aliases")," for more information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"nsisCustomization")," - A path to a .nsis file that's used to customize the installer for Windows. See ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/oclif/nsis-custom"},"nsis-custom")," for more information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"cacheDir")," - CLI cache directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"macOS: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/Library/Caches/mycli")),(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.cache/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_CACHE_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"configDir")," - CLI config directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.config/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_CONFIG_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"dataDir")," - CLI data directory",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Unix: ",(0,i.kt)("inlineCode",{parentName:"li"},"~/.data/mycli")),(0,i.kt)("li",{parentName:"ul"},"Windows: ",(0,i.kt)("inlineCode",{parentName:"li"},"%LOCALAPPDATA%\\mycli")),(0,i.kt)("li",{parentName:"ul"},"Can be overridden with ",(0,i.kt)("inlineCode",{parentName:"li"},"XDG_DATA_HOME")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"dirname")," - dirname used with ",(0,i.kt)("inlineCode",{parentName:"li"},"cacheDir|configDir|dataDir"),". Can be overridden in ",(0,i.kt)("inlineCode",{parentName:"li"},"package.json"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"errlog")," - path to error log inside of ",(0,i.kt)("inlineCode",{parentName:"li"},"cacheDir")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"home")," - user home directory"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"platform")," - operating system ",(0,i.kt)("inlineCode",{parentName:"li"},"darwin|linux|win32")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"arch")," - process architecture ",(0,i.kt)("inlineCode",{parentName:"li"},"x64|x86")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"shell")," - current shell in use"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"userAgent")," - user-agent intended for http calls. example: ",(0,i.kt)("inlineCode",{parentName:"li"},"mycli/1.2.3 (darwin-x64) node-9.0.0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"windows")," - boolean"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"topicSeparator")," - the separator to use between topics - only colons (",(0,i.kt)("inlineCode",{parentName:"li"},'":"'),") and spaces (",(0,i.kt)("inlineCode",{parentName:"li"},'" "'),") are supported."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"debug")," - set to 1 if debug is enabled (with ",(0,i.kt)("inlineCode",{parentName:"li"},"${BIN}_DEBUG=1")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"DEBUG=$BIN"),"). In the future this may be used for multiple debug levels."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"npmRegistry")," - current npm registry to use with the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-plugins"},"plugins")," plugin"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"plugins")," - loaded plugins"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"commands")," - all commands in CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"default")," - default cli command"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"topics")," - all topics in CLI"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"commandIDs")," - string IDs of all commands"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"async runHook(event, opts)")," - trigger a hook")),(0,i.kt)("h2",{id:"custom-user-configuration"},"Custom User Configuration"),(0,i.kt)("p",null,"Often it's useful to have a custom configuration for your users. One way to implement this is to read a ",(0,i.kt)("inlineCode",{parentName:"p"},"config.json")," file from the CLI's config directory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nimport * as fs from 'fs-extra'\nimport * as path from 'path'\n\nexport class extends Command {\n async run() {\n const userConfig = await fs.readJSON(path.join(this.config.configDir, 'config.json'))\n\n this.log('User config:')\n console.dir(userConfig)\n }\n}\n")),(0,i.kt)("p",null,"To share this logic between different commands, use a ",(0,i.kt)("a",{parentName:"p",href:"/docs/base_class"},"base class"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8705a681.31d90ccb.js b/assets/js/8705a681.56669df9.js similarity index 99% rename from assets/js/8705a681.31d90ccb.js rename to assets/js/8705a681.56669df9.js index 1e558ff3..89e5d135 100644 --- a/assets/js/8705a681.31d90ccb.js +++ b/assets/js/8705a681.56669df9.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2863],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>g});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=c(n),u=r,g=m["".concat(l,".").concat(u)]||m[u]||d[u]||o;return n?a.createElement(g,i(i({ref:t},p),{},{components:n})):a.createElement(g,i({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>g,frontMatter:()=>s,metadata:()=>c,toc:()=>m});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=["components"],s={title:"Running Commands Programmatically"},l=void 0,c={unversionedId:"running_programmatically",id:"running_programmatically",title:"Running Commands Programmatically",description:"If you need to run a command from another, or programmatically run a command in another codebase, there are a couple options.",source:"@site/../docs/running_programmatically.md",sourceDirName:".",slug:"/running_programmatically",permalink:"/docs/running_programmatically",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/running_programmatically.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Running Commands Programmatically"},sidebar:"docs",previous:{title:"Testing",permalink:"/docs/testing"},next:{title:"Just-in-Time Plugin Installation",permalink:"/docs/jit_plugins"}},p={},m=[{value:"Sharing code with modules",id:"sharing-code-with-modules",level:2},{value:"Calling commands directly",id:"calling-commands-directly",level:2}],d={toc:m},u="wrapper";function g(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"If you need to run a command from another, or programmatically run a command in another codebase, there are a couple options."),(0,o.kt)("p",null,"First, it is generally a bad idea to run a command directly as the command exports a user interface, not a code interface. It's a design smell that should rarely (if ever) be used. Generally speaking, it's better to break up the code so that it can be called directly rather than as a command. We'll show this better method first."),(0,o.kt)("h2",{id:"sharing-code-with-modules"},"Sharing code with modules"),(0,o.kt)("p",null,"For example, if we use ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config list")," as an example, we could have a command that outputs the config vars of an app to the screen like this:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/list.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export class ConfigList extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigList)\n const config = await api.get(`/apps/${flags.app}/config-vars`)\n for (let [key, value] of Object.entries(config)) {\n this.log(`${key}=${value}`)\n }\n }\n}\n")),(0,o.kt)("p",null,"If we had another command such as ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config update")," that would do some logic then display the config variables using the same logic, we should create a new module that we could call directly:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {displayConfigVars} from '../displayConfigVars'\n\nexport class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await displayConfigVars(flags.app)\n }\n}\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/displayConfigVars.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export async function displayConfigVars(app: string) {\n const config = await api.get(`/apps/${app}config-vars`)\n for (let [key, value] of Object.entries(config)) {\n this.log(`${key}=${value}`)\n }\n}\n")),(0,o.kt)("p",null,"This is the recommended way to share code. This can be extended further by putting shared code into its own npm package."),(0,o.kt)("h2",{id:"calling-commands-directly"},"Calling commands directly"),(0,o.kt)("p",null,"Still, if you ",(0,o.kt)("em",{parentName:"p"},"really")," want to call a command directly, it's easy to do. You have a couple of options."),(0,o.kt)("p",null,"If you know that the command you want to run is installed in the CLI, you can use ",(0,o.kt)("inlineCode",{parentName:"p"},"this.config.runCommand"),". For this, we could write our ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config update")," command like so:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await this.config.runCommand('config:list', ['--global'])\n }\n}\n")),(0,o.kt)("p",null,"Or you could import the command directly and execute it directly like so:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {ConfigList} from './config/list'\n\nexport class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await ConfigList.run(['--global'])\n }\n}\n")),(0,o.kt)("p",null,"This works because commands have a static ",(0,o.kt)("inlineCode",{parentName:"p"},".run()")," ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/command.ts"},"method on them")," that can be used to instantiate the command and run the instance ",(0,o.kt)("inlineCode",{parentName:"p"},".run()")," method. It takes in the argv as input to the command."))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2863],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>g});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=c(n),u=r,g=m["".concat(l,".").concat(u)]||m[u]||d[u]||o;return n?a.createElement(g,i(i({ref:t},p),{},{components:n})):a.createElement(g,i({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>g,frontMatter:()=>s,metadata:()=>c,toc:()=>m});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=["components"],s={title:"Running Commands Programmatically"},l=void 0,c={unversionedId:"running_programmatically",id:"running_programmatically",title:"Running Commands Programmatically",description:"If you need to run a command from another, or programmatically run a command in another codebase, there are a couple options.",source:"@site/../docs/running_programmatically.md",sourceDirName:".",slug:"/running_programmatically",permalink:"/docs/running_programmatically",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/running_programmatically.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Running Commands Programmatically"},sidebar:"docs",previous:{title:"Testing",permalink:"/docs/testing"},next:{title:"Just-in-Time Plugin Installation",permalink:"/docs/jit_plugins"}},p={},m=[{value:"Sharing code with modules",id:"sharing-code-with-modules",level:2},{value:"Calling commands directly",id:"calling-commands-directly",level:2}],d={toc:m},u="wrapper";function g(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(u,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"If you need to run a command from another, or programmatically run a command in another codebase, there are a couple options."),(0,o.kt)("p",null,"First, it is generally a bad idea to run a command directly as the command exports a user interface, not a code interface. It's a design smell that should rarely (if ever) be used. Generally speaking, it's better to break up the code so that it can be called directly rather than as a command. We'll show this better method first."),(0,o.kt)("h2",{id:"sharing-code-with-modules"},"Sharing code with modules"),(0,o.kt)("p",null,"For example, if we use ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config list")," as an example, we could have a command that outputs the config vars of an app to the screen like this:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/list.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export class ConfigList extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigList)\n const config = await api.get(`/apps/${flags.app}/config-vars`)\n for (let [key, value] of Object.entries(config)) {\n this.log(`${key}=${value}`)\n }\n }\n}\n")),(0,o.kt)("p",null,"If we had another command such as ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config update")," that would do some logic then display the config variables using the same logic, we should create a new module that we could call directly:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {displayConfigVars} from '../displayConfigVars'\n\nexport class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await displayConfigVars(flags.app)\n }\n}\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/displayConfigVars.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export async function displayConfigVars(app: string) {\n const config = await api.get(`/apps/${app}config-vars`)\n for (let [key, value] of Object.entries(config)) {\n this.log(`${key}=${value}`)\n }\n}\n")),(0,o.kt)("p",null,"This is the recommended way to share code. This can be extended further by putting shared code into its own npm package."),(0,o.kt)("h2",{id:"calling-commands-directly"},"Calling commands directly"),(0,o.kt)("p",null,"Still, if you ",(0,o.kt)("em",{parentName:"p"},"really")," want to call a command directly, it's easy to do. You have a couple of options."),(0,o.kt)("p",null,"If you know that the command you want to run is installed in the CLI, you can use ",(0,o.kt)("inlineCode",{parentName:"p"},"this.config.runCommand"),". For this, we could write our ",(0,o.kt)("inlineCode",{parentName:"p"},"sf config update")," command like so:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"export class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await this.config.runCommand('config:list', ['--global'])\n }\n}\n")),(0,o.kt)("p",null,"Or you could import the command directly and execute it directly like so:"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"./src/commands/config/update.ts")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {ConfigList} from './config/list'\n\nexport class ConfigUpdate extends Command {\n static flags = {\n app: Flags.string({required: true})\n }\n\n async run() {\n const {flags} = await this.parse(ConfigUpdate)\n await this.doUpdate(flags.app)\n await ConfigList.run(['--global'])\n }\n}\n")),(0,o.kt)("p",null,"This works because commands have a static ",(0,o.kt)("inlineCode",{parentName:"p"},".run()")," ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/command.ts"},"method on them")," that can be used to instantiate the command and run the instance ",(0,o.kt)("inlineCode",{parentName:"p"},".run()")," method. It takes in the argv as input to the command."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935116ff.1384990f.js b/assets/js/935116ff.5b67c00b.js similarity index 99% rename from assets/js/935116ff.1384990f.js rename to assets/js/935116ff.5b67c00b.js index 3a92181a..85441dd2 100644 --- a/assets/js/935116ff.1384990f.js +++ b/assets/js/935116ff.5b67c00b.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2638],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>f});var n=o(7294);function r(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function a(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=p(o),h=r,f=c["".concat(s,".").concat(h)]||c[h]||d[h]||a;return o?n.createElement(f,i(i({ref:t},u),{},{components:o})):n.createElement(f,i({ref:t},u))}));function f(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=o.length,i=new Array(a);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{o.r(t),o.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var n=o(7462),r=o(3366),a=(o(7294),o(3905)),i=["components"],l={title:"FAQs"},s=void 0,p={unversionedId:"faqs",id:"faqs",title:"FAQs",description:"Why Node?",source:"@site/../docs/faqs.md",sourceDirName:".",slug:"/faqs",permalink:"/docs/faqs",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/faqs.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"FAQs"},sidebar:"docs",previous:{title:"Features",permalink:"/docs/features"},next:{title:"Generator Commands",permalink:"/docs/generator_commands"}},u={},c=[{value:"Why Node?",id:"why-node",level:2},{value:"I want a single binary CLI like with Go",id:"i-want-a-single-binary-cli-like-with-go",level:2},{value:"Should I use TypeScript or JavaScript?",id:"should-i-use-typescript-or-javascript",level:2},{value:"What editor is best for oclif?",id:"what-editor-is-best-for-oclif",level:2},{value:"Should I use npm or yarn?",id:"should-i-use-npm-or-yarn",level:2},{value:"How can I make the oclif generator run faster?",id:"how-can-i-make-the-oclif-generator-run-faster",level:2},{value:"Why isn't Node X supported?",id:"why-isnt-node-x-supported",level:2},{value:"How do I pronounce "oclif"?",id:"how-do-i-pronounce-oclif",level:2}],d={toc:c},h="wrapper";function f(e){var t=e.components,o=(0,r.Z)(e,i);return(0,a.kt)(h,(0,n.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"why-node"},"Why Node?"),(0,a.kt)("p",null,"There are a number of reasons why Node is the best choice for writing CLI code. At Salesforce, we've released the heroku CLI in Ruby, Go, as well as Node. ",(0,a.kt)("a",{parentName:"p",href:"https://blog.heroku.com/evolution-of-heroku-cli-2008-2017"},"This article gets more into detail on that history"),", but we've certainly found that Node offers the best of everything."),(0,a.kt)("p",null,"First, JavaScript is the biggest language in the world. More people are able to write JavaScript than any other language and it by far has the biggest open source community. Everyone can write it and you'll find the most helpful libraries to help build your CLI."),(0,a.kt)("p",null,"We've found that Node has the best cross platform support of any language we've used. In general, if you write code on macOS, you won't find many issues making it also run on Windows."),(0,a.kt)("p",null,"Node has the best support for our ",(0,a.kt)("a",{parentName:"p",href:"/docs/plugins"},"plugins")," model. Plugins are a way to share code between CLIs, to modularize a CLIs codebase, or allow users to add functionality to an existing CLI. With Node, we're able to have separate dependency versions sitting alongside one another. This means if you want to release an update to a dependency in one plugin, it won't affect how another plugin works. oclif takes this to an extreme and even flag parsing is done at the individual plugin level. If we ever want to make a breaking change to flag parsing (we certainly don't intend to, but this is just an example), you can update just one plugin and keep the old behavior in other plugins. This is very helpful for large CLI codebases where you want to migrate to new code slowly."),(0,a.kt)("h2",{id:"i-want-a-single-binary-cli-like-with-go"},"I want a single binary CLI like with Go"),(0,a.kt)("p",null,"Use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/zeit/pkg"},"pkg"),". Just make sure to add the commands and other source files by setting ",(0,a.kt)("inlineCode",{parentName:"p"},'pkg.scripts: "./lib/**/*.js"')," in ",(0,a.kt)("inlineCode",{parentName:"p"},"package.json"),"."),(0,a.kt)("p",null,"In the Salesforce CLI, however, we prefer to ship a tarball (and various installers) that has Node baked in. Use ",(0,a.kt)("inlineCode",{parentName:"p"},"oclif pack")," to create a set of tarballs for different platforms with Node built in. You'll likely need to use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-update"},"@oclif/plugin-update")," with this, otherwise the users won't have a way to update the CLI from the tarball without reinstalling it."),(0,a.kt)("h2",{id:"should-i-use-typescript-or-javascript"},"Should I use TypeScript or JavaScript?"),(0,a.kt)("p",null,"We suggest TypeScript as we find the typing to really help when refactoring code and updating dependencies. It's nicer to get compilation errors rather than finding errors in production."),(0,a.kt)("p",null,"We've put a lot of care into making it easy to make a TypeScript CLI even if you've never written TypeScript before. We generate CLIs and plugins that use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/TypeStrong/ts-node"},"ts-node")," to make it fast to run the TypeScript code without a compilation step. You won't have to mess around with build configuration using oclif."),(0,a.kt)("p",null,"Still, the languages today are very similar. The code you write in JavaScript will be nearly identical to what you would have in TypeScript. (Just no type definitions, of course)"),(0,a.kt)("h2",{id:"what-editor-is-best-for-oclif"},"What editor is best for oclif?"),(0,a.kt)("p",null,"Of course if you already have a go-to editor, you should use that. However, we typically recommend ",(0,a.kt)("a",{parentName:"p",href:"https://code.visualstudio.com"},"vscode"),"."),(0,a.kt)("p",null,"Microsoft has done a great job with this editor and it works particularly well in TypeScript projects. You'll get nice type checking, linting, and autocomplete right out of the box."),(0,a.kt)("h2",{id:"should-i-use-npm-or-yarn"},"Should I use npm or yarn?"),(0,a.kt)("p",null,"It really doesn't make that much of a difference. If you're just getting started, keep it simple and use npm which comes with Node. We like to use yarn internally as it's a bit faster and we find the lockfiles friendlier."),(0,a.kt)("h2",{id:"how-can-i-make-the-oclif-generator-run-faster"},"How can I make the oclif generator run faster?"),(0,a.kt)("p",null,"If you're using npx, install it first with ",(0,a.kt)("inlineCode",{parentName:"p"},"npm install -g oclif"),". This won't stay current with updates though, so you'll need to run ",(0,a.kt)("inlineCode",{parentName:"p"},"npm update -g oclif")," to get new versions of the generator."),(0,a.kt)("h2",{id:"why-isnt-node-x-supported"},"Why isn't Node X supported?"),(0,a.kt)("p",null,"The oclif project follows and supports ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/en/about/releases/"},"Node's LTS support schedule"),". This allows oclif to stay current with Node's development."),(0,a.kt)("h2",{id:"how-do-i-pronounce-oclif"},'How do I pronounce "oclif"?'),(0,a.kt)("p",null,'We say "oh-cliff".'))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2638],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>f});var n=o(7294);function r(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function a(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function i(e){for(var t=1;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var o=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=p(o),h=r,f=c["".concat(s,".").concat(h)]||c[h]||d[h]||a;return o?n.createElement(f,i(i({ref:t},u),{},{components:o})):n.createElement(f,i({ref:t},u))}));function f(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=o.length,i=new Array(a);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{o.r(t),o.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var n=o(7462),r=o(3366),a=(o(7294),o(3905)),i=["components"],l={title:"FAQs"},s=void 0,p={unversionedId:"faqs",id:"faqs",title:"FAQs",description:"Why Node?",source:"@site/../docs/faqs.md",sourceDirName:".",slug:"/faqs",permalink:"/docs/faqs",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/faqs.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"FAQs"},sidebar:"docs",previous:{title:"Features",permalink:"/docs/features"},next:{title:"Generator Commands",permalink:"/docs/generator_commands"}},u={},c=[{value:"Why Node?",id:"why-node",level:2},{value:"I want a single binary CLI like with Go",id:"i-want-a-single-binary-cli-like-with-go",level:2},{value:"Should I use TypeScript or JavaScript?",id:"should-i-use-typescript-or-javascript",level:2},{value:"What editor is best for oclif?",id:"what-editor-is-best-for-oclif",level:2},{value:"Should I use npm or yarn?",id:"should-i-use-npm-or-yarn",level:2},{value:"How can I make the oclif generator run faster?",id:"how-can-i-make-the-oclif-generator-run-faster",level:2},{value:"Why isn't Node X supported?",id:"why-isnt-node-x-supported",level:2},{value:"How do I pronounce "oclif"?",id:"how-do-i-pronounce-oclif",level:2}],d={toc:c},h="wrapper";function f(e){var t=e.components,o=(0,r.Z)(e,i);return(0,a.kt)(h,(0,n.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"why-node"},"Why Node?"),(0,a.kt)("p",null,"There are a number of reasons why Node is the best choice for writing CLI code. At Salesforce, we've released the heroku CLI in Ruby, Go, as well as Node. ",(0,a.kt)("a",{parentName:"p",href:"https://blog.heroku.com/evolution-of-heroku-cli-2008-2017"},"This article gets more into detail on that history"),", but we've certainly found that Node offers the best of everything."),(0,a.kt)("p",null,"First, JavaScript is the biggest language in the world. More people are able to write JavaScript than any other language and it by far has the biggest open source community. Everyone can write it and you'll find the most helpful libraries to help build your CLI."),(0,a.kt)("p",null,"We've found that Node has the best cross platform support of any language we've used. In general, if you write code on macOS, you won't find many issues making it also run on Windows."),(0,a.kt)("p",null,"Node has the best support for our ",(0,a.kt)("a",{parentName:"p",href:"/docs/plugins"},"plugins")," model. Plugins are a way to share code between CLIs, to modularize a CLIs codebase, or allow users to add functionality to an existing CLI. With Node, we're able to have separate dependency versions sitting alongside one another. This means if you want to release an update to a dependency in one plugin, it won't affect how another plugin works. oclif takes this to an extreme and even flag parsing is done at the individual plugin level. If we ever want to make a breaking change to flag parsing (we certainly don't intend to, but this is just an example), you can update just one plugin and keep the old behavior in other plugins. This is very helpful for large CLI codebases where you want to migrate to new code slowly."),(0,a.kt)("h2",{id:"i-want-a-single-binary-cli-like-with-go"},"I want a single binary CLI like with Go"),(0,a.kt)("p",null,"Use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/zeit/pkg"},"pkg"),". Just make sure to add the commands and other source files by setting ",(0,a.kt)("inlineCode",{parentName:"p"},'pkg.scripts: "./lib/**/*.js"')," in ",(0,a.kt)("inlineCode",{parentName:"p"},"package.json"),"."),(0,a.kt)("p",null,"In the Salesforce CLI, however, we prefer to ship a tarball (and various installers) that has Node baked in. Use ",(0,a.kt)("inlineCode",{parentName:"p"},"oclif pack")," to create a set of tarballs for different platforms with Node built in. You'll likely need to use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-update"},"@oclif/plugin-update")," with this, otherwise the users won't have a way to update the CLI from the tarball without reinstalling it."),(0,a.kt)("h2",{id:"should-i-use-typescript-or-javascript"},"Should I use TypeScript or JavaScript?"),(0,a.kt)("p",null,"We suggest TypeScript as we find the typing to really help when refactoring code and updating dependencies. It's nicer to get compilation errors rather than finding errors in production."),(0,a.kt)("p",null,"We've put a lot of care into making it easy to make a TypeScript CLI even if you've never written TypeScript before. We generate CLIs and plugins that use ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/TypeStrong/ts-node"},"ts-node")," to make it fast to run the TypeScript code without a compilation step. You won't have to mess around with build configuration using oclif."),(0,a.kt)("p",null,"Still, the languages today are very similar. The code you write in JavaScript will be nearly identical to what you would have in TypeScript. (Just no type definitions, of course)"),(0,a.kt)("h2",{id:"what-editor-is-best-for-oclif"},"What editor is best for oclif?"),(0,a.kt)("p",null,"Of course if you already have a go-to editor, you should use that. However, we typically recommend ",(0,a.kt)("a",{parentName:"p",href:"https://code.visualstudio.com"},"vscode"),"."),(0,a.kt)("p",null,"Microsoft has done a great job with this editor and it works particularly well in TypeScript projects. You'll get nice type checking, linting, and autocomplete right out of the box."),(0,a.kt)("h2",{id:"should-i-use-npm-or-yarn"},"Should I use npm or yarn?"),(0,a.kt)("p",null,"It really doesn't make that much of a difference. If you're just getting started, keep it simple and use npm which comes with Node. We like to use yarn internally as it's a bit faster and we find the lockfiles friendlier."),(0,a.kt)("h2",{id:"how-can-i-make-the-oclif-generator-run-faster"},"How can I make the oclif generator run faster?"),(0,a.kt)("p",null,"If you're using npx, install it first with ",(0,a.kt)("inlineCode",{parentName:"p"},"npm install -g oclif"),". This won't stay current with updates though, so you'll need to run ",(0,a.kt)("inlineCode",{parentName:"p"},"npm update -g oclif")," to get new versions of the generator."),(0,a.kt)("h2",{id:"why-isnt-node-x-supported"},"Why isn't Node X supported?"),(0,a.kt)("p",null,"The oclif project follows and supports ",(0,a.kt)("a",{parentName:"p",href:"https://nodejs.org/en/about/releases/"},"Node's LTS support schedule"),". This allows oclif to stay current with Node's development."),(0,a.kt)("h2",{id:"how-do-i-pronounce-oclif"},'How do I pronounce "oclif"?'),(0,a.kt)("p",null,'We say "oh-cliff".'))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/958c0a42.85c99996.js b/assets/js/958c0a42.c6f748e3.js similarity index 95% rename from assets/js/958c0a42.85c99996.js rename to assets/js/958c0a42.c6f748e3.js index 4f24313c..10b99e35 100644 --- a/assets/js/958c0a42.85c99996.js +++ b/assets/js/958c0a42.c6f748e3.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3261],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,d=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(d,i(i({ref:t},c),{},{components:n})):r.createElement(d,i({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),a=n(3366),o=(n(7294),n(3905)),i=["components"],l={title:"Customizing Help in oclif"},p=void 0,s={permalink:"/blog/2020/05/05/introducing-custom-help-classes",source:"@site/blog/2020-05-05-introducing-custom-help-classes.md",title:"Customizing Help in oclif",description:"Out of the box oclif provides a great help experience for CLIs.",date:"2020-05-05T00:00:00.000Z",formattedDate:"May 5, 2020",tags:[],readingTime:1.67,hasTruncateMarker:!1,authors:[],frontMatter:{title:"Customizing Help in oclif"},prevItem:{title:"Pretty Printable Errors",permalink:"/blog/2020/07/01/pretty-printable-errors"},nextItem:{title:"oclif TSLint to ESLint Migration",permalink:"/blog/2019/12/05/oclif-eslint-migration"}},c={authorsImageUrls:[]},u=[{value:"Getting started with custom help",id:"getting-started-with-custom-help",level:2},{value:"Separating TOPICS & COMMANDS in the new deafult Help class",id:"separating-topics--commands-in-the-new-deafult-help-class",level:2}],h={toc:u},m="wrapper";function d(e){var t=e.components,n=(0,a.Z)(e,i);return(0,o.kt)(m,(0,r.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs."),(0,o.kt)("p",null,"But what if, as an oclif developer, you want to customize some or all of the output?"),(0,o.kt)("p",null,"You can now customize your CLI's help output by implementing the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class."),(0,o.kt)("h2",{id:"getting-started-with-custom-help"},"Getting started with custom help"),(0,o.kt)("p",null,"If you have not done so yet, update ",(0,o.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ yarn add --latest @oclif/core\n")),(0,o.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,o.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./lib/help"\n // ...\n }\n // ...\n}\n')),(0,o.kt)("p",null,"From here there are two paths, implement the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new ",(0,o.kt)("a",{parentName:"p",href:"../../../../docs/help_classes"},"Help Classes docs"),"."),(0,o.kt)("h2",{id:"separating-topics--commands-in-the-new-deafult-help-class"},"Separating TOPICS & COMMANDS in the new deafult ",(0,o.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,o.kt)("p",null,'Previously, topics and child commands were listed in help output under a single list heading called "COMMANDS". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).'),(0,o.kt)("p",null,"The new default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help"),' class splits the list of children into distinct lists of "TOPICS" and "COMMANDS", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - "COMMANDS" - and what is providing structure - "TOPICS" - when looking at the help output.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"VERSION\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\n\nUSAGE\n $ plugin-help-example [COMMAND]\n\nTOPICS\n topic this is a topic and has child topics or commands\n\nCOMMANDS\n hello describe the command here\n help display help for plugin-help-example\n")),(0,o.kt)("p",null,"We look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[3261],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,d=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(d,i(i({ref:t},c),{},{components:n})):r.createElement(d,i({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var r=n(7462),a=n(3366),o=(n(7294),n(3905)),i=["components"],l={title:"Customizing Help in oclif"},p=void 0,s={permalink:"/blog/2020/05/05/introducing-custom-help-classes",source:"@site/blog/2020-05-05-introducing-custom-help-classes.md",title:"Customizing Help in oclif",description:"Out of the box oclif provides a great help experience for CLIs.",date:"2020-05-05T00:00:00.000Z",formattedDate:"May 5, 2020",tags:[],readingTime:1.67,hasTruncateMarker:!1,authors:[],frontMatter:{title:"Customizing Help in oclif"},prevItem:{title:"Pretty Printable Errors",permalink:"/blog/2020/07/01/pretty-printable-errors"},nextItem:{title:"oclif TSLint to ESLint Migration",permalink:"/blog/2019/12/05/oclif-eslint-migration"}},c={authorsImageUrls:[]},u=[{value:"Getting started with custom help",id:"getting-started-with-custom-help",level:2},{value:"Separating TOPICS & COMMANDS in the new default Help class",id:"separating-topics--commands-in-the-new-default-help-class",level:2}],h={toc:u},m="wrapper";function d(e){var t=e.components,n=(0,a.Z)(e,i);return(0,o.kt)(m,(0,r.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs."),(0,o.kt)("p",null,"But what if, as an oclif developer, you want to customize some or all of the output?"),(0,o.kt)("p",null,"You can now customize your CLI's help output by implementing the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class."),(0,o.kt)("h2",{id:"getting-started-with-custom-help"},"Getting started with custom help"),(0,o.kt)("p",null,"If you have not done so yet, update ",(0,o.kt)("inlineCode",{parentName:"p"},"@oclif/core"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ yarn add --latest @oclif/core\n")),(0,o.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,o.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./lib/help"\n // ...\n }\n // ...\n}\n')),(0,o.kt)("p",null,"From here there are two paths, implement the ",(0,o.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new ",(0,o.kt)("a",{parentName:"p",href:"../../../../docs/help_classes"},"Help Classes docs"),"."),(0,o.kt)("h2",{id:"separating-topics--commands-in-the-new-default-help-class"},"Separating TOPICS & COMMANDS in the new default ",(0,o.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,o.kt)("p",null,'Previously, topics and child commands were listed in help output under a single list heading called "COMMANDS". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).'),(0,o.kt)("p",null,"The new default ",(0,o.kt)("inlineCode",{parentName:"p"},"Help"),' class splits the list of children into distinct lists of "TOPICS" and "COMMANDS", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - "COMMANDS" - and what is providing structure - "TOPICS" - when looking at the help output.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"VERSION\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\n\nUSAGE\n $ plugin-help-example [COMMAND]\n\nTOPICS\n topic this is a topic and has child topics or commands\n\nCOMMANDS\n hello describe the command here\n help display help for plugin-help-example\n")),(0,o.kt)("p",null,"We look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9eaa546a.37cf75d3.js b/assets/js/9eaa546a.46c67a2d.js similarity index 99% rename from assets/js/9eaa546a.37cf75d3.js rename to assets/js/9eaa546a.46c67a2d.js index 259187ad..f56186a6 100644 --- a/assets/js/9eaa546a.37cf75d3.js +++ b/assets/js/9eaa546a.46c67a2d.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8059],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,f=c["".concat(s,".").concat(m)]||c[m]||d[m]||r;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>u,toc:()=>c});var o=n(7462),a=n(3366),r=(n(7294),n(3905)),i=["components"],l={title:"Features"},s=void 0,u={unversionedId:"features",id:"features",title:"Features",description:"Flag/Argument parsing",source:"@site/../docs/features.md",sourceDirName:".",slug:"/features",permalink:"/docs/features",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/features.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Features"},sidebar:"docs",previous:{title:"Introduction",permalink:"/docs/introduction"},next:{title:"FAQs",permalink:"/docs/faqs"}},p={},c=[{value:"Flag/Argument parsing",id:"flagargument-parsing",level:3},{value:"Configurable Topic Separators",id:"configurable-topic-separators",level:3},{value:"Super Speed",id:"super-speed",level:3},{value:"CLI Generator",id:"cli-generator",level:3},{value:"Testing Helpers",id:"testing-helpers",level:3},{value:"Auto-documentation",id:"auto-documentation",level:3},{value:"Plugins",id:"plugins",level:3},{value:"Hooks",id:"hooks",level:3},{value:"JSON Output",id:"json-output",level:3},{value:"TypeScript (or not)",id:"typescript-or-not",level:3},{value:"Auto-updating Installers",id:"auto-updating-installers",level:3},{value:"Autocomplete",id:"autocomplete",level:3}],d={toc:c},m="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,i);return(0,r.kt)(m,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h3",{id:"flagargument-parsing"},"Flag/Argument parsing"),(0,r.kt)("p",null,"No CLI framework would be complete without a flag parser. We've built a custom one from years of experimentation that we feel consistently handles user input flexible enough for the user to be able to easily use the CLI in ways they expect, but without compromising strictness guarantees to the developer."),(0,r.kt)("h3",{id:"configurable-topic-separators"},"Configurable Topic Separators"),(0,r.kt)("p",null,"By default topics will be separated with colons, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"my:awesome:command"),". However, you have the option to use spaces if you prefer, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"my awesome command"),"."),(0,r.kt)("h3",{id:"super-speed"},"Super Speed"),(0,r.kt)("p",null,"The overhead for running an oclif CLI command is almost nothing. ",(0,r.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/@oclif/core?activeTab=dependencies"},"It requires very few dependencies")," (only 28 dependencies in a minimal setup\u2014including all transitive dependencies). Also, only the command to be executed will be required with node. So large CLIs with many commands will load just as fast as a small one with a single command."),(0,r.kt)("h3",{id:"cli-generator"},"CLI Generator"),(0,r.kt)("p",null,"Run a single command to scaffold out a fully functional CLI and get started quickly. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/generator_commands"},"Generator Commands"),"."),(0,r.kt)("h3",{id:"testing-helpers"},"Testing Helpers"),(0,r.kt)("p",null,"We've put a lot of work into making commands easily testable and easy to mock out stdout/stderr. The generator will automatically create ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world/blob/main/test/commands/hello/world.test.ts"},"scaffolded tests"),"."),(0,r.kt)("h3",{id:"auto-documentation"},"Auto-documentation"),(0,r.kt)("p",null,"By default you can pass ",(0,r.kt)("inlineCode",{parentName:"p"},"--help")," to the CLI to get help such as flag options and argument information. This information is also automatically placed in the README whenever the npm package of the CLI is published. See the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world"},"hello-world CLI example")),(0,r.kt)("h3",{id:"plugins"},"Plugins"),(0,r.kt)("p",null,"Using plugins, users of the CLI can extend it with new functionality, a CLI can be split into modular components, and functionality can be shared amongst multiple CLIs. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/plugins#building-your-own-plugin"},"Building your own plugin"),"."),(0,r.kt)("h3",{id:"hooks"},"Hooks"),(0,r.kt)("p",null,"Use lifecycle hooks to run functionality any time a CLI starts, or on custom triggers. Use this whenever custom functionality needs to be shared between various components of the CLI. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/hooks"},"Hooks"),"."),(0,r.kt)("h3",{id:"json-output"},"JSON Output"),(0,r.kt)("p",null,"You can opt-in to using the ",(0,r.kt)("inlineCode",{parentName:"p"},"--json")," flag which will automatically suppress console logs and display the final result of the command as valid JSON output. This is very useful if you want your CLI to be used for scripting in CI/CD environments. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/json"},"JSON"),"."),(0,r.kt)("h3",{id:"typescript-or-not"},"TypeScript (or not)"),(0,r.kt)("p",null,"Everything in the core of oclif is written in TypeScript and the generator can build fully configured TypeScript CLIs or just plain JavaScript CLIs. By virtue of static properties in TypeScript the syntax is a bit cleaner in TypeScript \u2014 but everything will work no matter which language you choose. If you use plugins support, the CLI will automatically use ",(0,r.kt)("inlineCode",{parentName:"p"},"ts-node")," to run the plugins making it easy and fast to use TypeScript with minimal-to-no boilerplate needed for any oclif CLI."),(0,r.kt)("h3",{id:"auto-updating-installers"},"Auto-updating Installers"),(0,r.kt)("p",null,"oclif can package your CLI into ",(0,r.kt)("a",{parentName:"p",href:"/docs/releasing"},"different installers")," that will not require the user to already have node installed on the machine. These can be made auto-updatable by using ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-update"},"plugin-update"),"."),(0,r.kt)("h3",{id:"autocomplete"},"Autocomplete"),(0,r.kt)("p",null,"Include terminal autocompletion for your CLI via ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-autocomplete"},"plugin-autocomplete"),". Once installed, users can complete command names and flag names."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$ my-cli p # will list all commands starting with 'p' for completion\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8059],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),u=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,f=c["".concat(s,".").concat(m)]||c[m]||d[m]||r;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>u,toc:()=>c});var o=n(7462),a=n(3366),r=(n(7294),n(3905)),i=["components"],l={title:"Features"},s=void 0,u={unversionedId:"features",id:"features",title:"Features",description:"Flag/Argument parsing",source:"@site/../docs/features.md",sourceDirName:".",slug:"/features",permalink:"/docs/features",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/features.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Features"},sidebar:"docs",previous:{title:"Introduction",permalink:"/docs/introduction"},next:{title:"FAQs",permalink:"/docs/faqs"}},p={},c=[{value:"Flag/Argument parsing",id:"flagargument-parsing",level:3},{value:"Configurable Topic Separators",id:"configurable-topic-separators",level:3},{value:"Super Speed",id:"super-speed",level:3},{value:"CLI Generator",id:"cli-generator",level:3},{value:"Testing Helpers",id:"testing-helpers",level:3},{value:"Auto-documentation",id:"auto-documentation",level:3},{value:"Plugins",id:"plugins",level:3},{value:"Hooks",id:"hooks",level:3},{value:"JSON Output",id:"json-output",level:3},{value:"TypeScript (or not)",id:"typescript-or-not",level:3},{value:"Auto-updating Installers",id:"auto-updating-installers",level:3},{value:"Autocomplete",id:"autocomplete",level:3}],d={toc:c},m="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,i);return(0,r.kt)(m,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h3",{id:"flagargument-parsing"},"Flag/Argument parsing"),(0,r.kt)("p",null,"No CLI framework would be complete without a flag parser. We've built a custom one from years of experimentation that we feel consistently handles user input flexible enough for the user to be able to easily use the CLI in ways they expect, but without compromising strictness guarantees to the developer."),(0,r.kt)("h3",{id:"configurable-topic-separators"},"Configurable Topic Separators"),(0,r.kt)("p",null,"By default topics will be separated with colons, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"my:awesome:command"),". However, you have the option to use spaces if you prefer, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"my awesome command"),"."),(0,r.kt)("h3",{id:"super-speed"},"Super Speed"),(0,r.kt)("p",null,"The overhead for running an oclif CLI command is almost nothing. ",(0,r.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/@oclif/core?activeTab=dependencies"},"It requires very few dependencies")," (only 28 dependencies in a minimal setup\u2014including all transitive dependencies). Also, only the command to be executed will be required with node. So large CLIs with many commands will load just as fast as a small one with a single command."),(0,r.kt)("h3",{id:"cli-generator"},"CLI Generator"),(0,r.kt)("p",null,"Run a single command to scaffold out a fully functional CLI and get started quickly. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/generator_commands"},"Generator Commands"),"."),(0,r.kt)("h3",{id:"testing-helpers"},"Testing Helpers"),(0,r.kt)("p",null,"We've put a lot of work into making commands easily testable and easy to mock out stdout/stderr. The generator will automatically create ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world/blob/main/test/commands/hello/world.test.ts"},"scaffolded tests"),"."),(0,r.kt)("h3",{id:"auto-documentation"},"Auto-documentation"),(0,r.kt)("p",null,"By default you can pass ",(0,r.kt)("inlineCode",{parentName:"p"},"--help")," to the CLI to get help such as flag options and argument information. This information is also automatically placed in the README whenever the npm package of the CLI is published. See the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/hello-world"},"hello-world CLI example")),(0,r.kt)("h3",{id:"plugins"},"Plugins"),(0,r.kt)("p",null,"Using plugins, users of the CLI can extend it with new functionality, a CLI can be split into modular components, and functionality can be shared amongst multiple CLIs. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/plugins#building-your-own-plugin"},"Building your own plugin"),"."),(0,r.kt)("h3",{id:"hooks"},"Hooks"),(0,r.kt)("p",null,"Use lifecycle hooks to run functionality any time a CLI starts, or on custom triggers. Use this whenever custom functionality needs to be shared between various components of the CLI. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/hooks"},"Hooks"),"."),(0,r.kt)("h3",{id:"json-output"},"JSON Output"),(0,r.kt)("p",null,"You can opt-in to using the ",(0,r.kt)("inlineCode",{parentName:"p"},"--json")," flag which will automatically suppress console logs and display the final result of the command as valid JSON output. This is very useful if you want your CLI to be used for scripting in CI/CD environments. See ",(0,r.kt)("a",{parentName:"p",href:"https://oclif.io/docs/json"},"JSON"),"."),(0,r.kt)("h3",{id:"typescript-or-not"},"TypeScript (or not)"),(0,r.kt)("p",null,"Everything in the core of oclif is written in TypeScript and the generator can build fully configured TypeScript CLIs or just plain JavaScript CLIs. By virtue of static properties in TypeScript the syntax is a bit cleaner in TypeScript \u2014 but everything will work no matter which language you choose. If you use plugins support, the CLI will automatically use ",(0,r.kt)("inlineCode",{parentName:"p"},"ts-node")," to run the plugins making it easy and fast to use TypeScript with minimal-to-no boilerplate needed for any oclif CLI."),(0,r.kt)("h3",{id:"auto-updating-installers"},"Auto-updating Installers"),(0,r.kt)("p",null,"oclif can package your CLI into ",(0,r.kt)("a",{parentName:"p",href:"/docs/releasing"},"different installers")," that will not require the user to already have node installed on the machine. These can be made auto-updatable by using ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-update"},"plugin-update"),"."),(0,r.kt)("h3",{id:"autocomplete"},"Autocomplete"),(0,r.kt)("p",null,"Include terminal autocompletion for your CLI via ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-autocomplete"},"plugin-autocomplete"),". Once installed, users can complete command names and flag names."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$ my-cli p # will list all commands starting with 'p' for completion\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a92e169d.701f84c9.js b/assets/js/a92e169d.bd0fb0a8.js similarity index 98% rename from assets/js/a92e169d.701f84c9.js rename to assets/js/a92e169d.bd0fb0a8.js index 07edf28e..eb416c26 100644 --- a/assets/js/a92e169d.701f84c9.js +++ b/assets/js/a92e169d.bd0fb0a8.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6332],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),s=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),m=s(n),f=r,u=m["".concat(i,".").concat(f)]||m[f]||d[f]||o;return n?a.createElement(u,l(l({ref:t},p),{},{components:n})):a.createElement(u,l({ref:t},p))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[m]="string"==typeof e?e:r,l[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>c,metadata:()=>s,toc:()=>m});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),l=["components"],c={title:"Global Flags"},i=void 0,s={unversionedId:"global_flags",id:"global_flags",title:"Global Flags",description:"There are some instances where you might want to define a flag once for all of your commands. In this case you can add a global flag to an abstract base Command class. For example,",source:"@site/../docs/global_flags.md",sourceDirName:".",slug:"/global_flags",permalink:"/docs/global_flags",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/global_flags.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Global Flags"},sidebar:"docs",previous:{title:"Flexible Taxonomy",permalink:"/docs/flexible_taxonomy"},next:{title:"Single Command CLI",permalink:"/docs/single_command_cli"}},p={},m=[],d={toc:m},f="wrapper";function u(e){var t=e.components,n=(0,r.Z)(e,l);return(0,o.kt)(f,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"There are some instances where you might want to define a flag once for all of your commands. In this case you can add a global flag to an abstract base ",(0,o.kt)("inlineCode",{parentName:"p"},"Command")," class. For example,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import { Command, Flags } from '@oclif/core';\n\nexport abstract class BaseCommand extends Command {\n static baseFlags = {\n interactive: Flags.boolean({\n char: 'i',\n description: 'Run command in interactive mode',\n }),\n };\n}\n")),(0,o.kt)("p",null,"Any command that extends ",(0,o.kt)("inlineCode",{parentName:"p"},"BaseCommand")," will now have an ",(0,o.kt)("inlineCode",{parentName:"p"},"--interactive")," flag on it."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6332],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>u});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),s=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),m=s(n),f=r,u=m["".concat(i,".").concat(f)]||m[f]||d[f]||o;return n?a.createElement(u,l(l({ref:t},p),{},{components:n})):a.createElement(u,l({ref:t},p))}));function u(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[m]="string"==typeof e?e:r,l[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>c,metadata:()=>s,toc:()=>m});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),l=["components"],c={title:"Global Flags"},i=void 0,s={unversionedId:"global_flags",id:"global_flags",title:"Global Flags",description:"There are some instances where you might want to define a flag once for all of your commands. In this case you can add a global flag to an abstract base Command class. For example,",source:"@site/../docs/global_flags.md",sourceDirName:".",slug:"/global_flags",permalink:"/docs/global_flags",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/global_flags.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Global Flags"},sidebar:"docs",previous:{title:"Flexible Taxonomy",permalink:"/docs/flexible_taxonomy"},next:{title:"Single Command CLI",permalink:"/docs/single_command_cli"}},p={},m=[],d={toc:m},f="wrapper";function u(e){var t=e.components,n=(0,r.Z)(e,l);return(0,o.kt)(f,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"There are some instances where you might want to define a flag once for all of your commands. In this case you can add a global flag to an abstract base ",(0,o.kt)("inlineCode",{parentName:"p"},"Command")," class. For example,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import { Command, Flags } from '@oclif/core';\n\nexport abstract class BaseCommand extends Command {\n static baseFlags = {\n interactive: Flags.boolean({\n char: 'i',\n description: 'Run command in interactive mode',\n }),\n };\n}\n")),(0,o.kt)("p",null,"Any command that extends ",(0,o.kt)("inlineCode",{parentName:"p"},"BaseCommand")," will now have an ",(0,o.kt)("inlineCode",{parentName:"p"},"--interactive")," flag on it."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a96ec439.3e244ed4.js b/assets/js/a96ec439.0aea02dd.js similarity index 98% rename from assets/js/a96ec439.3e244ed4.js rename to assets/js/a96ec439.0aea02dd.js index 9dab3cbe..72e6e95e 100644 --- a/assets/js/a96ec439.3e244ed4.js +++ b/assets/js/a96ec439.0aea02dd.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6731],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},f="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),f=l(n),m=o,d=f["".concat(s,".").concat(m)]||f[m]||u[m]||i;return n?r.createElement(d,a(a({ref:t},p),{},{components:n})):r.createElement(d,a({ref:t},p))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[f]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>d,frontMatter:()=>c,metadata:()=>l,toc:()=>f});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],c={title:"Notifications"},s=void 0,l={unversionedId:"notifications",id:"notifications",title:"Notifications",description:"Use node-notifier for cross-platform OS notifications.",source:"@site/../docs/notifications.md",sourceDirName:".",slug:"/notifications",permalink:"/docs/notifications",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/notifications.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Notifications"},sidebar:"docs",previous:{title:"Table",permalink:"/docs/table"},next:{title:"Debugging",permalink:"/docs/debugging"}},p={},f=[],u={toc:f},m="wrapper";function d(e){var t=e.components,c=(0,o.Z)(e,a);return(0,i.kt)(m,(0,r.Z)({},u,c,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Use ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/mikaelbr/node-notifier"},"node-notifier")," for cross-platform OS notifications."),(0,i.kt)("p",null,"Example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nimport * as notifier from 'node-notifier'\n\nexport class MyCommand extends Command {\n async run() {\n notifier.notify({\n title: 'My notification',\n message: 'Hello!'\n })\n }\n}\n")),(0,i.kt)("p",null,"Demo:"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"notification demo",src:n(5925).Z,width:"1028",height:"803"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/mikaelbr/node-notifier"},"node-notifier")," is capable of much more such as adding images, sounds, and even buttons and user input."))}d.isMDXComponent=!0},5925:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/notification_demo-4cc045397623e249062842eb4b8afab0.gif"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[6731],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},f="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),f=l(n),m=o,d=f["".concat(s,".").concat(m)]||f[m]||u[m]||i;return n?r.createElement(d,a(a({ref:t},p),{},{components:n})):r.createElement(d,a({ref:t},p))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[f]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>d,frontMatter:()=>c,metadata:()=>l,toc:()=>f});var r=n(7462),o=n(3366),i=(n(7294),n(3905)),a=["components"],c={title:"Notifications"},s=void 0,l={unversionedId:"notifications",id:"notifications",title:"Notifications",description:"Use node-notifier for cross-platform OS notifications.",source:"@site/../docs/notifications.md",sourceDirName:".",slug:"/notifications",permalink:"/docs/notifications",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/notifications.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Notifications"},sidebar:"docs",previous:{title:"Table",permalink:"/docs/table"},next:{title:"Debugging",permalink:"/docs/debugging"}},p={},f=[],u={toc:f},m="wrapper";function d(e){var t=e.components,c=(0,o.Z)(e,a);return(0,i.kt)(m,(0,r.Z)({},u,c,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Use ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/mikaelbr/node-notifier"},"node-notifier")," for cross-platform OS notifications."),(0,i.kt)("p",null,"Example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nimport * as notifier from 'node-notifier'\n\nexport class MyCommand extends Command {\n async run() {\n notifier.notify({\n title: 'My notification',\n message: 'Hello!'\n })\n }\n}\n")),(0,i.kt)("p",null,"Demo:"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"notification demo",src:n(5925).Z,width:"1028",height:"803"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/mikaelbr/node-notifier"},"node-notifier")," is capable of much more such as adding images, sounds, and even buttons and user input."))}d.isMDXComponent=!0},5925:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/notification_demo-4cc045397623e249062842eb4b8afab0.gif"}}]); \ No newline at end of file diff --git a/assets/js/b2f554cd.d0fa6f76.js b/assets/js/b2f554cd.8147c378.js similarity index 99% rename from assets/js/b2f554cd.d0fa6f76.js rename to assets/js/b2f554cd.8147c378.js index 61ae0dc8..c9ba501b 100644 --- a/assets/js/b2f554cd.d0fa6f76.js +++ b/assets/js/b2f554cd.8147c378.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1477],{10:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2022/01/12/announcing-oclif-v2","metadata":{"permalink":"/blog/2022/01/12/announcing-oclif-v2","source":"@site/blog/2022-01-12-announcing-oclif-v2.md","title":"Announcing oclif v2!","description":"Hello and happy new year! It\'s our great pleasure to announce that we have released oclif v2, which uses the new @oclif/core library! \ud83c\udf89","date":"2022-01-12T00:00:00.000Z","formattedDate":"January 12, 2022","tags":[],"readingTime":4.48,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Announcing oclif v2!"},"nextItem":{"title":"Introducing @oclif/core","permalink":"/blog/2021/03/01/introducing-oclif-core"}},"content":"Hello and happy new year! It\'s our great pleasure to announce that we have released oclif v2, which uses the new [@oclif/core](https://github.com/oclif/core) library! \ud83c\udf89\\n\\noclif v2 includes many changes that improve the experience of both creating and using an oclif CLI.\\n\\nGoing forward, we don\'t plan to make any updates to oclif v1 and its corresponding libraries, except for critical security fixes. See the [compatibility matrix](#compatibility-matrix) for a list of these libraries. In order to give developers time to migrate from v1 to v2, we\'re not completely dropping support yet. But at some point in the future we\'ll archive the v1 repositories and deprecate their versions on npm.\\n\\n## What\u2019s changing?\\n\\n### Repository Changes\\n\\nAll repositories under the [oclif org](https://github.com/oclif/) now use `main` as their primary branch and `oclif-v1` as the legacy branch. The `main` branch corresponds to oclif v2 and the `oclif-v1` branch to oclif v1. If you find any repos that don\u2019t have a `main` branch, you can safely assume that they\'re not used in oclif v2 and will be deprecated in the future.\\n\\n### Consolidating Tools & Libraries\\n\\nThe [`oclif-dev`](https://github.com/oclif/dev-cli) CLI has now been incorporated into [`oclif`](https://github.com/oclif/oclif). You now no longer need to install a separate package to manage your entire CLI\u2019s lifecycle.\\n\\nThe following libraries have been consolidated under [`@oclif/core`](https://github.com/oclif/core) and will be deprecated at some point in the future. Read the [migration guide](https://github.com/oclif/core/blob/main/MIGRATION.md) to learn how to update your CLI or plugin to use the new core library.\\n\\n* `@oclif/command`\\n* `@oclif/config`\\n* `@oclif/error`\\n* `@oclif/help`\\n* `@oclif/parser`\\n\\n### No more single vs multi command CLIs\\n\\nThere\'s only one \\"type\\" of oclif v2 CLI, but it can have as few or as many commands as a developer wants. As a result, there\u2019s only one command to generate CLIs, `oclif generate`, as opposed to the old `oclif single` and `oclif multi` commands.\\n\\n### Node > 12\\n\\nTo ensure oclif CLIs are as secure as possible, all v2 libraries and plugins support only Node 12 or higher as of now. Going forward, they\'ll support only Node Maintenance or higher, as defined by Node\'s release schedule here: https://nodejs.org/en/about/releases/.\\n\\n## What\u2019s new?\\n\\n### New example CLI\\n\\n[`oclif-hello-world`](https://github.com/oclif/hello-world/) is our new example repo. This is also the repo that\'s [used as a template](https://github.com/oclif/oclif/blob/edc6616e51/src/generators/cli.ts#L74) when running `oclif generate` to create a new CLI. This repo will always be able to be referenced as an example of what an oclif v2 CLI should look like.\\n\\n### Spaced commands\\n\\noclif CLIs can now use spaces, instead of colons, to separate topics and subcommands. To enable this feature, simply add `\u201ctopicSeparator\\": \\" \\"` to the oclif config in your package.json. See an example in our [example repo](https://github.com/oclif/hello-world/blob/main/package.json#L55).\\n\\n```\\n// Old commands that use :\\n$ mycli do:something\\n```\\n```\\n// New spaced commands\\n$ mycli do something\\n```\\n\\n> Note: Spaced commands are backwards compatible. So if you enable spaced commands for your CLI, users will still be able to use `:` as a separator. This ensures that any existing scripts don\'t break.\\n\\n### New Help Output\\n\\nWe\u2019ve revamped the way command help is outputted to the terminal, making it both easier to implement and easier to read. See the difference between the old help output on the left and the new help output on the right in the screenshots below.\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n
oclif v1oclif v2
\\n\\nNotice that there are new sections for flags and global flags, examples are displayed with better spacing, and there is a section at the bottom called Configuration Variables. This Configuration Variables section is not part of the new help by default. But we\'ve added support for custom help sections, which is what the `sf` CLI uses to create the new section. \\n\\n### Async Command Parsing\\n\\nWe\u2019ve also improved the performance of new CLIs by rewriting how commands are parsed on initialization. The [new parser](https://github.com/oclif/core/blob/main/src/parser/parse.ts) is asynchronous, which makes CLIs with a lot of commands or installed plugins much faster.\\n\\n## What\u2019s coming next?\\n\\nPart of our charter for the release of oclif v2 includes improving our engagement with the oclif community. We know that over the past couple of years we\u2019ve reduced our involvement, and a lot of issues and PRs have languished in limbo. Hopefully you\u2019ve already seen increased activity and responses from oclif maintainers recently, but if you haven\u2019t, please don\u2019t hesitate to ping us by tagging [@admins](https://github.com/orgs/oclif/teams/admins) in oclif repos.\\n\\nWe also want to start interviewing members of the oclif community to acquire feedback and prioritize the features and fixes you deem most important!\\n\\nBest,\\n\\nThe oclif team\\n\\n
\\n\\n### Reference material \\n\\n#### Migration Guide\\n\\nThis guide explains how to upgrade a CLI or plugin from the old oclif v1 libraries to the new `@oclif/core` library that oclif v2 uses.\\n\\nhttps://github.com/oclif/core/blob/main/MIGRATION.md\\n\\n#### Compatibility Matrix\\n\\nThe following matrix shows how the v1 libraries and plugins relate to the new v2 ones. Use this matrix as a guide to know what to drop and which versions to switch when upgrading your plugins and CLIs to v2.\\n\\n| | oclif \\"v1\\" | oclif \\"v2\\" |\\n| - | - | -|\\n| Utility CLIs | oclif@<2
@oclif/dev-cli@<2 | oclif@>=2\\n| Main packages | @oclif/command
@oclif/config
@oclif/errors
@oclif/parser
@oclif/plugin-help
| @oclif/core@>=1\\n| Node LTS | Node v8-14 | Node v12+ (at time of writing) |\\n| TypeScript | typescript@<4 | typescript@>=4 |\\n| Main plugins | @oclif/plugin-autocomplete@<1
@oclif/plugin-commands@<2
@oclif/plugin-help@<4
@oclif/plugin-not-found@<2
@oclif/plugin-plugins@<2
@oclif/plugin-update@<2
plugin-warn-if-update-available@<2
plugin-which@<2
| @oclif/plugin-autocomplete@>=1
@oclif/plugin-commands@>=2
@oclif/plugin-help@>=4
@oclif/plugin-not-found@>=2
@oclif/plugin-plugins@>=2
@oclif/plugin-update@>=2
@oclif/plugin-warn-if-update-available@>=2
@oclif/plugin-which@>=2
|"},{"id":"/2021/03/01/introducing-oclif-core","metadata":{"permalink":"/blog/2021/03/01/introducing-oclif-core","source":"@site/blog/2021-03-01-introducing-oclif-core.md","title":"Introducing @oclif/core","description":"Greetings!","date":"2021-03-01T00:00:00.000Z","formattedDate":"March 1, 2021","tags":[],"readingTime":2.18,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Introducing @oclif/core"},"prevItem":{"title":"Announcing oclif v2!","permalink":"/blog/2022/01/12/announcing-oclif-v2"},"nextItem":{"title":"oclif Summer Update","permalink":"/blog/2020/08/26/summer-update"}},"content":"Greetings!\\n\\nWe hope this blog post finds you well.\\n\\n### Introducing...\\n\\nWe are excited to announce the next iteration of the oclif project today: `@oclif/core`.\\n\\nWe have learned a lot in the last three years of developing oclif, developing on oclif and supporting millions of command runs a day via Heroku and Salesforce CLIs.\\n`@oclif/core` (\\"Core\\") simplifies the oclif development experience and introduces highly requested new features.\\n\\nCore combines the essential oclif packages into one \\"core\\" package, aptly named `@oclif/core`.\\n\\nCore also introduces:\\n- A default command option\\n- Colon or space command syntax\\n- Async command parsing\\n- Command piping to arguments\\n\\nWith the introduction of default command functionality, Core simplifies the oclif project and removes the notion of single or multi command CLIs. Core CLIs can have 1 or many commands.\\n\\nAlong with Core, we moved the oclif-dev CLI into the oclif CLI creating a single \\"utility\\" CLI. This CLI also introduces a new AWS S3 compatible publishing scheme.\\n\\n### What to expect in the near future\\n\\nCore is in pre-release beta and being actively developed for new internal Salesforce CLIs.\\n\\nMuch documentation needs to be written in the coming months including migration paths. Migration onto Core should be as painless as possible with many exports remaining entirely unchanged. Look for forthcoming blog posts and documentation on [oclif.io](https://oclif.io).\\n\\nEarly this summer, tentively June 1, we will release Core v1. Core\'s release will coincide with major bumps to many other oclif plugin packages. See the compatibility matrix below.\\n\\nAt Core\'s v1 release, the current \\"main\\" oclif packages (namely: command, config, errors & parser) will go into maintenance mode until Jan 2022. They will receive _only_ bug and security fixes and they remain compatible with current versions of the oclif and oclif-dev CLIs. Afterwhich, they will be archived.\\n\\nCompanioning Core, the next major release of the oclif CLI (literally `oclif@2`) will generate Core CLIs.\\n\\n### Going forward\\n\\nWe are excited to release Core! We invite you to poke around the [Core repo](https://github.com/oclif/core). It may appear to be a big change but Core keeps what you already enjoy about oclif while reducing development complexity, project dependencies, package coupling and bundle size and introduces many requested features previously too prickly to weave into the current oclif architecture.\\n\\nBest,\\n\\nThe oclif team\\n\\n#### Reference: Compatibility matrix\\n\\n| | oclif \\"v1\\" | oclif \\"Core\\" |\\n| - | - | -|\\n| Utility CLIs | oclif@<2
@oclif/dev-cli@<2 | oclif@>=2\\n| Main packages | @oclif/core@<2
@oclif/config@<2
@oclif/errors@<2
@oclif/parser@<4
@oclif/plugin-help@<4
| @oclif/core@>=1\\n| Node LTS | Node v8-14 | Node v12+ |\\n| TypeScript | typescript@<4 | typescript@>=4 |\\n| Main plugins | @oclif/plugin-autocomplete@<1
@oclif/plugin-commands@<2
@oclif/plugin-help@<4
@oclif/plugin-not-found@<2
@oclif/plugin-plugins@<2
@oclif/plugin-update@<2
plugin-warn-if-update-available@<2
plugin-which@<2
| @oclif/plugin-autocomplete@>=2
@oclif/plugin-commands@>=2
@oclif/plugin-help@>=4
@oclif/plugin-not-found@>=2
@oclif/plugin-plugins@>=2
@oclif/plugin-update@>=2
@oclif/plugin-warn-if-update-available@>=2
@oclif/plugin-which@>=2
|"},{"id":"/2020/08/26/summer-update","metadata":{"permalink":"/blog/2020/08/26/summer-update","source":"@site/blog/2020-08-26-summer-update.md","title":"oclif Summer Update","description":"Hello oclif developers! We hope you are all doing well.","date":"2020-08-26T00:00:00.000Z","formattedDate":"August 26, 2020","tags":[],"readingTime":1.355,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif Summer Update"},"prevItem":{"title":"Introducing @oclif/core","permalink":"/blog/2021/03/01/introducing-oclif-core"},"nextItem":{"title":"Pretty Printable Errors","permalink":"/blog/2020/07/01/pretty-printable-errors"}},"content":"Hello oclif developers! We hope you are all doing well.\\n\\nEarlier this year, we started our planning for oclifconf v2 and, like all conference, had to change course. We opted not to hold a virtual conference, however, we wanted to take some time to highlight a few oclif features shipped this year.\\n\\n## Feature: Help templating\\n\\nOne of the most requested features, help templating enables oclif developers to customize the help output for their CLI.\\n\\nRead [the announcement](/blog/introducing-custom-help-classes).\\n\\n## Feature: Custom error delegation\\n\\nThis feature both improved how oclif throws and handles errors and allows oclif developers to overwrite or interject in oclif\u2019s error handling.\\n\\nRead [the announcement](/blog/2020/07/01/pretty-printable-errors).\\n\\n## Feature: postrun hooks\\n\\nWe have added a new lifecycle event `postrun`. Your CLI can now run a hook after a command has ran.\\n\\nSee our [hook documentation](/docs/hooks).\\n\\n## Feature: Root index command\\n\\nPreviously, oclif would display CLI help if only the binary name with no command ID was invoked, oclif now supports a \\"root index\\" command. If present, a command defined at `src/commands/index.ts` will be run if no command ID is found.\\n\\n## 1 million weekly downloads\\n\\nWhile exact oclif usage metrics are hard to pin down, we use npm download statistics of oclif packages as a rough approximation. Earlier this year, oclif\'s command package hit 1 million weekly downloads for the first time!\\n\\n\\nThis year has been presented its challenges on everyone. We want to thank you, oclif developers, whom have taken the time to use and improve the oclif project. We look forward to seeing you all - in person - in the future!\\n\\nAll our best,\\n\\nThe oclif team"},{"id":"/2020/07/01/pretty-printable-errors","metadata":{"permalink":"/blog/2020/07/01/pretty-printable-errors","source":"@site/blog/2020-07-01-pretty-printable-errors.md","title":"Pretty Printable Errors","description":"Often CLIs are used as handy tools and when things go wrong it\u2019s useful to have additional context. In oclif we have added a couple of additional properties that can show extra context to the users when an error is displayed. The code, ref and suggestions will now be displayed if they are included. This will work with an existing oclif CLI by adding the latest @oclif/errors and @oclif/core to the CLI\'s package.json dependencies.","date":"2020-07-01T00:00:00.000Z","formattedDate":"July 1, 2020","tags":[],"readingTime":0.995,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Pretty Printable Errors"},"prevItem":{"title":"oclif Summer Update","permalink":"/blog/2020/08/26/summer-update"},"nextItem":{"title":"Customizing Help in oclif","permalink":"/blog/2020/05/05/introducing-custom-help-classes"}},"content":"Often CLIs are used as handy tools and when things go wrong it\u2019s useful to have additional context. In oclif we have added a couple of additional properties that can show extra context to the users when an error is displayed. The `code`, `ref` and `suggestions` will now be displayed if they are included. This will work with an existing oclif CLI by adding the latest @oclif/errors and @oclif/core to the CLI\'s package.json dependencies.\\n\\nFor example, using `this.error` with the additional properties:\\n```js\\nclass TestError extends Command {\\n async run() {\\n this.error(\\"An error has occurred!\\", {\\n code: \\"OCLIF_ERR\\",\\n ref: \\"https://oclif.io/docs/commands#thiserrormessage-string--error-options-code-string-exit-number\\",\\n suggestions: [\\"Use these extra properties to provide additional context\\"],\\n })\\n }\\n}\\n```\\n\\nwould result with the following output:\\n```text\\n\u203a Error: An error has occurred!\\n\u203a Code: OCLIF_ERR\\n\u203a Try this: Use these extra properties to provide additional context\\n\u203a Reference: https://oclif.io/docs/commands#thiserrormessage-string--error-options-code-string-exit-number\\n```\\n\\nIf these properties are not provided then nothing changes and the CLI will continue to display the single error message output as it did before. Additionally, as part of this exercise we\u2019ve added documentation around [Error Handling in oclif](/docs/error_handling) which should come in handy if the need arises to extend oclif\u2019s default handling of errors."},{"id":"/2020/05/05/introducing-custom-help-classes","metadata":{"permalink":"/blog/2020/05/05/introducing-custom-help-classes","source":"@site/blog/2020-05-05-introducing-custom-help-classes.md","title":"Customizing Help in oclif","description":"Out of the box oclif provides a great help experience for CLIs.","date":"2020-05-05T00:00:00.000Z","formattedDate":"May 5, 2020","tags":[],"readingTime":1.67,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Customizing Help in oclif"},"prevItem":{"title":"Pretty Printable Errors","permalink":"/blog/2020/07/01/pretty-printable-errors"},"nextItem":{"title":"oclif TSLint to ESLint Migration","permalink":"/blog/2019/12/05/oclif-eslint-migration"}},"content":"Out of the box oclif provides a great help experience for CLIs.\\n\\nBut what if, as an oclif developer, you want to customize some or all of the output?\\n\\nYou can now customize your CLI\'s help output by implementing the `HelpBase` abstract class.\\n\\n## Getting started with custom help\\n\\nIf you have not done so yet, update `@oclif/core`.\\n\\n\\n```\\n$ yarn add --latest @oclif/core\\n```\\n\\nTo get started, first define the filepath to your help class in oclif\'s config in package.json. This is a relative path to the help class, without a file extension.\\n\\nFor this example, the help class will be created in a file at \\"[project root]/src/help.ts\\".\\n\\n```\\n{\\n // ...\\n \\"oclif\\": {\\n \\"helpClass\\": \\"./lib/help\\"\\n // ...\\n }\\n // ...\\n}\\n```\\n\\nFrom here there are two paths, implement the `HelpBase` abstract class yourself or overwrite the parts of the default `Help` class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new [Help Classes docs](../../../../docs/help_classes).\\n\\n\\n## Separating TOPICS & COMMANDS in the new deafult `Help` class\\n\\nPreviously, topics and child commands were listed in help output under a single list heading called \\"COMMANDS\\". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).\\n\\nThe new default `Help` class splits the list of children into distinct lists of \\"TOPICS\\" and \\"COMMANDS\\", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - \\"COMMANDS\\" - and what is providing structure - \\"TOPICS\\" - when looking at the help output.\\n\\n```\\nVERSION\\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\\n\\nUSAGE\\n $ plugin-help-example [COMMAND]\\n\\nTOPICS\\n topic this is a topic and has child topics or commands\\n\\nCOMMANDS\\n hello describe the command here\\n help display help for plugin-help-example\\n```\\n\\nWe look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"},{"id":"/2019/12/05/oclif-eslint-migration","metadata":{"permalink":"/blog/2019/12/05/oclif-eslint-migration","source":"@site/blog/2019-12-05-oclif-eslint-migration.md","title":"oclif TSLint to ESLint Migration","description":"Back in February of this year, plans were announced to deprecate TSLint in favor of ESLint. TSLint\'s goal has become to work toward a \u201cunified developer experience\u201d by supporting ESLint development going forward.","date":"2019-12-05T00:00:00.000Z","formattedDate":"December 5, 2019","tags":[],"readingTime":2.18,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif TSLint to ESLint Migration"},"prevItem":{"title":"Customizing Help in oclif","permalink":"/blog/2020/05/05/introducing-custom-help-classes"},"nextItem":{"title":"oclif\'s Current Node Support","permalink":"/blog/2019/10/31/oclif-node-updates"}},"content":"Back in February of this year, plans were announced to [deprecate TSLint](https://github.com/palantir/tslint/issues/4534) in favor of ESLint. TSLint\'s goal has become to work toward a \u201cunified developer experience\u201d by supporting ESLint development going forward.\\n\\n\\n\\n## What has changed in oclif\\n\\nTo keep inline with the community, oclif has transitioned to ESLint for all our core libraries as well as all our official plugins.\\n\\nStarting in v1.15.x, oclif will now optionally generate projects with ESLint for both TypeScript and JavaScript CLI\u2019s.\\n\\nESLint does require Node to be on stable LTS version, at the time of writing, Node 8.10.x, Node 10.13.x & Node 12.x.x.\\n\\n## How does this affect you\\n\\nExisting CLI\u2019s are unchanged, but any newly generated CLI\'s will only give the option of using ESLint. If you are running tslint in your CLI, we recommend you switch to ESLint as well.\\n\\nIn migrating our projects we took the following steps (for an example of these changes see this [pull request](https://github.com/oclif/githubcli/pull/10)).\\n\\n1. Install eslint\\n\\n `$ yarn add eslint eslint-config-oclif eslint-config-oclif-typescript --dev`\\n2. Add eslint related files\\n```shell\\n$ echo \'{\\n \\"extends\\": [\\n \\"oclif\\",\\n \\"oclif-typescript\\"\\n ],\\n \\"rules\\": {\\n }\\n}\' > .eslintrc\\n```\\n3. Remove tslint and related packages\\n\\n `$ yarn remove @oclif/tslint tslint`\\n4. Remove tslint related configuration files\\n\\n `$ rm tslint.json`\\n5. Change lint script in our package.json from something like:\\n\\n `\\"lint\\": \\"tsc -p test --noEmit && tslint -p test -t stylish\\"`\\n \\n to\\n \\n `\\"lint\\": \\"eslint . --ext .ts --config .eslintrc\\"`\\n\\nTo preserve the test compile (tsc -p test --noEmit) we also made the following updates to our scripts:\\n\\n`\\"pretest\\": \\"tsc -p test --noEmit\\"`\\n\\nIn some cases we had our posttest duplicating the same steps as our lint script so it\u2019s cleaner to have it reference the lint job directly with:\\n\\n`\\"posttest\\": \\"yarn lint\\"`\\n\\n\\n6. Run `yarn lint --fix`. This attempts to auto-fix any linting violations automatically. In the case an auto-fix isn\u2019t available it should be fixed manually or ignored (see the [eslint configuration doc](https://eslint.org/docs/user-guide/configuring) for more information) \\n7. Do a search in the codebase for `tslint` and remove any unnecessary tslint disabling comments, like: \\n```javascript\\n/* tslint:disable:object-literal-sort-keys */\\n```\\n\\n\\nIf you are on a version of Node that is not supported by ESLint, you will also need to update your Node engine. ESLint supports Node 8, 10, and 12 so you should upgrade to the most recent Node version compatible with your CLI and also supported by ESLint (see ESLint\'s [Installation and Usage](https://www.npmjs.com/package/eslint#installation-and-usage) instructions).\\n\\n## When will this take effect\\n\\nThese changes have taken effect in oclif v1.15.1. When you generate a new CLI or plugin it will now contain configuration for ESLint instead of TSLint."},{"id":"/2019/10/31/oclif-node-updates","metadata":{"permalink":"/blog/2019/10/31/oclif-node-updates","source":"@site/blog/2019-10-31-oclif-node-updates.md","title":"oclif\'s Current Node Support","description":"To maintain a healthy project trajectory, oclif follows and supports Node Active LTS release, currently Node 10 & Node 12. This means ensuring that oclif continues to play nice with coming Active LTS Node versions and other packages in the ecosystem. Moving forward also means leaving older versions behind. Starting in 2020, Node will stop maintaining Node 8 and it is our intent at that time to also follow suit. Let\u2019s take a look at a few ways we will be supporting these changes.","date":"2019-10-31T00:00:00.000Z","formattedDate":"October 31, 2019","tags":[],"readingTime":2.4,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif\'s Current Node Support"},"prevItem":{"title":"oclif TSLint to ESLint Migration","permalink":"/blog/2019/12/05/oclif-eslint-migration"},"nextItem":{"title":"CLI Flags Explained","permalink":"/blog/2019/02/20/cli-flags-explained"}},"content":"To maintain a healthy project trajectory, oclif follows and supports [Node Active LTS release](https://nodejs.org/en/about/releases/), currently Node 10 & Node 12. This means ensuring that oclif continues to play nice with coming Active LTS Node versions and other packages in the ecosystem. Moving forward also means leaving older versions behind. Starting in 2020, Node will stop maintaining [Node 8](https://github.com/nodejs/Release#release-schedule) and it is our intent at that time to also follow suit. Let\u2019s take a look at a few ways we will be supporting these changes.\\n\\n## CI Environments\\n\\nCLIs created with the oclif cli going forward will be generated with a CircleCI configuration with Node 10 & 12 and an Appveyor configuration using Node 10. We have also added Node latest to CircleCi to be an early warning detection against coming Node changes (Node latest is managed by CircleCI).\\n\\nWe have already updated every oclif repo\'s CI configs to reflect this.\\n\\nIf your existing CLI uses either Appveyor or CircleCI you can update your config files also, like so:\\n\\n### .circleci/config.yml\\n\\nYour CircleCI config should contain a `node-latest` job, aliased as `test`. From this, there should be two extensions of this job for the Active LTS Node versions, Node 10 and Node 12.\\n\\n```\\n node-10:\\n <<: *node-latest\\n docker:\\n - image: node:10\\n node-12:\\n <<: *node-latest\\n docker:\\n - image: node:12\\n```\\n\\nNotice that these declarations only change the Docker Node images used to run that job.\\n\\nAdditionally, the jobs listed within workflows must also be updated to reflect our changes in configuration:\\n\\n```\\n jobs:\\n - node-latest\\n - node-10\\n - node-12\\n```\\n\\n### appveyor.yml\\n\\nFor appveyor we are currently only testing the oldest Active LTS Node version, Node 10. Update the `nodejs_version` proppert in your appveyor.yml file to reflect this.\\n\\n```\\nenvironment:\\n nodejs_version: \\"10\\"\\n```\\n\\n\\n## Deprecating Node 8 & Updating packge.json engines\\n\\nIn Jan 2020, Node will end its Node 8 maintenance. We will follow suit by setting the package.json engine property in oclif packages to `>=10` and bumping the package\'s major versions.\\n\\nDepending on how you ship your CLI you may wish to also bump the engines version in your CLI\'s package.json. You can read more about the implications of the engines property configuration in the [npm documentation](https://docs.npmjs.com/files/package.json#engines).\\n\\nAlso consider distributing your CLI with [its own Node version](https://oclif.io/docs/releasing#standalone-tarballs).\\n\\n## Packaged Node Version\\n\\nWhen using dev-cli to pack your CLI it will use the Node version as specified in your package.json under the `oclif.update.node.version` property. This value should reflect an Active LTS Node version (dev-cli does not currently enforce versions).\\n\\n## Supporting the future\\n\\nAs a community we may discover bumps along the way as we upgrade. If you notice something related to oclif please feel free to open an issue or submit a pull request under the relevant oclif package within [the org](https://github.com/oclif).\\n\\nWe look forward to using the latest from Node and the community and keeping oclif healthy along the way."},{"id":"/2019/02/20/cli-flags-explained","metadata":{"permalink":"/blog/2019/02/20/cli-flags-explained","source":"@site/blog/2019-02-20-cli-flags-explained.md","title":"CLI Flags Explained","description":"oclif makes it easy to create a command line interface (CLI) in node. Most commands have parameters \u2014 also known as \\"flags\\", \\"args\\", and sometimes \\"options\\". This blog post explains what these parameters are and when to use them. We also have a new feature that makes it easier for users to detect typos when using parameters.","date":"2019-02-20T00:00:00.000Z","formattedDate":"February 20, 2019","tags":[],"readingTime":4.925,"hasTruncateMarker":false,"authors":[{"name":"Casey Watts and Jeff Dickey"}],"frontMatter":{"author":"Casey Watts and Jeff Dickey","title":"CLI Flags Explained"},"prevItem":{"title":"oclif\'s Current Node Support","permalink":"/blog/2019/10/31/oclif-node-updates"},"nextItem":{"title":"Introducing oclif","permalink":"/blog/2018/03/20/introducing-oclif"}},"content":"`oclif` makes it easy to create a command line interface (CLI) in node. Most commands have **parameters** \u2014 also known as \\"flags\\", \\"args\\", and sometimes \\"options\\". This blog post explains what these parameters are and when to use them. We also have a new feature that makes it easier for users to detect typos when using parameters.\\n\\n_Note the following describes GNU-style flags. Not all CLIs follow this convention, but it is the most commonly used._\\n\\n## Parts of Speech\\n\\nAny command line interface command has a few standard \\"parts of speech\\". As a user of CLI tools, knowing these parts of speech can help you make fewer typos. It can also help you understand complex commands other people share with you more quickly. If you are designing a CLI tool it is even more important to understand these parts of speech, so you can come up with the most ergonomic interface for your users.\\n\x3c!-- DIAGRAM OF PARTS OF SPEECH EXAMPLE --\x3e\\n\\nOf the many ways you can pass data to a CLI command, three of them are **parameters** that are always to the \\"right\\" of the command. The three types of parameters are **argument**, **short flag**, and **long flag**.\\n\\n### Example `ls`\\nOne of the most common and simplest unix commands is `ls` which \\"lists\\" the contents of a directory.\\n\\n#### command\\n\\n```\\nls\\n```\\n\\nThis command `ls` works on its own, as a standalone **command**. Without any parameters this command will list the contents of the current folder, using an implied `.` directory.\\n\\n#### argument\\n\\n```\\nls .\\nls ~/code/some-repo-name\\n```\\n\\nIf you pass a command **argument** to this command, like the directory name `.` (current folder) or `~/code/some-repo-name`, it will list the contents of that directory instead.\\n\\nAn argument is anything to the right of a command that is not a flag. An argument can come before or after flags.\\n\\n#### Long flag\\nTo list additional files that are normally hidden (like `~/.bashrc`), you can use a flag on the `ls` command. `ls --all` is the **long flag** form. A long flag always uses a double dash, and it is always represented by multiple characters.\\n\\n```\\nls --all\\nls . --all\\n```\\n\\n#### Short flag\\n\\nThere is also a **short flag** form of this flag: `ls -a`. The `a` is short for `all` in this case. A short flag always uses a single dash, and it is always represented by a single letter.\\n\\n```\\nls -a\\nls . -a\\n```\\n\\nShort flags can **stack** too, so you don\'t need a separate dash for each one. Order does not matter for these, unless passing a flag argument.\\n\\n```\\nls -la\\n```\\n\\n#### Flag arguments\\nMany flags accept an **option**, which is a \\"flag argument\\" (as opposed to a \\"command argument\\"). In general a command\'s parameters can be in any order, but flags that accept options must have the option directly after the flag.\\n\\nFor an example, here the `-x` flag does not accept an option but the `-f` flag does. `archive.tar` is the option being passed to `-f`.\\n\\n```\\ntar -x -f archive.tar\\ntar -xf archive.tar\\n```\\n\\nA flag and its option can be separated by a space ` ` or an equals sign `=`. Interestingly, short flags (but not long flags) can even skip the space, although many people find it much easier to read with the space or equals sign.\\n\\nThese three are all valid and equivalent:\\n\\n```\\ntar -f archive.tar\\ntar -f=archive.tar\\ntar -farchive.tar\\n```\\n\\nLong flags must have a space or equals sign to separate the flag from its option.\\n\\n```\\ngit log --pretty=oneline\\ngit log --pretty oneline\\n```\\n\\n## Other Ways of Passing Data\\n\\nWe\'ve covered **parameters**, which are **arguments**, **short flags** and **long flags**. There are two other ways to pass data to a command: **environment variables** (\\"env vars\\"), or **standard input** (\\"stdin\\"). These won\'t be covered in this blog post.\\n\\n\\n## Designing a Command\\n\\nScenario: we want to design an oclif command that echos an input like \\"Casey\\", and returns \\"hi, Casey!\\". There are many ways the user could pass this in, and here we show an example of each type of input.\\n\\n### argument\\n\\n```\\ngreet-me Casey\\n```\\n\\n### short flag with argument\\n\\n```\\ngreet-me -n Casey\\ngreet-me -n=Casey\\ngreet-me -nCasey\\n```\\n\\n### long flag with argument\\n\\n```\\ngreet-me --name=Casey\\ngreet-me --name Casey\\n```\\n\\n### environment variable\\n\\n```\\nNAME=Casey greet-me\\n```\\n\\n### standard input\\n\\n```\\necho \\"Casey\\" | greet-me\\n```\\n\\n## Command ergonomics\\n\\n### Short flag vs long flag\\nMany CLI commands allow for both long flag and short flag forms. In the Heroku CLI every flag has at least a long flag form and roughly half of the flags also have a short flag form.\\n\\nThe long flag form is easier to read, but takes more characters to type. It is often most useful when you want someone to understand a particular command statement quickly and easily, such as in a README.\\n\\nThe short flag form is quicker to type, and is often better for frequently used commands. Short flags are especially useful when stacking short flags together.\\n\\n\\n\x3c!-- ## Did you mean?\\nIt is really easy to make a typo and use one dash instead of two, or vice versa. This \\"Long flag / short flag mismatch\\" is quite common. We hope that by catching these typos we will help you make fewer typos, save you from frustration, and speed up your development.\\n\\n`oclif` can now detect when you accidentally have the wrong number of dashes for a command, and suggest a change to the command.\\n\\n```\\nheroku config --s\\n> did you mean \\"heroku config -s\\"?\\n```\\n\\n```\\nheroku config -something-long\\n> did you mean \\"heroku config --something-long\\"?\\n```\\n\\n```\\nheroku config ---something-long\\n> did you mean to use FEWER DASHES? (something like this?)\\n```\\n\\nThis is an example of a \\"did you mean?\\" command, like this ruby plugin [did_you_mean](https://github.com/yuki24/did_you_mean).\\n--\x3e"},{"id":"/2018/03/20/introducing-oclif","metadata":{"permalink":"/blog/2018/03/20/introducing-oclif","source":"@site/blog/2018-03-20-introducing-oclif.md","title":"Introducing oclif","description":"Introducing oclif","date":"2018-03-20T00:00:00.000Z","formattedDate":"March 20, 2018","tags":[],"readingTime":0.285,"hasTruncateMarker":false,"authors":[{"name":"Jeff Dickey"}],"frontMatter":{"author":"Jeff Dickey","title":"Introducing oclif"},"prevItem":{"title":"CLI Flags Explained","permalink":"/blog/2019/02/20/cli-flags-explained"}},"content":"![Introducing oclif](/img/2018-03-20-introducing-oclif/header.png)\\n\\nCoding for the browser takes serious time. You need to deal with front-end JS, CSS, design, product, and a ton more. On the other hand, building for a CLI takes a fraction of the effort. This makes CLIs particularly great for prototyping out new functionality, offering admin/internal tools, or power-user functionality.\\n\\nRead More"}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1477],{10:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2022/01/12/announcing-oclif-v2","metadata":{"permalink":"/blog/2022/01/12/announcing-oclif-v2","source":"@site/blog/2022-01-12-announcing-oclif-v2.md","title":"Announcing oclif v2!","description":"Hello and happy new year! It\'s our great pleasure to announce that we have released oclif v2, which uses the new @oclif/core library! \ud83c\udf89","date":"2022-01-12T00:00:00.000Z","formattedDate":"January 12, 2022","tags":[],"readingTime":4.48,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Announcing oclif v2!"},"nextItem":{"title":"Introducing @oclif/core","permalink":"/blog/2021/03/01/introducing-oclif-core"}},"content":"Hello and happy new year! It\'s our great pleasure to announce that we have released oclif v2, which uses the new [@oclif/core](https://github.com/oclif/core) library! \ud83c\udf89\\n\\noclif v2 includes many changes that improve the experience of both creating and using an oclif CLI.\\n\\nGoing forward, we don\'t plan to make any updates to oclif v1 and its corresponding libraries, except for critical security fixes. See the [compatibility matrix](#compatibility-matrix) for a list of these libraries. In order to give developers time to migrate from v1 to v2, we\'re not completely dropping support yet. But at some point in the future we\'ll archive the v1 repositories and deprecate their versions on npm.\\n\\n## What\u2019s changing?\\n\\n### Repository Changes\\n\\nAll repositories under the [oclif org](https://github.com/oclif/) now use `main` as their primary branch and `oclif-v1` as the legacy branch. The `main` branch corresponds to oclif v2 and the `oclif-v1` branch to oclif v1. If you find any repos that don\u2019t have a `main` branch, you can safely assume that they\'re not used in oclif v2 and will be deprecated in the future.\\n\\n### Consolidating Tools & Libraries\\n\\nThe [`oclif-dev`](https://github.com/oclif/dev-cli) CLI has now been incorporated into [`oclif`](https://github.com/oclif/oclif). You now no longer need to install a separate package to manage your entire CLI\u2019s lifecycle.\\n\\nThe following libraries have been consolidated under [`@oclif/core`](https://github.com/oclif/core) and will be deprecated at some point in the future. Read the [migration guide](https://github.com/oclif/core/blob/main/MIGRATION.md) to learn how to update your CLI or plugin to use the new core library.\\n\\n* `@oclif/command`\\n* `@oclif/config`\\n* `@oclif/error`\\n* `@oclif/help`\\n* `@oclif/parser`\\n\\n### No more single vs multi command CLIs\\n\\nThere\'s only one \\"type\\" of oclif v2 CLI, but it can have as few or as many commands as a developer wants. As a result, there\u2019s only one command to generate CLIs, `oclif generate`, as opposed to the old `oclif single` and `oclif multi` commands.\\n\\n### Node > 12\\n\\nTo ensure oclif CLIs are as secure as possible, all v2 libraries and plugins support only Node 12 or higher as of now. Going forward, they\'ll support only Node Maintenance or higher, as defined by Node\'s release schedule here: https://nodejs.org/en/about/releases/.\\n\\n## What\u2019s new?\\n\\n### New example CLI\\n\\n[`oclif-hello-world`](https://github.com/oclif/hello-world/) is our new example repo. This is also the repo that\'s [used as a template](https://github.com/oclif/oclif/blob/edc6616e51/src/generators/cli.ts#L74) when running `oclif generate` to create a new CLI. This repo will always be able to be referenced as an example of what an oclif v2 CLI should look like.\\n\\n### Spaced commands\\n\\noclif CLIs can now use spaces, instead of colons, to separate topics and subcommands. To enable this feature, simply add `\u201ctopicSeparator\\": \\" \\"` to the oclif config in your package.json. See an example in our [example repo](https://github.com/oclif/hello-world/blob/main/package.json#L55).\\n\\n```\\n// Old commands that use :\\n$ mycli do:something\\n```\\n```\\n// New spaced commands\\n$ mycli do something\\n```\\n\\n> Note: Spaced commands are backwards compatible. So if you enable spaced commands for your CLI, users will still be able to use `:` as a separator. This ensures that any existing scripts don\'t break.\\n\\n### New Help Output\\n\\nWe\u2019ve revamped the way command help is outputted to the terminal, making it both easier to implement and easier to read. See the difference between the old help output on the left and the new help output on the right in the screenshots below.\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n
oclif v1oclif v2
\\n\\nNotice that there are new sections for flags and global flags, examples are displayed with better spacing, and there is a section at the bottom called Configuration Variables. This Configuration Variables section is not part of the new help by default. But we\'ve added support for custom help sections, which is what the `sf` CLI uses to create the new section. \\n\\n### Async Command Parsing\\n\\nWe\u2019ve also improved the performance of new CLIs by rewriting how commands are parsed on initialization. The [new parser](https://github.com/oclif/core/blob/main/src/parser/parse.ts) is asynchronous, which makes CLIs with a lot of commands or installed plugins much faster.\\n\\n## What\u2019s coming next?\\n\\nPart of our charter for the release of oclif v2 includes improving our engagement with the oclif community. We know that over the past couple of years we\u2019ve reduced our involvement, and a lot of issues and PRs have languished in limbo. Hopefully you\u2019ve already seen increased activity and responses from oclif maintainers recently, but if you haven\u2019t, please don\u2019t hesitate to ping us by tagging [@admins](https://github.com/orgs/oclif/teams/admins) in oclif repos.\\n\\nWe also want to start interviewing members of the oclif community to acquire feedback and prioritize the features and fixes you deem most important!\\n\\nBest,\\n\\nThe oclif team\\n\\n
\\n\\n### Reference material \\n\\n#### Migration Guide\\n\\nThis guide explains how to upgrade a CLI or plugin from the old oclif v1 libraries to the new `@oclif/core` library that oclif v2 uses.\\n\\nhttps://github.com/oclif/core/blob/main/MIGRATION.md\\n\\n#### Compatibility Matrix\\n\\nThe following matrix shows how the v1 libraries and plugins relate to the new v2 ones. Use this matrix as a guide to know what to drop and which versions to switch when upgrading your plugins and CLIs to v2.\\n\\n| | oclif \\"v1\\" | oclif \\"v2\\" |\\n| - | - | -|\\n| Utility CLIs | oclif@<2
@oclif/dev-cli@<2 | oclif@>=2\\n| Main packages | @oclif/command
@oclif/config
@oclif/errors
@oclif/parser
@oclif/plugin-help
| @oclif/core@>=1\\n| Node LTS | Node v8-14 | Node v12+ (at time of writing) |\\n| TypeScript | typescript@<4 | typescript@>=4 |\\n| Main plugins | @oclif/plugin-autocomplete@<1
@oclif/plugin-commands@<2
@oclif/plugin-help@<4
@oclif/plugin-not-found@<2
@oclif/plugin-plugins@<2
@oclif/plugin-update@<2
plugin-warn-if-update-available@<2
plugin-which@<2
| @oclif/plugin-autocomplete@>=1
@oclif/plugin-commands@>=2
@oclif/plugin-help@>=4
@oclif/plugin-not-found@>=2
@oclif/plugin-plugins@>=2
@oclif/plugin-update@>=2
@oclif/plugin-warn-if-update-available@>=2
@oclif/plugin-which@>=2
|"},{"id":"/2021/03/01/introducing-oclif-core","metadata":{"permalink":"/blog/2021/03/01/introducing-oclif-core","source":"@site/blog/2021-03-01-introducing-oclif-core.md","title":"Introducing @oclif/core","description":"Greetings!","date":"2021-03-01T00:00:00.000Z","formattedDate":"March 1, 2021","tags":[],"readingTime":2.18,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Introducing @oclif/core"},"prevItem":{"title":"Announcing oclif v2!","permalink":"/blog/2022/01/12/announcing-oclif-v2"},"nextItem":{"title":"oclif Summer Update","permalink":"/blog/2020/08/26/summer-update"}},"content":"Greetings!\\n\\nWe hope this blog post finds you well.\\n\\n### Introducing...\\n\\nWe are excited to announce the next iteration of the oclif project today: `@oclif/core`.\\n\\nWe have learned a lot in the last three years of developing oclif, developing on oclif and supporting millions of command runs a day via Heroku and Salesforce CLIs.\\n`@oclif/core` (\\"Core\\") simplifies the oclif development experience and introduces highly requested new features.\\n\\nCore combines the essential oclif packages into one \\"core\\" package, aptly named `@oclif/core`.\\n\\nCore also introduces:\\n- A default command option\\n- Colon or space command syntax\\n- Async command parsing\\n- Command piping to arguments\\n\\nWith the introduction of default command functionality, Core simplifies the oclif project and removes the notion of single or multi command CLIs. Core CLIs can have 1 or many commands.\\n\\nAlong with Core, we moved the oclif-dev CLI into the oclif CLI creating a single \\"utility\\" CLI. This CLI also introduces a new AWS S3 compatible publishing scheme.\\n\\n### What to expect in the near future\\n\\nCore is in pre-release beta and being actively developed for new internal Salesforce CLIs.\\n\\nMuch documentation needs to be written in the coming months including migration paths. Migration onto Core should be as painless as possible with many exports remaining entirely unchanged. Look for forthcoming blog posts and documentation on [oclif.io](https://oclif.io).\\n\\nEarly this summer, tentively June 1, we will release Core v1. Core\'s release will coincide with major bumps to many other oclif plugin packages. See the compatibility matrix below.\\n\\nAt Core\'s v1 release, the current \\"main\\" oclif packages (namely: command, config, errors & parser) will go into maintenance mode until Jan 2022. They will receive _only_ bug and security fixes and they remain compatible with current versions of the oclif and oclif-dev CLIs. Afterwhich, they will be archived.\\n\\nCompanioning Core, the next major release of the oclif CLI (literally `oclif@2`) will generate Core CLIs.\\n\\n### Going forward\\n\\nWe are excited to release Core! We invite you to poke around the [Core repo](https://github.com/oclif/core). It may appear to be a big change but Core keeps what you already enjoy about oclif while reducing development complexity, project dependencies, package coupling and bundle size and introduces many requested features previously too prickly to weave into the current oclif architecture.\\n\\nBest,\\n\\nThe oclif team\\n\\n#### Reference: Compatibility matrix\\n\\n| | oclif \\"v1\\" | oclif \\"Core\\" |\\n| - | - | -|\\n| Utility CLIs | oclif@<2
@oclif/dev-cli@<2 | oclif@>=2\\n| Main packages | @oclif/core@<2
@oclif/config@<2
@oclif/errors@<2
@oclif/parser@<4
@oclif/plugin-help@<4
| @oclif/core@>=1\\n| Node LTS | Node v8-14 | Node v12+ |\\n| TypeScript | typescript@<4 | typescript@>=4 |\\n| Main plugins | @oclif/plugin-autocomplete@<1
@oclif/plugin-commands@<2
@oclif/plugin-help@<4
@oclif/plugin-not-found@<2
@oclif/plugin-plugins@<2
@oclif/plugin-update@<2
plugin-warn-if-update-available@<2
plugin-which@<2
| @oclif/plugin-autocomplete@>=2
@oclif/plugin-commands@>=2
@oclif/plugin-help@>=4
@oclif/plugin-not-found@>=2
@oclif/plugin-plugins@>=2
@oclif/plugin-update@>=2
@oclif/plugin-warn-if-update-available@>=2
@oclif/plugin-which@>=2
|"},{"id":"/2020/08/26/summer-update","metadata":{"permalink":"/blog/2020/08/26/summer-update","source":"@site/blog/2020-08-26-summer-update.md","title":"oclif Summer Update","description":"Hello oclif developers! We hope you are all doing well.","date":"2020-08-26T00:00:00.000Z","formattedDate":"August 26, 2020","tags":[],"readingTime":1.355,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif Summer Update"},"prevItem":{"title":"Introducing @oclif/core","permalink":"/blog/2021/03/01/introducing-oclif-core"},"nextItem":{"title":"Pretty Printable Errors","permalink":"/blog/2020/07/01/pretty-printable-errors"}},"content":"Hello oclif developers! We hope you are all doing well.\\n\\nEarlier this year, we started our planning for oclifconf v2 and, like all conference, had to change course. We opted not to hold a virtual conference, however, we wanted to take some time to highlight a few oclif features shipped this year.\\n\\n## Feature: Help templating\\n\\nOne of the most requested features, help templating enables oclif developers to customize the help output for their CLI.\\n\\nRead [the announcement](/blog/introducing-custom-help-classes).\\n\\n## Feature: Custom error delegation\\n\\nThis feature both improved how oclif throws and handles errors and allows oclif developers to overwrite or interject in oclif\u2019s error handling.\\n\\nRead [the announcement](/blog/2020/07/01/pretty-printable-errors).\\n\\n## Feature: postrun hooks\\n\\nWe have added a new lifecycle event `postrun`. Your CLI can now run a hook after a command has ran.\\n\\nSee our [hook documentation](/docs/hooks).\\n\\n## Feature: Root index command\\n\\nPreviously, oclif would display CLI help if only the binary name with no command ID was invoked, oclif now supports a \\"root index\\" command. If present, a command defined at `src/commands/index.ts` will be run if no command ID is found.\\n\\n## 1 million weekly downloads\\n\\nWhile exact oclif usage metrics are hard to pin down, we use npm download statistics of oclif packages as a rough approximation. Earlier this year, oclif\'s command package hit 1 million weekly downloads for the first time!\\n\\n\\nThis year has been presented its challenges on everyone. We want to thank you, oclif developers, whom have taken the time to use and improve the oclif project. We look forward to seeing you all - in person - in the future!\\n\\nAll our best,\\n\\nThe oclif team"},{"id":"/2020/07/01/pretty-printable-errors","metadata":{"permalink":"/blog/2020/07/01/pretty-printable-errors","source":"@site/blog/2020-07-01-pretty-printable-errors.md","title":"Pretty Printable Errors","description":"Often CLIs are used as handy tools and when things go wrong it\u2019s useful to have additional context. In oclif we have added a couple of additional properties that can show extra context to the users when an error is displayed. The code, ref and suggestions will now be displayed if they are included. This will work with an existing oclif CLI by adding the latest @oclif/errors and @oclif/core to the CLI\'s package.json dependencies.","date":"2020-07-01T00:00:00.000Z","formattedDate":"July 1, 2020","tags":[],"readingTime":0.995,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Pretty Printable Errors"},"prevItem":{"title":"oclif Summer Update","permalink":"/blog/2020/08/26/summer-update"},"nextItem":{"title":"Customizing Help in oclif","permalink":"/blog/2020/05/05/introducing-custom-help-classes"}},"content":"Often CLIs are used as handy tools and when things go wrong it\u2019s useful to have additional context. In oclif we have added a couple of additional properties that can show extra context to the users when an error is displayed. The `code`, `ref` and `suggestions` will now be displayed if they are included. This will work with an existing oclif CLI by adding the latest @oclif/errors and @oclif/core to the CLI\'s package.json dependencies.\\n\\nFor example, using `this.error` with the additional properties:\\n```js\\nclass TestError extends Command {\\n async run() {\\n this.error(\\"An error has occurred!\\", {\\n code: \\"OCLIF_ERR\\",\\n ref: \\"https://oclif.io/docs/commands#thiserrormessage-string--error-options-code-string-exit-number\\",\\n suggestions: [\\"Use these extra properties to provide additional context\\"],\\n })\\n }\\n}\\n```\\n\\nwould result with the following output:\\n```text\\n\u203a Error: An error has occurred!\\n\u203a Code: OCLIF_ERR\\n\u203a Try this: Use these extra properties to provide additional context\\n\u203a Reference: https://oclif.io/docs/commands#thiserrormessage-string--error-options-code-string-exit-number\\n```\\n\\nIf these properties are not provided then nothing changes and the CLI will continue to display the single error message output as it did before. Additionally, as part of this exercise we\u2019ve added documentation around [Error Handling in oclif](/docs/error_handling) which should come in handy if the need arises to extend oclif\u2019s default handling of errors."},{"id":"/2020/05/05/introducing-custom-help-classes","metadata":{"permalink":"/blog/2020/05/05/introducing-custom-help-classes","source":"@site/blog/2020-05-05-introducing-custom-help-classes.md","title":"Customizing Help in oclif","description":"Out of the box oclif provides a great help experience for CLIs.","date":"2020-05-05T00:00:00.000Z","formattedDate":"May 5, 2020","tags":[],"readingTime":1.67,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"Customizing Help in oclif"},"prevItem":{"title":"Pretty Printable Errors","permalink":"/blog/2020/07/01/pretty-printable-errors"},"nextItem":{"title":"oclif TSLint to ESLint Migration","permalink":"/blog/2019/12/05/oclif-eslint-migration"}},"content":"Out of the box oclif provides a great help experience for CLIs.\\n\\nBut what if, as an oclif developer, you want to customize some or all of the output?\\n\\nYou can now customize your CLI\'s help output by implementing the `HelpBase` abstract class.\\n\\n## Getting started with custom help\\n\\nIf you have not done so yet, update `@oclif/core`.\\n\\n\\n```\\n$ yarn add --latest @oclif/core\\n```\\n\\nTo get started, first define the filepath to your help class in oclif\'s config in package.json. This is a relative path to the help class, without a file extension.\\n\\nFor this example, the help class will be created in a file at \\"[project root]/src/help.ts\\".\\n\\n```\\n{\\n // ...\\n \\"oclif\\": {\\n \\"helpClass\\": \\"./lib/help\\"\\n // ...\\n }\\n // ...\\n}\\n```\\n\\nFrom here there are two paths, implement the `HelpBase` abstract class yourself or overwrite the parts of the default `Help` class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both in the new [Help Classes docs](../../../../docs/help_classes).\\n\\n\\n## Separating TOPICS & COMMANDS in the new default `Help` class\\n\\nPreviously, topics and child commands were listed in help output under a single list heading called \\"COMMANDS\\". But we found this can be slightly confusing. Some topics are commands also (a.k.a. topic-commands) while others are simply organizational namespacing (and when ran just show their help).\\n\\nThe new default `Help` class splits the list of children into distinct lists of \\"TOPICS\\" and \\"COMMANDS\\", with the possibility of an item appearing in both if it a topic-command. This makes it clearer what is expected to be ran - \\"COMMANDS\\" - and what is providing structure - \\"TOPICS\\" - when looking at the help output.\\n\\n```\\nVERSION\\n plugin-help-example/0.0.0 darwin-x64 node-v12.12.0\\n\\nUSAGE\\n $ plugin-help-example [COMMAND]\\n\\nTOPICS\\n topic this is a topic and has child topics or commands\\n\\nCOMMANDS\\n hello describe the command here\\n help display help for plugin-help-example\\n```\\n\\nWe look forward to seeing what custom help features you implement in your oclif CLIs with this new feature!"},{"id":"/2019/12/05/oclif-eslint-migration","metadata":{"permalink":"/blog/2019/12/05/oclif-eslint-migration","source":"@site/blog/2019-12-05-oclif-eslint-migration.md","title":"oclif TSLint to ESLint Migration","description":"Back in February of this year, plans were announced to deprecate TSLint in favor of ESLint. TSLint\'s goal has become to work toward a \u201cunified developer experience\u201d by supporting ESLint development going forward.","date":"2019-12-05T00:00:00.000Z","formattedDate":"December 5, 2019","tags":[],"readingTime":2.18,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif TSLint to ESLint Migration"},"prevItem":{"title":"Customizing Help in oclif","permalink":"/blog/2020/05/05/introducing-custom-help-classes"},"nextItem":{"title":"oclif\'s Current Node Support","permalink":"/blog/2019/10/31/oclif-node-updates"}},"content":"Back in February of this year, plans were announced to [deprecate TSLint](https://github.com/palantir/tslint/issues/4534) in favor of ESLint. TSLint\'s goal has become to work toward a \u201cunified developer experience\u201d by supporting ESLint development going forward.\\n\\n\\n\\n## What has changed in oclif\\n\\nTo keep inline with the community, oclif has transitioned to ESLint for all our core libraries as well as all our official plugins.\\n\\nStarting in v1.15.x, oclif will now optionally generate projects with ESLint for both TypeScript and JavaScript CLI\u2019s.\\n\\nESLint does require Node to be on stable LTS version, at the time of writing, Node 8.10.x, Node 10.13.x & Node 12.x.x.\\n\\n## How does this affect you\\n\\nExisting CLI\u2019s are unchanged, but any newly generated CLI\'s will only give the option of using ESLint. If you are running tslint in your CLI, we recommend you switch to ESLint as well.\\n\\nIn migrating our projects we took the following steps (for an example of these changes see this [pull request](https://github.com/oclif/githubcli/pull/10)).\\n\\n1. Install eslint\\n\\n `$ yarn add eslint eslint-config-oclif eslint-config-oclif-typescript --dev`\\n2. Add eslint related files\\n```shell\\n$ echo \'{\\n \\"extends\\": [\\n \\"oclif\\",\\n \\"oclif-typescript\\"\\n ],\\n \\"rules\\": {\\n }\\n}\' > .eslintrc\\n```\\n3. Remove tslint and related packages\\n\\n `$ yarn remove @oclif/tslint tslint`\\n4. Remove tslint related configuration files\\n\\n `$ rm tslint.json`\\n5. Change lint script in our package.json from something like:\\n\\n `\\"lint\\": \\"tsc -p test --noEmit && tslint -p test -t stylish\\"`\\n \\n to\\n \\n `\\"lint\\": \\"eslint . --ext .ts --config .eslintrc\\"`\\n\\nTo preserve the test compile (tsc -p test --noEmit) we also made the following updates to our scripts:\\n\\n`\\"pretest\\": \\"tsc -p test --noEmit\\"`\\n\\nIn some cases we had our posttest duplicating the same steps as our lint script so it\u2019s cleaner to have it reference the lint job directly with:\\n\\n`\\"posttest\\": \\"yarn lint\\"`\\n\\n\\n6. Run `yarn lint --fix`. This attempts to auto-fix any linting violations automatically. In the case an auto-fix isn\u2019t available it should be fixed manually or ignored (see the [eslint configuration doc](https://eslint.org/docs/user-guide/configuring) for more information) \\n7. Do a search in the codebase for `tslint` and remove any unnecessary tslint disabling comments, like: \\n```javascript\\n/* tslint:disable:object-literal-sort-keys */\\n```\\n\\n\\nIf you are on a version of Node that is not supported by ESLint, you will also need to update your Node engine. ESLint supports Node 8, 10, and 12 so you should upgrade to the most recent Node version compatible with your CLI and also supported by ESLint (see ESLint\'s [Installation and Usage](https://www.npmjs.com/package/eslint#installation-and-usage) instructions).\\n\\n## When will this take effect\\n\\nThese changes have taken effect in oclif v1.15.1. When you generate a new CLI or plugin it will now contain configuration for ESLint instead of TSLint."},{"id":"/2019/10/31/oclif-node-updates","metadata":{"permalink":"/blog/2019/10/31/oclif-node-updates","source":"@site/blog/2019-10-31-oclif-node-updates.md","title":"oclif\'s Current Node Support","description":"To maintain a healthy project trajectory, oclif follows and supports Node Active LTS release, currently Node 10 & Node 12. This means ensuring that oclif continues to play nice with coming Active LTS Node versions and other packages in the ecosystem. Moving forward also means leaving older versions behind. Starting in 2020, Node will stop maintaining Node 8 and it is our intent at that time to also follow suit. Let\u2019s take a look at a few ways we will be supporting these changes.","date":"2019-10-31T00:00:00.000Z","formattedDate":"October 31, 2019","tags":[],"readingTime":2.4,"hasTruncateMarker":false,"authors":[],"frontMatter":{"title":"oclif\'s Current Node Support"},"prevItem":{"title":"oclif TSLint to ESLint Migration","permalink":"/blog/2019/12/05/oclif-eslint-migration"},"nextItem":{"title":"CLI Flags Explained","permalink":"/blog/2019/02/20/cli-flags-explained"}},"content":"To maintain a healthy project trajectory, oclif follows and supports [Node Active LTS release](https://nodejs.org/en/about/releases/), currently Node 10 & Node 12. This means ensuring that oclif continues to play nice with coming Active LTS Node versions and other packages in the ecosystem. Moving forward also means leaving older versions behind. Starting in 2020, Node will stop maintaining [Node 8](https://github.com/nodejs/Release#release-schedule) and it is our intent at that time to also follow suit. Let\u2019s take a look at a few ways we will be supporting these changes.\\n\\n## CI Environments\\n\\nCLIs created with the oclif cli going forward will be generated with a CircleCI configuration with Node 10 & 12 and an Appveyor configuration using Node 10. We have also added Node latest to CircleCi to be an early warning detection against coming Node changes (Node latest is managed by CircleCI).\\n\\nWe have already updated every oclif repo\'s CI configs to reflect this.\\n\\nIf your existing CLI uses either Appveyor or CircleCI you can update your config files also, like so:\\n\\n### .circleci/config.yml\\n\\nYour CircleCI config should contain a `node-latest` job, aliased as `test`. From this, there should be two extensions of this job for the Active LTS Node versions, Node 10 and Node 12.\\n\\n```\\n node-10:\\n <<: *node-latest\\n docker:\\n - image: node:10\\n node-12:\\n <<: *node-latest\\n docker:\\n - image: node:12\\n```\\n\\nNotice that these declarations only change the Docker Node images used to run that job.\\n\\nAdditionally, the jobs listed within workflows must also be updated to reflect our changes in configuration:\\n\\n```\\n jobs:\\n - node-latest\\n - node-10\\n - node-12\\n```\\n\\n### appveyor.yml\\n\\nFor appveyor we are currently only testing the oldest Active LTS Node version, Node 10. Update the `nodejs_version` proppert in your appveyor.yml file to reflect this.\\n\\n```\\nenvironment:\\n nodejs_version: \\"10\\"\\n```\\n\\n\\n## Deprecating Node 8 & Updating packge.json engines\\n\\nIn Jan 2020, Node will end its Node 8 maintenance. We will follow suit by setting the package.json engine property in oclif packages to `>=10` and bumping the package\'s major versions.\\n\\nDepending on how you ship your CLI you may wish to also bump the engines version in your CLI\'s package.json. You can read more about the implications of the engines property configuration in the [npm documentation](https://docs.npmjs.com/files/package.json#engines).\\n\\nAlso consider distributing your CLI with [its own Node version](https://oclif.io/docs/releasing#standalone-tarballs).\\n\\n## Packaged Node Version\\n\\nWhen using dev-cli to pack your CLI it will use the Node version as specified in your package.json under the `oclif.update.node.version` property. This value should reflect an Active LTS Node version (dev-cli does not currently enforce versions).\\n\\n## Supporting the future\\n\\nAs a community we may discover bumps along the way as we upgrade. If you notice something related to oclif please feel free to open an issue or submit a pull request under the relevant oclif package within [the org](https://github.com/oclif).\\n\\nWe look forward to using the latest from Node and the community and keeping oclif healthy along the way."},{"id":"/2019/02/20/cli-flags-explained","metadata":{"permalink":"/blog/2019/02/20/cli-flags-explained","source":"@site/blog/2019-02-20-cli-flags-explained.md","title":"CLI Flags Explained","description":"oclif makes it easy to create a command line interface (CLI) in node. Most commands have parameters \u2014 also known as \\"flags\\", \\"args\\", and sometimes \\"options\\". This blog post explains what these parameters are and when to use them. We also have a new feature that makes it easier for users to detect typos when using parameters.","date":"2019-02-20T00:00:00.000Z","formattedDate":"February 20, 2019","tags":[],"readingTime":4.925,"hasTruncateMarker":false,"authors":[{"name":"Casey Watts and Jeff Dickey"}],"frontMatter":{"author":"Casey Watts and Jeff Dickey","title":"CLI Flags Explained"},"prevItem":{"title":"oclif\'s Current Node Support","permalink":"/blog/2019/10/31/oclif-node-updates"},"nextItem":{"title":"Introducing oclif","permalink":"/blog/2018/03/20/introducing-oclif"}},"content":"`oclif` makes it easy to create a command line interface (CLI) in node. Most commands have **parameters** \u2014 also known as \\"flags\\", \\"args\\", and sometimes \\"options\\". This blog post explains what these parameters are and when to use them. We also have a new feature that makes it easier for users to detect typos when using parameters.\\n\\n_Note the following describes GNU-style flags. Not all CLIs follow this convention, but it is the most commonly used._\\n\\n## Parts of Speech\\n\\nAny command line interface command has a few standard \\"parts of speech\\". As a user of CLI tools, knowing these parts of speech can help you make fewer typos. It can also help you understand complex commands other people share with you more quickly. If you are designing a CLI tool it is even more important to understand these parts of speech, so you can come up with the most ergonomic interface for your users.\\n\x3c!-- DIAGRAM OF PARTS OF SPEECH EXAMPLE --\x3e\\n\\nOf the many ways you can pass data to a CLI command, three of them are **parameters** that are always to the \\"right\\" of the command. The three types of parameters are **argument**, **short flag**, and **long flag**.\\n\\n### Example `ls`\\nOne of the most common and simplest unix commands is `ls` which \\"lists\\" the contents of a directory.\\n\\n#### command\\n\\n```\\nls\\n```\\n\\nThis command `ls` works on its own, as a standalone **command**. Without any parameters this command will list the contents of the current folder, using an implied `.` directory.\\n\\n#### argument\\n\\n```\\nls .\\nls ~/code/some-repo-name\\n```\\n\\nIf you pass a command **argument** to this command, like the directory name `.` (current folder) or `~/code/some-repo-name`, it will list the contents of that directory instead.\\n\\nAn argument is anything to the right of a command that is not a flag. An argument can come before or after flags.\\n\\n#### Long flag\\nTo list additional files that are normally hidden (like `~/.bashrc`), you can use a flag on the `ls` command. `ls --all` is the **long flag** form. A long flag always uses a double dash, and it is always represented by multiple characters.\\n\\n```\\nls --all\\nls . --all\\n```\\n\\n#### Short flag\\n\\nThere is also a **short flag** form of this flag: `ls -a`. The `a` is short for `all` in this case. A short flag always uses a single dash, and it is always represented by a single letter.\\n\\n```\\nls -a\\nls . -a\\n```\\n\\nShort flags can **stack** too, so you don\'t need a separate dash for each one. Order does not matter for these, unless passing a flag argument.\\n\\n```\\nls -la\\n```\\n\\n#### Flag arguments\\nMany flags accept an **option**, which is a \\"flag argument\\" (as opposed to a \\"command argument\\"). In general a command\'s parameters can be in any order, but flags that accept options must have the option directly after the flag.\\n\\nFor an example, here the `-x` flag does not accept an option but the `-f` flag does. `archive.tar` is the option being passed to `-f`.\\n\\n```\\ntar -x -f archive.tar\\ntar -xf archive.tar\\n```\\n\\nA flag and its option can be separated by a space ` ` or an equals sign `=`. Interestingly, short flags (but not long flags) can even skip the space, although many people find it much easier to read with the space or equals sign.\\n\\nThese three are all valid and equivalent:\\n\\n```\\ntar -f archive.tar\\ntar -f=archive.tar\\ntar -farchive.tar\\n```\\n\\nLong flags must have a space or equals sign to separate the flag from its option.\\n\\n```\\ngit log --pretty=oneline\\ngit log --pretty oneline\\n```\\n\\n## Other Ways of Passing Data\\n\\nWe\'ve covered **parameters**, which are **arguments**, **short flags** and **long flags**. There are two other ways to pass data to a command: **environment variables** (\\"env vars\\"), or **standard input** (\\"stdin\\"). These won\'t be covered in this blog post.\\n\\n\\n## Designing a Command\\n\\nScenario: we want to design an oclif command that echos an input like \\"Casey\\", and returns \\"hi, Casey!\\". There are many ways the user could pass this in, and here we show an example of each type of input.\\n\\n### argument\\n\\n```\\ngreet-me Casey\\n```\\n\\n### short flag with argument\\n\\n```\\ngreet-me -n Casey\\ngreet-me -n=Casey\\ngreet-me -nCasey\\n```\\n\\n### long flag with argument\\n\\n```\\ngreet-me --name=Casey\\ngreet-me --name Casey\\n```\\n\\n### environment variable\\n\\n```\\nNAME=Casey greet-me\\n```\\n\\n### standard input\\n\\n```\\necho \\"Casey\\" | greet-me\\n```\\n\\n## Command ergonomics\\n\\n### Short flag vs long flag\\nMany CLI commands allow for both long flag and short flag forms. In the Heroku CLI every flag has at least a long flag form and roughly half of the flags also have a short flag form.\\n\\nThe long flag form is easier to read, but takes more characters to type. It is often most useful when you want someone to understand a particular command statement quickly and easily, such as in a README.\\n\\nThe short flag form is quicker to type, and is often better for frequently used commands. Short flags are especially useful when stacking short flags together.\\n\\n\\n\x3c!-- ## Did you mean?\\nIt is really easy to make a typo and use one dash instead of two, or vice versa. This \\"Long flag / short flag mismatch\\" is quite common. We hope that by catching these typos we will help you make fewer typos, save you from frustration, and speed up your development.\\n\\n`oclif` can now detect when you accidentally have the wrong number of dashes for a command, and suggest a change to the command.\\n\\n```\\nheroku config --s\\n> did you mean \\"heroku config -s\\"?\\n```\\n\\n```\\nheroku config -something-long\\n> did you mean \\"heroku config --something-long\\"?\\n```\\n\\n```\\nheroku config ---something-long\\n> did you mean to use FEWER DASHES? (something like this?)\\n```\\n\\nThis is an example of a \\"did you mean?\\" command, like this ruby plugin [did_you_mean](https://github.com/yuki24/did_you_mean).\\n--\x3e"},{"id":"/2018/03/20/introducing-oclif","metadata":{"permalink":"/blog/2018/03/20/introducing-oclif","source":"@site/blog/2018-03-20-introducing-oclif.md","title":"Introducing oclif","description":"Introducing oclif","date":"2018-03-20T00:00:00.000Z","formattedDate":"March 20, 2018","tags":[],"readingTime":0.285,"hasTruncateMarker":false,"authors":[{"name":"Jeff Dickey"}],"frontMatter":{"author":"Jeff Dickey","title":"Introducing oclif"},"prevItem":{"title":"CLI Flags Explained","permalink":"/blog/2019/02/20/cli-flags-explained"}},"content":"![Introducing oclif](/img/2018-03-20-introducing-oclif/header.png)\\n\\nCoding for the browser takes serious time. You need to deal with front-end JS, CSS, design, product, and a ton more. On the other hand, building for a CLI takes a fraction of the effort. This makes CLIs particularly great for prototyping out new functionality, offering admin/internal tools, or power-user functionality.\\n\\nRead More"}]}')}}]); \ No newline at end of file diff --git a/assets/js/b3cc73c6.e528833c.js b/assets/js/b3cc73c6.d2977a60.js similarity index 99% rename from assets/js/b3cc73c6.e528833c.js rename to assets/js/b3cc73c6.d2977a60.js index fc9fb510..62b8b230 100644 --- a/assets/js/b3cc73c6.e528833c.js +++ b/assets/js/b3cc73c6.d2977a60.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9638],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>m});var a=o(7294);function r(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function n(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,a)}return o}function i(e){for(var t=1;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var o=e.components,r=e.mdxType,n=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(o),f=r,m=p["".concat(l,".").concat(f)]||p[f]||d[f]||n;return o?a.createElement(m,i(i({ref:t},u),{},{components:o})):a.createElement(m,i({ref:t},u))}));function m(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var n=o.length,i=new Array(n);i[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{o.r(t),o.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var a=o(7462),r=o(3366),n=(o(7294),o(3905)),i=["components"],s={title:"How We Work"},l=void 0,c={unversionedId:"how_we_work",id:"how_we_work",title:"How We Work",description:"oclif is an open-source project built and maintained by Salesforce and an essential component of Salesforce's developer experiences, powering millions of users' CLIs a day via the Salesforce CLI, the Heroku CLI and others.",source:"@site/../docs/how_we_work.md",sourceDirName:".",slug:"/how_we_work",permalink:"/docs/how_we_work",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/how_we_work.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"How We Work"},sidebar:"docs",previous:{title:"Related Repositories",permalink:"/docs/related_repos"},next:{title:"Feedback",permalink:"/docs/feedback"}},u={},p=[{value:"Code of Conduct & Community Guidelines",id:"code-of-conduct--community-guidelines",level:2},{value:"Work Tracking",id:"work-tracking",level:2},{value:"Issues",id:"issues",level:2},{value:"Pull Requests",id:"pull-requests",level:2},{value:"Deprecations",id:"deprecations",level:2},{value:"Blog Posts",id:"blog-posts",level:2},{value:"Feedback",id:"feedback",level:2},{value:"Updates to How We Work",id:"updates-to-how-we-work",level:2}],d={toc:p},f="wrapper";function m(e){var t=e.components,o=(0,r.Z)(e,i);return(0,n.kt)(f,(0,a.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"oclif is an open-source project built and maintained by Salesforce and an essential component of Salesforce's developer experiences, powering millions of users' CLIs a day via the Salesforce CLI, the Heroku CLI and ",(0,n.kt)("a",{parentName:"p",href:"https://www.npmjs.com/browse/depended/@oclif/core"},"others"),"."),(0,n.kt)("p",null,"As an open-source project, ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/oclif"},"oclif repos live on GitHub")," and are published to ",(0,n.kt)("a",{parentName:"p",href:"https://www.npmjs.com/search?q=oclif"},"npmjs.com"),"."),(0,n.kt)("h2",{id:"code-of-conduct--community-guidelines"},"Code of Conduct & Community Guidelines"),(0,n.kt)("p",null,"We are thrilled to offer oclif as open-source. As such, please review our project ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/salesforce/oss-template/blob/master/CODE_OF_CONDUCT.md"},"Code of Conduct"),". If you have any questions or concerns, please ",(0,n.kt)("a",{parentName:"p",href:"/docs/feedback"},"contact us"),"."),(0,n.kt)("h2",{id:"work-tracking"},"Work Tracking"),(0,n.kt)("p",null,"We use a ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/orgs/oclif/projects/1"},"GitHub Project board")," to manage our work across all oclif repos. This board is used kanban style, in which, cards (i.e. work items) move left to right as they progress towards \u201cDone\u201d and higher priority cards sit towards the top of the columns, with lower priority cards sitting further below."),(0,n.kt)("h2",{id:"issues"},"Issues"),(0,n.kt)("p",null,"Issues are made in their corresponding repo as appropriate. If you are unsure which repo an issue might belong to, make an ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/oclif/oclif/issues"},"issue in the oclif repo"),"."),(0,n.kt)("p",null,"We triage issues as we can, usually with a week of when it was created (unfortunately, we can make no commitment to when an issue will be triaged)."),(0,n.kt)("p",null,"Issues triaged by an our team will be marked with one of the following labels :"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u201cbug\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cenhancement\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cdocs\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cwont-fix\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cinvalid\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cduplicate\u201d")),(0,n.kt)("p",null,"An issue will be considered stale after a month has passed with no further feedback or input from the author after input from an oclif team member. Stale issues will be notified with a comment of its stale state and any actions needed to take to keep it alive."),(0,n.kt)("p",null,"An issue will be closed if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"It has been fixed via a PR"),(0,n.kt)("li",{parentName:"ul"},"Has a \u201cwont-fix\u201d, \u201cinvalid\u201d or \u201cduplicate\u201d label"),(0,n.kt)("li",{parentName:"ul"},"A week has passed after a stale issue notification has been posted with no further feedback or input from the author")),(0,n.kt)("h2",{id:"pull-requests"},"Pull Requests"),(0,n.kt)("p",null,"We review repo PRs as we can, usually with two weeks of when it was created (unfortunately, we can make no commitment to when a PR will be reviewed)."),(0,n.kt)("p",null,"PRs reviewers may seek additional changes or clarifying input from the author as appropriate."),(0,n.kt)("p",null,"Note: It is often more conducive to first open an issue and solicit feedback on possible solutions for your PR. We hate to see PR\u2019s we don\u2019t end up accepting and this helps to avoid that!"),(0,n.kt)("p",null,"A PR will be considered stale after a month has passed with no further feedback or input from the author after input from an oclif team member. Stale PRs will be notified with a comment of its stale state and any actions needed to take to keep it alive."),(0,n.kt)("p",null,"A PR will be closed if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"It has been merged"),(0,n.kt)("li",{parentName:"ul"},"After a dialogue with the author informing them why the PR cannot be accepted"),(0,n.kt)("li",{parentName:"ul"},"A week has passed after a stale PR notification has been posted with no further feedback or input from the author")),(0,n.kt)("h2",{id:"deprecations"},"Deprecations"),(0,n.kt)("p",null,"oclif packages follow semantic versioning and therefore only deprecate features in new major version releases."),(0,n.kt)("p",null,"In the exceptional case a deprecation needs to happen outside a new major version, we will notify users via our blog or, as appropriate, with deprecation warnings in the tooling itself."),(0,n.kt)("h2",{id:"blog-posts"},"Blog Posts"),(0,n.kt)("p",null,"We aim to announce most features via ",(0,n.kt)("a",{parentName:"p",href:"/blog"},"our blog"),". Be sure to check back regularly to see new announcements!"),(0,n.kt)("h2",{id:"feedback"},"Feedback"),(0,n.kt)("p",null,"See our ",(0,n.kt)("a",{parentName:"p",href:"/docs/feedback"},"Feedback page"),"."),(0,n.kt)("h2",{id:"updates-to-how-we-work"},"Updates to How We Work"),(0,n.kt)("p",null,"Please check back periodically to review any updates to this page."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9638],{3905:(e,t,o)=>{o.d(t,{Zo:()=>u,kt:()=>m});var a=o(7294);function r(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function n(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,a)}return o}function i(e){for(var t=1;t=0||(r[o]=e[o]);return r}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(r[o]=e[o])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):i(i({},t),e)),o},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var o=e.components,r=e.mdxType,n=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(o),f=r,m=p["".concat(l,".").concat(f)]||p[f]||d[f]||n;return o?a.createElement(m,i(i({ref:t},u),{},{components:o})):a.createElement(m,i({ref:t},u))}));function m(e,t){var o=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var n=o.length,i=new Array(n);i[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{o.r(t),o.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var a=o(7462),r=o(3366),n=(o(7294),o(3905)),i=["components"],s={title:"How We Work"},l=void 0,c={unversionedId:"how_we_work",id:"how_we_work",title:"How We Work",description:"oclif is an open-source project built and maintained by Salesforce and an essential component of Salesforce's developer experiences, powering millions of users' CLIs a day via the Salesforce CLI, the Heroku CLI and others.",source:"@site/../docs/how_we_work.md",sourceDirName:".",slug:"/how_we_work",permalink:"/docs/how_we_work",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/how_we_work.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"How We Work"},sidebar:"docs",previous:{title:"Related Repositories",permalink:"/docs/related_repos"},next:{title:"Feedback",permalink:"/docs/feedback"}},u={},p=[{value:"Code of Conduct & Community Guidelines",id:"code-of-conduct--community-guidelines",level:2},{value:"Work Tracking",id:"work-tracking",level:2},{value:"Issues",id:"issues",level:2},{value:"Pull Requests",id:"pull-requests",level:2},{value:"Deprecations",id:"deprecations",level:2},{value:"Blog Posts",id:"blog-posts",level:2},{value:"Feedback",id:"feedback",level:2},{value:"Updates to How We Work",id:"updates-to-how-we-work",level:2}],d={toc:p},f="wrapper";function m(e){var t=e.components,o=(0,r.Z)(e,i);return(0,n.kt)(f,(0,a.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"oclif is an open-source project built and maintained by Salesforce and an essential component of Salesforce's developer experiences, powering millions of users' CLIs a day via the Salesforce CLI, the Heroku CLI and ",(0,n.kt)("a",{parentName:"p",href:"https://www.npmjs.com/browse/depended/@oclif/core"},"others"),"."),(0,n.kt)("p",null,"As an open-source project, ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/oclif"},"oclif repos live on GitHub")," and are published to ",(0,n.kt)("a",{parentName:"p",href:"https://www.npmjs.com/search?q=oclif"},"npmjs.com"),"."),(0,n.kt)("h2",{id:"code-of-conduct--community-guidelines"},"Code of Conduct & Community Guidelines"),(0,n.kt)("p",null,"We are thrilled to offer oclif as open-source. As such, please review our project ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/salesforce/oss-template/blob/master/CODE_OF_CONDUCT.md"},"Code of Conduct"),". If you have any questions or concerns, please ",(0,n.kt)("a",{parentName:"p",href:"/docs/feedback"},"contact us"),"."),(0,n.kt)("h2",{id:"work-tracking"},"Work Tracking"),(0,n.kt)("p",null,"We use a ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/orgs/oclif/projects/1"},"GitHub Project board")," to manage our work across all oclif repos. This board is used kanban style, in which, cards (i.e. work items) move left to right as they progress towards \u201cDone\u201d and higher priority cards sit towards the top of the columns, with lower priority cards sitting further below."),(0,n.kt)("h2",{id:"issues"},"Issues"),(0,n.kt)("p",null,"Issues are made in their corresponding repo as appropriate. If you are unsure which repo an issue might belong to, make an ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/oclif/oclif/issues"},"issue in the oclif repo"),"."),(0,n.kt)("p",null,"We triage issues as we can, usually with a week of when it was created (unfortunately, we can make no commitment to when an issue will be triaged)."),(0,n.kt)("p",null,"Issues triaged by an our team will be marked with one of the following labels :"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u201cbug\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cenhancement\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cdocs\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cwont-fix\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cinvalid\u201d"),(0,n.kt)("li",{parentName:"ul"},"\u201cduplicate\u201d")),(0,n.kt)("p",null,"An issue will be considered stale after a month has passed with no further feedback or input from the author after input from an oclif team member. Stale issues will be notified with a comment of its stale state and any actions needed to take to keep it alive."),(0,n.kt)("p",null,"An issue will be closed if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"It has been fixed via a PR"),(0,n.kt)("li",{parentName:"ul"},"Has a \u201cwont-fix\u201d, \u201cinvalid\u201d or \u201cduplicate\u201d label"),(0,n.kt)("li",{parentName:"ul"},"A week has passed after a stale issue notification has been posted with no further feedback or input from the author")),(0,n.kt)("h2",{id:"pull-requests"},"Pull Requests"),(0,n.kt)("p",null,"We review repo PRs as we can, usually with two weeks of when it was created (unfortunately, we can make no commitment to when a PR will be reviewed)."),(0,n.kt)("p",null,"PRs reviewers may seek additional changes or clarifying input from the author as appropriate."),(0,n.kt)("p",null,"Note: It is often more conducive to first open an issue and solicit feedback on possible solutions for your PR. We hate to see PR\u2019s we don\u2019t end up accepting and this helps to avoid that!"),(0,n.kt)("p",null,"A PR will be considered stale after a month has passed with no further feedback or input from the author after input from an oclif team member. Stale PRs will be notified with a comment of its stale state and any actions needed to take to keep it alive."),(0,n.kt)("p",null,"A PR will be closed if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"It has been merged"),(0,n.kt)("li",{parentName:"ul"},"After a dialogue with the author informing them why the PR cannot be accepted"),(0,n.kt)("li",{parentName:"ul"},"A week has passed after a stale PR notification has been posted with no further feedback or input from the author")),(0,n.kt)("h2",{id:"deprecations"},"Deprecations"),(0,n.kt)("p",null,"oclif packages follow semantic versioning and therefore only deprecate features in new major version releases."),(0,n.kt)("p",null,"In the exceptional case a deprecation needs to happen outside a new major version, we will notify users via our blog or, as appropriate, with deprecation warnings in the tooling itself."),(0,n.kt)("h2",{id:"blog-posts"},"Blog Posts"),(0,n.kt)("p",null,"We aim to announce most features via ",(0,n.kt)("a",{parentName:"p",href:"/blog"},"our blog"),". Be sure to check back regularly to see new announcements!"),(0,n.kt)("h2",{id:"feedback"},"Feedback"),(0,n.kt)("p",null,"See our ",(0,n.kt)("a",{parentName:"p",href:"/docs/feedback"},"Feedback page"),"."),(0,n.kt)("h2",{id:"updates-to-how-we-work"},"Updates to How We Work"),(0,n.kt)("p",null,"Please check back periodically to review any updates to this page."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b4a95747.0a5eacce.js b/assets/js/b4a95747.1e529c97.js similarity index 98% rename from assets/js/b4a95747.0a5eacce.js rename to assets/js/b4a95747.1e529c97.js index 16138280..a2395358 100644 --- a/assets/js/b4a95747.0a5eacce.js +++ b/assets/js/b4a95747.1e529c97.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5289],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,f=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?r.createElement(f,l(l({ref:t},c),{},{components:n})):r.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:o,l[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>s,metadata:()=>p,toc:()=>u});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),l=["components"],s={title:"JSON"},i=void 0,p={unversionedId:"json",id:"json",title:"JSON",description:"If you want to use the --json flag to return JSON output to the user, then you can set the enableJsonFlag property on the Command class.",source:"@site/../docs/json.md",sourceDirName:".",slug:"/json",permalink:"/docs/json",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/json.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"JSON"},sidebar:"docs",previous:{title:"Error Handling",permalink:"/docs/error_handling"},next:{title:"Release",permalink:"/docs/releasing"}},c={},u=[],m={toc:u},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,l);return(0,a.kt)(d,(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you want to use the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag to return JSON output to the user, then you can set the ",(0,a.kt)("inlineCode",{parentName:"p"},"enableJsonFlag")," property on the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," class."),(0,a.kt)("p",null,"When this property is set and the user supplies the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag, the command will suppress all logs and instead log the return value to the console in JSON format. ",(0,a.kt)("strong",{parentName:"p"},"Note")," log suppression will only work if you use the logging methods on the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," class instance. In other words, ",(0,a.kt)("inlineCode",{parentName:"p"},"this.log")," will be automatically suppressed but ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log")," will not be."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nexport class HelloCommand extends Command {\n public static enableJsonFlag = true\n public async run(): Promise<{ message: string }> {\n console.log('hello, world!')\n return { message: 'hello, world!' }\n }\n}\n\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ my-cli hello\nhello, world!\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ my-cli hello --json\n{\n "message": "hello, world!"\n}\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5289],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,f=u["".concat(i,".").concat(d)]||u[d]||m[d]||a;return n?r.createElement(f,l(l({ref:t},c),{},{components:n})):r.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:o,l[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>s,metadata:()=>p,toc:()=>u});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),l=["components"],s={title:"JSON"},i=void 0,p={unversionedId:"json",id:"json",title:"JSON",description:"If you want to use the --json flag to return JSON output to the user, then you can set the enableJsonFlag property on the Command class.",source:"@site/../docs/json.md",sourceDirName:".",slug:"/json",permalink:"/docs/json",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/json.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"JSON"},sidebar:"docs",previous:{title:"Error Handling",permalink:"/docs/error_handling"},next:{title:"Release",permalink:"/docs/releasing"}},c={},u=[],m={toc:u},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,l);return(0,a.kt)(d,(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you want to use the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag to return JSON output to the user, then you can set the ",(0,a.kt)("inlineCode",{parentName:"p"},"enableJsonFlag")," property on the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," class."),(0,a.kt)("p",null,"When this property is set and the user supplies the ",(0,a.kt)("inlineCode",{parentName:"p"},"--json")," flag, the command will suppress all logs and instead log the return value to the console in JSON format. ",(0,a.kt)("strong",{parentName:"p"},"Note")," log suppression will only work if you use the logging methods on the ",(0,a.kt)("inlineCode",{parentName:"p"},"Command")," class instance. In other words, ",(0,a.kt)("inlineCode",{parentName:"p"},"this.log")," will be automatically suppressed but ",(0,a.kt)("inlineCode",{parentName:"p"},"console.log")," will not be."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command} from '@oclif/core'\nexport class HelloCommand extends Command {\n public static enableJsonFlag = true\n public async run(): Promise<{ message: string }> {\n console.log('hello, world!')\n return { message: 'hello, world!' }\n }\n}\n\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ my-cli hello\nhello, world!\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ my-cli hello --json\n{\n "message": "hello, world!"\n}\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c5890d18.933b9d04.js b/assets/js/c5890d18.dbb7b07c.js similarity index 99% rename from assets/js/c5890d18.933b9d04.js rename to assets/js/c5890d18.dbb7b07c.js index 3e229c42..39c2623a 100644 --- a/assets/js/c5890d18.933b9d04.js +++ b/assets/js/c5890d18.dbb7b07c.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8038],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>h});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},m=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},c=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),u=p(n),c=a,h=u["".concat(s,".").concat(c)]||u[c]||d[c]||r;return n?i.createElement(h,l(l({ref:t},m),{},{components:n})):i.createElement(h,l({ref:t},m))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:a,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>p,toc:()=>u});var i=n(7462),a=n(3366),r=(n(7294),n(3905)),l=["components"],o={title:"Themes"},s=void 0,p={unversionedId:"themes",id:"themes",title:"Themes",description:"oclif supports themes that users can either define for themselves or select from a variety of themes you ship with your CLI.",source:"@site/../docs/themes.md",sourceDirName:".",slug:"/themes",permalink:"/docs/themes",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/themes.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Themes"},sidebar:"docs",previous:{title:"ESM",permalink:"/docs/esm"},next:{title:"Examples",permalink:"/docs/examples"}},m={},u=[{value:"theme.json",id:"themejson",level:2},{value:"Supported Theme Properties",id:"supported-theme-properties",level:3},{value:"Disabling Themes",id:"disabling-themes",level:2},{value:"Extending Themes",id:"extending-themes",level:2}],d={toc:u},c="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,l);return(0,r.kt)(c,(0,i.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"oclif supports themes that users can either define for themselves or select from a variety of themes you ship with your CLI."),(0,r.kt)("p",null,"By default, the theme only applies to help output but you can extend the theme for your own purposes if you want. See ",(0,r.kt)("a",{parentName:"p",href:"#extending-themes"},"Extending Themes")," section below."),(0,r.kt)("h2",{id:"themejson"},"theme.json"),(0,r.kt)("p",null,"By default oclif will read themes from ",(0,r.kt)("inlineCode",{parentName:"p"},"~/.config//theme.json"),"."),(0,r.kt)("p",null,"This file takes the following shape:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "bin": "white",\n "command": "cyan",\n "commandSummary": "white",\n "dollarSign": "white",\n "flag": "white",\n "flagDefaultValue": "blue",\n "flagOptions": "white",\n "flagRequired": "red",\n "flagSeparator": "white",\n "sectionDescription": "white",\n "sectionHeader": "underline",\n "topic": "white",\n "version": "white"\n}\n')),(0,r.kt)("h3",{id:"supported-theme-properties"},"Supported Theme Properties"),(0,r.kt)("p",null,"As mentioned, the theme only applies to help output by default. The following properties can be used:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alias"),": the aliases under the ",(0,r.kt)("inlineCode",{parentName:"li"},"ALIASES")," section"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"bin"),": the name of your CLI's executable (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"sf"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"heroku"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"command"),": the command's name"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"commandSummary"),": the command's summary"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"dollarSign"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"$")," printed before ",(0,r.kt)("inlineCode",{parentName:"li"},"examples")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"usage")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flag"),": flag names and short characters"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagDefaultValue"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"[default: X]")," shown on flags with a default"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagOptions"),": the valid options for a flag"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagRequired"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"(required)")," that shows on required flags"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagSeparator"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},",")," that separates the short char and long flag names (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"-f, --foo"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sectionDescription"),": the text inside of each section (e.g. everything under ",(0,r.kt)("inlineCode",{parentName:"li"},"DESCRIPTION"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sectionHeader"),": the section header (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"DESCRIPTION"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"topic"),": the topics under the ",(0,r.kt)("inlineCode",{parentName:"li"},"TOPICS")," section"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"version"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"VERSION")," section that shows under the root help (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"sf --help"),")")),(0,r.kt)("p",null,"The values for each of these must be one of the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a hex code, e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"#FF0000")),(0,r.kt)("li",{parentName:"ul"},"a rgb, e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"rgb(255,255,255)")),(0,r.kt)("li",{parentName:"ul"},"a style supported by ",(0,r.kt)("inlineCode",{parentName:"li"},"chalk")," (see ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/chalk/chalk/#styles"},"https://github.com/chalk/chalk/#styles"),")")),(0,r.kt)("p",null,"Any invalid values will be ignored."),(0,r.kt)("h2",{id:"disabling-themes"},"Disabling Themes"),(0,r.kt)("p",null,"Themes can be disabled by using ",(0,r.kt)("inlineCode",{parentName:"p"},"_DISABLE_THEME")," environment variable."),(0,r.kt)("h2",{id:"extending-themes"},"Extending Themes"),(0,r.kt)("p",null,"By default oclif only uses the theme for the help output but you can use the theme for other purposes if you desire. For instance maybe you'd like to log colorized ",(0,r.kt)("inlineCode",{parentName:"p"},"info:")," logs to the user during a command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport default class Hello extends Command {\n public async run(): Promise {\n this.info('starting process!')\n // do some stuff...\n this.info('still making progress!')\n // do some more stuff...\n this.info('process complete!')\n }\n\n public info(msg: string): void {\n this.log(ux.colorize(this.config.theme?.info, 'info:'), msg)\n }\n}\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[8038],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>h});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},m=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},c=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),u=p(n),c=a,h=u["".concat(s,".").concat(c)]||u[c]||d[c]||r;return n?i.createElement(h,l(l({ref:t},m),{},{components:n})):i.createElement(h,l({ref:t},m))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:a,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>p,toc:()=>u});var i=n(7462),a=n(3366),r=(n(7294),n(3905)),l=["components"],o={title:"Themes"},s=void 0,p={unversionedId:"themes",id:"themes",title:"Themes",description:"oclif supports themes that users can either define for themselves or select from a variety of themes you ship with your CLI.",source:"@site/../docs/themes.md",sourceDirName:".",slug:"/themes",permalink:"/docs/themes",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/themes.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Themes"},sidebar:"docs",previous:{title:"ESM",permalink:"/docs/esm"},next:{title:"Examples",permalink:"/docs/examples"}},m={},u=[{value:"theme.json",id:"themejson",level:2},{value:"Supported Theme Properties",id:"supported-theme-properties",level:3},{value:"Disabling Themes",id:"disabling-themes",level:2},{value:"Extending Themes",id:"extending-themes",level:2}],d={toc:u},c="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,l);return(0,r.kt)(c,(0,i.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"oclif supports themes that users can either define for themselves or select from a variety of themes you ship with your CLI."),(0,r.kt)("p",null,"By default, the theme only applies to help output but you can extend the theme for your own purposes if you want. See ",(0,r.kt)("a",{parentName:"p",href:"#extending-themes"},"Extending Themes")," section below."),(0,r.kt)("h2",{id:"themejson"},"theme.json"),(0,r.kt)("p",null,"By default oclif will read themes from ",(0,r.kt)("inlineCode",{parentName:"p"},"~/.config//theme.json"),"."),(0,r.kt)("p",null,"This file takes the following shape:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "bin": "white",\n "command": "cyan",\n "commandSummary": "white",\n "dollarSign": "white",\n "flag": "white",\n "flagDefaultValue": "blue",\n "flagOptions": "white",\n "flagRequired": "red",\n "flagSeparator": "white",\n "sectionDescription": "white",\n "sectionHeader": "underline",\n "topic": "white",\n "version": "white"\n}\n')),(0,r.kt)("h3",{id:"supported-theme-properties"},"Supported Theme Properties"),(0,r.kt)("p",null,"As mentioned, the theme only applies to help output by default. The following properties can be used:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"alias"),": the aliases under the ",(0,r.kt)("inlineCode",{parentName:"li"},"ALIASES")," section"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"bin"),": the name of your CLI's executable (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"sf"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"heroku"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"command"),": the command's name"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"commandSummary"),": the command's summary"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"dollarSign"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"$")," printed before ",(0,r.kt)("inlineCode",{parentName:"li"},"examples")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"usage")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flag"),": flag names and short characters"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagDefaultValue"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"[default: X]")," shown on flags with a default"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagOptions"),": the valid options for a flag"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagRequired"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"(required)")," that shows on required flags"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"flagSeparator"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},",")," that separates the short char and long flag names (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"-f, --foo"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sectionDescription"),": the text inside of each section (e.g. everything under ",(0,r.kt)("inlineCode",{parentName:"li"},"DESCRIPTION"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sectionHeader"),": the section header (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"DESCRIPTION"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"topic"),": the topics under the ",(0,r.kt)("inlineCode",{parentName:"li"},"TOPICS")," section"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"version"),": the ",(0,r.kt)("inlineCode",{parentName:"li"},"VERSION")," section that shows under the root help (e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"sf --help"),")")),(0,r.kt)("p",null,"The values for each of these must be one of the following:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"a hex code, e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"#FF0000")),(0,r.kt)("li",{parentName:"ul"},"a rgb, e.g. ",(0,r.kt)("inlineCode",{parentName:"li"},"rgb(255,255,255)")),(0,r.kt)("li",{parentName:"ul"},"a style supported by ",(0,r.kt)("inlineCode",{parentName:"li"},"chalk")," (see ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/chalk/chalk/#styles"},"https://github.com/chalk/chalk/#styles"),")")),(0,r.kt)("p",null,"Any invalid values will be ignored."),(0,r.kt)("h2",{id:"disabling-themes"},"Disabling Themes"),(0,r.kt)("p",null,"Themes can be disabled by using ",(0,r.kt)("inlineCode",{parentName:"p"},"_DISABLE_THEME")," environment variable."),(0,r.kt)("h2",{id:"extending-themes"},"Extending Themes"),(0,r.kt)("p",null,"By default oclif only uses the theme for the help output but you can use the theme for other purposes if you desire. For instance maybe you'd like to log colorized ",(0,r.kt)("inlineCode",{parentName:"p"},"info:")," logs to the user during a command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Command, ux} from '@oclif/core'\n\nexport default class Hello extends Command {\n public async run(): Promise {\n this.info('starting process!')\n // do some stuff...\n this.info('still making progress!')\n // do some more stuff...\n this.info('process complete!')\n }\n\n public info(msg: string): void {\n this.log(ux.colorize(this.config.theme?.info, 'info:'), msg)\n }\n}\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c81fd975.ec148956.js b/assets/js/c81fd975.cd142838.js similarity index 99% rename from assets/js/c81fd975.ec148956.js rename to assets/js/c81fd975.cd142838.js index 277f54df..63cd7246 100644 --- a/assets/js/c81fd975.ec148956.js +++ b/assets/js/c81fd975.cd142838.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9310],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||r;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>u});var o=n(7462),a=n(3366),r=(n(7294),n(3905)),i=["components"],s={title:"Testing"},c=void 0,l={unversionedId:"testing",id:"testing",title:"Testing",description:"Testing in oclif can be done with any testing framework. You can run commands with MyCommand.run() which returns a promise you can wait on.",source:"@site/../docs/testing.md",sourceDirName:".",slug:"/testing",permalink:"/docs/testing",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/testing.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Testing"},sidebar:"docs",previous:{title:"Release",permalink:"/docs/releasing"},next:{title:"Running Commands Programmatically",permalink:"/docs/running_programmatically"}},p={},u=[{value:"stdout/stderr",id:"stdoutstderr",level:2},{value:"Code Coverage",id:"code-coverage",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,i);return(0,r.kt)(m,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Testing in oclif can be done with any testing framework. You can run commands with ",(0,r.kt)("inlineCode",{parentName:"p"},"MyCommand.run()")," which returns a promise you can wait on."),(0,r.kt)("p",null,"There are common tasks however when writing CLI tools. For this, we have a conventional set of tools that we suggest using to test your CLI. These are based on ",(0,r.kt)("a",{parentName:"p",href:"https://mochajs.org"},"mocha")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/fancy-test"},"fancy-test"),"."),(0,r.kt)("p",null,"Mocha is the top JavaScript testing framework and a solid choice for any project. fancy-test is a tool we developed that builds on top of mocha to make it easy to repeat patterns and write concise mocha tests. There is also a library ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/test"},"@oclif/test")," that extends fancy-test with helpers specific to testing oclif CLIs. These are things like running a command or hook or checking if an exit status code is set, for example."),(0,r.kt)("p",null,"Any CLI built with oclif will come preloaded with these tools and an example test that should work out of the box with ",(0,r.kt)("inlineCode",{parentName:"p"},"npm test")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"yarn test"),"."),(0,r.kt)("p",null,"As an example, let's look at the ",(0,r.kt)("inlineCode",{parentName:"p"},"heroku whoami")," command which makes an API call to get the current logged in user. If the user is not logged in, it exits with status 100. (This is a simplified example, here is ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/heroku/heroku-cli-plugin-auth"},"the actual code"),".)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"src/commands/whoami.ts")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import Command from '@heroku-cli/command'\n\nexport class Whoami extends Command {\n async run() {\n try {\n let {body: account} = await this.heroku.get('/account')\n this.log(account.email)\n } catch (err) {\n if (err.statusCode === 401) {\n this.error('not logged in', {exit: 100})\n }\n throw err\n }\n }\n}\n")),(0,r.kt)("p",null,"Another common tool we like to use in testing oclif CLIs is ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/node-nock/nock"},"nock"),". Install the ",(0,r.kt)("inlineCode",{parentName:"p"},"nock")," package as a devDependency."),(0,r.kt)("p",null,"Here is the test code"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"test/commands/whoami.test.ts")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-typescript"},"import {expect, test} from '@oclif/test'\n\ndescribe('auth:whoami', () => {\n test\n .nock('https://api.heroku.com', api => api\n .get('/account')\n // user is logged in, return their name\n .reply(200, {email: 'jeff@example.com'})\n )\n .stdout()\n .command(['auth:whoami'])\n .it('shows user email when logged in', ctx => {\n expect(ctx.stdout).to.equal('jeff@example.com\\n')\n })\n\n test\n .nock('https://api.heroku.com', api => api\n .get('/account')\n // HTTP 401 means the user is not logged in with valid credentials\n .reply(401)\n )\n .command(['auth:whoami'])\n // checks to ensure the command exits with status 100\n .exit(100)\n .it('exits with status 100 when not logged in')\n})\n")),(0,r.kt)("p",null,"These tools are setup to not only mock out the stdout/stderr and HTTP calls, but they're setup to ensure they automatically reset after the test. A common issue we've had when building CLIs with simpler ",(0,r.kt)("inlineCode",{parentName:"p"},"beforeEach/afterEach")," filters is that if the ",(0,r.kt)("inlineCode",{parentName:"p"},"afterEach")," filters aren't setup correctly, a failing test can leave mocks around that make later tests fail. Using fancy-test, we avoid this problem and only have to declare our mocks once."),(0,r.kt)("p",null,"For more on how to test with oclif, check out the docs for ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/fancy-test"},"fancy-test")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/test"},"@oclif/test"),"."),(0,r.kt)("h2",{id:"stdoutstderr"},"stdout/stderr"),(0,r.kt)("p",null,"The stdout/stderr mocks use ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/stdout-stderr"},"stdout-stderr")," under the hood. This library can be used standalone if you'd prefer to use jest or want a different testing setup but still have the ability to mock out stdout and stderr."),(0,r.kt)("p",null,"If you want to see the output but leave it mocked, you can either pass in ",(0,r.kt)("inlineCode",{parentName:"p"},"{print: true}")," to the options, or set ",(0,r.kt)("inlineCode",{parentName:"p"},"TEST_OUTPUT=1"),"."),(0,r.kt)("h2",{id:"code-coverage"},"Code Coverage"),(0,r.kt)("p",null,"Code coverage is provided automatically for JavaScript and TypeScript projects via ",(0,r.kt)("a",{parentName:"p",href:"https://npm.im/nyc"},"nyc"),". Just run ",(0,r.kt)("inlineCode",{parentName:"p"},"yarn test")," and it will show the code coverage. The coverage can optionally be sent to ",(0,r.kt)("a",{parentName:"p",href:"https://codecov.io"},"codecov")," in the CI scripts as well."))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9310],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||r;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>u});var o=n(7462),a=n(3366),r=(n(7294),n(3905)),i=["components"],s={title:"Testing"},c=void 0,l={unversionedId:"testing",id:"testing",title:"Testing",description:"Testing in oclif can be done with any testing framework. You can run commands with MyCommand.run() which returns a promise you can wait on.",source:"@site/../docs/testing.md",sourceDirName:".",slug:"/testing",permalink:"/docs/testing",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/testing.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Testing"},sidebar:"docs",previous:{title:"Release",permalink:"/docs/releasing"},next:{title:"Running Commands Programmatically",permalink:"/docs/running_programmatically"}},p={},u=[{value:"stdout/stderr",id:"stdoutstderr",level:2},{value:"Code Coverage",id:"code-coverage",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,i);return(0,r.kt)(m,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Testing in oclif can be done with any testing framework. You can run commands with ",(0,r.kt)("inlineCode",{parentName:"p"},"MyCommand.run()")," which returns a promise you can wait on."),(0,r.kt)("p",null,"There are common tasks however when writing CLI tools. For this, we have a conventional set of tools that we suggest using to test your CLI. These are based on ",(0,r.kt)("a",{parentName:"p",href:"https://mochajs.org"},"mocha")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/fancy-test"},"fancy-test"),"."),(0,r.kt)("p",null,"Mocha is the top JavaScript testing framework and a solid choice for any project. fancy-test is a tool we developed that builds on top of mocha to make it easy to repeat patterns and write concise mocha tests. There is also a library ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/test"},"@oclif/test")," that extends fancy-test with helpers specific to testing oclif CLIs. These are things like running a command or hook or checking if an exit status code is set, for example."),(0,r.kt)("p",null,"Any CLI built with oclif will come preloaded with these tools and an example test that should work out of the box with ",(0,r.kt)("inlineCode",{parentName:"p"},"npm test")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"yarn test"),"."),(0,r.kt)("p",null,"As an example, let's look at the ",(0,r.kt)("inlineCode",{parentName:"p"},"heroku whoami")," command which makes an API call to get the current logged in user. If the user is not logged in, it exits with status 100. (This is a simplified example, here is ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/heroku/heroku-cli-plugin-auth"},"the actual code"),".)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"src/commands/whoami.ts")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import Command from '@heroku-cli/command'\n\nexport class Whoami extends Command {\n async run() {\n try {\n let {body: account} = await this.heroku.get('/account')\n this.log(account.email)\n } catch (err) {\n if (err.statusCode === 401) {\n this.error('not logged in', {exit: 100})\n }\n throw err\n }\n }\n}\n")),(0,r.kt)("p",null,"Another common tool we like to use in testing oclif CLIs is ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/node-nock/nock"},"nock"),". Install the ",(0,r.kt)("inlineCode",{parentName:"p"},"nock")," package as a devDependency."),(0,r.kt)("p",null,"Here is the test code"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"test/commands/whoami.test.ts")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-typescript"},"import {expect, test} from '@oclif/test'\n\ndescribe('auth:whoami', () => {\n test\n .nock('https://api.heroku.com', api => api\n .get('/account')\n // user is logged in, return their name\n .reply(200, {email: 'jeff@example.com'})\n )\n .stdout()\n .command(['auth:whoami'])\n .it('shows user email when logged in', ctx => {\n expect(ctx.stdout).to.equal('jeff@example.com\\n')\n })\n\n test\n .nock('https://api.heroku.com', api => api\n .get('/account')\n // HTTP 401 means the user is not logged in with valid credentials\n .reply(401)\n )\n .command(['auth:whoami'])\n // checks to ensure the command exits with status 100\n .exit(100)\n .it('exits with status 100 when not logged in')\n})\n")),(0,r.kt)("p",null,"These tools are setup to not only mock out the stdout/stderr and HTTP calls, but they're setup to ensure they automatically reset after the test. A common issue we've had when building CLIs with simpler ",(0,r.kt)("inlineCode",{parentName:"p"},"beforeEach/afterEach")," filters is that if the ",(0,r.kt)("inlineCode",{parentName:"p"},"afterEach")," filters aren't setup correctly, a failing test can leave mocks around that make later tests fail. Using fancy-test, we avoid this problem and only have to declare our mocks once."),(0,r.kt)("p",null,"For more on how to test with oclif, check out the docs for ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/fancy-test"},"fancy-test")," and ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/oclif/test"},"@oclif/test"),"."),(0,r.kt)("h2",{id:"stdoutstderr"},"stdout/stderr"),(0,r.kt)("p",null,"The stdout/stderr mocks use ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/jdxcode/stdout-stderr"},"stdout-stderr")," under the hood. This library can be used standalone if you'd prefer to use jest or want a different testing setup but still have the ability to mock out stdout and stderr."),(0,r.kt)("p",null,"If you want to see the output but leave it mocked, you can either pass in ",(0,r.kt)("inlineCode",{parentName:"p"},"{print: true}")," to the options, or set ",(0,r.kt)("inlineCode",{parentName:"p"},"TEST_OUTPUT=1"),"."),(0,r.kt)("h2",{id:"code-coverage"},"Code Coverage"),(0,r.kt)("p",null,"Code coverage is provided automatically for JavaScript and TypeScript projects via ",(0,r.kt)("a",{parentName:"p",href:"https://npm.im/nyc"},"nyc"),". Just run ",(0,r.kt)("inlineCode",{parentName:"p"},"yarn test")," and it will show the code coverage. The coverage can optionally be sent to ",(0,r.kt)("a",{parentName:"p",href:"https://codecov.io"},"codecov")," in the CI scripts as well."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c94a68c1.db1aa280.js b/assets/js/c94a68c1.47c94d90.js similarity index 98% rename from assets/js/c94a68c1.db1aa280.js rename to assets/js/c94a68c1.47c94d90.js index 5a0a38d0..afc3f942 100644 --- a/assets/js/c94a68c1.db1aa280.js +++ b/assets/js/c94a68c1.47c94d90.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9147],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),d=a,g=u["".concat(l,".").concat(d)]||u[d]||m[d]||o;return r?n.createElement(g,i(i({ref:t},p),{},{components:r})):n.createElement(g,i({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>g,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var n=r(7462),a=r(3366),o=(r(7294),r(3905)),i=["components"],s={title:"Command Arguments"},l=void 0,c={unversionedId:"args",id:"args",title:"Command Arguments",description:"Arguments are positional arguments passed to the command. For example, if this command was run with mycli arg1 arg2 it would be declared like this:",source:"@site/../docs/args.md",sourceDirName:".",slug:"/args",permalink:"/docs/args",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/args.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Arguments"},sidebar:"docs",previous:{title:"Commands",permalink:"/docs/commands"},next:{title:"Command Flags",permalink:"/docs/flags"}},p={},u=[],m={toc:u},d="wrapper";function g(e){var t=e.components,r=(0,a.Z)(e,i);return(0,o.kt)(d,(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Arguments are positional arguments passed to the command. For example, if this command was run with ",(0,o.kt)("inlineCode",{parentName:"p"},"mycli arg1 arg2")," it would be declared like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Args, Command} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static args = {\n firstArg: Args.string(),\n secondArg: Args.string(),\n }\n\n async run() {\n // can get args as an object\n const {args} = await this.parse(MyCLI)\n this.log(`running my command with args: ${args.firstArg}, ${args.secondArg}`)\n // can also get the args as an array\n const {argv} = await this.parse(MyCLI)\n this.log(`running my command with args: ${argv[0]}, ${argv[1]}`)\n }\n}\n")),(0,o.kt)("p",null,"Here are the options arguments can have:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"static args = {\n firstArg: Args.string(\n {\n name: 'file', // name of arg to show in help and reference with args[name]\n required: false, // make the arg required with `required: true`\n description: 'output file', // help description\n hidden: true, // hide this arg from help\n parse: input => 'output', // instead of the user input, return a different value\n default: 'world', // default value if no arg input\n options: ['a', 'b'], // only allow input to be from a discrete set\n }\n ),\n}\n")),(0,o.kt)("p",null,"Here are the types of args that ",(0,o.kt)("inlineCode",{parentName:"p"},"Args")," exports:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"string"),(0,o.kt)("li",{parentName:"ul"},"integer"),(0,o.kt)("li",{parentName:"ul"},"boolean"),(0,o.kt)("li",{parentName:"ul"},"url"),(0,o.kt)("li",{parentName:"ul"},"file"),(0,o.kt)("li",{parentName:"ul"},"directory"),(0,o.kt)("li",{parentName:"ul"},"custom")),(0,o.kt)("p",null,"For variable length arguments, disable argument validation with ",(0,o.kt)("inlineCode",{parentName:"p"},"static strict = false")," on the command."))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9147],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>g});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),d=a,g=u["".concat(l,".").concat(d)]||u[d]||m[d]||o;return r?n.createElement(g,i(i({ref:t},p),{},{components:r})):n.createElement(g,i({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>g,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var n=r(7462),a=r(3366),o=(r(7294),r(3905)),i=["components"],s={title:"Command Arguments"},l=void 0,c={unversionedId:"args",id:"args",title:"Command Arguments",description:"Arguments are positional arguments passed to the command. For example, if this command was run with mycli arg1 arg2 it would be declared like this:",source:"@site/../docs/args.md",sourceDirName:".",slug:"/args",permalink:"/docs/args",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/args.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Arguments"},sidebar:"docs",previous:{title:"Commands",permalink:"/docs/commands"},next:{title:"Command Flags",permalink:"/docs/flags"}},p={},u=[],m={toc:u},d="wrapper";function g(e){var t=e.components,r=(0,a.Z)(e,i);return(0,o.kt)(d,(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Arguments are positional arguments passed to the command. For example, if this command was run with ",(0,o.kt)("inlineCode",{parentName:"p"},"mycli arg1 arg2")," it would be declared like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Args, Command} from '@oclif/core'\n\nexport class MyCLI extends Command {\n static args = {\n firstArg: Args.string(),\n secondArg: Args.string(),\n }\n\n async run() {\n // can get args as an object\n const {args} = await this.parse(MyCLI)\n this.log(`running my command with args: ${args.firstArg}, ${args.secondArg}`)\n // can also get the args as an array\n const {argv} = await this.parse(MyCLI)\n this.log(`running my command with args: ${argv[0]}, ${argv[1]}`)\n }\n}\n")),(0,o.kt)("p",null,"Here are the options arguments can have:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"static args = {\n firstArg: Args.string(\n {\n name: 'file', // name of arg to show in help and reference with args[name]\n required: false, // make the arg required with `required: true`\n description: 'output file', // help description\n hidden: true, // hide this arg from help\n parse: input => 'output', // instead of the user input, return a different value\n default: 'world', // default value if no arg input\n options: ['a', 'b'], // only allow input to be from a discrete set\n }\n ),\n}\n")),(0,o.kt)("p",null,"Here are the types of args that ",(0,o.kt)("inlineCode",{parentName:"p"},"Args")," exports:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"string"),(0,o.kt)("li",{parentName:"ul"},"integer"),(0,o.kt)("li",{parentName:"ul"},"boolean"),(0,o.kt)("li",{parentName:"ul"},"url"),(0,o.kt)("li",{parentName:"ul"},"file"),(0,o.kt)("li",{parentName:"ul"},"directory"),(0,o.kt)("li",{parentName:"ul"},"custom")),(0,o.kt)("p",null,"For variable length arguments, disable argument validation with ",(0,o.kt)("inlineCode",{parentName:"p"},"static strict = false")," on the command."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d0e73d62.7a23908d.js b/assets/js/d0e73d62.3830f8e4.js similarity index 98% rename from assets/js/d0e73d62.7a23908d.js rename to assets/js/d0e73d62.3830f8e4.js index 34492c22..c4349033 100644 --- a/assets/js/d0e73d62.7a23908d.js +++ b/assets/js/d0e73d62.3830f8e4.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2134],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),u=c(n),m=i,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,s(s({ref:t},p),{},{components:n})):r.createElement(f,s({ref:t},p))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,s=new Array(o);s[0]=m;var a={};for(var l in t)hasOwnProperty.call(t,l)&&(a[l]=t[l]);a.originalType=e,a[u]="string"==typeof e?e:i,s[1]=a;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var r=n(7462),i=n(3366),o=(n(7294),n(3905)),s=["components"],a={title:"NSIS Installer Customization"},l=void 0,c={unversionedId:"nsis-installer_customization",id:"nsis-installer_customization",title:"NSIS Installer Customization",description:"Sometimes you need to verify some dependencies, ensure there are no conflicting CLIs installed, or do some other custom logic before installing your CLI. For npm-scenarios, simply specify a preinstall script. But Windows installers don't include this script. You must instead write your own nsis modification to do these checks. See where this custom script gets placed in the installer in the oclif/oclif repo.",source:"@site/../docs/nsis-installer_customization.md",sourceDirName:".",slug:"/nsis-installer_customization",permalink:"/docs/nsis-installer_customization",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/nsis-installer_customization.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"NSIS Installer Customization"},sidebar:"docs",previous:{title:"Aliases",permalink:"/docs/aliases"},next:{title:"Custom Base Class",permalink:"/docs/base_class"}},p={},u=[],d={toc:u},m="wrapper";function f(e){var t=e.components,n=(0,i.Z)(e,s);return(0,o.kt)(m,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Sometimes you need to verify some dependencies, ensure there are no conflicting CLIs installed, or do some other custom logic before installing your CLI. For npm-scenarios, simply specify a ",(0,o.kt)("inlineCode",{parentName:"p"},"preinstall")," script. But Windows installers don't include this script. You must instead write your own nsis modification to do these checks. See where this custom script gets placed in the installer in the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/oclif/oclif/blob/b8d76af9290716ef69d8d1026f98041268306dfd/src/commands/pack/win.ts#L60"},"oclif/oclif")," repo."),(0,o.kt)("p",null,"See how ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/cli"},"Salesforce CLI")," did this to prevent their new major version being installed on top of an older, and incompatible, version. In that ",(0,o.kt)("inlineCode",{parentName:"p"},"package.json"),", they specified an nsis installer like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'\n{\n "name": "mycli",\n "version": "0.0.0",\n "description": "My CLI",\n "main": "bin/run.js",\n "bin": "./bin/run.js",\n "oclif": {\n "nsisCustomization": "scripts/nsis.nsi"\n }\n}\n')),(0,o.kt)("p",null,"And then their custom script was loaded into the installer during the packing phase of the CLI."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2134],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),u=c(n),m=i,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,s(s({ref:t},p),{},{components:n})):r.createElement(f,s({ref:t},p))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,s=new Array(o);s[0]=m;var a={};for(var l in t)hasOwnProperty.call(t,l)&&(a[l]=t[l]);a.originalType=e,a[u]="string"==typeof e?e:i,s[1]=a;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var r=n(7462),i=n(3366),o=(n(7294),n(3905)),s=["components"],a={title:"NSIS Installer Customization"},l=void 0,c={unversionedId:"nsis-installer_customization",id:"nsis-installer_customization",title:"NSIS Installer Customization",description:"Sometimes you need to verify some dependencies, ensure there are no conflicting CLIs installed, or do some other custom logic before installing your CLI. For npm-scenarios, simply specify a preinstall script. But Windows installers don't include this script. You must instead write your own nsis modification to do these checks. See where this custom script gets placed in the installer in the oclif/oclif repo.",source:"@site/../docs/nsis-installer_customization.md",sourceDirName:".",slug:"/nsis-installer_customization",permalink:"/docs/nsis-installer_customization",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/nsis-installer_customization.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"NSIS Installer Customization"},sidebar:"docs",previous:{title:"Aliases",permalink:"/docs/aliases"},next:{title:"Custom Base Class",permalink:"/docs/base_class"}},p={},u=[],d={toc:u},m="wrapper";function f(e){var t=e.components,n=(0,i.Z)(e,s);return(0,o.kt)(m,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Sometimes you need to verify some dependencies, ensure there are no conflicting CLIs installed, or do some other custom logic before installing your CLI. For npm-scenarios, simply specify a ",(0,o.kt)("inlineCode",{parentName:"p"},"preinstall")," script. But Windows installers don't include this script. You must instead write your own nsis modification to do these checks. See where this custom script gets placed in the installer in the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/oclif/oclif/blob/b8d76af9290716ef69d8d1026f98041268306dfd/src/commands/pack/win.ts#L60"},"oclif/oclif")," repo."),(0,o.kt)("p",null,"See how ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/salesforcecli/cli"},"Salesforce CLI")," did this to prevent their new major version being installed on top of an older, and incompatible, version. In that ",(0,o.kt)("inlineCode",{parentName:"p"},"package.json"),", they specified an nsis installer like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'\n{\n "name": "mycli",\n "version": "0.0.0",\n "description": "My CLI",\n "main": "bin/run.js",\n "bin": "./bin/run.js",\n "oclif": {\n "nsisCustomization": "scripts/nsis.nsi"\n }\n}\n')),(0,o.kt)("p",null,"And then their custom script was loaded into the installer during the packing phase of the CLI."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d665a578.052e6995.js b/assets/js/d665a578.03eb317e.js similarity index 98% rename from assets/js/d665a578.052e6995.js rename to assets/js/d665a578.03eb317e.js index a289b923..63d7d720 100644 --- a/assets/js/d665a578.052e6995.js +++ b/assets/js/d665a578.03eb317e.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9510],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),f=o,d=u["".concat(c,".").concat(f)]||u[f]||m[f]||a;return r?n.createElement(d,l(l({ref:t},p),{},{components:r})):n.createElement(d,l({ref:t},p))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),l=["components"],i={title:"Examples"},c=void 0,s={unversionedId:"examples",id:"examples",title:"Examples",description:"Here are some examples to get an idea of how to use oclif in various setups.",source:"@site/../docs/examples.md",sourceDirName:".",slug:"/examples",permalink:"/docs/examples",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/examples.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Examples"},sidebar:"docs",previous:{title:"Themes",permalink:"/docs/themes"},next:{title:"External Links",permalink:"/docs/external_links"}},p={},u=[],m={toc:u},f="wrapper";function d(e){var t=e.components,r=(0,o.Z)(e,l);return(0,a.kt)(f,(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Here are some examples to get an idea of how to use oclif in various setups."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/hello-world"},"Hello World Example"))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[9510],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),f=o,d=u["".concat(c,".").concat(f)]||u[f]||m[f]||a;return r?n.createElement(d,l(l({ref:t},p),{},{components:r})):n.createElement(d,l({ref:t},p))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,l=new Array(a);l[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),l=["components"],i={title:"Examples"},c=void 0,s={unversionedId:"examples",id:"examples",title:"Examples",description:"Here are some examples to get an idea of how to use oclif in various setups.",source:"@site/../docs/examples.md",sourceDirName:".",slug:"/examples",permalink:"/docs/examples",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/examples.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Examples"},sidebar:"docs",previous:{title:"Themes",permalink:"/docs/themes"},next:{title:"External Links",permalink:"/docs/external_links"}},p={},u=[],m={toc:u},f="wrapper";function d(e){var t=e.components,r=(0,o.Z)(e,l);return(0,a.kt)(f,(0,n.Z)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Here are some examples to get an idea of how to use oclif in various setups."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/hello-world"},"Hello World Example"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d9b0bdb4.15d89fe6.js b/assets/js/d9b0bdb4.03a2a904.js similarity index 98% rename from assets/js/d9b0bdb4.15d89fe6.js rename to assets/js/d9b0bdb4.03a2a904.js index 09c740ee..c039f335 100644 --- a/assets/js/d9b0bdb4.15d89fe6.js +++ b/assets/js/d9b0bdb4.03a2a904.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5933],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(s,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,c(c({ref:t},u),{},{components:r})):n.createElement(m,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,c[1]=i;for(var l=2;l{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),c=["components"],i={title:"Feedback"},s=void 0,l={unversionedId:"feedback",id:"feedback",title:"Feedback",description:"If you have any suggestions or just want to let us know what you think of oclif, send us a message at or file an issue in our repos.",source:"@site/../docs/feedback.md",sourceDirName:".",slug:"/feedback",permalink:"/docs/feedback",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/feedback.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Feedback"},sidebar:"docs",previous:{title:"How We Work",permalink:"/docs/how_we_work"}},u={},p=[],f={toc:p},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,c);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you have any suggestions or just want to let us know what you think of oclif, send us a message at ",(0,a.kt)("a",{parentName:"p",href:"mailto:alm-cli@salesforce.com"},"alm-cli@salesforce.com")," or file an issue in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif"},"our repos"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5933],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(s,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,c(c({ref:t},u),{},{components:r})):n.createElement(m,c({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,c[1]=i;for(var l=2;l{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),c=["components"],i={title:"Feedback"},s=void 0,l={unversionedId:"feedback",id:"feedback",title:"Feedback",description:"If you have any suggestions or just want to let us know what you think of oclif, send us a message at or file an issue in our repos.",source:"@site/../docs/feedback.md",sourceDirName:".",slug:"/feedback",permalink:"/docs/feedback",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/feedback.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Feedback"},sidebar:"docs",previous:{title:"How We Work",permalink:"/docs/how_we_work"}},u={},p=[],f={toc:p},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,c);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"If you have any suggestions or just want to let us know what you think of oclif, send us a message at ",(0,a.kt)("a",{parentName:"p",href:"mailto:alm-cli@salesforce.com"},"alm-cli@salesforce.com")," or file an issue in ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif"},"our repos"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/df1cd967.74c1da59.js b/assets/js/df1cd967.ea06b04e.js similarity index 98% rename from assets/js/df1cd967.74c1da59.js rename to assets/js/df1cd967.ea06b04e.js index b7773a3f..0b6afb87 100644 --- a/assets/js/df1cd967.74c1da59.js +++ b/assets/js/df1cd967.ea06b04e.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2712],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function p(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),s=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):p(p({},t),e)),r},l=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=s(r),m=n,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?o.createElement(f,p(p({ref:t},l),{},{components:r})):o.createElement(f,p({ref:t},l))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,p=new Array(a);p[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:n,p[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var o=r(7462),n=r(3366),a=(r(7294),r(3905)),p=["components"],i={title:"Topic Separators"},c=void 0,s={unversionedId:"topic_separator",id:"topic_separator",title:"Topic Separators",description:"By default, topics will be separated with colons, e.g. mycommand. However, you have the option to use spaces if you prefer, e.g. my awesome command.",source:"@site/../docs/topic_separator.md",sourceDirName:".",slug:"/topic_separator",permalink:"/docs/topic_separator",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/topic_separator.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Topic Separators"},sidebar:"docs",previous:{title:"Topics",permalink:"/docs/topics"},next:{title:"Hooks",permalink:"/docs/hooks"}},l={},u=[],d={toc:u},m="wrapper";function f(e){var t=e.components,r=(0,n.Z)(e,p);return(0,a.kt)(m,(0,o.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"By default, topics will be separated with colons, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"my:awesome:command"),". However, you have the option to use spaces if you prefer, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"my awesome command"),"."),(0,a.kt)("p",null,"To do this, simply set the ",(0,a.kt)("inlineCode",{parentName:"p"},"topicSeparator")," property in the oclif section of your package.json"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "topicSeparator": " "\n }\n}\n')),(0,a.kt)("p",null,"Currently colons (",(0,a.kt)("inlineCode",{parentName:"p"},'":"'),") and spaces (",(0,a.kt)("inlineCode",{parentName:"p"},'" "'),") are the only supported topic separators."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2712],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function p(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),s=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):p(p({},t),e)),r},l=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=s(r),m=n,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return r?o.createElement(f,p(p({ref:t},l),{},{components:r})):o.createElement(f,p({ref:t},l))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,p=new Array(a);p[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:n,p[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>f,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var o=r(7462),n=r(3366),a=(r(7294),r(3905)),p=["components"],i={title:"Topic Separators"},c=void 0,s={unversionedId:"topic_separator",id:"topic_separator",title:"Topic Separators",description:"By default, topics will be separated with colons, e.g. mycommand. However, you have the option to use spaces if you prefer, e.g. my awesome command.",source:"@site/../docs/topic_separator.md",sourceDirName:".",slug:"/topic_separator",permalink:"/docs/topic_separator",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/topic_separator.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Topic Separators"},sidebar:"docs",previous:{title:"Topics",permalink:"/docs/topics"},next:{title:"Hooks",permalink:"/docs/hooks"}},l={},u=[],d={toc:u},m="wrapper";function f(e){var t=e.components,r=(0,n.Z)(e,p);return(0,a.kt)(m,(0,o.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"By default, topics will be separated with colons, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"my:awesome:command"),". However, you have the option to use spaces if you prefer, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"my awesome command"),"."),(0,a.kt)("p",null,"To do this, simply set the ",(0,a.kt)("inlineCode",{parentName:"p"},"topicSeparator")," property in the oclif section of your package.json"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "oclif": {\n "topicSeparator": " "\n }\n}\n')),(0,a.kt)("p",null,"Currently colons (",(0,a.kt)("inlineCode",{parentName:"p"},'":"'),") and spaces (",(0,a.kt)("inlineCode",{parentName:"p"},'" "'),") are the only supported topic separators."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e360e27f.f1d2a447.js b/assets/js/e360e27f.17dbfd91.js similarity index 99% rename from assets/js/e360e27f.f1d2a447.js rename to assets/js/e360e27f.17dbfd91.js index 5fad7124..c3677195 100644 --- a/assets/js/e360e27f.f1d2a447.js +++ b/assets/js/e360e27f.17dbfd91.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5990],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=i.createContext({}),p=function(e){var t=i.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return i.createElement(u.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,u=e.parentName,s=r(e,["components","mdxType","originalType","parentName"]),c=p(n),d=o,f=c["".concat(u,".").concat(d)]||c[d]||m[d]||l;return n?i.createElement(f,a(a({ref:t},s),{},{components:n})):i.createElement(f,a({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,a=new Array(l);a[0]=d;var r={};for(var u in t)hasOwnProperty.call(t,u)&&(r[u]=t[u]);r.originalType=e,r[c]="string"==typeof e?e:o,a[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>u,default:()=>f,frontMatter:()=>r,metadata:()=>p,toc:()=>c});var i=n(7462),o=n(3366),l=(n(7294),n(3905)),a=["components"],r={title:"Plugins"},u=void 0,p={unversionedId:"plugins",id:"plugins",title:"Plugins",description:"Plugins are a great way to offer experimental functionality, allow users to extend your CLI, break up a CLI into modular components, or share functionality between CLIs.",source:"@site/../docs/plugins.md",sourceDirName:".",slug:"/plugins",permalink:"/docs/plugins",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/plugins.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Plugins"},sidebar:"docs",previous:{title:"Hooks",permalink:"/docs/hooks"},next:{title:"Help Classes",permalink:"/docs/help_classes"}},s={},c=[{value:"Useful Plugins",id:"useful-plugins",level:2},{value:"Community Plugins",id:"community-plugins",level:2},{value:"Building your own plugin",id:"building-your-own-plugin",level:2}],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,a);return(0,l.kt)(d,(0,i.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"Plugins are a great way to offer experimental functionality, allow users to extend your CLI, break up a CLI into modular components, or share functionality between CLIs."),(0,l.kt)("p",null,"Plugins can have commands or hooks just like a CLI. To add a plugin such as the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-not-found"},"not-found plugin")," plugin, first add it to your CLI with ",(0,l.kt)("inlineCode",{parentName:"p"},"yarn add @oclif/plugin-not-found"),", then add the following to your ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-js"},'{\n "name": "mycli",\n "version": "0.0.0",\n // ...\n "oclif": {\n "plugins": [\n "@oclif/plugin-help",\n "@oclif/plugin-not-found"\n ]\n }\n}\n')),(0,l.kt)("p",null,"If you want users to be able to install their own plugins into your CLI, use the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-plugins"},"plugins plugin"),"."),(0,l.kt)("h2",{id:"useful-plugins"},"Useful Plugins"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-not-found"},"@oclif/plugin-not-found"),' - Display a friendly "did you mean" message if a command is not found.'),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-plugins"},"@oclif/plugin-plugins")," - Allow users to add plugins to extend your CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-update"},"@oclif/plugin-update")," - Add autoupdate support to the CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-help"},"@oclif/plugin-help")," - Help plugin for oclif."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-warn-if-update-available"},"@oclif/plugin-warn-if-update-available")," - Show a warning message if user is running an out of date CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-which"},"@oclif/plugin-which")," - Show which plugin a command comes from."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-commands"},"@oclif/plugin-commands")," - Add a ",(0,l.kt)("inlineCode",{parentName:"li"},"commands")," command to list all the commands."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-autocomplete"},"@oclif/plugin-autocomplete")," - Add bash/zsh autocomplete.")),(0,l.kt)("h2",{id:"community-plugins"},"Community Plugins"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/natzcam/conf-cli"},"conf-cli")," - Adds a ",(0,l.kt)("inlineCode",{parentName:"li"},"conf")," command to share state/configuration between commands. Uses ",(0,l.kt)("a",{parentName:"li",href:"https://github.com/sindresorhus/conf"},"sindresorhus/conf"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.npmjs.com/package/oclif-dynamic-commands"},"dynamic-commands")," - Load commands dynamically based on commands found under the current working directory."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/oclif.github.io/blob/docs/docs/plugins.md"},"Add yours here"),"!")),(0,l.kt)("h2",{id:"building-your-own-plugin"},"Building your own plugin"),(0,l.kt)("p",null,"Writing code for plugins is essentially the same as writing within a CLI. They can export 3 different types: commands, hooks, and other plugins."),(0,l.kt)("p",null,"Run ",(0,l.kt)("inlineCode",{parentName:"p"},"npx oclif generate mynewplugin")," to create a plugin in a new directory. This will come with a sample command called ",(0,l.kt)("inlineCode",{parentName:"p"},"hello"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5990],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=i.createContext({}),p=function(e){var t=i.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return i.createElement(u.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,u=e.parentName,s=r(e,["components","mdxType","originalType","parentName"]),c=p(n),d=o,f=c["".concat(u,".").concat(d)]||c[d]||m[d]||l;return n?i.createElement(f,a(a({ref:t},s),{},{components:n})):i.createElement(f,a({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,a=new Array(l);a[0]=d;var r={};for(var u in t)hasOwnProperty.call(t,u)&&(r[u]=t[u]);r.originalType=e,r[c]="string"==typeof e?e:o,a[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>u,default:()=>f,frontMatter:()=>r,metadata:()=>p,toc:()=>c});var i=n(7462),o=n(3366),l=(n(7294),n(3905)),a=["components"],r={title:"Plugins"},u=void 0,p={unversionedId:"plugins",id:"plugins",title:"Plugins",description:"Plugins are a great way to offer experimental functionality, allow users to extend your CLI, break up a CLI into modular components, or share functionality between CLIs.",source:"@site/../docs/plugins.md",sourceDirName:".",slug:"/plugins",permalink:"/docs/plugins",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/plugins.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Plugins"},sidebar:"docs",previous:{title:"Hooks",permalink:"/docs/hooks"},next:{title:"Help Classes",permalink:"/docs/help_classes"}},s={},c=[{value:"Useful Plugins",id:"useful-plugins",level:2},{value:"Community Plugins",id:"community-plugins",level:2},{value:"Building your own plugin",id:"building-your-own-plugin",level:2}],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,o.Z)(e,a);return(0,l.kt)(d,(0,i.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"Plugins are a great way to offer experimental functionality, allow users to extend your CLI, break up a CLI into modular components, or share functionality between CLIs."),(0,l.kt)("p",null,"Plugins can have commands or hooks just like a CLI. To add a plugin such as the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-not-found"},"not-found plugin")," plugin, first add it to your CLI with ",(0,l.kt)("inlineCode",{parentName:"p"},"yarn add @oclif/plugin-not-found"),", then add the following to your ",(0,l.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-js"},'{\n "name": "mycli",\n "version": "0.0.0",\n // ...\n "oclif": {\n "plugins": [\n "@oclif/plugin-help",\n "@oclif/plugin-not-found"\n ]\n }\n}\n')),(0,l.kt)("p",null,"If you want users to be able to install their own plugins into your CLI, use the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/oclif/plugin-plugins"},"plugins plugin"),"."),(0,l.kt)("h2",{id:"useful-plugins"},"Useful Plugins"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-not-found"},"@oclif/plugin-not-found"),' - Display a friendly "did you mean" message if a command is not found.'),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-plugins"},"@oclif/plugin-plugins")," - Allow users to add plugins to extend your CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-update"},"@oclif/plugin-update")," - Add autoupdate support to the CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-help"},"@oclif/plugin-help")," - Help plugin for oclif."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-warn-if-update-available"},"@oclif/plugin-warn-if-update-available")," - Show a warning message if user is running an out of date CLI."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-which"},"@oclif/plugin-which")," - Show which plugin a command comes from."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-commands"},"@oclif/plugin-commands")," - Add a ",(0,l.kt)("inlineCode",{parentName:"li"},"commands")," command to list all the commands."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/plugin-autocomplete"},"@oclif/plugin-autocomplete")," - Add bash/zsh autocomplete.")),(0,l.kt)("h2",{id:"community-plugins"},"Community Plugins"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/natzcam/conf-cli"},"conf-cli")," - Adds a ",(0,l.kt)("inlineCode",{parentName:"li"},"conf")," command to share state/configuration between commands. Uses ",(0,l.kt)("a",{parentName:"li",href:"https://github.com/sindresorhus/conf"},"sindresorhus/conf"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.npmjs.com/package/oclif-dynamic-commands"},"dynamic-commands")," - Load commands dynamically based on commands found under the current working directory."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/oclif/oclif.github.io/blob/docs/docs/plugins.md"},"Add yours here"),"!")),(0,l.kt)("h2",{id:"building-your-own-plugin"},"Building your own plugin"),(0,l.kt)("p",null,"Writing code for plugins is essentially the same as writing within a CLI. They can export 3 different types: commands, hooks, and other plugins."),(0,l.kt)("p",null,"Run ",(0,l.kt)("inlineCode",{parentName:"p"},"npx oclif generate mynewplugin")," to create a plugin in a new directory. This will come with a sample command called ",(0,l.kt)("inlineCode",{parentName:"p"},"hello"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e3703649.2f81b37b.js b/assets/js/e3703649.4c80b50d.js similarity index 99% rename from assets/js/e3703649.2f81b37b.js rename to assets/js/e3703649.4c80b50d.js index 1ee4dd5a..82cb5ddb 100644 --- a/assets/js/e3703649.2f81b37b.js +++ b/assets/js/e3703649.4c80b50d.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5679],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>u});var o=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=o.createContext({}),i=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=i(e.components);return o.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,l=e.mdxType,a=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=i(n),h=l,u=m["".concat(p,".").concat(h)]||m[h]||d[h]||a;return n?o.createElement(u,r(r({ref:t},c),{},{components:n})):o.createElement(u,r({ref:t},c))}));function u(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=n.length,r=new Array(a);r[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:l,r[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>m});var o=n(7462),l=n(3366),a=(n(7294),n(3905)),r=["components"],s={title:"Help Classes"},p=void 0,i={unversionedId:"help_classes",id:"help_classes",title:"Help Classes",description:"Out of the box oclif provides a great help experience for CLIs. Users can invoke help with the --help flag.",source:"@site/../docs/help_classes.md",sourceDirName:".",slug:"/help_classes",permalink:"/docs/help_classes",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/help_classes.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Help Classes"},sidebar:"docs",previous:{title:"Plugins",permalink:"/docs/plugins"},next:{title:"Error Handling",permalink:"/docs/error_handling"}},c={},m=[{value:"Custom Help",id:"custom-help",level:2},{value:"Extending the HelpBase class",id:"extending-the-helpbase-class",level:2},{value:"Extending the default Help class",id:"extending-the-default-help-class",level:2},{value:"Building custom help classes in JavaScript projects",id:"building-custom-help-classes-in-javascript-projects",level:2}],d={toc:m},h="wrapper";function u(e){var t=e.components,n=(0,l.Z)(e,r);return(0,a.kt)(h,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs. Users can invoke help with the ",(0,a.kt)("inlineCode",{parentName:"p"},"--help")," flag."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli login --help\n")),(0,a.kt)("p",null,"If you want your CLI to have an explicit ",(0,a.kt)("inlineCode",{parentName:"p"},"help")," command, add ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-help")," as an ",(0,a.kt)("a",{parentName:"p",href:"/docs/plugins"},"oclif plugin in your config"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli help\n")),(0,a.kt)("h2",{id:"custom-help"},"Custom Help"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ yarn add @oclif/core --latest\n")),(0,a.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,a.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./dist/help"\n // ...\n }\n // ...\n}\n')),(0,a.kt)("p",null,"From here there are two paths, implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,a.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both below."),(0,a.kt)("h2",{id:"extending-the-helpbase-class"},"Extending the ",(0,a.kt)("inlineCode",{parentName:"h2"},"HelpBase")," class"),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class provides a starting point requiring the minimum needed methods implemented to be compatible with oclif."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, HelpBase} from '@oclif/core';\n\nexport default class CustomHelp extends HelpBase {\n showHelp(args: string[]) {\n console.log('This will be displayed in multi-command CLIs')\n }\n\n showCommandHelp(command: Command) {\n console.log('This will be displayed in single-command CLIs')\n }\n}\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"showHelp")," method is called by oclif to display help in multi-command CLIs, while ",(0,a.kt)("inlineCode",{parentName:"p"},"showCommandHelp")," is called directly for single-command CLIs."),(0,a.kt)("p",null,"The class is instantiated with a ",(0,a.kt)("inlineCode",{parentName:"p"},"config")," property that provides helpful context for constructing your custom output."),(0,a.kt)("p",null,"To see an example of what is possible take a look at the source code for the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/help/index.ts"},"default ",(0,a.kt)("inlineCode",{parentName:"a"},"Help")," class exported from @oclif/core"),"."),(0,a.kt)("h2",{id:"extending-the-default-help-class"},"Extending the default ",(0,a.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,a.kt)("p",null,"The default ",(0,a.kt)("inlineCode",{parentName:"p"},"Help")," class provides many method \u201chooks\u201d that make it easy to override the particular parts of help's output you want to customize."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, Help, Topic} from '@oclif/core';\n\nexport default class MyHelpClass extends Help {\n // acts as a \"router\"\n // and based on the args it receives\n // calls one of showRootHelp, showTopicHelp,\n // or showCommandHelp\n showHelp(args: string[]): void {\n }\n\n // display the root help of a CLI\n showRootHelp(): void {\n }\n\n // display help for a topic\n showTopicHelp(topic: Topic): void {\n }\n\n // display help for a command\n showCommandHelp(command: Command): void {\n }\n\n // the default implementations of showRootHelp\n // showTopicHelp and showCommandHelp\n // will call various format methods that\n // provide the formatting for their corresponding\n // help sections;\n // these can be overwritten as well\n\n // the formatting responsible for the header\n // displayed for the root help\n formatRoot(): string {\n }\n\n // the formatting for an individual topic\n formatTopic(topic: Config.Topic): string {\n }\n\n // the formatting for a list of topics\n protected formatTopics(topics: Config.Topic[]): string {\n }\n\n // the formatting for a list of commands\n formatCommands(commands: Config.Command[]): string {\n }\n\n // the formatting for an individual command\n formatCommand(command: Config.Command): string {\n }\n}\n")),(0,a.kt)("p",null,"To see the default implementation of these methods take a look at the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/help/index.ts"},"default ",(0,a.kt)("inlineCode",{parentName:"a"},"Help")," class exported from @oclif/core"),"."),(0,a.kt)("p",null,"To start experimenting, define ",(0,a.kt)("inlineCode",{parentName:"p"},"showCommandHelp")," in your custom help class and change the output."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, Help, Topic} from '@oclif/core';\n\nexport default class MyHelpClass extends Help {\n public showCommandHelp(command: Config.Command) {\n console.log('Display my custom command help!')\n }\n}\n")),(0,a.kt)("p",null,"Then run help for any command."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli login --help\nDisplay my custom command help!\n")),(0,a.kt)("h2",{id:"building-custom-help-classes-in-javascript-projects"},"Building custom help classes in JavaScript projects"),(0,a.kt)("p",null,'These examples above followed a TypeScript project. For JavaScript project with an example help file at "',"[project root]",'/src/help.js" would have a package.json with the ',(0,a.kt)("inlineCode",{parentName:"p"},"helpClass")," defined:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./src/help"\n // ...\n }\n // ...\n}\n')),(0,a.kt)("p",null,"The imports are handled slightly different for JavaScript projects but the rest of the help class mimic the TypeScript examples above, except without type annotations."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {HelpBase} = require('@oclif/core');\n\nmodule.exports = class MyHelpClass extends HelpBase {\n showHelp(args) {\n console.log('This will be displayed in multi-command CLIs')\n }\n\n showCommandHelp(command) {\n console.log('This will be displayed for a single command')\n }\n}\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {Help} = require('@oclif/core');\n\nmodule.exports = class MyHelpClass extends Help {\n showHelp(args) {\n }\n\n showRootHelp() {\n }\n\n showTopicHelp(topic) {\n }\n\n showCommandHelp(command) {\n }\n\n formatRoot() {\n }\n\n formatTopic(topic) {\n }\n\n formatTopics(topics) {\n }\n\n formatCommands(commands) {\n }\n\n formatCommand(command) {\n }\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5679],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>u});var o=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=o.createContext({}),i=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=i(e.components);return o.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,l=e.mdxType,a=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=i(n),h=l,u=m["".concat(p,".").concat(h)]||m[h]||d[h]||a;return n?o.createElement(u,r(r({ref:t},c),{},{components:n})):o.createElement(u,r({ref:t},c))}));function u(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=n.length,r=new Array(a);r[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:l,r[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>m});var o=n(7462),l=n(3366),a=(n(7294),n(3905)),r=["components"],s={title:"Help Classes"},p=void 0,i={unversionedId:"help_classes",id:"help_classes",title:"Help Classes",description:"Out of the box oclif provides a great help experience for CLIs. Users can invoke help with the --help flag.",source:"@site/../docs/help_classes.md",sourceDirName:".",slug:"/help_classes",permalink:"/docs/help_classes",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/help_classes.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Help Classes"},sidebar:"docs",previous:{title:"Plugins",permalink:"/docs/plugins"},next:{title:"Error Handling",permalink:"/docs/error_handling"}},c={},m=[{value:"Custom Help",id:"custom-help",level:2},{value:"Extending the HelpBase class",id:"extending-the-helpbase-class",level:2},{value:"Extending the default Help class",id:"extending-the-default-help-class",level:2},{value:"Building custom help classes in JavaScript projects",id:"building-custom-help-classes-in-javascript-projects",level:2}],d={toc:m},h="wrapper";function u(e){var t=e.components,n=(0,l.Z)(e,r);return(0,a.kt)(h,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Out of the box oclif provides a great help experience for CLIs. Users can invoke help with the ",(0,a.kt)("inlineCode",{parentName:"p"},"--help")," flag."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli login --help\n")),(0,a.kt)("p",null,"If you want your CLI to have an explicit ",(0,a.kt)("inlineCode",{parentName:"p"},"help")," command, add ",(0,a.kt)("inlineCode",{parentName:"p"},"@oclif/plugin-help")," as an ",(0,a.kt)("a",{parentName:"p",href:"/docs/plugins"},"oclif plugin in your config"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli help\n")),(0,a.kt)("h2",{id:"custom-help"},"Custom Help"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ yarn add @oclif/core --latest\n")),(0,a.kt)("p",null,"To get started, first define the filepath to your help class in oclif's config in package.json. This is a relative path to the help class, without a file extension."),(0,a.kt)("p",null,'For this example, the help class will be created in a file at "',"[project root]",'/src/help.ts".'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./dist/help"\n // ...\n }\n // ...\n}\n')),(0,a.kt)("p",null,"From here there are two paths, implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class yourself or overwrite the parts of the default ",(0,a.kt)("inlineCode",{parentName:"p"},"Help")," class you want to customize (ex: how command usage is displayed). We recommend the latter approach but cover both below."),(0,a.kt)("h2",{id:"extending-the-helpbase-class"},"Extending the ",(0,a.kt)("inlineCode",{parentName:"h2"},"HelpBase")," class"),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"HelpBase")," abstract class provides a starting point requiring the minimum needed methods implemented to be compatible with oclif."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, HelpBase} from '@oclif/core';\n\nexport default class CustomHelp extends HelpBase {\n showHelp(args: string[]) {\n console.log('This will be displayed in multi-command CLIs')\n }\n\n showCommandHelp(command: Command) {\n console.log('This will be displayed in single-command CLIs')\n }\n}\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"showHelp")," method is called by oclif to display help in multi-command CLIs, while ",(0,a.kt)("inlineCode",{parentName:"p"},"showCommandHelp")," is called directly for single-command CLIs."),(0,a.kt)("p",null,"The class is instantiated with a ",(0,a.kt)("inlineCode",{parentName:"p"},"config")," property that provides helpful context for constructing your custom output."),(0,a.kt)("p",null,"To see an example of what is possible take a look at the source code for the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/help/index.ts"},"default ",(0,a.kt)("inlineCode",{parentName:"a"},"Help")," class exported from @oclif/core"),"."),(0,a.kt)("h2",{id:"extending-the-default-help-class"},"Extending the default ",(0,a.kt)("inlineCode",{parentName:"h2"},"Help")," class"),(0,a.kt)("p",null,"The default ",(0,a.kt)("inlineCode",{parentName:"p"},"Help")," class provides many method \u201chooks\u201d that make it easy to override the particular parts of help's output you want to customize."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, Help, Topic} from '@oclif/core';\n\nexport default class MyHelpClass extends Help {\n // acts as a \"router\"\n // and based on the args it receives\n // calls one of showRootHelp, showTopicHelp,\n // or showCommandHelp\n showHelp(args: string[]): void {\n }\n\n // display the root help of a CLI\n showRootHelp(): void {\n }\n\n // display help for a topic\n showTopicHelp(topic: Topic): void {\n }\n\n // display help for a command\n showCommandHelp(command: Command): void {\n }\n\n // the default implementations of showRootHelp\n // showTopicHelp and showCommandHelp\n // will call various format methods that\n // provide the formatting for their corresponding\n // help sections;\n // these can be overwritten as well\n\n // the formatting responsible for the header\n // displayed for the root help\n formatRoot(): string {\n }\n\n // the formatting for an individual topic\n formatTopic(topic: Config.Topic): string {\n }\n\n // the formatting for a list of topics\n protected formatTopics(topics: Config.Topic[]): string {\n }\n\n // the formatting for a list of commands\n formatCommands(commands: Config.Command[]): string {\n }\n\n // the formatting for an individual command\n formatCommand(command: Config.Command): string {\n }\n}\n")),(0,a.kt)("p",null,"To see the default implementation of these methods take a look at the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/oclif/core/blob/main/src/help/index.ts"},"default ",(0,a.kt)("inlineCode",{parentName:"a"},"Help")," class exported from @oclif/core"),"."),(0,a.kt)("p",null,"To start experimenting, define ",(0,a.kt)("inlineCode",{parentName:"p"},"showCommandHelp")," in your custom help class and change the output."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-TypeScript"},"import {Command, Help, Topic} from '@oclif/core';\n\nexport default class MyHelpClass extends Help {\n public showCommandHelp(command: Config.Command) {\n console.log('Display my custom command help!')\n }\n}\n")),(0,a.kt)("p",null,"Then run help for any command."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"$ my-cli login --help\nDisplay my custom command help!\n")),(0,a.kt)("h2",{id:"building-custom-help-classes-in-javascript-projects"},"Building custom help classes in JavaScript projects"),(0,a.kt)("p",null,'These examples above followed a TypeScript project. For JavaScript project with an example help file at "',"[project root]",'/src/help.js" would have a package.json with the ',(0,a.kt)("inlineCode",{parentName:"p"},"helpClass")," defined:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'{\n // ...\n "oclif": {\n "helpClass": "./src/help"\n // ...\n }\n // ...\n}\n')),(0,a.kt)("p",null,"The imports are handled slightly different for JavaScript projects but the rest of the help class mimic the TypeScript examples above, except without type annotations."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {HelpBase} = require('@oclif/core');\n\nmodule.exports = class MyHelpClass extends HelpBase {\n showHelp(args) {\n console.log('This will be displayed in multi-command CLIs')\n }\n\n showCommandHelp(command) {\n console.log('This will be displayed for a single command')\n }\n}\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const {Help} = require('@oclif/core');\n\nmodule.exports = class MyHelpClass extends Help {\n showHelp(args) {\n }\n\n showRootHelp() {\n }\n\n showTopicHelp(topic) {\n }\n\n showCommandHelp(command) {\n }\n\n formatRoot() {\n }\n\n formatTopic(topic) {\n }\n\n formatTopics(topics) {\n }\n\n formatCommands(commands) {\n }\n\n formatCommand(command) {\n }\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f182954c.026bff16.js b/assets/js/f182954c.264f8346.js similarity index 98% rename from assets/js/f182954c.026bff16.js rename to assets/js/f182954c.264f8346.js index 0510c22b..e674c37f 100644 --- a/assets/js/f182954c.026bff16.js +++ b/assets/js/f182954c.264f8346.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[182],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(c,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],l={title:"Related Repositories"},c=void 0,s={unversionedId:"related_repos",id:"related_repos",title:"Related Repositories",description:"* @oclif/core - Base library for oclif CLIs or plugins. This can be used directly without the generator.",source:"@site/../docs/related_repos.md",sourceDirName:".",slug:"/related_repos",permalink:"/docs/related_repos",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/related_repos.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Related Repositories"},sidebar:"docs",previous:{title:"External Links",permalink:"/docs/external_links"},next:{title:"How We Work",permalink:"/docs/how_we_work"}},p={},u=[],f={toc:u},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/core"},"@oclif/core")," - Base library for oclif CLIs or plugins. This can be used directly without the generator."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/test"},"@oclif/test")," - Test helper for oclif.")))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[182],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(c,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var n=r(7462),o=r(3366),a=(r(7294),r(3905)),i=["components"],l={title:"Related Repositories"},c=void 0,s={unversionedId:"related_repos",id:"related_repos",title:"Related Repositories",description:"* @oclif/core - Base library for oclif CLIs or plugins. This can be used directly without the generator.",source:"@site/../docs/related_repos.md",sourceDirName:".",slug:"/related_repos",permalink:"/docs/related_repos",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/related_repos.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Related Repositories"},sidebar:"docs",previous:{title:"External Links",permalink:"/docs/external_links"},next:{title:"How We Work",permalink:"/docs/how_we_work"}},p={},u=[],f={toc:u},d="wrapper";function m(e){var t=e.components,r=(0,o.Z)(e,i);return(0,a.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/core"},"@oclif/core")," - Base library for oclif CLIs or plugins. This can be used directly without the generator."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/oclif/test"},"@oclif/test")," - Test helper for oclif.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f6c5328e.39ab04ee.js b/assets/js/f6c5328e.36c1c2ed.js similarity index 99% rename from assets/js/f6c5328e.39ab04ee.js rename to assets/js/f6c5328e.36c1c2ed.js index 636d8d9c..2a81ec1f 100644 --- a/assets/js/f6c5328e.39ab04ee.js +++ b/assets/js/f6c5328e.36c1c2ed.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5125],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),d=a,f=u["".concat(s,".").concat(d)]||u[d]||m[d]||i;return n?o.createElement(f,r(r({ref:t},p),{},{components:n})):o.createElement(f,r({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>u});var o=n(7462),a=n(3366),i=(n(7294),n(3905)),r=["components"],l={title:"Hooks"},s=void 0,c={unversionedId:"hooks",id:"hooks",title:"Hooks",description:"oclif exposes lifecycle event hooks such as init and commandnotfound. See below for a list of all the lifecycle events. In addition to these built-in events, you can create your own events and allow commands/plugins to watch for these custom events. It's a great way to allow multiple plugins to interact with each other.",source:"@site/../docs/hooks.md",sourceDirName:".",slug:"/hooks",permalink:"/docs/hooks",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/hooks.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Hooks"},sidebar:"docs",previous:{title:"Topic Separators",permalink:"/docs/topic_separator"},next:{title:"Plugins",permalink:"/docs/plugins"}},p={},u=[{value:"Lifecycle Events",id:"lifecycle-events",level:2},{value:"Custom Events",id:"custom-events",level:2}],m={toc:u},d="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,r);return(0,i.kt)(d,(0,o.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"oclif exposes lifecycle event hooks such as ",(0,i.kt)("inlineCode",{parentName:"p"},"init")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"command_not_found"),". ",(0,i.kt)("a",{parentName:"p",href:"#lifecycle-events"},"See below for a list of all the lifecycle events"),". In addition to these built-in events, you can create your own events and allow commands/plugins to watch for these custom events. It's a great way to allow multiple plugins to interact with each other."),(0,i.kt)("p",null,"Multiple hooks are run in parallel. ",(0,i.kt)("strong",{parentName:"p"},"This behavior may change in a future release.")),(0,i.kt)("p",null,"A basic hook looks like the following in TypeScript:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Hook} from '@oclif/core'\n\nconst hook: Hook<'init'> = async function (options) {\n console.log(`example init hook running before ${options.id}`)\n}\n\nexport default hook\n")),(0,i.kt)("p",null,"The hook must also be declared with the event's name and hook's file path under oclif's settings in ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "init": "./lib/hooks/init/example"\n }\n }\n')),(0,i.kt)("p",null,"Multiple hooks of the same event type can be declared with an array."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "init": [\n "./lib/hooks/init/example",\n "./lib/hooks/init/another_hook"\n ]\n }\n }\n')),(0,i.kt)("p",null,"You can create hooks with ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif generate hook myhook --event=init"),"."),(0,i.kt)("h2",{id:"lifecycle-events"},"Lifecycle Events"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"init")," - runs when the CLI is initialized before a command is found to run"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"prerun")," - runs after ",(0,i.kt)("inlineCode",{parentName:"li"},"init")," and after the command is found, but just before running the command itself"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"postrun")," - runs after the command only if the command finishes with no error"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"command_not_found")," - runs if a command is not found before the error is displayed")),(0,i.kt)("h2",{id:"custom-events"},"Custom Events"),(0,i.kt)("p",null,"Custom events are just like lifecycle events, but you need to call ",(0,i.kt)("inlineCode",{parentName:"p"},"this.config.runHook()")," to fire the event."),(0,i.kt)("p",null,"For example, you could define an analytics post function that you will run in your command after submitting analytics telemetry. First define:"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"src/hooks/analytics/post.ts")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"const hook = async function (options: {id: string}) {\n // code to post options.id to analytics server\n}\n\nexport default hook\n")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"package.json")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "analytics": "./lib/hooks/analytics/post"\n },\n },\n')),(0,i.kt)("p",null,"Then in any command you want to trigger the event:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},"export class extends Command {\n async run() {\n // emit analytics\n await this.config.runHook('analytics', {id: 'my_command'})\n }\n}\n")),(0,i.kt)("p",null,"If you need to exit during a hook, use ",(0,i.kt)("inlineCode",{parentName:"p"},"this.error()")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"this.exit()"),". Otherwise the hook will just emit a warning. This is to prevent an issue such as a plugin failing in ",(0,i.kt)("inlineCode",{parentName:"p"},"init")," causing the entire CLI to not function."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[5125],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),d=a,f=u["".concat(s,".").concat(d)]||u[d]||m[d]||i;return n?o.createElement(f,r(r({ref:t},p),{},{components:n})):o.createElement(f,r({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,r[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>u});var o=n(7462),a=n(3366),i=(n(7294),n(3905)),r=["components"],l={title:"Hooks"},s=void 0,c={unversionedId:"hooks",id:"hooks",title:"Hooks",description:"oclif exposes lifecycle event hooks such as init and commandnotfound. See below for a list of all the lifecycle events. In addition to these built-in events, you can create your own events and allow commands/plugins to watch for these custom events. It's a great way to allow multiple plugins to interact with each other.",source:"@site/../docs/hooks.md",sourceDirName:".",slug:"/hooks",permalink:"/docs/hooks",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/hooks.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Hooks"},sidebar:"docs",previous:{title:"Topic Separators",permalink:"/docs/topic_separator"},next:{title:"Plugins",permalink:"/docs/plugins"}},p={},u=[{value:"Lifecycle Events",id:"lifecycle-events",level:2},{value:"Custom Events",id:"custom-events",level:2}],m={toc:u},d="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,r);return(0,i.kt)(d,(0,o.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"oclif exposes lifecycle event hooks such as ",(0,i.kt)("inlineCode",{parentName:"p"},"init")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"command_not_found"),". ",(0,i.kt)("a",{parentName:"p",href:"#lifecycle-events"},"See below for a list of all the lifecycle events"),". In addition to these built-in events, you can create your own events and allow commands/plugins to watch for these custom events. It's a great way to allow multiple plugins to interact with each other."),(0,i.kt)("p",null,"Multiple hooks are run in parallel. ",(0,i.kt)("strong",{parentName:"p"},"This behavior may change in a future release.")),(0,i.kt)("p",null,"A basic hook looks like the following in TypeScript:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"import {Hook} from '@oclif/core'\n\nconst hook: Hook<'init'> = async function (options) {\n console.log(`example init hook running before ${options.id}`)\n}\n\nexport default hook\n")),(0,i.kt)("p",null,"The hook must also be declared with the event's name and hook's file path under oclif's settings in ",(0,i.kt)("inlineCode",{parentName:"p"},"package.json"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "init": "./lib/hooks/init/example"\n }\n }\n')),(0,i.kt)("p",null,"Multiple hooks of the same event type can be declared with an array."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "init": [\n "./lib/hooks/init/example",\n "./lib/hooks/init/another_hook"\n ]\n }\n }\n')),(0,i.kt)("p",null,"You can create hooks with ",(0,i.kt)("inlineCode",{parentName:"p"},"oclif generate hook myhook --event=init"),"."),(0,i.kt)("h2",{id:"lifecycle-events"},"Lifecycle Events"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"init")," - runs when the CLI is initialized before a command is found to run"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"prerun")," - runs after ",(0,i.kt)("inlineCode",{parentName:"li"},"init")," and after the command is found, but just before running the command itself"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"postrun")," - runs after the command only if the command finishes with no error"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"command_not_found")," - runs if a command is not found before the error is displayed")),(0,i.kt)("h2",{id:"custom-events"},"Custom Events"),(0,i.kt)("p",null,"Custom events are just like lifecycle events, but you need to call ",(0,i.kt)("inlineCode",{parentName:"p"},"this.config.runHook()")," to fire the event."),(0,i.kt)("p",null,"For example, you could define an analytics post function that you will run in your command after submitting analytics telemetry. First define:"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"src/hooks/analytics/post.ts")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-typescript"},"const hook = async function (options: {id: string}) {\n // code to post options.id to analytics server\n}\n\nexport default hook\n")),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"package.json")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},' "oclif": {\n "commands": "./lib/commands",\n "hooks": {\n "analytics": "./lib/hooks/analytics/post"\n },\n },\n')),(0,i.kt)("p",null,"Then in any command you want to trigger the event:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-js"},"export class extends Command {\n async run() {\n // emit analytics\n await this.config.runHook('analytics', {id: 'my_command'})\n }\n}\n")),(0,i.kt)("p",null,"If you need to exit during a hook, use ",(0,i.kt)("inlineCode",{parentName:"p"},"this.error()")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"this.exit()"),". Otherwise the hook will just emit a warning. This is to prevent an issue such as a plugin failing in ",(0,i.kt)("inlineCode",{parentName:"p"},"init")," causing the entire CLI to not function."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f905d0fe.8522804b.js b/assets/js/f905d0fe.47993f97.js similarity index 98% rename from assets/js/f905d0fe.8522804b.js rename to assets/js/f905d0fe.47993f97.js index 0eed333f..ee472192 100644 --- a/assets/js/f905d0fe.8522804b.js +++ b/assets/js/f905d0fe.47993f97.js @@ -1 +1 @@ -"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1342],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),m=s(n),d=o,f=m["".concat(l,".").concat(d)]||m[d]||p[d]||a;return n?r.createElement(f,c(c({ref:t},u),{},{components:n})):r.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[m]="string"==typeof e?e:o,c[1]=i;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>f,frontMatter:()=>i,metadata:()=>s,toc:()=>m});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),c=["components"],i={title:"Command Execution"},l=void 0,s={unversionedId:"command_execution",id:"command_execution",title:"Command Execution",description:"Below is a diagram that outlines at a high level the process that occurs every time a user executes an oclif command.",source:"@site/../docs/command_execution.md",sourceDirName:".",slug:"/command_execution",permalink:"/docs/command_execution",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/command_execution.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709583362,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Execution"},sidebar:"docs",previous:{title:"Generator Commands",permalink:"/docs/generator_commands"},next:{title:"Plugin Loading",permalink:"/docs/plugin_loading"}},u={},m=[],p={toc:m},d="wrapper";function f(e){var t=e.components,i=(0,o.Z)(e,c);return(0,a.kt)(d,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Below is a diagram that outlines at a high level the process that occurs every time a user executes an oclif command."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"command execution flow",src:n(1799).Z,width:"3258",height:"4910"})))}f.isMDXComponent=!0},1799:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/command-execution-flow-7722f834b51111bcf89f6c2f7ae2cdf5.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1342],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),m=s(n),d=o,f=m["".concat(l,".").concat(d)]||m[d]||p[d]||a;return n?r.createElement(f,c(c({ref:t},u),{},{components:n})):r.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[m]="string"==typeof e?e:o,c[1]=i;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>f,frontMatter:()=>i,metadata:()=>s,toc:()=>m});var r=n(7462),o=n(3366),a=(n(7294),n(3905)),c=["components"],i={title:"Command Execution"},l=void 0,s={unversionedId:"command_execution",id:"command_execution",title:"Command Execution",description:"Below is a diagram that outlines at a high level the process that occurs every time a user executes an oclif command.",source:"@site/../docs/command_execution.md",sourceDirName:".",slug:"/command_execution",permalink:"/docs/command_execution",draft:!1,editUrl:"https://github.com/oclif/oclif.github.io/tree/docs/docs/../docs/command_execution.md",tags:[],version:"current",lastUpdatedBy:"Mike Donnalley",lastUpdatedAt:1709593271,formattedLastUpdatedAt:"Mar 4, 2024",frontMatter:{title:"Command Execution"},sidebar:"docs",previous:{title:"Generator Commands",permalink:"/docs/generator_commands"},next:{title:"Plugin Loading",permalink:"/docs/plugin_loading"}},u={},m=[],p={toc:m},d="wrapper";function f(e){var t=e.components,i=(0,o.Z)(e,c);return(0,a.kt)(d,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Below is a diagram that outlines at a high level the process that occurs every time a user executes an oclif command."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"command execution flow",src:n(1799).Z,width:"3258",height:"4910"})))}f.isMDXComponent=!0},1799:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/command-execution-flow-7722f834b51111bcf89f6c2f7ae2cdf5.jpg"}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.205bf67e.js b/assets/js/runtime~main.205bf67e.js deleted file mode 100644 index 4791fc53..00000000 --- a/assets/js/runtime~main.205bf67e.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e,f,a,c,d={},b={};function r(e){var f=b[e];if(void 0!==f)return f.exports;var a=b[e]={id:e,loaded:!1,exports:{}};return d[e].call(a.exports,a,a.exports,r),a.loaded=!0,a.exports}r.m=d,r.c=b,e=[],r.O=(f,a,c,d)=>{if(!a){var b=1/0;for(i=0;i=d)&&Object.keys(r.O).every((e=>r.O[e](a[o])))?a.splice(o--,1):(t=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[a,c,d]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var d=Object.create(null);r.r(d);var b={};f=f||[null,a({}),a([]),a(a)];for(var t=2&c&&e;"object"==typeof t&&!~f.indexOf(t);t=a(t))Object.getOwnPropertyNames(t).forEach((f=>b[f]=()=>e[f]));return b.default=()=>e,r.d(d,b),d},r.d=(e,f)=>{for(var a in f)r.o(f,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:f[a]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((f,a)=>(r.f[a](e,f),f)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",182:"f182954c",187:"713bb917",257:"7bd58895",533:"b2b675dd",637:"3e452c7e",1160:"35586d92",1342:"f905d0fe",1369:"169e66bc",1477:"b2f554cd",1660:"03abeb31",1926:"5d5620c4",2026:"82247a8b",2048:"2f98ad87",2134:"d0e73d62",2265:"258a6413",2535:"814f3328",2638:"935116ff",2712:"df1cd967",2728:"3ba497c2",2796:"853133bb",2863:"8705a681",3089:"a6aa9e1f",3118:"4fdccd00",3261:"958c0a42",3316:"104cbb75",3321:"0b218a01",3457:"c4b40215",3459:"253cd3dc",3608:"9e4087bc",3725:"1ed4142b",3797:"f85046f2",3807:"5f98988e",4026:"3bc14f20",4117:"bc0981ca",4195:"c4f5d8e4",4299:"28395ba4",4535:"765c6b61",5125:"f6c5328e",5289:"b4a95747",5445:"0085e091",5575:"c637b865",5679:"e3703649",5901:"1d5c88f5",5917:"3042343a",5933:"d9b0bdb4",5990:"e360e27f",6079:"6de0e435",6103:"ccc49370",6109:"b439faf3",6332:"a92e169d",6568:"03a88bad",6731:"a96ec439",7006:"1f61ef73",7591:"49140ced",7755:"e2e9d59a",7905:"32060389",7918:"17896441",7920:"1a4e3797",8038:"c5890d18",8059:"9eaa546a",8349:"53e18611",8472:"30d74566",8504:"6f3bb722",8925:"19fd9079",9147:"c94a68c1",9244:"2a33acc4",9280:"7b0e8dfa",9310:"c81fd975",9510:"d665a578",9514:"1be78505",9544:"04855d6d",9562:"2486267b",9638:"b3cc73c6"}[e]||e)+"."+{53:"ab9b21f3",182:"026bff16",187:"2de4941a",257:"621b46ec",394:"255027a6",533:"aeb2bd53",637:"7eeef943",1160:"eb012dea",1342:"8522804b",1369:"8f151728",1426:"1fae09de",1477:"d0fa6f76",1660:"89aea179",1926:"1f758151",2026:"0c6962c1",2048:"07ccdeec",2134:"7a23908d",2265:"3eeaaf68",2535:"f62945c9",2638:"1384990f",2712:"74c1da59",2728:"a59ca14d",2796:"5e345192",2863:"31d90ccb",3089:"44b8b2a6",3118:"4793cac0",3261:"85c99996",3316:"891f291a",3321:"a5a6a16e",3457:"958da13d",3459:"f5e32f88",3608:"8aa78bd7",3725:"29563194",3797:"4569824b",3807:"f1ff6838",4026:"6584ac46",4117:"93698a97",4195:"e395d55d",4299:"b965d79e",4535:"ff5592fd",4972:"dc728d36",5125:"39ab04ee",5289:"0a5eacce",5445:"4e4bf217",5575:"c4b7a8d7",5679:"2f81b37b",5901:"08aca381",5917:"cb8ecb82",5933:"15d89fe6",5990:"f1d2a447",6048:"76869424",6079:"c31d17e8",6103:"52966b67",6109:"b508707d",6332:"701f84c9",6568:"62d28b63",6731:"3e244ed4",6945:"29c43de0",7006:"2c97d45b",7591:"7ab97290",7755:"e38db0d1",7905:"636715d9",7918:"ffa056ea",7920:"a85c1838",8038:"933b9d04",8059:"37cf75d3",8349:"7a0136ba",8472:"5738672b",8504:"458468c6",8894:"143a3960",8925:"626d5720",9147:"db1aa280",9244:"d46170c8",9280:"aa41e2c2",9310:"ec148956",9510:"052e6995",9514:"1e420c2f",9544:"7543c909",9562:"f3aad5aa",9638:"e528833c"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),c={},r.l=(e,f,a,d)=>{if(c[e])c[e].push(f);else{var b,t;if(void 0!==a)for(var o=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(u);var d=c[e];if(delete c[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach((e=>e(a))),f)return f(a)},u=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),t&&document.head.appendChild(b)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918",32060389:"7905","935f2afb":"53",f182954c:"182","713bb917":"187","7bd58895":"257",b2b675dd:"533","3e452c7e":"637","35586d92":"1160",f905d0fe:"1342","169e66bc":"1369",b2f554cd:"1477","03abeb31":"1660","5d5620c4":"1926","82247a8b":"2026","2f98ad87":"2048",d0e73d62:"2134","258a6413":"2265","814f3328":"2535","935116ff":"2638",df1cd967:"2712","3ba497c2":"2728","853133bb":"2796","8705a681":"2863",a6aa9e1f:"3089","4fdccd00":"3118","958c0a42":"3261","104cbb75":"3316","0b218a01":"3321",c4b40215:"3457","253cd3dc":"3459","9e4087bc":"3608","1ed4142b":"3725",f85046f2:"3797","5f98988e":"3807","3bc14f20":"4026",bc0981ca:"4117",c4f5d8e4:"4195","28395ba4":"4299","765c6b61":"4535",f6c5328e:"5125",b4a95747:"5289","0085e091":"5445",c637b865:"5575",e3703649:"5679","1d5c88f5":"5901","3042343a":"5917",d9b0bdb4:"5933",e360e27f:"5990","6de0e435":"6079",ccc49370:"6103",b439faf3:"6109",a92e169d:"6332","03a88bad":"6568",a96ec439:"6731","1f61ef73":"7006","49140ced":"7591",e2e9d59a:"7755","1a4e3797":"7920",c5890d18:"8038","9eaa546a":"8059","53e18611":"8349","30d74566":"8472","6f3bb722":"8504","19fd9079":"8925",c94a68c1:"9147","2a33acc4":"9244","7b0e8dfa":"9280",c81fd975:"9310",d665a578:"9510","1be78505":"9514","04855d6d":"9544","2486267b":"9562",b3cc73c6:"9638"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(f,a)=>{var c=r.o(e,f)?e[f]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var d=new Promise(((a,d)=>c=e[f]=[a,d]));a.push(c[2]=d);var b=r.p+r.u(f),t=new Error;r.l(b,(a=>{if(r.o(e,f)&&(0!==(c=e[f])&&(e[f]=void 0),c)){var d=a&&("load"===a.type?"missing":a.type),b=a&&a.target&&a.target.src;t.message="Loading chunk "+f+" failed.\n("+d+": "+b+")",t.name="ChunkLoadError",t.type=d,t.request=b,c[1](t)}}),"chunk-"+f,f)}},r.O.j=f=>0===e[f];var f=(f,a)=>{var c,d,[b,t,o]=a,n=0;if(b.some((f=>0!==e[f]))){for(c in t)r.o(t,c)&&(r.m[c]=t[c]);if(o)var i=o(r)}for(f&&f(a);n{"use strict";var e,a,f,d,c={},b={};function r(e){var a=b[e];if(void 0!==a)return a.exports;var f=b[e]={id:e,loaded:!1,exports:{}};return c[e].call(f.exports,f,f.exports,r),f.loaded=!0,f.exports}r.m=c,r.c=b,e=[],r.O=(a,f,d,c)=>{if(!f){var b=1/0;for(i=0;i=c)&&Object.keys(r.O).every((e=>r.O[e](f[o])))?f.splice(o--,1):(t=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[f,d,c]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var c=Object.create(null);r.r(c);var b={};a=a||[null,f({}),f([]),f(f)];for(var t=2&d&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,r.d(c,b),c},r.d=(e,a)=>{for(var f in a)r.o(a,f)&&!r.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,f)=>(r.f[f](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",182:"f182954c",187:"713bb917",257:"7bd58895",533:"b2b675dd",637:"3e452c7e",1160:"35586d92",1342:"f905d0fe",1369:"169e66bc",1477:"b2f554cd",1660:"03abeb31",1926:"5d5620c4",2026:"82247a8b",2048:"2f98ad87",2134:"d0e73d62",2265:"258a6413",2535:"814f3328",2638:"935116ff",2712:"df1cd967",2728:"3ba497c2",2796:"853133bb",2863:"8705a681",3089:"a6aa9e1f",3118:"4fdccd00",3261:"958c0a42",3316:"104cbb75",3321:"0b218a01",3457:"c4b40215",3459:"253cd3dc",3608:"9e4087bc",3725:"1ed4142b",3797:"f85046f2",3807:"5f98988e",4026:"3bc14f20",4117:"bc0981ca",4195:"c4f5d8e4",4299:"28395ba4",4535:"765c6b61",5125:"f6c5328e",5289:"b4a95747",5445:"0085e091",5575:"c637b865",5679:"e3703649",5901:"1d5c88f5",5917:"3042343a",5933:"d9b0bdb4",5990:"e360e27f",6079:"6de0e435",6103:"ccc49370",6109:"b439faf3",6332:"a92e169d",6568:"03a88bad",6731:"a96ec439",7006:"1f61ef73",7591:"49140ced",7755:"e2e9d59a",7905:"32060389",7918:"17896441",7920:"1a4e3797",8038:"c5890d18",8059:"9eaa546a",8349:"53e18611",8472:"30d74566",8504:"6f3bb722",8925:"19fd9079",9147:"c94a68c1",9244:"2a33acc4",9280:"7b0e8dfa",9310:"c81fd975",9510:"d665a578",9514:"1be78505",9544:"04855d6d",9562:"2486267b",9638:"b3cc73c6"}[e]||e)+"."+{53:"ab9b21f3",182:"264f8346",187:"ce493d17",257:"45570e39",394:"255027a6",533:"aeb2bd53",637:"f8151866",1160:"d74a9192",1342:"47993f97",1369:"8f151728",1426:"1fae09de",1477:"8147c378",1660:"62d31294",1926:"3f17b57d",2026:"eaab3884",2048:"28a95877",2134:"3830f8e4",2265:"fb7ccdd8",2535:"f62945c9",2638:"5b67c00b",2712:"ea06b04e",2728:"a59ca14d",2796:"5e345192",2863:"56669df9",3089:"44b8b2a6",3118:"4793cac0",3261:"c6f748e3",3316:"23da78ae",3321:"c7ec91a6",3457:"958da13d",3459:"f5e32f88",3608:"8aa78bd7",3725:"e0b1cff1",3797:"4569824b",3807:"f1ff6838",4026:"6584ac46",4117:"93698a97",4195:"e395d55d",4299:"b965d79e",4535:"ff5592fd",4972:"dc728d36",5125:"36c1c2ed",5289:"1e529c97",5445:"4e4bf217",5575:"c4b7a8d7",5679:"4c80b50d",5901:"08aca381",5917:"6f606eba",5933:"03a2a904",5990:"17dbfd91",6048:"76869424",6079:"ffe363a4",6103:"52966b67",6109:"b508707d",6332:"bd0fb0a8",6568:"58ba0022",6731:"0aea02dd",6945:"29c43de0",7006:"050e594a",7591:"7ab97290",7755:"e38db0d1",7905:"44959ed9",7918:"ffa056ea",7920:"a85c1838",8038:"dbb7b07c",8059:"46c67a2d",8349:"ac600542",8472:"3e37533e",8504:"9a353140",8894:"143a3960",8925:"580d846e",9147:"47c94d90",9244:"1213b158",9280:"aa41e2c2",9310:"cd142838",9510:"03eb317e",9514:"1e420c2f",9544:"7543c909",9562:"95b52046",9638:"d2977a60"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},r.l=(e,a,f,c)=>{if(d[e])d[e].push(a);else{var b,t;if(void 0!==f)for(var o=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(u);var c=d[e];if(delete d[e],b.parentNode&&b.parentNode.removeChild(b),c&&c.forEach((e=>e(f))),a)return a(f)},u=setTimeout(l.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=l.bind(null,b.onerror),b.onload=l.bind(null,b.onload),t&&document.head.appendChild(b)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918",32060389:"7905","935f2afb":"53",f182954c:"182","713bb917":"187","7bd58895":"257",b2b675dd:"533","3e452c7e":"637","35586d92":"1160",f905d0fe:"1342","169e66bc":"1369",b2f554cd:"1477","03abeb31":"1660","5d5620c4":"1926","82247a8b":"2026","2f98ad87":"2048",d0e73d62:"2134","258a6413":"2265","814f3328":"2535","935116ff":"2638",df1cd967:"2712","3ba497c2":"2728","853133bb":"2796","8705a681":"2863",a6aa9e1f:"3089","4fdccd00":"3118","958c0a42":"3261","104cbb75":"3316","0b218a01":"3321",c4b40215:"3457","253cd3dc":"3459","9e4087bc":"3608","1ed4142b":"3725",f85046f2:"3797","5f98988e":"3807","3bc14f20":"4026",bc0981ca:"4117",c4f5d8e4:"4195","28395ba4":"4299","765c6b61":"4535",f6c5328e:"5125",b4a95747:"5289","0085e091":"5445",c637b865:"5575",e3703649:"5679","1d5c88f5":"5901","3042343a":"5917",d9b0bdb4:"5933",e360e27f:"5990","6de0e435":"6079",ccc49370:"6103",b439faf3:"6109",a92e169d:"6332","03a88bad":"6568",a96ec439:"6731","1f61ef73":"7006","49140ced":"7591",e2e9d59a:"7755","1a4e3797":"7920",c5890d18:"8038","9eaa546a":"8059","53e18611":"8349","30d74566":"8472","6f3bb722":"8504","19fd9079":"8925",c94a68c1:"9147","2a33acc4":"9244","7b0e8dfa":"9280",c81fd975:"9310",d665a578:"9510","1be78505":"9514","04855d6d":"9544","2486267b":"9562",b3cc73c6:"9638"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,f)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)f.push(d[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var c=new Promise(((f,c)=>d=e[a]=[f,c]));f.push(d[2]=c);var b=r.p+r.u(a),t=new Error;r.l(b,(f=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var c=f&&("load"===f.type?"missing":f.type),b=f&&f.target&&f.target.src;t.message="Loading chunk "+a+" failed.\n("+c+": "+b+")",t.name="ChunkLoadError",t.type=c,t.request=b,d[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,f)=>{var d,c,[b,t,o]=f,n=0;if(b.some((a=>0!==e[a]))){for(d in t)r.o(t,d)&&(r.m[d]=t[d]);if(o)var i=o(r)}for(a&&a(f);n