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
@@ -1,7 +1,6 @@
1
1
  import axios from 'axios';
2
2
  import {fs} from '@appium/support';
3
3
  import type {StringRecord} from '@appium/types';
4
- import _ from 'lodash';
5
4
  import {log as logger} from '../logger';
6
5
 
7
6
  /**
@@ -44,13 +43,13 @@ export default async function registerNode(
44
43
  data: string,
45
44
  addr: string,
46
45
  port: number,
47
- basePath: string
46
+ basePath: string,
48
47
  ): Promise<void>;
49
48
  export default async function registerNode(
50
49
  data: Grid3NodeConfig,
51
50
  addr?: string,
52
51
  port?: number,
53
- basePath?: string
52
+ basePath?: string,
54
53
  ): Promise<void>;
55
54
  /**
56
55
  * Registers this server as a node with a **Selenium Grid 3** hub.
@@ -71,24 +70,24 @@ export default async function registerNode(
71
70
  data: string | Grid3NodeConfig,
72
71
  addr?: string,
73
72
  port?: number,
74
- basePath?: string
73
+ basePath?: string,
75
74
  ): Promise<void> {
76
75
  if (typeof data === 'string') {
77
76
  if (addr === undefined || port === undefined || basePath === undefined) {
78
77
  throw logger.errorWithException(
79
78
  'When the first argument is a Selenium Grid 3 node config file path, address, port, and basePath ' +
80
- 'are required (e.g. match your Appium `--address`, `--port`, and base path).'
79
+ 'are required (e.g. match your Appium `--address`, `--port`, and base path).',
81
80
  );
82
81
  }
83
82
  if (typeof port !== 'number' || !Number.isFinite(port)) {
84
83
  throw logger.errorWithException(
85
- 'When registering from a node config file path, port must be a finite number.'
84
+ 'When registering from a node config file path, port must be a finite number.',
86
85
  );
87
86
  }
88
87
  }
89
88
 
90
89
  let configHolder: Grid3NodeConfig;
91
- if (_.isString(data)) {
90
+ if (typeof data === 'string') {
92
91
  const configFilePath = data;
93
92
  let fileContent: string;
94
93
  try {
@@ -96,7 +95,7 @@ export default async function registerNode(
96
95
  } catch (err) {
97
96
  logger.error(
98
97
  `Unable to load Selenium Grid 3 node configuration file ${configFilePath} to ` +
99
- `register with the hub: ${(err as Error).message}`
98
+ `register with the hub: ${(err as Error).message}`,
100
99
  );
101
100
  return;
102
101
  }
@@ -105,7 +104,7 @@ export default async function registerNode(
105
104
  } catch (err) {
106
105
  throw logger.errorWithException(
107
106
  `Syntax error in Selenium Grid 3 node configuration file ${configFilePath}: ` +
108
- (err as Error).message
107
+ (err as Error).message,
109
108
  );
110
109
  }
111
110
  } else {
@@ -124,7 +123,7 @@ function hubUri(config: Grid3HubConfiguration): string {
124
123
  /** POST registration payload to the Selenium Grid 3 hub. */
125
124
  async function registerToGrid(
126
125
  postOptions: {url: string; method: string; data: Grid3NodeConfig},
127
- configHolder: Grid3NodeConfig
126
+ configHolder: Grid3NodeConfig,
128
127
  ): Promise<void> {
129
128
  const hubCfg = configHolder.configuration;
130
129
  if (!hubCfg) {
@@ -136,12 +135,12 @@ async function registerToGrid(
136
135
  throw new Error(`Request failed with code ${status}`);
137
136
  }
138
137
  logger.debug(
139
- `Appium successfully registered with the Selenium Grid 3 hub at ` + hubUri(hubCfg)
138
+ `Appium successfully registered with the Selenium Grid 3 hub at ` + hubUri(hubCfg),
140
139
  );
141
140
  } catch (err) {
142
141
  logger.error(
143
142
  `An attempt to register with the Selenium Grid 3 hub was unsuccessful: ` +
144
- (err as Error).message
143
+ (err as Error).message,
145
144
  );
146
145
  }
147
146
  }
@@ -150,14 +149,18 @@ function postRequest(
150
149
  configHolder: Grid3NodeConfig,
151
150
  addr?: string,
152
151
  port?: number,
153
- basePath?: string
152
+ basePath?: string,
154
153
  ): void {
155
154
  // Move Selenium Grid 3 (flat) configuration properties into `configuration`
156
- if (!_.has(configHolder, 'configuration')) {
155
+ if (
156
+ configHolder != null &&
157
+ typeof configHolder === 'object' &&
158
+ !Object.hasOwn(configHolder, 'configuration')
159
+ ) {
157
160
  const configuration: StringRecord = {};
158
161
  const holder = configHolder as StringRecord;
159
- for (const property in holder) {
160
- if (_.has(holder, property) && property !== 'capabilities') {
162
+ for (const property of Object.keys(holder)) {
163
+ if (property !== 'capabilities') {
161
164
  configuration[property] = holder[property];
162
165
  delete holder[property];
163
166
  }
@@ -198,10 +201,14 @@ function postRequest(
198
201
  }
199
202
 
200
203
  const registerCycleInterval = cfg.registerCycle;
201
- if (registerCycleInterval === undefined || isNaN(registerCycleInterval) || registerCycleInterval <= 0) {
204
+ if (
205
+ registerCycleInterval === undefined ||
206
+ isNaN(registerCycleInterval) ||
207
+ registerCycleInterval <= 0
208
+ ) {
202
209
  logger.warn(
203
210
  `'registerCycle' is not a valid positive number. ` +
204
- `No registration request will be sent to the Selenium Grid 3 hub.`
211
+ `No registration request will be sent to the Selenium Grid 3 hub.`,
205
212
  );
206
213
  return;
207
214
  }
@@ -209,7 +216,7 @@ function postRequest(
209
216
  let first = true;
210
217
  logger.debug(
211
218
  `Starting auto-register thread for Selenium Grid 3. ` +
212
- `Will try to register every ${registerCycleInterval} ms.`
219
+ `Will try to register every ${registerCycleInterval} ms.`,
213
220
  );
214
221
  setInterval(async function registerRetry() {
215
222
  if (first) {
@@ -6,7 +6,7 @@ import {
6
6
  server as baseServer,
7
7
  type ServerOpts,
8
8
  } from '@appium/base-driver';
9
- import _ from 'lodash';
9
+ import {console as supportConsole, util} from '@appium/support';
10
10
  import type {AppiumServer, Driver, MethodMap, UpdateServerCallback} from '@appium/types';
11
11
  import {WebSocketServer} from 'ws';
12
12
  import type {NetworkInterfaceInfo} from 'node:os';
@@ -25,16 +25,15 @@ const isStdoutTTY = process.stdout.isTTY;
25
25
  /**
26
26
  * Logs a value to the console using the info logger (with util.inspect formatting).
27
27
  */
28
- export const inspect = _.flow(
29
- _.partialRight(dump as (object: unknown, options: InspectOptions) => string, {
30
- colors: true,
31
- depth: null,
32
- compact: !isStdoutTTY,
33
- }),
34
- (...args: unknown[]) => {
35
- logger.info(...args);
36
- },
37
- );
28
+ export function inspect(value: unknown): void {
29
+ logger.info(
30
+ dump(value, {
31
+ colors: true,
32
+ depth: null,
33
+ compact: !isStdoutTTY,
34
+ } satisfies InspectOptions),
35
+ );
36
+ }
38
37
 
39
38
  /**
40
39
  * Prints the current build info JSON to stdout.
@@ -52,7 +51,7 @@ export async function showBuildInfo(): Promise<void> {
52
51
  * Human-readable label for where Appium resolved `APPIUM_HOME` from (CLI, env, or autodetect).
53
52
  */
54
53
  export function determineAppiumHomeSource(appiumHomeFromArgs?: string | null): string {
55
- if (!_.isNil(appiumHomeFromArgs)) {
54
+ if (util.hasValue(appiumHomeFromArgs)) {
56
55
  return 'appiumHome config value';
57
56
  }
58
57
  if (process.env.APPIUM_HOME) {
@@ -110,7 +109,7 @@ export async function preflightChecks(
110
109
  }
111
110
  } catch (err: unknown) {
112
111
  const message = err instanceof Error ? err.message : String(err);
113
- logger.error((message as string & {red: string}).red);
112
+ logger.error(supportConsole.styleText('red', message));
114
113
  if (throwInsteadOfExit) {
115
114
  throw err;
116
115
  }
@@ -131,10 +130,10 @@ export async function logStartupInfo(args: ParsedArgs<CliCommandServer>): Promis
131
130
  logger.info(welcome);
132
131
 
133
132
  const showArgs = getNonDefaultServerArgs(args);
134
- if (_.size(showArgs)) {
133
+ if (Object.keys(showArgs).length) {
135
134
  logNonDefaultArgsWarning(showArgs);
136
135
  }
137
- if (!_.isEmpty(args.defaultCapabilities)) {
136
+ if (!util.isEmpty(args.defaultCapabilities)) {
138
137
  logDefaultCapabilitiesWarning(args.defaultCapabilities);
139
138
  }
140
139
  }
@@ -146,13 +145,18 @@ export function getServerUpdaters(
146
145
  driverClasses: DriverNameMap,
147
146
  pluginClasses: PluginNameMap,
148
147
  ): UpdateServerCallback[] {
149
- return _.compact(_.map([...driverClasses.keys(), ...pluginClasses.keys()], 'updateServer'));
148
+ return [...driverClasses.keys(), ...pluginClasses.keys()]
149
+ .map((klass) => klass.updateServer)
150
+ .filter(Boolean) as UpdateServerCallback[];
150
151
  }
151
152
 
152
153
  /**
153
154
  * Merges `newMethodMap` contributions from all active drivers and plugins into one method map.
154
155
  */
155
- export function getExtraMethodMap(driverClasses: DriverNameMap, pluginClasses: PluginNameMap): MethodMap<Driver> {
156
+ export function getExtraMethodMap(
157
+ driverClasses: DriverNameMap,
158
+ pluginClasses: PluginNameMap,
159
+ ): MethodMap<Driver> {
156
160
  return [...driverClasses.keys(), ...pluginClasses.keys()].reduce<MethodMap<Driver>>(
157
161
  (map, klass) => ({
158
162
  ...map,
@@ -184,7 +188,7 @@ export function buildServerOpts(
184
188
  };
185
189
  const normalizedBasePath = normalizeBasePath(parsedArgs.basePath);
186
190
  for (const timeoutArgName of ['keepAliveTimeout', 'requestTimeout'] as const) {
187
- if (_.isInteger(parsedArgs[timeoutArgName])) {
191
+ if (Number.isInteger(parsedArgs[timeoutArgName])) {
188
192
  serverOpts[timeoutArgName] = parsedArgs[timeoutArgName] * 1000;
189
193
  }
190
194
  }
@@ -214,7 +218,9 @@ function logNonDefaultArgsWarning(args: Args): void {
214
218
  inspect(args);
215
219
  }
216
220
 
217
- function logDefaultCapabilitiesWarning(caps: ParsedArgs<CliCommandServer>['defaultCapabilities']): void {
221
+ function logDefaultCapabilitiesWarning(
222
+ caps: ParsedArgs<CliCommandServer>['defaultCapabilities'],
223
+ ): void {
218
224
  logger.info(
219
225
  'Default capabilities, which will be added to each request ' +
220
226
  'unless overridden by desired capabilities:',
@@ -1,12 +1,10 @@
1
1
  /* eslint-disable no-console */
2
- import _ from 'lodash';
3
2
  import path from 'node:path';
4
3
  import os from 'node:os';
5
4
  import * as semver from 'semver';
6
5
  import {system, fs, npm} from '@appium/support';
7
- import {log as logger} from '../logger';
8
- import {getAppiumModuleRoot, npmPackage} from '../utils';
9
- import {rootDir, updateBuildInfo, getBuildInfo} from '../helpers/build';
6
+ import {appiumPackageRoot, npmPackage} from '../utils';
7
+ import {updateBuildInfo, getBuildInfo} from '../helpers/build';
10
8
 
11
9
  const MIN_NODE_VERSION = (npmPackage.engines as Record<string, string>).node;
12
10
 
@@ -26,7 +24,9 @@ interface DebugInfoInput {
26
24
  export function checkNodeOk(): void {
27
25
  const version = getNodeVersion();
28
26
  if (!semver.satisfies(version, MIN_NODE_VERSION)) {
29
- throw new Error(`Node version must be at least ${MIN_NODE_VERSION}; current is ${version.version}`);
27
+ throw new Error(
28
+ `Node version must be at least ${MIN_NODE_VERSION}; current is ${version.version}`,
29
+ );
30
30
  }
31
31
  }
32
32
 
@@ -34,13 +34,7 @@ export function checkNodeOk(): void {
34
34
  * Adjusts NODE_PATH so CJS drivers/plugins can load peer deps. Does not work with ESM.
35
35
  */
36
36
  export function adjustNodePath(): void {
37
- let appiumModuleSearchRoot: string;
38
- try {
39
- appiumModuleSearchRoot = path.dirname(getAppiumModuleRoot());
40
- } catch (error) {
41
- logger.warn((error as Error).message);
42
- return;
43
- }
37
+ const appiumModuleSearchRoot = path.dirname(appiumPackageRoot);
44
38
 
45
39
  const refreshRequirePaths = (): boolean => {
46
40
  try {
@@ -73,7 +67,9 @@ export function adjustNodePath(): void {
73
67
  if (refreshRequirePaths()) {
74
68
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
75
69
  } else {
76
- process.env.NODE_PATH = _.without(nodePathParts, appiumModuleSearchRoot).join(path.delimiter);
70
+ process.env.NODE_PATH = nodePathParts
71
+ .filter((p) => p !== appiumModuleSearchRoot)
72
+ .join(path.delimiter);
77
73
  }
78
74
  }
79
75
 
@@ -81,10 +77,14 @@ export function adjustNodePath(): void {
81
77
  * Prints JSON debug info (OS, Node/npm, Appium build, installed drivers/plugins) to stdout.
82
78
  * Input combines extension config snapshots with the resolved Appium home path.
83
79
  */
84
- export async function showDebugInfo({driverConfig, pluginConfig, appiumHome}: DebugInfoInput): Promise<void> {
80
+ export async function showDebugInfo({
81
+ driverConfig,
82
+ pluginConfig,
83
+ appiumHome,
84
+ }: DebugInfoInput): Promise<void> {
85
85
  const getNpmVersion = async (): Promise<string> => {
86
86
  const {stdout} = await npm.exec('--version', [], {cwd: process.cwd()});
87
- return _.trim(stdout);
87
+ return stdout.trim();
88
88
  };
89
89
  const findNpmLocation = async (): Promise<string> =>
90
90
  await fs.which(system.isWindows() ? 'npm.cmd' : 'npm');
@@ -114,7 +114,7 @@ export async function showDebugInfo({driverConfig, pluginConfig, appiumHome}: De
114
114
  },
115
115
  },
116
116
  appium: {
117
- location: rootDir,
117
+ location: appiumPackageRoot,
118
118
  homedir: appiumHome,
119
119
  build: getBuildInfo(),
120
120
  drivers: driverConfig.installedExtensions,
@@ -134,7 +134,7 @@ export async function showDebugInfo({driverConfig, pluginConfig, appiumHome}: De
134
134
  export async function requireDir(
135
135
  root: string,
136
136
  requireWriteable = true,
137
- displayName = 'folder path'
137
+ displayName = 'folder path',
138
138
  ): Promise<void> {
139
139
  let stat;
140
140
  try {
@@ -146,10 +146,7 @@ export async function requireDir(
146
146
  return;
147
147
  } catch {}
148
148
  }
149
- throw new Error(
150
- `The ${displayName} '${root}' must exist and be a valid directory`,
151
- {cause: e}
152
- );
149
+ throw new Error(`The ${displayName} '${root}' must exist and be a valid directory`, {cause: e});
153
150
  }
154
151
  if (stat && !stat.isDirectory()) {
155
152
  throw new Error(`The ${displayName} '${root}' must be a valid directory`);
@@ -160,7 +157,7 @@ export async function requireDir(
160
157
  } catch (e) {
161
158
  throw new Error(
162
159
  `The ${displayName} '${root}' must be writeable for the current user account '${os.userInfo().username}'`,
163
- {cause: e}
160
+ {cause: e},
164
161
  );
165
162
  }
166
163
  }
@@ -1,8 +1,9 @@
1
1
  /* eslint-disable no-console */
2
- import _ from 'lodash';
2
+ import {util} from '@appium/support';
3
3
  import {getDefaultsForSchema, getAllArgSpecs} from '../schema/schema';
4
4
  import type {Args} from 'appium/types';
5
5
  import type {ReadConfigFileResult} from './config-file';
6
+ import {difference, getPath, pickBy, setPath} from '../utils';
6
7
 
7
8
  interface FlattenedArg {
8
9
  value: unknown;
@@ -21,15 +22,15 @@ export function getNonDefaultServerArgs(parsedArgs: Args): Args {
21
22
  */
22
23
  const flatten = (args: Args): Record<string, FlattenedArg> => {
23
24
  const argSpecs = getAllArgSpecs();
24
- const flattened = _.reduce(
25
- [...argSpecs.values()],
26
- (acc: Record<string, FlattenedArg>, argSpec: {dest: string}) => {
27
- if (_.has(args, argSpec.dest)) {
28
- acc[argSpec.dest] = {value: _.get(args, argSpec.dest), argSpec};
25
+ const flattened = [...argSpecs.values()].reduce<Record<string, FlattenedArg>>(
26
+ (acc, argSpec: {dest: string}) => {
27
+ const value = getPath(args, argSpec.dest);
28
+ if (value !== undefined) {
29
+ acc[argSpec.dest] = {value, argSpec};
29
30
  }
30
31
  return acc;
31
32
  },
32
- {}
33
+ {},
33
34
  );
34
35
 
35
36
  return flattened;
@@ -41,24 +42,22 @@ export function getNonDefaultServerArgs(parsedArgs: Args): Args {
41
42
  const typesDiffer = (dest: string): boolean =>
42
43
  typeof args[dest].value !== typeof defaultsFromSchema[dest];
43
44
 
44
- const defaultValueIsArray = (dest: string): boolean => _.isArray(defaultsFromSchema[dest]);
45
+ const defaultValueIsArray = (dest: string): boolean => Array.isArray(defaultsFromSchema[dest]);
45
46
 
46
- const argsValueIsArray = (dest: string): boolean => _.isArray(args[dest].value);
47
+ const argsValueIsArray = (dest: string): boolean => Array.isArray(args[dest].value);
47
48
 
48
49
  const arraysDiffer = (dest: string): boolean =>
49
- _.gt(_.size(_.difference(args[dest].value as any[], defaultsFromSchema[dest] as any[])), 0);
50
+ difference(args[dest].value as unknown[], defaultsFromSchema[dest] as unknown[]).length > 0;
50
51
 
51
52
  const valuesDiffer = (dest: string): boolean => args[dest].value !== defaultsFromSchema[dest];
52
53
 
53
- const defaultIsDefined = (dest: string): boolean => !_.isUndefined(defaultsFromSchema[dest]);
54
+ const defaultIsDefined = (dest: string): boolean => defaultsFromSchema[dest] !== undefined;
54
55
 
55
- // note that `_.overEvery` is like an "AND", and `_.overSome` is like an "OR"
56
- const argValueNotArrayOrArraysDiffer = _.overSome([_.negate(argsValueIsArray), arraysDiffer]);
56
+ const argValueNotArrayOrArraysDiffer = (dest: string) =>
57
+ !argsValueIsArray(dest) || arraysDiffer(dest);
57
58
 
58
- const defaultValueNotArrayAndValuesDiffer = _.overEvery([
59
- _.negate(defaultValueIsArray),
60
- valuesDiffer,
61
- ]);
59
+ const defaultValueNotArrayAndValuesDiffer = (dest: string) =>
60
+ !defaultValueIsArray(dest) && valuesDiffer(dest);
62
61
 
63
62
  /**
64
63
  * This used to be a hideous conditional, but it's broken up into a hideous function instead.
@@ -71,23 +70,24 @@ export function getNonDefaultServerArgs(parsedArgs: Args): Args {
71
70
  * - ensures the args value is an array
72
71
  * - ensures the args values do not differ from the default values
73
72
  */
74
- const isNotDefault = _.overEvery([
75
- defaultIsDefined,
76
- _.overSome([
77
- typesDiffer,
78
- _.overEvery([defaultValueIsArray, argValueNotArrayOrArraysDiffer]),
79
- defaultValueNotArrayAndValuesDiffer,
80
- ]),
81
- ]);
73
+ const isNotDefault = (dest: string) =>
74
+ defaultIsDefined(dest) &&
75
+ (typesDiffer(dest) ||
76
+ (defaultValueIsArray(dest) && argValueNotArrayOrArraysDiffer(dest)) ||
77
+ defaultValueNotArrayAndValuesDiffer(dest));
82
78
 
83
79
  const defaultsFromSchema = getDefaultsForSchema(true) as Record<string, unknown>;
84
80
 
85
- return _.reduce(
86
- _.pickBy(args, (_v, key) => isNotDefault(key)),
87
- // explodes the flattened object back into nested one
88
- (acc: Args, {value, argSpec}: FlattenedArg) => _.set(acc, argSpec.dest, value),
89
- {} as Args
90
- );
81
+ const nonDefault = pickBy(args, (_v, key) => isNotDefault(String(key)));
82
+ const result = {} as Args;
83
+ for (const entry of Object.values(nonDefault)) {
84
+ if (!entry) {
85
+ continue;
86
+ }
87
+ const {value, argSpec} = entry;
88
+ setPath(result as Record<string, unknown>, argSpec.dest, value);
89
+ }
90
+ return result;
91
91
  }
92
92
 
93
93
  /**
@@ -106,7 +106,7 @@ export function showConfig(
106
106
  nonDefaultPreConfigParsedArgs: Partial<Args>,
107
107
  configResult: ReadConfigFileResult,
108
108
  defaults: Partial<Args>,
109
- parsedArgs: Args
109
+ parsedArgs: Args,
110
110
  ): void {
111
111
  console.log('Appium Configuration\n');
112
112
  console.log('from defaults:\n');
@@ -118,7 +118,7 @@ export function showConfig(
118
118
  console.log(`\n(no configuration file loaded)`);
119
119
  }
120
120
  const compactedNonDefaultPreConfigArgs = compactConfig(nonDefaultPreConfigParsedArgs);
121
- if (_.isEmpty(compactedNonDefaultPreConfigArgs)) {
121
+ if (util.isEmpty(compactedNonDefaultPreConfigArgs)) {
122
122
  console.log(`\n(no CLI parameters provided)`);
123
123
  } else {
124
124
  console.log('\nvia CLI or function call:\n');
@@ -135,9 +135,12 @@ export function showConfig(
135
135
  * 3. Removes empty objects (but not `false` values)
136
136
  * Does not operate recursively.
137
137
  */
138
- const compactConfig = _.partial(
139
- _.omitBy,
140
- _,
141
- (value: unknown, key: string) =>
142
- key === 'subcommand' || _.isUndefined(value) || (_.isObject(value) && _.isEmpty(value))
143
- );
138
+ function compactConfig<T extends Record<string, unknown>>(obj: T): Partial<T> {
139
+ return pickBy(
140
+ obj,
141
+ (value, key) =>
142
+ key !== 'subcommand' &&
143
+ value !== undefined &&
144
+ !(value !== null && typeof value === 'object' && util.isEmpty(value)),
145
+ );
146
+ }
package/lib/cli/args.ts CHANGED
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {util} from '@appium/support';
2
2
  import type {ArgumentOptions} from 'argparse';
3
3
  import type {ExtensionType} from '@appium/types';
4
4
  import type {CliExtensionSubcommand} from 'appium/types';
@@ -49,7 +49,7 @@ const globalExtensionArgs: ArgumentDefinitions = new Map([
49
49
  *
50
50
  * The result is memoized because parser setup is static across process lifetime.
51
51
  */
52
- export const getExtensionArgs = _.memoize(function getExtensionArgs(): Record<
52
+ export const getExtensionArgs = util.memoize(function getExtensionArgs(): Record<
53
53
  ExtensionType,
54
54
  Record<CliExtensionSubcommand, ArgumentDefinitions>
55
55
  > {
@@ -220,8 +220,7 @@ function makeUpdateArgs(type: ExtensionType): ArgumentDefinitions {
220
220
  required: false,
221
221
  default: false,
222
222
  action: 'store_true',
223
- help:
224
- 'Include any available major revision updates, which may have breaking changes',
223
+ help: 'Include any available major revision updates, which may have breaking changes',
225
224
  },
226
225
  ],
227
226
  ]);
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {console, util} from '@appium/support';
2
2
  import type {ExtMetadata, ExtRecord, InstallType} from 'appium/types';
3
3
  import ExtensionCliCommand from './extension-command';
4
4
  import type {
@@ -9,8 +9,6 @@ import type {
9
9
  RunOutput,
10
10
  } from './extension-command';
11
11
  import {KNOWN_DRIVERS} from '../constants';
12
- import '@colors/colors';
13
-
14
12
  const REQ_DRIVER_FIELDS = ['driverName', 'automationName', 'platformNames', 'mainClass'];
15
13
  type DriverInstallOpts = {driver: string; installType: InstallType; packageName?: string};
16
14
  type DriverUninstallOpts = {driver: string};
@@ -29,7 +27,11 @@ export default class DriverCliCommand extends ExtensionCliCommand<'driver'> {
29
27
  *
30
28
  * @param opts - install options
31
29
  */
32
- async install({driver, installType, packageName}: DriverInstallOpts): Promise<ExtRecord<'driver'>> {
30
+ async install({
31
+ driver,
32
+ installType,
33
+ packageName,
34
+ }: DriverInstallOpts): Promise<ExtRecord<'driver'>> {
33
35
  return await super._install({
34
36
  installSpec: driver,
35
37
  installType,
@@ -91,9 +93,9 @@ export default class DriverCliCommand extends ExtensionCliCommand<'driver'> {
91
93
  */
92
94
  override getPostInstallText({extName, extData}: ExtensionArgs<'driver'>): PostInstallText {
93
95
  return (
94
- `Driver ${extName}@${extData.version} successfully installed\n`.green +
95
- `- automationName: ${extData.automationName.green}\n` +
96
- `- platformNames: ${JSON.stringify(extData.platformNames).green}`
96
+ `${console.styleText('green', `Driver ${extName}@${extData.version} successfully installed`)}\n` +
97
+ `- automationName: ${console.styleText('green', extData.automationName)}\n` +
98
+ `- platformNames: ${console.styleText('green', JSON.stringify(extData.platformNames))}`
97
99
  );
98
100
  }
99
101
 
@@ -106,16 +108,20 @@ export default class DriverCliCommand extends ExtensionCliCommand<'driver'> {
106
108
  * @param driverMetadata - `appium` metadata from extension package
107
109
  * @param installSpec - install spec from CLI
108
110
  */
109
- override validateExtensionFields(driverMetadata: ExtMetadata<'driver'>, installSpec: string): void {
110
- const missingFields = REQ_DRIVER_FIELDS.reduce(
111
- (acc, field) => (driverMetadata[field] ? acc : [...acc, field]),
112
- []
111
+ override validateExtensionFields(
112
+ driverMetadata: ExtMetadata<'driver'>,
113
+ installSpec: string,
114
+ ): void {
115
+ const missingFields = REQ_DRIVER_FIELDS.reduce<string[]>(
116
+ (acc, field) =>
117
+ driverMetadata[field as keyof typeof driverMetadata] ? acc : [...acc, field],
118
+ [],
113
119
  );
114
120
 
115
- if (!_.isEmpty(missingFields)) {
121
+ if (!util.isEmpty(missingFields)) {
116
122
  throw new Error(
117
123
  `Driver "${installSpec}" did not expose correct fields for compatibility ` +
118
- `with Appium. Missing fields: ${JSON.stringify(missingFields)}`
124
+ `with Appium. Missing fields: ${JSON.stringify(missingFields)}`,
119
125
  );
120
126
  }
121
127
  }