appium 2.0.0-beta.6 → 2.0.0-beta.60

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 (204) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +156 -65
  3. package/build/lib/appium.d.ts +229 -0
  4. package/build/lib/appium.d.ts.map +1 -0
  5. package/build/lib/appium.js +678 -439
  6. package/build/lib/appium.js.map +1 -0
  7. package/build/lib/cli/args.d.ts +17 -0
  8. package/build/lib/cli/args.d.ts.map +1 -0
  9. package/build/lib/cli/args.js +263 -319
  10. package/build/lib/cli/args.js.map +1 -0
  11. package/build/lib/cli/driver-command.d.ts +102 -0
  12. package/build/lib/cli/driver-command.d.ts.map +1 -0
  13. package/build/lib/cli/driver-command.js +131 -81
  14. package/build/lib/cli/driver-command.js.map +1 -0
  15. package/build/lib/cli/extension-command.d.ts +402 -0
  16. package/build/lib/cli/extension-command.d.ts.map +1 -0
  17. package/build/lib/cli/extension-command.js +799 -383
  18. package/build/lib/cli/extension-command.js.map +1 -0
  19. package/build/lib/cli/extension.d.ts +23 -0
  20. package/build/lib/cli/extension.d.ts.map +1 -0
  21. package/build/lib/cli/extension.js +71 -54
  22. package/build/lib/cli/extension.js.map +1 -0
  23. package/build/lib/cli/parser.d.ts +84 -0
  24. package/build/lib/cli/parser.d.ts.map +1 -0
  25. package/build/lib/cli/parser.js +240 -128
  26. package/build/lib/cli/parser.js.map +1 -0
  27. package/build/lib/cli/plugin-command.d.ts +99 -0
  28. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  29. package/build/lib/cli/plugin-command.js +125 -81
  30. package/build/lib/cli/plugin-command.js.map +1 -0
  31. package/build/lib/cli/utils.d.ts +29 -0
  32. package/build/lib/cli/utils.d.ts.map +1 -0
  33. package/build/lib/cli/utils.js +72 -51
  34. package/build/lib/cli/utils.js.map +1 -0
  35. package/build/lib/config-file.d.ts +100 -0
  36. package/build/lib/config-file.d.ts.map +1 -0
  37. package/build/lib/config-file.js +207 -0
  38. package/build/lib/config-file.js.map +1 -0
  39. package/build/lib/config.d.ts +49 -0
  40. package/build/lib/config.d.ts.map +1 -0
  41. package/build/lib/config.js +267 -202
  42. package/build/lib/config.js.map +1 -0
  43. package/build/lib/constants.d.ts +56 -0
  44. package/build/lib/constants.d.ts.map +1 -0
  45. package/build/lib/constants.js +73 -0
  46. package/build/lib/constants.js.map +1 -0
  47. package/build/lib/extension/driver-config.d.ts +82 -0
  48. package/build/lib/extension/driver-config.d.ts.map +1 -0
  49. package/build/lib/extension/driver-config.js +210 -0
  50. package/build/lib/extension/driver-config.js.map +1 -0
  51. package/build/lib/extension/extension-config.d.ts +270 -0
  52. package/build/lib/extension/extension-config.d.ts.map +1 -0
  53. package/build/lib/extension/extension-config.js +601 -0
  54. package/build/lib/extension/extension-config.js.map +1 -0
  55. package/build/lib/extension/index.d.ts +48 -0
  56. package/build/lib/extension/index.d.ts.map +1 -0
  57. package/build/lib/extension/index.js +105 -0
  58. package/build/lib/extension/index.js.map +1 -0
  59. package/build/lib/extension/manifest-migrations.d.ts +27 -0
  60. package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
  61. package/build/lib/extension/manifest-migrations.js +134 -0
  62. package/build/lib/extension/manifest-migrations.js.map +1 -0
  63. package/build/lib/extension/manifest.d.ts +145 -0
  64. package/build/lib/extension/manifest.d.ts.map +1 -0
  65. package/build/lib/extension/manifest.js +528 -0
  66. package/build/lib/extension/manifest.js.map +1 -0
  67. package/build/lib/extension/package-changed.d.ts +11 -0
  68. package/build/lib/extension/package-changed.d.ts.map +1 -0
  69. package/build/lib/extension/package-changed.js +62 -0
  70. package/build/lib/extension/package-changed.js.map +1 -0
  71. package/build/lib/extension/plugin-config.d.ts +56 -0
  72. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  73. package/build/lib/extension/plugin-config.js +102 -0
  74. package/build/lib/extension/plugin-config.js.map +1 -0
  75. package/build/lib/grid-register.d.ts +10 -0
  76. package/build/lib/grid-register.d.ts.map +1 -0
  77. package/build/lib/grid-register.js +122 -144
  78. package/build/lib/grid-register.js.map +1 -0
  79. package/build/lib/logger.d.ts +3 -0
  80. package/build/lib/logger.d.ts.map +1 -0
  81. package/build/lib/logger.js +5 -17
  82. package/build/lib/logger.js.map +1 -0
  83. package/build/lib/logsink.d.ts +4 -0
  84. package/build/lib/logsink.d.ts.map +1 -0
  85. package/build/lib/logsink.js +190 -187
  86. package/build/lib/logsink.js.map +1 -0
  87. package/build/lib/main.d.ts +62 -0
  88. package/build/lib/main.d.ts.map +1 -0
  89. package/build/lib/main.js +339 -229
  90. package/build/lib/main.js.map +1 -0
  91. package/build/lib/schema/arg-spec.d.ts +143 -0
  92. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  93. package/build/lib/schema/arg-spec.js +164 -0
  94. package/build/lib/schema/arg-spec.js.map +1 -0
  95. package/build/lib/schema/cli-args.d.ts +19 -0
  96. package/build/lib/schema/cli-args.d.ts.map +1 -0
  97. package/build/lib/schema/cli-args.js +217 -0
  98. package/build/lib/schema/cli-args.js.map +1 -0
  99. package/build/lib/schema/cli-transformers.d.ts +5 -0
  100. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  101. package/build/lib/schema/cli-transformers.js +124 -0
  102. package/build/lib/schema/cli-transformers.js.map +1 -0
  103. package/build/lib/schema/index.d.ts +3 -0
  104. package/build/lib/schema/index.d.ts.map +1 -0
  105. package/build/lib/schema/index.js +19 -0
  106. package/build/lib/schema/index.js.map +1 -0
  107. package/build/lib/schema/keywords.d.ts +24 -0
  108. package/build/lib/schema/keywords.d.ts.map +1 -0
  109. package/build/lib/schema/keywords.js +128 -0
  110. package/build/lib/schema/keywords.js.map +1 -0
  111. package/build/lib/schema/schema.d.ts +260 -0
  112. package/build/lib/schema/schema.d.ts.map +1 -0
  113. package/build/lib/schema/schema.js +640 -0
  114. package/build/lib/schema/schema.js.map +1 -0
  115. package/build/lib/utils.d.ts +266 -0
  116. package/build/lib/utils.d.ts.map +1 -0
  117. package/build/lib/utils.js +349 -273
  118. package/build/lib/utils.js.map +1 -0
  119. package/build/types/cli.d.ts +134 -0
  120. package/build/types/cli.d.ts.map +1 -0
  121. package/build/types/cli.js +3 -0
  122. package/build/types/cli.js.map +1 -0
  123. package/build/types/index.d.ts +15 -0
  124. package/build/types/index.d.ts.map +1 -0
  125. package/build/types/index.js +19 -0
  126. package/build/types/index.js.map +1 -0
  127. package/build/types/manifest/base.d.ts +135 -0
  128. package/build/types/manifest/base.d.ts.map +1 -0
  129. package/build/types/manifest/base.js +3 -0
  130. package/build/types/manifest/base.js.map +1 -0
  131. package/build/types/manifest/index.d.ts +21 -0
  132. package/build/types/manifest/index.d.ts.map +1 -0
  133. package/build/types/manifest/index.js +42 -0
  134. package/build/types/manifest/index.js.map +1 -0
  135. package/build/types/manifest/v3.d.ts +139 -0
  136. package/build/types/manifest/v3.d.ts.map +1 -0
  137. package/build/types/manifest/v3.js +3 -0
  138. package/build/types/manifest/v3.js.map +1 -0
  139. package/build/types/manifest/v4.d.ts +139 -0
  140. package/build/types/manifest/v4.d.ts.map +1 -0
  141. package/build/types/manifest/v4.js +3 -0
  142. package/build/types/manifest/v4.js.map +1 -0
  143. package/driver.d.ts +1 -0
  144. package/driver.js +14 -0
  145. package/index.js +11 -0
  146. package/lib/appium.js +558 -186
  147. package/lib/cli/args.js +277 -422
  148. package/lib/cli/driver-command.js +132 -24
  149. package/lib/cli/extension-command.js +751 -272
  150. package/lib/cli/extension.js +49 -18
  151. package/lib/cli/parser.js +263 -83
  152. package/lib/cli/plugin-command.js +122 -22
  153. package/lib/cli/utils.js +24 -10
  154. package/lib/config-file.js +220 -0
  155. package/lib/config.js +246 -111
  156. package/lib/constants.js +79 -0
  157. package/lib/extension/driver-config.js +247 -0
  158. package/lib/extension/extension-config.js +709 -0
  159. package/lib/extension/index.js +116 -0
  160. package/lib/extension/manifest-migrations.js +136 -0
  161. package/lib/extension/manifest.js +580 -0
  162. package/lib/extension/package-changed.js +64 -0
  163. package/lib/extension/plugin-config.js +112 -0
  164. package/lib/grid-register.js +49 -35
  165. package/lib/logger.js +1 -2
  166. package/lib/logsink.js +64 -38
  167. package/lib/main.js +318 -103
  168. package/lib/schema/arg-spec.js +229 -0
  169. package/lib/schema/cli-args.js +238 -0
  170. package/lib/schema/cli-transformers.js +119 -0
  171. package/lib/schema/index.js +2 -0
  172. package/lib/schema/keywords.js +136 -0
  173. package/lib/schema/schema.js +725 -0
  174. package/lib/utils.js +289 -167
  175. package/package.json +84 -84
  176. package/plugin.d.ts +1 -0
  177. package/plugin.js +13 -0
  178. package/scripts/autoinstall-extensions.js +243 -0
  179. package/support.d.ts +1 -0
  180. package/support.js +13 -0
  181. package/tsconfig.json +25 -0
  182. package/types/cli.ts +193 -0
  183. package/types/index.ts +20 -0
  184. package/types/manifest/README.md +30 -0
  185. package/types/manifest/base.ts +158 -0
  186. package/types/manifest/index.ts +28 -0
  187. package/types/manifest/v3.ts +161 -0
  188. package/types/manifest/v4.ts +161 -0
  189. package/CHANGELOG.md +0 -3515
  190. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  191. package/build/lib/cli/npm.js +0 -208
  192. package/build/lib/cli/parser-helpers.js +0 -82
  193. package/build/lib/driver-config.js +0 -77
  194. package/build/lib/drivers.js +0 -96
  195. package/build/lib/extension-config.js +0 -253
  196. package/build/lib/plugin-config.js +0 -59
  197. package/build/lib/plugins.js +0 -14
  198. package/lib/cli/npm.js +0 -184
  199. package/lib/cli/parser-helpers.js +0 -79
  200. package/lib/driver-config.js +0 -46
  201. package/lib/drivers.js +0 -81
  202. package/lib/extension-config.js +0 -209
  203. package/lib/plugin-config.js +0 -34
  204. package/lib/plugins.js +0 -10
package/lib/utils.js CHANGED
@@ -1,65 +1,76 @@
1
1
  import _ from 'lodash';
2
2
  import logger from './logger';
3
- import { processCapabilities, PROTOCOLS } from 'appium-base-driver';
4
- import findRoot from 'find-root';
3
+ import {processCapabilities, PROTOCOLS, STANDARD_CAPS} from '@appium/base-driver';
4
+ import {inspect as dump} from 'util';
5
+ import {node} from '@appium/support';
6
+ import path from 'path';
7
+ import {SERVER_SUBCOMMAND, DRIVER_TYPE, PLUGIN_TYPE} from './constants';
5
8
 
6
9
  const W3C_APPIUM_PREFIX = 'appium';
10
+ const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
7
11
 
8
- function inspectObject (args) {
9
- function getValueArray (obj, indent = ' ') {
10
- if (!_.isObject(obj)) {
11
- return [obj];
12
- }
12
+ /**
13
+ *
14
+ * If `stdout` is a TTY, this is `true`.
15
+ *
16
+ * Used for tighter control over log output.
17
+ * @type {boolean}
18
+ */
19
+ const isStdoutTTY = process.stdout.isTTY;
13
20
 
14
- let strArr = ['{'];
15
- for (let [arg, value] of _.toPairs(obj)) {
16
- if (!_.isObject(value)) {
17
- strArr.push(`${indent} ${arg}: ${value}`);
18
- } else {
19
- value = getValueArray(value, `${indent} `);
20
- strArr.push(`${indent} ${arg}: ${value.shift()}`);
21
- strArr.push(...value);
22
- }
23
- }
24
- strArr.push(`${indent}}`);
25
- return strArr;
26
- }
27
- for (let [arg, value] of _.toPairs(args)) {
28
- value = getValueArray(value);
29
- logger.info(` ${arg}: ${value.shift()}`);
30
- for (let val of value) {
31
- logger.info(val);
32
- }
21
+ /**
22
+ * Dumps to value to the console using `info` logger.
23
+ *
24
+ * @todo May want to force color to be `false` if {@link isStdoutTTY} is `false`.
25
+ */
26
+ const inspect = _.flow(
27
+ _.partialRight(
28
+ /** @type {(object: any, options: import('util').InspectOptions) => string} */ (dump),
29
+ {colors: true, depth: null, compact: !isStdoutTTY}
30
+ ),
31
+ (...args) => {
32
+ logger.info(...args);
33
33
  }
34
- }
34
+ );
35
35
 
36
36
  /**
37
37
  * Takes the caps that were provided in the request and translates them
38
38
  * into caps that can be used by the inner drivers.
39
39
  *
40
- * @param {Object} jsonwpCapabilities
41
- * @param {Object} w3cCapabilities
42
- * @param {Object} constraints
43
- * @param {Object} defaultCapabilities
40
+ * @template {Constraints} C
41
+ * @template [J=any]
42
+ * @param {J} jsonwpCapabilities
43
+ * @param {W3CCapabilities<C>} w3cCapabilities
44
+ * @param {C} constraints
45
+ * @param {NSCapabilities<C>} [defaultCapabilities]
46
+ * @returns {ParsedDriverCaps<C,J>|InvalidCaps<C,J>}
44
47
  */
45
- function parseCapsForInnerDriver (jsonwpCapabilities, w3cCapabilities, constraints = {}, defaultCapabilities = {}) {
48
+ function parseCapsForInnerDriver(
49
+ jsonwpCapabilities,
50
+ w3cCapabilities,
51
+ constraints = /** @type {C} */ ({}),
52
+ defaultCapabilities = {}
53
+ ) {
46
54
  // Check if the caller sent JSONWP caps, W3C caps, or both
47
- const hasW3CCaps = _.isPlainObject(w3cCapabilities) &&
55
+ const hasW3CCaps =
56
+ _.isPlainObject(w3cCapabilities) &&
48
57
  (_.has(w3cCapabilities, 'alwaysMatch') || _.has(w3cCapabilities, 'firstMatch'));
49
58
  const hasJSONWPCaps = _.isPlainObject(jsonwpCapabilities);
50
- let protocol = null;
51
- let desiredCaps = {};
52
- let processedW3CCapabilities = null;
53
- let processedJsonwpCapabilities = null;
59
+ let desiredCaps = /** @type {ParsedDriverCaps<C>['desiredCaps']} */ ({});
60
+ /** @type {ParsedDriverCaps<C>['processedW3CCapabilities']} */
61
+ let processedW3CCapabilities;
62
+ /** @type {ParsedDriverCaps<C>['processedJsonwpCapabilities']} */
63
+ let processedJsonwpCapabilities;
54
64
 
55
- if (!hasJSONWPCaps && !hasW3CCaps) {
56
- return {
65
+ if (!hasW3CCaps) {
66
+ return /** @type {InvalidCaps<C>} */ ({
57
67
  protocol: PROTOCOLS.W3C,
58
- error: new Error('Either JSONWP or W3C capabilities should be provided'),
59
- };
68
+ error: new Error('W3C capabilities should be provided'),
69
+ });
60
70
  }
61
71
 
62
- const {W3C, MJSONWP} = PROTOCOLS;
72
+ const {W3C} = PROTOCOLS;
73
+ const protocol = W3C;
63
74
 
64
75
  // Make sure we don't mutate the original arguments
65
76
  jsonwpCapabilities = _.cloneDeep(jsonwpCapabilities);
@@ -71,16 +82,23 @@ function parseCapsForInnerDriver (jsonwpCapabilities, w3cCapabilities, constrain
71
82
  for (const [defaultCapKey, defaultCapValue] of _.toPairs(defaultCapabilities)) {
72
83
  let isCapAlreadySet = false;
73
84
  // Check if the key is already present in firstMatch entries
74
- for (const firstMatchEntry of (w3cCapabilities.firstMatch || [])) {
75
- if (_.isPlainObject(firstMatchEntry)
76
- && _.has(removeAppiumPrefixes(firstMatchEntry), removeAppiumPrefix(defaultCapKey))) {
85
+ for (const firstMatchEntry of w3cCapabilities.firstMatch ?? []) {
86
+ if (
87
+ _.isPlainObject(firstMatchEntry) &&
88
+ _.has(removeAppiumPrefixes(firstMatchEntry), removeAppiumPrefix(defaultCapKey))
89
+ ) {
77
90
  isCapAlreadySet = true;
78
91
  break;
79
92
  }
80
93
  }
81
94
  // Check if the key is already present in alwaysMatch entries
82
- isCapAlreadySet = isCapAlreadySet || (_.isPlainObject(w3cCapabilities.alwaysMatch)
83
- && _.has(removeAppiumPrefixes(w3cCapabilities.alwaysMatch), removeAppiumPrefix(defaultCapKey)));
95
+ isCapAlreadySet =
96
+ isCapAlreadySet ||
97
+ (_.isPlainObject(w3cCapabilities.alwaysMatch) &&
98
+ _.has(
99
+ removeAppiumPrefixes(w3cCapabilities.alwaysMatch),
100
+ removeAppiumPrefix(defaultCapKey)
101
+ ));
84
102
  if (isCapAlreadySet) {
85
103
  // Skip if the key is already present in the provided caps
86
104
  continue;
@@ -88,69 +106,42 @@ function parseCapsForInnerDriver (jsonwpCapabilities, w3cCapabilities, constrain
88
106
 
89
107
  // Only add the default capability if it is not overridden
90
108
  if (_.isEmpty(w3cCapabilities.firstMatch)) {
91
- w3cCapabilities.firstMatch = [{[defaultCapKey]: defaultCapValue}];
109
+ w3cCapabilities.firstMatch = /** @type {W3CCapabilities<C>['firstMatch']} */ ([
110
+ {[defaultCapKey]: defaultCapValue},
111
+ ]);
92
112
  } else {
93
113
  w3cCapabilities.firstMatch[0][defaultCapKey] = defaultCapValue;
94
114
  }
95
115
  }
96
116
  }
97
117
  if (hasJSONWPCaps) {
98
- jsonwpCapabilities = Object.assign({}, removeAppiumPrefixes(defaultCapabilities), jsonwpCapabilities);
118
+ jsonwpCapabilities = {
119
+ ...removeAppiumPrefixes(defaultCapabilities),
120
+ ...jsonwpCapabilities,
121
+ };
99
122
  }
100
123
  }
101
124
 
102
125
  // Get MJSONWP caps
103
126
  if (hasJSONWPCaps) {
104
- protocol = MJSONWP;
105
- desiredCaps = jsonwpCapabilities;
106
127
  processedJsonwpCapabilities = {...jsonwpCapabilities};
107
128
  }
108
129
 
109
130
  // Get W3C caps
110
131
  if (hasW3CCaps) {
111
- protocol = W3C;
112
132
  // Call the process capabilities algorithm to find matching caps on the W3C
113
133
  // (see: https://github.com/jlipps/simple-wd-spec#processing-capabilities)
114
- let isFixingNeededForW3cCaps = false;
115
134
  try {
116
135
  desiredCaps = processCapabilities(w3cCapabilities, constraints, true);
117
136
  } catch (error) {
118
- if (!hasJSONWPCaps) {
119
- return {
120
- desiredCaps,
121
- processedJsonwpCapabilities,
122
- processedW3CCapabilities,
123
- protocol,
124
- error,
125
- };
126
- }
127
137
  logger.info(`Could not parse W3C capabilities: ${error.message}`);
128
- isFixingNeededForW3cCaps = true;
129
- }
130
-
131
- if (hasJSONWPCaps && !isFixingNeededForW3cCaps) {
132
- const differingKeys = _.difference(_.keys(removeAppiumPrefixes(processedJsonwpCapabilities)), _.keys(removeAppiumPrefixes(desiredCaps)));
133
- if (!_.isEmpty(differingKeys)) {
134
- logger.info(`The following capabilities were provided in the JSONWP desired capabilities that are missing ` +
135
- `in W3C capabilities: ${JSON.stringify(differingKeys)}`);
136
- isFixingNeededForW3cCaps = true;
137
- }
138
- }
139
-
140
- if (isFixingNeededForW3cCaps && hasJSONWPCaps) {
141
- logger.info('Trying to fix W3C capabilities by merging them with JSONWP caps');
142
- w3cCapabilities = fixW3cCapabilities(w3cCapabilities, jsonwpCapabilities);
143
- try {
144
- desiredCaps = processCapabilities(w3cCapabilities, constraints, true);
145
- } catch (error) {
146
- logger.warn(`Could not parse fixed W3C capabilities: ${error.message}. Falling back to JSONWP protocol`);
147
- return {
148
- desiredCaps: processedJsonwpCapabilities,
149
- processedJsonwpCapabilities,
150
- processedW3CCapabilities: null,
151
- protocol: MJSONWP,
152
- };
153
- }
138
+ return /** @type {InvalidCaps<C,J>} */ ({
139
+ desiredCaps,
140
+ processedJsonwpCapabilities,
141
+ processedW3CCapabilities,
142
+ protocol,
143
+ error,
144
+ });
154
145
  }
155
146
 
156
147
  // Create a new w3c capabilities payload that contains only the matching caps in `alwaysMatch`
@@ -160,99 +151,110 @@ function parseCapsForInnerDriver (jsonwpCapabilities, w3cCapabilities, constrain
160
151
  };
161
152
  }
162
153
 
163
- return {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities, protocol};
154
+ return /** @type {ParsedDriverCaps<C,J>} */ ({
155
+ desiredCaps,
156
+ processedJsonwpCapabilities,
157
+ processedW3CCapabilities,
158
+ protocol,
159
+ });
164
160
  }
165
161
 
166
162
  /**
167
- * This helper method tries to fix corrupted W3C capabilities by
168
- * merging them to existing JSONWP capabilities.
169
- *
170
- * @param {Object} w3cCaps W3C capabilities
171
- * @param {Object} jsonwpCaps JSONWP capabilities
172
- * @return {Object} Fixed W3C capabilities
163
+ * Takes a capabilities objects and prefixes capabilities with `appium:`
164
+ * @template {Constraints} [C={}]
165
+ * @param {Capabilities<C>} caps - Desired capabilities object
166
+ * @returns {NSCapabilities<C>}
173
167
  */
174
- function fixW3cCapabilities (w3cCaps, jsonwpCaps) {
175
- const result = {
176
- firstMatch: w3cCaps.firstMatch || [],
177
- alwaysMatch: w3cCaps.alwaysMatch || {},
178
- };
179
- const keysToInsert = _.keys(jsonwpCaps);
180
- const removeMatchingKeys = (match) => {
181
- _.pull(keysToInsert, match);
182
- const colonIndex = match.indexOf(':');
183
- if (colonIndex >= 0 && match.length > colonIndex) {
184
- _.pull(keysToInsert, match.substring(colonIndex + 1));
185
- }
186
- if (keysToInsert.includes(`${W3C_APPIUM_PREFIX}:${match}`)) {
187
- _.pull(keysToInsert, `${W3C_APPIUM_PREFIX}:${match}`);
188
- }
189
- };
168
+ function insertAppiumPrefixes(caps) {
169
+ return /** @type {NSCapabilities<C>} */ (
170
+ _.mapKeys(caps, (_, key) =>
171
+ STANDARD_CAPS_LOWERCASE.has(key.toLowerCase()) || key.includes(':')
172
+ ? key
173
+ : `${W3C_APPIUM_PREFIX}:${key}`
174
+ )
175
+ );
176
+ }
190
177
 
191
- for (const firstMatchEntry of result.firstMatch) {
192
- for (const pair of _.toPairs(firstMatchEntry)) {
193
- removeMatchingKeys(pair[0]);
194
- }
195
- }
178
+ /**
179
+ * @template {Constraints} [C={}]
180
+ * @param {NSCapabilities<C>} caps
181
+ * @returns {Capabilities<C>}
182
+ */
183
+ function removeAppiumPrefixes(caps) {
184
+ return /** @type {Capabilities<C>} */ (_.mapKeys(caps, (_, key) => removeAppiumPrefix(key)));
185
+ }
196
186
 
197
- for (const pair of _.toPairs(result.alwaysMatch)) {
198
- removeMatchingKeys(pair[0]);
199
- }
187
+ /**
188
+ * @param {string} key
189
+ * @returns {string}
190
+ */
191
+ function removeAppiumPrefix(key) {
192
+ const prefix = `${W3C_APPIUM_PREFIX}:`;
193
+ return _.startsWith(key, prefix) ? key.substring(prefix.length) : key;
194
+ }
200
195
 
201
- for (const key of keysToInsert) {
202
- result.alwaysMatch[key] = jsonwpCaps[key];
203
- }
204
- return result;
196
+ /**
197
+ *
198
+ * @param {string} pkgName
199
+ * @returns {string|undefined}
200
+ */
201
+ function getPackageVersion(pkgName) {
202
+ const pkgInfo = require(`${pkgName}/package.json`) || {};
203
+ return pkgInfo.version;
205
204
  }
206
205
 
207
206
  /**
208
- * Takes a capabilities objects and prefixes capabilities with `appium:`
209
- * @param {Object} caps Desired capabilities object
207
+ * Adjusts NODE_PATH environment variable,
208
+ * so drivers and plugins could load their peer dependencies.
209
+ * Read https://nodejs.org/api/modules.html#loading-from-the-global-folders
210
+ * for more details.
211
+ * @returns {void}
210
212
  */
211
- function insertAppiumPrefixes (caps) {
212
- // Standard, non-prefixed capabilities (see https://www.w3.org/TR/webdriver/#dfn-table-of-standard-capabilities)
213
- const STANDARD_CAPS = [
214
- 'browserName',
215
- 'browserVersion',
216
- 'platformName',
217
- 'acceptInsecureCerts',
218
- 'pageLoadStrategy',
219
- 'proxy',
220
- 'setWindowRect',
221
- 'timeouts',
222
- 'unhandledPromptBehavior'
223
- ];
224
-
225
- let prefixedCaps = {};
226
- for (let [name, value] of _.toPairs(caps)) {
227
- if (STANDARD_CAPS.includes(name) || name.includes(':')) {
228
- prefixedCaps[name] = value;
213
+ function adjustNodePath() {
214
+ const selfRoot = node.getModuleRootSync('appium', __filename);
215
+ if (!selfRoot || path.dirname(selfRoot).length >= selfRoot.length) {
216
+ return;
217
+ }
218
+ const nodeModulesRoot = path.dirname(selfRoot);
219
+
220
+ const refreshRequirePaths = () => {
221
+ try {
222
+ // ! This hack allows us to avoid modification of import
223
+ // ! statements in client modules. It uses a private API though,
224
+ // ! so it could break (maybe, eventually).
225
+ // See https://gist.github.com/branneman/8048520#7-the-hack
226
+ // @ts-ignore see above comment
227
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
228
+ require('module').Module._initPaths();
229
+ return true;
230
+ } catch (e) {
231
+ return false;
232
+ }
233
+ };
234
+
235
+ if (!process.env.NODE_PATH) {
236
+ process.env.NODE_PATH = nodeModulesRoot;
237
+ if (refreshRequirePaths()) {
238
+ process.env.APPIUM_OMIT_PEER_DEPS = '1';
229
239
  } else {
230
- prefixedCaps[`${W3C_APPIUM_PREFIX}:${name}`] = value;
240
+ delete process.env.NODE_PATH;
231
241
  }
242
+ return;
232
243
  }
233
- return prefixedCaps;
234
- }
235
244
 
236
- function removeAppiumPrefixes (caps) {
237
- if (!_.isPlainObject(caps)) {
238
- return caps;
245
+ const nodePathParts = process.env.NODE_PATH.split(path.delimiter);
246
+ if (nodePathParts.includes(nodeModulesRoot)) {
247
+ process.env.APPIUM_OMIT_PEER_DEPS = '1';
248
+ return;
239
249
  }
240
250
 
241
- const fixedCaps = {};
242
- for (let [name, value] of _.toPairs(caps)) {
243
- fixedCaps[removeAppiumPrefix(name)] = value;
251
+ nodePathParts.push(nodeModulesRoot);
252
+ process.env.NODE_PATH = nodePathParts.join(path.delimiter);
253
+ if (refreshRequirePaths()) {
254
+ process.env.APPIUM_OMIT_PEER_DEPS = '1';
255
+ } else {
256
+ process.env.NODE_PATH = _.without(nodePathParts, nodeModulesRoot).join(path.delimiter);
244
257
  }
245
- return fixedCaps;
246
- }
247
-
248
- function removeAppiumPrefix (key) {
249
- const prefix = `${W3C_APPIUM_PREFIX}:`;
250
- return _.startsWith(key, prefix) ? key.substring(prefix.length) : key;
251
- }
252
-
253
- function getPackageVersion (pkgName) {
254
- const pkgInfo = require(`${pkgName}/package.json`) || {};
255
- return pkgInfo.version;
256
258
  }
257
259
 
258
260
  /**
@@ -271,7 +273,7 @@ function getPackageVersion (pkgName) {
271
273
  * setting items or a dictionary containing parsed Appium setting names along with
272
274
  * their values.
273
275
  */
274
- function pullSettings (caps) {
276
+ function pullSettings(caps) {
275
277
  if (!_.isPlainObject(caps) || _.isEmpty(caps)) {
276
278
  return {};
277
279
  }
@@ -289,9 +291,129 @@ function pullSettings (caps) {
289
291
  return result;
290
292
  }
291
293
 
292
- const rootDir = findRoot(__dirname);
294
+ /**
295
+ * @template {CliCommand} [Cmd=ServerCommand]
296
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
297
+ * @param {Args<Cmd, SubCmd>} args
298
+ * @returns {args is Args<ServerCommand>}
299
+ */
300
+ export function isServerCommandArgs(args) {
301
+ return args.subcommand === SERVER_SUBCOMMAND;
302
+ }
303
+
304
+ /**
305
+ * @template {CliCommand} [Cmd=ServerCommand]
306
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
307
+ * @param {Args<Cmd, SubCmd>} args
308
+ * @returns {args is Args<CliExtensionCommand, SubCmd>}
309
+ */
310
+ export function isExtensionCommandArgs(args) {
311
+ return args.subcommand === DRIVER_TYPE || args.subcommand === PLUGIN_TYPE;
312
+ }
313
+
314
+ /**
315
+ * @template {CliCommand} Cmd
316
+ * @template {CliExtensionSubcommand} SubCmd
317
+ * @param {Args<Cmd, SubCmd>} args
318
+ * @returns {args is Args<DriverCommand, SubCmd>}
319
+ */
320
+ export function isDriverCommandArgs(args) {
321
+ return args.subcommand === DRIVER_TYPE;
322
+ }
323
+
324
+ /**
325
+ * @template {CliCommand} Cmd
326
+ * @template {CliExtensionSubcommand} SubCmd
327
+ * @param {Args<Cmd, SubCmd>} args
328
+ * @returns {args is Args<PluginCommand, SubCmd>}
329
+ */
330
+ export function isPluginCommandArgs(args) {
331
+ return args.subcommand === PLUGIN_TYPE;
332
+ }
293
333
 
294
334
  export {
295
- inspectObject, parseCapsForInnerDriver, insertAppiumPrefixes, rootDir,
296
- getPackageVersion, pullSettings, removeAppiumPrefixes,
335
+ inspect,
336
+ parseCapsForInnerDriver,
337
+ insertAppiumPrefixes,
338
+ getPackageVersion,
339
+ pullSettings,
340
+ removeAppiumPrefixes,
341
+ adjustNodePath,
297
342
  };
343
+
344
+ /**
345
+ * @typedef {import('@appium/types').StringRecord} StringRecord
346
+ * @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
347
+ */
348
+
349
+ /**
350
+ * @template {Constraints} [C=BaseDriverCapConstraints]
351
+ * @template [J=any]
352
+ * @typedef ParsedDriverCaps
353
+ * @property {Capabilities<C>} desiredCaps
354
+ * @property {string} protocol
355
+ * @property {J} [processedJsonwpCapabilities]
356
+ * @property {W3CCapabilities<C>} [processedW3CCapabilities]
357
+ */
358
+
359
+ /**
360
+ * @todo protocol is more specific
361
+ * @template {Constraints} [C=BaseDriverCapConstraints]
362
+ * @template [J=any]
363
+ * @typedef InvalidCaps
364
+ * @property {Error} error
365
+ * @property {string} protocol
366
+ * @property {Capabilities<C>} [desiredCaps]
367
+ * @property {J} [processedJsonwpCapabilities]
368
+ * @property {W3CCapabilities<C>} [processedW3CCapabilities]
369
+ */
370
+
371
+ /**
372
+ * @template {Constraints} C
373
+ * @typedef {import('@appium/types').Capabilities<C>} Capabilities
374
+ */
375
+
376
+ /**
377
+ * @template {Constraints} C
378
+ * @typedef {import('@appium/types').W3CCapabilities<C>} W3CCapabilities
379
+ */
380
+
381
+ /**
382
+ * @template {Constraints} C
383
+ * @typedef {import('@appium/types').NSCapabilities<C>} NSCapabilities
384
+ */
385
+
386
+ /**
387
+ * @template {Constraints} C
388
+ * @typedef {import('@appium/types').ConstraintsToCaps<C>} ConstraintsToCaps
389
+ */
390
+
391
+ /**
392
+ * @template T
393
+ * @typedef {import('type-fest').StringKeyOf<T>} StringKeyOf
394
+ */
395
+
396
+ /**
397
+ * @typedef {import('@appium/types').Constraints} Constraints
398
+ */
399
+
400
+ /**
401
+ * @typedef {import('appium/types').CliCommand} CliCommand
402
+ * @typedef {import('appium/types').CliExtensionSubcommand} CliExtensionSubcommand
403
+ * @typedef {import('appium/types').CliExtensionCommand} CliExtensionCommand
404
+ * @typedef {import('appium/types').CliCommandServer} ServerCommand
405
+ * @typedef {import('appium/types').CliCommandDriver} DriverCommand
406
+ * @typedef {import('appium/types').CliCommandPlugin} PluginCommand
407
+ */
408
+
409
+ /**
410
+ * @template {CliCommand} [Cmd=ServerCommand]
411
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
412
+ * @typedef {import('appium/types').Args<Cmd, SubCmd>} Args
413
+ */
414
+
415
+ /**
416
+ * @template {CliCommand} [Cmd=ServerCommand]
417
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
418
+ * @typedef {import('appium/types').ParsedArgs<Cmd, SubCmd>} ParsedArgs
419
+ */