appium 3.5.0 → 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 (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
@@ -2,10 +2,9 @@ import type {ExtensionType} from '@appium/types';
2
2
  import type {ExtClass, ExtManifest, ExtName, ExtRecord, InstallType} from 'appium/types';
3
3
  import type {SchemaObject} from 'ajv';
4
4
  import {util, fs, system} from '@appium/support';
5
- import _ from 'lodash';
6
5
  import path from 'node:path';
6
+ import {capitalize, resolveFrom} from '../utils';
7
7
  import {pathToFileURL} from 'node:url';
8
- import resolveFrom from 'resolve-from';
9
8
  import {satisfies} from 'semver';
10
9
  import {commandClasses} from '../cli/extension';
11
10
  import type {
@@ -100,26 +99,29 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
100
99
  * @param extManifest - Parsed extension metadata
101
100
  */
102
101
  static extDataHasSchema<E extends ExtensionType>(
103
- extManifest: ExtManifest<E>
102
+ extManifest: ExtManifest<E>,
104
103
  ): extManifest is ExtManifestWithSchema<E> {
105
- return _.isString(extManifest?.schema) || _.isObject(extManifest?.schema);
104
+ return (
105
+ typeof extManifest?.schema === 'string' ||
106
+ (extManifest?.schema !== null && typeof extManifest?.schema === 'object')
107
+ );
106
108
  }
107
109
 
108
110
  private static async _readExtensionSchema<E extends ExtensionType>(
109
111
  appiumHome: string,
110
112
  extType: E,
111
113
  extName: string,
112
- extManifest: ExtManifestWithSchema<E>
114
+ extManifest: ExtManifestWithSchema<E>,
113
115
  ): Promise<SchemaObject | undefined> {
114
116
  const {pkgName, schema: argSchemaPath} = extManifest;
115
117
  if (!argSchemaPath) {
116
118
  throw new TypeError(
117
- `No \`schema\` property found in config for ${extType} ${pkgName} -- why is this function being called?`
119
+ `No \`schema\` property found in config for ${extType} ${pkgName} -- why is this function being called?`,
118
120
  );
119
121
  }
120
122
  let moduleObject: any;
121
- if (_.isString(argSchemaPath)) {
122
- const schemaPath = resolveFrom(appiumHome, path.join(pkgName, argSchemaPath));
123
+ if (typeof argSchemaPath === 'string') {
124
+ const schemaPath = await resolveFrom(appiumHome, path.join(pkgName, argSchemaPath));
123
125
  moduleObject = require(schemaPath);
124
126
  } else {
125
127
  moduleObject = argSchemaPath;
@@ -136,7 +138,10 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
136
138
  * @param extName - Extension key as stored in the manifest
137
139
  * @param extManifest - Manifest entry for that extension
138
140
  */
139
- async getProblems(extName: string, extManifest: ExtManifest<ExtType>): Promise<ExtManifestProblem[]> {
141
+ async getProblems(
142
+ extName: string,
143
+ extManifest: ExtManifest<ExtType>,
144
+ ): Promise<ExtManifestProblem[]> {
140
145
  return [
141
146
  ...this.getGenericConfigProblems(extManifest, extName),
142
147
  ...this.getConfigProblems(extManifest, extName),
@@ -168,32 +173,32 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
168
173
  */
169
174
  getValidationResultSummaries(
170
175
  errorMap: Map<string, ExtManifestProblem[]> = new Map(),
171
- warningMap: Map<string, string[]> = new Map()
176
+ warningMap: Map<string, string[]> = new Map(),
172
177
  ): {errorSummaries: string[]; warningSummaries: string[]} {
173
178
  const errorSummaries: string[] = [];
174
179
  for (const [extName, problems] of errorMap.entries()) {
175
- if (_.isEmpty(problems)) {
180
+ if (util.isEmpty(problems)) {
176
181
  continue;
177
182
  }
178
183
  // remove this extension from the list since it's not valid
179
184
  errorSummaries.push(
180
185
  `${this.extensionType} "${extName}" had ${util.pluralize(
181
186
  'error',
182
- problems.length
183
- )} and will not be available:`
187
+ problems.length,
188
+ )} and will not be available:`,
184
189
  );
185
190
  for (const problem of problems) {
186
191
  errorSummaries.push(
187
- ` - ${problem.err} (Actual value: ` + `${JSON.stringify(problem.val)})`
192
+ ` - ${problem.err} (Actual value: ` + `${JSON.stringify(problem.val)})`,
188
193
  );
189
194
  }
190
195
  }
191
196
  const warningSummaries: string[] = [];
192
197
  for (const [extName, warnings] of warningMap.entries()) {
193
- if (_.isEmpty(warnings)) {
198
+ if (util.isEmpty(warnings)) {
194
199
  continue;
195
200
  }
196
- const extTypeText = _.capitalize(this.extensionType);
201
+ const extTypeText = capitalize(this.extensionType);
197
202
  const problemEnumerationText = util.pluralize('potential problem', warnings.length, true);
198
203
  warningSummaries.push(`${extTypeText} "${extName}" has ${problemEnumerationText}: `);
199
204
  for (const warning of warnings) {
@@ -215,7 +220,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
215
220
  async addExtension(
216
221
  extName: string,
217
222
  extManifest: ExtManifest<ExtType>,
218
- {write = true}: ExtensionConfigMutationOpts = {}
223
+ {write = true}: ExtensionConfigMutationOpts = {},
219
224
  ): Promise<void> {
220
225
  this.manifest.setExtension(this.extensionType, extName, extManifest);
221
226
  if (write) {
@@ -234,7 +239,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
234
239
  async updateExtension(
235
240
  extName: ExtName<ExtType>,
236
241
  extManifest: ExtManifest<ExtType>,
237
- {write = true}: ExtensionConfigMutationOpts = {}
242
+ {write = true}: ExtensionConfigMutationOpts = {},
238
243
  ): Promise<void> {
239
244
  const existing = this.installedExtensions[extName];
240
245
  this.manifest.setExtension(this.extensionType, extName as string, {
@@ -255,7 +260,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
255
260
  */
256
261
  async removeExtension(
257
262
  extName: ExtName<ExtType>,
258
- {write = true}: ExtensionConfigMutationOpts = {}
263
+ {write = true}: ExtensionConfigMutationOpts = {},
259
264
  ): Promise<void> {
260
265
  this.manifest.deleteExtension(this.extensionType, extName);
261
266
  if (write) {
@@ -268,16 +273,16 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
268
273
  */
269
274
  print(_activeNames?: ExtName<ExtType>[]): void {
270
275
  void _activeNames;
271
- if (_.isEmpty(this.installedExtensions)) {
276
+ if (util.isEmpty(this.installedExtensions)) {
272
277
  log.info(
273
278
  `No ${this.extensionType}s have been installed in ${this.appiumHome}. Use the "appium ${this.extensionType}" ` +
274
- 'command to install the one(s) you want to use.'
279
+ 'command to install the one(s) you want to use.',
275
280
  );
276
281
  return;
277
282
  }
278
283
 
279
284
  log.info(`Available ${this.extensionType}s:`);
280
- for (const [extName, extManifest] of _.toPairs(this.installedExtensions) as Array<
285
+ for (const [extName, extManifest] of Object.entries(this.installedExtensions) as Array<
281
286
  [string, ExtManifest<ExtType>]
282
287
  >) {
283
288
  log.info(` - ${this.extensionDesc(extName, extManifest)}`);
@@ -310,7 +315,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
310
315
  const MainClass = mod[mainClass];
311
316
  if (!MainClass) {
312
317
  throw new ReferenceError(
313
- `Could not find a class named "${mainClass}" exported by ${this.extensionType} "${extName}"`
318
+ `Could not find a class named "${mainClass}" exported by ${this.extensionType} "${extName}"`,
314
319
  );
315
320
  }
316
321
  return MainClass;
@@ -329,20 +334,20 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
329
334
  */
330
335
  async readExtensionSchema(
331
336
  extName: string,
332
- extManifest: ExtManifestWithSchema<ExtType>
337
+ extManifest: ExtManifestWithSchema<ExtType>,
333
338
  ): Promise<SchemaObject | undefined> {
334
339
  return await ExtensionConfig._readExtensionSchema(
335
340
  this.appiumHome,
336
341
  this.extensionType,
337
342
  extName,
338
- extManifest
343
+ extManifest,
339
344
  );
340
345
  }
341
346
 
342
347
  /** Optional async warnings for this extension kind; override in subclasses when needed. */
343
348
  protected async getConfigWarnings(
344
349
  _extManifest: ExtManifest<ExtType>,
345
- _extName: string
350
+ _extName: string,
346
351
  ): Promise<string[]> {
347
352
  void _extManifest;
348
353
  void _extName;
@@ -357,7 +362,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
357
362
  const errorMap = new Map<string, ExtManifestProblem[]>();
358
363
  const warningMap = new Map<string, string[]>();
359
364
 
360
- for (const [extName, extManifest] of _.toPairs(exts)) {
365
+ for (const [extName, extManifest] of Object.entries(exts)) {
361
366
  const [errors, warnings] = await Promise.all([
362
367
  this.getProblems(extName, extManifest),
363
368
  this.getWarnings(extName, extManifest),
@@ -371,26 +376,26 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
371
376
 
372
377
  const {errorSummaries, warningSummaries} = this.getValidationResultSummaries(
373
378
  errorMap,
374
- warningMap
379
+ warningMap,
375
380
  );
376
381
 
377
- if (!_.isEmpty(errorSummaries)) {
382
+ if (!util.isEmpty(errorSummaries)) {
378
383
  log.error(
379
384
  `Appium encountered ${util.pluralize('error', errorMap.size, true)} while validating ${
380
385
  this.extensionType
381
- }s found in manifest ${this.manifestPath}`
386
+ }s found in manifest ${this.manifestPath}`,
382
387
  );
383
388
  for (const summary of errorSummaries) {
384
389
  log.error(summary);
385
390
  }
386
- } else if (!_.isEmpty(warningSummaries)) {
391
+ } else if (!util.isEmpty(warningSummaries)) {
387
392
  // only display warnings if there are no errors!
388
393
  log.warn(
389
394
  `Appium encountered ${util.pluralize(
390
395
  'warning',
391
396
  warningMap.size,
392
- true
393
- )} while validating ${this.extensionType}s found in manifest ${this.manifestPath}`
397
+ true,
398
+ )} while validating ${this.extensionType}s found in manifest ${this.manifestPath}`,
394
399
  );
395
400
  for (const summary of warningSummaries) {
396
401
  log.warn(summary);
@@ -418,13 +423,13 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
418
423
  */
419
424
  protected async getGenericConfigWarnings(
420
425
  extManifest: ExtManifest<ExtType>,
421
- extName: string
426
+ extName: string,
422
427
  ): Promise<string[]> {
423
428
  const {appiumVersion, installSpec, installType, pkgName} = extManifest;
424
429
  const warnings: string[] = [];
425
430
 
426
431
  const invalidFields: string[] = [];
427
- if (!_.isString(installSpec)) {
432
+ if (typeof installSpec !== 'string') {
428
433
  invalidFields.push('installSpec');
429
434
  }
430
435
 
@@ -432,27 +437,27 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
432
437
  invalidFields.push('installType');
433
438
  }
434
439
 
435
- const extTypeText = _.capitalize(this.extensionType);
440
+ const extTypeText = capitalize(this.extensionType);
436
441
 
437
442
  if (invalidFields.length) {
438
443
  const invalidFieldsEnumerationText = util.pluralize(
439
444
  'invalid or missing field',
440
445
  invalidFields.length,
441
- true
446
+ true,
442
447
  );
443
448
  const invalidFieldsText = invalidFields.map((field) => `"${field}"`).join(', ');
444
449
 
445
450
  warnings.push(
446
451
  `${extTypeText} "${extName}" (package \`${pkgName}\`) has ${invalidFieldsEnumerationText} (${invalidFieldsText}) in \`extensions.yaml\`; ` +
447
- `this may cause upgrades done via the \`appium\` CLI tool to fail. Please reinstall with \`appium ${this.extensionType} uninstall ` +
448
- `${extName}\` and \`appium ${this.extensionType} install ${extName}\` to attempt a fix.`
452
+ `this may cause upgrades done via the \`appium\` CLI tool to fail. Please reinstall with \`appium ${this.extensionType} uninstall ` +
453
+ `${extName}\` and \`appium ${this.extensionType} install ${extName}\` to attempt a fix.`,
449
454
  );
450
455
  }
451
456
 
452
457
  const createPeerWarning = (reason: string): string =>
453
458
  `${extTypeText} "${extName}" (package \`${pkgName}\`) may be incompatible with the current version of Appium (v${APPIUM_VER}) due to ${reason}`;
454
459
 
455
- if (_.isString(appiumVersion) && !satisfies(APPIUM_VER, appiumVersion)) {
460
+ if (typeof appiumVersion === 'string' && !satisfies(APPIUM_VER, appiumVersion)) {
456
461
  const listData = await this.getListData();
457
462
  const extListData = listData[extName] as ExtensionListData<ExtType> | undefined;
458
463
  if (extListData?.installed) {
@@ -460,33 +465,33 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
460
465
  if (!upToDate && updateVersion) {
461
466
  warnings.push(
462
467
  createPeerWarning(
463
- `its peer dependency on Appium ${appiumVersion}. Try to upgrade \`${pkgName}\` to v${updateVersion} or newer.`
464
- )
468
+ `its peer dependency on Appium ${appiumVersion}. Try to upgrade \`${pkgName}\` to v${updateVersion} or newer.`,
469
+ ),
465
470
  );
466
471
  } else {
467
472
  warnings.push(
468
473
  createPeerWarning(
469
- `its peer dependency on Appium ${appiumVersion}. Please install a compatible version of the ${_.toLower(extTypeText)}.`
470
- )
474
+ `its peer dependency on Appium ${appiumVersion}. Please install a compatible version of the ${extTypeText.toLowerCase()}.`,
475
+ ),
471
476
  );
472
477
  }
473
478
  }
474
- } else if (!_.isString(appiumVersion)) {
479
+ } else if (typeof appiumVersion !== 'string') {
475
480
  const listData = await this.getListData();
476
481
  const extListData = listData[extName] as InstalledExtensionListData<ExtType> | undefined;
477
482
  if (!extListData?.upToDate && extListData?.updateVersion) {
478
483
  warnings.push(
479
484
  createPeerWarning(
480
485
  `an invalid or missing peer dependency on Appium. A newer version of \`${pkgName}\` is available; ` +
481
- `please attempt to upgrade "${extName}" to v${extListData.updateVersion} or newer.`
482
- )
486
+ `please attempt to upgrade "${extName}" to v${extListData.updateVersion} or newer.`,
487
+ ),
483
488
  );
484
489
  } else {
485
490
  warnings.push(
486
491
  createPeerWarning(
487
492
  `an invalid or missing peer dependency on Appium. ` +
488
- `Please ask the developer of \`${pkgName}\` to add a peer dependency on \`^appium@${APPIUM_VER}\`.`
489
- )
493
+ `Please ask the developer of \`${pkgName}\` to add a peer dependency on \`^appium@${APPIUM_VER}\`.`,
494
+ ),
490
495
  );
491
496
  }
492
497
  }
@@ -496,12 +501,12 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
496
501
  /** Validates and registers extension CLI/config schema when the manifest defines a `schema` field. */
497
502
  protected async getSchemaProblems(
498
503
  extManifest: ExtManifest<ExtType>,
499
- extName: string
504
+ extName: string,
500
505
  ): Promise<ExtManifestProblem[]> {
501
506
  const problems: ExtManifestProblem[] = [];
502
507
  const {schema: argSchemaPath} = extManifest;
503
508
  if (ExtensionConfig.extDataHasSchema(extManifest)) {
504
- if (_.isString(argSchemaPath)) {
509
+ if (typeof argSchemaPath === 'string') {
505
510
  if (isAllowedSchemaFileExtension(argSchemaPath)) {
506
511
  try {
507
512
  await this.readExtensionSchema(extName, extManifest);
@@ -519,7 +524,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
519
524
  val: argSchemaPath,
520
525
  });
521
526
  }
522
- } else if (_.isPlainObject(argSchemaPath)) {
527
+ } else if (util.isPlainObject(argSchemaPath)) {
523
528
  try {
524
529
  await this.readExtensionSchema(extName, extManifest);
525
530
  } catch (err: any) {
@@ -541,27 +546,27 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
541
546
  /** Blocking issues for required manifest fields shared by all extensions (version, package name, main class). */
542
547
  protected getGenericConfigProblems(
543
548
  extManifest: ExtManifest<ExtType>,
544
- extName: string
549
+ extName: string,
545
550
  ): ExtManifestProblem[] {
546
551
  void extName;
547
552
  const {version, pkgName, mainClass} = extManifest;
548
553
  const problems: ExtManifestProblem[] = [];
549
554
 
550
- if (!_.isString(version)) {
555
+ if (typeof version !== 'string') {
551
556
  problems.push({
552
557
  err: `Invalid or missing \`version\` field in my \`package.json\` and/or \`extensions.yaml\` (must be a string)`,
553
558
  val: version,
554
559
  });
555
560
  }
556
561
 
557
- if (!_.isString(pkgName)) {
562
+ if (typeof pkgName !== 'string') {
558
563
  problems.push({
559
564
  err: `Invalid or missing \`name\` field in my \`package.json\` and/or \`extensions.yaml\` (must be a string)`,
560
565
  val: pkgName,
561
566
  });
562
567
  }
563
568
 
564
- if (!_.isString(mainClass)) {
569
+ if (typeof mainClass !== 'string') {
565
570
  problems.push({
566
571
  err: `Invalid or missing \`appium.mainClass\` field in my \`package.json\` and/or \`mainClass\` field in \`extensions.yaml\` (must be a string)`,
567
572
  val: mainClass,
@@ -574,7 +579,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
574
579
  /** Driver- or plugin-specific blocking validation; override in subclasses when needed. */
575
580
  protected getConfigProblems(
576
581
  _extManifest: ExtManifest<ExtType>,
577
- _extName: string
582
+ _extName: string,
578
583
  ): ExtManifestProblem[] {
579
584
  void _extManifest;
580
585
  void _extName;
@@ -591,7 +596,7 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
591
596
  } catch (e: any) {
592
597
  throw new ReferenceError(
593
598
  `Could not read the ${this.extensionType} manifest at ${packageJsonPath}: ${e.message}`,
594
- {cause: e}
599
+ {cause: e},
595
600
  );
596
601
  }
597
602
  let entryPointRelativePath: string | undefined;
@@ -599,18 +604,19 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
599
604
  if (extensionManifest.type === 'module' && extensionManifest.exports) {
600
605
  entryPointRelativePath = resolveEsmEntryPoint(extensionManifest.exports);
601
606
  }
602
- entryPointRelativePath = entryPointRelativePath ?? extensionManifest.main ?? DEFAULT_ENTRY_POINT;
607
+ entryPointRelativePath =
608
+ entryPointRelativePath ?? extensionManifest.main ?? DEFAULT_ENTRY_POINT;
603
609
  } catch (e: any) {
604
610
  throw new ReferenceError(
605
611
  `Could not find the ${this.extensionType} installed at ${moduleRoot}: ${e.message}`,
606
- {cause: e}
612
+ {cause: e},
607
613
  );
608
614
  }
609
615
  const entryPointFullPath = path.resolve(moduleRoot, entryPointRelativePath as string);
610
- if (!await fs.exists(entryPointFullPath)) {
616
+ if (!(await fs.exists(entryPointFullPath))) {
611
617
  throw new ReferenceError(
612
618
  `Cannot find a valid ${this.extensionType} main entry point in '${packageJsonPath}'. ` +
613
- `Assumed entry point: '${entryPointFullPath}'`
619
+ `Assumed entry point: '${entryPointFullPath}'`,
614
620
  );
615
621
  }
616
622
  // note: this will only reload the entry point
@@ -627,8 +633,10 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
627
633
  * @param extName - Manifest key
628
634
  * @param extManifest - Entry used for version and kind-specific labels
629
635
  */
630
- public abstract extensionDesc(extName: ExtName<ExtType>, extManifest: ExtManifest<ExtType>): string;
631
-
636
+ public abstract extensionDesc(
637
+ extName: ExtName<ExtType>,
638
+ extManifest: ExtManifest<ExtType>,
639
+ ): string;
632
640
  }
633
641
 
634
642
  /**
@@ -637,10 +645,10 @@ export abstract class ExtensionConfig<ExtType extends ExtensionType> {
637
645
  * @param exportsValue - `package.json` `exports` value or nested fragment
638
646
  */
639
647
  export function resolveEsmEntryPoint(exportsValue: unknown): string | undefined {
640
- if (_.isString(exportsValue) && exportsValue) {
648
+ if (typeof exportsValue === 'string' && exportsValue) {
641
649
  return exportsValue;
642
650
  }
643
- if (!_.isPlainObject(exportsValue)) {
651
+ if (!util.isPlainObject(exportsValue)) {
644
652
  return;
645
653
  }
646
654
 
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {util, timing} from '@appium/support';
2
2
  import {asyncmap} from 'asyncbox';
3
3
  import type {DriverClass, ExtensionType, PluginClass} from '@appium/types';
4
4
  import type {ExtClass} from 'appium/types';
@@ -6,7 +6,7 @@ import {USE_ALL_PLUGINS} from '../constants';
6
6
  import {log} from '../logger';
7
7
  import {DriverConfig} from './driver-config';
8
8
  import {Manifest} from './manifest';
9
- import {timing} from '@appium/support';
9
+ import {zip} from '../utils';
10
10
  import {PluginConfig} from './plugin-config';
11
11
 
12
12
  export type ExtensionConfigs = {
@@ -45,31 +45,40 @@ export async function loadExtensions(appiumHome: string): Promise<ExtensionConfi
45
45
  export async function getActivePlugins(
46
46
  pluginConfig: PluginConfig,
47
47
  maxParallelImports: number,
48
- usePlugins: string[] = []
48
+ usePlugins: string[] = [],
49
49
  ): Promise<PluginNameMap> {
50
- if (_.isEmpty(usePlugins)) {
50
+ if (util.isEmpty(usePlugins)) {
51
51
  return new Map();
52
52
  }
53
53
 
54
54
  let filteredPluginNames: string[] = [];
55
55
  if (usePlugins.length === 1 && usePlugins[0] === USE_ALL_PLUGINS) {
56
- filteredPluginNames = _.keys(pluginConfig.installedExtensions);
56
+ filteredPluginNames = Object.keys(pluginConfig.installedExtensions);
57
57
  } else {
58
58
  for (const pluginName of usePlugins) {
59
59
  if (pluginName in pluginConfig.installedExtensions) {
60
60
  filteredPluginNames.push(pluginName);
61
61
  } else if (pluginName === USE_ALL_PLUGINS) {
62
- throw new Error(`The reserved plugin name '${pluginName}' cannot be combined with other names.`);
62
+ throw new Error(
63
+ `The reserved plugin name '${pluginName}' cannot be combined with other names.`,
64
+ );
63
65
  } else {
64
- const suffix = _.isEmpty(pluginConfig.installedExtensions)
66
+ const suffix = util.isEmpty(pluginConfig.installedExtensions)
65
67
  ? `You don't have any plugins installed yet.`
66
- : `Only the following ${_.size(pluginConfig.installedExtensions) === 1 ? `plugin is` : `plugins are`} ` +
67
- `available: ${_.keys(pluginConfig.installedExtensions)}`;
68
- throw new Error(`Could not load the plugin '${pluginName}' because it is not installed. ${suffix}`);
68
+ : `Only the following ${Object.keys(pluginConfig.installedExtensions).length === 1 ? `plugin is` : `plugins are`} ` +
69
+ `available: ${Object.keys(pluginConfig.installedExtensions)}`;
70
+ throw new Error(
71
+ `Could not load the plugin '${pluginName}' because it is not installed. ${suffix}`,
72
+ );
69
73
  }
70
74
  }
71
75
  }
72
- const pairs = await importExtensions('plugin', pluginConfig, filteredPluginNames, maxParallelImports);
76
+ const pairs = await importExtensions(
77
+ 'plugin',
78
+ pluginConfig,
79
+ filteredPluginNames,
80
+ maxParallelImports,
81
+ );
73
82
  return new Map(pairs as Array<[PluginClass, string]>);
74
83
  }
75
84
 
@@ -81,34 +90,40 @@ export async function getActivePlugins(
81
90
  export async function getActiveDrivers(
82
91
  driverConfig: DriverConfig,
83
92
  maxParallelImports: number,
84
- useDrivers: string[] = []
93
+ useDrivers: string[] = [],
85
94
  ): Promise<DriverNameMap> {
86
95
  let filteredDriverNames: string[] = [];
87
- if (_.isEmpty(useDrivers)) {
88
- filteredDriverNames = _.keys(driverConfig.installedExtensions);
96
+ if (util.isEmpty(useDrivers)) {
97
+ filteredDriverNames = Object.keys(driverConfig.installedExtensions);
89
98
  } else {
90
99
  for (const driverName of useDrivers) {
91
100
  if (driverName in driverConfig.installedExtensions) {
92
101
  filteredDriverNames.push(driverName);
93
102
  } else {
94
- const suffix = _.isEmpty(driverConfig.installedExtensions)
103
+ const suffix = util.isEmpty(driverConfig.installedExtensions)
95
104
  ? `You don't have any drivers installed yet.`
96
- : `Only the following ${_.size(driverConfig.installedExtensions) === 1 ? `driver is` : `drivers are`} ` +
97
- `available: ${_.keys(driverConfig.installedExtensions)}`;
98
- throw new Error(`Could not load the driver '${driverName}' because it is not installed. ${suffix}`);
105
+ : `Only the following ${Object.keys(driverConfig.installedExtensions).length === 1 ? `driver is` : `drivers are`} ` +
106
+ `available: ${Object.keys(driverConfig.installedExtensions)}`;
107
+ throw new Error(
108
+ `Could not load the driver '${driverName}' because it is not installed. ${suffix}`,
109
+ );
99
110
  }
100
111
  }
101
112
  }
102
- const pairs = await importExtensions('driver', driverConfig, filteredDriverNames, maxParallelImports);
113
+ const pairs = await importExtensions(
114
+ 'driver',
115
+ driverConfig,
116
+ filteredDriverNames,
117
+ maxParallelImports,
118
+ );
103
119
  return new Map(pairs as Array<[DriverClass, string]>);
104
120
  }
105
121
 
106
-
107
122
  async function importExtensions(
108
123
  extType: 'driver' | 'plugin',
109
124
  config: DriverConfig | PluginConfig,
110
125
  extNames: string[],
111
- asyncImportChunkSize: number
126
+ asyncImportChunkSize: number,
112
127
  ): Promise<Array<[ExtClass<ExtensionType>, string]>> {
113
128
  const extClasses = await asyncmap(
114
129
  extNames,
@@ -117,19 +132,21 @@ async function importExtensions(
117
132
  const timer = new timing.Timer().start();
118
133
  try {
119
134
  const extClass = await config.requireAsync(extName as never);
120
- log.debug(`${extClass.name} has been successfully loaded in ${timer.getDuration().asSeconds.toFixed(3)}s`);
135
+ log.debug(
136
+ `${extClass.name} has been successfully loaded in ${timer.getDuration().asSeconds.toFixed(3)}s`,
137
+ );
121
138
  return extClass as ExtClass<ExtensionType>;
122
139
  } catch (err: any) {
123
140
  log.error(
124
141
  `Could not load ${extType} '${extName}', so it will not be available. Error ` +
125
- `in loading the ${extType} was: ${err.message}`
142
+ `in loading the ${extType} was: ${err.message}`,
126
143
  );
127
144
  log.debug(err.stack);
128
145
  }
129
146
  },
130
- {concurrency: asyncImportChunkSize}
147
+ {concurrency: asyncImportChunkSize},
131
148
  );
132
- return _.zip(extClasses, extNames).filter(([extClass]) => Boolean(extClass)) as Array<
149
+ return zip(extClasses, extNames).filter(([extClass]) => Boolean(extClass)) as Array<
133
150
  [ExtClass<ExtensionType>, string]
134
151
  >;
135
152
  }