Device plugin management (1/n): use static metadata for checking plugin compatibility with devices

Summary:
*Stack summary*: this stack adds ability to manage device plugins in the same way as client plugins: install, update, uninstall, enable (star) and disable (unstar) them.

*Diff summary*: changed the way how plugin compatibility with devices is checked from dynamic call to "supportsDevice" to static checks of "supportedDevices" metadata property which make it possible to check compatibility without even downloading plugin from Marketplace.

Changelog: plugin compatibility with devices is now checked according to metadata in property "supportedDevices" in package.json

Reviewed By: mweststrate

Differential Revision: D26315848

fbshipit-source-id: 6e4b052c4ea0507ee185fc17999b6211cdb11093
This commit is contained in:
Anton Nikolaev
2021-02-16 10:46:11 -08:00
committed by Facebook GitHub Bot
parent 19f2fccc79
commit 899fcd0783
16 changed files with 263 additions and 65 deletions

View File

@@ -72,7 +72,7 @@ test('Devices can disconnect', async () => {
test('New device with same serial removes & cleans the old one', async () => { test('New device with same serial removes & cleans the old one', async () => {
const deviceplugin = new _SandyPluginDefinition( const deviceplugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails({pluginType: 'device'}),
{ {
devicePlugin(client: DevicePluginClient) { devicePlugin(client: DevicePluginClient) {
const destroy = jest.fn(); const destroy = jest.fn();

View File

@@ -17,9 +17,13 @@ import {
Idler, Idler,
createState, createState,
} from 'flipper-plugin'; } from 'flipper-plugin';
import type {DevicePluginDefinition, DevicePluginMap} from '../plugin'; import {
DevicePluginDefinition,
DevicePluginMap,
FlipperDevicePlugin,
} from '../plugin';
import {getFlipperLibImplementation} from '../utils/flipperLibImplementation'; import {getFlipperLibImplementation} from '../utils/flipperLibImplementation';
import {DeviceSpec, OS as PluginOS} from 'flipper-plugin-lib'; import {DeviceSpec, OS as PluginOS, PluginDetails} from 'flipper-plugin-lib';
export type DeviceShell = { export type DeviceShell = {
stdout: stream.Readable; stdout: stream.Readable;
@@ -175,6 +179,38 @@ export default class BaseDevice {
return null; return null;
} }
supportsPlugin(plugin: DevicePluginDefinition | PluginDetails) {
let pluginDetails: PluginDetails;
if (isDevicePluginDefinition(plugin)) {
pluginDetails = plugin.details;
if (!pluginDetails.pluginType && !pluginDetails.supportedDevices) {
// TODO T84453692: this branch is to support plugins defined with the legacy approach. Need to remove this branch after some transition period when
// all the plugins will be migrated to the new approach with static compatibility metadata in package.json.
if (plugin instanceof _SandyPluginDefinition) {
return (
plugin.isDevicePlugin &&
plugin.asDevicePluginModule().supportsDevice(this as any)
);
} else {
return plugin.supportsDevice(this);
}
}
} else {
pluginDetails = plugin;
}
return (
pluginDetails.pluginType === 'device' &&
(!pluginDetails.supportedDevices ||
pluginDetails.supportedDevices?.some(
(d) =>
(!d.os || d.os === this.os) &&
(!d.type || d.type === this.deviceType) &&
(d.archived === undefined || d.archived === this.isArchived) &&
(!d.specs || d.specs.every((spec) => this.specs.includes(spec))),
))
);
}
loadDevicePlugins( loadDevicePlugins(
devicePlugins?: DevicePluginMap, devicePlugins?: DevicePluginMap,
pluginStates?: Record<string, any>, pluginStates?: Record<string, any>,
@@ -189,9 +225,11 @@ export default class BaseDevice {
} }
loadDevicePlugin(plugin: DevicePluginDefinition, initialState?: any) { loadDevicePlugin(plugin: DevicePluginDefinition, initialState?: any) {
if (plugin instanceof _SandyPluginDefinition) { if (!this.supportsPlugin(plugin)) {
if (plugin.asDevicePluginModule().supportsDevice(this as any)) { return;
}
this.devicePlugins.push(plugin.id); this.devicePlugins.push(plugin.id);
if (plugin instanceof _SandyPluginDefinition) {
this.sandyPluginStates.set( this.sandyPluginStates.set(
plugin.id, plugin.id,
new _SandyDevicePluginInstance( new _SandyDevicePluginInstance(
@@ -202,11 +240,6 @@ export default class BaseDevice {
), ),
); );
} }
} else {
if (plugin.supportsDevice(this)) {
this.devicePlugins.push(plugin.id);
}
}
} }
unloadDevicePlugin(pluginId: string) { unloadDevicePlugin(pluginId: string) {
@@ -231,3 +264,12 @@ export default class BaseDevice {
this.sandyPluginStates.clear(); this.sandyPluginStates.clear();
} }
} }
function isDevicePluginDefinition(
definition: any,
): definition is DevicePluginDefinition {
return (
(definition as any).prototype instanceof FlipperDevicePlugin ||
(definition instanceof _SandyPluginDefinition && definition.isDevicePlugin)
);
}

View File

@@ -0,0 +1,152 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import BaseDevice from '../BaseDevice';
import * as DeviceTestPluginModule from '../../test-utils/DeviceTestPlugin';
import {TestUtils, _SandyPluginDefinition} from 'flipper-plugin';
import ArchivedDevice from '../ArchivedDevice';
const physicalDevicePluginDetails = TestUtils.createMockPluginDetails({
id: 'physicalDevicePlugin',
name: 'flipper-plugin-physical-device',
version: '0.0.1',
pluginType: 'device',
supportedDevices: [
{
os: 'iOS',
type: 'physical',
archived: false,
},
{
os: 'Android',
type: 'physical',
},
],
});
const physicalDevicePlugin = new _SandyPluginDefinition(
physicalDevicePluginDetails,
DeviceTestPluginModule,
);
const iosPhysicalDevicePluginDetails = TestUtils.createMockPluginDetails({
id: 'iosPhysicalDevicePlugin',
name: 'flipper-plugin-ios-physical-device',
version: '0.0.1',
pluginType: 'device',
supportedDevices: [
{
os: 'iOS',
type: 'physical',
},
],
});
const iosPhysicalDevicePlugin = new _SandyPluginDefinition(
iosPhysicalDevicePluginDetails,
DeviceTestPluginModule,
);
const iosEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
id: 'iosEmulatorDevicePlugin',
name: 'flipper-plugin-ios-emulator-device',
version: '0.0.1',
pluginType: 'device',
supportedDevices: [
{
os: 'iOS',
type: 'emulator',
},
],
});
const iosEmulatorDevicePlugin = new _SandyPluginDefinition(
iosEmulatorlDevicePluginDetails,
DeviceTestPluginModule,
);
const androiKaiosPhysicalDevicePluginDetails = TestUtils.createMockPluginDetails(
{
id: 'androidPhysicalDevicePlugin',
name: 'flipper-plugin-android-physical-device',
version: '0.0.1',
pluginType: 'device',
supportedDevices: [
{
os: 'Android',
type: 'physical',
specs: ['KaiOS'],
},
],
},
);
const androidKaiosPhysicalDevicePlugin = new _SandyPluginDefinition(
androiKaiosPhysicalDevicePluginDetails,
DeviceTestPluginModule,
);
const androidEmulatorlDevicePluginDetails = TestUtils.createMockPluginDetails({
id: 'androidEmulatorDevicePlugin',
name: 'flipper-plugin-android-emulator-device',
version: '0.0.1',
pluginType: 'device',
supportedDevices: [
{
os: 'Android',
type: 'emulator',
},
],
});
const androidEmulatorDevicePlugin = new _SandyPluginDefinition(
androidEmulatorlDevicePluginDetails,
DeviceTestPluginModule,
);
test('ios physical device compatibility', () => {
const device = new BaseDevice('serial', 'physical', 'test device', 'iOS');
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
});
test('archived device compatibility', () => {
const device = new ArchivedDevice({
serial: 'serial',
deviceType: 'physical',
title: 'test device',
os: 'iOS',
screenshotHandle: null,
});
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeTruthy();
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
});
test('android emulator device compatibility', () => {
const device = new BaseDevice('serial', 'emulator', 'test device', 'Android');
expect(device.supportsPlugin(physicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeTruthy();
});
test('android KaiOS device compatibility', () => {
const device = new BaseDevice(
'serial',
'physical',
'test device',
'Android',
['KaiOS'],
);
expect(device.supportsPlugin(physicalDevicePlugin)).toBeTruthy();
expect(device.supportsPlugin(iosPhysicalDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(iosEmulatorDevicePlugin)).toBeFalsy();
expect(device.supportsPlugin(androidKaiosPhysicalDevicePlugin)).toBeTruthy();
expect(device.supportsPlugin(androidEmulatorDevicePlugin)).toBeFalsy();
});

View File

@@ -41,7 +41,6 @@ import {
registerInstalledPlugins, registerInstalledPlugins,
} from '../reducers/plugins'; } from '../reducers/plugins';
import {_SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
import type BaseDevice from '../devices/BaseDevice';
import {pluginStarred, pluginUnstarred} from '../reducers/connections'; import {pluginStarred, pluginUnstarred} from '../reducers/connections';
import {deconstructClientId} from '../utils/clientUtils'; import {deconstructClientId} from '../utils/clientUtils';
import {clearMessageQueue} from '../reducers/pluginMessageQueue'; import {clearMessageQueue} from '../reducers/pluginMessageQueue';
@@ -239,13 +238,13 @@ function updateClientPlugin(
function updateDevicePlugin(store: Store, plugin: DevicePluginDefinition) { function updateDevicePlugin(store: Store, plugin: DevicePluginDefinition) {
const devices = store.getState().connections.devices; const devices = store.getState().connections.devices;
const devicesWithEnabledPlugin = devices.filter((d) => const devicesWithEnabledPlugin = devices.filter((d) =>
supportsDevice(plugin, d), d.supportsPlugin(plugin),
); );
devicesWithEnabledPlugin.forEach((d) => { devicesWithEnabledPlugin.forEach((d) => {
d.unloadDevicePlugin(plugin.id); d.unloadDevicePlugin(plugin.id);
}); });
store.dispatch(clearPluginState({pluginId: plugin.id})); store.dispatch(clearPluginState({pluginId: plugin.id}));
const previousVersion = store.getState().plugins.clientPlugins.get(plugin.id); const previousVersion = store.getState().plugins.devicePlugins.get(plugin.id);
if (previousVersion) { if (previousVersion) {
// unload previous version from Electron cache // unload previous version from Electron cache
unloadPluginModule(previousVersion.details); unloadPluginModule(previousVersion.details);
@@ -305,14 +304,3 @@ export function isDevicePluginDefinition(
(definition instanceof _SandyPluginDefinition && definition.isDevicePlugin) (definition instanceof _SandyPluginDefinition && definition.isDevicePlugin)
); );
} }
function supportsDevice(plugin: DevicePluginDefinition, device: BaseDevice) {
if (plugin instanceof _SandyPluginDefinition) {
return (
plugin.isDevicePlugin &&
plugin.asDevicePluginModule().supportsDevice(device as any)
);
} else {
return plugin.supportsDevice(device);
}
}

View File

@@ -241,6 +241,7 @@ export class FlipperDevicePlugin<
this.teardown(); this.teardown();
} }
// TODO T84453692: remove this function after some transition period in favor of BaseDevice.supportsPlugin.
static supportsDevice(_device: BaseDevice): boolean { static supportsDevice(_device: BaseDevice): boolean {
throw new Error( throw new Error(
'supportsDevice is unimplemented in FlipperDevicePlugin class', 'supportsDevice is unimplemented in FlipperDevicePlugin class',

View File

@@ -13,6 +13,7 @@ import BaseDevice from '../../devices/BaseDevice';
import MacDevice from '../../devices/MacDevice'; import MacDevice from '../../devices/MacDevice';
import {FlipperDevicePlugin} from '../../plugin'; import {FlipperDevicePlugin} from '../../plugin';
import MetroDevice from '../../devices/MetroDevice'; import MetroDevice from '../../devices/MetroDevice';
import {TestUtils} from 'flipper-plugin';
test('doing a double REGISTER_DEVICE keeps the last', () => { test('doing a double REGISTER_DEVICE keeps the last', () => {
const device1 = new BaseDevice('serial', 'physical', 'title', 'Android'); const device1 = new BaseDevice('serial', 'physical', 'title', 'Android');
@@ -61,6 +62,10 @@ test('triggering REGISTER_DEVICE before REGISTER_PLUGINS still registers device
static supportsDevice() { static supportsDevice() {
return true; return true;
} }
static details = TestUtils.createMockPluginDetails({
id: 'test',
pluginType: 'device',
});
} }
const stateWithDevice = reducer(undefined, { const stateWithDevice = reducer(undefined, {

View File

@@ -71,7 +71,6 @@ test('it should initialize device sandy plugins', async () => {
expect(device.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf( expect(device.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf(
_SandyDevicePluginInstance, _SandyDevicePluginInstance,
); );
expect(TestPlugin.asDevicePluginModule().supportsDevice).toBeCalledTimes(1);
const instanceApi: PluginApi = device.sandyPluginStates.get(TestPlugin.id)! const instanceApi: PluginApi = device.sandyPluginStates.get(TestPlugin.id)!
.instanceApi; .instanceApi;

View File

@@ -88,12 +88,18 @@ describe('basic findBestDevice with metro present', () => {
beforeEach(async () => { beforeEach(async () => {
flipper = await createMockFlipperWithPlugin(logsPlugin); flipper = await createMockFlipperWithPlugin(logsPlugin);
flipper.device.supportsPlugin = (p) => {
return p.id !== 'unsupportedDevicePlugin';
};
testDevice = flipper.device; testDevice = flipper.device;
// flipper.store.dispatch(registerPlugins([LogsPlugin])) // flipper.store.dispatch(registerPlugins([LogsPlugin]))
await registerMetroDevice(undefined, flipper.store, flipper.logger); await registerMetroDevice(undefined, flipper.store, flipper.logger);
metro = findMetroDevice( metro = findMetroDevice(
flipper.store.getState().connections.devices, flipper.store.getState().connections.devices,
)! as MetroDevice; )! as MetroDevice;
metro.supportsPlugin = (p) => {
return p.id !== 'unsupportedDevicePlugin';
};
}); });
test('findMetroDevice', () => { test('findMetroDevice', () => {

View File

@@ -19,6 +19,7 @@ import {registerPlugins} from '../reducers/plugins';
import {getInstance} from '../fb-stubs/Logger'; import {getInstance} from '../fb-stubs/Logger';
import {initializeFlipperLibImplementation} from '../utils/flipperLibImplementation'; import {initializeFlipperLibImplementation} from '../utils/flipperLibImplementation';
import pluginManager from '../dispatcher/pluginManager'; import pluginManager from '../dispatcher/pluginManager';
import {PluginDetails} from 'flipper-plugin-lib';
export interface AppOptions { export interface AppOptions {
plugins?: PluginDefinition[]; plugins?: PluginDefinition[];
@@ -35,6 +36,7 @@ export interface ClientOptions {
export interface DeviceOptions { export interface DeviceOptions {
serial?: string; serial?: string;
isSupportedByPlugin?: (p: PluginDetails) => boolean;
} }
export default class MockFlipper { export default class MockFlipper {
@@ -105,13 +107,19 @@ export default class MockFlipper {
this.unsubscribePluginManager && this.unsubscribePluginManager(); this.unsubscribePluginManager && this.unsubscribePluginManager();
} }
public createDevice({serial}: DeviceOptions = {}): BaseDevice { public createDevice({
serial,
isSupportedByPlugin,
}: DeviceOptions = {}): BaseDevice {
const device = new BaseDevice( const device = new BaseDevice(
serial ?? `serial_${++this._deviceCounter}`, serial ?? `serial_${++this._deviceCounter}`,
'physical', 'physical',
'MockAndroidDevice', 'MockAndroidDevice',
'Android', 'Android',
); );
device.supportsPlugin = !isSupportedByPlugin
? () => true
: isSupportedByPlugin;
this._store.dispatch({ this._store.dispatch({
type: 'REGISTER_DEVICE', type: 'REGISTER_DEVICE',
payload: device, payload: device,

View File

@@ -1333,7 +1333,7 @@ test('Sandy plugins are imported properly', async () => {
}); });
const sandyDeviceTestPlugin = new _SandyPluginDefinition( const sandyDeviceTestPlugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails({pluginType: 'device'}),
{ {
supportsDevice: () => true, supportsDevice: () => true,
devicePlugin(client: DevicePluginClient) { devicePlugin(client: DevicePluginClient) {
@@ -1536,7 +1536,7 @@ test('Sandy plugin with custom import', async () => {
test('Sandy device plugin with custom import', async () => { test('Sandy device plugin with custom import', async () => {
const plugin = new _SandyPluginDefinition( const plugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails({pluginType: 'device'}),
{ {
supportsDevice: () => true, supportsDevice: () => true,
devicePlugin(client: DevicePluginClient) { devicePlugin(client: DevicePluginClient) {
@@ -1665,7 +1665,10 @@ test('Sandy plugins with complex data are imported / exported correctly', async
test('Sandy device plugins with complex data are imported / exported correctly', async () => { test('Sandy device plugins with complex data are imported / exported correctly', async () => {
const deviceplugin = new _SandyPluginDefinition( const deviceplugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails({id: 'deviceplugin'}), TestUtils.createMockPluginDetails({
id: 'deviceplugin',
pluginType: 'device',
}),
{ {
supportsDevice() { supportsDevice() {
return true; return true;

View File

@@ -27,7 +27,6 @@ import type {
PluginDetails, PluginDetails,
} from 'flipper-plugin-lib'; } from 'flipper-plugin-lib';
import {filterNewestVersionOfEachPlugin} from '../dispatcher/plugins'; import {filterNewestVersionOfEachPlugin} from '../dispatcher/plugins';
import ArchivedDevice from '../devices/ArchivedDevice';
export const defaultEnabledBackgroundPlugins = ['Navigation']; // The navigation plugin is enabled always, to make sure the navigation features works export const defaultEnabledBackgroundPlugins = ['Navigation']; // The navigation plugin is enabled always, to make sure the navigation features works
@@ -182,12 +181,12 @@ export function computePluginLists(
userStarredPlugins: State['connections']['userStarredPlugins'], userStarredPlugins: State['connections']['userStarredPlugins'],
_pluginsChanged?: number, // this argument is purely used to invalidate the memoization cache _pluginsChanged?: number, // this argument is purely used to invalidate the memoization cache
) { ) {
const devicePlugins: DevicePluginDefinition[] = const devicePlugins: DevicePluginDefinition[] = [
device?.devicePlugins.map((name) => plugins.devicePlugins.get(name)!) ?? []; ...plugins.devicePlugins.values(),
const metroPlugins: DevicePluginDefinition[] = ].filter((p) => device?.supportsPlugin(p));
metroDevice?.devicePlugins.map( const metroPlugins: DevicePluginDefinition[] = [
(name) => plugins.devicePlugins.get(name)!, ...plugins.devicePlugins.values(),
) ?? []; ].filter((p) => metroDevice?.supportsPlugin(p));
const enabledPlugins: ClientPluginDefinition[] = []; const enabledPlugins: ClientPluginDefinition[] = [];
const disabledPlugins: ClientPluginDefinition[] = []; const disabledPlugins: ClientPluginDefinition[] = [];
const unavailablePlugins: [plugin: PluginDetails, reason: string][] = []; const unavailablePlugins: [plugin: PluginDetails, reason: string][] = [];
@@ -198,16 +197,12 @@ export function computePluginLists(
if (device) { if (device) {
// find all device plugins that aren't part of the current device / metro // find all device plugins that aren't part of the current device / metro
const detectedDevicePlugins = new Set([ for (const p of plugins.devicePlugins.values()) {
...device.devicePlugins, if (!device.supportsPlugin(p) && !metroDevice?.supportsPlugin(p)) {
...(metroDevice?.devicePlugins ?? []),
]);
for (const [name, definition] of plugins.devicePlugins.entries()) {
if (!detectedDevicePlugins.has(name)) {
unavailablePlugins.push([ unavailablePlugins.push([
definition.details, p.details,
`Device plugin '${getPluginTitle( `Device plugin '${getPluginTitle(
definition.details, p.details,
)}' is not supported by the current device type.`, )}' is not supported by the current device type.`,
]); ]);
} }

View File

@@ -16,7 +16,7 @@ import {DevicePluginPredicate, DevicePluginFactory} from './DevicePlugin';
*/ */
export type FlipperDevicePluginModule = { export type FlipperDevicePluginModule = {
/** predicate that determines if this plugin applies to the currently selcted device */ /** predicate that determines if this plugin applies to the currently selcted device */
supportsDevice: DevicePluginPredicate; supportsDevice: DevicePluginPredicate; // TODO T84453692: remove this function after some transition period in favor of BaseDevice.supportsPlugin.
/** the factory function that initializes a plugin instance */ /** the factory function that initializes a plugin instance */
devicePlugin: DevicePluginFactory; devicePlugin: DevicePluginFactory;
/** the component type that can render this plugin */ /** the component type that can render this plugin */
@@ -52,7 +52,7 @@ export class SandyPluginDefinition {
constructor(details: ActivatablePluginDetails, module: any) { constructor(details: ActivatablePluginDetails, module: any) {
this.id = details.id; this.id = details.id;
this.details = details; this.details = details;
if (module.supportsDevice) { if (details.pluginType === 'device' || module.supportsDevice) {
// device plugin // device plugin
this.isDevicePlugin = true; this.isDevicePlugin = true;
if (!module.devicePlugin || typeof module.devicePlugin !== 'function') { if (!module.devicePlugin || typeof module.devicePlugin !== 'function') {

View File

@@ -297,7 +297,7 @@ export function startDevicePlugin<Module extends FlipperDevicePluginModule>(
options?: StartPluginOptions, options?: StartPluginOptions,
): StartDevicePluginResult<Module> { ): StartDevicePluginResult<Module> {
const definition = new SandyPluginDefinition( const definition = new SandyPluginDefinition(
createMockPluginDetails(), createMockPluginDetails({pluginType: 'device'}),
module, module,
); );
if (!definition.isDevicePlugin) { if (!definition.isDevicePlugin) {
@@ -402,7 +402,6 @@ export function createMockPluginDetails(
dir: '', dir: '',
name: 'TestPlugin', name: 'TestPlugin',
specVersion: 0, specVersion: 0,
pluginType: 'client',
entry: '', entry: '',
isBundled: false, isBundled: false,
isActivatable: true, isActivatable: true,

View File

@@ -27,7 +27,7 @@ export interface PluginDetails {
url?: string; url?: string;
}; };
flipperSDKVersion?: string; flipperSDKVersion?: string;
pluginType: PluginType; pluginType?: PluginType;
supportedDevices?: SupportedDevice[]; supportedDevices?: SupportedDevice[];
} }

View File

@@ -49,7 +49,7 @@ test('getPluginDetailsV1', async () => {
"isBundled": false, "isBundled": false,
"main": "dist/bundle.js", "main": "dist/bundle.js",
"name": "flipper-plugin-test", "name": "flipper-plugin-test",
"pluginType": "client", "pluginType": undefined,
"source": "src/index.tsx", "source": "src/index.tsx",
"specVersion": 1, "specVersion": 1,
"supportedDevices": undefined, "supportedDevices": undefined,
@@ -90,7 +90,7 @@ test('getPluginDetailsV2', async () => {
"isBundled": false, "isBundled": false,
"main": "dist/bundle.js", "main": "dist/bundle.js",
"name": "flipper-plugin-test", "name": "flipper-plugin-test",
"pluginType": "client", "pluginType": undefined,
"source": "src/index.tsx", "source": "src/index.tsx",
"specVersion": 2, "specVersion": 2,
"supportedDevices": undefined, "supportedDevices": undefined,
@@ -131,7 +131,7 @@ test('id used as title if the latter omited', async () => {
"isBundled": false, "isBundled": false,
"main": "dist/bundle.js", "main": "dist/bundle.js",
"name": "flipper-plugin-test", "name": "flipper-plugin-test",
"pluginType": "client", "pluginType": undefined,
"source": "src/index.tsx", "source": "src/index.tsx",
"specVersion": 2, "specVersion": 2,
"supportedDevices": undefined, "supportedDevices": undefined,
@@ -171,7 +171,7 @@ test('name without "flipper-plugin-" prefix is used as title if the latter omite
"isBundled": false, "isBundled": false,
"main": "dist/bundle.js", "main": "dist/bundle.js",
"name": "flipper-plugin-test", "name": "flipper-plugin-test",
"pluginType": "client", "pluginType": undefined,
"source": "src/index.tsx", "source": "src/index.tsx",
"specVersion": 2, "specVersion": 2,
"supportedDevices": undefined, "supportedDevices": undefined,
@@ -214,7 +214,7 @@ test('flipper-plugin-version is parsed', async () => {
"isBundled": false, "isBundled": false,
"main": "dist/bundle.js", "main": "dist/bundle.js",
"name": "flipper-plugin-test", "name": "flipper-plugin-test",
"pluginType": "client", "pluginType": undefined,
"source": "src/index.tsx", "source": "src/index.tsx",
"specVersion": 2, "specVersion": 2,
"supportedDevices": undefined, "supportedDevices": undefined,

View File

@@ -87,7 +87,7 @@ function getPluginDetailsV1(packageJson: any): PluginDetails {
category: packageJson.category, category: packageJson.category,
bugs: packageJson.bugs, bugs: packageJson.bugs,
flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'],
pluginType: packageJson?.pluginType || 'client', pluginType: packageJson?.pluginType,
supportedDevices: packageJson?.supportedDevices, supportedDevices: packageJson?.supportedDevices,
}; };
} }
@@ -109,7 +109,7 @@ function getPluginDetailsV2(packageJson: any): PluginDetails {
category: packageJson.category, category: packageJson.category,
bugs: packageJson.bugs, bugs: packageJson.bugs,
flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'],
pluginType: packageJson?.pluginType || 'client', pluginType: packageJson?.pluginType,
supportedDevices: packageJson?.supportedDevices, supportedDevices: packageJson?.supportedDevices,
}; };
} }