appium 2.0.0-beta.5 → 2.0.0-beta.52

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 (199) hide show
  1. package/README.md +156 -63
  2. package/build/lib/appium.d.ts +226 -0
  3. package/build/lib/appium.d.ts.map +1 -0
  4. package/build/lib/appium.js +694 -439
  5. package/build/lib/appium.js.map +1 -0
  6. package/build/lib/cli/args.d.ts +17 -0
  7. package/build/lib/cli/args.d.ts.map +1 -0
  8. package/build/lib/cli/args.js +253 -319
  9. package/build/lib/cli/args.js.map +1 -0
  10. package/build/lib/cli/driver-command.d.ts +102 -0
  11. package/build/lib/cli/driver-command.d.ts.map +1 -0
  12. package/build/lib/cli/driver-command.js +126 -81
  13. package/build/lib/cli/driver-command.js.map +1 -0
  14. package/build/lib/cli/extension-command.d.ts +385 -0
  15. package/build/lib/cli/extension-command.d.ts.map +1 -0
  16. package/build/lib/cli/extension-command.js +731 -383
  17. package/build/lib/cli/extension-command.js.map +1 -0
  18. package/build/lib/cli/extension.d.ts +23 -0
  19. package/build/lib/cli/extension.d.ts.map +1 -0
  20. package/build/lib/cli/extension.js +71 -54
  21. package/build/lib/cli/extension.js.map +1 -0
  22. package/build/lib/cli/parser.d.ts +84 -0
  23. package/build/lib/cli/parser.d.ts.map +1 -0
  24. package/build/lib/cli/parser.js +240 -128
  25. package/build/lib/cli/parser.js.map +1 -0
  26. package/build/lib/cli/plugin-command.d.ts +99 -0
  27. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  28. package/build/lib/cli/plugin-command.js +120 -81
  29. package/build/lib/cli/plugin-command.js.map +1 -0
  30. package/build/lib/cli/utils.d.ts +29 -0
  31. package/build/lib/cli/utils.d.ts.map +1 -0
  32. package/build/lib/cli/utils.js +72 -51
  33. package/build/lib/cli/utils.js.map +1 -0
  34. package/build/lib/config-file.d.ts +100 -0
  35. package/build/lib/config-file.d.ts.map +1 -0
  36. package/build/lib/config-file.js +207 -0
  37. package/build/lib/config-file.js.map +1 -0
  38. package/build/lib/config.d.ts +49 -0
  39. package/build/lib/config.d.ts.map +1 -0
  40. package/build/lib/config.js +265 -201
  41. package/build/lib/config.js.map +1 -0
  42. package/build/lib/constants.d.ts +49 -0
  43. package/build/lib/constants.d.ts.map +1 -0
  44. package/build/lib/constants.js +66 -0
  45. package/build/lib/constants.js.map +1 -0
  46. package/build/lib/extension/driver-config.d.ts +82 -0
  47. package/build/lib/extension/driver-config.d.ts.map +1 -0
  48. package/build/lib/extension/driver-config.js +212 -0
  49. package/build/lib/extension/driver-config.js.map +1 -0
  50. package/build/lib/extension/extension-config.d.ts +249 -0
  51. package/build/lib/extension/extension-config.d.ts.map +1 -0
  52. package/build/lib/extension/extension-config.js +581 -0
  53. package/build/lib/extension/extension-config.js.map +1 -0
  54. package/build/lib/extension/index.d.ts +48 -0
  55. package/build/lib/extension/index.d.ts.map +1 -0
  56. package/build/lib/extension/index.js +105 -0
  57. package/build/lib/extension/index.js.map +1 -0
  58. package/build/lib/extension/manifest-migrations.d.ts +27 -0
  59. package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
  60. package/build/lib/extension/manifest-migrations.js +118 -0
  61. package/build/lib/extension/manifest-migrations.js.map +1 -0
  62. package/build/lib/extension/manifest.d.ts +145 -0
  63. package/build/lib/extension/manifest.d.ts.map +1 -0
  64. package/build/lib/extension/manifest.js +521 -0
  65. package/build/lib/extension/manifest.js.map +1 -0
  66. package/build/lib/extension/package-changed.d.ts +11 -0
  67. package/build/lib/extension/package-changed.d.ts.map +1 -0
  68. package/build/lib/extension/package-changed.js +62 -0
  69. package/build/lib/extension/package-changed.js.map +1 -0
  70. package/build/lib/extension/plugin-config.d.ts +56 -0
  71. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  72. package/build/lib/extension/plugin-config.js +102 -0
  73. package/build/lib/extension/plugin-config.js.map +1 -0
  74. package/build/lib/grid-register.d.ts +10 -0
  75. package/build/lib/grid-register.d.ts.map +1 -0
  76. package/build/lib/grid-register.js +122 -144
  77. package/build/lib/grid-register.js.map +1 -0
  78. package/build/lib/logger.d.ts +3 -0
  79. package/build/lib/logger.d.ts.map +1 -0
  80. package/build/lib/logger.js +5 -17
  81. package/build/lib/logger.js.map +1 -0
  82. package/build/lib/logsink.d.ts +4 -0
  83. package/build/lib/logsink.d.ts.map +1 -0
  84. package/build/lib/logsink.js +190 -187
  85. package/build/lib/logsink.js.map +1 -0
  86. package/build/lib/main.d.ts +62 -0
  87. package/build/lib/main.d.ts.map +1 -0
  88. package/build/lib/main.js +348 -228
  89. package/build/lib/main.js.map +1 -0
  90. package/build/lib/schema/arg-spec.d.ts +143 -0
  91. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  92. package/build/lib/schema/arg-spec.js +164 -0
  93. package/build/lib/schema/arg-spec.js.map +1 -0
  94. package/build/lib/schema/cli-args.d.ts +19 -0
  95. package/build/lib/schema/cli-args.d.ts.map +1 -0
  96. package/build/lib/schema/cli-args.js +217 -0
  97. package/build/lib/schema/cli-args.js.map +1 -0
  98. package/build/lib/schema/cli-transformers.d.ts +5 -0
  99. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  100. package/build/lib/schema/cli-transformers.js +124 -0
  101. package/build/lib/schema/cli-transformers.js.map +1 -0
  102. package/build/lib/schema/index.d.ts +3 -0
  103. package/build/lib/schema/index.d.ts.map +1 -0
  104. package/build/lib/schema/index.js +19 -0
  105. package/build/lib/schema/index.js.map +1 -0
  106. package/build/lib/schema/keywords.d.ts +24 -0
  107. package/build/lib/schema/keywords.d.ts.map +1 -0
  108. package/build/lib/schema/keywords.js +128 -0
  109. package/build/lib/schema/keywords.js.map +1 -0
  110. package/build/lib/schema/schema.d.ts +259 -0
  111. package/build/lib/schema/schema.d.ts.map +1 -0
  112. package/build/lib/schema/schema.js +615 -0
  113. package/build/lib/schema/schema.js.map +1 -0
  114. package/build/lib/utils.d.ts +121 -0
  115. package/build/lib/utils.d.ts.map +1 -0
  116. package/build/lib/utils.js +351 -273
  117. package/build/lib/utils.js.map +1 -0
  118. package/build/tsconfig.tsbuildinfo +1 -0
  119. package/build/types/cli.d.ts +134 -0
  120. package/build/types/cli.d.ts.map +1 -0
  121. package/build/types/cli.js +3 -0
  122. package/build/types/cli.js.map +1 -0
  123. package/build/types/index.d.ts +15 -0
  124. package/build/types/index.d.ts.map +1 -0
  125. package/build/types/index.js +19 -0
  126. package/build/types/index.js.map +1 -0
  127. package/build/types/manifest/base.d.ts +135 -0
  128. package/build/types/manifest/base.d.ts.map +1 -0
  129. package/build/types/manifest/base.js +3 -0
  130. package/build/types/manifest/base.js.map +1 -0
  131. package/build/types/manifest/index.d.ts +19 -0
  132. package/build/types/manifest/index.d.ts.map +1 -0
  133. package/build/types/manifest/index.js +40 -0
  134. package/build/types/manifest/index.js.map +1 -0
  135. package/build/types/manifest/v3.d.ts +139 -0
  136. package/build/types/manifest/v3.d.ts.map +1 -0
  137. package/build/types/manifest/v3.js +3 -0
  138. package/build/types/manifest/v3.js.map +1 -0
  139. package/driver.d.ts +1 -0
  140. package/driver.js +14 -0
  141. package/index.js +11 -0
  142. package/lib/appium.js +535 -186
  143. package/lib/cli/args.js +267 -422
  144. package/lib/cli/driver-command.js +126 -23
  145. package/lib/cli/extension-command.js +679 -271
  146. package/lib/cli/extension.js +48 -17
  147. package/lib/cli/parser.js +263 -83
  148. package/lib/cli/plugin-command.js +115 -20
  149. package/lib/cli/utils.js +24 -10
  150. package/lib/config-file.js +220 -0
  151. package/lib/config.js +244 -110
  152. package/lib/constants.js +71 -0
  153. package/lib/extension/driver-config.js +250 -0
  154. package/lib/extension/extension-config.js +682 -0
  155. package/lib/extension/index.js +116 -0
  156. package/lib/extension/manifest-migrations.js +120 -0
  157. package/lib/extension/manifest.js +573 -0
  158. package/lib/extension/package-changed.js +64 -0
  159. package/lib/extension/plugin-config.js +112 -0
  160. package/lib/grid-register.js +49 -35
  161. package/lib/logger.js +1 -2
  162. package/lib/logsink.js +64 -38
  163. package/lib/main.js +321 -101
  164. package/lib/schema/arg-spec.js +229 -0
  165. package/lib/schema/cli-args.js +238 -0
  166. package/lib/schema/cli-transformers.js +119 -0
  167. package/lib/schema/index.js +2 -0
  168. package/lib/schema/keywords.js +136 -0
  169. package/lib/schema/schema.js +722 -0
  170. package/lib/utils.js +291 -167
  171. package/package.json +83 -84
  172. package/plugin.d.ts +1 -0
  173. package/plugin.js +13 -0
  174. package/scripts/autoinstall-extensions.js +237 -0
  175. package/support.d.ts +1 -0
  176. package/support.js +13 -0
  177. package/tsconfig.json +25 -0
  178. package/types/cli.ts +189 -0
  179. package/types/index.ts +20 -0
  180. package/types/manifest/README.md +30 -0
  181. package/types/manifest/base.ts +158 -0
  182. package/types/manifest/index.ts +27 -0
  183. package/types/manifest/v3.ts +161 -0
  184. package/CHANGELOG.md +0 -3515
  185. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  186. package/build/lib/cli/npm.js +0 -208
  187. package/build/lib/cli/parser-helpers.js +0 -82
  188. package/build/lib/driver-config.js +0 -77
  189. package/build/lib/drivers.js +0 -96
  190. package/build/lib/extension-config.js +0 -253
  191. package/build/lib/plugin-config.js +0 -59
  192. package/build/lib/plugins.js +0 -14
  193. package/lib/cli/npm.js +0 -184
  194. package/lib/cli/parser-helpers.js +0 -79
  195. package/lib/driver-config.js +0 -46
  196. package/lib/drivers.js +0 -81
  197. package/lib/extension-config.js +0 -209
  198. package/lib/plugin-config.js +0 -34
  199. package/lib/plugins.js +0 -10
@@ -1,404 +1,752 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
8
- exports.default = void 0;
9
-
10
- require("source-map-support/register");
11
-
12
- var _lodash = _interopRequireDefault(require("lodash"));
13
-
14
- var _npm = _interopRequireDefault(require("./npm"));
15
-
16
- var _path = _interopRequireDefault(require("path"));
17
-
18
- var _appiumSupport = require("appium-support");
19
-
20
- var _utils = require("./utils");
21
-
22
- var _extensionConfig = require("../extension-config");
23
-
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ExtensionCommand = void 0;
7
+ /* eslint-disable no-console */
8
+ const bluebird_1 = __importDefault(require("bluebird"));
9
+ const lodash_1 = __importDefault(require("lodash"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const support_1 = require("@appium/support");
12
+ const utils_1 = require("./utils");
13
+ const teen_process_1 = require("teen_process");
14
+ const extension_config_1 = require("../extension/extension-config");
15
+ const package_changed_1 = require("../extension/package-changed");
24
16
  const UPDATE_ALL = 'installed';
25
-
26
- class NotUpdatableError extends Error {}
27
-
28
- class NoUpdatesAvailableError extends Error {}
29
-
17
+ class NotUpdatableError extends Error {
18
+ }
19
+ class NoUpdatesAvailableError extends Error {
20
+ }
21
+ /**
22
+ * Omits `driverName`/`pluginName` props from the receipt to make a {@linkcode ExtManifest}
23
+ * @template {ExtensionType} ExtType
24
+ * @param {ExtInstallReceipt<ExtType>} receipt
25
+ * @returns {ExtManifest<ExtType>}
26
+ */
27
+ function receiptToManifest(receipt) {
28
+ return /** @type {ExtManifest<ExtType>} */ (lodash_1.default.omit(receipt, 'driverName', 'pluginName'));
29
+ }
30
+ /**
31
+ * @template {ExtensionType} ExtType
32
+ */
30
33
  class ExtensionCommand {
31
- constructor({
32
- config,
33
- json,
34
- type
35
- }) {
36
- this.config = config;
37
- this.type = type;
38
- this.isJsonOutput = json;
39
- this.npm = new _npm.default(this.config.appiumHome);
40
- this.knownExtensions = {};
41
- }
42
-
43
- async execute(args) {
44
- const cmd = args[`${this.type}Command`];
45
-
46
- if (!_lodash.default.isFunction(ExtensionCommand.prototype[cmd])) {
47
- throw new Error(`Cannot handle ${this.type} command ${cmd}`);
34
+ /**
35
+ * Build an ExtensionCommand
36
+ * @param {ExtensionCommandOptions<ExtType>} opts
37
+ */
38
+ constructor({ config, json }) {
39
+ this.config = config;
40
+ this.log = new support_1.console.CliConsole({ jsonMode: json });
41
+ this.isJsonOutput = Boolean(json);
48
42
  }
49
-
50
- const executeCmd = this[cmd].bind(this);
51
- return await executeCmd(args);
52
- }
53
-
54
- async list({
55
- showInstalled,
56
- showUpdates
57
- }) {
58
- const lsMsg = `Listing ${showInstalled ? 'installed' : 'available'} ${this.type}s`;
59
- const installedNames = Object.keys(this.config.installedExtensions);
60
- const knownNames = Object.keys(this.knownExtensions);
61
- const exts = [...installedNames, ...knownNames].reduce((acc, name) => {
62
- if (!acc[name]) {
63
- if (installedNames.includes(name)) {
64
- acc[name] = { ...this.config.installedExtensions[name],
65
- installed: true
66
- };
67
- } else if (!showInstalled) {
68
- acc[name] = {
69
- pkgName: this.knownExtensions[name],
70
- installed: false
71
- };
72
- }
73
- }
74
-
75
- return acc;
76
- }, {});
77
- await (0, _utils.spinWith)(this.isJsonOutput, lsMsg, async () => {
78
- if (!showUpdates) {
79
- return;
80
- }
81
-
82
- for (const [ext, data] of _lodash.default.toPairs(exts)) {
83
- const {
84
- installed,
85
- installType
86
- } = data;
87
-
88
- if (!installed || installType !== _extensionConfig.INSTALL_TYPE_NPM) {
89
- continue;
90
- }
91
-
92
- const updates = await this.checkForExtensionUpdate(ext);
93
- data.updateVersion = updates.safeUpdate;
94
- data.unsafeUpdateVersion = updates.unsafeUpdate;
95
- data.upToDate = updates.safeUpdate === null && updates.unsafeUpdate === null;
96
- }
97
- });
98
-
99
- if (this.isJsonOutput) {
100
- return exts;
43
+ /**
44
+ * `driver` or `plugin`, depending on the `ExtensionConfig`.
45
+ */
46
+ get type() {
47
+ return this.config.extensionType;
101
48
  }
102
-
103
- for (const [name, {
104
- installType,
105
- installSpec,
106
- installed,
107
- updateVersion,
108
- unsafeUpdateVersion,
109
- version,
110
- upToDate
111
- }] of _lodash.default.toPairs(exts)) {
112
- let typeTxt;
113
-
114
- switch (installType) {
115
- case _extensionConfig.INSTALL_TYPE_GIT:
116
- case _extensionConfig.INSTALL_TYPE_GITHUB:
117
- typeTxt = `(cloned from ${installSpec})`.yellow;
118
- break;
119
-
120
- case _extensionConfig.INSTALL_TYPE_LOCAL:
121
- typeTxt = `(linked from ${installSpec})`.magenta;
122
- break;
123
-
124
- default:
125
- typeTxt = '(NPM)';
126
- }
127
-
128
- const installTxt = installed ? `@${version.yellow} ${('[installed ' + typeTxt + ']').green}` : ' [not installed]'.grey;
129
- const updateTxt = showUpdates && updateVersion ? ` [${updateVersion} available]`.magenta : '';
130
- const upToDateTxt = showUpdates && upToDate ? ` [Up to date]`.green : '';
131
- const unsafeUpdateTxt = showUpdates && unsafeUpdateVersion ? ` [${unsafeUpdateVersion} available (potentially unsafe)]`.cyan : '';
132
- console.log(`- ${name.yellow}${installTxt}${updateTxt}${upToDateTxt}${unsafeUpdateTxt}`);
49
+ /**
50
+ * Logs a message and returns an {@linkcode Error} to throw.
51
+ *
52
+ * For TS to understand that a function throws an exception, it must actually throw an exception--
53
+ * in other words, _calling_ a function which is guaranteed to throw an exception is not enough--
54
+ * nor is something like `@returns {never}` which does not imply a thrown exception.
55
+ * @param {string} message
56
+ * @protected
57
+ * @throws {Error}
58
+ */
59
+ _createFatalError(message) {
60
+ return new Error(this.log.decorate(message, 'error'));
133
61
  }
134
-
135
- return exts;
136
- }
137
-
138
- async install({
139
- ext,
140
- installType,
141
- packageName
142
- }) {
143
- (0, _utils.log)(this.isJsonOutput, `Attempting to find and install ${this.type} '${ext}'`);
144
- let extData;
145
- let installSpec = ext;
146
-
147
- if (packageName && [_extensionConfig.INSTALL_TYPE_LOCAL, _extensionConfig.INSTALL_TYPE_NPM].includes(installType)) {
148
- throw new Error(`When using --source=${installType}, cannot also use --package`);
149
- }
150
-
151
- if (!packageName && [_extensionConfig.INSTALL_TYPE_GIT, _extensionConfig.INSTALL_TYPE_GITHUB].includes(installType)) {
152
- throw new Error(`When using --source=${installType}, must also use --package`);
62
+ /**
63
+ * Take a CLI parse and run an extension command based on its type
64
+ *
65
+ * @param {object} args - a key/value object with CLI flags and values
66
+ * @return {Promise<object>} the result of the specific command which is executed
67
+ */
68
+ async execute(args) {
69
+ const cmd = args[`${this.type}Command`];
70
+ if (!lodash_1.default.isFunction(this[cmd])) {
71
+ throw this._createFatalError(`Cannot handle ${this.type} command ${cmd}`);
72
+ }
73
+ const executeCmd = this[cmd].bind(this);
74
+ return await executeCmd(args);
153
75
  }
154
-
155
- if (installType === _extensionConfig.INSTALL_TYPE_LOCAL) {
156
- const msg = `Linking ${this.type} from local path`;
157
- const pkgJsonData = await (0, _utils.spinWith)(this.isJsonOutput, msg, async () => await this.npm.linkPackage(installSpec));
158
- extData = this.getExtensionFields(pkgJsonData);
159
- extData.installPath = extData.pkgName;
160
- } else if (installType === _extensionConfig.INSTALL_TYPE_GITHUB) {
161
- if (installSpec.split('/').length !== 2) {
162
- throw new Error(`Github ${this.type} spec ${installSpec} appeared to be invalid; ` + 'it should be of the form <org>/<repo>');
163
- }
164
-
165
- extData = await this.installViaNpm({
166
- ext: installSpec,
167
- pkgName: packageName
168
- });
169
- } else if (installType === _extensionConfig.INSTALL_TYPE_GIT) {
170
- installSpec = installSpec.replace(/\.git$/, '');
171
- extData = await this.installViaNpm({
172
- ext: installSpec,
173
- pkgName: packageName
174
- });
175
- } else {
176
- let name, pkgVer;
177
- const splits = installSpec.split('@');
178
-
179
- if (installSpec[0] === '@') {
180
- [name, pkgVer] = [`@${splits[1]}`, splits[2]];
181
- } else {
182
- [name, pkgVer] = splits;
183
- }
184
-
185
- let pkgName;
186
-
187
- if (installType === _extensionConfig.INSTALL_TYPE_NPM) {
188
- pkgName = name;
189
- } else {
76
+ /**
77
+ * List extensions
78
+ *
79
+ * @param {ListOptions} opts
80
+ * @return {Promise<ExtensionListData>} map of extension names to extension data
81
+ */
82
+ async list({ showInstalled, showUpdates }) {
83
+ const lsMsg = `Listing ${showInstalled ? 'installed' : 'available'} ${this.type}s`;
84
+ const installedNames = Object.keys(this.config.installedExtensions);
190
85
  const knownNames = Object.keys(this.knownExtensions);
191
-
192
- if (!_lodash.default.includes(knownNames, name)) {
193
- const msg = `Could not resolve ${this.type}; are you sure it's in the list ` + `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
194
- throw new Error(msg);
195
- }
196
-
197
- pkgName = this.knownExtensions[name];
198
- installType = _extensionConfig.INSTALL_TYPE_NPM;
199
- }
200
-
201
- extData = await this.installViaNpm({
202
- ext,
203
- pkgName,
204
- pkgVer
205
- });
206
- }
207
-
208
- const extName = extData[`${this.type}Name`];
209
- delete extData[`${this.type}Name`];
210
-
211
- if (this.config.isInstalled(extName)) {
212
- throw new Error(`A ${this.type} named '${extName}' is already installed. ` + `Did you mean to update? 'appium ${this.type} update'. See ` + `installed ${this.type}s with 'appium ${this.type} list --installed'.`);
86
+ const exts = [...installedNames, ...knownNames].reduce((acc, name) => {
87
+ if (!acc[name]) {
88
+ if (installedNames.includes(name)) {
89
+ acc[name] = {
90
+ ...this.config.installedExtensions[name],
91
+ installed: true,
92
+ };
93
+ }
94
+ else if (!showInstalled) {
95
+ acc[name] = { pkgName: this.knownExtensions[name], installed: false };
96
+ }
97
+ }
98
+ return acc;
99
+ },
100
+ /**
101
+ * This accumulator contains either {@linkcode UninstalledExtensionLIstData} _or_
102
+ * {@linkcode InstalledExtensionListData} without upgrade information (which is added by the below code block)
103
+ * @type {Record<string,Partial<InstalledExtensionListData>|UninstalledExtensionListData>}
104
+ */ ({}));
105
+ // if we want to show whether updates are available, put that behind a spinner
106
+ await (0, utils_1.spinWith)(this.isJsonOutput, lsMsg, async () => {
107
+ if (!showUpdates) {
108
+ return;
109
+ }
110
+ for (const [ext, data] of lodash_1.default.toPairs(exts)) {
111
+ if (!data.installed || data.installType !== extension_config_1.INSTALL_TYPE_NPM) {
112
+ // don't need to check for updates on exts that aren't installed
113
+ // also don't need to check for updates on non-npm exts
114
+ continue;
115
+ }
116
+ try {
117
+ const updates = await this.checkForExtensionUpdate(ext);
118
+ data.updateVersion = updates.safeUpdate;
119
+ data.unsafeUpdateVersion = updates.unsafeUpdate;
120
+ data.upToDate = updates.safeUpdate === null && updates.unsafeUpdate === null;
121
+ }
122
+ catch (e) {
123
+ data.updateError = e.message;
124
+ }
125
+ }
126
+ });
127
+ const listData = /** @type {ExtensionListData} */ (exts);
128
+ // if we're just getting the data, short circuit return here since we don't need to do any
129
+ // formatting logic
130
+ if (this.isJsonOutput) {
131
+ return listData;
132
+ }
133
+ for (const [name, data] of lodash_1.default.toPairs(listData)) {
134
+ let installTxt = ' [not installed]'.grey;
135
+ let updateTxt = '';
136
+ let upToDateTxt = '';
137
+ let unsafeUpdateTxt = '';
138
+ if (data.installed) {
139
+ const { installType, installSpec, updateVersion, unsafeUpdateVersion, version, upToDate, updateError, } = data;
140
+ let typeTxt;
141
+ switch (installType) {
142
+ case extension_config_1.INSTALL_TYPE_GIT:
143
+ case extension_config_1.INSTALL_TYPE_GITHUB:
144
+ typeTxt = `(cloned from ${installSpec})`.yellow;
145
+ break;
146
+ case extension_config_1.INSTALL_TYPE_LOCAL:
147
+ typeTxt = `(linked from ${installSpec})`.magenta;
148
+ break;
149
+ default:
150
+ typeTxt = '(NPM)';
151
+ }
152
+ installTxt = `@${version.yellow} ${('[installed ' + typeTxt + ']').green}`;
153
+ if (showUpdates) {
154
+ if (updateError) {
155
+ updateTxt = ` [Cannot check for updates: ${updateError}]`.red;
156
+ }
157
+ else {
158
+ if (updateVersion) {
159
+ updateTxt = ` [${updateVersion} available]`.magenta;
160
+ }
161
+ if (upToDate) {
162
+ upToDateTxt = ` [Up to date]`.green;
163
+ }
164
+ if (unsafeUpdateVersion) {
165
+ unsafeUpdateTxt = ` [${unsafeUpdateVersion} available (potentially unsafe)]`.cyan;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ this.log.log(`- ${name.yellow}${installTxt}${updateTxt}${upToDateTxt}${unsafeUpdateTxt}`);
171
+ }
172
+ return listData;
213
173
  }
214
-
215
- extData.installType = installType;
216
- extData.installSpec = installSpec;
217
- await this.config.addExtension(extName, extData);
218
- (0, _utils.log)(this.isJsonOutput, this.getPostInstallText({
219
- extName,
220
- extData
221
- }));
222
- return this.config.installedExtensions;
223
- }
224
-
225
- async installViaNpm({
226
- ext,
227
- pkgName,
228
- pkgVer
229
- }) {
230
- const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
231
- const specMsg = npmSpec === ext ? '' : ` using NPM install spec '${npmSpec}'`;
232
- const msg = `Installing '${ext}'${specMsg}`;
233
-
234
- try {
235
- const pkgJsonData = await (0, _utils.spinWith)(this.isJsonOutput, msg, async () => await this.npm.installPackage({
236
- pkgDir: _path.default.resolve(this.config.appiumHome, pkgName),
237
- pkgName,
238
- pkgVer
239
- }));
240
- const extData = this.getExtensionFields(pkgJsonData);
241
- extData.installPath = pkgName;
242
- return extData;
243
- } catch (err) {
244
- throw new Error(`Encountered an error when installing package: ${err.message}`);
174
+ /**
175
+ * Install an extension
176
+ *
177
+ * @param {InstallOpts} opts
178
+ * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data
179
+ */
180
+ async _install({ installSpec, installType, packageName }) {
181
+ /** @type {ExtInstallReceipt<ExtType>} */
182
+ let receipt;
183
+ if (packageName && [extension_config_1.INSTALL_TYPE_LOCAL, extension_config_1.INSTALL_TYPE_NPM].includes(installType)) {
184
+ throw this._createFatalError(`When using --source=${installType}, cannot also use --package`);
185
+ }
186
+ if (!packageName && [extension_config_1.INSTALL_TYPE_GIT, extension_config_1.INSTALL_TYPE_GITHUB].includes(installType)) {
187
+ throw this._createFatalError(`When using --source=${installType}, must also use --package`);
188
+ }
189
+ /**
190
+ * @type {InstallViaNpmArgs}
191
+ */
192
+ let installViaNpmOpts;
193
+ /**
194
+ * The probable (?) name of the extension derived from the install spec.
195
+ *
196
+ * If using a local install type, this will remain empty.
197
+ * @type {string}
198
+ */
199
+ let probableExtName = '';
200
+ // depending on `installType`, build the options to pass into `installViaNpm`
201
+ if (installType === extension_config_1.INSTALL_TYPE_GITHUB) {
202
+ if (installSpec.split('/').length !== 2) {
203
+ throw this._createFatalError(`Github ${this.type} spec ${installSpec} appeared to be invalid; ` +
204
+ 'it should be of the form <org>/<repo>');
205
+ }
206
+ installViaNpmOpts = {
207
+ installSpec,
208
+ installType,
209
+ pkgName: /** @type {string} */ (packageName),
210
+ };
211
+ probableExtName = installSpec;
212
+ }
213
+ else if (installType === extension_config_1.INSTALL_TYPE_GIT) {
214
+ // git urls can have '.git' at the end, but this is not necessary and would complicate the
215
+ // way we download and name directories, so we can just remove it
216
+ installSpec = installSpec.replace(/\.git$/, '');
217
+ installViaNpmOpts = {
218
+ installSpec,
219
+ installType,
220
+ pkgName: /** @type {string} */ (packageName),
221
+ };
222
+ probableExtName = installSpec;
223
+ }
224
+ else {
225
+ let pkgName, pkgVer;
226
+ if (installType === extension_config_1.INSTALL_TYPE_LOCAL) {
227
+ pkgName = path_1.default.isAbsolute(installSpec) ? installSpec : path_1.default.resolve(installSpec);
228
+ }
229
+ else {
230
+ // at this point we have either an npm package or an appium verified extension
231
+ // name or a local path. both of which will be installed via npm.
232
+ // extensions installed via npm can include versions or tags after the '@'
233
+ // sign, so check for that. We also need to be careful that package names themselves can
234
+ // contain the '@' symbol, as in `npm install @appium/fake-driver@1.2.0`
235
+ let name;
236
+ const splits = installSpec.split('@');
237
+ if (installSpec[0] === '@') {
238
+ // this is the case where we have an npm org included in the package name
239
+ [name, pkgVer] = [`@${splits[1]}`, splits[2]];
240
+ }
241
+ else {
242
+ // this is the case without an npm org
243
+ [name, pkgVer] = splits;
244
+ }
245
+ if (installType === extension_config_1.INSTALL_TYPE_NPM) {
246
+ // if we're installing a named package from npm, we don't need to check
247
+ // against the appium extension list; just use the installSpec as is
248
+ pkgName = name;
249
+ }
250
+ else {
251
+ // if we're installing a named appium driver (like 'xcuitest') we need to
252
+ // dereference the actual npm package ('appiupm-xcuitest-driver'), so
253
+ // check it exists and get the correct package
254
+ const knownNames = Object.keys(this.knownExtensions);
255
+ if (!lodash_1.default.includes(knownNames, name)) {
256
+ const msg = `Could not resolve ${this.type}; are you sure it's in the list ` +
257
+ `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
258
+ throw this._createFatalError(msg);
259
+ }
260
+ probableExtName = name;
261
+ pkgName = this.knownExtensions[name];
262
+ // given that we'll use the install type in the driver json, store it as
263
+ // 'npm' now
264
+ installType = extension_config_1.INSTALL_TYPE_NPM;
265
+ }
266
+ }
267
+ installViaNpmOpts = { installSpec, pkgName, pkgVer, installType };
268
+ }
269
+ // fail fast here if we can
270
+ if (probableExtName && this.config.isInstalled(probableExtName)) {
271
+ throw this._createFatalError(`A ${this.type} named "${probableExtName}" is already installed. ` +
272
+ `Did you mean to update? Run "appium ${this.type} update". See ` +
273
+ `installed ${this.type}s with "appium ${this.type} list --installed".`);
274
+ }
275
+ receipt = await this.installViaNpm(installViaNpmOpts);
276
+ // this _should_ be the same as `probablyExtName` as the one derived above unless
277
+ // install type is local.
278
+ /** @type {string} */
279
+ const extName = receipt[ /** @type {string} */(`${this.type}Name`)];
280
+ // check _a second time_ with the more-accurate extName
281
+ if (this.config.isInstalled(extName)) {
282
+ throw this._createFatalError(`A ${this.type} named "${extName}" is already installed. ` +
283
+ `Did you mean to update? Run "appium ${this.type} update". See ` +
284
+ `installed ${this.type}s with "appium ${this.type} list --installed".`);
285
+ }
286
+ // this field does not exist as such in the manifest (it's used as a property name instead)
287
+ // so that's why it's being removed here.
288
+ /** @type {ExtManifest<ExtType>} */
289
+ const extManifest = receiptToManifest(receipt);
290
+ const [errors, warnings] = await bluebird_1.default.all([
291
+ this.config.getProblems(extName, extManifest),
292
+ this.config.getWarnings(extName, extManifest),
293
+ ]);
294
+ const errorMap = new Map([[extName, errors]]);
295
+ const warningMap = new Map([[extName, warnings]]);
296
+ const { errorSummaries, warningSummaries } = this.config.getValidationResultSummaries(errorMap, warningMap);
297
+ if (!lodash_1.default.isEmpty(errorSummaries)) {
298
+ throw this._createFatalError(errorSummaries.join('\n'));
299
+ }
300
+ // note that we won't show any warnings if there were errors.
301
+ if (!lodash_1.default.isEmpty(warningSummaries)) {
302
+ this.log.warn(warningSummaries.join('\n'));
303
+ }
304
+ await this.config.addExtension(extName, extManifest);
305
+ // update the hash if we've changed the local `package.json`
306
+ if (await support_1.env.hasAppiumDependency(this.config.appiumHome)) {
307
+ await (0, package_changed_1.packageDidChange)(this.config.appiumHome);
308
+ }
309
+ // log info for the user
310
+ this.log.info(this.getPostInstallText({ extName, extData: receipt }));
311
+ return this.config.installedExtensions;
245
312
  }
246
- }
247
-
248
- getPostInstallText() {
249
- throw new Error('Must be implemented in final class');
250
- }
251
-
252
- getExtensionFields(pkgJsonData) {
253
- if (!pkgJsonData.appium) {
254
- throw new Error(`Installed driver did not have an 'appium' section in its ` + `package.json file as expected`);
313
+ /**
314
+ * Install an extension via NPM
315
+ *
316
+ * @param {InstallViaNpmArgs} args
317
+ * @returns {Promise<ExtInstallReceipt<ExtType>>}
318
+ */
319
+ async installViaNpm({ installSpec, pkgName, pkgVer, installType }) {
320
+ const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
321
+ const specMsg = npmSpec === installSpec ? '' : ` using NPM install spec '${npmSpec}'`;
322
+ const msg = `Installing '${installSpec}'${specMsg}`;
323
+ try {
324
+ const { pkg, path } = await (0, utils_1.spinWith)(this.isJsonOutput, msg, async () => {
325
+ const { pkg, installPath: path } = await support_1.npm.installPackage(this.config.appiumHome, pkgName, {
326
+ pkgVer,
327
+ installType,
328
+ });
329
+ this.validatePackageJson(pkg, installSpec);
330
+ return { pkg, path };
331
+ });
332
+ return this.getInstallationReceipt({
333
+ pkg,
334
+ installPath: path,
335
+ installType,
336
+ installSpec,
337
+ });
338
+ }
339
+ catch (err) {
340
+ throw this._createFatalError(`Encountered an error when installing package: ${err.message}`);
341
+ }
255
342
  }
256
-
257
- const {
258
- appium,
259
- name,
260
- version
261
- } = pkgJsonData;
262
- this.validateExtensionFields(appium);
263
- return { ...appium,
264
- pkgName: name,
265
- version
266
- };
267
- }
268
-
269
- validateExtensionFields() {
270
- throw new Error('Must be implemented in final class');
271
- }
272
-
273
- async uninstall({
274
- ext
275
- }) {
276
- if (!this.config.isInstalled(ext)) {
277
- throw new Error(`Can't uninstall ${this.type} '${ext}'; it is not installed`);
343
+ /**
344
+ * Get the text which should be displayed to the user after an extension has been installed. This
345
+ * is designed to be overridden by drivers/plugins with their own particular text.
346
+ *
347
+ * @param {ExtensionArgs} args
348
+ * @returns {string}
349
+ */
350
+ // eslint-disable-next-line no-unused-vars
351
+ getPostInstallText(args) {
352
+ throw this._createFatalError('Must be implemented in final class');
278
353
  }
279
-
280
- try {
281
- await _appiumSupport.fs.rimraf(this.config.getInstallPath(ext));
282
- } finally {
283
- await this.config.removeExtension(ext);
354
+ /**
355
+ * Once a package is installed on-disk, this gathers some necessary metadata for validation.
356
+ *
357
+ * @param {GetInstallationReceiptOpts<ExtType>} opts
358
+ * @returns {ExtInstallReceipt<ExtType>}
359
+ */
360
+ getInstallationReceipt({ pkg, installPath, installType, installSpec }) {
361
+ const { appium, name, version, peerDependencies } = pkg;
362
+ /** @type {import('appium/types').InternalMetadata} */
363
+ const internal = {
364
+ pkgName: name,
365
+ version,
366
+ installType,
367
+ installSpec,
368
+ installPath,
369
+ appiumVersion: peerDependencies?.appium,
370
+ };
371
+ /** @type {ExtMetadata<ExtType>} */
372
+ const extMetadata = appium;
373
+ return {
374
+ ...internal,
375
+ ...extMetadata,
376
+ };
284
377
  }
285
-
286
- (0, _utils.log)(this.isJsonOutput, `Successfully uninstalled ${this.type} '${ext}'`.green);
287
- return this.config.installedExtensions;
288
- }
289
-
290
- async update({
291
- ext,
292
- unsafe
293
- }) {
294
- const shouldUpdateAll = ext === UPDATE_ALL;
295
-
296
- if (!shouldUpdateAll && !this.config.isInstalled(ext)) {
297
- throw new Error(`The ${this.type} '${ext}' was not installed, so can't be updated`);
378
+ /**
379
+ * Validates the _required_ root fields of an extension's `package.json` file.
380
+ *
381
+ * These required fields are:
382
+ * - `name`
383
+ * - `version`
384
+ * - `appium`
385
+ * @param {import('type-fest').PackageJson} pkg - `package.json` of extension
386
+ * @param {string} installSpec - Extension name/spec
387
+ * @throws {ReferenceError} If `package.json` has a missing or invalid field
388
+ * @returns {pkg is ExtPackageJson<ExtType>}
389
+ */
390
+ validatePackageJson(pkg, installSpec) {
391
+ const { appium, name, version } = /** @type {ExtPackageJson<ExtType>} */ (pkg);
392
+ /**
393
+ *
394
+ * @param {string} field
395
+ * @returns {ReferenceError}
396
+ */
397
+ const createMissingFieldError = (field) => new ReferenceError(`${this.type} "${installSpec}" invalid; missing a \`${field}\` field of its \`package.json\``);
398
+ if (!name) {
399
+ throw createMissingFieldError('name');
400
+ }
401
+ if (!version) {
402
+ throw createMissingFieldError('version');
403
+ }
404
+ if (!appium) {
405
+ throw createMissingFieldError('appium');
406
+ }
407
+ this.validateExtensionFields(appium, installSpec);
408
+ return true;
298
409
  }
299
-
300
- const extsToUpdate = shouldUpdateAll ? Object.keys(this.config.installedExtensions) : [ext];
301
- const errors = {};
302
- const updates = {};
303
-
304
- for (const e of extsToUpdate) {
305
- try {
306
- await (0, _utils.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' is updatable`, () => {
307
- if (this.config.installedExtensions[e].installType !== _extensionConfig.INSTALL_TYPE_NPM) {
308
- throw new NotUpdatableError();
309
- }
310
- });
311
- const update = await (0, _utils.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' needs an update`, async () => {
312
- const update = await this.checkForExtensionUpdate(e);
313
-
314
- if (!(update.safeUpdate || update.unsafeUpdate)) {
315
- throw new NoUpdatesAvailableError();
316
- }
317
-
318
- return update;
319
- });
320
-
321
- if (!unsafe && !update.safeUpdate) {
322
- throw new Error(`The ${this.type} '${e}' has a major revision update ` + `(${update.current} => ${update.unsafeUpdate}), which could include ` + `breaking changes. If you want to apply this update, re-run with --unsafe`);
323
- }
324
-
325
- const updateVer = unsafe && update.unsafeUpdate ? update.unsafeUpdate : update.safeUpdate;
326
- await (0, _utils.spinWith)(this.isJsonOutput, `Updating driver '${e}' from ${update.current} to ${updateVer}`, async () => await this.updateExtension(e, updateVer));
327
- updates[e] = {
328
- from: update.current,
329
- to: updateVer
330
- };
331
- } catch (err) {
332
- errors[e] = err;
333
- }
410
+ /**
411
+ * For any `package.json` fields which a particular type of extension requires, validate the
412
+ * presence and form of those fields on the `package.json` data, throwing an error if anything is
413
+ * amiss.
414
+ *
415
+ * @param {ExtMetadata<ExtType>} extMetadata - the data in the "appium" field of `package.json` for an extension
416
+ * @param {string} installSpec - Extension name/spec
417
+ */
418
+ // eslint-disable-next-line no-unused-vars
419
+ validateExtensionFields(extMetadata, installSpec) {
420
+ throw this._createFatalError('Must be implemented in final class');
334
421
  }
335
-
336
- (0, _utils.log)(this.isJsonOutput, 'Update report:');
337
-
338
- for (const [e, update] of _lodash.default.toPairs(updates)) {
339
- (0, _utils.log)(this.isJsonOutput, `- ${this.type} ${e} updated: ${update.from} => ${update.to}`.green);
422
+ /**
423
+ * Uninstall an extension.
424
+ *
425
+ * First tries to do this via `npm uninstall`, but if that fails, just `rm -rf`'s the extension dir.
426
+ *
427
+ * Will only remove the extension from the manifest if it has been successfully removed.
428
+ *
429
+ * @param {UninstallOpts} opts
430
+ * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data (without the extension just uninstalled)
431
+ */
432
+ async _uninstall({ installSpec }) {
433
+ if (!this.config.isInstalled(installSpec)) {
434
+ throw this._createFatalError(`Can't uninstall ${this.type} '${installSpec}'; it is not installed`);
435
+ }
436
+ const pkgName = this.config.installedExtensions[installSpec].pkgName;
437
+ await support_1.npm.uninstallPackage(this.config.appiumHome, pkgName);
438
+ await this.config.removeExtension(installSpec);
439
+ this.log.ok(`Successfully uninstalled ${this.type} '${installSpec}'`.green);
440
+ return this.config.installedExtensions;
340
441
  }
341
-
342
- for (const [e, err] of _lodash.default.toPairs(errors)) {
343
- if (err instanceof NotUpdatableError) {
344
- (0, _utils.log)(this.isJsonOutput, `- '${e}' was not installed via npm, so we could not check ` + `for updates`.yellow);
345
- } else if (err instanceof NoUpdatesAvailableError) {
346
- (0, _utils.log)(this.isJsonOutput, `- '${e}' had no updates available`.yellow);
347
- } else {
348
- (0, _utils.log)(this.isJsonOutput, `- '${e}' failed to update: ${err}`.red);
349
- }
442
+ /**
443
+ * Attempt to update one or more drivers using NPM
444
+ *
445
+ * @param {ExtensionUpdateOpts} updateSpec
446
+ * @return {Promise<ExtensionUpdateResult>}
447
+ */
448
+ async _update({ installSpec, unsafe }) {
449
+ const shouldUpdateAll = installSpec === UPDATE_ALL;
450
+ // if we're specifically requesting an update for an extension, make sure it's installed
451
+ if (!shouldUpdateAll && !this.config.isInstalled(installSpec)) {
452
+ throw this._createFatalError(`The ${this.type} "${installSpec}" was not installed, so can't be updated`);
453
+ }
454
+ const extsToUpdate = shouldUpdateAll
455
+ ? Object.keys(this.config.installedExtensions)
456
+ : [installSpec];
457
+ // 'errors' will have ext names as keys and error objects as values
458
+ /** @type {Record<string,Error>} */
459
+ const errors = {};
460
+ // 'updates' will have ext names as keys and update objects as values, where an update
461
+ // object is of the form {from: versionString, to: versionString}
462
+ /** @type {Record<string,UpdateReport>} */
463
+ const updates = {};
464
+ for (const e of extsToUpdate) {
465
+ try {
466
+ await (0, utils_1.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' is updatable`, () => {
467
+ if (this.config.installedExtensions[e].installType !== extension_config_1.INSTALL_TYPE_NPM) {
468
+ throw new NotUpdatableError();
469
+ }
470
+ });
471
+ const update = await (0, utils_1.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' needs an update`, async () => {
472
+ const update = await this.checkForExtensionUpdate(e);
473
+ if (!(update.safeUpdate || update.unsafeUpdate)) {
474
+ throw new NoUpdatesAvailableError();
475
+ }
476
+ return update;
477
+ });
478
+ if (!unsafe && !update.safeUpdate) {
479
+ throw this._createFatalError(`The ${this.type} '${e}' has a major revision update ` +
480
+ `(${update.current} => ${update.unsafeUpdate}), which could include ` +
481
+ `breaking changes. If you want to apply this update, re-run with --unsafe`);
482
+ }
483
+ const updateVer = unsafe && update.unsafeUpdate ? update.unsafeUpdate : update.safeUpdate;
484
+ await (0, utils_1.spinWith)(this.isJsonOutput, `Updating driver '${e}' from ${update.current} to ${updateVer}`, async () => await this.updateExtension(e, updateVer));
485
+ updates[e] = { from: update.current, to: updateVer };
486
+ }
487
+ catch (err) {
488
+ errors[e] = err;
489
+ }
490
+ }
491
+ this.log.info('Update report:');
492
+ for (const [e, update] of lodash_1.default.toPairs(updates)) {
493
+ this.log.ok(` - ${this.type} ${e} updated: ${update.from} => ${update.to}`.green);
494
+ }
495
+ for (const [e, err] of lodash_1.default.toPairs(errors)) {
496
+ if (err instanceof NotUpdatableError) {
497
+ this.log.warn(` - '${e}' was not installed via npm, so we could not check ` + `for updates`.yellow);
498
+ }
499
+ else if (err instanceof NoUpdatesAvailableError) {
500
+ this.log.info(` - '${e}' had no updates available`.yellow);
501
+ }
502
+ else {
503
+ // otherwise, make it pop with red!
504
+ this.log.error(` - '${e}' failed to update: ${err}`.red);
505
+ }
506
+ }
507
+ return { updates, errors };
350
508
  }
351
-
352
- return {
353
- updates,
354
- errors
355
- };
356
- }
357
-
358
- async checkForExtensionUpdate(ext) {
359
- const {
360
- version,
361
- pkgName
362
- } = this.config.installedExtensions[ext];
363
- let unsafeUpdate = await this.npm.getLatestVersion(pkgName);
364
- let safeUpdate = await this.npm.getLatestSafeUpgradeVersion(pkgName, version);
365
-
366
- if (!_appiumSupport.util.compareVersions(unsafeUpdate, '>', version)) {
367
- unsafeUpdate = null;
368
- safeUpdate = null;
509
+ /**
510
+ * Given an extension name, figure out what its highest possible version upgrade is, and also the
511
+ * highest possible safe upgrade.
512
+ *
513
+ * @param {string} ext - name of extension
514
+ * @return {Promise<PossibleUpdates>}
515
+ */
516
+ async checkForExtensionUpdate(ext) {
517
+ // TODO decide how we want to handle beta versions?
518
+ // this is a helper method, 'ext' is assumed to already be installed here, and of the npm
519
+ // install type
520
+ const { version, pkgName } = this.config.installedExtensions[ext];
521
+ /** @type {string?} */
522
+ let unsafeUpdate = await support_1.npm.getLatestVersion(this.config.appiumHome, pkgName);
523
+ let safeUpdate = await support_1.npm.getLatestSafeUpgradeVersion(this.config.appiumHome, pkgName, version);
524
+ if (unsafeUpdate !== null && !support_1.util.compareVersions(unsafeUpdate, '>', version)) {
525
+ // the latest version is not greater than the current version, so there's no possible update
526
+ unsafeUpdate = null;
527
+ safeUpdate = null;
528
+ }
529
+ if (unsafeUpdate && unsafeUpdate === safeUpdate) {
530
+ // the latest update is the same as the safe update, which means it's not actually unsafe
531
+ unsafeUpdate = null;
532
+ }
533
+ if (safeUpdate && !support_1.util.compareVersions(safeUpdate, '>', version)) {
534
+ // even the safe update is not later than the current, so it is not actually an update
535
+ safeUpdate = null;
536
+ }
537
+ return { current: version, safeUpdate, unsafeUpdate };
369
538
  }
370
-
371
- if (unsafeUpdate && unsafeUpdate === safeUpdate) {
372
- unsafeUpdate = null;
539
+ /**
540
+ * Actually update an extension installed by NPM, using the NPM cli. And update the installation
541
+ * manifest.
542
+ *
543
+ * @param {string} installSpec - name of extension to update
544
+ * @param {string} version - version string identifier to update extension to
545
+ * @returns {Promise<void>}
546
+ */
547
+ async updateExtension(installSpec, version) {
548
+ const { pkgName, installType } = this.config.installedExtensions[installSpec];
549
+ const extData = await this.installViaNpm({
550
+ installSpec,
551
+ installType,
552
+ pkgName,
553
+ pkgVer: version,
554
+ });
555
+ delete extData[ /** @type {string} */(`${this.type}Name`)];
556
+ await this.config.updateExtension(installSpec, extData);
373
557
  }
374
-
375
- if (safeUpdate && !_appiumSupport.util.compareVersions(safeUpdate, '>', version)) {
376
- safeUpdate = null;
558
+ /**
559
+ * Runs a script cached inside the "scripts" field under "appium"
560
+ * inside of the driver/plugins "package.json" file. Will throw
561
+ * an error if the driver/plugin does not contain a "scripts" field
562
+ * underneath the "appium" field in its package.json, if the
563
+ * "scripts" field is not a plain object, or if the scriptName is
564
+ * not found within "scripts" object.
565
+ *
566
+ * @param {RunOptions} opts
567
+ * @return {Promise<RunOutput>}
568
+ */
569
+ async _run({ installSpec, scriptName, extraArgs = [] }) {
570
+ if (!this.config.isInstalled(installSpec)) {
571
+ throw this._createFatalError(`The ${this.type} "${installSpec}" is not installed`);
572
+ }
573
+ const extConfig = this.config.installedExtensions[installSpec];
574
+ // note: TS cannot understand that _.has() is a type guard
575
+ if (!('scripts' in extConfig)) {
576
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' does not contain the ` +
577
+ `"scripts" field underneath the "appium" field in its package.json`);
578
+ }
579
+ const extScripts = extConfig.scripts;
580
+ if (!extScripts || !lodash_1.default.isPlainObject(extScripts)) {
581
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' "scripts" field must be a plain object`);
582
+ }
583
+ if (!(scriptName in extScripts)) {
584
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' does not support the script: '${scriptName}'`);
585
+ }
586
+ const runner = new teen_process_1.SubProcess(process.execPath, [extScripts[scriptName], ...extraArgs], {
587
+ cwd: this.config.getInstallPath(installSpec),
588
+ });
589
+ const output = new utils_1.RingBuffer(50);
590
+ runner.on('stream-line', (line) => {
591
+ output.enqueue(line);
592
+ this.log.log(line);
593
+ });
594
+ await runner.start(0);
595
+ try {
596
+ await runner.join();
597
+ this.log.ok(`${scriptName} successfully ran`.green);
598
+ return { output: output.getBuff() };
599
+ }
600
+ catch (err) {
601
+ this.log.error(`Encountered an error when running '${scriptName}': ${err.message}`.red);
602
+ return { error: err.message, output: output.getBuff() };
603
+ }
377
604
  }
378
-
379
- return {
380
- current: version,
381
- safeUpdate,
382
- unsafeUpdate
383
- };
384
- }
385
-
386
- async updateExtension(ext, version) {
387
- const {
388
- pkgName
389
- } = this.config.installedExtensions[ext];
390
- await this.installViaNpm({
391
- ext,
392
- pkgName,
393
- pkgVer: version
394
- });
395
- this.config.installedExtensions[ext].version = version;
396
- await this.config.write();
397
- }
398
-
399
605
  }
400
-
401
- exports.default = ExtensionCommand;require('source-map-support').install();
402
-
403
-
404
- //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9jbGkvZXh0ZW5zaW9uLWNvbW1hbmQuanMiXSwibmFtZXMiOlsiVVBEQVRFX0FMTCIsIk5vdFVwZGF0YWJsZUVycm9yIiwiRXJyb3IiLCJOb1VwZGF0ZXNBdmFpbGFibGVFcnJvciIsIkV4dGVuc2lvbkNvbW1hbmQiLCJjb25zdHJ1Y3RvciIsImNvbmZpZyIsImpzb24iLCJ0eXBlIiwiaXNKc29uT3V0cHV0IiwibnBtIiwiTlBNIiwiYXBwaXVtSG9tZSIsImtub3duRXh0ZW5zaW9ucyIsImV4ZWN1dGUiLCJhcmdzIiwiY21kIiwiXyIsImlzRnVuY3Rpb24iLCJwcm90b3R5cGUiLCJleGVjdXRlQ21kIiwiYmluZCIsImxpc3QiLCJzaG93SW5zdGFsbGVkIiwic2hvd1VwZGF0ZXMiLCJsc01zZyIsImluc3RhbGxlZE5hbWVzIiwiT2JqZWN0Iiwia2V5cyIsImluc3RhbGxlZEV4dGVuc2lvbnMiLCJrbm93bk5hbWVzIiwiZXh0cyIsInJlZHVjZSIsImFjYyIsIm5hbWUiLCJpbmNsdWRlcyIsImluc3RhbGxlZCIsInBrZ05hbWUiLCJleHQiLCJkYXRhIiwidG9QYWlycyIsImluc3RhbGxUeXBlIiwiSU5TVEFMTF9UWVBFX05QTSIsInVwZGF0ZXMiLCJjaGVja0ZvckV4dGVuc2lvblVwZGF0ZSIsInVwZGF0ZVZlcnNpb24iLCJzYWZlVXBkYXRlIiwidW5zYWZlVXBkYXRlVmVyc2lvbiIsInVuc2FmZVVwZGF0ZSIsInVwVG9EYXRlIiwiaW5zdGFsbFNwZWMiLCJ2ZXJzaW9uIiwidHlwZVR4dCIsIklOU1RBTExfVFlQRV9HSVQiLCJJTlNUQUxMX1RZUEVfR0lUSFVCIiwieWVsbG93IiwiSU5TVEFMTF9UWVBFX0xPQ0FMIiwibWFnZW50YSIsImluc3RhbGxUeHQiLCJncmVlbiIsImdyZXkiLCJ1cGRhdGVUeHQiLCJ1cFRvRGF0ZVR4dCIsInVuc2FmZVVwZGF0ZVR4dCIsImN5YW4iLCJjb25zb2xlIiwibG9nIiwiaW5zdGFsbCIsInBhY2thZ2VOYW1lIiwiZXh0RGF0YSIsIm1zZyIsInBrZ0pzb25EYXRhIiwibGlua1BhY2thZ2UiLCJnZXRFeHRlbnNpb25GaWVsZHMiLCJpbnN0YWxsUGF0aCIsInNwbGl0IiwibGVuZ3RoIiwiaW5zdGFsbFZpYU5wbSIsInJlcGxhY2UiLCJwa2dWZXIiLCJzcGxpdHMiLCJKU09OIiwic3RyaW5naWZ5IiwiZXh0TmFtZSIsImlzSW5zdGFsbGVkIiwiYWRkRXh0ZW5zaW9uIiwiZ2V0UG9zdEluc3RhbGxUZXh0IiwibnBtU3BlYyIsInNwZWNNc2ciLCJpbnN0YWxsUGFja2FnZSIsInBrZ0RpciIsInBhdGgiLCJyZXNvbHZlIiwiZXJyIiwibWVzc2FnZSIsImFwcGl1bSIsInZhbGlkYXRlRXh0ZW5zaW9uRmllbGRzIiwidW5pbnN0YWxsIiwiZnMiLCJyaW1yYWYiLCJnZXRJbnN0YWxsUGF0aCIsInJlbW92ZUV4dGVuc2lvbiIsInVwZGF0ZSIsInVuc2FmZSIsInNob3VsZFVwZGF0ZUFsbCIsImV4dHNUb1VwZGF0ZSIsImVycm9ycyIsImUiLCJjdXJyZW50IiwidXBkYXRlVmVyIiwidXBkYXRlRXh0ZW5zaW9uIiwiZnJvbSIsInRvIiwicmVkIiwiZ2V0TGF0ZXN0VmVyc2lvbiIsImdldExhdGVzdFNhZmVVcGdyYWRlVmVyc2lvbiIsInV0aWwiLCJjb21wYXJlVmVyc2lvbnMiLCJ3cml0ZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFHQSxNQUFNQSxVQUFVLEdBQUcsV0FBbkI7O0FBRUEsTUFBTUMsaUJBQU4sU0FBZ0NDLEtBQWhDLENBQXNDOztBQUN0QyxNQUFNQyx1QkFBTixTQUFzQ0QsS0FBdEMsQ0FBNEM7O0FBRTdCLE1BQU1FLGdCQUFOLENBQXVCO0FBZXBDQyxFQUFBQSxXQUFXLENBQUU7QUFBQ0MsSUFBQUEsTUFBRDtBQUFTQyxJQUFBQSxJQUFUO0FBQWVDLElBQUFBO0FBQWYsR0FBRixFQUF3QjtBQUNqQyxTQUFLRixNQUFMLEdBQWNBLE1BQWQ7QUFDQSxT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TUFBQUEsT0FBTjtBQUFlMEMsTUFBQUEsTUFBTSxFQUFFNUI7QUFBdkIsS0FBbkIsQ0FBTjtBQUNBLFNBQUs3QyxNQUFMLENBQVl1QixtQkFBWixDQUFnQ1MsR0FBaEMsRUFBcUNhLE9BQXJDLEdBQStDQSxPQUEvQztBQUNBLFVBQU0sS0FBSzdDLE1BQUwsQ0FBWWdILEtBQVosRUFBTjtBQUNEOztBQXhkbUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5cbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgTlBNIGZyb20gJy4vbnBtJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZnMsIHV0aWwgfSBmcm9tICdhcHBpdW0tc3VwcG9ydCc7XG5pbXBvcnQgeyBsb2csIHNwaW5XaXRoIH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgeyBJTlNUQUxMX1RZUEVfTlBNLCBJTlNUQUxMX1RZUEVfR0lULCBJTlNUQUxMX1RZUEVfR0lUSFVCLFxuICAgICAgICAgSU5TVEFMTF9UWVBFX0xPQ0FMIH0gZnJvbSAnLi4vZXh0ZW5zaW9uLWNvbmZpZyc7XG5cbmNvbnN0IFVQREFURV9BTEwgPSAnaW5zdGFsbGVkJztcblxuY2xhc3MgTm90VXBkYXRhYmxlRXJyb3IgZXh0ZW5kcyBFcnJvciB7fVxuY2xhc3MgTm9VcGRhdGVzQXZhaWxhYmxlRXJyb3IgZXh0ZW5kcyBFcnJvciB7fVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBFeHRlbnNpb25Db21tYW5kIHtcblxuICAvKipcbiAgICogQHR5cGVkZWYge09iamVjdH0gRXh0ZW5zaW9uQ29tbWFuZENvbnN0cnVjdG9yXG4gICAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBjb25maWcgLSB0aGUgRHJpdmVyQ29uZmlnIG9yIFBsdWdpbkNvbmZpZyBvYmplY3QgdXNlZCBmb3IgdGhpcyBjb21tYW5kXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0ganNvbiAtIHdoZXRoZXIgdGhlIG91dHB1dCBvZiB0aGlzIGNvbW1hbmQgc2hvdWxkIGJlIEpTT04gb3IgdGV4dFxuICAgKiBAcHJvcGVydHkge3N0cmluZ30gdHlwZSAtIERSSVZFUl9UWVBFIG9yIFBMVUdJTl9UWVBFXG4gICAqL1xuXG4gIC8qKlxuICAgKiBCdWlsZCBhbiBFeHRlbnNpb25Db21tYW5kXG4gICAqXG4gICAqIEBwYXJhbSB7RXh0ZW5zaW9uQ29tbWFuZENvbnN0cnVjdG9yfSBvcHRzXG4gICAqIEByZXR1cm4ge0V4dGVuc2lvbkNvbW1hbmR9XG4gICAqL1xuICBjb25zdHJ1Y3RvciAoe2NvbmZpZywganNvbiwgdHlwZX0pIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgIHRoaXMuaXNKc29uT3V0cHV0ID0ganNvbjtcbiAgICB0aGlzLm5wbSA9IG5ldyBOUE0odGhpcy5jb25maWcuYXBwaXVtSG9tZSk7XG4gICAgdGhpcy5rbm93bkV4dGVuc2lvbnMgPSB7fTsgLy8gdGhpcyBuZWVkcyB0byBiZSBvdmVycmlkZGVuIGluIGZpbmFsIGNsYXNzXG4gIH1cblxuICAvKipcbiAgICogVGFrZSBhIENMSSBwYXJzZSBhbmQgcnVuIGFuIGV4dGVuc2lvbiBjb21tYW5kIGJhc2VkIG9uIGl0cyB0eXBlXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gYSBrZXkvdmFsdWUgb2JqZWN0IHdpdGggQ0xJIGZsYWdzIGFuZCB2YWx1ZXNcbiAgICogQHJldHVybiB7b2JqZWN0fSB0aGUgcmVzdWx0IG9mIHRoZSBzcGVjaWZpYyBjb21tYW5kIHdoaWNoIGlzIGV4ZWN1dGVkXG4gICAqL1xuICBhc3luYyBleGVjdXRlIChhcmdzKSB7XG4gICAgY29uc3QgY21kID0gYXJnc1tgJHt0aGlzLnR5cGV9Q29tbWFuZGBdO1xuICAgIGlmICghXy5pc0Z1bmN0aW9uKEV4dGVuc2lvbkNvbW1hbmQucHJvdG90eXBlW2NtZF0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBoYW5kbGUgJHt0aGlzLnR5cGV9IGNvbW1hbmQgJHtjbWR9YCk7XG4gICAgfVxuICAgIGNvbnN0IGV4ZWN1dGVDbWQgPSB0aGlzW2NtZF0uYmluZCh0aGlzKTtcbiAgICByZXR1cm4gYXdhaXQgZXhlY3V0ZUNtZChhcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBMaXN0QXJnc1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IHNob3dJbnN0YWxsZWQgLSB3aGV0aGVyIHNob3VsZCBzaG93IG9ubHkgaW5zdGFsbGVkIGV4dGVuc2lvbnNcbiAgICogQHByb3BlcnR5IHtib29sZWFufSBzaG93VXBkYXRlcyAtIHdoZXRoZXIgc2hvdWxkIHNob3cgYXZhaWxhYmxlIHVwZGF0ZXNcbiAgICovXG5cbiAgLyoqXG4gICAqIExpc3QgZXh0ZW5zaW9uc1xuICAgKlxuICAgKiBAcGFyYW0ge0xpc3RBcmdzfSBhcmdzXG4gICAqIEByZXR1cm4ge29iamVjdH0gbWFwIG9mIGV4dGVuc2lvbiBuYW1lcyB0byBleHRlbnNpb24gZGF0YVxuICAgKi9cbiAgYXN5bmMgbGlzdCAoe3Nob3dJbnN0YWxsZWQsIHNob3dVcGRhdGVzfSkge1xuICAgIGNvbnN0IGxzTXNnID0gYExpc3RpbmcgJHtzaG93SW5zdGFsbGVkID8gJ2luc3RhbGxlZCcgOiAnYXZhaWxhYmxlJ30gJHt0aGlzLnR5cGV9c2A7XG4gICAgY29uc3QgaW5zdGFsbGVkTmFtZXMgPSBPYmplY3Qua2V5cyh0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zKTtcbiAgICBjb25zdCBrbm93bk5hbWVzID0gT2JqZWN0LmtleXModGhpcy5rbm93bkV4dGVuc2lvbnMpO1xuICAgIGNvbnN0IGV4dHMgPSBbLi4uaW5zdGFsbGVkTmFtZXMsIC4uLmtub3duTmFtZXNdLnJlZHVjZSgoYWNjLCBuYW1lKSA9PiB7XG4gICAgICBpZiAoIWFjY1tuYW1lXSkge1xuICAgICAgICBpZiAoaW5zdGFsbGVkTmFtZXMuaW5jbHVkZXMobmFtZSkpIHtcbiAgICAgICAgICBhY2NbbmFtZV0gPSB7Li4udGhpcy5jb25maWcuaW5zdGFsbGVkRXh0ZW5zaW9uc1tuYW1lXSwgaW5zdGFsbGVkOiB0cnVlfTtcbiAgICAgICAgfSBlbHNlIGlmICghc2hvd0luc3RhbGxlZCkge1xuICAgICAgICAgIGFjY1tuYW1lXSA9IHtwa2dOYW1lOiB0aGlzLmtub3duRXh0ZW5zaW9uc1tuYW1lXSwgaW5zdGFsbGVkOiBmYWxzZX07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pO1xuXG4gICAgLy8gaWYgd2Ugd2FudCB0byBzaG93IHdoZXRoZXIgdXBkYXRlcyBhcmUgYXZhaWxhYmxlLCBwdXQgdGhhdCBiZWhpbmQgYSBzcGlubmVyXG4gICAgYXdhaXQgc3BpbldpdGgodGhpcy5pc0pzb25PdXRwdXQsIGxzTXNnLCBhc3luYyAoKSA9PiB7XG4gICAgICBpZiAoIXNob3dVcGRhdGVzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgW2V4dCwgZGF0YV0gb2YgXy50b1BhaXJzKGV4dHMpKSB7XG4gICAgICAgIGNvbnN0IHtpbnN0YWxsZWQsIGluc3RhbGxUeXBlfSA9IGRhdGE7XG4gICAgICAgIGlmICghaW5zdGFsbGVkIHx8IGluc3RhbGxUeXBlICE9PSBJTlNUQUxMX1RZUEVfTlBNKSB7XG4gICAgICAgICAgLy8gZG9uJ3QgbmVlZCB0byBjaGVjayBmb3IgdXBkYXRlcyBvbiBleHRzIHRoYXQgYXJlbid0IGluc3RhbGxlZFxuICAgICAgICAgIC8vIGFsc28gZG9uJ3QgbmVlZCB0byBjaGVjayBmb3IgdXBkYXRlcyBvbiBub24tbnBtIGV4dHNcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB1cGRhdGVzID0gYXdhaXQgdGhpcy5jaGVja0ZvckV4dGVuc2lvblVwZGF0ZShleHQpO1xuICAgICAgICBkYXRhLnVwZGF0ZVZlcnNpb24gPSB1cGRhdGVzLnNhZmVVcGRhdGU7XG4gICAgICAgIGRhdGEudW5zYWZlVXBkYXRlVmVyc2lvbiA9IHVwZGF0ZXMudW5zYWZlVXBkYXRlO1xuICAgICAgICBkYXRhLnVwVG9EYXRlID0gdXBkYXRlcy5zYWZlVXBkYXRlID09PSBudWxsICYmIHVwZGF0ZXMudW5zYWZlVXBkYXRlID09PSBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gaWYgd2UncmUganVzdCBnZXR0aW5nIHRoZSBkYXRhLCBzaG9ydCBjaXJjdWl0IHJldHVybiBoZXJlIHNpbmNlIHdlIGRvbid0IG5lZWQgdG8gZG8gYW55XG4gICAgLy8gZm9ybWF0dGluZyBsb2dpY1xuICAgIGlmICh0aGlzLmlzSnNvbk91dHB1dCkge1xuICAgICAgcmV0dXJuIGV4dHM7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbXG4gICAgICBuYW1lLFxuICAgICAge2luc3RhbGxUeXBlLCBpbnN0YWxsU3BlYywgaW5zdGFsbGVkLCB1cGRhdGVWZXJzaW9uLCB1bnNhZmVVcGRhdGVWZXJzaW9uLCB2ZXJzaW9uLCB1cFRvRGF0ZX1cbiAgICBdIG9mIF8udG9QYWlycyhleHRzKSkge1xuICAgICAgbGV0IHR5cGVUeHQ7XG4gICAgICBzd2l0Y2ggKGluc3RhbGxUeXBlKSB7XG4gICAgICAgIGNhc2UgSU5TVEFMTF9UWVBFX0dJVDpcbiAgICAgICAgY2FzZSBJTlNUQUxMX1RZUEVfR0lUSFVCOlxuICAgICAgICAgIHR5cGVUeHQgPSBgKGNsb25lZCBmcm9tICR7aW5zdGFsbFNwZWN9KWAueWVsbG93O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIElOU1RBTExfVFlQRV9MT0NBTDpcbiAgICAgICAgICB0eXBlVHh0ID0gYChsaW5rZWQgZnJvbSAke2luc3RhbGxTcGVjfSlgLm1hZ2VudGE7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdHlwZVR4dCA9ICcoTlBNKSc7XG4gICAgICB9XG4gICAgICBjb25zdCBpbnN0YWxsVHh0ID0gaW5zdGFsbGVkID9cbiAgICAgICAgYEAke3ZlcnNpb24ueWVsbG93fSAkeygnW2luc3RhbGxlZCAnICsgdHlwZVR4dCArICddJykuZ3JlZW59YCA6XG4gICAgICAgICcgW25vdCBpbnN0YWxsZWRdJy5ncmV5O1xuICAgICAgY29uc3QgdXBkYXRlVHh0ID0gc2hvd1VwZGF0ZXMgJiYgdXBkYXRlVmVyc2lvbiA/XG4gICAgICAgIGAgWyR7dXBkYXRlVmVyc2lvbn0gYXZhaWxhYmxlXWAubWFnZW50YSA6XG4gICAgICAgICcnO1xuICAgICAgY29uc3QgdXBUb0RhdGVUeHQgPSBzaG93VXBkYXRlcyAmJiB1cFRvRGF0ZSA/XG4gICAgICAgIGAgW1VwIHRvIGRhdGVdYC5ncmVlbiA6XG4gICAgICAgICcnO1xuICAgICAgY29uc3QgdW5zYWZlVXBkYXRlVHh0ID0gc2hvd1VwZGF0ZXMgJiYgdW5zYWZlVXBkYXRlVmVyc2lvbiA/XG4gICAgICAgIGAgWyR7dW5zYWZlVXBkYXRlVmVyc2lvbn0gYXZhaWxhYmxlIChwb3RlbnRpYWxseSB1bnNhZmUpXWAuY3lhbiA6XG4gICAgICAgICcnO1xuXG4gICAgICBjb25zb2xlLmxvZyhgLSAke25hbWUueWVsbG93fSR7aW5zdGFsbFR4dH0ke3VwZGF0ZVR4dH0ke3VwVG9EYXRlVHh0fSR7dW5zYWZlVXBkYXRlVHh0fWApO1xuICAgIH1cblxuICAgIHJldHVybiBleHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIHtPYmplY3R9IEluc3RhbGxBcmdzXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBleHQgLSB0aGUgbmFtZSBvciBzcGVjIG9mIGFuIGV4dGVuc2lvbiB0byBpbnN0YWxsXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpbnN0YWxsVHlwZSAtIGhvdyB0byBpbnN0YWxsIHRoaXMgZXh0ZW5zaW9uLiBPbmUgb2YgdGhlIElOU1RBTExfVFlQRVNcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IFtwYWNrYWdlTmFtZV0gLSBmb3IgZ2l0L2dpdGh1YiBpbnN0YWxscywgdGhlIGV4dGVuc2lvbiBub2RlIHBhY2thZ2UgbmFtZVxuICAgKi9cblxuICAvKipcbiAgICogSW5zdGFsbCBhbiBleHRlbnNpb25cbiAgICpcbiAgICogQHBhcmFtIHtJbnN0YWxsQXJnc30gYXJnc1xuICAgKiBAcmV0dXJuIHtvYmplY3R9IG1hcCBvZiBhbGwgaW5zdGFsbGVkIGV4dGVuc2lvbiBuYW1lcyB0byBleHRlbnNpb24gZGF0YVxuICAgKi9cbiAgYXN5bmMgaW5zdGFsbCAoe2V4dCwgaW5zdGFsbFR5cGUsIHBhY2thZ2VOYW1lfSkge1xuICAgIGxvZyh0aGlzLmlzSnNvbk91dHB1dCwgYEF0dGVtcHRpbmcgdG8gZmluZCBhbmQgaW5zdGFsbCAke3RoaXMudHlwZX0gJyR7ZXh0fSdgKTtcblxuICAgIGxldCBleHREYXRhO1xuICAgIGxldCBpbnN0YWxsU3BlYyA9IGV4dDtcblxuICAgIGlmIChwYWNrYWdlTmFtZSAmJiBbSU5TVEFMTF9UWVBFX0xPQ0FMLCBJTlNUQUxMX1RZUEVfTlBNXS5pbmNsdWRlcyhpbnN0YWxsVHlwZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgV2hlbiB1c2luZyAtLXNvdXJjZT0ke2luc3RhbGxUeXBlfSwgY2Fubm90IGFsc28gdXNlIC0tcGFja2FnZWApO1xuICAgIH1cblxuICAgIGlmICghcGFja2FnZU5hbWUgJiYgW0lOU1RBTExfVFlQRV9HSVQsIElOU1RBTExfVFlQRV9HSVRIVUJdLmluY2x1ZGVzKGluc3RhbGxUeXBlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBXaGVuIHVzaW5nIC0tc291cmNlPSR7aW5zdGFsbFR5cGV9LCBtdXN0IGFsc28gdXNlIC0tcGFja2FnZWApO1xuICAgIH1cblxuICAgIGlmIChpbnN0YWxsVHlwZSA9PT0gSU5TVEFMTF9UWVBFX0xPQ0FMKSB7XG4gICAgICBjb25zdCBtc2cgPSBgTGlua2luZyAke3RoaXMudHlwZX0gZnJvbSBsb2NhbCBwYXRoYDtcbiAgICAgIGNvbnN0IHBrZ0pzb25EYXRhID0gYXdhaXQgc3BpbldpdGgodGhpcy5pc0pzb25PdXRwdXQsIG1zZywgYXN5bmMgKCkgPT4gKFxuICAgICAgICBhd2FpdCB0aGlzLm5wbS5saW5rUGFja2FnZShpbnN0YWxsU3BlYykpXG4gICAgICApO1xuICAgICAgZXh0RGF0YSA9IHRoaXMuZ2V0RXh0ZW5zaW9uRmllbGRzKHBrZ0pzb25EYXRhKTtcbiAgICAgIGV4dERhdGEuaW5zdGFsbFBhdGggPSBleHREYXRhLnBrZ05hbWU7XG4gICAgfSBlbHNlIGlmIChpbnN0YWxsVHlwZSA9PT0gSU5TVEFMTF9UWVBFX0dJVEhVQikge1xuICAgICAgaWYgKGluc3RhbGxTcGVjLnNwbGl0KCcvJykubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgR2l0aHViICR7dGhpcy50eXBlfSBzcGVjICR7aW5zdGFsbFNwZWN9IGFwcGVhcmVkIHRvIGJlIGludmFsaWQ7IGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2l0IHNob3VsZCBiZSBvZiB0aGUgZm9ybSA8b3JnPi88cmVwbz4nKTtcbiAgICAgIH1cbiAgICAgIGV4dERhdGEgPSBhd2FpdCB0aGlzLmluc3RhbGxWaWFOcG0oe2V4dDogaW5zdGFsbFNwZWMsIHBrZ05hbWU6IHBhY2thZ2VOYW1lfSk7XG4gICAgfSBlbHNlIGlmIChpbnN0YWxsVHlwZSA9PT0gSU5TVEFMTF9UWVBFX0dJVCkge1xuICAgICAgLy8gZ2l0IHVybHMgY2FuIGhhdmUgJy5naXQnIGF0IHRoZSBlbmQsIGJ1dCB0aGlzIGlzIG5vdCBuZWNlc3NhcnkgYW5kIHdvdWxkIGNvbXBsaWNhdGUgdGhlXG4gICAgICAvLyB3YXkgd2UgZG93bmxvYWQgYW5kIG5hbWUgZGlyZWN0b3JpZXMsIHNvIHdlIGNhbiBqdXN0IHJlbW92ZSBpdFxuICAgICAgaW5zdGFsbFNwZWMgPSBpbnN0YWxsU3BlYy5yZXBsYWNlKC9cXC5naXQkLywgJycpO1xuICAgICAgZXh0RGF0YSA9IGF3YWl0IHRoaXMuaW5zdGFsbFZpYU5wbSh7ZXh0OiBpbnN0YWxsU3BlYywgcGtnTmFtZTogcGFja2FnZU5hbWV9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gYXQgdGhpcyBwb2ludCB3ZSBoYXZlIGVpdGhlciBhbiBucG0gcGFja2FnZSBvciBhbiBhcHBpdW0gdmVyaWZpZWQgZXh0ZW5zaW9uXG4gICAgICAvLyBuYW1lLiBib3RoIG9mIHdoaWNoIHdpbGwgYmUgaW5zdGFsbGVkIHZpYSBucG0uXG4gICAgICAvLyBleHRlbnNpb25zIGluc3RhbGxlZCB2aWEgbnBtIGNhbiBpbmNsdWRlIHZlcnNpb25zIG9yIHRhZ3MgYWZ0ZXIgdGhlICdAJ1xuICAgICAgLy8gc2lnbiwgc28gY2hlY2sgZm9yIHRoYXQuIFdlIGFsc28gbmVlZCB0byBiZSBjYXJlZnVsIHRoYXQgcGFja2FnZSBuYW1lcyB0aGVtc2VsdmVzIGNhblxuICAgICAgLy8gY29udGFpbiB0aGUgJ0AnIHN5bWJvbCwgYXMgaW4gYG5wbSBpbnN0YWxsIEBhcHBpdW0vZmFrZS1kcml2ZXJAMS4yLjBgXG4gICAgICBsZXQgbmFtZSwgcGtnVmVyO1xuICAgICAgY29uc3Qgc3BsaXRzID0gaW5zdGFsbFNwZWMuc3BsaXQoJ0AnKTtcbiAgICAgIGlmIChpbnN0YWxsU3BlY1swXSA9PT0gJ0AnKSB7XG4gICAgICAgIC8vIHRoaXMgaXMgdGhlIGNhc2Ugd2hlcmUgd2UgaGF2ZSBhbiBucG0gb3JnIGluY2x1ZGVkIGluIHRoZSBwYWNrYWdlIG5hbWVcbiAgICAgICAgW25hbWUsIHBrZ1Zlcl0gPSBbYEAke3NwbGl0c1sxXX1gLCBzcGxpdHNbMl1dO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhpcyBpcyB0aGUgY2FzZSB3aXRob3V0IGFuIG5wbSBvcmdcbiAgICAgICAgW25hbWUsIHBrZ1Zlcl0gPSBzcGxpdHM7XG4gICAgICB9XG4gICAgICBsZXQgcGtnTmFtZTtcblxuICAgICAgaWYgKGluc3RhbGxUeXBlID09PSBJTlNUQUxMX1RZUEVfTlBNKSB7XG4gICAgICAgIC8vIGlmIHdlJ3JlIGluc3RhbGxpbmcgYSBuYW1lZCBwYWNrYWdlIGZyb20gbnBtLCB3ZSBkb24ndCBuZWVkIHRvIGNoZWNrXG4gICAgICAgIC8vIGFnYWluc3QgdGhlIGFwcGl1bSBleHRlbnNpb24gbGlzdDsganVzdCB1c2UgdGhlIGluc3RhbGxTcGVjIGFzIGlzXG4gICAgICAgIHBrZ05hbWUgPSBuYW1lO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gaWYgd2UncmUgaW5zdGFsbGluZyBhIG5hbWVkIGFwcGl1bSBkcml2ZXIgKGxpa2UgJ3hjdWl0ZXN0Jykgd2UgbmVlZCB0b1xuICAgICAgICAvLyBkZXJlZmVyZW5jZSB0aGUgYWN0dWFsIG5wbSBwYWNrYWdlICgnYXBwaXVwbS14Y3VpdGVzdC1kcml2ZXInKSwgc29cbiAgICAgICAgLy8gY2hlY2sgaXQgZXhpc3RzIGFuZCBnZXQgdGhlIGNvcnJlY3QgcGFja2FnZVxuICAgICAgICBjb25zdCBrbm93bk5hbWVzID0gT2JqZWN0LmtleXModGhpcy5rbm93bkV4dGVuc2lvbnMpO1xuICAgICAgICBpZiAoIV8uaW5jbHVkZXMoa25vd25OYW1lcywgbmFtZSkpIHtcbiAgICAgICAgICBjb25zdCBtc2cgPSBgQ291bGQgbm90IHJlc29sdmUgJHt0aGlzLnR5cGV9OyBhcmUgeW91IHN1cmUgaXQncyBpbiB0aGUgbGlzdCBgICtcbiAgICAgICAgICAgICAgICAgICAgICBgb2Ygc3VwcG9ydGVkICR7dGhpcy50eXBlfXM/ICR7SlNPTi5zdHJpbmdpZnkoa25vd25OYW1lcyl9YDtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgICAgICAgfVxuICAgICAgICBwa2dOYW1lID0gdGhpcy5rbm93bkV4dGVuc2lvbnNbbmFtZV07XG4gICAgICAgIC8vIGdpdmVuIHRoYXQgd2UnbGwgdXNlIHRoZSBpbnN0YWxsIHR5cGUgaW4gdGhlIGRyaXZlciBqc29uLCBzdG9yZSBpdCBhc1xuICAgICAgICAvLyAnbnBtJyBub3dcbiAgICAgICAgaW5zdGFsbFR5cGUgPSBJTlNUQUxMX1RZUEVfTlBNO1xuICAgICAgfVxuXG4gICAgICBleHREYXRhID0gYXdhaXQgdGhpcy5pbnN0YWxsVmlhTnBtKHtleHQsIHBrZ05hbWUsIHBrZ1Zlcn0pO1xuICAgIH1cblxuICAgIGNvbnN0IGV4dE5hbWUgPSBleHREYXRhW2Ake3RoaXMudHlwZX1OYW1lYF07XG4gICAgZGVsZXRlIGV4dERhdGFbYCR7dGhpcy50eXBlfU5hbWVgXTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5pc0luc3RhbGxlZChleHROYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBBICR7dGhpcy50eXBlfSBuYW1lZCAnJHtleHROYW1lfScgaXMgYWxyZWFkeSBpbnN0YWxsZWQuIGAgK1xuICAgICAgICAgICAgICAgICAgICAgIGBEaWQgeW91IG1lYW4gdG8gdXBkYXRlPyAnYXBwaXVtICR7dGhpcy50eXBlfSB1cGRhdGUnLiBTZWUgYCArXG4gICAgICAgICAgICAgICAgICAgICAgYGluc3RhbGxlZCAke3RoaXMudHlwZX1zIHdpdGggJ2FwcGl1bSAke3RoaXMudHlwZX0gbGlzdCAtLWluc3RhbGxlZCcuYCk7XG4gICAgfVxuXG4gICAgZXh0RGF0YS5pbnN0YWxsVHlwZSA9IGluc3RhbGxUeXBlO1xuICAgIGV4dERhdGEuaW5zdGFsbFNwZWMgPSBpbnN0YWxsU3BlYztcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5hZGRFeHRlbnNpb24oZXh0TmFtZSwgZXh0RGF0YSk7XG5cbiAgICAvLyBsb2cgaW5mbyBmb3IgdGhlIHVzZXJcbiAgICBsb2codGhpcy5pc0pzb25PdXRwdXQsIHRoaXMuZ2V0UG9zdEluc3RhbGxUZXh0KHtleHROYW1lLCBleHREYXRhfSkpO1xuXG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnM7XG4gIH1cblxuICAvKipcbiAgICogQHR5cGVkZWYge09iamVjdH0gSW5zdGFsbFZpYU5wbUFyZ3NcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IGV4dCAtIHRoZSBuYW1lIG9yIHNwZWMgb2YgYW4gZXh0ZW5zaW9uIHRvIGluc3RhbGxcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IHBrZ05hbWUgLSB0aGUgTlBNIHBhY2thZ2UgbmFtZSBvZiB0aGUgZXh0ZW5zaW9uXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBbcGtnVmVyXSAtIHRoZSBzcGVjaWZpYyB2ZXJzaW9uIG9mIHRoZSBOUE0gcGFja2FnZVxuICAgKi9cblxuICAvKipcbiAgICogSW5zdGFsbCBhbiBleHRlbnNpb24gdmlhIE5QTVxuICAgKlxuICAgKiBAcGFyYW0ge0luc3RhbGxWaWFOcG1BcmdzfSBhcmdzXG4gICAqL1xuICBhc3luYyBpbnN0YWxsVmlhTnBtICh7ZXh0LCBwa2dOYW1lLCBwa2dWZXJ9KSB7XG4gICAgY29uc3QgbnBtU3BlYyA9IGAke3BrZ05hbWV9JHtwa2dWZXIgPyAnQCcgKyBwa2dWZXIgOiAnJ31gO1xuICAgIGNvbnN0IHNwZWNNc2cgPSBucG1TcGVjID09PSBleHQgPyAnJyA6IGAgdXNpbmcgTlBNIGluc3RhbGwgc3BlYyAnJHtucG1TcGVjfSdgO1xuICAgIGNvbnN0IG1zZyA9IGBJbnN0YWxsaW5nICcke2V4dH0nJHtzcGVjTXNnfWA7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBrZ0pzb25EYXRhID0gYXdhaXQgc3BpbldpdGgodGhpcy5pc0pzb25PdXRwdXQsIG1zZywgYXN5bmMgKCkgPT4gKFxuICAgICAgICBhd2FpdCB0aGlzLm5wbS5pbnN0YWxsUGFja2FnZSh7XG4gICAgICAgICAgcGtnRGlyOiBwYXRoLnJlc29sdmUodGhpcy5jb25maWcuYXBwaXVtSG9tZSwgcGtnTmFtZSksXG4gICAgICAgICAgcGtnTmFtZSxcbiAgICAgICAgICBwa2dWZXJcbiAgICAgICAgfSlcbiAgICAgICkpO1xuICAgICAgY29uc3QgZXh0RGF0YSA9IHRoaXMuZ2V0RXh0ZW5zaW9uRmllbGRzKHBrZ0pzb25EYXRhKTtcbiAgICAgIGV4dERhdGEuaW5zdGFsbFBhdGggPSBwa2dOYW1lO1xuICAgICAgcmV0dXJuIGV4dERhdGE7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEVuY291bnRlcmVkIGFuIGVycm9yIHdoZW4gaW5zdGFsbGluZyBwYWNrYWdlOiAke2Vyci5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBFeHRlbnNpb25BcmdzXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBleHROYW1lIC0gdGhlIG5hbWUgb2YgYW4gZXh0ZW5zaW9uXG4gICAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBleHREYXRhIC0gdGhlIGRhdGEgZm9yIGFuIGluc3RhbGxlZCBleHRlbnNpb25cbiAgICovXG5cbiAgLyoqXG4gICAqIEdldCB0aGUgdGV4dCB3aGljaCBzaG91bGQgYmUgZGlzcGxheWVkIHRvIHRoZSB1c2VyIGFmdGVyIGFuIGV4dGVuc2lvbiBoYXMgYmVlbiBpbnN0YWxsZWQuIFRoaXNcbiAgICogaXMgZGVzaWduZWQgdG8gYmUgb3ZlcnJpZGRlbiBieSBkcml2ZXJzL3BsdWdpbnMgd2l0aCB0aGVpciBvd24gcGFydGljdWxhciB0ZXh0LlxuICAgKlxuICAgKiBAcGFyYW0ge0V4dGVuc2lvbkFyZ3N9IGFyZ3NcbiAgICovXG4gIGdldFBvc3RJbnN0YWxsVGV4dCAoLyp7ZXh0TmFtZSwgZXh0RGF0YX0qLykge1xuICAgIHRocm93IG5ldyBFcnJvcignTXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBmaW5hbCBjbGFzcycpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRha2UgYW4gTlBNIG1vZHVsZSdzIHBhY2thZ2UuanNvbiBhbmQgZXh0cmFjdCBBcHBpdW0gZHJpdmVyIGluZm9ybWF0aW9uIGZyb20gYSBzcGVjaWFsXG4gICAqICdhcHBpdW0nIGZpZWxkIGluIHRoZSBKU09OIGRhdGEuIFdlIG5lZWQgdGhpcyBpbmZvcm1hdGlvbiB0byBlLmcuIGRldGVybWluZSB3aGljaCBjbGFzcyB0b1xuICAgKiBsb2FkIGFzIHRoZSBtYWluIGRyaXZlciBjbGFzcywgb3IgdG8gYmUgYWJsZSB0byBkZXRlY3QgaW5jb21wYXRpYmlsaXRpZXMgYmV0d2VlbiBkcml2ZXIgYW5kXG4gICAqIGFwcGl1bSB2ZXJzaW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHBrZ0pzb25EYXRhIC0gdGhlIHBhY2thZ2UuanNvbiBkYXRhIGZvciBhIGRyaXZlciBtb2R1bGUsIGFzIGlmIGl0IGhhZCBiZWVuXG4gICAqIHN0cmFpZ2h0Zm9yd2FyZGx5ICdyZXF1aXJlJ2RcbiAgICovXG4gIGdldEV4dGVuc2lvbkZpZWxkcyAocGtnSnNvbkRhdGEpIHtcbiAgICBpZiAoIXBrZ0pzb25EYXRhLmFwcGl1bSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnN0YWxsZWQgZHJpdmVyIGRpZCBub3QgaGF2ZSBhbiAnYXBwaXVtJyBzZWN0aW9uIGluIGl0cyBgICtcbiAgICAgICAgICAgICAgICAgICAgICBgcGFja2FnZS5qc29uIGZpbGUgYXMgZXhwZWN0ZWRgKTtcbiAgICB9XG4gICAgY29uc3Qge2FwcGl1bSwgbmFtZSwgdmVyc2lvbn0gPSBwa2dKc29uRGF0YTtcbiAgICB0aGlzLnZhbGlkYXRlRXh0ZW5zaW9uRmllbGRzKGFwcGl1bSk7XG5cbiAgICByZXR1cm4gey4uLmFwcGl1bSwgcGtnTmFtZTogbmFtZSwgdmVyc2lvbn07XG4gIH1cblxuICAvKipcbiAgICogRm9yIGFueSBwYWNrYWdlLmpzb24gZmllbGRzIHdoaWNoIGEgcGFydGljdWxhciB0eXBlIG9mIGV4dGVuc2lvbiByZXF1aXJlcywgdmFsaWRhdGUgdGhlXG4gICAqIHByZXNlbmNlIGFuZCBmb3JtIG9mIHRob3NlIGZpZWxkcyBvbiB0aGUgcGFja2FnZS5qc29uIGRhdGEsIHRocm93aW5nIGFuIGVycm9yIGlmIGFueXRoaW5nIGlzXG4gICAqIGFtaXNzLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXBwaXVtUGtnRGF0YSAtIHRoZSBkYXRhIGluIHRoZSBcImFwcGl1bVwiIGZpZWxkIG9mIHBhY2thZ2UuanNvbiBmb3IgYW5cbiAgICogZXh0ZW5zaW9uXG4gICAqL1xuICB2YWxpZGF0ZUV4dGVuc2lvbkZpZWxkcyAoLyphcHBpdW1Qa2dEYXRhKi8pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ011c3QgYmUgaW1wbGVtZW50ZWQgaW4gZmluYWwgY2xhc3MnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBVbmluc3RhbGxBcmdzXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBleHQgLSB0aGUgbmFtZSBvciBzcGVjIG9mIGFuIGV4dGVuc2lvbiB0byB1bmluc3RhbGxcbiAgICovXG5cbiAgLyoqXG4gICAqIFVuaW5zdGFsbCBhbiBleHRlbnNpb25cbiAgICpcbiAgICogQHBhcmFtIHtVbmluc3RhbGxBcmdzfSBhcmdzXG4gICAqIEByZXR1cm4ge29iamVjdH0gbWFwIG9mIGFsbCBpbnN0YWxsZWQgZXh0ZW5zaW9uIG5hbWVzIHRvIGV4dGVuc2lvbiBkYXRhXG4gICAqL1xuICBhc3luYyB1bmluc3RhbGwgKHtleHR9KSB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy5pc0luc3RhbGxlZChleHQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbid0IHVuaW5zdGFsbCAke3RoaXMudHlwZX0gJyR7ZXh0fSc7IGl0IGlzIG5vdCBpbnN0YWxsZWRgKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLnJpbXJhZih0aGlzLmNvbmZpZy5nZXRJbnN0YWxsUGF0aChleHQpKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgYXdhaXQgdGhpcy5jb25maWcucmVtb3ZlRXh0ZW5zaW9uKGV4dCk7XG4gICAgfVxuICAgIGxvZyh0aGlzLmlzSnNvbk91dHB1dCwgYFN1Y2Nlc3NmdWxseSB1bmluc3RhbGxlZCAke3RoaXMudHlwZX0gJyR7ZXh0fSdgLmdyZWVuKTtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuaW5zdGFsbGVkRXh0ZW5zaW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBFeHRlbnNpb25VcGRhdGVPcHRzXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBleHQgLSB0aGUgbmFtZSBvZiB0aGUgZXh0ZW5zaW9uIHRvIHVwZGF0ZVxuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IHVuc2FmZSAtIGlmIHRydWUsIHdpbGwgcGVyZm9ybSB1bnNhZmUgdXBkYXRlcyBwYXN0IG1ham9yIHJldmlzaW9uXG4gICAqIGJvdW5kYXJpZXNcbiAgICovXG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIHtPYmplY3R9IFVwZGF0ZVJlcG9ydFxuICAgKiBAcHJvcGVydHkge3N0cmluZ30gZnJvbSAtIHZlcnNpb24gdXBkYXRlZCBmcm9tXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0byAtIHZlcnNpb24gdXBkYXRlZCB0b1xuICAgKi9cblxuICAvKipcbiAgICogQHR5cGVkZWYge09iamVjdH0gRXh0ZW5zaW9uVXBkYXRlUmVzdWx0XG4gICAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBlcnJvcnMgLSBtYXAgb2YgZXh0IG5hbWVzIHRvIGVycm9yIG9iamVjdHNcbiAgICogQHByb3BlcnR5IHtPYmplY3R9IHVwZGF0ZXMgLSBtYXAgb2YgZXh0IG5hbWVzIHRvIHtAbGluayBVcGRhdGVSZXBvcnR9c1xuICAgKi9cblxuICAvKipcbiAgICogQXR0ZW1wdCB0byB1cGRhdGUgb25lIG9yIG1vcmUgZHJpdmVycyB1c2luZyBOUE1cbiAgICpcbiAgICogQHBhcmFtIHtFeHRlbnNpb25VcGRhdGVPcHRzfSB1cGRhdGVTcGVjXG4gICAqIEByZXR1cm4ge0V4dGVuc2lvblVwZGF0ZVJlc3VsdH1cbiAgICovXG4gIGFzeW5jIHVwZGF0ZSAoe2V4dCwgdW5zYWZlfSkge1xuICAgIGNvbnN0IHNob3VsZFVwZGF0ZUFsbCA9IGV4dCA9PT0gVVBEQVRFX0FMTDtcbiAgICAvLyBpZiB3ZSdyZSBzcGVjaWZpY2FsbHkgcmVxdWVzdGluZyBhbiB1cGRhdGUgZm9yIGFuIGV4dGVuc2lvbiwgbWFrZSBzdXJlIGl0J3MgaW5zdGFsbGVkXG4gICAgaWYgKCFzaG91bGRVcGRhdGVBbGwgJiYgIXRoaXMuY29uZmlnLmlzSW5zdGFsbGVkKGV4dCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlICR7dGhpcy50eXBlfSAnJHtleHR9JyB3YXMgbm90IGluc3RhbGxlZCwgc28gY2FuJ3QgYmUgdXBkYXRlZGApO1xuICAgIH1cbiAgICBjb25zdCBleHRzVG9VcGRhdGUgPSBzaG91bGRVcGRhdGVBbGwgPyBPYmplY3Qua2V5cyh0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zKSA6IFtleHRdO1xuXG4gICAgLy8gJ2Vycm9ycycgd2lsbCBoYXZlIGV4dCBuYW1lcyBhcyBrZXlzIGFuZCBlcnJvciBvYmplY3RzIGFzIHZhbHVlc1xuICAgIGNvbnN0IGVycm9ycyA9IHt9O1xuXG4gICAgLy8gJ3VwZGF0ZXMnIHdpbGwgaGF2ZSBleHQgbmFtZXMgYXMga2V5cyBhbmQgdXBkYXRlIG9iamVjdHMgYXMgdmFsdWVzLCB3aGVyZSBhbiB1cGRhdGVcbiAgICAvLyBvYmplY3QgaXMgb2YgdGhlIGZvcm0ge2Zyb206IHZlcnNpb25TdHJpbmcsIHRvOiB2ZXJzaW9uU3RyaW5nfVxuICAgIGNvbnN0IHVwZGF0ZXMgPSB7fTtcblxuICAgIGZvciAoY29uc3QgZSBvZiBleHRzVG9VcGRhdGUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHNwaW5XaXRoKHRoaXMuaXNKc29uT3V0cHV0LCBgQ2hlY2tpbmcgaWYgJHt0aGlzLnR5cGV9ICcke2V9JyBpcyB1cGRhdGFibGVgLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnNbZV0uaW5zdGFsbFR5cGUgIT09IElOU1RBTExfVFlQRV9OUE0pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBOb3RVcGRhdGFibGVFcnJvcigpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHVwZGF0ZSA9IGF3YWl0IHNwaW5XaXRoKHRoaXMuaXNKc29uT3V0cHV0LCBgQ2hlY2tpbmcgaWYgJHt0aGlzLnR5cGV9ICcke2V9JyBuZWVkcyBhbiB1cGRhdGVgLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgdXBkYXRlID0gYXdhaXQgdGhpcy5jaGVja0ZvckV4dGVuc2lvblVwZGF0ZShlKTtcbiAgICAgICAgICBpZiAoISh1cGRhdGUuc2FmZVVwZGF0ZSB8fCB1cGRhdGUudW5zYWZlVXBkYXRlKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IE5vVXBkYXRlc0F2YWlsYWJsZUVycm9yKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB1cGRhdGU7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoIXVuc2FmZSAmJiAhdXBkYXRlLnNhZmVVcGRhdGUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSAke3RoaXMudHlwZX0gJyR7ZX0nIGhhcyBhIG1ham9yIHJldmlzaW9uIHVwZGF0ZSBgICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYCgke3VwZGF0ZS5jdXJyZW50fSA9PiAke3VwZGF0ZS51bnNhZmVVcGRhdGV9KSwgd2hpY2ggY291bGQgaW5jbHVkZSBgICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYGJyZWFraW5nIGNoYW5nZXMuIElmIHlvdSB3YW50IHRvIGFwcGx5IHRoaXMgdXBkYXRlLCByZS1ydW4gd2l0aCAtLXVuc2FmZWApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHVwZGF0ZVZlciA9IHVuc2FmZSAmJiB1cGRhdGUudW5zYWZlVXBkYXRlID8gdXBkYXRlLnVuc2FmZVVwZGF0ZSA6IHVwZGF0ZS5zYWZlVXBkYXRlO1xuICAgICAgICBhd2FpdCBzcGluV2l0aChcbiAgICAgICAgICB0aGlzLmlzSnNvbk91dHB1dCxcbiAgICAgICAgICBgVXBkYXRpbmcgZHJpdmVyICcke2V9JyBmcm9tICR7dXBkYXRlLmN1cnJlbnR9IHRvICR7dXBkYXRlVmVyfWAsXG4gICAgICAgICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy51cGRhdGVFeHRlbnNpb24oZSwgdXBkYXRlVmVyKVxuICAgICAgICApO1xuICAgICAgICB1cGRhdGVzW2VdID0ge2Zyb206IHVwZGF0ZS5jdXJyZW50LCB0bzogdXBkYXRlVmVyfTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBlcnJvcnNbZV0gPSBlcnI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgbG9nKHRoaXMuaXNKc29uT3V0cHV0LCAnVXBkYXRlIHJlcG9ydDonKTtcbiAgICBmb3IgKGNvbnN0IFtlLCB1cGRhdGVdIG9mIF8udG9QYWlycyh1cGRhdGVzKSkge1xuICAgICAgbG9nKHRoaXMuaXNKc29uT3V0cHV0LCBgLSAke3RoaXMudHlwZX0gJHtlfSB1cGRhdGVkOiAke3VwZGF0ZS5mcm9tfSA9PiAke3VwZGF0ZS50b31gLmdyZWVuKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBbZSwgZXJyXSBvZiBfLnRvUGFpcnMoZXJyb3JzKSkge1xuICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIE5vdFVwZGF0YWJsZUVycm9yKSB7XG4gICAgICAgIGxvZyh0aGlzLmlzSnNvbk91dHB1dCwgYC0gJyR7ZX0nIHdhcyBub3QgaW5zdGFsbGVkIHZpYSBucG0sIHNvIHdlIGNvdWxkIG5vdCBjaGVjayBgICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgZm9yIHVwZGF0ZXNgLnllbGxvdyk7XG4gICAgICB9IGVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIE5vVXBkYXRlc0F2YWlsYWJsZUVycm9yKSB7XG4gICAgICAgIGxvZyh0aGlzLmlzSnNvbk91dHB1dCwgYC0gJyR7ZX0nIGhhZCBubyB1cGRhdGVzIGF2YWlsYWJsZWAueWVsbG93KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG90aGVyd2lzZSwgbWFrZSBpdCBwb3Agd2l0aCByZWQhXG4gICAgICAgIGxvZyh0aGlzLmlzSnNvbk91dHB1dCwgYC0gJyR7ZX0nIGZhaWxlZCB0byB1cGRhdGU6ICR7ZXJyfWAucmVkKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4ge3VwZGF0ZXMsIGVycm9yc307XG4gIH1cblxuICAvKipcbiAgICogQHR5cGVkZWYgUG9zc2libGVVcGRhdGVzXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBjdXJyZW50IC0gY3VycmVudCB2ZXJzaW9uXG4gICAqIEBwcm9wZXJ0eSB7c3RyaW5nfG51bGx9IHNhZmVVcGRhdGUgLSB2ZXJzaW9uIHdlIGNhbiBzYWZlbHkgdXBkYXRlIHRvIGlmIGl0IGV4aXN0cywgb3IgbnVsbFxuICAgKiBAcHJvcGVydHkge3N0cmluZ3xudWxsfSB1bnNhZmVVcGRhdGUgLSB2ZXJzaW9uIHdlIGNhbiB1bnNhZmVseSB1cGRhdGUgdG8gaWYgaXQgZXhpc3RzLCBvciBudWxsXG4gICAqL1xuXG4gIC8qKlxuICAgKiBHaXZlbiBhbiBleHRlbnNpb24gbmFtZSwgZmlndXJlIG91dCB3aGF0IGl0cyBoaWdoZXN0IHBvc3NpYmxlIHZlcnNpb24gdXBncmFkZSBpcywgYW5kIGFsc28gdGhlXG4gICAqIGhpZ2hlc3QgcG9zc2libGUgc2FmZSB1cGdyYWRlLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXh0IC0gbmFtZSBvZiBleHRlbnNpb25cbiAgICogQHJldHVybiB7UG9zc2libGVVcGRhdGVzfVxuICAgKi9cbiAgYXN5bmMgY2hlY2tGb3JFeHRlbnNpb25VcGRhdGUgKGV4dCkge1xuICAgIC8vIFRPRE8gZGVjaWRlIGhvdyB3ZSB3YW50IHRvIGhhbmRsZSBiZXRhIHZlcnNpb25zP1xuICAgIC8vIHRoaXMgaXMgYSBoZWxwZXIgbWV0aG9kLCAnZXh0JyBpcyBhc3N1bWVkIHRvIGFscmVhZHkgYmUgaW5zdGFsbGVkIGhlcmUsIGFuZCBvZiB0aGUgbnBtXG4gICAgLy8gaW5zdGFsbCB0eXBlXG4gICAgY29uc3Qge3ZlcnNpb24sIHBrZ05hbWV9ID0gdGhpcy5jb25maWcuaW5zdGFsbGVkRXh0ZW5zaW9uc1tleHRdO1xuICAgIGxldCB1bnNhZmVVcGRhdGUgPSBhd2FpdCB0aGlzLm5wbS5nZXRMYXRlc3RWZXJzaW9uKHBrZ05hbWUpO1xuICAgIGxldCBzYWZlVXBkYXRlID0gYXdhaXQgdGhpcy5ucG0uZ2V0TGF0ZXN0U2FmZVVwZ3JhZGVWZXJzaW9uKHBrZ05hbWUsIHZlcnNpb24pO1xuICAgIGlmICghdXRpbC5jb21wYXJlVmVyc2lvbnModW5zYWZlVXBkYXRlLCAnPicsIHZlcnNpb24pKSB7XG4gICAgICAvLyB0aGUgbGF0ZXN0IHZlcnNpb24gaXMgbm90IGdyZWF0ZXIgdGhhbiB0aGUgY3VycmVudCB2ZXJzaW9uLCBzbyB0aGVyZSdzIG5vIHBvc3NpYmxlIHVwZGF0ZVxuICAgICAgdW5zYWZlVXBkYXRlID0gbnVsbDtcbiAgICAgIHNhZmVVcGRhdGUgPSBudWxsO1xuICAgIH1cbiAgICBpZiAodW5zYWZlVXBkYXRlICYmIHVuc2FmZVVwZGF0ZSA9PT0gc2FmZVVwZGF0ZSkge1xuICAgICAgLy8gdGhlIGxhdGVzdCB1cGRhdGUgaXMgdGhlIHNhbWUgYXMgdGhlIHNhZmUgdXBkYXRlLCB3aGljaCBtZWFucyBpdCdzIG5vdCBhY3R1YWxseSB1bnNhZmVcbiAgICAgIHVuc2FmZVVwZGF0ZSA9IG51bGw7XG4gICAgfVxuICAgIGlmIChzYWZlVXBkYXRlICYmICF1dGlsLmNvbXBhcmVWZXJzaW9ucyhzYWZlVXBkYXRlLCAnPicsIHZlcnNpb24pKSB7XG4gICAgICAvLyBldmVuIHRoZSBzYWZlIHVwZGF0ZSBpcyBub3QgbGF0ZXIgdGhhbiB0aGUgY3VycmVudCwgc28gaXQgaXMgbm90IGFjdHVhbGx5IGFuIHVwZGF0ZVxuICAgICAgc2FmZVVwZGF0ZSA9IG51bGw7XG4gICAgfVxuICAgIHJldHVybiB7Y3VycmVudDogdmVyc2lvbiwgc2FmZVVwZGF0ZSwgdW5zYWZlVXBkYXRlfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3R1YWxseSB1cGRhdGUgYW4gZXh0ZW5zaW9uIGluc3RhbGxlZCBieSBOUE0sIHVzaW5nIHRoZSBOUE0gY2xpLiBBbmQgdXBkYXRlIHRoZSBpbnN0YWxsYXRpb25cbiAgICogbWFuaWZlc3QuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBleHQgLSBuYW1lIG9mIGV4dGVuc2lvbiB0byB1cGRhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHZlcnNpb24gLSB2ZXJzaW9uIHN0cmluZyBpZGVudGlmaWVyIHRvIHVwZGF0ZSBleHRlbnNpb24gdG9cbiAgICovXG4gIGFzeW5jIHVwZGF0ZUV4dGVuc2lvbiAoZXh0LCB2ZXJzaW9uKSB7XG4gICAgY29uc3Qge3BrZ05hbWV9ID0gdGhpcy5jb25maWcuaW5zdGFsbGVkRXh0ZW5zaW9uc1tleHRdO1xuICAgIGF3YWl0IHRoaXMuaW5zdGFsbFZpYU5wbSh7ZXh0LCBwa2dOYW1lLCBwa2dWZXI6IHZlcnNpb259KTtcbiAgICB0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zW2V4dF0udmVyc2lvbiA9IHZlcnNpb247XG4gICAgYXdhaXQgdGhpcy5jb25maWcud3JpdGUoKTtcbiAgfVxufVxuIl0sImZpbGUiOiJsaWIvY2xpL2V4dGVuc2lvbi1jb21tYW5kLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uLy4uIn0=
606
+ exports.ExtensionCommand = ExtensionCommand;
607
+ exports.default = ExtensionCommand;
608
+ /**
609
+ * Options for the {@linkcode ExtensionCommand} constructor
610
+ * @template {ExtensionType} ExtType
611
+ * @typedef ExtensionCommandOptions
612
+ * @property {ExtensionConfig<ExtType>} config - the `DriverConfig` or `PluginConfig` instance used for this command
613
+ * @property {boolean} json - whether the output of this command should be JSON or text
614
+ */
615
+ /**
616
+ * Extra stuff about extensions; used indirectly by {@linkcode ExtensionCommand.list}.
617
+ *
618
+ * @typedef ExtensionMetadata
619
+ * @property {boolean} installed - If `true`, the extension is installed
620
+ * @property {string?} updateVersion - If the extension is installed, the version it can be updated to
621
+ * @property {string?} unsafeUpdateVersion - Same as above, but a major version bump
622
+ * @property {boolean} upToDate - If the extension is installed and the latest
623
+ * @property {string?} updateError - Update check error message (if present)
624
+ */
625
+ /**
626
+ * @typedef {import('@appium/types').ExtensionType} ExtensionType
627
+ * @typedef {import('@appium/types').DriverType} DriverType
628
+ * @typedef {import('@appium/types').PluginType} PluginType
629
+ */
630
+ /**
631
+ * @template {ExtensionType} ExtType
632
+ * @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
633
+ */
634
+ /**
635
+ * @template {ExtensionType} ExtType
636
+ * @typedef {import('../extension/extension-config').ExtensionConfig<ExtType>} ExtensionConfig
637
+ */
638
+ /**
639
+ * @template {ExtensionType} ExtType
640
+ * @typedef {import('appium/types').ExtMetadata<ExtType>} ExtMetadata
641
+ */
642
+ /**
643
+ * @template {ExtensionType} ExtType
644
+ * @typedef {import('appium/types').ExtManifest<ExtType>} ExtManifest
645
+ */
646
+ /**
647
+ * @template {ExtensionType} ExtType
648
+ * @typedef {import('appium/types').ExtPackageJson<ExtType>} ExtPackageJson
649
+ */
650
+ /**
651
+ * @template {ExtensionType} ExtType
652
+ * @typedef {import('appium/types').ExtInstallReceipt<ExtType>} ExtInstallReceipt
653
+ */
654
+ /**
655
+ * Possible return value for {@linkcode ExtensionCommand.list}
656
+ * @typedef {Partial<InstalledExtensionListData> & {pkgName: string, installed: false}} UninstalledExtensionListData
657
+ */
658
+ /**
659
+ * Possible return value for {@linkcode ExtensionCommand.list}
660
+ * @typedef {import('appium/types').InternalMetadata & ExtensionMetadata} InstalledExtensionListData
661
+ */
662
+ /**
663
+ * Return value of {@linkcode ExtensionCommand.list}.
664
+ * @typedef {Record<string,InstalledExtensionListData|UninstalledExtensionListData>} ExtensionListData
665
+ */
666
+ /**
667
+ * Options for {@linkcode ExtensionCommand._run}.
668
+ * @typedef RunOptions
669
+ * @property {string} installSpec - name of the extension to run a script from
670
+ * @property {string} scriptName - name of the script to run
671
+ * @property {string[]} [extraArgs] - arguments to pass to the script
672
+ */
673
+ /**
674
+ * Return value of {@linkcode ExtensionCommand._run}
675
+ *
676
+ * @typedef RunOutput
677
+ * @property {string} [error] - error message if script ran unsuccessfully, otherwise undefined
678
+ * @property {string[]} output - script output
679
+ */
680
+ /**
681
+ * Options for {@linkcode ExtensionCommand._update}.
682
+ * @typedef ExtensionUpdateOpts
683
+ * @property {string} installSpec - the name of the extension to update
684
+ * @property {boolean} unsafe - if true, will perform unsafe updates past major revision boundaries
685
+ */
686
+ /**
687
+ * Return value of {@linkcode ExtensionCommand._update}.
688
+ * @typedef ExtensionUpdateResult
689
+ * @property {Record<string,Error>} errors - map of ext names to error objects
690
+ * @property {Record<string,UpdateReport>} updates - map of ext names to {@linkcode UpdateReport}s
691
+ */
692
+ /**
693
+ * Part of result of {@linkcode ExtensionCommand._update}.
694
+ * @typedef UpdateReport
695
+ * @property {string} from - version the extension was updated from
696
+ * @property {string} to - version the extension was updated to
697
+ */
698
+ /**
699
+ * Options for {@linkcode ExtensionCommand._uninstall}.
700
+ * @typedef UninstallOpts
701
+ * @property {string} installSpec - the name or spec of an extension to uninstall
702
+ */
703
+ /**
704
+ * Used by {@linkcode ExtensionCommand.getPostInstallText}
705
+ * @typedef ExtensionArgs
706
+ * @property {string} extName - the name of an extension
707
+ * @property {object} extData - the data for an installed extension
708
+ */
709
+ /**
710
+ * Options for {@linkcode ExtensionCommand.installViaNpm}
711
+ * @typedef InstallViaNpmArgs
712
+ * @property {string} installSpec - the name or spec of an extension to install
713
+ * @property {string} pkgName - the NPM package name of the extension
714
+ * @property {import('appium/types').InstallType} installType - type of install
715
+ * @property {string} [pkgVer] - the specific version of the NPM package
716
+ */
717
+ /**
718
+ * Object returned by {@linkcode ExtensionCommand.checkForExtensionUpdate}
719
+ * @typedef PossibleUpdates
720
+ * @property {string} current - current version
721
+ * @property {string?} safeUpdate - version we can safely update to if it exists, or null
722
+ * @property {string?} unsafeUpdate - version we can unsafely update to if it exists, or null
723
+ */
724
+ /**
725
+ * Options for {@linkcode ExtensionCommand._install}
726
+ * @typedef InstallOpts
727
+ * @property {string} installSpec - the name or spec of an extension to install
728
+ * @property {InstallType} installType - how to install this extension. One of the INSTALL_TYPES
729
+ * @property {string} [packageName] - for git/github installs, the extension node package name
730
+ */
731
+ /**
732
+ * @template {ExtensionType} ExtType
733
+ * @typedef {ExtType extends DriverType ? typeof import('../constants').KNOWN_DRIVERS : ExtType extends PluginType ? typeof import('../constants').KNOWN_PLUGINS : never} KnownExtensions
734
+ */
735
+ /**
736
+ * @typedef ListOptions
737
+ * @property {boolean} showInstalled - whether should show only installed extensions
738
+ * @property {boolean} showUpdates - whether should show available updates
739
+ */
740
+ /**
741
+ * Opts for {@linkcode ExtensionCommand.getInstallationReceipt}
742
+ * @template {ExtensionType} ExtType
743
+ * @typedef GetInstallationReceiptOpts
744
+ * @property {string} installPath
745
+ * @property {string} installSpec
746
+ * @property {ExtPackageJson<ExtType>} pkg
747
+ * @property {InstallType} installType
748
+ */
749
+ /**
750
+ * @typedef {import('appium/types').InstallType} InstallType
751
+ */
752
+ //# sourceMappingURL=extension-command.js.map