appium 2.0.0-beta.46 → 2.0.0-beta.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +145 -44
  2. package/build/lib/appium.d.ts +3 -103
  3. package/build/lib/appium.d.ts.map +1 -1
  4. package/build/lib/appium.js +679 -549
  5. package/build/lib/appium.js.map +1 -1
  6. package/build/lib/cli/args.js +247 -127
  7. package/build/lib/cli/args.js.map +1 -1
  8. package/build/lib/cli/driver-command.js +63 -88
  9. package/build/lib/cli/driver-command.js.map +1 -1
  10. package/build/lib/cli/extension-command.d.ts +32 -23
  11. package/build/lib/cli/extension-command.d.ts.map +1 -1
  12. package/build/lib/cli/extension-command.js +730 -512
  13. package/build/lib/cli/extension-command.js.map +1 -1
  14. package/build/lib/cli/extension.d.ts +7 -6
  15. package/build/lib/cli/extension.d.ts.map +1 -1
  16. package/build/lib/cli/extension.js +68 -65
  17. package/build/lib/cli/extension.js.map +1 -1
  18. package/build/lib/cli/parser.d.ts +3 -3
  19. package/build/lib/cli/parser.d.ts.map +1 -1
  20. package/build/lib/cli/parser.js +234 -192
  21. package/build/lib/cli/parser.js.map +1 -1
  22. package/build/lib/cli/plugin-command.js +58 -87
  23. package/build/lib/cli/plugin-command.js.map +1 -1
  24. package/build/lib/cli/utils.js +66 -69
  25. package/build/lib/cli/utils.js.map +1 -1
  26. package/build/lib/config-file.d.ts.map +1 -1
  27. package/build/lib/config-file.js +189 -120
  28. package/build/lib/config-file.js.map +1 -1
  29. package/build/lib/config.d.ts.map +1 -1
  30. package/build/lib/config.js +254 -213
  31. package/build/lib/config.js.map +1 -1
  32. package/build/lib/constants.d.ts +5 -5
  33. package/build/lib/constants.d.ts.map +1 -1
  34. package/build/lib/constants.js +64 -59
  35. package/build/lib/constants.js.map +1 -1
  36. package/build/lib/extension/driver-config.js +199 -164
  37. package/build/lib/extension/driver-config.js.map +1 -1
  38. package/build/lib/extension/extension-config.d.ts +18 -16
  39. package/build/lib/extension/extension-config.d.ts.map +1 -1
  40. package/build/lib/extension/extension-config.js +523 -396
  41. package/build/lib/extension/extension-config.js.map +1 -1
  42. package/build/lib/extension/index.js +98 -68
  43. package/build/lib/extension/index.js.map +1 -1
  44. package/build/lib/extension/manifest-migrations.d.ts +27 -0
  45. package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
  46. package/build/lib/extension/manifest-migrations.js +99 -0
  47. package/build/lib/extension/manifest-migrations.js.map +1 -0
  48. package/build/lib/extension/manifest.d.ts +7 -56
  49. package/build/lib/extension/manifest.d.ts.map +1 -1
  50. package/build/lib/extension/manifest.js +432 -240
  51. package/build/lib/extension/manifest.js.map +1 -1
  52. package/build/lib/extension/package-changed.js +57 -61
  53. package/build/lib/extension/package-changed.js.map +1 -1
  54. package/build/lib/extension/plugin-config.d.ts +2 -3
  55. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  56. package/build/lib/extension/plugin-config.js +94 -70
  57. package/build/lib/extension/plugin-config.js.map +1 -1
  58. package/build/lib/grid-register.js +119 -137
  59. package/build/lib/grid-register.js.map +1 -1
  60. package/build/lib/logger.d.ts +1 -1
  61. package/build/lib/logger.d.ts.map +1 -1
  62. package/build/lib/logger.js +5 -15
  63. package/build/lib/logger.js.map +1 -1
  64. package/build/lib/logsink.d.ts.map +1 -1
  65. package/build/lib/logsink.js +189 -183
  66. package/build/lib/logsink.js.map +1 -1
  67. package/build/lib/main.d.ts +19 -12
  68. package/build/lib/main.d.ts.map +1 -1
  69. package/build/lib/main.js +330 -304
  70. package/build/lib/main.js.map +1 -1
  71. package/build/lib/schema/arg-spec.js +153 -108
  72. package/build/lib/schema/arg-spec.js.map +1 -1
  73. package/build/lib/schema/cli-args.js +203 -164
  74. package/build/lib/schema/cli-args.js.map +1 -1
  75. package/build/lib/schema/cli-transformers.js +117 -72
  76. package/build/lib/schema/cli-transformers.js.map +1 -1
  77. package/build/lib/schema/index.js +17 -32
  78. package/build/lib/schema/index.js.map +1 -1
  79. package/build/lib/schema/keywords.js +125 -67
  80. package/build/lib/schema/keywords.js.map +1 -1
  81. package/build/lib/schema/schema.d.ts.map +1 -1
  82. package/build/lib/schema/schema.js +582 -417
  83. package/build/lib/schema/schema.js.map +1 -1
  84. package/build/lib/utils.d.ts +41 -255
  85. package/build/lib/utils.d.ts.map +1 -1
  86. package/build/lib/utils.js +342 -193
  87. package/build/lib/utils.js.map +1 -1
  88. package/build/tsconfig.tsbuildinfo +1 -1
  89. package/build/types/cli.d.ts +45 -34
  90. package/build/types/cli.d.ts.map +1 -1
  91. package/build/types/cli.js +3 -0
  92. package/build/types/cli.js.map +1 -0
  93. package/build/types/index.d.ts +1 -2
  94. package/build/types/index.d.ts.map +1 -1
  95. package/build/types/index.js +19 -0
  96. package/build/types/index.js.map +1 -0
  97. package/build/types/manifest/base.d.ts +135 -0
  98. package/build/types/manifest/base.d.ts.map +1 -0
  99. package/build/types/manifest/base.js +3 -0
  100. package/build/types/manifest/base.js.map +1 -0
  101. package/build/types/manifest/index.d.ts +19 -0
  102. package/build/types/manifest/index.d.ts.map +1 -0
  103. package/build/types/manifest/index.js +40 -0
  104. package/build/types/manifest/index.js.map +1 -0
  105. package/build/types/manifest/v3.d.ts +139 -0
  106. package/build/types/manifest/v3.d.ts.map +1 -0
  107. package/build/types/manifest/v3.js +3 -0
  108. package/build/types/manifest/v3.js.map +1 -0
  109. package/lib/appium.js +1 -1
  110. package/lib/cli/args.js +1 -1
  111. package/lib/cli/extension-command.js +116 -61
  112. package/lib/cli/extension.js +9 -8
  113. package/lib/cli/parser.js +2 -2
  114. package/lib/config-file.js +2 -3
  115. package/lib/config.js +3 -2
  116. package/lib/constants.js +6 -5
  117. package/lib/extension/extension-config.js +24 -25
  118. package/lib/extension/manifest-migrations.js +99 -0
  119. package/lib/extension/manifest.js +79 -72
  120. package/lib/extension/plugin-config.js +1 -2
  121. package/lib/logsink.js +26 -5
  122. package/lib/main.js +58 -50
  123. package/lib/schema/schema.js +6 -1
  124. package/lib/utils.js +62 -0
  125. package/package.json +23 -24
  126. package/scripts/autoinstall-extensions.js +78 -26
  127. package/types/cli.ts +81 -42
  128. package/types/index.ts +1 -2
  129. package/types/manifest/README.md +30 -0
  130. package/types/manifest/base.ts +158 -0
  131. package/types/manifest/index.ts +27 -0
  132. package/types/manifest/v3.ts +161 -0
  133. package/build/types/appium-manifest.d.ts +0 -59
  134. package/build/types/appium-manifest.d.ts.map +0 -1
  135. package/build/types/extension-manifest.d.ts +0 -55
  136. package/build/types/extension-manifest.d.ts.map +0 -1
  137. package/types/appium-manifest.ts +0 -73
  138. package/types/extension-manifest.ts +0 -64
package/lib/utils.js CHANGED
@@ -4,6 +4,7 @@ import {processCapabilities, PROTOCOLS, STANDARD_CAPS} from '@appium/base-driver
4
4
  import {inspect as dump} from 'util';
5
5
  import {node} from '@appium/support';
6
6
  import path from 'path';
7
+ import {SERVER_SUBCOMMAND, DRIVER_TYPE, PLUGIN_TYPE} from './constants';
7
8
 
8
9
  const W3C_APPIUM_PREFIX = 'appium';
9
10
  const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
@@ -289,6 +290,46 @@ function pullSettings(caps) {
289
290
  return result;
290
291
  }
291
292
 
293
+ /**
294
+ * @template {CliCommand} [Cmd=ServerCommand]
295
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
296
+ * @param {Args<Cmd, SubCmd>} args
297
+ * @returns {args is Args<ServerCommand>}
298
+ */
299
+ export function isServerCommandArgs(args) {
300
+ return args.subcommand === SERVER_SUBCOMMAND;
301
+ }
302
+
303
+ /**
304
+ * @template {CliCommand} [Cmd=ServerCommand]
305
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
306
+ * @param {Args<Cmd, SubCmd>} args
307
+ * @returns {args is Args<CliExtensionCommand, SubCmd>}
308
+ */
309
+ export function isExtensionCommandArgs(args) {
310
+ return args.subcommand === DRIVER_TYPE || args.subcommand === PLUGIN_TYPE;
311
+ }
312
+
313
+ /**
314
+ * @template {CliCommand} Cmd
315
+ * @template {CliExtensionSubcommand} SubCmd
316
+ * @param {Args<Cmd, SubCmd>} args
317
+ * @returns {args is Args<DriverCommand, SubCmd>}
318
+ */
319
+ export function isDriverCommandArgs(args) {
320
+ return args.subcommand === DRIVER_TYPE;
321
+ }
322
+
323
+ /**
324
+ * @template {CliCommand} Cmd
325
+ * @template {CliExtensionSubcommand} SubCmd
326
+ * @param {Args<Cmd, SubCmd>} args
327
+ * @returns {args is Args<PluginCommand, SubCmd>}
328
+ */
329
+ export function isPluginCommandArgs(args) {
330
+ return args.subcommand === PLUGIN_TYPE;
331
+ }
332
+
292
333
  export {
293
334
  inspect,
294
335
  parseCapsForInnerDriver,
@@ -357,3 +398,24 @@ export {
357
398
  /**
358
399
  * @typedef {import('@appium/types').Constraints} Constraints
359
400
  */
401
+
402
+ /**
403
+ * @typedef {import('appium/types').CliCommand} CliCommand
404
+ * @typedef {import('appium/types').CliExtensionSubcommand} CliExtensionSubcommand
405
+ * @typedef {import('appium/types').CliExtensionCommand} CliExtensionCommand
406
+ * @typedef {import('appium/types').ServerCommand} ServerCommand
407
+ * @typedef {import('appium/types').DriverCommand} DriverCommand
408
+ * @typedef {import('appium/types').PluginCommand} PluginCommand
409
+ */
410
+
411
+ /**
412
+ * @template {CliCommand} [Cmd=ServerCommand]
413
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
414
+ * @typedef {import('appium/types').Args<Cmd, SubCmd>} Args
415
+ */
416
+
417
+ /**
418
+ * @template {CliCommand} [Cmd=ServerCommand]
419
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
420
+ * @typedef {import('appium/types').ParsedArgs<Cmd, SubCmd>} ParsedArgs
421
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium",
3
- "version": "2.0.0-beta.46",
3
+ "version": "2.0.0-beta.47",
4
4
  "description": "Automation for Apps.",
5
5
  "keywords": [
6
6
  "automation",
@@ -41,19 +41,15 @@
41
41
  "types"
42
42
  ],
43
43
  "scripts": {
44
- "build": "babel lib --root-mode=upward --out-dir=build/lib",
45
44
  "build:docs": "node docs/scripts/build-docs.js",
46
- "build:docs:cli": "node docs/scripts/gen-cli-args-docs.js",
47
45
  "build:docs:assets": "node docs/scripts/copy-assets.js",
48
- "dev": "npm run build -- --watch",
46
+ "build:docs:cli": "node docs/scripts/gen-cli-args-docs.js",
47
+ "build:docs:reference": "node docs/scripts/build-reference.js",
49
48
  "dev:docs": "npm run build:docs:assets && npm run dev:docs:en",
50
49
  "dev:docs:en": "mkdocs serve -f ./docs/mkdocs-en.yml",
51
50
  "dev:docs:ja": "mkdocs serve -f ./docs/mkdocs-ja.yml",
52
51
  "dev:docs:zh": "mkdocs serve -f ./docs/mkdocs-zh.yml",
53
- "fix": "npm run lint -- --fix",
54
52
  "postinstall": "node ./scripts/autoinstall-extensions.js",
55
- "lint": "eslint -c ../../.eslintrc --ignore-path ../../.eslintignore .",
56
- "prepare": "npm run build",
57
53
  "publish:docs": "cross-env APPIUM_DOCS_PUBLISH=1 npm run build:docs",
58
54
  "test": "npm run test:unit",
59
55
  "test:e2e": "mocha --timeout 1m --slow 30s \"./test/e2e/**/*.spec.js\"",
@@ -61,25 +57,25 @@
61
57
  "test:unit": "mocha \"./test/unit/**/*.spec.js\""
62
58
  },
63
59
  "dependencies": {
64
- "@appium/base-driver": "^8.7.3",
65
- "@appium/base-plugin": "^1.10.5",
66
- "@appium/docutils": "^0.0.13",
67
- "@appium/schema": "^0.0.9",
68
- "@appium/support": "^2.61.1",
69
- "@appium/types": "^0.5.0",
60
+ "@appium/base-driver": "^9.0.0",
61
+ "@appium/base-plugin": "^2.0.0",
62
+ "@appium/docutils": "^0.1.0",
63
+ "@appium/schema": "^0.1.0",
64
+ "@appium/support": "^3.0.0",
65
+ "@appium/types": "^0.6.0",
70
66
  "@sidvind/better-ajv-errors": "2.1.0",
71
67
  "@types/argparse": "2.0.10",
72
- "@types/bluebird": "3.5.37",
68
+ "@types/bluebird": "3.5.38",
73
69
  "@types/fancy-log": "2.0.0",
74
- "@types/semver": "7.3.12",
75
- "@types/teen_process": "1.16.1",
70
+ "@types/semver": "7.3.13",
71
+ "@types/teen_process": "2.0.0",
76
72
  "@types/wrap-ansi": "3.0.0",
77
- "ajv": "8.11.0",
73
+ "ajv": "8.11.2",
78
74
  "ajv-formats": "2.1.1",
79
75
  "argparse": "2.0.1",
80
- "async-lock": "1.3.2",
81
- "asyncbox": "2.9.2",
82
- "axios": "0.27.2",
76
+ "async-lock": "1.4.0",
77
+ "asyncbox": "2.9.4",
78
+ "axios": "1.2.1",
83
79
  "bluebird": "3.7.2",
84
80
  "cross-env": "7.0.3",
85
81
  "find-up": "5.0.0",
@@ -87,25 +83,28 @@
87
83
  "lilconfig": "2.0.6",
88
84
  "lodash": "4.17.21",
89
85
  "longjohn": "0.2.12",
90
- "npmlog": "6.0.2",
86
+ "npmlog": "7.0.1",
91
87
  "ora": "5.4.1",
92
88
  "package-changed": "1.9.0",
93
89
  "resolve-from": "5.0.0",
94
90
  "semver": "7.3.8",
95
91
  "source-map-support": "0.5.21",
96
92
  "teen_process": "2.0.2",
97
- "type-fest": "3.1.0",
93
+ "type-fest": "3.3.0",
98
94
  "winston": "3.8.2",
99
95
  "wrap-ansi": "7.0.0",
100
96
  "yaml": "2.1.3"
101
97
  },
102
98
  "engines": {
103
- "node": ">=14",
99
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0",
104
100
  "npm": ">=8"
105
101
  },
106
102
  "publishConfig": {
107
103
  "access": "public",
108
104
  "tag": "next"
109
105
  },
110
- "gitHead": "6b3cc1a8743f78c1f50320364f25f3011d2b2136"
106
+ "gitHead": "0823f0b60e40395cd1dc3b72cfa3c0092bc81302",
107
+ "typedoc": {
108
+ "entryPoint": "./build/lib/main.js"
109
+ }
111
110
  }
@@ -14,10 +14,24 @@
14
14
  * code upon failure (which will typically break a build). Otherwise, it
15
15
  * will always exit with code 0, even if errors occur.
16
16
  *
17
+ * @module
17
18
  * @example
18
19
  * `npm install -g appium --drivers=uiautomator2,xcuitest --plugins=images`
19
20
  */
20
21
 
22
+ const path = require('path');
23
+ const {exec} = require('teen_process');
24
+ const B = require('bluebird');
25
+
26
+ B.config({
27
+ cancellation: true,
28
+ });
29
+
30
+ /**
31
+ * This is only used if we're actually in the monorepo
32
+ */
33
+ const MONOREPO_ROOT = path.join(__dirname, '..', '..', '..');
34
+
21
35
  /** @type {import('../lib/cli/extension').runExtensionCommand} */
22
36
  let runExtensionCommand;
23
37
  /** @type {import('../lib/constants').DRIVER_TYPE} */
@@ -27,44 +41,82 @@ let PLUGIN_TYPE;
27
41
  /** @type {import('../lib/extension').loadExtensions} */
28
42
  let loadExtensions;
29
43
 
30
- const {env, util, logger} = require('@appium/support');
31
44
  const _ = require('lodash');
32
45
  const wrap = _.partial(
33
46
  require('wrap-ansi'),
34
47
  _,
35
- process.stderr.columns ?? process.stdout.columns ?? 25
48
+ process.stderr.columns ?? process.stdout.columns ?? 80
36
49
  );
37
-
38
50
  const ora = require('ora');
39
51
 
40
- const log = (message) => {
52
+ let env, util, logger;
53
+
54
+ function log(message) {
41
55
  console.error(wrap(`[Appium] ${message}`));
42
- };
43
-
44
- const spinner = ora({
45
- text: 'Checking Appium installation...',
46
- prefixText: '[Appium]',
47
- }).start();
48
-
49
- try {
50
- ({runExtensionCommand} = require('../build/lib/cli/extension'));
51
- ({DRIVER_TYPE, PLUGIN_TYPE} = require('../build/lib/constants'));
52
- ({loadExtensions} = require('../build/lib/extension'));
53
- spinner.succeed('Appium installation OK');
54
- // suppress logs from Appium, which mess up the script output
55
- logger.getLogger('Appium').level = 'error';
56
- } catch (e) {
57
- spinner.fail(`Could not load required module(s); has Appium been built? (${e.message})`);
58
- if (process.env.CI) {
59
- console.error('Detected CI environment, exiting with code 1');
60
- process.exitCode = 1;
61
- } else {
62
- process.exitCode = 0;
56
+ }
57
+
58
+ async function init() {
59
+ /** @type {import('ora').Ora} */
60
+ let spinner;
61
+
62
+ try {
63
+ ({env, util, logger} = require('@appium/support'));
64
+ require('..');
65
+ } catch {
66
+ spinner = ora({
67
+ text: 'Building Appium dev environment...',
68
+ prefixText: '[Appium]',
69
+ }).start();
70
+
71
+ try {
72
+ const {stderr, code} = await exec('npm', ['run', 'build'], {
73
+ cwd: MONOREPO_ROOT,
74
+ encoding: 'utf8',
75
+ });
76
+ if (!code) {
77
+ spinner.succeed('Appium build successfully.');
78
+ } else {
79
+ spinner.fail(`Building Appium failed!`);
80
+ log(stderr);
81
+ }
82
+ } catch (err) {
83
+ spinner.fail(`Building Appium failed!`);
84
+ log(err);
85
+ }
86
+ }
87
+
88
+ spinner = ora({
89
+ text: 'Checking Appium installation...',
90
+ prefixText: '[Appium]',
91
+ }).start();
92
+
93
+ try {
94
+ ({env, util, logger} = require('@appium/support'));
95
+ ({runExtensionCommand} = require('../build/lib/cli/extension'));
96
+ ({DRIVER_TYPE, PLUGIN_TYPE} = require('../build/lib/constants'));
97
+ ({loadExtensions} = require('../build/lib/extension'));
98
+ spinner.succeed('Appium installation OK');
99
+ // suppress logs from Appium, which mess up the script output
100
+ logger.getLogger('Appium').level = 'error';
101
+ } catch (e) {
102
+ spinner.fail(`Could not load required module(s); has Appium been built? (${e.message})`);
103
+ if (process.env.CI) {
104
+ log('Detected CI environment, exiting with code 1');
105
+ process.exitCode = 1;
106
+ } else {
107
+ process.exitCode = 0;
108
+ }
109
+ return false;
63
110
  }
64
- process.exit();
111
+
112
+ return true;
65
113
  }
66
114
 
67
115
  async function main() {
116
+ if (!(await init())) {
117
+ return;
118
+ }
119
+
68
120
  // if we're doing `npm install -g appium` then we will assume we don't have a local appium.
69
121
  if (!process.env.npm_config_global && (await env.hasAppiumDependency())) {
70
122
  log(`Found local Appium installation; skipping automatic installation of extensions.`);
package/types/cli.ts CHANGED
@@ -1,23 +1,39 @@
1
- import {ServerArgs} from '@appium/types';
2
- export type ServerSubcommand = 'server';
3
- export type DriverSubcommand = 'driver';
4
- export type PluginSubcommand = 'plugin';
1
+ import {DriverType, PluginType, ServerArgs} from '@appium/types';
2
+ import {SetOptional} from 'type-fest';
3
+ import {InstallType} from './manifest';
4
+ export type ServerCommand = 'server';
5
+ export type DriverCommand = DriverType;
6
+ export type PluginCommand = PluginType;
5
7
 
6
8
  /**
7
- * Possible subcommands for the `appium` CLI.
9
+ * Extension-specific commands
8
10
  */
9
- export type CliSubcommand = ServerSubcommand | DriverSubcommand | PluginSubcommand;
11
+ export type CliExtensionCommand = DriverCommand | PluginCommand;
10
12
 
11
13
  /**
12
- * Possible subcommands of {@linkcode DriverSubcommand} or
13
- * {@linkcode PluginSubcommand}.
14
+ * Possible commands for the `appium` CLI.
14
15
  */
15
- export type CliExtensionSubcommand =
16
- | 'install'
17
- | 'list'
18
- | 'run'
19
- | 'uninstall'
20
- | 'update';
16
+ export type CliCommand = ServerCommand | CliExtensionCommand;
17
+
18
+ /**
19
+ * Possible subcommands of {@linkcode DriverCommand} or
20
+ * {@linkcode PluginCommand}.
21
+ */
22
+ export type CliExtensionSubcommand = 'install' | 'list' | 'run' | 'uninstall' | 'update';
23
+
24
+ export interface CliExtensionSubcommandListArgs {
25
+ showInstalled?: boolean;
26
+ showUpdates?: boolean;
27
+ }
28
+
29
+ export interface CliExtensionSubcommandInstallArgs {
30
+ installType: InstallType;
31
+ packageName?: string;
32
+ }
33
+
34
+ export interface CliExtensionSubcommandUpdateArgs {
35
+ unsafe?: boolean;
36
+ }
21
37
 
22
38
  /**
23
39
  * Random stuff that may appear in the parsed args which has no equivalent in a
@@ -25,9 +41,9 @@ export type CliExtensionSubcommand =
25
41
  */
26
42
  export interface MoreArgs {
27
43
  /**
28
- * Possible subcommands. If empty, defaults to {@linkcode ServerSubcommand}.
44
+ * Possible subcommands. If empty, defaults to {@linkcode ServerCommand}.
29
45
  */
30
- subcommand?: CliSubcommand;
46
+ subcommand?: CliCommand;
31
47
 
32
48
  /**
33
49
  * Path to config file, if any. Does not make sense for this to be allowed in a config file!
@@ -79,19 +95,21 @@ export interface ProgrammaticArgs {
79
95
  showConfig?: boolean;
80
96
  }
81
97
 
98
+ export interface DriverExtArgs {
99
+ driverCommand: CliExtensionSubcommand;
100
+ driver?: string;
101
+ }
102
+
103
+ export interface PluginExtArgs {
104
+ pluginCommand: CliExtensionSubcommand;
105
+ plugin?: string;
106
+ }
107
+
82
108
  /**
83
109
  * These are args which the user will specify if using an extension command
84
110
  */
85
- export interface ExtArgs extends WithExtSubcommand {
86
- /**
87
- * Subcommands of `driver` subcommand
88
- */
89
- driverCommand?: CliExtensionSubcommand;
90
-
91
- /**
92
- * Subcommands of `plugin` subcommand
93
- */
94
- pluginCommand?: CliExtensionSubcommand;
111
+ export interface BaseExtArgs<Cmd extends CliExtensionCommand> {
112
+ subcommand: Cmd;
95
113
 
96
114
  /**
97
115
  * Output JSON instead of human-readable text
@@ -110,35 +128,56 @@ export interface ExtArgs extends WithExtSubcommand {
110
128
  }
111
129
 
112
130
  /**
113
- * Args having the `server` subcommand
131
+ * Args for extension commands; includes a subcommand
114
132
  */
115
- export interface WithServerSubcommand {
116
- subcommand?: ServerSubcommand;
117
- }
118
-
119
- /**
120
- * Args having the `driver` or `plugin` subcommand
121
- */
122
- export interface WithExtSubcommand {
123
- subcommand: DriverSubcommand | PluginSubcommand;
124
- }
133
+ export type ExtArgs<
134
+ Cmd extends CliExtensionCommand,
135
+ SubCmd extends CliExtensionSubcommand
136
+ > = BaseExtArgs<Cmd> &
137
+ (Cmd extends DriverCommand ? DriverExtArgs : Cmd extends PluginCommand ? PluginExtArgs : never) &
138
+ (SubCmd extends 'install'
139
+ ? CliExtensionSubcommandInstallArgs
140
+ : SubCmd extends 'list'
141
+ ? CliExtensionSubcommandListArgs
142
+ : SubCmd extends 'update'
143
+ ? CliExtensionSubcommandUpdateArgs
144
+ : never);
125
145
 
126
146
  /**
127
147
  * Some generic bits of arguments; should not be used outside this declaration
128
148
  */
129
- type CommonArgs<SArgs, T = WithServerSubcommand> = MoreArgs &
149
+ export type CommonArgs<
150
+ Cmd extends CliCommand = ServerCommand,
151
+ SubCmd extends CliExtensionSubcommand | void = void
152
+ > = MoreArgs &
130
153
  ProgrammaticArgs &
131
- (T extends WithServerSubcommand ? SArgs : T extends WithExtSubcommand ? ExtArgs : never);
154
+ (Cmd extends ServerCommand
155
+ ? ServerArgs
156
+ : Cmd extends CliExtensionCommand
157
+ ? SubCmd extends CliExtensionSubcommand
158
+ ? ExtArgs<Cmd, SubCmd>
159
+ : never
160
+ : never);
132
161
 
133
162
  /**
134
163
  * Fully-parsed arguments, containing defaults, computed args, and config file values.
135
164
  */
136
- export type ParsedArgs<T = WithServerSubcommand> = CommonArgs<ServerArgs, T>;
165
+ export type ParsedArgs<
166
+ Cmd extends CliCommand = ServerCommand,
167
+ SubCmd extends CliExtensionSubcommand | void = void
168
+ > = CommonArgs<Cmd, SubCmd>;
137
169
 
138
170
  /**
139
- * Partial arguments, as supplied by a user. _May_ have defaults applied; _may_ contain config values; _may_ contain computed args.
171
+ * Like {@linkcode ParsedArgs} except server arguments are all optional.
172
+ *
173
+ * _May_ have defaults applied; _may_ contain config values; _may_ contain computed args.
140
174
  */
141
- export type Args<T = WithServerSubcommand> = CommonArgs<Partial<ServerArgs>, T>;
175
+ export type Args<
176
+ Cmd extends CliCommand = ServerCommand,
177
+ SubCmd extends CliExtensionSubcommand | void = void
178
+ > = Cmd extends ServerCommand
179
+ ? SetOptional<CommonArgs<Cmd>, keyof ServerArgs>
180
+ : ParsedArgs<Cmd, SubCmd>;
142
181
 
143
182
  /**
144
183
  * Shown by `appium --build-info`
package/types/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import {ExtensionType, DriverType, DriverClass, PluginType, PluginClass} from '@appium/types';
2
2
 
3
- export * from './appium-manifest';
4
- export * from './extension-manifest';
3
+ export * from './manifest';
5
4
  export * from './cli';
6
5
 
7
6
  /**
@@ -0,0 +1,30 @@
1
+ # appium-manifest types
2
+
3
+ This dir contains versioned type declarations for our manifest file (`extensions.yaml`).
4
+
5
+ ## About
6
+
7
+ Originally, the manifest file was versioned; it had a `schemaRev` prop. Eventually, the requirement for this prop was dropped, and became optional. As of this writing, it is now required again.
8
+
9
+ The idea was that if Appium found an `extensions.yaml` with a `schemaRev` lower than its "current" revision, it would "migrate" the file to the current revision. When we removed the requirement for the `schemaRev` prop, we removed this logic.
10
+
11
+ As of _v3_ of the schema, we are reinstating versioning and migrations.
12
+
13
+ ## How To Add A New Version
14
+
15
+ The manifest file types—and thus its format—is composed of types used elsewhere in our codebase. This is probably a design flaw, but the fact remains that the manifest file's format is strongly coupled to Appium's extension-handling logic.
16
+
17
+ For that reason, it is _non-trivial_ to reuse the types declared by older revisions to declare a new revision. If and when someone de-couples the types from the schema, we will have to use the _copy-and-paste_ strategy to create a new version.
18
+
19
+ 1. The current version of the schema is defined in `constants.js` as `CURRENT_SCHEMA_REV`. **Increment** this value.
20
+ 2. **Copy** the `.ts` file in this directory corresponding to the (now old) current version of the schema into a new file named `v<new-version>.ts`. For example, if the current version is `3`, and you're creating `4`, then you would copy `v3.ts` to `v4.ts`.
21
+ 3. **Modify** your new file to do whatever it is you need to do with it. Do _not_ build types upon old versions of the schema.
22
+ 4. **Modify** `index.ts`:
23
+ 1. **Append** `import * as ManifestV<new-version> from './v<new-version>'`
24
+ 2. **Replace** `export * from './v<current-version>'` with `export * from './v<new-version>'`
25
+ 3. **Append** `ManifestV<new-version>` to the `export {ManifestV...}` line.
26
+ 4. **Append** a key/value pair to `ManifestDataVersions` with the new _numeric_ version number as the key and the value `ManifestV<new-version>.ManifestData`.
27
+ 5. **Create** a new `const SCHEMA_REV_<new-version> = <new-version>` in `manifest-migrations.js`.
28
+ 6. Finally, **append** a new key/value pair to the `Migrations` object in `manifest-migrations.js`. The key should be a reference to the constant created in step 5, and the value should be a function which performs the migration from the (old) current version to the new version.
29
+
30
+ -- @boneskull, Nov 8 2022
@@ -0,0 +1,158 @@
1
+ import {DriverType, ExtensionType, PluginType} from '@appium/types';
2
+ import {SchemaObject} from 'ajv';
3
+ import {PackageJson, SetRequired} from 'type-fest';
4
+
5
+ /**
6
+ * One of the possible extension installation stratgies
7
+ */
8
+ export type InstallType = 'npm' | 'git' | 'local' | 'github';
9
+
10
+ export interface InternalMetadata {
11
+ /**
12
+ * Package name of extension
13
+ *
14
+ * `name` from its `package.json`
15
+ */
16
+ pkgName: string;
17
+ /**
18
+ * Version of extension
19
+ *
20
+ * `version` from its `package.json`
21
+ */
22
+ version: string;
23
+ /**
24
+ * The method in which the user installed the extension (the `source` CLI arg)
25
+ */
26
+ installType: InstallType;
27
+ /**
28
+ * Whatever the user typed as the extension to install. May be derived from `package.json`
29
+ */
30
+ installSpec: string;
31
+ /**
32
+ * Maximum version of Appium that this extension is compatible with.
33
+ *
34
+ * If `undefined`, we'll try anyway.
35
+ */
36
+ appiumVersion?: string;
37
+ }
38
+
39
+ /**
40
+ * Shape of the `appium.schema` property in an extension's `package.json` (if it exists)
41
+ */
42
+ export type ExtSchemaMetadata = string | (SchemaObject & {[key: number]: never});
43
+
44
+ /**
45
+ * Manifest data shared by all extensions, as contained in `package.json`
46
+ */
47
+ export interface CommonExtMetadata {
48
+ /**
49
+ * The main class of the extension.
50
+ *
51
+ * The extension must export this class by name.
52
+ */
53
+ mainClass: string;
54
+
55
+ /**
56
+ * Lookup table of scripts to run via `appium <driver|plugin> run <script>` keyed by name.
57
+ */
58
+ scripts?: Record<string, string>;
59
+
60
+ /**
61
+ * Schema describing configuration options (and CLI args) for the extension.
62
+ *
63
+ * Can also just be a path (relative to the extension root) to an external JSON schema file.
64
+ */
65
+
66
+ schema?: ExtSchemaMetadata;
67
+ }
68
+
69
+ /**
70
+ * Driver-specific manifest data as stored in a driver's `package.json`
71
+ */
72
+ export interface DriverMetadata {
73
+ /**
74
+ * Automation name of the driver
75
+ */
76
+ automationName: string;
77
+ /**
78
+ * Platforms the driver supports
79
+ */
80
+ platformNames: string[];
81
+ /**
82
+ * Short name of the driver (displayed in `appium list`, etc.)
83
+ */
84
+ driverName: string;
85
+ }
86
+
87
+ /**
88
+ * Plugin-specific manifest data as stored in a plugin's `package.json`
89
+ */
90
+ export interface PluginMetadata {
91
+ /**
92
+ * Short name of the plugin (displayed in `appium list`, etc.)
93
+ */
94
+ pluginName: string;
95
+ }
96
+
97
+ /**
98
+ * Generic extension metadata as stored in the `appium` prop of an extension's `package.json`.
99
+ */
100
+ export type ExtMetadata<ExtType extends ExtensionType> = (ExtType extends DriverType
101
+ ? DriverMetadata
102
+ : ExtType extends PluginType
103
+ ? PluginMetadata
104
+ : never) &
105
+ CommonExtMetadata;
106
+
107
+ /**
108
+ * Combination of external + internal extension data with `driverName`/`pluginName` removed (it becomes a key in an {@linkcode ExtRecord} object).
109
+ * Part of `extensions.yaml`.
110
+ */
111
+ export type ExtManifest<ExtType extends ExtensionType> = Omit<
112
+ ExtMetadata<ExtType>,
113
+ 'driverName' | 'pluginName'
114
+ > &
115
+ InternalMetadata;
116
+
117
+ /**
118
+ * Lookup of extension name to {@linkcode ExtManifest}.
119
+ * @see {ManifestData}
120
+ */
121
+ export type ExtRecord<ExtType extends ExtensionType> = Record<string, ExtManifest<ExtType>>;
122
+
123
+ /**
124
+ * The shape of the `extensions.yaml` file
125
+ */
126
+ export interface ManifestData {
127
+ drivers: ExtRecord<DriverType>;
128
+ plugins: ExtRecord<PluginType>;
129
+ schemaRev?: number;
130
+ }
131
+
132
+ /**
133
+ * The name of an installed extension, as it appears in `extensions.yaml`
134
+ * (as a property name under `drivers` or `plugins`)
135
+ */
136
+ export type ExtName<ExtType extends ExtensionType> = keyof ExtRecord<ExtType>;
137
+
138
+ /**
139
+ * A `package.json` containing extension metadata.
140
+ * Must have the following properties:
141
+ * - `name`: the name of the extension
142
+ * - `version`: the version of the extension
143
+ * - `appium`: the metadata for the extension
144
+ * - `peerDependencies.appium`: the maximum compatible version of Appium
145
+ */
146
+ export type ExtPackageJson<ExtType extends ExtensionType> = SetRequired<
147
+ PackageJson,
148
+ 'name' | 'version'
149
+ > & {
150
+ appium: ExtMetadata<ExtType>;
151
+ peerDependencies: {appium: string; [key: string]: string};
152
+ };
153
+
154
+ /**
155
+ * A transient format between installation and insertion of extension metadata into the manifest.
156
+ */
157
+ export type ExtInstallReceipt<ExtType extends ExtensionType> = ExtMetadata<ExtType> &
158
+ InternalMetadata;