Yarn workspaces

Summary:
1) moved "sonar/desktop/src" to "sonar/desktop/app/src", so "app" is now a separate package containing the core Flipper app code
2) Configured yarn workspaces with the root in "sonar/desktop": app, static, pkg, doctor, headless-tests. Plugins are not included for now, I plan to do this later.

Reviewed By: jknoxville

Differential Revision: D20535782

fbshipit-source-id: 600b2301960f37c7d72166e0d04eba462bec9fc1
This commit is contained in:
Anton Nikolaev
2020-03-20 13:31:37 -07:00
committed by Facebook GitHub Bot
parent 676d7bbd24
commit 863f89351e
340 changed files with 1635 additions and 294 deletions

View File

@@ -0,0 +1,210 @@
/**
* 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 path from 'path';
import fs from 'fs';
import {Store, State} from '../reducers';
import {getPluginKey} from './pluginUtils';
import {serialize} from './serialization';
let pluginRecordingState: {
recording: string;
pluginName: string;
startState: any;
events: [string, any][];
endState: any;
} = initialRecordingState();
function initialRecordingState(): typeof pluginRecordingState {
return {
recording: '',
startState: undefined,
events: [],
endState: undefined,
pluginName: '',
};
}
export function flipperRecorderAddEvent(
pluginKey: string,
method: string,
params: any,
) {
if (pluginRecordingState.recording === pluginKey) {
pluginRecordingState.events.push([method, params]);
}
}
async function flipperStartPluginRecording(state: State) {
if (pluginRecordingState.recording) {
throw new Error('A plugin recording is already running');
}
const app = state.connections.selectedApp;
const client = state.connections.clients.find(client => client.id === app);
if (!app || !client) {
throw new Error('Can only record plugin states if a device is selected');
}
const selectedPlugin = state.connections.selectedPlugin;
const pluginKey = getPluginKey(client.id, null, selectedPlugin!);
const plugin = state.plugins.clientPlugins.get(selectedPlugin!);
if (!selectedPlugin || !plugin) {
throw new Error('Can only record plugin states if a plugin is selected');
}
pluginRecordingState = {
recording: pluginKey,
startState: undefined,
events: [],
endState: undefined,
pluginName: selectedPlugin,
};
// Note that we don't use the plugin's own serializeState, as that might interact with the
// device state, and is used for exporting Flipper traces.
pluginRecordingState.startState = await serialize(
state.pluginStates[pluginKey] || plugin.defaultPersistedState,
);
console.log(
`Started recordig the states of plugin ${selectedPlugin}..... Use window.flipperStopPluginRecording() to finish this process`,
);
}
async function flipperStopPluginRecording(state: State) {
if (!pluginRecordingState.recording) {
throw new Error('No plugin recording is running. ');
}
if (!pluginRecordingState.events.length) {
console.warn('No events were captured, cancelling recording');
pluginRecordingState = initialRecordingState();
return;
}
pluginRecordingState.endState = await serialize(
state.pluginStates[pluginRecordingState.recording],
);
const pluginName = pluginRecordingState.pluginName;
const snapShotFileContents = JSON.stringify(pluginRecordingState);
const snapShotFileName = `${pluginName}.pluginSnapshot.json`;
const testFileName = `${pluginName}EventsRunner.tsx`;
const outDir = getOutputDir(pluginName);
const testFileContents = generateTestSuite(pluginName, snapShotFileName);
await fs.promises.writeFile(
path.join(outDir, snapShotFileName),
snapShotFileContents,
'utf8',
);
await fs.promises.writeFile(
path.join(outDir, testFileName),
testFileContents,
'utf8',
);
console.log(
`Finished recording ${pluginRecordingState.events.length} for plugin ${
pluginRecordingState.recording
}. Generated files ${path.join(outDir, testFileName)} and ${path.join(
outDir,
snapShotFileName,
)}. Move them to the '__tests__ folder of your plugin to incorporate them`,
);
pluginRecordingState = initialRecordingState();
}
export function registerRecordingHooks(store: Store) {
Object.assign(window, {
flipperStartPluginRecording() {
flipperStartPluginRecording(store.getState());
},
flipperStopPluginRecording() {
flipperStopPluginRecording(store.getState());
},
});
}
function getOutputDir(pluginName: string) {
const outDir = path.join(process.cwd(), '..');
const fbPluginDir = path.join(
outDir,
'plugins',
'fb',
pluginName.toLowerCase(),
'__tests__',
);
const defaultPluginDir = path.join(
outDir,
'plugins',
pluginName.toLowerCase(),
'__tests__',
);
if (fs.existsSync(fbPluginDir)) {
return fbPluginDir;
} else if (fs.existsSync(defaultPluginDir)) {
return defaultPluginDir;
}
return outDir;
}
function generateTestSuite(pluginName: string, snapShotFileName: string) {
return `\
/**
* 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
*/
// This file was initially generated by using \`flipperStartPluginRecording()\` in Flipper console
import fs from 'fs';
import path from 'path';
import {deserialize} from 'flipper';
import Plugin from '../';
test('Verify events produce a consistent end state for plugin ${pluginName}', async () => {
const snapshotData: {
startState: string;
endState: string;
events: [string, any][];
} = JSON.parse(
await fs.promises.readFile(
path.join(__dirname, '${snapShotFileName}'),
'utf8',
),
);
const startState: typeof Plugin.defaultPersistedState = deserialize(
snapshotData.startState,
);
const endState: typeof Plugin.defaultPersistedState = deserialize(
snapshotData.endState,
);
const startTime = Date.now();
const generatedEndState = snapshotData.events.reduce(
(store, [method, params]) =>
Plugin.persistedStateReducer(store, method, params),
startState,
);
const totalTime = Date.now() - startTime;
expect(generatedEndState).toEqual(endState);
console.log(
\`Reducer took $\{totalTime\}ms. to process $\{snapshotData.events.length\} events\`,
);
});
`;
}