mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-06-28 17:03:08 +03:00
feature(redux-devtools-app/ui): add search feature to state
This commit is contained in:
parent
40b024a308
commit
9983459703
|
@ -8,6 +8,7 @@ import {
|
|||
socket,
|
||||
theme,
|
||||
StoreState,
|
||||
stateFilter,
|
||||
} from '@redux-devtools/app';
|
||||
import instances from './instancesReducer';
|
||||
import type { WindowStoreAction } from './windowStore';
|
||||
|
@ -22,6 +23,7 @@ const rootReducer: Reducer<StoreState, WindowStoreAction> =
|
|||
section,
|
||||
theme,
|
||||
connection,
|
||||
stateFilter,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
"javascript-stringify": "^2.1.0",
|
||||
"jsan": "^3.1.14",
|
||||
"jsondiffpatch": "^0.4.1",
|
||||
"jsonpath-plus": "github:80avin/JSONPath#3f59301410bad3a15e4e0f5160353d082db97faa",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"prop-types": "^15.8.1",
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
GET_REPORT_SUCCESS,
|
||||
ERROR,
|
||||
SET_PERSIST,
|
||||
SET_STATE_FILTER,
|
||||
} from '../constants/actionTypes';
|
||||
import {
|
||||
AUTH_ERROR,
|
||||
|
@ -48,6 +49,7 @@ import { MonitorStateMonitorState } from '../reducers/monitor';
|
|||
import { LiftedAction } from '@redux-devtools/core';
|
||||
import { Data } from '../reducers/reports';
|
||||
import { LiftedState } from '@redux-devtools/core';
|
||||
import { StateFilterState } from '../reducers/stateFilter';
|
||||
|
||||
let monitorReducer: (
|
||||
monitorProps: unknown,
|
||||
|
@ -82,6 +84,20 @@ export function changeTheme(data: ChangeThemeData): ChangeThemeAction {
|
|||
return { type: CHANGE_THEME, ...data.formData };
|
||||
}
|
||||
|
||||
export interface SetStateFilterAction {
|
||||
readonly type: typeof SET_STATE_FILTER;
|
||||
stateFilter: Partial<StateFilterState>;
|
||||
}
|
||||
|
||||
export function setStateFilter(
|
||||
stateFilter: SetStateFilterAction['stateFilter']
|
||||
): SetStateFilterAction {
|
||||
return {
|
||||
type: SET_STATE_FILTER,
|
||||
stateFilter,
|
||||
};
|
||||
}
|
||||
|
||||
export interface InitMonitorAction {
|
||||
type: '@@INIT_MONITOR';
|
||||
newMonitorState: unknown;
|
||||
|
@ -568,6 +584,7 @@ interface ReduxPersistRehydrateAction {
|
|||
export type StoreActionWithoutUpdateStateOrLiftedAction =
|
||||
| ChangeSectionAction
|
||||
| ChangeThemeAction
|
||||
| SetStateFilterAction
|
||||
| MonitorActionAction
|
||||
| SelectInstanceAction
|
||||
| SelectMonitorAction
|
||||
|
|
|
@ -17,6 +17,7 @@ export const TOGGLE_DISPATCHER = 'devTools/TOGGLE_DISPATCHER';
|
|||
export const EXPORT = 'devTools/EXPORT';
|
||||
export const SHOW_NOTIFICATION = 'devTools/SHOW_NOTIFICATION';
|
||||
export const CLEAR_NOTIFICATION = 'devTools/CLEAR_NOTIFICATION';
|
||||
export const SET_STATE_FILTER = 'devTools/SET_STATE_FILTER';
|
||||
|
||||
export const UPDATE_REPORTS = 'reports/UPDATE';
|
||||
export const GET_REPORT_REQUEST = 'reports/GET_REPORT_REQUEST';
|
||||
|
|
|
@ -8,12 +8,14 @@ import {
|
|||
DiffTab,
|
||||
} from '@redux-devtools/inspector-monitor';
|
||||
import { Action } from 'redux';
|
||||
import { selectMonitorTab } from '../../../actions';
|
||||
import { selectMonitorTab, setStateFilter } from '../../../actions';
|
||||
import RawTab from './RawTab';
|
||||
import ChartTab from './ChartTab';
|
||||
import VisualDiffTab from './VisualDiffTab';
|
||||
import { StoreState } from '../../../reducers';
|
||||
import { Delta } from 'jsondiffpatch';
|
||||
import { filter } from '../../../utils/searchUtils';
|
||||
import { StateFilterValue } from '@redux-devtools/ui/lib/types/StateFilter/StateFilter';
|
||||
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
|
@ -35,17 +37,35 @@ class SubTabs extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
selector = () => {
|
||||
switch (this.props.parentTab) {
|
||||
case 'Action':
|
||||
return { data: this.props.action };
|
||||
case 'Diff':
|
||||
return { data: this.props.delta };
|
||||
default:
|
||||
return { data: this.props.nextState };
|
||||
}
|
||||
filteredData = () => {
|
||||
const [data, _error] = filter(this.props.nextState as object, this.props.stateFilter);
|
||||
return data;
|
||||
};
|
||||
|
||||
treeSelector = (): Props => {
|
||||
const props = {
|
||||
...this.props,
|
||||
};
|
||||
if (this.props.nextState) props.nextState = this.filteredData();
|
||||
return props;
|
||||
};
|
||||
|
||||
selectorCreator =
|
||||
(parentTab: Props['parentTab'], selected: Props['selected']) => () => {
|
||||
if (selected === 'Tree')
|
||||
// FIXME change to (this.props.nextState ? { nextState: data } : {})
|
||||
return this.treeSelector();
|
||||
switch (parentTab) {
|
||||
case 'Action':
|
||||
return { data: this.props.action };
|
||||
case 'Diff':
|
||||
return { data: this.props.delta };
|
||||
default:
|
||||
return { data: this.filteredData() };
|
||||
}
|
||||
// {a: 1, b: {c: 2}, e: 5, c: {d: 1}, d: 2}
|
||||
};
|
||||
|
||||
updateTabs(props: Props) {
|
||||
const parentTab = props.parentTab;
|
||||
|
||||
|
@ -54,12 +74,17 @@ class SubTabs extends Component<Props> {
|
|||
{
|
||||
name: 'Tree',
|
||||
component: DiffTab,
|
||||
selector: () => this.props,
|
||||
selector: this.selectorCreator(
|
||||
this.props.parentTab,
|
||||
'Tree'
|
||||
) as () => Props,
|
||||
},
|
||||
{
|
||||
name: 'Raw',
|
||||
component: VisualDiffTab,
|
||||
selector: this.selector as () => { data?: Delta },
|
||||
selector: this.selectorCreator(this.props.parentTab, 'Raw') as () => {
|
||||
data?: Delta;
|
||||
},
|
||||
},
|
||||
];
|
||||
return;
|
||||
|
@ -69,21 +94,37 @@ class SubTabs extends Component<Props> {
|
|||
{
|
||||
name: 'Tree',
|
||||
component: parentTab === 'Action' ? ActionTab : StateTab,
|
||||
selector: () => this.props,
|
||||
selector: this.selectorCreator(
|
||||
this.props.parentTab,
|
||||
'Tree'
|
||||
) as () => Props,
|
||||
},
|
||||
{
|
||||
name: 'Chart',
|
||||
component: ChartTab,
|
||||
selector: this.selector,
|
||||
selector: this.selectorCreator(this.props.parentTab, 'Chart') as () => {
|
||||
data: unknown;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Raw',
|
||||
component: RawTab,
|
||||
selector: this.selector,
|
||||
selector: this.selectorCreator(this.props.parentTab, 'Raw') as () => {
|
||||
data: Delta;
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
setFilter = (value: StateFilterValue) => {
|
||||
this.setState({
|
||||
stateFilter: {
|
||||
isJsonPath: value.isJsonPath,
|
||||
searchString: value.searchString,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let selected = this.props.selected;
|
||||
if (selected === 'Chart' && this.props.parentTab === 'Diff')
|
||||
|
@ -94,6 +135,8 @@ class SubTabs extends Component<Props> {
|
|||
tabs={this.tabs! as any}
|
||||
selected={selected || 'Tree'}
|
||||
onClick={this.props.selectMonitorTab}
|
||||
setFilter={this.props.setStateFilter}
|
||||
stateFilterValue={this.props.stateFilter}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -102,10 +145,12 @@ class SubTabs extends Component<Props> {
|
|||
const mapStateToProps = (state: StoreState) => ({
|
||||
parentTab: state.monitor.monitorState!.tabName,
|
||||
selected: state.monitor.monitorState!.subTabName,
|
||||
stateFilter: state.stateFilter,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
selectMonitorTab,
|
||||
setStateFilter,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreators)(SubTabs);
|
||||
|
|
|
@ -65,5 +65,6 @@ export * from './reducers/reports';
|
|||
export * from './reducers/section';
|
||||
export * from './reducers/socket';
|
||||
export * from './reducers/theme';
|
||||
export * from './reducers/stateFilter';
|
||||
export * from './utils/monitorActions';
|
||||
export * from './utils/stringifyJSON';
|
||||
|
|
|
@ -7,6 +7,7 @@ import { notification, NotificationState } from './notification';
|
|||
import { instances, InstancesState } from './instances';
|
||||
import { reports, ReportsState } from './reports';
|
||||
import { theme, ThemeState } from './theme';
|
||||
import { stateFilter, StateFilterState } from './stateFilter';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export interface StoreState {
|
||||
|
@ -18,6 +19,7 @@ export interface StoreState {
|
|||
readonly instances: InstancesState;
|
||||
readonly reports: ReportsState;
|
||||
readonly notification: NotificationState;
|
||||
readonly stateFilter: StateFilterState;
|
||||
}
|
||||
|
||||
export const rootReducer = combineReducers<StoreState, StoreAction>({
|
||||
|
@ -29,4 +31,5 @@ export const rootReducer = combineReducers<StoreState, StoreAction>({
|
|||
instances,
|
||||
reports,
|
||||
notification,
|
||||
stateFilter,
|
||||
});
|
||||
|
|
18
packages/redux-devtools-app/src/reducers/stateFilter.ts
Normal file
18
packages/redux-devtools-app/src/reducers/stateFilter.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { StateFilterValue } from '@redux-devtools/ui/lib/types/StateFilter/StateFilter';
|
||||
import { StoreAction } from '../actions';
|
||||
import { SET_STATE_FILTER } from '../constants/actionTypes';
|
||||
|
||||
export type StateFilterState = StateFilterValue;
|
||||
|
||||
export function stateFilter(
|
||||
state: StateFilterState = {
|
||||
isJsonPath: false,
|
||||
searchString: '',
|
||||
},
|
||||
action: StoreAction
|
||||
): StateFilterState {
|
||||
if (action.type === SET_STATE_FILTER) {
|
||||
return { ...state, ...action.stateFilter };
|
||||
}
|
||||
return state;
|
||||
}
|
78
packages/redux-devtools-app/src/utils/searchUtils.ts
Normal file
78
packages/redux-devtools-app/src/utils/searchUtils.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import { StateFilterValue } from '@redux-devtools/ui/lib/types/StateFilter/StateFilter';
|
||||
import { JSONPath } from 'jsonpath-plus';
|
||||
import _ from 'lodash';
|
||||
|
||||
type Path = string[];
|
||||
|
||||
const _filterByPaths = (obj: any, paths: Path[]) => {
|
||||
if (typeof obj !== 'object' || obj === null) return obj;
|
||||
if (paths.length === 1 && !paths[0].length) return obj;
|
||||
|
||||
// groupBy top level key and,
|
||||
// remove that key from grouped path values
|
||||
// [['a', 'b'], ['a', 'c']] => {'a': ['b', 'c']}
|
||||
const groupedTopPaths = _.mapValues(_.groupBy(paths, 0), (val) =>
|
||||
val.map((v) => v.slice(1))
|
||||
);
|
||||
const topKeys = Object.keys(groupedTopPaths);
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
obj = obj.flatMap((_, i) =>
|
||||
i in groupedTopPaths ? _filterByPaths(obj[i], groupedTopPaths[i]) : []
|
||||
);
|
||||
return obj;
|
||||
}
|
||||
if (typeof obj === 'object') obj = _.pick(obj, topKeys);
|
||||
|
||||
for (const k of topKeys) {
|
||||
if (!(k in obj)) continue;
|
||||
obj[k] = _filterByPaths(obj[k], groupedTopPaths[k]);
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
const filterByPaths = (obj: any, paths: Path[]) => {
|
||||
const sortedUniqPaths = _.sortBy(_.uniqBy(paths, JSON.stringify), ['length']);
|
||||
// remove unnecessary depths
|
||||
// [['a'], ['a', 'b']] => [['a']]
|
||||
const filteredPaths = sortedUniqPaths.filter((s, i, arr) => {
|
||||
if (i === 0) return true;
|
||||
if (!_.isEqual(arr[i].slice(0, arr[i - 1].length), arr[i - 1])) return true;
|
||||
return false;
|
||||
});
|
||||
return _filterByPaths(obj, filteredPaths);
|
||||
};
|
||||
|
||||
export const filterByJsonPath = (obj: any, jsonpath: string) => {
|
||||
const paths = JSONPath({
|
||||
json: obj,
|
||||
path: jsonpath,
|
||||
resultType: 'path',
|
||||
evalType: 'safe',
|
||||
}).map((jp: string) => JSONPath.toPathArray(jp).slice(1)) as Path[];
|
||||
|
||||
if (paths.some((path: Path) => !path.length)) return obj;
|
||||
|
||||
const result = filterByPaths(obj, paths);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export type FilterType = 'jsonpath' | 'regexp-glob';
|
||||
export type FilterResult = [any, Error | null];
|
||||
|
||||
export const filter = (
|
||||
obj: any,
|
||||
stateFilter: StateFilterValue
|
||||
): FilterResult => {
|
||||
try {
|
||||
const { isJsonPath, searchString } = stateFilter;
|
||||
if (!searchString) return [obj, null];
|
||||
|
||||
if (isJsonPath) return [filterByJsonPath(obj, searchString), null];
|
||||
else return [filterByJsonPath(obj, `$..${searchString}`), null];
|
||||
} catch (error) {
|
||||
console.error('Filter Error', error);
|
||||
return [{}, error as Error];
|
||||
}
|
||||
};
|
61
packages/redux-devtools-ui/src/StateFilter/StateFilter.tsx
Normal file
61
packages/redux-devtools-ui/src/StateFilter/StateFilter.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
import React, {
|
||||
ChangeEvent,
|
||||
MouseEventHandler,
|
||||
PureComponent,
|
||||
ReactNode,
|
||||
SyntheticEvent,
|
||||
} from 'react';
|
||||
import createStyledComponent from '../utils/createStyledComponent';
|
||||
import styles from './styles';
|
||||
|
||||
export interface StateFilterValue {
|
||||
searchString: string;
|
||||
isJsonPath: boolean;
|
||||
}
|
||||
|
||||
export interface StateFilterProps {
|
||||
value: StateFilterValue;
|
||||
onChange: (value: Partial<StateFilterValue>) => void;
|
||||
}
|
||||
|
||||
const FormContainer = createStyledComponent(styles, 'form');
|
||||
|
||||
const searchPlaceholder = 'filter state...';
|
||||
|
||||
export class StateFilter extends PureComponent<StateFilterProps> {
|
||||
handleSubmit = (e: SyntheticEvent<HTMLFormElement, SubmitEvent>) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.onChange({
|
||||
searchString: e.currentTarget.value,
|
||||
});
|
||||
};
|
||||
toggleJSONPath: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
this.props.onChange({
|
||||
isJsonPath: !this.props.value.isJsonPath,
|
||||
});
|
||||
};
|
||||
render(): ReactNode {
|
||||
const { searchString, isJsonPath } = this.props.value;
|
||||
return (
|
||||
<FormContainer onSubmit={this.handleSubmit}>
|
||||
<input
|
||||
type="search"
|
||||
onChange={this.handleChange}
|
||||
value={searchString}
|
||||
placeholder={searchPlaceholder}
|
||||
/>
|
||||
{/* <button type="reset" onClick={this.handleClear}>x</button> */}
|
||||
<button
|
||||
aria-pressed={isJsonPath}
|
||||
title="Use JSONPath to filter state"
|
||||
type="button"
|
||||
onClick={this.toggleJSONPath}
|
||||
>
|
||||
{'{;}'}
|
||||
</button>
|
||||
</FormContainer>
|
||||
);
|
||||
}
|
||||
}
|
30
packages/redux-devtools-ui/src/StateFilter/styles/index.ts
Normal file
30
packages/redux-devtools-ui/src/StateFilter/styles/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { css, ThemedStyledProps } from 'styled-components';
|
||||
|
||||
import { Theme } from '../../themes/default';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export default ({ theme }: ThemedStyledProps<{}, Theme>) => css`
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
border-bottom: 0.5px solid;
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: ${theme.base06};
|
||||
}
|
||||
input::-webkit-input-placeholder {
|
||||
color: ${theme.base06};
|
||||
opacity: 0.6;
|
||||
}
|
||||
input::-moz-placeholder {
|
||||
color: ${theme.base06};
|
||||
opacity: 0.6;
|
||||
}
|
||||
button[aria-pressed='true'] {
|
||||
filter: invert();
|
||||
}
|
||||
button:focus {
|
||||
}
|
||||
`;
|
|
@ -1,7 +1,8 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TabsHeader, { ReactButtonElement, Tab } from './TabsHeader';
|
||||
import TabsHeader, { Tab } from './TabsHeader';
|
||||
import { TabsContainer } from './styles/common';
|
||||
import { StateFilterValue } from '../StateFilter/StateFilter';
|
||||
|
||||
export type Position = 'left' | 'right' | 'center';
|
||||
|
||||
|
@ -12,6 +13,8 @@ export interface TabsProps<P> {
|
|||
onClick: (value: string) => void;
|
||||
collapsible?: boolean;
|
||||
position: Position;
|
||||
setFilter?: (value: Partial<StateFilterValue>) => void;
|
||||
stateFilterValue?: StateFilterValue;
|
||||
}
|
||||
|
||||
export default class Tabs<P extends object> extends Component<TabsProps<P>> {
|
||||
|
@ -64,6 +67,8 @@ export default class Tabs<P extends object> extends Component<TabsProps<P>> {
|
|||
onClick={this.props.onClick}
|
||||
selected={this.props.selected}
|
||||
position={this.props.position}
|
||||
setFilter={this.props.setFilter}
|
||||
stateFilterValue={this.props.stateFilterValue}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { FaAngleDoubleRight } from 'react-icons/fa';
|
|||
import ContextMenu from '../ContextMenu';
|
||||
import createStyledComponent from '../utils/createStyledComponent';
|
||||
import * as styles from './styles';
|
||||
import { StateFilter, StateFilterValue } from '../StateFilter/StateFilter';
|
||||
|
||||
const TabsWrapper = createStyledComponent(styles);
|
||||
|
||||
|
@ -20,7 +21,7 @@ export interface Tab<P> {
|
|||
selector?: (tab: this) => P;
|
||||
}
|
||||
|
||||
interface Props<P> {
|
||||
interface PropsWithoutFilter<P> {
|
||||
tabs: ReactButtonElement[];
|
||||
items: Tab<P>[];
|
||||
main: boolean | undefined;
|
||||
|
@ -30,6 +31,13 @@ interface Props<P> {
|
|||
selected: string | undefined;
|
||||
}
|
||||
|
||||
interface PropsWithFilter<P> extends PropsWithoutFilter<P> {
|
||||
setFilter: (value: Partial<StateFilterValue>) => void;
|
||||
stateFilterValue: StateFilterValue;
|
||||
}
|
||||
|
||||
type Props<P> = PropsWithoutFilter<P> | PropsWithFilter<P>;
|
||||
|
||||
interface State {
|
||||
visibleTabs: ReactButtonElement[];
|
||||
hiddenTabs: ReactButtonElement[];
|
||||
|
@ -221,6 +229,12 @@ export default class TabsHeader<P> extends Component<Props<P>, State> {
|
|||
<FaAngleDoubleRight />
|
||||
</button>
|
||||
)}
|
||||
{'setFilter' in this.props && this.props.setFilter ? (
|
||||
<StateFilter
|
||||
value={this.props.stateFilterValue}
|
||||
onChange={this.props.setFilter}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{this.props.collapsible && contextMenu && (
|
||||
<ContextMenu
|
||||
|
|
|
@ -834,6 +834,7 @@ importers:
|
|||
jest-environment-jsdom: ^29.3.1
|
||||
jsan: ^3.1.14
|
||||
jsondiffpatch: ^0.4.1
|
||||
jsonpath-plus: github:80avin/JSONPath#3f59301410bad3a15e4e0f5160353d082db97faa
|
||||
localforage: ^1.10.0
|
||||
lodash: ^4.17.21
|
||||
prop-types: ^15.8.1
|
||||
|
@ -871,6 +872,7 @@ importers:
|
|||
javascript-stringify: 2.1.0
|
||||
jsan: 3.1.14
|
||||
jsondiffpatch: 0.4.1
|
||||
jsonpath-plus: github.com/80avin/JSONPath/3f59301410bad3a15e4e0f5160353d082db97faa
|
||||
localforage: 1.10.0
|
||||
lodash: 4.17.21
|
||||
prop-types: 15.8.1
|
||||
|
@ -6041,6 +6043,24 @@ packages:
|
|||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@jsep-plugin/assignment/1.2.1_jsep@1.3.8:
|
||||
resolution: {integrity: sha512-gaHqbubTi29aZpVbBlECRpmdia+L5/lh2BwtIJTmtxdbecEyyX/ejAOg7eQDGNvGOUmPY7Z2Yxdy9ioyH/VJeA==}
|
||||
engines: {node: '>= 10.16.0'}
|
||||
peerDependencies:
|
||||
jsep: ^0.4.0||^1.0.0
|
||||
dependencies:
|
||||
jsep: 1.3.8
|
||||
dev: false
|
||||
|
||||
/@jsep-plugin/regex/1.0.3_jsep@1.3.8:
|
||||
resolution: {integrity: sha512-XfZgry4DwEZvSFtS/6Y+R48D7qJYJK6R9/yJFyUFHCIUMEEHuJ4X95TDgJp5QkmzfLYvapMPzskV5HpIDrREug==}
|
||||
engines: {node: '>= 10.16.0'}
|
||||
peerDependencies:
|
||||
jsep: ^0.4.0||^1.0.0
|
||||
dependencies:
|
||||
jsep: 1.3.8
|
||||
dev: false
|
||||
|
||||
/@leichtgewicht/ip-codec/2.0.4:
|
||||
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
|
||||
dev: true
|
||||
|
@ -12718,7 +12738,7 @@ packages:
|
|||
'@typescript-eslint/eslint-plugin': 5.47.0_ncmi6noazr3nzas7jxykisekym
|
||||
'@typescript-eslint/utils': 5.47.0_lzzuuodtsqwxnvqeq4g4likcqa
|
||||
eslint: 8.30.0
|
||||
jest: 29.3.1_@types+node@18.11.17
|
||||
jest: 29.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
@ -15981,6 +16001,11 @@ packages:
|
|||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/jsep/1.3.8:
|
||||
resolution: {integrity: sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==}
|
||||
engines: {node: '>= 10.16.0'}
|
||||
dev: false
|
||||
|
||||
/jsesc/0.5.0:
|
||||
resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
|
||||
hasBin: true
|
||||
|
@ -16057,6 +16082,7 @@ packages:
|
|||
chalk: 2.4.2
|
||||
diff-match-patch: 1.0.5
|
||||
dev: false
|
||||
bundledDependencies: []
|
||||
|
||||
/jsonfile/4.0.0:
|
||||
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
|
||||
|
@ -16587,7 +16613,7 @@ packages:
|
|||
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
chalk: 4.1.1
|
||||
chalk: 4.1.2
|
||||
is-unicode-supported: 0.1.0
|
||||
dev: false
|
||||
|
||||
|
@ -17768,7 +17794,7 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
bl: 4.1.0
|
||||
chalk: 4.1.1
|
||||
chalk: 4.1.2
|
||||
cli-cursor: 3.1.0
|
||||
cli-spinners: 2.7.0
|
||||
is-interactive: 1.0.0
|
||||
|
@ -22697,6 +22723,17 @@ packages:
|
|||
resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
|
||||
dev: true
|
||||
|
||||
github.com/80avin/JSONPath/3f59301410bad3a15e4e0f5160353d082db97faa:
|
||||
resolution: {tarball: https://codeload.github.com/80avin/JSONPath/tar.gz/3f59301410bad3a15e4e0f5160353d082db97faa}
|
||||
name: jsonpath-plus
|
||||
version: 7.2.0
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
'@jsep-plugin/assignment': 1.2.1_jsep@1.3.8
|
||||
'@jsep-plugin/regex': 1.0.3_jsep@1.3.8
|
||||
jsep: 1.3.8
|
||||
dev: false
|
||||
|
||||
github.com/Methuselah96/chalk/7e66d0ff681fc10462ce327f1c4f82bfa13193e2:
|
||||
resolution: {tarball: https://codeload.github.com/Methuselah96/chalk/tar.gz/7e66d0ff681fc10462ce327f1c4f82bfa13193e2}
|
||||
name: chalk
|
||||
|
|
Loading…
Reference in New Issue
Block a user