@appium/support 7.0.4 → 7.0.6

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 (113) hide show
  1. package/build/lib/console.d.ts +42 -88
  2. package/build/lib/console.d.ts.map +1 -1
  3. package/build/lib/console.js +25 -85
  4. package/build/lib/console.js.map +1 -1
  5. package/build/lib/doctor.d.ts +6 -18
  6. package/build/lib/doctor.d.ts.map +1 -1
  7. package/build/lib/doctor.js +0 -15
  8. package/build/lib/doctor.js.map +1 -1
  9. package/build/lib/env.d.ts +14 -20
  10. package/build/lib/env.d.ts.map +1 -1
  11. package/build/lib/env.js +24 -61
  12. package/build/lib/env.js.map +1 -1
  13. package/build/lib/fs.d.ts +109 -148
  14. package/build/lib/fs.d.ts.map +1 -1
  15. package/build/lib/fs.js +130 -230
  16. package/build/lib/fs.js.map +1 -1
  17. package/build/lib/image-util.d.ts +7 -6
  18. package/build/lib/image-util.d.ts.map +1 -1
  19. package/build/lib/image-util.js +9 -6
  20. package/build/lib/image-util.js.map +1 -1
  21. package/build/lib/index.d.ts +19 -17
  22. package/build/lib/index.d.ts.map +1 -1
  23. package/build/lib/logger.d.ts +1 -1
  24. package/build/lib/logger.d.ts.map +1 -1
  25. package/build/lib/logger.js +1 -1
  26. package/build/lib/logger.js.map +1 -1
  27. package/build/lib/logging.d.ts +7 -15
  28. package/build/lib/logging.d.ts.map +1 -1
  29. package/build/lib/logging.js +36 -62
  30. package/build/lib/logging.js.map +1 -1
  31. package/build/lib/mjpeg.d.ts +19 -56
  32. package/build/lib/mjpeg.d.ts.map +1 -1
  33. package/build/lib/mjpeg.js +55 -78
  34. package/build/lib/mjpeg.js.map +1 -1
  35. package/build/lib/mkdirp.d.ts +4 -1
  36. package/build/lib/mkdirp.d.ts.map +1 -1
  37. package/build/lib/mkdirp.js +1 -2
  38. package/build/lib/mkdirp.js.map +1 -1
  39. package/build/lib/net.d.ts +52 -90
  40. package/build/lib/net.d.ts.map +1 -1
  41. package/build/lib/net.js +104 -193
  42. package/build/lib/net.js.map +1 -1
  43. package/build/lib/node.d.ts +16 -17
  44. package/build/lib/node.d.ts.map +1 -1
  45. package/build/lib/node.js +115 -120
  46. package/build/lib/node.js.map +1 -1
  47. package/build/lib/npm.d.ts +65 -86
  48. package/build/lib/npm.d.ts.map +1 -1
  49. package/build/lib/npm.js +64 -122
  50. package/build/lib/npm.js.map +1 -1
  51. package/build/lib/plist.d.ts +36 -29
  52. package/build/lib/plist.d.ts.map +1 -1
  53. package/build/lib/plist.js +62 -59
  54. package/build/lib/plist.js.map +1 -1
  55. package/build/lib/process.d.ts +19 -2
  56. package/build/lib/process.d.ts.map +1 -1
  57. package/build/lib/process.js +24 -7
  58. package/build/lib/process.js.map +1 -1
  59. package/build/lib/system.d.ts +41 -6
  60. package/build/lib/system.d.ts.map +1 -1
  61. package/build/lib/system.js +49 -14
  62. package/build/lib/system.js.map +1 -1
  63. package/build/lib/tempdir.d.ts +26 -49
  64. package/build/lib/tempdir.d.ts.map +1 -1
  65. package/build/lib/tempdir.js +46 -78
  66. package/build/lib/tempdir.js.map +1 -1
  67. package/build/lib/timing.d.ts +28 -22
  68. package/build/lib/timing.d.ts.map +1 -1
  69. package/build/lib/timing.js +16 -17
  70. package/build/lib/timing.js.map +1 -1
  71. package/build/lib/util.d.ts +164 -181
  72. package/build/lib/util.d.ts.map +1 -1
  73. package/build/lib/util.js +198 -253
  74. package/build/lib/util.js.map +1 -1
  75. package/build/lib/zip.d.ts +81 -139
  76. package/build/lib/zip.d.ts.map +1 -1
  77. package/build/lib/zip.js +235 -283
  78. package/build/lib/zip.js.map +1 -1
  79. package/lib/console.ts +139 -0
  80. package/lib/{doctor.js → doctor.ts} +6 -20
  81. package/lib/{env.js → env.ts} +34 -62
  82. package/lib/fs.ts +453 -0
  83. package/lib/image-util.ts +40 -0
  84. package/lib/index.ts +1 -0
  85. package/lib/{logger.js → logger.ts} +1 -1
  86. package/lib/logging.ts +157 -0
  87. package/lib/mjpeg.ts +186 -0
  88. package/lib/{mkdirp.js → mkdirp.ts} +2 -2
  89. package/lib/net.ts +305 -0
  90. package/lib/{node.js → node.ts} +136 -135
  91. package/lib/npm.ts +291 -0
  92. package/lib/plist.ts +187 -0
  93. package/lib/process.ts +62 -0
  94. package/lib/system.ts +95 -0
  95. package/lib/tempdir.ts +115 -0
  96. package/lib/{timing.js → timing.ts} +28 -33
  97. package/lib/util.ts +561 -0
  98. package/lib/{zip.js → zip.ts} +344 -299
  99. package/package.json +24 -26
  100. package/tsconfig.json +3 -5
  101. package/index.js +0 -1
  102. package/lib/console.js +0 -173
  103. package/lib/fs.js +0 -496
  104. package/lib/image-util.js +0 -32
  105. package/lib/logging.js +0 -145
  106. package/lib/mjpeg.js +0 -207
  107. package/lib/net.js +0 -336
  108. package/lib/npm.js +0 -310
  109. package/lib/plist.js +0 -182
  110. package/lib/process.js +0 -46
  111. package/lib/system.js +0 -48
  112. package/lib/tempdir.js +0 -131
  113. package/lib/util.js +0 -585
package/lib/tempdir.js DELETED
@@ -1,131 +0,0 @@
1
- /* This library is originated from temp.js at http://github.com/bruce/node-temp */
2
- import {fs} from './fs';
3
- import os from 'os';
4
- import nodePath from 'path';
5
- import cnst from 'constants';
6
- import log from './logger';
7
-
8
- const RDWR_EXCL = cnst.O_CREAT | cnst.O_TRUNC | cnst.O_RDWR | cnst.O_EXCL;
9
-
10
- /**
11
- * Generate a temporary directory in os.tempdir() or process.env.APPIUM_TMP_DIR.
12
- * e.g.
13
- * - No `process.env.APPIUM_TMP_DIR`: `/var/folders/34/2222sh8n27d6rcp7jqlkw8km0000gn/T/xxxxxxxx.yyyy`
14
- * - With `process.env.APPIUM_TMP_DIR = '/path/to/root'`: `/path/to/root/xxxxxxxx.yyyy`
15
- *
16
- * @returns {Promise<string>} A path to the temporary directory
17
- */
18
- async function tempDir() {
19
- const now = new Date();
20
- const filePath = nodePath.join(
21
- process.env.APPIUM_TMP_DIR || os.tmpdir(),
22
- [
23
- now.getFullYear(),
24
- now.getMonth(),
25
- now.getDate(),
26
- '-',
27
- process.pid,
28
- '-',
29
- (Math.random() * 0x100000000 + 1).toString(36),
30
- ].join('')
31
- );
32
- // creates a temp directory using the date and a random string
33
-
34
- await fs.mkdir(filePath, {recursive: true});
35
-
36
- return filePath;
37
- }
38
-
39
- /**
40
- * @typedef Affixes
41
- * @property {string} [prefix] - prefix of the temp directory name
42
- * @property {string} [suffix] - suffix of the temp directory name
43
- */
44
-
45
- /**
46
- * Generate a temporary directory in os.tempdir() or process.env.APPIUM_TMP_DIR
47
- * with arbitrary prefix/suffix for the directory name.
48
- *
49
- * @param {string|Affixes} rawAffixes
50
- * @param {string} [defaultPrefix]
51
- * @returns {Promise<string>} A path to the temporary directory with rawAffixes and defaultPrefix
52
- */
53
- async function path(rawAffixes, defaultPrefix) {
54
- const affixes = parseAffixes(rawAffixes, defaultPrefix);
55
- const name = `${affixes.prefix || ''}${affixes.suffix || ''}`;
56
- const tempDirectory = await tempDir();
57
- return nodePath.join(tempDirectory, name);
58
- }
59
-
60
- /**
61
- * @typedef OpenedAffixes
62
- * @property {string} path - The path to file
63
- * @property {number} fd - The file descriptor opened
64
- */
65
-
66
- /**
67
- * Generate a temporary directory in os.tempdir() or process.env.APPIUM_TMP_DIR
68
- * with arbitrary prefix/suffix for the directory name and return it as open.
69
- *
70
- * @param {Affixes} affixes
71
- * @returns {Promise<OpenedAffixes>}
72
- */
73
- async function open(affixes) {
74
- const filePath = await path(affixes, 'f-');
75
- try {
76
- let fd = await fs.open(filePath, RDWR_EXCL, 0o600);
77
- // opens the file in mode 384
78
- return {path: filePath, fd};
79
- } catch (err) {
80
- throw log.errorWithException(err);
81
- }
82
- }
83
-
84
- /**
85
- *
86
- * Returns prefix/suffix object
87
- *
88
- * @param {string|Affixes} rawAffixes
89
- * @param {string} [defaultPrefix]
90
- * @returns {Affixes}
91
- */
92
- function parseAffixes(rawAffixes, defaultPrefix) {
93
- /** @type {Affixes} */
94
- let affixes = {};
95
- if (rawAffixes) {
96
- switch (typeof rawAffixes) {
97
- case 'string':
98
- affixes.prefix = rawAffixes;
99
- break;
100
- case 'object':
101
- affixes = rawAffixes;
102
- break;
103
- default:
104
- throw new Error(`Unknown affix declaration: ${affixes}`);
105
- }
106
- } else {
107
- affixes.prefix = defaultPrefix;
108
- }
109
- return affixes;
110
- }
111
-
112
- const _static = tempDir();
113
-
114
- /**
115
- * Returns a new path to a temporary directory
116
- *
117
- * @returns {string} A new tempDir() if tempRootDirectory is not provided
118
- */
119
- const openDir = tempDir;
120
-
121
- /**
122
- * Returns a path to a temporary directory which is defined as static in the same process
123
- *
124
- * @returns {Promise<string>} A temp directory path which is defined as static in the same process
125
- */
126
-
127
- async function staticDir() {
128
- return _static;
129
- }
130
-
131
- export {open, path, openDir, staticDir};
package/lib/util.js DELETED
@@ -1,585 +0,0 @@
1
- import B from 'bluebird';
2
- import _ from 'lodash';
3
- import os from 'os';
4
- import path from 'path';
5
- import { fs } from './fs';
6
- import * as semver from 'semver';
7
- import {
8
- // https://www.npmjs.com/package/shell-quote
9
- quote as shellQuote,
10
- parse as shellParse,
11
- } from 'shell-quote';
12
- import pluralizeLib from 'pluralize';
13
- import stream from 'stream';
14
- import {Base64Encode} from 'base64-stream';
15
- import {
16
- // https://www.npmjs.com/package/uuid
17
- v1 as uuidV1,
18
- v3 as uuidV3,
19
- v4 as uuidV4,
20
- v5 as uuidV5,
21
- } from 'uuid';
22
- import * as _lockfile from 'lockfile';
23
-
24
- const W3C_WEB_ELEMENT_IDENTIFIER = 'element-6066-11e4-a52e-4f735466cecf';
25
- const KiB = 1024;
26
- const MiB = KiB * 1024;
27
- const GiB = MiB * 1024;
28
-
29
- /**
30
- * @template {string} T
31
- * @param {T} val
32
- * @returns {val is NonEmptyString<T>}
33
- */
34
- export function hasContent(val) {
35
- return _.isString(val) && val !== '';
36
- }
37
-
38
- /**
39
- * return true if the the value is not `undefined`, `null`, or `NaN`.
40
- *
41
- * XXX: `NaN` is not expressible in TypeScript.
42
- * @template T
43
- * @param {T} val
44
- * @returns {val is NonNullable<T>}
45
- */
46
- function hasValue(val) {
47
- // avoid incorrectly evaluating `0` as false
48
- if (_.isNumber(val)) {
49
- return !_.isNaN(val);
50
- }
51
- return !_.isUndefined(val) && !_.isNull(val);
52
- }
53
-
54
- /**
55
- * Escape spaces in string, for commandline calls
56
- * @param {string} str - The string to escape spaces in
57
- * @returns {string} The string with escaped spaces
58
- */
59
- function escapeSpace(str) {
60
- return str.split(/ /).join('\\ ');
61
- }
62
-
63
- /**
64
- * Escape special characters in string
65
- * @param {string|any} str - The string to escape special characters in
66
- * @param {string} quoteEscape - Whether to escape quotes
67
- * @returns {string|any} The string with escaped special characters, or original value if not a string
68
- */
69
- function escapeSpecialChars(str, quoteEscape) {
70
- if (typeof str !== 'string') {
71
- return str;
72
- }
73
- if (typeof quoteEscape === 'undefined') {
74
- // @ts-ignore to set false to mark no quote escaping
75
- quoteEscape = false;
76
- }
77
- str = str
78
- .replace(/[\\]/g, '\\\\')
79
- .replace(/[\/]/g, '\\/') // eslint-disable-line no-useless-escape
80
- .replace(/[\b]/g, '\\b')
81
- .replace(/[\f]/g, '\\f')
82
- .replace(/[\n]/g, '\\n')
83
- .replace(/[\r]/g, '\\r')
84
- .replace(/[\t]/g, '\\t')
85
- .replace(/[\"]/g, '\\"') // eslint-disable-line no-useless-escape
86
- .replace(/\\'/g, "\\'");
87
- if (quoteEscape) {
88
- const re = new RegExp(quoteEscape, 'g');
89
- str = str.replace(re, `\\${quoteEscape}`);
90
- }
91
- return str;
92
- }
93
-
94
- /**
95
- * Get the local IP address of the machine
96
- * @returns {string|undefined} The local IP address of the first external IPv4 interface, or undefined if not found
97
- */
98
- function localIp() {
99
- let ip = _.chain(os.networkInterfaces())
100
- .values()
101
- .flatten()
102
- // @ts-ignore this filter works fine
103
- .filter(({family, internal}) => family === 'IPv4' && internal === false)
104
- .map('address')
105
- .first()
106
- .value();
107
- return ip;
108
- }
109
-
110
- /*
111
- * Creates a promise that is cancellable, and will timeout
112
- * after `ms` delay
113
- */
114
- function cancellableDelay(ms) {
115
- let timer;
116
- let resolve;
117
- let reject;
118
-
119
- const delay = new B.Promise((_resolve, _reject) => {
120
- resolve = _resolve;
121
- reject = _reject;
122
- timer = setTimeout(function () {
123
- resolve();
124
- }, ms);
125
- });
126
-
127
- // override Bluebird's `cancel`, which does not work when using `await` on
128
- // a promise, since `resolve`/`reject` are never called
129
- delay.cancel = function () {
130
- clearTimeout(timer);
131
- // eslint-disable-next-line import/no-named-as-default-member
132
- reject(new B.CancellationError());
133
- };
134
- return delay;
135
- }
136
-
137
- function multiResolve(roots, ...args) {
138
- return roots.map((root) => path.resolve(root, ...args));
139
- }
140
-
141
- /**
142
- * Parses an object if possible. Otherwise returns the object without parsing.
143
- *
144
- * @param {any} obj
145
- * @returns {any}
146
- */
147
- function safeJsonParse(obj) {
148
- try {
149
- return JSON.parse(obj);
150
- } catch {
151
- // ignore: this is not json parsable
152
- return obj;
153
- }
154
- }
155
-
156
- /**
157
- * Stringifies the object passed in, converting Buffers into Strings for better
158
- * display. This mimics JSON.stringify (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)
159
- * except the `replacer` argument can only be a function.
160
- *
161
- * @param {any} obj - the object to be serialized
162
- * @param {((key:any, value:any) => any)?} replacer - function to transform the properties added to the
163
- * serialized object
164
- * @param {number|string|undefined} space - used to insert white space into the output JSON
165
- * string for readability purposes. Defaults to 2
166
- * @returns {string} - the JSON object serialized as a string
167
- */
168
- function jsonStringify(obj, replacer = null, space = 2) {
169
- // if no replacer is passed, or it is not a function, just use a pass-through
170
- const replacerFunc = _.isFunction(replacer) ? replacer : (k, v) => v;
171
-
172
- // Buffers cannot be serialized in a readable way
173
- const bufferToJSON = Buffer.prototype.toJSON;
174
- delete Buffer.prototype.toJSON;
175
- try {
176
- return JSON.stringify(
177
- obj,
178
- (key, value) => {
179
- const updatedValue = Buffer.isBuffer(value) ? value.toString('utf8') : value;
180
- return replacerFunc(key, updatedValue);
181
- },
182
- space
183
- );
184
- } finally {
185
- // restore the function, so as to not break further serialization
186
- Buffer.prototype.toJSON = bufferToJSON;
187
- }
188
- }
189
-
190
- /**
191
- * Removes the wrapper from element, if it exists.
192
- * { ELEMENT: 4 } becomes 4
193
- * { element-6066-11e4-a52e-4f735466cecf: 5 } becomes 5
194
- * @param {import('@appium/types').Element|string} el
195
- * @returns {string}
196
- */
197
- function unwrapElement(el) {
198
- for (const propName of [W3C_WEB_ELEMENT_IDENTIFIER, 'ELEMENT']) {
199
- if (_.has(el, propName)) {
200
- return /** @type {string} */ (el[propName]);
201
- }
202
- }
203
- return /** @type {string} */(el);
204
- }
205
-
206
- /**
207
- *
208
- * @param {string} elementId
209
- * @returns {import('@appium/types').Element}
210
- */
211
- function wrapElement(elementId) {
212
- return {
213
- ELEMENT: elementId,
214
- [W3C_WEB_ELEMENT_IDENTIFIER]: elementId,
215
- };
216
- }
217
-
218
- /*
219
- * Returns object consisting of all properties in the original element
220
- * which were truthy given the predicate.
221
- * If the predicate is
222
- * * missing - it will remove all properties whose values are `undefined`
223
- * * a scalar - it will test all properties' values against that value
224
- * * a function - it will pass each value and the original object into the function
225
- */
226
- function filterObject(obj, predicate) {
227
- let newObj = _.clone(obj);
228
- if (_.isUndefined(predicate)) {
229
- // remove any element from the object whose value is undefined
230
- predicate = (v) => !_.isUndefined(v);
231
- } else if (!_.isFunction(predicate)) {
232
- // make predicate into a function
233
- const valuePredicate = predicate;
234
- predicate = (v) => v === valuePredicate;
235
- }
236
- for (const key of Object.keys(obj)) {
237
- if (!predicate(obj[key], obj)) {
238
- delete newObj[key];
239
- }
240
- }
241
- return newObj;
242
- }
243
-
244
- /**
245
- * Converts number of bytes to a readable size string.
246
- *
247
- * @param {number|string} bytes - The actual number of bytes.
248
- * @returns {string} The actual string representation, for example
249
- * '1.00 KB' for '1024 B'
250
- * @throws {Error} If bytes count cannot be converted to an integer or
251
- * if it is less than zero.
252
- */
253
- function toReadableSizeString(bytes) {
254
- const intBytes = parseInt(String(bytes), 10);
255
- if (isNaN(intBytes) || intBytes < 0) {
256
- throw new Error(`Cannot convert '${bytes}' to a readable size format`);
257
- }
258
- if (intBytes >= GiB) {
259
- return `${(intBytes / (GiB * 1.0)).toFixed(2)} GB`;
260
- } else if (intBytes >= MiB) {
261
- return `${(intBytes / (MiB * 1.0)).toFixed(2)} MB`;
262
- } else if (intBytes >= KiB) {
263
- return `${(intBytes / (KiB * 1.0)).toFixed(2)} KB`;
264
- }
265
- return `${intBytes} B`;
266
- }
267
-
268
- /**
269
- * Checks whether the given path is a subpath of the
270
- * particular root folder. Both paths can include .. and . specifiers
271
- *
272
- * @param {string} originalPath The absolute file/folder path
273
- * @param {string} root The absolute root folder path
274
- * @param {?boolean} forcePosix Set it to true if paths must be interpreted in POSIX format
275
- * @returns {boolean} true if the given original path is the subpath of the root folder
276
- * @throws {Error} if any of the given paths is not absolute
277
- */
278
- function isSubPath(originalPath, root, forcePosix = null) {
279
- const pathObj = forcePosix ? path.posix : path;
280
- for (const p of [originalPath, root]) {
281
- if (!pathObj.isAbsolute(p)) {
282
- throw new Error(`'${p}' is expected to be an absolute path`);
283
- }
284
- }
285
- const normalizedRoot = pathObj.normalize(root);
286
- const normalizedPath = pathObj.normalize(originalPath);
287
- return normalizedPath.startsWith(normalizedRoot);
288
- }
289
-
290
- /**
291
- * Checks whether the given paths are pointing to the same file system
292
- * destination.
293
- *
294
- * @param {string} path1 - Absolute or relative path to a file/folder
295
- * @param {string} path2 - Absolute or relative path to a file/folder
296
- * @param {...string} pathN - Zero or more absolute or relative paths to files/folders
297
- * @returns {Promise<boolean>} true if all paths are pointing to the same file system item
298
- */
299
- async function isSameDestination(path1, path2, ...pathN) {
300
- const allPaths = [path1, path2, ...pathN];
301
- if (!(await B.reduce(allPaths, async (a, b) => a && (await fs.exists(b)), true))) {
302
- return false;
303
- }
304
-
305
- const areAllItemsEqual = (arr) => !!arr.reduce((a, b) => (a === b ? a : NaN));
306
- if (areAllItemsEqual(allPaths)) {
307
- return true;
308
- }
309
-
310
- let mapCb = async (x) =>
311
- (
312
- await fs.stat(x, {
313
- bigint: true,
314
- })
315
- ).ino;
316
- return areAllItemsEqual(await B.map(allPaths, mapCb));
317
- }
318
-
319
- /**
320
- * Coerces the given number/string to a valid version string
321
- *
322
- * @template {boolean} [Strict=true]
323
- * @param {string} ver - Version string to coerce
324
- * @param {Strict} [strict] - If `true` then an exception will be thrown
325
- * if `ver` cannot be coerced
326
- * @returns {Strict extends true ? string : string|null} Coerced version number or null if the string cannot be
327
- * coerced and strict mode is disabled
328
- * @throws {Error} if strict mode is enabled and `ver` cannot be coerced
329
- */
330
- function coerceVersion(ver, strict = /** @type {Strict} */ (true)) {
331
- // First try to parse as-is, then coerce if needed
332
- let result = semver.valid(`${ver}`);
333
- if (!result) {
334
- result = semver.valid(semver.coerce(`${ver}`));
335
- }
336
- if (strict && !result) {
337
- throw new Error(`'${ver}' cannot be coerced to a valid version number`);
338
- }
339
- return /** @type {Strict extends true ? string : string?} */ (result);
340
- }
341
-
342
- const SUPPORTED_OPERATORS = ['==', '!=', '>', '<', '>=', '<=', '='];
343
-
344
- /**
345
- * Compares two version strings
346
- *
347
- * @param {string} ver1 - The first version number to compare. Should be a valid
348
- * version number supported by semver parser.
349
- * @param {string} ver2 - The second version number to compare. Should be a valid
350
- * version number supported by semver parser.
351
- * @param {string} operator - One of supported version number operators:
352
- * ==, !=, >, <, <=, >=, =
353
- * @returns {boolean} true or false depending on the actual comparison result
354
- * @throws {Error} if an unsupported operator is supplied or any of the supplied
355
- * version strings cannot be coerced
356
- */
357
- function compareVersions(ver1, operator, ver2) {
358
- if (!SUPPORTED_OPERATORS.includes(operator)) {
359
- throw new Error(
360
- `The '${operator}' comparison operator is not supported. ` +
361
- `Only '${JSON.stringify(SUPPORTED_OPERATORS)}' operators are supported`
362
- );
363
- }
364
-
365
- const semverOperator = ['==', '!='].includes(operator) ? '=' : operator;
366
- const result = semver.satisfies(coerceVersion(ver1), `${semverOperator}${coerceVersion(ver2)}`);
367
- return operator === '!=' ? !result : result;
368
- }
369
-
370
- /**
371
- * Add appropriate quotes to command arguments. See https://github.com/substack/node-shell-quote
372
- * for more details
373
- *
374
- * @param {string|string[]} args - The arguments that will be parsed
375
- * @returns {string} - The arguments, quoted
376
- */
377
- function quote(args) {
378
- return shellQuote(_.castArray(args));
379
- }
380
-
381
- /**
382
- * @typedef PluralizeOptions
383
- * @property {boolean} [inclusive=false] - Whether to prefix with the number (e.g., 3 ducks)
384
- */
385
-
386
- /**
387
- * Get the form of a word appropriate to the count
388
- *
389
- * @param {string} word - The word to pluralize
390
- * @param {number} count - How many of the word exist
391
- * @param {PluralizeOptions|boolean} options - options for word pluralization,
392
- * or a boolean indicating the options.inclusive property
393
- * @returns {string} The word pluralized according to the number
394
- */
395
- function pluralize(word, count, options = {}) {
396
- let inclusive = false;
397
- if (_.isBoolean(options)) {
398
- // if passed in as a boolean
399
- inclusive = options;
400
- } else if (_.isBoolean(options?.inclusive)) {
401
- // if passed in as an options hash
402
- inclusive = options.inclusive;
403
- }
404
- return pluralizeLib(word, count, inclusive);
405
- }
406
-
407
- /**
408
- * @typedef EncodingOptions
409
- * @property {number} [maxSize=1073741824] The maximum size of
410
- * the resulting buffer in bytes. This is set to 1GB by default, because
411
- * Appium limits the maximum HTTP body size to 1GB. Also, the NodeJS heap
412
- * size must be enough to keep the resulting object (usually this size is
413
- * limited to 1.4 GB)
414
- */
415
-
416
- /**
417
- * Converts contents of a local file to an in-memory base-64 encoded buffer.
418
- * The operation is memory-usage friendly and should be used while encoding
419
- * large files to base64
420
- *
421
- * @param {string} srcPath The full path to the file being encoded
422
- * @param {EncodingOptions} opts
423
- * @returns {Promise<Buffer>} base64-encoded content of the source file as memory buffer
424
- * @throws {Error} if there was an error while reading the source file
425
- * or the source file is too
426
- */
427
- async function toInMemoryBase64(srcPath, opts = {}) {
428
- if (!(await fs.exists(srcPath)) || (await fs.stat(srcPath)).isDirectory()) {
429
- throw new Error(`No such file: ${srcPath}`);
430
- }
431
-
432
- const {maxSize = 1 * GiB} = opts;
433
- const resultBuffers = [];
434
- let resultBuffersSize = 0;
435
- const resultWriteStream = new stream.Writable({
436
- write: (buffer, encoding, next) => {
437
- resultBuffers.push(buffer);
438
- resultBuffersSize += buffer.length;
439
- if (maxSize > 0 && resultBuffersSize > maxSize) {
440
- resultWriteStream.emit(
441
- 'error',
442
- new Error(
443
- `The size of the resulting ` +
444
- `buffer must not be greater than ${toReadableSizeString(maxSize)}`
445
- )
446
- );
447
- }
448
- next();
449
- },
450
- });
451
-
452
- const readerStream = fs.createReadStream(srcPath);
453
- const base64EncoderStream = new Base64Encode();
454
- const resultWriteStreamPromise = new B((resolve, reject) => {
455
- resultWriteStream.once('error', (e) => {
456
- readerStream.unpipe(base64EncoderStream);
457
- base64EncoderStream.unpipe(resultWriteStream);
458
- readerStream.destroy();
459
- reject(e);
460
- });
461
- resultWriteStream.once('finish', resolve);
462
- });
463
- const readStreamPromise = new B((resolve, reject) => {
464
- readerStream.once('close', resolve);
465
- readerStream.once('error', (e) =>
466
- reject(new Error(`Failed to read '${srcPath}': ${e.message}`))
467
- );
468
- });
469
- readerStream.pipe(base64EncoderStream);
470
- base64EncoderStream.pipe(resultWriteStream);
471
-
472
- await B.all([readStreamPromise, resultWriteStreamPromise]);
473
- return Buffer.concat(resultBuffers);
474
- }
475
-
476
- /**
477
- * @typedef LockFileOptions
478
- * @property {number} [timeout=120] The max time in seconds to wait for the lock
479
- * @property {boolean} [tryRecovery=false] Whether to try lock recovery if
480
- * the first attempt to acquire it timed out.
481
- */
482
-
483
- /**
484
- * Create an async function which, when called, will not proceed until a certain file is no
485
- * longer present on the system. This allows for preventing concurrent behavior across processes
486
- * using a known lockfile path.
487
- *
488
- * @template T
489
- * @param {string} lockFile The full path to the file used for the lock
490
- * @param {LockFileOptions} opts
491
- * @returns async function that takes another async function defining the locked
492
- * behavior
493
- */
494
- function getLockFileGuard(lockFile, opts = {}) {
495
- const {timeout = 120, tryRecovery = false} = opts;
496
-
497
- const lock = /** @type {(lockfile: string, opts: import('lockfile').Options)=>B<void>} */ (
498
- B.promisify(_lockfile.lock)
499
- );
500
- const check = B.promisify(_lockfile.check);
501
- const unlock = B.promisify(_lockfile.unlock);
502
-
503
- /**
504
- * @param {(...args: any[]) => T} behavior
505
- * @returns {Promise<T>}
506
- */
507
- const guard = async (behavior) => {
508
- let triedRecovery = false;
509
- do {
510
- try {
511
- // if the lockfile doesn't exist, lock it synchronously to make sure no other call
512
- // on the same spin of the event loop can also initiate a lock. If the lockfile does exist
513
- // then just use the regular async 'lock' method which will wait on the lock.
514
- if (_lockfile.checkSync(lockFile)) {
515
- await lock(lockFile, {wait: timeout * 1000});
516
- } else {
517
- _lockfile.lockSync(lockFile);
518
- }
519
- break;
520
- } catch (e) {
521
- if (_.includes(e.message, 'EEXIST') && tryRecovery && !triedRecovery) {
522
- // There could be cases where a process has been forcefully terminated
523
- // without a chance to clean up pending locks: https://github.com/npm/lockfile/issues/26
524
- _lockfile.unlockSync(lockFile);
525
- triedRecovery = true;
526
- continue;
527
- }
528
- throw new Error(
529
- `Could not acquire lock on '${lockFile}' after ${timeout}s. ` +
530
- `Original error: ${e.message}`
531
- );
532
- }
533
- // eslint-disable-next-line no-constant-condition
534
- } while (true);
535
- try {
536
- return await behavior();
537
- } finally {
538
- // whether the behavior succeeded or not, get rid of the lock
539
- await unlock(lockFile);
540
- }
541
- };
542
-
543
- guard.check = async () => await check(lockFile);
544
-
545
- return guard;
546
- }
547
-
548
- export {
549
- hasValue,
550
- escapeSpace,
551
- escapeSpecialChars,
552
- localIp,
553
- cancellableDelay,
554
- multiResolve,
555
- safeJsonParse,
556
- wrapElement,
557
- unwrapElement,
558
- filterObject,
559
- toReadableSizeString,
560
- isSubPath,
561
- W3C_WEB_ELEMENT_IDENTIFIER,
562
- isSameDestination,
563
- compareVersions,
564
- coerceVersion,
565
- quote,
566
- jsonStringify,
567
- pluralize,
568
- GiB,
569
- MiB,
570
- KiB,
571
- toInMemoryBase64,
572
- uuidV1,
573
- uuidV3,
574
- uuidV4,
575
- uuidV5,
576
- shellParse,
577
- getLockFileGuard,
578
- };
579
-
580
- /**
581
- * A `string` which is never `''`.
582
- *
583
- * @template {string} T
584
- * @typedef {T extends '' ? never : T} NonEmptyString
585
- */