Make sure that limited top-level exports are exposed from flipper-plugin

Summary: This prefixes APIs of `flipper-plugin`, that are used by Flipper, but should not be used by plugins directly, with `_`. Also added tests to make sure we are always intentional when extending the exposed APIs

Reviewed By: passy

Differential Revision: D24991700

fbshipit-source-id: ed3700efa188fca7f5a14d5c68250598cf011e42
This commit is contained in:
Michel Weststrate
2020-11-16 13:08:05 -08:00
committed by Facebook GitHub Bot
parent cc438e60ad
commit 45db64f0d0
21 changed files with 156 additions and 90 deletions

View File

@@ -36,7 +36,7 @@ import {processMessagesLater} from './utils/messageQueue';
import {emitBytesReceived} from './dispatcher/tracking'; import {emitBytesReceived} from './dispatcher/tracking';
import {debounce} from 'lodash'; import {debounce} from 'lodash';
import {batch} from 'react-redux'; import {batch} from 'react-redux';
import {SandyPluginInstance} from 'flipper-plugin'; import {_SandyPluginInstance} from 'flipper-plugin';
import {flipperMessagesClientPlugin} from './utils/self-inspection/plugins/FlipperMessagesClientPlugin'; import {flipperMessagesClientPlugin} from './utils/self-inspection/plugins/FlipperMessagesClientPlugin';
import {getFlipperLibImplementation} from './utils/flipperLibImplementation'; import {getFlipperLibImplementation} from './utils/flipperLibImplementation';
@@ -148,11 +148,11 @@ export default class Client extends EventEmitter {
plugin: plugin:
| typeof FlipperPlugin | typeof FlipperPlugin
| typeof FlipperDevicePlugin | typeof FlipperDevicePlugin
| SandyPluginInstance; | _SandyPluginInstance;
messages: Params[]; messages: Params[];
} }
> = {}; > = {};
sandyPluginStates = new Map<string /*pluginID*/, SandyPluginInstance>(); sandyPluginStates = new Map<string /*pluginID*/, _SandyPluginInstance>();
requestCallbacks: Map< requestCallbacks: Map<
number, number,
@@ -251,7 +251,7 @@ export default class Client extends EventEmitter {
// TODO: needs to be wrapped in error tracking T68955280 // TODO: needs to be wrapped in error tracking T68955280
this.sandyPluginStates.set( this.sandyPluginStates.set(
plugin.id, plugin.id,
new SandyPluginInstance( new _SandyPluginInstance(
getFlipperLibImplementation(), getFlipperLibImplementation(),
plugin, plugin,
this, this,
@@ -301,7 +301,7 @@ export default class Client extends EventEmitter {
// TODO: needs to be wrapped in error tracking T68955280 // TODO: needs to be wrapped in error tracking T68955280
this.sandyPluginStates.set( this.sandyPluginStates.set(
plugin.id, plugin.id,
new SandyPluginInstance(getFlipperLibImplementation(), plugin, this), new _SandyPluginInstance(getFlipperLibImplementation(), plugin, this),
); );
} }
} }

View File

@@ -26,11 +26,11 @@ import electron, {MenuItemConstructorOptions} from 'electron';
import {notNull} from './utils/typeUtils'; import {notNull} from './utils/typeUtils';
import constants from './fb-stubs/constants'; import constants from './fb-stubs/constants';
import {Logger} from './fb-interfaces/Logger'; import {Logger} from './fb-interfaces/Logger';
import {NormalizedMenuEntry, buildInMenuEntries} from 'flipper-plugin'; import {NormalizedMenuEntry, _buildInMenuEntries} from 'flipper-plugin';
import {StyleGuide} from './sandy-chrome/StyleGuide'; import {StyleGuide} from './sandy-chrome/StyleGuide';
import {showEmulatorLauncher} from './sandy-chrome/appinspect/LaunchEmulator'; import {showEmulatorLauncher} from './sandy-chrome/appinspect/LaunchEmulator';
export type DefaultKeyboardAction = keyof typeof buildInMenuEntries; export type DefaultKeyboardAction = keyof typeof _buildInMenuEntries;
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help'; export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
export type KeyboardAction = { export type KeyboardAction = {
@@ -70,7 +70,7 @@ export function setupMenuBar(
.map((plugin) => plugin.keyboardActions || []) .map((plugin) => plugin.keyboardActions || [])
.flat() .flat()
.map((action: DefaultKeyboardAction | KeyboardAction) => .map((action: DefaultKeyboardAction | KeyboardAction) =>
typeof action === 'string' ? buildInMenuEntries[action] : action, typeof action === 'string' ? _buildInMenuEntries[action] : action,
) )
.filter(notNull), .filter(notNull),
); );

View File

@@ -46,7 +46,7 @@ import {Message} from './reducers/pluginMessageQueue';
import {Idler} from './utils/Idler'; import {Idler} from './utils/Idler';
import {processMessageQueue} from './utils/messageQueue'; import {processMessageQueue} from './utils/messageQueue';
import {ToggleButton, SmallText, Layout} from './ui'; import {ToggleButton, SmallText, Layout} from './ui';
import {SandyPluginRenderer} from 'flipper-plugin'; import {_SandyPluginRenderer} from 'flipper-plugin';
import {isDevicePluginDefinition} from './utils/pluginUtils'; import {isDevicePluginDefinition} from './utils/pluginUtils';
import ArchivedDevice from './devices/ArchivedDevice'; import ArchivedDevice from './devices/ArchivedDevice';
import {ContentContainer} from './sandy-chrome/ContentContainer'; import {ContentContainer} from './sandy-chrome/ContentContainer';
@@ -377,7 +377,9 @@ class PluginContainer extends PureComponent<Props, State> {
// happens if we selected a plugin that is not enabled on a specific app or not supported on a specific device. // happens if we selected a plugin that is not enabled on a specific app or not supported on a specific device.
return this.renderNoPluginActive(); return this.renderNoPluginActive();
} }
pluginElement = <SandyPluginRenderer key={pluginKey} plugin={instance} />; pluginElement = (
<_SandyPluginRenderer key={pluginKey} plugin={instance} />
);
} else { } else {
const props: PluginProps<Object> & { const props: PluginProps<Object> & {
key: string; key: string;

View File

@@ -12,7 +12,7 @@ import produce from 'immer';
import {FlipperPlugin} from '../plugin'; import {FlipperPlugin} from '../plugin';
import {renderMockFlipperWithPlugin} from '../test-utils/createMockFlipperWithPlugin'; import {renderMockFlipperWithPlugin} from '../test-utils/createMockFlipperWithPlugin';
import { import {
SandyPluginDefinition, _SandyPluginDefinition,
PluginClient, PluginClient,
TestUtils, TestUtils,
usePlugin, usePlugin,
@@ -141,7 +141,7 @@ test('PluginContainer can render Sandy plugins', async () => {
}; };
}; };
const definition = new SandyPluginDefinition( const definition = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
plugin, plugin,
@@ -339,7 +339,7 @@ test('PluginContainer triggers correct lifecycles for background plugin', async
return {connectedStub, disconnectedStub, activatedStub, deactivatedStub}; return {connectedStub, disconnectedStub, activatedStub, deactivatedStub};
}; };
const definition = new SandyPluginDefinition( const definition = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
plugin, plugin,
@@ -480,7 +480,7 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => {
}; };
}; };
const definition = new SandyPluginDefinition( const definition = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
plugin, plugin,
@@ -636,7 +636,7 @@ test('PluginContainer can render Sandy device plugins', async () => {
return {activatedStub, deactivatedStub, lastLogMessage}; return {activatedStub, deactivatedStub, lastLogMessage};
}; };
const definition = new SandyPluginDefinition( const definition = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
supportsDevice: () => true, supportsDevice: () => true,
@@ -750,7 +750,7 @@ test('PluginContainer + Sandy device plugin supports deeplink', async () => {
}; };
}; };
const definition = new SandyPluginDefinition( const definition = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
devicePlugin, devicePlugin,

View File

@@ -28,7 +28,7 @@ import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel';
import SandySettingsPanel from '../fb-stubs/SandySettingsPanel'; import SandySettingsPanel from '../fb-stubs/SandySettingsPanel';
import {reportUsage} from '../utils/metrics'; import {reportUsage} from '../utils/metrics';
import {Modal} from 'antd'; import {Modal} from 'antd';
import {Layout, NuxManagerContext} from 'flipper-plugin'; import {Layout, _NuxManagerContext} from 'flipper-plugin';
const Container = styled(FlexColumn)({ const Container = styled(FlexColumn)({
padding: 20, padding: 20,
@@ -358,7 +358,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
)(SettingsSheet); )(SettingsSheet);
function ResetTooltips() { function ResetTooltips() {
const nuxManager = useContext(NuxManagerContext); const nuxManager = useContext(_NuxManagerContext);
return ( return (
<Button <Button

View File

@@ -10,8 +10,8 @@
import stream from 'stream'; import stream from 'stream';
import { import {
DeviceLogEntry, DeviceLogEntry,
SandyDevicePluginInstance, _SandyDevicePluginInstance,
SandyPluginDefinition, _SandyPluginDefinition,
DeviceType, DeviceType,
DeviceLogListener, DeviceLogListener,
} from 'flipper-plugin'; } from 'flipper-plugin';
@@ -66,9 +66,9 @@ export default class BaseDevice {
// sorted list of supported device plugins // sorted list of supported device plugins
devicePlugins: string[] = []; devicePlugins: string[] = [];
sandyPluginStates: Map<string, SandyDevicePluginInstance> = new Map< sandyPluginStates: Map<string, _SandyDevicePluginInstance> = new Map<
string, string,
SandyDevicePluginInstance _SandyDevicePluginInstance
>(); >();
supportsOS(os: OS) { supportsOS(os: OS) {
@@ -175,12 +175,12 @@ export default class BaseDevice {
} }
loadDevicePlugin(plugin: DevicePluginDefinition) { loadDevicePlugin(plugin: DevicePluginDefinition) {
if (plugin instanceof SandyPluginDefinition) { if (plugin instanceof _SandyPluginDefinition) {
if (plugin.asDevicePluginModule().supportsDevice(this as any)) { if (plugin.asDevicePluginModule().supportsDevice(this as any)) {
this.devicePlugins.push(plugin.id); this.devicePlugins.push(plugin.id);
this.sandyPluginStates.set( this.sandyPluginStates.set(
plugin.id, plugin.id,
new SandyDevicePluginInstance( new _SandyDevicePluginInstance(
getFlipperLibImplementation(), getFlipperLibImplementation(),
plugin, plugin,
this, this,

View File

@@ -26,7 +26,7 @@ import configureStore from 'redux-mock-store';
import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK'; import {TEST_PASSING_GK, TEST_FAILING_GK} from '../../fb-stubs/GK';
import TestPlugin from './TestPlugin'; import TestPlugin from './TestPlugin';
import {resetConfigForTesting} from '../../utils/processConfig'; import {resetConfigForTesting} from '../../utils/processConfig';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
import {mocked} from 'ts-jest/utils'; import {mocked} from 'ts-jest/utils';
import loadDynamicPlugins from '../../utils/loadDynamicPlugins'; import loadDynamicPlugins from '../../utils/loadDynamicPlugins';
@@ -246,9 +246,9 @@ test('requirePlugin loads valid Sandy plugin', () => {
), ),
version: '1.0.0', version: '1.0.0',
flipperSDKVersion: '0.0.0', flipperSDKVersion: '0.0.0',
}) as SandyPluginDefinition; }) as _SandyPluginDefinition;
expect(plugin).not.toBeNull(); expect(plugin).not.toBeNull();
expect(plugin).toBeInstanceOf(SandyPluginDefinition); expect(plugin).toBeInstanceOf(_SandyPluginDefinition);
expect(plugin.id).toBe('Sample'); expect(plugin.id).toBe('Sample');
expect(plugin.details).toMatchObject({ expect(plugin.details).toMatchObject({
flipperSDKVersion: '0.0.0', flipperSDKVersion: '0.0.0',
@@ -296,9 +296,9 @@ test('requirePlugin loads valid Sandy Device plugin', () => {
), ),
version: '1.0.0', version: '1.0.0',
flipperSDKVersion: '0.0.0', flipperSDKVersion: '0.0.0',
}) as SandyPluginDefinition; }) as _SandyPluginDefinition;
expect(plugin).not.toBeNull(); expect(plugin).not.toBeNull();
expect(plugin).toBeInstanceOf(SandyPluginDefinition); expect(plugin).toBeInstanceOf(_SandyPluginDefinition);
expect(plugin.id).toBe('Sample'); expect(plugin.id).toBe('Sample');
expect(plugin.details).toMatchObject({ expect(plugin.details).toMatchObject({
flipperSDKVersion: '0.0.0', flipperSDKVersion: '0.0.0',

View File

@@ -32,7 +32,7 @@ import semver from 'semver';
import {PluginDetails} from 'flipper-plugin-lib'; import {PluginDetails} from 'flipper-plugin-lib';
import {tryCatchReportPluginFailures, reportUsage} from '../utils/metrics'; import {tryCatchReportPluginFailures, reportUsage} from '../utils/metrics';
import * as FlipperPluginSDK from 'flipper-plugin'; import * as FlipperPluginSDK from 'flipper-plugin';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
import loadDynamicPlugins from '../utils/loadDynamicPlugins'; import loadDynamicPlugins from '../utils/loadDynamicPlugins';
import Immer from 'immer'; import Immer from 'immer';
@@ -223,7 +223,7 @@ const requirePluginInternal = (
: reqFn(pluginDetails.entry); : reqFn(pluginDetails.entry);
if (pluginDetails.flipperSDKVersion) { if (pluginDetails.flipperSDKVersion) {
// Sandy plugin // Sandy plugin
return new SandyPluginDefinition(pluginDetails, plugin); return new _SandyPluginDefinition(pluginDetails, plugin);
} else { } else {
// classic plugin // classic plugin
if (plugin.default) { if (plugin.default) {

View File

@@ -34,7 +34,7 @@ import {PopoverProvider} from './ui/components/PopoverProvider';
import {initializeFlipperLibImplementation} from './utils/flipperLibImplementation'; import {initializeFlipperLibImplementation} from './utils/flipperLibImplementation';
import {enableConsoleHook} from './chrome/ConsoleLogs'; import {enableConsoleHook} from './chrome/ConsoleLogs';
import {sideEffect} from './utils/sideEffect'; import {sideEffect} from './utils/sideEffect';
import {NuxManagerContext, createNuxManager} from 'flipper-plugin'; import {_NuxManagerContext, _createNuxManager} from 'flipper-plugin';
if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') { if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
// By default Node.JS has its internal certificate storage and doesn't use // By default Node.JS has its internal certificate storage and doesn't use
@@ -57,9 +57,9 @@ const AppFrame = () => (
<TooltipProvider> <TooltipProvider>
<PopoverProvider> <PopoverProvider>
<ContextMenuProvider> <ContextMenuProvider>
<NuxManagerContext.Provider value={createNuxManager()}> <_NuxManagerContext.Provider value={_createNuxManager()}>
<App logger={logger} /> <App logger={logger} />
</NuxManagerContext.Provider> </_NuxManagerContext.Provider>
</ContextMenuProvider> </ContextMenuProvider>
</PopoverProvider> </PopoverProvider>
</TooltipProvider> </TooltipProvider>

View File

@@ -21,7 +21,7 @@ import {State as ReduxState} from './reducers';
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue'; import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';
import {PluginDetails} from 'flipper-plugin-lib'; import {PluginDetails} from 'flipper-plugin-lib';
import {Settings} from './reducers/settings'; import {Settings} from './reducers/settings';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
type Parameters = {[key: string]: any}; type Parameters = {[key: string]: any};
@@ -29,19 +29,19 @@ export type PluginDefinition = ClientPluginDefinition | DevicePluginDefinition;
export type DevicePluginDefinition = export type DevicePluginDefinition =
| typeof FlipperDevicePlugin | typeof FlipperDevicePlugin
| SandyPluginDefinition; | _SandyPluginDefinition;
export type ClientPluginDefinition = export type ClientPluginDefinition =
| typeof FlipperPlugin | typeof FlipperPlugin
| SandyPluginDefinition; | _SandyPluginDefinition;
export type ClientPluginMap = Map<string, ClientPluginDefinition>; export type ClientPluginMap = Map<string, ClientPluginDefinition>;
export type DevicePluginMap = Map<string, DevicePluginDefinition>; export type DevicePluginMap = Map<string, DevicePluginDefinition>;
export function isSandyPlugin( export function isSandyPlugin(
plugin?: PluginDefinition | null, plugin?: PluginDefinition | null,
): plugin is SandyPluginDefinition { ): plugin is _SandyPluginDefinition {
return plugin instanceof SandyPluginDefinition; return plugin instanceof _SandyPluginDefinition;
} }
// This function is intended to be called from outside of the plugin. // This function is intended to be called from outside of the plugin.

View File

@@ -11,8 +11,8 @@ import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWit
import {Store} from '../../'; import {Store} from '../../';
import {selectPlugin} from '../../reducers/connections'; import {selectPlugin} from '../../reducers/connections';
import { import {
SandyPluginDefinition, _SandyPluginDefinition,
SandyDevicePluginInstance, _SandyDevicePluginInstance,
DevicePluginClient, DevicePluginClient,
TestUtils, TestUtils,
} from 'flipper-plugin'; } from 'flipper-plugin';
@@ -42,7 +42,7 @@ function devicePlugin(client: DevicePluginClient) {
destroyStub, destroyStub,
}; };
} }
const TestPlugin = new SandyPluginDefinition(pluginDetails, { const TestPlugin = new _SandyPluginDefinition(pluginDetails, {
supportsDevice: jest.fn().mockImplementation(() => true), supportsDevice: jest.fn().mockImplementation(() => true),
devicePlugin: jest devicePlugin: jest
.fn() .fn()
@@ -69,7 +69,7 @@ test('it should initialize device sandy plugins', async () => {
// already started, so initialized immediately // already started, so initialized immediately
expect(initialized).toBe(true); expect(initialized).toBe(true);
expect(device.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf( expect(device.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf(
SandyDevicePluginInstance, _SandyDevicePluginInstance,
); );
expect(TestPlugin.asDevicePluginModule().supportsDevice).toBeCalledTimes(1); expect(TestPlugin.asDevicePluginModule().supportsDevice).toBeCalledTimes(1);
const instanceApi: PluginApi = device.sandyPluginStates.get(TestPlugin.id)! const instanceApi: PluginApi = device.sandyPluginStates.get(TestPlugin.id)!

View File

@@ -12,8 +12,8 @@ import {Store, Client} from '../../';
import {selectPlugin, starPlugin} from '../../reducers/connections'; import {selectPlugin, starPlugin} from '../../reducers/connections';
import {registerPlugins} from '../../reducers/plugins'; import {registerPlugins} from '../../reducers/plugins';
import { import {
SandyPluginDefinition, _SandyPluginDefinition,
SandyPluginInstance, _SandyPluginInstance,
PluginClient, PluginClient,
TestUtils, TestUtils,
} from 'flipper-plugin'; } from 'flipper-plugin';
@@ -49,7 +49,7 @@ function plugin(client: PluginClient<any, any>) {
messages, messages,
}; };
} }
const TestPlugin = new SandyPluginDefinition(pluginDetails, { const TestPlugin = new _SandyPluginDefinition(pluginDetails, {
plugin: jest.fn().mockImplementation(plugin) as typeof plugin, plugin: jest.fn().mockImplementation(plugin) as typeof plugin,
Component: jest.fn().mockImplementation(() => null), Component: jest.fn().mockImplementation(() => null),
}); });
@@ -82,7 +82,7 @@ test('it should initialize starred sandy plugins', async () => {
// already started, so initialized immediately // already started, so initialized immediately
expect(initialized).toBe(true); expect(initialized).toBe(true);
expect(client.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf( expect(client.sandyPluginStates.get(TestPlugin.id)).toBeInstanceOf(
SandyPluginInstance, _SandyPluginInstance,
); );
const instanceApi: PluginApi = client.sandyPluginStates.get(TestPlugin.id)! const instanceApi: PluginApi = client.sandyPluginStates.get(TestPlugin.id)!
.instanceApi; .instanceApi;
@@ -132,7 +132,7 @@ test('it should cleanup if client is removed', async () => {
test('it should not initialize a sandy plugin if not enabled', async () => { test('it should not initialize a sandy plugin if not enabled', async () => {
const {client, store} = await createMockFlipperWithPlugin(TestPlugin); const {client, store} = await createMockFlipperWithPlugin(TestPlugin);
const Plugin2 = new SandyPluginDefinition( const Plugin2 = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails({ TestUtils.createMockPluginDetails({
name: 'Plugin2', name: 'Plugin2',
id: 'Plugin2', id: 'Plugin2',
@@ -146,7 +146,7 @@ test('it should not initialize a sandy plugin if not enabled', async () => {
); );
const pluginState1 = client.sandyPluginStates.get(TestPlugin.id); const pluginState1 = client.sandyPluginStates.get(TestPlugin.id);
expect(pluginState1).toBeInstanceOf(SandyPluginInstance); expect(pluginState1).toBeInstanceOf(_SandyPluginInstance);
store.dispatch(registerPlugins([Plugin2])); store.dispatch(registerPlugins([Plugin2]));
await client.refreshPlugins(); await client.refreshPlugins();
// not yet enabled, so not yet started // not yet enabled, so not yet started
@@ -161,7 +161,7 @@ test('it should not initialize a sandy plugin if not enabled', async () => {
); );
expect(client.sandyPluginStates.get(Plugin2.id)).toBeInstanceOf( expect(client.sandyPluginStates.get(Plugin2.id)).toBeInstanceOf(
SandyPluginInstance, _SandyPluginInstance,
); );
const instance = client.sandyPluginStates.get(Plugin2.id)! const instance = client.sandyPluginStates.get(Plugin2.id)!
.instanceApi as PluginApi; .instanceApi as PluginApi;
@@ -238,7 +238,7 @@ test('it can send messages from sandy clients', async () => {
test('it should initialize "Navigation" plugin if not enabled', async () => { test('it should initialize "Navigation" plugin if not enabled', async () => {
const {client, store} = await createMockFlipperWithPlugin(TestPlugin); const {client, store} = await createMockFlipperWithPlugin(TestPlugin);
const Plugin2 = new SandyPluginDefinition( const Plugin2 = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails({ TestUtils.createMockPluginDetails({
name: 'Plugin2', name: 'Plugin2',
id: 'Navigation', id: 'Navigation',
@@ -252,7 +252,7 @@ test('it should initialize "Navigation" plugin if not enabled', async () => {
); );
const pluginState1 = client.sandyPluginStates.get(TestPlugin.id); const pluginState1 = client.sandyPluginStates.get(TestPlugin.id);
expect(pluginState1).toBeInstanceOf(SandyPluginInstance); expect(pluginState1).toBeInstanceOf(_SandyPluginInstance);
store.dispatch(registerPlugins([Plugin2])); store.dispatch(registerPlugins([Plugin2]));
await client.refreshPlugins(); await client.refreshPlugins();
// not enabled, but Navigation is an exception, so we still get an instance // not enabled, but Navigation is an exception, so we still get an instance

View File

@@ -16,7 +16,7 @@ import {findBestClient, findBestDevice, findMetroDevice} from '../AppInspect';
import {FlipperPlugin} from '../../../plugin'; import {FlipperPlugin} from '../../../plugin';
import MetroDevice from '../../../devices/MetroDevice'; import MetroDevice from '../../../devices/MetroDevice';
import BaseDevice from '../../../devices/BaseDevice'; import BaseDevice from '../../../devices/BaseDevice';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
import {createMockPluginDetails} from 'flipper-plugin/src/test-utils/test-utils'; import {createMockPluginDetails} from 'flipper-plugin/src/test-utils/test-utils';
import {selectPlugin, starPlugin} from '../../../reducers/connections'; import {selectPlugin, starPlugin} from '../../../reducers/connections';
import {registerMetroDevice} from '../../../dispatcher/metroDevice'; import {registerMetroDevice} from '../../../dispatcher/metroDevice';
@@ -25,7 +25,7 @@ import {addGatekeepedPlugins, registerPlugins} from '../../../reducers/plugins';
// eslint-disable-next-line // eslint-disable-next-line
import * as LogsPluginModule from '../../../../../plugins/logs/index'; import * as LogsPluginModule from '../../../../../plugins/logs/index';
const logsPlugin = new SandyPluginDefinition( const logsPlugin = new _SandyPluginDefinition(
createMockPluginDetails({id: 'DeviceLogs'}), createMockPluginDetails({id: 'DeviceLogs'}),
LogsPluginModule, LogsPluginModule,
); );
@@ -179,7 +179,7 @@ describe('basic findBestDevice with metro present', () => {
}, },
}; };
const unsupportedDevicePlugin = new SandyPluginDefinition( const unsupportedDevicePlugin = new _SandyPluginDefinition(
createMockPluginDetails({ createMockPluginDetails({
id: 'unsupportedDevicePlugin', id: 'unsupportedDevicePlugin',
title: 'Unsupported Device Plugin', title: 'Unsupported Device Plugin',
@@ -197,7 +197,7 @@ describe('basic findBestDevice with metro present', () => {
}, },
); );
const unsupportedPlugin = new SandyPluginDefinition( const unsupportedPlugin = new _SandyPluginDefinition(
createMockPluginDetails({ createMockPluginDetails({
id: 'unsupportedPlugin', id: 'unsupportedPlugin',
title: 'Unsupported Plugin', title: 'Unsupported Plugin',
@@ -211,7 +211,7 @@ describe('basic findBestDevice with metro present', () => {
gatekeeper: 'not for you', gatekeeper: 'not for you',
}); });
const plugin1 = new SandyPluginDefinition( const plugin1 = new _SandyPluginDefinition(
createMockPluginDetails({ createMockPluginDetails({
id: 'plugin1', id: 'plugin1',
title: 'Plugin 1', title: 'Plugin 1',
@@ -224,7 +224,7 @@ describe('basic findBestDevice with metro present', () => {
}, },
); );
const plugin2 = new SandyPluginDefinition( const plugin2 = new _SandyPluginDefinition(
createMockPluginDetails({ createMockPluginDetails({
id: 'plugin2', id: 'plugin2',
title: 'Plugin 2', title: 'Plugin 2',

View File

@@ -24,7 +24,7 @@ import {
PluginDefinition, PluginDefinition,
} from './plugin'; } from './plugin';
import {deconstructPluginKey} from './utils/clientUtils'; import {deconstructPluginKey} from './utils/clientUtils';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
import BaseDevice from './devices/BaseDevice'; import BaseDevice from './devices/BaseDevice';
import {State as PluginStates} from './reducers/pluginStates'; import {State as PluginStates} from './reducers/pluginStates';
@@ -171,7 +171,7 @@ function updateDevicePlugin(state: StoreState, plugin: DevicePluginDefinition) {
} }
function supportsDevice(plugin: DevicePluginDefinition, device: BaseDevice) { function supportsDevice(plugin: DevicePluginDefinition, device: BaseDevice) {
if (plugin instanceof SandyPluginDefinition) { if (plugin instanceof _SandyPluginDefinition) {
return ( return (
plugin.isDevicePlugin && plugin.isDevicePlugin &&
plugin.asDevicePluginModule().supportsDevice(device as any) plugin.asDevicePluginModule().supportsDevice(device as any)

View File

@@ -24,7 +24,7 @@ import {State as PluginsState} from '../../reducers/plugins';
import {renderMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin'; import {renderMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
import { import {
TestUtils, TestUtils,
SandyPluginDefinition, _SandyPluginDefinition,
createState, createState,
PluginClient, PluginClient,
} from 'flipper-plugin'; } from 'flipper-plugin';
@@ -1052,7 +1052,7 @@ test('test determinePluginsToProcess to ignore archived clients', async () => {
]); ]);
}); });
const sandyTestPlugin = new SandyPluginDefinition( const sandyTestPlugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
plugin( plugin(

View File

@@ -21,10 +21,10 @@ import {getPluginKey} from '../pluginUtils';
import {TestIdler} from '../Idler'; import {TestIdler} from '../Idler';
import {registerPlugins} from '../../reducers/plugins'; import {registerPlugins} from '../../reducers/plugins';
import { import {
SandyPluginDefinition, _SandyPluginDefinition,
TestUtils, TestUtils,
PluginClient, PluginClient,
SandyPluginInstance, _SandyPluginInstance,
} from 'flipper-plugin'; } from 'flipper-plugin';
type Events = { type Events = {
@@ -47,7 +47,7 @@ function plugin(client: PluginClient<Events, {}>) {
}; };
} }
const TestPlugin = new SandyPluginDefinition( const TestPlugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails(), TestUtils.createMockPluginDetails(),
{ {
plugin, plugin,
@@ -211,7 +211,7 @@ test('queue - events are NOT processed immediately if plugin is NOT selected (bu
}); });
test('queue - events ARE processed immediately if plugin is NOT selected / enabled BUT NAVIGATION', async () => { test('queue - events ARE processed immediately if plugin is NOT selected / enabled BUT NAVIGATION', async () => {
const NavigationPlugin = new SandyPluginDefinition( const NavigationPlugin = new _SandyPluginDefinition(
TestUtils.createMockPluginDetails({ TestUtils.createMockPluginDetails({
id: 'Navigation', id: 'Navigation',
}), }),
@@ -599,7 +599,7 @@ test('client - incoming messages are buffered and flushed together', async () =>
} }
`); `);
expect(client.messageBuffer[pluginKey].plugin).toBeInstanceOf( expect(client.messageBuffer[pluginKey].plugin).toBeInstanceOf(
SandyPluginInstance, _SandyPluginInstance,
); );
await sleep(500); await sleep(500);

View File

@@ -24,7 +24,7 @@ import {Idler, BaseIdler} from './Idler';
import {pluginIsStarred, getSelectedPluginKey} from '../reducers/connections'; import {pluginIsStarred, getSelectedPluginKey} from '../reducers/connections';
import {deconstructPluginKey} from './clientUtils'; import {deconstructPluginKey} from './clientUtils';
import {defaultEnabledBackgroundPlugins} from './pluginUtils'; import {defaultEnabledBackgroundPlugins} from './pluginUtils';
import {SandyPluginInstance} from 'flipper-plugin'; import {_SandyPluginInstance} from 'flipper-plugin';
import {addBackgroundStat} from './pluginStats'; import {addBackgroundStat} from './pluginStats';
function processMessageClassic( function processMessageClassic(
@@ -54,7 +54,7 @@ function processMessageClassic(
function processMessagesSandy( function processMessagesSandy(
pluginKey: string, pluginKey: string,
plugin: SandyPluginInstance, plugin: _SandyPluginInstance,
messages: Message[], messages: Message[],
) { ) {
const reducerStartTime = Date.now(); const reducerStartTime = Date.now();
@@ -83,10 +83,10 @@ export function processMessagesImmediately(
id: string; id: string;
persistedStateReducer: PersistedStateReducer | null; persistedStateReducer: PersistedStateReducer | null;
} }
| SandyPluginInstance, | _SandyPluginInstance,
messages: Message[], messages: Message[],
) { ) {
if (plugin instanceof SandyPluginInstance) { if (plugin instanceof _SandyPluginInstance) {
processMessagesSandy(pluginKey, plugin, messages); processMessagesSandy(pluginKey, plugin, messages);
} else { } else {
const persistedState = getCurrentPluginState(store, plugin, pluginKey); const persistedState = getCurrentPluginState(store, plugin, pluginKey);
@@ -116,11 +116,11 @@ export function processMessagesLater(
persistedStateReducer: PersistedStateReducer | null; persistedStateReducer: PersistedStateReducer | null;
maxQueueSize?: number; maxQueueSize?: number;
} }
| SandyPluginInstance, | _SandyPluginInstance,
messages: Message[], messages: Message[],
) { ) {
const pluginId = const pluginId =
plugin instanceof SandyPluginInstance ? plugin.definition.id : plugin.id; plugin instanceof _SandyPluginInstance ? plugin.definition.id : plugin.id;
const isSelected = const isSelected =
pluginKey === getSelectedPluginKey(store.getState().connections); pluginKey === getSelectedPluginKey(store.getState().connections);
switch (true) { switch (true) {
@@ -130,7 +130,7 @@ export function processMessagesLater(
processMessagesImmediately(store, pluginKey, plugin, messages); processMessagesImmediately(store, pluginKey, plugin, messages);
break; break;
case isSelected: case isSelected:
case plugin instanceof SandyPluginInstance: case plugin instanceof _SandyPluginInstance:
case plugin instanceof FlipperDevicePlugin: case plugin instanceof FlipperDevicePlugin:
case (plugin as any).prototype instanceof FlipperDevicePlugin: case (plugin as any).prototype instanceof FlipperDevicePlugin:
case pluginIsStarred( case pluginIsStarred(
@@ -142,7 +142,7 @@ export function processMessagesLater(
queueMessages( queueMessages(
pluginKey, pluginKey,
messages, messages,
plugin instanceof SandyPluginInstance plugin instanceof _SandyPluginInstance
? DEFAULT_MAX_QUEUE_SIZE ? DEFAULT_MAX_QUEUE_SIZE
: plugin.maxQueueSize, : plugin.maxQueueSize,
), ),
@@ -164,13 +164,13 @@ export async function processMessageQueue(
id: string; id: string;
persistedStateReducer: PersistedStateReducer | null; persistedStateReducer: PersistedStateReducer | null;
} }
| SandyPluginInstance, | _SandyPluginInstance,
pluginKey: string, pluginKey: string,
store: MiddlewareAPI, store: MiddlewareAPI,
progressCallback?: (progress: {current: number; total: number}) => void, progressCallback?: (progress: {current: number; total: number}) => void,
idler: BaseIdler = new Idler(), idler: BaseIdler = new Idler(),
): Promise<boolean> { ): Promise<boolean> {
if (!SandyPluginInstance.is(plugin) && !plugin.persistedStateReducer) { if (!_SandyPluginInstance.is(plugin) && !plugin.persistedStateReducer) {
return true; return true;
} }
const total = getPendingMessages(store, pluginKey).length; const total = getPendingMessages(store, pluginKey).length;
@@ -182,13 +182,13 @@ export async function processMessageQueue(
} }
// there are messages to process! lets do so until we have to idle // there are messages to process! lets do so until we have to idle
// persistedState is irrelevant for SandyPlugins, as they store state locally // persistedState is irrelevant for SandyPlugins, as they store state locally
const persistedState = SandyPluginInstance.is(plugin) const persistedState = _SandyPluginInstance.is(plugin)
? undefined ? undefined
: getCurrentPluginState(store, plugin, pluginKey); : getCurrentPluginState(store, plugin, pluginKey);
let offset = 0; let offset = 0;
let newPluginState = persistedState; let newPluginState = persistedState;
do { do {
if (SandyPluginInstance.is(plugin)) { if (_SandyPluginInstance.is(plugin)) {
// Optimization: we could send a batch of messages here // Optimization: we could send a batch of messages here
processMessagesSandy(pluginKey, plugin, [messages[offset]]); processMessagesSandy(pluginKey, plugin, [messages[offset]]);
} else { } else {
@@ -212,7 +212,7 @@ export async function processMessageQueue(
// resistent to kicking off this process twice; grabbing, processing messages, saving state is done synchronosly // resistent to kicking off this process twice; grabbing, processing messages, saving state is done synchronosly
// until the idler has to break // until the idler has to break
store.dispatch(clearMessageQueue(pluginKey, offset)); store.dispatch(clearMessageQueue(pluginKey, offset));
if (!SandyPluginInstance.is(plugin) && newPluginState !== persistedState) { if (!_SandyPluginInstance.is(plugin) && newPluginState !== persistedState) {
store.dispatch( store.dispatch(
setPluginState({ setPluginState({
pluginKey, pluginKey,

View File

@@ -18,7 +18,7 @@ import {State as PluginStatesState} from '../reducers/pluginStates';
import {State as PluginsState} from '../reducers/plugins'; import {State as PluginsState} from '../reducers/plugins';
import {State as PluginMessageQueueState} from '../reducers/pluginMessageQueue'; import {State as PluginMessageQueueState} from '../reducers/pluginMessageQueue';
import {deconstructPluginKey, deconstructClientId} from './clientUtils'; import {deconstructPluginKey, deconstructClientId} from './clientUtils';
import {SandyPluginDefinition} from 'flipper-plugin'; import {_SandyPluginDefinition} from 'flipper-plugin';
type Client = import('../Client').default; type Client = import('../Client').default;
@@ -239,6 +239,6 @@ export function isDevicePluginDefinition(
): definition is DevicePluginDefinition { ): definition is DevicePluginDefinition {
return ( return (
(definition as any).prototype instanceof FlipperDevicePlugin || (definition as any).prototype instanceof FlipperDevicePlugin ||
(definition instanceof SandyPluginDefinition && definition.isDevicePlugin) (definition instanceof _SandyPluginDefinition && definition.isDevicePlugin)
); );
} }

View File

@@ -0,0 +1,53 @@
/**
* 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 * as FlipperPluginModule from '../index';
test('Correct top level API exposed', () => {
const exposedAPIs: string[] = [];
const exposedTypes: string[] = [];
Object.entries(FlipperPluginModule).forEach(([key, value]) => {
if (key[0] === '_') {
return;
}
if (value === undefined) {
exposedTypes.push(key);
} else {
exposedAPIs.push(key);
}
});
expect(exposedAPIs.sort()).toMatchInlineSnapshot(`
Array [
"Layout",
"NUX",
"TestUtils",
"createState",
"renderReactRoot",
"theme",
"usePlugin",
"useValue",
]
`);
expect(exposedTypes.sort()).toMatchInlineSnapshot(`
Array [
"Atom",
"DefaultKeyboardAction",
"Device",
"DeviceLogEntry",
"DeviceLogListener",
"DevicePluginClient",
"DeviceType",
"FlipperLib",
"LogLevel",
"MenuEntry",
"NormalizedMenuEntry",
"PluginClient",
]
`);
});

View File

@@ -10,31 +10,41 @@
import './plugin/PluginBase'; import './plugin/PluginBase';
import * as TestUtilites from './test-utils/test-utils'; import * as TestUtilites from './test-utils/test-utils';
export {SandyPluginInstance, PluginClient} from './plugin/Plugin'; export {
SandyPluginInstance as _SandyPluginInstance,
PluginClient,
} from './plugin/Plugin';
export { export {
Device, Device,
DeviceLogEntry, DeviceLogEntry,
DeviceLogListener, DeviceLogListener,
DevicePluginClient, DevicePluginClient,
LogLevel, LogLevel,
SandyDevicePluginInstance, SandyDevicePluginInstance as _SandyDevicePluginInstance,
DeviceType, DeviceType,
} from './plugin/DevicePlugin'; } from './plugin/DevicePlugin';
export {SandyPluginDefinition} from './plugin/SandyPluginDefinition'; export {SandyPluginDefinition as _SandyPluginDefinition} from './plugin/SandyPluginDefinition';
export {SandyPluginRenderer} from './plugin/PluginRenderer'; export {SandyPluginRenderer as _SandyPluginRenderer} from './plugin/PluginRenderer';
export {SandyPluginContext, usePlugin} from './plugin/PluginContext'; export {
SandyPluginContext as _SandyPluginContext,
usePlugin,
} from './plugin/PluginContext';
export {createState, useValue, Atom} from './state/atom'; export {createState, useValue, Atom} from './state/atom';
export {FlipperLib} from './plugin/FlipperLib'; export {FlipperLib} from './plugin/FlipperLib';
export { export {
MenuEntry, MenuEntry,
NormalizedMenuEntry, NormalizedMenuEntry,
buildInMenuEntries, buildInMenuEntries as _buildInMenuEntries,
DefaultKeyboardAction, DefaultKeyboardAction,
} from './plugin/MenuEntry'; } from './plugin/MenuEntry';
export {theme} from './ui/theme'; export {theme} from './ui/theme';
export {Layout} from './ui/Layout'; export {Layout} from './ui/Layout';
export {NUX, NuxManagerContext, createNuxManager} from './ui/NUX'; export {
NUX,
NuxManagerContext as _NuxManagerContext,
createNuxManager as _createNuxManager,
} from './ui/NUX';
export {renderReactRoot} from './utils/renderReactRoot'; export {renderReactRoot} from './utils/renderReactRoot';

View File

@@ -10,7 +10,6 @@
import React, {createContext, useCallback, useContext} from 'react'; import React, {createContext, useCallback, useContext} from 'react';
import {Badge, Tooltip, Typography, Button} from 'antd'; import {Badge, Tooltip, Typography, Button} from 'antd';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import {SandyPluginInstance, theme} from 'flipper-plugin';
import {keyframes} from 'emotion'; import {keyframes} from 'emotion';
import reactElementToJSXString from 'react-element-to-jsx-string'; import reactElementToJSXString from 'react-element-to-jsx-string';
import {SandyPluginContext} from '../plugin/PluginContext'; import {SandyPluginContext} from '../plugin/PluginContext';
@@ -20,6 +19,8 @@ import {Layout} from './Layout';
import {BulbTwoTone} from '@ant-design/icons'; import {BulbTwoTone} from '@ant-design/icons';
import {createHash} from 'crypto'; import {createHash} from 'crypto';
import type {TooltipPlacement} from 'antd/lib/tooltip'; import type {TooltipPlacement} from 'antd/lib/tooltip';
import {SandyPluginInstance} from '../plugin/Plugin';
import {theme} from './theme';
const {Text} = Typography; const {Text} = Typography;