appium 2.0.0-beta.25 → 2.0.0-beta.28

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 (191) hide show
  1. package/build/lib/appium.d.ts +215 -0
  2. package/build/lib/appium.d.ts.map +1 -0
  3. package/build/lib/appium.js +94 -101
  4. package/build/lib/cli/args.d.ts +20 -0
  5. package/build/lib/cli/args.d.ts.map +1 -0
  6. package/build/lib/cli/args.js +19 -39
  7. package/build/lib/cli/driver-command.d.ts +36 -0
  8. package/build/lib/cli/driver-command.d.ts.map +1 -0
  9. package/build/lib/cli/driver-command.js +10 -13
  10. package/build/lib/cli/extension-command.d.ts +345 -0
  11. package/build/lib/cli/extension-command.d.ts.map +1 -0
  12. package/build/lib/cli/extension-command.js +117 -94
  13. package/build/lib/cli/extension.d.ts +14 -0
  14. package/build/lib/cli/extension.d.ts.map +1 -0
  15. package/build/lib/cli/extension.js +14 -22
  16. package/build/lib/cli/parser.d.ts +79 -0
  17. package/build/lib/cli/parser.d.ts.map +1 -0
  18. package/build/lib/cli/parser.js +9 -19
  19. package/build/lib/cli/plugin-command.d.ts +39 -0
  20. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  21. package/build/lib/cli/plugin-command.js +9 -14
  22. package/build/lib/cli/utils.d.ts +29 -0
  23. package/build/lib/cli/utils.d.ts.map +1 -0
  24. package/build/lib/cli/utils.js +2 -4
  25. package/build/lib/config-file.d.ts +100 -0
  26. package/build/lib/config-file.d.ts.map +1 -0
  27. package/build/lib/config-file.js +2 -4
  28. package/build/lib/config.d.ts +40 -0
  29. package/build/lib/config.d.ts.map +1 -0
  30. package/build/lib/config.js +8 -7
  31. package/build/lib/constants.d.ts +48 -0
  32. package/build/lib/constants.d.ts.map +1 -0
  33. package/build/lib/constants.js +60 -0
  34. package/build/lib/extension/driver-config.d.ts +84 -0
  35. package/build/lib/extension/driver-config.d.ts.map +1 -0
  36. package/build/lib/extension/driver-config.js +190 -0
  37. package/build/lib/extension/extension-config.d.ts +170 -0
  38. package/build/lib/extension/extension-config.d.ts.map +1 -0
  39. package/build/lib/extension/extension-config.js +297 -0
  40. package/build/lib/extension/index.d.ts +39 -0
  41. package/build/lib/extension/index.d.ts.map +1 -0
  42. package/build/lib/extension/index.js +77 -0
  43. package/build/lib/extension/manifest.d.ts +174 -0
  44. package/build/lib/extension/manifest.d.ts.map +1 -0
  45. package/build/lib/extension/manifest.js +246 -0
  46. package/build/lib/extension/package-changed.d.ts +11 -0
  47. package/build/lib/extension/package-changed.d.ts.map +1 -0
  48. package/build/lib/extension/package-changed.js +68 -0
  49. package/build/lib/extension/plugin-config.d.ts +62 -0
  50. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  51. package/build/lib/extension/plugin-config.js +87 -0
  52. package/build/lib/grid-register.d.ts +10 -0
  53. package/build/lib/grid-register.d.ts.map +1 -0
  54. package/build/lib/grid-register.js +2 -4
  55. package/build/lib/logger.d.ts +3 -0
  56. package/build/lib/logger.d.ts.map +1 -0
  57. package/build/lib/logger.js +2 -4
  58. package/build/lib/logsink.d.ts +4 -0
  59. package/build/lib/logsink.d.ts.map +1 -0
  60. package/build/lib/logsink.js +2 -4
  61. package/build/lib/main.d.ts +51 -0
  62. package/build/lib/main.d.ts.map +1 -0
  63. package/build/lib/main.js +40 -68
  64. package/build/lib/schema/arg-spec.d.ts +143 -0
  65. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  66. package/build/lib/schema/arg-spec.js +11 -14
  67. package/build/lib/schema/cli-args.d.ts +19 -0
  68. package/build/lib/schema/cli-args.d.ts.map +1 -0
  69. package/build/lib/schema/cli-args.js +2 -4
  70. package/build/lib/schema/cli-transformers.d.ts +5 -0
  71. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  72. package/build/lib/schema/cli-transformers.js +2 -4
  73. package/build/lib/schema/index.d.ts +3 -0
  74. package/build/lib/schema/index.d.ts.map +1 -0
  75. package/build/lib/schema/index.js +2 -4
  76. package/build/lib/schema/keywords.d.ts +24 -0
  77. package/build/lib/schema/keywords.d.ts.map +1 -0
  78. package/build/lib/schema/keywords.js +2 -4
  79. package/build/lib/schema/schema.d.ts +259 -0
  80. package/build/lib/schema/schema.d.ts.map +1 -0
  81. package/build/lib/schema/schema.js +57 -39
  82. package/build/lib/utils.d.ts +66 -0
  83. package/build/lib/utils.d.ts.map +1 -0
  84. package/build/lib/utils.js +6 -35
  85. package/build/tsconfig.tsbuildinfo +1 -0
  86. package/lib/appium.js +188 -117
  87. package/lib/cli/args.js +19 -24
  88. package/lib/cli/driver-command.js +19 -8
  89. package/lib/cli/extension-command.js +314 -184
  90. package/lib/cli/extension.js +18 -16
  91. package/lib/cli/parser.js +7 -16
  92. package/lib/cli/plugin-command.js +16 -7
  93. package/lib/cli/utils.js +1 -1
  94. package/lib/config-file.js +6 -7
  95. package/lib/config.js +17 -12
  96. package/lib/constants.js +78 -0
  97. package/lib/extension/driver-config.js +249 -0
  98. package/lib/extension/extension-config.js +458 -0
  99. package/lib/extension/index.js +102 -0
  100. package/lib/extension/manifest.js +486 -0
  101. package/lib/extension/package-changed.js +63 -0
  102. package/lib/extension/plugin-config.js +113 -0
  103. package/lib/grid-register.js +4 -4
  104. package/lib/logsink.js +4 -0
  105. package/lib/main.js +54 -92
  106. package/lib/schema/arg-spec.js +11 -7
  107. package/lib/schema/cli-args.js +1 -1
  108. package/lib/schema/cli-transformers.js +0 -1
  109. package/lib/schema/keywords.js +1 -2
  110. package/lib/schema/schema.js +62 -31
  111. package/lib/utils.js +48 -45
  112. package/package.json +30 -24
  113. package/{postinstall.js → scripts/postinstall.js} +1 -1
  114. package/types/appium-manifest.d.ts +61 -0
  115. package/types/cli.d.ts +134 -0
  116. package/types/extension.d.ts +56 -0
  117. package/types/external-manifest.d.ts +58 -0
  118. package/types/index.d.ts +7 -0
  119. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  120. package/build/check-npm-pack-files.js +0 -23
  121. package/build/commands-yml/parse.js +0 -319
  122. package/build/commands-yml/validator.js +0 -130
  123. package/build/index.js +0 -19
  124. package/build/lib/appium-config.schema.json +0 -0
  125. package/build/lib/cli/npm.js +0 -220
  126. package/build/lib/driver-config.js +0 -100
  127. package/build/lib/drivers.js +0 -100
  128. package/build/lib/ext-config-io.js +0 -165
  129. package/build/lib/extension-config.js +0 -320
  130. package/build/lib/plugin-config.js +0 -69
  131. package/build/lib/plugins.js +0 -18
  132. package/build/lib/schema/appium-config-schema.js +0 -253
  133. package/build/postinstall.js +0 -90
  134. package/build/test/cli/cli-e2e-specs.js +0 -221
  135. package/build/test/cli/cli-helpers.js +0 -86
  136. package/build/test/cli/cli-specs.js +0 -71
  137. package/build/test/cli/fixtures/test-driver/package.json +0 -27
  138. package/build/test/cli/schema-args-specs.js +0 -48
  139. package/build/test/cli/schema-e2e-specs.js +0 -47
  140. package/build/test/config-e2e-specs.js +0 -112
  141. package/build/test/config-file-e2e-specs.js +0 -191
  142. package/build/test/config-file-specs.js +0 -281
  143. package/build/test/config-specs.js +0 -258
  144. package/build/test/driver-e2e-specs.js +0 -435
  145. package/build/test/driver-specs.js +0 -386
  146. package/build/test/ext-config-io-specs.js +0 -181
  147. package/build/test/extension-config-specs.js +0 -365
  148. package/build/test/fixtures/allow-feat.txt +0 -5
  149. package/build/test/fixtures/caps.json +0 -3
  150. package/build/test/fixtures/config/allow-insecure.txt +0 -3
  151. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
  152. package/build/test/fixtures/config/appium.config.bad.json +0 -32
  153. package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
  154. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
  155. package/build/test/fixtures/config/appium.config.good.js +0 -40
  156. package/build/test/fixtures/config/appium.config.good.json +0 -33
  157. package/build/test/fixtures/config/appium.config.good.yaml +0 -30
  158. package/build/test/fixtures/config/appium.config.invalid.json +0 -31
  159. package/build/test/fixtures/config/appium.config.security-array.json +0 -5
  160. package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
  161. package/build/test/fixtures/config/appium.config.security-path.json +0 -5
  162. package/build/test/fixtures/config/driver-fake.config.json +0 -8
  163. package/build/test/fixtures/config/nodeconfig.json +0 -3
  164. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  165. package/build/test/fixtures/default-args.js +0 -35
  166. package/build/test/fixtures/deny-feat.txt +0 -5
  167. package/build/test/fixtures/driver.schema.js +0 -20
  168. package/build/test/fixtures/extensions.yaml +0 -27
  169. package/build/test/fixtures/flattened-schema.js +0 -532
  170. package/build/test/fixtures/plugin.schema.js +0 -20
  171. package/build/test/fixtures/schema-with-extensions.js +0 -28
  172. package/build/test/grid-register-specs.js +0 -74
  173. package/build/test/helpers.js +0 -75
  174. package/build/test/logger-specs.js +0 -76
  175. package/build/test/npm-specs.js +0 -20
  176. package/build/test/parser-specs.js +0 -319
  177. package/build/test/plugin-e2e-specs.js +0 -316
  178. package/build/test/schema/arg-spec-specs.js +0 -70
  179. package/build/test/schema/cli-args-specs.js +0 -408
  180. package/build/test/schema/schema-specs.js +0 -407
  181. package/build/test/utils-specs.js +0 -288
  182. package/lib/cli/npm.js +0 -251
  183. package/lib/driver-config.js +0 -101
  184. package/lib/drivers.js +0 -84
  185. package/lib/ext-config-io.js +0 -287
  186. package/lib/extension-config.js +0 -366
  187. package/lib/plugin-config.js +0 -63
  188. package/lib/plugins.js +0 -13
  189. package/lib/schema/appium-config-schema.js +0 -287
  190. package/types/appium-config.d.ts +0 -197
  191. package/types/types.d.ts +0 -206
@@ -0,0 +1,458 @@
1
+
2
+ import _ from 'lodash';
3
+ import path from 'path';
4
+ import resolveFrom from 'resolve-from';
5
+ import log from '../logger';
6
+ import {
7
+ ALLOWED_SCHEMA_EXTENSIONS,
8
+ isAllowedSchemaFileExtension,
9
+ registerSchema,
10
+ } from '../schema/schema';
11
+
12
+ const INSTALL_TYPE_NPM = 'npm';
13
+ const INSTALL_TYPE_LOCAL = 'local';
14
+ const INSTALL_TYPE_GITHUB = 'github';
15
+ const INSTALL_TYPE_GIT = 'git';
16
+
17
+ /** @type {Set<InstallType>} */
18
+ const INSTALL_TYPES = new Set([
19
+ INSTALL_TYPE_GIT,
20
+ INSTALL_TYPE_GITHUB,
21
+ INSTALL_TYPE_LOCAL,
22
+ INSTALL_TYPE_NPM,
23
+ ]);
24
+
25
+ /**
26
+ * This class is abstract. It should not be instantiated directly.
27
+ *
28
+ * Subclasses should provide the generic parameter to implement.
29
+ * @template {ExtensionType} ExtType
30
+ */
31
+ export class ExtensionConfig {
32
+ /** @type {ExtType} */
33
+ extensionType;
34
+
35
+ /** @type {`${ExtType}s`} */
36
+ configKey;
37
+
38
+ /** @type {ExtRecord<ExtType>} */
39
+ installedExtensions;
40
+
41
+ /** @type {ExtensionLogFn} */
42
+ log;
43
+
44
+ /** @type {Manifest} */
45
+ manifest;
46
+
47
+ /**
48
+ * @protected
49
+ * @param {ExtType} extensionType - Type of extension
50
+ * @param {Manifest} manifest - `Manifest` instance
51
+ * @param {ExtensionLogFn} [logFn]
52
+ */
53
+ constructor (extensionType, manifest, logFn) {
54
+ const logger = _.isFunction(logFn) ? logFn : log.error.bind(log);
55
+ this.extensionType = extensionType;
56
+ this.configKey = `${extensionType}s`;
57
+ this.installedExtensions = manifest.getExtensionData(extensionType);
58
+ this.log = logger;
59
+ this.manifest = manifest;
60
+ }
61
+
62
+ get manifestPath () {
63
+ return this.manifest.manifestPath;
64
+ }
65
+
66
+ get appiumHome () {
67
+ return this.manifest.appiumHome;
68
+ }
69
+
70
+ /**
71
+ * Checks extensions for problems
72
+ * @param {ExtRecord<ExtType>} exts - Extension data
73
+ */
74
+ validate (exts) {
75
+ const foundProblems =
76
+ /** @type {Record<ExtName<ExtType>,Problem[]>} */ ({});
77
+ for (const [
78
+ extName,
79
+ extData,
80
+ ] of /** @type {[ExtName<ExtType>, ExtManifest<ExtType>][]} */ (
81
+ _.toPairs(exts)
82
+ )) {
83
+ foundProblems[extName] = [
84
+ ...this.getGenericConfigProblems(extData, extName),
85
+ ...this.getConfigProblems(extData),
86
+ ...this.getSchemaProblems(extData, extName),
87
+ ];
88
+ }
89
+
90
+ const problemSummaries = [];
91
+ for (const [extName, problems] of _.toPairs(foundProblems)) {
92
+ if (_.isEmpty(problems)) {
93
+ continue;
94
+ }
95
+ // remove this extension from the list since it's not valid
96
+ delete exts[extName];
97
+ problemSummaries.push(
98
+ `${this.extensionType} ${extName} had errors and will not ` +
99
+ `be available. Errors:`,
100
+ );
101
+ for (const problem of problems) {
102
+ problemSummaries.push(
103
+ ` - ${problem.err} (Actual value: ` +
104
+ `${JSON.stringify(problem.val)})`,
105
+ );
106
+ }
107
+ }
108
+
109
+ if (!_.isEmpty(problemSummaries)) {
110
+ this.log(
111
+ `Appium encountered one or more errors while validating ` +
112
+ `the ${this.configKey} extension file (${this.manifestPath}):`,
113
+ );
114
+ for (const summary of problemSummaries) {
115
+ this.log(summary);
116
+ }
117
+ }
118
+
119
+ return exts;
120
+ }
121
+
122
+ /**
123
+ * @param {ExtManifest<ExtType>} extData
124
+ * @param {ExtName<ExtType>} extName
125
+ * @returns {Problem[]}
126
+ */
127
+ getSchemaProblems (extData, extName) {
128
+ const problems = [];
129
+ const {schema: argSchemaPath} = extData;
130
+ if (ExtensionConfig.extDataHasSchema(extData)) {
131
+ if (_.isString(argSchemaPath)) {
132
+ if (isAllowedSchemaFileExtension(argSchemaPath)) {
133
+ try {
134
+ this.readExtensionSchema(extName, extData);
135
+ } catch (err) {
136
+ problems.push({
137
+ err: `Unable to register schema at path ${argSchemaPath}; ${err.message}`,
138
+ val: argSchemaPath,
139
+ });
140
+ }
141
+ } else {
142
+ problems.push({
143
+ err: `Schema file has unsupported extension. Allowed: ${[
144
+ ...ALLOWED_SCHEMA_EXTENSIONS,
145
+ ].join(', ')}`,
146
+ val: argSchemaPath,
147
+ });
148
+ }
149
+ } else if (_.isPlainObject(argSchemaPath)) {
150
+ try {
151
+ this.readExtensionSchema(extName, extData);
152
+ } catch (err) {
153
+ problems.push({
154
+ err: `Unable to register embedded schema; ${err.message}`,
155
+ val: argSchemaPath,
156
+ });
157
+ }
158
+ } else {
159
+ problems.push({
160
+ err: 'Incorrectly formatted schema field; must be a path to a schema file or a schema object.',
161
+ val: argSchemaPath,
162
+ });
163
+ }
164
+ }
165
+ return problems;
166
+ }
167
+
168
+ /**
169
+ * @param {ExtManifest<ExtType>} extData
170
+ * @param {ExtName<ExtType>} extName
171
+ * @returns {Problem[]}
172
+ */
173
+ // eslint-disable-next-line no-unused-vars
174
+ getGenericConfigProblems (extData, extName) {
175
+ const {version, pkgName, installSpec, installType, mainClass} =
176
+ extData;
177
+ const problems = [];
178
+
179
+ if (!_.isString(version)) {
180
+ problems.push({err: 'Missing or incorrect version', val: version});
181
+ }
182
+
183
+ if (!_.isString(pkgName)) {
184
+ problems.push({
185
+ err: 'Missing or incorrect NPM package name',
186
+ val: pkgName,
187
+ });
188
+ }
189
+
190
+ if (!_.isString(installSpec)) {
191
+ problems.push({
192
+ err: 'Missing or incorrect installation spec',
193
+ val: installSpec,
194
+ });
195
+ }
196
+
197
+ if (!INSTALL_TYPES.has(installType)) {
198
+ problems.push({
199
+ err: 'Missing or incorrect install type',
200
+ val: installType,
201
+ });
202
+ }
203
+
204
+ if (!_.isString(mainClass)) {
205
+ problems.push({
206
+ err: 'Missing or incorrect driver class name',
207
+ val: mainClass,
208
+ });
209
+ }
210
+
211
+ return problems;
212
+ }
213
+
214
+ /**
215
+ * @abstract
216
+ * @param {ExtManifest<ExtType>} extData
217
+ * @returns {Problem[]}
218
+ */
219
+ // eslint-disable-next-line no-unused-vars
220
+ getConfigProblems (extData) {
221
+ // shoud override this method if special validation is necessary for this extension type
222
+ return [];
223
+ }
224
+
225
+ /**
226
+ * @param {string} extName
227
+ * @param {ExtManifest<ExtType>} extData
228
+ * @param {ExtensionConfigMutationOpts} [opts]
229
+ * @returns {Promise<void>}
230
+ */
231
+ async addExtension (extName, extData, {write = true} = {}) {
232
+ this.manifest.addExtension(this.extensionType, extName, extData);
233
+ if (write) {
234
+ await this.manifest.write();
235
+ }
236
+ }
237
+
238
+ /**
239
+ * @param {ExtName<ExtType>} extName
240
+ * @param {ExtManifest<ExtType>|import('../cli/extension-command').ExtensionFields<ExtType>} extData
241
+ * @param {ExtensionConfigMutationOpts} [opts]
242
+ * @returns {Promise<void>}
243
+ */
244
+ async updateExtension (extName, extData, {write = true} = {}) {
245
+ this.installedExtensions[extName] = {
246
+ ...this.installedExtensions[extName],
247
+ ...extData,
248
+ };
249
+ if (write) {
250
+ await this.manifest.write();
251
+ }
252
+ }
253
+
254
+ /**
255
+ * @param {ExtName<ExtType>} extName
256
+ * @param {ExtensionConfigMutationOpts} [opts]
257
+ * @returns {Promise<void>}
258
+ */
259
+ async removeExtension (extName, {write = true} = {}) {
260
+ delete this.installedExtensions[extName];
261
+ if (write) {
262
+ await this.manifest.write();
263
+ }
264
+ }
265
+
266
+ /**
267
+ * @param {ExtName<ExtType>[]} [activeNames]
268
+ * @returns {void}
269
+ */
270
+ // eslint-disable-next-line no-unused-vars
271
+ print (activeNames) {
272
+ if (_.isEmpty(this.installedExtensions)) {
273
+ log.info(
274
+ `No ${this.configKey} have been installed in ${this.appiumHome}. Use the "appium ${this.extensionType}" ` +
275
+ 'command to install the one(s) you want to use.',
276
+ );
277
+ return;
278
+ }
279
+
280
+ log.info(`Available ${this.configKey}:`);
281
+ for (const [
282
+ extName,
283
+ extData,
284
+ ] of /** @type {[string, ExtManifest<ExtType>][]} */ (
285
+ _.toPairs(this.installedExtensions)
286
+ )) {
287
+ log.info(` - ${this.extensionDesc(extName, extData)}`);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Returns a string describing the extension. Subclasses must implement.
293
+ * @param {ExtName<ExtType>} extName - Extension name
294
+ * @param {ExtManifest<ExtType>} extData - Extension data
295
+ * @returns {string}
296
+ * @abstract
297
+ */
298
+ // eslint-disable-next-line no-unused-vars
299
+ extensionDesc (extName, extData) {
300
+ throw new Error('This must be implemented in a subclass');
301
+ }
302
+
303
+ /**
304
+ * @param {string} extName
305
+ * @returns {string}
306
+ */
307
+ getInstallPath (extName) {
308
+ return path.join(this.appiumHome, 'node_modules', this.installedExtensions[extName].pkgName);
309
+ }
310
+
311
+ /**
312
+ * Loads extension and returns its main class (constructor)
313
+ * @param {ExtName<ExtType>} extName
314
+ * @returns {ExtClass<ExtType>}
315
+ */
316
+ require (extName) {
317
+ const {mainClass} = this.installedExtensions[extName];
318
+ const reqPath = this.getInstallPath(extName);
319
+ const reqResolved = require.resolve(reqPath);
320
+ // note: this will only reload the entry point
321
+ if (process.env.APPIUM_RELOAD_EXTENSIONS && require.cache[reqResolved]) {
322
+ log.debug(`Removing ${reqResolved} from require cache`);
323
+ delete require.cache[reqResolved];
324
+ }
325
+ log.debug(`Requiring ${this.extensionType} at ${reqPath}`);
326
+ return require(reqPath)[mainClass];
327
+ }
328
+
329
+ /**
330
+ * @param {string} extName
331
+ * @returns {boolean}
332
+ */
333
+ isInstalled (extName) {
334
+ return _.includes(Object.keys(this.installedExtensions), extName);
335
+ }
336
+
337
+ /**
338
+ * Intended to be called by corresponding instance methods of subclass.
339
+ * @private
340
+ * @template {ExtensionType} ExtType
341
+ * @param {string} appiumHome
342
+ * @param {ExtType} extType
343
+ * @param {ExtName<ExtType>} extName - Extension name (unique to its type)
344
+ * @param {ExtManifestWithSchema<ExtType>} extData - Extension config
345
+ * @returns {import('ajv').SchemaObject|undefined}
346
+ */
347
+ static _readExtensionSchema (appiumHome, extType, extName, extData) {
348
+ const {pkgName, schema: argSchemaPath} = extData;
349
+ if (!argSchemaPath) {
350
+ throw new TypeError(
351
+ `No \`schema\` property found in config for ${extType} ${pkgName} -- why is this function being called?`,
352
+ );
353
+ }
354
+ let moduleObject;
355
+ if (_.isString(argSchemaPath)) {
356
+ const schemaPath = resolveFrom(appiumHome, path.join(pkgName, argSchemaPath));
357
+ moduleObject = require(schemaPath);
358
+ } else {
359
+ moduleObject = argSchemaPath;
360
+ }
361
+ // this sucks. default exports should be destroyed
362
+ const schema = moduleObject.__esModule
363
+ ? moduleObject.default
364
+ : moduleObject;
365
+ registerSchema(extType, extName, schema);
366
+ return schema;
367
+ }
368
+
369
+ /**
370
+ * Returns `true` if a specific {@link ExtManifest} object has a `schema` prop.
371
+ * The {@link ExtManifest} object becomes a {@link ExtManifestWithSchema} object.
372
+ * @template {ExtensionType} ExtType
373
+ * @param {ExtManifest<ExtType>} extData
374
+ * @returns {extData is ExtManifestWithSchema<ExtType>}
375
+ */
376
+ static extDataHasSchema (extData) {
377
+ return _.isString(extData?.schema) || _.isObject(extData?.schema);
378
+ }
379
+
380
+ /**
381
+ * If an extension provides a schema, this will load the schema and attempt to
382
+ * register it with the schema registrar.
383
+ * @param {ExtName<ExtType>} extName - Name of extension
384
+ * @param {ExtManifestWithSchema<ExtType>} extData - Extension data
385
+ * @returns {import('ajv').SchemaObject|undefined}
386
+ */
387
+ readExtensionSchema (extName, extData) {
388
+ return ExtensionConfig._readExtensionSchema(
389
+ this.appiumHome,
390
+ this.extensionType,
391
+ extName,
392
+ extData,
393
+ );
394
+ }
395
+ }
396
+
397
+ export {
398
+ INSTALL_TYPE_NPM,
399
+ INSTALL_TYPE_GIT,
400
+ INSTALL_TYPE_LOCAL,
401
+ INSTALL_TYPE_GITHUB,
402
+ INSTALL_TYPES,
403
+ };
404
+
405
+ /**
406
+ * Config problem
407
+ * @typedef Problem
408
+ * @property {string} err - Error message
409
+ * @property {any} val - Associated value
410
+ */
411
+
412
+ /**
413
+ * An optional logging function provided to an {@link ExtensionConfig} subclass.
414
+ * @callback ExtensionLogFn
415
+ * @param {...any} args
416
+ * @returns {void}
417
+ */
418
+
419
+ /**
420
+ * @typedef {import('../../types').ExtensionType} ExtensionType
421
+ * @typedef {import('./manifest').Manifest} Manifest
422
+ */
423
+
424
+ /**
425
+ * @template T
426
+ * @typedef {import('../../types/appium-manifest').ExtManifest<T>} ExtManifest
427
+ */
428
+
429
+ /**
430
+ * @template T
431
+ * @typedef {import('../../types/appium-manifest').ExtManifestWithSchema<T>} ExtManifestWithSchema
432
+ */
433
+
434
+ /**
435
+ * @template T
436
+ * @typedef {import('../../types/appium-manifest').ExtName<T>} ExtName
437
+ */
438
+
439
+ /**
440
+ * @template T
441
+ * @typedef {import('../../types/extension').ExtClass<T>} ExtClass
442
+ */
443
+
444
+ /**
445
+ * @template T
446
+ * @typedef {import('../../types/appium-manifest').ExtRecord<T>} ExtRecord
447
+ */
448
+
449
+ /**
450
+ * Options for various methods in {@link ExtensionConfig}
451
+ * @typedef ExtensionConfigMutationOpts
452
+ * @property {boolean} [write=true] Whether or not to write the manifest to disk after a mutation operation
453
+ */
454
+
455
+ /**
456
+ * A valid install type
457
+ * @typedef {typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_GIT | typeof INSTALL_TYPE_LOCAL | typeof INSTALL_TYPE_GITHUB} InstallType
458
+ */
@@ -0,0 +1,102 @@
1
+
2
+ import _ from 'lodash';
3
+ import { USE_ALL_PLUGINS } from '../constants';
4
+ import log from '../logger';
5
+ import { DriverConfig } from './driver-config';
6
+ import { Manifest } from './manifest';
7
+ import { PluginConfig } from './plugin-config';
8
+
9
+ /**
10
+ * Loads extensions and creates `ExtensionConfig` instances.
11
+ *
12
+ * - Reads the manifest file, creating if necessary
13
+ * - Using the parsed extension data, creates/gets the `ExtensionConfig` subclass instances
14
+ * - Returns these instances
15
+ *
16
+ * If `appiumHome` is needed, use `resolveAppiumHome` from the `env` module in `@appium/support`.
17
+ * @param {string} appiumHome
18
+ * @returns {Promise<ExtensionConfigs>}
19
+ */
20
+ export async function loadExtensions (appiumHome) {
21
+ const manifest = Manifest.getInstance(appiumHome);
22
+ const {drivers, plugins} = await manifest.read();
23
+ const driverConfig =
24
+ DriverConfig.getInstance(manifest) ??
25
+ DriverConfig.create(manifest, {extData: drivers});
26
+ const pluginConfig =
27
+ PluginConfig.getInstance(manifest) ??
28
+ PluginConfig.create(manifest, {extData: plugins});
29
+ return {driverConfig, pluginConfig};
30
+ }
31
+
32
+ /**
33
+ * Find any plugin name which has been installed, and which has been requested for activation by
34
+ * using the --use-plugins flag, and turn each one into its class, so we can send them as objects
35
+ * to the server init. We also want to send/assign them to the umbrella driver so it can use them
36
+ * to wrap command execution
37
+ *
38
+ * @param {import('./plugin-config').PluginConfig} pluginConfig - a plugin extension config
39
+ * @param {string[]} usePlugins
40
+ * @returns {import('../../types').PluginClass[]}
41
+ */
42
+ export function getActivePlugins (pluginConfig, usePlugins = []) {
43
+ return _.compact(
44
+ Object.keys(pluginConfig.installedExtensions)
45
+ .filter(
46
+ (pluginName) =>
47
+ _.includes(usePlugins, pluginName) ||
48
+ (usePlugins.length === 1 && usePlugins[0] === USE_ALL_PLUGINS),
49
+ )
50
+ .map((pluginName) => {
51
+ try {
52
+ log.info(`Attempting to load plugin ${pluginName}...`);
53
+ const PluginClass = pluginConfig.require(pluginName);
54
+
55
+ PluginClass.pluginName = pluginName; // store the plugin name on the class so it can be used later
56
+ return PluginClass;
57
+ } catch (err) {
58
+ log.error(
59
+ `Could not load plugin '${pluginName}', so it will not be available. Error ` +
60
+ `in loading the plugin was: ${err.message}`,
61
+ );
62
+ log.debug(err.stack);
63
+ }
64
+ }),
65
+ );
66
+ }
67
+
68
+ /**
69
+ * Find any driver name which has been installed, and turn each one into its class, so we can send
70
+ * them as objects to the server init in case they need to add methods/routes or update the server.
71
+ * If the --drivers flag was given, this method only loads the given drivers.
72
+ *
73
+ * @param {import('./driver-config').DriverConfig} driverConfig - a driver extension config
74
+ * @param {string[]} [useDrivers] - optional list of drivers to load
75
+ */
76
+ export function getActiveDrivers (driverConfig, useDrivers = []) {
77
+ return _.compact(
78
+ Object.keys(driverConfig.installedExtensions)
79
+ .filter(
80
+ (driverName) =>
81
+ _.includes(useDrivers, driverName) || useDrivers.length === 0,
82
+ )
83
+ .map((driverName) => {
84
+ try {
85
+ log.info(`Attempting to load driver ${driverName}...`);
86
+ return driverConfig.require(driverName);
87
+ } catch (err) {
88
+ log.error(
89
+ `Could not load driver '${driverName}', so it will not be available. Error ` +
90
+ `in loading the driver was: ${err.message}`,
91
+ );
92
+ log.debug(err.stack);
93
+ }
94
+ }),
95
+ );
96
+ }
97
+
98
+ /**
99
+ * @typedef ExtensionConfigs
100
+ * @property {DriverConfig} driverConfig
101
+ * @property {PluginConfig} pluginConfig
102
+ */