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