mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-23 06:29:51 +03:00
finish
This commit is contained in:
parent
407a5bac43
commit
463e4db8df
|
@ -2,10 +2,10 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createDevTools } from 'redux-devtools';
|
import { createDevTools } from 'redux-devtools';
|
||||||
import DockMonitor from 'redux-devtools-dock-monitor';
|
import DockMonitor from 'redux-devtools-dock-monitor';
|
||||||
|
import { Location } from 'history';
|
||||||
import DevtoolsInspector from '../../../src/DevtoolsInspector';
|
import DevtoolsInspector from '../../../src/DevtoolsInspector';
|
||||||
import getOptions from './getOptions';
|
import getOptions from './getOptions';
|
||||||
import { base16Themes } from '../../../src/utils/createStylingFromTheme';
|
import { base16Themes } from '../../../src/utils/createStylingFromTheme';
|
||||||
import { Location } from 'history';
|
|
||||||
import { DemoAppState } from './reducers';
|
import { DemoAppState } from './reducers';
|
||||||
|
|
||||||
const CustomComponent = () => (
|
const CustomComponent = () => (
|
||||||
|
|
|
@ -194,7 +194,7 @@ const createRootReducer = (
|
||||||
): Reducer<DemoAppState, DemoAppAction> =>
|
): Reducer<DemoAppState, DemoAppAction> =>
|
||||||
combineReducers<DemoAppState, DemoAppAction>({
|
combineReducers<DemoAppState, DemoAppAction>({
|
||||||
router: connectRouter(history) as Reducer<RouterState, DemoAppAction>,
|
router: connectRouter(history) as Reducer<RouterState, DemoAppAction>,
|
||||||
timeoutUpdateEnabled: (state = false, action: DemoAppAction) =>
|
timeoutUpdateEnabled: (state = false, action) =>
|
||||||
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
||||||
? action.timeoutUpdateEnabled
|
? action.timeoutUpdateEnabled
|
||||||
: state,
|
: state,
|
||||||
|
@ -207,7 +207,7 @@ const createRootReducer = (
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
) => state,
|
) => state,
|
||||||
array: (state = [], action: DemoAppAction) =>
|
array: (state = [], action) =>
|
||||||
action.type === 'PUSH'
|
action.type === 'PUSH'
|
||||||
? [...state, Math.random()]
|
? [...state, Math.random()]
|
||||||
: action.type === 'POP'
|
: action.type === 'POP'
|
||||||
|
@ -215,13 +215,13 @@ const createRootReducer = (
|
||||||
: action.type === 'REPLACE'
|
: action.type === 'REPLACE'
|
||||||
? [Math.random(), ...state.slice(1)]
|
? [Math.random(), ...state.slice(1)]
|
||||||
: state,
|
: state,
|
||||||
hugeArrays: (state = [], action: DemoAppAction) =>
|
hugeArrays: (state = [], action) =>
|
||||||
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
||||||
hugeObjects: (state = [], action: DemoAppAction) =>
|
hugeObjects: (state = [], action) =>
|
||||||
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
||||||
iterators: (state = [], action: DemoAppAction) =>
|
iterators: (state = [], action) =>
|
||||||
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
||||||
nested: (state = NESTED, action: DemoAppAction) =>
|
nested: (state = NESTED, action) =>
|
||||||
action.type === 'CHANGE_NESTED'
|
action.type === 'CHANGE_NESTED'
|
||||||
? {
|
? {
|
||||||
...state,
|
...state,
|
||||||
|
@ -238,29 +238,26 @@ const createRootReducer = (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: state,
|
: state,
|
||||||
recursive: (state: { obj?: unknown }[] = [], action: DemoAppAction) =>
|
recursive: (state: { obj?: unknown }[] = [], action) =>
|
||||||
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
||||||
immutables: (
|
immutables: (state: Immutable.Map<string, unknown>[] = [], action) =>
|
||||||
state: Immutable.Map<string, unknown>[] = [],
|
|
||||||
action: DemoAppAction
|
|
||||||
) =>
|
|
||||||
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
||||||
maps: (state: Map<string, MapValue>[] = [], action: DemoAppAction) =>
|
maps: (state: Map<string, MapValue>[] = [], action) =>
|
||||||
action.type === 'ADD_NATIVE_MAP' ? [...state, NATIVE_MAP] : state,
|
action.type === 'ADD_NATIVE_MAP' ? [...state, NATIVE_MAP] : state,
|
||||||
immutableNested: (state = IMMUTABLE_NESTED, action: DemoAppAction) =>
|
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
||||||
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
||||||
? state.updateIn(
|
? state.updateIn(
|
||||||
['long', 'nested', 0, 'path', 'to', 'a'],
|
['long', 'nested', 0, 'path', 'to', 'a'],
|
||||||
(str: string) => str + '!'
|
(str: string) => str + '!'
|
||||||
)
|
)
|
||||||
: state,
|
: state,
|
||||||
addFunction: (state = null, action: DemoAppAction) =>
|
addFunction: (state = null, action) =>
|
||||||
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
||||||
addSymbol: (state = null, action: DemoAppAction) =>
|
addSymbol: (state = null, action) =>
|
||||||
action.type === 'ADD_SYMBOL'
|
action.type === 'ADD_SYMBOL'
|
||||||
? { s: window.Symbol('symbol'), error: new Error('TEST') }
|
? { s: window.Symbol('symbol'), error: new Error('TEST') }
|
||||||
: state,
|
: state,
|
||||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action: DemoAppAction) =>
|
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
||||||
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import DevtoolsInspector from './DevtoolsInspector';
|
import DevtoolsInspector from './DevtoolsInspector';
|
||||||
export default DevtoolsInspector;
|
export default DevtoolsInspector;
|
||||||
export { TabComponentProps } from './ActionPreview';
|
export { Tab, TabComponentProps } from './ActionPreview';
|
||||||
export { DevtoolsInspectorState } from './redux';
|
export { DevtoolsInspectorState } from './redux';
|
||||||
|
export { base16Themes } from './utils/createStylingFromTheme';
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "../../../../tsconfig.base.json",
|
"extends": "../../../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
"include": ["webpack.config.ts"]
|
"include": ["webpack.config.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
const path = require('path');
|
import * as path from 'path';
|
||||||
const webpack = require('webpack');
|
import * as webpack from 'webpack';
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
||||||
|
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||||
const pkg = require('./package.json');
|
import pkg from '../../package.json';
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'eval-source-map',
|
mode: process.env.NODE_ENV || 'development',
|
||||||
entry: isProduction
|
entry: isProduction
|
||||||
? ['./demo/src/js/index']
|
? ['./demo/src/js/index']
|
||||||
: [
|
: [
|
||||||
|
@ -20,39 +20,14 @@ module.exports = {
|
||||||
path: path.join(__dirname, 'demo/dist'),
|
path: path.join(__dirname, 'demo/dist'),
|
||||||
filename: 'js/bundle.js',
|
filename: 'js/bundle.js',
|
||||||
},
|
},
|
||||||
plugins: [
|
|
||||||
new CleanWebpackPlugin(),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
inject: true,
|
|
||||||
template: 'demo/src/index.html',
|
|
||||||
package: pkg,
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
].concat(
|
|
||||||
isProduction
|
|
||||||
? [
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
|
||||||
compress: { warnings: false },
|
|
||||||
output: { comments: false },
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
: [new webpack.HotModuleReplacementPlugin()]
|
|
||||||
),
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.js', '.jsx'],
|
|
||||||
},
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.(js|ts)x?$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
include: [
|
include: [
|
||||||
path.join(__dirname, 'src'),
|
path.join(__dirname, '../../src'),
|
||||||
path.join(__dirname, 'demo/src/js'),
|
path.join(__dirname, '../src/js'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -66,6 +41,22 @@ module.exports = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
inject: true,
|
||||||
|
template: 'demo/src/index.html',
|
||||||
|
package: pkg,
|
||||||
|
}),
|
||||||
|
new ForkTsCheckerWebpackPlugin({
|
||||||
|
typescript: {
|
||||||
|
configFile: 'demo/tsconfig.json',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
].concat(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()]),
|
||||||
devServer: isProduction
|
devServer: isProduction
|
||||||
? null
|
? null
|
||||||
: {
|
: {
|
||||||
|
@ -78,4 +69,5 @@ module.exports = {
|
||||||
},
|
},
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
},
|
},
|
||||||
|
devtool: 'eval-source-map',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,35 @@
|
||||||
import React from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import pkg from '../../../package.json';
|
|
||||||
import { Button, Toolbar, Spacer } from 'devui';
|
import { Button, Toolbar, Spacer } from 'devui';
|
||||||
import getOptions from './getOptions';
|
|
||||||
import { push as pushRoute } from 'connected-react-router';
|
import { push as pushRoute } from 'connected-react-router';
|
||||||
|
import pkg from '../../../package.json';
|
||||||
|
import getOptions from './getOptions';
|
||||||
|
import { DemoAppState } from './reducers';
|
||||||
|
import {
|
||||||
|
AddFunctionAction,
|
||||||
|
AddHugeObjectAction,
|
||||||
|
AddImmutableMapAction,
|
||||||
|
AddIteratorAction,
|
||||||
|
AddRecursiveAction,
|
||||||
|
AddSymbolAction,
|
||||||
|
ChangeImmutableNestedAction,
|
||||||
|
ChangeNestedAction,
|
||||||
|
HugePayloadAction,
|
||||||
|
IncrementAction,
|
||||||
|
PopAction,
|
||||||
|
PushAction,
|
||||||
|
PushHugeArrayAction,
|
||||||
|
ReplaceAction,
|
||||||
|
ShuffleArrayAction,
|
||||||
|
TimeoutUpdateAction,
|
||||||
|
ToggleTimeoutUpdateAction,
|
||||||
|
} from './reducers';
|
||||||
|
|
||||||
const styles = {
|
const styles: {
|
||||||
|
wrapper: CSSProperties;
|
||||||
|
muted: CSSProperties;
|
||||||
|
link: CSSProperties;
|
||||||
|
} = {
|
||||||
wrapper: {
|
wrapper: {
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
width: '450px',
|
width: '450px',
|
||||||
|
@ -24,7 +48,30 @@ const styles = {
|
||||||
|
|
||||||
const ROOT = '/'; // process.env.NODE_ENV === 'production' ? '/' : '/';
|
const ROOT = '/'; // process.env.NODE_ENV === 'production' ? '/' : '/';
|
||||||
|
|
||||||
class DemoApp extends React.Component {
|
interface Props
|
||||||
|
extends Omit<DemoAppState, 'addFunction' | 'addSymbol' | 'shuffleArray'> {
|
||||||
|
toggleTimeoutUpdate: (timeoutUpdateEnabled: boolean) => void;
|
||||||
|
timeoutUpdate: () => void;
|
||||||
|
increment: () => void;
|
||||||
|
push: () => void;
|
||||||
|
pop: () => void;
|
||||||
|
replace: () => void;
|
||||||
|
changeNested: () => void;
|
||||||
|
pushHugeArray: () => void;
|
||||||
|
addIterator: () => void;
|
||||||
|
addHugeObject: () => void;
|
||||||
|
addRecursive: () => void;
|
||||||
|
addImmutableMap: () => void;
|
||||||
|
changeImmutableNested: () => void;
|
||||||
|
hugePayload: () => void;
|
||||||
|
addFunction: () => void;
|
||||||
|
addSymbol: () => void;
|
||||||
|
shuffleArray: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DemoApp extends React.Component<Props> {
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const options = getOptions(this.props.router.location);
|
const options = getOptions(this.props.router.location);
|
||||||
|
|
||||||
|
@ -48,7 +95,7 @@ class DemoApp extends React.Component {
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Button onClick={this.props.pushHugeArray}>Push Huge Array</Button>
|
<Button onClick={this.props.pushHugeArray}>Push Huge Array</Button>
|
||||||
<Button onClick={this.props.addHugeObect}>Add Huge Object</Button>
|
<Button onClick={this.props.addHugeObject}>Add Huge Object</Button>
|
||||||
<Button onClick={this.props.hugePayload}>Huge Payload</Button>
|
<Button onClick={this.props.hugePayload}>Huge Payload</Button>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
@ -98,36 +145,40 @@ class DemoApp extends React.Component {
|
||||||
this.props.toggleTimeoutUpdate(enabled);
|
this.props.toggleTimeoutUpdate(enabled);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
this.timeout = setInterval(this.props.timeoutUpdate, 1000);
|
this.timeout = window.setInterval(this.props.timeoutUpdate, 1000);
|
||||||
} else {
|
} else {
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect((state) => state, {
|
export default connect((state: DemoAppState) => state, {
|
||||||
toggleTimeoutUpdate: (timeoutUpdateEnabled) => ({
|
toggleTimeoutUpdate: (
|
||||||
|
timeoutUpdateEnabled: boolean
|
||||||
|
): ToggleTimeoutUpdateAction => ({
|
||||||
type: 'TOGGLE_TIMEOUT_UPDATE',
|
type: 'TOGGLE_TIMEOUT_UPDATE',
|
||||||
timeoutUpdateEnabled,
|
timeoutUpdateEnabled,
|
||||||
}),
|
}),
|
||||||
timeoutUpdate: () => ({ type: 'TIMEOUT_UPDATE' }),
|
timeoutUpdate: (): TimeoutUpdateAction => ({ type: 'TIMEOUT_UPDATE' }),
|
||||||
increment: () => ({ type: 'INCREMENT' }),
|
increment: (): IncrementAction => ({ type: 'INCREMENT' }),
|
||||||
push: () => ({ type: 'PUSH' }),
|
push: (): PushAction => ({ type: 'PUSH' }),
|
||||||
pop: () => ({ type: 'POP' }),
|
pop: (): PopAction => ({ type: 'POP' }),
|
||||||
replace: () => ({ type: 'REPLACE' }),
|
replace: (): ReplaceAction => ({ type: 'REPLACE' }),
|
||||||
changeNested: () => ({ type: 'CHANGE_NESTED' }),
|
changeNested: (): ChangeNestedAction => ({ type: 'CHANGE_NESTED' }),
|
||||||
pushHugeArray: () => ({ type: 'PUSH_HUGE_ARRAY' }),
|
pushHugeArray: (): PushHugeArrayAction => ({ type: 'PUSH_HUGE_ARRAY' }),
|
||||||
addIterator: () => ({ type: 'ADD_ITERATOR' }),
|
addIterator: (): AddIteratorAction => ({ type: 'ADD_ITERATOR' }),
|
||||||
addHugeObect: () => ({ type: 'ADD_HUGE_OBJECT' }),
|
addHugeObject: (): AddHugeObjectAction => ({ type: 'ADD_HUGE_OBJECT' }),
|
||||||
addRecursive: () => ({ type: 'ADD_RECURSIVE' }),
|
addRecursive: (): AddRecursiveAction => ({ type: 'ADD_RECURSIVE' }),
|
||||||
addImmutableMap: () => ({ type: 'ADD_IMMUTABLE_MAP' }),
|
addImmutableMap: (): AddImmutableMapAction => ({ type: 'ADD_IMMUTABLE_MAP' }),
|
||||||
changeImmutableNested: () => ({ type: 'CHANGE_IMMUTABLE_NESTED' }),
|
changeImmutableNested: (): ChangeImmutableNestedAction => ({
|
||||||
hugePayload: () => ({
|
type: 'CHANGE_IMMUTABLE_NESTED',
|
||||||
|
}),
|
||||||
|
hugePayload: (): HugePayloadAction => ({
|
||||||
type: 'HUGE_PAYLOAD',
|
type: 'HUGE_PAYLOAD',
|
||||||
payload: Array.from({ length: 10000 }).map((_, i) => i),
|
payload: Array.from({ length: 10000 }).map((_, i) => i),
|
||||||
}),
|
}),
|
||||||
addFunction: () => ({ type: 'ADD_FUNCTION' }),
|
addFunction: (): AddFunctionAction => ({ type: 'ADD_FUNCTION' }),
|
||||||
addSymbol: () => ({ type: 'ADD_SYMBOL' }),
|
addSymbol: (): AddSymbolAction => ({ type: 'ADD_SYMBOL' }),
|
||||||
shuffleArray: () => ({ type: 'SHUFFLE_ARRAY' }),
|
shuffleArray: (): ShuffleArrayAction => ({ type: 'SHUFFLE_ARRAY' }),
|
||||||
pushRoute,
|
pushRoute,
|
||||||
})(DemoApp);
|
})(DemoApp);
|
|
@ -1,12 +1,18 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createDevTools } from 'redux-devtools';
|
import { createDevTools } from 'redux-devtools';
|
||||||
import InspectorMonitor from 'redux-devtools-inspector-monitor';
|
import InspectorMonitor, {
|
||||||
|
base16Themes,
|
||||||
|
Tab,
|
||||||
|
} from 'redux-devtools-inspector-monitor';
|
||||||
import DockMonitor from 'redux-devtools-dock-monitor';
|
import DockMonitor from 'redux-devtools-dock-monitor';
|
||||||
|
import { Location } from 'history';
|
||||||
import getOptions from './getOptions';
|
import getOptions from './getOptions';
|
||||||
import TestGenerator from '../../../src';
|
import TestGenerator from '../../../src';
|
||||||
|
import { DemoAppState } from './reducers';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
|
||||||
export const getDevTools = (location) =>
|
export const getDevTools = (location: { search: string }) =>
|
||||||
createDevTools(
|
createDevTools(
|
||||||
<DockMonitor
|
<DockMonitor
|
||||||
defaultIsVisible
|
defaultIsVisible
|
||||||
|
@ -15,27 +21,28 @@ export const getDevTools = (location) =>
|
||||||
changeMonitorKey="ctrl-m"
|
changeMonitorKey="ctrl-m"
|
||||||
>
|
>
|
||||||
<InspectorMonitor
|
<InspectorMonitor
|
||||||
theme={getOptions(location).theme}
|
theme={getOptions(location).theme as keyof typeof base16Themes}
|
||||||
shouldPersistState
|
|
||||||
invertTheme={!getOptions(location).dark}
|
invertTheme={!getOptions(location).dark}
|
||||||
supportImmutable={getOptions(location).supportImmutable}
|
supportImmutable={getOptions(location).supportImmutable}
|
||||||
tabs={(defaultTabs) => [
|
tabs={(defaultTabs) =>
|
||||||
{
|
[
|
||||||
name: 'Test',
|
{
|
||||||
component: TestGenerator,
|
name: 'Test',
|
||||||
},
|
component: TestGenerator,
|
||||||
...defaultTabs,
|
},
|
||||||
]}
|
...defaultTabs,
|
||||||
|
] as Tab<unknown, Action<unknown>>[]
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</DockMonitor>
|
</DockMonitor>
|
||||||
);
|
);
|
||||||
|
|
||||||
const UnconnectedDevTools = ({ location }) => {
|
const UnconnectedDevTools = ({ location }: { location: Location }) => {
|
||||||
const DevTools = getDevTools(location);
|
const DevTools = getDevTools(location);
|
||||||
return <DevTools />;
|
return <DevTools />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state: DemoAppState) => ({
|
||||||
location: state.router.location,
|
location: state.router.location,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
export default function getOptions(location) {
|
|
||||||
return {
|
|
||||||
useExtension: location.search.indexOf('ext') !== -1,
|
|
||||||
supportImmutable: location.search.indexOf('immutable') !== -1,
|
|
||||||
theme: do {
|
|
||||||
const match = location.search.match(/theme=([^&]+)/);
|
|
||||||
match ? match[1] : 'inspector';
|
|
||||||
},
|
|
||||||
dark: location.search.indexOf('dark') !== -1,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
export interface Options {
|
||||||
|
useExtension: boolean;
|
||||||
|
supportImmutable: boolean;
|
||||||
|
theme: string;
|
||||||
|
dark: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function getOptions(location: { search: string }) {
|
||||||
|
return {
|
||||||
|
useExtension: location.search.indexOf('ext') !== -1,
|
||||||
|
supportImmutable: location.search.indexOf('immutable') !== -1,
|
||||||
|
theme: getTheme(),
|
||||||
|
dark: location.search.indexOf('dark') !== -1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTheme() {
|
||||||
|
const match = /theme=([^&]+)/.exec(location.search);
|
||||||
|
return match ? match[1] : 'inspector';
|
||||||
|
}
|
|
@ -2,20 +2,26 @@ import 'devui/lib/presets';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Container } from 'devui';
|
import { Container } from 'devui';
|
||||||
import DemoApp from './DemoApp';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import createRootReducer from './reducers';
|
import {
|
||||||
import { createStore, applyMiddleware, compose } from 'redux';
|
createStore,
|
||||||
|
applyMiddleware,
|
||||||
|
compose,
|
||||||
|
StoreEnhancer,
|
||||||
|
StoreEnhancerStoreCreator,
|
||||||
|
} from 'redux';
|
||||||
import logger from 'redux-logger';
|
import logger from 'redux-logger';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router';
|
||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history';
|
||||||
import { ConnectedRouter, routerMiddleware } from 'connected-react-router';
|
import { ConnectedRouter, routerMiddleware } from 'connected-react-router';
|
||||||
import { persistState } from 'redux-devtools';
|
import { persistState } from 'redux-devtools';
|
||||||
|
import DemoApp from './DemoApp';
|
||||||
|
import createRootReducer from './reducers';
|
||||||
import getOptions from './getOptions';
|
import getOptions from './getOptions';
|
||||||
import { ConnectedDevTools, getDevTools } from './DevTools';
|
import { ConnectedDevTools, getDevTools } from './DevTools';
|
||||||
|
|
||||||
function getDebugSessionKey() {
|
function getDebugSessionKey() {
|
||||||
const matches = window.location.href.match(/[?&]debug_session=([^&#]+)\b/);
|
const matches = /[?&]debug_session=([^&#]+)\b/.exec(window.location.href);
|
||||||
return matches && matches.length > 0 ? matches[1] : null;
|
return matches && matches.length > 0 ? matches[1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,21 +35,23 @@ const DevTools = getDevTools(window.location);
|
||||||
const history = createBrowserHistory();
|
const history = createBrowserHistory();
|
||||||
|
|
||||||
const useDevtoolsExtension =
|
const useDevtoolsExtension =
|
||||||
!!window.__REDUX_DEVTOOLS_EXTENSION__ &&
|
!!((window as unknown) as { __REDUX_DEVTOOLS_EXTENSION__: unknown }) &&
|
||||||
getOptions(window.location).useExtension;
|
getOptions(window.location).useExtension;
|
||||||
|
|
||||||
const enhancer = compose(
|
const enhancer = compose(
|
||||||
applyMiddleware(logger, routerMiddleware(history)),
|
applyMiddleware(logger, routerMiddleware(history)),
|
||||||
(...args) => {
|
(next: StoreEnhancerStoreCreator) => {
|
||||||
const instrument = useDevtoolsExtension
|
const instrument = useDevtoolsExtension
|
||||||
? window.__REDUX_DEVTOOLS_EXTENSION__()
|
? ((window as unknown) as {
|
||||||
|
__REDUX_DEVTOOLS_EXTENSION__(): StoreEnhancer;
|
||||||
|
}).__REDUX_DEVTOOLS_EXTENSION__()
|
||||||
: DevTools.instrument();
|
: DevTools.instrument();
|
||||||
return instrument(...args);
|
return instrument(next);
|
||||||
},
|
},
|
||||||
persistState(getDebugSessionKey())
|
persistState(getDebugSessionKey())
|
||||||
);
|
);
|
||||||
|
|
||||||
const store = createStore(createRootReducer(history), {}, enhancer);
|
const store = createStore(createRootReducer(history), enhancer);
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
|
@ -1,125 +0,0 @@
|
||||||
import Immutable from 'immutable';
|
|
||||||
import shuffle from 'lodash.shuffle';
|
|
||||||
import { combineReducers } from 'redux';
|
|
||||||
import { connectRouter } from 'connected-react-router';
|
|
||||||
|
|
||||||
const NESTED = {
|
|
||||||
long: {
|
|
||||||
nested: [
|
|
||||||
{
|
|
||||||
path: {
|
|
||||||
to: {
|
|
||||||
a: 'key',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const IMMUTABLE_NESTED = Immutable.fromJS(NESTED);
|
|
||||||
|
|
||||||
/* eslint-disable babel/new-cap */
|
|
||||||
|
|
||||||
const IMMUTABLE_MAP = Immutable.Map({
|
|
||||||
map: Immutable.Map({ a: 1, b: 2, c: 3 }),
|
|
||||||
list: Immutable.List(['a', 'b', 'c']),
|
|
||||||
set: Immutable.Set(['a', 'b', 'c']),
|
|
||||||
stack: Immutable.Stack(['a', 'b', 'c']),
|
|
||||||
seq: Immutable.Seq([1, 2, 3, 4, 5, 6, 7, 8]),
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-enable babel/new-cap */
|
|
||||||
|
|
||||||
const HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({
|
|
||||||
str: 'key ' + key,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const HUGE_OBJECT = Array.from({ length: 5000 }).reduce(
|
|
||||||
(o, _, key) => ((o['key ' + key] = 'item ' + key), o),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
const FUNC = function (a, b, c) {
|
|
||||||
return a + b + c;
|
|
||||||
};
|
|
||||||
|
|
||||||
const RECURSIVE = {};
|
|
||||||
RECURSIVE.obj = RECURSIVE;
|
|
||||||
|
|
||||||
function createIterator() {
|
|
||||||
const iterable = {};
|
|
||||||
iterable[window.Symbol.iterator] = function* iterator() {
|
|
||||||
for (var i = 0; i < 333; i++) {
|
|
||||||
yield 'item ' + i;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return iterable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];
|
|
||||||
|
|
||||||
const createRootReducer = (history) =>
|
|
||||||
combineReducers({
|
|
||||||
router: connectRouter(history),
|
|
||||||
timeoutUpdateEnabled: (state = false, action) =>
|
|
||||||
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
|
||||||
? action.timeoutUpdateEnabled
|
|
||||||
: state,
|
|
||||||
store: (state = 0, action) =>
|
|
||||||
action.type === 'INCREMENT' ? state + 1 : state,
|
|
||||||
undefined: (state = { val: undefined }) => state,
|
|
||||||
null: (state = null) => state,
|
|
||||||
func: (state = () => {}) => state,
|
|
||||||
array: (state = [], action) =>
|
|
||||||
action.type === 'PUSH'
|
|
||||||
? [...state, Math.random()]
|
|
||||||
: action.type === 'POP'
|
|
||||||
? state.slice(0, state.length - 1)
|
|
||||||
: action.type === 'REPLACE'
|
|
||||||
? [Math.random(), ...state.slice(1)]
|
|
||||||
: state,
|
|
||||||
hugeArrays: (state = [], action) =>
|
|
||||||
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
|
||||||
hugeObjects: (state = [], action) =>
|
|
||||||
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
|
||||||
iterators: (state = [], action) =>
|
|
||||||
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
|
||||||
nested: (state = NESTED, action) =>
|
|
||||||
action.type === 'CHANGE_NESTED'
|
|
||||||
? {
|
|
||||||
...state,
|
|
||||||
long: {
|
|
||||||
nested: [
|
|
||||||
{
|
|
||||||
path: {
|
|
||||||
to: {
|
|
||||||
a: state.long.nested[0].path.to.a + '!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: state,
|
|
||||||
recursive: (state = [], action) =>
|
|
||||||
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
|
||||||
immutables: (state = [], action) =>
|
|
||||||
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
|
||||||
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
|
||||||
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
|
||||||
? state.updateIn(
|
|
||||||
['long', 'nested', 0, 'path', 'to', 'a'],
|
|
||||||
(str) => str + '!'
|
|
||||||
)
|
|
||||||
: state,
|
|
||||||
addFunction: (state = null, action) =>
|
|
||||||
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
|
||||||
addSymbol: (state = null, action) =>
|
|
||||||
action.type === 'ADD_SYMBOL' ? { s: window.Symbol('symbol') } : state,
|
|
||||||
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
|
||||||
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createRootReducer;
|
|
232
packages/redux-devtools-test-generator/demo/src/js/reducers.ts
Normal file
232
packages/redux-devtools-test-generator/demo/src/js/reducers.ts
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
import Immutable from 'immutable';
|
||||||
|
import shuffle from 'lodash.shuffle';
|
||||||
|
import { combineReducers, Reducer } from 'redux';
|
||||||
|
import {
|
||||||
|
connectRouter,
|
||||||
|
LocationChangeAction,
|
||||||
|
RouterState,
|
||||||
|
} from 'connected-react-router';
|
||||||
|
import { History } from 'history';
|
||||||
|
|
||||||
|
type Nested = { long: { nested: { path: { to: { a: string } } }[] } };
|
||||||
|
|
||||||
|
const NESTED = {
|
||||||
|
long: {
|
||||||
|
nested: [
|
||||||
|
{
|
||||||
|
path: {
|
||||||
|
to: {
|
||||||
|
a: 'key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMMUTABLE_NESTED = Immutable.fromJS(NESTED);
|
||||||
|
|
||||||
|
const IMMUTABLE_MAP = Immutable.Map({
|
||||||
|
map: Immutable.Map({ a: 1, b: 2, c: 3 }),
|
||||||
|
list: Immutable.List(['a', 'b', 'c']),
|
||||||
|
set: Immutable.Set(['a', 'b', 'c']),
|
||||||
|
stack: Immutable.Stack(['a', 'b', 'c']),
|
||||||
|
seq: Immutable.Seq([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
|
});
|
||||||
|
|
||||||
|
const HUGE_ARRAY = Array.from({ length: 5000 }).map((_, key) => ({
|
||||||
|
str: `key ${key}`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const HUGE_OBJECT = Array.from({ length: 5000 }).reduce(
|
||||||
|
(o: { [key: string]: string }, _, key) => (
|
||||||
|
(o[`key ${key}`] = `item ${key}`), o
|
||||||
|
),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const FUNC = function (a: number, b: number, c: number) {
|
||||||
|
return a + b + c;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RECURSIVE: { obj?: unknown } = {};
|
||||||
|
RECURSIVE.obj = RECURSIVE;
|
||||||
|
|
||||||
|
function createIterator() {
|
||||||
|
const iterable: { [Symbol.iterator](): IterableIterator<string> } = {
|
||||||
|
[Symbol.iterator]: function* iterator() {
|
||||||
|
for (let i = 0; i < 333; i++) {
|
||||||
|
yield `item ${i}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return iterable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_SHUFFLE_ARRAY = [0, 1, null, { id: 1 }, { id: 2 }, 'string'];
|
||||||
|
|
||||||
|
export interface ToggleTimeoutUpdateAction {
|
||||||
|
type: 'TOGGLE_TIMEOUT_UPDATE';
|
||||||
|
timeoutUpdateEnabled: boolean;
|
||||||
|
}
|
||||||
|
export interface TimeoutUpdateAction {
|
||||||
|
type: 'TIMEOUT_UPDATE';
|
||||||
|
}
|
||||||
|
export interface IncrementAction {
|
||||||
|
type: 'INCREMENT';
|
||||||
|
}
|
||||||
|
export interface PushAction {
|
||||||
|
type: 'PUSH';
|
||||||
|
}
|
||||||
|
export interface PopAction {
|
||||||
|
type: 'POP';
|
||||||
|
}
|
||||||
|
export interface ReplaceAction {
|
||||||
|
type: 'REPLACE';
|
||||||
|
}
|
||||||
|
export interface ChangeNestedAction {
|
||||||
|
type: 'CHANGE_NESTED';
|
||||||
|
}
|
||||||
|
export interface PushHugeArrayAction {
|
||||||
|
type: 'PUSH_HUGE_ARRAY';
|
||||||
|
}
|
||||||
|
export interface AddIteratorAction {
|
||||||
|
type: 'ADD_ITERATOR';
|
||||||
|
}
|
||||||
|
export interface AddHugeObjectAction {
|
||||||
|
type: 'ADD_HUGE_OBJECT';
|
||||||
|
}
|
||||||
|
export interface AddRecursiveAction {
|
||||||
|
type: 'ADD_RECURSIVE';
|
||||||
|
}
|
||||||
|
export interface AddImmutableMapAction {
|
||||||
|
type: 'ADD_IMMUTABLE_MAP';
|
||||||
|
}
|
||||||
|
export interface ChangeImmutableNestedAction {
|
||||||
|
type: 'CHANGE_IMMUTABLE_NESTED';
|
||||||
|
}
|
||||||
|
export interface HugePayloadAction {
|
||||||
|
type: 'HUGE_PAYLOAD';
|
||||||
|
payload: number[];
|
||||||
|
}
|
||||||
|
export interface AddFunctionAction {
|
||||||
|
type: 'ADD_FUNCTION';
|
||||||
|
}
|
||||||
|
export interface AddSymbolAction {
|
||||||
|
type: 'ADD_SYMBOL';
|
||||||
|
}
|
||||||
|
export interface ShuffleArrayAction {
|
||||||
|
type: 'SHUFFLE_ARRAY';
|
||||||
|
}
|
||||||
|
type DemoAppAction =
|
||||||
|
| ToggleTimeoutUpdateAction
|
||||||
|
| TimeoutUpdateAction
|
||||||
|
| IncrementAction
|
||||||
|
| PushAction
|
||||||
|
| PopAction
|
||||||
|
| ReplaceAction
|
||||||
|
| ChangeNestedAction
|
||||||
|
| PushHugeArrayAction
|
||||||
|
| AddIteratorAction
|
||||||
|
| AddHugeObjectAction
|
||||||
|
| AddRecursiveAction
|
||||||
|
| AddImmutableMapAction
|
||||||
|
| ChangeImmutableNestedAction
|
||||||
|
| HugePayloadAction
|
||||||
|
| AddFunctionAction
|
||||||
|
| AddSymbolAction
|
||||||
|
| ShuffleArrayAction
|
||||||
|
| LocationChangeAction;
|
||||||
|
|
||||||
|
export interface DemoAppState {
|
||||||
|
router: RouterState;
|
||||||
|
timeoutUpdateEnabled: boolean;
|
||||||
|
store: number;
|
||||||
|
undefined: { val: undefined };
|
||||||
|
null: null;
|
||||||
|
func: () => void;
|
||||||
|
array: number[];
|
||||||
|
hugeArrays: { str: string }[];
|
||||||
|
hugeObjects: { [key: string]: string }[];
|
||||||
|
iterators: { [Symbol.iterator](): IterableIterator<string> }[];
|
||||||
|
nested: Nested;
|
||||||
|
recursive: { obj?: unknown }[];
|
||||||
|
immutables: Immutable.Map<string, unknown>[];
|
||||||
|
immutableNested: Immutable.Map<unknown, unknown>;
|
||||||
|
addFunction: { f: (a: number, b: number, c: number) => number } | null;
|
||||||
|
addSymbol: { s: symbol; error: Error } | null;
|
||||||
|
shuffleArray: unknown[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const createRootReducer = (
|
||||||
|
history: History
|
||||||
|
): Reducer<DemoAppState, DemoAppAction> =>
|
||||||
|
combineReducers<DemoAppState, DemoAppAction>({
|
||||||
|
router: connectRouter(history) as Reducer<RouterState, DemoAppAction>,
|
||||||
|
timeoutUpdateEnabled: (state = false, action) =>
|
||||||
|
action.type === 'TOGGLE_TIMEOUT_UPDATE'
|
||||||
|
? action.timeoutUpdateEnabled
|
||||||
|
: state,
|
||||||
|
store: (state = 0, action) =>
|
||||||
|
action.type === 'INCREMENT' ? state + 1 : state,
|
||||||
|
undefined: (state = { val: undefined }) => state,
|
||||||
|
null: (state = null) => state,
|
||||||
|
func: (
|
||||||
|
state = () => {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
) => state,
|
||||||
|
array: (state = [], action) =>
|
||||||
|
action.type === 'PUSH'
|
||||||
|
? [...state, Math.random()]
|
||||||
|
: action.type === 'POP'
|
||||||
|
? state.slice(0, state.length - 1)
|
||||||
|
: action.type === 'REPLACE'
|
||||||
|
? [Math.random(), ...state.slice(1)]
|
||||||
|
: state,
|
||||||
|
hugeArrays: (state = [], action) =>
|
||||||
|
action.type === 'PUSH_HUGE_ARRAY' ? [...state, ...HUGE_ARRAY] : state,
|
||||||
|
hugeObjects: (state = [], action) =>
|
||||||
|
action.type === 'ADD_HUGE_OBJECT' ? [...state, HUGE_OBJECT] : state,
|
||||||
|
iterators: (state = [], action) =>
|
||||||
|
action.type === 'ADD_ITERATOR' ? [...state, createIterator()] : state,
|
||||||
|
nested: (state = NESTED, action) =>
|
||||||
|
action.type === 'CHANGE_NESTED'
|
||||||
|
? {
|
||||||
|
...state,
|
||||||
|
long: {
|
||||||
|
nested: [
|
||||||
|
{
|
||||||
|
path: {
|
||||||
|
to: {
|
||||||
|
a: state.long.nested[0].path.to.a + '!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: state,
|
||||||
|
recursive: (state = [], action) =>
|
||||||
|
action.type === 'ADD_RECURSIVE' ? [...state, { ...RECURSIVE }] : state,
|
||||||
|
immutables: (state = [], action) =>
|
||||||
|
action.type === 'ADD_IMMUTABLE_MAP' ? [...state, IMMUTABLE_MAP] : state,
|
||||||
|
immutableNested: (state = IMMUTABLE_NESTED, action) =>
|
||||||
|
action.type === 'CHANGE_IMMUTABLE_NESTED'
|
||||||
|
? state.updateIn(
|
||||||
|
['long', 'nested', 0, 'path', 'to', 'a'],
|
||||||
|
(str: string) => str + '!'
|
||||||
|
)
|
||||||
|
: state,
|
||||||
|
addFunction: (state = null, action) =>
|
||||||
|
action.type === 'ADD_FUNCTION' ? { f: FUNC } : state,
|
||||||
|
addSymbol: (state = null, action) =>
|
||||||
|
action.type === 'ADD_SYMBOL'
|
||||||
|
? { s: window.Symbol('symbol'), error: new Error('TEST') }
|
||||||
|
: state,
|
||||||
|
shuffleArray: (state = DEFAULT_SHUFFLE_ARRAY, action) =>
|
||||||
|
action.type === 'SHUFFLE_ARRAY' ? shuffle(state) : state,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createRootReducer;
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "../../../tsconfig.react.base.json",
|
"extends": "../../../tsconfig.react.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
"include": ["../src", "src"]
|
"include": ["../src", "src"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"extends": "../../tsconfig.react.base.json",
|
"extends": "../../tsconfig.react.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "lib"
|
"outDir": "lib",
|
||||||
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user