Summary: _typescript_ Reviewed By: passy Differential Revision: D17153997 fbshipit-source-id: 308a070b86430a9256beb93b4d3e5f8d5b6c6e52
183 lines
5.1 KiB
TypeScript
183 lines
5.1 KiB
TypeScript
/**
|
|
* Copyright 2018-present Facebook.
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
* @format
|
|
*/
|
|
|
|
import {Element} from 'flipper';
|
|
import {PersistedState} from './index';
|
|
import {SearchResultTree} from './Search';
|
|
import cloneDeep from 'lodash.clonedeep';
|
|
|
|
const propsForPersistedState = (
|
|
AXMode: boolean,
|
|
): {
|
|
ROOT: 'rootAXElement' | 'rootElement';
|
|
ELEMENTS: 'AXelements' | 'elements';
|
|
ELEMENT: 'axElement' | 'element';
|
|
} => {
|
|
return {
|
|
ROOT: AXMode ? 'rootAXElement' : 'rootElement',
|
|
ELEMENTS: AXMode ? 'AXelements' : 'elements',
|
|
ELEMENT: AXMode ? 'axElement' : 'element',
|
|
};
|
|
};
|
|
|
|
function constructSearchResultTree(
|
|
node: Element,
|
|
isMatch: boolean,
|
|
children: Array<SearchResultTree>,
|
|
_AXMode: boolean,
|
|
AXNode: Element | null,
|
|
): SearchResultTree {
|
|
const searchResult = {
|
|
id: node.id,
|
|
isMatch,
|
|
hasChildren: children.length > 0,
|
|
children: children.length > 0 ? children : [],
|
|
element: node,
|
|
axElement: AXNode,
|
|
};
|
|
return searchResult;
|
|
}
|
|
|
|
function isMatch(element: Element, query: string): boolean {
|
|
const nameMatch = element.name.toLowerCase().includes(query.toLowerCase());
|
|
return nameMatch || element.id === query;
|
|
}
|
|
|
|
export function searchNodes(
|
|
node: Element,
|
|
query: string,
|
|
AXMode: boolean,
|
|
state: PersistedState,
|
|
): SearchResultTree | null {
|
|
// Even if the axMode is true, we will have to search the normal elements too.
|
|
// The AXEelements will automatically populated in constructSearchResultTree
|
|
const elements = state[propsForPersistedState(false).ELEMENTS];
|
|
const children: Array<SearchResultTree> = [];
|
|
const match = isMatch(node, query);
|
|
|
|
for (const childID of node.children) {
|
|
const child = elements[childID];
|
|
const tree = searchNodes(child, query, AXMode, state);
|
|
if (tree) {
|
|
children.push(tree);
|
|
}
|
|
}
|
|
|
|
if (match || children.length > 0) {
|
|
return cloneDeep(
|
|
constructSearchResultTree(
|
|
node,
|
|
match,
|
|
children,
|
|
AXMode,
|
|
AXMode ? state.AXelements[node.id] : null,
|
|
),
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
class ProxyArchiveClient {
|
|
constructor(persistedState: PersistedState) {
|
|
this.persistedState = cloneDeep(persistedState);
|
|
}
|
|
persistedState: PersistedState;
|
|
subscribe(_method: string, _callback: (params: any) => void): void {
|
|
return;
|
|
}
|
|
|
|
supportsMethod(_method: string): Promise<boolean> {
|
|
return Promise.resolve(false);
|
|
}
|
|
|
|
send(_method: string, _params?: Object): void {
|
|
return;
|
|
}
|
|
|
|
call(method: string, paramaters?: {[key: string]: any}): Promise<any> {
|
|
switch (method) {
|
|
case 'getRoot': {
|
|
const {rootElement} = this.persistedState;
|
|
if (!rootElement) {
|
|
return Promise.resolve(null);
|
|
}
|
|
return Promise.resolve(this.persistedState.elements[rootElement]);
|
|
}
|
|
case 'getAXRoot': {
|
|
const {rootAXElement} = this.persistedState;
|
|
if (!rootAXElement) {
|
|
return Promise.resolve(null);
|
|
}
|
|
return Promise.resolve(this.persistedState.AXelements[rootAXElement]);
|
|
}
|
|
case 'getNodes': {
|
|
if (!paramaters) {
|
|
return Promise.reject(new Error('Called getNodes with no params'));
|
|
}
|
|
const {ids} = paramaters;
|
|
const arr: Array<Element> = [];
|
|
for (const id of ids) {
|
|
arr.push(this.persistedState.elements[id]);
|
|
}
|
|
return Promise.resolve({elements: arr});
|
|
}
|
|
case 'getAXNodes': {
|
|
if (!paramaters) {
|
|
return Promise.reject(new Error('Called getAXNodes with no params'));
|
|
}
|
|
const {ids} = paramaters;
|
|
const arr: Array<Element> = [];
|
|
for (const id of ids) {
|
|
arr.push(this.persistedState.AXelements[id]);
|
|
}
|
|
return Promise.resolve({elements: arr});
|
|
}
|
|
case 'getSearchResults': {
|
|
const {rootElement, rootAXElement} = this.persistedState;
|
|
|
|
if (!paramaters) {
|
|
return Promise.reject(
|
|
new Error('Called getSearchResults with no params'),
|
|
);
|
|
}
|
|
const {query, axEnabled} = paramaters;
|
|
if (!query) {
|
|
return Promise.reject(
|
|
new Error('query is not passed as a params to getSearchResults'),
|
|
);
|
|
}
|
|
let element: Element;
|
|
if (axEnabled) {
|
|
if (!rootAXElement) {
|
|
return Promise.reject(new Error('rootAXElement is undefined'));
|
|
}
|
|
element = this.persistedState.AXelements[rootAXElement];
|
|
} else {
|
|
if (!rootElement) {
|
|
return Promise.reject(new Error('rootElement is undefined'));
|
|
}
|
|
element = this.persistedState.elements[rootElement];
|
|
}
|
|
const output = searchNodes(
|
|
element,
|
|
query,
|
|
axEnabled,
|
|
this.persistedState,
|
|
);
|
|
return Promise.resolve({results: output, query});
|
|
}
|
|
case 'isConsoleEnabled': {
|
|
return Promise.resolve(false);
|
|
}
|
|
default: {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
export default ProxyArchiveClient;
|