feat(lsp): Add lsp wasm and connect to monaco (#16842)
* feat(lsp): Add flux-lsp-browswer dependency * feat(lsp): Change webpack settings to compile lsp wasm * feat(lsp): Add monaco lsp client dep * feat:lsp instantiate lsp server in monaco editor file * feat(lsp): Update monaco loaders and load in webpack.common * feat(lsp): Update flux-lsp-browser dependency * feat(lsp): Connect monaco to lsp server * feat(lsp): Add trigger characters * feat(lsp): Dispose of completion item provider * feat(lsp): Remove javascript and go as monaco languages * feat(lsp): Fix type errors in tests * feat(lsp): Define constants file for fluxlangid * feat(lsp): Remove console * feat(lsp): Fix variable and function insertion * feat(lsp): Fix script entering in DE * feat(lsp): FIx task tests * feat(lsp): Add monaco as global * feat(lsp): Add monaco to window typepull/16893/head
parent
f218dfaf67
commit
38e014ee90
|
|
@ -498,9 +498,9 @@ describe('DataExplorer', () => {
|
|||
.click()
|
||||
.focused()
|
||||
.type(
|
||||
`from(bucket: "defbuck")
|
||||
|> range(start: -10s)
|
||||
|> filter(fn: (r) => r._measurement == "no exist")`,
|
||||
`from(bucket: "defbuck"{rightarrow}
|
||||
|> range(start: -10s{rightarrow}
|
||||
|> filter(fn: (r{rightarrow} => r._measurement == "no exist"{rightarrow}`,
|
||||
{force: true, delay: TYPE_DELAY}
|
||||
)
|
||||
cy.getByTestID('time-machine-submit-button').click()
|
||||
|
|
@ -518,9 +518,9 @@ describe('DataExplorer', () => {
|
|||
.click()
|
||||
.focused()
|
||||
.type(
|
||||
`from(bucket: "defbuck")
|
||||
|> range(start: -15m, stop: now())
|
||||
|> filter(fn: (r) => r._measurement == `,
|
||||
`from(bucket: "defbuck"{rightarrow}
|
||||
|> range(start: -15m, stop: now({rightarrow}{rightarrow}
|
||||
|> filter(fn: (r{rightarrow} => r._measurement ==`,
|
||||
{force: true, delay: TYPE_DELAY}
|
||||
)
|
||||
})
|
||||
|
|
@ -528,14 +528,6 @@ describe('DataExplorer', () => {
|
|||
cy.getByTestID('toolbar-tab').click()
|
||||
//insert variable name by clicking on variable
|
||||
cy.get('.variables-toolbar--label').click()
|
||||
// finish flux
|
||||
cy.getByTestID('flux-editor').within(() => {
|
||||
cy.get('.react-monaco-editor-container')
|
||||
.should('exist')
|
||||
.click()
|
||||
.focused()
|
||||
.type(`)`, {force: true, delay: TYPE_DELAY})
|
||||
})
|
||||
|
||||
cy.getByTestID('save-query-as').click()
|
||||
cy.getByTestID('task--radio-button').click()
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ describe('Tasks', () => {
|
|||
const taskName = 'Bad Task'
|
||||
|
||||
createFirstTask(taskName, ({name}) => {
|
||||
return `import "influxdata/influxdb/v1"
|
||||
v1.tagValues(bucket: "${name}", tag: "_field")
|
||||
from(bucket: "${name}")
|
||||
|> range(start: -2m)
|
||||
|> to(org: "${name}")`
|
||||
return `import "influxdata/influxdb/v1{rightarrow}
|
||||
v1.tagValues(bucket: "${name}", tag: "_field"{rightarrow}
|
||||
from(bucket: "${name}"{rightarrow}
|
||||
|> range(start: -2m{rightarrow}
|
||||
|> to(org: "${name}"{rightarrow}`
|
||||
})
|
||||
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
|
|
@ -46,10 +46,10 @@ from(bucket: "${name}")
|
|||
it('can create a task', () => {
|
||||
const taskName = 'Task'
|
||||
createFirstTask(taskName, ({name}) => {
|
||||
return `import "influxdata/influxdb/v1"
|
||||
v1.tagValues(bucket: "${name}", tag: "_field")
|
||||
from(bucket: "${name}")
|
||||
|> range(start: -2m)`
|
||||
return `import "influxdata/influxdb/v1{rightarrow}
|
||||
v1.tagValues(bucket: "${name}", tag: "_field"{rightarrow}
|
||||
from(bucket: "${name}"{rightarrow}
|
||||
|> range(start: -2m{rightarrow}`
|
||||
})
|
||||
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
|
|
@ -62,11 +62,11 @@ from(bucket: "${name}")
|
|||
it.skip('can create a task using http.post', () => {
|
||||
const taskName = 'Task'
|
||||
createFirstTask(taskName, () => {
|
||||
return `import "http"
|
||||
return `import "http{rightarrow}
|
||||
http.post(
|
||||
url: "https://foo.bar/baz",
|
||||
data: bytes(v: "body")
|
||||
)`
|
||||
data: bytes(v: "body"{rightarrow}
|
||||
{rightarrow}`
|
||||
})
|
||||
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
|
|
@ -229,10 +229,10 @@ http.post(
|
|||
createFirstTask(
|
||||
taskName,
|
||||
({name}) => {
|
||||
return `import "influxdata/influxdb/v1"
|
||||
v1.tagValues(bucket: "${name}", tag: "_field")
|
||||
from(bucket: "${name}")
|
||||
|> range(start: -2m)`
|
||||
return `import "influxdata/influxdb/v1{rightarrow}
|
||||
v1.tagValues(bucket: "${name}", tag: "_field"{rightarrow}
|
||||
from(bucket: "${name}"{rightarrow}
|
||||
|> range(start: -2m{rightarrow}`
|
||||
},
|
||||
interval,
|
||||
offset
|
||||
|
|
@ -304,55 +304,22 @@ http.post(
|
|||
// https://github.com/influxdata/influxdb/issues/15552
|
||||
const firstTask = 'First_Task'
|
||||
const secondTask = 'Second_Task'
|
||||
const interval = '12h'
|
||||
const offset = '30m'
|
||||
const flux = name => `import "influxdata/influxdb/v1"
|
||||
v1.tagValues(bucket: "${name}", tag: "_field")
|
||||
from(bucket: "${name}")
|
||||
|> range(start: -2m)`
|
||||
beforeEach(() => {
|
||||
createFirstTask(
|
||||
firstTask,
|
||||
({name}) => {
|
||||
return flux(name)
|
||||
},
|
||||
interval,
|
||||
offset
|
||||
)
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
cy.getByTestID('task-card')
|
||||
.should('have.length', 1)
|
||||
.and('contain', firstTask)
|
||||
|
||||
cy.getByTestID('add-resource-dropdown--button').click()
|
||||
cy.getByTestID('add-resource-dropdown--new').click()
|
||||
cy.getByInputName('name').type(secondTask)
|
||||
cy.getByTestID('task-form-schedule-input').type(interval)
|
||||
cy.getByTestID('task-form-offset-input').type(offset)
|
||||
cy.get<Bucket>('@bucket').then(bucket => {
|
||||
cy.getByTestID('flux-editor').within(() => {
|
||||
cy.get('.react-monaco-editor-container')
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.focused()
|
||||
.type(flux(bucket), {force: true, delay: 2})
|
||||
cy.get('@org').then(({id}: Organization) => {
|
||||
cy.get<string>('@token').then(token => {
|
||||
cy.createTask(token, id, firstTask)
|
||||
cy.createTask(token, id, secondTask)
|
||||
})
|
||||
})
|
||||
|
||||
cy.fixture('routes').then(({orgs}) => {
|
||||
cy.get('@org').then(({id}: Organization) => {
|
||||
cy.visit(`${orgs}/${id}/tasks`)
|
||||
})
|
||||
})
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
cy.getByTestID('task-card')
|
||||
.should('have.length', 2)
|
||||
.and('contain', firstTask)
|
||||
.and('contain', secondTask)
|
||||
cy.getByTestID('task-card--name')
|
||||
.contains(firstTask)
|
||||
.click()
|
||||
})
|
||||
|
||||
it('when navigating using the navbar', () => {
|
||||
// verify that the previously input data exists
|
||||
cy.getByInputValue(firstTask)
|
||||
// navigate home
|
||||
cy.get('div.cf-nav--item.active').click()
|
||||
// click on the second task
|
||||
cy.getByTestID('task-card--name')
|
||||
.contains(secondTask)
|
||||
|
|
@ -368,10 +335,6 @@ http.post(
|
|||
})
|
||||
|
||||
it('when navigating using the cancel button', () => {
|
||||
// verify that the previously input data exists
|
||||
cy.getByInputValue(firstTask)
|
||||
// navigate home
|
||||
cy.getByTestID('task-cancel-btn').click()
|
||||
// click on the second task
|
||||
cy.getByTestID('task-card--name')
|
||||
.contains(secondTask)
|
||||
|
|
@ -388,10 +351,6 @@ http.post(
|
|||
})
|
||||
|
||||
it('when navigating using the save button', () => {
|
||||
// verify that the previously input data exists
|
||||
cy.getByInputValue(firstTask)
|
||||
// navigate home
|
||||
cy.getByTestID('task-save-btn').click()
|
||||
// click on the second task
|
||||
cy.getByTestID('task-card--name')
|
||||
.contains(secondTask)
|
||||
|
|
@ -421,16 +380,16 @@ function createFirstTask(
|
|||
|
||||
cy.getByTestID('add-resource-dropdown--new').click()
|
||||
|
||||
cy.getByInputName('name').type(name)
|
||||
cy.getByTestID('task-form-schedule-input').type(interval)
|
||||
cy.getByTestID('task-form-offset-input').type(offset)
|
||||
|
||||
cy.get<Bucket>('@bucket').then(bucket => {
|
||||
cy.getByTestID('flux-editor').within(() => {
|
||||
cy.get('.react-monaco-editor-container')
|
||||
cy.get('textarea.inputarea')
|
||||
.click()
|
||||
.focused()
|
||||
.type(flux(bucket), {force: true, delay: 2})
|
||||
})
|
||||
})
|
||||
|
||||
cy.getByInputName('name').type(name)
|
||||
cy.getByTestID('task-form-schedule-input').type(interval)
|
||||
cy.getByTestID('task-form-offset-input').type(offset)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import {MonacoType} from 'src/types'
|
||||
|
||||
//
|
||||
// got some globals here that only exist during compilation
|
||||
//
|
||||
|
||||
declare module '*.png'
|
||||
declare let monaco: MonacoType
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
monaco: MonacoType
|
||||
}
|
||||
}
|
||||
|
||||
window.monaco = window.monaco || {}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@influxdata/clockface": "1.1.5",
|
||||
"@influxdata/flux-lsp-browser": "^0.2.2",
|
||||
"@influxdata/flux-parser": "^0.3.0",
|
||||
"@influxdata/giraffe": "0.17.4",
|
||||
"@influxdata/influx": "0.5.5",
|
||||
|
|
@ -154,9 +155,10 @@
|
|||
"lodash": "^4.3.0",
|
||||
"memoize-one": "^4.0.2",
|
||||
"moment": "^2.13.0",
|
||||
"monaco-editor": "^0.18.1",
|
||||
"monaco-editor": "^0.19.2",
|
||||
"monaco-editor-textmate": "^2.2.1",
|
||||
"monaco-editor-webpack-plugin": "^1.7.0",
|
||||
"monaco-languageclient": "^0.11.0",
|
||||
"monaco-editor-webpack-plugin": "^1.8.2",
|
||||
"monaco-textmate": "^3.0.1",
|
||||
"normalizr": "^3.4.1",
|
||||
"onigasm": "^2.2.4",
|
||||
|
|
@ -174,7 +176,7 @@
|
|||
"react-grid-layout": "^0.16.6",
|
||||
"react-loadable": "^5.5.0",
|
||||
"react-markdown": "^4.0.3",
|
||||
"react-monaco-editor": "^0.32.1",
|
||||
"react-monaco-editor": "^0.33.0",
|
||||
"react-redux": "^5.1.2",
|
||||
"react-router": "^3.0.2",
|
||||
"react-router-redux": "^4.0.8",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export const FLUXLANGID = 'flux' as const
|
||||
|
|
@ -1,20 +1,83 @@
|
|||
// Types
|
||||
import {MonacoType} from 'src/types'
|
||||
// Libraries
|
||||
import {completion, sendMessage} from 'src/external/monaco.lspMessages'
|
||||
import {
|
||||
MonacoToProtocolConverter,
|
||||
ProtocolToMonacoConverter,
|
||||
} from 'monaco-languageclient/lib/monaco-converter'
|
||||
import {get} from 'lodash'
|
||||
|
||||
export const addSnippets = (monaco: MonacoType) => {
|
||||
monaco.languages.registerCompletionItemProvider('flux', {
|
||||
provideCompletionItems: () => {
|
||||
const suggestions = [
|
||||
{
|
||||
label: 'from',
|
||||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||
insertText: ['from(bucket: ${1})', '\t|>'].join('\n'),
|
||||
insertTextRules:
|
||||
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||
documentation: 'From-Statement',
|
||||
},
|
||||
] as any[]
|
||||
return {suggestions: suggestions}
|
||||
},
|
||||
})
|
||||
// Constants
|
||||
import {FLUXLANGID} from 'src/external/constants'
|
||||
|
||||
// Types
|
||||
import {CompletionItem} from 'monaco-languageclient/lib/services'
|
||||
import {MonacoType} from 'src/types'
|
||||
import {IDisposable} from 'monaco-editor'
|
||||
|
||||
const m2p = new MonacoToProtocolConverter()
|
||||
const p2m = new ProtocolToMonacoConverter()
|
||||
|
||||
export const registerCompletion = (monaco: MonacoType, server): IDisposable => {
|
||||
const completionProvider = monaco.languages.registerCompletionItemProvider(
|
||||
FLUXLANGID,
|
||||
{
|
||||
provideCompletionItems: (model, position, context) => {
|
||||
const wordUntil = model.getWordUntilPosition(position)
|
||||
const defaultRange = new monaco.Range(
|
||||
position.lineNumber,
|
||||
wordUntil.startColumn,
|
||||
position.lineNumber,
|
||||
wordUntil.endColumn
|
||||
)
|
||||
const response = sendMessage(
|
||||
completion(
|
||||
m2p.asPosition(position.lineNumber, position.column),
|
||||
context
|
||||
),
|
||||
server
|
||||
)
|
||||
|
||||
const completionItems = get(
|
||||
response,
|
||||
'result.items',
|
||||
null
|
||||
) as CompletionItem[]
|
||||
|
||||
if (!completionItems) {
|
||||
return
|
||||
}
|
||||
return p2m.asCompletionResult(completionItems, defaultRange)
|
||||
},
|
||||
triggerCharacters: [
|
||||
'.',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
],
|
||||
}
|
||||
)
|
||||
return completionProvider
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
export const tokenizeFlux = monaco => {
|
||||
monaco.languages.register({id: 'flux'})
|
||||
// Constants
|
||||
import {FLUXLANGID} from 'src/external/constants'
|
||||
|
||||
monaco.languages.setMonarchTokensProvider('flux', {
|
||||
export const tokenizeFlux = monaco => {
|
||||
monaco.languages.register({id: FLUXLANGID})
|
||||
|
||||
monaco.languages.setMonarchTokensProvider(FLUXLANGID, {
|
||||
keywords: ['from', 'range', 'filter', 'to'],
|
||||
tokenizer: {
|
||||
root: [
|
||||
|
|
|
|||
|
|
@ -2,14 +2,15 @@ import loader from 'src/external/monaco.onigasm'
|
|||
import {Registry} from 'monaco-textmate' // peer dependency
|
||||
import {wireTmGrammars} from 'monaco-editor-textmate'
|
||||
|
||||
// Constants
|
||||
import {FLUXLANGID} from 'src/external/constants'
|
||||
|
||||
// Types
|
||||
import {MonacoType} from 'src/types'
|
||||
|
||||
export async function addSyntax(monaco: MonacoType) {
|
||||
await loader()
|
||||
|
||||
monaco.languages.register({id: 'flux'})
|
||||
|
||||
const registry = new Registry({
|
||||
// TODO: this is maintained in influxdata/vsflux, which is currently
|
||||
// a private repo, so we can't use it yet (alex)
|
||||
|
|
@ -25,7 +26,17 @@ export async function addSyntax(monaco: MonacoType) {
|
|||
|
||||
// map of monaco "language id's" to TextMate scopeNames
|
||||
const grammars = new Map()
|
||||
grammars.set('flux', 'flux')
|
||||
grammars.set(FLUXLANGID, FLUXLANGID)
|
||||
|
||||
monaco.languages.setLanguageConfiguration(FLUXLANGID, {
|
||||
autoClosingPairs: [
|
||||
{open: '"', close: '"'},
|
||||
{open: '[', close: ']'},
|
||||
{open: "'", close: "'"},
|
||||
{open: '{', close: '}'},
|
||||
{open: '(', close: ')'},
|
||||
],
|
||||
})
|
||||
|
||||
await wireTmGrammars(monaco, registry, grammars)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
import {get} from 'lodash'
|
||||
|
||||
// Constants
|
||||
import {FLUXLANGID} from 'src/external/constants'
|
||||
|
||||
// Types
|
||||
import {ServerResponse} from 'src/types'
|
||||
|
||||
type LSPMessage =
|
||||
| typeof initialize
|
||||
| ReturnType<typeof didOpen>
|
||||
| ReturnType<typeof didChange>
|
||||
| ReturnType<typeof completion>
|
||||
|
||||
const URI = 'monacoeditor' as const
|
||||
const JSONRPC = '2.0' as const
|
||||
|
||||
export const initialize = {
|
||||
jsonrpc: JSONRPC,
|
||||
id: 1,
|
||||
method: 'initialize',
|
||||
params: {},
|
||||
} as const
|
||||
|
||||
export const didOpen = (text: string) => ({
|
||||
jsonrpc: JSONRPC,
|
||||
id: 2,
|
||||
method: 'textDocument/didOpen' as const,
|
||||
params: {
|
||||
textDocument: {
|
||||
uri: URI,
|
||||
languageId: FLUXLANGID,
|
||||
version: 1 as const,
|
||||
text,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const didChange = (
|
||||
newText: string,
|
||||
version: number,
|
||||
messageID: number
|
||||
) => ({
|
||||
jsonrpc: JSONRPC,
|
||||
id: messageID,
|
||||
method: 'textDocument/didChange' as const,
|
||||
params: {
|
||||
textDocument: {
|
||||
uri: URI,
|
||||
version: version,
|
||||
},
|
||||
contentChanges: [
|
||||
{
|
||||
text: newText,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
export const completion = (position, context) => ({
|
||||
jsonrpc: JSONRPC,
|
||||
id: 100,
|
||||
method: 'textDocument/completion' as const,
|
||||
params: {
|
||||
textDocument: {uri: URI},
|
||||
position,
|
||||
context,
|
||||
},
|
||||
})
|
||||
|
||||
export const parseResponse = (response: ServerResponse): null | object => {
|
||||
const message = response.get_message()
|
||||
if (message) {
|
||||
const split = message.split('\n')
|
||||
const parsed_msg = get(split, '2', null)
|
||||
return JSON.parse(parsed_msg)
|
||||
} else {
|
||||
const error = response.get_error()
|
||||
const split = error.split('\n')
|
||||
const parsed_err = get(split, '2', null)
|
||||
return JSON.parse(parsed_err)
|
||||
}
|
||||
}
|
||||
|
||||
export const sendMessage = (message: LSPMessage, server) => {
|
||||
const stringifiedMessage = JSON.stringify(message)
|
||||
const size = stringifiedMessage.length
|
||||
|
||||
const resp = server.process(
|
||||
`Content-Length: ${size}\r\n\r\n` + stringifiedMessage
|
||||
)
|
||||
|
||||
return parseResponse(resp)
|
||||
}
|
||||
|
|
@ -1,58 +1,72 @@
|
|||
// Libraries
|
||||
import React, {FC} from 'react'
|
||||
import React, {FC, useEffect, useRef, useState} from 'react'
|
||||
import {Server} from '@influxdata/flux-lsp-browser'
|
||||
|
||||
// Components
|
||||
import MonacoEditor from 'react-monaco-editor'
|
||||
|
||||
// Utils
|
||||
import addFluxTheme, {THEME_NAME} from 'src/external/monaco.fluxTheme'
|
||||
import {addSnippets} from 'src/external/monaco.fluxCompletions'
|
||||
import {registerCompletion} from 'src/external/monaco.fluxCompletions'
|
||||
import {addSyntax} from 'src/external/monaco.fluxSyntax'
|
||||
import {OnChangeScript} from 'src/types/flux'
|
||||
import {addKeyBindings} from 'src/external/monaco.keyBindings'
|
||||
import {
|
||||
sendMessage,
|
||||
initialize,
|
||||
didChange,
|
||||
didOpen,
|
||||
} from 'src/external/monaco.lspMessages'
|
||||
|
||||
// Constants
|
||||
import {FLUXLANGID} from 'src/external/constants'
|
||||
|
||||
// Types
|
||||
import {OnChangeScript} from 'src/types/flux'
|
||||
import {MonacoType, EditorType} from 'src/types'
|
||||
|
||||
import './FluxMonacoEditor.scss'
|
||||
|
||||
interface Position {
|
||||
line: number
|
||||
ch: number
|
||||
}
|
||||
|
||||
interface Props {
|
||||
script: string
|
||||
onChangeScript: OnChangeScript
|
||||
onSubmitScript?: () => void
|
||||
onCursorChange?: (position: Position) => void
|
||||
setEditorInstance?: (editor: EditorType) => void
|
||||
}
|
||||
|
||||
const FluxEditorMonaco: FC<Props> = props => {
|
||||
const FluxEditorMonaco: FC<Props> = ({
|
||||
script,
|
||||
onChangeScript,
|
||||
onSubmitScript,
|
||||
setEditorInstance,
|
||||
}) => {
|
||||
let completionProvider = {dispose: () => {}}
|
||||
const lspServer = useRef(new Server(false))
|
||||
const [docVersion, setdocVersion] = useState(2)
|
||||
const [msgID, setmsgID] = useState(3)
|
||||
|
||||
useEffect(() => {
|
||||
sendMessage(initialize, lspServer.current)
|
||||
sendMessage(didOpen(script), lspServer.current)
|
||||
return () => {
|
||||
completionProvider.dispose()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const editorWillMount = (monaco: MonacoType) => {
|
||||
monaco.languages.register({id: FLUXLANGID})
|
||||
addFluxTheme(monaco)
|
||||
addSnippets(monaco)
|
||||
addSyntax(monaco)
|
||||
completionProvider = registerCompletion(monaco, lspServer.current)
|
||||
}
|
||||
|
||||
const editorDidMount = (editor: EditorType, monaco: MonacoType) => {
|
||||
if (setEditorInstance) {
|
||||
setEditorInstance(editor)
|
||||
}
|
||||
addKeyBindings(editor, monaco)
|
||||
editor.onDidChangeCursorPosition(evt => {
|
||||
const {position} = evt
|
||||
const {onCursorChange} = props
|
||||
const pos = {
|
||||
line: position.lineNumber - 1,
|
||||
ch: position.column,
|
||||
}
|
||||
|
||||
if (onCursorChange) {
|
||||
onCursorChange(pos)
|
||||
}
|
||||
})
|
||||
|
||||
editor.focus()
|
||||
editor.onKeyUp(evt => {
|
||||
const {ctrlKey, code} = evt
|
||||
const {onSubmitScript} = props
|
||||
if (ctrlKey && code === 'Enter') {
|
||||
if (onSubmitScript) {
|
||||
onSubmitScript()
|
||||
|
|
@ -60,15 +74,21 @@ const FluxEditorMonaco: FC<Props> = props => {
|
|||
}
|
||||
})
|
||||
}
|
||||
const {script, onChangeScript} = props
|
||||
|
||||
const onChange = (text: string) => {
|
||||
sendMessage(didChange(text, docVersion, msgID), lspServer.current)
|
||||
setdocVersion(docVersion + 1)
|
||||
setmsgID(msgID + 1)
|
||||
onChangeScript(text)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="time-machine-editor" data-testid="flux-editor">
|
||||
<MonacoEditor
|
||||
language="flux"
|
||||
language={FLUXLANGID}
|
||||
theme={THEME_NAME}
|
||||
value={script}
|
||||
onChange={onChangeScript}
|
||||
onChange={onChange}
|
||||
options={{
|
||||
fontSize: 13,
|
||||
fontFamily: '"RobotoMono", monospace',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import React, {FC, useState} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {Position} from 'codemirror'
|
||||
|
||||
// Components
|
||||
import FluxEditor from 'src/shared/components/FluxMonacoEditor'
|
||||
|
|
@ -16,14 +15,16 @@ import {saveAndExecuteQueries} from 'src/timeMachine/actions/queries'
|
|||
|
||||
// Utils
|
||||
import {getActiveQuery, getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
import {insertFluxFunction} from 'src/timeMachine/utils/insertFunction'
|
||||
import {insertVariable} from 'src/timeMachine/utils/insertVariable'
|
||||
import {
|
||||
formatFunctionForInsert,
|
||||
generateImport,
|
||||
} from 'src/timeMachine/utils/insertFunction'
|
||||
|
||||
// Constants
|
||||
import {HANDLE_VERTICAL, HANDLE_NONE} from 'src/shared/constants'
|
||||
|
||||
// Types
|
||||
import {AppState, FluxToolbarFunction} from 'src/types'
|
||||
import {AppState, FluxToolbarFunction, EditorType} from 'src/types'
|
||||
|
||||
interface StateProps {
|
||||
activeQueryText: string
|
||||
|
|
@ -35,132 +36,122 @@ interface DispatchProps {
|
|||
onSubmitQueries: typeof saveAndExecuteQueries
|
||||
}
|
||||
|
||||
interface State {
|
||||
displayFluxFunctions: boolean
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps
|
||||
|
||||
class TimeMachineFluxEditor extends PureComponent<Props, State> {
|
||||
private cursorPosition: Position = {line: 0, ch: 0}
|
||||
const TimeMachineFluxEditor: FC<Props> = ({
|
||||
activeQueryText,
|
||||
onSubmitQueries,
|
||||
onSetActiveQueryText,
|
||||
activeTab,
|
||||
}) => {
|
||||
const [displayFluxFunctions, setDisplayFluxFunctions] = useState(true)
|
||||
const [editorInstance, setEditorInstance] = useState<EditorType>(null)
|
||||
|
||||
public state: State = {
|
||||
displayFluxFunctions: true,
|
||||
const showFluxFunctions = () => {
|
||||
setDisplayFluxFunctions(true)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
activeQueryText,
|
||||
onSubmitQueries,
|
||||
onSetActiveQueryText,
|
||||
activeTab,
|
||||
} = this.props
|
||||
const hideFluxFunctions = () => {
|
||||
setDisplayFluxFunctions(false)
|
||||
}
|
||||
|
||||
const divisions = [
|
||||
const handleInsertVariable = (variableName: string): void => {
|
||||
const p = editorInstance.getPosition()
|
||||
editorInstance.executeEdits('', [
|
||||
{
|
||||
size: 0.75,
|
||||
handleDisplay: HANDLE_NONE,
|
||||
render: () => {
|
||||
return (
|
||||
<FluxEditor
|
||||
script={activeQueryText}
|
||||
onChangeScript={onSetActiveQueryText}
|
||||
onSubmitScript={onSubmitQueries}
|
||||
onCursorChange={this.handleCursorPosition}
|
||||
/>
|
||||
)
|
||||
},
|
||||
range: new window.monaco.Range(
|
||||
p.lineNumber,
|
||||
p.column,
|
||||
p.lineNumber,
|
||||
p.column
|
||||
),
|
||||
text: `v.${variableName}`,
|
||||
},
|
||||
])
|
||||
onSetActiveQueryText(editorInstance.getValue())
|
||||
}
|
||||
|
||||
const handleInsertFluxFunction = (func: FluxToolbarFunction): void => {
|
||||
const p = editorInstance.getPosition()
|
||||
const edits = [
|
||||
{
|
||||
render: () => {
|
||||
return (
|
||||
<>
|
||||
<div className="toolbar-tab-container">
|
||||
{activeTab !== 'customCheckQuery' && (
|
||||
<ToolbarTab
|
||||
onSetActive={this.hideFluxFunctions}
|
||||
name="Variables"
|
||||
active={!this.state.displayFluxFunctions}
|
||||
/>
|
||||
)}
|
||||
<ToolbarTab
|
||||
onSetActive={this.showFluxFunctions}
|
||||
name="Functions"
|
||||
active={this.state.displayFluxFunctions}
|
||||
testID="functions-toolbar-tab"
|
||||
/>
|
||||
</div>
|
||||
{this.rightDivision}
|
||||
</>
|
||||
)
|
||||
},
|
||||
handlePixels: 6,
|
||||
size: 0.25,
|
||||
range: new window.monaco.Range(
|
||||
p.lineNumber,
|
||||
p.column,
|
||||
p.lineNumber,
|
||||
p.column
|
||||
),
|
||||
text: formatFunctionForInsert(func.name, func.example),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="time-machine-flux-editor">
|
||||
<Threesizer orientation={HANDLE_VERTICAL} divisions={divisions} />
|
||||
</div>
|
||||
const importStatement = generateImport(
|
||||
func.package,
|
||||
editorInstance.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
private get rightDivision(): JSX.Element {
|
||||
const {displayFluxFunctions} = this.state
|
||||
|
||||
if (displayFluxFunctions) {
|
||||
return (
|
||||
<FluxFunctionsToolbar
|
||||
onInsertFluxFunction={this.handleInsertFluxFunction}
|
||||
/>
|
||||
)
|
||||
if (importStatement) {
|
||||
edits.unshift({
|
||||
range: new window.monaco.Range(1, 1, 1, 1),
|
||||
text: `${importStatement}\n`,
|
||||
})
|
||||
}
|
||||
|
||||
return <VariableToolbar onClickVariable={this.handleInsertVariable} />
|
||||
editorInstance.executeEdits('', edits)
|
||||
onSetActiveQueryText(editorInstance.getValue())
|
||||
}
|
||||
|
||||
private handleCursorPosition = (position: Position): void => {
|
||||
this.cursorPosition = position
|
||||
}
|
||||
const divisions = [
|
||||
{
|
||||
size: 0.75,
|
||||
handleDisplay: HANDLE_NONE,
|
||||
render: () => {
|
||||
return (
|
||||
<FluxEditor
|
||||
script={activeQueryText}
|
||||
onChangeScript={onSetActiveQueryText}
|
||||
onSubmitScript={onSubmitQueries}
|
||||
setEditorInstance={setEditorInstance}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
render: () => {
|
||||
return (
|
||||
<>
|
||||
<div className="toolbar-tab-container">
|
||||
{activeTab !== 'customCheckQuery' && (
|
||||
<ToolbarTab
|
||||
onSetActive={hideFluxFunctions}
|
||||
name="Variables"
|
||||
active={!displayFluxFunctions}
|
||||
/>
|
||||
)}
|
||||
<ToolbarTab
|
||||
onSetActive={showFluxFunctions}
|
||||
name="Functions"
|
||||
active={displayFluxFunctions}
|
||||
testID="functions-toolbar-tab"
|
||||
/>
|
||||
</div>
|
||||
{displayFluxFunctions ? (
|
||||
<FluxFunctionsToolbar
|
||||
onInsertFluxFunction={handleInsertFluxFunction}
|
||||
/>
|
||||
) : (
|
||||
<VariableToolbar onClickVariable={handleInsertVariable} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
},
|
||||
handlePixels: 6,
|
||||
size: 0.25,
|
||||
},
|
||||
]
|
||||
|
||||
private handleInsertVariable = (variableName: string): void => {
|
||||
const {activeQueryText} = this.props
|
||||
const {line, ch} = this.cursorPosition
|
||||
|
||||
const {updatedScript, cursorPosition} = insertVariable(
|
||||
line,
|
||||
ch,
|
||||
activeQueryText,
|
||||
variableName
|
||||
)
|
||||
|
||||
this.props.onSetActiveQueryText(updatedScript)
|
||||
|
||||
this.handleCursorPosition(cursorPosition)
|
||||
}
|
||||
|
||||
private handleInsertFluxFunction = (func: FluxToolbarFunction): void => {
|
||||
const {activeQueryText, onSetActiveQueryText} = this.props
|
||||
const {line} = this.cursorPosition
|
||||
|
||||
const {updatedScript, cursorPosition} = insertFluxFunction(
|
||||
line,
|
||||
activeQueryText,
|
||||
func
|
||||
)
|
||||
|
||||
onSetActiveQueryText(updatedScript)
|
||||
this.handleCursorPosition(cursorPosition)
|
||||
}
|
||||
|
||||
private showFluxFunctions = () => {
|
||||
this.setState({displayFluxFunctions: true})
|
||||
}
|
||||
|
||||
private hideFluxFunctions = () => {
|
||||
this.setState({displayFluxFunctions: false})
|
||||
}
|
||||
return (
|
||||
<div className="time-machine-flux-editor">
|
||||
<Threesizer orientation={HANDLE_VERTICAL} divisions={divisions} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
|
|
|
|||
|
|
@ -1,44 +1,6 @@
|
|||
import {Position} from 'codemirror'
|
||||
|
||||
// Constants
|
||||
import {FROM, UNION} from 'src/shared/constants/fluxFunctions'
|
||||
|
||||
// Types
|
||||
import {FluxToolbarFunction} from 'src/types'
|
||||
|
||||
const rejoinScript = (scriptLines: string[]): string => {
|
||||
return scriptLines.join('\n')
|
||||
}
|
||||
|
||||
const insertAtLine = (
|
||||
lineNumber: number,
|
||||
scriptLines: string[],
|
||||
textToInsert: string,
|
||||
insertOnSameLine?: boolean
|
||||
): string => {
|
||||
const front = scriptLines.slice(0, lineNumber)
|
||||
const backStartIndex = insertOnSameLine ? lineNumber + 1 : lineNumber
|
||||
const back = scriptLines.slice(backStartIndex)
|
||||
|
||||
const updated = [...front, textToInsert, ...back]
|
||||
|
||||
return rejoinScript(updated)
|
||||
}
|
||||
|
||||
const getInsertLineNumber = (
|
||||
currentLineNumber: number,
|
||||
scriptLines: string[]
|
||||
): number => {
|
||||
const currentLine = scriptLines[currentLineNumber]
|
||||
|
||||
// Insert on the current line if its an empty line
|
||||
if (!currentLine.trim()) {
|
||||
return currentLineNumber
|
||||
}
|
||||
|
||||
return currentLineNumber + 1
|
||||
}
|
||||
|
||||
const functionRequiresNewLine = (funcName: string): boolean => {
|
||||
switch (funcName) {
|
||||
case FROM.name:
|
||||
|
|
@ -50,7 +12,10 @@ const functionRequiresNewLine = (funcName: string): boolean => {
|
|||
}
|
||||
}
|
||||
|
||||
const formatFunctionForInsert = (funcName: string, fluxFunction: string) => {
|
||||
export const formatFunctionForInsert = (
|
||||
funcName: string,
|
||||
fluxFunction: string
|
||||
) => {
|
||||
if (functionRequiresNewLine(funcName)) {
|
||||
return `\n${fluxFunction}`
|
||||
}
|
||||
|
|
@ -58,63 +23,15 @@ const formatFunctionForInsert = (funcName: string, fluxFunction: string) => {
|
|||
return ` |> ${fluxFunction}`
|
||||
}
|
||||
|
||||
const getCursorPosition = (
|
||||
insertLineNumber,
|
||||
formattedFunction,
|
||||
funcName
|
||||
): Position => {
|
||||
const ch = formattedFunction.length - 1
|
||||
const line = functionRequiresNewLine(funcName)
|
||||
? insertLineNumber + 1
|
||||
: insertLineNumber
|
||||
|
||||
return {line, ch}
|
||||
}
|
||||
|
||||
const genImport = (script: string, funcPackage: string) => {
|
||||
export const generateImport = (
|
||||
funcPackage: string,
|
||||
script: string
|
||||
): false | string => {
|
||||
const importStatement = `import "${funcPackage}"`
|
||||
|
||||
if (!funcPackage || script.includes(importStatement)) {
|
||||
return ''
|
||||
return false
|
||||
}
|
||||
|
||||
return importStatement
|
||||
}
|
||||
|
||||
export const insertFluxFunction = (
|
||||
currentLineNumber: number,
|
||||
currentScript: string,
|
||||
func: FluxToolbarFunction
|
||||
): {updatedScript: string; cursorPosition: Position} => {
|
||||
const {name, example} = func
|
||||
|
||||
const scriptLines = currentScript.split('\n')
|
||||
|
||||
let insertLineNumber = getInsertLineNumber(currentLineNumber, scriptLines)
|
||||
|
||||
const insertOnSameLine = currentLineNumber === insertLineNumber
|
||||
|
||||
const formattedFunction = formatFunctionForInsert(name, example)
|
||||
|
||||
let nextScript = insertAtLine(
|
||||
insertLineNumber,
|
||||
scriptLines,
|
||||
formattedFunction,
|
||||
insertOnSameLine
|
||||
)
|
||||
|
||||
const importStatement = genImport(nextScript, func.package)
|
||||
|
||||
if (importStatement) {
|
||||
nextScript = `${importStatement}\n${nextScript}`
|
||||
insertLineNumber += 1
|
||||
}
|
||||
|
||||
const nextCursorPos = getCursorPosition(
|
||||
insertLineNumber,
|
||||
formattedFunction,
|
||||
name
|
||||
)
|
||||
|
||||
return {updatedScript: nextScript, cursorPosition: nextCursorPos}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
import {Position} from 'codemirror'
|
||||
|
||||
const rejoinScript = (scriptLines: string[]): string => {
|
||||
return scriptLines.join('\n')
|
||||
}
|
||||
|
||||
const getCursorPosition = (
|
||||
currentLineNumber: number,
|
||||
currentCharacterNumber: number,
|
||||
variableName: string
|
||||
) => {
|
||||
return {
|
||||
line: currentLineNumber,
|
||||
ch: currentCharacterNumber + formatVariable(variableName).length,
|
||||
}
|
||||
}
|
||||
|
||||
const insertAtCharacter = (
|
||||
lineNumber: number,
|
||||
characterNumber: number,
|
||||
scriptLines: string[],
|
||||
variableName: string
|
||||
): string => {
|
||||
const lineToEdit = scriptLines[lineNumber]
|
||||
const front = lineToEdit.slice(0, characterNumber)
|
||||
const back = lineToEdit.slice(characterNumber, lineToEdit.length)
|
||||
|
||||
const updatedLine = `${front}${formatVariable(variableName)}${back}`
|
||||
scriptLines[lineNumber] = updatedLine
|
||||
|
||||
return rejoinScript(scriptLines)
|
||||
}
|
||||
|
||||
const formatVariable = (variableName: string): string => {
|
||||
return `v.${variableName}`
|
||||
}
|
||||
|
||||
export const insertVariable = (
|
||||
currentLineNumber: number,
|
||||
currentCharacterNumber: number,
|
||||
currentScript: string,
|
||||
variableName: string
|
||||
): {updatedScript: string; cursorPosition: Position} => {
|
||||
const scriptLines = currentScript.split('\n')
|
||||
|
||||
const updatedScript = insertAtCharacter(
|
||||
currentLineNumber,
|
||||
currentCharacterNumber,
|
||||
scriptLines,
|
||||
variableName
|
||||
)
|
||||
|
||||
const updatedCursorPosition = getCursorPosition(
|
||||
currentLineNumber,
|
||||
currentCharacterNumber,
|
||||
variableName
|
||||
)
|
||||
|
||||
return {updatedScript, cursorPosition: updatedCursorPosition}
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
import * as allMonaco from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
|
||||
import * as lsp from '@influxdata/flux-lsp-browser'
|
||||
|
||||
export type ServerResponse = lsp.ServerResponse
|
||||
export type MonacoType = typeof allMonaco
|
||||
export type EditorType = allMonaco.editor.IStandaloneCodeEditor
|
||||
|
|
|
|||
|
|
@ -40,5 +40,6 @@
|
|||
"src/**/*.test.tsx",
|
||||
"src/**/mocks.ts",
|
||||
"coverage"
|
||||
]
|
||||
],
|
||||
"include": ["global.d.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const path = require('path')
|
|||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
|
||||
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
|
||||
const webpack = require('webpack')
|
||||
const {
|
||||
|
|
@ -29,14 +30,29 @@ module.exports = {
|
|||
},
|
||||
extensions: ['.tsx', '.ts', '.js', '.wasm'],
|
||||
},
|
||||
node: {
|
||||
fs: 'empty',
|
||||
global: true,
|
||||
crypto: 'empty',
|
||||
tls: 'empty',
|
||||
net: 'empty',
|
||||
process: true,
|
||||
module: false,
|
||||
clearImmediate: false,
|
||||
setImmediate: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\flux_parser_bg.wasm$/,
|
||||
test: /flux_parser_bg.wasm$/,
|
||||
type: 'webassembly/experimental',
|
||||
},
|
||||
{
|
||||
test: /^((?!flux_parser_bg).)*.wasm$/,
|
||||
test: /flux-lsp-browser_bg.wasm$/,
|
||||
type: 'webassembly/experimental',
|
||||
},
|
||||
{
|
||||
test: /^((?!flux_parser_bg|flux-lsp-browser_bg).)*.wasm$/,
|
||||
loader: 'file-loader',
|
||||
type: 'javascript/auto',
|
||||
},
|
||||
|
|
@ -120,6 +136,10 @@ module.exports = {
|
|||
API_PREFIX: API_BASE_PATH,
|
||||
STATIC_PREFIX: BASE_PATH,
|
||||
}),
|
||||
new MonacoWebpackPlugin({
|
||||
languages: ['json', 'markdown'],
|
||||
features: ['!gotoSymbol'],
|
||||
}),
|
||||
],
|
||||
stats: {
|
||||
colors: true,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,24 @@ module.exports = {
|
|||
entry: {
|
||||
vendor,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
vscode: path.resolve(
|
||||
'./node_modules/monaco-languageclient/lib/vscode-compatibility'
|
||||
),
|
||||
},
|
||||
},
|
||||
node: {
|
||||
fs: 'empty',
|
||||
global: true,
|
||||
crypto: 'empty',
|
||||
tls: 'empty',
|
||||
net: 'empty',
|
||||
process: true,
|
||||
module: false,
|
||||
clearImmediate: false,
|
||||
setImmediate: true,
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, 'build'),
|
||||
filename: '[name].bundle.js',
|
||||
|
|
@ -32,6 +50,14 @@ module.exports = {
|
|||
include: MONACO_DIR,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
|
|
@ -40,7 +66,7 @@ module.exports = {
|
|||
path: path.join(__dirname, 'build', '[name]-manifest.json'),
|
||||
}),
|
||||
new MonacoWebpackPlugin({
|
||||
languages: ['json', 'javascript', 'go', 'markdown'],
|
||||
languages: ['json', 'markdown'],
|
||||
}),
|
||||
],
|
||||
stats: {
|
||||
|
|
|
|||
112
ui/yarn.lock
112
ui/yarn.lock
|
|
@ -1016,6 +1016,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@influxdata/clockface/-/clockface-1.1.5.tgz#dfedc4f59788717d5e92bd00935dda35c0c60fc8"
|
||||
integrity sha512-5+RDswLCiOBX21rey6e1j4vrwQ6obwMv+qcP6ucH7y0vTRnAaMk9lqKqHH3FGUqUEfBNegtj4Ho8430ywfS6ag==
|
||||
|
||||
"@influxdata/flux-lsp-browser@^0.2.2":
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/flux-lsp-browser/-/flux-lsp-browser-0.2.2.tgz#766ef965da25149ac300df6db1a64ad277b5b50b"
|
||||
integrity sha512-MlFmu7gVdgJ1pkoC1CRaWmjedi6IuSJa2Bg3vDl0l/1cJyAShtoDs8levYvL0gqcKyvq/i/baXrNXF+SCIM7MQ==
|
||||
|
||||
"@influxdata/flux-parser@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/flux-parser/-/flux-parser-0.3.0.tgz#b63123ac814ad32c65e46a4097ba3d8b959416a5"
|
||||
|
|
@ -1486,11 +1491,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
|
||||
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==
|
||||
|
||||
"@types/stack-utils@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
||||
|
|
@ -1520,27 +1520,6 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/webpack-sources@*":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92"
|
||||
integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/source-list-map" "*"
|
||||
source-map "^0.6.1"
|
||||
|
||||
"@types/webpack@^4.4.19":
|
||||
version "4.39.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.39.8.tgz#8083a4eb850ea02961ef6161465434c9b478851f"
|
||||
integrity sha512-lkJvwNJQUPW2SbVwAZW9s9whJp02nzLf2yTNwMULa4LloED9MYS1aNnGeoBCifpAI1pEBkTpLhuyRmBnLEOZAA==
|
||||
dependencies:
|
||||
"@types/anymatch" "*"
|
||||
"@types/node" "*"
|
||||
"@types/tapable" "*"
|
||||
"@types/uglify-js" "*"
|
||||
"@types/webpack-sources" "*"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/webpack@^4.4.31", "@types/webpack@^4.4.35":
|
||||
version "4.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.35.tgz#b7088eb2d471d5645e5503d272783cafa753583b"
|
||||
|
|
@ -5380,6 +5359,11 @@ glob-parent@^5.0.0:
|
|||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob-to-regexp@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
|
||||
|
||||
glob@7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
|
|
@ -7908,17 +7892,27 @@ monaco-editor-textmate@^2.2.1:
|
|||
resolved "https://registry.yarnpkg.com/monaco-editor-textmate/-/monaco-editor-textmate-2.2.1.tgz#93f3f1932061dd2311b92a42ea1c027cfeb3e439"
|
||||
integrity sha512-RYTNNfvyjK15M0JA8WIi9UduU10eX5724UGNKnaA8MSetehjThGENctUTuKaxPk/k3pq59QzaQ/C06A44iJd3Q==
|
||||
|
||||
monaco-editor-webpack-plugin@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.7.0.tgz#920cbeecca25f15d70d568a7e11b0ba4daf1ae83"
|
||||
integrity sha512-oItymcnlL14Sjd7EF7q+CMhucfwR/2BxsqrXIBrWL6LQplFfAfV+grLEQRmVHeGSBZ/Gk9ptzfueXnWcoEcFuA==
|
||||
monaco-editor-webpack-plugin@^1.8.2:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.8.2.tgz#3721b8d9a3e2e41b154cf2a2955a7d7246c03714"
|
||||
integrity sha512-g9G7A/lxQtpPsYaZFBqm73dwVkOziGUXExIR6iW7ksZUaiMkpvdTiE9O8edgdJGo+XtCmjycmIKB1Lt8VKbSTQ==
|
||||
dependencies:
|
||||
"@types/webpack" "^4.4.19"
|
||||
loader-utils "^1.2.3"
|
||||
|
||||
monaco-editor@^0.18.1:
|
||||
version "0.18.1"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.18.1.tgz#ced7c305a23109875feeaf395a504b91f6358cfc"
|
||||
integrity sha512-fmL+RFZ2Hrezy+X/5ZczQW51LUmvzfcqOurnkCIRFTyjdVjzR7JvENzI6+VKBJzJdPh6EYL4RoWl92b2Hrk9fw==
|
||||
monaco-editor@^0.19.2:
|
||||
version "0.19.3"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.19.3.tgz#1c994b3186c00650dbcd034d5370d46bf56c0663"
|
||||
integrity sha512-2n1vJBVQF2Hhi7+r1mMeYsmlf18hjVb6E0v5SoMZyb4aeOmYPKun+CE3gYpiNA1KEvtSdaDHFBqH9d7Wd9vREg==
|
||||
|
||||
monaco-languageclient@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/monaco-languageclient/-/monaco-languageclient-0.11.0.tgz#0968ec143c98bf2c9fa69c2a84ac9ad5448e039d"
|
||||
integrity sha512-aqvgI+gX5K711eCJ3ggsMIeJ5fv7LnhxgzkMPRxSrkp+5/KLKY80V/m7PzDvWri+zF5cZ6InIPSmAAekn4oRzA==
|
||||
dependencies:
|
||||
glob-to-regexp "^0.3.0"
|
||||
vscode-jsonrpc "^4.1.0-next"
|
||||
vscode-languageclient "^5.3.0-next"
|
||||
vscode-uri "^1.0.5"
|
||||
|
||||
monaco-textmate@^3.0.1:
|
||||
version "3.0.1"
|
||||
|
|
@ -9410,7 +9404,7 @@ prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, pr
|
|||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.7.2:
|
||||
prop-types@^15.5.0, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
|
|
@ -9772,13 +9766,13 @@ react-markdown@^4.0.3:
|
|||
unist-util-visit "^1.3.0"
|
||||
xtend "^4.0.1"
|
||||
|
||||
react-monaco-editor@^0.32.1:
|
||||
version "0.32.1"
|
||||
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.32.1.tgz#fa45d62fd19d5942cba98bd7c59336d21f8750e0"
|
||||
integrity sha512-gJjU9Rx/QuJr+Y4C0MSidMdkh1hmHGneIU8yI87bc5kd46ZXPNETqiigyUB7pKy4ZSuFHBhjhg2lgESaID43ag==
|
||||
react-monaco-editor@^0.33.0:
|
||||
version "0.33.0"
|
||||
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.33.0.tgz#822c331836ec39b1160faf22b0c722266f822460"
|
||||
integrity sha512-zFo3A55QHCABYm4Xt0HWQMq10GI+oxhhCUGDYgzLksU1iGrdvHudUNXTDZvE43B1gM+cPyJ75jla/464kss8Iw==
|
||||
dependencies:
|
||||
"@types/react" "^15.x || ^16.x"
|
||||
prop-types "^15.0.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-onclickoutside@^6.7.1:
|
||||
version "6.7.1"
|
||||
|
|
@ -12028,6 +12022,42 @@ vm-browserify@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
vscode-jsonrpc@^4.1.0-next:
|
||||
version "4.1.0-next.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.3.tgz#05fe742959a2726020d4d0bfbc3d3c97873c7fde"
|
||||
integrity sha512-Z6oxBiMks2+UADV1QHXVooSakjyhI+eHTnXzDyVvVMmegvSfkXk2w6mPEdSkaNHFBdtWW7n20H1yw2nA3A17mg==
|
||||
|
||||
vscode-jsonrpc@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz#9bab9c330d89f43fc8c1e8702b5c36e058a01794"
|
||||
integrity sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==
|
||||
|
||||
vscode-languageclient@^5.3.0-next:
|
||||
version "5.3.0-next.9"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.3.0-next.9.tgz#34f58017647f15cd86015f7af45935dc750611f7"
|
||||
integrity sha512-BFA3X1y2EI2CfsSBy0KG2Xr5BOYfd/97jTmD+doqL6oj+cY8S7AmRCOwb2f9Hbjq8GWL7YC+OJ0leZEUSPgP0A==
|
||||
dependencies:
|
||||
semver "^6.3.0"
|
||||
vscode-languageserver-protocol "^3.15.0-next.8"
|
||||
|
||||
vscode-languageserver-protocol@^3.15.0-next.8:
|
||||
version "3.15.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.2.tgz#e52c62923140b2655ad2472f6f29cfb83bacf5b8"
|
||||
integrity sha512-GdL05JKOgZ76RDg3suiGCl9enESM7iQgGw4x93ibTh4sldvZmakHmTeZ4iUApPPGKf6O3OVBtrsksBXnHYaxNg==
|
||||
dependencies:
|
||||
vscode-jsonrpc "^5.0.1"
|
||||
vscode-languageserver-types "3.15.1"
|
||||
|
||||
vscode-languageserver-types@3.15.1:
|
||||
version "3.15.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de"
|
||||
integrity sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==
|
||||
|
||||
vscode-uri@^1.0.5:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.8.tgz#9769aaececae4026fb6e22359cb38946580ded59"
|
||||
integrity sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
|
||||
|
|
|
|||
Loading…
Reference in New Issue