diff --git a/lib/DevTools.js b/lib/DevTools.js deleted file mode 100644 index 58f15a71d..000000000 --- a/lib/DevTools.js +++ /dev/null @@ -1,71 +0,0 @@ -import _ from 'underscore'; - -const ERROR_LABEL = 'Onyx DevTools - Error: '; - -/* eslint-disable no-underscore-dangle */ -class DevTools { - constructor() { - this.remoteDev = this.connectViaExtension(); - this.state = {}; - this.defaultState = {}; - } - - connectViaExtension(options) { - try { - if ((options && options.remote) || typeof window === 'undefined' || !window.__REDUX_DEVTOOLS_EXTENSION__) { - return; - } - return window.__REDUX_DEVTOOLS_EXTENSION__.connect(options); - } catch (e) { - console.error(ERROR_LABEL, e); - } - } - - /** - * Registers an action that updated the current state of the storage - * - * @param {string} type - name of the action - * @param {any} payload - data written to the storage - * @param {object} stateChanges - partial state that got updated after the changes - */ - registerAction(type, payload = undefined, stateChanges = {}) { - try { - if (!this.remoteDev) { - return; - } - const newState = { - ...this.state, - ...stateChanges, - }; - this.remoteDev.send({type, payload}, newState); - this.state = newState; - } catch (e) { - console.error(ERROR_LABEL, e); - } - } - - initState(initialState = {}) { - try { - if (!this.remoteDev) { - return; - } - this.remoteDev.init(initialState); - this.state = initialState; - this.defaultState = initialState; - } catch (e) { - console.error(ERROR_LABEL, e); - } - } - - /** - * This clears the internal state of the DevTools, preserving the keys included in `keysToPreserve` - * - * @param {string[]} keysToPreserve - */ - clearState(keysToPreserve = []) { - const newState = _.mapObject(this.state, (value, key) => (keysToPreserve.includes(key) ? value : this.defaultState[key])); - this.registerAction('CLEAR', undefined, newState); - } -} - -export default new DevTools(); diff --git a/lib/DevTools.ts b/lib/DevTools.ts new file mode 100644 index 000000000..76be784e9 --- /dev/null +++ b/lib/DevTools.ts @@ -0,0 +1,104 @@ +type DevtoolsOptions = { + maxAge?: number; + name?: string; + postTimelineUpdate?: () => void; + preAction?: () => void; + logTrace?: boolean; + remote?: boolean; +}; + +type DevtoolsSubscriber = (message: {type: string; payload: unknown; state: string}) => void; + +type DevtoolsConnection = { + send(data: Record, state: Record): void; + init(state: Record): void; + unsubscribe(): void; + subscribe(cb: DevtoolsSubscriber): () => void; +}; + +const ERROR_LABEL = 'Onyx DevTools - Error: '; + +type ReduxDevtools = { + connect(options?: DevtoolsOptions): DevtoolsConnection; +}; + +class DevTools { + private remoteDev?: DevtoolsConnection; + + private state: Record; + + private defaultState: Record; + + constructor() { + this.remoteDev = this.connectViaExtension(); + this.state = {}; + this.defaultState = {}; + } + + connectViaExtension(options?: DevtoolsOptions): DevtoolsConnection | undefined { + try { + // We don't want to augment the window type in a library code, so we use type assertion instead + // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-explicit-any + const reduxDevtools: ReduxDevtools = (window as any).__REDUX_DEVTOOLS_EXTENSION__; + + if ((options && options.remote) || typeof window === 'undefined' || !reduxDevtools) { + return; + } + // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-explicit-any + return reduxDevtools.connect(options); + } catch (e) { + console.error(ERROR_LABEL, e); + } + } + + /** + * Registers an action that updated the current state of the storage + * + * @param type - name of the action + * @param payload - data written to the storage + * @param stateChanges - partial state that got updated after the changes + */ + registerAction(type: string, payload: unknown, stateChanges: Record = {}) { + try { + if (!this.remoteDev) { + return; + } + const newState = { + ...this.state, + ...stateChanges, + }; + this.remoteDev.send({type, payload}, newState); + this.state = newState; + } catch (e) { + console.error(ERROR_LABEL, e); + } + } + + initState(initialState: Record = {}) { + try { + if (!this.remoteDev) { + return; + } + this.remoteDev.init(initialState); + this.state = initialState; + this.defaultState = initialState; + } catch (e) { + console.error(ERROR_LABEL, e); + } + } + + /** + * This clears the internal state of the DevTools, preserving the keys included in `keysToPreserve` + */ + public clearState(keysToPreserve: string[] = []): void { + const newState = Object.entries(this.state).reduce((obj: Record, [key, value]) => { + // eslint-disable-next-line no-param-reassign + obj[key] = keysToPreserve.includes(key) ? value : this.defaultState[key]; + return obj; + }, {}); + + this.registerAction('CLEAR', undefined, newState); + } +} + +export default new DevTools(); diff --git a/lib/MDTable.js b/lib/MDTable.js deleted file mode 100644 index 9a09132ef..000000000 --- a/lib/MDTable.js +++ /dev/null @@ -1,66 +0,0 @@ -import AsciTable from 'ascii-table'; - -class MDTable extends AsciTable { - /** - * Create a CSV string from the table data - * @returns {string} - */ - toCSV() { - return [this.getTitle(), this.getHeading(), ...this.getRows()].join('\n'); - } - - /** - * Create a JSON string from the table data - * @returns {string} - */ - toJSON() { - return JSON.stringify(super.toJSON()); - } - - /** - * Create a MD string from the table data - * @returns {string} - */ - toString() { - // Ignore modifying the first |---| for titled tables - let idx = this.getTitle() ? -2 : -1; - const ascii = super.toString().replace(/-\|/g, () => { - /* we replace "----|" with "---:|" to align the data to the right in MD */ - idx++; - - if (idx < 0 || this.leftAlignedCols.includes(idx)) { - return '-|'; - } - - return ':|'; - }); - - // strip the top and the bottom row (----) to make an MD table - const md = ascii.split('\n').slice(1, -1).join('\n'); - return md; - } -} - -/** - * Table Factory helper - * @param {Object} options - * @param {string} [options.title] - optional title center above the table - * @param {string[]} options.heading - table column names - * @param {number[]} [options.leftAlignedCols=[]] - indexes of columns that should be left aligned - * Pass the columns that are non numeric here - the rest will be aligned to the right - * @param {Array} [options.rows] The table can be initialized with row. Rows can also be added by `addRow` - * @returns {MDTable} - */ -MDTable.factory = ({title, heading, leftAlignedCols = [], rows = []}) => { - const table = new MDTable({title, heading, rows}); - table.leftAlignedCols = leftAlignedCols; - - /* By default we want everything aligned to the right as most values are numbers - * we just override the columns that are not right aligned */ - heading.forEach((name, idx) => table.setAlign(idx, AsciTable.RIGHT)); - leftAlignedCols.forEach((idx) => table.setAlign(idx, AsciTable.LEFT)); - - return table; -}; - -export default MDTable; diff --git a/lib/index.d.ts b/lib/index.d.ts deleted file mode 100644 index e69e736e4..000000000 --- a/lib/index.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Onyx, {OnyxUpdate, ConnectOptions} from './Onyx'; -import {CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, OnyxValue} from './types'; -import withOnyx from './withOnyx'; -import useOnyx, {UseOnyxResult, FetchStatus} from './useOnyx'; - -export default Onyx; -export { - CustomTypeOptions, - OnyxCollection, - OnyxEntry, - OnyxUpdate, - withOnyx, - ConnectOptions, - NullishDeep, - KeyValueMapping, - OnyxKey, - Selector, - WithOnyxInstanceState, - useOnyx, - UseOnyxResult, - OnyxValue, - FetchStatus, -}; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index b50e88d2e..000000000 --- a/lib/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import Onyx from './Onyx'; -import withOnyx from './withOnyx'; -import useOnyx from './useOnyx'; - -export default Onyx; -export {withOnyx, useOnyx}; diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 000000000..b16537f56 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,9 @@ +import Onyx from './Onyx'; +import type {OnyxUpdate, ConnectOptions} from './Onyx'; +import type {CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState} from './types'; +import useOnyx from './useOnyx'; +import withOnyx from './withOnyx'; + +export default Onyx; +export {withOnyx, useOnyx}; +export type {CustomTypeOptions, OnyxCollection, OnyxEntry, OnyxUpdate, ConnectOptions, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState};