This commit is contained in:
Nathan Bierema 2021-11-06 09:45:38 -04:00
parent 702c7e8103
commit 684b93052d
8 changed files with 138 additions and 60 deletions

View File

@ -8,11 +8,7 @@ import importState from './importState';
import generateId from './generateInstanceId'; import generateId from './generateInstanceId';
import { Config } from '../../browser/extension/inject/pageScript'; import { Config } from '../../browser/extension/inject/pageScript';
import { Action } from 'redux'; import { Action } from 'redux';
import { import { LiftedState, PerformAction } from '@redux-devtools/instrument';
EnhancedStore,
LiftedState,
PerformAction,
} from '@redux-devtools/instrument';
import { LibConfig } from '@redux-devtools/app/lib/actions'; import { LibConfig } from '@redux-devtools/app/lib/actions';
import { import {
ContentScriptToPageScriptMessage, ContentScriptToPageScriptMessage,
@ -527,7 +523,7 @@ export function disconnect() {
export interface ConnectResponse { export interface ConnectResponse {
init: <S, A extends Action<unknown>>( init: <S, A extends Action<unknown>>(
state: S, state: S,
liftedData: LiftedState<S, A, unknown> liftedData?: LiftedState<S, A, unknown>
) => void; ) => void;
subscribe: <S, A extends Action<unknown>>( subscribe: <S, A extends Action<unknown>>(
listener: (message: ListenerMessage<S, A>) => void listener: (message: ListenerMessage<S, A>) => void
@ -650,7 +646,7 @@ export function connect(preConfig: Config): ConnectResponse {
const init = <S, A extends Action<unknown>>( const init = <S, A extends Action<unknown>>(
state: S, state: S,
liftedData: LiftedState<S, A, unknown> liftedData?: LiftedState<S, A, unknown>
) => { ) => {
const message: InitMessage<S, A> = { const message: InitMessage<S, A> = {
type: 'INIT', type: 'INIT',

View File

@ -585,30 +585,41 @@ const preEnhancer =
const extensionCompose = const extensionCompose =
(config: Config) => (config: Config) =>
(...funcs: StoreEnhancer[]) => { (...funcs: StoreEnhancer[]): StoreEnhancer => {
return (...args: any[]) => { return (...args) => {
const instanceId = generateId(config.instanceId); const instanceId = generateId(config.instanceId);
return [preEnhancer(instanceId), ...funcs].reduceRight( return [preEnhancer(instanceId), ...funcs].reduceRight(
(composed, f) => f(composed), (composed, f) => f(composed),
(__REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId }) as any)( __REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args)
...args
)
); );
}; };
}; };
interface ReduxDevtoolsExtensionCompose {
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
(...funcs: StoreEnhancer[]): StoreEnhancer;
}
declare global { declare global {
interface Window { interface Window {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: unknown; __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: ReduxDevtoolsExtensionCompose;
} }
} }
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = (...funcs: any[]) => { function reduxDevtoolsExtensionCompose(
config: Config
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
function reduxDevtoolsExtensionCompose(
...funcs: StoreEnhancer[]
): StoreEnhancer;
function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) { if (funcs.length === 0) {
return __REDUX_DEVTOOLS_EXTENSION__(); return __REDUX_DEVTOOLS_EXTENSION__();
} }
if (funcs.length === 1 && typeof funcs[0] === 'object') { if (funcs.length === 1 && typeof funcs[0] === 'object') {
return extensionCompose(funcs[0]); return extensionCompose(funcs[0]);
} }
return extensionCompose({})(...funcs); return extensionCompose({})(...(funcs as StoreEnhancer[]));
}; }
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;

View File

@ -1,18 +1,28 @@
import { compose, StoreEnhancer } from 'redux'; import { compose, StoreEnhancer } from 'redux';
import { EnhancerOptions } from './index'; import { Config, EnhancerOptions } from './index';
declare const process: any; declare const process: {
env: {
NODE_ENV: string;
};
};
function extensionComposeStub(
config: Config
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools = export const composeWithDevTools =
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production' &&
typeof window !== 'undefined' && typeof window !== 'undefined' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: function () { : extensionComposeStub;
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
};
export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production' &&

View File

@ -180,20 +180,46 @@ export interface EnhancerOptions {
traceLimit?: number; traceLimit?: number;
} }
export interface Config extends EnhancerOptions {
type?: string;
}
interface ConnectResponse {
init: (state: unknown) => void;
send: (action: Action<unknown>, state: unknown) => void;
}
interface ReduxDevtoolsExtension {
(config?: Config): StoreEnhancer;
connect: (preConfig: Config) => ConnectResponse;
}
export interface ReduxDevtoolsExtensionCompose {
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
(...funcs: StoreEnhancer[]): StoreEnhancer;
}
declare global { declare global {
interface Window { interface Window {
__REDUX_DEVTOOLS_EXTENSION__?: (options?: EnhancerOptions) => StoreEnhancer; __REDUX_DEVTOOLS_EXTENSION__?: ReduxDevtoolsExtension;
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: ReduxDevtoolsExtensionCompose;
} }
} }
export const composeWithDevTools = function extensionComposeStub(
config: Config
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =
typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: function () { : extensionComposeStub;
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
};
export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =
typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__

View File

@ -1,23 +1,33 @@
import assign from './utils/assign'; import assign from './utils/assign';
import { compose, StoreEnhancer } from 'redux'; import {
import { EnhancerOptions } from './index'; Action,
compose,
Dispatch,
PreloadedState,
Reducer,
StoreEnhancer,
} from 'redux';
import { Config, EnhancerOptions } from './index';
function enhancer() { function enhancer(options?: EnhancerOptions): StoreEnhancer {
const config = arguments[0] || {}; const config: Config = options || {};
config.features = { pause: true, export: true, test: true }; config.features = { pause: true, export: true, test: true };
config.type = 'redux'; config.type = 'redux';
if (config.autoPause === undefined) config.autoPause = true; if (config.autoPause === undefined) config.autoPause = true;
if (config.latency === undefined) config.latency = 500; if (config.latency === undefined) config.latency = 500;
return function (createStore) { return function (createStore) {
return function (reducer, preloadedState, enhancer) { return function <S, A extends Action<unknown>>(
const store = createStore(reducer, preloadedState, enhancer); reducer: Reducer<S, A>,
preloadedState: PreloadedState<S> | undefined
) {
const store = createStore(reducer, preloadedState);
const origDispatch = store.dispatch; const origDispatch = store.dispatch;
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(config); const devTools = window.__REDUX_DEVTOOLS_EXTENSION__!.connect(config);
devTools.init(store.getState()); devTools.init(store.getState());
const dispatch = function (action) { const dispatch: Dispatch<A> = function (action) {
const r = origDispatch(action); const r = origDispatch(action);
devTools.send(action, store.getState()); devTools.send(action, store.getState());
return r; return r;
@ -29,24 +39,27 @@ function enhancer() {
}; };
} }
function composeWithEnhancer(config) { function composeWithEnhancer(config?: EnhancerOptions) {
return function () { return function (...funcs: StoreEnhancer[]) {
return compose(compose.apply(null, arguments), enhancer(config)); return compose(compose(...funcs), enhancer(config));
}; };
} }
export const composeWithDevTools = function () { export function composeWithDevTools(
config: Config
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
export function composeWithDevTools(...funcs: StoreEnhancer[]): StoreEnhancer;
export function composeWithDevTools(...funcs: [Config] | StoreEnhancer[]) {
if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) { if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
if (arguments.length === 0) return enhancer(); if (funcs.length === 0) return enhancer();
if (typeof arguments[0] === 'object') if (typeof funcs[0] === 'object') return composeWithEnhancer(funcs[0]);
return composeWithEnhancer(arguments[0]); return composeWithEnhancer()(...(funcs as StoreEnhancer[]));
return composeWithEnhancer().apply(null, arguments);
} }
if (arguments.length === 0) return undefined; if (funcs.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose; if (typeof funcs[0] === 'object') return compose;
return compose.apply(null, arguments); return compose(...(funcs as StoreEnhancer[]));
}; }
export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =
typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__

View File

@ -1,8 +1,22 @@
import { compose, StoreEnhancer } from 'redux'; import { compose, StoreEnhancer } from 'redux';
import * as logOnly from './logOnly'; import * as logOnly from './logOnly';
import { EnhancerOptions } from './index'; import { Config, EnhancerOptions } from './index';
declare const process: any; declare const process: {
env: {
NODE_ENV: string;
};
};
function extensionComposeStub(
config: Config
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
if (funcs.length === 0) return undefined;
if (typeof funcs[0] === 'object') return compose;
return compose(...(funcs as StoreEnhancer[]));
}
export const composeWithDevTools = export const composeWithDevTools =
process.env.NODE_ENV === 'production' process.env.NODE_ENV === 'production'
@ -10,11 +24,7 @@ export const composeWithDevTools =
: typeof window !== 'undefined' && : typeof window !== 'undefined' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
: function () { : extensionComposeStub;
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
};
export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer = export const devToolsEnhancer: (options?: EnhancerOptions) => StoreEnhancer =
process.env.NODE_ENV === 'production' process.env.NODE_ENV === 'production'

View File

@ -8,13 +8,17 @@ const objectKeys =
return keys; return keys;
}; };
export default function assign(obj: {}, newKey, newValue) { export default function assign<T, K extends keyof T>(
obj: T,
newKey: K,
newValue: T[K]
): T {
const keys = objectKeys(obj); const keys = objectKeys(obj);
const copy = {}; const copy: T = {} as T;
for (let i = 0, l = keys.length; i < l; i++) { for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]; const key = keys[i];
copy[key] = obj[key]; copy[key as keyof T] = obj[key as keyof T];
} }
copy[newKey] = newValue; copy[newKey] = newValue;

View File

@ -4790,6 +4790,7 @@ __metadata:
"@babel/preset-typescript": ^7.16.0 "@babel/preset-typescript": ^7.16.0
"@typescript-eslint/eslint-plugin": ^5.2.0 "@typescript-eslint/eslint-plugin": ^5.2.0
"@typescript-eslint/parser": ^5.2.0 "@typescript-eslint/parser": ^5.2.0
core-js: ^3.19.1
eslint: ^7.32.0 eslint: ^7.32.0
eslint-config-prettier: ^8.3.0 eslint-config-prettier: ^8.3.0
redux: ^4.1.2 redux: ^4.1.2
@ -11732,6 +11733,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"core-js@npm:^3.19.1":
version: 3.19.1
resolution: "core-js@npm:3.19.1"
checksum: 2f669061788dc6fea823f0433d871deeaaaacc7d68ef2748859509522a34df5c83e648c3c6a1993fed0ab188081b3cf32b957b2a1f46156a2b20bd775961ade4
languageName: node
linkType: hard
"core-util-is@npm:1.0.2": "core-util-is@npm:1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "core-util-is@npm:1.0.2" resolution: "core-util-is@npm:1.0.2"