@automattic/vip 2.32.2 → 2.32.4

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 (45) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/assets/dev-env.lando.template.yml.ejs +10 -2
  3. package/dist/bin/vip-dev-env-exec.js +1 -7
  4. package/dist/bin/vip-dev-env-shell.js +0 -4
  5. package/dist/bin/vip-dev-env-start.js +1 -1
  6. package/dist/bin/vip-dev-env-sync-sql.js +8 -6
  7. package/dist/bin/vip-dev-env-update.js +1 -2
  8. package/dist/bin/vip-import-sql.js +2 -2
  9. package/dist/bin/vip-logout.js +23 -0
  10. package/dist/bin/vip-slowlogs.js +192 -0
  11. package/dist/bin/vip-validate-preflight.js +8 -10
  12. package/dist/bin/vip-whoami.js +1 -2
  13. package/dist/bin/vip.js +1 -5
  14. package/dist/commands/backup-db.js +8 -9
  15. package/dist/lib/api/app.js +2 -2
  16. package/dist/lib/api/cache-purge.js +2 -2
  17. package/dist/lib/api/http.js +2 -3
  18. package/dist/lib/app-logs/app-logs.js +2 -2
  19. package/dist/lib/app-slowlogs/app-slowlogs.js +63 -0
  20. package/dist/lib/app-slowlogs/types.js +1 -0
  21. package/dist/lib/cli/apiConfig.js +1 -1
  22. package/dist/lib/client-file-uploader.js +19 -4
  23. package/dist/lib/config/software.js +4 -4
  24. package/dist/lib/constants/dev-environment.js +7 -3
  25. package/dist/lib/dev-environment/dev-environment-cli.js +110 -117
  26. package/dist/lib/dev-environment/dev-environment-configuration-file.js +35 -36
  27. package/dist/lib/dev-environment/dev-environment-core.js +36 -19
  28. package/dist/lib/dev-environment/dev-environment-lando.js +80 -72
  29. package/dist/lib/dev-environment/docker-utils.js +8 -9
  30. package/dist/lib/envvar/api-get-all.js +2 -2
  31. package/dist/lib/envvar/api-list.js +3 -6
  32. package/dist/lib/envvar/input.js +1 -2
  33. package/dist/lib/site-import/status.js +5 -5
  34. package/dist/lib/token.js +3 -6
  35. package/dist/lib/validations/is-multi-site-sql-dump.js +0 -1
  36. package/dist/lib/validations/is-multi-site.js +14 -12
  37. package/dist/lib/validations/is-multisite-domain-mapped.js +5 -10
  38. package/dist/lib/validations/line-by-line.js +9 -13
  39. package/dist/lib/validations/site-type.js +2 -7
  40. package/dist/lib/validations/sql.js +14 -19
  41. package/dist/lib/validations/utils.js +1 -1
  42. package/export.sql +627 -0
  43. package/npm-shrinkwrap.json +913 -926
  44. package/package.json +12 -9
  45. package/tsconfig.json +3 -1
@@ -24,18 +24,19 @@ exports.promptForComponent = promptForComponent;
24
24
  exports.promptForMultisite = promptForMultisite;
25
25
  exports.promptForPhpVersion = promptForPhpVersion;
26
26
  exports.promptForText = promptForText;
27
+ exports.promptForWordPress = promptForWordPress;
27
28
  exports.resolvePath = resolvePath;
28
29
  exports.resolvePhpVersion = resolvePhpVersion;
29
30
  exports.setIsTTY = setIsTTY;
30
31
  exports.validateDependencies = void 0;
32
+ var _nodeFs = require("node:fs");
33
+ var _path = _interopRequireDefault(require("path"));
34
+ var _nodeOs = require("node:os");
35
+ var _promises = require("node:dns/promises");
31
36
  var _chalk = _interopRequireDefault(require("chalk"));
32
37
  var _formatters = _interopRequireDefault(require("lando/lib/formatters"));
33
38
  var _enquirer = require("enquirer");
34
39
  var _debug = _interopRequireDefault(require("debug"));
35
- var _fs = _interopRequireDefault(require("fs"));
36
- var _path = _interopRequireDefault(require("path"));
37
- var _os = _interopRequireDefault(require("os"));
38
- var _dns = _interopRequireDefault(require("dns"));
39
40
  var _child_process = require("child_process");
40
41
  var _shelljs = require("shelljs");
41
42
  var _progress = require("../../lib/cli/progress");
@@ -46,11 +47,6 @@ var _devEnvironmentLando = require("./dev-environment-lando");
46
47
  var _userError = _interopRequireDefault(require("../user-error"));
47
48
  var _devEnvironmentConfigurationFile = require("./dev-environment-configuration-file");
48
49
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
49
- /**
50
- *
51
- * @format
52
- */
53
-
54
50
  /**
55
51
  * External dependencies
56
52
  */
@@ -81,11 +77,6 @@ const componentDemoNames = {
81
77
  muPlugins: 'vip-go-mu-plugins',
82
78
  appCode: 'vip-go-skeleton'
83
79
  };
84
-
85
- // Forward declaration to avoid no-use-before-define
86
-
87
- // eslint-disable-next-line no-redeclare
88
-
89
80
  async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
90
81
  const errorPrefix = _chalk.default.red('Error:');
91
82
  if (_devEnvironment.DEV_ENVIRONMENT_NOT_FOUND === exception.message) {
@@ -101,16 +92,13 @@ async function handleCLIException(exception, trackKey, trackBaseInfo = {}) {
101
92
  message = message.replace('ERROR: ', '');
102
93
  console.error(errorPrefix, message);
103
94
  if (trackKey) {
104
- try {
105
- const errorTrackingInfo = {
106
- ...trackBaseInfo,
107
- failure: message,
108
- stack: exception.stack
109
- };
110
- await (0, _tracker.trackEvent)(trackKey, errorTrackingInfo);
111
- } catch (trackException) {
112
- console.warn(errorPrefix, `Failed to record track event ${trackKey}`, trackException.message);
113
- }
95
+ const errorTrackingInfo = {
96
+ ...trackBaseInfo,
97
+ failure: message,
98
+ stack: exception.stack
99
+ };
100
+ // trackEvent does not throw
101
+ await (0, _tracker.trackEvent)(trackKey, errorTrackingInfo);
114
102
  }
115
103
  if (!process.env.DEBUG) {
116
104
  console.error(`\nPlease re-run the command with "--debug ${_chalk.default.bold('@automattic/vip:bin:dev-environment')}" appended to it and provide the stack trace on the support ticket.`);
@@ -127,7 +115,7 @@ const verifyDNSResolution = async slug => {
127
115
  debug(`Verifying DNS resolution for ${testDomain}`);
128
116
  let address;
129
117
  try {
130
- address = await _dns.default.promises.lookup(testDomain, 4);
118
+ address = await (0, _promises.lookup)(testDomain, 4);
131
119
  debug(`Got DNS response ${address.address}`);
132
120
  } catch (error) {
133
121
  throw new _userError.default(`DNS resolution for ${testDomain} failed. ${advice}`);
@@ -158,21 +146,13 @@ const validateDependencies = async (lando, slug, quiet) => {
158
146
  progressTracker.startPrinting();
159
147
  progressTracker.stepRunning('docker');
160
148
  }
161
- try {
162
- await (0, _devEnvironmentLando.validateDockerInstalled)(lando);
163
- } catch (exception) {
164
- throw new _userError.default(exception.message);
165
- }
149
+ (0, _devEnvironmentLando.validateDockerInstalled)(lando);
166
150
  if (!quiet) {
167
151
  progressTracker.stepSuccess('docker');
168
152
  progressTracker.stepSuccess('compose');
169
153
  progressTracker.print();
170
154
  }
171
- try {
172
- await (0, _devEnvironmentLando.validateDockerAccess)(lando);
173
- } catch (exception) {
174
- throw new _userError.default(exception.message);
175
- }
155
+ await (0, _devEnvironmentLando.validateDockerAccess)(lando);
176
156
  if (!quiet) {
177
157
  progressTracker.stepSuccess('access');
178
158
  progressTracker.print();
@@ -254,11 +234,13 @@ function processComponentOptionInput(passedParam, allowLocal) {
254
234
  function getOptionsFromAppInfo(appInfo) {
255
235
  var _appInfo$environment, _appInfo$environment2, _appInfo$environment3, _appInfo$environment4, _appInfo$environment5;
256
236
  return {
237
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
257
238
  title: ((_appInfo$environment = appInfo.environment) === null || _appInfo$environment === void 0 ? void 0 : _appInfo$environment.name) || appInfo.name || '',
258
- multisite: !!(appInfo !== null && appInfo !== void 0 && (_appInfo$environment2 = appInfo.environment) !== null && _appInfo$environment2 !== void 0 && _appInfo$environment2.isMultisite),
239
+ // NOSONAR
240
+ multisite: !!((_appInfo$environment2 = appInfo.environment) !== null && _appInfo$environment2 !== void 0 && _appInfo$environment2.isMultisite),
259
241
  mediaRedirectDomain: (_appInfo$environment3 = appInfo.environment) === null || _appInfo$environment3 === void 0 ? void 0 : _appInfo$environment3.primaryDomain,
260
- php: ((_appInfo$environment4 = appInfo.environment) === null || _appInfo$environment4 === void 0 ? void 0 : _appInfo$environment4.php) || '',
261
- wordpress: ((_appInfo$environment5 = appInfo.environment) === null || _appInfo$environment5 === void 0 ? void 0 : _appInfo$environment5.wordpress) || ''
242
+ php: ((_appInfo$environment4 = appInfo.environment) === null || _appInfo$environment4 === void 0 ? void 0 : _appInfo$environment4.php) ?? '',
243
+ wordpress: ((_appInfo$environment5 = appInfo.environment) === null || _appInfo$environment5 === void 0 ? void 0 : _appInfo$environment5.wordpress) ?? ''
262
244
  };
263
245
  }
264
246
 
@@ -272,7 +254,6 @@ function getOptionsFromAppInfo(appInfo) {
272
254
  */
273
255
  // eslint-disable-next-line complexity
274
256
  async function promptForArguments(preselectedOptions, defaultOptions, suppressPrompts = false) {
275
- var _preselectedOptions$m;
276
257
  debug('Provided preselected', preselectedOptions, 'and default', defaultOptions);
277
258
  if (suppressPrompts) {
278
259
  preselectedOptions = {
@@ -287,12 +268,12 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
287
268
  multisiteText += ` (${defaultOptions.title} ${defaultOptions.multisite ? 'IS' : 'is NOT'} multisite)`;
288
269
  }
289
270
  const instanceData = {
290
- wpTitle: preselectedOptions.title || (await promptForText('WordPress site title', defaultOptions.title || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.title)),
291
- multisite: resolveMultisite((_preselectedOptions$m = preselectedOptions.multisite) !== null && _preselectedOptions$m !== void 0 ? _preselectedOptions$m : await promptForMultisite(multisiteText, defaultOptions.multisite || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite)),
271
+ wpTitle: preselectedOptions.title ?? (await promptForText('WordPress site title', defaultOptions.title ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.title)),
272
+ multisite: resolveMultisite(preselectedOptions.multisite ?? (await promptForMultisite(multisiteText, defaultOptions.multisite ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite))),
292
273
  elasticsearch: false,
293
- php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php || _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.phpVersion)),
294
- mariadb: preselectedOptions.mariadb || defaultOptions.mariadb,
295
- mediaRedirectDomain: preselectedOptions.mediaRedirectDomain || '',
274
+ php: preselectedOptions.php ? resolvePhpVersion(preselectedOptions.php) : await promptForPhpVersion(resolvePhpVersion(defaultOptions.php ?? _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.phpVersion)),
275
+ mariadb: preselectedOptions.mariadb ?? defaultOptions.mariadb,
276
+ mediaRedirectDomain: preselectedOptions.mediaRedirectDomain ?? '',
296
277
  wordpress: {
297
278
  mode: 'image',
298
279
  tag: ''
@@ -320,58 +301,68 @@ async function promptForArguments(preselectedOptions, defaultOptions, suppressPr
320
301
  const mediaRedirectPromptText = `Would you like to redirect to ${defaultOptions.mediaRedirectDomain} for missing media files?`;
321
302
  const setMediaRedirectDomain = await promptForBoolean(mediaRedirectPromptText, true);
322
303
  if (setMediaRedirectDomain) {
323
- var _defaultOptions$media;
324
- instanceData.mediaRedirectDomain = (_defaultOptions$media = defaultOptions.mediaRedirectDomain) !== null && _defaultOptions$media !== void 0 ? _defaultOptions$media : '';
304
+ instanceData.mediaRedirectDomain = defaultOptions.mediaRedirectDomain;
325
305
  }
326
306
  }
307
+ instanceData.wordpress = await processWordPress((preselectedOptions.wordpress ?? '').toString(), (defaultOptions.wordpress ?? '').toString());
327
308
  for (const component of _devEnvironment.DEV_ENVIRONMENT_COMPONENTS) {
328
- var _preselectedOptions$c, _defaultOptions$compo;
329
- const option = ((_preselectedOptions$c = preselectedOptions[component]) !== null && _preselectedOptions$c !== void 0 ? _preselectedOptions$c : '').toString();
330
- const defaultValue = ((_defaultOptions$compo = defaultOptions[component]) !== null && _defaultOptions$compo !== void 0 ? _defaultOptions$compo : '').toString();
309
+ const option = (preselectedOptions[component] ?? '').toString();
310
+ const defaultValue = (defaultOptions[component] ?? '').toString();
331
311
 
332
312
  // eslint-disable-next-line no-await-in-loop
333
313
  const result = await processComponent(component, option, defaultValue, suppressPrompts);
334
- if (null === result) {
335
- throw new Error('processComponent() returned null');
336
- }
337
314
  instanceData[component] = result;
338
315
  }
339
- debug(`Processing elasticsearch with preselected "${preselectedOptions.elasticsearch}"`);
316
+ debug(`Processing elasticsearch with preselected "%s"`, preselectedOptions.elasticsearch);
340
317
  if ('elasticsearch' in preselectedOptions) {
341
318
  instanceData.elasticsearch = !!preselectedOptions.elasticsearch;
342
319
  } else {
343
320
  instanceData.elasticsearch = await promptForBoolean('Enable Elasticsearch (needed by Enterprise Search)?', !!defaultOptions.elasticsearch);
344
321
  }
345
- for (const service of ['phpmyadmin', 'xdebug', 'mailpit', 'photon']) {
322
+ const services = ['phpmyadmin', 'xdebug', 'mailpit', 'photon'];
323
+ for (const service of services) {
346
324
  if (service in instanceData) {
347
- if (service in preselectedOptions) {
348
- instanceData[service] = preselectedOptions[service];
325
+ const preselected = preselectedOptions[service];
326
+ if (preselected !== undefined) {
327
+ instanceData[service] = preselected;
349
328
  } else {
350
329
  // eslint-disable-next-line no-await-in-loop
351
- instanceData[service] = await promptForBoolean(`Enable ${promptLabels[service] || service}`, defaultOptions[service]);
330
+ instanceData[service] = await promptForBoolean(`Enable ${promptLabels[service] || service}`, !!defaultOptions[service]);
352
331
  }
353
332
  }
354
333
  }
355
334
  debug('Instance data after prompts', instanceData);
356
335
  return instanceData;
357
336
  }
337
+ async function processWordPress(preselectedValue, defaultValue) {
338
+ debug(`processing 'WordPress', with preselected/default - ${preselectedValue}/${defaultValue}`);
339
+ let result;
340
+ const allowLocal = false;
341
+ const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
342
+ if (preselectedValue) {
343
+ result = processComponentOptionInput(preselectedValue, allowLocal);
344
+ } else {
345
+ result = await promptForWordPress(defaultObject);
346
+ }
347
+ debug(result);
348
+ return result;
349
+ }
358
350
  async function processComponent(component, preselectedValue, defaultValue, suppressPrompts = false) {
359
351
  debug(`processing a component '${component}', with preselected/default - ${preselectedValue}/${defaultValue}`);
360
- let result = null;
361
- const allowLocal = component !== 'wordpress';
352
+ let result;
353
+ const allowLocal = true;
362
354
  const defaultObject = defaultValue ? processComponentOptionInput(defaultValue, allowLocal) : null;
363
355
  if (preselectedValue) {
364
356
  result = processComponentOptionInput(preselectedValue, allowLocal);
365
- if (allowLocal && suppressPrompts === false) {
357
+ if (!suppressPrompts) {
366
358
  console.log(`${_chalk.default.green('✓')} Path to your local ${componentDisplayNames[component]}: ${preselectedValue}`);
367
359
  }
368
360
  } else {
369
361
  result = await promptForComponent(component, allowLocal, defaultObject);
370
362
  }
371
363
  debug(result);
372
- while ('local' === ((_result = result) === null || _result === void 0 ? void 0 : _result.mode)) {
373
- var _result;
374
- const resolvedPath = resolvePath(result.dir || '');
364
+ while ('local' === result.mode) {
365
+ const resolvedPath = resolvePath(result.dir ?? '');
375
366
  result.dir = resolvedPath;
376
367
  const {
377
368
  result: isPathValid,
@@ -402,7 +393,7 @@ function validateLocalPath(component, providedPath) {
402
393
  const missingFiles = [];
403
394
  for (const file of files) {
404
395
  const filePath = _path.default.resolve(providedPath, file);
405
- if (!_fs.default.existsSync(filePath)) {
396
+ if (!(0, _nodeFs.existsSync)(filePath)) {
406
397
  missingFiles.push(file);
407
398
  }
408
399
  }
@@ -421,18 +412,17 @@ function validateLocalPath(component, providedPath) {
421
412
  };
422
413
  }
423
414
  function isNonEmptyDirectory(directoryPath) {
424
- const isDirectory = directoryPath && _fs.default.existsSync(directoryPath) && _fs.default.lstatSync(directoryPath).isDirectory();
425
- const isEmpty = isDirectory ? _fs.default.readdirSync(directoryPath).length === 0 : true;
415
+ const isDirectory = directoryPath && (0, _nodeFs.existsSync)(directoryPath) && (0, _nodeFs.lstatSync)(directoryPath).isDirectory();
416
+ const isEmpty = isDirectory ? (0, _nodeFs.readdirSync)(directoryPath).length === 0 : true;
426
417
  return !isEmpty && isDirectory;
427
418
  }
428
419
  function resolvePath(input) {
429
420
  // Resolve does not do ~ reliably
430
- const resolvedPath = input.replace(/^~/, _os.default.homedir());
421
+ const resolvedPath = input.replace(/^~/, (0, _nodeOs.homedir)());
431
422
  // And resolve to handle relative paths
432
423
  return _path.default.resolve(resolvedPath);
433
424
  }
434
425
  async function promptForText(message, initial) {
435
- var _result2;
436
426
  let result = {
437
427
  input: initial
438
428
  };
@@ -451,10 +441,12 @@ async function promptForText(message, initial) {
451
441
  validate: nonEmptyValidator
452
442
  });
453
443
  }
454
- return (((_result2 = result) === null || _result2 === void 0 ? void 0 : _result2.input) || '').trim();
444
+ return (result.input || '').trim();
455
445
  }
446
+ const multisiteOptions = ['subdomain', 'subdirectory'];
456
447
  async function promptForMultisite(message, initial) {
457
- var _result3;
448
+ var _result;
449
+ // `undefined` is used here only because our tests need overhauling
458
450
  let result = {
459
451
  input: initial
460
452
  };
@@ -466,8 +458,7 @@ async function promptForMultisite(message, initial) {
466
458
  initial
467
459
  });
468
460
  }
469
- let input = (((_result3 = result) === null || _result3 === void 0 ? void 0 : _result3.input) || initial.toString()).trim();
470
- const multisiteOptions = ['subdomain', 'subdirectory'];
461
+ let input = (((_result = result) === null || _result === void 0 ? void 0 : _result.input) ?? initial).toString().trim();
471
462
  const allowedOptions = [...FALSE_OPTIONS, ...TRUE_OPTIONS, ...multisiteOptions, 'none'];
472
463
  if (!allowedOptions.includes(input) && isStdinTTY) {
473
464
  const select = new _enquirer.Select({
@@ -482,18 +473,15 @@ function promptForBoolean(message, initial) {
482
473
  if (isStdinTTY) {
483
474
  const confirm = new _enquirer.Confirm({
484
475
  message,
485
- initial
476
+ initial: initial.toString()
486
477
  });
487
478
  return confirm.run();
488
479
  }
489
480
  return Promise.resolve(initial);
490
481
  }
491
482
  function resolveMultisite(value) {
492
- const allowedValues = ['subdomain', 'subdirectory'];
493
- if (typeof value === 'string' && !allowedValues.includes(value)) {
494
- return _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite;
495
- }
496
- return value;
483
+ const isMultisiteOption = val => typeof val === 'string' && multisiteOptions.includes(val) || typeof val === 'boolean';
484
+ return isMultisiteOption(value) ? value : _devEnvironment.DEV_ENVIRONMENT_DEFAULTS.multisite;
497
485
  }
498
486
  function resolvePhpVersion(version) {
499
487
  debug(`Resolving PHP version %j`, version);
@@ -506,7 +494,7 @@ function resolvePhpVersion(version) {
506
494
  const image = images.find(value => value === version);
507
495
  if (image) {
508
496
  result = image;
509
- } else if (version.indexOf('/') !== -1) {
497
+ } else if (version.includes('/')) {
510
498
  // Assuming this is a Docker image
511
499
  // This can happen when we first called `vip dev-env update -P image:ghcr.io/...`
512
500
  // and then called `vip dev-env update` again. The custom image won't match our images
@@ -541,12 +529,32 @@ async function promptForPhpVersion(initialValue) {
541
529
  }
542
530
  return resolvePhpVersion(answer);
543
531
  }
532
+ async function promptForWordPress(defaultObject) {
533
+ debug(`Prompting for wordpress with default:`, defaultObject);
534
+ const componentDisplayName = componentDisplayNames.wordpress;
535
+ const messagePrefix = `${componentDisplayName} - `;
544
536
 
545
- // eslint-disable-next-line no-redeclare
537
+ // image with selection
538
+ const tagChoices = await getTagChoices();
539
+ let option = (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.tag) ?? tagChoices[0].value;
540
+ if (isStdinTTY) {
541
+ const message = `${messagePrefix}Which version would you like`;
542
+ const selectTag = new _enquirer.Select({
543
+ message,
544
+ choices: tagChoices,
545
+ initial: option
546
+ });
547
+ option = await selectTag.run();
548
+ }
549
+ return {
550
+ mode: 'image',
551
+ tag: option
552
+ };
553
+ }
546
554
  async function promptForComponent(component, allowLocal, defaultObject) {
547
555
  debug(`Prompting for ${component} with default:`, defaultObject);
548
556
  const componentDisplayName = componentDisplayNames[component] || component;
549
- const componentDemoName = componentDemoNames[component] || component;
557
+ const componentDemoName = componentDemoNames[component];
550
558
  const modChoices = [];
551
559
  if (allowLocal) {
552
560
  modChoices.push({
@@ -579,62 +587,48 @@ async function promptForComponent(component, allowLocal, defaultObject) {
579
587
  debug(modeResult);
580
588
  const messagePrefix = selectMode ? '\t' : `${componentDisplayName} - `;
581
589
  if ('local' === modeResult) {
582
- const directoryPath = await promptForText(`${messagePrefix}What is a path to your local ${componentDisplayName}`, (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.dir) || '');
590
+ const directoryPath = await promptForText(`${messagePrefix}What is a path to your local ${componentDisplayName}`, (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.dir) ?? '');
583
591
  return {
584
592
  mode: modeResult,
585
593
  dir: directoryPath
586
594
  };
587
595
  }
588
596
 
589
- // image with selection
590
- if (component === 'wordpress') {
591
- const tagChoices = await getTagChoices();
592
- let option = (defaultObject === null || defaultObject === void 0 ? void 0 : defaultObject.tag) || tagChoices[0].value;
593
- if (isStdinTTY) {
594
- const message = `${messagePrefix}Which version would you like`;
595
- const selectTag = new _enquirer.Select({
596
- message,
597
- choices: tagChoices,
598
- initial: option
599
- });
600
- option = await selectTag.run();
601
- }
602
- return {
603
- mode: 'image',
604
- tag: option
605
- };
606
- }
607
-
608
597
  // image
609
598
  return {
610
599
  mode: modeResult
611
600
  };
612
601
  }
613
602
  const FALSE_OPTIONS = ['false', 'no', 'n', '0'];
603
+ const TRUE_OPTIONS = ['true', 'yes', 'y', '1'];
614
604
  function processBooleanOption(value) {
615
- var _value$toLowerCase;
616
605
  if (!value) {
617
606
  return false;
618
607
  }
619
- return !FALSE_OPTIONS.includes((_value$toLowerCase = value.toLowerCase) === null || _value$toLowerCase === void 0 ? void 0 : _value$toLowerCase.call(value));
608
+
609
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
610
+ return !FALSE_OPTIONS.includes(value.toString().toLowerCase()); // NOSONAR
620
611
  }
621
- const TRUE_OPTIONS = ['true', 'yes', 'y', '1'];
612
+
622
613
  function processStringOrBooleanOption(value) {
623
- var _value$toLowerCase2, _value$toLowerCase3;
624
- if (!value || FALSE_OPTIONS.includes((_value$toLowerCase2 = value.toLowerCase) === null || _value$toLowerCase2 === void 0 ? void 0 : _value$toLowerCase2.call(value))) {
614
+ if (typeof value === 'boolean') {
615
+ return value;
616
+ }
617
+ if (!value || FALSE_OPTIONS.includes(value.toLowerCase())) {
625
618
  return false;
626
619
  }
627
- if (TRUE_OPTIONS.includes((_value$toLowerCase3 = value.toLowerCase) === null || _value$toLowerCase3 === void 0 ? void 0 : _value$toLowerCase3.call(value))) {
620
+ if (TRUE_OPTIONS.includes(value.toLowerCase())) {
628
621
  return true;
629
622
  }
630
623
  return value;
631
624
  }
632
625
  function processVersionOption(value) {
633
- if (!isNaN(value) && value % 1 === 0) {
634
- // If it's an Integer passed in, let's ensure that it has a decimal in it to match the version tags e.g. 6 => 6.0
635
- return parseFloat(value).toFixed(1);
626
+ if (typeof value === 'string' || typeof value === 'number') {
627
+ if (!isNaN(value) && +value % 1 === 0) {
628
+ return parseFloat(value).toFixed(1);
629
+ }
636
630
  }
637
- return value + '';
631
+ return (value === null || value === void 0 ? void 0 : value.toString()) ?? '';
638
632
  }
639
633
  function addDevEnvConfigurationOptions(command) {
640
634
  // We leave the third parameter to undefined on some because the defaults are handled in preProcessInstanceData()
@@ -685,18 +679,17 @@ async function getTagChoices() {
685
679
  }
686
680
  function getEnvTrackingInfo(slug) {
687
681
  try {
688
- var _result$php;
689
682
  const envData = (0, _devEnvironmentCore.readEnvironmentData)(slug);
690
683
  const result = {
691
684
  slug
692
685
  };
693
686
  for (const key of Object.keys(envData)) {
694
- // track doesnt like camelCase
687
+ // track doesn't like camelCase
695
688
  const snakeCasedKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
696
- const value = _devEnvironment.DEV_ENVIRONMENT_COMPONENTS.includes(key) ? JSON.stringify(envData[key]) : envData[key];
689
+ const value = _devEnvironment.DEV_ENVIRONMENT_COMPONENTS_WITH_WP.includes(key) ? JSON.stringify(envData[key]) : envData[key];
697
690
  result[snakeCasedKey] = value;
698
691
  }
699
- result.php = (_result$php = result.php) === null || _result$php === void 0 ? void 0 : _result$php.replace(/.*:/, '');
692
+ result.php = result.php.replace(/.*:/, '');
700
693
  return result;
701
694
  } catch (err) {
702
695
  return {
@@ -704,14 +697,14 @@ function getEnvTrackingInfo(slug) {
704
697
  };
705
698
  }
706
699
  }
707
- async function postStart(slug, options) {
700
+ function postStart(slug, options) {
708
701
  if (options.openVSCode) {
709
702
  launchVSCode(slug);
710
703
  }
711
704
  }
712
705
  const launchVSCode = slug => {
713
706
  const workspacePath = (0, _devEnvironmentCore.getVSCodeWorkspacePath)(slug);
714
- if (_fs.default.existsSync(workspacePath)) {
707
+ if ((0, _nodeFs.existsSync)(workspacePath)) {
715
708
  console.log('VS Code workspace already exists, skipping creation.');
716
709
  } else {
717
710
  (0, _devEnvironmentCore.generateVSCodeWorkspace)(slug);
@@ -7,20 +7,16 @@ exports.CONFIGURATION_FILE_NAME = void 0;
7
7
  exports.getConfigurationFileOptions = getConfigurationFileOptions;
8
8
  exports.mergeConfigurationFileOptions = mergeConfigurationFileOptions;
9
9
  exports.printConfigurationFile = printConfigurationFile;
10
+ var _promises = require("node:fs/promises");
11
+ var _fs = require("fs");
12
+ var _nodePath = _interopRequireDefault(require("node:path"));
10
13
  var _debug = _interopRequireDefault(require("debug"));
11
- var _fs = _interopRequireDefault(require("fs"));
12
- var _path = _interopRequireDefault(require("path"));
13
14
  var _chalk = _interopRequireDefault(require("chalk"));
14
15
  var _jsYaml = _interopRequireWildcard(require("js-yaml"));
15
16
  var exit = _interopRequireWildcard(require("../cli/exit"));
16
17
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
18
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
18
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
- /**
20
- *
21
- * @format
22
- */
23
-
24
20
  /**
25
21
  * External dependencies
26
22
  */
@@ -33,12 +29,12 @@ const debug = (0, _debug.default)('@automattic/vip:bin:dev-environment');
33
29
  const CONFIGURATION_FILE_NAME = '.vip-dev-env.yml';
34
30
  exports.CONFIGURATION_FILE_NAME = CONFIGURATION_FILE_NAME;
35
31
  async function getConfigurationFileOptions() {
36
- const configurationFilePath = _path.default.join(process.cwd(), CONFIGURATION_FILE_NAME);
32
+ const configurationFilePath = _nodePath.default.join(process.cwd(), CONFIGURATION_FILE_NAME);
37
33
  let configurationFileContents = '';
38
- const fileExists = await _fs.default.promises.access(configurationFilePath, _fs.default.R_OK).then(() => true).catch(() => false);
34
+ const fileExists = await (0, _promises.access)(configurationFilePath, _fs.constants.R_OK).then(() => true).catch(() => false);
39
35
  if (fileExists) {
40
36
  debug('Reading configuration file from:', configurationFilePath);
41
- configurationFileContents = await _fs.default.promises.readFile(configurationFilePath, 'utf8');
37
+ configurationFileContents = await (0, _promises.readFile)(configurationFilePath, 'utf8');
42
38
  } else {
43
39
  return {};
44
40
  }
@@ -53,57 +49,60 @@ async function getConfigurationFileOptions() {
53
49
  const messageToShow = `Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} could not be loaded:\n` + err.toString();
54
50
  exit.withError(messageToShow);
55
51
  }
56
- const configuration = await sanitizeConfiguration(configurationFromFile).catch(async ({
57
- message
58
- }) => {
59
- exit.withError(message);
60
- return {};
61
- });
62
- debug('Sanitized configuration from file:', configuration);
63
- return configuration;
52
+ try {
53
+ const configuration = sanitizeConfiguration(configurationFromFile);
54
+ debug('Sanitized configuration from file:', configuration);
55
+ return configuration;
56
+ } catch (err) {
57
+ exit.withError(err instanceof Error ? err : new Error('Unknown error'));
58
+ }
64
59
  }
65
- async function sanitizeConfiguration(configuration) {
66
- var _configuration$mailpi;
60
+ function sanitizeConfiguration(configuration) {
61
+ var _configuration$title, _configuration$php, _configuration$wordpr, _configuration$muPlu, _configuration$appCo, _configuration$media;
67
62
  const genericConfigurationError = `Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} is available but ` + `couldn't be loaded. Ensure there is a ${_chalk.default.cyan('configuration-version')} and ${_chalk.default.cyan('slug')} ` + `configured. For example:\n\n${_chalk.default.grey(getConfigurationFileExample())}`;
68
63
  if (Array.isArray(configuration) || typeof configuration !== 'object') {
69
64
  throw new Error(genericConfigurationError);
70
65
  }
71
- if (configuration['configuration-version'] === undefined || configuration.slug === undefined) {
66
+ const version = configuration['configuration-version'];
67
+ if (typeof version !== 'string' && typeof version !== 'number' || configuration.slug === undefined || configuration.slug === null) {
72
68
  throw new Error(genericConfigurationError);
73
69
  }
74
- const validVersions = getAllConfigurationFileVersions().map(version => _chalk.default.cyan(version)).join(', ');
75
- if (!isValidConfigurationFileVersion(configuration['configuration-version'])) {
70
+ const validVersions = getAllConfigurationFileVersions().map(ver => _chalk.default.cyan(ver)).join(', ');
71
+ if (!isValidConfigurationFileVersion(version.toString())) {
76
72
  throw new Error(`Configuration file ${_chalk.default.grey(CONFIGURATION_FILE_NAME)} has an invalid ` + `${_chalk.default.cyan('configuration-version')} key. Update to a supported version. For example:\n\n` + _chalk.default.grey(getConfigurationFileExample()) + `\nSupported configuration versions: ${validVersions}.\n`);
77
73
  }
78
74
  const stringToBooleanIfDefined = value => {
79
- if (value === undefined || !['true', 'false'].includes(value)) {
75
+ if (typeof value !== 'string' || !['true', 'false'].includes(value)) {
80
76
  return undefined;
81
77
  }
82
78
  return value === 'true';
83
79
  };
84
80
  const sanitizedConfiguration = {
85
- 'configuration-version': configuration['configuration-version'],
86
- slug: configuration.slug,
87
- title: configuration.title,
81
+ version: version.toString(),
82
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
83
+ slug: configuration.slug.toString(),
84
+ // NOSONAR
85
+ title: (_configuration$title = configuration.title) === null || _configuration$title === void 0 ? void 0 : _configuration$title.toString(),
88
86
  multisite: stringToBooleanIfDefined(configuration.multisite),
89
- php: configuration.php,
90
- wordpress: configuration.wordpress,
91
- 'mu-plugins': configuration['mu-plugins'],
92
- 'app-code': configuration['app-code'],
87
+ php: (_configuration$php = configuration.php) === null || _configuration$php === void 0 ? void 0 : _configuration$php.toString(),
88
+ wordpress: (_configuration$wordpr = configuration.wordpress) === null || _configuration$wordpr === void 0 ? void 0 : _configuration$wordpr.toString(),
89
+ 'mu-plugins': (_configuration$muPlu = configuration['mu-plugins']) === null || _configuration$muPlu === void 0 ? void 0 : _configuration$muPlu.toString(),
90
+ 'app-code': (_configuration$appCo = configuration['app-code']) === null || _configuration$appCo === void 0 ? void 0 : _configuration$appCo.toString(),
93
91
  elasticsearch: stringToBooleanIfDefined(configuration.elasticsearch),
94
92
  phpmyadmin: stringToBooleanIfDefined(configuration.phpmyadmin),
95
93
  xdebug: stringToBooleanIfDefined(configuration.xdebug),
96
- mailpit: stringToBooleanIfDefined((_configuration$mailpi = configuration.mailpit) !== null && _configuration$mailpi !== void 0 ? _configuration$mailpi : configuration.mailhog),
97
- 'media-redirect-domain': configuration['media-redirect-domain'],
94
+ mailpit: stringToBooleanIfDefined(configuration.mailpit ?? configuration.mailhog),
95
+ 'media-redirect-domain': (_configuration$media = configuration['media-redirect-domain']) === null || _configuration$media === void 0 ? void 0 : _configuration$media.toString(),
98
96
  photon: stringToBooleanIfDefined(configuration.photon)
99
97
  };
100
98
 
101
99
  // Remove undefined values
102
- Object.keys(sanitizedConfiguration).forEach(key => sanitizedConfiguration[key] === undefined && delete sanitizedConfiguration[key]);
100
+ Object.keys(sanitizedConfiguration).forEach(
101
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
102
+ key => sanitizedConfiguration[key] === undefined && delete sanitizedConfiguration[key]);
103
103
  return sanitizedConfiguration;
104
104
  }
105
105
  function mergeConfigurationFileOptions(preselectedOptions, configurationFileOptions) {
106
- var _configurationFileOpt;
107
106
  // configurationFileOptions holds different parameters than present in
108
107
  // preselectedOptions like "slug", and friendly-named parameters (e.g.
109
108
  // 'app-code' vs 'appCode'). Selectively merge configurationFileOptions
@@ -119,7 +118,7 @@ function mergeConfigurationFileOptions(preselectedOptions, configurationFileOpti
119
118
  phpmyadmin: configurationFileOptions.phpmyadmin,
120
119
  xdebug: configurationFileOptions.xdebug,
121
120
  xdebugConfig: configurationFileOptions['xdebug-config'],
122
- mailpit: (_configurationFileOpt = configurationFileOptions.mailpit) !== null && _configurationFileOpt !== void 0 ? _configurationFileOpt : configurationFileOptions.mailhog,
121
+ mailpit: configurationFileOptions.mailpit ?? configurationFileOptions.mailhog,
123
122
  mediaRedirectDomain: configurationFileOptions['media-redirect-domain'],
124
123
  photon: configurationFileOptions.photon
125
124
  };