appium 3.5.0 → 3.5.2

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 (195) hide show
  1. package/build/lib/appium.d.ts.map +1 -1
  2. package/build/lib/appium.js +43 -45
  3. package/build/lib/appium.js.map +1 -1
  4. package/build/lib/bidi-commands.d.ts.map +1 -1
  5. package/build/lib/bidi-commands.js +34 -29
  6. package/build/lib/bidi-commands.js.map +1 -1
  7. package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -1
  8. package/build/lib/bootstrap/appium-initializer.js +13 -13
  9. package/build/lib/bootstrap/appium-initializer.js.map +1 -1
  10. package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -1
  11. package/build/lib/bootstrap/appium-main-runner.js +2 -2
  12. package/build/lib/bootstrap/appium-main-runner.js.map +1 -1
  13. package/build/lib/bootstrap/config-file.d.ts.map +1 -1
  14. package/build/lib/bootstrap/config-file.js +11 -11
  15. package/build/lib/bootstrap/config-file.js.map +1 -1
  16. package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -1
  17. package/build/lib/bootstrap/grid-v3-register.js +9 -6
  18. package/build/lib/bootstrap/grid-v3-register.js.map +1 -1
  19. package/build/lib/bootstrap/main-helpers.d.ts +1 -1
  20. package/build/lib/bootstrap/main-helpers.d.ts.map +1 -1
  21. package/build/lib/bootstrap/main-helpers.js +19 -20
  22. package/build/lib/bootstrap/main-helpers.js.map +1 -1
  23. package/build/lib/bootstrap/node-helpers.d.ts +1 -1
  24. package/build/lib/bootstrap/node-helpers.d.ts.map +1 -1
  25. package/build/lib/bootstrap/node-helpers.js +7 -14
  26. package/build/lib/bootstrap/node-helpers.js.map +1 -1
  27. package/build/lib/bootstrap/startup-config.d.ts.map +1 -1
  28. package/build/lib/bootstrap/startup-config.js +32 -30
  29. package/build/lib/bootstrap/startup-config.js.map +1 -1
  30. package/build/lib/cli/args.d.ts +3 -2
  31. package/build/lib/cli/args.d.ts.map +1 -1
  32. package/build/lib/cli/args.js +2 -5
  33. package/build/lib/cli/args.js.map +1 -1
  34. package/build/lib/cli/driver-command.d.ts +1 -2
  35. package/build/lib/cli/driver-command.d.ts.map +1 -1
  36. package/build/lib/cli/driver-command.js +7 -8
  37. package/build/lib/cli/driver-command.js.map +1 -1
  38. package/build/lib/cli/extension-command.d.ts +2 -2
  39. package/build/lib/cli/extension-command.d.ts.map +1 -1
  40. package/build/lib/cli/extension-command.js +100 -66
  41. package/build/lib/cli/extension-command.js.map +1 -1
  42. package/build/lib/cli/extension.d.ts.map +1 -1
  43. package/build/lib/cli/extension.js.map +1 -1
  44. package/build/lib/cli/parser.d.ts.map +1 -1
  45. package/build/lib/cli/parser.js +21 -14
  46. package/build/lib/cli/parser.js.map +1 -1
  47. package/build/lib/cli/plugin-command.d.ts +1 -1
  48. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  49. package/build/lib/cli/plugin-command.js +5 -5
  50. package/build/lib/cli/plugin-command.js.map +1 -1
  51. package/build/lib/cli/setup-command.d.ts +1 -1
  52. package/build/lib/cli/setup-command.d.ts.map +1 -1
  53. package/build/lib/cli/setup-command.js +14 -19
  54. package/build/lib/cli/setup-command.js.map +1 -1
  55. package/build/lib/cli/utils.d.ts.map +1 -1
  56. package/build/lib/cli/utils.js +3 -2
  57. package/build/lib/cli/utils.js.map +1 -1
  58. package/build/lib/doctor/doctor.d.ts +0 -1
  59. package/build/lib/doctor/doctor.d.ts.map +1 -1
  60. package/build/lib/doctor/doctor.js +12 -17
  61. package/build/lib/doctor/doctor.js.map +1 -1
  62. package/build/lib/extension/driver-config.d.ts.map +1 -1
  63. package/build/lib/extension/driver-config.js +11 -12
  64. package/build/lib/extension/driver-config.js.map +1 -1
  65. package/build/lib/extension/extension-config.d.ts.map +1 -1
  66. package/build/lib/extension/extension-config.js +28 -27
  67. package/build/lib/extension/extension-config.js.map +1 -1
  68. package/build/lib/extension/index.d.ts.map +1 -1
  69. package/build/lib/extension/index.js +13 -16
  70. package/build/lib/extension/index.js.map +1 -1
  71. package/build/lib/extension/manifest.d.ts +3 -2
  72. package/build/lib/extension/manifest.d.ts.map +1 -1
  73. package/build/lib/extension/manifest.js +19 -22
  74. package/build/lib/extension/manifest.js.map +1 -1
  75. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  76. package/build/lib/extension/plugin-config.js +7 -9
  77. package/build/lib/extension/plugin-config.js.map +1 -1
  78. package/build/lib/helpers/build.d.ts +0 -1
  79. package/build/lib/helpers/build.d.ts.map +1 -1
  80. package/build/lib/helpers/build.js +2 -4
  81. package/build/lib/helpers/build.js.map +1 -1
  82. package/build/lib/helpers/capability.d.ts.map +1 -1
  83. package/build/lib/helpers/capability.js +27 -22
  84. package/build/lib/helpers/capability.js.map +1 -1
  85. package/build/lib/helpers/network.d.ts.map +1 -1
  86. package/build/lib/helpers/network.js +4 -3
  87. package/build/lib/helpers/network.js.map +1 -1
  88. package/build/lib/insecure-features.d.ts.map +1 -1
  89. package/build/lib/insecure-features.js +9 -13
  90. package/build/lib/insecure-features.js.map +1 -1
  91. package/build/lib/inspector-commands.d.ts.map +1 -1
  92. package/build/lib/inspector-commands.js +29 -28
  93. package/build/lib/inspector-commands.js.map +1 -1
  94. package/build/lib/logsink.d.ts.map +1 -1
  95. package/build/lib/logsink.js +8 -7
  96. package/build/lib/logsink.js.map +1 -1
  97. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  98. package/build/lib/schema/arg-spec.js +5 -8
  99. package/build/lib/schema/arg-spec.js.map +1 -1
  100. package/build/lib/schema/cli-args.d.ts.map +1 -1
  101. package/build/lib/schema/cli-args.js +20 -19
  102. package/build/lib/schema/cli-args.js.map +1 -1
  103. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  104. package/build/lib/schema/cli-transformers.js.map +1 -1
  105. package/build/lib/schema/schema.d.ts.map +1 -1
  106. package/build/lib/schema/schema.js +28 -21
  107. package/build/lib/schema/schema.js.map +1 -1
  108. package/build/lib/utils/hash.d.ts +5 -0
  109. package/build/lib/utils/hash.d.ts.map +1 -0
  110. package/build/lib/{utils.js → utils/hash.js} +3 -21
  111. package/build/lib/utils/hash.js.map +1 -0
  112. package/build/lib/utils/index.d.ts +8 -0
  113. package/build/lib/utils/index.d.ts.map +1 -0
  114. package/build/lib/utils/index.js +31 -0
  115. package/build/lib/utils/index.js.map +1 -0
  116. package/build/lib/utils/is-package-changed.d.ts +16 -0
  117. package/build/lib/utils/is-package-changed.d.ts.map +1 -0
  118. package/build/lib/utils/is-package-changed.js +62 -0
  119. package/build/lib/utils/is-package-changed.js.map +1 -0
  120. package/build/lib/utils/object.d.ts +120 -0
  121. package/build/lib/utils/object.d.ts.map +1 -0
  122. package/build/lib/utils/object.js +288 -0
  123. package/build/lib/utils/object.js.map +1 -0
  124. package/build/lib/{extension → utils}/package-changed.d.ts +0 -1
  125. package/build/lib/utils/package-changed.d.ts.map +1 -0
  126. package/build/lib/{extension → utils}/package-changed.js +3 -4
  127. package/build/lib/utils/package-changed.js.map +1 -0
  128. package/build/lib/utils/package-json.d.ts +9 -0
  129. package/build/lib/utils/package-json.d.ts.map +1 -0
  130. package/build/lib/utils/package-json.js +32 -0
  131. package/build/lib/utils/package-json.js.map +1 -0
  132. package/build/lib/utils/resolve-from.d.ts +11 -0
  133. package/build/lib/utils/resolve-from.d.ts.map +1 -0
  134. package/build/lib/utils/resolve-from.js +41 -0
  135. package/build/lib/utils/resolve-from.js.map +1 -0
  136. package/build/types/cli.d.ts.map +1 -1
  137. package/build/types/index.d.ts.map +1 -1
  138. package/build/types/manifest/base.d.ts.map +1 -1
  139. package/build/types/manifest/v3.d.ts.map +1 -1
  140. package/build/types/manifest/v4.d.ts.map +1 -1
  141. package/lib/appium.ts +59 -55
  142. package/lib/bidi-commands.ts +106 -60
  143. package/lib/bootstrap/appium-initializer.ts +27 -19
  144. package/lib/bootstrap/appium-main-runner.ts +8 -4
  145. package/lib/bootstrap/config-file.ts +33 -16
  146. package/lib/bootstrap/grid-v3-register.ts +26 -19
  147. package/lib/bootstrap/main-helpers.ts +25 -19
  148. package/lib/bootstrap/node-helpers.ts +19 -22
  149. package/lib/bootstrap/startup-config.ts +42 -39
  150. package/lib/cli/args.ts +3 -4
  151. package/lib/cli/driver-command.ts +19 -13
  152. package/lib/cli/extension-command.ts +208 -143
  153. package/lib/cli/extension.ts +4 -6
  154. package/lib/cli/parser.ts +32 -30
  155. package/lib/cli/plugin-command.ts +20 -9
  156. package/lib/cli/setup-command.ts +54 -39
  157. package/lib/cli/utils.ts +4 -3
  158. package/lib/doctor/doctor.ts +15 -17
  159. package/lib/extension/driver-config.ts +22 -17
  160. package/lib/extension/extension-config.ts +74 -66
  161. package/lib/extension/index.ts +42 -25
  162. package/lib/extension/manifest.ts +34 -31
  163. package/lib/extension/plugin-config.ts +15 -10
  164. package/lib/helpers/build.ts +6 -5
  165. package/lib/helpers/capability.ts +40 -35
  166. package/lib/helpers/network.ts +6 -5
  167. package/lib/insecure-features.ts +16 -14
  168. package/lib/inspector-commands.ts +72 -40
  169. package/lib/logsink.ts +22 -26
  170. package/lib/schema/arg-spec.ts +9 -8
  171. package/lib/schema/cli-args-guards.ts +4 -4
  172. package/lib/schema/cli-args.ts +25 -21
  173. package/lib/schema/cli-transformers.ts +6 -2
  174. package/lib/schema/format-errors.ts +1 -1
  175. package/lib/schema/schema.ts +52 -38
  176. package/lib/{utils.ts → utils/hash.ts} +2 -19
  177. package/lib/utils/index.ts +23 -0
  178. package/lib/utils/is-package-changed.ts +78 -0
  179. package/lib/utils/object.ts +312 -0
  180. package/lib/{extension → utils}/package-changed.ts +6 -7
  181. package/lib/utils/package-json.ts +36 -0
  182. package/lib/utils/resolve-from.ts +40 -0
  183. package/package.json +13 -16
  184. package/scripts/autoinstall-extensions.js +8 -8
  185. package/tsconfig.json +8 -2
  186. package/types/cli.ts +18 -18
  187. package/types/index.ts +2 -2
  188. package/types/manifest/base.ts +2 -2
  189. package/types/manifest/v3.ts +2 -2
  190. package/types/manifest/v4.ts +2 -2
  191. package/build/lib/extension/package-changed.d.ts.map +0 -1
  192. package/build/lib/extension/package-changed.js.map +0 -1
  193. package/build/lib/utils.d.ts +0 -13
  194. package/build/lib/utils.d.ts.map +0 -1
  195. package/build/lib/utils.js.map +0 -1
@@ -1,12 +1,17 @@
1
- import {env, fs} from '@appium/support';
2
- import _ from 'lodash';
1
+ import {env, fs, util} from '@appium/support';
3
2
  import path from 'node:path';
4
3
  import * as YAML from 'yaml';
5
4
  import type {DriverType, ExtensionType, PluginType} from '@appium/types';
6
- 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';
7
12
  import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
8
13
  import {INSTALL_TYPE_DEV, INSTALL_TYPE_NPM} from './extension-config';
9
- import {packageDidChange} from './package-changed';
14
+ import {packageDidChange} from '../utils';
10
15
  import {migrate} from './manifest-migrations';
11
16
 
12
17
  const CONFIG_DATA_DRIVER_KEY = `${DRIVER_TYPE}s` as const;
@@ -29,7 +34,7 @@ export class Manifest {
29
34
  *
30
35
  * @param appiumHome - `APPIUM_HOME` path used as the cache key
31
36
  */
32
- static getInstance = _.memoize((appiumHome: string): Manifest => new Manifest(appiumHome));
37
+ static getInstance = util.memoize((appiumHome: string): Manifest => new Manifest(appiumHome));
33
38
 
34
39
  #data!: ManifestData;
35
40
  readonly #appiumHome: string;
@@ -39,7 +44,7 @@ export class Manifest {
39
44
 
40
45
  private constructor(appiumHome: string) {
41
46
  this.#appiumHome = appiumHome;
42
- this.#data = _.cloneDeep(INITIAL_MANIFEST_DATA) as ManifestData;
47
+ this.#data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
43
48
  }
44
49
 
45
50
  /** `APPIUM_HOME` directory this manifest is tied to. */
@@ -110,7 +115,7 @@ export class Manifest {
110
115
  data = YAML.parse(yaml) as ManifestData;
111
116
  } catch (err: any) {
112
117
  if (err.code === 'ENOENT') {
113
- data = _.cloneDeep(INITIAL_MANIFEST_DATA) as ManifestData;
118
+ data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
114
119
  shouldWrite = true;
115
120
  } else {
116
121
  throw new Error(
@@ -118,7 +123,7 @@ export class Manifest {
118
123
  `cache file (${manifestPathResolved}). It may be invalid YAML. Specific error: ${
119
124
  err.message
120
125
  }`,
121
- {cause: err}
126
+ {cause: err},
122
127
  );
123
128
  }
124
129
  }
@@ -165,9 +170,9 @@ export class Manifest {
165
170
  } catch (err: any) {
166
171
  throw new Error(
167
172
  `Appium could not create the directory for the manifest file: ${path.dirname(
168
- manifestPathResolved
173
+ manifestPathResolved,
169
174
  )}. Original error: ${err.message}`,
170
- {cause: err}
175
+ {cause: err},
171
176
  );
172
177
  }
173
178
  try {
@@ -178,7 +183,7 @@ export class Manifest {
178
183
  `Appium could not write to manifest at ${manifestPathResolved} using APPIUM_HOME ${
179
184
  this.#appiumHome
180
185
  }. Please ensure it is writable. Original error: ${err.message}`,
181
- {cause: err}
186
+ {cause: err},
182
187
  );
183
188
  }
184
189
  })();
@@ -211,9 +216,7 @@ export class Manifest {
211
216
  }
212
217
  };
213
218
 
214
- const queue: Promise<void>[] = [
215
- onMatch(path.join(this.#appiumHome, 'package.json'), true),
216
- ];
219
+ const queue: Promise<void>[] = [onMatch(path.join(this.#appiumHome, 'package.json'), true)];
217
220
 
218
221
  const filepaths = await fs.glob('node_modules/{*,@*/*}/package.json', {
219
222
  cwd: this.#appiumHome,
@@ -240,7 +243,7 @@ export class Manifest {
240
243
  addExtensionFromPackage(
241
244
  pkgJson: ExtPackageJson<ExtensionType>,
242
245
  pkgPath: string,
243
- 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,
244
247
  ): boolean {
245
248
  const extensionPath = path.dirname(pkgPath);
246
249
 
@@ -254,31 +257,31 @@ export class Manifest {
254
257
  };
255
258
 
256
259
  if (isDriver(pkgJson)) {
257
- const driverName = pkgJson.appium.driverName;
260
+ const {driverName, ...appiumDriverMeta} = pkgJson.appium;
258
261
  const value = {
259
- ..._.omit(pkgJson.appium, 'driverName'),
262
+ ...appiumDriverMeta,
260
263
  ...internal,
261
264
  };
262
- if (!_.isEqual(value, this.#data.drivers[driverName])) {
265
+ if (!util.isEqual(value, this.#data.drivers[driverName])) {
263
266
  this.setExtension(DRIVER_TYPE, driverName, value);
264
267
  return true;
265
268
  }
266
269
  return false;
267
270
  }
268
271
  if (isPlugin(pkgJson)) {
269
- const pluginName = pkgJson.appium.pluginName;
272
+ const {pluginName, ...appiumPluginMeta} = pkgJson.appium;
270
273
  const value = {
271
- ..._.omit(pkgJson.appium, 'pluginName'),
274
+ ...appiumPluginMeta,
272
275
  ...internal,
273
276
  };
274
- if (!_.isEqual(value, this.#data.plugins[pluginName])) {
277
+ if (!util.isEqual(value, this.#data.plugins[pluginName])) {
275
278
  this.setExtension(PLUGIN_TYPE, pluginName, value);
276
279
  return true;
277
280
  }
278
281
  return false;
279
282
  }
280
283
  throw new TypeError(
281
- `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}.`,
282
285
  );
283
286
  }
284
287
 
@@ -293,9 +296,9 @@ export class Manifest {
293
296
  setExtension<ExtType extends ExtensionType>(
294
297
  extType: ExtType,
295
298
  extName: string,
296
- extData: ExtManifest<ExtType>
299
+ extData: ExtManifest<ExtType>,
297
300
  ): ExtManifest<ExtType> {
298
- const data = _.cloneDeep(extData) as ExtManifest<ExtType>;
301
+ const data = structuredClone(extData) as ExtManifest<ExtType>;
299
302
  if (extType === DRIVER_TYPE) {
300
303
  this.#data.drivers[extName] = data as unknown as ExtManifest<DriverType>;
301
304
  } else {
@@ -336,7 +339,7 @@ export class Manifest {
336
339
  throw new Error(
337
340
  `Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${
338
341
  this.appiumHome
339
- }, manifest file: ${resolved}`
342
+ }, manifest file: ${resolved}`,
340
343
  );
341
344
  }
342
345
  }
@@ -347,10 +350,10 @@ export class Manifest {
347
350
 
348
351
  function isExtension(value: unknown): value is ExtPackageJson<ExtensionType> {
349
352
  return (
350
- _.isPlainObject(value) &&
351
- _.isPlainObject((value as {appium?: unknown}).appium) &&
352
- _.isString((value as {name?: unknown}).name) &&
353
- _.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'
354
357
  );
355
358
  }
356
359
 
@@ -358,7 +361,7 @@ function isDriver(value: unknown): value is ExtPackageJson<DriverType> {
358
361
  return (
359
362
  isExtension(value) &&
360
363
  'driverName' in value.appium &&
361
- _.isString((value.appium as {driverName?: unknown}).driverName)
364
+ typeof (value.appium as {driverName?: unknown}).driverName === 'string'
362
365
  );
363
366
  }
364
367
 
@@ -366,6 +369,6 @@ function isPlugin(value: unknown): value is ExtPackageJson<PluginType> {
366
369
  return (
367
370
  isExtension(value) &&
368
371
  'pluginName' in value.appium &&
369
- _.isString((value.appium as {pluginName?: unknown}).pluginName)
372
+ typeof (value.appium as {pluginName?: unknown}).pluginName === 'string'
370
373
  );
371
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);