@appium/support 2.57.3 → 2.59.0

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 (68) hide show
  1. package/build/lib/console.d.ts +110 -0
  2. package/build/lib/console.d.ts.map +1 -0
  3. package/build/lib/console.js +113 -0
  4. package/build/lib/env.d.ts.map +1 -1
  5. package/build/lib/env.js +1 -1
  6. package/build/lib/fs.d.ts.map +1 -1
  7. package/build/lib/fs.js +1 -1
  8. package/build/lib/image-util.d.ts.map +1 -1
  9. package/build/lib/image-util.js +1 -1
  10. package/build/lib/index.d.ts +3 -1
  11. package/build/lib/index.js +8 -3
  12. package/build/lib/log-internal.d.ts.map +1 -1
  13. package/build/lib/log-internal.js +1 -1
  14. package/build/lib/logger.d.ts +1 -1
  15. package/build/lib/logger.d.ts.map +1 -1
  16. package/build/lib/logger.js +1 -1
  17. package/build/lib/logging.d.ts +11 -4
  18. package/build/lib/logging.d.ts.map +1 -1
  19. package/build/lib/logging.js +7 -6
  20. package/build/lib/mjpeg.d.ts.map +1 -1
  21. package/build/lib/mjpeg.js +1 -1
  22. package/build/lib/mkdirp.js +1 -1
  23. package/build/lib/net.d.ts +5 -2
  24. package/build/lib/net.d.ts.map +1 -1
  25. package/build/lib/net.js +1 -1
  26. package/build/lib/node.d.ts +14 -0
  27. package/build/lib/node.d.ts.map +1 -1
  28. package/build/lib/node.js +22 -1
  29. package/build/lib/npm.d.ts.map +1 -1
  30. package/build/lib/npm.js +1 -1
  31. package/build/lib/plist.d.ts +1 -1
  32. package/build/lib/plist.d.ts.map +1 -1
  33. package/build/lib/plist.js +1 -1
  34. package/build/lib/process.d.ts.map +1 -1
  35. package/build/lib/process.js +1 -1
  36. package/build/lib/system.js +1 -1
  37. package/build/lib/tempdir.d.ts.map +1 -1
  38. package/build/lib/tempdir.js +1 -1
  39. package/build/lib/timing.d.ts.map +1 -1
  40. package/build/lib/timing.js +1 -1
  41. package/build/lib/util.d.ts +19 -2
  42. package/build/lib/util.d.ts.map +1 -1
  43. package/build/lib/util.js +3 -7
  44. package/build/lib/zip.d.ts +5 -5
  45. package/build/lib/zip.d.ts.map +1 -1
  46. package/build/lib/zip.js +2 -2
  47. package/build/tsconfig.tsbuildinfo +1 -1
  48. package/lib/console.js +173 -0
  49. package/lib/env.js +12 -14
  50. package/lib/fs.js +87 -62
  51. package/lib/image-util.js +50 -32
  52. package/lib/index.js +39 -8
  53. package/lib/log-internal.js +16 -11
  54. package/lib/logger.js +1 -1
  55. package/lib/logging.js +32 -30
  56. package/lib/mjpeg.js +32 -27
  57. package/lib/mkdirp.js +3 -3
  58. package/lib/net.js +60 -52
  59. package/lib/node.js +50 -16
  60. package/lib/npm.js +50 -47
  61. package/lib/plist.js +34 -18
  62. package/lib/process.js +8 -6
  63. package/lib/system.js +8 -8
  64. package/lib/tempdir.js +14 -9
  65. package/lib/timing.js +12 -15
  66. package/lib/util.js +121 -72
  67. package/lib/zip.js +88 -92
  68. package/package.json +11 -16
package/lib/net.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import _ from 'lodash';
2
2
  import fs from './fs';
3
3
  import B from 'bluebird';
4
- import { toReadableSizeString } from './util';
4
+ import {toReadableSizeString} from './util';
5
5
  import log from './logger';
6
6
  import Ftp from 'jsftp';
7
7
  import Timer from './timing';
@@ -12,10 +12,10 @@ const DEFAULT_TIMEOUT_MS = 4 * 60 * 1000;
12
12
 
13
13
  /**
14
14
  * Converts {@linkcode AuthCredentials} to credentials understood by {@linkcode axios}.
15
- * @param {AuthCredentials | import('axios').AxiosBasicCredentials} auth
15
+ * @param {AuthCredentials | import('axios').AxiosBasicCredentials} [auth]
16
16
  * @returns {import('axios').AxiosBasicCredentials?}
17
17
  */
18
- function toAxiosAuth (auth) {
18
+ function toAxiosAuth(auth) {
19
19
  if (!_.isPlainObject(auth)) {
20
20
  return null;
21
21
  }
@@ -24,7 +24,7 @@ function toAxiosAuth (auth) {
24
24
  username: _.get(auth, 'username', _.get(auth, 'user')),
25
25
  password: _.get(auth, 'password', _.get(auth, 'pass')),
26
26
  };
27
- return (axiosAuth.username && axiosAuth.password) ? axiosAuth : null;
27
+ return axiosAuth.username && axiosAuth.password ? axiosAuth : null;
28
28
  }
29
29
 
30
30
  /**
@@ -32,7 +32,11 @@ function toAxiosAuth (auth) {
32
32
  * @param {URL} parsedUri
33
33
  * @param {HttpUploadOptions & NetOptions} [uploadOptions]
34
34
  */
35
- async function uploadFileToHttp (localFileStream, parsedUri, uploadOptions = /** @type {HttpUploadOptions & NetOptions} */({})) {
35
+ async function uploadFileToHttp(
36
+ localFileStream,
37
+ parsedUri,
38
+ uploadOptions = /** @type {HttpUploadOptions & NetOptions} */ ({})
39
+ ) {
36
40
  const {
37
41
  method = 'POST',
38
42
  timeout = DEFAULT_TIMEOUT_MS,
@@ -41,7 +45,7 @@ async function uploadFileToHttp (localFileStream, parsedUri, uploadOptions = /**
41
45
  fileFieldName = 'file',
42
46
  formFields,
43
47
  } = uploadOptions;
44
- const { href } = parsedUri;
48
+ const {href} = parsedUri;
45
49
 
46
50
  /** @type {import('axios').AxiosRequestConfig} */
47
51
  const requestOpts = {
@@ -73,7 +77,7 @@ async function uploadFileToHttp (localFileStream, parsedUri, uploadOptions = /**
73
77
  }
74
78
  requestOpts.headers = {
75
79
  ...(_.isPlainObject(headers) ? headers : {}),
76
- ...form.getHeaders()
80
+ ...form.getHeaders(),
77
81
  };
78
82
  requestOpts.data = form;
79
83
  } else {
@@ -82,8 +86,10 @@ async function uploadFileToHttp (localFileStream, parsedUri, uploadOptions = /**
82
86
  }
83
87
  requestOpts.data = localFileStream;
84
88
  }
85
- log.debug(`Performing ${method} to ${href} with options (excluding data): ` +
86
- JSON.stringify(_.omit(requestOpts, ['data'])));
89
+ log.debug(
90
+ `Performing ${method} to ${href} with options (excluding data): ` +
91
+ JSON.stringify(_.omit(requestOpts, ['data']))
92
+ );
87
93
 
88
94
  const {status, statusText} = await axios(requestOpts);
89
95
  log.info(`Server response: ${status} ${statusText}`);
@@ -94,16 +100,13 @@ async function uploadFileToHttp (localFileStream, parsedUri, uploadOptions = /**
94
100
  * @param {URL} parsedUri
95
101
  * @param {NotHttpUploadOptions & NetOptions} [uploadOptions]
96
102
  */
97
- async function uploadFileToFtp (localFileStream, parsedUri, uploadOptions = /** @type {NotHttpUploadOptions & NetOptions} */({})) {
98
- const {
99
- auth,
100
- } = uploadOptions;
101
- const {
102
- hostname,
103
- port,
104
- protocol,
105
- pathname,
106
- } = parsedUri;
103
+ async function uploadFileToFtp(
104
+ localFileStream,
105
+ parsedUri,
106
+ uploadOptions = /** @type {NotHttpUploadOptions & NetOptions} */ ({})
107
+ ) {
108
+ const {auth} = uploadOptions;
109
+ const {hostname, port, protocol, pathname} = parsedUri;
107
110
 
108
111
  const ftpOpts = {
109
112
  host: hostname,
@@ -131,7 +134,7 @@ async function uploadFileToFtp (localFileStream, parsedUri, uploadOptions = /**
131
134
  * @param {URL} url
132
135
  * @returns {opts is HttpUploadOptions & NetOptions}
133
136
  */
134
- function isHttpUploadOptions (opts, url) {
137
+ function isHttpUploadOptions(opts, url) {
135
138
  try {
136
139
  const {protocol} = new URL(url);
137
140
  return protocol === 'http:' || protocol === 'https:';
@@ -146,7 +149,7 @@ function isHttpUploadOptions (opts, url) {
146
149
  * @param {URL} url
147
150
  * @returns {opts is NotHttpUploadOptions & NetOptions}
148
151
  */
149
- function isNotHttpUploadOptions (opts, url) {
152
+ function isNotHttpUploadOptions(opts, url) {
150
153
  try {
151
154
  const {protocol} = new URL(url);
152
155
  return protocol === 'ftp:';
@@ -163,14 +166,16 @@ function isNotHttpUploadOptions (opts, url) {
163
166
  * @param {(HttpUploadOptions|NotHttpUploadOptions) & NetOptions} [uploadOptions]
164
167
  * @returns {Promise<void>}
165
168
  */
166
- async function uploadFile (localPath, remoteUri, uploadOptions = /** @type {(HttpUploadOptions|NotHttpUploadOptions) & NetOptions} */({})) {
167
- if (!await fs.exists(localPath)) {
168
- throw new Error (`'${localPath}' does not exists or is not accessible`);
169
+ async function uploadFile(
170
+ localPath,
171
+ remoteUri,
172
+ uploadOptions = /** @type {(HttpUploadOptions|NotHttpUploadOptions) & NetOptions} */ ({})
173
+ ) {
174
+ if (!(await fs.exists(localPath))) {
175
+ throw new Error(`'${localPath}' does not exists or is not accessible`);
169
176
  }
170
177
 
171
- const {
172
- isMetered = true,
173
- } = uploadOptions;
178
+ const {isMetered = true} = uploadOptions;
174
179
  const url = new URL(remoteUri);
175
180
  const {size} = await fs.stat(localPath);
176
181
  if (isMetered) {
@@ -181,20 +186,24 @@ async function uploadFile (localPath, remoteUri, uploadOptions = /** @type {(Htt
181
186
  if (!uploadOptions.fileFieldName) {
182
187
  uploadOptions.headers = {
183
188
  ...(_.isPlainObject(uploadOptions.headers) ? uploadOptions.headers : {}),
184
- 'Content-Length': size
189
+ 'Content-Length': size,
185
190
  };
186
191
  }
187
192
  await uploadFileToHttp(fs.createReadStream(localPath), url, uploadOptions);
188
193
  } else if (isNotHttpUploadOptions(uploadOptions, url)) {
189
194
  await uploadFileToFtp(fs.createReadStream(localPath), url, uploadOptions);
190
195
  } else {
191
- throw new Error(`Cannot upload the file at '${localPath}' to '${remoteUri}'. ` +
192
- `Unsupported remote protocol '${url.protocol}'. ` +
193
- `Only http/https and ftp/ftps protocols are supported.`);
196
+ throw new Error(
197
+ `Cannot upload the file at '${localPath}' to '${remoteUri}'. ` +
198
+ `Unsupported remote protocol '${url.protocol}'. ` +
199
+ `Only http/https and ftp/ftps protocols are supported.`
200
+ );
194
201
  }
195
202
  if (isMetered) {
196
- log.info(`Uploaded '${localPath}' of ${toReadableSizeString(size)} size in ` +
197
- `${timer.getDuration().asSeconds.toFixed(3)}s`);
203
+ log.info(
204
+ `Uploaded '${localPath}' of ${toReadableSizeString(size)} size in ` +
205
+ `${timer.getDuration().asSeconds.toFixed(3)}s`
206
+ );
198
207
  }
199
208
  }
200
209
 
@@ -206,13 +215,12 @@ async function uploadFile (localPath, remoteUri, uploadOptions = /** @type {(Htt
206
215
  * @param {DownloadOptions & NetOptions} [downloadOptions]
207
216
  * @throws {Error} If download operation fails
208
217
  */
209
- async function downloadFile (remoteUrl, dstPath, downloadOptions = /** @type {DownloadOptions & NetOptions} */({})) {
210
- const {
211
- isMetered = true,
212
- auth,
213
- timeout = DEFAULT_TIMEOUT_MS,
214
- headers,
215
- } = downloadOptions;
218
+ async function downloadFile(
219
+ remoteUrl,
220
+ dstPath,
221
+ downloadOptions = /** @type {DownloadOptions & NetOptions} */ ({})
222
+ ) {
223
+ const {isMetered = true, auth, timeout = DEFAULT_TIMEOUT_MS, headers} = downloadOptions;
216
224
 
217
225
  /**
218
226
  * @type {import('axios').AxiosRequestConfig}
@@ -234,10 +242,7 @@ async function downloadFile (remoteUrl, dstPath, downloadOptions = /** @type {Do
234
242
  let responseLength;
235
243
  try {
236
244
  const writer = fs.createWriteStream(dstPath);
237
- const {
238
- data: responseStream,
239
- headers: responseHeaders,
240
- } = await axios(requestOpts);
245
+ const {data: responseStream, headers: responseHeaders} = await axios(requestOpts);
241
246
  responseLength = parseInt(responseHeaders['content-length'], 10);
242
247
  responseStream.pipe(writer);
243
248
 
@@ -256,13 +261,17 @@ async function downloadFile (remoteUrl, dstPath, downloadOptions = /** @type {Do
256
261
  const {size} = await fs.stat(dstPath);
257
262
  if (responseLength && size !== responseLength) {
258
263
  await fs.rimraf(dstPath);
259
- throw new Error(`The size of the file downloaded from ${remoteUrl} (${size} bytes) ` +
260
- `differs from the one in Content-Length response header (${responseLength} bytes)`);
264
+ throw new Error(
265
+ `The size of the file downloaded from ${remoteUrl} (${size} bytes) ` +
266
+ `differs from the one in Content-Length response header (${responseLength} bytes)`
267
+ );
261
268
  }
262
269
  if (isMetered) {
263
270
  const secondsElapsed = timer.getDuration().asSeconds;
264
- log.debug(`${remoteUrl} (${toReadableSizeString(size)}) ` +
265
- `has been downloaded to '${dstPath}' in ${secondsElapsed.toFixed(3)}s`);
271
+ log.debug(
272
+ `${remoteUrl} (${toReadableSizeString(size)}) ` +
273
+ `has been downloaded to '${dstPath}' in ${secondsElapsed.toFixed(3)}s`
274
+ );
266
275
  if (secondsElapsed >= 2) {
267
276
  const bytesPerSec = Math.floor(size / secondsElapsed);
268
277
  log.debug(`Approximate download speed: ${toReadableSizeString(bytesPerSec)}/s`);
@@ -270,21 +279,21 @@ async function downloadFile (remoteUrl, dstPath, downloadOptions = /** @type {Do
270
279
  }
271
280
  }
272
281
 
273
- export { uploadFile, downloadFile };
282
+ export {uploadFile, downloadFile};
274
283
 
275
284
  /**
276
285
  * Common options for {@linkcode uploadFile} and {@linkcode downloadFile}.
277
286
  * @typedef NetOptions
278
287
  * @property {boolean} [isMetered=true] - Whether to log the actual download performance
279
288
  * (e.g. timings and speed)
280
- * @property {AuthCredentials} auth
289
+ * @property {AuthCredentials} [auth] - Authentication credentials
281
290
  */
282
291
 
283
292
  /**
284
293
  * Specific options for {@linkcode downloadFile}.
285
294
  * @typedef DownloadOptions
286
295
  * @property {number} [timeout] - The actual request timeout in milliseconds; defaults to {@linkcode DEFAULT_TIMEOUT_MS}
287
- * @property {Record<string,any>} headers - Request headers mapping
296
+ * @property {Record<string,any>} [headers] - Request headers mapping
288
297
  */
289
298
 
290
299
  /**
@@ -316,4 +325,3 @@ export { uploadFile, downloadFile };
316
325
  * to be included into the upload request. This property is only considered if
317
326
  * `fileFieldName` is set
318
327
  */
319
-
package/lib/node.js CHANGED
@@ -1,9 +1,9 @@
1
- import { isWindows } from './system';
1
+ import {isWindows} from './system';
2
2
  import log from './logger';
3
3
  import _ from 'lodash';
4
- import { exec } from 'teen_process';
4
+ import {exec} from 'teen_process';
5
5
  import path from 'path';
6
- import { v4 as uuidV4 } from 'uuid';
6
+ import {v4 as uuidV4} from 'uuid';
7
7
 
8
8
  const ECMA_SIZES = Object.freeze({
9
9
  STRING: 2,
@@ -17,7 +17,7 @@ const ECMA_SIZES = Object.freeze({
17
17
  * @param {string} packageName - name of the package to link
18
18
  * @throws {Error} If the command fails
19
19
  */
20
- async function linkGlobalPackage (packageName) {
20
+ async function linkGlobalPackage(packageName) {
21
21
  try {
22
22
  log.debug(`Linking package '${packageName}'`);
23
23
  const cmd = isWindows() ? 'npm.cmd' : 'npm';
@@ -43,7 +43,7 @@ async function linkGlobalPackage (packageName) {
43
43
  * @returns {Promise<unknown>} - the package object
44
44
  * @throws {Error} If the package is not found locally or globally
45
45
  */
46
- async function requirePackage (packageName) {
46
+ async function requirePackage(packageName) {
47
47
  // first, get it in the normal way (see https://nodejs.org/api/modules.html#modules_all_together)
48
48
  try {
49
49
  log.debug(`Loading local package '${packageName}'`);
@@ -54,7 +54,12 @@ async function requirePackage (packageName) {
54
54
 
55
55
  // second, get it from where it ought to be in the global node_modules
56
56
  try {
57
- const globalPackageName = path.resolve(process.env.npm_config_prefix ?? '', 'lib', 'node_modules', packageName);
57
+ const globalPackageName = path.resolve(
58
+ process.env.npm_config_prefix ?? '',
59
+ 'lib',
60
+ 'node_modules',
61
+ packageName
62
+ );
58
63
  log.debug(`Loading global package '${globalPackageName}'`);
59
64
  return require(globalPackageName);
60
65
  } catch (err) {
@@ -71,18 +76,18 @@ async function requirePackage (packageName) {
71
76
  }
72
77
  }
73
78
 
74
- function extractAllProperties (obj) {
79
+ function extractAllProperties(obj) {
75
80
  const stringProperties = [];
76
81
  for (const prop in obj) {
77
82
  stringProperties.push(prop);
78
83
  }
79
84
  if (_.isFunction(Object.getOwnPropertySymbols)) {
80
- stringProperties.push(...(Object.getOwnPropertySymbols(obj)));
85
+ stringProperties.push(...Object.getOwnPropertySymbols(obj));
81
86
  }
82
87
  return stringProperties;
83
88
  }
84
89
 
85
- function _getSizeOfObject (seen, object) {
90
+ function _getSizeOfObject(seen, object) {
86
91
  if (_.isNil(object)) {
87
92
  return 0;
88
93
  }
@@ -113,13 +118,13 @@ function _getSizeOfObject (seen, object) {
113
118
  return bytes;
114
119
  }
115
120
 
116
- function getCalculator (seen) {
117
- return function calculator (obj) {
121
+ function getCalculator(seen) {
122
+ return function calculator(obj) {
118
123
  if (_.isBuffer(obj)) {
119
124
  return obj.length;
120
125
  }
121
126
 
122
- switch (typeof (obj)) {
127
+ switch (typeof obj) {
123
128
  case 'string':
124
129
  return obj.length * ECMA_SIZES.STRING;
125
130
  case 'boolean':
@@ -128,7 +133,7 @@ function getCalculator (seen) {
128
133
  return ECMA_SIZES.NUMBER;
129
134
  case 'symbol':
130
135
  return _.isFunction(Symbol.keyFor) && Symbol.keyFor(obj)
131
- ? /** @type {string} */(Symbol.keyFor(obj)).length * ECMA_SIZES.STRING
136
+ ? /** @type {string} */ (Symbol.keyFor(obj)).length * ECMA_SIZES.STRING
132
137
  : (obj.toString().length - 8) * ECMA_SIZES.STRING;
133
138
  case 'object':
134
139
  return _.isArray(obj)
@@ -147,7 +152,7 @@ function getCalculator (seen) {
147
152
  * @param {*} obj An object whose size should be calculated
148
153
  * @returns {number} Object size in bytes.
149
154
  */
150
- function getObjectSize (obj) {
155
+ function getObjectSize(obj) {
151
156
  return getCalculator(new WeakSet())(obj);
152
157
  }
153
158
 
@@ -159,11 +164,40 @@ const OBJECTS_MAPPING = new WeakMap();
159
164
  * @param {object} object Any valid ECMA object
160
165
  * @returns {string} A uuidV4 string that uniquely identifies given object
161
166
  */
162
- function getObjectId (object) {
167
+ function getObjectId(object) {
163
168
  if (!OBJECTS_MAPPING.has(object)) {
164
169
  OBJECTS_MAPPING.set(object, uuidV4());
165
170
  }
166
171
  return OBJECTS_MAPPING.get(object);
167
172
  }
168
173
 
169
- export { requirePackage, getObjectSize, getObjectId };
174
+ /**
175
+ * Perform deep freeze of the given object (e. g.
176
+ * all nested objects also become immutable).
177
+ * If the passed object is of a plain type
178
+ * then no change is done and the same object
179
+ * is returned.
180
+ * ! This function changes the given object,
181
+ * so it becomes immutable.
182
+ *
183
+ * @param {*} object Any valid ECMA object
184
+ * @returns {*} The same object that was passed to the
185
+ * function after it was made immutable.
186
+ */
187
+ function deepFreeze(object) {
188
+ let propNames;
189
+ try {
190
+ propNames = Object.getOwnPropertyNames(object);
191
+ } catch (ign) {
192
+ return object;
193
+ }
194
+ for (const name of propNames) {
195
+ const value = object[name];
196
+ if (value && typeof value === 'object') {
197
+ deepFreeze(value);
198
+ }
199
+ }
200
+ return Object.freeze(object);
201
+ }
202
+
203
+ export {requirePackage, getObjectSize, getObjectId, deepFreeze};
package/lib/npm.js CHANGED
@@ -2,31 +2,23 @@
2
2
 
3
3
  import path from 'path';
4
4
  import semver from 'semver';
5
- import { hasAppiumDependency } from './env';
6
- import { exec } from 'teen_process';
7
- import { fs } from './fs';
5
+ import {hasAppiumDependency} from './env';
6
+ import {exec} from 'teen_process';
7
+ import {fs} from './fs';
8
8
  import * as util from './util';
9
9
  import * as system from './system';
10
10
  import resolveFrom from 'resolve-from';
11
11
 
12
-
13
12
  /**
14
13
  * Relative path to directory containing any Appium internal files
15
14
  * XXX: this is duplicated in `appium/lib/constants.js`.
16
15
  */
17
- export const CACHE_DIR_RELATIVE_PATH = path.join(
18
- 'node_modules',
19
- '.cache',
20
- 'appium',
21
- );
16
+ export const CACHE_DIR_RELATIVE_PATH = path.join('node_modules', '.cache', 'appium');
22
17
 
23
18
  /**
24
19
  * Relative path to lockfile used when installing an extension via `appium`
25
20
  */
26
- export const INSTALL_LOCKFILE_RELATIVE_PATH = path.join(
27
- CACHE_DIR_RELATIVE_PATH,
28
- '.install.lock',
29
- );
21
+ export const INSTALL_LOCKFILE_RELATIVE_PATH = path.join(CACHE_DIR_RELATIVE_PATH, '.install.lock');
30
22
 
31
23
  /**
32
24
  * XXX: This should probably be a singleton, but it isn't. Maybe this module should just export functions?
@@ -37,7 +29,7 @@ export class NPM {
37
29
  * @private
38
30
  * @param {string} cwd
39
31
  */
40
- _getInstallLockfilePath (cwd) {
32
+ _getInstallLockfilePath(cwd) {
41
33
  return path.join(cwd, INSTALL_LOCKFILE_RELATIVE_PATH);
42
34
  }
43
35
 
@@ -51,8 +43,8 @@ export class NPM {
51
43
  * @param {ExecOpts} opts
52
44
  * @param {ExecOpts} [execOpts]
53
45
  */
54
- async exec (cmd, args, opts, execOpts = /** @type {ExecOpts} */({})) {
55
- let { cwd, json, lockFile } = opts;
46
+ async exec(cmd, args, opts, execOpts = /** @type {ExecOpts} */ ({})) {
47
+ let {cwd, json, lockFile} = opts;
56
48
 
57
49
  // make sure we perform the current operation in cwd
58
50
  execOpts = {...execOpts, cwd};
@@ -81,8 +73,12 @@ export class NPM {
81
73
  ret.json = JSON.parse(stdout);
82
74
  } catch (ign) {}
83
75
  } catch (e) {
84
- const {stdout = '', stderr = '', code = null} = /** @type {TeenProcessExecError} */(e);
85
- const err = new Error(`npm command '${args.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`);
76
+ const {stdout = '', stderr = '', code = null} = /** @type {TeenProcessExecError} */ (e);
77
+ const err = new Error(
78
+ `npm command '${args.join(
79
+ ' '
80
+ )}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`
81
+ );
86
82
  throw err;
87
83
  }
88
84
  return ret;
@@ -92,11 +88,13 @@ export class NPM {
92
88
  * @param {string} cwd
93
89
  * @param {string} pkg
94
90
  */
95
- async getLatestVersion (cwd, pkg) {
96
- return (await this.exec('view', [pkg, 'dist-tags'], {
97
- json: true,
98
- cwd
99
- })).json?.latest;
91
+ async getLatestVersion(cwd, pkg) {
92
+ return (
93
+ await this.exec('view', [pkg, 'dist-tags'], {
94
+ json: true,
95
+ cwd,
96
+ })
97
+ ).json?.latest;
100
98
  }
101
99
 
102
100
  /**
@@ -104,11 +102,13 @@ export class NPM {
104
102
  * @param {string} pkg
105
103
  * @param {string} curVersion
106
104
  */
107
- async getLatestSafeUpgradeVersion (cwd, pkg, curVersion) {
108
- const allVersions = (await this.exec('view', [pkg, 'versions'], {
109
- json: true,
110
- cwd
111
- })).json;
105
+ async getLatestSafeUpgradeVersion(cwd, pkg, curVersion) {
106
+ const allVersions = (
107
+ await this.exec('view', [pkg, 'versions'], {
108
+ json: true,
109
+ cwd,
110
+ })
111
+ ).json;
112
112
  return this.getLatestSafeUpgradeFromVersions(curVersion, allVersions);
113
113
  }
114
114
 
@@ -117,7 +117,7 @@ export class NPM {
117
117
  * @param {string} cwd
118
118
  * @param {string} [pkg]
119
119
  */
120
- async list (cwd, pkg) {
120
+ async list(cwd, pkg) {
121
121
  return (await this.exec('list', pkg ? [pkg] : [], {cwd, json: true})).json;
122
122
  }
123
123
 
@@ -131,7 +131,7 @@ export class NPM {
131
131
  *
132
132
  * @return {string|null} - the highest safely-upgradable version, or null if there isn't one
133
133
  */
134
- getLatestSafeUpgradeFromVersions (curVersion, allVersions) {
134
+ getLatestSafeUpgradeFromVersions(curVersion, allVersions) {
135
135
  let safeUpgradeVer = null;
136
136
  const curSemver = semver.parse(curVersion);
137
137
  if (curSemver === null) {
@@ -173,7 +173,7 @@ export class NPM {
173
173
  * @param {InstallPackageOpts} [opts]
174
174
  * @returns {Promise<import('type-fest').PackageJson>}
175
175
  */
176
- async installPackage (cwd, pkgName, {pkgVer} = {}) {
176
+ async installPackage(cwd, pkgName, {pkgVer} = {}) {
177
177
  /** @type {any} */
178
178
  let dummyPkgJson;
179
179
  const dummyPkgPath = path.join(cwd, 'package.json');
@@ -199,18 +199,19 @@ export class NPM {
199
199
  * "dummy" and is controlled by the user. So we'll just add it as a dev
200
200
  * dep; whatever else it does is up to the user's npm config.
201
201
  */
202
- const installOpts = await hasAppiumDependency(cwd) ?
203
- ['--save-dev'] :
204
- ['--save-dev', '--save-exact', '--global-style', '--no-package-lock'];
202
+ const installOpts = (await hasAppiumDependency(cwd))
203
+ ? ['--save-dev']
204
+ : ['--save-dev', '--save-exact', '--global-style', '--no-package-lock'];
205
205
 
206
- const res = await this.exec('install', [
207
- ...installOpts,
208
- pkgVer ? `${pkgName}@${pkgVer}` : pkgName
209
- ], {
210
- cwd,
211
- json: true,
212
- lockFile: this._getInstallLockfilePath(cwd)
213
- });
206
+ const res = await this.exec(
207
+ 'install',
208
+ [...installOpts, pkgVer ? `${pkgName}@${pkgVer}` : pkgName],
209
+ {
210
+ cwd,
211
+ json: true,
212
+ lockFile: this._getInstallLockfilePath(cwd),
213
+ }
214
+ );
214
215
 
215
216
  if (res.json) {
216
217
  // we parsed a valid json response, so if we got an error here, return that
@@ -228,9 +229,11 @@ export class NPM {
228
229
  try {
229
230
  return require(pkgJsonPath);
230
231
  } catch {
231
- throw new Error('The package was not downloaded correctly; its package.json ' +
232
- 'did not exist or was unreadable. We looked for it at ' +
233
- pkgJsonPath);
232
+ throw new Error(
233
+ 'The package was not downloaded correctly; its package.json ' +
234
+ 'did not exist or was unreadable. We looked for it at ' +
235
+ pkgJsonPath
236
+ );
234
237
  }
235
238
  }
236
239
 
@@ -238,10 +241,10 @@ export class NPM {
238
241
  * @param {string} cwd
239
242
  * @param {string} pkg
240
243
  */
241
- async uninstallPackage (cwd, pkg) {
244
+ async uninstallPackage(cwd, pkg) {
242
245
  await this.exec('uninstall', [pkg], {
243
246
  cwd,
244
- lockFile: this._getInstallLockfilePath(cwd)
247
+ lockFile: this._getInstallLockfilePath(cwd),
245
248
  });
246
249
  }
247
250
  }