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