@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.
- package/build/lib/console.d.ts +2 -2
- package/build/lib/console.d.ts.map +1 -1
- package/build/lib/console.js +4 -5
- package/build/lib/console.js.map +1 -1
- package/build/lib/doctor.d.ts +6 -6
- package/build/lib/doctor.d.ts.map +1 -1
- package/build/lib/doctor.js +7 -7
- package/build/lib/doctor.js.map +1 -1
- package/build/lib/env.d.ts +12 -5
- package/build/lib/env.d.ts.map +1 -1
- package/build/lib/env.js +5 -5
- package/build/lib/env.js.map +1 -1
- package/build/lib/fs.d.ts.map +1 -1
- package/build/lib/fs.js +11 -14
- package/build/lib/fs.js.map +1 -1
- package/build/lib/image-util.d.ts.map +1 -1
- package/build/lib/image-util.js +1 -1
- package/build/lib/image-util.js.map +1 -1
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/logging.d.ts.map +1 -1
- package/build/lib/logging.js +5 -8
- package/build/lib/logging.js.map +1 -1
- package/build/lib/mjpeg.d.ts.map +1 -1
- package/build/lib/mjpeg.js +7 -7
- package/build/lib/mjpeg.js.map +1 -1
- package/build/lib/net.d.ts.map +1 -1
- package/build/lib/net.js +21 -14
- package/build/lib/net.js.map +1 -1
- package/build/lib/node.d.ts.map +1 -1
- package/build/lib/node.js +7 -8
- package/build/lib/node.js.map +1 -1
- package/build/lib/npm.d.ts.map +1 -1
- package/build/lib/npm.js +3 -3
- package/build/lib/npm.js.map +1 -1
- package/build/lib/plist.js +11 -11
- package/build/lib/plist.js.map +1 -1
- package/build/lib/process.d.ts.map +1 -1
- package/build/lib/process.js +2 -2
- package/build/lib/process.js.map +1 -1
- package/build/lib/system.d.ts.map +1 -1
- package/build/lib/system.js +2 -3
- package/build/lib/system.js.map +1 -1
- package/build/lib/tempdir.d.ts +3 -2
- package/build/lib/tempdir.d.ts.map +1 -1
- package/build/lib/tempdir.js +2 -2
- package/build/lib/tempdir.js.map +1 -1
- package/build/lib/timing.d.ts.map +1 -1
- package/build/lib/timing.js +3 -7
- package/build/lib/timing.js.map +1 -1
- package/build/lib/util.d.ts +103 -24
- package/build/lib/util.d.ts.map +1 -1
- package/build/lib/util.js +158 -22
- package/build/lib/util.js.map +1 -1
- package/build/lib/zip.d.ts +42 -42
- package/build/lib/zip.d.ts.map +1 -1
- package/build/lib/zip.js +142 -142
- package/build/lib/zip.js.map +1 -1
- package/lib/console.ts +8 -9
- package/lib/doctor.ts +6 -6
- package/lib/env.ts +5 -5
- package/lib/fs.ts +14 -14
- package/lib/image-util.ts +2 -1
- package/lib/index.ts +7 -1
- package/lib/logging.ts +5 -5
- package/lib/mjpeg.ts +9 -7
- package/lib/net.ts +25 -19
- package/lib/node.ts +7 -8
- package/lib/npm.ts +5 -3
- package/lib/plist.ts +11 -11
- package/lib/process.ts +8 -2
- package/lib/system.ts +2 -3
- package/lib/tempdir.ts +2 -2
- package/lib/timing.ts +3 -5
- package/lib/util.ts +197 -44
- package/lib/zip.ts +223 -221
- package/package.json +11 -12
- package/tsconfig.json +1 -0
package/lib/util.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import B from 'bluebird';
|
|
2
|
-
import
|
|
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
|
-
|
|
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
|
|
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 (
|
|
49
|
-
return !
|
|
78
|
+
if (typeof val === 'number') {
|
|
79
|
+
return !Number.isNaN(val);
|
|
50
80
|
}
|
|
51
|
-
return
|
|
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 =
|
|
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 (
|
|
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 =
|
|
385
|
+
const newObj = {...obj} as Record<string, unknown>;
|
|
242
386
|
let pred: (v: unknown, o: T) => boolean;
|
|
243
|
-
if (
|
|
244
|
-
pred = (v) =>
|
|
245
|
-
} else if (
|
|
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(
|
|
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 (
|
|
587
|
+
if (typeof options === 'boolean') {
|
|
416
588
|
inclusive = options;
|
|
417
|
-
} else if (
|
|
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 (
|
|
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
|
}
|