Introduce types for Sandy plugins through code base

Summary:
So far there were 2 types of plugins: `FlipperPlugin` and `FlipperDevicePlugin`. This introduces a third kind: `SandyPluginDefinition`.

Unlike with the old plugins, the export of the module is not directly exposed as the plugin definition. Rather, we use class `SandyPluginDefinition` (instance) that holds a loaded definition and its meta data separately (`PluginDetails`). This means that we don't have to mix in and mutate loaded definitions, and that for unit tests we can avoid needing to provide a bunch of meta data. This also prevents a bunch of meta data existing on two places: on the loaded classes as static fields, and in the meta data field of the loaded class as well. Finally, we can now freely extends the `PluginDetails` interface in flipper, without needing to store it on the loaded classes and we are sure that no naming conflicts are caused by this in the future.

For compatibility with the existing code base, common fields are delegated from the `SandyPluginDefinition` class to the meta data.

Also cleaned up types around plugins a little bit and removed some unnecessary casts.

For all features that reason about plugins in general (such as exports), sandy plugins are ignored for now.

`SandyPluginInstance` is worked out in further diffs

The `instanceof` calls are replaced by a utility function in later diffs.

{F241363645}

Reviewed By: jknoxville

Differential Revision: D22091432

fbshipit-source-id: 3aa6b12fda5925268913779f3c3c9e84494438f8
This commit is contained in:
Michel Weststrate
2020-07-01 08:58:40 -07:00
committed by Facebook GitHub Bot
parent 845c9b67f5
commit 1029a6c97c
23 changed files with 332 additions and 160 deletions

View File

@@ -7,12 +7,18 @@
* @format
*/
import {FlipperDevicePlugin, FlipperPlugin, FlipperBasePlugin} from '../plugin';
import {
FlipperDevicePlugin,
FlipperBasePlugin,
PluginDefinition,
DevicePluginDefinition,
} from '../plugin';
import {State as PluginStatesState} from '../reducers/pluginStates';
import {State as PluginsState} from '../reducers/plugins';
import {State as PluginMessageQueueState} from '../reducers/pluginMessageQueue';
import {PluginDetails} from 'flipper-plugin-lib';
import {deconstructPluginKey, deconstructClientId} from './clientUtils';
import {SandyPluginDefinition} from 'flipper-plugin';
type Client = import('../Client').default;
@@ -20,11 +26,8 @@ export const defaultEnabledBackgroundPlugins = ['Navigation']; // The navigation
export function pluginsClassMap(
plugins: PluginsState,
): Map<string, typeof FlipperDevicePlugin | typeof FlipperPlugin> {
const pluginsMap: Map<
string,
typeof FlipperDevicePlugin | typeof FlipperPlugin
> = new Map([]);
): Map<string, PluginDefinition> {
const pluginsMap: Map<string, PluginDefinition> = new Map([]);
plugins.clientPlugins.forEach((val, key) => {
pluginsMap.set(key, val);
});
@@ -83,10 +86,7 @@ export function getEnabledOrExportPersistedStatePlugins(
plugins: PluginsState,
): Array<{id: string; label: string}> {
const appName = deconstructClientId(client.id).app;
const pluginsMap: Map<
string,
typeof FlipperDevicePlugin | typeof FlipperPlugin
> = pluginsClassMap(plugins);
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
// Enabled Plugins with no exportPersistedState function defined
const enabledPlugins = starredPlugin[appName]
? starredPlugin[appName]
@@ -141,10 +141,7 @@ export function getActivePersistentPlugins(
plugins: PluginsState,
selectedClient?: Client,
): {id: string; label: string}[] {
const pluginsMap: Map<
string,
typeof FlipperDevicePlugin | typeof FlipperPlugin
> = pluginsClassMap(plugins);
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
return getPersistentPlugins(plugins)
.map((pluginName) => pluginsMap.get(pluginName)!)
.sort(sortPluginsByName)
@@ -183,10 +180,7 @@ export function getActivePersistentPlugins(
}
export function getPersistentPlugins(plugins: PluginsState): Array<string> {
const pluginsMap: Map<
string,
typeof FlipperDevicePlugin | typeof FlipperPlugin
> = pluginsClassMap(plugins);
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
const arr: Array<PluginDetails> = plugins.disabledPlugins.concat(
plugins.gatekeepedPlugins,
@@ -210,32 +204,36 @@ export function getPersistentPlugins(plugins: PluginsState): Array<string> {
return (
plugin == 'DeviceLogs' ||
(pluginClass &&
// TODO: support Sandy plugin T68683449
!(pluginClass instanceof SandyPluginDefinition) &&
(pluginClass.defaultPersistedState != undefined ||
pluginClass.exportPersistedState != undefined))
);
});
}
export function getPluginTitle(pluginClass: typeof FlipperBasePlugin) {
export function getPluginTitle(pluginClass: PluginDefinition) {
return pluginClass.title || pluginClass.id;
}
export function sortPluginsByName(
a: typeof FlipperBasePlugin,
b: typeof FlipperBasePlugin,
a: PluginDefinition,
b: PluginDefinition,
): number {
// make sure Device plugins are sorted before normal plugins
if (
a.prototype instanceof FlipperDevicePlugin &&
!(b.prototype instanceof FlipperDevicePlugin)
) {
if (isDevicePluginDefinition(a) && !isDevicePluginDefinition(b)) {
return -1;
}
if (
b.prototype instanceof FlipperDevicePlugin &&
!(a.prototype instanceof FlipperDevicePlugin)
) {
if (isDevicePluginDefinition(b) && !isDevicePluginDefinition(a)) {
return 1;
}
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
}
export function isDevicePluginDefinition(
definition: PluginDefinition,
): definition is DevicePluginDefinition {
// TODO: support Sandy device plugins T68738317
// @ts-ignore
return definition.prototype instanceof FlipperDevicePlugin;
}