@appium/support 7.1.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/build/lib/console.d.ts +2 -2
  2. package/build/lib/console.d.ts.map +1 -1
  3. package/build/lib/console.js +4 -5
  4. package/build/lib/console.js.map +1 -1
  5. package/build/lib/doctor.d.ts +6 -6
  6. package/build/lib/doctor.d.ts.map +1 -1
  7. package/build/lib/doctor.js +7 -7
  8. package/build/lib/doctor.js.map +1 -1
  9. package/build/lib/env.d.ts +12 -5
  10. package/build/lib/env.d.ts.map +1 -1
  11. package/build/lib/env.js +5 -5
  12. package/build/lib/env.js.map +1 -1
  13. package/build/lib/fs.d.ts.map +1 -1
  14. package/build/lib/fs.js +11 -14
  15. package/build/lib/fs.js.map +1 -1
  16. package/build/lib/image-util.d.ts.map +1 -1
  17. package/build/lib/image-util.js +1 -1
  18. package/build/lib/image-util.js.map +1 -1
  19. package/build/lib/index.d.ts +1 -1
  20. package/build/lib/index.d.ts.map +1 -1
  21. package/build/lib/logging.d.ts.map +1 -1
  22. package/build/lib/logging.js +5 -8
  23. package/build/lib/logging.js.map +1 -1
  24. package/build/lib/mjpeg.d.ts.map +1 -1
  25. package/build/lib/mjpeg.js +7 -7
  26. package/build/lib/mjpeg.js.map +1 -1
  27. package/build/lib/net.d.ts.map +1 -1
  28. package/build/lib/net.js +21 -14
  29. package/build/lib/net.js.map +1 -1
  30. package/build/lib/node.d.ts.map +1 -1
  31. package/build/lib/node.js +7 -8
  32. package/build/lib/node.js.map +1 -1
  33. package/build/lib/npm.d.ts.map +1 -1
  34. package/build/lib/npm.js +3 -3
  35. package/build/lib/npm.js.map +1 -1
  36. package/build/lib/plist.js +11 -11
  37. package/build/lib/plist.js.map +1 -1
  38. package/build/lib/process.d.ts.map +1 -1
  39. package/build/lib/process.js +2 -2
  40. package/build/lib/process.js.map +1 -1
  41. package/build/lib/system.d.ts.map +1 -1
  42. package/build/lib/system.js +2 -3
  43. package/build/lib/system.js.map +1 -1
  44. package/build/lib/tempdir.d.ts +3 -2
  45. package/build/lib/tempdir.d.ts.map +1 -1
  46. package/build/lib/tempdir.js +2 -2
  47. package/build/lib/tempdir.js.map +1 -1
  48. package/build/lib/timing.d.ts.map +1 -1
  49. package/build/lib/timing.js +3 -7
  50. package/build/lib/timing.js.map +1 -1
  51. package/build/lib/util.d.ts +103 -24
  52. package/build/lib/util.d.ts.map +1 -1
  53. package/build/lib/util.js +158 -22
  54. package/build/lib/util.js.map +1 -1
  55. package/build/lib/zip.d.ts +42 -42
  56. package/build/lib/zip.d.ts.map +1 -1
  57. package/build/lib/zip.js +142 -142
  58. package/build/lib/zip.js.map +1 -1
  59. package/lib/console.ts +8 -9
  60. package/lib/doctor.ts +6 -6
  61. package/lib/env.ts +5 -5
  62. package/lib/fs.ts +14 -14
  63. package/lib/image-util.ts +2 -1
  64. package/lib/index.ts +7 -1
  65. package/lib/logging.ts +5 -5
  66. package/lib/mjpeg.ts +9 -7
  67. package/lib/net.ts +25 -19
  68. package/lib/node.ts +7 -8
  69. package/lib/npm.ts +5 -3
  70. package/lib/plist.ts +11 -11
  71. package/lib/process.ts +8 -2
  72. package/lib/system.ts +2 -3
  73. package/lib/tempdir.ts +2 -2
  74. package/lib/timing.ts +3 -5
  75. package/lib/util.ts +197 -44
  76. package/lib/zip.ts +223 -221
  77. package/package.json +11 -12
  78. package/tsconfig.json +1 -0
package/lib/util.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import B from 'bluebird';
2
- import _ from 'lodash';
2
+ import {randomUUID} from 'node:crypto';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import stream from 'node:stream';
6
- import {promisify} from 'node:util';
6
+ import {isDeepStrictEqual, promisify} from 'node:util';
7
7
  import {asyncmap} from 'asyncbox';
8
8
  import {fs} from './fs';
9
9
  import * as semver from 'semver';
@@ -11,7 +11,7 @@ import {quote as shellQuote, parse as shellParse} from 'shell-quote';
11
11
  export {shellParse};
12
12
  import pluralizeLib from 'pluralize';
13
13
  import {Base64Encode} from 'base64-stream';
14
- export {v1 as uuidV1, v3 as uuidV3, v4 as uuidV4, v5 as uuidV5} from 'uuid';
14
+ import {v1 as uuidV1Lib, v3 as uuidV3Lib, v5 as uuidV5Lib} from 'uuid';
15
15
  import * as _lockfile from 'lockfile';
16
16
  import type {Element} from '@appium/types';
17
17
 
@@ -28,6 +28,36 @@ export const GiB = MiB * 1024;
28
28
  /** A string which is never `''`. */
29
29
  export type NonEmptyString<T extends string = string> = T extends '' ? never : T;
30
30
 
31
+ /**
32
+ * @deprecated This helper is slated for removal. Please migrate callers away from UUID v1.
33
+ */
34
+ export function uuidV1(...args: Parameters<typeof uuidV1Lib>): ReturnType<typeof uuidV1Lib> {
35
+ return uuidV1Lib(...args);
36
+ }
37
+
38
+ /**
39
+ * @deprecated This helper is slated for removal. Please migrate callers away from UUID v3.
40
+ */
41
+ export function uuidV3(...args: Parameters<typeof uuidV3Lib>): ReturnType<typeof uuidV3Lib> {
42
+ return uuidV3Lib(...args);
43
+ }
44
+
45
+ /**
46
+ * Generates a v4 UUID using Node.js crypto.
47
+ *
48
+ * @returns A UUID v4 string
49
+ */
50
+ export function uuidV4(): string {
51
+ return randomUUID();
52
+ }
53
+
54
+ /**
55
+ * @deprecated This helper is slated for removal. Please migrate callers away from UUID v5.
56
+ */
57
+ export function uuidV5(...args: Parameters<typeof uuidV5Lib>): ReturnType<typeof uuidV5Lib> {
58
+ return uuidV5Lib(...args);
59
+ }
60
+
31
61
  /**
32
62
  * Type guard: returns true if the value is a non-empty string.
33
63
  *
@@ -35,7 +65,7 @@ export type NonEmptyString<T extends string = string> = T extends '' ? never : T
35
65
  * @returns `true` if `val` is a string with at least one character
36
66
  */
37
67
  export function hasContent(val: unknown): val is NonEmptyString {
38
- return _.isString(val) && val !== '';
68
+ return typeof val === 'string' && val !== '';
39
69
  }
40
70
 
41
71
  /**
@@ -45,10 +75,124 @@ export function hasContent(val: unknown): val is NonEmptyString {
45
75
  * @returns `true` if `val` is non-null and non-undefined (and not NaN for numbers)
46
76
  */
47
77
  export function hasValue<T>(val: T): val is NonNullable<T> {
48
- if (_.isNumber(val)) {
49
- return !_.isNaN(val);
78
+ if (typeof val === 'number') {
79
+ return !Number.isNaN(val);
50
80
  }
51
- return !_.isUndefined(val) && !_.isNull(val);
81
+ return val !== undefined && val !== null;
82
+ }
83
+
84
+ /**
85
+ * Creates a memoized version of a function.
86
+ *
87
+ * @param fn - Function to memoize
88
+ * @param resolver - Optional cache key resolver. If omitted, the first argument is used as the cache key.
89
+ * @returns Memoized function with a mutable `.cache` map (compatible with lodash-style cache resets in tests).
90
+ */
91
+ export function memoize<Fn extends (...args: any[]) => any>(
92
+ fn: Fn,
93
+ resolver?: (...args: Parameters<Fn>) => unknown
94
+ ): Fn & {cache: Map<unknown, ReturnType<Fn>>} {
95
+ const memoizedFn = (function (this: unknown, ...args: Parameters<Fn>) {
96
+ const key = resolver ? resolver.apply(this, args) : args[0];
97
+ if (memoizedFn.cache.has(key)) {
98
+ return memoizedFn.cache.get(key) as ReturnType<Fn>;
99
+ }
100
+ const result = fn.apply(this, args);
101
+ memoizedFn.cache.set(key, result);
102
+ return result;
103
+ }) as unknown as Fn & {cache: Map<unknown, ReturnType<Fn>>};
104
+ memoizedFn.cache = new Map<unknown, ReturnType<Fn>>();
105
+ return memoizedFn;
106
+ }
107
+
108
+ /**
109
+ * Returns true if the value is a plain object (Object prototype or null prototype).
110
+ *
111
+ * @param value - Value to check
112
+ * @returns `true` if the value is a plain object
113
+ */
114
+ export function isPlainObject(value: unknown): value is Record<string, unknown> {
115
+ if (value === null || typeof value !== 'object') {
116
+ return false;
117
+ }
118
+ const prototype = Object.getPrototypeOf(value);
119
+ return prototype === null || prototype === Object.prototype;
120
+ }
121
+
122
+ /**
123
+ * Returns true when the value has no elements/properties.
124
+ *
125
+ * @param value - Value to check
126
+ * @returns `true` if the value is empty
127
+ */
128
+ export function isEmpty(value: unknown): boolean {
129
+ if (value == null) {
130
+ return true;
131
+ }
132
+ if (typeof value === 'string' || Array.isArray(value) || Buffer.isBuffer(value)) {
133
+ return value.length === 0;
134
+ }
135
+ if (value instanceof Map || value instanceof Set) {
136
+ return value.size === 0;
137
+ }
138
+ if (typeof value === 'object' || typeof value === 'function') {
139
+ return Object.keys(value).length === 0;
140
+ }
141
+ return true;
142
+ }
143
+
144
+ /**
145
+ * Performs a deep equality check between two values.
146
+ *
147
+ * @param left - First value
148
+ * @param right - Second value
149
+ * @returns `true` when values are deeply equal
150
+ */
151
+ export function isEqual(left: unknown, right: unknown): boolean {
152
+ return isDeepStrictEqual(left, right);
153
+ }
154
+
155
+ /**
156
+ * Escapes RegExp special characters in a string.
157
+ *
158
+ * @param value - Input string
159
+ * @returns Escaped string safe for RegExp source
160
+ */
161
+ export function escapeRegExp(value: string): string {
162
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
163
+ }
164
+
165
+ /**
166
+ * Returns a duplicate-free copy of the input array.
167
+ *
168
+ * @param values - Input array
169
+ * @returns New array with unique values preserving input order
170
+ */
171
+ export function uniq<T>(values: readonly T[]): T[] {
172
+ return [...new Set(values)];
173
+ }
174
+
175
+ /**
176
+ * Truncates a string to a maximum length.
177
+ *
178
+ * @param value - Input string
179
+ * @param options - Truncation options or max length
180
+ * @returns Truncated string
181
+ */
182
+ export function truncateString(value: string, options: TruncateStringOptions | number = {}): string {
183
+ const normalizedOptions = typeof options === 'number' ? {length: options} : options;
184
+ const {length, omission = '…'} = normalizedOptions;
185
+ const stringValue =
186
+ value == null ? '' : typeof value === 'number' && Object.is(value, -0) ? '-0' : String(value);
187
+ const maxLength = length ?? 30;
188
+ if (maxLength <= 0) {
189
+ return omission;
190
+ }
191
+ if (stringValue.length <= maxLength) {
192
+ return stringValue;
193
+ }
194
+ const contentLength = maxLength - omission.length;
195
+ return contentLength > 0 ? `${stringValue.slice(0, contentLength)}${omission}` : omission;
52
196
  }
53
197
 
54
198
  /**
@@ -177,7 +321,7 @@ export function jsonStringify(
177
321
  replacer: ((key: string, value: unknown) => unknown) | null = null,
178
322
  space: number | string = 2
179
323
  ): string {
180
- const replacerFunc = _.isFunction(replacer) ? replacer : (_k: string, v: unknown) => v;
324
+ const replacerFunc = typeof replacer === 'function' ? replacer : (_k: string, v: unknown) => v;
181
325
 
182
326
  const bufferToJSON = Buffer.prototype.toJSON;
183
327
  delete (Buffer.prototype as Record<string, unknown>).toJSON;
@@ -204,7 +348,7 @@ export function jsonStringify(
204
348
  export function unwrapElement(el: Element | string): string {
205
349
  const elObj = el as unknown as Record<string, string>;
206
350
  for (const propName of [W3C_WEB_ELEMENT_IDENTIFIER, 'ELEMENT']) {
207
- if (_.has(elObj, propName)) {
351
+ if (Object.hasOwn(elObj, propName)) {
208
352
  return elObj[propName];
209
353
  }
210
354
  }
@@ -238,11 +382,11 @@ export function filterObject<T extends Record<string, unknown>>(
238
382
  obj: T,
239
383
  predicate?: ((value: unknown, obj: T) => boolean) | unknown
240
384
  ): Partial<T> {
241
- const newObj = _.clone(obj) as Record<string, unknown>;
385
+ const newObj = {...obj} as Record<string, unknown>;
242
386
  let pred: (v: unknown, o: T) => boolean;
243
- if (_.isUndefined(predicate)) {
244
- pred = (v) => !_.isUndefined(v);
245
- } else if (!_.isFunction(predicate)) {
387
+ if (predicate === undefined) {
388
+ pred = (v) => v !== undefined;
389
+ } else if (typeof predicate !== 'function') {
246
390
  const valuePredicate = predicate;
247
391
  pred = (v) => v === valuePredicate;
248
392
  } else {
@@ -354,6 +498,40 @@ export function coerceVersion(ver: string, strict = true): string | null {
354
498
 
355
499
  const SUPPORTED_OPERATORS = ['==', '!=', '>', '<', '>=', '<=', '='];
356
500
 
501
+ /** Options for pluralize(). */
502
+ export interface PluralizeOptions {
503
+ /** If true, prefix the result with the count (e.g. "3 ducks"). */
504
+ inclusive?: boolean;
505
+ }
506
+
507
+ /** Options for toInMemoryBase64(). */
508
+ export interface EncodingOptions {
509
+ /** Maximum size of the resulting buffer in bytes. Default 1GB. */
510
+ maxSize?: number;
511
+ }
512
+
513
+ /** Options for getLockFileGuard(). */
514
+ export interface LockFileOptions {
515
+ /** Max time in seconds to wait for the lock. Default 120. */
516
+ timeout?: number;
517
+ /** If true, attempt to unlock and retry once if the first acquisition times out (e.g. stale lock). */
518
+ tryRecovery?: boolean;
519
+ }
520
+
521
+ /** Options for truncateString(). */
522
+ export interface TruncateStringOptions {
523
+ /** Maximum length of the resulting string. Default 30. */
524
+ length?: number;
525
+ /** Suffix appended to truncated strings. Default "…". */
526
+ omission?: string;
527
+ }
528
+
529
+ /** Guard function that runs the given behavior under the lock. */
530
+ type LockFileGuardFn<T> = (behavior: () => Promise<T> | T) => Promise<T>;
531
+
532
+ /** Return type of getLockFileGuard: guard function with a .check() method. */
533
+ type LockFileGuard<T> = LockFileGuardFn<T> & {check: () => Promise<boolean>};
534
+
357
535
  /**
358
536
  * Compares two version strings using the given operator.
359
537
  *
@@ -389,13 +567,7 @@ export function compareVersions(
389
567
  * @returns Quoted string suitable for shell parsing
390
568
  */
391
569
  export function quote(args: string | string[]): string {
392
- return shellQuote(_.castArray(args));
393
- }
394
-
395
- /** Options for pluralize(). */
396
- export interface PluralizeOptions {
397
- /** If true, prefix the result with the count (e.g. "3 ducks"). */
398
- inclusive?: boolean;
570
+ return shellQuote(Array.isArray(args) ? args : [args]);
399
571
  }
400
572
 
401
573
  /**
@@ -412,20 +584,14 @@ export function pluralize(
412
584
  options: PluralizeOptions | boolean = {}
413
585
  ): string {
414
586
  let inclusive = false;
415
- if (_.isBoolean(options)) {
587
+ if (typeof options === 'boolean') {
416
588
  inclusive = options;
417
- } else if (_.isBoolean(options?.inclusive)) {
589
+ } else if (typeof options?.inclusive === 'boolean') {
418
590
  inclusive = options.inclusive;
419
591
  }
420
592
  return pluralizeLib(word, count, inclusive);
421
593
  }
422
594
 
423
- /** Options for toInMemoryBase64(). */
424
- export interface EncodingOptions {
425
- /** Maximum size of the resulting buffer in bytes. Default 1GB. */
426
- maxSize?: number;
427
- }
428
-
429
595
  /**
430
596
  * Reads a file and returns its contents as a base64-encoded buffer.
431
597
  *
@@ -487,20 +653,6 @@ export async function toInMemoryBase64(
487
653
  return Buffer.concat(resultBuffers);
488
654
  }
489
655
 
490
- /** Options for getLockFileGuard(). */
491
- export interface LockFileOptions {
492
- /** Max time in seconds to wait for the lock. Default 120. */
493
- timeout?: number;
494
- /** If true, attempt to unlock and retry once if the first acquisition times out (e.g. stale lock). */
495
- tryRecovery?: boolean;
496
- }
497
-
498
- /** Guard function that runs the given behavior under the lock. */
499
- type LockFileGuardFn<T> = (behavior: () => Promise<T> | T) => Promise<T>;
500
-
501
- /** Return type of getLockFileGuard: guard function with a .check() method. */
502
- type LockFileGuard<T> = LockFileGuardFn<T> & {check: () => Promise<boolean>};
503
-
504
656
  /**
505
657
  * Creates a guard that serializes access to a critical section using a lock file.
506
658
  * The returned function acquires the lock, runs the given behavior, then releases the lock.
@@ -537,13 +689,14 @@ export function getLockFileGuard<T>(
537
689
  acquired = true;
538
690
  } catch (e) {
539
691
  const err = e as Error;
540
- if (_.includes(err.message, 'EEXIST') && tryRecovery && !triedRecovery) {
692
+ if (err.message?.includes('EEXIST') && tryRecovery && !triedRecovery) {
541
693
  _lockfile.unlockSync(lockFile);
542
694
  triedRecovery = true;
543
695
  } else {
544
696
  throw new Error(
545
697
  `Could not acquire lock on '${lockFile}' after ${timeout}s. ` +
546
- `Original error: ${err.message}`
698
+ `Original error: ${err.message}`,
699
+ {cause: e}
547
700
  );
548
701
  }
549
702
  }