appium 3.2.2 → 3.3.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 +147 -205
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +169 -282
- package/build/lib/appium.js.map +1 -1
- package/build/lib/bidi-commands.d.ts.map +1 -1
- package/build/lib/bidi-commands.js +11 -11
- package/build/lib/bidi-commands.js.map +1 -1
- package/build/lib/bootstrap/appium-initializer.d.ts +21 -0
- package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -0
- package/build/lib/bootstrap/appium-initializer.js +146 -0
- package/build/lib/bootstrap/appium-initializer.js.map +1 -0
- package/build/lib/bootstrap/appium-main-runner.d.ts +22 -0
- package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -0
- package/build/lib/bootstrap/appium-main-runner.js +109 -0
- package/build/lib/bootstrap/appium-main-runner.js.map +1 -0
- package/build/lib/bootstrap/config-file.d.ts +37 -0
- package/build/lib/bootstrap/config-file.d.ts.map +1 -0
- package/build/lib/{config-file.js → bootstrap/config-file.js} +62 -138
- package/build/lib/bootstrap/config-file.js.map +1 -0
- package/build/lib/bootstrap/grid-v3-register.d.ts +20 -0
- package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -0
- package/build/lib/bootstrap/grid-v3-register.js +185 -0
- package/build/lib/bootstrap/grid-v3-register.js.map +1 -0
- package/build/lib/bootstrap/init-types.d.ts +16 -0
- package/build/lib/bootstrap/init-types.d.ts.map +1 -0
- package/build/lib/bootstrap/init-types.js +3 -0
- package/build/lib/bootstrap/init-types.js.map +1 -0
- package/build/lib/bootstrap/main-helpers.d.ts +55 -0
- package/build/lib/bootstrap/main-helpers.d.ts.map +1 -0
- package/build/lib/bootstrap/main-helpers.js +187 -0
- package/build/lib/bootstrap/main-helpers.js.map +1 -0
- package/build/lib/bootstrap/node-helpers.d.ts +32 -0
- package/build/lib/bootstrap/node-helpers.d.ts.map +1 -0
- package/build/lib/bootstrap/node-helpers.js +201 -0
- package/build/lib/bootstrap/node-helpers.js.map +1 -0
- package/build/lib/bootstrap/startup-config.d.ts +22 -0
- package/build/lib/bootstrap/startup-config.d.ts.map +1 -0
- package/build/lib/bootstrap/startup-config.js +111 -0
- package/build/lib/bootstrap/startup-config.js.map +1 -0
- package/build/lib/cli/args.d.ts +16 -12
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +20 -40
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.d.ts +51 -93
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +11 -66
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +173 -377
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +387 -656
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/extension.d.ts +10 -15
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js +15 -33
- package/build/lib/cli/extension.js.map +1 -1
- package/build/lib/cli/parser.d.ts +37 -66
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +69 -104
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.d.ts +50 -90
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +11 -63
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/setup-command.d.ts +21 -26
- package/build/lib/cli/setup-command.d.ts.map +1 -1
- package/build/lib/cli/setup-command.js +19 -61
- package/build/lib/cli/setup-command.js.map +1 -1
- package/build/lib/cli/utils.d.ts +33 -35
- package/build/lib/cli/utils.d.ts.map +1 -1
- package/build/lib/cli/utils.js +48 -50
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/constants.d.ts +23 -23
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +10 -15
- package/build/lib/constants.js.map +1 -1
- package/build/lib/doctor/doctor.d.ts +40 -57
- package/build/lib/doctor/doctor.d.ts.map +1 -1
- package/build/lib/doctor/doctor.js +31 -62
- package/build/lib/doctor/doctor.js.map +1 -1
- package/build/lib/extension/driver-config.d.ts +18 -77
- package/build/lib/extension/driver-config.d.ts.map +1 -1
- package/build/lib/extension/driver-config.js +37 -125
- package/build/lib/extension/driver-config.js.map +1 -1
- package/build/lib/extension/extension-config.d.ts +103 -210
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +180 -342
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/extension/index.d.ts +12 -29
- package/build/lib/extension/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +33 -75
- package/build/lib/extension/index.js.map +1 -1
- package/build/lib/extension/manifest-migrations.d.ts +3 -20
- package/build/lib/extension/manifest-migrations.d.ts.map +1 -1
- package/build/lib/extension/manifest-migrations.js +20 -101
- package/build/lib/extension/manifest-migrations.js.map +1 -1
- package/build/lib/extension/manifest.d.ts +61 -107
- package/build/lib/extension/manifest.d.ts.map +1 -1
- package/build/lib/extension/manifest.js +181 -356
- package/build/lib/extension/manifest.js.map +1 -1
- package/build/lib/extension/package-changed.d.ts +1 -3
- package/build/lib/extension/package-changed.d.ts.map +1 -1
- package/build/lib/extension/package-changed.js +8 -15
- package/build/lib/extension/package-changed.js.map +1 -1
- package/build/lib/extension/plugin-config.d.ts +10 -52
- package/build/lib/extension/plugin-config.d.ts.map +1 -1
- package/build/lib/extension/plugin-config.js +11 -63
- package/build/lib/extension/plugin-config.js.map +1 -1
- package/build/lib/helpers/build.d.ts +22 -0
- package/build/lib/helpers/build.d.ts.map +1 -0
- package/build/lib/helpers/build.js +109 -0
- package/build/lib/helpers/build.js.map +1 -0
- package/build/lib/helpers/capability.d.ts +38 -0
- package/build/lib/helpers/capability.d.ts.map +1 -0
- package/build/lib/helpers/capability.js +128 -0
- package/build/lib/helpers/capability.js.map +1 -0
- package/build/lib/helpers/network.d.ts +14 -0
- package/build/lib/helpers/network.d.ts.map +1 -0
- package/build/lib/helpers/network.js +35 -0
- package/build/lib/helpers/network.js.map +1 -0
- package/build/lib/insecure-features.js +6 -6
- package/build/lib/insecure-features.js.map +1 -1
- package/build/lib/inspector-commands.d.ts +6 -0
- package/build/lib/inspector-commands.d.ts.map +1 -1
- package/build/lib/inspector-commands.js +6 -0
- package/build/lib/inspector-commands.js.map +1 -1
- package/build/lib/logger.d.ts +2 -3
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js +2 -3
- package/build/lib/logger.js.map +1 -1
- package/build/lib/logsink.d.ts +13 -22
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +48 -103
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/main.d.ts +15 -58
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +25 -425
- package/build/lib/main.js.map +1 -1
- package/build/lib/schema/arg-spec.d.ts +32 -107
- package/build/lib/schema/arg-spec.d.ts.map +1 -1
- package/build/lib/schema/arg-spec.js +11 -107
- package/build/lib/schema/arg-spec.js.map +1 -1
- package/build/lib/schema/cli-args-guards.d.ts +34 -0
- package/build/lib/schema/cli-args-guards.d.ts.map +1 -0
- package/build/lib/schema/cli-args-guards.js +49 -0
- package/build/lib/schema/cli-args-guards.js.map +1 -0
- package/build/lib/schema/cli-args.d.ts +3 -15
- package/build/lib/schema/cli-args.d.ts.map +1 -1
- package/build/lib/schema/cli-args.js +17 -107
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/cli-transformers.d.ts +15 -12
- package/build/lib/schema/cli-transformers.d.ts.map +1 -1
- package/build/lib/schema/cli-transformers.js +15 -45
- package/build/lib/schema/cli-transformers.js.map +1 -1
- package/build/lib/schema/format-errors.d.ts +28 -0
- package/build/lib/schema/format-errors.d.ts.map +1 -0
- package/build/lib/schema/format-errors.js +29 -0
- package/build/lib/schema/format-errors.js.map +1 -0
- package/build/lib/schema/index.d.ts +4 -2
- package/build/lib/schema/index.d.ts.map +1 -1
- package/build/lib/schema/index.js +2 -0
- package/build/lib/schema/index.js.map +1 -1
- package/build/lib/schema/keywords.d.ts +12 -20
- package/build/lib/schema/keywords.d.ts.map +1 -1
- package/build/lib/schema/keywords.js +6 -51
- package/build/lib/schema/keywords.js.map +1 -1
- package/build/lib/schema/schema.d.ts +106 -231
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +88 -358
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils.d.ts +7 -267
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +10 -409
- package/build/lib/utils.js.map +1 -1
- package/lib/{appium.js → appium.ts} +297 -341
- package/lib/bidi-commands.ts +10 -14
- package/lib/bootstrap/appium-initializer.ts +212 -0
- package/lib/bootstrap/appium-main-runner.ts +172 -0
- package/lib/bootstrap/config-file.ts +178 -0
- package/lib/bootstrap/grid-v3-register.ts +250 -0
- package/lib/bootstrap/init-types.ts +31 -0
- package/lib/bootstrap/main-helpers.ts +223 -0
- package/lib/bootstrap/node-helpers.ts +180 -0
- package/lib/bootstrap/startup-config.ts +143 -0
- package/lib/cli/{args.js → args.ts} +45 -56
- package/lib/cli/driver-command.ts +122 -0
- package/lib/cli/{extension-command.js → extension-command.ts} +827 -906
- package/lib/cli/extension.ts +65 -0
- package/lib/cli/{parser.js → parser.ts} +93 -116
- package/lib/cli/plugin-command.ts +117 -0
- package/lib/cli/{setup-command.js → setup-command.ts} +59 -74
- package/lib/cli/utils.ts +97 -0
- package/lib/{constants.js → constants.ts} +30 -41
- package/lib/doctor/{doctor.js → doctor.ts} +82 -92
- package/lib/extension/driver-config.ts +165 -0
- package/lib/extension/{extension-config.js → extension-config.ts} +291 -405
- package/lib/extension/index.ts +143 -0
- package/lib/extension/manifest-migrations.ts +57 -0
- package/lib/extension/manifest.ts +369 -0
- package/lib/extension/{package-changed.js → package-changed.ts} +9 -18
- package/lib/extension/plugin-config.ts +62 -0
- package/lib/helpers/build.ts +111 -0
- package/lib/helpers/capability.ts +171 -0
- package/lib/helpers/network.ts +30 -0
- package/lib/insecure-features.ts +1 -1
- package/lib/inspector-commands.ts +6 -1
- package/lib/{logger.js → logger.ts} +1 -2
- package/lib/{logsink.js → logsink.ts} +91 -137
- package/lib/main.ts +60 -0
- package/lib/schema/arg-spec.ts +131 -0
- package/lib/schema/cli-args-guards.ts +67 -0
- package/lib/schema/cli-args.ts +171 -0
- package/lib/schema/cli-transformers.ts +83 -0
- package/lib/schema/format-errors.ts +43 -0
- package/lib/schema/index.ts +4 -0
- package/lib/schema/keywords.ts +96 -0
- package/lib/schema/schema.ts +448 -0
- package/lib/utils.ts +73 -0
- package/package.json +17 -18
- package/scripts/autoinstall-extensions.js +3 -0
- package/build/lib/config-file.d.ts +0 -100
- package/build/lib/config-file.d.ts.map +0 -1
- package/build/lib/config-file.js.map +0 -1
- package/build/lib/config.d.ts +0 -70
- package/build/lib/config.d.ts.map +0 -1
- package/build/lib/config.js +0 -390
- package/build/lib/config.js.map +0 -1
- package/build/lib/grid-register.d.ts +0 -10
- package/build/lib/grid-register.d.ts.map +0 -1
- package/build/lib/grid-register.js +0 -134
- package/build/lib/grid-register.js.map +0 -1
- package/lib/cli/driver-command.js +0 -174
- package/lib/cli/extension.js +0 -74
- package/lib/cli/plugin-command.js +0 -164
- package/lib/cli/utils.js +0 -91
- package/lib/config-file.js +0 -228
- package/lib/config.js +0 -389
- package/lib/extension/driver-config.js +0 -245
- package/lib/extension/index.js +0 -169
- package/lib/extension/manifest-migrations.js +0 -136
- package/lib/extension/manifest.js +0 -550
- package/lib/extension/plugin-config.js +0 -112
- package/lib/grid-register.js +0 -146
- package/lib/main.js +0 -545
- package/lib/schema/arg-spec.js +0 -229
- package/lib/schema/cli-args.js +0 -254
- package/lib/schema/cli-transformers.js +0 -113
- package/lib/schema/index.js +0 -2
- package/lib/schema/keywords.js +0 -136
- package/lib/schema/schema.js +0 -725
- package/lib/utils.js +0 -512
|
@@ -1,18 +1,28 @@
|
|
|
1
|
+
import type {ExtensionType} from '@appium/types';
|
|
2
|
+
import type {ExtClass, ExtManifest, ExtName, ExtRecord, InstallType} from 'appium/types';
|
|
3
|
+
import type {SchemaObject} from 'ajv';
|
|
1
4
|
import {util, fs, system} from '@appium/support';
|
|
2
5
|
import B from 'bluebird';
|
|
3
6
|
import _ from 'lodash';
|
|
4
7
|
import path from 'node:path';
|
|
8
|
+
import {pathToFileURL} from 'node:url';
|
|
5
9
|
import resolveFrom from 'resolve-from';
|
|
6
10
|
import {satisfies} from 'semver';
|
|
7
11
|
import {commandClasses} from '../cli/extension';
|
|
8
|
-
import {
|
|
9
|
-
|
|
12
|
+
import type {
|
|
13
|
+
ExtensionList,
|
|
14
|
+
ExtensionListData,
|
|
15
|
+
InstalledExtensionListData,
|
|
16
|
+
} from '../cli/extension-command';
|
|
17
|
+
import type {ExtCommand} from '../cli/extension';
|
|
18
|
+
import {APPIUM_VER} from '../helpers/build';
|
|
19
|
+
import {log} from '../logger';
|
|
10
20
|
import {
|
|
11
21
|
ALLOWED_SCHEMA_EXTENSIONS,
|
|
12
22
|
isAllowedSchemaFileExtension,
|
|
13
23
|
registerSchema,
|
|
14
24
|
} from '../schema/schema';
|
|
15
|
-
import {
|
|
25
|
+
import type {Manifest} from './manifest';
|
|
16
26
|
|
|
17
27
|
const DEFAULT_ENTRY_POINT = 'index.js';
|
|
18
28
|
/**
|
|
@@ -43,8 +53,7 @@ export const INSTALL_TYPE_GIT = 'git';
|
|
|
43
53
|
*/
|
|
44
54
|
export const INSTALL_TYPE_DEV = 'dev';
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
export const INSTALL_TYPES = new Set([
|
|
56
|
+
export const INSTALL_TYPES = new Set<InstallType>([
|
|
48
57
|
INSTALL_TYPE_GIT,
|
|
49
58
|
INSTALL_TYPE_GITHUB,
|
|
50
59
|
INSTALL_TYPE_LOCAL,
|
|
@@ -52,80 +61,98 @@ export const INSTALL_TYPES = new Set([
|
|
|
52
61
|
INSTALL_TYPE_DEV,
|
|
53
62
|
]);
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
* This class is abstract. It should not be instantiated directly.
|
|
57
|
-
*
|
|
58
|
-
* Subclasses should provide the generic parameter to implement.
|
|
59
|
-
* @template {ExtensionType} ExtType
|
|
60
|
-
*/
|
|
61
|
-
export class ExtensionConfig {
|
|
62
|
-
/**
|
|
63
|
-
* The type of extension this class is responsible for.
|
|
64
|
-
* @type {ExtType}
|
|
65
|
-
*/
|
|
66
|
-
extensionType;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Manifest data for the extensions of this type.
|
|
70
|
-
*
|
|
71
|
-
* This data should _not_ be written to by anything but {@linkcode Manifest}.
|
|
72
|
-
* @type {Readonly<ExtRecord<ExtType>>}
|
|
73
|
-
*/
|
|
74
|
-
installedExtensions;
|
|
64
|
+
export type ExtManifestProblem = {err: string; val: unknown};
|
|
75
65
|
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
export type ExtManifestWithSchema<E extends ExtensionType> = ExtManifest<E> & {
|
|
67
|
+
schema: NonNullable<ExtManifest<E>['schema']>;
|
|
68
|
+
};
|
|
78
69
|
|
|
79
|
-
|
|
80
|
-
manifest;
|
|
70
|
+
export type ExtensionConfigMutationOpts = {write?: boolean};
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Shared configuration and validation for installed Appium extensions (drivers or plugins).
|
|
74
|
+
* Subclasses fix the extension kind; do not instantiate this class directly.
|
|
75
|
+
*/
|
|
76
|
+
export abstract class ExtensionConfig<ExtType extends ExtensionType> {
|
|
77
|
+
readonly extensionType: ExtType;
|
|
78
|
+
readonly manifest: Manifest;
|
|
79
|
+
installedExtensions: ExtRecord<ExtType>;
|
|
80
|
+
#listDataCache: ExtensionList<ExtType> | undefined;
|
|
86
81
|
|
|
87
|
-
|
|
88
|
-
* @protected
|
|
89
|
-
* @param {ExtType} extensionType - Type of extension
|
|
90
|
-
* @param {Manifest} manifest - `Manifest` instance
|
|
91
|
-
*/
|
|
92
|
-
constructor(extensionType, manifest) {
|
|
82
|
+
protected constructor(extensionType: ExtType, manifest: Manifest) {
|
|
93
83
|
this.extensionType = extensionType;
|
|
94
|
-
this.installedExtensions = manifest.getExtensionData(extensionType);
|
|
95
84
|
this.manifest = manifest;
|
|
85
|
+
this.installedExtensions = manifest.getExtensionData(extensionType);
|
|
96
86
|
}
|
|
97
87
|
|
|
98
|
-
|
|
88
|
+
/** Path to `extensions.yaml` after the manifest has been read; otherwise undefined. */
|
|
89
|
+
get manifestPath(): string | undefined {
|
|
99
90
|
return this.manifest.manifestPath;
|
|
100
91
|
}
|
|
101
92
|
|
|
102
|
-
|
|
93
|
+
/** `APPIUM_HOME` directory this config is tied to. */
|
|
94
|
+
get appiumHome(): string {
|
|
103
95
|
return this.manifest.appiumHome;
|
|
104
96
|
}
|
|
105
97
|
|
|
106
98
|
/**
|
|
107
|
-
*
|
|
99
|
+
* Type guard: manifest entry includes a `schema` path or inline schema object.
|
|
100
|
+
*
|
|
101
|
+
* @param extManifest - Parsed extension metadata
|
|
102
|
+
*/
|
|
103
|
+
static extDataHasSchema<E extends ExtensionType>(
|
|
104
|
+
extManifest: ExtManifest<E>
|
|
105
|
+
): extManifest is ExtManifestWithSchema<E> {
|
|
106
|
+
return _.isString(extManifest?.schema) || _.isObject(extManifest?.schema);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private static async _readExtensionSchema<E extends ExtensionType>(
|
|
110
|
+
appiumHome: string,
|
|
111
|
+
extType: E,
|
|
112
|
+
extName: string,
|
|
113
|
+
extManifest: ExtManifestWithSchema<E>
|
|
114
|
+
): Promise<SchemaObject | undefined> {
|
|
115
|
+
const {pkgName, schema: argSchemaPath} = extManifest;
|
|
116
|
+
if (!argSchemaPath) {
|
|
117
|
+
throw new TypeError(
|
|
118
|
+
`No \`schema\` property found in config for ${extType} ${pkgName} -- why is this function being called?`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
let moduleObject: any;
|
|
122
|
+
if (_.isString(argSchemaPath)) {
|
|
123
|
+
const schemaPath = resolveFrom(appiumHome, path.join(pkgName, argSchemaPath));
|
|
124
|
+
moduleObject = require(schemaPath);
|
|
125
|
+
} else {
|
|
126
|
+
moduleObject = argSchemaPath;
|
|
127
|
+
}
|
|
128
|
+
// this sucks. default exports should be destroyed
|
|
129
|
+
const schema = moduleObject.__esModule ? moduleObject.default : moduleObject;
|
|
130
|
+
await registerSchema(extType, extName, schema as SchemaObject);
|
|
131
|
+
return schema;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Collects blocking validation issues for one extension (generic fields, type-specific rules, and schema).
|
|
108
136
|
*
|
|
109
|
-
* @param
|
|
110
|
-
* @param
|
|
111
|
-
* @returns {ExtManifestProblem[]}
|
|
137
|
+
* @param extName - Extension key as stored in the manifest
|
|
138
|
+
* @param extManifest - Manifest entry for that extension
|
|
112
139
|
*/
|
|
113
|
-
getProblems(extName, extManifest) {
|
|
140
|
+
async getProblems(extName: string, extManifest: ExtManifest<ExtType>): Promise<ExtManifestProblem[]> {
|
|
114
141
|
return [
|
|
115
142
|
...this.getGenericConfigProblems(extManifest, extName),
|
|
116
143
|
...this.getConfigProblems(extManifest, extName),
|
|
117
|
-
...this.getSchemaProblems(extManifest, extName),
|
|
144
|
+
...(await this.getSchemaProblems(extManifest, extName)),
|
|
118
145
|
];
|
|
119
146
|
}
|
|
120
147
|
|
|
121
148
|
/**
|
|
122
|
-
*
|
|
149
|
+
* Collects non-fatal issues for one extension (e.g. manifest quirks, peer dependency mismatches).
|
|
150
|
+
* Warnings do not by themselves prevent loading.
|
|
123
151
|
*
|
|
124
|
-
* @param
|
|
125
|
-
* @param
|
|
126
|
-
* @returns {Promise<string[]>}
|
|
152
|
+
* @param extName - Extension key as stored in the manifest
|
|
153
|
+
* @param extManifest - Manifest entry for that extension
|
|
127
154
|
*/
|
|
128
|
-
async getWarnings(extName, extManifest) {
|
|
155
|
+
async getWarnings(extName: string, extManifest: ExtManifest<ExtType>): Promise<string[]> {
|
|
129
156
|
const [genericConfigWarnings, configWarnings] = await B.all([
|
|
130
157
|
this.getGenericConfigWarnings(extManifest, extName),
|
|
131
158
|
this.getConfigWarnings(extManifest, extName),
|
|
@@ -135,28 +162,16 @@ export class ExtensionConfig {
|
|
|
135
162
|
}
|
|
136
163
|
|
|
137
164
|
/**
|
|
138
|
-
*
|
|
139
|
-
* @abstract
|
|
140
|
-
* @param {ExtManifest<ExtType>} extManifest
|
|
141
|
-
* @param {ExtName<ExtType>} extName
|
|
142
|
-
* @returns {Promise<string[]>}
|
|
143
|
-
*/
|
|
144
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
145
|
-
async getConfigWarnings(extManifest, extName) {
|
|
146
|
-
return [];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
165
|
+
* Turns per-extension errors and warnings into human-readable log lines for console output.
|
|
150
166
|
*
|
|
151
|
-
* @param
|
|
152
|
-
* @param
|
|
167
|
+
* @param errorMap - Extension name to list of blocking problems
|
|
168
|
+
* @param warningMap - Extension name to list of warning strings
|
|
153
169
|
*/
|
|
154
|
-
getValidationResultSummaries(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const errorSummaries = [];
|
|
170
|
+
getValidationResultSummaries(
|
|
171
|
+
errorMap: Map<string, ExtManifestProblem[]> = new Map(),
|
|
172
|
+
warningMap: Map<string, string[]> = new Map()
|
|
173
|
+
): {errorSummaries: string[]; warningSummaries: string[]} {
|
|
174
|
+
const errorSummaries: string[] = [];
|
|
160
175
|
for (const [extName, problems] of errorMap.entries()) {
|
|
161
176
|
if (_.isEmpty(problems)) {
|
|
162
177
|
continue;
|
|
@@ -174,8 +189,7 @@ export class ExtensionConfig {
|
|
|
174
189
|
);
|
|
175
190
|
}
|
|
176
191
|
}
|
|
177
|
-
|
|
178
|
-
const warningSummaries = [];
|
|
192
|
+
const warningSummaries: string[] = [];
|
|
179
193
|
for (const [extName, warnings] of warningMap.entries()) {
|
|
180
194
|
if (_.isEmpty(warnings)) {
|
|
181
195
|
continue;
|
|
@@ -192,27 +206,157 @@ export class ExtensionConfig {
|
|
|
192
206
|
}
|
|
193
207
|
|
|
194
208
|
/**
|
|
195
|
-
*
|
|
209
|
+
* Records a new installed extension in the manifest and optionally persists immediately.
|
|
196
210
|
*
|
|
197
|
-
*
|
|
211
|
+
* @param extName - Manifest key for the extension
|
|
212
|
+
* @param extManifest - Full manifest payload
|
|
198
213
|
*
|
|
199
|
-
*
|
|
214
|
+
* Pass `{ write: false }` to defer flushing until a later manifest write.
|
|
215
|
+
*/
|
|
216
|
+
async addExtension(
|
|
217
|
+
extName: string,
|
|
218
|
+
extManifest: ExtManifest<ExtType>,
|
|
219
|
+
{write = true}: ExtensionConfigMutationOpts = {}
|
|
220
|
+
): Promise<void> {
|
|
221
|
+
this.manifest.setExtension(this.extensionType, extName, extManifest);
|
|
222
|
+
if (write) {
|
|
223
|
+
await this.manifest.write();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Merges new metadata into an existing extension entry and optionally writes the manifest.
|
|
200
229
|
*
|
|
201
|
-
* @
|
|
202
|
-
* @param
|
|
203
|
-
*
|
|
230
|
+
* @param extName - Installed extension to update
|
|
231
|
+
* @param extManifest - Fields to merge over the current entry
|
|
232
|
+
*
|
|
233
|
+
* Pass `{ write: false }` to defer flushing until a later manifest write.
|
|
204
234
|
*/
|
|
205
|
-
async
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
235
|
+
async updateExtension(
|
|
236
|
+
extName: ExtName<ExtType>,
|
|
237
|
+
extManifest: ExtManifest<ExtType>,
|
|
238
|
+
{write = true}: ExtensionConfigMutationOpts = {}
|
|
239
|
+
): Promise<void> {
|
|
240
|
+
const existing = this.installedExtensions[extName];
|
|
241
|
+
this.manifest.setExtension(this.extensionType, extName as string, {
|
|
242
|
+
...existing,
|
|
243
|
+
...extManifest,
|
|
244
|
+
});
|
|
245
|
+
if (write) {
|
|
246
|
+
await this.manifest.write();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Drops an extension from the manifest and optionally persists immediately.
|
|
252
|
+
*
|
|
253
|
+
* @param extName - Installed extension to remove
|
|
254
|
+
*
|
|
255
|
+
* Pass `{ write: false }` to defer flushing until a later manifest write.
|
|
256
|
+
*/
|
|
257
|
+
async removeExtension(
|
|
258
|
+
extName: ExtName<ExtType>,
|
|
259
|
+
{write = true}: ExtensionConfigMutationOpts = {}
|
|
260
|
+
): Promise<void> {
|
|
261
|
+
this.manifest.deleteExtension(this.extensionType, extName);
|
|
262
|
+
if (write) {
|
|
263
|
+
await this.manifest.write();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Logs installed extensions to the console. Subclasses may use `activeNames` to annotate active plugins.
|
|
269
|
+
*/
|
|
270
|
+
print(_activeNames?: ExtName<ExtType>[]): void {
|
|
271
|
+
void _activeNames;
|
|
272
|
+
if (_.isEmpty(this.installedExtensions)) {
|
|
273
|
+
log.info(
|
|
274
|
+
`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.'
|
|
276
|
+
);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
log.info(`Available ${this.extensionType}s:`);
|
|
281
|
+
for (const [extName, extManifest] of _.toPairs(this.installedExtensions) as Array<
|
|
282
|
+
[string, ExtManifest<ExtType>]
|
|
283
|
+
>) {
|
|
284
|
+
log.info(` - ${this.extensionDesc(extName, extManifest)}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Root directory of an installed extension, preferring `installPath` and falling back to `node_modules/<pkgName>`.
|
|
290
|
+
*
|
|
291
|
+
* @param extName - Installed extension key
|
|
292
|
+
*/
|
|
293
|
+
getInstallPath(extName: keyof ExtRecord<ExtType> & string): string {
|
|
294
|
+
return (
|
|
295
|
+
this.installedExtensions[extName]?.installPath ??
|
|
296
|
+
path.join(this.appiumHome, 'node_modules', this.installedExtensions[extName].pkgName)
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Dynamically imports the extension entry point and returns the exported main class constructor.
|
|
302
|
+
*
|
|
303
|
+
* @param extName - Installed extension to load
|
|
304
|
+
*/
|
|
305
|
+
async requireAsync(extName: ExtName<ExtType>): Promise<ExtClass<ExtType>> {
|
|
306
|
+
const [reqPath, mainClass] = await this._resolveExtension(extName);
|
|
307
|
+
log.debug(`Requiring ${this.extensionType} at ${reqPath}`);
|
|
308
|
+
// https://github.com/nodejs/node/issues/31710
|
|
309
|
+
const importPath = system.isWindows() ? pathToFileURL(reqPath).href : reqPath;
|
|
310
|
+
const mod = (await import(importPath)) as Record<string, ExtClass<ExtType>>;
|
|
311
|
+
const MainClass = mod[mainClass];
|
|
312
|
+
if (!MainClass) {
|
|
313
|
+
throw new ReferenceError(
|
|
314
|
+
`Could not find a class named "${mainClass}" exported by ${this.extensionType} "${extName}"`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return MainClass;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Whether the manifest lists an extension under the given name. */
|
|
321
|
+
isInstalled(extName: string): boolean {
|
|
322
|
+
return extName in this.installedExtensions;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Loads the extension’s config schema from disk or inline JSON and registers it for CLI/config validation.
|
|
327
|
+
*
|
|
328
|
+
* @param extName - Extension key
|
|
329
|
+
* @param extManifest - Manifest entry that includes `schema`
|
|
330
|
+
*/
|
|
331
|
+
async readExtensionSchema(
|
|
332
|
+
extName: string,
|
|
333
|
+
extManifest: ExtManifestWithSchema<ExtType>
|
|
334
|
+
): Promise<SchemaObject | undefined> {
|
|
335
|
+
return await ExtensionConfig._readExtensionSchema(
|
|
336
|
+
this.appiumHome,
|
|
337
|
+
this.extensionType,
|
|
338
|
+
extName,
|
|
339
|
+
extManifest
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Optional async warnings for this extension kind; override in subclasses when needed. */
|
|
344
|
+
protected async getConfigWarnings(
|
|
345
|
+
_extManifest: ExtManifest<ExtType>,
|
|
346
|
+
_extName: string
|
|
347
|
+
): Promise<string[]> {
|
|
348
|
+
void _extManifest;
|
|
349
|
+
void _extName;
|
|
350
|
+
return [];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Validates all entries in `exts`, logs summaries, and removes keys that have blocking errors.
|
|
355
|
+
* Intended for subclasses’ `validate` implementation.
|
|
356
|
+
*/
|
|
357
|
+
protected async _validate(exts: ExtRecord<ExtType>): Promise<ExtRecord<ExtType>> {
|
|
358
|
+
const errorMap = new Map<string, ExtManifestProblem[]>();
|
|
359
|
+
const warningMap = new Map<string, string[]>();
|
|
216
360
|
|
|
217
361
|
for (const [extName, extManifest] of _.toPairs(exts)) {
|
|
218
362
|
const [errors, warnings] = await B.all([
|
|
@@ -257,18 +401,13 @@ export class ExtensionConfig {
|
|
|
257
401
|
}
|
|
258
402
|
|
|
259
403
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
* This is an expensive operation, so the result is cached. Currently, there is no
|
|
263
|
-
* use case for invalidating the cache.
|
|
264
|
-
* @protected
|
|
265
|
-
* @returns {Promise<import('../cli/extension-command').ExtensionList<ExtType>>}
|
|
404
|
+
* Fetches `appium driver|plugin list`-style data via the CLI command class; result is cached.
|
|
266
405
|
*/
|
|
267
|
-
async getListData() {
|
|
406
|
+
protected async getListData(): Promise<ExtensionList<ExtType>> {
|
|
268
407
|
if (this.#listDataCache) {
|
|
269
408
|
return this.#listDataCache;
|
|
270
409
|
}
|
|
271
|
-
const CommandClass =
|
|
410
|
+
const CommandClass = commandClasses[this.extensionType] as ExtCommand<ExtType>;
|
|
272
411
|
const cmd = new CommandClass({config: this, json: true});
|
|
273
412
|
const listData = await cmd.list({showInstalled: true, showUpdates: true});
|
|
274
413
|
this.#listDataCache = listData;
|
|
@@ -276,20 +415,16 @@ export class ExtensionConfig {
|
|
|
276
415
|
}
|
|
277
416
|
|
|
278
417
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* By definition, a non-empty list of warnings does _not_ imply the extension cannot be loaded,
|
|
282
|
-
* but it may not work as expected or otherwise throw an exception at runtime.
|
|
283
|
-
*
|
|
284
|
-
* @param {ExtManifest<ExtType>} extManifest
|
|
285
|
-
* @param {ExtName<ExtType>} extName
|
|
286
|
-
* @returns {Promise<string[]>}
|
|
418
|
+
* Warnings about manifest install fields and Appium peer dependency compatibility for one extension.
|
|
287
419
|
*/
|
|
288
|
-
async getGenericConfigWarnings(
|
|
420
|
+
protected async getGenericConfigWarnings(
|
|
421
|
+
extManifest: ExtManifest<ExtType>,
|
|
422
|
+
extName: string
|
|
423
|
+
): Promise<string[]> {
|
|
289
424
|
const {appiumVersion, installSpec, installType, pkgName} = extManifest;
|
|
290
|
-
const warnings = [];
|
|
425
|
+
const warnings: string[] = [];
|
|
291
426
|
|
|
292
|
-
const invalidFields = [];
|
|
427
|
+
const invalidFields: string[] = [];
|
|
293
428
|
if (!_.isString(installSpec)) {
|
|
294
429
|
invalidFields.push('installSpec');
|
|
295
430
|
}
|
|
@@ -315,20 +450,12 @@ export class ExtensionConfig {
|
|
|
315
450
|
);
|
|
316
451
|
}
|
|
317
452
|
|
|
318
|
-
|
|
319
|
-
* Helps concatenate warning messages related to peer dependencies
|
|
320
|
-
* @param {string} reason
|
|
321
|
-
* @returns string
|
|
322
|
-
*/
|
|
323
|
-
const createPeerWarning = (reason) =>
|
|
453
|
+
const createPeerWarning = (reason: string): string =>
|
|
324
454
|
`${extTypeText} "${extName}" (package \`${pkgName}\`) may be incompatible with the current version of Appium (v${APPIUM_VER}) due to ${reason}`;
|
|
325
455
|
|
|
326
456
|
if (_.isString(appiumVersion) && !satisfies(APPIUM_VER, appiumVersion)) {
|
|
327
457
|
const listData = await this.getListData();
|
|
328
|
-
const extListData =
|
|
329
|
-
/** @type {import('../cli/extension-command').ExtensionListData<ExtType>} */ (
|
|
330
|
-
listData[extName]
|
|
331
|
-
);
|
|
458
|
+
const extListData = listData[extName] as ExtensionListData<ExtType> | undefined;
|
|
332
459
|
if (extListData?.installed) {
|
|
333
460
|
const {updateVersion, upToDate} = extListData;
|
|
334
461
|
if (!upToDate && updateVersion) {
|
|
@@ -347,10 +474,7 @@ export class ExtensionConfig {
|
|
|
347
474
|
}
|
|
348
475
|
} else if (!_.isString(appiumVersion)) {
|
|
349
476
|
const listData = await this.getListData();
|
|
350
|
-
const extListData =
|
|
351
|
-
/** @type {import('../cli/extension-command').InstalledExtensionListData<ExtType>} */ (
|
|
352
|
-
listData[extName]
|
|
353
|
-
);
|
|
477
|
+
const extListData = listData[extName] as InstalledExtensionListData<ExtType> | undefined;
|
|
354
478
|
if (!extListData?.upToDate && extListData?.updateVersion) {
|
|
355
479
|
warnings.push(
|
|
356
480
|
createPeerWarning(
|
|
@@ -369,23 +493,20 @@ export class ExtensionConfig {
|
|
|
369
493
|
}
|
|
370
494
|
return warnings;
|
|
371
495
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
getSchemaProblems(extManifest, extName) {
|
|
380
|
-
/** @type {ExtManifestProblem[]} */
|
|
381
|
-
const problems = [];
|
|
496
|
+
|
|
497
|
+
/** Validates and registers extension CLI/config schema when the manifest defines a `schema` field. */
|
|
498
|
+
protected async getSchemaProblems(
|
|
499
|
+
extManifest: ExtManifest<ExtType>,
|
|
500
|
+
extName: string
|
|
501
|
+
): Promise<ExtManifestProblem[]> {
|
|
502
|
+
const problems: ExtManifestProblem[] = [];
|
|
382
503
|
const {schema: argSchemaPath} = extManifest;
|
|
383
504
|
if (ExtensionConfig.extDataHasSchema(extManifest)) {
|
|
384
505
|
if (_.isString(argSchemaPath)) {
|
|
385
506
|
if (isAllowedSchemaFileExtension(argSchemaPath)) {
|
|
386
507
|
try {
|
|
387
|
-
this.readExtensionSchema(extName, extManifest);
|
|
388
|
-
} catch (err) {
|
|
508
|
+
await this.readExtensionSchema(extName, extManifest);
|
|
509
|
+
} catch (err: any) {
|
|
389
510
|
problems.push({
|
|
390
511
|
err: `Unable to register schema at path ${argSchemaPath}; ${err.message}`,
|
|
391
512
|
val: argSchemaPath,
|
|
@@ -401,8 +522,8 @@ export class ExtensionConfig {
|
|
|
401
522
|
}
|
|
402
523
|
} else if (_.isPlainObject(argSchemaPath)) {
|
|
403
524
|
try {
|
|
404
|
-
this.readExtensionSchema(extName, extManifest);
|
|
405
|
-
} catch (err) {
|
|
525
|
+
await this.readExtensionSchema(extName, extManifest);
|
|
526
|
+
} catch (err: any) {
|
|
406
527
|
problems.push({
|
|
407
528
|
err: `Unable to register embedded schema; ${err.message}`,
|
|
408
529
|
val: argSchemaPath,
|
|
@@ -418,16 +539,14 @@ export class ExtensionConfig {
|
|
|
418
539
|
return problems;
|
|
419
540
|
}
|
|
420
541
|
|
|
421
|
-
/**
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
428
|
-
getGenericConfigProblems(extManifest, extName) {
|
|
542
|
+
/** Blocking issues for required manifest fields shared by all extensions (version, package name, main class). */
|
|
543
|
+
protected getGenericConfigProblems(
|
|
544
|
+
extManifest: ExtManifest<ExtType>,
|
|
545
|
+
extName: string
|
|
546
|
+
): ExtManifestProblem[] {
|
|
547
|
+
void extName;
|
|
429
548
|
const {version, pkgName, mainClass} = extManifest;
|
|
430
|
-
const problems = [];
|
|
549
|
+
const problems: ExtManifestProblem[] = [];
|
|
431
550
|
|
|
432
551
|
if (!_.isString(version)) {
|
|
433
552
|
problems.push({
|
|
@@ -453,139 +572,40 @@ export class ExtensionConfig {
|
|
|
453
572
|
return problems;
|
|
454
573
|
}
|
|
455
574
|
|
|
456
|
-
/**
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
getConfigProblems(extManifest, extName) {
|
|
464
|
-
// should override this method if special validation is necessary for this extension type
|
|
575
|
+
/** Driver- or plugin-specific blocking validation; override in subclasses when needed. */
|
|
576
|
+
protected getConfigProblems(
|
|
577
|
+
_extManifest: ExtManifest<ExtType>,
|
|
578
|
+
_extName: string
|
|
579
|
+
): ExtManifestProblem[] {
|
|
580
|
+
void _extManifest;
|
|
581
|
+
void _extName;
|
|
465
582
|
return [];
|
|
466
583
|
}
|
|
467
584
|
|
|
468
|
-
|
|
469
|
-
* @param {string} extName
|
|
470
|
-
* @param {ExtManifest<ExtType>} extManifest
|
|
471
|
-
* @param {ExtensionConfigMutationOpts} opts
|
|
472
|
-
* @returns {Promise<void>}
|
|
473
|
-
*/
|
|
474
|
-
async addExtension(extName, extManifest, {write = true} = {}) {
|
|
475
|
-
this.manifest.setExtension(this.extensionType, extName, extManifest);
|
|
476
|
-
if (write) {
|
|
477
|
-
await this.manifest.write();
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* @param {ExtName<ExtType>} extName
|
|
483
|
-
* @param {ExtManifest<ExtType>} extManifest
|
|
484
|
-
* @param {ExtensionConfigMutationOpts} opts
|
|
485
|
-
* @returns {Promise<void>}
|
|
486
|
-
*/
|
|
487
|
-
async updateExtension(extName, extManifest, {write = true} = {}) {
|
|
488
|
-
this.manifest.setExtension(this.extensionType, extName, {
|
|
489
|
-
...this.installedExtensions[extName],
|
|
490
|
-
...extManifest,
|
|
491
|
-
});
|
|
492
|
-
if (write) {
|
|
493
|
-
await this.manifest.write();
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* Remove an extension from the list of installed extensions, and optionally avoid a write to the manifest file.
|
|
499
|
-
*
|
|
500
|
-
* @param {ExtName<ExtType>} extName
|
|
501
|
-
* @param {ExtensionConfigMutationOpts} opts
|
|
502
|
-
* @returns {Promise<void>}
|
|
503
|
-
*/
|
|
504
|
-
async removeExtension(extName, {write = true} = {}) {
|
|
505
|
-
this.manifest.deleteExtension(this.extensionType, extName);
|
|
506
|
-
if (write) {
|
|
507
|
-
await this.manifest.write();
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* @param {ExtName<ExtType>[]} [activeNames]
|
|
513
|
-
* @returns {void}
|
|
514
|
-
*/
|
|
515
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
516
|
-
print(activeNames) {
|
|
517
|
-
if (_.isEmpty(this.installedExtensions)) {
|
|
518
|
-
log.info(
|
|
519
|
-
`No ${this.extensionType}s have been installed in ${this.appiumHome}. Use the "appium ${this.extensionType}" ` +
|
|
520
|
-
'command to install the one(s) you want to use.'
|
|
521
|
-
);
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
log.info(`Available ${this.extensionType}s:`);
|
|
526
|
-
for (const [extName, extManifest] of /** @type {[string, ExtManifest<ExtType>][]} */ (
|
|
527
|
-
_.toPairs(this.installedExtensions)
|
|
528
|
-
)) {
|
|
529
|
-
log.info(` - ${this.extensionDesc(extName, extManifest)}`);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* Returns a string describing the extension. Subclasses must implement.
|
|
535
|
-
* @param {ExtName<ExtType>} extName - Extension name
|
|
536
|
-
* @param {ExtManifest<ExtType>} extManifest - Extension data
|
|
537
|
-
* @returns {string}
|
|
538
|
-
* @abstract
|
|
539
|
-
*/
|
|
540
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
541
|
-
extensionDesc(extName, extManifest) {
|
|
542
|
-
throw new Error('This must be implemented in a subclass');
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* Returns--with reasonable accuracy--the path on disk to the extension.
|
|
547
|
-
*
|
|
548
|
-
* If `installPath` is present in the manifest, then it is used; otherwise we just guess.
|
|
549
|
-
* @param {keyof typeof this.installedExtensions} extName
|
|
550
|
-
* @returns {string}
|
|
551
|
-
*/
|
|
552
|
-
getInstallPath(extName) {
|
|
553
|
-
return (
|
|
554
|
-
this.installedExtensions[extName]?.installPath ??
|
|
555
|
-
path.join(this.appiumHome, 'node_modules', this.installedExtensions[extName].pkgName)
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
/**
|
|
560
|
-
*
|
|
561
|
-
* @param {ExtName<ExtType>} extName
|
|
562
|
-
* @returns {Promise<[string, string]>}
|
|
563
|
-
*/
|
|
564
|
-
async _resolveExtension(extName) {
|
|
585
|
+
private async _resolveExtension(extName: ExtName<ExtType>): Promise<[string, string]> {
|
|
565
586
|
const {mainClass} = this.installedExtensions[extName];
|
|
566
587
|
const moduleRoot = this.getInstallPath(extName);
|
|
567
588
|
const packageJsonPath = path.join(moduleRoot, 'package.json');
|
|
568
|
-
let extensionManifest
|
|
589
|
+
let extensionManifest: Record<string, any>;
|
|
569
590
|
try {
|
|
570
591
|
extensionManifest = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
571
|
-
} catch (e) {
|
|
592
|
+
} catch (e: any) {
|
|
572
593
|
throw new ReferenceError(
|
|
573
594
|
`Could not read the ${this.extensionType} manifest at ${packageJsonPath}: ${e.message}`
|
|
574
595
|
);
|
|
575
596
|
}
|
|
576
|
-
|
|
577
|
-
let entryPointRelativePath;
|
|
597
|
+
let entryPointRelativePath: string | undefined;
|
|
578
598
|
try {
|
|
579
599
|
if (extensionManifest.type === 'module' && extensionManifest.exports) {
|
|
580
600
|
entryPointRelativePath = resolveEsmEntryPoint(extensionManifest.exports);
|
|
581
601
|
}
|
|
582
602
|
entryPointRelativePath = entryPointRelativePath ?? extensionManifest.main ?? DEFAULT_ENTRY_POINT;
|
|
583
|
-
} catch (e) {
|
|
603
|
+
} catch (e: any) {
|
|
584
604
|
throw new ReferenceError(
|
|
585
605
|
`Could not find the ${this.extensionType} installed at ${moduleRoot}: ${e.message}`
|
|
586
606
|
);
|
|
587
607
|
}
|
|
588
|
-
const entryPointFullPath = path.resolve(moduleRoot,
|
|
608
|
+
const entryPointFullPath = path.resolve(moduleRoot, entryPointRelativePath as string);
|
|
589
609
|
if (!await fs.exists(entryPointFullPath)) {
|
|
590
610
|
throw new ReferenceError(
|
|
591
611
|
`Cannot find a valid ${this.extensionType} main entry point in '${packageJsonPath}'. ` +
|
|
@@ -601,98 +621,21 @@ export class ExtensionConfig {
|
|
|
601
621
|
}
|
|
602
622
|
|
|
603
623
|
/**
|
|
604
|
-
*
|
|
624
|
+
* One-line human description for list output; implemented per extension kind.
|
|
605
625
|
*
|
|
606
|
-
* @param
|
|
607
|
-
* @
|
|
608
|
-
*/
|
|
609
|
-
async requireAsync(extName) {
|
|
610
|
-
const [reqPath, mainClass] = await this._resolveExtension(extName);
|
|
611
|
-
log.debug(`Requiring ${this.extensionType} at ${reqPath}`);
|
|
612
|
-
// https://github.com/nodejs/node/issues/31710
|
|
613
|
-
const importPath = system.isWindows() ? pathToFileURL(reqPath).href : reqPath;
|
|
614
|
-
const MainClass = (await import(importPath))[mainClass];
|
|
615
|
-
if (!MainClass) {
|
|
616
|
-
throw new ReferenceError(
|
|
617
|
-
`Could not find a class named "${mainClass}" exported by ${this.extensionType} "${extName}"`
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
return MainClass;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* @param {string} extName
|
|
625
|
-
* @returns {boolean}
|
|
626
|
+
* @param extName - Manifest key
|
|
627
|
+
* @param extManifest - Entry used for version and kind-specific labels
|
|
626
628
|
*/
|
|
627
|
-
|
|
628
|
-
return extName in this.installedExtensions;
|
|
629
|
-
}
|
|
629
|
+
public abstract extensionDesc(extName: ExtName<ExtType>, extManifest: ExtManifest<ExtType>): string;
|
|
630
630
|
|
|
631
|
-
/**
|
|
632
|
-
* Intended to be called by corresponding instance methods of subclass.
|
|
633
|
-
* @private
|
|
634
|
-
* @template {ExtensionType} ExtType
|
|
635
|
-
* @param {string} appiumHome
|
|
636
|
-
* @param {ExtType} extType
|
|
637
|
-
* @param {ExtName<ExtType>} extName - Extension name (unique to its type)
|
|
638
|
-
* @param {ExtManifestWithSchema<ExtType>} extManifest - Extension config
|
|
639
|
-
* @returns {import('ajv').SchemaObject|undefined}
|
|
640
|
-
*/
|
|
641
|
-
static _readExtensionSchema(appiumHome, extType, extName, extManifest) {
|
|
642
|
-
const {pkgName, schema: argSchemaPath} = extManifest;
|
|
643
|
-
if (!argSchemaPath) {
|
|
644
|
-
throw new TypeError(
|
|
645
|
-
`No \`schema\` property found in config for ${extType} ${pkgName} -- why is this function being called?`
|
|
646
|
-
);
|
|
647
|
-
}
|
|
648
|
-
let moduleObject;
|
|
649
|
-
if (_.isString(argSchemaPath)) {
|
|
650
|
-
const schemaPath = resolveFrom(appiumHome, path.join(pkgName, argSchemaPath));
|
|
651
|
-
moduleObject = require(schemaPath);
|
|
652
|
-
} else {
|
|
653
|
-
moduleObject = argSchemaPath;
|
|
654
|
-
}
|
|
655
|
-
// this sucks. default exports should be destroyed
|
|
656
|
-
const schema = moduleObject.__esModule ? moduleObject.default : moduleObject;
|
|
657
|
-
registerSchema(extType, extName, schema);
|
|
658
|
-
return schema;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Returns `true` if a specific {@link ExtManifest} object has a `schema` prop.
|
|
663
|
-
* The {@link ExtManifest} object becomes a {@link ExtManifestWithSchema} object.
|
|
664
|
-
* @template {ExtensionType} ExtType
|
|
665
|
-
* @param {ExtManifest<ExtType>} extManifest
|
|
666
|
-
* @returns {extManifest is ExtManifestWithSchema<ExtType>}
|
|
667
|
-
*/
|
|
668
|
-
static extDataHasSchema(extManifest) {
|
|
669
|
-
return _.isString(extManifest?.schema) || _.isObject(extManifest?.schema);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* If an extension provides a schema, this will load the schema and attempt to
|
|
674
|
-
* register it with the schema registrar.
|
|
675
|
-
* @param {ExtName<ExtType>} extName - Name of extension
|
|
676
|
-
* @param {ExtManifestWithSchema<ExtType>} extManifest - Extension data
|
|
677
|
-
* @returns {import('ajv').SchemaObject|undefined}
|
|
678
|
-
*/
|
|
679
|
-
readExtensionSchema(extName, extManifest) {
|
|
680
|
-
return ExtensionConfig._readExtensionSchema(
|
|
681
|
-
this.appiumHome,
|
|
682
|
-
this.extensionType,
|
|
683
|
-
extName,
|
|
684
|
-
extManifest
|
|
685
|
-
);
|
|
686
|
-
}
|
|
687
631
|
}
|
|
688
632
|
|
|
689
633
|
/**
|
|
690
|
-
*
|
|
634
|
+
* Resolves a package `exports` field (string, `"."`, or `"import"`) to a relative entry path for ESM packages.
|
|
691
635
|
*
|
|
692
|
-
* @param
|
|
693
|
-
* @returns {string | undefined}
|
|
636
|
+
* @param exportsValue - `package.json` `exports` value or nested fragment
|
|
694
637
|
*/
|
|
695
|
-
export function resolveEsmEntryPoint(exportsValue) {
|
|
638
|
+
export function resolveEsmEntryPoint(exportsValue: unknown): string | undefined {
|
|
696
639
|
if (_.isString(exportsValue) && exportsValue) {
|
|
697
640
|
return exportsValue;
|
|
698
641
|
}
|
|
@@ -700,67 +643,10 @@ export function resolveEsmEntryPoint(exportsValue) {
|
|
|
700
643
|
return;
|
|
701
644
|
}
|
|
702
645
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
646
|
+
const obj = exportsValue as Record<string, unknown>;
|
|
647
|
+
for (const key of ['.', 'import'] as const) {
|
|
648
|
+
if (obj[key]) {
|
|
649
|
+
return resolveEsmEntryPoint(obj[key]);
|
|
706
650
|
}
|
|
707
651
|
}
|
|
708
652
|
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* An issue with the {@linkcode ExtManifest} for a particular extension.
|
|
712
|
-
*
|
|
713
|
-
* The existance of such an object implies that the extension cannot be loaded.
|
|
714
|
-
* @typedef ExtManifestProblem
|
|
715
|
-
* @property {string} err - Error message
|
|
716
|
-
* @property {any} val - Associated value
|
|
717
|
-
*/
|
|
718
|
-
|
|
719
|
-
/**
|
|
720
|
-
* An optional logging function provided to an {@link ExtensionConfig} subclass.
|
|
721
|
-
* @callback ExtensionLogFn
|
|
722
|
-
* @param {...any} args
|
|
723
|
-
* @returns {void}
|
|
724
|
-
*/
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
* @typedef {import('@appium/types').ExtensionType} ExtensionType
|
|
728
|
-
* @typedef {import('./manifest').Manifest} Manifest
|
|
729
|
-
* @typedef {import('appium/types').InstallType} InstallType
|
|
730
|
-
*/
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* @template {ExtensionType} ExtType
|
|
734
|
-
* @typedef {import('appium/types').ExtManifest<ExtType>} ExtManifest
|
|
735
|
-
*/
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* @template {ExtensionType} ExtType
|
|
739
|
-
* @typedef {ExtManifest<ExtType> & {schema: NonNullable<ExtManifest<ExtType>['schema']>}} ExtManifestWithSchema
|
|
740
|
-
*/
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* @template {ExtensionType} ExtType
|
|
744
|
-
* @typedef {import('appium/types').ExtName<ExtType>} ExtName
|
|
745
|
-
*/
|
|
746
|
-
|
|
747
|
-
/**
|
|
748
|
-
* @template {ExtensionType} ExtType
|
|
749
|
-
* @typedef {import('appium/types').ExtClass<ExtType>} ExtClass
|
|
750
|
-
*/
|
|
751
|
-
|
|
752
|
-
/**
|
|
753
|
-
* @template {ExtensionType} ExtType
|
|
754
|
-
* @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
|
|
755
|
-
*/
|
|
756
|
-
|
|
757
|
-
/**
|
|
758
|
-
* @template {ExtensionType} ExtType
|
|
759
|
-
* @typedef {import('../cli/extension').ExtCommand<ExtType>} ExtCommand
|
|
760
|
-
*/
|
|
761
|
-
|
|
762
|
-
/**
|
|
763
|
-
* Options for various methods in {@link ExtensionConfig}
|
|
764
|
-
* @typedef ExtensionConfigMutationOpts
|
|
765
|
-
* @property {boolean} [write=true] Whether or not to write the manifest to disk after a mutation operation
|
|
766
|
-
*/
|