@mikeyt23/node-cli-utils 1.4.1 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +45 -87
  2. package/dist/cjs/GitUtility.d.ts +7 -0
  3. package/dist/cjs/GitUtility.d.ts.map +1 -0
  4. package/dist/cjs/GitUtility.js +49 -0
  5. package/dist/cjs/NodeCliUtilsConfig.d.ts +21 -0
  6. package/dist/cjs/NodeCliUtilsConfig.d.ts.map +1 -0
  7. package/dist/cjs/NodeCliUtilsConfig.js +41 -0
  8. package/dist/cjs/TarballUtility.d.ts +63 -0
  9. package/dist/cjs/TarballUtility.d.ts.map +1 -0
  10. package/dist/cjs/TarballUtility.js +143 -0
  11. package/dist/cjs/certUtils.d.ts +66 -0
  12. package/dist/cjs/certUtils.d.ts.map +1 -0
  13. package/dist/cjs/certUtils.js +283 -0
  14. package/dist/cjs/dbMigrationUtils.d.ts +39 -0
  15. package/dist/cjs/dbMigrationUtils.d.ts.map +1 -0
  16. package/dist/cjs/dbMigrationUtils.js +195 -0
  17. package/dist/cjs/dotnetUtils.d.ts +25 -0
  18. package/dist/cjs/dotnetUtils.d.ts.map +1 -0
  19. package/dist/cjs/dotnetUtils.js +61 -0
  20. package/dist/cjs/esmSpecific.d.mts +7 -0
  21. package/dist/cjs/esmSpecific.d.mts.map +1 -0
  22. package/dist/cjs/esmSpecific.mjs +15 -0
  23. package/dist/cjs/generalUtils.d.ts +565 -0
  24. package/dist/cjs/generalUtils.d.ts.map +1 -0
  25. package/dist/cjs/generalUtils.js +1068 -0
  26. package/dist/cjs/generalUtilsInternal.d.ts +15 -0
  27. package/dist/cjs/generalUtilsInternal.d.ts.map +1 -0
  28. package/dist/cjs/generalUtilsInternal.js +317 -0
  29. package/dist/cjs/hostsUtils.d.ts +16 -0
  30. package/dist/cjs/hostsUtils.d.ts.map +1 -0
  31. package/dist/cjs/hostsUtils.js +82 -0
  32. package/dist/cjs/index.d.ts +4 -0
  33. package/dist/cjs/index.d.ts.map +1 -0
  34. package/dist/cjs/index.js +25 -0
  35. package/dist/cjs/package.json +5 -0
  36. package/dist/cjs/runWhileParentAlive.d.ts +2 -0
  37. package/dist/cjs/runWhileParentAlive.d.ts.map +1 -0
  38. package/dist/cjs/runWhileParentAlive.js +159 -0
  39. package/dist/esm/GitUtility.d.ts +7 -0
  40. package/dist/esm/GitUtility.d.ts.map +1 -0
  41. package/dist/esm/GitUtility.js +43 -0
  42. package/dist/esm/NodeCliUtilsConfig.d.ts +21 -0
  43. package/dist/esm/NodeCliUtilsConfig.d.ts.map +1 -0
  44. package/dist/esm/NodeCliUtilsConfig.js +35 -0
  45. package/dist/esm/TarballUtility.d.ts +63 -0
  46. package/dist/esm/TarballUtility.d.ts.map +1 -0
  47. package/dist/esm/TarballUtility.js +139 -0
  48. package/dist/esm/certUtils.d.ts +66 -0
  49. package/dist/esm/certUtils.d.ts.map +1 -0
  50. package/dist/esm/certUtils.js +271 -0
  51. package/dist/esm/dbMigrationUtils.d.ts +39 -0
  52. package/dist/esm/dbMigrationUtils.d.ts.map +1 -0
  53. package/dist/esm/dbMigrationUtils.js +184 -0
  54. package/dist/esm/dotnetUtils.d.ts +25 -0
  55. package/dist/esm/dotnetUtils.d.ts.map +1 -0
  56. package/dist/esm/dotnetUtils.js +54 -0
  57. package/dist/esm/esmSpecific.d.mts +7 -0
  58. package/dist/esm/esmSpecific.d.mts.map +1 -0
  59. package/dist/esm/esmSpecific.mjs +11 -0
  60. package/dist/esm/generalUtils.d.ts +565 -0
  61. package/dist/esm/generalUtils.d.ts.map +1 -0
  62. package/dist/esm/generalUtils.js +976 -0
  63. package/dist/esm/generalUtilsInternal.d.ts +15 -0
  64. package/dist/esm/generalUtilsInternal.d.ts.map +1 -0
  65. package/dist/esm/generalUtilsInternal.js +278 -0
  66. package/dist/esm/hostsUtils.d.ts +16 -0
  67. package/dist/esm/hostsUtils.d.ts.map +1 -0
  68. package/dist/esm/hostsUtils.js +69 -0
  69. package/dist/esm/index.d.ts +4 -0
  70. package/dist/esm/index.d.ts.map +1 -0
  71. package/dist/esm/index.js +4 -0
  72. package/dist/esm/runWhileParentAlive.d.ts +2 -0
  73. package/dist/esm/runWhileParentAlive.d.ts.map +1 -0
  74. package/dist/esm/runWhileParentAlive.js +151 -0
  75. package/package.json +69 -10
  76. package/index.js +0 -627
@@ -0,0 +1,1068 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.isPortAvailable = exports.getPlatformCode = exports.isDirectorySync = exports.isDirectory = exports.getHostname = exports.ExtendedError = exports.humanizeTime = exports.getPowershellHackArgs = exports.powershellHackPrefix = exports.logTable = exports.escapeStringForRegex = exports.findFilesRecursively = exports.deleteEnvIfExists = exports.sortDictionaryByKeyAsc = exports.filterDictionary = exports.copyModifiedEnv = exports.overwriteEnvFile = exports.copyNewEnvValues = exports.getConfirmationExample = exports.getConfirmation = exports.askQuestion = exports.isDockerRunning = exports.whichSync = exports.which = exports.isPlatformLinux = exports.isPlatformMac = exports.isPlatformWindows = exports.simpleSpawnAsync = exports.simpleSpawnSync = exports.simpleCmdAsync = exports.simpleCmdSync = exports.stringToLines = exports.stringToNonEmptyLines = exports.spawnDockerCompose = exports.isDockerComposeProjectNameValid = exports.requireValidPath = exports.requireString = exports.copyDirectoryContents = exports.emptyDirectory = exports.mkdirpSync = exports.mkdirp = exports.ensureDirectory = exports.spawnAsyncLongRunning = exports.spawnAsync = exports.sleep = exports.SimpleSpawnError = exports.SpawnError = exports.trace = exports.logIf = exports.log = void 0;
30
+ exports.Emoji = exports.yellow = exports.purple = exports.gray = exports.cyan = exports.green = exports.red = exports.color = exports.AnsiColor = exports.stripShellMetaCharacters = exports.hasWhitespace = exports.isValidDirName = exports.collapseWhitespace = exports.withRetryAsync = exports.getNormalizedError = exports.getRequiredEnvVar = void 0;
31
+ const node_fs_1 = __importDefault(require("node:fs"));
32
+ const promises_1 = __importDefault(require("node:fs/promises"));
33
+ const node_os_1 = require("node:os");
34
+ const node_path_1 = __importStar(require("node:path"));
35
+ const readline = __importStar(require("readline"));
36
+ const net = __importStar(require("net"));
37
+ const NodeCliUtilsConfig_js_1 = require("./NodeCliUtilsConfig.js");
38
+ const generalUtilsInternal_js_1 = require("./generalUtilsInternal.js");
39
+ const dockerComposeCommandsThatSupportDetached = ['exec', 'logs', 'ps', 'restart', 'run', 'start', 'stop', 'up'];
40
+ /**
41
+ * Just a wrapper for console.log() to type less.
42
+ * @param data The data to log
43
+ * @param moreData More data to log
44
+ */
45
+ function log(data, ...moreData) {
46
+ console.log(data, ...moreData);
47
+ }
48
+ exports.log = log;
49
+ /**
50
+ * Log conditionally. Useful for methods that have an option to either suppress output or to show it when it normally isn't.
51
+ * @param data The data to log
52
+ * @param moreData More data to log
53
+ */
54
+ function logIf(shouldLog, data, ...moreData) {
55
+ if (shouldLog) {
56
+ console.log(data, ...moreData);
57
+ }
58
+ }
59
+ exports.logIf = logIf;
60
+ /**
61
+ * Wrapper for console.log() that is suppressed if NodeCliUtilsConfig.logEnabled is false.
62
+ * @param data The data to log
63
+ * @param moreData More data to log
64
+ */
65
+ function trace(data, ...moreData) {
66
+ if (NodeCliUtilsConfig_js_1.config.traceEnabled) {
67
+ const prefix = `[TRACE]`;
68
+ console.log(prefix, data, ...moreData);
69
+ }
70
+ }
71
+ exports.trace = trace;
72
+ /**
73
+ * Error throw by {@link spawnAsync} when the spawned process exits with a non-zero exit code and options.throwOnNonZero is true.
74
+ *
75
+ * Contains a {@link SpawnResult} with the exit code, stdout, stderr, and error (if any).
76
+ */
77
+ class SpawnError extends Error {
78
+ constructor(message, result) {
79
+ super(message);
80
+ this.result = result;
81
+ }
82
+ }
83
+ exports.SpawnError = SpawnError;
84
+ /**
85
+ * Error throw by {@link simpleSpawnSync} and {@link simpleCmdSync} when the spawned process exits with a non-zero exit code and throwOnNonZero param is true (the default).
86
+ *
87
+ * Contains a {@link SimpleSpawnResult} with the exit code, stdout, stderr, and error (if any) in addition to stdoutLines, which is stdout split into lines from stdout that weren't empty.
88
+ */
89
+ class SimpleSpawnError extends Error {
90
+ constructor(message, result) {
91
+ super(message);
92
+ this.result = result;
93
+ }
94
+ }
95
+ exports.SimpleSpawnError = SimpleSpawnError;
96
+ /**
97
+ * Sleeps for the specified number of milliseconds.
98
+ * @param ms The number of milliseconds to sleep
99
+ * @returns A Promise that resolves after the specified number of milliseconds
100
+ */
101
+ async function sleep(ms) {
102
+ return new Promise((resolve) => {
103
+ setTimeout(resolve, ms);
104
+ });
105
+ }
106
+ exports.sleep = sleep;
107
+ /**
108
+ * This is a wrapper function for NodeJS spawn. Defaults stdio to inherit so that output is visible in the console,
109
+ * but note that this means stdout and stderr will not be available in the returned SpawnResult. To hide the output
110
+ * from the console but collect the stdout and stderr in the SpawnResult, use stdio: 'pipe'.
111
+ *
112
+ * When spawning long-running processes, use {@link spawnAsyncLongRunning} instead so that unexpected
113
+ * termination of the parent process will not orphan the child process tree on windows.
114
+ *
115
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
116
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
117
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
118
+ * @param command The command to spawn
119
+ * @param args The arguments to pass to the command
120
+ * @param options The options to pass to the command
121
+ * @returns A Promise that resolves to a {@link SpawnResult}
122
+ */
123
+ async function spawnAsync(command, args, options) {
124
+ return (0, generalUtilsInternal_js_1.spawnAsyncInternal)(command, args !== null && args !== void 0 ? args : [], options);
125
+ }
126
+ exports.spawnAsync = spawnAsync;
127
+ /**
128
+ * Use this alternate spawn wrapper instead of {@link spawnAsync} when spawning long-running processes to
129
+ * avoid orphaned child process trees on Windows.
130
+ *
131
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
132
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
133
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
134
+ * @param command The command to spawn
135
+ * @param args The arguments to pass to the command
136
+ * @param cwd The current working directory to run the command from - defaults to process.cwd()
137
+ * @returns A Promise that resolves to a {@link SpawnResult}
138
+ */
139
+ async function spawnAsyncLongRunning(command, args, cwd) {
140
+ return (0, generalUtilsInternal_js_1.spawnAsyncInternal)(command, args !== null && args !== void 0 ? args : [], { cwd: cwd, isLongRunning: true });
141
+ }
142
+ exports.spawnAsyncLongRunning = spawnAsyncLongRunning;
143
+ /**
144
+ * Ensure the directory exists. Similar to `mkdir -p` (creates parent directories if they don't exist).
145
+ * @param dir The directory to ensure exists. If it does not exist, it will be created.
146
+ */
147
+ async function ensureDirectory(dir) {
148
+ return await mkdirp(dir);
149
+ }
150
+ exports.ensureDirectory = ensureDirectory;
151
+ /**
152
+ * Create a directory. Will create parent directory structure if it don't exist. Similar to `mkdir -p`.
153
+ * @param dir The directory to create.
154
+ */
155
+ async function mkdirp(dir) {
156
+ requireString('dir', dir);
157
+ await promises_1.default.mkdir(dir, { recursive: true });
158
+ }
159
+ exports.mkdirp = mkdirp;
160
+ /**
161
+ * Create a directory. Will create parent directory structure if it don't exist. Similar to `mkdir -p`.
162
+ * @param dir The directory to create.
163
+ */
164
+ async function mkdirpSync(dir) {
165
+ requireString('dir', dir);
166
+ node_fs_1.default.mkdirSync(dir, { recursive: true });
167
+ }
168
+ exports.mkdirpSync = mkdirpSync;
169
+ /**
170
+ * Empties a directory of all files and subdirectories.
171
+ *
172
+ * Optionally skips files and directories at the top level.
173
+ * @param directoryToEmpty The directory to empty.
174
+ * @param fileAndDirectoryNamesToSkip An optional array of file and directory names to skip, but only at the top level of the directoryToEmpty.
175
+ */
176
+ async function emptyDirectory(directoryToEmpty, fileAndDirectoryNamesToSkip) {
177
+ requireString('directoryToEmpty', directoryToEmpty);
178
+ if (!node_fs_1.default.existsSync(directoryToEmpty)) {
179
+ trace(`directoryToEmpty does not exist - creating directory ${directoryToEmpty}`);
180
+ await mkdirp(directoryToEmpty);
181
+ return;
182
+ }
183
+ if (!node_fs_1.default.lstatSync(directoryToEmpty).isDirectory()) {
184
+ throw new Error(`directoryToEmpty is not a directory: ${directoryToEmpty}`);
185
+ }
186
+ // Add some guardrails to prevent accidentally emptying the wrong directory
187
+ const absolutePath = node_path_1.default.resolve(directoryToEmpty);
188
+ log(`emptying directory: ${absolutePath}`);
189
+ if (!absolutePath.startsWith(process.cwd())) {
190
+ throw new Error(`directoryToEmpty must be a child of the current working directory: ${directoryToEmpty}`);
191
+ }
192
+ if (absolutePath === process.cwd()) {
193
+ throw new Error(`directoryToEmpty cannot be the current working directory: ${directoryToEmpty}`);
194
+ }
195
+ const dir = await promises_1.default.opendir(directoryToEmpty, { encoding: 'utf-8' });
196
+ if (fileAndDirectoryNamesToSkip && !Array.isArray(fileAndDirectoryNamesToSkip)) {
197
+ throw new Error('fileAndDirectoryNamesToSkip must be an array');
198
+ }
199
+ let dirEntry = await dir.read();
200
+ while (dirEntry) {
201
+ if (fileAndDirectoryNamesToSkip === null || fileAndDirectoryNamesToSkip === void 0 ? void 0 : fileAndDirectoryNamesToSkip.includes(dirEntry.name)) {
202
+ dirEntry = await dir.read();
203
+ continue;
204
+ }
205
+ const direntPath = node_path_1.default.join(directoryToEmpty, dirEntry.name);
206
+ if (dirEntry.isDirectory()) {
207
+ await promises_1.default.rm(direntPath, { recursive: true });
208
+ }
209
+ else {
210
+ await promises_1.default.unlink(direntPath);
211
+ }
212
+ dirEntry = await dir.read();
213
+ }
214
+ await dir.close();
215
+ }
216
+ exports.emptyDirectory = emptyDirectory;
217
+ /**
218
+ * Copies the contents of a directory to another directory (not including the top-level directory itself).
219
+ *
220
+ * If the destination directory does not exist, it will be created.
221
+ * @param sourceDirectory Directory to copy from
222
+ * @param destinationDirectory Directory to copy to
223
+ */
224
+ async function copyDirectoryContents(sourceDirectory, destinationDirectory) {
225
+ requireString('sourceDirectory', sourceDirectory);
226
+ requireString('destinationDirectory', destinationDirectory);
227
+ if (!node_fs_1.default.existsSync(sourceDirectory)) {
228
+ throw new Error(`sourceDirectory directory does not exist: ${sourceDirectory}`);
229
+ }
230
+ if (!node_fs_1.default.lstatSync(sourceDirectory).isDirectory()) {
231
+ throw new Error(`sourceDirectory is not a directory: ${sourceDirectory}`);
232
+ }
233
+ if (!node_fs_1.default.existsSync(destinationDirectory)) {
234
+ await mkdirp(destinationDirectory);
235
+ }
236
+ if (!node_fs_1.default.lstatSync(destinationDirectory).isDirectory()) {
237
+ throw new Error(`destinationDirectory is not a directory: ${destinationDirectory}`);
238
+ }
239
+ const dir = await promises_1.default.opendir(sourceDirectory, { encoding: 'utf-8' });
240
+ let dirEntry = await dir.read();
241
+ while (dirEntry) {
242
+ const sourcePath = node_path_1.default.join(sourceDirectory, dirEntry.name);
243
+ const destPath = node_path_1.default.join(destinationDirectory, dirEntry.name);
244
+ if (dirEntry.isDirectory()) {
245
+ await copyDirectoryContents(sourcePath, destPath);
246
+ }
247
+ else {
248
+ await promises_1.default.copyFile(sourcePath, destPath);
249
+ }
250
+ dirEntry = await dir.read();
251
+ }
252
+ }
253
+ exports.copyDirectoryContents = copyDirectoryContents;
254
+ /**
255
+ * Helper method to validate that a non-falsy and non-empty value is provided for a parameter that should be a string.
256
+ * @param paramName The name of the parameter to be used in the error message
257
+ * @param paramValue The value of the parameter
258
+ */
259
+ function requireString(paramName, paramValue) {
260
+ if (paramValue === undefined || paramValue === null || paramValue === '' || typeof paramValue !== 'string' || paramValue.trim() === '') {
261
+ throw new Error(`Required param '${paramName}' is missing`);
262
+ }
263
+ }
264
+ exports.requireString = requireString;
265
+ /**
266
+ * Helper method to validate that the path actually exists for the provided value.
267
+ * @param paramName The name of the parameter, for logging purposes
268
+ * @param paramValue The value of the parameter
269
+ */
270
+ function requireValidPath(paramName, paramValue) {
271
+ requireString(paramName, paramValue);
272
+ if (!node_fs_1.default.existsSync(paramValue)) {
273
+ throw new Error(`Invalid or nonexistent path provided for param '${paramName}': ${paramValue}`);
274
+ }
275
+ }
276
+ exports.requireValidPath = requireValidPath;
277
+ /**
278
+ * Project names must contain only lowercase letters, decimal digits, dashes, and underscores, and must begin with a lowercase letter or decimal digit.
279
+ *
280
+ * See https://docs.docker.com/compose/environment-variables/envvars/#compose_project_name.
281
+ * @param projectName The string to validate
282
+ * @returns `true` if it's a valid docker compose project name and `false` otherwise
283
+ */
284
+ function isDockerComposeProjectNameValid(projectName) {
285
+ requireString('projectName', projectName);
286
+ // Ensure first char is a lowercase letter or digit
287
+ if (!/^[a-z0-9]/.test(projectName[0])) {
288
+ return false;
289
+ }
290
+ // Ensure the rest of the chars are only lowercase letters, digits, dashes and underscores
291
+ return /^[a-z0-9-_]+$/.test(projectName);
292
+ }
293
+ exports.isDockerComposeProjectNameValid = isDockerComposeProjectNameValid;
294
+ /**
295
+ * For docker compose commands, see https://docs.docker.com/compose/reference/. For available options for this wrapper function, see {@link DockerComposeOptions}.
296
+ *
297
+ * The current working directory will be the directory of the {@link dockerComposePath} unless specified in the options. This ensures relative paths in the
298
+ * docker compose file will be relative to itself by default.
299
+ *
300
+ * See {@link DockerComposeOptions.projectName} for info on where to locate your docker compose file and how to specify the docker project name.
301
+ * @param dockerComposePath Path to docker-compose.yml
302
+ * @param dockerComposeCommand The docker-compose command to run
303
+ * @param options {@link DockerComposeOptions} to use, including additional arguments to pass to the docker compose command and the project name
304
+ */
305
+ async function spawnDockerCompose(dockerComposePath, dockerComposeCommand, options) {
306
+ requireValidPath('dockerComposePath', dockerComposePath);
307
+ requireString('dockerComposeCommand', dockerComposeCommand);
308
+ if (options === null || options === void 0 ? void 0 : options.cwd) {
309
+ requireValidPath('cwd', options.cwd);
310
+ }
311
+ if ((options === null || options === void 0 ? void 0 : options.projectName) && !isDockerComposeProjectNameValid(options.projectName)) {
312
+ throw new Error('Invalid docker compose project name specified for the projectName param. Project names must contain only lowercase letters, decimal digits, dashes, and underscores, and must begin with a lowercase letter or decimal digit.');
313
+ }
314
+ if ((options === null || options === void 0 ? void 0 : options.profile) && !/[a-zA-Z0-9][a-zA-Z0-9_.-]+/.test(options.profile)) {
315
+ throw new Error('Invalid profile option - must match regex: [a-zA-Z0-9][a-zA-Z0-9_.-]+');
316
+ }
317
+ if (!await isDockerRunning()) {
318
+ throw new Error('Docker is not running');
319
+ }
320
+ const defaultOptions = { args: [], attached: false, projectName: undefined, cwd: undefined };
321
+ const mergedOptions = { ...defaultOptions, ...options };
322
+ const dockerComposeDir = node_path_1.default.dirname(dockerComposePath);
323
+ const dockerComposeFilename = node_path_1.default.basename(dockerComposePath);
324
+ if (!mergedOptions.cwd) {
325
+ mergedOptions.cwd = dockerComposeDir;
326
+ }
327
+ let spawnArgs = ['compose', '-f', mergedOptions.cwd ? node_path_1.default.resolve(dockerComposePath) : dockerComposeFilename];
328
+ if (mergedOptions.projectName) {
329
+ spawnArgs.push('--project-name', mergedOptions.projectName);
330
+ }
331
+ if (mergedOptions.profile) {
332
+ spawnArgs.push('--profile', mergedOptions.profile);
333
+ }
334
+ spawnArgs.push(dockerComposeCommand);
335
+ if (!mergedOptions.attached && dockerComposeCommandsThatSupportDetached.includes(dockerComposeCommand)) {
336
+ spawnArgs.push('--detach');
337
+ }
338
+ if (mergedOptions.args) {
339
+ spawnArgs = spawnArgs.concat(mergedOptions.args);
340
+ }
341
+ trace(`running command in ${mergedOptions.cwd}: docker ${spawnArgs.join(' ')}`);
342
+ const longRunning = dockerComposeCommandsThatSupportDetached.includes(dockerComposeCommand) && (options === null || options === void 0 ? void 0 : options.attached) === true;
343
+ trace(`docker compose command will be configured to use long running options: ${longRunning}`);
344
+ const spawnOptions = {
345
+ cwd: mergedOptions.cwd,
346
+ shell: isPlatformWindows(),
347
+ isLongRunning: longRunning
348
+ };
349
+ const spawnResult = await (0, generalUtilsInternal_js_1.spawnAsyncInternal)('docker', spawnArgs, spawnOptions);
350
+ if (spawnResult.code !== 0) {
351
+ throw new Error(`docker compose command failed with code ${spawnResult.code}`);
352
+ }
353
+ }
354
+ exports.spawnDockerCompose = spawnDockerCompose;
355
+ /**
356
+ * Splits a string into lines, removing `\n` and `\r` characters. Does not return empty lines. Also see {@link stringToLines}.
357
+ * @param str String to split into lines
358
+ * @returns An array of lines from the string, with empty lines removed
359
+ */
360
+ function stringToNonEmptyLines(str) {
361
+ if (!str) {
362
+ return [];
363
+ }
364
+ return str.split('\n').filter(line => line === null || line === void 0 ? void 0 : line.trim()).map(line => line.replace('\r', ''));
365
+ }
366
+ exports.stringToNonEmptyLines = stringToNonEmptyLines;
367
+ /**
368
+ * Splits a string into lines, removing `\n` and `\r` characters. Returns empty lines. Also see {@link stringToNonEmptyLines}.
369
+ * @param str String to split into lines
370
+ * @returns An array of lines from the string, with empty lines removed
371
+ */
372
+ function stringToLines(str) {
373
+ if (!str) {
374
+ return [];
375
+ }
376
+ return str.split('\n').map(line => line.replace('\r', ''));
377
+ }
378
+ exports.stringToLines = stringToLines;
379
+ /**
380
+ * Runs the requested command using NodeJS spawnSync wrapped in an outer Windows CMD.exe command and returns the result with stdout split into lines.
381
+ *
382
+ * Use this for simple quick commands that don't require a lot of control.
383
+ *
384
+ * For commands that aren't Windows and CMD specific, use {@link simpleSpawnSync}.
385
+ *
386
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
387
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
388
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
389
+ * @param command Command to run
390
+ * @param args Arguments to pass to the command
391
+ * @returns An object with the status code, stdout, stderr, and error (if any)
392
+ * @throws {@link SimpleSpawnError} if the command fails and throwOnNonZero is true
393
+ */
394
+ function simpleCmdSync(command, args, throwOnNonZero = true) {
395
+ if (!isPlatformWindows()) {
396
+ throw new Error('getCmdResult is only supported on Windows');
397
+ }
398
+ // Was previously spawning 'cmd' directly with params '/D', '/S', '/C' - but we may as well let NodeJS do the work of escaping args to work correctly with cmd
399
+ return (0, generalUtilsInternal_js_1.simpleSpawnSyncInternal)(command, args, throwOnNonZero, true);
400
+ }
401
+ exports.simpleCmdSync = simpleCmdSync;
402
+ /**
403
+ * Runs the requested command using {@link spawnAsync} wrapped in an outer Windows CMD.exe command and returns the result with stdout split into lines.
404
+ *
405
+ * Use this for simple quick commands that don't require a lot of control.
406
+ *
407
+ * For commands that aren't Windows and CMD specific, use {@link simpleSpawnAsync}.
408
+ *
409
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
410
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
411
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
412
+ * @param command Command to run
413
+ * @param args Arguments to pass to the command
414
+ * @returns An object with the status code, stdout, stderr, and error (if any)
415
+ * @throws {@link SimpleSpawnError} if the command fails and throwOnNonZero is true
416
+ */
417
+ async function simpleCmdAsync(command, args, throwOnNonZero = true) {
418
+ if (!isPlatformWindows()) {
419
+ throw new Error('getCmdResult is only supported on Windows');
420
+ }
421
+ // Was previously spawning 'cmd' directly with params '/D', '/S', '/C' - but we may as well let NodeJS do the work of escaping args to work correctly with cmd
422
+ return await (0, generalUtilsInternal_js_1.simpleSpawnAsyncInternal)(command, args, throwOnNonZero, true);
423
+ }
424
+ exports.simpleCmdAsync = simpleCmdAsync;
425
+ /**
426
+ * Runs the requested command using NodeJS spawnSync and returns the result with stdout split into lines.
427
+ *
428
+ * Use this for simple quick commands that don't require a lot of control.
429
+ *
430
+ * For commands that are Windows and CMD specific, use {@link simpleCmdSync}.
431
+ *
432
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
433
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
434
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
435
+ * @param command Command to run
436
+ * @param args Arguments to pass to the command
437
+ * @returns An object with the status code, stdout, stderr, and error (if any)
438
+ * @throws {@link SimpleSpawnError} if the command fails and throwOnNonZero is true
439
+ */
440
+ function simpleSpawnSync(command, args, throwOnNonZero = true) {
441
+ return (0, generalUtilsInternal_js_1.simpleSpawnSyncInternal)(command, args, throwOnNonZero);
442
+ }
443
+ exports.simpleSpawnSync = simpleSpawnSync;
444
+ /**
445
+ * Runs the requested command using {@link spawnAsync} and returns the result with stdout split into lines.
446
+ *
447
+ * Use this for simple quick commands that don't require a lot of control.
448
+ *
449
+ * For commands that are Windows and CMD specific, use {@link simpleCmdSync}.
450
+ *
451
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
452
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
453
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
454
+ * @param command Command to run
455
+ * @param args Arguments to pass to the command
456
+ * @returns An object with the status code, stdout, stderr, and error (if any)
457
+ * @throws {@link SimpleSpawnError} if the command fails and throwOnNonZero is true
458
+ */
459
+ async function simpleSpawnAsync(command, args, throwOnNonZero = true) {
460
+ return await (0, generalUtilsInternal_js_1.simpleSpawnAsyncInternal)(command, args, throwOnNonZero);
461
+ }
462
+ exports.simpleSpawnAsync = simpleSpawnAsync;
463
+ /**
464
+ * @returns `true` if platform() is 'win32', `false` otherwise
465
+ */
466
+ function isPlatformWindows() {
467
+ return (0, node_os_1.platform)() === 'win32';
468
+ }
469
+ exports.isPlatformWindows = isPlatformWindows;
470
+ /**
471
+ *
472
+ * @returns `true` if platform() is 'darwin', `false` otherwise
473
+ */
474
+ function isPlatformMac() {
475
+ return (0, node_os_1.platform)() === 'darwin';
476
+ }
477
+ exports.isPlatformMac = isPlatformMac;
478
+ /**
479
+ *
480
+ * @returns `true` if {@link isPlatformWindows} and {@link isPlatformMac} are both `false, otherwise returns `true`
481
+ */
482
+ function isPlatformLinux() {
483
+ return !isPlatformWindows() && !isPlatformMac();
484
+ }
485
+ exports.isPlatformLinux = isPlatformLinux;
486
+ /**
487
+ * This is a cross-platform method to get the location of a system command. Useful for checking if software
488
+ * is installed, where it's installed and whether there are multiple locations.
489
+ * @param commandName The name of the command to find
490
+ * @returns The location of the command, any additional locations, and an error if one occurred
491
+ */
492
+ async function which(commandName) {
493
+ return (0, generalUtilsInternal_js_1.whichInternal)(commandName, simpleCmdAsync, simpleSpawnAsync);
494
+ }
495
+ exports.which = which;
496
+ /**
497
+ * This is a cross-platform method to get the location of a system command. Useful for checking if software
498
+ * is installed, where it's installed and whether there are multiple locations.
499
+ * @param commandName The name of the command to find
500
+ * @returns The location of the command, any additional locations, and an error if one occurred
501
+ */
502
+ function whichSync(commandName) {
503
+ return (0, generalUtilsInternal_js_1.whichInternal)(commandName, simpleCmdSync, simpleSpawnSync);
504
+ }
505
+ exports.whichSync = whichSync;
506
+ /**
507
+ * First checks if docker is installed and if not immediately returns false. Then runs the `docker info`
508
+ * command and looks for "error during connect" in the output to determine if docker is running.
509
+ * @returns `true` if docker is installed and running, `false` otherwise
510
+ */
511
+ async function isDockerRunning() {
512
+ if (!whichSync('docker').location) {
513
+ trace('whichSync will not check if docker is running because docker does not appear to be installed - returning false');
514
+ return false;
515
+ }
516
+ try {
517
+ const result = await simpleSpawnAsync('docker', ['info']);
518
+ return !result.stdout.includes('error during connect');
519
+ }
520
+ catch (err) {
521
+ return false;
522
+ }
523
+ }
524
+ exports.isDockerRunning = isDockerRunning;
525
+ /**
526
+ * Uses built-in NodeJS readline to ask a question and return the user's answer.
527
+ * @param query The question to ask
528
+ * @returns A Promise that resolves to the user's answer
529
+ */
530
+ function askQuestion(query) {
531
+ const rl = readline.createInterface({
532
+ input: process.stdin,
533
+ output: process.stdout,
534
+ });
535
+ return new Promise(resolve => rl.question(`\n${query}\n`, ans => {
536
+ rl.close();
537
+ resolve(ans);
538
+ }));
539
+ }
540
+ exports.askQuestion = askQuestion;
541
+ /**
542
+ * A simple CLI prompt using the built-in NodeJS readline functionality to ask for confirmation.
543
+ * @param question The question to ask
544
+ * @returns A Promise that resolves to true if the user answers 'y' or 'yes', false otherwise
545
+ */
546
+ function getConfirmation(question) {
547
+ const rl = readline.createInterface({
548
+ input: process.stdin,
549
+ output: process.stdout,
550
+ });
551
+ return new Promise((resolve) => {
552
+ rl.question(`\n ${Emoji.RedQuestion} ${question}\n ${Emoji.RightArrow} Proceed? (yes/no): `, (answer) => {
553
+ rl.close();
554
+ const confirmed = answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
555
+ log(confirmed ? ` ${Emoji.GreenCheck} Proceeding\n` : ` ${Emoji.RedX} Aborting\n`);
556
+ resolve(confirmed);
557
+ });
558
+ });
559
+ }
560
+ exports.getConfirmation = getConfirmation;
561
+ /**
562
+ * Example of using {@link getConfirmation}.
563
+ */
564
+ async function getConfirmationExample() {
565
+ if (await getConfirmation('Do you even?')) {
566
+ log('you do even');
567
+ }
568
+ else {
569
+ log('you do not even');
570
+ }
571
+ }
572
+ exports.getConfirmationExample = getConfirmationExample;
573
+ /**
574
+ * Copy entries from a source .env file to a destination .env file for which the destination .env file does not already have entries.
575
+ * If the destination .env file does not exist, it will be created and populated with the source .env file's values.
576
+ *
577
+ * This is useful for copying values from a .env.template file to a root .env file.
578
+ *
579
+ * For copying root .env files to other locations, use {@link overwriteEnvFile}.
580
+ * @param sourcePath The path to the source .env file such as a `.env.template` file (use {@link overwriteEnvFile} for copying root .env files to other locations)
581
+ * @param destinationPath The path to the destination .env file, such as the root .env file
582
+ */
583
+ async function copyNewEnvValues(sourcePath, destinationPath) {
584
+ await (0, generalUtilsInternal_js_1.copyEnv)(sourcePath, destinationPath, false);
585
+ }
586
+ exports.copyNewEnvValues = copyNewEnvValues;
587
+ /**
588
+ * Copy entries from a source .env file to a destination .env file, overwriting any existing entries in the destination .env file.
589
+ * If the destination .env file does not exist, it will be created and populated with the source .env file's values.
590
+ *
591
+ * This is useful for copying values from a root .env file to additional locations (server, client, docker-compose directory, etc.)
592
+ * throughout your solution so you only have to manage one .env file.
593
+ *
594
+ * Note that this does not delete any existing entries in the destination .env file, which is useful if you have additional entries in
595
+ * the destination .env file that you don't want to overwrite.
596
+ *
597
+ * For copying .env.template files to root .env files, use {@link copyNewEnvValues}.
598
+ * @param sourcePath The path to the source .env file such as a root .env file (use {@link copyNewEnvValues} for .env.template files)
599
+ * @param destinationPath The path to the destination .env file
600
+ * @param suppressAddKeysMessages If true, messages about adding missing keys will not be logged (useful if you're always calling {@link copyModifiedEnv} after this call)
601
+ */
602
+ async function overwriteEnvFile(sourcePath, destinationPath, suppressAddKeysMessages = false) {
603
+ await (0, generalUtilsInternal_js_1.copyEnv)(sourcePath, destinationPath, true, suppressAddKeysMessages);
604
+ }
605
+ exports.overwriteEnvFile = overwriteEnvFile;
606
+ /**
607
+ * Copy entries from a source .env file to a destination .env file, but only for the keys specified in keepKeys.
608
+ * Will also modify entries in the destination .env file as specified in modifyEntries.
609
+ * @param sourcePath The path to the source .env file
610
+ * @param destinationPath The path to the destination .env file
611
+ * @param keepKeys The keys to keep from the source .env file
612
+ * @param modifyEntries The entries to modify in the destination .env file
613
+ */
614
+ async function copyModifiedEnv(sourcePath, destinationPath, keepKeys, modifyEntries) {
615
+ requireValidPath('sourcePath', sourcePath);
616
+ const destPathDir = node_path_1.default.dirname(destinationPath);
617
+ if (!node_fs_1.default.existsSync(destPathDir)) {
618
+ await ensureDirectory(destPathDir);
619
+ }
620
+ const sourceDict = (0, generalUtilsInternal_js_1.getEnvAsDictionary)(sourcePath);
621
+ const newDict = filterDictionary(sourceDict, key => keepKeys.includes(key));
622
+ if (modifyEntries && Object.keys(modifyEntries).length > 0) {
623
+ for (const [key, value] of Object.entries(modifyEntries)) {
624
+ newDict[key] = value;
625
+ }
626
+ }
627
+ const newSortedDict = sortDictionaryByKeyAsc(newDict);
628
+ const newEnvFileContent = (0, generalUtilsInternal_js_1.dictionaryToEnvFileString)(newSortedDict);
629
+ await promises_1.default.writeFile(destinationPath, newEnvFileContent);
630
+ }
631
+ exports.copyModifiedEnv = copyModifiedEnv;
632
+ /**
633
+ * Filters a dictionary by key.
634
+ * @param dict The dictionary to filter
635
+ * @param predicate A function that returns true if the key should be included in the filtered dictionary
636
+ * @returns A new dictionary with only the keys that passed the predicate
637
+ */
638
+ function filterDictionary(dict, predicate) {
639
+ // Notes to self:
640
+ // - The second param of reduce is the initial value of the accumulator
641
+ // - Reduce processes each element of the array and returns the accumulator for the next iteration
642
+ // - In our case, the accumulator is a new dictionary that we're building up
643
+ return Object.keys(dict)
644
+ .filter(predicate)
645
+ .reduce((accumulator, key) => {
646
+ accumulator[key] = dict[key];
647
+ return accumulator;
648
+ }, {});
649
+ }
650
+ exports.filterDictionary = filterDictionary;
651
+ /**
652
+ * Sorts a dictionary by key in ascending order.
653
+ * @param dict The dictionary to sort
654
+ * @returns A new dictionary sorted by key in ascending order
655
+ */
656
+ function sortDictionaryByKeyAsc(dict) {
657
+ const newSortedDict = Object.entries(dict).sort((a, b) => {
658
+ if (a < b) {
659
+ return -1;
660
+ }
661
+ if (a > b) {
662
+ return 1;
663
+ }
664
+ return 0;
665
+ });
666
+ return Object.fromEntries(newSortedDict);
667
+ }
668
+ exports.sortDictionaryByKeyAsc = sortDictionaryByKeyAsc;
669
+ /**
670
+ * Helper method to delete a .env file if it exists.
671
+ * @param envPath The path to the .env file to delete
672
+ */
673
+ async function deleteEnvIfExists(envPath) {
674
+ // Just protecting ourselves from accidentally deleting something we didn't mean to
675
+ if (envPath.endsWith('.env') === false) {
676
+ throw new Error(`envPath must end with '.env': ${envPath}`);
677
+ }
678
+ // Using fsp.unlink will throw an error if it's a directory
679
+ if (node_fs_1.default.existsSync(envPath)) {
680
+ await promises_1.default.unlink(envPath);
681
+ }
682
+ }
683
+ exports.deleteEnvIfExists = deleteEnvIfExists;
684
+ /**
685
+ * Searches a directory recursively for files that match the specified pattern.
686
+ * The filenamePattern is a simple text string with asterisks (*) for wildcards.
687
+ * @param dir The directory to find files in
688
+ * @param filenamePattern The pattern to match files against
689
+ * @param options Specify a max depth to search, defaults to 5
690
+ * @returns A Promise that resolves to an array of file paths that match the pattern
691
+ */
692
+ async function findFilesRecursively(dir, filenamePattern, options) {
693
+ (0, generalUtilsInternal_js_1.validateFindFilesRecursivelyParams)(dir, filenamePattern);
694
+ const defaultOptions = { maxDepth: 5, excludeDirectoryNames: [], returnForwardSlashRelativePaths: false };
695
+ const mergedOptions = { ...defaultOptions, ...options };
696
+ // Convert the pattern to a regex
697
+ const regex = new RegExp('^' + filenamePattern.split(/\*+/).map(escapeStringForRegex).join('.*') + '$');
698
+ const matches = [];
699
+ // Recursive function to search within directories
700
+ async function searchDirectory(directory, depth) {
701
+ var _a;
702
+ if (depth > mergedOptions.maxDepth)
703
+ return;
704
+ const entries = await promises_1.default.readdir(directory, { withFileTypes: true });
705
+ for (const entry of entries) {
706
+ const fullPath = (0, node_path_1.resolve)(directory, entry.name);
707
+ if (entry.isDirectory()) {
708
+ // Check if directory is in the exclude list
709
+ if (!((_a = mergedOptions.excludeDirectoryNames) === null || _a === void 0 ? void 0 : _a.includes(entry.name))) {
710
+ await searchDirectory(fullPath, depth + 1);
711
+ }
712
+ }
713
+ else if (entry.isFile() && regex.test(entry.name)) {
714
+ if (mergedOptions.returnForwardSlashRelativePaths) {
715
+ matches.push(node_path_1.default.relative(dir, fullPath).replace(/\\/g, '/'));
716
+ }
717
+ else {
718
+ matches.push(fullPath);
719
+ }
720
+ }
721
+ }
722
+ }
723
+ await searchDirectory(dir, 1); // Start search from the first depth
724
+ return matches;
725
+ }
726
+ exports.findFilesRecursively = findFilesRecursively;
727
+ /** Utility function to escape a string for use within regex */
728
+ function escapeStringForRegex(str) {
729
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
730
+ }
731
+ exports.escapeStringForRegex = escapeStringForRegex;
732
+ /**
733
+ * Logs the provided 2-dimensional string array as a formatted table.
734
+ *
735
+ * @param data 2-dimensional string array where the first row is the column headers
736
+ * @example
737
+ *
738
+ * logTable([
739
+ * ['Name', 'Age', 'Country'],
740
+ * ['Alice', '28', 'USA'],
741
+ * ['Bob', '22', 'Canada']
742
+ * ])
743
+ */
744
+ function logTable(data) {
745
+ if (data.length === 0 || data[0].length === 0)
746
+ return;
747
+ const numColumns = data[0].length;
748
+ const columnWidths = [];
749
+ for (let i = 0; i < numColumns; i++) {
750
+ columnWidths[i] = Math.max(...data.map(row => { var _a; return ((_a = row[i]) === null || _a === void 0 ? void 0 : _a.length) || 0; }));
751
+ }
752
+ const lineSeparator = columnWidths.map(width => '-'.repeat(width)).join(' + ');
753
+ for (let i = 0; i < data.length; i++) {
754
+ const paddedRowArray = data[i].map((cell, colIdx) => cell.padEnd(columnWidths[colIdx], ' '));
755
+ log(paddedRowArray.join(' | '));
756
+ if (i === 0)
757
+ log(lineSeparator);
758
+ }
759
+ }
760
+ exports.logTable = logTable;
761
+ /**
762
+ * See {@link getPowershellHackArgs}.
763
+ */
764
+ exports.powershellHackPrefix = `$env:PSModulePath = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine'); `;
765
+ /**
766
+ * Powershell doesn't load the system PSModulePath when running in a non-interactive shell.
767
+ * This is a workaround to set the PSModulePath environment variable to the system value before running a powershell command.
768
+ *
769
+ * **Warning:** Do NOT use this for generating commands dynamically from user input as it could be used to execute arbitrary code.
770
+ * This is meant solely for building up known commands that are not made up of unsanitized user input, and only at compile time.
771
+ * See {@link winInstallCert} and {@link winUninstallCert} for examples of taking user input and inserting it safely into known commands.
772
+ * @param command The powershell command to run
773
+ * @returns An array of arguments to pass to {@link spawnAsync} with the "powershell" command as the first argument
774
+ */
775
+ function getPowershellHackArgs(command) {
776
+ return ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', `${exports.powershellHackPrefix}${command}`];
777
+ }
778
+ exports.getPowershellHackArgs = getPowershellHackArgs;
779
+ /**
780
+ * Returns a humanized string representation of the number of milliseconds using ms, seconds, minutes, or hours.
781
+ * @param milliseconds The number of milliseconds to humanize
782
+ * @returns A humanized string representation of the number
783
+ */
784
+ function humanizeTime(milliseconds) {
785
+ let value;
786
+ let unit;
787
+ if (milliseconds < 1000) {
788
+ return `${milliseconds} ms`;
789
+ }
790
+ if (milliseconds < 60000) {
791
+ value = milliseconds / 1000;
792
+ unit = 'second';
793
+ }
794
+ else if (milliseconds < 3600000) {
795
+ value = milliseconds / 60000;
796
+ unit = 'minute';
797
+ }
798
+ else {
799
+ value = milliseconds / 3600000;
800
+ unit = 'hour';
801
+ }
802
+ let stringValue = value.toFixed(2);
803
+ if (stringValue.endsWith('.00')) {
804
+ stringValue = stringValue.slice(0, -3);
805
+ }
806
+ else if (stringValue.endsWith('0')) {
807
+ stringValue = stringValue.slice(0, -1);
808
+ }
809
+ if (stringValue !== '1') {
810
+ unit += 's';
811
+ }
812
+ return `${stringValue} ${unit}`;
813
+ }
814
+ exports.humanizeTime = humanizeTime;
815
+ class ExtendedError extends Error {
816
+ constructor(message, innerError) {
817
+ super(message);
818
+ this.innerError = innerError !== null && innerError !== void 0 ? innerError : null;
819
+ Object.setPrototypeOf(this, ExtendedError.prototype);
820
+ }
821
+ }
822
+ exports.ExtendedError = ExtendedError;
823
+ function getHostname(url) {
824
+ requireString('url', url);
825
+ trace(`attempting to convert url to hostname: ${url}`);
826
+ try {
827
+ const encodedUrl = encodeURI(url);
828
+ const parsedUrl = new URL(encodedUrl.startsWith('http') ? encodedUrl : 'https://' + encodedUrl);
829
+ trace(`parsed url: ${parsedUrl}`);
830
+ return parsedUrl.hostname;
831
+ }
832
+ catch (e) {
833
+ throw new ExtendedError("Invalid URL", e);
834
+ }
835
+ }
836
+ exports.getHostname = getHostname;
837
+ async function isDirectory(path) {
838
+ try {
839
+ const stats = await promises_1.default.stat(path);
840
+ return stats.isDirectory();
841
+ }
842
+ catch (err) {
843
+ trace('error checking idDirectory (returning false)', err);
844
+ return false;
845
+ }
846
+ }
847
+ exports.isDirectory = isDirectory;
848
+ function isDirectorySync(path) {
849
+ try {
850
+ const stats = node_fs_1.default.statSync(path);
851
+ return stats.isDirectory();
852
+ }
853
+ catch (err) {
854
+ trace('error checking idDirectory (returning false)', err);
855
+ return false;
856
+ }
857
+ }
858
+ exports.isDirectorySync = isDirectorySync;
859
+ /**
860
+ * This is a somewhat naive method but is useful if you rarely or never deal with unusual operating systems.
861
+ * @returns `win`, `mac` or `linux`
862
+ */
863
+ function getPlatformCode() {
864
+ if (isPlatformWindows()) {
865
+ return 'win';
866
+ }
867
+ if (isPlatformMac()) {
868
+ return 'mac';
869
+ }
870
+ if (isPlatformLinux()) {
871
+ return 'linux';
872
+ }
873
+ throw new Error('unrecognized platform: ' + (0, node_os_1.platform)());
874
+ }
875
+ exports.getPlatformCode = getPlatformCode;
876
+ /**
877
+ * Tries connecting to a port to see if it's being listened on or not. It's likely that this won't work in a lot of scenarios, so use it at your own risk.
878
+ * @param port The port to check
879
+ * @returns `true` if the port is available, `false` otherwise
880
+ */
881
+ async function isPortAvailable(port) {
882
+ return new Promise((resolve) => {
883
+ const tester = net.connect(port, '127.0.0.1');
884
+ tester.on('connect', () => {
885
+ tester.destroy();
886
+ resolve(false); // port is in use
887
+ });
888
+ tester.on('error', (err) => {
889
+ tester.destroy();
890
+ if (err.code === 'ECONNREFUSED') {
891
+ resolve(true); // port is available
892
+ }
893
+ else {
894
+ resolve(false); // some other error occurred, assume port is in use
895
+ }
896
+ });
897
+ });
898
+ }
899
+ exports.isPortAvailable = isPortAvailable;
900
+ /**
901
+ * Returns the value for an environment variable or throws if it's undefined or null. Pass optional {@param throwOnEmpty} to throw when the key exists but has an empty value.
902
+ * @param varName The name of the environment variable to get.
903
+ * @param throwOnEmpty Throw an error if key exists (not undefined or null) but is empty.
904
+ * @returns
905
+ */
906
+ function getRequiredEnvVar(varName, throwOnEmpty = true) {
907
+ requireString('varName', varName);
908
+ const val = process.env[varName];
909
+ if (val === undefined || val === null) {
910
+ throw new Error(`Missing required environment variable: ${varName}`);
911
+ }
912
+ if (throwOnEmpty && val.trim() === '') {
913
+ throw new Error(`Required environment variable is empty: ${varName}`);
914
+ }
915
+ return val;
916
+ }
917
+ exports.getRequiredEnvVar = getRequiredEnvVar;
918
+ function getNormalizedError(err) {
919
+ let lastErrorAsError;
920
+ if (err === undefined || err === null) {
921
+ lastErrorAsError = new Error('lastError was undefined or null');
922
+ }
923
+ else if (err instanceof Error) {
924
+ lastErrorAsError = err;
925
+ }
926
+ else if (typeof err === 'string') {
927
+ lastErrorAsError = new Error(err);
928
+ }
929
+ else if (err instanceof Object) {
930
+ try {
931
+ lastErrorAsError = new Error(JSON.stringify(err));
932
+ }
933
+ catch (jsonError) {
934
+ lastErrorAsError = new Error('Object could not be serialized - could not normalize');
935
+ }
936
+ }
937
+ else {
938
+ lastErrorAsError = new Error(`Unknown error of type ${typeof err} - could not normalize`);
939
+ }
940
+ return lastErrorAsError;
941
+ }
942
+ exports.getNormalizedError = getNormalizedError;
943
+ /**
944
+ * Call a function until it succeeds. Will stop after the number of calls specified by {@param maxCalls}, or forever if -1 is passed.
945
+ * @param func The function to call
946
+ * @param maxCalls The maximum number of times to call the function before giving up. Pass -1 to retry forever.
947
+ * @param delayMilliseconds The number of milliseconds to wait between calls
948
+ * @param options Options for controlling the behavior of the retry. See {@link WithRetryOptions}.
949
+ */
950
+ async function withRetryAsync(func, maxCalls, delayMilliseconds, options) {
951
+ var _a, _b;
952
+ let attemptNumber = 0;
953
+ let lastError;
954
+ const forever = maxCalls === -1;
955
+ const defaultOptions = { initialDelayMilliseconds: 0, traceEnabled: false };
956
+ const mergedOptions = { ...defaultOptions, ...options };
957
+ const shouldLog = NodeCliUtilsConfig_js_1.config.traceEnabled || mergedOptions.traceEnabled;
958
+ const retryLog = shouldLog ? log : () => { };
959
+ const funcName = (_b = (_a = mergedOptions.functionLabel) !== null && _a !== void 0 ? _a : func.name) !== null && _b !== void 0 ? _b : 'anonymous';
960
+ if (mergedOptions.initialDelayMilliseconds > 0) {
961
+ retryLog(`initialDelayMilliseconds set to ${mergedOptions.initialDelayMilliseconds} - waiting before first try`);
962
+ await sleep(mergedOptions.initialDelayMilliseconds);
963
+ }
964
+ // eslint-disable-next-line no-constant-condition
965
+ while (true) {
966
+ attemptNumber++;
967
+ retryLog(`calling ${funcName} - attempt number ${attemptNumber}`);
968
+ try {
969
+ await func();
970
+ retryLog(`attempt ${attemptNumber} was successful`);
971
+ break;
972
+ }
973
+ catch (err) {
974
+ if (shouldLog) {
975
+ console.error(err);
976
+ }
977
+ lastError = err;
978
+ }
979
+ if (!forever && attemptNumber === maxCalls) {
980
+ throw new ExtendedError(`Failed to run method with retry after ${maxCalls} attempts`, getNormalizedError(lastError));
981
+ }
982
+ retryLog(`attempt number ${attemptNumber} failed - waiting ${delayMilliseconds} milliseconds before trying again`);
983
+ await sleep(delayMilliseconds);
984
+ }
985
+ }
986
+ exports.withRetryAsync = withRetryAsync;
987
+ /**
988
+ * Collapses each instance of consecutive whitespace characters into a single space.
989
+ */
990
+ function collapseWhitespace(str) {
991
+ return str.replace(/\s+/g, ' ');
992
+ }
993
+ exports.collapseWhitespace = collapseWhitespace;
994
+ /**
995
+ * Check if a string is a valid directory name. This is a very simple check that just makes sure the string doesn't contain any invalid characters.
996
+ * @param dirName The directory name to check
997
+ * @returns `true` if the directory name is valid, `false` otherwise
998
+ */
999
+ function isValidDirName(dirName) {
1000
+ // List of generally invalid characters for directory names in Windows, macOS, and Linux
1001
+ const invalidChars = ['<', '>', ':', '"', '/', '\\', '|', '?', '*'];
1002
+ for (const char of dirName) {
1003
+ if (invalidChars.includes(char) || char.charCodeAt(0) <= 31) {
1004
+ return false;
1005
+ }
1006
+ }
1007
+ return true;
1008
+ }
1009
+ exports.isValidDirName = isValidDirName;
1010
+ function hasWhitespace(str) {
1011
+ return /\s/.test(str);
1012
+ }
1013
+ exports.hasWhitespace = hasWhitespace;
1014
+ function stripShellMetaCharacters(input) {
1015
+ const metaCharacters = [
1016
+ '\\', '`', '$', '"', "'", '<', '>', '|', ';', ' ',
1017
+ '&', '(', ')', '[', ']', '{', '}', '?', '*', '#', '~', '^'
1018
+ ];
1019
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1020
+ const regex = new RegExp(`[${metaCharacters.map(escapeRegex).join('')}]`, 'g');
1021
+ return input.replace(regex, '');
1022
+ }
1023
+ exports.stripShellMetaCharacters = stripShellMetaCharacters;
1024
+ var AnsiColor;
1025
+ (function (AnsiColor) {
1026
+ AnsiColor["RESET"] = "\u001B[0m";
1027
+ AnsiColor["RED"] = "\u001B[31m";
1028
+ AnsiColor["GREEN"] = "\u001B[32m";
1029
+ AnsiColor["YELLOW"] = "\u001B[33m";
1030
+ AnsiColor["CYAN"] = "\u001B[96m";
1031
+ AnsiColor["GRAY"] = "\u001B[90m";
1032
+ AnsiColor["PURPLE"] = "\u001B[35m";
1033
+ })(AnsiColor || (exports.AnsiColor = AnsiColor = {}));
1034
+ const color = (str, colorAnsiCode) => {
1035
+ return `${colorAnsiCode}${str}${AnsiColor.RESET}`;
1036
+ };
1037
+ exports.color = color;
1038
+ const red = (str) => (0, exports.color)(str, AnsiColor.RED);
1039
+ exports.red = red;
1040
+ const green = (str) => (0, exports.color)(str, AnsiColor.GREEN);
1041
+ exports.green = green;
1042
+ const cyan = (str) => (0, exports.color)(str, AnsiColor.CYAN);
1043
+ exports.cyan = cyan;
1044
+ const gray = (str) => (0, exports.color)(str, AnsiColor.GRAY);
1045
+ exports.gray = gray;
1046
+ const purple = (str) => (0, exports.color)(str, AnsiColor.PURPLE);
1047
+ exports.purple = purple;
1048
+ const yellow = (str) => (0, exports.color)(str, AnsiColor.YELLOW);
1049
+ exports.yellow = yellow;
1050
+ var Emoji;
1051
+ (function (Emoji) {
1052
+ Emoji["RightArrow"] = "\u27A1\uFE0F";
1053
+ Emoji["LeftArrow"] = "\u2B05\uFE0F";
1054
+ Emoji["GreenCheck"] = "\u2705";
1055
+ Emoji["Warning"] = "\u26A0\uFE0F";
1056
+ Emoji["Lightning"] = "\u26A1";
1057
+ Emoji["Exclamation"] = "\u2757";
1058
+ Emoji["RedQuestion"] = "\u2753";
1059
+ Emoji["RedX"] = "\u274C";
1060
+ Emoji["Info"] = "\u2139\uFE0F";
1061
+ Emoji["SadFace"] = "\uD83D\uDE22";
1062
+ Emoji["Tools"] = "\uD83D\uDEE0\uFE0F";
1063
+ Emoji["NoEntry"] = "\u26D4";
1064
+ Emoji["Stop"] = "\uD83D\uDED1";
1065
+ Emoji["Certificate"] = "\uD83D\uDCDC";
1066
+ Emoji["Key"] = "\uD83D\uDD11";
1067
+ })(Emoji || (exports.Emoji = Emoji = {}));
1068
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhbFV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2dlbmVyYWxVdGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSxzREFBd0I7QUFDeEIsZ0VBQWtDO0FBQ2xDLHFDQUFrQztBQUNsQyx1REFBeUM7QUFDekMsbURBQW9DO0FBQ3BDLHlDQUEwQjtBQUMxQixtRUFBZ0Q7QUFDaEQsdUVBQWtQO0FBTWxQLE1BQU0sd0NBQXdDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUE7QUFFaEg7Ozs7R0FJRztBQUNILFNBQWdCLEdBQUcsQ0FBQyxJQUFhLEVBQUUsR0FBRyxRQUFtQjtJQUN2RCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLENBQUM7QUFGRCxrQkFFQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixLQUFLLENBQUMsU0FBa0IsRUFBRSxJQUFhLEVBQUUsR0FBRyxRQUFtQjtJQUM3RSxJQUFJLFNBQVMsRUFBRTtRQUNiLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUE7S0FDL0I7QUFDSCxDQUFDO0FBSkQsc0JBSUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsS0FBSyxDQUFDLElBQWMsRUFBRSxHQUFHLFFBQW1CO0lBQzFELElBQUksOEJBQU0sQ0FBQyxZQUFZLEVBQUU7UUFDdkIsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFBO1FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFBO0tBQ3ZDO0FBQ0gsQ0FBQztBQUxELHNCQUtDO0FBaUNEOzs7O0dBSUc7QUFDSCxNQUFh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