@automattic/vip 4.1.6 → 4.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/dev-env.lando.template.yml.ejs +1 -1
- package/dist/bin/vip-app-deploy-token-generate.js +110 -78
- package/dist/bin/vip-app-deploy-token.js +24 -16
- package/dist/bin/vip-app-deploy-validate.js +45 -41
- package/dist/bin/vip-app-deploy.js +222 -215
- package/dist/bin/vip-app-list.js +59 -43
- package/dist/bin/vip-app.js +97 -66
- package/dist/bin/vip-backup-db.js +36 -29
- package/dist/bin/vip-backup.js +16 -9
- package/dist/bin/vip-cache-purge-url.js +93 -55
- package/dist/bin/vip-cache.js +23 -14
- package/dist/bin/vip-config-envvar-delete.js +74 -73
- package/dist/bin/vip-config-envvar-get-all.js +68 -68
- package/dist/bin/vip-config-envvar-get.js +46 -46
- package/dist/bin/vip-config-envvar-list.js +54 -57
- package/dist/bin/vip-config-envvar-set.js +102 -96
- package/dist/bin/vip-config-envvar.js +38 -24
- package/dist/bin/vip-config-software-get.js +88 -75
- package/dist/bin/vip-config-software-update.js +116 -120
- package/dist/bin/vip-config-software.js +31 -21
- package/dist/bin/vip-config.js +25 -17
- package/dist/bin/vip-db-phpmyadmin.js +40 -39
- package/dist/bin/vip-db.js +13 -12
- package/dist/bin/vip-defensive-mode-configure.js +197 -197
- package/dist/bin/vip-defensive-mode-disable.js +43 -35
- package/dist/bin/vip-defensive-mode-enable.js +47 -38
- package/dist/bin/vip-defensive-mode.js +28 -17
- package/dist/bin/vip-dev-env-create.js +147 -104
- package/dist/bin/vip-dev-env-destroy.js +48 -39
- package/dist/bin/vip-dev-env-envvar-delete.js +60 -49
- package/dist/bin/vip-dev-env-envvar-get-all.js +52 -45
- package/dist/bin/vip-dev-env-envvar-get.js +48 -37
- package/dist/bin/vip-dev-env-envvar-list.js +48 -41
- package/dist/bin/vip-dev-env-envvar-set.js +83 -70
- package/dist/bin/vip-dev-env-envvar.js +38 -23
- package/dist/bin/vip-dev-env-exec.js +81 -74
- package/dist/bin/vip-dev-env-import-media.js +34 -26
- package/dist/bin/vip-dev-env-import-sql.js +65 -51
- package/dist/bin/vip-dev-env-import.js +23 -14
- package/dist/bin/vip-dev-env-info.js +59 -50
- package/dist/bin/vip-dev-env-list.js +34 -31
- package/dist/bin/vip-dev-env-logs.js +59 -49
- package/dist/bin/vip-dev-env-purge.js +71 -63
- package/dist/bin/vip-dev-env-shell.js +82 -71
- package/dist/bin/vip-dev-env-start.js +77 -65
- package/dist/bin/vip-dev-env-stop.js +80 -74
- package/dist/bin/vip-dev-env-sync-sql.js +80 -72
- package/dist/bin/vip-dev-env-sync.js +18 -11
- package/dist/bin/vip-dev-env-update.js +93 -84
- package/dist/bin/vip-dev-env.js +25 -8
- package/dist/bin/vip-edge-workers-build.js +82 -54
- package/dist/bin/vip-edge-workers-delete.js +84 -52
- package/dist/bin/vip-edge-workers-deploy.js +186 -126
- package/dist/bin/vip-edge-workers-disable.js +75 -44
- package/dist/bin/vip-edge-workers-enable.js +86 -54
- package/dist/bin/vip-edge-workers-get.js +108 -88
- package/dist/bin/vip-edge-workers-init.js +83 -53
- package/dist/bin/vip-edge-workers-list.js +89 -54
- package/dist/bin/vip-edge-workers-new.js +98 -69
- package/dist/bin/vip-edge-workers-validate.js +123 -82
- package/dist/bin/vip-edge-workers.js +19 -6
- package/dist/bin/vip-export-sql.js +75 -69
- package/dist/bin/vip-export.js +12 -7
- package/dist/bin/vip-import-media-abort.js +99 -73
- package/dist/bin/vip-import-media-status.js +83 -51
- package/dist/bin/vip-import-media.js +165 -166
- package/dist/bin/vip-import-sql-status.js +75 -45
- package/dist/bin/vip-import-sql.js +536 -596
- package/dist/bin/vip-import-validate-files.js +122 -141
- package/dist/bin/vip-import-validate-sql.js +52 -16
- package/dist/bin/vip-import.js +16 -7
- package/dist/bin/vip-logout.js +17 -13
- package/dist/bin/vip-logs.js +209 -183
- package/dist/bin/vip-search-replace.js +85 -53
- package/dist/bin/vip-slowlogs.js +168 -147
- package/dist/bin/vip-sync.js +163 -133
- package/dist/bin/vip-whoami.js +71 -35
- package/dist/bin/vip-wp.js +506 -549
- package/dist/bin/vip.js +161 -116
- package/dist/commands/backup-db.js +183 -149
- package/dist/commands/dev-env-import-sql.js +162 -117
- package/dist/commands/dev-env-sync-sql.js +372 -330
- package/dist/commands/export-sql.js +441 -425
- package/dist/commands/phpmyadmin.js +232 -212
- package/dist/commands/wp-ssh.js +218 -187
- package/dist/lib/analytics/clients/tracks.js +84 -91
- package/dist/lib/analytics/index.js +27 -27
- package/dist/lib/api/app.js +37 -36
- package/dist/lib/api/cache-purge.js +17 -20
- package/dist/lib/api/constants.js +5 -6
- package/dist/lib/api/edge-workers.js +84 -135
- package/dist/lib/api/error-debug.js +10 -13
- package/dist/lib/api/feature-flags.js +16 -17
- package/dist/lib/api/http.js +47 -48
- package/dist/lib/api/user.js +17 -18
- package/dist/lib/api.js +107 -116
- package/dist/lib/app-logs/app-logs.js +24 -25
- package/dist/lib/app-slowlogs/app-slowlogs.js +23 -24
- package/dist/lib/app-slowlogs/types.js +2 -1
- package/dist/lib/app.js +6 -8
- package/dist/lib/backup-storage-availability/backup-storage-availability.js +119 -119
- package/dist/lib/backup-storage-availability/docker-machine-not-found-error.js +5 -6
- package/dist/lib/cli/apiConfig.js +71 -41
- package/dist/lib/cli/command.js +1120 -873
- package/dist/lib/cli/config.js +29 -29
- package/dist/lib/cli/envAlias.js +35 -50
- package/dist/lib/cli/exit.js +19 -19
- package/dist/lib/cli/format.js +172 -172
- package/dist/lib/cli/progress.js +193 -236
- package/dist/lib/cli/prompt.js +14 -15
- package/dist/lib/cli/runtime-mode.js +5 -6
- package/dist/lib/client-file-uploader.js +489 -641
- package/dist/lib/config/software.js +206 -212
- package/dist/lib/constants/dev-environment.js +40 -37
- package/dist/lib/constants/file-size.js +6 -7
- package/dist/lib/constants/vipgo.js +24 -12
- package/dist/lib/custom-deploy/custom-deploy.js +138 -120
- package/dist/lib/database.js +88 -85
- package/dist/lib/defensive-mode/api.js +41 -46
- package/dist/lib/defensive-mode/cli-helpers.js +40 -40
- package/dist/lib/dev-environment/dev-environment-cli.js +776 -735
- package/dist/lib/dev-environment/dev-environment-configuration-file.js +224 -191
- package/dist/lib/dev-environment/dev-environment-core.js +697 -732
- package/dist/lib/dev-environment/dev-environment-database.js +57 -41
- package/dist/lib/dev-environment/dev-environment-lando.js +734 -666
- package/dist/lib/dev-environment/docker-utils.js +96 -90
- package/dist/lib/dev-environment/env-vars.js +61 -59
- package/dist/lib/dev-environment/lando-loader.js +6 -7
- package/dist/lib/dev-environment/types.js +2 -1
- package/dist/lib/edge-workers/confirmation.js +42 -36
- package/dist/lib/edge-workers/deployment.js +150 -159
- package/dist/lib/edge-workers/index.js +68 -85
- package/dist/lib/edge-workers/location.js +26 -26
- package/dist/lib/edge-workers/output.js +14 -15
- package/dist/lib/edge-workers/project.js +123 -132
- package/dist/lib/edge-workers/toolchains/assemblyscript/constants.js +6 -8
- package/dist/lib/edge-workers/toolchains/assemblyscript/index.js +100 -101
- package/dist/lib/edge-workers/toolchains/assemblyscript/templates.js +31 -33
- package/dist/lib/edge-workers/toolchains/index.js +15 -15
- package/dist/lib/edge-workers/types.js +10 -38
- package/dist/lib/edge-workers/validation.js +161 -150
- package/dist/lib/env.js +16 -17
- package/dist/lib/envvar/api-delete.js +16 -18
- package/dist/lib/envvar/api-get-all.js +15 -19
- package/dist/lib/envvar/api-get.js +8 -9
- package/dist/lib/envvar/api-list.js +16 -21
- package/dist/lib/envvar/api-set.js +20 -19
- package/dist/lib/envvar/api.js +34 -29
- package/dist/lib/envvar/input.js +29 -34
- package/dist/lib/envvar/logging.js +9 -11
- package/dist/lib/envvar/read-file.js +6 -7
- package/dist/lib/http/download-file.js +76 -44
- package/dist/lib/http/proxy-agent.js +37 -40
- package/dist/lib/http/proxy-dispatcher.js +69 -71
- package/dist/lib/keychain/insecure.js +40 -36
- package/dist/lib/keychain/keychain.js +2 -1
- package/dist/lib/keychain/secure.js +16 -15
- package/dist/lib/keychain.js +22 -22
- package/dist/lib/live-backup-copy.js +117 -115
- package/dist/lib/logout.js +17 -19
- package/dist/lib/media-import/config.js +15 -14
- package/dist/lib/media-import/media-file-import.js +9 -13
- package/dist/lib/media-import/progress.js +53 -65
- package/dist/lib/media-import/status.js +241 -256
- package/dist/lib/media-import/utils.js +15 -15
- package/dist/lib/node-version-check.js +16 -16
- package/dist/lib/promise.js +16 -17
- package/dist/lib/read-file.js +48 -16
- package/dist/lib/rechallenge/client.js +37 -43
- package/dist/lib/rechallenge/errors.js +38 -37
- package/dist/lib/rechallenge/flow.js +148 -123
- package/dist/lib/rechallenge/index.js +23 -24
- package/dist/lib/rechallenge/link.js +153 -151
- package/dist/lib/rechallenge/open-browser.js +14 -17
- package/dist/lib/rechallenge/token-cache.js +83 -86
- package/dist/lib/rechallenge/types.js +5 -14
- package/dist/lib/retry.js +93 -129
- package/dist/lib/search-and-replace.js +164 -148
- package/dist/lib/site-import/db-file-import.js +12 -16
- package/dist/lib/site-import/status.js +291 -291
- package/dist/lib/token.js +86 -87
- package/dist/lib/tracker.js +51 -62
- package/dist/lib/types/graphql/rate-limit-exceeded-error.js +2 -1
- package/dist/lib/types.js +2 -1
- package/dist/lib/user-error.js +6 -8
- package/dist/lib/utils.js +81 -87
- package/dist/lib/validations/custom-deploy.js +218 -186
- package/dist/lib/validations/is-multi-site-sql-dump.js +6 -6
- package/dist/lib/validations/is-multi-site.js +83 -50
- package/dist/lib/validations/is-multisite-domain-mapped.js +92 -62
- package/dist/lib/validations/line-by-line.js +78 -46
- package/dist/lib/validations/site-type.js +59 -63
- package/dist/lib/validations/sql-insert-parser.js +415 -0
- package/dist/lib/validations/sql.js +551 -431
- package/dist/lib/validations/utils.js +27 -29
- package/dist/lib/vip-import-validate-files.js +481 -490
- package/dist/lib/wp/helpers.js +41 -45
- package/dist/lib/wp/readline.js +21 -57
- package/dist/lib/xdg-data.js +11 -12
- package/helpers/mark-cli-executable.js +9 -0
- package/node_modules/@apollo/client/CHANGELOG.md +10 -0
- package/node_modules/@apollo/client/__cjs/cache/inmemory/helpers.cjs +5 -0
- package/node_modules/@apollo/client/__cjs/cache/inmemory/helpers.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/cache/inmemory/inMemoryCache.cjs +2 -1
- package/node_modules/@apollo/client/__cjs/cache/inmemory/inMemoryCache.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/cache/inmemory/key-extractor.cjs +14 -2
- package/node_modules/@apollo/client/__cjs/cache/inmemory/key-extractor.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.cjs +16 -0
- package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.d.cts +2 -0
- package/node_modules/@apollo/client/__cjs/cache/inmemory/writeToStore.cjs +3 -2
- package/node_modules/@apollo/client/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/core/QueryInfo.cjs +9 -1
- package/node_modules/@apollo/client/__cjs/core/QueryInfo.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/core/QueryInfo.d.cts +1 -1
- package/node_modules/@apollo/client/__cjs/core/QueryManager.cjs +10 -3
- package/node_modules/@apollo/client/__cjs/core/QueryManager.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/react/hooks/useFragment.cjs.map +1 -1
- package/node_modules/@apollo/client/__cjs/react/hooks/useFragment.d.cts +42 -43
- package/node_modules/@apollo/client/__cjs/version.cjs +1 -1
- package/node_modules/@apollo/client/cache/inmemory/helpers.js +5 -0
- package/node_modules/@apollo/client/cache/inmemory/helpers.js.map +1 -1
- package/node_modules/@apollo/client/cache/inmemory/inMemoryCache.js +2 -1
- package/node_modules/@apollo/client/cache/inmemory/inMemoryCache.js.map +1 -1
- package/node_modules/@apollo/client/cache/inmemory/key-extractor.js +14 -2
- package/node_modules/@apollo/client/cache/inmemory/key-extractor.js.map +1 -1
- package/node_modules/@apollo/client/cache/inmemory/policies.d.ts +2 -0
- package/node_modules/@apollo/client/cache/inmemory/policies.js +17 -1
- package/node_modules/@apollo/client/cache/inmemory/policies.js.map +1 -1
- package/node_modules/@apollo/client/cache/inmemory/writeToStore.js +3 -2
- package/node_modules/@apollo/client/cache/inmemory/writeToStore.js.map +1 -1
- package/node_modules/@apollo/client/core/QueryInfo.d.ts +1 -1
- package/node_modules/@apollo/client/core/QueryInfo.js +10 -2
- package/node_modules/@apollo/client/core/QueryInfo.js.map +1 -1
- package/node_modules/@apollo/client/core/QueryManager.js +10 -3
- package/node_modules/@apollo/client/core/QueryManager.js.map +1 -1
- package/node_modules/@apollo/client/package.json +1 -1
- package/node_modules/@apollo/client/react/hooks/useFragment.d.ts +42 -43
- package/node_modules/@apollo/client/react/hooks/useFragment.js.map +1 -1
- package/node_modules/@apollo/client/react/hooks-compiled/useFragment.d.ts +42 -43
- package/node_modules/@apollo/client/react/hooks-compiled/useFragment.js.map +1 -1
- package/node_modules/@apollo/client/version.js +1 -1
- package/node_modules/@automattic/vip-search-replace/README.md +6 -1
- package/node_modules/@automattic/vip-search-replace/lib/index.js +46 -14
- package/node_modules/@automattic/vip-search-replace/package.json +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/zlib.d.ts +752 -0
- package/node_modules/check-disk-space/README.md +92 -32
- package/node_modules/check-disk-space/dist/check-disk-space.d.mts +58 -0
- package/node_modules/check-disk-space/dist/check-disk-space.mjs +170 -190
- package/node_modules/check-disk-space/package.json +43 -71
- package/node_modules/cpu-features/build/Makefile +2 -2
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/filesystem.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_linux_or_android.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_macos_or_iphone.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_windows.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_arm_linux_or_android.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_mips_linux_or_android.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_ppc_linux.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_freebsd.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_linux_or_android.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_macos.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_windows.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/stack_line_reader.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/string_view.o.d +1 -1
- package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpufeatures/src/binding.o.d +157 -145
- package/node_modules/cpu-features/build/Release/cpufeatures.node +0 -0
- package/node_modules/cpu-features/build/Release/obj.target/cpufeatures/src/binding.o +0 -0
- package/node_modules/cpu-features/build/Release/obj.target/cpufeatures.node +0 -0
- package/node_modules/cpu-features/build/config.gypi +100 -31
- package/node_modules/cpu-features/build/cpufeatures.target.mk +14 -14
- package/node_modules/cpu-features/build/deps/cpu_features/cpu_features.target.mk +14 -14
- package/node_modules/ssh2/lib/protocol/crypto/build/Makefile +2 -2
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d.raw +136 -0
- package/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk +14 -14
- package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
- package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
- package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
- package/node_modules/undici/package.json +3 -3
- package/node_modules/undici/types/api.d.ts +1 -1
- package/node_modules/undici/types/utility.d.ts +4 -4
- package/package.json +44 -13
- package/dist/lib/analytics/clients/client.js +0 -1
- package/dist/lib/analytics/clients/pendo.js +0 -78
- package/helpers/check-version.js +0 -16
- package/node_modules/check-disk-space/dist/check-disk-space.cjs +0 -210
- package/node_modules/check-disk-space/dist/check-disk-space.d.ts +0 -53
- package/node_modules/fetch-retry/.eslintignore +0 -1
- package/node_modules/fetch-retry/.eslintrc.yml +0 -20
- package/node_modules/fetch-retry/.github/workflows/node.js.yml +0 -32
- package/node_modules/fetch-retry/.husky/pre-commit +0 -6
- package/node_modules/fetch-retry/.nycrc.json +0 -24
- package/node_modules/fetch-retry/.travis.yml +0 -3
- package/node_modules/fetch-retry/LICENSE +0 -21
- package/node_modules/fetch-retry/README.md +0 -128
- package/node_modules/fetch-retry/dist/fetch-retry.umd.js +0 -151
- package/node_modules/fetch-retry/index.d.ts +0 -29
- package/node_modules/fetch-retry/index.js +0 -143
- package/node_modules/fetch-retry/package.json +0 -41
- package/node_modules/fetch-retry/rollup.config.js +0 -12
- package/node_modules/fetch-retry/test/.eslintrc.yml +0 -7
- package/node_modules/fetch-retry/test/integration/index.js +0 -212
- package/node_modules/fetch-retry/test/integration/mock-api/index.js +0 -42
- package/node_modules/fetch-retry/test/unit/index.js +0 -1169
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d +0 -265
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto.node.d +0 -1
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/sshcrypto.node.d +0 -1
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto/src/binding.o +0 -0
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto.node +0 -0
- package/node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node +0 -0
package/dist/lib/cli/config.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
6
|
exports.loadConfigFile = loadConfigFile;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// I don't like using synchronous versions, but until we migrate to ESM, we have to.
|
|
11
|
-
|
|
12
|
-
const debug = (0, _debug.default)('@automattic/vip:lib:cli:config');
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs")); // I don't like using synchronous versions, but until we migrate to ESM, we have to.
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const debug = (0, debug_1.default)('@automattic/vip:lib:cli:config');
|
|
13
11
|
function loadConfigFile() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
const paths = [
|
|
13
|
+
// Get `local` config first; this will only exist in dev as it's npmignore-d.
|
|
14
|
+
node_path_1.default.join(__dirname, '../../../config/config.local.json'),
|
|
15
|
+
node_path_1.default.join(__dirname, '../../../config/config.publish.json'),
|
|
16
|
+
];
|
|
17
|
+
for (const filePath of paths) {
|
|
18
|
+
try {
|
|
19
|
+
const data = node_fs_1.default.readFileSync(filePath, 'utf-8');
|
|
20
|
+
debug(`Found config file at ${filePath}`);
|
|
21
|
+
return JSON.parse(data);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const isEnoent = err instanceof Error && 'code' in err && err.code === 'ENOENT';
|
|
25
|
+
if (!isEnoent) {
|
|
26
|
+
debug(`Error reading config file at ${filePath}:`, err);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
27
29
|
}
|
|
28
|
-
|
|
29
|
-
return null;
|
|
30
|
+
return null;
|
|
30
31
|
}
|
|
31
32
|
const configFromFile = loadConfigFile();
|
|
32
33
|
if (null === configFromFile) {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
console.error('FATAL ERROR: Could not find a valid configuration file');
|
|
35
|
+
process.exit(1);
|
|
35
36
|
}
|
|
36
|
-
|
|
37
37
|
// Without this, TypeScript will export `configFromFile` as `Config | null`.
|
|
38
38
|
const exportedConfig = configFromFile;
|
|
39
|
-
|
|
39
|
+
exports.default = exportedConfig;
|
package/dist/lib/cli/envAlias.js
CHANGED
|
@@ -1,59 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.isAlias = isAlias;
|
|
5
4
|
exports.parseEnvAlias = parseEnvAlias;
|
|
6
5
|
exports.parseEnvAliasFromArgv = parseEnvAliasFromArgv;
|
|
7
6
|
function isAlias(alias) {
|
|
8
|
-
|
|
7
|
+
return /^@[A-Za-z0-9._-]+$/.test(alias);
|
|
9
8
|
}
|
|
10
9
|
function parseEnvAlias(alias) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
env = rest.join('.');
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
app,
|
|
29
|
-
env
|
|
30
|
-
};
|
|
10
|
+
if (!isAlias(alias)) {
|
|
11
|
+
throw new Error('Invalid environment alias. Aliases are in the format of @app-name or @app-name.environment-name');
|
|
12
|
+
}
|
|
13
|
+
// Remove the '@'
|
|
14
|
+
const stripped = alias.slice(1).toLowerCase();
|
|
15
|
+
// in JS, .split() with a limit discards the extra ones, so can't use it
|
|
16
|
+
// Also convert to lowercase because mixed case environment names would cause problems
|
|
17
|
+
const [app, ...rest] = stripped.split('.');
|
|
18
|
+
let env;
|
|
19
|
+
// Rejoin the env on '.' (if present), to handle instance names (env.instance-01)
|
|
20
|
+
if (rest.length) {
|
|
21
|
+
env = rest.join('.');
|
|
22
|
+
}
|
|
23
|
+
return { app, env };
|
|
31
24
|
}
|
|
32
25
|
function parseEnvAliasFromArgv(processArgv) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Splice out the alias
|
|
54
|
-
argv.splice(argv.indexOf(alias), 1);
|
|
55
|
-
return {
|
|
56
|
-
argv,
|
|
57
|
-
...parsedAlias
|
|
58
|
-
};
|
|
59
|
-
}
|
|
26
|
+
// Clone to not affect original arvg
|
|
27
|
+
const argv = processArgv.slice(0);
|
|
28
|
+
// If command included a `--` to indicate end of named args, lets only consider aliases
|
|
29
|
+
// _before_ it, so that it can be passed to other commands directly
|
|
30
|
+
const dashDashIndex = argv.indexOf('--');
|
|
31
|
+
let argsBeforeDashDash = argv;
|
|
32
|
+
if (dashDashIndex > -1) {
|
|
33
|
+
argsBeforeDashDash = argv.slice(0, dashDashIndex);
|
|
34
|
+
}
|
|
35
|
+
const alias = argsBeforeDashDash.find(arg => isAlias(arg));
|
|
36
|
+
if (!alias) {
|
|
37
|
+
return { argv };
|
|
38
|
+
}
|
|
39
|
+
// If we did have an alias, split it up into app/env
|
|
40
|
+
const parsedAlias = parseEnvAlias(alias);
|
|
41
|
+
// Splice out the alias
|
|
42
|
+
argv.splice(argv.indexOf(alias), 1);
|
|
43
|
+
return { argv, ...parsedAlias };
|
|
44
|
+
}
|
package/dist/lib/cli/exit.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
6
|
exports.withError = withError;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const debug_1 = __importDefault(require("debug"));
|
|
9
|
+
const runtime_mode_1 = require("./runtime-mode");
|
|
10
|
+
const env_1 = __importDefault(require("../../lib/env"));
|
|
10
11
|
function withError(message) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
12
|
+
const msg = message instanceof Error ? message.message : message;
|
|
13
|
+
console.error(`${chalk_1.default.red('Error: ')} ${msg.replace(/^Error:\s*/, '')}`);
|
|
14
|
+
// Debug ouput is printed below error output both for information
|
|
15
|
+
// hierarchy and to make it more likely that the user copies it to their
|
|
16
|
+
// clipboard when dragging across output.
|
|
17
|
+
console.log(`${chalk_1.default.yellow('Debug: ')} VIP-CLI v${env_1.default.app.version}, Node ${env_1.default.node.version}, ${env_1.default.os.name} ${env_1.default.os.version} ${env_1.default.os.arch}, Runtime ${(0, runtime_mode_1.getRuntimeModeLabel)()}`);
|
|
18
|
+
if (debug_1.default.names.length > 0 && message instanceof Error) {
|
|
19
|
+
console.error(chalk_1.default.yellow('Debug: '), message);
|
|
20
|
+
}
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
package/dist/lib/cli/format.js
CHANGED
|
@@ -1,195 +1,195 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports
|
|
6
|
-
exports.formatBytes = void 0;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatMetricBytes = exports.formatBytes = exports.RunningSprite = exports.RUNNING_SPRITE_GLYPHS = void 0;
|
|
7
7
|
exports.formatData = formatData;
|
|
8
|
-
exports.formatDuration = formatDuration;
|
|
9
8
|
exports.formatEnvironment = formatEnvironment;
|
|
10
|
-
exports.
|
|
11
|
-
exports.formatSearchReplaceValues = formatSearchReplaceValues;
|
|
12
|
-
exports.getGlyphForStatus = getGlyphForStatus;
|
|
9
|
+
exports.table = table;
|
|
13
10
|
exports.keyValue = keyValue;
|
|
14
11
|
exports.requoteArgs = requoteArgs;
|
|
15
|
-
exports.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
exports.capitalize = capitalize;
|
|
13
|
+
exports.getGlyphForStatus = getGlyphForStatus;
|
|
14
|
+
exports.formatSearchReplaceValues = formatSearchReplaceValues;
|
|
15
|
+
exports.formatDuration = formatDuration;
|
|
16
|
+
const plainjs_1 = require("@json2csv/plainjs");
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
20
19
|
function formatData(data, format) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
20
|
+
if (!data.length) {
|
|
21
|
+
return format === 'json' ? '[]' : '';
|
|
22
|
+
}
|
|
23
|
+
switch (format) {
|
|
24
|
+
case 'ids':
|
|
25
|
+
return ids(data);
|
|
26
|
+
case 'json':
|
|
27
|
+
return json(data);
|
|
28
|
+
case 'csv':
|
|
29
|
+
return csv(data);
|
|
30
|
+
case 'keyValue':
|
|
31
|
+
return keyValue(data);
|
|
32
|
+
case 'table':
|
|
33
|
+
default:
|
|
34
|
+
return table(data);
|
|
35
|
+
}
|
|
37
36
|
}
|
|
38
37
|
function escapeControlCharacter(character) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const codePoint = character.codePointAt(0);
|
|
39
|
+
if (codePoint === undefined) {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
return String.raw `\u${codePoint.toString(16).padStart(4, '0')}`;
|
|
44
43
|
}
|
|
45
44
|
function json(data) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
return JSON.stringify(data, null, '\t').replace(
|
|
46
|
+
// JSON.stringify already escapes C0 controls, but not DEL or C1 controls.
|
|
47
|
+
/[\u007f-\u009f]/g, escapeControlCharacter);
|
|
49
48
|
}
|
|
50
49
|
function formatEnvironment(environment) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
if ('production' === environment.toLowerCase()) {
|
|
51
|
+
return chalk_1.default.red(environment.toUpperCase());
|
|
52
|
+
}
|
|
53
|
+
return chalk_1.default.blueBright(environment.toLowerCase());
|
|
55
54
|
}
|
|
56
55
|
function ids(data) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
const fields = Object.keys(data[0]).map(key => key.toLowerCase());
|
|
57
|
+
if (0 > fields.indexOf('id')) {
|
|
58
|
+
return 'No ID field found';
|
|
59
|
+
}
|
|
60
|
+
const id = data.map(datum => datum.id);
|
|
61
|
+
return id.join(' ');
|
|
63
62
|
}
|
|
64
63
|
function csv(data) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
const fields = Object.keys(data[0]);
|
|
65
|
+
const parser = new plainjs_1.Parser({
|
|
66
|
+
formatters: {
|
|
67
|
+
header: (value) => {
|
|
68
|
+
return `"${value
|
|
69
|
+
.split(/(?=[A-Z])/)
|
|
70
|
+
.join(' ')
|
|
71
|
+
.toLowerCase()}"`;
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
fields,
|
|
75
|
+
});
|
|
76
|
+
return parser.parse(data);
|
|
75
77
|
}
|
|
76
78
|
function table(data) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
const fields = Object.keys(data[0]);
|
|
80
|
+
const dataTable = new cli_table3_1.default({
|
|
81
|
+
head: formatFields(fields),
|
|
82
|
+
style: {
|
|
83
|
+
head: ['brightBlue'],
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
data.forEach(datum => {
|
|
87
|
+
const row = fields.map(field => String(datum[field]));
|
|
88
|
+
dataTable.push(row);
|
|
89
|
+
});
|
|
90
|
+
return dataTable.toString();
|
|
89
91
|
}
|
|
90
92
|
function formatFields(fields) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
return fields.map(field => {
|
|
94
|
+
return field
|
|
95
|
+
.split(/(?=[A-Z])/)
|
|
96
|
+
.join(' ')
|
|
97
|
+
.toLowerCase();
|
|
98
|
+
});
|
|
94
99
|
}
|
|
95
100
|
function keyValue(values) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
const lines = [];
|
|
102
|
+
const pairs = values.length > 0;
|
|
103
|
+
if (pairs) {
|
|
104
|
+
lines.push('===================================');
|
|
105
|
+
}
|
|
106
|
+
for (const { key, value } of values) {
|
|
107
|
+
let formattedValue;
|
|
108
|
+
if (key.toLowerCase() === 'environment') {
|
|
109
|
+
formattedValue = formatEnvironment(value);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
formattedValue = value;
|
|
113
|
+
}
|
|
114
|
+
lines.push(`+ ${key}: ${formattedValue}`);
|
|
115
|
+
}
|
|
99
116
|
lines.push('===================================');
|
|
100
|
-
|
|
101
|
-
for (const {
|
|
102
|
-
key,
|
|
103
|
-
value
|
|
104
|
-
} of values) {
|
|
105
|
-
let formattedValue;
|
|
106
|
-
if (key.toLowerCase() === 'environment') {
|
|
107
|
-
formattedValue = formatEnvironment(value);
|
|
108
|
-
} else {
|
|
109
|
-
formattedValue = value;
|
|
110
|
-
}
|
|
111
|
-
lines.push(`+ ${key}: ${formattedValue}`);
|
|
112
|
-
}
|
|
113
|
-
lines.push('===================================');
|
|
114
|
-
return lines.join('\n');
|
|
117
|
+
return lines.join('\n');
|
|
115
118
|
}
|
|
116
119
|
function requoteArgs(args) {
|
|
117
|
-
|
|
120
|
+
return args.map(arg => `"${arg.replace(/"/g, '\\"')}"`);
|
|
118
121
|
}
|
|
119
122
|
function capitalize(str) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
if (typeof str !== 'string' || !str.length) {
|
|
124
|
+
return '';
|
|
125
|
+
}
|
|
126
|
+
return str[0].toUpperCase() + str.slice(1);
|
|
124
127
|
}
|
|
125
|
-
|
|
128
|
+
exports.RUNNING_SPRITE_GLYPHS = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
126
129
|
class RunningSprite {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
count;
|
|
131
|
+
constructor() {
|
|
132
|
+
this.count = 0;
|
|
133
|
+
}
|
|
134
|
+
next() {
|
|
135
|
+
if (++this.count >= exports.RUNNING_SPRITE_GLYPHS.length) {
|
|
136
|
+
this.count = 0;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
toString() {
|
|
140
|
+
const glyph = exports.RUNNING_SPRITE_GLYPHS[this.count];
|
|
141
|
+
this.next(); // TODO: throttle
|
|
142
|
+
return glyph;
|
|
143
|
+
}
|
|
141
144
|
}
|
|
142
145
|
exports.RunningSprite = RunningSprite;
|
|
143
146
|
function getGlyphForStatus(status, runningSprite) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
147
|
+
switch (status) {
|
|
148
|
+
case 'pending':
|
|
149
|
+
return '○';
|
|
150
|
+
case 'running':
|
|
151
|
+
return chalk_1.default.blueBright(runningSprite);
|
|
152
|
+
case 'success':
|
|
153
|
+
return chalk_1.default.green('✓');
|
|
154
|
+
case 'failed':
|
|
155
|
+
return chalk_1.default.red('✕');
|
|
156
|
+
case 'unknown':
|
|
157
|
+
return chalk_1.default.yellow('✕');
|
|
158
|
+
case 'skipped':
|
|
159
|
+
return chalk_1.default.green('-');
|
|
160
|
+
default:
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
160
163
|
}
|
|
161
|
-
|
|
162
164
|
// Format Search and Replace values to output
|
|
163
165
|
function formatSearchReplaceValues(values, message) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
// Convert single pair S-R values to arrays
|
|
167
|
+
const searchReplaceValues = typeof values === 'string' ? [values] : values;
|
|
168
|
+
return searchReplaceValues.map(pairs => {
|
|
169
|
+
// Turn each S-R pair into its own array, then trim away whitespace
|
|
170
|
+
const [from, to] = pairs.split(',').map(pair => pair.trim());
|
|
171
|
+
return message(from, to);
|
|
172
|
+
});
|
|
171
173
|
}
|
|
172
|
-
|
|
173
174
|
// Format bytes into kilobytes, megabytes, etc based on the size
|
|
174
175
|
// for historical reasons, this uses KB instead of KiB, MB instead of MiB and so on.
|
|
175
176
|
const formatBytes = (bytes, decimals = 2, bytesMultiplier = 1024, sizes = ['bytes', 'KB', 'MB', 'GB', 'TB']) => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
if (0 === bytes) {
|
|
178
|
+
return '0 Bytes';
|
|
179
|
+
}
|
|
180
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
181
|
+
const idx = Math.floor(Math.log(bytes) / Math.log(bytesMultiplier));
|
|
182
|
+
return `${parseFloat((bytes / Math.pow(bytesMultiplier, idx)).toFixed(dm))} ${sizes[idx]}`;
|
|
182
183
|
};
|
|
183
|
-
|
|
184
|
+
exports.formatBytes = formatBytes;
|
|
184
185
|
/**
|
|
185
186
|
* Format bytes in powers of 1000, based on the size
|
|
186
187
|
* This is how it's displayed on Macs
|
|
187
188
|
*/
|
|
188
|
-
exports.formatBytes = formatBytes;
|
|
189
189
|
const formatMetricBytes = (bytes, decimals = 2) => {
|
|
190
|
-
|
|
190
|
+
return (0, exports.formatBytes)(bytes, decimals, 1000);
|
|
191
191
|
};
|
|
192
|
-
|
|
192
|
+
exports.formatMetricBytes = formatMetricBytes;
|
|
193
193
|
/*
|
|
194
194
|
* Get the duration between two dates
|
|
195
195
|
*
|
|
@@ -197,30 +197,30 @@ const formatMetricBytes = (bytes, decimals = 2) => {
|
|
|
197
197
|
* @param {Date} to The end date
|
|
198
198
|
* @returns {string} The duration between the two dates
|
|
199
199
|
*/
|
|
200
|
-
exports.formatMetricBytes = formatMetricBytes;
|
|
201
200
|
function formatDuration(from, to) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
201
|
+
const millisecondsPerSecond = 1000;
|
|
202
|
+
const millisecondsPerMinute = 60 * millisecondsPerSecond;
|
|
203
|
+
const millisecondsPerHour = 60 * millisecondsPerMinute;
|
|
204
|
+
const millisecondsPerDay = 24 * millisecondsPerHour;
|
|
205
|
+
const duration = to.getTime() - from.getTime();
|
|
206
|
+
if (duration < 1000)
|
|
207
|
+
return '0 second';
|
|
208
|
+
const days = Math.floor(duration / millisecondsPerDay);
|
|
209
|
+
const hours = Math.floor((duration % millisecondsPerDay) / millisecondsPerHour);
|
|
210
|
+
const minutes = Math.floor((duration % millisecondsPerHour) / millisecondsPerMinute);
|
|
211
|
+
const seconds = Math.floor((duration % millisecondsPerMinute) / millisecondsPerSecond);
|
|
212
|
+
let durationString = '';
|
|
213
|
+
if (days > 0) {
|
|
214
|
+
durationString += `${days} day${days > 1 ? 's' : ''} `;
|
|
215
|
+
}
|
|
216
|
+
if (hours > 0) {
|
|
217
|
+
durationString += `${hours} hour${hours > 1 ? 's' : ''} `;
|
|
218
|
+
}
|
|
219
|
+
if (minutes > 0) {
|
|
220
|
+
durationString += `${minutes} minute${minutes > 1 ? 's' : ''} `;
|
|
221
|
+
}
|
|
222
|
+
if (seconds > 0) {
|
|
223
|
+
durationString += `${seconds} second${seconds > 1 ? 's' : ''}`;
|
|
224
|
+
}
|
|
225
|
+
return durationString.trim();
|
|
226
|
+
}
|