@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/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,178 +45,179 @@ 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;
61
61
  const bluebird_1 = __importDefault(require("bluebird"));
62
62
  const lodash_1 = __importDefault(require("lodash"));
63
- const os_1 = __importDefault(require("os"));
64
- const path_1 = __importDefault(require("path"));
63
+ const node_os_1 = __importDefault(require("node:os"));
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 stream_1 = __importDefault(require("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(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
- // eslint-disable-next-line import/no-named-as-default-member
182
183
  reject(new bluebird_1.default.CancellationError());
183
184
  };
184
185
  return delay;
185
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
+ */
186
194
  function multiResolve(roots, ...args) {
187
- return roots.map((root) => path_1.default.resolve(root, ...args));
195
+ return roots.map((root) => node_path_1.default.resolve(root, ...args));
188
196
  }
189
197
  /**
190
- * 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.
191
199
  *
192
- * @param {any} obj
193
- * @returns {any}
200
+ * @param obj - String (to parse) or other value (returned unchanged)
201
+ * @returns Parsed object or original value
194
202
  */
195
203
  function safeJsonParse(obj) {
196
204
  try {
197
205
  return JSON.parse(obj);
198
206
  }
199
207
  catch {
200
- // ignore: this is not json parsable
201
208
  return obj;
202
209
  }
203
210
  }
204
211
  /**
205
- * Stringifies the object passed in, converting Buffers into Strings for better
206
- * display. This mimics JSON.stringify (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)
207
- * except the `replacer` argument can only be a function.
212
+ * Stringifies an object to JSON, converting Buffers to strings for readable output.
208
213
  *
209
- * @param {any} obj - the object to be serialized
210
- * @param {((key:any, value:any) => any)?} replacer - function to transform the properties added to the
211
- * serialized object
212
- * @param {number|string|undefined} space - used to insert white space into the output JSON
213
- * string for readability purposes. Defaults to 2
214
- * @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
215
218
  */
216
219
  function jsonStringify(obj, replacer = null, space = 2) {
217
- // if no replacer is passed, or it is not a function, just use a pass-through
218
- const replacerFunc = lodash_1.default.isFunction(replacer) ? replacer : (k, v) => v;
219
- // Buffers cannot be serialized in a readable way
220
+ const replacerFunc = lodash_1.default.isFunction(replacer) ? replacer : (_k, v) => v;
220
221
  const bufferToJSON = Buffer.prototype.toJSON;
221
222
  delete Buffer.prototype.toJSON;
222
223
  try {
@@ -226,99 +227,100 @@ function jsonStringify(obj, replacer = null, space = 2) {
226
227
  }, space);
227
228
  }
228
229
  finally {
229
- // restore the function, so as to not break further serialization
230
230
  Buffer.prototype.toJSON = bufferToJSON;
231
231
  }
232
232
  }
233
233
  /**
234
- * Removes the wrapper from element, if it exists.
235
- * { ELEMENT: 4 } becomes 4
236
- * { element-6066-11e4-a52e-4f735466cecf: 5 } becomes 5
237
- * @param {import('@appium/types').Element|string} el
238
- * @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
239
238
  */
240
239
  function unwrapElement(el) {
241
- for (const propName of [W3C_WEB_ELEMENT_IDENTIFIER, 'ELEMENT']) {
242
- if (lodash_1.default.has(el, propName)) {
243
- 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];
244
244
  }
245
245
  }
246
- return /** @type {string} */ (el);
246
+ return el;
247
247
  }
248
248
  /**
249
+ * Wraps an element ID string in an element object compatible with both W3C and JSONWP.
249
250
  *
250
- * @param {string} elementId
251
- * @returns {import('@appium/types').Element}
251
+ * @param elementId - The element ID to wrap
252
+ * @returns Element object with both ELEMENT and W3C identifier keys
252
253
  */
253
254
  function wrapElement(elementId) {
254
255
  return {
255
256
  ELEMENT: elementId,
256
- [W3C_WEB_ELEMENT_IDENTIFIER]: elementId,
257
+ [exports.W3C_WEB_ELEMENT_IDENTIFIER]: elementId,
257
258
  };
258
259
  }
259
- /*
260
- * Returns object consisting of all properties in the original element
261
- * which were truthy given the predicate.
262
- * If the predicate is
263
- * * missing - it will remove all properties whose values are `undefined`
264
- * * a scalar - it will test all properties' values against that value
265
- * * 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
266
269
  */
267
270
  function filterObject(obj, predicate) {
268
- let newObj = lodash_1.default.clone(obj);
271
+ const newObj = lodash_1.default.clone(obj);
272
+ let pred;
269
273
  if (lodash_1.default.isUndefined(predicate)) {
270
- // remove any element from the object whose value is undefined
271
- predicate = (v) => !lodash_1.default.isUndefined(v);
274
+ pred = (v) => !lodash_1.default.isUndefined(v);
272
275
  }
273
276
  else if (!lodash_1.default.isFunction(predicate)) {
274
- // make predicate into a function
275
277
  const valuePredicate = predicate;
276
- predicate = (v) => v === valuePredicate;
278
+ pred = (v) => v === valuePredicate;
279
+ }
280
+ else {
281
+ pred = predicate;
277
282
  }
278
283
  for (const key of Object.keys(obj)) {
279
- if (!predicate(obj[key], obj)) {
284
+ if (!pred(obj[key], obj)) {
280
285
  delete newObj[key];
281
286
  }
282
287
  }
283
288
  return newObj;
284
289
  }
285
290
  /**
286
- * 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").
287
292
  *
288
- * @param {number|string} bytes - The actual number of bytes.
289
- * @returns {string} The actual string representation, for example
290
- * '1.00 KB' for '1024 B'
291
- * @throws {Error} If bytes count cannot be converted to an integer or
292
- * 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
293
296
  */
294
297
  function toReadableSizeString(bytes) {
295
298
  const intBytes = parseInt(String(bytes), 10);
296
299
  if (isNaN(intBytes) || intBytes < 0) {
297
300
  throw new Error(`Cannot convert '${bytes}' to a readable size format`);
298
301
  }
299
- if (intBytes >= GiB) {
300
- return `${(intBytes / (GiB * 1.0)).toFixed(2)} GB`;
302
+ if (intBytes >= exports.GiB) {
303
+ return `${(intBytes / (exports.GiB * 1.0)).toFixed(2)} GB`;
301
304
  }
302
- else if (intBytes >= MiB) {
303
- return `${(intBytes / (MiB * 1.0)).toFixed(2)} MB`;
305
+ else if (intBytes >= exports.MiB) {
306
+ return `${(intBytes / (exports.MiB * 1.0)).toFixed(2)} MB`;
304
307
  }
305
- else if (intBytes >= KiB) {
306
- return `${(intBytes / (KiB * 1.0)).toFixed(2)} KB`;
308
+ else if (intBytes >= exports.KiB) {
309
+ return `${(intBytes / (exports.KiB * 1.0)).toFixed(2)} KB`;
307
310
  }
308
311
  return `${intBytes} B`;
309
312
  }
310
313
  /**
311
- * Checks whether the given path is a subpath of the
312
- * particular root folder. Both paths can include .. and . specifiers
314
+ * Checks whether the given path is a subpath of the given root folder.
313
315
  *
314
- * @param {string} originalPath The absolute file/folder path
315
- * @param {string} root The absolute root folder path
316
- * @param {?boolean} forcePosix Set it to true if paths must be interpreted in POSIX format
317
- * @returns {boolean} true if the given original path is the subpath of the root folder
318
- * @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
319
321
  */
320
322
  function isSubPath(originalPath, root, forcePosix = null) {
321
- const pathObj = forcePosix ? path_1.default.posix : path_1.default;
323
+ const pathObj = forcePosix ? node_path_1.default.posix : node_path_1.default;
322
324
  for (const p of [originalPath, root]) {
323
325
  if (!pathObj.isAbsolute(p)) {
324
326
  throw new Error(`'${p}' is expected to be an absolute path`);
@@ -329,41 +331,27 @@ function isSubPath(originalPath, root, forcePosix = null) {
329
331
  return normalizedPath.startsWith(normalizedRoot);
330
332
  }
331
333
  /**
332
- * Checks whether the given paths are pointing to the same file system
333
- * destination.
334
+ * Checks whether the given paths refer to the same file system entity (same inode).
335
+ * All paths must exist.
334
336
  *
335
- * @param {string} path1 - Absolute or relative path to a file/folder
336
- * @param {string} path2 - Absolute or relative path to a file/folder
337
- * @param {...string} pathN - Zero or more absolute or relative paths to files/folders
338
- * @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
339
341
  */
340
342
  async function isSameDestination(path1, path2, ...pathN) {
341
343
  const allPaths = [path1, path2, ...pathN];
342
- 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)) {
343
345
  return false;
344
346
  }
345
347
  const areAllItemsEqual = (arr) => !!arr.reduce((a, b) => (a === b ? a : NaN));
346
348
  if (areAllItemsEqual(allPaths)) {
347
349
  return true;
348
350
  }
349
- let mapCb = async (x) => (await fs_1.fs.stat(x, {
350
- bigint: true,
351
- })).ino;
352
- 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));
353
353
  }
354
- /**
355
- * Coerces the given number/string to a valid version string
356
- *
357
- * @template {boolean} [Strict=true]
358
- * @param {string} ver - Version string to coerce
359
- * @param {Strict} [strict] - If `true` then an exception will be thrown
360
- * if `ver` cannot be coerced
361
- * @returns {Strict extends true ? string : string|null} Coerced version number or null if the string cannot be
362
- * coerced and strict mode is disabled
363
- * @throws {Error} if strict mode is enabled and `ver` cannot be coerced
364
- */
365
- function coerceVersion(ver, strict = /** @type {Strict} */ (true)) {
366
- // First try to parse as-is, then coerce if needed
354
+ function coerceVersion(ver, strict = true) {
367
355
  let result = semver.valid(`${ver}`);
368
356
  if (!result) {
369
357
  result = semver.valid(semver.coerce(`${ver}`));
@@ -371,21 +359,17 @@ function coerceVersion(ver, strict = /** @type {Strict} */ (true)) {
371
359
  if (strict && !result) {
372
360
  throw new Error(`'${ver}' cannot be coerced to a valid version number`);
373
361
  }
374
- return /** @type {Strict extends true ? string : string?} */ (result);
362
+ return result;
375
363
  }
376
364
  const SUPPORTED_OPERATORS = ['==', '!=', '>', '<', '>=', '<=', '='];
377
365
  /**
378
- * Compares two version strings
366
+ * Compares two version strings using the given operator.
379
367
  *
380
- * @param {string} ver1 - The first version number to compare. Should be a valid
381
- * version number supported by semver parser.
382
- * @param {string} ver2 - The second version number to compare. Should be a valid
383
- * version number supported by semver parser.
384
- * @param {string} operator - One of supported version number operators:
385
- * ==, !=, >, <, <=, >=, =
386
- * @returns {boolean} true or false depending on the actual comparison result
387
- * @throws {Error} if an unsupported operator is supplied or any of the supplied
388
- * 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
389
373
  */
390
374
  function compareVersions(ver1, operator, ver2) {
391
375
  if (!SUPPORTED_OPERATORS.includes(operator)) {
@@ -393,170 +377,131 @@ function compareVersions(ver1, operator, ver2) {
393
377
  `Only '${JSON.stringify(SUPPORTED_OPERATORS)}' operators are supported`);
394
378
  }
395
379
  const semverOperator = ['==', '!='].includes(operator) ? '=' : operator;
396
- 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}`);
397
383
  return operator === '!=' ? !result : result;
398
384
  }
399
385
  /**
400
- * Add appropriate quotes to command arguments. See https://github.com/substack/node-shell-quote
401
- * for more details
386
+ * Quotes and escapes command-line arguments so they can be safely passed to a shell.
402
387
  *
403
- * @param {string|string[]} args - The arguments that will be parsed
404
- * @returns {string} - The arguments, quoted
388
+ * @param args - Single argument or array of arguments to quote
389
+ * @returns Quoted string suitable for shell parsing
405
390
  */
406
391
  function quote(args) {
407
392
  return (0, shell_quote_1.quote)(lodash_1.default.castArray(args));
408
393
  }
409
394
  /**
410
- * @typedef PluralizeOptions
411
- * @property {boolean} [inclusive=false] - Whether to prefix with the number (e.g., 3 ducks)
412
- */
413
- /**
414
- * 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").
415
396
  *
416
- * @param {string} word - The word to pluralize
417
- * @param {number} count - How many of the word exist
418
- * @param {PluralizeOptions|boolean} options - options for word pluralization,
419
- * or a boolean indicating the options.inclusive property
420
- * @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
421
401
  */
422
402
  function pluralize(word, count, options = {}) {
423
403
  let inclusive = false;
424
404
  if (lodash_1.default.isBoolean(options)) {
425
- // if passed in as a boolean
426
405
  inclusive = options;
427
406
  }
428
407
  else if (lodash_1.default.isBoolean(options?.inclusive)) {
429
- // if passed in as an options hash
430
408
  inclusive = options.inclusive;
431
409
  }
432
410
  return (0, pluralize_1.default)(word, count, inclusive);
433
411
  }
434
412
  /**
435
- * @typedef EncodingOptions
436
- * @property {number} [maxSize=1073741824] The maximum size of
437
- * the resulting buffer in bytes. This is set to 1GB by default, because
438
- * Appium limits the maximum HTTP body size to 1GB. Also, the NodeJS heap
439
- * size must be enough to keep the resulting object (usually this size is
440
- * limited to 1.4 GB)
441
- */
442
- /**
443
- * Converts contents of a local file to an in-memory base-64 encoded buffer.
444
- * The operation is memory-usage friendly and should be used while encoding
445
- * large files to base64
413
+ * Reads a file and returns its contents as a base64-encoded buffer.
446
414
  *
447
- * @param {string} srcPath The full path to the file being encoded
448
- * @param {EncodingOptions} opts
449
- * @returns {Promise<Buffer>} base64-encoded content of the source file as memory buffer
450
- * @throws {Error} if there was an error while reading the source file
451
- * 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
452
419
  */
453
420
  async function toInMemoryBase64(srcPath, opts = {}) {
454
421
  if (!(await fs_1.fs.exists(srcPath)) || (await fs_1.fs.stat(srcPath)).isDirectory()) {
455
422
  throw new Error(`No such file: ${srcPath}`);
456
423
  }
457
- const { maxSize = 1 * GiB } = opts;
424
+ const { maxSize = 1 * exports.GiB } = opts;
458
425
  const resultBuffers = [];
459
426
  let resultBuffersSize = 0;
460
- const resultWriteStream = new stream_1.default.Writable({
461
- write: (buffer, encoding, next) => {
427
+ const resultWriteStream = new node_stream_1.default.Writable({
428
+ write(buffer, _encoding, next) {
462
429
  resultBuffers.push(buffer);
463
430
  resultBuffersSize += buffer.length;
464
431
  if (maxSize > 0 && resultBuffersSize > maxSize) {
465
- resultWriteStream.emit('error', new Error(`The size of the resulting ` +
466
- `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)}`));
467
433
  }
468
434
  next();
469
435
  },
470
436
  });
471
437
  const readerStream = fs_1.fs.createReadStream(srcPath);
472
438
  const base64EncoderStream = new base64_stream_1.Base64Encode();
473
- const resultWriteStreamPromise = new bluebird_1.default((resolve, reject) => {
439
+ const encoderWritable = base64EncoderStream;
440
+ const encoderReadable = base64EncoderStream;
441
+ const resultWriteStreamPromise = new Promise((resolve, reject) => {
474
442
  resultWriteStream.once('error', (e) => {
475
- readerStream.unpipe(base64EncoderStream);
476
- base64EncoderStream.unpipe(resultWriteStream);
443
+ readerStream.unpipe(encoderWritable);
444
+ encoderReadable.unpipe(resultWriteStream);
477
445
  readerStream.destroy();
478
446
  reject(e);
479
447
  });
480
- resultWriteStream.once('finish', resolve);
448
+ resultWriteStream.once('finish', () => resolve());
481
449
  });
482
- const readStreamPromise = new bluebird_1.default((resolve, reject) => {
483
- readerStream.once('close', resolve);
450
+ const readStreamPromise = new Promise((resolve, reject) => {
451
+ readerStream.once('close', () => resolve());
484
452
  readerStream.once('error', (e) => reject(new Error(`Failed to read '${srcPath}': ${e.message}`)));
485
453
  });
486
- readerStream.pipe(base64EncoderStream);
487
- base64EncoderStream.pipe(resultWriteStream);
488
- await bluebird_1.default.all([readStreamPromise, resultWriteStreamPromise]);
454
+ readerStream.pipe(encoderWritable);
455
+ encoderReadable.pipe(resultWriteStream);
456
+ await Promise.all([readStreamPromise, resultWriteStreamPromise]);
489
457
  return Buffer.concat(resultBuffers);
490
458
  }
491
459
  /**
492
- * @typedef LockFileOptions
493
- * @property {number} [timeout=120] The max time in seconds to wait for the lock
494
- * @property {boolean} [tryRecovery=false] Whether to try lock recovery if
495
- * the first attempt to acquire it timed out.
496
- */
497
- /**
498
- * Create an async function which, when called, will not proceed until a certain file is no
499
- * longer present on the system. This allows for preventing concurrent behavior across processes
500
- * 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.
501
463
  *
502
- * @template T
503
- * @param {string} lockFile The full path to the file used for the lock
504
- * @param {LockFileOptions} opts
505
- * @returns async function that takes another async function defining the locked
506
- * 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
507
467
  */
508
468
  function getLockFileGuard(lockFile, opts = {}) {
509
469
  const { timeout = 120, tryRecovery = false } = opts;
510
- const lock = /** @type {(lockfile: string, opts: import('lockfile').Options)=>B<void>} */ (bluebird_1.default.promisify(_lockfile.lock));
511
- const check = bluebird_1.default.promisify(_lockfile.check);
512
- const unlock = bluebird_1.default.promisify(_lockfile.unlock);
513
- /**
514
- * @param {(...args: any[]) => T} behavior
515
- * @returns {Promise<T>}
516
- */
517
- 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) => {
518
474
  let triedRecovery = false;
519
- do {
475
+ let acquired = false;
476
+ while (!acquired) {
520
477
  try {
521
- // if the lockfile doesn't exist, lock it synchronously to make sure no other call
522
- // on the same spin of the event loop can also initiate a lock. If the lockfile does exist
523
- // then just use the regular async 'lock' method which will wait on the lock.
524
478
  if (_lockfile.checkSync(lockFile)) {
525
479
  await lock(lockFile, { wait: timeout * 1000 });
526
480
  }
527
481
  else {
528
482
  _lockfile.lockSync(lockFile);
529
483
  }
530
- break;
484
+ acquired = true;
531
485
  }
532
486
  catch (e) {
533
- if (lodash_1.default.includes(e.message, 'EEXIST') && tryRecovery && !triedRecovery) {
534
- // There could be cases where a process has been forcefully terminated
535
- // 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) {
536
489
  _lockfile.unlockSync(lockFile);
537
490
  triedRecovery = true;
538
- continue;
539
491
  }
540
- throw new Error(`Could not acquire lock on '${lockFile}' after ${timeout}s. ` +
541
- `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
+ }
542
496
  }
543
- // eslint-disable-next-line no-constant-condition
544
- } while (true);
497
+ }
545
498
  try {
546
499
  return await behavior();
547
500
  }
548
501
  finally {
549
- // whether the behavior succeeded or not, get rid of the lock
550
502
  await unlock(lockFile);
551
503
  }
552
- };
553
- guard.check = async () => await check(lockFile);
504
+ }, { check: () => checkLock(lockFile) });
554
505
  return guard;
555
506
  }
556
- /**
557
- * A `string` which is never `''`.
558
- *
559
- * @template {string} T
560
- * @typedef {T extends '' ? never : T} NonEmptyString
561
- */
562
507
  //# sourceMappingURL=util.js.map