From 8ff1a795d1a843930d8dc26ff66f6f077d033406 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 13 Feb 2021 14:37:18 +0200 Subject: [PATCH] new cli command handling --- package-lock.json | 458 ++------------------------------------------- package.json | 4 +- src/cli.ts | 465 +++++++++++++++++++++++----------------------- 3 files changed, 256 insertions(+), 671 deletions(-) diff --git a/package-lock.json b/package-lock.json index 664de8e..56bdbff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@squeebot/cli", - "version": "3.0.0-1", + "version": "3.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -31,7 +31,9 @@ } }, "@squeebot/core": { - "version": "3.0.0", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@squeebot/core/-/core-3.2.0.tgz", + "integrity": "sha512-GOKjVqtWHrdDgLlXuosUMk42HiqXWlQz5dfuwfNNWDQDjALiVs65hvMAcerFlqXhxL2oKdlw4rWPRCZg6m8GTA==", "requires": { "dateformat": "^4.0.0", "fs-extra": "^9.0.1", @@ -39,352 +41,6 @@ "tar": "^6.0.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@types/dateformat": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz", - "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==" - }, - "@types/fs-extra": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.4.tgz", - "integrity": "sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==", - "requires": { - "@types/node": "*" - } - }, - "@types/minipass": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz", - "integrity": "sha512-wuzZksN4w4kyfoOv/dlpov4NOunwutLA/q7uc00xU02ZyUY+aoM5PWIXEKBMnm0NHd4a+N71BMjq+x7+2Af1fg==", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "14.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.9.tgz", - "integrity": "sha512-JsoLXFppG62tWTklIoO4knA+oDTYsmqWxHRvd4lpmfQRNhX6osheUOWETP2jMoV/2bEHuMra8Pp3Dmo/stBFcw==" - }, - "@types/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==" - }, - "@types/tar": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/tar/-/tar-4.0.4.tgz", - "integrity": "sha512-0Xv+xcmkTsOZdIF4yCnd7RkOOyfyqPaqJ7RZFKnwdxfDbkN3eAAE9sHl8zJFqBz4VhxolW9EErbjR1oyH7jK2A==", - "requires": { - "@types/minipass": "*", - "@types/node": "*" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "dateformat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.0.0.tgz", - "integrity": "sha512-zpKyDYpeePyYGJp2HhRxLHlA+jZQNjt+MwmcVmLxCIECeC4Ks3TI3yk/CSMKylbnCJ5htonfOugYtRRTpyoHow==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^1.0.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", - "requires": { - "has": "^1.0.3" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "requires": { - "yallist": "^4.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } - }, "semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", @@ -392,99 +48,6 @@ "requires": { "lru-cache": "^6.0.0" } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "requires": { - "tslib": "^1.8.1" - } - }, - "typescript": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", - "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==" - }, - "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, @@ -640,6 +203,11 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "dateformat": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", + "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -800,6 +368,14 @@ } } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", diff --git a/package.json b/package.json index a8837ff..adb1e41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@squeebot/cli", - "version": "3.0.2", + "version": "3.1.0", "description": "Squeebot v3 runtime, environments and configuration", "main": "dist/squeebot.js", "bin": { @@ -29,7 +29,7 @@ "typescript": "^4.0.5" }, "dependencies": { - "@squeebot/core": "^3.1.0", + "@squeebot/core": "^3.2.0", "fs-extra": "^9.0.1", "node-watch": "^0.7.0", "tar": "^6.0.5", diff --git a/src/cli.ts b/src/cli.ts index 05d978c..9204ae3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,59 +3,76 @@ import { IRepository } from '@squeebot/core/lib/plugin/repository'; import { ReadLine } from 'readline'; import { Squeebot } from './core'; -export class SqueebotCLI { - constructor(private bot: Squeebot) {} +declare type Executable = (...args: string[]) => Promise; - private async checkUpdate(repo: IRepository): Promise { - const updatable = await this.bot.repositoryManager.checkForUpdates(repo); - if (updatable.length) { - logger.log('[%s] The following plugins can be updated:', repo.name, - updatable.map((u) => u.name).join(', ')); - } else { - logger.log('[%s] All plugins are up-to-date!', repo.name); - } +class CLICommand { + constructor( + public name: string, + public func: Executable, + public sub: CLICommand[], + public after?: (returned: any, ...args: string[]) => Promise) {} + + public getSub(name: string): CLICommand | undefined { + return this.sub.find(c => c.name.startsWith(name)); } - private async repositoryCommand(...args: any[]): Promise { - const help = 'repository add | update | remove | plugins | list'; - if (!args[0] || (args[0] === 'help' && args[0] !== 'list')) { - logger.log(help); - return; + /** + * Executes a sub-command or, if not found, the current one. + * @param args Command arguments + */ + public async execute(args: string[]): Promise { + if (args[0]) { + const subl = this.getSub(args[0]); + if (subl) { + const rv1 = await subl.execute(args.slice(1)); + if (this.after) { + return this.after.call(this, rv1, ...args); + } + return rv1; + } } - switch (args[0]) { - case 'a': - case 'i': - case 'add': - case 'install': - if (!args[1]) { - logger.error('URL is required'); - return; + const rv2 = await this.func.call(this, ...args); + if (this.after) { + return this.after.call(this, rv2, ...args); + } + return rv2; + } +} + +function cmd(name: string, func: Executable, sub: CLICommand[] = []): CLICommand { + return new CLICommand(name, func, sub); +} + +export class SqueebotCLI { + private inspector = false; + private cmds: CLICommand[] = [ + // Repository management + cmd('repository', async (...args: string[]): Promise => { + logger.log('Usage: repository add | update | remove | plugins | list'); + }, [ + cmd('install', async (...args: string[]): Promise => { + if (!args.length) { + throw new Error('URL is required'); } - for (const urlp of args.slice(1)) { + for (const urlp of args) { const repo = await this.bot.repositoryManager.installRepository(urlp); logger.log('Installed repository %s!', repo.name); } - break; - case 'r': - case 'rem': - case 'remove': - case 'uninstall': - if (!args[1]) { - logger.error('Name is required'); - return; + }), + cmd('remove', async (...args: string[]): Promise => { + if (!args.length) { + throw new Error('Name is required'); } - for (const namep of args.slice(1)) { + for (const namep of args) { await this.bot.repositoryManager.uninstallRepository(namep); logger.log('Installed repository %s.', namep); } - break; - case 'u': - case 'upd': - case 'update': - if (!args[1]) { + }), + cmd('update', async (...args: string[]): Promise => { + if (!args.length) { const repolist = this.bot.repositoryManager.getAll(); for (const repo of repolist) { await this.checkUpdate(repo); @@ -63,124 +80,93 @@ export class SqueebotCLI { return; } - for (const namep of args.slice(1)) { + for (const namep of args) { const repo = this.bot.repositoryManager.getRepoByName(namep); if (!repo) { - logger.error('No such repository "%s" found.', namep); - return; + throw new Error(`No such repository "${namep}" found.`); } await this.checkUpdate(repo); } - break; - case 'list': + }), + cmd('plugins', async (...args: string[]): Promise => { + if (!args.length) { + throw new Error('Name is required'); + } + const repo = this.bot.repositoryManager.getRepoByName(args[0]); + if (!repo) { + throw new Error(`No such repository "${args[0]}" found.`); + } + logger.log('List of plugins in %s:', args[0], + repo.plugins.map(x => `${x.name}@${x.version}`).join(', ')); + }), + cmd('list', async (...args: string[]): Promise => { const repos = this.bot.repositoryManager.getAll(); logger.log('List of installed repositories:'); for (const repo of repos) { logger.log('%s: (%s) with %d plugins | Date: %s', repo.name, repo.url, repo.plugins.length, new Date(repo.created * 1000).toDateString()); } - break; - case 'plugins': { - if (!args[1]) { - logger.error('Name is required'); - return; - } - const repo = this.bot.repositoryManager.getRepoByName(args[1]); - if (!repo) { - logger.error('No such repository "%s" found.', args[1]); - return; - } - logger.log('List of plugins in %s:', args[1], - repo.plugins.map(x => `${x.name}@${x.version}`).join(', ')); - break; - } - default: - logger.log(help); - } - } - - private async pluginCommand(...args: any[]): Promise { - const help = 'plugin install | update | uninstall | enable | disable | start | restart | stop | list | running []'; - if (!args[0] || args[0] === 'help' || (!args[1] && args[0] !== 'list' && args[0] !== 'running')) { - logger.log(help); - return; - } - - switch (args[0]) { - case 'i': - case 'u': - case 'install': - case 'update': - for (const name of args.slice(1)) { + }), + ]), + // Plugin management + cmd('plugin', async (...args: string[]): Promise => { + logger.log('Usage: plugin install | update | remove | enable | disable | load | restart | kill | list | running []'); + }, [ + cmd('update', async (...args: string[]): Promise => { + for (const name of args) { const mf = await this.bot.repositoryManager.installPlugin(name); logger.log('Installed plugin %s version %s!', mf.name, mf.version); } - break; - case 'uninst': - case 'remove': - case 'uninstall': - for (const name of args.slice(1)) { - await this.bot.repositoryManager.uninstallPlugin(name); - logger.log('Uninstalled plugin %s.', name); - } - break; - case 'list': - logger.log('Installed plugins:', - this.bot.pluginManager.availablePlugins.map((mf) => mf.name).join(', ')); - break; - case 'running': - logger.log('Currently running plugins:', - this.bot.pluginManager.getLoaded().map((p) => p.manifest.name).join(', ')); - break; - case 's': - case 'run': - case 'load': - case 'start': - for (const name of args.slice(1)) { + }), + cmd('restart', async (...args: string[]): Promise => { + for (const name of args) { const plugin = this.bot.pluginManager.getAvailableByName(name); if (!plugin) { - logger.error('"%s" is not available. Maybe try installing it? plugin install', name, name); - return; - } - - await this.bot.pluginManager.load(plugin); - logger.log('Started plugin "%s" successfully.', name); - } - break; - case 'restart': - case 'reload': - for (const name of args.slice(1)) { - const plugin = this.bot.pluginManager.getAvailableByName(name); - if (!plugin) { - logger.error('"%s" is not available. Maybe try installing it? plugin install', name, name); - return; + throw new Error(`"${name}" is not available. Maybe try installing it? plugin install ${name}`); } logger.log('Scheduling restart for', name); await this.bot.pluginManager.restart(plugin); } - break; - case 'stop': - case 'kill': - case 'unload': - for (const name of args.slice(1)) { + }), + cmd('remove', async (...args: string[]): Promise => { + for (const name of args) { + await this.bot.repositoryManager.uninstallPlugin(name); + logger.log('Uninstalled plugin %s.', name); + } + }), + cmd('running', async (...args: string[]): Promise => { + logger.log('Currently running plugins:', + this.bot.pluginManager.getLoaded().map((p) => p.manifest.name).join(', ')); + }), + cmd('load', async (...args: string[]): Promise => { + for (const name of args) { + const plugin = this.bot.pluginManager.getAvailableByName(name); + if (!plugin) { + throw new Error(`"${name}" is not available. Maybe try installing it? plugin install`); + } + + await this.bot.pluginManager.load(plugin); + logger.log('Loaded plugin "%s" successfully.', name); + } + }), + cmd('kill', async (...args: string[]): Promise => { + for (const name of args) { if (!this.bot.pluginManager.getAvailableByName(name)) { - logger.error('No such plugin is available.'); - return; + throw new Error('No such plugin is available.'); } logger.log('Stopping plugin', name); this.bot.stream.emitTo(name, 'pluginUnload', name); } - break; - case 'enable': - for (const name of args.slice(1)) { + }), + cmd('enable', async (...args: string[]): Promise => { + for (const name of args) { if (!this.bot.pluginManager.getAvailableByName(name)) { - logger.error('No such plugin "%s" is available.', name); - return; + throw new Error(`No such plugin "${name}" found.`); } logger.log('Enabling plugin', name); @@ -196,12 +182,11 @@ export class SqueebotCLI { } await this.bot.config.save(); - break; - case 'disable': - for (const name of args.slice(1)) { + }), + cmd('disable', async (...args: string[]): Promise => { + for (const name of args) { if (!this.bot.pluginManager.getAvailableByName(name)) { - logger.error('No such plugin "%s" is available.', name); - return; + throw new Error(`No such plugin "${name}" found.`); } logger.log('Disabling plugin', name); @@ -217,163 +202,187 @@ export class SqueebotCLI { } await this.bot.config.save(); - break; - default: - logger.log(help); - } - } - - private async channelCommand(...args: any[]): Promise { - const help = 'channel new | del | list | addplugin | delplugin [] []'; - if (!args[0] || args[0] === 'help' || (!args[1] && args[0] !== 'list')) { - logger.log(help); - return; - } - - switch (args[0]) { - case 'new': - if (this.bot.channelManager.getChannelByName(args[1])) { - logger.error('A channel by that name already exists!'); - break; + }), + cmd('list', async (...args: string[]): Promise => { + logger.log('Installed plugins:', + this.bot.pluginManager.availablePlugins.map((mf) => mf.name).join(', ')); + }), + ]), + // Channel management, with an "after" handler + new CLICommand('channel', async (...args: string[]): Promise => { + logger.log('Usage: channel new | del | list | addplugin | delplugin [] []'); + }, [ + cmd('new', async (...args: string[]): Promise => { + if (this.bot.channelManager.getChannelByName(args[0])) { + throw new Error('A channel by that name already exists!'); } this.bot.channelManager.addChannel({ - name: args[1], + name: args[0], plugins: [], enabled: true, }); logger.log('Channel added!'); - break; - case 'del': - case 'delete': - case 'remove': - for (const name of args.slice(1)) { + }), + cmd('remove', async (...args: string[]): Promise => { + for (const name of args) { const chan = this.bot.channelManager.getChannelByName(name); if (!chan) { - logger.error('No such channel "%s" exists!', name); - return; + throw new Error(`No such channel "${name}" found.`); } this.bot.channelManager.removeChannel(chan); logger.log('Channel "%s" removed!', name); } - break; - case 'addp': - case 'addplugin': - const chan1 = this.bot.channelManager.getChannelByName(args[1]); + }), + cmd('addplugin', async (...args: string[]): Promise => { + const chan1 = this.bot.channelManager.getChannelByName(args[0]); if (!chan1) { - logger.error('No such channel exists!'); - return; + throw new Error('No such channel exists!'); } - if (!args[2]) { - logger.error('A plugin name is required.'); - return; + if (!args[1]) { + throw new Error('A plugin name is required.'); } - for (const name of args.slice(2)) { + for (const name of args.slice(1)) { if (chan1.plugins.indexOf(name) === -1) { chan1.plugins.push(name); } logger.log('Plugin "%s" added to channel!', name); } - break; - case 'list': - logger.log('Channels:\n', this.bot.channelManager.getAll().map((chan) => { - return ` => ${chan.name}: ${chan.plugins.join(', ')} (${chan.enabled ? 'enabled' : 'disabled'})`; - }).join('\n')); - break; - case 'remp': - case 'delp': - case 'remplugin': - case 'delplugin': - const chan2 = this.bot.channelManager.getChannelByName(args[1]); + }), + cmd('delplugin', async (...args: string[]): Promise => { + const chan2 = this.bot.channelManager.getChannelByName(args[0]); if (!chan2) { - logger.error('No such channel exists!'); - return; + throw new Error('No such channel exists!'); } - if (!args[2]) { - logger.error('A plugin name is required.'); - return; + if (!args[1]) { + throw new Error('A plugin name is required.'); } - for (const name of args.slice(2)) { - const idx = chan2.plugins.indexOf(args[2]); + for (const name of args.slice(1)) { + const idx = chan2.plugins.indexOf(name); if (idx !== -1) { chan2.plugins.splice(idx, 1); } logger.log('Plugin "%s" removed from channel!', name); } - - break; - case 'enable': - for (const name of args.slice(1)) { + }), + cmd('enable', async (...args: string[]): Promise => { + for (const name of args) { const chan = this.bot.channelManager.getChannelByName(name); if (!chan) { - logger.error('No such channel "%s" exists!', name); - return; + throw new Error(`No such channel "${name}" found.`); } chan.enabled = true; logger.log('Channel "%s" enabled!', name); } - break; - case 'disable': - for (const name of args.slice(1)) { + }), + cmd('disable', async (...args: string[]): Promise => { + for (const name of args) { const chan = this.bot.channelManager.getChannelByName(name); if (!chan) { - logger.error('No such channel "%s" exists!', name); - return; + throw new Error(`No such channel "${name}" found.`); } chan.enabled = false; logger.log('Channel "%s" disabled!', name); } - break; - } + }), + cmd('list', async (...args: string[]): Promise => { + logger.log('Channels:\n', this.bot.channelManager.getAll().map((chan) => { + return ` => ${chan.name}: ${chan.plugins.join(', ')} (${chan.enabled ? 'enabled' : 'disabled'})`; + }).join('\n')); + }), + ], async (r: any, ...args: string[]): Promise => { + // Don't save when we just printed help or a list + if (!args.length || 'list'.startsWith(args[0])) { + return r; + } + // Save current channel configuration + this.bot.config.config.channels = this.bot.channelManager.getAll(); + await this.bot.config.save(); + return r; + }), + // Enter inspector mode. Every line entered will be executed as JavaScript. + cmd('inspector', async (...args: string[]): Promise => { + this.inspector = true; + logger.warn('You have entered the JavaScript Inspector!'); + console.log('Squeebot is available via "sb" or "this.bot".'); + console.log('Type "exit" or "quit" to leave the inspector mode.'); + }), + ]; - this.bot.config.config.channels = this.bot.channelManager.getAll(); - await this.bot.config.save(); + constructor(private bot: Squeebot) {} + + private getCommand(name: string): CLICommand | undefined { + return this.cmds.find(c => c.name.startsWith(name)); + } + + private async checkUpdate(repo: IRepository): Promise { + const updatable = await this.bot.repositoryManager.checkForUpdates(repo); + if (updatable.length) { + logger.log('[%s] The following plugins can be updated:', repo.name, + updatable.map((u) => u.name).join(', ')); + } else { + logger.log('[%s] All plugins are up-to-date!', repo.name); + } + } + + private async sequentialExecute(cmds: string[][]): Promise { + for (const argv of cmds) { + if (!argv[0]) { + logger.log('Available CLI Commands:', this.cmds + .map(c => `(${c.name.charAt(0)})${c.name.substr(1)}`) + .join(', ')); + continue; + } + + const clicmd = this.getCommand(argv[0]); + if (!clicmd) { + continue; + } + + await clicmd.execute(argv.slice(1)); + } } public attach(rl: ReadLine): void { rl.on('line', (line: string) => { - const split = line.split(' '); - - if (!split[0]) { + // Inspector mode + if (this.inspector) { + if (line.startsWith('exit') || line.startsWith('quit')) { + this.inspector = false; + logger.warn('You have exited the JavaScript Inspector!'); + return; + } + const sb = this.bot; + try { + // tslint:disable-next-line: no-eval + console.log(eval(line)); + } catch (e) { + console.error(e.stack); + } return; } - switch (split[0]) { - case 'r': - case 'repo': - case 'repository': - this.repositoryCommand(...split.slice(1)).catch( - e => logger.error(e.message)); - break; - case 'p': - case 'pl': - case 'plugin': - this.pluginCommand(...split.slice(1)).catch( - e => logger.error(e.message)); - break; - case 'c': - case 'chan': - case 'channel': - this.channelCommand(...split.slice(1)).catch( - e => logger.error(e.message)); - break; - case 'stop': - case 'exit': - case 'quit': - case 'shutdown': - this.bot.shutdown(); - break; - } + // Executing commands in order. If previous command fails, the rest won't execute. + const executeList = line.split('&&'); + const toRun = executeList.map(subline => { + return subline + .replace(/\s+/g, ' ') + .replace(/^\s+|\s+$/, '') + .split(' ') + .map(l => l.replace(',', '')); + }); + + this.sequentialExecute(toRun).catch(e => logger.error(e.message)); }); } }