Move most of plugin tests to flipper-frontend-core
Summary: See D37139129 Reviewed By: passy Differential Revision: D37241829 fbshipit-source-id: d6bef24416e2b999d529fb6e275c64384c775c21
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f4fc07ffd2
commit
3e72831699
188
desktop/flipper-frontend-core/src/__tests__/plugins.node.tsx
Normal file
188
desktop/flipper-frontend-core/src/__tests__/plugins.node.tsx
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and 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 {
|
||||||
|
getDynamicPlugins,
|
||||||
|
checkDisabled,
|
||||||
|
checkGK,
|
||||||
|
createRequirePluginFunction,
|
||||||
|
getLatestCompatibleVersionOfEachPlugin,
|
||||||
|
} from '../plugins';
|
||||||
|
import {BundledPluginDetails, InstalledPluginDetails} from 'flipper-common';
|
||||||
|
import {_SandyPluginDefinition} from 'flipper-plugin';
|
||||||
|
import {getRenderHostInstance} from '../RenderHost';
|
||||||
|
|
||||||
|
let loadDynamicPluginsMock: jest.Mock;
|
||||||
|
|
||||||
|
const sampleInstalledPluginDetails: InstalledPluginDetails = {
|
||||||
|
name: 'other Name',
|
||||||
|
version: '1.0.0',
|
||||||
|
specVersion: 2,
|
||||||
|
pluginType: 'client',
|
||||||
|
main: 'dist/bundle.js',
|
||||||
|
source: 'src/index.js',
|
||||||
|
id: 'Sample',
|
||||||
|
title: 'Sample',
|
||||||
|
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-sample',
|
||||||
|
entry: 'this/path/does not/exist',
|
||||||
|
isBundled: false,
|
||||||
|
isActivatable: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const sampleBundledPluginDetails: BundledPluginDetails = {
|
||||||
|
...sampleInstalledPluginDetails,
|
||||||
|
id: 'SampleBundled',
|
||||||
|
isBundled: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
loadDynamicPluginsMock = getRenderHostInstance().flipperServer.exec =
|
||||||
|
jest.fn();
|
||||||
|
loadDynamicPluginsMock.mockResolvedValue([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getDynamicPlugins returns empty array on errors', async () => {
|
||||||
|
loadDynamicPluginsMock.mockRejectedValue(new Error('ooops'));
|
||||||
|
const res = await getDynamicPlugins();
|
||||||
|
expect(res).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('checkDisabled', () => {
|
||||||
|
const disabledPlugin = 'pluginName';
|
||||||
|
const hostConfig = getRenderHostInstance().serverConfig;
|
||||||
|
const orig = hostConfig.processConfig;
|
||||||
|
try {
|
||||||
|
hostConfig.processConfig = {
|
||||||
|
...orig,
|
||||||
|
disabledPlugins: [disabledPlugin],
|
||||||
|
};
|
||||||
|
const disabled = checkDisabled([]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
disabled({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
name: 'other Name',
|
||||||
|
version: '1.0.0',
|
||||||
|
}),
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
disabled({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
name: disabledPlugin,
|
||||||
|
version: '1.0.0',
|
||||||
|
}),
|
||||||
|
).toBeFalsy();
|
||||||
|
} finally {
|
||||||
|
hostConfig.processConfig = orig;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('checkGK for plugin without GK', () => {
|
||||||
|
expect(
|
||||||
|
checkGK([])({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
name: 'pluginID',
|
||||||
|
version: '1.0.0',
|
||||||
|
}),
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('checkGK for passing plugin', () => {
|
||||||
|
expect(
|
||||||
|
checkGK([])({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
name: 'pluginID',
|
||||||
|
gatekeeper: 'TEST_PASSING_GK',
|
||||||
|
version: '1.0.0',
|
||||||
|
}),
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('checkGK for failing plugin', () => {
|
||||||
|
const gatekeepedPlugins: InstalledPluginDetails[] = [];
|
||||||
|
const name = 'pluginID';
|
||||||
|
const plugins = checkGK(gatekeepedPlugins)({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
name,
|
||||||
|
gatekeeper: 'TEST_FAILING_GK',
|
||||||
|
version: '1.0.0',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(plugins).toBeFalsy();
|
||||||
|
expect(gatekeepedPlugins[0].name).toEqual(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('requirePlugin returns null for invalid requires', async () => {
|
||||||
|
const requireFn = createRequirePluginFunction(() => {
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
const plugin = await requireFn([])({
|
||||||
|
...sampleInstalledPluginDetails,
|
||||||
|
name: 'pluginID',
|
||||||
|
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-sample',
|
||||||
|
entry: 'this/path/does not/exist',
|
||||||
|
version: '1.0.0',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(plugin).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('newest version of each plugin is used', () => {
|
||||||
|
const bundledPlugins: BundledPluginDetails[] = [
|
||||||
|
{
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
id: 'TestPlugin1',
|
||||||
|
name: 'flipper-plugin-test1',
|
||||||
|
version: '0.1.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
id: 'TestPlugin2',
|
||||||
|
name: 'flipper-plugin-test2',
|
||||||
|
version: '0.1.0-alpha.201',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const installedPlugins: InstalledPluginDetails[] = [
|
||||||
|
{
|
||||||
|
...sampleInstalledPluginDetails,
|
||||||
|
id: 'TestPlugin2',
|
||||||
|
name: 'flipper-plugin-test2',
|
||||||
|
version: '0.1.0-alpha.21',
|
||||||
|
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test2',
|
||||||
|
entry: './test/index.js',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...sampleInstalledPluginDetails,
|
||||||
|
id: 'TestPlugin1',
|
||||||
|
name: 'flipper-plugin-test1',
|
||||||
|
version: '0.10.0',
|
||||||
|
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test1',
|
||||||
|
entry: './test/index.js',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const filteredPlugins = getLatestCompatibleVersionOfEachPlugin(
|
||||||
|
[...bundledPlugins, ...installedPlugins],
|
||||||
|
'0.1.0',
|
||||||
|
);
|
||||||
|
expect(filteredPlugins).toHaveLength(2);
|
||||||
|
expect(filteredPlugins).toContainEqual({
|
||||||
|
...sampleInstalledPluginDetails,
|
||||||
|
id: 'TestPlugin1',
|
||||||
|
name: 'flipper-plugin-test1',
|
||||||
|
version: '0.10.0',
|
||||||
|
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test1',
|
||||||
|
entry: './test/index.js',
|
||||||
|
});
|
||||||
|
expect(filteredPlugins).toContainEqual({
|
||||||
|
...sampleBundledPluginDetails,
|
||||||
|
id: 'TestPlugin2',
|
||||||
|
name: 'flipper-plugin-test2',
|
||||||
|
version: '0.1.0-alpha.201',
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -43,6 +43,10 @@ export abstract class AbstractPluginInitializer {
|
|||||||
return this._initialPlugins;
|
return this._initialPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get requirePlugin() {
|
||||||
|
return createRequirePluginFunction(this.requirePluginImpl.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
protected async _init(): Promise<_SandyPluginDefinition[]> {
|
protected async _init(): Promise<_SandyPluginDefinition[]> {
|
||||||
this.loadDefaultPluginIndex();
|
this.loadDefaultPluginIndex();
|
||||||
this.loadMarketplacePlugins();
|
this.loadMarketplacePlugins();
|
||||||
@@ -100,9 +104,7 @@ export abstract class AbstractPluginInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async loadPlugins(pluginsToLoad: ActivatablePluginDetails[]) {
|
protected async loadPlugins(pluginsToLoad: ActivatablePluginDetails[]) {
|
||||||
const loader = createRequirePluginFunction(
|
const loader = this.requirePlugin(this.failedPlugins);
|
||||||
this.requirePluginImpl.bind(this),
|
|
||||||
)(this.failedPlugins);
|
|
||||||
const initialPlugins: _SandyPluginDefinition[] = (
|
const initialPlugins: _SandyPluginDefinition[] = (
|
||||||
await pMap(pluginsToLoad, loader)
|
await pMap(pluginsToLoad, loader)
|
||||||
).filter(notNull);
|
).filter(notNull);
|
||||||
@@ -267,7 +269,7 @@ export const createRequirePluginFunction =
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapRequirePlugin =
|
export const wrapRequirePlugin =
|
||||||
(
|
(
|
||||||
requirePluginImpl: (
|
requirePluginImpl: (
|
||||||
pluginDetails: ActivatablePluginDetails,
|
pluginDetails: ActivatablePluginDetails,
|
||||||
|
|||||||
@@ -7,21 +7,17 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
jest.mock('../../../../app/src/defaultPlugins');
|
import dispatcher, {requirePluginInternal} from '../plugins';
|
||||||
import dispatcher, {
|
import {InstalledPluginDetails} from 'flipper-common';
|
||||||
getDynamicPlugins,
|
|
||||||
checkDisabled,
|
|
||||||
checkGK,
|
|
||||||
createRequirePluginFunction,
|
|
||||||
getLatestCompatibleVersionOfEachPlugin,
|
|
||||||
} from '../plugins';
|
|
||||||
import {BundledPluginDetails, InstalledPluginDetails} from 'flipper-common';
|
|
||||||
import {createRootReducer, State} from '../../reducers/index';
|
import {createRootReducer, State} from '../../reducers/index';
|
||||||
import {getLogger} from 'flipper-common';
|
import {getLogger} from 'flipper-common';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import TestPlugin from './TestPlugin';
|
import TestPlugin from './TestPlugin';
|
||||||
import {_SandyPluginDefinition} from 'flipper-plugin';
|
import {_SandyPluginDefinition} from 'flipper-plugin';
|
||||||
import {getRenderHostInstance} from 'flipper-frontend-core';
|
import {
|
||||||
|
getRenderHostInstance,
|
||||||
|
createRequirePluginFunction,
|
||||||
|
} from 'flipper-frontend-core';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
let loadDynamicPluginsMock: jest.Mock;
|
let loadDynamicPluginsMock: jest.Mock;
|
||||||
@@ -46,11 +42,8 @@ const sampleInstalledPluginDetails: InstalledPluginDetails = {
|
|||||||
isActivatable: true,
|
isActivatable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const sampleBundledPluginDetails: BundledPluginDetails = {
|
// bind to empty default plugin index so we try fetching from flipper-server every time
|
||||||
...sampleInstalledPluginDetails,
|
const requirePlugin = requirePluginInternal.bind({}, {});
|
||||||
id: 'SampleBundled',
|
|
||||||
isBundled: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
loadDynamicPluginsMock = getRenderHostInstance().flipperServer.exec =
|
loadDynamicPluginsMock = getRenderHostInstance().flipperServer.exec =
|
||||||
@@ -64,79 +57,8 @@ test('dispatcher dispatches REGISTER_PLUGINS', async () => {
|
|||||||
expect(actions.map((a) => a.type)).toContain('REGISTER_PLUGINS');
|
expect(actions.map((a) => a.type)).toContain('REGISTER_PLUGINS');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getDynamicPlugins returns empty array on errors', async () => {
|
test('requirePluginInternal returns null for invalid requires', async () => {
|
||||||
loadDynamicPluginsMock.mockRejectedValue(new Error('ooops'));
|
const requireFn = createRequirePluginFunction(requirePlugin)([]);
|
||||||
const res = await getDynamicPlugins();
|
|
||||||
expect(res).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checkDisabled', () => {
|
|
||||||
const disabledPlugin = 'pluginName';
|
|
||||||
const hostConfig = getRenderHostInstance().serverConfig;
|
|
||||||
const orig = hostConfig.processConfig;
|
|
||||||
try {
|
|
||||||
hostConfig.processConfig = {
|
|
||||||
...orig,
|
|
||||||
disabledPlugins: [disabledPlugin],
|
|
||||||
};
|
|
||||||
const disabled = checkDisabled([]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
disabled({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
name: 'other Name',
|
|
||||||
version: '1.0.0',
|
|
||||||
}),
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(
|
|
||||||
disabled({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
name: disabledPlugin,
|
|
||||||
version: '1.0.0',
|
|
||||||
}),
|
|
||||||
).toBeFalsy();
|
|
||||||
} finally {
|
|
||||||
hostConfig.processConfig = orig;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checkGK for plugin without GK', () => {
|
|
||||||
expect(
|
|
||||||
checkGK([])({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
name: 'pluginID',
|
|
||||||
version: '1.0.0',
|
|
||||||
}),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checkGK for passing plugin', () => {
|
|
||||||
expect(
|
|
||||||
checkGK([])({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
name: 'pluginID',
|
|
||||||
gatekeeper: 'TEST_PASSING_GK',
|
|
||||||
version: '1.0.0',
|
|
||||||
}),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checkGK for failing plugin', () => {
|
|
||||||
const gatekeepedPlugins: InstalledPluginDetails[] = [];
|
|
||||||
const name = 'pluginID';
|
|
||||||
const plugins = checkGK(gatekeepedPlugins)({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
name,
|
|
||||||
gatekeeper: 'TEST_FAILING_GK',
|
|
||||||
version: '1.0.0',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(plugins).toBeFalsy();
|
|
||||||
expect(gatekeepedPlugins[0].name).toEqual(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('requirePlugin returns null for invalid requires', async () => {
|
|
||||||
const requireFn = createRequirePluginFunction([]);
|
|
||||||
const plugin = await requireFn({
|
const plugin = await requireFn({
|
||||||
...sampleInstalledPluginDetails,
|
...sampleInstalledPluginDetails,
|
||||||
name: 'pluginID',
|
name: 'pluginID',
|
||||||
@@ -148,9 +70,9 @@ test('requirePlugin returns null for invalid requires', async () => {
|
|||||||
expect(plugin).toBeNull();
|
expect(plugin).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('requirePlugin loads plugin', async () => {
|
test('requirePluginInternal loads plugin', async () => {
|
||||||
const name = 'pluginID';
|
const name = 'pluginID';
|
||||||
const requireFn = createRequirePluginFunction([]);
|
const requireFn = createRequirePluginFunction(requirePlugin)([]);
|
||||||
const plugin = await requireFn({
|
const plugin = await requireFn({
|
||||||
...sampleInstalledPluginDetails,
|
...sampleInstalledPluginDetails,
|
||||||
name,
|
name,
|
||||||
@@ -170,63 +92,9 @@ test('requirePlugin loads plugin', async () => {
|
|||||||
expect(plugin!.id).toBe(TestPlugin.id);
|
expect(plugin!.id).toBe(TestPlugin.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('newest version of each plugin is used', () => {
|
test('requirePluginInternal loads valid Sandy plugin', async () => {
|
||||||
const bundledPlugins: BundledPluginDetails[] = [
|
|
||||||
{
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
id: 'TestPlugin1',
|
|
||||||
name: 'flipper-plugin-test1',
|
|
||||||
version: '0.1.0',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
id: 'TestPlugin2',
|
|
||||||
name: 'flipper-plugin-test2',
|
|
||||||
version: '0.1.0-alpha.201',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const installedPlugins: InstalledPluginDetails[] = [
|
|
||||||
{
|
|
||||||
...sampleInstalledPluginDetails,
|
|
||||||
id: 'TestPlugin2',
|
|
||||||
name: 'flipper-plugin-test2',
|
|
||||||
version: '0.1.0-alpha.21',
|
|
||||||
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test2',
|
|
||||||
entry: './test/index.js',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
...sampleInstalledPluginDetails,
|
|
||||||
id: 'TestPlugin1',
|
|
||||||
name: 'flipper-plugin-test1',
|
|
||||||
version: '0.10.0',
|
|
||||||
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test1',
|
|
||||||
entry: './test/index.js',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const filteredPlugins = getLatestCompatibleVersionOfEachPlugin([
|
|
||||||
...bundledPlugins,
|
|
||||||
...installedPlugins,
|
|
||||||
]);
|
|
||||||
expect(filteredPlugins).toHaveLength(2);
|
|
||||||
expect(filteredPlugins).toContainEqual({
|
|
||||||
...sampleInstalledPluginDetails,
|
|
||||||
id: 'TestPlugin1',
|
|
||||||
name: 'flipper-plugin-test1',
|
|
||||||
version: '0.10.0',
|
|
||||||
dir: '/Users/mock/.flipper/thirdparty/flipper-plugin-test1',
|
|
||||||
entry: './test/index.js',
|
|
||||||
});
|
|
||||||
expect(filteredPlugins).toContainEqual({
|
|
||||||
...sampleBundledPluginDetails,
|
|
||||||
id: 'TestPlugin2',
|
|
||||||
name: 'flipper-plugin-test2',
|
|
||||||
version: '0.1.0-alpha.201',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('requirePlugin loads valid Sandy plugin', async () => {
|
|
||||||
const name = 'pluginID';
|
const name = 'pluginID';
|
||||||
const requireFn = createRequirePluginFunction([]);
|
const requireFn = createRequirePluginFunction(requirePlugin)([]);
|
||||||
const plugin = (await requireFn({
|
const plugin = (await requireFn({
|
||||||
...sampleInstalledPluginDetails,
|
...sampleInstalledPluginDetails,
|
||||||
name,
|
name,
|
||||||
@@ -261,10 +129,10 @@ test('requirePlugin loads valid Sandy plugin', async () => {
|
|||||||
expect(typeof plugin.asPluginModule().plugin).toBe('function');
|
expect(typeof plugin.asPluginModule().plugin).toBe('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('requirePlugin errors on invalid Sandy plugin', async () => {
|
test('requirePluginInternal errors on invalid Sandy plugin', async () => {
|
||||||
const name = 'pluginID';
|
const name = 'pluginID';
|
||||||
const failedPlugins: any[] = [];
|
const failedPlugins: any[] = [];
|
||||||
const requireFn = createRequirePluginFunction(failedPlugins);
|
const requireFn = createRequirePluginFunction(requirePlugin)(failedPlugins);
|
||||||
await requireFn({
|
await requireFn({
|
||||||
...sampleInstalledPluginDetails,
|
...sampleInstalledPluginDetails,
|
||||||
name,
|
name,
|
||||||
@@ -279,9 +147,9 @@ test('requirePlugin errors on invalid Sandy plugin', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('requirePlugin loads valid Sandy Device plugin', async () => {
|
test('requirePluginInternal loads valid Sandy Device plugin', async () => {
|
||||||
const name = 'pluginID';
|
const name = 'pluginID';
|
||||||
const requireFn = createRequirePluginFunction([]);
|
const requireFn = createRequirePluginFunction(requirePlugin)([]);
|
||||||
const plugin = (await requireFn({
|
const plugin = (await requireFn({
|
||||||
...sampleInstalledPluginDetails,
|
...sampleInstalledPluginDetails,
|
||||||
pluginType: 'device',
|
pluginType: 'device',
|
||||||
|
|||||||
@@ -8,11 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Store} from '../reducers/index';
|
import type {Store} from '../reducers/index';
|
||||||
import {
|
import {Logger} from 'flipper-common';
|
||||||
InstalledPluginDetails,
|
|
||||||
Logger,
|
|
||||||
tryCatchReportPluginFailuresAsync,
|
|
||||||
} from 'flipper-common';
|
|
||||||
import {PluginDefinition} from '../plugin';
|
import {PluginDefinition} from '../plugin';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
@@ -30,23 +26,21 @@ import {
|
|||||||
pluginsInitialized,
|
pluginsInitialized,
|
||||||
} from '../reducers/plugins';
|
} from '../reducers/plugins';
|
||||||
import {FlipperBasePlugin} from '../plugin';
|
import {FlipperBasePlugin} from '../plugin';
|
||||||
import {ActivatablePluginDetails, ConcretePluginDetails} from 'flipper-common';
|
import {ActivatablePluginDetails} from 'flipper-common';
|
||||||
import {reportUsage} from 'flipper-common';
|
|
||||||
import * as FlipperPluginSDK from 'flipper-plugin';
|
import * as FlipperPluginSDK from 'flipper-plugin';
|
||||||
import {_SandyPluginDefinition} from 'flipper-plugin';
|
import {_SandyPluginDefinition} from 'flipper-plugin';
|
||||||
import * as Immer from 'immer';
|
import * as Immer from 'immer';
|
||||||
import * as antd from 'antd';
|
import * as antd from 'antd';
|
||||||
import * as emotion_styled from '@emotion/styled';
|
import * as emotion_styled from '@emotion/styled';
|
||||||
import * as antdesign_icons from '@ant-design/icons';
|
import * as antdesign_icons from '@ant-design/icons';
|
||||||
|
|
||||||
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
|
||||||
import isPluginCompatible from '../utils/isPluginCompatible';
|
import isPluginCompatible from '../utils/isPluginCompatible';
|
||||||
import isPluginVersionMoreRecent from '../utils/isPluginVersionMoreRecent';
|
|
||||||
import {createSandyPluginWrapper} from '../utils/createSandyPluginWrapper';
|
import {createSandyPluginWrapper} from '../utils/createSandyPluginWrapper';
|
||||||
import {
|
import {
|
||||||
AbstractPluginInitializer,
|
AbstractPluginInitializer,
|
||||||
getRenderHostInstance,
|
getRenderHostInstance,
|
||||||
setGlobalObject,
|
setGlobalObject,
|
||||||
|
isSandyPlugin,
|
||||||
|
wrapRequirePlugin,
|
||||||
} from 'flipper-frontend-core';
|
} from 'flipper-frontend-core';
|
||||||
import * as deprecatedExports from '../deprecated-exports';
|
import * as deprecatedExports from '../deprecated-exports';
|
||||||
import {getAppVersion} from '../utils/info';
|
import {getAppVersion} from '../utils/info';
|
||||||
@@ -124,142 +118,10 @@ export default async (store: Store, _logger: Logger) => {
|
|||||||
await uiPluginInitializer.init();
|
await uiPluginInitializer.init();
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getLatestCompatibleVersionOfEachPlugin<
|
export const requirePlugin = (pluginDetails: ActivatablePluginDetails) =>
|
||||||
T extends ConcretePluginDetails,
|
wrapRequirePlugin(uiPluginInitializer!.requirePluginImpl)(pluginDetails);
|
||||||
>(plugins: T[]): T[] {
|
|
||||||
const latestCompatibleVersions: Map<string, T> = new Map();
|
|
||||||
for (const plugin of plugins) {
|
|
||||||
if (isPluginCompatible(plugin)) {
|
|
||||||
const loadedVersion = latestCompatibleVersions.get(plugin.id);
|
|
||||||
if (!loadedVersion || isPluginVersionMoreRecent(plugin, loadedVersion)) {
|
|
||||||
latestCompatibleVersions.set(plugin.id, plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Array.from(latestCompatibleVersions.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getDynamicPlugins(): Promise<InstalledPluginDetails[]> {
|
export const requirePluginInternal = async (
|
||||||
try {
|
|
||||||
return await getRenderHostInstance().flipperServer!.exec(
|
|
||||||
'plugins-load-dynamic-plugins',
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to load dynamic plugins', e);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const checkGK =
|
|
||||||
(gatekeepedPlugins: Array<ActivatablePluginDetails>) =>
|
|
||||||
(plugin: ActivatablePluginDetails): boolean => {
|
|
||||||
try {
|
|
||||||
if (!plugin.gatekeeper) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const result = getRenderHostInstance().GK(plugin.gatekeeper);
|
|
||||||
if (!result) {
|
|
||||||
gatekeepedPlugins.push(plugin);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Failed to check GK for plugin ${plugin.id}`, err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const checkDisabled = (
|
|
||||||
disabledPlugins: Array<ActivatablePluginDetails>,
|
|
||||||
) => {
|
|
||||||
const config = getRenderHostInstance().serverConfig;
|
|
||||||
let enabledList: Set<string> | null = null;
|
|
||||||
let disabledList: Set<string> = new Set();
|
|
||||||
try {
|
|
||||||
if (config.env.FLIPPER_ENABLED_PLUGINS) {
|
|
||||||
enabledList = new Set<string>(
|
|
||||||
config.env.FLIPPER_ENABLED_PLUGINS.split(','),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
disabledList = new Set(config.processConfig.disabledPlugins);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to compute enabled/disabled plugins', e);
|
|
||||||
}
|
|
||||||
return (plugin: ActivatablePluginDetails): boolean => {
|
|
||||||
try {
|
|
||||||
if (disabledList.has(plugin.name)) {
|
|
||||||
disabledPlugins.push(plugin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
enabledList &&
|
|
||||||
!(
|
|
||||||
enabledList.has(plugin.name) ||
|
|
||||||
enabledList.has(plugin.id) ||
|
|
||||||
enabledList.has(plugin.name.replace('flipper-plugin-', ''))
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
disabledPlugins.push(plugin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(
|
|
||||||
`Failed to check whether plugin ${plugin.id} is disabled`,
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createRequirePluginFunction = (
|
|
||||||
failedPlugins: Array<[ActivatablePluginDetails, string]>,
|
|
||||||
) => {
|
|
||||||
return async (
|
|
||||||
pluginDetails: ActivatablePluginDetails,
|
|
||||||
): Promise<PluginDefinition | null> => {
|
|
||||||
try {
|
|
||||||
const pluginDefinition = await requirePlugin(pluginDetails);
|
|
||||||
if (
|
|
||||||
pluginDefinition &&
|
|
||||||
isDevicePluginDefinition(pluginDefinition) &&
|
|
||||||
pluginDefinition.details.pluginType !== 'device'
|
|
||||||
) {
|
|
||||||
console.warn(
|
|
||||||
`Package ${pluginDefinition.details.name} contains the device plugin "${pluginDefinition.title}" defined in a wrong format. Specify "pluginType" and "supportedDevices" properties and remove exported function "supportsDevice". See details at https://fbflipper.com/docs/extending/desktop-plugin-structure#creating-a-device-plugin.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return pluginDefinition;
|
|
||||||
} catch (e) {
|
|
||||||
failedPlugins.push([pluginDetails, e.message]);
|
|
||||||
console.error(`Plugin ${pluginDetails.id} failed to load`, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const requirePlugin = (
|
|
||||||
pluginDetails: ActivatablePluginDetails,
|
|
||||||
): Promise<PluginDefinition> => {
|
|
||||||
reportUsage(
|
|
||||||
'plugin:load',
|
|
||||||
{
|
|
||||||
version: pluginDetails.version,
|
|
||||||
},
|
|
||||||
pluginDetails.id,
|
|
||||||
);
|
|
||||||
return tryCatchReportPluginFailuresAsync(
|
|
||||||
() => uiPluginInitializer.requirePluginImpl(pluginDetails),
|
|
||||||
'plugin:load',
|
|
||||||
pluginDetails.id,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isSandyPlugin = (pluginDetails: ActivatablePluginDetails) => {
|
|
||||||
return !!pluginDetails.flipperSDKVersion;
|
|
||||||
};
|
|
||||||
|
|
||||||
const requirePluginInternal = async (
|
|
||||||
defaultPluginsIndex: any,
|
defaultPluginsIndex: any,
|
||||||
pluginDetails: ActivatablePluginDetails,
|
pluginDetails: ActivatablePluginDetails,
|
||||||
): Promise<PluginDefinition> => {
|
): Promise<PluginDefinition> => {
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
import type {PluginDefinition} from '../plugin';
|
import type {PluginDefinition} from '../plugin';
|
||||||
import type {State, Store} from '../reducers';
|
import type {State, Store} from '../reducers';
|
||||||
import type {State as PluginsState} from '../reducers/plugins';
|
import type {State as PluginsState} from '../reducers/plugins';
|
||||||
import type {BaseDevice} from 'flipper-frontend-core';
|
import {
|
||||||
|
BaseDevice,
|
||||||
|
getLatestCompatibleVersionOfEachPlugin,
|
||||||
|
} from 'flipper-frontend-core';
|
||||||
import type Client from '../Client';
|
import type Client from '../Client';
|
||||||
import type {
|
import type {
|
||||||
ActivatablePluginDetails,
|
ActivatablePluginDetails,
|
||||||
@@ -18,8 +21,8 @@ import type {
|
|||||||
DownloadablePluginDetails,
|
DownloadablePluginDetails,
|
||||||
PluginDetails,
|
PluginDetails,
|
||||||
} from 'flipper-common';
|
} from 'flipper-common';
|
||||||
import {getLatestCompatibleVersionOfEachPlugin} from '../dispatcher/plugins';
|
|
||||||
import {getPluginKey} from './pluginKey';
|
import {getPluginKey} from './pluginKey';
|
||||||
|
import {getAppVersion} from './info';
|
||||||
|
|
||||||
export type PluginLists = {
|
export type PluginLists = {
|
||||||
devicePlugins: PluginDefinition[];
|
devicePlugins: PluginDefinition[];
|
||||||
@@ -181,10 +184,10 @@ export function computePluginLists(
|
|||||||
} {
|
} {
|
||||||
const enabledDevicePluginsState = connections.enabledDevicePlugins;
|
const enabledDevicePluginsState = connections.enabledDevicePlugins;
|
||||||
const enabledPluginsState = connections.enabledPlugins;
|
const enabledPluginsState = connections.enabledPlugins;
|
||||||
const uninstalledMarketplacePlugins = getLatestCompatibleVersionOfEachPlugin([
|
const uninstalledMarketplacePlugins = getLatestCompatibleVersionOfEachPlugin(
|
||||||
...plugins.bundledPlugins.values(),
|
[...plugins.bundledPlugins.values(), ...plugins.marketplacePlugins],
|
||||||
...plugins.marketplacePlugins,
|
getAppVersion(),
|
||||||
]).filter((p) => !plugins.loadedPlugins.has(p.id));
|
).filter((p) => !plugins.loadedPlugins.has(p.id));
|
||||||
const devicePlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
|
const devicePlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
|
||||||
.filter((p) => device?.supportsPlugin(p))
|
.filter((p) => device?.supportsPlugin(p))
|
||||||
.filter((p) => enabledDevicePluginsState.has(p.id));
|
.filter((p) => enabledDevicePluginsState.has(p.id));
|
||||||
|
|||||||
Reference in New Issue
Block a user