appium 2.0.0-beta.26 → 2.0.0-beta.29

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 (118) hide show
  1. package/build/lib/appium.d.ts +215 -0
  2. package/build/lib/appium.d.ts.map +1 -0
  3. package/build/lib/appium.js +62 -54
  4. package/build/lib/cli/args.d.ts +20 -0
  5. package/build/lib/cli/args.d.ts.map +1 -0
  6. package/build/lib/cli/args.js +1 -1
  7. package/build/lib/cli/driver-command.d.ts +36 -0
  8. package/build/lib/cli/driver-command.d.ts.map +1 -0
  9. package/build/lib/cli/driver-command.js +8 -7
  10. package/build/lib/cli/extension-command.d.ts +345 -0
  11. package/build/lib/cli/extension-command.d.ts.map +1 -0
  12. package/build/lib/cli/extension-command.js +52 -38
  13. package/build/lib/cli/extension.d.ts +14 -0
  14. package/build/lib/cli/extension.d.ts.map +1 -0
  15. package/build/lib/cli/extension.js +7 -2
  16. package/build/lib/cli/parser.d.ts +79 -0
  17. package/build/lib/cli/parser.d.ts.map +1 -0
  18. package/build/lib/cli/parser.js +1 -1
  19. package/build/lib/cli/plugin-command.d.ts +39 -0
  20. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  21. package/build/lib/cli/plugin-command.js +6 -7
  22. package/build/lib/cli/utils.d.ts +29 -0
  23. package/build/lib/cli/utils.d.ts.map +1 -0
  24. package/build/lib/cli/utils.js +1 -1
  25. package/build/lib/config-file.d.ts +100 -0
  26. package/build/lib/config-file.d.ts.map +1 -0
  27. package/build/lib/config-file.js +1 -1
  28. package/build/lib/config.d.ts +40 -0
  29. package/build/lib/config.d.ts.map +1 -0
  30. package/build/lib/config.js +2 -2
  31. package/build/lib/constants.d.ts +48 -0
  32. package/build/lib/constants.d.ts.map +1 -0
  33. package/build/lib/constants.js +1 -1
  34. package/build/lib/extension/driver-config.d.ts +84 -0
  35. package/build/lib/extension/driver-config.d.ts.map +1 -0
  36. package/build/lib/extension/driver-config.js +1 -1
  37. package/build/lib/extension/extension-config.d.ts +170 -0
  38. package/build/lib/extension/extension-config.d.ts.map +1 -0
  39. package/build/lib/extension/extension-config.js +2 -2
  40. package/build/lib/extension/index.d.ts +39 -0
  41. package/build/lib/extension/index.d.ts.map +1 -0
  42. package/build/lib/extension/index.js +1 -1
  43. package/build/lib/extension/manifest.d.ts +174 -0
  44. package/build/lib/extension/manifest.d.ts.map +1 -0
  45. package/build/lib/extension/manifest.js +1 -1
  46. package/build/lib/extension/package-changed.d.ts +11 -0
  47. package/build/lib/extension/package-changed.d.ts.map +1 -0
  48. package/build/lib/extension/package-changed.js +1 -1
  49. package/build/lib/extension/plugin-config.d.ts +62 -0
  50. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  51. package/build/lib/extension/plugin-config.js +1 -1
  52. package/build/lib/grid-register.d.ts +10 -0
  53. package/build/lib/grid-register.d.ts.map +1 -0
  54. package/build/lib/logger.d.ts +3 -0
  55. package/build/lib/logger.d.ts.map +1 -0
  56. package/build/lib/logsink.d.ts +4 -0
  57. package/build/lib/logsink.d.ts.map +1 -0
  58. package/build/lib/logsink.js +1 -1
  59. package/build/lib/main.d.ts +51 -0
  60. package/build/lib/main.d.ts.map +1 -0
  61. package/build/lib/main.js +1 -1
  62. package/build/lib/schema/arg-spec.d.ts +143 -0
  63. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  64. package/build/lib/schema/arg-spec.js +1 -1
  65. package/build/lib/schema/cli-args.d.ts +19 -0
  66. package/build/lib/schema/cli-args.d.ts.map +1 -0
  67. package/build/lib/schema/cli-args.js +1 -1
  68. package/build/lib/schema/cli-transformers.d.ts +5 -0
  69. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  70. package/build/lib/schema/cli-transformers.js +1 -1
  71. package/build/lib/schema/index.d.ts +3 -0
  72. package/build/lib/schema/index.d.ts.map +1 -0
  73. package/build/lib/schema/keywords.d.ts +24 -0
  74. package/build/lib/schema/keywords.d.ts.map +1 -0
  75. package/build/lib/schema/keywords.js +1 -1
  76. package/build/lib/schema/schema.d.ts +259 -0
  77. package/build/lib/schema/schema.d.ts.map +1 -0
  78. package/build/lib/schema/schema.js +3 -3
  79. package/build/lib/utils.d.ts +66 -0
  80. package/build/lib/utils.d.ts.map +1 -0
  81. package/build/lib/utils.js +6 -4
  82. package/build/tsconfig.tsbuildinfo +1 -0
  83. package/lib/appium.js +163 -81
  84. package/lib/cli/args.js +1 -2
  85. package/lib/cli/driver-command.js +11 -8
  86. package/lib/cli/extension-command.js +129 -80
  87. package/lib/cli/extension.js +13 -3
  88. package/lib/cli/parser.js +1 -2
  89. package/lib/cli/plugin-command.js +16 -6
  90. package/lib/cli/utils.js +1 -1
  91. package/lib/config-file.js +3 -4
  92. package/lib/config.js +12 -8
  93. package/lib/constants.js +0 -1
  94. package/lib/extension/driver-config.js +31 -12
  95. package/lib/extension/extension-config.js +21 -22
  96. package/lib/extension/index.js +1 -2
  97. package/lib/extension/manifest.js +23 -127
  98. package/lib/extension/package-changed.js +0 -1
  99. package/lib/extension/plugin-config.js +9 -7
  100. package/lib/logsink.js +4 -0
  101. package/lib/main.js +9 -10
  102. package/lib/schema/arg-spec.js +10 -6
  103. package/lib/schema/cli-args.js +0 -1
  104. package/lib/schema/cli-transformers.js +0 -1
  105. package/lib/schema/keywords.js +0 -1
  106. package/lib/schema/schema.js +2 -3
  107. package/lib/utils.js +49 -16
  108. package/package.json +12 -14
  109. package/types/appium-manifest.d.ts +61 -0
  110. package/types/cli.d.ts +134 -0
  111. package/types/extension.d.ts +56 -0
  112. package/types/external-manifest.d.ts +58 -0
  113. package/types/index.d.ts +7 -0
  114. package/build/lib/appium-config.schema.json +0 -278
  115. package/build/lib/schema/appium-config-schema.js +0 -251
  116. package/lib/schema/appium-config-schema.js +0 -287
  117. package/types/appium-config.d.ts +0 -197
  118. package/types/types.d.ts +0 -245
@@ -1,12 +1,13 @@
1
- // @ts-check
2
1
  /* eslint-disable no-console */
3
2
 
4
3
  import _ from 'lodash';
5
- import { npm, fs, util } from '@appium/support';
4
+ import path from 'path';
5
+ import { npm, fs, util, env } from '@appium/support';
6
6
  import { log, spinWith, RingBuffer } from './utils';
7
7
  import { SubProcess } from 'teen_process';
8
8
  import { INSTALL_TYPE_NPM, INSTALL_TYPE_GIT, INSTALL_TYPE_GITHUB,
9
9
  INSTALL_TYPE_LOCAL } from '../extension/extension-config';
10
+ import { packageDidChange } from '../extension/package-changed';
10
11
 
11
12
  const UPDATE_ALL = 'installed';
12
13
 
@@ -16,7 +17,7 @@ class NoUpdatesAvailableError extends Error {}
16
17
  /**
17
18
  * @template {ExtensionType} ExtType
18
19
  */
19
- export default class ExtensionCommand {
20
+ class ExtensionCommand {
20
21
  /**
21
22
  * This is the `DriverConfig` or `PluginConfig`, depending on `ExtType`.
22
23
  * @type {ExtensionConfig<ExtType>}
@@ -25,7 +26,7 @@ export default class ExtensionCommand {
25
26
 
26
27
  /**
27
28
  * {@linkcode Record} of official plugins or drivers.
28
- * @type {ExtType extends import('../extension/manifest').DriverType ? typeof import('../constants').KNOWN_DRIVERS : typeof import('../constants').KNOWN_PLUGINS}
29
+ * @type {KnownExtensions<ExtType>}
29
30
  */
30
31
  knownExtensions;
31
32
 
@@ -59,7 +60,7 @@ export default class ExtensionCommand {
59
60
  */
60
61
  async execute (args) {
61
62
  const cmd = args[`${this.type}Command`];
62
- if (!_.isFunction(ExtensionCommand.prototype[cmd])) {
63
+ if (!_.isFunction(this[cmd])) {
63
64
  throw new Error(`Cannot handle ${this.type} command ${cmd}`);
64
65
  }
65
66
  const executeCmd = this[cmd].bind(this);
@@ -91,7 +92,12 @@ export default class ExtensionCommand {
91
92
  }
92
93
  }
93
94
  return acc;
94
- }, /** @type {ExtensionListData} */({}));
95
+ },
96
+ /**
97
+ * This accumulator contains either {@linkcode UninstalledExtensionLIstData} _or_
98
+ * {@linkcode InstalledExtensionListData} without upgrade information (which is added by the below code block)
99
+ * @type {Record<string,Partial<InstalledExtensionListData>|UninstalledExtensionListData>}
100
+ */({}));
95
101
 
96
102
  // if we want to show whether updates are available, put that behind a spinner
97
103
  await spinWith(this.isJsonOutput, lsMsg, async () => {
@@ -111,16 +117,18 @@ export default class ExtensionCommand {
111
117
  }
112
118
  });
113
119
 
120
+ const listData = /** @type {ExtensionListData} */(exts);
121
+
114
122
  // if we're just getting the data, short circuit return here since we don't need to do any
115
123
  // formatting logic
116
124
  if (this.isJsonOutput) {
117
- return exts;
125
+ return listData;
118
126
  }
119
127
 
120
128
  for (const [
121
129
  name,
122
130
  data
123
- ] of _.toPairs(exts)) {
131
+ ] of _.toPairs(listData)) {
124
132
  let installTxt = ' [not installed]'.grey;
125
133
  let updateTxt = '';
126
134
  let upToDateTxt = '';
@@ -157,7 +165,7 @@ export default class ExtensionCommand {
157
165
  console.log(`- ${name.yellow}${installTxt}${updateTxt}${upToDateTxt}${unsafeUpdateTxt}`);
158
166
  }
159
167
 
160
- return exts;
168
+ return listData;
161
169
  }
162
170
 
163
171
  /**
@@ -166,8 +174,7 @@ export default class ExtensionCommand {
166
174
  * @param {InstallArgs} args
167
175
  * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data
168
176
  */
169
- async install ({ext, installType, packageName}) {
170
- /** @type {ExtData<ExtType>} */
177
+ async _install ({ext, installType, packageName}) {
171
178
  let extData;
172
179
  let installSpec = ext;
173
180
 
@@ -179,14 +186,7 @@ export default class ExtensionCommand {
179
186
  throw new Error(`When using --source=${installType}, must also use --package`);
180
187
  }
181
188
 
182
- if (installType === INSTALL_TYPE_LOCAL) {
183
- const msg = `Linking ${this.type} from local path into ${this.config.appiumHome}`;
184
- const pkgJsonData = await spinWith(this.isJsonOutput, msg, async () => (
185
- await npm.linkPackage(this.config.appiumHome, installSpec))
186
- );
187
- extData = this.getExtensionFields(pkgJsonData);
188
- log(this.isJsonOutput, `Successfully linked ${extData.pkgName} into ${this.config.appiumHome}`);
189
- } else if (installType === INSTALL_TYPE_GITHUB) {
189
+ if (installType === INSTALL_TYPE_GITHUB) {
190
190
  if (installSpec.split('/').length !== 2) {
191
191
  throw new Error(`Github ${this.type} spec ${installSpec} appeared to be invalid; ` +
192
192
  'it should be of the form <org>/<repo>');
@@ -198,40 +198,44 @@ export default class ExtensionCommand {
198
198
  installSpec = installSpec.replace(/\.git$/, '');
199
199
  extData = await this.installViaNpm({ext: installSpec, pkgName: /** @type {string} */(packageName)});
200
200
  } else {
201
- // at this point we have either an npm package or an appium verified extension
202
- // name. both of which will be installed via npm.
203
- // extensions installed via npm can include versions or tags after the '@'
204
- // sign, so check for that. We also need to be careful that package names themselves can
205
- // contain the '@' symbol, as in `npm install @appium/fake-driver@1.2.0`
206
- let name, pkgVer;
207
- const splits = installSpec.split('@');
208
- if (installSpec[0] === '@') {
209
- // this is the case where we have an npm org included in the package name
210
- [name, pkgVer] = [`@${splits[1]}`, splits[2]];
201
+ let pkgName, pkgVer;
202
+ if (installType === INSTALL_TYPE_LOCAL) {
203
+ pkgName = path.isAbsolute(installSpec) ? installSpec : path.resolve(installSpec);
211
204
  } else {
212
- // this is the case without an npm org
213
- [name, pkgVer] = splits;
214
- }
215
- let pkgName;
205
+ // at this point we have either an npm package or an appium verified extension
206
+ // name or a local path. both of which will be installed via npm.
207
+ // extensions installed via npm can include versions or tags after the '@'
208
+ // sign, so check for that. We also need to be careful that package names themselves can
209
+ // contain the '@' symbol, as in `npm install @appium/fake-driver@1.2.0`
210
+ let name;
211
+ const splits = installSpec.split('@');
212
+ if (installSpec[0] === '@') {
213
+ // this is the case where we have an npm org included in the package name
214
+ [name, pkgVer] = [`@${splits[1]}`, splits[2]];
215
+ } else {
216
+ // this is the case without an npm org
217
+ [name, pkgVer] = splits;
218
+ }
216
219
 
217
- if (installType === INSTALL_TYPE_NPM) {
218
- // if we're installing a named package from npm, we don't need to check
219
- // against the appium extension list; just use the installSpec as is
220
- pkgName = name;
221
- } else {
222
- // if we're installing a named appium driver (like 'xcuitest') we need to
223
- // dereference the actual npm package ('appiupm-xcuitest-driver'), so
224
- // check it exists and get the correct package
225
- const knownNames = Object.keys(this.knownExtensions);
226
- if (!_.includes(knownNames, name)) {
227
- const msg = `Could not resolve ${this.type}; are you sure it's in the list ` +
228
- `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
229
- throw new Error(msg);
220
+ if (installType === INSTALL_TYPE_NPM) {
221
+ // if we're installing a named package from npm, we don't need to check
222
+ // against the appium extension list; just use the installSpec as is
223
+ pkgName = name;
224
+ } else {
225
+ // if we're installing a named appium driver (like 'xcuitest') we need to
226
+ // dereference the actual npm package ('appiupm-xcuitest-driver'), so
227
+ // check it exists and get the correct package
228
+ const knownNames = Object.keys(this.knownExtensions);
229
+ if (!_.includes(knownNames, name)) {
230
+ const msg = `Could not resolve ${this.type}; are you sure it's in the list ` +
231
+ `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
232
+ throw new Error(msg);
233
+ }
234
+ pkgName = this.knownExtensions[name];
235
+ // given that we'll use the install type in the driver json, store it as
236
+ // 'npm' now
237
+ installType = INSTALL_TYPE_NPM;
230
238
  }
231
- pkgName = this.knownExtensions[name];
232
- // given that we'll use the install type in the driver json, store it as
233
- // 'npm' now
234
- installType = INSTALL_TYPE_NPM;
235
239
  }
236
240
 
237
241
  extData = await this.installViaNpm({ext, pkgName, pkgVer});
@@ -246,9 +250,13 @@ export default class ExtensionCommand {
246
250
  `installed ${this.type}s with 'appium ${this.type} list --installed'.`);
247
251
  }
248
252
 
249
- extData.installType = installType;
250
- extData.installSpec = installSpec;
251
- await this.config.addExtension(extName, extData);
253
+ const extManifest = {...extData, installType, installSpec};
254
+ await this.config.addExtension(extName, extManifest);
255
+
256
+ // update the if we've changed the local `package.json`
257
+ if (await env.hasAppiumDependency(this.config.appiumHome)) {
258
+ await packageDidChange(this.config.appiumHome);
259
+ }
252
260
 
253
261
  // log info for the user
254
262
  log(this.isJsonOutput, this.getPostInstallText({extName, extData}));
@@ -260,7 +268,6 @@ export default class ExtensionCommand {
260
268
  * Install an extension via NPM
261
269
  *
262
270
  * @param {InstallViaNpmArgs} args
263
- * @returns {Promise<ExtData<ExtType>>}
264
271
  */
265
272
  async installViaNpm ({ext, pkgName, pkgVer}) {
266
273
  const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
@@ -296,8 +303,9 @@ export default class ExtensionCommand {
296
303
  * load as the main driver class, or to be able to detect incompatibilities between driver and
297
304
  * appium versions.
298
305
  *
299
- * @param {object} pkgJsonData - the package.json data for a driver module, as if it had been
306
+ * @param {ExtPackageJson<ExtType>} pkgJsonData - the package.json data for a driver module, as if it had been
300
307
  * straightforwardly 'require'd
308
+ * @returns {ExtensionFields<ExtType>}
301
309
  */
302
310
  getExtensionFields (pkgJsonData) {
303
311
  if (!pkgJsonData.appium) {
@@ -306,8 +314,9 @@ export default class ExtensionCommand {
306
314
  }
307
315
  const {appium, name, version} = pkgJsonData;
308
316
  this.validateExtensionFields(appium);
309
-
310
- return {...appium, pkgName: name, version};
317
+ /** @type {unknown} */
318
+ const result = {...appium, pkgName: name, version};
319
+ return /** @type {ExtensionFields<ExtType>} */(result);
311
320
  }
312
321
 
313
322
  /**
@@ -315,19 +324,20 @@ export default class ExtensionCommand {
315
324
  * presence and form of those fields on the package.json data, throwing an error if anything is
316
325
  * amiss.
317
326
  *
318
- * @param {import('../extension/manifest').ExternalData<ExtType>} appiumPkgData - the data in the "appium" field of package.json for an extension
327
+ * @param {ExtMetadata<ExtType>} appiumPkgData - the data in the "appium" field of package.json for an extension
319
328
  */
320
329
  // eslint-disable-next-line no-unused-vars
321
330
  validateExtensionFields (appiumPkgData) {
322
331
  throw new Error('Must be implemented in final class');
323
332
  }
333
+
324
334
  /**
325
335
  * Uninstall an extension
326
336
  *
327
337
  * @param {UninstallOpts} opts
328
338
  * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data
329
339
  */
330
- async uninstall ({ext}) {
340
+ async _uninstall ({ext}) {
331
341
  if (!this.config.isInstalled(ext)) {
332
342
  throw new Error(`Can't uninstall ${this.type} '${ext}'; it is not installed`);
333
343
  }
@@ -347,7 +357,7 @@ export default class ExtensionCommand {
347
357
  * @param {ExtensionUpdateOpts} updateSpec
348
358
  * @return {Promise<ExtensionUpdateResult>}
349
359
  */
350
- async update ({ext, unsafe}) {
360
+ async _update ({ext, unsafe}) {
351
361
  const shouldUpdateAll = ext === UPDATE_ALL;
352
362
  // if we're specifically requesting an update for an extension, make sure it's installed
353
363
  if (!shouldUpdateAll && !this.config.isInstalled(ext)) {
@@ -450,6 +460,7 @@ export default class ExtensionCommand {
450
460
  *
451
461
  * @param {string} ext - name of extension to update
452
462
  * @param {string} version - version string identifier to update extension to
463
+ * @returns {Promise<void>}
453
464
  */
454
465
  async updateExtension (ext, version) {
455
466
  const {pkgName} = this.config.installedExtensions[ext];
@@ -470,7 +481,7 @@ export default class ExtensionCommand {
470
481
  * @param {RunOptions} opts
471
482
  * @return {Promise<RunOutput>}
472
483
  */
473
- async run ({ext, scriptName}) {
484
+ async _run ({ext, scriptName}) {
474
485
  if (!_.has(this.config.installedExtensions, ext)) {
475
486
  throw new Error(`please install the ${this.type} first`);
476
487
  }
@@ -519,10 +530,8 @@ export default class ExtensionCommand {
519
530
  }
520
531
  }
521
532
 
522
- /**
523
- * @template {ExtensionType} ExtType
524
- * @typedef {import('../extension/extension-config').ExtensionConfig<ExtType>} ExtensionConfig
525
- */
533
+ export default ExtensionCommand;
534
+ export {ExtensionCommand};
526
535
 
527
536
  /**
528
537
  * Options for the {@linkcode ExtensionCommand} constructor
@@ -537,39 +546,68 @@ export default class ExtensionCommand {
537
546
  *
538
547
  * @typedef ExtensionMetadata
539
548
  * @property {boolean} installed - If `true`, the extension is installed
540
- * @property {string|null} [updateVersion] - If the extension is installed, the version it can be updated to
541
- * @property {string|null} [unsafeUpdateVersion] - Same as above, but a major version bump
542
- * @property {boolean} [upToDate] - If the extension is installed and the latest
549
+ * @property {string?} updateVersion - If the extension is installed, the version it can be updated to
550
+ * @property {string?} unsafeUpdateVersion - Same as above, but a major version bump
551
+ * @property {boolean} upToDate - If the extension is installed and the latest
552
+ */
553
+
554
+ /**
555
+ * @typedef {import('../../types').ExtensionType} ExtensionType
556
+ * @typedef {import('../../types').DriverType} DriverType
557
+ * @typedef {import('../../types').PluginType} PluginType
543
558
  */
544
559
 
545
560
  /**
546
- * @typedef {import('../extension/manifest').ExtensionType} ExtensionType
561
+ * @template {ExtensionType} ExtType
562
+ * @typedef {import('../../types/appium-manifest').ExtRecord<ExtType>} ExtRecord
547
563
  */
548
564
 
549
565
  /**
550
566
  * @template {ExtensionType} ExtType
551
- * @typedef {import('../extension/manifest').ExtRecord<ExtType>} ExtRecord
567
+ * @typedef {import('../extension/extension-config').ExtensionConfig<ExtType>} ExtensionConfig
552
568
  */
553
569
 
554
570
  /**
555
571
  * @template {ExtensionType} ExtType
556
- * @typedef {import('../extension/manifest').ExtData<ExtType>} ExtData
572
+ * @typedef {import('../../types/external-manifest').ExtMetadata<ExtType>} ExtMetadata
573
+ */
574
+
575
+ /**
576
+ * @template {ExtensionType} ExtType
577
+ * @typedef {import('../../types/appium-manifest').ExtManifest<ExtType>} ExtManifest
578
+ */
579
+
580
+ /**
581
+ * @template {ExtensionType} ExtType
582
+ * @typedef {import('../../types/external-manifest').ExtPackageJson<ExtType>} ExtPackageJson
583
+ */
584
+
585
+ /**
586
+ * Possible return value for {@linkcode ExtensionCommand.list}
587
+ * @typedef UninstalledExtensionListData
588
+ * @property {string} pkgName
589
+ * @property {false} installed
590
+ */
591
+
592
+ /**
593
+ * Possible return value for {@linkcode ExtensionCommand.list}
594
+ * @typedef {import('../../types/appium-manifest').InternalMetadata & ExtensionMetadata} InstalledExtensionListData
557
595
  */
558
596
 
559
597
  /**
560
598
  * Return value of {@linkcode ExtensionCommand.list}.
561
- * @typedef {Record<string, (import('../extension/manifest').InternalData & ExtensionMetadata) | { pkgName: string, installed: false }>} ExtensionListData
599
+ * @typedef {Record<string,InstalledExtensionListData|UninstalledExtensionListData>} ExtensionListData
562
600
  */
563
601
 
564
602
  /**
565
- * Options for {@linkcode ExtensionCommand.run}.
603
+ * Options for {@linkcode ExtensionCommand._run}.
566
604
  * @typedef RunOptions
567
605
  * @property {string} ext - name of the extension to run a script from
568
606
  * @property {string} scriptName - name of the script to run
569
607
  */
570
608
 
571
609
  /**
572
- * Return value of {@linkcode ExtensionCommand.run}
610
+ * Return value of {@linkcode ExtensionCommand._run}
573
611
  *
574
612
  * @typedef RunOutput
575
613
  * @property {string} [error] - error message if script ran unsuccessfully, otherwise undefined
@@ -577,28 +615,28 @@ export default class ExtensionCommand {
577
615
  */
578
616
 
579
617
  /**
580
- * Options for {@linkcode ExtensionCommand.update}.
618
+ * Options for {@linkcode ExtensionCommand._update}.
581
619
  * @typedef ExtensionUpdateOpts
582
620
  * @property {string} ext - the name of the extension to update
583
621
  * @property {boolean} unsafe - if true, will perform unsafe updates past major revision boundaries
584
622
  */
585
623
 
586
624
  /**
587
- * Return value of {@linkcode ExtensionCommand.update}.
625
+ * Return value of {@linkcode ExtensionCommand._update}.
588
626
  * @typedef ExtensionUpdateResult
589
627
  * @property {Record<string,Error>} errors - map of ext names to error objects
590
628
  * @property {Record<string,UpdateReport>} updates - map of ext names to {@linkcode UpdateReport}s
591
629
  */
592
630
 
593
631
  /**
594
- * Part of result of {@linkcode ExtensionCommand.update}.
632
+ * Part of result of {@linkcode ExtensionCommand._update}.
595
633
  * @typedef UpdateReport
596
634
  * @property {string} from - version the extension was updated from
597
635
  * @property {string} to - version the extension was updated to
598
636
  */
599
637
 
600
638
  /**
601
- * Options for {@linkcode ExtensionCommand.uninstall}.
639
+ * Options for {@linkcode ExtensionCommand._uninstall}.
602
640
  * @typedef UninstallOpts
603
641
  * @property {string} ext - the name or spec of an extension to uninstall
604
642
  */
@@ -627,9 +665,20 @@ export default class ExtensionCommand {
627
665
  */
628
666
 
629
667
  /**
630
- * Options for {@linkcode ExtensionCommand.install}
668
+ * Options for {@linkcode ExtensionCommand._install}
631
669
  * @typedef InstallArgs
632
670
  * @property {string} ext - the name or spec of an extension to install
633
- * @property {import('../extension/extension-config').InstallType} installType - how to install this extension. One of the INSTALL_TYPES
671
+ * @property {import('../../types/appium-manifest').InstallType} installType - how to install this extension. One of the INSTALL_TYPES
634
672
  * @property {string} [packageName] - for git/github installs, the extension node package name
635
673
  */
674
+
675
+ /**
676
+ * Returned by {@linkcode ExtensionCommand.getExtensionFields}
677
+ * @template {ExtensionType} ExtType
678
+ * @typedef {ExtMetadata<ExtType> & { pkgName: string, version: string } & import('../../types/external-manifest').CommonMetadata} ExtensionFields
679
+ */
680
+
681
+ /**
682
+ * @template {ExtensionType} ExtType
683
+ * @typedef {ExtType extends DriverType ? typeof import('../constants').KNOWN_DRIVERS : ExtType extends PluginType ? typeof import('../constants').KNOWN_PLUGINS : never} KnownExtensions
684
+ */
@@ -2,16 +2,21 @@
2
2
 
3
3
  import DriverCommand from './driver-command';
4
4
  import PluginCommand from './plugin-command';
5
- import { DRIVER_TYPE } from '../constants';
5
+ import { DRIVER_TYPE, PLUGIN_TYPE } from '../constants';
6
6
  import { errAndQuit, log, JSON_SPACES } from './utils';
7
7
 
8
+ const commandClasses = Object.freeze(/** @type {const} */({
9
+ [DRIVER_TYPE]: DriverCommand,
10
+ [PLUGIN_TYPE]: PluginCommand
11
+ }));
12
+
8
13
  /**
9
14
  * Run a subcommand of the 'appium driver' type. Each subcommand has its own set of arguments which
10
15
  * can be represented as a JS object.
11
16
  *
12
17
  * @param {Object} args - JS object where the key is the parameter name (as defined in
13
18
  * driver-parser.js)
14
- * @template {ExtensionType} ExtType
19
+ * @template {import('../extension/manifest').ExtensionType} ExtType
15
20
  * @param {import('../extension/extension-config').ExtensionConfig<ExtType>} configObject - Extension config object
16
21
  */
17
22
  async function runExtensionCommand (args, configObject) {
@@ -30,7 +35,7 @@ async function runExtensionCommand (args, configObject) {
30
35
  const logFn = (msg) => log(json, msg);
31
36
  let config = configObject;
32
37
  config.log = logFn;
33
- const CommandClass = type === DRIVER_TYPE ? DriverCommand : PluginCommand;
38
+ const CommandClass = /** @type {ExtCommand<ExtType>} */(commandClasses[type]);
34
39
  const cmd = new CommandClass({config, json});
35
40
  try {
36
41
  jsonResult = await cmd.execute(args);
@@ -53,3 +58,8 @@ async function runExtensionCommand (args, configObject) {
53
58
  export {
54
59
  runExtensionCommand,
55
60
  };
61
+
62
+ /**
63
+ * @template {import('../../types').ExtensionType} ExtType
64
+ * @typedef {ExtType extends import('../../types').DriverType ? import('@appium/types').Class<DriverCommand> : ExtType extends import('../../types').PluginType ? import('@appium/types').Class<PluginCommand> : never} ExtCommand
65
+ */
package/lib/cli/parser.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
 
3
2
  import { fs } from '@appium/support';
4
3
  import { ArgumentParser } from 'argparse';
@@ -101,7 +100,7 @@ class ArgParser {
101
100
  *
102
101
  * `ArgParser.prototype.parse_args` is an alias of this method.
103
102
  * @param {string[]} [args] - Array of arguments, ostensibly from `process.argv`. Gathers args from `process.argv` if not provided.
104
- * @returns {import('../../types/types').ParsedArgs} - The parsed arguments
103
+ * @returns {import('../../types/cli').ParsedArgs} - The parsed arguments
105
104
  */
106
105
  parseArgs (args = process.argv.slice(2)) {
107
106
  if (!NON_SERVER_ARGS.has(args[0])) {
@@ -1,30 +1,34 @@
1
1
  import _ from 'lodash';
2
2
  import ExtensionCommand from './extension-command';
3
- import { PLUGIN_TYPE, KNOWN_PLUGINS } from '../constants';
3
+ import { KNOWN_PLUGINS } from '../constants';
4
4
 
5
5
  const REQ_PLUGIN_FIELDS = ['pluginName', 'mainClass'];
6
6
 
7
7
  export default class PluginCommand extends ExtensionCommand {
8
8
 
9
+ /**
10
+ *
11
+ * @param {PluginCommandOptions} opts
12
+ */
9
13
  constructor ({config, json}) {
10
- super({config, json, type: PLUGIN_TYPE});
14
+ super({config, json});
11
15
  this.knownExtensions = KNOWN_PLUGINS;
12
16
  }
13
17
 
14
18
  async install ({plugin, installType, packageName}) {
15
- return await super.install({ext: plugin, installType, packageName});
19
+ return await super._install({ext: plugin, installType, packageName});
16
20
  }
17
21
 
18
22
  async uninstall ({plugin}) {
19
- return await super.uninstall({ext: plugin});
23
+ return await super._uninstall({ext: plugin});
20
24
  }
21
25
 
22
26
  async update ({plugin, unsafe}) {
23
- return await super.update({ext: plugin, unsafe});
27
+ return await super._update({ext: plugin, unsafe});
24
28
  }
25
29
 
26
30
  async run ({plugin, scriptName}) {
27
- return await super.run({ext: plugin, scriptName});
31
+ return await super._run({ext: plugin, scriptName});
28
32
  }
29
33
 
30
34
  getPostInstallText ({extName, extData}) {
@@ -44,3 +48,9 @@ export default class PluginCommand extends ExtensionCommand {
44
48
  }
45
49
 
46
50
  }
51
+
52
+ /**
53
+ * @typedef PluginCommandOptions
54
+ * @property {import('../extension/extension-config').ExtensionConfig<import('../extension/manifest').PluginType>} config
55
+ * @property {boolean} json
56
+ */
package/lib/cli/utils.js CHANGED
@@ -7,7 +7,7 @@ const JSON_SPACES = 4;
7
7
  /***
8
8
  * Log an error to the console and exit the process.
9
9
  * @param {boolean} json - whether we should log json or text
10
- * @param {string} msg - error message
10
+ * @param {any} msg - error message, object, Error instance, etc.
11
11
  */
12
12
  function errAndQuit (json, msg) {
13
13
  if (json) {
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
 
3
2
  import betterAjvErrors from '@sidvind/better-ajv-errors';
4
3
  import { lilconfig } from 'lilconfig';
@@ -186,7 +185,7 @@ export function normalizeConfig (config) {
186
185
  * @property {string} [filepath] - The path to the config file, if found
187
186
  * @property {boolean} [isEmpty] - If `true`, the config file exists but is empty
188
187
  * @property {NormalizedAppiumConfig} [config] - The parsed configuration
189
- * @property {string|betterAjvErrors.IOutputError[]} [reason] - Human-readable error messages and suggestions. If the `pretty` option is `true`, this will be a nice string to print.
188
+ * @property {string|import('@sidvind/better-ajv-errors').IOutputError[]} [reason] - Human-readable error messages and suggestions. If the `pretty` option is `true`, this will be a nice string to print.
190
189
  */
191
190
 
192
191
  /**
@@ -202,12 +201,12 @@ export function normalizeConfig (config) {
202
201
 
203
202
  /**
204
203
  * The contents of an Appium config file. Generated from schema
205
- * @typedef {import('../types/types').AppiumConfig} AppiumConfig
204
+ * @typedef {import('@appium/types').AppiumConfig} AppiumConfig
206
205
  */
207
206
 
208
207
  /**
209
208
  * The contents of an Appium config file with camelcased property names (and using `appiumCliDest` value if present). Generated from {@link AppiumConfig}
210
- * @typedef {import('../types/types').NormalizedAppiumConfig} NormalizedAppiumConfig
209
+ * @typedef {import('@appium/types').NormalizedAppiumConfig} NormalizedAppiumConfig
211
210
  */
212
211
 
213
212
  /**
package/lib/config.js CHANGED
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  /* eslint-disable no-console */
4
2
  import _ from 'lodash';
5
3
  import { system, fs } from '@appium/support';
@@ -19,6 +17,9 @@ const GIT_META_ROOT = '.git';
19
17
  const GIT_BINARY = `git${system.isWindows() ? '.exe' : ''}`;
20
18
  const GITHUB_API = 'https://api.github.com/repos/appium/appium';
21
19
 
20
+ /**
21
+ * @type {import('../types/cli').BuildInfo}
22
+ */
22
23
  const BUILD_INFO = {
23
24
  version: APPIUM_VER,
24
25
  };
@@ -34,7 +35,7 @@ async function updateBuildInfo (useGithubApiFallback = false) {
34
35
  }
35
36
  BUILD_INFO['git-sha'] = sha;
36
37
  const built = await getGitTimestamp(sha, useGithubApiFallback);
37
- if (!_.isEmpty(built)) {
38
+ if (built) {
38
39
  BUILD_INFO.built = built;
39
40
  }
40
41
  }
@@ -85,7 +86,7 @@ async function getGitRev (useGithubApiFallback = false) {
85
86
  /**
86
87
  * @param {string} commitSha
87
88
  * @param {boolean} [useGithubApiFallback]
88
- * @returns {Promise<number?>}
89
+ * @returns {Promise<string?>}
89
90
  */
90
91
  async function getGitTimestamp (commitSha, useGithubApiFallback = false) {
91
92
  const gitRoot = await findGitRoot();
@@ -121,10 +122,11 @@ async function getGitTimestamp (commitSha, useGithubApiFallback = false) {
121
122
  }
122
123
 
123
124
  /**
124
- * @return Mutable object containing Appium build information. By default it
125
+ * Mutable object containing Appium build information. By default it
125
126
  * only contains the Appium version, but is updated with the build timestamp
126
127
  * and git commit hash asynchronously as soon as `updateBuildInfo` is called
127
128
  * and succeeds.
129
+ * @returns {import('../types/cli').BuildInfo}
128
130
  */
129
131
  function getBuildInfo () {
130
132
  return BUILD_INFO;
@@ -166,7 +168,7 @@ function getNonDefaultServerArgs (parsedArgs) {
166
168
  * Flattens parsed args into a single level object for comparison with
167
169
  * flattened defaults across server args and extension args.
168
170
  * @param {ParsedArgs} args
169
- * @returns {Record<string, { value: any, argSpec: import('./schema/arg-spec').ArgSpec }>}
171
+ * @returns {Record<string, { value: any, argSpec: ArgSpec }>}
170
172
  */
171
173
  const flatten = (args) => {
172
174
  const argSpecs = getAllArgSpecs();
@@ -175,7 +177,7 @@ function getNonDefaultServerArgs (parsedArgs) {
175
177
  acc[argSpec.dest] = {value: _.get(args, argSpec.dest), argSpec};
176
178
  }
177
179
  return acc;
178
- }, /** @type {Record<string, { value: any, argSpec: import('./schema/arg-spec').ArgSpec }>} */({}));
180
+ }, /** @type {Record<string, { value: any, argSpec: ArgSpec }>} */({}));
179
181
 
180
182
  return flattened;
181
183
  };
@@ -304,5 +306,7 @@ export {
304
306
  };
305
307
 
306
308
  /**
307
- * @typedef {import('../types/types').ParsedArgs} ParsedArgs
309
+ * @typedef {import('../types/cli').ParsedArgs} ParsedArgs
310
+ * @typedef {import('./schema/arg-spec').ArgSpec} ArgSpec
308
311
  */
312
+
package/lib/constants.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
 
3
2
  import path from 'path';
4
3