[Console] Clean up use of any (#95065)

* cleaned up autocomplete.ts and get_endpoint_from_postition.ts of anys

* general clean up of lowering hanging fruit

* cleaned up remaining anys, still need to test

* fix remaining TS compilation issues

* also tidy up use of "as any" and some more ": any"

* addressed type issues and introduced the default editor settings object

* clean up @ts-ignore

* added comments to interface

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Jean-Louis Leysens 2021-03-24 14:05:08 +01:00 committed by GitHub
parent 6295ae71b5
commit edfdb78957
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 402 additions and 219 deletions

View file

@ -16,7 +16,7 @@ import { i18n } from '@kbn/i18n';
interface Props { interface Props {
getCurl: () => Promise<string>; getCurl: () => Promise<string>;
getDocumentation: () => Promise<string | null>; getDocumentation: () => Promise<string | null>;
autoIndent: (ev?: React.MouseEvent) => void; autoIndent: (ev: React.MouseEvent) => void;
addNotification?: (opts: { title: string }) => void; addNotification?: (opts: { title: string }) => void;
} }
@ -84,8 +84,7 @@ export class ConsoleMenu extends Component<Props, State> {
window.open(documentation, '_blank'); window.open(documentation, '_blank');
}; };
// Using `any` here per this issue: https://github.com/elastic/eui/issues/2265 autoIndent = (event: React.MouseEvent) => {
autoIndent: any = (event: React.MouseEvent) => {
this.closePopover(); this.closePopover();
this.props.autoIndent(event); this.props.autoIndent(event);
}; };

View file

@ -32,7 +32,7 @@ export type AutocompleteOptions = 'fields' | 'indices' | 'templates';
interface Props { interface Props {
onSaveSettings: (newSettings: DevToolsSettings) => void; onSaveSettings: (newSettings: DevToolsSettings) => void;
onClose: () => void; onClose: () => void;
refreshAutocompleteSettings: (selectedSettings: any) => void; refreshAutocompleteSettings: (selectedSettings: DevToolsSettings['autocomplete']) => void;
settings: DevToolsSettings; settings: DevToolsSettings;
} }
@ -233,7 +233,7 @@ export function DevToolsSettingsModal(props: Props) {
return rest; return rest;
})} })}
idToSelectedMap={checkboxIdToSelectedMap} idToSelectedMap={checkboxIdToSelectedMap}
onChange={(e: any) => { onChange={(e: unknown) => {
onAutocompleteChange(e as AutocompleteOptions); onAutocompleteChange(e as AutocompleteOptions);
}} }}
/> />

View file

@ -53,7 +53,7 @@ export function ConsoleHistory({ close }: Props) {
const selectedReq = useRef<any>(null); const selectedReq = useRef<any>(null);
const describeReq = useMemo(() => { const describeReq = useMemo(() => {
const _describeReq = (req: any) => { const _describeReq = (req: { endpoint: string; time: string }) => {
const endpoint = req.endpoint; const endpoint = req.endpoint;
const date = moment(req.time); const date = moment(req.time);

View file

@ -20,7 +20,7 @@ import { applyCurrentSettings } from '../editor/legacy/console_editor/apply_edit
interface Props { interface Props {
settings: DevToolsSettings; settings: DevToolsSettings;
req: any | null; req: { method: string; endpoint: string; data: string; time: string } | null;
} }
export function HistoryViewer({ settings, req }: Props) { export function HistoryViewer({ settings, req }: Props) {

View file

@ -14,7 +14,7 @@ export function applyCurrentSettings(
editor: CoreEditor | CustomAceEditor, editor: CoreEditor | CustomAceEditor,
settings: DevToolsSettings settings: DevToolsSettings
) { ) {
if ((editor as any).setStyles) { if ((editor as { setStyles?: Function }).setStyles) {
(editor as CoreEditor).setStyles({ (editor as CoreEditor).setStyles({
wrapLines: settings.wrapMode, wrapLines: settings.wrapMode,
fontSize: settings.fontSize + 'px', fontSize: settings.fontSize + 'px',

View file

@ -27,7 +27,7 @@ import {
// Mocked functions // Mocked functions
import { sendRequestToES } from '../../../../hooks/use_send_current_request_to_es/send_request_to_es'; import { sendRequestToES } from '../../../../hooks/use_send_current_request_to_es/send_request_to_es';
import { getEndpointFromPosition } from '../../../../../lib/autocomplete/get_endpoint_from_position'; import { getEndpointFromPosition } from '../../../../../lib/autocomplete/get_endpoint_from_position';
import type { DevToolsSettings } from '../../../../../services';
import * as consoleMenuActions from '../console_menu_actions'; import * as consoleMenuActions from '../console_menu_actions';
import { Editor } from './editor'; import { Editor } from './editor';
@ -40,7 +40,7 @@ describe('Legacy (Ace) Console Editor Component Smoke Test', () => {
<I18nProvider> <I18nProvider>
<ServicesContextProvider value={mockedAppContextValue}> <ServicesContextProvider value={mockedAppContextValue}>
<RequestContextProvider> <RequestContextProvider>
<EditorContextProvider settings={{} as any}> <EditorContextProvider settings={({} as unknown) as DevToolsSettings}>
<Editor initialTextValue="" /> <Editor initialTextValue="" />
</EditorContextProvider> </EditorContextProvider>
</RequestContextProvider> </RequestContextProvider>

View file

@ -229,7 +229,7 @@ function EditorUI({ initialTextValue }: EditorProps) {
getDocumentation={() => { getDocumentation={() => {
return getDocumentation(editorInstanceRef.current!, docLinkVersion); return getDocumentation(editorInstanceRef.current!, docLinkVersion);
}} }}
autoIndent={(event: any) => { autoIndent={(event) => {
autoIndent(editorInstanceRef.current!, event); autoIndent(editorInstanceRef.current!, event);
}} }}
addNotification={({ title }) => notifications.toasts.add({ title })} addNotification={({ title }) => notifications.toasts.add({ title })}

View file

@ -9,7 +9,7 @@
import { getEndpointFromPosition } from '../../../../lib/autocomplete/get_endpoint_from_position'; import { getEndpointFromPosition } from '../../../../lib/autocomplete/get_endpoint_from_position';
import { SenseEditor } from '../../../models/sense_editor'; import { SenseEditor } from '../../../models/sense_editor';
export async function autoIndent(editor: SenseEditor, event: Event) { export async function autoIndent(editor: SenseEditor, event: React.MouseEvent) {
event.preventDefault(); event.preventDefault();
await editor.autoIndent(); await editor.autoIndent();
editor.getCoreEditor().getContainer().focus(); editor.getCoreEditor().getContainer().focus();

View file

@ -15,14 +15,20 @@ import { retrieveAutoCompleteInfo } from '../../lib/mappings/mappings';
import { useServicesContext, useEditorActionContext } from '../contexts'; import { useServicesContext, useEditorActionContext } from '../contexts';
import { DevToolsSettings, Settings as SettingsService } from '../../services'; import { DevToolsSettings, Settings as SettingsService } from '../../services';
const getAutocompleteDiff = (newSettings: DevToolsSettings, prevSettings: DevToolsSettings) => { const getAutocompleteDiff = (
newSettings: DevToolsSettings,
prevSettings: DevToolsSettings
): AutocompleteOptions[] => {
return Object.keys(newSettings.autocomplete).filter((key) => { return Object.keys(newSettings.autocomplete).filter((key) => {
// @ts-ignore // @ts-ignore
return prevSettings.autocomplete[key] !== newSettings.autocomplete[key]; return prevSettings.autocomplete[key] !== newSettings.autocomplete[key];
}); }) as AutocompleteOptions[];
}; };
const refreshAutocompleteSettings = (settings: SettingsService, selectedSettings: any) => { const refreshAutocompleteSettings = (
settings: SettingsService,
selectedSettings: DevToolsSettings['autocomplete']
) => {
retrieveAutoCompleteInfo(settings, selectedSettings); retrieveAutoCompleteInfo(settings, selectedSettings);
}; };
@ -44,12 +50,12 @@ const fetchAutocompleteSettingsIfNeeded = (
if (isSettingsChanged) { if (isSettingsChanged) {
// If the user has changed one of the autocomplete settings, then we'll fetch just the // If the user has changed one of the autocomplete settings, then we'll fetch just the
// ones which have changed. // ones which have changed.
const changedSettings: any = autocompleteDiff.reduce( const changedSettings: DevToolsSettings['autocomplete'] = autocompleteDiff.reduce(
(changedSettingsAccum: any, setting: string): any => { (changedSettingsAccum, setting) => {
changedSettingsAccum[setting] = newSettings.autocomplete[setting as AutocompleteOptions]; changedSettingsAccum[setting] = newSettings.autocomplete[setting];
return changedSettingsAccum; return changedSettingsAccum;
}, },
{} {} as DevToolsSettings['autocomplete']
); );
retrieveAutoCompleteInfo(settings, changedSettings); retrieveAutoCompleteInfo(settings, changedSettings);
} else if (isPollingChanged && newSettings.polling) { } else if (isPollingChanged && newSettings.polling) {
@ -89,7 +95,7 @@ export function Settings({ onClose }: Props) {
<DevToolsSettingsModal <DevToolsSettingsModal
onClose={onClose} onClose={onClose}
onSaveSettings={onSaveSettings} onSaveSettings={onSaveSettings}
refreshAutocompleteSettings={(selectedSettings: any) => refreshAutocompleteSettings={(selectedSettings) =>
refreshAutocompleteSettings(settings, selectedSettings) refreshAutocompleteSettings(settings, selectedSettings)
} }
settings={settings.toJSON()} settings={settings.toJSON()}

View file

@ -11,11 +11,11 @@ import * as editor from '../../stores/editor';
import { DevToolsSettings } from '../../../services'; import { DevToolsSettings } from '../../../services';
import { createUseContext } from '../create_use_context'; import { createUseContext } from '../create_use_context';
const EditorReadContext = createContext<editor.Store>(null as any); const EditorReadContext = createContext<editor.Store>(editor.initialValue);
const EditorActionContext = createContext<Dispatch<editor.Action>>(null as any); const EditorActionContext = createContext<Dispatch<editor.Action>>(() => {});
export interface EditorContextArgs { export interface EditorContextArgs {
children: any; children: JSX.Element;
settings: DevToolsSettings; settings: DevToolsSettings;
} }
@ -25,7 +25,7 @@ export function EditorContextProvider({ children, settings }: EditorContextArgs)
settings, settings,
})); }));
return ( return (
<EditorReadContext.Provider value={state as any}> <EditorReadContext.Provider value={state}>
<EditorActionContext.Provider value={dispatch}>{children}</EditorActionContext.Provider> <EditorActionContext.Provider value={dispatch}>{children}</EditorActionContext.Provider>
</EditorReadContext.Provider> </EditorReadContext.Provider>
); );

View file

@ -10,8 +10,8 @@ import React, { createContext, useReducer, Dispatch } from 'react';
import { createUseContext } from './create_use_context'; import { createUseContext } from './create_use_context';
import * as store from '../stores/request'; import * as store from '../stores/request';
const RequestReadContext = createContext<store.Store>(null as any); const RequestReadContext = createContext<store.Store>(store.initialValue);
const RequestActionContext = createContext<Dispatch<store.Actions>>(null as any); const RequestActionContext = createContext<Dispatch<store.Actions>>(() => {});
export function RequestContextProvider({ children }: { children: React.ReactNode }) { export function RequestContextProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(store.reducer, store.initialValue); const [state, dispatch] = useReducer(store.reducer, store.initialValue);

View file

@ -9,6 +9,7 @@
import { notificationServiceMock } from '../../../../../core/public/mocks'; import { notificationServiceMock } from '../../../../../core/public/mocks';
import { httpServiceMock } from '../../../../../core/public/mocks'; import { httpServiceMock } from '../../../../../core/public/mocks';
import type { ObjectStorageClient } from '../../../common/types';
import { HistoryMock } from '../../services/history.mock'; import { HistoryMock } from '../../services/history.mock';
import { SettingsMock } from '../../services/settings.mock'; import { SettingsMock } from '../../services/settings.mock';
import { StorageMock } from '../../services/storage.mock'; import { StorageMock } from '../../services/storage.mock';
@ -18,7 +19,7 @@ import { ContextValue } from './services_context';
export const serviceContextMock = { export const serviceContextMock = {
create: (): ContextValue => { create: (): ContextValue => {
const storage = new StorageMock({} as any, 'test'); const storage = new StorageMock(({} as unknown) as Storage, 'test');
const http = httpServiceMock.createSetupContract(); const http = httpServiceMock.createSetupContract();
const api = createApi({ http }); const api = createApi({ http });
const esHostService = createEsHostService({ api }); const esHostService = createEsHostService({ api });
@ -31,7 +32,7 @@ export const serviceContextMock = {
settings: new SettingsMock(storage), settings: new SettingsMock(storage),
history: new HistoryMock(storage), history: new HistoryMock(storage),
notifications: notificationServiceMock.createSetupContract(), notifications: notificationServiceMock.createSetupContract(),
objectStorageClient: {} as any, objectStorageClient: ({} as unknown) as ObjectStorageClient,
}, },
docLinkVersion: 'NA', docLinkVersion: 'NA',
}; };

View file

@ -30,10 +30,10 @@ export interface ContextValue {
interface ContextProps { interface ContextProps {
value: ContextValue; value: ContextValue;
children: any; children: JSX.Element;
} }
const ServicesContext = createContext<ContextValue>(null as any); const ServicesContext = createContext<ContextValue | null>(null);
export function ServicesContextProvider({ children, value }: ContextProps) { export function ServicesContextProvider({ children, value }: ContextProps) {
useEffect(() => { useEffect(() => {
@ -46,8 +46,8 @@ export function ServicesContextProvider({ children, value }: ContextProps) {
export const useServicesContext = () => { export const useServicesContext = () => {
const context = useContext(ServicesContext); const context = useContext(ServicesContext);
if (context === undefined) { if (context == null) {
throw new Error('useServicesContext must be used inside the ServicesContextProvider.'); throw new Error('useServicesContext must be used inside the ServicesContextProvider.');
} }
return context; return context!;
}; };

View file

@ -7,12 +7,10 @@
*/ */
import RowParser from '../../../lib/row_parser'; import RowParser from '../../../lib/row_parser';
import { ESRequest } from '../../../types';
import { SenseEditor } from '../../models/sense_editor'; import { SenseEditor } from '../../models/sense_editor';
/**
* This function is considered legacy and should not be changed or updated before we have editor export function restoreRequestFromHistory(editor: SenseEditor, req: ESRequest) {
* interfaces in place (it's using a customized version of Ace directly).
*/
export function restoreRequestFromHistory(editor: SenseEditor, req: any) {
const coreEditor = editor.getCoreEditor(); const coreEditor = editor.getCoreEditor();
let pos = coreEditor.getCurrentPosition(); let pos = coreEditor.getCurrentPosition();
let prefix = ''; let prefix = '';

View file

@ -8,10 +8,11 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { instance as registry } from '../../contexts/editor_context/editor_registry'; import { instance as registry } from '../../contexts/editor_context/editor_registry';
import { ESRequest } from '../../../types';
import { restoreRequestFromHistory } from './restore_request_from_history'; import { restoreRequestFromHistory } from './restore_request_from_history';
export const useRestoreRequestFromHistory = () => { export const useRestoreRequestFromHistory = () => {
return useCallback((req: any) => { return useCallback((req: ESRequest) => {
const editor = registry.getInputEditor(); const editor = registry.getInputEditor();
restoreRequestFromHistory(editor, req); restoreRequestFromHistory(editor, req);
}, []); }, []);

View file

@ -8,19 +8,14 @@
import { extractWarningMessages } from '../../../lib/utils'; import { extractWarningMessages } from '../../../lib/utils';
import { XJson } from '../../../../../es_ui_shared/public'; import { XJson } from '../../../../../es_ui_shared/public';
const { collapseLiteralStrings } = XJson;
// @ts-ignore // @ts-ignore
import * as es from '../../../lib/es/es'; import * as es from '../../../lib/es/es';
import { BaseResponseType } from '../../../types'; import { BaseResponseType } from '../../../types';
export interface EsRequestArgs { const { collapseLiteralStrings } = XJson;
requests: any;
}
export interface ESRequestObject { export interface EsRequestArgs {
path: string; requests: Array<{ url: string; method: string; data: string[] }>;
data: any;
method: string;
} }
export interface ESResponseObject<V = unknown> { export interface ESResponseObject<V = unknown> {
@ -32,7 +27,7 @@ export interface ESResponseObject<V = unknown> {
} }
export interface ESRequestResult<V = unknown> { export interface ESRequestResult<V = unknown> {
request: ESRequestObject; request: { data: string; method: string; path: string };
response: ESResponseObject<V>; response: ESResponseObject<V>;
} }
@ -61,7 +56,7 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
resolve(results); resolve(results);
return; return;
} }
const req = requests.shift(); const req = requests.shift()!;
const esPath = req.url; const esPath = req.url;
const esMethod = req.method; const esMethod = req.method;
let esData = collapseLiteralStrings(req.data.join('\n')); let esData = collapseLiteralStrings(req.data.join('\n'));
@ -71,7 +66,7 @@ export function sendRequestToES(args: EsRequestArgs): Promise<ESRequestResult[]>
const startTime = Date.now(); const startTime = Date.now();
es.send(esMethod, esPath, esData).always( es.send(esMethod, esPath, esData).always(
(dataOrjqXHR: any, textStatus: string, jqXhrORerrorThrown: any) => { (dataOrjqXHR, textStatus: string, jqXhrORerrorThrown) => {
if (reqId !== CURRENT_REQ_ID) { if (reqId !== CURRENT_REQ_ID) {
return; return;
} }

View file

@ -10,7 +10,11 @@ import { SenseEditor } from '../../models/sense_editor';
import { getEndpointFromPosition } from '../../../lib/autocomplete/get_endpoint_from_position'; import { getEndpointFromPosition } from '../../../lib/autocomplete/get_endpoint_from_position';
import { MetricsTracker } from '../../../types'; import { MetricsTracker } from '../../../types';
export const track = (requests: any[], editor: SenseEditor, trackUiMetric: MetricsTracker) => { export const track = (
requests: Array<{ method: string }>,
editor: SenseEditor,
trackUiMetric: MetricsTracker
) => {
const coreEditor = editor.getCoreEditor(); const coreEditor = editor.getCoreEditor();
// `getEndpointFromPosition` gets values from the server-side generated JSON files which // `getEndpointFromPosition` gets values from the server-side generated JSON files which
// are a combination of JS, automatically generated JSON and manual overrides. That means // are a combination of JS, automatically generated JSON and manual overrides. That means

View file

@ -26,8 +26,8 @@ import { useSendCurrentRequestToES } from './use_send_current_request_to_es';
describe('useSendCurrentRequestToES', () => { describe('useSendCurrentRequestToES', () => {
let mockContextValue: ContextValue; let mockContextValue: ContextValue;
let dispatch: (...args: any[]) => void; let dispatch: (...args: unknown[]) => void;
const contexts = ({ children }: { children?: any }) => ( const contexts = ({ children }: { children: JSX.Element }) => (
<ServicesContextProvider value={mockContextValue}>{children}</ServicesContextProvider> <ServicesContextProvider value={mockContextValue}>{children}</ServicesContextProvider>
); );

View file

@ -9,12 +9,13 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useEditorActionContext } from '../contexts/editor_context'; import { useEditorActionContext } from '../contexts/editor_context';
import { instance as registry } from '../contexts/editor_context/editor_registry'; import { instance as registry } from '../contexts/editor_context/editor_registry';
import { SenseEditor } from '../models';
export const useSetInputEditor = () => { export const useSetInputEditor = () => {
const dispatch = useEditorActionContext(); const dispatch = useEditorActionContext();
return useCallback( return useCallback(
(editor: any) => { (editor: SenseEditor) => {
dispatch({ type: 'setInputEditor', payload: editor }); dispatch({ type: 'setInputEditor', payload: editor });
registry.setInputEditor(editor); registry.setInputEditor(editor);
}, },

View file

@ -8,7 +8,7 @@
import React from 'react'; import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom'; import { render, unmountComponentAtNode } from 'react-dom';
import { HttpSetup, NotificationsSetup } from 'src/core/public'; import { HttpSetup, NotificationsSetup, I18nStart } from 'src/core/public';
import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts'; import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts';
import { Main } from './containers'; import { Main } from './containers';
import { createStorage, createHistory, createSettings } from '../services'; import { createStorage, createHistory, createSettings } from '../services';
@ -20,7 +20,7 @@ import { createApi, createEsHostService } from './lib';
export interface BootDependencies { export interface BootDependencies {
http: HttpSetup; http: HttpSetup;
docLinkVersion: string; docLinkVersion: string;
I18nContext: any; I18nContext: I18nStart['Context'];
notifications: NotificationsSetup; notifications: NotificationsSetup;
usageCollection?: UsageCollectionSetup; usageCollection?: UsageCollectionSetup;
element: HTMLElement; element: HTMLElement;

View file

@ -13,7 +13,7 @@ import * as OutputMode from './mode/output';
import smartResize from './smart_resize'; import smartResize from './smart_resize';
export interface CustomAceEditor extends ace.Editor { export interface CustomAceEditor extends ace.Editor {
update: (text: string, mode?: any, cb?: () => void) => void; update: (text: string, mode?: unknown, cb?: () => void) => void;
append: (text: string, foldPrevious?: boolean, cb?: () => void) => void; append: (text: string, foldPrevious?: boolean, cb?: () => void) => void;
} }
@ -28,9 +28,9 @@ export function createReadOnlyAceEditor(element: HTMLElement): CustomAceEditor {
output.$blockScrolling = Infinity; output.$blockScrolling = Infinity;
output.resize = smartResize(output); output.resize = smartResize(output);
output.update = (val: string, mode?: any, cb?: () => void) => { output.update = (val: string, mode?: unknown, cb?: () => void) => {
if (typeof mode === 'function') { if (typeof mode === 'function') {
cb = mode; cb = mode as () => void;
mode = void 0; mode = void 0;
} }
@ -65,7 +65,7 @@ export function createReadOnlyAceEditor(element: HTMLElement): CustomAceEditor {
(function setupSession(session) { (function setupSession(session) {
session.setMode('ace/mode/text'); session.setMode('ace/mode/text');
(session as any).setFoldStyle('markbeginend'); ((session as unknown) as { setFoldStyle: (v: string) => void }).setFoldStyle('markbeginend');
session.setTabSize(2); session.setTabSize(2);
session.setUseWrapMode(true); session.setUseWrapMode(true);
})(output.getSession()); })(output.getSession());

View file

@ -13,7 +13,7 @@ jest.mock('./mode/worker', () => {
// @ts-ignore // @ts-ignore
window.Worker = function () { window.Worker = function () {
this.postMessage = () => {}; this.postMessage = () => {};
(this as any).terminate = () => {}; ((this as unknown) as { terminate: () => void }).terminate = () => {};
}; };
// @ts-ignore // @ts-ignore

View file

@ -31,8 +31,8 @@ const rangeToAceRange = ({ start, end }: Range) =>
new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1); new _AceRange(start.lineNumber - 1, start.column - 1, end.lineNumber - 1, end.column - 1);
export class LegacyCoreEditor implements CoreEditor { export class LegacyCoreEditor implements CoreEditor {
private _aceOnPaste: any; private _aceOnPaste: Function;
$actions: any; $actions: JQuery<HTMLElement>;
resize: () => void; resize: () => void;
constructor(private readonly editor: IAceEditor, actions: HTMLElement) { constructor(private readonly editor: IAceEditor, actions: HTMLElement) {
@ -41,7 +41,9 @@ export class LegacyCoreEditor implements CoreEditor {
const session = this.editor.getSession(); const session = this.editor.getSession();
session.setMode(new InputMode.Mode()); session.setMode(new InputMode.Mode());
(session as any).setFoldStyle('markbeginend'); ((session as unknown) as { setFoldStyle: (style: string) => void }).setFoldStyle(
'markbeginend'
);
session.setTabSize(2); session.setTabSize(2);
session.setUseWrapMode(true); session.setUseWrapMode(true);
@ -72,7 +74,7 @@ export class LegacyCoreEditor implements CoreEditor {
// torn down, e.g. by closing the History tab, and we don't need to do anything further. // torn down, e.g. by closing the History tab, and we don't need to do anything further.
if (session.bgTokenizer) { if (session.bgTokenizer) {
// Wait until the bgTokenizer is done running before executing the callback. // Wait until the bgTokenizer is done running before executing the callback.
if ((session.bgTokenizer as any).running) { if (((session.bgTokenizer as unknown) as { running: boolean }).running) {
setTimeout(check, checkInterval); setTimeout(check, checkInterval);
} else { } else {
resolve(); resolve();
@ -197,7 +199,7 @@ export class LegacyCoreEditor implements CoreEditor {
.addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false); .addMarker(rangeToAceRange(range), 'ace_snippet-marker', 'fullLine', false);
} }
removeMarker(ref: any) { removeMarker(ref: number) {
this.editor.getSession().removeMarker(ref); this.editor.getSession().removeMarker(ref);
} }
@ -222,8 +224,10 @@ export class LegacyCoreEditor implements CoreEditor {
} }
isCompleterActive() { isCompleterActive() {
// Secrets of the arcane here. return Boolean(
return Boolean((this.editor as any).completer && (this.editor as any).completer.activated); ((this.editor as unknown) as { completer: { activated: unknown } }).completer &&
((this.editor as unknown) as { completer: { activated: unknown } }).completer.activated
);
} }
private forceRetokenize() { private forceRetokenize() {
@ -250,7 +254,7 @@ export class LegacyCoreEditor implements CoreEditor {
this._aceOnPaste.call(this.editor, text); this._aceOnPaste.call(this.editor, text);
} }
private setActionsBar = (value?: any, topOrBottom: 'top' | 'bottom' = 'top') => { private setActionsBar = (value: number | null, topOrBottom: 'top' | 'bottom' = 'top') => {
if (value === null) { if (value === null) {
this.$actions.css('visibility', 'hidden'); this.$actions.css('visibility', 'hidden');
} else { } else {
@ -271,7 +275,7 @@ export class LegacyCoreEditor implements CoreEditor {
}; };
private hideActionsBar = () => { private hideActionsBar = () => {
this.setActionsBar(); this.setActionsBar(null);
}; };
execCommand(cmd: string) { execCommand(cmd: string) {
@ -295,7 +299,7 @@ export class LegacyCoreEditor implements CoreEditor {
}); });
} }
legacyUpdateUI(range: any) { legacyUpdateUI(range: Range) {
if (!this.$actions) { if (!this.$actions) {
return; return;
} }
@ -360,14 +364,19 @@ export class LegacyCoreEditor implements CoreEditor {
ace.define( ace.define(
'ace/autocomplete/text_completer', 'ace/autocomplete/text_completer',
['require', 'exports', 'module'], ['require', 'exports', 'module'],
function (require: any, exports: any) { function (
exports.getCompletions = function ( require: unknown,
innerEditor: any, exports: {
session: any, getCompletions: (
pos: any, innerEditor: unknown,
prefix: any, session: unknown,
callback: any pos: unknown,
) { prefix: unknown,
callback: (e: null | Error, values: string[]) => void
) => void;
}
) {
exports.getCompletions = function (innerEditor, session, pos, prefix, callback) {
callback(null, []); callback(null, []);
}; };
} }
@ -387,7 +396,7 @@ export class LegacyCoreEditor implements CoreEditor {
DO_NOT_USE_2: IAceEditSession, DO_NOT_USE_2: IAceEditSession,
pos: { row: number; column: number }, pos: { row: number; column: number },
prefix: string, prefix: string,
callback: (...args: any[]) => void callback: (...args: unknown[]) => void
) => { ) => {
const position: Position = { const position: Position = {
lineNumber: pos.row + 1, lineNumber: pos.row + 1,

View file

@ -7,9 +7,10 @@
*/ */
import { get, throttle } from 'lodash'; import { get, throttle } from 'lodash';
import type { Editor } from 'brace';
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default function (editor: any) { export default function (editor: Editor) {
const resize = editor.resize; const resize = editor.resize;
const throttledResize = throttle(() => { const throttledResize = throttle(() => {

View file

@ -25,7 +25,7 @@ export function detectCURL(text: string) {
export function parseCURL(text: string) { export function parseCURL(text: string) {
let state = 'NONE'; let state = 'NONE';
const out = []; const out = [];
let body: any[] = []; let body: string[] = [];
let line = ''; let line = '';
const lines = text.trim().split('\n'); const lines = text.trim().split('\n');
let matches; let matches;
@ -62,7 +62,7 @@ export function parseCURL(text: string) {
} }
function unescapeLastBodyEl() { function unescapeLastBodyEl() {
const str = body.pop().replace(/\\([\\"'])/g, '$1'); const str = body.pop()!.replace(/\\([\\"'])/g, '$1');
body.push(str); body.push(str);
} }

View file

@ -7,8 +7,10 @@
*/ */
import _ from 'lodash'; import _ from 'lodash';
import RowParser from '../../../lib/row_parser';
import { XJson } from '../../../../../es_ui_shared/public'; import { XJson } from '../../../../../es_ui_shared/public';
import RowParser from '../../../lib/row_parser';
import * as utils from '../../../lib/utils'; import * as utils from '../../../lib/utils';
// @ts-ignore // @ts-ignore
@ -16,22 +18,20 @@ import * as es from '../../../lib/es/es';
import { CoreEditor, Position, Range } from '../../../types'; import { CoreEditor, Position, Range } from '../../../types';
import { createTokenIterator } from '../../factories'; import { createTokenIterator } from '../../factories';
import createAutocompleter from '../../../lib/autocomplete/autocomplete';
import Autocomplete from '../../../lib/autocomplete/autocomplete';
const { collapseLiteralStrings } = XJson; const { collapseLiteralStrings } = XJson;
export class SenseEditor { export class SenseEditor {
currentReqRange: (Range & { markerRef: any }) | null; currentReqRange: (Range & { markerRef: unknown }) | null;
parser: any; parser: RowParser;
// @ts-ignore private readonly autocomplete: ReturnType<typeof createAutocompleter>;
private readonly autocomplete: any;
constructor(private readonly coreEditor: CoreEditor) { constructor(private readonly coreEditor: CoreEditor) {
this.currentReqRange = null; this.currentReqRange = null;
this.parser = new RowParser(this.coreEditor); this.parser = new RowParser(this.coreEditor);
this.autocomplete = new (Autocomplete as any)({ this.autocomplete = createAutocompleter({
coreEditor, coreEditor,
parser: this.parser, parser: this.parser,
}); });
@ -114,7 +114,10 @@ export class SenseEditor {
return this.coreEditor.setValue(data, reTokenizeAll); return this.coreEditor.setValue(data, reTokenizeAll);
}; };
replaceRequestRange = (newRequest: any, requestRange: Range) => { replaceRequestRange = (
newRequest: { method: string; url: string; data: string | string[] },
requestRange: Range
) => {
const text = utils.textFromRequest(newRequest); const text = utils.textFromRequest(newRequest);
if (requestRange) { if (requestRange) {
this.coreEditor.replaceRange(requestRange, text); this.coreEditor.replaceRange(requestRange, text);
@ -207,12 +210,12 @@ export class SenseEditor {
const request: { const request: {
method: string; method: string;
data: string[]; data: string[];
url: string | null; url: string;
range: Range; range: Range;
} = { } = {
method: '', method: '',
data: [], data: [],
url: null, url: '',
range, range,
}; };
@ -284,7 +287,7 @@ export class SenseEditor {
return []; return [];
} }
const requests: any = []; const requests: unknown[] = [];
let rangeStartCursor = expandedRange.start.lineNumber; let rangeStartCursor = expandedRange.start.lineNumber;
const endLineNumber = expandedRange.end.lineNumber; const endLineNumber = expandedRange.end.lineNumber;

View file

@ -9,8 +9,9 @@
import { Reducer } from 'react'; import { Reducer } from 'react';
import { produce } from 'immer'; import { produce } from 'immer';
import { identity } from 'fp-ts/lib/function'; import { identity } from 'fp-ts/lib/function';
import { DevToolsSettings } from '../../services'; import { DevToolsSettings, DEFAULT_SETTINGS } from '../../services';
import { TextObject } from '../../../common/text_object'; import { TextObject } from '../../../common/text_object';
import { SenseEditor } from '../models';
export interface Store { export interface Store {
ready: boolean; ready: boolean;
@ -21,15 +22,15 @@ export interface Store {
export const initialValue: Store = produce<Store>( export const initialValue: Store = produce<Store>(
{ {
ready: false, ready: false,
settings: null as any, settings: DEFAULT_SETTINGS,
currentTextObject: null, currentTextObject: null,
}, },
identity identity
); );
export type Action = export type Action =
| { type: 'setInputEditor'; payload: any } | { type: 'setInputEditor'; payload: SenseEditor }
| { type: 'setCurrentTextObject'; payload: any } | { type: 'setCurrentTextObject'; payload: TextObject }
| { type: 'updateSettings'; payload: DevToolsSettings }; | { type: 'updateSettings'; payload: DevToolsSettings };
export const reducer: Reducer<Store, Action> = (state, action) => export const reducer: Reducer<Store, Action> = (state, action) =>

View file

@ -63,7 +63,7 @@ export class AceTokensProvider implements TokensProvider {
return null; return null;
} }
const tokens: TokenInfo[] = this.session.getTokens(lineNumber - 1) as any; const tokens = (this.session.getTokens(lineNumber - 1) as unknown) as TokenInfo[];
if (!tokens || !tokens.length) { if (!tokens || !tokens.length) {
// We are inside of the document but have no tokens for this line. Return an empty // We are inside of the document but have no tokens for this line. Return an empty
// array to represent this empty line. // array to represent this empty line.
@ -74,7 +74,7 @@ export class AceTokensProvider implements TokensProvider {
} }
getTokenAt(pos: Position): Token | null { getTokenAt(pos: Position): Token | null {
const tokens: TokenInfo[] = this.session.getTokens(pos.lineNumber - 1) as any; const tokens = (this.session.getTokens(pos.lineNumber - 1) as unknown) as TokenInfo[];
if (tokens) { if (tokens) {
return extractTokenFromAceTokenRow(pos.lineNumber, pos.column, tokens); return extractTokenFromAceTokenRow(pos.lineNumber, pos.column, tokens);
} }

View file

@ -18,19 +18,21 @@ import {
// @ts-ignore // @ts-ignore
} from '../kb/kb'; } from '../kb/kb';
import { createTokenIterator } from '../../application/factories';
import { Position, Token, Range, CoreEditor } from '../../types';
import type RowParser from '../row_parser';
import * as utils from '../utils'; import * as utils from '../utils';
// @ts-ignore // @ts-ignore
import { populateContext } from './engine'; import { populateContext } from './engine';
import { AutoCompleteContext, ResultTerm } from './types';
// @ts-ignore // @ts-ignore
import { URL_PATH_END_MARKER } from './components/index'; import { URL_PATH_END_MARKER } from './components/index';
import { createTokenIterator } from '../../application/factories';
import { Position, Token, Range, CoreEditor } from '../../types'; let lastEvaluatedToken: Token | null = null;
let lastEvaluatedToken: any = null; function isUrlParamsToken(token: { type: string } | null) {
function isUrlParamsToken(token: any) {
switch ((token || {}).type) { switch ((token || {}).type) {
case 'url.param': case 'url.param':
case 'url.equal': case 'url.equal':
@ -54,7 +56,7 @@ function isUrlParamsToken(token: any) {
export function getCurrentMethodAndTokenPaths( export function getCurrentMethodAndTokenPaths(
editor: CoreEditor, editor: CoreEditor,
pos: Position, pos: Position,
parser: any, parser: RowParser,
forceEndOfUrl?: boolean /* Flag for indicating whether we want to avoid early escape optimization. */ forceEndOfUrl?: boolean /* Flag for indicating whether we want to avoid early escape optimization. */
) { ) {
const tokenIter = createTokenIterator({ const tokenIter = createTokenIterator({
@ -62,8 +64,8 @@ export function getCurrentMethodAndTokenPaths(
position: pos, position: pos,
}); });
const startPos = pos; const startPos = pos;
let bodyTokenPath: any = []; let bodyTokenPath: string[] | null = [];
const ret: any = {}; const ret: AutoCompleteContext = {};
const STATES = { const STATES = {
looking_for_key: 0, // looking for a key but without jumping over anything but white space and colon. looking_for_key: 0, // looking for a key but without jumping over anything but white space and colon.
@ -210,7 +212,12 @@ export function getCurrentMethodAndTokenPaths(
ret.urlParamsTokenPath = null; ret.urlParamsTokenPath = null;
ret.requestStartRow = tokenIter.getCurrentPosition().lineNumber; ret.requestStartRow = tokenIter.getCurrentPosition().lineNumber;
let curUrlPart: any; let curUrlPart:
| null
| string
| Array<string | Record<string, unknown>>
| undefined
| Record<string, unknown>;
while (t && isUrlParamsToken(t)) { while (t && isUrlParamsToken(t)) {
switch (t.type) { switch (t.type) {
@ -240,7 +247,7 @@ export function getCurrentMethodAndTokenPaths(
if (!ret.urlParamsTokenPath) { if (!ret.urlParamsTokenPath) {
ret.urlParamsTokenPath = []; ret.urlParamsTokenPath = [];
} }
ret.urlParamsTokenPath.unshift(curUrlPart || {}); ret.urlParamsTokenPath.unshift((curUrlPart as Record<string, string>) || {});
curUrlPart = null; curUrlPart = null;
break; break;
} }
@ -268,7 +275,7 @@ export function getCurrentMethodAndTokenPaths(
break; break;
case 'url.slash': case 'url.slash':
if (curUrlPart) { if (curUrlPart) {
ret.urlTokenPath.unshift(curUrlPart); ret.urlTokenPath.unshift(curUrlPart as string);
curUrlPart = null; curUrlPart = null;
} }
break; break;
@ -277,7 +284,7 @@ export function getCurrentMethodAndTokenPaths(
} }
if (curUrlPart) { if (curUrlPart) {
ret.urlTokenPath.unshift(curUrlPart); ret.urlTokenPath.unshift(curUrlPart as string);
} }
if (!ret.bodyTokenPath && !ret.urlParamsTokenPath) { if (!ret.bodyTokenPath && !ret.urlParamsTokenPath) {
@ -297,9 +304,15 @@ export function getCurrentMethodAndTokenPaths(
} }
// eslint-disable-next-line // eslint-disable-next-line
export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEditor; parser: any }) { export default function ({
coreEditor: editor,
parser,
}: {
coreEditor: CoreEditor;
parser: RowParser;
}) {
function isUrlPathToken(token: Token | null) { function isUrlPathToken(token: Token | null) {
switch ((token || ({} as any)).type) { switch ((token || ({} as Token)).type) {
case 'url.slash': case 'url.slash':
case 'url.comma': case 'url.comma':
case 'url.part': case 'url.part':
@ -309,8 +322,12 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
} }
function addMetaToTermsList(list: any, meta: any, template?: string) { function addMetaToTermsList(
return _.map(list, function (t: any) { list: unknown[],
meta: unknown,
template?: string
): Array<{ meta: unknown; template: unknown; name?: string }> {
return _.map(list, function (t) {
if (typeof t !== 'object') { if (typeof t !== 'object') {
t = { name: t }; t = { name: t };
} }
@ -318,8 +335,13 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
}); });
} }
function applyTerm(term: any) { function applyTerm(term: {
const context = term.context; value?: string;
context?: AutoCompleteContext;
template?: { __raw: boolean; value: string };
insertValue?: string;
}) {
const context = term.context!;
// make sure we get up to date replacement info. // make sure we get up to date replacement info.
addReplacementInfoToContext(context, editor.getCurrentPosition(), term.insertValue); addReplacementInfoToContext(context, editor.getCurrentPosition(), term.insertValue);
@ -346,7 +368,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} else { } else {
indentedTemplateLines = utils.jsonToString(term.template, true).split('\n'); indentedTemplateLines = utils.jsonToString(term.template, true).split('\n');
} }
let currentIndentation = editor.getLineValue(context.rangeToReplace.start.lineNumber); let currentIndentation = editor.getLineValue(context.rangeToReplace!.start.lineNumber);
currentIndentation = currentIndentation.match(/^\s*/)![0]; currentIndentation = currentIndentation.match(/^\s*/)![0];
for ( for (
let i = 1; let i = 1;
@ -374,8 +396,8 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
// disable listening to the changes we are making. // disable listening to the changes we are making.
editor.off('changeSelection', editorChangeListener); editor.off('changeSelection', editorChangeListener);
if (context.rangeToReplace.start.column !== context.rangeToReplace.end.column) { if (context.rangeToReplace!.start.column !== context.rangeToReplace!.end.column) {
editor.replace(context.rangeToReplace, valueToInsert); editor.replace(context.rangeToReplace!, valueToInsert);
} else { } else {
editor.insert(valueToInsert); editor.insert(valueToInsert);
} }
@ -384,12 +406,12 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
// go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do.
let newPos = { let newPos = {
lineNumber: context.rangeToReplace.start.lineNumber, lineNumber: context.rangeToReplace!.start.lineNumber,
column: column:
context.rangeToReplace.start.column + context.rangeToReplace!.start.column +
termAsString.length + termAsString.length +
context.prefixToAdd.length + context.prefixToAdd!.length +
(templateInserted ? 0 : context.suffixToAdd.length), (templateInserted ? 0 : context.suffixToAdd!.length),
}; };
const tokenIter = createTokenIterator({ const tokenIter = createTokenIterator({
@ -406,7 +428,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
break; break;
case 'punctuation.colon': case 'punctuation.colon':
nonEmptyToken = parser.nextNonEmptyToken(tokenIter); nonEmptyToken = parser.nextNonEmptyToken(tokenIter);
if ((nonEmptyToken || ({} as any)).type === 'paren.lparen') { if ((nonEmptyToken || ({} as Token)).type === 'paren.lparen') {
nonEmptyToken = parser.nextNonEmptyToken(tokenIter); nonEmptyToken = parser.nextNonEmptyToken(tokenIter);
newPos = tokenIter.getCurrentPosition(); newPos = tokenIter.getCurrentPosition();
if (nonEmptyToken && nonEmptyToken.value.indexOf('"') === 0) { if (nonEmptyToken && nonEmptyToken.value.indexOf('"') === 0) {
@ -429,7 +451,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
function getAutoCompleteContext(ctxEditor: CoreEditor, pos: Position) { function getAutoCompleteContext(ctxEditor: CoreEditor, pos: Position) {
// deduces all the parameters need to position and insert the auto complete // deduces all the parameters need to position and insert the auto complete
const context: any = { const context: AutoCompleteContext = {
autoCompleteSet: null, // instructions for what can be here autoCompleteSet: null, // instructions for what can be here
endpoint: null, endpoint: null,
urlPath: null, urlPath: null,
@ -501,7 +523,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
case 'whitespace': case 'whitespace':
t = parser.prevNonEmptyToken(tokenIter); t = parser.prevNonEmptyToken(tokenIter);
switch ((t || ({} as any)).type) { switch ((t || ({} as Token)).type) {
case 'method': case 'method':
// we moved one back // we moved one back
return 'path'; return 'path';
@ -552,7 +574,11 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
return null; return null;
} }
function addReplacementInfoToContext(context: any, pos: Position, replacingTerm?: any) { function addReplacementInfoToContext(
context: AutoCompleteContext,
pos: Position,
replacingTerm?: unknown
) {
// extract the initial value, rangeToReplace & textBoxPosition // extract the initial value, rangeToReplace & textBoxPosition
// Scenarios for current token: // Scenarios for current token:
@ -605,7 +631,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
default: default:
if (replacingTerm && context.updatedForToken.value === replacingTerm) { if (replacingTerm && context.updatedForToken.value === replacingTerm) {
context.rangeToReplace = { context.rangeToReplace = {
start: { lineNumber: pos.lineNumber, column: anchorToken.column }, start: { lineNumber: pos.lineNumber, column: anchorToken.position.column },
end: { end: {
lineNumber: pos.lineNumber, lineNumber: pos.lineNumber,
column: column:
@ -645,7 +671,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
} }
function addBodyPrefixSuffixToContext(context: any) { function addBodyPrefixSuffixToContext(context: AutoCompleteContext) {
// Figure out what happens next to the token to see whether it needs trailing commas etc. // Figure out what happens next to the token to see whether it needs trailing commas etc.
// Templates will be used if not destroying existing structure. // Templates will be used if not destroying existing structure.
@ -680,9 +706,9 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
context.addTemplate = true; context.addTemplate = true;
// extend range to replace to include all up to token // extend range to replace to include all up to token
context.rangeToReplace.end.lineNumber = tokenIter.getCurrentTokenLineNumber(); context.rangeToReplace!.end.lineNumber = tokenIter.getCurrentTokenLineNumber() as number;
context.rangeToReplace.end.column = context.rangeToReplace!.end.column =
tokenIter.getCurrentTokenColumn() + nonEmptyToken.value.length; (tokenIter.getCurrentTokenColumn() as number) + nonEmptyToken.value.length;
// move one more time to check if we need a trailing comma // move one more time to check if we need a trailing comma
nonEmptyToken = parser.nextNonEmptyToken(tokenIter); nonEmptyToken = parser.nextNonEmptyToken(tokenIter);
@ -711,11 +737,11 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
insertingRelativeToToken = 0; insertingRelativeToToken = 0;
} else { } else {
const pos = editor.getCurrentPosition(); const pos = editor.getCurrentPosition();
if (pos.column === context.updatedForToken.position.column) { if (pos.column === context.updatedForToken!.position.column) {
insertingRelativeToToken = -1; insertingRelativeToToken = -1;
} else if ( } else if (
pos.column < pos.column <
context.updatedForToken.position.column + context.updatedForToken.value.length context.updatedForToken!.position.column + context.updatedForToken!.value.length
) { ) {
insertingRelativeToToken = 0; insertingRelativeToToken = 0;
} else { } else {
@ -743,12 +769,12 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
return context; return context;
} }
function addUrlParamsPrefixSuffixToContext(context: any) { function addUrlParamsPrefixSuffixToContext(context: AutoCompleteContext) {
context.prefixToAdd = ''; context.prefixToAdd = '';
context.suffixToAdd = ''; context.suffixToAdd = '';
} }
function addMethodPrefixSuffixToContext(context: any) { function addMethodPrefixSuffixToContext(context: AutoCompleteContext) {
context.prefixToAdd = ''; context.prefixToAdd = '';
context.suffixToAdd = ''; context.suffixToAdd = '';
const tokenIter = createTokenIterator({ editor, position: editor.getCurrentPosition() }); const tokenIter = createTokenIterator({ editor, position: editor.getCurrentPosition() });
@ -761,12 +787,12 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
} }
function addPathPrefixSuffixToContext(context: any) { function addPathPrefixSuffixToContext(context: AutoCompleteContext) {
context.prefixToAdd = ''; context.prefixToAdd = '';
context.suffixToAdd = ''; context.suffixToAdd = '';
} }
function addMethodAutoCompleteSetToContext(context: any) { function addMethodAutoCompleteSetToContext(context: AutoCompleteContext) {
context.autoCompleteSet = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'].map((m, i) => ({ context.autoCompleteSet = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'].map((m, i) => ({
name: m, name: m,
score: -i, score: -i,
@ -774,7 +800,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
})); }));
} }
function addPathAutoCompleteSetToContext(context: any, pos: Position) { function addPathAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) {
const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); const ret = getCurrentMethodAndTokenPaths(editor, pos, parser);
context.method = ret.method; context.method = ret.method;
context.token = ret.token; context.token = ret.token;
@ -783,10 +809,10 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
const components = getTopLevelUrlCompleteComponents(context.method); const components = getTopLevelUrlCompleteComponents(context.method);
populateContext(ret.urlTokenPath, context, editor, true, components); populateContext(ret.urlTokenPath, context, editor, true, components);
context.autoCompleteSet = addMetaToTermsList(context.autoCompleteSet, 'endpoint'); context.autoCompleteSet = addMetaToTermsList(context.autoCompleteSet!, 'endpoint');
} }
function addUrlParamsAutoCompleteSetToContext(context: any, pos: Position) { function addUrlParamsAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) {
const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); const ret = getCurrentMethodAndTokenPaths(editor, pos, parser);
context.method = ret.method; context.method = ret.method;
context.otherTokenValues = ret.otherTokenValues; context.otherTokenValues = ret.otherTokenValues;
@ -813,7 +839,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
// zero length tokenPath is true // zero length tokenPath is true
return context; return context;
} }
let tokenPath: any[] = []; let tokenPath: string[] = [];
const currentParam = ret.urlParamsTokenPath.pop(); const currentParam = ret.urlParamsTokenPath.pop();
if (currentParam) { if (currentParam) {
tokenPath = Object.keys(currentParam); // single key object tokenPath = Object.keys(currentParam); // single key object
@ -830,7 +856,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
return context; return context;
} }
function addBodyAutoCompleteSetToContext(context: any, pos: Position) { function addBodyAutoCompleteSetToContext(context: AutoCompleteContext, pos: Position) {
const ret = getCurrentMethodAndTokenPaths(editor, pos, parser); const ret = getCurrentMethodAndTokenPaths(editor, pos, parser);
context.method = ret.method; context.method = ret.method;
context.otherTokenValues = ret.otherTokenValues; context.otherTokenValues = ret.otherTokenValues;
@ -859,7 +885,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
// needed for scope linking + global term resolving // needed for scope linking + global term resolving
context.endpointComponentResolver = getEndpointBodyCompleteComponents; context.endpointComponentResolver = getEndpointBodyCompleteComponents;
context.globalComponentResolver = getGlobalAutocompleteComponents; context.globalComponentResolver = getGlobalAutocompleteComponents;
let components; let components: unknown;
if (context.endpoint) { if (context.endpoint) {
components = context.endpoint.bodyAutocompleteRootComponents; components = context.endpoint.bodyAutocompleteRootComponents;
} else { } else {
@ -935,15 +961,19 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
} }
function getCompletions(position: Position, prefix: string, callback: (...args: any[]) => void) { function getCompletions(
position: Position,
prefix: string,
callback: (e: Error | null, result: ResultTerm[] | null) => void
) {
try { try {
const context = getAutoCompleteContext(editor, position); const context = getAutoCompleteContext(editor, position);
if (!context) { if (!context) {
callback(null, []); callback(null, []);
} else { } else {
const terms = _.map( const terms = _.map(
context.autoCompleteSet.filter((term: any) => Boolean(term) && term.name != null), context.autoCompleteSet!.filter((term) => Boolean(term) && term.name != null),
function (term: any) { function (term) {
if (typeof term !== 'object') { if (typeof term !== 'object') {
term = { term = {
name: term, name: term,
@ -951,7 +981,13 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} else { } else {
term = _.clone(term); term = _.clone(term);
} }
const defaults: any = { const defaults: {
value?: string;
meta: string;
score: number;
context: AutoCompleteContext;
completer?: { insertMatch: (v: unknown) => void };
} = {
value: term.name, value: term.name,
meta: 'API', meta: 'API',
score: 0, score: 0,
@ -969,7 +1005,10 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
} }
); );
terms.sort(function (t1: any, t2: any) { terms.sort(function (
t1: { score: number; name?: string },
t2: { score: number; name?: string }
) {
/* score sorts from high to low */ /* score sorts from high to low */
if (t1.score > t2.score) { if (t1.score > t2.score) {
return -1; return -1;
@ -978,7 +1017,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
return 1; return 1;
} }
/* names sort from low to high */ /* names sort from low to high */
if (t1.name < t2.name) { if (t1.name! < t2.name!) {
return -1; return -1;
} }
if (t1.name === t2.name) { if (t1.name === t2.name) {
@ -989,7 +1028,7 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
callback( callback(
null, null,
_.map(terms, function (t: any, i: any) { _.map(terms, function (t, i) {
t.insertValue = t.insertValue || t.value; t.insertValue = t.insertValue || t.value;
t.value = '' + t.value; // normalize to strings t.value = '' + t.value; // normalize to strings
t.score = -i; t.score = -i;
@ -1010,8 +1049,13 @@ export default function ({ coreEditor: editor, parser }: { coreEditor: CoreEdito
getCompletions, getCompletions,
// TODO: This needs to be cleaned up // TODO: This needs to be cleaned up
_test: { _test: {
getCompletions: (_editor: any, _editSession: any, pos: any, prefix: any, callback: any) => getCompletions: (
getCompletions(pos, prefix, callback), _editor: unknown,
_editSession: unknown,
pos: Position,
prefix: string,
callback: (e: Error | null, result: ResultTerm[] | null) => void
) => getCompletions(pos, prefix, callback),
addReplacementInfoToContext, addReplacementInfoToContext,
addChangeListener: () => editor.on('changeSelection', editorChangeListener), addChangeListener: () => editor.on('changeSelection', editorChangeListener),
removeChangeListener: () => editor.off('changeSelection', editorChangeListener), removeChangeListener: () => editor.off('changeSelection', editorChangeListener),

View file

@ -11,7 +11,7 @@ import { ConstantComponent } from './constant_component';
export class FullRequestComponent extends ConstantComponent { export class FullRequestComponent extends ConstantComponent {
private readonly name: string; private readonly name: string;
constructor(name: string, parent: any, private readonly template: string) { constructor(name: string, parent: unknown, private readonly template: string) {
super(name, parent); super(name, parent);
this.name = name; this.name = name;
} }

View file

@ -8,13 +8,14 @@
import { CoreEditor, Position } from '../../types'; import { CoreEditor, Position } from '../../types';
import { getCurrentMethodAndTokenPaths } from './autocomplete'; import { getCurrentMethodAndTokenPaths } from './autocomplete';
import type RowParser from '../row_parser';
// @ts-ignore // @ts-ignore
import { getTopLevelUrlCompleteComponents } from '../kb/kb'; import { getTopLevelUrlCompleteComponents } from '../kb/kb';
// @ts-ignore // @ts-ignore
import { populateContext } from './engine'; import { populateContext } from './engine';
export function getEndpointFromPosition(editor: CoreEditor, pos: Position, parser: any) { export function getEndpointFromPosition(editor: CoreEditor, pos: Position, parser: RowParser) {
const lineValue = editor.getLineValue(pos.lineNumber); const lineValue = editor.getLineValue(pos.lineNumber);
const context = { const context = {
...getCurrentMethodAndTokenPaths( ...getCurrentMethodAndTokenPaths(

View file

@ -0,0 +1,61 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { CoreEditor, Range, Token } from '../../types';
export interface ResultTerm {
context?: AutoCompleteContext;
insertValue?: string;
name?: string;
value?: string;
}
export interface AutoCompleteContext {
autoCompleteSet?: null | ResultTerm[];
endpoint?: null | {
paramsAutocomplete: {
getTopLevelComponents: (method?: string | null) => unknown;
};
bodyAutocompleteRootComponents: unknown;
id?: string;
documentation?: string;
};
urlPath?: null | unknown;
urlParamsTokenPath?: Array<Record<string, string>> | null;
method?: string | null;
token?: Token;
activeScheme?: unknown;
replacingToken?: boolean;
rangeToReplace?: Range;
autoCompleteType?: null | string;
editor?: CoreEditor;
/**
* The tokenized user input that prompted the current autocomplete at the cursor. This can be out of sync with
* the input that is currently being displayed in the editor.
*/
createdWithToken?: Token | null;
/**
* The tokenized user input that is currently being displayed at the cursor in the editor when the user accepted
* the autocomplete suggestion.
*/
updatedForToken?: Token | null;
addTemplate?: unknown;
prefixToAdd?: string;
suffixToAdd?: string;
textBoxPosition?: { lineNumber: number; column: number };
urlTokenPath?: string[];
otherTokenValues?: string;
requestStartRow?: number | null;
bodyTokenPath?: string[] | null;
endpointComponentResolver?: unknown;
globalComponentResolver?: unknown;
documentation?: string;
}

View file

@ -19,7 +19,7 @@ export function getVersion() {
return esVersion; return esVersion;
} }
export function getContentType(body: any) { export function getContentType(body: unknown) {
if (!body) return; if (!body) return;
return 'application/json'; return 'application/json';
} }
@ -27,7 +27,7 @@ export function getContentType(body: any) {
export function send( export function send(
method: string, method: string,
path: string, path: string,
data: any, data: string | object,
{ asSystemRequest }: SendOptions = {} { asSystemRequest }: SendOptions = {}
) { ) {
const wrappedDfd = $.Deferred(); const wrappedDfd = $.Deferred();
@ -47,10 +47,10 @@ export function send(
}; };
$.ajax(options).then( $.ajax(options).then(
(responseData: any, textStatus: string, jqXHR: any) => { (responseData, textStatus: string, jqXHR: unknown) => {
wrappedDfd.resolveWith({}, [responseData, textStatus, jqXHR]); wrappedDfd.resolveWith({}, [responseData, textStatus, jqXHR]);
}, },
((jqXHR: any, textStatus: string, errorThrown: Error) => { ((jqXHR: { status: number; responseText: string }, textStatus: string, errorThrown: Error) => {
if (jqXHR.status === 0) { if (jqXHR.status === 0) {
jqXHR.responseText = jqXHR.responseText =
"\n\nFailed to connect to Console's backend.\nPlease check the Kibana server is up and running"; "\n\nFailed to connect to Console's backend.\nPlease check the Kibana server is up and running";

View file

@ -75,7 +75,7 @@ export default class RowParser {
return MODE.REQUEST_START; return MODE.REQUEST_START;
} }
rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: any) { rowPredicate(lineNumber: number | undefined, editor: CoreEditor, value: number) {
const mode = this.getRowParseMode(lineNumber); const mode = this.getRowParseMode(lineNumber);
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
return (mode & value) > 0; return (mode & value) > 0;

View file

@ -15,7 +15,7 @@ const mockTokensProviderFactory = (tokenMtx: Token[][]): TokensProvider => {
return tokenMtx[lineNumber - 1] || null; return tokenMtx[lineNumber - 1] || null;
}, },
getTokenAt(pos: Position): Token | null { getTokenAt(pos: Position): Token | null {
return null as any; return null;
}, },
}; };
}; };

View file

@ -11,7 +11,7 @@ import { XJson } from '../../../../es_ui_shared/public';
const { collapseLiteralStrings, expandLiteralStrings } = XJson; const { collapseLiteralStrings, expandLiteralStrings } = XJson;
export function textFromRequest(request: any) { export function textFromRequest(request: { method: string; url: string; data: string | string[] }) {
let data = request.data; let data = request.data;
if (typeof data !== 'string') { if (typeof data !== 'string') {
data = data.join('\n'); data = data.join('\n');
@ -19,7 +19,7 @@ export function textFromRequest(request: any) {
return request.method + ' ' + request.url + '\n' + data; return request.method + ' ' + request.url + '\n' + data;
} }
export function jsonToString(data: any, indent: boolean) { export function jsonToString(data: object, indent: boolean) {
return JSON.stringify(data, null, indent ? 2 : 0); return JSON.stringify(data, null, indent ? 2 : 0);
} }

View file

@ -35,12 +35,12 @@ export class History {
// be triggered from different places in the app. The alternative would be to store // be triggered from different places in the app. The alternative would be to store
// this in state so that we hook into the React model, but it would require loading history // this in state so that we hook into the React model, but it would require loading history
// every time the application starts even if a user is not going to view history. // every time the application starts even if a user is not going to view history.
change(listener: (reqs: any[]) => void) { change(listener: (reqs: unknown[]) => void) {
const subscription = this.changeEmitter.subscribe(listener); const subscription = this.changeEmitter.subscribe(listener);
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
} }
addToHistory(endpoint: string, method: string, data: any) { addToHistory(endpoint: string, method: string, data?: string) {
const keys = this.getHistoryKeys(); const keys = this.getHistoryKeys();
keys.splice(0, MAX_NUMBER_OF_HISTORY_ITEMS); // only maintain most recent X; keys.splice(0, MAX_NUMBER_OF_HISTORY_ITEMS); // only maintain most recent X;
keys.forEach((key) => { keys.forEach((key) => {
@ -59,7 +59,7 @@ export class History {
this.changeEmitter.next(this.getHistory()); this.changeEmitter.next(this.getHistory());
} }
updateCurrentState(content: any) { updateCurrentState(content: string) {
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
this.storage.set('editor_state', { this.storage.set('editor_state', {
time: timestamp, time: timestamp,

View file

@ -8,4 +8,4 @@
export { createHistory, History } from './history'; export { createHistory, History } from './history';
export { createStorage, Storage, StorageKeys } from './storage'; export { createStorage, Storage, StorageKeys } from './storage';
export { createSettings, Settings, DevToolsSettings } from './settings'; export { createSettings, Settings, DevToolsSettings, DEFAULT_SETTINGS } from './settings';

View file

@ -8,6 +8,14 @@
import { Storage } from './index'; import { Storage } from './index';
export const DEFAULT_SETTINGS = Object.freeze({
fontSize: 14,
polling: true,
tripleQuotes: true,
wrapMode: true,
autocomplete: Object.freeze({ fields: true, indices: true, templates: true }),
});
export interface DevToolsSettings { export interface DevToolsSettings {
fontSize: number; fontSize: number;
wrapMode: boolean; wrapMode: boolean;
@ -24,50 +32,46 @@ export class Settings {
constructor(private readonly storage: Storage) {} constructor(private readonly storage: Storage) {}
getFontSize() { getFontSize() {
return this.storage.get('font_size', 14); return this.storage.get('font_size', DEFAULT_SETTINGS.fontSize);
} }
setFontSize(size: any) { setFontSize(size: number) {
this.storage.set('font_size', size); this.storage.set('font_size', size);
return true; return true;
} }
getWrapMode() { getWrapMode() {
return this.storage.get('wrap_mode', true); return this.storage.get('wrap_mode', DEFAULT_SETTINGS.wrapMode);
} }
setWrapMode(mode: any) { setWrapMode(mode: boolean) {
this.storage.set('wrap_mode', mode); this.storage.set('wrap_mode', mode);
return true; return true;
} }
setTripleQuotes(tripleQuotes: any) { setTripleQuotes(tripleQuotes: boolean) {
this.storage.set('triple_quotes', tripleQuotes); this.storage.set('triple_quotes', tripleQuotes);
return true; return true;
} }
getTripleQuotes() { getTripleQuotes() {
return this.storage.get('triple_quotes', true); return this.storage.get('triple_quotes', DEFAULT_SETTINGS.tripleQuotes);
} }
getAutocomplete() { getAutocomplete() {
return this.storage.get('autocomplete_settings', { return this.storage.get('autocomplete_settings', DEFAULT_SETTINGS.autocomplete);
fields: true,
indices: true,
templates: true,
});
} }
setAutocomplete(settings: any) { setAutocomplete(settings: object) {
this.storage.set('autocomplete_settings', settings); this.storage.set('autocomplete_settings', settings);
return true; return true;
} }
getPolling() { getPolling() {
return this.storage.get('console_polling', true); return this.storage.get('console_polling', DEFAULT_SETTINGS.polling);
} }
setPolling(polling: any) { setPolling(polling: boolean) {
this.storage.set('console_polling', polling); this.storage.set('console_polling', polling);
return true; return true;
} }

View file

@ -17,11 +17,11 @@ export enum StorageKeys {
export class Storage { export class Storage {
constructor(private readonly engine: IStorageEngine, private readonly prefix: string) {} constructor(private readonly engine: IStorageEngine, private readonly prefix: string) {}
encode(val: any) { encode(val: unknown) {
return JSON.stringify(val); return JSON.stringify(val);
} }
decode(val: any) { decode(val: string | null) {
if (typeof val === 'string') { if (typeof val === 'string') {
return JSON.parse(val); return JSON.parse(val);
} }
@ -37,7 +37,7 @@ export class Storage {
} }
} }
set(key: string, val: any) { set(key: string, val: unknown) {
this.engine.setItem(this.encodeKey(key), this.encode(val)); this.engine.setItem(this.encodeKey(key), this.encode(val));
return val; return val;
} }

View file

@ -11,6 +11,12 @@ export interface MetricsTracker {
load: (eventName: string) => void; load: (eventName: string) => void;
} }
export interface ESRequest {
method: string;
endpoint: string;
data?: string;
}
export type BaseResponseType = export type BaseResponseType =
| 'application/json' | 'application/json'
| 'text/csv' | 'text/csv'

View file

@ -21,7 +21,7 @@ export type EditorEvent =
export type AutoCompleterFunction = ( export type AutoCompleterFunction = (
pos: Position, pos: Position,
prefix: string, prefix: string,
callback: (...args: any[]) => void callback: (...args: unknown[]) => void
) => void; ) => void;
export interface Position { export interface Position {
@ -235,7 +235,7 @@ export interface CoreEditor {
* have this backdoor to update UI in response to request range changes, for example, as the user * have this backdoor to update UI in response to request range changes, for example, as the user
* moves the cursor around * moves the cursor around
*/ */
legacyUpdateUI(opts: any): void; legacyUpdateUI(opts: unknown): void;
/** /**
* A method to for the editor to resize, useful when, for instance, window size changes. * A method to for the editor to resize, useful when, for instance, window size changes.
@ -250,7 +250,11 @@ export interface CoreEditor {
/** /**
* Register a keyboard shortcut and provide a function to be called. * Register a keyboard shortcut and provide a function to be called.
*/ */
registerKeyboardShortcut(opts: { keys: any; fn: () => void; name: string }): void; registerKeyboardShortcut(opts: {
keys: string | { win?: string; mac?: string };
fn: () => void;
name: string;
}): void;
/** /**
* Register a completions function that will be called when the editor * Register a completions function that will be called when the editor

View file

@ -14,7 +14,7 @@ import url from 'url';
import { ESConfigForProxy } from '../types'; import { ESConfigForProxy } from '../types';
const createAgent = (legacyConfig: ESConfigForProxy) => { const createAgent = (legacyConfig: ESConfigForProxy) => {
const target = url.parse(_.head(legacyConfig.hosts) as any); const target = url.parse(_.head(legacyConfig.hosts)!);
if (!/^https/.test(target.protocol || '')) return new http.Agent(); if (!/^https/.test(target.protocol || '')) return new http.Agent();
const agentOptions: https.AgentOptions = {}; const agentOptions: https.AgentOptions = {};
@ -28,7 +28,7 @@ const createAgent = (legacyConfig: ESConfigForProxy) => {
agentOptions.rejectUnauthorized = true; agentOptions.rejectUnauthorized = true;
// by default, NodeJS is checking the server identify // by default, NodeJS is checking the server identify
agentOptions.checkServerIdentity = _.noop as any; agentOptions.checkServerIdentity = (_.noop as unknown) as https.AgentOptions['checkServerIdentity'];
break; break;
case 'full': case 'full':
agentOptions.rejectUnauthorized = true; agentOptions.rejectUnauthorized = true;

View file

@ -12,6 +12,17 @@ import { Agent as HttpsAgent, AgentOptions } from 'https';
import { WildcardMatcher } from './wildcard_matcher'; import { WildcardMatcher } from './wildcard_matcher';
interface Config {
match: {
protocol: string;
host: string;
port: string;
path: string;
};
ssl?: { verify?: boolean; ca?: string; cert?: string; key?: string };
timeout: number;
}
export class ProxyConfig { export class ProxyConfig {
// @ts-ignore // @ts-ignore
private id: string; private id: string;
@ -26,9 +37,9 @@ export class ProxyConfig {
private readonly sslAgent?: HttpsAgent; private readonly sslAgent?: HttpsAgent;
private verifySsl: any; private verifySsl: undefined | boolean;
constructor(config: { match: any; timeout: number }) { constructor(config: Config) {
config = { config = {
...config, ...config,
}; };
@ -61,8 +72,8 @@ export class ProxyConfig {
this.sslAgent = this._makeSslAgent(config); this.sslAgent = this._makeSslAgent(config);
} }
_makeSslAgent(config: any) { _makeSslAgent(config: Config) {
const ssl = config.ssl || {}; const ssl: Config['ssl'] = config.ssl || {};
this.verifySsl = ssl.verify; this.verifySsl = ssl.verify;
const sslAgentOpts: AgentOptions = { const sslAgentOpts: AgentOptions = {

View file

@ -6,6 +6,7 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import type { Agent } from 'http';
import { defaultsDeep } from 'lodash'; import { defaultsDeep } from 'lodash';
import { parse as parseUrl } from 'url'; import { parse as parseUrl } from 'url';
@ -14,7 +15,12 @@ import { ProxyConfig } from './proxy_config';
export class ProxyConfigCollection { export class ProxyConfigCollection {
private configs: ProxyConfig[]; private configs: ProxyConfig[];
constructor(configs: Array<{ match: any; timeout: number }> = []) { constructor(
configs: Array<{
match: { protocol: string; host: string; port: string; path: string };
timeout: number;
}> = []
) {
this.configs = configs.map((settings) => new ProxyConfig(settings)); this.configs = configs.map((settings) => new ProxyConfig(settings));
} }
@ -22,7 +28,7 @@ export class ProxyConfigCollection {
return Boolean(this.configs.length); return Boolean(this.configs.length);
} }
configForUri(uri: string): object { configForUri(uri: string): { agent: Agent; timeout: number } {
const parsedUri = parseUrl(uri); const parsedUri = parseUrl(uri);
const settings = this.configs.map((config) => config.getForParsedUri(parsedUri as any)); const settings = this.configs.map((config) => config.getForParsedUri(parsedUri as any));
return defaultsDeep({}, ...settings); return defaultsDeep({}, ...settings);

View file

@ -55,7 +55,7 @@ describe(`Console's send request`, () => {
fakeRequest = { fakeRequest = {
abort: sinon.stub(), abort: sinon.stub(),
on() {}, on() {},
once(event: string, fn: any) { once(event: string, fn: (v: string) => void) {
if (event === 'response') { if (event === 'response') {
return fn('done'); return fn('done');
} }

View file

@ -46,9 +46,9 @@ export const proxyRequest = ({
const client = uri.protocol === 'https:' ? https : http; const client = uri.protocol === 'https:' ? https : http;
let resolved = false; let resolved = false;
let resolve: any; let resolve: (res: http.IncomingMessage) => void;
let reject: any; let reject: (res: unknown) => void;
const reqPromise = new Promise<http.ServerResponse>((res, rej) => { const reqPromise = new Promise<http.IncomingMessage>((res, rej) => {
resolve = res; resolve = res;
reject = rej; reject = rej;
}); });

View file

@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server * in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { IKibanaResponse } from 'src/core/server';
import { getProxyRouteHandlerDeps } from './mocks'; import { getProxyRouteHandlerDeps } from './mocks';
import { Readable } from 'stream'; import { Readable } from 'stream';
@ -16,10 +16,14 @@ import * as requestModule from '../../../../lib/proxy_request';
import { createResponseStub } from './stubs'; import { createResponseStub } from './stubs';
describe('Console Proxy Route', () => { describe('Console Proxy Route', () => {
let request: any; let request: (
method: string,
path: string,
response?: string
) => Promise<IKibanaResponse> | IKibanaResponse;
beforeEach(() => { beforeEach(() => {
request = (method: string, path: string, response: string) => { request = (method, path, response) => {
(requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub(response)); (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub(response));
const handler = createHandler(getProxyRouteHandlerDeps({})); const handler = createHandler(getProxyRouteHandlerDeps({}));

View file

@ -41,7 +41,7 @@ function toURL(base: string, path: string) {
} }
function filterHeaders(originalHeaders: object, headersToKeep: string[]): object { function filterHeaders(originalHeaders: object, headersToKeep: string[]): object {
const normalizeHeader = function (header: any) { const normalizeHeader = function (header: string) {
if (!header) { if (!header) {
return ''; return '';
} }
@ -68,7 +68,7 @@ function getRequestConfig(
return { return {
...proxyConfigCollection.configForUri(uri), ...proxyConfigCollection.configForUri(uri),
headers: newHeaders, headers: newHeaders,
} as any; };
} }
return { return {
@ -81,7 +81,7 @@ function getProxyHeaders(req: KibanaRequest) {
const headers = Object.create(null); const headers = Object.create(null);
// Scope this proto-unsafe functionality to where it is being used. // Scope this proto-unsafe functionality to where it is being used.
function extendCommaList(obj: Record<string, any>, property: string, value: any) { function extendCommaList(obj: Record<string, any>, property: string, value: string) {
obj[property] = (obj[property] ? obj[property] + ',' : '') + value; obj[property] = (obj[property] ? obj[property] + ',' : '') + value;
} }
@ -142,7 +142,7 @@ export const createHandler = ({
}; };
esIncomingMessage = await proxyRequest({ esIncomingMessage = await proxyRequest({
method: method.toLowerCase() as any, method: method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head',
headers: requestHeaders, headers: requestHeaders,
uri, uri,
timeout, timeout,

View file

@ -6,6 +6,7 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import type { IKibanaResponse } from 'src/core/server';
import { kibanaResponseFactory } from '../../../../../../../core/server'; import { kibanaResponseFactory } from '../../../../../../../core/server';
import { getProxyRouteHandlerDeps } from './mocks'; import { getProxyRouteHandlerDeps } from './mocks';
import { createResponseStub } from './stubs'; import { createResponseStub } from './stubs';
@ -14,7 +15,7 @@ import * as requestModule from '../../../../lib/proxy_request';
import { createHandler } from './create_handler'; import { createHandler } from './create_handler';
describe('Console Proxy Route', () => { describe('Console Proxy Route', () => {
let request: any; let request: (method: string, path: string) => Promise<IKibanaResponse> | IKibanaResponse;
beforeEach(() => { beforeEach(() => {
(requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo')); (requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo'));

View file

@ -9,8 +9,12 @@
import { IncomingMessage } from 'http'; import { IncomingMessage } from 'http';
import { Readable } from 'stream'; import { Readable } from 'stream';
export function createResponseStub(response: any) { export function createResponseStub(response?: string) {
const resp: any = new Readable({ const resp: Readable & {
statusCode?: number;
statusMessage?: string;
headers?: Record<string, unknown>;
} = new Readable({
read() { read() {
if (response) { if (response) {
this.push(response); this.push(response);

View file

@ -15,6 +15,15 @@ import { jsSpecLoaders } from '../lib';
const PATH_TO_OSS_JSON_SPEC = resolve(__dirname, '../lib/spec_definitions/json'); const PATH_TO_OSS_JSON_SPEC = resolve(__dirname, '../lib/spec_definitions/json');
interface EndpointDescription {
methods?: string[];
patterns?: string | string[];
url_params?: Record<string, unknown>;
data_autocomplete_rules?: Record<string, unknown>;
url_components?: Record<string, unknown>;
priority?: number;
}
export class SpecDefinitionsService { export class SpecDefinitionsService {
private readonly name = 'es'; private readonly name = 'es';
@ -24,16 +33,23 @@ export class SpecDefinitionsService {
private hasLoadedSpec = false; private hasLoadedSpec = false;
public addGlobalAutocompleteRules(parentNode: string, rules: any) { public addGlobalAutocompleteRules(parentNode: string, rules: unknown) {
this.globalRules[parentNode] = rules; this.globalRules[parentNode] = rules;
} }
public addEndpointDescription(endpoint: string, description: any = {}) { public addEndpointDescription(endpoint: string, description: EndpointDescription = {}) {
let copiedDescription: any = {}; let copiedDescription: { patterns?: string; url_params?: Record<string, unknown> } = {};
if (this.endpoints[endpoint]) { if (this.endpoints[endpoint]) {
copiedDescription = { ...this.endpoints[endpoint] }; copiedDescription = { ...this.endpoints[endpoint] };
} }
let urlParamsDef: any; let urlParamsDef:
| {
ignore_unavailable?: string;
allow_no_indices?: string;
expand_wildcards?: string[];
}
| undefined;
_.each(description.patterns || [], function (p) { _.each(description.patterns || [], function (p) {
if (p.indexOf('{indices}') >= 0) { if (p.indexOf('{indices}') >= 0) {
urlParamsDef = urlParamsDef || {}; urlParamsDef = urlParamsDef || {};
@ -70,7 +86,7 @@ export class SpecDefinitionsService {
this.extensionSpecFilePaths.push(path); this.extensionSpecFilePaths.push(path);
} }
public addProcessorDefinition(processor: any) { public addProcessorDefinition(processor: unknown) {
if (!this.hasLoadedSpec) { if (!this.hasLoadedSpec) {
throw new Error( throw new Error(
'Cannot add a processor definition because spec definitions have not loaded!' 'Cannot add a processor definition because spec definitions have not loaded!'
@ -104,11 +120,13 @@ export class SpecDefinitionsService {
return generatedFiles.reduce((acc, file) => { return generatedFiles.reduce((acc, file) => {
const overrideFile = overrideFiles.find((f) => basename(f) === basename(file)); const overrideFile = overrideFiles.find((f) => basename(f) === basename(file));
const loadedSpec = JSON.parse(readFileSync(file, 'utf8')); const loadedSpec: Record<string, EndpointDescription> = JSON.parse(
readFileSync(file, 'utf8')
);
if (overrideFile) { if (overrideFile) {
merge(loadedSpec, JSON.parse(readFileSync(overrideFile, 'utf8'))); merge(loadedSpec, JSON.parse(readFileSync(overrideFile, 'utf8')));
} }
const spec: any = {}; const spec: Record<string, EndpointDescription> = {};
Object.entries(loadedSpec).forEach(([key, value]) => { Object.entries(loadedSpec).forEach(([key, value]) => {
if (acc[key]) { if (acc[key]) {
// add time to remove key collision // add time to remove key collision
@ -119,7 +137,7 @@ export class SpecDefinitionsService {
}); });
return { ...acc, ...spec }; return { ...acc, ...spec };
}, {} as any); }, {} as Record<string, EndpointDescription>);
} }
private loadJsonSpec() { private loadJsonSpec() {