appium 3.4.2 → 3.5.1

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 (196) hide show
  1. package/build/lib/appium.d.ts +3 -0
  2. package/build/lib/appium.d.ts.map +1 -1
  3. package/build/lib/appium.js +73 -51
  4. package/build/lib/appium.js.map +1 -1
  5. package/build/lib/bidi-commands.d.ts.map +1 -1
  6. package/build/lib/bidi-commands.js +36 -31
  7. package/build/lib/bidi-commands.js.map +1 -1
  8. package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -1
  9. package/build/lib/bootstrap/appium-initializer.js +13 -13
  10. package/build/lib/bootstrap/appium-initializer.js.map +1 -1
  11. package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -1
  12. package/build/lib/bootstrap/appium-main-runner.js +2 -2
  13. package/build/lib/bootstrap/appium-main-runner.js.map +1 -1
  14. package/build/lib/bootstrap/config-file.d.ts.map +1 -1
  15. package/build/lib/bootstrap/config-file.js +11 -11
  16. package/build/lib/bootstrap/config-file.js.map +1 -1
  17. package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -1
  18. package/build/lib/bootstrap/grid-v3-register.js +9 -6
  19. package/build/lib/bootstrap/grid-v3-register.js.map +1 -1
  20. package/build/lib/bootstrap/main-helpers.d.ts +1 -1
  21. package/build/lib/bootstrap/main-helpers.d.ts.map +1 -1
  22. package/build/lib/bootstrap/main-helpers.js +19 -20
  23. package/build/lib/bootstrap/main-helpers.js.map +1 -1
  24. package/build/lib/bootstrap/node-helpers.d.ts +1 -1
  25. package/build/lib/bootstrap/node-helpers.d.ts.map +1 -1
  26. package/build/lib/bootstrap/node-helpers.js +8 -16
  27. package/build/lib/bootstrap/node-helpers.js.map +1 -1
  28. package/build/lib/bootstrap/startup-config.d.ts.map +1 -1
  29. package/build/lib/bootstrap/startup-config.js +32 -30
  30. package/build/lib/bootstrap/startup-config.js.map +1 -1
  31. package/build/lib/cli/args.d.ts +3 -2
  32. package/build/lib/cli/args.d.ts.map +1 -1
  33. package/build/lib/cli/args.js +2 -5
  34. package/build/lib/cli/args.js.map +1 -1
  35. package/build/lib/cli/driver-command.d.ts +1 -2
  36. package/build/lib/cli/driver-command.d.ts.map +1 -1
  37. package/build/lib/cli/driver-command.js +7 -8
  38. package/build/lib/cli/driver-command.js.map +1 -1
  39. package/build/lib/cli/extension-command.d.ts +2 -2
  40. package/build/lib/cli/extension-command.d.ts.map +1 -1
  41. package/build/lib/cli/extension-command.js +105 -71
  42. package/build/lib/cli/extension-command.js.map +1 -1
  43. package/build/lib/cli/extension.d.ts.map +1 -1
  44. package/build/lib/cli/extension.js.map +1 -1
  45. package/build/lib/cli/parser.d.ts.map +1 -1
  46. package/build/lib/cli/parser.js +21 -14
  47. package/build/lib/cli/parser.js.map +1 -1
  48. package/build/lib/cli/plugin-command.d.ts +1 -1
  49. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  50. package/build/lib/cli/plugin-command.js +5 -5
  51. package/build/lib/cli/plugin-command.js.map +1 -1
  52. package/build/lib/cli/setup-command.d.ts +1 -1
  53. package/build/lib/cli/setup-command.d.ts.map +1 -1
  54. package/build/lib/cli/setup-command.js +14 -19
  55. package/build/lib/cli/setup-command.js.map +1 -1
  56. package/build/lib/cli/utils.d.ts.map +1 -1
  57. package/build/lib/cli/utils.js +3 -2
  58. package/build/lib/cli/utils.js.map +1 -1
  59. package/build/lib/doctor/doctor.d.ts +0 -1
  60. package/build/lib/doctor/doctor.d.ts.map +1 -1
  61. package/build/lib/doctor/doctor.js +12 -17
  62. package/build/lib/doctor/doctor.js.map +1 -1
  63. package/build/lib/extension/driver-config.d.ts.map +1 -1
  64. package/build/lib/extension/driver-config.js +11 -12
  65. package/build/lib/extension/driver-config.js.map +1 -1
  66. package/build/lib/extension/extension-config.d.ts.map +1 -1
  67. package/build/lib/extension/extension-config.js +30 -30
  68. package/build/lib/extension/extension-config.js.map +1 -1
  69. package/build/lib/extension/index.d.ts.map +1 -1
  70. package/build/lib/extension/index.js +28 -41
  71. package/build/lib/extension/index.js.map +1 -1
  72. package/build/lib/extension/manifest.d.ts +3 -2
  73. package/build/lib/extension/manifest.d.ts.map +1 -1
  74. package/build/lib/extension/manifest.js +20 -24
  75. package/build/lib/extension/manifest.js.map +1 -1
  76. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  77. package/build/lib/extension/plugin-config.js +7 -9
  78. package/build/lib/extension/plugin-config.js.map +1 -1
  79. package/build/lib/helpers/build.d.ts +0 -1
  80. package/build/lib/helpers/build.d.ts.map +1 -1
  81. package/build/lib/helpers/build.js +2 -4
  82. package/build/lib/helpers/build.js.map +1 -1
  83. package/build/lib/helpers/capability.d.ts.map +1 -1
  84. package/build/lib/helpers/capability.js +27 -22
  85. package/build/lib/helpers/capability.js.map +1 -1
  86. package/build/lib/helpers/network.d.ts.map +1 -1
  87. package/build/lib/helpers/network.js +4 -3
  88. package/build/lib/helpers/network.js.map +1 -1
  89. package/build/lib/insecure-features.d.ts.map +1 -1
  90. package/build/lib/insecure-features.js +9 -13
  91. package/build/lib/insecure-features.js.map +1 -1
  92. package/build/lib/inspector-commands.d.ts.map +1 -1
  93. package/build/lib/inspector-commands.js +29 -28
  94. package/build/lib/inspector-commands.js.map +1 -1
  95. package/build/lib/logsink.d.ts.map +1 -1
  96. package/build/lib/logsink.js +8 -7
  97. package/build/lib/logsink.js.map +1 -1
  98. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  99. package/build/lib/schema/arg-spec.js +5 -8
  100. package/build/lib/schema/arg-spec.js.map +1 -1
  101. package/build/lib/schema/cli-args.d.ts.map +1 -1
  102. package/build/lib/schema/cli-args.js +20 -19
  103. package/build/lib/schema/cli-args.js.map +1 -1
  104. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  105. package/build/lib/schema/cli-transformers.js.map +1 -1
  106. package/build/lib/schema/schema.d.ts.map +1 -1
  107. package/build/lib/schema/schema.js +28 -21
  108. package/build/lib/schema/schema.js.map +1 -1
  109. package/build/lib/utils/hash.d.ts +5 -0
  110. package/build/lib/utils/hash.d.ts.map +1 -0
  111. package/build/lib/{utils.js → utils/hash.js} +3 -21
  112. package/build/lib/utils/hash.js.map +1 -0
  113. package/build/lib/utils/index.d.ts +8 -0
  114. package/build/lib/utils/index.d.ts.map +1 -0
  115. package/build/lib/utils/index.js +31 -0
  116. package/build/lib/utils/index.js.map +1 -0
  117. package/build/lib/utils/is-package-changed.d.ts +16 -0
  118. package/build/lib/utils/is-package-changed.d.ts.map +1 -0
  119. package/build/lib/utils/is-package-changed.js +62 -0
  120. package/build/lib/utils/is-package-changed.js.map +1 -0
  121. package/build/lib/utils/object.d.ts +120 -0
  122. package/build/lib/utils/object.d.ts.map +1 -0
  123. package/build/lib/utils/object.js +288 -0
  124. package/build/lib/utils/object.js.map +1 -0
  125. package/build/lib/{extension → utils}/package-changed.d.ts +0 -1
  126. package/build/lib/utils/package-changed.d.ts.map +1 -0
  127. package/build/lib/{extension → utils}/package-changed.js +3 -4
  128. package/build/lib/utils/package-changed.js.map +1 -0
  129. package/build/lib/utils/package-json.d.ts +9 -0
  130. package/build/lib/utils/package-json.d.ts.map +1 -0
  131. package/build/lib/utils/package-json.js +32 -0
  132. package/build/lib/utils/package-json.js.map +1 -0
  133. package/build/lib/utils/resolve-from.d.ts +11 -0
  134. package/build/lib/utils/resolve-from.d.ts.map +1 -0
  135. package/build/lib/utils/resolve-from.js +41 -0
  136. package/build/lib/utils/resolve-from.js.map +1 -0
  137. package/build/types/cli.d.ts.map +1 -1
  138. package/build/types/index.d.ts.map +1 -1
  139. package/build/types/manifest/base.d.ts.map +1 -1
  140. package/build/types/manifest/v3.d.ts.map +1 -1
  141. package/build/types/manifest/v4.d.ts.map +1 -1
  142. package/lib/appium.ts +96 -61
  143. package/lib/bidi-commands.ts +107 -61
  144. package/lib/bootstrap/appium-initializer.ts +27 -19
  145. package/lib/bootstrap/appium-main-runner.ts +8 -4
  146. package/lib/bootstrap/config-file.ts +33 -16
  147. package/lib/bootstrap/grid-v3-register.ts +26 -19
  148. package/lib/bootstrap/main-helpers.ts +25 -19
  149. package/lib/bootstrap/node-helpers.ts +20 -24
  150. package/lib/bootstrap/startup-config.ts +42 -39
  151. package/lib/cli/args.ts +3 -4
  152. package/lib/cli/driver-command.ts +19 -13
  153. package/lib/cli/extension-command.ts +214 -149
  154. package/lib/cli/extension.ts +4 -6
  155. package/lib/cli/parser.ts +32 -30
  156. package/lib/cli/plugin-command.ts +20 -9
  157. package/lib/cli/setup-command.ts +54 -39
  158. package/lib/cli/utils.ts +4 -3
  159. package/lib/doctor/doctor.ts +15 -17
  160. package/lib/extension/driver-config.ts +22 -17
  161. package/lib/extension/extension-config.ts +76 -69
  162. package/lib/extension/index.ts +60 -51
  163. package/lib/extension/manifest.ts +35 -33
  164. package/lib/extension/plugin-config.ts +15 -10
  165. package/lib/helpers/build.ts +6 -5
  166. package/lib/helpers/capability.ts +40 -35
  167. package/lib/helpers/network.ts +6 -5
  168. package/lib/insecure-features.ts +16 -14
  169. package/lib/inspector-commands.ts +72 -40
  170. package/lib/logsink.ts +22 -26
  171. package/lib/schema/arg-spec.ts +9 -8
  172. package/lib/schema/cli-args-guards.ts +4 -4
  173. package/lib/schema/cli-args.ts +25 -21
  174. package/lib/schema/cli-transformers.ts +6 -2
  175. package/lib/schema/format-errors.ts +1 -1
  176. package/lib/schema/schema.ts +52 -38
  177. package/lib/{utils.ts → utils/hash.ts} +2 -19
  178. package/lib/utils/index.ts +23 -0
  179. package/lib/utils/is-package-changed.ts +78 -0
  180. package/lib/utils/object.ts +312 -0
  181. package/lib/{extension → utils}/package-changed.ts +6 -7
  182. package/lib/utils/package-json.ts +36 -0
  183. package/lib/utils/resolve-from.ts +40 -0
  184. package/package.json +16 -19
  185. package/scripts/autoinstall-extensions.js +8 -13
  186. package/tsconfig.json +8 -2
  187. package/types/cli.ts +18 -18
  188. package/types/index.ts +2 -2
  189. package/types/manifest/base.ts +2 -2
  190. package/types/manifest/v3.ts +2 -2
  191. package/types/manifest/v4.ts +2 -2
  192. package/build/lib/extension/package-changed.d.ts.map +0 -1
  193. package/build/lib/extension/package-changed.js.map +0 -1
  194. package/build/lib/utils.d.ts +0 -13
  195. package/build/lib/utils.d.ts.map +0 -1
  196. package/build/lib/utils.js.map +0 -1
@@ -1,13 +1,17 @@
1
- import B from 'bluebird';
2
- import {env, fs} from '@appium/support';
3
- import _ from 'lodash';
1
+ import {env, fs, util} from '@appium/support';
4
2
  import path from 'node:path';
5
3
  import * as YAML from 'yaml';
6
4
  import type {DriverType, ExtensionType, PluginType} from '@appium/types';
7
- import type {ExtManifest, ExtPackageJson, ExtRecord, InternalMetadata, ManifestData} from 'appium/types';
5
+ import type {
6
+ ExtManifest,
7
+ ExtPackageJson,
8
+ ExtRecord,
9
+ InternalMetadata,
10
+ ManifestData,
11
+ } from 'appium/types';
8
12
  import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
9
13
  import {INSTALL_TYPE_DEV, INSTALL_TYPE_NPM} from './extension-config';
10
- import {packageDidChange} from './package-changed';
14
+ import {packageDidChange} from '../utils';
11
15
  import {migrate} from './manifest-migrations';
12
16
 
13
17
  const CONFIG_DATA_DRIVER_KEY = `${DRIVER_TYPE}s` as const;
@@ -30,7 +34,7 @@ export class Manifest {
30
34
  *
31
35
  * @param appiumHome - `APPIUM_HOME` path used as the cache key
32
36
  */
33
- static getInstance = _.memoize((appiumHome: string): Manifest => new Manifest(appiumHome));
37
+ static getInstance = util.memoize((appiumHome: string): Manifest => new Manifest(appiumHome));
34
38
 
35
39
  #data!: ManifestData;
36
40
  readonly #appiumHome: string;
@@ -40,7 +44,7 @@ export class Manifest {
40
44
 
41
45
  private constructor(appiumHome: string) {
42
46
  this.#appiumHome = appiumHome;
43
- this.#data = _.cloneDeep(INITIAL_MANIFEST_DATA) as ManifestData;
47
+ this.#data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
44
48
  }
45
49
 
46
50
  /** `APPIUM_HOME` directory this manifest is tied to. */
@@ -111,7 +115,7 @@ export class Manifest {
111
115
  data = YAML.parse(yaml) as ManifestData;
112
116
  } catch (err: any) {
113
117
  if (err.code === 'ENOENT') {
114
- data = _.cloneDeep(INITIAL_MANIFEST_DATA) as ManifestData;
118
+ data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
115
119
  shouldWrite = true;
116
120
  } else {
117
121
  throw new Error(
@@ -119,7 +123,7 @@ export class Manifest {
119
123
  `cache file (${manifestPathResolved}). It may be invalid YAML. Specific error: ${
120
124
  err.message
121
125
  }`,
122
- {cause: err}
126
+ {cause: err},
123
127
  );
124
128
  }
125
129
  }
@@ -166,9 +170,9 @@ export class Manifest {
166
170
  } catch (err: any) {
167
171
  throw new Error(
168
172
  `Appium could not create the directory for the manifest file: ${path.dirname(
169
- manifestPathResolved
173
+ manifestPathResolved,
170
174
  )}. Original error: ${err.message}`,
171
- {cause: err}
175
+ {cause: err},
172
176
  );
173
177
  }
174
178
  try {
@@ -179,7 +183,7 @@ export class Manifest {
179
183
  `Appium could not write to manifest at ${manifestPathResolved} using APPIUM_HOME ${
180
184
  this.#appiumHome
181
185
  }. Please ensure it is writable. Original error: ${err.message}`,
182
- {cause: err}
186
+ {cause: err},
183
187
  );
184
188
  }
185
189
  })();
@@ -212,9 +216,7 @@ export class Manifest {
212
216
  }
213
217
  };
214
218
 
215
- const queue: Promise<void>[] = [
216
- onMatch(path.join(this.#appiumHome, 'package.json'), true),
217
- ];
219
+ const queue: Promise<void>[] = [onMatch(path.join(this.#appiumHome, 'package.json'), true)];
218
220
 
219
221
  const filepaths = await fs.glob('node_modules/{*,@*/*}/package.json', {
220
222
  cwd: this.#appiumHome,
@@ -224,7 +226,7 @@ export class Manifest {
224
226
  queue.push(onMatch(filepath));
225
227
  }
226
228
 
227
- await B.all(queue);
229
+ await Promise.all(queue);
228
230
 
229
231
  return didChange;
230
232
  }
@@ -241,7 +243,7 @@ export class Manifest {
241
243
  addExtensionFromPackage(
242
244
  pkgJson: ExtPackageJson<ExtensionType>,
243
245
  pkgPath: string,
244
- installType: typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_DEV = INSTALL_TYPE_NPM
246
+ installType: typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_DEV = INSTALL_TYPE_NPM,
245
247
  ): boolean {
246
248
  const extensionPath = path.dirname(pkgPath);
247
249
 
@@ -255,31 +257,31 @@ export class Manifest {
255
257
  };
256
258
 
257
259
  if (isDriver(pkgJson)) {
258
- const driverName = pkgJson.appium.driverName;
260
+ const {driverName, ...appiumDriverMeta} = pkgJson.appium;
259
261
  const value = {
260
- ..._.omit(pkgJson.appium, 'driverName'),
262
+ ...appiumDriverMeta,
261
263
  ...internal,
262
264
  };
263
- if (!_.isEqual(value, this.#data.drivers[driverName])) {
265
+ if (!util.isEqual(value, this.#data.drivers[driverName])) {
264
266
  this.setExtension(DRIVER_TYPE, driverName, value);
265
267
  return true;
266
268
  }
267
269
  return false;
268
270
  }
269
271
  if (isPlugin(pkgJson)) {
270
- const pluginName = pkgJson.appium.pluginName;
272
+ const {pluginName, ...appiumPluginMeta} = pkgJson.appium;
271
273
  const value = {
272
- ..._.omit(pkgJson.appium, 'pluginName'),
274
+ ...appiumPluginMeta,
273
275
  ...internal,
274
276
  };
275
- if (!_.isEqual(value, this.#data.plugins[pluginName])) {
277
+ if (!util.isEqual(value, this.#data.plugins[pluginName])) {
276
278
  this.setExtension(PLUGIN_TYPE, pluginName, value);
277
279
  return true;
278
280
  }
279
281
  return false;
280
282
  }
281
283
  throw new TypeError(
282
- `The extension in ${extensionPath} is neither a valid ${DRIVER_TYPE} nor a valid ${PLUGIN_TYPE}.`
284
+ `The extension in ${extensionPath} is neither a valid ${DRIVER_TYPE} nor a valid ${PLUGIN_TYPE}.`,
283
285
  );
284
286
  }
285
287
 
@@ -294,9 +296,9 @@ export class Manifest {
294
296
  setExtension<ExtType extends ExtensionType>(
295
297
  extType: ExtType,
296
298
  extName: string,
297
- extData: ExtManifest<ExtType>
299
+ extData: ExtManifest<ExtType>,
298
300
  ): ExtManifest<ExtType> {
299
- const data = _.cloneDeep(extData) as ExtManifest<ExtType>;
301
+ const data = structuredClone(extData) as ExtManifest<ExtType>;
300
302
  if (extType === DRIVER_TYPE) {
301
303
  this.#data.drivers[extName] = data as unknown as ExtManifest<DriverType>;
302
304
  } else {
@@ -337,7 +339,7 @@ export class Manifest {
337
339
  throw new Error(
338
340
  `Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${
339
341
  this.appiumHome
340
- }, manifest file: ${resolved}`
342
+ }, manifest file: ${resolved}`,
341
343
  );
342
344
  }
343
345
  }
@@ -348,10 +350,10 @@ export class Manifest {
348
350
 
349
351
  function isExtension(value: unknown): value is ExtPackageJson<ExtensionType> {
350
352
  return (
351
- _.isPlainObject(value) &&
352
- _.isPlainObject((value as {appium?: unknown}).appium) &&
353
- _.isString((value as {name?: unknown}).name) &&
354
- _.isString((value as {version?: unknown}).version)
353
+ util.isPlainObject(value) &&
354
+ util.isPlainObject((value as {appium?: unknown}).appium) &&
355
+ typeof (value as {name?: unknown}).name === 'string' &&
356
+ typeof (value as {version?: unknown}).version === 'string'
355
357
  );
356
358
  }
357
359
 
@@ -359,7 +361,7 @@ function isDriver(value: unknown): value is ExtPackageJson<DriverType> {
359
361
  return (
360
362
  isExtension(value) &&
361
363
  'driverName' in value.appium &&
362
- _.isString((value.appium as {driverName?: unknown}).driverName)
364
+ typeof (value.appium as {driverName?: unknown}).driverName === 'string'
363
365
  );
364
366
  }
365
367
 
@@ -367,6 +369,6 @@ function isPlugin(value: unknown): value is ExtPackageJson<PluginType> {
367
369
  return (
368
370
  isExtension(value) &&
369
371
  'pluginName' in value.appium &&
370
- _.isString((value.appium as {pluginName?: unknown}).pluginName)
372
+ typeof (value.appium as {pluginName?: unknown}).pluginName === 'string'
371
373
  );
372
374
  }
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {util} from '@appium/support';
2
2
  import type {PluginType} from '@appium/types';
3
3
  import type {ExtManifest, ExtName, ExtRecord} from 'appium/types';
4
4
  import {PLUGIN_TYPE} from '../constants';
@@ -17,7 +17,7 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
17
17
  const instance = new PluginConfig(manifest);
18
18
  if (PluginConfig.getInstance(manifest)) {
19
19
  throw new Error(
20
- `Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it.`
20
+ `Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it.`,
21
21
  );
22
22
  }
23
23
  PluginConfig._instances.set(manifest, instance);
@@ -34,7 +34,7 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
34
34
 
35
35
  public override extensionDesc(
36
36
  pluginName: ExtName<PluginType>,
37
- {version}: ExtManifest<PluginType>
37
+ {version}: ExtManifest<PluginType>,
38
38
  ): string {
39
39
  return `${String(pluginName)}@${version}`;
40
40
  }
@@ -42,21 +42,26 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
42
42
  override print(activeNames: ExtName<PluginType>[] = []): void {
43
43
  const pluginNames = Object.keys(this.installedExtensions);
44
44
 
45
- if (_.isEmpty(pluginNames)) {
45
+ if (util.isEmpty(pluginNames)) {
46
46
  log.info(
47
- `No plugins have been installed. Use the "appium plugin" ` + 'command to install the one(s) you want to use.'
47
+ `No plugins have been installed. Use the "appium plugin" ` +
48
+ 'command to install the one(s) you want to use.',
48
49
  );
49
50
  return;
50
51
  }
51
52
 
52
53
  log.info(`Available plugins:`);
53
- for (const [pluginName, pluginData] of _.toPairs(this.installedExtensions)) {
54
- const activeTxt = _.includes(activeNames, pluginName as ExtName<PluginType>) ? ' (ACTIVE)' : '';
55
- log.info(` - ${this.extensionDesc(pluginName as ExtName<PluginType>, pluginData)}${activeTxt}`);
54
+ for (const [pluginName, pluginData] of Object.entries(this.installedExtensions)) {
55
+ const activeTxt = activeNames.includes(pluginName as ExtName<PluginType>) ? ' (ACTIVE)' : '';
56
+ log.info(
57
+ ` - ${this.extensionDesc(pluginName as ExtName<PluginType>, pluginData)}${activeTxt}`,
58
+ );
56
59
  }
57
60
 
58
- if (_.isEmpty(activeNames)) {
59
- log.info('No plugins activated. Use the --use-plugins flag with names of plugins to activate');
61
+ if (util.isEmpty(activeNames)) {
62
+ log.info(
63
+ 'No plugins activated. Use the --use-plugins flag with names of plugins to activate',
64
+ );
60
65
  }
61
66
  }
62
67
  }
@@ -1,17 +1,15 @@
1
- import _ from 'lodash';
2
1
  import axios from 'axios';
3
2
  import {exec} from 'teen_process';
4
- import {system, fs} from '@appium/support';
3
+ import {system, fs, util} from '@appium/support';
5
4
  import type {BuildInfo} from 'appium/types';
6
5
  import {npmPackage} from '../utils';
7
6
 
8
7
  export const APPIUM_VER = npmPackage.version;
9
- export const rootDir = fs.findRoot(__dirname);
10
8
 
11
9
  const GIT_BINARY = `git${system.isWindows() ? '.exe' : ''}`;
12
10
  const GITHUB_API = 'https://api.github.com/repos/appium/appium';
13
11
 
14
- const getFullGitPath = _.memoize(async function getFullGitPath(): Promise<string | null> {
12
+ const getFullGitPath = util.memoize(async function getFullGitPath(): Promise<string | null> {
15
13
  try {
16
14
  return await fs.which(GIT_BINARY);
17
15
  } catch {
@@ -54,7 +52,10 @@ export async function getGitRev(useGithubApiFallback = false): Promise<string |
54
52
  return null;
55
53
  }
56
54
 
57
- async function getGitTimestamp(commitSha: string, useGithubApiFallback = false): Promise<string | null> {
55
+ async function getGitTimestamp(
56
+ commitSha: string,
57
+ useGithubApiFallback = false,
58
+ ): Promise<string | null> {
58
59
  const fullGitPath = await getFullGitPath();
59
60
  if (fullGitPath) {
60
61
  try {
@@ -5,14 +5,10 @@ import type {
5
5
  NSCapabilities,
6
6
  W3CCapabilities,
7
7
  } from '@appium/types';
8
- import _ from 'lodash';
8
+ import {util} from '@appium/support';
9
9
  import {log as logger} from '../logger';
10
- import {
11
- processCapabilities,
12
- STANDARD_CAPS,
13
- errors,
14
- isW3cCaps,
15
- } from '@appium/base-driver';
10
+ import {processCapabilities, STANDARD_CAPS, errors, isW3cCaps} from '@appium/base-driver';
11
+ import {mapKeys} from '../utils';
16
12
 
17
13
  const W3C_APPIUM_PREFIX = 'appium';
18
14
  const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
@@ -36,7 +32,7 @@ export interface InvalidCaps<C extends Constraints = BaseDriverCapConstraints> {
36
32
  export function makeNonW3cCapsError(): Error {
37
33
  return new errors.SessionNotCreatedError(
38
34
  'Session capabilities format must comply to the W3C standard. Make sure your client is up to date. ' +
39
- 'See https://www.w3.org/TR/webdriver/#new-session for more details.'
35
+ 'See https://www.w3.org/TR/webdriver/#new-session for more details.',
40
36
  );
41
37
  }
42
38
 
@@ -48,7 +44,7 @@ export function makeNonW3cCapsError(): Error {
48
44
  export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapConstraints>(
49
45
  w3cCapabilities: W3CCapabilities<C>,
50
46
  constraints: C = {} as C,
51
- defaultCapabilities: NSCapabilities<C> = {}
47
+ defaultCapabilities: NSCapabilities<C> = {},
52
48
  ): ParsedDriverCaps<C> | InvalidCaps<C> {
53
49
  if (!isW3cCaps(w3cCapabilities)) {
54
50
  return {error: makeNonW3cCapsError()};
@@ -58,16 +54,16 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
58
54
  // eslint-disable-next-line prefer-const -- assigned in success path after try
59
55
  let processedW3CCapabilities: W3CCapabilities<C> | undefined;
60
56
 
61
- w3cCapabilities = _.cloneDeep(w3cCapabilities);
62
- defaultCapabilities = _.cloneDeep(defaultCapabilities);
57
+ w3cCapabilities = structuredClone(w3cCapabilities);
58
+ defaultCapabilities = structuredClone(defaultCapabilities);
63
59
 
64
- if (!_.isEmpty(defaultCapabilities)) {
65
- for (const [defaultCapKey, defaultCapValue] of _.toPairs(defaultCapabilities)) {
60
+ if (!util.isEmpty(defaultCapabilities)) {
61
+ for (const [defaultCapKey, defaultCapValue] of Object.entries(defaultCapabilities)) {
66
62
  let isCapAlreadySet = false;
67
63
  for (const firstMatchEntry of w3cCapabilities.firstMatch ?? []) {
68
64
  if (
69
- _.isPlainObject(firstMatchEntry) &&
70
- _.has(removeAppiumPrefixes(firstMatchEntry as NSCapabilities<C>), removeAppiumPrefix(defaultCapKey))
65
+ util.isPlainObject(firstMatchEntry) &&
66
+ hasOwnCapability(firstMatchEntry as Record<string, unknown>, defaultCapKey)
71
67
  ) {
72
68
  isCapAlreadySet = true;
73
69
  break;
@@ -75,17 +71,16 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
75
71
  }
76
72
  isCapAlreadySet =
77
73
  isCapAlreadySet ||
78
- (_.isPlainObject(w3cCapabilities.alwaysMatch) &&
79
- _.has(
80
- removeAppiumPrefixes(w3cCapabilities.alwaysMatch),
81
- removeAppiumPrefix(defaultCapKey)
82
- ));
74
+ (util.isPlainObject(w3cCapabilities.alwaysMatch) &&
75
+ hasOwnCapability(w3cCapabilities.alwaysMatch as Record<string, unknown>, defaultCapKey));
83
76
  if (isCapAlreadySet) {
84
77
  continue;
85
78
  }
86
79
 
87
- if (_.isEmpty(w3cCapabilities.firstMatch)) {
88
- w3cCapabilities.firstMatch = [{[defaultCapKey]: defaultCapValue}] as W3CCapabilities<C>['firstMatch'];
80
+ if (util.isEmpty(w3cCapabilities.firstMatch)) {
81
+ w3cCapabilities.firstMatch = [
82
+ {[defaultCapKey]: defaultCapValue},
83
+ ] as W3CCapabilities<C>['firstMatch'];
89
84
  } else {
90
85
  (w3cCapabilities.firstMatch[0] as Record<string, unknown>)[defaultCapKey] = defaultCapValue;
91
86
  }
@@ -118,12 +113,12 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
118
113
  * Prefixes capability keys with `appium:` where appropriate.
119
114
  */
120
115
  export function insertAppiumPrefixes<C extends Constraints = BaseDriverCapConstraints>(
121
- caps: Capabilities<C>
116
+ caps: Capabilities<C>,
122
117
  ): NSCapabilities<C> {
123
- return _.mapKeys(caps, (_, key) =>
124
- STANDARD_CAPS_LOWERCASE.has(key.toLowerCase()) || key.includes(':')
125
- ? key
126
- : `${W3C_APPIUM_PREFIX}:${key}`
118
+ return mapKeys(caps as Record<string, unknown>, (_, key) =>
119
+ STANDARD_CAPS_LOWERCASE.has(String(key).toLowerCase()) || String(key).includes(':')
120
+ ? String(key)
121
+ : `${W3C_APPIUM_PREFIX}:${key}`,
127
122
  ) as NSCapabilities<C>;
128
123
  }
129
124
 
@@ -131,9 +126,11 @@ export function insertAppiumPrefixes<C extends Constraints = BaseDriverCapConstr
131
126
  * Removes `appium:` prefix from capability keys.
132
127
  */
133
128
  export function removeAppiumPrefixes<C extends Constraints = BaseDriverCapConstraints>(
134
- caps: NSCapabilities<C>
129
+ caps: NSCapabilities<C>,
135
130
  ): Capabilities<C> {
136
- return _.mapKeys(caps, (_, key) => removeAppiumPrefix(key)) as Capabilities<C>;
131
+ return mapKeys(caps as Record<string, unknown>, (_, key) =>
132
+ removeAppiumPrefix(String(key)),
133
+ ) as Capabilities<C>;
137
134
  }
138
135
 
139
136
  /**
@@ -142,16 +139,18 @@ export function removeAppiumPrefixes<C extends Constraints = BaseDriverCapConstr
142
139
  *
143
140
  * @returns Parsed settings object; empty if none found.
144
141
  */
145
- export function pullSettings(caps: Record<string, unknown> | null | undefined): Record<string, unknown> {
146
- if (!_.isPlainObject(caps) || _.isEmpty(caps)) {
142
+ export function pullSettings(
143
+ caps: Record<string, unknown> | null | undefined,
144
+ ): Record<string, unknown> {
145
+ if (!util.isPlainObject(caps) || util.isEmpty(caps)) {
147
146
  return {};
148
147
  }
149
148
 
150
149
  const result: Record<string, unknown> = {};
151
150
  const singleSettings: Record<string, unknown> = {};
152
- for (const [key, value] of _.toPairs(caps)) {
151
+ for (const [key, value] of Object.entries(caps)) {
153
152
  let match: RegExpExecArray | null;
154
- if (/^(s|appium:s)ettings$/.test(key) && _.isPlainObject(value)) {
153
+ if (/^(s|appium:s)ettings$/.test(key) && util.isPlainObject(value)) {
155
154
  Object.assign(result, value);
156
155
  delete caps[key];
157
156
  } else if ((match = /^(s|appium:s)ettings\[(\S+)\]$/.exec(key))) {
@@ -159,7 +158,7 @@ export function pullSettings(caps: Record<string, unknown> | null | undefined):
159
158
  delete caps[key];
160
159
  }
161
160
  }
162
- if (!_.isEmpty(singleSettings)) {
161
+ if (!util.isEmpty(singleSettings)) {
163
162
  Object.assign(result, singleSettings);
164
163
  }
165
164
  return result;
@@ -167,5 +166,11 @@ export function pullSettings(caps: Record<string, unknown> | null | undefined):
167
166
 
168
167
  function removeAppiumPrefix(key: string): string {
169
168
  const prefix = `${W3C_APPIUM_PREFIX}:`;
170
- return _.startsWith(key, prefix) ? key.substring(prefix.length) : key;
169
+ return key.startsWith(prefix) ? key.substring(prefix.length) : key;
170
+ }
171
+
172
+ /** True when `caps` has an own property matching `capKey` (with or without `appium:` prefix). */
173
+ function hasOwnCapability(caps: Record<string, unknown>, capKey: string): boolean {
174
+ const targetKey = removeAppiumPrefix(capKey);
175
+ return Object.keys(caps).some((key) => removeAppiumPrefix(key) === targetKey);
171
176
  }
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import os from 'node:os';
3
2
 
4
3
  export const V4_BROADCAST_IP = '0.0.0.0';
@@ -16,10 +15,12 @@ export function fetchInterfaces(family: 4 | 6 | null = null): os.NetworkInterfac
16
15
  } else if (family === 6) {
17
16
  familyValue = [6, 'IPv6'];
18
17
  }
19
- const ifaces = _.values(os.networkInterfaces()).filter(Boolean) as os.NetworkInterfaceInfo[][];
20
- return _.flatMap(ifaces).filter(
21
- (info) => !familyValue || familyValue.includes(info.family as 4 | 6 | string)
22
- );
18
+ const ifaces = Object.values(os.networkInterfaces()).filter(
19
+ Boolean,
20
+ ) as os.NetworkInterfaceInfo[][];
21
+ return ifaces
22
+ .flat()
23
+ .filter((info) => !familyValue || familyValue.includes(info.family as 4 | 6 | string));
23
24
  }
24
25
 
25
26
  /**
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {util} from '@appium/support';
2
2
  import {log as logger} from './logger';
3
3
 
4
4
  import type {AppiumDriver} from './appium';
@@ -20,20 +20,20 @@ export function configureGlobalFeatures(this: AppiumDriver) {
20
20
  `enabled unless explicitly disabled by --deny-insecure`,
21
21
  );
22
22
  this.relaxedSecurityEnabled = true;
23
- } else if (!_.isEmpty(this.args.allowInsecure)) {
23
+ } else if (!util.isEmpty(this.args.allowInsecure)) {
24
24
  this.allowInsecure = validateFeatures(this.args.allowInsecure);
25
25
  const globalAllowedFeatures = filterInsecureFeatures(this.allowInsecure);
26
- if (!_.isEmpty(globalAllowedFeatures)) {
26
+ if (!util.isEmpty(globalAllowedFeatures)) {
27
27
  logger.info('Explicitly enabling insecure features:');
28
28
  globalAllowedFeatures.forEach((a) => logger.info(` ${a}`));
29
29
  }
30
30
  }
31
- if (_.isEmpty(this.args.denyInsecure)) {
31
+ if (util.isEmpty(this.args.denyInsecure)) {
32
32
  return;
33
33
  }
34
34
  this.denyInsecure = validateFeatures(this.args.denyInsecure);
35
35
  const globalDeniedFeatures = filterInsecureFeatures(this.denyInsecure);
36
- if (_.isEmpty(globalDeniedFeatures)) {
36
+ if (util.isEmpty(globalDeniedFeatures)) {
37
37
  return;
38
38
  }
39
39
  logger.info('Explicitly disabling insecure features:');
@@ -60,19 +60,20 @@ export function configureDriverFeatures(
60
60
  driver.relaxedSecurityEnabled = true;
61
61
  }
62
62
  const allowedDriverFeatures = filterInsecureFeatures(this.allowInsecure, driverName);
63
- if (!_.isEmpty(allowedDriverFeatures)) {
64
- this.log.info('Explicitly enabling insecure features for this session ' +
65
- 'as per the server configuration:',
63
+ if (!util.isEmpty(allowedDriverFeatures)) {
64
+ this.log.info(
65
+ 'Explicitly enabling insecure features for this session ' +
66
+ 'as per the server configuration:',
66
67
  );
67
68
  allowedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
68
69
  driver.allowInsecure = allowedDriverFeatures;
69
70
  }
70
71
  const deniedDriverFeatures = filterInsecureFeatures(this.denyInsecure, driverName);
71
- if (_.isEmpty(deniedDriverFeatures)) {
72
+ if (util.isEmpty(deniedDriverFeatures)) {
72
73
  return;
73
74
  }
74
- this.log.info('Explicitly disabling insecure features for this session ' +
75
- 'as per the server configuration:',
75
+ this.log.info(
76
+ 'Explicitly disabling insecure features for this session ' + 'as per the server configuration:',
76
77
  );
77
78
  deniedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
78
79
  driver.denyInsecure = deniedDriverFeatures;
@@ -85,7 +86,8 @@ export function configureDriverFeatures(
85
86
  */
86
87
  function validateFeatures(features: string[]): string[] {
87
88
  const validator = (fullName: string) => {
88
- const errMsg = `The full feature name must include both the destination automation name or the ` +
89
+ const errMsg =
90
+ `The full feature name must include both the destination automation name or the ` +
89
91
  `'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
90
92
  `the feature name split by a colon. Got '${fullName}' instead`;
91
93
 
@@ -95,7 +97,7 @@ function validateFeatures(features: string[]): string[] {
95
97
  }
96
98
  const [automationName, featureName] = [
97
99
  fullName.substring(0, separatorPos),
98
- fullName.substring(separatorPos + 1)
100
+ fullName.substring(separatorPos + 1),
99
101
  ];
100
102
  if (!automationName || !featureName) {
101
103
  throw new Error(errMsg);
@@ -115,7 +117,7 @@ function validateFeatures(features: string[]): string[] {
115
117
  */
116
118
  function filterInsecureFeatures(
117
119
  features: string[],
118
- driverName: string = ALL_DRIVERS_MATCH
120
+ driverName: string = ALL_DRIVERS_MATCH,
119
121
  ): string[] {
120
122
  const filterFn = (fullName: string) => {
121
123
  const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);