Files
appium/packages/base-plugin/lib/plugin.js
Christopher Hiller 0dcd5fa371 fix(base-driver,base-plugin,types): update PluginCommand and DriverCommand types
The first arg of `PluginCommand` is a `NextPluginCallback` which now returns `Promise<unknown>` instead of `Promise<void>`, which was incorrect.

We use `unknown` rather than `any` because it forces us to be explicit about the return value of `await next()` if we are to call it.

Added a type `DriverCommandToPluginCommand` which essentially converts a `DriverCommand` to a `PluginCommand`.  It's probably best used as a type guard or decorator, but it can "fill in the blanks" when overloading commands in a plugin.

Also normalized some of the `TArgs`/`TReturn` stuff.
2023-03-27 14:23:25 -07:00

97 lines
3.1 KiB
JavaScript

import {logger} from '@appium/support';
import {validateExecuteMethodParams} from '@appium/base-driver';
/**
* @implements {Plugin}
*/
class BasePlugin {
/**
* Subclasses should use type `import('@appium/types').MethodMap<SubclassName>`.
*
* This will verify that the commands in the `newMethodMap` property are
* valid. It is impossible to use a generic type param here; the type of this should really
* be something like `MethodMap<T extends BasePlugin>` but that isn't a thing TS does.
*
* ```ts
* static newMethodMap = {
* '/session/:sessionId/fake_data': {
* GET: {command: 'getFakeSessionData', neverProxy: true},
* }
* } as const;
* ```
*/
static newMethodMap = {};
/**
* Subclasses should use type `import('@appium/types').ExecuteMethodMap<SubclassName>`.
*
* Building up this map allows the use of the convenience function `executeMethod`, which
* basically does verification of names and parameters for execute methods implemented by this
* plugin.
*
* ```ts
* static executeMethodMap = {
* 'foo: bar': {
* command: 'commandName',
* params: {required: ['thing1', 'thing2'], optional: ['thing3']},
* },
* } as const;
* ```
*/
static executeMethodMap = {};
/**
* @param {string} name
* @param {Record<string,unknown>} [cliArgs]
*/
constructor(name, cliArgs = {}) {
this.name = name;
this.cliArgs = cliArgs;
this.logger = logger.getLogger(`Plugin [${name}]`);
}
/**
* A convenience method that can be called by plugins who implement their own `executeMethodMap`.
* Only useful if your plugin has defined `executeMethodMap`. This helper requires passing in the
* `next` and `driver` objects since naturally we'd want to make sure to trigger the driver's own
* `executeMethod` call if an execute method is not found on the plugin itself.
*
* @template {Constraints} C
* @param {NextPluginCallback} next
* @param {Driver<C>} driver
* @param {string} script
* @param {readonly [import('@appium/types').StringRecord<unknown>] | readonly any[]} protoArgs
*/
async executeMethod(next, driver, script, protoArgs) {
const Plugin = /** @type {import('@appium/types').PluginClass<Plugin>} */ (this.constructor);
const commandMetadata = {...Plugin.executeMethodMap?.[script]};
if (!commandMetadata.command || !(commandMetadata.command in this)) {
this.logger.info(
`Plugin did not know how to handle method '${script}'. Passing control to next`
);
return await next();
}
const command = /** @type {import('@appium/types').PluginCommand<Driver<C>>} */ (
this[commandMetadata.command]
);
const args = validateExecuteMethodParams(protoArgs, commandMetadata.params);
return await command.call(this, next, driver, ...args);
}
}
export default BasePlugin;
export {BasePlugin};
/**
* @typedef {import('@appium/types').Plugin} Plugin
* @typedef {import('@appium/types').NextPluginCallback} NextPluginCallback
* @typedef {import('@appium/types').Constraints} Constraints
*/
/**
* @template {Constraints} C
* @typedef {import('@appium/types').Driver<C>} Driver
*/