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