Merge branch 'feature/actions' into 'release'

Feature/actions

See merge request theappsmith/internal-tools-client!22
This commit is contained in:
Abhinav Jha 2019-09-17 10:31:26 +00:00
commit d19c747228
17 changed files with 322 additions and 163 deletions

View File

@ -77,9 +77,11 @@
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"dotenv": "^8.1.0",
"eslint": "^6.4.0",
"eslint-config-prettier": "^6.1.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.14.3",
"icon-font-generator": "^2.1.10",
"redux-devtools": "^3.5.0"
},

View File

@ -0,0 +1,14 @@
import {
ReduxActionTypes,
ReduxAction,
} from "../constants/ReduxActionConstants";
import { ActionPayload } from "../constants/ActionConstants";
export const executeAction = (
actionPayloads?: ActionPayload[],
): ReduxAction<ActionPayload[] | undefined> => {
return {
type: ReduxActionTypes.EXECUTE_ACTION,
payload: actionPayloads,
};
};

View File

@ -1,71 +1,120 @@
import Api, { HttpMethod } from "./Api"
import { ApiResponse } from "./ApiResponses"
import { APIRequest } from './ApiRequests';
import API, { HttpMethod } from "./Api";
import { ApiResponse } from "./ApiResponses";
import { APIRequest } from "./ApiRequests";
import _ from "lodash";
export interface CreateActionRequest<T> extends APIRequest {
resourceId: string
actionConfiguration: T
resourceId: string;
actionName: string;
actionConfiguration: T;
}
export interface UpdateActionRequest<T> extends CreateActionRequest<T> {
actionId: string
actionId: string;
}
export interface APIConfig {
requestHeaders: Record<string, string>
method: HttpMethod
path: string
APIName: string
body: JSON
queryParams: Record<string, string>
resourceId: string;
actionName: string;
requestHeaders: Record<string, string>;
method: HttpMethod;
path: string;
body: JSON;
queryParams: Record<string, string>;
actionId: string;
}
export interface Property {
key: string;
value: string;
}
export interface APIConfigRequest {
headers: Property[];
httpMethod: HttpMethod;
path: string;
body: JSON;
queryParameters: Property[];
}
export interface QueryConfig {
queryString: string
queryString: string;
}
export interface ActionCreatedResponse extends ApiResponse {
actionId: string
dynamicBindingMap: Record<string, string>
}
export interface ActionUpdatedResponse extends ActionCreatedResponse {
export interface ActionCreateUpdateResponse extends ApiResponse {
actionId: string;
dynamicBindingMap: Record<string, string>;
}
export interface ExecuteActionRequest extends APIRequest {
actionId: string
dynamicBindingMap: Record<string, any>
actionId: string;
dynamicBindingMap: Record<string, any>;
}
export interface ExecuteActionResponse extends ApiResponse {
actionId: string
data: any
actionId: string;
data: any;
}
class ActionAPI extends Api {
static url = "/actions"
static createAPI(createAPI: CreateActionRequest<APIConfig>): Promise<ActionCreatedResponse> {
return Api.post(ActionAPI.url, createAPI)
class ActionAPI extends API {
static url = "v1/actions";
static createAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
const createAPI: CreateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: _.map(apiConfig.requestHeaders, (value, key) => {
return { key: key, value: value };
}),
queryParameters: _.map(apiConfig.queryParams, (value, key) => {
return { key: key, value: value };
}),
},
};
return API.post(ActionAPI.url, createAPI);
}
static updateAPI(updateAPI: UpdateActionRequest<APIConfig>): Promise<ActionUpdatedResponse> {
return Api.post(ActionAPI.url, updateAPI)
static updateAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
const updateAPI: UpdateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionId: apiConfig.actionId,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: _.map(apiConfig.requestHeaders, (value, key) => {
return { key: key, value: value };
}),
queryParameters: _.map(apiConfig.queryParams, (value, key) => {
return { key: key, value: value };
}),
},
};
return API.post(ActionAPI.url, updateAPI);
}
static createQuery(createQuery: CreateActionRequest<QueryConfig>): Promise<ActionCreatedResponse> {
return Api.post(ActionAPI.url, createQuery)
static createQuery(
createQuery: CreateActionRequest<QueryConfig>,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, createQuery);
}
static updateQuery(updateQuery: UpdateActionRequest<QueryConfig>): Promise<ActionUpdatedResponse> {
return Api.post(ActionAPI.url, updateQuery)
static updateQuery(
updateQuery: UpdateActionRequest<QueryConfig>,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, updateQuery);
}
static executeAction(executeAction: ExecuteActionRequest): Promise<ActionUpdatedResponse> {
return Api.post(ActionAPI.url, executeAction)
static executeAction(
executeAction: ExecuteActionRequest,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, executeAction);
}
}
export default ActionAPI
export default ActionAPI;

View File

@ -1,75 +1,75 @@
import { AlertType, MessageIntent } from "../widgets/AlertWidget";
export type EventType =
| "ON_CLICK"
| "ON_HOVER"
| "ON_TOGGLE"
| "ON_LOAD"
| "ON_TEXT_CHANGE"
| "ON_SUBMIT"
| "ON_CHECK_CHANGE"
| "ON_SELECT"
| "ON_DATE_SELECTED"
| "ON_DATE_RANGE_SELECTED"
export type EventType =
| "ON_CLICK"
| "ON_HOVER"
| "ON_TOGGLE"
| "ON_LOAD"
| "ON_TEXT_CHANGE"
| "ON_SUBMIT"
| "ON_CHECK_CHANGE"
| "ON_SELECT"
| "ON_DATE_SELECTED"
| "ON_DATE_RANGE_SELECTED";
export type ActionType =
export type ActionType =
| "API"
| "QUERY"
| "NAVIGATION"
| "ALERT"
| "JS_FUNCTION"
| "SET_VALUE"
| "DOWNLOAD"
| "QUERY"
| "NAVIGATION"
| "ALERT"
| "JS_FUNCTION"
| "SET_VALUE"
| "DOWNLOAD";
export interface ActionPayload {
actionType: ActionType
contextParams: Record<string, string>
actionType: ActionType;
contextParams: Record<string, string>;
}
export interface APIActionPayload extends ActionPayload {
apiId: string
apiId: string;
}
export interface QueryActionPayload extends ActionPayload {
queryId: string
queryId: string;
}
export type NavigationType = "NEW_TAB" | "INLINE"
export type NavigationType = "NEW_TAB" | "INLINE";
export interface NavigateActionPayload extends ActionPayload {
pageUrl: string
navigationType: NavigationType
pageUrl: string;
navigationType: NavigationType;
}
export interface ShowAlertActionPayload extends ActionPayload {
header: string
message: string
alertType: AlertType
intent: MessageIntent
header: string;
message: string;
alertType: AlertType;
intent: MessageIntent;
}
export interface SetValueActionPayload extends ActionPayload {
header: string
message: string
alertType: AlertType
intent: MessageIntent
header: string;
message: string;
alertType: AlertType;
intent: MessageIntent;
}
export interface ExecuteJSActionPayload extends ActionPayload {
jsFunctionId: string
jsFunctionId: string;
}
export type DownloadFiletype = "CSV" | "XLS" | "JSON" | "TXT"
export type DownloadFiletype = "CSV" | "XLS" | "JSON" | "TXT";
export interface DownloadDataActionPayload extends ActionPayload {
data: JSON
fileName: string
fileType: DownloadFiletype
data: JSON;
fileName: string;
fileType: DownloadFiletype;
}
export interface PageAction {
actionId: string
actionType: ActionType
actionName: string
dynamicBindings: string[]
}
actionId: string;
actionType: ActionType;
actionName: string;
dynamicBindings: string[];
}

View File

@ -7,7 +7,9 @@ class ButtonComponent extends React.Component<ButtonComponentProps> {
render() {
return (
<Container {...this.props}>
<Button icon={this.props.icon}>{this.props.text}</Button>
<Button icon={this.props.icon} onClick={this.props.onClick}>
{this.props.text}
</Button>
</Container>
);
}
@ -15,6 +17,7 @@ class ButtonComponent extends React.Component<ButtonComponentProps> {
interface ButtonComponentProps extends TextComponentProps {
icon?: MaybeElement;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
}
export default ButtonComponent;

View File

@ -1,7 +1,8 @@
import React from "react";
import styled from "styled-components";
import WidgetFactory from "../../utils/WidgetFactory";
import { WidgetTypes } from "../../constants/WidgetConstants";
import { WidgetTypes, RenderModes } from "../../constants/WidgetConstants";
import { WidgetFunctions } from "../../widgets/BaseWidget";
import { useDrop } from "react-dnd";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
@ -15,6 +16,7 @@ const ArtBoard = styled.div`
interface CanvasProps {
pageWidget: ContainerWidgetProps<any>;
addWidget: Function;
widgetFunctions: WidgetFunctions;
}
const Canvas = (props: CanvasProps) => {
@ -25,7 +27,12 @@ const Canvas = (props: CanvasProps) => {
return (
<React.Fragment>
<ArtBoard ref={drop}>
{props.pageWidget && WidgetFactory.createWidget(props.pageWidget)}
{props.pageWidget &&
WidgetFactory.createWidget(
props.pageWidget,
props.widgetFunctions,
RenderModes.CANVAS,
)}
</ArtBoard>
</React.Fragment>
);

View File

@ -4,6 +4,7 @@ import { XYCoord, useDragLayer } from "react-dnd";
import snapToGrid from "./snapToGrid";
import WidgetFactory from "../../utils/WidgetFactory";
import { RenderModes, WidgetType } from "../../constants/WidgetConstants";
import { ActionPayload } from "../../constants/ActionConstants";
const WrappedDragLayer = styled.div`
position: absolute;
@ -57,18 +58,21 @@ const EditorDragLayer: React.FC = () => {
}));
function renderItem() {
return WidgetFactory.createWidget({
widgetType: itemType as WidgetType,
widgetName: "",
widgetId: item.key,
topRow: 10,
leftColumn: 10,
bottomRow: 14,
rightColumn: 20,
parentColumnSpace: 1,
parentRowSpace: 1,
renderMode: RenderModes.CANVAS,
});
return WidgetFactory.createWidget(
{
widgetType: itemType as WidgetType,
widgetName: "",
widgetId: item.key,
topRow: 10,
leftColumn: 10,
bottomRow: 14,
rightColumn: 20,
parentColumnSpace: 1,
parentRowSpace: 1,
},
{ executeAction: (actionPayload?: ActionPayload[]) => {} },
RenderModes.CANVAS,
);
}
if (!isDragging) {

View File

@ -10,7 +10,9 @@ import EditorHeader from "./EditorHeader";
import CanvasWidgetsNormalizer from "../../normalizers/CanvasWidgetsNormalizer";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
import { fetchPage, addWidget } from "../../actions/pageActions";
import { executeAction } from "../../actions/widgetActions";
import { RenderModes } from "../../constants/WidgetConstants";
import { ActionPayload } from "../../constants/ActionConstants";
const CanvasContainer = styled.section`
height: 100%;
@ -44,6 +46,7 @@ const EditorWrapper = styled.div`
type EditorProps = {
pageWidget: ContainerWidgetProps<any> | any;
fetchCanvasWidgets: Function;
executeAction: (actionPayloads?: ActionPayload[]) => void;
cards: { [id: string]: WidgetCardProps[] } | any;
addPageWidget: Function;
page: string;
@ -66,6 +69,7 @@ class Editor extends Component<EditorProps> {
<Canvas
pageWidget={this.props.pageWidget}
addWidget={this.addWidgetToCanvas}
widgetFunctions={{ executeAction: this.props.executeAction }}
/>
</CanvasContainer>
</EditorWrapper>
@ -87,6 +91,8 @@ const mapStateToProps = (state: AppState): EditorReduxState => {
const mapDispatchToProps = (dispatch: any) => {
return {
executeAction: (actionPayloads?: ActionPayload[]) =>
dispatch(executeAction(actionPayloads)),
fetchCanvasWidgets: (pageId: string) =>
dispatch(fetchPage(pageId, RenderModes.CANVAS)),
addPageWidget: (pageId: string, widgetProps: WidgetProps) =>

View File

@ -1,28 +1,28 @@
import { createReducer } from "../../utils/AppsmithUtils"
import { createReducer } from "../../utils/AppsmithUtils";
import {
ReduxActionTypes,
ReduxAction,
} from "../../constants/ReduxActionConstants"
import _ from "lodash"
import { ActionCreatedResponse } from '../../api/ActionAPI'
import { PageAction } from '../../constants/ActionConstants';
} from "../../constants/ReduxActionConstants";
import _ from "lodash";
import { ActionCreateUpdateResponse } from "../../api/ActionAPI";
import { PageAction } from "../../constants/ActionConstants";
const initialState: ActionDataState = {
}
const initialState: ActionDataState = {};
export interface ActionDataState {
[name: string]: ActionCreatedResponse
[name: string]: ActionCreateUpdateResponse;
}
const actionsReducer = createReducer(initialState, {
[ReduxActionTypes.LOAD_CANVAS_ACTIONS]: (
state: ActionDataState,
action: ReduxAction<PageAction[]>
action: ReduxAction<PageAction[]>,
) => {
const actionMap = _.mapKeys(action.payload, (action: PageAction) => { return action.actionId })
return { ...state, ...actionMap }
}
})
const actionMap = _.mapKeys(action.payload, (action: PageAction) => {
return action.actionId;
});
return { ...state, ...actionMap };
},
});
export default actionsReducer
export default actionsReducer;

View File

@ -1,17 +1,15 @@
import CanvasWidgetsNormalizer from "../normalizers/CanvasWidgetsNormalizer";
import {
ReduxActionTypes,
ReduxAction,
} from "../constants/ReduxActionConstants";
import PageApi, { PageResponse, PageRequest } from "../api/PageApi";
import { call, put, takeEvery, select, all } from "redux-saga/effects";
import { RenderModes } from "../constants/WidgetConstants";
import { call, takeEvery, select, all } from "redux-saga/effects";
import {
APIActionPayload,
QueryActionPayload,
PageAction,
ActionPayload,
} from "../constants/ActionConstants";
import ActionAPI, { ActionCreatedResponse } from "../api/ActionAPI";
import ActionAPI, { ActionCreateUpdateResponse } from "../api/ActionAPI";
import { AppState } from "../reducers";
import { JSONPath } from "jsonpath-plus";
import _ from "lodash";
@ -23,21 +21,21 @@ const getDataTree = (state: AppState) => {
const getAction = (
state: AppState,
actionId: string,
): ActionCreatedResponse => {
): ActionCreateUpdateResponse => {
return state.entities.actions[actionId];
};
export function* evaluateJSONPath(jsonPath: string): any {
export function* evaluateJSONPathSaga(jsonPath: string): any {
const dataTree = yield select(getDataTree);
const result = JSONPath({ path: jsonPath, json: dataTree });
return result;
}
export function* executeAPIAction(apiAction: APIActionPayload) {
export function* executeAPIActionSaga(apiAction: APIActionPayload) {
const api: PageAction = yield select(getAction, apiAction.apiId);
const responses: any = yield all(
api.dynamicBindings.map((jsonPath: string) => {
return call(evaluateJSONPath, jsonPath);
return call(evaluateJSONPathSaga, jsonPath);
}),
);
const dynamicBindingMap: Record<string, any> = _.keyBy(
@ -52,11 +50,11 @@ export function* executeAPIAction(apiAction: APIActionPayload) {
});
}
export function* executeQueryAction(queryAction: QueryActionPayload) {
export function* executeQueryActionSaga(queryAction: QueryActionPayload) {
const query: PageAction = yield select(getAction, queryAction.queryId);
const responses: any = yield all(
query.dynamicBindings.map((jsonPath: string) => {
return call(evaluateJSONPath, jsonPath);
return call(evaluateJSONPathSaga, jsonPath);
}),
);
const dynamicBindingMap: Record<string, any> = _.keyBy(
@ -71,28 +69,21 @@ export function* executeQueryAction(queryAction: QueryActionPayload) {
});
}
export function* executeAction(pageRequestAction: ReduxAction<PageRequest>) {
const pageRequest = pageRequestAction.payload;
try {
const pageResponse: PageResponse = yield call(
PageApi.fetchPage,
pageRequest,
export function* executeActionSaga(action: ReduxAction<ActionPayload[]>) {
if (!_.isNil(action.payload)) {
yield all(
action.payload.map((actionPayload: ActionPayload) => {
switch (actionPayload.actionType) {
case "API":
const apiActionPaylod: APIActionPayload = actionPayload as APIActionPayload;
return call(executeAPIActionSaga, apiActionPaylod);
}
return undefined;
}),
);
if (pageRequest.renderMode === RenderModes.CANVAS) {
const normalizedResponse = CanvasWidgetsNormalizer.normalize(
pageResponse,
);
const payload = {
pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets,
};
yield put({ type: ReduxActionTypes.UPDATE_CANVAS, payload });
}
} catch (err) {
//TODO(abhinav): REFACTOR THIS
}
}
export function* watchExecuteAction() {
yield takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeAction);
export function* watchExecuteActionSaga() {
yield takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeActionSaga);
}

View File

@ -36,6 +36,6 @@ export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) {
}
}
export function* watchFetchPage() {
export function* watchFetchPageSaga() {
yield takeEvery(ReduxActionTypes.FETCH_PAGE, fetchPageSaga);
}

View File

@ -1,12 +1,12 @@
import { all, spawn } from "redux-saga/effects";
import { watchFetchPage } from "../sagas/PageSagas";
import { watchFetchPageSaga } from "../sagas/PageSagas";
import { fetchWidgetCardsSaga } from "./WidgetCardsPaneSagas";
import { watchExecuteAction } from "./ActionSagas";
import { watchExecuteActionSaga } from "./ActionSagas";
export function* rootSaga() {
yield all([
spawn(watchFetchPage),
spawn(watchFetchPageSaga),
spawn(fetchWidgetCardsSaga),
spawn(watchExecuteAction),
spawn(watchExecuteActionSaga),
]);
}

View File

@ -1,5 +1,10 @@
import { WidgetType } from "../constants/WidgetConstants";
import { WidgetBuilder, WidgetProps } from "../widgets/BaseWidget";
import { WidgetType, RenderMode } from "../constants/WidgetConstants";
import {
WidgetBuilder,
WidgetProps,
WidgetFunctions,
WidgetDataProps,
} from "../widgets/BaseWidget";
class WidgetFactory {
static widgetMap: Map<WidgetType, WidgetBuilder<WidgetProps>> = new Map();
@ -11,11 +16,22 @@ class WidgetFactory {
this.widgetMap.set(widgetType, widgetBuilder);
}
static createWidget(widgetData: WidgetProps): JSX.Element {
widgetData.key = widgetData.widgetId;
static createWidget(
widgetData: WidgetDataProps,
widgetFunctions: WidgetFunctions,
renderMode: RenderMode,
): JSX.Element {
const widgetProps: WidgetProps = {
key: widgetData.widgetId,
renderMode: renderMode,
...widgetData,
...widgetFunctions,
};
const widgetBuilder = this.widgetMap.get(widgetData.widgetType);
if (widgetBuilder) return widgetBuilder.buildWidget(widgetData);
else {
if (widgetBuilder) {
const widget = widgetBuilder.buildWidget(widgetProps);
return widget;
} else {
const ex: WidgetCreationException = {
message:
"Widget Builder not registered for widget type" +

View File

@ -14,9 +14,10 @@ import { BaseStyle } from "../editorComponents/BaseComponent";
import _ from "lodash";
import React from "react";
import DraggableComponent from "../editorComponents/DraggableComponent";
import { ActionPayload } from "../constants/ActionConstants";
abstract class BaseWidget<
T extends WidgetProps,
T extends WidgetProps & WidgetFunctions,
K extends WidgetState
> extends Component<T, K> {
constructor(props: T) {
@ -147,24 +148,31 @@ export interface DraggableWidget {
}
export interface WidgetBuilder<T extends WidgetProps> {
buildWidget(data: T): JSX.Element;
buildWidget(widgetProps: T): JSX.Element;
}
export interface WidgetProps {
export interface WidgetProps extends WidgetFunctions, WidgetDataProps {
key?: string;
renderMode: RenderMode;
}
export interface WidgetDataProps {
widgetId: string;
widgetType: WidgetType;
widgetName: string;
key?: string;
topRow: number;
leftColumn: number;
bottomRow: number;
rightColumn: number;
parentColumnSpace: number;
parentRowSpace: number;
renderMode: RenderMode;
isVisible?: boolean;
}
export interface WidgetFunctions {
executeAction: (actionPayloads?: ActionPayload[]) => void;
}
export interface WidgetCardProps {
widgetType: WidgetType;
key?: string;

View File

@ -5,13 +5,20 @@ import ButtonComponent from "../editorComponents/ButtonComponent";
import { ActionPayload } from "../constants/ActionConstants";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
onButtonClick() {
this.props.executeAction(this.props.onClick);
}
getPageView() {
return (
<ButtonComponent
style={this.getPositionStyle()}
widgetId={this.props.widgetId}
key={this.props.widgetId}
text={this.props.text || "Button"}
text={this.props.text}
onClick={() => {
this.onButtonClick();
}}
/>
);
}

View File

@ -1,5 +1,9 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import BaseWidget, {
WidgetProps,
WidgetState,
WidgetFunctions,
} from "./BaseWidget";
import ContainerComponent from "../editorComponents/ContainerComponent";
import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants";
import WidgetFactory from "../utils/WidgetFactory";
@ -49,7 +53,12 @@ class ContainerWidget extends BaseWidget<
renderChildWidget(childWidgetData: WidgetProps) {
childWidgetData.parentColumnSpace = this.state.snapColumnSpace;
childWidgetData.parentRowSpace = this.state.snapRowSpace;
return WidgetFactory.createWidget(childWidgetData);
const widgetFunctions: WidgetFunctions = this.props as WidgetFunctions;
return WidgetFactory.createWidget(
childWidgetData,
widgetFunctions,
this.props.renderMode,
);
}
getPageView() {

View File

@ -4411,7 +4411,7 @@ eslint-plugin-react-hooks@^1.6.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==
eslint-plugin-react@7.14.3:
eslint-plugin-react@7.14.3, eslint-plugin-react@^7.14.3:
version "7.14.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13"
integrity sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==
@ -4505,6 +4505,49 @@ eslint@^6.1.0, eslint@^6.4.0:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
eslint@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a"
integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==
dependencies:
"@babel/code-frame" "^7.0.0"
ajv "^6.10.0"
chalk "^2.1.0"
cross-spawn "^6.0.5"
debug "^4.0.1"
doctrine "^3.0.0"
eslint-scope "^5.0.0"
eslint-utils "^1.4.2"
eslint-visitor-keys "^1.1.0"
espree "^6.1.1"
esquery "^1.0.1"
esutils "^2.0.2"
file-entry-cache "^5.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
globals "^11.7.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
inquirer "^6.4.1"
is-glob "^4.0.0"
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0"
lodash "^4.17.14"
minimatch "^3.0.4"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
progress "^2.0.0"
regexpp "^2.0.1"
semver "^6.1.2"
strip-ansi "^5.2.0"
strip-json-comments "^3.0.1"
table "^5.2.3"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de"