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