fix: compiling issues for codemirror-lang-graphql

This commit is contained in:
Andrew Bastin
2021-11-10 14:31:00 +05:30
parent 8f6cf07e82
commit 7d7f628f6e
14 changed files with 14 additions and 325 deletions

View File

@@ -307,9 +307,7 @@ import { makeGQLHistoryEntry, addGraphqlHistoryEntry } from "~/newstore/history"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { getCurrentStrategyID } from "~/helpers/network"
import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest"
import { useNewCodemirror as useCodemirror } from "~/helpers/editor/codemirror"
import "codemirror/mode/javascript/javascript"
import "~/helpers/editor/modes/graphql"
import { useCodemirror } from "~/helpers/editor/codemirror"
import jsonLinter from "~/helpers/editor/linting/json"
import { createGQLQueryLinter } from "~/helpers/editor/linting/gqlQuery"
import queryCompleter from "~/helpers/editor/completion/gqlQuery"

View File

@@ -252,7 +252,6 @@ import {
setGQLURL,
setGQLVariables,
} from "~/newstore/GQLSession"
import "~/helpers/editor/modes/graphql"
function isTextFoundInGraphqlFieldObject(
text: string,

View File

@@ -30,7 +30,6 @@ import {
makeRESTRequest,
} from "~/helpers/types/HoppRESTRequest"
import { setRESTRequest } from "~/newstore/RESTSession"
import "codemirror/mode/shell/shell"
const {
$toast,

View File

@@ -175,7 +175,6 @@ import {
deleteAllRESTParams,
setRESTParams,
} from "~/newstore/RESTSession"
import "codemirror/mode/yaml/yaml"
const {
$toast,

View File

@@ -85,8 +85,7 @@
import { reactive, ref, useContext } from "@nuxtjs/composition-api"
import { usePreRequestScript } from "~/newstore/RESTSession"
import snippets from "~/helpers/preRequestScriptSnippets"
import "codemirror/mode/javascript/javascript"
import { useNewCodemirror as useCodemirror } from "~/helpers/editor/codemirror"
import { useCodemirror } from "~/helpers/editor/codemirror"
import linter from "~/helpers/editor/linting/preRequest"
import completer from "~/helpers/editor/completion/preRequest"

View File

@@ -72,11 +72,6 @@ import { useCodemirror } from "~/helpers/editor/codemirror"
import { getEditorLangForMimeType } from "~/helpers/editorutils"
import { pluckRef } from "~/helpers/utils/composables"
import { useRESTRequestBody } from "~/newstore/RESTSession"
import "codemirror/mode/yaml/yaml"
import "codemirror/mode/xml/xml"
import "codemirror/mode/css/css"
import "codemirror/mode/htmlmixed/htmlmixed"
import "codemirror/mode/javascript/javascript"
const props = defineProps<{
contentType: string

View File

@@ -85,7 +85,6 @@
import { reactive, ref, useContext } from "@nuxtjs/composition-api"
import { useTestScript } from "~/newstore/RESTSession"
import testSnippets from "~/helpers/testSnippets"
import "codemirror/mode/javascript/javascript"
import { useCodemirror } from "~/helpers/editor/codemirror"
import linter from "~/helpers/editor/linting/testScript"
import completer from "~/helpers/editor/completion/testScript"

View File

@@ -66,10 +66,6 @@
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import "codemirror/mode/xml/xml"
import "codemirror/mode/javascript/javascript"
import "codemirror/mode/css/css"
import "codemirror/mode/htmlmixed/htmlmixed"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
const props = defineProps<{

View File

@@ -145,9 +145,8 @@
<script setup lang="ts">
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api"
import { useNewCodemirror as useCodemirror } from "~/helpers/editor/codemirror"
import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import "codemirror/mode/javascript/javascript"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import jsonParse, { JSONObjectMember, JSONValue } from "~/helpers/jsonParse"
import { getJSONOutlineAtPos } from "~/helpers/newOutline"

View File

@@ -51,7 +51,6 @@
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import "codemirror/mode/xml/xml"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
const props = defineProps<{

View File

@@ -1,30 +1,3 @@
import CodeMirror from "codemirror"
import "codemirror-theme-github/theme/github.css"
import "codemirror/theme/base16-dark.css"
import "codemirror/theme/tomorrow-night-bright.css"
import "codemirror/lib/codemirror.css"
import "codemirror/addon/lint/lint.css"
import "codemirror/addon/dialog/dialog.css"
import "codemirror/addon/hint/show-hint.css"
import "codemirror/addon/fold/foldgutter.css"
import "codemirror/addon/fold/foldgutter"
import "codemirror/addon/fold/brace-fold"
import "codemirror/addon/fold/comment-fold"
import "codemirror/addon/fold/indent-fold"
import "codemirror/addon/display/autorefresh"
import "codemirror/addon/lint/lint"
import "codemirror/addon/hint/show-hint"
import "codemirror/addon/display/placeholder"
import "codemirror/addon/edit/closebrackets"
import "codemirror/addon/search/search"
import "codemirror/addon/search/searchcursor"
import "codemirror/addon/search/jump-to-line"
import "codemirror/addon/dialog/dialog"
import "codemirror/addon/selection/active-line"
import { keymap, EditorView, ViewPlugin, ViewUpdate } from "@codemirror/view"
import {
Extension,
@@ -39,7 +12,7 @@ import { basicSetup } from "@codemirror/basic-setup"
import { Completion, autocompletion } from "@codemirror/autocomplete"
import { linter } from "@codemirror/lint"
import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api"
import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api"
import { javascriptLanguage } from "@codemirror/lang-javascript"
import { jsonLanguage } from "@codemirror/lang-json"
@@ -52,191 +25,19 @@ import { Completer } from "./completion"
import { LinterDefinition } from "./linting/linter"
import { baseTheme, baseHighlightStyle } from "./themes/baseTheme"
type ExtendedEditorConfig = {
mode: string
placeholder: string
readOnly: boolean
lineWrapping: boolean
}
type CodeMirrorOptions = {
extendedEditorConfig: Omit<CodeMirror.EditorConfiguration, "value">
extendedEditorConfig: Partial<ExtendedEditorConfig>
linter: LinterDefinition | null
completer: Completer | null
}
const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = {
autoRefresh: true,
lineNumbers: true,
foldGutter: true,
autoCloseBrackets: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"Ctrl-Space": "autocomplete",
},
viewportMargin: Infinity,
styleActiveLine: true,
}
/**
* A Vue composable to mount and use Codemirror
*
* NOTE: Make sure to import all the necessary Codemirror modules,
* as this function doesn't import any other than the core
* @param el Reference to the dom node to attach to
* @param value Reference to value to read/write to
* @param options CodeMirror options to pass
*/
export function useCodemirror(
el: Ref<any | null>,
value: Ref<string>,
options: CodeMirrorOptions
): { cm: Ref<CodeMirror.Position | null>; cursor: Ref<CodeMirror.Position> } {
const { $colorMode } = useContext() as any
const cm = ref<CodeMirror.Editor | null>(null)
const cursor = ref<CodeMirror.Position>({ line: 0, ch: 0 })
const updateEditorConfig = () => {
Object.keys(options.extendedEditorConfig).forEach((key) => {
// Only update options which need updating
if (
cm.value &&
cm.value?.getOption(key as any) !==
(options.extendedEditorConfig as any)[key]
) {
cm.value?.setOption(
key as any,
(options.extendedEditorConfig as any)[key]
)
}
})
}
const updateLinterConfig = () => {
if (options.linter) {
cm.value?.setOption("lint", options.linter)
}
}
const updateCompleterConfig = () => {
if (options.completer) {
cm.value?.setOption("hintOptions", {
completeSingle: false,
hint: async (editor: CodeMirror.Editor) => {
const pos = editor.getCursor()
const text = editor.getValue()
const token = editor.getTokenAt(pos)
// It's not a word token, so, just increment to skip to next
if (token.string.toUpperCase() === token.string.toLowerCase())
token.start += 1
const result = await options.completer!(text, pos)
if (!result) return null
return <CodeMirror.Hints>{
from: { line: pos.line, ch: token.start },
to: { line: pos.line, ch: token.end },
list: result.completions
.sort((a, b) => a.score - b.score)
.map((x) => x.text),
}
},
})
}
}
const initialize = () => {
if (!el.value) return
cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG)
cm.value.setValue(value.value)
setTheme()
updateEditorConfig()
updateLinterConfig()
updateCompleterConfig()
cm.value.on("change", (instance) => {
// External update propagation (via watchers) should be ignored
if (instance.getValue() !== value.value) {
value.value = instance.getValue()
}
})
cm.value.on("cursorActivity", (instance) => {
cursor.value = instance.getCursor()
})
}
// Boot-up CodeMirror, set the value and listeners
onMounted(() => {
initialize()
})
// Reinitialize if the target ref updates
watch(el, () => {
if (cm.value) {
const parent = cm.value.getWrapperElement()
parent.remove()
cm.value = null
}
initialize()
})
const setTheme = () => {
if (cm.value) {
cm.value?.setOption("theme", getThemeName($colorMode.value))
}
}
const getThemeName = (mode: string) => {
switch (mode) {
case "system":
return "default"
case "light":
return "github"
case "dark":
return "base16-dark"
case "black":
return "tomorrow-night-bright"
default:
return "default"
}
}
// If the editor properties are reactive, watch for updates
watch(() => options.extendedEditorConfig, updateEditorConfig, {
immediate: true,
deep: true,
})
watch(() => options.linter, updateLinterConfig, { immediate: true })
watch(() => options.completer, updateCompleterConfig, { immediate: true })
// Watch value updates
watch(value, (newVal) => {
// Check if we are mounted
if (cm.value) {
// Don't do anything on internal updates
if (cm.value.getValue() !== newVal) {
cm.value.setValue(newVal)
}
}
})
// Push cursor updates
watch(cursor, (value) => {
if (value !== cm.value?.getCursor()) {
cm.value?.focus()
cm.value?.setCursor(value)
}
})
// Watch color mode updates and update theme
watch(() => $colorMode.value, setTheme)
return {
cm,
cursor,
}
}
const hoppCompleterExt = (completer: Completer): Extension => {
return autocompletion({
override: [
@@ -324,7 +125,7 @@ const getEditorLanguage = (
O.getOrElseW(() => [])
)
export function useNewCodemirror(
export function useCodemirror(
el: Ref<any | null>,
value: Ref<string>,
options: CodeMirrorOptions
@@ -380,7 +181,7 @@ export function useNewCodemirror(
EditorState.changeFilter.of(() => !options.extendedEditorConfig.readOnly),
language.of(
getEditorLanguage(
(options.extendedEditorConfig.mode as any) ?? "",
options.extendedEditorConfig.mode ?? "",
options.linter ?? undefined,
options.completer ?? undefined
)

View File

@@ -1,80 +0,0 @@
/**
* Copyright (c) 2021 GraphQL Contributors
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
import CodeMirror from "codemirror"
import {
LexRules,
ParseRules,
isIgnored,
onlineParser,
State,
} from "graphql-language-service-parser"
/**
* The GraphQL mode is defined as a tokenizer along with a list of rules, each
* of which is either a function or an array.
*
* * Function: Provided a token and the stream, returns an expected next step.
* * Array: A list of steps to take in order.
*
* A step is either another rule, or a terminal description of a token. If it
* is a rule, that rule is pushed onto the stack and the parsing continues from
* that point.
*
* If it is a terminal description, the token is checked against it using a
* `match` function. If the match is successful, the token is colored and the
* rule is stepped forward. If the match is unsuccessful, the remainder of the
* rule is skipped and the previous rule is advanced.
*
* This parsing algorithm allows for incremental online parsing within various
* levels of the syntax tree and results in a structured `state` linked-list
* which contains the relevant information to produce valuable typeaheads.
*/
CodeMirror.defineMode("graphql", (config) => {
const parser = onlineParser({
eatWhitespace: (stream) => stream.eatWhile(isIgnored),
lexRules: LexRules,
parseRules: ParseRules,
editorConfig: { tabSize: 2 },
})
return {
config,
startState: parser.startState,
token: parser.token as unknown as CodeMirror.Mode<any>["token"], // TODO: Check if the types are indeed compatible
indent,
electricInput: /^\s*[})\]]/,
fold: "brace",
lineComment: "#",
closeBrackets: {
pairs: '()[]{}""',
explode: "()[]{}",
},
}
})
// Seems the electricInput type in @types/codemirror is wrong (i.e it is written as electricinput instead of electricInput)
function indent(
this: CodeMirror.Mode<any> & {
electricInput?: RegExp
config?: CodeMirror.EditorConfiguration
},
state: State,
textAfter: string
) {
const levels = state.levels
// If there is no stack of levels, use the current level.
// Otherwise, use the top level, pre-emptively dedenting for close braces.
const level =
!levels || levels.length === 0
? state.indentLevel
: levels[levels.length - 1] -
(this.electricInput?.test(textAfter) ? 1 : 0)
return (level || 0) * (this.config?.indentUnit || 0)
}

View File

@@ -60,8 +60,6 @@
"acorn": "^8.5.0",
"acorn-walk": "^8.2.0",
"axios": "^0.24.0",
"codemirror": "^5.63.3",
"codemirror-theme-github": "^1.0.0",
"core-js": "^3.19.1",
"esprima": "^4.0.1",
"firebase": "^9.2.0",

12
pnpm-lock.yaml generated
View File

@@ -99,8 +99,6 @@ importers:
axios: ^0.24.0
babel-core: ^7.0.0-bridge.0
babel-jest: ^27.3.1
codemirror: ^5.63.3
codemirror-theme-github: ^1.0.0
core-js: ^3.19.1
eslint: ^8.1.0
eslint-config-prettier: ^8.3.0
@@ -186,8 +184,6 @@ importers:
acorn: 8.5.0
acorn-walk: 8.2.0
axios: 0.24.0
codemirror: 5.63.3
codemirror-theme-github: 1.0.0
core-js: 3.19.1
esprima: 4.0.1
firebase: 9.2.0
@@ -7915,14 +7911,6 @@ packages:
resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=}
engines: {node: '>=0.10.0'}
/codemirror-theme-github/1.0.0:
resolution: {integrity: sha512-suheFec2wlI4klyqn61MOFXjjrKPZiNY7d2py0OvTd5Z+7AsNxoGKDaS/HI59y7EAG1SkkXW/JQ1Rt2gDMxHfA==}
dev: false
/codemirror/5.63.3:
resolution: {integrity: sha512-1C+LELr+5grgJYqwZKqxrcbPsHFHapVaVAloBsFBASbpLnQqLw1U8yXJ3gT5D+rhxIiSpo+kTqN+hQ+9ialIXw==}
dev: false
/collect-v8-coverage/1.0.1:
resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==}
dev: true